mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-07 18:21:17 +02:00
Merge remote-tracking branch 'upstream/master' into 19489
This commit is contained in:
commit
59f8851b50
15 changed files with 234 additions and 27 deletions
68
examples/audioBall.js
Normal file
68
examples/audioBall.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
// audioBall.js
|
||||
// hifi
|
||||
//
|
||||
// Created by Athanasios Gaitatzes on 2/10/14.
|
||||
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||
//
|
||||
// This script creates a particle in front of the user that stays in front of
|
||||
// the user's avatar as they move, and animates it's radius and color
|
||||
// in response to the audio intensity.
|
||||
//
|
||||
|
||||
var sound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Animals/mexicanWhipoorwill.raw");
|
||||
var CHANCE_OF_PLAYING_SOUND = 0.01;
|
||||
|
||||
var FACTOR = 0.75;
|
||||
|
||||
var countParticles = 0; // the first time around we want to create the particle and thereafter to modify it.
|
||||
var particleID;
|
||||
|
||||
function updateParticle() {
|
||||
// the particle should be placed in front of the user's avatar
|
||||
var avatarFront = Quat.getFront(MyAvatar.orientation);
|
||||
|
||||
// move particle three units in front of the avatar
|
||||
var particlePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(avatarFront, 3));
|
||||
|
||||
if (Math.random() < CHANCE_OF_PLAYING_SOUND) {
|
||||
// play a sound at the location of the particle
|
||||
var options = new AudioInjectionOptions();
|
||||
options.position = particlePosition;
|
||||
options.volume = 0.75;
|
||||
Audio.playSound(sound, options);
|
||||
}
|
||||
|
||||
var audioAverageLoudness = MyAvatar.audioAverageLoudness * FACTOR;
|
||||
//print ("Audio Loudness = " + MyAvatar.audioLoudness + " -- Audio Average Loudness = " + MyAvatar.audioAverageLoudness);
|
||||
|
||||
if (countParticles < 1) {
|
||||
var particleProperies = {
|
||||
position: particlePosition // the particle should stay in front of the user's avatar as he moves
|
||||
, color: { red: 0, green: 255, blue: 0 }
|
||||
, radius: audioAverageLoudness
|
||||
, velocity: { x: 0.0, y: 0.0, z: 0.0 }
|
||||
, gravity: { x: 0.0, y: 0.0, z: 0.0 }
|
||||
, damping: 0.0
|
||||
}
|
||||
|
||||
particleID = Particles.addParticle (particleProperies);
|
||||
countParticles++;
|
||||
}
|
||||
else {
|
||||
// animates the particles radius and color in response to the changing audio intensity
|
||||
var newProperties = {
|
||||
position: particlePosition // the particle should stay in front of the user's avatar as he moves
|
||||
, color: { red: 0, green: 255 * audioAverageLoudness, blue: 0 }
|
||||
, radius: audioAverageLoudness
|
||||
};
|
||||
|
||||
Particles.editParticle (particleID, newProperties);
|
||||
}
|
||||
}
|
||||
|
||||
// register the call back so it fires before each data send
|
||||
Script.willSendVisualDataCallback.connect(updateParticle);
|
||||
|
||||
// register our scriptEnding callback
|
||||
Script.scriptEnding.connect(function scriptEnding() {});
|
|
@ -48,6 +48,8 @@
|
|||
#include <QXmlStreamReader>
|
||||
#include <QXmlStreamAttributes>
|
||||
#include <QMediaPlayer>
|
||||
#include <QMimeData>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <AudioInjector.h>
|
||||
#include <Logging.h>
|
||||
|
@ -199,7 +201,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
connect(audioThread, SIGNAL(started()), &_audio, SLOT(start()));
|
||||
|
||||
audioThread->start();
|
||||
|
||||
|
||||
connect(nodeList, SIGNAL(domainChanged(const QString&)), SLOT(domainChanged(const QString&)));
|
||||
connect(nodeList, &NodeList::nodeAdded, this, &Application::nodeAdded);
|
||||
connect(nodeList, &NodeList::nodeKilled, this, &Application::nodeKilled);
|
||||
|
@ -1418,6 +1420,32 @@ void Application::wheelEvent(QWheelEvent* event) {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::dropEvent(QDropEvent *event) {
|
||||
QString snapshotPath;
|
||||
const QMimeData *mimeData = event->mimeData();
|
||||
foreach (QUrl url, mimeData->urls()) {
|
||||
if (url.url().toLower().endsWith(SNAPSHOT_EXTENSION)) {
|
||||
snapshotPath = url.url().remove("file://");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SnapshotMetaData* snapshotData = Snapshot::parseSnapshotData(snapshotPath);
|
||||
if (snapshotData != NULL) {
|
||||
if (!snapshotData->getDomain().isEmpty()) {
|
||||
Menu::getInstance()->goToDomain(snapshotData->getDomain());
|
||||
}
|
||||
|
||||
_myAvatar->setPosition(snapshotData->getLocation());
|
||||
_myAvatar->setOrientation(snapshotData->getOrientation());
|
||||
} else {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText("No location details were found in this JPG, try dragging in an authentic Hifi snapshot.");
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.exec();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::sendPingPackets() {
|
||||
QByteArray pingPacket = NodeList::getInstance()->constructPingPacket();
|
||||
controlledBroadcastToNodes(pingPacket, NodeSet() << NodeType::VoxelServer
|
||||
|
@ -3842,7 +3870,7 @@ void Application::updateWindowTitle(){
|
|||
|
||||
QString title = QString() + _profile.getUsername() + " " + nodeList->getSessionUUID().toString()
|
||||
+ " @ " + nodeList->getDomainHostname() + buildVersion;
|
||||
|
||||
|
||||
qDebug("Application title set to: %s", title.toStdString().c_str());
|
||||
_window->setWindowTitle(title);
|
||||
}
|
||||
|
@ -4246,6 +4274,6 @@ void Application::takeSnapshot() {
|
|||
player->setMedia(QUrl::fromLocalFile(inf.absoluteFilePath()));
|
||||
player->play();
|
||||
|
||||
Snapshot::saveSnapshot(_glWidget, _profile.getUsername(), _myAvatar->getPosition());
|
||||
Snapshot::saveSnapshot(_glWidget, &_profile, _myAvatar);
|
||||
}
|
||||
|
||||
|
|
|
@ -93,6 +93,8 @@ static const float NODE_KILLED_RED = 1.0f;
|
|||
static const float NODE_KILLED_GREEN = 0.0f;
|
||||
static const float NODE_KILLED_BLUE = 0.0f;
|
||||
|
||||
static const QString SNAPSHOT_EXTENSION = ".jpg";
|
||||
|
||||
class Application : public QApplication {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -127,6 +129,7 @@ public:
|
|||
void touchUpdateEvent(QTouchEvent* event);
|
||||
|
||||
void wheelEvent(QWheelEvent* event);
|
||||
void dropEvent(QDropEvent *event);
|
||||
|
||||
bool event(QEvent* event);
|
||||
|
||||
|
|
|
@ -46,7 +46,8 @@ public:
|
|||
void render(int screenWidth, int screenHeight);
|
||||
|
||||
float getLastInputLoudness() const { return glm::max(_lastInputLoudness - _noiseGateMeasuredFloor, 0.f); }
|
||||
|
||||
float getAudioAverageInputLoudness() const { return _lastInputLoudness; }
|
||||
|
||||
void setNoiseGateEnabled(bool noiseGateEnabled) { _noiseGateEnabled = noiseGateEnabled; }
|
||||
|
||||
void setLastAcceleration(const glm::vec3 lastAcceleration) { _lastAcceleration = lastAcceleration; }
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include "Application.h"
|
||||
|
||||
#include "GLCanvas.h"
|
||||
#include <QMimeData>
|
||||
#include <QUrl>
|
||||
|
||||
GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer, QGL::NoStencilBuffer)) {
|
||||
}
|
||||
|
@ -16,6 +18,7 @@ GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer, QGL::NoStencilBuf
|
|||
void GLCanvas::initializeGL() {
|
||||
Application::getInstance()->initializeGL();
|
||||
setAttribute(Qt::WA_AcceptTouchEvents);
|
||||
setAcceptDrops(true);
|
||||
}
|
||||
|
||||
void GLCanvas::paintGL() {
|
||||
|
@ -67,4 +70,18 @@ bool GLCanvas::event(QEvent* event) {
|
|||
|
||||
void GLCanvas::wheelEvent(QWheelEvent* event) {
|
||||
Application::getInstance()->wheelEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void GLCanvas::dragEnterEvent(QDragEnterEvent* event) {
|
||||
const QMimeData *mimeData = event->mimeData();
|
||||
foreach (QUrl url, mimeData->urls()) {
|
||||
if (url.url().toLower().endsWith(SNAPSHOT_EXTENSION)) {
|
||||
event->acceptProposedAction();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLCanvas::dropEvent(QDropEvent* event) {
|
||||
Application::getInstance()->dropEvent(event);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,9 @@ protected:
|
|||
virtual bool event(QEvent* event);
|
||||
|
||||
virtual void wheelEvent(QWheelEvent* event);
|
||||
|
||||
virtual void dragEnterEvent(QDragEnterEvent *event);
|
||||
virtual void dropEvent(QDropEvent* event);
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__GLCanvas__) */
|
||||
|
|
|
@ -112,7 +112,7 @@ Menu::Menu() :
|
|||
MenuOption::GoToDomain,
|
||||
Qt::CTRL | Qt::Key_D,
|
||||
this,
|
||||
SLOT(goToDomain()));
|
||||
SLOT(goToDomainDialog()));
|
||||
addActionToQMenuAndActionHash(fileMenu,
|
||||
MenuOption::GoToLocation,
|
||||
Qt::CTRL | Qt::SHIFT | Qt::Key_L,
|
||||
|
@ -909,7 +909,7 @@ void Menu::goToDomain(const QString newDomain) {
|
|||
}
|
||||
}
|
||||
|
||||
void Menu::goToDomain() {
|
||||
void Menu::goToDomainDialog() {
|
||||
|
||||
QString currentDomainHostname = NodeList::getInstance()->getDomainHostname();
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ private slots:
|
|||
void aboutApp();
|
||||
void login();
|
||||
void editPreferences();
|
||||
void goToDomain();
|
||||
void goToDomainDialog();
|
||||
void goToLocation();
|
||||
void bandwidthDetailsClosed();
|
||||
void voxelStatsDetailsClosed();
|
||||
|
|
|
@ -141,7 +141,9 @@ void MyAvatar::update(float deltaTime) {
|
|||
}
|
||||
|
||||
// Get audio loudness data from audio input device
|
||||
_head.setAudioLoudness(Application::getInstance()->getAudio()->getLastInputLoudness());
|
||||
Audio* audio = Application::getInstance()->getAudio();
|
||||
_head.setAudioLoudness(audio->getLastInputLoudness());
|
||||
_head.setAudioAverageLoudness(audio->getAudioAverageInputLoudness());
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Gravity)) {
|
||||
setGravity(Application::getInstance()->getEnvironment()->getGravity(getPosition()));
|
||||
|
@ -609,7 +611,7 @@ void MyAvatar::loadData(QSettings* settings) {
|
|||
_position.y = loadSetting(settings, "position_y", 0.0f);
|
||||
_position.z = loadSetting(settings, "position_z", 0.0f);
|
||||
|
||||
_head.setPupilDilation(settings->value("pupilDilation", 0.0f).toFloat());
|
||||
_head.setPupilDilation(loadSetting(settings, "pupilDilation", 0.0f));
|
||||
|
||||
_leanScale = loadSetting(settings, "leanScale", 0.05f);
|
||||
_targetScale = loadSetting(settings, "scale", 1.0f);
|
||||
|
|
|
@ -45,5 +45,6 @@ private:
|
|||
TouchState _touchState;
|
||||
timeval* _lastReceivedPacket;
|
||||
|
||||
#endif /* defined(__hifi__Transmitter__) */
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__Transmitter__) */
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
#include <QDateTime>
|
||||
#include <QFileInfo>
|
||||
#include <QDebug>
|
||||
|
||||
// filename format: hifi-snap-by-%username%-on-%date%_%time%_@-%location%.jpg
|
||||
// %1 <= username, %2 <= date and time, %3 <= current location
|
||||
|
@ -21,18 +20,69 @@ const QString FILENAME_PATH_FORMAT = "hifi-snap-by-%1-on-%2@%3.jpg";
|
|||
const QString DATETIME_FORMAT = "yyyy-MM-dd_hh-mm-ss";
|
||||
const QString SNAPSHOTS_DIRECTORY = "Snapshots";
|
||||
|
||||
void Snapshot::saveSnapshot(QGLWidget* widget, QString username, glm::vec3 location) {
|
||||
QImage shot = widget->grabFrameBuffer();
|
||||
const QString LOCATION_X = "location-x";
|
||||
const QString LOCATION_Y = "location-y";
|
||||
const QString LOCATION_Z = "location-z";
|
||||
|
||||
const QString ORIENTATION_X = "orientation-x";
|
||||
const QString ORIENTATION_Y = "orientation-y";
|
||||
const QString ORIENTATION_Z = "orientation-z";
|
||||
const QString ORIENTATION_W = "orientation-w";
|
||||
|
||||
const QString DOMAIN_KEY = "domain";
|
||||
|
||||
|
||||
SnapshotMetaData* Snapshot::parseSnapshotData(QString snapshotPath) {
|
||||
|
||||
if (!QFile(snapshotPath).exists()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QImage shot(snapshotPath);
|
||||
|
||||
// no location data stored
|
||||
if (shot.text(LOCATION_X).isEmpty() || shot.text(LOCATION_Y).isEmpty() || shot.text(LOCATION_Z).isEmpty()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SnapshotMetaData* data = new SnapshotMetaData();
|
||||
data->setLocation(glm::vec3(shot.text(LOCATION_X).toFloat(),
|
||||
shot.text(LOCATION_Y).toFloat(),
|
||||
shot.text(LOCATION_Z).toFloat()));
|
||||
|
||||
data->setOrientation(glm::quat(shot.text(ORIENTATION_W).toFloat(),
|
||||
shot.text(ORIENTATION_X).toFloat(),
|
||||
shot.text(ORIENTATION_Y).toFloat(),
|
||||
shot.text(ORIENTATION_Z).toFloat()));
|
||||
|
||||
data->setDomain(shot.text(DOMAIN_KEY));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void Snapshot::saveSnapshot(QGLWidget* widget, Profile* profile, Avatar* avatar) {
|
||||
QImage shot = widget->grabFrameBuffer();
|
||||
|
||||
glm::vec3 location = avatar->getPosition();
|
||||
glm::quat orientation = avatar->getHead().getOrientation();
|
||||
|
||||
// add metadata
|
||||
shot.setText("location-x", QString::number(location.x));
|
||||
shot.setText("location-y", QString::number(location.y));
|
||||
shot.setText("location-z", QString::number(location.z));
|
||||
shot.setText(LOCATION_X, QString::number(location.x));
|
||||
shot.setText(LOCATION_Y, QString::number(location.y));
|
||||
shot.setText(LOCATION_Z, QString::number(location.z));
|
||||
|
||||
shot.setText(ORIENTATION_X, QString::number(orientation.x));
|
||||
shot.setText(ORIENTATION_Y, QString::number(orientation.y));
|
||||
shot.setText(ORIENTATION_Z, QString::number(orientation.z));
|
||||
shot.setText(ORIENTATION_W, QString::number(orientation.w));
|
||||
|
||||
shot.setText(DOMAIN_KEY, profile->getLastDomain());
|
||||
|
||||
QString formattedLocation = QString("%1_%2_%3").arg(location.x).arg(location.y).arg(location.z);
|
||||
// replace decimal . with '-'
|
||||
formattedLocation.replace('.', '-');
|
||||
|
||||
QString username = profile->getUsername();
|
||||
// normalize username, replace all non alphanumeric with '-'
|
||||
username.replace(QRegExp("[^A-Za-z0-9_]"), "-");
|
||||
|
||||
|
|
|
@ -9,19 +9,38 @@
|
|||
#ifndef __hifi__Snapshot__
|
||||
#define __hifi__Snapshot__
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QImage>
|
||||
#include <QGLWidget>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include "avatar/Avatar.h"
|
||||
#include "avatar/Profile.h"
|
||||
|
||||
class SnapshotMetaData {
|
||||
public:
|
||||
|
||||
QString getDomain() { return _domain; }
|
||||
void setDomain(QString domain) { _domain = domain; }
|
||||
|
||||
glm::vec3 getLocation() { return _location; }
|
||||
void setLocation(glm::vec3 location) { _location = location; }
|
||||
|
||||
glm::quat getOrientation() { return _orientation; }
|
||||
void setOrientation(glm::quat orientation) { _orientation = orientation; }
|
||||
|
||||
private:
|
||||
QString _domain;
|
||||
glm::vec3 _location;
|
||||
glm::quat _orientation;;
|
||||
};
|
||||
|
||||
class Snapshot {
|
||||
|
||||
public:
|
||||
static void saveSnapshot(QGLWidget* widget, QString username, glm::vec3 location);
|
||||
|
||||
private:
|
||||
QString _username;
|
||||
static void saveSnapshot(QGLWidget* widget, Profile* profile, Avatar* avatar);
|
||||
static SnapshotMetaData* parseSnapshotData(QString snapshotPath);
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__Snapshot__) */
|
||||
|
|
|
@ -76,7 +76,10 @@ class AvatarData : public NodeData {
|
|||
|
||||
Q_PROPERTY(glm::quat orientation READ getOrientation WRITE setOrientation)
|
||||
Q_PROPERTY(float headPitch READ getHeadPitch WRITE setHeadPitch)
|
||||
|
||||
|
||||
Q_PROPERTY(float audioLoudness READ getAudioLoudness WRITE setAudioLoudness)
|
||||
Q_PROPERTY(float audioAverageLoudness READ getAudioAverageLoudness WRITE setAudioAverageLoudness)
|
||||
|
||||
Q_PROPERTY(QUrl faceModelURL READ getFaceModelURL WRITE setFaceModelURL)
|
||||
Q_PROPERTY(QUrl skeletonModelURL READ getSkeletonModelURL WRITE setSkeletonModelURL)
|
||||
public:
|
||||
|
@ -107,6 +110,12 @@ public:
|
|||
float getHeadPitch() const { return _headData->getPitch(); }
|
||||
void setHeadPitch(float value) { _headData->setPitch(value); };
|
||||
|
||||
// access to Head().set/getAverageLoudness
|
||||
float getAudioLoudness() const { return _headData->getAudioLoudness(); }
|
||||
void setAudioLoudness(float value) { _headData->setAudioLoudness(value); }
|
||||
float getAudioAverageLoudness() const { return _headData->getAudioAverageLoudness(); }
|
||||
void setAudioAverageLoudness(float value) { _headData->setAudioAverageLoudness(value); }
|
||||
|
||||
// Scale
|
||||
float getTargetScale() const { return _targetScale; }
|
||||
void setTargetScale(float targetScale) { _targetScale = targetScale; }
|
||||
|
|
|
@ -41,9 +41,13 @@ public:
|
|||
|
||||
float getRoll() const { return _roll; }
|
||||
void setRoll(float roll) { _roll = glm::clamp(roll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); }
|
||||
|
||||
void setAudioLoudness(float audioLoudness) { _audioLoudness = audioLoudness; }
|
||||
|
||||
|
||||
float getAudioLoudness() const { return _audioLoudness; }
|
||||
void setAudioLoudness(float audioLoudness) { _audioLoudness = audioLoudness; }
|
||||
|
||||
float getAudioAverageLoudness() const { return _audioAverageLoudness; }
|
||||
void setAudioAverageLoudness(float audioAverageLoudness) { _audioAverageLoudness = audioAverageLoudness; }
|
||||
|
||||
const std::vector<float>& getBlendshapeCoefficients() const { return _blendshapeCoefficients; }
|
||||
|
||||
float getPupilDilation() const { return _pupilDilation; }
|
||||
|
@ -72,6 +76,7 @@ protected:
|
|||
float _rightEyeBlink;
|
||||
float _averageLoudness;
|
||||
float _browAudioLift;
|
||||
float _audioAverageLoudness;
|
||||
std::vector<float> _blendshapeCoefficients;
|
||||
float _pupilDilation;
|
||||
AvatarData* _owningAvatar;
|
||||
|
|
|
@ -807,7 +807,8 @@ void NodeList::loadData(QSettings *settings) {
|
|||
} else {
|
||||
_domainHostname = DEFAULT_DOMAIN_HOSTNAME;
|
||||
}
|
||||
|
||||
|
||||
emit domainChanged(_domainHostname);
|
||||
settings->endGroup();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue