Skip to content

Commit

Permalink
refactor: pointer events and some bug fixes (decentraland#539)
Browse files Browse the repository at this point in the history
  • Loading branch information
Agustin Mendez authored and eordano committed Mar 9, 2019
1 parent baf09ef commit b60ae2f
Show file tree
Hide file tree
Showing 82 changed files with 7,149 additions and 6,326 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@
"ephemeralkey": "^2.0.1",
"eth-connect": "^4.0.0",
"ethereum-blockies": "^0.1.1",
"fp-future": "^1.0.0",
"fp-future": "^1.0.1",
"google-protobuf": "^3.6.1",
"hammerjs": "^2.0.8",
"keccakjs": "^0.2.1",
Expand Down
4 changes: 2 additions & 2 deletions packages/dcl/WebGLParcelScene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ import { scene } from 'engine/renderer'

export class WebGLParcelScene extends WebGLScene<LoadableParcelScene> {
public encodedPositions: string
public setOfEntitiesOutsideBoundaries = new Set<BaseEntity>()

private setOfEntitiesOutsideBoundaries = new Set<BaseEntity>()
private parcelSet = new Set<string>()

private shouldValidateBoundaries = false

constructor(public data: EnvironmentData<LoadableParcelScene>) {
Expand Down Expand Up @@ -143,6 +142,7 @@ export class WebGLParcelScene extends WebGLScene<LoadableParcelScene> {
*/
checkBoundaries() {
const newSet = new Set<BaseEntity>()

this.context.entities.forEach(entity => checkParcelSceneBoundaries(this.parcelSet, newSet, entity))
// remove the highlight from the entities that were outside but they are no longer outside
this.setOfEntitiesOutsideBoundaries.forEach($ => {
Expand Down
13 changes: 6 additions & 7 deletions packages/dcl/entities/utils/AvatarEntity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,18 @@ import { profileObservable, ProfileEvent } from 'shared/comms/profile'
import { SharedSceneContext } from 'engine/entities/SharedSceneContext'
import { uuid } from 'atomicHelpers/math'
import { setEntityText } from 'engine/components/ephemeralComponents/TextShape'
import { Vector3Component, QuaternionComponent } from 'shared/types'
import { Color3 } from 'decentraland-ecs/src'
import { Color3, ReadOnlyVector3, ReadOnlyQuaternion } from 'decentraland-ecs/src'

export type AvatarAttributes = {
displayName: string
publicKey: string
avatarType?: string
leftHandPosition: Vector3Component
rightHandPosition: Vector3Component
leftHandPosition: ReadOnlyVector3
rightHandPosition: ReadOnlyVector3

headRotation: Vector3Component
leftHandRotation: QuaternionComponent
rightHandRotation: QuaternionComponent
headRotation: ReadOnlyVector3
leftHandRotation: ReadOnlyQuaternion
rightHandRotation: ReadOnlyQuaternion

muted: boolean

Expand Down
20 changes: 1 addition & 19 deletions packages/dcl/entities/utils/checkParcelSceneLimits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,6 @@ export function measureObject3D(obj: BABYLON.AbstractMesh | BABYLON.Mesh | BABYL
return { entities, triangles, bodies, textures, materials, geometries }
}

function totalBoundingInfo(meshes: BABYLON.AbstractMesh[]) {
let boundingInfo = meshes[0].getBoundingInfo()
let min = boundingInfo.boundingBox.minimumWorld.add(meshes[0].position)
let max = boundingInfo.boundingBox.maximumWorld.add(meshes[0].position)
for (let i = 1; i < meshes.length; i++) {
boundingInfo = meshes[i].getBoundingInfo()
min = BABYLON.Vector3.Minimize(min, boundingInfo.boundingBox.minimumWorld.add(meshes[i].position))
max = BABYLON.Vector3.Maximize(max, boundingInfo.boundingBox.maximumWorld.add(meshes[i].position))
}
return new BABYLON.BoundingInfo(min, max)
}

/**
* Returns the objects that are outside the parcelScene limits.
* Receives the encoded parcelScene parcels and the entity to traverse
Expand Down Expand Up @@ -88,13 +76,7 @@ export function checkParcelSceneBoundaries(
return 'BREAK'
}

const meshes = mesh.getChildMeshes(false)

if (meshes.length === 0) {
return 'CONTINUE'
}

const bbox = totalBoundingInfo(meshes)
const bbox = entity.getMeshesBoundingBox()

if (bbox.maximum.y > maxHeight || bbox.minimum.y < minHeight) {
objectsOutside.add(entity)
Expand Down
2 changes: 0 additions & 2 deletions packages/dcl/widgets/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export class WebGLUIScene extends WebGLScene<any> {

export async function initHudSystem(): Promise<WebGLUIScene> {
const context = new SharedSceneContext('/', 'ui-context-hud', false)
context.isInternal = true
const scene = new WebGLUIScene('hud', hudWorkerUrl, context)
const system = await scene.worker.system

Expand All @@ -46,7 +45,6 @@ export async function initHudSystem(): Promise<WebGLUIScene> {

export async function initChatSystem(): Promise<WebGLUIScene> {
const context = new SharedSceneContext('/', 'ui-context-chat', false)
context.isInternal = true
const scene = new WebGLUIScene('chat', chatWorkerUrl, context)
const system = await scene.worker.system

Expand Down
134 changes: 94 additions & 40 deletions packages/decentraland-ecs/src/decentraland/Input.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { DecentralandInterface } from './Types'
// tslint:disable:ter-indent
// tslint:disable:ter-indent

import { DecentralandInterface, PointerEvent } from './Types'
import { Vector3 } from './math'
import { Component, DisposableComponent } from '../ecs/Component'

declare let dcl: DecentralandInterface | void

Expand All @@ -20,46 +24,58 @@ export type InputState = Record<
}
>

export type EnginePointerEvent = {
/** Origin of the ray */
from: { x: number; y: number; z: number }
/** Direction vector of the ray (normalized) */
direction: { x: number; y: number; z: number }
/** Length of the ray */
length: number
/** ID of the pointer that triggered the event */
pointerId: number
export type LocalPointerEvent = PointerEvent & {
origin: Vector3
direction: Vector3
pointer: Pointer
hit?: PointerEvent['hit'] & {
hitPoint: Vector3
normal: Vector3
worldNormal: Vector3
}
}

export type PointerEvent = {
/** Origin of the ray */
from: Vector3
/** Direction vector of the ray (normalized) */
direction: Vector3
/** Length of the ray */
length: number
/** ID of the pointer that triggered the event */
pointerId: Pointer
/**
* @public
*/
export class PointerEventComponent {
constructor(public readonly callback: (event: LocalPointerEvent) => void) {
if (!callback || !('apply' in callback) || !('call' in callback)) {
throw new Error('Callback is not a function')
}
// tslint:disable-next-line:no-use-before-declare
Input.ensureInstance()
}
}

/**
* @public
*/
@Component('pointerDown')
export class OnPointerDown extends PointerEventComponent {}

/**
* @public
*/
@Component('pointerUp')
export class OnPointerUp extends PointerEventComponent {}

/**
* @public
*/
export class Input {
private static _instance: Input

static get instance(): Input {
if (!Input._instance) {
Input._instance = new Input()
}
Input.ensureInstance()
return Input._instance
}

public get state(): Readonly<InputState> {
return this.internalState
}

private subscriptions: Record<InputEventKind, Array<(e: PointerEvent) => void>> = {
private subscriptions: Record<InputEventKind, Array<(e: LocalPointerEvent) => void>> = {
BUTTON_A_DOWN: [],
BUTTON_A_UP: []
}
Expand All @@ -73,29 +89,35 @@ export class Input {
}
}

constructor() {
private constructor() {
if (typeof dcl !== 'undefined') {
dcl.subscribe('pointerUp')
dcl.subscribe('pointerDown')

dcl.onEvent(event => {
if (event.type === 'pointerUp') {
this.handlePointerUp(event.data as EnginePointerEvent)
this.handlePointerUp(event.data as PointerEvent)
} else if (event.type === 'pointerDown') {
this.handlePointerDown(event.data as EnginePointerEvent)
this.handlePointerDown(event.data as PointerEvent)
}
})
}
}

static ensureInstance(): any {
if (!Input._instance) {
Input._instance = new Input()
}
}

/**
* Subscribes to an input event and triggers the provided callback.
*
* Returns a function that can be called to remove the subscription.
* @param eventName - The name of the event (see InputEventKind).
* @param fn - A callback function to be called when the event is triggered.
*/
public subscribe(eventName: InputEventKind, fn: (e: PointerEvent) => void) {
public subscribe(eventName: InputEventKind, fn: (e: LocalPointerEvent) => void) {
this.subscriptions[eventName].push(fn)
return () => this.unsubscribe(eventName, fn)
}
Expand All @@ -105,7 +127,7 @@ export class Input {
* @param eventName - The name of the event (see InputEventKind).
* @param fn - The callback function used when subscribing to the event.
*/
public unsubscribe(eventName: InputEventKind, fn: (e: PointerEvent) => void) {
public unsubscribe(eventName: InputEventKind, fn: (e: LocalPointerEvent) => void) {
const index = this.subscriptions[eventName].indexOf(fn)
if (index > -1) {
this.subscriptions[eventName].splice(index, 1)
Expand All @@ -117,35 +139,67 @@ export class Input {
return Pointer.SECONDARY
}

private handlePointerUp(data: EnginePointerEvent) {
private handlePointerUp(data: PointerEvent) {
const pointer = this.getPointerById(data.pointerId)
const newData = {
length: data.length,
from: new Vector3(data.from.x, data.from.y, data.from.z),
direction: new Vector3(data.direction.x, data.direction.y, data.direction.z),
pointerId: pointer
const newData: LocalPointerEvent = {
...data,
pointer,
direction: new Vector3().copyFrom(data.direction),
origin: new Vector3().copyFrom(data.origin),
hit: data.hit
? {
...data.hit,
hitPoint: new Vector3().copyFrom(data.hit.hitPoint),
normal: new Vector3().copyFrom(data.hit.normal),
worldNormal: new Vector3().copyFrom(data.hit.worldNormal)
}
: undefined
}

this.internalState[Pointer.PRIMARY].BUTTON_A_DOWN = false

for (let i = 0; i < this.subscriptions['BUTTON_A_UP'].length; i++) {
this.subscriptions['BUTTON_A_UP'][i](newData)
}

if (newData.hit && newData.hit.entityId && DisposableComponent.engine) {
const entity = DisposableComponent.engine.entities[newData.hit.entityId]
const handler = entity && entity.getOrNull(OnPointerUp)
if (handler) {
handler.callback(newData)
}
}
}

private handlePointerDown(data: EnginePointerEvent) {
private handlePointerDown(data: PointerEvent) {
const pointer = this.getPointerById(data.pointerId)
const newData = {
length: data.length,
from: new Vector3(data.from.x, data.from.y, data.from.z),
direction: new Vector3(data.direction.x, data.direction.y, data.direction.z),
pointerId: pointer
const newData: LocalPointerEvent = {
...data,
pointer,
direction: new Vector3().copyFrom(data.direction),
origin: new Vector3().copyFrom(data.origin),
hit: data.hit
? {
...data.hit,
hitPoint: new Vector3().copyFrom(data.hit.hitPoint),
normal: new Vector3().copyFrom(data.hit.normal),
worldNormal: new Vector3().copyFrom(data.hit.worldNormal)
}
: undefined
}

this.internalState[Pointer.PRIMARY].BUTTON_A_DOWN = true

for (let i = 0; i < this.subscriptions['BUTTON_A_DOWN'].length; i++) {
this.subscriptions['BUTTON_A_DOWN'][i](newData)
}

if (newData.hit && newData.hit.entityId && DisposableComponent.engine) {
const entity = DisposableComponent.engine.entities[newData.hit.entityId]
const handler = entity && entity.getOrNull(OnPointerDown)
if (handler) {
handler.callback(newData)
}
}
}
}
Loading

0 comments on commit b60ae2f

Please sign in to comment.