mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 18:44:01 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into 19561
This commit is contained in:
commit
23068b0356
23 changed files with 880 additions and 595 deletions
|
@ -847,8 +847,9 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
// this is a script upload - ask the HTTPConnection to parse the form data
|
||||
QList<FormData> formData = connection->parseFormData();
|
||||
|
||||
// check how many instances of this assignment the user wants by checking the ASSIGNMENT-INSTANCES header
|
||||
// check optional headers for # of instances and pool
|
||||
const QString ASSIGNMENT_INSTANCES_HEADER = "ASSIGNMENT-INSTANCES";
|
||||
const QString ASSIGNMENT_POOL_HEADER = "ASSIGNMENT-POOL";
|
||||
|
||||
QByteArray assignmentInstancesValue = connection->requestHeaders().value(ASSIGNMENT_INSTANCES_HEADER.toLocal8Bit());
|
||||
|
||||
|
@ -860,25 +861,34 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
|
||||
numInstances = assignmentInstancesValue.toInt();
|
||||
}
|
||||
|
||||
|
||||
QString assignmentPool = emptyPool;
|
||||
QByteArray assignmentPoolValue = connection->requestHeaders().value(ASSIGNMENT_POOL_HEADER.toLocal8Bit());
|
||||
|
||||
if (!assignmentPoolValue.isEmpty()) {
|
||||
// specific pool requested, set that on the created assignment
|
||||
assignmentPool = QString(assignmentPoolValue);
|
||||
}
|
||||
|
||||
const char ASSIGNMENT_SCRIPT_HOST_LOCATION[] = "resources/web/assignment";
|
||||
|
||||
for (int i = 0; i < numInstances; i++) {
|
||||
|
||||
// create an assignment for this saved script
|
||||
Assignment* scriptAssignment = new Assignment(Assignment::CreateCommand, Assignment::AgentType);
|
||||
Assignment* scriptAssignment = new Assignment(Assignment::CreateCommand, Assignment::AgentType, assignmentPool);
|
||||
|
||||
QString newPath(ASSIGNMENT_SCRIPT_HOST_LOCATION);
|
||||
newPath += "/";
|
||||
// append the UUID for this script as the new filename, remove the curly braces
|
||||
newPath += uuidStringWithoutCurlyBraces(scriptAssignment->getUUID());
|
||||
|
||||
// create a file with the GUID of the assignment in the script host locaiton
|
||||
// create a file with the GUID of the assignment in the script host location
|
||||
QFile scriptFile(newPath);
|
||||
scriptFile.open(QIODevice::WriteOnly);
|
||||
scriptFile.write(formData[0].second);
|
||||
|
||||
qDebug("Saved a script for assignment at %s", qPrintable(newPath));
|
||||
qDebug() << qPrintable(QString("Saved a script for assignment at %1%2")
|
||||
.arg(newPath).arg(assignmentPool == emptyPool ? "" : " - pool is " + assignmentPool));
|
||||
|
||||
// add the script assigment to the assignment queue
|
||||
_assignmentQueue.enqueue(SharedAssignmentPointer(scriptAssignment));
|
||||
|
|
|
@ -27,7 +27,7 @@ Script.update.connect(function(deltaTime) {
|
|||
if (!jointMapping) {
|
||||
var avatarJointNames = Avatar.jointNames;
|
||||
var animationJointNames = animation.jointNames;
|
||||
if (avatarJointNames === 0 || animationJointNames.length === 0) {
|
||||
if (avatarJointNames.length === 0 || animationJointNames.length === 0) {
|
||||
return;
|
||||
}
|
||||
jointMapping = new Array(avatarJointNames.length);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -356,6 +356,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
QMutexLocker locker(&_settingsMutex);
|
||||
_previousScriptLocation = _settings->value("LastScriptLocation", QVariant("")).toString();
|
||||
}
|
||||
//When -url in command line, teleport to location
|
||||
urlGoTo(argc, constArgv);
|
||||
}
|
||||
|
||||
Application::~Application() {
|
||||
|
@ -821,6 +823,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
break;
|
||||
|
||||
case Qt::Key_E:
|
||||
case Qt::Key_PageUp:
|
||||
if (!_myAvatar->getDriveKeys(UP)) {
|
||||
_myAvatar->jump();
|
||||
}
|
||||
|
@ -832,6 +835,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
break;
|
||||
|
||||
case Qt::Key_C:
|
||||
case Qt::Key_PageDown:
|
||||
_myAvatar->setDriveKeys(DOWN, 1.f);
|
||||
break;
|
||||
|
||||
|
@ -1020,10 +1024,12 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
|
|||
|
||||
switch (event->key()) {
|
||||
case Qt::Key_E:
|
||||
case Qt::Key_PageUp:
|
||||
_myAvatar->setDriveKeys(UP, 0.f);
|
||||
break;
|
||||
|
||||
case Qt::Key_C:
|
||||
case Qt::Key_PageDown:
|
||||
_myAvatar->setDriveKeys(DOWN, 0.f);
|
||||
break;
|
||||
|
||||
|
@ -2735,7 +2741,7 @@ void Application::displayOverlay() {
|
|||
(Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth))
|
||||
? 80 : 20;
|
||||
drawText(_glWidget->width() - 100, _glWidget->height() - timerBottom, 0.30f, 1.0f, 0.f, frameTimer, WHITE_TEXT);
|
||||
drawText(_glWidget->width() - 100, _glWidget->height() - timerBottom, 0.30f, 0.0f, 0, frameTimer, WHITE_TEXT);
|
||||
}
|
||||
|
||||
_overlays.render2D();
|
||||
|
@ -3027,6 +3033,7 @@ void Application::resetSensors() {
|
|||
_mouseX = _glWidget->width() / 2;
|
||||
_mouseY = _glWidget->height() / 2;
|
||||
|
||||
_faceplus.reset();
|
||||
_faceshift.reset();
|
||||
_visage.reset();
|
||||
|
||||
|
@ -3576,3 +3583,38 @@ void Application::takeSnapshot() {
|
|||
|
||||
Snapshot::saveSnapshot(_glWidget, _myAvatar);
|
||||
}
|
||||
|
||||
void Application::urlGoTo(int argc, const char * constArgv[]) {
|
||||
//Gets the url (hifi://domain/destination/orientation)
|
||||
QString customUrl = getCmdOption(argc, constArgv, "-url");
|
||||
|
||||
if (customUrl.startsWith("hifi://")) {
|
||||
QStringList urlParts = customUrl.remove(0, CUSTOM_URL_SCHEME.length() + 2).split('/', QString::SkipEmptyParts);
|
||||
if (urlParts.count() > 1) {
|
||||
// if url has 2 or more parts, the first one is domain name
|
||||
QString domain = urlParts[0];
|
||||
|
||||
// second part is either a destination coordinate or
|
||||
// a place name
|
||||
QString destination = urlParts[1];
|
||||
|
||||
// any third part is an avatar orientation.
|
||||
QString orientation = urlParts.count() > 2 ? urlParts[2] : QString();
|
||||
|
||||
Menu::goToDomain(domain);
|
||||
|
||||
// goto either @user, #place, or x-xx,y-yy,z-zz
|
||||
// style co-ordinate.
|
||||
Menu::goTo(destination);
|
||||
|
||||
if (!orientation.isEmpty()) {
|
||||
// location orientation
|
||||
Menu::goToOrientation(orientation);
|
||||
}
|
||||
} else if (urlParts.count() == 1) {
|
||||
// location coordinates or place name
|
||||
QString destination = urlParts[0];
|
||||
Menu::goTo(destination);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,6 +129,7 @@ public:
|
|||
void initializeGL();
|
||||
void paintGL();
|
||||
void resizeGL(int width, int height);
|
||||
void urlGoTo(int argc, const char * constArgv[]);
|
||||
|
||||
void keyPressEvent(QKeyEvent* event);
|
||||
void keyReleaseEvent(QKeyEvent* event);
|
||||
|
|
|
@ -45,7 +45,7 @@ Camera::Camera() :
|
|||
_idealPosition(0.0f, 0.0f, 0.0f),
|
||||
_targetPosition(0.0f, 0.0f, 0.0f),
|
||||
_fieldOfView(DEFAULT_FIELD_OF_VIEW_DEGREES),
|
||||
_aspectRatio(16.f/9.f),
|
||||
_aspectRatio(16.0f/9.0f),
|
||||
_nearClip(0.08f), // default
|
||||
_farClip(50.0f * TREE_SCALE), // default
|
||||
_upShift(0.0f),
|
||||
|
@ -94,8 +94,8 @@ void Camera::updateFollowMode(float deltaTime) {
|
|||
|
||||
// derive t from tightness
|
||||
float t = _tightness * _modeShift * deltaTime;
|
||||
if (t > 1.0) {
|
||||
t = 1.0;
|
||||
if (t > 1.0f) {
|
||||
t = 1.0f;
|
||||
}
|
||||
|
||||
// handle keepLookingAt
|
||||
|
|
|
@ -316,7 +316,8 @@ Menu::Menu() :
|
|||
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Visage, 0, true,
|
||||
appInstance->getVisage(), SLOT(updateEnabled()));
|
||||
#endif
|
||||
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::GlowWhenSpeaking, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, false);
|
||||
|
||||
QMenu* handOptionsMenu = developerMenu->addMenu("Hand Options");
|
||||
|
|
|
@ -136,10 +136,10 @@ public:
|
|||
|
||||
void removeAction(QMenu* menu, const QString& actionName);
|
||||
|
||||
bool goToDestination(QString destination);
|
||||
void goToOrientation(QString orientation);
|
||||
void goToDomain(const QString newDomain);
|
||||
void goTo(QString destination);
|
||||
bool static goToDestination(QString destination);
|
||||
void static goToOrientation(QString orientation);
|
||||
void static goToDomain(const QString newDomain);
|
||||
void static goTo(QString destination);
|
||||
|
||||
public slots:
|
||||
|
||||
|
@ -307,6 +307,7 @@ namespace MenuOption {
|
|||
const QString Fullscreen = "Fullscreen";
|
||||
const QString FullscreenMirror = "Fullscreen Mirror";
|
||||
const QString GlowMode = "Cycle Glow Mode";
|
||||
const QString GlowWhenSpeaking = "Glow When Speaking";
|
||||
const QString GoHome = "Go Home";
|
||||
const QString GoTo = "Go To...";
|
||||
const QString GoToDomain = "Go To Domain...";
|
||||
|
|
|
@ -34,6 +34,7 @@ static const QString TEXDIR_FIELD = "texdir";
|
|||
static const QString LOD_FIELD = "lod";
|
||||
|
||||
static const QString S3_URL = "http://highfidelity-public.s3-us-west-1.amazonaws.com";
|
||||
static const QString DATA_SERVER_URL = "https://data-web.highfidelity.io";
|
||||
static const QString MODEL_URL = "/api/v1/models";
|
||||
|
||||
static const QString SETTING_NAME = "LastModelUploadLocation";
|
||||
|
@ -201,14 +202,14 @@ void ModelUploader::send() {
|
|||
|
||||
JSONCallbackParameters callbackParams;
|
||||
callbackParams.jsonCallbackReceiver = this;
|
||||
callbackParams.jsonCallbackMethod = "uploadSuccess";
|
||||
callbackParams.jsonCallbackMethod = "checkJSON";
|
||||
callbackParams.errorCallbackReceiver = this;
|
||||
callbackParams.errorCallbackMethod = "uploadFailed";
|
||||
callbackParams.updateReciever = this;
|
||||
callbackParams.updateSlot = SLOT(uploadUpdate(qint64, qint64));
|
||||
|
||||
AccountManager::getInstance().authenticatedRequest(MODEL_URL, QNetworkAccessManager::PostOperation, callbackParams, QByteArray(), _dataMultiPart);
|
||||
_dataMultiPart = NULL;
|
||||
AccountManager::getInstance().authenticatedRequest(MODEL_URL + "/" + QFileInfo(_url).baseName(),
|
||||
QNetworkAccessManager::GetOperation,
|
||||
callbackParams);
|
||||
|
||||
qDebug() << "Sending model...";
|
||||
_progressDialog = new QDialog();
|
||||
_progressBar = new QProgressBar(_progressDialog);
|
||||
|
@ -226,6 +227,61 @@ void ModelUploader::send() {
|
|||
_progressBar = NULL;
|
||||
}
|
||||
|
||||
void ModelUploader::checkJSON(const QJsonObject& jsonResponse) {
|
||||
if (jsonResponse.contains("status") && jsonResponse.value("status").toString() == "success") {
|
||||
qDebug() << "status : success";
|
||||
JSONCallbackParameters callbackParams;
|
||||
callbackParams.jsonCallbackReceiver = this;
|
||||
callbackParams.jsonCallbackMethod = "uploadSuccess";
|
||||
callbackParams.errorCallbackReceiver = this;
|
||||
callbackParams.errorCallbackMethod = "uploadFailed";
|
||||
callbackParams.updateReciever = this;
|
||||
callbackParams.updateSlot = SLOT(uploadUpdate(qint64, qint64));
|
||||
|
||||
if (jsonResponse.contains("exists") && jsonResponse.value("exists").toBool()) {
|
||||
qDebug() << "exists : true";
|
||||
if (jsonResponse.contains("can_update") && jsonResponse.value("can_update").toBool()) {
|
||||
qDebug() << "can_update : true";
|
||||
|
||||
AccountManager::getInstance().authenticatedRequest(MODEL_URL + "/" + QFileInfo(_url).baseName(),
|
||||
QNetworkAccessManager::PutOperation,
|
||||
callbackParams,
|
||||
QByteArray(),
|
||||
_dataMultiPart);
|
||||
_dataMultiPart = NULL;
|
||||
} else {
|
||||
qDebug() << "can_update : false";
|
||||
if (_progressDialog) {
|
||||
_progressDialog->reject();
|
||||
}
|
||||
QMessageBox::warning(NULL,
|
||||
QString("ModelUploader::checkJSON()"),
|
||||
QString("This model already exist and is own by someone else."),
|
||||
QMessageBox::Ok);
|
||||
deleteLater();
|
||||
}
|
||||
} else {
|
||||
qDebug() << "exists : false";
|
||||
AccountManager::getInstance().authenticatedRequest(MODEL_URL,
|
||||
QNetworkAccessManager::PostOperation,
|
||||
callbackParams,
|
||||
QByteArray(),
|
||||
_dataMultiPart);
|
||||
_dataMultiPart = NULL;
|
||||
}
|
||||
} else {
|
||||
qDebug() << "status : failed";
|
||||
if (_progressDialog) {
|
||||
_progressDialog->reject();
|
||||
}
|
||||
QMessageBox::warning(NULL,
|
||||
QString("ModelUploader::checkJSON()"),
|
||||
QString("Something went wrong with the data-server."),
|
||||
QMessageBox::Ok);
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void ModelUploader::uploadUpdate(qint64 bytesSent, qint64 bytesTotal) {
|
||||
if (_progressDialog) {
|
||||
_progressBar->setRange(0, bytesTotal);
|
||||
|
@ -249,11 +305,11 @@ void ModelUploader::uploadFailed(QNetworkReply::NetworkError errorCode, const QS
|
|||
if (_progressDialog) {
|
||||
_progressDialog->reject();
|
||||
}
|
||||
qDebug() << "Model upload failed (" << errorCode << "): " << errorString;
|
||||
QMessageBox::warning(NULL,
|
||||
QString("ModelUploader::uploadFailed()"),
|
||||
QString("There was a problem with your upload, please try again later."),
|
||||
QMessageBox::Ok);
|
||||
qDebug() << "Model upload failed (" << errorCode << "): " << errorString;
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ public slots:
|
|||
void send();
|
||||
|
||||
private slots:
|
||||
void checkJSON(const QJsonObject& jsonResponse);
|
||||
void uploadUpdate(qint64 bytesSent, qint64 bytesTotal);
|
||||
void uploadSuccess(const QJsonObject& jsonResponse);
|
||||
void uploadFailed(QNetworkReply::NetworkError errorCode, const QString& errorString);
|
||||
|
|
|
@ -211,9 +211,14 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
|
|||
const float GLOW_DISTANCE = 20.0f;
|
||||
const float GLOW_MAX_LOUDNESS = 2500.0f;
|
||||
const float MAX_GLOW = 0.5f;
|
||||
const float GLOW_FROM_AVERAGE_LOUDNESS = ((this == Application::getInstance()->getAvatar())
|
||||
? 0.0f
|
||||
: MAX_GLOW * getHeadData()->getAudioLoudness() / GLOW_MAX_LOUDNESS);
|
||||
|
||||
float GLOW_FROM_AVERAGE_LOUDNESS = ((this == Application::getInstance()->getAvatar())
|
||||
? 0.0f
|
||||
: MAX_GLOW * getHeadData()->getAudioLoudness() / GLOW_MAX_LOUDNESS);
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::GlowWhenSpeaking)) {
|
||||
GLOW_FROM_AVERAGE_LOUDNESS = 0.0f;
|
||||
}
|
||||
|
||||
Glower glower(_moving && distanceToTarget > GLOW_DISTANCE && renderMode == NORMAL_RENDER_MODE
|
||||
? 1.0f
|
||||
: GLOW_FROM_AVERAGE_LOUDNESS);
|
||||
|
|
|
@ -41,8 +41,15 @@ void Faceplus::init() {
|
|||
updateEnabled();
|
||||
}
|
||||
|
||||
void Faceplus::setState(const glm::quat& headRotation, float estimatedEyePitch, float estimatedEyeYaw,
|
||||
const QVector<float>& blendshapeCoefficients) {
|
||||
void Faceplus::reset() {
|
||||
if (_enabled) {
|
||||
QMetaObject::invokeMethod(_reader, "reset");
|
||||
}
|
||||
}
|
||||
|
||||
void Faceplus::setState(const glm::vec3& headTranslation, const glm::quat& headRotation,
|
||||
float estimatedEyePitch, float estimatedEyeYaw, const QVector<float>& blendshapeCoefficients) {
|
||||
_headTranslation = headTranslation;
|
||||
_headRotation = headRotation;
|
||||
_estimatedEyePitch = estimatedEyePitch;
|
||||
_estimatedEyeYaw = estimatedEyeYaw;
|
||||
|
@ -150,7 +157,7 @@ FaceplusReader::~FaceplusReader() {
|
|||
|
||||
void FaceplusReader::init() {
|
||||
#ifdef HAVE_FACEPLUS
|
||||
if (!faceplus_init("VGA")) {
|
||||
if (!faceplus_init("hHD")) {
|
||||
qDebug() << "Failed to initialized Faceplus.";
|
||||
return;
|
||||
}
|
||||
|
@ -191,7 +198,8 @@ void FaceplusReader::init() {
|
|||
}
|
||||
}
|
||||
_blendshapeCoefficients.resize(maxIndex + 1);
|
||||
|
||||
_referenceInitialized = false;
|
||||
|
||||
QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
|
||||
#endif
|
||||
}
|
||||
|
@ -203,10 +211,24 @@ void FaceplusReader::shutdown() {
|
|||
|
||||
void FaceplusReader::update() {
|
||||
#ifdef HAVE_FACEPLUS
|
||||
if (!(faceplus_synchronous_track() && faceplus_current_output_vector(_outputVector.data()))) {
|
||||
float x, y, rotation, scale;
|
||||
if (!(faceplus_synchronous_track() && faceplus_current_face_location(&x, &y, &rotation, &scale) && !glm::isnan(x) &&
|
||||
faceplus_current_output_vector(_outputVector.data()))) {
|
||||
QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
if (!_referenceInitialized) {
|
||||
_referenceX = x;
|
||||
_referenceY = y;
|
||||
_referenceScale = scale;
|
||||
_referenceInitialized = true;
|
||||
}
|
||||
const float TRANSLATION_SCALE = 10.0f;
|
||||
const float REFERENCE_DISTANCE = 10.0f;
|
||||
float depthScale = _referenceScale / scale;
|
||||
float z = REFERENCE_DISTANCE * (depthScale - 1.0f);
|
||||
glm::vec3 headTranslation((x - _referenceX) * depthScale * TRANSLATION_SCALE,
|
||||
(y - _referenceY) * depthScale * TRANSLATION_SCALE, z);
|
||||
glm::quat headRotation(glm::radians(glm::vec3(-_outputVector.at(_headRotationIndices[0]),
|
||||
_outputVector.at(_headRotationIndices[1]), -_outputVector.at(_headRotationIndices[2]))));
|
||||
float estimatedEyePitch = (_outputVector.at(_leftEyeRotationIndices[0]) +
|
||||
|
@ -222,10 +244,16 @@ void FaceplusReader::update() {
|
|||
}
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(Application::getInstance()->getFaceplus(), "setState", Q_ARG(const glm::quat&, headRotation),
|
||||
Q_ARG(float, estimatedEyePitch), Q_ARG(float, estimatedEyeYaw), Q_ARG(const QVector<float>&, _blendshapeCoefficients));
|
||||
QMetaObject::invokeMethod(Application::getInstance()->getFaceplus(), "setState", Q_ARG(const glm::vec3&, headTranslation),
|
||||
Q_ARG(const glm::quat&, headRotation), Q_ARG(float, estimatedEyePitch), Q_ARG(float, estimatedEyeYaw),
|
||||
Q_ARG(const QVector<float>&, _blendshapeCoefficients));
|
||||
|
||||
QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FaceplusReader::reset() {
|
||||
#ifdef HAVE_FACEPLUS
|
||||
_referenceInitialized = false;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -30,11 +30,12 @@ public:
|
|||
virtual ~Faceplus();
|
||||
|
||||
void init();
|
||||
|
||||
void reset();
|
||||
|
||||
bool isActive() const { return _active; }
|
||||
|
||||
Q_INVOKABLE void setState(const glm::quat& headRotation, float estimatedEyePitch, float estimatedEyeYaw,
|
||||
const QVector<float>& blendshapeCoefficients);
|
||||
Q_INVOKABLE void setState(const glm::vec3& headTranslation, const glm::quat& headRotation,
|
||||
float estimatedEyePitch, float estimatedEyeYaw, const QVector<float>& blendshapeCoefficients);
|
||||
|
||||
public slots:
|
||||
|
||||
|
@ -63,6 +64,7 @@ public:
|
|||
Q_INVOKABLE void init();
|
||||
Q_INVOKABLE void shutdown();
|
||||
Q_INVOKABLE void update();
|
||||
Q_INVOKABLE void reset();
|
||||
|
||||
private:
|
||||
|
||||
|
@ -72,6 +74,10 @@ private:
|
|||
int _headRotationIndices[3];
|
||||
int _leftEyeRotationIndices[2];
|
||||
int _rightEyeRotationIndices[2];
|
||||
float _referenceX;
|
||||
float _referenceY;
|
||||
float _referenceScale;
|
||||
bool _referenceInitialized;
|
||||
QVector<float> _blendshapeCoefficients;
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -60,11 +60,11 @@ Model::SkinLocations Model::_skinNormalMapLocations;
|
|||
Model::SkinLocations Model::_skinShadowLocations;
|
||||
|
||||
void Model::setScale(const glm::vec3& scale) {
|
||||
glm::vec3 deltaScale = _scale - scale;
|
||||
float scaleLength = glm::length(_scale);
|
||||
float relativeDeltaScale = glm::length(_scale - scale) / scaleLength;
|
||||
|
||||
// decreased epsilon because this wasn't handling scale changes of 0.01
|
||||
const float SMALLER_EPSILON = EPSILON * 0.0001f;
|
||||
if (glm::length2(deltaScale) > SMALLER_EPSILON) {
|
||||
const float ONE_PERCENT = 0.01f;
|
||||
if (relativeDeltaScale > ONE_PERCENT || scaleLength < EPSILON) {
|
||||
_scale = scale;
|
||||
rebuildShapes();
|
||||
}
|
||||
|
@ -468,20 +468,56 @@ void Model::clearShapes() {
|
|||
|
||||
void Model::rebuildShapes() {
|
||||
clearShapes();
|
||||
|
||||
if (_jointStates.isEmpty()) {
|
||||
|
||||
if (!_geometry) {
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure all the joints are updated correctly before we try to create their shapes
|
||||
for (int i = 0; i < _jointStates.size(); i++) {
|
||||
updateJointState(i);
|
||||
}
|
||||
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
|
||||
if (geometry.joints.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int numJoints = geometry.joints.size();
|
||||
QVector<glm::mat4> transforms;
|
||||
transforms.fill(glm::mat4(), numJoints);
|
||||
QVector<glm::quat> combinedRotations;
|
||||
combinedRotations.fill(glm::quat(), numJoints);
|
||||
QVector<bool> shapeIsSet;
|
||||
shapeIsSet.fill(false, numJoints);
|
||||
int rootIndex = 0;
|
||||
|
||||
float uniformScale = extractUniformScale(_scale);
|
||||
glm::quat inverseRotation = glm::inverse(_rotation);
|
||||
glm::vec3 rootPosition(0.f);
|
||||
int numShapesSet = 0;
|
||||
int lastNumShapesSet = -1;
|
||||
while (numShapesSet < numJoints && numShapesSet != lastNumShapesSet) {
|
||||
lastNumShapesSet = numShapesSet;
|
||||
for (int i = 0; i < numJoints; ++i) {
|
||||
if (shapeIsSet[i]) {
|
||||
continue;
|
||||
}
|
||||
const FBXJoint& joint = geometry.joints[i];
|
||||
int parentIndex = joint.parentIndex;
|
||||
if (parentIndex == -1) {
|
||||
rootIndex = i;
|
||||
glm::mat4 baseTransform = glm::mat4_cast(_rotation) * uniformScale * glm::translate(_offset);
|
||||
glm::quat combinedRotation = joint.preRotation * joint.rotation * joint.postRotation;
|
||||
transforms[i] = baseTransform * geometry.offset * glm::translate(joint.translation) * joint.preTransform *
|
||||
glm::mat4_cast(combinedRotation) * joint.postTransform;
|
||||
combinedRotations[i] = _rotation * combinedRotation;
|
||||
++numShapesSet;
|
||||
shapeIsSet[i] = true;
|
||||
} else if (shapeIsSet[parentIndex]) {
|
||||
glm::quat combinedRotation = joint.preRotation * joint.rotation * joint.postRotation;
|
||||
transforms[i] = transforms[parentIndex] * glm::translate(joint.translation) * joint.preTransform *
|
||||
glm::mat4_cast(combinedRotation) * joint.postTransform;
|
||||
combinedRotations[i] = combinedRotations[parentIndex] * combinedRotation;
|
||||
++numShapesSet;
|
||||
shapeIsSet[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// joint shapes
|
||||
Extents totalExtents;
|
||||
|
@ -489,48 +525,70 @@ void Model::rebuildShapes() {
|
|||
for (int i = 0; i < _jointStates.size(); i++) {
|
||||
const FBXJoint& joint = geometry.joints[i];
|
||||
|
||||
glm::vec3 jointToShapeOffset = uniformScale * (_jointStates[i].combinedRotation * joint.shapePosition);
|
||||
glm::vec3 worldPosition = extractTranslation(_jointStates[i].transform) + jointToShapeOffset + _translation;
|
||||
glm::vec3 worldPosition = extractTranslation(transforms[i]);
|
||||
Extents shapeExtents;
|
||||
shapeExtents.reset();
|
||||
|
||||
if (joint.parentIndex == -1) {
|
||||
rootPosition = worldPosition;
|
||||
}
|
||||
|
||||
float radius = uniformScale * joint.boneRadius;
|
||||
float halfHeight = 0.5f * uniformScale * joint.distanceToParent;
|
||||
if (joint.shapeType == Shape::CAPSULE_SHAPE && halfHeight > EPSILON) {
|
||||
Shape::Type type = joint.shapeType;
|
||||
if (type == Shape::CAPSULE_SHAPE && halfHeight < EPSILON) {
|
||||
// this capsule is effectively a sphere
|
||||
type = Shape::SPHERE_SHAPE;
|
||||
}
|
||||
if (type == Shape::CAPSULE_SHAPE) {
|
||||
CapsuleShape* capsule = new CapsuleShape(radius, halfHeight);
|
||||
capsule->setPosition(worldPosition);
|
||||
capsule->setRotation(_jointStates[i].combinedRotation * joint.shapeRotation);
|
||||
capsule->setRotation(combinedRotations[i] * joint.shapeRotation);
|
||||
_jointShapes.push_back(capsule);
|
||||
|
||||
glm::vec3 endPoint;
|
||||
capsule->getEndPoint(endPoint);
|
||||
glm::vec3 startPoint;
|
||||
capsule->getStartPoint(startPoint);
|
||||
glm::vec3 axis = (halfHeight + radius) * glm::normalize(endPoint - startPoint);
|
||||
|
||||
// add some points that bound a sphere at the center of the capsule
|
||||
glm::vec3 axis = glm::vec3(radius);
|
||||
shapeExtents.addPoint(worldPosition + axis);
|
||||
shapeExtents.addPoint(worldPosition - axis);
|
||||
} else {
|
||||
|
||||
// add the two furthest surface points of the capsule
|
||||
axis = (halfHeight + radius) * glm::normalize(endPoint - startPoint);
|
||||
shapeExtents.addPoint(worldPosition + axis);
|
||||
shapeExtents.addPoint(worldPosition - axis);
|
||||
|
||||
totalExtents.addExtents(shapeExtents);
|
||||
} else if (type == Shape::SPHERE_SHAPE) {
|
||||
SphereShape* sphere = new SphereShape(radius, worldPosition);
|
||||
_jointShapes.push_back(sphere);
|
||||
|
||||
glm::vec3 axis = glm::vec3(radius);
|
||||
shapeExtents.addPoint(worldPosition + axis);
|
||||
shapeExtents.addPoint(worldPosition - axis);
|
||||
totalExtents.addExtents(shapeExtents);
|
||||
} else {
|
||||
// this shape type is not handled and the joint shouldn't collide,
|
||||
// however we must have a shape for each joint,
|
||||
// so we make a bogus sphere with zero radius.
|
||||
// TODO: implement collision groups for more control over what collides with what
|
||||
SphereShape* sphere = new SphereShape(0.f, worldPosition);
|
||||
_jointShapes.push_back(sphere);
|
||||
}
|
||||
totalExtents.addExtents(shapeExtents);
|
||||
}
|
||||
|
||||
// bounding shape
|
||||
// NOTE: we assume that the longest side of totalExtents is the yAxis
|
||||
glm::vec3 diagonal = totalExtents.maximum - totalExtents.minimum;
|
||||
float capsuleRadius = 0.25f * (diagonal.x + diagonal.z); // half the average of x and z
|
||||
// the radius is half the RMS of the X and Z sides:
|
||||
float capsuleRadius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z));
|
||||
_boundingShape.setRadius(capsuleRadius);
|
||||
_boundingShape.setHalfHeight(0.5f * diagonal.y - capsuleRadius);
|
||||
|
||||
glm::quat inverseRotation = glm::inverse(_rotation);
|
||||
glm::vec3 rootPosition = extractTranslation(transforms[rootIndex]);
|
||||
_boundingShapeLocalOffset = inverseRotation * (0.5f * (totalExtents.maximum + totalExtents.minimum) - rootPosition);
|
||||
_boundingShape.setPosition(_translation - _rotation * _boundingShapeLocalOffset);
|
||||
_boundingShape.setRotation(_rotation);
|
||||
}
|
||||
|
||||
void Model::updateShapePositions() {
|
||||
|
@ -557,6 +615,7 @@ void Model::updateShapePositions() {
|
|||
_boundingRadius = sqrtf(_boundingRadius);
|
||||
_shapesAreDirty = false;
|
||||
_boundingShape.setPosition(rootPosition + _rotation * _boundingShapeLocalOffset);
|
||||
_boundingShape.setRotation(_rotation);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ void ClipboardScriptingInterface::exportVoxel(float x, float y, float z, float s
|
|||
}
|
||||
|
||||
bool ClipboardScriptingInterface::importVoxels() {
|
||||
qDebug() << "[DEBUG] Importing ... ";
|
||||
qDebug() << "Importing ... ";
|
||||
QEventLoop loop;
|
||||
connect(Application::getInstance(), SIGNAL(importDone()), &loop, SLOT(quit()));
|
||||
emit readyToImport();
|
||||
|
|
|
@ -171,6 +171,9 @@ void Stats::display(
|
|||
|
||||
unsigned int backgroundColor = 0x33333399;
|
||||
int verticalOffset = 0, lines = 0;
|
||||
float scale = 0.10f;
|
||||
float rotation = 0.0f;
|
||||
int font = 2;
|
||||
|
||||
QLocale locale(QLocale::English);
|
||||
std::stringstream voxelStats;
|
||||
|
@ -198,11 +201,11 @@ void Stats::display(
|
|||
sprintf(framesPerSecond, "Framerate: %3.0f FPS", fps);
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, serverNodes, color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, serverNodes, color);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarNodes, color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarNodes, color);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, framesPerSecond, color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, framesPerSecond, color);
|
||||
|
||||
if (_expanded) {
|
||||
char packetsPerSecondString[30];
|
||||
|
@ -211,9 +214,9 @@ void Stats::display(
|
|||
sprintf(averageMegabitsPerSecond, "Mbps: %3.2f", (float)bytesPerSecond * 8.f / 1000000.f);
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, packetsPerSecondString, color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, packetsPerSecondString, color);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, averageMegabitsPerSecond, color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, averageMegabitsPerSecond, color);
|
||||
}
|
||||
|
||||
verticalOffset = 0;
|
||||
|
@ -258,7 +261,7 @@ void Stats::display(
|
|||
"Buffer msecs %.1f",
|
||||
(float) (audio->getNetworkBufferLengthSamplesPerChannel() + (float) audio->getJitterBufferSamples()) /
|
||||
(float) audio->getNetworkSampleRate() * 1000.f);
|
||||
drawText(30, glWidget->height() - 22, 0.10f, 0.f, 2.f, audioJitter, color);
|
||||
drawText(30, glWidget->height() - 22, scale, rotation, font, audioJitter, color);
|
||||
|
||||
|
||||
char audioPing[30];
|
||||
|
@ -271,18 +274,18 @@ void Stats::display(
|
|||
sprintf(voxelAvgPing, "Voxel avg ping: %d", pingVoxel);
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, audioPing, color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, audioPing, color);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarPing, color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarPing, color);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, voxelAvgPing, color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, voxelAvgPing, color);
|
||||
|
||||
if (_expanded) {
|
||||
char voxelMaxPing[30];
|
||||
sprintf(voxelMaxPing, "Voxel max ping: %d", pingVoxelMax);
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, voxelMaxPing, color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, voxelMaxPing, color);
|
||||
}
|
||||
|
||||
verticalOffset = 0;
|
||||
|
@ -306,11 +309,11 @@ void Stats::display(
|
|||
char avatarMixerStats[200];
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarPosition, color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarPosition, color);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarVelocity, color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarVelocity, color);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarBodyYaw, color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarBodyYaw, color);
|
||||
|
||||
if (_expanded) {
|
||||
SharedNodePointer avatarMixer = NodeList::getInstance()->soloNodeOfType(NodeType::AvatarMixer);
|
||||
|
@ -323,7 +326,7 @@ void Stats::display(
|
|||
}
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarMixerStats, color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarMixerStats, color);
|
||||
|
||||
stringstream downloads;
|
||||
downloads << "Downloads: ";
|
||||
|
@ -333,7 +336,7 @@ void Stats::display(
|
|||
downloads << "(" << ResourceCache::getPendingRequestCount() << " pending)";
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, downloads.str().c_str(), color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, downloads.str().c_str(), color);
|
||||
}
|
||||
|
||||
verticalOffset = 0;
|
||||
|
@ -354,7 +357,7 @@ void Stats::display(
|
|||
voxelStats.str("");
|
||||
voxelStats << "Voxels Memory Nodes: " << VoxelTreeElement::getTotalMemoryUsage() / 1000000.f << "MB";
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color);
|
||||
|
||||
voxelStats.str("");
|
||||
voxelStats <<
|
||||
|
@ -364,14 +367,14 @@ void Stats::display(
|
|||
voxelStats << " / GPU: " << voxels->getVoxelMemoryUsageGPU() / 1000000.f << "MB";
|
||||
}
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color);
|
||||
|
||||
// Voxel Rendering
|
||||
voxelStats.str("");
|
||||
voxelStats.precision(4);
|
||||
voxelStats << "Voxel Rendering Slots Max: " << voxels->getMaxVoxels() / 1000.f << "K";
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color);
|
||||
}
|
||||
|
||||
voxelStats.str("");
|
||||
|
@ -379,7 +382,7 @@ void Stats::display(
|
|||
voxelStats << "Drawn: " << voxels->getVoxelsWritten() / 1000.f << "K " <<
|
||||
"Abandoned: " << voxels->getAbandonedVoxels() / 1000.f << "K ";
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color);
|
||||
|
||||
// iterate all the current voxel stats, and list their sending modes, and total voxel counts
|
||||
std::stringstream sendingMode("");
|
||||
|
@ -424,7 +427,7 @@ void Stats::display(
|
|||
sendingMode << " <SCENE STABLE>";
|
||||
}
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)sendingMode.str().c_str(), color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)sendingMode.str().c_str(), color);
|
||||
}
|
||||
|
||||
// Incoming packets
|
||||
|
@ -435,7 +438,7 @@ void Stats::display(
|
|||
voxelStats << "Voxel Packets to Process: " << qPrintable(packetsString)
|
||||
<< " [Recent Max: " << qPrintable(maxString) << "]";
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color);
|
||||
}
|
||||
|
||||
if (_resetRecentMaxPacketsSoon && voxelPacketsToProcess > 0) {
|
||||
|
@ -458,7 +461,7 @@ void Stats::display(
|
|||
voxelStats.str("");
|
||||
voxelStats << "Server voxels: " << qPrintable(serversTotalString);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color);
|
||||
|
||||
if (_expanded) {
|
||||
QString serversInternalString = locale.toString((uint)totalInternal);
|
||||
|
@ -469,7 +472,7 @@ void Stats::display(
|
|||
"Internal: " << qPrintable(serversInternalString) << " " <<
|
||||
"Leaves: " << qPrintable(serversLeavesString) << "";
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color);
|
||||
}
|
||||
|
||||
unsigned long localTotal = VoxelTreeElement::getNodeCount();
|
||||
|
@ -479,7 +482,7 @@ void Stats::display(
|
|||
voxelStats.str("");
|
||||
voxelStats << "Local voxels: " << qPrintable(localTotalString);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color);
|
||||
|
||||
if (_expanded) {
|
||||
unsigned long localInternal = VoxelTreeElement::getInternalNodeCount();
|
||||
|
@ -492,7 +495,7 @@ void Stats::display(
|
|||
"Internal: " << qPrintable(localInternalString) << " " <<
|
||||
"Leaves: " << qPrintable(localLeavesString) << "";
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color);
|
||||
}
|
||||
|
||||
// LOD Details
|
||||
|
@ -501,7 +504,7 @@ void Stats::display(
|
|||
QString displayLODDetails = Menu::getInstance()->getLODFeedbackText();
|
||||
voxelStats << "LOD: You can see " << qPrintable(displayLODDetails.trimmed());
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color);
|
||||
}
|
||||
|
||||
|
||||
|
@ -526,7 +529,7 @@ void Stats::display(
|
|||
);
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, reflectionsStatus, color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, reflectionsStatus, color);
|
||||
|
||||
float preDelay = Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingPreDelay) ?
|
||||
audioReflector->getPreDelay() : 0.0f;
|
||||
|
@ -539,14 +542,15 @@ void Stats::display(
|
|||
audioReflector->getSoundMsPerMeter());
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, reflectionsStatus, color);
|
||||
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, reflectionsStatus, color);
|
||||
|
||||
bool distanceAttenuationDisabled = Menu::getInstance()->isOptionChecked(
|
||||
MenuOption::AudioSpatialProcessingDontDistanceAttenuate);
|
||||
|
||||
bool alternateDistanceAttenuationEnabled = Menu::getInstance()->isOptionChecked(
|
||||
MenuOption::AudioSpatialProcessingAlternateDistanceAttenuate);
|
||||
|
||||
|
||||
sprintf(reflectionsStatus, "Attenuation: average %5.3f, max %5.3f, min %5.3f, %s: %5.3f",
|
||||
audioReflector->getAverageAttenuation(),
|
||||
audioReflector->getMaxAttenuation(),
|
||||
|
@ -556,7 +560,7 @@ void Stats::display(
|
|||
audioReflector->getDistanceAttenuationScalingFactor());
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, reflectionsStatus, color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, reflectionsStatus, color);
|
||||
|
||||
sprintf(reflectionsStatus, "Local Audio: %s Attenuation: %5.3f",
|
||||
(Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingProcessLocalAudio)
|
||||
|
@ -564,7 +568,7 @@ void Stats::display(
|
|||
audioReflector->getLocalAudioAttenuationFactor());
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, reflectionsStatus, color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, reflectionsStatus, color);
|
||||
|
||||
bool diffusionEnabled = Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingWithDiffusions);
|
||||
int fanout = diffusionEnabled ? audioReflector->getDiffusionFanout() : 0;
|
||||
|
@ -573,7 +577,7 @@ void Stats::display(
|
|||
(diffusionEnabled ? "yes" : "no"), fanout, diffusionPaths);
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, reflectionsStatus, color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, reflectionsStatus, color);
|
||||
|
||||
const float AS_PERCENT = 100.0f;
|
||||
float reflectiveRatio = audioReflector->getReflectiveRatio() * AS_PERCENT;
|
||||
|
@ -583,7 +587,7 @@ void Stats::display(
|
|||
reflectiveRatio, diffusionRatio, absorptionRatio);
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, reflectionsStatus, color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, reflectionsStatus, color);
|
||||
|
||||
sprintf(reflectionsStatus, "Comb Filter Window: %5.3f ms, Allowed: %d, Suppressed: %d",
|
||||
audioReflector->getCombFilterWindow(),
|
||||
|
@ -591,7 +595,7 @@ void Stats::display(
|
|||
audioReflector->getEchoesSuppressed());
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, reflectionsStatus, color);
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, reflectionsStatus, color);
|
||||
|
||||
sprintf(reflectionsStatus, "Wet/Dry Mix: Original: %5.3f Echoes: %5.3f",
|
||||
audioReflector->getOriginalSourceAttenuation(),
|
||||
|
|
|
@ -40,6 +40,7 @@ void Cube3DOverlay::render() {
|
|||
if (_isSolid) {
|
||||
glutSolidCube(_size);
|
||||
} else {
|
||||
glLineWidth(_lineWidth);
|
||||
glutWireCube(_size);
|
||||
}
|
||||
glPopMatrix();
|
||||
|
|
|
@ -67,21 +67,25 @@ Sound::Sound(float volume, float frequency, float duration, float decay, QObject
|
|||
}
|
||||
|
||||
Sound::Sound(const QUrl& sampleURL, QObject* parent) :
|
||||
QObject(parent)
|
||||
QObject(parent),
|
||||
_hasDownloaded(false)
|
||||
{
|
||||
// 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);
|
||||
connect(manager, SIGNAL(finished(QNetworkReply*)),
|
||||
this, SLOT(replyFinished(QNetworkReply*)));
|
||||
|
||||
qDebug() << "Requesting audio file" << sampleURL.toDisplayString();
|
||||
manager->get(QNetworkRequest(sampleURL));
|
||||
|
||||
QNetworkReply* soundDownload = manager->get(QNetworkRequest(sampleURL));
|
||||
connect(soundDownload, &QNetworkReply::finished, this, &Sound::replyFinished);
|
||||
connect(soundDownload, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(replyError(QNetworkReply::NetworkError)));
|
||||
}
|
||||
|
||||
void Sound::replyFinished(QNetworkReply* reply) {
|
||||
void Sound::replyFinished() {
|
||||
|
||||
QNetworkReply* reply = reinterpret_cast<QNetworkReply*>(sender());
|
||||
|
||||
// replace our byte array with the downloaded data
|
||||
QByteArray rawAudioByteArray = reply->readAll();
|
||||
|
||||
|
@ -108,6 +112,13 @@ void Sound::replyFinished(QNetworkReply* reply) {
|
|||
} else {
|
||||
qDebug() << "Network reply without 'Content-Type'.";
|
||||
}
|
||||
|
||||
_hasDownloaded = true;
|
||||
}
|
||||
|
||||
void Sound::replyError(QNetworkReply::NetworkError code) {
|
||||
QNetworkReply* reply = reinterpret_cast<QNetworkReply*>(sender());
|
||||
qDebug() << "Error downloading sound file at" << reply->url().toString() << "-" << reply->errorString();
|
||||
}
|
||||
|
||||
void Sound::downSample(const QByteArray& rawAudioByteArray) {
|
||||
|
|
|
@ -13,25 +13,30 @@
|
|||
#define hifi_Sound_h
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
class QNetworkReply;
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
||||
class Sound : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool downloaded READ hasDownloaded)
|
||||
public:
|
||||
Sound(const QUrl& sampleURL, QObject* parent = NULL);
|
||||
Sound(float volume, float frequency, float duration, float decay, QObject* parent = NULL);
|
||||
|
||||
bool hasDownloaded() const { return _hasDownloaded; }
|
||||
|
||||
const QByteArray& getByteArray() { return _byteArray; }
|
||||
|
||||
private:
|
||||
QByteArray _byteArray;
|
||||
|
||||
bool _hasDownloaded;
|
||||
|
||||
void downSample(const QByteArray& rawAudioByteArray);
|
||||
void interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray);
|
||||
|
||||
private slots:
|
||||
void replyFinished(QNetworkReply* reply);
|
||||
void replyFinished();
|
||||
void replyError(QNetworkReply::NetworkError code);
|
||||
};
|
||||
|
||||
#endif // hifi_Sound_h
|
||||
|
|
|
@ -97,13 +97,14 @@ class AvatarData : public QObject {
|
|||
Q_PROPERTY(float audioLoudness READ getAudioLoudness WRITE setAudioLoudness)
|
||||
Q_PROPERTY(float audioAverageLoudness READ getAudioAverageLoudness WRITE setAudioAverageLoudness)
|
||||
|
||||
Q_PROPERTY(QString displayName READ getDisplayName WRITE setDisplayName)
|
||||
Q_PROPERTY(QString faceModelURL READ getFaceModelURLFromScript WRITE setFaceModelURLFromScript)
|
||||
Q_PROPERTY(QString skeletonModelURL READ getSkeletonModelURLFromScript WRITE setSkeletonModelURLFromScript)
|
||||
Q_PROPERTY(QString billboardURL READ getBillboardURL WRITE setBillboardFromURL)
|
||||
|
||||
Q_PROPERTY(QStringList jointNames READ getJointNames)
|
||||
|
||||
Q_PROPERTY(QUuid sessionUUID READ getSessionUUID);
|
||||
Q_PROPERTY(QUuid sessionUUID READ getSessionUUID)
|
||||
public:
|
||||
AvatarData();
|
||||
virtual ~AvatarData();
|
||||
|
|
|
@ -1624,7 +1624,6 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
}
|
||||
float radiusScale = extractUniformScale(joint.transform * fbxCluster.inverseBindMatrix);
|
||||
JointShapeInfo& jointShapeInfo = jointShapeInfos[jointIndex];
|
||||
jointShapeInfo.boneBegin = rotateMeshToJoint * (radiusScale * (boneBegin - boneEnd));
|
||||
|
||||
float totalWeight = 0.0f;
|
||||
for (int j = 0; j < cluster.indices.size(); j++) {
|
||||
|
@ -1686,7 +1685,6 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
}
|
||||
}
|
||||
float radiusScale = extractUniformScale(joint.transform * firstFBXCluster.inverseBindMatrix);
|
||||
jointShapeInfo.boneBegin = rotateMeshToJoint * (radiusScale * (boneBegin - boneEnd));
|
||||
|
||||
glm::vec3 averageVertex(0.f);
|
||||
foreach (const glm::vec3& vertex, extracted.mesh.vertices) {
|
||||
|
@ -1722,6 +1720,14 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
FBXJoint& joint = geometry.joints[i];
|
||||
JointShapeInfo& jointShapeInfo = jointShapeInfos[i];
|
||||
|
||||
if (joint.parentIndex == -1) {
|
||||
jointShapeInfo.boneBegin = glm::vec3(0.0f);
|
||||
} else {
|
||||
const FBXJoint& parentJoint = geometry.joints[joint.parentIndex];
|
||||
glm::quat inverseRotation = glm::inverse(extractRotation(joint.transform));
|
||||
jointShapeInfo.boneBegin = inverseRotation * (extractTranslation(parentJoint.transform) - extractTranslation(joint.transform));
|
||||
}
|
||||
|
||||
// we use a capsule if the joint ANY mesh vertices successfully projected onto the bone
|
||||
// AND its boneRadius is not too close to zero
|
||||
bool collideLikeCapsule = jointShapeInfo.numProjectedVertices > 0
|
||||
|
@ -1733,12 +1739,12 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
joint.shapeType = Shape::CAPSULE_SHAPE;
|
||||
} else {
|
||||
// collide the joint like a sphere
|
||||
joint.shapeType = Shape::SPHERE_SHAPE;
|
||||
if (jointShapeInfo.numVertices > 0) {
|
||||
jointShapeInfo.averageVertex /= (float)jointShapeInfo.numVertices;
|
||||
joint.shapePosition = jointShapeInfo.averageVertex;
|
||||
} else {
|
||||
joint.shapePosition = glm::vec3(0.f);
|
||||
joint.shapeType = Shape::SPHERE_SHAPE;
|
||||
}
|
||||
if (jointShapeInfo.numProjectedVertices == 0
|
||||
&& jointShapeInfo.numVertices > 0) {
|
||||
|
@ -1747,6 +1753,15 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
jointShapeInfo.averageRadius /= (float)jointShapeInfo.numVertices;
|
||||
joint.boneRadius = jointShapeInfo.averageRadius;
|
||||
}
|
||||
|
||||
float distanceFromEnd = glm::length(joint.shapePosition);
|
||||
float distanceFromBegin = glm::distance(joint.shapePosition, jointShapeInfo.boneBegin);
|
||||
if (distanceFromEnd > joint.distanceToParent && distanceFromBegin > joint.distanceToParent) {
|
||||
// The shape is further from both joint endpoints than the endpoints are from each other
|
||||
// which probably means the model has a bad transform somewhere. We disable this shape
|
||||
// by setting its type to UNKNOWN_SHAPE.
|
||||
joint.shapeType = Shape::UNKNOWN_SHAPE;
|
||||
}
|
||||
}
|
||||
}
|
||||
geometry.palmDirection = parseVec3(mapping.value("palmDirection", "0, -1, 0").toString());
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include <QVariant>
|
||||
#include <QVector>
|
||||
|
||||
#include <Shape.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
|
@ -91,7 +93,7 @@ public:
|
|||
QString name;
|
||||
glm::vec3 shapePosition; // in joint frame
|
||||
glm::quat shapeRotation; // in joint frame
|
||||
int shapeType;
|
||||
Shape::Type shapeType;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -36,6 +36,9 @@ public:
|
|||
void setUndoStack(QUndoStack* undoStack) { _undoStack = undoStack; }
|
||||
|
||||
public slots:
|
||||
|
||||
/// provide the world scale
|
||||
const int getTreeScale() const { return TREE_SCALE; }
|
||||
|
||||
/// checks the local voxel tree for a voxel at the specified location and scale
|
||||
/// \param x the x-coordinate of the voxel (in meter units)
|
||||
|
|
Loading…
Reference in a new issue