@pirireis/webglobeplugins 0.11.1-alpha → 0.13.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 +247 -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/circle-accurate.js +176 -175
- package/programs/line-on-globe/circle.js +166 -164
- package/programs/line-on-globe/linestrip/data.js +4 -0
- package/programs/line-on-globe/{linestrip.js → linestrip/linestrip.js} +38 -39
- package/programs/line-on-globe/to-the-surface.js +111 -109
- package/programs/rings/distancering/circleflatprogram.js +116 -120
- package/programs/rings/distancering/circlepaddingfreeangleprogram.js +1 -1
- package/programs/rings/distancering/circlepaddysharedbuffer.js +368 -354
- package/programs/rings/distancering/index.js +6 -5
- package/programs/rings/distancering/paddyflatprogram.js +127 -136
- package/programs/rings/distancering/paddyflatprogram2d.js +129 -138
- package/programs/rings/distancering/paddyflatprogram3d.js +128 -136
- package/programs/totems/camerauniformblock.js +35 -8
- package/programs/totems/canvas-webglobe-info.js +55 -20
- package/programs/totems/{camerauniformblock copy.js → canvas-webglobe-info1.js} +11 -76
- package/programs/vectorfields/logics/pixelbased.js +4 -20
- package/shape-on-terrain/arc/naive/plugin.js +249 -288
- package/shape-on-terrain/circle/plugin.js +284 -0
- package/shape-on-terrain/type.js +1 -0
- package/util/account/index.js +2 -2
- package/util/account/single-attribute-buffer-management/buffer-manager.js +2 -3
- 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/rings/distancering/shader.js +0 -1
- package/programs/totems/camerauniformblock1.js +0 -171
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { LineStripProgramCache } from "../../programs/line-on-globe/linestrip/linestrip";
|
|
2
|
+
import { BufferManager, BufferOrchestrator } from "../../util/account/single-attribute-buffer-management/index";
|
|
3
|
+
import { CameraUniformBlockTotemCache } from "../../programs/totems/camerauniformblock";
|
|
4
|
+
import { createBufferAndReadInfo } from '../../util/gl-util/buffer/attribute-loader';
|
|
5
|
+
import * as CircleMethods from "../../Math/circle";
|
|
6
|
+
import * as CircleCDF from "../../Math/circle-cdf-points";
|
|
7
|
+
import * as vec3 from "../../Math/vec3";
|
|
8
|
+
import { globe3Dcoordinates, globe2Dcoordinates } from "../../Math/methods";
|
|
9
|
+
import { StaticDynamicStrategy, StaticDynamicState } from "../../util/build-strategy/static-dynamic";
|
|
10
|
+
import { WORLD_RADIUS_3D, WORLD_RADIUS_MERCATOR } from "../../Math/constants";
|
|
11
|
+
const CIRCLE_POINTS_COUNT_HALF = 65; // Half of the points plus one for the reflection
|
|
12
|
+
const CIRCLE_POINTS_COUNT = CIRCLE_POINTS_COUNT_HALF * 2 - 1; // Number of points to approximate the circle
|
|
13
|
+
const DENSE_PART_SAMPLE_RATIO = 0.80; // Ratio of the dense part of the circle
|
|
14
|
+
const STRENGTH_FACTOR = 2; // Strength factor for the circle sampling
|
|
15
|
+
// --- TUNABLE PARAMETERS ---
|
|
16
|
+
const ATTRACTION_LEVELS = 7;
|
|
17
|
+
// Radius below which the most even sampling (level 0) is always used.
|
|
18
|
+
const MIN_RADIUS_KM = 5000;
|
|
19
|
+
// The radius (km) at the center of the transition for the reference LOD.
|
|
20
|
+
// DECREASE this to make mid-sized circles use uneven samples EARLIER.
|
|
21
|
+
const MID_TRANSITION_RADIUS_KM = WORLD_RADIUS_MERCATOR * 0.85;
|
|
22
|
+
const RADIUS_INFLUENCE = 0.55; // How much the radius influences the transition.
|
|
23
|
+
// The reference LOD for the transition.
|
|
24
|
+
const MID_TRANSITION_LOD = 10;
|
|
25
|
+
// How much LOD shifts the curve. Higher means LOD has more influence.
|
|
26
|
+
const LOD_INFLUENCE = 0.385;
|
|
27
|
+
// Steepness of the transition. Higher value = more abrupt switch.
|
|
28
|
+
// DECREASE this to make large circles transition to higher tiers SLOWER.
|
|
29
|
+
const TRANSITION_STEEPNESS = 0.77;
|
|
30
|
+
/**
|
|
31
|
+
* @param lod The current zoom level.
|
|
32
|
+
* @param radiusMeters The circle's radius in meters.
|
|
33
|
+
* @returns An integer level from 0 to ATTRACTION_LEVELS - 1.
|
|
34
|
+
*/
|
|
35
|
+
const defineStregthLevel = (lod, radiusMeters) => {
|
|
36
|
+
const radiusKm = radiusMeters;
|
|
37
|
+
// return ATTRACTION_LEVELS - 1;
|
|
38
|
+
// 1. Enforce a minimum radius for even sampling.
|
|
39
|
+
if (radiusKm < MIN_RADIUS_KM) {
|
|
40
|
+
return 0;
|
|
41
|
+
}
|
|
42
|
+
// 2. Combine radius and LOD into a single variable.
|
|
43
|
+
const log_r_mid = Math.log(MID_TRANSITION_RADIUS_KM);
|
|
44
|
+
const log_r = Math.log(radiusKm);
|
|
45
|
+
const combined_input = RADIUS_INFLUENCE * (log_r - log_r_mid) + LOD_INFLUENCE * (lod - MID_TRANSITION_LOD);
|
|
46
|
+
// 3. Apply the logistic (sigmoid) function to get a strength value [0, 1].
|
|
47
|
+
const strength_factor = 1.0 / (1.0 + Math.pow(2.4, -TRANSITION_STEEPNESS * combined_input));
|
|
48
|
+
// 4. Scale the result to the available attraction levels and clamp.
|
|
49
|
+
const level = Math.floor(strength_factor * ATTRACTION_LEVELS);
|
|
50
|
+
return Math.min(level, ATTRACTION_LEVELS - 1);
|
|
51
|
+
};
|
|
52
|
+
const AnglesStash = CircleCDF.createCummulativeTemplateStash(ATTRACTION_LEVELS, CIRCLE_POINTS_COUNT_HALF, DENSE_PART_SAMPLE_RATIO, STRENGTH_FACTOR);
|
|
53
|
+
const _colorArray = new Float32Array(4); // Used to store the color for each circle
|
|
54
|
+
export class CircleOnTerrainPlugin {
|
|
55
|
+
id;
|
|
56
|
+
globe = null;
|
|
57
|
+
gl = null;
|
|
58
|
+
lineProgram = null;
|
|
59
|
+
bufferManagerMap = new Map();
|
|
60
|
+
bufferOrchestrator = new BufferOrchestrator();
|
|
61
|
+
circleMap = new Map();
|
|
62
|
+
_cameraUniformBlock = null;
|
|
63
|
+
_isFree = false;
|
|
64
|
+
_circleUBOHandler = null;
|
|
65
|
+
_opacity = 1;
|
|
66
|
+
_vao = null;
|
|
67
|
+
_dobuild = true; // This is used to trigger the build of circles when the camera position changes.
|
|
68
|
+
_staticDynamicStrategy = null;
|
|
69
|
+
_styleOptions = {
|
|
70
|
+
variativeColorsOn: false,
|
|
71
|
+
defaultColor: [0.1, 0.1, 1, 1], // Default color in RGBA format
|
|
72
|
+
defaultHeightFromGroundIn3D: 30.0
|
|
73
|
+
};
|
|
74
|
+
constructor(id, styleOptions = {
|
|
75
|
+
variativeColorsOn: false, defaultColor: [0.1, 0.1, 1, 1]
|
|
76
|
+
}) {
|
|
77
|
+
this.id = id;
|
|
78
|
+
this._styleOptions = styleOptions;
|
|
79
|
+
this._styleOptions.defaultColor = new Float32Array(this._styleOptions.defaultColor);
|
|
80
|
+
}
|
|
81
|
+
init(globe, gl) {
|
|
82
|
+
this.globe = globe;
|
|
83
|
+
this.gl = gl;
|
|
84
|
+
// Initialize the program cache for line strip rendering.
|
|
85
|
+
this._staticDynamicStrategy = new StaticDynamicStrategy(globe, 8);
|
|
86
|
+
this.lineProgram = LineStripProgramCache.get(globe);
|
|
87
|
+
// const g3D = globe3Dcoordinates(globe, 30);
|
|
88
|
+
const g2D = globe2Dcoordinates(globe);
|
|
89
|
+
// Initialize with a reasonable initial capacity to prevent buffer size issues
|
|
90
|
+
const initialCapacity = 100; // Start with capacity for 100 circles
|
|
91
|
+
this.bufferManagerMap.set("position3d", {
|
|
92
|
+
bufferManager: new BufferManager(gl, (CIRCLE_POINTS_COUNT + 1) * 3, { initialCapacity }), // plus 1 is for butting linestrips
|
|
93
|
+
adaptor: (item) => {
|
|
94
|
+
const { longLatArr, height = this._styleOptions.defaultHeightFromGroundIn3D } = item;
|
|
95
|
+
const result = globe3Dcoordinates(globe, height)(longLatArr, { paddingCount: 1, paddingValue: NaN });
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
this.bufferManagerMap.set("position2d", {
|
|
100
|
+
bufferManager: new BufferManager(gl, (CIRCLE_POINTS_COUNT + 1) * 2, { initialCapacity }),
|
|
101
|
+
adaptor: (item) => {
|
|
102
|
+
const { longLatArr } = item;
|
|
103
|
+
const result = g2D(longLatArr, { paddingCount: 1, paddingValue: NaN });
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
if (this._styleOptions.variativeColorsOn) {
|
|
108
|
+
this.bufferManagerMap.set("color", {
|
|
109
|
+
bufferManager: new BufferManager(gl, 4, { initialCapacity }),
|
|
110
|
+
adaptor: (item) => {
|
|
111
|
+
const { radius } = item;
|
|
112
|
+
// Calculate color based on radius
|
|
113
|
+
if (item.color) {
|
|
114
|
+
_colorArray.set(item.color);
|
|
115
|
+
return _colorArray;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
return this._styleOptions.defaultColor;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
this._vao = this.lineProgram.createVAO(createBufferAndReadInfo(this.bufferManagerMap.get("position3d")?.bufferManager.buffer), createBufferAndReadInfo(this.bufferManagerMap.get("position2d")?.bufferManager.buffer), this._styleOptions.variativeColorsOn ?
|
|
124
|
+
createBufferAndReadInfo(this.bufferManagerMap.get("color")?.bufferManager.buffer) : null);
|
|
125
|
+
this._circleUBOHandler = this.lineProgram.createUBO();
|
|
126
|
+
this._cameraUniformBlock = CameraUniformBlockTotemCache.get(globe);
|
|
127
|
+
}
|
|
128
|
+
insertCircle(key, longitude, latitude, radius, height = null) {
|
|
129
|
+
const circle = {
|
|
130
|
+
center: [longitude, latitude],
|
|
131
|
+
radius: radius
|
|
132
|
+
};
|
|
133
|
+
const circleForAzimuthCalc = CircleMethods.createCircleClosestAzimuthAngleProperties(circle);
|
|
134
|
+
this.circleMap.set(key, [circle, circleForAzimuthCalc, height]);
|
|
135
|
+
// @ts-ignore
|
|
136
|
+
if (this._staticDynamicStrategy.getState() !== StaticDynamicState.DYNAMIC) {
|
|
137
|
+
this.__buildStaticCircles([key]);
|
|
138
|
+
}
|
|
139
|
+
this.globe?.DrawRender();
|
|
140
|
+
}
|
|
141
|
+
deleteCircle(keys) {
|
|
142
|
+
for (const key of keys) {
|
|
143
|
+
if (this.circleMap.has(key)) {
|
|
144
|
+
this.circleMap.delete(key);
|
|
145
|
+
this.globe?.DrawRender();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
this._dobuild = true;
|
|
149
|
+
this.globe?.DrawRender();
|
|
150
|
+
}
|
|
151
|
+
// IMPLICIT METHODS
|
|
152
|
+
_buildCircles() {
|
|
153
|
+
// @ts-ignore
|
|
154
|
+
this._staticDynamicStrategy?.updateState();
|
|
155
|
+
const state = this._staticDynamicStrategy?.getState();
|
|
156
|
+
if (state === StaticDynamicState.TO_STATIC)
|
|
157
|
+
console.log("state", state);
|
|
158
|
+
if (state === StaticDynamicState.TO_STATIC) {
|
|
159
|
+
this.__buildStaticCircles();
|
|
160
|
+
}
|
|
161
|
+
else if (state === StaticDynamicState.DYNAMIC) {
|
|
162
|
+
this.__buildCircles();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
__buildCircles() {
|
|
166
|
+
const { globe, gl, _cameraUniformBlock, lineProgram, bufferOrchestrator, bufferManagerMap, circleMap } = this;
|
|
167
|
+
if (!globe || !gl || !_cameraUniformBlock || !lineProgram ||
|
|
168
|
+
!bufferOrchestrator || !bufferManagerMap || !circleMap)
|
|
169
|
+
throw new Error("Plugin not initialized properly");
|
|
170
|
+
// unoptimized.. resets all circles.
|
|
171
|
+
bufferOrchestrator.resetWithCapacity(bufferManagerMap, circleMap.size);
|
|
172
|
+
// Prepare the data for the buffers
|
|
173
|
+
const data = [{
|
|
174
|
+
key: "",
|
|
175
|
+
longLatArr: [],
|
|
176
|
+
height: null
|
|
177
|
+
}];
|
|
178
|
+
const lookAtPosition = _cameraUniformBlock.getLookAtVector();
|
|
179
|
+
const cameraPosition = _cameraUniformBlock.getNormalizedCameraVector();
|
|
180
|
+
vec3.divideScalar(cameraPosition, cameraPosition, WORLD_RADIUS_3D);
|
|
181
|
+
vec3.add(cameraPosition, cameraPosition, lookAtPosition);
|
|
182
|
+
vec3.normalize(cameraPosition, cameraPosition);
|
|
183
|
+
const currentLOD = globe.api_GetCurrentLODWithDecimal();
|
|
184
|
+
const circlePointsLongLat = new Float64Array((CIRCLE_POINTS_COUNT) * 2);
|
|
185
|
+
for (const [key, circle] of this.circleMap.entries()) {
|
|
186
|
+
const [{ radius, center }, circleForAzimuthCalc, height] = circle;
|
|
187
|
+
const closestAzimuthAngle = CircleMethods.closestAzimuthAngle(circleForAzimuthCalc, cameraPosition);
|
|
188
|
+
const stregthLevel = defineStregthLevel(currentLOD, radius);
|
|
189
|
+
// console.log('DrawStregthLevel', stregthLevel, currentLOD, radius);
|
|
190
|
+
if (stregthLevel < 0) {
|
|
191
|
+
console.warn(`CircleOnTerrainPlugin: Circle ${key} has too small radius for current LOD ${currentLOD}. Skipping., radius: ${radius}, stregthLevel: ${stregthLevel}`);
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
const templateAngles = AnglesStash[stregthLevel];
|
|
195
|
+
CircleCDF.globeFindPointByPolarHalfCircle(circlePointsLongLat, globe, center[0], center[1], radius, closestAzimuthAngle, templateAngles);
|
|
196
|
+
data[0].key = key;
|
|
197
|
+
data[0].longLatArr = circlePointsLongLat;
|
|
198
|
+
data[0].height = height;
|
|
199
|
+
// Add to buffer orchestrator
|
|
200
|
+
this.bufferOrchestrator.insertBulk(data, bufferManagerMap);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
// this will be used to build static circles, which are not affected by camera position or LOD.
|
|
204
|
+
// LOD < 8 or something
|
|
205
|
+
__buildStaticCircles(subSetIDs = null) {
|
|
206
|
+
const { globe, gl, _cameraUniformBlock, lineProgram, bufferOrchestrator, bufferManagerMap, circleMap } = this;
|
|
207
|
+
if (!globe || !gl || !_cameraUniformBlock || !lineProgram ||
|
|
208
|
+
!bufferOrchestrator || !bufferManagerMap || !circleMap)
|
|
209
|
+
throw new Error("Plugin not initialized properly");
|
|
210
|
+
const data = [{
|
|
211
|
+
key: "",
|
|
212
|
+
longLatArr: [],
|
|
213
|
+
height: null
|
|
214
|
+
}];
|
|
215
|
+
// ensure buffer orchestrotrator have enough capacity
|
|
216
|
+
// all circles are build with even sampling, AttractionLevel = 0
|
|
217
|
+
const templateAngles = AnglesStash[0];
|
|
218
|
+
const zeroRotation = 0;
|
|
219
|
+
if (!subSetIDs || subSetIDs.length === 0) {
|
|
220
|
+
const circlePointsLongLat = new Float64Array((CIRCLE_POINTS_COUNT) * 2);
|
|
221
|
+
bufferOrchestrator.resetWithCapacity(bufferManagerMap, circleMap.size);
|
|
222
|
+
for (const [key, circle] of this.circleMap.entries()) {
|
|
223
|
+
const [{ radius, center }, _, height] = circle;
|
|
224
|
+
CircleCDF.globeFindPointByPolarHalfCircle(circlePointsLongLat, globe, center[0], center[1], radius, zeroRotation, templateAngles);
|
|
225
|
+
data[0].key = key;
|
|
226
|
+
data[0].longLatArr = circlePointsLongLat;
|
|
227
|
+
data[0].height = height;
|
|
228
|
+
this.bufferOrchestrator.insertBulk(data, bufferManagerMap);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
// This does check the size beforehand.
|
|
233
|
+
// subset is probably is used to insert a single item or,
|
|
234
|
+
// rebuild of existing items which passed from rbushTree or similar indexed search.
|
|
235
|
+
// therefore, it is not necessary to check for new items and extend capacity
|
|
236
|
+
for (let key of subSetIDs) {
|
|
237
|
+
if (!this.circleMap.has(key)) {
|
|
238
|
+
console.warn(`CircleOnTerrainPlugin: Circle ${key} not found in circleMap.`);
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
const [{ radius, center }, _, height] = this.circleMap.get(key);
|
|
242
|
+
const circlePointsLongLat = new Float64Array((CIRCLE_POINTS_COUNT) * 2);
|
|
243
|
+
CircleCDF.globeFindPointByPolarHalfCircle(circlePointsLongLat, globe, center[0], center[1], radius, zeroRotation, templateAngles);
|
|
244
|
+
data[0].key = key;
|
|
245
|
+
data[0].longLatArr = circlePointsLongLat;
|
|
246
|
+
data[0].height = height;
|
|
247
|
+
this.bufferOrchestrator.insertBulk(data, bufferManagerMap);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// GLOBE API INTERFACE
|
|
252
|
+
draw3D() {
|
|
253
|
+
const { _isFree, globe, gl, lineProgram, bufferOrchestrator, bufferManagerMap, _vao, _circleUBOHandler } = this;
|
|
254
|
+
if (_isFree || !globe || !gl || !lineProgram || !bufferOrchestrator ||
|
|
255
|
+
!bufferManagerMap || !_vao || !_circleUBOHandler) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
this._buildCircles();
|
|
259
|
+
const drawOptions = {
|
|
260
|
+
drawRange: {
|
|
261
|
+
first: 0,
|
|
262
|
+
count: bufferOrchestrator.length * (CIRCLE_POINTS_COUNT + 1), // plus 1 is for cutting linestrips
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
gl.disable(gl.DEPTH_TEST);
|
|
266
|
+
lineProgram.draw(_vao, drawOptions, this._opacity, _circleUBOHandler);
|
|
267
|
+
gl.enable(gl.DEPTH_TEST);
|
|
268
|
+
}
|
|
269
|
+
free() {
|
|
270
|
+
if (this._isFree)
|
|
271
|
+
return;
|
|
272
|
+
this._isFree = true;
|
|
273
|
+
if (this.lineProgram) {
|
|
274
|
+
LineStripProgramCache.release(this.lineProgram);
|
|
275
|
+
this.lineProgram = null;
|
|
276
|
+
}
|
|
277
|
+
this.circleMap.clear();
|
|
278
|
+
this.bufferManagerMap.forEach(({ bufferManager }) => {
|
|
279
|
+
bufferManager.free();
|
|
280
|
+
});
|
|
281
|
+
this.bufferManagerMap.clear();
|
|
282
|
+
CameraUniformBlockTotemCache.release(this.globe);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/util/account/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import BufferOffsetManager from './bufferoffsetmanager';
|
|
2
|
-
export { BufferOffsetManager };
|
|
1
|
+
// import BufferOffsetManager from './bufferoffsetmanager';
|
|
2
|
+
// export { BufferOffsetManager };
|
|
3
3
|
export * from './single-attribute-buffer-management/index';
|
|
@@ -22,13 +22,12 @@ export class BufferManager {
|
|
|
22
22
|
itemSize;
|
|
23
23
|
bufferType;
|
|
24
24
|
isFreed = false;
|
|
25
|
-
constructor(gl, itemSize, { bufferType = "STATIC_DRAW", buffer = null, initialCapacity =
|
|
25
|
+
constructor(gl, itemSize, { bufferType = "STATIC_DRAW", buffer = null, initialCapacity = 10 } = {}) {
|
|
26
26
|
this.gl = gl;
|
|
27
27
|
this.itemSize = itemSize;
|
|
28
28
|
this.bufferType = bufferType;
|
|
29
29
|
this.buffer = buffer === null ? gl.createBuffer() : buffer;
|
|
30
|
-
|
|
31
|
-
this.resetWithCapacity(initialCapacity);
|
|
30
|
+
this.resetWithCapacity(initialCapacity);
|
|
32
31
|
}
|
|
33
32
|
resetWithCapacity(capacity) {
|
|
34
33
|
const { gl, buffer, bufferType, itemSize } = this;
|
|
@@ -20,7 +20,7 @@ export class BufferOrchestrator {
|
|
|
20
20
|
this._length = 0;
|
|
21
21
|
}
|
|
22
22
|
insertBulk(items, bufferManagersMap) {
|
|
23
|
-
this.
|
|
23
|
+
this.ensureSpace(items.length, bufferManagersMap);
|
|
24
24
|
const { offsetMap } = this;
|
|
25
25
|
const offsets = [];
|
|
26
26
|
for (const item of items) {
|
|
@@ -88,7 +88,7 @@ export class BufferOrchestrator {
|
|
|
88
88
|
}
|
|
89
89
|
return false;
|
|
90
90
|
}
|
|
91
|
-
|
|
91
|
+
ensureSpace(itemsLength, bufferManagersMap) {
|
|
92
92
|
if (itemsLength <= this.emptySpace)
|
|
93
93
|
return;
|
|
94
94
|
const newCapacity = this.length + itemsLength;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* # Considerations ---
|
|
3
|
+
* - RABIT LOD change should trigger build immediately
|
|
4
|
+
* - CRUD operations should trigger build immediately
|
|
5
|
+
* - CameraAngle Change should trigger build immediately for Plugins employ DENSITY variation mechanism
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
var State;
|
|
9
|
+
(function (State) {
|
|
10
|
+
State["STATIC"] = "STATIC";
|
|
11
|
+
State["DYNAMIC"] = "DYNAMIC";
|
|
12
|
+
State["TRANSIENT"] = "TRANSIENT";
|
|
13
|
+
})(State || (State = {}));
|
|
14
|
+
class GeneralStrategy {
|
|
15
|
+
globe;
|
|
16
|
+
_state = State.DYNAMIC;
|
|
17
|
+
_transitionLevel = 8; // Default transition level
|
|
18
|
+
_lastLOD = 1000; // an extreme value to trigger initial build
|
|
19
|
+
_lastCameraPosition = [0, 0, 0]; // Initial camera position
|
|
20
|
+
_lastLookInfo = {
|
|
21
|
+
CenterLong: 0,
|
|
22
|
+
CenterLat: 0,
|
|
23
|
+
Distance: 0,
|
|
24
|
+
Tilt: 0,
|
|
25
|
+
NorthAng: 0
|
|
26
|
+
};
|
|
27
|
+
_currentLOD = 1000; // an extreme value to trigger initial build
|
|
28
|
+
_currentCameraPosition = [0, 0, 0]; // Initial camera position
|
|
29
|
+
_currentLookInfo = {
|
|
30
|
+
CenterLong: 0,
|
|
31
|
+
CenterLat: 0,
|
|
32
|
+
Distance: 0,
|
|
33
|
+
Tilt: 0,
|
|
34
|
+
NorthAng: 0
|
|
35
|
+
};
|
|
36
|
+
// private _staticBuildThreshold: number = 8; // Default static build threshold
|
|
37
|
+
// private _triggerStaticBuild: boolean = false;
|
|
38
|
+
// private _isMovedParams: boolean = false
|
|
39
|
+
// private _isCameraChangedParams: boolean = false
|
|
40
|
+
// private _elevationChangedParams: boolean = false
|
|
41
|
+
constructor(globe, transitionLevel = 8) {
|
|
42
|
+
// Initialization logic if needed
|
|
43
|
+
this.globe = globe;
|
|
44
|
+
this._transitionLevel = transitionLevel;
|
|
45
|
+
}
|
|
46
|
+
calculateState() {
|
|
47
|
+
}
|
|
48
|
+
getState() {
|
|
49
|
+
return this._state;
|
|
50
|
+
}
|
|
51
|
+
// Additional methods and properties can be added here as needed
|
|
52
|
+
// @ts-ignore
|
|
53
|
+
_isMoved() {
|
|
54
|
+
}
|
|
55
|
+
// @ts-ignore
|
|
56
|
+
_isCameraChanged() {
|
|
57
|
+
}
|
|
58
|
+
// @ts-ignore
|
|
59
|
+
_elevationChanged() {
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export var StaticDynamicState;
|
|
2
|
+
(function (StaticDynamicState) {
|
|
3
|
+
StaticDynamicState["STATIC"] = "STATIC";
|
|
4
|
+
StaticDynamicState["DYNAMIC"] = "DYNAMIC";
|
|
5
|
+
StaticDynamicState["TO_STATIC"] = "TO_STATIC"; // TODO: Change this not bidirectional, go to static
|
|
6
|
+
})(StaticDynamicState || (StaticDynamicState = {}));
|
|
7
|
+
export class StaticDynamicStrategy {
|
|
8
|
+
globe;
|
|
9
|
+
_staticDynamicState = StaticDynamicState.DYNAMIC;
|
|
10
|
+
_transitionLevel = 8; // Default transition level
|
|
11
|
+
_lastStaticDynamicState = StaticDynamicState.STATIC;
|
|
12
|
+
constructor(globe, transitionLevel = 8) {
|
|
13
|
+
this.globe = globe;
|
|
14
|
+
this._transitionLevel = transitionLevel;
|
|
15
|
+
this.updateState();
|
|
16
|
+
}
|
|
17
|
+
updateState() {
|
|
18
|
+
const currentLOD = this.globe.api_GetCurrentLODWithDecimal();
|
|
19
|
+
const state = currentLOD < this._transitionLevel ? StaticDynamicState.STATIC : StaticDynamicState.DYNAMIC;
|
|
20
|
+
if (this._lastStaticDynamicState === StaticDynamicState.DYNAMIC && state === StaticDynamicState.STATIC) {
|
|
21
|
+
this._staticDynamicState = StaticDynamicState.TO_STATIC;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
this._staticDynamicState = state;
|
|
25
|
+
}
|
|
26
|
+
this._lastStaticDynamicState = this._staticDynamicState;
|
|
27
|
+
}
|
|
28
|
+
getState() {
|
|
29
|
+
return this._staticDynamicState;
|
|
30
|
+
}
|
|
31
|
+
}
|
package/globe-types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";
|
package/programs/interface.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
import { globeProgramCache } from "../programcache";
|
|
2
|
-
// import { getFrustumPlanes } from "../../Math/frustum/from-projection-matrix";
|
|
3
|
-
// import { getFrustum } from "../../Math/frustum/from-globeinfo"
|
|
4
|
-
// import { Plane } from "../../Math/";
|
|
5
|
-
export const CameraUniformBlockString = `
|
|
6
|
-
layout(std140) uniform CameraUniformBlock {
|
|
7
|
-
mat4 view; // 64 bytes 0
|
|
8
|
-
mat4 projection; // 64 bytes 64
|
|
9
|
-
vec3 translate; // 12 bytes 128
|
|
10
|
-
bool is3D; // 4 bytes 140
|
|
11
|
-
vec2 mapWH; // 8 bytes 144
|
|
12
|
-
vec2 screenWH; // 8 bytes 152
|
|
13
|
-
float z_level; // 4 bytes 160 | 164
|
|
14
|
-
float world_distance; // 4 bytes 164
|
|
15
|
-
float world_tilt; // 4 bytes 168
|
|
16
|
-
float world_north_angle; // 4 bytes 172
|
|
17
|
-
vec2 world_center_radian; // 8 bytes 176 | 184
|
|
18
|
-
}; // 14 lines
|
|
19
|
-
`;
|
|
20
|
-
const Radian = Math.PI / 180.0;
|
|
21
|
-
export default class CameraUniformBlockTotem {
|
|
22
|
-
constructor() {
|
|
23
|
-
this.id = "CameraUniformBlockTotem";
|
|
24
|
-
this.description = `Sets a uniform block and provides buffer for it. The following is the glsl uniform block:` + CameraUniformBlockString;
|
|
25
|
-
this.gl = null;
|
|
26
|
-
this.globe = null;
|
|
27
|
-
this.ubo = null;
|
|
28
|
-
// this._frustumPlanes = {
|
|
29
|
-
// left: new Plane(),
|
|
30
|
-
// right: new Plane(),
|
|
31
|
-
// top: new Plane(),
|
|
32
|
-
// bottom: new Plane(),
|
|
33
|
-
// near: new Plane(),
|
|
34
|
-
// far: new Plane()
|
|
35
|
-
// }
|
|
36
|
-
this._isMovedParams = {
|
|
37
|
-
lastLod: null,
|
|
38
|
-
isMoved: false,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
init(globe, gl) {
|
|
42
|
-
this.gl = gl;
|
|
43
|
-
this.globe = globe;
|
|
44
|
-
this.ubo = this._createUBO();
|
|
45
|
-
this.traslateFloat32 = new Float32Array(3);
|
|
46
|
-
this.mapWHFloat32 = new Float32Array(2);
|
|
47
|
-
this.setGeometry();
|
|
48
|
-
this.resize();
|
|
49
|
-
}
|
|
50
|
-
_createUBO() {
|
|
51
|
-
const { gl } = this;
|
|
52
|
-
const ubo = gl.createBuffer();
|
|
53
|
-
gl.bindBuffer(gl.UNIFORM_BUFFER, ubo);
|
|
54
|
-
// 184 bytes in reality. Overflow on linux for some reason. So, 200 bytes.
|
|
55
|
-
gl.bufferData(gl.UNIFORM_BUFFER, 200, gl.STREAM_DRAW);
|
|
56
|
-
gl.bindBufferBase(gl.UNIFORM_BUFFER, 0, ubo);
|
|
57
|
-
gl.bindBuffer(gl.UNIFORM_BUFFER, null);
|
|
58
|
-
return ubo;
|
|
59
|
-
}
|
|
60
|
-
resize() {
|
|
61
|
-
const { gl, globe, ubo } = this;
|
|
62
|
-
gl.bindBuffer(gl.UNIFORM_BUFFER, ubo);
|
|
63
|
-
gl.bufferSubData(gl.UNIFORM_BUFFER, 152, new Float32Array([globe.api_ScrW(), globe.api_ScrH()]));
|
|
64
|
-
gl.bindBuffer(gl.UNIFORM_BUFFER, null);
|
|
65
|
-
}
|
|
66
|
-
setGeometry() {
|
|
67
|
-
const { gl, globe, ubo } = this;
|
|
68
|
-
const is3D = globe.api_GetCurrentGeometry() === 0;
|
|
69
|
-
gl.bindBuffer(gl.UNIFORM_BUFFER, ubo);
|
|
70
|
-
gl.bufferSubData(gl.UNIFORM_BUFFER, 140, new Float32Array([is3D]));
|
|
71
|
-
}
|
|
72
|
-
draw3D(projection, modelView, translate) {
|
|
73
|
-
const { gl, traslateFloat32, ubo, mapWHFloat32, globe } = this;
|
|
74
|
-
gl.bindBuffer(gl.UNIFORM_BUFFER, ubo);
|
|
75
|
-
{ // view, projection, translat
|
|
76
|
-
gl.bufferSubData(gl.UNIFORM_BUFFER, 0, modelView);
|
|
77
|
-
gl.bufferSubData(gl.UNIFORM_BUFFER, 64, projection);
|
|
78
|
-
traslateFloat32.set([translate.x, translate.y, translate.z], 0);
|
|
79
|
-
gl.bufferSubData(gl.UNIFORM_BUFFER, 128, traslateFloat32);
|
|
80
|
-
}
|
|
81
|
-
{
|
|
82
|
-
// zoom level
|
|
83
|
-
gl.bufferSubData(gl.UNIFORM_BUFFER, 160, new Float32Array([globe.api_GetCurrentLODWithDecimal()]));
|
|
84
|
-
}
|
|
85
|
-
{ // mapWH
|
|
86
|
-
if (globe.api_GetCurrentGeometry() === 1) {
|
|
87
|
-
const { width, height } = globe.api_GetCurrentWorldWH();
|
|
88
|
-
mapWHFloat32.set([width, height]);
|
|
89
|
-
gl.bufferSubData(gl.UNIFORM_BUFFER, 144, mapWHFloat32);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
{
|
|
93
|
-
// float world_distance; // 4 bytes 164
|
|
94
|
-
// float world_tilt; // 4 bytes 168
|
|
95
|
-
// float world_north_angle; // 4 bytes 172
|
|
96
|
-
// vec2 world_center_radian; // 8 bytes 180
|
|
97
|
-
const { CenterLong, CenterLat, Distance, Tilt, NorthAng } = globe.api_GetCurrentLookInfo();
|
|
98
|
-
gl.bufferSubData(gl.UNIFORM_BUFFER, 164, new Float32Array([
|
|
99
|
-
Distance, Radian * Tilt, Radian * NorthAng, Radian * CenterLong, Radian * CenterLat
|
|
100
|
-
]));
|
|
101
|
-
}
|
|
102
|
-
// this._frustumPlanes = getFrustumPlanes(projection, translate);
|
|
103
|
-
gl.bindBuffer(gl.UNIFORM_BUFFER, null);
|
|
104
|
-
{ // isMoved
|
|
105
|
-
const currentLOD = globe.api_GetCurrentLODWithDecimal();
|
|
106
|
-
this._isMovedParams.isMoved = this._isMovedParams.lastLod !== currentLOD || globe.api_IsScreenMoving();
|
|
107
|
-
this._isMovedParams.lastLod = currentLOD;
|
|
108
|
-
}
|
|
109
|
-
// getFrustum(globe, 50, this._frustumPlanes);
|
|
110
|
-
this._normalizedCameraVector = (() => {
|
|
111
|
-
const { Fp, FUPos } = globe;
|
|
112
|
-
const cameraVector = [Fp.x, Fp.y, Fp.z];
|
|
113
|
-
const length = Math.sqrt(cameraVector.reduce((sum, val) => sum + val * val, 0));
|
|
114
|
-
return normalizedCameraVector.map(val => val / length);
|
|
115
|
-
})();
|
|
116
|
-
}
|
|
117
|
-
assignBindingPoint(program, bindingPoint) {
|
|
118
|
-
const { gl } = this;
|
|
119
|
-
const cameraBlockIndex = gl.getUniformBlockIndex(program, "CameraUniformBlock");
|
|
120
|
-
gl.uniformBlockBinding(program, cameraBlockIndex, bindingPoint);
|
|
121
|
-
}
|
|
122
|
-
getUBO() {
|
|
123
|
-
return this.ubo;
|
|
124
|
-
}
|
|
125
|
-
getFrustumPlanes() {
|
|
126
|
-
return this._frustumPlanes;
|
|
127
|
-
}
|
|
128
|
-
bind(bindingPoint) {
|
|
129
|
-
const { gl, ubo } = this;
|
|
130
|
-
gl.bindBufferBase(gl.UNIFORM_BUFFER, bindingPoint, ubo);
|
|
131
|
-
}
|
|
132
|
-
unbind(bindingPoint) {
|
|
133
|
-
const { gl } = this;
|
|
134
|
-
gl.bindBufferBase(gl.UNIFORM_BUFFER, bindingPoint, null);
|
|
135
|
-
}
|
|
136
|
-
isMoved() {
|
|
137
|
-
return this._isMovedParams.isMoved;
|
|
138
|
-
}
|
|
139
|
-
getCameraVector() {
|
|
140
|
-
return [this.globe.Fp.x, this.globe.Fp.y, this.globe.Fp.z];
|
|
141
|
-
}
|
|
142
|
-
getNormalizedCameraVector() {
|
|
143
|
-
return this._normalizedCameraVector;
|
|
144
|
-
}
|
|
145
|
-
getCameraUpPosition() {
|
|
146
|
-
return [this.globe.FUPos.x, this.globe.FUPos.y, this.globe.FUPos.z];
|
|
147
|
-
}
|
|
148
|
-
free() {
|
|
149
|
-
const { gl, ubo } = this;
|
|
150
|
-
gl.deleteBuffer(ubo);
|
|
151
|
-
}
|
|
152
|
-
readBuffer() {
|
|
153
|
-
const result = new Float32Array(41);
|
|
154
|
-
this.gl.bindBuffer(this.gl.UNIFORM_BUFFER, this.ubo);
|
|
155
|
-
this.gl.getBufferSubData(this.gl.UNIFORM_BUFFER, 0, result);
|
|
156
|
-
this.gl.bindBuffer(this.gl.UNIFORM_BUFFER, null);
|
|
157
|
-
return {
|
|
158
|
-
view: result.slice(0, 16),
|
|
159
|
-
projection: result.slice(16, 32),
|
|
160
|
-
translate: result.slice(32, 35),
|
|
161
|
-
is3D: result[35],
|
|
162
|
-
mapWH: result.slice(36, 38),
|
|
163
|
-
screenWH: result.slice(38, 40),
|
|
164
|
-
z_level: result[40]
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
export const CameraUniformBlockTotemCache = Object.freeze({
|
|
169
|
-
get: (globe) => { return globeProgramCache.getProgram(globe, CameraUniformBlockTotem); },
|
|
170
|
-
release: (globe) => { return globeProgramCache.releaseProgram(globe, CameraUniformBlockTotem); }
|
|
171
|
-
});
|