@pirireis/webglobeplugins 0.11.1-alpha → 0.12.0-alpha

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.
@@ -0,0 +1,249 @@
1
+ import { RADIANS } from "./methods";
2
+ function createTemplate(intervalCount, strength = 1.0) {
3
+ const out = new Array(intervalCount);
4
+ const TOTAL = 1;
5
+ let cummulative = 0;
6
+ if (strength <= 0) {
7
+ // If strength is 0, distribute evenly.
8
+ const step = TOTAL / (intervalCount - 1);
9
+ for (let i = 0; i < intervalCount; i++) {
10
+ out[i] = cummulative;
11
+ cummulative += step;
12
+ }
13
+ out[intervalCount - 1] = TOTAL; // Ensure the last value is exactly TOTAL
14
+ return out;
15
+ }
16
+ // If strength is greater than 0, bias towards the start.
17
+ const weights = new Array(intervalCount);
18
+ let currentStep = 1;
19
+ let totalWeight = 0;
20
+ // Calculate weights for each interval, decreasing for later intervals.
21
+ for (let i = 0; i < intervalCount; i++) {
22
+ // Using (i + 1) in the denominator gives earlier intervals the highest weight.
23
+ totalWeight += currentStep;
24
+ weights[i] = totalWeight;
25
+ currentStep += strength;
26
+ }
27
+ // Distribute the total angle based on the weights.
28
+ for (let i = 0; i < intervalCount; i++) {
29
+ // Round to the nearest whole number for this interval.
30
+ out[i] = (weights[i] / totalWeight) * TOTAL;
31
+ }
32
+ if (out[intervalCount - 1] !== TOTAL) {
33
+ out[intervalCount - 1] = TOTAL;
34
+ }
35
+ // console.log("createTemplate", "strength", strength, "intervalCount", intervalCount, "out", out);
36
+ return out;
37
+ }
38
+ function interpolation(a, b, t) {
39
+ return a + (b - a) * t;
40
+ }
41
+ /**
42
+ * Populates the `out` array with values from the `template` array,
43
+ * distributing the surplus length as interpolated values between the template samples.
44
+ *
45
+ * @param out The destination array to be filled. Its length must be >= template.length.
46
+ * @param template An ordered array of numbers to be placed in the `out` array.
47
+ * @param strength A parameter controlling the distribution bias of surplus samples.
48
+ * - strength = 0: Surplus samples are distributed evenly.
49
+ * - strength > 0: Surplus samples are biased towards the start of the template.
50
+ * - Higher values create a stronger bias.
51
+ */
52
+ function increasePopulation(// TODO: THERE IS A BUG
53
+ out, template, strength = 1.0) {
54
+ const sourceLength = template.length;
55
+ const destinationLength = out.length;
56
+ const outLengthAtStart = out.length;
57
+ // --- Handle Edge Cases ---
58
+ // If the template is empty, there is nothing to interpolate from.
59
+ if (sourceLength === 0) {
60
+ return;
61
+ }
62
+ // If the template has only one value, fill the output array with that value.
63
+ if (sourceLength === 1) {
64
+ out.fill(template[0]);
65
+ return;
66
+ }
67
+ // If the destination is not larger than the source, just copy the template values.
68
+ if (destinationLength <= sourceLength) {
69
+ for (let i = 0; i < destinationLength; i++) {
70
+ out[i] = template[i];
71
+ }
72
+ return;
73
+ }
74
+ // --- Main Logic ---
75
+ const surplus = destinationLength - sourceLength;
76
+ const numGaps = sourceLength - 1;
77
+ // This array will hold the number of extra samples to add in each gap.
78
+ const surplusPerGap = new Array(numGaps).fill(0);
79
+ if (surplus > 0) {
80
+ // --- Step 1: Determine the distribution of surplus items ---
81
+ // If strength is 0, distribute surplus items as evenly as possible.
82
+ if (strength <= 0) {
83
+ const baseToAdd = Math.floor(surplus / numGaps);
84
+ const remainder = surplus % numGaps;
85
+ for (let i = 0; i < numGaps; i++) {
86
+ // Distribute the remainder one by one to the first gaps.
87
+ surplusPerGap[i] = baseToAdd + (i < remainder ? 1 : 0);
88
+ }
89
+ }
90
+ else {
91
+ // Biased Distribution: more items in earlier gaps.
92
+ const weights = new Array(numGaps);
93
+ let totalWeight = 0;
94
+ // A. Calculate a weight for each gap. The weight decreases for later gaps.
95
+ // The `strength` parameter makes this decay steeper.
96
+ for (let i = 0; i < numGaps; i++) {
97
+ // Using (i + 1) in the denominator gives earlier gaps (i=0) the highest weight.
98
+ const weight = Math.pow(1 / (i + 1), strength);
99
+ weights[i] = weight;
100
+ totalWeight += weight;
101
+ }
102
+ // B. Distribute the surplus based on the calculated weights.
103
+ // This method ensures the total distributed count equals the surplus.
104
+ let distributedCount = 0;
105
+ for (let i = 0; i < numGaps - 1; i++) {
106
+ const idealCount = (weights[i] / totalWeight) * surplus;
107
+ // Round to the nearest whole number for this gap.
108
+ const countForThisGap = Math.ceil(idealCount);
109
+ surplusPerGap[i] = countForThisGap;
110
+ distributedCount += countForThisGap;
111
+ }
112
+ // Assign the remainder to the last gap to guarantee the sum is correct.
113
+ //surplusPerGap[numGaps - 1] = surplus - distributedCount;
114
+ // add to first
115
+ const leftover = surplus - distributedCount;
116
+ if (leftover > 0) {
117
+ surplusPerGap[0] += leftover; // Add any leftover to the first gap.
118
+ }
119
+ console.log("leftover", leftover, "distributedCount", distributedCount, "surplus", surplus);
120
+ }
121
+ }
122
+ // --- Step 2: Populate the `out` array ---
123
+ let outIndex = 0;
124
+ for (let i = 0; i < surplusPerGap.length; i++) {
125
+ if (typeof surplusPerGap[i] !== "number" || isNaN(surplusPerGap[i]) || !isFinite(surplusPerGap[i])) {
126
+ console.warn("increasePopulation: Invalid surplusPerGap value at index", i, ":", surplusPerGap[i]);
127
+ }
128
+ }
129
+ for (let i = 0; i < sourceLength; i++) {
130
+ // A. Add the original template item.
131
+ out[outIndex++] = template[i];
132
+ // B. If this is not the last template item, fill the gap after it.
133
+ if (i < numGaps) {
134
+ const numToAdd = surplusPerGap[i];
135
+ if (numToAdd <= 0)
136
+ continue;
137
+ const startVal = template[i];
138
+ const endVal = template[i + 1];
139
+ // C. Add the interpolated ("surplus") items for this gap.
140
+ // The total number of intervals in this gap is numToAdd + 1.
141
+ const totalIntervals = numToAdd + 1;
142
+ for (let j = 1; j <= numToAdd; j++) {
143
+ const t = j / totalIntervals; // The interpolation factor (0 < t < 1)
144
+ // Linear interpolation: out = start * (1 - t) + end * t
145
+ const interpolatedValue = startVal * (1 - t) + endVal * t;
146
+ out[outIndex++] = interpolatedValue;
147
+ if (outIndex >= out.length) {
148
+ console.warn("increasePopulation: Output array overflow. Stopping early.");
149
+ console.warn("processeed item ratio:", i, "/", sourceLength);
150
+ let count = numToAdd - j;
151
+ console.log("count", count);
152
+ for (let _i = i; _i < sourceLength; _i++) {
153
+ count += surplusPerGap[_i];
154
+ }
155
+ console.warn("increasePopulation: Not enough space to add", count, "more items.");
156
+ return; // Prevent overflow if the output array is not large enough.
157
+ }
158
+ }
159
+ }
160
+ }
161
+ // --- Step 3: Ensure the output length is correct ---
162
+ if (outLengthAtStart !== out.length) {
163
+ console.warn("increasePopulation: Output length mismatch. Expected", outLengthAtStart, "but got", out.length);
164
+ }
165
+ }
166
+ function createCummulativeTemplate(numberOfPoints, strength, denseRatio = 0.5 // Ratio of points to be densely packed at the start.
167
+ ) {
168
+ // Handle edge cases for the number of points.
169
+ if (numberOfPoints <= 0) {
170
+ // If zero or a negative number of points is requested, return an empty array.
171
+ return new Float64Array([]);
172
+ }
173
+ // Create the array to hold the results. Float64Array is used for high-precision floating-point numbers.
174
+ const distribution = new Float64Array(numberOfPoints);
175
+ if (numberOfPoints === 1) {
176
+ // If only one point is requested, it represents the entire range [0, 1].
177
+ // We place it at the start (0.0).
178
+ distribution[0] = 0.0;
179
+ return distribution;
180
+ }
181
+ // The exponent determines the curve of the distribution.
182
+ // We add 1 to the strength so that a strength of 0 results in an exponent of 1 (linear).
183
+ // We use Math.max(0, strength) to ensure the strength is not negative.
184
+ // The last index is used to normalize the position to a 0-1 range.
185
+ const lastIndex = numberOfPoints - 1;
186
+ distribution[0] = 0.0; // The first point is always at 0.0.
187
+ let totalWeight = 0;
188
+ let i = 1;
189
+ const denseCount = numberOfPoints * denseRatio;
190
+ for (i; i < denseCount; i++) {
191
+ // Calculate the ratio of the current index to the last index.
192
+ // The ratio is adjusted to create a non-linear distribution.
193
+ totalWeight += 1;
194
+ distribution[i] = totalWeight; // Store the raw value in the distribution array.
195
+ }
196
+ for (i; i < numberOfPoints; i++) {
197
+ // Calculate the ratio of the current index to the last index.
198
+ const ratio = 1 + ((i - denseCount) / lastIndex) / (1 - denseRatio) * 2;
199
+ const step = Math.pow(ratio, strength);
200
+ totalWeight += step;
201
+ distribution[i] = totalWeight; // Store the raw value in the distribution array.
202
+ // Apply the power function to create a non-linear distribution.
203
+ // The result is normalized to the range [0, 1].
204
+ }
205
+ for (let i = 1; i < numberOfPoints; i++) {
206
+ // Normalize the values to ensure they sum up to 1.
207
+ distribution[i] = distribution[i] / totalWeight;
208
+ }
209
+ console.log("distribution", distribution, "strength", strength, "numberOfPoints", numberOfPoints);
210
+ return distribution;
211
+ }
212
+ function createCummulativeTemplateStash(levels, numberOfPoints, denseRatio = 0.5, strengthMultiplier = 2.4) {
213
+ const stash = [];
214
+ for (let i = 0; i < levels; i++) {
215
+ const template = createCummulativeTemplate(numberOfPoints, i * strengthMultiplier, denseRatio);
216
+ stash.push(template);
217
+ }
218
+ return stash;
219
+ }
220
+ function globeFindPointByPolar(out, globe, centerLong, centerLat, radius, ratios) {
221
+ for (let i = 0; i < ratios.length; i++) {
222
+ const point = globe.Math.FindPointByPolar(centerLong, centerLat, radius, ratios[i]);
223
+ out[i * 2] = point.long;
224
+ out[i * 2 + 1] = point.lat;
225
+ }
226
+ }
227
+ function globeFindPointByPolarHalfCircle(out, globe, centerLong, centerLat, radius, rotation, ratios) {
228
+ const rotCentigrade = rotation / RADIANS + 720;
229
+ for (let i = 0; i < ratios.length; i++) {
230
+ const point = globe.Math.FindPointByPolar(centerLong, centerLat, radius, (ratios[i] * 180 + rotCentigrade) % 360);
231
+ out[i * 2] = point.long;
232
+ out[i * 2 + 1] = point.lat;
233
+ }
234
+ // fill reflection
235
+ let offset = out.length;
236
+ for (let i = 0; i < ratios.length - 1; i++) {
237
+ const point = globe.Math.FindPointByPolar(centerLong, centerLat, radius, ((-ratios[i]) * 180 + rotCentigrade) % 360);
238
+ out[offset - 2] = point.long;
239
+ out[offset - 1] = point.lat;
240
+ offset -= 2;
241
+ }
242
+ console.log("1");
243
+ }
244
+ export {
245
+ // createTemplate,
246
+ // increasePopulation,
247
+ // interpolation,
248
+ // createCummulativeTemplate,
249
+ createCummulativeTemplateStash, globeFindPointByPolar, globeFindPointByPolarHalfCircle };
package/Math/circle.js ADDED
@@ -0,0 +1,39 @@
1
+ import { RADIANS } from './methods';
2
+ import { subtract, normalize, dot, fromLongLatToUnitVector, copy, multiplyScalar } from './vec3';
3
+ const _0vec3 = [0, 0, 0];
4
+ function closestAzimuthAngle(circleProperties, point) {
5
+ const distance = dot(circleProperties.normal, point);
6
+ copy(_0vec3, circleProperties.normal);
7
+ multiplyScalar(_0vec3, _0vec3, distance);
8
+ subtract(_0vec3, point, _0vec3);
9
+ normalize(_0vec3, _0vec3);
10
+ const N = circleProperties.northPointProjectedToOriginPlaneNormalized;
11
+ const _dot = dot(_0vec3, N);
12
+ let angle = Math.acos(_dot);
13
+ const z = _0vec3[0] * N[1] - _0vec3[1] * N[0];
14
+ return z < 0 ? -angle : angle;
15
+ }
16
+ function createCircleClosestAzimuthAngleProperties(circle) {
17
+ const normal = Array(3);
18
+ fromLongLatToUnitVector(normal, [circle.center[0] * RADIANS, circle.center[1] * RADIANS]);
19
+ const distance = normal[2]; //dot(normal, [0, 0, 1] as Vec3)
20
+ const N = [0, 0, 0];
21
+ if (Math.abs(distance) < 1e-6) {
22
+ N[0] = -1;
23
+ N[1] = 0;
24
+ N[2] = 0;
25
+ }
26
+ else {
27
+ copy(N, normal);
28
+ multiplyScalar(N, N, distance);
29
+ N[0] = -N[0];
30
+ N[1] = -N[1];
31
+ N[2] = 1 - N[2];
32
+ }
33
+ normalize(N, N);
34
+ return {
35
+ normal: normal,
36
+ northPointProjectedToOriginPlaneNormalized: N,
37
+ };
38
+ }
39
+ export { closestAzimuthAngle, createCircleClosestAzimuthAngleProperties };
package/Math/methods.js CHANGED
@@ -84,14 +84,24 @@ export const globe3Dcoordinates = (globe, height = 0) => (longlats, { paddingCou
84
84
  }
85
85
  return result;
86
86
  };
