This commit is contained in:
Philip Rosedale 2014-09-23 12:50:52 -07:00
commit 729d3cf9bc
28 changed files with 233 additions and 416 deletions

View file

@ -293,9 +293,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
// set the account manager's root URL and trigger a login request if we don't have the access token
accountManager.setAuthURL(DEFAULT_NODE_AUTH_URL);
UserActivityLogger::getInstance().launch(applicationVersion());
// grab the location manager instance early so it lives in our thread
LocationManager::getInstance();
// once the event loop has started, check and signal for an access token
QMetaObject::invokeMethod(&accountManager, "checkAndSignalForAccessToken", Qt::QueuedConnection);
@ -1450,6 +1447,14 @@ void Application::checkBandwidthMeterClick() {
}
void Application::setFullscreen(bool fullscreen) {
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {
if (fullscreen) {
// Menu show() after hide() doesn't work with Rift VR display so set height instead.
_window->menuBar()->setMaximumHeight(0);
} else {
_window->menuBar()->setMaximumHeight(QWIDGETSIZE_MAX);
}
}
_window->setWindowState(fullscreen ? (_window->windowState() | Qt::WindowFullScreen) :
(_window->windowState() & ~Qt::WindowFullScreen));
}
@ -2730,7 +2735,8 @@ void Application::setupWorldLight() {
QImage Application::renderAvatarBillboard() {
_textureCache.getPrimaryFramebufferObject()->bind();
glDisable(GL_BLEND);
// the "glow" here causes an alpha of one
Glower glower;
const int BILLBOARD_SIZE = 64;
renderRearViewMirror(QRect(0, _glWidget->getDeviceHeight() - BILLBOARD_SIZE, BILLBOARD_SIZE, BILLBOARD_SIZE), true);
@ -2738,8 +2744,6 @@ QImage Application::renderAvatarBillboard() {
QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32);
glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
glEnable(GL_BLEND);
_textureCache.getPrimaryFramebufferObject()->release();
return image;
@ -4164,7 +4168,7 @@ void Application::takeSnapshot() {
player->setMedia(QUrl::fromLocalFile(inf.absoluteFilePath()));
player->play();
QString fileName = Snapshot::saveSnapshot(_glWidget, _myAvatar);
QString fileName = Snapshot::saveSnapshot();
AccountManager& accountManager = AccountManager::getInstance();
if (!accountManager.isLoggedIn()) {

View file

@ -38,6 +38,7 @@
#include "Application.h"
#include "AccountManager.h"
#include "Menu.h"
#include "scripting/LocationScriptingInterface.h"
#include "scripting/MenuScriptingInterface.h"
#include "Util.h"
#include "ui/AnimationsDialog.h"
@ -95,6 +96,7 @@ Menu::Menu() :
_jsConsole(NULL),
_octreeStatsDialog(NULL),
_lodToolsDialog(NULL),
_newLocationDialog(NULL),
_userLocationsDialog(NULL),
#ifdef Q_OS_MAC
_speechRecognizer(),
@ -1216,7 +1218,9 @@ void Menu::displayNameLocationResponse(const QString& errorString) {
void Menu::toggleLocationList() {
if (!_userLocationsDialog) {
_userLocationsDialog = DataWebDialog::dialogForPath("/locations");
JavascriptObjectMap locationObjectMap;
locationObjectMap.insert("InterfaceLocation", LocationScriptingInterface::getInstance());
_userLocationsDialog = DataWebDialog::dialogForPath("/locations", locationObjectMap);
}
if (!_userLocationsDialog->isVisible()) {
@ -1256,31 +1260,20 @@ void Menu::nameLocation() {
return;
}
QInputDialog nameDialog(Application::getInstance()->getWindow());
nameDialog.setWindowTitle("Name this location");
nameDialog.setLabelText("Name this location, then share that name with others.\n"
"When they come here, they'll have the same viewpoint\n"
"(wherever you are standing and looking now) as you.\n\n"
"Location name:");
nameDialog.resize((int) (nameDialog.parentWidget()->size().width() * 0.30), nameDialog.size().height());
if (nameDialog.exec() == QDialog::Accepted) {
QString locationName = nameDialog.textValue().trimmed();
if (locationName.isEmpty()) {
return;
}
MyAvatar* myAvatar = Application::getInstance()->getAvatar();
LocationManager* manager = new LocationManager();
connect(manager, &LocationManager::creationCompleted, this, &Menu::displayNameLocationResponse);
NamedLocation* location = new NamedLocation(locationName,
myAvatar->getPosition(), myAvatar->getOrientation(),
domainHandler.getUUID());
manager->createNamedLocation(location);
if (!_newLocationDialog) {
JavascriptObjectMap locationObjectMap;
locationObjectMap.insert("InterfaceLocation", LocationScriptingInterface::getInstance());
_newLocationDialog = DataWebDialog::dialogForPath("/locations/new", locationObjectMap);
}
if (!_newLocationDialog->isVisible()) {
_newLocationDialog->show();
}
_newLocationDialog->raise();
_newLocationDialog->activateWindow();
_newLocationDialog->showNormal();
}
void Menu::pasteToVoxel() {

View file

@ -27,7 +27,6 @@
#include "SpeechRecognizer.h"
#endif
#include "location/LocationManager.h"
#include "ui/ChatWindow.h"
#include "ui/DataWebDialog.h"
#include "ui/JSConsole.h"
@ -273,6 +272,7 @@ private:
QDialog* _jsConsole;
OctreeStatsDialog* _octreeStatsDialog;
LodToolsDialog* _lodToolsDialog;
QPointer<DataWebDialog> _newLocationDialog;
QPointer<DataWebDialog> _userLocationsDialog;
#ifdef Q_OS_MAC
SpeechRecognizer _speechRecognizer;

View file

@ -16,6 +16,7 @@
#include <QOpenGLFramebufferObject>
#include <QReadLocker>
#include <QWriteLocker>
#include <QThreadPool>
#include <QtDebug>
#include <glm/gtx/transform.hpp>
@ -636,9 +637,9 @@ HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale,
_heightTextureID(0),
_colorTextureID(0),
_materialTextureID(0),
_heightSize(glm::sqrt(height.size())),
_heightSize(glm::sqrt(float(height.size()))),
_heightIncrement(scale / (_heightSize - HEIGHT_EXTENSION)),
_colorSize(glm::sqrt(color.size() / DataBlock::COLOR_BYTES)),
_colorSize(glm::sqrt(float(color.size() / DataBlock::COLOR_BYTES))),
_colorIncrement(scale / (_colorSize - SHARED_EDGE)) {
_heightBounds.minimum.x -= _heightIncrement * HEIGHT_BORDER;
@ -663,7 +664,7 @@ HeightfieldBuffer::~HeightfieldBuffer() {
}
QByteArray HeightfieldBuffer::getUnextendedHeight() const {
int srcSize = glm::sqrt(_height.size());
int srcSize = glm::sqrt(float(_height.size()));
int destSize = srcSize - 3;
QByteArray unextended(destSize * destSize, 0);
const char* src = _height.constData() + srcSize + 1;
@ -675,7 +676,7 @@ QByteArray HeightfieldBuffer::getUnextendedHeight() const {
}
QByteArray HeightfieldBuffer::getUnextendedColor() const {
int srcSize = glm::sqrt(_color.size() / DataBlock::COLOR_BYTES);
int srcSize = glm::sqrt(float(_color.size() / DataBlock::COLOR_BYTES));
int destSize = srcSize - 1;
QByteArray unextended(destSize * destSize * DataBlock::COLOR_BYTES, 0);
const char* src = _color.constData();
@ -720,7 +721,7 @@ void HeightfieldBuffer::render(bool cursor) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, WHITE_COLOR);
} else {
int colorSize = glm::sqrt(_color.size() / DataBlock::COLOR_BYTES);
int colorSize = glm::sqrt(float(_color.size() / DataBlock::COLOR_BYTES));
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, colorSize, colorSize, 0, GL_RGB, GL_UNSIGNED_BYTE, _color.constData());
}
@ -731,7 +732,7 @@ void HeightfieldBuffer::render(bool cursor) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
int materialSize = glm::sqrt(_material.size());
int materialSize = glm::sqrt(float(_material.size()));
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, materialSize, materialSize, 0,
GL_LUMINANCE, GL_UNSIGNED_BYTE, _material.constData());
@ -1270,7 +1271,7 @@ int HeightfieldFetchVisitor::visit(MetavoxelInfo& info) {
char* dest = _buffer->getHeight().data() + destY * heightSize + destX;
const QByteArray& srcHeight = height->getContents();
int srcSize = glm::sqrt(srcHeight.size());
int srcSize = glm::sqrt(float(srcHeight.size()));
float srcIncrement = info.size / srcSize;
if (info.size == _buffer->getScale() && srcSize == (heightSize - HeightfieldBuffer::HEIGHT_EXTENSION)) {
@ -1323,7 +1324,7 @@ int HeightfieldFetchVisitor::visit(MetavoxelInfo& info) {
int destBytes = destWidth * DataBlock::COLOR_BYTES;
const QByteArray& srcColor = color->getContents();
srcSize = glm::sqrt(srcColor.size() / DataBlock::COLOR_BYTES);
srcSize = glm::sqrt(float(srcColor.size() / DataBlock::COLOR_BYTES));
int srcStride = srcSize * DataBlock::COLOR_BYTES;
srcIncrement = info.size / srcSize;
@ -1393,7 +1394,7 @@ int HeightfieldRegionVisitor::visit(MetavoxelInfo& info) {
HeightfieldHeightDataPointer height = info.inputValues.at(0).getInlineValue<HeightfieldHeightDataPointer>();
if (height) {
const QByteArray& heightContents = height->getContents();
int size = glm::sqrt(heightContents.size());
int size = glm::sqrt(float(heightContents.size()));
int extendedSize = size + HeightfieldBuffer::HEIGHT_EXTENSION;
int heightContentsSize = extendedSize * extendedSize;
@ -1401,7 +1402,7 @@ int HeightfieldRegionVisitor::visit(MetavoxelInfo& info) {
int colorContentsSize = 0;
if (color) {
const QByteArray& colorContents = color->getContents();
int colorSize = glm::sqrt(colorContents.size() / DataBlock::COLOR_BYTES);
int colorSize = glm::sqrt(float(colorContents.size() / DataBlock::COLOR_BYTES));
int extendedColorSize = colorSize + HeightfieldBuffer::SHARED_EDGE;
colorContentsSize = extendedColorSize * extendedColorSize * DataBlock::COLOR_BYTES;
}
@ -2319,9 +2320,16 @@ void StaticModelRenderer::renderUnclipped(float alpha, Mode mode) {
_model->render(alpha);
}
bool StaticModelRenderer::findRayIntersection(RayIntersectionInfo& intersection,
const glm::vec3& clipMinimum, float clipSize) const {
return _model->findRayIntersection(intersection);
bool StaticModelRenderer::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const {
RayIntersectionInfo info;
info._rayStart = origin;
info._rayDirection = direction;
if (!_model->findRayIntersection(info)) {
return false;
}
distance = info._hitDistance;
return true;
}
void StaticModelRenderer::applyTranslation(const glm::vec3& translation) {

View file

@ -370,8 +370,8 @@ public:
virtual void init(Spanner* spanner);
virtual void simulate(float deltaTime);
virtual bool findRayIntersection(RayIntersectionInfo& intersection,
const glm::vec3& clipMinimum, float clipSize) const;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const;
protected:

View file

@ -87,11 +87,13 @@ int ScriptsModel::rowCount(const QModelIndex& parent) const {
void ScriptsModel::updateScriptsLocation(const QString& newPath) {
_fsWatcher.removePath(_localDirectory.absolutePath());
_localDirectory.setPath(newPath);
if (!_localDirectory.absolutePath().isEmpty()) {
_fsWatcher.addPath(_localDirectory.absolutePath());
}
if (!newPath.isEmpty()) {
_localDirectory.setPath(newPath);
if (!_localDirectory.absolutePath().isEmpty()) {
_fsWatcher.addPath(_localDirectory.absolutePath());
}
}
reloadLocalFiles();
}

View file

@ -351,23 +351,23 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool
: GLOW_FROM_AVERAGE_LOUDNESS;
// render body
if (!postLighting && Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) {
renderBody(renderMode, glowLevel);
if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) {
renderBody(renderMode, postLighting, glowLevel);
}
if (renderMode != SHADOW_RENDER_MODE) {
// add local lights
const float BASE_LIGHT_DISTANCE = 2.0f;
const float LIGHT_EXPONENT = 1.0f;
const float LIGHT_CUTOFF = glm::radians(80.0f);
float distance = BASE_LIGHT_DISTANCE * _scale;
glm::vec3 position = glm::mix(_skeletonModel.getTranslation(), getHead()->getFaceModel().getTranslation(), 0.9f);
glm::quat orientation = getOrientation();
foreach (const AvatarManager::LocalLight& light, Application::getInstance()->getAvatarManager().getLocalLights()) {
glm::vec3 direction = orientation * light.direction;
Application::getInstance()->getDeferredLightingEffect()->addSpotLight(position - direction * distance,
distance * 2.0f, glm::vec3(), light.color, light.color, 1.0f, 0.5f, 0.0f, direction,
LIGHT_EXPONENT, LIGHT_CUTOFF);
}
if (!postLighting && renderMode != SHADOW_RENDER_MODE) {
// add local lights
const float BASE_LIGHT_DISTANCE = 2.0f;
const float LIGHT_EXPONENT = 1.0f;
const float LIGHT_CUTOFF = glm::radians(80.0f);
float distance = BASE_LIGHT_DISTANCE * _scale;
glm::vec3 position = glm::mix(_skeletonModel.getTranslation(), getHead()->getFaceModel().getTranslation(), 0.9f);
glm::quat orientation = getOrientation();
foreach (const AvatarManager::LocalLight& light, Application::getInstance()->getAvatarManager().getLocalLights()) {
glm::vec3 direction = orientation * light.direction;
Application::getInstance()->getDeferredLightingEffect()->addSpotLight(position - direction * distance,
distance * 2.0f, glm::vec3(), light.color, light.color, 1.0f, 0.5f, 0.0f, direction,
LIGHT_EXPONENT, LIGHT_CUTOFF);
}
}
@ -499,34 +499,40 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
return glm::angleAxis(angle * proportion, axis);
}
void Avatar::renderBody(RenderMode renderMode, float glowLevel) {
void Avatar::renderBody(RenderMode renderMode, bool postLighting, float glowLevel) {
Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ?
Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
{
Glower glower(glowLevel);
if (_shouldRenderBillboard || !(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
if ((_shouldRenderBillboard || !(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) &&
(postLighting || renderMode == SHADOW_RENDER_MODE)) {
// render the billboard until both models are loaded
renderBillboard();
return;
}
_skeletonModel.render(1.0f, modelRenderMode);
renderAttachments(renderMode);
getHand()->render(false, modelRenderMode);
if (postLighting) {
getHand()->render(false, modelRenderMode);
} else {
_skeletonModel.render(1.0f, modelRenderMode);
renderAttachments(renderMode);
}
}
getHead()->render(1.0f, modelRenderMode);
if (!postLighting) {
getHead()->render(1.0f, modelRenderMode);
if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) {
// Render Hair
glPushMatrix();
glm::vec3 headPosition = getHead()->getPosition();
glTranslatef(headPosition.x, headPosition.y, headPosition.z);
const glm::quat& rotation = getHead()->getFinalOrientationInWorldFrame();
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
_hair.render();
glPopMatrix();
if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) {
// Render Hair
glPushMatrix();
glm::vec3 headPosition = getHead()->getPosition();
glTranslatef(headPosition.x, headPosition.y, headPosition.z);
const glm::quat& rotation = getHead()->getFinalOrientationInWorldFrame();
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
_hair.render();
glPopMatrix();
}
}
}

View file

@ -228,7 +228,7 @@ protected:
glm::vec3 getDisplayNamePosition();
void renderDisplayName();
virtual void renderBody(RenderMode renderMode, float glowLevel = 0.0f);
virtual void renderBody(RenderMode renderMode, bool postLighting, float glowLevel = 0.0f);
virtual bool shouldRenderHead(const glm::vec3& cameraPosition, RenderMode renderMode) const;
void simulateAttachments(float deltaTime);

View file

@ -90,8 +90,6 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
} else {
_longTermAverageLoudness = glm::mix(_longTermAverageLoudness, _averageLoudness, glm::min(deltaTime / AUDIO_LONG_TERM_AVERAGING_SECS, 1.0f));
}
float deltaLoudness = glm::max(0.0f, _averageLoudness - _longTermAverageLoudness);
//qDebug() << "deltaLoudness: " << deltaLoudness;
if (!(_isFaceshiftConnected || billboard)) {
// Update eye saccades

View file

@ -1107,7 +1107,7 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName, const g
Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved);
}
void MyAvatar::renderBody(RenderMode renderMode, float glowLevel) {
void MyAvatar::renderBody(RenderMode renderMode, bool postLighting, float glowLevel) {
if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
return; // wait until both models are loaded
}
@ -1115,28 +1115,34 @@ void MyAvatar::renderBody(RenderMode renderMode, float glowLevel) {
// Render the body's voxels and head
Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ?
Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
_skeletonModel.render(1.0f, modelRenderMode);
renderAttachments(renderMode);
if (!postLighting) {
_skeletonModel.render(1.0f, modelRenderMode);
renderAttachments(renderMode);
}
// Render head so long as the camera isn't inside it
const Camera *camera = Application::getInstance()->getCamera();
const glm::vec3 cameraPos = camera->getPosition() + (camera->getRotation() * glm::vec3(0.0f, 0.0f, 1.0f)) * camera->getDistance();
if (shouldRenderHead(cameraPos, renderMode)) {
getHead()->render(1.0f, modelRenderMode);
if (!postLighting) {
getHead()->render(1.0f, modelRenderMode);
if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) {
// Render Hair
glPushMatrix();
glm::vec3 headPosition = getHead()->getPosition();
glTranslatef(headPosition.x, headPosition.y, headPosition.z);
const glm::quat& rotation = getHead()->getFinalOrientationInWorldFrame();
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
_hair.render();
glPopMatrix();
if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) {
// Render Hair
glPushMatrix();
glm::vec3 headPosition = getHead()->getPosition();
glTranslatef(headPosition.x, headPosition.y, headPosition.z);
const glm::quat& rotation = getHead()->getFinalOrientationInWorldFrame();
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
_hair.render();
glPopMatrix();
}
}
}
getHand()->render(true, modelRenderMode);
if (postLighting) {
getHand()->render(true, modelRenderMode);
}
}
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f;

View file

@ -49,7 +49,7 @@ public:
void moveWithLean();
void render(const glm::vec3& cameraPosition, RenderMode renderMode = NORMAL_RENDER_MODE, bool postLighting = false);
void renderBody(RenderMode renderMode, float glowLevel = 0.0f);
void renderBody(RenderMode renderMode, bool postLighting, float glowLevel = 0.0f);
bool shouldRenderHead(const glm::vec3& cameraPosition, RenderMode renderMode) const;
void renderDebugBodyPoints();
void renderHeadMouse(int screenWidth, int screenHeight) const;

View file

@ -1,151 +0,0 @@
//
// LocationManager.cpp
// interface/src/location
//
// Created by Stojce Slavkovski on 2/7/14.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <qhttpmultipart.h>
#include <qjsonobject.h>
#include <AccountManager.h>
#include "Application.h"
#include "ui/Snapshot.h"
#include "LocationManager.h"
const QString POST_LOCATION_CREATE = "/api/v1/locations/";
LocationManager& LocationManager::getInstance() {
static LocationManager sharedInstance;
return sharedInstance;
}
const QString UNKNOWN_ERROR_MESSAGE = "Unknown error creating named location. Please try again!";
const QString LOCATION_OBJECT_KEY = "location";
const QString LOCATION_ID_KEY = "id";
void LocationManager::namedLocationDataReceived(const QJsonObject& rootObject) {
if (rootObject.contains("status") && rootObject["status"].toString() == "success") {
emit creationCompleted(QString());
// successfuly created a location - grab the ID from the response and create a snapshot to upload
QString locationIDString = rootObject[LOCATION_OBJECT_KEY].toObject()[LOCATION_ID_KEY].toString();
updateSnapshotForExistingLocation(locationIDString);
} else {
emit creationCompleted(UNKNOWN_ERROR_MESSAGE);
}
}
void LocationManager::createNamedLocation(NamedLocation* namedLocation) {
AccountManager& accountManager = AccountManager::getInstance();
if (accountManager.isLoggedIn()) {
JSONCallbackParameters callbackParams;
callbackParams.jsonCallbackReceiver = this;
callbackParams.jsonCallbackMethod = "namedLocationDataReceived";
callbackParams.errorCallbackReceiver = this;
callbackParams.errorCallbackMethod = "errorDataReceived";
accountManager.authenticatedRequest(POST_LOCATION_CREATE, QNetworkAccessManager::PostOperation,
callbackParams, namedLocation->toJsonString().toUtf8());
}
}
void LocationManager::errorDataReceived(QNetworkReply& errorReply) {
if (errorReply.header(QNetworkRequest::ContentTypeHeader).toString().startsWith("application/json")) {
// we have some JSON error data we can parse for our error message
QJsonDocument responseJson = QJsonDocument::fromJson(errorReply.readAll());
QJsonObject dataObject = responseJson.object()["data"].toObject();
qDebug() << dataObject;
QString errorString = "There was a problem creating that location.\n";
// construct the error string from the returned attribute errors
foreach(const QString& key, dataObject.keys()) {
errorString += "\n\u2022 " + key + " - ";
QJsonValue keyedErrorValue = dataObject[key];
if (keyedErrorValue.isArray()) {
foreach(const QJsonValue& attributeErrorValue, keyedErrorValue.toArray()) {
errorString += attributeErrorValue.toString() + ", ";
}
// remove the trailing comma at end of error list
errorString.remove(errorString.length() - 2, 2);
} else if (keyedErrorValue.isString()) {
errorString += keyedErrorValue.toString();
}
}
// emit our creationCompleted signal with the error
emit creationCompleted(errorString);
} else {
creationCompleted(UNKNOWN_ERROR_MESSAGE);
}
}
void LocationManager::locationImageUpdateSuccess(const QJsonObject& rootObject) {
qDebug() << "Successfuly updated a location image.";
}
void LocationManager::updateSnapshotForExistingLocation(const QString& locationID) {
// first create a snapshot and save it
Application* application = Application::getInstance();
QTemporaryFile* tempImageFile = Snapshot::saveTempSnapshot(application->getGLWidget(), application->getAvatar());
if (tempImageFile && tempImageFile->open()) {
AccountManager& accountManager = AccountManager::getInstance();
// setup a multipart that is in the AccountManager thread - we need this so it can be cleaned up after the QNetworkReply
QHttpMultiPart* imageFileMultiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
imageFileMultiPart->moveToThread(accountManager.thread());
// parent the temp file to the QHttpMultipart after moving it to account manager thread
tempImageFile->moveToThread(accountManager.thread());
tempImageFile->setParent(imageFileMultiPart);
qDebug() << "Uploading a snapshot from" << QFileInfo(*tempImageFile).absoluteFilePath()
<< "as location image for" << locationID;
const QString LOCATION_IMAGE_NAME = "location[image]";
QHttpPart imagePart;
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader,
QVariant("form-data; name=\"" + LOCATION_IMAGE_NAME + "\";"
" filename=\"" + QFileInfo(tempImageFile->fileName()).fileName().toUtf8() + "\""));
imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
imagePart.setBodyDevice(tempImageFile);
imageFileMultiPart->append(imagePart);
const QString LOCATION_IMAGE_PUT_PATH = "api/v1/locations/%1/image";
JSONCallbackParameters imageCallbackParams;
imageCallbackParams.jsonCallbackReceiver = this;
imageCallbackParams.jsonCallbackMethod = "locationImageUpdateSuccess";
// make an authenticated request via account manager to upload the image
// don't do anything with error or success for now
AccountManager::getInstance().authenticatedRequest(LOCATION_IMAGE_PUT_PATH.arg(locationID),
QNetworkAccessManager::PutOperation,
JSONCallbackParameters(), QByteArray(), imageFileMultiPart);
} else {
qDebug() << "Couldn't open snapshot file to upload as location image. No location image will be stored.";
return;
}
}

View file

@ -1,47 +0,0 @@
//
// LocationManager.h
// interface/src/location
//
// Created by Stojce Slavkovski on 2/7/14.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_LocationManager_h
#define hifi_LocationManager_h
#include <QtCore>
#include <QtNetwork/QNetworkReply>
#include "NamedLocation.h"
class LocationManager : public QObject {
Q_OBJECT
public:
static LocationManager& getInstance();
enum NamedLocationCreateResponse {
Created,
AlreadyExists,
SystemError
};
void createNamedLocation(NamedLocation* namedLocation);
signals:
void creationCompleted(const QString& errorMessage);
private slots:
void namedLocationDataReceived(const QJsonObject& jsonObject);
void errorDataReceived(QNetworkReply& errorReply);
void locationImageUpdateSuccess(const QJsonObject& jsonObject);
private:
void updateSnapshotForExistingLocation(const QString& locationID);
};
#endif // hifi_LocationManager_h

View file

@ -1,33 +0,0 @@
//
// NamedLocation.cpp
// interface/src/location
//
// Created by Stojce Slavkovski on 2/1/14.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <AddressManager.h>
#include <UUID.h>
#include "NamedLocation.h"
NamedLocation::NamedLocation(const QString& name,
const glm::vec3& position, const glm::quat& orientation,
const QUuid& domainID) :
_name(name),
_position(position),
_orientation(orientation),
_domainID(domainID)
{
}
const QString JSON_FORMAT = "{\"location\":{\"path\":\"%1\",\"domain_id\":\"%2\",\"name\":\"%3\"}}";
QString NamedLocation::toJsonString() {
return JSON_FORMAT.arg(AddressManager::pathForPositionAndOrientation(_position, true, _orientation),
uuidStringWithoutCurlyBraces(_domainID), _name);
}

View file

@ -1,55 +0,0 @@
//
// NamedLocation.h
// interface/src/location
//
// Created by Stojce Slavkovski on 2/1/14.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_NamedLocation_h
#define hifi_NamedLocation_h
#include <glm/glm.hpp>
#include <glm/gtx/string_cast.hpp>
#include <glm/gtc/quaternion.hpp>
#include <QtCore>
class NamedLocation : public QObject {
Q_OBJECT
public:
NamedLocation(const QString& name, const glm::vec3& position, const glm::quat& orientation, const QUuid& domainID);
QString toJsonString();
bool isEmpty() { return _name.isNull() || _name.isEmpty(); }
void setName(QString name) { _name = name; }
const QString& getName() const { return _name; }
void setLocation(glm::vec3 position) { _position = position; }
const glm::vec3& getPosition() const { return _position; }
void setOrientation(const glm::quat& orentation) { _orientation = orentation; }
const glm::quat& getOrientation() const { return _orientation; }
void setDomainID(const QUuid& domainID) { _domainID = domainID; }
const QUuid& getDomainID() const { return _domainID; }
signals:
void dataReceived(bool locationExists);
private:
QString _name;
QString _createdBy;
glm::vec3 _position;
glm::quat _orientation;
QUuid _domainID;
};
#endif // hifi_NamedLocation_h

View file

@ -38,6 +38,11 @@ QString LocationScriptingInterface::getHostname() {
return NodeList::getInstance()->getDomainHandler().getHostname();
}
QString LocationScriptingInterface::getDomainID() const {
const QUuid& domainID = NodeList::getInstance()->getDomainHandler().getUUID();
return domainID.isNull() ? "" : uuidStringWithoutCurlyBraces(domainID);
}
void LocationScriptingInterface::assign(const QString& url) {
QMetaObject::invokeMethod(&AddressManager::getInstance(), "handleLookupString", Q_ARG(const QString&, url));
}

View file

@ -29,6 +29,7 @@ class LocationScriptingInterface : public QObject {
Q_PROPERTY(QString protocol READ getProtocol)
Q_PROPERTY(QString hostname READ getHostname)
Q_PROPERTY(QString pathname READ getPathname)
Q_PROPERTY(QString domainID READ getDomainID)
LocationScriptingInterface() { };
public:
static LocationScriptingInterface* getInstance();
@ -38,6 +39,7 @@ public:
QString getProtocol() { return HIFI_URL_SCHEME; };
QString getPathname();
QString getHostname();
QString getDomainID() const;
static QScriptValue locationGetter(QScriptContext* context, QScriptEngine* engine);
static QScriptValue locationSetter(QScriptContext* context, QScriptEngine* engine);

View file

@ -9,13 +9,14 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <qwebframe.h>
#include <qwebview.h>
#include <AccountManager.h>
#include <LimitedNodeList.h>
#include <OAuthNetworkAccessManager.h>
#include "Application.h"
#include "DataWebPage.h"
#include "DataWebDialog.h"
@ -23,19 +24,21 @@ DataWebDialog::DataWebDialog() {
// make sure the dialog deletes itself when it closes
setAttribute(Qt::WA_DeleteOnClose);
// use an OAuthNetworkAccessManager instead of regular QNetworkAccessManager so our requests are authed
page()->setNetworkAccessManager(OAuthNetworkAccessManager::getInstance());
// have the page delegate external links so they can be captured by the Application in case they are a hifi link
page()->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks);
// set our page to a DataWebPage
setPage(new DataWebPage(this));
// have the Application handle external links
connect(this, &QWebView::linkClicked, Application::getInstance(), &Application::openUrl);
}
DataWebDialog* DataWebDialog::dialogForPath(const QString& path) {
DataWebDialog* DataWebDialog::dialogForPath(const QString& path,
const JavascriptObjectMap& javascriptObjects) {
DataWebDialog* dialogWebView = new DataWebDialog();
dialogWebView->_javascriptObjects = javascriptObjects;
connect(dialogWebView->page()->mainFrame(), &QWebFrame::javaScriptWindowObjectCleared,
dialogWebView, &DataWebDialog::addJavascriptObjectsToWindow);
QUrl dataWebUrl(DEFAULT_NODE_AUTH_URL);
dataWebUrl.setPath(path);
@ -44,4 +47,10 @@ DataWebDialog* DataWebDialog::dialogForPath(const QString& path) {
dialogWebView->load(dataWebUrl);
return dialogWebView;
}
void DataWebDialog::addJavascriptObjectsToWindow() {
foreach(const QString& name, _javascriptObjects.keys()) {
page()->mainFrame()->addToJavaScriptWindowObject(name, _javascriptObjects[name]);
}
}

View file

@ -15,11 +15,18 @@
#include <qobject.h>
#include <qwebview.h>
typedef QMap<QString, QObject*> JavascriptObjectMap;
class DataWebDialog : public QWebView {
Q_OBJECT
public:
DataWebDialog();
static DataWebDialog* dialogForPath(const QString& path);
static DataWebDialog* dialogForPath(const QString& path,
const JavascriptObjectMap& javascriptObjects = JavascriptObjectMap());
private slots:
void addJavascriptObjectsToWindow();
private:
JavascriptObjectMap _javascriptObjects;
};
#endif // hifi_WebkitDialog_h

View file

@ -0,0 +1,31 @@
//
// DataWebPage.cpp
// interface/src/ui
//
// Created by Stephen Birarda on 2014-09-22.
// 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 <OAuthNetworkAccessManager.h>
#include "DataWebPage.h"
DataWebPage::DataWebPage(QObject* parent) :
QWebPage(parent)
{
// use an OAuthNetworkAccessManager instead of regular QNetworkAccessManager so our requests are authed
setNetworkAccessManager(OAuthNetworkAccessManager::getInstance());
// have the page delegate external links so they can be captured by the Application in case they are a hifi link
setLinkDelegationPolicy(QWebPage::DelegateExternalLinks);
// give the page an empty stylesheet
settings()->setUserStyleSheetUrl(QUrl());
}
void DataWebPage::javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID) {
qDebug() << "JS console message at line" << lineNumber << "from" << sourceID << "-" << message;
}

View file

@ -0,0 +1,24 @@
//
// DataWebPage.h
// interface/src/ui
//
// Created by Stephen Birarda on 2014-09-22.
// 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_DataWebPage_h
#define hifi_DataWebPage_h
#include <qwebpage.h>
class DataWebPage : public QWebPage {
public:
DataWebPage(QObject* parent = 0);
protected:
void javaScriptConsoleMessage(const QString & message, int lineNumber, const QString & sourceID);
};
#endif // hifi_DataWebPage_h

View file

@ -1031,7 +1031,7 @@ void ImportHeightfieldTool::apply() {
data.setRoot(AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), new MetavoxelNode(AttributeValue(
AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), encodeInline(colorPointer))));
int size = glm::sqrt(height.size()) + HeightfieldBuffer::SHARED_EDGE;
int size = glm::sqrt(float(height.size())) + HeightfieldBuffer::SHARED_EDGE;
QByteArray material(size * size, 0);
HeightfieldMaterialDataPointer materialPointer(new HeightfieldMaterialData(material));
data.setRoot(AttributeRegistry::getInstance()->getHeightfieldMaterialAttribute(), new MetavoxelNode(AttributeValue(
@ -1103,7 +1103,7 @@ void ImportHeightfieldTool::updateHeightImage() {
if (_loadingImage) {
return;
}
int size = glm::sqrt(_rawHeight.size());
int size = glm::sqrt(float(_rawHeight.size()));
_heightImage = QImage(size, size, QImage::Format_RGB888);
const quint16* src = _rawHeight.constData();
float scale = _heightScale->value(), offset = _heightOffset->value();

View file

@ -15,6 +15,7 @@
#include <QHeaderView>
#include <QMessageBox>
#include <QUrl>
#include <qurlquery.h>
#include <QXmlStreamReader>
#include <NetworkAccessManager.h>

View file

@ -9,7 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QtWebKitWidgets/QWebView>
#include <qwebview.h>
#include <qurlquery.h>
#include <AccountManager.h>

View file

@ -64,8 +64,8 @@ SnapshotMetaData* Snapshot::parseSnapshotData(QString snapshotPath) {
return data;
}
QString Snapshot::saveSnapshot(QGLWidget* widget, Avatar* avatar) {
QFile* snapshotFile = savedFileForSnapshot(widget, avatar, false);
QString Snapshot::saveSnapshot() {
QFile* snapshotFile = savedFileForSnapshot(false);
// we don't need the snapshot file, so close it, grab its filename and delete it
snapshotFile->close();
@ -77,14 +77,18 @@ QString Snapshot::saveSnapshot(QGLWidget* widget, Avatar* avatar) {
return snapshotPath;
}
QTemporaryFile* Snapshot::saveTempSnapshot(QGLWidget* widget, Avatar* avatar) {
QTemporaryFile* Snapshot::saveTempSnapshot() {
// return whatever we get back from saved file for snapshot
return static_cast<QTemporaryFile*>(savedFileForSnapshot(widget, avatar, true));;
return static_cast<QTemporaryFile*>(savedFileForSnapshot(true));;
}
QFile* Snapshot::savedFileForSnapshot(QGLWidget* widget, Avatar* avatar, bool isTemporary) {
QFile* Snapshot::savedFileForSnapshot(bool isTemporary) {
QGLWidget* widget = Application::getInstance()->getGLWidget();
QImage shot = widget->grabFrameBuffer();
Avatar* avatar = Application::getInstance()->getAvatar();
glm::vec3 location = avatar->getPosition();
glm::quat orientation = avatar->getHead()->getOrientation();

View file

@ -14,9 +14,11 @@
#include "InterfaceConfig.h"
#include <QImage>
#include <qimage.h>
#include <qfile.h>
#include <qtemporaryfile.h>
#include <QGLWidget>
#include <QString>
#include <qstring.h>
#include "avatar/Avatar.h"
@ -41,12 +43,12 @@ private:
class Snapshot {
public:
static QString saveSnapshot(QGLWidget* widget, Avatar* avatar);
static QTemporaryFile* saveTempSnapshot(QGLWidget* widget, Avatar* avatar);
static QString saveSnapshot();
static QTemporaryFile* saveTempSnapshot();
static SnapshotMetaData* parseSnapshotData(QString snapshotPath);
private:
static QFile* savedFileForSnapshot(QGLWidget* widget, Avatar* avatar, bool isTemporary);
static QFile* savedFileForSnapshot(bool isTemporary);
};
#endif // hifi_Snapshot_h

View file

@ -228,7 +228,7 @@ void writeRecordingToFile(RecordingPointer recording, const QString& filename) {
stream << numBlendshapes;
mask.resize(mask.size() + numBlendshapes);
}
for (int j = 0; j < numBlendshapes; ++j) {
for (quint32 j = 0; j < numBlendshapes; ++j) {
if (i == 0 ||
frame._blendshapeCoefficients[j] != previousFrame._blendshapeCoefficients[j]) {
writeFloat(stream, frame.getBlendshapeCoefficients()[j], BLENDSHAPE_RADIX);
@ -243,7 +243,7 @@ void writeRecordingToFile(RecordingPointer recording, const QString& filename) {
stream << numJoints;
mask.resize(mask.size() + numJoints);
}
for (int j = 0; j < numJoints; ++j) {
for (quint32 j = 0; j < numJoints; ++j) {
if (i == 0 ||
frame._jointRotations[j] != previousFrame._jointRotations[j]) {
writeQuat(stream, frame._jointRotations[j]);
@ -547,7 +547,7 @@ RecordingPointer readRecordingFromFile(RecordingPointer recording, const QString
stream >> numBlendshapes;
}
frame._blendshapeCoefficients.resize(numBlendshapes);
for (int j = 0; j < numBlendshapes; ++j) {
for (quint32 j = 0; j < numBlendshapes; ++j) {
if (!mask[maskIndex++] || !readFloat(stream, frame._blendshapeCoefficients[j], BLENDSHAPE_RADIX)) {
frame._blendshapeCoefficients[j] = previousFrame._blendshapeCoefficients[j];
}
@ -557,7 +557,7 @@ RecordingPointer readRecordingFromFile(RecordingPointer recording, const QString
stream >> numJoints;
}
frame._jointRotations.resize(numJoints);
for (int j = 0; j < numJoints; ++j) {
for (quint32 j = 0; j < numJoints; ++j) {
if (!mask[maskIndex++] || !readQuat(stream, frame._jointRotations[j])) {
frame._jointRotations[j] = previousFrame._jointRotations[j];
}

View file

@ -56,7 +56,7 @@ public:
void setShapes(QVector<ListShapeEntry>& shapes);
// TODO: either implement this or remove ListShape altogether
bool findRayIntersection(const glm::vec3& rayStart, const glm::vec3& rayDirection, float& distance) const { return false; }
bool findRayIntersection(RayIntersectionInfo& intersection) const { return false; }
protected:
void clear();