@pirireis/webglobeplugins 1.0.8 → 1.1.1

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.
@@ -44,8 +44,12 @@ function radianCheck(point) {
44
44
  }
45
45
  const _3RealEdges = new Uint32Array([uint32Escape, 0, 1, 2, 0]);
46
46
  const _2RealEdges_dismiss2 = new Uint32Array([uint32Escape, 0, 1, 2]);
47
- const _2RealEdges_dismiss1 = new Uint32Array([uint32Escape, 2, 0, 1]);
48
- const _2RealEdges_dismiss0 = new Uint32Array([uint32Escape, 1, 2, 0]);
47
+ // For 2-real-edge cases, the strip must traverse only the two real edges.
48
+ // Vertex indices are local: 0=p1, 1=p2, 2=p3.
49
+ // - dismiss1: real edges are (1-2) and (2-0) => strip 1->2->0
50
+ // - dismiss0: real edges are (2-0) and (0-1) => strip 2->0->1
51
+ const _2RealEdges_dismiss1 = new Uint32Array([uint32Escape, 1, 2, 0]);
52
+ const _2RealEdges_dismiss0 = new Uint32Array([uint32Escape, 2, 0, 1]);
49
53
  const _1realEdge_0 = new Uint32Array([uint32Escape, 0, 1]);
50
54
  const _1realEdge_1 = new Uint32Array([uint32Escape, 1, 2]);
