Skip to content

Commit 1f1c29c

Browse files
author
Les Moffat
committed
- Fix Race condition in spacebox image loading - version bump for rc release
1 parent c2a3b86 commit 1f1c29c

File tree

3 files changed

+64
-43
lines changed

3 files changed

+64
-43
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@maptiler/sdk",
3-
"version": "3.5.1-rc5",
3+
"version": "3.5.1-rc6",
44
"description": "The Javascript & TypeScript map SDK tailored for MapTiler Cloud",
55
"author": "MapTiler",
66
"module": "dist/maptiler-sdk.mjs",

src/custom-layers/CubemapLayer/loadCubemapTexture.ts

Lines changed: 61 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ let memoizedImages: HTMLImageElement[] | undefined = undefined;
2323
*/
2424
let facesKey: string | undefined = undefined;
2525

26+
interface ImageLoadingPromiseReturnValue {
27+
image: HTMLImageElement;
28+
key: CubemapFaceNames;
29+
}
30+
2631
/**
2732
* Loads a cubemap texture from a set of image URLs.
2833
*
@@ -63,7 +68,6 @@ export function loadCubemapTexture({ gl, faces, onReady, forceRefresh }: LoadCub
6368
facesKey = JSON.stringify(faces);
6469

6570
const texture = gl.createTexture();
66-
gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
6771

6872
if (!faces) {
6973
console.warn("[CubemapLayer][loadCubemapTexture]: Faces are null");
@@ -77,63 +81,80 @@ export function loadCubemapTexture({ gl, faces, onReady, forceRefresh }: LoadCub
7781
return;
7882
}
7983

80-
const promises = Object.entries(faces as CubemapFaces).map(([key, face]) => {
81-
return new Promise<HTMLImageElement>((resolve, reject) => {
84+
const imageLoadingPromises = Object.entries(faces).map(([key, face]) => {
85+
return new Promise<ImageLoadingPromiseReturnValue>((resolve, reject) => {
86+
const keyEnum = key as CubemapFaceNames;
8287
if (face === undefined) {
83-
console.warn(`[CubemapLayer][loadCubemapTexture]: Face ${key} is undefined`);
88+
reject(new Error(`[CubemapLayer][loadCubemapTexture]: Face ${key} is undefined`));
8489
return;
8590
}
86-
const glCubemapTarget = getGlCubemapTarget(gl, key as CubemapFaceNames);
8791

88-
if (glCubemapTarget) {
89-
const level = 0;
90-
const internalFormat = gl.RGBA;
91-
const format = gl.RGBA;
92-
const type = gl.UNSIGNED_BYTE;
92+
const image = new Image();
9393

94-
const image = new Image();
94+
image.crossOrigin = "anonymous";
9595

96-
image.crossOrigin = "anonymous";
96+
const handleLoad = () => {
97+
resolve({ image, key: keyEnum });
98+
};
9799

98-
const handleLoad = () => {
99-
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
100-
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
101-
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
102-
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
100+
image.src = face;
103101

104-
gl.texImage2D(glCubemapTarget, level, internalFormat, format, type, image);
102+
// in case the image is loaded from the cache.
103+
if (image.complete && image.naturalWidth > 0) {
104+
handleLoad();
105+
} else {
106+
image.onload = handleLoad;
107+
}
105108

106-
resolve(image);
107-
};
109+
image.onerror = () => {
110+
reject(new Error(`[CubemapLayer][loadCubemapTexture]: Error loading image ${face}`));
111+
};
112+
});
113+
});
114+
115+
void Promise.all(imageLoadingPromises)
116+
.then((imagesAndFaceKeys) => {
117+
for (let i = 0; i < imagesAndFaceKeys.length; i++) {
118+
const lod = 0;
119+
const internalFormat = gl.RGBA;
120+
const format = gl.RGBA;
121+
const type = gl.UNSIGNED_BYTE;
108122

109-
image.src = face;
123+
const { image, key } = imagesAndFaceKeys[i] ?? {};
110124

111-
// in case the image is loaded from the cache.
112-
if (image.complete && image.naturalWidth > 0) {
113-
handleLoad();
114-
} else {
115-
image.onload = handleLoad;
125+
if (!image || !key) {
126+
console.warn(`[CubemapLayer][loadCubemapTexture]: Image or key is null`);
127+
continue;
116128
}
117129

118-
image.onerror = () => {
119-
reject(new Error(`[CubemapLayer][loadCubemapTexture]: Error loading image ${face}`));
120-
};
130+
const glCubemapTarget = getGlCubemapTarget(gl, key);
131+
132+
gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
133+
134+
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
135+
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
136+
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
137+
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
138+
139+
gl.texImage2D(glCubemapTarget, lod, internalFormat, format, type, image);
121140
}
122-
});
123-
});
124141

125-
void Promise.all(promises).then((images) => {
126-
gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
127-
gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
142+
gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
143+
gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
128144

129-
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
130-
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
145+
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
146+
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
131147

132-
onReady(texture, images);
148+
const imageElements = imagesAndFaceKeys.map((image) => image.image);
133149

134-
memoizedImages = images;
135-
memoizedTexture = texture;
136-
});
150+
onReady(texture, imageElements);
151+
152+
memoizedImages = imageElements;
153+
memoizedTexture = texture;
154+
})
155+
.catch((error) => {
156+
console.error(`[CubemapLayer][loadCubemapTexture]: Error loading cubemap texture`, error);
157+
});
137158
}
138159

139160
function getGlCubemapTarget(gl: WebGLRenderingContext | WebGL2RenderingContext, key: CubemapFaceNames): number {

0 commit comments

Comments
 (0)