Browse Source

Variety of fixes to newly introduced GUICanvas, GpuBuffer and TriangleClipper
Moved to a different CLA service

BearishSun 9 years ago
parent
commit
2079efc1fe

+ 1 - 1
CONTRIBUTING.md

@@ -1 +1 @@
-Before contributing please sign the <a href="https://www.clahub.com/agreements/BearishSun/BansheeEngine">Contributor License Agreement</a>. This agreement gives us rights to use your contribution.
+Before contributing please sign the <a href="https://cla-assistant.io/BearishSun/BansheeEngine">Contributor License Agreement</a>. This agreement gives us rights to use your contribution.

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


+ 32 - 17
Data/Raw/Engine/Shaders/SpriteLine.bsl

@@ -1,3 +1,14 @@
+Parameters =
+{
+	mat4x4 	worldTransform;
+	float	invViewportWidth;
+	float	invViewportHeight;
+	
+	StructBuffer  	linePoints;
+	float 			lineWidth;
+	float4			tint;
+};
+
 Technique =
 Technique =
 {
 {
 	Language = "HLSL11";
 	Language = "HLSL11";
@@ -20,7 +31,7 @@ Technique =
 			{
 			{
 				float4 position : SV_POSITION;
 				float4 position : SV_POSITION;
 				float2 screenPos : TEXCOORD1;
 				float2 screenPos : TEXCOORD1;
-				uint lineIdx : BLENDINDICES0;
+				uint lineIdx : LINEIDX;
 			};
 			};
 		};
 		};
 		
 		
@@ -33,19 +44,19 @@ Technique =
 			struct VertexInput
 			struct VertexInput
 			{
 			{
 				float2 position : POSITION;
 				float2 position : POSITION;
-				uint lineIdx : LINEIDX;
+				uint lineIdx : BLENDINDICES0;
 			};			
 			};			
 			
 			
 			VStoFS main(VertexInput input)
 			VStoFS main(VertexInput input)
 			{
 			{
 				float4 tfrmdPos = mul(worldTransform, float4(input.position, 0, 1));
 				float4 tfrmdPos = mul(worldTransform, float4(input.position, 0, 1));
-
+				
 				float tfrmdX = -1.0f + (tfrmdPos.x * invViewportWidth);
 				float tfrmdX = -1.0f + (tfrmdPos.x * invViewportWidth);
 				float tfrmdY = 1.0f - (tfrmdPos.y * invViewportHeight);
 				float tfrmdY = 1.0f - (tfrmdPos.y * invViewportHeight);
 
 
 				VStoFS output;
 				VStoFS output;
 				output.position = float4(tfrmdX, tfrmdY, 0, 1);
 				output.position = float4(tfrmdX, tfrmdY, 0, 1);
-				output.screenPos.xy = input.position;
+				output.screenPos = tfrmdPos.xy;
 				output.lineIdx = input.lineIdx;
 				output.lineIdx = input.lineIdx;
 				
 				
 				return output;
 				return output;
@@ -82,32 +93,36 @@ Technique =
 				uint dummy;
 				uint dummy;
 				linePoints.GetDimensions(numPoints, dummy);
 				linePoints.GetDimensions(numPoints, dummy);
 				
 				
-				uint numLines = numPoints / 2 - 1;
+				uint numLines = numPoints - 1;
 								
 								
 				// Find nearest line
 				// Find nearest line
 				//// Distance to current line
 				//// Distance to current line
 				int lineIdx = (int)input.lineIdx;
 				int lineIdx = (int)input.lineIdx;
-				float2 a = linePoints.Load(lineIdx * 2 + 0);				
-				float2 b = linePoints.Load(lineIdx * 2 + 1);
+				float2 a = linePoints.Load(lineIdx + 0);				
+				float2 b = linePoints.Load(lineIdx + 1);
 				
 				
-				float minSquaredDistance = getSquaredDistanceToLine(a, b, input.screenPos);
+				float sqrdDist = getSquaredDistanceToLine(a, b, input.screenPos);
 
 
 				//// Distance to previous line
 				//// Distance to previous line
 				int prevLineIdx = max(0, lineIdx - 1);
 				int prevLineIdx = max(0, lineIdx - 1);
-				a = linePoints.Load(prevLineIdx * 2 + 0);				
-				b = linePoints.Load(prevLineIdx * 2 + 1);
+				a = linePoints.Load(prevLineIdx + 0);				
+				b = linePoints.Load(prevLineIdx + 1);
 				
 				
-				minSquaredDistance = min(minSquaredDistance, getSquaredDistanceToLine(a, b, input.screenPos));
+				sqrdDist = min(sqrdDist, getSquaredDistanceToLine(a, b, input.screenPos));
 				
 				
 				//// Distance to next line
 				//// Distance to next line
-				int nextLineIdx = min((int)numPoints - 1, lineIdx + 1);
-				a = linePoints.Load(nextLineIdx * 2 + 0);				
-				b = linePoints.Load(nextLineIdx * 2 + 1);
+				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));
 				
 				
-				minSquaredDistance = min(minSquaredDistance, getSquaredDistanceToLine(a, b, input.screenPos));
+				float sqrdLineWidth = lineWidth * lineWidth;
+				sqrdDist = max(sqrdDist - sqrdLineWidth, 0.0f);
 				
 				
-				// TODO - Use a different filter like Gaussian
-				float weight = clamp(minSquaredDistance / (lineWidth * lineWidth), 0, 1);
+				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 float4(tint.rgb, tint.a * weight);
 			}
 			}
 		};
 		};

