diff --git a/src/bit-components.js b/src/bit-components.js index d4134ea535..e9a8cad58f 100644 --- a/src/bit-components.js +++ b/src/bit-components.js @@ -273,6 +273,7 @@ EnvironmentSettings.map = new Map(); // TODO: Store this data elsewhere, since only one or two will ever exist. export const ObjectMenu = defineComponent({ + backgroundRef: Types.eid, pinButtonRef: Types.eid, unpinButtonRef: Types.eid, cameraFocusButtonRef: Types.eid, diff --git a/src/bit-systems/object-menu.ts b/src/bit-systems/object-menu.ts index 3caf5495c6..ad40db7c46 100644 --- a/src/bit-systems/object-menu.ts +++ b/src/bit-systems/object-menu.ts @@ -247,6 +247,11 @@ function updateVisibility(world: HubsWorld, menu: EntityID, frozen: boolean) { world.eid2obj.get(ObjectMenu.scaleButtonRef[menu])!.visible = visible && APP.hubChannel!.can("spawn_and_move_media"); world.eid2obj.get(ObjectMenu.openLinkButtonRef[menu])!.visible = visible; + // 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. + const same = ObjectMenuTransform.prevObjectRef[menu] === ObjectMenuTransform.targetObjectRef[menu]; + world.eid2obj.get(ObjectMenu.backgroundRef[menu])!.visible = visible && same; + // Hide unimplemented features for now. // TODO: Implement and show the buttons. world.eid2obj.get(ObjectMenu.cameraFocusButtonRef[menu])!.visible = false; diff --git a/src/inflators/plane.ts b/src/inflators/plane.ts new file mode 100644 index 0000000000..6a34c4251d --- /dev/null +++ b/src/inflators/plane.ts @@ -0,0 +1,37 @@ +import { addObject3DComponent } from "../utils/jsx-entity"; +import { HubsWorld } from "../app"; +import { EntityID } from "../utils/networking-types"; +import { Mesh, MeshBasicMaterial, PlaneGeometry } from "three"; + +const MATERIAL_DEFAULTS = { + color: "#000000", + opacity: 1, + transparent: false +}; + +const PLANE_DEFAULTS = { + width: 1, + height: 1, + material: MATERIAL_DEFAULTS +}; + +export interface MeshBasicMaterialParams { + color?: string; + opacity?: number; + transparent?: boolean; +} + +export interface PlaneParams { + width?: number; + height?: number; + material?: MeshBasicMaterialParams; +} + +export function inflatePlane(world: HubsWorld, eid: EntityID, params: PlaneParams) { + params = Object.assign({}, PLANE_DEFAULTS, params); + params.material = Object.assign({}, MATERIAL_DEFAULTS, params.material); + const geometry = new PlaneGeometry(params.width, params.height); + const material = new MeshBasicMaterial({ ...params.material }); + const obj = new Mesh(geometry, material); + addObject3DComponent(world, eid, obj); +} diff --git a/src/prefabs/object-menu.tsx b/src/prefabs/object-menu.tsx index 2bf4513bf8..d3348cd5de 100644 --- a/src/prefabs/object-menu.tsx +++ b/src/prefabs/object-menu.tsx @@ -5,6 +5,7 @@ import { Button3D, BUTTON_TYPES } from "./button3D"; import rotateIconSrc from "../assets/rotate-action.png"; import scaleIconSrc from "../assets/scale-action.png"; import removeIconSrc from "../assets/remove-action.png"; +import { Plane } from "./plane"; export async function loadObjectMenuButtonIcons() { return Promise.all([ @@ -221,6 +222,7 @@ function ScaleButton(props: Attrs) { // prettier-ignore const position = { + 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, @@ -239,6 +241,7 @@ const position = { export function ObjectMenuPrefab() { const refs = { + background: createRef(), pin: createRef(), unpin: createRef(), focus: createRef(), @@ -260,6 +263,7 @@ export function ObjectMenuPrefab() { name="Interactable Object Menu" objectMenuTransform={{ center: true }} objectMenu={{ + backgroundRef: refs.background, pinButtonRef: refs.pin, unpinButtonRef: refs.unpin, cameraFocusButtonRef: refs.focus, @@ -276,6 +280,14 @@ export function ObjectMenuPrefab() { scaleButtonRef: refs.scale }} > + diff --git a/src/prefabs/plane.tsx b/src/prefabs/plane.tsx new file mode 100644 index 0000000000..2d3ce8c985 --- /dev/null +++ b/src/prefabs/plane.tsx @@ -0,0 +1,19 @@ +/** @jsx createElementEntity */ +import { Attrs, createElementEntity } from "../utils/jsx-entity"; + +export interface PlaneParams extends Attrs { + width?: number; + height?: number; + material?: MeshBasicMaterialParams; +} + +export interface MeshBasicMaterialParams extends Attrs { + color?: string; + opacity?: number; + transparent?: boolean; + // TODO Add the rest of the material properties +} + +export function Plane({ width, height, material, name = "Plane", ...props }: PlaneParams) { + return ; +} diff --git a/src/utils/jsx-entity.ts b/src/utils/jsx-entity.ts index 251dd807d3..1be91cfde1 100644 --- a/src/utils/jsx-entity.ts +++ b/src/utils/jsx-entity.ts @@ -101,6 +101,7 @@ import { HubsVideoTexture } from "../textures/HubsVideoTexture"; import { inflateMediaLink, MediaLinkParams } from "../inflators/media-link"; import { inflateObjectMenuTarget, ObjectMenuTargetParams } from "../inflators/object-menu-target"; import { inflateObjectMenuTransform, ObjectMenuTransformParams } from "../inflators/object-menu-transform"; +import { inflatePlane, PlaneParams } from "../inflators/plane"; preload( new Promise(resolve => { @@ -314,6 +315,7 @@ export interface JSXComponentData extends ComponentData { networkedFloatyObject?: any; networkedTransform?: any; objectMenu?: { + backgroundRef: Ref; pinButtonRef: Ref; unpinButtonRef: Ref; cameraFocusButtonRef: Ref; @@ -365,6 +367,7 @@ export interface JSXComponentData extends ComponentData { inspectable?: boolean; objectMenuTransform?: OptionalParams; objectMenuTarget?: OptionalParams; + plane?: PlaneParams; } export interface GLTFComponentData extends ComponentData { @@ -480,7 +483,8 @@ const jsxInflators: Required<{ [K in keyof JSXComponentData]: InflatorFn }> = { video: inflateVideo, link: inflateLink, objectMenuTransform: inflateObjectMenuTransform, - objectMenuTarget: inflateObjectMenuTarget + objectMenuTarget: inflateObjectMenuTarget, + plane: inflatePlane }; export const gltfInflators: Required<{ [K in keyof GLTFComponentData]: InflatorFn }> = {