mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:44:02 +02:00
commit
127271110c
21 changed files with 681 additions and 206 deletions
|
@ -17,3 +17,4 @@ Script.load("users.js");
|
|||
Script.load("grab.js");
|
||||
Script.load("directory.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 };
|
||||
|
||||
IDENTITY_QUATERNION = { w: 1, x: 0, y: 0, z: 0 };
|
||||
|
||||
COLORS = {
|
||||
WHITE: {
|
||||
red: 255,
|
||||
|
|
|
@ -29,7 +29,7 @@ var SELECTION_OVERLAY = {
|
|||
|
||||
Highlighter = function() {
|
||||
this.highlightCube = Overlays.addOverlay("cube", this.SELECTION_OVERLAY);
|
||||
this.hightlighted = null;
|
||||
this.highlighted = null;
|
||||
var _this = this;
|
||||
Script.scriptEnding.connect(function() {
|
||||
_this.onCleanup();
|
||||
|
@ -40,9 +40,9 @@ Highlighter.prototype.onCleanup = function() {
|
|||
Overlays.deleteOverlay(this.highlightCube);
|
||||
}
|
||||
|
||||
Highlighter.prototype.highlight = function(entityId) {
|
||||
if (entityId != this.hightlighted) {
|
||||
this.hightlighted = entityId;
|
||||
Highlighter.prototype.highlight = function(entityIdOrPosition) {
|
||||
if (entityIdOrPosition != this.highlighted) {
|
||||
this.highlighted = entityIdOrPosition;
|
||||
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) {
|
||||
Overlays.editOverlay(this.highlightCube, {
|
||||
rotation: newRotation
|
||||
|
@ -60,11 +67,15 @@ Highlighter.prototype.setRotation = function(newRotation) {
|
|||
}
|
||||
|
||||
Highlighter.prototype.updateHighlight = function() {
|
||||
if (this.hightlighted) {
|
||||
var properties = Entities.getEntityProperties(this.hightlighted);
|
||||
if (this.highlighted) {
|
||||
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));
|
||||
Overlays.editOverlay(this.highlightCube, {
|
||||
position: properties.position,
|
||||
position: position,
|
||||
visible: true
|
||||
});
|
||||
} else {
|
||||
|
|
|
@ -11,13 +11,14 @@ Script.include("utils.js");
|
|||
Script.include("highlighter.js");
|
||||
Script.include("omniTool/models/modelBase.js");
|
||||
Script.include("omniTool/models/wand.js");
|
||||
Script.include("omniTool/models/invisibleWand.js");
|
||||
|
||||
OmniToolModules = {};
|
||||
OmniToolModuleType = null;
|
||||
|
||||
OmniTool = function(side) {
|
||||
this.OMNI_KEY = "OmniTool";
|
||||
this.MAX_FRAMERATE = 30;
|
||||
this.MAX_FRAMERATE = 60;
|
||||
this.UPDATE_INTERVAL = 1.0 / this.MAX_FRAMERATE
|
||||
this.SIDE = side;
|
||||
this.PALM = 2 * side;
|
||||
|
@ -28,6 +29,7 @@ OmniTool = function(side) {
|
|||
this.ignoreEntities = {};
|
||||
this.nearestOmniEntity = {
|
||||
id: null,
|
||||
|
||||
inside: false,
|
||||
position: null,
|
||||
distance: Infinity,
|
||||
|
@ -38,13 +40,11 @@ OmniTool = function(side) {
|
|||
|
||||
this.activeOmniEntityId = null;
|
||||
this.lastUpdateInterval = 0;
|
||||
this.tipLength = 0.4;
|
||||
this.active = false;
|
||||
this.module = null;
|
||||
this.moduleEntityId = null;
|
||||
this.lastScanPosition = ZERO_VECTOR;
|
||||
this.model = new Wand();
|
||||
this.model.setLength(this.tipLength);
|
||||
this.showWand(false);
|
||||
|
||||
// Connect to desired events
|
||||
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) {
|
||||
this.unloadModule();
|
||||
}
|
||||
|
@ -110,10 +127,9 @@ OmniTool.prototype.setActive = function(active) {
|
|||
if (active === this.active) {
|
||||
return;
|
||||
}
|
||||
logDebug("omnitool changing active state: " + active);
|
||||
logDebug("OmniTool changing active state: " + active);
|
||||
this.active = active;
|
||||
this.model.setVisible(this.active);
|
||||
|
||||
if (this.module && this.module.onActiveChanged) {
|
||||
this.module.onActiveChanged(this.side);
|
||||
}
|
||||
|
@ -125,14 +141,25 @@ OmniTool.prototype.onUpdate = function(deltaTime) {
|
|||
this.position = Controller.getSpatialControlPosition(this.PALM);
|
||||
// When on the base, hydras report a position of 0
|
||||
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();
|
||||
|
||||
|
@ -144,6 +171,19 @@ OmniTool.prototype.onUpdate = function(deltaTime) {
|
|||
OmniTool.prototype.onClick = function() {
|
||||
// First check to see if the user is switching to a new omni module
|
||||
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();
|
||||
return;
|
||||
}
|
||||
|
@ -157,12 +197,10 @@ OmniTool.prototype.onClick = function() {
|
|||
}
|
||||
|
||||
OmniTool.prototype.onRelease = function() {
|
||||
// FIXME how to I switch to a new module?
|
||||
if (this.module && this.module.onRelease) {
|
||||
this.module.onRelease();
|
||||
return;
|
||||
}
|
||||
logDebug("Base omnitool does nothing on release");
|
||||
}
|
||||
|
||||
// FIXME resturn a structure of all nearby entities to distances
|
||||
|
@ -210,6 +248,11 @@ OmniTool.prototype.getPosition = function() {
|
|||
OmniTool.prototype.onEnterNearestOmniEntity = function() {
|
||||
this.nearestOmniEntity.inside = true;
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
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.tipPosition = Vec3.sum(this.position, this.tipVector);
|
||||
}
|
||||
|
||||
ModelBase.prototype.setTipColors = function(color1, color2) {
|
||||
}
|
||||
|
||||
ModelBase.prototype.onCleanup = function() {
|
||||
}
|
||||
|
|
|
@ -1,22 +1,18 @@
|
|||
|
||||
Wand = function() {
|
||||
// Max updates fps
|
||||
this.MAX_FRAMERATE = 30
|
||||
this.UPDATE_INTERVAL = 1.0 / this.MAX_FRAMERATE
|
||||
this.DEFAULT_TIP_COLORS = [ {
|
||||
red: 128,
|
||||
green: 128,
|
||||
blue: 128,
|
||||
}, {
|
||||
red: 64,
|
||||
green: 64,
|
||||
blue: 64,
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 0,
|
||||
}];
|
||||
this.POINTER_ROTATION = Quat.fromPitchYawRollDegrees(45, 0, 45);
|
||||
|
||||
// FIXME does this need to be a member of this?
|
||||
this.lastUpdateInterval = 0;
|
||||
|
||||
|
||||
this.pointers = [
|
||||
Overlays.addOverlay("cube", {
|
||||
position: ZERO_VECTOR,
|
||||
|
@ -45,17 +41,7 @@ Wand = function() {
|
|||
|
||||
var _this = this;
|
||||
Script.scriptEnding.connect(function() {
|
||||
Overlays.deleteOverlay(_this.pointers[0]);
|
||||
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;
|
||||
}
|
||||
_this.onCleanup();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -76,7 +62,6 @@ Wand.prototype.setVisible = function(visible) {
|
|||
|
||||
Wand.prototype.setTransform = function(transform) {
|
||||
ModelBase.prototype.setTransform.call(this, transform);
|
||||
|
||||
var wandPosition = Vec3.sum(this.position, Vec3.multiply(0.5, this.tipVector));
|
||||
Overlays.editOverlay(this.pointers[0], {
|
||||
position: this.tipPosition,
|
||||
|
@ -106,7 +91,10 @@ Wand.prototype.setTipColors = function(color1, color2) {
|
|||
}
|
||||
|
||||
Wand.prototype.onUpdate = function(deltaTime) {
|
||||
logDebug("Z4");
|
||||
|
||||
if (this.visible) {
|
||||
logDebug("5");
|
||||
var time = new Date().getTime() / 250;
|
||||
var scale1 = Math.abs(Math.sin(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() {
|
||||
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"
|
|
@ -11,6 +11,15 @@ vec3toStr = function (v, 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) {
|
||||
var v = Vec3.subtract(end, start);
|
||||
var length = Vec3.length(v);
|
||||
|
@ -127,3 +136,13 @@ findSpherePointHit = function(sphereCenter, sphereRadius, point) {
|
|||
findSphereSphereHit = function(firstCenter, firstRadius, secondCenter, secondRadius) {
|
||||
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/edgeSpring.js");
|
||||
Script.include("../toys/magBalls/magBalls.js");
|
||||
Script.include("avatarRelativeOverlays.js");
|
||||
|
||||
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) {
|
||||
return getEntityCustomData(MAG_BALLS_DATA_NAME, id, {});
|
||||
}
|
||||
|
@ -34,54 +23,177 @@ setMagBallsData = function(id, value) {
|
|||
setEntityCustomData(MAG_BALLS_DATA_NAME, id, value);
|
||||
}
|
||||
|
||||
//var magBalls = new MagBalls();
|
||||
// DEBUGGING ONLY - Clear any previous balls
|
||||
// magBalls.clear();
|
||||
var UI_BALL_RADIUS = 0.01;
|
||||
var MODE_INFO = { };
|
||||
|
||||
OmniToolModules.MagBallsController.prototype.onClick = function() {
|
||||
logDebug("MagBallsController onClick: " + vec3toStr(this.tipPosition));
|
||||
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: "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);
|
||||
if (!this.selected) {
|
||||
this.selected = this.magBalls.createBall(this.tipPosition);
|
||||
}
|
||||
this.magBalls.selectBall(this.selected);
|
||||
this.highlighter.highlight(null);
|
||||
logDebug("Selected " + this.selected);
|
||||
|
||||
// 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.onRelease = function() {
|
||||
logDebug("MagBallsController onRelease: " + vec3toStr(this.tipPosition));
|
||||
OmniToolModules.MagBallsController.prototype.onUnload = function() {
|
||||
this.clearGhostEdges();
|
||||
if (this.selected) {
|
||||
this.magBalls.releaseBall(this.selected);
|
||||
this.selected = null;
|
||||
}
|
||||
this.uiOverlays.deleteAll();
|
||||
}
|
||||
|
||||
OmniToolModules.MagBallsController.prototype.onUpdate = function(deltaTime) {
|
||||
this.tipPosition = this.omniTool.getPosition();
|
||||
if (!this.selected) {
|
||||
// Find the highlight target and set it.
|
||||
var target = this.magBalls.findNearestNode(this.tipPosition, BALL_SELECTION_RADIUS);
|
||||
this.highlighter.highlight(target);
|
||||
if (!target) {
|
||||
this.magBalls.onUpdate(deltaTime);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
this.highlighter.highlight(null);
|
||||
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: COLORS.RED,
|
||||
color: color,
|
||||
alpha: 1,
|
||||
lineWidth: 5,
|
||||
visible: true,
|
||||
|
@ -89,6 +201,7 @@ OmniToolModules.MagBallsController.prototype.onUpdate = function(deltaTime) {
|
|||
} else {
|
||||
Overlays.editOverlay(this.ghostEdges[ballId], {
|
||||
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() {
|
||||
for(var ballId in this.ghostEdges) {
|
||||
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
|
||||
SCALE = 0.5;
|
||||
BALL_SIZE = 0.08 * SCALE;
|
||||
STICK_LENGTH = 0.24 * SCALE;
|
||||
MAG_BALLS_SCALE = 0.5;
|
||||
BALL_SIZE = 0.08 * MAG_BALLS_SCALE;
|
||||
STICK_LENGTH = 0.24 * MAG_BALLS_SCALE;
|
||||
|
||||
DEBUG_MAGSTICKS = true;
|
||||
|
||||
|
@ -11,8 +13,6 @@ EDGE_NAME = "MagStick";
|
|||
|
||||
BALL_RADIUS = BALL_SIZE / 2.0;
|
||||
|
||||
BALL_SELECTION_RADIUS = BALL_RADIUS * 1.5;
|
||||
|
||||
BALL_DIMENSIONS = {
|
||||
x: BALL_SIZE,
|
||||
y: BALL_SIZE,
|
||||
|
@ -45,10 +45,13 @@ BALL_PROTOTYPE = {
|
|||
// 2 millimeters
|
||||
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 = {
|
||||
x: 5,
|
||||
y: 5,
|
||||
z: 5
|
||||
x: LINE_DIAGONAL,
|
||||
y: LINE_DIAGONAL,
|
||||
z: LINE_DIAGONAL
|
||||
}
|
||||
|
||||
LINE_PROTOTYPE = {
|
||||
|
@ -75,3 +78,9 @@ EDGE_PROTOTYPE = LINE_PROTOTYPE;
|
|||
// ignoreCollisions: true,
|
||||
// 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;
|
||||
}
|
||||
|
||||
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 endPos = this.getAdjustedPosition(this.end, results);
|
||||
var vector = Vec3.subtract(endPos, startPos);
|
||||
|
|
|
@ -25,10 +25,6 @@ MagBalls = function() {
|
|||
this.refresh();
|
||||
|
||||
var _this = this;
|
||||
//Script.update.connect(function(deltaTime) {
|
||||
// _this.onUpdate(deltaTime);
|
||||
//});
|
||||
|
||||
Script.scriptEnding.connect(function() {
|
||||
_this.onCleanup();
|
||||
});
|
||||
|
@ -61,8 +57,13 @@ MagBalls.prototype.onUpdate = function(deltaTime) {
|
|||
if (!this.unstableEdges[edgeId]) {
|
||||
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) {
|
||||
var curPos = this.getNodePosition(nodeId);
|
||||
var newPos = nodeAdjustResults[nodeId];
|
||||
|
@ -71,18 +72,24 @@ MagBalls.prototype.onUpdate = function(deltaTime) {
|
|||
fixupEdges[edgeId] = true;
|
||||
}
|
||||
// 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) {
|
||||
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) {
|
||||
|
@ -357,4 +364,96 @@ MagBalls.prototype.onEntityAdded = function(entityId) {
|
|||
if (properties.name == BALL_NAME || properties.name == EDGE_NAME) {
|
||||
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) {
|
||||
_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) {
|
||||
|
|
|
@ -23,10 +23,12 @@
|
|||
out vec3 _normal;
|
||||
out vec3 _color;
|
||||
out vec2 _texCoord0;
|
||||
out vec4 _position;
|
||||
|
||||
void main(void) {
|
||||
_color = inColor.rgb;
|
||||
_texCoord0 = inTexCoord0.st;
|
||||
_position = inPosition;
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
|
|
Loading…
Reference in a new issue