@loaders.gl/terrain 3.1.0-alpha.3 → 3.1.0-beta.2

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.
Files changed (111) hide show
  1. package/dist/bundle.d.ts +2 -0
  2. package/dist/bundle.d.ts.map +1 -0
  3. package/dist/bundle.js +1180 -4
  4. package/dist/es5/bundle.js +7 -0
  5. package/dist/es5/bundle.js.map +1 -0
  6. package/dist/es5/index.js +43 -0
  7. package/dist/es5/index.js.map +1 -0
  8. package/dist/es5/lib/decode-quantized-mesh.js +277 -0
  9. package/dist/es5/lib/decode-quantized-mesh.js.map +1 -0
  10. package/dist/es5/lib/delatin/index.js +473 -0
  11. package/dist/es5/lib/delatin/index.js.map +1 -0
  12. package/dist/es5/lib/helpers/skirt.js +107 -0
  13. package/dist/es5/lib/helpers/skirt.js.map +1 -0
  14. package/dist/es5/lib/parse-quantized-mesh.js +109 -0
  15. package/dist/es5/lib/parse-quantized-mesh.js.map +1 -0
  16. package/dist/es5/lib/parse-terrain.js +192 -0
  17. package/dist/es5/lib/parse-terrain.js.map +1 -0
  18. package/dist/es5/lib/utils/version.js +9 -0
  19. package/dist/es5/lib/utils/version.js.map +1 -0
  20. package/dist/es5/quantized-mesh-loader.js +28 -0
  21. package/dist/es5/quantized-mesh-loader.js.map +1 -0
  22. package/dist/es5/terrain-loader.js +36 -0
  23. package/dist/es5/terrain-loader.js.map +1 -0
  24. package/dist/es5/workers/quantized-mesh-worker.js +8 -0
  25. package/dist/es5/workers/quantized-mesh-worker.js.map +1 -0
  26. package/dist/es5/workers/terrain-worker.js +8 -0
  27. package/dist/es5/workers/terrain-worker.js.map +1 -0
  28. package/dist/esm/bundle.js +5 -0
  29. package/dist/esm/bundle.js.map +1 -0
  30. package/dist/esm/index.js +16 -0
  31. package/dist/esm/index.js.map +1 -0
  32. package/dist/esm/lib/decode-quantized-mesh.js +268 -0
  33. package/dist/esm/lib/decode-quantized-mesh.js.map +1 -0
  34. package/dist/esm/lib/delatin/index.js +464 -0
  35. package/dist/esm/lib/delatin/index.js.map +1 -0
  36. package/dist/esm/lib/helpers/skirt.js +99 -0
  37. package/dist/esm/lib/helpers/skirt.js.map +1 -0
  38. package/dist/esm/lib/parse-quantized-mesh.js +96 -0
  39. package/dist/esm/lib/parse-quantized-mesh.js.map +1 -0
  40. package/dist/esm/lib/parse-terrain.js +180 -0
  41. package/dist/esm/lib/parse-terrain.js.map +1 -0
  42. package/dist/esm/lib/utils/version.js +2 -0
  43. package/dist/esm/lib/utils/version.js.map +1 -0
  44. package/dist/esm/quantized-mesh-loader.js +18 -0
  45. package/dist/esm/quantized-mesh-loader.js.map +1 -0
  46. package/dist/esm/terrain-loader.js +26 -0
  47. package/dist/esm/terrain-loader.js.map +1 -0
  48. package/dist/esm/workers/quantized-mesh-worker.js +4 -0
  49. package/dist/esm/workers/quantized-mesh-worker.js.map +1 -0
  50. package/dist/esm/workers/terrain-worker.js +4 -0
  51. package/dist/esm/workers/terrain-worker.js.map +1 -0
  52. package/dist/index.d.ts +77 -0
  53. package/dist/index.d.ts.map +1 -0
  54. package/dist/index.js +24 -14
  55. package/dist/lib/decode-quantized-mesh.d.ts +59 -0
  56. package/dist/lib/decode-quantized-mesh.d.ts.map +1 -0
  57. package/dist/lib/decode-quantized-mesh.js +200 -241
  58. package/dist/lib/delatin/index.d.ts +24 -0
  59. package/dist/lib/delatin/index.d.ts.map +1 -0
  60. package/dist/lib/delatin/index.js +397 -443
  61. package/dist/lib/helpers/skirt.d.ts +19 -0
  62. package/dist/lib/helpers/skirt.d.ts.map +1 -0
  63. package/dist/lib/helpers/skirt.js +119 -91
  64. package/dist/lib/parse-quantized-mesh.d.ts +25 -0
  65. package/dist/lib/parse-quantized-mesh.d.ts.map +1 -0
  66. package/dist/lib/parse-quantized-mesh.js +89 -90
  67. package/dist/lib/parse-terrain.d.ts +25 -0
  68. package/dist/lib/parse-terrain.d.ts.map +1 -0
  69. package/dist/lib/parse-terrain.js +148 -166
  70. package/dist/lib/utils/version.d.ts +2 -0
  71. package/dist/lib/utils/version.d.ts.map +1 -0
  72. package/dist/lib/utils/version.js +7 -2
  73. package/dist/quantized-mesh-loader.d.ts +21 -0
  74. package/dist/quantized-mesh-loader.d.ts.map +1 -0
  75. package/dist/quantized-mesh-loader.js +21 -16
  76. package/dist/quantized-mesh-worker.js +1218 -2
  77. package/dist/terrain-loader.d.ts +32 -0
  78. package/dist/terrain-loader.d.ts.map +1 -0
  79. package/dist/terrain-loader.js +32 -24
  80. package/dist/terrain-worker.js +1218 -2
  81. package/dist/workers/quantized-mesh-worker.d.ts +2 -0
  82. package/dist/workers/quantized-mesh-worker.d.ts.map +1 -0
  83. package/dist/workers/quantized-mesh-worker.js +5 -4
  84. package/dist/workers/terrain-worker.d.ts +2 -0
  85. package/dist/workers/terrain-worker.d.ts.map +1 -0
  86. package/dist/workers/terrain-worker.js +5 -4
  87. package/package.json +10 -10
  88. package/src/lib/{decode-quantized-mesh.js → decode-quantized-mesh.ts} +6 -1
  89. package/src/lib/delatin/{index.js → index.ts} +2 -0
  90. package/src/lib/helpers/{skirt.js → skirt.ts} +14 -7
  91. package/src/lib/{parse-quantized-mesh.js → parse-quantized-mesh.ts} +0 -0
  92. package/src/lib/{parse-terrain.js → parse-terrain.ts} +37 -3
  93. package/src/lib/utils/{version.js → version.ts} +0 -0
  94. package/src/workers/quantized-mesh-worker.js +0 -1
  95. package/src/workers/quantized-mesh-worker.ts +4 -0
  96. package/src/workers/terrain-worker.js +0 -1
  97. package/src/workers/terrain-worker.ts +4 -0
  98. package/dist/bundle.js.map +0 -1
  99. package/dist/dist.min.js +0 -2
  100. package/dist/dist.min.js.map +0 -1
  101. package/dist/index.js.map +0 -1
  102. package/dist/lib/decode-quantized-mesh.js.map +0 -1
  103. package/dist/lib/delatin/index.js.map +0 -1
  104. package/dist/lib/helpers/skirt.js.map +0 -1
  105. package/dist/lib/parse-quantized-mesh.js.map +0 -1
  106. package/dist/lib/parse-terrain.js.map +0 -1
  107. package/dist/lib/utils/version.js.map +0 -1
  108. package/dist/quantized-mesh-loader.js.map +0 -1
  109. package/dist/quantized-mesh-worker.js.map +0 -1
  110. package/dist/terrain-loader.js.map +0 -1
  111. package/dist/terrain-worker.js.map +0 -1
