Browse Source

Updated GUI so it can output different types of meshes (e.g. lines vs. triangles)

BearishSun 9 years ago
parent
commit
adcd1f7c57
36 changed files with 398 additions and 237 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. 9 14
      Data/Raw/Engine/Shaders/SpriteLine.bsl
  7. 1 1
      Documentation/Manuals/Native/gui.md
  8. 11 3
      Source/BansheeCore/Include/BsVertexDeclaration.h
  9. 40 23
      Source/BansheeCore/Source/BsVertexDeclaration.cpp
  10. 24 27
      Source/BansheeD3D11RenderAPI/Source/BsD3D11Mappings.cpp
  11. 3 8
      Source/BansheeD3D9RenderAPI/Source/BsD3D9Mappings.cpp
  12. 3 3
      Source/BansheeEditor/Include/BsGUIColor.h
  13. 11 6
      Source/BansheeEditor/Source/BsGUIColor.cpp
  14. 9 0
      Source/BansheeEngine/Include/BsEnums.h
  15. 3 3
      Source/BansheeEngine/Include/BsGUIButtonBase.h
  16. 3 3
      Source/BansheeEngine/Include/BsGUICanvas.h
  17. 7 9
      Source/BansheeEngine/Include/BsGUIElement.h
  18. 3 3
      Source/BansheeEngine/Include/BsGUIElementContainer.h
  19. 3 3
      Source/BansheeEngine/Include/BsGUIInputBox.h
  20. 3 3
      Source/BansheeEngine/Include/BsGUILabel.h
  21. 10 7
      Source/BansheeEngine/Include/BsGUIManager.h
  22. 3 3
      Source/BansheeEngine/Include/BsGUIScrollBar.h
  23. 3 3
      Source/BansheeEngine/Include/BsGUISliderHandle.h
  24. 3 3
      Source/BansheeEngine/Include/BsGUITexture.h
  25. 3 3
      Source/BansheeEngine/Include/BsGUIViewport.h
  26. 11 6
      Source/BansheeEngine/Source/BsGUIButtonBase.cpp
  27. 54 7
      Source/BansheeEngine/Source/BsGUICanvas.cpp
  28. 4 3
      Source/BansheeEngine/Source/BsGUIElementContainer.cpp
  29. 9 4
      Source/BansheeEngine/Source/BsGUIInputBox.cpp
  30. 8 4
      Source/BansheeEngine/Source/BsGUILabel.cpp
  31. 112 69
      Source/BansheeEngine/Source/BsGUIManager.cpp
  32. 9 4
      Source/BansheeEngine/Source/BsGUIScrollBar.cpp
  33. 9 4
      Source/BansheeEngine/Source/BsGUISliderHandle.cpp
  34. 9 4
      Source/BansheeEngine/Source/BsGUITexture.cpp
  35. 4 3
      Source/BansheeEngine/Source/BsGUIViewport.cpp
  36. 14 1
      Source/BansheeGLRenderAPI/Source/BsGLHardwareBufferManager.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


+ 9 - 14
Data/Raw/Engine/Shaders/SpriteLine.bsl

@@ -19,8 +19,8 @@ Technique =
 			struct VStoFS
 			{
 				float4 position : SV_POSITION;
-				float2 uv : TEXCOORD0;
-				float3 screenAndLinePos : TEXCOORD1;
+				float2 screenPos : TEXCOORD1;
+				uint lineIdx : BLENDINDICES0;
 			};
 		};
 		
@@ -33,8 +33,7 @@ Technique =
 			struct VertexInput
 			{
 				float2 position : POSITION;
-				float2 uv : TEXCOORD0;
-				uint vertexIdx : SV_VERTEXID;
+				uint lineIdx : LINEIDX;
 			};			
 			
 			VStoFS main(VertexInput input)
@@ -46,11 +45,8 @@ Technique =
 
 				VStoFS output;
 				output.position = float4(tfrmdX, tfrmdY, 0, 1);
-				output.uv = input.uv;
-				output.screenAndLinePos.xy = input.position;
-				
-				uint segmentIdx = input.vertexIdx / 2;
-				output.screenAndLinePos.z = (float)segmentIdx;
+				output.screenPos.xy = input.position;
+				output.lineIdx = input.lineIdx;
 				
 				return output;
 			}
@@ -90,26 +86,25 @@ Technique =
 								
 				// Find nearest line
 				//// Distance to current line
-				///// This will get interpolated between two nearest line segments, truncate to get the line index
-				int lineIdx = (int)input.screenAndLinePos.z;
+				int lineIdx = (int)input.lineIdx;
 				float2 a = linePoints.Load(lineIdx * 2 + 0);				
 				float2 b = linePoints.Load(lineIdx * 2 + 1);
 				
-				float minSquaredDistance = getSquaredDistanceToLine(a, b, input.screenAndLinePos.xy);
+				float minSquaredDistance = getSquaredDistanceToLine(a, b, input.screenPos);
 
 				//// Distance to previous line
 				int prevLineIdx = max(0, lineIdx - 1);
 				a = linePoints.Load(prevLineIdx * 2 + 0);				
 				b = linePoints.Load(prevLineIdx * 2 + 1);
 				
-				minSquaredDistance = min(minSquaredDistance, getSquaredDistanceToLine(a, b, input.screenAndLinePos.xy));
+				minSquaredDistance = min(minSquaredDistance, getSquaredDistanceToLine(a, b, input.screenPos));
 				
 				//// Distance to next line
 				int nextLineIdx = min((int)numPoints - 1, lineIdx + 1);
 				a = linePoints.Load(nextLineIdx * 2 + 0);				
 				b = linePoints.Load(nextLineIdx * 2 + 1);
 				
-				minSquaredDistance = min(minSquaredDistance, getSquaredDistanceToLine(a, b, input.screenAndLinePos.xy));
+				minSquaredDistance = min(minSquaredDistance, getSquaredDistanceToLine(a, b, input.screenPos));
 				
 				// TODO - Use a different filter like Gaussian
 				float weight = clamp(minSquaredDistance / (lineWidth * lineWidth), 0, 1);

+ 1 - 1
Documentation/Manuals/Native/gui.md

