@pirireis/webglobeplugins 1.0.6 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/programs/polygon-on-globe/texture-dem-triangles.js +1 -1
- package/semiplugins/shape-on-terrain/terrain-polygon/data/master-worker.js +4 -2
- package/semiplugins/shape-on-terrain/terrain-polygon/data/worker-contact.js +1 -1
- package/semiplugins/shape-on-terrain/terrain-polygon/terrain-polygon.js +23 -0
- package/util/picking/picker-displayer copy.js +176 -0
- package/util/picking/picker-displayer.js +135 -55
package/package.json
CHANGED
|
@@ -212,7 +212,7 @@ export class TextureDemTriangles {
|
|
|
212
212
|
if (this.globe.api_GetCurrentLODWithDecimal() < 14.5) {
|
|
213
213
|
drawOnTopBegin(gl);
|
|
214
214
|
}
|
|
215
|
-
drawArrays(gl, gl.TRIANGLES, drawOptions);
|
|
215
|
+
drawArrays(gl, drawOptions.drawMode ?? gl.TRIANGLES, drawOptions);
|
|
216
216
|
if (this.globe.api_GetCurrentLODWithDecimal() < 14.5) {
|
|
217
217
|
drawOnTopEnd(gl);
|
|
218
218
|
}
|
|
@@ -18,9 +18,11 @@ function initWorkers() {
|
|
|
18
18
|
addWorker();
|
|
19
19
|
}
|
|
20
20
|
function addWorker() {
|
|
21
|
-
// IMPORTANT:
|
|
21
|
+
// IMPORTANT: keep this extensionless so it resolves to:
|
|
22
|
+
// - ./worker.ts in source builds (when .ts is resolvable)
|
|
23
|
+
// - ./worker.js in published output (tsc emits .js to dist)
|
|
22
24
|
// @ts-ignore
|
|
23
|
-
const worker = new Worker(new URL("./worker
|
|
25
|
+
const worker = new Worker(new URL("./worker", import.meta.url), { type: "module" });
|
|
24
26
|
const wrapper = {
|
|
25
27
|
worker,
|
|
26
28
|
inProgress: false,
|
|
@@ -10,7 +10,7 @@ export class WorkerContact {
|
|
|
10
10
|
this.onResult = onResult;
|
|
11
11
|
// Initialize the Master Worker
|
|
12
12
|
// @ts-ignore
|
|
13
|
-
this._masterWorker = new Worker(new URL("./master-worker
|
|
13
|
+
this._masterWorker = new Worker(new URL("./master-worker", import.meta.url), { type: 'module' });
|
|
14
14
|
this._masterWorker.onmessage = (event) => {
|
|
15
15
|
this.onResult(event.data);
|
|
16
16
|
};
|
|
@@ -4,6 +4,7 @@ import { noRegisterGlobeProgramCache } from "../../../programs/programcache";
|
|
|
4
4
|
import { PickerDisplayer } from "../../../util/picking/picker-displayer";
|
|
5
5
|
import { IndexPolygonMap } from "./data/index-polygon-map";
|
|
6
6
|
import { TestRecords } from "./test-records";
|
|
7
|
+
import { defaultblendfunction } from "../../../util/globe-default-gl-states";
|
|
7
8
|
export class TerrainPolygonSemiPlugin {
|
|
8
9
|
id;
|
|
9
10
|
globe = null;
|
|
@@ -218,6 +219,8 @@ export class TerrainPolygonSemiPlugin {
|
|
|
218
219
|
draw3D() {
|
|
219
220
|
const gl = this.globe.gl;
|
|
220
221
|
gl.disable(gl.DEPTH_TEST);
|
|
222
|
+
gl.enable(gl.BLEND);
|
|
223
|
+
defaultblendfunction(gl);
|
|
221
224
|
// drawPoints
|
|
222
225
|
if (this._options.showTesselationPoints) {
|
|
223
226
|
this._program.draw(this._vao, this._drawPointsRangeIndexParams, this._uboHandler);
|
|
@@ -280,3 +283,23 @@ function inputCheck(input) {
|
|
|
280
283
|
}
|
|
281
284
|
return true;
|
|
282
285
|
}
|
|
286
|
+
function getGlStates(gl) {
|
|
287
|
+
return {
|
|
288
|
+
depthTest: gl.isEnabled(gl.DEPTH_TEST),
|
|
289
|
+
cullFace: gl.isEnabled(gl.CULL_FACE),
|
|
290
|
+
blend: gl.isEnabled(gl.BLEND),
|
|
291
|
+
scissorTest: gl.isEnabled(gl.SCISSOR_TEST),
|
|
292
|
+
depthMask: gl.getParameter(gl.DEPTH_WRITEMASK),
|
|
293
|
+
colorMask: gl.getParameter(gl.COLOR_WRITEMASK),
|
|
294
|
+
frontFace: gl.getParameter(gl.FRONT_FACE),
|
|
295
|
+
viewport: gl.getParameter(gl.VIEWPORT),
|
|
296
|
+
scissorBox: gl.getParameter(gl.SCISSOR_BOX),
|
|
297
|
+
currentProgram: gl.getParameter(gl.CURRENT_PROGRAM),
|
|
298
|
+
vao: gl.getParameter(gl.VERTEX_ARRAY_BINDING),
|
|
299
|
+
arrayBuffer: gl.getParameter(gl.ARRAY_BUFFER_BINDING),
|
|
300
|
+
elementArrayBuffer: gl.getParameter(gl.ELEMENT_ARRAY_BUFFER_BINDING),
|
|
301
|
+
framebuffer: gl.getParameter(gl.FRAMEBUFFER_BINDING),
|
|
302
|
+
activeTexture: gl.getParameter(gl.ACTIVE_TEXTURE),
|
|
303
|
+
texture2DArray: gl.getParameter(gl.TEXTURE_BINDING_2D_ARRAY),
|
|
304
|
+
};
|
|
305
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* add implicit texture display program for color
|
|
3
|
+
* add fence on query return and return id.
|
|
4
|
+
*/
|
|
5
|
+
import { textureOnCanvasProgramCache } from "../programs/draw-texture-on-canvas";
|
|
6
|
+
import { fence } from "./fence";
|
|
7
|
+
const ESCAPE_VALUE = -1;
|
|
8
|
+
class PickerDisplayer {
|
|
9
|
+
globe;
|
|
10
|
+
gl;
|
|
11
|
+
colorTexture;
|
|
12
|
+
indexTexture;
|
|
13
|
+
fbo;
|
|
14
|
+
_pbo;
|
|
15
|
+
_pboSize;
|
|
16
|
+
displayer;
|
|
17
|
+
_inProgress;
|
|
18
|
+
_indexType; // R32I for Integer, R32F for Float
|
|
19
|
+
_typedArrayConstructor;
|
|
20
|
+
constructor(globe, indexType = "R32I") {
|
|
21
|
+
this.globe = globe;
|
|
22
|
+
this.gl = globe.gl;
|
|
23
|
+
const gl = this.gl;
|
|
24
|
+
this.colorTexture = gl.createTexture(); // bind to color attachment 0
|
|
25
|
+
this.indexTexture = gl.createTexture(); // bind to color attachment 1
|
|
26
|
+
this.fbo = gl.createFramebuffer();
|
|
27
|
+
if (indexType === "R32F" && this.gl.getExtension("EXT_color_buffer_float") === null) {
|
|
28
|
+
throw new Error("EXT_color_buffer_float extension is required for R32F index type.");
|
|
29
|
+
}
|
|
30
|
+
this._indexType = indexType;
|
|
31
|
+
if (indexType === "R32I") {
|
|
32
|
+
this._typedArrayConstructor = Int32Array;
|
|
33
|
+
}
|
|
34
|
+
else if (indexType === "R32F") {
|
|
35
|
+
this._typedArrayConstructor = Float32Array;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
throw new Error("Invalid index type. Must be 'R32I' or 'R32F'.");
|
|
39
|
+
}
|
|
40
|
+
this._pbo = undefined;
|
|
41
|
+
this._pboSize = 0;
|
|
42
|
+
this._inProgress = false;
|
|
43
|
+
this.resize();
|
|
44
|
+
this.displayer = textureOnCanvasProgramCache.get(this.gl);
|
|
45
|
+
}
|
|
46
|
+
resize(width = null, height = null) {
|
|
47
|
+
if (width === null || height === null) {
|
|
48
|
+
width = this.globe.api_ScrW();
|
|
49
|
+
height = this.globe.api_ScrH();
|
|
50
|
+
}
|
|
51
|
+
const { gl, colorTexture, indexTexture } = this;
|
|
52
|
+
gl.deleteTexture(colorTexture);
|
|
53
|
+
gl.deleteTexture(indexTexture);
|
|
54
|
+
const colorTextureNew = gl.createTexture();
|
|
55
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
56
|
+
gl.bindTexture(gl.TEXTURE_2D, colorTextureNew);
|
|
57
|
+
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, width, height);
|
|
58
|
+
const indexTextureNew = gl.createTexture();
|
|
59
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
60
|
+
gl.bindTexture(gl.TEXTURE_2D, indexTextureNew);
|
|
61
|
+
gl.texStorage2D(gl.TEXTURE_2D, 1, gl[this._indexType], width, height); // gl.R32I or gl.R32F
|
|
62
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
63
|
+
this.colorTexture = colorTextureNew;
|
|
64
|
+
this.indexTexture = indexTextureNew;
|
|
65
|
+
}
|
|
66
|
+
clearTextures() {
|
|
67
|
+
const { gl, colorTexture, indexTexture } = this;
|
|
68
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
69
|
+
gl.bindTexture(gl.TEXTURE_2D, indexTexture);
|
|
70
|
+
if (this._indexType === "R32I") {
|
|
71
|
+
gl.clearBufferiv(gl.COLOR, 1, new Int32Array([-1, -1, -1, -1]));
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
gl.clearBufferfv(gl.COLOR, 1, new Float32Array([-1, -1, -1, -1]));
|
|
75
|
+
}
|
|
76
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
77
|
+
gl.bindTexture(gl.TEXTURE_2D, colorTexture);
|
|
78
|
+
gl.clearBufferfv(gl.COLOR, 0, new Float32Array([0, 0, 0, 0]));
|
|
79
|
+
}
|
|
80
|
+
// call before drawing the scene with gl picker shader
|
|
81
|
+
bindFBO() {
|
|
82
|
+
const { gl, colorTexture, indexTexture, fbo } = this;
|
|
83
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
84
|
+
gl.bindTexture(gl.TEXTURE_2D, indexTexture);
|
|
85
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
86
|
+
gl.bindTexture(gl.TEXTURE_2D, colorTexture);
|
|
87
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
|
|
88
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.colorTexture, 0);
|
|
89
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, this.indexTexture, 0);
|
|
90
|
+
gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1]);
|
|
91
|
+
const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
|
|
92
|
+
if (status !== gl.FRAMEBUFFER_COMPLETE) {
|
|
93
|
+
throw new Error(`Framebuffer is not complete: ${status.toString(16)}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// call after drawing the scene with gl picker shader
|
|
97
|
+
drawColorTexture() {
|
|
98
|
+
const { gl, colorTexture } = this;
|
|
99
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
100
|
+
gl.disable(gl.DEPTH_TEST);
|
|
101
|
+
this.displayer.draw(colorTexture);
|
|
102
|
+
gl.enable(gl.DEPTH_TEST);
|
|
103
|
+
}
|
|
104
|
+
pickXY(x, y, selectionPointFilling = 1, callback = () => { }) {
|
|
105
|
+
const size = Math.pow(1 + 2 * selectionPointFilling, 2);
|
|
106
|
+
return this._pick(size, x - selectionPointFilling, y - selectionPointFilling, 1 + 2 * selectionPointFilling, 1 + 2 * selectionPointFilling, callback);
|
|
107
|
+
}
|
|
108
|
+
pickBbox(left, top, right, bottom, callback) {
|
|
109
|
+
const size = (right - left) * (bottom - top);
|
|
110
|
+
return this._pick(size, left, top, right - left, bottom - top, callback);
|
|
111
|
+
}
|
|
112
|
+
_pick(size, startX, startY, lengthX, lengthY, callback) {
|
|
113
|
+
if (this._inProgress)
|
|
114
|
+
return false;
|
|
115
|
+
this._inProgress = true;
|
|
116
|
+
this._initHoldBuffer(size * 4);
|
|
117
|
+
const { gl, _pbo } = this;
|
|
118
|
+
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, _pbo);
|
|
119
|
+
this.bindFBO();
|
|
120
|
+
gl.readBuffer(gl.COLOR_ATTACHMENT1); // This is the attachment we want to read
|
|
121
|
+
const format = this._indexType === "R32I" ? gl.RED_INTEGER : gl.RED;
|
|
122
|
+
const type = this._indexType === "R32I" ? gl.INT : gl.FLOAT;
|
|
123
|
+
gl.readPixels(// This will read the pixels to the buffer asynchronously
|
|
124
|
+
startX, startY, lengthX, lengthY, format, type, 0);
|
|
125
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
126
|
+
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
|
|
127
|
+
fence(this.gl).then(() => {
|
|
128
|
+
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, _pbo);
|
|
129
|
+
// const data = new Int16Array(size);
|
|
130
|
+
const data = new this._typedArrayConstructor(size); // Int32Array or Float32Array
|
|
131
|
+
gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data);
|
|
132
|
+
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
|
|
133
|
+
const result = this._pickFromBuffer(data, size);
|
|
134
|
+
callback(result);
|
|
135
|
+
// gl.deleteBuffer(pbo);
|
|
136
|
+
this._inProgress = false;
|
|
137
|
+
});
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
_pickFromBuffer(array, size) {
|
|
141
|
+
const selectedObjects = new Set();
|
|
142
|
+
for (let i = 0; i < size; i += 1) {
|
|
143
|
+
const id = array[i];
|
|
144
|
+
if (id !== ESCAPE_VALUE) {
|
|
145
|
+
selectedObjects.add(id);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return selectedObjects;
|
|
149
|
+
}
|
|
150
|
+
_initHoldBuffer(size) {
|
|
151
|
+
if (this._pbo && this._pboSize >= size) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const { gl } = this;
|
|
155
|
+
const pbo = gl.createBuffer();
|
|
156
|
+
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, pbo);
|
|
157
|
+
gl.bufferData(gl.PIXEL_PACK_BUFFER, size, gl.STREAM_READ);
|
|
158
|
+
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
|
|
159
|
+
this._pboSize = size;
|
|
160
|
+
if (this._pbo !== undefined) {
|
|
161
|
+
gl.deleteBuffer(this._pbo);
|
|
162
|
+
}
|
|
163
|
+
this._pbo = pbo;
|
|
164
|
+
}
|
|
165
|
+
free() {
|
|
166
|
+
const { gl, colorTexture, indexTexture, fbo } = this;
|
|
167
|
+
gl.deleteTexture(colorTexture);
|
|
168
|
+
gl.deleteTexture(indexTexture);
|
|
169
|
+
gl.deleteFramebuffer(fbo);
|
|
170
|
+
if (this._pbo) {
|
|
171
|
+
gl.deleteBuffer(this._pbo);
|
|
172
|
+
}
|
|
173
|
+
textureOnCanvasProgramCache.release(this.gl);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
export { PickerDisplayer };
|
|
@@ -43,48 +43,108 @@ class PickerDisplayer {
|
|
|
43
43
|
this.resize();
|
|
44
44
|
this.displayer = textureOnCanvasProgramCache.get(this.gl);
|
|
45
45
|
}
|
|
46
|
+
_saveState() {
|
|
47
|
+
const gl = this.gl;
|
|
48
|
+
const framebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
|
|
49
|
+
const pixelPackBuffer = gl.getParameter(gl.PIXEL_PACK_BUFFER_BINDING);
|
|
50
|
+
const readBuffer = gl.getParameter(gl.READ_BUFFER);
|
|
51
|
+
const depthTestEnabled = gl.isEnabled(gl.DEPTH_TEST);
|
|
52
|
+
const activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE);
|
|
53
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
54
|
+
const tex2D_unit0 = gl.getParameter(gl.TEXTURE_BINDING_2D);
|
|
55
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
56
|
+
const tex2D_unit1 = gl.getParameter(gl.TEXTURE_BINDING_2D);
|
|
57
|
+
// Restore active texture last
|
|
58
|
+
gl.activeTexture(activeTexture);
|
|
59
|
+
const drawBuffer0 = gl.getParameter(gl.DRAW_BUFFER0);
|
|
60
|
+
const drawBuffer1 = gl.getParameter(gl.DRAW_BUFFER1);
|
|
61
|
+
return {
|
|
62
|
+
framebuffer,
|
|
63
|
+
pixelPackBuffer,
|
|
64
|
+
readBuffer,
|
|
65
|
+
depthTestEnabled,
|
|
66
|
+
activeTexture,
|
|
67
|
+
tex2D_unit0,
|
|
68
|
+
tex2D_unit1,
|
|
69
|
+
drawBuffer0,
|
|
70
|
+
drawBuffer1,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
_restoreState(s) {
|
|
74
|
+
const gl = this.gl;
|
|
75
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, s.framebuffer);
|
|
76
|
+
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, s.pixelPackBuffer);
|
|
77
|
+
gl.readBuffer(s.readBuffer);
|
|
78
|
+
if (s.depthTestEnabled)
|
|
79
|
+
gl.enable(gl.DEPTH_TEST);
|
|
80
|
+
else
|
|
81
|
+
gl.disable(gl.DEPTH_TEST);
|
|
82
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
83
|
+
gl.bindTexture(gl.TEXTURE_2D, s.tex2D_unit0);
|
|
84
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
85
|
+
gl.bindTexture(gl.TEXTURE_2D, s.tex2D_unit1);
|
|
86
|
+
gl.activeTexture(s.activeTexture);
|
|
87
|
+
// drawBuffers restore: default framebuffer expects BACK/NONE (implementation details vary),
|
|
88
|
+
// so only restore the number of buffers that makes sense for the bound FB.
|
|
89
|
+
if (s.framebuffer === null) {
|
|
90
|
+
gl.drawBuffers([s.drawBuffer0]);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
gl.drawBuffers([s.drawBuffer0, s.drawBuffer1]);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
46
96
|
resize(width = null, height = null) {
|
|
47
97
|
if (width === null || height === null) {
|
|
48
98
|
width = this.globe.api_ScrW();
|
|
49
99
|
height = this.globe.api_ScrH();
|
|
50
100
|
}
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
101
|
+
const gl = this.gl;
|
|
102
|
+
const saved = this._saveState();
|
|
103
|
+
try {
|
|
104
|
+
const { colorTexture, indexTexture } = this;
|
|
105
|
+
gl.deleteTexture(colorTexture);
|
|
106
|
+
gl.deleteTexture(indexTexture);
|
|
107
|
+
const colorTextureNew = gl.createTexture();
|
|
108
|
+
gl.bindTexture(gl.TEXTURE_2D, colorTextureNew);
|
|
109
|
+
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, width, height);
|
|
110
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
111
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
112
|
+
const indexTextureNew = gl.createTexture();
|
|
113
|
+
gl.bindTexture(gl.TEXTURE_2D, indexTextureNew);
|
|
114
|
+
gl.texStorage2D(gl.TEXTURE_2D, 1, gl[this._indexType], width, height); // gl.R32I or gl.R32F
|
|
115
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
116
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
117
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
118
|
+
this.colorTexture = colorTextureNew;
|
|
119
|
+
this.indexTexture = indexTextureNew;
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
this._restoreState(saved);
|
|
123
|
+
}
|
|
65
124
|
}
|
|
66
125
|
clearTextures() {
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
126
|
+
const gl = this.gl;
|
|
127
|
+
const saved = this._saveState();
|
|
128
|
+
try {
|
|
129
|
+
// Must clear the *FBO attachments*, not "textures".
|
|
130
|
+
this.bindFBO();
|
|
131
|
+
if (this._indexType === "R32I") {
|
|
132
|
+
gl.clearBufferiv(gl.COLOR, 1, new Int32Array([-1, -1, -1, -1]));
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
gl.clearBufferfv(gl.COLOR, 1, new Float32Array([-1, -1, -1, -1]));
|
|
136
|
+
}
|
|
137
|
+
gl.clearBufferfv(gl.COLOR, 0, new Float32Array([0, 0, 0, 0]));
|
|
72
138
|
}
|
|
73
|
-
|
|
74
|
-
|
|
139
|
+
finally {
|
|
140
|
+
this._restoreState(saved);
|
|
75
141
|
}
|
|
76
|
-
gl.activeTexture(gl.TEXTURE0);
|
|
77
|
-
gl.bindTexture(gl.TEXTURE_2D, colorTexture);
|
|
78
|
-
gl.clearBufferfv(gl.COLOR, 0, new Float32Array([0, 0, 0, 0]));
|
|
79
142
|
}
|
|
80
143
|
// call before drawing the scene with gl picker shader
|
|
81
144
|
bindFBO() {
|
|
82
|
-
const { gl,
|
|
83
|
-
gl.activeTexture(gl.TEXTURE1);
|
|
84
|
-
gl.bindTexture(gl.TEXTURE_2D, indexTexture);
|
|
85
|
-
gl.activeTexture(gl.TEXTURE0);
|
|
86
|
-
gl.bindTexture(gl.TEXTURE_2D, colorTexture);
|
|
145
|
+
const { gl, fbo } = this;
|
|
87
146
|
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
|
|
147
|
+
// No need to bind textures or change ACTIVE_TEXTURE for framebufferTexture2D.
|
|
88
148
|
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.colorTexture, 0);
|
|
89
149
|
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, this.indexTexture, 0);
|
|
90
150
|
gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1]);
|
|
@@ -95,11 +155,16 @@ class PickerDisplayer {
|
|
|
95
155
|
}
|
|
96
156
|
// call after drawing the scene with gl picker shader
|
|
97
157
|
drawColorTexture() {
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
158
|
+
const gl = this.gl;
|
|
159
|
+
const saved = this._saveState();
|
|
160
|
+
try {
|
|
161
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
162
|
+
gl.disable(gl.DEPTH_TEST);
|
|
163
|
+
this.displayer.draw(this.colorTexture);
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
this._restoreState(saved);
|
|
167
|
+
}
|
|
103
168
|
}
|
|
104
169
|
pickXY(x, y, selectionPointFilling = 1, callback = () => { }) {
|
|
105
170
|
const size = Math.pow(1 + 2 * selectionPointFilling, 2);
|
|
@@ -113,29 +178,44 @@ class PickerDisplayer {
|
|
|
113
178
|
if (this._inProgress)
|
|
114
179
|
return false;
|
|
115
180
|
this._inProgress = true;
|
|
116
|
-
this.
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const format = this._indexType === "R32I" ? gl.RED_INTEGER : gl.RED;
|
|
122
|
-
const type = this._indexType === "R32I" ? gl.INT : gl.FLOAT;
|
|
123
|
-
gl.readPixels(// This will read the pixels to the buffer asynchronously
|
|
124
|
-
startX, startY, lengthX, lengthY, format, type, 0);
|
|
125
|
-
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
126
|
-
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
|
|
127
|
-
fence(this.gl).then(() => {
|
|
181
|
+
const gl = this.gl;
|
|
182
|
+
const saved = this._saveState();
|
|
183
|
+
try {
|
|
184
|
+
this._initHoldBuffer(size * 4);
|
|
185
|
+
const { _pbo } = this;
|
|
128
186
|
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, _pbo);
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
gl.
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
187
|
+
this.bindFBO();
|
|
188
|
+
gl.readBuffer(gl.COLOR_ATTACHMENT1);
|
|
189
|
+
const format = this._indexType === "R32I" ? gl.RED_INTEGER : gl.RED;
|
|
190
|
+
const type = this._indexType === "R32I" ? gl.INT : gl.FLOAT;
|
|
191
|
+
gl.readPixels(startX, startY, lengthX, lengthY, format, type, 0);
|
|
192
|
+
// Restore state immediately after issuing readPixels (PBO keeps data for later getBufferSubData)
|
|
193
|
+
this._restoreState(saved);
|
|
194
|
+
fence(this.gl)
|
|
195
|
+
.then(() => {
|
|
196
|
+
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, _pbo);
|
|
197
|
+
const data = new this._typedArrayConstructor(size);
|
|
198
|
+
gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data);
|
|
199
|
+
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
|
|
200
|
+
const result = this._pickFromBuffer(data, size);
|
|
201
|
+
callback(result);
|
|
202
|
+
})
|
|
203
|
+
.catch(() => {
|
|
204
|
+
// Swallow or rethrow based on your app needs; important is not to wedge _inProgress.
|
|
205
|
+
})
|
|
206
|
+
.finally(() => {
|
|
207
|
+
this._inProgress = false;
|
|
208
|
+
});
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
this._restoreState(saved);
|
|
136
213
|
this._inProgress = false;
|
|
137
|
-
|
|
138
|
-
|
|
214
|
+
throw new Error("Picking failed.");
|
|
215
|
+
}
|
|
216
|
+
finally {
|
|
217
|
+
this._restoreState(saved);
|
|
218
|
+
}
|
|
139
219
|
}
|
|
140
220
|
_pickFromBuffer(array, size) {
|
|
141
221
|
const selectedObjects = new Set();
|