@pirireis/webglobeplugins 0.1.9 → 0.2.0

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.
File without changes
@@ -0,0 +1,151 @@
1
+ import { programCache as ringProgramCache } from '../partialrings/program';
2
+ import { LineOnGlobeCache } from '../programs/line-on-globe/naive';
3
+
4
+ export const RINGPARTIAL_DRAW_MODE = Object.freeze({
5
+ LINE_STRIP: "LINE_STRIP",
6
+ TRIANGLE_FAN: "TRIANGLE_FAN",
7
+ });
8
+
9
+ export default class Plugin {
10
+
11
+ constructor(id, { opacity = 1 } = {}) {
12
+ this.id = id;
13
+ this._opacity = opacity;
14
+ }
15
+
16
+ setOpacity(opacity) {
17
+ this._opacity = opacity;
18
+ this.globe.DrawRender();
19
+ }
20
+
21
+ init(globe, gl) {
22
+ this.gl = gl;
23
+ this.globe = globe;
24
+ this.lineProgram = LineOnGlobeCache.get(globe);
25
+ this.ringProgram = ringProgramCache.get(globe);
26
+ this.lineBufferManager = this.lineProgram.createBufferManager();
27
+ const { bufferManager, vao } = this.ringProgram.getBufferManagerAndVao();
28
+ this.ringBufferManager = bufferManager;
29
+ this.ringVao = vao;
30
+ }
31
+
32
+
33
+ draw3D() {
34
+ // vao, edgeCount, alphaMultiplier, drawMode,
35
+ this.lineProgram.draw(this.lineBufferManager.vao, this.lineBufferManager.length, this._opacity);
36
+ //bufferManager, vao, edgeCount, alphaMultiplier, drawMode
37
+ this.gl.disable(this.gl.DEPTH_TEST);
38
+ this.ringProgram.draw(this.ringBufferManager.length, this.ringVao, 32, this._opacity * 0.9, RINGPARTIAL_DRAW_MODE.TRIANGLE_FAN);
39
+ this.ringProgram.draw(this.ringBufferManager.length, this.ringVao, 32, this._opacity, RINGPARTIAL_DRAW_MODE.LINE_STRIP);
40
+ this.gl.enable(this.gl.DEPTH_TEST);
41
+ }
42
+
43
+
44
+ /**
45
+ *
46
+ * @param {Array<{key, long, lat, endLong, endLat, bearingAngle, radius, rgba:[4numbers]}>} items
47
+ */
48
+
49
+ insertBulk(items) {
50
+ for (let item of items) {
51
+ const { lat, long, endLat, endLong, radius = null, rgbaMode = null, bearingAngle = 0 } = item;
52
+ item.long = radian(long);
53
+ item.lat = radian(lat);
54
+ item.endLong = radian(endLong);
55
+ item.endLat = radian(endLat);
56
+ if (radius === null) {
57
+ item.radius = 100000;
58
+ }
59
+ if (rgbaMode === null) {
60
+ item.rgbaMode = 0;
61
+ }
62
+ const startAngle = calculateStartAngle(item.long, item.lat, item.endLong, item.endLat);
63
+
64
+ item.startAngle = startAngle;
65
+ const shaderBearingAngle = radian(bearingAngle - 90);
66
+ item.tailAngle = shaderBearingAngle - startAngle;
67
+ }
68
+ this.lineBufferManager.insertBulk(items);
69
+ this.ringBufferManager.insertBulk(items);
70
+ this.globe.DrawRender();
71
+ }
72
+
73
+ /**
74
+ *
75
+ * @param {Array<{key, long, lat, endLong, endLat, bearingAngle, rgba:[4numbers], colorMode}>} items // TIDI
76
+ */
77
+ updateBulk(items) { //TODO
78
+ this.lineBufferManager.updateBulk(items);
79
+ for (let item of items) {
80
+ const { long, lat, endLong, endLat } = item;
81
+ item.long = radian(long);
82
+ item.lat = radian(lat);
83
+ item.endLong = radian(endLong);
84
+ item.endLat = radian(endLat);
85
+ const startAngle = calculateStartAngle(item.long, item.lat, item.endLong, item.endLat);
86
+ item.startAngle = startAngle;
87
+ }
88
+ this.ringBufferManager.updateBulk(items);
89
+ this.globe.DrawRender();
90
+ }
91
+
92
+
93
+ deleteBulk(keys) {
94
+ this.lineBufferManager.deleteBulk(keys);
95
+ this.ringBufferManager.deleteBulk(keys);
96
+ this.globe.DrawRender();
97
+ }
98
+
99
+
100
+ defrag() {
101
+ this.lineBufferManager.defrag();
102
+ this.ringBufferManager.defrag();
103
+ this.globe.DrawRender();
104
+ }
105
+
106
+ /**
107
+ *
108
+ * @param {Array<{key, long, lat, endLong, endLat, bearing}>} items // TODO
109
+ */
110
+ updateCoordinatesBulk(items) { //TODO
111
+ for (let item of items) {
112
+ const { long, lat, endLong, endLat, bearingAngle } = item;
113
+ item.long = radian(long);
114
+ item.lat = radian(lat);
115
+ item.endLong = radian(endLong);
116
+ item.endLat = radian(endLat);
117
+ const startAngle = calculateStartAngle(item.long, item.lat, item.endLong, item.endLat);
118
+ item.startAngle = startAngle;
119
+ item.tailAngle = radian(bearingAngle - 90) - startAngle;
120
+ }
121
+ this.ringBufferManager.updateCenterAndAngleBulk(items);
122
+ this.lineBufferManager.updateCoordinatesBulk(items);
123
+ this.globe.DrawRender();
124
+ }
125
+
126
+ //TODO free
127
+ free() {
128
+ if (this.isFreed) return;
129
+ this.lineBufferManager.free();
130
+ this.ringBufferManager.free();
131
+ LineOnGlobeCache.free(this.globe);
132
+ ringProgramCache.free(this.globe);
133
+ this.isFreed = true;
134
+ }
135
+ }
136
+
137
+
138
+ const radian = (degree) => degree * Math.PI / 180;
139
+
140
+ const integralSec = (angle) => {
141
+ return Math.log(Math.tan(angle / 2 + Math.PI / 4));
142
+ }
143
+
144
+ const calculateStartAngle = (long, lat, endLong, endLat) => {
145
+ const dLat = (integralSec(endLat) - integralSec(lat)); // Because lines are strectes toward poles.
146
+ const dLong = endLong - long;
147
+
148
+ let angle = -Math.atan2(dLat, dLong);
149
+ return angle;
150
+ }
151
+
@@ -0,0 +1,3 @@
1
+ # Two proglems:
2
+ lines are curved to to arrive perpendicular to the longitude lines
3
+ patrial rings are not fit to the lines nor the bearing angle
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pirireis/webglobeplugins",
3
- "version": "0.1.9",
3
+ "version": "0.2.0",
4
4
  "main": "index.js",
