@combos-fun/plugin-renderer-3d-model 0.0.38 → 0.0.40

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/agent-skill.md CHANGED
@@ -1,26 +1,29 @@
1
1
  # `@combos-fun/plugin-renderer-3d-model` — Agent notes
2
2
 
3
- GLB / GLTF 3D model loader and animator. Loads via `ThreeContext.loadGLB()` (GLTFLoader) and drives included animations through Three.js `AnimationMixer`.
3
+ Loads a named 3D model through the engine resource system and drives included animations with Three.js `AnimationMixer`. `resource` is an engine **name**, never a URL.
4
+
5
+ Formats: `.glb` / `.gltf` (Draco, KTX2, meshopt), `.fbx`, `.obj` (+ optional `src.mtl`), `.stl`, `.dae`, `.ply`. Prefer `.glb` when you control the export. DCC sources (`.blend` / `.max` / `.c4d` / `.ma`) are not runtime-loadable.
4
6
 
5
7
  ## When to read
6
8
 
7
- Read for any 3D character / prop / scenery model: loading GLB / GLTF files, choosing animation clips, scrubbing animation speed.
9
+ Read for any 3D character / prop / scenery model: registering a model resource, choosing animation clips, scrubbing animation speed.
8
10
 
9
11
  ## Public API
10
12
 
11
13
  ```ts
12
14
  import { Model3D, Model3DSystem, type Model3DParams } from '@combos-fun/plugin-renderer-3d-model';
15
+ import { resource, RESOURCE_TYPE } from '@combos-fun/engine';
13
16
  ```
14
17
 
15
- `componentName = 'Model3D'`, `systemName = 'Model3DSystem'`. Currently only loads `.glb` / `.gltf` (Three.js `GLTFLoader`); other formats (FBX/OBJ/STL/DAE) are not supported.
18
+ `componentName = 'Model3D'`, `systemName = 'Model3DSystem'`. Importing this package registers `RESOURCE_TYPE.MODEL` (and the `GLB` alias) instance factories.
16
19
 
17
20
  ### `Model3DParams`
18
21
 
19
22
  | Field | Type | Default | Notes |
20
23
  |-------|------|---------|-------|
21
- | `resource` | `string` | `''` | GLB / GLTF URL (direct, not engine resource name) |
24
+ | `resource` | `string` | `''` | Engine resource name (`RESOURCE_TYPE.MODEL`). Missing name throws; URLs are not accepted. |
22
25
  | `autoPlay` | `boolean` | `true` | |
23
- | `animationIndex` | `number` | `0` | Index into the GLB's `animations` array |
26
+ | `animationIndex` | `number` | `0` | Index into the model's `animations` array |
24
27
  | `speed` | `number` | `1` | `AnimationMixer.timeScale` |
25
28
  | `positionX` / `Y` / `Z` | `number` | `0` |
26
29
  | `rotationX` / `Y` / `Z` | `number` | `0` |
@@ -28,35 +31,58 @@ import { Model3D, Model3DSystem, type Model3DParams } from '@combos-fun/plugin-r
28
31
 
29
32
  Changing `animationIndex` or `speed` restarts the animation cleanly.
30
33
 
34
+ ### Resource registration
35
+
36
+ ```ts
37
+ resource.addResource([
38
+ {
39
+ name: 'hero',
40
+ type: RESOURCE_TYPE.MODEL,
41
+ src: { model: { type: 'glb', url: 'https://cdn.example/hero.glb' } },
42
+ preload: true,
43
+ },
44
+ {
45
+ name: 'crate',
46
+ type: RESOURCE_TYPE.MODEL,
47
+ src: {
48
+ model: { type: 'obj', url: 'https://cdn.example/crate.obj' },
49
+ mtl: { type: 'mtl', url: 'https://cdn.example/crate.mtl' },
50
+ },
51
+ preload: true,
52
+ },
53
+ ]);
54
+ ```
55
+
56
+ CDN / http URLs belong in `src`, not on `Model3D.resource`. Sidecar files (gltf `.bin` / images, obj `.mtl`) should share the same directory as the main file, or be listed as extra `src` slots (`mtl`, `bin`).
57
+
31
58
  ## Required setup
32
59
 
33
- `Renderer3DSystem` then `Model3DSystem`. URL must be CORS-accessible and return valid binary GLB / JSON GLTF.
60
+ `Renderer3DSystem` then `Model3DSystem`. Gate `new Game(...)` on `resource.once(LOAD_EVENT.COMPLETE, ...)`.
34
61
 
35
62
  ## Runtime behaviour
36
63
 
37
- - Loading is async. While the GLB is loading, the GameObject has no
38
- visible mesh.
39
- - The system uses `increaseAsyncId` / `validateAsyncId` to drop stale
40
- loads if the component is removed mid-fetch.
41
- - The `AnimationMixer` is owned by the system; switching
42
- `animationIndex` calls `mixer.stopAllAction()` then plays the new clip.
64
+ - Loading is async. While the model is parsing, the GameObject has no visible mesh.
65
+ - The system uses `increaseAsyncId` / `validateAsyncId` to drop stale loads if the component is removed mid-fetch.
66
+ - Each GameObject gets a cloned scene (`SkeletonUtils.clone`) so two heroes can share one resource.
67
+ - The `AnimationMixer` is owned by `ThreeContext`; switching `animationIndex` calls `mixer.stopAllAction()` then plays the new clip.
43
68
 
44
69
  ## Common pitfalls
45
70
 
46
71
  | Symptom | Fix |
47
72
  |---------|-----|
73
+ | `Unknown resource` throw | Register the name with `resource.addResource` + `RESOURCE_TYPE.MODEL`; do not pass a URL to `Model3D.resource` |
48
74
  | Model not visible | Loaded at origin; adjust `position*` or check camera distance (camera is at z=5 by default) |
49
75
  | Wrong scale | Use `scaleX` / `Y` / `Z`; many GLBs export at meter scale |
50
- | Animation doesn't play | `autoPlay: true` is the default — check `animationIndex` is within `animations.length` |
51
- | Slow / stuttery animation | Lower-end GPU; reduce model polygon count or set `speed < 1` |
52
- | 404 / CORS | Verify URL returns valid GLB binary; check network tab |
76
+ | Animation doesn't play | `autoPlay: true` is the default — check `animationIndex` is within `animations.length` (OBJ/STL/PLY have none) |
77
+ | Draco / KTX2 glTF fails | Decoder WASM is fetched from Google Draco / unpkg three `basis/` — the page must allow that network |
78
+ | 404 / CORS | Verify `src.model.url` returns the file; check network tab |
53
79
 
54
80
  ## Minimal example
55
81
 
