Procházet zdrojové kódy

Started work on GUICanvas control needed for rendering things like animation curve editor

BearishSun před 9 roky
rodič
revize
cdfa21d8bb

+ 4 - 3
Documentation/GitHub/features.md

@@ -66,9 +66,10 @@ All features listed here are the ones currently available (implemented). If you
 	* Handles complex types (e.g. array, list, dictionary) and references
 	* Handles complex types (e.g. array, list, dictionary) and references
 	* Fast and small memory footprint
 	* Fast and small memory footprint
 * __Audio__
 * __Audio__
-  * 3D sounds
-  * Music
-  * Streaming
+  * 3D sounds (panning, attenuation, doppler effect) and 2D sounds (music, narration)
+  * On-the-fly streaming and decompression
+  * Multi-channel support up to 7.1 sound
+  * Multiple listener support for split-screen
   * Multiple backends
   * Multiple backends
     * OpenAL
     * OpenAL
 	* FMOD
 	* FMOD

+ 0 - 1
Documentation/GitHub/roadmap.md

@@ -2,7 +2,6 @@
 
 
 The focus right now is to implement the most critical missing features:
 The focus right now is to implement the most critical missing features:
  - Animation (skeletal, blend shapes, generic script variables)
  - Animation (skeletal, blend shapes, generic script variables)
- - Audio (popular file format support, music, 3D audio)
 
 
 Planned for Q3 2016 release.
 Planned for Q3 2016 release.
 
 

+ 1 - 1
Source/BansheeEditor/Source/BsDropDownWindow.cpp

@@ -47,7 +47,7 @@ namespace BansheeEngine
 		setSize(width, height);
 		setSize(width, height);
 
 
 		GUIPanel* backgroundPanel = mRootPanel->addNewElement<GUIPanel>(500);
 		GUIPanel* backgroundPanel = mRootPanel->addNewElement<GUIPanel>(500);
-		backgroundPanel->addElement(GUITexture::create(GUIImageScaleMode::RepeatToFit,
+		backgroundPanel->addElement(GUITexture::create(TextureScaleMode::RepeatToFit,
 			GUIOptions(GUIOption::flexibleWidth(), GUIOption::flexibleHeight()), "WindowBackground"));
 			GUIOptions(GUIOption::flexibleWidth(), GUIOption::flexibleHeight()), "WindowBackground"));
 
 
 		GUIPanel* windowFramePanel = mRootPanel->addNewElement<GUIPanel>(499);
 		GUIPanel* windowFramePanel = mRootPanel->addNewElement<GUIPanel>(499);

+ 3 - 3
Source/BansheeEditor/Source/BsGUIMenuBar.cpp

@@ -71,17 +71,17 @@ namespace BansheeEngine
 		mBgPanel->setWidth(1);
 		mBgPanel->setWidth(1);
 		mBgPanel->setHeight(50);
 		mBgPanel->setHeight(50);
 
 
-		mBgTexture = GUITexture::create(GUIImageScaleMode::StretchToFit,
+		mBgTexture = GUITexture::create(TextureScaleMode::StretchToFit,
 			GUIOptions(GUIOption::flexibleWidth(), GUIOption::flexibleHeight()), getBackgroundStyleType());
 			GUIOptions(GUIOption::flexibleWidth(), GUIOption::flexibleHeight()), getBackgroundStyleType());
 		
 		
 		GUILayoutX* bgLayout = mBgPanel->addNewElement<GUILayoutX>();
 		GUILayoutX* bgLayout = mBgPanel->addNewElement<GUILayoutX>();
 		bgLayout->addElement(mBgTexture);
 		bgLayout->addElement(mBgTexture);
 
 
-		mLogoTexture = GUITexture::create(GUIImageScaleMode::StretchToFit, getLogoStyleType());
+		mLogoTexture = GUITexture::create(TextureScaleMode::StretchToFit, getLogoStyleType());
 		mMinBtn = GUIButton::create(HString(L""), "WinMinimizeBtn");
 		mMinBtn = GUIButton::create(HString(L""), "WinMinimizeBtn");
 		mMaxBtn = GUIButton::create(HString(L""), "WinMaximizeBtn");
 		mMaxBtn = GUIButton::create(HString(L""), "WinMaximizeBtn");
 		mCloseBtn = GUIButton::create(HString(L""), "WinCloseBtn");
 		mCloseBtn = GUIButton::create(HString(L""), "WinCloseBtn");
-		mSplitterLine = GUITexture::create(GUIImageScaleMode::StretchToFit, getLineStyleType());
+		mSplitterLine = GUITexture::create(TextureScaleMode::StretchToFit, getLineStyleType());
 
 
 		GUILayout* mainLayout = mMainPanel->addNewElement<GUILayoutX>();
 		GUILayout* mainLayout = mMainPanel->addNewElement<GUILayoutX>();
 		mainLayout->addElement(mLogoTexture);
 		mainLayout->addElement(mLogoTexture);

+ 1 - 1
Source/BansheeEditor/Source/BsGUIWindowFrame.cpp

@@ -13,7 +13,7 @@ namespace BansheeEngine
 	}
 	}
 
 
 	GUIWindowFrame::GUIWindowFrame(const String& styleName, const GUIDimensions& dimensions)
 	GUIWindowFrame::GUIWindowFrame(const String& styleName, const GUIDimensions& dimensions)
-		:GUITexture(styleName, HSpriteTexture(), GUIImageScaleMode::StretchToFit, true, dimensions)
+		:GUITexture(styleName, HSpriteTexture(), TextureScaleMode::StretchToFit, true, dimensions)
 	{
 	{
 
 
 	}
 	}

+ 1 - 1
Source/BansheeEditor/Source/BsGUIWindowFrameWidget.cpp

@@ -20,7 +20,7 @@ namespace BansheeEngine
 		setSkin(skin);
 		setSkin(skin);
 
 
 		GUIPanel* backgroundPanel = getPanel()->addNewElement<GUIPanel>(500);
 		GUIPanel* backgroundPanel = getPanel()->addNewElement<GUIPanel>(500);
-		backgroundPanel->addElement(GUITexture::create(GUIImageScaleMode::RepeatToFit,
+		backgroundPanel->addElement(GUITexture::create(TextureScaleMode::RepeatToFit,
 			GUIOptions(GUIOption::flexibleWidth(), GUIOption::flexibleHeight()), "WindowBackground"));
 			GUIOptions(GUIOption::flexibleWidth(), GUIOption::flexibleHeight()), "WindowBackground"));
 
 
 		mWindowFramePanel = getPanel()->addNewElement<GUIPanel>(499);
 		mWindowFramePanel = getPanel()->addNewElement<GUIPanel>(499);

+ 2 - 0
Source/BansheeEngine/CMakeSources.cmake

