-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
create the <lume-collada-model> element
Also ensures that GltfModel stuff is re-exported.
- Loading branch information
Showing
8 changed files
with
223 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import Node, {NodeAttributes} from './Node.js' | ||
|
||
import type {ColladaModelBehavior, ColladaModelBehaviorAttributes} from '../html/index.js' | ||
|
||
export type ColladaModelAttributes = NodeAttributes | ||
|
||
/** | ||
* @element lume-collada-model | ||
* @class ColladaModel - Defines the `<lume-collada-model>` element, for loading 3D | ||
* models in the Collada format (.dae files). It is similar to an `<img>` tag, but for 3D. | ||
* | ||
* HTML Example: | ||
* | ||
* ```html | ||
* <lume-scene webgl> | ||
* <lume-collada-model src="path/to/model.dae"></lume-collada-model> | ||
* </lume-scene> | ||
* ``` | ||
* | ||
* JavaScript Example: | ||
* | ||
* ```js | ||
* const scene = new Scene | ||
* document.body.append(scene) | ||
* const model = new ColladaModel | ||
* model.src = 'path/to/model.dae' | ||
* scene.add(model) | ||
* ``` | ||
*/ | ||
export default class ColladaModel extends Node { | ||
static defaultElementName = 'lume-collada-model' | ||
static defaultBehaviors = ['collada-model'] | ||
|
||
// FIXME, without this accessor, the src property of the | ||
// ColladaModelBehavior may not be initially triggered when using JSX as in | ||
// <lume-collada-model src={"path/to/file.dae"}>. Why? | ||
// This accessor should not be required, because the behaviors already | ||
// set up the observation mechanism on their host elements. | ||
get src() { | ||
return this.__src | ||
} | ||
set src(v) { | ||
this.__src = v | ||
} | ||
|
||
private __src: string = '' | ||
} | ||
|
||
export {ColladaModel} | ||
|
||
import type {ElementAttributes} from '@lume/element' | ||
|
||
declare module '@lume/element' { | ||
namespace JSX { | ||
interface IntrinsicElements { | ||
'lume-collada-model': ElementAttributes< | ||
ColladaModel, | ||
ColladaModelAttributes, | ||
ElementAttributes<ColladaModelBehavior, ColladaModelBehaviorAttributes> | ||
> | ||
} | ||
} | ||
} | ||
|
||
declare global { | ||
interface HTMLElementTagNameMap { | ||
'lume-collada-model': ColladaModel | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
packages/lume/src/html/behaviors/ColladaModelBehavior.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import 'element-behaviors' | ||
import {reactive, autorun, stringAttribute} from '@lume/element' | ||
import {ColladaLoader} from 'three/examples/jsm/loaders/ColladaLoader.js' | ||
import {disposeObjectTree} from '../../utils/three.js' | ||
import {Events} from '../../core/Events.js' | ||
import {RenderableBehavior} from './RenderableBehavior.js' | ||
|
||
import type {StopFunction} from '@lume/element' | ||
import type {Collada} from 'three/examples/jsm/loaders/ColladaLoader.js' | ||
|
||
export type ColladaModelBehaviorAttributes = 'src' | ||
|
||
@reactive | ||
export class ColladaModelBehavior extends RenderableBehavior { | ||
/** Path to a .dae file. */ | ||
@stringAttribute('') src = '' | ||
|
||
colladaLoader?: ColladaLoader | ||
model: Collada | null = null | ||
|
||
protected static _observedProperties = ['src', ...(RenderableBehavior._observedProperties || [])] | ||
|
||
// This is incremented any time we need a pending load() to cancel (f.e. on | ||
// src change, or unloadGL cycle), so that the loader will ignore the | ||
// result when a version change has happened. | ||
private __version = 0 | ||
|
||
private __stopFns: StopFunction[] = [] | ||
|
||
loadGL() { | ||
if (!super.loadGL()) return false | ||
|
||
this.colladaLoader = new ColladaLoader() | ||
|
||
this.__stopFns.push( | ||
autorun(() => { | ||
this.src | ||
console.log(this.src) | ||
|
||
this.__cleanupModel() | ||
|
||
// TODO We can update only the material or model specifically | ||
// instead of reloading the whole object. | ||
this.__version++ | ||
this.__loadObj() | ||
}), | ||
) | ||
|
||
return true | ||
} | ||
|
||
unloadGL() { | ||
if (!super.unloadGL()) return false | ||
|
||
for (const stop of this.__stopFns) stop() | ||
|
||
this.colladaLoader = undefined | ||
|
||
this.__cleanupModel() | ||
|
||
// Increment this in case the loader is still loading, so it will ignore the result. | ||
this.__version++ | ||
|
||
return true | ||
} | ||
|
||
private __cleanupModel() { | ||
if (this.model) disposeObjectTree(this.model.scene) | ||
this.model = null | ||
} | ||
|
||
private __loadObj() { | ||
const {src, __version} = this | ||
|
||
console.log('load model!!!!', src) | ||
|
||
if (!src) return | ||
|
||
// In the following colladaLoader.load() callbacks, if __version doesn't | ||
// match, it means this.src or this.dracoDecoder changed while | ||
// a previous model was loading, in which case we ignore that | ||
// result and wait for the next model to load. | ||
|
||
this.colladaLoader!.load( | ||
src, | ||
model => __version == this.__version && this.__setModel(model), | ||
progress => __version == this.__version && this.element.emit(Events.PROGRESS, progress), | ||
error => __version == this.__version && this.__onError(src, error), | ||
) | ||
} | ||
|
||
private __onError(src: string, error: ErrorEvent) { | ||
const message = error?.message ?? `Failed to load ${this.element.tagName.toLowerCase()} with src "${src}".` | ||
console.warn(message) | ||
this.element.emit(Events.COLLADA_ERROR, {src}) | ||
} | ||
|
||
private __setModel(model: Collada) { | ||
this.model = model | ||
this.element.three.add(model.scene) | ||
this.element.emit(Events.COLLADA_LOAD, {model}) | ||
this.element.needsUpdate() | ||
} | ||
} | ||
|
||
elementBehaviors.define('collada-model', ColladaModelBehavior) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters