Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unprivileged object menu and layout update #6458

Merged
merged 1 commit into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 1 addition & 24 deletions src/bit-systems/object-menu-transform-system.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineQuery } from "bitecs";
import { defineQuery, removeComponent } from "bitecs";
import { HubsWorld } from "../app";
import { ObjectMenuTarget, ObjectMenuTransform } from "../bit-components";
import { EntityID } from "../utils/networking-types";
Expand All @@ -7,7 +7,6 @@ import { isFacingCamera, setFromObject, setMatrixWorld } from "../utils/three-ut
import { ObjectMenuTargetFlags } from "../inflators/object-menu-target";
import { ObjectMenuTransformFlags } from "../inflators/object-menu-transform";

const offset = new Vector3();
const tmpVec1 = new Vector3();
const tmpVec2 = new Vector3();
const tmpQuat1 = new Quaternion();
Expand Down Expand Up @@ -45,18 +44,6 @@ function transformMenu(world: HubsWorld, menu: EntityID) {
if (!targetObj || !enabled) return;

const menuObj = world.eid2obj.get(menu)!;

// Calculate the menu offset based on visible elements
const center = (ObjectMenuTransform.flags[menu] & ObjectMenuTransformFlags.Center) !== 0 ? true : false;
if (center && ObjectMenuTransform.targetObjectRef[menu] !== ObjectMenuTransform.prevObjectRef[menu]) {
getAABB(menuObj, aabb);
aabb.getCenter(tmpVec1);
getAABB(menuObj, aabb, true);
aabb.getCenter(tmpVec2);
offset.subVectors(tmpVec1, tmpVec2);
offset.z = 0;
}

const camera = APP.scene?.systems["hubs-systems"].cameraSystem.viewingCamera;
camera.updateMatrices();

Expand All @@ -75,11 +62,6 @@ function transformMenu(world: HubsWorld, menu: EntityID) {
menuObj.lookAt(tmpVec2.setFromMatrixPosition(camera.matrixWorld));
menuObj.translateZ(sphere.radius);

if (center) {
menuObj.position.add(offset);
menuObj.matrixNeedsUpdate = true;
}

// TODO We need to handle the menu positioning when the player is inside the bounding sphere.
// For now we are defaulting to the current AFrame behavior.
} else {
Expand All @@ -102,11 +84,6 @@ function transformMenu(world: HubsWorld, menu: EntityID) {
tmpMat4.multiply(tmpMat42);
}

if (center) {
tmpMat42.makeTranslation(offset.x, offset.y, offset.z);
tmpMat4.multiply(tmpMat42);
}

setMatrixWorld(menuObj, tmpMat4);
}
ObjectMenuTransform.prevObjectRef[menu] = ObjectMenuTransform.targetObjectRef[menu];
Expand Down
69 changes: 53 additions & 16 deletions src/bit-systems/object-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import { ObjectMenuTransformFlags } from "../inflators/object-menu-transform";
import { COLLISION_LAYERS } from "../constants";
import { FLOATY_OBJECT_FLAGS } from "../systems/floaty-object-system";
import { INSPECTABLE_FLAGS } from "./inspect-system";
import { ObjectMenuPositions } from "../prefabs/object-menu";
// Working variables.
const _vec3_1 = new Vector3();
const _vec3_2 = new Vector3();
Expand Down Expand Up @@ -282,26 +283,62 @@ 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 isDropped = hasComponent(world, ObjectDropped, target);
const isInspectable = hasComponent(world, Inspectable, target);
const isInspected = hasComponent(world, Inspected, target);
const isRefreshing = hasComponent(world, MediaRefresh, 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
world.eid2obj.get(ObjectMenu.unpinButtonRef[menu])!.visible = visible && isEntityPinned && canIPin;
world.eid2obj.get(ObjectMenu.pinButtonRef[menu])!.visible = visible && !isEntityPinned && canIPin;
world.eid2obj.get(ObjectMenu.removeButtonRef[menu])!.visible = visible && !isEntityPinned && canISpawnMove;
world.eid2obj.get(ObjectMenu.cloneButtonRef[menu])!.visible = visible && canISpawnMove;
world.eid2obj.get(ObjectMenu.rotateButtonRef[menu])!.visible =
visible && (!isEntityPinned || canIPin) && canISpawnMove;
world.eid2obj.get(ObjectMenu.scaleButtonRef[menu])!.visible =
visible && (!isEntityPinned || canIPin) && canISpawnMove;
world.eid2obj.get(ObjectMenu.openLinkButtonRef[menu])!.visible = visible;
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;
world.eid2obj.get(ObjectMenu.refreshButtonRef[menu])!.visible = visible && canIPin && canISpawnMove && !isRefreshing;
const openLinkButtonObj = world.eid2obj.get(ObjectMenu.openLinkButtonRef[menu])!;
const mirrorButtonObj = world.eid2obj.get(ObjectMenu.mirrorButtonRef[menu])!;
const inspectButtonObj = world.eid2obj.get(ObjectMenu.inspectButtonRef[menu])!;
const refreshButtonObj = world.eid2obj.get(ObjectMenu.refreshButtonRef[menu])!;

openLinkButtonObj.visible = visible;
mirrorButtonObj.visible = visible && isVideoImagePdf && !isMirrored;
inspectButtonObj.visible = visible && isInspectable && !isInspected;
refreshButtonObj.visible = visible && !isRefreshing;

if (canISpawnMove) {
world.eid2obj.get(ObjectMenu.unpinButtonRef[menu])!.visible = visible && isEntityPinned && canIPin;
world.eid2obj.get(ObjectMenu.pinButtonRef[menu])!.visible = visible && !isEntityPinned && canIPin;
world.eid2obj.get(ObjectMenu.removeButtonRef[menu])!.visible = visible && !isEntityPinned;
world.eid2obj.get(ObjectMenu.cloneButtonRef[menu])!.visible = visible;
world.eid2obj.get(ObjectMenu.rotateButtonRef[menu])!.visible = visible && (!isEntityPinned || canIPin);
world.eid2obj.get(ObjectMenu.scaleButtonRef[menu])!.visible = visible && (!isEntityPinned || canIPin);
world.eid2obj.get(ObjectMenu.dropButtonRef[menu])!.visible =
visible && !isVideoImagePdf && !isEntityPinned && !isDropped;

openLinkButtonObj.position.fromArray(ObjectMenuPositions.openLink);
mirrorButtonObj.position.fromArray(ObjectMenuPositions.mirror);
if (isEntityPinned) {
inspectButtonObj.position.fromArray(ObjectMenuPositions.inspectP);
} else {
inspectButtonObj.position.fromArray(ObjectMenuPositions.inspect);
}
refreshButtonObj.position.fromArray(ObjectMenuPositions.refresh);
} else {
[
ObjectMenu.unpinButtonRef[menu],
ObjectMenu.pinButtonRef[menu],
ObjectMenu.removeButtonRef[menu],
ObjectMenu.cloneButtonRef[menu],
ObjectMenu.rotateButtonRef[menu],
ObjectMenu.scaleButtonRef[menu],
ObjectMenu.dropButtonRef[menu]
].forEach(ref => {
world.eid2obj.get(ref)!.visible = false;
});

openLinkButtonObj.position.fromArray(ObjectMenuPositions.openLinkU);
mirrorButtonObj.position.fromArray(ObjectMenuPositions.mirrorU);
inspectButtonObj.position.fromArray(ObjectMenuPositions.inspectU);
refreshButtonObj.position.fromArray(ObjectMenuPositions.refreshU);
}

openLinkButtonObj.matrixNeedsUpdate = true;
mirrorButtonObj.matrixNeedsUpdate = true;
inspectButtonObj.matrixNeedsUpdate = true;
refreshButtonObj.matrixNeedsUpdate = true;

// 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 Down
6 changes: 1 addition & 5 deletions src/inflators/object-menu-transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import { ObjectMenuTransform } from "../bit-components";

export const ObjectMenuTransformFlags = {
Enabled: 1 << 0,
Center: 1 << 1,
Scale: 1 << 2
Scale: 1 << 1
};

export type ObjectMenuTransformParams = {
Expand All @@ -21,9 +20,6 @@ const DEFAULTS = {
export function inflateObjectMenuTransform(world: HubsWorld, eid: EntityID, params: ObjectMenuTransformParams) {
params = Object.assign({}, DEFAULTS, params);
addComponent(world, ObjectMenuTransform, eid);
if (params.center === true) {
ObjectMenuTransform.flags[eid] |= ObjectMenuTransformFlags.Center;
}
if (params.scale === true) {
ObjectMenuTransform.flags[eid] |= ObjectMenuTransformFlags.Scale;
}
Expand Down
118 changes: 39 additions & 79 deletions src/prefabs/object-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ function InspectButton(props: Attrs) {
height={buttonHeight}
type={BUTTON_TYPES.DEFAULT}
holdable
holdableButton
icon={{ texture, cacheKey, scale: [0.165, 0.165, 0.165] }}
{...props}
/>
Expand Down Expand Up @@ -195,6 +196,7 @@ function RotateButton(props: Attrs) {
height={buttonHeight}
type={BUTTON_TYPES.ACTION}
holdable
holdableButton
icon={{ texture, cacheKey, scale: [0.165, 0.165, 0.165] }}
{...props}
/>
Expand Down Expand Up @@ -226,29 +228,35 @@ function ScaleButton(props: Attrs) {
height={buttonHeight}
type={BUTTON_TYPES.ACTION}
holdable
holdableButton
icon={{ texture, cacheKey, scale: [0.165, 0.165, 0.165] }}
{...props}
/>
);
}

// prettier-ignore
const position = {
export const ObjectMenuPositions = {
background: [ 0, 0, uiZ - 0.0005] as ArrayVec3,
pin: [ 0, 0.125, uiZ] as ArrayVec3,
unpin: [ 0, 0.125, uiZ] as ArrayVec3,
focus: [-0.25, 0.375, uiZ] as ArrayVec3,
track: [ 0.25, 0.375, uiZ] as ArrayVec3,
remove: [ 0, -0.275, uiZ] as ArrayVec3,
drop: [ 0, -0.425, 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.25, -0.425, uiZ] as ArrayVec3,
clone: [-0.25, -0.275, uiZ] as ArrayVec3,
rotate: [ -0.2, -0.125, uiZ] as ArrayVec3,
mirror: [ 0, -0.125, uiZ] as ArrayVec3,
scale: [ 0.2, -0.125, uiZ] as ArrayVec3,
pin: [ 0, 0.225, uiZ] as ArrayVec3,
unpin: [ 0, 0.225, uiZ] as ArrayVec3,
focus: [-0.25, 0.575, uiZ] as ArrayVec3,
track: [ 0.25, 0.575, uiZ] as ArrayVec3,
remove: [ 0, -0.075, uiZ] as ArrayVec3,
drop: [ 0, -0.225, uiZ] as ArrayVec3,
inspect: [ 0, -0.225, uiZ] as ArrayVec3,
inspectU: [ 0, 0.075, uiZ] as ArrayVec3,
inspectP: [ 0, -0.075, uiZ] as ArrayVec3,
deserializeDrawing: [ -0.3, -0.425, uiZ] as ArrayVec3,
openLink: [ 0.25, -0.075, uiZ] as ArrayVec3,
openLinkU: [ 0, -0.075, uiZ] as ArrayVec3,
refresh: [ 0.25, -0.225, uiZ] as ArrayVec3,
refreshU: [ 0, -0.225, uiZ] as ArrayVec3,
clone: [-0.25, -0.075, uiZ] as ArrayVec3,
rotate: [ -0.2, 0.075, uiZ] as ArrayVec3,
mirror: [ 0, 0.075, uiZ] as ArrayVec3,
mirrorU: [ 0, 0.225, uiZ] as ArrayVec3,
scale: [ 0.2, 0.075, uiZ] as ArrayVec3,
};

export function ObjectMenuPrefab() {
Expand All @@ -273,7 +281,7 @@ export function ObjectMenuPrefab() {
return (
<entity
name="Interactable Object Menu"
objectMenuTransform={{ center: true }}
objectMenuTransform
objectMenu={{
backgroundRef: refs.background,
pinButtonRef: refs.pin,
Expand All @@ -295,75 +303,27 @@ export function ObjectMenuPrefab() {
<Plane
name={"Background"}
ref={refs.background}
position={position.background}
position={ObjectMenuPositions.background}
width={0.8}
height={0.8}
material={{ transparent: true, opacity: 0, side: FrontSide }}
renderOrder={APP.RENDER_ORDER.HUD_BACKGROUND}
layers={1 << Layers.CAMERA_LAYER_UI}
/>
<PinButton ref={refs.pin} position={position.pin} />
<UnpinButton ref={refs.unpin} position={position.unpin} />
<CameraFocusButton ref={refs.focus} position={position.focus} />
<CameraTrackButton ref={refs.track} position={position.track} />
<RemoveButton ref={refs.remove} position={position.remove} />
<DropButton ref={refs.drop} position={position.drop} />
<InspectButton ref={refs.inspect} position={position.inspect} />
<DeserializeDrawingButton ref={refs.deserializeDrawing} position={position.deserializeDrawing} />
<OpenLinkButton ref={refs.openLink} position={position.openLink} />
<RefreshButton ref={refs.refresh} position={position.refresh} />
<CloneButton ref={refs.clone} position={position.clone} />
<RotateButton ref={refs.rotate} position={position.rotate} />
<MirrorButton ref={refs.mirror} position={position.mirror} />
<ScaleButton ref={refs.scale} position={position.scale} />
<PinButton ref={refs.pin} position={ObjectMenuPositions.pin} />
<UnpinButton ref={refs.unpin} position={ObjectMenuPositions.unpin} />
<CameraFocusButton ref={refs.focus} position={ObjectMenuPositions.focus} />
<CameraTrackButton ref={refs.track} position={ObjectMenuPositions.track} />
<RemoveButton ref={refs.remove} position={ObjectMenuPositions.remove} />
<DropButton ref={refs.drop} position={ObjectMenuPositions.drop} />
<InspectButton ref={refs.inspect} position={ObjectMenuPositions.inspect} />
<DeserializeDrawingButton ref={refs.deserializeDrawing} position={ObjectMenuPositions.deserializeDrawing} />
<OpenLinkButton ref={refs.openLink} position={ObjectMenuPositions.openLink} />
<RefreshButton ref={refs.refresh} position={ObjectMenuPositions.refresh} />
<CloneButton ref={refs.clone} position={ObjectMenuPositions.clone} />
<RotateButton ref={refs.rotate} position={ObjectMenuPositions.rotate} />
<MirrorButton ref={refs.mirror} position={ObjectMenuPositions.mirror} />
<ScaleButton ref={refs.scale} position={ObjectMenuPositions.scale} />
</entity>
);
}

// ui interactable-ui
// layers mask 768
// withPermission: spawn_and_move_media

// pinButtonTip: Pinning will broadcast this object to Discord.

// sprite camera-action.png
// cameraFocusLabel focus

// sprite camera-action.png
// cameraTrackLabel track

// sprite remove-action.png
//

// visibility on content types:
// "contentTypes: video/ audio/ image/ application/vnd.apple.mpegurl application/x-mpegurl application/pdf; visible: false;"
// sprite drop-action.png
// hide-when-pinned-and-forbidden

// holdable
// sprite focus-action.png
// visibility-on-content-types="contentTypes: video/ audio/ image/ application/vnd.apple.mpegurl application/x-mpegurl application/pdf;"

// sprite deserialize-action.png
// class="deserialize-drawing" : lookup what else is using this

// text: open link

// text: refresh

// text: clone

// sprite: rotate-action.png
// hide-when-pinned-and-forbidden

// sprite: inspect-action.png
// visibility-on-content-types="contentTypes: video/ audio/ image/ application/vnd.apple.mpegurl application/x-mpegurl application/pdf;"

// sprite: scale-action.png
// hide-when-pinned-and-forbidden

// unprivileged menu...
// refreshButton
// openLinkButton
// mirrorMediaButton
// inspectButton
2 changes: 1 addition & 1 deletion src/prefabs/pdf-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export function PDFMenuPrefab() {
return (
<entity
name="PDF Menu"
objectMenuTransform={{ center: false, scale: true }}
objectMenuTransform={{ scale: true }}
pdfMenu={{
prevButtonRef: refPrev,
nextButtonRef: refNext,
Expand Down
2 changes: 1 addition & 1 deletion src/prefabs/video-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ export function VideoMenuPrefab() {
return (
<entity
name="Video Menu"
objectMenuTransform={{ center: false, scale: true }}
objectMenuTransform={{ scale: true }}
videoMenu={{
sliderRef,
timeLabelRef,
Expand Down
Loading