Home Reference Source

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

  1. import { Logger } from "cables-shared-client";
  2. import { CONSTANTS } from "./constants.js";
  3. import { Shader } from "./cgl_shader.js";
  4. import { ProfileData } from "./cgl_profiledata.js";
  5. import { CGState } from "../cg/cg_state.js";
  6. import { CG } from "../cg/cg_constants.js";
  7.  
  8.  
  9. /**
  10. * cables gl context/state manager
  11. * @class
  12. * @namespace external:CGL
  13. * @hideconstructor
  14. */
  15. // const Context(_patch)
  16. class Context extends CGState
  17. {
  18. constructor(_patch)
  19. {
  20. super(_patch);
  21.  
  22. this.gApi = CG.GAPI_WEBGL;
  23. this.aborted = false;
  24.  
  25. this.pushMvMatrix = this.pushModelMatrix; // deprecated and wrong... still used??
  26. this.popMvMatrix = this.popmMatrix = this.popModelMatrix;// deprecated and wrong... still used??
  27.  
  28. this.profileData = new ProfileData(this);
  29. this._log = new Logger("cgl_context", { "onError": _patch.config.onError });
  30. this._viewPort = [0, 0, 0, 0];
  31. this.glVersion = 0;
  32. this.glUseHalfFloatTex = false;
  33. this.clearCanvasTransparent = true;
  34. this.clearCanvasDepth = true;
  35. this.debugOneFrame = false;
  36. this.checkGlErrors = false; // true is slow // false should be default...
  37. this.maxTextureUnits = 0;
  38. this.maxVaryingVectors = 0;
  39. this.currentProgram = null;
  40. this._hadStackError = false;
  41. this.glSlowRenderer = false;
  42. this._isSafariCrap = false;
  43.  
  44. this.temporaryTexture = null;
  45. this._onetimeCallbacks = [];
  46. this.gl = null;
  47.  
  48. this._cursor = "auto";
  49. this._currentCursor = "";
  50.  
  51. this._viewPortStack = [];
  52. this._glFrameBufferStack = [];
  53. this._frameBufferStack = [];
  54. this._shaderStack = [];
  55. this._stackDepthTest = [];
  56. this.mainloopOp = null;
  57.  
  58. this._simpleShader = new Shader(this, "simpleshader");
  59. this._simpleShader.setModules(["MODULE_VERTEX_POSITION", "MODULE_COLOR", "MODULE_BEGIN_FRAG", "MODULE_VERTEX_MODELVIEW"]);
  60. this._simpleShader.setSource(Shader.getDefaultVertexShader(), Shader.getDefaultFragmentShader());
  61.  
  62. this._currentShader = this._simpleShader;
  63.  
  64.  
  65. this._oldCanvasWidth = -1;
  66. this._oldCanvasHeight = -1;
  67. this._enabledExtensions = {};
  68. }
  69.  
  70. // set pixelDensity(p)
  71. // {
  72. // this._pixelDensity = p;
  73. // }
  74.  
  75. // get pixelDensity()
  76. // {
  77. // return this._pixelDensity;
  78. // }
  79.  
  80.  
  81.  
  82. get viewPort()
  83. {
  84. if (this._viewPortStack.length > 3)
  85. {
  86. const l = this._viewPortStack.length;
  87.  
  88. return [
  89. this._viewPortStack[l - 4],
  90. this._viewPortStack[l - 3],
  91. this._viewPortStack[l - 2],
  92. this._viewPortStack[l - 1]
  93. ];
  94. }
  95. else
  96. {
  97. // workaround pre viewport stack times / or+and initial value...
  98.  
  99. return this._viewPort;
  100. }
  101. }
  102.  
  103.  
  104.  
  105. get mvMatrix() // deprecate
  106. {
  107. return this.mMatrix;
  108. }
  109.  
  110. set mvMatrix(m) // deprecate
  111. {
  112. this.mMatrix = m;
  113. }
  114.  
  115. _setCanvas(canv)
  116. {
  117. if (!canv) this._log.stack("_setCanvas undef");
  118.  
  119. if (!this.patch.config.canvas) this.patch.config.canvas = {};
  120. if (!this.patch.config.canvas.hasOwnProperty("preserveDrawingBuffer")) this.patch.config.canvas.preserveDrawingBuffer = false;
  121. if (!this.patch.config.canvas.hasOwnProperty("premultipliedAlpha")) this.patch.config.canvas.premultipliedAlpha = false;
  122. if (!this.patch.config.canvas.hasOwnProperty("alpha")) this.patch.config.canvas.alpha = false;
  123.  
  124. this.patch.config.canvas.stencil = true;
  125.  
  126. if (this.patch.config.hasOwnProperty("clearCanvasColor")) this.clearCanvasTransparent = this.patch.config.clearCanvasColor;
  127. if (this.patch.config.hasOwnProperty("clearCanvasDepth")) this.clearCanvasDepth = this.patch.config.clearCanvasDepth;
  128.  
  129. // safari stuff..........
  130. if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent) && (navigator.userAgent.match(/iPhone/i)))
  131. {
  132. this._isSafariCrap = true;
  133. this.glUseHalfFloatTex = true;
  134. }
  135.  
  136. if (!this.patch.config.canvas.forceWebGl1) this.gl = canv.getContext("webgl2", this.patch.config.canvas);
  137.  
  138.  
  139. if (!this.gl || this.gl.isContextLost())
  140. {
  141. this.aborted = true;
  142. this._log.error("NO_WEBGL", "sorry, could not initialize WebGL. Please check if your Browser supports WebGL or try to restart your browser.");
  143. return;
  144. }
  145.  
  146. if (this.gl.getParameter(this.gl.VERSION) != "WebGL 1.0")
  147. {
  148. this.glVersion = 2;
  149. }
  150. else
  151. {
  152. this.gl = canv.getContext("webgl", this.patch.config.canvas) || canv.getContext("experimental-webgl", this.patch.config.canvas);
  153. this.glVersion = 1;
  154.  
  155. // safari
  156. // if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent) && (navigator.userAgent.match(/iPhone/i)))
  157. // {
  158. // this.glUseHalfFloatTex = true;
  159. // }
  160.  
  161. // ios
  162. if (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream)
  163. {
  164. if (!this.patch.config.canvas.hasOwnProperty("powerPreference")) this.patch.config.canvas.powerPreference = "high-performance";
  165. }
  166.  
  167. this.enableExtension("OES_standard_derivatives");
  168. // this.enableExtension("GL_OES_standard_derivatives");
  169. const instancingExt = this.enableExtension("ANGLE_instanced_arrays") || this.gl;
  170. if (instancingExt.vertexAttribDivisorANGLE)
  171. {
  172. this.gl.vertexAttribDivisor = instancingExt.vertexAttribDivisorANGLE.bind(instancingExt);
  173. this.gl.drawElementsInstanced = instancingExt.drawElementsInstancedANGLE.bind(instancingExt);
  174. }
  175. }
  176.  
  177. const dbgRenderInfo = this.enableExtension("WEBGL_debug_renderer_info");
  178. if (dbgRenderInfo)
  179. {
  180. this.glRenderer = this.gl.getParameter(dbgRenderInfo.UNMASKED_RENDERER_WEBGL);
  181. if (this.glRenderer === "Google SwiftShader") this.glSlowRenderer = true;
  182. }
  183.  
  184. this.canvas.addEventListener("webglcontextlost", (event) =>
  185. {
  186. if (this.aborted) return this._log.warn("[cgl_state] aborted context lost... can be ignored...");
  187. this._log.error("canvas lost...", event);
  188. this.emitEvent("webglcontextlost");
  189. this.aborted = true;
  190. });
  191.  
  192.  
  193. this.maxAnisotropic = 0;
  194. if (this.enableExtension("EXT_texture_filter_anisotropic"))
  195. this.maxAnisotropic = this.gl.getParameter(this.enableExtension("EXT_texture_filter_anisotropic").MAX_TEXTURE_MAX_ANISOTROPY_EXT);
  196.  
  197.  
  198. this.maxVaryingVectors = this.gl.getParameter(this.gl.MAX_VARYING_VECTORS);
  199. this.maxTextureUnits = this.gl.getParameter(this.gl.MAX_TEXTURE_IMAGE_UNITS);
  200. this.maxTexSize = this.gl.getParameter(this.gl.MAX_TEXTURE_SIZE);
  201. this.maxUniformsFrag = this.gl.getParameter(this.gl.MAX_FRAGMENT_UNIFORM_VECTORS);
  202. this.maxUniformsVert = this.gl.getParameter(this.gl.MAX_VERTEX_UNIFORM_VECTORS);
  203. this.maxSamples = 0;
  204. if (this.gl.MAX_SAMPLES) this.maxSamples = this.gl.getParameter(this.gl.MAX_SAMPLES);
  205.  
  206. if (this.glVersion == 1)
  207. {
  208. this.enableExtension("OES_standard_derivatives");
  209. const instancingExt = this.enableExtension("ANGLE_instanced_arrays") || this.gl;
  210.  
  211. if (instancingExt.vertexAttribDivisorANGLE)
  212. {
  213. this.gl.vertexAttribDivisor = instancingExt.vertexAttribDivisorANGLE.bind(instancingExt);
  214. this.gl.drawElementsInstanced = instancingExt.drawElementsInstancedANGLE.bind(instancingExt);
  215. }
  216. }
  217.  
  218. this.DEPTH_FUNCS = [
  219. this.gl.NEVER,
  220. this.gl.ALWAYS,
  221. this.gl.LESS,
  222. this.gl.LEQUAL,
  223. this.gl.GREATER,
  224. this.gl.GEQUAL,
  225. this.gl.EQUAL,
  226. this.gl.NOTEQUAL
  227. ];
  228. this.CULL_MODES = [
  229. null,
  230. this.gl.BACK,
  231. this.gl.FRONT,
  232. this.gl.FRONT_AND_BACK
  233. ];
  234. }
  235.  
  236. getInfo()
  237. {
  238. return {
  239. "glVersion": this.glVersion,
  240. "glRenderer": this.glRenderer,
  241. "glUseHalfFloatTex": this.glUseHalfFloatTex,
  242. "maxVaryingVectors": this.maxVaryingVectors,
  243. "maxTextureUnits": this.maxTextureUnits,
  244. "maxTexSize": this.maxTexSize,
  245. "maxUniformsFrag": this.maxUniformsFrag,
  246. "maxUniformsVert": this.maxUniformsVert,
  247. "maxSamples": this.maxSamples
  248. };
  249. }
  250.  
  251.  
  252.  
  253.  
  254.  
  255. /**
  256. * @function popViewPort
  257. * @memberof Context
  258. * @instance
  259. * @description pop viewPort stack
  260. */
  261.  
  262.  
  263. popViewPort()
  264. {
  265. this._viewPortStack.pop();
  266. this._viewPortStack.pop();
  267. this._viewPortStack.pop();
  268. this._viewPortStack.pop();
  269.  
  270. if (this._viewPortStack.length == 0)
  271. {
  272. this.setViewPort(0, 0, this.canvasWidth, this.canvasHeight);
  273. // this.gl.viewport(this._viewPort[0], this._viewPort[1], this._viewPort[2], this._viewPort[3]);
  274. // this.setViewPort(this._viewPort[0], this._viewPort[1], this._viewPort[2], this._viewPort[3]);
  275. }
  276. else
  277. {
  278. // this.viewPort = [this._viewPortStack[this._viewPort.length - 4], this._viewPortStack[this._viewPort.length - 3], this._viewPortStack[this._viewPort.length - 2], this._viewPortStack[this._viewPort.length - 1]];
  279. // this.gl.viewport(this._viewPortStack[this._viewPort.length - 4], this._viewPortStack[this._viewPort.length - 3], this._viewPortStack[this._viewPort.length - 2], this._viewPortStack[this._viewPort.length - 1]);
  280. this.setViewPort(this._viewPortStack[this._viewPort.length - 4], this._viewPortStack[this._viewPort.length - 3], this._viewPortStack[this._viewPort.length - 2], this._viewPortStack[this._viewPort.length - 1]);
  281. }
  282. }
  283.  
  284. /**
  285. * @function pushViewPort
  286. * @memberof Context
  287. * @instance
  288. * @description push a new viewport onto stack
  289. * @param {Number} x
  290. * @param {Number} y
  291. * @param {Number} w
  292. * @param {Number} h
  293. */
  294.  
  295. pushViewPort(x, y, w, h)
  296. {
  297. this._viewPortStack.push(x, y, w, h);
  298. this.setViewPort(x, y, w, h);
  299. }
  300.  
  301.  
  302. // old
  303. getViewPort()
  304. {
  305. return this._viewPort;
  306. }
  307.  
  308. // old
  309. resetViewPort()
  310. {
  311. this.gl.viewport(this._viewPort[0], this._viewPort[1], this._viewPort[2], this._viewPort[3]);
  312. }
  313.  
  314. // old
  315. setViewPort(x, y, w, h)
  316. {
  317. this._viewPort[0] = Math.round(x);
  318. this._viewPort[1] = Math.round(y);
  319. this._viewPort[2] = Math.round(w);
  320. this._viewPort[3] = Math.round(h);
  321. this.gl.viewport(this._viewPort[0], this._viewPort[1], this._viewPort[2], this._viewPort[3]);
  322. }
  323.  
  324.  
  325. screenShot(cb, doScreenshotClearAlpha, mimeType, quality)
  326. {
  327. if (doScreenshotClearAlpha)
  328. {
  329. this.gl.clearColor(1, 1, 1, 1);
  330. this.gl.colorMask(false, false, false, true);
  331. this.gl.clear(this.gl.COLOR_BUFFER_BIT);
  332. this.gl.colorMask(true, true, true, true);
  333. }
  334.  
  335. if (this.canvas && this.canvas.toBlob)
  336. {
  337. this.canvas.toBlob((blob) =>
  338. {
  339. if (cb) cb(blob);
  340. else this._log.log("no screenshot callback...");
  341. }, mimeType, quality);
  342. }
  343. }
  344.  
  345. endFrame()
  346. {
  347. if (this.patch.isEditorMode()) CABLES.GL_MARKER.drawMarkerLayer(this);
  348.  
  349. this.setPreviousShader();
  350.  
  351. if (this._vMatrixStack.length() > 0) this.logStackError("view matrix stack length !=0 at end of rendering...");
  352. if (this._mMatrixStack.length() > 0) this.logStackError("mvmatrix stack length !=0 at end of rendering...");
  353. if (this._pMatrixStack.length() > 0) this.logStackError("pmatrix stack length !=0 at end of rendering...");
  354. if (this._glFrameBufferStack.length > 0) this.logStackError("glFrameBuffer stack length !=0 at end of rendering...");
  355. if (this._stackDepthTest.length > 0) this.logStackError("depthtest stack length !=0 at end of rendering...");
  356. if (this._stackDepthWrite.length > 0) this.logStackError("depthwrite stack length !=0 at end of rendering...");
  357. if (this._stackDepthFunc.length > 0) this.logStackError("depthfunc stack length !=0 at end of rendering...");
  358. if (this._stackBlend.length > 0) this.logStackError("blend stack length !=0 at end of rendering...");
  359. if (this._stackBlendMode.length > 0) this.logStackError("blendMode stack length !=0 at end of rendering...");
  360. if (this._shaderStack.length > 0) this.logStackError("this._shaderStack length !=0 at end of rendering...");
  361. if (this._stackCullFace.length > 0) this.logStackError("this._stackCullFace length !=0 at end of rendering...");
  362. if (this._stackCullFaceFacing.length > 0) this.logStackError("this._stackCullFaceFacing length !=0 at end of rendering...");
  363. if (this._viewPortStack.length > 0) this.logStackError("viewport stack length !=0 at end of rendering...");
  364.  
  365. this._frameStarted = false;
  366.  
  367. if (this._oldCanvasWidth != this.canvasWidth || this._oldCanvasHeight != this.canvasHeight)
  368. {
  369. this._oldCanvasWidth = this.canvasWidth;
  370. this._oldCanvasHeight = this.canvasHeight;
  371. this.emitEvent("resize");
  372. }
  373.  
  374. if (this._cursor != this._currentCursor)
  375. {
  376. this._currentCursor = this.canvas.style.cursor = this._cursor;
  377. }
  378.  
  379. this.emitEvent("endframe");
  380.  
  381. this.fpsCounter.endFrame();
  382. }
  383.  
  384. logStackError(str)
  385. {
  386. if (!this._hadStackError)
  387. {
  388. this._hadStackError = true;
  389. this._log.warn("[" + this.canvas.id + "]: ", str);
  390. }
  391. }
  392.  
  393. // shader stack
  394. getShader()
  395. {
  396. if (this._currentShader) if (!this.tempData || ((this.tempData.renderOffscreen === true) == this._currentShader.offScreenPass) === true) return this._currentShader;
  397.  
  398. for (let i = this._shaderStack.length - 1; i >= 0; i--) if (this._shaderStack[i]) if (this.tempData.renderOffscreen == this._shaderStack[i].offScreenPass) return this._shaderStack[i];
  399. }
  400.  
  401. getDefaultShader()
  402. {
  403. return this._simpleShader;
  404. }
  405.  
  406. /**
  407. * push a shader to the shader stack
  408. * @function pushShader
  409. * @memberof Context
  410. * @instance
  411. * @param {Object} shader
  412. * @function
  413. */
  414.  
  415. pushShader(shader)
  416. {
  417. if (this.tempData.forceShaderMods)
  418. {
  419. for (let i = 0; i < this.tempData.forceShaderMods.length; i++)
  420. {
  421. // if (!currentShader.forcedMod && currentShader != this.tempData.forceShaderMods[i])
  422. // {
  423. // currentShader.forcedMod = this.tempData.forceShaderMods[i];
  424. shader = this.tempData.forceShaderMods[i].bind(shader, false);
  425. // }
  426. // return currentShader;
  427. // if (this.tempData.forceShaderMods[i].currentShader() && shader != this.tempData.forceShaderMods[i].currentShader().shader)
  428. }
  429. }
  430.  
  431. this._shaderStack.push(shader);
  432. this._currentShader = shader;
  433. }
  434.  
  435.  
  436. /**
  437. * pop current used shader from shader stack
  438. * @function popShader
  439. * @memberof Context
  440. * @instance
  441. * @function
  442. */
  443. setPreviousShader()
  444. {
  445. if (this.tempData.forceShaderMods)
  446. {
  447. for (let i = 0; i < this.tempData.forceShaderMods.length; i++)
  448. {
  449. // const a =
  450. this.tempData.forceShaderMods[i].unbind(false);
  451. // if (a) return;
  452. // this.popShader();
  453. }
  454. }
  455.  
  456. if (this._shaderStack.length === 0) throw new Error("Invalid shader stack pop!");
  457. this._shaderStack.pop();
  458. this._currentShader = this._shaderStack[this._shaderStack.length - 1];
  459. }
  460.  
  461. /**
  462. * push a framebuffer to the framebuffer stack
  463. * @function pushGlFrameBuffer
  464. * @memberof Context
  465. * @instance
  466. * @param {Object} fb framebuffer
  467. * @function
  468. */
  469. pushGlFrameBuffer(fb)
  470. {
  471. this._glFrameBufferStack.push(fb);
  472. }
  473.  
  474. /**
  475. * pop framebuffer stack
  476. * @function popGlFrameBuffer
  477. * @memberof Context
  478. * @instance
  479. * @returns {Object} current framebuffer or null
  480. */
  481. popGlFrameBuffer()
  482. {
  483. if (this._glFrameBufferStack.length == 0) return null;
  484. this._glFrameBufferStack.pop();
  485. return this._glFrameBufferStack[this._glFrameBufferStack.length - 1];
  486. }
  487.  
  488. /**
  489. * get current framebuffer
  490. * @function getCurrentFrameBuffer
  491. * @memberof Context
  492. * @instance
  493. * @returns {Object} current framebuffer or null
  494. */
  495. getCurrentGlFrameBuffer()
  496. {
  497. if (this._glFrameBufferStack.length === 0) return null;
  498. return this._glFrameBufferStack[this._glFrameBufferStack.length - 1];
  499. }
  500.  
  501. /**
  502. * push a framebuffer to the framebuffer stack
  503. * @function pushGlFrameBuffer
  504. * @memberof Context
  505. * @instance
  506. * @param {Framebuffer} fb framebuffer
  507. */
  508. pushFrameBuffer(fb)
  509. {
  510. this._frameBufferStack.push(fb);
  511. }
  512.  
  513. /**
  514. * pop framebuffer stack
  515. * @function popFrameBuffer
  516. * @memberof Context
  517. * @instance
  518. * @returns {Framebuffer} current framebuffer or null
  519. */
  520. popFrameBuffer()
  521. {
  522. if (this._frameBufferStack.length == 0) return null;
  523. this._frameBufferStack.pop();
  524. return this._frameBufferStack[this._frameBufferStack.length - 1];
  525. }
  526.  
  527. /**
  528. * get current framebuffer
  529. * @function getCurrentFrameBuffer
  530. * @memberof Context
  531. * @instance
  532. * @returns {Framebuffer} current framebuffer or null
  533. */
  534. getCurrentFrameBuffer()
  535. {
  536. if (this._frameBufferStack.length === 0) return null;
  537. return this._frameBufferStack[this._frameBufferStack.length - 1];
  538. }
  539.  
  540.  
  541. renderStart(cgl, identTranslate, identTranslateView)
  542. {
  543. this.fpsCounter.startFrame();
  544. this.pushDepthTest(true);
  545. this.pushDepthWrite(true);
  546. this.pushDepthFunc(cgl.gl.LEQUAL);
  547. this.pushCullFaceFacing(cgl.gl.BACK);
  548. this.pushCullFace(false);
  549.  
  550. // if (this.clearCanvasTransparent)
  551. // {
  552. // cgl.gl.clearColor(0, 0, 0, 0);
  553. // cgl.gl.clear(cgl.gl.COLOR_BUFFER_BIT);
  554. // }
  555. // if (this.clearCanvasDepth) cgl.gl.clear(cgl.gl.DEPTH_BUFFER_BIT);
  556.  
  557. cgl.setViewPort(0, 0, cgl.canvasWidth, cgl.canvasHeight);
  558.  
  559. this._startMatrixStacks(identTranslate, identTranslateView);
  560.  
  561. cgl.pushBlendMode(CONSTANTS.BLEND_MODES.BLEND_NORMAL, false);
  562.  
  563. for (let i = 0; i < this._textureslots.length; i++) this._textureslots[i] = null;
  564.  
  565. this.pushShader(this._simpleShader);
  566.  
  567. this._frameStarted = true;
  568.  
  569. if (this._onetimeCallbacks.length > 0)
  570. {
  571. for (let i = 0; i < this._onetimeCallbacks.length; i++) this._onetimeCallbacks[i]();
  572. this._onetimeCallbacks.length = 0;
  573. }
  574.  
  575. for (let i = 0; i < this._textureslots.length; i++)
  576. {
  577. this.gl.activeTexture(this.gl.TEXTURE0 + i);
  578. this.gl.bindTexture(this.gl.TEXTURE_2D, null);
  579. this._textureslots[i] = null;
  580. }
  581.  
  582. this.emitEvent("beginFrame");
  583. }
  584.  
  585. renderEnd(cgl)
  586. {
  587. this._endMatrixStacks();
  588.  
  589. this.popDepthTest();
  590. this.popDepthWrite();
  591. this.popDepthFunc();
  592. this.popCullFaceFacing();
  593. this.popCullFace();
  594. this.popBlend();
  595. this.popBlendMode();
  596.  
  597. cgl.endFrame();
  598.  
  599. this.emitEvent("endFrame");
  600. }
  601.  
  602. getTexture(slot)
  603. {
  604. return this._textureslots[slot];
  605. }
  606.  
  607. hasFrameStarted()
  608. {
  609. return this._frameStarted;
  610. }
  611.  
  612. /**
  613. * log warning to console if the rendering of one frame has not been started / handy to check for async problems
  614. * @function checkFrameStarted
  615. * @memberof Context
  616. * @param string
  617. * @instance
  618. */
  619. checkFrameStarted(string)
  620. {
  621. if (!this._frameStarted)
  622. {
  623. this._log.warn("frame not started " + string);
  624. this.patch.printTriggerStack();
  625. }
  626. }
  627.  
  628.  
  629. setTexture(slot, t, type)
  630. {
  631. this.checkFrameStarted("cgl setTexture");
  632.  
  633. if (t === null) t = CGL.Texture.getEmptyTexture(this).tex;
  634.  
  635. if (this._textureslots[slot] != t)
  636. {
  637. this.gl.activeTexture(this.gl.TEXTURE0 + slot);
  638. this.gl.bindTexture(type || this.gl.TEXTURE_2D, t);
  639. this._textureslots[slot] = t;
  640. }
  641.  
  642.  
  643. return true;
  644. }
  645.  
  646. fullScreen()
  647. {
  648. if (this.canvas.requestFullscreen) this.canvas.requestFullscreen();
  649. else if (this.canvas.mozRequestFullScreen) this.canvas.mozRequestFullScreen();
  650. else if (this.canvas.webkitRequestFullscreen) this.canvas.webkitRequestFullscreen();
  651. else if (this.canvas.msRequestFullscreen) this.canvas.msRequestFullscreen();
  652. }
  653.  
  654.  
  655. printError(str)
  656. {
  657. if (!this.checkGlErrors) return;
  658. let found = false;
  659. let error = this.gl.getError();
  660.  
  661. if (error != this.gl.NO_ERROR)
  662. {
  663. let errStr = "";
  664. if (error == this.gl.OUT_OF_MEMORY) errStr = "OUT_OF_MEMORY";
  665. if (error == this.gl.INVALID_ENUM) errStr = "INVALID_ENUM";
  666. if (error == this.gl.INVALID_OPERATION) errStr = "INVALID_OPERATION";
  667. if (error == this.gl.INVALID_FRAMEBUFFER_OPERATION) errStr = "INVALID_FRAMEBUFFER_OPERATION";
  668. if (error == this.gl.INVALID_VALUE) errStr = "INVALID_VALUE";
  669. if (error == this.gl.CONTEXT_LOST_WEBGL)
  670. {
  671. this.aborted = true;
  672. errStr = "CONTEXT_LOST_WEBGL";
  673. }
  674. if (error == this.gl.NO_ERROR) errStr = "NO_ERROR";
  675.  
  676. found = true;
  677.  
  678.  
  679. this._log.warn("gl error [" + this.canvas.id + "]: ", str, error, errStr);
  680.  
  681. if (this.canvas.id.contains("glGuiCanvas"))
  682. if (!this._loggedGlError)
  683. {
  684. this.patch.printTriggerStack();
  685. this._log.stack("glerror");
  686. this._loggedGlError = true;
  687. }
  688. }
  689. error = this.gl.getError();
  690.  
  691. return found;
  692. }
  693.  
  694. saveScreenshot(filename, cb, pw, ph, noclearalpha)
  695. {
  696. this.patch.renderOneFrame();
  697.  
  698. let w = this.canvas.clientWidth * this.pixelDensity;
  699. let h = this.canvas.clientHeight * this.pixelDensity;
  700.  
  701. if (pw)
  702. {
  703. this.canvas.width = pw;
  704. w = pw;
  705. }
  706. if (ph)
  707. {
  708. this.canvas.height = ph;
  709. h = ph;
  710. }
  711.  
  712. function padLeft(nr, n, str)
  713. {
  714. return Array(n - String(nr).length + 1).join(str || "0") + nr;
  715. }
  716.  
  717. const d = new Date();
  718.  
  719. const dateStr = "".concat(String(d.getFullYear()) + String(d.getMonth() + 1) + String(d.getDate()), "_").concat(padLeft(d.getHours(), 2)).concat(padLeft(d.getMinutes(), 2)).concat(padLeft(d.getSeconds(), 2));
  720.  
  721. if (!filename) filename = "cables_" + dateStr + ".png";
  722. else filename += ".png";
  723.  
  724. this.patch.cgl.screenShot(function (blob)
  725. {
  726. this.canvas.width = w;
  727. this.canvas.height = h;
  728.  
  729. if (blob)
  730. {
  731. const anchor = document.createElement("a");
  732.  
  733. anchor.download = filename;
  734. anchor.href = URL.createObjectURL(blob);
  735.  
  736. setTimeout(function ()
  737. {
  738. anchor.click();
  739. if (cb) cb(blob);
  740. }, 100);
  741. }
  742. else
  743. {
  744. this._log.log("screenshot: no blob");
  745. }
  746. }.bind(this), noclearalpha);
  747. }
  748.  
  749. _dispose()
  750. {
  751. this._simpleShader.dispose();
  752. this.gl = null;
  753. }
  754. }
  755.  
  756.  
  757. Context.prototype.popShader = Context.prototype.setPreviousShader;
  758. Context.prototype.setShader = Context.prototype.pushShader;
  759.  
  760. /**
  761. * execute the callback next frame, once
  762. * @function addNextFrameOnceCallback
  763. * @memberof Context
  764. * @instance
  765. * @param {function} cb
  766. */
  767. Context.prototype.addNextFrameOnceCallback = function (cb)
  768. {
  769. if (cb && this._onetimeCallbacks.indexOf(cb) == -1) this._onetimeCallbacks.push(cb);
  770. };
  771.  
  772. // state depthtest
  773.  
  774. /**
  775. * push depth testing enabled state
  776. * @function pushDepthTest
  777. * @param {Boolean} enabled
  778. * @memberof Context
  779. * @instance
  780. */
  781. Context.prototype._stackDepthTest = [];
  782. Context.prototype.pushDepthTest = function (b)
  783. {
  784. this._stackDepthTest.push(b);
  785. if (!b) this.gl.disable(this.gl.DEPTH_TEST);
  786. else this.gl.enable(this.gl.DEPTH_TEST);
  787. };
  788. /**
  789. * current state of depth testing
  790. * @function stateCullFace
  791. * @returns {Boolean} enabled
  792. * @memberof Context
  793. * @instance
  794. */
  795. Context.prototype.stateDepthTest = function ()
  796. {
  797. return this._stackDepthTest[this._stackDepthTest.length - 1];
  798. };
  799.  
  800. /**
  801. * pop depth testing state
  802. * @function popCullFace
  803. * @memberof Context
  804. * @instance
  805. */
  806. Context.prototype.popDepthTest = function ()
  807. {
  808. this._stackDepthTest.pop();
  809.  
  810. if (!this._stackDepthTest[this._stackDepthTest.length - 1]) this.gl.disable(this.gl.DEPTH_TEST);
  811. else this.gl.enable(this.gl.DEPTH_TEST);
  812. };
  813.  
  814. // --------------------------------------
  815. // state depthwrite
  816.  
  817. /**
  818. * push depth write enabled state
  819. * @function pushDepthTest
  820. * @param {Boolean} enabled
  821. * @memberof Context
  822. * @instance
  823. */
  824. Context.prototype._stackDepthWrite = [];
  825. Context.prototype.pushDepthWrite = function (b)
  826. {
  827. b = b || false;
  828. this._stackDepthWrite.push(b);
  829. this.gl.depthMask(b);
  830. };
  831.  
  832. /**
  833. * current state of depth writing
  834. * @function stateDepthWrite
  835. * @returns {Boolean} enabled
  836. * @memberof Context
  837. * @instance
  838. */
  839. Context.prototype.stateDepthWrite = function ()
  840. {
  841. return this._stackDepthWrite[this._stackDepthWrite.length - 1];
  842. };
  843.  
  844. /**
  845. * pop depth writing state
  846. * @function popDepthWrite
  847. * @memberof Context
  848. * @instance
  849. */
  850. Context.prototype.popDepthWrite = function ()
  851. {
  852. this._stackDepthWrite.pop();
  853. this.gl.depthMask(this._stackDepthWrite[this._stackDepthWrite.length - 1] || false);
  854. };
  855.  
  856.  
  857. // --------------------------------------
  858. // state CullFace
  859.  
  860. Context.prototype._stackCullFace = [];
  861.  
  862. /**
  863. * push face culling face enabled state
  864. * @function pushCullFace
  865. * @param {Boolean} b enabled
  866. * @memberof Context
  867. * @instance
  868. */
  869. Context.prototype.pushCullFace = function (b)
  870. {
  871. this._stackCullFace.push(b);
  872.  
  873. if (b) this.gl.enable(this.gl.CULL_FACE);
  874. else this.gl.disable(this.gl.CULL_FACE);
  875. };
  876.  
  877. /**
  878. * current state of face culling
  879. * @function stateCullFace
  880. * @returns {Boolean} enabled
  881. * @memberof Context
  882. * @instance
  883. */
  884. Context.prototype.stateCullFace = function ()
  885. {
  886. return this._stackCullFace[this._stackCullFace.length - 1];
  887. };
  888.  
  889. /**
  890. * pop face culling enabled state
  891. * @function popCullFace
  892. * @memberof Context
  893. * @instance
  894. */
  895. Context.prototype.popCullFace = function ()
  896. {
  897. this._stackCullFace.pop();
  898.  
  899. if (this._stackCullFace[this._stackCullFace.length - 1]) this.gl.enable(this.gl.CULL_FACE);
  900. else this.gl.disable(this.gl.CULL_FACE);
  901. };
  902.  
  903.  
  904. // --------------------------------------
  905. // state CullFace Facing
  906.  
  907.  
  908. /**
  909. * push face culling face side
  910. * @function pushCullFaceFacing
  911. * @param {Number} cgl.gl.FRONT_AND_BACK, cgl.gl.BACK or cgl.gl.FRONT
  912. * @memberof Context
  913. * @instance
  914. */
  915. Context.prototype._stackCullFaceFacing = [];
  916. Context.prototype.pushCullFaceFacing = function (b)
  917. {
  918. this._stackCullFaceFacing.push(b);
  919. this.gl.cullFace(this._stackCullFaceFacing[this._stackCullFaceFacing.length - 1]);
  920. };
  921.  
  922. /**
  923. * current state of face culling side
  924. * @function stateCullFaceFacing
  925. * @returns {Boolean} enabled
  926. * @memberof Context
  927. * @instance
  928. */
  929. Context.prototype.stateCullFaceFacing = function ()
  930. {
  931. return this._stackCullFaceFacing[this._stackCullFaceFacing.length - 1];
  932. };
  933.  
  934. /**
  935. * pop face culling face side
  936. * @function popCullFaceFacing
  937. * @memberof Context
  938. * @instance
  939. */
  940. Context.prototype.popCullFaceFacing = function ()
  941. {
  942. this._stackCullFaceFacing.pop();
  943. if (this._stackCullFaceFacing.length > 0) this.gl.cullFace(this._stackCullFaceFacing[this._stackCullFaceFacing.length - 1]);
  944. };
  945.  
  946.  
  947. // --------------------------------------
  948. // state depthfunc
  949.  
  950. Context.prototype._stackDepthFunc = [];
  951.  
  952. /**
  953. * enable / disable depth testing
  954. * like `gl.depthFunc(boolean);`
  955. * @function pushDepthFunc
  956. * @memberof Context
  957. * @instance
  958. * @param {Boolean} f depthtesting
  959. */
  960. Context.prototype.pushDepthFunc = function (f)
  961. {
  962. this._stackDepthFunc.push(f);
  963. this.gl.depthFunc(f);
  964. };
  965.  
  966. /**
  967. * current state of blend
  968. * @function stateDepthFunc
  969. * @memberof Context
  970. * @instance
  971. * @returns {Boolean} depth testing enabled/disabled
  972. */
  973. Context.prototype.stateDepthFunc = function ()
  974. {
  975. if (this._stackDepthFunc.length > 0) return this._stackDepthFunc[this._stackDepthFunc.length - 1];
  976. return false;
  977. };
  978.  
  979. /**
  980. * pop depth testing and set the previous state
  981. * @function popDepthFunc
  982. * @memberof Context
  983. * @instance
  984. */
  985. Context.prototype.popDepthFunc = function ()
  986. {
  987. this._stackDepthFunc.pop();
  988. if (this._stackDepthFunc.length > 0) this.gl.depthFunc(this._stackDepthFunc[this._stackDepthFunc.length - 1]);
  989. };
  990.  
  991. // --------------------------------------
  992. // state blending
  993.  
  994. Context.prototype._stackBlend = [];
  995.  
  996. /**
  997. * enable / disable blend
  998. * like gl.enable(gl.BLEND); / gl.disable(gl.BLEND);
  999. * @function pushBlend
  1000. * @memberof Context
  1001. * @instance
  1002. * @param {boolean} b blending
  1003. */
  1004. Context.prototype.pushBlend = function (b)
  1005. {
  1006. this._stackBlend.push(b);
  1007. if (!b) this.gl.disable(this.gl.BLEND);
  1008. else this.gl.enable(this.gl.BLEND);
  1009. };
  1010.  
  1011. /**
  1012. * pop blend state and set the previous state
  1013. * @function popBlend
  1014. * @memberof Context
  1015. * @instance
  1016. */
  1017. Context.prototype.popBlend = function ()
  1018. {
  1019. this._stackBlend.pop();
  1020.  
  1021. if (!this._stackBlend[this._stackBlend.length - 1]) this.gl.disable(this.gl.BLEND);
  1022. else this.gl.enable(this.gl.BLEND);
  1023. };
  1024.  
  1025. /**
  1026. * current state of blend
  1027. * @function stateBlend
  1028. * @returns {boolean} blending enabled/disabled
  1029. * @memberof Context
  1030. * @instance
  1031. */
  1032. Context.prototype.stateBlend = function ()
  1033. {
  1034. return this._stackBlend[this._stackBlend.length - 1];
  1035. };
  1036.  
  1037. export const BLENDS = {
  1038. "BLEND_NONE": 0,
  1039. "BLEND_NORMAL": 1,
  1040. "BLEND_ADD": 2,
  1041. "BLEND_SUB": 3,
  1042. "BLEND_MUL": 4,
  1043. };
  1044.  
  1045. Context.prototype._stackBlendMode = [];
  1046. Context.prototype._stackBlendModePremul = [];
  1047.  
  1048. /**
  1049. * push and switch to predefined blendmode (CONSTANTS.BLEND_MODES.BLEND_NONE,CONSTANTS.BLEND_MODES.BLEND_NORMAL,CONSTANTS.BLEND_MODES.BLEND_ADD,CONSTANTS.BLEND_MODES.BLEND_SUB,CONSTANTS.BLEND_MODES.BLEND_MUL)
  1050. * @function pushBlendMode
  1051. * @memberof Context
  1052. * @instance
  1053. * @param {Number} blendMode
  1054. * @param {Boolean} premul premultiplied mode
  1055. */
  1056. Context.prototype.pushBlendMode = function (blendMode, premul)
  1057. {
  1058. this._stackBlendMode.push(blendMode);
  1059. this._stackBlendModePremul.push(premul);
  1060.  
  1061. const n = this._stackBlendMode.length - 1;
  1062.  
  1063. this.pushBlend(this._stackBlendMode[n] !== CONSTANTS.BLEND_MODES.BLEND_NONE);
  1064. this._setBlendMode(this._stackBlendMode[n], this._stackBlendModePremul[n]);
  1065. };
  1066.  
  1067. /**
  1068. * pop predefined blendmode / switch back to previous blendmode
  1069. * @function popBlendMode
  1070. * @memberof Context
  1071. * @instance
  1072. */
  1073. Context.prototype.popBlendMode = function ()
  1074. {
  1075. this._stackBlendMode.pop();
  1076. this._stackBlendModePremul.pop();
  1077.  
  1078. const n = this._stackBlendMode.length - 1;
  1079.  
  1080. this.popBlend(this._stackBlendMode[n] !== CONSTANTS.BLEND_MODES.BLEND_NONE);
  1081.  
  1082. if (n >= 0) this._setBlendMode(this._stackBlendMode[n], this._stackBlendModePremul[n]);
  1083. };
  1084.  
  1085.  
  1086. // --------------------------------------
  1087. // state stencil
  1088.  
  1089. Context.prototype._stackStencil = [];
  1090.  
  1091. /**
  1092. * enable / disable stencil testing
  1093.  
  1094. * @function pushStencil
  1095. * @memberof Context
  1096. * @instance
  1097. * @param {Boolean} b enable
  1098. */
  1099. Context.prototype.pushStencil = function (b)
  1100. {
  1101. this._stackStencil.push(b);
  1102. if (!b) this.gl.disable(this.gl.STENCIL_TEST);
  1103. else this.gl.enable(this.gl.STENCIL_TEST);
  1104. };
  1105.  
  1106. /**
  1107. * pop stencil test state and set the previous state
  1108. * @function popStencil
  1109. * @memberof Context
  1110. * @instance
  1111. */
  1112. Context.prototype.popStencil = function ()
  1113. {
  1114. this._stackStencil.pop();
  1115.  
  1116. if (!this._stackStencil[this._stackStencil.length - 1]) this.gl.disable(this.gl.STENCIL_TEST);
  1117. else this.gl.enable(this.gl.STENCIL_TEST);
  1118. };
  1119.  
  1120. // --------------------------------------
  1121.  
  1122.  
  1123. Context.prototype.glGetAttribLocation = function (prog, name)
  1124. {
  1125. const l = this.gl.getAttribLocation(prog, name);
  1126. // if (l == -1)
  1127. // {
  1128. // this._log.warn("get attr loc -1 ", name);
  1129. // }
  1130. return l;
  1131. };
  1132.  
  1133.  
  1134. /**
  1135. * should an op now draw helpermeshes
  1136. * @function shouldDrawHelpers
  1137. * @memberof Context
  1138. * @param op
  1139. * @instance
  1140. */
  1141. Context.prototype.shouldDrawHelpers = function (op)
  1142. {
  1143. if (this.tempData.shadowPass) return false;
  1144. if (!op.patch.isEditorMode()) return false;
  1145.  
  1146. // const fb = this.getCurrentFrameBuffer();
  1147. // if (fb && fb.getWidth)
  1148. // {
  1149. // const fbshould = this.canvasWidth / this.canvasHeight == fb.getWidth() / fb.getHeight();
  1150. // if (!fbshould) return false;
  1151. // }
  1152.  
  1153. return gui.shouldDrawOverlay;// || (CABLES.UI.renderHelperCurrent && op.isCurrentUiOp());
  1154. };
  1155.  
  1156. Context.prototype._setBlendMode = function (blendMode, premul)
  1157. {
  1158. const gl = this.gl;
  1159.  
  1160. if (blendMode == CONSTANTS.BLEND_MODES.BLEND_NONE)
  1161. {
  1162. // this.gl.disable(this.gl.BLEND);
  1163. }
  1164. else if (blendMode == CONSTANTS.BLEND_MODES.BLEND_ADD)
  1165. {
  1166. if (premul)
  1167. {
  1168. gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD);
  1169. gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.ONE);
  1170. }
  1171. else
  1172. {
  1173. gl.blendEquation(gl.FUNC_ADD);
  1174. gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
  1175. }
  1176. }
  1177. else if (blendMode == CONSTANTS.BLEND_MODES.BLEND_SUB)
  1178. {
  1179. if (premul)
  1180. {
  1181. gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD);
  1182. gl.blendFuncSeparate(gl.ZERO, gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ONE_MINUS_SRC_ALPHA);
  1183. }
  1184. else
  1185. {
  1186. gl.blendEquation(gl.FUNC_ADD);
  1187. gl.blendFunc(gl.ZERO, gl.ONE_MINUS_SRC_COLOR);
  1188. }
  1189. }
  1190. else if (blendMode == CONSTANTS.BLEND_MODES.BLEND_MUL)
  1191. {
  1192. if (premul)
  1193. {
  1194. gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD);
  1195. gl.blendFuncSeparate(gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA);
  1196. }
  1197. else
  1198. {
  1199. gl.blendEquation(gl.FUNC_ADD);
  1200. gl.blendFunc(gl.ZERO, gl.SRC_COLOR);
  1201. }
  1202. }
  1203. else if (blendMode == CONSTANTS.BLEND_MODES.BLEND_NORMAL)
  1204. {
  1205. if (premul)
  1206. {
  1207. gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD);
  1208. gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  1209. }
  1210. else
  1211. {
  1212. gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD);
  1213. gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  1214. }
  1215. }
  1216. else
  1217. {
  1218. this._log.log("setblendmode: unknown blendmode");
  1219. }
  1220. };
  1221.  
  1222. Context.prototype.createMesh = function (geom, options)
  1223. {
  1224. if (CABLES.UTILS.isNumeric(options))options = { "glPrimitive": options }; // old constructor fallback...
  1225. return new CGL.Mesh(this, geom, options);
  1226. };
  1227.  
  1228.  
  1229. /**
  1230. * set cursor
  1231. * @function setCursor
  1232. * @memberof Context
  1233. * @instance
  1234. * @param {String} str css cursor string
  1235. */
  1236. Context.prototype.setCursor = function (str)
  1237. {
  1238. this._cursor = str;
  1239. };
  1240.  
  1241. /**
  1242. * enable a webgl extension
  1243. * @function enableExtension
  1244. * @memberof Context
  1245. * @instance
  1246. * @param {String} name extension name
  1247. * @returns {Object} extension object or null
  1248. */
  1249. Context.prototype.enableExtension = function (name)
  1250. {
  1251. if (!this.gl) return null;
  1252.  
  1253. if (this._enabledExtensions.hasOwnProperty(name))
  1254. return this._enabledExtensions[name];
  1255.  
  1256. const o = this.gl.getExtension(name);
  1257. this._enabledExtensions[name] = o;
  1258.  
  1259. if (!o)
  1260. this._log.warn("[cgl_state] extension not available " + name);
  1261. // else
  1262. // this._log.log("enabled extension", name);
  1263.  
  1264. return o;
  1265. };
  1266.  
  1267. Context.prototype.checkTextureSize = function (x)
  1268. {
  1269. x = x || 1;
  1270. x = Math.floor(x);
  1271. x = Math.min(x, this.maxTexSize);
  1272. x = Math.max(x, 1);
  1273. return x;
  1274. };
  1275.  
  1276.  
  1277. export { Context };
  1278.