Skip to content

Commit

Permalink
Merge pull request #6445 from mozilla/bitecs-inspect-button
Browse files Browse the repository at this point in the history
Bitecs inspect button
  • Loading branch information
keianhzo authored Jan 23, 2024
2 parents 14afc90 + 3e17530 commit 1f7c920
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 30 deletions.
2 changes: 2 additions & 0 deletions src/bit-components.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ export const PenUpdated = defineComponent();
export const HoverMenuChild = defineComponent();
export const Static = defineComponent();
export const Inspectable = defineComponent();
export const InspectTargetChanged = defineComponent();
export const Inspected = defineComponent();
export const PreventAudioBoost = defineComponent();
export const IgnoreSpaceBubble = defineComponent();
export const Rigidbody = defineComponent({
Expand Down
19 changes: 19 additions & 0 deletions src/bit-systems/inspect-system.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { defineQuery, enterQuery, exitQuery, hasComponent, removeComponent } from "bitecs";
import { HubsWorld } from "../app";
import { InspectTargetChanged, Inspected } from "../bit-components";
import { CameraSystem } from "../systems/camera-system";
import { anyEntityWith } from "../utils/bit-utils";

const inspectedQuery = defineQuery([Inspected]);
const inspectedEnterQuery = enterQuery(inspectedQuery);
const inspectedExitQuery = exitQuery(inspectedQuery);
export function inspectSystem(world: HubsWorld, cameraSystem: CameraSystem) {
inspectedExitQuery(world).forEach(eid => {
cameraSystem.uninspect(hasComponent(world, InspectTargetChanged, eid));
removeComponent(world, InspectTargetChanged, eid);
});
inspectedEnterQuery(world).forEach(eid => {
const obj = world.eid2obj.get(eid);
cameraSystem.inspect(obj, 1.5, hasComponent(world, InspectTargetChanged, eid));
});
}
35 changes: 28 additions & 7 deletions src/bit-systems/object-menu.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { addComponent, defineQuery, enterQuery, entityExists, exitQuery, hasComponent } from "bitecs";
import { addComponent, defineQuery, enterQuery, entityExists, exitQuery, hasComponent, removeComponent } from "bitecs";
import { Matrix4, Vector3 } from "three";
import type { HubsWorld } from "../app";
import {
Expand All @@ -13,15 +13,18 @@ import {
RemoteRight,
Rigidbody,
Deleting,
Deletable,
MediaLoader,
ObjectDropped,
FloatyObject,
Owned,
MediaVideo,
MediaImage,
MediaPDF,
MediaMirrored
MediaMirrored,
Inspected,
Inspectable,
Deletable,
InspectTargetChanged
} from "../bit-components";
import {
anyEntityWith,
Expand Down Expand Up @@ -58,6 +61,11 @@ function clicked(world: HubsWorld, eid: EntityID) {
}

function objectMenuTarget(world: HubsWorld, menu: EntityID, sceneIsFrozen: boolean) {
const held = heldQuery(world).map(eid => eid === ObjectMenu.inspectButtonRef[menu])[0];
if (held) {
return ObjectMenu.targetRef[menu];
}

if (!sceneIsFrozen) {
return 0;
}
Expand All @@ -81,7 +89,6 @@ function objectMenuTarget(world: HubsWorld, menu: EntityID, sceneIsFrozen: boole
if (entityExists(world, ObjectMenu.targetRef[menu])) {
return ObjectMenu.targetRef[menu];
}

return 0;
}

Expand Down Expand Up @@ -192,8 +199,6 @@ function handleClicks(world: HubsWorld, menu: EntityID, hubChannel: HubChannel)
deleteTheDeletableAncestor(world, ObjectMenu.targetRef[menu]);
} else if (clicked(world, ObjectMenu.dropButtonRef[menu])) {
addComponent(world, ObjectDropped, ObjectMenu.targetRef[menu]);
} else if (clicked(world, ObjectMenu.inspectButtonRef[menu])) {
console.log("Clicked inspect");
} else if (clicked(world, ObjectMenu.deserializeDrawingButtonRef[menu])) {
console.log("Clicked deserialize drawing");
} else if (clicked(world, ObjectMenu.openLinkButtonRef[menu])) {
Expand All @@ -217,6 +222,13 @@ function handleHeldEnter(world: HubsWorld, eid: EntityID, menuEid: EntityID) {
ObjectMenu.flags[menuEid] &= ~ObjectMenuFlags.Visible;
startScaling(world, menuEid, ObjectMenu.targetRef[menuEid]);
break;
case ObjectMenu.inspectButtonRef[menuEid]:
if (!hasComponent(world, Inspected, ObjectMenu.targetRef[menuEid])) {
ObjectMenu.flags[menuEid] &= ~ObjectMenuFlags.Visible;
addComponent(world, Inspected, ObjectMenu.targetRef[menuEid]);
addComponent(world, InspectTargetChanged, ObjectMenu.targetRef[menuEid]);
}
break;
}
}

Expand All @@ -230,6 +242,13 @@ function handleHeldExit(world: HubsWorld, eid: EntityID, menuEid: EntityID) {
ObjectMenu.flags[menuEid] |= ObjectMenuFlags.Visible;
stopScaling(world, menuEid);
break;
case ObjectMenu.inspectButtonRef[menuEid]:
if (hasComponent(world, Inspected, ObjectMenu.targetRef[menuEid])) {
ObjectMenu.flags[menuEid] |= ObjectMenuFlags.Visible;
removeComponent(world, Inspected, ObjectMenu.targetRef[menuEid]);
addComponent(world, InspectTargetChanged, ObjectMenu.targetRef[menuEid]);
}
break;
}
}

Expand Down Expand Up @@ -263,6 +282,8 @@ function updateVisibility(world: HubsWorld, menu: EntityID, frozen: boolean) {
const media = MediaLoader.mediaRef[target];
const isVideoImagePdf = hasAnyComponent(world, [MediaVideo, MediaImage, MediaPDF], media);
const isMirrored = hasComponent(world, MediaMirrored, target);
const isInspectable = hasComponent(world, Inspectable, target);
const isInspected = hasComponent(world, Inspected, target);

// Parent visibility doesn't block raycasting, so we must set each button to be invisible
// TODO: Ensure that children of invisible entities aren't raycastable
Expand All @@ -278,6 +299,7 @@ function updateVisibility(world: HubsWorld, menu: EntityID, frozen: boolean) {
world.eid2obj.get(ObjectMenu.dropButtonRef[menu])!.visible =
!isVideoImagePdf && !isEntityPinned && !hasComponent(world, ObjectDropped, target);
world.eid2obj.get(ObjectMenu.mirrorButtonRef[menu])!.visible = isVideoImagePdf && !isMirrored;
world.eid2obj.get(ObjectMenu.inspectButtonRef[menu])!.visible = isVideoImagePdf && isInspectable && !isInspected;

// This is a hacky way of giving a chance to the object-menu-transform system to center the menu based on the
// visible buttons without accounting for the background plane.
Expand All @@ -289,7 +311,6 @@ function updateVisibility(world: HubsWorld, menu: EntityID, frozen: boolean) {
world.eid2obj.get(ObjectMenu.cameraFocusButtonRef[menu])!.visible = false;
world.eid2obj.get(ObjectMenu.cameraTrackButtonRef[menu])!.visible = false;
world.eid2obj.get(ObjectMenu.deserializeDrawingButtonRef[menu])!.visible = false;
world.eid2obj.get(ObjectMenu.inspectButtonRef[menu])!.visible = false;
world.eid2obj.get(ObjectMenu.refreshButtonRef[menu])!.visible = false;
}

Expand Down
12 changes: 8 additions & 4 deletions src/prefabs/object-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import scaleIconSrc from "../assets/scale-action.png";
import removeIconSrc from "../assets/remove-action.png";
import dropIconSrc from "../assets/drop-action.png";
import mirrorIconSrc from "../assets/mirror-action.png";
import inspectIconSrc from "../assets/focus-action.png";
import { Plane } from "./plane";
import { FrontSide } from "three";
import { Layers } from "../camera-layers";
Expand All @@ -17,7 +18,8 @@ export async function loadObjectMenuButtonIcons() {
loadTexture(scaleIconSrc, 1, "image/png"),
loadTexture(removeIconSrc, 1, "image/png"),
loadTexture(dropIconSrc, 1, "image/png"),
loadTexture(mirrorIconSrc, 1, "image/png")
loadTexture(mirrorIconSrc, 1, "image/png"),
loadTexture(inspectIconSrc, 1, "image/png")
]);
}

Expand Down Expand Up @@ -112,14 +114,16 @@ function DropButton(props: Attrs) {
}

function InspectButton(props: Attrs) {
const { texture, cacheKey } = loadTextureFromCache(inspectIconSrc, 1);
return (
<Button3D
name="Inspect Button"
scale={buttonScale}
width={0.4}
width={buttonHeight}
height={buttonHeight}
type={BUTTON_TYPES.DEFAULT}
text={"inspect"}
holdable
icon={{ texture, cacheKey, scale: [0.165, 0.165, 0.165] }}
{...props}
/>
);
Expand Down Expand Up @@ -237,7 +241,7 @@ const position = {
track: [ 0.25, 0.375, uiZ] as ArrayVec3,
remove: [ 0, -0.275, uiZ] as ArrayVec3,
drop: [ 0, -0.425, uiZ] as ArrayVec3,
inspect: [ -0.1, -0.625, uiZ] as ArrayVec3,
inspect: [ 0, -0.425, uiZ] as ArrayVec3,
deserializeDrawing: [ -0.3, -0.625, uiZ] as ArrayVec3,
openLink: [ 0.25, -0.275, uiZ] as ArrayVec3,
refresh: [ 0.3, -0.625, uiZ] as ArrayVec3,
Expand Down
43 changes: 30 additions & 13 deletions src/react-components/room/hooks/useObjectList.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, { useState, useEffect, useContext, createContext, useCallback, Children, cloneElement } from "react";
import PropTypes from "prop-types";
import { mediaSort, mediaSortAframe, getMediaType, getMediaTypeAframe } from "../../../utils/media-sorting.js";
import { shouldUseNewLoader } from "../../../utils/bit-utils";
import { defineQuery, hasComponent } from "bitecs";
import { MediaInfo } from "../../../bit-components.js";
import { anyEntityWith, shouldUseNewLoader } from "../../../utils/bit-utils";
import { addComponent, defineQuery, hasComponent, removeComponent } from "bitecs";
import { Inspected, MediaInfo } from "../../../bit-components.js";

function getUrl(eid) {
return hasComponent(APP.world, MediaInfo, eid) ? APP.getString(MediaInfo.accessibleUrl[eid]) : "";
Expand Down Expand Up @@ -56,14 +56,22 @@ function handleInspect(scene, object, callback) {

callback(object);

const object3D = shouldUseNewLoader() ? APP.world.eid2obj.get(object.eid) : object.el.object3D;

if (object3D !== cameraSystem.inspectable) {
if (cameraSystem.inspectable) {
cameraSystem.uninspect(false);
if (shouldUseNewLoader()) {
const inspected = anyEntityWith(APP.world, Inspected);
if (inspected != object.eid) {
if (inspected) {
removeComponent(APP.world, Inspected, inspected);
}
addComponent(APP.world, Inspected, object.eid);
}
} else {
if (object.el.object3D !== cameraSystem.inspectable) {
if (cameraSystem.inspectable) {
cameraSystem.uninspect(false);
}

cameraSystem.inspect(object3D, 1.5, false);
cameraSystem.inspect(object.el.object3D, 1.5, false);
}
}
}

Expand All @@ -72,11 +80,20 @@ function handleDeselect(scene, object, callback) {

callback(null);

cameraSystem.uninspect(false);
if (shouldUseNewLoader()) {
const inspected = anyEntityWith(APP.world, Inspected);
if (inspected) {
removeComponent(APP.world, Inspected, inspected);
}
if (object) {
addComponent(APP.world, Inspected, object.eid);
}
} else {
cameraSystem.uninspect(false);

if (object) {
const object3D = shouldUseNewLoader() ? APP.world.eid2obj.get(object.eid) : object.el.object3D;
cameraSystem.inspect(object3D, 1.5, false);
if (object) {
cameraSystem.inspect(object.el.object3D, 1.5, false);
}
}
}

Expand Down
31 changes: 25 additions & 6 deletions src/systems/camera-system.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,21 @@ import { qsGet } from "../utils/qs_truthy";
const customFOV = qsGet("fov");
const enableThirdPersonMode = qsTruthy("thirdPerson");
import { Layers } from "../camera-layers";
import { HoveredRemoteRight, Inspectable, LocalAvatar, RemoteAvatar } from "../bit-components";
import { findAncestorWithAnyComponent, findAncestorWithComponent, shouldUseNewLoader } from "../utils/bit-utils";
import { defineQuery } from "bitecs";
import {
HoveredRemoteRight,
InspectTargetChanged,
Inspectable,
Inspected,
LocalAvatar,
RemoteAvatar
} from "../bit-components";
import {
anyEntityWith,
findAncestorWithAnyComponent,
findAncestorWithComponent,
shouldUseNewLoader
} from "../utils/bit-utils";
import { addComponent, defineQuery, removeComponent } from "bitecs";

function getInspectableInHierarchy(eid) {
let inspectable = findAncestorWithComponent(APP.world, Inspectable, eid);
Expand Down Expand Up @@ -460,8 +472,8 @@ export class CameraSystem {
if (shouldUseNewLoader()) {
if (hoveredQuery(APP.world).length) {
const hovered = hoveredQuery(APP.world)[0];
const obj = APP.world.eid2obj.get(hovered);
this.inspect(obj, 1.5);
addComponent(APP.world, Inspected, hovered);
addComponent(APP.world, InspectTargetChanged, hovered);
}
} else {
const hoverEl = this.interaction.state.rightRemote.hovered || this.interaction.state.leftRemote.hovered;
Expand All @@ -472,7 +484,14 @@ export class CameraSystem {
}
} else if (this.mode === CAMERA_MODE_INSPECT && this.userinput.get(paths.actions.stopInspecting)) {
scene.emit("uninspect");
this.uninspect();
if (shouldUseNewLoader()) {
const inspected = anyEntityWith(APP.world, Inspected);
if (inspected) {
removeComponent(APP.world, Inspected, inspected);
}
} else {
this.uninspect();
}
}

if (this.userinput.get(paths.actions.nextCameraMode)) {
Expand Down
2 changes: 2 additions & 0 deletions src/systems/hubs-systems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ import { followInFovSystem } from "../bit-systems/follow-in-fov-system";
import { linkedMediaSystem } from "../bit-systems/linked-media-system";
import { linkedVideoSystem } from "../bit-systems/linked-video-system";
import { linkedPDFSystem } from "../bit-systems/linked-pdf-system";
import { inspectSystem } from "../bit-systems/inspect-system";

declare global {
interface Window {
Expand Down Expand Up @@ -283,6 +284,7 @@ export function mainTick(xrFrame: XRFrame, renderer: WebGLRenderer, scene: Scene
linkedMediaSystem(world);
linkedVideoSystem(world);
linkedPDFSystem(world);
inspectSystem(world, hubsSystems.cameraSystem);

objectMenuTransformSystem(world);

Expand Down

0 comments on commit 1f7c920

Please sign in to comment.