You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

824 lines
25KB

  1. /*
  2. * TSDGLDataBuffer.js
  3. * Keynote HTML Player
  4. *
  5. * Created by Tungwei Cheng
  6. * Copyright (c) 2018 Apple Inc. All rights reserved.
  7. */
  8. var CHAR_MAX = 127;
  9. var UCHAR_MAX = 255;
  10. var SHRT_MAX = 32767;
  11. var USHRT_MAX = 65535;
  12. /* Boolean */
  13. var GL_FALSE = 0;
  14. var GL_TRUE = 1;
  15. /* BeginMode */
  16. var GL_POINTS = 0x0000;
  17. var GL_LINES = 0x0001;
  18. var GL_LINE_LOOP = 0x0002;
  19. var GL_LINE_STRIP = 0x0003;
  20. var GL_TRIANGLES = 0x0004;
  21. var GL_TRIANGLE_STRIP = 0x0005;
  22. var GL_TRIANGLE_FAN = 0x0006;
  23. /* DataType */
  24. var GL_BYTE = 0x1400;
  25. var GL_UNSIGNED_BYTE = 0x1401;
  26. var GL_SHORT = 0x1402;
  27. var GL_UNSIGNED_SHORT = 0x1403;
  28. var GL_INT = 0x1404;
  29. var GL_UNSIGNED_INT = 0x1405;
  30. var GL_FLOAT = 0x1406;
  31. var GL_DOUBLE = 0x140A;
  32. var GL_STREAM_DRAW = 0x88E0;
  33. var GL_STATIC_DRAW = 0x88E4;
  34. var GL_DYNAMIC_DRAW = 0x88E8;
  35. var GL_FLOAT_VEC2 = 0x8B50;
  36. var GL_FLOAT_VEC3 = 0x8B51;
  37. var GL_FLOAT_VEC4 = 0x8B52;
  38. var GL_INT_VEC2 = 0x8B53;
  39. var GL_INT_VEC3 = 0x8B54;
  40. var GL_INT_VEC4 = 0x8B55;
  41. var GL_BOOL = 0x8B56;
  42. var GL_BOOL_VEC2 = 0x8B57;
  43. var GL_BOOL_VEC3 = 0x8B58;
  44. var GL_BOOL_VEC4 = 0x8B59;
  45. var GL_FLOAT_MAT2 = 0x8B5A;
  46. var GL_FLOAT_MAT3 = 0x8B5B;
  47. var GL_FLOAT_MAT4 = 0x8B5C;
  48. var GL_SAMPLER_1D = 0x8B5D;
  49. var GL_SAMPLER_2D = 0x8B5E;
  50. var GL_SAMPLER_3D = 0x8B5F;
  51. var GL_SAMPLER_CUBE = 0x8B60;
  52. var TSDGLDataBufferDataTypeUnknown = 0;
  53. var TSDGLDataBufferDataTypeByte = GL_BYTE;
  54. var TSDGLDataBufferDataTypeUnsignedByte = GL_UNSIGNED_BYTE;
  55. var TSDGLDataBufferDataTypeShort = GL_SHORT;
  56. var TSDGLDataBufferDataTypeUnsignedShort = GL_UNSIGNED_SHORT;
  57. var TSDGLDataBufferDataTypeFloat = GL_FLOAT;
  58. function TSDGLDataBufferDataTypeAsGLEnum(dataType) {
  59. var result = 0;
  60. switch (dataType) {
  61. case TSDGLDataBufferDataTypeByte:
  62. result = GL_BYTE;
  63. break;
  64. case TSDGLDataBufferDataTypeUnsignedByte:
  65. result = GL_UNSIGNED_BYTE;
  66. break;
  67. case TSDGLDataBufferDataTypeUnsignedShort:
  68. result = GL_UNSIGNED_SHORT;
  69. break;
  70. case TSDGLDataBufferDataTypeShort:
  71. result = GL_SHORT;
  72. break;
  73. case TSDGLDataBufferDataTypeFloat:
  74. result = GL_FLOAT;
  75. break;
  76. case TSDGLDataBufferDataTypeUnknown:
  77. console.log("Unknown TSDGLdataBufferDataType!");
  78. break;
  79. }
  80. return result;
  81. }
  82. function TSDGLDataBufferDataTypeSize(dataType) {
  83. var result = 0;
  84. switch (dataType) {
  85. case GL_BYTE:
  86. result = 1;
  87. break;
  88. case GL_UNSIGNED_BYTE:
  89. result = 1;
  90. break;
  91. case GL_SHORT:
  92. result = 2;
  93. break;
  94. case GL_UNSIGNED_SHORT:
  95. result = 2;
  96. break;
  97. case GL_FLOAT:
  98. result = 4;
  99. break;
  100. default:
  101. break;
  102. }
  103. return result;
  104. }
  105. function TSDGLPoint2DByteFromPoint2D(aPoint, isNormalized) {
  106. var x = TSDGLbyteFromFloat(aPoint.x, isNormalized);
  107. var y = TSDGLbyteFromFloat(aPoint.y, isNormalized);
  108. var p = new Int8Array(2);
  109. p.set([x, y], 0);
  110. return p;
  111. }
  112. function TSDGLbyteFromFloat(aFloat, isNormalized) {
  113. if (isNormalized) {
  114. aFloat *= CHAR_MAX;
  115. }
  116. return aFloat;
  117. }
  118. function TSDGLPoint2DUnsignedByteFromPoint2D(aPoint, isNormalized) {
  119. var x = TSDGLubyteFromFloat(aPoint.x, isNormalized);
  120. var y = TSDGLubyteFromFloat(aPoint.y, isNormalized);
  121. var p = new Uint8Array(2);
  122. p.set([x, y], 0);
  123. return p;
  124. }
  125. function TSDGLubyteFromFloat(aFloat, isNormalized) {
  126. if (isNormalized) {
  127. aFloat *= UCHAR_MAX;
  128. }
  129. return aFloat;
  130. }
  131. function TSDGLPoint2DShortFromPoint2D(aPoint, isNormalized) {
  132. var x = TSDGLshortFromFloat(aPoint.x, isNormalized);
  133. var y = TSDGLshortFromFloat(aPoint.y, isNormalized);
  134. var p = new Int16Array(4);
  135. p.set([x, y], 0);
  136. return p;
  137. }
  138. function TSDGLshortFromFloat(aFloat, isNormalized) {
  139. if (isNormalized) {
  140. aFloat *= SHRT_MAX;
  141. }
  142. return aFloat;
  143. }
  144. function TSDGLPoint2DUnsignedShortFromPoint2D(aPoint, isNormalized) {
  145. var x = TSDGLushortFromFloat(aPoint.x, isNormalized);
  146. var y = TSDGLushortFromFloat(aPoint.y, isNormalized);
  147. var p = new Uint16Array(4);
  148. p.set([x, y], 0);
  149. return p;
  150. }
  151. function TSDGLushortFromFloat(aFloat, isNormalized) {
  152. if (isNormalized) {
  153. aFloat *= USHRT_MAX;
  154. }
  155. return aFloat;
  156. }
  157. function TSDGLDataBufferSetGLPoint2DWithDataType(mGLData, bufferOffset, dataType, isNormalized, aPoint2D) {
  158. switch (dataType) {
  159. case TSDGLDataBufferDataTypeByte:
  160. var value = TSDGLPoint2DByteFromPoint2D(aPoint2D, isNormalized);
  161. var typedArray = new Int8Array(mGLData);
  162. typedArray.set(value, bufferOffset);
  163. break;
  164. case TSDGLDataBufferDataTypeUnsignedByte:
  165. var value = TSDGLPoint2DUnsignedByteFromPoint2D(aPoint2D, isNormalized);
  166. var typedArray = new Uint8Array(mGLData);
  167. typedArray.set(value, bufferOffset);
  168. break;
  169. case TSDGLDataBufferDataTypeShort:
  170. var value = TSDGLPoint2DShortFromPoint2D(aPoint2D, isNormalized);
  171. var typedArray = new Int16Array(mGLData);
  172. typedArray.set(value, bufferOffset/2);
  173. break;
  174. case TSDGLDataBufferDataTypeUnsignedShort:
  175. var value = TSDGLPoint2DUnsignedShortFromPoint2D(aPoint2D, isNormalized);
  176. var typedArray = new Uint16Array(mGLData);
  177. typedArray.set(value, bufferOffset/2);
  178. break;
  179. case TSDGLDataBufferDataTypeFloat:
  180. var typedArray = new Float32Array(mGLData);
  181. typedArray.set([aPoint2D.x, aPoint2D.y], bufferOffset/4);
  182. break;
  183. case TSDGLDataBufferDataTypeUnknown:
  184. console.log("Unknown data type!");
  185. break;
  186. }
  187. }
  188. var TSDGLDataBufferAttribute = Class.create({
  189. initialize: function(name, bufferUsage, dataType, normalized, componentCount) {
  190. this.locationInShader = -1;
  191. this.bufferOffset = null;
  192. this.dataArrayBuffer = null;
  193. this.dataBuffer = null;
  194. this.initWithName(name, bufferUsage, dataType, normalized, componentCount);
  195. },
  196. initWithName: function(attributeName, bufferUsage, dataType, isNormalized, componentCount) {
  197. this.name = attributeName;
  198. this.bufferUsage = bufferUsage;
  199. this.dataType = dataType;
  200. if (this.dataType === GL_SHORT) {
  201. this.dataType = GL_FLOAT;
  202. }
  203. this.componentCount = componentCount;
  204. this.isNormalized = isNormalized;
  205. this.locationInShader = -1;
  206. }
  207. });
  208. var TSDGLDataArrayBuffer = Class.create({
  209. initialize: function(gl) {
  210. this.gl = gl;
  211. this._vertexAttributes = null;
  212. this.mVertexCount = 0;
  213. // data type size in bytes
  214. this._dataTypeSizeInBytes = 0;
  215. // GL_STATIC_DRAW, GL_STREAM_DRAW, etc
  216. this._bufferUsage = 0;
  217. this.mNeedsUpdateFirstIndex = [];
  218. this.mNeedsUpdateLastIndex = [];
  219. this.mGLData = null;
  220. // GL vertex data buffer
  221. this.mGLDataBufferHasBeenSetup = false;
  222. this.mGLDataBuffers = [];
  223. this.mAttributeOffsetsDictionary = null;
  224. this.GLDataBufferEntrySize = 0;
  225. // for double-buffering
  226. this.bufferCount = 1;
  227. this.currentBufferIndex = 0;
  228. },
  229. initWithVertexAttributes: function(attributes, vertexCount, bufferCount) {
  230. this._vertexAttributes = attributes.slice();
  231. this.mVertexCount = vertexCount;
  232. this.mAttributeOffsetsDictionary = {};
  233. // Sort the attributes into buffers by buffer usage type
  234. var bufferSizeIfFloats = 0;
  235. var bufferOffset = 0;
  236. for (var i = 0, length = this._vertexAttributes.length; i < length; i++) {
  237. var attribute = this._vertexAttributes[i];
  238. // Assign data array buffer to attribute
  239. attribute.dataArrayBuffer = this;
  240. var dataTypeSizeInBytes = TSDGLDataBufferDataTypeSize(attribute.dataType);
  241. if (this._bufferUsage === 0) {
  242. this._bufferUsage = attribute.bufferUsage;
  243. }
  244. // Assign buffer offset
  245. attribute.bufferOffset = bufferOffset;
  246. var paddedSize = attribute.componentCount * dataTypeSizeInBytes;
  247. paddedSize = (paddedSize + 3) & ~3;
  248. bufferOffset += paddedSize;
  249. bufferSizeIfFloats += attribute.componentCount * 4;
  250. }
  251. // Create the buffer data (if necessary)
  252. this.GLDataBufferEntrySize = bufferOffset;
  253. // We need to give the arraybuffer a size
  254. if (this.GLDataBufferEntrySize > 0) {
  255. this.mGLData = new ArrayBuffer(this.mVertexCount * this.GLDataBufferEntrySize);
  256. }
  257. this.bufferCount = bufferCount;
  258. this.mNeedsUpdateFirstIndex = [];
  259. this.mNeedsUpdateLastIndex = [];
  260. for (var i = 0; i < bufferCount; i++) {
  261. this.mNeedsUpdateFirstIndex[i] = -1;
  262. this.mNeedsUpdateLastIndex[i] = -1;
  263. }
  264. },
  265. p_setupGLDataBufferIfNecessary: function() {
  266. var gl = this.gl;
  267. // Sets up GL buffers
  268. if (this.mGLDataBufferHasBeenSetup) {
  269. return;
  270. }
  271. for (var i = 0; i < this.bufferCount; i++) {
  272. this.mGLDataBuffers[i] = gl.createBuffer();
  273. gl.bindBuffer(gl.ARRAY_BUFFER, this.mGLDataBuffers[i]);
  274. gl.bufferData(gl.ARRAY_BUFFER, this.mGLData, this._bufferUsage);
  275. this.mNeedsUpdateFirstIndex[i] = -1;
  276. this.mNeedsUpdateLastIndex[i] = -1;
  277. }
  278. this.mGLDataBufferHasBeenSetup = true;
  279. },
  280. updateDataBufferIfNecessary: function() {
  281. this.p_setupGLDataBufferIfNecessary();
  282. if (!this.hasUpdatedData()) {
  283. // Nothing needs to be updated!
  284. return;
  285. }
  286. if (this._bufferUsage == GL_STATIC_DRAW) {
  287. console.log("We're GL_STATIC_DRAW but trying (and FAILING) to update the array after initial setup!");
  288. return;
  289. }
  290. var gl = this.gl;
  291. // Combine all buffer's updated ranges, in case they're not the same...
  292. var firstIndex = Number.MAX_SAFE_INTEGER;
  293. var lastIndex = -1;
  294. for (var i = 0; i < this.bufferCount; i++) {
  295. var thisFirstIndex = this.mNeedsUpdateFirstIndex[i];
  296. if (thisFirstIndex !== -1) {
  297. firstIndex = Math.min(firstIndex, thisFirstIndex);
  298. }
  299. var thisLastIndex = this.mNeedsUpdateLastIndex[i];
  300. if (thisLastIndex !== -1) {
  301. lastIndex = Math.max(lastIndex, this.mNeedsUpdateLastIndex[i]);
  302. }
  303. }
  304. var offset = firstIndex;
  305. var size = lastIndex + 1 - firstIndex;
  306. offset *= this.GLDataBufferEntrySize;
  307. size *= this.GLDataBufferEntrySize;
  308. gl.bindBuffer(gl.ARRAY_BUFFER, this.mGLDataBuffers[this.currentBufferIndex]);
  309. gl.bufferSubData(gl.ARRAY_BUFFER, offset, this.mGLData);
  310. this.mNeedsUpdateFirstIndex[this.currentBufferIndex] = -1;
  311. this.mNeedsUpdateLastIndex[this.currentBufferIndex] = -1;
  312. },
  313. p_bufferOffsetOfAttribute: function(attribute, index, component) {
  314. var bufferOffset = index * this.GLDataBufferEntrySize;
  315. bufferOffset += attribute.bufferOffset;
  316. if (component !== 0) {
  317. bufferOffset += TSDGLDataBufferDataTypeSize(attribute.dataType) * component;
  318. }
  319. return bufferOffset;
  320. },
  321. setGLPoint2D: function(aPoint2D, attribute, index) {
  322. var bufferOffset = this.p_bufferOffsetOfAttribute(attribute, index, 0);
  323. TSDGLDataBufferSetGLPoint2DWithDataType(this.mGLData, bufferOffset, attribute.dataType, attribute.isNormalized, aPoint2D);
  324. this.addIndexNeedsUpdate(index);
  325. },
  326. enableVertexAttributeArrayBuffersWithShader: function(shader) {
  327. var gl = this.gl;
  328. this.updateDataBufferIfNecessary();
  329. gl.bindBuffer(gl.ARRAY_BUFFER, this.mGLDataBuffers[this.currentBufferIndex]);
  330. for (var i = 0, length = this._vertexAttributes.length; i < length; i++) {
  331. var attribute = this._vertexAttributes[i];
  332. var locationInShader = attribute.locationInShader;
  333. if (locationInShader === -1) {
  334. locationInShader = shader.locationForAttribute(attribute.name);
  335. if (locationInShader === -1) {
  336. console.log("Could not find attribute " + attribute.name + "in shader!");
  337. }
  338. attribute.locationInShader = locationInShader;
  339. }
  340. var stride = 0;
  341. if (this._vertexAttributes.length > 1) {
  342. // we're not tight-packed, so need to specify how many elements to skip when iterating
  343. stride = this.GLDataBufferEntrySize;
  344. }
  345. var dataType = TSDGLDataBufferDataTypeAsGLEnum(attribute.dataType);
  346. gl.enableVertexAttribArray(locationInShader);
  347. gl.vertexAttribPointer(locationInShader, attribute.componentCount, dataType, attribute.isNormalized ? GL_TRUE : GL_FALSE, stride, attribute.bufferOffset);
  348. }
  349. },
  350. disableVertexAttributeArrayBuffersWithShader: function(shader) {
  351. var gl = this.gl;
  352. for (var i = 0, length = this._vertexAttributes.length; i < length; i++) {
  353. var attribute = this._vertexAttributes[i];
  354. gl.disableVertexAttribArray(attribute.locationInShader);
  355. }
  356. gl.bindBuffer(gl.ARRAY_BUFFER, null);
  357. },
  358. hasUpdatedData: function() {
  359. for (var i = 0; i < this.bufferCount; i++) {
  360. if (this.mNeedsUpdateFirstIndex[i] !== -1) {
  361. return true;
  362. }
  363. }
  364. return false;
  365. },
  366. addIndexNeedsUpdate: function(index) {
  367. var currentBufferIndex = this.currentBufferIndex;
  368. var mNeedsUpdateFirstIndex = this.mNeedsUpdateFirstIndex;
  369. var mNeedsUpdateLastIndex = this.mNeedsUpdateLastIndex;
  370. mNeedsUpdateFirstIndex[currentBufferIndex] = (mNeedsUpdateFirstIndex[currentBufferIndex] == -1) ? index : Math.min(mNeedsUpdateFirstIndex[currentBufferIndex], index);
  371. mNeedsUpdateLastIndex[currentBufferIndex] = (mNeedsUpdateLastIndex[currentBufferIndex] == -1) ? index : Math.max(mNeedsUpdateLastIndex[currentBufferIndex], index);
  372. }
  373. });
  374. var TSDGLDataBuffer = Class.create({
  375. initialize: function(gl) {
  376. this.gl = gl;
  377. this.mCurrentBufferIndex = 0;
  378. this.mArrayBuffers = [];
  379. this.mAttributeToArrayBuffersDictionary = {};
  380. // Element array buffer
  381. this.mElementArrayCount = 0;
  382. this.mGLElementData = null;
  383. this.mGLElementDataBufferWasSetup = false;
  384. this.mGLElementDataBuffer = null;
  385. this.mGLElementMeshSize = {
  386. width: 0,
  387. height: 0
  388. }
  389. this.mGLElementQuadParticleCount = 0;
  390. },
  391. p_setupGLElementArrayBufferIfNecessary: function() {
  392. var gl = this.gl;
  393. if (this.mGLElementDataBufferWasSetup) {
  394. return;
  395. }
  396. if (!this.mGLElementData) {
  397. this.mGLElementDataBufferWasSetup = true;
  398. return;
  399. }
  400. var useIndexCounter = false;
  401. var indexCounter = 0;
  402. if (!CGSizeEqualToSize(this.mGLElementMeshSize, CGSizeZero)) {
  403. useIndexCounter = true;
  404. // set up grid-based element array data
  405. for (var y = 0; y < this.mGLElementMeshSize.height - 1; ++y) {
  406. for (var x = 0; x < this.mGLElementMeshSize.width; ++x) {
  407. this.setGLushort((y + 0) * this.mGLElementMeshSize.width + x, indexCounter++);
  408. this.setGLushort((y + 1) * this.mGLElementMeshSize.width + x, indexCounter++);
  409. }
  410. }
  411. } else if (this.mGLElementQuadParticleCount != 0) {
  412. useIndexCounter = true;
  413. this.drawMode = GL_TRIANGLES;
  414. // set up quad particle-based element array data
  415. for (var i = 0; i < this.mGLElementQuadParticleCount; ++i) {
  416. // First triangle
  417. this.setGLushort((4 * i + 0), indexCounter++);
  418. this.setGLushort((4 * i + 1), indexCounter++);
  419. this.setGLushort((4 * i + 2), indexCounter++);
  420. // Second triangle
  421. this.setGLushort((4 * i + 0), indexCounter++);
  422. this.setGLushort((4 * i + 2), indexCounter++);
  423. this.setGLushort((4 * i + 3), indexCounter++);
  424. }
  425. }
  426. this.mGLElementDataBuffer = gl.createBuffer();
  427. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.mGLElementDataBuffer);
  428. this.mGLElementDataBufferWasSetup = true;
  429. },
  430. newDataBufferWithVertexAttributes: function(attributes, meshSize, isDoubleBuffered) {
  431. var vertexCount = meshSize.width * meshSize.height;
  432. var indexCount = meshSize.width * 2 * (meshSize.height - 1);
  433. this.initWithVertexAttributesDesignated(attributes, vertexCount, indexCount, isDoubleBuffered);
  434. this.mGLElementMeshSize = meshSize;
  435. },
  436. initWithVertexAttributes: function(attributes, meshSize) {
  437. var vertexCount = meshSize.width * meshSize.height;
  438. var indexCount = meshSize.width * 2 * (meshSize.height - 1);
  439. this.initWithVertexAttributesDesignated(attributes, vertexCount, indexCount, false);
  440. this.mGLElementMeshSize = meshSize;
  441. },
  442. initWithVertexAttributesDesignated: function(attributes, vertexCount, indexElementCount, isDoubleBuffered) {
  443. this._doubleBuffered = isDoubleBuffered;
  444. this.drawMode = GL_TRIANGLE_STRIP;
  445. this._vertexAttributes = attributes;
  446. this._vertexCount = vertexCount;
  447. this.mArrayBuffers = [];
  448. this.mAttributeToArrayBuffersDictionary = {};
  449. var attributesToArrange = attributes.slice();
  450. while (attributesToArrange.length > 0) {
  451. var thisAttribute = attributesToArrange[0];
  452. var currentAttributes = [];
  453. for (var i = 0, length = attributesToArrange.length; i < length; i++) {
  454. var attribute = attributesToArrange[i];
  455. if (attribute.bufferUsage == thisAttribute.bufferUsage) {
  456. currentAttributes.push(attribute);
  457. }
  458. }
  459. var bufferCount = ((isDoubleBuffered && thisAttribute.bufferUsage !== GL_STATIC_DRAW) ? 2 : 1);
  460. var arrayBuffer = new TSDGLDataArrayBuffer(this.gl);
  461. arrayBuffer.initWithVertexAttributes(currentAttributes, vertexCount, bufferCount);
  462. for (var i = 0, length = currentAttributes.length; i < length; i++) {
  463. var attribute = currentAttributes[i];
  464. // this will cause circular reference
  465. attribute.dataBuffer = this;
  466. this.mAttributeToArrayBuffersDictionary[attribute.name] = arrayBuffer;
  467. }
  468. this.mArrayBuffers.push(arrayBuffer);
  469. for (var i = 0, length = currentAttributes.length; i < length; i++) {
  470. var element = currentAttributes[i];
  471. attributesToArrange.splice(attributesToArrange.indexOf(element), 1);
  472. }
  473. }
  474. if (indexElementCount > 0) {
  475. this.mElementArrayCount = indexElementCount;
  476. this.mGLElementData = new ArrayBuffer(this.mElementArrayCount * 2);
  477. }
  478. },
  479. initWithVertexRect: function(vertexRect, textureRect, meshSize, isTextureFlipped, includeCenterAttribute) {
  480. var gl = this.gl;
  481. var shouldSetupTexCoords = !CGRectEqualToRect(textureRect, CGRectZero);
  482. var quadAttributes = [];
  483. var positionAttribute = new TSDGLDataBufferAttribute("Position", GL_STATIC_DRAW, GL_FLOAT, false, 2);
  484. quadAttributes.push(positionAttribute);
  485. var texCoordAttribute;
  486. if (shouldSetupTexCoords) {
  487. var dataType = GL_SHORT;
  488. if (CGRectEqualToRect(textureRect, CGRectMake(0, 0, 1, 1)) && CGSizeEqualToSize(meshSize, CGSizeMake(2, 2))) {
  489. // If we're just passing in the unit rectangle, we can use lower precision texcoords!
  490. dataType = GL_UNSIGNED_BYTE;
  491. }
  492. texCoordAttribute = new TSDGLDataBufferAttribute("TexCoord", GL_STATIC_DRAW, dataType, true, 2);
  493. quadAttributes.push(texCoordAttribute);
  494. }
  495. var centerAttribute;
  496. if (includeCenterAttribute) {
  497. centerAttribute = new TSDGLDataBufferAttribute("Center", GL_STATIC_DRAW, GL_FLOAT, false, 2);
  498. quadAttributes.push(centerAttribute);
  499. }
  500. this.initWithVertexAttributes(quadAttributes, meshSize);
  501. var index = 0;
  502. // This is TSDGLPoint2D in native which is a struct of float type
  503. var center = TSDCenterOfRect(vertexRect);
  504. var verticesWide = parseInt(meshSize.width - 1);
  505. var verticesHigh = parseInt(meshSize.height - 1);
  506. for (var row = 0; row <= verticesHigh; ++row) {
  507. for (var col = 0; col <= verticesWide; ++col) {
  508. var point = WebGraphics.makePoint(col / verticesWide, row / verticesHigh);
  509. // This is TSDGLPoint2D in native which is a struct of float type
  510. var vertex = TSDPointFromNormalizedRect(point, vertexRect);
  511. this.setGLPoint2D(vertex, positionAttribute, index);
  512. if (shouldSetupTexCoords) {
  513. var texCoord = TSDPointFromNormalizedRect(point, textureRect);
  514. if (isTextureFlipped) {
  515. texCoord = WebGraphics.makePoint(texCoord.x, 1.0 - texCoord.y);
  516. }
  517. this.setGLPoint2D(texCoord, texCoordAttribute, index);
  518. }
  519. if (includeCenterAttribute) {
  520. this.setGLPoint2D(center, centerAttribute, index);
  521. }
  522. index++;
  523. }
  524. }
  525. },
  526. setGLPoint2D: function(aPoint2D, attribute, index) {
  527. attribute.dataArrayBuffer.setGLPoint2D(aPoint2D, attribute, index);
  528. },
  529. setGLushort: function(aShort, index) {
  530. var bufferOffset = index;
  531. var typedArray = new Uint16Array(this.mGLElementData);
  532. typedArray.set([aShort], bufferOffset);
  533. },
  534. enableElementArrayBuffer: function() {
  535. var gl = this.gl;
  536. this.p_setupGLElementArrayBufferIfNecessary();
  537. if (this.mGLElementDataBufferWasSetup) {
  538. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.mGLElementDataBuffer);
  539. }
  540. },
  541. disableElementArrayBuffer: function() {
  542. var gl = this.gl;
  543. if (this.mGLElementDataBufferWasSetup) {
  544. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
  545. }
  546. },
  547. enableDataBufferWithShader: function(shader) {
  548. // Vertex Array Object is an expension in WebGL and currently not implemented in Safari
  549. if (!shader.isActive) {
  550. shader.activate();
  551. }
  552. for (var i = 0, length = this.mArrayBuffers.length; i < length; i++) {
  553. var buffer = this.mArrayBuffers[i];
  554. buffer.enableVertexAttributeArrayBuffersWithShader(shader);
  555. }
  556. this.enableElementArrayBuffer();
  557. this._enabledShader = shader;
  558. this._isEnabled = true;
  559. },
  560. disableDataBufferWithShader: function(shader) {
  561. if (!this._isEnabled) {
  562. return;
  563. }
  564. this.disableElementArrayBuffer();
  565. for (var i = 0, length = this.mArrayBuffers.length; i < length; i++) {
  566. var buffer = this.mArrayBuffers[i];
  567. buffer.disableVertexAttributeArrayBuffersWithShader(shader);
  568. }
  569. this._enabledShader = null;
  570. this._isEnabled = false;
  571. },
  572. drawWithShader: function(shader, shouldDeactivateShader) {
  573. var gl = this.gl;
  574. var range = {
  575. location: 0,
  576. length: this.mElementArrayCount > 0 ? this.mElementArrayCount : this._vertexCount
  577. };
  578. this.enableDataBufferWithShader(shader);
  579. if (this.mGLElementDataBufferWasSetup && this.mElementArrayCount > 0) {
  580. // we need to send element data to element array buffer, e.g. [0, 2, 1, 3]
  581. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.mGLElementData, gl.STATIC_DRAW);
  582. if (!CGSizeEqualToSize(this.mGLElementMeshSize, CGSizeZero)) {
  583. // Draw mesh by rows
  584. var width = this.mGLElementMeshSize.width;
  585. for (var y = 0; y < this.mGLElementMeshSize.height - 1; ++y) {
  586. // location is vertex location, so need to multiply by two to get index location
  587. gl.drawElements(this.drawMode, width * 2, gl.UNSIGNED_SHORT, 2 * y * width * 2);
  588. }
  589. } else {
  590. // just draw everything
  591. gl.drawElements(this.drawMode, range.length, gl.UNSIGNED_SHORT, 2 * range.location);
  592. }
  593. } else {
  594. // No element data; just pass vertices straight down
  595. gl.drawArrays(this.drawMode, range.location, range.length);
  596. }
  597. this.disableDataBufferWithShader(shader);
  598. // Swap buffers
  599. if (this.isDoubleBuffered) {
  600. this.mCurrentBufferIndex = (this.mCurrentBufferIndex + 1) % 2;
  601. for (var i = 0, length = this.mArrayBuffers.length; i < length; i++) {
  602. var buffer = this.mArrayBuffers[i];
  603. if (buffer.bufferCount != 1) {
  604. buffer.currentBufferIndex = this.mCurrentBufferIndex;
  605. }
  606. }
  607. }
  608. if (shouldDeactivateShader) {
  609. shader.deactivate();
  610. }
  611. },
  612. vertexAttributeNamed: function(attributeName) {
  613. for (var attrib in this._vertexAttributes) {
  614. var attribute = this._vertexAttributes[attrib];
  615. if (attribute.name === attributeName) {
  616. return attribute;
  617. }
  618. }
  619. return null;
  620. }
  621. });