@@ -16,7 +16,7 @@ You will almost certainly be interested in `GUIElement`, and are unlikely to nee
 When creating a custom GUI element you will need to override the @ref BansheeEngine::GUIElement "GUIElement" type. The minimum set of methods you need to implement for your custom elements are:
  - @ref BansheeEngine::GUIElement::_getOptimalSize "_getOptimalSize()" - Return the optimal size of your GUI element. This is used for controlling the size of the element in a layout (if it's not fixed). For example if your element was displaying a texture 64x64 in size, then the optimal size should probably return 64x64. If you element is displaying text you can use @ref BansheeEngine::GUIHelper "GUIHelper" to help you calculate the bounds of the text. If displaying something else then it's up to you to determine what constitutes an optimal size.
  - @ref BansheeEngine::GUIElement::_getNumRenderElements() "_getNumRenderElements()" - Return the number of separate elements that your GUIElement consists of. Each element has its own mesh, material and texture. In most cases there is only one element.
- - @ref BansheeEngine::GUIElement::_getMeshSize() "_getMeshSize()" - Returns the number of vertices and indices for the mesh of the render element at the specified index (e.g. one quad (4 vertices, 6 indices) if the GUI element displays just one texture). This allows external systems to know how big of a buffer to allocate for the element's mesh.
+ - @ref BansheeEngine::GUIElement::_getMeshInfo() "_getMeshInfo()" - Returns the number of vertices and indices for the mesh of the render element at the specified index (e.g. one quad (4 vertices, 6 indices) if the GUI element displays just one texture). This allows external systems to know how big of a buffer to allocate for the element's mesh. It also returns the type of the mesh which lets external systems know in which format will be vertices be provided (e.g. 2D vertex followed by 2D UV coordinate) when calling @ref BansheeEngine::GUIElement::_fillBuffer() "_fillBuffer()".
  - @ref BansheeEngine::GUIElement::_fillBuffer() "_fillBuffer()" - This is the meat of the `GUIElement` override. It allows you to fill a buffer with vertices, uv coordinates and indices for a mesh for the specified render element. This allows you to fully control the look of your GUI element by providing customized geometry.
  - @ref BansheeEngine::GUIElement::_getMaterial() "_getMaterial()" - Here you should return a material that will be applied to the mesh output in the previous method, as well as an optional texture or color tint. You can choose from a set of pre-built materials or use your own material. 
  - @ref BansheeEngine::GUIElement::updateRenderElementsInternal() "updateRenderElementsInternal()" - Called whenever the element's size or style changes. In this method you should rebuild the element's mesh. (While you could build the mesh in `_fillBuffer` it is inefficient as `_fillBuffer` will get called much more often than `updateRenderElementsInternal` due to mesh batching).

+ 11 - 3
Source/BansheeCore/Include/BsVertexDeclaration.h

@@ -34,16 +34,24 @@ namespace BansheeEngine
         VET_FLOAT2 = 1, /**< 2D floating point value */
         VET_FLOAT3 = 2, /**< 3D floating point value */
         VET_FLOAT4 = 3, /**< 4D floating point value */
-		VET_COLOR = 4, /**< 4D floating point value */
+		VET_COLOR = 4, /**< Color encoded in 32-bits (8-bits per channel). */
 		VET_SHORT1 = 5, /**< 1D 16-bit signed integer value */
 		VET_SHORT2 = 6, /**< 2D 16-bit signed integer value */
-		VET_SHORT3 = 7, /**< 3D 16-bit signed integer value */
 		VET_SHORT4 = 8, /**< 4D 16-bit signed integer value */
         VET_UBYTE4 = 9, /**< 4D 8-bit unsigned integer value */
         VET_COLOR_ARGB = 10, /**< Color encoded in 32-bits (8-bits per channel) in ARGB order) */
         VET_COLOR_ABGR = 11, /**< Color encoded in 32-bits (8-bits per channel) in ABGR order) */
 		VET_UINT4 = 12, /**< 4D 32-bit unsigned integer value */
-		VET_SINT4 = 13  /**< 4D 32-bit signed integer value */
+		VET_INT4 = 13,  /**< 4D 32-bit signed integer value */
+		VET_USHORT1 = 14, /**< 1D 16-bit unsigned integer value */
+		VET_USHORT2 = 15, /**< 2D 16-bit unsigned integer value */
+		VET_USHORT4 = 17, /**< 4D 16-bit unsigned integer value */
+		VET_INT1 = 18,  /**< 1D 32-bit signed integer value */
+		VET_INT2 = 19,  /**< 2D 32-bit signed integer value */
+		VET_INT3 = 20,  /**< 3D 32-bit signed integer value */
+		VET_UINT1 = 21,  /**< 1D 32-bit signed integer value */
+		VET_UINT2 = 22,  /**< 2D 32-bit signed integer value */
+		VET_UINT3 = 23,  /**< 3D 32-bit signed integer value */
     };
 
 	/**	Describes a single vertex element in a vertex declaration. */

+ 40 - 23
Source/BansheeCore/Source/BsVertexDeclaration.cpp

@@ -30,25 +30,41 @@ namespace BansheeEngine
 		case VET_FLOAT1:
 			return sizeof(float);
 		case VET_FLOAT2:
-			return sizeof(float)*2;
+			return sizeof(float) * 2;
 		case VET_FLOAT3:
-			return sizeof(float)*3;
+			return sizeof(float) * 3;
 		case VET_FLOAT4:
-			return sizeof(float)*4;
+			return sizeof(float) * 4;
+		case VET_USHORT1:
+			return sizeof(UINT16);
+		case VET_USHORT2:
+			return sizeof(UINT16) * 2;
+		case VET_USHORT4:
+			return sizeof(UINT16) * 4;
 		case VET_SHORT1:
-			return sizeof(short);
+			return sizeof(INT16);
 		case VET_SHORT2:
-			return sizeof(short)*2;
-		case VET_SHORT3:
-			return sizeof(short)*3;
+			return sizeof(INT16) * 2;
 		case VET_SHORT4:
-			return sizeof(short)*4;
-		case VET_UBYTE4:
-			return sizeof(unsigned char)*4;
+			return sizeof(INT16) * 4;
+		case VET_UINT1:
+			return sizeof(UINT32);
+		case VET_UINT2:
+			return sizeof(UINT32) * 2;
+		case VET_UINT3:
+			return sizeof(UINT32) * 3;
 		case VET_UINT4:
 			return sizeof(UINT32) * 4;
-		case VET_SINT4:
+		case VET_INT4:
 			return sizeof(INT32) * 4;
+		case VET_INT1:
+			return sizeof(INT32);
+		case VET_INT2:
+			return sizeof(INT32) * 2;
+		case VET_INT3:
+			return sizeof(INT32) * 3;
+		case VET_UBYTE4:
+			return sizeof(UINT8) * 4;
 		}
 
 		return 0;
@@ -63,26 +79,27 @@ namespace BansheeEngine
 		case VET_COLOR_ARGB:
 			return 4;
 		case VET_FLOAT1:
+		case VET_SHORT1:
+		case VET_USHORT1:
+		case VET_INT1:
+		case VET_UINT1:
 			return 1;
 		case VET_FLOAT2:
+		case VET_SHORT2:
+		case VET_USHORT2:
+		case VET_INT2:
+		case VET_UINT2:
 			return 2;
 		case VET_FLOAT3:
+		case VET_INT3:
+		case VET_UINT3:
 			return 3;
 		case VET_FLOAT4:
-			return 4;
-		case VET_SHORT1:
-			return 1;
-		case VET_SHORT2:
-			return 2;
-		case VET_SHORT3:
-			return 3;
 		case VET_SHORT4:
-			return 4;
-		case VET_UBYTE4:
-			return 4;
+		case VET_USHORT4:
+		case VET_INT4:
 		case VET_UINT4:
-			return 4;
-		case VET_SINT4:
+		case VET_UBYTE4:
 			return 4;
 		}
 

+ 24 - 27
Source/BansheeD3D11RenderAPI/Source/BsD3D11Mappings.cpp

@@ -160,13 +160,10 @@ namespace BansheeEngine
 		{
 		case FT_MIN:
 			return D3D11_MIN_FILTER_SHIFT;
-			break;
 		case FT_MAG:
 			return D3D11_MAG_FILTER_SHIFT;
-			break;
 		case FT_MIP:
 			return D3D11_MIP_FILTER_SHIFT;
-			break;
 		}
 
 		// Unsupported type
@@ -282,34 +279,44 @@ namespace BansheeEngine
 		case VET_COLOR_ABGR:
 		case VET_COLOR_ARGB:
 			return DXGI_FORMAT_R8G8B8A8_UNORM;
-			break;
 		case VET_FLOAT1:
 			return DXGI_FORMAT_R32_FLOAT;
-			break;
 		case VET_FLOAT2:
 			return DXGI_FORMAT_R32G32_FLOAT;
-			break;
 		case VET_FLOAT3:
 			return DXGI_FORMAT_R32G32B32_FLOAT;
-			break;
 		case VET_FLOAT4:
 			return DXGI_FORMAT_R32G32B32A32_FLOAT;
