Marko Pintera 11 лет назад
Родитель
Сommit
1195be6fb8

+ 5 - 5
BansheeEditor/Include/BsGUIResourceTreeView.h

@@ -7,6 +7,11 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
+	struct DraggedResources
+	{
+		Vector<String> resourceUUIDs;
+	};
+
 	class GUIResourceTreeView : public GUITreeView
 	class GUIResourceTreeView : public GUITreeView
 	{
 	{
 		struct ResourceTreeElement : public GUITreeView::TreeElement
 		struct ResourceTreeElement : public GUITreeView::TreeElement
@@ -15,11 +20,6 @@ namespace BansheeEngine
 			WString mElementName;
 			WString mElementName;
 		};
 		};
 
 
-		struct DraggedResources
-		{
-			Vector<String> resourceUUIDs;
-		};
-
 		struct InternalDraggedResources
 		struct InternalDraggedResources
 		{
 		{
 			InternalDraggedResources(UINT32 numObjects);
 			InternalDraggedResources(UINT32 numObjects);

+ 51 - 0
MBansheeEditor/GUI/GUIResourceField.cs

@@ -0,0 +1,51 @@
+using System;
+using System.Runtime.CompilerServices;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    public sealed class GUIResourceField : GUIElement
+    {
+        public delegate void OnChangedDelegate(Resource newValue);
+
+        public event OnChangedDelegate OnChanged;
+
+        public Resource Value
+        {
+            get
+            {
+                Resource value;
+                Internal_GetValue(mCachedPtr, out value);
+                return value;
+            }
+
+            set { Internal_SetValue(mCachedPtr, value); }
+        }
+
+        public GUIResourceField(Type type, GUIContent title, int titleWidth = 100, string style = "", params GUIOption[] options)
+        {
+            Internal_CreateInstance(this, type, title, titleWidth, style, options, true);
+        }
+
+        public GUIResourceField(Type type, string style = "", params GUIOption[] options)
+        {
+            Internal_CreateInstance(this, type, null, 0, style, options, false);
+        }
+
+        private void DoOnChanged(Resource newValue)
+        {
+            if (OnChanged != null)
+                OnChanged(newValue);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CreateInstance(GUIResourceField instance, Type type, GUIContent title, int titleWidth,
+            string style, GUIOption[] options, bool withTitle);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetValue(IntPtr nativeInstance, out Resource value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetValue(IntPtr nativeInstance, Resource value);
+    }
+}

+ 1 - 0
MBansheeEditor/MBansheeEditor.csproj

@@ -46,6 +46,7 @@
     <Compile Include="EditorApplication.cs" />
     <Compile Include="EditorApplication.cs" />
     <Compile Include="EditorWindow.cs" />
     <Compile Include="EditorWindow.cs" />
     <Compile Include="GUI\GUIGameObjectField.cs" />
     <Compile Include="GUI\GUIGameObjectField.cs" />
+    <Compile Include="GUI\GUIResourceField.cs" />
     <Compile Include="GUI\GUIVector3Field.cs" />
     <Compile Include="GUI\GUIVector3Field.cs" />
     <Compile Include="GUI\GUIColorField.cs" />
     <Compile Include="GUI\GUIColorField.cs" />
     <Compile Include="GUI\GUIFloatField.cs" />
     <Compile Include="GUI\GUIFloatField.cs" />

+ 75 - 0
SBansheeEditor/Include/BsGUIResourceField.h

@@ -0,0 +1,75 @@
+#pragma once
+
+#include "BsScriptEditorPrerequisites.h"
+#include "BsGUIElementContainer.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BED_EXPORT GUIResourceField : public GUIElementContainer
+	{
+		struct PrivatelyConstruct {};
+
+	public:
+		static const String& getGUITypeName();
+
+		static GUIResourceField* create(const String& type, const GUIContent& labelContent, UINT32 labelWidth, const GUIOptions& layoutOptions,
+			const String& style = StringUtil::BLANK);
+
+		static GUIResourceField* create(const String& type, const GUIContent& labelContent, const GUIOptions& layoutOptions,
+			const String& style = StringUtil::BLANK);
+
+		static GUIResourceField* create(const String& type, const HString& labelText, UINT32 labelWidth, const GUIOptions& layoutOptions,
+			const String& style = StringUtil::BLANK);
+
+		static GUIResourceField* create(const String& type, const HString& labelText, const GUIOptions& layoutOptions,
+			const String& style = StringUtil::BLANK);
+
+		static GUIResourceField* create(const String& type, const GUIOptions& layoutOptions, const String& style = StringUtil::BLANK);
+
+		static GUIResourceField* create(const String& type, const GUIContent& labelContent, UINT32 labelWidth,
+			const String& style = StringUtil::BLANK);
+
+		static GUIResourceField* create(const String& type, const GUIContent& labelContent,
+			const String& style = StringUtil::BLANK);
+
+		static GUIResourceField* create(const String& type, const HString& labelText, UINT32 labelWidth,
+			const String& style = StringUtil::BLANK);
+
+		static GUIResourceField* create(const String& type, const HString& labelText,
+			const String& style = StringUtil::BLANK);
+
+		static GUIResourceField* create(const String& type, const String& style = StringUtil::BLANK);
+
+		GUIResourceField(const PrivatelyConstruct& dummy, const String& type, const GUIContent& labelContent,
+			UINT32 labelWidth, const String& style, const GUILayoutOptions& layoutOptions, bool withLabel);
+
+		HResource getValue() const;
+		void setValue(const HResource& value);
+
+		String getUUID() const { return mUUID; }
+		void setUUID(const String& uuid);
+
+		void _updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
+			RectI clipRect, UINT8 widgetDepth, UINT16 areaDepth);
+
+		Vector2I _getOptimalSize() const;
+
+		Event<void(const String&)> onValueChanged;
+	private:
+		virtual ~GUIResourceField();
+
+		void styleUpdated();
+
+		void dataDropped(void* data);
+
+	private:
+		static const UINT32 DEFAULT_LABEL_WIDTH;
+
+		GUILayout* mLayout;
+		GUILabel* mLabel;
+		GUIDropButton* mDropButton;
+		GUIButton* mClearButton;
+		String mType;
+		String mUUID;
+	};
+}

+ 29 - 0
SBansheeEditor/Include/BsScriptGUIResourceField.h

@@ -0,0 +1,29 @@
+#pragma once
+
+#include "BsScriptEditorPrerequisites.h"
+#include "BsScriptGUIElement.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BED_EXPORT ScriptGUIResourceField : public TScriptGUIElement<ScriptGUIResourceField>
+	{
+	public:
+		SCRIPT_OBJ(BansheeEditorAssemblyName, "BansheeEditor", "GUIResourceField")
+
+	private:
+		static void internal_createInstance(MonoObject* instance, MonoReflectionType* type, MonoObject* title, UINT32 titleWidth,
+			MonoString* style, MonoArray* guiOptions, bool withTitle);
+
+		static void internal_getValue(ScriptGUIResourceField* nativeInstance, MonoObject** output);
+		static void internal_setValue(ScriptGUIResourceField* nativeInstance, MonoObject* value);
+
+		static void onChanged(MonoObject* instance, const HResource& newValue);
+		static MonoObject* nativeToManagedResource(const HResource& instance);
+
+		ScriptGUIResourceField(MonoObject* instance, GUIResourceField* resourceField);
+
+		typedef void(__stdcall *OnChangedThunkDef) (MonoObject*, MonoObject*, MonoException**);
+
+		static OnChangedThunkDef onChangedThunk;
+	};
+}

