Browse Source

Use hardware GUI line rendering instead of shader-based one, it didn't look as good as it needed and there were design issues
Started work on GUITimeline element of the animation editor

BearishSun 9 years ago
parent
commit
71b1f79b19
30 changed files with 350 additions and 350 deletions
  1. BIN
      Data/Engine/GUISkin.asset
  2. BIN
      Data/Engine/ResourceManifest.asset
  3. BIN
      Data/Engine/Shaders/SpriteLine.bsl.asset
  4. BIN
      Data/Engine/Timestamp.asset
  5. BIN
      Data/Engine/arial.ttf.asset
  6. 8 124
      Data/Raw/Engine/Shaders/SpriteLine.bsl
  7. 1 1
      Source/BansheeCore/Include/BsInput.h
  8. 3 6
      Source/BansheeEngine/Include/BsGUICanvas.h
  9. 11 0
      Source/BansheeEngine/Include/BsGUIHelper.h
  10. 0 31
      Source/BansheeEngine/Include/BsSpriteMaterials.h
  11. 66 57
      Source/BansheeEngine/Source/BsGUICanvas.cpp
  12. 18 0
      Source/BansheeEngine/Source/BsGUIHelper.cpp
  13. 1 2
      Source/BansheeEngine/Source/BsGUIManager.cpp
  14. 1 40
      Source/BansheeEngine/Source/BsSpriteMaterials.cpp
  15. 1 0
      Source/MBansheeEditor/GUI/EditorStyles.cs
  16. 5 0
      Source/MBansheeEditor/General/Program.cs
  17. 1 0
      Source/MBansheeEditor/MBansheeEditor.csproj
  18. 133 0
      Source/MBansheeEditor/Windows/Animation/GUITimeline.cs
  19. 2 22
      Source/MBansheeEditor/Windows/AnimationWindow.cs
  20. 1 1
      Source/MBansheeEditor/Windows/Library/LibraryWindow.cs
  21. 2 2
      Source/MBansheeEditor/Windows/Scene/SceneWindow.cs
  22. 11 15
      Source/MBansheeEngine/GUI/GUICanvas.cs
  23. 28 3
      Source/MBansheeEngine/GUI/GUIUtility.cs
  24. 2 2
      Source/MBansheeEngine/Input/Input.cs
  25. 1 1
      Source/MBansheeEngine/MBansheeEngine.csproj
  26. 2 2
      Source/SBansheeEngine/CMakeSources.cmake
  27. 2 2
      Source/SBansheeEngine/Include/BsScriptGUICanvas.h
  28. 34 33
      Source/SBansheeEngine/Include/BsScriptGUIUtility.h
  29. 4 5
      Source/SBansheeEngine/Source/BsScriptGUICanvas.cpp
  30. 12 1
      Source/SBansheeEngine/Source/BsScriptGUIUtility.cpp

BIN
Data/Engine/GUISkin.asset


BIN
Data/Engine/ResourceManifest.asset


BIN
Data/Engine/Shaders/SpriteLine.bsl.asset


BIN
Data/Engine/Timestamp.asset


BIN
Data/Engine/arial.ttf.asset


+ 8 - 124
Data/Raw/Engine/Shaders/SpriteLine.bsl

@@ -3,10 +3,8 @@ Parameters =
 	mat4x4 	worldTransform;
 	float	invViewportWidth;
 	float	invViewportHeight;
-	
-	StructBuffer  	linePoints;
-	float 			lineWidth;
-	float4			tint;
+
+	float4	tint;
 };
 
 Technique =
@@ -25,13 +23,14 @@ Technique =
 		DepthRead = false;
 		DepthWrite = false;
 		
+		Multisample = false; // This controls line rendering algorithm
+		AALine = true;
+		
 		Common = 
 		{
 			struct VStoFS
 			{
 				float4 position : SV_POSITION;
-				float2 screenPos : TEXCOORD1;
-				uint lineIdx : LINEIDX;
 			};
 		};
 		
@@ -44,7 +43,6 @@ Technique =
 			struct VertexInput
 			{
 				float2 position : POSITION;
-				uint lineIdx : BLENDINDICES0;
 			};			
 			
 			VStoFS main(VertexInput input)
@@ -56,74 +54,18 @@ Technique =
 
 				VStoFS output;
 				output.position = float4(tfrmdX, tfrmdY, 0, 1);
-				output.screenPos = tfrmdPos.xy;
-				output.lineIdx = input.lineIdx;
-				
+
 				return output;
 			}
 		};
 		
 		Fragment =
 		{
-			StructuredBuffer<float2> linePoints;
-			float lineWidth;
 			float4 tint;
 			
-			float getSquaredDistanceToLine(float2 a, float2 b, float2 pt)
-			{
-				float2 lineDiff = b - a;
-				float sqrdLineLength = dot(lineDiff, lineDiff);
-				
-				float2 pointDiff = pt - a;
-				if(sqrdLineLength < 0.0001f) // a == b
-					return dot(pointDiff, pointDiff);
-				else
-				{
-					float t = clamp(dot(pointDiff, lineDiff / sqrdLineLength), 0, 1);
-					float2 projPoint = a + lineDiff * t;
-					float2 toLineDiff = projPoint - pt;
-					return dot(toLineDiff, toLineDiff);
-				} 
-			}
-
 			float4 main(VStoFS input) : SV_Target
 			{
-				// Get number of lines
-				uint numPoints;
-				uint dummy;
-				linePoints.GetDimensions(numPoints, dummy);
-				
-				uint numLines = numPoints - 1;
-								
-				// Find nearest line
-				//// Distance to current line
-				int lineIdx = (int)input.lineIdx;
-				float2 a = linePoints.Load(lineIdx + 0);				
-				float2 b = linePoints.Load(lineIdx + 1);
-				
-				float sqrdDist = getSquaredDistanceToLine(a, b, input.screenPos);
-
-				//// Distance to previous line
-				int prevLineIdx = max(0, lineIdx - 1);
-				a = linePoints.Load(prevLineIdx + 0);				
-				b = linePoints.Load(prevLineIdx + 1);
-				
-				sqrdDist = min(sqrdDist, getSquaredDistanceToLine(a, b, input.screenPos));
-				
-				//// Distance to next line
-				int nextLineIdx = min((int)numLines - 1, lineIdx + 1);
-				a = linePoints.Load(nextLineIdx + 0);				
-				b = linePoints.Load(nextLineIdx + 1);
-				
-				sqrdDist = min(sqrdDist, getSquaredDistanceToLine(a, b, input.screenPos));
-				
-				float sqrdLineWidth = lineWidth * lineWidth;
-				sqrdDist = max(sqrdDist - sqrdLineWidth, 0.0f);
-				
-				float featherWidth = 1.0f; // When changing this change the width of the line quads as well
-				float filtered = sqrdDist / (featherWidth * featherWidth); // TODO - Use a different filter like Gaussian
-				float weight = 1.0f - clamp(filtered, 0, 1);
-				return float4(tint.rgb, tint.a * weight);
+				return tint;
 			}
 		};
 	};