-			break;
+		case VET_USHORT1:
+			return DXGI_FORMAT_R16_UINT;
+		case VET_USHORT2:
+			return DXGI_FORMAT_R16G16_UINT;
+		case VET_USHORT4:
+			return DXGI_FORMAT_R16G16B16A16_UINT;
+		case VET_SHORT1:
+			return DXGI_FORMAT_R16_SINT;
 		case VET_SHORT2:
 			return DXGI_FORMAT_R16G16_SINT;
-			break;
 		case VET_SHORT4:
 			return DXGI_FORMAT_R16G16B16A16_SINT;
-			break;
-		case VET_UBYTE4:
-			return DXGI_FORMAT_R8G8B8A8_UINT;
-			break;
+		case VET_UINT1:
+			return DXGI_FORMAT_R32_UINT;
+		case VET_UINT2:
+			return DXGI_FORMAT_R32G32_UINT;
+		case VET_UINT3:
+			return DXGI_FORMAT_R32G32B32_UINT;
 		case VET_UINT4:
 			return DXGI_FORMAT_R32G32B32A32_UINT;
-			break;
-		case VET_SINT4:
+		case VET_INT1:
+			return DXGI_FORMAT_R32_SINT;
+		case VET_INT2:
+			return DXGI_FORMAT_R32G32_SINT;
+		case VET_INT3:
+			return DXGI_FORMAT_R32G32B32_SINT;
+		case VET_INT4:
 			return DXGI_FORMAT_R32G32B32A32_SINT;
-			break;
+		case VET_UBYTE4:
+			return DXGI_FORMAT_R8G8B8A8_UINT;
 		}
 
 		// Unsupported type
@@ -349,34 +356,24 @@ namespace BansheeEngine
 		{
 		case VES_BLEND_INDICES:
 			return "BLENDINDICES";
-			break;
 		case VES_BLEND_WEIGHTS:
 			return "BLENDWEIGHT";
-			break;
 		case VES_COLOR:
 			return "COLOR";
-			break;
 		case VES_NORMAL:
 			return "NORMAL";
-			break;
 		case VES_POSITION:
 			return "POSITION";
-			break;
 		case VES_TEXCOORD:
 			return "TEXCOORD";
-			break;
 		case VES_BITANGENT:
 			return "BINORMAL";
-			break;
 		case VES_TANGENT:
 			return "TANGENT";
-			break;
 		case VES_POSITIONT:
 			return "POSITIONT";
-			break;
 		case VES_PSIZE:
 			return "PSIZE";
-			break;
 		}
 
 		// Unsupported type
@@ -390,7 +387,7 @@ namespace BansheeEngine
 		case D3D_REGISTER_COMPONENT_FLOAT32:
 			return VET_FLOAT4;
 		case D3D_REGISTER_COMPONENT_SINT32:
-			return VET_SINT4;
+			return VET_INT4;
 		case D3D_REGISTER_COMPONENT_UINT32:
 			return VET_UINT4;
 		default:

+ 3 - 8
Source/BansheeD3D9RenderAPI/Source/BsD3D9Mappings.cpp

@@ -337,28 +337,23 @@ namespace BansheeEngine
 		case VET_COLOR_ABGR:
 		case VET_COLOR_ARGB:
 			return D3DDECLTYPE_D3DCOLOR;
-			break;
 		case VET_FLOAT1:
 			return D3DDECLTYPE_FLOAT1;
-			break;
 		case VET_FLOAT2:
 			return D3DDECLTYPE_FLOAT2;
-			break;
 		case VET_FLOAT3:
 			return D3DDECLTYPE_FLOAT3;
-			break;
 		case VET_FLOAT4:
 			return D3DDECLTYPE_FLOAT4;
-			break;
         case VET_SHORT2:
 			return D3DDECLTYPE_SHORT2;
-			break;
         case VET_SHORT4:
 			return D3DDECLTYPE_SHORT4;
-			break;
         case VET_UBYTE4:
             return D3DDECLTYPE_UBYTE4;
-            break;
+		default:
+			LOGWRN("Invalid vertex element type for DX9.");
+			break;
 		}
 
 		return D3DDECLTYPE_FLOAT3;

+ 3 - 3
Source/BansheeEditor/Include/BsGUIColor.h

@@ -65,11 +65,11 @@ namespace BansheeEngine
 		const SpriteMaterialInfo& _getMaterial(UINT32 renderElementIdx, SpriteMaterial** material) const override;
 
 		/** @copydoc GUIElement::_getMeshSize() */
-		void _getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const override;
+		void _getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const override;
 
 		/** @copydoc GUIElement::_fillBuffer() */
-		void _fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset, 
-			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const override;
+		void _fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset, 
+			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const override;
 
 		/** @copydoc GUIElement::updateRenderElementsInternal() */
 		void updateRenderElementsInternal() override;

+ 11 - 6
Source/BansheeEditor/Source/BsGUIColor.cpp

@@ -78,7 +78,7 @@ namespace BansheeEngine
 		}
 	}
 
-	void GUIColor::_getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const
+	void GUIColor::_getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const
 	{
 		UINT32 alphaSpriteIdx = mColorSprite->getNumRenderElements();
 
@@ -90,6 +90,7 @@ namespace BansheeEngine
 
 		numVertices = numQuads * 4;
 		numIndices = numQuads * 6;
+		type = GUIMeshType::Triangle;
 	}
 
 	void GUIColor::updateRenderElementsInternal()
@@ -119,15 +120,19 @@ namespace BansheeEngine
 		return GUIHelper::calcOptimalContentsSize(Vector2I(80, 10), *_getStyle(), _getDimensions()); // Arbitrary size
 	}
 
-	void GUIColor::_fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
-		UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
+	void GUIColor::_fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
+		UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const
 	{
+		UINT8* uvs = vertices + sizeof(Vector2);
+		UINT32 vertexStride = sizeof(Vector2) * 2;
+		UINT32 indexStride = sizeof(UINT32);
+		
 		UINT32 alphaSpriteIdx = mColorSprite->getNumRenderElements();
-
+		
 		Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
 		if(renderElementIdx < alphaSpriteIdx)
 		{
-			mColorSprite->fillBuffer(vertices, uv, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
+			mColorSprite->fillBuffer(vertices, uvs, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
 				vertexStride, indexStride, renderElementIdx, offset, mLayoutData.getLocalClipRect());
 		}
 		else if(renderElementIdx >= alphaSpriteIdx)
@@ -139,7 +144,7 @@ namespace BansheeEngine
 			Rect2I alphaClipRect = mLayoutData.getLocalClipRect();
 			alphaClipRect.x -= xOffset;
 
-			mAlphaSprite->fillBuffer(vertices, uv, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
+			mAlphaSprite->fillBuffer(vertices, uvs, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
 				vertexStride, indexStride, alphaSpriteIdx - renderElementIdx, alphaOffset, alphaClipRect);
 		}
 	}

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

@@ -44,5 +44,14 @@ namespace BansheeEngine
 		RepeatToFit /**< Image will keep its original size, but will repeat in order to fill the assigned area. */
 	};
 
+	/** Types of GUI meshes that can be output by GUI elements. */
+	enum class GUIMeshType
+	{
+		/** Mesh containing a set of vertices as 2D position followed by 2D UV coordinates. */
+		Triangle,
+		/** Mesh containing a set of vertices as 2D position followed by vertex indices. */
+		Line
+	};
+
 	/** @} */
 }

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

@@ -72,11 +72,11 @@ namespace BansheeEngine
 		const SpriteMaterialInfo& _getMaterial(UINT32 renderElementIdx, SpriteMaterial** material) const override;
 
 		/** @copydoc GUIElement::_getMeshSize() */
-		void _getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const override;
+		void _getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const override;
 
 		/** @copydoc GUIElement::_fillBuffer */
