mirror of
https://github.com/overte-org/overte.git
synced 2025-04-25 00:56:48 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into metavoxels
This commit is contained in:
commit
d48b7b8ede
35 changed files with 1351 additions and 291 deletions
|
@ -13,7 +13,6 @@ include(${MACRO_DIR}/IncludeGLM.cmake)
|
|||
include_glm(${TARGET_NAME} ${ROOT_DIR})
|
||||
|
||||
include(${MACRO_DIR}/SetupHifiProject.cmake)
|
||||
|
||||
setup_hifi_project(${TARGET_NAME} TRUE)
|
||||
|
||||
# link in the shared library
|
||||
|
|
|
@ -171,7 +171,7 @@ void DomainServer::createStaticAssignmentsForTypeGivenConfigString(Assignment::T
|
|||
|
||||
QStringList multiConfigList = configString.split(";", QString::SkipEmptyParts);
|
||||
|
||||
const QString ASSIGNMENT_CONFIG_POOL_REGEX = "--pool\\s*(\\w+)";
|
||||
const QString ASSIGNMENT_CONFIG_POOL_REGEX = "--pool\\s*([\\w-]+)";
|
||||
QRegExp poolRegex(ASSIGNMENT_CONFIG_POOL_REGEX);
|
||||
|
||||
// read each config to a payload for this type of assignment
|
||||
|
|
62
examples/addVoxelOnMouseClickExample.js
Normal file
62
examples/addVoxelOnMouseClickExample.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
//
|
||||
// addVoxelOnMouseClickExample.js
|
||||
// hifi
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2/6/14.
|
||||
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||
//
|
||||
// This is an example script that demonstrates use of the Camera and Voxels class to implement
|
||||
// clicking on a voxel and adding a new voxel on the clicked on face
|
||||
//
|
||||
//
|
||||
|
||||
function mousePressEvent(event) {
|
||||
print("mousePressEvent event.x,y=" + event.x + ", " + event.y);
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
var intersection = Voxels.findRayIntersection(pickRay);
|
||||
if (intersection.intersects) {
|
||||
|
||||
// Note: due to the current C++ "click on voxel" behavior, these values may be the animated color for the voxel
|
||||
print("clicked on voxel.red/green/blue=" + intersection.voxel.red + ", "
|
||||
+ intersection.voxel.green + ", " + intersection.voxel.blue);
|
||||
print("clicked on voxel.x/y/z/s=" + intersection.voxel.x + ", "
|
||||
+ intersection.voxel.y + ", " + intersection.voxel.z+ ": " + intersection.voxel.s);
|
||||
print("clicked on face=" + intersection.face);
|
||||
print("clicked on distance=" + intersection.distance);
|
||||
|
||||
var newVoxel = {
|
||||
x: intersection.voxel.x,
|
||||
y: intersection.voxel.y,
|
||||
z: intersection.voxel.z,
|
||||
s: intersection.voxel.s,
|
||||
red: 255,
|
||||
green: 0,
|
||||
blue: 255 };
|
||||
|
||||
if (intersection.face == "MIN_X_FACE") {
|
||||
newVoxel.x -= newVoxel.s;
|
||||
} else if (intersection.face == "MAX_X_FACE") {
|
||||
newVoxel.x += newVoxel.s;
|
||||
} else if (intersection.face == "MIN_Y_FACE") {
|
||||
newVoxel.y -= newVoxel.s;
|
||||
} else if (intersection.face == "MAX_Y_FACE") {
|
||||
newVoxel.y += newVoxel.s;
|
||||
} else if (intersection.face == "MIN_Z_FACE") {
|
||||
newVoxel.z -= newVoxel.s;
|
||||
} else if (intersection.face == "MAX_Z_FACE") {
|
||||
newVoxel.z += newVoxel.s;
|
||||
}
|
||||
|
||||
print("Voxels.setVoxel("+newVoxel.x + ", "
|
||||
+ newVoxel.y + ", " + newVoxel.z + ", " + newVoxel.s + ", "
|
||||
+ newVoxel.red + ", " + newVoxel.green + ", " + newVoxel.blue + ")" );
|
||||
|
||||
Voxels.setVoxel(newVoxel.x, newVoxel.y, newVoxel.z, newVoxel.s, newVoxel.red, newVoxel.green, newVoxel.blue);
|
||||
}
|
||||
}
|
||||
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
|
||||
function scriptEnding() {
|
||||
}
|
||||
Script.scriptEnding.connect(scriptEnding);
|
|
@ -20,6 +20,7 @@ function checkController() {
|
|||
var numberOfTriggers = Controller.getNumberOfTriggers();
|
||||
var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
|
||||
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
|
||||
var triggerToggled = false;
|
||||
|
||||
// this is expected for hydras
|
||||
if (numberOfTriggers == 2 && controllersPerTrigger == 2) {
|
||||
|
@ -46,157 +47,150 @@ function checkController() {
|
|||
}
|
||||
}
|
||||
|
||||
// register the call back so it fires before each data send
|
||||
Script.willSendVisualDataCallback.connect(checkController);
|
||||
|
||||
function printKeyEvent(eventName, event) {
|
||||
print(eventName);
|
||||
print(" event.key=" + event.key);
|
||||
print(" event.text=" + event.text);
|
||||
print(" event.isShifted=" + event.isShifted);
|
||||
print(" event.isControl=" + event.isControl);
|
||||
print(" event.isMeta=" + event.isMeta);
|
||||
print(" event.isAlt=" + event.isAlt);
|
||||
print(" event.isKeypad=" + event.isKeypad);
|
||||
}
|
||||
function keyPressEvent(event) {
|
||||
print("keyPressEvent event.key=" + event.key);
|
||||
print("keyPressEvent event.text=" + event.text);
|
||||
printKeyEvent("keyPressEvent", event);
|
||||
|
||||
print("keyPressEvent event.isShifted=" + event.isShifted);
|
||||
print("keyPressEvent event.isControl=" + event.isControl);
|
||||
print("keyPressEvent event.isMeta=" + event.isMeta);
|
||||
print("keyPressEvent event.isAlt=" + event.isAlt);
|
||||
print("keyPressEvent event.isKeypad=" + event.isKeypad);
|
||||
|
||||
|
||||
if (event.key == "A".charCodeAt(0)) {
|
||||
if (event.text == "A") {
|
||||
print("the A key was pressed");
|
||||
}
|
||||
if (event.key == " ".charCodeAt(0)) {
|
||||
if (event.text == " ") {
|
||||
print("the <space> key was pressed");
|
||||
}
|
||||
}
|
||||
|
||||
function mouseMoveEvent(event) {
|
||||
print("mouseMoveEvent event.x,y=" + event.x + ", " + event.y);
|
||||
}
|
||||
function keyReleaseEvent(event) {
|
||||
printKeyEvent("keyReleaseEvent", event);
|
||||
|
||||
function touchBeginEvent(event) {
|
||||
print("touchBeginEvent event.x,y=" + event.x + ", " + event.y);
|
||||
if (event.text == "A") {
|
||||
print("the A key was released");
|
||||
}
|
||||
if (event.text == " ") {
|
||||
print("the <space> key was pressed");
|
||||
}
|
||||
}
|
||||
|
||||
function touchUpdateEvent(event) {
|
||||
print("touchUpdateEvent event.x,y=" + event.x + ", " + event.y);
|
||||
}
|
||||
|
||||
function touchEndEvent(event) {
|
||||
print("touchEndEvent event.x,y=" + event.x + ", " + event.y);
|
||||
}
|
||||
|
||||
// register the call back so it fires before each data send
|
||||
Script.willSendVisualDataCallback.connect(checkController);
|
||||
|
||||
// Map keyPress and mouse move events to our callbacks
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
var KeyEvent_A = {
|
||||
key: "A".charCodeAt(0),
|
||||
text: "A",
|
||||
isShifted: false,
|
||||
isMeta: false
|
||||
};
|
||||
|
||||
var KeyEvent_a = {
|
||||
text: "a",
|
||||
isShifted: false,
|
||||
isMeta: false
|
||||
};
|
||||
|
||||
var KeyEvent_a2 = {
|
||||
key: "a".charCodeAt(0),
|
||||
isShifted: false,
|
||||
isMeta: false
|
||||
};
|
||||
|
||||
var KeyEvent_a3 = {
|
||||
text: "a"
|
||||
};
|
||||
|
||||
var KeyEvent_A2 = {
|
||||
text: "A"
|
||||
};
|
||||
|
||||
|
||||
var KeyEvent_9 = {
|
||||
text: "9"
|
||||
};
|
||||
|
||||
var KeyEvent_Num = {
|
||||
text: "#"
|
||||
};
|
||||
|
||||
var KeyEvent_At = {
|
||||
text: "@"
|
||||
};
|
||||
|
||||
var KeyEvent_MetaAt = {
|
||||
text: "@",
|
||||
isMeta: true
|
||||
};
|
||||
|
||||
var KeyEvent_Up = {
|
||||
text: "up"
|
||||
};
|
||||
var KeyEvent_Down = {
|
||||
text: "down"
|
||||
};
|
||||
var KeyEvent_Left = {
|
||||
text: "left"
|
||||
};
|
||||
var KeyEvent_Right = {
|
||||
text: "right"
|
||||
};
|
||||
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||
|
||||
// prevent the A key from going through to the application
|
||||
print("KeyEvent_A");
|
||||
Controller.captureKeyEvents(KeyEvent_A);
|
||||
|
||||
print("KeyEvent_A2");
|
||||
Controller.captureKeyEvents(KeyEvent_A2);
|
||||
|
||||
print("KeyEvent_a");
|
||||
Controller.captureKeyEvents(KeyEvent_a);
|
||||
|
||||
print("KeyEvent_a2");
|
||||
Controller.captureKeyEvents(KeyEvent_a2);
|
||||
|
||||
print("KeyEvent_a3");
|
||||
Controller.captureKeyEvents(KeyEvent_a3);
|
||||
|
||||
print("KeyEvent_9");
|
||||
Controller.captureKeyEvents(KeyEvent_9);
|
||||
|
||||
print("KeyEvent_Num");
|
||||
Controller.captureKeyEvents(KeyEvent_Num);
|
||||
|
||||
print("KeyEvent_At");
|
||||
Controller.captureKeyEvents(KeyEvent_At);
|
||||
|
||||
print("KeyEvent_MetaAt");
|
||||
Controller.captureKeyEvents(KeyEvent_MetaAt);
|
||||
|
||||
print("KeyEvent_Up");
|
||||
Controller.captureKeyEvents(KeyEvent_Up);
|
||||
print("KeyEvent_Down");
|
||||
Controller.captureKeyEvents(KeyEvent_Down);
|
||||
print("KeyEvent_Left");
|
||||
Controller.captureKeyEvents(KeyEvent_Left);
|
||||
print("KeyEvent_Right");
|
||||
Controller.captureKeyEvents(KeyEvent_Right);
|
||||
Controller.captureKeyEvents({ text: "A" });
|
||||
Controller.captureKeyEvents({ key: "A".charCodeAt(0) }); // same as above, just another example of how to capture the key
|
||||
Controller.captureKeyEvents({ text: " " });
|
||||
Controller.captureKeyEvents({ text: "@", isMeta: true });
|
||||
Controller.captureKeyEvents({ text: "page up" });
|
||||
Controller.captureKeyEvents({ text: "page down" });
|
||||
|
||||
|
||||
function printMouseEvent(eventName, event) {
|
||||
print(eventName);
|
||||
print(" event.x,y=" + event.x + ", " + event.y);
|
||||
print(" event.button=" + event.button);
|
||||
print(" event.isLeftButton=" + event.isLeftButton);
|
||||
print(" event.isRightButton=" + event.isRightButton);
|
||||
print(" event.isMiddleButton=" + event.isMiddleButton);
|
||||
print(" event.isShifted=" + event.isShifted);
|
||||
print(" event.isControl=" + event.isControl);
|
||||
print(" event.isMeta=" + event.isMeta);
|
||||
print(" event.isAlt=" + event.isAlt);
|
||||
}
|
||||
|
||||
function mouseMoveEvent(event) {
|
||||
printMouseEvent("mouseMoveEvent", event);
|
||||
}
|
||||
function mousePressEvent(event) {
|
||||
printMouseEvent("mousePressEvent", event);
|
||||
}
|
||||
|
||||
function mouseReleaseEvent(event) {
|
||||
printMouseEvent("mouseReleaseEvent", event);
|
||||
}
|
||||
|
||||
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
||||
|
||||
function printTouchEvent(eventName, event) {
|
||||
print(eventName);
|
||||
|
||||
print(" event.x,y=" + event.x + ", " + event.y);
|
||||
print(" event.isPressed=" + event.isPressed);
|
||||
print(" event.isMoved=" + event.isMoved);
|
||||
print(" event.isStationary=" + event.isStationary);
|
||||
print(" event.isReleased=" + event.isReleased);
|
||||
print(" event.isShifted=" + event.isShifted);
|
||||
print(" event.isControl=" + event.isControl);
|
||||
print(" event.isMeta=" + event.isMeta);
|
||||
print(" event.isAlt=" + event.isAlt);
|
||||
for (var i = 0; i < event.points.length; i++) {
|
||||
print(" event.points[" + i + "].x.y:" + event.points[i].x + ", " + event.points[i].y);
|
||||
}
|
||||
print(" event.radius=" + event.radius);
|
||||
print(" event.isPinching=" + event.isPinching);
|
||||
print(" event.isPinchOpening=" + event.isPinchOpening);
|
||||
|
||||
print(" event.angle=" + event.angle);
|
||||
for (var i = 0; i < event.points.length; i++) {
|
||||
print(" event.angles[" + i + "]:" + event.angles[i]);
|
||||
}
|
||||
print(" event.isRotating=" + event.isRotating);
|
||||
print(" event.rotating=" + event.rotating);
|
||||
}
|
||||
|
||||
function touchBeginEvent(event) {
|
||||
printTouchEvent("touchBeginEvent", event);
|
||||
}
|
||||
|
||||
function touchUpdateEvent(event) {
|
||||
printTouchEvent("touchUpdateEvent", event);
|
||||
}
|
||||
|
||||
function touchEndEvent(event) {
|
||||
printTouchEvent("touchEndEvent", event);
|
||||
}
|
||||
// Map touch events to our callbacks
|
||||
Controller.touchBeginEvent.connect(touchBeginEvent);
|
||||
Controller.touchUpdateEvent.connect(touchUpdateEvent);
|
||||
Controller.touchEndEvent.connect(touchEndEvent);
|
||||
|
||||
// disable the standard application for touch events
|
||||
Controller.captureTouchEvents();
|
||||
|
||||
function wheelEvent(event) {
|
||||
print("wheelEvent");
|
||||
print(" event.x,y=" + event.x + ", " + event.y);
|
||||
print(" event.delta=" + event.delta);
|
||||
print(" event.orientation=" + event.orientation);
|
||||
print(" event.isLeftButton=" + event.isLeftButton);
|
||||
print(" event.isRightButton=" + event.isRightButton);
|
||||
print(" event.isMiddleButton=" + event.isMiddleButton);
|
||||
print(" event.isShifted=" + event.isShifted);
|
||||
print(" event.isControl=" + event.isControl);
|
||||
print(" event.isMeta=" + event.isMeta);
|
||||
print(" event.isAlt=" + event.isAlt);
|
||||
}
|
||||
|
||||
Controller.wheelEvent.connect(wheelEvent);
|
||||
|
||||
function scriptEnding() {
|
||||
// re-enabled the standard application for touch events
|
||||
Controller.releaseTouchEvents();
|
||||
Controller.releaseKeyEvents({ text: "A" });
|
||||
Controller.releaseKeyEvents({ key: "A".charCodeAt(0) }); // same as above, just another example of how to capture the key
|
||||
Controller.releaseKeyEvents({ text: " " });
|
||||
Controller.releaseKeyEvents({ text: "@", isMeta: true });
|
||||
Controller.releaseKeyEvents({ text: "page up" });
|
||||
Controller.releaseKeyEvents({ text: "page down" });
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
|
170
examples/editVoxels.js
Normal file
170
examples/editVoxels.js
Normal file
|
@ -0,0 +1,170 @@
|
|||
//
|
||||
// editVoxels.js
|
||||
// hifi
|
||||
//
|
||||
// Created by Philip Rosedale on February 8, 2014
|
||||
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||
//
|
||||
// Captures mouse clicks and edits voxels accordingly.
|
||||
//
|
||||
// click = create a new voxel on this face, same color as old
|
||||
// Alt + click = delete this voxel
|
||||
// shift + click = recolor this voxel
|
||||
//
|
||||
// Click and drag to create more new voxels in the same direction
|
||||
//
|
||||
|
||||
function vLength(v) {
|
||||
return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
|
||||
}
|
||||
|
||||
var key_alt = false;
|
||||
var key_shift = false;
|
||||
var isAdding = false;
|
||||
|
||||
var lastVoxelPosition = { x: 0, y: 0, z: 0 };
|
||||
var lastVoxelColor = { red: 0, green: 0, blue: 0 };
|
||||
var lastVoxelScale = 0;
|
||||
var dragStart = { x: 0, y: 0 };
|
||||
|
||||
// Create a table of the different colors you can choose
|
||||
var colors = new Array();
|
||||
colors[0] = { red: 237, green: 175, blue: 0 };
|
||||
colors[1] = { red: 61, green: 211, blue: 72 };
|
||||
colors[2] = { red: 51, green: 204, blue: 204 };
|
||||
colors[3] = { red: 63, green: 169, blue: 245 };
|
||||
colors[4] = { red: 193, green: 99, blue: 122 };
|
||||
colors[5] = { red: 255, green: 54, blue: 69 };
|
||||
colors[6] = { red: 124, green: 36, blue: 36 };
|
||||
colors[7] = { red: 63, green: 35, blue: 19 };
|
||||
var numColors = 6;
|
||||
var whichColor = 0;
|
||||
|
||||
// Create sounds for adding, deleting, recoloring voxels
|
||||
var addSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Electronic/ElectronicBurst1.raw");
|
||||
var deleteSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Bubbles/bubbles1.raw");
|
||||
var changeColorSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Electronic/ElectronicBurst6.raw");
|
||||
var audioOptions = new AudioInjectionOptions();
|
||||
|
||||
function mousePressEvent(event) {
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
var intersection = Voxels.findRayIntersection(pickRay);
|
||||
audioOptions.volume = 1.0;
|
||||
audioOptions.position = { x: intersection.voxel.x, y: intersection.voxel.y, z: intersection.voxel.z };
|
||||
|
||||
if (intersection.intersects) {
|
||||
if (key_alt) {
|
||||
// Delete voxel
|
||||
Voxels.eraseVoxel(intersection.voxel.x, intersection.voxel.y, intersection.voxel.z, intersection.voxel.s);
|
||||
Audio.playSound(deleteSound, audioOptions);
|
||||
|
||||
} else if (key_shift) {
|
||||
// Recolor Voxel
|
||||
whichColor++;
|
||||
if (whichColor == numColors) whichColor = 0;
|
||||
Voxels.setVoxel(intersection.voxel.x,
|
||||
intersection.voxel.y,
|
||||
intersection.voxel.z,
|
||||
intersection.voxel.s,
|
||||
colors[whichColor].red, colors[whichColor].green, colors[whichColor].blue);
|
||||
Audio.playSound(changeColorSound, audioOptions);
|
||||
} else {
|
||||
// Add voxel on face
|
||||
var newVoxel = {
|
||||
x: intersection.voxel.x,
|
||||
y: intersection.voxel.y,
|
||||
z: intersection.voxel.z,
|
||||
s: intersection.voxel.s,
|
||||
red: intersection.voxel.red,
|
||||
green: intersection.voxel.green,
|
||||
blue: intersection.voxel.blue };
|
||||
|
||||
if (intersection.face == "MIN_X_FACE") {
|
||||
newVoxel.x -= newVoxel.s;
|
||||
} else if (intersection.face == "MAX_X_FACE") {
|
||||
newVoxel.x += newVoxel.s;
|
||||
} else if (intersection.face == "MIN_Y_FACE") {
|
||||
newVoxel.y -= newVoxel.s;
|
||||
} else if (intersection.face == "MAX_Y_FACE") {
|
||||
newVoxel.y += newVoxel.s;
|
||||
} else if (intersection.face == "MIN_Z_FACE") {
|
||||
newVoxel.z -= newVoxel.s;
|
||||
} else if (intersection.face == "MAX_Z_FACE") {
|
||||
newVoxel.z += newVoxel.s;
|
||||
}
|
||||
|
||||
Voxels.setVoxel(newVoxel.x, newVoxel.y, newVoxel.z, newVoxel.s, newVoxel.red, newVoxel.green, newVoxel.blue);
|
||||
lastVoxelPosition = { x: newVoxel.x, y: newVoxel.y, z: newVoxel.z };
|
||||
lastVoxelColor = { red: newVoxel.red, green: newVoxel.green, blue: newVoxel.blue };
|
||||
lastVoxelScale = newVoxel.s;
|
||||
|
||||
Audio.playSound(addSound, audioOptions);
|
||||
dragStart = { x: event.x, y: event.y };
|
||||
isAdding = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function keyPressEvent(event) {
|
||||
key_alt = event.isAlt;
|
||||
key_shift = event.isShifted;
|
||||
}
|
||||
function keyReleaseEvent(event) {
|
||||
key_alt = false;
|
||||
key_shift = false;
|
||||
}
|
||||
function mouseMoveEvent(event) {
|
||||
if (isAdding) {
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
var lastVoxelDistance = { x: pickRay.origin.x - lastVoxelPosition.x,
|
||||
y: pickRay.origin.y - lastVoxelPosition.y,
|
||||
z: pickRay.origin.z - lastVoxelPosition.z };
|
||||
var distance = vLength(lastVoxelDistance);
|
||||
var mouseSpot = { x: pickRay.direction.x * distance, y: pickRay.direction.y * distance, z: pickRay.direction.z * distance };
|
||||
mouseSpot.x += pickRay.origin.x;
|
||||
mouseSpot.y += pickRay.origin.y;
|
||||
mouseSpot.z += pickRay.origin.z;
|
||||
var dx = mouseSpot.x - lastVoxelPosition.x;
|
||||
var dy = mouseSpot.y - lastVoxelPosition.y;
|
||||
var dz = mouseSpot.z - lastVoxelPosition.z;
|
||||
if (dx > lastVoxelScale) {
|
||||
lastVoxelPosition.x += lastVoxelScale;
|
||||
Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z,
|
||||
lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue);
|
||||
} else if (dx < -lastVoxelScale) {
|
||||
lastVoxelPosition.x -= lastVoxelScale;
|
||||
Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z,
|
||||
lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue);
|
||||
} else if (dy > lastVoxelScale) {
|
||||
lastVoxelPosition.y += lastVoxelScale;
|
||||
Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z,
|
||||
lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue);
|
||||
} else if (dy < -lastVoxelScale) {
|
||||
lastVoxelPosition.y -= lastVoxelScale;
|
||||
Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z,
|
||||
lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue);
|
||||
} else if (dz > lastVoxelScale) {
|
||||
lastVoxelPosition.z += lastVoxelScale;
|
||||
Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z,
|
||||
lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue);
|
||||
} else if (dz < -lastVoxelScale) {
|
||||
lastVoxelPosition.z -= lastVoxelScale;
|
||||
Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z,
|
||||
lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function mouseReleaseEvent(event) {
|
||||
isAdding = false;
|
||||
}
|
||||
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
||||
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||
|
||||
function scriptEnding() {
|
||||
}
|
||||
Script.scriptEnding.connect(scriptEnding);
|
122
examples/lookAtExample.js
Normal file
122
examples/lookAtExample.js
Normal file
|
@ -0,0 +1,122 @@
|
|||
//
|
||||
// lookAtExample.js
|
||||
// hifi
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2/6/14.
|
||||
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||
//
|
||||
// This is an example script that demonstrates use of the Camera class's lookAt(), keepLookingAt(), and stopLookingAt()
|
||||
// features.
|
||||
//
|
||||
// To use the script, click on a voxel, and the camera will switch into independent mode and fix it's lookAt on the point
|
||||
// on the face of the voxel that you clicked. Click again and it will stop looking at that point. While in this fixed mode
|
||||
// you can use the arrow keys to change the position of the camera.
|
||||
//
|
||||
//
|
||||
|
||||
var lookingAtSomething = false;
|
||||
var oldMode = Camera.getMode();
|
||||
|
||||
function cancelLookAt() {
|
||||
if (lookingAtSomething) {
|
||||
lookingAtSomething = false;
|
||||
Camera.stopLooking();
|
||||
Camera.setMode(oldMode);
|
||||
releaseMovementKeys();
|
||||
}
|
||||
}
|
||||
|
||||
function captureMovementKeys() {
|
||||
Controller.captureKeyEvents({ text: "up" }); // Z-
|
||||
Controller.captureKeyEvents({ text: "down" }); // Z+
|
||||
Controller.captureKeyEvents({ text: "UP" }); // Y+
|
||||
Controller.captureKeyEvents({ text: "DOWN" }); // Y-
|
||||
Controller.captureKeyEvents({ text: "left" }); // X+
|
||||
Controller.captureKeyEvents({ text: "right" }); // X-
|
||||
}
|
||||
|
||||
function releaseMovementKeys() {
|
||||
Controller.releaseKeyEvents({ text: "up" }); // Z-
|
||||
Controller.releaseKeyEvents({ text: "down" }); // Z+
|
||||
Controller.releaseKeyEvents({ text: "UP" }); // Y+
|
||||
Controller.releaseKeyEvents({ text: "DOWN" }); // Y-
|
||||
Controller.releaseKeyEvents({ text: "left" }); // X+
|
||||
Controller.releaseKeyEvents({ text: "right" }); // X-
|
||||
}
|
||||
|
||||
var cameraPosition = Camera.getPosition();
|
||||
function moveCamera() {
|
||||
if (lookingAtSomething) {
|
||||
Camera.setPosition(cameraPosition);
|
||||
}
|
||||
}
|
||||
|
||||
Script.willSendVisualDataCallback.connect(moveCamera);
|
||||
|
||||
|
||||
function mousePressEvent(event) {
|
||||
if (lookingAtSomething) {
|
||||
cancelLookAt();
|
||||
} else {
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
var intersection = Voxels.findRayIntersection(pickRay);
|
||||
if (intersection.intersects) {
|
||||
|
||||
// remember the old mode we were in
|
||||
oldMode = Camera.getMode();
|
||||
|
||||
print("looking at intersection point: " + intersection.intersection.x + ", "
|
||||
+ intersection.intersection.y + ", " + intersection.intersection.z);
|
||||
|
||||
// switch to independent mode
|
||||
Camera.setMode("independent");
|
||||
|
||||
// tell the camera to fix it's look at on the point we clicked
|
||||
Camera.keepLookingAt(intersection.intersection);
|
||||
|
||||
// keep track of the fact that we're in this looking at mode
|
||||
lookingAtSomething = true;
|
||||
|
||||
captureMovementKeys();
|
||||
cameraPosition = Camera.getPosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
|
||||
function keyPressEvent(event) {
|
||||
if (lookingAtSomething) {
|
||||
|
||||
if (event.text == "ESC") {
|
||||
cancelLookAt();
|
||||
}
|
||||
|
||||
var MOVE_DELTA = 0.5;
|
||||
|
||||
if (event.text == "UP" && !event.isShifted) {
|
||||
cameraPosition.z -= MOVE_DELTA;
|
||||
}
|
||||
if (event.text == "DOWN" && !event.isShifted) {
|
||||
cameraPosition.z += MOVE_DELTA;
|
||||
}
|
||||
if (event.text == "LEFT" && !event.isShifted) {
|
||||
cameraPosition.x += MOVE_DELTA;
|
||||
}
|
||||
if (event.text == "RIGHT" && !event.isShifted) {
|
||||
cameraPosition.x -= MOVE_DELTA;
|
||||
}
|
||||
if (event.text == "UP" && event.isShifted) {
|
||||
cameraPosition.y += MOVE_DELTA;
|
||||
}
|
||||
if (event.text == "DOWN" && event.isShifted) {
|
||||
cameraPosition.y -= MOVE_DELTA;
|
||||
}
|
||||
}
|
||||
}
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
|
||||
function scriptEnding() {
|
||||
cancelLookAt();
|
||||
}
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
120
examples/multitouchExample.js
Normal file
120
examples/multitouchExample.js
Normal file
|
@ -0,0 +1,120 @@
|
|||
//
|
||||
// multitouchExample.js
|
||||
// hifi
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2/9/14.
|
||||
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||
//
|
||||
// This is an example script that demonstrates use of the Controller class's multi-touch features
|
||||
//
|
||||
// When this script is running:
|
||||
// * Four finger rotate gesture will rotate your avatar.
|
||||
// * Three finger swipe up/down will adjust the pitch of your avatars head.
|
||||
//
|
||||
|
||||
var lastX = 0;
|
||||
var lastY = 0;
|
||||
var lastAngle = 0;
|
||||
var yawFromMultiTouch = 0;
|
||||
var pitchFromMultiTouch = 0;
|
||||
var wantDebugging = false;
|
||||
var ROTATE_YAW_SCALE = 0.15;
|
||||
var MOUSE_PITCH_SCALE = -12.5;
|
||||
var FIXED_MOUSE_TIMESTEP = 0.016;
|
||||
|
||||
var ROTATE_TOUCH_POINTS = 4;
|
||||
var PITCH_TOUCH_POINTS = 3;
|
||||
|
||||
|
||||
function printTouchEvent(eventName, event) {
|
||||
print(eventName);
|
||||
print(" event.x,y=" + event.x + ", " + event.y);
|
||||
print(" event.isPressed=" + event.isPressed);
|
||||
print(" event.isMoved=" + event.isMoved);
|
||||
print(" event.isStationary=" + event.isStationary);
|
||||
print(" event.isReleased=" + event.isReleased);
|
||||
print(" event.isShifted=" + event.isShifted);
|
||||
print(" event.isControl=" + event.isControl);
|
||||
print(" event.isMeta=" + event.isMeta);
|
||||
print(" event.isAlt=" + event.isAlt);
|
||||
print(" event.touchPoints=" + event.touchPoints);
|
||||
for (var i = 0; i < event.points.length; i++) {
|
||||
print(" event.points[" + i + "].x.y:" + event.points[i].x + ", " + event.points[i].y);
|
||||
}
|
||||
print(" event.radius=" + event.radius);
|
||||
print(" event.isPinching=" + event.isPinching);
|
||||
print(" event.isPinchOpening=" + event.isPinchOpening);
|
||||
|
||||
print(" event.angle=" + event.angle);
|
||||
print(" event.deltaAngle=" + event.deltaAngle);
|
||||
for (var i = 0; i < event.points.length; i++) {
|
||||
print(" event.angles[" + i + "]:" + event.angles[i]);
|
||||
}
|
||||
print(" event.isRotating=" + event.isRotating);
|
||||
print(" event.rotating=" + event.rotating);
|
||||
}
|
||||
|
||||
function touchBeginEvent(event) {
|
||||
printTouchEvent("touchBeginEvent", event);
|
||||
lastX = event.x;
|
||||
lastY = event.y;
|
||||
}
|
||||
|
||||
function touchUpdateEvent(event) {
|
||||
printTouchEvent("touchUpdateEvent", event);
|
||||
|
||||
if (event.isRotating && event.touchPoints == ROTATE_TOUCH_POINTS) {
|
||||
// it's possible for the multitouch rotate gesture to generate angle changes which are faster than comfortable to
|
||||
// view, so we will scale this change in angle to make it more comfortable
|
||||
var scaledRotate = event.deltaAngle * ROTATE_YAW_SCALE;
|
||||
print(">>> event.deltaAngle=" + event.deltaAngle);
|
||||
print(">>> scaledRotate=" + scaledRotate);
|
||||
yawFromMultiTouch += scaledRotate;
|
||||
}
|
||||
|
||||
if (event.touchPoints == PITCH_TOUCH_POINTS) {
|
||||
pitchFromMultiTouch += ((event.y - lastY) * MOUSE_PITCH_SCALE * FIXED_MOUSE_TIMESTEP);
|
||||
}
|
||||
lastX = event.x;
|
||||
lastY = event.y;
|
||||
lastAngle = event.angle;
|
||||
}
|
||||
|
||||
function touchEndEvent(event) {
|
||||
printTouchEvent("touchEndEvent", event);
|
||||
}
|
||||
// Map touch events to our callbacks
|
||||
Controller.touchBeginEvent.connect(touchBeginEvent);
|
||||
Controller.touchUpdateEvent.connect(touchUpdateEvent);
|
||||
Controller.touchEndEvent.connect(touchEndEvent);
|
||||
|
||||
|
||||
|
||||
function update() {
|
||||
// rotate body yaw for yaw received from multitouch rotate
|
||||
var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3( { x: 0, y: yawFromMultiTouch, z: 0 } ));
|
||||
if (wantDebugging) {
|
||||
print("changing orientation"
|
||||
+ " [old]MyAvatar.orientation="+MyAvatar.orientation.x + "," + MyAvatar.orientation.y + ","
|
||||
+ MyAvatar.orientation.z + "," + MyAvatar.orientation.w
|
||||
+ " newOrientation="+newOrientation.x + "," + newOrientation.y + "," + newOrientation.z + "," + newOrientation.w);
|
||||
}
|
||||
MyAvatar.orientation = newOrientation;
|
||||
yawFromMultiTouch = 0;
|
||||
|
||||
// apply pitch from mouse
|
||||
var newPitch = MyAvatar.headPitch + pitchFromMultiTouch;
|
||||
if (wantDebugging) {
|
||||
print("changing pitch [old]MyAvatar.headPitch="+MyAvatar.headPitch+ " newPitch="+newPitch);
|
||||
}
|
||||
MyAvatar.headPitch = newPitch;
|
||||
pitchFromMultiTouch = 0;
|
||||
}
|
||||
Script.willSendVisualDataCallback.connect(update);
|
||||
|
||||
|
||||
function scriptEnding() {
|
||||
// handle any shutdown logic here
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(scriptEnding);
|
|
@ -4,6 +4,7 @@
|
|||
//
|
||||
// This sample script moves a voxel around like a bird and sometimes makes tweeting noises
|
||||
//
|
||||
|
||||
function vLength(v) {
|
||||
return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
|
||||
}
|
||||
|
@ -15,20 +16,24 @@ function randVector(a, b) {
|
|||
var rval = { x: a + Math.random() * (b - a), y: a + Math.random() * (b - a), z: a + Math.random() * (b - a) };
|
||||
return rval;
|
||||
}
|
||||
|
||||
function vMinus(a, b) {
|
||||
var rval = { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z };
|
||||
return rval;
|
||||
}
|
||||
|
||||
function vPlus(a, b) {
|
||||
var rval = { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z };
|
||||
return rval;
|
||||
}
|
||||
|
||||
function vCopy(a, b) {
|
||||
a.x = b.x;
|
||||
a.y = b.y;
|
||||
a.z = b.z;
|
||||
return;
|
||||
}
|
||||
|
||||
// Returns a vector which is fraction of the way between a and b
|
||||
function vInterpolate(a, b, fraction) {
|
||||
var rval = { x: a.x + (b.x - a.x) * fraction, y: a.y + (b.y - a.y) * fraction, z: a.z + (b.z - a.z) * fraction };
|
||||
|
@ -62,6 +67,7 @@ if (which < 0.2) {
|
|||
size = 0.15;
|
||||
}
|
||||
|
||||
|
||||
var startTimeInSeconds = new Date().getTime() / 1000;
|
||||
|
||||
var birdLifetime = 20; // lifetime of the bird in seconds!
|
||||
|
@ -72,15 +78,19 @@ var frame = 0;
|
|||
var moving = false;
|
||||
var tweeting = 0;
|
||||
var moved = false;
|
||||
var CHANCE_OF_MOVING = 0.05;
|
||||
|
||||
var CHANCE_OF_MOVING = 0.00;
|
||||
var CHANCE_OF_FLAPPING = 0.05;
|
||||
var CHANCE_OF_TWEETING = 0.05;
|
||||
var START_HEIGHT_ABOVE_ME = 1.5;
|
||||
var BIRD_GRAVITY = -0.1;
|
||||
var BIRD_FLAP = 1.0;
|
||||
var myPosition = MyAvatar.position;
|
||||
var properties = {
|
||||
lifetime: birdLifetime,
|
||||
position: { x: myPosition.x, y: myPosition.y + START_HEIGHT_ABOVE_ME, z: myPosition.z },
|
||||
velocity: { x: 0, y: 0, z: 0 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
velocity: { x: 0, y: Math.random() * BIRD_FLAP, z: 0 },
|
||||
gravity: { x: 0, y: BIRD_GRAVITY, z: 0 },
|
||||
radius : 0.1,
|
||||
color: { red: 0,
|
||||
green: 255,
|
||||
|
@ -94,6 +104,7 @@ function moveBird() {
|
|||
// check to see if we've been running long enough that our bird is dead
|
||||
var nowTimeInSeconds = new Date().getTime() / 1000;
|
||||
if ((nowTimeInSeconds - startTimeInSeconds) >= birdLifetime) {
|
||||
|
||||
print("our bird is dying, stop our script");
|
||||
Script.stop();
|
||||
return;
|
||||
|
@ -115,11 +126,22 @@ function moveBird() {
|
|||
} else {
|
||||
tweeting -= 1;
|
||||
}
|
||||
if (Math.random() < CHANCE_OF_FLAPPING) {
|
||||
// Add a little upward impulse to our bird
|
||||
// TODO: Get velocity
|
||||
//
|
||||
var newProperties = {
|
||||
velocity: { x:0.0, y: Math.random() * BIRD_FLAP, z: 0.0 }
|
||||
};
|
||||
Particles.editParticle(particleID, newProperties);
|
||||
print("flap!");
|
||||
}
|
||||
// Moving behavior
|
||||
if (moving == false) {
|
||||
if (Math.random() < CHANCE_OF_MOVING) {
|
||||
targetPosition = randVector(- range, range);
|
||||
targetPosition = randVector(-range, range);
|
||||
targetPosition = vPlus(targetPosition, myPosition);
|
||||
|
||||
if (targetPosition.x < 0) {
|
||||
targetPosition.x = 0;
|
||||
}
|
||||
|
@ -170,5 +192,6 @@ function moveBird() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// register the call back so it fires before each data send
|
||||
Script.willSendVisualDataCallback.connect(moveBird);
|
||||
|
|
37
examples/rayPickExample.js
Normal file
37
examples/rayPickExample.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// rayPickExample.js
|
||||
// hifi
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2/6/14.
|
||||
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||
//
|
||||
// This is an example script that demonstrates use of the Camera class
|
||||
//
|
||||
//
|
||||
|
||||
function mouseMoveEvent(event) {
|
||||
print("mouseMoveEvent event.x,y=" + event.x + ", " + event.y);
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
print("called Camera.computePickRay()");
|
||||
print("computePickRay origin=" + pickRay.origin.x + ", " + pickRay.origin.y + ", " + pickRay.origin.z);
|
||||
print("computePickRay direction=" + pickRay.direction.x + ", " + pickRay.direction.y + ", " + pickRay.direction.z);
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
var intersection = Voxels.findRayIntersection(pickRay);
|
||||
if (intersection.intersects) {
|
||||
print("intersection voxel.red/green/blue=" + intersection.voxel.red + ", "
|
||||
+ intersection.voxel.green + ", " + intersection.voxel.blue);
|
||||
print("intersection voxel.x/y/z/s=" + intersection.voxel.x + ", "
|
||||
+ intersection.voxel.y + ", " + intersection.voxel.z+ ": " + intersection.voxel.s);
|
||||
print("intersection face=" + intersection.face);
|
||||
print("intersection distance=" + intersection.distance);
|
||||
print("intersection intersection.x/y/z=" + intersection.intersection.x + ", "
|
||||
+ intersection.intersection.y + ", " + intersection.intersection.z);
|
||||
}
|
||||
}
|
||||
|
||||
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||
|
||||
function scriptEnding() {
|
||||
}
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
|
@ -135,7 +135,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
_isTouchPressed(false),
|
||||
_mousePressed(false),
|
||||
_isHoverVoxel(false),
|
||||
_isHoverVoxelSounding(false),
|
||||
_mouseVoxelScale(1.0f / 1024.0f),
|
||||
_mouseVoxelScaleInitialized(false),
|
||||
_justEditedVoxel(false),
|
||||
|
@ -448,7 +447,7 @@ void Application::paintGL() {
|
|||
_myCamera.setTargetRotation(_myAvatar->getHead().getOrientation());
|
||||
|
||||
} else if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
|
||||
_myCamera.setTightness(0.0f); // In first person, camera follows head exactly without delay
|
||||
_myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay
|
||||
_myCamera.setTargetPosition(_myAvatar->getHead().calculateAverageEyePosition());
|
||||
_myCamera.setTargetRotation(_myAvatar->getHead().getCameraOrientation());
|
||||
|
||||
|
@ -1199,7 +1198,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
|
|||
return;
|
||||
}
|
||||
if (_isHoverVoxel) {
|
||||
_myAvatar->orbit(getMouseVoxelWorldCoordinates(_hoverVoxel), deltaX, deltaY);
|
||||
//_myAvatar->orbit(getMouseVoxelWorldCoordinates(_hoverVoxel), deltaX, deltaY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1219,11 +1218,6 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
|
|||
}
|
||||
}
|
||||
|
||||
const bool MAKE_SOUND_ON_VOXEL_HOVER = false;
|
||||
const bool MAKE_SOUND_ON_VOXEL_CLICK = true;
|
||||
const float HOVER_VOXEL_FREQUENCY = 7040.f;
|
||||
const float HOVER_VOXEL_DECAY = 0.999f;
|
||||
|
||||
void Application::mousePressEvent(QMouseEvent* event) {
|
||||
_controllerScriptingInterface.emitMousePressEvent(event); // send events to any registered scripts
|
||||
|
||||
|
@ -1263,37 +1257,6 @@ void Application::mousePressEvent(QMouseEvent* event) {
|
|||
pasteVoxels();
|
||||
}
|
||||
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::VoxelDeleteMode) &&
|
||||
MAKE_SOUND_ON_VOXEL_CLICK && _isHoverVoxel && !_isHoverVoxelSounding) {
|
||||
_hoverVoxelOriginalColor[0] = _hoverVoxel.red;
|
||||
_hoverVoxelOriginalColor[1] = _hoverVoxel.green;
|
||||
_hoverVoxelOriginalColor[2] = _hoverVoxel.blue;
|
||||
_hoverVoxelOriginalColor[3] = 1;
|
||||
const float RED_CLICK_FREQUENCY = 1000.f;
|
||||
const float GREEN_CLICK_FREQUENCY = 1250.f;
|
||||
const float BLUE_CLICK_FREQUENCY = 1330.f;
|
||||
const float MIDDLE_A_FREQUENCY = 440.f;
|
||||
float frequency = MIDDLE_A_FREQUENCY +
|
||||
(_hoverVoxel.red / 255.f * RED_CLICK_FREQUENCY +
|
||||
_hoverVoxel.green / 255.f * GREEN_CLICK_FREQUENCY +
|
||||
_hoverVoxel.blue / 255.f * BLUE_CLICK_FREQUENCY) / 3.f;
|
||||
|
||||
_audio.startCollisionSound(1.0, frequency, 0.0, HOVER_VOXEL_DECAY, false);
|
||||
_isHoverVoxelSounding = true;
|
||||
|
||||
const float PERCENTAGE_TO_MOVE_TOWARD = 0.90f;
|
||||
glm::vec3 newTarget = getMouseVoxelWorldCoordinates(_hoverVoxel);
|
||||
glm::vec3 myPosition = _myAvatar->getPosition();
|
||||
|
||||
// If there is not an action tool set (add, delete, color), move to this voxel
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::ClickToFly) &&
|
||||
!(Menu::getInstance()->isOptionChecked(MenuOption::VoxelAddMode) ||
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::VoxelDeleteMode) ||
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::VoxelColorMode))) {
|
||||
_myAvatar->setMoveTarget(myPosition + (newTarget - myPosition) * PERCENTAGE_TO_MOVE_TOWARD);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (event->button() == Qt::RightButton && Menu::getInstance()->isVoxelModeActionChecked()) {
|
||||
deleteVoxelUnderCursor();
|
||||
}
|
||||
|
@ -1324,7 +1287,9 @@ void Application::mouseReleaseEvent(QMouseEvent* event) {
|
|||
}
|
||||
|
||||
void Application::touchUpdateEvent(QTouchEvent* event) {
|
||||
_controllerScriptingInterface.emitTouchUpdateEvent(event); // send events to any registered scripts
|
||||
TouchEvent thisEvent(*event, _lastTouchEvent);
|
||||
_controllerScriptingInterface.emitTouchUpdateEvent(thisEvent); // send events to any registered scripts
|
||||
_lastTouchEvent = thisEvent;
|
||||
|
||||
// if one of our scripts have asked to capture this event, then stop processing it
|
||||
if (_controllerScriptingInterface.isTouchCaptured()) {
|
||||
|
@ -1355,8 +1320,10 @@ void Application::touchUpdateEvent(QTouchEvent* event) {
|
|||
}
|
||||
|
||||
void Application::touchBeginEvent(QTouchEvent* event) {
|
||||
_controllerScriptingInterface.emitTouchBeginEvent(event); // send events to any registered scripts
|
||||
TouchEvent thisEvent(*event); // on touch begin, we don't compare to last event
|
||||
_controllerScriptingInterface.emitTouchBeginEvent(thisEvent); // send events to any registered scripts
|
||||
|
||||
_lastTouchEvent = thisEvent; // and we reset our last event to this event before we call our update
|
||||
touchUpdateEvent(event);
|
||||
|
||||
// if one of our scripts have asked to capture this event, then stop processing it
|
||||
|
@ -1371,7 +1338,9 @@ void Application::touchBeginEvent(QTouchEvent* event) {
|
|||
}
|
||||
|
||||
void Application::touchEndEvent(QTouchEvent* event) {
|
||||
_controllerScriptingInterface.emitTouchEndEvent(event); // send events to any registered scripts
|
||||
TouchEvent thisEvent(*event, _lastTouchEvent);
|
||||
_controllerScriptingInterface.emitTouchEndEvent(thisEvent); // send events to any registered scripts
|
||||
_lastTouchEvent = thisEvent;
|
||||
|
||||
// if one of our scripts have asked to capture this event, then stop processing it
|
||||
if (_controllerScriptingInterface.isTouchCaptured()) {
|
||||
|
@ -2039,45 +2008,9 @@ void Application::updateHoverVoxels(float deltaTime, float& distance, BoxFace& f
|
|||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels()");
|
||||
|
||||
// If we have clicked on a voxel, update it's color
|
||||
if (_isHoverVoxelSounding) {
|
||||
VoxelTreeElement* hoveredNode = _voxels.getVoxelAt(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s);
|
||||
if (hoveredNode) {
|
||||
float bright = _audio.getCollisionSoundMagnitude();
|
||||
nodeColor clickColor = { 255 * bright + _hoverVoxelOriginalColor[0] * (1.f - bright),
|
||||
_hoverVoxelOriginalColor[1] * (1.f - bright),
|
||||
_hoverVoxelOriginalColor[2] * (1.f - bright), 1 };
|
||||
hoveredNode->setColor(clickColor);
|
||||
if (bright < 0.01f) {
|
||||
hoveredNode->setColor(_hoverVoxelOriginalColor);
|
||||
_isHoverVoxelSounding = false;
|
||||
}
|
||||
} else {
|
||||
// Voxel is not found, clear all
|
||||
_isHoverVoxelSounding = false;
|
||||
_isHoverVoxel = false;
|
||||
}
|
||||
} else {
|
||||
// Check for a new hover voxel
|
||||
glm::vec4 oldVoxel(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s);
|
||||
// only do this work if MAKE_SOUND_ON_VOXEL_HOVER or MAKE_SOUND_ON_VOXEL_CLICK is enabled,
|
||||
// and make sure the tree is not already busy... because otherwise you'll have to wait.
|
||||
if (!_mousePressed) {
|
||||
{
|
||||
PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels() _voxels.findRayIntersection()");
|
||||
_isHoverVoxel = _voxels.findRayIntersection(_mouseRayOrigin, _mouseRayDirection, _hoverVoxel, distance, face);
|
||||
}
|
||||
if (MAKE_SOUND_ON_VOXEL_HOVER && _isHoverVoxel &&
|
||||
glm::vec4(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s) != oldVoxel) {
|
||||
|
||||
_hoverVoxelOriginalColor[0] = _hoverVoxel.red;
|
||||
_hoverVoxelOriginalColor[1] = _hoverVoxel.green;
|
||||
_hoverVoxelOriginalColor[2] = _hoverVoxel.blue;
|
||||
_hoverVoxelOriginalColor[3] = 1;
|
||||
_audio.startCollisionSound(1.0, HOVER_VOXEL_FREQUENCY * _hoverVoxel.s * TREE_SCALE, 0.0, HOVER_VOXEL_DECAY, false);
|
||||
_isHoverVoxelSounding = true;
|
||||
}
|
||||
}
|
||||
if (!_mousePressed) {
|
||||
PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels() _voxels.findRayIntersection()");
|
||||
_isHoverVoxel = _voxels.findRayIntersection(_mouseRayOrigin, _mouseRayDirection, _hoverVoxel, distance, face);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4101,6 +4034,7 @@ void Application::loadScript(const QString& fileNameString) {
|
|||
// setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so
|
||||
// we can use the same ones from the application.
|
||||
scriptEngine->getVoxelsScriptingInterface()->setPacketSender(&_voxelEditSender);
|
||||
scriptEngine->getVoxelsScriptingInterface()->setVoxelTree(_voxels.getTree());
|
||||
scriptEngine->getParticlesScriptingInterface()->setPacketSender(&_particleEditSender);
|
||||
scriptEngine->getParticlesScriptingInterface()->setParticleTree(_particles.getTree());
|
||||
|
||||
|
|
|
@ -419,8 +419,6 @@ private:
|
|||
|
||||
VoxelDetail _hoverVoxel; // Stuff about the voxel I am hovering or clicking
|
||||
bool _isHoverVoxel;
|
||||
bool _isHoverVoxelSounding;
|
||||
nodeColor _hoverVoxelOriginalColor;
|
||||
|
||||
VoxelDetail _mouseVoxel; // details of the voxel to be edited
|
||||
float _mouseVoxelScale; // the scale for adding/removing voxels
|
||||
|
@ -490,6 +488,8 @@ private:
|
|||
void displayUpdateDialog();
|
||||
bool shouldSkipVersion(QString latestVersion);
|
||||
void takeSnapshot();
|
||||
|
||||
TouchEvent _lastTouchEvent;
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__Application__) */
|
||||
|
|
|
@ -65,6 +65,10 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* p
|
|||
_measuredJitter(0),
|
||||
_jitterBufferSamples(initialJitterBufferSamples),
|
||||
_lastInputLoudness(0),
|
||||
_averageInputLoudness(0),
|
||||
_noiseGateOpen(false),
|
||||
_noiseGateEnabled(true),
|
||||
_noiseGateFramesToClose(0),
|
||||
_lastVelocity(0),
|
||||
_lastAcceleration(0),
|
||||
_totalPacketsReceived(0),
|
||||
|
@ -348,12 +352,40 @@ void Audio::handleAudioInput() {
|
|||
_inputFormat, _desiredInputFormat);
|
||||
|
||||
float loudness = 0;
|
||||
|
||||
float thisSample = 0;
|
||||
int samplesOverNoiseGate = 0;
|
||||
|
||||
const float NOISE_GATE_HEIGHT = 3.f;
|
||||
const int NOISE_GATE_WIDTH = 5;
|
||||
const int NOISE_GATE_CLOSE_FRAME_DELAY = 30;
|
||||
|
||||
for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) {
|
||||
loudness += fabsf(monoAudioSamples[i]);
|
||||
thisSample = fabsf(monoAudioSamples[i]);
|
||||
loudness += thisSample;
|
||||
// Noise Reduction: Count peaks above the average loudness
|
||||
if (thisSample > (_averageInputLoudness * NOISE_GATE_HEIGHT)) {
|
||||
samplesOverNoiseGate++;
|
||||
}
|
||||
}
|
||||
|
||||
_lastInputLoudness = loudness / NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
|
||||
const float LOUDNESS_AVERAGING_FRAMES = 1000.f; // This will be about 10 seconds
|
||||
_averageInputLoudness = (1.f - 1.f / LOUDNESS_AVERAGING_FRAMES) * _averageInputLoudness + (1.f / LOUDNESS_AVERAGING_FRAMES) * _lastInputLoudness;
|
||||
|
||||
if (_noiseGateEnabled) {
|
||||
if (samplesOverNoiseGate > NOISE_GATE_WIDTH) {
|
||||
_noiseGateOpen = true;
|
||||
_noiseGateFramesToClose = NOISE_GATE_CLOSE_FRAME_DELAY;
|
||||
} else {
|
||||
if (--_noiseGateFramesToClose == 0) {
|
||||
_noiseGateOpen = false;
|
||||
}
|
||||
}
|
||||
if (!_noiseGateOpen) {
|
||||
for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) {
|
||||
monoAudioSamples[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add input data just written to the scope
|
||||
QMetaObject::invokeMethod(_scope, "addSamples", Qt::QueuedConnection,
|
||||
|
@ -524,6 +556,10 @@ void Audio::toggleMute() {
|
|||
muteToggled();
|
||||
}
|
||||
|
||||
void Audio::toggleAudioNoiseReduction() {
|
||||
_noiseGateEnabled = !_noiseGateEnabled;
|
||||
}
|
||||
|
||||
void Audio::render(int screenWidth, int screenHeight) {
|
||||
if (_audioInput && _audioOutput) {
|
||||
glLineWidth(2.0);
|
||||
|
|
|
@ -45,7 +45,9 @@ public:
|
|||
|
||||
void render(int screenWidth, int screenHeight);
|
||||
|
||||
float getLastInputLoudness() const { return _lastInputLoudness; }
|
||||
float getLastInputLoudness() const { return glm::max(_lastInputLoudness - _averageInputLoudness, 0.f); }
|
||||
|
||||
void setNoiseGateEnabled(bool noiseGateEnabled) { _noiseGateEnabled = noiseGateEnabled; }
|
||||
|
||||
void setLastAcceleration(const glm::vec3 lastAcceleration) { _lastAcceleration = lastAcceleration; }
|
||||
void setLastVelocity(const glm::vec3 lastVelocity) { _lastVelocity = lastVelocity; }
|
||||
|
@ -73,6 +75,7 @@ public slots:
|
|||
void handleAudioInput();
|
||||
void reset();
|
||||
void toggleMute();
|
||||
void toggleAudioNoiseReduction();
|
||||
|
||||
virtual void handleAudioByteArray(const QByteArray& audioByteArray);
|
||||
|
||||
|
@ -106,6 +109,10 @@ private:
|
|||
float _measuredJitter;
|
||||
int16_t _jitterBufferSamples;
|
||||
float _lastInputLoudness;
|
||||
float _averageInputLoudness;
|
||||
bool _noiseGateOpen;
|
||||
bool _noiseGateEnabled;
|
||||
int _noiseGateFramesToClose;
|
||||
glm::vec3 _lastVelocity;
|
||||
glm::vec3 _lastAcceleration;
|
||||
int _totalPacketsReceived;
|
||||
|
|
|
@ -58,7 +58,9 @@ Camera::Camera() :
|
|||
_modeShift(1.0f),
|
||||
_linearModeShift(0.0f),
|
||||
_modeShiftRate(1.0f),
|
||||
_scale(1.0f)
|
||||
_scale(1.0f),
|
||||
_lookingAt(0.0f, 0.0f, 0.0f),
|
||||
_isKeepLookingAt(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -94,8 +96,12 @@ void Camera::updateFollowMode(float deltaTime) {
|
|||
t = 1.0;
|
||||
}
|
||||
|
||||
// Update position and rotation, setting directly if tightness is 0.0
|
||||
// handle keepLookingAt
|
||||
if (_isKeepLookingAt) {
|
||||
lookAt(_lookingAt);
|
||||
}
|
||||
|
||||
// Update position and rotation, setting directly if tightness is 0.0
|
||||
if (_needsToInitialize || (_tightness == 0.0f)) {
|
||||
_rotation = _targetRotation;
|
||||
_idealPosition = _targetPosition + _scale * (_rotation * glm::vec3(0.0f, _upShift, _distance));
|
||||
|
@ -155,6 +161,15 @@ void Camera::setMode(CameraMode m) {
|
|||
}
|
||||
}
|
||||
|
||||
void Camera::setTargetPosition(const glm::vec3& t) {
|
||||
_targetPosition = t;
|
||||
|
||||
// handle keepLookingAt
|
||||
if (_isKeepLookingAt) {
|
||||
lookAt(_lookingAt);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Camera::setTargetRotation( const glm::quat& targetRotation ) {
|
||||
_targetRotation = targetRotation;
|
||||
|
@ -222,6 +237,19 @@ void Camera::setFrustumWasReshaped() {
|
|||
_frustumNeedsReshape = false;
|
||||
}
|
||||
|
||||
void Camera::lookAt(const glm::vec3& lookAt) {
|
||||
glm::vec3 up = IDENTITY_UP;
|
||||
glm::mat4 lookAtMatrix = glm::lookAt(_targetPosition, lookAt, up);
|
||||
glm::quat rotation = glm::quat_cast(lookAtMatrix);
|
||||
rotation.w = -rotation.w; // Rosedale approved
|
||||
setTargetRotation(rotation);
|
||||
}
|
||||
|
||||
void Camera::keepLookingAt(const glm::vec3& point) {
|
||||
lookAt(point);
|
||||
_isKeepLookingAt = true;
|
||||
_lookingAt = point;
|
||||
}
|
||||
|
||||
CameraScriptableObject::CameraScriptableObject(Camera* camera, ViewFrustum* viewFrustum) :
|
||||
_camera(camera), _viewFrustum(viewFrustum)
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
|
@ -37,7 +38,7 @@ public:
|
|||
void setUpShift(float u) { _upShift = u; }
|
||||
void setDistance(float d) { _distance = d; }
|
||||
void setPosition(const glm::vec3& p) { _position = p; }
|
||||
void setTargetPosition(const glm::vec3& t) { _targetPosition = t; }
|
||||
void setTargetPosition(const glm::vec3& t);
|
||||
void setTightness(float t) { _tightness = t; }
|
||||
void setTargetRotation(const glm::quat& rotation);
|
||||
|
||||
|
@ -68,6 +69,17 @@ public:
|
|||
|
||||
bool getFrustumNeedsReshape() const; // call to find out if the view frustum needs to be reshaped
|
||||
void setFrustumWasReshaped(); // call this after reshaping the view frustum.
|
||||
|
||||
// These only work on independent cameras
|
||||
/// one time change to what the camera is looking at
|
||||
void lookAt(const glm::vec3& value);
|
||||
|
||||
/// fix what the camera is looking at, and keep the camera looking at this even if position changes
|
||||
void keepLookingAt(const glm::vec3& value);
|
||||
|
||||
/// stops the keep looking at feature, doesn't change what's being looked at, but will stop camera from
|
||||
/// continuing to update it's orientation to keep looking at the item
|
||||
void stopLooking() { _isKeepLookingAt = false; }
|
||||
|
||||
private:
|
||||
|
||||
|
@ -99,6 +111,9 @@ private:
|
|||
float _linearModeShift;
|
||||
float _modeShiftRate;
|
||||
float _scale;
|
||||
|
||||
glm::vec3 _lookingAt;
|
||||
bool _isKeepLookingAt;
|
||||
|
||||
void updateFollowMode(float deltaTime);
|
||||
};
|
||||
|
@ -119,6 +134,17 @@ public slots:
|
|||
void setOrientation(const glm::quat& value) { _camera->setTargetRotation(value); }
|
||||
glm::quat getOrientation() const { return _camera->getRotation(); }
|
||||
|
||||
// These only work on independent cameras
|
||||
/// one time change to what the camera is looking at
|
||||
void lookAt(const glm::vec3& value) { _camera->lookAt(value);}
|
||||
|
||||
/// fix what the camera is looking at, and keep the camera looking at this even if position changes
|
||||
void keepLookingAt(const glm::vec3& value) { _camera->keepLookingAt(value);}
|
||||
|
||||
/// stops the keep looking at feature, doesn't change what's being looked at, but will stop camera from
|
||||
/// continuing to update it's orientation to keep looking at the item
|
||||
void stopLooking() { _camera->stopLooking();}
|
||||
|
||||
PickRay computePickRay(float x, float y);
|
||||
|
||||
private:
|
||||
|
|
|
@ -28,9 +28,10 @@ public:
|
|||
void emitMousePressEvent(QMouseEvent* event) { emit mousePressEvent(MouseEvent(*event)); }
|
||||
void emitMouseReleaseEvent(QMouseEvent* event) { emit mouseReleaseEvent(MouseEvent(*event)); }
|
||||
|
||||
void emitTouchBeginEvent(QTouchEvent* event) { emit touchBeginEvent(*event); }
|
||||
void emitTouchEndEvent(QTouchEvent* event) { emit touchEndEvent(*event); }
|
||||
void emitTouchUpdateEvent(QTouchEvent* event) { emit touchUpdateEvent(*event); }
|
||||
void emitTouchBeginEvent(const TouchEvent& event) { emit touchBeginEvent(event); }
|
||||
void emitTouchEndEvent(const TouchEvent& event) { emit touchEndEvent(event); }
|
||||
void emitTouchUpdateEvent(const TouchEvent& event) { emit touchUpdateEvent(event); }
|
||||
|
||||
void emitWheelEvent(QWheelEvent* event) { emit wheelEvent(*event); }
|
||||
|
||||
bool isKeyCaptured(QKeyEvent* event) const;
|
||||
|
|
|
@ -457,6 +457,11 @@ Menu::Menu() :
|
|||
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::CoverageMapV2, Qt::SHIFT | Qt::CTRL | Qt::Key_P);
|
||||
|
||||
QMenu* audioDebugMenu = developerMenu->addMenu("Audio Debugging Tools");
|
||||
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioNoiseReduction,
|
||||
0,
|
||||
true,
|
||||
appInstance->getAudio(),
|
||||
SLOT(toggleAudioNoiseReduction()));
|
||||
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoServerAudio);
|
||||
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoLocalAudio);
|
||||
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::MuteAudio,
|
||||
|
|
|
@ -187,6 +187,7 @@ namespace MenuOption {
|
|||
const QString Enable3DTVMode = "Enable 3DTV Mode";
|
||||
const QString EnableOcclusionCulling = "Enable Occlusion Culling";
|
||||
const QString EnableVoxelPacketCompression = "Enable Voxel Packet Compression";
|
||||
const QString AudioNoiseReduction = "Audio Noise Reduction";
|
||||
const QString EchoServerAudio = "Echo Server Audio";
|
||||
const QString EchoLocalAudio = "Echo Local Audio";
|
||||
const QString MuteAudio = "Mute Microphone";
|
||||
|
|
|
@ -82,7 +82,6 @@ public:
|
|||
//getters
|
||||
bool isInitialized() const { return _initialized; }
|
||||
SkeletonModel& getSkeletonModel() { return _skeletonModel; }
|
||||
float getHeadYawRate() const { return _head.yawRate; }
|
||||
glm::vec3 getChestPosition() const;
|
||||
float getScale() const { return _scale; }
|
||||
const glm::vec3& getVelocity() const { return _velocity; }
|
||||
|
|
|
@ -59,15 +59,15 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX
|
|||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) *
|
||||
joint.preTransform * glm::mat4_cast(joint.preRotation)));
|
||||
state.rotation = glm::angleAxis(-_owningHead->getRoll(), glm::normalize(inverse * axes[2])) *
|
||||
glm::angleAxis(_owningHead->getYaw(), glm::normalize(inverse * axes[1])) *
|
||||
glm::angleAxis(-_owningHead->getPitch(), glm::normalize(inverse * axes[0])) * joint.rotation;
|
||||
glm::angleAxis(_owningHead->getTweakedYaw(), glm::normalize(inverse * axes[1])) *
|
||||
glm::angleAxis(-_owningHead->getTweakedPitch(), glm::normalize(inverse * axes[0])) * joint.rotation;
|
||||
}
|
||||
|
||||
void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) {
|
||||
// likewise with the eye joints
|
||||
glm::mat4 inverse = glm::inverse(parentState.transform * glm::translate(state.translation) *
|
||||
joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation));
|
||||
glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getOrientation() * IDENTITY_FRONT, 0.0f));
|
||||
glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getTweakedOrientation() * IDENTITY_FRONT, 0.0f));
|
||||
glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(_owningHead->getLookAtPosition() +
|
||||
_owningHead->getSaccade() - _translation, 1.0f));
|
||||
glm::quat between = rotationBetween(front, lookAt);
|
||||
|
|
|
@ -18,7 +18,6 @@ using namespace std;
|
|||
|
||||
Head::Head(Avatar* owningAvatar) :
|
||||
HeadData((AvatarData*)owningAvatar),
|
||||
yawRate(0.0f),
|
||||
_returnHeadToCenter(false),
|
||||
_position(0.0f, 0.0f, 0.0f),
|
||||
_rotation(0.0f, 0.0f, 0.0f),
|
||||
|
@ -37,6 +36,9 @@ Head::Head(Avatar* owningAvatar) :
|
|||
_leftEyeBlinkVelocity(0.0f),
|
||||
_rightEyeBlinkVelocity(0.0f),
|
||||
_timeWithoutTalking(0.0f),
|
||||
_tweakedPitch(0.f),
|
||||
_tweakedYaw(0.f),
|
||||
_tweakedRoll(0.f),
|
||||
_isCameraMoving(false),
|
||||
_faceModel(this)
|
||||
{
|
||||
|
@ -186,9 +188,14 @@ glm::quat Head::getOrientation() const {
|
|||
return glm::quat(glm::radians(_bodyRotation)) * glm::quat(glm::radians(glm::vec3(_pitch, _yaw, _roll)));
|
||||
}
|
||||
|
||||
glm::quat Head::getTweakedOrientation() const {
|
||||
return glm::quat(glm::radians(_bodyRotation)) * glm::quat(glm::radians(glm::vec3(getTweakedPitch(), getTweakedYaw(), getTweakedRoll() )));
|
||||
}
|
||||
|
||||
glm::quat Head::getCameraOrientation () const {
|
||||
Avatar* owningAvatar = static_cast<Avatar*>(_owningAvatar);
|
||||
return owningAvatar->getWorldAlignedOrientation();
|
||||
return owningAvatar->getWorldAlignedOrientation()
|
||||
* glm::quat(glm::radians(glm::vec3(_pitch, 0.f, 0.0f)));
|
||||
}
|
||||
|
||||
glm::quat Head::getEyeRotation(const glm::vec3& eyePosition) const {
|
||||
|
@ -200,6 +207,18 @@ glm::vec3 Head::getScalePivot() const {
|
|||
return _faceModel.isActive() ? _faceModel.getTranslation() : _position;
|
||||
}
|
||||
|
||||
float Head::getTweakedYaw() const {
|
||||
return glm::clamp(_yaw + _tweakedYaw, MIN_HEAD_YAW, MAX_HEAD_YAW);
|
||||
}
|
||||
|
||||
float Head::getTweakedPitch() const {
|
||||
return glm::clamp(_pitch + _tweakedPitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH);
|
||||
}
|
||||
|
||||
float Head::getTweakedRoll() const {
|
||||
return glm::clamp(_roll + _tweakedRoll, MIN_HEAD_ROLL, MAX_HEAD_ROLL);
|
||||
}
|
||||
|
||||
void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) {
|
||||
|
||||
Application::getInstance()->getGlowEffect()->begin();
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include <AvatarData.h>
|
||||
#include <HeadData.h>
|
||||
|
||||
#include <VoxelConstants.h>
|
||||
|
||||
|
@ -47,6 +47,7 @@ public:
|
|||
void setRenderLookatVectors(bool onOff) { _renderLookatVectors = onOff; }
|
||||
|
||||
glm::quat getOrientation() const;
|
||||
glm::quat getTweakedOrientation() const;
|
||||
glm::quat getCameraOrientation () const;
|
||||
const glm::vec3& getAngularVelocity() const { return _angularVelocity; }
|
||||
void setAngularVelocity(glm::vec3 angularVelocity) { _angularVelocity = angularVelocity; }
|
||||
|
@ -70,9 +71,15 @@ public:
|
|||
|
||||
/// Returns the point about which scaling occurs.
|
||||
glm::vec3 getScalePivot() const;
|
||||
|
||||
float yawRate;
|
||||
|
||||
void tweakPitch(float pitch) { _tweakedPitch = pitch; }
|
||||
void tweakYaw(float yaw) { _tweakedYaw = yaw; }
|
||||
void tweakRoll(float roll) { _tweakedRoll = roll; }
|
||||
|
||||
float getTweakedPitch() const;
|
||||
float getTweakedYaw() const;
|
||||
float getTweakedRoll() const;
|
||||
|
||||
private:
|
||||
// disallow copies of the Head, copy of owning Avatar is disallowed too
|
||||
Head(const Head&);
|
||||
|
@ -96,6 +103,12 @@ private:
|
|||
float _leftEyeBlinkVelocity;
|
||||
float _rightEyeBlinkVelocity;
|
||||
float _timeWithoutTalking;
|
||||
|
||||
// tweaked angles affect the rendered head, but not the camera
|
||||
float _tweakedPitch;
|
||||
float _tweakedYaw;
|
||||
float _tweakedRoll;
|
||||
|
||||
bool _isCameraMoving;
|
||||
FaceModel _faceModel;
|
||||
|
||||
|
|
|
@ -396,9 +396,9 @@ void MyAvatar::updateFromGyros(bool turnWithHead) {
|
|||
const float AVATAR_HEAD_PITCH_MAGNIFY = 1.0f;
|
||||
const float AVATAR_HEAD_YAW_MAGNIFY = 1.0f;
|
||||
const float AVATAR_HEAD_ROLL_MAGNIFY = 1.0f;
|
||||
_head.setPitch(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY);
|
||||
_head.setYaw(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY);
|
||||
_head.setRoll(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY);
|
||||
_head.tweakPitch(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY);
|
||||
_head.tweakYaw(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY);
|
||||
_head.tweakRoll(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY);
|
||||
|
||||
// Update torso lean distance based on accelerometer data
|
||||
const float TORSO_LENGTH = 0.5f;
|
||||
|
|
|
@ -107,7 +107,6 @@ QByteArray AvatarData::toByteArray() {
|
|||
destinationBuffer += sizeof(_headData->_lookAtPosition);
|
||||
|
||||
// Instantaneous audio loudness (used to drive facial animation)
|
||||
//destinationBuffer += packFloatToByte(destinationBuffer, std::min(MAX_AUDIO_LOUDNESS, _audioLoudness), MAX_AUDIO_LOUDNESS);
|
||||
memcpy(destinationBuffer, &_headData->_audioLoudness, sizeof(float));
|
||||
destinationBuffer += sizeof(float);
|
||||
|
||||
|
@ -215,7 +214,6 @@ int AvatarData::parseData(const QByteArray& packet) {
|
|||
sourceBuffer += sizeof(_headData->_lookAtPosition);
|
||||
|
||||
// Instantaneous audio loudness (used to drive facial animation)
|
||||
//sourceBuffer += unpackFloatFromByte(sourceBuffer, _audioLoudness, MAX_AUDIO_LOUDNESS);
|
||||
memcpy(&_headData->_audioLoudness, sourceBuffer, sizeof(float));
|
||||
sourceBuffer += sizeof(float);
|
||||
|
||||
|
|
|
@ -9,18 +9,29 @@
|
|||
// scripting engine
|
||||
|
||||
#include <QDebug>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
#include "EventTypes.h"
|
||||
|
||||
|
||||
KeyEvent::KeyEvent() {
|
||||
key = 0;
|
||||
text = QString("");
|
||||
isShifted = false;
|
||||
isMeta = false;
|
||||
isControl = false;
|
||||
isValid = false;
|
||||
void registerEventTypes(QScriptEngine* engine) {
|
||||
qScriptRegisterMetaType(engine, keyEventToScriptValue, keyEventFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, mouseEventToScriptValue, mouseEventFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, touchEventToScriptValue, touchEventFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, wheelEventToScriptValue, wheelEventFromScriptValue);
|
||||
}
|
||||
|
||||
KeyEvent::KeyEvent() :
|
||||
key(0),
|
||||
text(""),
|
||||
isShifted(false),
|
||||
isControl(false),
|
||||
isMeta(false),
|
||||
isAlt(false),
|
||||
isKeypad(false),
|
||||
isValid(false)
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
KeyEvent::KeyEvent(const QKeyEvent& event) {
|
||||
key = event.key();
|
||||
|
@ -73,43 +84,34 @@ KeyEvent::KeyEvent(const QKeyEvent& event) {
|
|||
text = "DELETE";
|
||||
} else if (key == Qt::Key_Backspace) {
|
||||
text = "BACKSPACE";
|
||||
} else if (key == Qt::Key_Shift) {
|
||||
text = "SHIFT";
|
||||
} else if (key == Qt::Key_Alt) {
|
||||
text = "ALT";
|
||||
} else if (key == Qt::Key_Control) {
|
||||
text = "CONTROL";
|
||||
} else if (key == Qt::Key_Meta) {
|
||||
text = "META";
|
||||
} else if (key == Qt::Key_PageDown) {
|
||||
text = "PAGE DOWN";
|
||||
} else if (key == Qt::Key_PageUp) {
|
||||
text = "PAGE UP";
|
||||
} else if (key == Qt::Key_Home) {
|
||||
text = "HOME";
|
||||
} else if (key == Qt::Key_End) {
|
||||
text = "END";
|
||||
} else if (key == Qt::Key_Help) {
|
||||
text = "HELP";
|
||||
}
|
||||
}
|
||||
|
||||
MouseEvent::MouseEvent(const QMouseEvent& event) {
|
||||
x = event.x();
|
||||
y = event.y();
|
||||
}
|
||||
|
||||
TouchEvent::TouchEvent(const QTouchEvent& event) {
|
||||
// convert the touch points into an average
|
||||
const QList<QTouchEvent::TouchPoint>& tPoints = event.touchPoints();
|
||||
float touchAvgX = 0.0f;
|
||||
float touchAvgY = 0.0f;
|
||||
int numTouches = tPoints.count();
|
||||
if (numTouches > 1) {
|
||||
for (int i = 0; i < numTouches; ++i) {
|
||||
touchAvgX += tPoints[i].pos().x();
|
||||
touchAvgY += tPoints[i].pos().y();
|
||||
}
|
||||
touchAvgX /= (float)(numTouches);
|
||||
touchAvgY /= (float)(numTouches);
|
||||
}
|
||||
x = touchAvgX;
|
||||
y = touchAvgY;
|
||||
}
|
||||
|
||||
WheelEvent::WheelEvent(const QWheelEvent& event) {
|
||||
x = event.x();
|
||||
y = event.y();
|
||||
}
|
||||
|
||||
|
||||
void registerEventTypes(QScriptEngine* engine) {
|
||||
qScriptRegisterMetaType(engine, keyEventToScriptValue, keyEventFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, mouseEventToScriptValue, mouseEventFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, touchEventToScriptValue, touchEventFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, wheelEventToScriptValue, wheelEventFromScriptValue);
|
||||
bool KeyEvent::operator==(const KeyEvent& other) const {
|
||||
return other.key == key
|
||||
&& other.isShifted == isShifted
|
||||
&& other.isControl == isControl
|
||||
&& other.isMeta == isMeta
|
||||
&& other.isAlt == isAlt
|
||||
&& other.isKeypad == isKeypad;
|
||||
}
|
||||
|
||||
QScriptValue keyEventToScriptValue(QScriptEngine* engine, const KeyEvent& event) {
|
||||
|
@ -188,6 +190,24 @@ void keyEventFromScriptValue(const QScriptValue& object, KeyEvent& event) {
|
|||
event.key = Qt::Key_Delete;
|
||||
} else if (event.text.toUpper() == "BACKSPACE") {
|
||||
event.key = Qt::Key_Backspace;
|
||||
} else if (event.text.toUpper() == "SHIFT") {
|
||||
event.key = Qt::Key_Shift;
|
||||
} else if (event.text.toUpper() == "ALT") {
|
||||
event.key = Qt::Key_Alt;
|
||||
} else if (event.text.toUpper() == "CONTROL") {
|
||||
event.key = Qt::Key_Control;
|
||||
} else if (event.text.toUpper() == "META") {
|
||||
event.key = Qt::Key_Meta;
|
||||
} else if (event.text.toUpper() == "PAGE DOWN") {
|
||||
event.key = Qt::Key_PageDown;
|
||||
} else if (event.text.toUpper() == "PAGE UP") {
|
||||
event.key = Qt::Key_PageUp;
|
||||
} else if (event.text.toUpper() == "HOME") {
|
||||
event.key = Qt::Key_Home;
|
||||
} else if (event.text.toUpper() == "END") {
|
||||
event.key = Qt::Key_End;
|
||||
} else if (event.text.toUpper() == "HELP") {
|
||||
event.key = Qt::Key_Help;
|
||||
} else {
|
||||
event.key = event.text.at(0).unicode();
|
||||
}
|
||||
|
@ -224,10 +244,67 @@ void keyEventFromScriptValue(const QScriptValue& object, KeyEvent& event) {
|
|||
}
|
||||
}
|
||||
|
||||
MouseEvent::MouseEvent() :
|
||||
x(0.0f),
|
||||
y(0.0f),
|
||||
isLeftButton(false),
|
||||
isRightButton(false),
|
||||
isMiddleButton(false),
|
||||
isShifted(false),
|
||||
isControl(false),
|
||||
isMeta(false),
|
||||
isAlt(false)
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
MouseEvent::MouseEvent(const QMouseEvent& event) {
|
||||
x = event.x();
|
||||
y = event.y();
|
||||
|
||||
// single button that caused the event
|
||||
switch (event.button()) {
|
||||
case Qt::LeftButton:
|
||||
button = "LEFT";
|
||||
isLeftButton = true;
|
||||
break;
|
||||
case Qt::RightButton:
|
||||
button = "RIGHT";
|
||||
isRightButton = true;
|
||||
break;
|
||||
case Qt::MiddleButton:
|
||||
button = "MIDDLE";
|
||||
isMiddleButton = true;
|
||||
break;
|
||||
default:
|
||||
button = "NONE";
|
||||
break;
|
||||
}
|
||||
// button pressed state
|
||||
isLeftButton = isLeftButton || (event.buttons().testFlag(Qt::LeftButton));
|
||||
isRightButton = isRightButton || (event.buttons().testFlag(Qt::RightButton));
|
||||
isMiddleButton = isMiddleButton || (event.buttons().testFlag(Qt::MiddleButton));
|
||||
|
||||
// keyboard modifiers
|
||||
isShifted = event.modifiers().testFlag(Qt::ShiftModifier);
|
||||
isMeta = event.modifiers().testFlag(Qt::MetaModifier);
|
||||
isControl = event.modifiers().testFlag(Qt::ControlModifier);
|
||||
isAlt = event.modifiers().testFlag(Qt::AltModifier);
|
||||
}
|
||||
|
||||
QScriptValue mouseEventToScriptValue(QScriptEngine* engine, const MouseEvent& event) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("x", event.x);
|
||||
obj.setProperty("y", event.y);
|
||||
obj.setProperty("button", event.button);
|
||||
obj.setProperty("isLeftButton", event.isLeftButton);
|
||||
obj.setProperty("isRightButton", event.isRightButton);
|
||||
obj.setProperty("isMiddleButton", event.isMiddleButton);
|
||||
obj.setProperty("isShifted", event.isShifted);
|
||||
obj.setProperty("isMeta", event.isMeta);
|
||||
obj.setProperty("isControl", event.isControl);
|
||||
obj.setProperty("isAlt", event.isAlt);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -235,10 +312,192 @@ void mouseEventFromScriptValue(const QScriptValue& object, MouseEvent& event) {
|
|||
// nothing for now...
|
||||
}
|
||||
|
||||
TouchEvent::TouchEvent() :
|
||||
x(0.0f),
|
||||
y(0.0f),
|
||||
isPressed(false),
|
||||
isMoved(false),
|
||||
isStationary(false),
|
||||
isReleased(false),
|
||||
isShifted(false),
|
||||
isControl(false),
|
||||
isMeta(false),
|
||||
isAlt(false),
|
||||
touchPoints(0),
|
||||
points(),
|
||||
radius(0.0f),
|
||||
isPinching(false),
|
||||
isPinchOpening(false),
|
||||
angles(),
|
||||
angle(0.0f),
|
||||
deltaAngle(0.0f),
|
||||
isRotating(false),
|
||||
rotating("none")
|
||||
{
|
||||
};
|
||||
|
||||
TouchEvent::TouchEvent(const QTouchEvent& event) :
|
||||
// these values are not set by initWithQTouchEvent() because they only apply to comparing to other events
|
||||
isPinching(false),
|
||||
isPinchOpening(false),
|
||||
deltaAngle(0.0f),
|
||||
isRotating(false),
|
||||
rotating("none")
|
||||
{
|
||||
initWithQTouchEvent(event);
|
||||
}
|
||||
|
||||
TouchEvent::TouchEvent(const QTouchEvent& event, const TouchEvent& other) {
|
||||
initWithQTouchEvent(event);
|
||||
calculateMetaAttributes(other);
|
||||
}
|
||||
|
||||
// returns the degrees between two points (note: 0 degrees is 'east')
|
||||
float angleBetweenPoints(const glm::vec2& a, const glm::vec2& b ) {
|
||||
glm::vec2 length = b - a;
|
||||
float radian = std::atan2(length.y, length.x);
|
||||
float angle = radian * 180.0f / PIE;
|
||||
if (angle < 0) {
|
||||
angle += 360.0f;
|
||||
};
|
||||
return angle;
|
||||
}
|
||||
|
||||
void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) {
|
||||
// convert the touch points into an average
|
||||
const QList<QTouchEvent::TouchPoint>& tPoints = event.touchPoints();
|
||||
float touchAvgX = 0.0f;
|
||||
float touchAvgY = 0.0f;
|
||||
touchPoints = tPoints.count();
|
||||
if (touchPoints > 1) {
|
||||
for (int i = 0; i < touchPoints; ++i) {
|
||||
touchAvgX += tPoints[i].pos().x();
|
||||
touchAvgY += tPoints[i].pos().y();
|
||||
|
||||
// add it to our points vector
|
||||
glm::vec2 thisPoint(tPoints[i].pos().x(), tPoints[i].pos().y());
|
||||
points << thisPoint;
|
||||
}
|
||||
touchAvgX /= (float)(touchPoints);
|
||||
touchAvgY /= (float)(touchPoints);
|
||||
} else {
|
||||
// I'm not sure this should ever happen, why would Qt send us a touch event for only one point?
|
||||
// maybe this happens in the case of a multi-touch where all but the last finger is released?
|
||||
touchAvgX = tPoints[0].pos().x();
|
||||
touchAvgY = tPoints[0].pos().y();
|
||||
}
|
||||
x = touchAvgX;
|
||||
y = touchAvgY;
|
||||
|
||||
// after calculating the center point (average touch point), determine the maximum radius
|
||||
// also calculate the rotation angle for each point
|
||||
float maxRadius = 0.0f;
|
||||
glm::vec2 center(x,y);
|
||||
for (int i = 0; i < touchPoints; ++i) {
|
||||
glm::vec2 touchPoint(tPoints[i].pos().x(), tPoints[i].pos().y());
|
||||
float thisRadius = glm::distance(center,touchPoint);
|
||||
if (thisRadius > maxRadius) {
|
||||
maxRadius = thisRadius;
|
||||
}
|
||||
|
||||
// calculate the angle for this point
|
||||
float thisAngle = angleBetweenPoints(center,touchPoint);
|
||||
angles << thisAngle;
|
||||
}
|
||||
radius = maxRadius;
|
||||
|
||||
// after calculating the angles for each touch point, determine the average angle
|
||||
float totalAngle = 0.0f;
|
||||
for (int i = 0; i < touchPoints; ++i) {
|
||||
totalAngle += angles[i];
|
||||
}
|
||||
angle = totalAngle/(float)touchPoints;
|
||||
|
||||
isPressed = event.touchPointStates().testFlag(Qt::TouchPointPressed);
|
||||
isMoved = event.touchPointStates().testFlag(Qt::TouchPointMoved);
|
||||
isStationary = event.touchPointStates().testFlag(Qt::TouchPointStationary);
|
||||
isReleased = event.touchPointStates().testFlag(Qt::TouchPointReleased);
|
||||
|
||||
// keyboard modifiers
|
||||
isShifted = event.modifiers().testFlag(Qt::ShiftModifier);
|
||||
isMeta = event.modifiers().testFlag(Qt::MetaModifier);
|
||||
isControl = event.modifiers().testFlag(Qt::ControlModifier);
|
||||
isAlt = event.modifiers().testFlag(Qt::AltModifier);
|
||||
}
|
||||
|
||||
void TouchEvent::calculateMetaAttributes(const TouchEvent& other) {
|
||||
// calculate comparative event attributes...
|
||||
if (other.radius > radius) {
|
||||
isPinching = true;
|
||||
isPinchOpening = false;
|
||||
} else if (other.radius < radius) {
|
||||
isPinchOpening = true;
|
||||
isPinching = false;
|
||||
} else {
|
||||
isPinching = other.isPinching;
|
||||
isPinchOpening = other.isPinchOpening;
|
||||
}
|
||||
|
||||
// determine if the points are rotating...
|
||||
// note: if the number of touch points change between events, then we don't consider ourselves to be rotating
|
||||
if (touchPoints == other.touchPoints) {
|
||||
deltaAngle = angle - other.angle;
|
||||
if (other.angle < angle) {
|
||||
isRotating = true;
|
||||
rotating = "clockwise";
|
||||
} else if (other.angle > angle) {
|
||||
isRotating = true;
|
||||
rotating = "counterClockwise";
|
||||
} else {
|
||||
isRotating = false;
|
||||
rotating = "none";
|
||||
}
|
||||
} else {
|
||||
deltaAngle = 0.0f;
|
||||
isRotating = false;
|
||||
rotating = "none";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QScriptValue touchEventToScriptValue(QScriptEngine* engine, const TouchEvent& event) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("x", event.x);
|
||||
obj.setProperty("y", event.y);
|
||||
obj.setProperty("isPressed", event.isPressed);
|
||||
obj.setProperty("isMoved", event.isMoved);
|
||||
obj.setProperty("isStationary", event.isStationary);
|
||||
obj.setProperty("isReleased", event.isReleased);
|
||||
obj.setProperty("isShifted", event.isShifted);
|
||||
obj.setProperty("isMeta", event.isMeta);
|
||||
obj.setProperty("isControl", event.isControl);
|
||||
obj.setProperty("isAlt", event.isAlt);
|
||||
obj.setProperty("touchPoints", event.touchPoints);
|
||||
|
||||
QScriptValue pointsObj = engine->newArray();
|
||||
int index = 0;
|
||||
foreach (glm::vec2 point, event.points) {
|
||||
QScriptValue thisPoint = vec2toScriptValue(engine, point);
|
||||
pointsObj.setProperty(index, thisPoint);
|
||||
index++;
|
||||
}
|
||||
obj.setProperty("points", pointsObj);
|
||||
obj.setProperty("radius", event.radius);
|
||||
obj.setProperty("isPinching", event.isPinching);
|
||||
obj.setProperty("isPinchOpening", event.isPinchOpening);
|
||||
|
||||
obj.setProperty("angle", event.angle);
|
||||
obj.setProperty("deltaAngle", event.deltaAngle);
|
||||
QScriptValue anglesObj = engine->newArray();
|
||||
index = 0;
|
||||
foreach (float angle, event.angles) {
|
||||
anglesObj.setProperty(index, angle);
|
||||
index++;
|
||||
}
|
||||
obj.setProperty("angles", anglesObj);
|
||||
|
||||
obj.setProperty("isRotating", event.isRotating);
|
||||
obj.setProperty("rotating", event.rotating);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -246,10 +505,58 @@ void touchEventFromScriptValue(const QScriptValue& object, TouchEvent& event) {
|
|||
// nothing for now...
|
||||
}
|
||||
|
||||
WheelEvent::WheelEvent() :
|
||||
x(0.0f),
|
||||
y(0.0f),
|
||||
delta(0.0f),
|
||||
orientation("UNKNOwN"),
|
||||
isLeftButton(false),
|
||||
isRightButton(false),
|
||||
isMiddleButton(false),
|
||||
isShifted(false),
|
||||
isControl(false),
|
||||
isMeta(false),
|
||||
isAlt(false)
|
||||
{
|
||||
};
|
||||
|
||||
WheelEvent::WheelEvent(const QWheelEvent& event) {
|
||||
x = event.x();
|
||||
y = event.y();
|
||||
|
||||
delta = event.delta();
|
||||
if (event.orientation() == Qt::Horizontal) {
|
||||
orientation = "HORIZONTAL";
|
||||
} else {
|
||||
orientation = "VERTICAL";
|
||||
}
|
||||
|
||||
// button pressed state
|
||||
isLeftButton = (event.buttons().testFlag(Qt::LeftButton));
|
||||
isRightButton = (event.buttons().testFlag(Qt::RightButton));
|
||||
isMiddleButton = (event.buttons().testFlag(Qt::MiddleButton));
|
||||
|
||||
// keyboard modifiers
|
||||
isShifted = event.modifiers().testFlag(Qt::ShiftModifier);
|
||||
isMeta = event.modifiers().testFlag(Qt::MetaModifier);
|
||||
isControl = event.modifiers().testFlag(Qt::ControlModifier);
|
||||
isAlt = event.modifiers().testFlag(Qt::AltModifier);
|
||||
}
|
||||
|
||||
|
||||
QScriptValue wheelEventToScriptValue(QScriptEngine* engine, const WheelEvent& event) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("x", event.x);
|
||||
obj.setProperty("y", event.y);
|
||||
obj.setProperty("delta", event.delta);
|
||||
obj.setProperty("orientation", event.orientation);
|
||||
obj.setProperty("isLeftButton", event.isLeftButton);
|
||||
obj.setProperty("isRightButton", event.isRightButton);
|
||||
obj.setProperty("isMiddleButton", event.isMiddleButton);
|
||||
obj.setProperty("isShifted", event.isShifted);
|
||||
obj.setProperty("isMeta", event.isMeta);
|
||||
obj.setProperty("isControl", event.isControl);
|
||||
obj.setProperty("isAlt", event.isAlt);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,13 +23,7 @@ class KeyEvent {
|
|||
public:
|
||||
KeyEvent();
|
||||
KeyEvent(const QKeyEvent& event);
|
||||
inline bool operator==(const KeyEvent& other) const {
|
||||
return other.key == key
|
||||
&& other.isShifted == isShifted
|
||||
&& other.isControl == isControl
|
||||
&& other.isMeta == isMeta
|
||||
&& other.isAlt == isAlt
|
||||
&& other.isKeypad == isKeypad; }
|
||||
bool operator==(const KeyEvent& other) const;
|
||||
int key;
|
||||
QString text;
|
||||
bool isShifted;
|
||||
|
@ -43,26 +37,67 @@ public:
|
|||
|
||||
class MouseEvent {
|
||||
public:
|
||||
MouseEvent() : x(0), y(0) { };
|
||||
MouseEvent();
|
||||
MouseEvent(const QMouseEvent& event);
|
||||
int x;
|
||||
int y;
|
||||
QString button;
|
||||
bool isLeftButton;
|
||||
bool isRightButton;
|
||||
bool isMiddleButton;
|
||||
bool isShifted;
|
||||
bool isControl;
|
||||
bool isMeta;
|
||||
bool isAlt;
|
||||
};
|
||||
|
||||
class TouchEvent {
|
||||
public:
|
||||
TouchEvent() : x(0), y(0) { };
|
||||
TouchEvent();
|
||||
TouchEvent(const QTouchEvent& event);
|
||||
TouchEvent(const QTouchEvent& event, const TouchEvent& other);
|
||||
|
||||
float x;
|
||||
float y;
|
||||
bool isPressed;
|
||||
bool isMoved;
|
||||
bool isStationary;
|
||||
bool isReleased;
|
||||
bool isShifted;
|
||||
bool isControl;
|
||||
bool isMeta;
|
||||
bool isAlt;
|
||||
int touchPoints;
|
||||
QVector<glm::vec2> points;
|
||||
float radius;
|
||||
bool isPinching;
|
||||
bool isPinchOpening;
|
||||
QVector<float> angles; // angle from center to each point
|
||||
float angle; // the average of the angles
|
||||
float deltaAngle; // the change in average angle from last event
|
||||
bool isRotating;
|
||||
QString rotating;
|
||||
|
||||
private:
|
||||
void initWithQTouchEvent(const QTouchEvent& event);
|
||||
void calculateMetaAttributes(const TouchEvent& other);
|
||||
};
|
||||
|
||||
class WheelEvent {
|
||||
public:
|
||||
WheelEvent() : x(0), y(0) { };
|
||||
WheelEvent();
|
||||
WheelEvent(const QWheelEvent& event);
|
||||
int x;
|
||||
int y;
|
||||
int delta;
|
||||
QString orientation;
|
||||
bool isLeftButton;
|
||||
bool isRightButton;
|
||||
bool isMiddleButton;
|
||||
bool isShifted;
|
||||
bool isControl;
|
||||
bool isMeta;
|
||||
bool isAlt;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(KeyEvent)
|
||||
|
|
|
@ -125,6 +125,7 @@ void ScriptEngine::init() {
|
|||
qScriptRegisterMetaType(&_engine, ParticlePropertiesToScriptValue, ParticlePropertiesFromScriptValue);
|
||||
qScriptRegisterMetaType(&_engine, ParticleIDtoScriptValue, ParticleIDfromScriptValue);
|
||||
qScriptRegisterSequenceMetaType<QVector<ParticleID> >(&_engine);
|
||||
qScriptRegisterSequenceMetaType<QVector<glm::vec2> >(&_engine);
|
||||
|
||||
QScriptValue soundConstructorValue = _engine.newFunction(soundConstructor);
|
||||
QScriptValue soundMetaObject = _engine.newQMetaObject(&Sound::staticMetaObject, soundConstructorValue);
|
||||
|
|
|
@ -81,7 +81,6 @@ QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay)
|
|||
QScriptValue direction = vec3toScriptValue(engine, pickRay.direction);
|
||||
obj.setProperty("direction", direction);
|
||||
return obj;
|
||||
|
||||
}
|
||||
|
||||
void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay) {
|
||||
|
|
|
@ -46,5 +46,4 @@ Q_DECLARE_METATYPE(PickRay)
|
|||
QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay);
|
||||
void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,11 +9,12 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cm
|
|||
set(TARGET_NAME voxels)
|
||||
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
find_package(Qt5Script REQUIRED)
|
||||
|
||||
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
||||
setup_hifi_library(${TARGET_NAME})
|
||||
|
||||
qt5_use_modules(${TARGET_NAME} Widgets)
|
||||
qt5_use_modules(${TARGET_NAME} Widgets Script)
|
||||
|
||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||
include_glm(${TARGET_NAME} ${ROOT_DIR})
|
||||
|
|
|
@ -5,10 +5,13 @@
|
|||
// Created by Brad Hefta-Gaub on 1/29/2014
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <RegisteredMetaTypes.h>
|
||||
#include "VoxelDetail.h"
|
||||
|
||||
void registerVoxelMetaTypes(QScriptEngine* engine) {
|
||||
qScriptRegisterMetaType(engine, voxelDetailToScriptValue, voxelDetailFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, rayToVoxelIntersectionResultToScriptValue, rayToVoxelIntersectionResultFromScriptValue);
|
||||
}
|
||||
|
||||
QScriptValue voxelDetailToScriptValue(QScriptEngine* engine, const VoxelDetail& voxelDetail) {
|
||||
|
@ -33,5 +36,78 @@ void voxelDetailFromScriptValue(const QScriptValue &object, VoxelDetail& voxelDe
|
|||
voxelDetail.blue = object.property("blue").toVariant().toInt();
|
||||
}
|
||||
|
||||
RayToVoxelIntersectionResult::RayToVoxelIntersectionResult() :
|
||||
intersects(false),
|
||||
voxel(),
|
||||
distance(0),
|
||||
face()
|
||||
{
|
||||
};
|
||||
|
||||
QScriptValue rayToVoxelIntersectionResultToScriptValue(QScriptEngine* engine, const RayToVoxelIntersectionResult& value) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("intersects", value.intersects);
|
||||
QScriptValue voxelValue = voxelDetailToScriptValue(engine, value.voxel);
|
||||
obj.setProperty("voxel", voxelValue);
|
||||
obj.setProperty("distance", value.distance);
|
||||
|
||||
QString faceName = "";
|
||||
// handle BoxFace
|
||||
switch (value.face) {
|
||||
case MIN_X_FACE:
|
||||
faceName = "MIN_X_FACE";
|
||||
break;
|
||||
case MAX_X_FACE:
|
||||
faceName = "MAX_X_FACE";
|
||||
break;
|
||||
case MIN_Y_FACE:
|
||||
faceName = "MIN_Y_FACE";
|
||||
break;
|
||||
case MAX_Y_FACE:
|
||||
faceName = "MAX_Y_FACE";
|
||||
break;
|
||||
case MIN_Z_FACE:
|
||||
faceName = "MIN_Z_FACE";
|
||||
break;
|
||||
case MAX_Z_FACE:
|
||||
faceName = "MAX_Z_FACE";
|
||||
break;
|
||||
}
|
||||
obj.setProperty("face", faceName);
|
||||
|
||||
QScriptValue intersection = vec3toScriptValue(engine, value.intersection);
|
||||
obj.setProperty("intersection", intersection);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void rayToVoxelIntersectionResultFromScriptValue(const QScriptValue& object, RayToVoxelIntersectionResult& value) {
|
||||
value.intersects = object.property("intersects").toVariant().toBool();
|
||||
QScriptValue voxelValue = object.property("voxel");
|
||||
if (voxelValue.isValid()) {
|
||||
voxelDetailFromScriptValue(voxelValue, value.voxel);
|
||||
}
|
||||
value.distance = object.property("distance").toVariant().toFloat();
|
||||
|
||||
QString faceName = object.property("face").toVariant().toString();
|
||||
if (faceName == "MIN_X_FACE") {
|
||||
value.face = MIN_X_FACE;
|
||||
} else if (faceName == "MAX_X_FACE") {
|
||||
value.face = MAX_X_FACE;
|
||||
} else if (faceName == "MIN_Y_FACE") {
|
||||
value.face = MIN_Y_FACE;
|
||||
} else if (faceName == "MAX_Y_FACE") {
|
||||
value.face = MAX_Y_FACE;
|
||||
} else if (faceName == "MIN_Z_FACE") {
|
||||
value.face = MIN_Z_FACE;
|
||||
} else {
|
||||
value.face = MAX_Z_FACE;
|
||||
};
|
||||
QScriptValue intersection = object.property("intersection");
|
||||
if (intersection.isValid()) {
|
||||
vec3FromScriptValue(intersection, value.intersection);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <QtScript/QScriptEngine>
|
||||
|
||||
#include <AABox.h>
|
||||
#include <SharedUtil.h>
|
||||
#include "VoxelConstants.h"
|
||||
|
||||
|
@ -32,5 +33,19 @@ void registerVoxelMetaTypes(QScriptEngine* engine);
|
|||
QScriptValue voxelDetailToScriptValue(QScriptEngine* engine, const VoxelDetail& color);
|
||||
void voxelDetailFromScriptValue(const QScriptValue &object, VoxelDetail& color);
|
||||
|
||||
class RayToVoxelIntersectionResult {
|
||||
public:
|
||||
RayToVoxelIntersectionResult();
|
||||
bool intersects;
|
||||
VoxelDetail voxel;
|
||||
float distance;
|
||||
BoxFace face;
|
||||
glm::vec3 intersection;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(RayToVoxelIntersectionResult)
|
||||
|
||||
QScriptValue rayToVoxelIntersectionResultToScriptValue(QScriptEngine* engine, const RayToVoxelIntersectionResult& results);
|
||||
void rayToVoxelIntersectionResultFromScriptValue(const QScriptValue& object, RayToVoxelIntersectionResult& results);
|
||||
|
||||
#endif /* defined(__hifi__VoxelDetail__) */
|
|
@ -41,3 +41,26 @@ void VoxelsScriptingInterface::eraseVoxel(float x, float y, float z, float scale
|
|||
getVoxelPacketSender()->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &deleteVoxelDetail);
|
||||
}
|
||||
|
||||
|
||||
RayToVoxelIntersectionResult VoxelsScriptingInterface::findRayIntersection(const PickRay& ray) {
|
||||
RayToVoxelIntersectionResult result;
|
||||
if (_tree) {
|
||||
if (_tree->tryLockForRead()) {
|
||||
OctreeElement* element;
|
||||
result.intersects = _tree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face);
|
||||
if (result.intersects) {
|
||||
VoxelTreeElement* voxel = (VoxelTreeElement*)element;
|
||||
result.voxel.x = voxel->getCorner().x;
|
||||
result.voxel.y = voxel->getCorner().y;
|
||||
result.voxel.z = voxel->getCorner().z;
|
||||
result.voxel.s = voxel->getScale();
|
||||
result.voxel.red = voxel->getColor()[0];
|
||||
result.voxel.green = voxel->getColor()[1];
|
||||
result.voxel.blue = voxel->getColor()[2];
|
||||
result.intersection = ray.origin + (ray.direction * result.distance);
|
||||
}
|
||||
_tree->unlock();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -12,18 +12,22 @@
|
|||
#include <QtCore/QObject>
|
||||
|
||||
#include <OctreeScriptingInterface.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
|
||||
#include "VoxelConstants.h"
|
||||
#include "VoxelEditPacketSender.h"
|
||||
#include "VoxelTree.h"
|
||||
|
||||
/// handles scripting of voxel commands from JS passed to assigned clients
|
||||
class VoxelsScriptingInterface : public OctreeScriptingInterface {
|
||||
Q_OBJECT
|
||||
public:
|
||||
public:
|
||||
VoxelsScriptingInterface() : _tree(NULL) {};
|
||||
VoxelEditPacketSender* getVoxelPacketSender() { return (VoxelEditPacketSender*)getPacketSender(); }
|
||||
|
||||
virtual NodeType_t getServerNodeType() const { return NodeType::VoxelServer; }
|
||||
virtual OctreeEditPacketSender* createPacketSender() { return new VoxelEditPacketSender(); }
|
||||
void setVoxelTree(VoxelTree* tree) { _tree = tree; }
|
||||
|
||||
public slots:
|
||||
/// queues the creation of a voxel which will be sent by calling process on the PacketSender
|
||||
|
@ -53,8 +57,12 @@ public slots:
|
|||
/// \param scale the scale of the voxel (in meter units)
|
||||
void eraseVoxel(float x, float y, float z, float scale);
|
||||
|
||||
/// If the scripting context has visible voxels, this will determine a ray intersection
|
||||
RayToVoxelIntersectionResult findRayIntersection(const PickRay& ray);
|
||||
|
||||
private:
|
||||
void queueVoxelAdd(PacketType addPacketType, VoxelDetail& addVoxelDetails);
|
||||
VoxelTree* _tree;
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__VoxelsScriptingInterface__) */
|
||||
|
|
|
@ -13,9 +13,11 @@ include(${MACRO_DIR}/IncludeGLM.cmake)
|
|||
include_glm(${TARGET_NAME} ${ROOT_DIR})
|
||||
|
||||
include(${MACRO_DIR}/SetupHifiProject.cmake)
|
||||
|
||||
setup_hifi_project(${TARGET_NAME} TRUE)
|
||||
|
||||
find_package(Qt5Script REQUIRED)
|
||||
qt5_use_modules(${TARGET_NAME} Script)
|
||||
|
||||
# link in the shared library
|
||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
||||
|
|
Loading…
Reference in a new issue