overte-thingvellir/script-archive/magBalls.js
2016-04-26 11:18:22 -07:00

311 lines
9.2 KiB
JavaScript

//
// Created by Bradley Austin Davis on 2015/08/25
// Copyright 2015 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
//
// FIXME Script paths have to be relative to the caller, in this case libraries/OmniTool.js
Script.include("magBalls/constants.js");
Script.include("magBalls/graph.js");
Script.include("magBalls/edgeSpring.js");
Script.include("magBalls/magBalls.js");
Script.include("libraries/avatarRelativeOverlays.js");
OmniToolModuleType = "MagBallsController"
getMagBallsData = function(id) {
return getEntityCustomData(MAG_BALLS_DATA_NAME, id, {});
}
setMagBallsData = function(id, value) {
setEntityCustomData(MAG_BALLS_DATA_NAME, id, value);
}
var UI_BALL_RADIUS = 0.01;
var MODE_INFO = { };
MODE_INFO[BALL_EDIT_MODE_ADD] = {
uiPosition: {
x: 0.15,
y: -0.08,
z: -0.35,
},
colors: [ COLORS.GREEN, COLORS.BLUE ],
// FIXME use an http path or find a way to get the relative path to the file
url: Script.resolvePath('html/magBalls/addMode.html'),
};
MODE_INFO[BALL_EDIT_MODE_DELETE] = {
uiPosition: {
x: 0.20,
y: -0.08,
z: -0.32,
},
colors: [ COLORS.RED, COLORS.BLUE ],
// FIXME use an http path or find a way to get the relative path to the file
url: Script.resolvePath('html/magBalls/deleteMode.html'),
};
var UI_POSITION_MODE_LABEL = Vec3.multiply(0.5,
Vec3.sum(MODE_INFO[BALL_EDIT_MODE_ADD].uiPosition,
MODE_INFO[BALL_EDIT_MODE_DELETE].uiPosition));
UI_POSITION_MODE_LABEL.y = -0.02;
var UI_BALL_PROTOTYPE = {
size: UI_BALL_RADIUS * 2.0,
alpha: 1.0,
solid: true,
visible: true,
}
OmniToolModules.MagBallsController = function(omniTool, entityId) {
this.omniTool = omniTool;
this.entityId = entityId;
// In hold mode, holding a ball requires that you keep the action
// button pressed, while if this is false, clicking on a ball selects
// it and clicking again will drop it.
this.holdMode = true;
this.highlighter = new Highlighter();
this.magBalls = new MagBalls();
this.highlighter.setSize(BALL_SIZE);
this.ghostEdges = {};
this.selectionRadiusMultipler = 1.5;
this.uiOverlays = new AvatarRelativeOverlays();
// create the overlay relative to the avatar
this.uiOverlays.addOverlay("sphere", mergeObjects(UI_BALL_PROTOTYPE, {
color: MODE_INFO[BALL_EDIT_MODE_ADD].colors[0],
position: MODE_INFO[BALL_EDIT_MODE_ADD].uiPosition,
}));
this.uiOverlays.addOverlay("sphere", mergeObjects(UI_BALL_PROTOTYPE, {
color: MODE_INFO[BALL_EDIT_MODE_DELETE].colors[0],
position: MODE_INFO[BALL_EDIT_MODE_DELETE].uiPosition,
}));
// FIXME find the proper URLs to use
this.modeLabel = this.uiOverlays.addOverlay("web3d", {
isFacingAvatar: true,
alpha: 1.0,
dimensions: { x: 0.16, y: 0.12, z: 0.001},
color: "White",
position: UI_POSITION_MODE_LABEL,
});
this.setMode(BALL_EDIT_MODE_ADD);
// DEBUGGING ONLY - Fix old, bad edge bounding boxes
//for (var edgeId in this.magBalls.edges) {
// Entities.editEntity(edgeId, {
// dimensions: LINE_DIMENSIONS,
// });
//}
// DEBUGGING ONLY - Clear any previous balls
// this.magBalls.clear();
// DEBUGGING ONLY - Attempt to fix connections between balls
// and delete bad connections. Warning... if you haven't looked around
// and caused the domain server to send you all the nearby balls as well as the connections,
// this can break your structures
// this.magBalls.repair();
}
OmniToolModules.MagBallsController.prototype.onUnload = function() {
this.clearGhostEdges();
this.uiOverlays.deleteAll();
}
OmniToolModules.MagBallsController.prototype.setMode = function(mode) {
if (mode === this.mode) {
return;
}
logDebug("Changing mode to '" + mode + "'");
Overlays.editOverlay(this.modeLabel, {
url: MODE_INFO[mode].url
});
this.mode = mode;
var color1;
var color2;
switch (this.mode) {
case BALL_EDIT_MODE_ADD:
color1 = COLORS.BLUE;
color2 = COLORS.GREEN;
break;
case BALL_EDIT_MODE_MOVE:
color1 = COLORS.GREEN;
color2 = COLORS.LIGHT_GREEN;
break;
case BALL_EDIT_MODE_DELETE:
color1 = COLORS.RED;
color2 = COLORS.BLUE;
break;
case BALL_EDIT_MODE_DELETE_SHAPE:
color1 = COLORS.RED;
color2 = COLORS.YELLOW;
break;
}
this.omniTool.model.setTipColors(color1, color2);
}
OmniToolModules.MagBallsController.prototype.findUiBallHit = function() {
var result = null;
for (var mode in MODE_INFO) {
var modeInfo = MODE_INFO[mode];
var spherePoint = getEyeRelativePosition(modeInfo.uiPosition);
if (findSpherePointHit(spherePoint, UI_BALL_RADIUS * 2, this.tipPosition)) {
this.highlighter.highlight(spherePoint);
this.highlighter.setColor("White");
// FIXME why doesn't this work?
this.highlighter.setSize(UI_BALL_RADIUS * 4);
return mode;
}
}
return;
}
OmniToolModules.MagBallsController.prototype.onUpdateSelected = function(deltaTime) {
if (!this.selected) {
return;
}
Entities.editEntity(this.selected, { position: this.tipPosition });
var targetBalls = this.magBalls.findPotentialEdges(this.selected);
for (var ballId in targetBalls) {
var targetPosition = this.magBalls.getNodePosition(ballId);
var distance = Vec3.distance(targetPosition, this.tipPosition);
var variance = this.magBalls.getVariance(distance);
var mix = Math.abs(variance) / this.magBalls.MAX_VARIANCE;
var color = colorMix(COLORS.YELLOW, COLORS.RED, mix);
if (!this.ghostEdges[ballId]) {
// create the ovleray
this.ghostEdges[ballId] = Overlays.addOverlay("line3d", {
start: this.magBalls.getNodePosition(ballId),
end: this.tipPosition,
color: color,
alpha: 1,
lineWidth: 5,
visible: true,
});
} else {
Overlays.editOverlay(this.ghostEdges[ballId], {
end: this.tipPosition,
color: color,
});
}
}
for (var ballId in this.ghostEdges) {
if (!targetBalls[ballId]) {
Overlays.deleteOverlay(this.ghostEdges[ballId]);
delete this.ghostEdges[ballId];
}
}
}
OmniToolModules.MagBallsController.prototype.onUpdate = function(deltaTime) {
this.tipPosition = this.omniTool.getPosition();
this.uiOverlays.onUpdate(deltaTime);
this.onUpdateSelected();
if (this.findUiBallHit()) {
return;
}
if (!this.selected) {
// Find the highlight target and set it.
var target = this.magBalls.findNearestNode(this.tipPosition, BALL_RADIUS * this.selectionRadiusMultipler);
this.highlighter.highlight(target);
this.highlighter.setColor(MODE_INFO[this.mode].colors[0]);
if (!target) {
this.magBalls.onUpdate(deltaTime);
}
return;
}
}
OmniToolModules.MagBallsController.prototype.deselect = function() {
if (!this.selected) {
return false
}
this.clearGhostEdges();
this.magBalls.releaseBall(this.selected);
this.selected = null;
return true;
}
OmniToolModules.MagBallsController.prototype.onClick = function() {
var newMode = this.findUiBallHit();
if (newMode) {
if (this.selected) {
this.magBalls.destroyNode(highlighted);
this.selected = null;
}
this.setMode(newMode);
return;
}
if (this.deselect()) {
return;
}
logDebug("MagBallsController onClick: " + vec3toStr(this.tipPosition));
// TODO add checking against UI shapes for adding or deleting balls.
var highlighted = this.highlighter.highlighted;
if (this.mode == BALL_EDIT_MODE_ADD && !highlighted) {
highlighted = this.magBalls.createBall(this.tipPosition);
}
// Nothing to select or create means we're done here.
if (!highlighted) {
return;
}
switch (this.mode) {
case BALL_EDIT_MODE_ADD:
case BALL_EDIT_MODE_MOVE:
this.magBalls.selectBall(highlighted);
this.selected = highlighted;
logDebug("Selected " + this.selected);
break;
case BALL_EDIT_MODE_DELETE:
this.magBalls.destroyNode(highlighted);
break;
case BALL_EDIT_MODE_DELETE_SHAPE:
logDebug("Not implemented yet");
break;
}
if (this.selected) {
this.highlighter.highlight(null);
}
}
OmniToolModules.MagBallsController.prototype.onRelease = function() {
if (this.holdMode) {
this.deselect();
}
}
OmniToolModules.MagBallsController.prototype.clearGhostEdges = function() {
for(var ballId in this.ghostEdges) {
Overlays.deleteOverlay(this.ghostEdges[ballId]);
delete this.ghostEdges[ballId];
}
}