/JadEngine-Development/Jad/Import/JVertexCollector.cs
# · C# · 457 lines · 227 code · 96 blank · 134 comment · 23 complexity · cef83abad69aa6378912a3d6854d2c85 MD5 · raw file
- #region Using directives
-
- using System;
- using System.IO;
- using System.Collections.Generic;
-
- using Microsoft.DirectX;
- using Microsoft.DirectX.Direct3D;
-
- using JadEngine.Core;
- using JadEngine.Scene;
- using JadEngine.Video;
-
- #endregion
-
- namespace JadEngine.Import
- {
- /// <summary>
- /// Tool class used to build a VertexBuffer and IndexBuffer given a lot
- /// of vertex information. This class is usefull for importing, as you do not
- /// have to worry about if the vertex has position, texcoords, normals...
- /// You can see examples usign this class on the importes
- /// </summary>
- public class JVertexCollector
- {
- #region structs
-
- /// <summary>
- /// The internal structure for vertex
- /// </summary>
- internal struct internalVertex
- {
- internal Vector3 Position;
- internal Vector2[] TexCoord;
- internal Vector3 Normal;
- internal Vector3 Tangent;
- }
-
- #endregion
-
- #region Fields
-
- /// <summary>
- /// The parent video object
- /// </summary>
- JVideo _video;
-
- /// <summary>
- /// Used to find a mesh quickly
- /// </summary>
- Dictionary<string, int> _dictionary;
-
- /// <summary>
- /// The key that is builded for every vertex
- /// </summary>
- string _key;
-
- /// <summary>
- /// Final number of vertices created
- /// </summary>
- int _numVertices;
-
- /// <summary>
- /// Final number of indices created
- /// </summary>
- int _numIndices;
-
- /// <summary>
- /// MatID for the current vertex
- /// </summary>
- int _matID;
-
- /// <summary>
- /// List of attributes. Each list contains a list of indices for this attribute
- /// </summary>
- List<List<int>> _attributes;
-
- /// <summary>
- /// Temporal list of indices
- /// </summary>
- List<int> _indices;
-
- /// <summary>
- /// Temporal list of vertices
- /// </summary>
- List<internalVertex> _vertices;
-
- /// <summary>
- /// The final VertexBuffer created
- /// </summary>
- JVertexBuffer _vertexBuffer;
-
- /// <summary>
- /// The final IndexBuffer created
- /// </summary>
- JIndexBuffer _indexBuffer;
-
- /// <summary>
- /// The attribute range, used for submaterials into the mesh. If NumAttributes=1 this value can be null
- /// </summary>
- AttributeRange[] _attributeRange;
-
- /// <summary>
- /// Informs if the buffer has Normals
- /// </summary>
- bool _hasNormal;
-
- /// <summary>
- /// Informs if the buffer has Tangents
- /// </summary>
- bool _hasTangent;
-
- /// <summary>
- /// Informs the higher TexCoord stage. A value of 0 is no TexCoord
- /// </summary>
- int _maxTexCoord;
-
- /// <summary>
- /// If this value is true, we only have one material, so we can optimize
- /// the way we get the indices
- /// </summary>
- bool _onlyOneMatID;
-
- /// <summary>
- /// The current vertex when adding
- /// </summary>
- internalVertex _currentVertex;
-
- #endregion
-
- #region Properties
-
- /// <summary>
- /// Gets the attribute range, used for submaterials into the mesh
- /// </summary>
- public AttributeRange[] AttributeRange
- {
- get { return _attributeRange; }
- }
-
- /// <summary>
- /// Gets if the buffer has Normals
- /// </summary>
- public bool HasNormal
- {
- get { return _hasNormal; }
- }
-
- /// <summary>
- /// Gets if the buffer has Tangents
- /// </summary>
- public bool HasTangent
- {
- get { return _hasTangent; }
- }
-
- /// <summary>
- /// Gets the higher TexCoord stage. A value of 0 is no TexCoord
- /// </summary>
- public int MaxTexCoord
- {
- get { return _maxTexCoord; }
- }
-
- /// <summary>
- /// Gets the VertexBuffer
- /// </summary>
- public JVertexBuffer VertexBuffer
- {
- get { return _vertexBuffer; }
- }
-
- /// <summary>
- /// Gets the IndexBuffer
- /// </summary>
- public JIndexBuffer IndexBuffer
- {
- get { return _indexBuffer; }
- }
-
- #endregion
-
- #region Constructors
-
- /// <summary>
- /// Default constructor
- /// </summary>
- /// <param name="video">The parent video instance</param>
- public JVertexCollector(JVideo video)
- {
- _video = video;
- }
-
- #endregion
-
- #region Methods
-
- /// <summary>
- /// Initialize the collector.
- /// </summary>
- /// <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>
- public void Initialize(bool onlyOneMatID)
- {
- _dictionary = new Dictionary<string, int>();
- _indices = new List<int>();
- _attributes = new List<List<int>>();
- _vertices = new List<internalVertex>();
-
- _onlyOneMatID = onlyOneMatID;
- _hasNormal = _hasTangent=false;
- _maxTexCoord = -1;
- _numVertices = 0;
- _numIndices = 0;
- }
-
- /// <summary>
- /// Begins the new vertice addition
- /// </summary>
- public void Begin()
- {
- Begin(0);
- }
-
- /// <summary>
- /// Begins the new vertice addition with material ID
- /// </summary>
- /// <param name="matID">The material ID for this vertex</param>
- public void Begin(int matID)
- {
- _key = null;
- _currentVertex = new internalVertex();
- _currentVertex.TexCoord = new Vector2[8];
- _matID = matID;
- }
-
- /// <summary>
- /// Adds the position
- /// </summary>
- /// <param name="position">A valid position</param>
- public void AddPosition(Vector3 position)
- {
- _key += position.ToString();
-
- _currentVertex.Position = position;
- }
-
- /// <summary>
- /// Adds the normal
- /// </summary>
- /// <param name="normal">A valid normal</param>
- public void AddNormal(Vector3 normal)
- {
- _key += normal.ToString();
-
- _currentVertex.Normal = normal;
-
- _hasNormal = true;
- }
-
- /// <summary>
- /// Adds the tangent
- /// </summary>
- /// <param name="tangent">A valid tangent</param>
- public void AddTangent(Vector3 tangent)
- {
- _key += tangent.ToString();
-
- _currentVertex.Tangent = tangent;
-
- _hasTangent = true;
- }
-
- /// <summary>
- /// Adds the texture coord
- /// </summary>
- /// <param name="num">The texCoord stage</param>
- /// <param name="texCoord">A valid TexCoord</param>
- public void AddTexCoord(int num, Vector2 texCoord)
- {
- _key += texCoord.ToString();
-
- _currentVertex.TexCoord[num] = texCoord;
-
- if (num > _maxTexCoord) _maxTexCoord = num;
- }
-
- /// <summary>
- /// Ends the new vertice addition
- /// </summary>
- public void End()
- {
- int index;
-
- // If this vertex does not exists
- if (!_dictionary.ContainsKey(_key))
- {
- _dictionary.Add(_key, _numVertices);
-
- _vertices.Add(_currentVertex);
-
- index = _numVertices;
-
- _numVertices++;
-
- }
- else
- {
- index = _dictionary[_key];
- }
-
- if (_onlyOneMatID)
- {
- _indices.Add(index);
- }
- else
- {
- // We have a list of a list of ints.
- // The first element is the MatID
-
- List<int> indexListToAdd = null;
-
- // Check for the matID if exists
- for (int i = 0; i < _attributes.Count; i++)
- {
- List<int> indexList = _attributes[i];
-
- if (indexList[0] == _matID)
- {
- indexListToAdd = indexList;
- break;
- }
- }
-
- // If not, add a new element
- if (indexListToAdd == null)
- {
- indexListToAdd = new List<int>();
-
- _attributes.Add(indexListToAdd);
-
- // And the first element is the matID
- indexListToAdd.Add(_matID);
- }
-
- // Add the index to the list
- indexListToAdd.Add(index);
- }
-
- _numIndices++;
- }
-
- /// <summary>
- /// Finish the collector, builds the buffers and fill the mesh information
- /// </summary>
- public void FinishAndFill(JMesh mesh)
- {
- Finish();
-
- FillMesh(mesh);
- }
-
- /// <summary>
- /// Finish the collector and builds the buffers. Yo can use the properties
- /// to get information about the buffers created
- /// </summary>
- public void Finish()
- {
- _vertexBuffer = new JVertexBuffer(_numVertices);
-
- _vertexBuffer.Position = new Vector3[_numVertices];
-
- if(_hasNormal) _vertexBuffer.Normal = new Vector3[_numVertices];
-
- if (_hasTangent) _vertexBuffer.Tangent = new Vector3[_numVertices];
-
- _maxTexCoord++;
-
- if (_maxTexCoord != 0) _vertexBuffer.TexCoord = new Vector2[_maxTexCoord,_numVertices];
-
- int i=0;
-
- foreach (internalVertex vertex in _vertices)
- {
- _vertexBuffer.Position[i] = vertex.Position;
-
- if (_hasNormal) _vertexBuffer.Normal[i] = vertex.Normal;
-
- if (_hasTangent) _vertexBuffer.Tangent[i] = vertex.Tangent;
-
- if (_maxTexCoord != 0)
- {
- for (int j = 0; j < _maxTexCoord; j++)
- _vertexBuffer.TexCoord[j, i] = vertex.TexCoord[j];
- }
- i++;
- }
-
- _indexBuffer = new JIndexBuffer((_numVertices > ushort.MaxValue), _numIndices);
-
- if (_onlyOneMatID)
- {
- _indices.CopyTo(_indexBuffer.Indices);
- }
- else
- {
- _attributeRange = new AttributeRange[_attributes.Count];
-
- int attributeID = 0,numIndex=0;
-
- if (_attributes.Count > 1)
- numIndex = 0;
-
- foreach (List<int> indices in _attributes)
- {
- int numIndices=indices.Count-1;
-
- _attributeRange[attributeID].AttributeId = attributeID;
- _attributeRange[attributeID].FaceStart = numIndex / 3;
- _attributeRange[attributeID].FaceCount = numIndices/3;
- _attributeRange[attributeID].VertexCount = 0;
- _attributeRange[attributeID++].VertexStart = 0;
-
- indices.CopyTo(1, _indexBuffer.Indices, numIndex, numIndices);
-
- numIndex += numIndices;
-
- }
-
- // If we have only one subset, we do not need attributeRange
- if (_attributes.Count == 1) _attributeRange = null;
-
- }
-
- // Release memory
- _dictionary.Clear();
- _vertices.Clear();
- _indices.Clear();
- _attributes.Clear();
- }
-
- /// <summary>
- /// Fill the mesh vertex buffer and index buffer
- /// </summary>
- /// <param name="mesh">A valid instance</param>
- public void FillMesh(JMesh mesh)
- {
- mesh.VertexBuffer = _vertexBuffer;
- mesh.IndexBuffer = _indexBuffer;
- mesh.AttributeRange = _attributeRange;
-
- if (_hasNormal) mesh.NormalsComputed = true;
- if (_hasTangent) mesh.TangentComputed = true;
- }
-
- #endregion
- }
- }