Home Reference Source

cables_dev/cables/src/core/cgl/cgl_mesh.js

  1. import { Logger } from "cables-shared-client";
  2. import { Uniform } from "./cgl_shader_uniform.js";
  3. import { CONSTANTS } from "./constants.js";
  4.  
  5. const MESH = {};
  6. MESH.lastMesh = null;
  7.  
  8. /**
  9. * webgl renderable 3d object
  10. * @class
  11. * @namespace external:CGL
  12. * @hideconstructor
  13. * @param {Context} _cgl cgl
  14. * @param {Geometry} __geom geometry
  15. * @param {Number} _options glPrimitive
  16. * @example
  17. * const cgl=this._cgl
  18. * const mesh=new CGL.Mesh(cgl, geometry);
  19. *
  20. * function render()
  21. * {
  22. * mesh.render(cgl.getShader());
  23. * }
  24. */
  25. const Mesh = function (_cgl, __geom, _options)
  26. {
  27. this._cgl = _cgl;
  28.  
  29. let options = _options || {};
  30. if (CABLES.UTILS.isNumeric(options))options = { "glPrimitive": _options }; // old constructor fallback...
  31. this._log = new Logger("cgl_mesh");
  32. this._bufVertexAttrib = null;
  33. this._bufVerticesIndizes = this._cgl.gl.createBuffer();
  34. this._indexType = this._cgl.gl.UNSIGNED_SHORT;
  35. this._attributes = [];
  36. this._attribLocs = {};
  37. this._geom = null;
  38. this._lastShader = null;
  39. this._numInstances = 0;
  40. this._glPrimitive = options.glPrimitive;
  41.  
  42. this.opId = options.opId || "";
  43. this._preWireframeGeom = null;
  44. this.addVertexNumbers = false;
  45. this._name = "unknown";
  46.  
  47. this.feedBackAttributes = [];
  48. this.setGeom(__geom);
  49.  
  50. this._feedBacks = [];
  51. this._feedBacksChanged = false;
  52. this._transformFeedBackLoc = -1;
  53. this._lastAttrUpdate = 0;
  54.  
  55. this.memFreed = false;
  56.  
  57. this._cgl.profileData.addHeavyEvent("mesh constructed", this._name);
  58.  
  59. this._queryExt = null;
  60.  
  61. Object.defineProperty(this, "numInstances", {
  62. get()
  63. {
  64. return this._numInstances;
  65. },
  66. set(v)
  67. {
  68. this.setNumInstances(v);
  69. },
  70. });
  71. };
  72.  
  73. Mesh.prototype.freeMem = function ()
  74. {
  75. this.memFreed = true;
  76.  
  77. for (let i = 0; i < this._attributes.length; i++)
  78. {
  79. this._attributes[i].floatArray = null;
  80. }
  81. };
  82.  
  83. /**
  84. * @function updateVertices
  85. * @memberof Mesh
  86. * @instance
  87. * @description update vertices only from a geometry
  88. * @param {Geometry} geom
  89. */
  90. Mesh.prototype.updateVertices = function (geom)
  91. {
  92. this.setAttribute(CONSTANTS.SHADER.SHADERVAR_VERTEX_POSITION, geom.vertices, 3);
  93. this._numVerts = geom.vertices.length / 3;
  94. };
  95.  
  96. Mesh.prototype.setAttributePointer = function (attrName, name, stride, offset)
  97. {
  98. for (let i = 0; i < this._attributes.length; i++)
  99. {
  100. if (this._attributes[i].name == attrName)
  101. {
  102. if (!this._attributes[i].pointer) this._attributes[i].pointer = [];
  103.  
  104. this._attributes[i].pointer.push(
  105. {
  106. "loc": -1,
  107. "name": name,
  108. "stride": stride,
  109. "offset": offset,
  110. "instanced": attrName == CONSTANTS.SHADER.SHADERVAR_INSTANCE_MMATRIX,
  111. }
  112. );
  113. }
  114. }
  115. };
  116.  
  117. Mesh.prototype.getAttribute = function (name)
  118. {
  119. for (let i = 0; i < this._attributes.length; i++) if (this._attributes[i].name == name) return this._attributes[i];
  120. };
  121.  
  122. Mesh.prototype.setAttributeRange = function (attr, array, start, end)
  123. {
  124. if (!attr) return;
  125. if (!start && !end) return;
  126.  
  127. if (!attr.name)
  128. {
  129. this._log.stack("no attrname?!");
  130. }
  131.  
  132. this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER, attr.buffer);
  133. this._cgl.profileData.profileMeshAttributes += (end - start) || 0;
  134.  
  135. this._cgl.profileData.profileSingleMeshAttribute[this._name] = this._cgl.profileData.profileSingleMeshAttribute[this._name] || 0;
  136. this._cgl.profileData.profileSingleMeshAttribute[this._name] += (end - start) || 0;
  137.  
  138. if (attr.numItems < array.length / attr.itemSize)
  139. {
  140. this._resizeAttr(array, attr);
  141. }
  142.  
  143. if (end > array.length)
  144. {
  145. if (CABLES.platform.isDevEnv())
  146. this._log.log(this._cgl.canvas.id + " " + attr.name + " buffersubdata out of bounds ?", array.length, end, start, attr);
  147. // end = array.length - 1;
  148. return;
  149. }
  150.  
  151. if (this._cgl.glVersion == 1) this._cgl.gl.bufferSubData(this._cgl.gl.ARRAY_BUFFER, 0, array); // probably slow/ maybe create and array with only changed size ??
  152. else this._cgl.gl.bufferSubData(this._cgl.gl.ARRAY_BUFFER, start * 4, array, start, (end - start));
  153. };
  154.  
  155. Mesh.prototype._resizeAttr = function (array, attr)
  156. {
  157. if (attr.buffer)
  158. this._cgl.gl.deleteBuffer(attr.buffer);
  159.  
  160. attr.buffer = this._cgl.gl.createBuffer();
  161. this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER, attr.buffer);
  162. this._bufferArray(array, attr);
  163. attr.numItems = array.length / attr.itemSize;// numItems;
  164. };
  165.  
  166.  
  167. Mesh.prototype._bufferArray = function (array, attr)
  168. {
  169. let floatArray = attr.floatArray || null;
  170. if (!array) return;
  171.  
  172.  
  173. if (this._cgl.debugOneFrame)
  174. {
  175. console.log("_bufferArray", array.length, attr.name); // eslint-disable-line
  176. }
  177.  
  178. if (!(array instanceof Float32Array))
  179. {
  180. if (attr && floatArray && floatArray.length == array.length)
  181. {
  182. floatArray.set(array);
  183. // floatArray = floatArray;
  184. }
  185. else
  186. {
  187. floatArray = new Float32Array(array);
  188.  
  189. if (this._cgl.debugOneFrame)
  190. {
  191. console.log("_bufferArray create new float32array", array.length, attr.name); // eslint-disable-line
  192. }
  193.  
  194. if (array.length > 10000)
  195. {
  196. this._cgl.profileData.profileNonTypedAttrib++;
  197. this._cgl.profileData.profileNonTypedAttribNames = "(" + this._name + ":" + attr.name + ")";
  198. }
  199. }
  200. }
  201. else floatArray = array;
  202.  
  203. attr.arrayLength = floatArray.length;
  204. attr.floatArray = null;// floatArray;
  205.  
  206. this._cgl.gl.bufferData(this._cgl.gl.ARRAY_BUFFER, floatArray, this._cgl.gl.DYNAMIC_DRAW);
  207. };
  208.  
  209. /**
  210. * @function setAttribute
  211. * @description update attribute
  212. * @memberof Mesh
  213. * @instance
  214. * @param {String} attribute name
  215. * @param {Array} data
  216. * @param {Number} itemSize
  217. * @param {Object} options
  218. */
  219. Mesh.prototype.addAttribute = Mesh.prototype.updateAttribute = Mesh.prototype.setAttribute = function (name, array, itemSize, options)
  220. {
  221. if (!array)
  222. {
  223. this._log.error("mesh addAttribute - no array given! " + name);
  224. throw new Error();
  225. }
  226. let cb = null;
  227. let instanced = false;
  228. let i = 0;
  229. const numItems = array.length / itemSize;
  230.  
  231. this._cgl.profileData.profileMeshAttributes += numItems || 0;
  232.  
  233. if (typeof options == "function")
  234. {
  235. cb = options;
  236. }
  237.  
  238. if (typeof options == "object")
  239. {
  240. if (options.cb) cb = options.cb;
  241. if (options.instanced) instanced = options.instanced;
  242. }
  243.  
  244. if (name == CONSTANTS.SHADER.SHADERVAR_INSTANCE_MMATRIX) instanced = true;
  245.  
  246.  
  247. for (i = 0; i < this._attributes.length; i++)
  248. {
  249. const attr = this._attributes[i];
  250. if (attr.name == name)
  251. {
  252. if (attr.numItems === numItems)
  253. {
  254. }
  255. else
  256. {
  257. // this._log.log("wrong buffer size", this._geom.name, attr.name, attr.numItems, numItems);
  258. this._resizeAttr(array, attr);
  259. }
  260.  
  261. this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER, attr.buffer);
  262. this._bufferArray(array, attr);
  263.  
  264. return attr;
  265. }
  266. }
  267.  
  268. // create new buffer...
  269.  
  270. const buffer = this._cgl.gl.createBuffer();
  271.  
  272. this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER, buffer);
  273. // this._cgl.gl.bufferData(this._cgl.gl.ARRAY_BUFFER, floatArray, this._cgl.gl.DYNAMIC_DRAW);
  274.  
  275. let type = this._cgl.gl.FLOAT;
  276. if (options && options.type) type = options.type;
  277. const attr = {
  278. "buffer": buffer,
  279. "name": name,
  280. "cb": cb,
  281. "itemSize": itemSize,
  282. "numItems": numItems,
  283. "startItem": 0,
  284. "instanced": instanced,
  285. "type": type
  286. };
  287.  
  288. this._bufferArray(array, attr);
  289.  
  290. if (name == CONSTANTS.SHADER.SHADERVAR_VERTEX_POSITION) this._bufVertexAttrib = attr;
  291. this._attributes.push(attr);
  292. this._attribLocs = {};
  293.  
  294. return attr;
  295. };
  296.  
  297. Mesh.prototype.getAttributes = function ()
  298. {
  299. return this._attributes;
  300. };
  301.  
  302. /**
  303. * @function updateTexCoords
  304. * @description update texture coordinates only from a geometry
  305. * @memberof Mesh
  306. * @instance
  307. * @param {Geometry} geom
  308. */
  309. Mesh.prototype.updateTexCoords = function (geom)
  310. {
  311. if (geom.texCoords && geom.texCoords.length > 0)
  312. {
  313. this.setAttribute(CONSTANTS.SHADER.SHADERVAR_VERTEX_TEXCOORD, geom.texCoords, 2);
  314. }
  315. else
  316. {
  317. const tcBuff = new Float32Array(Math.round((geom.vertices.length / 3) * 2));
  318. this.setAttribute(CONSTANTS.SHADER.SHADERVAR_VERTEX_TEXCOORD, tcBuff, 2);
  319. }
  320. };
  321.  
  322.  
  323. /**
  324. * @function updateNormals
  325. * @description update normals only from a geometry
  326. * @memberof Mesh
  327. * @instance
  328. * @param {Geometry} geom
  329. */
  330. Mesh.prototype.updateNormals = function (geom)
  331. {
  332. if (geom.vertexNormals && geom.vertexNormals.length > 0)
  333. {
  334. this.setAttribute(CONSTANTS.SHADER.SHADERVAR_VERTEX_NORMAL, geom.vertexNormals, 3);
  335. }
  336. else
  337. {
  338. const tcBuff = new Float32Array(Math.round((geom.vertices.length)));
  339. this.setAttribute(CONSTANTS.SHADER.SHADERVAR_VERTEX_NORMAL, tcBuff, 3);
  340. }
  341. };
  342.  
  343.  
  344. Mesh.prototype._setVertexNumbers = function (arr)
  345. {
  346. if (!this._verticesNumbers || this._verticesNumbers.length != this._numVerts || arr)
  347. {
  348. if (arr) this._verticesNumbers = arr;
  349. else
  350. {
  351. this._verticesNumbers = new Float32Array(this._numVerts);
  352. for (let i = 0; i < this._numVerts; i++) this._verticesNumbers[i] = i;
  353. }
  354.  
  355. this.setAttribute(CONSTANTS.SHADER.SHADERVAR_VERTEX_NUMBER, this._verticesNumbers, 1, (attr, geom, shader) =>
  356. {
  357. if (!shader.uniformNumVertices) shader.uniformNumVertices = new Uniform(shader, "f", "numVertices", this._numVerts);
  358. shader.uniformNumVertices.setValue(this._numVerts);
  359.  
  360. // console.log("this._numVerts", this._numVerts, attr, shader.uniformNumVertices);
  361. });
  362. }
  363. };
  364.  
  365. /**
  366. * @function setVertexIndices
  367. * @description update vertex indices / faces
  368. * @memberof Mesh
  369. * @instance
  370. * @param {array} vertIndices
  371. */
  372. Mesh.prototype.setVertexIndices = function (vertIndices)
  373. {
  374. if (!this._bufVerticesIndizes)
  375. {
  376. this._log.warn("no bufVerticesIndizes: " + this._name);
  377. return;
  378. }
  379. if (vertIndices.length > 0)
  380. {
  381. if (vertIndices instanceof Float32Array) this._log.warn("vertIndices float32Array: " + this._name);
  382.  
  383. for (let i = 0; i < vertIndices.length; i++)
  384. {
  385. if (vertIndices[i] >= this._numVerts)
  386. {
  387. this._log.warn("invalid index in " + this._name, i, vertIndices[i]);
  388. return;
  389. }
  390. }
  391.  
  392. this._cgl.gl.bindBuffer(this._cgl.gl.ELEMENT_ARRAY_BUFFER, this._bufVerticesIndizes);
  393.  
  394. // todo cache this ?
  395. // if(!this.vertIndicesTyped || this.vertIndicesTyped.length!=this._geom.verticesIndices.length)
  396.  
  397. if (vertIndices.length > 65535)
  398. {
  399. this.vertIndicesTyped = new Uint32Array(vertIndices);
  400. this._indexType = this._cgl.gl.UNSIGNED_INT;
  401. }
  402. else
  403. if (vertIndices instanceof Uint32Array)
  404. {
  405. this.vertIndicesTyped = vertIndices;
  406. this._indexType = this._cgl.gl.UNSIGNED_INT;
  407. }
  408. else
  409. if (!(vertIndices instanceof Uint16Array))
  410. {
  411. this.vertIndicesTyped = new Uint16Array(vertIndices);
  412. this._indexType = this._cgl.gl.UNSIGNED_SHORT;
  413. }
  414. else this.vertIndicesTyped = vertIndices;
  415.  
  416. this._cgl.gl.bufferData(this._cgl.gl.ELEMENT_ARRAY_BUFFER, this.vertIndicesTyped, this._cgl.gl.DYNAMIC_DRAW);
  417. this._bufVerticesIndizes.itemSize = 1;
  418. this._bufVerticesIndizes.numItems = vertIndices.length;
  419. }
  420. else this._bufVerticesIndizes.numItems = 0;
  421. };
  422.  
  423. /**
  424. * @function setGeom
  425. * @memberof Mesh
  426. * @instance
  427. * @description set geometry for mesh
  428. * @param {Geometry} geom
  429. * @param {boolean} removeRef
  430. */
  431. Mesh.prototype.setGeom = function (geom, removeRef)
  432. {
  433. this._geom = geom;
  434. if (geom.glPrimitive != null) this._glPrimitive = geom.glPrimitive;
  435. if (this._geom && this._geom.name) this._name = "mesh " + this._geom.name;
  436.  
  437. MESH.lastMesh = null;
  438. this._cgl.profileData.profileMeshSetGeom++;
  439.  
  440. this._disposeAttributes();
  441.  
  442. this.updateVertices(this._geom);
  443. this.setVertexIndices(this._geom.verticesIndices);
  444.  
  445. if (this.addVertexNumbers) this._setVertexNumbers();
  446.  
  447. const geomAttribs = this._geom.getAttributes();
  448.  
  449. const attribAssoc = {
  450. "texCoords": CONSTANTS.SHADER.SHADERVAR_VERTEX_TEXCOORD,
  451. "vertexNormals": CONSTANTS.SHADER.SHADERVAR_VERTEX_NORMAL,
  452. "vertexColors": CONSTANTS.SHADER.SHADERVAR_VERTEX_COLOR,
  453. "tangents": "attrTangent",
  454. "biTangents": "attrBiTangent",
  455. };
  456.  
  457. for (const index in geomAttribs)
  458. if (geomAttribs[index].data && geomAttribs[index].data.length)
  459. this.setAttribute(attribAssoc[index] || index, geomAttribs[index].data, geomAttribs[index].itemSize);
  460.  
  461.  
  462. if (removeRef)
  463. {
  464. this._geom = null;
  465. }
  466. };
  467.  
  468. Mesh.prototype._preBind = function (shader)
  469. {
  470. for (let i = 0; i < this._attributes.length; i++)
  471. if (this._attributes[i].cb)
  472. this._attributes[i].cb(this._attributes[i], this._geom, shader);
  473. };
  474.  
  475. Mesh.prototype._checkAttrLengths = function ()
  476. {
  477. if (this.memFreed) return;
  478. // check length
  479. for (let i = 0; i < this._attributes.length; i++)
  480. {
  481. if (this._attributes[i].arrayLength / this._attributes[i].itemSize < this._attributes[0].arrayLength / this._attributes[0].itemSize)
  482. {
  483. let name = "unknown";
  484. if (this._geom)name = this._geom.name;
  485. // this._log.warn(
  486. // name + ": " + this._attributes[i].name +
  487. // " wrong attr length. is:", this._attributes[i].arrayLength / this._attributes[i].itemSize,
  488. // " should be:", this._attributes[0].arrayLength / this._attributes[0].itemSize,
  489. // );
  490. }
  491. }
  492. };
  493.  
  494. Mesh.prototype._bind = function (shader)
  495. {
  496. if (!shader.isValid()) return;
  497.  
  498. let attrLocs = [];
  499. if (this._attribLocs[shader.id]) attrLocs = this._attribLocs[shader.id];
  500. else this._attribLocs[shader.id] = attrLocs;
  501.  
  502. this._lastShader = shader;
  503. if (shader.lastCompile > this._lastAttrUpdate || attrLocs.length != this._attributes.length)
  504. {
  505. this._lastAttrUpdate = shader.lastCompile;
  506. for (let i = 0; i < this._attributes.length; i++) attrLocs[i] = -1;
  507. }
  508.  
  509. for (let i = 0; i < this._attributes.length; i++)
  510. {
  511. const attribute = this._attributes[i];
  512. if (attrLocs[i] == -1)
  513. {
  514. if (attribute._attrLocationLastShaderTime != shader.lastCompile)
  515. {
  516. attribute._attrLocationLastShaderTime = shader.lastCompile;
  517. attrLocs[i] = this._cgl.glGetAttribLocation(shader.getProgram(), attribute.name);
  518. // this._log.log('attribloc',attribute.name,attrLocs[i]);
  519. this._cgl.profileData.profileAttrLoc++;
  520. }
  521. }
  522.  
  523. if (attrLocs[i] != -1)
  524. {
  525. this._cgl.gl.enableVertexAttribArray(attrLocs[i]);
  526. this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER, attribute.buffer);
  527.  
  528. if (attribute.instanced)
  529. {
  530. // todo: easier way to fill mat4 attribs...
  531. if (attribute.itemSize <= 4)
  532. {
  533. if (!attribute.itemSize || attribute.itemSize == 0) this._log.warn("instanced attrib itemsize error", this._geom.name, attribute);
  534.  
  535. this._cgl.gl.vertexAttribPointer(attrLocs[i], attribute.itemSize, attribute.type, false, attribute.itemSize * 4, 0);
  536. this._cgl.gl.vertexAttribDivisor(attrLocs[i], 1);
  537. }
  538. else if (attribute.itemSize == 16)
  539. {
  540. const stride = 16 * 4;
  541.  
  542. this._cgl.gl.vertexAttribPointer(attrLocs[i], 4, attribute.type, false, stride, 0);
  543. this._cgl.gl.enableVertexAttribArray(attrLocs[i] + 1);
  544. this._cgl.gl.vertexAttribPointer(attrLocs[i] + 1, 4, attribute.type, false, stride, 4 * 4 * 1);
  545. this._cgl.gl.enableVertexAttribArray(attrLocs[i] + 2);
  546. this._cgl.gl.vertexAttribPointer(attrLocs[i] + 2, 4, attribute.type, false, stride, 4 * 4 * 2);
  547. this._cgl.gl.enableVertexAttribArray(attrLocs[i] + 3);
  548. this._cgl.gl.vertexAttribPointer(attrLocs[i] + 3, 4, attribute.type, false, stride, 4 * 4 * 3);
  549.  
  550. this._cgl.gl.vertexAttribDivisor(attrLocs[i], 1);
  551. this._cgl.gl.vertexAttribDivisor(attrLocs[i] + 1, 1);
  552. this._cgl.gl.vertexAttribDivisor(attrLocs[i] + 2, 1);
  553. this._cgl.gl.vertexAttribDivisor(attrLocs[i] + 3, 1);
  554. }
  555. else
  556. {
  557. this._log.warn("unknown instance attrib size", attribute.name);
  558. }
  559. }
  560. else
  561. {
  562. if (!attribute.itemSize || attribute.itemSize == 0) this._log.warn("attrib itemsize error", this._name, attribute);
  563. this._cgl.gl.vertexAttribPointer(attrLocs[i], attribute.itemSize, attribute.type, false, attribute.itemSize * 4, 0);
  564.  
  565. if (attribute.pointer)
  566. {
  567. for (let ip = 0; ip < attribute.pointer.length; ip++)
  568. {
  569. const pointer = attribute.pointer[ip];
  570.  
  571. if (pointer.loc == -1)
  572. pointer.loc = this._cgl.glGetAttribLocation(shader.getProgram(), pointer.name);
  573.  
  574. this._cgl.profileData.profileAttrLoc++;
  575.  
  576. this._cgl.gl.enableVertexAttribArray(pointer.loc);
  577. this._cgl.gl.vertexAttribPointer(pointer.loc, attribute.itemSize, attribute.type, false, pointer.stride, pointer.offset);
  578. }
  579. }
  580. if (this.bindFeedback) this.bindFeedback(attribute);
  581. }
  582. }
  583. }
  584.  
  585. if (this._bufVerticesIndizes && this._bufVerticesIndizes.numItems !== 0) this._cgl.gl.bindBuffer(this._cgl.gl.ELEMENT_ARRAY_BUFFER, this._bufVerticesIndizes);
  586. };
  587.  
  588. Mesh.prototype.unBind = function ()
  589. {
  590. const shader = this._lastShader;
  591. this._lastShader = null;
  592. if (!shader) return;
  593.  
  594. let attrLocs = [];
  595. if (this._attribLocs[shader.id]) attrLocs = this._attribLocs[shader.id];
  596. else this._attribLocs[shader.id] = attrLocs;
  597.  
  598. MESH.lastMesh = null;
  599.  
  600. for (let i = 0; i < this._attributes.length; i++)
  601. {
  602. if (this._attributes[i].instanced)
  603. {
  604. // todo: easier way to fill mat4 attribs...
  605. if (this._attributes[i].itemSize <= 4)
  606. {
  607. if (attrLocs[i] != -1) this._cgl.gl.vertexAttribDivisor(attrLocs[i], 0);
  608. if (attrLocs[i] >= 0) this._cgl.gl.disableVertexAttribArray(attrLocs[i]);
  609. }
  610. else
  611. {
  612. this._cgl.gl.vertexAttribDivisor(attrLocs[i], 0);
  613. this._cgl.gl.vertexAttribDivisor(attrLocs[i] + 1, 0);
  614. this._cgl.gl.vertexAttribDivisor(attrLocs[i] + 2, 0);
  615. this._cgl.gl.vertexAttribDivisor(attrLocs[i] + 3, 0);
  616. this._cgl.gl.disableVertexAttribArray(attrLocs[i] + 1);
  617. this._cgl.gl.disableVertexAttribArray(attrLocs[i] + 2);
  618. this._cgl.gl.disableVertexAttribArray(attrLocs[i] + 3);
  619. }
  620. }
  621.  
  622. if (attrLocs[i] != -1) this._cgl.gl.disableVertexAttribArray(attrLocs[i]);
  623. }
  624. };
  625.  
  626. Mesh.prototype.meshChanged = function ()
  627. {
  628. return this._cgl.lastMesh && this._cgl.lastMesh != this;
  629. };
  630.  
  631. Mesh.prototype.printDebug = function (shader)
  632. {
  633. console.log("--attributes");
  634. for (let i = 0; i < this._attributes.length; i++)
  635. {
  636. console.log("attribute " + i + " " + this._attributes[i].name);
  637. }
  638. };
  639.  
  640. Mesh.prototype.setNumVertices = function (num)
  641. {
  642. this._bufVertexAttrib.numItems = num;
  643. };
  644.  
  645. Mesh.prototype.getNumVertices = function ()
  646. {
  647. return this._bufVertexAttrib.numItems;
  648. };
  649.  
  650.  
  651. /**
  652. * @function render
  653. * @memberof Mesh
  654. * @instance
  655. * @description draw mesh to screen
  656. * @param {Shader} shader
  657. */
  658. Mesh.prototype.render = function (shader)
  659. {
  660. // TODO: enable/disablevertex only if the mesh has changed... think drawing 10000x the same mesh
  661.  
  662. if (!shader || !shader.isValid() || this._cgl.aborted) return;
  663.  
  664. this._checkAttrLengths();
  665.  
  666. if (this._geom)
  667. {
  668. if (this._preWireframeGeom && !shader.wireframe && !this._geom.isIndexed())
  669. {
  670. this.setGeom(this._preWireframeGeom);
  671. this._preWireframeGeom = null;
  672. // console.log("remove prewireframe geom");
  673. }
  674.  
  675. if (shader.wireframe)
  676. {
  677. let changed = false;
  678.  
  679. if (this._geom.isIndexed())
  680. {
  681. if (!this._preWireframeGeom)
  682. {
  683. this._preWireframeGeom = this._geom;
  684. this._geom = this._geom.copy();
  685. }
  686.  
  687. this._geom.unIndex();
  688. changed = true;
  689. }
  690.  
  691. if (!this._geom.getAttribute("attrBarycentric"))
  692. {
  693. if (!this._preWireframeGeom)
  694. {
  695. this._preWireframeGeom = this._geom;
  696. this._geom = this._geom.copy();
  697. }
  698. changed = true;
  699.  
  700. this._geom.calcBarycentric();
  701. }
  702. if (changed) this.setGeom(this._geom);
  703. }
  704. // if (shader.wireframe)
  705. // console.log(shader.wireframe, this._geom.isIndexed());
  706. }
  707.  
  708. let needsBind = false;
  709. if (MESH.lastMesh != this)
  710. {
  711. if (MESH.lastMesh) MESH.lastMesh.unBind();
  712. needsBind = true;
  713. }
  714.  
  715.  
  716. // var needsBind=false;
  717. // {
  718. // needsBind=true;
  719. // }
  720. if (needsBind) this._preBind(shader);
  721.  
  722. if (!shader.bind()) return;
  723.  
  724. // if(needsBind)
  725. this._bind(shader);
  726. if (this.addVertexNumbers) this._setVertexNumbers();
  727.  
  728. MESH.lastMesh = this;
  729.  
  730. let prim = this._cgl.gl.TRIANGLES;
  731. if (this._glPrimitive !== undefined) prim = this._glPrimitive;
  732. if (shader.glPrimitive !== null) prim = shader.glPrimitive;
  733.  
  734. let elementDiv = 1;
  735. let doQuery = this._cgl.profileData.doProfileGlQuery;
  736. let queryStarted = false;
  737. if (doQuery)
  738. {
  739. let id = this._name + " - " + shader.getName() + " #" + shader.id;
  740. if (this._numInstances) id += " instanced " + this._numInstances + "x";
  741.  
  742. let queryProfilerData = this._cgl.profileData.glQueryData[id];
  743.  
  744. if (!queryProfilerData) queryProfilerData = { "id": id, "num": 0 };
  745.  
  746. if (shader.opId)queryProfilerData.shaderOp = shader.opId;
  747. if (this.opId)queryProfilerData.meshOp = this.opId;
  748.  
  749. this._cgl.profileData.glQueryData[id] = queryProfilerData;
  750.  
  751. if (!this._queryExt && this._queryExt !== false) this._queryExt = this._cgl.enableExtension("EXT_disjoint_timer_query_webgl2") || false;
  752. if (this._queryExt)
  753. {
  754. if (queryProfilerData._drawQuery)
  755. {
  756. const available = this._cgl.gl.getQueryParameter(queryProfilerData._drawQuery, this._cgl.gl.QUERY_RESULT_AVAILABLE);
  757. if (available)
  758. {
  759. const elapsedNanos = this._cgl.gl.getQueryParameter(queryProfilerData._drawQuery, this._cgl.gl.QUERY_RESULT);
  760. const currentTimeGPU = elapsedNanos / 1000000;
  761.  
  762. queryProfilerData._times = queryProfilerData._times || 0;
  763. queryProfilerData._times += currentTimeGPU;
  764. queryProfilerData._numcount++;
  765. queryProfilerData.when = performance.now();
  766. queryProfilerData._drawQuery = null;
  767. queryProfilerData.queryStarted = false;
  768. }
  769. }
  770.  
  771. if (!queryProfilerData.queryStarted)
  772. {
  773. queryProfilerData._drawQuery = this._cgl.gl.createQuery();
  774. this._cgl.gl.beginQuery(this._queryExt.TIME_ELAPSED_EXT, queryProfilerData._drawQuery);
  775. queryStarted = queryProfilerData.queryStarted = true;
  776. }
  777. }
  778. }
  779.  
  780.  
  781. if (this.hasFeedbacks && this.hasFeedbacks()) this.drawFeedbacks(shader, prim);
  782. else if (!this._bufVerticesIndizes || this._bufVerticesIndizes.numItems === 0)
  783. {
  784. // for (let i = 0; i < this._attributes.length; i++)
  785. // {
  786. // if (this._attributes[i].arrayLength / this._attributes[i].itemSize != this._bufVertexAttrib.floatArray.length / 3)
  787. // {
  788. // this._log.warn("attrib buffer length wrong! ", this._attributes[i].name, this._attributes[i].arrayLength / this._attributes[i].itemSize, this._bufVertexAttrib.floatArray.length / 3, this._attributes[i].itemSize);
  789. // // this._log.log(this);
  790. // // debugger;
  791. // return;
  792. // }
  793. // }
  794.  
  795.  
  796. if (prim == this._cgl.gl.TRIANGLES)elementDiv = 3;
  797. if (this._numInstances === 0) this._cgl.gl.drawArrays(prim, this._bufVertexAttrib.startItem, this._bufVertexAttrib.numItems - this._bufVertexAttrib.startItem);
  798. else this._cgl.gl.drawArraysInstanced(prim, this._bufVertexAttrib.startItem, this._bufVertexAttrib.numItems, this._numInstances);
  799. }
  800. else
  801. {
  802. if (prim == this._cgl.gl.TRIANGLES)elementDiv = 3;
  803. if (this._numInstances === 0)
  804. {
  805. // console.log("la", this._bufVerticesIndizes.numItems);
  806.  
  807. this._cgl.gl.drawElements(prim, this._bufVerticesIndizes.numItems, this._indexType, 0);
  808. }
  809. else
  810. {
  811. this._cgl.gl.drawElementsInstanced(prim, this._bufVerticesIndizes.numItems, this._indexType, 0, this._numInstances);
  812. }
  813. }
  814.  
  815. if (this._cgl.debugOneFrame && this._cgl.gl.getError() != this._cgl.gl.NO_ERROR)
  816. {
  817. this._log.error("mesh draw gl error");
  818. this._log.error("mesh", this);
  819. this._log.error("shader", shader);
  820.  
  821. const attribNames = [];
  822. for (let i = 0; i < this._cgl.gl.getProgramParameter(shader.getProgram(), this._cgl.gl.ACTIVE_ATTRIBUTES); i++)
  823. {
  824. const name = this._cgl.gl.getActiveAttrib(shader.getProgram(), i).name;
  825. this._log.error("attrib ", name);
  826. }
  827. }
  828.  
  829. this._cgl.profileData.profileMeshNumElements += (this._bufVertexAttrib.numItems / elementDiv) * (this._numInstances || 1);
  830. this._cgl.profileData.profileMeshDraw++;
  831.  
  832. if (doQuery && queryStarted)
  833. {
  834. this._cgl.gl.endQuery(this._queryExt.TIME_ELAPSED_EXT);
  835. }
  836.  
  837. this._cgl.printError("mesh render " + this._name);
  838.  
  839. this.unBind();
  840. };
  841.  
  842. Mesh.prototype.setNumInstances = function (n)
  843. {
  844. n = Math.max(0, n);
  845. if (this._numInstances != n)
  846. {
  847. this._numInstances = n;
  848. const indexArr = new Float32Array(n);
  849. for (let i = 0; i < n; i++) indexArr[i] = i;
  850. this.setAttribute(CONSTANTS.SHADER.SHADERVAR_INSTANCE_INDEX, indexArr, 1, { "instanced": true });
  851. }
  852. };
  853.  
  854. Mesh.prototype._disposeAttributes = function ()
  855. {
  856. if (!this._attributes) return;
  857.  
  858. for (let i = 0; i < this._attributes.length; i++)
  859. {
  860. if (this._attributes[i].buffer)
  861. {
  862. this._cgl.gl.deleteBuffer(this._attributes[i].buffer);
  863. this._attributes[i].buffer = null;
  864. }
  865. }
  866. this._attributes.length = 0;
  867. };
  868.  
  869. Mesh.prototype.dispose = function ()
  870. {
  871. if (this._bufVertexAttrib && this._bufVertexAttrib.buffer) this._cgl.gl.deleteBuffer(this._bufVertexAttrib.buffer);
  872. if (this._bufVerticesIndizes) this._cgl.gl.deleteBuffer(this._bufVerticesIndizes);
  873. this._bufVerticesIndizes = null;
  874.  
  875. this._disposeAttributes();
  876. };
  877.  
  878.  
  879.  
  880. export { Mesh, MESH };