56
82
  ```ts
57
83
  const hero = new GameObject('hero');
58
84
  hero.addComponent(new Model3D({
59
- resource: '/assets/hero.glb',
85
+ resource: 'hero',
60
86
  autoPlay: true,
61
87
  animationIndex: 0,
62
88
  speed: 1,
@@ -4,7 +4,7 @@
4
4
  "category": "rendering",
5
5
  "dimension": "3d",
6
6
  "isCore": false,
7
- "keywords": ["3d", "model", "glb", "gltf", "animation", "mesh"],
7
+ "keywords": ["3d", "model", "glb", "gltf", "fbx", "obj", "stl", "dae", "ply", "animation", "mesh"],
8
8
  "agentSkill": "./agent-skill.md",
9
9
  "requires": ["@combos-fun/engine", "@combos-fun/plugin-renderer-3d"],
10
10
  "exports": ["Model3D", "Model3DSystem"]
@@ -4,6 +4,18 @@ var tslib = require('tslib');
4
4
  var engine = require('@combos-fun/engine');
5
5
  var inspectorDecorator = require('@combos-fun/inspector-decorator');
6
6
  var pluginRenderer3d = require('@combos-fun/plugin-renderer-3d');
7
+ var SkeletonUtils_js = require('three/addons/utils/SkeletonUtils.js');
8
+ var three = require('three');
9
+ var GLTFLoader_js = require('three/addons/loaders/GLTFLoader.js');
10
+ var DRACOLoader_js = require('three/addons/loaders/DRACOLoader.js');
11
+ var KTX2Loader_js = require('three/addons/loaders/KTX2Loader.js');
12
+ var FBXLoader_js = require('three/addons/loaders/FBXLoader.js');
13
+ var OBJLoader_js = require('three/addons/loaders/OBJLoader.js');
14
+ var MTLLoader_js = require('three/addons/loaders/MTLLoader.js');
15
+ var STLLoader_js = require('three/addons/loaders/STLLoader.js');
16
+ var ColladaLoader_js = require('three/addons/loaders/ColladaLoader.js');
17
+ var PLYLoader_js = require('three/addons/loaders/PLYLoader.js');
18
+ var meshopt_decoder_module_js = require('three/addons/libs/meshopt_decoder.module.js');
7
19
 
8
20
  class Model3D extends engine.Component {
9
21
  constructor() {
@@ -33,7 +45,7 @@ tslib.__decorate([
33
45
  type: 'string',
34
46
  group: 'Model3D',
35
47
  label: 'resource',
36
- description: 'Resource id from the asset registry.',
48
+ description: 'Engine resource name registered with RESOURCE_TYPE.MODEL.',
37
49
  editor: 'text',
38
50
  })
39
51
  ], Model3D.prototype, "resource", void 0);
@@ -156,6 +168,163 @@ tslib.__decorate([
156
168
  })
157
169
  ], Model3D.prototype, "scaleZ", void 0);
158
170
 
171
+ const THREE_ADDON_CDN = 'https://unpkg.com/three@0.172.0/examples/jsm/libs';
172
+ const DRACO_DECODER_PATH = 'https://www.gstatic.com/draco/versioned/decoders/1.5.7/';
173
+ const BASIS_TRANSCODER_PATH = `${THREE_ADDON_CDN}/basis/`;
174
+ let sharedDraco = null;
175
+ let sharedKtx2 = null;
176
+ let ktx2DetectedFor = null;
177
+ function dirOf(url) {
178
+ const clean = String(url || '').split('?')[0].split('#')[0];
179
+ const slash = clean.lastIndexOf('/');
180
+ return slash >= 0 ? clean.slice(0, slash + 1) : '';
181
+ }
182
+ function asText(data) {
183
+ if (typeof data === 'string')
184
+ return data;
185
+ if (data instanceof ArrayBuffer)
186
+ return new TextDecoder().decode(data);
187
+ if (ArrayBuffer.isView(data)) {
188
+ return new TextDecoder().decode(data);
189
+ }
190
+ if (data && typeof data === 'object')
191
+ return JSON.stringify(data);
192
+ throw new Error('expected text payload for this model format');
193
+ }
194
+ function asBuffer(data) {
195
+ if (data instanceof ArrayBuffer)
196
+ return data;
197
+ if (ArrayBuffer.isView(data)) {
198
+ const view = data;
199
+ return view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength);
200
+ }
201
+ throw new Error('expected binary payload for this model format');
202
+ }
203
+ function wrapGroup(object, animations = []) {
204
+ if (object instanceof three.Group) {
205
+ return { scene: object, animations };
206
+ }
207
+ const scene = new three.Group();
208
+ scene.add(object);
209
+ return { scene, animations };
210
+ }
211
+ function geometryToModel(geometry) {
212
+ geometry.computeVertexNormals?.();
213
+ const mesh = new three.Mesh(geometry, new three.MeshStandardMaterial({ color: 0x888888, metalness: 0.1, roughness: 0.8 }));
214
+ const scene = new three.Group();
215
+ scene.add(mesh);
216
+ return { scene, animations: [] };
217
+ }
218
+ function modelPayload(res) {
219
+ const slot = res.src?.model || res.src?.glb || res.src?.gltf;
220
+ const data = res.data?.model ?? res.data?.glb ?? res.data?.gltf;
221
+ if (data == null) {
222
+ throw new Error(`Resource "${res.name}" has no model data; use RESOURCE_TYPE.MODEL with src.model.url`);
223
+ }
224
+ const type = String(slot?.type || 'glb').toLowerCase();
225
+ return { data, type, path: dirOf(slot?.url || '') };
226
+ }
227
+ function ensureGltfExtras(loader, renderer) {
228
+ if (!sharedDraco) {
229
+ sharedDraco = new DRACOLoader_js.DRACOLoader();
230
+ sharedDraco.setDecoderPath(DRACO_DECODER_PATH);
231
+ }
232
+ loader.setDRACOLoader(sharedDraco);
233
+ if (!sharedKtx2) {
234
+ sharedKtx2 = new KTX2Loader_js.KTX2Loader();
235
+ sharedKtx2.setTranscoderPath(BASIS_TRANSCODER_PATH);
236
+ }
237
+ if (renderer && ktx2DetectedFor !== renderer) {
238
+ sharedKtx2.detectSupport(renderer);
239
+ ktx2DetectedFor = renderer;
240
+ }
241
+ loader.setKTX2Loader(sharedKtx2);
242
+ loader.setMeshoptDecoder(meshopt_decoder_module_js.MeshoptDecoder);
243
+ }
244
+ function parseGltf(data, path, renderer) {
245
+ const loader = new GLTFLoader_js.GLTFLoader();
246
+ ensureGltfExtras(loader, renderer);
247
+ const payload = typeof data === 'object' && data && !(data instanceof ArrayBuffer) && !ArrayBuffer.isView(data)
248
+ ? JSON.stringify(data)
249
+ : data instanceof ArrayBuffer || ArrayBuffer.isView(data)
250
+ ? asBuffer(data)
251
+ : asText(data);
252
+ return new Promise((resolve, reject) => {
253
+ loader.parse(payload, path, (gltf) => {
254
+ resolve(wrapGroup(gltf.scene, gltf.animations || []));
255
+ }, (err) => {
256
+ reject(err instanceof Error ? err : new Error(String(err)));
257
+ });
258
+ });
259
+ }
260
+ async function parseFbx(data, path) {
261
+ const loader = new FBXLoader_js.FBXLoader();
262
+ const object = loader.parse(asBuffer(data), path);
263
+ const animations = (object.animations || []);
264
+ return wrapGroup(object, animations);
265
+ }
266
+ async function parseObj(res, data, path) {
267
+ const objLoader = new OBJLoader_js.OBJLoader();
268
+ const mtlText = res.data?.mtl;
269
+ if (mtlText != null) {
270
+ const mtlLoader = new MTLLoader_js.MTLLoader();
271
+ const mtlPath = dirOf(res.src?.mtl?.url || '') || path;
272
+ const materials = mtlLoader.parse(asText(mtlText), mtlPath);
273
+ materials.preload();
274
+ objLoader.setMaterials(materials);
275
+ }
276
+ return wrapGroup(objLoader.parse(asText(data)));
277
+ }
278
+ async function parseCollada(data, path) {
279
+ const loader = new ColladaLoader_js.ColladaLoader();
280
+ const result = loader.parse(asText(data), path);
281
+ return wrapGroup(result.scene, result.animations || []);
282
+ }
283
+ async function parseModelResource(res, renderer) {
284
+ const { data, type, path } = modelPayload(res);
285
+ switch (type) {
286
+ case 'glb':
287
+ case 'gltf':
288
+ return parseGltf(data, path, renderer);
289
+ case 'fbx':
290
+ return parseFbx(data, path);
291
+ case 'obj':
292
+ return parseObj(res, data, path);
293
+ case 'stl':
294
+ return geometryToModel(new STLLoader_js.STLLoader().parse(asBuffer(data)));
295
+ case 'ply':
296
+ return geometryToModel(new PLYLoader_js.PLYLoader().parse(asBuffer(data)));
297
+ case 'dae':
298
+ case 'collada':
299
+ return parseCollada(data, path);
300
+ default:
301
+ throw new Error(`Unsupported 3D model type "${type}" for resource "${res.name}". ` +
302
+ 'Use glb, gltf, fbx, obj, stl, dae, or ply.');
303
+ }
304
+ }
305
+ function createModelInstance(res) {
306
+ let cached = null;
307
+ return {
308
+ async parse(renderer) {
309
+ if (!cached) {
310
+ cached = await parseModelResource(res, renderer);
311
+ }
312
+ return cached;
313
+ },
314
+ dispose() {
315
+ cached = null;
316
+ },
317
+ };
318
+ }
319
+ engine.resource.registerInstance(engine.RESOURCE_TYPE.MODEL, (res) => createModelInstance(res));
320
+ engine.resource.registerInstance(engine.RESOURCE_TYPE.GLB, (res) => createModelInstance(res));
321
+ engine.resource.registerDestroy(engine.RESOURCE_TYPE.MODEL, ({ instance }) => {
322
+ instance?.dispose?.();
323
+ });
324
+ engine.resource.registerDestroy(engine.RESOURCE_TYPE.GLB, ({ instance }) => {
325
+ instance?.dispose?.();
326
+ });
327
+
159
328
  let Model3DSystem = class Model3DSystem extends pluginRenderer3d.Renderer3D {
160
329
  constructor() {
161
330
  super(...arguments);
@@ -196,7 +365,7 @@ let Model3DSystem = class Model3DSystem extends pluginRenderer3d.Renderer3D {
196
365
  if (!component.resource)
197
366
  return;
198
367
  const asyncId = this.increaseAsyncId(gameObject.id);
199
- await this.threeContext.loadGLB(gameObject.id, component.resource);
368
+ await this.attachNamedModel(gameObject.id, component.resource);
200
369
  if (!this.validateAsyncId(gameObject.id, asyncId))
201
370
  return;
202
371
  if (component.autoPlay) {
@@ -211,7 +380,7 @@ let Model3DSystem = class Model3DSystem extends pluginRenderer3d.Renderer3D {
211
380
  if (!component.resource)
212
381
  return;
213
382
  const asyncId = this.increaseAsyncId(changed.gameObject.id);
214
- await this.threeContext.loadGLB(changed.gameObject.id, component.resource);
383
+ await this.attachNamedModel(changed.gameObject.id, component.resource);
215
384
  if (!this.validateAsyncId(changed.gameObject.id, asyncId))
216
385
  return;
217
386
  if (component.autoPlay) {
@@ -222,6 +391,16 @@ let Model3DSystem = class Model3DSystem extends pluginRenderer3d.Renderer3D {
222
391
  this.threeContext.playAnimation(changed.gameObject.id, component.animationIndex, component.speed);
223
392
  }
224
393
  }
394
+ async attachNamedModel(id, name) {
395
+ const res = await pluginRenderer3d.requireNamedResource(name);
396
+ const instance = res.instance;
397
+ if (!instance || typeof instance.parse !== 'function') {
398
+ throw new Error(`Resource "${name}" is not a MODEL instance; register RESOURCE_TYPE.MODEL and import Model3DSystem`);
399
+ }
400
+ const parsed = await instance.parse(this.threeContext.renderer);
401
+ const clone = SkeletonUtils_js.clone(parsed.scene);
402
+ this.threeContext.attachParsedModel(id, clone, parsed.animations);
403
+ }
225
404
  };
226
405
  Model3DSystem = tslib.__decorate([
227
406
  engine.decorators.componentObserver({
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-renderer-3d-model.cjs.js","sources":["../lib/component.ts","../lib/system.ts"],"sourcesContent":["import { Component } from '@combos-fun/engine';\nimport { Field } from '@combos-fun/inspector-decorator';\n\nexport interface Model3DParams {\n resource?: string;\n autoPlay?: boolean;\n animationIndex?: number;\n speed?: number;\n positionX?: number;\n positionY?: number;\n positionZ?: number;\n rotationX?: number;\n rotationY?: number;\n rotationZ?: number;\n scaleX?: number;\n scaleY?: number;\n scaleZ?: number;\n}\n\nexport default class Model3D extends Component<Model3DParams> {\n static componentName: string = 'Model3D';\n\n @Field({\n\n type: 'string',\n\n group: 'Model3D',\n\n label: 'resource',\n\n description: 'Resource id from the asset registry.',\n\n editor: 'text',\n\n })\n\n resource: string = '';\n @Field({\n type: 'boolean',\n group: 'Model3D',\n label: 'autoPlay',\n description: 'Start playing automatically when loaded.',\n editor: 'toggle',\n })\n autoPlay: boolean = true;\n @Field({\n type: 'number',\n group: 'Model3D',\n label: 'animationIndex',\n description: 'Animation clip index.',\n editor: 'number-stepper',\n })\n animationIndex: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'speed',\n description: 'Playback speed.',\n editor: 'number-stepper',\n })\n speed: number = 1;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'positionX',\n description: 'Local X position.',\n editor: 'number-stepper',\n })\n positionX: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'positionY',\n description: 'Local Y position.',\n editor: 'number-stepper',\n })\n positionY: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'positionZ',\n description: 'Local Z position.',\n editor: 'number-stepper',\n })\n positionZ: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Model3D',\n label: 'rotationX',\n description: 'Rotation around X in radians.',\n editor: 'number-stepper',\n })\n rotationX: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Model3D',\n label: 'rotationY',\n description: 'Rotation around Y in radians.',\n editor: 'number-stepper',\n })\n rotationY: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Model3D',\n label: 'rotationZ',\n description: 'Rotation around Z in radians.',\n editor: 'number-stepper',\n })\n rotationZ: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'scaleX',\n description: 'Scale on X.',\n editor: 'number-stepper',\n })\n scaleX: number = 1;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'scaleY',\n description: 'Scale on Y.',\n editor: 'number-stepper',\n })\n scaleY: number = 1;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'scaleZ',\n description: 'Scale on Z.',\n editor: 'number-stepper',\n })\n scaleZ: number = 1;\n\n init(obj?: Model3DParams) {\n if (obj) Object.assign(this, obj);\n }\n}\n","import { decorators, ComponentChanged, OBSERVER_TYPE, GameObject } from '@combos-fun/engine';\nimport { Renderer3D, Renderer3DSystem } from '@combos-fun/plugin-renderer-3d';\nimport Model3D from './component';\n\n@decorators.componentObserver({\n Model3D: [\n 'resource',\n 'positionX', 'positionY', 'positionZ',\n 'rotationX', 'rotationY', 'rotationZ',\n 'scaleX', 'scaleY', 'scaleZ',\n 'speed', 'animationIndex',\n ],\n})\nexport default class Model3DSystem extends Renderer3D {\n static systemName = 'Model3DSystem';\n name: string = 'Model3DSystem';\n\n init() {\n const renderer3DSystem = this.game.getSystem(Renderer3DSystem) as Renderer3DSystem;\n renderer3DSystem.rendererManager.register(this);\n }\n\n componentChanged(changed: ComponentChanged) {\n if (changed.componentName !== 'Model3D') return;\n\n const component = changed.component as Model3D;\n\n if (changed.type === OBSERVER_TYPE.ADD) {\n this.handleAdd(changed.gameObject, component);\n } else if (changed.type === OBSERVER_TYPE.CHANGE) {\n this.handleChange(changed);\n } else if (changed.type === OBSERVER_TYPE.REMOVE) {\n this.increaseAsyncId(changed.gameObject.id);\n this.threeContext.removeModel(changed.gameObject.id);\n }\n }\n\n rendererUpdate(gameObject: GameObject) {\n const component = gameObject.getComponent(Model3D) as Model3D;\n if (!component) return;\n\n const model = this.threeContext.models.get(gameObject.id);\n if (!model) return;\n\n model.position.set(component.positionX, component.positionY, component.positionZ);\n model.rotation.set(component.rotationX, component.rotationY, component.rotationZ);\n model.scale.set(component.scaleX, component.scaleY, component.scaleZ);\n }\n\n private async handleAdd(gameObject: GameObject, component: Model3D) {\n if (!component.resource) return;\n\n const asyncId = this.increaseAsyncId(gameObject.id);\n await this.threeContext.loadGLB(gameObject.id, component.resource);\n if (!this.validateAsyncId(gameObject.id, asyncId)) return;\n\n if (component.autoPlay) {\n this.threeContext.playAnimation(\n gameObject.id,\n component.animationIndex,\n component.speed,\n );\n }\n }\n\n private async handleChange(changed: ComponentChanged) {\n const component = changed.component as Model3D;\n const changedProp = changed.prop?.prop?.[0];\n\n if (changedProp === 'resource') {\n this.threeContext.removeModel(changed.gameObject.id);\n if (!component.resource) return;\n\n const asyncId = this.increaseAsyncId(changed.gameObject.id);\n await this.threeContext.loadGLB(changed.gameObject.id, component.resource);\n if (!this.validateAsyncId(changed.gameObject.id, asyncId)) return;\n\n if (component.autoPlay) {\n this.threeContext.playAnimation(\n changed.gameObject.id,\n component.animationIndex,\n component.speed,\n );\n }\n }\n\n if (changedProp === 'speed' || changedProp === 'animationIndex') {\n this.threeContext.playAnimation(\n changed.gameObject.id,\n component.animationIndex,\n component.speed,\n );\n }\n }\n}\n"],"names":["Component","__decorate","Field","Renderer3D","Renderer3DSystem","OBSERVER_TYPE","decorators"],"mappings":"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"}
1
+ {"version":3,"file":"plugin-renderer-3d-model.cjs.js","sources":["../lib/component.ts","../lib/parseModel.ts","../lib/system.ts"],"sourcesContent":["import { Component } from '@combos-fun/engine';\nimport { Field } from '@combos-fun/inspector-decorator';\n\nexport interface Model3DParams {\n resource?: string;\n autoPlay?: boolean;\n animationIndex?: number;\n speed?: number;\n positionX?: number;\n positionY?: number;\n positionZ?: number;\n rotationX?: number;\n rotationY?: number;\n rotationZ?: number;\n scaleX?: number;\n scaleY?: number;\n scaleZ?: number;\n}\n\nexport default class Model3D extends Component<Model3DParams> {\n static componentName: string = 'Model3D';\n\n @Field({\n\n type: 'string',\n\n group: 'Model3D',\n\n label: 'resource',\n\n description: 'Engine resource name registered with RESOURCE_TYPE.MODEL.',\n\n editor: 'text',\n\n })\n\n resource: string = '';\n @Field({\n type: 'boolean',\n group: 'Model3D',\n label: 'autoPlay',\n description: 'Start playing automatically when loaded.',\n editor: 'toggle',\n })\n autoPlay: boolean = true;\n @Field({\n type: 'number',\n group: 'Model3D',\n label: 'animationIndex',\n description: 'Animation clip index.',\n editor: 'number-stepper',\n })\n animationIndex: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'speed',\n description: 'Playback speed.',\n editor: 'number-stepper',\n })\n speed: number = 1;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'positionX',\n description: 'Local X position.',\n editor: 'number-stepper',\n })\n positionX: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'positionY',\n description: 'Local Y position.',\n editor: 'number-stepper',\n })\n positionY: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'positionZ',\n description: 'Local Z position.',\n editor: 'number-stepper',\n })\n positionZ: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Model3D',\n label: 'rotationX',\n description: 'Rotation around X in radians.',\n editor: 'number-stepper',\n })\n rotationX: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Model3D',\n label: 'rotationY',\n description: 'Rotation around Y in radians.',\n editor: 'number-stepper',\n })\n rotationY: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Model3D',\n label: 'rotationZ',\n description: 'Rotation around Z in radians.',\n editor: 'number-stepper',\n })\n rotationZ: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'scaleX',\n description: 'Scale on X.',\n editor: 'number-stepper',\n })\n scaleX: number = 1;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'scaleY',\n description: 'Scale on Y.',\n editor: 'number-stepper',\n })\n scaleY: number = 1;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'scaleZ',\n description: 'Scale on Z.',\n editor: 'number-stepper',\n })\n scaleZ: number = 1;\n\n init(obj?: Model3DParams) {\n if (obj) Object.assign(this, obj);\n }\n}\n","import { resource, RESOURCE_TYPE } from '@combos-fun/engine';\nimport type { ResourceStruct } from '@combos-fun/engine';\nimport {\n AnimationClip,\n BufferGeometry,\n Group,\n Mesh,\n MeshStandardMaterial,\n Object3D,\n} from 'three';\nimport type { WebGLRenderer } from 'three';\nimport { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';\nimport { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';\nimport { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js';\nimport { FBXLoader } from 'three/addons/loaders/FBXLoader.js';\nimport { OBJLoader } from 'three/addons/loaders/OBJLoader.js';\nimport { MTLLoader } from 'three/addons/loaders/MTLLoader.js';\nimport { STLLoader } from 'three/addons/loaders/STLLoader.js';\nimport { ColladaLoader } from 'three/addons/loaders/ColladaLoader.js';\nimport { PLYLoader } from 'three/addons/loaders/PLYLoader.js';\nimport { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js';\n\nexport interface ParsedModel {\n scene: Group;\n animations: AnimationClip[];\n}\n\nexport interface ModelResourceInstance {\n parse(renderer?: WebGLRenderer): Promise<ParsedModel>;\n dispose(): void;\n}\n\nconst THREE_ADDON_CDN = 'https://unpkg.com/three@0.172.0/examples/jsm/libs';\nconst DRACO_DECODER_PATH = 'https://www.gstatic.com/draco/versioned/decoders/1.5.7/';\nconst BASIS_TRANSCODER_PATH = `${THREE_ADDON_CDN}/basis/`;\n\nlet sharedDraco: DRACOLoader | null = null;\nlet sharedKtx2: KTX2Loader | null = null;\nlet ktx2DetectedFor: WebGLRenderer | null = null;\n\nfunction dirOf(url: string): string {\n const clean = String(url || '').split('?')[0].split('#')[0];\n const slash = clean.lastIndexOf('/');\n return slash >= 0 ? clean.slice(0, slash + 1) : '';\n}\n\nfunction asText(data: unknown): string {\n if (typeof data === 'string') return data;\n if (data instanceof ArrayBuffer) return new TextDecoder().decode(data);\n if (ArrayBuffer.isView(data)) {\n return new TextDecoder().decode(data as ArrayBufferView);\n }\n if (data && typeof data === 'object') return JSON.stringify(data);\n throw new Error('expected text payload for this model format');\n}\n\nfunction asBuffer(data: unknown): ArrayBuffer {\n if (data instanceof ArrayBuffer) return data;\n if (ArrayBuffer.isView(data)) {\n const view = data as ArrayBufferView;\n return view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength);\n }\n throw new Error('expected binary payload for this model format');\n}\n\nfunction wrapGroup(object: Object3D, animations: AnimationClip[] = []): ParsedModel {\n if (object instanceof Group) {\n return { scene: object, animations };\n }\n const scene = new Group();\n scene.add(object);\n return { scene, animations };\n}\n\nfunction geometryToModel(geometry: BufferGeometry): ParsedModel {\n geometry.computeVertexNormals?.();\n const mesh = new Mesh(\n geometry,\n new MeshStandardMaterial({ color: 0x888888, metalness: 0.1, roughness: 0.8 }),\n );\n const scene = new Group();\n scene.add(mesh);\n return { scene, animations: [] };\n}\n\nfunction modelPayload(res: ResourceStruct): { data: unknown; type: string; path: string } {\n const slot = res.src?.model || res.src?.glb || res.src?.gltf;\n const data = res.data?.model ?? res.data?.glb ?? res.data?.gltf;\n if (data == null) {\n throw new Error(\n `Resource \"${res.name}\" has no model data; use RESOURCE_TYPE.MODEL with src.model.url`,\n );\n }\n const type = String(slot?.type || 'glb').toLowerCase();\n return { data, type, path: dirOf(slot?.url || '') };\n}\n\nfunction ensureGltfExtras(loader: GLTFLoader, renderer?: WebGLRenderer) {\n if (!sharedDraco) {\n sharedDraco = new DRACOLoader();\n sharedDraco.setDecoderPath(DRACO_DECODER_PATH);\n }\n loader.setDRACOLoader(sharedDraco);\n\n if (!sharedKtx2) {\n sharedKtx2 = new KTX2Loader();\n sharedKtx2.setTranscoderPath(BASIS_TRANSCODER_PATH);\n }\n if (renderer && ktx2DetectedFor !== renderer) {\n sharedKtx2.detectSupport(renderer);\n ktx2DetectedFor = renderer;\n }\n loader.setKTX2Loader(sharedKtx2);\n loader.setMeshoptDecoder(MeshoptDecoder);\n}\n\nfunction parseGltf(\n data: unknown,\n path: string,\n renderer?: WebGLRenderer,\n): Promise<ParsedModel> {\n const loader = new GLTFLoader();\n ensureGltfExtras(loader, renderer);\n const payload =\n typeof data === 'object' && data && !(data instanceof ArrayBuffer) && !ArrayBuffer.isView(data)\n ? JSON.stringify(data)\n : data instanceof ArrayBuffer || ArrayBuffer.isView(data)\n ? asBuffer(data)\n : asText(data);\n\n return new Promise((resolve, reject) => {\n loader.parse(\n payload as ArrayBuffer | string,\n path,\n (gltf) => {\n resolve(wrapGroup(gltf.scene, gltf.animations || []));\n },\n (err) => {\n reject(err instanceof Error ? err : new Error(String(err)));\n },\n );\n });\n}\n\nasync function parseFbx(data: unknown, path: string): Promise<ParsedModel> {\n const loader = new FBXLoader();\n const object = loader.parse(asBuffer(data), path);\n const animations = (object.animations || []) as AnimationClip[];\n return wrapGroup(object, animations);\n}\n\nasync function parseObj(res: ResourceStruct, data: unknown, path: string): Promise<ParsedModel> {\n const objLoader = new OBJLoader();\n const mtlText = res.data?.mtl;\n if (mtlText != null) {\n const mtlLoader = new MTLLoader();\n const mtlPath = dirOf(res.src?.mtl?.url || '') || path;\n const materials = mtlLoader.parse(asText(mtlText), mtlPath);\n materials.preload();\n objLoader.setMaterials(materials);\n }\n return wrapGroup(objLoader.parse(asText(data)));\n}\n\nasync function parseCollada(data: unknown, path: string): Promise<ParsedModel> {\n const loader = new ColladaLoader();\n const result = loader.parse(asText(data), path);\n return wrapGroup(result.scene, result.animations || []);\n}\n\nexport async function parseModelResource(\n res: ResourceStruct,\n renderer?: WebGLRenderer,\n): Promise<ParsedModel> {\n const { data, type, path } = modelPayload(res);\n switch (type) {\n case 'glb':\n case 'gltf':\n return parseGltf(data, path, renderer);\n case 'fbx':\n return parseFbx(data, path);\n case 'obj':\n return parseObj(res, data, path);\n case 'stl':\n return geometryToModel(new STLLoader().parse(asBuffer(data)));\n case 'ply':\n return geometryToModel(new PLYLoader().parse(asBuffer(data)));\n case 'dae':\n case 'collada':\n return parseCollada(data, path);\n default:\n throw new Error(\n `Unsupported 3D model type \"${type}\" for resource \"${res.name}\". ` +\n 'Use glb, gltf, fbx, obj, stl, dae, or ply.',\n );\n }\n}\n\nfunction createModelInstance(res: ResourceStruct): ModelResourceInstance {\n let cached: ParsedModel | null = null;\n return {\n async parse(renderer?: WebGLRenderer) {\n if (!cached) {\n cached = await parseModelResource(res, renderer);\n }\n return cached;\n },\n dispose() {\n cached = null;\n },\n };\n}\n\nresource.registerInstance(RESOURCE_TYPE.MODEL, (res) => createModelInstance(res));\nresource.registerInstance(RESOURCE_TYPE.GLB, (res) => createModelInstance(res));\nresource.registerDestroy(RESOURCE_TYPE.MODEL, ({ instance }) => {\n instance?.dispose?.();\n});\nresource.registerDestroy(RESOURCE_TYPE.GLB, ({ instance }) => {\n instance?.dispose?.();\n});\n","import { decorators, ComponentChanged, OBSERVER_TYPE, GameObject } from '@combos-fun/engine';\nimport {\n Renderer3D,\n Renderer3DSystem,\n requireNamedResource,\n} from '@combos-fun/plugin-renderer-3d';\nimport { Group } from 'three';\nimport { clone as cloneSkinned } from 'three/addons/utils/SkeletonUtils.js';\nimport Model3D from './component';\nimport './parseModel';\nimport type { ModelResourceInstance } from './parseModel';\n\n@decorators.componentObserver({\n Model3D: [\n 'resource',\n 'positionX', 'positionY', 'positionZ',\n 'rotationX', 'rotationY', 'rotationZ',\n 'scaleX', 'scaleY', 'scaleZ',\n 'speed', 'animationIndex',\n ],\n})\nexport default class Model3DSystem extends Renderer3D {\n static systemName = 'Model3DSystem';\n name: string = 'Model3DSystem';\n\n init() {\n const renderer3DSystem = this.game.getSystem(Renderer3DSystem) as Renderer3DSystem;\n renderer3DSystem.rendererManager.register(this);\n }\n\n componentChanged(changed: ComponentChanged) {\n if (changed.componentName !== 'Model3D') return;\n\n const component = changed.component as Model3D;\n\n if (changed.type === OBSERVER_TYPE.ADD) {\n this.handleAdd(changed.gameObject, component);\n } else if (changed.type === OBSERVER_TYPE.CHANGE) {\n this.handleChange(changed);\n } else if (changed.type === OBSERVER_TYPE.REMOVE) {\n this.increaseAsyncId(changed.gameObject.id);\n this.threeContext.removeModel(changed.gameObject.id);\n }\n }\n\n rendererUpdate(gameObject: GameObject) {\n const component = gameObject.getComponent(Model3D) as Model3D;\n if (!component) return;\n\n const model = this.threeContext.models.get(gameObject.id);\n if (!model) return;\n\n model.position.set(component.positionX, component.positionY, component.positionZ);\n model.rotation.set(component.rotationX, component.rotationY, component.rotationZ);\n model.scale.set(component.scaleX, component.scaleY, component.scaleZ);\n }\n\n private async handleAdd(gameObject: GameObject, component: Model3D) {\n if (!component.resource) return;\n\n const asyncId = this.increaseAsyncId(gameObject.id);\n await this.attachNamedModel(gameObject.id, component.resource);\n if (!this.validateAsyncId(gameObject.id, asyncId)) return;\n\n if (component.autoPlay) {\n this.threeContext.playAnimation(\n gameObject.id,\n component.animationIndex,\n component.speed,\n );\n }\n }\n\n private async handleChange(changed: ComponentChanged) {\n const component = changed.component as Model3D;\n const changedProp = changed.prop?.prop?.[0];\n\n if (changedProp === 'resource') {\n this.threeContext.removeModel(changed.gameObject.id);\n if (!component.resource) return;\n\n const asyncId = this.increaseAsyncId(changed.gameObject.id);\n await this.attachNamedModel(changed.gameObject.id, component.resource);\n if (!this.validateAsyncId(changed.gameObject.id, asyncId)) return;\n\n if (component.autoPlay) {\n this.threeContext.playAnimation(\n changed.gameObject.id,\n component.animationIndex,\n component.speed,\n );\n }\n }\n\n if (changedProp === 'speed' || changedProp === 'animationIndex') {\n this.threeContext.playAnimation(\n changed.gameObject.id,\n component.animationIndex,\n component.speed,\n );\n }\n }\n\n private async attachNamedModel(id: number, name: string) {\n const res = await requireNamedResource(name);\n const instance = res.instance as ModelResourceInstance | undefined;\n if (!instance || typeof instance.parse !== 'function') {\n throw new Error(\n `Resource \"${name}\" is not a MODEL instance; register RESOURCE_TYPE.MODEL and import Model3DSystem`,\n );\n }\n const parsed = await instance.parse(this.threeContext.renderer);\n const clone = cloneSkinned(parsed.scene) as Group;\n this.threeContext.attachParsedModel(id, clone, parsed.animations);\n }\n}\n"],"names":["Component","__decorate","Field","Group","Mesh","MeshStandardMaterial","DRACOLoader","KTX2Loader","MeshoptDecoder","GLTFLoader","FBXLoader","OBJLoader","MTLLoader","ColladaLoader","STLLoader","PLYLoader","resource","RESOURCE_TYPE","Renderer3D","Renderer3DSystem","OBSERVER_TYPE","requireNamedResource","cloneSkinned","decorators"],"mappings":"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"}
@@ -1 +1 @@
1
- "use strict";var e=require("tslib"),t=require("@combos-fun/engine"),o=require("@combos-fun/inspector-decorator"),i=require("@combos-fun/plugin-renderer-3d");class r extends t.Component{constructor(){super(...arguments),this.resource="",this.autoPlay=!0,this.animationIndex=0,this.speed=1,this.positionX=0,this.positionY=0,this.positionZ=0,this.rotationX=0,this.rotationY=0,this.rotationZ=0,this.scaleX=1,this.scaleY=1,this.scaleZ=1}static{this.componentName="Model3D"}init(e){e&&Object.assign(this,e)}}e.__decorate([o.Field({type:"string",group:"Model3D",label:"resource",description:"Resource id from the asset registry.",editor:"text"})],r.prototype,"resource",void 0),e.__decorate([o.Field({type:"boolean",group:"Model3D",label:"autoPlay",description:"Start playing automatically when loaded.",editor:"toggle"})],r.prototype,"autoPlay",void 0),e.__decorate([o.Field({type:"number",group:"Model3D",label:"animationIndex",description:"Animation clip index.",editor:"number-stepper"})],r.prototype,"animationIndex",void 0),e.__decorate([o.Field({type:"number",step:.1,group:"Model3D",label:"speed",description:"Playback speed.",editor:"number-stepper"})],r.prototype,"speed",void 0),e.__decorate([o.Field({type:"number",step:.1,group:"Model3D",label:"positionX",description:"Local X position.",editor:"number-stepper"})],r.prototype,"positionX",void 0),e.__decorate([o.Field({type:"number",step:.1,group:"Model3D",label:"positionY",description:"Local Y position.",editor:"number-stepper"})],r.prototype,"positionY",void 0),e.__decorate([o.Field({type:"number",step:.1,group:"Model3D",label:"positionZ",description:"Local Z position.",editor:"number-stepper"})],r.prototype,"positionZ",void 0),e.__decorate([o.Field({type:"number",step:.01,group:"Model3D",label:"rotationX",description:"Rotation around X in radians.",editor:"number-stepper"})],r.prototype,"rotationX",void 0),e.__decorate([o.Field({type:"number",step:.01,group:"Model3D",label:"rotationY",description:"Rotation around Y in radians.",editor:"number-stepper"})],r.prototype,"rotationY",void 0),e.__decorate([o.Field({type:"number",step:.01,group:"Model3D",label:"rotationZ",description:"Rotation around Z in radians.",editor:"number-stepper"})],r.prototype,"rotationZ",void 0),e.__decorate([o.Field({type:"number",step:.1,group:"Model3D",label:"scaleX",description:"Scale on X.",editor:"number-stepper"})],r.prototype,"scaleX",void 0),e.__decorate([o.Field({type:"number",step:.1,group:"Model3D",label:"scaleY",description:"Scale on Y.",editor:"number-stepper"})],r.prototype,"scaleY",void 0),e.__decorate([o.Field({type:"number",step:.1,group:"Model3D",label:"scaleZ",description:"Scale on Z.",editor:"number-stepper"})],r.prototype,"scaleZ",void 0);let n=class extends i.Renderer3D{constructor(){super(...arguments),this.name="Model3DSystem"}static{this.systemName="Model3DSystem"}init(){this.game.getSystem(i.Renderer3DSystem).rendererManager.register(this)}componentChanged(e){if("Model3D"!==e.componentName)return;const o=e.component;e.type===t.OBSERVER_TYPE.ADD?this.handleAdd(e.gameObject,o):e.type===t.OBSERVER_TYPE.CHANGE?this.handleChange(e):e.type===t.OBSERVER_TYPE.REMOVE&&(this.increaseAsyncId(e.gameObject.id),this.threeContext.removeModel(e.gameObject.id))}rendererUpdate(e){const t=e.getComponent(r);if(!t)return;const o=this.threeContext.models.get(e.id);o&&(o.position.set(t.positionX,t.positionY,t.positionZ),o.rotation.set(t.rotationX,t.rotationY,t.rotationZ),o.scale.set(t.scaleX,t.scaleY,t.scaleZ))}async handleAdd(e,t){if(!t.resource)return;const o=this.increaseAsyncId(e.id);await this.threeContext.loadGLB(e.id,t.resource),this.validateAsyncId(e.id,o)&&t.autoPlay&&this.threeContext.playAnimation(e.id,t.animationIndex,t.speed)}async handleChange(e){const t=e.component,o=e.prop?.prop?.[0];if("resource"===o){if(this.threeContext.removeModel(e.gameObject.id),!t.resource)return;const o=this.increaseAsyncId(e.gameObject.id);if(await this.threeContext.loadGLB(e.gameObject.id,t.resource),!this.validateAsyncId(e.gameObject.id,o))return;t.autoPlay&&this.threeContext.playAnimation(e.gameObject.id,t.animationIndex,t.speed)}"speed"!==o&&"animationIndex"!==o||this.threeContext.playAnimation(e.gameObject.id,t.animationIndex,t.speed)}};n=e.__decorate([t.decorators.componentObserver({Model3D:["resource","positionX","positionY","positionZ","rotationX","rotationY","rotationZ","scaleX","scaleY","scaleZ","speed","animationIndex"]})],n);var s=n;exports.Model3D=r,exports.Model3DSystem=s;
1
+ "use strict";var e=require("tslib"),t=require("@combos-fun/engine"),r=require("@combos-fun/inspector-decorator"),o=require("@combos-fun/plugin-renderer-3d"),n=require("three/addons/utils/SkeletonUtils.js"),s=require("three"),i=require("three/addons/loaders/GLTFLoader.js"),a=require("three/addons/loaders/DRACOLoader.js"),d=require("three/addons/loaders/KTX2Loader.js"),c=require("three/addons/loaders/FBXLoader.js"),p=require("three/addons/loaders/OBJLoader.js"),l=require("three/addons/loaders/MTLLoader.js"),u=require("three/addons/loaders/STLLoader.js"),m=require("three/addons/loaders/ColladaLoader.js"),h=require("three/addons/loaders/PLYLoader.js"),y=require("three/addons/libs/meshopt_decoder.module.js");class f extends t.Component{constructor(){super(...arguments),this.resource="",this.autoPlay=!0,this.animationIndex=0,this.speed=1,this.positionX=0,this.positionY=0,this.positionZ=0,this.rotationX=0,this.rotationY=0,this.rotationZ=0,this.scaleX=1,this.scaleY=1,this.scaleZ=1}static{this.componentName="Model3D"}init(e){e&&Object.assign(this,e)}}e.__decorate([r.Field({type:"string",group:"Model3D",label:"resource",description:"Engine resource name registered with RESOURCE_TYPE.MODEL.",editor:"text"})],f.prototype,"resource",void 0),e.__decorate([r.Field({type:"boolean",group:"Model3D",label:"autoPlay",description:"Start playing automatically when loaded.",editor:"toggle"})],f.prototype,"autoPlay",void 0),e.__decorate([r.Field({type:"number",group:"Model3D",label:"animationIndex",description:"Animation clip index.",editor:"number-stepper"})],f.prototype,"animationIndex",void 0),e.__decorate([r.Field({type:"number",step:.1,group:"Model3D",label:"speed",description:"Playback speed.",editor:"number-stepper"})],f.prototype,"speed",void 0),e.__decorate([r.Field({type:"number",step:.1,group:"Model3D",label:"positionX",description:"Local X position.",editor:"number-stepper"})],f.prototype,"positionX",void 0),e.__decorate([r.Field({type:"number",step:.1,group:"Model3D",label:"positionY",description:"Local Y position.",editor:"number-stepper"})],f.prototype,"positionY",void 0),e.__decorate([r.Field({type:"number",step:.1,group:"Model3D",label:"positionZ",description:"Local Z position.",editor:"number-stepper"})],f.prototype,"positionZ",void 0),e.__decorate([r.Field({type:"number",step:.01,group:"Model3D",label:"rotationX",description:"Rotation around X in radians.",editor:"number-stepper"})],f.prototype,"rotationX",void 0),e.__decorate([r.Field({type:"number",step:.01,group:"Model3D",label:"rotationY",description:"Rotation around Y in radians.",editor:"number-stepper"})],f.prototype,"rotationY",void 0),e.__decorate([r.Field({type:"number",step:.01,group:"Model3D",label:"rotationZ",description:"Rotation around Z in radians.",editor:"number-stepper"})],f.prototype,"rotationZ",void 0),e.__decorate([r.Field({type:"number",step:.1,group:"Model3D",label:"scaleX",description:"Scale on X.",editor:"number-stepper"})],f.prototype,"scaleX",void 0),e.__decorate([r.Field({type:"number",step:.1,group:"Model3D",label:"scaleY",description:"Scale on Y.",editor:"number-stepper"})],f.prototype,"scaleY",void 0),e.__decorate([r.Field({type:"number",step:.1,group:"Model3D",label:"scaleZ",description:"Scale on Z.",editor:"number-stepper"})],f.prototype,"scaleZ",void 0);let b=null,g=null,E=null;function w(e){const t=String(e||"").split("?")[0].split("#")[0],r=t.lastIndexOf("/");return r>=0?t.slice(0,r+1):""}function M(e){if("string"==typeof e)return e;if(e instanceof ArrayBuffer)return(new TextDecoder).decode(e);if(ArrayBuffer.isView(e))return(new TextDecoder).decode(e);if(e&&"object"==typeof e)return JSON.stringify(e);throw new Error("expected text payload for this model format")}function D(e){if(e instanceof ArrayBuffer)return e;if(ArrayBuffer.isView(e)){const t=e;return t.buffer.slice(t.byteOffset,t.byteOffset+t.byteLength)}throw new Error("expected binary payload for this model format")}function L(e,t=[]){if(e instanceof s.Group)return{scene:e,animations:t};const r=new s.Group;return r.add(e),{scene:r,animations:t}}function _(e){e.computeVertexNormals?.();const t=new s.Mesh(e,new s.MeshStandardMaterial({color:8947848,metalness:.1,roughness:.8})),r=new s.Group;return r.add(t),{scene:r,animations:[]}}function O(e,t,r){const o=new i.GLTFLoader;!function(e,t){b||(b=new a.DRACOLoader,b.setDecoderPath("https://www.gstatic.com/draco/versioned/decoders/1.5.7/")),e.setDRACOLoader(b),g||(g=new d.KTX2Loader,g.setTranscoderPath("https://unpkg.com/three@0.172.0/examples/jsm/libs/basis/")),t&&E!==t&&(g.detectSupport(t),E=t),e.setKTX2Loader(g),e.setMeshoptDecoder(y.MeshoptDecoder)}(o,r);const n="object"!=typeof e||!e||e instanceof ArrayBuffer||ArrayBuffer.isView(e)?e instanceof ArrayBuffer||ArrayBuffer.isView(e)?D(e):M(e):JSON.stringify(e);return new Promise((e,r)=>{o.parse(n,t,t=>{e(L(t.scene,t.animations||[]))},e=>{r(e instanceof Error?e:new Error(String(e)))})})}async function x(e,t){const{data:r,type:o,path:n}=function(e){const t=e.src?.model||e.src?.glb||e.src?.gltf,r=e.data?.model??e.data?.glb??e.data?.gltf;if(null==r)throw new Error(`Resource "${e.name}" has no model data; use RESOURCE_TYPE.MODEL with src.model.url`);return{data:r,type:String(t?.type||"glb").toLowerCase(),path:w(t?.url||"")}}(e);switch(o){case"glb":case"gltf":return O(r,n,t);case"fbx":return async function(e,t){const r=(new c.FBXLoader).parse(D(e),t);return L(r,r.animations||[])}(r,n);case"obj":return async function(e,t,r){const o=new p.OBJLoader,n=e.data?.mtl;if(null!=n){const t=new l.MTLLoader,s=w(e.src?.mtl?.url||"")||r,i=t.parse(M(n),s);i.preload(),o.setMaterials(i)}return L(o.parse(M(t)))}(e,r,n);case"stl":return _((new u.STLLoader).parse(D(r)));case"ply":return _((new h.PLYLoader).parse(D(r)));case"dae":case"collada":return async function(e,t){const r=(new m.ColladaLoader).parse(M(e),t);return L(r.scene,r.animations||[])}(r,n);default:throw new Error(`Unsupported 3D model type "${o}" for resource "${e.name}". Use glb, gltf, fbx, obj, stl, dae, or ply.`)}}function R(e){let t=null;return{parse:async r=>(t||(t=await x(e,r)),t),dispose(){t=null}}}t.resource.registerInstance(t.RESOURCE_TYPE.MODEL,e=>R(e)),t.resource.registerInstance(t.RESOURCE_TYPE.GLB,e=>R(e)),t.resource.registerDestroy(t.RESOURCE_TYPE.MODEL,({instance:e})=>{e?.dispose?.()}),t.resource.registerDestroy(t.RESOURCE_TYPE.GLB,({instance:e})=>{e?.dispose?.()});let S=class extends o.Renderer3D{constructor(){super(...arguments),this.name="Model3DSystem"}static{this.systemName="Model3DSystem"}init(){this.game.getSystem(o.Renderer3DSystem).rendererManager.register(this)}componentChanged(e){if("Model3D"!==e.componentName)return;const r=e.component;e.type===t.OBSERVER_TYPE.ADD?this.handleAdd(e.gameObject,r):e.type===t.OBSERVER_TYPE.CHANGE?this.handleChange(e):e.type===t.OBSERVER_TYPE.REMOVE&&(this.increaseAsyncId(e.gameObject.id),this.threeContext.removeModel(e.gameObject.id))}rendererUpdate(e){const t=e.getComponent(f);if(!t)return;const r=this.threeContext.models.get(e.id);r&&(r.position.set(t.positionX,t.positionY,t.positionZ),r.rotation.set(t.rotationX,t.rotationY,t.rotationZ),r.scale.set(t.scaleX,t.scaleY,t.scaleZ))}async handleAdd(e,t){if(!t.resource)return;const r=this.increaseAsyncId(e.id);await this.attachNamedModel(e.id,t.resource),this.validateAsyncId(e.id,r)&&t.autoPlay&&this.threeContext.playAnimation(e.id,t.animationIndex,t.speed)}async handleChange(e){const t=e.component,r=e.prop?.prop?.[0];if("resource"===r){if(this.threeContext.removeModel(e.gameObject.id),!t.resource)return;const r=this.increaseAsyncId(e.gameObject.id);if(await this.attachNamedModel(e.gameObject.id,t.resource),!this.validateAsyncId(e.gameObject.id,r))return;t.autoPlay&&this.threeContext.playAnimation(e.gameObject.id,t.animationIndex,t.speed)}"speed"!==r&&"animationIndex"!==r||this.threeContext.playAnimation(e.gameObject.id,t.animationIndex,t.speed)}async attachNamedModel(e,t){const r=(await o.requireNamedResource(t)).instance;if(!r||"function"!=typeof r.parse)throw new Error(`Resource "${t}" is not a MODEL instance; register RESOURCE_TYPE.MODEL and import Model3DSystem`);const s=await r.parse(this.threeContext.renderer),i=n.clone(s.scene);this.threeContext.attachParsedModel(e,i,s.animations)}};S=e.__decorate([t.decorators.componentObserver({Model3D:["resource","positionX","positionY","positionZ","rotationX","rotationY","rotationZ","scaleX","scaleY","scaleZ","speed","animationIndex"]})],S);var Y=S;exports.Model3D=f,exports.Model3DSystem=Y;
@@ -1,4 +1,5 @@
1
1
  import { Component, ComponentChanged, GameObject } from '@combos-fun/engine';