@@ -78,6 +78,7 @@ set(BS_BANSHEEENGINE_SRC_GUI
 	"Source/BsShortcutKey.cpp"
 	"Source/BsShortcutKey.cpp"
 	"Source/BsShortcutManager.cpp"
 	"Source/BsShortcutManager.cpp"
 	"Source/BsCGUIWidget.cpp"
 	"Source/BsCGUIWidget.cpp"
+	"Source/BsGUICanvas.cpp"
 )
 )
 
 
 set(BS_BANSHEEENGINE_INC_PLATFORM
 set(BS_BANSHEEENGINE_INC_PLATFORM
@@ -259,6 +260,7 @@ set(BS_BANSHEEENGINE_INC_GUI
 	"Include/BsCGUIWidget.h"
 	"Include/BsCGUIWidget.h"
 	"Include/BsShortcutManager.h"
 	"Include/BsShortcutManager.h"
 	"Include/BsShortcutKey.h"
 	"Include/BsShortcutKey.h"
+	"Include/BsGUICanvas.h"
 )
 )
 
 
 set(BS_BANSHEEENGINE_SRC_NOFILTER
 set(BS_BANSHEEENGINE_SRC_NOFILTER

+ 9 - 0
Source/BansheeEngine/Include/BsEnums.h

@@ -35,5 +35,14 @@ namespace BansheeEngine
 		RenType_LitTextured
 		RenType_LitTextured
 	};
 	};
 
 
+	/**	Type of scaling modes for GUI images. */
+	enum class TextureScaleMode
+	{
+		StretchToFit, /**< Image will stretch non-uniformly in all dimensions in order to cover the assigned area fully. */
+		ScaleToFit, /**< Image will scale uniformly until one dimension is aligned with the assigned area. Remaining dimension might have empty space. */
+		CropToFit, /**< Image will scale uniformly until both dimensions are larger or aligned with the assigned area. Remaining dimension might be cropped. */
+		RepeatToFit /**< Image will keep its original size, but will repeat in order to fill the assigned area. */
+	};
+
 	/** @} */
 	/** @} */
 }
 }

+ 207 - 0
Source/BansheeEngine/Include/BsGUICanvas.h

@@ -0,0 +1,207 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsGUIElement.h"
+#include "BsImageSprite.h"
+#include "BsTextSprite.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup GUI
+	 *  @{
+	 */
+
+	/**	
+	 * A GUI element that allows the user to draw custom graphics. All drawn elements relative to the canvas, to its origin
+	 * in the top left corner.
+	 */
+	class BS_EXPORT GUICanvas : public GUIElement
+	{
+	public:
+		/** Returns type name of the GUI element used for finding GUI element styles.  */
+		static const String& getGUITypeName();
+
+		/**
+		 * Creates a new GUI canvas element.
+		 *
+		 * @param[in]	options			Options that allow you to control how is the element positioned and sized. This will
+		 *								override any similar options set by style.
+		 * @param[in]	styleName		Optional style to use for the element. Style will be retrieved from GUISkin of the
+		 *								GUIWidget the element is used on. If not specified default style is used.
+		 */
+		static GUICanvas* create(const GUIOptions& options, const String& styleName = StringUtil::BLANK);
+
+		/**
+		 * Creates a new GUI canvas element.
+		 *
+		 * @param[in]	styleName		Optional style to use for the element. Style will be retrieved from GUISkin of the 
+		 *								GUIWidget the element is used on. If not specified default style is used.
+		 */
+		static GUICanvas* create(const String& styleName = StringUtil::BLANK);
+		
+		/** 
+		 * Draws a line going from @p a to @p b.
+		 *
+		 * @param[in]	a		Starting point of the line, relative to the canvas origin (top-left).
+		 * @param[in]	b		Ending point of the line, relative to the canvas origin (top-left).
+		 * @param[in]	color	Color of the line.
+		 */
+		void drawLine(const Vector2I& a, const Vector2I& b, const Color& color = Color::White);
+
+		/** 
+		 * Draws multiple lines following the path by the provided vertices. First vertex connects to the second vertex,
+		 * and every following vertex connects to the previous vertex.
+		 *
+		 * @param[in]	vertices	Points to use for drawing the line. Must have at least two elements. All points are 
+		 *							relative to the canvas origin (top-left).
+		 * @param[in]	color		Color of the line.
+		 */
+		void drawPolyLine(const Vector<Vector2I>& vertices, const Color& color = Color::White);
+
+		/** 
+		 * Draws a quad with a the provided texture displayed.
+		 *
+		 * @param[in]	texture		Texture to draw.
+		 * @param[in]	area		Position and size of the texture to draw. Position is relative to the canvas origin 
+		 *							(top-left). If size is zero, the default texture size will be used.
+		 * @param[in]	scaleMode	Scale mode to use when sizing the texture. Only relevant if the provided quad size
+		 *							doesn't match the texture size.
+		 * @param[in]	color		Color to tint the drawn texture with.
+		 */
+		void drawTexture(const HSpriteTexture& texture, const Rect2I& area, 
+			TextureScaleMode scaleMode = TextureScaleMode::StretchToFit, const Color& color = Color::White);
+
+		/** 
+		 * Draws a triangle strip. First three vertices are used to form the initial triangle, and every next vertex will
+		 * form a triangle with the previous two.
+		 *
+		 * @param[in]	vertices	A set of points defining the triangles. Must have at least three elements. All points
+		 *							are relative to the canvas origin (top-left).
+		 * @param[in]	color		Color of the triangles.
+		 */
+		void drawTriangleStrip(const Vector<Vector2I>& vertices, const Color& color = Color::White);
+
+		/** 
+		 * Draws a triangle list. Every three vertices in the list represent a unique triangle.
+		 *
+		 * @param[in]	vertices	A set of points defining the triangles. Must have at least three elements, and its size
+		 *							must be a multiple of three.
+		 * @param[in]	color		Color of the triangles.
+		 */
+		void drawTriangleList(const Vector<Vector2I>& vertices, const Color& color = Color::White);
+
+		/**
+		 * Draws a piece of text with the wanted font. The text will be aligned to the top-left corner of the provided
+		 * position, and will not be word wrapped.
+		 *
+		 * @param[in]	text		Text to draw.
+		 * @param[in]	position	Position of the text to draw. This represents the top-left corner of the text. It is
+		 *							relative to the canvas origin (top-left).
+		 * @param[in]	size		Size of the font.
+		 * @param[in]	color		Color of the text.
+		 */
+		void drawText(const WString& text, const Vector2I& position, const HFont& font, UINT32 size = 10, 
+			const Color& color = Color::White);
+
+		/** Clears the canvas, removing any previously drawn elements. */
+		void clear();
+
+	public: // ***** INTERNAL ******
+		/** @name Internal
+		 *  @{
+		 */
+
+		/** @copydoc GUIElement::_getOptimalSize */
+		Vector2I _getOptimalSize() const override;
+
+		/** @} */
+	protected:
+		/** Type of elements that may be drawn on the canvas. */
+		enum class CanvasElementType
+		{
+			Line,
+			Triangle,
+			Image,
+			Text
+		};
+
+		/** Represents a single element drawn by the canvas. */
+		struct CanvasElement
+		{
+			CanvasElementType type;
+			Color color;
+
+			union
+			{
+				ImageSprite* imageSprite;
+				UINT32 imageDataId;
+				TextureScaleMode scaleMode;
+			};
+
+			union
+			{
+				UINT32 vertexStart;
+				UINT32 numVertices;
+			};
+
+			union
+			{
+				TextSprite* textSprite;
+				UINT32 textDataId;
+				UINT32 size;
+			};
+		};
+
+		/** Information required for drawing a text canvas element. */
+		struct TextElementData
+		{
+			WString string;
+			HFont font;
+			Vector2I position;
+		};
+
+		/** Information required for drawing an image canvas element. */
+		struct ImageElementData
+		{
+			HSpriteTexture texture;
+			Rect2I area;
+		};
+
+		GUICanvas(const String& styleName, const GUIDimensions& dimensions);
+		virtual ~GUICanvas();
+
+		/** @copydoc GUIElement::_getNumRenderElements */
+		UINT32 _getNumRenderElements() const override;
+
+		/** @copydoc GUIElement::_getMaterial */
+		const SpriteMaterialInfo& _getMaterial(UINT32 renderElementIdx) const override;
+
+		/** @copydoc GUIElement::_getNumQuads */
+		UINT32 _getNumQuads(UINT32 renderElementIdx) const override;
+
+		/** @copydoc GUIElement::_fillBuffer */
+		void _fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, 
+			UINT32 maxNumQuads, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const override;
+
+		/** @copydoc GUIElement::updateRenderElementsInternal */
+		void updateRenderElementsInternal() override;
+
+		/** Build an image sprite from the provided canvas element. */
+		void buildImageElement(const CanvasElement& element);
+
+		/** Build a text sprite from the provided canvas element. */
+		void buildTextElement(const CanvasElement& element);
+
+		Vector<CanvasElement> mElements;
+
+		Vector<ImageElementData> mImageData;
+		Vector<TextElementData> mTextData;
+		Vector<Vector2I> mVertexData;
+
+		Vector2I* mOutVertices;
+	};
+
+	/** @} */
+}

