MeshBatch.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. #include "Base.h"
  2. #include "MeshBatch.h"
  3. namespace gameplay
  4. {
  5. MeshBatch::MeshBatch(const VertexFormat& vertexFormat, Mesh::PrimitiveType primitiveType, Material* material, bool indexed, unsigned int initialCapacity, unsigned int growSize)
  6. : _vertexFormat(vertexFormat), _primitiveType(primitiveType), _material(material), _indexed(indexed), _capacity(0), _growSize(growSize),
  7. _vertexCapacity(0), _indexCapacity(0), _vertexCount(0), _indexCount(0), _vertices(NULL), _verticesPtr(NULL), _indices(NULL), _indicesPtr(NULL)
  8. {
  9. resize(initialCapacity);
  10. }
  11. MeshBatch::MeshBatch(const MeshBatch& copy)
  12. : _vertexFormat(copy._vertexFormat)
  13. {
  14. // hidden
  15. }
  16. MeshBatch::~MeshBatch()
  17. {
  18. SAFE_RELEASE(_material);
  19. SAFE_DELETE_ARRAY(_vertices);
  20. SAFE_DELETE_ARRAY(_indices);
  21. }
  22. MeshBatch* MeshBatch::create(const VertexFormat& vertexFormat, Mesh::PrimitiveType primitiveType, const char* materialPath, bool indexed, unsigned int initialCapacity, unsigned int growSize)
  23. {
  24. Material* material = Material::create(materialPath);
  25. if (material == NULL)
  26. {
  27. GP_ERROR("Failed to create material for mesh batch from file '%s'.", materialPath);
  28. return NULL;
  29. }
  30. MeshBatch* batch = create(vertexFormat, primitiveType, material, indexed, initialCapacity, growSize);
  31. SAFE_RELEASE(material); // batch now owns the material
  32. return batch;
  33. }
  34. MeshBatch* MeshBatch::create(const VertexFormat& vertexFormat, Mesh::PrimitiveType primitiveType, Material* material, bool indexed, unsigned int initialCapacity, unsigned int growSize)
  35. {
  36. GP_ASSERT(material);
  37. MeshBatch* batch = new MeshBatch(vertexFormat, primitiveType, material, indexed, initialCapacity, growSize);
  38. material->addRef();
  39. return batch;
  40. }
  41. void MeshBatch::updateVertexAttributeBinding()
  42. {
  43. GP_ASSERT(_material);
  44. // Update our vertex attribute bindings.
  45. for (unsigned int i = 0, techniqueCount = _material->getTechniqueCount(); i < techniqueCount; ++i)
  46. {
  47. Technique* t = _material->getTechnique(i);
  48. GP_ASSERT(t);
  49. for (unsigned int j = 0, passCount = t->getPassCount(); j < passCount; ++j)
  50. {
  51. Pass* p = t->getPass(j);
  52. GP_ASSERT(p);
  53. VertexAttributeBinding* b = VertexAttributeBinding::create(_vertexFormat, _vertices, p->getEffect());
  54. p->setVertexAttributeBinding(b);
  55. SAFE_RELEASE(b);
  56. }
  57. }
  58. }
  59. unsigned int MeshBatch::getCapacity() const
  60. {
  61. return _capacity;
  62. }
  63. void MeshBatch::setCapacity(unsigned int capacity)
  64. {
  65. resize(capacity);
  66. }
  67. bool MeshBatch::resize(unsigned int capacity)
  68. {
  69. if (capacity == 0)
  70. {
  71. GP_ERROR("Invalid resize capacity (0).");
  72. return false;
  73. }
  74. if (capacity == _capacity)
  75. return true;
  76. // Store old batch data.
  77. unsigned char* oldVertices = _vertices;
  78. unsigned short* oldIndices = _indices;
  79. unsigned int vertexCapacity = 0;
  80. switch (_primitiveType)
  81. {
  82. case Mesh::LINES:
  83. vertexCapacity = capacity * 2;
  84. break;
  85. case Mesh::LINE_STRIP:
  86. vertexCapacity = capacity + 1;
  87. break;
  88. case Mesh::POINTS:
  89. vertexCapacity = capacity;
  90. break;
  91. case Mesh::TRIANGLES:
  92. vertexCapacity = capacity * 3;
  93. break;
  94. case Mesh::TRIANGLE_STRIP:
  95. vertexCapacity = capacity + 2;
  96. break;
  97. default:
  98. GP_ERROR("Unsupported primitive type for mesh batch (%d).", _primitiveType);
  99. return false;
  100. }
  101. // We have no way of knowing how many vertices will be stored in the batch
  102. // (we only know how many indices will be stored). Assume the worst case
  103. // for now, which is the same number of vertices as indices.
  104. unsigned int indexCapacity = vertexCapacity;
  105. if (indexCapacity > USHRT_MAX)
  106. {
  107. GP_ERROR("Index capacity is greater than the maximum unsigned short value (%d > %d).", indexCapacity, USHRT_MAX);
  108. return false;
  109. }
  110. // Allocate new data and reset pointers.
  111. unsigned int voffset = _verticesPtr - _vertices;
  112. unsigned int vBytes = vertexCapacity * _vertexFormat.getVertexSize();
  113. _vertices = new unsigned char[vBytes];
  114. if (voffset >= vBytes)
  115. voffset = vBytes - 1;
  116. _verticesPtr = _vertices + voffset;
  117. if (_indexed)
  118. {
  119. unsigned int ioffset = _indicesPtr - _indices;
  120. _indices = new unsigned short[indexCapacity];
  121. if (ioffset >= indexCapacity)
  122. ioffset = indexCapacity - 1;
  123. _indicesPtr = _indices + ioffset;
  124. }
  125. // Copy old data back in
  126. if (oldVertices)
  127. memcpy(_vertices, oldVertices, std::min(_vertexCapacity, vertexCapacity) * _vertexFormat.getVertexSize());
  128. SAFE_DELETE_ARRAY(oldVertices);
  129. if (oldIndices)
  130. memcpy(_indices, oldIndices, std::min(_indexCapacity, indexCapacity) * sizeof(unsigned short));
  131. SAFE_DELETE_ARRAY(oldIndices);
  132. // Assign new capacities
  133. _capacity = capacity;
  134. _vertexCapacity = vertexCapacity;
  135. _indexCapacity = indexCapacity;
  136. // Update our vertex attribute bindings now that our client array pointers have changed
  137. updateVertexAttributeBinding();
  138. return true;
  139. }
  140. void MeshBatch::begin()
  141. {
  142. _vertexCount = 0;
  143. _indexCount = 0;
  144. _verticesPtr = _vertices;
  145. _indicesPtr = _indices;
  146. }
  147. void MeshBatch::end()
  148. {
  149. }
  150. void MeshBatch::draw()
  151. {
  152. if (_vertexCount == 0 || (_indexed && _indexCount == 0))
  153. return; // nothing to draw
  154. // Not using VBOs, so unbind the element array buffer.
  155. // ARRAY_BUFFER will be unbound automatically during pass->bind().
  156. GL_ASSERT( glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0 ) );
  157. GP_ASSERT(_material);
  158. if (_indexed)
  159. GP_ASSERT(_indices);
  160. // Bind the material.
  161. Technique* technique = _material->getTechnique();
  162. GP_ASSERT(technique);
  163. unsigned int passCount = technique->getPassCount();
  164. for (unsigned int i = 0; i < passCount; ++i)
  165. {
  166. Pass* pass = technique->getPass(i);
  167. GP_ASSERT(pass);
  168. pass->bind();
  169. if (_indexed)
  170. {
  171. GL_ASSERT( glDrawElements(_primitiveType, _indexCount, GL_UNSIGNED_SHORT, (GLvoid*)_indices) );
  172. }
  173. else
  174. {
  175. GL_ASSERT( glDrawArrays(_primitiveType, 0, _vertexCount) );
  176. }
  177. pass->unbind();
  178. }
  179. }
  180. }