minerender 2.1.0-alpha.7 → 2.1.0-alpha.8
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/dist/browser/index.d.mts +5 -1
- package/dist/browser/index.d.ts +5 -1
- package/dist/browser/index.js +86 -48
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.mjs +86 -48
- package/dist/browser/index.mjs.map +1 -1
- package/dist/bundle.js +86 -48
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +4 -0
- package/dist/node/index.d.ts +4 -0
- package/dist/node/index.js +88 -49
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +88 -49
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/browser/index.d.mts
CHANGED
|
@@ -852,6 +852,7 @@ declare class EntityObject extends SceneObject {
|
|
|
852
852
|
constructor(entity: EntityModel, options?: Partial<EntityObjectOptions>);
|
|
853
853
|
init(): Promise<void>;
|
|
854
854
|
dispose(): void;
|
|
855
|
+
private get textureKey();
|
|
855
856
|
protected loadTextures(): Promise<void>;
|
|
856
857
|
protected createMeshes(force?: boolean): void;
|
|
857
858
|
protected applyTextures(): Promise<void>;
|
|
@@ -1511,6 +1512,9 @@ declare class Skins {
|
|
|
1511
1512
|
}
|
|
1512
1513
|
|
|
1513
1514
|
declare class TextureLoader {
|
|
1515
|
+
private static readonly failedTextures;
|
|
1516
|
+
/** Reports whether image loading failed, so cached textures can be retried. */
|
|
1517
|
+
static hasFailed(texture: Texture): boolean;
|
|
1514
1518
|
protected static createTexture(): Texture;
|
|
1515
1519
|
static loadInBackground(src: string, format?: PixelFormat, rotation?: number): Texture;
|
|
1516
1520
|
static load(src: string, format?: PixelFormat, rotation?: number): Texture;
|
|
@@ -1620,7 +1624,7 @@ declare class BrowserCache extends PersistentCache<LocalForage> {
|
|
|
1620
1624
|
*
|
|
1621
1625
|
* `image-size` pulls in `fs`/`path` at module scope, so it can only live in the Node build.
|
|
1622
1626
|
* Everything MineRender loads is a PNG in practice; GIF and JPEG are handled as a courtesy and
|
|
1623
|
-
* anything else falls through to an empty result
|
|
1627
|
+
* anything else falls through to an empty result, which ImageLoader rejects.
|
|
1624
1628
|
*/
|
|
1625
1629
|
declare function probeImageSize(data: Uint8Array): ImageSizeInfo;
|
|
1626
1630
|
|
package/dist/browser/index.d.ts
CHANGED
|
@@ -852,6 +852,7 @@ declare class EntityObject extends SceneObject {
|
|
|
852
852
|
constructor(entity: EntityModel, options?: Partial<EntityObjectOptions>);
|
|
853
853
|
init(): Promise<void>;
|
|
854
854
|
dispose(): void;
|
|
855
|
+
private get textureKey();
|
|
855
856
|
protected loadTextures(): Promise<void>;
|
|
856
857
|
protected createMeshes(force?: boolean): void;
|
|
857
858
|
protected applyTextures(): Promise<void>;
|
|
@@ -1511,6 +1512,9 @@ declare class Skins {
|
|
|
1511
1512
|
}
|
|
1512
1513
|
|
|
1513
1514
|
declare class TextureLoader {
|
|
1515
|
+
private static readonly failedTextures;
|
|
1516
|
+
/** Reports whether image loading failed, so cached textures can be retried. */
|
|
1517
|
+
static hasFailed(texture: Texture): boolean;
|
|
1514
1518
|
protected static createTexture(): Texture;
|
|
1515
1519
|
static loadInBackground(src: string, format?: PixelFormat, rotation?: number): Texture;
|
|
1516
1520
|
static load(src: string, format?: PixelFormat, rotation?: number): Texture;
|
|
@@ -1620,7 +1624,7 @@ declare class BrowserCache extends PersistentCache<LocalForage> {
|
|
|
1620
1624
|
*
|
|
1621
1625
|
* `image-size` pulls in `fs`/`path` at module scope, so it can only live in the Node build.
|
|
1622
1626
|
* Everything MineRender loads is a PNG in practice; GIF and JPEG are handled as a courtesy and
|
|
1623
|
-
* anything else falls through to an empty result
|
|
1627
|
+
* anything else falls through to an empty result, which ImageLoader rejects.
|
|
1624
1628
|
*/
|
|
1625
1629
|
declare function probeImageSize(data: Uint8Array): ImageSizeInfo;
|
|
1626
1630
|
|
package/dist/browser/index.js
CHANGED
|
@@ -912,29 +912,41 @@ var ImageLoader = class _ImageLoader {
|
|
|
912
912
|
static async loadAsync(src) {
|
|
913
913
|
return new Promise((resolve, reject) => {
|
|
914
914
|
const image = this._createImage();
|
|
915
|
-
image.src = src;
|
|
916
915
|
image.onload = () => resolve(image);
|
|
917
|
-
image.onerror = (err) => reject(err);
|
|
916
|
+
image.onerror = (err) => reject(err instanceof Error ? err : new Error("Failed to decode image"));
|
|
917
|
+
image.src = src;
|
|
918
918
|
});
|
|
919
919
|
}
|
|
920
920
|
static loadElement(src, onload, onerr) {
|
|
921
921
|
const image = this._createImage();
|
|
922
|
-
image.src = src;
|
|
923
922
|
if (onload)
|
|
924
923
|
image.onload = onload;
|
|
925
924
|
if (onerr)
|
|
926
925
|
image.onerror = onerr;
|
|
926
|
+
image.src = src;
|
|
927
927
|
return image;
|
|
928
928
|
}
|
|
929
929
|
static async loadData(src) {
|
|
930
930
|
console.debug(p2, "loadData", src);
|
|
931
|
-
|
|
931
|
+
const image = await this.loadCanvasData(src);
|
|
932
|
+
return image.data.getImageData(0, 0, image.width, image.height);
|
|
932
933
|
}
|
|
933
934
|
static async loadCanvasData(src) {
|
|
934
|
-
|
|
935
|
+
const keyStr = serializeImageKey({ src });
|
|
936
|
+
const info = this.getInfo(src);
|
|
937
|
+
const cached = Caching.rawImageCache.getIfPresent(keyStr);
|
|
938
|
+
try {
|
|
939
|
+
return await this.infoToCanvasData(await info);
|
|
940
|
+
} catch (err) {
|
|
941
|
+
if (cached && Caching.rawImageCache.getIfPresent(keyStr) === cached) {
|
|
942
|
+
Caching.rawImageCache.invalidate(keyStr);
|
|
943
|
+
}
|
|
944
|
+
throw err;
|
|
945
|
+
}
|
|
935
946
|
}
|
|
936
947
|
static async infoToCanvasData(info) {
|
|
937
|
-
const
|
|
948
|
+
const type = info.type === "jpg" ? "jpeg" : info.type ?? "png";
|
|
949
|
+
const image = await _ImageLoader.loadAsync(`data:image/${type};base64,${info.data.toString("base64")}`);
|
|
938
950
|
const canvas = createCanvas(info.width, info.height);
|
|
939
951
|
const context = canvas.getContext("2d");
|
|
940
952
|
context.drawImage(image, 0, 0);
|
|
@@ -945,11 +957,8 @@ var ImageLoader = class _ImageLoader {
|
|
|
945
957
|
};
|
|
946
958
|
}
|
|
947
959
|
static async infoToData(info) {
|
|
948
|
-
const image = await
|
|
949
|
-
|
|
950
|
-
const context = canvas.getContext("2d");
|
|
951
|
-
context.drawImage(image, 0, 0);
|
|
952
|
-
return context.getImageData(0, 0, canvas.width, canvas.height);
|
|
960
|
+
const image = await this.infoToCanvasData(info);
|
|
961
|
+
return image.data.getImageData(0, 0, image.width, image.height);
|
|
953
962
|
}
|
|
954
963
|
static async getData(src) {
|
|
955
964
|
const keyStr = serializeImageKey({ src });
|
|
@@ -964,13 +973,16 @@ var ImageLoader = class _ImageLoader {
|
|
|
964
973
|
});
|
|
965
974
|
}
|
|
966
975
|
static async processResponse(response) {
|
|
967
|
-
const src = response.config
|
|
976
|
+
const src = response.config?.url;
|
|
968
977
|
const data = import_buffer.Buffer.from(response.data);
|
|
969
978
|
const { width, height, type } = Env.provider.imageSize(data);
|
|
979
|
+
if (!width || !height) {
|
|
980
|
+
throw new Error("Invalid or unsupported image dimensions");
|
|
981
|
+
}
|
|
970
982
|
return {
|
|
971
983
|
src,
|
|
972
|
-
width
|
|
973
|
-
height
|
|
984
|
+
width,
|
|
985
|
+
height,
|
|
974
986
|
type,
|
|
975
987
|
data
|
|
976
988
|
};
|
|
@@ -987,15 +999,7 @@ var ImageLoader = class _ImageLoader {
|
|
|
987
999
|
return Requests.genericRequest({
|
|
988
1000
|
url: src,
|
|
989
1001
|
responseType: "arraybuffer"
|
|
990
|
-
}).then(this.processResponse)
|
|
991
|
-
return {
|
|
992
|
-
src,
|
|
993
|
-
width: 0,
|
|
994
|
-
height: 0,
|
|
995
|
-
type: void 0,
|
|
996
|
-
data: import_buffer.Buffer.from([0])
|
|
997
|
-
};
|
|
998
|
-
});
|
|
1002
|
+
}).then(this.processResponse);
|
|
999
1003
|
}
|
|
1000
1004
|
static async getInfo(src) {
|
|
1001
1005
|
const keyStr = serializeImageKey({ src });
|
|
@@ -1017,16 +1021,22 @@ var ImageLoader = class _ImageLoader {
|
|
|
1017
1021
|
|
|
1018
1022
|
// src/texture/TextureLoader.ts
|
|
1019
1023
|
var TextureLoader = class {
|
|
1024
|
+
/** Reports whether image loading failed, so cached textures can be retried. */
|
|
1025
|
+
static hasFailed(texture) {
|
|
1026
|
+
return this.failedTextures.has(texture);
|
|
1027
|
+
}
|
|
1020
1028
|
static createTexture() {
|
|
1021
1029
|
return new import_three4.Texture();
|
|
1022
1030
|
}
|
|
1023
1031
|
static loadInBackground(src, format = import_three4.RGBAFormat, rotation = 0) {
|
|
1024
1032
|
const texture = this.createTexture();
|
|
1025
1033
|
texture.colorSpace = THREE.SRGBColorSpace;
|
|
1026
|
-
const image = ImageLoader.loadElement(src)
|
|
1027
|
-
image.onload = function() {
|
|
1034
|
+
const image = ImageLoader.loadElement(src, () => {
|
|
1028
1035
|
texture.needsUpdate = true;
|
|
1029
|
-
}
|
|
1036
|
+
}, (error) => {
|
|
1037
|
+
this.failedTextures.add(texture);
|
|
1038
|
+
console.warn("Failed to load texture", src, error);
|
|
1039
|
+
});
|
|
1030
1040
|
texture.image = image;
|
|
1031
1041
|
texture.format = format;
|
|
1032
1042
|
texture.rotation = rotation;
|
|
@@ -1036,14 +1046,18 @@ var TextureLoader = class {
|
|
|
1036
1046
|
const texture = new import_three4.Texture();
|
|
1037
1047
|
texture.colorSpace = THREE.SRGBColorSpace;
|
|
1038
1048
|
ImageLoader.getData(src).then((image) => {
|
|
1039
|
-
texture.needsUpdate = true;
|
|
1040
1049
|
texture.image = image;
|
|
1050
|
+
texture.needsUpdate = true;
|
|
1051
|
+
}).catch((error) => {
|
|
1052
|
+
this.failedTextures.add(texture);
|
|
1053
|
+
console.warn("Failed to load texture", src, error);
|
|
1041
1054
|
});
|
|
1042
1055
|
texture.format = format;
|
|
1043
1056
|
texture.rotation = rotation;
|
|
1044
1057
|
return Textures.initTextureProps(texture);
|
|
1045
1058
|
}
|
|
1046
1059
|
};
|
|
1060
|
+
TextureLoader.failedTextures = /* @__PURE__ */ new WeakSet();
|
|
1047
1061
|
|
|
1048
1062
|
// src/texture/Textures.ts
|
|
1049
1063
|
var THREE2 = __toESM(require("three"));
|
|
@@ -1067,6 +1081,10 @@ var Textures = class _Textures {
|
|
|
1067
1081
|
}
|
|
1068
1082
|
static getImage(key) {
|
|
1069
1083
|
const keyStr = serializeTextureKey(key);
|
|
1084
|
+
const cached = Caching.textureCache.peek(keyStr);
|
|
1085
|
+
if (cached && TextureLoader.hasFailed(cached)) {
|
|
1086
|
+
Caching.textureCache.invalidate(keyStr);
|
|
1087
|
+
}
|
|
1070
1088
|
return Caching.textureCache.get(keyStr, (k) => {
|
|
1071
1089
|
return _Textures.createImage(key);
|
|
1072
1090
|
});
|
|
@@ -1211,6 +1229,10 @@ var _Materials = class _Materials {
|
|
|
1211
1229
|
}
|
|
1212
1230
|
static getImage(key) {
|
|
1213
1231
|
const keyStr = serializeMaterialKey(key);
|
|
1232
|
+
const map = Caching.materialCache.peek(keyStr)?.map;
|
|
1233
|
+
if (map && TextureLoader.hasFailed(map)) {
|
|
1234
|
+
Caching.materialCache.invalidate(keyStr);
|
|
1235
|
+
}
|
|
1214
1236
|
return Caching.materialCache.get(keyStr, (k) => {
|
|
1215
1237
|
return _Materials.createImage(key);
|
|
1216
1238
|
});
|
|
@@ -1868,11 +1890,21 @@ var ModelTextures = class {
|
|
|
1868
1890
|
return this._persistentMetaCache ?? (this._persistentMetaCache = PersistentCache.open("minerender-texturemeta"));
|
|
1869
1891
|
}
|
|
1870
1892
|
static async get(key) {
|
|
1871
|
-
const
|
|
1872
|
-
|
|
1873
|
-
|
|
1893
|
+
const keyStr = key.serialize();
|
|
1894
|
+
const pending = this.preload(key);
|
|
1895
|
+
const cached = Caching.textureAssetCache.getIfPresent(keyStr);
|
|
1896
|
+
try {
|
|
1897
|
+
const asset = await pending;
|
|
1898
|
+
if (asset) {
|
|
1899
|
+
return await ImageLoader.infoToCanvasData(asset);
|
|
1900
|
+
}
|
|
1901
|
+
return void 0;
|
|
1902
|
+
} catch (err) {
|
|
1903
|
+
if (cached && Caching.textureAssetCache.getIfPresent(keyStr) === cached) {
|
|
1904
|
+
Caching.textureAssetCache.invalidate(keyStr);
|
|
1905
|
+
}
|
|
1906
|
+
throw err;
|
|
1874
1907
|
}
|
|
1875
|
-
return void 0;
|
|
1876
1908
|
}
|
|
1877
1909
|
static async preload(key) {
|
|
1878
1910
|
const keyStr = key.serialize();
|
|
@@ -3063,8 +3095,8 @@ var EntityObject = class extends SceneObject {
|
|
|
3063
3095
|
dispose() {
|
|
3064
3096
|
super.dispose();
|
|
3065
3097
|
}
|
|
3066
|
-
|
|
3067
|
-
|
|
3098
|
+
get textureKey() {
|
|
3099
|
+
return new AssetKey(
|
|
3068
3100
|
this.entity.key?.namespace ?? DEFAULT_NAMESPACE,
|
|
3069
3101
|
this.entity.key.path,
|
|
3070
3102
|
//TODO: texture may differ from entity name; most of them are in subdirectories for multiple variants etc.
|
|
@@ -3072,7 +3104,10 @@ var EntityObject = class extends SceneObject {
|
|
|
3072
3104
|
"entity",
|
|
3073
3105
|
"assets",
|
|
3074
3106
|
".png"
|
|
3075
|
-
)
|
|
3107
|
+
);
|
|
3108
|
+
}
|
|
3109
|
+
async loadTextures() {
|
|
3110
|
+
this.imageData = await ModelTextures.get(this.textureKey);
|
|
3076
3111
|
}
|
|
3077
3112
|
//TODO: abstract this, since extracted model data can be used for entities, blocks, players
|
|
3078
3113
|
createMeshes(force = false) {
|
|
@@ -3105,20 +3140,23 @@ var EntityObject = class extends SceneObject {
|
|
|
3105
3140
|
this.meshesCreated = true;
|
|
3106
3141
|
}
|
|
3107
3142
|
async applyTextures() {
|
|
3108
|
-
const
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3143
|
+
const assetKeyStr = this.textureKey.serialize();
|
|
3144
|
+
const keyStr = `entity:${assetKeyStr}`;
|
|
3145
|
+
let mat = Caching.materialCache.getIfPresent(keyStr);
|
|
3146
|
+
if (!mat) {
|
|
3147
|
+
const pending = this.loadTextures();
|
|
3148
|
+
const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
|
|
3149
|
+
await pending;
|
|
3150
|
+
if (!this.imageData) return;
|
|
3151
|
+
const canvas = this.imageData.data.canvas;
|
|
3152
|
+
const createMaterial = () => Materials.createBasicCanvasMaterial(canvas);
|
|
3153
|
+
mat = cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
|
|
3154
|
+
this.imageData = void 0;
|
|
3155
|
+
}
|
|
3156
|
+
this.iterateAllMeshes((mesh) => {
|
|
3157
|
+
mesh.material = mat;
|
|
3158
|
+
});
|
|
3159
|
+
this.notifyDirty();
|
|
3122
3160
|
}
|
|
3123
3161
|
};
|
|
3124
3162
|
EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS, {});
|