+ 3 - 3
Source/BansheeEngine/Include/BsGUIElement.h

@@ -47,7 +47,7 @@ namespace BansheeEngine
 		virtual void setTint(const Color& color);
 		virtual void setTint(const Color& color);
 
 
 		/** @copydoc GUIElementBase::resetDimensions */
 		/** @copydoc GUIElementBase::resetDimensions */
-		virtual void resetDimensions() override;
+		void resetDimensions() override;
 
 
 		/**	Sets new style to be used by the element. */
 		/**	Sets new style to be used by the element. */
 		void setStyle(const String& styleName);
 		void setStyle(const String& styleName);
@@ -181,10 +181,10 @@ namespace BansheeEngine
 		UINT8 _getElementDepth() const;
 		UINT8 _getElementDepth() const;
 
 
 		/** @copydoc GUIElementBase::_setLayoutData */
 		/** @copydoc GUIElementBase::_setLayoutData */
-		virtual void _setLayoutData(const GUILayoutData& data) override;
+		void _setLayoutData(const GUILayoutData& data) override;
 
 
 		/** @copydoc GUIElementBase::_changeParentWidget */
 		/** @copydoc GUIElementBase::_changeParentWidget */
-		virtual void _changeParentWidget(GUIWidget* widget) override;
+		void _changeParentWidget(GUIWidget* widget) override;
 
 
 		/**
 		/**
 		 * Returns depth for a specific render element. This contains a combination of widget depth (8 bit(, area depth
 		 * Returns depth for a specific render element. This contains a combination of widget depth (8 bit(, area depth

+ 16 - 25
Source/BansheeEngine/Include/BsGUITexture.h

@@ -12,15 +12,6 @@ namespace BansheeEngine
 	 *  @{
 	 *  @{
 	 */
 	 */
 
 
-	/**	Type of scaling modes for GUI images. */
-	enum class GUIImageScaleMode
-	{
-		StretchToFit, /**< Image will stretch non-uniformly in all dimensions in order to cover the assigned area fully. */
-		ScaleToFit, /**< Image will scale uniformly until one dimension is aligned with the assigned area. Remaining dimension might have empty space. */
-		CropToFit, /**< Image will scale uniformly until both dimensions are larger or aligned with the assigned area. Remaining dimension might be cropped. */
-		RepeatToFit /**< Image will keep its original size, but will repeat in order to fill the assigned area. */
-	};
-
 	/**	A GUI element that displays a texture. */
 	/**	A GUI element that displays a texture. */
 	class BS_EXPORT GUITexture : public GUIElement
 	class BS_EXPORT GUITexture : public GUIElement
 	{
 	{
@@ -40,7 +31,7 @@ namespace BansheeEngine
 		 * @param[in]	styleName		Optional style to use for the element. Style will be retrieved from GUISkin of the
 		 * @param[in]	styleName		Optional style to use for the element. Style will be retrieved from GUISkin of the
 		 *								GUIWidget the element is used on. If not specified default style is used.
 		 *								GUIWidget the element is used on. If not specified default style is used.
 		 */
 		 */
-		static GUITexture* create(const HSpriteTexture& texture, GUIImageScaleMode scale, bool transparent,
+		static GUITexture* create(const HSpriteTexture& texture, TextureScaleMode scale, bool transparent,
 			const GUIOptions& options, const String& styleName = StringUtil::BLANK);
 			const GUIOptions& options, const String& styleName = StringUtil::BLANK);
 
 
 		/**
 		/**
@@ -53,7 +44,7 @@ namespace BansheeEngine
 		 * @param[in]	styleName		Optional style to use for the element. Style will be retrieved from GUISkin of the 
 		 * @param[in]	styleName		Optional style to use for the element. Style will be retrieved from GUISkin of the 
 		 *								GUIWidget the element is used on. If not specified default style is used.
 		 *								GUIWidget the element is used on. If not specified default style is used.
 		 */
 		 */
-		static GUITexture* create(const HSpriteTexture& texture, GUIImageScaleMode scale, bool transparent,
+		static GUITexture* create(const HSpriteTexture& texture, TextureScaleMode scale, bool transparent,
 			const String& styleName = StringUtil::BLANK);
 			const String& styleName = StringUtil::BLANK);
 
 
 		/**
 		/**
@@ -67,7 +58,7 @@ namespace BansheeEngine
 		 * @param[in]	styleName		Optional style to use for the element. Style will be retrieved from GUISkin of the
 		 * @param[in]	styleName		Optional style to use for the element. Style will be retrieved from GUISkin of the
 		 *								GUIWidget the element is used on. If not specified default style is used.
 		 *								GUIWidget the element is used on. If not specified default style is used.
 		 */
 		 */
-		static GUITexture* create(const HSpriteTexture& texture, GUIImageScaleMode scale, 
+		static GUITexture* create(const HSpriteTexture& texture, TextureScaleMode scale, 
 			const GUIOptions& options, const String& styleName = StringUtil::BLANK);
 			const GUIOptions& options, const String& styleName = StringUtil::BLANK);
 
 
 		/**
 		/**
@@ -79,7 +70,7 @@ namespace BansheeEngine
 		 * @param[in]	styleName		Optional style to use for the element. Style will be retrieved from GUISkin of the
 		 * @param[in]	styleName		Optional style to use for the element. Style will be retrieved from GUISkin of the
 		 *								GUIWidget the element is used on. If not specified default style is used.
 		 *								GUIWidget the element is used on. If not specified default style is used.
 		 */
 		 */
-		static GUITexture* create(const HSpriteTexture& texture, GUIImageScaleMode scale, 
+		static GUITexture* create(const HSpriteTexture& texture, TextureScaleMode scale, 
 			const String& styleName = StringUtil::BLANK);
 			const String& styleName = StringUtil::BLANK);
 
 
 		/**
 		/**
@@ -114,7 +105,7 @@ namespace BansheeEngine
 		 * @param[in]	styleName		Optional style to use for the element. Style will be retrieved from GUISkin of the
 		 * @param[in]	styleName		Optional style to use for the element. Style will be retrieved from GUISkin of the
 		 *								GUIWidget the element is used on. If not specified default style is used.
 		 *								GUIWidget the element is used on. If not specified default style is used.
 		 */
 		 */
-		static GUITexture* create(GUIImageScaleMode scale, const GUIOptions& options, 
+		static GUITexture* create(TextureScaleMode scale, const GUIOptions& options, 
 			const String& styleName = StringUtil::BLANK);
 			const String& styleName = StringUtil::BLANK);
 
 
 		/**
 		/**
@@ -124,7 +115,7 @@ namespace BansheeEngine
 		 * @param[in]	styleName		Optional style to use for the element. Style will be retrieved from GUISkin of the
 		 * @param[in]	styleName		Optional style to use for the element. Style will be retrieved from GUISkin of the
 		 *								GUIWidget the element is used on. If not specified default style is used.
 		 *								GUIWidget the element is used on. If not specified default style is used.
 		 */
 		 */
-		static GUITexture* create(GUIImageScaleMode scale, const String& styleName = StringUtil::BLANK);
+		static GUITexture* create(TextureScaleMode scale, const String& styleName = StringUtil::BLANK);
 
 
 		/**
 		/**
 		 * Creates a new GUI texture element. Uses the "normal" texture from the active GUI element style.
 		 * Creates a new GUI texture element. Uses the "normal" texture from the active GUI element style.
@@ -157,40 +148,40 @@ namespace BansheeEngine
 		 */
 		 */
 
 
 		/** @copydoc GUIElement::_getElementType */
 		/** @copydoc GUIElement::_getElementType */
-		virtual ElementType _getElementType() const override { return ElementType::Texture; }
+		ElementType _getElementType() const override { return ElementType::Texture; }
 
 
 		/** @copydoc GUIElement::_getOptimalSize */
 		/** @copydoc GUIElement::_getOptimalSize */
-		virtual Vector2I _getOptimalSize() const override;
+		Vector2I _getOptimalSize() const override;
 
 
 		/** @} */
 		/** @} */
 	protected:
 	protected:
-		GUITexture(const String& styleName, const HSpriteTexture& texture, GUIImageScaleMode scale, 
+		GUITexture(const String& styleName, const HSpriteTexture& texture, TextureScaleMode scale, 
 			bool transparent, const GUIDimensions& dimensions);
 			bool transparent, const GUIDimensions& dimensions);
 		virtual ~GUITexture();
 		virtual ~GUITexture();
 
 
 		/** @copydoc GUIElement::_getNumRenderElements */
 		/** @copydoc GUIElement::_getNumRenderElements */
-		virtual UINT32 _getNumRenderElements() const override;
+		UINT32 _getNumRenderElements() const override;
 
 
 		/** @copydoc GUIElement::_getMaterial */
 		/** @copydoc GUIElement::_getMaterial */
-		virtual const SpriteMaterialInfo& _getMaterial(UINT32 renderElementIdx) const override;
+		const SpriteMaterialInfo& _getMaterial(UINT32 renderElementIdx) const override;
 
 
 		/** @copydoc GUIElement::_getNumQuads */
 		/** @copydoc GUIElement::_getNumQuads */
-		virtual UINT32 _getNumQuads(UINT32 renderElementIdx) const override;
+		UINT32 _getNumQuads(UINT32 renderElementIdx) const override;
 
 
 		/** @copydoc GUIElement::_fillBuffer */
 		/** @copydoc GUIElement::_fillBuffer */
-		virtual void _fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, 
+		void _fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, 
 			UINT32 maxNumQuads, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const override;
 			UINT32 maxNumQuads, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const override;
 
 
 		/** @copydoc GUIElement::updateRenderElementsInternal */
 		/** @copydoc GUIElement::updateRenderElementsInternal */
-		virtual void updateRenderElementsInternal() override;
+		void updateRenderElementsInternal() override;
 
 
 		/** @copydoc GUIElement::styleUpdated */
 		/** @copydoc GUIElement::styleUpdated */
-		virtual void styleUpdated() override;
+		void styleUpdated() override;
 
 
 		ImageSprite* mImageSprite;
 		ImageSprite* mImageSprite;
 		HSpriteTexture mActiveTexture;
 		HSpriteTexture mActiveTexture;
 		IMAGE_SPRITE_DESC mDesc;
 		IMAGE_SPRITE_DESC mDesc;
-		GUIImageScaleMode mScaleMode;
+		TextureScaleMode mScaleMode;
 		bool mTransparent;
 		bool mTransparent;
 		bool mUsingStyleTexture;
 		bool mUsingStyleTexture;
 	};
 	};