-		void _fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
-			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const override;
+		void _fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
+			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const override;
 
 		/** @copydoc GUIElement::updateRenderElementsInternal */
 		void updateRenderElementsInternal() override;

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

@@ -192,11 +192,11 @@ namespace BansheeEngine
 		const SpriteMaterialInfo& _getMaterial(UINT32 renderElementIdx, SpriteMaterial** material) const override;
 
 		/** @copydoc GUIElement::_getMeshSize() */
-		void _getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const override;
+		void _getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const override;
 
 		/** @copydoc GUIElement::_fillBuffer */
-		void _fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
-			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const override;
+		void _fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
+			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const override;
 
 		/** @copydoc GUIElement::updateRenderElementsInternal */
 		void updateRenderElementsInternal() override;

+ 7 - 9
Source/BansheeEngine/Include/BsGUIElement.h

@@ -108,19 +108,19 @@ namespace BansheeEngine
 		virtual const SpriteMaterialInfo& _getMaterial(UINT32 renderElementIdx, SpriteMaterial** material) const = 0;
 
 		/**
-		 * Returns the number of vertices and indices that the specified render element will use. You will need this value
-		 * when creating the buffers before calling _fillBuffer().
+		 * Returns the type of mesh and number of vertices and indices that the specified render element will use. You will
+		 * need this value when creating the buffers before calling _fillBuffer().
 		 *
 		 * @see		_getNumRenderElements()
 		 * @see		_fillBuffer()
 		 */
-		virtual void _getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const = 0;
+		virtual void _getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const = 0;
 
 		/**
 		 * Fill the pre-allocated vertex, uv and index buffers with the mesh data for the specified render element.
 		 * 			
-		 * @param[out]	vertices			Previously allocated buffer where to store the vertices.
-		 * @param[out]	uv					Previously allocated buffer where to store the uv coordinates.
+		 * @param[out]	vertices			Previously allocated buffer where to store the vertices. Output is expected
+		 *									to match the GUIMeshType as returned by _getMeshInfo.
 		 * @param[out]	indices				Previously allocated buffer where to store the indices.
 		 * @param[in]	vertexOffset		At which vertex should the method start filling the buffer.
 		 * @param[in]	indexOffset			At which index should the method start filling the buffer.
@@ -128,15 +128,13 @@ namespace BansheeEngine
 		 *									safety.
 		 * @param[in]	maxNumIndices		Total number of indices the buffers were allocated for. Used only for memory
 		 *									safety.
-		 * @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]	renderElementIdx	Zero-based index of the render element.
 		 *
 		 * @see		_getNumRenderElements()
 		 * @see		_getMeshSize()
 		 */
-		virtual void _fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
-			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const = 0;
+		virtual void _fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
+			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const = 0;
 
 		/**
 		 * Recreates the internal render elements. Must be called before fillBuffer if element is dirty. Marks the element

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

@@ -25,11 +25,11 @@ namespace BansheeEngine
 		const SpriteMaterialInfo& _getMaterial(UINT32 renderElementIdx, SpriteMaterial** material) const override;
 
 		/** @copydoc GUIElement::_getMeshSize() */
-		void _getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const override;
+		void _getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const override;
 
 		/** @copydoc GUIElement::_fillBuffer */
-		void _fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
-			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const override;
+		void _fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
+			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const override;
 
 		/** @copydoc GUIElement::_getOptimalSize */
 		Vector2I _getOptimalSize() const override;

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

@@ -107,11 +107,11 @@ namespace BansheeEngine
 		const SpriteMaterialInfo& _getMaterial(UINT32 renderElementIdx, SpriteMaterial** material) const override;
 
 		/** @copydoc GUIElement::_getMeshSize() */
-		void _getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const override;
+		void _getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const override;
 
 		/** @copydoc GUIElement::_fillBuffer() */
-		void _fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
-			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const override;
+		void _fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
+			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const override;
 
 		/** @copydoc GUIElement::updateRenderElementsInternal() */
 		void updateRenderElementsInternal() override;

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

@@ -85,11 +85,11 @@ namespace BansheeEngine
 		const SpriteMaterialInfo& _getMaterial(UINT32 renderElementIdx, SpriteMaterial** material) const override;
 
 		/** @copydoc GUIElement::_getMeshSize() */
-		void _getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const override;
+		void _getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const override;
 
 		/** @copydoc GUIElement::_fillBuffer */
-		void _fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
-			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const override;
+		void _fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
+			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const override;
 
 		/** @copydoc GUIElement::updateRenderElementsInternal */
 		void updateRenderElementsInternal() override;

+ 10 - 7
Source/BansheeEngine/Include/BsGUIManager.h

@@ -48,11 +48,13 @@ namespace BansheeEngine
 			Dragging
 		};
 
-		/** Material data required for rendering a single GUI mesh. */
-		struct GUIMaterialData
+		/** Data required for rendering a single GUI mesh. */
+		struct GUIMeshData
 		{
+			SPtr<TransientMesh> mesh;
 			SpriteMaterial* material;
 			SpriteMaterialInfo matInfo;
+			GUIWidget* widget;
 		};
 
 		/**	GUI render data for a single viewport. */
@@ -62,9 +64,8 @@ namespace BansheeEngine
 				:isDirty(true)
 			{ }
 
-			Vector<SPtr<TransientMesh>> cachedMeshes;
-			Vector<GUIMaterialData> cachedMaterials;
-			Vector<GUIWidget*> cachedWidgetsPerMesh;
+			Vector<GUIMeshData> cachedTriangleMeshes;
+			Vector<GUIMeshData> cachedLineMeshes;
 			Vector<GUIWidget*> widgets;
 			bool isDirty;
 		};
@@ -347,12 +348,14 @@ namespace BansheeEngine
 
 		Vector<WidgetInfo> mWidgets;
 		UnorderedMap<const Viewport*, GUIRenderData> mCachedGUIData;
-		SPtr<MeshHeap> mMeshHeap;
+		SPtr<MeshHeap> mTriangleMeshHeap;
+		SPtr<MeshHeap> mLineMeshHeap;
 
 		std::atomic<GUIManagerCore*> mCore;
 		bool mCoreDirty;
 
-		SPtr<VertexDataDesc> mVertexDesc;
+		SPtr<VertexDataDesc> mTriangleVertexDesc;
+		SPtr<VertexDataDesc> mLineVertexDesc;
 
 		Stack<GUIElement*> mScheduledForDestruction;
 

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

@@ -83,11 +83,11 @@ namespace BansheeEngine
 		const SpriteMaterialInfo& _getMaterial(UINT32 renderElementIdx, SpriteMaterial** material) const override;
 
 		/** @copydoc GUIElement::_getMeshSize() */
-		void _getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const override;
+		void _getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const override;
 
 		/** @copydoc GUIElement::_fillBuffer */
-		void _fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
-			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const override;
+		void _fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
+			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const override;
 
 		/** @copydoc GUIElement::updateRenderElementsInternal */
 		void updateRenderElementsInternal() override;

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

@@ -109,11 +109,11 @@ namespace BansheeEngine
 		const SpriteMaterialInfo& _getMaterial(UINT32 renderElementIdx, SpriteMaterial** material) const override;
 
 		/** @copydoc GUIElement::_getMeshSize() */
-		void _getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const override;
+		void _getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const override;
 
 		/** @copydoc GUIElement::_fillBuffer() */
-		void _fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
-			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const override;
+		void _fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
+			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const override;
 
 		/** @copydoc GUIElement::updateRenderElementsInternal() */
 		void updateRenderElementsInternal() override;

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

