merge upstream/master into andrew/thermonuclear

This commit is contained in:
Andrew Meadows 2014-12-02 11:41:29 -08:00
commit ff7559c2c2
41 changed files with 1094 additions and 294 deletions

View file

@ -96,12 +96,13 @@ Currently building on Windows has been tested using the following compilers:
#####Windows SDK 7.1
Whichever version of Visual Studio you use, you will need [Microsoft Windows SDK for Windows 7 and .NET Framework 4](http://www.microsoft.com/en-us/download/details.aspx?id=8279).
If using Visual Studio 2010, or using Visual Studio 2013 but building as a Visual Studio 2010 project, you need [Microsoft Windows SDK for Windows 7 and .NET Framework 4](http://www.microsoft.com/en-us/download/details.aspx?id=8279).
NOTE: If using Visual Studio C++ 2010 Express, you need to follow a specific install order. See below before installing the Windows SDK.
######Windows 8.1
You may have already downloaded the Windows 8 SDK (e.g. if you have previously installed Visual Studio 2013). If so, change CMAKE_PREFIX_PATH in %HIFI_DIR%\CMakeLists.txt to point to the Windows 8 SDK binaries. The default path is `C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86`
######Windows SDK 8.1
If using Visual Studio 2013 and building as a Visual Studio 2013 project you need the Windows 8 SDK which you should already have as part of installing Visual Studio 2013. You should be able to see it at `C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86`.
#####Visual Studio C++ 2010 Express
@ -123,9 +124,11 @@ Some of the build instructions will ask you to start a Visual Studio Command Pro
#####Visual Studio 2013
This product must be purchased separately.
You can use the Community or Professional editions of Visual Studio 2013.
Visual Studio 2013 doesn't have a shortcut to start a Visual Studio Command Prompt. Instead, start a regular command prompt and then run:
You can start a Visual Studio 2013 command prompt using the shortcut provided in the Visual Studio Tools folder installed as part of Visual Studio 2013.
Or you can start a regular command prompt and then run:
"%VS120COMNTOOLS%\vsvars32.bat"
@ -146,6 +149,8 @@ Once Qt is installed, you need to manually configure the following:
* Make sure the Qt runtime DLLs are loadable. You must do this before you attempt to build because some tools for the build depend on Qt. E.g., add to the PATH: `Qt\5.2.0\msvc2010_opengl\bin\`.
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.2.0\msvc2010_opengl` directory.
If building as a Visual Studio 2013 project, download and configure the msvc2013 version of Qt instead.
####External Libraries
CMake will need to know where the headers and libraries for required external dependencies are.

View file

@ -10,6 +10,7 @@
//
#include <QtCore/QProcess>
#include <QtCore/qsharedmemory.h>
#include <QtCore/QThread>
#include <QtCore/QTimer>
@ -38,7 +39,8 @@ int hifiSockAddrMeta = qRegisterMetaType<HifiSockAddr>("HifiSockAddr");
AssignmentClient::AssignmentClient(int &argc, char **argv) :
QCoreApplication(argc, argv),
_shutdownEventListener(this),
_assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME)
_assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME),
_localASPortSharedMem(NULL)
{
LogUtils::init();
@ -89,13 +91,7 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
// create a NodeList as an unassigned client
NodeList* nodeList = NodeList::createInstance(NodeType::Unassigned);
unsigned short assignmentServerPort = DEFAULT_DOMAIN_SERVER_PORT;
// check for an overriden assignment server port
if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION)) {
assignmentServerPort =
argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION).toString().toUInt();
}
quint16 assignmentServerPort = DEFAULT_DOMAIN_SERVER_PORT;
// check for an overriden assignment server hostname
if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION)) {
@ -103,10 +99,16 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
_assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString();
}
HifiSockAddr assignmentServerSocket(_assignmentServerHostname, assignmentServerPort, true);
nodeList->setAssignmentServerSocket(assignmentServerSocket);
// check for an overriden assignment server port
if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION)) {
assignmentServerPort =
argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION).toString().toUInt();
}
_assignmentServerSocket = HifiSockAddr(_assignmentServerHostname, assignmentServerPort, true);
nodeList->setAssignmentServerSocket(_assignmentServerSocket);
qDebug() << "Assignment server socket is" << assignmentServerSocket;
qDebug() << "Assignment server socket is" << _assignmentServerSocket;
// call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required
qDebug() << "Waiting for assignment -" << _requestAssignment;
@ -129,7 +131,40 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
void AssignmentClient::sendAssignmentRequest() {
if (!_currentAssignment) {
NodeList::getInstance()->sendAssignment(_requestAssignment);
NodeList* nodeList = NodeList::getInstance();
if (_assignmentServerHostname == "localhost") {
// we want to check again for the local domain-server port in case the DS has restarted
if (!_localASPortSharedMem) {
_localASPortSharedMem = new QSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, this);
if (!_localASPortSharedMem->attach(QSharedMemory::ReadOnly)) {
qWarning() << "Could not attach to shared memory at key" << DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY
<< "- will attempt to connect to domain-server on" << _assignmentServerSocket.getPort();
}
}
if (_localASPortSharedMem->isAttached()) {
_localASPortSharedMem->lock();
quint16 localAssignmentServerPort;
memcpy(&localAssignmentServerPort, _localASPortSharedMem->data(), sizeof(localAssignmentServerPort));
_localASPortSharedMem->unlock();
if (localAssignmentServerPort != _assignmentServerSocket.getPort()) {
qDebug() << "Port for local assignment server read from shared memory is"
<< localAssignmentServerPort;
_assignmentServerSocket.setPort(localAssignmentServerPort);
nodeList->setAssignmentServerSocket(_assignmentServerSocket);
}
}
}
nodeList->sendAssignment(_requestAssignment);
}
}

View file

@ -17,6 +17,8 @@
#include "ShutdownEventListener.h"
#include "ThreadedAssignment.h"
class QSharedMemory;
class AssignmentClient : public QCoreApplication {
Q_OBJECT
public:
@ -34,6 +36,8 @@ private:
static SharedAssignmentPointer _currentAssignment;
ShutdownEventListener _shutdownEventListener;
QString _assignmentServerHostname;
HifiSockAddr _assignmentServerSocket;
QSharedMemory* _localASPortSharedMem;
};
#endif // hifi_AssignmentClient_h

View file

@ -48,8 +48,13 @@ elseif (UNIX)
select_library_configurations(XINERAMA)
elseif (WIN32)
find_library(LIBOVR_LIBRARY_DEBUG NAMES libovrd PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${LIBOVR_SEARCH_DIRS})
find_library(LIBOVR_LIBRARY_RELEASE NAMES libovr PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${LIBOVR_SEARCH_DIRS})
if (MSVC10)
find_library(LIBOVR_LIBRARY_DEBUG NAMES libovrd PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${LIBOVR_SEARCH_DIRS})
find_library(LIBOVR_LIBRARY_RELEASE NAMES libovr PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${LIBOVR_SEARCH_DIRS})
elseif (MSVC12)
find_library(LIBOVR_LIBRARY_DEBUG NAMES libovrd PATH_SUFFIXES Lib/Win32/VS2013 HINTS ${LIBOVR_SEARCH_DIRS})
find_library(LIBOVR_LIBRARY_RELEASE NAMES libovr PATH_SUFFIXES Lib/Win32/VS2013 HINTS ${LIBOVR_SEARCH_DIRS})
endif ()
find_package(ATL)
endif ()

View file

@ -18,6 +18,7 @@
#include <QtCore/QJsonObject>
#include <QtCore/QJsonArray>
#include <QtCore/QProcess>
#include <QtCore/qsharedmemory.h>
#include <QtCore/QStandardPaths>
#include <QtCore/QTimer>
#include <QtCore/QUrlQuery>
@ -228,6 +229,21 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
LimitedNodeList* nodeList = LimitedNodeList::createInstance(domainServerPort, domainServerDTLSPort);
// no matter the local port, save it to shared mem so that local assignment clients can ask what it is
QSharedMemory* sharedPortMem = new QSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, this);
quint16 localPort = nodeList->getNodeSocket().localPort();
// attempt to create the shared memory segment
if (sharedPortMem->create(sizeof(localPort)) || sharedPortMem->attach()) {
sharedPortMem->lock();
memcpy(sharedPortMem->data(), &localPort, sizeof(localPort));
sharedPortMem->unlock();
qDebug() << "Wrote local listening port" << localPort << "to shared memory at key" << DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY;
} else {
qWarning() << "Failed to create and attach to shared memory to share local port with assignment-client children.";
}
// set our LimitedNodeList UUID to match the UUID from our config
// nodes will currently use this to add resources to data-web that relate to our domain
const QString METAVERSE_DOMAIN_ID_KEY_PATH = "metaverse.id";
@ -321,9 +337,31 @@ bool DomainServer::optionallySetupAssignmentPayment() {
void DomainServer::setupAutomaticNetworking() {
LimitedNodeList* nodeList = LimitedNodeList::getInstance();
const int STUN_REFLEXIVE_KEEPALIVE_INTERVAL_MSECS = 10 * 1000;
const int STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS = 30 * 1000;
// setup our timer to check our IP via stun every X seconds
QTimer* dynamicIPTimer = new QTimer(this);
connect(dynamicIPTimer, &QTimer::timeout, this, &DomainServer::requestCurrentPublicSocketViaSTUN);
if (_automaticNetworkingSetting == FULL_AUTOMATIC_NETWORKING_VALUE) {
dynamicIPTimer->start(STUN_REFLEXIVE_KEEPALIVE_INTERVAL_MSECS);
// setup a timer to heartbeat with the ice-server every so often
QTimer* iceHeartbeatTimer = new QTimer(this);
connect(iceHeartbeatTimer, &QTimer::timeout, this, &DomainServer::performICEUpdates);
iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS);
// call our sendHeartbeaToIceServer immediately anytime a local or public socket changes
connect(nodeList, &LimitedNodeList::localSockAddrChanged, this, &DomainServer::sendHeartbeatToIceServer);
connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendHeartbeatToIceServer);
}
if (!didSetupAccountManagerWithAccessToken()) {
qDebug() << "Cannot setup domain-server automatic networking without an access token.";
qDebug() << "Please add an access token to your config file or via the web interface.";
qDebug() << "Cannot send heartbeat to data server without an access token.";
qDebug() << "Add an access token to your config file or via the web interface.";
return;
}
@ -334,37 +372,18 @@ void DomainServer::setupAutomaticNetworking() {
if (_automaticNetworkingSetting == IP_ONLY_AUTOMATIC_NETWORKING_VALUE ||
_automaticNetworkingSetting == FULL_AUTOMATIC_NETWORKING_VALUE) {
LimitedNodeList* nodeList = LimitedNodeList::getInstance();
const QUuid& domainID = nodeList->getSessionUUID();
if (!domainID.isNull()) {
qDebug() << "domain-server" << _automaticNetworkingSetting << "automatic networking enabled for ID"
<< uuidStringWithoutCurlyBraces(domainID) << "via" << _oauthProviderURL.toString();
const int STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS = 30 * 1000;
const int STUN_REFLEXIVE_KEEPALIVE_INTERVAL_MSECS = 10 * 1000;
// setup our timer to check our IP via stun every X seconds
QTimer* dynamicIPTimer = new QTimer(this);
connect(dynamicIPTimer, &QTimer::timeout, this, &DomainServer::requestCurrentPublicSocketViaSTUN);
if (_automaticNetworkingSetting == IP_ONLY_AUTOMATIC_NETWORKING_VALUE) {
dynamicIPTimer->start(STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS);
// send public socket changes to the data server so nodes can find us at our new IP
connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::performIPAddressUpdate);
} else {
dynamicIPTimer->start(STUN_REFLEXIVE_KEEPALIVE_INTERVAL_MSECS);
// setup a timer to heartbeat with the ice-server every so often
QTimer* iceHeartbeatTimer = new QTimer(this);
connect(iceHeartbeatTimer, &QTimer::timeout, this, &DomainServer::performICEUpdates);
iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS);
// call our sendHeartbeaToIceServer immediately anytime a local or public socket changes
connect(nodeList, &LimitedNodeList::localSockAddrChanged, this, &DomainServer::sendHeartbeatToIceServer);
connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendHeartbeatToIceServer);
// send our heartbeat to data server so it knows what our network settings are
sendHeartbeatToDataServer();
}