@@ -152,10 +94,6 @@ Technique =
 			uniform mat4 worldTransform;
 
 			in vec2 bs_position;
-			in int bs_blendindices;
-			
-			out vec2 screenPos;
-			out flat int lineIdx;
 
 			out gl_PerVertex
 			{
@@ -170,72 +108,18 @@ Technique =
 				float tfrmdY = 1.0f - (tfrmdPos.y * invViewportHeight);
 
 				gl_Position = vec4(tfrmdX, tfrmdY, 0, 1);
-				screenPos = tfrmdPos.xy;
-				lineIdx = bs_blendindices;
 			}
 		};
 		
 		Fragment =
 		{
-			uniform samplerBuffer linePoints;
-			uniform float lineWidth;
 			uniform vec4 tint;
 			
-			in vec2 screenPos;
-			in flat int lineIdx;
 			out vec4 fragColor;
-		
-			float getSquaredDistanceToLine(vec2 a, vec2 b, vec2 pt)
-			{
-				vec2 lineDiff = b - a;
-				float sqrdLineLength = dot(lineDiff, lineDiff);
-				
-				vec2 pointDiff = pt - a;
-				if(sqrdLineLength < 0.0001f) // a == b
-					return dot(pointDiff, pointDiff);
-				else
-				{
-					float t = clamp(dot(pointDiff, lineDiff / sqrdLineLength), 0, 1);
-					vec2 projPoint = a + lineDiff * t;
-					vec2 toLineDiff = projPoint - pt;
-					return dot(toLineDiff, toLineDiff);
-				} 
-			}
 
 			void main()
 			{
-				// Get number of lines
-				int numPoints = textureSize(linePoints);
-				int numLines = numPoints - 1;
-								
-				// Find nearest line
-				//// Distance to current line
-				vec2 a = texelFetch(linePoints, lineIdx + 0).xy;				
-				vec2 b = texelFetch(linePoints, lineIdx + 1).xy;
-				
-				float sqrdDist = getSquaredDistanceToLine(a, b, screenPos);
-
-				//// Distance to previous line
-				int prevLineIdx = max(0, lineIdx - 1);
-				a = texelFetch(linePoints, prevLineIdx + 0).xy;				
-				b = texelFetch(linePoints, prevLineIdx + 1).xy;
-				
-				sqrdDist = min(sqrdDist, getSquaredDistanceToLine(a, b, screenPos));
-				
-				//// Distance to next line
-				int nextLineIdx = min(numLines - 1, lineIdx + 1);
-				a = texelFetch(linePoints, nextLineIdx + 0).xy;				
-				b = texelFetch(linePoints, nextLineIdx + 1).xy;
-				
-				sqrdDist = min(sqrdDist, getSquaredDistanceToLine(a, b, screenPos));
-				
-				float sqrdLineWidth = lineWidth * lineWidth;
-				sqrdDist = max(sqrdDist - sqrdLineWidth, 0.0f);
-				
-				float featherWidth = 1.0f; // When changing this change the width of the line quads as well
-				float filtered = sqrdDist / (featherWidth * featherWidth); // TODO - Use a different filter like Gaussian
-				float weight = 1.0f - clamp(filtered, 0, 1);
-				fragColor = vec4(tint.rgb, tint.a * weight);
+				fragColor = tint;
 			}
 		};
 	};

+ 1 - 1
Source/BansheeCore/Include/BsInput.h

@@ -98,7 +98,7 @@ namespace BansheeEngine
 		/** Returns position of the pointer (for example mouse cursor) relative to the screen. */
 		Vector2I getPointerPosition() const;
 
-		/** Returns difference between last and current pointer position. */
+		/** Returns difference between pointer position between current and last frame. */
 		Vector2I getPointerDelta() const { return mPointerDelta; }
 
 		/**

+ 3 - 6
Source/BansheeEngine/Include/BsGUICanvas.h

@@ -46,10 +46,9 @@ namespace BansheeEngine
 		 *
 		 * @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]	width	Width of the line, in pixels.
 		 * @param[in]	color	Color of the line.
 		 */
-		void drawLine(const Vector2I& a, const Vector2I& b, float width = 1.0f, const Color& color = Color::White);
+		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,
@@ -57,10 +56,9 @@ namespace BansheeEngine
 		 *
 		 * @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]	width		Width of the line, in pixels.
 		 * @param[in]	color		Color of the line.
 		 */
-		void drawPolyLine(const Vector<Vector2I>& vertices, float width = 1.0f, const Color& color = Color::White);
+		void drawPolyLine(const Vector<Vector2I>& vertices, const Color& color = Color::White);
 
 		/** 
 		 * Draws a quad with a the provided texture displayed.
@@ -147,7 +145,6 @@ namespace BansheeEngine
 					UINT32 numVertices;
 					mutable UINT32 clippedVertexStart;
 					mutable UINT32 clippedNumVertices;
-					float lineWidth;
 				};
 
 				struct
@@ -231,7 +228,7 @@ namespace BansheeEngine
 		Vector<Vector2> mVertexData;
 
 		mutable Vector<Vector2> mClippedVertices;
-		mutable Vector<Vector3> mClippedLineVertices; // z coordinate = line index
+		mutable Vector<Vector2> mClippedLineVertices;
 		mutable Vector2 mLastOffset;
 		mutable Rect2I mLastClipRect;
 		mutable bool mForceTriangleBuild;

+ 11 - 0
Source/BansheeEngine/Include/BsGUIHelper.h

@@ -49,6 +49,17 @@ namespace BansheeEngine
 		 */
 		static Vector2I calcOptimalContentsSize(const WString& text, const GUIElementStyle& style, 
 			const GUIDimensions& dimensions);
+
+		/**
+		 * Calculates optimal content size for the provided text using the provided font and size. Size is calculated
+		 * without word wrap.
+		 *
+		 * @param[in]	text			Text to calculate the size for.
+		 * @param[in]	font			Font to use for rendering the text.
+		 * @param[in]	fontSize		Size of individual characters in the font, in points.
+		 * @return						Width/height required to display the text, in pixels.
+		 */
+		static Vector2I calcTextSize(const WString& text, const HFont& font, UINT32 fontSize);
 	};
 
 	/** @} */

+ 0 - 31
Source/BansheeEngine/Include/BsSpriteMaterials.h

