mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-10 01:36:26 +02:00
Merge branch master of upstream
This commit is contained in:
commit
2c3784c7d5
28 changed files with 1664 additions and 350 deletions
|
@ -312,6 +312,8 @@ void DomainServer::createScriptedAssignmentsFromArray(const QJsonArray &configAr
|
||||||
int numInstances = jsonObject[ASSIGNMENT_INSTANCES_KEY].toInt();
|
int numInstances = jsonObject[ASSIGNMENT_INSTANCES_KEY].toInt();
|
||||||
numInstances = (numInstances == 0 ? 1 : numInstances);
|
numInstances = (numInstances == 0 ? 1 : numInstances);
|
||||||
|
|
||||||
|
qDebug() << "Adding a static scripted assignment from" << assignmentURL;
|
||||||
|
|
||||||
for (int i = 0; i < numInstances; i++) {
|
for (int i = 0; i < numInstances; i++) {
|
||||||
// add a scripted assignment to the queue for this instance
|
// add a scripted assignment to the queue for this instance
|
||||||
Assignment* scriptAssignment = new Assignment(Assignment::CreateCommand,
|
Assignment* scriptAssignment = new Assignment(Assignment::CreateCommand,
|
||||||
|
@ -319,13 +321,8 @@ void DomainServer::createScriptedAssignmentsFromArray(const QJsonArray &configAr
|
||||||
assignmentPool);
|
assignmentPool);
|
||||||
scriptAssignment->setPayload(assignmentURL.toUtf8());
|
scriptAssignment->setPayload(assignmentURL.toUtf8());
|
||||||
|
|
||||||
qDebug() << "Adding scripted assignment to queue -" << *scriptAssignment;
|
|
||||||
qDebug() << "URL for script is" << assignmentURL;
|
|
||||||
|
|
||||||
// scripts passed on CL or via JSON are static - so they are added back to the queue if the node dies
|
// scripts passed on CL or via JSON are static - so they are added back to the queue if the node dies
|
||||||
SharedAssignmentPointer sharedScriptAssignment(scriptAssignment);
|
addStaticAssignmentToAssignmentHash(scriptAssignment);
|
||||||
_unfulfilledAssignments.enqueue(sharedScriptAssignment);
|
|
||||||
_allAssignments.insert(sharedScriptAssignment->getUUID(), sharedScriptAssignment);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -407,7 +404,7 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock
|
||||||
PendingAssignedNodeData* pendingAssigneeData = NULL;
|
PendingAssignedNodeData* pendingAssigneeData = NULL;
|
||||||
|
|
||||||
if (isAssignment) {
|
if (isAssignment) {
|
||||||
pendingAssigneeData = _pendingAssignedNodes.take(packetUUID);
|
pendingAssigneeData = _pendingAssignedNodes.value(packetUUID);
|
||||||
|
|
||||||
if (pendingAssigneeData) {
|
if (pendingAssigneeData) {
|
||||||
matchingQueuedAssignment = matchingQueuedAssignmentForCheckIn(pendingAssigneeData->getAssignmentUUID(), nodeType);
|
matchingQueuedAssignment = matchingQueuedAssignmentForCheckIn(pendingAssigneeData->getAssignmentUUID(), nodeType);
|
||||||
|
@ -416,12 +413,21 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock
|
||||||
qDebug() << "Assignment deployed with" << uuidStringWithoutCurlyBraces(packetUUID)
|
qDebug() << "Assignment deployed with" << uuidStringWithoutCurlyBraces(packetUUID)
|
||||||
<< "matches unfulfilled assignment"
|
<< "matches unfulfilled assignment"
|
||||||
<< uuidStringWithoutCurlyBraces(matchingQueuedAssignment->getUUID());
|
<< uuidStringWithoutCurlyBraces(matchingQueuedAssignment->getUUID());
|
||||||
|
|
||||||
|
// remove this unique assignment deployment from the hash of pending assigned nodes
|
||||||
|
// cleanup of the PendingAssignedNodeData happens below after the node has been added to the LimitedNodeList
|
||||||
|
_pendingAssignedNodes.remove(packetUUID);
|
||||||
|
} else {
|
||||||
|
// this is a node connecting to fulfill an assignment that doesn't exist
|
||||||
|
// don't reply back to them so they cycle back and re-request an assignment
|
||||||
|
qDebug() << "No match for assignment deployed with" << uuidStringWithoutCurlyBraces(packetUUID);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!matchingQueuedAssignment && !_oauthProviderURL.isEmpty() && _argumentVariantMap.contains(ALLOWED_ROLES_CONFIG_KEY)) {
|
if (!isAssignment && !_oauthProviderURL.isEmpty() && _argumentVariantMap.contains(ALLOWED_ROLES_CONFIG_KEY)) {
|
||||||
// this is an Agent, and we require authentication so we can compare the user's roles to our list of allowed ones
|
// this is an Agent, and we require authentication so we can compare the user's roles to our list of allowed ones
|
||||||
if (_sessionAuthenticationHash.contains(packetUUID)) {
|
if (_sessionAuthenticationHash.contains(packetUUID)) {
|
||||||
if (!_sessionAuthenticationHash.value(packetUUID)) {
|
if (!_sessionAuthenticationHash.value(packetUUID)) {
|
||||||
|
|
|
@ -31,12 +31,12 @@ var originalProperties = {
|
||||||
green: 255,
|
green: 255,
|
||||||
blue: 0 },
|
blue: 0 },
|
||||||
|
|
||||||
//modelURL: "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/Feisar_Ship.FBX",
|
modelURL: "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/Feisar_Ship.FBX",
|
||||||
//modelURL: "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/birarda/birarda_head.fbx",
|
//modelURL: "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/birarda/birarda_head.fbx",
|
||||||
//modelURL: "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/pug.fbx",
|
//modelURL: "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/pug.fbx",
|
||||||
//modelURL: "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/newInvader16x16-large-purple.svo",
|
//modelURL: "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/newInvader16x16-large-purple.svo",
|
||||||
//modelURL: "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/minotaur/mino_full.fbx",
|
//modelURL: "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/minotaur/mino_full.fbx",
|
||||||
modelURL: "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/Combat_tank_V01.FBX",
|
//modelURL: "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/Combat_tank_V01.FBX",
|
||||||
|
|
||||||
modelRotation: rotation
|
modelRotation: rotation
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,7 +28,7 @@ var NEW_VOXEL_SIZE = 1.0;
|
||||||
var NEW_VOXEL_DISTANCE_FROM_CAMERA = 3.0;
|
var NEW_VOXEL_DISTANCE_FROM_CAMERA = 3.0;
|
||||||
var PIXELS_PER_EXTRUDE_VOXEL = 16;
|
var PIXELS_PER_EXTRUDE_VOXEL = 16;
|
||||||
var WHEEL_PIXELS_PER_SCALE_CHANGE = 100;
|
var WHEEL_PIXELS_PER_SCALE_CHANGE = 100;
|
||||||
var MAX_VOXEL_SCALE = 1.0;
|
var MAX_VOXEL_SCALE = 16.0;
|
||||||
var MIN_VOXEL_SCALE = 1.0 / Math.pow(2.0, 8.0);
|
var MIN_VOXEL_SCALE = 1.0 / Math.pow(2.0, 8.0);
|
||||||
var WHITE_COLOR = { red: 255, green: 255, blue: 255 };
|
var WHITE_COLOR = { red: 255, green: 255, blue: 255 };
|
||||||
|
|
||||||
|
@ -394,6 +394,9 @@ function ScaleSelector() {
|
||||||
if (this.power < 13) {
|
if (this.power < 13) {
|
||||||
++this.power;
|
++this.power;
|
||||||
this.scale *= 2.0;
|
this.scale *= 2.0;
|
||||||
|
if (this.scale > MAX_VOXEL_SCALE) {
|
||||||
|
this.scale = MAX_VOXEL_SCALE;
|
||||||
|
}
|
||||||
this.update();
|
this.update();
|
||||||
rescaleImport();
|
rescaleImport();
|
||||||
resizeVoxelSound.play(voxelSizePlus);
|
resizeVoxelSound.play(voxelSizePlus);
|
||||||
|
@ -1056,6 +1059,9 @@ function mousePressEvent(event) {
|
||||||
lastVoxelPosition = { x: voxelDetails.x, y: voxelDetails.y, z: voxelDetails.z };
|
lastVoxelPosition = { x: voxelDetails.x, y: voxelDetails.y, z: voxelDetails.z };
|
||||||
lastVoxelColor = { red: newColor.red, green: newColor.green, blue: newColor.blue };
|
lastVoxelColor = { red: newColor.red, green: newColor.green, blue: newColor.blue };
|
||||||
lastVoxelScale = voxelDetails.s;
|
lastVoxelScale = voxelDetails.s;
|
||||||
|
if (lastVoxelScale > MAX_VOXEL_SCALE) {
|
||||||
|
lastVoxelScale = MAX_VOXEL_SCALE;
|
||||||
|
}
|
||||||
|
|
||||||
addVoxelSound.playRandom();
|
addVoxelSound.playRandom();
|
||||||
|
|
||||||
|
|
302
examples/locationsMenu.js
Normal file
302
examples/locationsMenu.js
Normal file
|
@ -0,0 +1,302 @@
|
||||||
|
//
|
||||||
|
// locationsMenu.js
|
||||||
|
// examples
|
||||||
|
//
|
||||||
|
// Created by Ryan Huffman on 5/28/14
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
var scriptUrl = "https://script.google.com/macros/s/AKfycbwIo4lmF-qUwX1Z-9eA_P-g2gse9oFhNcjVyyksGukyDDEFXgU/exec?action=listOwners&domain=alpha.highfidelity.io";
|
||||||
|
|
||||||
|
var LocationMenu = function(opts) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var pageSize = opts.pageSize || 10;
|
||||||
|
var menuWidth = opts.menuWidth || 150;
|
||||||
|
var menuHeight = opts.menuItemHeight || 24;
|
||||||
|
|
||||||
|
var inactiveColor = { red: 51, green: 102, blue: 102 };
|
||||||
|
var activeColor = { red: 18, green: 66, blue: 66 };
|
||||||
|
var prevNextColor = { red: 192, green: 192, blue: 192 };
|
||||||
|
var disabledColor = { red: 64, green: 64, blue: 64};
|
||||||
|
var position = { x: 0, y: 0 };
|
||||||
|
|
||||||
|
var locationIconUrl = "http://highfidelity-public.s3-us-west-1.amazonaws.com/images/tools/location.svg";
|
||||||
|
var toolHeight = 50;
|
||||||
|
var toolWidth = 50;
|
||||||
|
var visible = false;
|
||||||
|
var menuItemOffset = {
|
||||||
|
x: 55,
|
||||||
|
y: 0,
|
||||||
|
};
|
||||||
|
var menuItemPadding = 5;
|
||||||
|
var margin = 7;
|
||||||
|
var fullMenuHeight = (2 * menuItemOffset.y) + (menuHeight * (pageSize + 1));
|
||||||
|
var menuOffset = -fullMenuHeight + toolHeight;
|
||||||
|
|
||||||
|
var windowDimensions = Controller.getViewportDimensions();
|
||||||
|
|
||||||
|
this.locations = [];
|
||||||
|
this.numPages = 1;
|
||||||
|
this.page = 0;
|
||||||
|
|
||||||
|
this.menuToggleButton = Overlays.addOverlay("image", {
|
||||||
|
x: position.x,
|
||||||
|
y: position.y,
|
||||||
|
width: toolWidth, height: toolHeight,
|
||||||
|
subImage: { x: 0, y: toolHeight, width: toolWidth, height: toolHeight },
|
||||||
|
imageURL: locationIconUrl,
|
||||||
|
alpha: 0.9
|
||||||
|
});
|
||||||
|
|
||||||
|
this.background = Overlays.addOverlay("text", {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: menuWidth + 10,
|
||||||
|
height: (menuHeight * (pageSize + 1)) + 10,
|
||||||
|
color: { red: 0, green: 0, blue: 0},
|
||||||
|
topMargin: 4,
|
||||||
|
leftMargin: 4,
|
||||||
|
text: "",
|
||||||
|
visible: visible,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.menuItems = [];
|
||||||
|
for (var i = 0; i < pageSize; i++) {
|
||||||
|
var menuItem = Overlays.addOverlay("text", {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: menuWidth,
|
||||||
|
height: menuHeight,
|
||||||
|
color: inactiveColor,
|
||||||
|
topMargin: margin,
|
||||||
|
leftMargin: margin,
|
||||||
|
text: (i == 0) ? "Loading..." : "",
|
||||||
|
visible: visible,
|
||||||
|
});
|
||||||
|
this.menuItems.push({ overlay: menuItem, location: null });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.previousButton = Overlays.addOverlay("text", {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: menuWidth / 2,
|
||||||
|
height: menuHeight,
|
||||||
|
color: disabledColor,
|
||||||
|
topMargin: margin,
|
||||||
|
leftMargin: margin,
|
||||||
|
text: "Previous",
|
||||||
|
visible: visible,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.nextButton = Overlays.addOverlay("text", {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: menuWidth / 2,
|
||||||
|
height: menuHeight,
|
||||||
|
color: disabledColor,
|
||||||
|
topMargin: margin,
|
||||||
|
leftMargin: margin,
|
||||||
|
text: "Next",
|
||||||
|
visible: visible,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.reposition = function(force) {
|
||||||
|
var newWindowDimensions = Controller.getViewportDimensions();
|
||||||
|
if (force || newWindowDimensions.y != windowDimensions.y) {
|
||||||
|
windowDimensions = newWindowDimensions;
|
||||||
|
|
||||||
|
position.x = 8;
|
||||||
|
position.y = Math.floor(windowDimensions.y / 2) + 25 + 50 + 8;
|
||||||
|
|
||||||
|
Overlays.editOverlay(self.menuToggleButton, {
|
||||||
|
x: position.x,
|
||||||
|
y: position.y,
|
||||||
|
});
|
||||||
|
Overlays.editOverlay(self.background, {
|
||||||
|
x: position.x + menuItemOffset.x,
|
||||||
|
y: position.y + menuItemOffset.y - 2 * menuItemPadding + menuOffset,
|
||||||
|
});
|
||||||
|
for (var i = 0; i < pageSize; i++) {
|
||||||
|
Overlays.editOverlay(self.menuItems[i].overlay, {
|
||||||
|
x: position.x + menuItemOffset.x + menuItemPadding,
|
||||||
|
y: position.y + menuItemOffset.y - menuItemPadding + (i * menuHeight) + menuOffset,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Overlays.editOverlay(self.previousButton, {
|
||||||
|
x: position.x + menuItemOffset.x + menuItemPadding,
|
||||||
|
y: position.y + menuItemOffset.y - menuItemPadding + (pageSize * menuHeight) + menuOffset,
|
||||||
|
});
|
||||||
|
Overlays.editOverlay(self.nextButton, {
|
||||||
|
x: position.x + menuItemOffset.x + menuItemPadding + (menuWidth / 2),
|
||||||
|
y: position.y + menuItemOffset.y - menuItemPadding + (pageSize * menuHeight) + menuOffset,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateLocations = function(locations) {
|
||||||
|
this.locations = locations;
|
||||||
|
this.numPages = Math.ceil(locations.length / pageSize);
|
||||||
|
this.goToPage(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setError = function() {
|
||||||
|
Overlays.editOverlay(this.menuItems[0].overlay, { text: "Error loading data" });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.toggleMenu = function() {
|
||||||
|
visible = !visible;
|
||||||
|
for (var i = 0; i < this.menuItems.length; i++) {
|
||||||
|
Overlays.editOverlay(this.menuItems[i].overlay, { visible: visible});
|
||||||
|
}
|
||||||
|
Overlays.editOverlay(this.previousButton, { visible: visible});
|
||||||
|
Overlays.editOverlay(this.nextButton, { visible: visible});
|
||||||
|
Overlays.editOverlay(this.background, { visible: visible});
|
||||||
|
if (visible) {
|
||||||
|
Overlays.editOverlay(this.menuToggleButton, { subImage: { x: 0, y: 0, width: toolWidth, height: toolHeight } }),
|
||||||
|
} else {
|
||||||
|
Overlays.editOverlay(this.menuToggleButton, { subImage: { x: 0, y: toolHeight, width: toolWidth, height: toolHeight } }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.goToPage = function(pageNumber) {
|
||||||
|
if (pageNumber < 0 || pageNumber >= this.numPages) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.page = pageNumber;
|
||||||
|
var start = pageNumber * pageSize;
|
||||||
|
for (var i = 0; i < pageSize; i++) {
|
||||||
|
var update = {};
|
||||||
|
var location = null;
|
||||||
|
if (start + i < this.locations.length) {
|
||||||
|
location = this.locations[start + i];
|
||||||
|
update.text = (start + i + 1) + ". " + location.username;
|
||||||
|
update.color = inactiveColor;
|
||||||
|
} else {
|
||||||
|
update.text = "";
|
||||||
|
update.color = disabledColor;
|
||||||
|
}
|
||||||
|
Overlays.editOverlay(this.menuItems[i].overlay, update);
|
||||||
|
this.menuItems[i].location = location;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.previousEnabled = pageNumber > 0;
|
||||||
|
this.nextEnabled = pageNumber < (this.numPages - 1);
|
||||||
|
|
||||||
|
Overlays.editOverlay(this.previousButton, { color: this.previousEnabled ? prevNextColor : disabledColor});
|
||||||
|
Overlays.editOverlay(this.nextButton, { color: this.nextEnabled ? prevNextColor : disabledColor });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mousePressEvent = function(event) {
|
||||||
|
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
|
||||||
|
|
||||||
|
if (clickedOverlay == self.menuToggleButton) {
|
||||||
|
self.toggleMenu();
|
||||||
|
} else if (clickedOverlay == self.previousButton) {
|
||||||
|
if (self.previousEnabled) {
|
||||||
|
Overlays.editOverlay(clickedOverlay, { color: activeColor });
|
||||||
|
}
|
||||||
|
} else if (clickedOverlay == self.nextButton) {
|
||||||
|
if (self.nextEnabled) {
|
||||||
|
Overlays.editOverlay(clickedOverlay, { color: activeColor });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (var i = 0; i < self.menuItems.length; i++) {
|
||||||
|
if (clickedOverlay == self.menuItems[i].overlay) {
|
||||||
|
if (self.menuItems[i].location != null) {
|
||||||
|
Overlays.editOverlay(clickedOverlay, { color: activeColor });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mouseReleaseEvent = function(event) {
|
||||||
|
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
|
||||||
|
|
||||||
|
if (clickedOverlay == self.previousButton) {
|
||||||
|
if (self.previousEnabled) {
|
||||||
|
Overlays.editOverlay(clickedOverlay, { color: inactiveColor });
|
||||||
|
self.goToPage(self.page - 1);
|
||||||
|
}
|
||||||
|
} else if (clickedOverlay == self.nextButton) {
|
||||||
|
if (self.nextEnabled) {
|
||||||
|
Overlays.editOverlay(clickedOverlay, { color: inactiveColor });
|
||||||
|
self.goToPage(self.page + 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (var i = 0; i < self.menuItems.length; i++) {
|
||||||
|
if (clickedOverlay == self.menuItems[i].overlay) {
|
||||||
|
if (self.menuItems[i].location != null) {
|
||||||
|
Overlays.editOverlay(clickedOverlay, { color: inactiveColor });
|
||||||
|
var location = self.menuItems[i].location;
|
||||||
|
Window.location = "hifi://" + location.domain + "/"
|
||||||
|
+ location.x + "," + location.y + "," + location.z;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cleanup = function() {
|
||||||
|
for (var i = 0; i < self.menuItems.length; i++) {
|
||||||
|
Overlays.deleteOverlay(self.menuItems[i].overlay);
|
||||||
|
}
|
||||||
|
Overlays.deleteOverlay(self.menuToggleButton);
|
||||||
|
Overlays.deleteOverlay(self.previousButton);
|
||||||
|
Overlays.deleteOverlay(self.nextButton);
|
||||||
|
Overlays.deleteOverlay(self.background);
|
||||||
|
}
|
||||||
|
|
||||||
|
Controller.mousePressEvent.connect(this.mousePressEvent);
|
||||||
|
Controller.mouseReleaseEvent.connect(this.mouseReleaseEvent);
|
||||||
|
Script.update.connect(this.reposition);
|
||||||
|
Script.scriptEnding.connect(this.cleanup);
|
||||||
|
|
||||||
|
this.reposition(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
var locationMenu = new LocationMenu({ pageSize: 8 });
|
||||||
|
|
||||||
|
print("Loading strip data from " + scriptUrl);
|
||||||
|
|
||||||
|
var req = new XMLHttpRequest();
|
||||||
|
req.responseType = 'json';
|
||||||
|
|
||||||
|
req.onreadystatechange = function() {
|
||||||
|
if (req.readyState == req.DONE) {
|
||||||
|
if (req.status == 200 && req.response != null) {
|
||||||
|
for (var domain in req.response) {
|
||||||
|
var locations = req.response[domain];
|
||||||
|
var users = [];
|
||||||
|
for (var i = 0; i < locations.length; i++) {
|
||||||
|
var loc = locations[i];
|
||||||
|
var x1 = loc[1],
|
||||||
|
x2 = loc[2],
|
||||||
|
y1 = loc[3],
|
||||||
|
y2 = loc[4];
|
||||||
|
users.push({
|
||||||
|
domain: domain,
|
||||||
|
username: loc[0],
|
||||||
|
x: x1,
|
||||||
|
y: 300,
|
||||||
|
z: y1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
locationMenu.updateLocations(users);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print("Error loading data: " + req.status + " " + req.statusText + ", " + req.errorCode + ": " + req.responseText);
|
||||||
|
locationMenu.setError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
req.open("GET", scriptUrl);
|
||||||
|
req.send();
|
20
interface/resources/styles/console.qss
Normal file
20
interface/resources/styles/console.qss
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
* {
|
||||||
|
font-family: Inconsolata, Lucida Console, Andale Mono, Monaco;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#promptTextEdit {
|
||||||
|
color: #425d72;
|
||||||
|
}
|
||||||
|
|
||||||
|
#promptTextEdit:!enabled {
|
||||||
|
color: #7f7f7f;
|
||||||
|
}
|
||||||
|
|
||||||
|
#promptGutterLabel {
|
||||||
|
color: #a9bbc3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#promptGutterLabel:!enabled {
|
||||||
|
color: #7f7f7f;
|
||||||
|
}
|
|
@ -102,18 +102,11 @@ const int STARTUP_JITTER_SAMPLES = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / 2
|
||||||
// Startup optimistically with small jitter buffer that
|
// Startup optimistically with small jitter buffer that
|
||||||
// will start playback on the second received audio packet.
|
// will start playback on the second received audio packet.
|
||||||
|
|
||||||
const int MIRROR_VIEW_TOP_PADDING = 5;
|
|
||||||
const int MIRROR_VIEW_LEFT_PADDING = 10;
|
|
||||||
const int MIRROR_VIEW_WIDTH = 265;
|
|
||||||
const int MIRROR_VIEW_HEIGHT = 215;
|
|
||||||
const float MIRROR_FULLSCREEN_DISTANCE = 0.35f;
|
|
||||||
const float MIRROR_REARVIEW_DISTANCE = 0.65f;
|
|
||||||
const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f;
|
|
||||||
const float MIRROR_FIELD_OF_VIEW = 30.0f;
|
|
||||||
|
|
||||||
const QString CHECK_VERSION_URL = "https://highfidelity.io/latestVersion.xml";
|
const QString CHECK_VERSION_URL = "https://highfidelity.io/latestVersion.xml";
|
||||||
const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/hifi.skipversion";
|
const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/hifi.skipversion";
|
||||||
|
|
||||||
|
const QString DEFAULT_SCRIPTS_JS_URL = "http://public.highfidelity.io/scripts/defaultScripts.js";
|
||||||
|
|
||||||
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||||
if (message.size() > 0) {
|
if (message.size() > 0) {
|
||||||
QString dateString = QDateTime::currentDateTime().toTimeSpec(Qt::LocalTime).toString(Qt::ISODate);
|
QString dateString = QDateTime::currentDateTime().toTimeSpec(Qt::LocalTime).toString(Qt::ISODate);
|
||||||
|
@ -171,6 +164,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
||||||
_bytesPerSecond(0),
|
_bytesPerSecond(0),
|
||||||
_nodeBoundsDisplay(this),
|
_nodeBoundsDisplay(this),
|
||||||
_previousScriptLocation(),
|
_previousScriptLocation(),
|
||||||
|
_applicationOverlay(),
|
||||||
_runningScriptsWidget(new RunningScriptsWidget(_window)),
|
_runningScriptsWidget(new RunningScriptsWidget(_window)),
|
||||||
_runningScriptsWidgetWasVisible(false),
|
_runningScriptsWidgetWasVisible(false),
|
||||||
_trayIcon(new QSystemTrayIcon(_window))
|
_trayIcon(new QSystemTrayIcon(_window))
|
||||||
|
@ -370,7 +364,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
||||||
qDebug() << "This is a first run...";
|
qDebug() << "This is a first run...";
|
||||||
// clear the scripts, and set out script to our default scripts
|
// clear the scripts, and set out script to our default scripts
|
||||||
clearScriptsBeforeRunning();
|
clearScriptsBeforeRunning();
|
||||||
loadScript("http://public.highfidelity.io/scripts/defaultScripts.js");
|
loadScript(DEFAULT_SCRIPTS_JS_URL);
|
||||||
|
|
||||||
QMutexLocker locker(&_settingsMutex);
|
QMutexLocker locker(&_settingsMutex);
|
||||||
_settings->setValue("firstRun",QVariant(false));
|
_settings->setValue("firstRun",QVariant(false));
|
||||||
|
@ -630,10 +624,12 @@ void Application::paintGL() {
|
||||||
|
|
||||||
if (OculusManager::isConnected()) {
|
if (OculusManager::isConnected()) {
|
||||||
OculusManager::display(whichCamera);
|
OculusManager::display(whichCamera);
|
||||||
|
|
||||||
} else if (TV3DManager::isConnected()) {
|
} else if (TV3DManager::isConnected()) {
|
||||||
_glowEffect.prepare();
|
_glowEffect.prepare();
|
||||||
TV3DManager::display(whichCamera);
|
TV3DManager::display(whichCamera);
|
||||||
_glowEffect.render();
|
_glowEffect.render();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
_glowEffect.prepare();
|
_glowEffect.prepare();
|
||||||
|
|
||||||
|
@ -652,7 +648,7 @@ void Application::paintGL() {
|
||||||
_rearMirrorTools->render(true);
|
_rearMirrorTools->render(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
displayOverlay();
|
_applicationOverlay.renderOverlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
_frameCount++;
|
_frameCount++;
|
||||||
|
@ -2594,183 +2590,6 @@ void Application::computeOffAxisFrustum(float& left, float& right, float& bottom
|
||||||
_viewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane);
|
_viewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane);
|
||||||
}
|
}
|
||||||
|
|
||||||
const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f };
|
|
||||||
|
|
||||||
void Application::displayOverlay() {
|
|
||||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displayOverlay()");
|
|
||||||
|
|
||||||
// Render 2D overlay: I/O level bar graphs and text
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
|
||||||
glPushMatrix();
|
|
||||||
|
|
||||||
glLoadIdentity();
|
|
||||||
gluOrtho2D(0, _glWidget->width(), _glWidget->height(), 0);
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
|
||||||
glDisable(GL_LIGHTING);
|
|
||||||
|
|
||||||
// Display a single screen-size quad to create an alpha blended 'collision' flash
|
|
||||||
if (_audio.getCollisionFlashesScreen()) {
|
|
||||||
float collisionSoundMagnitude = _audio.getCollisionSoundMagnitude();
|
|
||||||
const float VISIBLE_COLLISION_SOUND_MAGNITUDE = 0.5f;
|
|
||||||
if (collisionSoundMagnitude > VISIBLE_COLLISION_SOUND_MAGNITUDE) {
|
|
||||||
renderCollisionOverlay(_glWidget->width(), _glWidget->height(), _audio.getCollisionSoundMagnitude());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Audio VU Meter and Mute Icon
|
|
||||||
const int MUTE_ICON_SIZE = 24;
|
|
||||||
const int AUDIO_METER_INSET = 2;
|
|
||||||
const int MUTE_ICON_PADDING = 10;
|
|
||||||
const int AUDIO_METER_WIDTH = MIRROR_VIEW_WIDTH - MUTE_ICON_SIZE - AUDIO_METER_INSET - MUTE_ICON_PADDING;
|
|
||||||
const int AUDIO_METER_SCALE_WIDTH = AUDIO_METER_WIDTH - 2 * AUDIO_METER_INSET;
|
|
||||||
const int AUDIO_METER_HEIGHT = 8;
|
|
||||||
const int AUDIO_METER_GAP = 5;
|
|
||||||
const int AUDIO_METER_X = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_INSET + AUDIO_METER_GAP;
|
|
||||||
|
|
||||||
int audioMeterY;
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
|
|
||||||
audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_GAP + MUTE_ICON_PADDING;
|
|
||||||
} else {
|
|
||||||
audioMeterY = AUDIO_METER_GAP + MUTE_ICON_PADDING;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float AUDIO_METER_BLUE[] = {0.0, 0.0, 1.0};
|
|
||||||
const float AUDIO_METER_GREEN[] = {0.0, 1.0, 0.0};
|
|
||||||
const float AUDIO_METER_RED[] = {1.0, 0.0, 0.0};
|
|
||||||
const float AUDIO_GREEN_START = 0.25 * AUDIO_METER_SCALE_WIDTH;
|
|
||||||
const float AUDIO_RED_START = 0.80 * AUDIO_METER_SCALE_WIDTH;
|
|
||||||
const float CLIPPING_INDICATOR_TIME = 1.0f;
|
|
||||||
const float AUDIO_METER_AVERAGING = 0.5;
|
|
||||||
const float LOG2 = log(2.f);
|
|
||||||
const float METER_LOUDNESS_SCALE = 2.8f / 5.f;
|
|
||||||
const float LOG2_LOUDNESS_FLOOR = 11.f;
|
|
||||||
float audioLevel = 0.f;
|
|
||||||
float loudness = _audio.getLastInputLoudness() + 1.f;
|
|
||||||
|
|
||||||
_trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.f - AUDIO_METER_AVERAGING) * loudness;
|
|
||||||
float log2loudness = log(_trailingAudioLoudness) / LOG2;
|
|
||||||
|
|
||||||
if (log2loudness <= LOG2_LOUDNESS_FLOOR) {
|
|
||||||
audioLevel = (log2loudness / LOG2_LOUDNESS_FLOOR) * METER_LOUDNESS_SCALE * AUDIO_METER_SCALE_WIDTH;
|
|
||||||
} else {
|
|
||||||
audioLevel = (log2loudness - (LOG2_LOUDNESS_FLOOR - 1.f)) * METER_LOUDNESS_SCALE * AUDIO_METER_SCALE_WIDTH;
|
|
||||||
}
|
|
||||||
if (audioLevel > AUDIO_METER_SCALE_WIDTH) {
|
|
||||||
audioLevel = AUDIO_METER_SCALE_WIDTH;
|
|
||||||
}
|
|
||||||
bool isClipping = ((_audio.getTimeSinceLastClip() > 0.f) && (_audio.getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME));
|
|
||||||
|
|
||||||
if ((_audio.getTimeSinceLastClip() > 0.f) && (_audio.getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME)) {
|
|
||||||
const float MAX_MAGNITUDE = 0.7f;
|
|
||||||
float magnitude = MAX_MAGNITUDE * (1 - _audio.getTimeSinceLastClip() / CLIPPING_INDICATOR_TIME);
|
|
||||||
renderCollisionOverlay(_glWidget->width(), _glWidget->height(), magnitude, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
_audio.renderToolBox(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP,
|
|
||||||
audioMeterY,
|
|
||||||
Menu::getInstance()->isOptionChecked(MenuOption::Mirror));
|
|
||||||
|
|
||||||
_audio.renderScope(_glWidget->width(), _glWidget->height());
|
|
||||||
|
|
||||||
glBegin(GL_QUADS);
|
|
||||||
if (isClipping) {
|
|
||||||
glColor3f(1, 0, 0);
|
|
||||||
} else {
|
|
||||||
glColor3f(0.475f, 0.475f, 0.475f);
|
|
||||||
}
|
|
||||||
|
|
||||||
audioMeterY += AUDIO_METER_HEIGHT;
|
|
||||||
|
|
||||||
glColor3f(0, 0, 0);
|
|
||||||
// Draw audio meter background Quad
|
|
||||||
glVertex2i(AUDIO_METER_X, audioMeterY);
|
|
||||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY);
|
|
||||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY + AUDIO_METER_HEIGHT);
|
|
||||||
glVertex2i(AUDIO_METER_X, audioMeterY + AUDIO_METER_HEIGHT);
|
|
||||||
|
|
||||||
|
|
||||||
if (audioLevel > AUDIO_RED_START) {
|
|
||||||
if (!isClipping) {
|
|
||||||
glColor3fv(AUDIO_METER_RED);
|
|
||||||
} else {
|
|
||||||
glColor3f(1, 1, 1);
|
|
||||||
}
|
|
||||||
// Draw Red Quad
|
|
||||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_RED_START, audioMeterY + AUDIO_METER_INSET);
|
|
||||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET);
|
|
||||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
|
||||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_RED_START, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
|
||||||
audioLevel = AUDIO_RED_START;
|
|
||||||
}
|
|
||||||
if (audioLevel > AUDIO_GREEN_START) {
|
|
||||||
if (!isClipping) {
|
|
||||||
glColor3fv(AUDIO_METER_GREEN);
|
|
||||||
} else {
|
|
||||||
glColor3f(1, 1, 1);
|
|
||||||
}
|
|
||||||
// Draw Green Quad
|
|
||||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_GREEN_START, audioMeterY + AUDIO_METER_INSET);
|
|
||||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET);
|
|
||||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
|
||||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_GREEN_START, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
|
||||||
audioLevel = AUDIO_GREEN_START;
|
|
||||||
}
|
|
||||||
// Draw Blue Quad
|
|
||||||
if (!isClipping) {
|
|
||||||
glColor3fv(AUDIO_METER_BLUE);
|
|
||||||
} else {
|
|
||||||
glColor3f(1, 1, 1);
|
|
||||||
}
|
|
||||||
// Draw Blue (low level) quad
|
|
||||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, audioMeterY + AUDIO_METER_INSET);
|
|
||||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET);
|
|
||||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
|
||||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) {
|
|
||||||
_myAvatar->renderHeadMouse(_glWidget->width(), _glWidget->height());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display stats and log text onscreen
|
|
||||||
glLineWidth(1.0f);
|
|
||||||
glPointSize(1.0f);
|
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
|
|
||||||
// let's set horizontal offset to give stats some margin to mirror
|
|
||||||
int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2;
|
|
||||||
int voxelPacketsToProcess = _voxelProcessor.packetsToProcessCount();
|
|
||||||
// Onscreen text about position, servers, etc
|
|
||||||
Stats::getInstance()->display(WHITE_TEXT, horizontalOffset, _fps, _packetsPerSecond, _bytesPerSecond, voxelPacketsToProcess);
|
|
||||||
// Bandwidth meter
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) {
|
|
||||||
Stats::drawBackground(0x33333399, _glWidget->width() - 296, _glWidget->height() - 68, 296, 68);
|
|
||||||
_bandwidthMeter.render(_glWidget->width(), _glWidget->height());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show on-screen msec timer
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::FrameTimer)) {
|
|
||||||
char frameTimer[10];
|
|
||||||
quint64 mSecsNow = floor(usecTimestampNow() / 1000.0 + 0.5);
|
|
||||||
sprintf(frameTimer, "%d\n", (int)(mSecsNow % 1000));
|
|
||||||
int timerBottom =
|
|
||||||
(Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
|
|
||||||
Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth))
|
|
||||||
? 80 : 20;
|
|
||||||
drawText(_glWidget->width() - 100, _glWidget->height() - timerBottom, 0.30f, 0.0f, 0, frameTimer, WHITE_TEXT);
|
|
||||||
}
|
|
||||||
_nodeBoundsDisplay.drawOverlay();
|
|
||||||
|
|
||||||
// give external parties a change to hook in
|
|
||||||
emit renderingOverlay();
|
|
||||||
|
|
||||||
_overlays.render2D();
|
|
||||||
|
|
||||||
glPopMatrix();
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) {
|
glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) {
|
||||||
float horizontalScale = _glWidget->width() / 2.0f;
|
float horizontalScale = _glWidget->width() / 2.0f;
|
||||||
float verticalScale = _glWidget->height() / 2.0f;
|
float verticalScale = _glWidget->height() / 2.0f;
|
||||||
|
@ -3437,16 +3256,21 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript
|
||||||
return _scriptEnginesHash[scriptName];
|
return _scriptEnginesHash[scriptName];
|
||||||
}
|
}
|
||||||
|
|
||||||
// start the script on a new thread...
|
ScriptEngine* scriptEngine;
|
||||||
QUrl scriptUrl(scriptName);
|
if (scriptName.isNull()) {
|
||||||
ScriptEngine* scriptEngine = new ScriptEngine(scriptUrl, &_controllerScriptingInterface);
|
scriptEngine = new ScriptEngine(NO_SCRIPT, "", &_controllerScriptingInterface);
|
||||||
_scriptEnginesHash.insert(scriptUrl.toString(), scriptEngine);
|
} else {
|
||||||
|
// start the script on a new thread...
|
||||||
|
QUrl scriptUrl(scriptName);
|
||||||
|
scriptEngine = new ScriptEngine(scriptUrl, &_controllerScriptingInterface);
|
||||||
|
_scriptEnginesHash.insert(scriptName, scriptEngine);
|
||||||
|
|
||||||
if (!scriptEngine->hasScript()) {
|
if (!scriptEngine->hasScript()) {
|
||||||
qDebug() << "Application::loadScript(), script failed to load...";
|
qDebug() << "Application::loadScript(), script failed to load...";
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
_runningScriptsWidget->setRunningScripts(getRunningScripts());
|
||||||
}
|
}
|
||||||
_runningScriptsWidget->setRunningScripts(getRunningScripts());
|
|
||||||
|
|
||||||
// setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so
|
// setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so
|
||||||
// we can use the same ones from the application.
|
// we can use the same ones from the application.
|
||||||
|
@ -3545,6 +3369,12 @@ void Application::reloadAllScripts() {
|
||||||
stopAllScripts(true);
|
stopAllScripts(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::loadDefaultScripts() {
|
||||||
|
if (!_scriptEnginesHash.contains(DEFAULT_SCRIPTS_JS_URL)) {
|
||||||
|
loadScript(DEFAULT_SCRIPTS_JS_URL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Application::manageRunningScriptsWidgetVisibility(bool shown) {
|
void Application::manageRunningScriptsWidgetVisibility(bool shown) {
|
||||||
if (_runningScriptsWidgetWasVisible && shown) {
|
if (_runningScriptsWidgetWasVisible && shown) {
|
||||||
_runningScriptsWidget->show();
|
_runningScriptsWidget->show();
|
||||||
|
|
|
@ -83,6 +83,7 @@
|
||||||
#include "ui/LogDialog.h"
|
#include "ui/LogDialog.h"
|
||||||
#include "ui/UpdateDialog.h"
|
#include "ui/UpdateDialog.h"
|
||||||
#include "ui/overlays/Overlays.h"
|
#include "ui/overlays/Overlays.h"
|
||||||
|
#include "ui/ApplicationOverlay.h"
|
||||||
#include "ui/RunningScriptsWidget.h"
|
#include "ui/RunningScriptsWidget.h"
|
||||||
#include "voxels/VoxelFade.h"
|
#include "voxels/VoxelFade.h"
|
||||||
#include "voxels/VoxelHideShowThread.h"
|
#include "voxels/VoxelHideShowThread.h"
|
||||||
|
@ -116,6 +117,15 @@ static const QString CUSTOM_URL_SCHEME = "hifi:";
|
||||||
static const float BILLBOARD_FIELD_OF_VIEW = 30.0f; // degrees
|
static const float BILLBOARD_FIELD_OF_VIEW = 30.0f; // degrees
|
||||||
static const float BILLBOARD_DISTANCE = 5.0f; // meters
|
static const float BILLBOARD_DISTANCE = 5.0f; // meters
|
||||||
|
|
||||||
|
static const int MIRROR_VIEW_TOP_PADDING = 5;
|
||||||
|
static const int MIRROR_VIEW_LEFT_PADDING = 10;
|
||||||
|
static const int MIRROR_VIEW_WIDTH = 265;
|
||||||
|
static const int MIRROR_VIEW_HEIGHT = 215;
|
||||||
|
static const float MIRROR_FULLSCREEN_DISTANCE = 0.35f;
|
||||||
|
static const float MIRROR_REARVIEW_DISTANCE = 0.65f;
|
||||||
|
static const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f;
|
||||||
|
static const float MIRROR_FIELD_OF_VIEW = 30.0f;
|
||||||
|
|
||||||
class Application : public QApplication {
|
class Application : public QApplication {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -182,6 +192,7 @@ public:
|
||||||
ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; }
|
ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; }
|
||||||
VoxelSystem* getVoxels() { return &_voxels; }
|
VoxelSystem* getVoxels() { return &_voxels; }
|
||||||
VoxelTree* getVoxelTree() { return _voxels.getTree(); }
|
VoxelTree* getVoxelTree() { return _voxels.getTree(); }
|
||||||
|
const VoxelPacketProcessor& getVoxelPacketProcessor() const { return _voxelProcessor; }
|
||||||
ParticleTreeRenderer* getParticles() { return &_particles; }
|
ParticleTreeRenderer* getParticles() { return &_particles; }
|
||||||
MetavoxelSystem* getMetavoxels() { return &_metavoxels; }
|
MetavoxelSystem* getMetavoxels() { return &_metavoxels; }
|
||||||
ModelTreeRenderer* getModels() { return &_models; }
|
ModelTreeRenderer* getModels() { return &_models; }
|
||||||
|
@ -205,6 +216,13 @@ public:
|
||||||
BandwidthMeter* getBandwidthMeter() { return &_bandwidthMeter; }
|
BandwidthMeter* getBandwidthMeter() { return &_bandwidthMeter; }
|
||||||
QUndoStack* getUndoStack() { return &_undoStack; }
|
QUndoStack* getUndoStack() { return &_undoStack; }
|
||||||
QSystemTrayIcon* getTrayIcon() { return _trayIcon; }
|
QSystemTrayIcon* getTrayIcon() { return _trayIcon; }
|
||||||
|
ApplicationOverlay& getApplicationOverlay() { return _applicationOverlay; }
|
||||||
|
Overlays& getOverlays() { return _overlays; }
|
||||||
|
|
||||||
|
float getFps() const { return _fps; }
|
||||||
|
float getPacketsPerSecond() const { return _packetsPerSecond; }
|
||||||
|
float getBytesPerSecond() const { return _bytesPerSecond; }
|
||||||
|
const glm::vec3& getViewMatrixTranslation() const { return _viewMatrixTranslation; }
|
||||||
|
|
||||||
/// if you need to access the application settings, use lockSettings()/unlockSettings()
|
/// if you need to access the application settings, use lockSettings()/unlockSettings()
|
||||||
QSettings* lockSettings() { _settingsMutex.lock(); return _settings; }
|
QSettings* lockSettings() { _settingsMutex.lock(); return _settings; }
|
||||||
|
@ -305,11 +323,12 @@ public slots:
|
||||||
void loadScriptURLDialog();
|
void loadScriptURLDialog();
|
||||||
void toggleLogDialog();
|
void toggleLogDialog();
|
||||||
void initAvatarAndViewFrustum();
|
void initAvatarAndViewFrustum();
|
||||||
ScriptEngine* loadScript(const QString& fileNameString, bool loadScriptFromEditor = false);
|
ScriptEngine* loadScript(const QString& fileNameString = QString(), bool loadScriptFromEditor = false);
|
||||||
void scriptFinished(const QString& scriptName);
|
void scriptFinished(const QString& scriptName);
|
||||||
void stopAllScripts(bool restart = false);
|
void stopAllScripts(bool restart = false);
|
||||||
void stopScript(const QString& scriptName);
|
void stopScript(const QString& scriptName);
|
||||||
void reloadAllScripts();
|
void reloadAllScripts();
|
||||||
|
void loadDefaultScripts();
|
||||||
void toggleRunningScriptsWidget();
|
void toggleRunningScriptsWidget();
|
||||||
|
|
||||||
void uploadHead();
|
void uploadHead();
|
||||||
|
@ -377,7 +396,6 @@ private:
|
||||||
glm::vec3 getSunDirection();
|
glm::vec3 getSunDirection();
|
||||||
|
|
||||||
void updateShadowMap();
|
void updateShadowMap();
|
||||||
void displayOverlay();
|
|
||||||
void renderRearViewMirror(const QRect& region, bool billboard = false);
|
void renderRearViewMirror(const QRect& region, bool billboard = false);
|
||||||
void renderViewFrustum(ViewFrustum& viewFrustum);
|
void renderViewFrustum(ViewFrustum& viewFrustum);
|
||||||
|
|
||||||
|
@ -552,6 +570,7 @@ private:
|
||||||
TouchEvent _lastTouchEvent;
|
TouchEvent _lastTouchEvent;
|
||||||
|
|
||||||
Overlays _overlays;
|
Overlays _overlays;
|
||||||
|
ApplicationOverlay _applicationOverlay;
|
||||||
|
|
||||||
AudioReflector _audioReflector;
|
AudioReflector _audioReflector;
|
||||||
RunningScriptsWidget* _runningScriptsWidget;
|
RunningScriptsWidget* _runningScriptsWidget;
|
||||||
|
|
|
@ -73,6 +73,11 @@ const int ONE_SECOND_OF_FRAMES = 60;
|
||||||
const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES;
|
const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES;
|
||||||
const float MUTE_RADIUS = 50;
|
const float MUTE_RADIUS = 50;
|
||||||
|
|
||||||
|
const QString CONSOLE_TITLE = "Scripting Console";
|
||||||
|
const float CONSOLE_WINDOW_OPACITY = 0.95f;
|
||||||
|
const int CONSOLE_WIDTH = 800;
|
||||||
|
const int CONSOLE_HEIGHT = 200;
|
||||||
|
|
||||||
Menu::Menu() :
|
Menu::Menu() :
|
||||||
_actionHash(),
|
_actionHash(),
|
||||||
_audioJitterBufferSamples(0),
|
_audioJitterBufferSamples(0),
|
||||||
|
@ -81,6 +86,7 @@ Menu::Menu() :
|
||||||
_faceshiftEyeDeflection(DEFAULT_FACESHIFT_EYE_DEFLECTION),
|
_faceshiftEyeDeflection(DEFAULT_FACESHIFT_EYE_DEFLECTION),
|
||||||
_frustumDrawMode(FRUSTUM_DRAW_MODE_ALL),
|
_frustumDrawMode(FRUSTUM_DRAW_MODE_ALL),
|
||||||
_viewFrustumOffset(DEFAULT_FRUSTUM_OFFSET),
|
_viewFrustumOffset(DEFAULT_FRUSTUM_OFFSET),
|
||||||
|
_jsConsole(NULL),
|
||||||
_octreeStatsDialog(NULL),
|
_octreeStatsDialog(NULL),
|
||||||
_lodToolsDialog(NULL),
|
_lodToolsDialog(NULL),
|
||||||
_maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM),
|
_maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM),
|
||||||
|
@ -227,6 +233,12 @@ Menu::Menu() :
|
||||||
_chatWindow = new ChatWindow(Application::getInstance()->getWindow());
|
_chatWindow = new ChatWindow(Application::getInstance()->getWindow());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
addActionToQMenuAndActionHash(toolsMenu,
|
||||||
|
MenuOption::Console,
|
||||||
|
Qt::CTRL | Qt::ALT | Qt::Key_J,
|
||||||
|
this,
|
||||||
|
SLOT(toggleConsole()));
|
||||||
|
|
||||||
QMenu* viewMenu = addMenu("View");
|
QMenu* viewMenu = addMenu("View");
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(viewMenu,
|
addCheckableActionToQMenuAndActionHash(viewMenu,
|
||||||
|
@ -1258,6 +1270,25 @@ void Menu::toggleChat() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Menu::toggleConsole() {
|
||||||
|
QMainWindow* mainWindow = Application::getInstance()->getWindow();
|
||||||
|
if (!_jsConsole) {
|
||||||
|
QDialog* dialog = new QDialog(mainWindow, Qt::WindowStaysOnTopHint);
|
||||||
|
QVBoxLayout* layout = new QVBoxLayout(dialog);
|
||||||
|
dialog->setLayout(new QVBoxLayout(dialog));
|
||||||
|
|
||||||
|
dialog->resize(QSize(CONSOLE_WIDTH, CONSOLE_HEIGHT));
|
||||||
|
layout->setMargin(0);
|
||||||
|
layout->setSpacing(0);
|
||||||
|
layout->addWidget(new JSConsole(dialog));
|
||||||
|
dialog->setWindowOpacity(CONSOLE_WINDOW_OPACITY);
|
||||||
|
dialog->setWindowTitle(CONSOLE_TITLE);
|
||||||
|
|
||||||
|
_jsConsole = dialog;
|
||||||
|
}
|
||||||
|
_jsConsole->setVisible(!_jsConsole->isVisible());
|
||||||
|
}
|
||||||
|
|
||||||
void Menu::audioMuteToggled() {
|
void Menu::audioMuteToggled() {
|
||||||
QAction *muteAction = _actionHash.value(MenuOption::MuteAudio);
|
QAction *muteAction = _actionHash.value(MenuOption::MuteAudio);
|
||||||
muteAction->setChecked(Application::getInstance()->getAudio()->getMuted());
|
muteAction->setChecked(Application::getInstance()->getAudio()->getMuted());
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "location/LocationManager.h"
|
#include "location/LocationManager.h"
|
||||||
#include "ui/PreferencesDialog.h"
|
#include "ui/PreferencesDialog.h"
|
||||||
#include "ui/ChatWindow.h"
|
#include "ui/ChatWindow.h"
|
||||||
|
#include "ui/JSConsole.h"
|
||||||
#include "ui/ScriptEditorWindow.h"
|
#include "ui/ScriptEditorWindow.h"
|
||||||
|
|
||||||
const float ADJUST_LOD_DOWN_FPS = 40.0;
|
const float ADJUST_LOD_DOWN_FPS = 40.0;
|
||||||
|
@ -189,6 +190,7 @@ private slots:
|
||||||
void showMetavoxelEditor();
|
void showMetavoxelEditor();
|
||||||
void showScriptEditor();
|
void showScriptEditor();
|
||||||
void showChat();
|
void showChat();
|
||||||
|
void toggleConsole();
|
||||||
void toggleChat();
|
void toggleChat();
|
||||||
void audioMuteToggled();
|
void audioMuteToggled();
|
||||||
void namedLocationCreated(LocationManager::NamedLocationCreateResponse response);
|
void namedLocationCreated(LocationManager::NamedLocationCreateResponse response);
|
||||||
|
@ -243,6 +245,7 @@ private:
|
||||||
QPointer<MetavoxelEditor> _MetavoxelEditor;
|
QPointer<MetavoxelEditor> _MetavoxelEditor;
|
||||||
QPointer<ScriptEditorWindow> _ScriptEditor;
|
QPointer<ScriptEditorWindow> _ScriptEditor;
|
||||||
QPointer<ChatWindow> _chatWindow;
|
QPointer<ChatWindow> _chatWindow;
|
||||||
|
QDialog* _jsConsole;
|
||||||
OctreeStatsDialog* _octreeStatsDialog;
|
OctreeStatsDialog* _octreeStatsDialog;
|
||||||
LodToolsDialog* _lodToolsDialog;
|
LodToolsDialog* _lodToolsDialog;
|
||||||
int _maxVoxels;
|
int _maxVoxels;
|
||||||
|
@ -308,6 +311,7 @@ namespace MenuOption {
|
||||||
const QString CollideWithParticles = "Collide With Particles";
|
const QString CollideWithParticles = "Collide With Particles";
|
||||||
const QString CollideWithVoxels = "Collide With Voxels";
|
const QString CollideWithVoxels = "Collide With Voxels";
|
||||||
const QString Collisions = "Collisions";
|
const QString Collisions = "Collisions";
|
||||||
|
const QString Console = "Console...";
|
||||||
const QString DecreaseAvatarSize = "Decrease Avatar Size";
|
const QString DecreaseAvatarSize = "Decrease Avatar Size";
|
||||||
const QString DecreaseVoxelSize = "Decrease Voxel Size";
|
const QString DecreaseVoxelSize = "Decrease Voxel Size";
|
||||||
const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD";
|
const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD";
|
||||||
|
|
|
@ -49,9 +49,9 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) {
|
||||||
void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) {
|
void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) {
|
||||||
// get the rotation axes in joint space and use them to adjust the rotation
|
// get the rotation axes in joint space and use them to adjust the rotation
|
||||||
glm::mat3 axes = glm::mat3_cast(_rotation);
|
glm::mat3 axes = glm::mat3_cast(_rotation);
|
||||||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) *
|
glm::mat3 inverse = glm::mat3(glm::inverse(parentState._transform * glm::translate(state._translation) *
|
||||||
joint.preTransform * glm::mat4_cast(joint.preRotation)));
|
joint.preTransform * glm::mat4_cast(joint.preRotation)));
|
||||||
state.rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalRoll(), glm::normalize(inverse * axes[2]))
|
state._rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalRoll(), glm::normalize(inverse * axes[2]))
|
||||||
* glm::angleAxis(RADIANS_PER_DEGREE * _owningHead->getFinalYaw(), glm::normalize(inverse * axes[1]))
|
* glm::angleAxis(RADIANS_PER_DEGREE * _owningHead->getFinalYaw(), glm::normalize(inverse * axes[1]))
|
||||||
* glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalPitch(), glm::normalize(inverse * axes[0]))
|
* glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalPitch(), glm::normalize(inverse * axes[0]))
|
||||||
* joint.rotation;
|
* joint.rotation;
|
||||||
|
@ -59,17 +59,34 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX
|
||||||
|
|
||||||
void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) {
|
void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) {
|
||||||
// likewise with the eye joints
|
// likewise with the eye joints
|
||||||
glm::mat4 inverse = glm::inverse(parentState.transform * glm::translate(state.translation) *
|
glm::mat4 inverse = glm::inverse(parentState._transform * glm::translate(state._translation) *
|
||||||
joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation));
|
joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation));
|
||||||
glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getFinalOrientation() * IDENTITY_FRONT, 0.0f));
|
glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getFinalOrientation() * IDENTITY_FRONT, 0.0f));
|
||||||
glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(_owningHead->getLookAtPosition() +
|
glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(_owningHead->getLookAtPosition() +
|
||||||
_owningHead->getSaccade() - _translation, 1.0f));
|
_owningHead->getSaccade() - _translation, 1.0f));
|
||||||
glm::quat between = rotationBetween(front, lookAt);
|
glm::quat between = rotationBetween(front, lookAt);
|
||||||
const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE;
|
const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE;
|
||||||
state.rotation = glm::angleAxis(glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE), glm::axis(between)) *
|
state._rotation = glm::angleAxis(glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE), glm::axis(between)) *
|
||||||
joint.rotation;
|
joint.rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FaceModel::updateJointState(int index) {
|
||||||
|
JointState& state = _jointStates[index];
|
||||||
|
const FBXJoint& joint = state.getFBXJoint();
|
||||||
|
if (joint.parentIndex != -1) {
|
||||||
|
const JointState& parentState = _jointStates.at(joint.parentIndex);
|
||||||
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
|
if (index == geometry.neckJointIndex) {
|
||||||
|
maybeUpdateNeckRotation(parentState, joint, state);
|
||||||
|
|
||||||
|
} else if (index == geometry.leftEyeJointIndex || index == geometry.rightEyeJointIndex) {
|
||||||
|
maybeUpdateEyeRotation(parentState, joint, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Model::updateJointState(index);
|
||||||
|
}
|
||||||
|
|
||||||
bool FaceModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const {
|
bool FaceModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const {
|
||||||
if (!isActive()) {
|
if (!isActive()) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -28,7 +28,8 @@ public:
|
||||||
|
|
||||||
virtual void maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state);
|
virtual void maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state);
|
||||||
virtual void maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state);
|
virtual void maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state);
|
||||||
|
virtual void updateJointState(int index);
|
||||||
|
|
||||||
/// Retrieve the positions of up to two eye meshes.
|
/// Retrieve the positions of up to two eye meshes.
|
||||||
/// \return whether or not both eye meshes were found
|
/// \return whether or not both eye meshes were found
|
||||||
bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const;
|
bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const;
|
||||||
|
|
|
@ -45,7 +45,7 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
|
||||||
}
|
}
|
||||||
int jointIndex = geometry.humanIKJointIndices.at(humanIKJointIndex);
|
int jointIndex = geometry.humanIKJointIndices.at(humanIKJointIndex);
|
||||||
if (jointIndex != -1) {
|
if (jointIndex != -1) {
|
||||||
setJointRotation(jointIndex, _rotation * prioVR->getJointRotations().at(i), true, PALM_PRIORITY);
|
setJointRotation(jointIndex, _rotation * prioVR->getJointRotations().at(i), PALM_PRIORITY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -188,8 +188,8 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) {
|
||||||
setJointPosition(parentJointIndex, palm.getPosition() + forearmVector *
|
setJointPosition(parentJointIndex, palm.getPosition() + forearmVector *
|
||||||
geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale),
|
geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale),
|
||||||
glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY);
|
glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY);
|
||||||
setJointRotation(parentJointIndex, palmRotation, true, PALM_PRIORITY);
|
setJointRotation(parentJointIndex, palmRotation, PALM_PRIORITY);
|
||||||
_jointStates[jointIndex].rotation = glm::quat();
|
_jointStates[jointIndex]._rotation = glm::quat();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
setJointPosition(jointIndex, palm.getPosition(), palmRotation,
|
setJointPosition(jointIndex, palm.getPosition(), palmRotation,
|
||||||
|
@ -199,10 +199,10 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) {
|
||||||
|
|
||||||
void SkeletonModel::updateJointState(int index) {
|
void SkeletonModel::updateJointState(int index) {
|
||||||
JointState& state = _jointStates[index];
|
JointState& state = _jointStates[index];
|
||||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
const FBXJoint& joint = state.getFBXJoint();
|
||||||
const FBXJoint& joint = geometry.joints.at(index);
|
|
||||||
if (joint.parentIndex != -1) {
|
if (joint.parentIndex != -1) {
|
||||||
const JointState& parentState = _jointStates.at(joint.parentIndex);
|
const JointState& parentState = _jointStates.at(joint.parentIndex);
|
||||||
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
if (index == geometry.leanJointIndex) {
|
if (index == geometry.leanJointIndex) {
|
||||||
maybeUpdateLeanRotation(parentState, joint, state);
|
maybeUpdateLeanRotation(parentState, joint, state);
|
||||||
|
|
||||||
|
@ -217,9 +217,9 @@ void SkeletonModel::updateJointState(int index) {
|
||||||
Model::updateJointState(index);
|
Model::updateJointState(index);
|
||||||
|
|
||||||
if (index == _geometry->getFBXGeometry().rootJointIndex) {
|
if (index == _geometry->getFBXGeometry().rootJointIndex) {
|
||||||
state.transform[3][0] = 0.0f;
|
state._transform[3][0] = 0.0f;
|
||||||
state.transform[3][1] = 0.0f;
|
state._transform[3][1] = 0.0f;
|
||||||
state.transform[3][2] = 0.0f;
|
state._transform[3][2] = 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,9 +229,9 @@ void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const
|
||||||
}
|
}
|
||||||
// get the rotation axes in joint space and use them to adjust the rotation
|
// get the rotation axes in joint space and use them to adjust the rotation
|
||||||
glm::mat3 axes = glm::mat3_cast(_rotation);
|
glm::mat3 axes = glm::mat3_cast(_rotation);
|
||||||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) *
|
glm::mat3 inverse = glm::mat3(glm::inverse(parentState._transform * glm::translate(state._translation) *
|
||||||
joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation)));
|
joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation)));
|
||||||
state.rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanSideways(),
|
state._rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanSideways(),
|
||||||
glm::normalize(inverse * axes[2])) * glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanForward(),
|
glm::normalize(inverse * axes[2])) * glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanForward(),
|
||||||
glm::normalize(inverse * axes[0])) * joint.rotation;
|
glm::normalize(inverse * axes[0])) * joint.rotation;
|
||||||
}
|
}
|
||||||
|
@ -255,11 +255,11 @@ void SkeletonModel::renderJointConstraints(int jointIndex) {
|
||||||
do {
|
do {
|
||||||
const FBXJoint& joint = geometry.joints.at(jointIndex);
|
const FBXJoint& joint = geometry.joints.at(jointIndex);
|
||||||
const JointState& jointState = _jointStates.at(jointIndex);
|
const JointState& jointState = _jointStates.at(jointIndex);
|
||||||
glm::vec3 position = extractTranslation(jointState.transform) + _translation;
|
glm::vec3 position = extractTranslation(jointState._transform) + _translation;
|
||||||
|
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glTranslatef(position.x, position.y, position.z);
|
glTranslatef(position.x, position.y, position.z);
|
||||||
glm::quat parentRotation = (joint.parentIndex == -1) ? _rotation : _jointStates.at(joint.parentIndex).combinedRotation;
|
glm::quat parentRotation = (joint.parentIndex == -1) ? _rotation : _jointStates.at(joint.parentIndex)._combinedRotation;
|
||||||
glm::vec3 rotationAxis = glm::axis(parentRotation);
|
glm::vec3 rotationAxis = glm::axis(parentRotation);
|
||||||
glRotatef(glm::degrees(glm::angle(parentRotation)), rotationAxis.x, rotationAxis.y, rotationAxis.z);
|
glRotatef(glm::degrees(glm::angle(parentRotation)), rotationAxis.x, rotationAxis.y, rotationAxis.z);
|
||||||
float fanScale = directionSize * 0.75f;
|
float fanScale = directionSize * 0.75f;
|
||||||
|
@ -292,7 +292,7 @@ void SkeletonModel::renderJointConstraints(int jointIndex) {
|
||||||
}
|
}
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
|
|
||||||
renderOrientationDirections(position, jointState.combinedRotation, directionSize);
|
renderOrientationDirections(position, jointState._combinedRotation, directionSize);
|
||||||
jointIndex = joint.parentIndex;
|
jointIndex = joint.parentIndex;
|
||||||
|
|
||||||
} while (jointIndex != -1 && geometry.joints.at(jointIndex).isFree);
|
} while (jointIndex != -1 && geometry.joints.at(jointIndex).isFree);
|
||||||
|
@ -355,12 +355,12 @@ void SkeletonModel::setHandPosition(int jointIndex, const glm::vec3& position, c
|
||||||
glm::vec3 forwardVector(rightHand ? -1.0f : 1.0f, 0.0f, 0.0f);
|
glm::vec3 forwardVector(rightHand ? -1.0f : 1.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
glm::quat shoulderRotation = rotationBetween(forwardVector, elbowPosition - shoulderPosition);
|
glm::quat shoulderRotation = rotationBetween(forwardVector, elbowPosition - shoulderPosition);
|
||||||
setJointRotation(shoulderJointIndex, shoulderRotation, true, PALM_PRIORITY);
|
setJointRotation(shoulderJointIndex, shoulderRotation, PALM_PRIORITY);
|
||||||
|
|
||||||
setJointRotation(elbowJointIndex, rotationBetween(shoulderRotation * forwardVector,
|
setJointRotation(elbowJointIndex, rotationBetween(shoulderRotation * forwardVector,
|
||||||
wristPosition - elbowPosition) * shoulderRotation, true, PALM_PRIORITY);
|
wristPosition - elbowPosition) * shoulderRotation, PALM_PRIORITY);
|
||||||
|
|
||||||
setJointRotation(jointIndex, rotation, true, PALM_PRIORITY);
|
setJointRotation(jointIndex, rotation, PALM_PRIORITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkeletonModel::getLeftHandPosition(glm::vec3& position) const {
|
bool SkeletonModel::getLeftHandPosition(glm::vec3& position) const {
|
||||||
|
|
|
@ -50,7 +50,8 @@ void OculusManager::connect() {
|
||||||
_sensorDevice = *_hmdDevice->GetSensor();
|
_sensorDevice = *_hmdDevice->GetSensor();
|
||||||
_sensorFusion = new SensorFusion;
|
_sensorFusion = new SensorFusion;
|
||||||
_sensorFusion->AttachToSensor(_sensorDevice);
|
_sensorFusion->AttachToSensor(_sensorDevice);
|
||||||
|
_sensorFusion->SetPredictionEnabled(true);
|
||||||
|
|
||||||
HMDInfo info;
|
HMDInfo info;
|
||||||
_hmdDevice->GetDeviceInfo(&info);
|
_hmdDevice->GetDeviceInfo(&info);
|
||||||
_stereoConfig.SetHMDInfo(info);
|
_stereoConfig.SetHMDInfo(info);
|
||||||
|
@ -81,7 +82,13 @@ void OculusManager::configureCamera(Camera& camera, int screenWidth, int screenH
|
||||||
|
|
||||||
void OculusManager::display(Camera& whichCamera) {
|
void OculusManager::display(Camera& whichCamera) {
|
||||||
#ifdef HAVE_LIBOVR
|
#ifdef HAVE_LIBOVR
|
||||||
Application::getInstance()->getGlowEffect()->prepare();
|
ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay();
|
||||||
|
// We only need to render the overlays to a texture once, then we just render the texture as a quad
|
||||||
|
// PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay()
|
||||||
|
applicationOverlay.renderOverlay(true);
|
||||||
|
const bool displayOverlays = false;
|
||||||
|
|
||||||
|
Application::getInstance()->getGlowEffect()->prepare();
|
||||||
|
|
||||||
// render the left eye view to the left side of the screen
|
// render the left eye view to the left side of the screen
|
||||||
const StereoEyeParams& leftEyeParams = _stereoConfig.GetEyeRenderParams(StereoEye_Left);
|
const StereoEyeParams& leftEyeParams = _stereoConfig.GetEyeRenderParams(StereoEye_Left);
|
||||||
|
@ -100,6 +107,10 @@ void OculusManager::display(Camera& whichCamera) {
|
||||||
|
|
||||||
Application::getInstance()->displaySide(whichCamera);
|
Application::getInstance()->displaySide(whichCamera);
|
||||||
|
|
||||||
|
if (displayOverlays) {
|
||||||
|
applicationOverlay.displayOverlayTextureOculus(whichCamera);
|
||||||
|
}
|
||||||
|
|
||||||
// and the right eye to the right side
|
// and the right eye to the right side
|
||||||
const StereoEyeParams& rightEyeParams = _stereoConfig.GetEyeRenderParams(StereoEye_Right);
|
const StereoEyeParams& rightEyeParams = _stereoConfig.GetEyeRenderParams(StereoEye_Right);
|
||||||
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
@ -115,6 +126,10 @@ void OculusManager::display(Camera& whichCamera) {
|
||||||
|
|
||||||
Application::getInstance()->displaySide(whichCamera);
|
Application::getInstance()->displaySide(whichCamera);
|
||||||
|
|
||||||
|
if (displayOverlays) {
|
||||||
|
applicationOverlay.displayOverlayTextureOculus(whichCamera);
|
||||||
|
}
|
||||||
|
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
|
|
||||||
// restore our normal viewport
|
// restore our normal viewport
|
||||||
|
@ -187,7 +202,7 @@ void OculusManager::reset() {
|
||||||
|
|
||||||
void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) {
|
void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) {
|
||||||
#ifdef HAVE_LIBOVR
|
#ifdef HAVE_LIBOVR
|
||||||
_sensorFusion->GetOrientation().GetEulerAngles<Axis_Y, Axis_X, Axis_Z, Rotate_CCW, Handed_R>(&yaw, &pitch, &roll);
|
_sensorFusion->GetPredictedOrientation().GetEulerAngles<Axis_Y, Axis_X, Axis_Z, Rotate_CCW, Handed_R>(&yaw, &pitch, &roll);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ static void setPalm(float deltaTime, int index) {
|
||||||
glm::vec3 position;
|
glm::vec3 position;
|
||||||
glm::quat rotation;
|
glm::quat rotation;
|
||||||
|
|
||||||
Model* skeletonModel = &Application::getInstance()->getAvatar()->getSkeletonModel();
|
SkeletonModel* skeletonModel = &Application::getInstance()->getAvatar()->getSkeletonModel();
|
||||||
int jointIndex;
|
int jointIndex;
|
||||||
glm::quat inverseRotation = glm::inverse(Application::getInstance()->getAvatar()->getOrientation());
|
glm::quat inverseRotation = glm::inverse(Application::getInstance()->getAvatar()->getOrientation());
|
||||||
if (index == LEFT_HAND_INDEX) {
|
if (index == LEFT_HAND_INDEX) {
|
||||||
|
|
|
@ -139,8 +139,7 @@ QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) {
|
||||||
if (_isEmpty && _renderMode != DIFFUSE_ADD_MODE) {
|
if (_isEmpty && _renderMode != DIFFUSE_ADD_MODE) {
|
||||||
// copy the primary to the screen
|
// copy the primary to the screen
|
||||||
if (QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) {
|
if (QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) {
|
||||||
QOpenGLFramebufferObject::blitFramebuffer(destFBO, primaryFBO);
|
QOpenGLFramebufferObject::blitFramebuffer(destFBO, primaryFBO);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
maybeBind(destFBO);
|
maybeBind(destFBO);
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
|
|
@ -135,13 +135,11 @@ void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locati
|
||||||
program.release();
|
program.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<Model::JointState> Model::createJointStates(const FBXGeometry& geometry) {
|
QVector<JointState> Model::createJointStates(const FBXGeometry& geometry) {
|
||||||
QVector<JointState> jointStates;
|
QVector<JointState> jointStates;
|
||||||
foreach (const FBXJoint& joint, geometry.joints) {
|
foreach (const FBXJoint& joint, geometry.joints) {
|
||||||
JointState state;
|
JointState state;
|
||||||
state.translation = joint.translation;
|
state.setFBXJoint(joint);
|
||||||
state.rotation = joint.rotation;
|
|
||||||
state.animationPriority = 0.0f;
|
|
||||||
jointStates.append(state);
|
jointStates.append(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,23 +158,17 @@ QVector<Model::JointState> Model::createJointStates(const FBXGeometry& geometry)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
JointState& state = jointStates[i];
|
JointState& state = jointStates[i];
|
||||||
const FBXJoint& joint = geometry.joints[i];
|
const FBXJoint& joint = state.getFBXJoint();
|
||||||
int parentIndex = joint.parentIndex;
|
int parentIndex = joint.parentIndex;
|
||||||
if (parentIndex == -1) {
|
if (parentIndex == -1) {
|
||||||
_rootIndex = i;
|
_rootIndex = i;
|
||||||
glm::mat4 baseTransform = glm::mat4_cast(_rotation) * glm::scale(_scale) * glm::translate(_offset);
|
glm::mat4 baseTransform = glm::mat4_cast(_rotation) * glm::scale(_scale) * glm::translate(_offset) * geometry.offset;
|
||||||
glm::quat combinedRotation = joint.preRotation * state.rotation * joint.postRotation;
|
state.updateWorldTransform(baseTransform, _rotation);
|
||||||
state.transform = baseTransform * geometry.offset * glm::translate(state.translation) * joint.preTransform *
|
|
||||||
glm::mat4_cast(combinedRotation) * joint.postTransform;
|
|
||||||
state.combinedRotation = _rotation * combinedRotation;
|
|
||||||
++numJointsSet;
|
++numJointsSet;
|
||||||
jointIsSet[i] = true;
|
jointIsSet[i] = true;
|
||||||
} else if (jointIsSet[parentIndex]) {
|
} else if (jointIsSet[parentIndex]) {
|
||||||
const JointState& parentState = jointStates.at(parentIndex);
|
const JointState& parentState = jointStates.at(parentIndex);
|
||||||
glm::quat combinedRotation = joint.preRotation * state.rotation * joint.postRotation;
|
state.updateWorldTransform(parentState._transform, parentState._combinedRotation);
|
||||||
state.transform = parentState.transform * glm::translate(state.translation) * joint.preTransform *
|
|
||||||
glm::mat4_cast(combinedRotation) * joint.postTransform;
|
|
||||||
state.combinedRotation = parentState.combinedRotation * combinedRotation;
|
|
||||||
++numJointsSet;
|
++numJointsSet;
|
||||||
jointIsSet[i] = true;
|
jointIsSet[i] = true;
|
||||||
}
|
}
|
||||||
|
@ -372,7 +364,7 @@ void Model::reset() {
|
||||||
}
|
}
|
||||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
for (int i = 0; i < _jointStates.size(); i++) {
|
for (int i = 0; i < _jointStates.size(); i++) {
|
||||||
_jointStates[i].rotation = geometry.joints.at(i).rotation;
|
_jointStates[i]._rotation = geometry.joints.at(i).rotation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,7 +574,7 @@ bool Model::getJointState(int index, glm::quat& rotation) const {
|
||||||
if (index == -1 || index >= _jointStates.size()) {
|
if (index == -1 || index >= _jointStates.size()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
rotation = _jointStates.at(index).rotation;
|
rotation = _jointStates.at(index)._rotation;
|
||||||
const glm::quat& defaultRotation = _geometry->getFBXGeometry().joints.at(index).rotation;
|
const glm::quat& defaultRotation = _geometry->getFBXGeometry().joints.at(index).rotation;
|
||||||
return glm::abs(rotation.x - defaultRotation.x) >= EPSILON ||
|
return glm::abs(rotation.x - defaultRotation.x) >= EPSILON ||
|
||||||
glm::abs(rotation.y - defaultRotation.y) >= EPSILON ||
|
glm::abs(rotation.y - defaultRotation.y) >= EPSILON ||
|
||||||
|
@ -593,13 +585,13 @@ bool Model::getJointState(int index, glm::quat& rotation) const {
|
||||||
void Model::setJointState(int index, bool valid, const glm::quat& rotation, float priority) {
|
void Model::setJointState(int index, bool valid, const glm::quat& rotation, float priority) {
|
||||||
if (index != -1 && index < _jointStates.size()) {
|
if (index != -1 && index < _jointStates.size()) {
|
||||||
JointState& state = _jointStates[index];
|
JointState& state = _jointStates[index];
|
||||||
if (priority >= state.animationPriority) {
|
if (priority >= state._animationPriority) {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
state.rotation = rotation;
|
state._rotation = rotation;
|
||||||
state.animationPriority = priority;
|
state._animationPriority = priority;
|
||||||
} else if (priority == state.animationPriority) {
|
} else if (priority == state._animationPriority) {
|
||||||
state.rotation = _geometry->getFBXGeometry().joints.at(index).rotation;
|
state._rotation = _geometry->getFBXGeometry().joints.at(index).rotation;
|
||||||
state.animationPriority = 0.0f;
|
state._animationPriority = 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -632,7 +624,7 @@ bool Model::getJointPosition(int jointIndex, glm::vec3& position) const {
|
||||||
if (jointIndex == -1 || _jointStates.isEmpty()) {
|
if (jointIndex == -1 || _jointStates.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
position = _translation + extractTranslation(_jointStates[jointIndex].transform);
|
position = _translation + extractTranslation(_jointStates[jointIndex]._transform);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -640,7 +632,7 @@ bool Model::getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind)
|
||||||
if (jointIndex == -1 || _jointStates.isEmpty()) {
|
if (jointIndex == -1 || _jointStates.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
rotation = _jointStates[jointIndex].combinedRotation *
|
rotation = _jointStates[jointIndex]._combinedRotation *
|
||||||
(fromBind ? _geometry->getFBXGeometry().joints[jointIndex].inverseBindRotation :
|
(fromBind ? _geometry->getFBXGeometry().joints[jointIndex].inverseBindRotation :
|
||||||
_geometry->getFBXGeometry().joints[jointIndex].inverseDefaultRotation);
|
_geometry->getFBXGeometry().joints[jointIndex].inverseDefaultRotation);
|
||||||
return true;
|
return true;
|
||||||
|
@ -858,11 +850,11 @@ void Model::updateShapePositions() {
|
||||||
for (int i = 0; i < _jointStates.size(); i++) {
|
for (int i = 0; i < _jointStates.size(); i++) {
|
||||||
const FBXJoint& joint = geometry.joints[i];
|
const FBXJoint& joint = geometry.joints[i];
|
||||||
// shape position and rotation need to be in world-frame
|
// shape position and rotation need to be in world-frame
|
||||||
glm::vec3 jointToShapeOffset = uniformScale * (_jointStates[i].combinedRotation * joint.shapePosition);
|
glm::vec3 jointToShapeOffset = uniformScale * (_jointStates[i]._combinedRotation * joint.shapePosition);
|
||||||
glm::vec3 worldPosition = extractTranslation(_jointStates[i].transform) + jointToShapeOffset + _translation;
|
glm::vec3 worldPosition = extractTranslation(_jointStates[i]._transform) + jointToShapeOffset + _translation;
|
||||||
Shape* shape = _jointShapes[i];
|
Shape* shape = _jointShapes[i];
|
||||||
shape->setPosition(worldPosition);
|
shape->setPosition(worldPosition);
|
||||||
shape->setRotation(_jointStates[i].combinedRotation * joint.shapeRotation);
|
shape->setRotation(_jointStates[i]._combinedRotation * joint.shapeRotation);
|
||||||
float distance = glm::distance(worldPosition, _translation) + shape->getBoundingRadius();
|
float distance = glm::distance(worldPosition, _translation) + shape->getBoundingRadius();
|
||||||
if (distance > _boundingRadius) {
|
if (distance > _boundingRadius) {
|
||||||
_boundingRadius = distance;
|
_boundingRadius = distance;
|
||||||
|
@ -884,12 +876,12 @@ bool Model::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct
|
||||||
float radiusScale = extractUniformScale(_scale);
|
float radiusScale = extractUniformScale(_scale);
|
||||||
for (int i = 0; i < _jointStates.size(); i++) {
|
for (int i = 0; i < _jointStates.size(); i++) {
|
||||||
const FBXJoint& joint = geometry.joints[i];
|
const FBXJoint& joint = geometry.joints[i];
|
||||||
glm::vec3 end = extractTranslation(_jointStates[i].transform);
|
glm::vec3 end = extractTranslation(_jointStates[i]._transform);
|
||||||
float endRadius = joint.boneRadius * radiusScale;
|
float endRadius = joint.boneRadius * radiusScale;
|
||||||
glm::vec3 start = end;
|
glm::vec3 start = end;
|
||||||
float startRadius = joint.boneRadius * radiusScale;
|
float startRadius = joint.boneRadius * radiusScale;
|
||||||
if (joint.parentIndex != -1) {
|
if (joint.parentIndex != -1) {
|
||||||
start = extractTranslation(_jointStates[joint.parentIndex].transform);
|
start = extractTranslation(_jointStates[joint.parentIndex]._transform);
|
||||||
startRadius = geometry.joints[joint.parentIndex].boneRadius * radiusScale;
|
startRadius = geometry.joints[joint.parentIndex].boneRadius * radiusScale;
|
||||||
}
|
}
|
||||||
// for now, use average of start and end radii
|
// for now, use average of start and end radii
|
||||||
|
@ -1115,7 +1107,7 @@ void Model::simulateInternal(float deltaTime) {
|
||||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||||
for (int j = 0; j < mesh.clusters.size(); j++) {
|
for (int j = 0; j < mesh.clusters.size(); j++) {
|
||||||
const FBXCluster& cluster = mesh.clusters.at(j);
|
const FBXCluster& cluster = mesh.clusters.at(j);
|
||||||
state.clusterMatrices[j] = _jointStates[cluster.jointIndex].transform * cluster.inverseBindMatrix;
|
state.clusterMatrices[j] = _jointStates[cluster.jointIndex]._transform * cluster.inverseBindMatrix;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1127,21 +1119,15 @@ void Model::simulateInternal(float deltaTime) {
|
||||||
|
|
||||||
void Model::updateJointState(int index) {
|
void Model::updateJointState(int index) {
|
||||||
JointState& state = _jointStates[index];
|
JointState& state = _jointStates[index];
|
||||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
const FBXJoint& joint = state.getFBXJoint();
|
||||||
const FBXJoint& joint = geometry.joints.at(index);
|
|
||||||
|
|
||||||
if (joint.parentIndex == -1) {
|
if (joint.parentIndex == -1) {
|
||||||
glm::mat4 baseTransform = glm::mat4_cast(_rotation) * glm::scale(_scale) * glm::translate(_offset);
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
glm::quat combinedRotation = joint.preRotation * state.rotation * joint.postRotation;
|
glm::mat4 baseTransform = glm::mat4_cast(_rotation) * glm::scale(_scale) * glm::translate(_offset) * geometry.offset;
|
||||||
state.transform = baseTransform * geometry.offset * glm::translate(state.translation) * joint.preTransform *
|
state.updateWorldTransform(baseTransform, _rotation);
|
||||||
glm::mat4_cast(combinedRotation) * joint.postTransform;
|
|
||||||
state.combinedRotation = _rotation * combinedRotation;
|
|
||||||
} else {
|
} else {
|
||||||
const JointState& parentState = _jointStates.at(joint.parentIndex);
|
const JointState& parentState = _jointStates.at(joint.parentIndex);
|
||||||
glm::quat combinedRotation = joint.preRotation * state.rotation * joint.postRotation;
|
state.updateWorldTransform(parentState._transform, parentState._combinedRotation);
|
||||||
state.transform = parentState.transform * glm::translate(state.translation) * joint.preTransform *
|
|
||||||
glm::mat4_cast(combinedRotation) * joint.postTransform;
|
|
||||||
state.combinedRotation = parentState.combinedRotation * combinedRotation;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1169,22 +1155,22 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const
|
||||||
glm::quat endRotation;
|
glm::quat endRotation;
|
||||||
if (useRotation) {
|
if (useRotation) {
|
||||||
getJointRotation(jointIndex, endRotation, true);
|
getJointRotation(jointIndex, endRotation, true);
|
||||||
applyRotationDelta(jointIndex, rotation * glm::inverse(endRotation), priority);
|
applyRotationDelta(jointIndex, rotation * glm::inverse(endRotation), true, priority);
|
||||||
getJointRotation(jointIndex, endRotation, true);
|
getJointRotation(jointIndex, endRotation, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// then, we go from the joint upwards, rotating the end as close as possible to the target
|
// then, we go from the joint upwards, rotating the end as close as possible to the target
|
||||||
glm::vec3 endPosition = extractTranslation(_jointStates[jointIndex].transform);
|
glm::vec3 endPosition = extractTranslation(_jointStates[jointIndex]._transform);
|
||||||
for (int j = 1; freeLineage.at(j - 1) != lastFreeIndex; j++) {
|
for (int j = 1; freeLineage.at(j - 1) != lastFreeIndex; j++) {
|
||||||
int index = freeLineage.at(j);
|
int index = freeLineage.at(j);
|
||||||
const FBXJoint& joint = geometry.joints.at(index);
|
JointState& state = _jointStates[index];
|
||||||
|
const FBXJoint& joint = state.getFBXJoint();
|
||||||
if (!(joint.isFree || allIntermediatesFree)) {
|
if (!(joint.isFree || allIntermediatesFree)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
JointState& state = _jointStates[index];
|
glm::vec3 jointPosition = extractTranslation(state._transform);
|
||||||
glm::vec3 jointPosition = extractTranslation(state.transform);
|
|
||||||
glm::vec3 jointVector = endPosition - jointPosition;
|
glm::vec3 jointVector = endPosition - jointPosition;
|
||||||
glm::quat oldCombinedRotation = state.combinedRotation;
|
glm::quat oldCombinedRotation = state._combinedRotation;
|
||||||
glm::quat combinedDelta;
|
glm::quat combinedDelta;
|
||||||
float combinedWeight;
|
float combinedWeight;
|
||||||
if (useRotation) {
|
if (useRotation) {
|
||||||
|
@ -1202,7 +1188,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const
|
||||||
for (int k = j - 1; k > 0; k--) {
|
for (int k = j - 1; k > 0; k--) {
|
||||||
int index = freeLineage.at(k);
|
int index = freeLineage.at(k);
|
||||||
updateJointState(index);
|
updateJointState(index);
|
||||||
positionSum += extractTranslation(_jointStates.at(index).transform);
|
positionSum += extractTranslation(_jointStates.at(index)._transform);
|
||||||
}
|
}
|
||||||
glm::vec3 projectedCenterOfMass = glm::cross(jointVector,
|
glm::vec3 projectedCenterOfMass = glm::cross(jointVector,
|
||||||
glm::cross(positionSum / (j - 1.0f) - jointPosition, jointVector));
|
glm::cross(positionSum / (j - 1.0f) - jointPosition, jointVector));
|
||||||
|
@ -1213,8 +1199,8 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const
|
||||||
1.0f / (combinedWeight + 1.0f));
|
1.0f / (combinedWeight + 1.0f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
applyRotationDelta(index, combinedDelta, priority);
|
applyRotationDelta(index, combinedDelta, true, priority);
|
||||||
glm::quat actualDelta = state.combinedRotation * glm::inverse(oldCombinedRotation);
|
glm::quat actualDelta = state._combinedRotation * glm::inverse(oldCombinedRotation);
|
||||||
endPosition = actualDelta * jointVector + jointPosition;
|
endPosition = actualDelta * jointVector + jointPosition;
|
||||||
if (useRotation) {
|
if (useRotation) {
|
||||||
endRotation = actualDelta * endRotation;
|
endRotation = actualDelta * endRotation;
|
||||||
|
@ -1231,35 +1217,34 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Model::setJointRotation(int jointIndex, const glm::quat& rotation, bool fromBind, float priority) {
|
bool Model::setJointRotation(int jointIndex, const glm::quat& rotation, float priority) {
|
||||||
if (jointIndex == -1 || _jointStates.isEmpty()) {
|
if (jointIndex == -1 || _jointStates.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
JointState& state = _jointStates[jointIndex];
|
JointState& state = _jointStates[jointIndex];
|
||||||
if (priority >= state.animationPriority) {
|
if (priority >= state._animationPriority) {
|
||||||
state.rotation = state.rotation * glm::inverse(state.combinedRotation) * rotation *
|
state._rotation = state._rotation * glm::inverse(state._combinedRotation) * rotation *
|
||||||
glm::inverse(fromBind ? _geometry->getFBXGeometry().joints.at(jointIndex).inverseBindRotation :
|
glm::inverse(_geometry->getFBXGeometry().joints.at(jointIndex).inverseBindRotation);
|
||||||
_geometry->getFBXGeometry().joints.at(jointIndex).inverseDefaultRotation);
|
state._animationPriority = priority;
|
||||||
state.animationPriority = priority;
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::setJointTranslation(int jointIndex, const glm::vec3& translation) {
|
void Model::setJointTranslation(int jointIndex, const glm::vec3& translation) {
|
||||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
JointState& state = _jointStates[jointIndex];
|
||||||
const FBXJoint& joint = geometry.joints.at(jointIndex);
|
const FBXJoint& joint = state.getFBXJoint();
|
||||||
|
|
||||||
glm::mat4 parentTransform;
|
glm::mat4 parentTransform;
|
||||||
if (joint.parentIndex == -1) {
|
if (joint.parentIndex == -1) {
|
||||||
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
parentTransform = glm::mat4_cast(_rotation) * glm::scale(_scale) * glm::translate(_offset) * geometry.offset;
|
parentTransform = glm::mat4_cast(_rotation) * glm::scale(_scale) * glm::translate(_offset) * geometry.offset;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
parentTransform = _jointStates.at(joint.parentIndex).transform;
|
parentTransform = _jointStates.at(joint.parentIndex)._transform;
|
||||||
}
|
}
|
||||||
JointState& state = _jointStates[jointIndex];
|
|
||||||
glm::vec3 preTranslation = extractTranslation(joint.preTransform * glm::mat4_cast(joint.preRotation *
|
glm::vec3 preTranslation = extractTranslation(joint.preTransform * glm::mat4_cast(joint.preRotation *
|
||||||
state.rotation * joint.postRotation) * joint.postTransform);
|
state._rotation * joint.postRotation) * joint.postTransform);
|
||||||
state.translation = glm::vec3(glm::inverse(parentTransform) * glm::vec4(translation, 1.0f)) - preTranslation;
|
state._translation = glm::vec3(glm::inverse(parentTransform) * glm::vec4(translation, 1.0f)) - preTranslation;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Model::restoreJointPosition(int jointIndex, float percent, float priority) {
|
bool Model::restoreJointPosition(int jointIndex, float percent, float priority) {
|
||||||
|
@ -1271,11 +1256,11 @@ bool Model::restoreJointPosition(int jointIndex, float percent, float priority)
|
||||||
|
|
||||||
foreach (int index, freeLineage) {
|
foreach (int index, freeLineage) {
|
||||||
JointState& state = _jointStates[index];
|
JointState& state = _jointStates[index];
|
||||||
if (priority == state.animationPriority) {
|
if (priority == state._animationPriority) {
|
||||||
const FBXJoint& joint = geometry.joints.at(index);
|
const FBXJoint& joint = geometry.joints.at(index);
|
||||||
state.rotation = safeMix(state.rotation, joint.rotation, percent);
|
state._rotation = safeMix(state._rotation, joint.rotation, percent);
|
||||||
state.translation = glm::mix(state.translation, joint.translation, percent);
|
state._translation = glm::mix(state._translation, joint.translation, percent);
|
||||||
state.animationPriority = 0.0f;
|
state._animationPriority = 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1297,23 +1282,23 @@ float Model::getLimbLength(int jointIndex) const {
|
||||||
|
|
||||||
void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain, float priority) {
|
void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain, float priority) {
|
||||||
JointState& state = _jointStates[jointIndex];
|
JointState& state = _jointStates[jointIndex];
|
||||||
if (priority < state.animationPriority) {
|
if (priority < state._animationPriority) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state.animationPriority = priority;
|
state._animationPriority = priority;
|
||||||
const FBXJoint& joint = _geometry->getFBXGeometry().joints[jointIndex];
|
const FBXJoint& joint = state.getFBXJoint();
|
||||||
if (!constrain || (joint.rotationMin == glm::vec3(-PI, -PI, -PI) &&
|
if (!constrain || (joint.rotationMin == glm::vec3(-PI, -PI, -PI) &&
|
||||||
joint.rotationMax == glm::vec3(PI, PI, PI))) {
|
joint.rotationMax == glm::vec3(PI, PI, PI))) {
|
||||||
// no constraints
|
// no constraints
|
||||||
state.rotation = state.rotation * glm::inverse(state.combinedRotation) * delta * state.combinedRotation;
|
state._rotation = state._rotation * glm::inverse(state._combinedRotation) * delta * state._combinedRotation;
|
||||||
state.combinedRotation = delta * state.combinedRotation;
|
state._combinedRotation = delta * state._combinedRotation;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
glm::quat targetRotation = delta * state.combinedRotation;
|
glm::quat targetRotation = delta * state._combinedRotation;
|
||||||
glm::vec3 eulers = safeEulerAngles(state.rotation * glm::inverse(state.combinedRotation) * targetRotation);
|
glm::vec3 eulers = safeEulerAngles(state._rotation * glm::inverse(state._combinedRotation) * targetRotation);
|
||||||
glm::quat newRotation = glm::quat(glm::clamp(eulers, joint.rotationMin, joint.rotationMax));
|
glm::quat newRotation = glm::quat(glm::clamp(eulers, joint.rotationMin, joint.rotationMax));
|
||||||
state.combinedRotation = state.combinedRotation * glm::inverse(state.rotation) * newRotation;
|
state._combinedRotation = state._combinedRotation * glm::inverse(state._rotation) * newRotation;
|
||||||
state.rotation = newRotation;
|
state._rotation = newRotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int BALL_SUBDIVISIONS = 10;
|
const int BALL_SUBDIVISIONS = 10;
|
||||||
|
@ -1851,10 +1836,10 @@ void AnimationHandle::simulate(float deltaTime) {
|
||||||
for (int i = 0; i < _jointMappings.size(); i++) {
|
for (int i = 0; i < _jointMappings.size(); i++) {
|
||||||
int mapping = _jointMappings.at(i);
|
int mapping = _jointMappings.at(i);
|
||||||
if (mapping != -1) {
|
if (mapping != -1) {
|
||||||
Model::JointState& state = _model->_jointStates[mapping];
|
JointState& state = _model->_jointStates[mapping];
|
||||||
if (_priority >= state.animationPriority) {
|
if (_priority >= state._animationPriority) {
|
||||||
state.rotation = frame.rotations.at(i);
|
state._rotation = frame.rotations.at(i);
|
||||||
state.animationPriority = _priority;
|
state._animationPriority = _priority;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1875,10 +1860,10 @@ void AnimationHandle::simulate(float deltaTime) {
|
||||||
for (int i = 0; i < _jointMappings.size(); i++) {
|
for (int i = 0; i < _jointMappings.size(); i++) {
|
||||||
int mapping = _jointMappings.at(i);
|
int mapping = _jointMappings.at(i);
|
||||||
if (mapping != -1) {
|
if (mapping != -1) {
|
||||||
Model::JointState& state = _model->_jointStates[mapping];
|
JointState& state = _model->_jointStates[mapping];
|
||||||
if (_priority >= state.animationPriority) {
|
if (_priority >= state._animationPriority) {
|
||||||
state.rotation = safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction);
|
state._rotation = safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction);
|
||||||
state.animationPriority = _priority;
|
state._animationPriority = _priority;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1888,10 +1873,32 @@ void AnimationHandle::replaceMatchingPriorities(float newPriority) {
|
||||||
for (int i = 0; i < _jointMappings.size(); i++) {
|
for (int i = 0; i < _jointMappings.size(); i++) {
|
||||||
int mapping = _jointMappings.at(i);
|
int mapping = _jointMappings.at(i);
|
||||||
if (mapping != -1) {
|
if (mapping != -1) {
|
||||||
Model::JointState& state = _model->_jointStates[mapping];
|
JointState& state = _model->_jointStates[mapping];
|
||||||
if (_priority == state.animationPriority) {
|
if (_priority == state._animationPriority) {
|
||||||
state.animationPriority = newPriority;
|
state._animationPriority = newPriority;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// JointState TODO: move this class to its own files
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
JointState::JointState() :
|
||||||
|
_translation(0.0f),
|
||||||
|
_animationPriority(0.0f),
|
||||||
|
_fbxJoint(NULL) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void JointState::setFBXJoint(const FBXJoint& joint) {
|
||||||
|
assert(&joint != NULL);
|
||||||
|
_translation = joint.translation;
|
||||||
|
_rotation = joint.rotation;
|
||||||
|
_fbxJoint = &joint;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JointState::updateWorldTransform(const glm::mat4& baseTransform, const glm::quat& parentRotation) {
|
||||||
|
glm::quat combinedRotation = _fbxJoint->preRotation * _rotation * _fbxJoint->postRotation;
|
||||||
|
_transform = baseTransform * glm::translate(_translation) * _fbxJoint->preTransform * glm::mat4_cast(combinedRotation) * _fbxJoint->postTransform;
|
||||||
|
_combinedRotation = parentRotation * combinedRotation;
|
||||||
|
}
|
||||||
|
|
|
@ -30,6 +30,25 @@ class Shape;
|
||||||
|
|
||||||
typedef QSharedPointer<AnimationHandle> AnimationHandlePointer;
|
typedef QSharedPointer<AnimationHandle> AnimationHandlePointer;
|
||||||
typedef QWeakPointer<AnimationHandle> WeakAnimationHandlePointer;
|
typedef QWeakPointer<AnimationHandle> WeakAnimationHandlePointer;
|
||||||
|
|
||||||
|
class JointState {
|
||||||
|
public:
|
||||||
|
JointState();
|
||||||
|
|
||||||
|
void setFBXJoint(const FBXJoint& joint);
|
||||||
|
const FBXJoint& getFBXJoint() const { return *_fbxJoint; }
|
||||||
|
|
||||||
|
void updateWorldTransform(const glm::mat4& baseTransform, const glm::quat& parentRotation);
|
||||||
|
|
||||||
|
glm::vec3 _translation; // translation relative to parent
|
||||||
|
glm::quat _rotation; // rotation relative to parent
|
||||||
|
glm::mat4 _transform; // rotation to world frame + translation in model frame
|
||||||
|
glm::quat _combinedRotation; // rotation from joint local to world frame
|
||||||
|
float _animationPriority; // the priority of the animation affecting this joint
|
||||||
|
|
||||||
|
private:
|
||||||
|
const FBXJoint* _fbxJoint; // JointState does not own its FBXJoint
|
||||||
|
};
|
||||||
|
|
||||||
/// A generic 3D model displaying geometry loaded from a URL.
|
/// A generic 3D model displaying geometry loaded from a URL.
|
||||||
class Model : public QObject {
|
class Model : public QObject {
|
||||||
|
@ -182,15 +201,6 @@ protected:
|
||||||
bool _snappedToCenter; /// are we currently snapped to center
|
bool _snappedToCenter; /// are we currently snapped to center
|
||||||
int _rootIndex;
|
int _rootIndex;
|
||||||
|
|
||||||
class JointState {
|
|
||||||
public:
|
|
||||||
glm::vec3 translation; // translation relative to parent
|
|
||||||
glm::quat rotation; // rotation relative to parent
|
|
||||||
glm::mat4 transform; // rotation to world frame + translation in model frame
|
|
||||||
glm::quat combinedRotation; // rotation from joint local to world frame
|
|
||||||
float animationPriority; // the priority of the animation affecting this joint
|
|
||||||
};
|
|
||||||
|
|
||||||
bool _shapesAreDirty;
|
bool _shapesAreDirty;
|
||||||
QVector<JointState> _jointStates;
|
QVector<JointState> _jointStates;
|
||||||
QVector<Shape*> _jointShapes;
|
QVector<Shape*> _jointShapes;
|
||||||
|
@ -221,7 +231,7 @@ protected:
|
||||||
bool setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat& rotation = glm::quat(),
|
bool setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat& rotation = glm::quat(),
|
||||||
bool useRotation = false, int lastFreeIndex = -1, bool allIntermediatesFree = false,
|
bool useRotation = false, int lastFreeIndex = -1, bool allIntermediatesFree = false,
|
||||||
const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f), float priority = 1.0f);
|
const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f), float priority = 1.0f);
|
||||||
bool setJointRotation(int jointIndex, const glm::quat& rotation, bool fromBind = false, float priority = 1.0f);
|
bool setJointRotation(int jointIndex, const glm::quat& rotation, float priority = 1.0f);
|
||||||
|
|
||||||
void setJointTranslation(int jointIndex, const glm::vec3& translation);
|
void setJointTranslation(int jointIndex, const glm::vec3& translation);
|
||||||
|
|
||||||
|
|
343
interface/src/ui/ApplicationOverlay.cpp
Normal file
343
interface/src/ui/ApplicationOverlay.cpp
Normal file
|
@ -0,0 +1,343 @@
|
||||||
|
//
|
||||||
|
// ApplicationOverlay.cpp
|
||||||
|
// interface/src/ui/overlays
|
||||||
|
//
|
||||||
|
// Created by Benjamin Arnold on 5/27/14.
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "InterfaceConfig.h"
|
||||||
|
|
||||||
|
#include <QOpenGLFramebufferObject>
|
||||||
|
#include <PerfStat.h>
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include "ApplicationOverlay.h"
|
||||||
|
|
||||||
|
#include "ui/Stats.h"
|
||||||
|
|
||||||
|
ApplicationOverlay::ApplicationOverlay() : _framebufferObject(NULL) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplicationOverlay::~ApplicationOverlay() {
|
||||||
|
if (_framebufferObject != NULL) {
|
||||||
|
delete _framebufferObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f };
|
||||||
|
|
||||||
|
// Renders the overlays either to a texture or to the screen
|
||||||
|
void ApplicationOverlay::renderOverlay(bool renderToTexture) {
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");
|
||||||
|
|
||||||
|
Application* application = Application::getInstance();
|
||||||
|
|
||||||
|
Overlays& overlays = application->getOverlays();
|
||||||
|
QGLWidget* glWidget = application->getGLWidget();
|
||||||
|
MyAvatar* myAvatar = application->getAvatar();
|
||||||
|
Audio* audio = application->getAudio();
|
||||||
|
const VoxelPacketProcessor& voxelPacketProcessor = application->getVoxelPacketProcessor();
|
||||||
|
BandwidthMeter* bandwidthMeter = application->getBandwidthMeter();
|
||||||
|
NodeBounds& nodeBoundsDisplay = application->getNodeBoundsDisplay();
|
||||||
|
|
||||||
|
if (renderToTexture) {
|
||||||
|
getFramebufferObject()->bind();
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
// Render 2D overlay: I/O level bar graphs and text
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glPushMatrix();
|
||||||
|
|
||||||
|
glLoadIdentity();
|
||||||
|
gluOrtho2D(0, glWidget->width(), glWidget->height(), 0);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
|
||||||
|
// Display a single screen-size quad to create an alpha blended 'collision' flash
|
||||||
|
if (audio->getCollisionFlashesScreen()) {
|
||||||
|
float collisionSoundMagnitude = audio->getCollisionSoundMagnitude();
|
||||||
|
const float VISIBLE_COLLISION_SOUND_MAGNITUDE = 0.5f;
|
||||||
|
if (collisionSoundMagnitude > VISIBLE_COLLISION_SOUND_MAGNITUDE) {
|
||||||
|
renderCollisionOverlay(glWidget->width(), glWidget->height(), audio->getCollisionSoundMagnitude());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Audio VU Meter and Mute Icon
|
||||||
|
const int MUTE_ICON_SIZE = 24;
|
||||||
|
const int AUDIO_METER_INSET = 2;
|
||||||
|
const int MUTE_ICON_PADDING = 10;
|
||||||
|
const int AUDIO_METER_WIDTH = MIRROR_VIEW_WIDTH - MUTE_ICON_SIZE - AUDIO_METER_INSET - MUTE_ICON_PADDING;
|
||||||
|
const int AUDIO_METER_SCALE_WIDTH = AUDIO_METER_WIDTH - 2 * AUDIO_METER_INSET;
|
||||||
|
const int AUDIO_METER_HEIGHT = 8;
|
||||||
|
const int AUDIO_METER_GAP = 5;
|
||||||
|
const int AUDIO_METER_X = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_INSET + AUDIO_METER_GAP;
|
||||||
|
|
||||||
|
int audioMeterY;
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
|
||||||
|
audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_GAP + MUTE_ICON_PADDING;
|
||||||
|
} else {
|
||||||
|
audioMeterY = AUDIO_METER_GAP + MUTE_ICON_PADDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float AUDIO_METER_BLUE[] = { 0.0, 0.0, 1.0 };
|
||||||
|
const float AUDIO_METER_GREEN[] = { 0.0, 1.0, 0.0 };
|
||||||
|
const float AUDIO_METER_RED[] = { 1.0, 0.0, 0.0 };
|
||||||
|
const float AUDIO_GREEN_START = 0.25 * AUDIO_METER_SCALE_WIDTH;
|
||||||
|
const float AUDIO_RED_START = 0.80 * AUDIO_METER_SCALE_WIDTH;
|
||||||
|
const float CLIPPING_INDICATOR_TIME = 1.0f;
|
||||||
|
const float AUDIO_METER_AVERAGING = 0.5;
|
||||||
|
const float LOG2 = log(2.f);
|
||||||
|
const float METER_LOUDNESS_SCALE = 2.8f / 5.f;
|
||||||
|
const float LOG2_LOUDNESS_FLOOR = 11.f;
|
||||||
|
float audioLevel = 0.f;
|
||||||
|
float loudness = audio->getLastInputLoudness() + 1.f;
|
||||||
|
|
||||||
|
_trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.f - AUDIO_METER_AVERAGING) * loudness;
|
||||||
|
float log2loudness = log(_trailingAudioLoudness) / LOG2;
|
||||||
|
|
||||||
|
if (log2loudness <= LOG2_LOUDNESS_FLOOR) {
|
||||||
|
audioLevel = (log2loudness / LOG2_LOUDNESS_FLOOR) * METER_LOUDNESS_SCALE * AUDIO_METER_SCALE_WIDTH;
|
||||||
|
} else {
|
||||||
|
audioLevel = (log2loudness - (LOG2_LOUDNESS_FLOOR - 1.f)) * METER_LOUDNESS_SCALE * AUDIO_METER_SCALE_WIDTH;
|
||||||
|
}
|
||||||
|
if (audioLevel > AUDIO_METER_SCALE_WIDTH) {
|
||||||
|
audioLevel = AUDIO_METER_SCALE_WIDTH;
|
||||||
|
}
|
||||||
|
bool isClipping = ((audio->getTimeSinceLastClip() > 0.f) && (audio->getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME));
|
||||||
|
|
||||||
|
if ((audio->getTimeSinceLastClip() > 0.f) && (audio->getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME)) {
|
||||||
|
const float MAX_MAGNITUDE = 0.7f;
|
||||||
|
float magnitude = MAX_MAGNITUDE * (1 - audio->getTimeSinceLastClip() / CLIPPING_INDICATOR_TIME);
|
||||||
|
renderCollisionOverlay(glWidget->width(), glWidget->height(), magnitude, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
audio->renderToolBox(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP,
|
||||||
|
audioMeterY,
|
||||||
|
Menu::getInstance()->isOptionChecked(MenuOption::Mirror));
|
||||||
|
|
||||||
|
audio->renderScope(glWidget->width(), glWidget->height());
|
||||||
|
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
if (isClipping) {
|
||||||
|
glColor3f(1, 0, 0);
|
||||||
|
} else {
|
||||||
|
glColor3f(0.475f, 0.475f, 0.475f);
|
||||||
|
}
|
||||||
|
|
||||||
|
audioMeterY += AUDIO_METER_HEIGHT;
|
||||||
|
|
||||||
|
glColor3f(0, 0, 0);
|
||||||
|
// Draw audio meter background Quad
|
||||||
|
glVertex2i(AUDIO_METER_X, audioMeterY);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY + AUDIO_METER_HEIGHT);
|
||||||
|
glVertex2i(AUDIO_METER_X, audioMeterY + AUDIO_METER_HEIGHT);
|
||||||
|
|
||||||
|
if (audioLevel > AUDIO_RED_START) {
|
||||||
|
if (!isClipping) {
|
||||||
|
glColor3fv(AUDIO_METER_RED);
|
||||||
|
} else {
|
||||||
|
glColor3f(1, 1, 1);
|
||||||
|
}
|
||||||
|
// Draw Red Quad
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_RED_START, audioMeterY + AUDIO_METER_INSET);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_RED_START, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||||
|
audioLevel = AUDIO_RED_START;
|
||||||
|
}
|
||||||
|
if (audioLevel > AUDIO_GREEN_START) {
|
||||||
|
if (!isClipping) {
|
||||||
|
glColor3fv(AUDIO_METER_GREEN);
|
||||||
|
} else {
|
||||||
|
glColor3f(1, 1, 1);
|
||||||
|
}
|
||||||
|
// Draw Green Quad
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_GREEN_START, audioMeterY + AUDIO_METER_INSET);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_GREEN_START, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||||
|
audioLevel = AUDIO_GREEN_START;
|
||||||
|
}
|
||||||
|
// Draw Blue Quad
|
||||||
|
if (!isClipping) {
|
||||||
|
glColor3fv(AUDIO_METER_BLUE);
|
||||||
|
} else {
|
||||||
|
glColor3f(1, 1, 1);
|
||||||
|
}
|
||||||
|
// Draw Blue (low level) quad
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, audioMeterY + AUDIO_METER_INSET);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) {
|
||||||
|
myAvatar->renderHeadMouse(glWidget->width(), glWidget->height());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display stats and log text onscreen
|
||||||
|
glLineWidth(1.0f);
|
||||||
|
glPointSize(1.0f);
|
||||||
|
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
|
||||||
|
// let's set horizontal offset to give stats some margin to mirror
|
||||||
|
int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2;
|
||||||
|
int voxelPacketsToProcess = voxelPacketProcessor.packetsToProcessCount();
|
||||||
|
// Onscreen text about position, servers, etc
|
||||||
|
Stats::getInstance()->display(WHITE_TEXT, horizontalOffset, application->getFps(), application->getPacketsPerSecond(), application->getBytesPerSecond(), voxelPacketsToProcess);
|
||||||
|
// Bandwidth meter
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) {
|
||||||
|
Stats::drawBackground(0x33333399, glWidget->width() - 296, glWidget->height() - 68, 296, 68);
|
||||||
|
bandwidthMeter->render(glWidget->width(), glWidget->height());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show on-screen msec timer
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::FrameTimer)) {
|
||||||
|
char frameTimer[10];
|
||||||
|
quint64 mSecsNow = floor(usecTimestampNow() / 1000.0 + 0.5);
|
||||||
|
sprintf(frameTimer, "%d\n", (int)(mSecsNow % 1000));
|
||||||
|
int timerBottom =
|
||||||
|
(Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
|
||||||
|
Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth))
|
||||||
|
? 80 : 20;
|
||||||
|
drawText(glWidget->width() - 100, glWidget->height() - timerBottom, 0.30f, 0.0f, 0, frameTimer, WHITE_TEXT);
|
||||||
|
}
|
||||||
|
nodeBoundsDisplay.drawOverlay();
|
||||||
|
|
||||||
|
// give external parties a change to hook in
|
||||||
|
emit application->renderingOverlay();
|
||||||
|
|
||||||
|
overlays.render2D();
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glEnable(GL_LIGHTING);
|
||||||
|
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||||
|
|
||||||
|
|
||||||
|
if (renderToTexture) {
|
||||||
|
getFramebufferObject()->release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draws the FBO texture for the screen
|
||||||
|
void ApplicationOverlay::displayOverlayTexture(Camera& whichCamera) {
|
||||||
|
|
||||||
|
Application* application = Application::getInstance();
|
||||||
|
QGLWidget* glWidget = application->getGLWidget();
|
||||||
|
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, getFramebufferObject()->texture());
|
||||||
|
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glPushMatrix();
|
||||||
|
|
||||||
|
glLoadIdentity();
|
||||||
|
gluOrtho2D(0, glWidget->width(), glWidget->height(), 0);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
glTexCoord2f(0, 0); glVertex2i(0, glWidget->height());
|
||||||
|
glTexCoord2f(1, 0); glVertex2i(glWidget->width(), glWidget->height());
|
||||||
|
glTexCoord2f(1, 1); glVertex2i(glWidget->width(), 0);
|
||||||
|
glTexCoord2f(0, 1); glVertex2i(0, 0);
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draws the FBO texture for Oculus rift. TODO: Draw a curved texture instead of plane.
|
||||||
|
void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
|
||||||
|
|
||||||
|
Application* application = Application::getInstance();
|
||||||
|
|
||||||
|
QGLWidget* glWidget = application->getGLWidget();
|
||||||
|
MyAvatar* myAvatar = application->getAvatar();
|
||||||
|
const glm::vec3& viewMatrixTranslation = application->getViewMatrixTranslation();
|
||||||
|
|
||||||
|
// Calculates the world space width and height of the texture based on a desired FOV
|
||||||
|
const float overlayFov = whichCamera.getFieldOfView() * PI / 180.0f;
|
||||||
|
const float overlayDistance = 1;
|
||||||
|
const float overlayAspectRatio = glWidget->width() / (float)glWidget->height();
|
||||||
|
const float overlayHeight = overlayDistance * tan(overlayFov);
|
||||||
|
const float overlayWidth = overlayHeight * overlayAspectRatio;
|
||||||
|
const float halfOverlayWidth = overlayWidth / 2;
|
||||||
|
const float halfOverlayHeight = overlayHeight / 2;
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, getFramebufferObject()->texture());
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
|
||||||
|
glPushMatrix();
|
||||||
|
glLoadIdentity();
|
||||||
|
// Transform to world space
|
||||||
|
glm::quat rotation = whichCamera.getRotation();
|
||||||
|
glm::vec3 axis2 = glm::axis(rotation);
|
||||||
|
glRotatef(-glm::degrees(glm::angle(rotation)), axis2.x, axis2.y, axis2.z);
|
||||||
|
glTranslatef(viewMatrixTranslation.x, viewMatrixTranslation.y, viewMatrixTranslation.z);
|
||||||
|
|
||||||
|
// Translate to the front of the camera
|
||||||
|
glm::vec3 pos = whichCamera.getPosition();
|
||||||
|
glm::quat rot = myAvatar->getOrientation();
|
||||||
|
glm::vec3 axis = glm::axis(rot);
|
||||||
|
pos += rot * glm::vec3(0.0, 0.0, -overlayDistance);
|
||||||
|
|
||||||
|
glTranslatef(pos.x, pos.y, pos.z);
|
||||||
|
glRotatef(glm::degrees(glm::angle(rot)), axis.x, axis.y, axis.z);
|
||||||
|
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
glTexCoord2f(1, 0); glVertex3f(-halfOverlayWidth, halfOverlayHeight, 0);
|
||||||
|
glTexCoord2f(0, 0); glVertex3f(halfOverlayWidth, halfOverlayHeight, 0);
|
||||||
|
glTexCoord2f(0, 1); glVertex3f(halfOverlayWidth, -halfOverlayHeight, 0);
|
||||||
|
glTexCoord2f(1, 1); glVertex3f(-halfOverlayWidth, -halfOverlayHeight, 0);
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||||
|
glEnable(GL_LIGHTING);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QOpenGLFramebufferObject* ApplicationOverlay::getFramebufferObject() {
|
||||||
|
if (!_framebufferObject) {
|
||||||
|
_framebufferObject = new QOpenGLFramebufferObject(Application::getInstance()->getGLWidget()->size());
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, _framebufferObject->texture());
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
return _framebufferObject;
|
||||||
|
}
|
||||||
|
|
38
interface/src/ui/ApplicationOverlay.h
Normal file
38
interface/src/ui/ApplicationOverlay.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
//
|
||||||
|
// ApplicationOverlay.h
|
||||||
|
// interface/src/ui/overlays
|
||||||
|
//
|
||||||
|
// Created by Benjamin Arnold on 5/27/14.
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_ApplicationOverlay_h
|
||||||
|
#define hifi_ApplicationOverlay_h
|
||||||
|
|
||||||
|
class Overlays;
|
||||||
|
class QOpenGLFramebufferObject;
|
||||||
|
|
||||||
|
// Handles the drawing of the overlays to the scree
|
||||||
|
class ApplicationOverlay {
|
||||||
|
public:
|
||||||
|
|
||||||
|
ApplicationOverlay();
|
||||||
|
~ApplicationOverlay();
|
||||||
|
|
||||||
|
void renderOverlay(bool renderToTexture = false);
|
||||||
|
void displayOverlayTexture(Camera& whichCamera);
|
||||||
|
void displayOverlayTextureOculus(Camera& whichCamera);
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
QOpenGLFramebufferObject* getFramebufferObject();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
QOpenGLFramebufferObject* _framebufferObject;
|
||||||
|
float _trailingAudioLoudness;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_ApplicationOverlay_h
|
229
interface/src/ui/JSConsole.cpp
Normal file
229
interface/src/ui/JSConsole.cpp
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
//
|
||||||
|
// JSConsole.cpp
|
||||||
|
// interface/src/ui
|
||||||
|
//
|
||||||
|
// Created by Ryan Huffman on 05/12/14.
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QScrollBar>
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include "ScriptHighlighting.h"
|
||||||
|
|
||||||
|
#include "JSConsole.h"
|
||||||
|
|
||||||
|
const int NO_CURRENT_HISTORY_COMMAND = -1;
|
||||||
|
const int MAX_HISTORY_SIZE = 64;
|
||||||
|
|
||||||
|
const QString COMMAND_STYLE = "color: #266a9b;";
|
||||||
|
|
||||||
|
const QString RESULT_SUCCESS_STYLE = "color: #677373;";
|
||||||
|
const QString RESULT_ERROR_STYLE = "color: #d13b22;";
|
||||||
|
|
||||||
|
const QString GUTTER_PREVIOUS_COMMAND = "<span style=\"color: #57b8bb;\"><</span>";
|
||||||
|
const QString GUTTER_ERROR = "<span style=\"color: #d13b22;\">X</span>";
|
||||||
|
|
||||||
|
JSConsole::JSConsole(QWidget* parent, ScriptEngine* scriptEngine) :
|
||||||
|
QWidget(parent),
|
||||||
|
_ui(new Ui::Console),
|
||||||
|
_currentCommandInHistory(NO_CURRENT_HISTORY_COMMAND),
|
||||||
|
_commandHistory(),
|
||||||
|
_scriptEngine(scriptEngine) {
|
||||||
|
|
||||||
|
_ui->setupUi(this);
|
||||||
|
_ui->promptTextEdit->setLineWrapMode(QTextEdit::NoWrap);
|
||||||
|
_ui->promptTextEdit->setWordWrapMode(QTextOption::NoWrap);
|
||||||
|
_ui->promptTextEdit->installEventFilter(this);
|
||||||
|
|
||||||
|
QFile styleSheet(Application::resourcesPath() + "styles/console.qss");
|
||||||
|
if (styleSheet.open(QIODevice::ReadOnly)) {
|
||||||
|
QDir::setCurrent(Application::resourcesPath());
|
||||||
|
setStyleSheet(styleSheet.readAll());
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(_ui->scrollArea->verticalScrollBar(), SIGNAL(rangeChanged(int, int)), this, SLOT(scrollToBottom()));
|
||||||
|
connect(_ui->promptTextEdit, SIGNAL(textChanged()), this, SLOT(resizeTextInput()));
|
||||||
|
|
||||||
|
|
||||||
|
if (_scriptEngine == NULL) {
|
||||||
|
_scriptEngine = Application::getInstance()->loadScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(_scriptEngine, SIGNAL(evaluationFinished(QScriptValue, bool)),
|
||||||
|
this, SLOT(handleEvalutationFinished(QScriptValue, bool)));
|
||||||
|
connect(_scriptEngine, SIGNAL(printedMessage(const QString&)), this, SLOT(handlePrint(const QString&)));
|
||||||
|
|
||||||
|
resizeTextInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
JSConsole::~JSConsole() {
|
||||||
|
delete _ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSConsole::executeCommand(const QString& command) {
|
||||||
|
_commandHistory.prepend(command);
|
||||||
|
if (_commandHistory.length() > MAX_HISTORY_SIZE) {
|
||||||
|
_commandHistory.removeLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
_ui->promptTextEdit->setDisabled(true);
|
||||||
|
|
||||||
|
appendMessage(">", "<span style='" + COMMAND_STYLE + "'>" + command.toHtmlEscaped() + "</span>");
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod(_scriptEngine, "evaluate", Q_ARG(const QString&, command));
|
||||||
|
|
||||||
|
resetCurrentCommandHistory();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSConsole::handleEvalutationFinished(QScriptValue result, bool isException) {
|
||||||
|
_ui->promptTextEdit->setDisabled(false);
|
||||||
|
|
||||||
|
// Make sure focus is still on this window - some commands are blocking and can take awhile to execute.
|
||||||
|
if (window()->isActiveWindow()) {
|
||||||
|
_ui->promptTextEdit->setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString gutter = (isException || result.isError()) ? GUTTER_ERROR : GUTTER_PREVIOUS_COMMAND;
|
||||||
|
QString resultColor = (isException || result.isError()) ? RESULT_ERROR_STYLE : RESULT_SUCCESS_STYLE;
|
||||||
|
QString resultStr = "<span style='" + resultColor + "'>" + result.toString().toHtmlEscaped() + "</span>";
|
||||||
|
appendMessage(gutter, resultStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSConsole::handlePrint(const QString& message) {
|
||||||
|
appendMessage("", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSConsole::mouseReleaseEvent(QMouseEvent* event) {
|
||||||
|
_ui->promptTextEdit->setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSConsole::showEvent(QShowEvent* event) {
|
||||||
|
_ui->promptTextEdit->setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JSConsole::eventFilter(QObject* sender, QEvent* event) {
|
||||||
|
if (sender == _ui->promptTextEdit) {
|
||||||
|
if (event->type() == QEvent::KeyPress) {
|
||||||
|
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||||
|
int key = keyEvent->key();
|
||||||
|
|
||||||
|
if ((key == Qt::Key_Return || key == Qt::Key_Enter)) {
|
||||||
|
if (keyEvent->modifiers() & Qt::ShiftModifier) {
|
||||||
|
// If the shift key is being used then treat it as a regular return/enter. If this isn't done,
|
||||||
|
// a new QTextBlock isn't created.
|
||||||
|
keyEvent->setModifiers(keyEvent->modifiers() & ~Qt::ShiftModifier);
|
||||||
|
} else {
|
||||||
|
QString command = _ui->promptTextEdit->toPlainText().trimmed();
|
||||||
|
|
||||||
|
if (!command.isEmpty()) {
|
||||||
|
QTextCursor cursor = _ui->promptTextEdit->textCursor();
|
||||||
|
_ui->promptTextEdit->clear();
|
||||||
|
|
||||||
|
executeCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (key == Qt::Key_Down) {
|
||||||
|
// Go to the next command in history if the cursor is at the last line of the current command.
|
||||||
|
int blockNumber = _ui->promptTextEdit->textCursor().blockNumber();
|
||||||
|
int blockCount = _ui->promptTextEdit->document()->blockCount();
|
||||||
|
if (blockNumber == blockCount - 1) {
|
||||||
|
setToNextCommandInHistory();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (key == Qt::Key_Up) {
|
||||||
|
// Go to the previous command in history if the cursor is at the first line of the current command.
|
||||||
|
int blockNumber = _ui->promptTextEdit->textCursor().blockNumber();
|
||||||
|
if (blockNumber == 0) {
|
||||||
|
setToPreviousCommandInHistory();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSConsole::setToNextCommandInHistory() {
|
||||||
|
if (_currentCommandInHistory >= 0) {
|
||||||
|
_currentCommandInHistory--;
|
||||||
|
if (_currentCommandInHistory == NO_CURRENT_HISTORY_COMMAND) {
|
||||||
|
setAndSelectCommand(_rootCommand);
|
||||||
|
} else {
|
||||||
|
setAndSelectCommand(_commandHistory[_currentCommandInHistory]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSConsole::setToPreviousCommandInHistory() {
|
||||||
|
if (_currentCommandInHistory < (_commandHistory.length() - 1)) {
|
||||||
|
if (_currentCommandInHistory == NO_CURRENT_HISTORY_COMMAND) {
|
||||||
|
_rootCommand = _ui->promptTextEdit->toPlainText();
|
||||||
|
}
|
||||||
|
_currentCommandInHistory++;
|
||||||
|
setAndSelectCommand(_commandHistory[_currentCommandInHistory]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSConsole::resetCurrentCommandHistory() {
|
||||||
|
_currentCommandInHistory = NO_CURRENT_HISTORY_COMMAND;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSConsole::resizeTextInput() {
|
||||||
|
_ui->promptTextEdit->setFixedHeight(_ui->promptTextEdit->document()->size().height());
|
||||||
|
_ui->promptTextEdit->updateGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSConsole::setAndSelectCommand(const QString& text) {
|
||||||
|
QTextCursor cursor = _ui->promptTextEdit->textCursor();
|
||||||
|
cursor.select(QTextCursor::Document);
|
||||||
|
cursor.deleteChar();
|
||||||
|
cursor.insertText(text);
|
||||||
|
cursor.movePosition(QTextCursor::End);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSConsole::scrollToBottom() {
|
||||||
|
QScrollBar* scrollBar = _ui->scrollArea->verticalScrollBar();
|
||||||
|
scrollBar->setValue(scrollBar->maximum());
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSConsole::appendMessage(const QString& gutter, const QString& message) {
|
||||||
|
QWidget* logLine = new QWidget(_ui->logArea);
|
||||||
|
QHBoxLayout* layout = new QHBoxLayout(logLine);
|
||||||
|
layout->setMargin(0);
|
||||||
|
layout->setSpacing(4);
|
||||||
|
|
||||||
|
QLabel* gutterLabel = new QLabel(logLine);
|
||||||
|
QLabel* messageLabel = new QLabel(logLine);
|
||||||
|
|
||||||
|
gutterLabel->setFixedWidth(16);
|
||||||
|
gutterLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||||
|
messageLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||||
|
|
||||||
|
gutterLabel->setStyleSheet("font-size: 14px; font-family: Inconsolata, Lucida Console, Andale Mono, Monaco;");
|
||||||
|
messageLabel->setStyleSheet("font-size: 14px; font-family: Inconsolata, Lucida Console, Andale Mono, Monaco;");
|
||||||
|
|
||||||
|
gutterLabel->setText(gutter);
|
||||||
|
messageLabel->setText(message);
|
||||||
|
|
||||||
|
layout->addWidget(gutterLabel);
|
||||||
|
layout->addWidget(messageLabel);
|
||||||
|
logLine->setLayout(layout);
|
||||||
|
|
||||||
|
layout->setAlignment(gutterLabel, Qt::AlignTop);
|
||||||
|
|
||||||
|
layout->setStretch(0, 0);
|
||||||
|
layout->setStretch(1, 1);
|
||||||
|
|
||||||
|
_ui->logArea->layout()->addWidget(logLine);
|
||||||
|
|
||||||
|
_ui->logArea->updateGeometry();
|
||||||
|
scrollToBottom();
|
||||||
|
}
|
62
interface/src/ui/JSConsole.h
Normal file
62
interface/src/ui/JSConsole.h
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
//
|
||||||
|
// JSConsole.h
|
||||||
|
// interface/src/ui
|
||||||
|
//
|
||||||
|
// Created by Ryan Huffman on 05/12/14.
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_JSConsole_h
|
||||||
|
#define hifi_JSConsole_h
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include "ui_console.h"
|
||||||
|
#include "ScriptEngine.h"
|
||||||
|
|
||||||
|
class JSConsole : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
JSConsole(QWidget* parent, ScriptEngine* scriptEngine = NULL);
|
||||||
|
~JSConsole();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void executeCommand(const QString& command);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void commandExecuting(const QString& command);
|
||||||
|
void commandFinished(const QString& result);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void setAndSelectCommand(const QString& command);
|
||||||
|
virtual bool eventFilter(QObject* sender, QEvent* event);
|
||||||
|
virtual void mouseReleaseEvent(QMouseEvent* event);
|
||||||
|
virtual void showEvent(QShowEvent* event);
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
void scrollToBottom();
|
||||||
|
void resizeTextInput();
|
||||||
|
void handleEvalutationFinished(QScriptValue result, bool isException);
|
||||||
|
void handlePrint(const QString& message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void appendMessage(const QString& gutter, const QString& message);
|
||||||
|
void setToNextCommandInHistory();
|
||||||
|
void setToPreviousCommandInHistory();
|
||||||
|
void resetCurrentCommandHistory();
|
||||||
|
|
||||||
|
Ui::Console* _ui;
|
||||||
|
int _currentCommandInHistory;
|
||||||
|
QList<QString> _commandHistory;
|
||||||
|
QString _rootCommand;
|
||||||
|
ScriptEngine* _scriptEngine;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // hifi_JSConsole_h
|
|
@ -29,6 +29,8 @@ PreferencesDialog::PreferencesDialog(QWidget* parent, Qt::WindowFlags flags) : F
|
||||||
connect(ui.buttonBrowseHead, &QPushButton::clicked, this, &PreferencesDialog::openHeadModelBrowser);
|
connect(ui.buttonBrowseHead, &QPushButton::clicked, this, &PreferencesDialog::openHeadModelBrowser);
|
||||||
connect(ui.buttonBrowseBody, &QPushButton::clicked, this, &PreferencesDialog::openBodyModelBrowser);
|
connect(ui.buttonBrowseBody, &QPushButton::clicked, this, &PreferencesDialog::openBodyModelBrowser);
|
||||||
connect(ui.buttonBrowseLocation, &QPushButton::clicked, this, &PreferencesDialog::openSnapshotLocationBrowser);
|
connect(ui.buttonBrowseLocation, &QPushButton::clicked, this, &PreferencesDialog::openSnapshotLocationBrowser);
|
||||||
|
connect(ui.buttonReloadDefaultScripts, &QPushButton::clicked,
|
||||||
|
Application::getInstance(), &Application::loadDefaultScripts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreferencesDialog::accept() {
|
void PreferencesDialog::accept() {
|
||||||
|
|
|
@ -27,6 +27,9 @@
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "FlowLayout.h"
|
#include "FlowLayout.h"
|
||||||
|
#include "JSConsole.h"
|
||||||
|
|
||||||
|
const int CONSOLE_HEIGHT = 150;
|
||||||
|
|
||||||
ScriptEditorWindow::ScriptEditorWindow() :
|
ScriptEditorWindow::ScriptEditorWindow() :
|
||||||
_ScriptEditorWindowUI(new Ui::ScriptEditorWindow),
|
_ScriptEditorWindowUI(new Ui::ScriptEditorWindow),
|
||||||
|
@ -48,6 +51,10 @@ ScriptEditorWindow::ScriptEditorWindow() :
|
||||||
connect(new QShortcut(QKeySequence("Ctrl+S"), this), &QShortcut::activated, this,&ScriptEditorWindow::saveScriptClicked);
|
connect(new QShortcut(QKeySequence("Ctrl+S"), this), &QShortcut::activated, this,&ScriptEditorWindow::saveScriptClicked);
|
||||||
connect(new QShortcut(QKeySequence("Ctrl+O"), this), &QShortcut::activated, this, &ScriptEditorWindow::loadScriptClicked);
|
connect(new QShortcut(QKeySequence("Ctrl+O"), this), &QShortcut::activated, this, &ScriptEditorWindow::loadScriptClicked);
|
||||||
connect(new QShortcut(QKeySequence("F5"), this), &QShortcut::activated, this, &ScriptEditorWindow::toggleRunScriptClicked);
|
connect(new QShortcut(QKeySequence("F5"), this), &QShortcut::activated, this, &ScriptEditorWindow::toggleRunScriptClicked);
|
||||||
|
|
||||||
|
QWidget* console = new JSConsole(this);
|
||||||
|
console->setFixedHeight(CONSOLE_HEIGHT);
|
||||||
|
this->layout()->addWidget(console);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptEditorWindow::~ScriptEditorWindow() {
|
ScriptEditorWindow::~ScriptEditorWindow() {
|
||||||
|
|
258
interface/ui/console.ui
Normal file
258
interface/ui/console.ui
Normal file
|
@ -0,0 +1,258 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Console</class>
|
||||||
|
<widget class="QWidget" name="Console">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1055</width>
|
||||||
|
<height>205</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QDialog { background: white }</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="widget" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QScrollArea" name="scrollArea">
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="verticalScrollBarPolicy">
|
||||||
|
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||||
|
</property>
|
||||||
|
<property name="widgetResizable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1040</width>
|
||||||
|
<height>205</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background-color: white;</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
<item alignment="Qt::AlignTop">
|
||||||
|
<widget class="QWidget" name="widget_2" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="logArea" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background-color: white;</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="inputArea" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,0">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item alignment="Qt::AlignTop">
|
||||||
|
<widget class="QLabel" name="promptGutterLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>16</width>
|
||||||
|
<height>23</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16</width>
|
||||||
|
<height>23</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">padding: 0px 0 0 0;</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>></string>
|
||||||
|
</property>
|
||||||
|
<property name="textFormat">
|
||||||
|
<enum>Qt::PlainText</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="promptTextEdit">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Inconsolata,Lucida Console,Andale Mono,Monaco</family>
|
||||||
|
<pointsize>-1</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="verticalScrollBarPolicy">
|
||||||
|
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||||
|
</property>
|
||||||
|
<property name="horizontalScrollBarPolicy">
|
||||||
|
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -134,8 +134,8 @@ color: #0e7077</string>
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>30</y>
|
<y>30</y>
|
||||||
<width>615</width>
|
<width>494</width>
|
||||||
<height>491</height>
|
<height>384</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="frameShape">
|
<property name="frameShape">
|
||||||
|
@ -154,9 +154,9 @@ color: #0e7077</string>
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>-271</y>
|
<y>-204</y>
|
||||||
<width>598</width>
|
<width>494</width>
|
||||||
<height>1018</height>
|
<height>1091</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
@ -612,6 +612,78 @@ color: #0e7077</string>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="avatarTitleLabel_3">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Arial</family>
|
||||||
|
<pointsize>20</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">color: #0e7077</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Scripts</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="widget" native="true">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonReloadDefaultScripts">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background: #0e7077;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
font: bold 14pt;
|
||||||
|
padding: 10px;margin-top:10px</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Load Default Scripts</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_13">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="verticalSpacer">
|
<spacer name="verticalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <glm/gtx/transform.hpp>
|
||||||
|
|
||||||
#include <FBXReader.h>
|
#include <FBXReader.h>
|
||||||
#include <GeometryUtil.h>
|
#include <GeometryUtil.h>
|
||||||
|
|
||||||
|
@ -177,21 +179,41 @@ bool ModelTreeElement::findDetailedRayIntersection(const glm::vec3& origin, cons
|
||||||
|
|
||||||
extents.minimum *= scale;
|
extents.minimum *= scale;
|
||||||
extents.maximum *= scale;
|
extents.maximum *= scale;
|
||||||
|
|
||||||
calculateRotatedExtents(extents, model.getModelRotation());
|
|
||||||
|
|
||||||
extents.minimum += model.getPosition();
|
|
||||||
extents.maximum += model.getPosition();
|
|
||||||
|
|
||||||
AABox rotatedExtentsBox(extents.minimum, (extents.maximum - extents.minimum));
|
|
||||||
|
|
||||||
|
Extents rotatedExtents = extents;
|
||||||
|
|
||||||
|
calculateRotatedExtents(rotatedExtents, model.getModelRotation());
|
||||||
|
|
||||||
|
rotatedExtents.minimum += model.getPosition();
|
||||||
|
rotatedExtents.maximum += model.getPosition();
|
||||||
|
|
||||||
|
|
||||||
|
AABox rotatedExtentsBox(rotatedExtents.minimum, (rotatedExtents.maximum - rotatedExtents.minimum));
|
||||||
|
|
||||||
|
// if it's in our AABOX for our rotated extents, then check to see if it's in our non-AABox
|
||||||
if (rotatedExtentsBox.findRayIntersection(origin, direction, localDistance, localFace)) {
|
if (rotatedExtentsBox.findRayIntersection(origin, direction, localDistance, localFace)) {
|
||||||
if (localDistance < distance) {
|
|
||||||
distance = localDistance;
|
// extents is the model relative, scaled, centered extents of the model
|
||||||
face = localFace;
|
glm::mat4 rotation = glm::mat4_cast(model.getModelRotation());
|
||||||
*intersectedObject = (void*)(&model);
|
glm::mat4 translation = glm::translate(model.getPosition());
|
||||||
somethingIntersected = true;
|
glm::mat4 modelToWorldMatrix = translation * rotation;
|
||||||
}
|
glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix);
|
||||||
|
|
||||||
|
AABox modelFrameBox(extents.minimum, (extents.maximum - extents.minimum));
|
||||||
|
|
||||||
|
glm::vec3 modelFrameOrigin = glm::vec3(worldToModelMatrix * glm::vec4(origin, 1.0f));
|
||||||
|
glm::vec3 modelFrameDirection = glm::vec3(worldToModelMatrix * glm::vec4(direction, 1.0f));
|
||||||
|
|
||||||
|
// we can use the AABox's ray intersection by mapping our origin and direction into the model frame
|
||||||
|
// and testing intersection there.
|
||||||
|
if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, localDistance, localFace)) {
|
||||||
|
if (localDistance < distance) {
|
||||||
|
distance = localDistance;
|
||||||
|
face = localFace;
|
||||||
|
*intersectedObject = (void*)(&model);
|
||||||
|
somethingIntersected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (localDistance < distance) {
|
} else if (localDistance < distance) {
|
||||||
distance = localDistance;
|
distance = localDistance;
|
||||||
|
|
|
@ -314,6 +314,18 @@ void ScriptEngine::evaluate() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileName, int lineNumber) {
|
||||||
|
QScriptValue result = _engine.evaluate(program, fileName, lineNumber);
|
||||||
|
bool hasUncaughtException = _engine.hasUncaughtException();
|
||||||
|
if (hasUncaughtException) {
|
||||||
|
int line = _engine.uncaughtExceptionLineNumber();
|
||||||
|
qDebug() << "Uncaught exception at line" << line << ": " << result.toString();
|
||||||
|
}
|
||||||
|
emit evaluationFinished(result, hasUncaughtException);
|
||||||
|
_engine.clearExceptions();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void ScriptEngine::sendAvatarIdentityPacket() {
|
void ScriptEngine::sendAvatarIdentityPacket() {
|
||||||
if (_isAvatar && _avatarData) {
|
if (_isAvatar && _avatarData) {
|
||||||
_avatarData->sendIdentityPacket();
|
_avatarData->sendIdentityPacket();
|
||||||
|
|
|
@ -92,6 +92,7 @@ public:
|
||||||
public slots:
|
public slots:
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
|
QScriptValue evaluate(const QString& program, const QString& fileName = QString(), int lineNumber = 1);
|
||||||
QObject* setInterval(const QScriptValue& function, int intervalMS);
|
QObject* setInterval(const QScriptValue& function, int intervalMS);
|
||||||
QObject* setTimeout(const QScriptValue& function, int timeoutMS);
|
QObject* setTimeout(const QScriptValue& function, int timeoutMS);
|
||||||
void clearInterval(QObject* timer) { stopTimer(reinterpret_cast<QTimer*>(timer)); }
|
void clearInterval(QObject* timer) { stopTimer(reinterpret_cast<QTimer*>(timer)); }
|
||||||
|
@ -107,6 +108,7 @@ signals:
|
||||||
void printedMessage(const QString& message);
|
void printedMessage(const QString& message);
|
||||||
void errorMessage(const QString& message);
|
void errorMessage(const QString& message);
|
||||||
void runningStateChanged();
|
void runningStateChanged();
|
||||||
|
void evaluationFinished(QScriptValue result, bool isException);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QString _scriptContents;
|
QString _scriptContents;
|
||||||
|
|
Loading…
Reference in a new issue