View file

@ -0,0 +1,37 @@
//
// developerMenuItems.js
// examples
//
// Created by Brad Hefta-Gaub on 2/24/14
// Copyright 2013 High Fidelity, Inc.
//
// Adds a bunch of developer and debugging menu items
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
function setupMenus() {
if (!Menu.menuExists("Developer")) {
Menu.addMenu("Developer");
}
if (!Menu.menuExists("Developer > Entities")) {
Menu.addMenu("Developer > Entities");
Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Display Model Bounds", isCheckable: true, isChecked: false });
Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Display Model Element Bounds", isCheckable: true, isChecked: false });
Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Display Model Element Children", isCheckable: true, isChecked: false });
Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Disable Light Entities", isCheckable: true, isChecked: false });
Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't Attempt to Reduce Material Switches", isCheckable: true, isChecked: false });
Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't Attempt Render Entities as Scene", isCheckable: true, isChecked: false });
Menu.addMenu("Developer > Entities > Culling");
Menu.addMenuItem({ menuName: "Developer > Entities > Culling", menuItemName: "Don't Cull Out Of View Mesh Parts", isCheckable: true, isChecked: false });
Menu.addMenuItem({ menuName: "Developer > Entities > Culling", menuItemName: "Don't Cull Too Small Mesh Parts", isCheckable: true, isChecked: false });
}
}
function scriptEnding() {
Menu.removeMenu("Developer > Entities");
}
setupMenus();
Script.scriptEnding.connect(scriptEnding);

View file

