Răsfoiți Sursa

Added Camera inspector
Fixes for GUISliderField and GUIEnumField

BearishSun 10 ani în urmă
părinte
comite
5efdd7772b

+ 5 - 5
BansheeEditor/Source/BsBuiltinEditorResources.cpp

@@ -1321,7 +1321,7 @@ namespace BansheeEngine
 
 		GUIElementStyle editorVector2FieldStyle;
 		editorVector2FieldStyle.fixedHeight = true;
-		editorVector2FieldStyle.height = 30;
+		editorVector2FieldStyle.height = 21;
 		editorVector2FieldStyle.minWidth = 30;
 		editorVector2FieldStyle.subStyles[GUIVector2Field::getLabelStyleType()] = GUITextField::getLabelStyleType();
 		editorVector2FieldStyle.subStyles[GUIVector2Field::getFloatFieldStyleType()] = GUIFloatField::getGUITypeName();
@@ -1330,7 +1330,7 @@ namespace BansheeEngine
 
 		GUIElementStyle editorVector3FieldStyle;
 		editorVector3FieldStyle.fixedHeight = true;
-		editorVector3FieldStyle.height = 30;
+		editorVector3FieldStyle.height = 21;
 		editorVector3FieldStyle.minWidth = 30;
 		editorVector3FieldStyle.subStyles[GUIVector3Field::getLabelStyleType()] = GUITextField::getLabelStyleType();
 		editorVector3FieldStyle.subStyles[GUIVector3Field::getFloatFieldStyleType()] = GUIFloatField::getGUITypeName();
@@ -1339,7 +1339,7 @@ namespace BansheeEngine
 
 		GUIElementStyle editorVector4FieldStyle;
 		editorVector4FieldStyle.fixedHeight = true;
-		editorVector4FieldStyle.height = 30;
+		editorVector4FieldStyle.height = 21;
 		editorVector4FieldStyle.minWidth = 30;
 		editorVector4FieldStyle.subStyles[GUIVector4Field::getLabelStyleType()] = GUITextField::getLabelStyleType();
 		editorVector4FieldStyle.subStyles[GUIVector4Field::getFloatFieldStyleType()] = GUIFloatField::getGUITypeName();
@@ -1348,7 +1348,7 @@ namespace BansheeEngine
 
 		GUIElementStyle editorListBoxFieldStyle;
 		editorListBoxFieldStyle.fixedHeight = true;
-		editorListBoxFieldStyle.height = 30;
+		editorListBoxFieldStyle.height = 21;
 		editorListBoxFieldStyle.minWidth = 30;
 		editorListBoxFieldStyle.subStyles[GUIListBoxField::getLabelStyleType()] = GUIListBoxField::getLabelStyleType();
 		editorListBoxFieldStyle.subStyles[GUIListBoxField::getListBoxStyleType()] = GUIListBox::getGUITypeName();
@@ -1357,7 +1357,7 @@ namespace BansheeEngine
 
 		GUIElementStyle editorSliderFieldStyle;
 		editorSliderFieldStyle.fixedHeight = true;
-		editorSliderFieldStyle.height = 30;
+		editorSliderFieldStyle.height = 21;
 		editorSliderFieldStyle.minWidth = 30;
 		editorSliderFieldStyle.subStyles[GUISliderField::getLabelStyleType()] = GUISliderField::getLabelStyleType();
 		editorSliderFieldStyle.subStyles[GUISliderField::getInputStyleType()] = GUIInputBox::getGUITypeName();

+ 1 - 1
BansheeEngine/Source/BsGUISlider.cpp

@@ -156,7 +156,7 @@ namespace BansheeEngine
 	void GUISlider::setValue(float value)
 	{
 		float diff = mMaxRange - mMinRange;
-		float pct = value / diff;
+		float pct = (value - mMinRange) / diff;
 
 		setPercent(pct);
 	}