2
+ import { WebGLRenderer, Group, AnimationClip } from 'three';
2
3
  import { Renderer3D } from '@combos-fun/plugin-renderer-3d';
3
4
 
4
5
  interface Model3DParams {
@@ -34,6 +35,15 @@ declare class Model3D extends Component<Model3DParams> {
34
35
  init(obj?: Model3DParams): void;
35
36
  }
36
37
 
38
+ interface ParsedModel {
39
+ scene: Group;
40
+ animations: AnimationClip[];
41
+ }
42
+ interface ModelResourceInstance {
43
+ parse(renderer?: WebGLRenderer): Promise<ParsedModel>;
44
+ dispose(): void;
45
+ }
46
+
37
47
  declare class Model3DSystem extends Renderer3D {
38
48
  static systemName: string;
39
49
  name: string;
@@ -42,7 +52,8 @@ declare class Model3DSystem extends Renderer3D {
42
52
  rendererUpdate(gameObject: GameObject): void;
43
53
  private handleAdd;
44
54
  private handleChange;
55
+ private attachNamedModel;
45
56
  }
46
57
 
47
58
  export { Model3D, Model3DSystem };
48
- export type { Model3DParams };
59
+ export type { Model3DParams, ModelResourceInstance, ParsedModel };
@@ -1,7 +1,19 @@
1
1
  import { __decorate } from 'tslib';
2
- import { Component, OBSERVER_TYPE, decorators } from '@combos-fun/engine';
2
+ import { Component, resource, RESOURCE_TYPE, OBSERVER_TYPE, decorators } from '@combos-fun/engine';
3
3
  import { Field } from '@combos-fun/inspector-decorator';
4
- import { Renderer3D, Renderer3DSystem } from '@combos-fun/plugin-renderer-3d';
4
+ import { Renderer3D, Renderer3DSystem, requireNamedResource } from '@combos-fun/plugin-renderer-3d';
5
+ import { clone } from 'three/addons/utils/SkeletonUtils.js';
6
+ import { Mesh, MeshStandardMaterial, Group } from 'three';
7
+ import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
8
+ import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
9
+ import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js';
10
+ import { FBXLoader } from 'three/addons/loaders/FBXLoader.js';
11
+ import { OBJLoader } from 'three/addons/loaders/OBJLoader.js';
12
+ import { MTLLoader } from 'three/addons/loaders/MTLLoader.js';
13
+ import { STLLoader } from 'three/addons/loaders/STLLoader.js';
14
+ import { ColladaLoader } from 'three/addons/loaders/ColladaLoader.js';
15
+ import { PLYLoader } from 'three/addons/loaders/PLYLoader.js';
16
+ import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js';
5
17
 
6
18
  class Model3D extends Component {
7
19
  constructor() {
@@ -31,7 +43,7 @@ __decorate([
31
43
  type: 'string',
32
44
  group: 'Model3D',
33
45
  label: 'resource',
34
- description: 'Resource id from the asset registry.',
46
+ description: 'Engine resource name registered with RESOURCE_TYPE.MODEL.',
35
47
  editor: 'text',
36
48
  })
37
49
  ], Model3D.prototype, "resource", void 0);
@@ -154,6 +166,163 @@ __decorate([
154
166
  })
155
167
  ], Model3D.prototype, "scaleZ", void 0);
