Flatlogic Bot 055d24df95 WORKING
2025-10-14 02:37:44 +00:00

161 lines
4.5 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 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, height } = viewport;
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();
/**
* Return the picked object rendered within a given rectangle.
*
* @param {BoundingRectangle} screenSpaceRectangle
* @returns {object|undefined} The object rendered in the middle of the rectangle, or undefined if nothing was rendered.
*/
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;
};
/**
* Return voxel tile and sample information as rendered by a pickVoxel pass,
* within a given rectangle.
*
* @param {BoundingRectangle} screenSpaceRectangle
* @returns {TypedArray}
*/
PickFramebuffer.prototype.readVoxelInfo = 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,
});
// Read the center pixel
const halfWidth = Math.floor(width * 0.5);
const halfHeight = Math.floor(height * 0.5);
const index = 4 * (halfHeight * width + halfWidth);
return pixels.slice(index, index + 4);
};
PickFramebuffer.prototype.isDestroyed = function () {
return false;
};
PickFramebuffer.prototype.destroy = function () {
this._fb.destroy();
return destroyObject(this);
};
export default PickFramebuffer;