+ 6 - 0
Source/BansheeEngine/Include/BsImageSprite.h

@@ -56,6 +56,12 @@ namespace BansheeEngine
 		 */
 		 */
 		void update(const IMAGE_SPRITE_DESC& desc, UINT64 groupId);
 		void update(const IMAGE_SPRITE_DESC& desc, UINT64 groupId);
 
 
+		/** 
+		 * Calculates the required UV scale in order for a texture of size @p sourceSize to be placed on the surface
+		 * of @p destSize size, while respecting the chosen scale mode.
+		 */
+		static Vector2 getTextureUVScale(Vector2I sourceSize, Vector2I destSize, TextureScaleMode scaleMode);
+
 	private:
 	private:
 		/**	Clears internal geometry buffers. */
 		/**	Clears internal geometry buffers. */
 		void clearMesh();
 		void clearMesh();

+ 5 - 1
Source/BansheeEngine/Include/BsSprite.h

@@ -36,6 +36,10 @@ namespace BansheeEngine
 	/** Contains information for initializing a sprite material. */
 	/** Contains information for initializing a sprite material. */
 	struct SpriteMaterialInfo
 	struct SpriteMaterialInfo
 	{
 	{
+		SpriteMaterialInfo()
+			:type(SpriteMaterial::Image), groupId(0) 
+		{ }
+
 		/** Generates a hash value that describes the contents of this object. */
 		/** Generates a hash value that describes the contents of this object. */
 		UINT64 generateHash() const;
 		UINT64 generateHash() const;
 
 
@@ -126,7 +130,7 @@ namespace BansheeEngine
 		 * @param[in]	vertexStride		Number of bytes between of vertices in the provided vertex and uv data.
 		 * @param[in]	vertexStride		Number of bytes between of vertices in the provided vertex and uv data.
 		 * @param[in]	indexStride			Number of bytes between two indexes in the provided index data.
 		 * @param[in]	indexStride			Number of bytes between two indexes in the provided index data.
 		 * @param[in]	renderElementIdx	Zero-based index of the render element.
 		 * @param[in]	renderElementIdx	Zero-based index of the render element.
-		 * @param[in]	offset				Position offset to apply to all vertices.
+		 * @param[in]	offset				Position offset to apply to all vertices, after clipping.
 		 * @param[in]	clipRect			Rectangle to clip the vertices to. 
 		 * @param[in]	clipRect			Rectangle to clip the vertices to. 
 		 * @param[in]	clip				Should the vertices be clipped to the provided @p clipRect.
 		 * @param[in]	clip				Should the vertices be clipped to the provided @p clipRect.
 		 *
 		 *

+ 339 - 0
Source/BansheeEngine/Source/BsGUICanvas.cpp

@@ -0,0 +1,339 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsGUICanvas.h"
+#include "BsGUISkin.h"
+#include "BsSpriteTexture.h"
+#include "BsGUIDimensions.h"
+#include "BsGUITexture.h"
+
+namespace BansheeEngine
+{
+	const String& GUICanvas::getGUITypeName()
+	{
+		static String name = "Canvas";
+		return name;
+	}
+
+	GUICanvas::GUICanvas(const String& styleName, const GUIDimensions& dimensions)
+		:GUIElement(styleName, dimensions), mOutVertices(nullptr)
+	{
+
+	}
+
+	GUICanvas::~GUICanvas()
+	{
+		clear();
+	}
+
+	GUICanvas* GUICanvas::create(const GUIOptions& options, const String& styleName)
+	{
+		return new (bs_alloc<GUICanvas>()) GUICanvas(getStyleName<GUICanvas>(styleName), GUIDimensions::create(options));
+	}
+
+	GUICanvas* GUICanvas::create(const String& styleName)
+	{
+		return new (bs_alloc<GUICanvas>()) GUICanvas(getStyleName<GUICanvas>(styleName), GUIDimensions::create());
+	}
+
+	void GUICanvas::drawLine(const Vector2I& a, const Vector2I& b, const Color& color)
+	{
+		mElements.push_back(CanvasElement());
+		CanvasElement& element = mElements.back();
+
+		element.type = CanvasElementType::Line;
+		element.color = color;
+
+		element.vertexStart = (UINT32)mVertexData.size();
+		element.numVertices = 2;
+
+		mVertexData.push_back(a);
+		mVertexData.push_back(b);
+
+		_markContentAsDirty();
+	}
+
+	void GUICanvas::drawPolyLine(const Vector<Vector2I>& vertices, const Color& color)
+	{
+		if(vertices.size() < 2)
+		{
+			LOGWRN("Invalid number of vertices. Ignoring call.");
+			return;
+		}
+
+		mElements.push_back(CanvasElement());
+		CanvasElement& element = mElements.back();
+
+		element.type = CanvasElementType::Line;
+		element.color = color;
+
+		element.vertexStart = (UINT32)mVertexData.size();
+		element.numVertices = vertices.size();
+
+		mVertexData.insert(mVertexData.end(), vertices.begin(), vertices.end());
+		_markContentAsDirty();
+	}
+
+	void GUICanvas::drawTexture(const HSpriteTexture& texture, const Rect2I& area, TextureScaleMode scaleMode, 
+		const Color& color)
+	{
+		mElements.push_back(CanvasElement());
+		CanvasElement& element = mElements.back();
+
+		element.type = CanvasElementType::Image;
+		element.color = color;
+		element.imageDataId = (UINT32)mImageData.size();
+		element.scaleMode = scaleMode;
+		element.imageSprite = bs_new<ImageSprite>();
+
+		mImageData.push_back({ texture, area });
+		_markContentAsDirty();
+	}
+
+	void GUICanvas::drawTriangleStrip(const Vector<Vector2I>& vertices, const Color& color)
+	{
+		if (vertices.size() < 3)
+		{
+			LOGWRN("Invalid number of vertices. Ignoring call.");
+			return;
+		}
+
+		mElements.push_back(CanvasElement());
+		CanvasElement& element = mElements.back();
+
+		element.type = CanvasElementType::Triangle;
+		element.color = color;
+
+		element.vertexStart = (UINT32)mVertexData.size();
+		element.numVertices = (UINT32)(vertices.size() - 2) * 3;
+
+		// Convert strip to list
+		for(UINT32 i = 2; i < (UINT32)vertices.size(); i++)
+		{
+			mVertexData.push_back(vertices[i - 2]);
+			mVertexData.push_back(vertices[i - 1]);
+			mVertexData.push_back(vertices[i - 0]);
+		}
+
+		_markContentAsDirty();
+	}
+
+	void GUICanvas::drawTriangleList(const Vector<Vector2I>& vertices, const Color& color)
+	{
+		if (vertices.size() < 3 || vertices.size() % 3 != 0)
+		{
+			LOGWRN("Invalid number of vertices. Ignoring call.");
+			return;
+		}
+
+		mElements.push_back(CanvasElement());
+		CanvasElement& element = mElements.back();
+
+		element.type = CanvasElementType::Triangle;
+		element.color = color;
+
+		element.vertexStart = (UINT32)mVertexData.size();
+		element.numVertices = (UINT32)vertices.size();
+
+		mVertexData.insert(mVertexData.end(), vertices.begin(), vertices.end());
+		_markContentAsDirty();
+	}
+
+	void GUICanvas::drawText(const WString& text, const Vector2I& position, const HFont& font, UINT32 size, 
+		const Color& color)
+	{
+		mElements.push_back(CanvasElement());
+		CanvasElement& element = mElements.back();
+
+		element.type = CanvasElementType::Text;
+		element.color = color;
+		element.textDataId = (UINT32)mTextData.size();
+		element.size = size;
+		element.textSprite = bs_new<TextSprite>();
+
+		mTextData.push_back({ text, font, position });
+		_markContentAsDirty();
+	}
+
+	void GUICanvas::clear()
+	{
+		bs_delete(mOutVertices);
+		mOutVertices = nullptr;
+
+		for (auto& element : mElements)
+		{
+			if(element.imageSprite != nullptr)
+				bs_delete(element.imageSprite);
+		}
+
+		mElements.clear();
+
+		mVertexData.clear();
+		mImageData.clear();
+		mTextData.clear();
+	}
+
+	UINT32 GUICanvas::_getNumRenderElements() const
+	{
+		return (UINT32)mElements.size();
+	}
+
+	const SpriteMaterialInfo& GUICanvas::_getMaterial(UINT32 renderElementIdx) const
+	{
+		static const SpriteMaterialInfo defaultMatInfo;
+
+		const CanvasElement& element = mElements[renderElementIdx];
+		switch (element.type)
+		{
+		case CanvasElementType::Line:
+			// TODO
+			return defaultMatInfo;
+		case CanvasElementType::Image:
+			return element.imageSprite->getMaterialInfo(renderElementIdx);
+		case CanvasElementType::Text:
+			return element.textSprite->getMaterialInfo(renderElementIdx);
+		case CanvasElementType::Triangle:
+			// TODO
+			return defaultMatInfo;
+		default:
+			return defaultMatInfo;
+		}
+	}
+
+	UINT32 GUICanvas::_getNumQuads(UINT32 renderElementIdx) const
+	{
+		// TODO - This needs to be refactored to return triangle count instead
+
+		const CanvasElement& element = mElements[renderElementIdx];
+		switch (element.type)
+		{
+		case CanvasElementType::Line:
+			// TODO
+			return 0;
+		case CanvasElementType::Image:
+			return element.imageSprite->getNumQuads(renderElementIdx);
+		case CanvasElementType::Text:
+			return element.textSprite->getNumQuads(renderElementIdx);
+		case CanvasElementType::Triangle:
+			// TODO
+			return 0;
+		default:
+			return 0;
+		}
+	}
+
+	void GUICanvas::updateRenderElementsInternal()
+	{
+		bs_delete(mOutVertices);
+		mOutVertices = nullptr;
+
+		for(auto& element : mElements)
+		{
+			switch(element.type)
+			{
+			case CanvasElementType::Line:
+				// TODO
+				break;
+			case CanvasElementType::Image:
+				buildImageElement(element);
+				break;
+			case CanvasElementType::Text:
+				buildTextElement(element);
+				break;
+			case CanvasElementType::Triangle:
+				// TODO
+				break;
+			}
+		}
+
+		GUIElement::updateRenderElementsInternal();
+	}
+
+	void GUICanvas::buildImageElement(const CanvasElement& element)
+	{
+		assert(element.type == CanvasElementType::Image);
+
+		const ImageElementData& imageData = mImageData[element.imageDataId];
+
+		IMAGE_SPRITE_DESC desc;
+		desc.width = imageData.area.width;
+		desc.height = imageData.area.height;
+
+		desc.transparent = true;
+		desc.color = element.color;
+
+		Vector2I textureSize;
+		if (SpriteTexture::checkIsLoaded(imageData.texture))
+		{
+			desc.texture = imageData.texture.getInternalPtr();
+			textureSize.x = desc.texture->getWidth();
+			textureSize.y = desc.texture->getHeight();
+		}
+
+		Vector2I destSize(mLayoutData.area.width, mLayoutData.area.height);
+		desc.uvScale = ImageSprite::getTextureUVScale(textureSize, destSize, element.scaleMode);
+
+		element.imageSprite->update(desc, (UINT64)_getParentWidget());
+	}
+
+	void GUICanvas::buildTextElement(const CanvasElement& element)
+	{
+		assert(element.type == CanvasElementType::Text);
+
+		const TextElementData& textData = mTextData[element.textDataId];
+
+		TEXT_SPRITE_DESC desc;
+		desc.font = textData.font;
+		desc.fontSize = element.size;
+		desc.text = textData.string;
+		desc.color = element.color;
+
+		element.textSprite->update(desc, (UINT64)_getParentWidget());
+	}
+
+	Vector2I GUICanvas::_getOptimalSize() const
+	{
+		return Vector2I(10, 10);
+	}
+
+	void GUICanvas::_fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads,
+		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
+	{
+		const CanvasElement& element = mElements[renderElementIdx];
+
+		Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
+		Rect2I clipRect = mLayoutData.getLocalClipRect();
+		switch(element.type)
+		{
+		case CanvasElementType::Line:
+			// TODO - Handle offset and clipping, output vertices
+			break;
+		case CanvasElementType::Image:
+		{
+			const Rect2I& area = mImageData[element.imageDataId].area;
+
+			offset.x += area.x;
+			offset.y += area.y;
+			clipRect.x -= area.x;
+			clipRect.y -= area.y;
+
+			element.imageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads,
+				vertexStride, indexStride, renderElementIdx, offset, clipRect);
+		}
+			break;
+		case CanvasElementType::Text:
+		{
+			const Vector2I& position = mTextData[element.textDataId].position;
+			offset += position;
+			clipRect.x += position.x;
+			clipRect.y += position.y;
+
+			element.textSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads,
+				vertexStride, indexStride, renderElementIdx, offset, mLayoutData.getLocalClipRect());
+		}
+			break;
+		case CanvasElementType::Triangle:
+			// TODO - Handle offset and clipping, output vertices
+			break;
+		}
+	}
+}

