mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Working on magballs polish
This commit is contained in:
parent
41daea7d92
commit
c8069ba73c
21 changed files with 681 additions and 206 deletions
|
@ -17,3 +17,4 @@ Script.load("users.js");
|
||||||
Script.load("grab.js");
|
Script.load("grab.js");
|
||||||
Script.load("directory.js");
|
Script.load("directory.js");
|
||||||
Script.load("dialTone.js");
|
Script.load("dialTone.js");
|
||||||
|
Script.load("libraries/omniTool.js");
|
||||||
|
|
25
examples/html/magBalls/addMode.html
Normal file
25
examples/html/magBalls/addMode.html
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../style.css">
|
||||||
|
<style>
|
||||||
|
.container {
|
||||||
|
display:table;
|
||||||
|
position:absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: 25vw;
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
line-height: normal;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container"><span>Add</span></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
25
examples/html/magBalls/deleteMode.html
Normal file
25
examples/html/magBalls/deleteMode.html
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../style.css">
|
||||||
|
<style>
|
||||||
|
.container {
|
||||||
|
display:table;
|
||||||
|
position:absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: 25vw;
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
line-height: normal;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container"><span>Delete</span></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
14
examples/html/magBalls/magBalls.css
Normal file
14
examples/html/magBalls/magBalls.css
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
.container {
|
||||||
|
display:table;
|
||||||
|
position:absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: 25vw;
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
line-height: normal;
|
||||||
|
text-align: center;
|
||||||
|
}
|
25
examples/html/magBalls/moveMode.html
Normal file
25
examples/html/magBalls/moveMode.html
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../style.css">
|
||||||
|
<style>
|
||||||
|
.container {
|
||||||
|
display:table;
|
||||||
|
position:absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: 25vw;
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
line-height: normal;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container"><span>Move</span></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
55
examples/libraries/avatarRelativeOverlays.js
Normal file
55
examples/libraries/avatarRelativeOverlays.js
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
|
||||||
|
AvatarRelativeOverlays = function() {
|
||||||
|
// id -> position & rotation
|
||||||
|
this.overlays = {};
|
||||||
|
this.lastAvatarTransform = {
|
||||||
|
position: ZERO_VECTOR,
|
||||||
|
rotation: IDENTITY_QUATERNION,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME judder in movement is annoying.... add an option to
|
||||||
|
// automatically hide all overlays when the position or orientation change and then
|
||||||
|
// restore the ones that were previously visible once the movement stops.
|
||||||
|
AvatarRelativeOverlays.prototype.onUpdate = function(deltaTime) {
|
||||||
|
// cache avatar position and orientation and only update on change
|
||||||
|
if (Vec3.equal(this.lastAvatarTransform.position, MyAvatar.position) &&
|
||||||
|
Quat.equal(this.lastAvatarTransform.rotation, MyAvatar.orientation)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lastAvatarTransform.position = MyAvatar.position;
|
||||||
|
this.lastAvatarTransform.rotation = MyAvatar.orientation;
|
||||||
|
for (var overlayId in this.overlays) {
|
||||||
|
this.updateOverlayTransform(overlayId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AvatarRelativeOverlays.prototype.updateOverlayTransform = function(overlayId) {
|
||||||
|
Overlays.editOverlay(overlayId, {
|
||||||
|
position: getEyeRelativePosition(this.overlays[overlayId].position),
|
||||||
|
rotation: getAvatarRelativeRotation(this.overlays[overlayId].rotation),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
AvatarRelativeOverlays.prototype.addOverlay = function(type, overlayDefinition) {
|
||||||
|
var overlayId = Overlays.addOverlay(type, overlayDefinition);
|
||||||
|
if (!overlayId) {
|
||||||
|
logDebug("Failed to create overlay of type " + type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.overlays[overlayId] = {
|
||||||
|
position: overlayDefinition.position || ZERO_VECTOR,
|
||||||
|
rotation: overlayDefinition.rotation || IDENTITY_QUATERNION,
|
||||||
|
};
|
||||||
|
this.updateOverlayTransform(overlayId);
|
||||||
|
return overlayId;
|
||||||
|
}
|
||||||
|
|
||||||
|
AvatarRelativeOverlays.prototype.deleteAll = function() {
|
||||||
|
for (var overlayId in this.overlays) {
|
||||||
|
Overlays.deleteOverlay(overlayId);
|
||||||
|
}
|
||||||
|
this.overlays = {};
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@ STICK_URL = HIFI_PUBLIC_BUCKET + "models/props/geo_stick.fbx";
|
||||||
|
|
||||||
ZERO_VECTOR = { x: 0, y: 0, z: 0 };
|
ZERO_VECTOR = { x: 0, y: 0, z: 0 };
|
||||||
|
|
||||||
|
IDENTITY_QUATERNION = { w: 1, x: 0, y: 0, z: 0 };
|
||||||
|
|
||||||
COLORS = {
|
COLORS = {
|
||||||
WHITE: {
|
WHITE: {
|
||||||
red: 255,
|
red: 255,
|
||||||
|
|
|
@ -29,7 +29,7 @@ var SELECTION_OVERLAY = {
|
||||||
|
|
||||||
Highlighter = function() {
|
Highlighter = function() {
|
||||||
this.highlightCube = Overlays.addOverlay("cube", this.SELECTION_OVERLAY);
|
this.highlightCube = Overlays.addOverlay("cube", this.SELECTION_OVERLAY);
|
||||||
this.hightlighted = null;
|
this.highlighted = null;
|
||||||
var _this = this;
|
var _this = this;
|
||||||
Script.scriptEnding.connect(function() {
|
Script.scriptEnding.connect(function() {
|
||||||
_this.onCleanup();
|
_this.onCleanup();
|
||||||
|
@ -40,9 +40,9 @@ Highlighter.prototype.onCleanup = function() {
|
||||||
Overlays.deleteOverlay(this.highlightCube);
|
Overlays.deleteOverlay(this.highlightCube);
|
||||||
}
|
}
|
||||||
|
|
||||||
Highlighter.prototype.highlight = function(entityId) {
|
Highlighter.prototype.highlight = function(entityIdOrPosition) {
|
||||||
if (entityId != this.hightlighted) {
|
if (entityIdOrPosition != this.highlighted) {
|
||||||
this.hightlighted = entityId;
|
this.highlighted = entityIdOrPosition;
|
||||||
this.updateHighlight();
|
this.updateHighlight();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,13 @@ Highlighter.prototype.setSize = function(newSize) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Highlighter.prototype.setColor = function(color) {
|
||||||
|
Overlays.editOverlay(this.highlightCube, {
|
||||||
|
color: color
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Highlighter.prototype.setRotation = function(newRotation) {
|
Highlighter.prototype.setRotation = function(newRotation) {
|
||||||
Overlays.editOverlay(this.highlightCube, {
|
Overlays.editOverlay(this.highlightCube, {
|
||||||
rotation: newRotation
|
rotation: newRotation
|
||||||
|
@ -60,11 +67,15 @@ Highlighter.prototype.setRotation = function(newRotation) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Highlighter.prototype.updateHighlight = function() {
|
Highlighter.prototype.updateHighlight = function() {
|
||||||
if (this.hightlighted) {
|
if (this.highlighted) {
|
||||||
var properties = Entities.getEntityProperties(this.hightlighted);
|
var position = this.highlighted;
|
||||||
|
if (typeof this.highlighted === "string") {
|
||||||
|
var properties = Entities.getEntityProperties(this.highlighted);
|
||||||
|
position = properties.position;
|
||||||
|
}
|
||||||
// logDebug("Making highlight " + this.highlightCube + " visible @ " + vec3toStr(properties.position));
|
// logDebug("Making highlight " + this.highlightCube + " visible @ " + vec3toStr(properties.position));
|
||||||
Overlays.editOverlay(this.highlightCube, {
|
Overlays.editOverlay(this.highlightCube, {
|
||||||
position: properties.position,
|
position: position,
|
||||||
visible: true
|
visible: true
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -11,13 +11,14 @@ Script.include("utils.js");
|
||||||
Script.include("highlighter.js");
|
Script.include("highlighter.js");
|
||||||
Script.include("omniTool/models/modelBase.js");
|
Script.include("omniTool/models/modelBase.js");
|
||||||
Script.include("omniTool/models/wand.js");
|
Script.include("omniTool/models/wand.js");
|
||||||
|
Script.include("omniTool/models/invisibleWand.js");
|
||||||
|
|
||||||
OmniToolModules = {};
|
OmniToolModules = {};
|
||||||
OmniToolModuleType = null;
|
OmniToolModuleType = null;
|
||||||
|
|
||||||
OmniTool = function(side) {
|
OmniTool = function(side) {
|
||||||
this.OMNI_KEY = "OmniTool";
|
this.OMNI_KEY = "OmniTool";
|
||||||
this.MAX_FRAMERATE = 30;
|
this.MAX_FRAMERATE = 60;
|
||||||
this.UPDATE_INTERVAL = 1.0 / this.MAX_FRAMERATE
|
this.UPDATE_INTERVAL = 1.0 / this.MAX_FRAMERATE
|
||||||
this.SIDE = side;
|
this.SIDE = side;
|
||||||
this.PALM = 2 * side;
|
this.PALM = 2 * side;
|
||||||
|
@ -28,6 +29,7 @@ OmniTool = function(side) {
|
||||||
this.ignoreEntities = {};
|
this.ignoreEntities = {};
|
||||||
this.nearestOmniEntity = {
|
this.nearestOmniEntity = {
|
||||||
id: null,
|
id: null,
|
||||||
|
|
||||||
inside: false,
|
inside: false,
|
||||||
position: null,
|
position: null,
|
||||||
distance: Infinity,
|
distance: Infinity,
|
||||||
|
@ -38,13 +40,11 @@ OmniTool = function(side) {
|
||||||
|
|
||||||
this.activeOmniEntityId = null;
|
this.activeOmniEntityId = null;
|
||||||
this.lastUpdateInterval = 0;
|
this.lastUpdateInterval = 0;
|
||||||
this.tipLength = 0.4;
|
|
||||||
this.active = false;
|
this.active = false;
|
||||||
this.module = null;
|
this.module = null;
|
||||||
this.moduleEntityId = null;
|
this.moduleEntityId = null;
|
||||||
this.lastScanPosition = ZERO_VECTOR;
|
this.lastScanPosition = ZERO_VECTOR;
|
||||||
this.model = new Wand();
|
this.showWand(false);
|
||||||
this.model.setLength(this.tipLength);
|
|
||||||
|
|
||||||
// Connect to desired events
|
// Connect to desired events
|
||||||
var _this = this;
|
var _this = this;
|
||||||
|
@ -65,6 +65,23 @@ OmniTool = function(side) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OmniTool.prototype.showWand = function(show) {
|
||||||
|
if (this.model && this.model.onCleanup) {
|
||||||
|
this.model.onCleanup();
|
||||||
|
}
|
||||||
|
logDebug("Showing wand: " + show);
|
||||||
|
if (show) {
|
||||||
|
this.model = new Wand();
|
||||||
|
this.model.setLength(0.4);
|
||||||
|
this.model.setVisible(true);
|
||||||
|
} else {
|
||||||
|
this.model = new InvisibleWand();
|
||||||
|
this.model.setLength(0.1);
|
||||||
|
this.model.setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
OmniTool.prototype.onCleanup = function(action) {
|
OmniTool.prototype.onCleanup = function(action) {
|
||||||
this.unloadModule();
|
this.unloadModule();
|
||||||
}
|
}
|
||||||
|
@ -110,10 +127,9 @@ OmniTool.prototype.setActive = function(active) {
|
||||||
if (active === this.active) {
|
if (active === this.active) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logDebug("omnitool changing active state: " + active);
|
logDebug("OmniTool changing active state: " + active);
|
||||||
this.active = active;
|
this.active = active;
|
||||||
this.model.setVisible(this.active);
|
this.model.setVisible(this.active);
|
||||||
|
|
||||||
if (this.module && this.module.onActiveChanged) {
|
if (this.module && this.module.onActiveChanged) {
|
||||||
this.module.onActiveChanged(this.side);
|
this.module.onActiveChanged(this.side);
|
||||||
}
|
}
|
||||||
|
@ -125,14 +141,25 @@ OmniTool.prototype.onUpdate = function(deltaTime) {
|
||||||
this.position = Controller.getSpatialControlPosition(this.PALM);
|
this.position = Controller.getSpatialControlPosition(this.PALM);
|
||||||
// When on the base, hydras report a position of 0
|
// When on the base, hydras report a position of 0
|
||||||
this.setActive(Vec3.length(this.position) > 0.001);
|
this.setActive(Vec3.length(this.position) > 0.001);
|
||||||
|
if (!this.active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (this.model) {
|
||||||
|
// Update the wand
|
||||||
|
var rawRotation = Controller.getSpatialControlRawRotation(this.PALM);
|
||||||
|
this.rotation = Quat.multiply(MyAvatar.orientation, rawRotation);
|
||||||
|
this.model.setTransform({
|
||||||
|
rotation: this.rotation,
|
||||||
|
position: this.position,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.model.onUpdate) {
|
||||||
|
this.model.onUpdate(deltaTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var rawRotation = Controller.getSpatialControlRawRotation(this.PALM);
|
|
||||||
this.rotation = Quat.multiply(MyAvatar.orientation, rawRotation);
|
|
||||||
|
|
||||||
this.model.setTransform({
|
|
||||||
rotation: this.rotation,
|
|
||||||
position: this.position,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.scan();
|
this.scan();
|
||||||
|
|
||||||
|
@ -144,6 +171,19 @@ OmniTool.prototype.onUpdate = function(deltaTime) {
|
||||||
OmniTool.prototype.onClick = function() {
|
OmniTool.prototype.onClick = function() {
|
||||||
// First check to see if the user is switching to a new omni module
|
// First check to see if the user is switching to a new omni module
|
||||||
if (this.nearestOmniEntity.inside && this.nearestOmniEntity.omniProperties.script) {
|
if (this.nearestOmniEntity.inside && this.nearestOmniEntity.omniProperties.script) {
|
||||||
|
|
||||||
|
// If this is already the active entity, turn it off
|
||||||
|
// FIXME add a flag to allow omni modules to cause this entity to be
|
||||||
|
// ignored in order to support items that will be picked up.
|
||||||
|
if (this.moduleEntityId && this.moduleEntityId == this.nearestOmniEntity.id) {
|
||||||
|
this.showWand(false);
|
||||||
|
this.unloadModule();
|
||||||
|
this.highlighter.setColor("White");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.showWand(true);
|
||||||
|
this.highlighter.setColor("Red");
|
||||||
this.activateNewOmniModule();
|
this.activateNewOmniModule();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -157,12 +197,10 @@ OmniTool.prototype.onClick = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
OmniTool.prototype.onRelease = function() {
|
OmniTool.prototype.onRelease = function() {
|
||||||
// FIXME how to I switch to a new module?
|
|
||||||
if (this.module && this.module.onRelease) {
|
if (this.module && this.module.onRelease) {
|
||||||
this.module.onRelease();
|
this.module.onRelease();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logDebug("Base omnitool does nothing on release");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME resturn a structure of all nearby entities to distances
|
// FIXME resturn a structure of all nearby entities to distances
|
||||||
|
@ -210,6 +248,11 @@ OmniTool.prototype.getPosition = function() {
|
||||||
OmniTool.prototype.onEnterNearestOmniEntity = function() {
|
OmniTool.prototype.onEnterNearestOmniEntity = function() {
|
||||||
this.nearestOmniEntity.inside = true;
|
this.nearestOmniEntity.inside = true;
|
||||||
this.highlighter.highlight(this.nearestOmniEntity.id);
|
this.highlighter.highlight(this.nearestOmniEntity.id);
|
||||||
|
if (this.moduleEntityId && this.moduleEntityId == this.nearestOmniEntity.id) {
|
||||||
|
this.highlighter.setColor("Red");
|
||||||
|
} else {
|
||||||
|
this.highlighter.setColor("White");
|
||||||
|
}
|
||||||
logDebug("On enter omniEntity " + this.nearestOmniEntity.id);
|
logDebug("On enter omniEntity " + this.nearestOmniEntity.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
6
examples/libraries/omniTool/models/invisibleWand.js
Normal file
6
examples/libraries/omniTool/models/invisibleWand.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
InvisibleWand = function() {
|
||||||
|
}
|
||||||
|
|
||||||
|
InvisibleWand.prototype = Object.create( ModelBase.prototype );
|
||||||
|
|
|
@ -17,3 +17,9 @@ ModelBase.prototype.setTransform = function(transform) {
|
||||||
this.tipVector = Vec3.multiplyQbyV(this.rotation, { x: 0, y: this.length, z: 0 });
|
this.tipVector = Vec3.multiplyQbyV(this.rotation, { x: 0, y: this.length, z: 0 });
|
||||||
this.tipPosition = Vec3.sum(this.position, this.tipVector);
|
this.tipPosition = Vec3.sum(this.position, this.tipVector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ModelBase.prototype.setTipColors = function(color1, color2) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelBase.prototype.onCleanup = function() {
|
||||||
|
}
|
||||||
|
|
|
@ -1,22 +1,18 @@
|
||||||
|
|
||||||
Wand = function() {
|
Wand = function() {
|
||||||
// Max updates fps
|
// Max updates fps
|
||||||
this.MAX_FRAMERATE = 30
|
|
||||||
this.UPDATE_INTERVAL = 1.0 / this.MAX_FRAMERATE
|
|
||||||
this.DEFAULT_TIP_COLORS = [ {
|
this.DEFAULT_TIP_COLORS = [ {
|
||||||
red: 128,
|
red: 128,
|
||||||
green: 128,
|
green: 128,
|
||||||
blue: 128,
|
blue: 128,
|
||||||
}, {
|
}, {
|
||||||
red: 64,
|
red: 0,
|
||||||
green: 64,
|
green: 0,
|
||||||
blue: 64,
|
blue: 0,
|
||||||
}];
|
}];
|
||||||
this.POINTER_ROTATION = Quat.fromPitchYawRollDegrees(45, 0, 45);
|
this.POINTER_ROTATION = Quat.fromPitchYawRollDegrees(45, 0, 45);
|
||||||
|
|
||||||
// FIXME does this need to be a member of this?
|
|
||||||
this.lastUpdateInterval = 0;
|
|
||||||
|
|
||||||
this.pointers = [
|
this.pointers = [
|
||||||
Overlays.addOverlay("cube", {
|
Overlays.addOverlay("cube", {
|
||||||
position: ZERO_VECTOR,
|
position: ZERO_VECTOR,
|
||||||
|
@ -45,17 +41,7 @@ Wand = function() {
|
||||||
|
|
||||||
var _this = this;
|
var _this = this;
|
||||||
Script.scriptEnding.connect(function() {
|
Script.scriptEnding.connect(function() {
|
||||||
Overlays.deleteOverlay(_this.pointers[0]);
|
_this.onCleanup();
|
||||||
Overlays.deleteOverlay(_this.pointers[1]);
|
|
||||||
Overlays.deleteOverlay(_this.wand);
|
|
||||||
});
|
|
||||||
|
|
||||||
Script.update.connect(function(deltaTime) {
|
|
||||||
_this.lastUpdateInterval += deltaTime;
|
|
||||||
if (_this.lastUpdateInterval >= _this.UPDATE_INTERVAL) {
|
|
||||||
_this.onUpdate(_this.lastUpdateInterval);
|
|
||||||
_this.lastUpdateInterval = 0;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +62,6 @@ Wand.prototype.setVisible = function(visible) {
|
||||||
|
|
||||||
Wand.prototype.setTransform = function(transform) {
|
Wand.prototype.setTransform = function(transform) {
|
||||||
ModelBase.prototype.setTransform.call(this, transform);
|
ModelBase.prototype.setTransform.call(this, transform);
|
||||||
|
|
||||||
var wandPosition = Vec3.sum(this.position, Vec3.multiply(0.5, this.tipVector));
|
var wandPosition = Vec3.sum(this.position, Vec3.multiply(0.5, this.tipVector));
|
||||||
Overlays.editOverlay(this.pointers[0], {
|
Overlays.editOverlay(this.pointers[0], {
|
||||||
position: this.tipPosition,
|
position: this.tipPosition,
|
||||||
|
@ -106,7 +91,10 @@ Wand.prototype.setTipColors = function(color1, color2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Wand.prototype.onUpdate = function(deltaTime) {
|
Wand.prototype.onUpdate = function(deltaTime) {
|
||||||
|
logDebug("Z4");
|
||||||
|
|
||||||
if (this.visible) {
|
if (this.visible) {
|
||||||
|
logDebug("5");
|
||||||
var time = new Date().getTime() / 250;
|
var time = new Date().getTime() / 250;
|
||||||
var scale1 = Math.abs(Math.sin(time));
|
var scale1 = Math.abs(Math.sin(time));
|
||||||
var scale2 = Math.abs(Math.cos(time));
|
var scale2 = Math.abs(Math.cos(time));
|
||||||
|
@ -118,3 +106,9 @@ Wand.prototype.onUpdate = function(deltaTime) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Wand.prototype.onCleanup = function() {
|
||||||
|
Overlays.deleteOverlay(this.pointers[0]);
|
||||||
|
Overlays.deleteOverlay(this.pointers[1]);
|
||||||
|
Overlays.deleteOverlay(this.wand);
|
||||||
|
}
|
|
@ -1,9 +1,36 @@
|
||||||
|
|
||||||
OmniToolModules.Test = function() {
|
Script.include("avatarRelativeOverlays.js");
|
||||||
|
|
||||||
|
OmniToolModules.Test = function(omniTool, activeEntityId) {
|
||||||
|
this.omniTool = omniTool;
|
||||||
|
this.activeEntityId = activeEntityId;
|
||||||
|
this.avatarOverlays = new AvatarRelativeOverlays();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OmniToolModules.Test.prototype.onUnload = function() {
|
||||||
|
if (this.testOverlay) {
|
||||||
|
Overlays.deleteOverlay(this.testOverlay);
|
||||||
|
this.testOverlay = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var CUBE_POSITION = {
|
||||||
|
x: 0.1,
|
||||||
|
y: -0.1,
|
||||||
|
z: -0.4
|
||||||
|
};
|
||||||
|
|
||||||
OmniToolModules.Test.prototype.onClick = function() {
|
OmniToolModules.Test.prototype.onClick = function() {
|
||||||
logDebug("Test module onClick");
|
if (this.testOverlay) {
|
||||||
|
Overlays.deleteOverlay(this.testOverlay);
|
||||||
|
this.testOverlay = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
OmniToolModules.Test.prototype.onUpdate = function(deltaTime) {
|
||||||
|
this.avatarOverlays.onUpdate(deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
OmniToolModuleType = "Test"
|
OmniToolModuleType = "Test"
|
|
@ -11,6 +11,15 @@ vec3toStr = function (v, digits) {
|
||||||
return "{ " + v.x.toFixed(digits) + ", " + v.y.toFixed(digits) + ", " + v.z.toFixed(digits)+ " }";
|
return "{ " + v.x.toFixed(digits) + ", " + v.y.toFixed(digits) + ", " + v.z.toFixed(digits)+ " }";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
colorMix = function(colorA, colorB, mix) {
|
||||||
|
var result = {};
|
||||||
|
for (var key in colorA) {
|
||||||
|
result[key] = (colorA[key] * (1 - mix)) + (colorB[key] * mix);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
scaleLine = function (start, end, scale) {
|
scaleLine = function (start, end, scale) {
|
||||||
var v = Vec3.subtract(end, start);
|
var v = Vec3.subtract(end, start);
|
||||||
var length = Vec3.length(v);
|
var length = Vec3.length(v);
|
||||||
|
@ -127,3 +136,13 @@ findSpherePointHit = function(sphereCenter, sphereRadius, point) {
|
||||||
findSphereSphereHit = function(firstCenter, firstRadius, secondCenter, secondRadius) {
|
findSphereSphereHit = function(firstCenter, firstRadius, secondCenter, secondRadius) {
|
||||||
return findSpherePointHit(firstCenter, firstRadius + secondRadius, secondCenter);
|
return findSpherePointHit(firstCenter, firstRadius + secondRadius, secondCenter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Given a vec3 v, return a vec3 that is the same vector relative to the avatars
|
||||||
|
// DEFAULT eye position, rotated into the avatars reference frame.
|
||||||
|
getEyeRelativePosition = function(v) {
|
||||||
|
return Vec3.sum(MyAvatar.getDefaultEyePosition(), Vec3.multiplyQbyV(MyAvatar.orientation, v));
|
||||||
|
}
|
||||||
|
|
||||||
|
getAvatarRelativeRotation = function(q) {
|
||||||
|
return Quat.multiply(MyAvatar.orientation, q);
|
||||||
|
}
|
||||||
|
|
|
@ -11,21 +11,10 @@ Script.include("../toys/magBalls/constants.js");
|
||||||
Script.include("../toys/magBalls/graph.js");
|
Script.include("../toys/magBalls/graph.js");
|
||||||
Script.include("../toys/magBalls/edgeSpring.js");
|
Script.include("../toys/magBalls/edgeSpring.js");
|
||||||
Script.include("../toys/magBalls/magBalls.js");
|
Script.include("../toys/magBalls/magBalls.js");
|
||||||
|
Script.include("avatarRelativeOverlays.js");
|
||||||
|
|
||||||
OmniToolModuleType = "MagBallsController"
|
OmniToolModuleType = "MagBallsController"
|
||||||
|
|
||||||
|
|
||||||
OmniToolModules.MagBallsController = function(omniTool, entityId) {
|
|
||||||
this.omniTool = omniTool;
|
|
||||||
this.entityId = entityId;
|
|
||||||
this.highlighter = new Highlighter();
|
|
||||||
this.magBalls = new MagBalls();
|
|
||||||
this.highlighter.setSize(BALL_SIZE);
|
|
||||||
this.ghostEdges = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
var MAG_BALLS_DATA_NAME = "magBalls";
|
|
||||||
|
|
||||||
getMagBallsData = function(id) {
|
getMagBallsData = function(id) {
|
||||||
return getEntityCustomData(MAG_BALLS_DATA_NAME, id, {});
|
return getEntityCustomData(MAG_BALLS_DATA_NAME, id, {});
|
||||||
}
|
}
|
||||||
|
@ -34,54 +23,177 @@ setMagBallsData = function(id, value) {
|
||||||
setEntityCustomData(MAG_BALLS_DATA_NAME, id, value);
|
setEntityCustomData(MAG_BALLS_DATA_NAME, id, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
//var magBalls = new MagBalls();
|
var UI_BALL_RADIUS = 0.01;
|
||||||
// DEBUGGING ONLY - Clear any previous balls
|
var MODE_INFO = { };
|
||||||
// magBalls.clear();
|
|
||||||
|
|
||||||
OmniToolModules.MagBallsController.prototype.onClick = function() {
|
MODE_INFO[BALL_EDIT_MODE_ADD] = {
|
||||||
logDebug("MagBallsController onClick: " + vec3toStr(this.tipPosition));
|
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: "file:///" + Script.resolvePath('../html/magBalls/addMode.html').replace("c:", "C:"),
|
||||||
|
};
|
||||||
|
|
||||||
|
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: "file:///" + Script.resolvePath('../html/magBalls/deleteMode.html').replace("c:", "C:"),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
this.selected = this.highlighter.hightlighted;
|
|
||||||
logDebug("This selected: " + this.selected);
|
// create the overlay relative to the avatar
|
||||||
if (!this.selected) {
|
this.uiOverlays.addOverlay("sphere", mergeObjects(UI_BALL_PROTOTYPE, {
|
||||||
this.selected = this.magBalls.createBall(this.tipPosition);
|
color: MODE_INFO[BALL_EDIT_MODE_ADD].colors[0],
|
||||||
}
|
position: MODE_INFO[BALL_EDIT_MODE_ADD].uiPosition,
|
||||||
this.magBalls.selectBall(this.selected);
|
}));
|
||||||
this.highlighter.highlight(null);
|
this.uiOverlays.addOverlay("sphere", mergeObjects(UI_BALL_PROTOTYPE, {
|
||||||
logDebug("Selected " + this.selected);
|
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.onRelease = function() {
|
OmniToolModules.MagBallsController.prototype.onUnload = function() {
|
||||||
logDebug("MagBallsController onRelease: " + vec3toStr(this.tipPosition));
|
|
||||||
this.clearGhostEdges();
|
this.clearGhostEdges();
|
||||||
if (this.selected) {
|
this.uiOverlays.deleteAll();
|
||||||
this.magBalls.releaseBall(this.selected);
|
|
||||||
this.selected = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OmniToolModules.MagBallsController.prototype.onUpdate = function(deltaTime) {
|
|
||||||
this.tipPosition = this.omniTool.getPosition();
|
OmniToolModules.MagBallsController.prototype.setMode = function(mode) {
|
||||||
if (!this.selected) {
|
if (mode === this.mode) {
|
||||||
// Find the highlight target and set it.
|
return;
|
||||||
var target = this.magBalls.findNearestNode(this.tipPosition, BALL_SELECTION_RADIUS);
|
}
|
||||||
this.highlighter.highlight(target);
|
|
||||||
if (!target) {
|
logDebug("Changing mode to '" + mode + "'");
|
||||||
this.magBalls.onUpdate(deltaTime);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.highlighter.highlight(null);
|
|
||||||
Entities.editEntity(this.selected, { position: this.tipPosition });
|
Entities.editEntity(this.selected, { position: this.tipPosition });
|
||||||
var targetBalls = this.magBalls.findPotentialEdges(this.selected);
|
var targetBalls = this.magBalls.findPotentialEdges(this.selected);
|
||||||
for (var ballId in targetBalls) {
|
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]) {
|
if (!this.ghostEdges[ballId]) {
|
||||||
// create the ovleray
|
// create the ovleray
|
||||||
this.ghostEdges[ballId] = Overlays.addOverlay("line3d", {
|
this.ghostEdges[ballId] = Overlays.addOverlay("line3d", {
|
||||||
start: this.magBalls.getNodePosition(ballId),
|
start: this.magBalls.getNodePosition(ballId),
|
||||||
end: this.tipPosition,
|
end: this.tipPosition,
|
||||||
color: COLORS.RED,
|
color: color,
|
||||||
alpha: 1,
|
alpha: 1,
|
||||||
lineWidth: 5,
|
lineWidth: 5,
|
||||||
visible: true,
|
visible: true,
|
||||||
|
@ -89,6 +201,7 @@ OmniToolModules.MagBallsController.prototype.onUpdate = function(deltaTime) {
|
||||||
} else {
|
} else {
|
||||||
Overlays.editOverlay(this.ghostEdges[ballId], {
|
Overlays.editOverlay(this.ghostEdges[ballId], {
|
||||||
end: this.tipPosition,
|
end: this.tipPosition,
|
||||||
|
color: color,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,6 +213,95 @@ OmniToolModules.MagBallsController.prototype.onUpdate = function(deltaTime) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
OmniToolModules.MagBallsController.prototype.clearGhostEdges = function() {
|
||||||
for(var ballId in this.ghostEdges) {
|
for(var ballId in this.ghostEdges) {
|
||||||
Overlays.deleteOverlay(this.ghostEdges[ballId]);
|
Overlays.deleteOverlay(this.ghostEdges[ballId]);
|
||||||
|
@ -108,6 +310,3 @@ OmniToolModules.MagBallsController.prototype.clearGhostEdges = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BallController.prototype.onUnload = function() {
|
|
||||||
this.clearGhostEdges();
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
|
||||||
|
MAG_BALLS_DATA_NAME = "magBalls";
|
||||||
|
|
||||||
// FIXME make this editable through some script UI, so the user can customize the size of the structure built
|
// FIXME make this editable through some script UI, so the user can customize the size of the structure built
|
||||||
SCALE = 0.5;
|
MAG_BALLS_SCALE = 0.5;
|
||||||
BALL_SIZE = 0.08 * SCALE;
|
BALL_SIZE = 0.08 * MAG_BALLS_SCALE;
|
||||||
STICK_LENGTH = 0.24 * SCALE;
|
STICK_LENGTH = 0.24 * MAG_BALLS_SCALE;
|
||||||
|
|
||||||
DEBUG_MAGSTICKS = true;
|
DEBUG_MAGSTICKS = true;
|
||||||
|
|
||||||
|
@ -11,8 +13,6 @@ EDGE_NAME = "MagStick";
|
||||||
|
|
||||||
BALL_RADIUS = BALL_SIZE / 2.0;
|
BALL_RADIUS = BALL_SIZE / 2.0;
|
||||||
|
|
||||||
BALL_SELECTION_RADIUS = BALL_RADIUS * 1.5;
|
|
||||||
|
|
||||||
BALL_DIMENSIONS = {
|
BALL_DIMENSIONS = {
|
||||||
x: BALL_SIZE,
|
x: BALL_SIZE,
|
||||||
y: BALL_SIZE,
|
y: BALL_SIZE,
|
||||||
|
@ -45,10 +45,13 @@ BALL_PROTOTYPE = {
|
||||||
// 2 millimeters
|
// 2 millimeters
|
||||||
BALL_EPSILON = (.002) / BALL_DISTANCE;
|
BALL_EPSILON = (.002) / BALL_DISTANCE;
|
||||||
|
|
||||||
|
// FIXME better handling of the line bounding box would require putting the
|
||||||
|
// origin in the middle of the line, not at one end
|
||||||
|
LINE_DIAGONAL = Math.sqrt((STICK_LENGTH * STICK_LENGTH * 2) * 3) * 1.1;
|
||||||
LINE_DIMENSIONS = {
|
LINE_DIMENSIONS = {
|
||||||
x: 5,
|
x: LINE_DIAGONAL,
|
||||||
y: 5,
|
y: LINE_DIAGONAL,
|
||||||
z: 5
|
z: LINE_DIAGONAL
|
||||||
}
|
}
|
||||||
|
|
||||||
LINE_PROTOTYPE = {
|
LINE_PROTOTYPE = {
|
||||||
|
@ -75,3 +78,9 @@ EDGE_PROTOTYPE = LINE_PROTOTYPE;
|
||||||
// ignoreCollisions: true,
|
// ignoreCollisions: true,
|
||||||
// collisionsWillMove: false
|
// collisionsWillMove: false
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
BALL_EDIT_MODE_ADD = "add";
|
||||||
|
BALL_EDIT_MODE_MOVE = "move";
|
||||||
|
BALL_EDIT_MODE_DELETE = "delete";
|
||||||
|
BALL_EDIT_MODE_DELETE_SHAPE = "deleteShape";
|
||||||
|
|
|
@ -1,95 +0,0 @@
|
||||||
findMatchingNode = function(position, nodePositions) {
|
|
||||||
for (var nodeId in nodePositions) {
|
|
||||||
var nodePos = nodePositions[nodeId];
|
|
||||||
var distance = Vec3.distance(position, nodePos);
|
|
||||||
if (distance < 0.03) {
|
|
||||||
return nodeId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repairConnections = function() {
|
|
||||||
var ids = Entities.findEntities(MyAvatar.position, 50);
|
|
||||||
|
|
||||||
// Find all the balls and record their positions
|
|
||||||
var nodePositions = {};
|
|
||||||
for (var i in ids) {
|
|
||||||
var id = ids[i];
|
|
||||||
var properties = Entities.getEntityProperties(id);
|
|
||||||
if (properties.name == BALL_NAME) {
|
|
||||||
nodePositions[id] = properties.position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now check all the edges to see if they're valid (point to balls)
|
|
||||||
// and ensure that the balls point back to them
|
|
||||||
var ballsToEdges = {};
|
|
||||||
for (var i in ids) {
|
|
||||||
var id = ids[i];
|
|
||||||
var properties = Entities.getEntityProperties(id);
|
|
||||||
if (properties.name == EDGE_NAME) {
|
|
||||||
var startPos = properties.position;
|
|
||||||
var endPos = Vec3.sum(startPos, properties.linePoints[1]);
|
|
||||||
var magBallData = getMagBallsData(id);
|
|
||||||
var update = false;
|
|
||||||
if (!magBallData.start) {
|
|
||||||
var startNode = findMatchingNode(startPos, nodePositions);
|
|
||||||
if (startNode) {
|
|
||||||
logDebug("Found start node " + startNode)
|
|
||||||
magBallData.start = startNode;
|
|
||||||
update = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!magBallData.end) {
|
|
||||||
var endNode = findMatchingNode(endPos, nodePositions);
|
|
||||||
if (endNode) {
|
|
||||||
logDebug("Found end node " + endNode)
|
|
||||||
magBallData.end = endNode;
|
|
||||||
update = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!magBallData.start || !magBallData.end) {
|
|
||||||
logDebug("Didn't find both ends");
|
|
||||||
Entities.deleteEntity(id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!ballsToEdges[magBallData.start]) {
|
|
||||||
ballsToEdges[magBallData.start] = [ id ];
|
|
||||||
} else {
|
|
||||||
ballsToEdges[magBallData.start].push(id);
|
|
||||||
}
|
|
||||||
if (!ballsToEdges[magBallData.end]) {
|
|
||||||
ballsToEdges[magBallData.end] = [ id ];
|
|
||||||
} else {
|
|
||||||
ballsToEdges[magBallData.end].push(id);
|
|
||||||
}
|
|
||||||
if (update) {
|
|
||||||
logDebug("Updating incomplete edge " + id);
|
|
||||||
magBallData.length = BALL_DISTANCE;
|
|
||||||
setMagBallsData(id, magBallData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (var nodeId in ballsToEdges) {
|
|
||||||
var magBallData = getMagBallsData(nodeId);
|
|
||||||
var edges = magBallData.edges || [];
|
|
||||||
var edgeHash = {};
|
|
||||||
for (var i in edges) {
|
|
||||||
edgeHash[edges[i]] = true;
|
|
||||||
}
|
|
||||||
var update = false;
|
|
||||||
for (var i in ballsToEdges[nodeId]) {
|
|
||||||
var edgeId = ballsToEdges[nodeId][i];
|
|
||||||
if (!edgeHash[edgeId]) {
|
|
||||||
update = true;
|
|
||||||
edgeHash[edgeId] = true;
|
|
||||||
edges.push(edgeId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (update) {
|
|
||||||
logDebug("Fixing node with missing edge data");
|
|
||||||
magBallData.edges = edges;
|
|
||||||
setMagBallsData(nodeId, magBallData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,7 +9,10 @@ EdgeSpring = function(edgeId, graph) {
|
||||||
this.desiredLength = magBallsData.length || BALL_DISTANCE;
|
this.desiredLength = magBallsData.length || BALL_DISTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
EdgeSpring.prototype.adjust = function(results) {
|
// FIXME as iterations increase, start introducing some randomness
|
||||||
|
// to the adjustment so that we avoid false equilibriums
|
||||||
|
// Alternatively, larger iterations could increase the acceptable variance
|
||||||
|
EdgeSpring.prototype.adjust = function(results, iterations) {
|
||||||
var startPos = this.getAdjustedPosition(this.start, results);
|
var startPos = this.getAdjustedPosition(this.start, results);
|
||||||
var endPos = this.getAdjustedPosition(this.end, results);
|
var endPos = this.getAdjustedPosition(this.end, results);
|
||||||
var vector = Vec3.subtract(endPos, startPos);
|
var vector = Vec3.subtract(endPos, startPos);
|
||||||
|
|
|
@ -25,10 +25,6 @@ MagBalls = function() {
|
||||||
this.refresh();
|
this.refresh();
|
||||||
|
|
||||||
var _this = this;
|
var _this = this;
|
||||||
//Script.update.connect(function(deltaTime) {
|
|
||||||
// _this.onUpdate(deltaTime);
|
|
||||||
//});
|
|
||||||
|
|
||||||
Script.scriptEnding.connect(function() {
|
Script.scriptEnding.connect(function() {
|
||||||
_this.onCleanup();
|
_this.onCleanup();
|
||||||
});
|
});
|
||||||
|
@ -61,8 +57,13 @@ MagBalls.prototype.onUpdate = function(deltaTime) {
|
||||||
if (!this.unstableEdges[edgeId]) {
|
if (!this.unstableEdges[edgeId]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
adjusted |= this.edgeObjects[edgeId].adjust(nodeAdjustResults);
|
// FIXME need to add some randomness to this so that objects don't hit a
|
||||||
|
// false equilibrium
|
||||||
|
// FIXME should this be done node-wise, to more easily account for the number of edge
|
||||||
|
// connections for a node?
|
||||||
|
adjusted |= this.edgeObjects[edgeId].adjust(nodeAdjustResults, this.adjustIterations);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var nodeId in nodeAdjustResults) {
|
for (var nodeId in nodeAdjustResults) {
|
||||||
var curPos = this.getNodePosition(nodeId);
|
var curPos = this.getNodePosition(nodeId);
|
||||||
var newPos = nodeAdjustResults[nodeId];
|
var newPos = nodeAdjustResults[nodeId];
|
||||||
|
@ -71,18 +72,24 @@ MagBalls.prototype.onUpdate = function(deltaTime) {
|
||||||
fixupEdges[edgeId] = true;
|
fixupEdges[edgeId] = true;
|
||||||
}
|
}
|
||||||
// logDebug("Moving node Id " + nodeId + " " + (distance * 1000).toFixed(3) + " mm");
|
// logDebug("Moving node Id " + nodeId + " " + (distance * 1000).toFixed(3) + " mm");
|
||||||
Entities.editEntity(nodeId, { position: newPos, color: COLORS.RED });
|
Entities.editEntity(nodeId, {
|
||||||
|
position: newPos,
|
||||||
|
// DEBUGGING, flashes moved balls
|
||||||
|
// color: COLORS.RED
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEBUGGING, flashes moved balls
|
||||||
|
//Script.setTimeout(function(){
|
||||||
|
// for (var nodeId in nodeAdjustResults) {
|
||||||
|
// Entities.editEntity(nodeId, { color: BALL_COLOR });
|
||||||
|
// }
|
||||||
|
//}, ((UPDATE_INTERVAL * 1000) / 2));
|
||||||
|
|
||||||
for (var edgeId in fixupEdges) {
|
for (var edgeId in fixupEdges) {
|
||||||
this.fixupEdge(edgeId);
|
this.fixupEdge(edgeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Script.setTimeout(function(){
|
|
||||||
for (var nodeId in nodeAdjustResults) {
|
|
||||||
Entities.editEntity(nodeId, { color: BALL_COLOR });
|
|
||||||
}
|
|
||||||
}, ((UPDATE_INTERVAL * 1000) / 2));
|
|
||||||
|
|
||||||
if (!adjusted || this.adjustIterations > this.MAX_ADJUST_ITERATIONS) {
|
if (!adjusted || this.adjustIterations > this.MAX_ADJUST_ITERATIONS) {
|
||||||
if (adjusted) {
|
if (adjusted) {
|
||||||
|
@ -357,4 +364,96 @@ MagBalls.prototype.onEntityAdded = function(entityId) {
|
||||||
if (properties.name == BALL_NAME || properties.name == EDGE_NAME) {
|
if (properties.name == BALL_NAME || properties.name == EDGE_NAME) {
|
||||||
this.refreshNeeded = 1;
|
this.refreshNeeded = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
findMatchingNode = function(position, nodePositions) {
|
||||||
|
for (var nodeId in nodePositions) {
|
||||||
|
var nodePos = nodePositions[nodeId];
|
||||||
|
var distance = Vec3.distance(position, nodePos);
|
||||||
|
if (distance < 0.03) {
|
||||||
|
return nodeId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MagBalls.prototype.repair = function() {
|
||||||
|
// Find all the balls and record their positions
|
||||||
|
var nodePositions = {};
|
||||||
|
for (var nodeId in this.nodes) {
|
||||||
|
nodePositions[nodeId] = this.getNodePosition(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now check all the edges to see if they're valid (point to balls)
|
||||||
|
// and ensure that the balls point back to them
|
||||||
|
var ballsToEdges = {};
|
||||||
|
|
||||||
|
// WARNING O(n^2) algorithm, every edge that is broken does
|
||||||
|
// an O(N) search against the nodes
|
||||||
|
for (var edgeId in this.edges) {
|
||||||
|
var properties = Entities.getEntityProperties(edgeId);
|
||||||
|
var startPos = properties.position;
|
||||||
|
var endPos = Vec3.sum(startPos, properties.linePoints[1]);
|
||||||
|
var magBallData = getMagBallsData(edgeId);
|
||||||
|
var update = false;
|
||||||
|
if (!magBallData.start) {
|
||||||
|
var startNode = findMatchingNode(startPos, nodePositions);
|
||||||
|
if (startNode) {
|
||||||
|
logDebug("Found start node " + startNode)
|
||||||
|
magBallData.start = startNode;
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!magBallData.end) {
|
||||||
|
var endNode = findMatchingNode(endPos, nodePositions);
|
||||||
|
if (endNode) {
|
||||||
|
logDebug("Found end node " + endNode)
|
||||||
|
magBallData.end = endNode;
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!magBallData.start || !magBallData.end) {
|
||||||
|
logDebug("Didn't find both ends");
|
||||||
|
this.destroyEdge(edgeId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!ballsToEdges[magBallData.start]) {
|
||||||
|
ballsToEdges[magBallData.start] = [ edgeId ];
|
||||||
|
} else {
|
||||||
|
ballsToEdges[magBallData.start].push(edgeId);
|
||||||
|
}
|
||||||
|
if (!ballsToEdges[magBallData.end]) {
|
||||||
|
ballsToEdges[magBallData.end] = [ edgeId ];
|
||||||
|
} else {
|
||||||
|
ballsToEdges[magBallData.end].push(edgeId);
|
||||||
|
}
|
||||||
|
if (update) {
|
||||||
|
logDebug("Updating incomplete edge " + edgeId);
|
||||||
|
magBallData.length = BALL_DISTANCE;
|
||||||
|
setMagBallsData(edgeId, magBallData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var nodeId in ballsToEdges) {
|
||||||
|
var magBallData = getMagBallsData(nodeId);
|
||||||
|
var edges = magBallData.edges || [];
|
||||||
|
var edgeHash = {};
|
||||||
|
for (var i in edges) {
|
||||||
|
edgeHash[edges[i]] = true;
|
||||||
|
}
|
||||||
|
var update = false;
|
||||||
|
for (var i in ballsToEdges[nodeId]) {
|
||||||
|
var edgeId = ballsToEdges[nodeId][i];
|
||||||
|
if (!edgeHash[edgeId]) {
|
||||||
|
update = true;
|
||||||
|
edgeHash[edgeId] = true;
|
||||||
|
edges.push(edgeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (update) {
|
||||||
|
logDebug("Fixing node with missing edge data");
|
||||||
|
magBallData.edges = edges;
|
||||||
|
setMagBallsData(nodeId, magBallData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -147,7 +147,12 @@ QScriptValue Web3DOverlay::getProperty(const QString& property) {
|
||||||
|
|
||||||
void Web3DOverlay::setURL(const QString& url) {
|
void Web3DOverlay::setURL(const QString& url) {
|
||||||
_url = url;
|
_url = url;
|
||||||
_isLoaded = false;
|
if (_webSurface) {
|
||||||
|
AbstractViewStateInterface::instance()->postLambdaEvent([this, url] {
|
||||||
|
_webSurface->getRootItem()->setProperty("url", url);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Web3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) {
|
bool Web3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) {
|
||||||
|
|
|
@ -23,10 +23,12 @@
|
||||||
out vec3 _normal;
|
out vec3 _normal;
|
||||||
out vec3 _color;
|
out vec3 _color;
|
||||||
out vec2 _texCoord0;
|
out vec2 _texCoord0;
|
||||||
|
out vec4 _position;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
_color = inColor.rgb;
|
_color = inColor.rgb;
|
||||||
_texCoord0 = inTexCoord0.st;
|
_texCoord0 = inTexCoord0.st;
|
||||||
|
_position = inPosition;
|
||||||
|
|
||||||
// standard transform
|
// standard transform
|
||||||
TransformCamera cam = getTransformCamera();
|
TransformCamera cam = getTransformCamera();
|
||||||
|
|
Loading…
Reference in a new issue