@headless-three/renderer 0.1.10 → 0.3.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.
- package/README.md +32 -0
- package/dist/gpu-output.d.ts +190 -0
- package/dist/gpu-output.d.ts.map +1 -0
- package/dist/gpu-output.js +114 -0
- package/dist/gpu-output.js.map +1 -0
- package/dist/index.d.ts +26 -770
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +32 -6226
- package/dist/index.js.map +1 -1
- package/dist/index.part-001.d.ts +95 -0
- package/dist/index.part-001.d.ts.map +1 -0
- package/dist/index.part-001.js +273 -0
- package/dist/index.part-001.js.map +1 -0
- package/dist/index.part-002.d.ts +69 -0
- package/dist/index.part-002.d.ts.map +1 -0
- package/dist/index.part-002.js +211 -0
- package/dist/index.part-002.js.map +1 -0
- package/dist/index.part-003.d.ts +105 -0
- package/dist/index.part-003.d.ts.map +1 -0
- package/dist/index.part-003.js +270 -0
- package/dist/index.part-003.js.map +1 -0
- package/dist/index.part-004.d.ts +78 -0
- package/dist/index.part-004.d.ts.map +1 -0
- package/dist/index.part-004.js +390 -0
- package/dist/index.part-004.js.map +1 -0
- package/dist/index.part-005.d.ts +75 -0
- package/dist/index.part-005.d.ts.map +1 -0
- package/dist/index.part-005.js +236 -0
- package/dist/index.part-005.js.map +1 -0
- package/dist/index.part-006.d.ts +105 -0
- package/dist/index.part-006.d.ts.map +1 -0
- package/dist/index.part-006.js +262 -0
- package/dist/index.part-006.js.map +1 -0
- package/dist/index.part-007.d.ts +112 -0
- package/dist/index.part-007.d.ts.map +1 -0
- package/dist/index.part-007.js +358 -0
- package/dist/index.part-007.js.map +1 -0
- package/dist/index.part-008.d.ts +240 -0
- package/dist/index.part-008.d.ts.map +1 -0
- package/dist/index.part-008.js +458 -0
- package/dist/index.part-008.js.map +1 -0
- package/dist/index.part-009.d.ts +46 -0
- package/dist/index.part-009.d.ts.map +1 -0
- package/dist/index.part-009.js +379 -0
- package/dist/index.part-009.js.map +1 -0
- package/dist/index.part-010.d.ts +24 -0
- package/dist/index.part-010.d.ts.map +1 -0
- package/dist/index.part-010.js +277 -0
- package/dist/index.part-010.js.map +1 -0
- package/dist/index.part-011.d.ts +21 -0
- package/dist/index.part-011.d.ts.map +1 -0
- package/dist/index.part-011.js +361 -0
- package/dist/index.part-011.js.map +1 -0
- package/dist/index.part-012.d.ts +115 -0
- package/dist/index.part-012.d.ts.map +1 -0
- package/dist/index.part-012.js +298 -0
- package/dist/index.part-012.js.map +1 -0
- package/dist/index.part-013.d.ts +37 -0
- package/dist/index.part-013.d.ts.map +1 -0
- package/dist/index.part-013.js +341 -0
- package/dist/index.part-013.js.map +1 -0
- package/dist/index.part-014.d.ts +43 -0
- package/dist/index.part-014.d.ts.map +1 -0
- package/dist/index.part-014.js +441 -0
- package/dist/index.part-014.js.map +1 -0
- package/dist/index.part-015.d.ts +45 -0
- package/dist/index.part-015.d.ts.map +1 -0
- package/dist/index.part-015.js +432 -0
- package/dist/index.part-015.js.map +1 -0
- package/dist/index.part-016.d.ts +55 -0
- package/dist/index.part-016.d.ts.map +1 -0
- package/dist/index.part-016.js +382 -0
- package/dist/index.part-016.js.map +1 -0
- package/dist/index.part-017.d.ts +55 -0
- package/dist/index.part-017.d.ts.map +1 -0
- package/dist/index.part-017.js +436 -0
- package/dist/index.part-017.js.map +1 -0
- package/dist/index.part-018.d.ts +34 -0
- package/dist/index.part-018.d.ts.map +1 -0
- package/dist/index.part-018.js +365 -0
- package/dist/index.part-018.js.map +1 -0
- package/dist/index.part-019.d.ts +29 -0
- package/dist/index.part-019.d.ts.map +1 -0
- package/dist/index.part-019.js +261 -0
- package/dist/index.part-019.js.map +1 -0
- package/dist/index.part-020.d.ts +37 -0
- package/dist/index.part-020.d.ts.map +1 -0
- package/dist/index.part-020.js +388 -0
- package/dist/index.part-020.js.map +1 -0
- package/dist/index.part-021.d.ts +10 -0
- package/dist/index.part-021.d.ts.map +1 -0
- package/dist/index.part-021.js +142 -0
- package/dist/index.part-021.js.map +1 -0
- package/dist/loaders.d.ts +27 -91
- package/dist/loaders.d.ts.map +1 -1
- package/dist/loaders.js +22 -855
- package/dist/loaders.js.map +1 -1
- package/dist/loaders.part-001.d.ts +163 -0
- package/dist/loaders.part-001.d.ts.map +1 -0
- package/dist/loaders.part-001.js +277 -0
- package/dist/loaders.part-001.js.map +1 -0
- package/dist/loaders.part-002.d.ts +33 -0
- package/dist/loaders.part-002.d.ts.map +1 -0
- package/dist/loaders.part-002.js +511 -0
- package/dist/loaders.part-002.js.map +1 -0
- package/dist/loaders.part-003.d.ts +23 -0
- package/dist/loaders.part-003.d.ts.map +1 -0
- package/dist/loaders.part-003.js +138 -0
- package/dist/loaders.part-003.js.map +1 -0
- package/dist/materials.d.ts +33 -49
- package/dist/materials.d.ts.map +1 -1
- package/dist/materials.js +39 -4339
- package/dist/materials.js.map +1 -1
- package/dist/materials.part-001.d.ts +153 -0
- package/dist/materials.part-001.d.ts.map +1 -0
- package/dist/materials.part-001.js +347 -0
- package/dist/materials.part-001.js.map +1 -0
- package/dist/materials.part-002.d.ts +46 -0
- package/dist/materials.part-002.d.ts.map +1 -0
- package/dist/materials.part-002.js +299 -0
- package/dist/materials.part-002.js.map +1 -0
- package/dist/materials.part-003.d.ts +14 -0
- package/dist/materials.part-003.d.ts.map +1 -0
- package/dist/materials.part-003.js +438 -0
- package/dist/materials.part-003.js.map +1 -0
- package/dist/materials.part-004.d.ts +30 -0
- package/dist/materials.part-004.d.ts.map +1 -0
- package/dist/materials.part-004.js +464 -0
- package/dist/materials.part-004.js.map +1 -0
- package/dist/materials.part-005.d.ts +38 -0
- package/dist/materials.part-005.d.ts.map +1 -0
- package/dist/materials.part-005.js +366 -0
- package/dist/materials.part-005.js.map +1 -0
- package/dist/materials.part-006.d.ts +18 -0
- package/dist/materials.part-006.d.ts.map +1 -0
- package/dist/materials.part-006.js +391 -0
- package/dist/materials.part-006.js.map +1 -0
- package/dist/materials.part-007.d.ts +24 -0
- package/dist/materials.part-007.d.ts.map +1 -0
- package/dist/materials.part-007.js +467 -0
- package/dist/materials.part-007.js.map +1 -0
- package/dist/materials.part-008.d.ts +95 -0
- package/dist/materials.part-008.d.ts.map +1 -0
- package/dist/materials.part-008.js +404 -0
- package/dist/materials.part-008.js.map +1 -0
- package/dist/materials.part-009.d.ts +89 -0
- package/dist/materials.part-009.d.ts.map +1 -0
- package/dist/materials.part-009.js +412 -0
- package/dist/materials.part-009.js.map +1 -0
- package/dist/materials.part-010.d.ts +46 -0
- package/dist/materials.part-010.d.ts.map +1 -0
- package/dist/materials.part-010.js +375 -0
- package/dist/materials.part-010.js.map +1 -0
- package/dist/materials.part-011.d.ts +25 -0
- package/dist/materials.part-011.d.ts.map +1 -0
- package/dist/materials.part-011.js +435 -0
- package/dist/materials.part-011.js.map +1 -0
- package/dist/materials.part-012.d.ts +15 -0
- package/dist/materials.part-012.d.ts.map +1 -0
- package/dist/materials.part-012.js +229 -0
- package/dist/materials.part-012.js.map +1 -0
- package/dist/scene.d.ts +19 -279
- package/dist/scene.d.ts.map +1 -1
- package/dist/scene.js +21 -3931
- package/dist/scene.js.map +1 -1
- package/dist/scene.part-001.d.ts +375 -0
- package/dist/scene.part-001.d.ts.map +1 -0
- package/dist/scene.part-001.js +20 -0
- package/dist/scene.part-001.js.map +1 -0
- package/dist/scene.part-002.d.ts +28 -0
- package/dist/scene.part-002.d.ts.map +1 -0
- package/dist/scene.part-002.js +311 -0
- package/dist/scene.part-002.js.map +1 -0
- package/dist/scene.part-003.d.ts +26 -0
- package/dist/scene.part-003.d.ts.map +1 -0
- package/dist/scene.part-003.js +384 -0
- package/dist/scene.part-003.js.map +1 -0
- package/dist/scene.part-004.d.ts +24 -0
- package/dist/scene.part-004.d.ts.map +1 -0
- package/dist/scene.part-004.js +287 -0
- package/dist/scene.part-004.js.map +1 -0
- package/dist/scene.part-005.d.ts +37 -0
- package/dist/scene.part-005.d.ts.map +1 -0
- package/dist/scene.part-005.js +350 -0
- package/dist/scene.part-005.js.map +1 -0
- package/dist/scene.part-006.d.ts +25 -0
- package/dist/scene.part-006.d.ts.map +1 -0
- package/dist/scene.part-006.js +362 -0
- package/dist/scene.part-006.js.map +1 -0
- package/dist/scene.part-007.d.ts +36 -0
- package/dist/scene.part-007.d.ts.map +1 -0
- package/dist/scene.part-007.js +417 -0
- package/dist/scene.part-007.js.map +1 -0
- package/dist/scene.part-008.d.ts +78 -0
- package/dist/scene.part-008.d.ts.map +1 -0
- package/dist/scene.part-008.js +416 -0
- package/dist/scene.part-008.js.map +1 -0
- package/dist/scene.part-009.d.ts +25 -0
- package/dist/scene.part-009.d.ts.map +1 -0
- package/dist/scene.part-009.js +330 -0
- package/dist/scene.part-009.js.map +1 -0
- package/dist/scene.part-010.d.ts +32 -0
- package/dist/scene.part-010.d.ts.map +1 -0
- package/dist/scene.part-010.js +336 -0
- package/dist/scene.part-010.js.map +1 -0
- package/dist/scene.part-011.d.ts +100 -0
- package/dist/scene.part-011.d.ts.map +1 -0
- package/dist/scene.part-011.js +262 -0
- package/dist/scene.part-011.js.map +1 -0
- package/dist/scene.part-012.d.ts +48 -0
- package/dist/scene.part-012.d.ts.map +1 -0
- package/dist/scene.part-012.js +357 -0
- package/dist/scene.part-012.js.map +1 -0
- package/dist/scene.part-013.d.ts +51 -0
- package/dist/scene.part-013.d.ts.map +1 -0
- package/dist/scene.part-013.js +368 -0
- package/dist/scene.part-013.js.map +1 -0
- package/dist/scene.part-014.d.ts +16 -0
- package/dist/scene.part-014.d.ts.map +1 -0
- package/dist/scene.part-014.js +112 -0
- package/dist/scene.part-014.js.map +1 -0
- package/dist/types.d.ts +53 -1564
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +4 -1
- package/dist/types.js.map +1 -1
- package/dist/types.part-001.d.ts +386 -0
- package/dist/types.part-001.d.ts.map +1 -0
- package/dist/types.part-001.js +4 -0
- package/dist/types.part-001.js.map +1 -0
- package/dist/types.part-002.d.ts +407 -0
- package/dist/types.part-002.d.ts.map +1 -0
- package/dist/types.part-002.js +3 -0
- package/dist/types.part-002.js.map +1 -0
- package/dist/types.part-003.d.ts +427 -0
- package/dist/types.part-003.d.ts.map +1 -0
- package/dist/types.part-003.js +3 -0
- package/dist/types.part-003.js.map +1 -0
- package/dist/types.part-004.d.ts +351 -0
- package/dist/types.part-004.d.ts.map +1 -0
- package/dist/types.part-004.js +3 -0
- package/dist/types.part-004.js.map +1 -0
- package/native.d.ts +130 -0
- package/native.js +56 -52
- package/package.json +11 -8
package/dist/loaders.js
CHANGED
|
@@ -1,858 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.EncodedImageTextureLoader = void 0;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
exports.
|
|
12
|
-
|
|
13
|
-
exports.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
setRequestHeader() {
|
|
30
|
-
return this;
|
|
31
|
-
}
|
|
32
|
-
setWithCredentials() {
|
|
33
|
-
return this;
|
|
34
|
-
}
|
|
35
|
-
setPath(loaderPath) {
|
|
36
|
-
this.loaderPath = validatedTextureLoaderPath(loaderPath, 'loaderPath');
|
|
37
|
-
return this;
|
|
38
|
-
}
|
|
39
|
-
load(url, onLoad, _onProgress, onError) {
|
|
40
|
-
const texture = new Texture();
|
|
41
|
-
const requestedUrl = requiredString(url, 'url');
|
|
42
|
-
const loadCallback = optionalFunction(onLoad, 'onLoad');
|
|
43
|
-
const errorCallback = optionalFunction(onError, 'onError');
|
|
44
|
-
const source = resolveLoadingManagerUrl(this.manager, resolveTextureLoaderSource(requestedUrl, this.loaderPath));
|
|
45
|
-
const encodedDataUri = encodedImageDataUriBuffer(source);
|
|
46
|
-
const data = encodedDataUri
|
|
47
|
-
? Promise.resolve(encodedDataUri)
|
|
48
|
-
: /^blob:/i.test(source)
|
|
49
|
-
? readBlobUrlBuffer(source)
|
|
50
|
-
: (0, promises_1.readFile)(resolveLocalAssetPath(source, this.rootDir));
|
|
51
|
-
this.manager?.itemStart?.(source);
|
|
52
|
-
data.then((buffer) => {
|
|
53
|
-
texture.image = buffer;
|
|
54
|
-
texture.source.data = buffer;
|
|
55
|
-
texture.needsUpdate = true;
|
|
56
|
-
try {
|
|
57
|
-
loadCallback?.(texture);
|
|
58
|
-
}
|
|
59
|
-
finally {
|
|
60
|
-
this.manager?.itemEnd?.(source);
|
|
61
|
-
}
|
|
62
|
-
}, (error) => {
|
|
63
|
-
this.manager?.itemError?.(source);
|
|
64
|
-
this.manager?.itemEnd?.(source);
|
|
65
|
-
errorCallback?.(error);
|
|
66
|
-
});
|
|
67
|
-
return texture;
|
|
68
|
-
}
|
|
69
|
-
loadAsync(url, onProgress) {
|
|
70
|
-
return new Promise((resolve, reject) => {
|
|
71
|
-
try {
|
|
72
|
-
this.load(url, resolve, onProgress, reject);
|
|
73
|
-
}
|
|
74
|
-
catch (error) {
|
|
75
|
-
reject(error);
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
exports.EncodedImageTextureLoader = EncodedImageTextureLoader;
|
|
81
|
-
function createEncodedImageTextureLoader(rootDir, manager) {
|
|
82
|
-
return new EncodedImageTextureLoader(rootDir, manager);
|
|
83
|
-
}
|
|
84
|
-
async function createNodeGltfLoader(rootDir = process.cwd(), options = {}) {
|
|
85
|
-
const loaderOptions = objectOptions(options, 'options');
|
|
86
|
-
const root = resolveLocalRootDir(rootDir, 'rootDir');
|
|
87
|
-
const { configureLoader, installFetch, manager, registerTextureHandlers, } = validateNodeGltfLoaderOptions(loaderOptions);
|
|
88
|
-
const loadingManager = manager ?? new LoadingManager();
|
|
89
|
-
if (installFetch !== false) {
|
|
90
|
-
installLocalFileFetch();
|
|
91
|
-
}
|
|
92
|
-
installEncodedImageSupportProbe();
|
|
93
|
-
const encodedImages = createEncodedImageTextureLoader(root, loadingManager);
|
|
94
|
-
if (registerTextureHandlers !== false) {
|
|
95
|
-
registerEncodedImageHandlers(loadingManager, encodedImages);
|
|
96
|
-
}
|
|
97
|
-
const { GLTFLoader } = await importGltfLoader();
|
|
98
|
-
const loader = new GLTFLoader(loadingManager);
|
|
99
|
-
loader.setPath?.((0, node_url_1.pathToFileURL)(`${root}${node_path_1.default.sep}`).href);
|
|
100
|
-
await configureLoader?.(loader);
|
|
101
|
-
installAnimationPointerExtension(loader);
|
|
102
|
-
installNodeVisibilityExtension(loader);
|
|
103
|
-
installEmbeddedGlbImageNormalizer(loader);
|
|
104
|
-
return { encodedImages, loader, manager: loadingManager, rootDir: root };
|
|
105
|
-
}
|
|
106
|
-
async function loadGltfFromFile(filePath, options = {}) {
|
|
107
|
-
const loaderOptions = objectOptions(options, 'options');
|
|
108
|
-
validateLoadGltfFromFileOptions(loaderOptions);
|
|
109
|
-
const absolute = resolveLocalAssetPath(requiredString(filePath, 'filePath'));
|
|
110
|
-
const rootDirOption = optionalString(loaderOptions.rootDir, 'options.rootDir');
|
|
111
|
-
const root = rootDirOption == null ? node_path_1.default.dirname(absolute) : resolveLocalRootDir(rootDirOption, 'options.rootDir');
|
|
112
|
-
const baseUrl = optionalString(loaderOptions.baseUrl, 'options.baseUrl') ?? (0, node_url_1.pathToFileURL)(`${root}${node_path_1.default.sep}`).href;
|
|
113
|
-
const { loader } = await createNodeGltfLoader(root, loaderOptions);
|
|
114
|
-
const bytes = await (0, promises_1.readFile)(absolute);
|
|
115
|
-
return await new Promise((resolve, reject) => {
|
|
116
|
-
loader.parse(arrayBufferView(bytes), baseUrl, (gltf) => resolve(gltf), reject);
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
async function loadVrmFromFile(filePath, options = {}) {
|
|
120
|
-
const loaderOptions = objectOptions(options, 'options');
|
|
121
|
-
validateLoadGltfFromFileOptions(loaderOptions);
|
|
122
|
-
const validatedFilePath = requiredString(filePath, 'filePath');
|
|
123
|
-
const { VRMLoaderPlugin, configureLoader, ...gltfOptions } = loaderOptions;
|
|
124
|
-
const configureLoaderCallback = optionalFunction(configureLoader, 'options.configureLoader');
|
|
125
|
-
const VrmPlugin = optionalFunction(VRMLoaderPlugin, 'options.VRMLoaderPlugin') ?? await importVrmLoaderPlugin();
|
|
126
|
-
return await loadGltfFromFile(validatedFilePath, {
|
|
127
|
-
...gltfOptions,
|
|
128
|
-
configureLoader: async (loader) => {
|
|
129
|
-
registerLoaderPlugin(loader, (parser) => new VrmPlugin(parser), 'VRMLoaderPlugin');
|
|
130
|
-
await configureLoaderCallback?.(loader);
|
|
131
|
-
},
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
async function loadVrmAnimationFromFile(filePath, options = {}) {
|
|
135
|
-
const loaderOptions = objectOptions(options, 'options');
|
|
136
|
-
validateLoadGltfFromFileOptions(loaderOptions);
|
|
137
|
-
const validatedFilePath = requiredString(filePath, 'filePath');
|
|
138
|
-
const { VRMAnimationLoaderPlugin, VRMLoaderPlugin, configureLoader, ...gltfOptions } = loaderOptions;
|
|
139
|
-
const VrmPlugin = optionalFunction(VRMLoaderPlugin, 'options.VRMLoaderPlugin');
|
|
140
|
-
const configureLoaderCallback = optionalFunction(configureLoader, 'options.configureLoader');
|
|
141
|
-
const AnimationPlugin = optionalFunction(VRMAnimationLoaderPlugin, 'options.VRMAnimationLoaderPlugin') ?? await importVrmAnimationLoaderPlugin();
|
|
142
|
-
return await loadGltfFromFile(validatedFilePath, {
|
|
143
|
-
...gltfOptions,
|
|
144
|
-
configureLoader: async (loader) => {
|
|
145
|
-
if (VrmPlugin) {
|
|
146
|
-
registerLoaderPlugin(loader, (parser) => new VrmPlugin(parser), 'VRMLoaderPlugin');
|
|
147
|
-
}
|
|
148
|
-
registerLoaderPlugin(loader, (parser) => new AnimationPlugin(parser), 'VRMAnimationLoaderPlugin');
|
|
149
|
-
await configureLoaderCallback?.(loader);
|
|
150
|
-
},
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
async function applyVrmAnimation(vrm, vrmAnimation, options = {}) {
|
|
154
|
-
const helperOptions = objectOptions(options, 'options');
|
|
155
|
-
const model = resolveVrmModelInput(vrm);
|
|
156
|
-
const animationIndex = optionalNonNegativeInteger(helperOptions.animationIndex, 'options.animationIndex') ?? 0;
|
|
157
|
-
const animation = resolveVrmAnimationInput(vrmAnimation, animationIndex);
|
|
158
|
-
const time = optionalNonNegativeNumber(helperOptions.time, 'options.time') ?? 0;
|
|
159
|
-
const updateDelta = optionalNonNegativeNumber(helperOptions.updateDelta, 'options.updateDelta') ?? 0;
|
|
160
|
-
const updateVrm = optionalBoolean(helperOptions.updateVrm, 'options.updateVrm') ?? true;
|
|
161
|
-
const createClip = optionalFunction(helperOptions.createVRMAnimationClip, 'options.createVRMAnimationClip')
|
|
162
|
-
?? await importVrmAnimationClipFactory();
|
|
163
|
-
const Mixer = optionalFunction(helperOptions.AnimationMixer, 'options.AnimationMixer') ?? AnimationMixer;
|
|
164
|
-
const clip = createClip(animation, model);
|
|
165
|
-
const mixer = new Mixer(model.scene);
|
|
166
|
-
if (typeof mixer.clipAction !== 'function') {
|
|
167
|
-
throw new TypeError('AnimationMixer must provide a clipAction() function.');
|
|
168
|
-
}
|
|
169
|
-
const action = mixer.clipAction(clip);
|
|
170
|
-
if (!action || typeof action.play !== 'function') {
|
|
171
|
-
throw new TypeError('AnimationMixer.clipAction() must return an action with play().');
|
|
172
|
-
}
|
|
173
|
-
action.play();
|
|
174
|
-
if (typeof mixer.setTime === 'function') {
|
|
175
|
-
mixer.setTime(time);
|
|
176
|
-
}
|
|
177
|
-
else if (typeof mixer.update === 'function') {
|
|
178
|
-
mixer.update(time);
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
181
|
-
throw new TypeError('AnimationMixer must provide setTime() or update().');
|
|
182
|
-
}
|
|
183
|
-
if (updateVrm && model.update != null) {
|
|
184
|
-
if (typeof model.update !== 'function') {
|
|
185
|
-
throw new TypeError('vrm.update must be a function when provided.');
|
|
186
|
-
}
|
|
187
|
-
model.update(updateDelta);
|
|
188
|
-
}
|
|
189
|
-
return { action, clip, mixer };
|
|
190
|
-
}
|
|
191
|
-
function resolveVrmModelInput(vrm) {
|
|
192
|
-
const input = objectOptions(vrm, 'vrm');
|
|
193
|
-
const userData = input.userData;
|
|
194
|
-
const wrapped = userData != null
|
|
195
|
-
&& typeof userData === 'object'
|
|
196
|
-
&& !Array.isArray(userData)
|
|
197
|
-
&& 'vrm' in userData;
|
|
198
|
-
const label = wrapped ? 'vrm.userData.vrm' : 'vrm';
|
|
199
|
-
const model = objectOptions(wrapped ? userData.vrm : vrm, label);
|
|
200
|
-
if (model.scene == null || typeof model.scene !== 'object' || Array.isArray(model.scene)) {
|
|
201
|
-
throw new TypeError(`${label}.scene must be an object.`);
|
|
202
|
-
}
|
|
203
|
-
return model;
|
|
204
|
-
}
|
|
205
|
-
function resolveVrmAnimationInput(vrmAnimation, animationIndex = 0) {
|
|
206
|
-
const input = objectOptions(vrmAnimation, 'vrmAnimation');
|
|
207
|
-
const userData = input.userData;
|
|
208
|
-
if (userData == null || typeof userData !== 'object' || Array.isArray(userData) || !('vrmAnimations' in userData)) {
|
|
209
|
-
return vrmAnimation;
|
|
210
|
-
}
|
|
211
|
-
const animations = userData.vrmAnimations;
|
|
212
|
-
if (!Array.isArray(animations)) {
|
|
213
|
-
throw new TypeError('vrmAnimation.userData.vrmAnimations must be an array.');
|
|
214
|
-
}
|
|
215
|
-
objectOptions(animations[animationIndex], `vrmAnimation.userData.vrmAnimations[${animationIndex}]`);
|
|
216
|
-
return animations[animationIndex];
|
|
217
|
-
}
|
|
218
|
-
function encodedImageDataUriBuffer(url) {
|
|
219
|
-
if (!/^data:/i.test(url))
|
|
220
|
-
return null;
|
|
221
|
-
const comma = url.indexOf(',');
|
|
222
|
-
if (comma < 0) {
|
|
223
|
-
throw new Error('Data URI texture is missing a comma separator.');
|
|
224
|
-
}
|
|
225
|
-
const metadata = url.slice(5, comma).toLowerCase();
|
|
226
|
-
if (!/^image\/(?:png|jpe?g|webp)(?:;|$)/.test(metadata)) {
|
|
227
|
-
throw new Error('Data URI texture is not a supported encoded image. Use PNG, JPEG, or WebP data URIs.');
|
|
228
|
-
}
|
|
229
|
-
const payload = url.slice(comma + 1);
|
|
230
|
-
if (/(?:^|;)base64(?:;|$)/.test(metadata)) {
|
|
231
|
-
return Buffer.from(payload, 'base64');
|
|
232
|
-
}
|
|
233
|
-
return Buffer.from(decodeURIComponent(payload), 'utf8');
|
|
234
|
-
}
|
|
235
|
-
async function readBlobUrlBuffer(url) {
|
|
236
|
-
if (typeof fetch !== 'function') {
|
|
237
|
-
throw new Error('Blob URL textures require global fetch support. Install a fetch polyfill or rewrite embedded images as files/data URIs before loading.');
|
|
238
|
-
}
|
|
239
|
-
const response = await fetch(url);
|
|
240
|
-
if (!response.ok) {
|
|
241
|
-
throw new Error(`Blob URL texture fetch failed with status ${response.status}.`);
|
|
242
|
-
}
|
|
243
|
-
const contentType = response.headers.get('content-type')?.split(';', 1)[0].trim().toLowerCase();
|
|
244
|
-
if (contentType && !/^image\/(?:png|jpe?g|webp)$/.test(contentType)) {
|
|
245
|
-
throw new Error(`Blob URL texture has unsupported content type "${contentType}". Use PNG, JPEG, or WebP embedded images.`);
|
|
246
|
-
}
|
|
247
|
-
return Buffer.from(await response.arrayBuffer());
|
|
248
|
-
}
|
|
249
|
-
function resolveTextureLoaderSource(url, loaderPath) {
|
|
250
|
-
if (!loaderPath || isAbsoluteOrSpecialAssetUrl(url))
|
|
251
|
-
return url;
|
|
252
|
-
if (node_path_1.default.isAbsolute(loaderPath))
|
|
253
|
-
return node_path_1.default.join(loaderPath, url);
|
|
254
|
-
if (node_path_1.default.win32.isAbsolute(loaderPath))
|
|
255
|
-
return node_path_1.default.win32.join(loaderPath, url);
|
|
256
|
-
if (/^[a-z][a-z0-9+.-]*:/i.test(loaderPath)) {
|
|
257
|
-
return new URL(url, ensureDirectoryUrl(loaderPath)).href;
|
|
258
|
-
}
|
|
259
|
-
return node_path_1.default.join(loaderPath, url);
|
|
260
|
-
}
|
|
261
|
-
function validatedTextureLoaderPath(loaderPath, label) {
|
|
262
|
-
const value = requiredString(loaderPath, label);
|
|
263
|
-
if (!value || node_path_1.default.isAbsolute(value) || node_path_1.default.win32.isAbsolute(value) || /^file:/i.test(value))
|
|
264
|
-
return value;
|
|
265
|
-
if (/^[a-z][a-z0-9+.-]*:/i.test(value)) {
|
|
266
|
-
throw new Error(`${label} is not a local directory path: ${value}`);
|
|
267
|
-
}
|
|
268
|
-
return value;
|
|
269
|
-
}
|
|
270
|
-
function resolveLoadingManagerUrl(manager, url) {
|
|
271
|
-
const resolveURL = manager?.resolveURL;
|
|
272
|
-
if (resolveURL == null)
|
|
273
|
-
return url;
|
|
274
|
-
const resolved = resolveURL.call(manager, url);
|
|
275
|
-
return requiredString(resolved, 'manager.resolveURL return value');
|
|
276
|
-
}
|
|
277
|
-
function isAbsoluteOrSpecialAssetUrl(url) {
|
|
278
|
-
return /^data:/i.test(url)
|
|
279
|
-
|| /^blob:/i.test(url)
|
|
280
|
-
|| node_path_1.default.isAbsolute(url)
|
|
281
|
-
|| node_path_1.default.win32.isAbsolute(url)
|
|
282
|
-
|| /^file:/i.test(url)
|
|
283
|
-
|| /^[a-z][a-z0-9+.-]*:/i.test(url);
|
|
284
|
-
}
|
|
285
|
-
function ensureDirectoryUrl(url) {
|
|
286
|
-
return url.endsWith('/') ? url : `${url}/`;
|
|
287
|
-
}
|
|
288
|
-
function resolveLocalAssetPath(url, rootDir = process.cwd()) {
|
|
289
|
-
const assetUrl = requiredString(url, 'url');
|
|
290
|
-
requiredString(rootDir, 'rootDir');
|
|
291
|
-
if (/^data:/i.test(assetUrl)) {
|
|
292
|
-
throw new Error('Data URI textures should be decoded or written to files before loading in Node.');
|
|
293
|
-
}
|
|
294
|
-
if (node_path_1.default.isAbsolute(assetUrl) || node_path_1.default.win32.isAbsolute(assetUrl))
|
|
295
|
-
return node_path_1.default.normalize(assetUrl);
|
|
296
|
-
if (/^file:/i.test(assetUrl))
|
|
297
|
-
return (0, node_url_1.fileURLToPath)(assetUrl);
|
|
298
|
-
if (/^[a-z][a-z0-9+.-]*:/i.test(assetUrl)) {
|
|
299
|
-
throw new Error(`Remote texture URL is not a local file: ${assetUrl}`);
|
|
300
|
-
}
|
|
301
|
-
const root = resolveLocalRootDir(rootDir, 'rootDir');
|
|
302
|
-
return node_path_1.default.resolve(root, assetUrl);
|
|
303
|
-
}
|
|
304
|
-
function resolveLocalRootDir(rootDir, label) {
|
|
305
|
-
const value = requiredString(rootDir, label);
|
|
306
|
-
if (/^data:/i.test(value)) {
|
|
307
|
-
throw new Error(`${label} must be a local directory path, not a data URI.`);
|
|
308
|
-
}
|
|
309
|
-
if (node_path_1.default.isAbsolute(value) || node_path_1.default.win32.isAbsolute(value)) {
|
|
310
|
-
return node_path_1.default.normalize(value);
|
|
311
|
-
}
|
|
312
|
-
if (/^file:/i.test(value)) {
|
|
313
|
-
return (0, node_url_1.fileURLToPath)(value);
|
|
314
|
-
}
|
|
315
|
-
if (/^[a-z][a-z0-9+.-]*:/i.test(value)) {
|
|
316
|
-
throw new Error(`${label} is not a local directory path: ${value}`);
|
|
317
|
-
}
|
|
318
|
-
return node_path_1.default.resolve(value);
|
|
319
|
-
}
|
|
320
|
-
function installLocalFileFetch() {
|
|
321
|
-
const marker = Symbol.for('headless-three-renderer.local-file-fetch');
|
|
322
|
-
const globalScope = globalThis;
|
|
323
|
-
if (typeof globalScope.self === 'undefined') {
|
|
324
|
-
globalScope.self = globalScope;
|
|
325
|
-
}
|
|
326
|
-
if (globalScope[marker])
|
|
327
|
-
return;
|
|
328
|
-
if (typeof globalScope.ProgressEvent === 'undefined') {
|
|
329
|
-
const EventCtor = typeof globalScope.Event === 'function'
|
|
330
|
-
? globalScope.Event
|
|
331
|
-
: class Event {
|
|
332
|
-
constructor(type) {
|
|
333
|
-
this.type = type;
|
|
334
|
-
}
|
|
335
|
-
};
|
|
336
|
-
globalScope.ProgressEvent = class ProgressEvent extends EventCtor {
|
|
337
|
-
constructor(type, init = {}) {
|
|
338
|
-
super(type);
|
|
339
|
-
this.lengthComputable = init.lengthComputable ?? false;
|
|
340
|
-
this.loaded = init.loaded ?? 0;
|
|
341
|
-
this.total = init.total ?? 0;
|
|
342
|
-
}
|
|
343
|
-
};
|
|
344
|
-
}
|
|
345
|
-
const nativeFetch = globalScope.fetch;
|
|
346
|
-
globalScope.fetch = async (input, init) => {
|
|
347
|
-
const url = typeof input === 'string' || input instanceof URL ? String(input) : input?.url;
|
|
348
|
-
if (typeof url === 'string' && url.startsWith('file:')) {
|
|
349
|
-
const buffer = await (0, promises_1.readFile)((0, node_url_1.fileURLToPath)(url));
|
|
350
|
-
const ResponseCtor = globalScope.Response;
|
|
351
|
-
if (typeof ResponseCtor !== 'function') {
|
|
352
|
-
throw new Error('global Response is not available; install a fetch polyfill before loading local files.');
|
|
353
|
-
}
|
|
354
|
-
return new ResponseCtor(buffer);
|
|
355
|
-
}
|
|
356
|
-
if (typeof nativeFetch !== 'function') {
|
|
357
|
-
throw new Error('global fetch is not available; install a fetch polyfill before loading remote assets.');
|
|
358
|
-
}
|
|
359
|
-
return nativeFetch(input, init);
|
|
360
|
-
};
|
|
361
|
-
globalScope[marker] = true;
|
|
362
|
-
}
|
|
363
|
-
function installEncodedImageSupportProbe() {
|
|
364
|
-
const globalScope = globalThis;
|
|
365
|
-
if (typeof globalScope.Image === 'function')
|
|
366
|
-
return;
|
|
367
|
-
const marker = Symbol.for('headless-three-renderer.encoded-image-probe');
|
|
368
|
-
if (globalScope[marker])
|
|
369
|
-
return;
|
|
370
|
-
globalScope.Image = class EncodedImageProbe {
|
|
371
|
-
constructor() {
|
|
372
|
-
this.height = 0;
|
|
373
|
-
this.onerror = null;
|
|
374
|
-
this.onload = null;
|
|
375
|
-
this.width = 0;
|
|
376
|
-
}
|
|
377
|
-
set src(value) {
|
|
378
|
-
const url = String(value ?? '');
|
|
379
|
-
const supported = /^data:image\/webp[;,]/i.test(url);
|
|
380
|
-
this.width = supported ? 1 : 0;
|
|
381
|
-
this.height = supported ? 1 : 0;
|
|
382
|
-
queueMicrotask(() => {
|
|
383
|
-
if (supported) {
|
|
384
|
-
this.onload?.();
|
|
385
|
-
}
|
|
386
|
-
else {
|
|
387
|
-
this.onerror?.();
|
|
388
|
-
}
|
|
389
|
-
});
|
|
390
|
-
}
|
|
391
|
-
};
|
|
392
|
-
globalScope[marker] = true;
|
|
393
|
-
}
|
|
394
|
-
function registerEncodedImageHandlers(manager, encodedImages) {
|
|
395
|
-
manager.addHandler(/^blob:/i, encodedImages);
|
|
396
|
-
manager.addHandler(/^data:image\/(?:png|jpe?g|webp)/i, encodedImages);
|
|
397
|
-
manager.addHandler(/\.(png|jpe?g|webp)$/i, encodedImages);
|
|
398
|
-
}
|
|
399
|
-
function arrayBufferView(buffer) {
|
|
400
|
-
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
401
|
-
}
|
|
402
|
-
function installEmbeddedGlbImageNormalizer(loader) {
|
|
403
|
-
const originalParse = loader.parse.bind(loader);
|
|
404
|
-
loader.parse = (data, parsePath, onLoad, onError) => {
|
|
405
|
-
originalParse(normalizeEmbeddedGlbImages(data), parsePath, onLoad, onError);
|
|
406
|
-
};
|
|
407
|
-
}
|
|
408
|
-
function installNodeVisibilityExtension(loader) {
|
|
409
|
-
registerLoaderPlugin(loader, (parser) => ({
|
|
410
|
-
name: 'KHR_node_visibility',
|
|
411
|
-
afterRoot(gltf) {
|
|
412
|
-
applyNodeVisibilityExtension(gltf, parser);
|
|
413
|
-
},
|
|
414
|
-
}), 'KHR_node_visibility');
|
|
415
|
-
}
|
|
416
|
-
function installAnimationPointerExtension(loader) {
|
|
417
|
-
registerLoaderPlugin(loader, (parser) => ({
|
|
418
|
-
name: 'KHR_animation_pointer',
|
|
419
|
-
afterRoot(gltf) {
|
|
420
|
-
return applyAnimationPointerExtension(gltf, parser);
|
|
421
|
-
},
|
|
422
|
-
}), 'KHR_animation_pointer');
|
|
423
|
-
}
|
|
424
|
-
async function applyAnimationPointerExtension(gltf, parser) {
|
|
425
|
-
const animationDefs = parser.json?.animations;
|
|
426
|
-
const clips = gltf.animations;
|
|
427
|
-
if (!Array.isArray(animationDefs) || !Array.isArray(clips) || typeof parser.getDependency !== 'function')
|
|
428
|
-
return;
|
|
429
|
-
for (let animationIndex = 0; animationIndex < animationDefs.length; animationIndex++) {
|
|
430
|
-
const animationDef = animationDefs[animationIndex];
|
|
431
|
-
const clip = clips[animationIndex];
|
|
432
|
-
if (!clip || !Array.isArray(clip.tracks) || !Array.isArray(animationDef.channels) || !Array.isArray(animationDef.samplers))
|
|
433
|
-
continue;
|
|
434
|
-
for (const channel of animationDef.channels) {
|
|
435
|
-
const pointer = channel.target?.extensions?.KHR_animation_pointer?.pointer;
|
|
436
|
-
const match = typeof pointer === 'string'
|
|
437
|
-
? pointer.match(/^\/materials\/(\d+)\/pbrMetallicRoughness\/baseColorFactor$/)
|
|
438
|
-
: null;
|
|
439
|
-
if (!match)
|
|
440
|
-
continue;
|
|
441
|
-
const samplerIndex = channel.sampler;
|
|
442
|
-
const sampler = typeof samplerIndex === 'number' ? animationDef.samplers[samplerIndex] : undefined;
|
|
443
|
-
if (!sampler || sampler.interpolation === 'CUBICSPLINE' || typeof sampler.input !== 'number' || typeof sampler.output !== 'number')
|
|
444
|
-
continue;
|
|
445
|
-
const materialIndex = Number.parseInt(match[1], 10);
|
|
446
|
-
const targets = materialAnimationTargets(gltf, parser, materialIndex);
|
|
447
|
-
if (targets.length === 0)
|
|
448
|
-
continue;
|
|
449
|
-
const [inputAccessor, outputAccessor] = await Promise.all([
|
|
450
|
-
parser.getDependency('accessor', sampler.input),
|
|
451
|
-
parser.getDependency('accessor', sampler.output),
|
|
452
|
-
]);
|
|
453
|
-
const times = inputAccessor.array;
|
|
454
|
-
const values = outputAccessor.array;
|
|
455
|
-
const itemSize = outputAccessor.itemSize ?? 0;
|
|
456
|
-
if (!times || !values || itemSize < 3)
|
|
457
|
-
continue;
|
|
458
|
-
const colorValues = animationPointerColorValues(times.length, values, itemSize);
|
|
459
|
-
const interpolation = sampler.interpolation === 'STEP' ? InterpolateDiscrete : InterpolateLinear;
|
|
460
|
-
for (const target of targets) {
|
|
461
|
-
clip.tracks.push(new ColorKeyframeTrack(`${target}.material.color`, times, colorValues, interpolation));
|
|
462
|
-
}
|
|
463
|
-
clip.resetDuration?.();
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
function materialAnimationTargets(gltf, parser, materialIndex) {
|
|
468
|
-
const associations = parser.associations;
|
|
469
|
-
if (!associations)
|
|
470
|
-
return [];
|
|
471
|
-
const targets = [];
|
|
472
|
-
const seen = new Set();
|
|
473
|
-
for (const root of gltfRootScenes(gltf)) {
|
|
474
|
-
root.traverse?.((object) => {
|
|
475
|
-
const mesh = object;
|
|
476
|
-
if (mesh.isMesh !== true)
|
|
477
|
-
return;
|
|
478
|
-
const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
|
|
479
|
-
if (!materials.some((material) => associations.get(material)?.materials === materialIndex))
|
|
480
|
-
return;
|
|
481
|
-
const target = mesh.name || mesh.uuid;
|
|
482
|
-
if (target && !seen.has(target)) {
|
|
483
|
-
seen.add(target);
|
|
484
|
-
targets.push(target);
|
|
485
|
-
}
|
|
486
|
-
});
|
|
487
|
-
}
|
|
488
|
-
return targets;
|
|
489
|
-
}
|
|
490
|
-
function animationPointerColorValues(keyframeCount, values, itemSize) {
|
|
491
|
-
const colors = new Float32Array(keyframeCount * 3);
|
|
492
|
-
for (let keyframe = 0; keyframe < keyframeCount; keyframe++) {
|
|
493
|
-
const source = keyframe * itemSize;
|
|
494
|
-
const target = keyframe * 3;
|
|
495
|
-
colors[target] = Number(values[source] ?? 0);
|
|
496
|
-
colors[target + 1] = Number(values[source + 1] ?? 0);
|
|
497
|
-
colors[target + 2] = Number(values[source + 2] ?? 0);
|
|
498
|
-
}
|
|
499
|
-
return colors;
|
|
500
|
-
}
|
|
501
|
-
function applyNodeVisibilityExtension(gltf, parser) {
|
|
502
|
-
const associations = parser.associations;
|
|
503
|
-
const nodes = parser.json?.nodes;
|
|
504
|
-
if (!associations || !Array.isArray(nodes))
|
|
505
|
-
return;
|
|
506
|
-
const nodeIndexByName = uniqueNodeIndexByName(nodes);
|
|
507
|
-
for (const root of gltfRootScenes(gltf)) {
|
|
508
|
-
root.traverse?.((object) => {
|
|
509
|
-
const association = associations.get(object);
|
|
510
|
-
let nodeIndex = association?.nodes;
|
|
511
|
-
const objectName = typeof object.name === 'string'
|
|
512
|
-
? object.name
|
|
513
|
-
: '';
|
|
514
|
-
const associatedNode = typeof nodeIndex === 'number' && Number.isInteger(nodeIndex)
|
|
515
|
-
? nodes[nodeIndex]
|
|
516
|
-
: undefined;
|
|
517
|
-
const associatedName = typeof associatedNode?.name === 'string'
|
|
518
|
-
? associatedNode.name
|
|
519
|
-
: '';
|
|
520
|
-
if (objectName && associatedName !== objectName) {
|
|
521
|
-
nodeIndex = nodeIndexByName.get(objectName) ?? nodeIndex;
|
|
522
|
-
}
|
|
523
|
-
if (typeof nodeIndex !== 'number' || !Number.isInteger(nodeIndex))
|
|
524
|
-
return;
|
|
525
|
-
const node = nodes[nodeIndex];
|
|
526
|
-
if (!node || typeof node !== 'object' || Array.isArray(node))
|
|
527
|
-
return;
|
|
528
|
-
const visible = node.extensions?.KHR_node_visibility?.visible;
|
|
529
|
-
const objectLike = object;
|
|
530
|
-
if (visible === false) {
|
|
531
|
-
objectLike.visible = false;
|
|
532
|
-
}
|
|
533
|
-
else if (visible === true) {
|
|
534
|
-
objectLike.visible = true;
|
|
535
|
-
}
|
|
536
|
-
});
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
function uniqueNodeIndexByName(nodes) {
|
|
540
|
-
const counts = new Map();
|
|
541
|
-
for (const node of nodes) {
|
|
542
|
-
const name = typeof node?.name === 'string'
|
|
543
|
-
? node.name
|
|
544
|
-
: '';
|
|
545
|
-
if (name)
|
|
546
|
-
counts.set(name, (counts.get(name) ?? 0) + 1);
|
|
547
|
-
}
|
|
548
|
-
const result = new Map();
|
|
549
|
-
nodes.forEach((node, index) => {
|
|
550
|
-
const name = typeof node?.name === 'string'
|
|
551
|
-
? node.name
|
|
552
|
-
: '';
|
|
553
|
-
if (name && counts.get(name) === 1)
|
|
554
|
-
result.set(name, index);
|
|
555
|
-
});
|
|
556
|
-
return result;
|
|
557
|
-
}
|
|
558
|
-
function gltfRootScenes(gltf) {
|
|
559
|
-
const root = gltf;
|
|
560
|
-
const scenes = Array.isArray(root?.scenes) ? root.scenes : [];
|
|
561
|
-
const result = scenes.filter(isTraversableObject);
|
|
562
|
-
if (isTraversableObject(root?.scene) && !result.includes(root.scene)) {
|
|
563
|
-
result.push(root.scene);
|
|
564
|
-
}
|
|
565
|
-
return result;
|
|
566
|
-
}
|
|
567
|
-
function isTraversableObject(value) {
|
|
568
|
-
return !!value && typeof value === 'object' && typeof value.traverse === 'function';
|
|
569
|
-
}
|
|
570
|
-
function normalizeEmbeddedGlbImages(data) {
|
|
571
|
-
if (typeof data === 'string') {
|
|
572
|
-
validateGltfTextImageReferences(data);
|
|
573
|
-
return data;
|
|
574
|
-
}
|
|
575
|
-
const bytes = Buffer.from(data);
|
|
576
|
-
const normalized = rewriteGlbBufferViewImages(bytes);
|
|
577
|
-
if (!normalized) {
|
|
578
|
-
validateGltfTextImageReferences(bytes);
|
|
579
|
-
}
|
|
580
|
-
return normalized ? arrayBufferView(normalized) : data;
|
|
581
|
-
}
|
|
582
|
-
function rewriteGlbBufferViewImages(bytes) {
|
|
583
|
-
if (bytes.byteLength < 20 || bytes.readUInt32LE(0) !== 0x46546c67 || bytes.readUInt32LE(4) !== 2) {
|
|
584
|
-
return null;
|
|
585
|
-
}
|
|
586
|
-
let offset = 12;
|
|
587
|
-
let jsonChunk = null;
|
|
588
|
-
let binChunk = null;
|
|
589
|
-
while (offset + 8 <= bytes.byteLength) {
|
|
590
|
-
const chunkLength = bytes.readUInt32LE(offset);
|
|
591
|
-
const chunkType = bytes.readUInt32LE(offset + 4);
|
|
592
|
-
const chunkStart = offset + 8;
|
|
593
|
-
const chunkEnd = chunkStart + chunkLength;
|
|
594
|
-
if (chunkEnd > bytes.byteLength)
|
|
595
|
-
return null;
|
|
596
|
-
const chunk = bytes.subarray(chunkStart, chunkEnd);
|
|
597
|
-
if (chunkType === 0x4e4f534a) {
|
|
598
|
-
jsonChunk = chunk;
|
|
599
|
-
}
|
|
600
|
-
else if (chunkType === 0x004e4942 && binChunk === null) {
|
|
601
|
-
binChunk = chunk;
|
|
602
|
-
}
|
|
603
|
-
offset = chunkEnd;
|
|
604
|
-
}
|
|
605
|
-
if (!jsonChunk || !binChunk)
|
|
606
|
-
return null;
|
|
607
|
-
let json;
|
|
608
|
-
try {
|
|
609
|
-
json = JSON.parse(jsonChunk.toString('utf8').trimEnd());
|
|
610
|
-
}
|
|
611
|
-
catch {
|
|
612
|
-
return null;
|
|
613
|
-
}
|
|
614
|
-
let changed = false;
|
|
615
|
-
for (const image of gltfImages(json, 'GLB')) {
|
|
616
|
-
validateGltfImageUri(image);
|
|
617
|
-
if (!image || !Number.isInteger(image.bufferView))
|
|
618
|
-
continue;
|
|
619
|
-
if (typeof image.mimeType !== 'string') {
|
|
620
|
-
throw new Error('GLB bufferView image is missing mimeType. Embedded GLB images must declare PNG, JPEG, or WebP mimeType values.');
|
|
621
|
-
}
|
|
622
|
-
validateSupportedEmbeddedImageType('GLB bufferView image', image.mimeType);
|
|
623
|
-
const imageBytes = glbBufferViewBytes(json, binChunk, image.bufferView);
|
|
624
|
-
if (!imageBytes)
|
|
625
|
-
continue;
|
|
626
|
-
image.uri = `data:${image.mimeType};base64,${imageBytes.toString('base64')}`;
|
|
627
|
-
delete image.bufferView;
|
|
628
|
-
changed = true;
|
|
629
|
-
}
|
|
630
|
-
return changed ? encodeGlb(json, binChunk) : null;
|
|
631
|
-
}
|
|
632
|
-
function validateGltfTextImageReferences(data) {
|
|
633
|
-
const text = typeof data === 'string' ? data : data.toString('utf8');
|
|
634
|
-
if (!text.trimStart().startsWith('{'))
|
|
635
|
-
return;
|
|
636
|
-
let json;
|
|
637
|
-
try {
|
|
638
|
-
json = JSON.parse(text);
|
|
639
|
-
}
|
|
640
|
-
catch {
|
|
641
|
-
return;
|
|
642
|
-
}
|
|
643
|
-
for (const image of gltfImages(json, 'glTF')) {
|
|
644
|
-
validateGltfImageUri(image);
|
|
645
|
-
if (image && Number.isInteger(image.bufferView)) {
|
|
646
|
-
if (typeof image.mimeType !== 'string') {
|
|
647
|
-
throw new Error('glTF bufferView image is missing mimeType. Embedded glTF images must declare PNG, JPEG, or WebP mimeType values.');
|
|
648
|
-
}
|
|
649
|
-
validateSupportedEmbeddedImageType('glTF bufferView image', image.mimeType);
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
function gltfImages(json, label) {
|
|
654
|
-
const images = json.images;
|
|
655
|
-
if (images == null)
|
|
656
|
-
return [];
|
|
657
|
-
if (!Array.isArray(images)) {
|
|
658
|
-
throw new Error(`${label}.images must be an array.`);
|
|
659
|
-
}
|
|
660
|
-
for (let i = 0; i < images.length; i += 1) {
|
|
661
|
-
const image = images[i];
|
|
662
|
-
if (!image || typeof image !== 'object' || Array.isArray(image)) {
|
|
663
|
-
throw new Error(`${label}.images[${i}] must be an object.`);
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
return images;
|
|
667
|
-
}
|
|
668
|
-
function validateGltfImageUri(image) {
|
|
669
|
-
const uri = typeof image?.uri === 'string' ? image.uri : null;
|
|
670
|
-
if (!uri)
|
|
671
|
-
return;
|
|
672
|
-
const mimeType = imageMimeTypeFromUri(uri);
|
|
673
|
-
if (mimeType) {
|
|
674
|
-
validateSupportedEmbeddedImageType('glTF image URI', mimeType);
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
function imageMimeTypeFromUri(uri) {
|
|
678
|
-
const dataUriMatch = uri.match(/^data:([^;,]+)/i);
|
|
679
|
-
if (dataUriMatch)
|
|
680
|
-
return dataUriMatch[1].toLowerCase();
|
|
681
|
-
if (/\.ktx2(?:$|[?#])/i.test(uri))
|
|
682
|
-
return 'image/ktx2';
|
|
683
|
-
if (/\.basis(?:$|[?#])/i.test(uri))
|
|
684
|
-
return 'image/basis';
|
|
685
|
-
return null;
|
|
686
|
-
}
|
|
687
|
-
function validateSupportedEmbeddedImageType(label, mimeType) {
|
|
688
|
-
if (!/^image\/(?:png|jpe?g|webp)$/i.test(mimeType)) {
|
|
689
|
-
throw unsupportedEmbeddedImageTypeError(label, mimeType);
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
function unsupportedEmbeddedImageTypeError(label, mimeType) {
|
|
693
|
-
if (/(?:ktx2|basis|compressed)/i.test(mimeType)) {
|
|
694
|
-
return new Error(`${label} uses compressed texture MIME type "${mimeType}". KTX2, Basis, and compressed texture inputs are not decoded by @headless-three/renderer yet; pre-decode the texture to RGBA data or an encoded PNG/JPEG/WebP image before loading.`);
|
|
695
|
-
}
|
|
696
|
-
return new Error(`${label} uses unsupported MIME type "${mimeType}". Embedded GLB images must be PNG, JPEG, or WebP encoded images.`);
|
|
697
|
-
}
|
|
698
|
-
function glbBufferViewBytes(json, binChunk, index) {
|
|
699
|
-
const bufferView = json.bufferViews?.[index];
|
|
700
|
-
if (!bufferView || bufferView.buffer !== 0 || !Number.isFinite(bufferView.byteLength)) {
|
|
701
|
-
return null;
|
|
702
|
-
}
|
|
703
|
-
const byteOffset = bufferView.byteOffset == null ? 0 : bufferView.byteOffset;
|
|
704
|
-
if (!Number.isFinite(byteOffset))
|
|
705
|
-
return null;
|
|
706
|
-
const start = Math.trunc(byteOffset);
|
|
707
|
-
const end = start + Math.trunc(bufferView.byteLength);
|
|
708
|
-
if (start < 0 || end < start || end > binChunk.byteLength)
|
|
709
|
-
return null;
|
|
710
|
-
return binChunk.subarray(start, end);
|
|
711
|
-
}
|
|
712
|
-
function encodeGlb(json, binChunk) {
|
|
713
|
-
const jsonBytes = paddedChunk(Buffer.from(JSON.stringify(json), 'utf8'), 0x20);
|
|
714
|
-
const binBytes = paddedChunk(binChunk, 0x00);
|
|
715
|
-
const totalLength = 12 + 8 + jsonBytes.length + 8 + binBytes.length;
|
|
716
|
-
const glb = Buffer.alloc(totalLength);
|
|
717
|
-
let offset = 0;
|
|
718
|
-
offset = writeGlbUint32(glb, offset, 0x46546c67);
|
|
719
|
-
offset = writeGlbUint32(glb, offset, 2);
|
|
720
|
-
offset = writeGlbUint32(glb, offset, totalLength);
|
|
721
|
-
offset = writeGlbUint32(glb, offset, jsonBytes.length);
|
|
722
|
-
offset = writeGlbUint32(glb, offset, 0x4e4f534a);
|
|
723
|
-
jsonBytes.copy(glb, offset);
|
|
724
|
-
offset += jsonBytes.length;
|
|
725
|
-
offset = writeGlbUint32(glb, offset, binBytes.length);
|
|
726
|
-
offset = writeGlbUint32(glb, offset, 0x004e4942);
|
|
727
|
-
binBytes.copy(glb, offset);
|
|
728
|
-
return glb;
|
|
729
|
-
}
|
|
730
|
-
function paddedChunk(buffer, fill) {
|
|
731
|
-
const padded = Buffer.alloc((buffer.length + 3) & ~3, fill);
|
|
732
|
-
buffer.copy(padded);
|
|
733
|
-
return padded;
|
|
734
|
-
}
|
|
735
|
-
function writeGlbUint32(buffer, offset, value) {
|
|
736
|
-
buffer.writeUInt32LE(value, offset);
|
|
737
|
-
return offset + 4;
|
|
738
|
-
}
|
|
739
|
-
function optionalBoolean(value, label) {
|
|
740
|
-
if (value == null)
|
|
741
|
-
return undefined;
|
|
742
|
-
if (typeof value === 'boolean')
|
|
743
|
-
return value;
|
|
744
|
-
throw new TypeError(`${label} must be a boolean.`);
|
|
745
|
-
}
|
|
746
|
-
function optionalNonNegativeNumber(value, label) {
|
|
747
|
-
if (value == null)
|
|
748
|
-
return undefined;
|
|
749
|
-
if (typeof value === 'number' && Number.isFinite(value) && value >= 0)
|
|
750
|
-
return value;
|
|
751
|
-
throw new TypeError(`${label} must be a finite non-negative number.`);
|
|
752
|
-
}
|
|
753
|
-
function optionalNonNegativeInteger(value, label) {
|
|
754
|
-
if (value == null)
|
|
755
|
-
return undefined;
|
|
756
|
-
if (typeof value === 'number' && Number.isInteger(value) && value >= 0)
|
|
757
|
-
return value;
|
|
758
|
-
throw new TypeError(`${label} must be a non-negative integer.`);
|
|
759
|
-
}
|
|
760
|
-
function validateNodeGltfLoaderOptions(options) {
|
|
761
|
-
return {
|
|
762
|
-
configureLoader: optionalFunction(options.configureLoader, 'options.configureLoader'),
|
|
763
|
-
installFetch: optionalBoolean(options.installFetch, 'options.installFetch'),
|
|
764
|
-
manager: optionalLoadingManager(options.manager, 'options.manager'),
|
|
765
|
-
registerTextureHandlers: optionalBoolean(options.registerTextureHandlers, 'options.registerTextureHandlers'),
|
|
766
|
-
};
|
|
767
|
-
}
|
|
768
|
-
function validateLoadGltfFromFileOptions(options) {
|
|
769
|
-
validateNodeGltfLoaderOptions(options);
|
|
770
|
-
optionalString(options.rootDir, 'options.rootDir');
|
|
771
|
-
optionalString(options.baseUrl, 'options.baseUrl');
|
|
772
|
-
}
|
|
773
|
-
function requiredString(value, label) {
|
|
774
|
-
if (typeof value === 'string')
|
|
775
|
-
return value;
|
|
776
|
-
throw new TypeError(`${label} must be a string.`);
|
|
777
|
-
}
|
|
778
|
-
function optionalString(value, label) {
|
|
779
|
-
if (value == null)
|
|
780
|
-
return undefined;
|
|
781
|
-
return requiredString(value, label);
|
|
782
|
-
}
|
|
783
|
-
function objectOptions(value, label) {
|
|
784
|
-
if (value != null && typeof value === 'object' && !Array.isArray(value)) {
|
|
785
|
-
return value;
|
|
786
|
-
}
|
|
787
|
-
throw new TypeError(`${label} must be an object.`);
|
|
788
|
-
}
|
|
789
|
-
function optionalFunction(value, label) {
|
|
790
|
-
if (value == null)
|
|
791
|
-
return undefined;
|
|
792
|
-
if (typeof value === 'function')
|
|
793
|
-
return value;
|
|
794
|
-
throw new TypeError(`${label} must be a function.`);
|
|
795
|
-
}
|
|
796
|
-
function optionalLoadingManager(value, label) {
|
|
797
|
-
if (value == null)
|
|
798
|
-
return undefined;
|
|
799
|
-
if (typeof value.addHandler !== 'function') {
|
|
800
|
-
throw new TypeError(`${label} must provide an addHandler() function.`);
|
|
801
|
-
}
|
|
802
|
-
for (const method of ['itemStart', 'itemEnd', 'itemError', 'resolveURL']) {
|
|
803
|
-
if (value[method] != null && typeof value[method] !== 'function') {
|
|
804
|
-
throw new TypeError(`${label}.${method} must be a function when provided.`);
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
return value;
|
|
808
|
-
}
|
|
809
|
-
function registerLoaderPlugin(loader, callback, label) {
|
|
810
|
-
if (typeof loader.register !== 'function') {
|
|
811
|
-
throw new Error(`GLTFLoader.register is required to install ${label}.`);
|
|
812
|
-
}
|
|
813
|
-
loader.register(callback);
|
|
814
|
-
}
|
|
815
|
-
const dynamicImport = new Function('specifier', 'return import(specifier)');
|
|
816
|
-
function importGltfLoader() {
|
|
817
|
-
return dynamicImport('three/examples/jsm/loaders/GLTFLoader.js');
|
|
818
|
-
}
|
|
819
|
-
async function importVrmLoaderPlugin() {
|
|
820
|
-
let module;
|
|
821
|
-
try {
|
|
822
|
-
module = await dynamicImport('@pixiv/three-vrm');
|
|
823
|
-
}
|
|
824
|
-
catch {
|
|
825
|
-
throw new Error('Missing optional dependency @pixiv/three-vrm. Install it in your project or pass VRMLoaderPlugin to loadVrmFromFile().');
|
|
826
|
-
}
|
|
827
|
-
if (typeof module.VRMLoaderPlugin !== 'function') {
|
|
828
|
-
throw new Error('@pixiv/three-vrm did not export VRMLoaderPlugin.');
|
|
829
|
-
}
|
|
830
|
-
return module.VRMLoaderPlugin;
|
|
831
|
-
}
|
|
832
|
-
async function importVrmAnimationLoaderPlugin() {
|
|
833
|
-
let module;
|
|
834
|
-
try {
|
|
835
|
-
module = await dynamicImport('@pixiv/three-vrm-animation');
|
|
836
|
-
}
|
|
837
|
-
catch {
|
|
838
|
-
throw new Error('Missing optional dependency @pixiv/three-vrm-animation. Install it in your project or pass VRMAnimationLoaderPlugin to loadVrmAnimationFromFile().');
|
|
839
|
-
}
|
|
840
|
-
if (typeof module.VRMAnimationLoaderPlugin !== 'function') {
|
|
841
|
-
throw new Error('@pixiv/three-vrm-animation did not export VRMAnimationLoaderPlugin.');
|
|
842
|
-
}
|
|
843
|
-
return module.VRMAnimationLoaderPlugin;
|
|
844
|
-
}
|
|
845
|
-
async function importVrmAnimationClipFactory() {
|
|
846
|
-
let module;
|
|
847
|
-
try {
|
|
848
|
-
module = await dynamicImport('@pixiv/three-vrm-animation');
|
|
849
|
-
}
|
|
850
|
-
catch {
|
|
851
|
-
throw new Error('Missing optional dependency @pixiv/three-vrm-animation. Install it in your project or pass createVRMAnimationClip to applyVrmAnimation().');
|
|
852
|
-
}
|
|
853
|
-
if (typeof module.createVRMAnimationClip !== 'function') {
|
|
854
|
-
throw new Error('@pixiv/three-vrm-animation did not export createVRMAnimationClip.');
|
|
855
|
-
}
|
|
856
|
-
return module.createVRMAnimationClip;
|
|
857
|
-
}
|
|
3
|
+
exports.installLocalFileFetch = exports.resolveLocalAssetPath = exports.applyVrmAnimation = exports.loadVrmAnimationFromFile = exports.loadVrmFromFile = exports.loadGltfFromFile = exports.createNodeGltfLoader = exports.createEncodedImageTextureLoader = exports.EncodedImageTextureLoader = void 0;
|
|
4
|
+
require("./loaders.part-001");
|
|
5
|
+
require("./loaders.part-002");
|
|
6
|
+
require("./loaders.part-003");
|
|
7
|
+
var loaders_part_001_1 = require("./loaders.part-001");
|
|
8
|
+
Object.defineProperty(exports, "EncodedImageTextureLoader", { enumerable: true, get: function () { return loaders_part_001_1.EncodedImageTextureLoader; } });
|
|
9
|
+
var loaders_part_001_2 = require("./loaders.part-001");
|
|
10
|
+
Object.defineProperty(exports, "createEncodedImageTextureLoader", { enumerable: true, get: function () { return loaders_part_001_2.createEncodedImageTextureLoader; } });
|
|
11
|
+
var loaders_part_001_3 = require("./loaders.part-001");
|
|
12
|
+
Object.defineProperty(exports, "createNodeGltfLoader", { enumerable: true, get: function () { return loaders_part_001_3.createNodeGltfLoader; } });
|
|
13
|
+
var loaders_part_001_4 = require("./loaders.part-001");
|
|
14
|
+
Object.defineProperty(exports, "loadGltfFromFile", { enumerable: true, get: function () { return loaders_part_001_4.loadGltfFromFile; } });
|
|
15
|
+
var loaders_part_001_5 = require("./loaders.part-001");
|
|
16
|
+
Object.defineProperty(exports, "loadVrmFromFile", { enumerable: true, get: function () { return loaders_part_001_5.loadVrmFromFile; } });
|
|
17
|
+
var loaders_part_001_6 = require("./loaders.part-001");
|
|
18
|
+
Object.defineProperty(exports, "loadVrmAnimationFromFile", { enumerable: true, get: function () { return loaders_part_001_6.loadVrmAnimationFromFile; } });
|
|
19
|
+
var loaders_part_001_7 = require("./loaders.part-001");
|
|
20
|
+
Object.defineProperty(exports, "applyVrmAnimation", { enumerable: true, get: function () { return loaders_part_001_7.applyVrmAnimation; } });
|
|
21
|
+
var loaders_part_002_1 = require("./loaders.part-002");
|
|
22
|
+
Object.defineProperty(exports, "resolveLocalAssetPath", { enumerable: true, get: function () { return loaders_part_002_1.resolveLocalAssetPath; } });
|
|
23
|
+
var loaders_part_002_2 = require("./loaders.part-002");
|
|
24
|
+
Object.defineProperty(exports, "installLocalFileFetch", { enumerable: true, get: function () { return loaders_part_002_2.installLocalFileFetch; } });
|
|
858
25
|
//# sourceMappingURL=loaders.js.map
|