VertexArray.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*global define*/
  2. define([
  3. '../Core/ComponentDatatype',
  4. '../Core/defaultValue',
  5. '../Core/defined',
  6. '../Core/defineProperties',
  7. '../Core/destroyObject',
  8. '../Core/DeveloperError'
  9. ], function(
  10. ComponentDatatype,
  11. defaultValue,
  12. defined,
  13. defineProperties,
  14. destroyObject,
  15. DeveloperError) {
  16. "use strict";
  17. function addAttribute(attributes, attribute, index) {
  18. var hasVertexBuffer = defined(attribute.vertexBuffer);
  19. var hasValue = defined(attribute.value);
  20. var componentsPerAttribute = attribute.value ? attribute.value.length : attribute.componentsPerAttribute;
  21. //>>includeStart('debug', pragmas.debug);
  22. if (!hasVertexBuffer && !hasValue) {
  23. throw new DeveloperError('attribute must have a vertexBuffer or a value.');
  24. }
  25. if (hasVertexBuffer && hasValue) {
  26. throw new DeveloperError('attribute cannot have both a vertexBuffer and a value. It must have either a vertexBuffer property defining per-vertex data or a value property defining data for all vertices.');
  27. }
  28. if ((componentsPerAttribute !== 1) &&
  29. (componentsPerAttribute !== 2) &&
  30. (componentsPerAttribute !== 3) &&
  31. (componentsPerAttribute !== 4)) {
  32. if (hasValue) {
  33. throw new DeveloperError('attribute.value.length must be in the range [1, 4].');
  34. }
  35. throw new DeveloperError('attribute.componentsPerAttribute must be in the range [1, 4].');
  36. }
  37. if (defined(attribute.componentDatatype) && !ComponentDatatype.validate(attribute.componentDatatype)) {
  38. throw new DeveloperError('attribute must have a valid componentDatatype or not specify it.');
  39. }
  40. if (defined(attribute.strideInBytes) && (attribute.strideInBytes > 255)) {
  41. // WebGL limit. Not in GL ES.
  42. throw new DeveloperError('attribute must have a strideInBytes less than or equal to 255 or not specify it.');
  43. }
  44. //>>includeEnd('debug');
  45. // Shallow copy the attribute; we do not want to copy the vertex buffer.
  46. var attr = {
  47. index : defaultValue(attribute.index, index),
  48. enabled : defaultValue(attribute.enabled, true),
  49. vertexBuffer : attribute.vertexBuffer,
  50. value : hasValue ? attribute.value.slice(0) : undefined,
  51. componentsPerAttribute : componentsPerAttribute,
  52. componentDatatype : defaultValue(attribute.componentDatatype, ComponentDatatype.FLOAT),
  53. normalize : defaultValue(attribute.normalize, false),
  54. offsetInBytes : defaultValue(attribute.offsetInBytes, 0),
  55. strideInBytes : defaultValue(attribute.strideInBytes, 0)
  56. };
  57. if (hasVertexBuffer) {
  58. // Common case: vertex buffer for per-vertex data
  59. attr.vertexAttrib = function(gl) {
  60. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer._getBuffer());
  61. gl.vertexAttribPointer(this.index, this.componentsPerAttribute, this.componentDatatype, this.normalize, this.strideInBytes, this.offsetInBytes);
  62. gl.enableVertexAttribArray(this.index);
  63. };
  64. attr.disableVertexAttribArray = function(gl) {
  65. gl.disableVertexAttribArray(this.index);
  66. };
  67. } else {
  68. // Less common case: value array for the same data for each vertex
  69. switch (attr.componentsPerAttribute) {
  70. case 1:
  71. attr.vertexAttrib = function(gl) {
  72. gl.vertexAttrib1fv(this.index, this.value);
  73. };
  74. break;
  75. case 2:
  76. attr.vertexAttrib = function(gl) {
  77. gl.vertexAttrib2fv(this.index, this.value);
  78. };
  79. break;
  80. case 3:
  81. attr.vertexAttrib = function(gl) {
  82. gl.vertexAttrib3fv(this.index, this.value);
  83. };
  84. break;
  85. case 4:
  86. attr.vertexAttrib = function(gl) {
  87. gl.vertexAttrib4fv(this.index, this.value);
  88. };
  89. break;
  90. }
  91. attr.disableVertexAttribArray = function(gl) {
  92. };
  93. }
  94. attributes.push(attr);
  95. }
  96. function bind(gl, attributes, indexBuffer) {
  97. for ( var i = 0; i < attributes.length; ++i) {
  98. var attribute = attributes[i];
  99. if (attribute.enabled) {
  100. attribute.vertexAttrib(gl);
  101. }
  102. }
  103. if (defined(indexBuffer)) {
  104. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer._getBuffer());
  105. }
  106. }
  107. /**
  108. * @private
  109. */
  110. var VertexArray = function(gl, vertexArrayObject, attributes, indexBuffer) {
  111. //>>includeStart('debug', pragmas.debug);
  112. if (!defined(attributes)) {
  113. throw new DeveloperError('attributes is required.');
  114. }
  115. //>>includeEnd('debug');
  116. var i;
  117. var vaAttributes = [];
  118. var numberOfVertices = 1; // if every attribute is backed by a single value
  119. for (i = 0; i < attributes.length; ++i) {
  120. addAttribute(vaAttributes, attributes[i], i);
  121. }
  122. for (i = 0; i < vaAttributes.length; ++i) {
  123. var attribute = vaAttributes[i];
  124. if (defined(attribute.vertexBuffer)) {
  125. // This assumes that each vertex buffer in the vertex array has the same number of vertices.
  126. var bytes = attribute.strideInBytes || (attribute.componentsPerAttribute * ComponentDatatype.getSizeInBytes(attribute.componentDatatype));
  127. numberOfVertices = attribute.vertexBuffer.sizeInBytes / bytes;
  128. break;
  129. }
  130. }
  131. // Verify all attribute names are unique
  132. var uniqueIndices = {};
  133. for ( var j = 0; j < vaAttributes.length; ++j) {
  134. var index = vaAttributes[j].index;
  135. if (uniqueIndices[index]) {
  136. throw new DeveloperError('Index ' + index + ' is used by more than one attribute.');
  137. }
  138. uniqueIndices[index] = true;
  139. }
  140. var vao;
  141. // Setup VAO if extension is supported
  142. if (defined(vertexArrayObject)) {
  143. vao = vertexArrayObject.createVertexArrayOES();
  144. vertexArrayObject.bindVertexArrayOES(vao);
  145. bind(gl, vaAttributes, indexBuffer);
  146. vertexArrayObject.bindVertexArrayOES(null);
  147. }
  148. this._numberOfVertices = numberOfVertices;
  149. this._gl = gl;
  150. this._vaoExtension = vertexArrayObject;
  151. this._vao = vao;
  152. this._attributes = vaAttributes;
  153. this._indexBuffer = indexBuffer;
  154. };
  155. defineProperties(VertexArray.prototype, {
  156. numberOfAttributes : {
  157. get : function() {
  158. return this._attributes.length;
  159. }
  160. },
  161. numberOfVertices : {
  162. get : function() {
  163. return this._numberOfVertices;
  164. }
  165. },
  166. indexBuffer : {
  167. get : function() {
  168. return this._indexBuffer;
  169. }
  170. }
  171. });
  172. /**
  173. * index is the location in the array of attributes, not the index property of an attribute.
  174. */
  175. VertexArray.prototype.getAttribute = function(index) {
  176. //>>includeStart('debug', pragmas.debug);
  177. if (!defined(index)) {
  178. throw new DeveloperError('index is required.');
  179. }
  180. //>>includeEnd('debug');
  181. return this._attributes[index];
  182. };
  183. VertexArray.prototype._bind = function() {
  184. if (defined(this._vao)) {
  185. this._vaoExtension.bindVertexArrayOES(this._vao);
  186. } else {
  187. bind(this._gl, this._attributes, this._indexBuffer);
  188. }
  189. };
  190. VertexArray.prototype._unBind = function() {
  191. if (defined(this._vao)) {
  192. this._vaoExtension.bindVertexArrayOES(null);
  193. } else {
  194. var attributes = this._attributes;
  195. var gl = this._gl;
  196. for ( var i = 0; i < attributes.length; ++i) {
  197. var attribute = attributes[i];
  198. if (attribute.enabled) {
  199. attribute.disableVertexAttribArray(gl);
  200. }
  201. }
  202. if (this._indexBuffer) {
  203. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
  204. }
  205. }
  206. };
  207. VertexArray.prototype.isDestroyed = function() {
  208. return false;
  209. };
  210. VertexArray.prototype.destroy = function() {
  211. var attributes = this._attributes;
  212. for ( var i = 0; i < attributes.length; ++i) {
  213. var vertexBuffer = attributes[i].vertexBuffer;
  214. if (defined(vertexBuffer) && !vertexBuffer.isDestroyed() && vertexBuffer.vertexArrayDestroyable) {
  215. vertexBuffer.destroy();
  216. }
  217. }
  218. var indexBuffer = this._indexBuffer;
  219. if (defined(indexBuffer) && !indexBuffer.isDestroyed() && indexBuffer.vertexArrayDestroyable) {
  220. indexBuffer.destroy();
  221. }
  222. if (defined(this._vao)) {
  223. this._vaoExtension.deleteVertexArrayOES(this._vao);
  224. }
  225. return destroyObject(this);
  226. };
  227. return VertexArray;
  228. });