Skip to content

Commit

Permalink
BitECS inspect button
Browse files Browse the repository at this point in the history
  • Loading branch information
keianhzo committed Jan 23, 2024
1 parent baa50aa commit 7299358
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 25 deletions.
5 changes: 4 additions & 1 deletion src/bit-components.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,10 @@ export const PenActive = defineComponent();
export const PenUpdated = defineComponent();
export const HoverMenuChild = defineComponent();
export const Static = defineComponent();
export const Inspectable = defineComponent();
export const Inspectable = defineComponent({
fireChangeEvent: Types.ui8
});
export const Inspected = defineComponent();
export const PreventAudioBoost = defineComponent();
export const IgnoreSpaceBubble = defineComponent();
export const Rigidbody = defineComponent({
Expand Down
18 changes: 18 additions & 0 deletions src/bit-systems/inspect-system.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { defineQuery, enterQuery, exitQuery } from "bitecs";
import { HubsWorld } from "../app";
import { Inspectable, Inspected } from "../bit-components";
import { CameraSystem } from "../systems/camera-system";

const inspectedQuery = defineQuery([Inspected]);
const inspectedEnterQuery = enterQuery(inspectedQuery);
const inspectedExitQuery = exitQuery(inspectedQuery);
export function inspectSystem(world: HubsWorld, cameraSystem: CameraSystem) {
inspectedEnterQuery(world).forEach(eid => {
const obj = world.eid2obj.get(eid);
cameraSystem.inspect(obj, 1.5, Boolean(Inspectable.fireChangeEvent[eid]));
});
inspectedExitQuery(world).forEach(eid => {
const obj = world.eid2obj.get(eid);
cameraSystem.uninspect(Boolean(Inspectable.fireChangeEvent[eid]));
});
}
35 changes: 27 additions & 8 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,16 @@ import {
RemoteRight,
Rigidbody,
Deleting,
Deletable,
MediaLoader,
ObjectDropped,
FloatyObject,
Owned,
MediaVideo,
MediaImage,
MediaPDF,
MediaMirrored
MediaMirrored,
Inspected,
Inspectable
} from "../bit-components";
import {
anyEntityWith,
Expand Down Expand Up @@ -58,6 +59,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 @@ -67,7 +73,7 @@ function objectMenuTarget(world: HubsWorld, menu: EntityID, sceneIsFrozen: boole
// We should probably use something more meaningful to refer to that spawned media root than Deletable.
// Maybe something like MediaRoot or SpawnedMediaRoot.
const target = hoveredQuery(world).map(eid =>
findAncestorWithComponents(world, [Deletable, ObjectMenuTarget], eid)
findAncestorWithComponents(world, [Inspectable, ObjectMenuTarget], eid)
)[0];
if (target) {
if (hasComponent(world, Deleting, target)) {
Expand All @@ -81,7 +87,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 +197,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 +220,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]);
Inspectable.fireChangeEvent[ObjectMenu.targetRef[menuEid]] = 1;
}
break;
}
}

Expand All @@ -230,6 +240,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]);
Inspectable.fireChangeEvent[ObjectMenu.targetRef[menuEid]] = 1;
}
break;
}
}

Expand Down Expand Up @@ -263,6 +280,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 +297,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 +309,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
38 changes: 26 additions & 12 deletions src/react-components/room/hooks/useObjectList.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import React, { useState, useEffect, useContext, createContext, useCallback, Chi
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 { addComponent, defineQuery, hasComponent, removeComponent } from "bitecs";
import { Inspectable, 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,21 @@ 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()) {
if (hasComponent(APP.world, Inspected, object.eid)) {
removeComponent(APP.world, Inspected, object.eid);
} else {
addComponent(APP.world, Inspected, object.eid);
Inspectable.fireChangeEvent[object.eid] = 0;
}
} 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 +79,18 @@ function handleDeselect(scene, object, callback) {

callback(null);

cameraSystem.uninspect(false);
if (shouldUseNewLoader()) {
if (object) {
removeComponent(APP.world, Inspected, object.eid);
Inspectable.fireChangeEvent[object.eid] = 0;
}
} 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) {
const object3D = shouldUseNewLoader() ? APP.world.eid2obj.get(object.eid) : object.el.object3D;
cameraSystem.inspect(object3D, 1.5, false);
}
}
}

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 7299358

Please sign in to comment.