+ 1 - 1
Source/BansheeEngine/Source/BsGUIDropDownContent.cpp

@@ -121,7 +121,7 @@ namespace BansheeEngine
 
 
 			if (element.isSeparator())
 			if (element.isSeparator())
 			{
 			{
-				visElem.separator = GUITexture::create(GUIImageScaleMode::StretchToFit, getSubStyleName(SEPARATOR_STYLE_TYPE));
+				visElem.separator = GUITexture::create(TextureScaleMode::StretchToFit, getSubStyleName(SEPARATOR_STYLE_TYPE));
 				_registerChildElement(visElem.separator);
 				_registerChildElement(visElem.separator);
 			}
 			}
 			else if (element.isSubMenu())
 			else if (element.isSubMenu())

+ 1 - 1
Source/BansheeEngine/Source/BsGUIDropDownMenu.cpp

@@ -211,7 +211,7 @@ namespace BansheeEngine
 
 
 		GUILayout* backgroundLayout = mBackgroundPanel->addNewElement<GUILayoutX>();
 		GUILayout* backgroundLayout = mBackgroundPanel->addNewElement<GUILayoutX>();
 
 
-		mBackgroundFrame = GUITexture::create(GUIImageScaleMode::StretchToFit, mOwner->mBackgroundStyle);
+		mBackgroundFrame = GUITexture::create(TextureScaleMode::StretchToFit, mOwner->mBackgroundStyle);
 		backgroundLayout->addElement(mBackgroundFrame);
 		backgroundLayout->addElement(mBackgroundFrame);
 
 
 		mContentLayout = mContentPanel->addNewElement<GUILayoutY>();
 		mContentLayout = mContentPanel->addNewElement<GUILayoutY>();