5
5
  "author": "Toprak Nihat Deniz Ozturk",
6
6
  "license": "MIT"
@@ -0,0 +1,89 @@
1
+ import BufferOffsetManager from "../util/account/bufferoffsetmanager";
2
+
3
+
4
+
5
+ const ITEM_SIZE = 10;
6
+ export default class BufferManager extends BufferOffsetManager {
7
+ constructor(globe, gl, buffer, { initialCapacity = 10, bufferType = "DYNAMIC_DRAW" } = {}) {
8
+ super(ITEM_SIZE, { capacity: initialCapacity });
9
+ this.globe = globe;
10
+ this.gl = gl;
11
+ this.buffer = buffer;
12
+ this.bufferType = bufferType;
13
+
14
+
15
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
16
+ gl.bufferData(gl.ARRAY_BUFFER, initialCapacity * ITEM_SIZE * 4, gl[bufferType]);
17
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
18
+ }
19
+
20
+ /**
21
+ *
22
+ * @param { Array<{key, long, lat, startAngle, tailAngle, radius, rgba[4], rgbaMode }>} rings
23
+ * @returns
24
+ */
25
+ insertBulk(items) {
26
+ if (items.length === 0) return;
27
+ this.autoExtendBuffer(items.length);
28
+ const { gl, buffer } = this;
29
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
30
+ for (let { key, long, lat, startAngle, tailAngle, rgba, radius, rgbaMode } of items) {
31
+ const offset = this.getOffset(key) | this.nextOffset();
32
+ this.setOffset(key, offset);
33
+ const block = new Float32Array([
34
+ long, lat, startAngle, tailAngle, ...rgba, radius, rgbaMode]);
35
+ gl.bufferSubData(gl.ARRAY_BUFFER, offset, block);
36
+ // 2 1 1 1 4 1 = 10
37
+ }
38
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
39
+ this.globe.DrawRender();
40
+ }
41
+
42
+
43
+ /**
44
+ * @param {Array<{key, long, lat, startAngle, tailAngle}>} items
45
+ *
46
+ * */
47
+ updateCenterAndAngleBulk(items) {
48
+ const { gl, buffer } = this;
49
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
50
+ for (let { key, long, lat, startAngle, tailAngle } of items) {
51
+ const offset = this.getOffset(key);
52
+ if (offset === null) {
53
+ console.warn(`key ${key} not found`);
54
+ continue;
55
+ }
56
+ const block = new Float32Array([long, lat, startAngle, tailAngle]);
57
+ gl.bufferSubData(gl.ARRAY_BUFFER, offset, block);
58
+ }
59
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
60
+ this.globe.DrawRender();
61
+ }
62
+ /**
63
+ *
64
+ * @param {Array<{key:string, payload:Float32Array}} items
65
+ * @param {PART_OFFSET_LOOPUP} part | long, lat, START_ANGLE, ROTATION_ANGLE, RADIUS, rgba, rgba_MODE
66
+ * @returns
67
+ */
68
+ updatePartial(items, part) {
69
+ const { gl, buffer } = this;
70
+ this._updatePartial(items, part, gl, buffer);
71
+ this.globe.DrawRender();
72
+
73
+ }
74
+
75
+
76
+
77
+ deleteBulk(keys) {
78
+ this._deleteBulk(keys);
79
+ this.globe.DrawRender();
80
+ }
81
+
82
+
83
+
84
+
85
+ free() {
86
+ this.gl.deleteBuffer(this.buffer);
87
+ this.buffer = null;
88
+ }
89
+ }
@@ -1,3 +1,3 @@
1
1
  import PartialRing, { RINGPARTIAL_ALPHA_MODE, RINGPARTIAL_DRAW_MODE, PART_OFFSET_LOOPUP } from './plugin';
2
2
 
