overte/unpublishedScripts/marketplace/shapes/modules/createPalette.js

552 lines
20 KiB
JavaScript

//
// createPalette.js
//
// Created by David Rowe on 28 Jul 2017.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* global CreatePalette:true, App, Feedback, History, Preload, UIT */
CreatePalette = function (side, leftInputs, rightInputs, uiCommandCallback) {
// Tool menu displayed on top of forearm.
"use strict";
var paletteOriginOverlay,
paletteHeaderHeadingOverlay,
paletteHeaderBarOverlay,
paletteTitleOverlay,
palettePanelOverlay,
paletteItemOverlays = [],
paletteItemPositions = [],
paletteItemHoverOverlays = [],
iconOverlays = [],
staticOverlays = [],
LEFT_HAND = 0,
controlJointName,
PALETTE_ORIGIN_POSITION = {
x: 0,
y: UIT.dimensions.handOffset,
z: UIT.dimensions.canvasSeparation + UIT.dimensions.canvas.x / 2
},
PALETTE_ORIGIN_ROTATION = Quat.ZERO,
paletteLateralOffset,
PALETTE_ORIGIN_PROPERTIES = {
dimensions: { x: 0.005, y: 0.005, z: 0.005 },
localPosition: PALETTE_ORIGIN_POSITION,
localRotation: PALETTE_ORIGIN_ROTATION,
color: { red: 255, blue: 0, green: 0 },
alpha: 1.0,
parentID: Uuid.SELF,
ignoreRayIntersection: true,
visible: false
},
PALETTE_HEADER_HEADING_PROPERTIES = {
url: Script.resolvePath("../assets/gray-header.fbx"),
dimensions: UIT.dimensions.headerHeading, // Model is in rotated coordinate system but can override.
localPosition: {
x: 0,
y: UIT.dimensions.canvas.y / 2 - UIT.dimensions.headerHeading.y / 2,
z: UIT.dimensions.headerHeading.z / 2
},
localRotation: Quat.ZERO,
alpha: 1.0,
solid: true,
ignoreRayIntersection: false,
visible: true
},
PALETTE_HEADER_BAR_PROPERTIES = {
url: Script.resolvePath("../assets/blue-header-bar.fbx"),
dimensions: UIT.dimensions.headerBar, // Model is in rotated coordinate system but can override.
localPosition: {
x: 0,
y: UIT.dimensions.canvas.y / 2 - UIT.dimensions.headerHeading.y - UIT.dimensions.headerBar.y / 2,
z: UIT.dimensions.headerBar.z / 2
},
localRotation: Quat.ZERO,
alpha: 1.0,
solid: true,
ignoreRayIntersection: false,
visible: true
},
PALETTE_TITLE_PROPERTIES = {
url: Script.resolvePath("../assets/create/create-heading.svg"),
scale: 0.0363,
localPosition: {
x: 0,
y: 0,
z: PALETTE_HEADER_HEADING_PROPERTIES.dimensions.z / 2 + UIT.dimensions.imageOverlayOffset
},
localRotation: Quat.ZERO,
color: UIT.colors.white,
alpha: 1.0,
emissive: true,
ignoreRayIntersection: true,
isFacingAvatar: false,
visible: true
},
PALETTE_PANEL_PROPERTIES = {
dimensions: UIT.dimensions.panel,
localPosition: { x: 0, y: (UIT.dimensions.panel.y - UIT.dimensions.canvas.y) / 2, z: UIT.dimensions.panel.z / 2 },
localRotation: Quat.ZERO,
color: UIT.colors.baseGray,
alpha: 1.0,
solid: true,
ignoreRayIntersection: false,
visible: true
},
ENTITY_CREATION_DIMENSIONS = { x: 0.2, y: 0.2, z: 0.2 },
ENTITY_CREATION_COLOR = { red: 192, green: 192, blue: 192 },
PALETTE_ITEM = {
overlay: "cube", // Invisible cube for hit area.
properties: {
dimensions: UIT.dimensions.itemCollisionZone,
localRotation: Quat.ZERO,
alpha: 0.0, // Invisible.
solid: true,
ignoreRayIntersection: false,
visible: true // So that laser intersects.
},
hoverButton: {
// Relative to root overlay.
overlay: "cube",
properties: {
dimensions: UIT.dimensions.paletteItemButtonDimensions,
localPosition: UIT.dimensions.paletteItemButtonOffset,
localRotation: Quat.ZERO,
color: UIT.colors.blueHighlight,
alpha: 1.0,
emissive: true, // TODO: This has no effect.
solid: true,
ignoreRayIntersection: true,
visible: false
}
},
icon: {
// Relative to hoverButton.
overlay: "model",
properties: {
dimensions: UIT.dimensions.paletteItemIconDimensions,
localPosition: UIT.dimensions.paletteItemIconOffset,
localRotation: Quat.ZERO,
emissive: true, // TODO: This has no effect.
ignoreRayIntersection: true
}
},
entity: {
dimensions: ENTITY_CREATION_DIMENSIONS
}
},
PALETTE_ITEMS = [
{
icon: {
properties: {
url: Script.resolvePath("../assets/create/cube.fbx")
}
},
entity: {
type: "Box",
dimensions: ENTITY_CREATION_DIMENSIONS,
color: ENTITY_CREATION_COLOR
}
},
{
icon: {
properties: {
url: Script.resolvePath("../assets/create/sphere.fbx")
}
},
entity: {
type: "Sphere",
dimensions: ENTITY_CREATION_DIMENSIONS,
color: ENTITY_CREATION_COLOR
}
},
{
icon: {
properties: {
url: Script.resolvePath("../assets/create/tetrahedron.fbx")
}
},
entity: {
type: "Shape",
shape: "Tetrahedron",
dimensions: ENTITY_CREATION_DIMENSIONS,
color: ENTITY_CREATION_COLOR
}
},
{
icon: {
properties: {
url: Script.resolvePath("../assets/create/octahedron.fbx")
}
},
entity: {
type: "Shape",
shape: "Octahedron",
dimensions: ENTITY_CREATION_DIMENSIONS,
color: ENTITY_CREATION_COLOR
}
},
{
icon: {
properties: {
url: Script.resolvePath("../assets/create/icosahedron.fbx")
}
},
entity: {
type: "Shape",
shape: "Icosahedron",
dimensions: ENTITY_CREATION_DIMENSIONS,
color: ENTITY_CREATION_COLOR
}
},
{
icon: {
properties: {
url: Script.resolvePath("../assets/create/dodecahedron.fbx")
}
},
entity: {
type: "Shape",
shape: "Dodecahedron",
dimensions: ENTITY_CREATION_DIMENSIONS,
color: ENTITY_CREATION_COLOR
}
},
{
icon: {
properties: {
url: Script.resolvePath("../assets/create/hexagon.fbx"),
dimensions: { x: 0.02078, y: 0.024, z: 0.024 },
localRotation: Quat.fromVec3Degrees({ x: 90, y: 0, z: 0 })
}
},
entity: {
type: "Shape",
shape: "Hexagon",
dimensions: ENTITY_CREATION_DIMENSIONS,
color: ENTITY_CREATION_COLOR
}
},
{
icon: {
properties: {
url: Script.resolvePath("../assets/create/prism.fbx"),
localRotation: Quat.fromVec3Degrees({ x: 90, y: 0, z: 0 })
}
},
entity: {
type: "Shape",
shape: "Triangle",
dimensions: ENTITY_CREATION_DIMENSIONS,
color: ENTITY_CREATION_COLOR
}
},
{
icon: {
properties: {
url: Script.resolvePath("../assets/create/octagon.fbx"),
dimensions: { x: 0.023805, y: 0.024, z: 0.024 },
localRotation: Quat.fromVec3Degrees({ x: 90, y: 0, z: 0 })
}
},
entity: {
type: "Shape",
shape: "Octagon",
dimensions: ENTITY_CREATION_DIMENSIONS,
color: ENTITY_CREATION_COLOR
}
},
{
icon: {
properties: {
url: Script.resolvePath("../assets/create/cylinder.fbx"),
localRotation: Quat.fromVec3Degrees({ x: 90, y: 0, z: 0 })
}
},
entity: {
type: "Shape",
shape: "Cylinder",
dimensions: ENTITY_CREATION_DIMENSIONS,
color: ENTITY_CREATION_COLOR
}
},
{
icon: {
properties: {
url: Script.resolvePath("../assets/create/cone.fbx"),
localRotation: Quat.fromVec3Degrees({ x: 90, y: 0, z: 0 })
}
},
entity: {
type: "Shape",
shape: "Cone",
dimensions: ENTITY_CREATION_DIMENSIONS,
color: ENTITY_CREATION_COLOR
}
},
{
icon: {
properties: {
url: Script.resolvePath("../assets/create/circle.fbx"),
dimensions: { x: 0.024, y: 0.0005, z: 0.024 },
localRotation: Quat.fromVec3Degrees({ x: 90, y: 0, z: 0 })
}
},
entity: {
type: "Shape",
shape: "Circle",
dimensions: ENTITY_CREATION_DIMENSIONS,
color: ENTITY_CREATION_COLOR
}
}
],
isDisplaying = false,
NONE = -1,
highlightedItem = NONE,
wasTriggerClicked = false,
otherSide,
// References.
controlHand;
if (!(this instanceof CreatePalette)) {
return new CreatePalette();
}
function getAssetURLs() {
return Preload.findURLs([PALETTE_HEADER_HEADING_PROPERTIES, PALETTE_HEADER_BAR_PROPERTIES, PALETTE_TITLE_PROPERTIES,
PALETTE_ITEMS]);
}
function setHand(hand) {
// Assumes UI is not displaying.
var NUMBER_OF_HANDS = 2;
side = hand;
otherSide = (side + 1) % NUMBER_OF_HANDS;
controlHand = side === LEFT_HAND ? rightInputs.hand() : leftInputs.hand();
controlJointName = side === LEFT_HAND ? "LeftHand" : "RightHand";
paletteLateralOffset = side === LEFT_HAND ? -UIT.dimensions.handLateralOffset : UIT.dimensions.handLateralOffset;
}
setHand(side);
function getOverlayIDs() {
return [palettePanelOverlay, paletteHeaderHeadingOverlay, paletteHeaderBarOverlay].concat(paletteItemOverlays);
}
function setVisible(visible) {
var i,
length;
for (i = 0, length = staticOverlays.length; i < length; i++) {
Overlays.editOverlay(staticOverlays[i], { visible: visible });
}
if (!visible) {
for (i = 0, length = paletteItemHoverOverlays.length; i < length; i++) {
Overlays.editOverlay(paletteItemHoverOverlays[i], { visible: false });
}
}
}
function update(intersectionOverlayID) {
var itemIndex,
isTriggerClicked,
properties,
CREATE_OFFSET = { x: 0, y: 0.05, z: -0.02 },
INVERSE_HAND_BASIS_ROTATION = Quat.fromVec3Degrees({ x: 0, y: 0, z: -90 }),
entityID;
itemIndex = paletteItemOverlays.indexOf(intersectionOverlayID);
// Unhighlight and lower old item.
if (highlightedItem !== NONE && (itemIndex === NONE || itemIndex !== highlightedItem)) {
Overlays.editOverlay(paletteItemHoverOverlays[highlightedItem], {
localPosition: UIT.dimensions.paletteItemButtonOffset,
visible: false
});
highlightedItem = NONE;
}
// Highlight and raise new item.
if (itemIndex !== NONE && highlightedItem !== itemIndex) {
Feedback.play(otherSide, Feedback.HOVER_BUTTON);
Overlays.editOverlay(paletteItemHoverOverlays[itemIndex], {
localPosition: UIT.dimensions.paletteItemButtonHoveredOffset,
visible: true
});
highlightedItem = itemIndex;
}
// Press item and create new entity.
isTriggerClicked = controlHand.triggerClicked();
if (highlightedItem !== NONE && isTriggerClicked && !wasTriggerClicked) {
// Create entity.
Feedback.play(otherSide, Feedback.CREATE_ENTITY);
properties = Object.clone(PALETTE_ITEMS[itemIndex].entity);
properties.position = Vec3.sum(controlHand.palmPosition(),
Vec3.multiplyQbyV(controlHand.orientation(),
Vec3.sum({ x: 0, y: properties.dimensions.z / 2, z: 0 }, CREATE_OFFSET)));
properties.rotation = Quat.multiply(controlHand.orientation(), INVERSE_HAND_BASIS_ROTATION);
entityID = Entities.addEntity(properties);
if (entityID !== Uuid.NULL) {
History.prePush(
otherSide,
{ deleteEntities: [{ entityID: entityID }] },
{ createEntities: [{ entityID: entityID, properties: properties }] }
);
} else {
Feedback.play(otherSide, Feedback.GENERAL_ERROR);
}
// Lower and unhighlight item.
Overlays.editOverlay(paletteItemHoverOverlays[itemIndex], {
localPosition: UIT.dimensions.paletteItemButtonOffset,
visible: false
});
uiCommandCallback("autoGrab");
}
wasTriggerClicked = isTriggerClicked;
}
function itemPosition(index) {
// Position relative to palette panel.
var ITEMS_PER_ROW = 4,
ROW_ZERO_Y_OFFSET = 0.0860,
ROW_SPACING = 0.0560,
COLUMN_ZERO_OFFSET = -0.08415,
COLUMN_SPACING = 0.0561,
row,
column;
row = Math.floor(index / ITEMS_PER_ROW);
column = index % ITEMS_PER_ROW;
return {
x: COLUMN_ZERO_OFFSET + column * COLUMN_SPACING,
y: ROW_ZERO_Y_OFFSET - row * ROW_SPACING,
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.itemCollisionZone.z / 2
};
}
function display() {
// Creates and shows menu entities.
var handJointIndex,
properties,
i,
length;
if (isDisplaying) {
return;
}
// Joint index.
handJointIndex = MyAvatar.getJointIndex(controlJointName);
if (handJointIndex === NONE) {
// Don't display if joint isn't available (yet) to attach to.
// User can clear this condition by toggling the app off and back on once avatar finishes loading.
App.log(side, "ERROR: CreatePalette: Hand joint index isn't available!");
return;
}
// Calculate position to put palette.
properties = Object.clone(PALETTE_ORIGIN_PROPERTIES);
properties.parentJointIndex = handJointIndex;
properties.localPosition = Vec3.sum(PALETTE_ORIGIN_POSITION, { x: paletteLateralOffset, y: 0, z: 0 });
paletteOriginOverlay = Overlays.addOverlay("sphere", properties);
// Header.
properties = Object.clone(PALETTE_HEADER_HEADING_PROPERTIES);
properties.parentID = paletteOriginOverlay;
paletteHeaderHeadingOverlay = Overlays.addOverlay("model", properties);
properties = Object.clone(PALETTE_HEADER_BAR_PROPERTIES);
properties.parentID = paletteOriginOverlay;
paletteHeaderBarOverlay = Overlays.addOverlay("model", properties);
properties = Object.clone(PALETTE_TITLE_PROPERTIES);
properties.parentID = paletteHeaderHeadingOverlay;
paletteTitleOverlay = Overlays.addOverlay("image3d", properties);
// Palette background.
properties = Object.clone(PALETTE_PANEL_PROPERTIES);
properties.parentID = paletteOriginOverlay;
palettePanelOverlay = Overlays.addOverlay("cube", properties);
// Palette items.
for (i = 0, length = PALETTE_ITEMS.length; i < length; i++) {
// Collision overlay.
properties = Object.clone(PALETTE_ITEM.properties);
properties.parentID = palettePanelOverlay;
properties.localPosition = itemPosition(i);
paletteItemOverlays[i] = Overlays.addOverlay(PALETTE_ITEM.overlay, properties);
paletteItemPositions[i] = properties.localPosition;
// Highlight overlay.
properties = Object.clone(PALETTE_ITEM.hoverButton.properties);
properties.parentID = paletteItemOverlays[i];
paletteItemHoverOverlays[i] = Overlays.addOverlay(PALETTE_ITEM.hoverButton.overlay, properties);
// Icon overlay.
properties = Object.clone(PALETTE_ITEM.icon.properties);
properties = Object.merge(properties, PALETTE_ITEMS[i].icon.properties);
properties.parentID = paletteItemHoverOverlays[i];
iconOverlays[i] = Overlays.addOverlay(PALETTE_ITEM.icon.overlay, properties);
}
// Always-visible overlays.
staticOverlays = [].concat(paletteHeaderHeadingOverlay, paletteHeaderBarOverlay, paletteTitleOverlay,
palettePanelOverlay, paletteItemOverlays, iconOverlays);
isDisplaying = true;
}
function clear() {
// Deletes menu entities.
if (!isDisplaying) {
return;
}
Overlays.deleteOverlay(paletteOriginOverlay); // Automatically deletes all other overlays because they're children.
paletteItemOverlays = [];
paletteItemHoverOverlays = [];
iconOverlays = [];
staticOverlays = [];
isDisplaying = false;
}
function destroy() {
clear();
}
return {
assetURLs: getAssetURLs,
setHand: setHand,
overlayIDs: getOverlayIDs,
setVisible: setVisible,
update: update,
display: display,
clear: clear,
destroy: destroy
};
};
CreatePalette.prototype = {};