@@ -166,11 +166,11 @@ namespace BansheeEngine
 		const SpriteMaterialInfo& _getMaterial(UINT32 renderElementIdx, SpriteMaterial** material) const override;
 
 		/** @copydoc GUIElement::_getMeshSize() */
-		void _getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const override;
+		void _getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const override;
 
 		/** @copydoc GUIElement::_fillBuffer */
-		void _fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
-			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const override;
+		void _fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
+			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const override;
 
 		/** @copydoc GUIElement::updateRenderElementsInternal */
 		void updateRenderElementsInternal() override;

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

@@ -70,11 +70,11 @@ namespace BansheeEngine
 		const SpriteMaterialInfo& _getMaterial(UINT32 renderElementIdx, SpriteMaterial** material) const override;
 
 		/** @copydoc GUIElement::_getMeshSize() */
-		void _getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const override;
+		void _getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const override;
 
 		/** @copydoc GUIElement::_fillBuffer */
-		void _fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
-			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const override;
+		void _fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
+			UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const override;
 
 		/** @copydoc GUIElement::updateClippedBounds */
 		void updateClippedBounds() override;

+ 11 - 6
Source/BansheeEngine/Source/BsGUIButtonBase.cpp

@@ -91,7 +91,7 @@ namespace BansheeEngine
 		}
 	}
 
-	void GUIButtonBase::_getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const
+	void GUIButtonBase::_getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const
 	{
 		UINT32 textSpriteIdx = mImageSprite->getNumRenderElements();
 		UINT32 contentImgSpriteIdx = textSpriteIdx + mTextSprite->getNumRenderElements();
@@ -106,6 +106,7 @@ namespace BansheeEngine
 
 		numVertices = numQuads * 4;
 		numIndices = numQuads * 6;
+		type = GUIMeshType::Triangle;
 	}
 
 	void GUIButtonBase::updateRenderElementsInternal()
@@ -203,9 +204,13 @@ namespace BansheeEngine
 		return 2;
 	}
 
-	void GUIButtonBase::_fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
-		UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
+	void GUIButtonBase::_fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
+		UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const
 	{
+		UINT8* uvs = vertices + sizeof(Vector2);
+		UINT32 vertexStride = sizeof(Vector2) * 2;
+		UINT32 indexStride = sizeof(UINT32);
+
 		UINT32 textSpriteIdx = mImageSprite->getNumRenderElements();
 		UINT32 contentImgSpriteIdx = textSpriteIdx + mTextSprite->getNumRenderElements();
 
@@ -213,7 +218,7 @@ namespace BansheeEngine
 		{
 			Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
 
-			mImageSprite->fillBuffer(vertices, uv, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
+			mImageSprite->fillBuffer(vertices, uvs, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
 				vertexStride, indexStride, renderElementIdx, offset, mLayoutData.getLocalClipRect());
 
 			return;
@@ -280,12 +285,12 @@ namespace BansheeEngine
 
 		if(renderElementIdx >= contentImgSpriteIdx)
 		{
-			mContentImageSprite->fillBuffer(vertices, uv, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
+			mContentImageSprite->fillBuffer(vertices, uvs, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
 				vertexStride, indexStride, contentImgSpriteIdx - renderElementIdx, imageOffset, imageClipRect);
 		}
 		else
 		{
-			mTextSprite->fillBuffer(vertices, uv, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
+			mTextSprite->fillBuffer(vertices, uvs, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
 				vertexStride, indexStride, textSpriteIdx - renderElementIdx, textOffset, textClipRect);
 		}
 	}

+ 54 - 7
Source/BansheeEngine/Source/BsGUICanvas.cpp

@@ -228,7 +228,7 @@ namespace BansheeEngine
 		}
 	}
 
-	void GUICanvas::_getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const
+	void GUICanvas::_getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const
 	{
 		Vector2 offset((float)mLayoutData.area.x, (float)mLayoutData.area.y);
 		Rect2I clipRect = mLayoutData.getLocalClipRect();
@@ -242,21 +242,29 @@ namespace BansheeEngine
 			UINT32 numQuads = element.imageSprite->getNumQuads(renderElementIdx);
 			numVertices = numQuads * 4;
 			numIndices = numQuads * 6;
+			type = GUIMeshType::Triangle;
 		}
 		case CanvasElementType::Text:
 		{
 			UINT32 numQuads = element.textSprite->getNumQuads(renderElementIdx);
 			numVertices = numQuads * 4;
 			numIndices = numQuads * 6;
+			type = GUIMeshType::Triangle;
 		}
 		case CanvasElementType::Line:
+			numVertices = element.clippedNumVertices;
+			numIndices = element.clippedNumVertices;
+			type = GUIMeshType::Line;
+			break;
 		case CanvasElementType::Triangle:
 			numVertices = element.clippedNumVertices;
 			numIndices = element.clippedNumVertices;
+			type = GUIMeshType::Triangle;
 			break;
 		default:
 			numVertices = 0;
 			numIndices = 0;
+			type = GUIMeshType::Triangle;
 			break;
 		}
 	}
@@ -300,9 +308,12 @@ namespace BansheeEngine
 		return Vector2I(10, 10);
 	}
 
-	void GUICanvas::_fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
-		UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
+	void GUICanvas::_fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
+		UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const
 	{
+		UINT8* uvs = vertices + sizeof(Vector2);
+		UINT32 indexStride = sizeof(UINT32);
+
 		Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
 		Rect2I clipRect = mLayoutData.getLocalClipRect();
 
@@ -314,6 +325,7 @@ namespace BansheeEngine
 		{
 		case CanvasElementType::Image:
 		{
+			UINT32 vertexStride = sizeof(Vector2) * 2;
 			const Rect2I& area = mImageData[element.dataId].area;
 
 			offset.x += area.x;
@@ -321,24 +333,26 @@ namespace BansheeEngine
 			clipRect.x -= area.x;
 			clipRect.y -= area.y;
 
-			element.imageSprite->fillBuffer(vertices, uv, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
+			element.imageSprite->fillBuffer(vertices, uvs, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
 				vertexStride, indexStride, renderElementIdx, offset, clipRect);
 		}
 			break;
 		case CanvasElementType::Text:
 		{
+			UINT32 vertexStride = sizeof(Vector2) * 2;
 			const Vector2I& position = mTextData[element.dataId].position;
 			offset += position;
 			clipRect.x += position.x;
 			clipRect.y += position.y;
 
-			element.textSprite->fillBuffer(vertices, uv, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
+			element.textSprite->fillBuffer(vertices, uvs, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
 				vertexStride, indexStride, renderElementIdx, offset, mLayoutData.getLocalClipRect());
 		}
 			break;
 		case CanvasElementType::Triangle:
-		case CanvasElementType::Line:
 		{
+			UINT32 vertexStride = sizeof(Vector2) * 2;
+
 			UINT32 startVert = vertexOffset;
 			UINT32 startIndex = indexOffset;
 
@@ -352,7 +366,7 @@ namespace BansheeEngine
 			assert((startIndex + numIndices) <= maxIndexIdx);
 
 			UINT8* vertDst = vertices + startVert * vertexStride;
-			UINT8* uvDst = uv + startVert * vertexStride;
+			UINT8* uvDst = uvs + startVert * vertexStride;
 			UINT32* indexDst = indices + startIndex;
 
 			Vector2 zeroUV;
@@ -367,6 +381,39 @@ namespace BansheeEngine
 			}
 		}
 			break;
+		case CanvasElementType::Line:
+		{
+			UINT32 vertexStride = sizeof(Vector2) + sizeof(UINT32);
+
+			UINT32 startVert = vertexOffset;
+			UINT32 startIndex = indexOffset;
+
+			UINT32 maxVertIdx = maxNumVerts;
+			UINT32 maxIndexIdx = maxNumIndices;
+
+			UINT32 numVertices = element.clippedNumVertices;
+			UINT32 numIndices = numVertices;
+
+			assert((startVert + numVertices) <= maxVertIdx);
+			assert((startIndex + numIndices) <= maxIndexIdx);
+
+			UINT8* vertDst = vertices + startVert * vertexStride;
+			UINT8* lineIdxDst = vertDst + sizeof(UINT32);
+			UINT32* indexDst = indices + startIndex;
+
+			for (UINT32 i = 0; i < element.clippedNumVertices; i++)
+			{
+				UINT32 lineIdx = i / 6;
+
+				memcpy(vertDst, &mClippedVertices[element.clippedVertexStart + i], sizeof(Vector2));
+				memcpy(lineIdxDst, &lineIdx, sizeof(UINT32));
+
+				vertDst += vertexStride;
+				lineIdxDst += vertexStride;
+				indexDst[i] = i;
+			}
+		}
+		break;
 		}
 	}
 

+ 4 - 3
Source/BansheeEngine/Source/BsGUIElementContainer.cpp

@@ -25,14 +25,15 @@ namespace BansheeEngine
 		return dummy;
 	}
 