3
- export { PartialRing, RINGPARTIAL_ALPHA_MODE, RINGPARTIAL_DRAW_MODE, PART_OFFSET_LOOPUP };
3
+ export { PartialRing, RINGPARTIAL_ALPHA_MODE, RINGPARTIAL_DRAW_MODE, PART_OFFSET_LOOPUP };
@@ -20,12 +20,13 @@ export const RINGPARTIAL_ALPHA_MODE = Object.freeze({
20
20
 
21
21
 
22
22
  export const PART_OFFSET_LOOPUP = Object.freeze({
23
- CENTER: 0,
23
+ LONG: 0,
24
+ LAT: 1,
24
25
  START_ANGLE: 2,
25
26
  TAIL_ANGLE: 3,
26
- COLOR: 4,
27
+ RGBA: 4,
27
28
  RADIUS: 8,
28
- COLOR_MODE: 9,
29
+ RGBA_MODE: 9,
29
30
  });
30
31
 
31
32
 
@@ -47,8 +48,6 @@ export default class {
47
48
  const { vao, buffer } = this.program.getVaoBuffer();
48
49
  this.vao = vao;
49
50
  this.buffer = buffer;
50
-
51
-
52
51
  }
53
52
 
54
53
 
@@ -57,7 +56,7 @@ export default class {
57
56
 
58
57
  if (LOD < this.startLod || LOD > this.endLod) return;
59
58
  this.program.draw(
60
- this.bufferManager,
59
+ this.bufferManager.length,
61
60
  this.vao,
62
61
  this.edgeCount,
63
62
  this.alphaMultiplier,
@@ -82,8 +81,8 @@ export default class {
82
81
  if (endLod !== null) this.endLod = endLod;
83
82
  }
84
83
 
85
- createBufferMAnager(initialCapacity = 10, extendRatio = 1.2, bufferType = 'DYNAMIC_DRAW') {
86
- if (!this.bufferManager) { this.bufferManager = new BufferManager(this.globe, this.gl, this.buffer, bufferType, { initialCapacity, extendRatio }); }
84
+ createBufferMAnager(initialCapacity = 10, bufferType = 'DYNAMIC_DRAW') {
85
+ if (!this.bufferManager) { this.bufferManager = new BufferManager(this.globe, this.gl, this.buffer, { initialCapacity, bufferType, }); }
87
86
  return this.bufferManager;
88
87
  }
89
88
 
@@ -96,13 +95,12 @@ export default class {
96
95
 
97
96
  class BufferManager extends BufferOffsetManager {
98
97
 
99
- constructor(globe, gl, buffer, bufferType, { initialCapacity = 10, extendRatio = 1.2 } = {}) {
100
- super(10, { capacity: initialCapacity });
98
+ constructor(globe, gl, buffer, { initialCapacity = 10, bufferType, } = {}) {
99
+ super(10, { capacity: initialCapacity, bufferType, });
101
100
  this.globe = globe;
102
101
  this.gl = gl;
103
102
  this.buffer = buffer;
104
103
  this.bufferType = bufferType;
105
- this.extendRatio = extendRatio;
106
104
 
107
105
 
108
106
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
@@ -112,22 +110,20 @@ class BufferManager extends BufferOffsetManager {
112
110
 
113
111
  /**
114
112
  *
115
- * @param { Array<{key, center[2], startAngle, tailAngle, radius, color[4], color_mode }>} rings
113
+ * @param { Array<{key, long, lat, startAngle, tailAngle, radius, rgba[4], rgbaMode }>} rings
116
114
  * @returns
117
115
  */
118
- insertRings(rings) {
119
- if (rings.length === 0) return;
120
- this._autoExtendBuffer(rings.length);
116
+ insertBulk(items) {
117
+ if (items.length === 0) return;
118
+ console.log(items)
119
+ this.autoExtendBuffer(items.length);
121
120
  const { gl, buffer } = this;
122
121
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
123
- for (let { key, center, startAngle, tailAngle, color, radius, colorMode } of rings) {
124
- let offset = this.getOffset(key);
125
- if (offset === undefined) {
126
- offset = this.nextOffset();
127
- this.setOffset(key, offset);
128
- }
122
+ for (let { key, long, lat, startAngle, tailAngle, rgba, radius, rgbaMode } of items) {
123
+ const offset = this.getOffset(key) | this.nextOffset();
124
+ this.setOffset(key, offset);
129
125
  const block = new Float32Array([
130
- ...center, startAngle, tailAngle, ...color, radius, colorMode]);
126
+ long, lat, startAngle, tailAngle, ...rgba, radius, rgbaMode]);
131
127
  gl.bufferSubData(gl.ARRAY_BUFFER, offset, block);
132
128
  // 2 1 1 1 4 1 = 10
133
129
  }
@@ -138,13 +134,13 @@ class BufferManager extends BufferOffsetManager {
138
134
 
139
135
  /**
140
136
  *
141
- * @param {Array<{key:string, payload:Float32Array}} rings
142
- * @param {PART_OFFSET_LOOPUP} part | CENTER, START_ANGLE, ROTATION_ANGLE, RADIUS, COLOR, COLOR_MODE
137
+ * @param {Array<{key:string, payload:Float32Array}} items
138
+ * @param {PART_OFFSET_LOOPUP} part | long, lat, START_ANGLE, ROTATION_ANGLE, RADIUS, rgba, rgba_MODE
143
139
  * @returns
144
140
  */
145
- updatePartial(rings, part) {
141
+ updatePartial(items, part) {
146
142
  const { gl, buffer } = this;
147
- this._updatePartial(rings, part, gl, buffer);
143
+ this._updatePartial(items, part, gl, buffer);
148
144
  this.globe.DrawRender();
149
145
 
150
146
  }
@@ -156,13 +152,6 @@ class BufferManager extends BufferOffsetManager {
156
152
  this.globe.DrawRender();
157
153
  }
158
154
 
159
- _autoExtendBuffer(payloadSize) {
160
- const { gl, buffer, bufferType, extendRatio } = this;
161
- if (payloadSize <= this.spaceLeft) return;
162
- const newCapacity = Math.ceil((payloadSize + this.length) * extendRatio);
163
- this.extendBuffer(gl, buffer, bufferType, newCapacity);
164
- }
165
-
166
155
 
167
156
  free() {
168
157
  this.gl.deleteBuffer(this.buffer);
@@ -1,6 +1,6 @@
1
1
  import { createProgram, shaderfunctions } from "../util";
2
2
  import { CameraUniformBlockTotem, CameraUniformBlockString, noRegisterGlobeProgramCache, globeProgramCache } from "../programs";
3
-
3
+ import BufferManager from "./buffer-manager";
4
4
  import {
5
5
  POLE,
6
6
  PI,
@@ -8,7 +8,7 @@ import {
8
8
  mercatorXYTo2DPoint,
9
9
  longLatRadToCartesian3D,
10
10
  circleLimpFromLongLatRadCenterCartesian3D,
11
- circleLimpFromLongLatRadCenterMercatorCompass,
11
+ circleLimpFromLongLatRadCenterMercatorRealDistance,
12
12
  cartesian3DToGLPosition
13
13
 
14
14
 
@@ -35,13 +35,13 @@ const vertexShaderSource = `#version 300 es` +
35
35
  mercatorXYTo2DPoint +
36
36
  longLatRadToCartesian3D +
37
37
  circleLimpFromLongLatRadCenterCartesian3D +
38
- circleLimpFromLongLatRadCenterMercatorCompass +
38
+ circleLimpFromLongLatRadCenterMercatorRealDistance +
39
39
  cartesian3DToGLPosition + `
40
40
 
41
41
  uniform float edge_count;
42
42
  uniform int draw_mode; // %2 => 0: LINE_STRIP, 1: TRIANGLE_FAN
43
43
  uniform float plugin_alpha_multiplier;
44
-
44
+ //, lat, startAngle, tailAngle, ...rgba, radius, rgbaMode
45
45
  in vec2 center; // long, lat in radian
46
46
  in float start_angle; // the start of partial circle from bearing point
47
47
  in float tail_angle; // the rotation of the partial circle
@@ -56,20 +56,17 @@ out vec4 v_color;
56
56
  void main() {
57
57
  if (color_mode == 2.0 || radius == 0.0) { return; }
58
58
 
59
- float vertexID;
59
+ float vertexID = float(gl_VertexID);
60
60
  float radius_ = radius;
61
61
  float alpha = plugin_alpha_multiplier;
62
62
  if (draw_mode == 1) { // TRIANGLE_FAN
63
- vertexID = float(gl_VertexID - 1);
64
63
  if (gl_VertexID == 0) {
65
- radius_ = 0.0; vertexID = 0.0;
64
+ radius_ = 0.0;
66
65
  if ( color_mode == 1.0 ) { alpha = 0.0; }
67
66
  }
68
- } else { // LINE_STRIP
69
- vertexID = float(gl_VertexID);
67
+ vertexID -= 1.0;
70
68
  }
71
-
72
- float phase = ( vertexID / edge_count);
69
+ float phase = ( vertexID / edge_count);
73
70
 
74
71
  if ( color_mode == 1.0 ) {
75
72
  if ( tail_angle < 0.0 ) {
@@ -83,7 +80,7 @@ void main() {
83
80
 
84
81
  float angle;
85
82
  if ( tail_angle > 0.0 ) {
86
- angle = tail_angle * (-phase + 1.0) + start_angle;
83
+ angle = tail_angle * (-phase + 1.0 - 1.0 / edge_count) + start_angle;
87
84
  } else {
88
85
  angle = tail_angle * phase + start_angle;
89
86
  }
@@ -94,13 +91,14 @@ void main() {
94
91
  gl_Position = cartesian3DToGLPosition(pos);
95
92
  }
96
93
  else {
97
- vec2 pos = circleLimpFromLongLatRadCenterMercatorCompass(center, radius_, angle);
94
+
95
+ vec2 pos = circleLimpFromLongLatRadCenterMercatorRealDistance(center, radius_, angle);
98
96
  v_pos = pos;
99
97
  gl_Position = mercatorXYTo2DPoint(pos);
100
98
  }
101
99
 
102
100
 
103
- gl_PointSize = 2.0;
101
+ gl_PointSize = 10.0;
104
102
  }`;
105
103
 
106
104
 
@@ -162,7 +160,7 @@ export class Logic {
162
160
 
163
161
 
164
162
 
165
- draw(bufferManager, vao, edgeCount, alphaMultiplier, drawMode) {
163
+ draw(length, vao, edgeCount, alphaMultiplier, drawMode) {
166
164
  const { gl, program, cameraBlockTotem, cameraBlockBindingPoint } = this
167
165
 
168
166
  gl.disable(gl.DEPTH_TEST);
@@ -182,7 +180,7 @@ export class Logic {
182
180
  const overdraw = drawModeMap[drawMode];
183
181
  cameraBlockTotem.bind(cameraBlockBindingPoint);
184
182
  gl.bindVertexArray(vao);
185
- gl.drawArraysInstanced(gl[drawMode], 0, edgeCount + overdraw, bufferManager.length);
183
+ gl.drawArraysInstanced(gl[drawMode], 0, edgeCount + overdraw, length);
186
184
  cameraBlockTotem.unbind(cameraBlockBindingPoint);
187
185
  gl.bindVertexArray(null);
188
186
  gl.enable(gl.DEPTH_TEST);
@@ -237,9 +235,17 @@ export class Logic {
237
235
  buffer,
238
236
  }
239
237
  }
238
+
239
+ getBufferManagerAndVao({ capacity = 10, bufferType = "DYNAMIC_DRAW" } = {}) {
240
+ const { vao, buffer } = this.getVaoBuffer();
241
+ return {
242
+ bufferManager: new BufferManager(this.globe, this.gl, buffer, { capacity, bufferType }),
243
+ vao
244
+ };
245
+ }
240
246
  }
241
247
 
242
248
  export const programCache = Object.freeze({
243
249
  get: (globe) => noRegisterGlobeProgramCache.getProgram(globe, Logic),
244
- free: (globe) => noRegisterGlobeProgramCache.releaseProgram(globe, Logic)
250
+ release: (globe) => noRegisterGlobeProgramCache.releaseProgram(globe, Logic)
245
251
  });
@@ -0,0 +1 @@
1
+ import { LineOnGlobeCache } from './program.js';
@@ -0,0 +1,267 @@
1
+ import { CameraUniformBlockString, CameraUniformBlockTotem } from "../totems";
2
+ import { longLatRadToMercator, longLatRadToCartesian3D, cartesian3DToGLPosition, mercatorXYTo2DPoint } from "../../util/shaderfunctions/geometrytransformations";
3
+ import { createProgram } from "../../util";
4
+ import { noRegisterGlobeProgramCache, globeProgramCache } from "../programcache";
5
+ import BufferOffsetManger from "../../util/account/bufferoffsetmanager";
6
+ const Radian = Math.PI / 180.0;
7
+ const GLOBE_MIDPOINT_COUNT = 100;
8
+ const ITEM_SIZE = 8;
9
+
10
+ const vertexShader = `#version 300 es
11
+ precision highp float;
12
+ ${CameraUniformBlockString}
13
+ ${longLatRadToMercator}
14
+ ${longLatRadToCartesian3D}
15
+ ${cartesian3DToGLPosition}
16
+ ${mercatorXYTo2DPoint}
17
+
18
+ in vec2 start_position;
19
+ in vec2 end_position;
20
+ in vec4 color;
21
+ out vec4 v_color;
22
+
23
+ void main() {
24
+
25
+ vec2 longLat;
26
+ if (is3D) {
27
+ float interpolation = float(gl_VertexID) / ${GLOBE_MIDPOINT_COUNT}.0;
28
+ longLat = mix(start_position, end_position, interpolation);
29
+ vec3 cartesian = longLatRadToCartesian3D(longLat);
30
+ gl_Position = cartesian3DToGLPosition(cartesian);
31
+ } else {
32
+ if ( gl_VertexID == 0 ) {
33
+ longLat = start_position;
34
+ } else {
35
+ longLat = end_position;
36
+ }
37
+ vec2 mercator = longLatRadToMercator(longLat);
38
+ gl_Position = mercatorXYTo2DPoint(mercator);
39
+ }
40
+ v_color = color;
41
+ }
42
+ `
43
+
44
+ const fragmentShader = `#version 300 es
45
+ precision highp float;
46
+ uniform float opacity;
47
+ in vec4 v_color;
48
+ out vec4 color;
49
+ void main() {
50
+ color = v_color;
51
+ color.a *= opacity;
52
+ }
53
+ `
54
+
55
+
56
+ class Logic {
57
+
58
+ constructor(globe) {
59
+ this.globe = globe;
60
+ this.gl = globe.gl;
61
+ this.program = createProgram(this.gl, vertexShader, fragmentShader);
62
+ this._lastOpacity = 1.0;
63
+ const { gl, program } = this;
64
+ {
65
+ // assign attribute locations
66
+ gl.bindAttribLocation(program, 0, "start_position");
67
+ gl.bindAttribLocation(program, 1, "end_position");
68
+ gl.bindAttribLocation(program, 2, "color");
69
+ }
70
+
71
+ {
72
+ this._opacityLocation = gl.getUniformLocation(program, "opacity");
73
+ const currentProgram = gl.getParameter(gl.CURRENT_PROGRAM);
74
+ gl.useProgram(program);
75
+ gl.uniform1f(this._opacityLocation, this._lastOpacity);
76
+ gl.useProgram(currentProgram);
77
+
78
+ }
79
+
80
+ this.cameraBlockBindingPoint = 0;
81
+ const cameraBlockIndex = this.gl.getUniformBlockIndex(this.program, "CameraUniformBlock");
82
+ this.cameraBlockTotem = globeProgramCache.getProgram(globe, CameraUniformBlockTotem);
83
+ gl.uniformBlockBinding(this.program, cameraBlockIndex, this.cameraBlockBindingPoint);
84
+
85
+
86
+ }
87
+
88
+
89
+ draw(vao, length, opacity) {
90
+ const { gl, program, globe } = this;
91
+ gl.useProgram(program);
92
+ const { cameraBlockTotem, cameraBlockBindingPoint } = this;
93
+ cameraBlockTotem.bind(cameraBlockBindingPoint);
94
+ gl.bindVertexArray(vao);
95
+ if (opacity !== this._lastOpacity) {
96
+ gl.uniform1f(this._opacityLocation, opacity);
97
+ this._lastOpacity = opacity;
98
+ }
99
+ const drawCount = globe.api_GetCurrentGeometry() === 0 ? GLOBE_MIDPOINT_COUNT : 2;
100
+ gl.disable(gl.DEPTH_TEST);
101
+ gl.drawArraysInstanced(gl.LINE_STRIP, 0, drawCount, length);
102
+ gl.bindVertexArray(null);
103
+ cameraBlockTotem.unbind(cameraBlockBindingPoint);
104
+ gl.enable(gl.DEPTH_TEST);
105
+ }
106
+
107
+
108
+ createBufferManager({ capacity = 10, bufferType = "DYNAMIC_DRAW" } = {}) {
109
+ return new BufferManager(this.globe, { capacity, bufferType });
110
+ }
111
+ }
112
+
113
+
114
+ class BufferManager extends BufferOffsetManger {
115
+
116
+ constructor(globe, { capacity = 10, bufferType = "DYNAMIC_DRAW" } = {}) {
117
+ super(ITEM_SIZE, { capacity, bufferType });
118
+ this.globe = globe
119
+ this.gl = globe.gl;
120
+ this.buffer = this.gl.createBuffer();
121
+
122
+ const { gl, buffer } = this;
123
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
124
+ gl.bufferData(gl.ARRAY_BUFFER, capacity * ITEM_SIZE * 4, gl[bufferType]);
125
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
126
+
127
+ this.vao = gl.createVertexArray();
128
+ {
129
+ gl.bindVertexArray(this.vao);
130
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
131
+ gl.enableVertexAttribArray(0);
132
+ gl.vertexAttribPointer(0, 2, gl.FLOAT, false, ITEM_SIZE * 4, 0);
133
+ gl.enableVertexAttribArray(1);
134
+ gl.vertexAttribPointer(1, 2, gl.FLOAT, false, ITEM_SIZE * 4, 8);
135
+ gl.enableVertexAttribArray(2);
136
+ gl.vertexAttribPointer(2, 4, gl.FLOAT, false, ITEM_SIZE * 4, 16);
137
+ gl.vertexAttribDivisor(0, 1);
138
+ gl.vertexAttribDivisor(1, 1);
139
+ gl.vertexAttribDivisor(2, 1);
140
+ gl.bindVertexArray(null);
141
+ }
142
+ }
143
+
144
+
145
+ /**
146
+ *
147
+ * @param {Array<{key:string, long:number, lat:number, endLong:number, endLat:number, rgba:[4numbers] }} items
148
+ */
149
+ insertBulk(items) {
150
+ this.autoExtendBuffer(items.length)
151
+ const { gl, buffer, globe } = this;
152
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
153
+ for (let { key, long, lat, endLong, endLat, rgba } of items) {
154
+
155
+ const payload = new Float32Array([
156
+ long,
157
+ lat,
158
+ endLong,
159
+ endLat,
160
+ ...rgba]);
161
+ const offset = this.getOffset(key) | this.nextOffset();
162
+ gl.bufferSubData(gl.ARRAY_BUFFER, offset, payload);
163
+ this.setOffset(key, offset);
164
+ }
165
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
166
+ globe.DrawRender();
167
+ }
168
+
169
+ /**
170
+ *
171
+ * @param {Array<{key:string, long:number, lat:number, endLong:number, endLat:number, rgba:[4numbers] }} items
172
+ */
173
+ updateBulk(items) {
174
+ const { gl, buffer, globe } = this;
175
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
176
+ for (let { key, long, lat, endLong, endLat, rgba } of items) {
177
+ const payload = new Float32Array([
178
+ long,
179
+ lat,
180
+ endLong,
181
+ endLat,
182
+ ...rgba]);
183
+ const offset = this.getOffset(key);
184
+ if (offset !== undefined) {
185
+ gl.bufferSubData(gl.ARRAY_BUFFER, offset, payload);
186
+ } else {
187
+ console.warn("key not found", key);
188
+ }
189
+ }
190
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
191
+ globe.DrawRender();
192
+ }
193
+
194
+ /**
195
+ *
196
+ * @param {Array<{key:string, long:number, lat:number, endLong:number, endLat:number }} items
197
+ */
198
+ updateCoordinatesBulk(items) {
199
+ const { gl, buffer, globe } = this;
200
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
201
+ for (let { key, long, lat, endLong, endLat } of items) {
202
+ const payload = new Float32Array([
203
+ long,
204
+ lat,
205
+ endLong,
206
+ endLat]);
207
+ const offset = this.getOffset(key);
208
+ if (offset !== undefined) {
209
+ gl.bufferSubData(gl.ARRAY_BUFFER, offset, payload);
210
+ } else {
211
+ console.warn("key not found", key);
212
+ }
213
+ }
214
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
215
+ globe.DrawRender();
216
+ }
217
+
218
+
219
+ /**
220
+ *
221
+ * @param {Array<{key:string, rgba:[4numbers] }} items
222
+ */
223
+ updateColorBulk(items) {
224
+ const { gl, buffer, globe } = this;
225
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
226
+ for (let { key, rgba } of items) {
227
+ const payload = new Float32Array([...rgba]);
228
+ const offset = this.getOffset(key);
229
+ if (offset !== undefined) {
230
+ gl.bufferSubData(gl.ARRAY_BUFFER, offset + 16, payload);
231
+ } else {
232
+ console.warn("key not found", key);
233
+ }
234
+ }
235
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
236
+ globe.DrawRender();
237
+ }
238
+
239
+
240
+ /**
241
+ *
242
+ * @param {Array<string>} keys
243
+ */
244
+ deleteBulk(keys) {
245
+ const { gl, buffer, globe } = this;
246
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
247
+ const emptyBlock = new Float32Array(ITEM_SIZE).fill(0);
248
+ for (let key of keys) {
249
+ const offset = this.getOffset(key);
250
+ if (offset !== undefined) {
251
+ this.deleteFromAccount(key);
252
+ gl.bufferSubData(gl.ARRAY_BUFFER, offset, emptyBlock);
253
+ } else {
254
+ console.warn("key not found", key);
255
+ }
256
+ }
257
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
258
+ globe.DrawRender();
259
+ }
260
+ }
261
+
262
+
263
+ export const LineOnGlobeCache = Object.freeze({
264
+ get: (globe) => { return noRegisterGlobeProgramCache.getProgram(globe, Logic) },
265
+ free: (globe) => { return noRegisterGlobeProgramCache.releaseProgram(globe, Logic) }
266
+ });
267
+
@@ -128,8 +128,8 @@ class Logic {
128
128
  }
129
129
  gl.disable(gl.DEPTH_TEST);
130
130
  gl.drawArraysInstanced(gl.LINES, 0, 2, attrBufferManager.length);
131
- gl.enable(gl.DEPTH_TEST);
132
131
  cameraBlockTotem.unbind(cameraBlockBindingPoint);
132
+ gl.enable(gl.DEPTH_TEST);
133
133
  gl.bindVertexArray(null);
134
134
 
135
135
  }
@@ -31,6 +31,9 @@ export default class {
31
31
  this.circleEdgeCount = 360;
32
32
  this._onedegreepaddingOn = oneDegreePadding;
33
33
  this.bufferManager = null;
34
+
35
+ this._deleteCounter = 0;
36
+ this._deleteThreshold = 10;
34
37
  }
35
38
 
36
39
 
@@ -56,6 +59,9 @@ export default class {
56
59
  this.circleProgramCache?.releaseProgram(this.globe);
57
60
  this.PaddingProgramCache?.releaseProgram(this.globe);
58
61
  this.PaddingFreeAngleCache?.releaseProgram(this.globe);
62
+ this.gl.deleteVertexArray(this.bufferManager?.vao);
63
+ this.gl.deleteVertexArray(this.paddingBufferManager?.vao);
64
+ this.paddingBufferManager?.free();
59
65
  this.bufferManager?.free();
60
66
  this.textPlugin?.free();
61
67
  this.circleFlatProgram = null;
@@ -157,8 +163,14 @@ export default class {
157
163
  this.bufferManager.removeCenters(centerIds);
158
164
  this.paddingBufferManager.removeCenters(centerIds);
159
165
  this.textPlugin?.removeCenters(centerIds);
160
- // this.bufferManager.defrag();
161
- // this.paddingBufferManager.defrag();
166
+ this._deleteCounter += centerIds.length;
167
+ if (this._deleteCounter > this._deleteThreshold) {
168
+ // this is naive since we are not checking the actual deletion
169
+ // but it works
170
+ this._deleteCounter = 0;
171
+ this.bufferManager.defrag();
172
+ this.paddingBufferManager.defrag();
173
+ }
162
174
  this.globe.DrawRender();
163
175
 
164
176
  }
@@ -75,6 +75,19 @@ export default class {
75
75
  }
76
76
  }
77
77
 
78
+ _deleteBulk(keys) {
79
+ const { gl, buffer } = this;
80
+ const emptyBlock = new Float32Array(this.itemSize).fill(0)
81
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
82
+ for (let key of keys) {
83
+ const offset = this.getOffset(key);
84
+ if (offset !== undefined) {
85
+ this.deleteFromAccount(key);
86
+ gl.bufferSubData(gl.ARRAY_BUFFER, offset, emptyBlock);
87
+ }
88
+ }
89
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
90
+ }
78
91
 
79
92
 
80
93
  offsetMapIterator() { // can be used for defraging the real buffer.
@@ -91,7 +104,6 @@ export default class {
91
104
  const itemCount = this.itemCount;
92
105
  const capacity = (newCapacity && newCapacity > itemCount) ? newCapacity : itemCount;
93
106
 
94
-
95
107
  const newArray = new Float32Array(itemCount * itemSize);
96
108
 
97
109
  const bufferData = this._getBufferData();
@@ -112,9 +124,16 @@ export default class {
112
124
 
113
125
  this._capacity = capacity;
114
126
  this.tombstoneOffSet = [];
127
+ this._length = itemCount;
115
128
  this.offSetMap = newOffSetMap;
116
129
  }
117
130
 
131
+ autoExtendBuffer(payloadSize) {
132
+ if (payloadSize <= this.spaceLeft) return;
133
+ const newCapacity = Math.ceil((payloadSize + this.length));
134
+ this.extendBuffer(newCapacity);
135
+ }
136
+
118
137
 
119
138
  extendBuffer(newCapacity) {
120
139
  const { gl, buffer, bufferType } = this;
@@ -139,8 +158,8 @@ export default class {
139
158
  */
140
159
  _updatePartial(items, partOffset) {
141
160
  const { gl, buffer } = this;
142
- gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
143
161
  const partStart = partOffset * 4;
162
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
144
163
  for (let { key, payload } of items) {
145
164
  let offset = this.getOffset(key);
146
165
  if (offset !== undefined) {
@@ -161,7 +180,6 @@ export default class {
161
180
  }
162
181
 
163
182
 
164
-
165
183
  _removeFromBuffer(keys) {
166
184
  const { gl, buffer } = this;
167
185
  const emptyBlock = new Float32Array(this.itemSize).fill(0)
@@ -175,6 +193,16 @@ export default class {
175
193
  }
176
194
  gl.bindBuffer(gl.ARRAY_BUFFER, null);
177
195
  }
196
+
197
+
198
+
199
+
200
+ free() {
201
+ this.gl.deleteBuffer(this.buffer);
202
+ this.buffer = null;
203
+ this.vao = null;
204
+ this.gl = null;
205
+ }
178
206
  }
179
207
 
180
208
 
@@ -159,3 +159,93 @@ vec2 circleLimpFromLongLatRadCenterMercatorCompass(vec2 center, float radius, fl
159
159
  }`;
160
160
 
161
161
 
162
+ // Function to interpolate between two Cartesian points using spherical interpolation (slerp)
163
+ export const slerp = `
164
+ vec3 slerp(vec3 A, vec3 B, float t) {
165
+ float cosTheta = dot(A, B);
166
+ float theta = acos(clamp(cosTheta, -1.0, 1.0)); // Angle between the points
167
+
168
+ float sinTheta = sin(theta);
169
+
170
+ // Avoid division by zero // many points falls in to this category
171
+ if (sinTheta < 0.00001) {
172
+ return mix(A, B, t); // Linear interpolation as fallback
173
+ }
174
+
175
+ float factorA = sin((1.0 - t) * theta) / sinTheta;
176
+ float factorB = sin(t * theta) / sinTheta;
177
+
178
+ return factorA * A + factorB * B;
179
+ }
180
+ `;
181
+
182
+ // Function to convert Cartesian coordinates back to spherical (latitude, longitude)
183
+ export const cartesianToSpherical = `
184
+ vec2 cartesianToSpherical(vec3 point) {
185
+ float lat = degrees(asin(point.z)); // Latitude
186
+ float lon = degrees(atan(point.y, point.x)); // Longitude
187
+
188
+ return vec2(lat, lon);
189
+ }`;
190
+
191
+ // Main function to calculate an intermediate point
192
+
193
+ export const interpolateGeographicPoint = slerp + cartesianToSpherical + longLatRadToCartesian3D + `
194
+ vec3 interpolateGeographicPoint(vec2 start, vec2 end, float t) {
195
+ vec3 pointA = longLatRadToCartesian3D(start);
196
+ vec3 pointB = longLatRadToCartesian3D(end);
197
+ vec3 interpolatedPoint = slerp(pointA, pointB, t);
198
+ return interpolatedPoint;
199
+ // return cartesianToSpherical(interpolatedPoint);
200
+ }
201
+ `;
202
+
203
+
204
+
205
+ export const angleBetweenTwoPointsRadian = `
206
+ float angleBetweenTwoPointsRadian(vec2 start_, vec2 end_) {
207
+ float start_lat = log( tan( ( 1.0 - start_.y ) * PI / 2.0 ) );
208
+ float end_lat = log( tan( ( 1.0 - end_.y ) * PI / 2.0 ) );
209
+ float angle = atan( (end_lat - start_lat )/ (end_.x - start_.x));
210
+ return angle;
211
+ }
212
+ `
213
+
214
+ export const circleCircumferenceInterPolationOf2PointsRadian = `
215
+ float circleCircumferenceInterPolationOf2PointsRadian(vec2 center, vec2 target, float bearing_angle, float ratio) {
216
+ vec2 t = target - center;
217
+ float mainAngle = atan(t.x, t.y);
218
+ float angle = mainAngle - * ratio;
219
+ return angle;
220
+ }
221
+ `
222
+
223
+ export const circumferencePoints = `
224
+ vec2 circumferencePoints(vec2 center, vec2 target, vec2 target2, float phase, float radius) {
225
+ // Calculate vectors from center to target and target2
226
+ vec2 v1 = target - center;
227
+ vec2 v2 = target2 - center;
228
+
229
+ // Normalize the vectors to ensure they are on the unit circle
230
+ v1 = normalize(v1);
231
+ v2 = normalize(v2);
232
+
233
+ // Calculate the angle between the vectors
234
+ float angle1 = atan(v1.y, v1.x);
235
+ float angle2 = atan(v2.y, v2.x);
236
+
237
+ // Ensure the angles are continuous (handle wrap-around at 2π)
238
+ if (angle2 < angle1) {
239
+ angle2 += 2.0 * 3.14159265359; // Add 2π to angle2 if it is smaller
240
+ }
241
+
242
+ // Interpolate the angle based on the phase
243
+ float interpolatedAngle = mix(angle1, angle2, phase);
244
+
245
+ // Calculate the new point on the circle
246
+ vec2 result = vec2(cos(interpolatedAngle), sin(interpolatedAngle));
247
+
248
+ // Scale back to the original circle radius and shift to center
249
+ return center + radius * result;
250
+ }
251
+ `
package/wind/plugin.js CHANGED
@@ -696,9 +696,12 @@ export default class WindPlugin {
696
696
 
697
697
  gl.activeTexture(gl.TEXTURE0);
698
698
  if (this._doDraw()) {
699
- gl.disable(gl.DEPTH_TEST);
700
- gl.disable(gl.STENCIL_TEST);
699
+ const depthTest = gl.isEnabled(gl.DEPTH_TEST);
700
+ if (depthTest) gl.disable(gl.DEPTH_TEST);
701
+ // if (gl.disable(gl.STENCIL_TEST); //
701
702
  this._draw();
703
+ // if (depthTest) gl.enable(gl.DEPTH_TEST); // TODO: stencil
704
+
702
705
  }
703
706
 
704
707
  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
@@ -862,8 +865,8 @@ export default class WindPlugin {
862
865
 
863
866
  _resetMachineStates() {
864
867
  const { gl, globe } = this;
865
- gl.disable(gl.DEPTH_TEST);
866
- gl.disable(gl.STENCIL_TEST);
868
+ // gl.disable(gl.DEPTH_TEST);
869
+ // gl.disable(gl.STENCIL_TEST);
867
870
  gl.activeTexture(gl.TEXTURE0);
868
871
  gl.viewport(0, 0, globe.api_ScrW(), globe.api_ScrH());
869
872
  }
@@ -1,115 +0,0 @@
1
- import { CameraUniformBlockString, CameraUniformBlockTotem } from "../totems";
2
- import { longLatRadToMercator, longLatRadToCartesian3D, cartesian3DToGLPosition, mercatorXYTo2DPoint } from "../shaderfunctions/geometrytransformations";
3
- import { createProgram } from "../webgl/program";
4
- import { noRegisterGlobeProgramCache, globeProgramCache } from "../programcache";
5
- import { BufferOffsetManger } from "../../util/account";
6
-
7
- const GLOBE_MIDPOINT_COUNT = 100;
8
- const ITEM_SIZE = 8;
9
-
10
- const vertexShader = `#version 300 es
11
- precision highp float;
12
- ${CameraUniformBlockString}
13
- ${longLatRadToMercator}
14
- ${longLatRadToCartesian3D}
15
- ${cartesian3DToGLPosition}
16
- ${mercatorXYTo2DPoint}
17
-
18
- in vec2 start_position;
19
- in vec2 end_position;
20
- in vec4 color;
21
- out vec4 v_color;
22
-
23
- void main() {
24
-
25
- vec2 longLat;
26
- if (is3D) {
27
- float interpolation = float(gl_VertexID) / ${GLOBE_MIDPOINT_COUNT}.0;
28
- longLat = mix(start_position, end_position, interpolation)
29
- vec3 cartesian = longLatRadToMercator(longLat);
30
- gl_Position = cartesian3DToGLPosition(cartesian);
31
- } else {
32
- if ( gl_VertexID == 0 ) {
33
- longLat = start_position;
34
- } else {
35
- longLat = end_position;
36
- }
37
- vec2 mercator = longLatRadToMercator(longLat);
38
- gl_Position = mercatorXYTo2DPoint(mercator);
39
- }
40
- v_color = color;
41
- }
42
- `
43
-
44
- const fragmentShader = `#version 300 es
45
- precision highp float;
46
- in vec4 v_color;
47
- out vec4 color;
48
- void main() {
49
- color = v_color;
50
- }
51
- `
52
-
53
-
54
- class Logic {
55
-
56
- constructor(globe) {
57
- this.globe = globe;
58
- this.gl = gl;
59
- this.program = createProgram(gl, vertexShader, fragmentShader);
60
- const { gl, program } = this;
61
- {
62
- // assign attribute locations
63
- gl.bindAttribLocation(program, 0, "start_position");
64
- gl.bindAttribLocation(program, 1, "end_position");
65
- gl.bindAttribLocation(program, 2, "color");
66
-
67
- }
68
-
69
-
70
- this.cameraBlockBindingPoint = 0;
71
- const cameraBlockIndex = this.gl.getUniformBlockIndex(this.program, "CameraUniformBlock");
72
- this.cameraBlockTotem = globeProgramCache.getProgram(globe, CameraUniformBlockTotem);
73
-
74
- }
75
-
76
-
77
- draw(bufferManager) {
78
-
79
- }
80
-
81
-
82
-
83
- }
84
-
85
-
86
- class BufferManager extends BufferOffsetManger {
87
-
88
- constructor(gl, { capacity = 10, bufferType = "DYNAMIC_DRAW" } = {}) {
89
- super(ITEM_SIZE, { capacity, bufferType });
90
- this.gl = gl;
91
- this.buffer = gl.createBuffer();
92
-
93
- const { gl, buffer } = this;
94
- gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
95
- gl.bufferData(gl.ARRAY_BUFFER, _capacity * ITEM_SIZE * 4, gl[bufferType]);
96
- gl.bindBuffer(gl.ARRAY_BUFFER, null);
97
-
98
- this.vao = gl.createVertexArray();
99
- {
100
-
101
- }
102
- }
103
-
104
- insertBulk(items) {
105
-
106
- }
107
- }
108
-
109
-
110
-
111
- export const programCache = Object.freeze({
112
- get: (globe) => { return noRegisterGlobeProgramCache.getProgram(globe, Logic) },
113
- release: (globe) => { noRegisterGlobeProgramCache.releaseProgram(globe, Logic) }
114
- });
115
-