Skip to content

Commit ee7fbf0

Browse files
author
Sascha Braun
committed
add first (unstable) version of asset bundle to replace preload slot in scene
1 parent 16e2233 commit ee7fbf0

File tree

11 files changed

+368
-61
lines changed

11 files changed

+368
-61
lines changed

samples/views/Demo.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ export default class About extends Vue {
9898
}
9999

100100
public created() {
101+
console.log("scene", this.scene1);
102+
101103
let idx = 0;
102104
for (let x = 0; x < 5; ++x) {
103105
for (let z = 0; z < 5; ++z) {
@@ -111,8 +113,10 @@ export default class About extends Vue {
111113
}
112114
}
113115

114-
this.cubeFactory = async () => {
116+
this.cubeFactory = async (app: Application) => {
115117
// await new Promise(r => setTimeout(r, 2000));
118+
// return new THREE.CylinderBufferGeometry(1, 1, 1, 6, 6);
119+
116120
return new THREE.BoxBufferGeometry(1, 1, 1);
117121
};
118122
this.planeFactory = async () => {

samples/views/Demo.vue

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,30 @@
2424
<three>
2525
<renderer :canvas="canvas" camera="main" :scene="activeScene" antialias shadows/>
2626

27-
<scene name="scene1" @load="startLoading" @load-progress="loadingProgress" @loaded="finishLoading">
28-
<template slot="preload">
29-
<div>
30-
<texture name="crateTex" src="/assets/textures/crate.jpg"/>
31-
<material name="cubeMat" :factory="cubeMaterialFactory"/>
27+
<asset-bundle name="PolygonMini" preload>
28+
<texture name="PolygonMini_Tex" src="/assets/textures/PolygonMinis_Texture_01.png"/>
3229

33-
<texture name="PolygonMini_Tex" src="/assets/textures/PolygonMinis_Texture_01.png"/>
34-
<material name="PolygonMini_Mat" :factory="polygonMaterialFactory"/>
30+
<material name="PolygonMini_Mat" :factory="polygonMaterialFactory"/>
3531

36-
<geometry name="cube" :factory="cubeFactory"/>
32+
<model name="grassModel" src="/assets/models/SM_Env_Grass_01.fbx" materials="PolygonMini_Mat"/>
33+
<model name="PM_column" src="/assets/models/SM_Tile_Hex_Column_02.fbx" materials="PolygonMini_Mat"/>
34+
<model name="PM_flat" src="/assets/models/SM_Tile_Hex_Flat_01.fbx" materials="PolygonMini_Mat"/>
35+
</asset-bundle>
3736

38-
<model name="grassModel" src="/assets/models/SM_Env_Grass_01.fbx" materials="PolygonMini_Mat"/>
39-
<model name="PM_column" src="/assets/models/SM_Tile_Hex_Column_02.fbx" materials="PolygonMini_Mat"/>
40-
<model name="PM_flat" src="/assets/models/SM_Tile_Hex_Flat_01.fbx" materials="PolygonMini_Mat"/>
41-
</div>
37+
<asset-bundle name="Crate" preload>
38+
<texture name="crateTex" src="/assets/textures/crate.jpg"/>
39+
<material name="cubeMat" :factory="cubeMaterialFactory"/>
40+
<geometry name="cube" :factory="cubeFactory"/>
41+
</asset-bundle>
4242

43-
<geometry name="plane" :factory="planeFactory"/>
44-
<material name="waterMat" :factory="waterMaterialFactory"/>
43+
<asset-bundle dependencies="Crate" name="Scene1" preload>
4544

46-
</template>
45+
<geometry name="plane" :factory="planeFactory"/>
46+
<material name="waterMat" :factory="waterMaterialFactory"/>
47+
48+
</asset-bundle>
49+
50+
<scene name="scene1" assets="PolygonMini, Scene1, Crate, Crate" @load="startLoading" @load-progress="loadingProgress" @loaded="finishLoading">
4751

4852
<fog exp2/>
4953

@@ -114,7 +118,7 @@
114118

115119
</scene>
116120

117-
<scene name="scene2" @load="startLoading" @load-progress="loadingProgress" @loaded="finishLoading">
121+
<scene name="scene2" assets="PolygonMini, Scene1, Crate, Crate" @load="startLoading" @load-progress="loadingProgress" @loaded="finishLoading">
118122
<!-- <template slot="preload">
119123
<material name="scene2_mat" :factory="materialFactory"/>
120124
<geometry name="scene2_field" :factory="geometryFactory"/>

src/components/AssetBundle.ts

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import Vue, { VNode } from "vue";
2+
import { Component, Mixins, Prop } from "vue-property-decorator";
3+
4+
import { AssetBundle as Bundle } from "../core";
5+
import { isThreeAssetComponent, ThreeComponent } from "./base";
6+
7+
@Component
8+
export class AssetBundle extends Mixins(ThreeComponent) {
9+
@Prop({ type: String, default: "" })
10+
public name!: string;
11+
12+
@Prop({ type: Boolean, default: false })
13+
public preload!: boolean;
14+
15+
@Prop({ type: [String, Array], default: () => [] })
16+
public dependencies!: string | string[];
17+
18+
private m_isActive = false;
19+
private m_bundle!: Bundle;
20+
21+
public mounted() {
22+
const manager = this.app().assets;
23+
this.m_bundle = manager.createBundle(this.name);
24+
this.m_bundle.onload = this.onLoadBundle;
25+
this.m_bundle.onunload = this.onUnloadBundle;
26+
// TODO handle preload on / off
27+
// this.m_bundle.preload = this.preload;
28+
}
29+
30+
public beforeDestroy() {
31+
const manager = this.app().assets;
32+
manager.deleteBundle(this.name);
33+
}
34+
35+
public render(h: any) {
36+
if (!this.m_isActive) {
37+
return null;
38+
}
39+
return h("div", this.$slots.default);
40+
}
41+
42+
private async onLoadBundle(): Promise<void> {
43+
this.m_isActive = true;
44+
45+
const bundles = this.getBundles(this.dependencies);
46+
const deps = this.m_bundle.registerDependencies(bundles);
47+
48+
await Vue.nextTick();
49+
await deps;
50+
51+
console.log("load assets for bundle ", this.name);
52+
53+
this.registerAssets(this.$slots.default);
54+
}
55+
56+
private async onUnloadBundle() {
57+
this.m_isActive = false;
58+
}
59+
60+
private registerAssets(nodes: VNode[] | undefined) {
61+
if (nodes) {
62+
for (const node of nodes) {
63+
const component = node.componentInstance;
64+
if (component && isThreeAssetComponent(component)) {
65+
this.m_bundle.registerAsset(component.asset);
66+
}
67+
this.registerAssets(node.children);
68+
}
69+
}
70+
}
71+
72+
private getBundles(dependencies: string | string[]): Bundle[] {
73+
const manager = this.app().assets;
74+
const bundles: Bundle[] = [];
75+
76+
if (!dependencies) {
77+
return bundles;
78+
}
79+
if (typeof dependencies === "string") {
80+
dependencies = dependencies.split(",").map(mat => mat.trim());
81+
}
82+
if (!Array.isArray(dependencies)) {
83+
throw new Error(
84+
`AssetBundle "${
85+
this.name
86+
}" could not be loaded: "dependencies" have to be either a string or an array`
87+
);
88+
}
89+
(dependencies as string[]).forEach(dep => {
90+
const bundle = manager.getBundle(dep);
91+
if (bundle) {
92+
bundles.push(bundle);
93+
}
94+
});
95+
return bundles;
96+
}
97+
}

src/components/Model.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export class Model extends Mixins(ThreeComponent, ThreeAssetComponent) {
1515
@Prop({ type: String })
1616
public src!: string;
1717

18-
@Prop({ default: [] })
18+
@Prop({ type: [String, Array], default: () => [] })
1919
public materials!: string | string[];
2020

2121
public async created() {

src/components/Scene.ts

Lines changed: 64 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@ import * as THREE from "three";
22
import { VNode } from "vue";
33
import { Component, Mixins, Prop, Provide, Vue, Watch } from "vue-property-decorator";
44

5-
import { AssetType } from "../types";
6-
import { isThreeAssetComponent, ThreeAssetComponent, ThreeComponent } from "./base";
5+
import { AssetBundle } from "../core";
6+
import { AssetType, OnLoadAssetBundleData } from "../types";
7+
import { isThreeAssetComponent, ThreeComponent } from "./base";
78

89
@Component
910
export class Scene extends Mixins(ThreeComponent) {
1011
@Prop({ type: String, default: "" })
1112
public name!: string;
1213

14+
@Prop({ type: [String, Array], default: () => [] })
15+
public assets!: string | string[];
16+
1317
@Provide("scene")
1418
private provideScene = this.getScene;
1519

@@ -20,6 +24,7 @@ export class Scene extends Mixins(ThreeComponent) {
2024
private m_isActive = false;
2125
private m_isReady = false;
2226
private m_scene?: THREE.Scene;
27+
private m_bundle!: AssetBundle;
2328

2429
@Watch("name")
2530
private watchName() {
@@ -36,11 +41,15 @@ export class Scene extends Mixins(ThreeComponent) {
3641
// deactive children
3742
this.m_isReady = false;
3843

44+
console.log("scene bundle unuse");
45+
46+
await this.m_bundle.unuse();
3947
await Vue.nextTick();
4048

4149
if (this.m_scene) {
4250
this.app().sceneManager.remove(this.m_scene.name);
4351
}
52+
4453
this.m_isActive = false;
4554
this.m_scene = undefined;
4655
}
@@ -51,8 +60,6 @@ export class Scene extends Mixins(ThreeComponent) {
5160

5261
// tell the component to render the component (see render)
5362
this.m_isActive = true;
54-
// wait for preload components to load...
55-
await Vue.nextTick();
5663

5764
// now preload
5865
await this.preloadAssets();
@@ -61,40 +68,60 @@ export class Scene extends Mixins(ThreeComponent) {
6168
}
6269

6370
public mounted() {
71+
this.m_bundle = new AssetBundle(this.app());
72+
this.m_bundle.onload = async () => {
73+
const bundles = this.getBundles(this.assets);
74+
console.log("scene load bundles", bundles);
75+
await this.m_bundle.registerDependencies(bundles);
76+
};
77+
6478
const manager = this.app().sceneManager;
6579
manager.on("activate", this.onSceneActivate);
6680
manager.on("deactivate", this.onSceneDeactivate);
6781
this.watchName();
6882
}
6983

7084
public beforeDestroy() {
85+
this.m_bundle.unuse();
86+
7187
const manager = this.app().sceneManager;
7288
manager.off("activate", this.onSceneActivate);
7389
manager.off("deactivate", this.onSceneDeactivate);
7490
this.onDeactivate();
7591
}
7692

7793
public render(h: any) {
78-
if (!this.m_isActive) {
94+
if (!this.m_isActive || !this.m_isReady) {
7995
return null;
8096
}
8197

82-
return h("div", [
83-
h("div", this.$slots.preload),
84-
h("div", this.m_isReady ? this.$slots.default : null)
85-
]);
98+
return h("div", this.$slots.default);
8699
}
87100

88101
private async preloadAssets() {
89102
this.$emit("load");
90103

91-
const data: { counter: number; assets: Array<Promise<AssetType>> } = {
92-
assets: [],
93-
counter: 0
104+
const data = {
105+
count: 0,
106+
amount: 0
107+
};
108+
109+
const progressListener = () => {
110+
++data.amount;
111+
console.log(data.amount, data.count);
112+
this.$emit("load-progress", data.amount, data.count);
94113
};
95-
this.recursivePreload(data, this.$slots.preload);
96114

97-
await Promise.all(data.assets);
115+
await this.m_bundle.use(progressListener);
116+
117+
// we can now count assets to be loaded..
118+
data.count = AssetBundle.countAssets([this.m_bundle]);
119+
120+
console.log("count", data.count);
121+
122+
await this.m_bundle.isReady();
123+
124+
console.log("loaded!");
98125
this.$emit("loaded");
99126
}
100127

@@ -111,23 +138,29 @@ export class Scene extends Mixins(ThreeComponent) {
111138
this.onDeactivate();
112139
};
113140

114-
private recursivePreload(
115-
data: { counter: number; assets: Array<Promise<AssetType>> },
116-
nodes: VNode[] | undefined
117-
) {
118-
if (nodes) {
119-
for (const node of nodes) {
120-
const component = node.componentInstance;
121-
if (component && isThreeAssetComponent(component)) {
122-
const p = component.asset.then(asset => {
123-
++data.counter;
124-
this.$emit("load-progress", data.counter, data.assets.length);
125-
return asset;
126-
});
127-
data.assets.push(p);
128-
}
129-
this.recursivePreload(data, node.children);
130-
}
141+
private getBundles(dependencies: string | string[]): AssetBundle[] {
142+
const manager = this.app().assets;
143+
const bundles: AssetBundle[] = [];
144+
145+
if (!dependencies) {
146+
return bundles;
147+
}
148+
if (typeof dependencies === "string") {
149+
dependencies = dependencies.split(",").map(mat => mat.trim());
131150
}
151+
if (!Array.isArray(dependencies)) {
152+
throw new Error(
153+
`AssetBundle "${
154+
this.name
155+
}" could not be loaded: "dependencies" have to be either a string or an array`
156+
);
157+
}
158+
(dependencies as string[]).forEach(dep => {
159+
const bundle = manager.getBundle(dep);
160+
if (bundle) {
161+
bundles.push(bundle);
162+
}
163+
});
164+
return bundles;
132165
}
133166
}

src/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ export * from "./Grid";
1212
export * from "./Axes";
1313
export * from "./Model";
1414
export * from "./Renderer";
15+
export * from "./AssetBundle";
1516

1617
export * from "./properties";

src/core/Application.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export class Application {
1616
public readonly sceneManager = new SceneManager();
1717
public readonly cameraManager = new CameraManager();
1818
public readonly renderers = new RendererManager(this);
19-
public readonly assets = new AssetManager();
19+
public readonly assets = new AssetManager(this);
2020
public readonly inputs = new InputManager();
2121

2222
private _disposed = false;

0 commit comments

Comments
 (0)