-	void GUIElementContainer::_getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const
+	void GUIElementContainer::_getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const
 	{
 		numVertices = 0;
 		numIndices = 0;
+		type = GUIMeshType::Triangle;
 	}
 
-	void GUIElementContainer::_fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
-		UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
+	void GUIElementContainer::_fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
+		UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const
 	{ }
 
 	Vector2I GUIElementContainer::_getOptimalSize() const

+ 9 - 4
Source/BansheeEngine/Source/BsGUIInputBox.cpp

@@ -130,7 +130,7 @@ namespace BansheeEngine
 		return sprite->getMaterialInfo(localRenderElementIdx);
 	}
 
-	void GUIInputBox::_getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const
+	void GUIInputBox::_getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const
 	{
 		UINT32 localRenderElementIdx;
 		Sprite* sprite = renderElemToSprite(renderElementIdx, localRenderElementIdx);
@@ -138,6 +138,7 @@ namespace BansheeEngine
 		UINT32 numQuads = sprite->getNumQuads(localRenderElementIdx);
 		numVertices = numQuads * 4;
 		numIndices = numQuads * 6;
+		type = GUIMeshType::Triangle;
 	}
 
 	void GUIInputBox::updateRenderElementsInternal()
@@ -386,15 +387,19 @@ namespace BansheeEngine
 		return false;
 	}
 
-	void GUIInputBox::_fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
-		UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
+	void GUIInputBox::_fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
+		UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const
 	{
+		UINT8* uvs = vertices + sizeof(Vector2);
+		UINT32 vertexStride = sizeof(Vector2) * 2;
+		UINT32 indexStride = sizeof(UINT32);
+
 		UINT32 localRenderElementIdx;
 		Sprite* sprite = renderElemToSprite(renderElementIdx, localRenderElementIdx);
 		Vector2I offset = renderElemToOffset(renderElementIdx);
 		Rect2I clipRect = renderElemToClipRect(renderElementIdx);
 
-		sprite->fillBuffer(vertices, uv, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices, vertexStride, 
+		sprite->fillBuffer(vertices, uvs, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices, vertexStride, 
 			indexStride, localRenderElementIdx, offset, clipRect);
 	}
 

+ 8 - 4
Source/BansheeEngine/Source/BsGUILabel.cpp

@@ -30,12 +30,13 @@ namespace BansheeEngine
 		return mTextSprite->getMaterialInfo(renderElementIdx);
 	}
 
-	void GUILabel::_getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const
+	void GUILabel::_getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const
 	{
 		UINT32 numQuads = mTextSprite->getNumQuads(renderElementIdx);
 
 		numVertices = numQuads * 4;
 		numIndices = numQuads * 6;
+		type = GUIMeshType::Triangle;
 	}
 
 	void GUILabel::updateRenderElementsInternal()
@@ -60,12 +61,15 @@ namespace BansheeEngine
 		return GUIHelper::calcOptimalContentsSize(mContent, *_getStyle(), _getDimensions());
 	}
 
-	void GUILabel::_fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
-		UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
+	void GUILabel::_fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
+		UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const
 	{
+		UINT8* uvs = vertices + sizeof(Vector2);
+		UINT32 vertexStride = sizeof(Vector2) * 2;
+		UINT32 indexStride = sizeof(UINT32);
 		Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
 
-		mTextSprite->fillBuffer(vertices, uv, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices, vertexStride,
+		mTextSprite->fillBuffer(vertices, uvs, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices, vertexStride,
 			indexStride, renderElementIdx, offset, mLayoutData.getLocalClipRect());
 	}
 

+ 112 - 69
Source/BansheeEngine/Source/BsGUIManager.cpp

@@ -59,6 +59,7 @@ namespace BansheeEngine
 	{
 		SpriteMaterial* material;
 		SpriteMaterialInfo matInfo;
+		GUIMeshType meshType;
 		UINT32 numVertices;
 		UINT32 numIndices;
 		UINT32 depth;
@@ -99,11 +100,17 @@ namespace BansheeEngine
 		GUIDropDownBoxManager::startUp();
 		GUITooltipManager::startUp();
 
-		mVertexDesc = bs_shared_ptr_new<VertexDataDesc>();
-		mVertexDesc->addVertElem(VET_FLOAT2, VES_POSITION);
-		mVertexDesc->addVertElem(VET_FLOAT2, VES_TEXCOORD);
+		mTriangleVertexDesc = bs_shared_ptr_new<VertexDataDesc>();
+		mTriangleVertexDesc->addVertElem(VET_FLOAT2, VES_POSITION);
+		mTriangleVertexDesc->addVertElem(VET_FLOAT2, VES_TEXCOORD);
 
-		mMeshHeap = MeshHeap::create(MESH_HEAP_INITIAL_NUM_VERTS, MESH_HEAP_INITIAL_NUM_INDICES, mVertexDesc);
+		mTriangleMeshHeap = MeshHeap::create(MESH_HEAP_INITIAL_NUM_VERTS, MESH_HEAP_INITIAL_NUM_INDICES, mTriangleVertexDesc);
+
+		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);
 
 		// Need to defer this call because I want to make sure all managers are initialized first
 		deferredCall(std::bind(&GUIManager::updateCaretTexture, this));
@@ -215,10 +222,16 @@ namespace BansheeEngine
 
 		if(renderData.widgets.size() == 0)
 		{
-			for (auto& mesh : renderData.cachedMeshes)
+			for (auto& entry : renderData.cachedTriangleMeshes)
+			{
+				if (entry.mesh != nullptr)
+					mTriangleMeshHeap->dealloc(entry.mesh);
+			}
+
+			for (auto& entry : renderData.cachedLineMeshes)
 			{
-				if (mesh != nullptr)
-					mMeshHeap->dealloc(mesh);
+				if (entry.mesh != nullptr)
+					mLineMeshHeap->dealloc(entry.mesh);
 			}
 
 			mCachedGUIData.erase(renderTarget);
@@ -385,35 +398,38 @@ namespace BansheeEngine
 				auto insertedData = corePerCameraData.insert(std::make_pair(camera->getCore(), Vector<GUICoreRenderData>()));
 				Vector<GUICoreRenderData>& cameraData = insertedData.first->second;
 
+				const Vector<GUIMeshData>* cachedMeshSets[2] = { &renderData.cachedTriangleMeshes, &renderData.cachedLineMeshes };
+
 				UINT32 meshIdx = 0;
-				for (auto& mesh : renderData.cachedMeshes)
+				for (auto& meshSet : cachedMeshSets)
 				{
-					const GUIMaterialData& guiMaterial = renderData.cachedMaterials[meshIdx];
-					GUIWidget* widget = renderData.cachedWidgetsPerMesh[meshIdx];
-
-					if (guiMaterial.matInfo.texture == nullptr || !guiMaterial.matInfo.texture.isLoaded())
+					const Vector<GUIMeshData>& cachedMeshes = *meshSet;
+					for (auto& entry : cachedMeshes)
 					{
-						meshIdx++;
-						continue;
-					}
+						if (entry.matInfo.texture == nullptr || !entry.matInfo.texture.isLoaded())
+						{
+							meshIdx++;
+							continue;
+						}
 
-					if (mesh == nullptr)
-					{
-						meshIdx++;
-						continue;
-					}
+						if (entry.mesh == nullptr)
+						{
+							meshIdx++;
+							continue;
+						}
 
-					cameraData.push_back(GUICoreRenderData());
-					GUICoreRenderData& newEntry = cameraData.back();
+						cameraData.push_back(GUICoreRenderData());
+						GUICoreRenderData& newEntry = cameraData.back();
 
-					newEntry.material = guiMaterial.material;
-					newEntry.texture = guiMaterial.matInfo.texture->getCore();
-					newEntry.tint = guiMaterial.matInfo.tint;
-					newEntry.mesh = mesh->getCore();
-					newEntry.worldTransform = widget->getWorldTfrm();
-					newEntry.additionalData = guiMaterial.matInfo.additionalData;
+						newEntry.material = entry.material;
+						newEntry.texture = entry.matInfo.texture->getCore();
+						newEntry.tint = entry.matInfo.tint;
+						newEntry.mesh = entry.mesh->getCore();
+						newEntry.worldTransform = entry.widget->getWorldTfrm();
+						newEntry.additionalData = entry.matInfo.additionalData;
 
-					meshIdx++;
+						meshIdx++;
+					}
 				}
 			}
 
