Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
SplitExtensions.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 using System;
4 using System.Collections.Generic;
5 
6 using SiliconStudio.Core;
7 using SiliconStudio.Paradox.Effects.Data;
8 using SiliconStudio.Paradox.Graphics;
9 using SiliconStudio.Paradox.Graphics.Data;
10 
11 namespace SiliconStudio.Paradox.Extensions
12 {
13  public static class SplitExtensions
14  {
15  public static List<MeshData> SplitMeshes(List<MeshData> meshes, bool can32bitIndex)
16  {
17  var finalList = new List<MeshData>();
18  foreach (var mesh in meshes)
19  {
20  var drawDatas = SplitMesh(mesh.Draw, can32bitIndex);
21  if (drawDatas.Count <= 1)
22  {
23  finalList.Add(mesh);
24  }
25  else
26  {
27  foreach (var draw in drawDatas)
28  {
29  var newMeshData = new MeshData
30  {
31  Material = mesh.Material,
32  Parameters = mesh.Parameters,
33  Name = mesh.Name,
34  Draw = draw,
35  NodeIndex = mesh.NodeIndex,
36  Skinning = mesh.Skinning,
37  };
38  finalList.Add(newMeshData);
39  }
40  }
41  }
42 
43  return finalList;
44  }
45 
46  /// <summary>
47  /// Split the mesh if it has strictly more than 65535 vertices (max index = 65534) on a plaftorm that does not support 32 bits indices.
48  /// </summary>
49  /// <param name="meshDrawData">The mesh to analyze.</param>
50  /// <param name="can32bitIndex">A flag stating if 32 bit indices are allowed.</param>
51  /// <returns>A list of meshes.</returns>
52  public unsafe static List<MeshDrawData> SplitMesh(MeshDrawData meshDrawData, bool can32bitIndex)
53  {
54  if (meshDrawData.IndexBuffer == null)
55  return new List<MeshDrawData> { meshDrawData };
56 
57  if (!meshDrawData.IndexBuffer.Is32Bit) // already 16 bits buffer
58  return new List<MeshDrawData> { meshDrawData };
59 
60  var verticesCount = meshDrawData.VertexBuffers[0].Count;
61  if (verticesCount <= ushort.MaxValue) // can be put in a 16 bits buffer - 65535 = 0xFFFF is kept for primitive restart in strip
62  {
63  meshDrawData.CompactIndexBuffer();
64  return new List<MeshDrawData> { meshDrawData };
65  }
66 
67  // now, we only have a 32 bits buffer that is justified because of a large vertex buffer
68 
69  if (can32bitIndex) // do nothing
70  return new List<MeshDrawData> { meshDrawData };
71 
72  // TODO: handle primitives other than triangle list
73  if (meshDrawData.PrimitiveType != PrimitiveType.TriangleList)
74  return new List<MeshDrawData> { meshDrawData };
75 
76  // Split the mesh
77  var finalList = new List<MeshDrawData>();
78  fixed (byte* indicesByte = &meshDrawData.IndexBuffer.Buffer.Value.Content[0])
79  {
80  var indicesUint = (uint*)indicesByte;
81 
82  var splitInfos = new List<SplitInformation>();
83  var currentSplit = new SplitInformation();
84  currentSplit.StartTriangleIndex = 0;
85  var currentIndexUintPtr = indicesUint;
86  for (int triangleIndex = 0; triangleIndex < meshDrawData.IndexBuffer.Count / 3; ++triangleIndex)
87  {
88  var verticesToAdd = 0;
89  var index0 = *currentIndexUintPtr++;
90  var index1 = *currentIndexUintPtr++;
91  var index2 = *currentIndexUintPtr++;
92  if (!currentSplit.UsedIndices.Contains(index0)) ++verticesToAdd;
93  if (!currentSplit.UsedIndices.Contains(index1)) ++verticesToAdd;
94  if (!currentSplit.UsedIndices.Contains(index2)) ++verticesToAdd;
95 
96  if (currentSplit.UsedIndices.Count + verticesToAdd > 65535) // append in the same group
97  {
98  splitInfos.Add(currentSplit);
99  currentSplit = new SplitInformation();
100  currentSplit.StartTriangleIndex = triangleIndex;
101  }
102  AddTriangle(currentSplit, index0, index1, index2, triangleIndex);
103  }
104 
105  if (currentSplit.UsedIndices.Count > 0)
106  splitInfos.Add(currentSplit);
107 
108  foreach (var splitInfo in splitInfos)
109  {
110  var triangleCount = splitInfo.LastTriangleIndex - splitInfo.StartTriangleIndex + 1;
111  var newMeshDrawData = new MeshDrawData
112  {
113  PrimitiveType = PrimitiveType.TriangleList,
114  DrawCount = 3 * triangleCount,
115  VertexBuffers = new VertexBufferBindingData[meshDrawData.VertexBuffers.Length]
116  };
117 
118  // vertex buffers
119  for (int vbIndex = 0; vbIndex < meshDrawData.VertexBuffers.Length; ++ vbIndex)
120  {
121  var stride = meshDrawData.VertexBuffers[vbIndex].Stride;
122  if (stride == 0)
123  stride = meshDrawData.VertexBuffers[vbIndex].Declaration.VertexStride;
124  var newVertexBuffer = new byte[splitInfo.UsedIndices.Count * stride];
125 
126  fixed (byte* vertexBufferPtr = &meshDrawData.VertexBuffers[vbIndex].Buffer.Value.Content[0])
127  fixed (byte* newVertexBufferPtr = &newVertexBuffer[vbIndex])
128  {
129  //copy vertex buffer
130  foreach (var index in splitInfo.UsedIndices)
131  Utilities.CopyMemory((IntPtr)(newVertexBufferPtr + stride * splitInfo.IndexRemapping[index]), (IntPtr)(vertexBufferPtr + stride * index), stride);
132  }
133 
134  newMeshDrawData.VertexBuffers[vbIndex] = new VertexBufferBindingData
135  {
136  Offset = 0,
137  Count = splitInfo.UsedIndices.Count,
138  Buffer = new BufferData(BufferFlags.VertexBuffer, newVertexBuffer),
139  Declaration = meshDrawData.VertexBuffers[vbIndex].Declaration,
140  Stride = 0
141  };
142  }
143 
144  // index buffer
145  var newIndexBuffer = new byte[sizeof(ushort) * 3 * triangleCount];
146  fixed (byte* newIndexBufferPtr = &newIndexBuffer[0])
147  {
148  var newIndexBufferUshortPtr = (ushort*)newIndexBufferPtr;
149  var currentIndexPtr = &indicesUint[3 * splitInfo.StartTriangleIndex];
150  for (int triangleIndex = 0; triangleIndex < triangleCount; ++triangleIndex)
151  {
152  var index0 = *currentIndexPtr++;
153  var index1 = *currentIndexPtr++;
154  var index2 = *currentIndexPtr++;
155 
156  var newIndex0 = splitInfo.IndexRemapping[index0];
157  var newIndex1 = splitInfo.IndexRemapping[index1];
158  var newIndex2 = splitInfo.IndexRemapping[index2];
159 
160  *newIndexBufferUshortPtr++ = newIndex0;
161  *newIndexBufferUshortPtr++ = newIndex1;
162  *newIndexBufferUshortPtr++ = newIndex2;
163  }
164  }
165 
166  newMeshDrawData.IndexBuffer = new IndexBufferBindingData
167  {
168  Offset = 0,
169  Count = triangleCount * 3,
170  Buffer = new BufferData(BufferFlags.IndexBuffer, newIndexBuffer),
171  Is32Bit = false
172  };
173 
174  finalList.Add(newMeshDrawData);
175  }
176  }
177  return finalList;
178  }
179 
180  /// <summary>
181  /// Add the triangle to the split information.
182  /// </summary>
183  /// <param name="currentSplit">The current split information.</param>
184  /// <param name="index0">The index of the first vertex.</param>
185  /// <param name="index1">The index of the second vertex.</param>
186  /// <param name="index2">The index of the third vertex.</param>
187  /// <param name="triangleIndex">The original index of the triangle.</param>
188  private static void AddTriangle(SplitInformation currentSplit, uint index0, uint index1, uint index2, int triangleIndex)
189  {
190  if (currentSplit.UsedIndices.Add(index0)) currentSplit.IndexRemapping.Add(index0, (ushort)(currentSplit.UsedIndices.Count - 1));
191  if (currentSplit.UsedIndices.Add(index1)) currentSplit.IndexRemapping.Add(index1, (ushort)(currentSplit.UsedIndices.Count - 1));
192  if (currentSplit.UsedIndices.Add(index2)) currentSplit.IndexRemapping.Add(index2, (ushort)(currentSplit.UsedIndices.Count - 1));
193  currentSplit.LastTriangleIndex = triangleIndex;
194  }
195 
196  private class SplitInformation
197  {
198  public readonly Dictionary<uint, ushort> IndexRemapping;
199 
200  public readonly HashSet<uint> UsedIndices;
201 
202  public int StartTriangleIndex;
203 
204  public int LastTriangleIndex;
205 
206  public SplitInformation()
207  {
208  IndexRemapping = new Dictionary<uint, ushort>();
209  UsedIndices = new HashSet<uint>();
210  }
211  }
212  }
213 }
static unsafe List< MeshDrawData > SplitMesh(MeshDrawData meshDrawData, bool can32bitIndex)
Split the mesh if it has strictly more than 65535 vertices (max index = 65534) on a plaftorm that doe...
static List< MeshData > SplitMeshes(List< MeshData > meshes, bool can32bitIndex)
SiliconStudio.Paradox.Graphics.Data.VertexBufferBindingData[] VertexBuffers
Data field for SiliconStudio.Paradox.Effects.MeshDraw.VertexBuffers.
Definition: EngineData.cs:185
SiliconStudio.Paradox.Graphics.PrimitiveType PrimitiveType
Data field for SiliconStudio.Paradox.Effects.MeshDraw.PrimitiveType.
Definition: EngineData.cs:170
SiliconStudio.Paradox.Graphics.Data.IndexBufferBindingData IndexBuffer
Data field for SiliconStudio.Paradox.Effects.MeshDraw.IndexBuffer.
Definition: EngineData.cs:190
SiliconStudio.Core.Serialization.ContentReference< SiliconStudio.Paradox.Graphics.Data.BufferData > Buffer
Data field for SiliconStudio.Paradox.Graphics.VertexBufferBinding.Buffer.
All-in-One Buffer class linked SharpDX.Direct3D11.Buffer.
Data type for SiliconStudio.Paradox.Graphics.IndexBufferBinding.
SiliconStudio.Core.Serialization.ContentReference< SiliconStudio.Paradox.Graphics.Data.BufferData > Buffer
Data field for SiliconStudio.Paradox.Graphics.IndexBufferBinding.Buffer.
Data type for SiliconStudio.Paradox.Graphics.VertexBufferBinding.
Data type for SiliconStudio.Paradox.Effects.Mesh.
Definition: EngineData.cs:197
Data type for SiliconStudio.Paradox.Effects.MeshDraw.
Definition: EngineData.cs:165
PrimitiveType
Defines how vertex data is ordered.
System.Boolean Is32Bit
Data field for SiliconStudio.Paradox.Graphics.IndexBufferBinding.Is32Bit.
Content of a GPU buffer (vertex buffer, index buffer, etc...).
Definition: BufferData.cs:10