Merge branch 'master' of https://github.com/highfidelity/hifi into 19755

This commit is contained in:
Stojce Slavkovski 2014-06-17 23:22:03 +02:00
commit 8b5e3486a3
25 changed files with 803 additions and 353 deletions

View file

@ -335,7 +335,7 @@ void AudioMixer::prepareMixForListeningNode(Node* node) {
AudioMixerClientData* otherNodeClientData = (AudioMixerClientData*) otherNode->getLinkedData(); AudioMixerClientData* otherNodeClientData = (AudioMixerClientData*) otherNode->getLinkedData();
// enumerate the ARBs attached to the otherNode and add all that should be added to mix // enumerate the ARBs attached to the otherNode and add all that should be added to mix
for (unsigned int i = 0; i < otherNodeClientData->getRingBuffers().size(); i++) { for (int i = 0; i < otherNodeClientData->getRingBuffers().size(); i++) {
PositionalAudioRingBuffer* otherNodeBuffer = otherNodeClientData->getRingBuffers()[i]; PositionalAudioRingBuffer* otherNodeBuffer = otherNodeClientData->getRingBuffers()[i];
if ((*otherNode != *node if ((*otherNode != *node

View file

@ -25,14 +25,14 @@ AudioMixerClientData::AudioMixerClientData() :
} }
AudioMixerClientData::~AudioMixerClientData() { AudioMixerClientData::~AudioMixerClientData() {
for (unsigned int i = 0; i < _ringBuffers.size(); i++) { for (int i = 0; i < _ringBuffers.size(); i++) {
// delete this attached PositionalAudioRingBuffer // delete this attached PositionalAudioRingBuffer
delete _ringBuffers[i]; delete _ringBuffers[i];
} }
} }
AvatarAudioRingBuffer* AudioMixerClientData::getAvatarAudioRingBuffer() const { AvatarAudioRingBuffer* AudioMixerClientData::getAvatarAudioRingBuffer() const {
for (unsigned int i = 0; i < _ringBuffers.size(); i++) { for (int i = 0; i < _ringBuffers.size(); i++) {
if (_ringBuffers[i]->getType() == PositionalAudioRingBuffer::Microphone) { if (_ringBuffers[i]->getType() == PositionalAudioRingBuffer::Microphone) {
return (AvatarAudioRingBuffer*) _ringBuffers[i]; return (AvatarAudioRingBuffer*) _ringBuffers[i];
} }
@ -79,7 +79,7 @@ int AudioMixerClientData::parseData(const QByteArray& packet) {
InjectedAudioRingBuffer* matchingInjectedRingBuffer = NULL; InjectedAudioRingBuffer* matchingInjectedRingBuffer = NULL;
for (unsigned int i = 0; i < _ringBuffers.size(); i++) { for (int i = 0; i < _ringBuffers.size(); i++) {
if (_ringBuffers[i]->getType() == PositionalAudioRingBuffer::Injector if (_ringBuffers[i]->getType() == PositionalAudioRingBuffer::Injector
&& ((InjectedAudioRingBuffer*) _ringBuffers[i])->getStreamIdentifier() == streamIdentifier) { && ((InjectedAudioRingBuffer*) _ringBuffers[i])->getStreamIdentifier() == streamIdentifier) {
matchingInjectedRingBuffer = (InjectedAudioRingBuffer*) _ringBuffers[i]; matchingInjectedRingBuffer = (InjectedAudioRingBuffer*) _ringBuffers[i];
@ -99,7 +99,7 @@ int AudioMixerClientData::parseData(const QByteArray& packet) {
} }
void AudioMixerClientData::checkBuffersBeforeFrameSend(int jitterBufferLengthSamples) { void AudioMixerClientData::checkBuffersBeforeFrameSend(int jitterBufferLengthSamples) {
for (unsigned int i = 0; i < _ringBuffers.size(); i++) { for (int i = 0; i < _ringBuffers.size(); i++) {
if (_ringBuffers[i]->shouldBeAddedToMix(jitterBufferLengthSamples)) { if (_ringBuffers[i]->shouldBeAddedToMix(jitterBufferLengthSamples)) {
// this is a ring buffer that is ready to go // this is a ring buffer that is ready to go
// set its flag so we know to push its buffer when all is said and done // set its flag so we know to push its buffer when all is said and done
@ -113,7 +113,7 @@ void AudioMixerClientData::checkBuffersBeforeFrameSend(int jitterBufferLengthSam
} }
void AudioMixerClientData::pushBuffersAfterFrameSend() { void AudioMixerClientData::pushBuffersAfterFrameSend() {
for (unsigned int i = 0; i < _ringBuffers.size(); i++) { for (int i = 0; i < _ringBuffers.size(); i++) {
// this was a used buffer, push the output pointer forwards // this was a used buffer, push the output pointer forwards
PositionalAudioRingBuffer* audioBuffer = _ringBuffers[i]; PositionalAudioRingBuffer* audioBuffer = _ringBuffers[i];

View file

@ -659,7 +659,7 @@ void DomainServer::readAvailableDatagrams() {
wasNoisyTimerStarted = true; wasNoisyTimerStarted = true;
} }
const quint64 NOISY_MESSAGE_INTERVAL_MSECS = 5 * 1000; const qint64 NOISY_MESSAGE_INTERVAL_MSECS = 5 * 1000;
if (requestAssignment.getType() != Assignment::AgentType if (requestAssignment.getType() != Assignment::AgentType
|| noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) { || noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) {

View file

@ -691,6 +691,10 @@ function rayPlaneIntersection(pickRay, point, normal) {
} }
function mousePressEvent(event) { function mousePressEvent(event) {
if (altIsPressed) {
return;
}
mouseLastPosition = { x: event.x, y: event.y }; mouseLastPosition = { x: event.x, y: event.y };
modelSelected = false; modelSelected = false;
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
@ -790,6 +794,10 @@ var oldModifier = 0;
var modifier = 0; var modifier = 0;
var wasShifted = false; var wasShifted = false;
function mouseMoveEvent(event) { function mouseMoveEvent(event) {
if (altIsPressed) {
return;
}
var pickRay = Camera.computePickRay(event.x, event.y); var pickRay = Camera.computePickRay(event.x, event.y);
if (!modelSelected) { if (!modelSelected) {
@ -894,6 +902,10 @@ function mouseMoveEvent(event) {
} }
function mouseReleaseEvent(event) { function mouseReleaseEvent(event) {
if (altIsPressed) {
return;
}
modelSelected = false; modelSelected = false;
glowedModelID.id = -1; glowedModelID.id = -1;
@ -962,4 +974,16 @@ Menu.menuItemEvent.connect(function(menuItem){
} }
}); });
// handling of inspect.js concurrence
altIsPressed = false;
Controller.keyPressEvent.connect(function(event) {
if (event.text == "ALT") {
altIsPressed = true;
}
});
Controller.keyReleaseEvent.connect(function(event) {
if (event.text == "ALT") {
altIsPressed = false;
}
});

View file

@ -34,6 +34,7 @@ var noMode = 0;
var orbitMode = 1; var orbitMode = 1;
var radialMode = 2; var radialMode = 2;
var panningMode = 3; var panningMode = 3;
var detachedMode = 4;
var mode = noMode; var mode = noMode;
@ -48,6 +49,9 @@ var radius = 0.0;
var azimuth = 0.0; var azimuth = 0.0;
var altitude = 0.0; var altitude = 0.0;
var avatarPosition;
var avatarOrientation;
function handleRadialMode(dx, dy) { function handleRadialMode(dx, dy) {
azimuth += dx / AZIMUTH_RATE; azimuth += dx / AZIMUTH_RATE;
@ -108,7 +112,7 @@ function restoreCameraState() {
} }
function handleModes() { function handleModes() {
var newMode = noMode; var newMode = (mode == noMode) ? noMode : detachedMode;
if (alt) { if (alt) {
if (control) { if (control) {
if (shift) { if (shift) {
@ -121,6 +125,22 @@ function handleModes() {
} }
} }
// if entering detachMode
if (newMode == detachedMode && mode != detachedMode) {
avatarPosition = MyAvatar.position;
avatarOrientation = MyAvatar.orientation;
}
// if leaving detachMode
if (mode == detachedMode && newMode == detachedMode &&
(avatarPosition.x != MyAvatar.position.x ||
avatarPosition.y != MyAvatar.position.y ||
avatarPosition.z != MyAvatar.position.z ||
avatarOrientation.x != MyAvatar.orientation.x ||
avatarOrientation.y != MyAvatar.orientation.y ||
avatarOrientation.z != MyAvatar.orientation.z ||
avatarOrientation.w != MyAvatar.orientation.w)) {
newMode = noMode;
}
// if leaving noMode // if leaving noMode
if (mode == noMode && newMode != noMode) { if (mode == noMode && newMode != noMode) {
saveCameraState(); saveCameraState();
@ -177,30 +197,45 @@ function keyReleaseEvent(event) {
function mousePressEvent(event) { function mousePressEvent(event) {
if (alt && !isActive) { if (alt && !isActive) {
isActive = true;
mouseLastX = event.x; mouseLastX = event.x;
mouseLastY = event.y; mouseLastY = event.y;
// Compute trajectories related values // Compute trajectories related values
var pickRay = Camera.computePickRay(mouseLastX, mouseLastY); var pickRay = Camera.computePickRay(mouseLastX, mouseLastY);
var intersection = Voxels.findRayIntersection(pickRay); var voxelIntersection = Voxels.findRayIntersection(pickRay);
var modelIntersection = Models.findRayIntersection(pickRay);
position = Camera.getPosition(); position = Camera.getPosition();
avatarTarget = MyAvatar.getTargetAvatarPosition(); var avatarTarget = MyAvatar.getTargetAvatarPosition();
voxelTarget = intersection.intersection; var voxelTarget = voxelIntersection.intersection;
if (Vec3.length(Vec3.subtract(avatarTarget, position)) < Vec3.length(Vec3.subtract(voxelTarget, position))) {
if (avatarTarget.x != 0 || avatarTarget.y != 0 || avatarTarget.z != 0) {
center = avatarTarget; var distance = -1;
} else { var string;
center = voxelTarget;
if (modelIntersection.intersects && modelIntersection.accurate) {
distance = modelIntersection.distance;
center = modelIntersection.modelProperties.position;
string = "Inspecting model";
} }
} else {
if (voxelTarget.x != 0 || voxelTarget.y != 0 || voxelTarget.z != 0) { if ((distance == -1 || Vec3.length(Vec3.subtract(avatarTarget, position)) < distance) &&
center = voxelTarget; (avatarTarget.x != 0 || avatarTarget.y != 0 || avatarTarget.z != 0)) {
} else { distance = Vec3.length(Vec3.subtract(avatarTarget, position));
center = avatarTarget; center = avatarTarget;
string = "Inspecting avatar";
} }
if ((distance == -1 || Vec3.length(Vec3.subtract(voxelTarget, position)) < distance) &&
(voxelTarget.x != 0 || voxelTarget.y != 0 || voxelTarget.z != 0)) {
distance = Vec3.length(Vec3.subtract(voxelTarget, position));
center = voxelTarget;
string = "Inspecting voxel";
}
if (distance == -1) {
return;
} }
vector = Vec3.subtract(position, center); vector = Vec3.subtract(position, center);
@ -209,6 +244,8 @@ function mousePressEvent(event) {
altitude = Math.asin(vector.y / Vec3.length(vector)); altitude = Math.asin(vector.y / Vec3.length(vector));
Camera.keepLookingAt(center); Camera.keepLookingAt(center);
print(string);
isActive = true;
} }
} }
@ -235,6 +272,10 @@ function mouseMoveEvent(event) {
} }
} }
function update() {
handleModes();
}
function scriptEnding() { function scriptEnding() {
if (mode != noMode) { if (mode != noMode) {
restoreCameraState(); restoreCameraState();
@ -248,4 +289,5 @@ Controller.mousePressEvent.connect(mousePressEvent);
Controller.mouseReleaseEvent.connect(mouseReleaseEvent); Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
Controller.mouseMoveEvent.connect(mouseMoveEvent); Controller.mouseMoveEvent.connect(mouseMoveEvent);
Script.update.connect(update);
Script.scriptEnding.connect(scriptEnding); Script.scriptEnding.connect(scriptEnding);

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View file

@ -1419,7 +1419,7 @@ bool Audio::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo)
// proportional to the accelerator ratio. // proportional to the accelerator ratio.
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
const float Audio::CALLBACK_ACCELERATOR_RATIO = 0.4f; const float Audio::CALLBACK_ACCELERATOR_RATIO = 0.1f;
#endif #endif
#ifdef Q_OS_MAC #ifdef Q_OS_MAC

View file

@ -45,6 +45,7 @@
#include "ui/ModelsBrowser.h" #include "ui/ModelsBrowser.h"
#include "ui/LoginDialog.h" #include "ui/LoginDialog.h"
#include "ui/NodeBounds.h" #include "ui/NodeBounds.h"
#include "devices/OculusManager.h"
Menu* Menu::_instance = NULL; Menu* Menu::_instance = NULL;
@ -83,6 +84,7 @@ Menu::Menu() :
_audioJitterBufferSamples(0), _audioJitterBufferSamples(0),
_bandwidthDialog(NULL), _bandwidthDialog(NULL),
_fieldOfView(DEFAULT_FIELD_OF_VIEW_DEGREES), _fieldOfView(DEFAULT_FIELD_OF_VIEW_DEGREES),
_realWorldFieldOfView(DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES),
_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),
@ -91,6 +93,9 @@ Menu::Menu() :
_lodToolsDialog(NULL), _lodToolsDialog(NULL),
_maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM), _maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM),
_voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE), _voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE),
_oculusUIAngularSize(DEFAULT_OCULUS_UI_ANGULAR_SIZE),
_sixenseReticleMoveSpeed(DEFAULT_SIXENSE_RETICLE_MOVE_SPEED),
_invertSixenseButtons(DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS),
_automaticAvatarLOD(true), _automaticAvatarLOD(true),
_avatarLODDecreaseFPS(DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS), _avatarLODDecreaseFPS(DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS),
_avatarLODIncreaseFPS(ADJUST_LOD_UP_FPS), _avatarLODIncreaseFPS(ADJUST_LOD_UP_FPS),
@ -165,6 +170,8 @@ Menu::Menu() :
Qt::Key_At, Qt::Key_At,
this, this,
SLOT(goTo())); SLOT(goTo()));
connect(&LocationManager::getInstance(), &LocationManager::multipleDestinationsFound,
this, &Menu::multipleDestinationsDecision);
addDisabledActionAndSeparator(fileMenu, "Upload Avatar Model"); addDisabledActionAndSeparator(fileMenu, "Upload Avatar Model");
addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadHead, 0, Application::getInstance(), SLOT(uploadHead())); addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadHead, 0, Application::getInstance(), SLOT(uploadHead()));
@ -387,7 +394,6 @@ Menu::Menu() :
QMenu* sixenseOptionsMenu = developerMenu->addMenu("Sixense Options"); QMenu* sixenseOptionsMenu = developerMenu->addMenu("Sixense Options");
addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseMouseInput, 0, true); addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseMouseInput, 0, true);
addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseInvertInputButtons, 0, false);
QMenu* handOptionsMenu = developerMenu->addMenu("Hand Options"); QMenu* handOptionsMenu = developerMenu->addMenu("Hand Options");
@ -1072,9 +1078,7 @@ bool Menu::goToURL(QString location) {
} }
void Menu::goToUser(const QString& user) { void Menu::goToUser(const QString& user) {
LocationManager* manager = &LocationManager::getInstance(); LocationManager::getInstance().goTo(user);
manager->goTo(user);
connect(manager, &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision);
} }
/// Open a url, shortcutting any "hifi" scheme URLs to the local application. /// Open a url, shortcutting any "hifi" scheme URLs to the local application.
@ -1096,13 +1100,10 @@ void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJson
int userResponse = msgBox.exec(); int userResponse = msgBox.exec();
if (userResponse == QMessageBox::Ok) { if (userResponse == QMessageBox::Ok) {
Application::getInstance()->getAvatar()->goToLocationFromResponse(userData); Application::getInstance()->getAvatar()->goToLocationFromAddress(userData["address"].toObject());
} else if (userResponse == QMessageBox::Open) { } else if (userResponse == QMessageBox::Open) {
Application::getInstance()->getAvatar()->goToLocationFromResponse(userData); Application::getInstance()->getAvatar()->goToLocationFromAddress(placeData["address"].toObject());
} }
LocationManager* manager = reinterpret_cast<LocationManager*>(sender());
disconnect(manager, &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision);
} }
void Menu::muteEnvironment() { void Menu::muteEnvironment() {

View file

@ -90,6 +90,12 @@ public:
void setFieldOfView(float fieldOfView) { _fieldOfView = fieldOfView; } void setFieldOfView(float fieldOfView) { _fieldOfView = fieldOfView; }
float getRealWorldFieldOfView() const { return _realWorldFieldOfView; } float getRealWorldFieldOfView() const { return _realWorldFieldOfView; }
void setRealWorldFieldOfView(float realWorldFieldOfView) { _realWorldFieldOfView = realWorldFieldOfView; } void setRealWorldFieldOfView(float realWorldFieldOfView) { _realWorldFieldOfView = realWorldFieldOfView; }
float getOculusUIAngularSize() const { return _oculusUIAngularSize; }
void setOculusUIAngularSize(float oculusUIAngularSize) { _oculusUIAngularSize = oculusUIAngularSize; }
float getSixenseReticleMoveSpeed() const { return _sixenseReticleMoveSpeed; }
void setSixenseReticleMoveSpeed(float sixenseReticleMoveSpeed) { _sixenseReticleMoveSpeed = sixenseReticleMoveSpeed; }
bool getInvertSixenseButtons() const { return _invertSixenseButtons; }
void setInvertSixenseButtons(bool invertSixenseButtons) { _invertSixenseButtons = invertSixenseButtons; }
float getFaceshiftEyeDeflection() const { return _faceshiftEyeDeflection; } float getFaceshiftEyeDeflection() const { return _faceshiftEyeDeflection; }
void setFaceshiftEyeDeflection(float faceshiftEyeDeflection) { _faceshiftEyeDeflection = faceshiftEyeDeflection; } void setFaceshiftEyeDeflection(float faceshiftEyeDeflection) { _faceshiftEyeDeflection = faceshiftEyeDeflection; }
@ -255,6 +261,9 @@ private:
LodToolsDialog* _lodToolsDialog; LodToolsDialog* _lodToolsDialog;
int _maxVoxels; int _maxVoxels;
float _voxelSizeScale; float _voxelSizeScale;
float _oculusUIAngularSize;
float _sixenseReticleMoveSpeed;
bool _invertSixenseButtons;
bool _automaticAvatarLOD; bool _automaticAvatarLOD;
float _avatarLODDecreaseFPS; float _avatarLODDecreaseFPS;
float _avatarLODIncreaseFPS; float _avatarLODIncreaseFPS;
@ -400,7 +409,6 @@ namespace MenuOption {
const QString SettingsExport = "Export Settings"; const QString SettingsExport = "Export Settings";
const QString SettingsImport = "Import Settings"; const QString SettingsImport = "Import Settings";
const QString SimpleShadows = "Simple"; const QString SimpleShadows = "Simple";
const QString SixenseInvertInputButtons = "Invert Sixense Mouse Input Buttons";
const QString SixenseMouseInput = "Enable Sixense Mouse Input"; const QString SixenseMouseInput = "Enable Sixense Mouse Input";
const QString ShowBordersVoxelNodes = "Show Voxel Nodes"; const QString ShowBordersVoxelNodes = "Show Voxel Nodes";
const QString ShowBordersModelNodes = "Show Model Nodes"; const QString ShowBordersModelNodes = "Show Model Nodes";

View file

@ -21,6 +21,8 @@
#include <SharedUtil.h> #include <SharedUtil.h>
#include <QThread>
#include "InterfaceConfig.h" #include "InterfaceConfig.h"
#include "ui/TextRenderer.h" #include "ui/TextRenderer.h"
#include "VoxelConstants.h" #include "VoxelConstants.h"
@ -409,7 +411,43 @@ void runTimingTests() {
float NSEC_TO_USEC = 1.0f / 1000.0f; float NSEC_TO_USEC = 1.0f / 1000.0f;
elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
qDebug("QElapsedTimer::nsecElapsed() usecs: %f", elapsedUsecs / (float) numTests); qDebug("QElapsedTimer::nsecElapsed() usecs: %f", elapsedUsecs);
// Test sleep functions for accuracy
startTime.start();
QThread::msleep(1);
elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
qDebug("QThread::msleep(1) ms: %f", elapsedUsecs / 1000.0f);
startTime.start();
QThread::sleep(1);
elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
qDebug("QThread::sleep(1) ms: %f", elapsedUsecs / 1000.0f);
startTime.start();
usleep(1);
elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
qDebug("usleep(1) ms: %f", elapsedUsecs / 1000.0f);
startTime.start();
usleep(10);
elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
qDebug("usleep(10) ms: %f", elapsedUsecs / 1000.0f);
startTime.start();
usleep(100);
elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
qDebug("usleep(100) ms: %f", elapsedUsecs / 1000.0f);
startTime.start();
usleep(1000);
elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
qDebug("usleep(1000) ms: %f", elapsedUsecs / 1000.0f);
startTime.start();
usleep(15000);
elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
qDebug("usleep(15000) ms: %f", elapsedUsecs / 1000.0f);
// Random number generation // Random number generation
startTime.start(); startTime.start();

View file

@ -1626,13 +1626,18 @@ void MyAvatar::resetSize() {
} }
void MyAvatar::goToLocationFromResponse(const QJsonObject& jsonObject) { void MyAvatar::goToLocationFromResponse(const QJsonObject& jsonObject) {
if (jsonObject["status"].toString() == "success") { if (jsonObject["status"].toString() == "success") {
QJsonObject locationObject = jsonObject["data"].toObject()["address"].toObject();
goToLocationFromAddress(locationObject);
} else {
QMessageBox::warning(Application::getInstance()->getWindow(), "", "That user or location could not be found.");
}
}
void MyAvatar::goToLocationFromAddress(const QJsonObject& locationObject) {
// send a node kill request, indicating to other clients that they should play the "disappeared" effect // send a node kill request, indicating to other clients that they should play the "disappeared" effect
sendKillAvatar(); sendKillAvatar();
QJsonObject locationObject = jsonObject["data"].toObject()["address"].toObject();
QString positionString = locationObject["position"].toString(); QString positionString = locationObject["position"].toString();
QString orientationString = locationObject["orientation"].toString(); QString orientationString = locationObject["orientation"].toString();
QString domainHostnameString = locationObject["domain"].toString(); QString domainHostnameString = locationObject["domain"].toString();
@ -1659,9 +1664,6 @@ void MyAvatar::goToLocationFromResponse(const QJsonObject& jsonObject) {
coordinateItems[2].toFloat()) - newOrientation * IDENTITY_FRONT * DISTANCE_TO_USER; coordinateItems[2].toFloat()) - newOrientation * IDENTITY_FRONT * DISTANCE_TO_USER;
setPosition(newPosition); setPosition(newPosition);
emit transformChanged(); emit transformChanged();
} else {
QMessageBox::warning(Application::getInstance()->getWindow(), "", "That user or location could not be found.");
}
} }
void MyAvatar::updateMotionBehaviorsFromMenu() { void MyAvatar::updateMotionBehaviorsFromMenu() {

View file

@ -129,6 +129,7 @@ public slots:
void resetSize(); void resetSize();
void goToLocationFromResponse(const QJsonObject& jsonObject); void goToLocationFromResponse(const QJsonObject& jsonObject);
void goToLocationFromAddress(const QJsonObject& jsonObject);
// Set/Get update the thrust that will move the avatar around // Set/Get update the thrust that will move the avatar around
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };

View file

@ -20,6 +20,8 @@
#include "renderer/ProgramObject.h" #include "renderer/ProgramObject.h"
const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f;
class Camera; class Camera;
/// Handles interaction with the Oculus Rift. /// Handles interaction with the Oculus Rift.

View file

@ -185,6 +185,17 @@ void SixenseManager::update(float deltaTime) {
#endif // HAVE_SIXENSE #endif // HAVE_SIXENSE
} }
//Constants for getCursorPixelRangeMultiplier()
const float MIN_PIXEL_RANGE_MULT = 0.4f;
const float MAX_PIXEL_RANGE_MULT = 2.0f;
const float RANGE_MULT = (MAX_PIXEL_RANGE_MULT - MIN_PIXEL_RANGE_MULT) * 0.01;
//Returns a multiplier to be applied to the cursor range for the controllers
float SixenseManager::getCursorPixelRangeMult() const {
//scales (0,100) to (MINIMUM_PIXEL_RANGE_MULT, MAXIMUM_PIXEL_RANGE_MULT)
return Menu::getInstance()->getSixenseReticleMoveSpeed() * RANGE_MULT + MIN_PIXEL_RANGE_MULT;
}
#ifdef HAVE_SIXENSE #ifdef HAVE_SIXENSE
// the calibration sequence is: // the calibration sequence is:
@ -339,7 +350,7 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) {
Qt::MouseButton bumperButton; Qt::MouseButton bumperButton;
Qt::MouseButton triggerButton; Qt::MouseButton triggerButton;
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseInvertInputButtons)) { if (Menu::getInstance()->getInvertSixenseButtons()) {
bumperButton = Qt::LeftButton; bumperButton = Qt::LeftButton;
triggerButton = Qt::RightButton; triggerButton = Qt::RightButton;
} else { } else {
@ -347,14 +358,15 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) {
triggerButton = Qt::LeftButton; triggerButton = Qt::LeftButton;
} }
// Get the angles, scaled between 0-1 // Get the angles, scaled between (-0.5,0.5)
float xAngle = (atan2(direction.z, direction.x) + M_PI_2) + 0.5f; float xAngle = (atan2(direction.z, direction.x) + M_PI_2);
float yAngle = 1.0f - ((atan2(direction.z, direction.y) + M_PI_2) + 0.5f); float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2));
float cursorRange = widget->width(); // Get the pixel range over which the xAngle and yAngle are scaled
float cursorRange = widget->width() * getCursorPixelRangeMult();
pos.setX(cursorRange * xAngle); pos.setX(widget->width() / 2.0f + cursorRange * xAngle);
pos.setY(cursorRange * yAngle); pos.setY(widget->height() / 2.0f + cursorRange * yAngle);
//If we are off screen then we should stop processing, and if a trigger or bumper is pressed, //If we are off screen then we should stop processing, and if a trigger or bumper is pressed,
//we should unpress them. //we should unpress them.

View file

@ -30,6 +30,9 @@ const unsigned int BUTTON_FWD = 1U << 7;
// Event type that represents moving the controller // Event type that represents moving the controller
const unsigned int CONTROLLER_MOVE_EVENT = 1500U; const unsigned int CONTROLLER_MOVE_EVENT = 1500U;
const float DEFAULT_SIXENSE_RETICLE_MOVE_SPEED = 37.5f;
const bool DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS = false;
/// Handles interaction with the Sixense SDK (e.g., Razer Hydra). /// Handles interaction with the Sixense SDK (e.g., Razer Hydra).
class SixenseManager : public QObject { class SixenseManager : public QObject {
Q_OBJECT Q_OBJECT
@ -39,6 +42,7 @@ public:
~SixenseManager(); ~SixenseManager();
void update(float deltaTime); void update(float deltaTime);
float getCursorPixelRangeMult() const;
public slots: public slots:

View file

@ -16,10 +16,11 @@
const QString GET_USER_ADDRESS = "/api/v1/users/%1/address"; const QString GET_USER_ADDRESS = "/api/v1/users/%1/address";
const QString GET_PLACE_ADDRESS = "/api/v1/places/%1/address"; const QString GET_PLACE_ADDRESS = "/api/v1/places/%1/address";
const QString GET_ADDRESSES = "/api/v1/addresses/%1";
const QString POST_PLACE_CREATE = "/api/v1/places/"; const QString POST_PLACE_CREATE = "/api/v1/places/";
LocationManager::LocationManager() : _userData(), _placeData() { LocationManager::LocationManager() {
}; };
@ -74,58 +75,38 @@ void LocationManager::goTo(QString destination) {
// go to coordinate destination or to Username // go to coordinate destination or to Username
if (!goToDestination(destination)) { if (!goToDestination(destination)) {
// reset data on local variables destination = QString(QUrl::toPercentEncoding(destination));
_userData = QJsonObject();
_placeData = QJsonObject();
JSONCallbackParameters callbackParams; JSONCallbackParameters callbackParams;
callbackParams.jsonCallbackReceiver = this; callbackParams.jsonCallbackReceiver = this;
callbackParams.jsonCallbackMethod = "goToUserFromResponse"; callbackParams.jsonCallbackMethod = "goToAddressFromResponse";
AccountManager::getInstance().authenticatedRequest(GET_USER_ADDRESS.arg(destination), AccountManager::getInstance().authenticatedRequest(GET_ADDRESSES.arg(destination),
QNetworkAccessManager::GetOperation,
callbackParams);
callbackParams.jsonCallbackMethod = "goToLocationFromResponse";
AccountManager::getInstance().authenticatedRequest(GET_PLACE_ADDRESS.arg(destination),
QNetworkAccessManager::GetOperation, QNetworkAccessManager::GetOperation,
callbackParams); callbackParams);
} }
} }
void LocationManager::goToUserFromResponse(const QJsonObject& jsonObject) { void LocationManager::goToAddressFromResponse(const QJsonObject& responseData) {
_userData = jsonObject; QJsonValue status = responseData["status"];
checkForMultipleDestinations(); qDebug() << responseData;
} if (!status.isUndefined() && status.toString() == "success") {
const QJsonObject& data = responseData["data"].toObject();
const QJsonValue& userObject = data["user"];
const QJsonValue& placeObject = data["place"];
void LocationManager::goToLocationFromResponse(const QJsonObject& jsonObject) { if (!placeObject.isUndefined() && !userObject.isUndefined()) {
_placeData = jsonObject; emit multipleDestinationsFound(userObject.toObject(), placeObject.toObject());
checkForMultipleDestinations(); } else if (placeObject.isUndefined()) {
} Application::getInstance()->getAvatar()->goToLocationFromAddress(userObject.toObject()["address"].toObject());
} else {
void LocationManager::checkForMultipleDestinations() { Application::getInstance()->getAvatar()->goToLocationFromAddress(placeObject.toObject()["address"].toObject());
if (!_userData.isEmpty() && !_placeData.isEmpty()) {
if (_userData.contains("status") && _userData["status"].toString() == "success" &&
_placeData.contains("status") && _placeData["status"].toString() == "success") {
emit multipleDestinationsFound(_userData, _placeData);
return;
} }
} else {
if (_userData.contains("status") && _userData["status"].toString() == "success") {
Application::getInstance()->getAvatar()->goToLocationFromResponse(_userData);
return;
}
if (_placeData.contains("status") && _placeData["status"].toString() == "success") {
Application::getInstance()->getAvatar()->goToLocationFromResponse(_placeData);
return;
}
QMessageBox::warning(Application::getInstance()->getWindow(), "", "That user or location could not be found."); QMessageBox::warning(Application::getInstance()->getWindow(), "", "That user or location could not be found.");
} }
} }
void LocationManager::goToUser(QString userName) { void LocationManager::goToUser(QString userName) {
JSONCallbackParameters callbackParams; JSONCallbackParameters callbackParams;
callbackParams.jsonCallbackReceiver = Application::getInstance()->getAvatar(); callbackParams.jsonCallbackReceiver = Application::getInstance()->getAvatar();
callbackParams.jsonCallbackMethod = "goToLocationFromResponse"; callbackParams.jsonCallbackMethod = "goToLocationFromResponse";

View file

@ -39,11 +39,7 @@ public:
bool goToDestination(QString destination); bool goToDestination(QString destination);
private: private:
QJsonObject _userData;
QJsonObject _placeData;
void replaceLastOccurrence(const QChar search, const QChar replace, QString& string); void replaceLastOccurrence(const QChar search, const QChar replace, QString& string);
void checkForMultipleDestinations();
signals: signals:
void creationCompleted(LocationManager::NamedLocationCreateResponse response); void creationCompleted(LocationManager::NamedLocationCreateResponse response);
@ -52,8 +48,7 @@ signals:
private slots: private slots:
void namedLocationDataReceived(const QJsonObject& data); void namedLocationDataReceived(const QJsonObject& data);
void errorDataReceived(QNetworkReply::NetworkError error, const QString& message); void errorDataReceived(QNetworkReply::NetworkError error, const QString& message);
void goToLocationFromResponse(const QJsonObject& jsonObject); void goToAddressFromResponse(const QJsonObject& jsonObject);
void goToUserFromResponse(const QJsonObject& jsonObject);
}; };

View file

@ -33,8 +33,8 @@ ApplicationOverlay::ApplicationOverlay() :
_framebufferObject(NULL), _framebufferObject(NULL),
_oculusAngle(65.0f * RADIANS_PER_DEGREE), _oculusAngle(65.0f * RADIANS_PER_DEGREE),
_distance(0.5f), _distance(0.5f),
_textureFov(PI / 2.5f), _textureFov(DEFAULT_OCULUS_UI_ANGULAR_SIZE * RADIANS_PER_DEGREE),
_uiType(HEMISPHERE) { _crosshairTexture(0) {
} }
@ -46,10 +46,14 @@ ApplicationOverlay::~ApplicationOverlay() {
const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f }; const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f };
const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f };
// Renders the overlays either to a texture or to the screen // Renders the overlays either to a texture or to the screen
void ApplicationOverlay::renderOverlay(bool renderToTexture) { void ApplicationOverlay::renderOverlay(bool renderToTexture) {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");
_textureFov = Menu::getInstance()->getOculusUIAngularSize() * RADIANS_PER_DEGREE;
Application* application = Application::getInstance(); Application* application = Application::getInstance();
Overlays& overlays = application->getOverlays(); Overlays& overlays = application->getOverlays();
@ -150,32 +154,10 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
Application* application = Application::getInstance(); Application* application = Application::getInstance();
QGLWidget* glWidget = application->getGLWidget();
MyAvatar* myAvatar = application->getAvatar(); MyAvatar* myAvatar = application->getAvatar();
const glm::vec3& viewMatrixTranslation = application->getViewMatrixTranslation(); const glm::vec3& viewMatrixTranslation = application->getViewMatrixTranslation();
// Get vertical FoV of the displayed overlay texture
const float halfVerticalAngle = _oculusAngle / 2.0f;
const float overlayAspectRatio = glWidget->width() / (float)glWidget->height();
const float halfOverlayHeight = _distance * tan(halfVerticalAngle);
const float overlayHeight = halfOverlayHeight * 2.0f;
// The more vertices, the better the curve
const int numHorizontalVertices = 20;
const int numVerticalVertices = 20;
// U texture coordinate width at each quad
const float quadTexWidth = 1.0f / (numHorizontalVertices - 1);
const float quadTexHeight = 1.0f / (numVerticalVertices - 1);
// Get horizontal angle and angle increment from vertical angle and aspect ratio
const float horizontalAngle = halfVerticalAngle * 2.0f * overlayAspectRatio;
const float angleIncrement = horizontalAngle / (numHorizontalVertices - 1);
const float halfHorizontalAngle = horizontalAngle / 2;
const float verticalAngleIncrement = _oculusAngle / (numVerticalVertices - 1);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glEnable(GL_BLEND); glEnable(GL_BLEND);
@ -210,8 +192,6 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
glEnable(GL_ALPHA_TEST); glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.01f); glAlphaFunc(GL_GREATER, 0.01f);
float leftX, rightX, leftZ, rightZ, topZ, bottomZ;
//Draw the magnifiers //Draw the magnifiers
for (int i = 0; i < _numMagnifiers; i++) { for (int i = 0; i < _numMagnifiers; i++) {
renderMagnifier(_mouseX[i], _mouseY[i]); renderMagnifier(_mouseX[i], _mouseY[i]);
@ -220,41 +200,9 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
glDepthMask(GL_FALSE); glDepthMask(GL_FALSE);
glDisable(GL_ALPHA_TEST); glDisable(GL_ALPHA_TEST);
//TODO: Remove immediate mode in favor of VBO
if (_uiType == HEMISPHERE) {
renderTexturedHemisphere(); renderTexturedHemisphere();
} else{
glBegin(GL_QUADS);
// Place the vertices in a semicircle curve around the camera
for (int i = 0; i < numHorizontalVertices - 1; i++) {
for (int j = 0; j < numVerticalVertices - 1; j++) {
// Calculate the X and Z coordinates from the angles and radius from camera renderControllerPointersOculus();
leftX = sin(angleIncrement * i - halfHorizontalAngle) * _distance;
rightX = sin(angleIncrement * (i + 1) - halfHorizontalAngle) * _distance;
leftZ = -cos(angleIncrement * i - halfHorizontalAngle) * _distance;
rightZ = -cos(angleIncrement * (i + 1) - halfHorizontalAngle) * _distance;
if (_uiType == 2) {
topZ = -cos((verticalAngleIncrement * (j + 1) - halfVerticalAngle) * overlayAspectRatio) * _distance;
bottomZ = -cos((verticalAngleIncrement * j - halfVerticalAngle) * overlayAspectRatio) * _distance;
} else {
topZ = -99999;
bottomZ = -99999;
}
glTexCoord2f(quadTexWidth * i, (j + 1) * quadTexHeight);
glVertex3f(leftX, (j + 1) * quadTexHeight * overlayHeight - halfOverlayHeight, max(topZ, leftZ));
glTexCoord2f(quadTexWidth * (i + 1), (j + 1) * quadTexHeight);
glVertex3f(rightX, (j + 1) * quadTexHeight * overlayHeight - halfOverlayHeight, max(topZ, rightZ));
glTexCoord2f(quadTexWidth * (i + 1), j * quadTexHeight);
glVertex3f(rightX, j * quadTexHeight * overlayHeight - halfOverlayHeight, max(bottomZ, rightZ));
glTexCoord2f(quadTexWidth * i, j * quadTexHeight);
glVertex3f(leftX, j * quadTexHeight * overlayHeight - halfOverlayHeight, max(bottomZ, leftZ));
}
}
glEnd();
}
glPopMatrix(); glPopMatrix();
@ -272,51 +220,37 @@ void ApplicationOverlay::renderPointers() {
Application* application = Application::getInstance(); Application* application = Application::getInstance();
// Render a crosshair over the mouse when in Oculus // Render a crosshair over the mouse when in Oculus
_numMagnifiers = 0; _numMagnifiers = 0;
int mouseX = application->getMouseX();
int mouseY = application->getMouseY(); //lazily load crosshair texture
if (_crosshairTexture == 0) {
_crosshairTexture = Application::getInstance()->getGLWidget()->bindTexture(QImage(Application::resourcesPath() + "images/sixense-reticle.png"));
}
glEnable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _crosshairTexture);
if (OculusManager::isConnected() && application->getLastMouseMoveType() == QEvent::MouseMove) { if (OculusManager::isConnected() && application->getLastMouseMoveType() == QEvent::MouseMove) {
const float pointerWidth = 10; //If we are in oculus, render reticle later
const float pointerHeight = 10;
const float crossPad = 4;
_numMagnifiers = 1; _numMagnifiers = 1;
_mouseX[0] = application->getMouseX(); _mouseX[0] = application->getMouseX();
_mouseY[0] = application->getMouseY(); _mouseY[0] = application->getMouseY();
mouseX -= pointerWidth / 2.0f;
mouseY += pointerHeight / 2.0f;
glBegin(GL_QUADS);
glColor3f(1, 0, 0);
//Horizontal crosshair
glVertex2i(mouseX, mouseY - crossPad);
glVertex2i(mouseX + pointerWidth, mouseY - crossPad);
glVertex2i(mouseX + pointerWidth, mouseY - pointerHeight + crossPad);
glVertex2i(mouseX, mouseY - pointerHeight + crossPad);
//Vertical crosshair
glVertex2i(mouseX + crossPad, mouseY);
glVertex2i(mouseX + pointerWidth - crossPad, mouseY);
glVertex2i(mouseX + pointerWidth - crossPad, mouseY - pointerHeight);
glVertex2i(mouseX + crossPad, mouseY - pointerHeight);
glEnd();
} else if (application->getLastMouseMoveType() == CONTROLLER_MOVE_EVENT && Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) { } else if (application->getLastMouseMoveType() == CONTROLLER_MOVE_EVENT && Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) {
//only render controller pointer if we aren't already rendering a mouse pointer //only render controller pointer if we aren't already rendering a mouse pointer
renderControllerPointer(); renderControllerPointers();
} }
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
} }
void ApplicationOverlay::renderControllerPointer() { void ApplicationOverlay::renderControllerPointers() {
Application* application = Application::getInstance(); Application* application = Application::getInstance();
QGLWidget* glWidget = application->getGLWidget(); QGLWidget* glWidget = application->getGLWidget();
MyAvatar* myAvatar = application->getAvatar(); MyAvatar* myAvatar = application->getAvatar();
const HandData* handData = Application::getInstance()->getAvatar()->getHandData(); const HandData* handData = Application::getInstance()->getAvatar()->getHandData();
int numberOfPalms = handData->getNumPalms();
for (unsigned int palmIndex = 2; palmIndex < 4; palmIndex++) { for (unsigned int palmIndex = 2; palmIndex < 4; palmIndex++) {
const PalmData* palmData = NULL; const PalmData* palmData = NULL;
@ -334,14 +268,15 @@ void ApplicationOverlay::renderControllerPointer() {
// Get directon relative to avatar orientation // Get directon relative to avatar orientation
glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * palmData->getFingerDirection(); glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * palmData->getFingerDirection();
// Get the angles, scaled between 0-1 // Get the angles, scaled between (-0.5,0.5)
float xAngle = (atan2(direction.z, direction.x) + M_PI_2) + 0.5f; float xAngle = (atan2(direction.z, direction.x) + M_PI_2) ;
float yAngle = 1.0f - ((atan2(direction.z, direction.y) + M_PI_2) + 0.5f); float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2));
float cursorRange = glWidget->width(); // Get the pixel range over which the xAngle and yAngle are scaled
float cursorRange = glWidget->width() * application->getSixenseManager()->getCursorPixelRangeMult();
int mouseX = cursorRange * xAngle; int mouseX = glWidget->width() / 2.0f + cursorRange * xAngle;
int mouseY = cursorRange * yAngle; int mouseY = glWidget->height() / 2.0f + cursorRange * yAngle;
//If the cursor is out of the screen then don't render it //If the cursor is out of the screen then don't render it
if (mouseX < 0 || mouseX >= glWidget->width() || mouseY < 0 || mouseY >= glWidget->height()) { if (mouseX < 0 || mouseX >= glWidget->width() || mouseY < 0 || mouseY >= glWidget->height()) {
@ -350,18 +285,16 @@ void ApplicationOverlay::renderControllerPointer() {
float pointerWidth = 40; float pointerWidth = 40;
float pointerHeight = 40; float pointerHeight = 40;
float crossPad = 16;
//if we have the oculus, we should make the cursor smaller since it will be //if we have the oculus, we should make the cursor smaller since it will be
//magnified //magnified
if (OculusManager::isConnected()) { if (OculusManager::isConnected()) {
pointerWidth /= 4;
pointerHeight /= 4;
crossPad /= 4;
_mouseX[_numMagnifiers] = mouseX; _mouseX[_numMagnifiers] = mouseX;
_mouseY[_numMagnifiers] = mouseY; _mouseY[_numMagnifiers] = mouseY;
_numMagnifiers++; _numMagnifiers++;
//If oculus is enabled, we draw the crosshairs later
continue;
} }
mouseX -= pointerWidth / 2.0f; mouseX -= pointerWidth / 2.0f;
@ -369,70 +302,94 @@ void ApplicationOverlay::renderControllerPointer() {
glBegin(GL_QUADS); glBegin(GL_QUADS);
glColor3f(0.0f, 0.0f, 1.0f); glColor3f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2]);
//Horizontal crosshair glTexCoord2d(0.0f, 0.0f); glVertex2i(mouseX, mouseY);
glVertex2i(mouseX, mouseY - crossPad); glTexCoord2d(1.0f, 0.0f); glVertex2i(mouseX + pointerWidth, mouseY);
glVertex2i(mouseX + pointerWidth, mouseY - crossPad); glTexCoord2d(1.0f, 1.0f); glVertex2i(mouseX + pointerWidth, mouseY - pointerHeight);
glVertex2i(mouseX + pointerWidth, mouseY - pointerHeight + crossPad); glTexCoord2d(0.0f, 1.0f); glVertex2i(mouseX, mouseY - pointerHeight);
glVertex2i(mouseX, mouseY - pointerHeight + crossPad);
//Vertical crosshair
glVertex2i(mouseX + crossPad, mouseY);
glVertex2i(mouseX + pointerWidth - crossPad, mouseY);
glVertex2i(mouseX + pointerWidth - crossPad, mouseY - pointerHeight);
glVertex2i(mouseX + crossPad, mouseY - pointerHeight);
glEnd(); glEnd();
} }
} }
void ApplicationOverlay::renderControllerPointersOculus() {
Application* application = Application::getInstance();
QGLWidget* glWidget = application->getGLWidget();
const int widgetWidth = glWidget->width();
const int widgetHeight = glWidget->height();
const float reticleSize = 50.0f;
glBindTexture(GL_TEXTURE_2D, _crosshairTexture);
glDisable(GL_DEPTH_TEST);
for (int i = 0; i < _numMagnifiers; i++) {
float mouseX = (float)_mouseX[i];
float mouseY = (float)_mouseY[i];
mouseX -= reticleSize / 2;
mouseY += reticleSize / 2;
//Get new UV coordinates from our magnification window
float newULeft = mouseX / widgetWidth;
float newURight = (mouseX + reticleSize) / widgetWidth;
float newVBottom = 1.0 - mouseY / widgetHeight;
float newVTop = 1.0 - (mouseY - reticleSize) / widgetHeight;
// Project our position onto the hemisphere using the UV coordinates
float lX = sin((newULeft - 0.5f) * _textureFov);
float rX = sin((newURight - 0.5f) * _textureFov);
float bY = sin((newVBottom - 0.5f) * _textureFov);
float tY = sin((newVTop - 0.5f) * _textureFov);
float dist;
//Bottom Left
dist = sqrt(lX * lX + bY * bY);
float blZ = sqrt(1.0f - dist * dist);
//Top Left
dist = sqrt(lX * lX + tY * tY);
float tlZ = sqrt(1.0f - dist * dist);
//Bottom Right
dist = sqrt(rX * rX + bY * bY);
float brZ = sqrt(1.0f - dist * dist);
//Top Right
dist = sqrt(rX * rX + tY * tY);
float trZ = sqrt(1.0f - dist * dist);
glBegin(GL_QUADS);
glColor3f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2]);
glTexCoord2f(0.0f, 0.0f); glVertex3f(lX, tY, -tlZ);
glTexCoord2f(1.0f, 0.0f); glVertex3f(rX, tY, -trZ);
glTexCoord2f(1.0f, 1.0f); glVertex3f(rX, bY, -brZ);
glTexCoord2f(0.0f, 1.0f); glVertex3f(lX, bY, -blZ);
glEnd();
}
glEnable(GL_DEPTH_TEST);
}
//Renders a small magnification of the currently bound texture at the coordinates //Renders a small magnification of the currently bound texture at the coordinates
void ApplicationOverlay::renderMagnifier(int mouseX, int mouseY) void ApplicationOverlay::renderMagnifier(int mouseX, int mouseY)
{ {
Application* application = Application::getInstance(); Application* application = Application::getInstance();
QGLWidget* glWidget = application->getGLWidget(); QGLWidget* glWidget = application->getGLWidget();
MyAvatar* myAvatar = application->getAvatar();
const glm::vec3& viewMatrixTranslation = application->getViewMatrixTranslation();
float leftX, rightX, leftZ, rightZ, topZ, bottomZ;
const int widgetWidth = glWidget->width(); const int widgetWidth = glWidget->width();
const int widgetHeight = glWidget->height(); const int widgetHeight = glWidget->height();
const float magnification = 4.0f; const float magnification = 4.0f;
// Get vertical FoV of the displayed overlay texture
const float halfVerticalAngle = _oculusAngle / 2.0f;
const float overlayAspectRatio = glWidget->width() / (float)glWidget->height();
const float halfOverlayHeight = _distance * tan(halfVerticalAngle);
// Get horizontal angle and angle increment from vertical angle and aspect ratio
const float horizontalAngle = halfVerticalAngle * 2.0f * overlayAspectRatio;
const float halfHorizontalAngle = horizontalAngle / 2;
float magnifyWidth = 80.0f; float magnifyWidth = 80.0f;
float magnifyHeight = 60.0f; float magnifyHeight = 60.0f;
mouseX -= magnifyWidth / 2; mouseX -= magnifyWidth / 2;
mouseY -= magnifyHeight / 2; mouseY -= magnifyHeight / 2;
//clamp the magnification
if (mouseX < 0) {
magnifyWidth += mouseX;
mouseX = 0;
} else if (mouseX + magnifyWidth > widgetWidth) {
magnifyWidth = widgetWidth - mouseX;
}
if (mouseY < 0) {
magnifyHeight += mouseY;
mouseY = 0;
} else if (mouseY + magnifyHeight > widgetHeight) {
magnifyHeight = widgetHeight - mouseY;
}
const float halfMagnifyHeight = magnifyHeight / 2.0f;
float newWidth = magnifyWidth * magnification; float newWidth = magnifyWidth * magnification;
float newHeight = magnifyHeight * magnification; float newHeight = magnifyHeight * magnification;
@ -446,15 +403,7 @@ void ApplicationOverlay::renderMagnifier(int mouseX, int mouseY)
float newMouseX = (mouseX + magnifyWidth / 2) - newWidth / 2.0f; float newMouseX = (mouseX + magnifyWidth / 2) - newWidth / 2.0f;
float newMouseY = (mouseY + magnifyHeight / 2) + newHeight / 2.0f; float newMouseY = (mouseY + magnifyHeight / 2) + newHeight / 2.0f;
// Get angle on the UI
float leftAngle = (newMouseX / (float)widgetWidth) * horizontalAngle - halfHorizontalAngle;
float rightAngle = ((newMouseX + newWidth) / (float)widgetWidth) * horizontalAngle - halfHorizontalAngle;
float bottomAngle = (newMouseY / (float)widgetHeight) * _oculusAngle - halfVerticalAngle;
float topAngle = ((newMouseY - newHeight) / (float)widgetHeight) * _oculusAngle - halfVerticalAngle;
// Get position on hemisphere using angle // Get position on hemisphere using angle
if (_uiType == HEMISPHERE) {
//Get new UV coordinates from our magnification window //Get new UV coordinates from our magnification window
float newULeft = newMouseX / widgetWidth; float newULeft = newMouseX / widgetWidth;
@ -491,33 +440,6 @@ void ApplicationOverlay::renderMagnifier(int mouseX, int mouseY)
glEnd(); glEnd();
} else {
leftX = sin(leftAngle) * _distance;
rightX = sin(rightAngle) * _distance;
leftZ = -cos(leftAngle) * _distance;
rightZ = -cos(rightAngle) * _distance;
if (_uiType == CURVED_SEMICIRCLE) {
topZ = -cos(topAngle * overlayAspectRatio) * _distance;
bottomZ = -cos(bottomAngle * overlayAspectRatio) * _distance;
} else {
// Dont want to use topZ or bottomZ for SEMICIRCLE
topZ = -99999;
bottomZ = -99999;
}
float bottomY = (1.0 - newMouseY / (float)widgetHeight) * halfOverlayHeight * 2.0f - halfOverlayHeight;
float topY = bottomY + (newHeight / widgetHeight) * halfOverlayHeight * 2;
//TODO: Remove immediate mode in favor of VBO
glBegin(GL_QUADS);
glTexCoord2f(magnifyULeft, magnifyVBottom); glVertex3f(leftX, topY, max(topZ, leftZ));
glTexCoord2f(magnifyURight, magnifyVBottom); glVertex3f(rightX, topY, max(topZ, rightZ));
glTexCoord2f(magnifyURight, magnifyVTop); glVertex3f(rightX, bottomY, max(bottomZ, rightZ));
glTexCoord2f(magnifyULeft, magnifyVTop); glVertex3f(leftX, bottomY, max(bottomZ, leftZ));
glEnd();
}
} }
void ApplicationOverlay::renderAudioMeter() { void ApplicationOverlay::renderAudioMeter() {
@ -696,8 +618,11 @@ void ApplicationOverlay::renderTexturedHemisphere() {
static VerticesIndices vbo(0, 0); static VerticesIndices vbo(0, 0);
int vertices = slices * (stacks - 1) + 1; int vertices = slices * (stacks - 1) + 1;
int indices = slices * 2 * 3 * (stacks - 2) + slices * 3; int indices = slices * 2 * 3 * (stacks - 2) + slices * 3;
//We only generate the VBO once
if (vbo.first == 0) { static float oldTextureFOV = _textureFov;
//We only generate the VBO when the _textureFov changes
if (vbo.first == 0 || oldTextureFOV != _textureFov) {
oldTextureFOV = _textureFov;
TextureVertex* vertexData = new TextureVertex[vertices]; TextureVertex* vertexData = new TextureVertex[vertices];
TextureVertex* vertex = vertexData; TextureVertex* vertex = vertexData;
for (int i = 0; i < stacks - 1; i++) { for (int i = 0; i < stacks - 1; i++) {
@ -722,7 +647,9 @@ void ApplicationOverlay::renderTexturedHemisphere() {
vertex->uv.y = 0.5f; vertex->uv.y = 0.5f;
vertex++; vertex++;
if (vbo.first == 0){
glGenBuffers(1, &vbo.first); glGenBuffers(1, &vbo.first);
}
glBindBuffer(GL_ARRAY_BUFFER, vbo.first); glBindBuffer(GL_ARRAY_BUFFER, vbo.first);
const int BYTES_PER_VERTEX = sizeof(TextureVertex); const int BYTES_PER_VERTEX = sizeof(TextureVertex);
glBufferData(GL_ARRAY_BUFFER, vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW);

View file

@ -19,8 +19,6 @@ class QOpenGLFramebufferObject;
class ApplicationOverlay { class ApplicationOverlay {
public: public:
enum UIType { HEMISPHERE, SEMICIRCLE, CURVED_SEMICIRCLE };
ApplicationOverlay(); ApplicationOverlay();
~ApplicationOverlay(); ~ApplicationOverlay();
@ -31,11 +29,6 @@ public:
// Getters // Getters
QOpenGLFramebufferObject* getFramebufferObject(); QOpenGLFramebufferObject* getFramebufferObject();
float getOculusAngle() const { return _oculusAngle; }
// Setters
void setOculusAngle(float oculusAngle) { _oculusAngle = oculusAngle; }
void setUIType(UIType uiType) { _uiType = uiType; }
private: private:
// Interleaved vertex data // Interleaved vertex data
@ -47,7 +40,8 @@ private:
typedef QPair<GLuint, GLuint> VerticesIndices; typedef QPair<GLuint, GLuint> VerticesIndices;
void renderPointers(); void renderPointers();
void renderControllerPointer(); void renderControllerPointers();
void renderControllerPointersOculus();
void renderMagnifier(int mouseX, int mouseY); void renderMagnifier(int mouseX, int mouseY);
void renderAudioMeter(); void renderAudioMeter();
void renderStatsAndLogs(); void renderStatsAndLogs();
@ -58,10 +52,11 @@ private:
float _oculusAngle; float _oculusAngle;
float _distance; float _distance;
float _textureFov; float _textureFov;
UIType _uiType;
int _mouseX[2]; int _mouseX[2];
int _mouseY[2]; int _mouseY[2];
int _numMagnifiers; int _numMagnifiers;
GLuint _crosshairTexture;
}; };
#endif // hifi_ApplicationOverlay_h #endif // hifi_ApplicationOverlay_h

View file

@ -137,6 +137,13 @@ void PreferencesDialog::loadPreferences() {
ui.maxVoxelsSpin->setValue(menuInstance->getMaxVoxels()); ui.maxVoxelsSpin->setValue(menuInstance->getMaxVoxels());
ui.maxVoxelsPPSSpin->setValue(menuInstance->getMaxVoxelPacketsPerSecond()); ui.maxVoxelsPPSSpin->setValue(menuInstance->getMaxVoxelPacketsPerSecond());
ui.oculusUIAngularSizeSpin->setValue(menuInstance->getOculusUIAngularSize());
ui.sixenseReticleMoveSpeedSpin->setValue(menuInstance->getSixenseReticleMoveSpeed());
ui.invertSixenseButtonsCheckBox->setChecked(menuInstance->getInvertSixenseButtons());
} }
void PreferencesDialog::savePreferences() { void PreferencesDialog::savePreferences() {
@ -189,6 +196,12 @@ void PreferencesDialog::savePreferences() {
(float)ui.faceshiftEyeDeflectionSider->maximum()); (float)ui.faceshiftEyeDeflectionSider->maximum());
Menu::getInstance()->setMaxVoxelPacketsPerSecond(ui.maxVoxelsPPSSpin->value()); Menu::getInstance()->setMaxVoxelPacketsPerSecond(ui.maxVoxelsPPSSpin->value());
Menu::getInstance()->setOculusUIAngularSize(ui.oculusUIAngularSizeSpin->value());
Menu::getInstance()->setSixenseReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value());
Menu::getInstance()->setInvertSixenseButtons(ui.invertSixenseButtonsCheckBox->isChecked());
Menu::getInstance()->setAudioJitterBufferSamples(ui.audioJitterSpin->value()); Menu::getInstance()->setAudioJitterBufferSamples(ui.audioJitterSpin->value());
Application::getInstance()->getAudio()->setJitterBufferSamples(ui.audioJitterSpin->value()); Application::getInstance()->getAudio()->setJitterBufferSamples(ui.audioJitterSpin->value());

View file

@ -154,9 +154,9 @@ color: #0e7077</string>
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>-204</y> <y>-1002</y>
<width>494</width> <width>477</width>
<height>1091</height> <height>1386</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2">
@ -1605,6 +1605,331 @@ padding: 10px;margin-top:10px</string>
</item> </item>
</layout> </layout>
</item> </item>
<item>
<widget class="QLabel" name="oculusRiftTitleLabel">
<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>Oculus Rift</string>
</property>
<property name="alignment">
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_15">
<property name="spacing">
<number>0</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="label_12">
<property name="font">
<font>
<family>Arial</family>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(51, 51, 51)</string>
</property>
<property name="text">
<string>User Interface Angular Size</string>
</property>
<property name="indent">
<number>15</number>
</property>
<property name="buddy">
<cstring>maxVoxelsSpin</cstring>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_15">
<property name="font">
<font>
<family>Arial</family>
</font>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QSpinBox" name="oculusUIAngularSizeSpin">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>125</width>
<height>36</height>
</size>
</property>
<property name="font">
<font>
<family>Arial</family>
</font>
</property>
<property name="minimum">
<number>30</number>
</property>
<property name="maximum">
<number>160</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="value">
<number>72</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="sixenseControllersTitleLabel">
<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>Sixense Controllers</string>
</property>
<property name="alignment">
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_17">
<property name="spacing">
<number>0</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="label_14">
<property name="font">
<font>
<family>Arial</family>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(51, 51, 51)</string>
</property>
<property name="text">
<string>Invert Mouse Buttons</string>
</property>
<property name="indent">
<number>15</number>
</property>
<property name="buddy">
<cstring>maxVoxelsSpin</cstring>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_17">
<property name="font">
<font>
<family>Arial</family>
</font>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="invertSixenseButtonsCheckBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>32</width>
<height>0</height>
</size>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_16">
<property name="spacing">
<number>0</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="label_13">
<property name="font">
<font>
<family>Arial</family>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(51, 51, 51)</string>
</property>
<property name="text">
<string>Reticle Movement Speed</string>
</property>
<property name="indent">
<number>15</number>
</property>
<property name="buddy">
<cstring>maxVoxelsSpin</cstring>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_16">
<property name="font">
<font>
<family>Arial</family>
</font>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QSpinBox" name="sixenseReticleMoveSpeedSpin">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>125</width>
<height>36</height>
</size>
</property>
<property name="font">
<font>
<family>Arial</family>
</font>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="value">
<number>50</number>
</property>
</widget>
</item>
</layout>
</item>
</layout> </layout>
</widget> </widget>
</widget> </widget>

View file

@ -258,7 +258,7 @@ void Sound::interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& ou
// Now pull out the data // Now pull out the data
quint32 outputAudioByteArraySize = qFromLittleEndian<quint32>(dataHeader.descriptor.size); quint32 outputAudioByteArraySize = qFromLittleEndian<quint32>(dataHeader.descriptor.size);
outputAudioByteArray.resize(outputAudioByteArraySize); outputAudioByteArray.resize(outputAudioByteArraySize);
if (waveStream.readRawData(outputAudioByteArray.data(), outputAudioByteArraySize) != outputAudioByteArraySize) { if (waveStream.readRawData(outputAudioByteArray.data(), outputAudioByteArraySize) != (int)outputAudioByteArraySize) {
qDebug() << "Error reading WAV file"; qDebug() << "Error reading WAV file";
} }

View file

@ -180,6 +180,18 @@ static bool findIntersection(float origin, float direction, float corner, float
return false; return false;
} }
// finds the intersection between a ray and the inside facing plane on one axis
static bool findInsideOutIntersection(float origin, float direction, float corner, float size, float& distance) {
if (direction > EPSILON) {
distance = -1.0f * (origin - (corner + size)) / direction;
return true;
} else if (direction < -EPSILON) {
distance = -1.0f * (origin - corner) / direction;
return true;
}
return false;
}
bool AABox::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const { bool AABox::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const {
// handle the trivial cases where the expanded box contains the start or end // handle the trivial cases where the expanded box contains the start or end
if (expandedContains(start, expansion) || expandedContains(end, expansion)) { if (expandedContains(start, expansion) || expandedContains(end, expansion)) {
@ -207,9 +219,34 @@ bool AABox::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& e
bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const { bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const {
// handle the trivial case where the box contains the origin // handle the trivial case where the box contains the origin
if (contains(origin)) { if (contains(origin)) {
// We still want to calculate the distance from the origin to the inside out plane
float axisDistance;
if ((findInsideOutIntersection(origin.x, direction.x, _corner.x, _scale.x, axisDistance) && axisDistance >= 0 &&
isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale.y) &&
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale.z))) {
distance = axisDistance;
face = direction.x > 0 ? MIN_X_FACE : MAX_X_FACE;
return true;
}
if ((findInsideOutIntersection(origin.y, direction.y, _corner.y, _scale.y, axisDistance) && axisDistance >= 0 &&
isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x) &&
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale.z))) {
distance = axisDistance;
face = direction.y > 0 ? MIN_Y_FACE : MAX_Y_FACE;
return true;
}
if ((findInsideOutIntersection(origin.z, direction.z, _corner.z, _scale.z, axisDistance) && axisDistance >= 0 &&
isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale.y) &&
isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x))) {
distance = axisDistance;
face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE;
return true;
}
// This case is unexpected, but mimics the previous behavior for inside out intersections
distance = 0; distance = 0;
return true; return true;
} }
// check each axis // check each axis
float axisDistance; float axisDistance;
if ((findIntersection(origin.x, direction.x, _corner.x, _scale.x, axisDistance) && axisDistance >= 0 && if ((findIntersection(origin.x, direction.x, _corner.x, _scale.x, axisDistance) && axisDistance >= 0 &&

View file

@ -169,6 +169,18 @@ static bool findIntersection(float origin, float direction, float corner, float
return false; return false;
} }
// finds the intersection between a ray and the inside facing plane on one axis
static bool findInsideOutIntersection(float origin, float direction, float corner, float size, float& distance) {
if (direction > EPSILON) {
distance = -1.0f * (origin - (corner + size)) / direction;
return true;
} else if (direction < -EPSILON) {
distance = -1.0f * (origin - corner) / direction;
return true;
}
return false;
}
bool AACube::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const { bool AACube::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const {
// handle the trivial cases where the expanded box contains the start or end // handle the trivial cases where the expanded box contains the start or end
if (expandedContains(start, expansion) || expandedContains(end, expansion)) { if (expandedContains(start, expansion) || expandedContains(end, expansion)) {
@ -196,9 +208,35 @@ bool AACube::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3&
bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const { bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const {
// handle the trivial case where the box contains the origin // handle the trivial case where the box contains the origin
if (contains(origin)) { if (contains(origin)) {
// We still want to calculate the distance from the origin to the inside out plane
float axisDistance;
if ((findInsideOutIntersection(origin.x, direction.x, _corner.x, _scale, axisDistance) && axisDistance >= 0 &&
isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) &&
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) {
distance = axisDistance;
face = direction.x > 0 ? MIN_X_FACE : MAX_X_FACE;
return true;
}
if ((findInsideOutIntersection(origin.y, direction.y, _corner.y, _scale, axisDistance) && axisDistance >= 0 &&
isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale) &&
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) {
distance = axisDistance;
face = direction.y > 0 ? MIN_Y_FACE : MAX_Y_FACE;
return true;
}
if ((findInsideOutIntersection(origin.z, direction.z, _corner.z, _scale, axisDistance) && axisDistance >= 0 &&
isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) &&
isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) {
distance = axisDistance;
face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE;
return true;
}
// This case is unexpected, but mimics the previous behavior for inside out intersections
distance = 0; distance = 0;
return true; return true;
} }
// check each axis // check each axis
float axisDistance; float axisDistance;
if ((findIntersection(origin.x, direction.x, _corner.x, _scale, axisDistance) && axisDistance >= 0 && if ((findIntersection(origin.x, direction.x, _corner.x, _scale, axisDistance) && axisDistance >= 0 &&

View file

@ -26,6 +26,7 @@
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QDateTime> #include <QDateTime>
#include <QElapsedTimer> #include <QElapsedTimer>
#include <QThread>
#include "OctalCode.h" #include "OctalCode.h"
#include "SharedUtil.h" #include "SharedUtil.h"
@ -415,13 +416,17 @@ void printVoxelCode(unsigned char* voxelCode) {
#ifdef _WIN32 #ifdef _WIN32
void usleep(int waitTime) { void usleep(int waitTime) {
__int64 time1 = 0, time2 = 0, sysFreq = 0; const quint64 BUSY_LOOP_USECS = 2000;
quint64 compTime = waitTime + usecTimestampNow();
QueryPerformanceCounter((LARGE_INTEGER *)&time1); quint64 compTimeSleep = compTime - BUSY_LOOP_USECS;
QueryPerformanceFrequency((LARGE_INTEGER *)&sysFreq); while (true) {
do { if (usecTimestampNow() < compTimeSleep) {
QueryPerformanceCounter((LARGE_INTEGER *)&time2); QThread::msleep(1);
} while( (time2 - time1) < waitTime); }
if (usecTimestampNow() >= compTime) {
break;
}
}
} }
#endif #endif