Skip to content

Commit

Permalink
feat: add support for shared world items
Browse files Browse the repository at this point in the history
  • Loading branch information
agviegas committed Apr 20, 2024
1 parent 042c5f9 commit f6b716c
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 51 deletions.
56 changes: 37 additions & 19 deletions packages/components/src/core/Cameras/src/simple-camera.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class SimpleCamera extends BaseCamera implements Updateable, Disposable {

readonly three: THREE.PerspectiveCamera;

private _controls?: CameraControls;
private _allControls = new Map<string, CameraControls>();

/**
* The object that controls the camera. An instance of
Expand All @@ -38,14 +38,21 @@ export class SimpleCamera extends BaseCamera implements Updateable, Disposable {
* object to move, rotate, look at objects, etc.
*/
get controls() {
if (!this._controls) {
throw new Error("Camera not initialized!");
if (!this.currentWorld) {
throw new Error("This camera needs a world to work!");
}
const controls = this._allControls.get(this.currentWorld.uuid);
if (!controls) {
throw new Error("Controls not found!");
}
return this._controls;
return controls;
}

/** {@link Component.enabled} */
get enabled() {
if (this.currentWorld === null) {
return false;
}
return this.controls.enabled;
}

Expand All @@ -60,13 +67,22 @@ export class SimpleCamera extends BaseCamera implements Updateable, Disposable {

this.setupEvents(true);

this.onWorldChanged.add(() => {
this.onWorldChanged.add(({ action, world }) => {
// This makes sure the DOM element of the camera
// controls matches the one of the renderer
if (this._controls) {
this._controls.dispose();
// controls matches the one of the renderer for
// a specific world
if (action === "added") {
const controls = this.newCameraControls();
this._allControls.set(world.uuid, controls);
}

if (action === "removed") {
const controls = this._allControls.get(world.uuid);
if (controls) {
controls.dispose();
this._allControls.delete(world.uuid);
}
}
this._controls = this.newCameraControls();
});
}

Expand All @@ -78,17 +94,19 @@ export class SimpleCamera extends BaseCamera implements Updateable, Disposable {
this.onBeforeUpdate.reset();
this.onAfterUpdate.reset();
this.three.removeFromParent();
this.controls.dispose();
this.onDisposed.trigger();
this.onDisposed.reset();
for (const [_id, controls] of this._allControls) {
controls.dispose();
}
}

/** {@link Updateable.update} */
async update(_delta: number) {
update(_delta: number) {
if (this.enabled) {
await this.onBeforeUpdate.trigger(this);
this.onBeforeUpdate.trigger(this);
this.controls.update(_delta);
await this.onAfterUpdate.trigger(this);
this.onAfterUpdate.trigger(this);
}
}

Expand All @@ -97,9 +115,9 @@ export class SimpleCamera extends BaseCamera implements Updateable, Disposable {
* {@link Components.renderer}.
*/
updateAspect = () => {
if (!this.world || !this.world.renderer) return;
if (this.world.renderer?.isResizeable()) {
const size = this.world.renderer.getSize();
if (!this.currentWorld || !this.currentWorld.renderer) return;
if (this.currentWorld.renderer?.isResizeable()) {
const size = this.currentWorld.renderer.getSize();
this.three.aspect = size.width / size.height;
this.three.updateProjectionMatrix();
this.onAspectUpdated.trigger();
Expand All @@ -115,14 +133,14 @@ export class SimpleCamera extends BaseCamera implements Updateable, Disposable {
}

private newCameraControls() {
if (!this.world) {
if (!this.currentWorld) {
throw new Error("This camera needs a world to work!");
}
if (!this.world.renderer) {
if (!this.currentWorld.renderer) {
throw new Error("This camera needs a renderer to work!");
}
CameraControls.install({ THREE: SimpleCamera.getSubsetOfThree() });
const { domElement } = this.world.renderer.three;
const { domElement } = this.currentWorld.renderer.three;
const controls = new CameraControls(this.three, domElement);
controls.smoothTime = 0.2;
controls.dollyToCursor = true;
Expand Down
6 changes: 3 additions & 3 deletions packages/components/src/core/Renderers/src/simple-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ export class SimpleRenderer extends BaseRenderer {

/** {@link Updateable.update} */
update() {
if (!this.enabled || !this.world) return;
if (!this.enabled || !this.currentWorld) return;
this.onBeforeUpdate.trigger(this);
const scene = this.world.scene.three;
const camera = this.world.camera.three;
const scene = this.currentWorld.scene.three;
const camera = this.currentWorld.camera.three;
this.three.render(scene, camera);
if (scene instanceof THREE.Scene) {
this._renderer2D.render(scene, camera);
Expand Down
26 changes: 15 additions & 11 deletions packages/components/src/core/Types/src/base-world-item.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
import { Base } from "./base";
import { World } from "./world";
import { Event } from "./event";
import { Components } from "../../Components";

/**
* One of the elements that make a world. It can be either a scene, a camera
* or a renderer.
*/
export abstract class BaseWorldItem extends Base {
private _world: World | null = null;
readonly worlds = new Map<string, World>();

readonly onWorldChanged = new Event<World | null>();
readonly onWorldChanged = new Event<{
world: World;
action: "added" | "removed";
}>();

get world() {
if (!this._world) {
throw new Error("World not initialized!");
}
return this._world;
}
currentWorld: World | null = null;

protected constructor(components: Components) {
super(components);

set world(world: World | null) {
this._world = world;
this.onWorldChanged.trigger(world);
this.onWorldChanged.add(({ world, action }) => {
if (action === "removed") {
this.worlds.delete(world.uuid);
}
});
}
}
60 changes: 42 additions & 18 deletions packages/components/src/core/Worlds/src/simple-world.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,10 @@ export class SimpleWorld extends Base implements World {
}

set scene(scene: BaseScene) {
if (this._scene) {
this._scene.world = null;
}
this._scene = scene;
scene.world = this;
scene.worlds.set(this.uuid, this);
scene.currentWorld = this;
scene.onWorldChanged.trigger({ world: this, action: "added" });
}

get camera() {
Expand All @@ -49,24 +48,22 @@ export class SimpleWorld extends Base implements World {
}

set camera(camera: BaseCamera) {
if (this._camera) {
this._camera.world = null;
}
this._camera = camera;
camera.world = this;
camera.worlds.set(this.uuid, this);
camera.currentWorld = this;
camera.onWorldChanged.trigger({ world: this, action: "added" });
}

get renderer() {
return this._renderer;
}

set renderer(renderer: BaseRenderer | null) {
if (this._renderer) {
this._renderer.world = null;
}
this._renderer = renderer;
if (renderer) {
renderer.world = this;
renderer.worlds.set(this.uuid, this);
renderer.currentWorld = this;
renderer.onWorldChanged.trigger({ world: this, action: "added" });
}
}

Expand All @@ -76,24 +73,51 @@ export class SimpleWorld extends Base implements World {

update(delta?: number) {
if (!this.enabled) return;

this.scene.currentWorld = this;
this.camera.currentWorld = this;
if (this.renderer) {
this.renderer.currentWorld = this;
}

this.onBeforeUpdate.trigger();

if (this.scene.isUpdateable()) {
this.scene.update(delta);
}

if (this.camera.isUpdateable()) {
this.camera.update(delta);
}

if (this.renderer) {
this.renderer.update(delta);
}

this.onAfterUpdate.trigger();
}

dispose() {
dispose(disposeResources = true) {
this.enabled = false;
this.scene.dispose();
if (this.camera.isDisposeable()) {
this.camera.dispose();
}

this.scene.onWorldChanged.trigger({ world: this, action: "removed" });
this.camera.onWorldChanged.trigger({ world: this, action: "removed" });
if (this.renderer) {
this.renderer.dispose();
this.renderer.onWorldChanged.trigger({ world: this, action: "removed" });
}

if (disposeResources) {
this.scene.dispose();
if (this.camera.isDisposeable()) {
this.camera.dispose();
}
if (this.renderer) {
this.renderer.dispose();
}
}

this._scene = null as any;
this._camera = null as any;
this._renderer = null as any;
}
}

0 comments on commit f6b716c

Please sign in to comment.