@@ -37,37 +37,6 @@ namespace BansheeEngine
 	{
 	public:
 		SpriteLineMaterial();
-
-		/** @copydoc SpriteMaterial::getMergeHash */
-		UINT64 getMergeHash(const SpriteMaterialInfo& info) const override;
-
-		/** @copydoc SpriteMaterial::merge */
-		void merge(SpriteMaterialInfo& mergeInto, const SpriteMaterialInfo& mergeFrom) const override;
-
-		/** @copydoc SpriteMaterial::render */
-		void render(const SPtr<MeshCoreBase>& mesh, const SPtr<TextureCore>& texture,
-			const SPtr<SamplerStateCore>& sampler, const Color& tint, const Matrix4& worldTransform,
-			const Vector2& invViewportSize, const SPtr<SpriteMaterialExtraInfo>& additionalData) const override;
-	};
-
-	/** Extra data required by the SpriteLineMaterial. */
-	struct SpriteMaterialLineInfo : SpriteMaterialExtraInfo
-	{
-		/** @copydoc SpriteMaterialLineInfo::clone() */
-		SPtr<SpriteMaterialExtraInfo> clone() const override
-		{
-			SPtr<SpriteMaterialLineInfo> info = bs_shared_ptr_new<SpriteMaterialLineInfo>();
-			info->points = points;
-			info->width = width;
-
-			return info;
-		}
-
-		Vector<Vector2> points;
-		float width;
-
-		// Core thread only
-		SPtr<GpuBufferCore> pointBuffer;
 	};
 
 	/** @} */

+ 66 - 57
Source/BansheeEngine/Source/BsGUICanvas.cpp

@@ -42,12 +42,12 @@ namespace BansheeEngine
 		return new (bs_alloc<GUICanvas>()) GUICanvas(getStyleName<GUICanvas>(styleName), GUIDimensions::create());
 	}
 
-	void GUICanvas::drawLine(const Vector2I& a, const Vector2I& b, float width, const Color& color)
+	void GUICanvas::drawLine(const Vector2I& a, const Vector2I& b, const Color& color)
 	{
-		drawPolyLine({ a, b }, width, color);
+		drawPolyLine({ a, b }, color);
 	}
 
