Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
UIBatch.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 
4 using System;
5 using System.Collections.Generic;
6 using System.Runtime.InteropServices;
7 
8 using SiliconStudio.Core.Mathematics;
9 
10 namespace SiliconStudio.Paradox.Graphics
11 {
12  /// <summary>
13  /// A utility class to batch and draw UI images.
14  /// </summary>
15  public class UIBatch : BatchBase<UIBatch.UIImageDrawInfo>
16  {
17  private static readonly List<short[]> PrimiteTypeToIndices = new List<short[]>(4);
18 
19  private readonly Effect uiSeparateAlphaEffect;
20 
21  private bool separateAlphaEffectBinded;
22 
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;
28 
29  /// <summary>
30  /// The view projection matrix that will be used for the current begin/end draw calls.
31  /// </summary>
32  private Matrix viewProjectionMatrix;
33 
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;
38 
39  private readonly Vector4[] shiftVectorX = new Vector4[4];
40  private readonly Vector4[] shiftVectorY = new Vector4[4];
41 
42  private readonly Texture2D whiteTexture;
43 
44  static UIBatch()
45  {
46  PrimiteTypeToIndices.Add(new short[6]); // rectangle
47  PrimiteTypeToIndices.Add(new short[54]); // border rectangle
48  PrimiteTypeToIndices.Add(new short[36]); // cube
49  PrimiteTypeToIndices.Add(new short[36]); // reverse cube
50 
51  // rectangle
52  var indices = PrimiteTypeToIndices[(int)PrimitiveType.Rectangle];
53  indices[0] = 0;
54  indices[1] = 1;
55  indices[2] = 2;
56  indices[3] = 1;
57  indices[4] = 3;
58  indices[5] = 2;
59 
60  // border rectangle
61  indices = PrimiteTypeToIndices[(int)PrimitiveType.BorderRectangle];
62  var count = 0;
63  for (var j = 0; j < 3; ++j)
64  {
65  for (var l = 0; l < 3; ++l)
66  {
67  indices[count++] = (short)((j << 2) + l + 0);
68  indices[count++] = (short)((j << 2) + l + 1);
69  indices[count++] = (short)((j << 2) + l + 4);
70 
71  indices[count++] = (short)((j << 2) + l + 1);
72  indices[count++] = (short)((j << 2) + l + 5);
73  indices[count++] = (short)((j << 2) + l + 4);
74  }
75  }
76 
77  // cube
78  count = 0;
79  indices = PrimiteTypeToIndices[(int)PrimitiveType.Cube];
80  indices[count++] = 0; //back
81  indices[count++] = 2;
82  indices[count++] = 1;
83  indices[count++] = 1;
84  indices[count++] = 2;
85  indices[count++] = 3;
86 
87  indices[count++] = 5; // right
88  indices[count++] = 1;
89  indices[count++] = 7;
90  indices[count++] = 1;
91  indices[count++] = 3;
92  indices[count++] = 7;
93 
94  indices[count++] = 4; // front
95  indices[count++] = 5;
96  indices[count++] = 6;
97  indices[count++] = 5;
98  indices[count++] = 7;
99  indices[count++] = 6;
100 
101  indices[count++] = 0; // left
102  indices[count++] = 4;
103  indices[count++] = 2;
104  indices[count++] = 4;
105  indices[count++] = 6;
106  indices[count++] = 2;
107 
108  indices[count++] = 0; // top
109  indices[count++] = 1;
110  indices[count++] = 4;
111  indices[count++] = 1;
112  indices[count++] = 5;
113  indices[count++] = 4;
114 
115  indices[count++] = 2; // bottom
116  indices[count++] = 6;
117  indices[count++] = 3;
118  indices[count++] = 3;
119  indices[count++] = 6;
120  indices[count ] = 7;
121 
122  // reverse cube
123  var cubeIndices = PrimiteTypeToIndices[(int)PrimitiveType.Cube];
124  indices = PrimiteTypeToIndices[(int)PrimitiveType.ReverseCube];
125  for( var i=0; i<cubeIndices.Length; i += 3)
126  {
127  indices[i+0] = cubeIndices[i+0];
128  indices[i+1] = cubeIndices[i+2];
129  indices[i+2] = cubeIndices[i+1];
130  }
131  }
132 
133  /// <summary>
134  /// Creates a new instance of <see cref="UIBatch"/>.
135  /// </summary>
136  /// <param name="device">A valid instance of <see cref="GraphicsDevice"/>.</param>
137  public UIBatch(GraphicsDevice device)
138  : base(device, UIEffect.Bytecode,
139  ResourceBufferInfo.CreateDynamicIndexBufferInfo("UIBatch.VertexIndexBuffers", MaxIndicesCount, MaxVerticesCount),
141  {
142  // Create the two ui effects
143  uiSeparateAlphaEffect = new Effect(GraphicsDevice, UIEffectSeparateAlpha.Bytecode) {Name = "SeparatedAlphaBatchEffect"};
144 
145  // Create a 1x1 pixel white texture
146  whiteTexture = Texture2D.New(GraphicsDevice, 1, 1, PixelFormat.R8G8B8A8_UNorm, new Byte[] { 255, 255, 255, 255 });
147  }
148 
149  /// <summary>
150  /// Begins a image batch rendering using the specified blend state, depth stencil and a view-projection transformation matrix.
151  /// Passing null for any of the state objects selects the default default state objects (BlendState.AlphaBlend, DepthStencilState.None).
152  /// </summary>
153  /// <param name="blendState">Blending options.</param>
154  /// <param name="depthStencilState">Depth and stencil options.</param>
155  /// <param name="viewProjection">The view projection matrix used for this series of draw calls</param>
156  /// <param name="stencilValue">The value of the stencil buffer to take as reference</param>
157  public void Begin(ref Matrix viewProjection, BlendState blendState, DepthStencilState depthStencilState, int stencilValue)
158  {
159  Begin(ref viewProjection, blendState, null, null, depthStencilState, stencilValue);
160  }
161 
162  /// <summary>
163  /// Begins a image batch rendering using the specified blend state, sampler, depth stencil, rasterizer state objects, and the view-projection transformation matrix.
164  /// Passing null for any of the state objects selects the default default state objects (BlendState.AlphaBlend, DepthStencilState.None, RasterizerState.CullCounterClockwise, SamplerState.LinearClamp).
165  /// </summary>
166  /// <param name="blendState">Blending options.</param>
167  /// <param name="samplerState">Texture sampling options.</param>
168  /// <param name="depthStencilState">Depth and stencil options.</param>
169  /// <param name="rasterizerState">Rasterization options.</param>
170  /// <param name="viewProjection">The view projection matrix used for this series of draw calls</param>
171  /// <param name="stencilValue">The value of the stencil buffer to take as reference</param>
172  public void Begin(ref Matrix viewProjection, BlendState blendState, SamplerState samplerState, RasterizerState rasterizerState, DepthStencilState depthStencilState, int stencilValue)
173  {
174  separateAlphaEffectBinded = false;
175  viewProjectionMatrix = viewProjection;
176 
177  Begin(null, SpriteSortMode.BackToFront, blendState, samplerState, depthStencilState, rasterizerState, stencilValue);
178  }
179 
180  /// <summary>
181  /// Draw a rectangle of the provided size at the position specified by the world matrix having the provided color.
182  /// </summary>
183  /// <param name="worldMatrix">The world matrix specifying the position of the rectangle in the world</param>
184  /// <param name="elementSize">The size of the rectangle</param>
185  /// <param name="color">The color of the rectangle</param>
186  /// <param name="depthBias">The depth bias to use when drawing the element</param>
187  public void DrawRectangle(ref Matrix worldMatrix, ref Vector3 elementSize, ref Color color, int depthBias)
188  {
189  // Skip items with null size
190  if (elementSize.Length() < MathUtil.ZeroTolerance)
191  return;
192 
193  // Calculate the information needed to draw.
194  var drawInfo = new UIImageDrawInfo
195  {
196  DepthBias = depthBias,
197  Color = color,
198  Primitive = PrimitiveType.Rectangle
199  };
200 
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;
211 
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);
217 
218  var elementInfo = new ElementInfo(4, 6, ref drawInfo, depthBias);
219 
220  Draw(whiteTexture, whiteTexture, ref elementInfo);
221  }
222 
223  /// <summary>
224  /// Draw a cube of the provided size at the position specified by the world matrix having the provided color.
225  /// </summary>
226  /// <param name="worldMatrix">The world matrix specifying the position of the cube in the world</param>
227  /// <param name="elementSize">The size of the cube</param>
228  /// <param name="color">The color of the cube</param>
229  /// <param name="depthBias">The depth bias to use when drawing the element</param>
230  public void DrawCube(ref Matrix worldMatrix, ref Vector3 elementSize, ref Color color, int depthBias)
231  {
232  DrawCube(ref worldMatrix, ref elementSize, ref color, depthBias, false);
233  }
234 
235  /// <summary>
236  /// Draw a colored background having provided size at the position specified by the world matrix.
237  /// </summary>
238  /// <param name="worldMatrix">The world matrix specifying the position of the element in the world</param>
239  /// <param name="elementSize">The size of the element</param>
240  /// <param name="color">The color of the element</param>
241  /// <param name="depthBias">The depth bias to use when drawing the element</param>
242  public void DrawBackground(ref Matrix worldMatrix, ref Vector3 elementSize, ref Color color, int depthBias)
243  {
244  DrawCube(ref worldMatrix, ref elementSize, ref color, depthBias, true);
245  }
246 
247  private void DrawCube(ref Matrix worldMatrix, ref Vector3 elementSize, ref Color color, int depthBias, bool isReverse)
248  {
249  // Skip items with null size
250  if (elementSize.Length() < MathUtil.ZeroTolerance)
251  return;
252 
253  // Calculate the information needed to draw.
254  var drawInfo = new UIImageDrawInfo
255  {
256  DepthBias = depthBias,
257  Color = color,
258  Primitive = isReverse? PrimitiveType.ReverseCube: PrimitiveType.Cube
259  };
260 
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;
271 
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);
278 
279  var elementInfo = new ElementInfo(8, 6 * 6, ref drawInfo, depthBias);
280 
281  Draw(whiteTexture, whiteTexture, ref elementInfo);
282  }
283 
284  /// <summary>
285  /// Batch a new border image draw to the draw list.
286  /// </summary>
287  /// <param name="texture">The texture to use during the draw</param>
288  /// <param name="texture1">An optional texture that can be used to substitute <paramref name="texture"/>'s alpha</param>
289  /// <param name="worldMatrix">The world matrix of the element</param>
290  /// <param name="sourceRectangle">The rectangle indicating the source region of the texture to use</param>
291  /// <param name="elementSize">The size of the ui element</param>
292  /// <param name="borderSize">The size of the borders in the texture in pixels (left/right/top/bottom)</param>
293  /// <param name="color">The color to apply to the texture image.</param>
294  /// <param name="depthBias">The depth bias of the ui element</param>
295  /// <param name="imageOrientation">The rotation to apply on the image uv</param>
296  /// <param name="swizzle">Swizzle mode indicating the swizzle use when sampling the texture in the shader</param>
297  /// <param name="snapImage">Indicate if the image needs to be snapped or not</param>
298  public void DrawImage(Texture2D texture, Texture2D texture1, ref Matrix worldMatrix, ref RectangleF sourceRectangle, ref Vector3 elementSize, ref Vector4 borderSize,
299  ref Color color, int depthBias, ImageOrientation imageOrientation = ImageOrientation.AsIs, SwizzleMode swizzle = SwizzleMode.None, bool snapImage = false)
300  {
301  // Check that texture is not null
302  if (texture == null)
303  throw new ArgumentNullException("texture");
304 
305  // Skip items with null size
306  if (elementSize.Length() < MathUtil.ZeroTolerance)
307  return;
308 
309  // End the current batching session and change the effect if required
310  if (texture1 == null && separateAlphaEffectBinded || texture1 != null && !separateAlphaEffectBinded)
311  {
312  End();
313  separateAlphaEffectBinded = !separateAlphaEffectBinded;
314  Begin(separateAlphaEffectBinded? uiSeparateAlphaEffect: null, SortMode, BlendState, SamplerState, DepthStencilState, RasterizerState, StencilReferenceValue);
315  }
316 
317  // Calculate the information needed to draw.
318  var drawInfo = new UIImageDrawInfo
319  {
320  Source =
321  {
322  X = sourceRectangle.X / texture.Width,
323  Y = sourceRectangle.Y / texture.Height,
324  Width = sourceRectangle.Width / texture.Width,
325  Height = sourceRectangle.Height / texture.Height
326  },
327  DepthBias = depthBias,
328  Color = color,
329  Swizzle = swizzle,
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),
333  };
334 
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);
337 
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;
348 
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);
353 
354  // rotate origin and unit axis if need.
355  var leftTopCorner = vector4LeftTop;
356  if (imageOrientation == ImageOrientation.Rotated90)
357  {
358  var unitX = drawInfo.UnitXWorld;
359  drawInfo.UnitXWorld = -drawInfo.UnitYWorld;
360  drawInfo.UnitYWorld = unitX;
361  leftTopCorner = new Vector4(-0.5f, 0.5f, 0, 1);
362  }
363  Vector4.Transform(ref leftTopCorner, ref worldViewProjection, out drawInfo.LeftTopCornerWorld);
364 
365  var verticesPerElement = 4;
366  var indicesPerElement = 6;
367  if (drawInfo.Primitive == PrimitiveType.BorderRectangle)
368  {
369  verticesPerElement = 16;
370  indicesPerElement = 54;
371  }
372 
373  var elementInfo = new ElementInfo(verticesPerElement, indicesPerElement, ref drawInfo, depthBias);
374 
375  Draw(texture, texture1, ref elementInfo);
376  }
377 
378  /// <summary>
379  /// Batch the draws required to display the provided text to the draw list.
380  /// </summary>
381  /// <param name="fontSize">The size to use when rendering the font</param>
382  /// <param name="fontInternalScale">The size of the font glyphs to use in pixels</param>
383  /// <param name="text">The text to draw on the screen</param>
384  /// <param name="worldMatrix">The world matrix of the element</param>
385  /// <param name="elementSize">The 2D size of the element to draw in virtual pixels</param>
386  /// <param name="color">The color of the text to draw</param>
387  /// <param name="alignment">The alignment of the text to draw</param>
388  /// <param name="depthBias">The depth bias of the ui element</param>
389  /// <param name="font">The fond to use to draw the text</param>
390  /// <param name="snapText">Indicate if the rendered string should be snapped to the closed pixel.</param>
391  public void DrawString(SpriteFont font, string text, float fontSize, ref Vector2 fontInternalScale, ref Matrix worldMatrix, ref Vector2 elementSize,
392  ref Color color, TextAlignment alignment, int depthBias, bool snapText)
393  {
394  var drawCommand = new SpriteFont.InternalUIDrawCommand
395  {
396  WorldMatrix = worldMatrix,
397  Batch = this,
398  Color = color,
399  DepthBias = depthBias,
400  FontScale = fontInternalScale,
401  SnapText = snapText,
402  Alignment = alignment,
403  Size = elementSize,
404  };
405 
406  DrawString(font, text, ref drawCommand);
407  }
408 
409  internal void DrawString(SpriteFont font, string text, ref SpriteFont.InternalUIDrawCommand drawCommand)
410  {
411  if (font == null)
412  throw new ArgumentNullException("font");
413 
414  if (text == null)
415  throw new ArgumentNullException("text");
416 
417  var proxy = new SpriteFont.StringProxy(text);
418 
419  // shift the string position so that it is written from the left/top corner of the element
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;
424 
425  font.InternalUIDraw(ref proxy, ref drawCommand);
426  }
427 
428  protected override unsafe void UpdateBufferValuesFromElementInfo(ref ElementInfo elementInfo, IntPtr vertexPtr, IntPtr indexPtr, int vertexOffset)
429  {
430  // the vertex buffer
431  var vertex = (VertexPositionColorTextureSwizzle*)vertexPtr;
432  fixed (UIImageDrawInfo* drawInfo = &elementInfo.DrawInfo)
433  {
434  switch (drawInfo->Primitive)
435  {
436  case PrimitiveType.Rectangle:
437  CalculateRectangleVertices(drawInfo, vertex);
438  break;
439  case PrimitiveType.BorderRectangle:
440  CalculateBorderRectangleVertices(drawInfo, vertex);
441  break;
442  case PrimitiveType.Cube:
443  case PrimitiveType.ReverseCube:
444  CalculateCubeVertices(drawInfo, vertex);
445  break;
446  default:
447  throw new ArgumentOutOfRangeException();
448  }
449 
450  // the index buffer
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);
455  }
456  }
457 
458  private unsafe void CalculateCubeVertices(UIImageDrawInfo* drawInfo, VertexPositionColorTextureSwizzle* vertex)
459  {
460  var currentPosition = drawInfo->LeftTopCornerWorld;
461 
462  // set the two first line of vertices
463  for (var l = 0; l < 2; ++l)
464  {
465  for (int r = 0; r < 2; r++)
466  {
467  for (int c = 0; c < 2; c++)
468  {
469  vertex->Color = drawInfo->Color;
470  vertex->Swizzle = (int)drawInfo->Swizzle;
471  vertex->TextureCoordinate.X = 0; // cubes are used only for color
472  vertex->TextureCoordinate.Y = 0; // cubes are used only for color
473 
474  vertex->Position.X = currentPosition.X;
475  vertex->Position.Y = currentPosition.Y;
476  vertex->Position.Z = currentPosition.Z - currentPosition.W * drawInfo->DepthBias * DepthBiasShiftOneUnit;
477  vertex->Position.W = currentPosition.W;
478 
479  vertex++;
480 
481  if (c == 0)
482  Vector4.Add(ref currentPosition, ref drawInfo->UnitXWorld, out currentPosition);
483  else
484  Vector4.Subtract(ref currentPosition, ref drawInfo->UnitXWorld, out currentPosition);
485  }
486 
487  if (r == 0)
488  Vector4.Add(ref currentPosition, ref drawInfo->UnitYWorld, out currentPosition);
489  else
490  Vector4.Subtract(ref currentPosition, ref drawInfo->UnitYWorld, out currentPosition);
491  }
492 
493  Vector4.Add(ref currentPosition, ref drawInfo->UnitZWorld, out currentPosition);
494  }
495  }
496 
497  private unsafe void CalculateBorderRectangleVertices(UIImageDrawInfo* drawInfo, VertexPositionColorTextureSwizzle* vertex)
498  {
499  // set the texture uv vectors
500  var uvX = new Vector4();
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;
505  var uvY = new Vector4();
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;
510 
511  // set the shift vectors
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;
516 
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;
521 
522  for (int r = 0; r < 4; r++)
523  {
524  Vector4 currentRowPosition;
525  Vector4.Add(ref drawInfo->LeftTopCornerWorld, ref shiftVectorY[r], out currentRowPosition);
526 
527  for (int c = 0; c < 4; c++)
528  {
529  Vector4 currentPosition;
530  Vector4.Add(ref currentRowPosition, ref shiftVectorX[c], out currentPosition);
531 
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;
536 
537  vertex->Color = drawInfo->Color;
538 
539  vertex->TextureCoordinate.X = uvX[c];
540  vertex->TextureCoordinate.Y = uvY[r];
541 
542  vertex->Swizzle = (int)drawInfo->Swizzle;
543 
544  vertex++;
545  }
546  }
547  }
548 
549  private unsafe void CalculateRectangleVertices(UIImageDrawInfo* drawInfo, VertexPositionColorTextureSwizzle* vertex)
550  {
551  var backBufferHalfWidth = GraphicsDevice.BackBuffer.Width / 2;
552  var backBufferHalfHeight = GraphicsDevice.BackBuffer.Height / 2;
553 
554  var currentPosition = drawInfo->LeftTopCornerWorld;
555 
556  // snap first pixel to prevent possible problems when left/top is in the middle of a pixel
557  if (drawInfo->SnapImage)
558  {
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;
566  }
567 
568  var textureCoordX = new Vector2(drawInfo->Source.Left, drawInfo->Source.Right);
569  var textureCoordY = new Vector2(drawInfo->Source.Top, drawInfo->Source.Bottom);
570 
571  // set the two first line of vertices
572  for (int r = 0; r < 2; r++)
573  {
574  for (int c = 0; c < 2; c++)
575  {
576  vertex->Color = drawInfo->Color;
577  vertex->Swizzle = (int)drawInfo->Swizzle;
578  vertex->TextureCoordinate.X = textureCoordX[c];
579  vertex->TextureCoordinate.Y = textureCoordY[r];
580 
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;
585 
586  if (drawInfo->SnapImage)
587  {
588  vertex->Position.X = (float)(Math.Round(vertex->Position.X * backBufferHalfWidth) / backBufferHalfWidth);
589  vertex->Position.Y = (float)(Math.Round(vertex->Position.Y * backBufferHalfHeight) / backBufferHalfHeight);
590  }
591 
592  vertex++;
593 
594  if (c == 0)
595  Vector4.Add(ref currentPosition, ref drawInfo->UnitXWorld, out currentPosition);
596  else
597  Vector4.Subtract(ref currentPosition, ref drawInfo->UnitXWorld, out currentPosition);
598  }
599 
600  Vector4.Add(ref currentPosition, ref drawInfo->UnitYWorld, out currentPosition);
601  }
602  }
603 
604  /// <summary>
605  /// The primitive type to draw for an element.
606  /// </summary>
607  public enum PrimitiveType
608  {
609  /// <summary>
610  /// A simple rectangle composed of 2 triangles
611  /// </summary>
612  Rectangle,
613 
614  /// <summary>
615  /// A rectangle with borders tessellated as 3x3 rectangles
616  /// </summary>
617  BorderRectangle,
618 
619  /// <summary>
620  /// A simple cube (not necessary square faces)
621  /// </summary>
622  Cube,
623 
624  /// <summary>
625  /// A cube with back and front faces inversed.
626  /// </summary>
627  ReverseCube,
628  }
629 
630  [StructLayout(LayoutKind.Sequential)]
631  public struct UIImageDrawInfo
632  {
640  public Color Color;
641  public int DepthBias;
643  public bool SnapImage;
645 
646  public float CalculateDepthOrigin()
647  {
648  return LeftTopCornerWorld.Z / LeftTopCornerWorld.W - DepthBias * DepthBiasShiftOneUnit;
649  }
650  }
651  }
652 }
SiliconStudio.Paradox.Games.Mathematics.Vector2 Vector2
float W
The W component of the vector.
Definition: Vector4.cs:101
Represents a two dimensional mathematical vector.
Definition: Vector2.cs:42
Color(byte value)
Initializes a new instance of the Color struct.
Definition: Color.cs:48
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...
Definition: UIBatch.cs:187
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. ...
Definition: UIBatch.cs:428
TextAlignment
Specify the available text alignment when rendering text.
Definition: TextAlignment.cs:8
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.
Definition: UIBatch.cs:298
float X
The X component of the vector.
Definition: Vector4.cs:83
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.
Definition: UIBatch.cs:391
A utility class to batch and draw UI images.
Definition: UIBatch.cs:15
Represents a three dimensional mathematical vector.
Definition: Vector3.cs:42
PrimitiveType
The primitive type to draw for an element.
Definition: UIBatch.cs:607
UIBatch(GraphicsDevice device)
Creates a new instance of UIBatch.
Definition: UIBatch.cs:137
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.
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...
Definition: UIBatch.cs:242
Define a RectangleF. This structure is slightly different from System.Drawing.RectangleF as it is int...
Definition: RectangleF.cs:36
_In_ size_t count
Definition: DirectXTexP.h:174
SpriteSortMode
Defines sprite sort-rendering options.
SpriteFont to use with SpriteBatch. See SpriteFont to learn how to use it.
Definition: SpriteFont.cs:26
Represents a four dimensional mathematical vector.
Definition: Vector4.cs:42
float Y
The Y component of the vector.
Definition: Vector2.cs:79
Represents a 32-bit color (4 bytes) in the form of RGBA (in byte order: R, G, B, A).
Definition: Color.cs:16
A Texture 2D frontend to SharpDX.Direct3D11.Texture2D.
Definition: Texture2D.cs:37
float Y
The Y component of the vector.
Definition: Vector4.cs:89
System.Windows.Shapes.Rectangle Rectangle
Definition: ColorPicker.cs:16
SwizzleMode
Specify how to swizzle a vector.
Definition: SwizzleMode.cs:8
float X
The X component of the vector.
Definition: Vector2.cs:73
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...
Definition: UIBatch.cs:157
SiliconStudio.Core.Mathematics.Vector3 Vector3
float Z
The Z component of the vector.
Definition: Vector4.cs:95
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...
Definition: UIBatch.cs:230
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).
Definition: UIBatch.cs:172
ImageOrientation
Defines the possible rotations to apply on image regions.
Represents a 4x4 mathematical matrix.
Definition: Matrix.cs:47