@@ -574,7 +590,7 @@ namespace BansheeEngine
 						foundGroup->matInfo = matInfo.clone();
 						foundGroup->material = spriteMaterial;
 
-						guiElem->_getMeshSize(renderElemIdx, foundGroup->numVertices, foundGroup->numIndices);
+						guiElem->_getMeshInfo(renderElemIdx, foundGroup->numVertices, foundGroup->numIndices, foundGroup->meshType);
 					}
 					else
 					{
@@ -584,7 +600,10 @@ namespace BansheeEngine
 						
 						UINT32 numVertices;
 						UINT32 numIndices;
-						guiElem->_getMeshSize(renderElemIdx, numVertices, numIndices);
+						GUIMeshType meshType;
+						guiElem->_getMeshInfo(renderElemIdx, numVertices, numIndices, meshType);
+						assert(meshType == foundGroup->meshType); // It's expected that GUI element doesn't use same material for different mesh types so this should always be true
+
 						foundGroup->numVertices += numVertices;
 						foundGroup->numIndices += numIndices;
 
@@ -600,68 +619,83 @@ namespace BansheeEngine
 					// requires all elements to be unique
 				};
 
+				UINT32 numTriangleMeshes = 0;
+				UINT32 numLineMeshes = 0;
 				FrameSet<GUIMaterialGroup*, std::function<bool(GUIMaterialGroup*, GUIMaterialGroup*)>> sortedGroups(groupComp);
 				for(auto& material : materialGroups)
 				{
 					for(auto& group : material.second)
 					{
 						sortedGroups.insert(&group);
+
+						if (group.meshType == GUIMeshType::Triangle)
+							numTriangleMeshes++;
+						else // Line
+							numLineMeshes++;
 					}
 				}
 
-				UINT32 numMeshes = (UINT32)sortedGroups.size();
-				UINT32 oldNumMeshes = (UINT32)renderData.cachedMeshes.size();
+				UINT32 oldNumTriangleMeshes = (UINT32)renderData.cachedTriangleMeshes.size();
+				for (UINT32 i = numTriangleMeshes; i < oldNumTriangleMeshes; i++)
+					mTriangleMeshHeap->dealloc(renderData.cachedTriangleMeshes[i].mesh);
 
-				if(numMeshes < oldNumMeshes)
-				{
-					for (UINT32 i = numMeshes; i < oldNumMeshes; i++)
-						mMeshHeap->dealloc(renderData.cachedMeshes[i]);
+				renderData.cachedTriangleMeshes.resize(numTriangleMeshes);
 
-					renderData.cachedMeshes.resize(numMeshes);
-				}
+				UINT32 oldNumLineMeshes = (UINT32)renderData.cachedLineMeshes.size();
+				for (UINT32 i = numLineMeshes; i < oldNumLineMeshes; i++)
+					mLineMeshHeap->dealloc(renderData.cachedLineMeshes[i].mesh);
 
-				renderData.cachedMaterials.resize(numMeshes);
-
-				if(mSeparateMeshesByWidget)
-					renderData.cachedWidgetsPerMesh.resize(numMeshes);
+				renderData.cachedLineMeshes.resize(numLineMeshes);
 
 				// Fill buffers for each group and update their meshes
-				UINT32 groupIdx = 0;
+				UINT32 triangleMeshIdx = 0;
+				UINT32 lineMeshIdx = 0;
 				for(auto& group : sortedGroups)
 				{
-					GUIMaterialData& matData = renderData.cachedMaterials[groupIdx];
-					matData.matInfo = group->matInfo;
-					matData.material = group->material;
+					SPtr<MeshData> meshData;
+					GUIWidget* widget;
 
-					if(mSeparateMeshesByWidget)
+					if (group->elements.size() == 0)
+						widget = nullptr;
+					else
 					{
-						if(group->elements.size() == 0)
-							renderData.cachedWidgetsPerMesh[groupIdx] = nullptr;
-						else
-						{
-							GUIElement* elem = group->elements.begin()->element;
-							renderData.cachedWidgetsPerMesh[groupIdx] = elem->_getParentWidget();
-						}
+						GUIElement* elem = group->elements.begin()->element;
+						widget = elem->_getParentWidget();
+					}
+
+					if (group->meshType == GUIMeshType::Triangle)
+					{
+						meshData = bs_shared_ptr_new<MeshData>(group->numVertices, group->numIndices, mTriangleVertexDesc);
+
+						GUIMeshData& guiMeshData = renderData.cachedTriangleMeshes[triangleMeshIdx];
+						guiMeshData.matInfo = group->matInfo;
+						guiMeshData.material = group->material;
+						guiMeshData.widget = widget;
 					}
+					else // Line
+					{
+						meshData = bs_shared_ptr_new<MeshData>(group->numVertices, group->numIndices, mLineVertexDesc);
 
-					SPtr<MeshData> meshData = bs_shared_ptr_new<MeshData>(group->numVertices, group->numIndices, mVertexDesc);
+						GUIMeshData& guiMeshData = renderData.cachedLineMeshes[lineMeshIdx];
+						guiMeshData.matInfo = group->matInfo;
+						guiMeshData.material = group->material;
+						guiMeshData.widget = widget;
+					}
 
 					UINT8* vertices = meshData->getElementData(VES_POSITION);
-					UINT8* uvs = meshData->getElementData(VES_TEXCOORD);
 					UINT32* indices = meshData->getIndices32();
-					UINT32 vertexStride = meshData->getVertexDesc()->getVertexStride();
-					UINT32 indexStride = meshData->getIndexElementSize();
 
 					UINT32 indexOffset = 0;
 					UINT32 vertexOffset = 0;
 					for(auto& matElement : group->elements)
 					{
-						matElement.element->_fillBuffer(vertices, uvs, indices, vertexOffset, indexOffset, group->numVertices,
-							group->numIndices, vertexStride, indexStride, matElement.renderElement);
+						matElement.element->_fillBuffer(vertices, indices, vertexOffset, indexOffset, group->numVertices,
+							group->numIndices, matElement.renderElement);
 
 						UINT32 numVertices;
 						UINT32 numIndices;
-						matElement.element->_getMeshSize(matElement.renderElement, numVertices, numIndices);
+						GUIMeshType meshType;
+						matElement.element->_getMeshInfo(matElement.renderElement, numVertices, numIndices, meshType);
 
 						UINT32 indexStart = indexOffset;
 						UINT32 indexEnd = indexStart + numIndices;
@@ -673,17 +707,26 @@ namespace BansheeEngine
 						vertexOffset += numVertices;
 					}
 
-					if(groupIdx < (UINT32)renderData.cachedMeshes.size())
+					if (group->meshType == GUIMeshType::Triangle)
 					{
-						mMeshHeap->dealloc(renderData.cachedMeshes[groupIdx]);
-						renderData.cachedMeshes[groupIdx] = mMeshHeap->alloc(meshData);
+						GUIMeshData& guiMeshData = renderData.cachedTriangleMeshes[triangleMeshIdx];
+
+						if(guiMeshData.mesh != nullptr)
+							mTriangleMeshHeap->dealloc(guiMeshData.mesh);
+
+						guiMeshData.mesh = mTriangleMeshHeap->alloc(meshData);
+						triangleMeshIdx++;
 					}
-					else
+					else // Line
 					{
-						renderData.cachedMeshes.push_back(mMeshHeap->alloc(meshData));
-					}
+						GUIMeshData& guiMeshData = renderData.cachedLineMeshes[lineMeshIdx];
 
-					groupIdx++;
+						if (guiMeshData.mesh != nullptr)
+							mLineMeshHeap->dealloc(guiMeshData.mesh);
+
+						guiMeshData.mesh = mLineMeshHeap->alloc(meshData);
+						lineMeshIdx++;
+					}
 				}
 			}
 