-	void GUICanvas::drawPolyLine(const Vector<Vector2I>& vertices, float width, const Color& color)
+	void GUICanvas::drawPolyLine(const Vector<Vector2I>& vertices, const Color& color)
 	{
 		if(vertices.size() < 2)
 		{
@@ -63,7 +63,6 @@ namespace BansheeEngine
 		element.dataId = (UINT32)mTriangleElementData.size();
 		element.vertexStart = (UINT32)mVertexData.size();
 		element.numVertices = (UINT32)vertices.size();
-		element.lineWidth = width * 0.5f;
 
 		mTriangleElementData.push_back(TriangleElementData());
 		TriangleElementData& elemData = mTriangleElementData.back();
@@ -114,7 +113,6 @@ namespace BansheeEngine
 		element.dataId = (UINT32)mTriangleElementData.size();
 		element.vertexStart = (UINT32)mVertexData.size();
 		element.numVertices = (UINT32)(vertices.size() - 2) * 3;
-		element.lineWidth = 0.0f; // Not used
 
 		// Convert strip to list
 		for(UINT32 i = 2; i < (UINT32)vertices.size(); i++)
@@ -158,7 +156,6 @@ namespace BansheeEngine
 		element.dataId = (UINT32)mTriangleElementData.size();
 		element.vertexStart = (UINT32)mVertexData.size();
 		element.numVertices = (UINT32)vertices.size();
-		element.lineWidth = 0.0f; // Not used
 
 		for (auto& vertex : vertices)
 			mVertexData.push_back(Vector2((float)vertex.x, (float)vertex.y));
@@ -225,6 +222,8 @@ namespace BansheeEngine
 		buildAllTriangleElementsIfDirty(offset, clipRect);
 
 		const CanvasElement& element = findElement(renderElementIdx);
+		renderElementIdx -= element.renderElemStart;
+
 		switch (element.type)
 		{
 		case CanvasElementType::Line:
@@ -234,8 +233,8 @@ namespace BansheeEngine
 			*material = element.imageSprite->getMaterial(0);
 			return element.imageSprite->getMaterialInfo(0);
 		case CanvasElementType::Text:
-			*material = element.imageSprite->getMaterial(renderElementIdx - element.renderElemStart);
-			return element.textSprite->getMaterialInfo(renderElementIdx - element.renderElemStart);
+			*material = element.imageSprite->getMaterial(renderElementIdx);
+			return element.textSprite->getMaterialInfo(renderElementIdx);
 		case CanvasElementType::Triangle:
 			*material = SpriteManager::instance().getImageTransparentMaterial();
 			return mTriangleElementData[element.dataId].matInfo;
@@ -252,6 +251,8 @@ namespace BansheeEngine
 		buildAllTriangleElementsIfDirty(offset, clipRect);
 
 		const CanvasElement& element = findElement(renderElementIdx);
+		renderElementIdx -= element.renderElemStart;
+
 		switch (element.type)
 		{
 		case CanvasElementType::Image:
@@ -260,6 +261,7 @@ namespace BansheeEngine
 			numVertices = numQuads * 4;
 			numIndices = numQuads * 6;
 			type = GUIMeshType::Triangle;
+			break;
 		}
 		case CanvasElementType::Text:
 		{
@@ -267,6 +269,7 @@ namespace BansheeEngine
 			numVertices = numQuads * 4;
 			numIndices = numQuads * 6;
 			type = GUIMeshType::Triangle;
+			break;
 		}
 		case CanvasElementType::Line:
 			numVertices = element.clippedNumVertices;
@@ -338,6 +341,8 @@ namespace BansheeEngine
 		buildAllTriangleElementsIfDirty(floatOffset, clipRect);
 
 		const CanvasElement& element = findElement(renderElementIdx);
+		renderElementIdx -= element.renderElemStart;
+
 		switch(element.type)
 		{
 		case CanvasElementType::Image:
@@ -400,7 +405,7 @@ namespace BansheeEngine
 			break;
 		case CanvasElementType::Line:
 		{
-			UINT32 vertexStride = sizeof(Vector2) + sizeof(UINT32);
+			UINT32 vertexStride = sizeof(Vector2);
 
 			UINT32 startVert = vertexOffset;
 			UINT32 startIndex = indexOffset;
@@ -415,19 +420,15 @@ namespace BansheeEngine
 			assert((startIndex + numIndices) <= maxIndexIdx);
 
 			UINT8* vertDst = vertices + startVert * vertexStride;
-			UINT8* lineIdxDst = vertDst + sizeof(Vector2);
 			UINT32* indexDst = indices + startIndex;
 
 			for (UINT32 i = 0; i < element.clippedNumVertices; i++)
 			{
-				const Vector3& point = mClippedLineVertices[element.clippedVertexStart + i];
-				UINT32 lineIdx = (UINT32)point.z;
+				const Vector2& point = mClippedLineVertices[element.clippedVertexStart + i];
 
 				memcpy(vertDst, &point, sizeof(Vector2));
-				memcpy(lineIdxDst, &lineIdx, sizeof(UINT32));
 
 				vertDst += vertexStride;
-				lineIdxDst += vertexStride;
 				indexDst[i] = i;
 			}
 		}
@@ -503,62 +504,70 @@ namespace BansheeEngine
 		else
 		{
 			UINT32 numLines = element.numVertices - 1;
-
-			UINT8* verticesToClip = (UINT8*)bs_stack_alloc(sizeof(Vector3) * (numLines * 6));
-			UINT32 trianglesToClip = numLines * 2;
-
 			const Vector2* linePoints = &mVertexData[element.vertexStart];
-			ShapeMeshes2D::quadLineList(linePoints, element.numVertices, element.lineWidth, LINE_SMOOTH_BORDER_WIDTH, 
-				verticesToClip, sizeof(Vector3), false);
 
-			SPtr<SpriteMaterialLineInfo> lineInfo = bs_shared_ptr_new<SpriteMaterialLineInfo>();
-			lineInfo->width = element.lineWidth;
-
-			for (UINT32 i = 0; i < element.numVertices; i++)
+			struct Plane2D
 			{
-				Vector2 point = linePoints[i];
-				point += offset; // Move to screen space
-
-				lineInfo->points.push_back(point);
-			}
-
-			TriangleElementData& elemData = mTriangleElementData[element.dataId];
-			elemData.matInfo.additionalData = lineInfo;
+				Plane2D(const Vector2& normal, float d)
+					:normal(normal), d(d)
+				{ }
 
-			// Store line index with each vertex as Z coordinate, so we know which line newly added triangles belong to
-			Vector3* quadVertices = (Vector3*)verticesToClip;
-			for(UINT32 i = 0; i < numLines; i++)
-			{
-				for(UINT32 j = 0; j < 6; j++)
-				{
-					quadVertices->z = (float)i;
-					quadVertices++;
-				}
-			}
-
-			Vector<Plane> clipPlanes =
-			{
-				Plane(Vector3(1.0f, 0.0f, 0.0f), (float)clipRect.x),
-				Plane(Vector3(-1.0f, 0.0f, 0.0f), (float)-(clipRect.x + clipRect.width)),
-				Plane(Vector3(0, 1.0f, 0), (float)(clipRect.y + clipRect.height)),
-				Plane(Vector3(0.0f, -1.0f, 0.0f), (float)-clipRect.y)
+				Vector2 normal;
+				float d;
 			};
 
-			Vector3 offset3D(offset.x, offset.y, 0.0f);
-			auto writeCallback = [&](Vector3* vertices, Vector2* uvs, UINT32 count)
+			std::array<Plane2D, 4> clipPlanes =
 			{
-				for (UINT32 i = 0; i < count; i++)
-					mClippedLineVertices.push_back(vertices[i] + offset3D);
-
-				element.clippedNumVertices += count;
+				Plane2D(Vector2(1.0f, 0.0f), (float)clipRect.x),
+				Plane2D(Vector2(-1.0f, 0.0f), (float)-(clipRect.x + clipRect.width)),
+				Plane2D(Vector2(0.0f, 1.0f), (float)clipRect.y),
+				Plane2D(Vector2(0.0f, -1.0f), (float)-(clipRect.y + clipRect.height))
 			};
 
 			element.clippedVertexStart = (UINT32)mClippedLineVertices.size();
 			element.clippedNumVertices = 0;
 
-			MeshUtility::clip3D(verticesToClip, nullptr, trianglesToClip, sizeof(Vector3), clipPlanes, writeCallback);
+			for (UINT32 i = 0; i < numLines; i++)
+			{
+				Vector2 a = linePoints[i];
+				Vector2 b = linePoints[i + 1];
 
-			bs_stack_free(verticesToClip);
+				bool isVisible = true;
+				for(UINT32 j = 0; j < (UINT32)clipPlanes.size(); j++)
+				{
+					const Plane2D& plane = clipPlanes[j];
+					float d0 = plane.normal.dot(a) - plane.d;
+					float d1 = plane.normal.dot(b) - plane.d;
+
+					// Line not visible
+					if (d0 <= 0 && d1 <= 0)
+					{
+						isVisible = false;
+						break;
+					}
+
+					// Line visible completely
+					if (d0 >= 0 && d1 >= 0)
+						continue;
+
+					// The line is split by the plane, compute the point of intersection.
+					float t = d0 / (d0 - d1);
+					Vector2 intersectPt = (1 - t)*a + t*b;
+
+					if (d0 > 0)
+						b = intersectPt;
+					else
+						a = intersectPt;
+				}
+
+				if (!isVisible)
+					continue;
+
+				mClippedLineVertices.push_back(a + offset);
+				mClippedLineVertices.push_back(b + offset);
+
+				element.clippedNumVertices += 2;
+			}
 		}
 	}
 

+ 18 - 0
Source/BansheeEngine/Source/BsGUIHelper.cpp

@@ -57,4 +57,22 @@ namespace BansheeEngine
 
 		return Vector2I(contentWidth, contentHeight);
 	}
+
+	Vector2I GUIHelper::calcTextSize(const WString& text, const HFont& font, UINT32 fontSize)
+	{
+		Vector2I size;
+		if (font != nullptr)
+		{
+			bs_frame_mark();
+
+			TextData<FrameAlloc> textData(text, font, fontSize, 0, 0, false);
+
+			size.x = textData.getWidth();
+			size.y = textData.getNumLines() * textData.getLineHeight();
+
+			bs_frame_clear();
+		}
+
+		return size;
+	}
 }

+ 1 - 2
Source/BansheeEngine/Source/BsGUIManager.cpp

@@ -108,7 +108,6 @@ namespace BansheeEngine
 
 		mLineVertexDesc = bs_shared_ptr_new<VertexDataDesc>();
 		mLineVertexDesc->addVertElem(VET_FLOAT2, VES_POSITION);
-		mLineVertexDesc->addVertElem(VET_UINT1, VES_BLEND_INDICES);
 
 		mLineMeshHeap = MeshHeap::create(MESH_HEAP_INITIAL_NUM_VERTS, MESH_HEAP_INITIAL_NUM_INDICES, mLineVertexDesc);
 
@@ -724,7 +723,7 @@ namespace BansheeEngine
 						if (guiMeshData.mesh != nullptr)
 							mLineMeshHeap->dealloc(guiMeshData.mesh);
 
-						guiMeshData.mesh = mLineMeshHeap->alloc(meshData);
+						guiMeshData.mesh = mLineMeshHeap->alloc(meshData, DOT_LINE_LIST);
 						lineMeshIdx++;
 					}
 				}