+ 4 - 0
SBansheeEditor/SBansheeEditor.vcxproj

@@ -228,6 +228,7 @@
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="Include\BsGUIGameObjectField.h" />
     <ClInclude Include="Include\BsGUIGameObjectField.h" />
     <ClInclude Include="Include\BsGUIPanelContainer.h" />
     <ClInclude Include="Include\BsGUIPanelContainer.h" />
+    <ClInclude Include="Include\BsGUIResourceField.h" />
     <ClInclude Include="Include\BsScriptEditorPrerequisites.h" />
     <ClInclude Include="Include\BsScriptEditorPrerequisites.h" />
     <ClInclude Include="Include\BsScriptEditorWindow.h" />
     <ClInclude Include="Include\BsScriptEditorWindow.h" />
     <ClInclude Include="Include\BsScriptGUIColorField.h" />
     <ClInclude Include="Include\BsScriptGUIColorField.h" />
@@ -236,6 +237,7 @@
     <ClInclude Include="Include\BsScriptGUIGameObjectField.h" />
     <ClInclude Include="Include\BsScriptGUIGameObjectField.h" />
     <ClInclude Include="Include\BsScriptGUIIntField.h" />
     <ClInclude Include="Include\BsScriptGUIIntField.h" />
     <ClInclude Include="Include\BsScriptGUIPanelContainer.h" />
     <ClInclude Include="Include\BsScriptGUIPanelContainer.h" />