@ -19,6 +19,7 @@ var warpPosition = { x: 0, y: 0, z: 0 };
var hipsToEyes;
var restoreCountdownTimer;
var headTurningTimer = 0.0;
// Overlays to show target location
@ -168,6 +169,20 @@ function update(deltaTime) {
restoreCountDownTimer = 0.0;
}
}
var HEAD_TURN_TIME = 0.10;
var HEAD_TURN_DEGREES = 4.0;
var HEAD_TURN_START_ANGLE = 45.0;
var currentYaw = MyAvatar.getHeadFinalYaw();
if (Math.abs(currentYaw) > HEAD_TURN_START_ANGLE) {
headTurningTimer += deltaTime;
if (headTurningTimer > HEAD_TURN_TIME) {
headTurningTimer = 0.0;
MyAvatar.orientation = Quat.multiply(Quat.fromPitchYawRollDegrees(0, (currentYaw > 0) ? HEAD_TURN_DEGREES: -HEAD_TURN_DEGREES, 0),
MyAvatar.orientation);
}
} else {
headTurningTimer = 0.0;
}
}
Controller.keyPressEvent.connect(function(event) {

View file

@ -6,7 +6,7 @@
var gridColor = { red: 0, green: 0, blue: 0 };
var gridColors = [
{ red: 0, green: 0, blue: 0 },
{ red: 128, green: 128, blue: 128 },
{ red: 255, green: 255, blue: 255 },
{ red: 255, green: 0, blue: 0 },
{ red: 0, green: 255, blue: 0},
{ red: 0, green: 0, blue: 255 },

View file

@ -471,17 +471,20 @@ var leapHands = (function () {
} else {
hands[h].inactiveCount += 1;
if (hands[h].inactiveCount < MAX_HAND_INACTIVE_COUNT) {
if (hands[h].inactiveCount === MAX_HAND_INACTIVE_COUNT) {
if (h === 0) {
MyAvatar.clearJointData("LeftHand");
MyAvatar.clearJointData("LeftForeArm");
MyAvatar.clearJointData("LeftArm");
} else {
MyAvatar.clearJointData("RightHand");
MyAvatar.clearJointData("RightForeArm");
MyAvatar.clearJointData("RightArm");
hands[h].inactiveCount += 1;
if (hands[h].inactiveCount === MAX_HAND_INACTIVE_COUNT) {
if (h === 0) {
MyAvatar.clearJointData("LeftHand");
MyAvatar.clearJointData("LeftForeArm");
MyAvatar.clearJointData("LeftArm");
} else {
MyAvatar.clearJointData("RightHand");
MyAvatar.clearJointData("RightForeArm");
MyAvatar.clearJointData("RightArm");
}
}
}
}

View file

@ -200,6 +200,13 @@ SelectionManager = (function() {
return that;
})();
// Normalize degrees to be in the range (-180, 180]
function normalizeDegrees(degrees) {
while (degrees > 180) degrees -= 360;
while (degrees <= -180) degrees += 360;
return degrees;
}
SelectionDisplay = (function () {
var that = {};
@ -207,6 +214,12 @@ SelectionDisplay = (function () {
var GRABBER_DISTANCE_TO_SIZE_RATIO = 0.0075;
// These are multipliers for sizing the rotation degrees display while rotating an entity
var ROTATION_DISPLAY_DISTANCE_MULTIPLIER = 1.2;
var ROTATION_DISPLAY_SIZE_X_MULTIPLIER = 0.5;
var ROTATION_DISPLAY_SIZE_Y_MULTIPLIER = 0.18;
var ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER = 0.17;
var showExtendedStretchHandles = false;
var spaceMode = SPACE_LOCAL;
@ -306,7 +319,7 @@ SelectionDisplay = (function () {
var highlightBox = Overlays.addOverlay("cube", {
position: { x:0, y: 0, z: 0},
size: 1,
color: { red: 180, green: 180, blue: 180},
color: { red: 90, green: 90, blue: 90},
alpha: 1,
solid: false,
visible: false,
@ -318,7 +331,7 @@ SelectionDisplay = (function () {
var selectionBox = Overlays.addOverlay("cube", {
position: { x:0, y: 0, z: 0},
size: 1,
color: { red: 180, green: 180, blue: 180},
color: { red: 60, green: 60, blue: 60},
alpha: 1,
solid: false,
visible: false,
@ -326,6 +339,24 @@ SelectionDisplay = (function () {
lineWidth: 1.0,
});
var rotationDegreesDisplay = Overlays.addOverlay("text3d", {
position: { x:0, y: 0, z: 0},
text: "",
color: { red: 0, green: 0, blue: 0},
backgroundColor: { red: 255, green: 255, blue: 255 },
alpha: 0.7,
visible: false,
isFacingAvatar: true,
drawInFront: true,
ignoreRayIntersection: true,
dimensions: { x: 0, y: 0 },
lineHeight: 0.0,
topMargin: 0,
rightMargin: 0,
bottomMargin: 0,
leftMargin: 0,
});
var grabberMoveUp = Overlays.addOverlay("billboard", {
url: HIFI_PUBLIC_BUCKET + "images/up-arrow.png",
position: { x:0, y: 0, z: 0},
@ -585,6 +616,7 @@ SelectionDisplay = (function () {
rotateOverlayCurrent,
rotateZeroOverlay,
rotateCurrentOverlay,
rotationDegreesDisplay,
xRailOverlay,
yRailOverlay,
zRailOverlay,
@ -848,8 +880,8 @@ SelectionDisplay = (function () {
} else {
yawHandleRotation = Quat.fromVec3Degrees({ x: 270, y: 270, z: 0 });
rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 180 });
pitchHandleRotation = Quat.fromVec3Degrees({ x: 180, y: 270, z: 0 });
rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 180 });
yawNormal = { x: 0, y: 1, z: 0 };
rollNormal = { x: 0, y: 0, z: 1 };
@ -1292,7 +1324,11 @@ SelectionDisplay = (function () {
var vec3Mult = function(v1, v2) {
return { x: v1.x * v2.x, y: v1.y * v2.y, z: v1.z * v2.z };
}
var makeStretchTool = function(stretchMode, direction, pivot) {
// stretchMode - name of mode
// direction - direction to stretch in
// pivot - point to use as a pivot
// offset - the position of the overlay tool relative to the selections center position
var makeStretchTool = function(stretchMode, direction, pivot, offset) {
var signs = {
x: direction.x < 0 ? -1 : (direction.x > 0 ? 1 : 0),
y: direction.y < 0 ? -1 : (direction.y > 0 ? 1 : 0),
@ -1313,6 +1349,7 @@ SelectionDisplay = (function () {
var initialDimensions = null;
var initialIntersection = null;
var initialProperties = null;
var pickRayPosition = null;
var rotation = null;
var onBegin = function(event) {
@ -1321,13 +1358,22 @@ SelectionDisplay = (function () {
rotation = spaceMode == SPACE_LOCAL ? properties.rotation : Quat.fromPitchYawRollDegrees(0, 0, 0);
if (spaceMode == SPACE_LOCAL) {
rotation = SelectionManager.localRotation;
initialPosition = SelectionManager.localPosition;
initialDimensions = SelectionManager.localDimensions;
} else {
rotation = SelectionManager.worldRotation;
initialPosition = SelectionManager.worldPosition;
initialDimensions = SelectionManager.worldDimensions;
}
var scaledOffset = {
x: initialDimensions.x * offset.x * 0.5,
y: initialDimensions.y * offset.y * 0.5,
z: initialDimensions.z * offset.z * 0.5,
};
pickRayPosition = Vec3.sum(initialPosition, Vec3.multiplyQbyV(rotation, scaledOffset));
if (numDimensions == 1 && mask.x) {
var start = Vec3.multiplyQbyV(rotation, { x: -10000, y: 0, z: 0 });
start = Vec3.sum(start, properties.position);
@ -1381,7 +1427,7 @@ SelectionDisplay = (function () {
planeNormal = Vec3.multiplyQbyV(rotation, planeNormal);
var pickRay = Camera.computePickRay(event.x, event.y);
lastPick = rayPlaneIntersection(pickRay,
initialPosition,
pickRayPosition,
planeNormal);
// Overlays.editOverlay(normalLine, {
@ -1416,7 +1462,7 @@ SelectionDisplay = (function () {
var pickRay = Camera.computePickRay(event.x, event.y);
newPick = rayPlaneIntersection(pickRay,
initialPosition,
pickRayPosition,
planeNormal);
var vector = Vec3.subtract(newPick, lastPick);
@ -1491,44 +1537,64 @@ SelectionDisplay = (function () {
};
};
function addStretchTool(overlay, mode, pivot, direction) {
function addStretchTool(overlay, mode, pivot, direction, offset) {
if (!pivot) {
pivot = Vec3.multiply(-1, direction);
pivot.y = direction.y;
}
var tool = makeStretchTool(mode, direction, pivot);
var tool = makeStretchTool(mode, direction, pivot, offset);
addGrabberTool(overlay, tool);
}
addStretchTool(grabberNEAR, "STRETCH_NEAR", { x: 0, y: 0, z: -1 }, { x: 0, y: 0, z: 1 });
addStretchTool(grabberFAR, "STRETCH_FAR", { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: -1 });
addStretchTool(grabberTOP, "STRETCH_TOP", { x: 0, y: 1, z: 0 }, { x: 0, y: -1, z: 0 });
addStretchTool(grabberBOTTOM, "STRETCH_BOTTOM", { x: 0, y: -1, z: 0 }, { x: 0, y: 1, z: 0 });
addStretchTool(grabberRIGHT, "STRETCH_RIGHT", { x: 1, y: 0, z: 0 }, { x: -1, y: 0, z: 0 });
addStretchTool(grabberLEFT, "STRETCH_LEFT", { x: -1, y: 0, z: 0 }, { x: 1, y: 0, z: 0 });
addStretchTool(grabberNEAR, "STRETCH_NEAR", { x: 0, y: 0, z: -1 }, { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: -1 });
addStretchTool(grabberFAR, "STRETCH_FAR", { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: -1 }, { x: 0, y: 0, z: 1 });
addStretchTool(grabberTOP, "STRETCH_TOP", { x: 0, y: 1, z: 0 }, { x: 0, y: -1, z: 0 }, { x: 0, y: 1, z: 0 });
addStretchTool(grabberBOTTOM, "STRETCH_BOTTOM", { x: 0, y: -1, z: 0 }, { x: 0, y: 1, z: 0 }, { x: 0, y: -1, z: 0 });
addStretchTool(grabberRIGHT, "STRETCH_RIGHT", { x: 1, y: 0, z: 0 }, { x: -1, y: 0, z: 0 }, { x: 1, y: 0, z: 0 });
addStretchTool(grabberLEFT, "STRETCH_LEFT", { x: -1, y: 0, z: 0 }, { x: 1, y: 0, z: 0 }, { x: -1, y: 0, z: 0 });
addStretchTool(grabberLBN, "STRETCH_LBN", null, {x: 1, y: 0, z: 1});
addStretchTool(grabberRBN, "STRETCH_RBN", null, {x: -1, y: 0, z: 1});
addStretchTool(grabberLBF, "STRETCH_LBF", null, {x: 1, y: 0, z: -1});
addStretchTool(grabberRBF, "STRETCH_RBF", null, {x: -1, y: 0, z: -1});
addStretchTool(grabberLTN, "STRETCH_LTN", null, {x: 1, y: 0, z: 1});
addStretchTool(grabberRTN, "STRETCH_RTN", null, {x: -1, y: 0, z: 1});
addStretchTool(grabberLTF, "STRETCH_LTF", null, {x: 1, y: 0, z: -1});
addStretchTool(grabberRTF, "STRETCH_RTF", null, {x: -1, y: 0, z: -1});
addStretchTool(grabberLBN, "STRETCH_LBN", null, {x: 1, y: 0, z: 1}, { x: -1, y: -1, z: -1 });
addStretchTool(grabberRBN, "STRETCH_RBN", null, {x: -1, y: 0, z: 1}, { x: 1, y: -1, z: -1 });
addStretchTool(grabberLBF, "STRETCH_LBF", null, {x: 1, y: 0, z: -1}, { x: -1, y: -1, z: 1 });
addStretchTool(grabberRBF, "STRETCH_RBF", null, {x: -1, y: 0, z: -1}, { x: 1, y: -1, z: 1 });
addStretchTool(grabberLTN, "STRETCH_LTN", null, {x: 1, y: 0, z: 1}, { x: -1, y: 1, z: -1 });
addStretchTool(grabberRTN, "STRETCH_RTN", null, {x: -1, y: 0, z: 1}, { x: 1, y: 1, z: -1 });
addStretchTool(grabberLTF, "STRETCH_LTF", null, {x: 1, y: 0, z: -1}, { x: -1, y: 1, z: 1 });
addStretchTool(grabberRTF, "STRETCH_RTF", null, {x: -1, y: 0, z: -1}, { x: 1, y: 1, z: 1 });
addStretchTool(grabberEdgeTR, "STRETCH_EdgeTR", null, {x: 1, y: 1, z: 0});
addStretchTool(grabberEdgeTL, "STRETCH_EdgeTL", null, {x: -1, y: 1, z: 0});
addStretchTool(grabberEdgeTF, "STRETCH_EdgeTF", null, {x: 0, y: 1, z: -1});
addStretchTool(grabberEdgeTN, "STRETCH_EdgeTN", null, {x: 0, y: 1, z: 1});
addStretchTool(grabberEdgeBR, "STRETCH_EdgeBR", null, {x: -1, y: 0, z: 0});
addStretchTool(grabberEdgeBL, "STRETCH_EdgeBL", null, {x: 1, y: 0, z: 0});
addStretchTool(grabberEdgeBF, "STRETCH_EdgeBF", null, {x: 0, y: 0, z: -1});
addStretchTool(grabberEdgeBN, "STRETCH_EdgeBN", null, {x: 0, y: 0, z: 1});
addStretchTool(grabberEdgeNR, "STRETCH_EdgeNR", null, {x: -1, y: 0, z: 1});
addStretchTool(grabberEdgeNL, "STRETCH_EdgeNL", null, {x: 1, y: 0, z: 1});
addStretchTool(grabberEdgeFR, "STRETCH_EdgeFR", null, {x: -1, y: 0, z: -1});
addStretchTool(grabberEdgeFL, "STRETCH_EdgeFL", null, {x: 1, y: 0, z: -1});
addStretchTool(grabberEdgeTR, "STRETCH_EdgeTR", null, {x: 1, y: 1, z: 0}, { x: 1, y: 1, z: 0 });
addStretchTool(grabberEdgeTL, "STRETCH_EdgeTL", null, {x: -1, y: 1, z: 0}, { x: -1, y: 1, z: 0 });
addStretchTool(grabberEdgeTF, "STRETCH_EdgeTF", null, {x: 0, y: 1, z: -1}, { x: 0, y: 1, z: -1 });
addStretchTool(grabberEdgeTN, "STRETCH_EdgeTN", null, {x: 0, y: 1, z: 1}, { x: 0, y: 1, z: 1 });
addStretchTool(grabberEdgeBR, "STRETCH_EdgeBR", null, {x: -1, y: 0, z: 0}, { x: 1, y: -1, z: 0 });
addStretchTool(grabberEdgeBL, "STRETCH_EdgeBL", null, {x: 1, y: 0, z: 0}, { x: -1, y: -1, z: 0 });
addStretchTool(grabberEdgeBF, "STRETCH_EdgeBF", null, {x: 0, y: 0, z: -1}, { x: 0, y: -1, z: -1 });
addStretchTool(grabberEdgeBN, "STRETCH_EdgeBN", null, {x: 0, y: 0, z: 1}, { x: 0, y: -1, z: 1 });
addStretchTool(grabberEdgeNR, "STRETCH_EdgeNR", null, {x: -1, y: 0, z: 1}, { x: 1, y: 0, z: -1 });
addStretchTool(grabberEdgeNL, "STRETCH_EdgeNL", null, {x: 1, y: 0, z: 1}, { x: -1, y: 0, z: -1 });
addStretchTool(grabberEdgeFR, "STRETCH_EdgeFR", null, {x: -1, y: 0, z: -1}, { x: 1, y: 0, z: 1 });
addStretchTool(grabberEdgeFL, "STRETCH_EdgeFL", null, {x: 1, y: 0, z: -1}, { x: -1, y: 0, z: 1 });
function updateRotationDegreesOverlay(angleFromZero, handleRotation, centerPosition) {
var angle = angleFromZero * (Math.PI / 180);
var position = {
x: Math.cos(angle) * outerRadius * ROTATION_DISPLAY_DISTANCE_MULTIPLIER,
y: Math.sin(angle) * outerRadius * ROTATION_DISPLAY_DISTANCE_MULTIPLIER,
z: 0,
};
position = Vec3.multiplyQbyV(handleRotation, position);
position = Vec3.sum(centerPosition, position);
Overlays.editOverlay(rotationDegreesDisplay, {
position: position,
dimensions: {
x: innerRadius * ROTATION_DISPLAY_SIZE_X_MULTIPLIER,
y: innerRadius * ROTATION_DISPLAY_SIZE_Y_MULTIPLIER
},
lineHeight: innerRadius * ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER,
text: normalizeDegrees(angleFromZero),
});
}
var initialPosition = SelectionManager.worldPosition;
addGrabberTool(yawHandle, {
@ -1570,11 +1636,18 @@ SelectionDisplay = (function () {
endAt: 0,
innerRadius: 0.9,
});
Overlays.editOverlay(rotationDegreesDisplay, {
visible: true,
});
updateRotationDegreesOverlay(0, yawHandleRotation, yawCenter);
},
onEnd: function(event, reason) {
Overlays.editOverlay(rotateOverlayInner, { visible: false });
Overlays.editOverlay(rotateOverlayOuter, { visible: false });
Overlays.editOverlay(rotateOverlayCurrent, { visible: false });
Overlays.editOverlay(rotationDegreesDisplay, { visible: false });
pushCommandForSelections();
},
@ -1605,12 +1678,9 @@ SelectionDisplay = (function () {
var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal);
var distanceFromCenter = Vec3.distance(center, result.intersection);
var snapToInner = false;
// var innerRadius = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1;
if (distanceFromCenter < innerRadius) {
angleFromZero = Math.floor(angleFromZero/innerSnapAngle) * innerSnapAngle;
snapToInner = true;
}
var snapToInner = distanceFromCenter < innerRadius;
var snapAngle = snapToInner ? innerSnapAngle : 1.0;
angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle;
// for debugging
if (debug) {
@ -1632,7 +1702,9 @@ SelectionDisplay = (function () {
rotation: Quat.multiply(yawChange, initialProperties.rotation),
});
}
updateRotationDegreesOverlay(angleFromZero, yawHandleRotation, yawCenter);
// update the rotation display accordingly...
var startAtCurrent = 0;
var endAtCurrent = angleFromZero;
@ -1701,11 +1773,18 @@ SelectionDisplay = (function () {
endAt: 0,
innerRadius: 0.9,
});
Overlays.editOverlay(rotationDegreesDisplay, {
visible: true,
});
updateRotationDegreesOverlay(0, pitchHandleRotation, pitchCenter);
},
onEnd: function(event, reason) {
Overlays.editOverlay(rotateOverlayInner, { visible: false });
Overlays.editOverlay(rotateOverlayOuter, { visible: false });
Overlays.editOverlay(rotateOverlayCurrent, { visible: false });
Overlays.editOverlay(rotationDegreesDisplay, { visible: false });
pushCommandForSelections();
},
@ -1736,11 +1815,9 @@ SelectionDisplay = (function () {
var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal);
var distanceFromCenter = Vec3.distance(center, result.intersection);
var snapToInner = false;
if (distanceFromCenter < innerRadius) {
angleFromZero = Math.floor(angleFromZero/innerSnapAngle) * innerSnapAngle;
snapToInner = true;
}
var snapToInner = distanceFromCenter < innerRadius;
var snapAngle = snapToInner ? innerSnapAngle : 1.0;
angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle;
// for debugging
if (debug) {
@ -1764,6 +1841,8 @@ SelectionDisplay = (function () {
});
}
updateRotationDegreesOverlay(angleFromZero, pitchHandleRotation, pitchCenter);
// update the rotation display accordingly...
var startAtCurrent = 0;
var endAtCurrent = angleFromZero;
@ -1831,11 +1910,18 @@ SelectionDisplay = (function () {
endAt: 0,
innerRadius: 0.9,
});
Overlays.editOverlay(rotationDegreesDisplay, {
visible: true,
});
updateRotationDegreesOverlay(0, rollHandleRotation, rollCenter);
},
onEnd: function(event, reason) {
Overlays.editOverlay(rotateOverlayInner, { visible: false });
Overlays.editOverlay(rotateOverlayOuter, { visible: false });
Overlays.editOverlay(rotateOverlayCurrent, { visible: false });
Overlays.editOverlay(rotationDegreesDisplay, { visible: false });
pushCommandForSelections();
},
@ -1866,11 +1952,9 @@ SelectionDisplay = (function () {
var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal);
var distanceFromCenter = Vec3.distance(center, result.intersection);
var snapToInner = false;
if (distanceFromCenter < innerRadius) {
angleFromZero = Math.floor(angleFromZero/innerSnapAngle) * innerSnapAngle;
snapToInner = true;
}
var snapToInner = distanceFromCenter < innerRadius;
var snapAngle = snapToInner ? innerSnapAngle : 1.0;
angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle;
// for debugging
if (debug) {
@ -1893,6 +1977,8 @@ SelectionDisplay = (function () {
});
}
updateRotationDegreesOverlay(angleFromZero, rollHandleRotation, rollCenter);
// update the rotation display accordingly...
var startAtCurrent = 0;
var endAtCurrent = angleFromZero;

View file

@ -36,25 +36,36 @@ uniform vec2 depthTexCoordOffset;
uniform vec2 depthTexCoordScale;
void main(void) {
float depthVal = texture2D(depthMap, gl_TexCoord[0].st).r;
vec4 normalVal = texture2D(normalMap, gl_TexCoord[0].st);
vec4 diffuseVal = texture2D(diffuseMap, gl_TexCoord[0].st);
vec4 specularVal = texture2D(specularMap, gl_TexCoord[0].st);
// compute the view space position using the depth
float z = near / (texture2D(depthMap, gl_TexCoord[0].st).r * depthScale - 1.0);
float z = near / (depthVal * depthScale - 1.0);
vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 0.0);
// get the normal from the map
vec4 normal = texture2D(normalMap, gl_TexCoord[0].st);
vec4 normalizedNormal = normalize(normal * 2.0 - vec4(1.0, 1.0, 1.0, 2.0));
// compute the base color based on OpenGL lighting model
float diffuse = dot(normalizedNormal, gl_LightSource[0].position);
float facingLight = step(0.0, diffuse);
vec4 baseColor = texture2D(diffuseMap, gl_TexCoord[0].st) * (gl_FrontLightModelProduct.sceneColor +
gl_FrontLightProduct[0].ambient + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
// compute the specular multiplier (sans exponent)
float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - normalize(position)),
normalizedNormal));
// add specular contribution
vec4 specularColor = texture2D(specularMap, gl_TexCoord[0].st);
gl_FragColor = vec4(baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb, normal.a);
vec4 normal = normalVal;
if ((normalVal.a >= 0.45) && (normalVal.a <= 0.55)) {
normal.a = 1.0;
normalVal.a = 0.0;
gl_FragColor = vec4(diffuseVal.rgb * specularVal.rgb, 1.0);
} else {
vec3 normalizedNormal = normalize(normal.xyz * 2.0 - vec3(1.0));
// compute the base color based on OpenGL lighting model
float diffuse = dot(normalizedNormal, gl_LightSource[0].position.xyz);
float facingLight = step(0.0, diffuse);
vec3 baseColor = diffuseVal.rgb * (gl_FrontLightModelProduct.sceneColor.rgb +
gl_FrontLightProduct[0].ambient.rgb + gl_FrontLightProduct[0].diffuse.rgb * (diffuse * facingLight));
// compute the specular multiplier (sans exponent)
float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position.xyz - normalize(position.xyz)),
normalizedNormal));
// add specular contribution
vec4 specularColor = specularVal;
gl_FragColor = vec4(baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb, normal.a);
}
}

View file

@ -31,7 +31,7 @@ void main(void) {
// set the diffuse, normal, specular data
vec4 diffuse = texture2D(diffuseMap, gl_TexCoord[0].st);
vec4 emissive = texture2D(emissiveMap, interpolatedTexcoord1.st);
gl_FragData[0] = vec4(gl_Color.rgb * diffuse.rgb * (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb), mix(gl_Color.a, 1.0 - gl_Color.a, step(diffuse.a, alphaThreshold)));
gl_FragData[1] = normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
gl_FragData[2] = vec4(gl_FrontMaterial.specular.rgb, gl_FrontMaterial.shininess / 128.0);
gl_FragData[0] = vec4(gl_Color.rgb * diffuse.rgb, mix(gl_Color.a, 1.0 - gl_Color.a, step(diffuse.a, alphaThreshold)));
gl_FragData[1] = normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 0.5);
gl_FragData[2] = vec4((vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb), gl_FrontMaterial.shininess / 128.0);
}

View file

@ -4,7 +4,7 @@
// model_normal_map.frag
// fragment shader
//
// Created by Andrzej Kapolka on 10/14/13.
// Created by Andrzej Kapolka on 10/29/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.

View file

@ -438,6 +438,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
void Application::aboutToQuit() {
_aboutToQuit = true;
setFullscreen(false); // if you exit while in full screen, you'll get bad behavior when you restart.
}
Application::~Application() {
@ -651,20 +652,11 @@ void Application::paintGL() {
}
} else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
//Only behave like a true mirror when in the OR
if (OculusManager::isConnected()) {
_myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
_myCamera.setPosition(_myAvatar->getHead()->getEyePosition() +
glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0) +
(_myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) *
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
} else {
_myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
_myCamera.setPosition(_myAvatar->getHead()->getEyePosition() +
glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0) +
(_myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) *
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
}
_myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
_myCamera.setPosition(_myAvatar->getDefaultEyePosition() +
glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0) +
(_myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) *
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
}
// Update camera position
@ -851,7 +843,7 @@ bool Application::event(QEvent* event) {
QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event);
if (!fileEvent->url().isEmpty()) {
AddressManager::getInstance().handleLookupString(fileEvent->url().toLocalFile());
AddressManager::getInstance().handleLookupString(fileEvent->url().toString());
}
return false;
@ -1569,6 +1561,10 @@ void Application::checkBandwidthMeterClick() {
}
void Application::setFullscreen(bool fullscreen) {
if (Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen) != fullscreen) {
Menu::getInstance()->getActionForOption(MenuOption::Fullscreen)->setChecked(fullscreen);
}
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {
if (fullscreen) {
// Menu show() after hide() doesn't work with Rift VR display so set height instead.
@ -1579,6 +1575,7 @@ void Application::setFullscreen(bool fullscreen) {
}
_window->setWindowState(fullscreen ? (_window->windowState() | Qt::WindowFullScreen) :
(_window->windowState() & ~Qt::WindowFullScreen));
_window->show();
}
void Application::setEnable3DTVMode(bool enable3DTVMode) {
@ -1586,6 +1583,10 @@ void Application::setEnable3DTVMode(bool enable3DTVMode) {
}
void Application::setEnableVRMode(bool enableVRMode) {
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode) != enableVRMode) {
Menu::getInstance()->getActionForOption(MenuOption::EnableVRMode)->setChecked(enableVRMode);
}
if (enableVRMode) {
if (!OculusManager::isConnected()) {
// attempt to reconnect the Oculus manager - it's possible this was a workaround
@ -1596,6 +1597,11 @@ void Application::setEnableVRMode(bool enableVRMode) {
OculusManager::recalibrate();
} else {
OculusManager::abandonCalibration();
_mirrorCamera.setHmdPosition(glm::vec3());
_mirrorCamera.setHmdRotation(glm::quat());
_myCamera.setHmdPosition(glm::vec3());
_myCamera.setHmdRotation(glm::quat());
}
resizeGL(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight());
@ -3509,7 +3515,6 @@ void Application::deleteVoxelAt(const VoxelDetail& voxel) {
}
}
void Application::resetSensors() {
_mouseX = _glWidget->width() / 2;
_mouseY = _glWidget->height() / 2;
@ -3523,7 +3528,11 @@ void Application::resetSensors() {
_prioVR.reset();
//_leapmotion.reset();
QCursor::setPos(_mouseX, _mouseY);
QScreen* currentScreen = _window->windowHandle()->screen();
QWindow* mainWindow = _window->windowHandle();
QPoint windowCenter = mainWindow->geometry().center();
QCursor::setPos(currentScreen, windowCenter);
_myAvatar->reset();
QMetaObject::invokeMethod(&_audio, "reset", Qt::QueuedConnection);
@ -4008,26 +4017,23 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser
return _scriptEnginesHash[scriptURLString];
}
ScriptEngine* scriptEngine;
if (scriptFilename.isNull()) {
scriptEngine = new ScriptEngine(NO_SCRIPT, "", &_controllerScriptingInterface);
} else {
// start the script on a new thread...
scriptEngine = new ScriptEngine(scriptUrl, &_controllerScriptingInterface);
if (!scriptEngine->hasScript()) {
qDebug() << "Application::loadScript(), script failed to load...";
QMessageBox::warning(getWindow(), "Error Loading Script", scriptURLString + " failed to load.");
return NULL;
}
_scriptEnginesHash.insertMulti(scriptURLString, scriptEngine);
_runningScriptsWidget->setRunningScripts(getRunningScripts());
UserActivityLogger::getInstance().loadedScript(scriptURLString);
}
ScriptEngine* scriptEngine = new ScriptEngine(NO_SCRIPT, "", &_controllerScriptingInterface);
scriptEngine->setUserLoaded(isUserLoaded);
registerScriptEngineWithApplicationServices(scriptEngine);
if (scriptFilename.isNull()) {
// this had better be the script editor (we should de-couple so somebody who thinks they are loading a script
// doesn't just get an empty script engine)
// we can complete setup now since there isn't a script we have to load
registerScriptEngineWithApplicationServices(scriptEngine);
} else {
// connect to the appropriate signals of this script engine
connect(scriptEngine, &ScriptEngine::scriptLoaded, this, &Application::handleScriptEngineLoaded);
connect(scriptEngine, &ScriptEngine::errorLoadingScript, this, &Application::handleScriptLoadError);
// get the script engine object to load the script at the designated script URL
scriptEngine->loadURL(scriptUrl);
}
// restore the main window's active state
if (activateMainWindow && !loadScriptFromEditor) {
@ -4038,6 +4044,22 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser
return scriptEngine;
}
void Application::handleScriptEngineLoaded(const QUrl& scriptURL) {
ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(sender());
_scriptEnginesHash.insertMulti(scriptURL.toString(), scriptEngine);
_runningScriptsWidget->setRunningScripts(getRunningScripts());
UserActivityLogger::getInstance().loadedScript(scriptURL.toString());
// register our application services and set it off on its own thread
registerScriptEngineWithApplicationServices(scriptEngine);
}
void Application::handleScriptLoadError(const QUrl& scriptURL) {
qDebug() << "Application::loadScript(), script failed to load...";
QMessageBox::warning(getWindow(), "Error Loading Script", scriptURL.toString() + " failed to load.");
}
void Application::scriptFinished(const QString& scriptName) {
const QString& scriptURLString = QUrl(scriptName).toString();
QHash<QString, ScriptEngine*>::iterator it = _scriptEnginesHash.find(scriptURLString);

View file

@ -71,6 +71,7 @@
#include "scripting/ControllerScriptingInterface.h"
#include "ui/BandwidthDialog.h"
#include "ui/BandwidthMeter.h"
#include "ui/HMDToolsDialog.h"
#include "ui/ModelsBrowser.h"
#include "ui/NodeBounds.h"
#include "ui/OctreeStatsDialog.h"
@ -392,9 +393,13 @@ private slots:
void timer();
void idle();
void aboutToQuit();
void handleScriptEngineLoaded(const QUrl& scriptURL);
void handleScriptLoadError(const QUrl& scriptURL);
void connectedToDomain(const QString& hostname);
friend class HMDToolsDialog;
void setFullscreen(bool fullscreen);
void setEnable3DTVMode(bool enable3DTVMode);
void setEnableVRMode(bool enableVRMode);

View file

@ -97,6 +97,7 @@ Menu::Menu() :
_jsConsole(NULL),
_octreeStatsDialog(NULL),
_lodToolsDialog(NULL),
_hmdToolsDialog(NULL),
_newLocationDialog(NULL),
_userLocationsDialog(NULL),
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
@ -334,6 +335,12 @@ Menu::Menu() :
appInstance, SLOT(cameraMenuChanged()));
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::UserInterface, Qt::Key_Slash, true);
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, Qt::META | Qt::Key_H,
false,
this,
SLOT(hmdTools(bool)));
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::EnableVRMode, 0,
false,
appInstance,
@ -438,23 +445,7 @@ Menu::Menu() :
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderBoundingCollisionShapes);
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtVectors, 0, false);
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderFocusIndicator, 0, false);
QMenu* entitiesDebugMenu = developerMenu->addMenu("Entities");
addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DisplayModelBounds, 0, false);
addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DisplayModelElementProxy, 0, false);
addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DisplayModelElementChildProxies, 0, false);
addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DisableLightEntities, 0, false);
addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DontReduceMaterialSwitches, 0, false);
addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DontRenderEntitiesAsScene, 0, false);
QMenu* entityCullingMenu = entitiesDebugMenu->addMenu("Culling");
addCheckableActionToQMenuAndActionHash(entityCullingMenu, MenuOption::DontCullOutOfViewMeshParts, 0, false);
addCheckableActionToQMenuAndActionHash(entityCullingMenu, MenuOption::DontCullTooSmallMeshParts, 0, false);
QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxels");
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures);
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion);
@ -652,6 +643,10 @@ Menu::Menu() :
Menu::~Menu() {
bandwidthDetailsClosed();
octreeStatsDetailsClosed();
if (_hmdToolsDialog) {
delete _hmdToolsDialog;
_hmdToolsDialog = NULL;
}
}
void Menu::loadSettings(QSettings* settings) {
@ -1594,6 +1589,25 @@ void Menu::lodToolsClosed() {
}
}
void Menu::hmdTools(bool showTools) {
if (showTools) {
if (!_hmdToolsDialog) {
_hmdToolsDialog = new HMDToolsDialog(Application::getInstance()->getGLWidget());
connect(_hmdToolsDialog, SIGNAL(closed()), SLOT(hmdToolsClosed()));
}
_hmdToolsDialog->show();
_hmdToolsDialog->raise();
} else {
hmdToolsClosed();
}
Application::getInstance()->getWindow()->activateWindow();
}
void Menu::hmdToolsClosed() {
Menu::getInstance()->getActionForOption(MenuOption::HMDTools)->setChecked(false);
_hmdToolsDialog->hide();
}
void Menu::cycleFrustumRenderMode() {
_frustumDrawMode = (FrustumDrawMode)((_frustumDrawMode + 1) % FRUSTUM_DRAW_MODE_COUNT);
updateFrustumRenderModeAction();

View file

@ -76,6 +76,7 @@ class QSettings;
class AnimationsDialog;
class AttachmentsDialog;
class BandwidthDialog;
class HMDToolsDialog;
class LodToolsDialog;
class MetavoxelEditor;
class MetavoxelNetworkSimulator;
@ -120,6 +121,7 @@ public:
ViewFrustumOffset getViewFrustumOffset() const { return _viewFrustumOffset; }
OctreeStatsDialog* getOctreeStatsDialog() const { return _octreeStatsDialog; }
LodToolsDialog* getLodToolsDialog() const { return _lodToolsDialog; }
HMDToolsDialog* getHMDToolsDialog() const { return _hmdToolsDialog; }
int getMaxVoxels() const { return _maxVoxels; }
QAction* getUseVoxelShader() const { return _useVoxelShader; }
@ -183,6 +185,7 @@ public slots:
void bandwidthDetails();
void octreeStatsDetails();
void lodTools();
void hmdTools(bool showTools);
void loadSettings(QSettings* settings = NULL);
void saveSettings(QSettings* settings = NULL);
void importSettings();
@ -217,6 +220,7 @@ private slots:
void bandwidthDetailsClosed();
void octreeStatsDetailsClosed();
void lodToolsClosed();
void hmdToolsClosed();
void cycleFrustumRenderMode();
void runTests();
void showMetavoxelEditor();
@ -284,6 +288,7 @@ private:
QDialog* _jsConsole;
OctreeStatsDialog* _octreeStatsDialog;
LodToolsDialog* _lodToolsDialog;
HMDToolsDialog* _hmdToolsDialog;
QPointer<DataWebDialog> _newLocationDialog;
QPointer<DataWebDialog> _userLocationsDialog;
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
@ -400,6 +405,7 @@ namespace MenuOption {
const QString NamesAboveHeads = "Names Above Heads";
const QString GoToUser = "Go To User";
const QString HeadMouse = "Head Mouse";
const QString HMDTools = "HMD Tools";
const QString IncreaseAvatarSize = "Increase Avatar Size";
const QString IncreaseVoxelSize = "Increase Voxel Size";
const QString KeyboardMotorControl = "Enable Keyboard Motor Control";

View file

@ -273,7 +273,12 @@ void Head::setCorrectedLookAtPosition(glm::vec3 correctedLookAtPosition) {
_correctedLookAtPosition = correctedLookAtPosition;
}
glm::quat Head::getCameraOrientation () const {
glm::quat Head::getCameraOrientation() const {
// NOTE: Head::getCameraOrientation() is not used for orienting the camera "view" while in Oculus mode, so
// you may wonder why this code is here. This method will be called while in Oculus mode to determine how
// to change the driving direction while in Oculus mode. It is used to support driving toward where you're
// head is looking. Note that in oculus mode, your actual camera view and where your head is looking is not
// always the same.
if (OculusManager::isConnected()) {
return getOrientation();
}

View file

@ -367,6 +367,15 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
const float TORSO_LENGTH = 0.5f;
glm::vec3 relativePosition = estimatedPosition - glm::vec3(0.0f, -TORSO_LENGTH, 0.0f);
const float MAX_LEAN = 45.0f;
// Invert left/right lean when in mirror mode
// NOTE: this is kinda a hack, it's the same hack we use to make the head tilt. But it's not really a mirror
// it just makes you feel like you're looking in a mirror because the body movements of the avatar appear to
// match your body movements.
if (OculusManager::isConnected() && Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_MIRROR) {
relativePosition.x = -relativePosition.x;
}
head->setLeanSideways(glm::clamp(glm::degrees(atanf(relativePosition.x * _leanScale / TORSO_LENGTH)),
-MAX_LEAN, MAX_LEAN));
head->setLeanForward(glm::clamp(glm::degrees(atanf(relativePosition.z * _leanScale / TORSO_LENGTH)),

View file

@ -135,16 +135,20 @@ glm::vec3 vec3FromLeapVector(const Leap::Vector& vec) {
void Leapmotion::update() {
#ifdef HAVE_LEAPMOTION
// Check that the controller is actually active
bool wasActive = _active;
_active = _controller.isConnected();
if (!_active) {
return;
if (_active || wasActive) {
// Go through all the joints and increment their counter since last update.
// Increment all counters once after controller first becomes inactive so that each joint reports itself as inactive.
// TODO C++11 for (auto jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++) {
for (JointTracker::Vector::iterator jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++) {
(*jointIt).tickNewFrame();
}
}
// go through all the joints and increment their counter since last update
// TODO C++11 for (auto jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++) {
for (JointTracker::Vector::iterator jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++) {
(*jointIt).tickNewFrame();
if (!_active) {
return;
}
// Get the most recent frame and report some basic information

View file

@ -119,14 +119,14 @@ MotionTracker::JointTracker::JointTracker() :
_absFrame(),
_semantic(""),
_parent(INVALID_PARENT),
_lastUpdate(0)
_lastUpdate(1) // Joint inactive
{
}
MotionTracker::JointTracker::JointTracker(const Semantic& semantic, Index parent) :
_semantic(semantic),
_parent(parent),
_lastUpdate(0)
_lastUpdate(1) // Joint inactive
{
}

View file

@ -14,9 +14,14 @@
#include "OculusManager.h"
#include <QDesktopWidget>
#include <QGuiApplication>
#include <QOpenGLFramebufferObject>
#include <QScreen>
#include <glm/glm.hpp>
#include <SharedUtil.h>
#include <UserActivityLogger.h>
#include "Application.h"
@ -75,9 +80,7 @@ glm::vec3 OculusManager::_rightEyePosition = glm::vec3();
void OculusManager::connect() {
#ifdef HAVE_LIBOVR
_calibrationState = UNCALIBRATED;
qDebug() << "Oculus SDK" << OVR_VERSION_STRING;
ovr_Initialize();
_ovrHmd = ovrHmd_Create(0);
@ -86,6 +89,7 @@ void OculusManager::connect() {
UserActivityLogger::getInstance().connectedDevice("hmd", "oculus");
}
_isConnected = true;
#if defined(__APPLE__) || defined(_WIN32)
_eyeFov[0] = _ovrHmd->DefaultEyeFov[0];
_eyeFov[1] = _ovrHmd->DefaultEyeFov[1];
@ -715,3 +719,59 @@ void OculusManager::overrideOffAxisFrustum(float& left, float& right, float& bot
}
#endif
}
int OculusManager::getHMDScreen() {
int hmdScreenIndex = -1; // unknown
#ifdef HAVE_LIBOVR
// TODO: it might be smarter to handle multiple HMDs connected in this case. but for now,
// we will simply assume the initialization code that set up _ovrHmd picked the best hmd
if (_ovrHmd) {
QString productNameFromOVR = _ovrHmd->ProductName;
int hmdWidth = _ovrHmd->Resolution.w;
int hmdHeight = _ovrHmd->Resolution.h;
int hmdAtX = _ovrHmd->WindowsPos.x;
int hmdAtY = _ovrHmd->WindowsPos.y;
// we will score the likelihood that each screen is a match based on the following
// rubrik of potential matching features
const int EXACT_NAME_MATCH = 100;
const int SIMILAR_NAMES = 10;
const int EXACT_LOCATION_MATCH = 50;
const int EXACT_RESOLUTION_MATCH = 25;
int bestMatchScore = 0;
// look at the display list and see if we can find the best match
QDesktopWidget* desktop = QApplication::desktop();
int screenNumber = 0;
foreach (QScreen* screen, QGuiApplication::screens()) {
QString screenName = screen->name();
QRect screenRect = desktop->screenGeometry(screenNumber);
int screenScore = 0;
if (screenName == productNameFromOVR) {
screenScore += EXACT_NAME_MATCH;
}
if (similarStrings(screenName, productNameFromOVR)) {
screenScore += SIMILAR_NAMES;
}
if (hmdWidth == screenRect.width() && hmdHeight == screenRect.height()) {
screenScore += EXACT_RESOLUTION_MATCH;
}
if (hmdAtX == screenRect.x() && hmdAtY == screenRect.y()) {
screenScore += EXACT_LOCATION_MATCH;
}
if (screenScore > bestMatchScore) {
bestMatchScore = screenScore;
hmdScreenIndex = screenNumber;
}
screenNumber++;
}
}
#endif
return hmdScreenIndex;
}

View file

@ -52,11 +52,15 @@ public:
static glm::vec3 getLeftEyePosition() { return _leftEyePosition; }
static glm::vec3 getRightEyePosition() { return _rightEyePosition; }
static int getHMDScreen();
private:
#ifdef HAVE_LIBOVR
static void generateDistortionMesh();
static void renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]);
static bool similarNames(const QString& nameA,const QString& nameB);
struct DistortionVertex {
glm::vec2 pos;
glm::vec2 texR;

View file

@ -477,7 +477,8 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) {
triggerButton = Qt::LeftButton;
}
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) {
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)
|| Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {
pos = application->getApplicationOverlay().getPalmClickLocation(palm);
} else {
// Get directon relative to avatar orientation

View file

@ -138,11 +138,9 @@ void AnimationHandle::simulate(float deltaTime) {
return;
}
// TODO: When moving the loop/frame calculations to AnimationLoop class, we changed this behavior
// see AnimationLoop class for more details. Do we need to support clamping the endFrameIndex to
// the max number of frames in the geometry???
//
// float endFrameIndex = qMin(_lastFrame, animationGeometry.animationFrames.size() - (_loop ? 0.0f : 1.0f));
if (_animationLoop.getMaxFrameIndexHint() != animationGeometry.animationFrames.size()) {
_animationLoop.setMaxFrameIndexHint(animationGeometry.animationFrames.size());
}
// blend between the closest two frames
applyFrame(getFrameIndex());

View file

@ -829,10 +829,25 @@ void GeometryReader::run() {
return;
}
try {
QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&,
std::string urlname = _url.path().toLower().toStdString();
FBXGeometry fbxgeo;
if (_url.path().toLower().endsWith(".svo")) {
fbxgeo = readSVO(_reply->readAll());
} else {
bool grabLightmaps = true;
float lightmapLevel = 1.0f;
// HACK: For monday 12/01/2014 we need to kill lighmaps loading in starchamber...
if (_url.path().toLower().endsWith("loungev4_11-18.fbx")) {
grabLightmaps = false;
} else if (_url.path().toLower().endsWith("apt8_reboot.fbx")) {
lightmapLevel = 4.0f;
}
fbxgeo = readFBX(_reply->readAll(), _mapping, grabLightmaps, lightmapLevel);
}
QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&, fbxgeo));
_url.path().toLower().endsWith(".svo") ? readSVO(_reply->readAll()) : readFBX(_reply->readAll(), _mapping)));
// _url.path().toLower().endsWith(".svo") ? readSVO(_reply->readAll()) : readFBX(_reply->readAll(), _mapping)));
} catch (const QString& error) {
qDebug() << "Error reading " << _url << ": " << error;

View file

@ -2347,8 +2347,12 @@ int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMod
diffuseMap = (_dilatedTextures[i][j] =
static_cast<DilatableNetworkTexture*>(diffuseMap)->getDilatedTexture(_pupilDilation)).data();
}
GLBATCH(glBindTexture)(GL_TEXTURE_2D, !diffuseMap ?
Application::getInstance()->getTextureCache()->getWhiteTextureID() : diffuseMap->getID());
static bool showDiffuse = true;
if (showDiffuse && diffuseMap) {
GLBATCH(glBindTexture)(GL_TEXTURE_2D, diffuseMap->getID());
} else {
GLBATCH(glBindTexture)(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getWhiteTextureID());
}
if (locations->texcoordMatrices >= 0) {
glm::mat4 texcoordTransform[2];
@ -2377,22 +2381,27 @@ int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMod
GLBATCH(glActiveTexture)(GL_TEXTURE0);
}
if (locations->emissiveTextureUnit >= 0) {
assert(locations->emissiveParams >= 0); // we should have the emissiveParams defined in the shader
GLBATCH(glUniform2f)(locations->emissiveParams, 0.1f, 4.0f);
GLBATCH(glActiveTexture)(GL_TEXTURE0 + locations->emissiveTextureUnit);
Texture* emissiveMap = networkPart.emissiveTexture.data();
GLBATCH(glBindTexture)(GL_TEXTURE_2D, !emissiveMap ?
Application::getInstance()->getTextureCache()->getWhiteTextureID() : emissiveMap->getID());
GLBATCH(glActiveTexture)(GL_TEXTURE0);
}
if (args) {
args->_materialSwitches++;
}
}
// HACK: For unkwon reason (yet!) this code that should be assigned only if the material changes need to be called for every
// drawcall with an emissive, so let's do it for now.
if (locations->emissiveTextureUnit >= 0) {
// assert(locations->emissiveParams >= 0); // we should have the emissiveParams defined in the shader
float emissiveOffset = part.emissiveParams.x;
float emissiveScale = part.emissiveParams.y;
GLBATCH(glUniform2f)(locations->emissiveParams, emissiveOffset, emissiveScale);
GLBATCH(glActiveTexture)(GL_TEXTURE0 + locations->emissiveTextureUnit);
Texture* emissiveMap = networkPart.emissiveTexture.data();
GLBATCH(glBindTexture)(GL_TEXTURE_2D, !emissiveMap ?
Application::getInstance()->getTextureCache()->getWhiteTextureID() : emissiveMap->getID());
GLBATCH(glActiveTexture)(GL_TEXTURE0);
}
lastMaterialID = part.materialID;
}

View file

@ -984,7 +984,8 @@ void ApplicationOverlay::renderAudioMeter() {
const int AUDIO_METER_X = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_INSET + AUDIO_METER_GAP;
int audioMeterY;
bool boxed = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) &&
bool smallMirrorVisible = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !OculusManager::isConnected();
bool boxed = smallMirrorVisible &&
!Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror);
if (boxed) {
audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_GAP + MUTE_ICON_PADDING;

View file

@ -0,0 +1,309 @@
//
// HMDToolsDialog.cpp
// interface/src/ui
//
// Created by Brad Hefta-Gaub on 7/19/13.
// Copyright 2013 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 <QFormLayout>
#include <QGuiApplication>
#include <QDialogButtonBox>
#include <QDesktopWidget>
#include <QPushButton>
#include <QString>
#include <QScreen>
#include <QWindow>
#include <VoxelConstants.h>
#include "Menu.h"
#include "devices/OculusManager.h"
#include "ui/HMDToolsDialog.h"
HMDToolsDialog::HMDToolsDialog(QWidget* parent) :
QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint) ,
_previousScreen(NULL),
_hmdScreen(NULL),
_hmdScreenNumber(-1),
_switchModeButton(NULL),
_debugDetails(NULL),
_previousDialogScreen(NULL),
_inHDMMode(false)
{
this->setWindowTitle("HMD Tools");
// Create layouter
QFormLayout* form = new QFormLayout();
const int WIDTH = 350;
// Add a button to enter
_switchModeButton = new QPushButton("Enter HMD Mode");
_switchModeButton->setFixedWidth(WIDTH);
form->addRow("", _switchModeButton);
connect(_switchModeButton,SIGNAL(clicked(bool)),this,SLOT(switchModeClicked(bool)));
// Create a label with debug details...
_debugDetails = new QLabel();
_debugDetails->setText(getDebugDetails());
const int HEIGHT = 100;
_debugDetails->setFixedSize(WIDTH, HEIGHT);
form->addRow("", _debugDetails);
this->QDialog::setLayout(form);
_wasMoved = false;
_previousRect = Application::getInstance()->getWindow()->rect();
Application::getInstance()->getWindow()->activateWindow();
// watch for our application window moving screens. If it does we want to update our screen details
QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle();
connect(mainWindow, &QWindow::screenChanged, this, &HMDToolsDialog::applicationWindowScreenChanged);
// watch for our dialog window moving screens. If it does we want to enforce our rules about
// what screens we're allowed on
QWindow* dialogWindow = windowHandle();
connect(dialogWindow, &QWindow::screenChanged, this, &HMDToolsDialog::dialogWindowScreenChanged);
connect(dialogWindow, &QWindow::xChanged, this, &HMDToolsDialog::dialogWindowGeometryChanged);
connect(dialogWindow, &QWindow::yChanged, this, &HMDToolsDialog::dialogWindowGeometryChanged);
connect(dialogWindow, &QWindow::widthChanged, this, &HMDToolsDialog::dialogWindowGeometryChanged);
connect(dialogWindow, &QWindow::heightChanged, this, &HMDToolsDialog::dialogWindowGeometryChanged);
// when the application is about to quit, leave HDM mode
connect(Application::getInstance(), SIGNAL(aboutToQuit()), this, SLOT(aboutToQuit()));
// keep track of changes to the number of screens
connect(QApplication::desktop(), &QDesktopWidget::screenCountChanged, this, &HMDToolsDialog::screenCountChanged);
}
HMDToolsDialog::~HMDToolsDialog() {
}
void HMDToolsDialog::applicationWindowScreenChanged(QScreen* screen) {
_debugDetails->setText(getDebugDetails());
}
void HMDToolsDialog::dialogWindowGeometryChanged(int arg) {
QWindow* dialogWindow = windowHandle();
_previousDialogRect = rect();
_previousDialogRect = QRect(dialogWindow->mapToGlobal(_previousDialogRect.topLeft()),
dialogWindow->mapToGlobal(_previousDialogRect.bottomRight()));
_previousDialogScreen = dialogWindow->screen();
}
void HMDToolsDialog::dialogWindowScreenChanged(QScreen* screen) {
_debugDetails->setText(getDebugDetails());
// if we have more than one screen, and a known hmdScreen then try to
// keep our dialog off of the hmdScreen
if (QApplication::desktop()->screenCount() > 1) {
// we want to use a local variable here because we are not necesarily in HMD mode
int hmdScreenNumber = OculusManager::getHMDScreen();
if (_hmdScreenNumber >= 0) {
QScreen* hmdScreen = QGuiApplication::screens()[hmdScreenNumber];
if (screen == hmdScreen) {
qDebug() << "HMD Tools: Whoa! What are you doing? You don't want to move me to the HMD Screen!";
QWindow* dialogWindow = windowHandle();
// try to pick a better screen
QScreen* betterScreen = NULL;
QWindow* appWindow = Application::getInstance()->getWindow()->windowHandle();
QScreen* appScreen = appWindow->screen();
if (_previousDialogScreen && _previousDialogScreen != hmdScreen) {
// first, if the previous dialog screen is not the HMD screen, then move it there.
betterScreen = appScreen;
} else if (appScreen != hmdScreen) {
// second, if the application screen is not the HMD screen, then move it there.
betterScreen = appScreen;
} else if (_previousScreen && _previousScreen != hmdScreen) {
// third, if the application screen is the HMD screen, we want to move it to
// the previous screen
betterScreen = _previousScreen;
} else {
// last, if we can't use the previous screen the use the primary desktop screen
int desktopPrimaryScreenNumber = QApplication::desktop()->primaryScreen();
QScreen* desktopPrimaryScreen = QGuiApplication::screens()[desktopPrimaryScreenNumber];
betterScreen = desktopPrimaryScreen;
}
if (betterScreen) {
dialogWindow->setScreen(betterScreen);
dialogWindow->setGeometry(_previousDialogRect);
}
}
}
}
}
QString HMDToolsDialog::getDebugDetails() const {
QString results;
int hmdScreenNumber = OculusManager::getHMDScreen();
if (hmdScreenNumber >= 0) {
results += "HMD Screen: " + QGuiApplication::screens()[hmdScreenNumber]->name() + "\n";
} else {
results += "HMD Screen Name: Unknown\n";
}
int desktopPrimaryScreenNumber = QApplication::desktop()->primaryScreen();
QScreen* desktopPrimaryScreen = QGuiApplication::screens()[desktopPrimaryScreenNumber];
results += "Desktop's Primary Screen: " + desktopPrimaryScreen->name() + "\n";
results += "Application Primary Screen: " + QGuiApplication::primaryScreen()->name() + "\n";
QScreen* mainWindowScreen = Application::getInstance()->getWindow()->windowHandle()->screen();
results += "Application Main Window Screen: " + mainWindowScreen->name() + "\n";
results += "Total Screens: " + QString::number(QApplication::desktop()->screenCount()) + "\n";
return results;
}
void HMDToolsDialog::switchModeClicked(bool checked) {
if (!_inHDMMode) {
enterHDMMode();
} else {
leaveHDMMode();
}
}
void HMDToolsDialog::enterHDMMode() {
if (!_inHDMMode) {
_switchModeButton->setText("Leave HMD Mode");
_debugDetails->setText(getDebugDetails());
_hmdScreenNumber = OculusManager::getHMDScreen();
if (_hmdScreenNumber >= 0) {
QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle();
_hmdScreen = QGuiApplication::screens()[_hmdScreenNumber];
_previousRect = Application::getInstance()->getWindow()->rect();
_previousRect = QRect(mainWindow->mapToGlobal(_previousRect.topLeft()),
mainWindow->mapToGlobal(_previousRect.bottomRight()));
_previousScreen = mainWindow->screen();
QRect rect = QApplication::desktop()->screenGeometry(_hmdScreenNumber);
mainWindow->setScreen(_hmdScreen);
mainWindow->setGeometry(rect);
_wasMoved = true;
}
// if we're on a single screen setup, then hide our tools window when entering HMD mode
if (QApplication::desktop()->screenCount() == 1) {
close();
}
Application::getInstance()->setFullscreen(true);
Application::getInstance()->setEnableVRMode(true);
const int SLIGHT_DELAY = 500;
QTimer::singleShot(SLIGHT_DELAY, this, SLOT(activateWindowAfterEnterMode()));
_inHDMMode = true;
}
}
void HMDToolsDialog::activateWindowAfterEnterMode() {
Application::getInstance()->getWindow()->activateWindow();
// center the cursor on the main application window
centerCursorOnWidget(Application::getInstance()->getWindow());
}
void HMDToolsDialog::leaveHDMMode() {
if (_inHDMMode) {
_switchModeButton->setText("Enter HMD Mode");
_debugDetails->setText(getDebugDetails());
Application::getInstance()->setFullscreen(false);
Application::getInstance()->setEnableVRMode(false);
Application::getInstance()->getWindow()->activateWindow();
if (_wasMoved) {
QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle();
mainWindow->setScreen(_previousScreen);
mainWindow->setGeometry(_previousRect);
const int SLIGHT_DELAY = 1500;
QTimer::singleShot(SLIGHT_DELAY, this, SLOT(moveWindowAfterLeaveMode()));
}
_wasMoved = false;
_inHDMMode = false;
}
}
void HMDToolsDialog::moveWindowAfterLeaveMode() {
QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle();
mainWindow->setScreen(_previousScreen);
mainWindow->setGeometry(_previousRect);
Application::getInstance()->getWindow()->activateWindow();
Application::getInstance()->resetSensors();
}
void HMDToolsDialog::reject() {
// Just regularly close upon ESC
close();
}
void HMDToolsDialog::closeEvent(QCloseEvent* event) {
// TODO: consider if we want to prevent closing of this window with event->ignore();
this->QDialog::closeEvent(event);
emit closed();
}
void HMDToolsDialog::centerCursorOnWidget(QWidget* widget) {
QWindow* window = widget->windowHandle();
QScreen* screen = window->screen();
QPoint windowCenter = window->geometry().center();
QCursor::setPos(screen, windowCenter);
}
void HMDToolsDialog::showEvent(QShowEvent* event) {
// center the cursor on the hmd tools dialog
centerCursorOnWidget(this);
}
void HMDToolsDialog::hideEvent(QHideEvent* event) {
// center the cursor on the main application window
centerCursorOnWidget(Application::getInstance()->getWindow());
}
void HMDToolsDialog::aboutToQuit() {
if (_inHDMMode) {
leaveHDMMode();
}
}
void HMDToolsDialog::screenCountChanged(int newCount) {
if (!OculusManager::isConnected()) {
OculusManager::connect();
}
int hmdScreenNumber = OculusManager::getHMDScreen();
if (_inHDMMode && _hmdScreenNumber != hmdScreenNumber) {
qDebug() << "HMD Display changed WHILE IN HMD MODE";
leaveHDMMode();
// if there is a new best HDM screen then go back into HDM mode after done leaving
if (hmdScreenNumber >= 0) {
qDebug() << "Trying to go back into HDM Mode";
const int SLIGHT_DELAY = 2000;
QTimer::singleShot(SLIGHT_DELAY, this, SLOT(enterHDMMode()));
}
}
_debugDetails->setText(getDebugDetails());
}

View file

@ -0,0 +1,63 @@
//
// HMDToolsDialog.h
// interface/src/ui
//
// Created by Brad Hefta-Gaub on 7/19/13.
// Copyright 2013 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_HMDToolsDialog_h
#define hifi_HMDToolsDialog_h
#include <QDialog>
class HMDToolsDialog : public QDialog {
Q_OBJECT
public:
// Sets up the UI
HMDToolsDialog(QWidget* parent);
~HMDToolsDialog();
QString getDebugDetails() const;
signals:
void closed();
public slots:
void reject();
void switchModeClicked(bool checked);
void activateWindowAfterEnterMode();
void moveWindowAfterLeaveMode();
void applicationWindowScreenChanged(QScreen* screen);
void dialogWindowScreenChanged(QScreen* screen);
void dialogWindowGeometryChanged(int arg);
void aboutToQuit();
void screenCountChanged(int newCount);
protected:
virtual void closeEvent(QCloseEvent*); // Emits a 'closed' signal when this dialog is closed.
virtual void showEvent(QShowEvent* event);
virtual void hideEvent(QHideEvent* event);
private:
void centerCursorOnWidget(QWidget* widget);
void enterHDMMode();
void leaveHDMMode();
bool _wasMoved;
QRect _previousRect;
QScreen* _previousScreen;
QScreen* _hmdScreen;
int _hmdScreenNumber;
QPushButton* _switchModeButton;
QLabel* _debugDetails;
QRect _previousDialogRect;
QScreen* _previousDialogScreen;
bool _inHDMMode;
};
#endif // hifi_HMDToolsDialog_h

View file

@ -21,6 +21,7 @@ ToolWindow::ToolWindow(QWidget* parent) :
_hasShown(false),
_lastGeometry() {
setDockOptions(QMainWindow::ForceTabbedDocks);
Application::getInstance()->installEventFilter(this);
}
@ -99,8 +100,17 @@ void ToolWindow::onChildVisibilityUpdated(bool visible) {
}
void ToolWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget* dockWidget) {
QList<QDockWidget*> dockWidgets = findChildren<QDockWidget*>();
QMainWindow::addDockWidget(area, dockWidget);
// We want to force tabbing, so retabify all of our widgets.
QDockWidget* lastDockWidget = dockWidget;
foreach (QDockWidget* nextDockWidget, dockWidgets) {
tabifyDockWidget(lastDockWidget, nextDockWidget);
lastDockWidget = nextDockWidget;
}
connect(dockWidget, &QDockWidget::visibilityChanged, this, &ToolWindow::onChildVisibilityUpdated);
}

View file

@ -20,7 +20,8 @@ AnimationLoop::AnimationLoop() :
_firstFrame(0.0f),
_lastFrame(FLT_MAX),
_running(false),
_frameIndex(0.0f)
_frameIndex(0.0f),
_maxFrameIndexHint(FLT_MAX)
{
}
@ -55,7 +56,7 @@ void AnimationLoop::simulate(float deltaTime) {
// If we knew the number of frames from the animation, we'd consider using it here
// animationGeometry.animationFrames.size()
float maxFrame = _lastFrame;
float maxFrame = _maxFrameIndexHint;
float endFrameIndex = qMin(_lastFrame, maxFrame - (_loop ? 0.0f : 1.0f));
float startFrameIndex = qMin(_firstFrame, endFrameIndex);
if ((!_loop && (_frameIndex < startFrameIndex || _frameIndex > endFrameIndex)) || startFrameIndex == endFrameIndex) {

View file

@ -44,6 +44,9 @@ public:
void setFrameIndex(float frameIndex) { _frameIndex = glm::clamp(frameIndex, _firstFrame, _lastFrame); }
float getFrameIndex() const { return _frameIndex; }
void setMaxFrameIndexHint(float value) { _maxFrameIndexHint = value; }
float getMaxFrameIndexHint() const { return _maxFrameIndexHint; }
void start() { setRunning(true); }
void stop() { setRunning(false); }
@ -58,6 +61,7 @@ private:
float _lastFrame;
bool _running;
float _frameIndex;
float _maxFrameIndexHint;
};
#endif // hifi_AnimationLoop_h

View file

@ -344,7 +344,9 @@ QVector<glm::quat> ModelEntityItem::getAnimationFrame() {
Animation* myAnimation = getAnimation(_animationURL);
QVector<FBXAnimationFrame> frames = myAnimation->getFrames();
int frameCount = frames.size();
if (_animationLoop.getMaxFrameIndexHint() != frameCount) {
_animationLoop.setMaxFrameIndexHint(frameCount);
}
if (frameCount > 0) {
int animationFrameIndex = (int)(glm::floor(getAnimationFrameIndex())) % frameCount;
if (animationFrameIndex < 0 || animationFrameIndex > frameCount) {

View file

@ -1194,7 +1194,7 @@ int matchTextureUVSetToAttributeChannel(const std::string& texUVSetName, const Q
}
}
FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) {
FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, bool loadLightmaps, float lightmapLevel) {
QHash<QString, ExtractedMesh> meshes;
QHash<QString, QString> modelIDsToNames;
QHash<QString, int> meshIDsToMeshIndices;
@ -1216,6 +1216,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
QHash<QString, QString> bumpTextures;
QHash<QString, QString> specularTextures;
QHash<QString, QString> emissiveTextures;
QHash<QString, QString> ambientTextures;
QHash<QString, QString> localRotations;
QHash<QString, QString> xComponents;
QHash<QString, QString> yComponents;
@ -1597,9 +1598,28 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
} else if (property.properties.at(0) == "Opacity") {
material.opacity = property.properties.at(index).value<double>();
}
#if defined(DEBUG_FBXREADER)
else {
const std::string propname = property.properties.at(0).toString().toStdString();
if (propname == "EmissiveFactor") {
}
}
#endif
}
}
}
#if defined(DEBUG_FBXREADER)
else {
std::string propname = subobject.name.data();
int unknown = 0;
if ( (propname == "Version")
||(propname == "ShadingModel")
||(propname == "Multilayer")) {
} else {
unknown++;
}
}
#endif
}
material.id = getID(object.properties);
materials.insert(material.id, material);
@ -1684,10 +1704,13 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
} else if (type.contains("shininess")) {
counter++;
} else if (type.contains("emissive")) {
} else if (loadLightmaps && type.contains("emissive")) {
emissiveTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
} else if (loadLightmaps && type.contains("ambient")) {
ambientTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
} else {
std::string typenam = type.data();
counter++;
}
}
@ -1930,19 +1953,21 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
}
FBXTexture emissiveTexture;
glm::vec2 emissiveParams(0.f, 1.f);
emissiveParams.y = lightmapLevel;
QString emissiveTextureID = emissiveTextures.value(childID);
if (!emissiveTextureID.isNull()) {
emissiveTexture = getTexture(emissiveTextureID, textureNames, textureFilenames, textureContent, textureParams);
// FBX files generated by 3DSMax have an intermediate texture parent, apparently
foreach (const QString& childTextureID, childMap.values(diffuseTextureID)) {
if (textureFilenames.contains(childTextureID)) {
emissiveTexture = getTexture(emissiveTextureID, textureNames, textureFilenames, textureContent, textureParams);
}
QString ambientTextureID = ambientTextures.value(childID);
if (!emissiveTextureID.isNull() || !ambientTextureID.isNull()) {
if (!emissiveTextureID.isNull()) {
emissiveTexture = getTexture(emissiveTextureID, textureNames, textureFilenames, textureContent, textureParams);
emissiveParams.y = 4.0f;
} else if (!ambientTextureID.isNull()) {
emissiveTexture = getTexture(ambientTextureID, textureNames, textureFilenames, textureContent, textureParams);
}
emissiveTexture.texcoordSet = matchTextureUVSetToAttributeChannel(emissiveTexture.texcoordSetName, extracted.texcoordSetMap);
detectDifferentUVs |= (emissiveTexture.texcoordSet != 0) || (!emissiveTexture.transform.isIdentity());
}
@ -1970,6 +1995,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
if (!emissiveTexture.filename.isNull()) {
part.emissiveTexture = emissiveTexture;
}
part.emissiveParams = emissiveParams;
part.materialID = material.id;
}
}
@ -2346,10 +2373,10 @@ QByteArray writeMapping(const QVariantHash& mapping) {
return buffer.data();
}
FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping) {
FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool loadLightmaps, float lightmapLevel) {
QBuffer buffer(const_cast<QByteArray*>(&model));
buffer.open(QIODevice::ReadOnly);
return extractFBXGeometry(parseFBX(&buffer), mapping);
return extractFBXGeometry(parseFBX(&buffer), mapping, loadLightmaps, lightmapLevel);
}
bool addMeshVoxelsOperation(OctreeElement* element, void* extraData) {

View file

@ -119,6 +119,7 @@ public:
glm::vec3 diffuseColor;
glm::vec3 specularColor;
glm::vec3 emissiveColor;
glm::vec2 emissiveParams;
float shininess;
float opacity;
@ -252,7 +253,7 @@ QByteArray writeMapping(const QVariantHash& mapping);
/// Reads FBX geometry from the supplied model and mapping data.
/// \exception QString if an error occurs in parsing
FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping);
FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool loadLightmaps = true, float lightmapLevel = 1.0f);
/// Reads SVO geometry from the supplied model data.
FBXGeometry readSVO(const QByteArray& model);

View file

@ -44,6 +44,8 @@ const char DEFAULT_ASSIGNMENT_SERVER_HOSTNAME[] = "localhost";
const char STUN_SERVER_HOSTNAME[] = "stun.highfidelity.io";
const unsigned short STUN_SERVER_PORT = 3478;
const QString DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY = "domain-server.local-port";
class HifiSockAddr;
typedef QSet<NodeType_t> NodeSet;

View file

@ -100,71 +100,6 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam
{
}
ScriptEngine::ScriptEngine(const QUrl& scriptURL,
AbstractControllerScriptingInterface* controllerScriptingInterface) :
_scriptContents(),
_isFinished(false),
_isRunning(false),
_isInitialized(false),
_isAvatar(false),
_avatarIdentityTimer(NULL),
_avatarBillboardTimer(NULL),
_timerFunctionMap(),
_isListeningToAudioStream(false),
_avatarSound(NULL),
_numAvatarSoundSentBytes(0),
_controllerScriptingInterface(controllerScriptingInterface),
_avatarData(NULL),
_scriptName(),
_fileNameString(),
_quatLibrary(),
_vec3Library(),
_uuidLibrary(),
_animationCache(this),
_isUserLoaded(false),
_arrayBufferClass(new ArrayBufferClass(this))
{
QString scriptURLString = scriptURL.toString();
_fileNameString = scriptURLString;
QUrl url(scriptURL);
// if the scheme length is one or lower, maybe they typed in a file, let's try
const int WINDOWS_DRIVE_LETTER_SIZE = 1;
if (url.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) {
url = QUrl::fromLocalFile(scriptURLString);
}
// ok, let's see if it's valid... and if so, load it
if (url.isValid()) {
if (url.scheme() == "file") {
QString fileName = url.toLocalFile();
QFile scriptFile(fileName);
if (scriptFile.open(QFile::ReadOnly | QFile::Text)) {
qDebug() << "Loading file:" << fileName;
QTextStream in(&scriptFile);
_scriptContents = in.readAll();
} else {
qDebug() << "ERROR Loading file:" << fileName;
emit errorMessage("ERROR Loading file:" + fileName);
}
} else {
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
qDebug() << "Downloading script at" << url;
QEventLoop loop;
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
if (reply->error() == QNetworkReply::NoError && reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 200) {
_scriptContents = reply->readAll();
} else {
qDebug() << "ERROR Loading file:" << url.toString();
emit errorMessage("ERROR Loading file:" + url.toString());
}
}
}
}
void ScriptEngine::setIsAvatar(bool isAvatar) {
_isAvatar = isAvatar;
@ -217,6 +152,56 @@ bool ScriptEngine::setScriptContents(const QString& scriptContents, const QStrin
return true;
}
void ScriptEngine::loadURL(const QUrl& scriptURL) {
if (_isRunning) {
return;
}
QString scriptURLString = scriptURL.toString();
_fileNameString = scriptURLString;
QUrl url(scriptURL);
// if the scheme length is one or lower, maybe they typed in a file, let's try
const int WINDOWS_DRIVE_LETTER_SIZE = 1;
if (url.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) {
url = QUrl::fromLocalFile(scriptURLString);
}
// ok, let's see if it's valid... and if so, load it
if (url.isValid()) {
if (url.scheme() == "file") {
QString fileName = url.toLocalFile();
QFile scriptFile(fileName);
if (scriptFile.open(QFile::ReadOnly | QFile::Text)) {
qDebug() << "Loading file:" << fileName;
QTextStream in(&scriptFile);
_scriptContents = in.readAll();
emit scriptLoaded(url);
} else {
qDebug() << "ERROR Loading file:" << fileName;
emit errorLoadingScript(url);
}
} else {
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
connect(reply, &QNetworkReply::finished, this, &ScriptEngine::handleScriptDownload);
}
}
}
void ScriptEngine::handleScriptDownload() {
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
if (reply->error() == QNetworkReply::NoError && reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 200) {
_scriptContents = reply->readAll();
emit scriptLoaded(reply->url());
} else {
qDebug() << "ERROR Loading file:" << reply->url().toString();
emit errorLoadingScript(reply->url());
}
}
Q_SCRIPT_DECLARE_QMETAOBJECT(LocalVoxels, QString)
void ScriptEngine::init() {

View file

@ -40,9 +40,6 @@ const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0 / 60.0f) * 1000 * 10
class ScriptEngine : public QScriptEngine {
Q_OBJECT
public:
ScriptEngine(const QUrl& scriptURL,
AbstractControllerScriptingInterface* controllerScriptingInterface = NULL);
ScriptEngine(const QString& scriptContents = NO_SCRIPT,
const QString& fileNameString = QString(""),
AbstractControllerScriptingInterface* controllerScriptingInterface = NULL);
@ -94,6 +91,7 @@ public:
bool isUserLoaded() const { return _isUserLoaded; }
public slots:
void loadURL(const QUrl& scriptURL);
void stop();
QScriptValue evaluate(const QString& program, const QString& fileName = QString(), int lineNumber = 1);
@ -109,6 +107,8 @@ public slots:
void nodeKilled(SharedNodePointer node);
signals:
void scriptLoaded(const QUrl& scriptURL);
void errorLoadingScript(const QUrl& scriptURL);
void update(float deltaTime);
void scriptEnding();
void finished(const QString& fileNameString);
@ -155,6 +155,8 @@ private:
ArrayBufferClass* _arrayBufferClass;
QHash<QUuid, quint16> _outgoingScriptAudioSequenceNumbers;
private slots:
void handleScriptDownload();
};
#endif // hifi_ScriptEngine_h

View file

@ -655,3 +655,24 @@ QString formatSecondsElapsed(float seconds) {
}
return result;
}
bool similarStrings(const QString& stringA, const QString& stringB) {
QStringList aWords = stringA.split(" ");
QStringList bWords = stringB.split(" ");
float aWordsInB = 0.0f;
foreach(QString aWord, aWords) {
if (bWords.contains(aWord)) {
aWordsInB += 1.0f;
}
}
float bWordsInA = 0.0f;
foreach(QString bWord, bWords) {
if (aWords.contains(bWord)) {
bWordsInA += 1.0f;
}
}
float similarity = 0.5f * (aWordsInB / (float)bWords.size()) + 0.5f * (bWordsInA / (float)aWords.size());
const float SIMILAR_ENOUGH = 0.5f; // half the words the same is similar enough for us
return similarity >= SIMILAR_ENOUGH;
}

View file

@ -131,6 +131,6 @@ bool isNaN(float value);
QString formatUsecTime(float usecs, int prec = 3);
QString formatSecondsElapsed(float seconds);
bool similarStrings(const QString& stringA, const QString& stringB);
#endif // hifi_SharedUtil_h