+ 1 - 1
MBansheeEditor/GUI/GUIEnumField.cs

@@ -50,7 +50,7 @@ namespace BansheeEditor
         /// <param name="titleWidth">Width of the title label in pixels.</param>
         /// <param name="options">Options that allow you to control how is the element positioned and sized. This will 
         ///                       override any similar options set by style.</param>
-        public GUIEnumField(Type enumType, GUIContent title, int titleWidth = 100, params GUIOption[] options)
+        public GUIEnumField(Type enumType, GUIContent title, int titleWidth, params GUIOption[] options)
         {
             Internal_CreateInstance(this, Enum.GetNames(enumType), Enum.GetValues(enumType), title, titleWidth, "", options, true);
         }

+ 171 - 5
MBansheeEditor/Inspectors/CameraInspector.cs

@@ -6,10 +6,25 @@ namespace BansheeEditor
     /// <summary>
     /// Renders an inspector for the <see cref="Camera"/> component.
     /// </summary>
+    [CustomInspector(typeof(Camera))]
     public class CameraInspector : Inspector
     {
         private bool isInitialized;
-        private List<InspectableField> inspectableFields = new List<InspectableField>();
+        private GUIEnumField mProjectionTypeField = new GUIEnumField(typeof(ProjectionType), new LocEdString("Projection type"));
+        private GUISliderField mFieldOfView = new GUISliderField(1, 360, new LocEdString("Field of view"));
+        private GUIFloatField mOrthoHeight = new GUIFloatField(new LocEdString("Orthographic height"));
+        private GUIFloatField mAspectField = new GUIFloatField(new LocEdString("Aspect ratio"));
+        private GUIFloatField mNearPlaneField = new GUIFloatField(new LocEdString("Near plane"));
+        private GUIFloatField mFarPlaneField = new GUIFloatField(new LocEdString("Far plane"));
+        private GUIFloatField mViewportXField = new GUIFloatField(new LocEdString("X"), 30);
+        private GUIFloatField mViewportYField = new GUIFloatField(new LocEdString("Y"), 30);
+        private GUIFloatField mViewportWidthField = new GUIFloatField(new LocEdString("Width"), 30);
+        private GUIFloatField mViewportHeightField = new GUIFloatField(new LocEdString("Height"), 30);
+        private GUIEnumField mClearFlagsFields = new GUIEnumField(typeof (ClearFlags), new LocEdString("Clear flags"));
+        private GUIIntField mClearStencilField = new GUIIntField(new LocEdString("Clear stencil"));
+        private GUIFloatField mClearDepthField = new GUIFloatField(new LocEdString("Clear depth"));
+        private GUIColorField mClearColorField = new GUIColorField(new LocEdString("Clear color"));
+        private GUIIntField mPriorityField = new GUIIntField(new LocEdString("Render priority"));
 
         /// <summary>
         /// Initializes required data the first time <see cref="Refresh"/> is called.
@@ -20,7 +35,71 @@ namespace BansheeEditor
             {
                 Camera camera = (Camera) referencedObject;
 
+                mProjectionTypeField.OnSelectionChanged += x =>
+                {
+                    camera.ProjectionType = (ProjectionType) x;
+
+                    if (camera.ProjectionType == ProjectionType.Orthographic)
+                    {
+                        mFieldOfView.Visible = false;
+                        mOrthoHeight.Visible = true;
+                    }
+                    else
+                    {
+                        mFieldOfView.Visible = true;
+                        mOrthoHeight.Visible = false;
+                    }
+                };
+
+                Debug.Log(camera.FieldOfView);
                 
+                mFieldOfView.OnChanged += x => camera.FieldOfView = x;
+                mOrthoHeight.OnChanged += x => camera.OrthoHeight = x;
+                mAspectField.OnChanged += x => camera.AspectRatio = x;
+                mNearPlaneField.OnChanged += x => camera.NearClipPlane = x;
+                mFarPlaneField.OnChanged += x => camera.FarClipPlane = x;
+                mViewportXField.OnChanged += x => 
+                    { Rect2 rect = camera.ViewportRect; rect.x = x; camera.ViewportRect = rect; };
+                mViewportYField.OnChanged += x => 
+                    { Rect2 rect = camera.ViewportRect; rect.y = x; camera.ViewportRect = rect; };
+                mViewportWidthField.OnChanged += x => 
+                    { Rect2 rect = camera.ViewportRect; rect.width = x; camera.ViewportRect = rect; };
+                mViewportHeightField.OnChanged += x => 
+                    { Rect2 rect = camera.ViewportRect; rect.height = x; camera.ViewportRect = rect; };
+                mClearFlagsFields.OnSelectionChanged += x => camera.ClearFlags = (ClearFlags)x;
+                mClearStencilField.OnChanged += x => camera.ClearStencil = (ushort)x;
+                mClearDepthField.OnChanged += x => camera.ClearDepth = x;
+                mClearColorField.OnChanged += x => camera.ClearColor = x;
+                mPriorityField.OnChanged += x => camera.Priority = x;
+
+                layout.AddElement(mProjectionTypeField);
+                layout.AddElement(mFieldOfView);
+                layout.AddElement(mOrthoHeight);
+                layout.AddElement(mAspectField);
+                layout.AddElement(mNearPlaneField);
+                layout.AddElement(mFarPlaneField);
+                GUILayoutX viewportTopLayout = layout.AddLayoutX();
+                viewportTopLayout.AddElement(new GUILabel(new LocEdString("Viewport"), GUIOption.FixedWidth(100)));
+                GUILayoutY viewportContentLayout = viewportTopLayout.AddLayoutY();
+
+                GUILayoutX viewportTopRow = viewportContentLayout.AddLayoutX();
+                viewportTopRow.AddElement(mViewportXField);
+                viewportTopRow.AddElement(mViewportWidthField);
+
+                GUILayoutX viewportBotRow = viewportContentLayout.AddLayoutX();
+                viewportBotRow.AddElement(mViewportYField);
+                viewportBotRow.AddElement(mViewportHeightField);
+
+                layout.AddElement(mClearFlagsFields);
+                layout.AddElement(mClearColorField);
+                layout.AddElement(mClearDepthField);
+                layout.AddElement(mClearStencilField);
+                layout.AddElement(mPriorityField);
+
+                if (camera.ProjectionType == ProjectionType.Orthographic)
+                    mFieldOfView.Visible = false;
+                else
+                    mOrthoHeight.Visible = false;
             }
 
             isInitialized = true;
@@ -32,13 +111,100 @@ namespace BansheeEditor
             if (!isInitialized)
                 Initialize();
 
+            Camera camera = referencedObject as Camera;
+            if (camera == null)
+                return false;
+
             bool anythingModified = false;
 
-            int currentIndex = 0;
-            foreach (var field in inspectableFields)
+            if (mProjectionTypeField.Value != (int) camera.ProjectionType)
+            {
+                mProjectionTypeField.Value = (int)camera.ProjectionType;
+                anythingModified = true;
+            }
+
+            if (mFieldOfView.Value != camera.FieldOfView.Degrees)
+            {
+                mFieldOfView.Value = camera.FieldOfView.Degrees;
+                anythingModified = true;
+            }
+
+            if (mOrthoHeight.Value != camera.OrthoHeight)
+            {
+                mOrthoHeight.Value = camera.OrthoHeight;
+                anythingModified = true;
+            }
+
+            if (mAspectField.Value != camera.AspectRatio)
+            {
+                mAspectField.Value = camera.AspectRatio;
+                anythingModified = true;
+            }
+
+            if (mNearPlaneField.Value != camera.NearClipPlane)
+            {
+                mNearPlaneField.Value = camera.NearClipPlane;
+                anythingModified = true;
+            }
+
+            if (mFarPlaneField.Value != camera.FarClipPlane)
+            {
+                mFarPlaneField.Value = camera.FarClipPlane;
+                anythingModified = true;
+            }
+
+            if (mViewportXField.Value != camera.ViewportRect.x)
+            {
+                mViewportXField.Value = camera.ViewportRect.x;
+                anythingModified = true;
+            }
+
+            if (mViewportYField.Value != camera.ViewportRect.y)
+            {
+                mViewportYField.Value = camera.ViewportRect.y;
+                anythingModified = true;
+            }
+
+            if (mViewportWidthField.Value != camera.ViewportRect.width)
+            {
+                mViewportWidthField.Value = camera.ViewportRect.width;
+                anythingModified = true;
+            }
+
+            if (mViewportHeightField.Value != camera.ViewportRect.height)
+            {
+                mViewportHeightField.Value = camera.ViewportRect.height;
+                anythingModified = true;
+            }
+
+            if (mClearFlagsFields.Value != (int)camera.ClearFlags)
+            {
+                mClearFlagsFields.Value = (int)camera.ClearFlags;
+                anythingModified = true;
+            }
+
+            if (mClearStencilField.Value != camera.ClearStencil)
+            {
+                mClearStencilField.Value = camera.ClearStencil;
+                anythingModified = true;
+            }
+
+            if (mClearDepthField.Value != camera.ClearDepth)
+            {
+                mClearDepthField.Value = camera.ClearDepth;
+                anythingModified = true;
+            }
+
+            if (mClearColorField.Value != camera.ClearColor)
+            {
+                mClearColorField.Value = camera.ClearColor;
+                anythingModified = true;
+            }
+
+            if (mPriorityField.Value != camera.Priority)
             {
-                anythingModified |= field.Refresh(currentIndex);
-                currentIndex += field.GetNumLayoutElements();
+                mPriorityField.Value = camera.Priority;
+                anythingModified = true;
             }
 
             return anythingModified;

+ 8 - 8
MBansheeEditor/LibraryMenu.cs

@@ -59,7 +59,7 @@ namespace BansheeEditor
         /// <summary>
         /// Creates a new material with the default shader in the currently selected project library folder.
         /// </summary>
-        [MenuItem("Resources/Create/Material", 50, false, "IsLibraryWindowActive")]
+        [MenuItem("Resources/Create/Material", 1050, false, "IsLibraryWindowActive")]
         internal static void CreateEmptyMaterial()
         {
             LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
@@ -72,7 +72,7 @@ namespace BansheeEditor
         /// <summary>
         /// Creates a new shader containing a rough code outline in the currently selected project library folder.
         /// </summary>
-        [MenuItem("Resources/Create/Shader", 49, false, "IsLibraryWindowActive")]
+        [MenuItem("Resources/Create/Shader", 1049, false, "IsLibraryWindowActive")]
         internal static void CreateEmptyShader()
         {
             LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
@@ -85,7 +85,7 @@ namespace BansheeEditor
         /// <summary>
         /// Creates a new C# script containing a rough code outline in the currently selected project library folder.
         /// </summary>
-        [MenuItem("Resources/Create/C# script", 48, false, "IsLibraryWindowActive")]
+        [MenuItem("Resources/Create/C# script", 1048, false, "IsLibraryWindowActive")]
         internal static void CreateEmptyCSScript()
         {
             LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
@@ -98,7 +98,7 @@ namespace BansheeEditor
         /// <summary>
         /// Creates a new empty sprite texture in the currently selected project library folder.
         /// </summary>
-        [MenuItem("Resources/Create/Sprite texture", 47, false, "IsLibraryWindowActive")]
+        [MenuItem("Resources/Create/Sprite texture", 1047, false, "IsLibraryWindowActive")]
         internal static void CreateEmptySpriteTexture()
         {
             LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
@@ -111,7 +111,7 @@ namespace BansheeEditor
         /// <summary>
         /// Creates a new empty GUI skin in the currently selected project library folder.
         /// </summary>
-        [MenuItem("Resources/Create/GUI skin", 46, false, "IsLibraryWindowActive")]
+        [MenuItem("Resources/Create/GUI skin", 1046, false, "IsLibraryWindowActive")]
         internal static void CreateEmptyGUISkin()
         {
             LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
@@ -124,7 +124,7 @@ namespace BansheeEditor
         /// <summary>
         /// Creates a new empty string table in the currently selected project library folder.
         /// </summary>
-        [MenuItem("Resources/Create/String table", 45, false, "IsLibraryWindowActive")]
+        [MenuItem("Resources/Create/String table", 1045, false, "IsLibraryWindowActive")]
         internal static void CreateEmptyStringTable()
         {
             LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
@@ -137,7 +137,7 @@ namespace BansheeEditor
         /// <summary>
         /// Opens the currently selected project library file or folder in the default external application.
         /// </summary>
-        [MenuItem("Resources/Open externally", 40, true, "IsLibraryWindowActive")]
+        [MenuItem("Resources/Open externally", 1040, true, "IsLibraryWindowActive")]
         internal static void OpenExternally()
         {
             LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
@@ -150,7 +150,7 @@ namespace BansheeEditor
         /// <summary>
         /// Explores the current project library folder in the external file system explorer.
         /// </summary>
-        [MenuItem("Resources/Explore location", 39, false, "IsLibraryWindowActive")]
+        [MenuItem("Resources/Explore location", 1039, false, "IsLibraryWindowActive")]
         internal static void ExploreLocation()
         {
             LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();

+ 2 - 2
MBansheeEngine/Camera.cs

@@ -16,7 +16,7 @@ namespace BansheeEngine
         private NativeCamera native;
 
         [SerializeField]
-        private SerializableData serializableData = new SerializableData();
+        internal SerializableData serializableData = new SerializableData();
 
         /// <summary>
         /// Returns the non-component version of Camera that is wrapped by this component. 
@@ -393,7 +393,7 @@ namespace BansheeEngine
         /// Holds all data the camera component needs to persist through serialization.
         /// </summary>
         [SerializeObject]
-        private struct SerializableData
+        internal struct SerializableData
         {
             public float aspectRatio;
             public float nearClipPlane;

+ 1 - 0
MBansheeEngine/MBansheeEngine.csproj

@@ -112,6 +112,7 @@
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Math\Quaternion.cs" />
+    <Compile Include="Range.cs" />
     <Compile Include="Renderable.cs" />
     <Compile Include="NativeRenderable.cs" />
     <Compile Include="RenderTarget.cs" />

+ 2 - 2
MBansheeEngine/NativeCamera.cs

@@ -57,7 +57,7 @@ namespace BansheeEngine
 
         internal Degree fieldOfView
         {
-            get { return Internal_GetFieldOfView(mCachedPtr); }
+            get { Degree value; Internal_GetFieldOfView(mCachedPtr, out value); return value; }
             set { Internal_SetFieldOfView(mCachedPtr, value); }
         }
 
@@ -228,7 +228,7 @@ namespace BansheeEngine
         private static extern void Internal_SetFarClip(IntPtr instance, float value);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern Degree Internal_GetFieldOfView(IntPtr instance);
+        private static extern void Internal_GetFieldOfView(IntPtr instance, out Degree value);
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetFieldOfView(IntPtr instance, Degree value);
 

+ 25 - 0
MBansheeEngine/Range.cs

@@ -0,0 +1,25 @@
+using System;
+
+namespace BansheeEngine
+{
+    /// <summary>
+    /// Makes an integer or a floating point field be displayed as a slider with a specified range in the inspector.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Field)]
+    public sealed class Range : Attribute
+    {
+        /// <summary>
+        /// Creates a new range attribute.
+        /// </summary>
+        /// <param name="min">Minimum boundary of the range to clamp the field value to.</param>
+        /// <param name="max">Maximum boundary of the range to clamp the field value to.</param>
+        public Range(float min, float max)
+        {
+            this.min = min;
+            this.max = max;
+        }
+
+        private float min;
+        private float max;
+    }
+}

+ 13 - 1
MBansheeEngine/SerializableObject.cs

@@ -35,7 +35,7 @@ namespace BansheeEngine
         /// Creates a new serializable object for the specified object type.
         /// </summary>
         /// <param name="objectType">C# type of the object.</param>
-        /// <param name="parentObject">Specific instance of the object of <paramref name="objectType"/></param>
+        /// <param name="parentObject">Specific instance of the object of <paramref name="objectType"/>.</param>
         public SerializableObject(Type objectType, object parentObject)
         {
             Internal_CreateInstance(this, objectType);
@@ -44,6 +44,18 @@ namespace BansheeEngine
             this.parentObject = parentObject;
         }
 
+        /// <summary>
+        /// Creates a new serializable object for the specified object. Object must not be null.
+        /// </summary>
+        /// <param name="parentObject">Specific instance of the object.</param>
+        public SerializableObject(object parentObject)
+        {
+            Internal_CreateInstance(this, parentObject.GetType());
+
+            this.parentProperty = null;
+            this.parentObject = parentObject;
+        }
+
         /// <summary>
         /// Returns all fields in the object.
         /// </summary>

+ 17 - 2
MBansheeEngine/SerializableProperty.cs

@@ -34,8 +34,8 @@ namespace BansheeEngine
             Dictionary
         }
 
-        internal delegate object Getter();
-        internal delegate void Setter(object value);
+        public delegate object Getter();
+        public delegate void Setter(object value);
 
         private FieldType type;
         private Type internalType;
@@ -48,6 +48,21 @@ namespace BansheeEngine
         private SerializableProperty()
         { }
 
+        /// <summary>
+        /// Creates a new serializable property.
+        /// </summary>
+        /// <param name="type">Type of data the property contains.</param>
+        /// <param name="internalType">Type of data the property contains, as C# type.</param>
+        /// <param name="getter">Method that allows you to retrieve contents of the property.</param>
+        /// <param name="setter">Method that allows you to set contents of the property</param>
+        public SerializableProperty(FieldType type, Type internalType, Getter getter, Setter setter)
+        {
+            this.type = type;
+            this.internalType = internalType;
+            this.getter = getter;
+            this.setter = setter;
+        }
+
         /// <summary>
         /// Finalizes construction of the serializable property. Must be called after creation.
         /// </summary>

+ 2 - 0
SBansheeEditor/Source/BsScriptGUIEnumField.cpp

@@ -81,6 +81,8 @@ namespace BansheeEngine
 			memcpy(((UINT8*)&nativeValue) + offsetDst, valuesArr.getRawPtr(elemSize, i) + offsetSrc, 
 				std::min(elemSize, (UINT32)sizeof(UINT32)));
 #endif
+
+			nativeValues.push_back(nativeValue);
 		}
 			
 

+ 1 - 1
SBansheeEngine/Include/BsScriptCamera.h

@@ -52,7 +52,7 @@ namespace BansheeEngine
 		static float internal_GetFarClip(ScriptCamera* instance);
 		static void internal_SetFarClip(ScriptCamera* instance, float value);
 
-		static Degree internal_GetFieldOfView(ScriptCamera* instance);
+		static void internal_GetFieldOfView(ScriptCamera* instance, Degree* value);
 		static void internal_SetFieldOfView(ScriptCamera* instance, Degree value);
 
 		static Rect2 internal_GetViewportRect(ScriptCamera* instance);

+ 2 - 2
SBansheeEngine/Source/BsScriptCamera.cpp

@@ -164,9 +164,9 @@ namespace BansheeEngine
 		instance->mCamera->setFarClipDistance(value);
 	}
 
-	Degree ScriptCamera::internal_GetFieldOfView(ScriptCamera* instance)
+	void ScriptCamera::internal_GetFieldOfView(ScriptCamera* instance, Degree* value)
 	{
-		return instance->mCamera->getHorzFOV();
+		*value = instance->mCamera->getHorzFOV();
 	}
 
 	void ScriptCamera::internal_SetFieldOfView(ScriptCamera* instance, Degree value)

+ 10 - 4
TODO.txt

@@ -54,18 +54,21 @@ Polish
 
 Ribek use:
  - Hook up color picker to guicolor field
+ - When drop down opens in a list box that is horizontally scrolled is opens are what feels like an incorrect offset
+ - When hiding a component in inspector, it doesn't immediately reposition the components below it
+ - Having en empty component in inspector shows a small empty background, it shouldn't show anything
  - Component inspectors for: Camera, Renderable, Point/Spot/Directional lights
  - Resource inspectors for: Material, Texture, Mesh, Font, Shader, Script Code, Plain Text, Sprite Texture, GUISkin, StringTable, Prefab (just something basic for now)
  - Test release mode
  - Order top-level menu entries according to priority and set valid priorities
+ - Add temporary icon textures too all icon buttons currently containing only text so that Ribek can modify them
+  - Also add dummy icons to toolbar (New Project, Open Project, Save Scene, Undo, Redo, Basic shapes, Camera, Renderable, Lights)
 
 Other polish:
  - C# interface for Font and SpriteTexture
  - Add menu items:
   - Edit: Cut/Copy/Paste/Duplicate/Delete(need to make sure it works in Hierarchy, with shortcuts), View/Move/rotate/scale
   - Game Object (also add to context): Create(Empty, Empty Child, Camera, Renderable, Point/Spot/Directional Light), Apply prefab, Break prefab, Revert prefab
- - Add temporary icon textures too all icon buttons currently containing only text so that Ribek can modify them
-  - Also add dummy icons to toolbar (New Project, Open Project, Save Scene, Undo, Redo, Basic shapes, Camera, Renderable, Lights)
  - When I expand inspector elements and them come back to that object it should remember the previous state
    - Add a chaching mechanism to inspector (likely based on instance ID & property names)
    - This has to work not only when I come back to the object, but whenever inspector rebuilds (e.g. after removing element from array)
@@ -102,8 +105,7 @@ Optional:
   - Add commands for breaking or reverting a scene object 
   - Test & finalize undo/redo system
   - Add Undo/Redo menu and toolbar entries to "Edit" menu
- - Update GUISlider so has min/max limits, plus step size
-  - Add Range[] attribute to C# that forces a float/int to be displayed as a slider
+ - Add Range[] attribute to C# that forces a float/int to be displayed as a slider
  - Add "focus on object" key (F) - animate it: rotate camera towards then speed towards while zooming in (+ menu entry)
  - Ortographic camera views (+ gizmo in scene view corner that shows camera orientation)
  - Drag to select in scene view
@@ -158,6 +160,10 @@ Mono cannot marshal structures? Taken from their documentation:
  Internal calls do not provide support for marshalling structures. This means that any API calls that take a structure 
  (excluding the system types like int32, int64, etc) must be passed as a pointer, in C# this means passing the value as a "ref" or "out" parameter.
 
+Mono has problems with returning a struct from an internal C++ method. Returned value might end up being corrupted. It works weirdly as
+I am able (for example) return a Rect2 with no problems, but it doesn't work when returning a Degree struct. Returning the value as input
+parameter solves the problem (presumably boxing the return value would also work).
+
 Sometimes exceptions cause a crash in Event, although this is due to an exception triggering a dialog box which triggers
 the message loop and causes another exception. Make sure to look for the original exception.