MeshBatch.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. #include "Base.h"
  2. #include "MeshBatch.h"
  3. #include "Material.h"
  4. namespace gameplay
  5. {
  6. MeshBatch::MeshBatch(const VertexFormat& vertexFormat, Mesh::PrimitiveType primitiveType, Material* material, bool indexed, unsigned int initialCapacity, unsigned int growSize)
  7. : _vertexFormat(vertexFormat), _primitiveType(primitiveType), _material(material), _indexed(indexed), _capacity(0), _growSize(growSize),
  8. _vertexCapacity(0), _indexCapacity(0), _vertexCount(0), _indexCount(0), _vertices(NULL), _verticesPtr(NULL), _indices(NULL), _indicesPtr(NULL)
  9. {
  10. resize(initialCapacity);
  11. }
  12. MeshBatch::~MeshBatch()
  13. {
  14. SAFE_RELEASE(_material);
  15. SAFE_DELETE_ARRAY(_vertices);
  16. SAFE_DELETE_ARRAY(_indices);
  17. }
  18. MeshBatch* MeshBatch::create(const VertexFormat& vertexFormat, Mesh::PrimitiveType primitiveType, const char* materialPath, bool indexed, unsigned int initialCapacity, unsigned int growSize)
  19. {
  20. Material* material = Material::create(materialPath);
  21. if (material == NULL)
  22. {
  23. GP_ERROR("Failed to create material for mesh batch from file '%s'.", materialPath);
  24. return NULL;
  25. }
  26. MeshBatch* batch = create(vertexFormat, primitiveType, material, indexed, initialCapacity, growSize);
  27. SAFE_RELEASE(material); // batch now owns the material
  28. return batch;
  29. }
  30. MeshBatch* MeshBatch::create(const VertexFormat& vertexFormat, Mesh::PrimitiveType primitiveType, Material* material, bool indexed, unsigned int initialCapacity, unsigned int growSize)
  31. {
  32. GP_ASSERT(material);
  33. MeshBatch* batch = new MeshBatch(vertexFormat, primitiveType, material, indexed, initialCapacity, growSize);
  34. material->addRef();
  35. return batch;
  36. }
  37. void MeshBatch::add(const void* vertices, size_t size, unsigned int vertexCount, const unsigned short* indices, unsigned int indexCount)
  38. {
  39. GP_ASSERT(vertices);
  40. unsigned int newVertexCount = _vertexCount + vertexCount;
  41. unsigned int newIndexCount = _indexCount + indexCount;
  42. if (_primitiveType == Mesh::TRIANGLE_STRIP && _vertexCount > 0)
  43. newIndexCount += 2; // need an extra 2 indices for connecting strips with degenerate triangles
  44. // Do we need to grow the batch?
  45. while (newVertexCount > _vertexCapacity || (_indexed && newIndexCount > _indexCapacity))
  46. {
  47. if (_growSize == 0)
  48. return; // growing disabled, just clip batch
  49. if (!resize(_capacity + _growSize))
  50. return; // failed to grow
  51. }
  52. // Copy vertex data.
  53. GP_ASSERT(_verticesPtr);
  54. unsigned int vBytes = vertexCount * _vertexFormat.getVertexSize();
  55. memcpy(_verticesPtr, vertices, vBytes);
  56. // Copy index data.
  57. if (_indexed)
  58. {
  59. GP_ASSERT(indices);
  60. GP_ASSERT(_indicesPtr);
  61. if (_vertexCount == 0)
  62. {
  63. // Simply copy values directly into the start of the index array.
  64. memcpy(_indicesPtr, indices, indexCount * sizeof(unsigned short));
  65. }
  66. else
  67. {
  68. if (_primitiveType == Mesh::TRIANGLE_STRIP)
  69. {
  70. // Create a degenerate triangle to connect separate triangle strips
  71. // by duplicating the previous and next vertices.
  72. _indicesPtr[0] = *(_indicesPtr-1);
  73. _indicesPtr[1] = _vertexCount;
  74. _indicesPtr += 2;
  75. }
  76. // Loop through all indices and insert them, with their values offset by
  77. // 'vertexCount' so that they are relative to the first newly inserted vertex.
  78. for (unsigned int i = 0; i < indexCount; ++i)
  79. {
  80. _indicesPtr[i] = indices[i] + _vertexCount;
  81. }
  82. }
  83. _indicesPtr += indexCount;
  84. _indexCount = newIndexCount;
  85. }
  86. _verticesPtr += vBytes;
  87. _vertexCount = newVertexCount;
  88. }
  89. void MeshBatch::updateVertexAttributeBinding()
  90. {
  91. GP_ASSERT(_material);
  92. // Update our vertex attribute bindings.
  93. for (unsigned int i = 0, techniqueCount = _material->getTechniqueCount(); i < techniqueCount; ++i)
  94. {
  95. Technique* t = _material->getTechniqueByIndex(i);
  96. GP_ASSERT(t);
  97. for (unsigned int j = 0, passCount = t->getPassCount(); j < passCount; ++j)
  98. {
  99. Pass* p = t->getPassByIndex(j);
  100. GP_ASSERT(p);
  101. VertexAttributeBinding* b = VertexAttributeBinding::create(_vertexFormat, _vertices, p->getEffect());
  102. p->setVertexAttributeBinding(b);
  103. SAFE_RELEASE(b);
  104. }
  105. }
  106. }
  107. unsigned int MeshBatch::getCapacity() const
  108. {
  109. return _capacity;
  110. }
  111. void MeshBatch::setCapacity(unsigned int capacity)
  112. {
  113. resize(capacity);
  114. }
  115. bool MeshBatch::resize(unsigned int capacity)
  116. {
  117. if (capacity == 0)
  118. {
  119. GP_ERROR("Invalid resize capacity (0).");
  120. return false;
  121. }
  122. if (capacity == _capacity)
  123. return true;
  124. // Store old batch data.
  125. unsigned char* oldVertices = _vertices;
  126. unsigned short* oldIndices = _indices;
  127. unsigned int vertexCapacity = 0;
  128. switch (_primitiveType)
  129. {
  130. case Mesh::LINES:
  131. vertexCapacity = capacity * 2;
  132. break;
  133. case Mesh::LINE_STRIP:
  134. vertexCapacity = capacity + 1;
  135. break;
  136. case Mesh::POINTS:
  137. vertexCapacity = capacity;
  138. break;
  139. case Mesh::TRIANGLES:
  140. vertexCapacity = capacity * 3;
  141. break;
  142. case Mesh::TRIANGLE_STRIP:
  143. vertexCapacity = capacity + 2;
  144. break;
  145. default:
  146. GP_ERROR("Unsupported primitive type for mesh batch (%d).", _primitiveType);
  147. return false;
  148. }
  149. // We have no way of knowing how many vertices will be stored in the batch
  150. // (we only know how many indices will be stored). Assume the worst case
  151. // for now, which is the same number of vertices as indices.
  152. unsigned int indexCapacity = vertexCapacity;
  153. if (_indexed && indexCapacity > USHRT_MAX)
  154. {
  155. GP_ERROR("Index capacity is greater than the maximum unsigned short value (%d > %d).", indexCapacity, USHRT_MAX);
  156. return false;
  157. }
  158. // Allocate new data and reset pointers.
  159. unsigned int voffset = _verticesPtr - _vertices;
  160. unsigned int vBytes = vertexCapacity * _vertexFormat.getVertexSize();
  161. _vertices = new unsigned char[vBytes];
  162. if (voffset >= vBytes)
  163. voffset = vBytes - 1;
  164. _verticesPtr = _vertices + voffset;
  165. if (_indexed)
  166. {
  167. unsigned int ioffset = _indicesPtr - _indices;
  168. _indices = new unsigned short[indexCapacity];
  169. if (ioffset >= indexCapacity)
  170. ioffset = indexCapacity - 1;
  171. _indicesPtr = _indices + ioffset;
  172. }
  173. // Copy old data back in
  174. if (oldVertices)
  175. memcpy(_vertices, oldVertices, std::min(_vertexCapacity, vertexCapacity) * _vertexFormat.getVertexSize());
  176. SAFE_DELETE_ARRAY(oldVertices);
  177. if (oldIndices)
  178. memcpy(_indices, oldIndices, std::min(_indexCapacity, indexCapacity) * sizeof(unsigned short));
  179. SAFE_DELETE_ARRAY(oldIndices);
  180. // Assign new capacities
  181. _capacity = capacity;
  182. _vertexCapacity = vertexCapacity;
  183. _indexCapacity = indexCapacity;
  184. // Update our vertex attribute bindings now that our client array pointers have changed
  185. updateVertexAttributeBinding();
  186. return true;
  187. }
  188. void MeshBatch::add(const float* vertices, unsigned int vertexCount, const unsigned short* indices, unsigned int indexCount)
  189. {
  190. add(vertices, sizeof(float), vertexCount, indices, indexCount);
  191. }
  192. void MeshBatch::start()
  193. {
  194. _vertexCount = 0;
  195. _indexCount = 0;
  196. _verticesPtr = _vertices;
  197. _indicesPtr = _indices;
  198. }
  199. void MeshBatch::finish()
  200. {
  201. }
  202. void MeshBatch::draw()
  203. {
  204. if (_vertexCount == 0 || (_indexed && _indexCount == 0))
  205. return; // nothing to draw
  206. // Not using VBOs, so unbind the element array buffer.
  207. // ARRAY_BUFFER will be unbound automatically during pass->bind().
  208. GL_ASSERT( glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0 ) );
  209. GP_ASSERT(_material);
  210. if (_indexed)
  211. GP_ASSERT(_indices);
  212. // Bind the material.
  213. Technique* technique = _material->getTechnique();
  214. GP_ASSERT(technique);
  215. unsigned int passCount = technique->getPassCount();
  216. for (unsigned int i = 0; i < passCount; ++i)
  217. {
  218. Pass* pass = technique->getPassByIndex(i);
  219. GP_ASSERT(pass);
  220. pass->bind();
  221. if (_indexed)
  222. {
  223. GL_ASSERT( glDrawElements(_primitiveType, _indexCount, GL_UNSIGNED_SHORT, (GLvoid*)_indices) );
  224. }
  225. else
  226. {
  227. GL_ASSERT( glDrawArrays(_primitiveType, 0, _vertexCount) );
  228. }
  229. pass->unbind();
  230. }
  231. }
  232. }