From f5c3554dacee67c1aae1c76d63629a94283d691f Mon Sep 17 00:00:00 2001 From: Paul Shannon Date: Mon, 23 Oct 2017 12:23:47 -0700 Subject: [PATCH] Upgrade Dojo 2 to 0.1.0 --- package.json | 14 ++-- src/App.ts | 27 ++------ src/components/pokeControl.ts | 42 ++++++++++++ src/components/trackPosition.ts | 39 ------------ src/configuration/monsters.ts | 33 ++++++++++ src/containers/AssetContainer.ts | 13 ++++ src/containers/OutsideContainer.ts | 34 ++++++++++ src/context/AppContext.ts | 48 ++++++++++++++ src/context/OutsideContext.ts | 83 ++++++++++++++++++++++++ src/definitions/characters.ts | 32 ---------- src/framework/Container.ts | 26 ++++++++ src/framework/Executor.ts | 0 src/framework/InjectorBase.ts | 19 ++++++ src/framework/inject.ts | 88 ++++++++++++++++++++++++++ src/framework/util/genericMapper.ts | 7 -- src/initialize.ts | 33 +++++++--- src/interfaces.d.ts | 7 ++ src/main.ts | 4 +- src/stages/Outside.ts | 36 ----------- src/util/properties.ts | 31 +++++++++ src/{framework => widgets}/Assets.ts | 18 +++--- src/{framework => widgets}/Controls.ts | 6 +- src/{framework => widgets}/ObjModel.ts | 21 ------ src/widgets/Outside.ts | 39 ++++++++++++ src/widgets/meta/BoundingBox.ts | 15 +++++ tests/unit/App.ts | 2 +- tests/unit/stages/Outside.ts | 14 +--- 27 files changed, 531 insertions(+), 200 deletions(-) create mode 100644 src/components/pokeControl.ts delete mode 100644 src/components/trackPosition.ts create mode 100644 src/configuration/monsters.ts create mode 100644 src/containers/AssetContainer.ts create mode 100644 src/containers/OutsideContainer.ts create mode 100644 src/context/AppContext.ts create mode 100644 src/context/OutsideContext.ts delete mode 100644 src/definitions/characters.ts create mode 100644 src/framework/Container.ts create mode 100644 src/framework/Executor.ts create mode 100644 src/framework/InjectorBase.ts create mode 100644 src/framework/inject.ts delete mode 100644 src/framework/util/genericMapper.ts create mode 100644 src/interfaces.d.ts delete mode 100644 src/stages/Outside.ts create mode 100644 src/util/properties.ts rename src/{framework => widgets}/Assets.ts (66%) rename src/{framework => widgets}/Controls.ts (85%) rename src/{framework => widgets}/ObjModel.ts (54%) create mode 100644 src/widgets/Outside.ts create mode 100644 src/widgets/meta/BoundingBox.ts diff --git a/package.json b/package.json index 434080d..1c1fd61 100644 --- a/package.json +++ b/package.json @@ -9,17 +9,19 @@ "watch": "dojo build -w" }, "dependencies": { - "@dojo/core": "next", - "@dojo/has": "next", - "@dojo/i18n": "next", - "@dojo/routing": "next", - "@dojo/shim": "next", - "@dojo/widget-core": "next", + "@dojo/core": "^0.1.0", + "@dojo/has": "^0.1.0", + "@dojo/i18n": "^0.1.0", + "@dojo/routing": "^0.1.0", + "@dojo/shim": "^0.1.0", + "@dojo/widget-core": "^0.1.0", "@types/aframe": "^0.5.0", "@webcomponents/custom-elements": "^1.0.2", "@webcomponents/html-imports": "^1.0.1", "aframe": "^0.7.0", "aframe-environment-component": "^1.0.0", + "aframe-physics-system": "^2.1.0", + "cannon": "^0.6.2", "maquette": "devpaul/maquette#custom-elements-dist" }, "devDependencies": { diff --git a/src/App.ts b/src/App.ts index be080a6..9f8f5e6 100644 --- a/src/App.ts +++ b/src/App.ts @@ -1,33 +1,16 @@ import { v, w } from '@dojo/widget-core/d'; import { DNode, WidgetProperties } from '@dojo/widget-core/interfaces'; import { WidgetBase } from '@dojo/widget-core/WidgetBase'; -import Outside from './stages/Outside'; -import Assets from './framework/Assets'; -import { MonsterName, monsters } from './definitions/characters'; -import { Container } from '@dojo/widget-core/Container'; -import Controls from './framework/Controls'; -import genericMapper from './framework/util/genericMapper'; +import Controls from './widgets/Controls'; +import AssetContainer from './containers/AssetContainer'; +import OutsideContainer from './containers/OutsideContainer'; export default class App extends WidgetBase { - private static selectMonster(): MonsterName { - const num = Math.floor(Math.random() * monsters.length); - return monsters[num]; - } - - monster = App.selectMonster(); - - distance = Math.random() * 8 + 2; - protected render(): DNode { - const AssetEntity = Container(Assets, 'assets', genericMapper()); - return v('a-scene', [ - w(AssetEntity, { }), + w(AssetContainer, {}), w(Controls, {}), - w(Outside, { - monster: this.monster, - monsterDistance: this.distance - }), + w(OutsideContainer, {}), ]); } } diff --git a/src/components/pokeControl.ts b/src/components/pokeControl.ts new file mode 100644 index 0000000..7cf4c4c --- /dev/null +++ b/src/components/pokeControl.ts @@ -0,0 +1,42 @@ +import { Handle } from '@dojo/interfaces/core'; +import { createHandle } from '@dojo/core/lang'; +import { EventHandler } from '@dojo/widget-core/interfaces'; +const AFrame = require('aframe'); + +export const componentName = 'poke-control'; + +export default function register() { + AFrame.registerComponent(componentName, { + eventHandles: [] as Handle[], + + init() { + }, + + play() { + const el = this.el; + const events: { [key: string ]: EventHandler } = { + 'trackpadup': (event: Event) => { + this.onButtonUp(event); + }, + 'trackpaddown': (event: Event) => { + this.onButtonDown(event); + } + }; + + for (let eventName in events) { + const handler = events[eventName]; + el.addEventListener(eventName, handler); + this.eventHandles.push(createHandle(() => { + el.removeEventListener(eventName, handler); + })); + } + }, + + pause() { + while (this.eventHandles.length) { + const handle = this.eventHandles.pop(); + handle.destroy(); + } + } + }); +} diff --git a/src/components/trackPosition.ts b/src/components/trackPosition.ts deleted file mode 100644 index 6647815..0000000 --- a/src/components/trackPosition.ts +++ /dev/null @@ -1,39 +0,0 @@ -const AFrame = require('aframe'); - -export const trackPosition = 'track-position'; - -interface TrackPositionProperties extends AFrame.Component { - controllerBody: THREE.Object3D; -} - -export default function register() { - AFrame.registerComponent(trackPosition, { - schema: { - type: 'string' - }, - - init() { - - }, - - update() { - const targetName = this.data; - const target = document.querySelector(targetName); - // TODO used with Daydream controller models - this.controllerBody = target.getObjectByName('Body_Body_Cylinder'); - }, - - tick(this: TrackPositionProperties) { - if (!this.controllerBody) { - return; - } - const controllerObj = this.controllerBody.geometry; - this.el!.setAttribute('position', position); - }, - - getBoundingSphere() { - - } - }); -} - diff --git a/src/configuration/monsters.ts b/src/configuration/monsters.ts new file mode 100644 index 0000000..600c1a1 --- /dev/null +++ b/src/configuration/monsters.ts @@ -0,0 +1,33 @@ +import { Environment, MonsterDefinition } from '../context/OutsideContext'; +import { ObjModelAsset } from '../interfaces'; +import { assign } from '@dojo/shim/object'; + +declare type MonsterConfigurationItem = MonsterDefinition & ObjModelAsset; + +export const enum MonsterName { + CharDerp = 'charderp', + Robot = 'robot' +} + +const assetFolder = 'assets/characters/'; + +function createMonster(name: string): { name: string } & ObjModelAsset { + return { + name, + mtl: `${ assetFolder }${ name }.mtl`, + obj: `${ assetFolder }${ name }.obj` + }; +} + +const monsters: Array = [ + assign(createMonster(MonsterName.CharDerp), { + environment: Environment.Forest, + heights: { min: 1.5, max: 2 } + }), + assign(createMonster(MonsterName.Robot), { + environment: Environment.Forest, + heights: { min: 1.5, max: 2 } + }) +]; + +export default monsters; diff --git a/src/containers/AssetContainer.ts b/src/containers/AssetContainer.ts new file mode 100644 index 0000000..9932895 --- /dev/null +++ b/src/containers/AssetContainer.ts @@ -0,0 +1,13 @@ +import Container from '../framework/Container'; +import Assets from '../widgets/Assets'; +import AppContext from '../context/AppContext'; + +const AssetContainer = Container(Assets, 'app-state', { + getProperties(context: AppContext) { + return { + assets: context.assets + } + } +}); + +export default AssetContainer; diff --git a/src/containers/OutsideContainer.ts b/src/containers/OutsideContainer.ts new file mode 100644 index 0000000..899fbbf --- /dev/null +++ b/src/containers/OutsideContainer.ts @@ -0,0 +1,34 @@ +import Outside, { OutsideProperties } from '../widgets/Outside'; +import Container from '../framework/Container'; +import { throws } from '../util/properties'; +import OutsideContext from '../context/OutsideContext'; +import AppContext from '../context/AppContext'; + +const OutsideContainer = Container(Outside, [ 'outside', 'app-state' ], { + getProperties(payload: [OutsideContext, AppContext]): OutsideProperties { + const [ + outside = throws(), + appContext = throws() + ] = payload; + let monster: OutsideProperties['monster']; + const monsterInfo = outside.monster; + if (monsterInfo) { + const assets = appContext.getObjMtlAssets(monsterInfo.name); + if (assets && assets.obj && assets.mtl) { + monster = { + distance: monsterInfo.distance, + height: monsterInfo.height, + mtl: `#${ assets.mtl.id }`, + name: monsterInfo.name, + obj: `#${ assets.obj.id }` + } + } + } + return { + environment: outside.environment, + monster + } + } +}); + +export default OutsideContainer; diff --git a/src/context/AppContext.ts b/src/context/AppContext.ts new file mode 100644 index 0000000..a5243f5 --- /dev/null +++ b/src/context/AppContext.ts @@ -0,0 +1,48 @@ +import { InjectorBase } from '../framework/InjectorBase'; + +/** + * Application Asset used for loading models, video, and images by A-Frame's + */ +export interface Asset { + id: string; + src: string; +} + +export default class AppContext extends InjectorBase { + private _assets: Map = new Map(); + + /** + * @return a list of all active assets + */ + get assets(): Asset[] { + return Array.from(this._assets.values()); + } + + /** + * Adds an asset + */ + addAsset(id: string, src: string) { + if (!this._assets.has(id)) { + this._assets.set(id, { + id, + src + }); + this.emitInvalidate(); + } + } + + /** + * Adds an Obj model asset + */ + addObjMtlAssets(name: string, objSrc: string, mtlSrc?: string) { + this.addAsset(`${ name }-obj`, objSrc); + mtlSrc && this.addAsset(`${ name }-mtl`, mtlSrc); + } + + getObjMtlAssets(name: string): { mtl?: Asset, obj?: Asset } { + return { + mtl: this._assets.get(`${ name }-mtl`), + obj: this._assets.get(`${ name }-obj`) + } + } +} diff --git a/src/context/OutsideContext.ts b/src/context/OutsideContext.ts new file mode 100644 index 0000000..85c25b6 --- /dev/null +++ b/src/context/OutsideContext.ts @@ -0,0 +1,83 @@ +import { InjectorBase } from '../framework/InjectorBase'; +import { ObjModelAsset } from '../interfaces'; + +interface Monster { + distance: number; + height: number; + name: string; +} + +export const enum Environment { + Checkerboard = 'checkerboard', + Desert = 'egypt', + Forest = 'forest' +} + +/** + * Defines a monster's traits + */ +export interface MonsterDefinition { + /** environment where the monster appears */ + environment: Environment; + /** the range of heights for this monster */ + heights: { + min: number, + max: number + }; + /** The name of the monster */ + name: string; +} + +export default class OutsideContext extends InjectorBase { + private _environment: Environment = Environment.Forest; + private _monster?: Monster; + private _monsterDefinitions: Map = new Map(); + + get environment(): Environment { + return this._environment; + } + + get monster(): Monster | undefined { + return this._monster; + } + + addMonster(definitions: MonsterDefinition) { + this._monsterDefinitions.set(definitions.name, definitions); + } + + randomizeEncounter() { + const { + heights, + name, + } = this.randomMonster(); + const distance = Math.random() * 8 + 2; + const height = Math.random() * (heights.max - heights.min) + heights.min; + + this.setMonster({ + name, + height, + distance + }); + } + + setEnvironment(name: Environment) { + if (this._environment !== name) { + this._environment = name; + this.emitInvalidate(); + } + } + + setMonster(monster: Monster | undefined) { + if (this._monster !== monster) { + this._monster = monster; + this.emitInvalidate(); + } + } + + private randomMonster() { + const max = this._monsterDefinitions.size; + const num = Math.floor(Math.random() * max); + const definitions = Array.from(this._monsterDefinitions.values()); + return definitions[num]; + } +} diff --git a/src/definitions/characters.ts b/src/definitions/characters.ts deleted file mode 100644 index 969c2a1..0000000 --- a/src/definitions/characters.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { registry } from '@dojo/widget-core/d'; -import { BaseInjector, Context, Injector } from '@dojo/widget-core/Injector'; -import { Asset } from '../framework/Assets'; - -export const enum MonsterName { - CharDerp = 'charderp', - Robot = 'robot' -} - -export const monsters: ReadonlyArray = Object.freeze([ MonsterName.CharDerp, MonsterName.Robot ]); - -export function initialize() { - const assets: Asset[] = []; - - for (let monster of monsters) { - const obj = `${ monster }-obj`; - const mtl = `${ monster }-mtl`; - - const definition = { - name: monster, - src: `#${ obj }`, - mtl: `#${ mtl }` - }; - - registry.define(monster, Injector(BaseInjector, new Context(definition))); - assets.push({ id: obj, src: `assets/characters/${ monster }.obj`}); - assets.push({ id: mtl, src: `assets/characters/${ monster }.mtl`}); - } - - registry.define('assets', Injector(BaseInjector, new Context({ assets }))); -} - diff --git a/src/framework/Container.ts b/src/framework/Container.ts new file mode 100644 index 0000000..b08397a --- /dev/null +++ b/src/framework/Container.ts @@ -0,0 +1,26 @@ +import { WidgetBase } from '@dojo/widget-core/WidgetBase'; +import { Constructor, DNode, RegistryLabel } from '@dojo/widget-core/interfaces'; +import { w } from '@dojo/widget-core/d'; +import { inject, GetProperties } from './inject'; + +export type Container = Constructor>>; + +export function Container ( + component: Constructor | RegistryLabel, + name: RegistryLabel | RegistryLabel[], + { getProperties }: { getProperties: GetProperties } +): Container { + @inject({ name, getProperties }) + class WidgetContainer extends WidgetBase> { + public __setProperties__(properties: Partial): void { + super.__setProperties__(properties as any); + this.invalidate(); + } + protected render(): DNode { + return w(component, this.properties, this.children); + } + } + return WidgetContainer; +} + +export default Container; diff --git a/src/framework/Executor.ts b/src/framework/Executor.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/framework/InjectorBase.ts b/src/framework/InjectorBase.ts new file mode 100644 index 0000000..b5b059c --- /dev/null +++ b/src/framework/InjectorBase.ts @@ -0,0 +1,19 @@ +import Injector from '@dojo/widget-core/Injector'; + +export class InjectorBase extends Injector { + constructor() { + super({}); + } + + get(): this { + return this; + } + + set() { + throw new Error('not implemented'); + } + + protected emitInvalidate() { + this.emit({type: 'invalidate'}); + } +} diff --git a/src/framework/inject.ts b/src/framework/inject.ts new file mode 100644 index 0000000..8b3c73c --- /dev/null +++ b/src/framework/inject.ts @@ -0,0 +1,88 @@ +import WeakMap from '@dojo/shim/WeakMap'; +import { RegistryLabel } from '@dojo/widget-core/interfaces'; +import beforeProperties from '@dojo/widget-core/decorators/beforeProperties'; +import Injector from '@dojo/widget-core/Injector'; +import handleDecorator from '@dojo/widget-core/decorators/handleDecorator'; +import RegistryHandler from '@dojo/widget-core/RegistryHandler'; +import Evented from '@dojo/core/Evented'; + +/** + * Map of instances against registered injectors. + */ +const registeredInjectorsMap: WeakMap = new WeakMap(); + +/** + * Defines the contract requires for the get properties function + * used to map the injected properties. + */ +export interface GetProperties { + (payload: any, properties: T): T; +} + +/** + * Defines the inject configuration required for use of the `inject` decorator + */ +export interface InjectConfig { + + /** + * The label of the registry injector + */ + name: RegistryLabel | RegistryLabel[]; + + /** + * Function that returns propertues to inject using the passed properties + * and the injected payload. + */ + getProperties: GetProperties; +} + +export interface InjectionTarget extends Evented { + registry: RegistryHandler; +} + +function registerInjector(target: InjectionTarget, injector: Injector) { + const registeredInjectors = registeredInjectorsMap.get(target) || []; + if (registeredInjectors.length === 0) { + registeredInjectorsMap.set(target, registeredInjectors); + } + if (registeredInjectors.indexOf(injector) === -1) { + injector.on('invalidate', () => { + target.emit({type: 'invalidated', target }); + }); + registeredInjectors.push(injector); + } +} + +/** + * Decorator retrieves an injector from an available registry using the name and + * calls the `getProperties` function with the payload from the injector + * and current properties with the the injected properties returned. + * + * @param InjectConfig the inject configuration + */ +export function inject({ name, getProperties }: InjectConfig) { + return handleDecorator((target, propertyKey) => { + beforeProperties(function(this: InjectionTarget, properties: any) { + if (Array.isArray(name)) { + const payload = []; + for (let injectorName of name) { + const injector = this.registry.getInjector(injectorName); + if (injector) { + registerInjector(this, injector); + } + payload.push(injector && injector.get()); + } + return getProperties(payload, properties); + } + else { + const injector = this.registry.getInjector(name); + if (injector) { + registerInjector(this, injector); + } + return getProperties(injector && injector.get(), properties); + } + })(target); + }); +} + +export default inject; diff --git a/src/framework/util/genericMapper.ts b/src/framework/util/genericMapper.ts deleted file mode 100644 index 4fad181..0000000 --- a/src/framework/util/genericMapper.ts +++ /dev/null @@ -1,7 +0,0 @@ -export default function genericMapper() { - return { - getProperties(context: any): T { - return context.get(); - } - } -} diff --git a/src/initialize.ts b/src/initialize.ts index 3e5fadb..48cf960 100644 --- a/src/initialize.ts +++ b/src/initialize.ts @@ -1,16 +1,29 @@ -import { initialize as initCharacters } from './definitions/characters'; import registerHeightComponent from './components/heightComponent'; -import registerTrackPosition from './components/trackPosition'; - -let initialized = false; +import Registry from '@dojo/widget-core/Registry'; +import AppContext from './context/AppContext'; +import OutsideContext from './context/OutsideContext'; +import monsters from './configuration/monsters'; export default function initialize() { - if (initialized) { - console.error('Application already initialized'); - } + const registry = new Registry(); + const appContext = new AppContext(); + const outsideContext = new OutsideContext(); + registry.defineInjector('app-state', appContext); + registry.defineInjector('outside', outsideContext); - initCharacters(); + initializeMonsters(appContext, outsideContext); registerHeightComponent(); - registerTrackPosition(); - initialized = true; + outsideContext.randomizeEncounter(); + return registry; +} + +function initializeMonsters(appContext: AppContext, outsideContext: OutsideContext) { + for (let monster of monsters) { + appContext.addObjMtlAssets(monster.name, monster.obj, monster.mtl); + outsideContext.addMonster({ + name: monster.name, + heights: monster.heights, + environment: monster.environment + }) + } } diff --git a/src/interfaces.d.ts b/src/interfaces.d.ts new file mode 100644 index 0000000..f5b22a3 --- /dev/null +++ b/src/interfaces.d.ts @@ -0,0 +1,7 @@ +/** + * OBJ model definition consists of an obj file (or inline path) and an optional mtl material file + */ +export interface ObjModelAsset { + mtl?: string; + obj: string; +} diff --git a/src/main.ts b/src/main.ts index 594e600..28f83d5 100644 --- a/src/main.ts +++ b/src/main.ts @@ -12,9 +12,9 @@ if (!root) { throw new Error('cannot find target node'); } -initialize(); +const registry = initialize(); const Projector = ProjectorMixin(App); const projector = new Projector(); - +projector.setProperties({ registry }); projector.append(root); diff --git a/src/stages/Outside.ts b/src/stages/Outside.ts deleted file mode 100644 index c0db25f..0000000 --- a/src/stages/Outside.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { v, w } from '@dojo/widget-core/d'; -import { DNode, WidgetProperties } from '@dojo/widget-core/interfaces'; -import { WidgetBase } from '@dojo/widget-core/WidgetBase'; -import { Container } from '@dojo/widget-core/Container'; -import ObjModel from '../framework/ObjModel'; -import { MonsterName } from '../definitions/characters'; -import genericMapper from '../framework/util/genericMapper'; -import { objHeight } from '../components/heightComponent'; -import { trackPosition } from '../components/trackPosition'; - -export interface OutsideProperties extends WidgetProperties { - monster: MonsterName; - monsterDistance?: number; -} - -export default class Outside extends WidgetBase { - protected render() { - const { monster, monsterDistance = 5 } = this.properties; - const Derpymon = Container(ObjModel, monster, genericMapper()); - - return [ - v('a-entity', { - environment: 'preset: forest' - }), - w(Derpymon, { - position: `0 0 -${ monsterDistance }`, - [objHeight]: '2' - }), - v('a-sphere', { - [trackPosition]: '#controls', - radius: '0.15', - color: 'red' - }) - ]; - } -} diff --git a/src/util/properties.ts b/src/util/properties.ts new file mode 100644 index 0000000..dd3ef43 --- /dev/null +++ b/src/util/properties.ts @@ -0,0 +1,31 @@ +import { GetProperties } from '@dojo/widget-core/decorators/inject'; + +/** + * Filter properties from the injected data into a subset of properties + * @param whitelist list of property names + * @return a getProperties function for the injector + */ +export function filteredProps(whitelist: string[]): GetProperties { + return (properties: any) => { + const props: any = {}; + for (let item of whitelist) { + props[item] = properties[item]; + } + return props; + } +} + +/** + * @param props properties passed to be cloned + * @return a cloned set of enumerable properties + */ +export function cloneProps(props: T) { + return Object.assign({}, props); +} + +/** + * Used as a fail-safe for a required property + */ +export function throws(message: string = 'Missing a required property'): never { + throw new Error(message); +} diff --git a/src/framework/Assets.ts b/src/widgets/Assets.ts similarity index 66% rename from src/framework/Assets.ts rename to src/widgets/Assets.ts index 903095b..35ebdfe 100644 --- a/src/framework/Assets.ts +++ b/src/widgets/Assets.ts @@ -1,22 +1,20 @@ import { WidgetBase } from '@dojo/widget-core/WidgetBase'; import { DNode, WidgetProperties } from '@dojo/widget-core/interfaces'; import { v } from '@dojo/widget-core/d'; - -export interface Asset { - id: string; - src: string; -} +import AppContext from '../context/AppContext'; export interface AssetProperties extends WidgetProperties { - assets: Asset[]; + assets?: AppContext['assets']; } export default class Assets extends WidgetBase { protected render(): DNode { - const assets = this.properties.assets.map((asset) => { - return v('a-asset-item', asset); - }); + const { + assets = [] + } = this.properties; - return v('a-assets', {}, assets); + return v('a-assets', {}, assets.map((asset) => { + return v('a-asset-item', asset); + })); } } diff --git a/src/framework/Controls.ts b/src/widgets/Controls.ts similarity index 85% rename from src/framework/Controls.ts rename to src/widgets/Controls.ts index daed379..be18de7 100644 --- a/src/framework/Controls.ts +++ b/src/widgets/Controls.ts @@ -17,8 +17,12 @@ export default class Controls extends WidgetBase { protected render(): DNode[] { return [ v('a-entity', { - id: 'controls', + 'class': '.controls', 'daydream-controls': '' + }), + v('a-entity', { + 'class': '.controls', + 'vive-controls': '' }) ]; } diff --git a/src/framework/ObjModel.ts b/src/widgets/ObjModel.ts similarity index 54% rename from src/framework/ObjModel.ts rename to src/widgets/ObjModel.ts index ab21b36..c1f27ad 100644 --- a/src/framework/ObjModel.ts +++ b/src/widgets/ObjModel.ts @@ -1,34 +1,13 @@ import { WidgetBase } from '@dojo/widget-core/WidgetBase'; import { DNode, WidgetProperties } from '@dojo/widget-core/interfaces'; import { v } from '@dojo/widget-core/d'; -import MetaBase from "@dojo/widget-core/meta/Base"; -import * as THREE from "three" -import { Box3 } from 'three'; - -export interface ObjMetadata { - boundingBox: Box3; -} export interface AssetProperties extends WidgetProperties { mtl: string; src: string; - objMetadata: Map; [ key: string ]: any; } -export class EntityMeta extends MetaBase { - boundingBox(key: string): Box3 { - this.requireNode(key); - const node = this.nodes.get(key); - - if (!node) { - return new Box3(); - } - - return new THREE.Box3().setFromObject( ( node).object3D ); - } -} - export default class ObjModel extends WidgetBase { protected getProperties() { return Object.assign({}, this.properties); diff --git a/src/widgets/Outside.ts b/src/widgets/Outside.ts new file mode 100644 index 0000000..4ec2414 --- /dev/null +++ b/src/widgets/Outside.ts @@ -0,0 +1,39 @@ +import { v, w } from '@dojo/widget-core/d'; +import { WidgetProperties } from '@dojo/widget-core/interfaces'; +import { WidgetBase } from '@dojo/widget-core/WidgetBase'; +import ObjModel from './ObjModel'; +import { objHeight } from '../components/heightComponent'; + +export interface Monster { + name: string; + distance: number; + height: number; + mtl: string; + obj: string; +} + +export interface OutsideProperties extends WidgetProperties { + environment: string; + monster?: Monster; +} + +export default class Outside extends WidgetBase { + protected render() { + const { + environment, + monster + } = this.properties; + + return [ + v('a-entity', { + environment: `preset: ${ environment }` + }), + monster ? w(ObjModel, { + mtl: monster.mtl, + src: monster.obj, + position: `0 0 -${ monster.distance }`, + [objHeight]: `${ monster.height }` + }) : null + ]; + } +} diff --git a/src/widgets/meta/BoundingBox.ts b/src/widgets/meta/BoundingBox.ts new file mode 100644 index 0000000..5e64394 --- /dev/null +++ b/src/widgets/meta/BoundingBox.ts @@ -0,0 +1,15 @@ +import MetaBase from "@dojo/widget-core/meta/Base"; +import * as THREE from "three" +import { Box3 } from 'three'; + +export class BoundingBox extends MetaBase { + boundingBox(key: string): Box3 { + const node = this.getNode(key); + + if (!node) { + return new Box3(); + } + + return new THREE.Box3().setFromObject( ( node).object3D ); + } +} diff --git a/tests/unit/App.ts b/tests/unit/App.ts index 54e5ad5..c812ce4 100644 --- a/tests/unit/App.ts +++ b/tests/unit/App.ts @@ -4,7 +4,7 @@ import { VNode } from '@dojo/interfaces/vdom'; import { spy, SinonSpy } from 'sinon'; import App from './../../src/App'; -import Outside from './../../src/stages/Outside'; +import Outside from '../../src/widgets/Outside'; let helloWorldSpy: SinonSpy; let helloWorldSetPropertiesSpy: SinonSpy; diff --git a/tests/unit/stages/Outside.ts b/tests/unit/stages/Outside.ts index 9b9efe4..c2ed713 100644 --- a/tests/unit/stages/Outside.ts +++ b/tests/unit/stages/Outside.ts @@ -2,8 +2,7 @@ import * as registerSuite from 'intern/lib/interfaces/object'; import { assert } from 'chai'; import { VNode } from '@dojo/interfaces/vdom'; -import Outside from '../../../src/stages/Outside'; -import { MonsterName } from '../../../src/definitions/characters'; +import Outside from '../../../src/widgets/Outside'; registerSuite({ name: 'Outside', @@ -11,17 +10,6 @@ registerSuite({ 'render'() { const helloWorld = new Outside(); - const vnode = helloWorld.__render__(); - assert.strictEqual(vnode.vnodeSelector, 'div'); - assert.equal(vnode.text, 'Hello, Dojo World!'); - }, - - 'render with stranger'() { - const helloWorld = new Outside(); - helloWorld.__setProperties__({ - monster: MonsterName.CharDerp - }); - const vnode = helloWorld.__render__(); assert.strictEqual(vnode.vnodeSelector, 'div'); assert.equal(vnode.text, 'Hello, Dojo World!');