mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-14 02:06:30 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi
This commit is contained in:
commit
f1e2ba1267
66 changed files with 1561 additions and 308 deletions
|
@ -12,6 +12,9 @@ set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
|
|||
# setup for find modules
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/")
|
||||
|
||||
find_package(Qt5 COMPONENTS Script)
|
||||
include_directories(SYSTEM "${Qt5Script_INCLUDE_DIRS}")
|
||||
|
||||
# set up the external glm library
|
||||
include("${MACRO_DIR}/IncludeGLM.cmake")
|
||||
include_glm(${TARGET_NAME} "${ROOT_DIR}")
|
||||
|
@ -35,4 +38,4 @@ link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
|
|||
# add a definition for ssize_t so that windows doesn't bail
|
||||
if (WIN32)
|
||||
add_definitions(-Dssize_t=long)
|
||||
endif ()
|
||||
endif ()
|
||||
|
|
|
@ -13,13 +13,13 @@
|
|||
#include <QtCore/QEventLoop>
|
||||
#include <QtCore/QStandardPaths>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkDiskCache>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
||||
#include <AudioRingBuffer.h>
|
||||
#include <AvatarData.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <ResourceCache.h>
|
||||
|
@ -208,12 +208,14 @@ void Agent::run() {
|
|||
scriptURL = QUrl(_payload);
|
||||
}
|
||||
|
||||
QNetworkAccessManager *networkManager = new QNetworkAccessManager(this);
|
||||
QNetworkReply *reply = networkManager->get(QNetworkRequest(scriptURL));
|
||||
QNetworkDiskCache* cache = new QNetworkDiskCache(networkManager);
|
||||
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkReply *reply = networkAccessManager.get(QNetworkRequest(scriptURL));
|
||||
QNetworkDiskCache* cache = new QNetworkDiskCache(&networkAccessManager);
|
||||
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
||||
cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "agentCache");
|
||||
networkManager->setCache(cache);
|
||||
QMetaObject::invokeMethod(&networkAccessManager, "setCache",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_ARG(QAbstractNetworkCache*, cache));
|
||||
|
||||
qDebug() << "Downloading script at" << scriptURL.toString();
|
||||
|
||||
|
@ -222,10 +224,6 @@ void Agent::run() {
|
|||
|
||||
loop.exec();
|
||||
|
||||
// let the AvatarData and ResourceCache classes use our QNetworkAccessManager
|
||||
AvatarData::setNetworkAccessManager(networkManager);
|
||||
ResourceCache::setNetworkAccessManager(networkManager);
|
||||
|
||||
QString scriptContents(reply->readAll());
|
||||
|
||||
qDebug() << "Downloaded script:" << scriptContents;
|
||||
|
|
|
@ -38,11 +38,11 @@
|
|||
#include <QtCore/QJsonObject>
|
||||
#include <QtCore/QJsonValue>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
||||
#include <Logging.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <NodeList.h>
|
||||
#include <Node.h>
|
||||
#include <PacketHeaders.h>
|
||||
|
@ -482,8 +482,8 @@ void AudioMixer::run() {
|
|||
|
||||
nodeList->linkedDataCreateCallback = attachNewBufferToNode;
|
||||
|
||||
// setup a QNetworkAccessManager to ask the domain-server for our settings
|
||||
QNetworkAccessManager *networkManager = new QNetworkAccessManager(this);
|
||||
// setup a NetworkAccessManager to ask the domain-server for our settings
|
||||
NetworkAccessManager& networkManager = NetworkAccessManager::getInstance();
|
||||
|
||||
QUrl settingsJSONURL;
|
||||
settingsJSONURL.setScheme("http");
|
||||
|
@ -500,7 +500,7 @@ void AudioMixer::run() {
|
|||
qDebug() << "Requesting settings for assignment from domain-server at" << settingsJSONURL.toString();
|
||||
|
||||
while (!reply || reply->error() != QNetworkReply::NoError) {
|
||||
reply = networkManager->get(QNetworkRequest(settingsJSONURL));
|
||||
reply = networkManager.get(QNetworkRequest(settingsJSONURL));
|
||||
|
||||
QEventLoop loop;
|
||||
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
//
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QTimer>
|
||||
#include <QUuid>
|
||||
|
||||
|
|
|
@ -51,8 +51,6 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
|
||||
_argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments());
|
||||
|
||||
_networkAccessManager = new QNetworkAccessManager(this);
|
||||
|
||||
if (optionallyReadX509KeyAndCertificate() && optionallySetupOAuth() && optionallySetupAssignmentPayment()) {
|
||||
// we either read a certificate and private key or were not passed one
|
||||
// and completed login or did not need to
|
||||
|
@ -1196,7 +1194,7 @@ bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &u
|
|||
QNetworkRequest tokenRequest(tokenRequestUrl);
|
||||
tokenRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
|
||||
QNetworkReply* tokenReply = _networkAccessManager->post(tokenRequest, tokenPostBody.toLocal8Bit());
|
||||
QNetworkReply* tokenReply = NetworkAccessManager::getInstance().post(tokenRequest, tokenPostBody.toLocal8Bit());
|
||||
|
||||
qDebug() << "Requesting a token for user with session UUID" << uuidStringWithoutCurlyBraces(stateUUID);
|
||||
|
||||
|
@ -1233,7 +1231,7 @@ void DomainServer::handleTokenRequestFinished() {
|
|||
profileURL.setPath("/api/v1/users/profile");
|
||||
profileURL.setQuery(QString("%1=%2").arg(OAUTH_JSON_ACCESS_TOKEN_KEY, accessToken));
|
||||
|
||||
QNetworkReply* profileReply = _networkAccessManager->get(QNetworkRequest(profileURL));
|
||||
QNetworkReply* profileReply = NetworkAccessManager::getInstance().get(QNetworkRequest(profileURL));
|
||||
|
||||
qDebug() << "Requesting access token for user with session UUID" << uuidStringWithoutCurlyBraces(matchingSessionUUID);
|
||||
|
||||
|
|
|
@ -103,8 +103,6 @@ private:
|
|||
|
||||
bool _isUsingDTLS;
|
||||
|
||||
QNetworkAccessManager* _networkAccessManager;
|
||||
|
||||
QUrl _oauthProviderURL;
|
||||
QString _oauthClientID;
|
||||
QString _oauthClientSecret;
|
||||
|
|
5
interface/external/oculus/readme.txt
vendored
5
interface/external/oculus/readme.txt
vendored
|
@ -10,4 +10,7 @@ You can download the Oculus SDK from https://developer.oculusvr.com/ (account cr
|
|||
You may optionally choose to copy the SDK folders to a location outside the repository (so you can re-use with different checkouts and different projects).
|
||||
If so our CMake find module expects you to set the ENV variable 'HIFI_LIB_DIR' to a directory containing a subfolder 'oculus' that contains the three folders mentioned above.
|
||||
|
||||
2. Clear your build directory, run cmake and build, and you should be all set.
|
||||
NOTE: For Windows users, you should copy libovr.lib and libovrd.lib from the \oculus\Lib\Win32\VS2010 directory to the \oculus\Lib\Win32\ directory.
|
||||
|
||||
2. Clear your build directory, run cmake and build, and you should be all set.
|
||||
|
||||
|
|
|
@ -11,18 +11,114 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// the texture containing our permutations and normals
|
||||
uniform sampler2D permutationNormalTexture;
|
||||
// implementation based on Ken Perlin's Improved Noise reference implementation (orig. in Java) at
|
||||
// http://mrl.nyu.edu/~perlin/noise/
|
||||
|
||||
uniform sampler2D permutationTexture;
|
||||
|
||||
// the noise frequency
|
||||
const float frequency = 65536.0; // looks better with current TREE_SCALE, was 1024 when TREE_SCALE was either 512 or 128
|
||||
const float frequency = 256.0;
|
||||
//const float frequency = 65536.0; // looks better with current TREE_SCALE, was 1024 when TREE_SCALE was either 512 or 128
|
||||
|
||||
// the noise amplitude
|
||||
const float amplitude = 0.1;
|
||||
const float amplitude = 0.5;
|
||||
|
||||
// the position in model space
|
||||
varying vec3 position;
|
||||
|
||||
// gradient based on gradients from cube edge centers rather than random from texture lookup
|
||||
float randomEdgeGrad(int hash, vec3 position){
|
||||
int h = int(mod(hash, 16));
|
||||
float u = h < 8 ? position.x : position.y;
|
||||
float v = h < 4 ? position.y : h == 12 || h == 14 ? position.x : position.z;
|
||||
bool even = mod(hash, 2) == 0;
|
||||
bool four = mod(hash, 4) == 0;
|
||||
return (even ? u : -u) + (four ? v : -v);
|
||||
}
|
||||
|
||||
// still have the option to lookup based on texture
|
||||
float randomTextureGrad(int hash, vec3 position){
|
||||
float u = float(hash) / 256.0;
|
||||
vec3 g = -1 + 2 * texture2D(permutationTexture, vec2(u, 0.75)).rgb;
|
||||
return dot(position, g);
|
||||
}
|
||||
|
||||
float improvedGrad(int hash, vec3 position){
|
||||
// Untested whether texture lookup is faster than math, uncomment one line or the other to try out
|
||||
// cube edge gradients versus random spherical gradients sent in texture.
|
||||
|
||||
// return randomTextureGrad(hash, position);
|
||||
return randomEdgeGrad(hash, position);
|
||||
}
|
||||
|
||||
// 5th order fade function to remove 2nd order discontinuties
|
||||
vec3 fade3(vec3 t){
|
||||
return t * t * t * (t * (t * 6 - 15) + 10);
|
||||
}
|
||||
|
||||
int permutation(int index){
|
||||
float u = float(index) / 256.0;
|
||||
float t = texture2D(permutationTexture, vec2(u, 0.25)).r;
|
||||
return int(t * 256);
|
||||
}
|
||||
|
||||
float improvedNoise(vec3 position){
|
||||
int X = int(mod(floor(position.x), 256));
|
||||
int Y = int(mod(floor(position.y), 256));
|
||||
int Z = int(mod(floor(position.z), 256));
|
||||
|
||||
vec3 fracs = fract(position);
|
||||
|
||||
vec3 fades = fade3(fracs);
|
||||
|
||||
int A = permutation(X + 0) + Y;
|
||||
int AA = permutation(A + 0) + Z;
|
||||
int AB = permutation(A + 1) + Z;
|
||||
int B = permutation(X + 1) + Y;
|
||||
int BA = permutation(B + 0) + Z;
|
||||
int BB = permutation(B + 1) + Z;
|
||||
|
||||
float gradAA0 = improvedGrad(permutation(AA + 0), vec3(fracs.x , fracs.y , fracs.z ));
|
||||
float gradBA0 = improvedGrad(permutation(BA + 0), vec3(fracs.x - 1, fracs.y , fracs.z ));
|
||||
float gradAB0 = improvedGrad(permutation(AB + 0), vec3(fracs.x , fracs.y - 1, fracs.z ));
|
||||
float gradBB0 = improvedGrad(permutation(BB + 0), vec3(fracs.x - 1, fracs.y - 1, fracs.z ));
|
||||
float gradAA1 = improvedGrad(permutation(AA + 1), vec3(fracs.x , fracs.y , fracs.z - 1));
|
||||
float gradBA1 = improvedGrad(permutation(BA + 1), vec3(fracs.x - 1, fracs.y , fracs.z - 1));
|
||||
float gradAB1 = improvedGrad(permutation(AB + 1), vec3(fracs.x , fracs.y - 1, fracs.z - 1));
|
||||
float gradBB1 = improvedGrad(permutation(BB + 1), vec3(fracs.x - 1, fracs.y - 1, fracs.z - 1));
|
||||
|
||||
return mix(mix(mix(gradAA0, gradBA0, fades.x), mix(gradAB0, gradBB0, fades.x), fades.y), mix(mix(gradAA1, gradBA1, fades.x), mix(gradAB1, gradBB1, fades.x), fades.y), fades.z);
|
||||
}
|
||||
|
||||
float turbulence(vec3 position, float power){
|
||||
return (1.0f / power) * improvedNoise(power * position);
|
||||
}
|
||||
|
||||
float turb(vec3 position){
|
||||
return turbulence(position, 1)
|
||||
+ turbulence(position, 2),
|
||||
+ turbulence(position, 4)
|
||||
+ turbulence(position, 8)
|
||||
+ turbulence(position, 16)
|
||||
+ turbulence(position, 32)
|
||||
+ turbulence(position, 64)
|
||||
+ turbulence(position, 128)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
void main(void) {
|
||||
|
||||
// get noise in range 0 .. 1
|
||||
float noise = clamp(0.5f + amplitude * turb(position * frequency), 0, 1);
|
||||
|
||||
// apply vertex lighting
|
||||
vec3 color = gl_Color.rgb * vec3(noise, noise, noise);
|
||||
gl_FragColor = vec4(color, 1);
|
||||
}
|
||||
|
||||
|
||||
/* old implementation
|
||||
// returns the gradient at a single corner of our sampling cube
|
||||
vec3 grad(vec3 location) {
|
||||
float p1 = texture2D(permutationNormalTexture, vec2(location.x / 256.0, 0.25)).r;
|
||||
|
@ -60,7 +156,4 @@ float perlin(vec3 location) {
|
|||
mix(mix(ffcv, cfcv, params.x), mix(fccv, cccv, params.x), params.y),
|
||||
params.z);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
gl_FragColor = vec4(gl_Color.rgb * (1.0 + amplitude*(perlin(position * frequency) - 1.0)), 1.0);
|
||||
}
|
||||
*/
|
|
@ -32,7 +32,6 @@
|
|||
#include <QKeyEvent>
|
||||
#include <QMenuBar>
|
||||
#include <QMouseEvent>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkDiskCache>
|
||||
#include <QOpenGLFramebufferObject>
|
||||
|
@ -53,17 +52,18 @@
|
|||
|
||||
#include <AccountManager.h>
|
||||
#include <AudioInjector.h>
|
||||
#include <LocalVoxelsList.h>
|
||||
#include <Logging.h>
|
||||
#include <ModelsScriptingInterface.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <OctalCode.h>
|
||||
#include <OctreeSceneStats.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <ParticlesScriptingInterface.h>
|
||||
#include <PerfStat.h>
|
||||
#include <ResourceCache.h>
|
||||
#include <UserActivityLogger.h>
|
||||
#include <UUID.h>
|
||||
#include <OctreeSceneStats.h>
|
||||
#include <LocalVoxelsList.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "InterfaceVersion.h"
|
||||
|
@ -315,12 +315,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
|
||||
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
||||
|
||||
_networkAccessManager = new QNetworkAccessManager(this);
|
||||
QNetworkDiskCache* cache = new QNetworkDiskCache(_networkAccessManager);
|
||||
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkDiskCache* cache = new QNetworkDiskCache(&networkAccessManager);
|
||||
cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "interfaceCache");
|
||||
_networkAccessManager->setCache(cache);
|
||||
QMetaObject::invokeMethod(&networkAccessManager, "setCache",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_ARG(QAbstractNetworkCache*, cache));
|
||||
|
||||
ResourceCache::setNetworkAccessManager(_networkAccessManager);
|
||||
ResourceCache::setRequestLimit(3);
|
||||
|
||||
_window->setCentralWidget(_glWidget);
|
||||
|
@ -403,18 +404,19 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
}
|
||||
|
||||
Application::~Application() {
|
||||
qInstallMessageHandler(NULL);
|
||||
|
||||
saveSettings();
|
||||
storeSizeAndPosition();
|
||||
saveScripts();
|
||||
|
||||
int DELAY_TIME = 1000;
|
||||
UserActivityLogger::getInstance().close(DELAY_TIME);
|
||||
|
||||
qInstallMessageHandler(NULL);
|
||||
|
||||
// make sure we don't call the idle timer any more
|
||||
delete idleTimer;
|
||||
|
||||
|
||||
_sharedVoxelSystem.changeTree(new VoxelTree);
|
||||
|
||||
saveSettings();
|
||||
|
||||
delete _voxelImporter;
|
||||
|
||||
// let the avatar mixer know we're out
|
||||
|
@ -437,8 +439,6 @@ Application::~Application() {
|
|||
_particleEditSender.terminate();
|
||||
_modelEditSender.terminate();
|
||||
|
||||
storeSizeAndPosition();
|
||||
saveScripts();
|
||||
|
||||
VoxelTreeElement::removeDeleteHook(&_voxels); // we don't need to do this processing on shutdown
|
||||
Menu::getInstance()->deleteLater();
|
||||
|
@ -446,8 +446,6 @@ Application::~Application() {
|
|||
_myAvatar = NULL;
|
||||
|
||||
delete _glWidget;
|
||||
|
||||
AccountManager::getInstance().destroy();
|
||||
}
|
||||
|
||||
void Application::saveSettings() {
|
||||
|
@ -595,13 +593,17 @@ void Application::paintGL() {
|
|||
//Note, the camera distance is set in Camera::setMode() so we dont have to do it here.
|
||||
_myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing
|
||||
_myCamera.setTargetPosition(_myAvatar->getUprightHeadPosition());
|
||||
_myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation());
|
||||
if (OculusManager::isConnected()) {
|
||||
_myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation());
|
||||
} else {
|
||||
_myCamera.setTargetRotation(_myAvatar->getHead()->getOrientation());
|
||||
}
|
||||
|
||||
} else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||
_myCamera.setTightness(0.0f);
|
||||
_myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
|
||||
_myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
|
||||
_myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition());
|
||||
_myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition() + glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0));
|
||||
}
|
||||
|
||||
// Update camera position
|
||||
|
@ -639,6 +641,10 @@ void Application::paintGL() {
|
|||
//If we aren't using the glow shader, we have to clear the color and depth buffer
|
||||
if (!glowEnabled) {
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
} else if (OculusManager::isConnected()) {
|
||||
//Clear the color buffer to ensure that there isnt any residual color
|
||||
//Left over from when OR was not connected.
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
if (OculusManager::isConnected()) {
|
||||
|
@ -650,13 +656,8 @@ void Application::paintGL() {
|
|||
}
|
||||
|
||||
} else if (TV3DManager::isConnected()) {
|
||||
if (glowEnabled) {
|
||||
_glowEffect.prepare();
|
||||
}
|
||||
|
||||
TV3DManager::display(whichCamera);
|
||||
if (glowEnabled) {
|
||||
_glowEffect.render();
|
||||
}
|
||||
|
||||
} else {
|
||||
if (glowEnabled) {
|
||||
|
@ -1144,7 +1145,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
|
|||
|
||||
_lastMouseMove = usecTimestampNow();
|
||||
|
||||
if (_mouseHidden && showMouse && !OculusManager::isConnected()) {
|
||||
if (_mouseHidden && showMouse && !OculusManager::isConnected() && !TV3DManager::isConnected()) {
|
||||
getGLWidget()->setCursor(Qt::ArrowCursor);
|
||||
_mouseHidden = false;
|
||||
_seenMouseMove = true;
|
||||
|
@ -3808,7 +3809,8 @@ void Application::initAvatarAndViewFrustum() {
|
|||
void Application::checkVersion() {
|
||||
QNetworkRequest latestVersionRequest((QUrl(CHECK_VERSION_URL)));
|
||||
latestVersionRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
|
||||
connect(Application::getInstance()->getNetworkAccessManager()->get(latestVersionRequest), SIGNAL(finished()), SLOT(parseVersionXml()));
|
||||
QNetworkReply* reply = NetworkAccessManager::getInstance().get(latestVersionRequest);
|
||||
connect(reply, SIGNAL(finished()), SLOT(parseVersionXml()));
|
||||
}
|
||||
|
||||
void Application::parseVersionXml() {
|
||||
|
|
|
@ -97,7 +97,6 @@ class QActionGroup;
|
|||
class QGLWidget;
|
||||
class QKeyEvent;
|
||||
class QMouseEvent;
|
||||
class QNetworkAccessManager;
|
||||
class QSettings;
|
||||
class QWheelEvent;
|
||||
|
||||
|
@ -236,7 +235,6 @@ public:
|
|||
void lockOctreeSceneStats() { _octreeSceneStatsLock.lockForRead(); }
|
||||
void unlockOctreeSceneStats() { _octreeSceneStatsLock.unlock(); }
|
||||
|
||||
QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; }
|
||||
GeometryCache* getGeometryCache() { return &_geometryCache; }
|
||||
AnimationCache* getAnimationCache() { return &_animationCache; }
|
||||
TextureCache* getTextureCache() { return &_textureCache; }
|
||||
|
@ -423,7 +421,6 @@ private:
|
|||
QThread* _nodeThread;
|
||||
DatagramProcessor _datagramProcessor;
|
||||
|
||||
QNetworkAccessManager* _networkAccessManager;
|
||||
QMutex _settingsMutex;
|
||||
QSettings* _settings;
|
||||
int _numChangedSettings;
|
||||
|
|
|
@ -432,7 +432,7 @@ void Audio::handleAudioInput() {
|
|||
|
||||
float inputToNetworkInputRatio = calculateDeviceToNetworkInputRatio(_numInputCallbackBytes);
|
||||
|
||||
unsigned int inputSamplesRequired = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * inputToNetworkInputRatio;
|
||||
int inputSamplesRequired = (int)((float)NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * inputToNetworkInputRatio);
|
||||
|
||||
QByteArray inputByteArray = _inputDevice->readAll();
|
||||
|
||||
|
@ -1379,8 +1379,10 @@ bool Audio::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceInfo) {
|
|||
|
||||
// cleanup any previously initialized device
|
||||
if (_audioInput) {
|
||||
// The call to stop() causes _inputDevice to be destructed.
|
||||
// That in turn causes it to be disconnected (see for example
|
||||
// http://stackoverflow.com/questions/9264750/qt-signals-and-slots-object-disconnect).
|
||||
_audioInput->stop();
|
||||
disconnect(_inputDevice);
|
||||
_inputDevice = NULL;
|
||||
|
||||
delete _audioInput;
|
||||
|
|
|
@ -91,6 +91,7 @@ Menu::Menu() :
|
|||
_jsConsole(NULL),
|
||||
_octreeStatsDialog(NULL),
|
||||
_lodToolsDialog(NULL),
|
||||
_userLocationsDialog(NULL),
|
||||
_maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM),
|
||||
_voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE),
|
||||
_oculusUIAngularSize(DEFAULT_OCULUS_UI_ANGULAR_SIZE),
|
||||
|
@ -166,6 +167,11 @@ Menu::Menu() :
|
|||
Qt::CTRL | Qt::Key_N,
|
||||
this,
|
||||
SLOT(nameLocation()));
|
||||
addActionToQMenuAndActionHash(fileMenu,
|
||||
MenuOption::MyLocations,
|
||||
Qt::CTRL | Qt::Key_K,
|
||||
this,
|
||||
SLOT(toggleLocationList()));
|
||||
addActionToQMenuAndActionHash(fileMenu,
|
||||
MenuOption::GoTo,
|
||||
Qt::Key_At,
|
||||
|
@ -1184,6 +1190,17 @@ void Menu::namedLocationCreated(LocationManager::NamedLocationCreateResponse res
|
|||
msgBox.exec();
|
||||
}
|
||||
|
||||
void Menu::toggleLocationList() {
|
||||
if (!_userLocationsDialog) {
|
||||
_userLocationsDialog = new UserLocationsDialog(Application::getInstance()->getWindow());
|
||||
}
|
||||
if (_userLocationsDialog->isVisible()) {
|
||||
_userLocationsDialog->hide();
|
||||
} else {
|
||||
_userLocationsDialog->show();
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::nameLocation() {
|
||||
// check if user is logged in or show login dialog if not
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "ui/JSConsole.h"
|
||||
#include "ui/LoginDialog.h"
|
||||
#include "ui/ScriptEditorWindow.h"
|
||||
#include "ui/UserLocationsDialog.h"
|
||||
|
||||
const float ADJUST_LOD_DOWN_FPS = 40.0;
|
||||
const float ADJUST_LOD_UP_FPS = 55.0;
|
||||
|
@ -199,6 +200,7 @@ private slots:
|
|||
void goToDomainDialog();
|
||||
void goToLocation();
|
||||
void nameLocation();
|
||||
void toggleLocationList();
|
||||
void bandwidthDetailsClosed();
|
||||
void octreeStatsDetailsClosed();
|
||||
void lodToolsClosed();
|
||||
|
@ -265,6 +267,7 @@ private:
|
|||
QDialog* _jsConsole;
|
||||
OctreeStatsDialog* _octreeStatsDialog;
|
||||
LodToolsDialog* _lodToolsDialog;
|
||||
UserLocationsDialog* _userLocationsDialog;
|
||||
int _maxVoxels;
|
||||
float _voxelSizeScale;
|
||||
float _oculusUIAngularSize;
|
||||
|
@ -395,6 +398,7 @@ namespace MenuOption {
|
|||
const QString MoveWithLean = "Move with Lean";
|
||||
const QString MuteAudio = "Mute Microphone";
|
||||
const QString MuteEnvironment = "Mute Environment";
|
||||
const QString MyLocations = "My Locations...";
|
||||
const QString NameLocation = "Name this location";
|
||||
const QString NewVoxelCullingMode = "New Voxel Culling Mode";
|
||||
const QString OctreeStats = "Voxel and Particle Statistics";
|
||||
|
|
|
@ -396,7 +396,7 @@ void ModelUploader::uploadFailed(QNetworkReply::NetworkError errorCode, const QS
|
|||
void ModelUploader::checkS3() {
|
||||
qDebug() << "Checking S3 for " << _url;
|
||||
QNetworkRequest request(_url);
|
||||
QNetworkReply* reply = _networkAccessManager.head(request);
|
||||
QNetworkReply* reply = NetworkAccessManager::getInstance().head(request);
|
||||
connect(reply, SIGNAL(finished()), SLOT(processCheck()));
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,6 @@ private:
|
|||
bool _readyToSend;
|
||||
|
||||
QHttpMultiPart* _dataMultiPart;
|
||||
QNetworkAccessManager _networkAccessManager;
|
||||
|
||||
int _numberOfChecks;
|
||||
QTimer _timer;
|
||||
|
|
|
@ -11,14 +11,15 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QUrl>
|
||||
#include <QUrlQuery>
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
#include "ScriptsModel.h"
|
||||
#include <NetworkAccessManager.h>
|
||||
|
||||
#include "Menu.h"
|
||||
|
||||
#include "ScriptsModel.h"
|
||||
|
||||
static const QString S3_URL = "http://highfidelity-public.s3-us-west-1.amazonaws.com";
|
||||
static const QString PUBLIC_URL = "http://public.highfidelity.io";
|
||||
|
@ -30,8 +31,6 @@ static const QString IS_TRUNCATED_NAME = "IsTruncated";
|
|||
static const QString CONTAINER_NAME = "Contents";
|
||||
static const QString KEY_NAME = "Key";
|
||||
|
||||
static const int SCRIPT_PATH = Qt::UserRole;
|
||||
|
||||
ScriptItem::ScriptItem(const QString& filename, const QString& fullPath) :
|
||||
_filename(filename),
|
||||
_fullPath(fullPath) {
|
||||
|
@ -113,14 +112,15 @@ void ScriptsModel::requestRemoteFiles(QString marker) {
|
|||
}
|
||||
url.setQuery(query);
|
||||
|
||||
QNetworkAccessManager* accessManager = new QNetworkAccessManager(this);
|
||||
connect(accessManager, SIGNAL(finished(QNetworkReply*)), SLOT(downloadFinished(QNetworkReply*)));
|
||||
|
||||
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest request(url);
|
||||
accessManager->get(request);
|
||||
QNetworkReply* reply = networkAccessManager.get(request);
|
||||
connect(reply, SIGNAL(finished()), SLOT(downloadFinished()));
|
||||
|
||||
}
|
||||
|
||||
void ScriptsModel::downloadFinished(QNetworkReply* reply) {
|
||||
void ScriptsModel::downloadFinished() {
|
||||
QNetworkReply* reply = static_cast<QNetworkReply*>(sender());
|
||||
bool finished = true;
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
|
||||
protected slots:
|
||||
void updateScriptsLocation(const QString& newPath);
|
||||
void downloadFinished(QNetworkReply* reply);
|
||||
void downloadFinished();
|
||||
void reloadLocalFiles();
|
||||
void reloadRemoteFiles();
|
||||
|
||||
|
|
246
interface/src/UserLocationsModel.cpp
Normal file
246
interface/src/UserLocationsModel.cpp
Normal file
|
@ -0,0 +1,246 @@
|
|||
//
|
||||
// UserLocationsModel.cpp
|
||||
// interface/src
|
||||
//
|
||||
// Created by Ryan Huffman on 06/24/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QDebug>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "AccountManager.h"
|
||||
#include "Application.h"
|
||||
#include "UserLocationsModel.h"
|
||||
|
||||
static const QString PLACES_GET = "/api/v1/places";
|
||||
static const QString PLACES_UPDATE = "/api/v1/places/%1";
|
||||
static const QString PLACES_DELETE= "/api/v1/places/%1";
|
||||
|
||||
UserLocation::UserLocation(QString id, QString name, QString location) :
|
||||
_id(id),
|
||||
_name(name),
|
||||
_location(location),
|
||||
_previousName(name),
|
||||
_updating(false) {
|
||||
}
|
||||
|
||||
void UserLocation::requestRename(const QString& newName) {
|
||||
if (!_updating && newName.toLower() != _name) {
|
||||
_updating = true;
|
||||
|
||||
JSONCallbackParameters callbackParams(this, "handleRenameResponse", this, "handleRenameError");
|
||||
QJsonObject jsonNameObject;
|
||||
jsonNameObject.insert("name", QJsonValue(newName));
|
||||
QJsonDocument jsonDocument(jsonNameObject);
|
||||
AccountManager::getInstance().authenticatedRequest(PLACES_UPDATE.arg(_id),
|
||||
QNetworkAccessManager::PutOperation,
|
||||
callbackParams,
|
||||
jsonDocument.toJson());
|
||||
_previousName = _name;
|
||||
_name = newName;
|
||||
|
||||
emit updated(_name);
|
||||
}
|
||||
}
|
||||
|
||||
void UserLocation::handleRenameResponse(const QJsonObject& responseData) {
|
||||
_updating = false;
|
||||
|
||||
QJsonValue status = responseData["status"];
|
||||
if (!status.isUndefined() && status.toString() == "success") {
|
||||
QString updatedName = responseData["data"].toObject()["name"].toString();
|
||||
_name = updatedName;
|
||||
} else {
|
||||
_name = _previousName;
|
||||
|
||||
QString msg = "There was an error renaming location '" + _name + "'";
|
||||
|
||||
QJsonValue data = responseData["data"];
|
||||
if (!data.isUndefined()) {
|
||||
QJsonValue nameError = data.toObject()["name"];
|
||||
if (!nameError.isUndefined()) {
|
||||
msg += ": " + nameError.toString();
|
||||
}
|
||||
}
|
||||
qDebug() << msg;
|
||||
QMessageBox::warning(Application::getInstance()->getWindow(), "Error", msg);
|
||||
}
|
||||
|
||||
emit updated(_name);
|
||||
}
|
||||
|
||||
void UserLocation::handleRenameError(QNetworkReply::NetworkError error, const QString& errorString) {
|
||||
_updating = false;
|
||||
|
||||
QString msg = "There was an error renaming location '" + _name + "': " + errorString;
|
||||
qDebug() << msg;
|
||||
QMessageBox::warning(Application::getInstance()->getWindow(), "Error", msg);
|
||||
|
||||
emit updated(_name);
|
||||
}
|
||||
|
||||
void UserLocation::requestDelete() {
|
||||
if (!_updating) {
|
||||
_updating = true;
|
||||
|
||||
JSONCallbackParameters callbackParams(this, "handleDeleteResponse", this, "handleDeleteError");
|
||||
AccountManager::getInstance().authenticatedRequest(PLACES_DELETE.arg(_id),
|
||||
QNetworkAccessManager::DeleteOperation,
|
||||
callbackParams);
|
||||
}
|
||||
}
|
||||
|
||||
void UserLocation::handleDeleteResponse(const QJsonObject& responseData) {
|
||||
_updating = false;
|
||||
|
||||
QJsonValue status = responseData["status"];
|
||||
if (!status.isUndefined() && status.toString() == "success") {
|
||||
emit deleted(_name);
|
||||
} else {
|
||||
QString msg = "There was an error deleting location '" + _name + "'";
|
||||
qDebug() << msg;
|
||||
QMessageBox::warning(Application::getInstance()->getWindow(), "Error", msg);
|
||||
}
|
||||
}
|
||||
|
||||
void UserLocation::handleDeleteError(QNetworkReply::NetworkError error, const QString& errorString) {
|
||||
_updating = false;
|
||||
|
||||
QString msg = "There was an error deleting location '" + _name + "': " + errorString;
|
||||
qDebug() << msg;
|
||||
QMessageBox::warning(Application::getInstance()->getWindow(), "Error", msg);
|
||||
}
|
||||
|
||||
UserLocationsModel::UserLocationsModel(QObject* parent) :
|
||||
QAbstractListModel(parent),
|
||||
_updating(false) {
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
UserLocationsModel::~UserLocationsModel() {
|
||||
qDeleteAll(_locations);
|
||||
_locations.clear();
|
||||
}
|
||||
|
||||
void UserLocationsModel::update() {
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void UserLocationsModel::deleteLocation(const QModelIndex& index) {
|
||||
UserLocation* location = _locations[index.row()];
|
||||
location->requestDelete();
|
||||
}
|
||||
|
||||
void UserLocationsModel::renameLocation(const QModelIndex& index, const QString& newName) {
|
||||
UserLocation* location = _locations[index.row()];
|
||||
location->requestRename(newName);
|
||||
}
|
||||
|
||||
void UserLocationsModel::refresh() {
|
||||
if (!_updating) {
|
||||
beginResetModel();
|
||||
qDeleteAll(_locations);
|
||||
_locations.clear();
|
||||
_updating = true;
|
||||
endResetModel();
|
||||
|
||||
JSONCallbackParameters callbackParams(this, "handleLocationsResponse");
|
||||
AccountManager::getInstance().authenticatedRequest(PLACES_GET,
|
||||
QNetworkAccessManager::GetOperation,
|
||||
callbackParams);
|
||||
}
|
||||
}
|
||||
|
||||
void UserLocationsModel::handleLocationsResponse(const QJsonObject& responseData) {
|
||||
_updating = false;
|
||||
|
||||
QJsonValue status = responseData["status"];
|
||||
if (!status.isUndefined() && status.toString() == "success") {
|
||||
beginResetModel();
|
||||
QJsonArray locations = responseData["data"].toObject()["places"].toArray();
|
||||
for (QJsonArray::const_iterator it = locations.constBegin(); it != locations.constEnd(); it++) {
|
||||
QJsonObject location = (*it).toObject();
|
||||
QJsonObject address = location["address"].toObject();
|
||||
UserLocation* userLocation = new UserLocation(location["id"].toString(), location["name"].toString(),
|
||||
"hifi://" + address["domain"].toString()
|
||||
+ "/" + address["position"].toString()
|
||||
+ "/" + address["orientation"].toString());
|
||||
_locations.append(userLocation);
|
||||
connect(userLocation, &UserLocation::deleted, this, &UserLocationsModel::removeLocation);
|
||||
connect(userLocation, &UserLocation::updated, this, &UserLocationsModel::update);
|
||||
}
|
||||
endResetModel();
|
||||
} else {
|
||||
qDebug() << "Error loading location data";
|
||||
}
|
||||
}
|
||||
|
||||
void UserLocationsModel::removeLocation(const QString& name) {
|
||||
beginResetModel();
|
||||
for (QList<UserLocation*>::iterator it = _locations.begin(); it != _locations.end(); it++) {
|
||||
if ((*it)->name() == name) {
|
||||
_locations.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
int UserLocationsModel::rowCount(const QModelIndex& parent) const {
|
||||
if (parent.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_updating) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return _locations.length();
|
||||
}
|
||||
|
||||
QVariant UserLocationsModel::data(const QModelIndex& index, int role) const {
|
||||
if (role == Qt::DisplayRole) {
|
||||
if (_updating) {
|
||||
return QVariant("Updating...");
|
||||
} else if (index.row() > _locations.length()) {
|
||||
return QVariant();
|
||||
} else if (index.column() == NameColumn) {
|
||||
return _locations[index.row()]->name();
|
||||
} else if (index.column() == LocationColumn) {
|
||||
return QVariant(_locations[index.row()]->location());
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
|
||||
}
|
||||
QVariant UserLocationsModel::headerData(int section, Qt::Orientation orientation, int role) const {
|
||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
||||
switch (section) {
|
||||
case NameColumn: return "Name";
|
||||
case LocationColumn: return "Location";
|
||||
default: return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
Qt::ItemFlags UserLocationsModel::flags(const QModelIndex& index) const {
|
||||
if (index.row() < _locations.length()) {
|
||||
UserLocation* ul = _locations[index.row()];
|
||||
if (ul->isUpdating()) {
|
||||
return Qt::NoItemFlags;
|
||||
}
|
||||
}
|
||||
|
||||
return QAbstractListModel::flags(index);
|
||||
}
|
82
interface/src/UserLocationsModel.h
Normal file
82
interface/src/UserLocationsModel.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
//
|
||||
// UserLocationsModel.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by Ryan Huffman on 06/24/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_UserLocationsModel_h
|
||||
#define hifi_UserLocationsModel_h
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QModelIndex>
|
||||
#include <QVariant>
|
||||
|
||||
|
||||
class UserLocation : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
UserLocation(QString id, QString name, QString location);
|
||||
bool isUpdating() { return _updating; }
|
||||
void requestRename(const QString& newName);
|
||||
void requestDelete();
|
||||
|
||||
QString id() { return _id; }
|
||||
QString name() { return _name; }
|
||||
QString location() { return _location; }
|
||||
|
||||
public slots:
|
||||
void handleRenameResponse(const QJsonObject& responseData);
|
||||
void handleRenameError(QNetworkReply::NetworkError error, const QString& errorString);
|
||||
void handleDeleteResponse(const QJsonObject& responseData);
|
||||
void handleDeleteError(QNetworkReply::NetworkError error, const QString& errorString);
|
||||
|
||||
signals:
|
||||
void updated(const QString& name);
|
||||
void deleted(const QString& name);
|
||||
|
||||
private:
|
||||
QString _id;
|
||||
QString _name;
|
||||
QString _location;
|
||||
QString _previousName;
|
||||
bool _updating;
|
||||
|
||||
};
|
||||
|
||||
class UserLocationsModel : public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
UserLocationsModel(QObject* parent = NULL);
|
||||
~UserLocationsModel();
|
||||
|
||||
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
||||
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
|
||||
virtual int columnCount(const QModelIndex& parent = QModelIndex()) const { return 2; };
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
virtual Qt::ItemFlags flags(const QModelIndex& index) const;
|
||||
|
||||
void deleteLocation(const QModelIndex& index);
|
||||
void renameLocation(const QModelIndex& index, const QString& newName);
|
||||
|
||||
enum Columns {
|
||||
NameColumn = 0,
|
||||
LocationColumn
|
||||
};
|
||||
|
||||
public slots:
|
||||
void refresh();
|
||||
void update();
|
||||
void handleLocationsResponse(const QJsonObject& responseData);
|
||||
void removeLocation(const QString& name);
|
||||
|
||||
private:
|
||||
bool _updating;
|
||||
QList<UserLocation*> _locations;
|
||||
};
|
||||
|
||||
#endif // hifi_UserLocationsModel_h
|
|
@ -51,10 +51,10 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX
|
|||
glm::mat3 axes = glm::mat3_cast(glm::quat());
|
||||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() * glm::translate(state.getDefaultTranslationInParentFrame()) *
|
||||
joint.preTransform * glm::mat4_cast(joint.preRotation)));
|
||||
state._rotationInParentFrame = glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalRoll(), glm::normalize(inverse * axes[2]))
|
||||
state.setRotationInParentFrame(glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalRoll(), glm::normalize(inverse * axes[2]))
|
||||
* glm::angleAxis(RADIANS_PER_DEGREE * _owningHead->getFinalYaw(), glm::normalize(inverse * axes[1]))
|
||||
* glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalPitch(), glm::normalize(inverse * axes[0]))
|
||||
* joint.rotation;
|
||||
* joint.rotation);
|
||||
}
|
||||
|
||||
void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) {
|
||||
|
@ -68,8 +68,8 @@ void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJ
|
|||
_owningHead->getSaccade() - _translation, 1.0f));
|
||||
glm::quat between = rotationBetween(front, lookAt);
|
||||
const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE;
|
||||
state._rotationInParentFrame = glm::angleAxis(glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE), glm::axis(between)) *
|
||||
joint.rotation;
|
||||
state.setRotationInParentFrame(glm::angleAxis(glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE), glm::axis(between)) *
|
||||
joint.rotation);
|
||||
}
|
||||
|
||||
void FaceModel::updateJointState(int index) {
|
||||
|
|
|
@ -219,10 +219,9 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) {
|
|||
JointState& parentState = _jointStates[parentJointIndex];
|
||||
parentState.setRotationFromBindFrame(palmRotation, PALM_PRIORITY);
|
||||
// lock hand to forearm by slamming its rotation (in parent-frame) to identity
|
||||
_jointStates[jointIndex]._rotationInParentFrame = glm::quat();
|
||||
_jointStates[jointIndex].setRotationInParentFrame(glm::quat());
|
||||
} else {
|
||||
setJointPosition(jointIndex, palmPosition, palmRotation,
|
||||
true, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY);
|
||||
inverseKinematics(jointIndex, palmPosition, palmRotation, PALM_PRIORITY);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,9 +257,9 @@ void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const
|
|||
glm::mat3 axes = glm::mat3_cast(glm::quat());
|
||||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() * glm::translate(state.getDefaultTranslationInParentFrame()) *
|
||||
joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation)));
|
||||
state._rotationInParentFrame = glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanSideways(),
|
||||
state.setRotationInParentFrame(glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanSideways(),
|
||||
glm::normalize(inverse * axes[2])) * glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanForward(),
|
||||
glm::normalize(inverse * axes[0])) * joint.rotation;
|
||||
glm::normalize(inverse * axes[0])) * joint.rotation);
|
||||
}
|
||||
|
||||
void SkeletonModel::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) {
|
||||
|
@ -537,6 +536,11 @@ void SkeletonModel::buildRagdollConstraints() {
|
|||
}
|
||||
}
|
||||
|
||||
void SkeletonModel::updateVisibleJointStates() {
|
||||
Model::updateVisibleJointStates();
|
||||
// TODO: implement this to move visible joints to agree with joint shape positions
|
||||
}
|
||||
|
||||
// virtual
|
||||
void SkeletonModel::stepRagdollForward(float deltaTime) {
|
||||
const float RAGDOLL_FOLLOWS_JOINTS_TIMESCALE = 0.03f;
|
||||
|
@ -644,7 +648,6 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) {
|
|||
_ragdollPoints[i]._lastPosition = _ragdollPoints[i]._position;
|
||||
continue;
|
||||
}
|
||||
assert(parentIndex != -1);
|
||||
|
||||
glm::quat modifiedRotation = joint.preRotation * joint.rotation * joint.postRotation;
|
||||
transforms[i] = transforms[parentIndex] * glm::translate(joint.translation)
|
||||
|
@ -700,7 +703,7 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) {
|
|||
_boundingRadius = 0.5f * glm::length(diagonal);
|
||||
}
|
||||
|
||||
void SkeletonModel::resetShapePositions() {
|
||||
void SkeletonModel::resetShapePositionsToDefaultPose() {
|
||||
// DEBUG method.
|
||||
// Moves shapes to the joint default locations for debug visibility into
|
||||
// how the bounding shape is computed.
|
||||
|
|
|
@ -93,6 +93,8 @@ public:
|
|||
/// Retrieve the positions of up to two eye meshes.
|
||||
/// \return whether or not both eye meshes were found
|
||||
bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const;
|
||||
|
||||
virtual void updateVisibleJointStates();
|
||||
|
||||
// virtual overrride from Ragdoll
|
||||
virtual void stepRagdollForward(float deltaTime);
|
||||
|
@ -104,7 +106,7 @@ public:
|
|||
float getBoundingShapeRadius() const { return _boundingShape.getRadius(); }
|
||||
const CapsuleShape& getBoundingShape() const { return _boundingShape; }
|
||||
|
||||
void resetShapePositions(); // DEBUG method
|
||||
void resetShapePositionsToDefaultPose(); // DEBUG method
|
||||
|
||||
void renderRagdoll();
|
||||
protected:
|
||||
|
|
|
@ -266,7 +266,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
|
|||
|
||||
ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay();
|
||||
|
||||
// We only need to render the overlays to a texture once, then we just render the texture as a quad
|
||||
// We only need to render the overlays to a texture once, then we just render the texture on the hemisphere
|
||||
// PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay()
|
||||
applicationOverlay.renderOverlay(true);
|
||||
const bool displayOverlays = Menu::getInstance()->isOptionChecked(MenuOption::DisplayOculusOverlays);
|
||||
|
|
|
@ -93,6 +93,18 @@ void TV3DManager::display(Camera& whichCamera) {
|
|||
int portalW = Application::getInstance()->getGLWidget()->width() / 2;
|
||||
int portalH = Application::getInstance()->getGLWidget()->height();
|
||||
|
||||
const bool glowEnabled = Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect);
|
||||
|
||||
ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay();
|
||||
|
||||
// We only need to render the overlays to a texture once, then we just render the texture as a quad
|
||||
// PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay()
|
||||
applicationOverlay.renderOverlay(true);
|
||||
|
||||
if (glowEnabled) {
|
||||
Application::getInstance()->getGlowEffect()->prepare();
|
||||
}
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
|
@ -102,13 +114,21 @@ void TV3DManager::display(Camera& whichCamera) {
|
|||
|
||||
glPushMatrix();
|
||||
{
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity(); // reset projection matrix
|
||||
glFrustum(_leftEye.left, _leftEye.right, _leftEye.bottom, _leftEye.top, nearZ, farZ); // set left view frustum
|
||||
GLfloat p[4][4];
|
||||
glGetFloatv(GL_PROJECTION_MATRIX, &(p[0][0]));
|
||||
GLfloat cotangent = p[1][1];
|
||||
GLfloat fov = atan(1.0f / cotangent);
|
||||
glTranslatef(_leftEye.modelTranslation, 0.0, 0.0); // translate to cancel parallax
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
Application::getInstance()->displaySide(whichCamera);
|
||||
|
||||
applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov);
|
||||
}
|
||||
glPopMatrix();
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
@ -124,14 +144,25 @@ void TV3DManager::display(Camera& whichCamera) {
|
|||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity(); // reset projection matrix
|
||||
glFrustum(_rightEye.left, _rightEye.right, _rightEye.bottom, _rightEye.top, nearZ, farZ); // set left view frustum
|
||||
GLfloat p[4][4];
|
||||
glGetFloatv(GL_PROJECTION_MATRIX, &(p[0][0]));
|
||||
GLfloat cotangent = p[1][1];
|
||||
GLfloat fov = atan(1.0f / cotangent);
|
||||
glTranslatef(_rightEye.modelTranslation, 0.0, 0.0); // translate to cancel parallax
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
Application::getInstance()->displaySide(whichCamera);
|
||||
|
||||
applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov);
|
||||
}
|
||||
glPopMatrix();
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
// reset the viewport to how we started
|
||||
glViewport(0, 0, Application::getInstance()->getGLWidget()->width(), Application::getInstance()->getGLWidget()->height());
|
||||
|
||||
if (glowEnabled) {
|
||||
Application::getInstance()->getGlowEffect()->render();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,14 +11,26 @@
|
|||
|
||||
#include <glm/gtx/norm.hpp>
|
||||
|
||||
//#include <GeometryUtil.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "JointState.h"
|
||||
|
||||
JointState::JointState() :
|
||||
_animationPriority(0.0f),
|
||||
_fbxJoint(NULL) {
|
||||
_fbxJoint(NULL),
|
||||
_isConstrained(false) {
|
||||
}
|
||||
|
||||
void JointState::copyState(const JointState& state) {
|
||||
_animationPriority = state._animationPriority;
|
||||
_transform = state._transform;
|
||||
_rotation = extractRotation(_transform);
|
||||
_rotationInParentFrame = state._rotationInParentFrame;
|
||||
|
||||
_visibleTransform = state._visibleTransform;
|
||||
_visibleRotation = extractRotation(_visibleTransform);
|
||||
_visibleRotationInParentFrame = state._visibleRotationInParentFrame;
|
||||
// DO NOT copy _fbxJoint
|
||||
}
|
||||
|
||||
void JointState::setFBXJoint(const FBXJoint* joint) {
|
||||
|
@ -26,14 +38,10 @@ void JointState::setFBXJoint(const FBXJoint* joint) {
|
|||
_rotationInParentFrame = joint->rotation;
|
||||
// NOTE: JointState does not own the FBXJoint to which it points.
|
||||
_fbxJoint = joint;
|
||||
}
|
||||
|
||||
void JointState::copyState(const JointState& state) {
|
||||
_rotationInParentFrame = state._rotationInParentFrame;
|
||||
_transform = state._transform;
|
||||
_rotation = extractRotation(_transform);
|
||||
_animationPriority = state._animationPriority;
|
||||
// DO NOT copy _fbxJoint
|
||||
// precompute whether there are any constraints or not
|
||||
float distanceMin = glm::distance(_fbxJoint->rotationMin, glm::vec3(-PI));
|
||||
float distanceMax = glm::distance(_fbxJoint->rotationMax, glm::vec3(PI));
|
||||
_isConstrained = distanceMin > EPSILON || distanceMax > EPSILON;
|
||||
}
|
||||
|
||||
void JointState::computeTransform(const glm::mat4& parentTransform) {
|
||||
|
@ -43,6 +51,13 @@ void JointState::computeTransform(const glm::mat4& parentTransform) {
|
|||
_rotation = extractRotation(_transform);
|
||||
}
|
||||
|
||||
void JointState::computeVisibleTransform(const glm::mat4& parentTransform) {
|
||||
glm::quat modifiedRotation = _fbxJoint->preRotation * _visibleRotationInParentFrame * _fbxJoint->postRotation;
|
||||
glm::mat4 modifiedTransform = _fbxJoint->preTransform * glm::mat4_cast(modifiedRotation) * _fbxJoint->postTransform;
|
||||
_visibleTransform = parentTransform * glm::translate(_fbxJoint->translation) * modifiedTransform;
|
||||
_visibleRotation = extractRotation(_visibleTransform);
|
||||
}
|
||||
|
||||
glm::quat JointState::getRotationFromBindToModelFrame() const {
|
||||
return _rotation * _fbxJoint->inverseBindRotation;
|
||||
}
|
||||
|
@ -50,16 +65,16 @@ glm::quat JointState::getRotationFromBindToModelFrame() const {
|
|||
void JointState::restoreRotation(float fraction, float priority) {
|
||||
assert(_fbxJoint != NULL);
|
||||
if (priority == _animationPriority || _animationPriority == 0.0f) {
|
||||
_rotationInParentFrame = safeMix(_rotationInParentFrame, _fbxJoint->rotation, fraction);
|
||||
setRotationInParentFrame(safeMix(_rotationInParentFrame, _fbxJoint->rotation, fraction));
|
||||
_animationPriority = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void JointState::setRotationFromBindFrame(const glm::quat& rotation, float priority) {
|
||||
// rotation is from bind- to model-frame
|
||||
assert(_fbxJoint != NULL);
|
||||
if (priority >= _animationPriority) {
|
||||
// rotation is from bind- to model-frame
|
||||
_rotationInParentFrame = _rotationInParentFrame * glm::inverse(_rotation) * rotation * glm::inverse(_fbxJoint->inverseBindRotation);
|
||||
setRotationInParentFrame(_rotationInParentFrame * glm::inverse(_rotation) * rotation * glm::inverse(_fbxJoint->inverseBindRotation));
|
||||
_animationPriority = priority;
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +83,9 @@ void JointState::clearTransformTranslation() {
|
|||
_transform[3][0] = 0.0f;
|
||||
_transform[3][1] = 0.0f;
|
||||
_transform[3][2] = 0.0f;
|
||||
_visibleTransform[3][0] = 0.0f;
|
||||
_visibleTransform[3][1] = 0.0f;
|
||||
_visibleTransform[3][2] = 0.0f;
|
||||
}
|
||||
|
||||
void JointState::setRotation(const glm::quat& rotation, bool constrain, float priority) {
|
||||
|
@ -75,27 +93,59 @@ void JointState::setRotation(const glm::quat& rotation, bool constrain, float pr
|
|||
}
|
||||
|
||||
void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, float priority) {
|
||||
// NOTE: delta is in jointParent-frame
|
||||
// NOTE: delta is in model-frame
|
||||
assert(_fbxJoint != NULL);
|
||||
if (priority < _animationPriority) {
|
||||
return;
|
||||
}
|
||||
_animationPriority = priority;
|
||||
if (!constrain || (_fbxJoint->rotationMin == glm::vec3(-PI, -PI, -PI) &&
|
||||
_fbxJoint->rotationMax == glm::vec3(PI, PI, PI))) {
|
||||
if (!constrain || !_isConstrained) {
|
||||
// no constraints
|
||||
_rotationInParentFrame = _rotationInParentFrame * glm::inverse(_rotation) * delta * _rotation;
|
||||
_rotation = delta * _rotation;
|
||||
return;
|
||||
}
|
||||
glm::quat targetRotation = delta * _rotation;
|
||||
glm::vec3 eulers = safeEulerAngles(_rotationInParentFrame * glm::inverse(_rotation) * targetRotation);
|
||||
glm::quat newRotation = glm::quat(glm::clamp(eulers, _fbxJoint->rotationMin, _fbxJoint->rotationMax));
|
||||
_rotation = _rotation * glm::inverse(_rotationInParentFrame) * newRotation;
|
||||
_rotationInParentFrame = newRotation;
|
||||
glm::quat targetRotation = _rotationInParentFrame * glm::inverse(_rotation) * delta * _rotation;
|
||||
setRotationInParentFrame(targetRotation);
|
||||
}
|
||||
|
||||
/// Applies delta rotation to joint but mixes a little bit of the default pose as well.
|
||||
/// This helps keep an IK solution stable.
|
||||
void JointState::mixRotationDelta(const glm::quat& delta, float mixFactor, float priority) {
|
||||
// NOTE: delta is in model-frame
|
||||
assert(_fbxJoint != NULL);
|
||||
if (priority < _animationPriority) {
|
||||
return;
|
||||
}
|
||||
_animationPriority = priority;
|
||||
glm::quat targetRotation = _rotationInParentFrame * glm::inverse(_rotation) * delta * _rotation;
|
||||
if (mixFactor > 0.0f && mixFactor <= 1.0f) {
|
||||
targetRotation = safeMix(targetRotation, _fbxJoint->rotation, mixFactor);
|
||||
}
|
||||
setRotationInParentFrame(targetRotation);
|
||||
}
|
||||
|
||||
|
||||
glm::quat JointState::computeParentRotation() const {
|
||||
// R = Rp * Rpre * r * Rpost
|
||||
// Rp = R * (Rpre * r * Rpost)^
|
||||
return _rotation * glm::inverse(_fbxJoint->preRotation * _rotationInParentFrame * _fbxJoint->postRotation);
|
||||
}
|
||||
|
||||
void JointState::setRotationInParentFrame(const glm::quat& targetRotation) {
|
||||
glm::quat parentRotation = computeParentRotation();
|
||||
_rotationInParentFrame = targetRotation;
|
||||
// R' = Rp * Rpre * r' * Rpost
|
||||
_rotation = parentRotation * _fbxJoint->preRotation * _rotationInParentFrame * _fbxJoint->postRotation;
|
||||
}
|
||||
|
||||
const glm::vec3& JointState::getDefaultTranslationInParentFrame() const {
|
||||
assert(_fbxJoint != NULL);
|
||||
return _fbxJoint->translation;
|
||||
}
|
||||
|
||||
void JointState::slaveVisibleTransform() {
|
||||
_visibleTransform = _transform;
|
||||
_visibleRotation = _rotation;
|
||||
_visibleRotationInParentFrame = _rotationInParentFrame;
|
||||
}
|
||||
|
|
|
@ -22,12 +22,19 @@ class JointState {
|
|||
public:
|
||||
JointState();
|
||||
|
||||
void copyState(const JointState& state);
|
||||
|
||||
void setFBXJoint(const FBXJoint* joint);
|
||||
const FBXJoint& getFBXJoint() const { return *_fbxJoint; }
|
||||
|
||||
void copyState(const JointState& state);
|
||||
|
||||
void computeTransform(const glm::mat4& parentTransform);
|
||||
|
||||
void computeVisibleTransform(const glm::mat4& parentTransform);
|
||||
const glm::mat4& getVisibleTransform() const { return _visibleTransform; }
|
||||
glm::quat getVisibleRotation() const { return _visibleRotation; }
|
||||
glm::vec3 getVisiblePosition() const { return extractTranslation(_visibleTransform); }
|
||||
|
||||
const glm::mat4& getTransform() const { return _transform; }
|
||||
|
||||
glm::quat getRotation() const { return _rotation; }
|
||||
|
@ -39,11 +46,19 @@ public:
|
|||
/// \param rotation rotation of joint in model-frame
|
||||
void setRotation(const glm::quat& rotation, bool constrain, float priority);
|
||||
|
||||
/// \param delta is in the jointParent-frame
|
||||
/// \param delta is in the model-frame
|
||||
void applyRotationDelta(const glm::quat& delta, bool constrain = true, float priority = 1.0f);
|
||||
|
||||
const glm::vec3& getDefaultTranslationInParentFrame() const;
|
||||
/// Applies delta rotation to joint but mixes a little bit of the default pose as well.
|
||||
/// This helps keep an IK solution stable.
|
||||
/// \param delta rotation change in model-frame
|
||||
/// \param mixFactor fraction in range [0,1] of how much default pose to blend in (0 is none, 1 is all)
|
||||
/// \param priority priority level of this animation blend
|
||||
void mixRotationDelta(const glm::quat& delta, float mixFactor, float priority = 1.0f);
|
||||
|
||||
/// Blends a fraciton of default pose into joint rotation.
|
||||
/// \param fraction fraction in range [0,1] of how much default pose to blend in (0 is none, 1 is all)
|
||||
/// \param priority priority level of this animation blend
|
||||
void restoreRotation(float fraction, float priority);
|
||||
|
||||
/// \param rotation is from bind- to model-frame
|
||||
|
@ -51,16 +66,36 @@ public:
|
|||
/// NOTE: the JointState's model-frame transform/rotation are NOT updated!
|
||||
void setRotationFromBindFrame(const glm::quat& rotation, float priority);
|
||||
|
||||
void setRotationInParentFrame(const glm::quat& targetRotation);
|
||||
const glm::quat& getRotationInParentFrame() const { return _rotationInParentFrame; }
|
||||
|
||||
const glm::vec3& getDefaultTranslationInParentFrame() const;
|
||||
|
||||
|
||||
void clearTransformTranslation();
|
||||
|
||||
glm::quat _rotationInParentFrame; // joint- to parentJoint-frame
|
||||
void slaveVisibleTransform();
|
||||
|
||||
float _animationPriority; // the priority of the animation affecting this joint
|
||||
|
||||
private:
|
||||
/// \return parent model-frame rotation
|
||||
// (used to keep _rotation consistent when modifying _rotationInWorldFrame directly)
|
||||
glm::quat computeParentRotation() const;
|
||||
|
||||
/// debug helper function
|
||||
void loadBindRotation();
|
||||
|
||||
glm::mat4 _transform; // joint- to model-frame
|
||||
glm::quat _rotation; // joint- to model-frame
|
||||
glm::quat _rotationInParentFrame; // joint- to parentJoint-frame
|
||||
|
||||
glm::mat4 _visibleTransform;
|
||||
glm::quat _visibleRotation;
|
||||
glm::quat _visibleRotationInParentFrame;
|
||||
|
||||
const FBXJoint* _fbxJoint; // JointState does NOT own its FBXJoint
|
||||
bool _isConstrained;
|
||||
};
|
||||
|
||||
#endif // hifi_JointState_h
|
||||
|
|
|
@ -39,8 +39,8 @@ Model::Model(QObject* parent) :
|
|||
_scaledToFit(false),
|
||||
_snapModelToCenter(false),
|
||||
_snappedToCenter(false),
|
||||
_showTrueJointTransforms(false),
|
||||
_rootIndex(-1),
|
||||
//_enableCollisionShapes(false),
|
||||
_lodDistance(0.0f),
|
||||
_pupilDilation(0.0f),
|
||||
_url("http://invalid.com") {
|
||||
|
@ -460,7 +460,7 @@ void Model::reset() {
|
|||
}
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
for (int i = 0; i < _jointStates.size(); i++) {
|
||||
_jointStates[i]._rotationInParentFrame = geometry.joints.at(i).rotation;
|
||||
_jointStates[i].setRotationInParentFrame(geometry.joints.at(i).rotation);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -571,6 +571,9 @@ void Model::setJointStates(QVector<JointState> states) {
|
|||
radius = distance;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < _jointStates.size(); i++) {
|
||||
_jointStates[i].slaveVisibleTransform();
|
||||
}
|
||||
_boundingRadius = radius;
|
||||
}
|
||||
|
||||
|
@ -686,7 +689,7 @@ bool Model::getJointState(int index, glm::quat& rotation) const {
|
|||
if (index == -1 || index >= _jointStates.size()) {
|
||||
return false;
|
||||
}
|
||||
rotation = _jointStates.at(index)._rotationInParentFrame;
|
||||
rotation = _jointStates.at(index).getRotationInParentFrame();
|
||||
const glm::quat& defaultRotation = _geometry->getFBXGeometry().joints.at(index).rotation;
|
||||
return glm::abs(rotation.x - defaultRotation.x) >= EPSILON ||
|
||||
glm::abs(rotation.y - defaultRotation.y) >= EPSILON ||
|
||||
|
@ -699,7 +702,7 @@ void Model::setJointState(int index, bool valid, const glm::quat& rotation, floa
|
|||
JointState& state = _jointStates[index];
|
||||
if (priority >= state._animationPriority) {
|
||||
if (valid) {
|
||||
state._rotationInParentFrame = rotation;
|
||||
state.setRotationInParentFrame(rotation);
|
||||
state._animationPriority = priority;
|
||||
} else {
|
||||
state.restoreRotation(1.0f, priority);
|
||||
|
@ -765,6 +768,23 @@ bool Model::getJointCombinedRotation(int jointIndex, glm::quat& rotation) const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Model::getVisibleJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const {
|
||||
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
|
||||
return false;
|
||||
}
|
||||
// position is in world-frame
|
||||
position = _translation + _rotation * _jointStates[jointIndex].getVisiblePosition();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Model::getVisibleJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const {
|
||||
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
|
||||
return false;
|
||||
}
|
||||
rotation = _rotation * _jointStates[jointIndex].getVisibleRotation();
|
||||
return true;
|
||||
}
|
||||
|
||||
QStringList Model::getJointNames() const {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QStringList result;
|
||||
|
@ -918,6 +938,8 @@ void Model::simulateInternal(float deltaTime) {
|
|||
for (int i = 0; i < _jointStates.size(); i++) {
|
||||
updateJointState(i);
|
||||
}
|
||||
updateVisibleJointStates();
|
||||
|
||||
_shapesAreDirty = ! _shapes.isEmpty();
|
||||
|
||||
// update the attachment transforms and simulate them
|
||||
|
@ -928,8 +950,13 @@ void Model::simulateInternal(float deltaTime) {
|
|||
|
||||
glm::vec3 jointTranslation = _translation;
|
||||
glm::quat jointRotation = _rotation;
|
||||
getJointPositionInWorldFrame(attachment.jointIndex, jointTranslation);
|
||||
getJointRotationInWorldFrame(attachment.jointIndex, jointRotation);
|
||||
if (_showTrueJointTransforms) {
|
||||
getJointPositionInWorldFrame(attachment.jointIndex, jointTranslation);
|
||||
getJointRotationInWorldFrame(attachment.jointIndex, jointRotation);
|
||||
} else {
|
||||
getVisibleJointPositionInWorldFrame(attachment.jointIndex, jointTranslation);
|
||||
getVisibleJointRotationInWorldFrame(attachment.jointIndex, jointRotation);
|
||||
}
|
||||
|
||||
model->setTranslation(jointTranslation + jointRotation * attachment.translation * _scale);
|
||||
model->setRotation(jointRotation * attachment.rotation);
|
||||
|
@ -944,9 +971,16 @@ void Model::simulateInternal(float deltaTime) {
|
|||
for (int i = 0; i < _meshStates.size(); i++) {
|
||||
MeshState& state = _meshStates[i];
|
||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||
for (int j = 0; j < mesh.clusters.size(); j++) {
|
||||
const FBXCluster& cluster = mesh.clusters.at(j);
|
||||
state.clusterMatrices[j] = modelToWorld * _jointStates[cluster.jointIndex].getTransform() * cluster.inverseBindMatrix;
|
||||
if (_showTrueJointTransforms) {
|
||||
for (int j = 0; j < mesh.clusters.size(); j++) {
|
||||
const FBXCluster& cluster = mesh.clusters.at(j);
|
||||
state.clusterMatrices[j] = modelToWorld * _jointStates[cluster.jointIndex].getTransform() * cluster.inverseBindMatrix;
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < mesh.clusters.size(); j++) {
|
||||
const FBXCluster& cluster = mesh.clusters.at(j);
|
||||
state.clusterMatrices[j] = modelToWorld * _jointStates[cluster.jointIndex].getVisibleTransform() * cluster.inverseBindMatrix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -972,6 +1006,14 @@ void Model::updateJointState(int index) {
|
|||
}
|
||||
}
|
||||
|
||||
void Model::updateVisibleJointStates() {
|
||||
if (!_showTrueJointTransforms) {
|
||||
for (int i = 0; i < _jointStates.size(); i++) {
|
||||
_jointStates[i].slaveVisibleTransform();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Model::setJointPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation, bool useRotation,
|
||||
int lastFreeIndex, bool allIntermediatesFree, const glm::vec3& alignment, float priority) {
|
||||
if (jointIndex == -1 || _jointStates.isEmpty()) {
|
||||
|
@ -1058,6 +1100,128 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position, const gl
|
|||
return true;
|
||||
}
|
||||
|
||||
void Model::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm::quat& targetRotation, float priority) {
|
||||
// NOTE: targetRotation is from bind- to model-frame
|
||||
|
||||
if (endIndex == -1 || _jointStates.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
const QVector<int>& freeLineage = geometry.joints.at(endIndex).freeLineage;
|
||||
if (freeLineage.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
int numFree = freeLineage.size();
|
||||
|
||||
// store and remember topmost parent transform
|
||||
glm::mat4 topParentTransform;
|
||||
{
|
||||
int index = freeLineage.last();
|
||||
const JointState& state = _jointStates.at(index);
|
||||
const FBXJoint& joint = state.getFBXJoint();
|
||||
int parentIndex = joint.parentIndex;
|
||||
if (parentIndex == -1) {
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
topParentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset;
|
||||
} else {
|
||||
topParentTransform = _jointStates[parentIndex].getTransform();
|
||||
}
|
||||
}
|
||||
|
||||
// this is a cyclic coordinate descent algorithm: see
|
||||
// http://www.ryanjuckett.com/programming/animation/21-cyclic-coordinate-descent-in-2d
|
||||
|
||||
// keep track of the position of the end-effector
|
||||
JointState& endState = _jointStates[endIndex];
|
||||
glm::vec3 endPosition = endState.getPosition();
|
||||
float distanceToGo = glm::distance(targetPosition, endPosition);
|
||||
|
||||
const int MAX_ITERATION_COUNT = 2;
|
||||
const float ACCEPTABLE_IK_ERROR = 0.005f; // 5mm
|
||||
int numIterations = 0;
|
||||
do {
|
||||
++numIterations;
|
||||
// moving up, rotate each free joint to get endPosition closer to target
|
||||
for (int j = 1; j < numFree; j++) {
|
||||
int nextIndex = freeLineage.at(j);
|
||||
JointState& nextState = _jointStates[nextIndex];
|
||||
FBXJoint nextJoint = nextState.getFBXJoint();
|
||||
if (! nextJoint.isFree) {
|
||||
continue;
|
||||
}
|
||||
|
||||
glm::vec3 pivot = nextState.getPosition();
|
||||
glm::vec3 leverArm = endPosition - pivot;
|
||||
float leverLength = glm::length(leverArm);
|
||||
if (leverLength < EPSILON) {
|
||||
continue;
|
||||
}
|
||||
glm::quat deltaRotation = rotationBetween(leverArm, targetPosition - pivot);
|
||||
|
||||
/* DON'T REMOVE! This code provides the gravitational effect on the IK solution.
|
||||
* It is commented out for the moment because we're blending the IK solution with
|
||||
* the default pose which provides similar stability, but we might want to use
|
||||
* gravity again later.
|
||||
|
||||
// We want to mix the shortest rotation with one that will pull the system down with gravity.
|
||||
// So we compute a simplified center of mass, where each joint has a mass of 1.0 and we don't
|
||||
// bother averaging it because we only need direction.
|
||||
if (j > 1) {
|
||||
|
||||
glm::vec3 centerOfMass(0.0f);
|
||||
for (int k = 0; k < j; ++k) {
|
||||
int massIndex = freeLineage.at(k);
|
||||
centerOfMass += _jointStates[massIndex].getPosition() - pivot;
|
||||
}
|
||||
// the gravitational effect is a rotation that tends to align the two cross products
|
||||
const glm::vec3 worldAlignment = glm::vec3(0.0f, -1.f, 0.0f);
|
||||
glm::quat gravityDelta = rotationBetween(glm::cross(centerOfMass, leverArm),
|
||||
glm::cross(worldAlignment, leverArm));
|
||||
|
||||
float gravityAngle = glm::angle(gravityDelta);
|
||||
const float MIN_GRAVITY_ANGLE = 0.1f;
|
||||
float mixFactor = 0.5f;
|
||||
if (gravityAngle < MIN_GRAVITY_ANGLE) {
|
||||
// the final rotation is a mix of the two
|
||||
mixFactor = 0.5f * gravityAngle / MIN_GRAVITY_ANGLE;
|
||||
}
|
||||
deltaRotation = safeMix(deltaRotation, gravityDelta, mixFactor);
|
||||
}
|
||||
*/
|
||||
|
||||
// Apply the rotation, but use mixRotationDelta() which blends a bit of the default pose
|
||||
// at in the process. This provides stability to the IK solution and removes the necessity
|
||||
// for the gravity effect.
|
||||
glm::quat oldNextRotation = nextState.getRotation();
|
||||
float mixFactor = 0.03f;
|
||||
nextState.mixRotationDelta(deltaRotation, mixFactor, priority);
|
||||
|
||||
// measure the result of the rotation which may have been modified by
|
||||
// blending and constraints
|
||||
glm::quat actualDelta = nextState.getRotation() * glm::inverse(oldNextRotation);
|
||||
endPosition = pivot + actualDelta * leverArm;
|
||||
}
|
||||
|
||||
// recompute transforms from the top down
|
||||
glm::mat4 parentTransform = topParentTransform;
|
||||
for (int j = numFree - 1; j >= 0; --j) {
|
||||
JointState& freeState = _jointStates[freeLineage.at(j)];
|
||||
freeState.computeTransform(parentTransform);
|
||||
parentTransform = freeState.getTransform();
|
||||
}
|
||||
|
||||
// measure our success
|
||||
endPosition = endState.getPosition();
|
||||
distanceToGo = glm::distance(targetPosition, endPosition);
|
||||
} while (numIterations < MAX_ITERATION_COUNT && distanceToGo < ACCEPTABLE_IK_ERROR);
|
||||
|
||||
// set final rotation of the end joint
|
||||
endState.setRotationFromBindFrame(targetRotation, priority);
|
||||
|
||||
_shapesAreDirty = !_shapes.isEmpty();
|
||||
}
|
||||
|
||||
bool Model::restoreJointPosition(int jointIndex, float fraction, float priority) {
|
||||
if (jointIndex == -1 || _jointStates.isEmpty()) {
|
||||
return false;
|
||||
|
@ -1605,7 +1769,7 @@ void AnimationHandle::applyFrame(float frameIndex) {
|
|||
if (mapping != -1) {
|
||||
JointState& state = _model->_jointStates[mapping];
|
||||
if (_priority >= state._animationPriority) {
|
||||
state._rotationInParentFrame = safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction);
|
||||
state.setRotationInParentFrame(safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction));
|
||||
state._animationPriority = _priority;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,6 +120,9 @@ public:
|
|||
bool getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const;
|
||||
bool getJointCombinedRotation(int jointIndex, glm::quat& rotation) const;
|
||||
|
||||
bool getVisibleJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const;
|
||||
bool getVisibleJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const;
|
||||
|
||||
/// \param jointIndex index of joint in model structure
|
||||
/// \param position[out] position of joint in model-frame
|
||||
/// \return true if joint exists
|
||||
|
@ -152,6 +155,7 @@ protected:
|
|||
|
||||
bool _snapModelToCenter; /// is the model's offset automatically adjusted to center around 0,0,0 in model space
|
||||
bool _snappedToCenter; /// are we currently snapped to center
|
||||
bool _showTrueJointTransforms;
|
||||
int _rootIndex;
|
||||
|
||||
QVector<JointState> _jointStates;
|
||||
|
@ -176,6 +180,8 @@ protected:
|
|||
|
||||
/// Updates the state of the joint at the specified index.
|
||||
virtual void updateJointState(int index);
|
||||
|
||||
virtual void updateVisibleJointStates();
|
||||
|
||||
/// \param jointIndex index of joint in model structure
|
||||
/// \param position position of joint in model-frame
|
||||
|
@ -188,6 +194,8 @@ protected:
|
|||
bool setJointPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation = glm::quat(),
|
||||
bool useRotation = false, int lastFreeIndex = -1, bool allIntermediatesFree = false,
|
||||
const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f), float priority = 1.0f);
|
||||
|
||||
void inverseKinematics(int jointIndex, glm::vec3 position, const glm::quat& rotation, float priority);
|
||||
|
||||
/// Restores the indexed joint to its default position.
|
||||
/// \param fraction the fraction of the default position to apply (i.e., 0.25f to slerp one fourth of the way to
|
||||
|
|
|
@ -85,6 +85,33 @@ void TextureCache::setFrameBufferSize(QSize frameBufferSize) {
|
|||
}
|
||||
}
|
||||
|
||||
// use fixed table of permutations. Could also make ordered list programmatically
|
||||
// and then shuffle algorithm. For testing, this ensures consistent behavior in each run.
|
||||
// this list taken from Ken Perlin's Improved Noise reference implementation (orig. in Java) at
|
||||
// http://mrl.nyu.edu/~perlin/noise/
|
||||
|
||||
const int permutation[256] =
|
||||
{
|
||||
151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225,
|
||||
140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148,
|
||||
247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32,
|
||||
57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175,
|
||||
74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122,
|
||||
60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54,
|
||||
65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169,
|
||||
200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64,
|
||||
52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212,
|
||||
207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213,
|
||||
119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9,
|
||||
129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104,
|
||||
218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241,
|
||||
81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157,
|
||||
184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93,
|
||||
222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180
|
||||
};
|
||||
|
||||
#define USE_CHRIS_NOISE 1
|
||||
|
||||
GLuint TextureCache::getPermutationNormalTextureID() {
|
||||
if (_permutationNormalTextureID == 0) {
|
||||
glGenTextures(1, &_permutationNormalTextureID);
|
||||
|
@ -92,10 +119,17 @@ GLuint TextureCache::getPermutationNormalTextureID() {
|
|||
|
||||
// the first line consists of random permutation offsets
|
||||
unsigned char data[256 * 2 * 3];
|
||||
#if (USE_CHRIS_NOISE==1)
|
||||
for (int i = 0; i < 256; i++) {
|
||||
data[3*i+0] = permutation[i];
|
||||
data[3*i+1] = permutation[i];
|
||||
data[3*i+2] = permutation[i];
|
||||
#else
|
||||
for (int i = 0; i < 256 * 3; i++) {
|
||||
data[i] = rand() % 256;
|
||||
#endif
|
||||
}
|
||||
// the next, random unit normals
|
||||
|
||||
for (int i = 256 * 3; i < 256 * 3 * 2; i += 3) {
|
||||
glm::vec3 randvec = glm::sphericalRand(1.0f);
|
||||
data[i] = ((randvec.x + 1.0f) / 2.0f) * 255.0f;
|
||||
|
@ -105,7 +139,6 @@ GLuint TextureCache::getPermutationNormalTextureID() {
|
|||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
return _permutationNormalTextureID;
|
||||
|
|
|
@ -41,8 +41,7 @@ ApplicationOverlay::ApplicationOverlay() :
|
|||
_textureFov(DEFAULT_OCULUS_UI_ANGULAR_SIZE * RADIANS_PER_DEGREE),
|
||||
_alpha(1.0f),
|
||||
_active(true),
|
||||
_crosshairTexture(0)
|
||||
{
|
||||
_crosshairTexture(0) {
|
||||
|
||||
memset(_reticleActive, 0, sizeof(_reticleActive));
|
||||
memset(_magActive, 0, sizeof(_reticleActive));
|
||||
|
@ -206,7 +205,7 @@ void ApplicationOverlay::getClickLocation(int &x, int &y) const {
|
|||
}
|
||||
}
|
||||
|
||||
// Draws the FBO texture for Oculus rift. TODO: Draw a curved texture instead of plane.
|
||||
// Draws the FBO texture for Oculus rift.
|
||||
void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
|
||||
|
||||
if (_alpha == 0.0f) {
|
||||
|
@ -293,6 +292,107 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
|
|||
|
||||
}
|
||||
|
||||
// Draws the FBO texture for 3DTV.
|
||||
void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov) {
|
||||
|
||||
if (_alpha == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
Application* application = Application::getInstance();
|
||||
|
||||
MyAvatar* myAvatar = application->getAvatar();
|
||||
const glm::vec3& viewMatrixTranslation = application->getViewMatrixTranslation();
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||
glBindTexture(GL_TEXTURE_2D, getFramebufferObject()->texture());
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
// Transform to world space
|
||||
glm::quat rotation = whichCamera.getRotation();
|
||||
glm::vec3 axis2 = glm::axis(rotation);
|
||||
glRotatef(-glm::degrees(glm::angle(rotation)), axis2.x, axis2.y, axis2.z);
|
||||
glTranslatef(viewMatrixTranslation.x, viewMatrixTranslation.y, viewMatrixTranslation.z);
|
||||
|
||||
// Translate to the front of the camera
|
||||
glm::vec3 pos = whichCamera.getPosition();
|
||||
glm::quat rot = myAvatar->getOrientation();
|
||||
glm::vec3 axis = glm::axis(rot);
|
||||
|
||||
glTranslatef(pos.x, pos.y, pos.z);
|
||||
glRotatef(glm::degrees(glm::angle(rot)), axis.x, axis.y, axis.z);
|
||||
|
||||
glColor4f(1.0f, 1.0f, 1.0f, _alpha);
|
||||
|
||||
//Render
|
||||
// fov -= RADIANS_PER_DEGREE * 2.5f; //reduce by 5 degrees so it fits in the view
|
||||
const GLfloat distance = 1.0f;
|
||||
|
||||
const GLfloat halfQuadHeight = distance * tan(fov);
|
||||
const GLfloat halfQuadWidth = halfQuadHeight * aspectRatio;
|
||||
const GLfloat quadWidth = halfQuadWidth * 2.0f;
|
||||
const GLfloat quadHeight = halfQuadHeight * 2.0f;
|
||||
|
||||
GLfloat x = -halfQuadWidth;
|
||||
GLfloat y = -halfQuadHeight;
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
glTexCoord2f(0.0f, 1.0f); glVertex3f(x, y + quadHeight, -distance);
|
||||
glTexCoord2f(1.0f, 1.0f); glVertex3f(x + quadWidth, y + quadHeight, -distance);
|
||||
glTexCoord2f(1.0f, 0.0f); glVertex3f(x + quadWidth, y, -distance);
|
||||
glTexCoord2f(0.0f, 0.0f); glVertex3f(x, y, -distance);
|
||||
|
||||
glEnd();
|
||||
|
||||
if (_crosshairTexture == 0) {
|
||||
_crosshairTexture = Application::getInstance()->getGLWidget()->bindTexture(QImage(Application::resourcesPath() + "images/sixense-reticle.png"));
|
||||
}
|
||||
|
||||
//draw the mouse pointer
|
||||
glBindTexture(GL_TEXTURE_2D, _crosshairTexture);
|
||||
|
||||
const float reticleSize = 40.0f / application->getGLWidget()->width() * quadWidth;
|
||||
x -= reticleSize / 2.0f;
|
||||
y += reticleSize / 2.0f;
|
||||
const float mouseX = (application->getMouseX() / (float)application->getGLWidget()->width()) * quadWidth;
|
||||
const float mouseY = (1.0 - (application->getMouseY() / (float)application->getGLWidget()->height())) * quadHeight;
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
glColor3f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2]);
|
||||
|
||||
glTexCoord2d(0.0f, 0.0f); glVertex3f(x + mouseX, y + mouseY, -distance);
|
||||
glTexCoord2d(1.0f, 0.0f); glVertex3f(x + mouseX + reticleSize, y + mouseY, -distance);
|
||||
glTexCoord2d(1.0f, 1.0f); glVertex3f(x + mouseX + reticleSize, y + mouseY - reticleSize, -distance);
|
||||
glTexCoord2d(0.0f, 1.0f); glVertex3f(x + mouseX, y + mouseY - reticleSize, -distance);
|
||||
|
||||
glEnd();
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glDepthMask(GL_TRUE);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||
glEnable(GL_LIGHTING);
|
||||
|
||||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
//Renders optional pointers
|
||||
void ApplicationOverlay::renderPointers() {
|
||||
Application* application = Application::getInstance();
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
void renderOverlay(bool renderToTexture = false);
|
||||
void displayOverlayTexture();
|
||||
void displayOverlayTextureOculus(Camera& whichCamera);
|
||||
void displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov);
|
||||
void computeOculusPickRay(float x, float y, glm::vec3& direction) const;
|
||||
void getClickLocation(int &x, int &y) const;
|
||||
|
||||
|
|
|
@ -14,10 +14,11 @@
|
|||
#include <QGridLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QMessageBox>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QUrl>
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
#include <NetworkAccessManager.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
#include "ModelsBrowser.h"
|
||||
|
@ -210,10 +211,10 @@ void ModelHandler::update() {
|
|||
}
|
||||
for (int i = 0; i < _model.rowCount(); ++i) {
|
||||
QUrl url(_model.item(i,0)->data(Qt::UserRole).toString());
|
||||
QNetworkAccessManager* accessManager = new QNetworkAccessManager(this);
|
||||
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest request(url);
|
||||
accessManager->head(request);
|
||||
connect(accessManager, SIGNAL(finished(QNetworkReply*)), SLOT(downloadFinished(QNetworkReply*)));
|
||||
QNetworkReply* reply = networkAccessManager.head(request);
|
||||
connect(reply, SIGNAL(finished()), SLOT(processCheck()));
|
||||
}
|
||||
_lock.unlock();
|
||||
}
|
||||
|
@ -233,7 +234,8 @@ void ModelHandler::exit() {
|
|||
_lock.unlock();
|
||||
}
|
||||
|
||||
void ModelHandler::downloadFinished(QNetworkReply* reply) {
|
||||
void ModelHandler::downloadFinished() {
|
||||
QNetworkReply* reply = static_cast<QNetworkReply*>(sender());
|
||||
QByteArray data = reply->readAll();
|
||||
|
||||
if (!data.isEmpty()) {
|
||||
|
@ -261,10 +263,10 @@ void ModelHandler::queryNewFiles(QString marker) {
|
|||
|
||||
// Download
|
||||
url.setQuery(query);
|
||||
QNetworkAccessManager* accessManager = new QNetworkAccessManager(this);
|
||||
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest request(url);
|
||||
accessManager->get(request);
|
||||
connect(accessManager, SIGNAL(finished(QNetworkReply*)), SLOT(downloadFinished(QNetworkReply*)));
|
||||
QNetworkReply* reply = networkAccessManager.get(request);
|
||||
connect(reply, SIGNAL(finished()), SLOT(processCheck()));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ public slots:
|
|||
void exit();
|
||||
|
||||
private slots:
|
||||
void downloadFinished(QNetworkReply* reply);
|
||||
void downloadFinished();
|
||||
|
||||
private:
|
||||
bool _initiateExit;
|
||||
|
|
|
@ -148,8 +148,8 @@ void ScriptEditorWidget::loadFile(const QString& scriptPath) {
|
|||
disconnect(_scriptEngine, &ScriptEngine::finished, this, &ScriptEditorWidget::onScriptFinished);
|
||||
}
|
||||
} else {
|
||||
QNetworkAccessManager* networkManager = new QNetworkAccessManager(this);
|
||||
QNetworkReply* reply = networkManager->get(QNetworkRequest(url));
|
||||
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
|
||||
qDebug() << "Downloading included script at" << scriptPath;
|
||||
QEventLoop loop;
|
||||
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
|
|
|
@ -40,8 +40,7 @@ Q_DECLARE_METATYPE(QNetworkAccessManager::Operation)
|
|||
|
||||
SnapshotShareDialog::SnapshotShareDialog(QString fileName, QWidget* parent) :
|
||||
QDialog(parent),
|
||||
_fileName(fileName),
|
||||
_networkAccessManager(NULL)
|
||||
_fileName(fileName)
|
||||
{
|
||||
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
@ -92,10 +91,6 @@ void SnapshotShareDialog::uploadSnapshot() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!_networkAccessManager) {
|
||||
_networkAccessManager = new QNetworkAccessManager(this);
|
||||
}
|
||||
|
||||
QHttpMultiPart* multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||||
|
||||
QHttpPart apiKeyPart;
|
||||
|
@ -118,9 +113,7 @@ void SnapshotShareDialog::uploadSnapshot() {
|
|||
QUrl url(FORUM_UPLOADS_URL);
|
||||
QNetworkRequest request(url);
|
||||
|
||||
QNetworkReply* reply = _networkAccessManager->post(request, multiPart);
|
||||
|
||||
|
||||
QNetworkReply* reply = NetworkAccessManager::getInstance().post(request, multiPart);
|
||||
connect(reply, &QNetworkReply::finished, this, &SnapshotShareDialog::uploadRequestFinished);
|
||||
|
||||
QEventLoop loop;
|
||||
|
@ -129,11 +122,6 @@ void SnapshotShareDialog::uploadSnapshot() {
|
|||
}
|
||||
|
||||
void SnapshotShareDialog::sendForumPost(QString snapshotPath) {
|
||||
|
||||
if (!_networkAccessManager) {
|
||||
_networkAccessManager = new QNetworkAccessManager(this);
|
||||
}
|
||||
|
||||
// post to Discourse forum
|
||||
QNetworkRequest request;
|
||||
QUrl forumUrl(FORUM_POST_URL);
|
||||
|
@ -148,7 +136,7 @@ void SnapshotShareDialog::sendForumPost(QString snapshotPath) {
|
|||
request.setUrl(forumUrl);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
|
||||
QNetworkReply* requestReply = _networkAccessManager->post(request, postData);
|
||||
QNetworkReply* requestReply = NetworkAccessManager::getInstance().post(request, postData);
|
||||
connect(requestReply, &QNetworkReply::finished, this, &SnapshotShareDialog::postRequestFinished);
|
||||
|
||||
QEventLoop loop;
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
#include "ui_shareSnapshot.h"
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QUrl>
|
||||
|
||||
|
@ -26,7 +25,6 @@ public:
|
|||
|
||||
private:
|
||||
QString _fileName;
|
||||
QNetworkAccessManager* _networkAccessManager;
|
||||
Ui_SnapshotShareDialog _ui;
|
||||
|
||||
void uploadSnapshot();
|
||||
|
|
77
interface/src/ui/UserLocationsDialog.cpp
Normal file
77
interface/src/ui/UserLocationsDialog.cpp
Normal file
|
@ -0,0 +1,77 @@
|
|||
//
|
||||
// UserLocationsDialog.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Ryan Huffman on 06/24/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QDebug>
|
||||
#include <QInputDialog>
|
||||
#include <QPushButton>
|
||||
|
||||
#include "Menu.h"
|
||||
#include "UserLocationsDialog.h"
|
||||
|
||||
UserLocationsDialog::UserLocationsDialog(QWidget* parent) :
|
||||
QDialog(parent),
|
||||
_ui(),
|
||||
_proxyModel(this),
|
||||
_userLocationsModel(this) {
|
||||
|
||||
_ui.setupUi(this);
|
||||
|
||||
_proxyModel.setSourceModel(&_userLocationsModel);
|
||||
_proxyModel.setDynamicSortFilter(true);
|
||||
|
||||
_ui.locationsTreeView->setModel(&_proxyModel);
|
||||
_ui.locationsTreeView->setSortingEnabled(true);
|
||||
_ui.locationsTreeView->sortByColumn(UserLocationsModel::NameColumn, Qt::AscendingOrder);
|
||||
|
||||
connect(_ui.locationsTreeView->selectionModel(), &QItemSelectionModel::selectionChanged,
|
||||
this, &UserLocationsDialog::updateEnabled);
|
||||
connect(&_userLocationsModel, &UserLocationsModel::modelReset, this, &UserLocationsDialog::updateEnabled);
|
||||
connect(&_userLocationsModel, &UserLocationsModel::modelReset, &_proxyModel, &QSortFilterProxyModel::invalidate);
|
||||
connect(_ui.locationsTreeView, &QTreeView::doubleClicked, this, &UserLocationsDialog::goToModelIndex);
|
||||
|
||||
connect(_ui.deleteButton, &QPushButton::clicked, this, &UserLocationsDialog::deleteSelection);
|
||||
connect(_ui.renameButton, &QPushButton::clicked, this, &UserLocationsDialog::renameSelection);
|
||||
connect(_ui.refreshButton, &QPushButton::clicked, &_userLocationsModel, &UserLocationsModel::refresh);
|
||||
|
||||
this->setWindowTitle("My Locations");
|
||||
}
|
||||
|
||||
void UserLocationsDialog::updateEnabled() {
|
||||
bool enabled = _ui.locationsTreeView->selectionModel()->hasSelection();
|
||||
_ui.renameButton->setEnabled(enabled);
|
||||
_ui.deleteButton->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void UserLocationsDialog::goToModelIndex(const QModelIndex& index) {
|
||||
QVariant location = _proxyModel.data(index.sibling(index.row(), UserLocationsModel::LocationColumn));
|
||||
Menu::getInstance()->goToURL(location.toString());
|
||||
}
|
||||
|
||||
void UserLocationsDialog::deleteSelection() {
|
||||
QModelIndex selection = _ui.locationsTreeView->selectionModel()->currentIndex();
|
||||
selection = _proxyModel.mapToSource(selection);
|
||||
if (selection.isValid()) {
|
||||
_userLocationsModel.deleteLocation(selection);
|
||||
}
|
||||
}
|
||||
|
||||
void UserLocationsDialog::renameSelection() {
|
||||
QModelIndex selection = _ui.locationsTreeView->selectionModel()->currentIndex();
|
||||
selection = _proxyModel.mapToSource(selection);
|
||||
if (selection.isValid()) {
|
||||
bool ok;
|
||||
QString name = _userLocationsModel.data(selection.sibling(selection.row(), UserLocationsModel::NameColumn)).toString();
|
||||
QString newName = QInputDialog::getText(this, "Rename '" + name + "'", "Set name to:", QLineEdit::Normal, name, &ok);
|
||||
if (ok && !newName.isEmpty()) {
|
||||
_userLocationsModel.renameLocation(selection, newName);
|
||||
}
|
||||
}
|
||||
}
|
35
interface/src/ui/UserLocationsDialog.h
Normal file
35
interface/src/ui/UserLocationsDialog.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// UserLocationsDialog.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Ryan Huffman on 06/24/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_UserLocationsDialog_h
|
||||
#define hifi_UserLocationsDialog_h
|
||||
|
||||
#include "ui_userLocationsDialog.h"
|
||||
#include "UserLocationsModel.h"
|
||||
|
||||
class UserLocationsDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
UserLocationsDialog(QWidget* parent = NULL);
|
||||
|
||||
protected slots:
|
||||
void updateEnabled();
|
||||
void goToModelIndex(const QModelIndex& index);
|
||||
void deleteSelection();
|
||||
void renameSelection();
|
||||
|
||||
private:
|
||||
Ui::UserLocationsDialog _ui;
|
||||
QSortFilterProxyModel _proxyModel;
|
||||
UserLocationsModel _userLocationsModel;
|
||||
};
|
||||
|
||||
#endif // hifi_UserLocationsDialog_h
|
|
@ -14,8 +14,7 @@
|
|||
#include "BillboardOverlay.h"
|
||||
|
||||
BillboardOverlay::BillboardOverlay()
|
||||
: _manager(NULL),
|
||||
_scale(1.0f),
|
||||
: _scale(1.0f),
|
||||
_isFacingAvatar(true) {
|
||||
}
|
||||
|
||||
|
@ -119,18 +118,13 @@ void BillboardOverlay::setProperties(const QScriptValue &properties) {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: handle setting image multiple times, how do we manage releasing the bound texture?
|
||||
void BillboardOverlay::setBillboardURL(const QUrl url) {
|
||||
// TODO: are we creating too many QNetworkAccessManager() when multiple calls to setImageURL are made?
|
||||
_manager->deleteLater();
|
||||
_manager = new QNetworkAccessManager();
|
||||
connect(_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
|
||||
_manager->get(QNetworkRequest(url));
|
||||
QNetworkReply* reply = NetworkAccessManager::getInstance().get(QNetworkRequest(url));
|
||||
connect(reply, &QNetworkReply::finished, this, &BillboardOverlay::replyFinished);
|
||||
}
|
||||
|
||||
void BillboardOverlay::replyFinished(QNetworkReply* reply) {
|
||||
void BillboardOverlay::replyFinished() {
|
||||
// replace our byte array with the downloaded data
|
||||
QNetworkReply* reply = static_cast<QNetworkReply*>(sender());
|
||||
_billboard = reply->readAll();
|
||||
_manager->deleteLater();
|
||||
_manager = NULL;
|
||||
}
|
||||
|
|
|
@ -27,12 +27,11 @@ public:
|
|||
virtual void setProperties(const QScriptValue& properties);
|
||||
|
||||
private slots:
|
||||
void replyFinished(QNetworkReply* reply);
|
||||
void replyFinished();
|
||||
|
||||
private:
|
||||
void setBillboardURL(const QUrl url);
|
||||
|
||||
QNetworkAccessManager* _manager;
|
||||
QUrl _url;
|
||||
QByteArray _billboard;
|
||||
QSize _size;
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include "ImageOverlay.h"
|
||||
|
||||
ImageOverlay::ImageOverlay() :
|
||||
_manager(NULL),
|
||||
_textureID(0),
|
||||
_renderImage(false),
|
||||
_textureBound(false),
|
||||
|
@ -36,21 +35,18 @@ ImageOverlay::~ImageOverlay() {
|
|||
|
||||
// TODO: handle setting image multiple times, how do we manage releasing the bound texture?
|
||||
void ImageOverlay::setImageURL(const QUrl& url) {
|
||||
// TODO: are we creating too many QNetworkAccessManager() when multiple calls to setImageURL are made?
|
||||
_manager->deleteLater();
|
||||
_manager = new QNetworkAccessManager();
|
||||
connect(_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
|
||||
_manager->get(QNetworkRequest(url));
|
||||
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
|
||||
connect(reply, &QNetworkReply::finished, this, &ImageOverlay::replyFinished);
|
||||
}
|
||||
|
||||
void ImageOverlay::replyFinished(QNetworkReply* reply) {
|
||||
|
||||
void ImageOverlay::replyFinished() {
|
||||
QNetworkReply* reply = static_cast<QNetworkReply*>(sender());
|
||||
|
||||
// replace our byte array with the downloaded data
|
||||
QByteArray rawData = reply->readAll();
|
||||
_textureImage.loadFromData(rawData);
|
||||
_renderImage = true;
|
||||
_manager->deleteLater();
|
||||
_manager = NULL;
|
||||
}
|
||||
|
||||
void ImageOverlay::render() {
|
||||
|
|
|
@ -16,13 +16,13 @@
|
|||
|
||||
#include <QGLWidget>
|
||||
#include <QImage>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QRect>
|
||||
#include <QScriptValue>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Overlay.h"
|
||||
|
@ -46,13 +46,12 @@ public:
|
|||
virtual void setProperties(const QScriptValue& properties);
|
||||
|
||||
private slots:
|
||||
void replyFinished(QNetworkReply* reply); // we actually want to hide this...
|
||||
void replyFinished(); // we actually want to hide this...
|
||||
|
||||
private:
|
||||
|
||||
QUrl _imageURL;
|
||||
QImage _textureImage;
|
||||
QNetworkAccessManager* _manager;
|
||||
|
||||
GLuint _textureID;
|
||||
QRect _fromImage; // where from in the image to sample
|
||||
|
|
|
@ -84,13 +84,13 @@ void Overlays::render3D() {
|
|||
return;
|
||||
}
|
||||
bool myAvatarComputed = false;
|
||||
MyAvatar* avatar;
|
||||
MyAvatar* avatar = NULL;
|
||||
glm::quat myAvatarRotation;
|
||||
glm::vec3 myAvatarPosition;
|
||||
float angle;
|
||||
glm::vec3 axis;
|
||||
float myAvatarScale;
|
||||
|
||||
glm::vec3 myAvatarPosition(0.0f);
|
||||
float angle = 0.0f;
|
||||
glm::vec3 axis(0.0f, 1.0f, 0.0f);
|
||||
float myAvatarScale = 1.0f;
|
||||
|
||||
foreach(Overlay* thisOverlay, _overlays3D) {
|
||||
glPushMatrix();
|
||||
switch (thisOverlay->getAnchor()) {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
#include <QGLWidget>
|
||||
#include <QImage>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QRect>
|
||||
#include <QScriptValue>
|
||||
|
|
130
interface/ui/userLocationsDialog.ui
Normal file
130
interface/ui/userLocationsDialog.ui
Normal file
|
@ -0,0 +1,130 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>UserLocationsDialog</class>
|
||||
<widget class="QWidget" name="UserLocationsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>929</width>
|
||||
<height>633</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font-size: 16px</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>My Locations</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<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="QPushButton" name="refreshButton">
|
||||
<property name="text">
|
||||
<string>Refresh</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeView" name="locationsTreeView">
|
||||
<property name="indentation">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rootIsDecorated">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<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="QPushButton" name="renameButton">
|
||||
<property name="text">
|
||||
<string>Rename</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="deleteButton">
|
||||
<property name="text">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -12,6 +12,9 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cm
|
|||
|
||||
set(TARGET_NAME audio)
|
||||
|
||||
find_package(Qt5 COMPONENTS Script)
|
||||
include_directories(SYSTEM "${Qt5Script_INCLUDE_DIRS}")
|
||||
|
||||
# set up the external glm library
|
||||
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
||||
setup_hifi_library(${TARGET_NAME})
|
||||
|
@ -26,4 +29,4 @@ link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
|
|||
# add a definition for ssize_t so that windows doesn't bail
|
||||
if (WIN32)
|
||||
add_definitions(-Dssize_t=long)
|
||||
endif ()
|
||||
endif ()
|
||||
|
|
|
@ -53,7 +53,7 @@ void AudioRingBuffer::reset() {
|
|||
_isStarved = true;
|
||||
}
|
||||
|
||||
void AudioRingBuffer::resizeForFrameSize(qint64 numFrameSamples) {
|
||||
void AudioRingBuffer::resizeForFrameSize(int numFrameSamples) {
|
||||
delete[] _buffer;
|
||||
_sampleCapacity = numFrameSamples * RING_BUFFER_LENGTH_FRAMES;
|
||||
_buffer = new int16_t[_sampleCapacity];
|
||||
|
@ -70,14 +70,14 @@ int AudioRingBuffer::parseData(const QByteArray& packet) {
|
|||
return writeData(packet.data() + numBytesBeforeAudioData, packet.size() - numBytesBeforeAudioData);
|
||||
}
|
||||
|
||||
qint64 AudioRingBuffer::readSamples(int16_t* destination, qint64 maxSamples) {
|
||||
int AudioRingBuffer::readSamples(int16_t* destination, int maxSamples) {
|
||||
return readData((char*) destination, maxSamples * sizeof(int16_t));
|
||||
}
|
||||
|
||||
qint64 AudioRingBuffer::readData(char *data, qint64 maxSize) {
|
||||
int AudioRingBuffer::readData(char *data, int maxSize) {
|
||||
|
||||
// only copy up to the number of samples we have available
|
||||
int numReadSamples = std::min((unsigned) (maxSize / sizeof(int16_t)), samplesAvailable());
|
||||
int numReadSamples = std::min((int) (maxSize / sizeof(int16_t)), samplesAvailable());
|
||||
|
||||
// If we're in random access mode, then we consider our number of available read samples slightly
|
||||
// differently. Namely, if anything has been written, we say we have as many samples as they ask for
|
||||
|
@ -118,14 +118,14 @@ qint64 AudioRingBuffer::readData(char *data, qint64 maxSize) {
|
|||
return numReadSamples * sizeof(int16_t);
|
||||
}
|
||||
|
||||
qint64 AudioRingBuffer::writeSamples(const int16_t* source, qint64 maxSamples) {
|
||||
int AudioRingBuffer::writeSamples(const int16_t* source, int maxSamples) {
|
||||
return writeData((const char*) source, maxSamples * sizeof(int16_t));
|
||||
}
|
||||
|
||||
qint64 AudioRingBuffer::writeData(const char* data, qint64 maxSize) {
|
||||
int AudioRingBuffer::writeData(const char* data, int maxSize) {
|
||||
// make sure we have enough bytes left for this to be the right amount of audio
|
||||
// otherwise we should not copy that data, and leave the buffer pointers where they are
|
||||
int samplesToCopy = std::min((quint64)(maxSize / sizeof(int16_t)), (quint64)_sampleCapacity);
|
||||
int samplesToCopy = std::min((int)(maxSize / sizeof(int16_t)), _sampleCapacity);
|
||||
|
||||
int samplesRoomFor = _sampleCapacity - samplesAvailable();
|
||||
if (samplesToCopy > samplesRoomFor) {
|
||||
|
@ -167,7 +167,7 @@ void AudioRingBuffer::shiftReadPosition(unsigned int numSamples) {
|
|||
}
|
||||
}
|
||||
|
||||
unsigned int AudioRingBuffer::samplesAvailable() const {
|
||||
int AudioRingBuffer::samplesAvailable() const {
|
||||
if (!_endOfLastWrite) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -208,7 +208,7 @@ int AudioRingBuffer::addSilentFrame(int numSilentSamples) {
|
|||
return numSilentSamples * sizeof(int16_t);
|
||||
}
|
||||
|
||||
bool AudioRingBuffer::isNotStarvedOrHasMinimumSamples(unsigned int numRequiredSamples) const {
|
||||
bool AudioRingBuffer::isNotStarvedOrHasMinimumSamples(int numRequiredSamples) const {
|
||||
if (!_isStarved) {
|
||||
return true;
|
||||
} else {
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
~AudioRingBuffer();
|
||||
|
||||
void reset();
|
||||
void resizeForFrameSize(qint64 numFrameSamples);
|
||||
void resizeForFrameSize(int numFrameSamples);
|
||||
|
||||
int getSampleCapacity() const { return _sampleCapacity; }
|
||||
|
||||
|
@ -53,20 +53,20 @@ public:
|
|||
const int16_t* getNextOutput() const { return _nextOutput; }
|
||||
const int16_t* getBuffer() const { return _buffer; }
|
||||
|
||||
qint64 readSamples(int16_t* destination, qint64 maxSamples);
|
||||
qint64 writeSamples(const int16_t* source, qint64 maxSamples);
|
||||
int readSamples(int16_t* destination, int maxSamples);
|
||||
int writeSamples(const int16_t* source, int maxSamples);
|
||||
|
||||
qint64 readData(char* data, qint64 maxSize);
|
||||
qint64 writeData(const char* data, qint64 maxSize);
|
||||
int readData(char* data, int maxSize);
|
||||
int writeData(const char* data, int maxSize);
|
||||
|
||||
int16_t& operator[](const int index);
|
||||
const int16_t& operator[] (const int index) const;
|
||||
|
||||
void shiftReadPosition(unsigned int numSamples);
|
||||
|
||||
unsigned int samplesAvailable() const;
|
||||
int samplesAvailable() const;
|
||||
|
||||
bool isNotStarvedOrHasMinimumSamples(unsigned int numRequiredSamples) const;
|
||||
bool isNotStarvedOrHasMinimumSamples(int numRequiredSamples) const;
|
||||
|
||||
bool isStarved() const { return _isStarved; }
|
||||
void setIsStarved(bool isStarved) { _isStarved = isStarved; }
|
||||
|
|
|
@ -212,7 +212,7 @@ bool PositionalAudioRingBuffer::shouldBeAddedToMix() {
|
|||
}
|
||||
|
||||
return false;
|
||||
} else if (samplesAvailable() < (unsigned int)samplesPerFrame) {
|
||||
} else if (samplesAvailable() < samplesPerFrame) {
|
||||
// if the buffer doesn't have a full frame of samples to take for mixing, it is starved
|
||||
_isStarved = true;
|
||||
|
||||
|
|
|
@ -15,12 +15,12 @@
|
|||
|
||||
#include <QDataStream>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <qendian.h>
|
||||
|
||||
#include <LimitedNodeList.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "AudioRingBuffer.h"
|
||||
|
@ -73,11 +73,11 @@ Sound::Sound(const QUrl& sampleURL, QObject* parent) :
|
|||
// assume we have a QApplication or QCoreApplication instance and use the
|
||||
// QNetworkAccess manager to grab the raw audio file at the given URL
|
||||
|
||||
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
|
||||
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
|
||||
qDebug() << "Requesting audio file" << sampleURL.toDisplayString();
|
||||
|
||||
QNetworkReply* soundDownload = manager->get(QNetworkRequest(sampleURL));
|
||||
QNetworkReply* soundDownload = networkAccessManager.get(QNetworkRequest(sampleURL));
|
||||
connect(soundDownload, &QNetworkReply::finished, this, &Sound::replyFinished);
|
||||
connect(soundDownload, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(replyError(QNetworkReply::NetworkError)));
|
||||
}
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
#include <QtCore/QDataStream>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QUuid>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <SharedUtil.h>
|
||||
|
@ -33,8 +33,6 @@ quint64 DEFAULT_FILTERED_LOG_EXPIRY = 2 * USECS_PER_SECOND;
|
|||
|
||||
using namespace std;
|
||||
|
||||
QNetworkAccessManager* AvatarData::networkAccessManager = NULL;
|
||||
|
||||
AvatarData::AvatarData() :
|
||||
_sessionUUID(),
|
||||
_handPosition(0,0,0),
|
||||
|
@ -751,18 +749,15 @@ void AvatarData::setBillboard(const QByteArray& billboard) {
|
|||
void AvatarData::setBillboardFromURL(const QString &billboardURL) {
|
||||
_billboardURL = billboardURL;
|
||||
|
||||
if (AvatarData::networkAccessManager) {
|
||||
qDebug() << "Changing billboard for avatar to PNG at" << qPrintable(billboardURL);
|
||||
|
||||
QNetworkRequest billboardRequest;
|
||||
billboardRequest.setUrl(QUrl(billboardURL));
|
||||
|
||||
QNetworkReply* networkReply = AvatarData::networkAccessManager->get(billboardRequest);
|
||||
connect(networkReply, SIGNAL(finished()), this, SLOT(setBillboardFromNetworkReply()));
|
||||
|
||||
} else {
|
||||
qDebug() << "Billboard PNG download requested but no network access manager is available.";
|
||||
}
|
||||
|
||||
qDebug() << "Changing billboard for avatar to PNG at" << qPrintable(billboardURL);
|
||||
|
||||
QNetworkRequest billboardRequest;
|
||||
billboardRequest.setUrl(QUrl(billboardURL));
|
||||
|
||||
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkReply* networkReply = networkAccessManager.get(billboardRequest);
|
||||
connect(networkReply, SIGNAL(finished()), this, SLOT(setBillboardFromNetworkReply()));
|
||||
}
|
||||
|
||||
void AvatarData::setBillboardFromNetworkReply() {
|
||||
|
@ -839,8 +834,9 @@ void AvatarData::updateJointMappings() {
|
|||
_jointIndices.clear();
|
||||
_jointNames.clear();
|
||||
|
||||
if (networkAccessManager && _skeletonModelURL.fileName().toLower().endsWith(".fst")) {
|
||||
QNetworkReply* networkReply = networkAccessManager->get(QNetworkRequest(_skeletonModelURL));
|
||||
if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) {
|
||||
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkReply* networkReply = networkAccessManager.get(QNetworkRequest(_skeletonModelURL));
|
||||
connect(networkReply, SIGNAL(finished()), this, SLOT(setJointMappingsFromNetworkReply()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,7 +102,6 @@ enum KeyState {
|
|||
const glm::vec3 vec3Zero(0.0f);
|
||||
|
||||
class QDataStream;
|
||||
class QNetworkAccessManager;
|
||||
|
||||
class AttachmentData;
|
||||
class JointData;
|
||||
|
@ -269,8 +268,6 @@ public:
|
|||
QElapsedTimer& getLastUpdateTimer() { return _lastUpdateTimer; }
|
||||
|
||||
virtual float getBoundingRadius() const { return 1.f; }
|
||||
|
||||
static void setNetworkAccessManager(QNetworkAccessManager* sharedAccessManager) { networkAccessManager = sharedAccessManager; }
|
||||
|
||||
public slots:
|
||||
void sendIdentityPacket();
|
||||
|
@ -323,8 +320,6 @@ protected:
|
|||
|
||||
QHash<QString, int> _jointIndices; ///< 1-based, since zero is returned for missing keys
|
||||
QStringList _jointNames; ///< in order of depth-first traversal
|
||||
|
||||
static QNetworkAccessManager* networkAccessManager;
|
||||
|
||||
quint64 _errorLogExpiry; ///< time in future when to log an error
|
||||
|
||||
|
|
|
@ -37,19 +37,20 @@ Q_DECLARE_METATYPE(JSONCallbackParameters)
|
|||
|
||||
const QString ACCOUNTS_GROUP = "accounts";
|
||||
|
||||
JSONCallbackParameters::JSONCallbackParameters() :
|
||||
jsonCallbackReceiver(NULL),
|
||||
jsonCallbackMethod(),
|
||||
errorCallbackReceiver(NULL),
|
||||
errorCallbackMethod(),
|
||||
updateReciever(NULL),
|
||||
updateSlot()
|
||||
JSONCallbackParameters::JSONCallbackParameters(QObject* jsonCallbackReceiver, const QString& jsonCallbackMethod,
|
||||
QObject* errorCallbackReceiver, const QString& errorCallbackMethod,
|
||||
QObject* updateReceiver, const QString& updateSlot) :
|
||||
jsonCallbackReceiver(jsonCallbackReceiver),
|
||||
jsonCallbackMethod(jsonCallbackMethod),
|
||||
errorCallbackReceiver(errorCallbackReceiver),
|
||||
errorCallbackMethod(errorCallbackMethod),
|
||||
updateReciever(updateReceiver),
|
||||
updateSlot(updateSlot)
|
||||
{
|
||||
}
|
||||
|
||||
AccountManager::AccountManager() :
|
||||
_authURL(),
|
||||
_networkAccessManager(NULL),
|
||||
_pendingCallbackMap(),
|
||||
_accountInfo()
|
||||
{
|
||||
|
@ -153,9 +154,7 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager::
|
|||
const JSONCallbackParameters& callbackParams,
|
||||
const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) {
|
||||
|
||||
if (!_networkAccessManager) {
|
||||
_networkAccessManager = new QNetworkAccessManager(this);
|
||||
}
|
||||
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
|
||||
if (hasValidAccessToken()) {
|
||||
QNetworkRequest authenticatedRequest;
|
||||
|
@ -184,26 +183,29 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager::
|
|||
|
||||
switch (operation) {
|
||||
case QNetworkAccessManager::GetOperation:
|
||||
networkReply = _networkAccessManager->get(authenticatedRequest);
|
||||
networkReply = networkAccessManager.get(authenticatedRequest);
|
||||
break;
|
||||
case QNetworkAccessManager::PostOperation:
|
||||
case QNetworkAccessManager::PutOperation:
|
||||
if (dataMultiPart) {
|
||||
if (operation == QNetworkAccessManager::PostOperation) {
|
||||
networkReply = _networkAccessManager->post(authenticatedRequest, dataMultiPart);
|
||||
networkReply = networkAccessManager.post(authenticatedRequest, dataMultiPart);
|
||||
} else {
|
||||
networkReply = _networkAccessManager->put(authenticatedRequest, dataMultiPart);
|
||||
networkReply = networkAccessManager.put(authenticatedRequest, dataMultiPart);
|
||||
}
|
||||
dataMultiPart->setParent(networkReply);
|
||||
} else {
|
||||
authenticatedRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
if (operation == QNetworkAccessManager::PostOperation) {
|
||||
networkReply = _networkAccessManager->post(authenticatedRequest, dataByteArray);
|
||||
networkReply = networkAccessManager.post(authenticatedRequest, dataByteArray);
|
||||
} else {
|
||||
networkReply = _networkAccessManager->put(authenticatedRequest, dataByteArray);
|
||||
networkReply = networkAccessManager.put(authenticatedRequest, dataByteArray);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case QNetworkAccessManager::DeleteOperation:
|
||||
networkReply = networkAccessManager.sendCustomRequest(authenticatedRequest, "DELETE");
|
||||
break;
|
||||
default:
|
||||
// other methods not yet handled
|
||||
|
@ -304,9 +306,7 @@ bool AccountManager::checkAndSignalForAccessToken() {
|
|||
|
||||
void AccountManager::requestAccessToken(const QString& login, const QString& password) {
|
||||
|
||||
if (!_networkAccessManager) {
|
||||
_networkAccessManager = new QNetworkAccessManager(this);
|
||||
}
|
||||
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
|
||||
QNetworkRequest request;
|
||||
|
||||
|
@ -324,7 +324,7 @@ void AccountManager::requestAccessToken(const QString& login, const QString& pas
|
|||
request.setUrl(grantURL);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
|
||||
QNetworkReply* requestReply = _networkAccessManager->post(request, postData);
|
||||
QNetworkReply* requestReply = networkAccessManager.post(request, postData);
|
||||
connect(requestReply, &QNetworkReply::finished, this, &AccountManager::requestAccessTokenFinished);
|
||||
connect(requestReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestAccessTokenError(QNetworkReply::NetworkError)));
|
||||
}
|
||||
|
@ -376,15 +376,13 @@ void AccountManager::requestAccessTokenError(QNetworkReply::NetworkError error)
|
|||
}
|
||||
|
||||
void AccountManager::requestProfile() {
|
||||
if (!_networkAccessManager) {
|
||||
_networkAccessManager = new QNetworkAccessManager(this);
|
||||
}
|
||||
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
|
||||
QUrl profileURL = _authURL;
|
||||
profileURL.setPath("/api/v1/users/profile");
|
||||
profileURL.setQuery("access_token=" + _accountInfo.getAccessToken().token);
|
||||
|
||||
QNetworkReply* profileReply = _networkAccessManager->get(QNetworkRequest(profileURL));
|
||||
QNetworkReply* profileReply = networkAccessManager.get(QNetworkRequest(profileURL));
|
||||
connect(profileReply, &QNetworkReply::finished, this, &AccountManager::requestProfileFinished);
|
||||
connect(profileReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestProfileError(QNetworkReply::NetworkError)));
|
||||
}
|
||||
|
|
|
@ -15,14 +15,17 @@
|
|||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
||||
#include "NetworkAccessManager.h"
|
||||
|
||||
#include "DataServerAccountInfo.h"
|
||||
|
||||
class JSONCallbackParameters {
|
||||
public:
|
||||
JSONCallbackParameters();
|
||||
JSONCallbackParameters(QObject* jsonCallbackReceiver = NULL, const QString& jsonCallbackMethod = QString(),
|
||||
QObject* errorCallbackReceiver = NULL, const QString& errorCallbackMethod = QString(),
|
||||
QObject* updateReceiver = NULL, const QString& updateSlot = QString());
|
||||
|
||||
bool isEmpty() const { return !jsonCallbackReceiver && !errorCallbackReceiver; }
|
||||
|
||||
|
@ -58,8 +61,6 @@ public:
|
|||
|
||||
const DataServerAccountInfo& getAccountInfo() const { return _accountInfo; }
|
||||
|
||||
void destroy() { delete _networkAccessManager; }
|
||||
|
||||
public slots:
|
||||
void requestAccessTokenFinished();
|
||||
void requestProfileFinished();
|
||||
|
@ -93,7 +94,6 @@ private:
|
|||
QHttpMultiPart* dataMultiPart);
|
||||
|
||||
QUrl _authURL;
|
||||
QNetworkAccessManager* _networkAccessManager;
|
||||
QMap<QNetworkReply*, JSONCallbackParameters> _pendingCallbackMap;
|
||||
|
||||
DataServerAccountInfo _accountInfo;
|
||||
|
|
149
libraries/networking/src/NetworkAccessManager.cpp
Normal file
149
libraries/networking/src/NetworkAccessManager.cpp
Normal file
|
@ -0,0 +1,149 @@
|
|||
//
|
||||
// NetworkAccessManager.cpp
|
||||
//
|
||||
//
|
||||
// Created by Clement on 7/1/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QMetaObject>
|
||||
#include <QThread>
|
||||
|
||||
#include "NetworkAccessManager.h"
|
||||
|
||||
NetworkAccessManager& NetworkAccessManager::getInstance() {
|
||||
static NetworkAccessManager sharedInstance;
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
NetworkAccessManager::NetworkAccessManager() {
|
||||
}
|
||||
|
||||
QNetworkReply* NetworkAccessManager::get(const QNetworkRequest& request) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QNetworkReply* result;
|
||||
QMetaObject::invokeMethod(this,
|
||||
"get",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QNetworkReply*, result),
|
||||
Q_ARG(const QNetworkRequest, request));
|
||||
return result;
|
||||
}
|
||||
return QNetworkAccessManager::get(request);
|
||||
}
|
||||
|
||||
QNetworkReply* NetworkAccessManager::head(const QNetworkRequest& request) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QNetworkReply* result;
|
||||
QMetaObject::invokeMethod(this,
|
||||
"head",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QNetworkReply*, result),
|
||||
Q_ARG(const QNetworkRequest, request));
|
||||
return result;
|
||||
}
|
||||
return QNetworkAccessManager::head(request);
|
||||
}
|
||||
|
||||
QNetworkReply* NetworkAccessManager::post(const QNetworkRequest& request, QIODevice* data) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QNetworkReply* result;
|
||||
QMetaObject::invokeMethod(this,
|
||||
"post",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QNetworkReply*, result),
|
||||
Q_ARG(const QNetworkRequest, request),
|
||||
Q_ARG(QIODevice*, data));
|
||||
return result;
|
||||
}
|
||||
return QNetworkAccessManager::post(request, data);
|
||||
}
|
||||
|
||||
QNetworkReply* NetworkAccessManager::post(const QNetworkRequest& request, const QByteArray& data) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QNetworkReply* result;
|
||||
QMetaObject::invokeMethod(this,
|
||||
"post",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QNetworkReply*, result),
|
||||
Q_ARG(const QNetworkRequest, request),
|
||||
Q_ARG(const QByteArray, data));
|
||||
return result;
|
||||
}
|
||||
return QNetworkAccessManager::post(request, data);
|
||||
}
|
||||
|
||||
QNetworkReply* NetworkAccessManager::post(const QNetworkRequest& request, QHttpMultiPart* multiPart) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QNetworkReply* result;
|
||||
QMetaObject::invokeMethod(this,
|
||||
"post",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QNetworkReply*, result),
|
||||
Q_ARG(const QNetworkRequest, request),
|
||||
Q_ARG(QHttpMultiPart*, multiPart));
|
||||
return result;
|
||||
}
|
||||
return QNetworkAccessManager::post(request, multiPart);
|
||||
}
|
||||
|
||||
QNetworkReply* NetworkAccessManager::put(const QNetworkRequest& request, QIODevice* data) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QNetworkReply* result;
|
||||
QMetaObject::invokeMethod(this,
|
||||
"put",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QNetworkReply*, result),
|
||||
Q_ARG(const QNetworkRequest, request),
|
||||
Q_ARG(QIODevice*, data));
|
||||
return result;
|
||||
}
|
||||
return QNetworkAccessManager::put(request, data);
|
||||
}
|
||||
|
||||
QNetworkReply* NetworkAccessManager::put(const QNetworkRequest& request, QHttpMultiPart* multiPart) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QNetworkReply* result;
|
||||
QMetaObject::invokeMethod(this,
|
||||
"put",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QNetworkReply*, result),
|
||||
Q_ARG(const QNetworkRequest, request),
|
||||
Q_ARG(QHttpMultiPart*, multiPart));
|
||||
return result;
|
||||
}
|
||||
return QNetworkAccessManager::put(request, multiPart);
|
||||
}
|
||||
|
||||
QNetworkReply* NetworkAccessManager::put(const QNetworkRequest & request, const QByteArray & data) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QNetworkReply* result;
|
||||
QMetaObject::invokeMethod(this,
|
||||
"put",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QNetworkReply*, result),
|
||||
Q_ARG(const QNetworkRequest, request),
|
||||
Q_ARG(const QByteArray, data));
|
||||
return result;
|
||||
}
|
||||
return QNetworkAccessManager::put(request, data);
|
||||
}
|
||||
|
||||
|
||||
QNetworkReply* NetworkAccessManager::sendCustomRequest(const QNetworkRequest& request, const QByteArray& verb, QIODevice* data) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QNetworkReply* result;
|
||||
QMetaObject::invokeMethod(this,
|
||||
"sendCustomRequest",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QNetworkReply*, result),
|
||||
Q_ARG(const QNetworkRequest, request),
|
||||
Q_ARG(const QByteArray, verb),
|
||||
Q_ARG(QIODevice*, data));
|
||||
return result;
|
||||
}
|
||||
return QNetworkAccessManager::sendCustomRequest(request, verb, data);
|
||||
}
|
41
libraries/networking/src/NetworkAccessManager.h
Normal file
41
libraries/networking/src/NetworkAccessManager.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// NetworkAccessManager.h
|
||||
//
|
||||
//
|
||||
// Created by Clement on 7/1/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_NetworkAccessManager_h
|
||||
#define hifi_NetworkAccessManager_h
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkConfiguration>
|
||||
#include <QNetworkProxy>
|
||||
|
||||
/// Wrapper around QNetworkAccessManager wo that we only use one instance
|
||||
/// For any other method you should need, make sure to be on the right thread
|
||||
/// or call the method using QMetaObject::invokeMethod()
|
||||
class NetworkAccessManager : public QNetworkAccessManager {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static NetworkAccessManager& getInstance();
|
||||
|
||||
Q_INVOKABLE QNetworkReply* get(const QNetworkRequest& request);
|
||||
Q_INVOKABLE QNetworkReply* head(const QNetworkRequest& request);
|
||||
Q_INVOKABLE QNetworkReply* post(const QNetworkRequest& request, QIODevice* data);
|
||||
Q_INVOKABLE QNetworkReply* post(const QNetworkRequest& request, const QByteArray& data);
|
||||
Q_INVOKABLE QNetworkReply* post(const QNetworkRequest& request, QHttpMultiPart* multiPart);
|
||||
Q_INVOKABLE QNetworkReply* put(const QNetworkRequest& request, QIODevice* data);
|
||||
Q_INVOKABLE QNetworkReply* put(const QNetworkRequest& request, QHttpMultiPart* multiPart);
|
||||
Q_INVOKABLE QNetworkReply* put(const QNetworkRequest& request, const QByteArray& data);
|
||||
Q_INVOKABLE QNetworkReply* sendCustomRequest(const QNetworkRequest& request, const QByteArray& verb, QIODevice* data = 0);
|
||||
|
||||
private:
|
||||
NetworkAccessManager();
|
||||
};
|
||||
|
||||
#endif // hifi_NetworkAccessManager_h
|
|
@ -16,6 +16,8 @@
|
|||
#include <QTimer>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "NetworkAccessManager.h"
|
||||
|
||||
#include "ResourceCache.h"
|
||||
|
||||
ResourceCache::ResourceCache(QObject* parent) :
|
||||
|
@ -103,8 +105,6 @@ void ResourceCache::requestCompleted(Resource* resource) {
|
|||
}
|
||||
}
|
||||
|
||||
QNetworkAccessManager* ResourceCache::_networkAccessManager = NULL;
|
||||
|
||||
const int DEFAULT_REQUEST_LIMIT = 10;
|
||||
int ResourceCache::_requestLimit = DEFAULT_REQUEST_LIMIT;
|
||||
|
||||
|
@ -219,7 +219,7 @@ void Resource::init() {
|
|||
if (_url.isEmpty()) {
|
||||
_startedLoading = _loaded = true;
|
||||
|
||||
} else if (!(_url.isValid() && ResourceCache::getNetworkAccessManager())) {
|
||||
} else if (!(_url.isValid())) {
|
||||
_startedLoading = _failedToLoad = true;
|
||||
}
|
||||
}
|
||||
|
@ -272,7 +272,7 @@ void Resource::handleReplyTimeout() {
|
|||
}
|
||||
|
||||
void Resource::makeRequest() {
|
||||
_reply = ResourceCache::getNetworkAccessManager()->get(_request);
|
||||
_reply = NetworkAccessManager::getInstance().get(_request);
|
||||
|
||||
connect(_reply, SIGNAL(downloadProgress(qint64,qint64)), SLOT(handleDownloadProgress(qint64,qint64)));
|
||||
connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(handleReplyError()));
|
|
@ -22,7 +22,6 @@
|
|||
#include <QUrl>
|
||||
#include <QWeakPointer>
|
||||
|
||||
class QNetworkAccessManager;
|
||||
class QNetworkReply;
|
||||
class QTimer;
|
||||
|
||||
|
@ -33,10 +32,6 @@ class ResourceCache : public QObject {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
static void setNetworkAccessManager(QNetworkAccessManager* manager) { _networkAccessManager = manager; }
|
||||
static QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; }
|
||||
|
||||
static void setRequestLimit(int limit) { _requestLimit = limit; }
|
||||
static int getRequestLimit() { return _requestLimit; }
|
||||
|
||||
|
@ -76,7 +71,6 @@ private:
|
|||
QHash<QUrl, QWeakPointer<Resource> > _resources;
|
||||
int _lastLRUKey;
|
||||
|
||||
static QNetworkAccessManager* _networkAccessManager;
|
||||
static int _requestLimit;
|
||||
static QList<QPointer<Resource> > _pendingRequests;
|
||||
static QList<Resource*> _loadingRequests;
|
|
@ -83,17 +83,10 @@ void UserActivityLogger::close(int delayTime) {
|
|||
|
||||
// In order to get the end of the session, we need to give the account manager enough time to send the packet.
|
||||
QEventLoop loop;
|
||||
// Here we connect the callbacks to stop the event loop
|
||||
JSONCallbackParameters params;
|
||||
params.jsonCallbackReceiver = &loop;
|
||||
params.errorCallbackReceiver = &loop;
|
||||
params.jsonCallbackMethod = "quit";
|
||||
params.errorCallbackMethod = "quit";
|
||||
// In case something goes wrong, we also setup a timer so that the delai is not greater than delayTime
|
||||
QTimer timer;
|
||||
connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
|
||||
// Now we can log it
|
||||
logAction(ACTION_NAME, QJsonObject(), params);
|
||||
logAction(ACTION_NAME, QJsonObject());
|
||||
timer.start(delayTime);
|
||||
loop.exec();
|
||||
}
|
||||
|
|
|
@ -183,7 +183,6 @@ void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particleA)
|
|||
|
||||
// MIN_VALID_SPEED is obtained by computing speed gained at one gravity after the shortest expected frame
|
||||
const float MIN_EXPECTED_FRAME_PERIOD = 0.0167f; // 1/60th of a second
|
||||
const float HALTING_SPEED = 9.8 * MIN_EXPECTED_FRAME_PERIOD / (float)(TREE_SCALE);
|
||||
|
||||
void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
|
||||
// particles that are in hand, don't collide with avatars
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <QtCore/QEventLoop>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QScriptEngine>
|
||||
|
@ -23,6 +22,7 @@
|
|||
#include <AvatarData.h>
|
||||
#include <CollisionInfo.h>
|
||||
#include <ModelsScriptingInterface.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <ParticlesScriptingInterface.h>
|
||||
|
@ -142,8 +142,8 @@ ScriptEngine::ScriptEngine(const QUrl& scriptURL,
|
|||
emit errorMessage("ERROR Loading file:" + fileName);
|
||||
}
|
||||
} else {
|
||||
QNetworkAccessManager* networkManager = new QNetworkAccessManager(this);
|
||||
QNetworkReply* reply = networkManager->get(QNetworkRequest(url));
|
||||
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
|
||||
qDebug() << "Downloading included script at" << url;
|
||||
QEventLoop loop;
|
||||
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||
|
@ -648,8 +648,8 @@ void ScriptEngine::include(const QString& includeFile) {
|
|||
QString includeContents;
|
||||
|
||||
if (url.scheme() == "http" || url.scheme() == "ftp") {
|
||||
QNetworkAccessManager* networkManager = new QNetworkAccessManager(this);
|
||||
QNetworkReply* reply = networkManager->get(QNetworkRequest(url));
|
||||
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
|
||||
qDebug() << "Downloading included script at" << includeFile;
|
||||
QEventLoop loop;
|
||||
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include <QEventLoop>
|
||||
|
||||
#include <NetworkAccessManager.h>
|
||||
|
||||
#include "XMLHttpRequestClass.h"
|
||||
|
||||
XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) :
|
||||
|
@ -22,7 +24,6 @@ XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) :
|
|||
_url(),
|
||||
_method(""),
|
||||
_responseType(""),
|
||||
_manager(this),
|
||||
_request(),
|
||||
_reply(NULL),
|
||||
_sendData(NULL),
|
||||
|
@ -161,7 +162,7 @@ void XMLHttpRequestClass::send(const QString& data) {
|
|||
}
|
||||
|
||||
void XMLHttpRequestClass::doSend() {
|
||||
_reply = _manager.sendCustomRequest(_request, _method.toLatin1(), _sendData);
|
||||
_reply = NetworkAccessManager::getInstance().sendCustomRequest(_request, _method.toLatin1(), _sendData);
|
||||
|
||||
connectToReply(_reply);
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#define hifi_XMLHttpRequestClass_h
|
||||
|
||||
#include <QBuffer>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QObject>
|
||||
|
@ -104,7 +103,6 @@ private:
|
|||
QUrl _url;
|
||||
QString _method;
|
||||
QString _responseType;
|
||||
QNetworkAccessManager _manager;
|
||||
QNetworkRequest _request;
|
||||
QNetworkReply* _reply;
|
||||
QBuffer* _sendData;
|
||||
|
|
|
@ -10,7 +10,7 @@ set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
|
|||
set(TARGET_NAME shared)
|
||||
project(${TARGET_NAME})
|
||||
|
||||
find_package(Qt5 COMPONENTS Network Widgets Xml)
|
||||
find_package(Qt5 COMPONENTS Network Widgets Xml Script)
|
||||
|
||||
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
||||
setup_hifi_library(${TARGET_NAME})
|
||||
|
@ -32,4 +32,8 @@ if (UNIX AND NOT APPLE)
|
|||
target_link_libraries(${TARGET_NAME} "${CMAKE_THREAD_LIBS_INIT}")
|
||||
endif (UNIX AND NOT APPLE)
|
||||
|
||||
target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets)
|
||||
# There is something special (bug) about Qt5Scripts, that we have to explicitly add its include
|
||||
# directory when Qt5 (5.2.1) is compiled from source and is not in a standard place.
|
||||
include_directories(SYSTEM "${Qt5Script_INCLUDE_DIRS}")
|
||||
|
||||
target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets)
|
||||
|
|
|
@ -24,9 +24,6 @@ int MAX_ENTITIES_PER_SIMULATION = 64;
|
|||
int MAX_COLLISIONS_PER_SIMULATION = 256;
|
||||
|
||||
|
||||
const int NUM_SHAPE_BITS = 6;
|
||||
const int SHAPE_INDEX_MASK = (1 << (NUM_SHAPE_BITS + 1)) - 1;
|
||||
|
||||
PhysicsSimulation::PhysicsSimulation() : _collisionList(MAX_COLLISIONS_PER_SIMULATION),
|
||||
_numIterations(0), _numCollisions(0), _constraintError(0.0f), _stepTime(0) {
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ void SequenceNumberStatsTests::runAllTests() {
|
|||
pruneTest();
|
||||
}
|
||||
|
||||
const int UINT16_RANGE = std::numeric_limits<quint16>::max() + 1;
|
||||
const quint32 UINT16_RANGE = std::numeric_limits<quint16>::max() + 1;
|
||||
|
||||
|
||||
void SequenceNumberStatsTests::rolloverTest() {
|
||||
|
@ -34,7 +34,7 @@ void SequenceNumberStatsTests::rolloverTest() {
|
|||
quint16 seq = 79; // start on some random number
|
||||
|
||||
for (int R = 0; R < 2; R++) {
|
||||
for (int i = 0; i < 3 * UINT16_RANGE; i++) {
|
||||
for (quint32 i = 0; i < 3 * UINT16_RANGE; i++) {
|
||||
stats.sequenceNumberReceived(seq);
|
||||
seq = seq + (quint16)1;
|
||||
|
||||
|
@ -53,12 +53,12 @@ void SequenceNumberStatsTests::earlyLateTest() {
|
|||
|
||||
SequenceNumberStats stats;
|
||||
quint16 seq = 65530;
|
||||
int numSent = 0;
|
||||
quint32 numSent = 0;
|
||||
|
||||
int numEarly = 0;
|
||||
int numLate = 0;
|
||||
int numLost = 0;
|
||||
int numRecovered = 0;
|
||||
quint32 numEarly = 0;
|
||||
quint32 numLate = 0;
|
||||
quint32 numLost = 0;
|
||||
quint32 numRecovered = 0;
|
||||
|
||||
for (int R = 0; R < 2; R++) {
|
||||
for (int T = 0; T < 10000; T++) {
|
||||
|
@ -122,12 +122,12 @@ void SequenceNumberStatsTests::duplicateTest() {
|
|||
|
||||
SequenceNumberStats stats;
|
||||
quint16 seq = 12345;
|
||||
int numSent = 0;
|
||||
quint32 numSent = 0;
|
||||
|
||||
int numDuplicate = 0;
|
||||
int numEarly = 0;
|
||||
int numLate = 0;
|
||||
int numLost = 0;
|
||||
quint32 numDuplicate = 0;
|
||||
quint32 numEarly = 0;
|
||||
quint32 numLate = 0;
|
||||
quint32 numLost = 0;
|
||||
|
||||
for (int R = 0; R < 2; R++) {
|
||||
for (int T = 0; T < 10000; T++) {
|
||||
|
@ -210,10 +210,10 @@ void SequenceNumberStatsTests::pruneTest() {
|
|||
|
||||
SequenceNumberStats stats;
|
||||
quint16 seq = 54321;
|
||||
int numSent = 0;
|
||||
quint32 numSent = 0;
|
||||
|
||||
int numEarly = 0;
|
||||
int numLost = 0;
|
||||
quint32 numEarly = 0;
|
||||
quint32 numLost = 0;
|
||||
|
||||
for (int R = 0; R < 2; R++) {
|
||||
for (int T = 0; T < 1000; T++) {
|
||||
|
|
Loading…
Reference in a new issue