+ 1 - 1
Source/BansheeEngine/Source/BsGUIRenderTexture.cpp

@@ -15,7 +15,7 @@ namespace BansheeEngine
 
 
 	GUIRenderTexture::GUIRenderTexture(const String& styleName, const SPtr<RenderTexture>& texture, bool transparent, 
 	GUIRenderTexture::GUIRenderTexture(const String& styleName, const SPtr<RenderTexture>& texture, bool transparent, 
 		const GUIDimensions& dimensions)
 		const GUIDimensions& dimensions)
-		:GUITexture(styleName, HSpriteTexture(), GUIImageScaleMode::StretchToFit, false, dimensions), mTransparent(transparent)
+		:GUITexture(styleName, HSpriteTexture(), TextureScaleMode::StretchToFit, false, dimensions), mTransparent(transparent)
 	{
 	{
 		setRenderTexture(texture);
 		setRenderTexture(texture);
 	}
 	}

+ 17 - 60
Source/BansheeEngine/Source/BsGUITexture.cpp

@@ -15,7 +15,7 @@ namespace BansheeEngine
 	}
 	}
 
 
 	GUITexture::GUITexture(const String& styleName, const HSpriteTexture& texture, 
 	GUITexture::GUITexture(const String& styleName, const HSpriteTexture& texture, 
-		GUIImageScaleMode scale, bool transparent, const GUIDimensions& dimensions)
+		TextureScaleMode scale, bool transparent, const GUIDimensions& dimensions)
 		:GUIElement(styleName, dimensions), mScaleMode(scale), mTransparent(transparent), mUsingStyleTexture(false)
 		:GUIElement(styleName, dimensions), mScaleMode(scale), mTransparent(transparent), mUsingStyleTexture(false)
 	{
 	{
 		mImageSprite = bs_new<ImageSprite>();
 		mImageSprite = bs_new<ImageSprite>();
@@ -37,28 +37,28 @@ namespace BansheeEngine
 		bs_delete(mImageSprite);
 		bs_delete(mImageSprite);
 	}
 	}
 
 
-	GUITexture* GUITexture::create(const HSpriteTexture& texture, GUIImageScaleMode scale, bool transparent,
+	GUITexture* GUITexture::create(const HSpriteTexture& texture, TextureScaleMode scale, bool transparent,
 		const GUIOptions& options, const String& styleName)
 		const GUIOptions& options, const String& styleName)
 	{
 	{
 		return new (bs_alloc<GUITexture>()) GUITexture(getStyleName<GUITexture>(styleName),
 		return new (bs_alloc<GUITexture>()) GUITexture(getStyleName<GUITexture>(styleName),
 			texture, scale, transparent, GUIDimensions::create(options));
 			texture, scale, transparent, GUIDimensions::create(options));
 	}
 	}
 
 
-	GUITexture* GUITexture::create(const HSpriteTexture& texture, GUIImageScaleMode scale, bool transparent,
+	GUITexture* GUITexture::create(const HSpriteTexture& texture, TextureScaleMode scale, bool transparent,
 		const String& styleName)
 		const String& styleName)
 	{
 	{
 		return new (bs_alloc<GUITexture>()) GUITexture(getStyleName<GUITexture>(styleName),
 		return new (bs_alloc<GUITexture>()) GUITexture(getStyleName<GUITexture>(styleName),
 			texture, scale, transparent, GUIDimensions::create());
 			texture, scale, transparent, GUIDimensions::create());
 	}
 	}
 
 