+ 1 - 40
Source/BansheeEngine/Source/BsSpriteMaterials.cpp

@@ -21,44 +21,5 @@ namespace BansheeEngine
 
 	SpriteLineMaterial::SpriteLineMaterial()
 		: SpriteMaterial(3, BuiltinResources::instance().createSpriteLineMaterial())
-	{
-		
-	}
-
-	UINT64 SpriteLineMaterial::getMergeHash(const SpriteMaterialInfo& info) const
-	{
-		size_t hash = SpriteMaterial::getMergeHash(info);
-
-		SPtr<SpriteMaterialLineInfo> extraInfo = std::static_pointer_cast<SpriteMaterialLineInfo>(info.additionalData);
-		hash_combine(hash, extraInfo->width);
-
-		return (UINT64)hash;
-	}
-
-	void SpriteLineMaterial::merge(SpriteMaterialInfo& mergeInto, const SpriteMaterialInfo& mergeFrom) const
-	{
-		SPtr<SpriteMaterialLineInfo> extraInfoDest = std::static_pointer_cast<SpriteMaterialLineInfo>(mergeInto.additionalData);
-		SPtr<SpriteMaterialLineInfo> extraInfoSrc = std::static_pointer_cast<SpriteMaterialLineInfo>(mergeFrom.additionalData);
-
-		extraInfoDest->points.insert(extraInfoDest->points.end(), extraInfoSrc->points.begin(), extraInfoSrc->points.end());
-	}
-
-	void SpriteLineMaterial::render(const SPtr<MeshCoreBase>& mesh, const SPtr<TextureCore>& texture,
-		const SPtr<SamplerStateCore>& sampler, const Color& tint, const Matrix4& worldTransform,
-		const Vector2& invViewportSize, const SPtr<SpriteMaterialExtraInfo>& additionalData) const
-	{
-		SPtr<SpriteMaterialLineInfo> lineInfo = std::static_pointer_cast<SpriteMaterialLineInfo>(additionalData);
-		if(lineInfo->pointBuffer == nullptr)
-		{
-			UINT32 numPoints = (UINT32)lineInfo->points.size();
-			lineInfo->pointBuffer = GpuBufferCore::create(numPoints, 0, GBT_STANDARD, BF_32X2F, GBU_STATIC);
-			lineInfo->pointBuffer->writeData(0, numPoints * sizeof(Vector2), &lineInfo->points[0], BufferWriteType::Discard);
-		}
-		
-		mMaterial->setBuffer("linePoints", lineInfo->pointBuffer);
-		mMaterial->setFloat("lineWidth", lineInfo->width);
-
-		// Note: If the line shader ends up using a more complex filter, generate a filter LUT as a pre-process step
-		SpriteMaterial::render(mesh, texture, sampler, tint, worldTransform, invViewportSize, additionalData);
-	}
+	{ }
 }

+ 1 - 0
Source/MBansheeEditor/GUI/EditorStyles.cs