+    <ClInclude Include="Include\BsScriptGUIResourceField.h" />
     <ClInclude Include="Include\BsScriptGUITextField.h" />
     <ClInclude Include="Include\BsScriptGUITextField.h" />
     <ClInclude Include="Include\BsScriptGUIToggleField.h" />
     <ClInclude Include="Include\BsScriptGUIToggleField.h" />
     <ClInclude Include="Include\BsScriptGUIVector2Field.h" />
     <ClInclude Include="Include\BsScriptGUIVector2Field.h" />
@@ -245,6 +247,7 @@
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsGUIGameObjectField.cpp" />
     <ClCompile Include="Source\BsGUIGameObjectField.cpp" />
     <ClCompile Include="Source\BsGUIPanelContainer.cpp" />
     <ClCompile Include="Source\BsGUIPanelContainer.cpp" />
+    <ClCompile Include="Source\BsGUIResourceField.cpp" />
     <ClCompile Include="Source\BsScriptEditorPlugin.cpp" />
     <ClCompile Include="Source\BsScriptEditorPlugin.cpp" />
     <ClCompile Include="Source\BsScriptEditorWindow.cpp" />
     <ClCompile Include="Source\BsScriptEditorWindow.cpp" />
     <ClCompile Include="Source\BsScriptGUIColorField.cpp" />
     <ClCompile Include="Source\BsScriptGUIColorField.cpp" />
@@ -253,6 +256,7 @@
     <ClCompile Include="Source\BsScriptGUIGameObjectField.cpp" />
     <ClCompile Include="Source\BsScriptGUIGameObjectField.cpp" />
     <ClCompile Include="Source\BsScriptGUIIntField.cpp" />
     <ClCompile Include="Source\BsScriptGUIIntField.cpp" />
     <ClCompile Include="Source\BsScriptGUIPanelContainer.cpp" />
     <ClCompile Include="Source\BsScriptGUIPanelContainer.cpp" />
+    <ClCompile Include="Source\BsScriptGUIResourceField.cpp" />
     <ClCompile Include="Source\BsScriptGUITextField.cpp" />
     <ClCompile Include="Source\BsScriptGUITextField.cpp" />
     <ClCompile Include="Source\BsScriptGUIToggleField.cpp" />
     <ClCompile Include="Source\BsScriptGUIToggleField.cpp" />
     <ClCompile Include="Source\BsScriptGUIVector2Field.cpp" />
     <ClCompile Include="Source\BsScriptGUIVector2Field.cpp" />

+ 12 - 0
SBansheeEditor/SBansheeEditor.vcxproj.filters

@@ -60,6 +60,12 @@
     <ClInclude Include="Include\BsScriptGUIGameObjectField.h">
     <ClInclude Include="Include\BsScriptGUIGameObjectField.h">
       <Filter>Header Files</Filter>
       <Filter>Header Files</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\BsGUIResourceField.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsScriptGUIResourceField.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptEditorPlugin.cpp">
     <ClCompile Include="Source\BsScriptEditorPlugin.cpp">