+ 5 - 2
Source/BansheeCore/Source/BsGpuBuffer.cpp

@@ -92,8 +92,11 @@ namespace BansheeEngine
 	SPtr<GpuBufferCore> GpuBufferCore::create(UINT32 elementCount, UINT32 elementSize, GpuBufferType type,
 	SPtr<GpuBufferCore> GpuBufferCore::create(UINT32 elementCount, UINT32 elementSize, GpuBufferType type,
 		GpuBufferFormat format, GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
 		GpuBufferFormat format, GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
 	{
 	{
-		return HardwareBufferCoreManager::instance().createGpuBufferInternal(elementCount, elementSize, type, format,
-			usage, randomGpuWrite, useCounter);
+		SPtr<GpuBufferCore> gpuBuffer = HardwareBufferCoreManager::instance().createGpuBufferInternal(elementCount, 
+			elementSize, type, format, usage, randomGpuWrite, useCounter);
+
+		gpuBuffer->initialize();
+		return gpuBuffer;
 	}
 	}
 
 
 	GpuBuffer::GpuBuffer(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, GpuBufferFormat format, 
 	GpuBuffer::GpuBuffer(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, GpuBufferFormat format, 

+ 4 - 4
Source/BansheeCore/Source/BsGpuParams.cpp

@@ -501,8 +501,8 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 		UINT32 paramBufferOffset = textureInfoOffset + loadStoreSurfacesSize;
 		UINT32 paramBufferOffset = textureInfoOffset + loadStoreSurfacesSize;
 		UINT32 textureArrayOffset = paramBufferOffset + paramBufferSize;
 		UINT32 textureArrayOffset = paramBufferOffset + paramBufferSize;
 		UINT32 loadStoreTextureArrayOffset = textureArrayOffset + textureArraySize;
 		UINT32 loadStoreTextureArrayOffset = textureArrayOffset + textureArraySize;
-		UINT32 bufferArrayOffset = loadStoreTextureArrayOffset + bufferArraySize;
-		UINT32 samplerArrayOffset = bufferArrayOffset + loadStoreTextureArraySize;
+		UINT32 bufferArrayOffset = loadStoreTextureArrayOffset + loadStoreTextureArraySize;
+		UINT32 samplerArrayOffset = bufferArrayOffset + bufferArraySize;
 
 
 		assert(data.getBufferSize() == totalSize);
 		assert(data.getBufferSize() == totalSize);
 
 
@@ -623,8 +623,8 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 		UINT32 paramBufferOffset = textureInfoOffset + loadStoreSurfacesSize;
 		UINT32 paramBufferOffset = textureInfoOffset + loadStoreSurfacesSize;
 		UINT32 textureArrayOffset = paramBufferOffset + paramBufferSize;
 		UINT32 textureArrayOffset = paramBufferOffset + paramBufferSize;
 		UINT32 loadStoreTextureArrayOffset = textureArrayOffset + textureArraySize;
 		UINT32 loadStoreTextureArrayOffset = textureArrayOffset + textureArraySize;
-		UINT32 bufferArrayOffset = loadStoreTextureArrayOffset + bufferArraySize;
-		UINT32 samplerArrayOffset = bufferArrayOffset + loadStoreTextureArraySize;
+		UINT32 bufferArrayOffset = loadStoreTextureArrayOffset + loadStoreTextureArraySize;
+		UINT32 samplerArrayOffset = bufferArrayOffset + bufferArraySize;
 
 
 		UINT8* data = allocator->alloc(totalSize);
 		UINT8* data = allocator->alloc(totalSize);
 
 

+ 6 - 6
Source/BansheeCore/Source/BsMeshUtility.cpp

@@ -344,7 +344,7 @@ namespace BansheeEngine
 				{
 				{
 					ClipEdge& edge = mesh.edges[face.edges[j]];
 					ClipEdge& edge = mesh.edges[face.edges[j]];
 					ClipVert& v0 = mesh.verts[edge.verts[0]];
 					ClipVert& v0 = mesh.verts[edge.verts[0]];
-					ClipVert& v1 = mesh.verts[edge.verts[0]];
+					ClipVert& v1 = mesh.verts[edge.verts[1]];
 
 
 					v0.occurs = 0;
 					v0.occurs = 0;
 					v1.occurs = 0;
 					v1.occurs = 0;
@@ -379,7 +379,7 @@ namespace BansheeEngine
 			if (edge.visible)
 			if (edge.visible)
 			{
 			{
 				ClipVert& v0 = mesh.verts[edge.verts[0]];
 				ClipVert& v0 = mesh.verts[edge.verts[0]];
-				ClipVert& v1 = mesh.verts[edge.verts[0]];
+				ClipVert& v1 = mesh.verts[edge.verts[1]];
 
 
 				v0.occurs++;
 				v0.occurs++;
 				v1.occurs++;
 				v1.occurs++;
@@ -475,7 +475,7 @@ namespace BansheeEngine
 		UINT32 numEdges = (UINT32)face.edges.size();
 		UINT32 numEdges = (UINT32)face.edges.size();
 		UINT32* sortedEdges = (UINT32*)bs_stack_alloc(sizeof(UINT32) * numEdges);
 		UINT32* sortedEdges = (UINT32*)bs_stack_alloc(sizeof(UINT32) * numEdges);
 		for (UINT32 i = 0; i < numEdges; i++)
 		for (UINT32 i = 0; i < numEdges; i++)
-			sortedEdges[i] = i;
+			sortedEdges[i] = face.edges[i];
 
 
 		// Bubble sort to arrange edges in contiguous order
 		// Bubble sort to arrange edges in contiguous order
 		for (UINT32 i0 = 0, i1 = 1, choice = 1; i1 < numEdges - 1; i0 = i1, i1++)
 		for (UINT32 i0 = 0, i1 = 1, choice = 1; i1 < numEdges - 1; i0 = i1, i1++)
@@ -497,13 +497,13 @@ namespace BansheeEngine
 		}
 		}
 
 
 		// Add the first two vertices
 		// Add the first two vertices
-		sortedVerts[0] = mesh.edges[face.edges[sortedEdges[0]]].verts[0];
-		sortedVerts[1] = mesh.edges[face.edges[sortedEdges[0]]].verts[1];
+		sortedVerts[0] = mesh.edges[sortedEdges[0]].verts[0];
+		sortedVerts[1] = mesh.edges[sortedEdges[0]].verts[1];
 
 
 		// Add the remaining vertices
 		// Add the remaining vertices
 		for (UINT32 i = 1; i < numEdges; i++)
 		for (UINT32 i = 1; i < numEdges; i++)
 		{
 		{
-			const ClipEdge& edge = mesh.edges[face.edges[sortedEdges[i]]];
+			const ClipEdge& edge = mesh.edges[sortedEdges[i]];
 
 
 			if (edge.verts[0] == sortedVerts[i])
 			if (edge.verts[0] == sortedVerts[i])
 				sortedVerts[i + 1] = edge.verts[1];
 				sortedVerts[i + 1] = edge.verts[1];

+ 1 - 1
Source/BansheeD3D11RenderAPI/Source/BsD3D11GpuBuffer.cpp

@@ -18,7 +18,7 @@ namespace BansheeEngine
 		if (type != GBT_STANDARD)
 		if (type != GBT_STANDARD)
 			assert(format == BF_UNKNOWN && "Format must be set to BF_UNKNOWN when using non-standard buffers");
 			assert(format == BF_UNKNOWN && "Format must be set to BF_UNKNOWN when using non-standard buffers");
 		else
 		else
-			assert(elementSize != 0 && "No element size can be provided for standard buffer. Size is determined from format.");
+			assert(elementSize == 0 && "No element size can be provided for standard buffer. Size is determined from format.");
 	}
 	}
 
 
 	D3D11GpuBufferCore::~D3D11GpuBufferCore()
 	D3D11GpuBufferCore::~D3D11GpuBufferCore()

+ 2 - 2
Source/BansheeD3D11RenderAPI/Source/BsD3D11GpuBufferView.cpp

@@ -57,8 +57,8 @@ namespace BansheeEngine
 		{
 		{
 			desc.Format = DXGI_FORMAT_UNKNOWN;
 			desc.Format = DXGI_FORMAT_UNKNOWN;
 			desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
 			desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
-			desc.Buffer.ElementOffset = firstElement * elementWidth;
-			desc.Buffer.ElementWidth = elementWidth;
+			desc.Buffer.FirstElement = firstElement;
+			desc.Buffer.NumElements = numElements;
 		}
 		}
 		else if (props.getType() == GBT_RAW)
 		else if (props.getType() == GBT_RAW)
 		{
 		{

+ 4 - 1
Source/BansheeEngine/Include/BsGUICanvas.h

@@ -227,13 +227,16 @@ namespace BansheeEngine
 
 
 		Vector<ImageElementData> mImageData;
 		Vector<ImageElementData> mImageData;
 		Vector<TextElementData> mTextData;
 		Vector<TextElementData> mTextData;
-		Vector<TriangleElementData> mTriangleElementData;
+		mutable Vector<TriangleElementData> mTriangleElementData;
 		Vector<Vector2> mVertexData;
 		Vector<Vector2> mVertexData;
 
 
 		mutable Vector<Vector2> mClippedVertices;
 		mutable Vector<Vector2> mClippedVertices;
+		mutable Vector<Vector3> mClippedLineVertices; // z coordinate = line index
 		mutable Vector2 mLastOffset;
 		mutable Vector2 mLastOffset;
 		mutable Rect2I mLastClipRect;
 		mutable Rect2I mLastClipRect;
 		mutable bool mForceTriangleBuild;
 		mutable bool mForceTriangleBuild;
+
+		static const float LINE_SMOOTH_BORDER_WIDTH;
 	};
 	};
 
 
 	/** @} */
 	/** @} */

+ 12 - 3
Source/BansheeEngine/Include/BsShapeMeshes2D.h

@@ -60,6 +60,9 @@ namespace BansheeEngine
 		 * @param[in]	a				Start point of the line.
 		 * @param[in]	a				Start point of the line.
 		 * @param[in]	b				End point of the line.
 		 * @param[in]	b				End point of the line.
 		 * @param[in]	width			Width of the line.
 		 * @param[in]	width			Width of the line.
+		 * @param[in]	border			Optional border that will increase the width and the length at both end-points. 
+		 *								Useful if you are using some kind of filtering for the line rendering, as the
+		 *								filtered pixels can belong to the border region.
 		 * @param[in]	color			Color of the line.
 		 * @param[in]	color			Color of the line.
 		 * @param[out]	meshData		Mesh data that will be populated by this method.
 		 * @param[out]	meshData		Mesh data that will be populated by this method.
 		 * @param[in]	vertexOffset	Offset in number of vertices from the start of the buffer to start writing at.
 		 * @param[in]	vertexOffset	Offset in number of vertices from the start of the buffer to start writing at.
@@ -74,7 +77,7 @@ namespace BansheeEngine
 		 * @note
 		 * @note
 		 * Primitives are output in the form of a triangle list.
 		 * Primitives are output in the form of a triangle list.
 		 */
 		 */
-		static void quadLine(const Vector2& a, const Vector2& b, float width, const Color& color,
+		static void quadLine(const Vector2& a, const Vector2& b, float width, float border, const Color& color,
 			const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset);
 			const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset);
 
 
 		/**
 		/**
@@ -101,6 +104,9 @@ namespace BansheeEngine
 		 *
 		 *
 		 * @param[in]	linePoints		A list of start and end points for the lines.
 		 * @param[in]	linePoints		A list of start and end points for the lines.
 		 * @param[in]	width			Width of the line.
 		 * @param[in]	width			Width of the line.
+		 * @param[in]	border			Optional border that will increase the width and the length at both end-points.
+		 *								Useful if you are using some kind of filtering for the line rendering, as the
+		 *								filtered pixels can belong to the border region.
 		 * @param[in]	color			Color of the line.
 		 * @param[in]	color			Color of the line.
 		 * @param[out]	meshData		Mesh data that will be populated by this method.
 		 * @param[out]	meshData		Mesh data that will be populated by this method.
 		 * @param[in]	vertexOffset	Offset in number of vertices from the start of the buffer to start writing at.
 		 * @param[in]	vertexOffset	Offset in number of vertices from the start of the buffer to start writing at.
@@ -115,7 +121,7 @@ namespace BansheeEngine
 		 * @note
 		 * @note
 		 * Primitives are output in the form of a triangle list.
 		 * Primitives are output in the form of a triangle list.
 		 */
 		 */
-		static void quadLineList(const Vector<Vector2>& linePoints, float width, 
+		static void quadLineList(const Vector<Vector2>& linePoints, float width, float border,
 			const Color& color, const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset);
 			const Color& color, const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset);
 
 
 		/**
 		/**
@@ -125,6 +131,9 @@ namespace BansheeEngine
 		 * @param[in]	linePoints		A list of start and end points for the lines.
 		 * @param[in]	linePoints		A list of start and end points for the lines.
 		 * @param[in]	numPoints		Number of points in the @p linePoints buffer.
 		 * @param[in]	numPoints		Number of points in the @p linePoints buffer.
 		 * @param[in]	width			Width of the line.
 		 * @param[in]	width			Width of the line.
+		 * @param[in]	border			Optional border that will increase the width and the length at both end-points.
+		 *								Useful if you are using some kind of filtering for the line rendering, as the
+		 *								filtered pixels can belong to the border region.
 		 * @param[out]	outVertices		Pre-allocated buffer for the vertices, of size ((numLines * 2) + 2) * @p vertexStride
 		 * @param[out]	outVertices		Pre-allocated buffer for the vertices, of size ((numLines * 2) + 2) * @p vertexStride
 		 *								if @p indexed is true, or (numLines * 6) * @p vertexStride if false.
 		 *								if @p indexed is true, or (numLines * 6) * @p vertexStride if false.
 		 * @param[in]	vertexStride	Distance between two vertices in the output buffer. Must be at least sizeof(Vector2).
 		 * @param[in]	vertexStride	Distance between two vertices in the output buffer. Must be at least sizeof(Vector2).
@@ -132,7 +141,7 @@ namespace BansheeEngine
 		 *								buffer will be used for rendering. If false then (numLines * 6) vertices will be
 		 *								buffer will be used for rendering. If false then (numLines * 6) vertices will be
 		 *								generated.
 		 *								generated.
 		 */
 		 */
-		static void quadLineList(const Vector2* linePoints, UINT32 numPoints, float width, UINT8* outVertices, 
+		static void quadLineList(const Vector2* linePoints, UINT32 numPoints, float width, float border, UINT8* outVertices,
 			UINT32 vertexStride, bool indexed);
 			UINT32 vertexStride, bool indexed);
 
 
 		static const UINT32 NUM_VERTICES_AA_LINE;
 		static const UINT32 NUM_VERTICES_AA_LINE;

+ 80 - 31
Source/BansheeEngine/Source/BsGUICanvas.cpp

@@ -8,10 +8,13 @@
 #include "BsShapeMeshes2D.h"
 #include "BsShapeMeshes2D.h"
 #include "BsSpriteManager.h"
 #include "BsSpriteManager.h"
 #include "BsSpriteMaterials.h"
 #include "BsSpriteMaterials.h"
+#include "BsMeshUtility.h"
 #include "BsException.h"
 #include "BsException.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
+	const float GUICanvas::LINE_SMOOTH_BORDER_WIDTH = 3.0f;
+
 	const String& GUICanvas::getGUITypeName()
 	const String& GUICanvas::getGUITypeName()
 	{
 	{
 		static String name = "Canvas";
 		static String name = "Canvas";
@@ -60,22 +63,19 @@ namespace BansheeEngine
 		element.dataId = (UINT32)mTriangleElementData.size();
 		element.dataId = (UINT32)mTriangleElementData.size();
 		element.vertexStart = (UINT32)mVertexData.size();
 		element.vertexStart = (UINT32)mVertexData.size();
 		element.numVertices = (UINT32)vertices.size();
 		element.numVertices = (UINT32)vertices.size();
-		element.lineWidth = width;
+		element.lineWidth = width * 0.5f;
 
 
 		mTriangleElementData.push_back(TriangleElementData());
 		mTriangleElementData.push_back(TriangleElementData());
 		TriangleElementData& elemData = mTriangleElementData.back();
 		TriangleElementData& elemData = mTriangleElementData.back();
 		elemData.matInfo.groupId = 0;
 		elemData.matInfo.groupId = 0;
 		elemData.matInfo.tint = color;
 		elemData.matInfo.tint = color;
 
 
-		SPtr<SpriteMaterialLineInfo> lineInfo = bs_shared_ptr_new<SpriteMaterialLineInfo>();
-		lineInfo->width = width;
-
 		for (auto& vertex : vertices)
 		for (auto& vertex : vertices)
 		{
 		{
 			Vector2 point = Vector2((float)vertex.x, (float)vertex.y);
 			Vector2 point = Vector2((float)vertex.x, (float)vertex.y);
+			point += Vector2(0.5f, 0.5f); // Offset to the middle of the pixel
 
 
 			mVertexData.push_back(point);
 			mVertexData.push_back(point);
-			lineInfo->points.push_back(point);
 		}
 		}
 
 
 		mForceTriangleBuild = true;
 		mForceTriangleBuild = true;
@@ -207,6 +207,7 @@ namespace BansheeEngine
 		mTextData.clear();
 		mTextData.clear();
 		mTriangleElementData.clear();
 		mTriangleElementData.clear();
 		mClippedVertices.clear();
 		mClippedVertices.clear();
+		mClippedLineVertices.clear();
 		mForceTriangleBuild = false;
 		mForceTriangleBuild = false;
 	}
 	}
 
 
@@ -219,6 +220,10 @@ namespace BansheeEngine
 	{
 	{
 		static const SpriteMaterialInfo defaultMatInfo;
 		static const SpriteMaterialInfo defaultMatInfo;
 
 
+		Vector2 offset((float)mLayoutData.area.x, (float)mLayoutData.area.y);
+		Rect2I clipRect = mLayoutData.getLocalClipRect();
+		buildAllTriangleElementsIfDirty(offset, clipRect);
+
 		const CanvasElement& element = findElement(renderElementIdx);
 		const CanvasElement& element = findElement(renderElementIdx);
 		switch (element.type)
 		switch (element.type)
 		{
 		{
@@ -410,14 +415,15 @@ namespace BansheeEngine
 			assert((startIndex + numIndices) <= maxIndexIdx);
 			assert((startIndex + numIndices) <= maxIndexIdx);
 
 
 			UINT8* vertDst = vertices + startVert * vertexStride;
 			UINT8* vertDst = vertices + startVert * vertexStride;
-			UINT8* lineIdxDst = vertDst + sizeof(UINT32);
+			UINT8* lineIdxDst = vertDst + sizeof(Vector2);
 			UINT32* indexDst = indices + startIndex;
 			UINT32* indexDst = indices + startIndex;
 
 
 			for (UINT32 i = 0; i < element.clippedNumVertices; i++)
 			for (UINT32 i = 0; i < element.clippedNumVertices; i++)
 			{
 			{
-				UINT32 lineIdx = i / 6;
+				const Vector3& point = mClippedLineVertices[element.clippedVertexStart + i];
+				UINT32 lineIdx = (UINT32)point.z;
 
 
-				memcpy(vertDst, &mClippedVertices[element.clippedVertexStart + i], sizeof(Vector2));
+				memcpy(vertDst, &point, sizeof(Vector2));
 				memcpy(lineIdxDst, &lineIdx, sizeof(UINT32));
 				memcpy(lineIdxDst, &lineIdx, sizeof(UINT32));
 
 
 				vertDst += vertexStride;
 				vertDst += vertexStride;
@@ -475,43 +481,85 @@ namespace BansheeEngine
 	{
 	{
 		assert(element.type == CanvasElementType::Triangle || element.type == CanvasElementType::Line);
 		assert(element.type == CanvasElementType::Triangle || element.type == CanvasElementType::Line);
 
 
-		UINT8* verticesToClip;
-		UINT32 trianglesToClip;
-		bool freeVertices;
-
 		if (element.type == CanvasElementType::Triangle)
 		if (element.type == CanvasElementType::Triangle)
 		{
 		{
-			verticesToClip = (UINT8*)&mVertexData[element.vertexStart];
-			trianglesToClip = element.numVertices / 3;
-			freeVertices = false;
+			UINT8* verticesToClip = (UINT8*)&mVertexData[element.vertexStart];
+			UINT32 trianglesToClip = element.numVertices / 3;
+
+			auto writeCallback = [&](Vector2* vertices, Vector2* uvs, UINT32 count)
+			{
+				for (UINT32 i = 0; i < count; i++)
+					mClippedVertices.push_back(vertices[i] + offset);
+
+				element.clippedNumVertices += count;
+			};
+
+			element.clippedVertexStart = (UINT32)mClippedVertices.size();
+			element.clippedNumVertices = 0;
+
+			ImageSprite::clipTrianglesToRect(verticesToClip, nullptr, trianglesToClip, sizeof(Vector2), clipRect, 
+				writeCallback);
 		}
 		}
 		else
 		else
 		{
 		{
 			UINT32 numLines = element.numVertices - 1;
 			UINT32 numLines = element.numVertices - 1;
 
 
-			verticesToClip = (UINT8*)bs_stack_alloc(sizeof(Vector2) * (numLines * 6));
-			trianglesToClip = numLines * 2;
-			freeVertices = true;
+			UINT8* verticesToClip = (UINT8*)bs_stack_alloc(sizeof(Vector3) * (numLines * 6));
+			UINT32 trianglesToClip = numLines * 2;
 
 
 			const Vector2* linePoints = &mVertexData[element.vertexStart];
 			const Vector2* linePoints = &mVertexData[element.vertexStart];
-			ShapeMeshes2D::quadLineList(linePoints, element.numVertices, element.lineWidth, verticesToClip,
-				sizeof(Vector2), false);
-		}
+			ShapeMeshes2D::quadLineList(linePoints, element.numVertices, element.lineWidth, LINE_SMOOTH_BORDER_WIDTH, 
+				verticesToClip, sizeof(Vector3), false);
 
 
-		element.clippedVertexStart = (UINT32)mClippedVertices.size();
-		element.clippedNumVertices = 0;
-		auto writeCallback = [&](Vector2* vertices, Vector2* uvs, UINT32 count)
-		{
-			for (UINT32 i = 0; i < count; i++)
-				mClippedVertices.push_back(vertices[i] + offset);
+			SPtr<SpriteMaterialLineInfo> lineInfo = bs_shared_ptr_new<SpriteMaterialLineInfo>();
+			lineInfo->width = element.lineWidth;
+
+			for (UINT32 i = 0; i < element.numVertices; i++)
+			{
+				Vector2 point = linePoints[i];
+				point += offset; // Move to screen space
+
+				lineInfo->points.push_back(point);
+			}
+
+			TriangleElementData& elemData = mTriangleElementData[element.dataId];
+			elemData.matInfo.additionalData = lineInfo;
+
+			// 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++;
+				}
+			}
 
 
-			element.clippedNumVertices += count;
-		};
+			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)
+			};
+
+			Vector3 offset3D(offset.x, offset.y, 0.0f);
+			auto writeCallback = [&](Vector3* vertices, Vector2* uvs, UINT32 count)
+			{
+				for (UINT32 i = 0; i < count; i++)
+					mClippedLineVertices.push_back(vertices[i] + offset3D);
 
 
-		ImageSprite::clipTrianglesToRect(verticesToClip, nullptr, trianglesToClip, sizeof(Vector2), clipRect, writeCallback);
+				element.clippedNumVertices += count;
+			};
+
+			element.clippedVertexStart = (UINT32)mClippedLineVertices.size();
+			element.clippedNumVertices = 0;
+
+			MeshUtility::clip3D(verticesToClip, nullptr, trianglesToClip, sizeof(Vector3), clipPlanes, writeCallback);
 
 
-		if(freeVertices)
 			bs_stack_free(verticesToClip);
 			bs_stack_free(verticesToClip);
+		}
 	}
 	}
 
 
 	void GUICanvas::buildAllTriangleElementsIfDirty(const Vector2& offset, const Rect2I& clipRect) const
 	void GUICanvas::buildAllTriangleElementsIfDirty(const Vector2& offset, const Rect2I& clipRect) const
@@ -522,6 +570,7 @@ namespace BansheeEngine
 			return;
 			return;
 
 
 		mClippedVertices.clear();
 		mClippedVertices.clear();
+		mClippedLineVertices.clear();
 		for(auto& element : mElements)
 		for(auto& element : mElements)
 		{
 		{
 			if (element.type != CanvasElementType::Triangle && element.type != CanvasElementType::Line)
 			if (element.type != CanvasElementType::Triangle && element.type != CanvasElementType::Line)

+ 18 - 16
Source/BansheeEngine/Source/BsShapeMeshes2D.cpp

@@ -41,11 +41,11 @@ namespace BansheeEngine
 		pixelLine(a, b, positionData, vertexOffset, meshData->getVertexDesc()->getVertexStride(), indexData, indexOffset);
 		pixelLine(a, b, positionData, vertexOffset, meshData->getVertexDesc()->getVertexStride(), indexData, indexOffset);
 	}
 	}
 
 
-	void ShapeMeshes2D::quadLine(const Vector2& a, const Vector2& b, float width, const Color& color, 
+	void ShapeMeshes2D::quadLine(const Vector2& a, const Vector2& b, float width, float border, const Color& color,
 		const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset)
 		const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset)
 	{
 	{
 		Vector<Vector2> linePoints = { a, b };
 		Vector<Vector2> linePoints = { a, b };
-		quadLineList(linePoints, width, color, meshData, vertexOffset, indexOffset);
+		quadLineList(linePoints, width, border, color, meshData, vertexOffset, indexOffset);
 	}
 	}
 
 
 	void ShapeMeshes2D::pixelLineList(const Vector<Vector2>& linePoints, const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset)
 	void ShapeMeshes2D::pixelLineList(const Vector<Vector2>& linePoints, const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset)
@@ -71,7 +71,7 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
-	void ShapeMeshes2D::quadLineList(const Vector<Vector2>& linePoints, float width, const Color& color,
+	void ShapeMeshes2D::quadLineList(const Vector<Vector2>& linePoints, float width, float border, const Color& color,
 		const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset)
 		const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset)
 	{
 	{
 		UINT32 numPoints = (UINT32)linePoints.size();
 		UINT32 numPoints = (UINT32)linePoints.size();
@@ -86,7 +86,7 @@ namespace BansheeEngine
 		UINT8* outColors = vertexOffset + meshData->getElementData(VES_COLOR);
 		UINT8* outColors = vertexOffset + meshData->getElementData(VES_COLOR);
 
 
 		UINT32 vertexStride = meshData->getVertexDesc()->getVertexStride();
 		UINT32 vertexStride = meshData->getVertexDesc()->getVertexStride();
-		quadLineList(&linePoints[0], numPoints, width, outVertices, vertexStride, true);
+		quadLineList(&linePoints[0], numPoints, width, border, outVertices, vertexStride, true);
 
 
 		RGBA colorValue = color.getAsRGBA();
 		RGBA colorValue = color.getAsRGBA();
 
 
@@ -116,12 +116,14 @@ namespace BansheeEngine
 		outColors += vertexStride;
 		outColors += vertexStride;
 	}
 	}
 
 
-	void ShapeMeshes2D::quadLineList(const Vector2* linePoints, UINT32 numPoints, float width, UINT8* outVertices,
+	void ShapeMeshes2D::quadLineList(const Vector2* linePoints, UINT32 numPoints, float width, float border, UINT8* outVertices,
 		UINT32 vertexStride, bool indexed)
 		UINT32 vertexStride, bool indexed)
 	{
 	{
 		assert(numPoints >= 2);
 		assert(numPoints >= 2);
 		UINT32 numLines = numPoints - 1;
 		UINT32 numLines = numPoints - 1;
 
 
+		width += border;
+
 		Vector2 prevPoints[2];
 		Vector2 prevPoints[2];
 
 
 		// Start segment
 		// Start segment
@@ -135,8 +137,8 @@ namespace BansheeEngine
 			// Flip 90 degrees
 			// Flip 90 degrees
 			Vector2 normal(diff.y, -diff.x);
 			Vector2 normal(diff.y, -diff.x);
 
 
-			prevPoints[0] = a - normal * width;
-			prevPoints[1] = a + normal * width;
+			prevPoints[0] = a - normal * width - diff * border;
+			prevPoints[1] = a + normal * width - diff * border;
 
 
 			memcpy(outVertices, &prevPoints[0], sizeof(prevPoints[0]));
 			memcpy(outVertices, &prevPoints[0], sizeof(prevPoints[0]));
 			outVertices += vertexStride;
 			outVertices += vertexStride;
@@ -186,15 +188,18 @@ namespace BansheeEngine
 
 
 				if (!indexed)
 				if (!indexed)
 				{
 				{
-					memcpy(outVertices, &prevPoints[1], sizeof(prevPoints[1]));
+					memcpy(outVertices, &curPoints[0], sizeof(curPoints[0]));
 					outVertices += vertexStride;
 					outVertices += vertexStride;
 
 
-					memcpy(outVertices, &curPoints[1], sizeof(curPoints[1]));
+					memcpy(outVertices, &prevPoints[1], sizeof(prevPoints[1]));
 					outVertices += vertexStride;
 					outVertices += vertexStride;
 
 
 					memcpy(outVertices, &curPoints[0], sizeof(curPoints[0]));
 					memcpy(outVertices, &curPoints[0], sizeof(curPoints[0]));
 					outVertices += vertexStride;
 					outVertices += vertexStride;
 
 
+					memcpy(outVertices, &curPoints[1], sizeof(curPoints[1]));
+					outVertices += vertexStride;
+
 					prevPoints[0] = curPoints[0];
 					prevPoints[0] = curPoints[0];
 					prevPoints[1] = curPoints[1];
 					prevPoints[1] = curPoints[1];
 				}
 				}
@@ -213,8 +218,8 @@ namespace BansheeEngine
 			Vector2 normal(diff.y, -diff.x);
 			Vector2 normal(diff.y, -diff.x);
 
 
 			Vector2 curPoints[2];
 			Vector2 curPoints[2];
-			curPoints[0] = a - normal * width;
-			curPoints[1] = a + normal * width;
+			curPoints[0] = b - normal * width + diff * border;
+			curPoints[1] = b + normal * width + diff * border;
 
 
 			memcpy(outVertices, &curPoints[0], sizeof(curPoints[0]));
 			memcpy(outVertices, &curPoints[0], sizeof(curPoints[0]));
 			outVertices += vertexStride;
 			outVertices += vertexStride;
@@ -224,13 +229,10 @@ namespace BansheeEngine
 
 
 			if (!indexed)
 			if (!indexed)
 			{
 			{
-				memcpy(outVertices, &prevPoints[1], sizeof(prevPoints[1]));
-				outVertices += vertexStride;
-
-				memcpy(outVertices, &curPoints[1], sizeof(curPoints[1]));
+				memcpy(outVertices, &curPoints[0], sizeof(curPoints[0]));
 				outVertices += vertexStride;
 				outVertices += vertexStride;
 
 
-				memcpy(outVertices, &curPoints[0], sizeof(curPoints[0]));
+				memcpy(outVertices, &prevPoints[1], sizeof(prevPoints[1]));
 				outVertices += vertexStride;
 				outVertices += vertexStride;
 			}
 			}
 		}
 		}

+ 2 - 3
Source/BansheeEngine/Source/BsSpriteMaterials.cpp

@@ -51,9 +51,8 @@ namespace BansheeEngine
 		if(lineInfo->pointBuffer == nullptr)
 		if(lineInfo->pointBuffer == nullptr)
 		{
 		{
 			UINT32 numPoints = (UINT32)lineInfo->points.size();
 			UINT32 numPoints = (UINT32)lineInfo->points.size();
-			SPtr<GpuBufferCore> pointBuffer = GpuBufferCore::create(numPoints, 0, GBT_STANDARD, BF_32X2F, GBU_STATIC);
-
-			pointBuffer->writeData(0, numPoints * sizeof(Vector2), &lineInfo->points[0], BufferWriteType::Discard);
+			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->setBuffer("linePoints", lineInfo->pointBuffer);

+ 8 - 6
Source/MBansheeEditor/Windows/AnimationWindow.cs

@@ -44,19 +44,21 @@ namespace BansheeEditor
             }
             }
 
 
             {
             {
-                Vector2I a = new Vector2I(150, 20);
-                Vector2I b = new Vector2I(230, 20);
-                Vector2I c = new Vector2I(150, 70);
+                Vector2I a = new Vector2I(50, 20);
+                Vector2I b = new Vector2I(100, 20);
+                Vector2I c = new Vector2I(240, 60);
 
 
-                canvas.DrawTriangleList(new Vector2I[] {a, b, c});
+                Vector2I[] vertices = {c, b};
+                canvas.DrawPolyLine(vertices, 1.0f);
             }
             }
+
             GUI.AddElement(canvas);
             GUI.AddElement(canvas);
         }
         }
 
 
         private void OnEditorUpdate()
         private void OnEditorUpdate()
         {
         {
-            int position = (int)(MathEx.Sin(Time.RealElapsed)*50.0f + 50.0f);
-            canvas.SetPosition(position, 0);
+            //int position = (int)(MathEx.Sin(Time.RealElapsed)*50.0f + 50.0f);
+            //canvas.SetPosition(position, 0);
         }
         }
 
 
         private void OnDestroy()
         private void OnDestroy()