VertexArray.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  1. import Check from '../Core/Check.js';
  2. import ComponentDatatype from '../Core/ComponentDatatype.js';
  3. import defaultValue from '../Core/defaultValue.js';
  4. import defined from '../Core/defined.js';
  5. import defineProperties from '../Core/defineProperties.js';
  6. import destroyObject from '../Core/destroyObject.js';
  7. import DeveloperError from '../Core/DeveloperError.js';
  8. import Geometry from '../Core/Geometry.js';
  9. import IndexDatatype from '../Core/IndexDatatype.js';
  10. import CesiumMath from '../Core/Math.js';
  11. import RuntimeError from '../Core/RuntimeError.js';
  12. import Buffer from './Buffer.js';
  13. import BufferUsage from './BufferUsage.js';
  14. import ContextLimits from './ContextLimits.js';
  15. function addAttribute(attributes, attribute, index, context) {
  16. var hasVertexBuffer = defined(attribute.vertexBuffer);
  17. var hasValue = defined(attribute.value);
  18. var componentsPerAttribute = attribute.value ? attribute.value.length : attribute.componentsPerAttribute;
  19. //>>includeStart('debug', pragmas.debug);
  20. if (!hasVertexBuffer && !hasValue) {
  21. throw new DeveloperError('attribute must have a vertexBuffer or a value.');
  22. }
  23. if (hasVertexBuffer && hasValue) {
  24. 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.');
  25. }
  26. if ((componentsPerAttribute !== 1) &&
  27. (componentsPerAttribute !== 2) &&
  28. (componentsPerAttribute !== 3) &&
  29. (componentsPerAttribute !== 4)) {
  30. if (hasValue) {
  31. throw new DeveloperError('attribute.value.length must be in the range [1, 4].');
  32. }
  33. throw new DeveloperError('attribute.componentsPerAttribute must be in the range [1, 4].');
  34. }
  35. if (defined(attribute.componentDatatype) && !ComponentDatatype.validate(attribute.componentDatatype)) {
  36. throw new DeveloperError('attribute must have a valid componentDatatype or not specify it.');
  37. }
  38. if (defined(attribute.strideInBytes) && (attribute.strideInBytes > 255)) {
  39. // WebGL limit. Not in GL ES.
  40. throw new DeveloperError('attribute must have a strideInBytes less than or equal to 255 or not specify it.');
  41. }
  42. if (defined(attribute.instanceDivisor) && (attribute.instanceDivisor > 0) && !context.instancedArrays) {
  43. throw new DeveloperError('instanced arrays is not supported');
  44. }
  45. if (defined(attribute.instanceDivisor) && (attribute.instanceDivisor < 0)) {
  46. throw new DeveloperError('attribute must have an instanceDivisor greater than or equal to zero');
  47. }
  48. if (defined(attribute.instanceDivisor) && hasValue) {
  49. throw new DeveloperError('attribute cannot have have an instanceDivisor if it is not backed by a buffer');
  50. }
  51. if (defined(attribute.instanceDivisor) && (attribute.instanceDivisor > 0) && (attribute.index === 0)) {
  52. throw new DeveloperError('attribute zero cannot have an instanceDivisor greater than 0');
  53. }
  54. //>>includeEnd('debug');
  55. // Shallow copy the attribute; we do not want to copy the vertex buffer.
  56. var attr = {
  57. index : defaultValue(attribute.index, index),
  58. enabled : defaultValue(attribute.enabled, true),
  59. vertexBuffer : attribute.vertexBuffer,
  60. value : hasValue ? attribute.value.slice(0) : undefined,
  61. componentsPerAttribute : componentsPerAttribute,
  62. componentDatatype : defaultValue(attribute.componentDatatype, ComponentDatatype.FLOAT),
  63. normalize : defaultValue(attribute.normalize, false),
  64. offsetInBytes : defaultValue(attribute.offsetInBytes, 0),
  65. strideInBytes : defaultValue(attribute.strideInBytes, 0),
  66. instanceDivisor : defaultValue(attribute.instanceDivisor, 0)
  67. };
  68. if (hasVertexBuffer) {
  69. // Common case: vertex buffer for per-vertex data
  70. attr.vertexAttrib = function(gl) {
  71. var index = this.index;
  72. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer._getBuffer());
  73. gl.vertexAttribPointer(index, this.componentsPerAttribute, this.componentDatatype, this.normalize, this.strideInBytes, this.offsetInBytes);
  74. gl.enableVertexAttribArray(index);
  75. if (this.instanceDivisor > 0) {
  76. context.glVertexAttribDivisor(index, this.instanceDivisor);
  77. context._vertexAttribDivisors[index] = this.instanceDivisor;
  78. context._previousDrawInstanced = true;
  79. }
  80. };
  81. attr.disableVertexAttribArray = function(gl) {
  82. gl.disableVertexAttribArray(this.index);
  83. if (this.instanceDivisor > 0) {
  84. context.glVertexAttribDivisor(index, 0);
  85. }
  86. };
  87. } else {
  88. // Less common case: value array for the same data for each vertex
  89. switch (attr.componentsPerAttribute) {
  90. case 1:
  91. attr.vertexAttrib = function(gl) {
  92. gl.vertexAttrib1fv(this.index, this.value);
  93. };
  94. break;
  95. case 2:
  96. attr.vertexAttrib = function(gl) {
  97. gl.vertexAttrib2fv(this.index, this.value);
  98. };
  99. break;
  100. case 3:
  101. attr.vertexAttrib = function(gl) {
  102. gl.vertexAttrib3fv(this.index, this.value);
  103. };
  104. break;
  105. case 4:
  106. attr.vertexAttrib = function(gl) {
  107. gl.vertexAttrib4fv(this.index, this.value);
  108. };
  109. break;
  110. }
  111. attr.disableVertexAttribArray = function(gl) {
  112. };
  113. }
  114. attributes.push(attr);
  115. }
  116. function bind(gl, attributes, indexBuffer) {
  117. for ( var i = 0; i < attributes.length; ++i) {
  118. var attribute = attributes[i];
  119. if (attribute.enabled) {
  120. attribute.vertexAttrib(gl);
  121. }
  122. }
  123. if (defined(indexBuffer)) {
  124. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer._getBuffer());
  125. }
  126. }
  127. /**
  128. * Creates a vertex array, which defines the attributes making up a vertex, and contains an optional index buffer
  129. * to select vertices for rendering. Attributes are defined using object literals as shown in Example 1 below.
  130. *
  131. * @param {Object} options Object with the following properties:
  132. * @param {Context} options.context The context in which the VertexArray gets created.
  133. * @param {Object[]} options.attributes An array of attributes.
  134. * @param {IndexBuffer} [options.indexBuffer] An optional index buffer.
  135. *
  136. * @returns {VertexArray} The vertex array, ready for use with drawing.
  137. *
  138. * @exception {DeveloperError} Attribute must have a <code>vertexBuffer</code>.
  139. * @exception {DeveloperError} Attribute must have a <code>componentsPerAttribute</code>.
  140. * @exception {DeveloperError} Attribute must have a valid <code>componentDatatype</code> or not specify it.
  141. * @exception {DeveloperError} Attribute must have a <code>strideInBytes</code> less than or equal to 255 or not specify it.
  142. * @exception {DeveloperError} Index n is used by more than one attribute.
  143. *
  144. *
  145. * @example
  146. * // Example 1. Create a vertex array with vertices made up of three floating point
  147. * // values, e.g., a position, from a single vertex buffer. No index buffer is used.
  148. * var positionBuffer = Buffer.createVertexBuffer({
  149. * context : context,
  150. * sizeInBytes : 12,
  151. * usage : BufferUsage.STATIC_DRAW
  152. * });
  153. * var attributes = [
  154. * {
  155. * index : 0,
  156. * enabled : true,
  157. * vertexBuffer : positionBuffer,
  158. * componentsPerAttribute : 3,
  159. * componentDatatype : ComponentDatatype.FLOAT,
  160. * normalize : false,
  161. * offsetInBytes : 0,
  162. * strideInBytes : 0 // tightly packed
  163. * instanceDivisor : 0 // not instanced
  164. * }
  165. * ];
  166. * var va = new VertexArray({
  167. * context : context,
  168. * attributes : attributes
  169. * });
  170. *
  171. * @example
  172. * // Example 2. Create a vertex array with vertices from two different vertex buffers.
  173. * // Each vertex has a three-component position and three-component normal.
  174. * var positionBuffer = Buffer.createVertexBuffer({
  175. * context : context,
  176. * sizeInBytes : 12,
  177. * usage : BufferUsage.STATIC_DRAW
  178. * });
  179. * var normalBuffer = Buffer.createVertexBuffer({
  180. * context : context,
  181. * sizeInBytes : 12,
  182. * usage : BufferUsage.STATIC_DRAW
  183. * });
  184. * var attributes = [
  185. * {
  186. * index : 0,
  187. * vertexBuffer : positionBuffer,
  188. * componentsPerAttribute : 3,
  189. * componentDatatype : ComponentDatatype.FLOAT
  190. * },
  191. * {
  192. * index : 1,
  193. * vertexBuffer : normalBuffer,
  194. * componentsPerAttribute : 3,
  195. * componentDatatype : ComponentDatatype.FLOAT
  196. * }
  197. * ];
  198. * var va = new VertexArray({
  199. * context : context,
  200. * attributes : attributes
  201. * });
  202. *
  203. * @example
  204. * // Example 3. Creates the same vertex layout as Example 2 using a single
  205. * // vertex buffer, instead of two.
  206. * var buffer = Buffer.createVertexBuffer({
  207. * context : context,
  208. * sizeInBytes : 24,
  209. * usage : BufferUsage.STATIC_DRAW
  210. * });
  211. * var attributes = [
  212. * {
  213. * vertexBuffer : buffer,
  214. * componentsPerAttribute : 3,
  215. * componentDatatype : ComponentDatatype.FLOAT,
  216. * offsetInBytes : 0,
  217. * strideInBytes : 24
  218. * },
  219. * {
  220. * vertexBuffer : buffer,
  221. * componentsPerAttribute : 3,
  222. * componentDatatype : ComponentDatatype.FLOAT,
  223. * normalize : true,
  224. * offsetInBytes : 12,
  225. * strideInBytes : 24
  226. * }
  227. * ];
  228. * var va = new VertexArray({
  229. * context : context,
  230. * attributes : attributes
  231. * });
  232. *
  233. * @see Buffer#createVertexBuffer
  234. * @see Buffer#createIndexBuffer
  235. * @see Context#draw
  236. *
  237. * @private
  238. */
  239. function VertexArray(options) {
  240. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  241. //>>includeStart('debug', pragmas.debug);
  242. Check.defined('options.context', options.context);
  243. Check.defined('options.attributes', options.attributes);
  244. //>>includeEnd('debug');
  245. var context = options.context;
  246. var gl = context._gl;
  247. var attributes = options.attributes;
  248. var indexBuffer = options.indexBuffer;
  249. var i;
  250. var vaAttributes = [];
  251. var numberOfVertices = 1; // if every attribute is backed by a single value
  252. var hasInstancedAttributes = false;
  253. var hasConstantAttributes = false;
  254. var length = attributes.length;
  255. for (i = 0; i < length; ++i) {
  256. addAttribute(vaAttributes, attributes[i], i, context);
  257. }
  258. length = vaAttributes.length;
  259. for (i = 0; i < length; ++i) {
  260. var attribute = vaAttributes[i];
  261. if (defined(attribute.vertexBuffer) && (attribute.instanceDivisor === 0)) {
  262. // This assumes that each vertex buffer in the vertex array has the same number of vertices.
  263. var bytes = attribute.strideInBytes || (attribute.componentsPerAttribute * ComponentDatatype.getSizeInBytes(attribute.componentDatatype));
  264. numberOfVertices = attribute.vertexBuffer.sizeInBytes / bytes;
  265. break;
  266. }
  267. }
  268. for (i = 0; i < length; ++i) {
  269. if (vaAttributes[i].instanceDivisor > 0) {
  270. hasInstancedAttributes = true;
  271. }
  272. if (defined(vaAttributes[i].value)) {
  273. hasConstantAttributes = true;
  274. }
  275. }
  276. //>>includeStart('debug', pragmas.debug);
  277. // Verify all attribute names are unique
  278. var uniqueIndices = {};
  279. for (i = 0; i < length; ++i) {
  280. var index = vaAttributes[i].index;
  281. if (uniqueIndices[index]) {
  282. throw new DeveloperError('Index ' + index + ' is used by more than one attribute.');
  283. }
  284. uniqueIndices[index] = true;
  285. }
  286. //>>includeEnd('debug');
  287. var vao;
  288. // Setup VAO if supported
  289. if (context.vertexArrayObject) {
  290. vao = context.glCreateVertexArray();
  291. context.glBindVertexArray(vao);
  292. bind(gl, vaAttributes, indexBuffer);
  293. context.glBindVertexArray(null);
  294. }
  295. this._numberOfVertices = numberOfVertices;
  296. this._hasInstancedAttributes = hasInstancedAttributes;
  297. this._hasConstantAttributes = hasConstantAttributes;
  298. this._context = context;
  299. this._gl = gl;
  300. this._vao = vao;
  301. this._attributes = vaAttributes;
  302. this._indexBuffer = indexBuffer;
  303. }
  304. function computeNumberOfVertices(attribute) {
  305. return attribute.values.length / attribute.componentsPerAttribute;
  306. }
  307. function computeAttributeSizeInBytes(attribute) {
  308. return ComponentDatatype.getSizeInBytes(attribute.componentDatatype) * attribute.componentsPerAttribute;
  309. }
  310. function interleaveAttributes(attributes) {
  311. var j;
  312. var name;
  313. var attribute;
  314. // Extract attribute names.
  315. var names = [];
  316. for (name in attributes) {
  317. // Attribute needs to have per-vertex values; not a constant value for all vertices.
  318. if (attributes.hasOwnProperty(name) &&
  319. defined(attributes[name]) &&
  320. defined(attributes[name].values)) {
  321. names.push(name);
  322. if (attributes[name].componentDatatype === ComponentDatatype.DOUBLE) {
  323. attributes[name].componentDatatype = ComponentDatatype.FLOAT;
  324. attributes[name].values = ComponentDatatype.createTypedArray(ComponentDatatype.FLOAT, attributes[name].values);
  325. }
  326. }
  327. }
  328. // Validation. Compute number of vertices.
  329. var numberOfVertices;
  330. var namesLength = names.length;
  331. if (namesLength > 0) {
  332. numberOfVertices = computeNumberOfVertices(attributes[names[0]]);
  333. for (j = 1; j < namesLength; ++j) {
  334. var currentNumberOfVertices = computeNumberOfVertices(attributes[names[j]]);
  335. if (currentNumberOfVertices !== numberOfVertices) {
  336. throw new RuntimeError(
  337. 'Each attribute list must have the same number of vertices. ' +
  338. 'Attribute ' + names[j] + ' has a different number of vertices ' +
  339. '(' + currentNumberOfVertices.toString() + ')' +
  340. ' than attribute ' + names[0] +
  341. ' (' + numberOfVertices.toString() + ').');
  342. }
  343. }
  344. }
  345. // Sort attributes by the size of their components. From left to right, a vertex stores floats, shorts, and then bytes.
  346. names.sort(function(left, right) {
  347. return ComponentDatatype.getSizeInBytes(attributes[right].componentDatatype) - ComponentDatatype.getSizeInBytes(attributes[left].componentDatatype);
  348. });
  349. // Compute sizes and strides.
  350. var vertexSizeInBytes = 0;
  351. var offsetsInBytes = {};
  352. for (j = 0; j < namesLength; ++j) {
  353. name = names[j];
  354. attribute = attributes[name];
  355. offsetsInBytes[name] = vertexSizeInBytes;
  356. vertexSizeInBytes += computeAttributeSizeInBytes(attribute);
  357. }
  358. if (vertexSizeInBytes > 0) {
  359. // Pad each vertex to be a multiple of the largest component datatype so each
  360. // attribute can be addressed using typed arrays.
  361. var maxComponentSizeInBytes = ComponentDatatype.getSizeInBytes(attributes[names[0]].componentDatatype); // Sorted large to small
  362. var remainder = vertexSizeInBytes % maxComponentSizeInBytes;
  363. if (remainder !== 0) {
  364. vertexSizeInBytes += (maxComponentSizeInBytes - remainder);
  365. }
  366. // Total vertex buffer size in bytes, including per-vertex padding.
  367. var vertexBufferSizeInBytes = numberOfVertices * vertexSizeInBytes;
  368. // Create array for interleaved vertices. Each attribute has a different view (pointer) into the array.
  369. var buffer = new ArrayBuffer(vertexBufferSizeInBytes);
  370. var views = {};
  371. for (j = 0; j < namesLength; ++j) {
  372. name = names[j];
  373. var sizeInBytes = ComponentDatatype.getSizeInBytes(attributes[name].componentDatatype);
  374. views[name] = {
  375. pointer : ComponentDatatype.createTypedArray(attributes[name].componentDatatype, buffer),
  376. index : offsetsInBytes[name] / sizeInBytes, // Offset in ComponentType
  377. strideInComponentType : vertexSizeInBytes / sizeInBytes
  378. };
  379. }
  380. // Copy attributes into one interleaved array.
  381. // PERFORMANCE_IDEA: Can we optimize these loops?
  382. for (j = 0; j < numberOfVertices; ++j) {
  383. for ( var n = 0; n < namesLength; ++n) {
  384. name = names[n];
  385. attribute = attributes[name];
  386. var values = attribute.values;
  387. var view = views[name];
  388. var pointer = view.pointer;
  389. var numberOfComponents = attribute.componentsPerAttribute;
  390. for ( var k = 0; k < numberOfComponents; ++k) {
  391. pointer[view.index + k] = values[(j * numberOfComponents) + k];
  392. }
  393. view.index += view.strideInComponentType;
  394. }
  395. }
  396. return {
  397. buffer : buffer,
  398. offsetsInBytes : offsetsInBytes,
  399. vertexSizeInBytes : vertexSizeInBytes
  400. };
  401. }
  402. // No attributes to interleave.
  403. return undefined;
  404. }
  405. /**
  406. * Creates a vertex array from a geometry. A geometry contains vertex attributes and optional index data
  407. * in system memory, whereas a vertex array contains vertex buffers and an optional index buffer in WebGL
  408. * memory for use with rendering.
  409. * <br /><br />
  410. * The <code>geometry</code> argument should use the standard layout like the geometry returned by {@link BoxGeometry}.
  411. * <br /><br />
  412. * <code>options</code> can have four properties:
  413. * <ul>
  414. * <li><code>geometry</code>: The source geometry containing data used to create the vertex array.</li>
  415. * <li><code>attributeLocations</code>: An object that maps geometry attribute names to vertex shader attribute locations.</li>
  416. * <li><code>bufferUsage</code>: The expected usage pattern of the vertex array's buffers. On some WebGL implementations, this can significantly affect performance. See {@link BufferUsage}. Default: <code>BufferUsage.DYNAMIC_DRAW</code>.</li>
  417. * <li><code>interleave</code>: Determines if all attributes are interleaved in a single vertex buffer or if each attribute is stored in a separate vertex buffer. Default: <code>false</code>.</li>
  418. * </ul>
  419. * <br />
  420. * If <code>options</code> is not specified or the <code>geometry</code> contains no data, the returned vertex array is empty.
  421. *
  422. * @param {Object} options An object defining the geometry, attribute indices, buffer usage, and vertex layout used to create the vertex array.
  423. *
  424. * @exception {RuntimeError} Each attribute list must have the same number of vertices.
  425. * @exception {DeveloperError} The geometry must have zero or one index lists.
  426. * @exception {DeveloperError} Index n is used by more than one attribute.
  427. *
  428. *
  429. * @example
  430. * // Example 1. Creates a vertex array for rendering a box. The default dynamic draw
  431. * // usage is used for the created vertex and index buffer. The attributes are not
  432. * // interleaved by default.
  433. * var geometry = new BoxGeometry();
  434. * var va = VertexArray.fromGeometry({
  435. * context : context,
  436. * geometry : geometry,
  437. * attributeLocations : GeometryPipeline.createAttributeLocations(geometry),
  438. * });
  439. *
  440. * @example
  441. * // Example 2. Creates a vertex array with interleaved attributes in a
  442. * // single vertex buffer. The vertex and index buffer have static draw usage.
  443. * var va = VertexArray.fromGeometry({
  444. * context : context,
  445. * geometry : geometry,
  446. * attributeLocations : GeometryPipeline.createAttributeLocations(geometry),
  447. * bufferUsage : BufferUsage.STATIC_DRAW,
  448. * interleave : true
  449. * });
  450. *
  451. * @example
  452. * // Example 3. When the caller destroys the vertex array, it also destroys the
  453. * // attached vertex buffer(s) and index buffer.
  454. * va = va.destroy();
  455. *
  456. * @see Buffer#createVertexBuffer
  457. * @see Buffer#createIndexBuffer
  458. * @see GeometryPipeline.createAttributeLocations
  459. * @see ShaderProgram
  460. */
  461. VertexArray.fromGeometry = function(options) {
  462. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  463. //>>includeStart('debug', pragmas.debug);
  464. Check.defined('options.context', options.context);
  465. //>>includeEnd('debug');
  466. var context = options.context;
  467. var geometry = defaultValue(options.geometry, defaultValue.EMPTY_OBJECT);
  468. var bufferUsage = defaultValue(options.bufferUsage, BufferUsage.DYNAMIC_DRAW);
  469. var attributeLocations = defaultValue(options.attributeLocations, defaultValue.EMPTY_OBJECT);
  470. var interleave = defaultValue(options.interleave, false);
  471. var createdVAAttributes = options.vertexArrayAttributes;
  472. var name;
  473. var attribute;
  474. var vertexBuffer;
  475. var vaAttributes = (defined(createdVAAttributes)) ? createdVAAttributes : [];
  476. var attributes = geometry.attributes;
  477. if (interleave) {
  478. // Use a single vertex buffer with interleaved vertices.
  479. var interleavedAttributes = interleaveAttributes(attributes);
  480. if (defined(interleavedAttributes)) {
  481. vertexBuffer = Buffer.createVertexBuffer({
  482. context : context,
  483. typedArray : interleavedAttributes.buffer,
  484. usage : bufferUsage
  485. });
  486. var offsetsInBytes = interleavedAttributes.offsetsInBytes;
  487. var strideInBytes = interleavedAttributes.vertexSizeInBytes;
  488. for (name in attributes) {
  489. if (attributes.hasOwnProperty(name) && defined(attributes[name])) {
  490. attribute = attributes[name];
  491. if (defined(attribute.values)) {
  492. // Common case: per-vertex attributes
  493. vaAttributes.push({
  494. index : attributeLocations[name],
  495. vertexBuffer : vertexBuffer,
  496. componentDatatype : attribute.componentDatatype,
  497. componentsPerAttribute : attribute.componentsPerAttribute,
  498. normalize : attribute.normalize,
  499. offsetInBytes : offsetsInBytes[name],
  500. strideInBytes : strideInBytes
  501. });
  502. } else {
  503. // Constant attribute for all vertices
  504. vaAttributes.push({
  505. index : attributeLocations[name],
  506. value : attribute.value,
  507. componentDatatype : attribute.componentDatatype,
  508. normalize : attribute.normalize
  509. });
  510. }
  511. }
  512. }
  513. }
  514. } else {
  515. // One vertex buffer per attribute.
  516. for (name in attributes) {
  517. if (attributes.hasOwnProperty(name) && defined(attributes[name])) {
  518. attribute = attributes[name];
  519. var componentDatatype = attribute.componentDatatype;
  520. if (componentDatatype === ComponentDatatype.DOUBLE) {
  521. componentDatatype = ComponentDatatype.FLOAT;
  522. }
  523. vertexBuffer = undefined;
  524. if (defined(attribute.values)) {
  525. vertexBuffer = Buffer.createVertexBuffer({
  526. context : context,
  527. typedArray : ComponentDatatype.createTypedArray(componentDatatype, attribute.values),
  528. usage : bufferUsage
  529. });
  530. }
  531. vaAttributes.push({
  532. index : attributeLocations[name],
  533. vertexBuffer : vertexBuffer,
  534. value : attribute.value,
  535. componentDatatype : componentDatatype,
  536. componentsPerAttribute : attribute.componentsPerAttribute,
  537. normalize : attribute.normalize
  538. });
  539. }
  540. }
  541. }
  542. var indexBuffer;
  543. var indices = geometry.indices;
  544. if (defined(indices)) {
  545. if ((Geometry.computeNumberOfVertices(geometry) >= CesiumMath.SIXTY_FOUR_KILOBYTES) && context.elementIndexUint) {
  546. indexBuffer = Buffer.createIndexBuffer({
  547. context : context,
  548. typedArray : new Uint32Array(indices),
  549. usage : bufferUsage,
  550. indexDatatype : IndexDatatype.UNSIGNED_INT
  551. });
  552. } else{
  553. indexBuffer = Buffer.createIndexBuffer({
  554. context : context,
  555. typedArray : new Uint16Array(indices),
  556. usage : bufferUsage,
  557. indexDatatype : IndexDatatype.UNSIGNED_SHORT
  558. });
  559. }
  560. }
  561. return new VertexArray({
  562. context : context,
  563. attributes : vaAttributes,
  564. indexBuffer : indexBuffer
  565. });
  566. };
  567. defineProperties(VertexArray.prototype, {
  568. numberOfAttributes : {
  569. get : function() {
  570. return this._attributes.length;
  571. }
  572. },
  573. numberOfVertices : {
  574. get : function() {
  575. return this._numberOfVertices;
  576. }
  577. },
  578. indexBuffer : {
  579. get : function() {
  580. return this._indexBuffer;
  581. }
  582. }
  583. });
  584. /**
  585. * index is the location in the array of attributes, not the index property of an attribute.
  586. */
  587. VertexArray.prototype.getAttribute = function(index) {
  588. //>>includeStart('debug', pragmas.debug);
  589. Check.defined('index', index);
  590. //>>includeEnd('debug');
  591. return this._attributes[index];
  592. };
  593. // Workaround for ANGLE, where the attribute divisor seems to be part of the global state instead
  594. // of the VAO state. This function is called when the vao is bound, and should be removed
  595. // once the ANGLE issue is resolved. Setting the divisor should normally happen in vertexAttrib and
  596. // disableVertexAttribArray.
  597. function setVertexAttribDivisor(vertexArray) {
  598. var context = vertexArray._context;
  599. var hasInstancedAttributes = vertexArray._hasInstancedAttributes;
  600. if (!hasInstancedAttributes && !context._previousDrawInstanced) {
  601. return;
  602. }
  603. context._previousDrawInstanced = hasInstancedAttributes;
  604. var divisors = context._vertexAttribDivisors;
  605. var attributes = vertexArray._attributes;
  606. var maxAttributes = ContextLimits.maximumVertexAttributes;
  607. var i;
  608. if (hasInstancedAttributes) {
  609. var length = attributes.length;
  610. for (i = 0; i < length; ++i) {
  611. var attribute = attributes[i];
  612. if (attribute.enabled) {
  613. var divisor = attribute.instanceDivisor;
  614. var index = attribute.index;
  615. if (divisor !== divisors[index]) {
  616. context.glVertexAttribDivisor(index, divisor);
  617. divisors[index] = divisor;
  618. }
  619. }
  620. }
  621. } else {
  622. for (i = 0; i < maxAttributes; ++i) {
  623. if (divisors[i] > 0) {
  624. context.glVertexAttribDivisor(i, 0);
  625. divisors[i] = 0;
  626. }
  627. }
  628. }
  629. }
  630. // Vertex attributes backed by a constant value go through vertexAttrib[1234]f[v]
  631. // which is part of context state rather than VAO state.
  632. function setConstantAttributes(vertexArray, gl) {
  633. var attributes = vertexArray._attributes;
  634. var length = attributes.length;
  635. for (var i = 0; i < length; ++i) {
  636. var attribute = attributes[i];
  637. if (attribute.enabled && defined(attribute.value)) {
  638. attribute.vertexAttrib(gl);
  639. }
  640. }
  641. }
  642. VertexArray.prototype._bind = function() {
  643. if (defined(this._vao)) {
  644. this._context.glBindVertexArray(this._vao);
  645. if (this._context.instancedArrays) {
  646. setVertexAttribDivisor(this);
  647. }
  648. if (this._hasConstantAttributes) {
  649. setConstantAttributes(this, this._gl);
  650. }
  651. } else {
  652. bind(this._gl, this._attributes, this._indexBuffer);
  653. }
  654. };
  655. VertexArray.prototype._unBind = function() {
  656. if (defined(this._vao)) {
  657. this._context.glBindVertexArray(null);
  658. } else {
  659. var attributes = this._attributes;
  660. var gl = this._gl;
  661. for ( var i = 0; i < attributes.length; ++i) {
  662. var attribute = attributes[i];
  663. if (attribute.enabled) {
  664. attribute.disableVertexAttribArray(gl);
  665. }
  666. }
  667. if (this._indexBuffer) {
  668. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
  669. }
  670. }
  671. };
  672. VertexArray.prototype.isDestroyed = function() {
  673. return false;
  674. };
  675. VertexArray.prototype.destroy = function() {
  676. var attributes = this._attributes;
  677. for ( var i = 0; i < attributes.length; ++i) {
  678. var vertexBuffer = attributes[i].vertexBuffer;
  679. if (defined(vertexBuffer) && !vertexBuffer.isDestroyed() && vertexBuffer.vertexArrayDestroyable) {
  680. vertexBuffer.destroy();
  681. }
  682. }
  683. var indexBuffer = this._indexBuffer;
  684. if (defined(indexBuffer) && !indexBuffer.isDestroyed() && indexBuffer.vertexArrayDestroyable) {
  685. indexBuffer.destroy();
  686. }
  687. if (defined(this._vao)) {
  688. this._context.glDeleteVertexArray(this._vao);
  689. }
  690. return destroyObject(this);
  691. };
  692. export default VertexArray;