@@ -1,180 +1,162 @@
1
- import { getMeshBoundingBox } from '@loaders.gl/schema';
2
- import Martini from '@mapbox/martini';
3
- import Delatin from './delatin';
4
- import { addSkirt } from './helpers/skirt';
5
-
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const schema_1 = require("@loaders.gl/schema");
7
+ const martini_1 = __importDefault(require("@mapbox/martini"));
8
+ const delatin_1 = __importDefault(require("./delatin"));
9
+ const skirt_1 = require("./helpers/skirt");
6
10
  function getTerrain(imageData, width, height, elevationDecoder, tesselator) {
7
- const {
8
- rScaler,
9
- bScaler,
10
- gScaler,
11
- offset
12
- } = elevationDecoder;
13
- const terrain = new Float32Array((width + 1) * (height + 1));
14
-
15
- for (let i = 0, y = 0; y < height; y++) {
16
- for (let x = 0; x < width; x++, i++) {
17
- const k = i * 4;
18
- const r = imageData[k + 0];
19
- const g = imageData[k + 1];
20
- const b = imageData[k + 2];
21
- terrain[i + y] = r * rScaler + g * gScaler + b * bScaler + offset;
11
+ const { rScaler, bScaler, gScaler, offset } = elevationDecoder;
12
+ // From Martini demo
13
+ // https://observablehq.com/@mourner/martin-real-time-rtin-terrain-mesh
14
+ const terrain = new Float32Array((width + 1) * (height + 1));
15
+ // decode terrain values
16
+ for (let i = 0, y = 0; y < height; y++) {
17
+ for (let x = 0; x < width; x++, i++) {
18
+ const k = i * 4;
19
+ const r = imageData[k + 0];
20
+ const g = imageData[k + 1];
21
+ const b = imageData[k + 2];
22
+ terrain[i + y] = r * rScaler + g * gScaler + b * bScaler + offset;
23
+ }
22
24
  }
23
- }
24
-
25
- if (tesselator === 'martini') {
26
- for (let i = (width + 1) * width, x = 0; x < width; x++, i++) {
27
- terrain[i] = terrain[i - width - 1];
25
+ if (tesselator === 'martini') {
26
+ // backfill bottom border
27
+ for (let i = (width + 1) * width, x = 0; x < width; x++, i++) {
28
+ terrain[i] = terrain[i - width - 1];
29
+ }
30
+ // backfill right border
31
+ for (let i = height, y = 0; y < height + 1; y++, i += height + 1) {
32
+ terrain[i] = terrain[i - 1];
33
+ }
28
34
  }
29
-
30
- for (let i = height, y = 0; y < height + 1; y++, i += height + 1) {
31
- terrain[i] = terrain[i - 1];
32
- }
33
- }
34
-
35
- return terrain;
35
+ return terrain;
36
36
  }
37
-
38
37
  function getMeshAttributes(vertices, terrain, width, height, bounds) {
39
- const gridSize = width + 1;
40
- const numOfVerticies = vertices.length / 2;
41
- const positions = new Float32Array(numOfVerticies * 3);
42
- const texCoords = new Float32Array(numOfVerticies * 2);
43
- const [minX, minY, maxX, maxY] = bounds || [0, 0, width, height];
44
- const xScale = (maxX - minX) / width;
45
- const yScale = (maxY - minY) / height;
46
-
47
- for (let i = 0; i < numOfVerticies; i++) {
48
- const x = vertices[i * 2];
49
- const y = vertices[i * 2 + 1];
50
- const pixelIdx = y * gridSize + x;
51
- positions[3 * i + 0] = x * xScale + minX;
52
- positions[3 * i + 1] = -y * yScale + maxY;
53
- positions[3 * i + 2] = terrain[pixelIdx];
54
- texCoords[2 * i + 0] = x / width;
55
- texCoords[2 * i + 1] = y / height;
56
- }
57
-
58
- return {
59
- POSITION: {
60
- value: positions,
61
- size: 3
62
- },
63
- TEXCOORD_0: {
64
- value: texCoords,
65
- size: 2
38
+ const gridSize = width + 1;
39
+ const numOfVerticies = vertices.length / 2;
40
+ // vec3. x, y in pixels, z in meters
41
+ const positions = new Float32Array(numOfVerticies * 3);
42
+ // vec2. 1 to 1 relationship with position. represents the uv on the texture image. 0,0 to 1,1.
43
+ const texCoords = new Float32Array(numOfVerticies * 2);
44
+ const [minX, minY, maxX, maxY] = bounds || [0, 0, width, height];
45
+ const xScale = (maxX - minX) / width;
46
+ const yScale = (maxY - minY) / height;
47
+ for (let i = 0; i < numOfVerticies; i++) {
48
+ const x = vertices[i * 2];
49
+ const y = vertices[i * 2 + 1];
50
+ const pixelIdx = y * gridSize + x;
51
+ positions[3 * i + 0] = x * xScale + minX;
52
+ positions[3 * i + 1] = -y * yScale + maxY;
53
+ positions[3 * i + 2] = terrain[pixelIdx];
54
+ texCoords[2 * i + 0] = x / width;
55
+ texCoords[2 * i + 1] = y / height;
66
56
  }
67
- };
57
+ return {
58
+ POSITION: { value: positions, size: 3 },
59
+ TEXCOORD_0: { value: texCoords, size: 2 }
60
+ // NORMAL: {}, - optional, but creates the high poly look with lighting
61
+ };
68
62
  }
69
-
63
+ /**
64
+ * Returns generated mesh object from image data
65
+ *
66
+ * @param {object} terrainImage terrain image data
67
+ * @param {object} terrainOptions terrain options
68
+ * @returns mesh object
69
+ */
70
70
  function getMesh(terrainImage, terrainOptions) {
71
- if (terrainImage === null) {
72
- return null;
73
- }
74
-
75
- const {
76
- meshMaxError,
77
- bounds,
78
- elevationDecoder
79
- } = terrainOptions;
80
- const {
81
- data,
82
- width,
83
- height
84
- } = terrainImage;
85
- let terrain;
86
- let mesh;
87
-
88
- switch (terrainOptions.tesselator) {
89
- case 'martini':
90
- terrain = getTerrain(data, width, height, elevationDecoder, terrainOptions.tesselator);
91
- mesh = getMartiniTileMesh(meshMaxError, width, terrain);
92
- break;
93
-
94
- case 'delatin':
95
- terrain = getTerrain(data, width, height, elevationDecoder, terrainOptions.tesselator);
96
- mesh = getDelatinTileMesh(meshMaxError, width, height, terrain);
97
- break;
98
-
99
- default:
100
- if (width === height && !(height & width - 1)) {
101
- terrain = getTerrain(data, width, height, elevationDecoder, 'martini');
102
- mesh = getMartiniTileMesh(meshMaxError, width, terrain);
103
- } else {
104
- terrain = getTerrain(data, width, height, elevationDecoder, 'delatin');
105
- mesh = getDelatinTileMesh(meshMaxError, width, height, terrain);
106
- }
107
-
108
- break;
109
- }
110
-
111
- const {
112
- vertices
113
- } = mesh;
114
- let {
115
- triangles
116
- } = mesh;
117
- let attributes = getMeshAttributes(vertices, terrain, width, height, bounds);
118
- const boundingBox = getMeshBoundingBox(attributes);
119
-
120
- if (terrainOptions.skirtHeight) {
121
- const {
122
- attributes: newAttributes,
123
- triangles: newTriangles
124
- } = addSkirt(attributes, triangles, terrainOptions.skirtHeight);
125
- attributes = newAttributes;
126
- triangles = newTriangles;
127
- }
128
-
129
- return {
130
- loaderData: {
131
- header: {}
132
- },
133
- header: {
134
- vertexCount: triangles.length,
135
- boundingBox
136
- },
137
- mode: 4,
138
- indices: {
139
- value: Uint32Array.from(triangles),
140
- size: 1
141
- },
142
- attributes
143
- };
71
+ if (terrainImage === null) {
72
+ return null;
73
+ }
74
+ const { meshMaxError, bounds, elevationDecoder } = terrainOptions;
75
+ const { data, width, height } = terrainImage;
76
+ let terrain;
77
+ let mesh;
78
+ switch (terrainOptions.tesselator) {
79
+ case 'martini':
80
+ terrain = getTerrain(data, width, height, elevationDecoder, terrainOptions.tesselator);
81
+ mesh = getMartiniTileMesh(meshMaxError, width, terrain);
82
+ break;
83
+ case 'delatin':
84
+ terrain = getTerrain(data, width, height, elevationDecoder, terrainOptions.tesselator);
85
+ mesh = getDelatinTileMesh(meshMaxError, width, height, terrain);
86
+ break;
87
+ // auto
88
+ default:
89
+ if (width === height && !(height & (width - 1))) {
90
+ terrain = getTerrain(data, width, height, elevationDecoder, 'martini');
91
+ mesh = getMartiniTileMesh(meshMaxError, width, terrain);
92
+ }
93
+ else {
94
+ terrain = getTerrain(data, width, height, elevationDecoder, 'delatin');
95
+ mesh = getDelatinTileMesh(meshMaxError, width, height, terrain);
96
+ }
97
+ break;
98
+ }
99
+ const { vertices } = mesh;
100
+ let { triangles } = mesh;
101
+ let attributes = getMeshAttributes(vertices, terrain, width, height, bounds);
102
+ // Compute bounding box before adding skirt so that z values are not skewed
103
+ const boundingBox = (0, schema_1.getMeshBoundingBox)(attributes);
104
+ if (terrainOptions.skirtHeight) {
105
+ const { attributes: newAttributes, triangles: newTriangles } = (0, skirt_1.addSkirt)(attributes, triangles, terrainOptions.skirtHeight);
106
+ attributes = newAttributes;
107
+ triangles = newTriangles;
108
+ }
109
+ return {
110
+ // Data return by this loader implementation
111
+ loaderData: {
112
+ header: {}
113
+ },
114
+ header: {
115
+ vertexCount: triangles.length,
116
+ boundingBox
117
+ },
118
+ mode: 4,
119
+ indices: { value: Uint32Array.from(triangles), size: 1 },
120
+ attributes
121
+ };
144
122
  }
145
-
123
+ /**
124
+ * Get Martini generated vertices and triangles
125
+ *
126
+ * @param {number} meshMaxError threshold for simplifying mesh
127
+ * @param {number} width width of the input data
128
+ * @param {number[] | Float32Array} terrain elevation data
129
+ * @returns {{vertices: Uint16Array, triangles: Uint32Array}} vertices and triangles data
130
+ */
146
131
  function getMartiniTileMesh(meshMaxError, width, terrain) {
147
- const gridSize = width + 1;
148
- const martini = new Martini(gridSize);
149
- const tile = martini.createTile(terrain);
150
- const {
151
- vertices,
152
- triangles
153
- } = tile.getMesh(meshMaxError);
154
- return {
155
- vertices,
156
- triangles
157
- };
132
+ const gridSize = width + 1;
133
+ const martini = new martini_1.default(gridSize);
134
+ const tile = martini.createTile(terrain);
135
+ const { vertices, triangles } = tile.getMesh(meshMaxError);
136
+ return { vertices, triangles };
158
137
  }
159
-
138
+ /**
139
+ * Get Delatin generated vertices and triangles
140
+ *
141
+ * @param {number} meshMaxError threshold for simplifying mesh
142
+ * @param {number} width width of the input data array
143
+ * @param {number} height height of the input data array
144
+ * @param {number[] | Float32Array} terrain elevation data
145
+ * @returns {{vertices: number[], triangles: number[]}} vertices and triangles data
146
+ */
160
147
  function getDelatinTileMesh(meshMaxError, width, height, terrain) {
161
- const tin = new Delatin(terrain, width + 1, height + 1);
162
- tin.run(meshMaxError);
163
- const {
164
- coords,
165
- triangles
166
- } = tin;
167
- const vertices = coords;
168
- return {
169
- vertices,
170
- triangles
171
- };
148
+ const tin = new delatin_1.default(terrain, width + 1, height + 1);
149
+ tin.run(meshMaxError);
150
+ // @ts-expect-error
151
+ const { coords, triangles } = tin;
152
+ const vertices = coords;
153
+ return { vertices, triangles };
172
154
  }
173
-
174
- export default async function loadTerrain(arrayBuffer, options, context) {
175
- options.image = options.image || {};
176
- options.image.type = 'data';
177
- const image = await context.parse(arrayBuffer, options, options.baseUri);
178
- return getMesh(image, options.terrain);
155
+ async function loadTerrain(arrayBuffer, options, context) {
156
+ options.image = options.image || {};
157
+ options.image.type = 'data';
158
+ const image = await context.parse(arrayBuffer, options, options.baseUri);
159
+ // Extend function to support additional mesh generation options (square grid or delatin)
160
+ return getMesh(image, options.terrain);
179
161
  }
180
- //# sourceMappingURL=parse-terrain.js.map
162
+ exports.default = loadTerrain;
@@ -0,0 +1,2 @@
1
+ export declare const VERSION: any;
2
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/version.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,OAAO,KAA8D,CAAC"}
@@ -1,2 +1,7 @@
1
- export const VERSION = typeof "3.1.0-alpha.3" !== 'undefined' ? "3.1.0-alpha.3" : 'latest';
2
- //# sourceMappingURL=version.js.map
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VERSION = void 0;
4
+ // Version constant cannot be imported, it needs to correspond to the build version of **this** module.
5
+ // __VERSION__ is injected by babel-plugin-version-inline
6
+ // @ts-ignore TS2304: Cannot find name '__VERSION__'.
7
+ exports.VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'latest';
@@ -0,0 +1,21 @@
1
+ import type { Loader } from '@loaders.gl/loader-utils';
2
+ /**
3
+ * Worker loader for quantized meshes
4
+ */
5
+ export declare const QuantizedMeshLoader: {
6
+ name: string;
7
+ id: string;
8
+ module: string;
9
+ version: any;
10
+ worker: boolean;
11
+ extensions: string[];
12
+ mimeTypes: string[];
13
+ options: {
14
+ 'quantized-mesh': {
15
+ bounds: number[];
16
+ skirtHeight: null;
17
+ };
18
+ };
19
+ };
20
+ export declare const _typecheckQuantizedMeshLoader: Loader;
21
+ //# sourceMappingURL=quantized-mesh-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quantized-mesh-loader.d.ts","sourceRoot":"","sources":["../src/quantized-mesh-loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,0BAA0B,CAAC;AAGrD;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;CAc/B,CAAC;AAEF,eAAO,MAAM,6BAA6B,EAAE,MAA4B,CAAC"}
@@ -1,18 +1,23 @@
1
- import { VERSION } from './lib/utils/version';
2
- export const QuantizedMeshLoader = {
3
- name: 'Quantized Mesh',
4
- id: 'quantized-mesh',
5
- module: 'terrain',
6
- version: VERSION,
7
- worker: true,
8
- extensions: ['terrain'],
9
- mimeTypes: ['application/vnd.quantized-mesh'],
10
- options: {
11
- 'quantized-mesh': {
12
- bounds: [0, 0, 1, 1],
13
- skirtHeight: null
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports._typecheckQuantizedMeshLoader = exports.QuantizedMeshLoader = void 0;
4
+ const version_1 = require("./lib/utils/version");
5
+ /**
6
+ * Worker loader for quantized meshes
7
+ */
8
+ exports.QuantizedMeshLoader = {
9
+ name: 'Quantized Mesh',
10
+ id: 'quantized-mesh',
11
+ module: 'terrain',
12
+ version: version_1.VERSION,
13
+ worker: true,
14
+ extensions: ['terrain'],
15
+ mimeTypes: ['application/vnd.quantized-mesh'],
16
+ options: {
17
+ 'quantized-mesh': {
18
+ bounds: [0, 0, 1, 1],
19
+ skirtHeight: null
20
+ }
14
21
  }
15
- }
16
22
  };
17
- export const _typecheckQuantizedMeshLoader = QuantizedMeshLoader;
18
- //# sourceMappingURL=quantized-mesh-loader.js.map
23
+ exports._typecheckQuantizedMeshLoader = exports.QuantizedMeshLoader;