5 using System.Collections.Generic;
6 using System.Runtime.InteropServices;
8 using SiliconStudio.Core.Mathematics;
10 namespace SiliconStudio.
Paradox.Graphics
15 public class UIBatch : BatchBase<UIBatch.UIImageDrawInfo>
17 private static readonly List<short[]> PrimiteTypeToIndices =
new List<short[]>(4);
19 private readonly
Effect uiSeparateAlphaEffect;
21 private bool separateAlphaEffectBinded;
23 private const int MaxVerticesPerElement = 16;
24 private const int MaxIndicesPerElement = 54;
25 private const int MaxElementBatchNumber = 2048;
26 private const int MaxVerticesCount = MaxVerticesPerElement * MaxElementBatchNumber;
27 private const int MaxIndicesCount = MaxIndicesPerElement * MaxElementBatchNumber;
32 private Matrix viewProjectionMatrix;
34 private Vector4 vector4LeftTop =
new Vector4(-0.5f, -0.5f, -0.5f, 1);
35 private Vector4 vector4UnitX = Vector4.UnitX;
36 private Vector4 vector4UnitY = Vector4.UnitY;
37 private Vector4 vector4UnitZ = Vector4.UnitZ;
46 PrimiteTypeToIndices.Add(
new short[6]);
47 PrimiteTypeToIndices.Add(
new short[54]);
48 PrimiteTypeToIndices.Add(
new short[36]);
49 PrimiteTypeToIndices.Add(
new short[36]);
52 var indices = PrimiteTypeToIndices[(int)
PrimitiveType.Rectangle];
61 indices = PrimiteTypeToIndices[(
int)PrimitiveType.BorderRectangle];
63 for (var j = 0; j < 3; ++j)
65 for (var l = 0; l < 3; ++l)
67 indices[count++] = (short)((j << 2) + l + 0);
68 indices[count++] = (short)((j << 2) + l + 1);
69 indices[count++] = (short)((j << 2) + l + 4);
71 indices[count++] = (short)((j << 2) + l + 1);
72 indices[count++] = (short)((j << 2) + l + 5);
73 indices[count++] = (short)((j << 2) + l + 4);
101 indices[count++] = 0;
102 indices[count++] = 4;
103 indices[count++] = 2;
104 indices[count++] = 4;
105 indices[count++] = 6;
106 indices[count++] = 2;
108 indices[count++] = 0;
109 indices[count++] = 1;
110 indices[count++] = 4;
111 indices[count++] = 1;
112 indices[count++] = 5;
113 indices[count++] = 4;
115 indices[count++] = 2;
116 indices[count++] = 6;
117 indices[count++] = 3;
118 indices[count++] = 3;
119 indices[count++] = 6;
123 var cubeIndices = PrimiteTypeToIndices[(
int)PrimitiveType.Cube];
124 indices = PrimiteTypeToIndices[(int)
PrimitiveType.ReverseCube];
125 for( var i=0; i<cubeIndices.Length; i += 3)
127 indices[i+0] = cubeIndices[i+0];
128 indices[i+1] = cubeIndices[i+2];
129 indices[i+2] = cubeIndices[i+1];
138 : base(device, UIEffect.Bytecode,
139 ResourceBufferInfo.CreateDynamicIndexBufferInfo(
"UIBatch.VertexIndexBuffers", MaxIndicesCount, MaxVerticesCount),
143 uiSeparateAlphaEffect =
new Effect(
GraphicsDevice, UIEffectSeparateAlpha.Bytecode) {Name =
"SeparatedAlphaBatchEffect"};
146 whiteTexture = Texture2D.New(
GraphicsDevice, 1, 1, PixelFormat.R8G8B8A8_UNorm,
new Byte[] { 255, 255, 255, 255 });
159 Begin(ref viewProjection, blendState, null, null, depthStencilState, stencilValue);
174 separateAlphaEffectBinded =
false;
175 viewProjectionMatrix = viewProjection;
177 Begin(null,
SpriteSortMode.BackToFront, blendState, samplerState, depthStencilState, rasterizerState, stencilValue);
190 if (elementSize.Length() < MathUtil.ZeroTolerance)
196 DepthBias = depthBias,
198 Primitive = PrimitiveType.Rectangle
201 var matrix = worldMatrix;
202 matrix.M11 *= elementSize.X;
203 matrix.M12 *= elementSize.X;
204 matrix.M13 *= elementSize.X;
205 matrix.M21 *= elementSize.Y;
206 matrix.M22 *= elementSize.Y;
207 matrix.M23 *= elementSize.Y;
208 matrix.M31 *= elementSize.Z;
209 matrix.M32 *= elementSize.Z;
210 matrix.M33 *= elementSize.Z;
212 Matrix worldViewProjection;
213 Matrix.Multiply(ref matrix, ref viewProjectionMatrix, out worldViewProjection);
214 Vector4.Transform(ref vector4UnitX, ref worldViewProjection, out drawInfo.UnitXWorld);
215 Vector4.Transform(ref vector4UnitY, ref worldViewProjection, out drawInfo.UnitYWorld);
216 Vector4.Transform(ref vector4LeftTop, ref worldViewProjection, out drawInfo.LeftTopCornerWorld);
218 var elementInfo =
new ElementInfo(4, 6, ref drawInfo, depthBias);
220 Draw(whiteTexture, whiteTexture, ref elementInfo);
232 DrawCube(ref worldMatrix, ref elementSize, ref color, depthBias,
false);
244 DrawCube(ref worldMatrix, ref elementSize, ref color, depthBias,
true);
247 private void DrawCube(ref
Matrix worldMatrix, ref
Vector3 elementSize, ref
Color color,
int depthBias,
bool isReverse)
250 if (elementSize.Length() < MathUtil.ZeroTolerance)
254 var drawInfo =
new UIImageDrawInfo
256 DepthBias = depthBias,
258 Primitive = isReverse? PrimitiveType.ReverseCube: PrimitiveType.Cube
261 var matrix = worldMatrix;
262 matrix.M11 *= elementSize.X;
263 matrix.M12 *= elementSize.X;
264 matrix.M13 *= elementSize.X;
265 matrix.M21 *= elementSize.Y;
266 matrix.M22 *= elementSize.Y;
267 matrix.M23 *= elementSize.Y;
268 matrix.M31 *= elementSize.Z;
269 matrix.M32 *= elementSize.Z;
270 matrix.M33 *= elementSize.Z;
272 Matrix worldViewProjection;
273 Matrix.Multiply(ref matrix, ref viewProjectionMatrix, out worldViewProjection);
274 Vector4.Transform(ref vector4UnitX, ref worldViewProjection, out drawInfo.UnitXWorld);
275 Vector4.Transform(ref vector4UnitY, ref worldViewProjection, out drawInfo.UnitYWorld);
276 Vector4.Transform(ref vector4UnitZ, ref worldViewProjection, out drawInfo.UnitZWorld);
277 Vector4.Transform(ref vector4LeftTop, ref worldViewProjection, out drawInfo.LeftTopCornerWorld);
279 var elementInfo =
new ElementInfo(8, 6 * 6, ref drawInfo, depthBias);
281 Draw(whiteTexture, whiteTexture, ref elementInfo);
303 throw new ArgumentNullException(
"texture");
306 if (elementSize.Length() < MathUtil.ZeroTolerance)
310 if (texture1 == null && separateAlphaEffectBinded || texture1 != null && !separateAlphaEffectBinded)
313 separateAlphaEffectBinded = !separateAlphaEffectBinded;
322 X = sourceRectangle.X / texture.Width,
323 Y = sourceRectangle.Y / texture.Height,
324 Width = sourceRectangle.Width / texture.Width,
325 Height = sourceRectangle.Height / texture.Height
327 DepthBias = depthBias,
330 SnapImage = snapImage,
331 Primitive = borderSize == Vector4.Zero? PrimitiveType.Rectangle : PrimitiveType.BorderRectangle,
332 BorderSize =
new Vector4(borderSize.X / sourceRectangle.Width, borderSize.Y / sourceRectangle.Width, borderSize.Z / sourceRectangle.Height, borderSize.W / sourceRectangle.Height),
335 var rotatedSize = imageOrientation == ImageOrientation.AsIs? elementSize:
new Vector3(elementSize.Y, elementSize.X, 0);
336 drawInfo.VertexShift =
new Vector4(borderSize.X / rotatedSize.X, 1f - borderSize.Y / rotatedSize.X, borderSize.Z / rotatedSize.Y, 1f - borderSize.W / rotatedSize.Y);
338 var matrix = worldMatrix;
339 matrix.M11 *= elementSize.X;
340 matrix.M12 *= elementSize.X;
341 matrix.M13 *= elementSize.X;
342 matrix.M21 *= elementSize.Y;
343 matrix.M22 *= elementSize.Y;
344 matrix.M23 *= elementSize.Y;
345 matrix.M31 *= elementSize.Z;
346 matrix.M32 *= elementSize.Z;
347 matrix.M33 *= elementSize.Z;
349 Matrix worldViewProjection;
350 Matrix.Multiply(ref matrix, ref viewProjectionMatrix, out worldViewProjection);
351 Vector4.Transform(ref vector4UnitX, ref worldViewProjection, out drawInfo.UnitXWorld);
352 Vector4.Transform(ref vector4UnitY, ref worldViewProjection, out drawInfo.UnitYWorld);
355 var leftTopCorner = vector4LeftTop;
358 var unitX = drawInfo.UnitXWorld;
359 drawInfo.UnitXWorld = -drawInfo.UnitYWorld;
360 drawInfo.UnitYWorld = unitX;
361 leftTopCorner =
new Vector4(-0.5f, 0.5f, 0, 1);
363 Vector4.Transform(ref leftTopCorner, ref worldViewProjection, out drawInfo.LeftTopCornerWorld);
365 var verticesPerElement = 4;
366 var indicesPerElement = 6;
369 verticesPerElement = 16;
370 indicesPerElement = 54;
373 var elementInfo =
new ElementInfo(verticesPerElement, indicesPerElement, ref drawInfo, depthBias);
375 Draw(texture, texture1, ref elementInfo);
394 var drawCommand =
new SpriteFont.InternalUIDrawCommand
396 WorldMatrix = worldMatrix,
399 DepthBias = depthBias,
400 FontScale = fontInternalScale,
402 Alignment = alignment,
406 DrawString(font, text, ref drawCommand);
409 internal void DrawString(
SpriteFont font,
string text, ref
SpriteFont.InternalUIDrawCommand drawCommand)
412 throw new ArgumentNullException(
"font");
415 throw new ArgumentNullException(
"text");
417 var proxy =
new SpriteFont.StringProxy(text);
420 var offsets = drawCommand.Size / 2;
421 drawCommand.WorldMatrix.M41 -= drawCommand.WorldMatrix.M11 * offsets.X + drawCommand.WorldMatrix.M21 * offsets.Y;
422 drawCommand.WorldMatrix.M42 -= drawCommand.WorldMatrix.M12 * offsets.X + drawCommand.WorldMatrix.M22 * offsets.Y;
423 drawCommand.WorldMatrix.M43 -= drawCommand.WorldMatrix.M13 * offsets.X + drawCommand.WorldMatrix.M23 * offsets.Y;
425 font.InternalUIDraw(ref proxy, ref drawCommand);
434 switch (drawInfo->Primitive)
436 case PrimitiveType.Rectangle:
437 CalculateRectangleVertices(drawInfo, vertex);
439 case PrimitiveType.BorderRectangle:
440 CalculateBorderRectangleVertices(drawInfo, vertex);
442 case PrimitiveType.Cube:
443 case PrimitiveType.ReverseCube:
444 CalculateCubeVertices(drawInfo, vertex);
447 throw new ArgumentOutOfRangeException();
451 var index = (
short*)indexPtr;
452 var indices = PrimiteTypeToIndices[(int)drawInfo->Primitive];
453 for (var i = 0; i < indices.Length; ++i)
454 index[i] = (
short)(indices[i] + vertexOffset);
460 var currentPosition = drawInfo->LeftTopCornerWorld;
463 for (var l = 0; l < 2; ++l)
465 for (
int r = 0; r < 2; r++)
467 for (
int c = 0; c < 2; c++)
470 vertex->
Swizzle = (int)drawInfo->Swizzle;
476 vertex->
Position.
Z = currentPosition.Z - currentPosition.W * drawInfo->DepthBias * DepthBiasShiftOneUnit;
482 Vector4.Add(ref currentPosition, ref drawInfo->UnitXWorld, out currentPosition);
484 Vector4.Subtract(ref currentPosition, ref drawInfo->UnitXWorld, out currentPosition);
488 Vector4.Add(ref currentPosition, ref drawInfo->UnitYWorld, out currentPosition);
490 Vector4.Subtract(ref currentPosition, ref drawInfo->UnitYWorld, out currentPosition);
493 Vector4.Add(ref currentPosition, ref drawInfo->UnitZWorld, out currentPosition);
497 private unsafe
void CalculateBorderRectangleVertices(UIImageDrawInfo* drawInfo, VertexPositionColorTextureSwizzle* vertex)
501 uvX[0] = drawInfo->Source.Left;
502 uvX[3] = drawInfo->Source.Right;
503 uvX[1] = uvX[0] + drawInfo->Source.Width * drawInfo->BorderSize.X;
504 uvX[2] = uvX[3] - drawInfo->Source.Width * drawInfo->BorderSize.Y;
506 uvY[0] = drawInfo->Source.Top;
507 uvY[3] = drawInfo->Source.Bottom;
508 uvY[1] = uvY[0] + drawInfo->Source.Height * drawInfo->BorderSize.Z;
509 uvY[2] = uvY[3] - drawInfo->Source.Height * drawInfo->BorderSize.W;
512 shiftVectorX[0] = Vector4.Zero;
513 Vector4.Multiply(ref drawInfo->UnitXWorld, drawInfo->VertexShift.X, out shiftVectorX[1]);
514 Vector4.Multiply(ref drawInfo->UnitXWorld, drawInfo->VertexShift.Y, out shiftVectorX[2]);
515 shiftVectorX[3] = drawInfo->UnitXWorld;
517 shiftVectorY[0] = Vector4.Zero;
518 Vector4.Multiply(ref drawInfo->UnitYWorld, drawInfo->VertexShift.Z, out shiftVectorY[1]);
519 Vector4.Multiply(ref drawInfo->UnitYWorld, drawInfo->VertexShift.W, out shiftVectorY[2]);
520 shiftVectorY[3] = drawInfo->UnitYWorld;
522 for (
int r = 0; r < 4; r++)
525 Vector4.Add(ref drawInfo->LeftTopCornerWorld, ref shiftVectorY[r], out currentRowPosition);
527 for (
int c = 0; c < 4; c++)
530 Vector4.Add(ref currentRowPosition, ref shiftVectorX[c], out currentPosition);
532 vertex->Position.X = currentPosition.X;
533 vertex->Position.Y = currentPosition.Y;
534 vertex->Position.Z = currentPosition.Z - (currentPosition.W * drawInfo->DepthBias * DepthBiasShiftOneUnit);
535 vertex->Position.W = currentPosition.W;
537 vertex->Color = drawInfo->Color;
539 vertex->TextureCoordinate.X = uvX[c];
540 vertex->TextureCoordinate.Y = uvY[r];
542 vertex->Swizzle = (int)drawInfo->Swizzle;
549 private unsafe
void CalculateRectangleVertices(UIImageDrawInfo* drawInfo, VertexPositionColorTextureSwizzle* vertex)
551 var backBufferHalfWidth = GraphicsDevice.BackBuffer.Width / 2;
552 var backBufferHalfHeight = GraphicsDevice.BackBuffer.Height / 2;
554 var currentPosition = drawInfo->LeftTopCornerWorld;
557 if (drawInfo->SnapImage)
559 var invW = 1.0f / currentPosition.W;
560 currentPosition.X *= invW;
561 currentPosition.Y *= invW;
562 currentPosition.X = (float)(Math.Round(currentPosition.X * backBufferHalfWidth) / backBufferHalfWidth);
563 currentPosition.Y = (float)(Math.Round(currentPosition.Y * backBufferHalfHeight) / backBufferHalfHeight);
564 currentPosition.X *= currentPosition.W;
565 currentPosition.Y *= currentPosition.W;
568 var textureCoordX =
new Vector2(drawInfo->Source.Left, drawInfo->Source.Right);
569 var textureCoordY =
new Vector2(drawInfo->Source.Top, drawInfo->Source.Bottom);
572 for (
int r = 0; r < 2; r++)
574 for (
int c = 0; c < 2; c++)
576 vertex->Color = drawInfo->Color;
577 vertex->Swizzle = (int)drawInfo->Swizzle;
578 vertex->TextureCoordinate.X = textureCoordX[c];
579 vertex->TextureCoordinate.Y = textureCoordY[r];
581 vertex->Position.X = currentPosition.X;
582 vertex->Position.Y = currentPosition.Y;
583 vertex->Position.Z = currentPosition.Z - currentPosition.W * drawInfo->DepthBias * DepthBiasShiftOneUnit;
584 vertex->Position.W = currentPosition.W;
586 if (drawInfo->SnapImage)
588 vertex->Position.X = (float)(Math.Round(vertex->Position.X * backBufferHalfWidth) / backBufferHalfWidth);
589 vertex->Position.Y = (float)(Math.Round(vertex->Position.Y * backBufferHalfHeight) / backBufferHalfHeight);
595 Vector4.Add(ref currentPosition, ref drawInfo->UnitXWorld, out currentPosition);
597 Vector4.Subtract(ref currentPosition, ref drawInfo->UnitXWorld, out currentPosition);
600 Vector4.Add(ref currentPosition, ref drawInfo->UnitYWorld, out currentPosition);
630 [StructLayout(LayoutKind.Sequential)]
648 return LeftTopCornerWorld.Z / LeftTopCornerWorld.W - DepthBias * DepthBiasShiftOneUnit;
SiliconStudio.Paradox.Games.Mathematics.Vector2 Vector2
float W
The W component of the vector.
Represents a two dimensional mathematical vector.
Color(byte value)
Initializes a new instance of the Color struct.
void DrawRectangle(ref Matrix worldMatrix, ref Vector3 elementSize, ref Color color, int depthBias)
Draw a rectangle of the provided size at the position specified by the world matrix having the provid...
Contains depth-stencil state for the device.
Describes a custom vertex format structure that contains position, color, texture and swizzle informa...
override unsafe void UpdateBufferValuesFromElementInfo(ref ElementInfo elementInfo, IntPtr vertexPtr, IntPtr indexPtr, int vertexOffset)
Update the mapped vertex and index buffer values using the provided element info. ...
TextAlignment
Specify the available text alignment when rendering text.
void DrawImage(Texture2D texture, Texture2D texture1, ref Matrix worldMatrix, ref RectangleF sourceRectangle, ref Vector3 elementSize, ref Vector4 borderSize, ref Color color, int depthBias, ImageOrientation imageOrientation=ImageOrientation.AsIs, SwizzleMode swizzle=SwizzleMode.None, bool snapImage=false)
Batch a new border image draw to the draw list.
float X
The X component of the vector.
void DrawString(SpriteFont font, string text, float fontSize, ref Vector2 fontInternalScale, ref Matrix worldMatrix, ref Vector2 elementSize, ref Color color, TextAlignment alignment, int depthBias, bool snapText)
Batch the draws required to display the provided text to the draw list.
A utility class to batch and draw UI images.
Represents a three dimensional mathematical vector.
PrimitiveType
The primitive type to draw for an element.
UIBatch(GraphicsDevice device)
Creates a new instance of UIBatch.
Performs primitive-based rendering, creates resources, handles system-level variables, adjusts gamma ramp levels, and creates shaders. See The+GraphicsDevice+class to learn more about the class.
Vector4 LeftTopCornerWorld
Vector4 Position
XYZ position.
void DrawBackground(ref Matrix worldMatrix, ref Vector3 elementSize, ref Color color, int depthBias)
Draw a colored background having provided size at the position specified by the world matrix...
Define a RectangleF. This structure is slightly different from System.Drawing.RectangleF as it is int...
SpriteSortMode
Defines sprite sort-rendering options.
SpriteFont to use with SpriteBatch. See SpriteFont to learn how to use it.
Represents a four dimensional mathematical vector.
Color Color
The vertex color.
float Y
The Y component of the vector.
Represents a 32-bit color (4 bytes) in the form of RGBA (in byte order: R, G, B, A).
float CalculateDepthOrigin()
A Texture 2D frontend to SharpDX.Direct3D11.Texture2D.
float Y
The Y component of the vector.
Vector2 TextureCoordinate
UV texture coordinates.
System.Windows.Shapes.Rectangle Rectangle
SwizzleMode
Specify how to swizzle a vector.
float X
The X component of the vector.
void Begin(ref Matrix viewProjection, BlendState blendState, DepthStencilState depthStencilState, int stencilValue)
Begins a image batch rendering using the specified blend state, depth stencil and a view-projection t...
SiliconStudio.Core.Mathematics.Vector3 Vector3
float Z
The Z component of the vector.
float Swizzle
The Swizzle mode
void DrawCube(ref Matrix worldMatrix, ref Vector3 elementSize, ref Color color, int depthBias)
Draw a cube of the provided size at the position specified by the world matrix having the provided co...
void Begin(ref Matrix viewProjection, BlendState blendState, SamplerState samplerState, RasterizerState rasterizerState, DepthStencilState depthStencilState, int stencilValue)
Begins a image batch rendering using the specified blend state, sampler, depth stencil, rasterizer state objects, and the view-projection transformation matrix. Passing null for any of the state objects selects the default default state objects (BlendState.AlphaBlend, DepthStencilState.None, RasterizerState.CullCounterClockwise, SamplerState.LinearClamp).
ImageOrientation
Defines the possible rotations to apply on image regions.
Represents a 4x4 mathematical matrix.