You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

146 lines
4.0 KiB
JavaScript

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 Framebuffer from "../Renderer/Framebuffer.js";
import PassState from "../Renderer/PassState.js";
import Renderbuffer from "../Renderer/Renderbuffer.js";
import RenderbufferFormat from "../Renderer/RenderbufferFormat.js";
import Texture from "../Renderer/Texture.js";
/**
* @private
*/
function PickFramebuffer(context) {
// Override per-command states
var passState = new PassState(context);
passState.blendingEnabled = false;
passState.scissorTest = {
enabled: true,
rectangle: new BoundingRectangle(),
};
passState.viewport = new BoundingRectangle();
this._context = context;
this._fb = undefined;
this._passState = passState;
this._width = 0;
this._height = 0;
}
PickFramebuffer.prototype.begin = function (screenSpaceRectangle, viewport) {
var context = this._context;
var width = viewport.width;
var height = viewport.height;
BoundingRectangle.clone(
screenSpaceRectangle,
this._passState.scissorTest.rectangle
);
// Initially create or recreate renderbuffers and framebuffer used for picking
if (!defined(this._fb) || this._width !== width || this._height !== height) {
this._width = width;
this._height = height;
this._fb = this._fb && this._fb.destroy();
this._fb = new Framebuffer({
context: context,
colorTextures: [
new Texture({
context: context,
width: width,
height: height,
}),
],
depthStencilRenderbuffer: new Renderbuffer({
context: context,
width: width,
height: height,
format: RenderbufferFormat.DEPTH_STENCIL,
}),
});
this._passState.framebuffer = this._fb;
}
this._passState.viewport.width = width;
this._passState.viewport.height = height;
return this._passState;
};
var colorScratch = new Color();
PickFramebuffer.prototype.end = function (screenSpaceRectangle) {
var width = defaultValue(screenSpaceRectangle.width, 1.0);
var height = defaultValue(screenSpaceRectangle.height, 1.0);
var context = this._context;
var pixels = context.readPixels({
x: screenSpaceRectangle.x,
y: screenSpaceRectangle.y,
width: width,
height: height,
framebuffer: this._fb,
});
var max = Math.max(width, height);
var length = max * max;
var halfWidth = Math.floor(width * 0.5);
var halfHeight = Math.floor(height * 0.5);
var x = 0;
var y = 0;
var dx = 0;
var 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 (var i = 0; i < length; ++i) {
if (
-halfWidth <= x &&
x <= halfWidth &&
-halfHeight <= y &&
y <= halfHeight
) {
var 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]);
var 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)) {
var temp = dx;
dx = -dy;
dy = temp;
}
x += dx;
y += dy;
}
return undefined;
};
PickFramebuffer.prototype.isDestroyed = function () {
return false;
};
PickFramebuffer.prototype.destroy = function () {
this._fb = this._fb && this._fb.destroy();
return destroyObject(this);
};
export default PickFramebuffer;