@@ -107,5 +113,11 @@
     <ClCompile Include="Source\BsScriptGUIGameObjectField.cpp">
     <ClCompile Include="Source\BsScriptGUIGameObjectField.cpp">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\BsGUIResourceField.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsScriptGUIResourceField.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 225 - 0
SBansheeEditor/Source/BsGUIResourceField.cpp

@@ -0,0 +1,225 @@
+#include "BsGUIResourceField.h"
+#include "BsGUIArea.h"
+#include "BsGUILayout.h"
+#include "BsGUILabel.h"
+#include "BsGUIDropButton.h"
+#include "BsGUIButton.h"
+#include "BsBuiltinResources.h"
+#include "BsGUIWidget.h"
+#include "BsGUIMouseEvent.h"
+#include "BsGUIResourceTreeView.h"
+#include "BsGUIWidget.h"
+#include "BsGameObjectManager.h"
+#include "BsRuntimeScriptObjects.h"
+#include "BsMonoClass.h"
+#include "BsResources.h"
+#include "BsEditorGUI.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	const UINT32 GUIResourceField::DEFAULT_LABEL_WIDTH = 100;
+
+	GUIResourceField::GUIResourceField(const PrivatelyConstruct& dummy, const String& type, const GUIContent& labelContent, UINT32 labelWidth,
+		const String& style, const GUILayoutOptions& layoutOptions, bool withLabel)
+		:GUIElementContainer(layoutOptions, style), mLabel(nullptr), mClearButton(nullptr), mDropButton(nullptr), mType(type)
+	{
+		mLayout = &addLayoutXInternal(this);
+
+		if (withLabel)
+		{
+			mLabel = GUILabel::create(labelContent, GUIOptions(GUIOption::fixedWidth(labelWidth)), getSubStyleName(EditorGUI::ObjectFieldLabelStyleName));
+			mLayout->addElement(mLabel);
+		}
+
+		mDropButton = GUIDropButton::create((UINT32)DragAndDropType::SceneObject, GUIOptions(GUIOption::flexibleWidth()), getSubStyleName(EditorGUI::ObjectFieldDropBtnStyleName));
+		mClearButton = GUIButton::create(HString(L""), getSubStyleName(EditorGUI::ObjectFieldClearBtnStyleName));
+
+		mLayout->addElement(mDropButton);
+		mLayout->addElement(mClearButton);
+
+		mDropButton->onDataDropped.connect(std::bind(&GUIResourceField::dataDropped, this, _1));
+	}
+
+	GUIResourceField::~GUIResourceField()
+	{
+
+	}
+
+	GUIResourceField* GUIResourceField::create(const String& type, const GUIContent& labelContent, UINT32 labelWidth, const GUIOptions& layoutOptions,
+		const String& style)
+	{
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &EditorGUI::ObjectFieldStyleName;
+
+		return bs_new<GUIResourceField>(PrivatelyConstruct(), type, labelContent, labelWidth, *curStyle,
+			GUILayoutOptions::create(layoutOptions), true);
+	}
+
+	GUIResourceField* GUIResourceField::create(const String& type, const GUIContent& labelContent, const GUIOptions& layoutOptions,
+		const String& style)
+	{
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &EditorGUI::ObjectFieldStyleName;
+
+		return bs_new<GUIResourceField>(PrivatelyConstruct(), type, labelContent, DEFAULT_LABEL_WIDTH, *curStyle,
+			GUILayoutOptions::create(layoutOptions), true);
+	}
+
+	GUIResourceField* GUIResourceField::create(const String& type, const HString& labelText, UINT32 labelWidth, const GUIOptions& layoutOptions,
+		const String& style)
+	{
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &EditorGUI::ObjectFieldStyleName;
+
+		return bs_new<GUIResourceField>(PrivatelyConstruct(), type, GUIContent(labelText), labelWidth, *curStyle,
+			GUILayoutOptions::create(layoutOptions), true);
+	}
+
+	GUIResourceField* GUIResourceField::create(const String& type, const HString& labelText, const GUIOptions& layoutOptions,
+		const String& style)
+	{
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &EditorGUI::ObjectFieldStyleName;
+
+		return bs_new<GUIResourceField>(PrivatelyConstruct(), type, GUIContent(labelText), DEFAULT_LABEL_WIDTH, *curStyle,
+			GUILayoutOptions::create(layoutOptions), true);
+	}
+
+	GUIResourceField* GUIResourceField::create(const String& type, const GUIOptions& layoutOptions, const String& style)
+	{
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &EditorGUI::ObjectFieldStyleName;
+
+		return bs_new<GUIResourceField>(PrivatelyConstruct(), type, GUIContent(), 0, *curStyle,
+			GUILayoutOptions::create(layoutOptions), false);
+	}
+
+	GUIResourceField* GUIResourceField::create(const String& type, const GUIContent& labelContent, UINT32 labelWidth,
+		const String& style)
+	{
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &EditorGUI::ObjectFieldStyleName;
+
+		return bs_new<GUIResourceField>(PrivatelyConstruct(), type, labelContent, labelWidth, *curStyle,
+			GUILayoutOptions::create(), true);
+	}
+
+	GUIResourceField* GUIResourceField::create(const String& type, const GUIContent& labelContent,
+		const String& style)
+	{
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &EditorGUI::ObjectFieldStyleName;
+
+		return bs_new<GUIResourceField>(PrivatelyConstruct(), type, labelContent, DEFAULT_LABEL_WIDTH, *curStyle,
+			GUILayoutOptions::create(), true);
+	}
+
+	GUIResourceField* GUIResourceField::create(const String& type, const HString& labelText, UINT32 labelWidth,
+		const String& style)
+	{
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &EditorGUI::ObjectFieldStyleName;
+
+		return bs_new<GUIResourceField>(PrivatelyConstruct(), type, GUIContent(labelText), labelWidth, *curStyle,
+			GUILayoutOptions::create(), true);
+	}
+
+	GUIResourceField* GUIResourceField::create(const String& type, const HString& labelText,
+		const String& style)
+	{
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &EditorGUI::ObjectFieldStyleName;
+
+		return bs_new<GUIResourceField>(PrivatelyConstruct(), type, GUIContent(labelText), DEFAULT_LABEL_WIDTH, *curStyle,
+			GUILayoutOptions::create(), true);
+	}
+
+	GUIResourceField* GUIResourceField::create(const String& type, const String& style)
+	{
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &EditorGUI::ObjectFieldStyleName;
+
+		return bs_new<GUIResourceField>(PrivatelyConstruct(), type, GUIContent(), 0, *curStyle,
+			GUILayoutOptions::create(), false);
+	}
+
+	HResource GUIResourceField::getValue() const
+	{
+		return Resources::instance().loadFromUUID(mUUID);
+	}
+
+	void GUIResourceField::setValue(const HResource& value)
+	{
+		if (value)
+			setUUID(value.getUUID());
+		else
+			setUUID("");
+	}
+
+	void GUIResourceField::setUUID(const String& uuid)
+	{ 
+		mUUID = uuid;
+
+		Path filePath;
+		if (Resources::instance().getFilePathFromUUID(mUUID, filePath))
+		{
+			mDropButton->setContent(GUIContent(filePath.getFilename(false)));
+		}
+		else
+			mDropButton->setContent(GUIContent(HString(L"None")));
+
+		onValueChanged(mUUID);
+	}
+
+	void GUIResourceField::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
+		RectI clipRect, UINT8 widgetDepth, UINT16 areaDepth)
+	{
+		mLayout->_updateLayoutInternal(x, y, width, height, clipRect, widgetDepth, areaDepth);
+	}
+
+	Vector2I GUIResourceField::_getOptimalSize() const
+	{
+		return mLayout->_getOptimalSize();
+	}
+
+	void GUIResourceField::dataDropped(void* data)
+	{
+		DraggedResources* draggedResources = reinterpret_cast<DraggedResources*>(data);
+		UINT32 numResources = (UINT32)draggedResources->resourceUUIDs.size();
+
+		if (numResources <= 0)
+			return;
+
+		for (UINT32 i = 0; i < numResources; i++)
+		{
+			// TODO - I need to be able to check resource type without loading it
+		}
+	}
+
+	void GUIResourceField::styleUpdated()
+	{
+		if (mLabel != nullptr)
+			mLabel->setStyle(getSubStyleName(EditorGUI::ObjectFieldLabelStyleName));
+
+		mDropButton->setStyle(getSubStyleName(EditorGUI::ObjectFieldDropBtnStyleName));
+		mClearButton->setStyle(getSubStyleName(EditorGUI::ObjectFieldClearBtnStyleName));
+	}
+
+	const String& GUIResourceField::getGUITypeName()
+	{
+		static String typeName = "GUIResourceField";
+		return typeName;
+	}
+}