51
55
  const _1realEdge_2 = new Uint32Array([uint32Escape, 2, 0]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pirireis/webglobeplugins",
3
- "version": "1.0.8",
3
+ "version": "1.1.1",
4
4
  "main": "index.js",
5
5
  "author": "Toprak Nihat Deniz Ozturk",
6
6
  "license": "MIT",
@@ -15,4 +15,4 @@
15
15
  "peerDependencies": {
16
16
  "@pirireis/webglobe": "6.2.51^"
17
17
  }
18
- }
18
+ }
@@ -125,6 +125,11 @@ function mergeAndSendResults() {
125
125
  let vertexOffset = 3; // reserve 3 vertices
126
126
  let arcCounter = BASE_REAL_EDGE_ARC_INDICES;
127
127
  for (const out of validOutputs) {
128
+ const outPosVertexCount = Math.floor(out.vec3s.length / 3);
129
+ const outXYVertexCount = Math.floor(out.longLats.length / 2);
130
+ const outPickVertexCount = out.pickIndices ? out.pickIndices.length : Number.POSITIVE_INFINITY;
131
+ const outColorVertexCount = out.variativeColors ? Math.floor(out.variativeColors.length / 4) : Number.POSITIVE_INFINITY;
132
+ const outSafeVertexCount = Math.min(outPosVertexCount, outXYVertexCount, outPickVertexCount, outColorVertexCount);
128
133
  merged.vec3s.set(out.vec3s, offsetVec3s);
129
134
  offsetVec3s += out.vec3s.length;
130
135
  for (let i = 0; i < out.indices.length; i++) {
@@ -133,8 +138,15 @@ function mergeAndSendResults() {
133
138
  if (_arcState && merged.realEdgeArcIndices && out.realEdgeArcIndices) {
134
139
  for (let i = 0; i < out.realEdgeArcIndices.length; i++) {
135
140
  const realEdgeIndice = out.realEdgeArcIndices[i];
136
- merged.realEdgeArcIndices[arcCounter++] =
137
- realEdgeIndice === uint32Escape ? uint32Escape : realEdgeIndice + vertexOffset;
141
+ if (realEdgeIndice === uint32Escape) {
142
+ merged.realEdgeArcIndices[arcCounter++] = uint32Escape;
143
+ }
144
+ else {
145
+ // Defensive: discard any out-of-range arc indices so we never
146
+ // generate a merged index that references missing attribute data.
147
+ merged.realEdgeArcIndices[arcCounter++] =
148
+ realEdgeIndice >= outSafeVertexCount ? uint32Escape : realEdgeIndice + vertexOffset;
149
+ }
138
150
  }
139
151
  }
140
152
  offsetIndices += out.indices.length;
@@ -141,7 +141,10 @@ self.onmessage = (event) => {
141
141
  output.realEdgeArcIndices[arcOffset + i] = uint32Escape;
142
142
  }
143
143
  else {
144
- output.realEdgeArcIndices[arcOffset + i] = value + startVertex;
144
+ // Guard against occasional out-of-range arc indices.
145
+ // Invalid indices would crash ANGLE with "vertex buffer not big enough".
146
+ output.realEdgeArcIndices[arcOffset + i] =
147
+ value >= vertexCount ? uint32Escape : value + startVertex;
145
148
  }
146
149
  }
147
150
  arcOffset += result.realEdgeArcIndices.length;
@@ -115,11 +115,18 @@ export class TerrainPolygonSemiPlugin {
115
115
  this._drawPointsRangeIndexParams.elementBuffer = this._elementArrayBuffer;
116
116
  }
117
117
  insertBulk(polygons) {
118
- // if (this._indexPolygonMap) {
119
118
  let filteredPolygons = polygons.filter(inputCheck);
119
+ // Drop precision to 8 digits after dot before moving forward
120
+ filteredPolygons = filteredPolygons.map((p) => ({
121
+ ...p,
122
+ geometry: p.geometry.map((g) => ({
123
+ ...g,
124
+ vertices: g.vertices.map((v) => roundTo8(v)),
125
+ })),
126
+ }));
120
127
  filteredPolygons = this._indexPolygonMap.insertBulk(filteredPolygons);
121
- // }
122
128
  this._workerContact.insertBulk(filteredPolygons);
129
+ this.globe.DrawRender(); // If the window is not focused, this may be needed to force processing.
123
130
  }
124
131
  deleteBulk(keys) {
125
132
  this._workerContact.deleteBulk(keys);
@@ -149,6 +156,37 @@ export class TerrainPolygonSemiPlugin {
149
156
  }
150
157
  setBuffers(data) {
151
158
  const gl = this.globe.gl;
159
+ const posVertexCount = Math.floor(data.vec3s.length / 3);
160
+ const xyVertexCount = Math.floor(data.longLats.length / 2);
161
+ let safeVertexCount = Math.min(posVertexCount, xyVertexCount);
162
+ if (this._options.pickable && data.pickIndices) {
163
+ safeVertexCount = Math.min(safeVertexCount, data.pickIndices.length);
164
+ }
165
+ if (this._options.variativeColorsOn && data.variativeColors) {
166
+ safeVertexCount = Math.min(safeVertexCount, Math.floor(data.variativeColors.length / 4));
167
+ }
168
+ // Guard against invalid indices referencing beyond uploaded attribute buffers.
169
+ // This prevents ANGLE "Vertex buffer is not big enough for the draw call" errors.
170
+ let maxTriangleIndex = -1;
171
+ for (let i = 0; i < data.indices.length; i++) {
172
+ const v = data.indices[i];
173
+ if (v > maxTriangleIndex)
174
+ maxTriangleIndex = v;
175
+ }
176
+ const trianglesInvalid = safeVertexCount === 0 || maxTriangleIndex >= safeVertexCount;
177
+ if (trianglesInvalid) {
178
+ console.warn("TerrainPolygonSemiPlugin: skipping draw due to invalid vertex/index sizing", {
179
+ posVertexCount,
180
+ xyVertexCount,
181
+ safeVertexCount,
182
+ indicesLength: data.indices.length,
183
+ maxTriangleIndex,
184
+ pickIndicesLength: data.pickIndices?.length ?? null,
185
+ variativeColorsLength: data.variativeColors?.length ?? null,
186
+ });
187
+ this._drawRangeIndexParams.drawRange.count = 0;
188
+ this._drawPointsRangeIndexParams.drawRange.count = 0;
189
+ }
152
190
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._elementArrayBuffer);
153
191
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, data.indices, gl.STREAM_DRAW);
154
192
  gl.bindBuffer(gl.ARRAY_BUFFER, this._vec3Buffer);
@@ -166,7 +204,25 @@ export class TerrainPolygonSemiPlugin {
166
204
  if (this._options.drawEdges && data.realEdgeArcIndices) {
167
205
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._drawRealEdgeArcs.elementBuffer);
168
206
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, data.realEdgeArcIndices, gl.STREAM_DRAW);
169
- this._drawRealEdgeArcs.drawRange.count = data.realEdgeArcIndices.length;
207
+ // If the edge index stream includes primitive-restart (0xFFFFFFFF) indices,
208
+ // the draw call requires PRIMITIVE_RESTART_FIXED_INDEX to be enabled.
209
+ // Also validate edge indices are within bounds.
210
+ let maxEdgeIndex = -1;
211
+ const PRIMITIVE_RESTART_INDEX = 0xFFFFFFFF;
212
+ for (let i = 0; i < data.realEdgeArcIndices.length; i++) {
213
+ const v = data.realEdgeArcIndices[i];
214
+ if (v === PRIMITIVE_RESTART_INDEX)
215
+ continue;
216
+ if (v > maxEdgeIndex)
217
+ maxEdgeIndex = v;
218
+ }
219
+ if (safeVertexCount === 0 || maxEdgeIndex >= safeVertexCount) {
220
+ console.warn("TerrainPolygonSemiPlugin: disabling edge draw due to invalid edge indices", { safeVertexCount, maxEdgeIndex, edgeIndexCount: data.realEdgeArcIndices.length });
221
+ this._drawRealEdgeArcs.drawRange.count = 0;
222
+ }
223
+ else {
224
+ this._drawRealEdgeArcs.drawRange.count = data.realEdgeArcIndices.length;
225
+ }
170
226
  }
171
227
  else {
172
228
  this._drawRealEdgeArcs.drawRange.count = 0;
@@ -230,9 +286,6 @@ export class TerrainPolygonSemiPlugin {
230
286
  this._pickerDisplayer.clearTextures();
231
287
  // gl.enable(gl.DEPTH_TEST);
232
288
  }
233
- else {
234
- // gl.disable(gl.DEPTH_TEST);
235
- }
236
289
  gl.frontFace(gl.CW);
237
290
  this._program.draw(this._vao, this._drawRangeIndexParams, this._uboHandler);
238
291
  gl.frontFace(gl.CCW);
@@ -303,3 +356,6 @@ function getGlStates(gl) {
303
356
  texture2DArray: gl.getParameter(gl.TEXTURE_BINDING_2D_ARRAY),
304
357
  };
305
358
  }
359
+ function roundTo8(n) {
360
+ return Math.round(n * 1e8) / 1e8;
361
+ }
@@ -17,6 +17,7 @@ class PickerDisplayer {
17
17
  _inProgress;
18
18
  _indexType; // R32I for Integer, R32F for Float
19
19
  _typedArrayConstructor;
20
+ _lastWidthHeight = null;
20
21
  constructor(globe, indexType = "R32I") {
21
22
  this.globe = globe;
22
23
  this.gl = globe.gl;
@@ -98,29 +99,29 @@ class PickerDisplayer {
98
99
  width = this.globe.api_ScrW();
99
100
  height = this.globe.api_ScrH();
100
101
  }
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);
102
+ if (this._lastWidthHeight &&
103
+ this._lastWidthHeight.width === width &&
104
+ this._lastWidthHeight.height === height) {
105
+ return;
123
106
  }
107
+ this._lastWidthHeight = { width, height };
108
+ const gl = this.gl;
109
+ const { colorTexture, indexTexture } = this;
110
+ gl.deleteTexture(colorTexture);
111
+ gl.deleteTexture(indexTexture);
112
+ const colorTextureNew = gl.createTexture();
113
+ gl.bindTexture(gl.TEXTURE_2D, colorTextureNew);
114
+ gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, width, height);
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
+ const indexTextureNew = gl.createTexture();
118
+ gl.bindTexture(gl.TEXTURE_2D, indexTextureNew);
119
+ gl.texStorage2D(gl.TEXTURE_2D, 1, gl[this._indexType], width, height); // gl.R32I or gl.R32F
120
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
121
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
122
+ gl.bindTexture(gl.TEXTURE_2D, null);
123
+ this.colorTexture = colorTextureNew;
124
+ this.indexTexture = indexTextureNew;
124
125
  }
125
126
  clearTextures() {
126
127
  const gl = this.gl;
@@ -143,6 +144,7 @@ class PickerDisplayer {
143
144
  // call before drawing the scene with gl picker shader
144
145
  bindFBO() {
145
146
  const { gl, fbo } = this;
147
+ this.resize();
146
148
  gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
147
149
  // No need to bind textures or change ACTIVE_TEXTURE for framebufferTexture2D.
148
150
  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.colorTexture, 0);