@@ -12,6 +12,7 @@ namespace BansheeEditor
     /// </summary>
     public static class EditorStyles
     {
+        public const int DefaultFontSize = 8;
         public const string Blank = "Blank";
         public const string Label = "Label";
         public const string LabelCentered = "LabelCentered";

+ 5 - 0
Source/MBansheeEditor/General/Program.cs

@@ -64,6 +64,11 @@ namespace BansheeEditor
      *  @{
      */
 
+    /** @defgroup AnimationEditor Animation Editor 
+     *  Animation editor window and related functionality.
+     *  @{
+     */
+
     /** @defgroup Gizmos Gizmos 
      *  Interface for creating custom gizmos.
      */

+ 1 - 0
Source/MBansheeEditor/MBansheeEditor.csproj

@@ -48,6 +48,7 @@
     <Compile Include="Inspectors\PostProcessSettingsInspector.cs" />
     <Compile Include="Windows\AboutBox.cs" />
     <Compile Include="Windows\AnimationWindow.cs" />
+    <Compile Include="Windows\Animation\GUITimeline.cs" />
     <Compile Include="Windows\BrowseDialog.cs" />
     <Compile Include="Windows\Build\BuildManager.cs" />
     <Compile Include="Windows\Build\BuildWindow.cs" />

+ 133 - 0
Source/MBansheeEditor/Windows/Animation/GUITimeline.cs

@@ -0,0 +1,133 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /** @addtogroup AnimationEditor
+     *  @{
+     */
+
+    // TODO DOC
+    public class GUITimeline
+    {
+        private const float LARGE_TICK_HEIGHT_PCT = 0.5f;
+        private const float SMALL_TICK_HEIGHT_PCT = 0.25f;
+
+        private GUICanvas canvas;
+        private int width;
+        private int height;
+        private float rangeStart = 0.0f;
+        private float rangeEnd = 60.0f;
+        private int fps = 60;
+
+        public GUITimeline(GUILayout layout, int width, int height)
+        {
+            canvas = new GUICanvas();
+            layout.AddElement(canvas);
+
+            SetSize(width, height);
+        }
+
+        public void SetSize(int width, int height)
+        {
+            this.width = width;
+            this.height = height;
+
+            canvas.SetWidth(width);
+            canvas.SetHeight(height);
+
+            Rebuild();
+        }
+
+        public void SetRange(float start, float end)
+        {
+            rangeStart = start;
+            rangeEnd = end;
+
+            Rebuild();
+        }
+
+        public void SetFPS(int fps)
+        {
+            this.fps = fps;
+
+            Rebuild();
+        }
+
+        private void Rebuild()
+        {
+            canvas.Clear();
+
+            canvas.DrawLine(new Vector2I(50, 20), new Vector2I(50, 40), Color.White);
+            canvas.DrawLine(new Vector2I(100, 20), new Vector2I(100, 40), Color.White);
+
+            return;
+
+            // TODO - Calculate interval sizes based on set range, width and FPS
+            //      - Dynamically change tick heights?
+            //      - Draw text (and convert seconds to minutes/hours as needed)
+
+            float largeTickInterval = 50.0f; // TODO - Must be multiple of small tick interval
+            float smallTickInterval = 10.0f; // TODO
+
+            float offsetLarge = MathEx.CeilToInt(rangeStart / largeTickInterval) * largeTickInterval - rangeStart;
+            float offsetSmall = MathEx.CeilToInt(rangeStart / smallTickInterval) * smallTickInterval - rangeStart;
+
+            int largeTickHeight = (int)(height * LARGE_TICK_HEIGHT_PCT);
+            int smallTickHeight = (int)(height * SMALL_TICK_HEIGHT_PCT);
+
+            bool drawSmallTicks = true; // TODO
+
+            float length = rangeEnd - rangeStart;
+            for (float t = offsetSmall; t <= length; t += smallTickInterval)
+            {
+                Debug.Log(t + " - " + length + " - " + width);
+
+                float distanceToLargeTick = MathEx.CeilToInt(t / largeTickInterval) * largeTickInterval - t;
+                if (MathEx.ApproxEquals(distanceToLargeTick, 0.0f))
+                {
+                    int xPos = (int)((t/length)*width);
+
+                    Vector2I start = new Vector2I(xPos, height - largeTickHeight);
+                    Vector2I end = new Vector2I(xPos, height);
+
+                    canvas.DrawLine(start, end, Color.DarkGray);
+
+                    TimeSpan intervalSpan = TimeSpan.FromSeconds(largeTickInterval);
+                    TimeSpan timeSpan = TimeSpan.FromSeconds(rangeStart + t);
+
+                    string timeString;
+                    if(intervalSpan.Minutes > 0)
+                        timeString = timeSpan.ToString(@"m\:ss");
+                    else
+                        timeString = timeSpan.ToString(@"ss\:fff");
+
+                    Vector2I textBounds = GUIUtility.CalculateTextBounds(timeString, Builtin.DefaultFont, 
+                        EditorStyles.DefaultFontSize);
+
+                    Vector2I textPosition = new Vector2I();
+                    textPosition.x = -textBounds.x/2;
+
+                    //canvas.DrawText(timeString, textPosition, Builtin.DefaultFont, Color.DarkGray, 
+                    //    EditorStyles.DefaultFontSize);
+                }
+                else
+                {
+                    if (drawSmallTicks)
+                    {
+                        int xPos = (int)((t / length) * width);
+
+                        Vector2I start = new Vector2I(xPos, height - smallTickHeight);
+                        Vector2I end = new Vector2I(xPos, height);
+
+                        canvas.DrawLine(start, end, Color.LightGray);
+                    }
+                }
+            }
+        }
+    }
+
+    /** @} */
+}

+ 2 - 22
Source/MBansheeEditor/Windows/AnimationWindow.cs

@@ -13,7 +13,7 @@ namespace BansheeEditor
     /// </summary>
     internal class AnimationWindow : EditorWindow
     {
-        private GUICanvas canvas;
+        private GUITimeline timeline;
 
         /// <summary>
         /// Opens the animation window.
@@ -32,27 +32,7 @@ namespace BansheeEditor
 
         private void OnInitialize()
         {
-            canvas = new GUICanvas(GUIOption.FixedWidth(200), GUIOption.FixedHeight(200));
-
-            {
-                Vector2I a = new Vector2I(0, 0);
-                Vector2I b = new Vector2I(200, 0);
-                Vector2I c = new Vector2I(200, 200);
-                Vector2I d = new Vector2I(0, 200);
-
-                canvas.DrawTriangleStrip(new Vector2I[] { b, c, a, d }, Color.BansheeOrange);
-            }
-
-            {
-                Vector2I a = new Vector2I(50, 20);
-                Vector2I b = new Vector2I(100, 20);
-                Vector2I c = new Vector2I(240, 60);
-
-                Vector2I[] vertices = {a, b};
-                canvas.DrawPolyLine(vertices, 1.0f);
-            }
-
-            GUI.AddElement(canvas);
+            timeline = new GUITimeline(GUI, 300, 40);
         }
 
         private void OnEditorUpdate()

+ 1 - 1
Source/MBansheeEditor/Windows/Library/LibraryWindow.cs

@@ -1238,7 +1238,7 @@ namespace BansheeEditor
             StopRename();
 
             Vector2I openPosition;
-            Rect2I buttonBounds = GUILayoutUtility.CalculateBounds(optionsButton, GUI);
+            Rect2I buttonBounds = GUIUtility.CalculateBounds(optionsButton, GUI);
 
             openPosition.x = buttonBounds.x + buttonBounds.width / 2;
             openPosition.y = buttonBounds.y + buttonBounds.height / 2;

+ 2 - 2
Source/MBansheeEditor/Windows/Scene/SceneWindow.cs

@@ -432,7 +432,7 @@ namespace BansheeEditor
             scenePos = screenPos;
             Vector2I windowPos = ScreenToWindowPos(screenPos);
 
-            Rect2I bounds = GUILayoutUtility.CalculateBounds(renderTextureGUI, GUI);
+            Rect2I bounds = GUIUtility.CalculateBounds(renderTextureGUI, GUI);
             if (bounds.Contains(windowPos))
             {
                 scenePos.x = windowPos.x - bounds.x;
@@ -865,7 +865,7 @@ namespace BansheeEditor
 
             Rect2I rtBounds = new Rect2I(0, 0, width, height);
             renderTextureGUI.Bounds = rtBounds;
-            focusCatcher.Bounds = GUILayoutUtility.CalculateBounds(rtPanel, GUI);
+            focusCatcher.Bounds = GUIUtility.CalculateBounds(rtPanel, GUI);
 
             sceneAxesGUI.SetPosition(width - HandleAxesGUISize - HandleAxesGUIPaddingX, HandleAxesGUIPaddingY);
 

+ 11 - 15
Source/MBansheeEngine/GUI/GUICanvas.cs

@@ -54,11 +54,10 @@ namespace BansheeEngine
         /// </summary>
         /// <param name="a">Starting point of the line, relative to the canvas origin (top-left).</param>
         /// <param name="b">Ending point of the line, relative to the canvas origin (top-left).</param>
-        /// <param name="width">Color of the line.</param>
-        public void DrawLine(Vector2I a, Vector2I b, float width = 1.0f)
+        public void DrawLine(Vector2I a, Vector2I b)
         {
             Color color = Color.White;
-            Internal_DrawLine(mCachedPtr, ref a, ref b, width, ref color);
+            Internal_DrawLine(mCachedPtr, ref a, ref b, ref color);
         }
 
         /// <summary>
@@ -66,11 +65,10 @@ namespace BansheeEngine
         /// </summary>
         /// <param name="a">Starting point of the line, relative to the canvas origin (top-left).</param>
         /// <param name="b">Ending point of the line, relative to the canvas origin (top-left).</param>
-        /// <param name="color">Width of the line, in pixels.</param>
-        /// <param name="width">Color of the line.</param>
-        public void DrawLine(Vector2I a, Vector2I b, Color color, float width = 1.0f)
+        /// <param name="color">Color of the line.</param>
+        public void DrawLine(Vector2I a, Vector2I b, Color color)
         {
-            Internal_DrawLine(mCachedPtr, ref a, ref b, width, ref color);
+            Internal_DrawLine(mCachedPtr, ref a, ref b, ref color);
         }
 
         /// <summary>
@@ -79,11 +77,10 @@ namespace BansheeEngine
         /// </summary>
         /// <param name="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>
-        /// <param name="width">Width of the line, in pixels.</param>
-        public void DrawPolyLine(Vector2I[] vertices, float width = 1.0f)
+        public void DrawPolyLine(Vector2I[] vertices)
         {
             Color color = Color.White;
-            Internal_DrawPolyLine(mCachedPtr, vertices, width, ref color);
+            Internal_DrawPolyLine(mCachedPtr, vertices, ref color);
         }
 
         /// <summary>
@@ -93,10 +90,9 @@ namespace BansheeEngine
         /// <param name="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>
         /// <param name="color">Color of the line.</param>
-        /// <param name="width">Width of the line, in pixels.</param>
-        public void DrawPolyLine(Vector2I[] vertices, Color color, float width = 1.0f)
+        public void DrawPolyLine(Vector2I[] vertices, Color color)
         {
-            Internal_DrawPolyLine(mCachedPtr, vertices, width, ref color);
+            Internal_DrawPolyLine(mCachedPtr, vertices, ref color);
         }
 
         /// <summary>
@@ -233,11 +229,11 @@ namespace BansheeEngine
         private static extern void Internal_CreateInstance(GUICanvas instance, string style, GUIOption[] options);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_DrawLine(IntPtr nativeInstance, ref Vector2I a, ref Vector2I b, float width, 
+        private static extern void Internal_DrawLine(IntPtr nativeInstance, ref Vector2I a, ref Vector2I b,
             ref Color color);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_DrawPolyLine(IntPtr nativeInstance, Vector2I[] vertices, float width, 
+        private static extern void Internal_DrawPolyLine(IntPtr nativeInstance, Vector2I[] vertices,
             ref Color color);
 
         [MethodImpl(MethodImplOptions.InternalCall)]

+ 28 - 3
Source/MBansheeEngine/GUI/GUILayoutUtility.cs → Source/MBansheeEngine/GUI/GUIUtility.cs

@@ -10,10 +10,9 @@ namespace BansheeEngine
      */
 
     /// <summary>
-    /// Helper class that performs various operations related to
-    /// GUILayout and GUI element sizing/placement.
+    /// Various helper functionality that's useful when creating GUI elements.
     /// </summary>
-    public class GUILayoutUtility
+    public class GUIUtility
     {
         /// <summary>
         /// Calculates optimal size of a GUI element.
@@ -47,11 +46,37 @@ namespace BansheeEngine
             return output;
         }
 
+        /// <summary>
+        /// Calculates optimal content size for the provided text using the provided font and size. Size is calculated
+        /// without word wrap.
+        /// </summary>
+        /// <param name="text">Text to calculate the bounds for.</param>
+        /// <param name="font">Font that will be used for rendering the text.</param>
+        /// <param name="fontSize">Size of individual characters in the font, in points.</param>
+        /// <returns>Width/height required to display the text, in pixels.</returns>
+        public static Vector2I CalculateTextBounds(string text, Font font, int fontSize)
+        {
+            Vector2I output;
+
+            if (font != null && text != null)
+            {
+                IntPtr fontPtr = font.GetCachedPtr();
+                Internal_CalculateTextBounds(text, fontPtr, fontSize, out output);
+            }
+            else
+                output = new Vector2I();
+
+            return output;
+        }
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_CalculateOptimalSize(IntPtr element, out Vector2I output);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_CalculateBounds(IntPtr element, IntPtr relativeTo, out Rect2I output);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CalculateTextBounds(string text, IntPtr fontPtr, int fontSize, out Vector2I output);
     }
 
     /** @} */

+ 2 - 2
Source/MBansheeEngine/Input/Input.cs

@@ -203,7 +203,7 @@ namespace BansheeEngine
         public static event PointerEventDelegate OnPointerReleased;
 
         /// <summary>
-        /// Triggered when a button on the pointing device (mouse, touch) is pressed twice in rappid succession.
+        /// Triggered when a button on the pointing device (mouse, touch) is pressed twice in rapid succession.
         /// </summary>
         public static event PointerEventDelegate OnPointerDoubleClick;
 
@@ -305,7 +305,7 @@ namespace BansheeEngine
         }
 
         /// <summary>
-        /// Returns difference between last and current pointer position.
+        /// Returns difference pointer position of the current and last frame.
         /// </summary>
         public static Vector2I PointerDelta
         {

+ 1 - 1
Source/MBansheeEngine/MBansheeEngine.csproj

@@ -76,7 +76,7 @@
     <Compile Include="Utility\FileEx.cs" />
     <Compile Include="GUI\Font.cs" />
     <Compile Include="Scene\GameObject.cs" />
-    <Compile Include="GUI\GUILayoutUtility.cs" />
+    <Compile Include="GUI\GUIUtility.cs" />
     <Compile Include="GUI\GUIButton.cs" />
     <Compile Include="GUI\GUIContent.cs" />
     <Compile Include="GUI\GUIElement.cs" />

+ 2 - 2
Source/SBansheeEngine/CMakeSources.cmake

@@ -30,7 +30,7 @@ set(BS_SBANSHEEENGINE_SRC_WRAPPERS_GUI
 	"Source/BsScriptGUIToggle.cpp"
 	"Source/BsScriptGUIToggleGroup.cpp"
 	"Source/BsScriptGUIElement.cpp"
-	"Source/BsScriptGUILayoutUtility.cpp"
+	"Source/BsScriptGUIUtility.cpp"
 	"Source/BsScriptGUIRenderTexture.cpp"
 	"Source/BsScriptGUISlider.cpp"
 	"Source/BsScriptGUIProgressBar.cpp"
@@ -159,7 +159,7 @@ set(BS_SBANSHEEENGINE_INC_WRAPPERS_GUI
 	"Include/BsScriptGUIToggle.h"
 	"Include/BsScriptGUIToggleGroup.h"
 	"Include/BsScriptGUIElement.h"
-	"Include/BsScriptGUILayoutUtility.h"
+	"Include/BsScriptGUIUtility.h"
 	"Include/BsScriptGUIRenderTexture.h"
 	"Include/BsScriptGUISlider.h"
 	"Include/BsScriptGUIProgressBar.h"

+ 2 - 2
Source/SBansheeEngine/Include/BsScriptGUICanvas.h

@@ -24,8 +24,8 @@ namespace BansheeEngine
 		/* 								CLR HOOKS						   		*/
 		/************************************************************************/
 		static void internal_createInstance(MonoObject* instance, MonoString* style, MonoArray* guiOptions);
-		static void internal_drawLine(ScriptGUICanvas* nativeInstance, Vector2I* a, Vector2I* b, float width, Color* color);
-		static void internal_drawPolyLine(ScriptGUICanvas* nativeInstance, MonoArray* vertices, float width, Color* color);
+		static void internal_drawLine(ScriptGUICanvas* nativeInstance, Vector2I* a, Vector2I* b, Color* color);
+		static void internal_drawPolyLine(ScriptGUICanvas* nativeInstance, MonoArray* vertices, Color* color);
 		static void internal_drawTexture(ScriptGUICanvas* nativeInstance, ScriptSpriteTexture* texture, Rect2I* area,
 			TextureScaleMode scaleMode, Color* color);
 		static void internal_drawTriangleStrip(ScriptGUICanvas* nativeInstance, MonoArray* vertices, Color* color);

+ 34 - 33
Source/SBansheeEngine/Include/BsScriptGUILayoutUtility.h → Source/SBansheeEngine/Include/BsScriptGUIUtility.h

@@ -1,34 +1,35 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsScriptEnginePrerequisites.h"
-#include "BsScriptObject.h"
-#include "BsScriptGUIElement.h"
-#include "BsVector2I.h"
-#include "BsRect2I.h"
-
-namespace BansheeEngine
-{
-	/** @addtogroup ScriptInteropEngine
-	 *  @{
-	 */
-
-	/**	Interop class between C++ & CLR for GUILayoutUtility. */
-	class BS_SCR_BE_EXPORT ScriptGUILayoutUtility : public ScriptObject<ScriptGUILayoutUtility>
-	{
-	public:
-		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "GUILayoutUtility")
-
-		ScriptGUILayoutUtility();
-
-	private:
-		/************************************************************************/
-		/* 								CLR HOOKS						   		*/
-		/************************************************************************/
-		static void internal_CalculateOptimalSize(ScriptGUIElementBaseTBase* guiElement, Vector2I* output);
-		static void internal_CalculateBounds(ScriptGUIElementBaseTBase* guiElement, ScriptGUILayout* relativeTo, Rect2I* output);
-	};
-
-	/** @} */
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsScriptObject.h"
+#include "BsScriptGUIElement.h"
+#include "BsVector2I.h"
+#include "BsRect2I.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup ScriptInteropEngine
+	 *  @{
+	 */
+
+	/**	Interop class between C++ & CLR for GUILayoutUtility. */
+	class BS_SCR_BE_EXPORT ScriptGUILayoutUtility : public ScriptObject<ScriptGUILayoutUtility>
+	{
+	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "GUIUtility")
+
+		ScriptGUILayoutUtility();
+
+	private:
+		/************************************************************************/
+		/* 								CLR HOOKS						   		*/
+		/************************************************************************/
+		static void internal_CalculateOptimalSize(ScriptGUIElementBaseTBase* guiElement, Vector2I* output);
+		static void internal_CalculateBounds(ScriptGUIElementBaseTBase* guiElement, ScriptGUILayout* relativeTo, Rect2I* output);
+		static void internal_CalculateTextBounds(MonoString* text, ScriptFont* fontPtr, int fontSize, Vector2I* output);
+	};
+
+	/** @} */
 }

+ 4 - 5
Source/SBansheeEngine/Source/BsScriptGUICanvas.cpp

@@ -43,14 +43,13 @@ namespace BansheeEngine
 		new (bs_alloc<ScriptGUICanvas>()) ScriptGUICanvas(instance, guiCanvas);
 	}
 
-	void ScriptGUICanvas::internal_drawLine(ScriptGUICanvas* nativeInstance, Vector2I* a, Vector2I* b, float width, Color* color)
+	void ScriptGUICanvas::internal_drawLine(ScriptGUICanvas* nativeInstance, Vector2I* a, Vector2I* b, Color* color)
 	{
 		GUICanvas* canvas = (GUICanvas*)nativeInstance->getGUIElement();
-		canvas->drawLine(*a, *b, width, *color);
+		canvas->drawLine(*a, *b, *color);
 	}
 
-	void ScriptGUICanvas::internal_drawPolyLine(ScriptGUICanvas* nativeInstance, MonoArray* vertices, float width, 
-		Color* color)
+	void ScriptGUICanvas::internal_drawPolyLine(ScriptGUICanvas* nativeInstance, MonoArray* vertices, Color* color)
 	{
 		GUICanvas* canvas = (GUICanvas*)nativeInstance->getGUIElement();
 
@@ -60,7 +59,7 @@ namespace BansheeEngine
 		Vector<Vector2I> nativeVertices(size);
 		memcpy(nativeVertices.data(), verticesArray.getRawPtr<Vector2I>(), sizeof(Vector2I) * size);
 
-		canvas->drawPolyLine(nativeVertices, width, *color);
+		canvas->drawPolyLine(nativeVertices, *color);
 	}
 
 	void ScriptGUICanvas::internal_drawTexture(ScriptGUICanvas* nativeInstance, ScriptSpriteTexture* texture, Rect2I* area,

+ 12 - 1
Source/SBansheeEngine/Source/BsScriptGUILayoutUtility.cpp → Source/SBansheeEngine/Source/BsScriptGUIUtility.cpp

@@ -1,6 +1,6 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsScriptGUILayoutUtility.h"
+#include "BsScriptGUIUtility.h"
 #include "BsScriptMeta.h"
 #include "BsMonoField.h"
 #include "BsMonoClass.h"
@@ -11,6 +11,8 @@
 #include "BsGUIElementBase.h"
 #include "BsScriptGUILayout.h"
 #include "BsGUILayoutUtility.h"
+#include "BsGUIHelper.h"
+#include "BsScriptFont.h"
 
 namespace BansheeEngine
 {
@@ -22,6 +24,7 @@ namespace BansheeEngine
 	{
 		metaData.scriptClass->addInternalCall("Internal_CalculateOptimalSize", &ScriptGUILayoutUtility::internal_CalculateOptimalSize);
 		metaData.scriptClass->addInternalCall("Internal_CalculateBounds", &ScriptGUILayoutUtility::internal_CalculateBounds);
+		metaData.scriptClass->addInternalCall("Internal_CalculateTextBounds", &ScriptGUILayoutUtility::internal_CalculateTextBounds);
 	}
 
 	void ScriptGUILayoutUtility::internal_CalculateOptimalSize(ScriptGUIElementBaseTBase* guiElement, Vector2I* output)
@@ -37,4 +40,12 @@ namespace BansheeEngine
 
 		*output = guiElement->getGUIElement()->getBounds(relativeToPanel);
 	}
+
+	void ScriptGUILayoutUtility::internal_CalculateTextBounds(MonoString* text, ScriptFont* fontPtr, int fontSize, Vector2I* output)
+	{
+		WString nativeText = MonoUtil::monoToWString(text);
+		HFont nativeFont = fontPtr->getHandle();
+
+		*output = GUIHelper::calcTextSize(nativeText, nativeFont, fontSize);
+	}
 }