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;
|