87
- export const globe2Dcoordinates = (globe) => (longlats, { paddingCount = 0, paddingValue = NaN }) => {
87
+ const manhattanDistance = (a, b) => {
88
+ return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]);
89
+ };
90
+ export const globe2Dcoordinates = (globe, distanceFilterMeter = WORLD_RADIUS_MERCATOR) => (longlats, { paddingCount = 0, paddingValue = NaN }) => {
91
+ let _lastXY = [NaN, NaN];
88
92
  const len = longlats.length / 2;
89
93
  const result = new Float32Array(len * 2 + paddingCount * 2).fill(paddingValue);
90
94
  for (let i = 0; i < len; i++) {
91
95
  const long = longlats[i * 2];
92
96
  const lat = longlats[i * 2 + 1];
93
- const xyz = globe.api_GetMercator2DPoint(long, lat);
94
- result.set(xyz, i * 2);
97
+ const xy = globe.api_GetMercator2DPoint(long, lat);
98
+ if (manhattanDistance(_lastXY, xy) > distanceFilterMeter) {
99
+ result.set([paddingValue, paddingValue], i * 2);
100
+ }
101
+ else {
102
+ result.set(xy, i * 2);
103
+ }
104
+ _lastXY = xy;
95
105
  }
96
106
  return result;
97
107
  };
