JAVASCRIPT   79

context.js

Guest on 22nd July 2021 12:06:36 PM

  1. goog.provide('ol.webgl.Context');
  2.  
  3. goog.require('goog.array');
  4. goog.require('goog.asserts');
  5. goog.require('goog.events');
  6. goog.require('goog.log');
  7. goog.require('goog.object');
  8. goog.require('ol');
  9. goog.require('ol.webgl.Buffer');
  10. goog.require('ol.webgl.WebGLContextEventType');
  11.  
  12.  
  13. /**
  14.  * @typedef {{buf: ol.webgl.Buffer,
  15.  *            buffer: WebGLBuffer}}
  16.  */
  17. ol.webgl.BufferCacheEntry;
  18.  
  19.  
  20.  
  21. /**
  22.  * @classdesc
  23.  * A WebGL context for accessing low-level WebGL capabilities.
  24.  *
  25.  * @constructor
  26.  * @extends {goog.events.EventTarget}
  27.  * @param {HTMLCanvasElement} canvas Canvas.
  28.  * @param {WebGLRenderingContext} gl GL.
  29.  * @api
  30.  */
  31. ol.webgl.Context = function(canvas, gl) {
  32.  
  33.   /**
  34.    * @private
  35.    * @type {HTMLCanvasElement}
  36.    */
  37.   this.canvas_ = canvas;
  38.  
  39.   /**
  40.    * @private
  41.    * @type {WebGLRenderingContext}
  42.    */
  43.   this.gl_ = gl;
  44.  
  45.   /**
  46.    * @private
  47.    * @type {Object.<number, ol.webgl.BufferCacheEntry>}
  48.    */
  49.   this.bufferCache_ = {};
  50.  
  51.   /**
  52.    * @private
  53.    * @type {Object.<number, WebGLShader>}
  54.    */
  55.   this.shaderCache_ = {};
  56.  
  57.   /**
  58.    * @private
  59.    * @type {Object.<string, WebGLProgram>}
  60.    */
  61.   this.programCache_ = {};
  62.  
  63.   /**
  64.    * @private
  65.    * @type {WebGLProgram}
  66.    */
  67.   this.currentProgram_ = null;
  68.  
  69.   /**
  70.    * @private
  71.    * @type {WebGLFramebuffer}
  72.    */
  73.   this.hitDetectionFramebuffer_ = null;
  74.  
  75.   /**
  76.    * @private
  77.    * @type {WebGLTexture}
  78.    */
  79.   this.hitDetectionTexture_ = null;
  80.  
  81.   /**
  82.    * @private
  83.    * @type {WebGLRenderbuffer}
  84.    */
  85.   this.hitDetectionRenderbuffer_ = null;
  86.  
  87.   /**
  88.    * @type {boolean}
  89.    */
  90.   this.hasOESElementIndexUint = goog.array.contains(
  91.       ol.WEBGL_EXTENSIONS, 'OES_element_index_uint');
  92.  
  93.   // use the OES_element_index_uint extension if available
  94.   if (this.hasOESElementIndexUint) {
  95.     var ext = gl.getExtension('OES_element_index_uint');
  96.     goog.asserts.assert(!goog.isNull(ext));
  97.   }
  98.  
  99.   goog.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.LOST,
  100.       this.handleWebGLContextLost, false, this);
  101.   goog.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.RESTORED,
  102.       this.handleWebGLContextRestored, false, this);
  103.  
  104. };
  105.  
  106.  
  107. /**
  108.  * Just bind the buffer if it's in the cache. Otherwise create
  109.  * the WebGL buffer, bind it, populate it, and add an entry to
  110.  * the cache.
  111.  * @param {number} target Target.
  112.  * @param {ol.webgl.Buffer} buf Buffer.
  113.  */
  114. ol.webgl.Context.prototype.bindBuffer = function(target, buf) {
  115.   var gl = this.getGL();
  116.   var arr = buf.getArray();
  117.   var bufferKey = goog.getUid(buf);
  118.   if (bufferKey in this.bufferCache_) {
  119.     var bufferCacheEntry = this.bufferCache_[bufferKey];
  120.     gl.bindBuffer(target, bufferCacheEntry.buffer);
  121.   } else {
  122.     var buffer = gl.createBuffer();
  123.     gl.bindBuffer(target, buffer);
  124.     goog.asserts.assert(target == goog.webgl.ARRAY_BUFFER ||
  125.         target == goog.webgl.ELEMENT_ARRAY_BUFFER);
  126.     var /** @type {ArrayBufferView} */ arrayBuffer;
  127.     if (target == goog.webgl.ARRAY_BUFFER) {
  128.       arrayBuffer = new Float32Array(arr);
  129.     } else if (target == goog.webgl.ELEMENT_ARRAY_BUFFER) {
  130.       arrayBuffer = this.hasOESElementIndexUint ?
  131.           new Uint32Array(arr) : new Uint16Array(arr);
  132.     } else {
  133.       goog.asserts.fail();
  134.     }
  135.     gl.bufferData(target, arrayBuffer, buf.getUsage());
  136.     this.bufferCache_[bufferKey] = {
  137.       buf: buf,
  138.       buffer: buffer
  139.     };
  140.   }
  141. };
  142.  
  143.  
  144. /**
  145.  * @param {ol.webgl.Buffer} buf Buffer.
  146.  */
  147. ol.webgl.Context.prototype.deleteBuffer = function(buf) {
  148.   var gl = this.getGL();
  149.   var bufferKey = goog.getUid(buf);
  150.   goog.asserts.assert(bufferKey in this.bufferCache_);
  151.   var bufferCacheEntry = this.bufferCache_[bufferKey];
  152.   if (!gl.isContextLost()) {
  153.     gl.deleteBuffer(bufferCacheEntry.buffer);
  154.   }
  155.   delete this.bufferCache_[bufferKey];
  156. };
  157.  
  158.  
  159. /**
  160.  * @inheritDoc
  161.  */
  162. ol.webgl.Context.prototype.disposeInternal = function() {
  163.   var gl = this.getGL();
  164.   if (!gl.isContextLost()) {
  165.     goog.object.forEach(this.bufferCache_, function(bufferCacheEntry) {
  166.       gl.deleteBuffer(bufferCacheEntry.buffer);
  167.     });
  168.     goog.object.forEach(this.programCache_, function(program) {
  169.       gl.deleteProgram(program);
  170.     });
  171.     goog.object.forEach(this.shaderCache_, function(shader) {
  172.       gl.deleteShader(shader);
  173.     });
  174.     // delete objects for hit-detection
  175.     gl.deleteFramebuffer(this.hitDetectionFramebuffer_);
  176.     gl.deleteRenderbuffer(this.hitDetectionRenderbuffer_);
  177.     gl.deleteTexture(this.hitDetectionTexture_);
  178.   }
  179. };
  180.  
  181.  
  182. /**
  183.  * @return {HTMLCanvasElement} Canvas.
  184.  */
  185. ol.webgl.Context.prototype.getCanvas = function() {
  186.   return this.canvas_;
  187. };
  188.  
  189.  
  190. /**
  191.  * @return {WebGLRenderingContext} GL.
  192.  * @api
  193.  */
  194. ol.webgl.Context.prototype.getGL = function() {
  195.   return this.gl_;
  196. };
  197.  
  198.  
  199. /**
  200.  * @return {WebGLFramebuffer} The framebuffer for the hit-detection.
  201.  * @api
  202.  */
  203. ol.webgl.Context.prototype.getHitDetectionFramebuffer = function() {
  204.   if (goog.isNull(this.hitDetectionFramebuffer_)) {
  205.     this.initHitDetectionFramebuffer_();
  206.   }
  207.   return this.hitDetectionFramebuffer_;
  208. };
  209.  
  210.  
  211. /**
  212.  * Get shader from the cache if it's in the cache. Otherwise, create
  213.  * the WebGLĀ shader, compile it, and add entry to cache.
  214.  * @param {ol.webgl.Shader} shaderObject Shader object.
  215.  * @return {WebGLShader} Shader.
  216.  *//
  217. ol.webgl.Context.prototype.getShader = function(shaderObject) {
  218.   var shaderKey = goog.getUid(shaderObject);
  219.   if (shaderKey in this.shaderCache_) {
  220.     return this.shaderCache_[shaderKey];
  221.   } else {
  222.     var gl = this.getGL();
  223.     var shader = gl.createShader(shaderObject.getType());
  224.     gl.shaderSource(shader, shaderObject.getSource());
  225.     gl.compileShader(shader);
  226.     if (goog.DEBUG) {
  227.       if (!gl.getShaderParameter(shader, goog.webgl.COMPILE_STATUS) &&
  228.           !gl.isContextLost()) {
  229.         goog.log.error(this.logger_, gl.getShaderInfoLog(shader));
  230.       }
  231.     }
  232.     goog.asserts.assert(
  233.         gl.getShaderParameter(shader, goog.webgl.COMPILE_STATUS) ||
  234.         gl.isContextLost());
  235.     this.shaderCache_[shaderKey] = shader;
  236.     return shader;
  237.   }
  238. };
  239.  
  240. /**
  241.  * Get the program from the cache if it's in the cache. Otherwise create
  242.  * the WebGLĀ program, attach the shaders to it, and add an entry to the
  243.  * cache.
  244.  * @param {ol.webgl.shader.Fragment} fragmentShaderObject Fragment shader.
  245.  * @param {ol.webgl.shader.Vertex} vertexShaderObject Vertex shader.
  246.  * @return {WebGLProgram} Program.
  247.  */*/
  248. ol.webgl.Context.prototype.getProgram = function(
  249.     fragmentShaderObject, vertexShaderObject) {
  250.   var programKey =
  251.       goog.getUid(fragmentShaderObject) + ' + goog.getUid(vertexShaderObject);
  252.  if (programKey in this.programCache_) {
  253.    return this.programCache_[programKey];
  254.  } else {
  255.    var gl = this.getGL();
  256.    var program = gl.createProgram();
  257.    gl.attachShader(program, this.getShader(fragmentShaderObject));
  258.    gl.attachShader(program, this.getShader(vertexShaderObject));
  259.    gl.linkProgram(program);
  260.    if (goog.DEBUG) {
  261.      if (!gl.getProgramParameter(program, goog.webgl.LINK_STATUS) &&
  262.          !gl.isContextLost()) {
  263.        goog.log.error(this.logger_, gl.getProgramInfoLog(program));
  264.      }
  265.    }
  266.    goog.asserts.assert(
  267.        gl.getProgramParameter(program, goog.webgl.LINK_STATUS) ||
  268.        gl.isContextLost());
  269.    this.programCache_[programKey] = program;
  270.    return program;
  271.  }
  272. };
  273.  
  274.  
  275. /**
  276. * FIXME empy description for jsdoc
  277. */
  278. ol.webgl.Context.prototype.handleWebGLContextLost = function() {
  279.  goog.object.clear(this.bufferCache_);
  280.  goog.object.clear(this.shaderCache_);
  281.  goog.object.clear(this.programCache_);
  282.  this.currentProgram_ = null;
  283.  this.hitDetectionFramebuffer_ = null;
  284.  this.hitDetectionTexture_ = null;
  285.  this.hitDetectionRenderbuffer_ = null;
  286. };
  287.  
  288.  
  289. /**
  290. * FIXME empy description for jsdoc
  291. */
  292. ol.webgl.Context.prototype.handleWebGLContextRestored = function() {
  293. };
  294.  
  295.  
  296. /**
  297. * Creates a 1x1 pixel framebuffer for the hit-detection.
  298. * @private
  299. */
  300. ol.webgl.Context.prototype.initHitDetectionFramebuffer_ = function() {
  301.  var gl = this.gl_;
  302.  var framebuffer = gl.createFramebuffer();
  303.  gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
  304.  
  305.  var texture = ol.webgl.Context.createEmptyTexture(gl, 1, 1);
  306.  var renderbuffer = gl.createRenderbuffer();
  307.  gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
  308.  gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 1, 1);
  309.  gl.framebufferTexture2D(
  310.      gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
  311.  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT,
  312.      gl.RENDERBUFFER, renderbuffer);
  313.  
  314.  gl.bindTexture(gl.TEXTURE_2D, null);
  315.  gl.bindRenderbuffer(gl.RENDERBUFFER, null);
  316.  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  317.  
  318.  this.hitDetectionFramebuffer_ = framebuffer;
  319.  this.hitDetectionTexture_ = texture;
  320.  this.hitDetectionRenderbuffer_ = renderbuffer;
  321. };
  322.  
  323.  
  324. /**
  325. * Just return false if that program is used already. Other use
  326. * that program (call `gl.useProgram`) and make it the "current
  327. * program".
  328. * @param {WebGLProgram} program Program.
  329. * @return {boolean} Changed.
  330. * @api
  331. */
  332. ol.webgl.Context.prototype.useProgram = function(program) {
  333.  if (program == this.currentProgram_) {
  334.    return false;
  335.  } else {
  336.    var gl = this.getGL();
  337.    gl.useProgram(program);
  338.    this.currentProgram_ = program;
  339.    return true;
  340.  }
  341. };
  342.  
  343.  
  344. /**
  345. * @private
  346. * @type {goog.log.Logger}
  347. */
  348. ol.webgl.Context.prototype.logger_ = goog.log.getLogger('('ol.webgl.Context');
  349. /**
  350.  * @param {WebGLRenderingContext} gl WebGL rendering context.
  351.  * @param {number=} opt_wrapS wrapS.
  352.  * @param {number=} opt_wrapT wrapT.
  353.  * @return {WebGLTexture}
  354.  * @private
  355.  */*/
  356. ol.webgl.Context.createTexture_ = function(gl, opt_wrapS, opt_wrapT) {
  357.   var texture = gl.createTexture();
  358.   gl.bindTexture(gl.TEXTURE_2D, texture);
  359.   gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  360.   gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  361.  
  362.   if (goog.isDef(opt_wrapS)) {
  363.     gl.texParameteri(
  364.         goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_S, opt_wrapS);
  365.   }
  366.   if (goog.isDef(opt_wrapT)) {
  367.     gl.texParameteri(
  368.         goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_T, opt_wrapT);
  369.   }
  370.  
  371.   return texture;
  372. };
  373. /**
  374.  * @param {WebGLRenderingContext} gl WebGL rendering context.
  375.  * @param {number} width Width.
  376.  * @param {number} height Height.
  377.  * @param {number=} opt_wrapS wrapS.
  378.  * @param {number=} opt_wrapT wrapT.
  379.  * @return {WebGLTexture}
  380.  */*/
  381. ol.webgl.Context.createEmptyTexture = function(
  382.     gl, width, height, opt_wrapS, opt_wrapT) {
  383.   var texture = ol.webgl.Context.createTexture_(gl, opt_wrapS, opt_wrapT);
  384.   gl.texImage2D(
  385.       gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE,
  386.       null);
  387.  
  388.   return texture;
  389. };
  390. /**
  391.  * @param {WebGLRenderingContext} gl WebGL rendering context.
  392.  * @param {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} image Image.
  393.  * @param {number=} opt_wrapS wrapS.
  394.  * @param {number=} opt_wrapT wrapT.
  395.  * @return {WebGLTexture}
  396.  */*/
  397. ol.webgl.Context.createTexture = function(gl, image, opt_wrapS, opt_wrapT) {
  398.   var texture = ol.webgl.Context.createTexture_(gl, opt_wrapS, opt_wrapT);
  399.   gl.texImage2D(
  400.       gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
  401.  
  402.   return texture;
  403.  

Raw Paste


Login or Register to edit or fork this paste. It's free.