+ 123 - 0
SBansheeEditor/Source/BsScriptGUIResourceField.cpp

@@ -0,0 +1,123 @@
+#include "BsScriptGUIResourceField.h"
+#include "BsScriptMeta.h"
+#include "BsMonoField.h"
+#include "BsMonoClass.h"
+#include "BsMonoManager.h"
+#include "BsMonoMethod.h"
+#include "BsSpriteTexture.h"
+#include "BsMonoUtil.h"
+#include "BsGUILayout.h"
+#include "BsGUIResourceField.h"
+#include "BsGUIOptions.h"
+#include "BsGUIContent.h"
+#include "BsScriptGUIElementStyle.h"
+#include "BsScriptGUILayout.h"
+#include "BsScriptGUIArea.h"
+#include "BsScriptHString.h"
+#include "BsScriptGUIContent.h"
+#include "BsScriptResource.h"
+#include "BsScriptResourceManager.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	ScriptGUIResourceField::OnChangedThunkDef ScriptGUIResourceField::onChangedThunk;
+
+	ScriptGUIResourceField::ScriptGUIResourceField(MonoObject* instance, GUIResourceField* resourceField)
+		:TScriptGUIElement(instance, resourceField)
+	{
+
+	}
+
+	void ScriptGUIResourceField::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptGUIResourceField::internal_createInstance);
+		metaData.scriptClass->addInternalCall("Internal_GetValue", &ScriptGUIResourceField::internal_getValue);
+		metaData.scriptClass->addInternalCall("Internal_SetValue", &ScriptGUIResourceField::internal_setValue);
+
+		onChangedThunk = (OnChangedThunkDef)metaData.scriptClass->getMethod("DoOnChanged", 1).getThunk();
+	}
+
+	void ScriptGUIResourceField::internal_createInstance(MonoObject* instance, MonoReflectionType* type, MonoObject* title, UINT32 titleWidth,
+		MonoString* style, MonoArray* guiOptions, bool withTitle)
+	{
+		GUIOptions options;
+
+		UINT32 arrayLen = (UINT32)mono_array_length(guiOptions);
+		for (UINT32 i = 0; i < arrayLen; i++)
+			options.addOption(mono_array_get(guiOptions, GUIOption, i));
+
+		String styleName = toString(MonoUtil::monoToWString(style));
+
+		MonoType* monoType = mono_reflection_type_get_type(type);
+		::MonoClass* monoClass = mono_type_get_class(monoType);
+
+		String typeNamespace = mono_class_get_namespace(monoClass);
+		String typeName = mono_class_get_name(monoClass);
+
+		String fullTypeName = typeNamespace + "::" + typeName;
+
+		GUIResourceField* guiResourceField = nullptr;
+		if (withTitle)
+		{
+			GUIContent nativeContent(ScriptGUIContent::getText(title), ScriptGUIContent::getImage(title), ScriptGUIContent::getTooltip(title));
+			guiResourceField = GUIResourceField::create(fullTypeName, nativeContent, titleWidth, options, styleName);
+		}
+		else
+		{
+			guiResourceField = GUIResourceField::create(fullTypeName, options, styleName);
+		}
+
+		guiResourceField->onValueChanged.connect(std::bind(&ScriptGUIResourceField::onChanged, instance, _1));
+
+		ScriptGUIResourceField* nativeInstance = new (bs_alloc<ScriptGUIResourceField>()) ScriptGUIResourceField(instance, guiResourceField);
+	}
+
+	void ScriptGUIResourceField::internal_getValue(ScriptGUIResourceField* nativeInstance, MonoObject** output)
+	{
+		GUIResourceField* resourceField = static_cast<GUIResourceField*>(nativeInstance->getGUIElement());
+
+		HResource resource = resourceField->getValue();
+		*output = nativeToManagedResource(resource);
+	}
+
+	void ScriptGUIResourceField::internal_setValue(ScriptGUIResourceField* nativeInstance, MonoObject* value)
+	{
+		GUIResourceField* resourceField = static_cast<GUIResourceField*>(nativeInstance->getGUIElement());
+
+		if (value == nullptr)
+			resourceField->setValue(HResource());
+		else
+		{
+			ScriptResourceBase* scriptResource = ScriptResource::toNative(value);
+			resourceField->setValue(scriptResource->getNativeHandle());
+		}
+	}
+
+	void ScriptGUIResourceField::onChanged(MonoObject* instance, const HResource& newValue)
+	{
+		MonoException* exception = nullptr;
+		MonoObject* managedObj = nativeToManagedResource(newValue);
+
+		onChangedThunk(instance, managedObj, &exception);
+
+		MonoUtil::throwIfException(exception);
+	}
+
+	MonoObject* ScriptGUIResourceField::nativeToManagedResource(const HResource& instance)
+	{
+		if (instance == nullptr)
+		{
+			return nullptr;
+		}
+		else
+		{
+			ScriptResourceBase* scriptResource = ScriptResourceManager::instance().getScriptResource(instance);
+			if (scriptResource == nullptr)
+				return nullptr;
+			else
+				return scriptResource->getManagedInstance();
+		}
+	}
+}