package/Math/vec3.js CHANGED
@@ -80,7 +80,7 @@ function equals(a, b) {
80
80
  Math.abs(a[1] - b[1]) < EPSILON &&
81
81
  Math.abs(a[2] - b[2]) < EPSILON);
82
82
  }
83
- function toUnitVectorLongLat(out, a) {
83
+ function fromUnitVectorToLongLat(out, a) {
84
84
  const len = length(a); // TODO Might drop length check
85
85
  if (len === 0) {
86
86
  throw new Error('Cannot convert a zero vector to unit vector');
@@ -88,7 +88,7 @@ function toUnitVectorLongLat(out, a) {
88
88
  out[0] = Math.atan2(a[1], a[0]); // Longitude
89
89
  out[1] = Math.asin(a[2] / len); // Latitude
90
90
  }
91
- function fromUnitVectorLongLat(out, longLat) {
91
+ function fromLongLatToUnitVector(out, longLat) {
92
92
  const longitude = longLat[0];
93
93
  const latitude = longLat[1];
94
94
  const cosLat = Math.cos(latitude);
@@ -119,4 +119,4 @@ function randomUnit(out) {
119
119
  function str(a) {
120
120
  return `Vec3(${a[0].toFixed(2)}, ${a[1].toFixed(2)}, ${a[2].toFixed(2)})`;
121
121
  }
122
- export { create, set, clone, copy, add, subtract, dot, cross, multiplyScalar, divideScalar, lengthSquared, length, normalize, distanceSquared, distance, equals, toUnitVectorLongLat, fromUnitVectorLongLat, applyQuaternion, randomUnit, str };
122
+ export { create, set, clone, copy, add, subtract, dot, cross, multiplyScalar, divideScalar, lengthSquared, length, normalize, distanceSquared, distance, equals, fromUnitVectorToLongLat, fromLongLatToUnitVector, applyQuaternion, randomUnit, str };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pirireis/webglobeplugins",
3
- "version": "0.11.1-alpha",
3
+ "version": "0.12.0-alpha",
4
4
  "main": "index.js",
5
5
  "author": "Toprak Nihat Deniz Ozturk",
6
6
  "license": "MIT",
@@ -1,7 +1,6 @@
1
1
  import { createProgram } from "../../util/webglobjectbuilders";
2
- import "../interface";
3
2
  import { CameraUniformBlockString, CameraUniformBlockTotemCache } from "../totems/index";
4
- import { cartesian3DToGLPosition, mercatorXYToGLPosition, } from "../../util/shaderfunctions/geometrytransformations.js";
3
+ import { cartesian3DToGLPosition, mercatorXYToGLPosition, } from "../../util/shaderfunctions/geometrytransformations";
5
4
  import { noRegisterGlobeProgramCache } from "../programcache";
6
5
  import { attributeLoader } from "../../util/gl-util/buffer/attribute-loader";
7
6
  import "../../util/gl-util/buffer/attribute-loader";
@@ -57,7 +56,7 @@ void main() {
57
56
  v_position = vec3( position2d, 0.0 );
58
57
  v_flat_position = vec3( position2d, 0.0 );
59
58
  }
60
- gl_PointSize = 4.0;
59
+ gl_PointSize = 6.0;
61
60
  }`;
62
61
  const fragmentShaderSource = `#version 300 es
63
62
  precision highp float;
@@ -88,7 +87,7 @@ void main() {
88
87
  outColor = vec4( v_color.rgb, v_color.a * opacity );
89
88
  }
90
89
  }`;
91
- class Logic {
90
+ export class LineProgram {
92
91
  _vaosPublished = [];
93
92
  _ubosPublished = [];
94
93
  program;
@@ -164,6 +163,6 @@ class Logic {
164
163
  }
165
164
  }
166
165
  export const LineStripProgramCache = Object.freeze({
167
- get: (globe) => noRegisterGlobeProgramCache.getProgram(globe, Logic),
168
- release: (globe) => noRegisterGlobeProgramCache.releaseProgram(globe, Logic),
166
+ get: (globe) => noRegisterGlobeProgramCache.getProgram(globe, LineProgram),
167
+ release: (globe) => noRegisterGlobeProgramCache.releaseProgram(globe, LineProgram),
169
168
  });
@@ -1,4 +1,6 @@
1
1
  import { globeProgramCache } from "../programcache";
2
+ import { fromLongLatToUnitVector } from "../../Math/vec3";
3
+ import { RADIANS } from "../../Math/methods";
2
4
  export const CameraUniformBlockString = `
3
5
  layout(std140) uniform CameraUniformBlock {
4
6
  mat4 view; // 64 bytes 0
@@ -15,6 +17,7 @@ layout(std140) uniform CameraUniformBlock {
15
17
  }; // 14 lines
16
18
  `;
17
19
  const Radian = Math.PI / 180.0;
20
+ const _0vec3 = [0, 0, 0];
18
21
  export default class CameraUniformBlockTotem {
19
22
  id;
20
23
  description;
@@ -24,7 +27,7 @@ export default class CameraUniformBlockTotem {
24
27
  traslateFloat32;
25
28
  mapWHFloat32;
26
29
  _isMovedParams;
27
- _normalizedCameraVector;
30
+ _normalizedCameraVector = [0, 0, 0]; // Normalized camera vector
28
31
  // _frustumPlanes: any; // Uncomment and type if used
29
32
  constructor() {
30
33
  this.id = "CameraUniformBlockTotem";
@@ -127,14 +130,31 @@ export default class CameraUniformBlockTotem {
127
130
  globe.api_IsScreenMoving();
128
131
  this._isMovedParams.lastLod = currentLOD;
129
132
  }
130
- // getFrustum(globe, 50, this._frustumPlanes);
131
- this._normalizedCameraVector = (() => {
132
- const { Fp } = globe;
133
+ this.__setCameraVectors();
134
+ }
135
+ __setCameraVectors() {
136
+ if (!this.globe) {
137
+ throw new Error("Globe is not initialized");
138
+ }
139
+ const globe = this.globe;
140
+ const currentGeom = globe.api_GetCurrentGeometry();
141
+ if (currentGeom === 0) {
142
+ const { Fp, FUPos } = globe;
133
143
  const cameraVector = [Fp.x, Fp.y, Fp.z];
134
144
  const length = Math.sqrt(cameraVector.reduce((sum, val) => sum + val * val, 0));
135
- return cameraVector.map((val) => val / length);
136
- })();
145
+ this._normalizedCameraVector[0] = cameraVector[0] / length;
146
+ this._normalizedCameraVector[1] = cameraVector[1] / length;
147
+ this._normalizedCameraVector[2] = cameraVector[2] / length;
148
+ }
149
+ else if (currentGeom === 1) {
150
+ const { CenterLong, CenterLat } = globe.api_GetCurrentLookInfo();
151
+ fromLongLatToUnitVector(_0vec3, [CenterLong * RADIANS, CenterLat * RADIANS]);
152
+ this._normalizedCameraVector[0] = _0vec3[0];
153
+ this._normalizedCameraVector[1] = _0vec3[1];
154
+ this._normalizedCameraVector[2] = _0vec3[2];
155
+ }
137
156
  }
157
+ // TODO: cut implicits to the bottom
138
158
  assignBindingPoint(program, bindingPoint) {
139
159
  const gl = this.gl;
140
160
  const cameraBlockIndex = gl.getUniformBlockIndex(program, "CameraUniformBlock");
@@ -163,12 +183,19 @@ export default class CameraUniformBlockTotem {
163
183
  return [globe.Fp.x, globe.Fp.y, globe.Fp.z];
164
184
  }
165
185
  getNormalizedCameraVector() {
166
- return this._normalizedCameraVector;
186
+ return this._normalizedCameraVector || _0vec3;
167
187
  }
168
- getCameraUpPosition() {
188
+ getCameraUpVector() {
169
189
  const globe = this.globe;
170
190
  return [globe.FUPos.x, globe.FUPos.y, globe.FUPos.z];
171
191
  }
192
+ getLookAtVector() {
193
+ const globe = this.globe;
194
+ const { CenterLong, CenterLat } = globe.api_GetCurrentLookInfo();
195
+ const result = [0, 0, 0];
196
+ fromLongLatToUnitVector(result, [CenterLong * RADIANS, CenterLat * RADIANS]);
197
+ return result;
198
+ }
172
199
  free() {
173
200
  const gl = this.gl;
174
201
  const ubo = this.ubo;
@@ -1,21 +1,32 @@
1
1
  import { globeProgramCache } from "../programcache";
2
- export const WebglobeInfoUniformBlockString = `
3
- layout(std140) uniform WebglobeInfo {
4
- vec2 canvas_resolution;
5
- vec2 mouse_radian_long_lat;
6
- vec2 mouse_pixel_xy;
7
- float north_angle;
8
- float world_tilt;
9
- float earth_distance;
10
- };
2
+ export const WebGlobeInfoUniformBlockString = `
3
+ layout(std140) uniform WebGlobeInfo {
4
+ vec2 canvas_resolution;
5
+ vec2 mouse_radian_long_lat;
6
+ vec2 mouse_pixel_xy;
7
+ float north_angle;
8
+ float world_tilt;
9
+ float earth_distance;
10
+ };
11
11
  `;
12
- export default class CameraUniformBlockTotem {
12
+ export default class CanvasWebGlobeInfo {
13
+ id;
14
+ description;
15
+ gl;
16
+ globe;
17
+ ubo;
18
+ traslateFloat32;
19
+ mapWHFloat32;
13
20
  constructor() {
14
- this.id = "CameraUniformBlockTotem";
15
- this.description = `Sets a uniform block and provides buffer for it. The following is the glsl uniform block:` + CameraUniformBlockString;
21
+ this.id = "CanvasWebGlobeInfo";
22
+ this.description =
23
+ `Sets a uniform block and provides buffer for it. The following is the glsl uniform block:` +
24
+ WebGlobeInfoUniformBlockString;
16
25
  this.gl = null;
17
26
  this.globe = null;
18
27
  this.ubo = null;
28
+ this.traslateFloat32 = new Float32Array(3);
29
+ this.mapWHFloat32 = new Float32Array(2);
19
30
  }
20
31
  init(globe, gl) {
21
32
  this.gl = gl;
@@ -27,8 +38,12 @@ export default class CameraUniformBlockTotem {
27
38
  this.resize();
28
39
  }
29
40
  _createUBO() {
30
- const { gl } = this;
41
+ if (!this.gl)
42
+ return null;
43
+ const gl = this.gl;
31
44
  const ubo = gl.createBuffer();
45
+ if (!ubo)
46
+ return null;
32
47
  gl.bindBuffer(gl.UNIFORM_BUFFER, ubo);
33
48
  gl.bufferData(gl.UNIFORM_BUFFER, 164, gl.STREAM_DRAW);
34
49
  gl.bindBufferBase(gl.UNIFORM_BUFFER, 0, ubo);
@@ -36,21 +51,28 @@ export default class CameraUniformBlockTotem {
36
51
  return ubo;
37
52
  }
38
53
  resize() {
54
+ if (!this.gl || !this.globe || !this.ubo)
55
+ return;
39
56
  const { gl, globe, ubo } = this;
40
57
  gl.bindBuffer(gl.UNIFORM_BUFFER, ubo);
41
58
  gl.bufferSubData(gl.UNIFORM_BUFFER, 152, new Float32Array([globe.api_ScrW(), globe.api_ScrH()]));
42
59
  gl.bindBuffer(gl.UNIFORM_BUFFER, null);
43
60
  }
44
61
  setGeometry() {
62
+ if (!this.gl || !this.globe || !this.ubo)
63
+ return;
45
64
  const { gl, globe, ubo } = this;
46
- const is3D = globe.api_GetCurrentGeometry() === 0;
65
+ const is3D = globe.api_GetCurrentGeometry() === 0 ? 1 : 0;
47
66
  gl.bindBuffer(gl.UNIFORM_BUFFER, ubo);
48
67
  gl.bufferSubData(gl.UNIFORM_BUFFER, 140, new Float32Array([is3D]));
49
68
  }
50
69
  draw3D(projection, modelView, translate) {
70
+ if (!this.gl || !this.globe || !this.ubo)
71
+ return;
51
72
  const { gl, traslateFloat32, ubo, mapWHFloat32, globe } = this;
52
73
  gl.bindBuffer(gl.UNIFORM_BUFFER, ubo);
53
- { // view, projection, translate
74
+ {
75
+ // view, projection, translate
54
76
  gl.bufferSubData(gl.UNIFORM_BUFFER, 0, modelView);
55
77
  gl.bufferSubData(gl.UNIFORM_BUFFER, 64, projection);
56
78
  traslateFloat32.set([translate.x, translate.y, translate.z], 0);
@@ -60,7 +82,8 @@ export default class CameraUniformBlockTotem {
60
82
  // zoom level
61
83
  gl.bufferSubData(gl.UNIFORM_BUFFER, 160, new Float32Array([globe.api_GetCurrentLODWithDecimal()]));
62
84
  }
63
- { // mapWH
85
+ {
86
+ // mapWH
64
87
  if (globe.api_GetCurrentGeometry() === 1) {
65
88
  const { width, height } = globe.api_GetCurrentWorldWH();
66
89
  mapWHFloat32.set([width, height]);
@@ -73,18 +96,26 @@ export default class CameraUniformBlockTotem {
73
96
  return this.ubo;
74
97
  }
75
98
  bind(bindingPoint) {
99
+ if (!this.gl || !this.ubo)
100
+ return;
76
101
  const { gl, ubo } = this;
77
102
  gl.bindBufferBase(gl.UNIFORM_BUFFER, bindingPoint, ubo);
78
103
  }
79
104
  unbind(bindingPoint) {
105
+ if (!this.gl)
106
+ return;
80
107
  const { gl } = this;
81
108
  gl.bindBufferBase(gl.UNIFORM_BUFFER, bindingPoint, null);
82
109
  }
83
110
  free() {
111
+ if (!this.gl || !this.ubo)
112
+ return;
84
113
  const { gl, ubo } = this;
85
114
  gl.deleteBuffer(ubo);
86
115
  }
87
116
  readBuffer() {
117
+ if (!this.gl || !this.ubo)
118
+ return null;
88
119
  const result = new Float32Array(41);
89
120
  this.gl.bindBuffer(this.gl.UNIFORM_BUFFER, this.ubo);
90
121
  this.gl.getBufferSubData(this.gl.UNIFORM_BUFFER, 0, result);
@@ -96,11 +127,15 @@ export default class CameraUniformBlockTotem {
96
127
  is3D: result[35],
97
128
  mapWH: result.slice(36, 38),
98
129
  screenWH: result.slice(38, 40),
99
- z_level: result[40]
130
+ z_level: result[40],
100
131
  };
101
132
  }
102
133
  }
103
- export const CameraUniformBlockTotemCache = Object.freeze({
104
- get: (globe) => { return globeProgramCache.getProgram(globe, CameraUniformBlockTotem); },
105
- release: (globe) => { return globeProgramCache.releaseProgram(globe, CameraUniformBlockTotem); }
134
+ export const CanvasWebGlobeInfoCache = Object.freeze({
135
+ get: (globe) => {
136
+ return globeProgramCache.getProgram(globe, CanvasWebGlobeInfo);
137
+ },
138
+ release: (globe) => {
139
+ return globeProgramCache.releaseProgram(globe, CanvasWebGlobeInfo);
140
+ },
106
141
  });