+ 9 - 4
Source/BansheeEngine/Source/BsGUIScrollBar.cpp

@@ -74,12 +74,13 @@ namespace BansheeEngine
 		return mImageSprite->getMaterialInfo(renderElementIdx);
 	}
 
-	void GUIScrollBar::_getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const
+	void GUIScrollBar::_getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const
 	{
 		UINT32 numQuads = mImageSprite->getNumQuads(renderElementIdx);
 
 		numVertices = numQuads * 4;
 		numIndices = numQuads * 6;
+		type = GUIMeshType::Triangle;
 	}
 
 	void GUIScrollBar::updateRenderElementsInternal()
@@ -118,11 +119,15 @@ namespace BansheeEngine
 		return 3;
 	}
 
-	void GUIScrollBar::_fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
-		UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
+	void GUIScrollBar::_fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
+		UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const
 	{
+		UINT8* uvs = vertices + sizeof(Vector2);
+		UINT32 vertexStride = sizeof(Vector2) * 2;
+		UINT32 indexStride = sizeof(UINT32);
+
 		Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
-		mImageSprite->fillBuffer(vertices, uv, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
+		mImageSprite->fillBuffer(vertices, uvs, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
 			vertexStride, indexStride, renderElementIdx, offset, mLayoutData.getLocalClipRect());
 	}
 

+ 9 - 4
Source/BansheeEngine/Source/BsGUISliderHandle.cpp

@@ -80,11 +80,12 @@ namespace BansheeEngine
 		return mImageSprite->getMaterialInfo(renderElementIdx);
 	}
 
-	void GUISliderHandle::_getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const
+	void GUISliderHandle::_getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const
 	{
 		UINT32 numQuads = mImageSprite->getNumQuads(renderElementIdx);
 		numVertices = numQuads * 4;
 		numIndices = numQuads * 6;
+		type = GUIMeshType::Triangle;
 	}
 
 	void GUISliderHandle::updateRenderElementsInternal()
@@ -138,9 +139,13 @@ namespace BansheeEngine
 		return Vector2I();
 	}
 
-	void GUISliderHandle::_fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
-		UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
+	void GUISliderHandle::_fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
+		UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const
 	{
+		UINT8* uvs = vertices + sizeof(Vector2);
+		UINT32 vertexStride = sizeof(Vector2) * 2;
+		UINT32 indexStride = sizeof(UINT32);
+
 		Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
 		if(mHorizontal)
 			offset.x += getHandlePosPx();
@@ -153,7 +158,7 @@ namespace BansheeEngine
 		else
 			clipRect.y -= getHandlePosPx();
 
-		mImageSprite->fillBuffer(vertices, uv, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
+		mImageSprite->fillBuffer(vertices, uvs, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
 			vertexStride, indexStride, renderElementIdx, offset, clipRect);
 	}
 

+ 9 - 4
Source/BansheeEngine/Source/BsGUITexture.cpp

@@ -127,11 +127,12 @@ namespace BansheeEngine
 		return mImageSprite->getMaterialInfo(renderElementIdx);
 	}
 
-	void GUITexture::_getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const
+	void GUITexture::_getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const
 	{
 		UINT32 numQuads = mImageSprite->getNumQuads(renderElementIdx);
 		numVertices = numQuads * 4;
 		numIndices = numQuads * 6;
+		type = GUIMeshType::Triangle;
 	}
 
 	void GUITexture::updateRenderElementsInternal()
@@ -196,11 +197,15 @@ namespace BansheeEngine
 		return optimalSize;
 	}
 
-	void GUITexture::_fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
-		UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
+	void GUITexture::_fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
+		UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const
 	{
+		UINT8* uvs = vertices + sizeof(Vector2);
+		UINT32 vertexStride = sizeof(Vector2) * 2;
+		UINT32 indexStride = sizeof(UINT32);
+
 		Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
-		mImageSprite->fillBuffer(vertices, uv, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
+		mImageSprite->fillBuffer(vertices, uvs, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
 			vertexStride, indexStride, renderElementIdx, offset, mLayoutData.getLocalClipRect());
 	}
 }

+ 4 - 3
Source/BansheeEngine/Source/BsGUIViewport.cpp

@@ -53,10 +53,11 @@ namespace BansheeEngine
 		return dummy;
 	}
 
-	void GUIViewport::_getMeshSize(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices) const
+	void GUIViewport::_getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const
 	{
 		numVertices = 0;
 		numIndices = 0;
+		type = GUIMeshType::Triangle;
 	}
 
 	void GUIViewport::updateClippedBounds()
@@ -70,8 +71,8 @@ namespace BansheeEngine
 		return Vector2I(0, 0);
 	}
 
-	void GUIViewport::_fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
-		UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
+	void GUIViewport::_fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
+		UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const
 	{
 
 	}

+ 14 - 1
Source/BansheeGLRenderAPI/Source/BsGLHardwareBufferManager.cpp

@@ -73,9 +73,22 @@ namespace BansheeEngine
                 return GL_FLOAT;
             case VET_SHORT1:
             case VET_SHORT2:
-            case VET_SHORT3:
             case VET_SHORT4:
                 return GL_SHORT;
+			case VET_USHORT1:
+			case VET_USHORT2:
+			case VET_USHORT4:
+				return GL_UNSIGNED_SHORT;
+			case VET_INT1:
+			case VET_INT2:
+			case VET_INT3:
+			case VET_INT4:
+				return GL_INT;
+			case VET_UINT1:
+			case VET_UINT2:
+			case VET_UINT3:
+			case VET_UINT4:
+				return GL_UNSIGNED_INT;
             case VET_COLOR:
 			case VET_COLOR_ABGR:
 			case VET_COLOR_ARGB: