/JadEngine-Development/Jad/Import/JVertexCollector.cs

# · C# · 457 lines · 227 code · 96 blank · 134 comment · 23 complexity · cef83abad69aa6378912a3d6854d2c85 MD5 · raw file

  1. #region Using directives
  2. using System;
  3. using System.IO;
  4. using System.Collections.Generic;
  5. using Microsoft.DirectX;
  6. using Microsoft.DirectX.Direct3D;
  7. using JadEngine.Core;
  8. using JadEngine.Scene;
  9. using JadEngine.Video;
  10. #endregion
  11. namespace JadEngine.Import
  12. {
  13. /// <summary>
  14. /// Tool class used to build a VertexBuffer and IndexBuffer given a lot
  15. /// of vertex information. This class is usefull for importing, as you do not
  16. /// have to worry about if the vertex has position, texcoords, normals...
  17. /// You can see examples usign this class on the importes
  18. /// </summary>
  19. public class JVertexCollector
  20. {
  21. #region structs
  22. /// <summary>
  23. /// The internal structure for vertex
  24. /// </summary>
  25. internal struct internalVertex
  26. {
  27. internal Vector3 Position;
  28. internal Vector2[] TexCoord;
  29. internal Vector3 Normal;
  30. internal Vector3 Tangent;
  31. }
  32. #endregion
  33. #region Fields
  34. /// <summary>
  35. /// The parent video object
  36. /// </summary>
  37. JVideo _video;
  38. /// <summary>
  39. /// Used to find a mesh quickly
  40. /// </summary>
  41. Dictionary<string, int> _dictionary;
  42. /// <summary>
  43. /// The key that is builded for every vertex
  44. /// </summary>
  45. string _key;
  46. /// <summary>
  47. /// Final number of vertices created
  48. /// </summary>
  49. int _numVertices;
  50. /// <summary>
  51. /// Final number of indices created
  52. /// </summary>
  53. int _numIndices;
  54. /// <summary>
  55. /// MatID for the current vertex
  56. /// </summary>
  57. int _matID;
  58. /// <summary>
  59. /// List of attributes. Each list contains a list of indices for this attribute
  60. /// </summary>
  61. List<List<int>> _attributes;
  62. /// <summary>
  63. /// Temporal list of indices
  64. /// </summary>
  65. List<int> _indices;
  66. /// <summary>
  67. /// Temporal list of vertices
  68. /// </summary>
  69. List<internalVertex> _vertices;
  70. /// <summary>
  71. /// The final VertexBuffer created
  72. /// </summary>
  73. JVertexBuffer _vertexBuffer;
  74. /// <summary>
  75. /// The final IndexBuffer created
  76. /// </summary>
  77. JIndexBuffer _indexBuffer;
  78. /// <summary>
  79. /// The attribute range, used for submaterials into the mesh. If NumAttributes=1 this value can be null
  80. /// </summary>
  81. AttributeRange[] _attributeRange;
  82. /// <summary>
  83. /// Informs if the buffer has Normals
  84. /// </summary>
  85. bool _hasNormal;
  86. /// <summary>
  87. /// Informs if the buffer has Tangents
  88. /// </summary>
  89. bool _hasTangent;
  90. /// <summary>
  91. /// Informs the higher TexCoord stage. A value of 0 is no TexCoord
  92. /// </summary>
  93. int _maxTexCoord;
  94. /// <summary>
  95. /// If this value is true, we only have one material, so we can optimize
  96. /// the way we get the indices
  97. /// </summary>
  98. bool _onlyOneMatID;
  99. /// <summary>
  100. /// The current vertex when adding
  101. /// </summary>
  102. internalVertex _currentVertex;
  103. #endregion
  104. #region Properties
  105. /// <summary>
  106. /// Gets the attribute range, used for submaterials into the mesh
  107. /// </summary>
  108. public AttributeRange[] AttributeRange
  109. {
  110. get { return _attributeRange; }
  111. }
  112. /// <summary>
  113. /// Gets if the buffer has Normals
  114. /// </summary>
  115. public bool HasNormal
  116. {
  117. get { return _hasNormal; }
  118. }
  119. /// <summary>
  120. /// Gets if the buffer has Tangents
  121. /// </summary>
  122. public bool HasTangent
  123. {
  124. get { return _hasTangent; }
  125. }
  126. /// <summary>
  127. /// Gets the higher TexCoord stage. A value of 0 is no TexCoord
  128. /// </summary>
  129. public int MaxTexCoord
  130. {
  131. get { return _maxTexCoord; }
  132. }
  133. /// <summary>
  134. /// Gets the VertexBuffer
  135. /// </summary>
  136. public JVertexBuffer VertexBuffer
  137. {
  138. get { return _vertexBuffer; }
  139. }
  140. /// <summary>
  141. /// Gets the IndexBuffer
  142. /// </summary>
  143. public JIndexBuffer IndexBuffer
  144. {
  145. get { return _indexBuffer; }
  146. }
  147. #endregion
  148. #region Constructors
  149. /// <summary>
  150. /// Default constructor
  151. /// </summary>
  152. /// <param name="video">The parent video instance</param>
  153. public JVertexCollector(JVideo video)
  154. {
  155. _video = video;
  156. }
  157. #endregion
  158. #region Methods
  159. /// <summary>
  160. /// Initialize the collector.
  161. /// </summary>
  162. /// <param name="onlyOneMatID">If you know that the mesh has only one material, set this parameter to true as it will optimize the insertion of vertices. If you do not know that, set it to false</param>
  163. public void Initialize(bool onlyOneMatID)
  164. {
  165. _dictionary = new Dictionary<string, int>();
  166. _indices = new List<int>();
  167. _attributes = new List<List<int>>();
  168. _vertices = new List<internalVertex>();
  169. _onlyOneMatID = onlyOneMatID;
  170. _hasNormal = _hasTangent=false;
  171. _maxTexCoord = -1;
  172. _numVertices = 0;
  173. _numIndices = 0;
  174. }
  175. /// <summary>
  176. /// Begins the new vertice addition
  177. /// </summary>
  178. public void Begin()
  179. {
  180. Begin(0);
  181. }
  182. /// <summary>
  183. /// Begins the new vertice addition with material ID
  184. /// </summary>
  185. /// <param name="matID">The material ID for this vertex</param>
  186. public void Begin(int matID)
  187. {
  188. _key = null;
  189. _currentVertex = new internalVertex();
  190. _currentVertex.TexCoord = new Vector2[8];
  191. _matID = matID;
  192. }
  193. /// <summary>
  194. /// Adds the position
  195. /// </summary>
  196. /// <param name="position">A valid position</param>
  197. public void AddPosition(Vector3 position)
  198. {
  199. _key += position.ToString();
  200. _currentVertex.Position = position;
  201. }
  202. /// <summary>
  203. /// Adds the normal
  204. /// </summary>
  205. /// <param name="normal">A valid normal</param>
  206. public void AddNormal(Vector3 normal)
  207. {
  208. _key += normal.ToString();
  209. _currentVertex.Normal = normal;
  210. _hasNormal = true;
  211. }
  212. /// <summary>
  213. /// Adds the tangent
  214. /// </summary>
  215. /// <param name="tangent">A valid tangent</param>
  216. public void AddTangent(Vector3 tangent)
  217. {
  218. _key += tangent.ToString();
  219. _currentVertex.Tangent = tangent;
  220. _hasTangent = true;
  221. }
  222. /// <summary>
  223. /// Adds the texture coord
  224. /// </summary>
  225. /// <param name="num">The texCoord stage</param>
  226. /// <param name="texCoord">A valid TexCoord</param>
  227. public void AddTexCoord(int num, Vector2 texCoord)
  228. {
  229. _key += texCoord.ToString();
  230. _currentVertex.TexCoord[num] = texCoord;
  231. if (num > _maxTexCoord) _maxTexCoord = num;
  232. }
  233. /// <summary>
  234. /// Ends the new vertice addition
  235. /// </summary>
  236. public void End()
  237. {
  238. int index;
  239. // If this vertex does not exists
  240. if (!_dictionary.ContainsKey(_key))
  241. {
  242. _dictionary.Add(_key, _numVertices);
  243. _vertices.Add(_currentVertex);
  244. index = _numVertices;
  245. _numVertices++;
  246. }
  247. else
  248. {
  249. index = _dictionary[_key];
  250. }
  251. if (_onlyOneMatID)
  252. {
  253. _indices.Add(index);
  254. }
  255. else
  256. {
  257. // We have a list of a list of ints.
  258. // The first element is the MatID
  259. List<int> indexListToAdd = null;
  260. // Check for the matID if exists
  261. for (int i = 0; i < _attributes.Count; i++)
  262. {
  263. List<int> indexList = _attributes[i];
  264. if (indexList[0] == _matID)
  265. {
  266. indexListToAdd = indexList;
  267. break;
  268. }
  269. }
  270. // If not, add a new element
  271. if (indexListToAdd == null)
  272. {
  273. indexListToAdd = new List<int>();
  274. _attributes.Add(indexListToAdd);
  275. // And the first element is the matID
  276. indexListToAdd.Add(_matID);
  277. }
  278. // Add the index to the list
  279. indexListToAdd.Add(index);
  280. }
  281. _numIndices++;
  282. }
  283. /// <summary>
  284. /// Finish the collector, builds the buffers and fill the mesh information
  285. /// </summary>
  286. public void FinishAndFill(JMesh mesh)
  287. {
  288. Finish();
  289. FillMesh(mesh);
  290. }
  291. /// <summary>
  292. /// Finish the collector and builds the buffers. Yo can use the properties
  293. /// to get information about the buffers created
  294. /// </summary>
  295. public void Finish()
  296. {
  297. _vertexBuffer = new JVertexBuffer(_numVertices);
  298. _vertexBuffer.Position = new Vector3[_numVertices];
  299. if(_hasNormal) _vertexBuffer.Normal = new Vector3[_numVertices];
  300. if (_hasTangent) _vertexBuffer.Tangent = new Vector3[_numVertices];
  301. _maxTexCoord++;
  302. if (_maxTexCoord != 0) _vertexBuffer.TexCoord = new Vector2[_maxTexCoord,_numVertices];
  303. int i=0;
  304. foreach (internalVertex vertex in _vertices)
  305. {
  306. _vertexBuffer.Position[i] = vertex.Position;
  307. if (_hasNormal) _vertexBuffer.Normal[i] = vertex.Normal;
  308. if (_hasTangent) _vertexBuffer.Tangent[i] = vertex.Tangent;
  309. if (_maxTexCoord != 0)
  310. {
  311. for (int j = 0; j < _maxTexCoord; j++)
  312. _vertexBuffer.TexCoord[j, i] = vertex.TexCoord[j];
  313. }
  314. i++;
  315. }
  316. _indexBuffer = new JIndexBuffer((_numVertices > ushort.MaxValue), _numIndices);
  317. if (_onlyOneMatID)
  318. {
  319. _indices.CopyTo(_indexBuffer.Indices);
  320. }
  321. else
  322. {
  323. _attributeRange = new AttributeRange[_attributes.Count];
  324. int attributeID = 0,numIndex=0;
  325. if (_attributes.Count > 1)
  326. numIndex = 0;
  327. foreach (List<int> indices in _attributes)
  328. {
  329. int numIndices=indices.Count-1;
  330. _attributeRange[attributeID].AttributeId = attributeID;
  331. _attributeRange[attributeID].FaceStart = numIndex / 3;
  332. _attributeRange[attributeID].FaceCount = numIndices/3;
  333. _attributeRange[attributeID].VertexCount = 0;
  334. _attributeRange[attributeID++].VertexStart = 0;
  335. indices.CopyTo(1, _indexBuffer.Indices, numIndex, numIndices);
  336. numIndex += numIndices;
  337. }
  338. // If we have only one subset, we do not need attributeRange
  339. if (_attributes.Count == 1) _attributeRange = null;
  340. }
  341. // Release memory
  342. _dictionary.Clear();
  343. _vertices.Clear();
  344. _indices.Clear();
  345. _attributes.Clear();
  346. }
  347. /// <summary>
  348. /// Fill the mesh vertex buffer and index buffer
  349. /// </summary>
  350. /// <param name="mesh">A valid instance</param>
  351. public void FillMesh(JMesh mesh)
  352. {
  353. mesh.VertexBuffer = _vertexBuffer;
  354. mesh.IndexBuffer = _indexBuffer;
  355. mesh.AttributeRange = _attributeRange;
  356. if (_hasNormal) mesh.NormalsComputed = true;
  357. if (_hasTangent) mesh.TangentComputed = true;
  358. }
  359. #endregion
  360. }
  361. }