-	GUITexture* GUITexture::create(const HSpriteTexture& texture, GUIImageScaleMode scale, 
+	GUITexture* GUITexture::create(const HSpriteTexture& texture, TextureScaleMode scale, 
 		const GUIOptions& options, const String& styleName)
 		const GUIOptions& options, const String& styleName)
 	{
 	{
 		return new (bs_alloc<GUITexture>()) GUITexture(getStyleName<GUITexture>(styleName), 
 		return new (bs_alloc<GUITexture>()) GUITexture(getStyleName<GUITexture>(styleName), 
 			texture, scale, true, GUIDimensions::create(options));
 			texture, scale, true, GUIDimensions::create(options));
 	}
 	}
 
 
-	GUITexture* GUITexture::create(const HSpriteTexture& texture, GUIImageScaleMode scale, 
+	GUITexture* GUITexture::create(const HSpriteTexture& texture, TextureScaleMode scale, 
 		const String& styleName)
 		const String& styleName)
 	{
 	{
 		return new (bs_alloc<GUITexture>()) GUITexture(getStyleName<GUITexture>(styleName), 
 		return new (bs_alloc<GUITexture>()) GUITexture(getStyleName<GUITexture>(styleName), 
@@ -69,22 +69,22 @@ namespace BansheeEngine
 		const GUIOptions& options, const String& styleName)
 		const GUIOptions& options, const String& styleName)
 	{
 	{
 		return new (bs_alloc<GUITexture>()) GUITexture(getStyleName<GUITexture>(styleName), 
 		return new (bs_alloc<GUITexture>()) GUITexture(getStyleName<GUITexture>(styleName), 
-			texture, GUIImageScaleMode::StretchToFit, true, GUIDimensions::create(options));
+			texture, TextureScaleMode::StretchToFit, true, GUIDimensions::create(options));
 	}
 	}
 
 
 	GUITexture* GUITexture::create(const HSpriteTexture& texture, const String& styleName)
 	GUITexture* GUITexture::create(const HSpriteTexture& texture, const String& styleName)
 	{
 	{
 		return new (bs_alloc<GUITexture>()) GUITexture(getStyleName<GUITexture>(styleName),
 		return new (bs_alloc<GUITexture>()) GUITexture(getStyleName<GUITexture>(styleName),
-			texture, GUIImageScaleMode::StretchToFit, true, GUIDimensions::create());
+			texture, TextureScaleMode::StretchToFit, true, GUIDimensions::create());
 	}
 	}
 
 
-	GUITexture* GUITexture::create(GUIImageScaleMode scale, const GUIOptions& options, const String& styleName)
+	GUITexture* GUITexture::create(TextureScaleMode scale, const GUIOptions& options, const String& styleName)
 	{
 	{
 		return new (bs_alloc<GUITexture>()) GUITexture(getStyleName<GUITexture>(styleName), 
 		return new (bs_alloc<GUITexture>()) GUITexture(getStyleName<GUITexture>(styleName), 
 			HSpriteTexture(), scale, true, GUIDimensions::create(options));
 			HSpriteTexture(), scale, true, GUIDimensions::create(options));
 	}
 	}
 
 
-	GUITexture* GUITexture::create(GUIImageScaleMode scale, const String& styleName)
+	GUITexture* GUITexture::create(TextureScaleMode scale, const String& styleName)
 	{
 	{
 		return new (bs_alloc<GUITexture>()) GUITexture(getStyleName<GUITexture>(styleName), 
 		return new (bs_alloc<GUITexture>()) GUITexture(getStyleName<GUITexture>(styleName), 
 			HSpriteTexture(), scale, true, GUIDimensions::create());
 			HSpriteTexture(), scale, true, GUIDimensions::create());
@@ -93,13 +93,13 @@ namespace BansheeEngine
 	GUITexture* GUITexture::create(const GUIOptions& options, const String& styleName)
 	GUITexture* GUITexture::create(const GUIOptions& options, const String& styleName)
 	{
 	{
 		return new (bs_alloc<GUITexture>()) GUITexture(getStyleName<GUITexture>(styleName), 
 		return new (bs_alloc<GUITexture>()) GUITexture(getStyleName<GUITexture>(styleName), 
-			HSpriteTexture(), GUIImageScaleMode::StretchToFit, true, GUIDimensions::create(options));
+			HSpriteTexture(), TextureScaleMode::StretchToFit, true, GUIDimensions::create(options));
 	}
 	}
 
 
 	GUITexture* GUITexture::create(const String& styleName)
 	GUITexture* GUITexture::create(const String& styleName)
 	{
 	{
 		return new (bs_alloc<GUITexture>()) GUITexture(getStyleName<GUITexture>(styleName), 
 		return new (bs_alloc<GUITexture>()) GUITexture(getStyleName<GUITexture>(styleName), 
-			HSpriteTexture(), GUIImageScaleMode::StretchToFit, true, GUIDimensions::create());
+			HSpriteTexture(), TextureScaleMode::StretchToFit, true, GUIDimensions::create());
 	}
 	}
 
 
 	void GUITexture::setTexture(const HSpriteTexture& texture)
 	void GUITexture::setTexture(const HSpriteTexture& texture)
@@ -143,60 +143,17 @@ namespace BansheeEngine
 		mDesc.transparent = mTransparent;
 		mDesc.transparent = mTransparent;
 		mDesc.color = getTint();
 		mDesc.color = getTint();
 
 
-		float optimalWidth = 0.0f;
-		float optimalHeight = 0.0f;
+		Vector2I textureSize;
 		if (SpriteTexture::checkIsLoaded(mActiveTexture))
 		if (SpriteTexture::checkIsLoaded(mActiveTexture))
 		{
 		{
 			mDesc.texture = mActiveTexture.getInternalPtr();
 			mDesc.texture = mActiveTexture.getInternalPtr();
-			optimalWidth = (float)mDesc.texture->getWidth();
-			optimalHeight = (float)mDesc.texture->getHeight();
-		}
-
-		switch (mScaleMode)
-		{
-		case GUIImageScaleMode::StretchToFit:
-			mDesc.uvScale = Vector2(1.0f, 1.0f);
-			break;
-		case GUIImageScaleMode::ScaleToFit:
-			mDesc.uvScale.x = optimalWidth / mLayoutData.area.width;
-			mDesc.uvScale.y = optimalHeight / mLayoutData.area.height;
-
-			if(mDesc.uvScale.x < mDesc.uvScale.y)
-			{
-				mDesc.uvScale.x = 1.0f;
-				mDesc.uvScale.y = (mLayoutData.area.width * (optimalHeight / optimalWidth)) / mLayoutData.area.height;
-			}
-			else
-			{
-				mDesc.uvScale.x = (mLayoutData.area.height * (optimalWidth / optimalHeight)) / mLayoutData.area.width;
-				mDesc.uvScale.y = 1.0f;
-			}
-
-			break;
-		case GUIImageScaleMode::CropToFit:
-			mDesc.uvScale.x = optimalWidth / mLayoutData.area.width;
-			mDesc.uvScale.y = optimalHeight / mLayoutData.area.height;
-
-			if(mDesc.uvScale.x < mDesc.uvScale.y)
-			{
-				mDesc.uvScale.x = (mLayoutData.area.height * (optimalWidth / optimalHeight)) / mLayoutData.area.width;
-				mDesc.uvScale.y = 1.0f;
-			}
-			else
-			{
-				mDesc.uvScale.x = 1.0f;
-				mDesc.uvScale.y = (mLayoutData.area.width * (optimalHeight / optimalWidth)) / mLayoutData.area.height;
-			}
-
-			break;
-		case GUIImageScaleMode::RepeatToFit:
-			mDesc.uvScale.x = mLayoutData.area.width / optimalWidth;
-			mDesc.uvScale.y = mLayoutData.area.height / optimalHeight;
-			break;
-		default:
-			break;
+			textureSize.x = mDesc.texture->getWidth();
+			textureSize.y = mDesc.texture->getHeight();
 		}
 		}
 
 
+		Vector2I destSize(mLayoutData.area.width, mLayoutData.area.height);
+		mDesc.uvScale = ImageSprite::getTextureUVScale(textureSize, destSize, mScaleMode);
+		
 		mImageSprite->update(mDesc, (UINT64)_getParentWidget());
 		mImageSprite->update(mDesc, (UINT64)_getParentWidget());
 		
 		
 		GUIElement::updateRenderElementsInternal();
 		GUIElement::updateRenderElementsInternal();

+ 1 - 1
Source/BansheeEngine/Source/BsGUITooltip.cpp

@@ -72,7 +72,7 @@ namespace BansheeEngine
 
 
 		GUILayout* backgroundLayout = backgroundPanel->addNewElement<GUILayoutX>();
 		GUILayout* backgroundLayout = backgroundPanel->addNewElement<GUILayoutX>();
 
 
-		GUITexture* backgroundFrame = GUITexture::create(GUIImageScaleMode::StretchToFit, getFrameStyleName());
+		GUITexture* backgroundFrame = GUITexture::create(TextureScaleMode::StretchToFit, getFrameStyleName());
 		backgroundLayout->addElement(backgroundFrame);
 		backgroundLayout->addElement(backgroundFrame);
 
 
 		GUILayout* contentLayout = contentPanel->addNewElement<GUILayoutY>();
 		GUILayout* contentLayout = contentPanel->addNewElement<GUILayoutY>();

+ 52 - 0
Source/BansheeEngine/Source/BsImageSprite.cpp

@@ -265,4 +265,56 @@ namespace BansheeEngine
 		mCachedRenderElements.clear();
 		mCachedRenderElements.clear();
 		updateBounds();
 		updateBounds();
 	}
 	}
+
+	Vector2 ImageSprite::getTextureUVScale(Vector2I sourceSize, Vector2I destSize, TextureScaleMode scaleMode)
+	{
+		Vector2 uvScale = Vector2(1.0f, 1.0f);
+
+		switch (scaleMode)
+		{
+		case TextureScaleMode::ScaleToFit:
+			uvScale.x = sourceSize.x / (float)destSize.x;
+			uvScale.y = sourceSize.y / (float)destSize.y;
+
+			if (uvScale.x < uvScale.y)
+			{
+				uvScale.x = 1.0f;
+				uvScale.y = (destSize.x * (sourceSize.y / (float)sourceSize.x)) / destSize.y;
+			}
+			else
+			{
+				uvScale.x = (destSize.y * (sourceSize.x / (float)sourceSize.y)) / destSize.x;
+				uvScale.y = 1.0f;
+			}
+
+			break;
+		case TextureScaleMode::CropToFit:
+			uvScale.x = sourceSize.x / (float)destSize.x;
+			uvScale.y = sourceSize.y / (float)destSize.y;
+
+			if (uvScale.x < uvScale.y)
+			{
+				uvScale.x = (destSize.y * (sourceSize.x / (float)sourceSize.y)) / destSize.x;
+				uvScale.y = 1.0f;
+			}
+			else
+			{
+				uvScale.x = 1.0f;
+				uvScale.y = (destSize.x * (sourceSize.y / (float)sourceSize.x)) / destSize.y;
+			}
+
+			break;
+		case TextureScaleMode::RepeatToFit:
+			uvScale.x = destSize.x / (float)sourceSize.x;
+			uvScale.y = destSize.y / (float)sourceSize.y;
+			break;
+		case TextureScaleMode::StretchToFit:
+			// Do nothing, (1.0f, 1.0f) is the default UV scale
+			break;
+		default:
+			break;
+		}
+
+		return uvScale;
+	}
 }
 }