+ 1 - 1
SBansheeEngine/Include/BsScriptEnginePrerequisites.h

@@ -21,7 +21,7 @@
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	class ScriptResourceManager;
 	class ScriptResourceManager;
-	class ScriptResource;
+	class ScriptResourceBase;
 	class ScriptFont;
 	class ScriptFont;
 	class ScriptSpriteTexture;
 	class ScriptSpriteTexture;
 	class ScriptTexture2D;
 	class ScriptTexture2D;

+ 17 - 3
SBansheeEngine/Include/BsScriptResource.h

@@ -5,7 +5,7 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
-	class BS_SCR_BE_EXPORT ScriptResource : public ScriptObjectBase
+	class BS_SCR_BE_EXPORT ScriptResourceBase : public ScriptObjectBase
 	{
 	{
 	public:
 	public:
 		virtual HResource getNativeHandle() const = 0;
 		virtual HResource getNativeHandle() const = 0;
@@ -14,9 +14,23 @@ namespace BansheeEngine
 	protected:
 	protected:
 		friend class ScriptResourceManager;
 		friend class ScriptResourceManager;
 
 
-		ScriptResource(MonoObject* instance)
+		ScriptResourceBase(MonoObject* instance)
 			:ScriptObjectBase(instance)
 			:ScriptObjectBase(instance)
 		{ }
 		{ }
-		virtual ~ScriptResource() {}
+		virtual ~ScriptResourceBase() {}
+	};
+
+	class BS_SCR_BE_EXPORT ScriptResource : public ScriptObject<ScriptResource, ScriptResourceBase>
+	{
+	public:
+		static String getAssemblyName() { return BansheeEngineAssemblyName; }
+		static String getNamespace() { return "BansheeEngine"; }
+		static String getTypeName() { return "Resource"; }
+		static void initRuntimeData() { }
+
+	private:
+		ScriptResource(MonoObject* instance)
+			:ScriptObject(instance)
+		{ }
 	};
 	};
 }
 }

