| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 | import BoundingRectangle from "../Core/BoundingRectangle.js";import Color from "../Core/Color.js";import defaultValue from "../Core/defaultValue.js";import defined from "../Core/defined.js";import destroyObject from "../Core/destroyObject.js";import FramebufferManager from "../Renderer/FramebufferManager.js";import PassState from "../Renderer/PassState.js";/** * @private */function PickFramebuffer(context) {  // Override per-command states  const passState = new PassState(context);  passState.blendingEnabled = false;  passState.scissorTest = {    enabled: true,    rectangle: new BoundingRectangle(),  };  passState.viewport = new BoundingRectangle();  this._context = context;  this._fb = new FramebufferManager({    depthStencil: true,  });  this._passState = passState;  this._width = 0;  this._height = 0;}PickFramebuffer.prototype.begin = function (screenSpaceRectangle, viewport) {  const context = this._context;  const width = viewport.width;  const height = viewport.height;  BoundingRectangle.clone(    screenSpaceRectangle,    this._passState.scissorTest.rectangle  );  // Create or recreate renderbuffers and framebuffer used for picking  this._width = width;  this._height = height;  this._fb.update(context, width, height);  this._passState.framebuffer = this._fb.framebuffer;  this._passState.viewport.width = width;  this._passState.viewport.height = height;  return this._passState;};const colorScratch = new Color();PickFramebuffer.prototype.end = function (screenSpaceRectangle) {  const width = defaultValue(screenSpaceRectangle.width, 1.0);  const height = defaultValue(screenSpaceRectangle.height, 1.0);  const context = this._context;  const pixels = context.readPixels({    x: screenSpaceRectangle.x,    y: screenSpaceRectangle.y,    width: width,    height: height,    framebuffer: this._fb.framebuffer,  });  const max = Math.max(width, height);  const length = max * max;  const halfWidth = Math.floor(width * 0.5);  const halfHeight = Math.floor(height * 0.5);  let x = 0;  let y = 0;  let dx = 0;  let dy = -1;  // Spiral around the center pixel, this is a workaround until  // we can access the depth buffer on all browsers.  // The region does not have to square and the dimensions do not have to be odd, but  // loop iterations would be wasted. Prefer square regions where the size is odd.  for (let i = 0; i < length; ++i) {    if (      -halfWidth <= x &&      x <= halfWidth &&      -halfHeight <= y &&      y <= halfHeight    ) {      const index = 4 * ((halfHeight - y) * width + x + halfWidth);      colorScratch.red = Color.byteToFloat(pixels[index]);      colorScratch.green = Color.byteToFloat(pixels[index + 1]);      colorScratch.blue = Color.byteToFloat(pixels[index + 2]);      colorScratch.alpha = Color.byteToFloat(pixels[index + 3]);      const object = context.getObjectByPickColor(colorScratch);      if (defined(object)) {        return object;      }    }    // if (top right || bottom left corners) || (top left corner) || (bottom right corner + (1, 0))    // change spiral direction    if (x === y || (x < 0 && -x === y) || (x > 0 && x === 1 - y)) {      const temp = dx;      dx = -dy;      dy = temp;    }    x += dx;    y += dy;  }  return undefined;};PickFramebuffer.prototype.isDestroyed = function () {  return false;};PickFramebuffer.prototype.destroy = function () {  this._fb.destroy();  return destroyObject(this);};export default PickFramebuffer;
 |