+ 1 - 1
Source/BansheeEngine/Source/BsSplashScreen.cpp

@@ -38,7 +38,7 @@ namespace BansheeEngine
 
 
 		WINDOW_DESC windowDesc;
 		WINDOW_DESC windowDesc;
 		windowDesc.border = WindowBorder::None;
 		windowDesc.border = WindowBorder::None;
-		windowDesc.width = 557;
+		windowDesc.width = 543;
 		windowDesc.height = 680;
 		windowDesc.height = 680;
 		windowDesc.left = -1;
 		windowDesc.left = -1;
 		windowDesc.top = -1;
 		windowDesc.top = -1;

+ 4 - 2
Source/BansheeUtility/Include/BsCrashHandler.h

@@ -17,8 +17,10 @@ namespace BansheeEngine
 
 
 	/** Saves crash data and notifies the user when a crash occurs. */
 	/** Saves crash data and notifies the user when a crash occurs. */
 	// TODO - Crashes are reported in the same process as the main application. This can be a problem if the crash was caused
 	// TODO - Crashes are reported in the same process as the main application. This can be a problem if the crash was caused
-	// by heap. Any further use of the heap by the reporting methods will cause a silent crash, failing to log it. A more appropriate
-	// way of doing it should be to resume another process to actually handle the crash.
+	// by heap. Any further use of the heap by the reporting methods will cause a silent crash, failing to log it. A more
+	// appropriate way of doing it should be to resume another process to actually handle the crash.
+	//  - Perhaps an even better option would be to use a private heap for all engine allocations. So when corruptions does
+	//    happen the crash handler can use the default heap with no issues.
 	class BS_UTILITY_EXPORT CrashHandler
 	class BS_UTILITY_EXPORT CrashHandler
 	{
 	{
 	public:
 	public:

+ 1 - 1
Source/SBansheeEngine/Include/BsScriptGUITexture.h

@@ -25,7 +25,7 @@ namespace BansheeEngine
 		/* 								CLR HOOKS						   		*/
 		/* 								CLR HOOKS						   		*/
 		/************************************************************************/
 		/************************************************************************/
 		static void internal_createInstance(MonoObject* instance, MonoObject* texture, 
 		static void internal_createInstance(MonoObject* instance, MonoObject* texture, 
-			GUIImageScaleMode scale, bool transparent, MonoString* style, MonoArray* guiOptions);
+			TextureScaleMode scale, bool transparent, MonoString* style, MonoArray* guiOptions);
 		static void internal_setTexture(ScriptGUITexture* nativeInstance, MonoObject* texture);
 		static void internal_setTexture(ScriptGUITexture* nativeInstance, MonoObject* texture);
 		static void internal_setTint(ScriptGUITexture* nativeInstance, Color* color);
 		static void internal_setTint(ScriptGUITexture* nativeInstance, Color* color);
 	};
 	};

+ 1 - 1
Source/SBansheeEngine/Source/BsScriptGUITexture.cpp

@@ -32,7 +32,7 @@ namespace BansheeEngine
 	}
 	}
 
 
 	void ScriptGUITexture::internal_createInstance(MonoObject* instance, MonoObject* texture, 
 	void ScriptGUITexture::internal_createInstance(MonoObject* instance, MonoObject* texture, 
-		GUIImageScaleMode scale, bool transparent, MonoString* style, MonoArray* guiOptions)
+		TextureScaleMode scale, bool transparent, MonoString* style, MonoArray* guiOptions)
 	{
 	{
 		GUIOptions options;
 		GUIOptions options;