+ 3 - 3
SBansheeEngine/Include/BsScriptResourceManager.h

@@ -48,12 +48,12 @@ namespace BansheeEngine
 		/**
 		/**
 		 * @note Returns nullptr if script resource doesn't exist.
 		 * @note Returns nullptr if script resource doesn't exist.
 		 */
 		 */
-		ScriptResource* getScriptResource(const HResource& resourceHandle);
+		ScriptResourceBase* getScriptResource(const HResource& resourceHandle);
 
 
-		void destroyScriptResource(ScriptResource* resource);
+		void destroyScriptResource(ScriptResourceBase* resource);
 
 
 	private:
 	private:
-		UnorderedMap<String, ScriptResource*> mScriptResources;
+		UnorderedMap<String, ScriptResourceBase*> mScriptResources;
 		MonoClass* mTextureClass;
 		MonoClass* mTextureClass;
 		MonoClass* mSpriteTextureClass;
 		MonoClass* mSpriteTextureClass;
 
 

+ 1 - 1
SBansheeEngine/Include/BsScriptSpriteTexture.h

@@ -6,7 +6,7 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
-	class BS_SCR_BE_EXPORT ScriptSpriteTexture : public ScriptObject<ScriptSpriteTexture, ScriptResource>
+	class BS_SCR_BE_EXPORT ScriptSpriteTexture : public ScriptObject<ScriptSpriteTexture, ScriptResourceBase>
 	{
 	{
 	public:
 	public:
 		SCRIPT_OBJ(BansheeEngineAssemblyName, "BansheeEngine", "SpriteTexture")
 		SCRIPT_OBJ(BansheeEngineAssemblyName, "BansheeEngine", "SpriteTexture")

+ 1 - 1
SBansheeEngine/Include/BsScriptTexture2D.h

@@ -7,7 +7,7 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
-	class BS_SCR_BE_EXPORT ScriptTexture2D : public ScriptObject<ScriptTexture2D, ScriptResource>
+	class BS_SCR_BE_EXPORT ScriptTexture2D : public ScriptObject<ScriptTexture2D, ScriptResourceBase>
 	{
 	{
 	public:
 	public:
 		SCRIPT_OBJ(BansheeEngineAssemblyName, "BansheeEngine", "Texture2D")
 		SCRIPT_OBJ(BansheeEngineAssemblyName, "BansheeEngine", "Texture2D")

+ 3 - 3
SBansheeEngine/Source/BsScriptResourceManager.cpp

@@ -70,7 +70,7 @@ namespace BansheeEngine
 		return static_cast<ScriptSpriteTexture*>(getScriptResource(resourceHandle));
 		return static_cast<ScriptSpriteTexture*>(getScriptResource(resourceHandle));
 	}
 	}
 
 
-	ScriptResource* ScriptResourceManager::getScriptResource(const HResource& resourceHandle)
+	ScriptResourceBase* ScriptResourceManager::getScriptResource(const HResource& resourceHandle)
 	{
 	{
 		const String& uuid = resourceHandle.getUUID();
 		const String& uuid = resourceHandle.getUUID();
 
 
@@ -84,7 +84,7 @@ namespace BansheeEngine
 		return nullptr;
 		return nullptr;
 	}
 	}
 
 
-	void ScriptResourceManager::destroyScriptResource(ScriptResource* resource)
+	void ScriptResourceManager::destroyScriptResource(ScriptResourceBase* resource)
 	{
 	{
 		HResource resourceHandle = resource->getNativeHandle();
 		HResource resourceHandle = resource->getNativeHandle();
 		const String& uuid = resourceHandle.getUUID();
 		const String& uuid = resourceHandle.getUUID();
@@ -95,7 +95,7 @@ namespace BansheeEngine
 		auto findIter = mScriptResources.find(uuid);
 		auto findIter = mScriptResources.find(uuid);
 		if(findIter != mScriptResources.end())
 		if(findIter != mScriptResources.end())
 		{
 		{
-			(resource)->~ScriptResource();
+			(resource)->~ScriptResourceBase();
 			MemoryAllocator<GenAlloc>::free(resource);
 			MemoryAllocator<GenAlloc>::free(resource);
 
 
 			mScriptResources.erase(findIter);
 			mScriptResources.erase(findIter);