@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.
- package/Math/arc-cdf-points.js +252 -0
- package/Math/{arc-generate-points.js → arc-generate-points copy.js } +4 -0
- package/Math/arc-generate-points-exponantial.js +254 -0
- package/Math/arc.js +5 -5
- package/Math/circle-cdf-points.js +249 -0
- package/Math/circle.js +39 -0
- package/Math/methods.js +13 -3
- package/Math/vec3.js +3 -3
- package/package.json +1 -1
- package/programs/line-on-globe/linestrip.js +5 -6
- package/programs/totems/camerauniformblock.js +35 -8
- package/programs/totems/canvas-webglobe-info.js +55 -20
- package/programs/totems/{camerauniformblock1.js → canvas-webglobe-info1.js} +11 -76
- package/programs/vectorfields/logics/pixelbased.js +1 -1
- package/shape-on-terrain/arc/naive/plugin.js +204 -288
- package/shape-on-terrain/circle/plugin.js +252 -0
- package/util/account/single-attribute-buffer-management/buffer-orchestrator.js +2 -2
- package/util/build-strategy/general-strategy.js +62 -0
- package/util/build-strategy/static-dynamic.js +31 -0
- package/util/gl-util/draw-options/types.js +1 -1
- package/globe-types.js +0 -1
- package/programs/interface.js +0 -1
- package/programs/totems/camerauniformblock copy.js +0 -171
|
@@ -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
|
-
|
|
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
|
|
94
|
-
|
|
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
|
|
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
|
|
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,
|
|
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,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
|
|
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 =
|
|
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
|
|
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,
|
|
168
|
-
release: (globe) => noRegisterGlobeProgramCache.releaseProgram(globe,
|
|
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
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
3
|
-
layout(std140) uniform
|
|
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
|
|
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 = "
|
|
15
|
-
this.description =
|
|
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
|
-
|
|
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
|
-
{
|
|
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
|
-
{
|
|
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
|
|
104
|
-
get: (globe) => {
|
|
105
|
-
|
|
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
|
});
|