156
168
 
169
+ const THREE_ADDON_CDN = 'https://unpkg.com/three@0.172.0/examples/jsm/libs';
170
+ const DRACO_DECODER_PATH = 'https://www.gstatic.com/draco/versioned/decoders/1.5.7/';
171
+ const BASIS_TRANSCODER_PATH = `${THREE_ADDON_CDN}/basis/`;
172
+ let sharedDraco = null;
173
+ let sharedKtx2 = null;
174
+ let ktx2DetectedFor = null;
175
+ function dirOf(url) {
176
+ const clean = String(url || '').split('?')[0].split('#')[0];
177
+ const slash = clean.lastIndexOf('/');
178
+ return slash >= 0 ? clean.slice(0, slash + 1) : '';
179
+ }
180
+ function asText(data) {
181
+ if (typeof data === 'string')
182
+ return data;
183
+ if (data instanceof ArrayBuffer)
184
+ return new TextDecoder().decode(data);
185
+ if (ArrayBuffer.isView(data)) {
186
+ return new TextDecoder().decode(data);
187
+ }
188
+ if (data && typeof data === 'object')
189
+ return JSON.stringify(data);
190
+ throw new Error('expected text payload for this model format');
191
+ }
192
+ function asBuffer(data) {
193
+ if (data instanceof ArrayBuffer)
194
+ return data;
195
+ if (ArrayBuffer.isView(data)) {
196
+ const view = data;
197
+ return view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength);
198
+ }
199
+ throw new Error('expected binary payload for this model format');
200
+ }
201
+ function wrapGroup(object, animations = []) {
202
+ if (object instanceof Group) {
203
+ return { scene: object, animations };
204
+ }
205
+ const scene = new Group();
206
+ scene.add(object);
207
+ return { scene, animations };
208
+ }
209
+ function geometryToModel(geometry) {
210
+ geometry.computeVertexNormals?.();
211
+ const mesh = new Mesh(geometry, new MeshStandardMaterial({ color: 0x888888, metalness: 0.1, roughness: 0.8 }));
212
+ const scene = new Group();
213
+ scene.add(mesh);
214
+ return { scene, animations: [] };
215
+ }
216
+ function modelPayload(res) {
217
+ const slot = res.src?.model || res.src?.glb || res.src?.gltf;
218
+ const data = res.data?.model ?? res.data?.glb ?? res.data?.gltf;
219
+ if (data == null) {
220
+ throw new Error(`Resource "${res.name}" has no model data; use RESOURCE_TYPE.MODEL with src.model.url`);
221
+ }
222
+ const type = String(slot?.type || 'glb').toLowerCase();
223
+ return { data, type, path: dirOf(slot?.url || '') };
224
+ }
225
+ function ensureGltfExtras(loader, renderer) {
226
+ if (!sharedDraco) {
227
+ sharedDraco = new DRACOLoader();
228
+ sharedDraco.setDecoderPath(DRACO_DECODER_PATH);
229
+ }
230
+ loader.setDRACOLoader(sharedDraco);
231
+ if (!sharedKtx2) {
232
+ sharedKtx2 = new KTX2Loader();
233
+ sharedKtx2.setTranscoderPath(BASIS_TRANSCODER_PATH);
234
+ }
235
+ if (renderer && ktx2DetectedFor !== renderer) {
236
+ sharedKtx2.detectSupport(renderer);
237
+ ktx2DetectedFor = renderer;
238
+ }
239
+ loader.setKTX2Loader(sharedKtx2);
240
+ loader.setMeshoptDecoder(MeshoptDecoder);
241
+ }
242
+ function parseGltf(data, path, renderer) {
243
+ const loader = new GLTFLoader();
244
+ ensureGltfExtras(loader, renderer);
245
+ const payload = typeof data === 'object' && data && !(data instanceof ArrayBuffer) && !ArrayBuffer.isView(data)
246
+ ? JSON.stringify(data)
247
+ : data instanceof ArrayBuffer || ArrayBuffer.isView(data)
248
+ ? asBuffer(data)
249
+ : asText(data);
250
+ return new Promise((resolve, reject) => {
251
+ loader.parse(payload, path, (gltf) => {
252
+ resolve(wrapGroup(gltf.scene, gltf.animations || []));
253
+ }, (err) => {
254
+ reject(err instanceof Error ? err : new Error(String(err)));
255
+ });
256
+ });
257
+ }
258
+ async function parseFbx(data, path) {
259
+ const loader = new FBXLoader();
260
+ const object = loader.parse(asBuffer(data), path);
261
+ const animations = (object.animations || []);
262
+ return wrapGroup(object, animations);
263
+ }
264
+ async function parseObj(res, data, path) {
265
+ const objLoader = new OBJLoader();
266
+ const mtlText = res.data?.mtl;
267
+ if (mtlText != null) {
268
+ const mtlLoader = new MTLLoader();
269
+ const mtlPath = dirOf(res.src?.mtl?.url || '') || path;
270
+ const materials = mtlLoader.parse(asText(mtlText), mtlPath);
271
+ materials.preload();
272
+ objLoader.setMaterials(materials);
273
+ }
274
+ return wrapGroup(objLoader.parse(asText(data)));
275
+ }
276
+ async function parseCollada(data, path) {
277
+ const loader = new ColladaLoader();
278
+ const result = loader.parse(asText(data), path);
279
+ return wrapGroup(result.scene, result.animations || []);
280
+ }
281
+ async function parseModelResource(res, renderer) {
282
+ const { data, type, path } = modelPayload(res);
283
+ switch (type) {
284
+ case 'glb':
285
+ case 'gltf':
286
+ return parseGltf(data, path, renderer);
287
+ case 'fbx':
288
+ return parseFbx(data, path);
289
+ case 'obj':
290
+ return parseObj(res, data, path);
291
+ case 'stl':
292
+ return geometryToModel(new STLLoader().parse(asBuffer(data)));
293
+ case 'ply':
294
+ return geometryToModel(new PLYLoader().parse(asBuffer(data)));
295
+ case 'dae':
296
+ case 'collada':
297
+ return parseCollada(data, path);
298
+ default:
299
+ throw new Error(`Unsupported 3D model type "${type}" for resource "${res.name}". ` +
300
+ 'Use glb, gltf, fbx, obj, stl, dae, or ply.');
301
+ }
302
+ }
303
+ function createModelInstance(res) {
304
+ let cached = null;
305
+ return {
306
+ async parse(renderer) {
307
+ if (!cached) {
308
+ cached = await parseModelResource(res, renderer);
309
+ }
310
+ return cached;
311
+ },
312
+ dispose() {
313
+ cached = null;
314
+ },
315
+ };
316
+ }
317
+ resource.registerInstance(RESOURCE_TYPE.MODEL, (res) => createModelInstance(res));
318
+ resource.registerInstance(RESOURCE_TYPE.GLB, (res) => createModelInstance(res));
319
+ resource.registerDestroy(RESOURCE_TYPE.MODEL, ({ instance }) => {
320
+ instance?.dispose?.();
321
+ });
322
+ resource.registerDestroy(RESOURCE_TYPE.GLB, ({ instance }) => {
323
+ instance?.dispose?.();
324
+ });
325
+
157
326
  let Model3DSystem = class Model3DSystem extends Renderer3D {
158
327
  constructor() {
159
328
  super(...arguments);
@@ -194,7 +363,7 @@ let Model3DSystem = class Model3DSystem extends Renderer3D {
194
363
  if (!component.resource)
195
364
  return;
196
365
  const asyncId = this.increaseAsyncId(gameObject.id);
197
- await this.threeContext.loadGLB(gameObject.id, component.resource);
366
+ await this.attachNamedModel(gameObject.id, component.resource);
198
367
  if (!this.validateAsyncId(gameObject.id, asyncId))
199
368
  return;
200
369
  if (component.autoPlay) {
@@ -209,7 +378,7 @@ let Model3DSystem = class Model3DSystem extends Renderer3D {
209
378
  if (!component.resource)
210
379
  return;
211
380
  const asyncId = this.increaseAsyncId(changed.gameObject.id);
212
- await this.threeContext.loadGLB(changed.gameObject.id, component.resource);
381
+ await this.attachNamedModel(changed.gameObject.id, component.resource);
213
382
  if (!this.validateAsyncId(changed.gameObject.id, asyncId))
214
383
  return;
215
384
  if (component.autoPlay) {
@@ -220,6 +389,16 @@ let Model3DSystem = class Model3DSystem extends Renderer3D {
220
389
  this.threeContext.playAnimation(changed.gameObject.id, component.animationIndex, component.speed);
221
390
  }
222
391
  }
392
+ async attachNamedModel(id, name) {
393
+ const res = await requireNamedResource(name);
394
+ const instance = res.instance;
395
+ if (!instance || typeof instance.parse !== 'function') {
396
+ throw new Error(`Resource "${name}" is not a MODEL instance; register RESOURCE_TYPE.MODEL and import Model3DSystem`);
397
+ }
398
+ const parsed = await instance.parse(this.threeContext.renderer);
399
+ const clone$1 = clone(parsed.scene);
400
+ this.threeContext.attachParsedModel(id, clone$1, parsed.animations);
401
+ }
223
402
  };
224
403
  Model3DSystem = __decorate([
225
404
  decorators.componentObserver({
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-renderer-3d-model.esm.js","sources":["../lib/component.ts","../lib/system.ts"],"sourcesContent":["import { Component } from '@combos-fun/engine';\nimport { Field } from '@combos-fun/inspector-decorator';\n\nexport interface Model3DParams {\n resource?: string;\n autoPlay?: boolean;\n animationIndex?: number;\n speed?: number;\n positionX?: number;\n positionY?: number;\n positionZ?: number;\n rotationX?: number;\n rotationY?: number;\n rotationZ?: number;\n scaleX?: number;\n scaleY?: number;\n scaleZ?: number;\n}\n\nexport default class Model3D extends Component<Model3DParams> {\n static componentName: string = 'Model3D';\n\n @Field({\n\n type: 'string',\n\n group: 'Model3D',\n\n label: 'resource',\n\n description: 'Resource id from the asset registry.',\n\n editor: 'text',\n\n })\n\n resource: string = '';\n @Field({\n type: 'boolean',\n group: 'Model3D',\n label: 'autoPlay',\n description: 'Start playing automatically when loaded.',\n editor: 'toggle',\n })\n autoPlay: boolean = true;\n @Field({\n type: 'number',\n group: 'Model3D',\n label: 'animationIndex',\n description: 'Animation clip index.',\n editor: 'number-stepper',\n })\n animationIndex: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'speed',\n description: 'Playback speed.',\n editor: 'number-stepper',\n })\n speed: number = 1;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'positionX',\n description: 'Local X position.',\n editor: 'number-stepper',\n })\n positionX: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'positionY',\n description: 'Local Y position.',\n editor: 'number-stepper',\n })\n positionY: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'positionZ',\n description: 'Local Z position.',\n editor: 'number-stepper',\n })\n positionZ: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Model3D',\n label: 'rotationX',\n description: 'Rotation around X in radians.',\n editor: 'number-stepper',\n })\n rotationX: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Model3D',\n label: 'rotationY',\n description: 'Rotation around Y in radians.',\n editor: 'number-stepper',\n })\n rotationY: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Model3D',\n label: 'rotationZ',\n description: 'Rotation around Z in radians.',\n editor: 'number-stepper',\n })\n rotationZ: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'scaleX',\n description: 'Scale on X.',\n editor: 'number-stepper',\n })\n scaleX: number = 1;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'scaleY',\n description: 'Scale on Y.',\n editor: 'number-stepper',\n })\n scaleY: number = 1;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'scaleZ',\n description: 'Scale on Z.',\n editor: 'number-stepper',\n })\n scaleZ: number = 1;\n\n init(obj?: Model3DParams) {\n if (obj) Object.assign(this, obj);\n }\n}\n","import { decorators, ComponentChanged, OBSERVER_TYPE, GameObject } from '@combos-fun/engine';\nimport { Renderer3D, Renderer3DSystem } from '@combos-fun/plugin-renderer-3d';\nimport Model3D from './component';\n\n@decorators.componentObserver({\n Model3D: [\n 'resource',\n 'positionX', 'positionY', 'positionZ',\n 'rotationX', 'rotationY', 'rotationZ',\n 'scaleX', 'scaleY', 'scaleZ',\n 'speed', 'animationIndex',\n ],\n})\nexport default class Model3DSystem extends Renderer3D {\n static systemName = 'Model3DSystem';\n name: string = 'Model3DSystem';\n\n init() {\n const renderer3DSystem = this.game.getSystem(Renderer3DSystem) as Renderer3DSystem;\n renderer3DSystem.rendererManager.register(this);\n }\n\n componentChanged(changed: ComponentChanged) {\n if (changed.componentName !== 'Model3D') return;\n\n const component = changed.component as Model3D;\n\n if (changed.type === OBSERVER_TYPE.ADD) {\n this.handleAdd(changed.gameObject, component);\n } else if (changed.type === OBSERVER_TYPE.CHANGE) {\n this.handleChange(changed);\n } else if (changed.type === OBSERVER_TYPE.REMOVE) {\n this.increaseAsyncId(changed.gameObject.id);\n this.threeContext.removeModel(changed.gameObject.id);\n }\n }\n\n rendererUpdate(gameObject: GameObject) {\n const component = gameObject.getComponent(Model3D) as Model3D;\n if (!component) return;\n\n const model = this.threeContext.models.get(gameObject.id);\n if (!model) return;\n\n model.position.set(component.positionX, component.positionY, component.positionZ);\n model.rotation.set(component.rotationX, component.rotationY, component.rotationZ);\n model.scale.set(component.scaleX, component.scaleY, component.scaleZ);\n }\n\n private async handleAdd(gameObject: GameObject, component: Model3D) {\n if (!component.resource) return;\n\n const asyncId = this.increaseAsyncId(gameObject.id);\n await this.threeContext.loadGLB(gameObject.id, component.resource);\n if (!this.validateAsyncId(gameObject.id, asyncId)) return;\n\n if (component.autoPlay) {\n this.threeContext.playAnimation(\n gameObject.id,\n component.animationIndex,\n component.speed,\n );\n }\n }\n\n private async handleChange(changed: ComponentChanged) {\n const component = changed.component as Model3D;\n const changedProp = changed.prop?.prop?.[0];\n\n if (changedProp === 'resource') {\n this.threeContext.removeModel(changed.gameObject.id);\n if (!component.resource) return;\n\n const asyncId = this.increaseAsyncId(changed.gameObject.id);\n await this.threeContext.loadGLB(changed.gameObject.id, component.resource);\n if (!this.validateAsyncId(changed.gameObject.id, asyncId)) return;\n\n if (component.autoPlay) {\n this.threeContext.playAnimation(\n changed.gameObject.id,\n component.animationIndex,\n component.speed,\n );\n }\n }\n\n if (changedProp === 'speed' || changedProp === 'animationIndex') {\n this.threeContext.playAnimation(\n changed.gameObject.id,\n component.animationIndex,\n component.speed,\n );\n }\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plugin-renderer-3d-model.esm.js","sources":["../lib/component.ts","../lib/parseModel.ts","../lib/system.ts"],"sourcesContent":["import { Component } from '@combos-fun/engine';\nimport { Field } from '@combos-fun/inspector-decorator';\n\nexport interface Model3DParams {\n resource?: string;\n autoPlay?: boolean;\n animationIndex?: number;\n speed?: number;\n positionX?: number;\n positionY?: number;\n positionZ?: number;\n rotationX?: number;\n rotationY?: number;\n rotationZ?: number;\n scaleX?: number;\n scaleY?: number;\n scaleZ?: number;\n}\n\nexport default class Model3D extends Component<Model3DParams> {\n static componentName: string = 'Model3D';\n\n @Field({\n\n type: 'string',\n\n group: 'Model3D',\n\n label: 'resource',\n\n description: 'Engine resource name registered with RESOURCE_TYPE.MODEL.',\n\n editor: 'text',\n\n })\n\n resource: string = '';\n @Field({\n type: 'boolean',\n group: 'Model3D',\n label: 'autoPlay',\n description: 'Start playing automatically when loaded.',\n editor: 'toggle',\n })\n autoPlay: boolean = true;\n @Field({\n type: 'number',\n group: 'Model3D',\n label: 'animationIndex',\n description: 'Animation clip index.',\n editor: 'number-stepper',\n })\n animationIndex: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'speed',\n description: 'Playback speed.',\n editor: 'number-stepper',\n })\n speed: number = 1;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'positionX',\n description: 'Local X position.',\n editor: 'number-stepper',\n })\n positionX: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'positionY',\n description: 'Local Y position.',\n editor: 'number-stepper',\n })\n positionY: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'positionZ',\n description: 'Local Z position.',\n editor: 'number-stepper',\n })\n positionZ: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Model3D',\n label: 'rotationX',\n description: 'Rotation around X in radians.',\n editor: 'number-stepper',\n })\n rotationX: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Model3D',\n label: 'rotationY',\n description: 'Rotation around Y in radians.',\n editor: 'number-stepper',\n })\n rotationY: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Model3D',\n label: 'rotationZ',\n description: 'Rotation around Z in radians.',\n editor: 'number-stepper',\n })\n rotationZ: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'scaleX',\n description: 'Scale on X.',\n editor: 'number-stepper',\n })\n scaleX: number = 1;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'scaleY',\n description: 'Scale on Y.',\n editor: 'number-stepper',\n })\n scaleY: number = 1;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Model3D',\n label: 'scaleZ',\n description: 'Scale on Z.',\n editor: 'number-stepper',\n })\n scaleZ: number = 1;\n\n init(obj?: Model3DParams) {\n if (obj) Object.assign(this, obj);\n }\n}\n","import { resource, RESOURCE_TYPE } from '@combos-fun/engine';\nimport type { ResourceStruct } from '@combos-fun/engine';\nimport {\n AnimationClip,\n BufferGeometry,\n Group,\n Mesh,\n MeshStandardMaterial,\n Object3D,\n} from 'three';\nimport type { WebGLRenderer } from 'three';\nimport { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';\nimport { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';\nimport { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js';\nimport { FBXLoader } from 'three/addons/loaders/FBXLoader.js';\nimport { OBJLoader } from 'three/addons/loaders/OBJLoader.js';\nimport { MTLLoader } from 'three/addons/loaders/MTLLoader.js';\nimport { STLLoader } from 'three/addons/loaders/STLLoader.js';\nimport { ColladaLoader } from 'three/addons/loaders/ColladaLoader.js';\nimport { PLYLoader } from 'three/addons/loaders/PLYLoader.js';\nimport { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js';\n\nexport interface ParsedModel {\n scene: Group;\n animations: AnimationClip[];\n}\n\nexport interface ModelResourceInstance {\n parse(renderer?: WebGLRenderer): Promise<ParsedModel>;\n dispose(): void;\n}\n\nconst THREE_ADDON_CDN = 'https://unpkg.com/three@0.172.0/examples/jsm/libs';\nconst DRACO_DECODER_PATH = 'https://www.gstatic.com/draco/versioned/decoders/1.5.7/';\nconst BASIS_TRANSCODER_PATH = `${THREE_ADDON_CDN}/basis/`;\n\nlet sharedDraco: DRACOLoader | null = null;\nlet sharedKtx2: KTX2Loader | null = null;\nlet ktx2DetectedFor: WebGLRenderer | null = null;\n\nfunction dirOf(url: string): string {\n const clean = String(url || '').split('?')[0].split('#')[0];\n const slash = clean.lastIndexOf('/');\n return slash >= 0 ? clean.slice(0, slash + 1) : '';\n}\n\nfunction asText(data: unknown): string {\n if (typeof data === 'string') return data;\n if (data instanceof ArrayBuffer) return new TextDecoder().decode(data);\n if (ArrayBuffer.isView(data)) {\n return new TextDecoder().decode(data as ArrayBufferView);\n }\n if (data && typeof data === 'object') return JSON.stringify(data);\n throw new Error('expected text payload for this model format');\n}\n\nfunction asBuffer(data: unknown): ArrayBuffer {\n if (data instanceof ArrayBuffer) return data;\n if (ArrayBuffer.isView(data)) {\n const view = data as ArrayBufferView;\n return view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength);\n }\n throw new Error('expected binary payload for this model format');\n}\n\nfunction wrapGroup(object: Object3D, animations: AnimationClip[] = []): ParsedModel {\n if (object instanceof Group) {\n return { scene: object, animations };\n }\n const scene = new Group();\n scene.add(object);\n return { scene, animations };\n}\n\nfunction geometryToModel(geometry: BufferGeometry): ParsedModel {\n geometry.computeVertexNormals?.();\n const mesh = new Mesh(\n geometry,\n new MeshStandardMaterial({ color: 0x888888, metalness: 0.1, roughness: 0.8 }),\n );\n const scene = new Group();\n scene.add(mesh);\n return { scene, animations: [] };\n}\n\nfunction modelPayload(res: ResourceStruct): { data: unknown; type: string; path: string } {\n const slot = res.src?.model || res.src?.glb || res.src?.gltf;\n const data = res.data?.model ?? res.data?.glb ?? res.data?.gltf;\n if (data == null) {\n throw new Error(\n `Resource \"${res.name}\" has no model data; use RESOURCE_TYPE.MODEL with src.model.url`,\n );\n }\n const type = String(slot?.type || 'glb').toLowerCase();\n return { data, type, path: dirOf(slot?.url || '') };\n}\n\nfunction ensureGltfExtras(loader: GLTFLoader, renderer?: WebGLRenderer) {\n if (!sharedDraco) {\n sharedDraco = new DRACOLoader();\n sharedDraco.setDecoderPath(DRACO_DECODER_PATH);\n }\n loader.setDRACOLoader(sharedDraco);\n\n if (!sharedKtx2) {\n sharedKtx2 = new KTX2Loader();\n sharedKtx2.setTranscoderPath(BASIS_TRANSCODER_PATH);\n }\n if (renderer && ktx2DetectedFor !== renderer) {\n sharedKtx2.detectSupport(renderer);\n ktx2DetectedFor = renderer;\n }\n loader.setKTX2Loader(sharedKtx2);\n loader.setMeshoptDecoder(MeshoptDecoder);\n}\n\nfunction parseGltf(\n data: unknown,\n path: string,\n renderer?: WebGLRenderer,\n): Promise<ParsedModel> {\n const loader = new GLTFLoader();\n ensureGltfExtras(loader, renderer);\n const payload =\n typeof data === 'object' && data && !(data instanceof ArrayBuffer) && !ArrayBuffer.isView(data)\n ? JSON.stringify(data)\n : data instanceof ArrayBuffer || ArrayBuffer.isView(data)\n ? asBuffer(data)\n : asText(data);\n\n return new Promise((resolve, reject) => {\n loader.parse(\n payload as ArrayBuffer | string,\n path,\n (gltf) => {\n resolve(wrapGroup(gltf.scene, gltf.animations || []));\n },\n (err) => {\n reject(err instanceof Error ? err : new Error(String(err)));\n },\n );\n });\n}\n\nasync function parseFbx(data: unknown, path: string): Promise<ParsedModel> {\n const loader = new FBXLoader();\n const object = loader.parse(asBuffer(data), path);\n const animations = (object.animations || []) as AnimationClip[];\n return wrapGroup(object, animations);\n}\n\nasync function parseObj(res: ResourceStruct, data: unknown, path: string): Promise<ParsedModel> {\n const objLoader = new OBJLoader();\n const mtlText = res.data?.mtl;\n if (mtlText != null) {\n const mtlLoader = new MTLLoader();\n const mtlPath = dirOf(res.src?.mtl?.url || '') || path;\n const materials = mtlLoader.parse(asText(mtlText), mtlPath);\n materials.preload();\n objLoader.setMaterials(materials);\n }\n return wrapGroup(objLoader.parse(asText(data)));\n}\n\nasync function parseCollada(data: unknown, path: string): Promise<ParsedModel> {\n const loader = new ColladaLoader();\n const result = loader.parse(asText(data), path);\n return wrapGroup(result.scene, result.animations || []);\n}\n\nexport async function parseModelResource(\n res: ResourceStruct,\n renderer?: WebGLRenderer,\n): Promise<ParsedModel> {\n const { data, type, path } = modelPayload(res);\n switch (type) {\n case 'glb':\n case 'gltf':\n return parseGltf(data, path, renderer);\n case 'fbx':\n return parseFbx(data, path);\n case 'obj':\n return parseObj(res, data, path);\n case 'stl':\n return geometryToModel(new STLLoader().parse(asBuffer(data)));\n case 'ply':\n return geometryToModel(new PLYLoader().parse(asBuffer(data)));\n case 'dae':\n case 'collada':\n return parseCollada(data, path);\n default:\n throw new Error(\n `Unsupported 3D model type \"${type}\" for resource \"${res.name}\". ` +\n 'Use glb, gltf, fbx, obj, stl, dae, or ply.',\n );\n }\n}\n\nfunction createModelInstance(res: ResourceStruct): ModelResourceInstance {\n let cached: ParsedModel | null = null;\n return {\n async parse(renderer?: WebGLRenderer) {\n if (!cached) {\n cached = await parseModelResource(res, renderer);\n }\n return cached;\n },\n dispose() {\n cached = null;\n },\n };\n}\n\nresource.registerInstance(RESOURCE_TYPE.MODEL, (res) => createModelInstance(res));\nresource.registerInstance(RESOURCE_TYPE.GLB, (res) => createModelInstance(res));\nresource.registerDestroy(RESOURCE_TYPE.MODEL, ({ instance }) => {\n instance?.dispose?.();\n});\nresource.registerDestroy(RESOURCE_TYPE.GLB, ({ instance }) => {\n instance?.dispose?.();\n});\n","import { decorators, ComponentChanged, OBSERVER_TYPE, GameObject } from '@combos-fun/engine';\nimport {\n Renderer3D,\n Renderer3DSystem,\n requireNamedResource,\n} from '@combos-fun/plugin-renderer-3d';\nimport { Group } from 'three';\nimport { clone as cloneSkinned } from 'three/addons/utils/SkeletonUtils.js';\nimport Model3D from './component';\nimport './parseModel';\nimport type { ModelResourceInstance } from './parseModel';\n\n@decorators.componentObserver({\n Model3D: [\n 'resource',\n 'positionX', 'positionY', 'positionZ',\n 'rotationX', 'rotationY', 'rotationZ',\n 'scaleX', 'scaleY', 'scaleZ',\n 'speed', 'animationIndex',\n ],\n})\nexport default class Model3DSystem extends Renderer3D {\n static systemName = 'Model3DSystem';\n name: string = 'Model3DSystem';\n\n init() {\n const renderer3DSystem = this.game.getSystem(Renderer3DSystem) as Renderer3DSystem;\n renderer3DSystem.rendererManager.register(this);\n }\n\n componentChanged(changed: ComponentChanged) {\n if (changed.componentName !== 'Model3D') return;\n\n const component = changed.component as Model3D;\n\n if (changed.type === OBSERVER_TYPE.ADD) {\n this.handleAdd(changed.gameObject, component);\n } else if (changed.type === OBSERVER_TYPE.CHANGE) {\n this.handleChange(changed);\n } else if (changed.type === OBSERVER_TYPE.REMOVE) {\n this.increaseAsyncId(changed.gameObject.id);\n this.threeContext.removeModel(changed.gameObject.id);\n }\n }\n\n rendererUpdate(gameObject: GameObject) {\n const component = gameObject.getComponent(Model3D) as Model3D;\n if (!component) return;\n\n const model = this.threeContext.models.get(gameObject.id);\n if (!model) return;\n\n model.position.set(component.positionX, component.positionY, component.positionZ);\n model.rotation.set(component.rotationX, component.rotationY, component.rotationZ);\n model.scale.set(component.scaleX, component.scaleY, component.scaleZ);\n }\n\n private async handleAdd(gameObject: GameObject, component: Model3D) {\n if (!component.resource) return;\n\n const asyncId = this.increaseAsyncId(gameObject.id);\n await this.attachNamedModel(gameObject.id, component.resource);\n if (!this.validateAsyncId(gameObject.id, asyncId)) return;\n\n if (component.autoPlay) {\n this.threeContext.playAnimation(\n gameObject.id,\n component.animationIndex,\n component.speed,\n );\n }\n }\n\n private async handleChange(changed: ComponentChanged) {\n const component = changed.component as Model3D;\n const changedProp = changed.prop?.prop?.[0];\n\n if (changedProp === 'resource') {\n this.threeContext.removeModel(changed.gameObject.id);\n if (!component.resource) return;\n\n const asyncId = this.increaseAsyncId(changed.gameObject.id);\n await this.attachNamedModel(changed.gameObject.id, component.resource);\n if (!this.validateAsyncId(changed.gameObject.id, asyncId)) return;\n\n if (component.autoPlay) {\n this.threeContext.playAnimation(\n changed.gameObject.id,\n component.animationIndex,\n component.speed,\n );\n }\n }\n\n if (changedProp === 'speed' || changedProp === 'animationIndex') {\n this.threeContext.playAnimation(\n changed.gameObject.id,\n component.animationIndex,\n component.speed,\n );\n }\n }\n\n private async attachNamedModel(id: number, name: string) {\n const res = await requireNamedResource(name);\n const instance = res.instance as ModelResourceInstance | undefined;\n if (!instance || typeof instance.parse !== 'function') {\n throw new Error(\n `Resource \"${name}\" is not a MODEL instance; register RESOURCE_TYPE.MODEL and import Model3DSystem`,\n );\n }\n const parsed = await instance.parse(this.threeContext.renderer);\n const clone = cloneSkinned(parsed.scene) as Group;\n this.threeContext.attachParsedModel(id, clone, parsed.animations);\n }\n}\n"],"names":["clone","cloneSkinned"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@combos-fun/plugin-renderer-3d-model",
3
- "version": "0.0.38",
4
- "description": "GLB / GLTF 3D model loader and animator",
3
+ "version": "0.0.40",
4
+ "description": "Named 3D model loader (glTF/GLB, FBX, OBJ, STL, Collada, PLY) and animator",
5
5
  "main": "index.js",
6
6
  "module": "dist/plugin-renderer-3d-model.esm.js",
7
7
  "bundle": "CombosFun.plugin.renderer.3d.model",
@@ -26,9 +26,9 @@
26
26
  "pluginManifest": "./combos-plugin.json"
27
27
  },
28
28
  "dependencies": {
29
- "@combos-fun/engine": "0.0.38",
30
- "@combos-fun/inspector-decorator": "0.0.38",
31
- "@combos-fun/plugin-renderer-3d": "0.0.38",
29
+ "@combos-fun/engine": "0.0.39",
30
+ "@combos-fun/inspector-decorator": "0.0.39",
31
+ "@combos-fun/plugin-renderer-3d": "0.0.39",
32
32
  "three": "^0.172.0"
33
33
  },
34
34
  "keywords": [
@@ -37,6 +37,11 @@
37
37
  "model",
38
38
  "glb",
39
39
  "gltf",
40
+ "fbx",
41
+ "obj",
42
+ "stl",
43
+ "dae",
44
+ "ply",
40
45
  "animation",
41
46
  "mesh"
42
47
  ],