From 01a3eaa26baf4ddc894d3b1f047bf4f4b52ce02f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sun, 5 Oct 2014 19:10:55 -0700 Subject: [PATCH 001/119] added experimental MyAvatar.setSkeletonOffset() for improved walk animations --- interface/src/avatar/Avatar.cpp | 17 +++++++++++++++++ interface/src/avatar/Avatar.h | 6 ++++++ interface/src/avatar/MyAvatar.cpp | 22 ++++++++++++++++++++++ interface/src/avatar/MyAvatar.h | 5 ++++- interface/src/avatar/SkeletonModel.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 2 +- libraries/avatars/src/AvatarData.h | 6 +++--- 7 files changed, 54 insertions(+), 6 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 2b72fe2c23..6ceca9b426 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -24,6 +24,7 @@ #include #include #include +#include // adebug #include "Application.h" #include "Avatar.h" @@ -52,6 +53,7 @@ const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f; Avatar::Avatar() : AvatarData(), _skeletonModel(this), + _skeletonOffset(0.0f), _bodyYawDelta(0.0f), _velocity(0.0f), _positionDeltaAccumulator(0.0f), @@ -762,6 +764,21 @@ bool Avatar::findCollisions(const QVector& shapes, CollisionList& return collided; } +void Avatar::setSkeletonOffset(const glm::vec3& offset) { + const float MAX_OFFSET_LENGTH = _scale * 0.5f; + float offsetLength = glm::length(offset); + if (offsetLength > MAX_OFFSET_LENGTH) { + _skeletonOffset = (MAX_OFFSET_LENGTH / offsetLength) * offset; + } else { + _skeletonOffset = offset; + } + std::cout << "adebug set offset = " << offset << std::endl; // adebug +} + +glm::vec3 Avatar::getSkeletonPosition() const { + return _position + _skeletonOffset; +} + QVector Avatar::getJointRotations() const { if (QThread::currentThread() != thread()) { return AvatarData::getJointRotations(); diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index cbdebc6a48..29fb4cf241 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -69,6 +69,7 @@ class Texture; class Avatar : public AvatarData { Q_OBJECT Q_PROPERTY(quint32 collisionGroups READ getCollisionGroups WRITE setCollisionGroups) + Q_PROPERTY(glm::vec3 skeletonOffset READ getSkeletonOffset WRITE setSkeletonOffset) public: Avatar(); @@ -146,6 +147,10 @@ public: quint32 getCollisionGroups() const { return _collisionGroups; } virtual void setCollisionGroups(quint32 collisionGroups) { _collisionGroups = (collisionGroups & VALID_COLLISION_GROUPS); } + + Q_INVOKABLE void setSkeletonOffset(const glm::vec3& offset); + Q_INVOKABLE glm::vec3 getSkeletonOffset() { return _skeletonOffset; } + virtual glm::vec3 getSkeletonPosition() const; Q_INVOKABLE glm::vec3 getJointPosition(int index) const; Q_INVOKABLE glm::vec3 getJointPosition(const QString& name) const; @@ -184,6 +189,7 @@ signals: protected: Hair _hair; SkeletonModel _skeletonModel; + glm::vec3 _skeletonOffset; QVector _attachmentModels; float _bodyYawDelta; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index aae1907b76..5b6433365c 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -108,6 +108,20 @@ MyAvatar::~MyAvatar() { _lookAtTargetAvatar.clear(); } +QByteArray MyAvatar::toByteArray() { + CameraMode mode = Application::getInstance()->getCamera()->getMode(); + if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) { + // fake the avatar position that is sent up to the AvatarMixer + glm::vec3 oldPosition = _position; + _position += _skeletonOffset; + QByteArray array = AvatarData::toByteArray(); + // copy the correct position back + _position = oldPosition; + return array; + } + return AvatarData::toByteArray(); +} + void MyAvatar::reset() { _skeletonModel.reset(); getHead()->reset(); @@ -1052,6 +1066,14 @@ void MyAvatar::setAttachmentData(const QVector& attachmentData) _billboardValid = false; } +glm::vec3 MyAvatar::getSkeletonPosition() const { + CameraMode mode = Application::getInstance()->getCamera()->getMode(); + if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) { + return Avatar::getSkeletonPosition(); + } + return Avatar::getPosition(); +} + QString MyAvatar::getScriptedMotorFrame() const { QString frame = "avatar"; if (_scriptedMotorFrame == SCRIPTED_MOTOR_CAMERA_FRAME) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 98fc5ff74d..34a8ec6f5e 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -41,7 +41,8 @@ class MyAvatar : public Avatar { public: MyAvatar(); ~MyAvatar(); - + + QByteArray toByteArray(); void reset(); void update(float deltaTime); void simulate(float deltaTime); @@ -133,6 +134,8 @@ public: virtual void setFaceModelURL(const QUrl& faceModelURL); virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); virtual void setAttachmentData(const QVector& attachmentData); + + virtual glm::vec3 getSkeletonPosition() const; void clearJointAnimationPriorities(); diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index a1fccf1a10..cf14038331 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -77,7 +77,7 @@ const float PALM_PRIORITY = DEFAULT_PRIORITY; const float LEAN_PRIORITY = DEFAULT_PRIORITY; void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { - setTranslation(_owningAvatar->getPosition()); + setTranslation(_owningAvatar->getSkeletonPosition()); static const glm::quat refOrientation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); setRotation(_owningAvatar->getOrientation() * refOrientation); setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getScale() * MODEL_SCALE); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index ef7083e3bf..d8679d5550 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -67,7 +67,7 @@ AvatarData::~AvatarData() { delete _referential; } -const glm::vec3& AvatarData::getPosition() { +const glm::vec3& AvatarData::getPosition() const { if (_referential) { _referential->update(); } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 1fd4052974..d6636ff384 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -138,15 +138,15 @@ public: AvatarData(); virtual ~AvatarData(); - const QUuid& getSessionUUID() { return _sessionUUID; } + const QUuid& getSessionUUID() const { return _sessionUUID; } - const glm::vec3& getPosition(); + const glm::vec3& getPosition() const; virtual void setPosition(const glm::vec3 position, bool overideReferential = false); glm::vec3 getHandPosition() const; void setHandPosition(const glm::vec3& handPosition); - QByteArray toByteArray(); + virtual QByteArray toByteArray(); /// \return true if an error should be logged bool shouldLogError(const quint64& now); From a0a5530641a5f968cc0f381c49f6e79c3a4cda8f Mon Sep 17 00:00:00 2001 From: NextPrior Date: Tue, 10 Jun 2014 22:04:39 -0700 Subject: [PATCH 002/119] Initial reverb implementation Conflicts: interface/CMakeLists.txt interface/src/Audio.cpp interface/src/Audio.h libraries/script-engine/src/ScriptEngine.cpp --- cmake/modules/FindGverb.cmake | 38 ++ examples/audioReverbOff.js | 12 + examples/audioReverbOn.js | 32 ++ interface/CMakeLists.txt | 9 + interface/external/gverb/CMakeLists.txt | 2 + .../external/gverb/include/ladspa-util.h | 234 +++++++++++ interface/external/gverb/include/lv2.h | 392 ++++++++++++++++++ interface/external/gverb/src/gverb.c | 207 +++++++++ interface/external/gverb/src/gverb.h | 234 +++++++++++ interface/external/gverb/src/gverbdsp.c | 130 ++++++ interface/external/gverb/src/gverbdsp.h | 85 ++++ interface/src/Audio.cpp | 173 +++++++- interface/src/Audio.h | 17 + .../AudioDeviceScriptingInterface.cpp | 8 + .../scripting/AudioDeviceScriptingInterface.h | 2 + libraries/audio/src/AudioEffectOptions.cpp | 12 + libraries/audio/src/AudioEffectOptions.h | 99 +++++ libraries/script-engine/src/ScriptEngine.cpp | 4 + 18 files changed, 1689 insertions(+), 1 deletion(-) create mode 100644 cmake/modules/FindGverb.cmake create mode 100644 examples/audioReverbOff.js create mode 100644 examples/audioReverbOn.js create mode 100644 interface/external/gverb/CMakeLists.txt create mode 100644 interface/external/gverb/include/ladspa-util.h create mode 100644 interface/external/gverb/include/lv2.h create mode 100644 interface/external/gverb/src/gverb.c create mode 100644 interface/external/gverb/src/gverb.h create mode 100644 interface/external/gverb/src/gverbdsp.c create mode 100644 interface/external/gverb/src/gverbdsp.h create mode 100644 libraries/audio/src/AudioEffectOptions.cpp create mode 100644 libraries/audio/src/AudioEffectOptions.h diff --git a/cmake/modules/FindGverb.cmake b/cmake/modules/FindGverb.cmake new file mode 100644 index 0000000000..904813c007 --- /dev/null +++ b/cmake/modules/FindGverb.cmake @@ -0,0 +1,38 @@ +# FindGVerb.cmake +# +# Try to find the Gverb library. +# +# You must provide a GVERB_ROOT_DIR which contains src and include directories +# +# Once done this will define +# +# GVERB_FOUND - system found Gverb +# GVERB_INCLUDE_DIRS - the Gverb include directory +# +# 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 +# + +if (GVERB_INCLUDE_DIRS) + # in cache already + set(GVERB_FOUND TRUE) +else () + find_path(GVERB_INCLUDE_DIRS gverb.h ${GVERB_ROOT_DIR}/src) + + if (GVERB_INCLUDE_DIRS) + set(GVERB_FOUND TRUE) + endif (GVERB_INCLUDE_DIRS) + + if (GVERB_FOUND) + if (NOT GVERB_FIND_QUIETLY) + message(STATUS "Found Gverb... ${GVERB_LIBRARIES}") + endif (NOT GVERB_FIND_QUIETLY) + else () + if (GVERB_FIND_REQUIRED) + message(FATAL_ERROR "Could not find Gverb") + endif (GVERB_FIND_REQUIRED) + endif () + +endif () diff --git a/examples/audioReverbOff.js b/examples/audioReverbOff.js new file mode 100644 index 0000000000..1076a825a7 --- /dev/null +++ b/examples/audioReverbOff.js @@ -0,0 +1,12 @@ +// +// audioReverbOff.js +// examples +// +// 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 +// +// +AudioDevice.setReverb(false); +print("Reberb is now off."); diff --git a/examples/audioReverbOn.js b/examples/audioReverbOn.js new file mode 100644 index 0000000000..6d43c31943 --- /dev/null +++ b/examples/audioReverbOn.js @@ -0,0 +1,32 @@ +// +// audioReverbOn.js +// examples +// +// 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 + +// http://wiki.audacityteam.org/wiki/GVerb#Instant_reverb_settings +var audioOptions = new AudioEffectOptions(); + +// Square Meters +audioOptions.maxRoomSize = 50; +audioOptions.roomSize = 50; + +// Seconds +audioOptions.reverbTime = 4; + +// Between 0 - 1 +audioOptions.damping = 0.50; +audioOptions.inputBandwidth = 0.75; + +// dB +audioOptions.earlyLevel = -22; +audioOptions.tailLevel = -28; +audioOptions.dryLevel = 0; +audioOptions.wetLevel = 6; + +AudioDevice.setReverbOptions(audioOptions); +AudioDevice.setReverb(true); +print("Reverb is now on with the updated options."); diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 16ca977bae..3caa7c470e 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -14,6 +14,9 @@ endforeach() find_package(Qt5LinguistTools REQUIRED) find_package(Qt5LinguistToolsMacros) +# As Gverb is currently the only reverb library, it's required. +find_package(Gverb REQUIRED) + if (DEFINED ENV{JOB_ID}) set(BUILD_SEQ $ENV{JOB_ID}) else () @@ -167,6 +170,12 @@ if (QXMPP_FOUND AND NOT DISABLE_QXMPP AND WIN32) add_definitions(-DQXMPP_STATIC) endif () +if (GVERB_FOUND) + add_subdirectory(${GVERB_ROOT_DIR}) + include_directories(${GVERB_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} gverb) +endif (GVERB_FOUND) + # include headers for interface and InterfaceConfig. include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes") include_directories("${OPENSSL_INCLUDE_DIR}") diff --git a/interface/external/gverb/CMakeLists.txt b/interface/external/gverb/CMakeLists.txt new file mode 100644 index 0000000000..140b45b727 --- /dev/null +++ b/interface/external/gverb/CMakeLists.txt @@ -0,0 +1,2 @@ +cmake_minimum_required(VERSION 2.8) +add_library(gverb include/ladspa-util.h include/lv2.h src/gverb.h src/gverb.c src/gverbdsp.h src/gverbdsp.c) diff --git a/interface/external/gverb/include/ladspa-util.h b/interface/external/gverb/include/ladspa-util.h new file mode 100644 index 0000000000..149d0aaacd --- /dev/null +++ b/interface/external/gverb/include/ladspa-util.h @@ -0,0 +1,234 @@ +/* Some misc util functions for audio DSP work, written by Steve Harris, + * December 2000 + * + * steve@plugin.org.uk + */ + +#ifndef LADSPA_UTIL_H +#define LADSPA_UTIL_H + +#include +#include +#include + +#define buffer_write(a, b) a=(b) + +// 16.16 fixpoint +typedef union { + int32_t all; + struct { +#ifdef WORDS_BIGENDIAN + int16_t in; + uint16_t fr; +#else + uint16_t fr; + int16_t in; +#endif + } part; +} fixp16; + +// 32.32 fixpoint +typedef union { + int64_t all; + struct { +#ifdef WORDS_BIGENDIAN + int32_t in; + uint32_t fr; +#else + uint32_t fr; + int32_t in; +#endif + } part; +} fixp32; + +/* 32 bit "pointer cast" union */ +typedef union { + float f; + int32_t i; +} ls_pcast32; + +// Sometimes it doesn't get defined, even though it eists and C99 is declared +long int lrintf (float x); + +// 1.0 / ln(2) +#define LN2R 1.442695041f + +/* detet floating point denormal numbers by comparing them to the smallest + * normal, crap, but reliable */ +#define DN_CHECK(x, l) if (fabs(x) < 1e-38) printf("DN: "l"\n") + +// Denormalise floats, only actually needed for PIII and recent PowerPC +//#define FLUSH_TO_ZERO(fv) (((*(unsigned int*)&(fv))&0x7f800000)==0)?0.0f:(fv) + +static inline float flush_to_zero(float f) +{ + ls_pcast32 v; + + v.f = f; + + // original: return (v.i & 0x7f800000) == 0 ? 0.0f : f; + // version from Tim Blechmann + return (v.i & 0x7f800000) < 0x08000000 ? 0.0f : f; +} + +static inline void round_to_zero(volatile float *f) +{ + *f += 1e-18; + *f -= 1e-18; +} + +/* A set of branchless clipping operations from Laurent de Soras */ + +static inline float f_max(float x, float a) +{ + x -= a; + x += fabs(x); + x *= 0.5; + x += a; + + return x; +} + +static inline float f_min(float x, float b) +{ + x = b - x; + x += fabs(x); + x *= 0.5; + x = b - x; + + return x; +} + +static inline float f_clamp(float x, float a, float b) +{ + const float x1 = fabs(x - a); + const float x2 = fabs(x - b); + + x = x1 + a + b; + x -= x2; + x *= 0.5; + + return x; +} + +// Limit a value to be l<=v<=u +#define LIMIT(v,l,u) ((v)<(l)?(l):((v)>(u)?(u):(v))) + +// Truncate-to-zero modulo (ANSI C doesn't specify) will only work +// if -m < v < 2m +#define MOD(v,m) (v<0?v+m:(v>=m?v-m:v)) + +// Truncate-to-zero modulo (ANSI C doesn't specify) will only work +// if v > -m and v < m +#define NEG_MOD(v,m) ((v)<0?((v)+(m)):(v)) + +// Convert a value in dB's to a coefficent +#define DB_CO(g) ((g) > -90.0f ? powf(10.0f, (g) * 0.05f) : 0.0f) +#define CO_DB(v) (20.0f * log10f(v)) + +// Linearly interpolate [ = a * (1 - f) + b * f] +#define LIN_INTERP(f,a,b) ((a) + (f) * ((b) - (a))) + +// Cubic interpolation function +static inline float cube_interp(const float fr, const float inm1, const float + in, const float inp1, const float inp2) +{ + return in + 0.5f * fr * (inp1 - inm1 + + fr * (4.0f * inp1 + 2.0f * inm1 - 5.0f * in - inp2 + + fr * (3.0f * (in - inp1) - inm1 + inp2))); +} + +/* fast sin^2 aproxiamtion, adapted from jan AT rpgfan's posting to the + * music-dsp list */ +static inline float f_sin_sq(float angle) +{ + const float asqr = angle * angle; + float result = -2.39e-08f; + + result *= asqr; + result += 2.7526e-06f; + result *= asqr; + result -= 1.98409e-04f; + result *= asqr; + result += 8.3333315e-03f; + result *= asqr; + result -= 1.666666664e-01f; + result *= asqr; + result += 1.0f; + result *= angle; + + return result * result; +} + +#ifdef HAVE_LRINTF + +#define f_round(f) lrintf(f) + +#else + +// Round float to int using IEEE int* hack +static inline int f_round(float f) +{ + ls_pcast32 p; + + p.f = f; + p.f += (3<<22); + + return p.i - 0x4b400000; +} + +#endif + +// Truncate float to int +static inline int f_trunc(float f) +{ + return f_round(floorf(f)); +} + +/* Andrew Simper's pow(2, x) aproximation from the music-dsp list */ + +#if 0 + +/* original */ +static inline float f_pow2(float x) +{ + long *px = (long*)(&x); // store address of float as long pointer + const float tx = (x-0.5f) + (3<<22); // temporary value for truncation + const long lx = *((long*)&tx) - 0x4b400000; // integer power of 2 + const float dx = x-(float)(lx); // float remainder of power of 2 + + x = 1.0f + dx*(0.6960656421638072f + // cubic apporoximation of 2^x + dx*(0.224494337302845f + // for x in the range [0, 1] + dx*(0.07944023841053369f))); + *px += (lx<<23); // add integer power of 2 to exponent + + return x; +} + +#else + +/* union version */ +static inline float f_pow2(float x) +{ + ls_pcast32 *px, tx, lx; + float dx; + + px = (ls_pcast32 *)&x; // store address of float as long pointer + tx.f = (x-0.5f) + (3<<22); // temporary value for truncation + lx.i = tx.i - 0x4b400000; // integer power of 2 + dx = x - (float)lx.i; // float remainder of power of 2 + + x = 1.0f + dx * (0.6960656421638072f + // cubic apporoximation of 2^x + dx * (0.224494337302845f + // for x in the range [0, 1] + dx * (0.07944023841053369f))); + (*px).i += (lx.i << 23); // add integer power of 2 to exponent + + return (*px).f; +} + +#endif + +/* Fast exponentiation function, y = e^x */ +#define f_exp(x) f_pow2(x * LN2R) + +#endif diff --git a/interface/external/gverb/include/lv2.h b/interface/external/gverb/include/lv2.h new file mode 100644 index 0000000000..d5257824c6 --- /dev/null +++ b/interface/external/gverb/include/lv2.h @@ -0,0 +1,392 @@ +/* LV2 - LADSPA (Linux Audio Developer's Simple Plugin API) Version 2 + * Revision 1 + * + * Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis, + * Stefan Westerfeld. + * Copyright (C) 2006-2008 Steve Harris, Dave Robillard. + * + * This header is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, + * or (at your option) any later version. + * + * This header is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + * USA. + */ + +#ifndef LV2_H_INCLUDED +#define LV2_H_INCLUDED + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* ************************************************************************* */ + + +/** @file lv2.h + * + * Revision: 1 + * + * == Overview == + * + * There are a large number of open source and free software synthesis + * packages in use or development at this time. This API ('LV2') + * attempts to give programmers the ability to write simple 'plugin' + * audio processors in C/C++ and link them dynamically ('plug') into + * a range of these packages ('hosts'). It should be possible for any + * host and any plugin to communicate completely through this interface. + * + * This API is deliberately as short and simple as possible. + * The information required to use a plugin is in a companion data + * (RDF) file. The shared library portion of the API (defined in this + * header) does not contain enough information to make use of the plugin + * possible - the data file is mandatory. + * + * Plugins are expected to distinguish between control rate and audio + * rate data (or other types of data defined by extensions). Plugins have + * 'ports' that are inputs or outputs and each plugin is 'run' for a 'block' + * corresponding to a short time interval measured in samples. Audio rate + * data is communicated using arrays with one element per sample processed, + * allowing a block of audio to be processed by the plugin in a single + * pass. Control rate data is communicated using single values. Control + * rate data has a single value at the start of a call to the 'run()' + * function, and may be considered to remain this value for its duration. + * Thus the 'control rate' is determined by the block size, controlled by + * the host. The plugin may assume that all its input and output ports have + * been connected to the relevant data location (see the 'connect_port()' + * function below) before it is asked to run, unless the port has been set + * 'connection optional' in the plugin's data file. + * + * Plugins will reside in shared object files suitable for dynamic linking + * by dlopen() and family. The file will provide a number of 'plugin + * types' that can be used to instantiate actual plugins (sometimes known + * as 'plugin instances') that can be connected together to perform tasks. + * The host can access these plugin types using the lv2_descriptor() + * function. + * + * This API contains very limited error-handling. + * + * == Threading rules == + * + * Certain hosts may need to call the functions provided by a plugin from + * multiple threads. For this to be safe, the plugin must be written so that + * those functions can be executed simultaneously without problems. + * To facilitate this, the functions provided by a plugin are divided into + * classes: + * + * - Discovery class: lv2_descriptor(), extension_data() + * - Instantiation class: instantiate(), cleanup(), activate(), deactivate() + * - Audio class: run(), connect_port() + * + * Extensions to this specification which add new functions MUST declare in + * which of these classes the functions belong, or define new classes for them. + * The rules that hosts must follow are these: + * + * - When a function from the Discovery class is running, no other + * functions in the same shared object file may run. + * - When a function from the Instantiation class is running for a plugin + * instance, no other functions for that instance may run. + * - When a function is running for a plugin instance, no other + * function in the same class may run for that instance. + * + * Any simultaneous calls that are not explicitly forbidden by these rules + * are allowed. For example, a host may call run() for two different plugin + * instances simultaneously. + */ + + +/* ************************************************************************* */ + + +/** Plugin Handle. + * + * This plugin handle indicates a particular instance of the plugin + * concerned. It is valid to compare this to NULL (0 for C++) but + * otherwise the host MUST NOT attempt to interpret it. The plugin + * may use it to reference internal instance data. */ +typedef void * LV2_Handle; + + +/* ************************************************************************* */ + + +/** Feature data. + * + * These are passed to a plugin's instantiate method to represent a special + * feature the host has which the plugin may depend on. This is to allow + * extensions to the LV2 specification without causing any breakage. + * Extensions may specify what data needs to be passed here. The base + * LV2 specification does not define any features; hosts are not required + * to use this facility. */ +typedef struct _LV2_Feature { + /** A globally unique, case-sensitive identifier for this feature. + * + * This MUST be defined in the specification of any LV2 extension which + * defines a host feature. */ + const char * URI; + + /** Pointer to arbitrary data. + * + * This is to allow hosts to pass data to a plugin (simple values, data + * structures, function pointers, etc) as part of a 'feature'. The LV2 + * specification makes no restrictions on the contents of this data. + * The data here MUST be cleary defined by the LV2 extension which defines + * this feature. + * If no data is required, this may be set to NULL. */ + void * data; +} LV2_Feature; + + +/* ************************************************************************* */ + + +/** Descriptor for a Type of Plugin. + * + * This structure is used to describe a plugin type. It provides a number + * of functions to instantiate it, link it to buffers and run it. */ +typedef struct _LV2_Descriptor { + + /** A globally unique, case-sensitive identifier for this plugin type. + * + * All plugins with the same URI MUST be compatible in terms of 'port + * signature', meaning they have the same number of ports, same port + * shortnames, and roughly the same functionality. URIs should + * probably contain a version number (or similar) for this reason. + * + * Rationale: When serializing session/patch/etc files, hosts MUST + * refer to a loaded plugin by the plugin URI only. In the future + * loading a plugin with this URI MUST yield a plugin with the + * same ports (etc) which is 100% compatible. */ + const char * URI; + + /** Function pointer that instantiates a plugin. + * + * A handle is returned indicating the new plugin instance. The + * instantiation function accepts a sample rate as a parameter as well + * as the plugin descriptor from which this instantiate function was + * found. This function must return NULL if instantiation fails. + * + * bundle_path is a string of the path to the LV2 bundle which contains + * this plugin binary. It MUST include the trailing directory separator + * (e.g. '/') so that BundlePath + filename gives the path to a file + * in the bundle. + * + * features is a NULL terminated array of LV2_Feature structs which + * represent the features the host supports. Plugins may refuse to + * instantiate if required features are not found here (however hosts + * SHOULD NOT use this as a discovery mechanism, instead reading the + * data file before attempting to instantiate the plugin). This array + * must always exist; if a host has no features, it MUST pass a single + * element array containing NULL (to simplify plugins). + * + * Note that instance initialisation should generally occur in + * activate() rather than here. If a host calls instantiate, it MUST + * call cleanup() at some point in the future. */ + LV2_Handle (*instantiate)(const struct _LV2_Descriptor * descriptor, + double sample_rate, + const char * bundle_path, + const LV2_Feature *const * features); + + /** Function pointer that connects a port on a plugin instance to a memory + * location where the block of data for the port will be read/written. + * + * The data location is expected to be of the type defined in the + * plugin's data file (e.g. an array of float for an lv2:AudioPort). + * Memory issues are managed by the host. The plugin must read/write + * the data at these locations every time run() is called, data + * present at the time of this connection call MUST NOT be + * considered meaningful. + * + * The host MUST NOT try to connect a data buffer to a port index + * that is not defined in the RDF data for the plugin. If it does, + * the plugin's behaviour is undefined. + * + * connect_port() may be called more than once for a plugin instance + * to allow the host to change the buffers that the plugin is reading + * or writing. These calls may be made before or after activate() + * or deactivate() calls. Note that there may be realtime constraints + * on connect_port (see lv2:hardRTCapable in lv2.ttl). + * + * connect_port() MUST be called at least once for each port before + * run() is called. The plugin must pay careful attention to the block + * size passed to the run function as the block allocated may only just + * be large enough to contain the block of data (typically samples), and + * is not guaranteed to be constant. + * + * Plugin writers should be aware that the host may elect to use the + * same buffer for more than one port and even use the same buffer for + * both input and output (see lv2:inPlaceBroken in lv2.ttl). + * However, overlapped buffers or use of a single buffer for both + * audio and control data may result in unexpected behaviour. + * + * If the plugin has the feature lv2:hardRTCapable then there are + * various things that the plugin MUST NOT do within the connect_port() + * function (see lv2.ttl). */ + void (*connect_port)(LV2_Handle instance, + uint32_t port, + void * data_location); + + /** Function pointer that initialises a plugin instance and activates + * it for use. + * + * This is separated from instantiate() to aid real-time support and so + * that hosts can reinitialise a plugin instance by calling deactivate() + * and then activate(). In this case the plugin instance must reset all + * state information dependent on the history of the plugin instance + * except for any data locations provided by connect_port(). If there + * is nothing for activate() to do then the plugin writer may provide + * a NULL rather than an empty function. + * + * When present, hosts MUST call this function once before run() + * is called for the first time. This call SHOULD be made as close + * to the run() call as possible and indicates to real-time plugins + * that they are now live, however plugins MUST NOT rely on a prompt + * call to run() after activate(). activate() may not be called again + * unless deactivate() is called first (after which activate() may be + * called again, followed by deactivate, etc. etc.). If a host calls + * activate, it MUST call deactivate at some point in the future. + * + * Note that connect_port() may be called before or after a call to + * activate(). */ + void (*activate)(LV2_Handle instance); + + /** Function pointer that runs a plugin instance for a block. + * + * Two parameters are required: the first is a handle to the particular + * instance to be run and the second indicates the block size (in + * samples) for which the plugin instance may run. + * + * Note that if an activate() function exists then it must be called + * before run(). If deactivate() is called for a plugin instance then + * the plugin instance may not be reused until activate() has been + * called again. + * + * If the plugin has the feature lv2:hardRTCapable then there are + * various things that the plugin MUST NOT do within the run() + * function (see lv2.ttl). */ + void (*run)(LV2_Handle instance, + uint32_t sample_count); + + /** This is the counterpart to activate() (see above). If there is + * nothing for deactivate() to do then the plugin writer may provide + * a NULL rather than an empty function. + * + * Hosts must deactivate all activated units after they have been run() + * for the last time. This call SHOULD be made as close to the last + * run() call as possible and indicates to real-time plugins that + * they are no longer live, however plugins MUST NOT rely on prompt + * deactivation. Note that connect_port() may be called before or + * after a call to deactivate(). + * + * Note that deactivation is not similar to pausing as the plugin + * instance will be reinitialised when activate() is called to reuse it. + * Hosts MUST NOT call deactivate() unless activate() was previously + * called. */ + void (*deactivate)(LV2_Handle instance); + + /** This is the counterpart to instantiate() (see above). Once an instance + * of a plugin has been finished with it can be deleted using this + * function. The instance handle passed ceases to be valid after + * this call. + * + * If activate() was called for a plugin instance then a corresponding + * call to deactivate() MUST be made before cleanup() is called. + * Hosts MUST NOT call cleanup() unless instantiate() was previously + * called. */ + void (*cleanup)(LV2_Handle instance); + + /** Function pointer that can be used to return additional instance data for + * a plugin defined by some extenion (e.g. a struct containing additional + * function pointers). + * + * The actual type and meaning of the returned object MUST be specified + * precisely by the extension if it defines any extra data. If a particular + * extension does not define extra instance data, this function MUST return + * NULL for that extension's URI. If a plugin does not support any + * extensions that define extra instance data, this function pointer may be + * set to NULL rather than providing an empty function. + * + * The only parameter is the URI of the extension. The plugin MUST return + * NULL if it does not support the extension, but hosts SHOULD NOT use this + * as a discovery method (e.g. hosts should only call this function for + * extensions known to be supported by the plugin from the data file). + * + * The host is never responsible for freeing the returned value. + * + * NOTE: This function should return a struct (likely containing function + * pointers) and NOT a direct function pointer. Standard C and C++ do not + * allow type casts from void* to a function pointer type. To provide + * additional functions a struct should be returned containing the extra + * function pointers (which is valid standard code, and a much better idea + * for extensibility anyway). */ + const void* (*extension_data)(const char * uri); + +} LV2_Descriptor; + + +/* ****************************************************************** */ + + +/** Accessing Plugin Types. + * + * The exact mechanism by which plugins are loaded is host-dependent, + * however all most hosts will need to know is the URI of the plugin they + * wish to load. The environment variable LV2_PATH, if present, should + * contain a colon-separated path indicating directories (containing + * plugin bundle subdirectories) that should be searched (in order) + * for plugins. It is expected that hosts will use a library to provide + * this functionality. + * + * A plugin programmer must include a function called "lv2_descriptor" + * with the following function prototype within the shared object + * file. This function will have C-style linkage (if you are using + * C++ this is taken care of by the 'extern "C"' clause at the top of + * the file). + * + * A host will find the plugin shared object file by one means or another, + * find the lv2_descriptor() function, call it, and proceed from there. + * + * Plugin types are accessed by index (not ID) using values from 0 + * upwards. Out of range indexes must result in this function returning + * NULL, so the plugin count can be determined by checking for the least + * index that results in NULL being returned. Index has no meaning, + * hosts MUST NOT depend on it remaining constant (ie when serialising) + * in any way. */ +const LV2_Descriptor * lv2_descriptor(uint32_t index); + + +/** Datatype corresponding to the lv2_descriptor() function. */ +typedef const LV2_Descriptor * +(*LV2_Descriptor_Function)(uint32_t index); + + +/* ******************************************************************** */ + + +/* Put this (LV2_SYMBOL_EXPORT) before any functions that are to be loaded + * by the host as a symbol from the dynamic library. + */ +#ifdef WIN32 +#define LV2_SYMBOL_EXPORT __declspec(dllexport) +#else +#define LV2_SYMBOL_EXPORT +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* LV2_H_INCLUDED */ + diff --git a/interface/external/gverb/src/gverb.c b/interface/external/gverb/src/gverb.c new file mode 100644 index 0000000000..e3980232bc --- /dev/null +++ b/interface/external/gverb/src/gverb.c @@ -0,0 +1,207 @@ +/* + + Copyright (C) 1999 Juhana Sadeharju + kouhia at nic.funet.fi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + + +#include +#include +#include +#include +#include "gverbdsp.h" +#include "gverb.h" +#include "../include/ladspa-util.h" + +ty_gverb *gverb_new(int srate, float maxroomsize, float roomsize, + float revtime, + float damping, float spread, + float inputbandwidth, float earlylevel, + float taillevel) +{ + ty_gverb *p; + float ga,gb,gt; + int i,n; + float r; + float diffscale; + int a,b,c,cc,d,dd,e; + float spread1,spread2; + + p = (ty_gverb *)malloc(sizeof(ty_gverb)); + p->rate = srate; + p->fdndamping = damping; + p->maxroomsize = maxroomsize; + p->roomsize = roomsize; + p->revtime = revtime; + p->earlylevel = earlylevel; + p->taillevel = taillevel; + + p->maxdelay = p->rate*p->maxroomsize/340.0; + p->largestdelay = p->rate*p->roomsize/340.0; + + + /* Input damper */ + + p->inputbandwidth = inputbandwidth; + p->inputdamper = damper_make(1.0 - p->inputbandwidth); + + + /* FDN section */ + + + p->fdndels = (ty_fixeddelay **)calloc(FDNORDER, sizeof(ty_fixeddelay *)); + for(i = 0; i < FDNORDER; i++) { + p->fdndels[i] = fixeddelay_make((int)p->maxdelay+1000); + } + p->fdngains = (float *)calloc(FDNORDER, sizeof(float)); + p->fdnlens = (int *)calloc(FDNORDER, sizeof(int)); + + p->fdndamps = (ty_damper **)calloc(FDNORDER, sizeof(ty_damper *)); + for(i = 0; i < FDNORDER; i++) { + p->fdndamps[i] = damper_make(p->fdndamping); + } + + ga = 60.0; + gt = p->revtime; + ga = powf(10.0f,-ga/20.0f); + n = p->rate*gt; + p->alpha = pow((double)ga, 1.0/(double)n); + + gb = 0.0; + for(i = 0; i < FDNORDER; i++) { + if (i == 0) gb = 1.000000*p->largestdelay; + if (i == 1) gb = 0.816490*p->largestdelay; + if (i == 2) gb = 0.707100*p->largestdelay; + if (i == 3) gb = 0.632450*p->largestdelay; + +#if 0 + p->fdnlens[i] = nearest_prime((int)gb, 0.5); +#else + p->fdnlens[i] = f_round(gb); +#endif + p->fdngains[i] = -powf((float)p->alpha,p->fdnlens[i]); + } + + p->d = (float *)calloc(FDNORDER, sizeof(float)); + p->u = (float *)calloc(FDNORDER, sizeof(float)); + p->f = (float *)calloc(FDNORDER, sizeof(float)); + + /* Diffuser section */ + + diffscale = (float)p->fdnlens[3]/(210+159+562+410); + spread1 = spread; + spread2 = 3.0*spread; + + b = 210; + r = 0.125541; + a = spread1*r; + c = 210+159+a; + cc = c-b; + r = 0.854046; + a = spread2*r; + d = 210+159+562+a; + dd = d-c; + e = 1341-d; + + p->ldifs = (ty_diffuser **)calloc(4, sizeof(ty_diffuser *)); + p->ldifs[0] = diffuser_make((int)(diffscale*b),0.75); + p->ldifs[1] = diffuser_make((int)(diffscale*cc),0.75); + p->ldifs[2] = diffuser_make((int)(diffscale*dd),0.625); + p->ldifs[3] = diffuser_make((int)(diffscale*e),0.625); + + b = 210; + r = -0.568366; + a = spread1*r; + c = 210+159+a; + cc = c-b; + r = -0.126815; + a = spread2*r; + d = 210+159+562+a; + dd = d-c; + e = 1341-d; + + p->rdifs = (ty_diffuser **)calloc(4, sizeof(ty_diffuser *)); + p->rdifs[0] = diffuser_make((int)(diffscale*b),0.75); + p->rdifs[1] = diffuser_make((int)(diffscale*cc),0.75); + p->rdifs[2] = diffuser_make((int)(diffscale*dd),0.625); + p->rdifs[3] = diffuser_make((int)(diffscale*e),0.625); + + + + /* Tapped delay section */ + + p->tapdelay = fixeddelay_make(44000); + p->taps = (int *)calloc(FDNORDER, sizeof(int)); + p->tapgains = (float *)calloc(FDNORDER, sizeof(float)); + + p->taps[0] = 5+0.410*p->largestdelay; + p->taps[1] = 5+0.300*p->largestdelay; + p->taps[2] = 5+0.155*p->largestdelay; + p->taps[3] = 5+0.000*p->largestdelay; + + for(i = 0; i < FDNORDER; i++) { + p->tapgains[i] = pow(p->alpha,(double)p->taps[i]); + } + + return(p); +} + +void gverb_free(ty_gverb *p) +{ + int i; + + damper_free(p->inputdamper); + for(i = 0; i < FDNORDER; i++) { + fixeddelay_free(p->fdndels[i]); + damper_free(p->fdndamps[i]); + diffuser_free(p->ldifs[i]); + diffuser_free(p->rdifs[i]); + } + free(p->fdndels); + free(p->fdngains); + free(p->fdnlens); + free(p->fdndamps); + free(p->d); + free(p->u); + free(p->f); + free(p->ldifs); + free(p->rdifs); + free(p->taps); + free(p->tapgains); + fixeddelay_free(p->tapdelay); + free(p); +} + +void gverb_flush(ty_gverb *p) +{ + int i; + + damper_flush(p->inputdamper); + for(i = 0; i < FDNORDER; i++) { + fixeddelay_flush(p->fdndels[i]); + damper_flush(p->fdndamps[i]); + diffuser_flush(p->ldifs[i]); + diffuser_flush(p->rdifs[i]); + } + memset(p->d, 0, FDNORDER * sizeof(float)); + memset(p->u, 0, FDNORDER * sizeof(float)); + memset(p->f, 0, FDNORDER * sizeof(float)); + fixeddelay_flush(p->tapdelay); +} + +/* swh: other functions are now in the .h file for inlining */ diff --git a/interface/external/gverb/src/gverb.h b/interface/external/gverb/src/gverb.h new file mode 100644 index 0000000000..21bc1c3fef --- /dev/null +++ b/interface/external/gverb/src/gverb.h @@ -0,0 +1,234 @@ +/* + + Copyright (C) 1999 Juhana Sadeharju + kouhia at nic.funet.fi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#ifndef GVERB_H +#define GVERB_H + +#include +#include +#include +#include "gverbdsp.h" +#include "gverb.h" +#include "../include/ladspa-util.h" + +#define FDNORDER 4 + +typedef struct { + int rate; + float inputbandwidth; + float taillevel; + float earlylevel; + ty_damper *inputdamper; + float maxroomsize; + float roomsize; + float revtime; + float maxdelay; + float largestdelay; + ty_fixeddelay **fdndels; + float *fdngains; + int *fdnlens; + ty_damper **fdndamps; + float fdndamping; + ty_diffuser **ldifs; + ty_diffuser **rdifs; + ty_fixeddelay *tapdelay; + int *taps; + float *tapgains; + float *d; + float *u; + float *f; + double alpha; +} ty_gverb; + + +ty_gverb *gverb_new(int, float, float, float, float, float, float, float, float); +void gverb_free(ty_gverb *); +void gverb_flush(ty_gverb *); +static void gverb_do(ty_gverb *, float, float *, float *); +static void gverb_set_roomsize(ty_gverb *, float); +static void gverb_set_revtime(ty_gverb *, float); +static void gverb_set_damping(ty_gverb *, float); +static void gverb_set_inputbandwidth(ty_gverb *, float); +static void gverb_set_earlylevel(ty_gverb *, float); +static void gverb_set_taillevel(ty_gverb *, float); + +/* + * This FDN reverb can be made smoother by setting matrix elements at the + * diagonal and near of it to zero or nearly zero. By setting diagonals to zero + * means we remove the effect of the parallel comb structure from the + * reverberation. A comb generates uniform impulse stream to the reverberation + * impulse response, and thus it is not good. By setting near diagonal elements + * to zero means we remove delay sequences having consequtive delays of the + * similar lenths, when the delays are in sorted in length with respect to + * matrix element index. The matrix described here could be generated by + * differencing Rocchesso's circulant matrix at max diffuse value and at low + * diffuse value (approaching parallel combs). + * + * Example 1: + * Set a(k,k), for all k, equal to 0. + * + * Example 2: + * Set a(k,k), a(k,k-1) and a(k,k+1) equal to 0. + * + * Example 3: The transition to zero gains could be smooth as well. + * a(k,k-1) and a(k,k+1) could be 0.3, and a(k,k-2) and a(k,k+2) could + * be 0.5, say. + */ + +static inline void gverb_fdnmatrix(float *a, float *b) +{ + const float dl0 = a[0], dl1 = a[1], dl2 = a[2], dl3 = a[3]; + + b[0] = 0.5f*(+dl0 + dl1 - dl2 - dl3); + b[1] = 0.5f*(+dl0 - dl1 - dl2 + dl3); + b[2] = 0.5f*(-dl0 + dl1 - dl2 + dl3); + b[3] = 0.5f*(+dl0 + dl1 + dl2 + dl3); +} + +static inline void gverb_do(ty_gverb *p, float x, float *yl, float *yr) +{ + float z; + unsigned int i; + float lsum,rsum,sum,sign; + + if ((x != x) || fabsf(x) > 100000.0f) { + x = 0.0f; + } + + z = damper_do(p->inputdamper, x); + + z = diffuser_do(p->ldifs[0],z); + + for(i = 0; i < FDNORDER; i++) { + p->u[i] = p->tapgains[i]*fixeddelay_read(p->tapdelay,p->taps[i]); + } + fixeddelay_write(p->tapdelay,z); + + for(i = 0; i < FDNORDER; i++) { + p->d[i] = damper_do(p->fdndamps[i], + p->fdngains[i]*fixeddelay_read(p->fdndels[i], + p->fdnlens[i])); + } + + sum = 0.0f; + sign = 1.0f; + for(i = 0; i < FDNORDER; i++) { + sum += sign*(p->taillevel*p->d[i] + p->earlylevel*p->u[i]); + sign = -sign; + } + sum += x*p->earlylevel; + lsum = sum; + rsum = sum; + + gverb_fdnmatrix(p->d,p->f); + + for(i = 0; i < FDNORDER; i++) { + fixeddelay_write(p->fdndels[i],p->u[i]+p->f[i]); + } + + lsum = diffuser_do(p->ldifs[1],lsum); + lsum = diffuser_do(p->ldifs[2],lsum); + lsum = diffuser_do(p->ldifs[3],lsum); + rsum = diffuser_do(p->rdifs[1],rsum); + rsum = diffuser_do(p->rdifs[2],rsum); + rsum = diffuser_do(p->rdifs[3],rsum); + + *yl = lsum; + *yr = rsum; +} + +static inline void gverb_set_roomsize(ty_gverb *p, const float a) +{ + unsigned int i; + + if (a <= 1.0 || (a != a)) { + p->roomsize = 1.0; + } else { + p->roomsize = a; + } + p->largestdelay = p->rate * p->roomsize * 0.00294f; + + p->fdnlens[0] = f_round(1.000000f*p->largestdelay); + p->fdnlens[1] = f_round(0.816490f*p->largestdelay); + p->fdnlens[2] = f_round(0.707100f*p->largestdelay); + p->fdnlens[3] = f_round(0.632450f*p->largestdelay); + for(i = 0; i < FDNORDER; i++) { + p->fdngains[i] = -powf((float)p->alpha, p->fdnlens[i]); + } + + p->taps[0] = 5+f_round(0.410f*p->largestdelay); + p->taps[1] = 5+f_round(0.300f*p->largestdelay); + p->taps[2] = 5+f_round(0.155f*p->largestdelay); + p->taps[3] = 5+f_round(0.000f*p->largestdelay); + + for(i = 0; i < FDNORDER; i++) { + p->tapgains[i] = powf((float)p->alpha, p->taps[i]); + } + +} + +static inline void gverb_set_revtime(ty_gverb *p,float a) +{ + float ga,gt; + double n; + unsigned int i; + + p->revtime = a; + + ga = 60.0; + gt = p->revtime; + ga = powf(10.0f,-ga/20.0f); + n = p->rate*gt; + p->alpha = (double)powf(ga,1.0f/n); + + for(i = 0; i < FDNORDER; i++) { + p->fdngains[i] = -powf((float)p->alpha, p->fdnlens[i]); + } + +} + +static inline void gverb_set_damping(ty_gverb *p,float a) +{ + unsigned int i; + + p->fdndamping = a; + for(i = 0; i < FDNORDER; i++) { + damper_set(p->fdndamps[i],p->fdndamping); + } +} + +static inline void gverb_set_inputbandwidth(ty_gverb *p,float a) +{ + p->inputbandwidth = a; + damper_set(p->inputdamper,1.0 - p->inputbandwidth); +} + +static inline void gverb_set_earlylevel(ty_gverb *p,float a) +{ + p->earlylevel = a; +} + +static inline void gverb_set_taillevel(ty_gverb *p,float a) +{ + p->taillevel = a; +} + +#endif diff --git a/interface/external/gverb/src/gverbdsp.c b/interface/external/gverb/src/gverbdsp.c new file mode 100644 index 0000000000..05a90f897e --- /dev/null +++ b/interface/external/gverb/src/gverbdsp.c @@ -0,0 +1,130 @@ + + +/* + + Copyright (C) 1999 Juhana Sadeharju + kouhia at nic.funet.fi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#include +#include +#include +#include + +#include "gverbdsp.h" + +#define TRUE 1 +#define FALSE 0 + +ty_diffuser *diffuser_make(int size, float coeff) +{ + ty_diffuser *p; + int i; + + p = (ty_diffuser *)malloc(sizeof(ty_diffuser)); + p->size = size; + p->coeff = coeff; + p->idx = 0; + p->buf = (float *)malloc(size*sizeof(float)); + for (i = 0; i < size; i++) p->buf[i] = 0.0; + return(p); +} + +void diffuser_free(ty_diffuser *p) +{ + free(p->buf); + free(p); +} + +void diffuser_flush(ty_diffuser *p) +{ + memset(p->buf, 0, p->size * sizeof(float)); +} + +ty_damper *damper_make(float damping) +{ + ty_damper *p; + + p = (ty_damper *)malloc(sizeof(ty_damper)); + p->damping = damping; + p->delay = 0.0f; + return(p); +} + +void damper_free(ty_damper *p) +{ + free(p); +} + +void damper_flush(ty_damper *p) +{ + p->delay = 0.0f; +} + +ty_fixeddelay *fixeddelay_make(int size) +{ + ty_fixeddelay *p; + int i; + + p = (ty_fixeddelay *)malloc(sizeof(ty_fixeddelay)); + p->size = size; + p->idx = 0; + p->buf = (float *)malloc(size*sizeof(float)); + for (i = 0; i < size; i++) p->buf[i] = 0.0; + return(p); +} + +void fixeddelay_free(ty_fixeddelay *p) +{ + free(p->buf); + free(p); +} + +void fixeddelay_flush(ty_fixeddelay *p) +{ + memset(p->buf, 0, p->size * sizeof(float)); +} + +int isprime(int n) +{ + unsigned int i; + const unsigned int lim = (int)sqrtf((float)n); + + if (n == 2) return(TRUE); + if ((n & 1) == 0) return(FALSE); + for(i = 3; i <= lim; i += 2) + if ((n % i) == 0) return(FALSE); + return(TRUE); +} + +int nearest_prime(int n, float rerror) + /* relative error; new prime will be in range + * [n-n*rerror, n+n*rerror]; + */ +{ + int bound,k; + + if (isprime(n)) return(n); + /* assume n is large enough and n*rerror enough smaller than n */ + bound = n*rerror; + for(k = 1; k <= bound; k++) { + if (isprime(n+k)) return(n+k); + if (isprime(n-k)) return(n-k); + } + return(-1); +} diff --git a/interface/external/gverb/src/gverbdsp.h b/interface/external/gverb/src/gverbdsp.h new file mode 100644 index 0000000000..8b8b41d169 --- /dev/null +++ b/interface/external/gverb/src/gverbdsp.h @@ -0,0 +1,85 @@ + +#ifndef GVERBDSP_H +#define GVERBDSP_H + +#include "../include/ladspa-util.h" + +typedef struct { + int size; + int idx; + float *buf; +} ty_fixeddelay; + +typedef struct { + int size; + float coeff; + int idx; + float *buf; +} ty_diffuser; + +typedef struct { + float damping; + float delay; +} ty_damper; + +ty_diffuser *diffuser_make(int, float); +void diffuser_free(ty_diffuser *); +void diffuser_flush(ty_diffuser *); +//float diffuser_do(ty_diffuser *, float); + +ty_damper *damper_make(float); +void damper_free(ty_damper *); +void damper_flush(ty_damper *); +//void damper_set(ty_damper *, float); +//float damper_do(ty_damper *, float); + +ty_fixeddelay *fixeddelay_make(int); +void fixeddelay_free(ty_fixeddelay *); +void fixeddelay_flush(ty_fixeddelay *); +//float fixeddelay_read(ty_fixeddelay *, int); +//void fixeddelay_write(ty_fixeddelay *, float); + +int isprime(int); +int nearest_prime(int, float); + +static inline float diffuser_do(ty_diffuser *p, float x) +{ + float y,w; + + w = x - p->buf[p->idx]*p->coeff; + w = flush_to_zero(w); + y = p->buf[p->idx] + w*p->coeff; + p->buf[p->idx] = w; + p->idx = (p->idx + 1) % p->size; + return(y); +} + +static inline float fixeddelay_read(ty_fixeddelay *p, int n) +{ + int i; + + i = (p->idx - n + p->size) % p->size; + return(p->buf[i]); +} + +static inline void fixeddelay_write(ty_fixeddelay *p, float x) +{ + p->buf[p->idx] = x; + p->idx = (p->idx + 1) % p->size; +} + +static inline void damper_set(ty_damper *p, float damping) +{ + p->damping = damping; +} + +static inline float damper_do(ty_damper *p, float x) +{ + float y; + + y = x*(1.0-p->damping) + p->delay*p->damping; + p->delay = y; + return(y); +} + +#endif diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 365064e979..7a55302310 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -123,11 +123,14 @@ Audio::Audio(QObject* parent) : memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL); // Create the noise sample array _noiseSampleFrames = new float[NUMBER_OF_NOISE_SAMPLE_FRAMES]; - + connect(&_receivedAudioStream, &MixedProcessedAudioStream::addedSilence, this, &Audio::addStereoSilenceToScope, Qt::DirectConnection); connect(&_receivedAudioStream, &MixedProcessedAudioStream::addedLastFrameRepeatedWithFade, this, &Audio::addLastFrameRepeatedWithFadeToScope, Qt::DirectConnection); connect(&_receivedAudioStream, &MixedProcessedAudioStream::addedStereoSamples, this, &Audio::addStereoSamplesToScope, Qt::DirectConnection); connect(&_receivedAudioStream, &MixedProcessedAudioStream::processSamples, this, &Audio::processReceivedSamples, Qt::DirectConnection); + + // Initialize GVerb + initGverb(); } void Audio::init(QGLWidget *parent) { @@ -489,6 +492,70 @@ bool Audio::switchOutputToAudioDevice(const QString& outputDeviceName) { return switchOutputToAudioDevice(getNamedAudioDeviceForMode(QAudio::AudioOutput, outputDeviceName)); } +void Audio::initGverb() { + // Initialize a new gverb instance + _gverb = gverb_new(_outputFormat.sampleRate(), _reverbOptions.getMaxRoomSize(), _reverbOptions.getRoomSize(), _reverbOptions.getReverbTime(), + _reverbOptions.getDamping(), _reverbOptions.getSpread(), _reverbOptions.getInputBandwidth(), _reverbOptions.getEarlyLevel(), + _reverbOptions.getTailLevel()); + + // Configure the instance (these functions are not super well named - they actually set several internal variables) + gverb_set_roomsize(_gverb, _reverbOptions.getRoomSize()); + gverb_set_revtime(_gverb, _reverbOptions.getReverbTime()); + gverb_set_damping(_gverb, _reverbOptions.getDamping()); + gverb_set_inputbandwidth(_gverb, _reverbOptions.getInputBandwidth()); + gverb_set_earlylevel(_gverb, DB_CO(_reverbOptions.getEarlyLevel())); + gverb_set_taillevel(_gverb, DB_CO(_reverbOptions.getTailLevel())); +} + +void Audio::setReverbOptions(const AudioEffectOptions* options) { + // Save the new options + _reverbOptions.setMaxRoomSize(options->getMaxRoomSize()); + _reverbOptions.setRoomSize(options->getRoomSize()); + _reverbOptions.setReverbTime(options->getReverbTime()); + _reverbOptions.setDamping(options->getDamping()); + _reverbOptions.setSpread(options->getSpread()); + _reverbOptions.setInputBandwidth(options->getInputBandwidth()); + _reverbOptions.setEarlyLevel(options->getEarlyLevel()); + _reverbOptions.setTailLevel(options->getTailLevel()); + + _reverbOptions.setDryLevel(options->getDryLevel()); + _reverbOptions.setWetLevel(options->getWetLevel()); + + // Apply them to the reverb instance(s) + initGverb(); +} + +void Audio::addReverb(int16_t* samplesData, int numSamples, QAudioFormat& audioFormat) { + float dryFraction = DB_CO(_reverbOptions.getDryLevel()); + float wetFraction = DB_CO(_reverbOptions.getWetLevel()); + + float lValue,rValue; + for (int sample = 0; sample < numSamples; sample += audioFormat.channelCount()) { + // Run GVerb + float value = (float)samplesData[sample]; + gverb_do(_gverb, value, &lValue, &rValue); + + // Mix, accounting for clipping, the left and right channels. Ignore the rest. + for (unsigned int j = sample; j < sample + audioFormat.channelCount(); j++) { + if (j == sample) { + // left channel + int lResult = (int)(samplesData[j] * dryFraction + lValue * wetFraction); + if (lResult > 32767) lResult = 32767; + if (lResult < -32768) lResult = -32768; + samplesData[j] = (int16_t)lResult; + } else if (j == (sample + 1)) { + // right channel + int rResult = (int)(samplesData[j] * dryFraction + rValue * wetFraction); + if (rResult > 32767) rResult = 32767; + if (rResult < -32768) rResult = -32768; + samplesData[j] = (int16_t)rResult; + } else { + // ignore channels above 2 + } + } + } +} + void Audio::handleAudioInput() { static char audioDataPacket[MAX_PACKET_SIZE]; @@ -1060,6 +1127,110 @@ void Audio::toggleStereoInput() { } } +void Audio::processReceivedAudio(const QByteArray& audioByteArray) { + _ringBuffer.parseData(audioByteArray); + + float networkOutputToOutputRatio = (_desiredOutputFormat.sampleRate() / (float) _outputFormat.sampleRate()) + * (_desiredOutputFormat.channelCount() / (float) _outputFormat.channelCount()); + + if (!_ringBuffer.isStarved() && _audioOutput && _audioOutput->bytesFree() == _audioOutput->bufferSize()) { + // we don't have any audio data left in the output buffer + // we just starved + //qDebug() << "Audio output just starved."; + _ringBuffer.setIsStarved(true); + _numFramesDisplayStarve = 10; + } + + // if there is anything in the ring buffer, decide what to do + if (_ringBuffer.samplesAvailable() > 0) { + + int numNetworkOutputSamples = _ringBuffer.samplesAvailable(); + int numDeviceOutputSamples = numNetworkOutputSamples / networkOutputToOutputRatio; + + QByteArray outputBuffer; + outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t)); + + int numSamplesNeededToStartPlayback = NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (_jitterBufferSamples * 2); + + if (!_ringBuffer.isNotStarvedOrHasMinimumSamples(numSamplesNeededToStartPlayback)) { + // We are still waiting for enough samples to begin playback + // qDebug() << numNetworkOutputSamples << " samples so far, waiting for " << numSamplesNeededToStartPlayback; + } else { + // We are either already playing back, or we have enough audio to start playing back. + //qDebug() << "pushing " << numNetworkOutputSamples; + _ringBuffer.setIsStarved(false); + + int16_t* ringBufferSamples = new int16_t[numNetworkOutputSamples]; + if (_processSpatialAudio) { + unsigned int sampleTime = _spatialAudioStart; + QByteArray buffer; + buffer.resize(numNetworkOutputSamples * sizeof(int16_t)); + + _ringBuffer.readSamples((int16_t*)buffer.data(), numNetworkOutputSamples); + // Accumulate direct transmission of audio from sender to receiver + if (Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingIncludeOriginal)) { + emit preProcessOriginalInboundAudio(sampleTime, buffer, _desiredOutputFormat); + addSpatialAudioToBuffer(sampleTime, buffer, numNetworkOutputSamples); + } + + // Send audio off for spatial processing + emit processInboundAudio(sampleTime, buffer, _desiredOutputFormat); + + // copy the samples we'll resample from the spatial audio ring buffer - this also + // pushes the read pointer of the spatial audio ring buffer forwards + _spatialAudioRingBuffer.readSamples(ringBufferSamples, numNetworkOutputSamples); + + // Advance the start point for the next packet of audio to arrive + _spatialAudioStart += numNetworkOutputSamples / _desiredOutputFormat.channelCount(); + } else { + // copy the samples we'll resample from the ring buffer - this also + // pushes the read pointer of the ring buffer forwards + _ringBuffer.readSamples(ringBufferSamples, numNetworkOutputSamples); + } + + // copy the packet from the RB to the output + linearResampling(ringBufferSamples, + (int16_t*) outputBuffer.data(), + numNetworkOutputSamples, + numDeviceOutputSamples, + _desiredOutputFormat, _outputFormat); + + if(_reverb) { + addReverb((int16_t*)outputBuffer.data(), numDeviceOutputSamples, _outputFormat); + } + + if (_outputDevice) { + _outputDevice->write(outputBuffer); + } + + if (_scopeEnabled && !_scopeEnabledPause) { + unsigned int numAudioChannels = _desiredOutputFormat.channelCount(); + int16_t* samples = ringBufferSamples; + for (int numSamples = numNetworkOutputSamples / numAudioChannels; numSamples > 0; numSamples -= NETWORK_SAMPLES_PER_FRAME) { + + unsigned int audioChannel = 0; + addBufferToScope( + _scopeOutputLeft, + _scopeOutputOffset, + samples, audioChannel, numAudioChannels); + + audioChannel = 1; + addBufferToScope( + _scopeOutputRight, + _scopeOutputOffset, + samples, audioChannel, numAudioChannels); + + _scopeOutputOffset += NETWORK_SAMPLES_PER_FRAME; + _scopeOutputOffset %= _samplesPerScope; + samples += NETWORK_SAMPLES_PER_FRAME * numAudioChannels; + } + } + + delete[] ringBufferSamples; + } + } +} + void Audio::processProceduralAudio(int16_t* monoInput, int numSamples) { // zero out the locally injected audio in preparation for audio procedural sounds diff --git a/interface/src/Audio.h b/interface/src/Audio.h index e94e5ab16c..548ae19143 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -44,6 +44,14 @@ #include #include "MixedProcessedAudioStream.h" +#include "AudioEffectOptions.h" +#include +#include + +extern "C" { + #include + #include +} static const int NUM_AUDIO_CHANNELS = 2; @@ -160,6 +168,8 @@ public slots: float getInputVolume() const { return (_audioInput) ? _audioInput->volume() : 0.0f; } void setInputVolume(float volume) { if (_audioInput) _audioInput->setVolume(volume); } + void setReverb(bool reverb) { _reverb = reverb; } + void setReverbOptions(const AudioEffectOptions* options); const AudioStreamStats& getAudioMixerAvatarStreamAudioStats() const { return _audioMixerAvatarStreamAudioStats; } const QHash& getAudioMixerInjectedStreamAudioStatsMap() const { return _audioMixerInjectedStreamAudioStatsMap; } @@ -231,6 +241,9 @@ private: int _proceduralEffectSample; bool _muted; bool _localEcho; + bool _reverb; + AudioEffectOptions _reverbOptions; + ty_gverb *_gverb; GLuint _micTextureId; GLuint _muteTextureId; GLuint _boxTextureId; @@ -250,6 +263,10 @@ private: // 2. Mix with the audio input void processProceduralAudio(int16_t* monoInput, int numSamples); + // Adds Reverb + void initGverb(); + void addReverb(int16_t* samples, int numSamples, QAudioFormat& format); + // Add sounds that we want the user to not hear themselves, by adding on top of mic input signal void addProceduralSounds(int16_t* monoInput, int numSamples); diff --git a/interface/src/scripting/AudioDeviceScriptingInterface.cpp b/interface/src/scripting/AudioDeviceScriptingInterface.cpp index 688b0942d5..bcb5fc308d 100644 --- a/interface/src/scripting/AudioDeviceScriptingInterface.cpp +++ b/interface/src/scripting/AudioDeviceScriptingInterface.cpp @@ -70,3 +70,11 @@ float AudioDeviceScriptingInterface::getInputVolume() { void AudioDeviceScriptingInterface::setInputVolume(float volume) { Application::getInstance()->getAudio()->setInputVolume(volume); } + +void AudioDeviceScriptingInterface::setReverb(bool reverb) { + Application::getInstance()->getAudio()->setReverb(reverb); +} + +void AudioDeviceScriptingInterface::setReverbOptions(const AudioEffectOptions* options) { + Application::getInstance()->getAudio()->setReverbOptions(options); +} diff --git a/interface/src/scripting/AudioDeviceScriptingInterface.h b/interface/src/scripting/AudioDeviceScriptingInterface.h index 62f1153a0b..45bdbc92e2 100644 --- a/interface/src/scripting/AudioDeviceScriptingInterface.h +++ b/interface/src/scripting/AudioDeviceScriptingInterface.h @@ -39,6 +39,8 @@ public slots: float getInputVolume(); void setInputVolume(float volume); + void setReverb(bool reverb); + void setReverbOptions(const AudioEffectOptions* options); }; #endif // hifi_AudioDeviceScriptingInterface_h diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp new file mode 100644 index 0000000000..d2200d8d5e --- /dev/null +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -0,0 +1,12 @@ +// +// AudioEffectOptions.cpp +// hifi +// + +#include "AudioEffectOptions.h" + +AudioEffectOptions::AudioEffectOptions() { } + +QScriptValue AudioEffectOptions::constructor(QScriptContext* context, QScriptEngine* engine) { + return engine->newQObject(new AudioEffectOptions()); +} diff --git a/libraries/audio/src/AudioEffectOptions.h b/libraries/audio/src/AudioEffectOptions.h new file mode 100644 index 0000000000..81a47de08c --- /dev/null +++ b/libraries/audio/src/AudioEffectOptions.h @@ -0,0 +1,99 @@ +// +// AudioEffectOptions.h +// hifi +// + +#ifndef __hifi__AudioEffectOptions__ +#define __hifi__AudioEffectOptions__ + +#include +#include +#include + +class AudioEffectOptions : public QObject { + Q_OBJECT + + // Meters Square + Q_PROPERTY(float maxRoomSize READ getMaxRoomSize WRITE setMaxRoomSize) + Q_PROPERTY(float roomSize READ getRoomSize WRITE setRoomSize) + + // Seconds + Q_PROPERTY(float reverbTime READ getReverbTime WRITE setReverbTime) + + // Ratio between 0 and 1 + Q_PROPERTY(float damping READ getDamping WRITE setDamping) + + // (?) Does not appear to be set externally very often + Q_PROPERTY(float spread READ getSpread WRITE setSpread) + + // Ratio between 0 and 1 + Q_PROPERTY(float inputBandwidth READ getInputBandwidth WRITE setInputBandwidth) + + // in dB + Q_PROPERTY(float earlyLevel READ getEarlyLevel WRITE setEarlyLevel) + Q_PROPERTY(float tailLevel READ getTailLevel WRITE setTailLevel) + Q_PROPERTY(float dryLevel READ getDryLevel WRITE setDryLevel) + Q_PROPERTY(float wetLevel READ getWetLevel WRITE setWetLevel) + +public: + AudioEffectOptions(); + + static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); + + float getRoomSize() const { return _roomSize; } + void setRoomSize(float roomSize ) { _roomSize = roomSize; } + + float getMaxRoomSize() const { return _maxRoomSize; } + void setMaxRoomSize(float maxRoomSize ) { _maxRoomSize = maxRoomSize; } + + float getReverbTime() const { return _reverbTime; } + void setReverbTime(float reverbTime ) { _reverbTime = reverbTime; } + + float getDamping() const { return _damping; } + void setDamping(float damping ) { _damping = damping; } + + float getSpread() const { return _spread; } + void setSpread(float spread ) { _spread = spread; } + + float getInputBandwidth() const { return _inputBandwidth; } + void setInputBandwidth(float inputBandwidth ) { _inputBandwidth = inputBandwidth; } + + float getEarlyLevel() const { return _earlyLevel; } + void setEarlyLevel(float earlyLevel ) { _earlyLevel = earlyLevel; } + + float getTailLevel() const { return _tailLevel; } + void setTailLevel(float tailLevel ) { _tailLevel = tailLevel; } + + float getDryLevel() const { return _dryLevel; } + void setDryLevel(float dryLevel) { _dryLevel = dryLevel; } + + float getWetLevel() const { return _wetLevel; } + void setWetLevel(float wetLevel) { _wetLevel = wetLevel; } + +private: + // http://wiki.audacityteam.org/wiki/GVerb#Instant_Reverberb_settings + + // Meters Square + float _maxRoomSize = 50.0f; + float _roomSize = 50.0f; + + // Seconds + float _reverbTime = 4.0f; + + // Ratio between 0 and 1 + float _damping = 0.5f; + + // ? (Does not appear to be set externally very often) + float _spread = 15.0f; + + // Ratio between 0 and 1 + float _inputBandwidth = 0.75f; + + // dB + float _earlyLevel = -22.0f; + float _tailLevel = -28.0f; + float _dryLevel = 0.0f; + float _wetLevel = 6.0f; +}; + +#endif /* defined(__hifi__AudioEffectOptions__) */ diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 51789aec3a..f3d202cccc 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -41,6 +41,7 @@ #include "ScriptEngine.h" #include "TypedArrays.h" #include "XMLHttpRequestClass.h" +#include "AudioEffectOptions.h" VoxelsScriptingInterface ScriptEngine::_voxelsScriptingInterface; ParticlesScriptingInterface ScriptEngine::_particlesScriptingInterface; @@ -276,6 +277,9 @@ void ScriptEngine::init() { QScriptValue localVoxelsValue = scriptValueFromQMetaObject(); globalObject().setProperty("LocalVoxels", localVoxelsValue); + + QScriptValue audioEffectOptionsConstructorValue = _engine.newFunction(AudioEffectOptions::constructor); + _engine.globalObject().setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue); qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue); qScriptRegisterMetaType(this, inputControllerToScriptValue, inputControllerFromScriptValue); From f09dc1aeaca81fc1a2c8af81f10021c6bb35440b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 14 Oct 2014 15:17:31 -0700 Subject: [PATCH 003/119] remove deprecated _engine member from ScriptEngine --- libraries/script-engine/src/ScriptEngine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index f3d202cccc..8b80dc9b24 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -278,8 +278,8 @@ void ScriptEngine::init() { QScriptValue localVoxelsValue = scriptValueFromQMetaObject(); globalObject().setProperty("LocalVoxels", localVoxelsValue); - QScriptValue audioEffectOptionsConstructorValue = _engine.newFunction(AudioEffectOptions::constructor); - _engine.globalObject().setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue); + QScriptValue audioEffectOptionsConstructorValue = newFunction(AudioEffectOptions::constructor); + globalObject().setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue); qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue); qScriptRegisterMetaType(this, inputControllerToScriptValue, inputControllerFromScriptValue); From 954be926e1114612cfa2536b94d77a0ba4239593 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 14 Oct 2014 15:48:43 -0700 Subject: [PATCH 004/119] Fix cmake --- cmake/modules/FindGverb.cmake | 4 ++-- interface/CMakeLists.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/modules/FindGverb.cmake b/cmake/modules/FindGverb.cmake index 904813c007..80aca29b93 100644 --- a/cmake/modules/FindGverb.cmake +++ b/cmake/modules/FindGverb.cmake @@ -27,11 +27,11 @@ else () if (GVERB_FOUND) if (NOT GVERB_FIND_QUIETLY) - message(STATUS "Found Gverb... ${GVERB_LIBRARIES}") + message(STATUS "Found Gverb: ${GVERB_INCLUDE_DIRS}") endif (NOT GVERB_FIND_QUIETLY) else () if (GVERB_FIND_REQUIRED) - message(FATAL_ERROR "Could not find Gverb") + message(FATAL_ERROR "Could NOT find Gverb") endif (GVERB_FIND_REQUIRED) endif () diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 3caa7c470e..8674dd484a 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -2,7 +2,7 @@ set(TARGET_NAME interface) project(${TARGET_NAME}) # set a default root dir for each of our optional externals if it was not passed -set(OPTIONAL_EXTERNALS "Faceplus" "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp" "SDL2") +set(OPTIONAL_EXTERNALS "Faceplus" "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "GVERB") foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE) if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR) From 0f128509d80b79b3e05b0d487249dd73ade660a4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 16 Oct 2014 10:58:19 -0700 Subject: [PATCH 005/119] removed old processReceivedAudio method --- interface/src/Audio.cpp | 108 ++-------------------------------------- 1 file changed, 4 insertions(+), 104 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 7a55302310..7fdfa61e84 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -951,6 +951,10 @@ void Audio::processReceivedSamples(const QByteArray& inputBuffer, QByteArray& ou numNetworkOutputSamples, numDeviceOutputSamples, _desiredOutputFormat, _outputFormat); + + if(_reverb) { + addReverb((int16_t*)outputBuffer.data(), numDeviceOutputSamples, _outputFormat); + } } void Audio::addReceivedAudioToStream(const QByteArray& audioByteArray) { @@ -1127,110 +1131,6 @@ void Audio::toggleStereoInput() { } } -void Audio::processReceivedAudio(const QByteArray& audioByteArray) { - _ringBuffer.parseData(audioByteArray); - - float networkOutputToOutputRatio = (_desiredOutputFormat.sampleRate() / (float) _outputFormat.sampleRate()) - * (_desiredOutputFormat.channelCount() / (float) _outputFormat.channelCount()); - - if (!_ringBuffer.isStarved() && _audioOutput && _audioOutput->bytesFree() == _audioOutput->bufferSize()) { - // we don't have any audio data left in the output buffer - // we just starved - //qDebug() << "Audio output just starved."; - _ringBuffer.setIsStarved(true); - _numFramesDisplayStarve = 10; - } - - // if there is anything in the ring buffer, decide what to do - if (_ringBuffer.samplesAvailable() > 0) { - - int numNetworkOutputSamples = _ringBuffer.samplesAvailable(); - int numDeviceOutputSamples = numNetworkOutputSamples / networkOutputToOutputRatio; - - QByteArray outputBuffer; - outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t)); - - int numSamplesNeededToStartPlayback = NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (_jitterBufferSamples * 2); - - if (!_ringBuffer.isNotStarvedOrHasMinimumSamples(numSamplesNeededToStartPlayback)) { - // We are still waiting for enough samples to begin playback - // qDebug() << numNetworkOutputSamples << " samples so far, waiting for " << numSamplesNeededToStartPlayback; - } else { - // We are either already playing back, or we have enough audio to start playing back. - //qDebug() << "pushing " << numNetworkOutputSamples; - _ringBuffer.setIsStarved(false); - - int16_t* ringBufferSamples = new int16_t[numNetworkOutputSamples]; - if (_processSpatialAudio) { - unsigned int sampleTime = _spatialAudioStart; - QByteArray buffer; - buffer.resize(numNetworkOutputSamples * sizeof(int16_t)); - - _ringBuffer.readSamples((int16_t*)buffer.data(), numNetworkOutputSamples); - // Accumulate direct transmission of audio from sender to receiver - if (Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingIncludeOriginal)) { - emit preProcessOriginalInboundAudio(sampleTime, buffer, _desiredOutputFormat); - addSpatialAudioToBuffer(sampleTime, buffer, numNetworkOutputSamples); - } - - // Send audio off for spatial processing - emit processInboundAudio(sampleTime, buffer, _desiredOutputFormat); - - // copy the samples we'll resample from the spatial audio ring buffer - this also - // pushes the read pointer of the spatial audio ring buffer forwards - _spatialAudioRingBuffer.readSamples(ringBufferSamples, numNetworkOutputSamples); - - // Advance the start point for the next packet of audio to arrive - _spatialAudioStart += numNetworkOutputSamples / _desiredOutputFormat.channelCount(); - } else { - // copy the samples we'll resample from the ring buffer - this also - // pushes the read pointer of the ring buffer forwards - _ringBuffer.readSamples(ringBufferSamples, numNetworkOutputSamples); - } - - // copy the packet from the RB to the output - linearResampling(ringBufferSamples, - (int16_t*) outputBuffer.data(), - numNetworkOutputSamples, - numDeviceOutputSamples, - _desiredOutputFormat, _outputFormat); - - if(_reverb) { - addReverb((int16_t*)outputBuffer.data(), numDeviceOutputSamples, _outputFormat); - } - - if (_outputDevice) { - _outputDevice->write(outputBuffer); - } - - if (_scopeEnabled && !_scopeEnabledPause) { - unsigned int numAudioChannels = _desiredOutputFormat.channelCount(); - int16_t* samples = ringBufferSamples; - for (int numSamples = numNetworkOutputSamples / numAudioChannels; numSamples > 0; numSamples -= NETWORK_SAMPLES_PER_FRAME) { - - unsigned int audioChannel = 0; - addBufferToScope( - _scopeOutputLeft, - _scopeOutputOffset, - samples, audioChannel, numAudioChannels); - - audioChannel = 1; - addBufferToScope( - _scopeOutputRight, - _scopeOutputOffset, - samples, audioChannel, numAudioChannels); - - _scopeOutputOffset += NETWORK_SAMPLES_PER_FRAME; - _scopeOutputOffset %= _samplesPerScope; - samples += NETWORK_SAMPLES_PER_FRAME * numAudioChannels; - } - } - - delete[] ringBufferSamples; - } - } -} - void Audio::processProceduralAudio(int16_t* monoInput, int numSamples) { // zero out the locally injected audio in preparation for audio procedural sounds From ea7c2e2fa37c2ee715a5f33712061962003cd24d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 16 Oct 2014 15:28:24 -0700 Subject: [PATCH 006/119] Added reverb settings to DS settings --- .../resources/describe-settings.json | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index b8bc783aa1..bb331b63eb 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -154,6 +154,33 @@ "placeholder": "0.18" } ] + }, + { + "name": "reverb", + "type": "table", + "label": "Reverb Settings", + "help": "In this table you can set custom reverb values for each audio zones", + "numbered": true, + "columns": [ + { + "name": "zone", + "label": "Zone", + "can_set": true, + "placeholder": "Audio_Zone" + }, + { + "name": "reverb_time", + "label": "Reverb Time", + "can_set": true, + "placeholder": "(in sec)" + }, + { + "name": "wet_level", + "label": "Wet Level", + "can_set": true, + "placeholder": "(in db)" + } + ] } ] }, From 26b1e8fc29b874b92311120849e15099c352c18c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 16 Oct 2014 22:46:40 -0700 Subject: [PATCH 007/119] grab reverb settings on mixer side --- assignment-client/src/audio/AudioMixer.cpp | 33 ++++++++++++++++++++++ assignment-client/src/audio/AudioMixer.h | 8 +++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 8caf4ddf09..6f709f2ec8 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -1033,6 +1033,39 @@ void AudioMixer::parseSettingsObject(const QJsonObject &settingsObject) { } } } + + const QString REVERB = "reverb"; + if (audioEnvGroupObject[REVERB].isArray()) { + const QJsonArray& reverb = audioEnvGroupObject[REVERB].toArray(); + + const QString ZONE = "zone"; + const QString REVERB_TIME = "reverb_time"; + const QString WET_LEVEL = "wet_level"; + for (int i = 0; i < reverb.count(); ++i) { + QJsonObject reverbObject = reverb[i].toObject(); + + if (reverbObject.contains(ZONE) && + reverbObject.contains(REVERB_TIME) && + reverbObject.contains(WET_LEVEL)) { + + bool okReverbTime, okWetLevel; + QString zone = reverbObject.value(ZONE).toString(); + float reverbTime = reverbObject.value(REVERB_TIME).toString().toFloat(&okReverbTime); + float wetLevel = reverbObject.value(WET_LEVEL).toString().toFloat(&okWetLevel); + + if (okReverbTime && okWetLevel && _audioZones.contains(zone)) { + + ReverbSettings settings; + settings.zone = zone; + settings.reverbTime = reverbTime; + settings.wetLevel = wetLevel; + + _zoneReverbSettings.push_back(settings); + qDebug() << "Added Reverb:" << zone << reverbTime << wetLevel; + } + } + } + } } } diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 3cfa5443a8..ff976dec61 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -82,7 +82,13 @@ private: float coefficient; }; QVector _zonesSettings; - + struct ReverbSettings { + QString zone; + float reverbTime; + float wetLevel; + }; + QVector _zoneReverbSettings; + static InboundAudioStream::Settings _streamSettings; static bool _printStreamStats; From 37b47b52d376f4a33342eec11d92dbfdf8b86379 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Oct 2014 11:49:57 -0700 Subject: [PATCH 008/119] Stream reverb settings from mixer to interface --- assignment-client/src/audio/AudioMixer.cpp | 28 ++++++++++++++++++++-- interface/src/Audio.cpp | 22 +++++++++++++---- libraries/audio/src/InboundAudioStream.cpp | 21 +++++++++++++--- libraries/audio/src/InboundAudioStream.h | 9 +++++++ 4 files changed, 70 insertions(+), 10 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 6f709f2ec8..f4e0ed2466 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -428,8 +428,8 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l } int AudioMixer::prepareMixForListeningNode(Node* node) { - AvatarAudioStream* nodeAudioStream = ((AudioMixerClientData*) node->getLinkedData())->getAvatarAudioStream(); - AudioMixerClientData* listenerNodeData = (AudioMixerClientData*)node->getLinkedData(); + AvatarAudioStream* nodeAudioStream = static_cast(node->getLinkedData())->getAvatarAudioStream(); + AudioMixerClientData* listenerNodeData = static_cast(node->getLinkedData()); // zero out the client mix for this node memset(_preMixSamples, 0, sizeof(_preMixSamples)); @@ -730,6 +730,30 @@ void AudioMixer::run() { memcpy(dataAt, &sequence, sizeof(quint16)); dataAt += sizeof(quint16); + // Pack stream properties + for (int i = 0; i < _zoneReverbSettings.size(); ++i) { + glm::vec3 streamPosition = static_cast(node->getLinkedData())->getAvatarAudioStream()->getPosition(); + if (_audioZones[_zoneReverbSettings[i].zone].contains(streamPosition)) { + bool hasReverb = true; + float reverbTime = _zoneReverbSettings[i].reverbTime; + float wetLevel = _zoneReverbSettings[i].wetLevel; + + memcpy(dataAt, &hasReverb, sizeof(bool)); + dataAt += sizeof(bool); + memcpy(dataAt, &reverbTime, sizeof(float)); + dataAt += sizeof(float); + memcpy(dataAt, &wetLevel, sizeof(float)); + dataAt += sizeof(float); + + qDebug() << "Out" << sequence << reverbTime << wetLevel; + } else { + bool hasReverb = false; + memcpy(dataAt, &hasReverb, sizeof(bool)); + dataAt += sizeof(bool); + } + } + + // pack mixed audio samples memcpy(dataAt, _mixSamples, NETWORK_BUFFER_LENGTH_BYTES_STEREO); dataAt += NETWORK_BUFFER_LENGTH_BYTES_STEREO; diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 7fdfa61e84..e566ce77b9 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -787,7 +787,6 @@ void Audio::handleAudioInput() { NodeList* nodeList = NodeList::getInstance(); SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer); - if (_recorder && _recorder.data()->isRecording()) { _recorder.data()->record(reinterpret_cast(networkAudioSamples), numNetworkBytes); } @@ -907,12 +906,10 @@ void Audio::addLastFrameRepeatedWithFadeToScope(int samplesPerChannel) { } void Audio::processReceivedSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer) { - const int numNetworkOutputSamples = inputBuffer.size() / sizeof(int16_t); const int numDeviceOutputSamples = numNetworkOutputSamples * (_outputFormat.sampleRate() * _outputFormat.channelCount()) / (_desiredOutputFormat.sampleRate() * _desiredOutputFormat.channelCount()); - outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t)); const int16_t* receivedSamples; @@ -952,13 +949,28 @@ void Audio::processReceivedSamples(const QByteArray& inputBuffer, QByteArray& ou numDeviceOutputSamples, _desiredOutputFormat, _outputFormat); - if(_reverb) { + if (_receivedAudioStream.hasReverb()) { + bool reverbChanged = false; + + if (_reverbOptions.getReverbTime() != _receivedAudioStream.getRevebTime()) { + _reverbOptions.setReverbTime(_receivedAudioStream.getRevebTime()); + reverbChanged = true; + } + if (_reverbOptions.getWetLevel() != _receivedAudioStream.getWetLevel()) { + _reverbOptions.setWetLevel(_receivedAudioStream.getWetLevel()); + reverbChanged = true; + } + if (reverbChanged) { + initGverb(); + } + } + + if(_reverb || _receivedAudioStream.hasReverb()) { addReverb((int16_t*)outputBuffer.data(), numDeviceOutputSamples, _outputFormat); } } void Audio::addReceivedAudioToStream(const QByteArray& audioByteArray) { - if (_audioOutput) { // Audio output must exist and be correctly set up if we're going to process received audio _receivedAudioStream.parseData(audioByteArray); diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index dda57d87da..e92e7c32d6 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -44,7 +44,8 @@ InboundAudioStream::InboundAudioStream(int numFrameSamples, int numFramesCapacit _framesAvailableStat(), _currentJitterBufferFrames(0), _timeGapStatsForStatsPacket(0, STATS_FOR_STATS_PACKET_WINDOW_SECONDS), - _repetitionWithFade(settings._repetitionWithFade) + _repetitionWithFade(settings._repetitionWithFade), + _hasReverb(false) { } @@ -162,9 +163,23 @@ int InboundAudioStream::parseData(const QByteArray& packet) { } int InboundAudioStream::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) { + int read = 0; + if (type == PacketTypeMixedAudio) { + memcpy(&_hasReverb, packetAfterSeqNum.data() + read, sizeof(bool)); + read += sizeof(bool); + + if (_hasReverb) { + memcpy(&_reverbTime, packetAfterSeqNum.data() + read, sizeof(float)); + read += sizeof(float); + memcpy(&_wetLevel, packetAfterSeqNum.data() + read, sizeof(float)); + read += sizeof(float); + qDebug() << "In" << _reverbTime << _wetLevel; + } + } + // mixed audio packets do not have any info between the seq num and the audio data. - numAudioSamples = packetAfterSeqNum.size() / sizeof(int16_t); - return 0; + numAudioSamples = (packetAfterSeqNum.size() - read) / sizeof(int16_t); + return read; } int InboundAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) { diff --git a/libraries/audio/src/InboundAudioStream.h b/libraries/audio/src/InboundAudioStream.h index a395b1c6c8..3e69db0afb 100644 --- a/libraries/audio/src/InboundAudioStream.h +++ b/libraries/audio/src/InboundAudioStream.h @@ -154,6 +154,10 @@ public: int getOverflowCount() const { return _ringBuffer.getOverflowCount(); } int getPacketsReceived() const { return _incomingSequenceNumberStats.getReceived(); } + + bool hasReverb() const { return _hasReverb; } + float getRevebTime() const { return _reverbTime; } + float getWetLevel() const { return _wetLevel; } public slots: /// This function should be called every second for all the stats to function properly. If dynamic jitter buffers @@ -243,6 +247,11 @@ protected: MovingMinMaxAvg _timeGapStatsForStatsPacket; bool _repetitionWithFade; + + // Reverb properties + bool _hasReverb; + float _reverbTime; + float _wetLevel; }; float calculateRepeatedFrameFadeFactor(int indexOfRepeat); From ce949b73508b98e1029be9862e97ea4e60ff1db0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Oct 2014 12:11:29 -0700 Subject: [PATCH 009/119] Coding Standard default values --- libraries/audio/src/AudioEffectOptions.cpp | 13 ++++++++++++- libraries/audio/src/AudioEffectOptions.h | 20 ++++++++++---------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp index d2200d8d5e..4653085d5e 100644 --- a/libraries/audio/src/AudioEffectOptions.cpp +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -5,7 +5,18 @@ #include "AudioEffectOptions.h" -AudioEffectOptions::AudioEffectOptions() { } +AudioEffectOptions::AudioEffectOptions() : + _maxRoomSize(50.0f), + _roomSize(50.0f), + _reverbTime(4.0f), + _damping(0.5f), + _spread(15.0f), + _inputBandwidth(0.75f), + _earlyLevel(-22.0f), + _tailLevel(-28.0f), + _dryLevel(0.0f), + _wetLevel(6.0f) { +} QScriptValue AudioEffectOptions::constructor(QScriptContext* context, QScriptEngine* engine) { return engine->newQObject(new AudioEffectOptions()); diff --git a/libraries/audio/src/AudioEffectOptions.h b/libraries/audio/src/AudioEffectOptions.h index 81a47de08c..18965f3a91 100644 --- a/libraries/audio/src/AudioEffectOptions.h +++ b/libraries/audio/src/AudioEffectOptions.h @@ -74,26 +74,26 @@ private: // http://wiki.audacityteam.org/wiki/GVerb#Instant_Reverberb_settings // Meters Square - float _maxRoomSize = 50.0f; - float _roomSize = 50.0f; + float _maxRoomSize; + float _roomSize; // Seconds - float _reverbTime = 4.0f; + float _reverbTime; // Ratio between 0 and 1 - float _damping = 0.5f; + float _damping; // ? (Does not appear to be set externally very often) - float _spread = 15.0f; + float _spread; // Ratio between 0 and 1 - float _inputBandwidth = 0.75f; + float _inputBandwidth; // dB - float _earlyLevel = -22.0f; - float _tailLevel = -28.0f; - float _dryLevel = 0.0f; - float _wetLevel = 6.0f; + float _earlyLevel; + float _tailLevel; + float _dryLevel; + float _wetLevel; }; #endif /* defined(__hifi__AudioEffectOptions__) */ From 997f1db8359634a8efa56f8db0e67315aa1bb1de Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Oct 2014 13:37:49 -0700 Subject: [PATCH 010/119] handle JSON for audioEffectOptions args --- libraries/audio/src/AudioEffectOptions.cpp | 46 +++++++++++++++++++++- libraries/audio/src/AudioEffectOptions.h | 2 +- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp index 4653085d5e..dbe9b51e5b 100644 --- a/libraries/audio/src/AudioEffectOptions.cpp +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -5,7 +5,18 @@ #include "AudioEffectOptions.h" -AudioEffectOptions::AudioEffectOptions() : +static const QString MAX_ROOM_SIZE_HANDLE = "maxRoomSize"; +static const QString ROOM_SIZE_HANDLE = "roomSize"; +static const QString REVERB_TIME_HANDLE = "reverbTime"; +static const QString DAMPIMG_HANDLE = "damping"; +static const QString SPREAD_HANDLE = "spread"; +static const QString INPUT_BANDWIDTH_HANDLE = "inputBandwidth"; +static const QString EARLY_LEVEL_HANDLE = "earlyLevel"; +static const QString TAIL_LEVEL_HANDLE = "tailLevel"; +static const QString DRY_LEVEL_HANDLE = "dryLevel"; +static const QString WET_LEVEL_HANDLE = "wetLevel"; + +AudioEffectOptions::AudioEffectOptions(QScriptValue arguments) : _maxRoomSize(50.0f), _roomSize(50.0f), _reverbTime(4.0f), @@ -16,8 +27,39 @@ AudioEffectOptions::AudioEffectOptions() : _tailLevel(-28.0f), _dryLevel(0.0f), _wetLevel(6.0f) { + if (arguments.property(MAX_ROOM_SIZE_HANDLE).isNumber()) { + _maxRoomSize = arguments.property(MAX_ROOM_SIZE_HANDLE).toNumber(); + } + if (arguments.property(ROOM_SIZE_HANDLE).isNumber()) { + _roomSize = arguments.property(ROOM_SIZE_HANDLE).toNumber(); + } + if (arguments.property(REVERB_TIME_HANDLE).isNumber()) { + _reverbTime = arguments.property(REVERB_TIME_HANDLE).toNumber(); + } + if (arguments.property(DAMPIMG_HANDLE).isNumber()) { + _damping = arguments.property(DAMPIMG_HANDLE).toNumber(); + } + if (arguments.property(SPREAD_HANDLE).isNumber()) { + _spread = arguments.property(SPREAD_HANDLE).toNumber(); + } + if (arguments.property(INPUT_BANDWIDTH_HANDLE).isNumber()) { + _inputBandwidth = arguments.property(INPUT_BANDWIDTH_HANDLE).toNumber(); + } + if (arguments.property(EARLY_LEVEL_HANDLE).isNumber()) { + _earlyLevel = arguments.property(EARLY_LEVEL_HANDLE).toNumber(); + } + if (arguments.property(TAIL_LEVEL_HANDLE).isNumber()) { + _tailLevel = arguments.property(TAIL_LEVEL_HANDLE).toNumber(); + } + if (arguments.property(DRY_LEVEL_HANDLE).isNumber()) { + _dryLevel = arguments.property(DRY_LEVEL_HANDLE).toNumber(); + } + if (arguments.property(WET_LEVEL_HANDLE).isNumber()) { + _wetLevel = arguments.property(WET_LEVEL_HANDLE).toNumber(); + } + } QScriptValue AudioEffectOptions::constructor(QScriptContext* context, QScriptEngine* engine) { - return engine->newQObject(new AudioEffectOptions()); + return engine->newQObject(new AudioEffectOptions(context->argument(0))); } diff --git a/libraries/audio/src/AudioEffectOptions.h b/libraries/audio/src/AudioEffectOptions.h index 18965f3a91..b3db9fd0f7 100644 --- a/libraries/audio/src/AudioEffectOptions.h +++ b/libraries/audio/src/AudioEffectOptions.h @@ -36,7 +36,7 @@ class AudioEffectOptions : public QObject { Q_PROPERTY(float wetLevel READ getWetLevel WRITE setWetLevel) public: - AudioEffectOptions(); + AudioEffectOptions(QScriptValue arguments = QScriptValue()); static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); From 5a11104bdf92ee0ac6eaa45a68a8ad56deeaa09c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Oct 2014 13:45:16 -0700 Subject: [PATCH 011/119] Updated script --- examples/audioReverbOff.js | 12 ----------- examples/audioReverbOn.js | 43 ++++++++++++++++++++++---------------- 2 files changed, 25 insertions(+), 30 deletions(-) delete mode 100644 examples/audioReverbOff.js diff --git a/examples/audioReverbOff.js b/examples/audioReverbOff.js deleted file mode 100644 index 1076a825a7..0000000000 --- a/examples/audioReverbOff.js +++ /dev/null @@ -1,12 +0,0 @@ -// -// audioReverbOff.js -// examples -// -// 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 -// -// -AudioDevice.setReverb(false); -print("Reberb is now off."); diff --git a/examples/audioReverbOn.js b/examples/audioReverbOn.js index 6d43c31943..479f5bba74 100644 --- a/examples/audioReverbOn.js +++ b/examples/audioReverbOn.js @@ -8,25 +8,32 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // http://wiki.audacityteam.org/wiki/GVerb#Instant_reverb_settings -var audioOptions = new AudioEffectOptions(); - -// Square Meters -audioOptions.maxRoomSize = 50; -audioOptions.roomSize = 50; - -// Seconds -audioOptions.reverbTime = 4; - -// Between 0 - 1 -audioOptions.damping = 0.50; -audioOptions.inputBandwidth = 0.75; - -// dB -audioOptions.earlyLevel = -22; -audioOptions.tailLevel = -28; -audioOptions.dryLevel = 0; -audioOptions.wetLevel = 6; +var audioOptions = new AudioEffectOptions({ + // Square Meters + maxRoomSize: 50, + roomSize: 50, + + // Seconds + reverbTime: 4, + + // Between 0 - 1 + damping: 0.50, + inputBandwidth: 0.75, + + // dB + earlyLevel: -22, + tailLevel: -28, + dryLevel: 0, + wetLevel: 6 +}); AudioDevice.setReverbOptions(audioOptions); AudioDevice.setReverb(true); print("Reverb is now on with the updated options."); + +function scriptEnding() { + AudioDevice.setReverb(false); + print("Reberb is now off."); +} + +Script.scriptEnding.connect(scriptEnding); \ No newline at end of file From 6f9557fe672200bba31211a33b3939c9df9f0ae4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Oct 2014 15:06:02 -0700 Subject: [PATCH 012/119] Do not destroy script reverb settings --- assignment-client/src/audio/AudioMixer.cpp | 2 - interface/src/Audio.cpp | 84 ++++++++++++---------- interface/src/Audio.h | 4 +- libraries/audio/src/AudioEffectOptions.cpp | 20 +++++- libraries/audio/src/AudioEffectOptions.h | 2 + libraries/audio/src/InboundAudioStream.cpp | 1 - 6 files changed, 69 insertions(+), 44 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index f4e0ed2466..9b91dd8c1e 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -744,8 +744,6 @@ void AudioMixer::run() { dataAt += sizeof(float); memcpy(dataAt, &wetLevel, sizeof(float)); dataAt += sizeof(float); - - qDebug() << "Out" << sequence << reverbTime << wetLevel; } else { bool hasReverb = false; memcpy(dataAt, &hasReverb, sizeof(bool)); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index e566ce77b9..ff41da6e81 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -494,40 +494,43 @@ bool Audio::switchOutputToAudioDevice(const QString& outputDeviceName) { void Audio::initGverb() { // Initialize a new gverb instance - _gverb = gverb_new(_outputFormat.sampleRate(), _reverbOptions.getMaxRoomSize(), _reverbOptions.getRoomSize(), _reverbOptions.getReverbTime(), - _reverbOptions.getDamping(), _reverbOptions.getSpread(), _reverbOptions.getInputBandwidth(), _reverbOptions.getEarlyLevel(), - _reverbOptions.getTailLevel()); + _gverb = gverb_new(_outputFormat.sampleRate(), _reverbOptions->getMaxRoomSize(), _reverbOptions->getRoomSize(), + _reverbOptions->getReverbTime(), _reverbOptions->getDamping(), _reverbOptions->getSpread(), + _reverbOptions->getInputBandwidth(), _reverbOptions->getEarlyLevel(), + _reverbOptions->getTailLevel()); // Configure the instance (these functions are not super well named - they actually set several internal variables) - gverb_set_roomsize(_gverb, _reverbOptions.getRoomSize()); - gverb_set_revtime(_gverb, _reverbOptions.getReverbTime()); - gverb_set_damping(_gverb, _reverbOptions.getDamping()); - gverb_set_inputbandwidth(_gverb, _reverbOptions.getInputBandwidth()); - gverb_set_earlylevel(_gverb, DB_CO(_reverbOptions.getEarlyLevel())); - gverb_set_taillevel(_gverb, DB_CO(_reverbOptions.getTailLevel())); + gverb_set_roomsize(_gverb, _reverbOptions->getRoomSize()); + gverb_set_revtime(_gverb, _reverbOptions->getReverbTime()); + gverb_set_damping(_gverb, _reverbOptions->getDamping()); + gverb_set_inputbandwidth(_gverb, _reverbOptions->getInputBandwidth()); + gverb_set_earlylevel(_gverb, DB_CO(_reverbOptions->getEarlyLevel())); + gverb_set_taillevel(_gverb, DB_CO(_reverbOptions->getTailLevel())); } void Audio::setReverbOptions(const AudioEffectOptions* options) { // Save the new options - _reverbOptions.setMaxRoomSize(options->getMaxRoomSize()); - _reverbOptions.setRoomSize(options->getRoomSize()); - _reverbOptions.setReverbTime(options->getReverbTime()); - _reverbOptions.setDamping(options->getDamping()); - _reverbOptions.setSpread(options->getSpread()); - _reverbOptions.setInputBandwidth(options->getInputBandwidth()); - _reverbOptions.setEarlyLevel(options->getEarlyLevel()); - _reverbOptions.setTailLevel(options->getTailLevel()); + _scriptReverbOptions.setMaxRoomSize(options->getMaxRoomSize()); + _scriptReverbOptions.setRoomSize(options->getRoomSize()); + _scriptReverbOptions.setReverbTime(options->getReverbTime()); + _scriptReverbOptions.setDamping(options->getDamping()); + _scriptReverbOptions.setSpread(options->getSpread()); + _scriptReverbOptions.setInputBandwidth(options->getInputBandwidth()); + _scriptReverbOptions.setEarlyLevel(options->getEarlyLevel()); + _scriptReverbOptions.setTailLevel(options->getTailLevel()); - _reverbOptions.setDryLevel(options->getDryLevel()); - _reverbOptions.setWetLevel(options->getWetLevel()); + _scriptReverbOptions.setDryLevel(options->getDryLevel()); + _scriptReverbOptions.setWetLevel(options->getWetLevel()); - // Apply them to the reverb instance(s) - initGverb(); + if (_reverbOptions == &_scriptReverbOptions) { + // Apply them to the reverb instance(s) + initGverb(); + } } void Audio::addReverb(int16_t* samplesData, int numSamples, QAudioFormat& audioFormat) { - float dryFraction = DB_CO(_reverbOptions.getDryLevel()); - float wetFraction = DB_CO(_reverbOptions.getWetLevel()); + float dryFraction = DB_CO(_reverbOptions->getDryLevel()); + float wetFraction = DB_CO(_reverbOptions->getWetLevel()); float lValue,rValue; for (int sample = 0; sample < numSamples; sample += audioFormat.channelCount()) { @@ -949,23 +952,26 @@ void Audio::processReceivedSamples(const QByteArray& inputBuffer, QByteArray& ou numDeviceOutputSamples, _desiredOutputFormat, _outputFormat); - if (_receivedAudioStream.hasReverb()) { - bool reverbChanged = false; - - if (_reverbOptions.getReverbTime() != _receivedAudioStream.getRevebTime()) { - _reverbOptions.setReverbTime(_receivedAudioStream.getRevebTime()); - reverbChanged = true; - } - if (_reverbOptions.getWetLevel() != _receivedAudioStream.getWetLevel()) { - _reverbOptions.setWetLevel(_receivedAudioStream.getWetLevel()); - reverbChanged = true; - } - if (reverbChanged) { - initGverb(); - } - } - if(_reverb || _receivedAudioStream.hasReverb()) { + if (_receivedAudioStream.hasReverb()) { + _reverbOptions = &_zoneReverbOptions; + + bool reverbChanged = false; + if (_zoneReverbOptions.getReverbTime() != _receivedAudioStream.getRevebTime()) { + _zoneReverbOptions.setReverbTime(_receivedAudioStream.getRevebTime()); + reverbChanged = true; + } + if (_zoneReverbOptions.getWetLevel() != _receivedAudioStream.getWetLevel()) { + _zoneReverbOptions.setWetLevel(_receivedAudioStream.getWetLevel()); + reverbChanged = true; + } + if (reverbChanged) { + initGverb(); + } + } else { + _reverbOptions = &_scriptReverbOptions; + } + addReverb((int16_t*)outputBuffer.data(), numDeviceOutputSamples, _outputFormat); } } diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 7390a3c28c..900b6ce0d6 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -241,7 +241,9 @@ private: bool _muted; bool _localEcho; bool _reverb; - AudioEffectOptions _reverbOptions; + AudioEffectOptions _scriptReverbOptions; + AudioEffectOptions _zoneReverbOptions; + AudioEffectOptions* _reverbOptions; ty_gverb *_gverb; GLuint _micTextureId; GLuint _muteTextureId; diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp index dbe9b51e5b..8f1acd7ec0 100644 --- a/libraries/audio/src/AudioEffectOptions.cpp +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -57,7 +57,25 @@ AudioEffectOptions::AudioEffectOptions(QScriptValue arguments) : if (arguments.property(WET_LEVEL_HANDLE).isNumber()) { _wetLevel = arguments.property(WET_LEVEL_HANDLE).toNumber(); } - +} + +AudioEffectOptions::AudioEffectOptions(const AudioEffectOptions &other) { + *this = other; +} + +AudioEffectOptions& AudioEffectOptions::operator=(const AudioEffectOptions &other) { + _maxRoomSize = other._maxRoomSize; + _roomSize = other._roomSize; + _reverbTime = other._reverbTime; + _damping = other._damping; + _spread = other._spread; + _inputBandwidth = other._inputBandwidth; + _earlyLevel = other._earlyLevel; + _tailLevel = other._tailLevel; + _dryLevel = other._dryLevel; + _wetLevel = other._wetLevel; + + return *this; } QScriptValue AudioEffectOptions::constructor(QScriptContext* context, QScriptEngine* engine) { diff --git a/libraries/audio/src/AudioEffectOptions.h b/libraries/audio/src/AudioEffectOptions.h index b3db9fd0f7..ae99face0f 100644 --- a/libraries/audio/src/AudioEffectOptions.h +++ b/libraries/audio/src/AudioEffectOptions.h @@ -37,6 +37,8 @@ class AudioEffectOptions : public QObject { public: AudioEffectOptions(QScriptValue arguments = QScriptValue()); + AudioEffectOptions(const AudioEffectOptions &other); + AudioEffectOptions& operator=(const AudioEffectOptions &other); static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index e92e7c32d6..59578951f8 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -173,7 +173,6 @@ int InboundAudioStream::parseStreamProperties(PacketType type, const QByteArray& read += sizeof(float); memcpy(&_wetLevel, packetAfterSeqNum.data() + read, sizeof(float)); read += sizeof(float); - qDebug() << "In" << _reverbTime << _wetLevel; } } From 94f66ef37a12585a822cf465aa29d9b7bd2b3214 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Oct 2014 15:35:01 -0700 Subject: [PATCH 013/119] Reverb logic tweaks --- interface/src/Audio.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index ff41da6e81..527703f7a4 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -92,6 +92,8 @@ Audio::Audio(QObject* parent) : _collisionSoundDuration(0.0f), _proceduralEffectSample(0), _muted(false), + _reverb(false), + _reverbOptions(&_scriptReverbOptions), _processSpatialAudio(false), _spatialAudioStart(0), _spatialAudioFinish(0), @@ -531,7 +533,7 @@ void Audio::setReverbOptions(const AudioEffectOptions* options) { void Audio::addReverb(int16_t* samplesData, int numSamples, QAudioFormat& audioFormat) { float dryFraction = DB_CO(_reverbOptions->getDryLevel()); float wetFraction = DB_CO(_reverbOptions->getWetLevel()); - + float lValue,rValue; for (int sample = 0; sample < numSamples; sample += audioFormat.channelCount()) { // Run GVerb @@ -953,10 +955,9 @@ void Audio::processReceivedSamples(const QByteArray& inputBuffer, QByteArray& ou _desiredOutputFormat, _outputFormat); if(_reverb || _receivedAudioStream.hasReverb()) { + bool reverbChanged = false; if (_receivedAudioStream.hasReverb()) { - _reverbOptions = &_zoneReverbOptions; - bool reverbChanged = false; if (_zoneReverbOptions.getReverbTime() != _receivedAudioStream.getRevebTime()) { _zoneReverbOptions.setReverbTime(_receivedAudioStream.getRevebTime()); reverbChanged = true; @@ -965,13 +966,19 @@ void Audio::processReceivedSamples(const QByteArray& inputBuffer, QByteArray& ou _zoneReverbOptions.setWetLevel(_receivedAudioStream.getWetLevel()); reverbChanged = true; } - if (reverbChanged) { - initGverb(); + + if (_reverbOptions != &_zoneReverbOptions) { + _reverbOptions = &_zoneReverbOptions; + reverbChanged = true; } - } else { + } else if (_reverbOptions != &_scriptReverbOptions) { _reverbOptions = &_scriptReverbOptions; + reverbChanged = true; } + if (reverbChanged) { + initGverb(); + } addReverb((int16_t*)outputBuffer.data(), numDeviceOutputSamples, _outputFormat); } } From 585403629615859f635dfbc894ad93d963967051 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Oct 2014 16:02:59 -0700 Subject: [PATCH 014/119] cmake fix for ubuntu --- interface/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 1d86e7601b..1c9c68ec5f 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -2,7 +2,7 @@ set(TARGET_NAME interface) project(${TARGET_NAME}) # set a default root dir for each of our optional externals if it was not passed -set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "GVERB") +set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "Gverb") foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE) if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR) From 7c54da033cb1b87917564e0f3c73cfac5e02d43d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Oct 2014 16:29:19 -0700 Subject: [PATCH 015/119] Changed reverb time label --- domain-server/resources/describe-settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index a34b854b8e..026fe252b2 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -170,7 +170,7 @@ }, { "name": "reverb_time", - "label": "Reverb Time", + "label": "Reverb Decay Time", "can_set": true, "placeholder": "(in sec)" }, From ee4c7c25bfb7672073b54ee987315c1aaf621142 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Oct 2014 16:50:49 -0700 Subject: [PATCH 016/119] Header fix --- libraries/script-engine/src/ScriptEngine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index e1459d4f2c..bab3e0ce4a 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -40,7 +41,6 @@ #include "ScriptEngine.h" #include "TypedArrays.h" #include "XMLHttpRequestClass.h" -#include "AudioEffectOptions.h" VoxelsScriptingInterface ScriptEngine::_voxelsScriptingInterface; EntityScriptingInterface ScriptEngine::_entityScriptingInterface; From 9a7ca8b1324e96634c22d0e674f2ef53f81e74ac Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Oct 2014 17:23:58 -0700 Subject: [PATCH 017/119] Fix header --- libraries/audio/src/AudioEffectOptions.cpp | 7 ++++++- libraries/audio/src/AudioEffectOptions.h | 13 +++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp index 8f1acd7ec0..480779afd2 100644 --- a/libraries/audio/src/AudioEffectOptions.cpp +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -1,6 +1,11 @@ // // AudioEffectOptions.cpp -// hifi +// libraries/audio/src +// +// 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 "AudioEffectOptions.h" diff --git a/libraries/audio/src/AudioEffectOptions.h b/libraries/audio/src/AudioEffectOptions.h index ae99face0f..97aac7c82c 100644 --- a/libraries/audio/src/AudioEffectOptions.h +++ b/libraries/audio/src/AudioEffectOptions.h @@ -1,10 +1,15 @@ // // AudioEffectOptions.h -// hifi +// libraries/audio/src +// +// 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__AudioEffectOptions__ -#define __hifi__AudioEffectOptions__ +#ifndef hifi_AudioEffectOptions_h +#define hifi_AudioEffectOptions_h #include #include @@ -98,4 +103,4 @@ private: float _wetLevel; }; -#endif /* defined(__hifi__AudioEffectOptions__) */ +#endif // hifi_AudioEffectOptions_h From 047ee0a51353d22b7660feda83cd552c0d4965e6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 21 Oct 2014 12:20:12 -0700 Subject: [PATCH 018/119] pipe texture names through to NetworkTexture --- interface/src/renderer/GeometryCache.cpp | 4 ++++ interface/src/renderer/GeometryCache.h | 2 +- interface/src/renderer/TextureCache.h | 5 ++++- libraries/fbx/src/FBXReader.cpp | 23 ++++++++++++++++------- libraries/fbx/src/FBXReader.h | 2 +- 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index 107dac62f5..c34a5a8d7a 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -405,6 +405,7 @@ void GeometryCache::renderGrid(int xDivisions, int yDivisions) { } QSharedPointer GeometryCache::getGeometry(const QUrl& url, const QUrl& fallback, bool delayLoad) { + qDebug() << "Getting a resource at" << url; return getResource(url, fallback, delayLoad).staticCast(); } @@ -727,18 +728,21 @@ void NetworkGeometry::setGeometry(const FBXGeometry& geometry) { networkPart.diffuseTexture = Application::getInstance()->getTextureCache()->getTexture( _textureBase.resolved(QUrl(part.diffuseTexture.filename)), DEFAULT_TEXTURE, mesh.isEye, part.diffuseTexture.content); + networkPart.diffuseTexture->setName(part.diffuseTexture.name); networkPart.diffuseTexture->setLoadPriorities(_loadPriorities); } if (!part.normalTexture.filename.isEmpty()) { networkPart.normalTexture = Application::getInstance()->getTextureCache()->getTexture( _textureBase.resolved(QUrl(part.normalTexture.filename)), NORMAL_TEXTURE, false, part.normalTexture.content); + networkPart.normalTexture->setName(part.normalTexture.name); networkPart.normalTexture->setLoadPriorities(_loadPriorities); } if (!part.specularTexture.filename.isEmpty()) { networkPart.specularTexture = Application::getInstance()->getTextureCache()->getTexture( _textureBase.resolved(QUrl(part.specularTexture.filename)), SPECULAR_TEXTURE, false, part.specularTexture.content); + networkPart.specularTexture->setName(part.specularTexture.name); networkPart.specularTexture->setLoadPriorities(_loadPriorities); } networkMesh.parts.append(networkPart); diff --git a/interface/src/renderer/GeometryCache.h b/interface/src/renderer/GeometryCache.h index e0ada10e5b..1f45825c61 100644 --- a/interface/src/renderer/GeometryCache.h +++ b/interface/src/renderer/GeometryCache.h @@ -136,7 +136,7 @@ private: /// The state associated with a single mesh part. class NetworkMeshPart { -public: +public: QSharedPointer diffuseTexture; QSharedPointer normalTexture; diff --git a/interface/src/renderer/TextureCache.h b/interface/src/renderer/TextureCache.h index 11ce312fa3..29740621e3 100644 --- a/interface/src/renderer/TextureCache.h +++ b/interface/src/renderer/TextureCache.h @@ -145,6 +145,9 @@ public: /// Returns the lazily-computed average texture color. const QColor& getAverageColor() const { return _averageColor; } + + const QString& getName() const { return _name; } + void setName(const QString& name) { _name = name; } protected: @@ -156,7 +159,7 @@ protected: virtual void imageLoaded(const QImage& image); private: - + QString _name; TextureType _type; bool _translucent; QColor _averageColor; diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index e735e2e47b..2a51a83ab8 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -984,10 +984,13 @@ public: QVector values; }; -FBXTexture getTexture(const QString& textureID, const QHash& textureFilenames, - const QHash& textureContent) { +FBXTexture getTexture(const QString& textureID, + const QHash& textureNames, + const QHash& textureFilenames, + const QHash& textureContent) { FBXTexture texture; texture.filename = textureFilenames.value(textureID); + texture.name = textureNames.value(textureID); texture.content = textureContent.value(texture.filename); return texture; } @@ -1012,6 +1015,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) QHash models; QHash clusters; QHash animationCurves; + QHash textureNames; QHash textureFilenames; QHash textureContent; QHash materials; @@ -1278,6 +1282,11 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) QByteArray filename = subobject.properties.at(0).toByteArray(); filename = filename.mid(qMax(filename.lastIndexOf('\\'), filename.lastIndexOf('/')) + 1); textureFilenames.insert(getID(object.properties), filename); + } else if (subobject.name == "TextureName") { + // trim the name from the timestamp + QString name = QString(subobject.properties.at(0).toByteArray()); + name = name.left(name.indexOf('[')); + textureNames.insert(getID(object.properties), name); } } } else if (object.name == "Video") { @@ -1612,12 +1621,12 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) FBXTexture diffuseTexture; QString diffuseTextureID = diffuseTextures.value(childID); if (!diffuseTextureID.isNull()) { - diffuseTexture = getTexture(diffuseTextureID, textureFilenames, textureContent); + diffuseTexture = getTexture(diffuseTextureID, textureNames, textureFilenames, textureContent); // FBX files generated by 3DSMax have an intermediate texture parent, apparently foreach (const QString& childTextureID, childMap.values(diffuseTextureID)) { if (textureFilenames.contains(childTextureID)) { - diffuseTexture = getTexture(diffuseTextureID, textureFilenames, textureContent); + diffuseTexture = getTexture(diffuseTextureID, textureNames, textureFilenames, textureContent); } } } @@ -1625,14 +1634,14 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) FBXTexture normalTexture; QString bumpTextureID = bumpTextures.value(childID); if (!bumpTextureID.isNull()) { - normalTexture = getTexture(bumpTextureID, textureFilenames, textureContent); + normalTexture = getTexture(bumpTextureID, textureNames, textureFilenames, textureContent); generateTangents = true; } FBXTexture specularTexture; QString specularTextureID = specularTextures.value(childID); if (!specularTextureID.isNull()) { - specularTexture = getTexture(specularTextureID, textureFilenames, textureContent); + specularTexture = getTexture(specularTextureID, textureNames, textureFilenames, textureContent); } for (int j = 0; j < extracted.partMaterialTextures.size(); j++) { @@ -1658,7 +1667,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) materialIndex++; } else if (textureFilenames.contains(childID)) { - FBXTexture texture = getTexture(childID, textureFilenames, textureContent); + FBXTexture texture = getTexture(childID, textureNames, textureFilenames, textureContent); for (int j = 0; j < extracted.partMaterialTextures.size(); j++) { int partTexture = extracted.partMaterialTextures.at(j).second; if (partTexture == textureIndex && !(partTexture == 0 && materialsHaveTextures)) { diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index cbf0cfcca6..49b0534438 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -95,7 +95,7 @@ public: /// A texture map in an FBX document. class FBXTexture { public: - + QString name; QByteArray filename; QByteArray content; }; From 76afc32c1a1b72c6404c4a1cf3686cb947b80ad3 Mon Sep 17 00:00:00 2001 From: Ryan Date: Tue, 21 Oct 2014 15:28:06 -0700 Subject: [PATCH 019/119] making hair look and move more like Rick James and less like Blondie --- interface/src/Hair.cpp | 6 +++--- interface/src/Hair.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/Hair.cpp b/interface/src/Hair.cpp index e9c110d4ac..6ca0d4a899 100644 --- a/interface/src/Hair.cpp +++ b/interface/src/Hair.cpp @@ -92,7 +92,7 @@ Hair::Hair(int strands, } } -const float SOUND_THRESHOLD = 50.0f; +const float SOUND_THRESHOLD = 40.0f; void Hair::simulate(float deltaTime) { deltaTime = glm::clamp(deltaTime, 0.0f, 1.0f / 30.0f); @@ -121,13 +121,13 @@ void Hair::simulate(float deltaTime) { (_radius - glm::length(_hairPosition[vertexIndex])); } // Add random thing driven by loudness - float loudnessFactor = (_loudness > SOUND_THRESHOLD) ? logf(_loudness - SOUND_THRESHOLD) / 8000.0f : 0.0f; + float loudnessFactor = (_loudness > SOUND_THRESHOLD) ? logf(_loudness - SOUND_THRESHOLD) / 2000.0f : 0.0f; const float QUIESCENT_LOUDNESS = 0.0f; _hairPosition[vertexIndex] += randVector() * (QUIESCENT_LOUDNESS + loudnessFactor) * ((float)link / (float)_links); // Add gravity - const float SCALE_GRAVITY = 0.10f; + const float SCALE_GRAVITY = 0.13f; _hairPosition[vertexIndex] += _gravity * deltaTime * SCALE_GRAVITY; // Add linear acceleration diff --git a/interface/src/Hair.h b/interface/src/Hair.h index 036d137cd3..f799140c53 100644 --- a/interface/src/Hair.h +++ b/interface/src/Hair.h @@ -26,7 +26,7 @@ const int HAIR_CONSTRAINTS = 2; const int DEFAULT_HAIR_STRANDS = 20; const int DEFAULT_HAIR_LINKS = 10; const float DEFAULT_HAIR_RADIUS = 0.15f; -const float DEFAULT_HAIR_LINK_LENGTH = 0.04f; +const float DEFAULT_HAIR_LINK_LENGTH = 0.06f; const float DEFAULT_HAIR_THICKNESS = 0.025f; class Hair { From cc28fe958eccc7f46d3c16892aa1cd1b9afdb95a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 21 Oct 2014 15:44:34 -0700 Subject: [PATCH 020/119] add a hack method to NetworkGeometry to change a material texture by name --- interface/src/renderer/GeometryCache.cpp | 18 ++++++++++++++++++ interface/src/renderer/GeometryCache.h | 2 ++ interface/src/renderer/Model.h | 3 +++ 3 files changed, 23 insertions(+) diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index c34a5a8d7a..35765c50b8 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -613,6 +613,24 @@ void NetworkGeometry::clearLoadPriority(const QPointer& owner) { } } +void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& url) { + for (int i = 0; i < _meshes.size(); i++) { + NetworkMesh& mesh = _meshes[i]; + for (int j = 0; j < mesh.parts.size(); j++) { + NetworkMeshPart& part = mesh.parts[j]; + + QSharedPointer matchingTexture = QSharedPointer(); + if (part.diffuseTexture->getName() == name) { + part.diffuseTexture = + Application::getInstance()->getTextureCache()->getTexture(url, DEFAULT_TEXTURE, + _geometry.meshes[i].isEye, QByteArray()); + part.diffuseTexture->setName(name); + part.diffuseTexture->setLoadPriorities(_loadPriorities); + } + } + } +} + /// Reads geometry in a worker thread. class GeometryReader : public QRunnable { public: diff --git a/interface/src/renderer/GeometryCache.h b/interface/src/renderer/GeometryCache.h index 1f45825c61..461d622a02 100644 --- a/interface/src/renderer/GeometryCache.h +++ b/interface/src/renderer/GeometryCache.h @@ -107,6 +107,8 @@ public: virtual void setLoadPriorities(const QHash, float>& priorities); virtual void clearLoadPriority(const QPointer& owner); + void setTextureWithNameToURL(const QString& name, const QUrl& url); + protected: virtual void init(); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 86fa0c2b7a..3618d8103e 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -183,6 +183,9 @@ public: void inverseKinematics(int jointIndex, glm::vec3 position, const glm::quat& rotation, float priority); + void setTextureWithNameToURL(const QString& name, const QUrl& url) + { _geometry->setTextureWithNameToURL(name, url); } + protected: QSharedPointer _geometry; From fc39e827347694dc6b97f6a2b87e9994287603a6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 21 Oct 2014 16:11:58 -0700 Subject: [PATCH 021/119] allow a texture change in ModelOverlay properties --- interface/src/ui/overlays/ModelOverlay.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 12f54f02d9..ac3d7b8a2b 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -102,6 +102,16 @@ void ModelOverlay::setProperties(const QScriptValue &properties) { } _updateModel = true; } + + QScriptValue texturesValue = properties.property("textures"); + if (texturesValue.isValid()) { + QVariantMap textureMap = texturesValue.toVariant().toMap(); + foreach(const QString& key, textureMap.keys()) { + QUrl newTextureURL = textureMap[key].toUrl(); + qDebug() << "Updating texture named" << key << "to texture at URL" << newTextureURL; + _model.setTextureWithNameToURL(key, newTextureURL); + } + } if (properties.property("position").isValid()) { _updateModel = true; From d81158f941760be32fdc59697dd7c54c8ae7c76c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 21 Oct 2014 17:45:21 -0700 Subject: [PATCH 022/119] Remove Gverb source code --- interface/external/gverb/CMakeLists.txt | 2 - .../external/gverb/include/ladspa-util.h | 234 ----------- interface/external/gverb/include/lv2.h | 392 ------------------ interface/external/gverb/src/gverb.c | 207 --------- interface/external/gverb/src/gverb.h | 234 ----------- interface/external/gverb/src/gverbdsp.c | 130 ------ interface/external/gverb/src/gverbdsp.h | 85 ---- 7 files changed, 1284 deletions(-) delete mode 100644 interface/external/gverb/CMakeLists.txt delete mode 100644 interface/external/gverb/include/ladspa-util.h delete mode 100644 interface/external/gverb/include/lv2.h delete mode 100644 interface/external/gverb/src/gverb.c delete mode 100644 interface/external/gverb/src/gverb.h delete mode 100644 interface/external/gverb/src/gverbdsp.c delete mode 100644 interface/external/gverb/src/gverbdsp.h diff --git a/interface/external/gverb/CMakeLists.txt b/interface/external/gverb/CMakeLists.txt deleted file mode 100644 index 140b45b727..0000000000 --- a/interface/external/gverb/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -cmake_minimum_required(VERSION 2.8) -add_library(gverb include/ladspa-util.h include/lv2.h src/gverb.h src/gverb.c src/gverbdsp.h src/gverbdsp.c) diff --git a/interface/external/gverb/include/ladspa-util.h b/interface/external/gverb/include/ladspa-util.h deleted file mode 100644 index 149d0aaacd..0000000000 --- a/interface/external/gverb/include/ladspa-util.h +++ /dev/null @@ -1,234 +0,0 @@ -/* Some misc util functions for audio DSP work, written by Steve Harris, - * December 2000 - * - * steve@plugin.org.uk - */ - -#ifndef LADSPA_UTIL_H -#define LADSPA_UTIL_H - -#include -#include -#include - -#define buffer_write(a, b) a=(b) - -// 16.16 fixpoint -typedef union { - int32_t all; - struct { -#ifdef WORDS_BIGENDIAN - int16_t in; - uint16_t fr; -#else - uint16_t fr; - int16_t in; -#endif - } part; -} fixp16; - -// 32.32 fixpoint -typedef union { - int64_t all; - struct { -#ifdef WORDS_BIGENDIAN - int32_t in; - uint32_t fr; -#else - uint32_t fr; - int32_t in; -#endif - } part; -} fixp32; - -/* 32 bit "pointer cast" union */ -typedef union { - float f; - int32_t i; -} ls_pcast32; - -// Sometimes it doesn't get defined, even though it eists and C99 is declared -long int lrintf (float x); - -// 1.0 / ln(2) -#define LN2R 1.442695041f - -/* detet floating point denormal numbers by comparing them to the smallest - * normal, crap, but reliable */ -#define DN_CHECK(x, l) if (fabs(x) < 1e-38) printf("DN: "l"\n") - -// Denormalise floats, only actually needed for PIII and recent PowerPC -//#define FLUSH_TO_ZERO(fv) (((*(unsigned int*)&(fv))&0x7f800000)==0)?0.0f:(fv) - -static inline float flush_to_zero(float f) -{ - ls_pcast32 v; - - v.f = f; - - // original: return (v.i & 0x7f800000) == 0 ? 0.0f : f; - // version from Tim Blechmann - return (v.i & 0x7f800000) < 0x08000000 ? 0.0f : f; -} - -static inline void round_to_zero(volatile float *f) -{ - *f += 1e-18; - *f -= 1e-18; -} - -/* A set of branchless clipping operations from Laurent de Soras */ - -static inline float f_max(float x, float a) -{ - x -= a; - x += fabs(x); - x *= 0.5; - x += a; - - return x; -} - -static inline float f_min(float x, float b) -{ - x = b - x; - x += fabs(x); - x *= 0.5; - x = b - x; - - return x; -} - -static inline float f_clamp(float x, float a, float b) -{ - const float x1 = fabs(x - a); - const float x2 = fabs(x - b); - - x = x1 + a + b; - x -= x2; - x *= 0.5; - - return x; -} - -// Limit a value to be l<=v<=u -#define LIMIT(v,l,u) ((v)<(l)?(l):((v)>(u)?(u):(v))) - -// Truncate-to-zero modulo (ANSI C doesn't specify) will only work -// if -m < v < 2m -#define MOD(v,m) (v<0?v+m:(v>=m?v-m:v)) - -// Truncate-to-zero modulo (ANSI C doesn't specify) will only work -// if v > -m and v < m -#define NEG_MOD(v,m) ((v)<0?((v)+(m)):(v)) - -// Convert a value in dB's to a coefficent -#define DB_CO(g) ((g) > -90.0f ? powf(10.0f, (g) * 0.05f) : 0.0f) -#define CO_DB(v) (20.0f * log10f(v)) - -// Linearly interpolate [ = a * (1 - f) + b * f] -#define LIN_INTERP(f,a,b) ((a) + (f) * ((b) - (a))) - -// Cubic interpolation function -static inline float cube_interp(const float fr, const float inm1, const float - in, const float inp1, const float inp2) -{ - return in + 0.5f * fr * (inp1 - inm1 + - fr * (4.0f * inp1 + 2.0f * inm1 - 5.0f * in - inp2 + - fr * (3.0f * (in - inp1) - inm1 + inp2))); -} - -/* fast sin^2 aproxiamtion, adapted from jan AT rpgfan's posting to the - * music-dsp list */ -static inline float f_sin_sq(float angle) -{ - const float asqr = angle * angle; - float result = -2.39e-08f; - - result *= asqr; - result += 2.7526e-06f; - result *= asqr; - result -= 1.98409e-04f; - result *= asqr; - result += 8.3333315e-03f; - result *= asqr; - result -= 1.666666664e-01f; - result *= asqr; - result += 1.0f; - result *= angle; - - return result * result; -} - -#ifdef HAVE_LRINTF - -#define f_round(f) lrintf(f) - -#else - -// Round float to int using IEEE int* hack -static inline int f_round(float f) -{ - ls_pcast32 p; - - p.f = f; - p.f += (3<<22); - - return p.i - 0x4b400000; -} - -#endif - -// Truncate float to int -static inline int f_trunc(float f) -{ - return f_round(floorf(f)); -} - -/* Andrew Simper's pow(2, x) aproximation from the music-dsp list */ - -#if 0 - -/* original */ -static inline float f_pow2(float x) -{ - long *px = (long*)(&x); // store address of float as long pointer - const float tx = (x-0.5f) + (3<<22); // temporary value for truncation - const long lx = *((long*)&tx) - 0x4b400000; // integer power of 2 - const float dx = x-(float)(lx); // float remainder of power of 2 - - x = 1.0f + dx*(0.6960656421638072f + // cubic apporoximation of 2^x - dx*(0.224494337302845f + // for x in the range [0, 1] - dx*(0.07944023841053369f))); - *px += (lx<<23); // add integer power of 2 to exponent - - return x; -} - -#else - -/* union version */ -static inline float f_pow2(float x) -{ - ls_pcast32 *px, tx, lx; - float dx; - - px = (ls_pcast32 *)&x; // store address of float as long pointer - tx.f = (x-0.5f) + (3<<22); // temporary value for truncation - lx.i = tx.i - 0x4b400000; // integer power of 2 - dx = x - (float)lx.i; // float remainder of power of 2 - - x = 1.0f + dx * (0.6960656421638072f + // cubic apporoximation of 2^x - dx * (0.224494337302845f + // for x in the range [0, 1] - dx * (0.07944023841053369f))); - (*px).i += (lx.i << 23); // add integer power of 2 to exponent - - return (*px).f; -} - -#endif - -/* Fast exponentiation function, y = e^x */ -#define f_exp(x) f_pow2(x * LN2R) - -#endif diff --git a/interface/external/gverb/include/lv2.h b/interface/external/gverb/include/lv2.h deleted file mode 100644 index d5257824c6..0000000000 --- a/interface/external/gverb/include/lv2.h +++ /dev/null @@ -1,392 +0,0 @@ -/* LV2 - LADSPA (Linux Audio Developer's Simple Plugin API) Version 2 - * Revision 1 - * - * Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis, - * Stefan Westerfeld. - * Copyright (C) 2006-2008 Steve Harris, Dave Robillard. - * - * This header is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation; either version 2.1 of the License, - * or (at your option) any later version. - * - * This header is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 - * USA. - */ - -#ifndef LV2_H_INCLUDED -#define LV2_H_INCLUDED - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -/* ************************************************************************* */ - - -/** @file lv2.h - * - * Revision: 1 - * - * == Overview == - * - * There are a large number of open source and free software synthesis - * packages in use or development at this time. This API ('LV2') - * attempts to give programmers the ability to write simple 'plugin' - * audio processors in C/C++ and link them dynamically ('plug') into - * a range of these packages ('hosts'). It should be possible for any - * host and any plugin to communicate completely through this interface. - * - * This API is deliberately as short and simple as possible. - * The information required to use a plugin is in a companion data - * (RDF) file. The shared library portion of the API (defined in this - * header) does not contain enough information to make use of the plugin - * possible - the data file is mandatory. - * - * Plugins are expected to distinguish between control rate and audio - * rate data (or other types of data defined by extensions). Plugins have - * 'ports' that are inputs or outputs and each plugin is 'run' for a 'block' - * corresponding to a short time interval measured in samples. Audio rate - * data is communicated using arrays with one element per sample processed, - * allowing a block of audio to be processed by the plugin in a single - * pass. Control rate data is communicated using single values. Control - * rate data has a single value at the start of a call to the 'run()' - * function, and may be considered to remain this value for its duration. - * Thus the 'control rate' is determined by the block size, controlled by - * the host. The plugin may assume that all its input and output ports have - * been connected to the relevant data location (see the 'connect_port()' - * function below) before it is asked to run, unless the port has been set - * 'connection optional' in the plugin's data file. - * - * Plugins will reside in shared object files suitable for dynamic linking - * by dlopen() and family. The file will provide a number of 'plugin - * types' that can be used to instantiate actual plugins (sometimes known - * as 'plugin instances') that can be connected together to perform tasks. - * The host can access these plugin types using the lv2_descriptor() - * function. - * - * This API contains very limited error-handling. - * - * == Threading rules == - * - * Certain hosts may need to call the functions provided by a plugin from - * multiple threads. For this to be safe, the plugin must be written so that - * those functions can be executed simultaneously without problems. - * To facilitate this, the functions provided by a plugin are divided into - * classes: - * - * - Discovery class: lv2_descriptor(), extension_data() - * - Instantiation class: instantiate(), cleanup(), activate(), deactivate() - * - Audio class: run(), connect_port() - * - * Extensions to this specification which add new functions MUST declare in - * which of these classes the functions belong, or define new classes for them. - * The rules that hosts must follow are these: - * - * - When a function from the Discovery class is running, no other - * functions in the same shared object file may run. - * - When a function from the Instantiation class is running for a plugin - * instance, no other functions for that instance may run. - * - When a function is running for a plugin instance, no other - * function in the same class may run for that instance. - * - * Any simultaneous calls that are not explicitly forbidden by these rules - * are allowed. For example, a host may call run() for two different plugin - * instances simultaneously. - */ - - -/* ************************************************************************* */ - - -/** Plugin Handle. - * - * This plugin handle indicates a particular instance of the plugin - * concerned. It is valid to compare this to NULL (0 for C++) but - * otherwise the host MUST NOT attempt to interpret it. The plugin - * may use it to reference internal instance data. */ -typedef void * LV2_Handle; - - -/* ************************************************************************* */ - - -/** Feature data. - * - * These are passed to a plugin's instantiate method to represent a special - * feature the host has which the plugin may depend on. This is to allow - * extensions to the LV2 specification without causing any breakage. - * Extensions may specify what data needs to be passed here. The base - * LV2 specification does not define any features; hosts are not required - * to use this facility. */ -typedef struct _LV2_Feature { - /** A globally unique, case-sensitive identifier for this feature. - * - * This MUST be defined in the specification of any LV2 extension which - * defines a host feature. */ - const char * URI; - - /** Pointer to arbitrary data. - * - * This is to allow hosts to pass data to a plugin (simple values, data - * structures, function pointers, etc) as part of a 'feature'. The LV2 - * specification makes no restrictions on the contents of this data. - * The data here MUST be cleary defined by the LV2 extension which defines - * this feature. - * If no data is required, this may be set to NULL. */ - void * data; -} LV2_Feature; - - -/* ************************************************************************* */ - - -/** Descriptor for a Type of Plugin. - * - * This structure is used to describe a plugin type. It provides a number - * of functions to instantiate it, link it to buffers and run it. */ -typedef struct _LV2_Descriptor { - - /** A globally unique, case-sensitive identifier for this plugin type. - * - * All plugins with the same URI MUST be compatible in terms of 'port - * signature', meaning they have the same number of ports, same port - * shortnames, and roughly the same functionality. URIs should - * probably contain a version number (or similar) for this reason. - * - * Rationale: When serializing session/patch/etc files, hosts MUST - * refer to a loaded plugin by the plugin URI only. In the future - * loading a plugin with this URI MUST yield a plugin with the - * same ports (etc) which is 100% compatible. */ - const char * URI; - - /** Function pointer that instantiates a plugin. - * - * A handle is returned indicating the new plugin instance. The - * instantiation function accepts a sample rate as a parameter as well - * as the plugin descriptor from which this instantiate function was - * found. This function must return NULL if instantiation fails. - * - * bundle_path is a string of the path to the LV2 bundle which contains - * this plugin binary. It MUST include the trailing directory separator - * (e.g. '/') so that BundlePath + filename gives the path to a file - * in the bundle. - * - * features is a NULL terminated array of LV2_Feature structs which - * represent the features the host supports. Plugins may refuse to - * instantiate if required features are not found here (however hosts - * SHOULD NOT use this as a discovery mechanism, instead reading the - * data file before attempting to instantiate the plugin). This array - * must always exist; if a host has no features, it MUST pass a single - * element array containing NULL (to simplify plugins). - * - * Note that instance initialisation should generally occur in - * activate() rather than here. If a host calls instantiate, it MUST - * call cleanup() at some point in the future. */ - LV2_Handle (*instantiate)(const struct _LV2_Descriptor * descriptor, - double sample_rate, - const char * bundle_path, - const LV2_Feature *const * features); - - /** Function pointer that connects a port on a plugin instance to a memory - * location where the block of data for the port will be read/written. - * - * The data location is expected to be of the type defined in the - * plugin's data file (e.g. an array of float for an lv2:AudioPort). - * Memory issues are managed by the host. The plugin must read/write - * the data at these locations every time run() is called, data - * present at the time of this connection call MUST NOT be - * considered meaningful. - * - * The host MUST NOT try to connect a data buffer to a port index - * that is not defined in the RDF data for the plugin. If it does, - * the plugin's behaviour is undefined. - * - * connect_port() may be called more than once for a plugin instance - * to allow the host to change the buffers that the plugin is reading - * or writing. These calls may be made before or after activate() - * or deactivate() calls. Note that there may be realtime constraints - * on connect_port (see lv2:hardRTCapable in lv2.ttl). - * - * connect_port() MUST be called at least once for each port before - * run() is called. The plugin must pay careful attention to the block - * size passed to the run function as the block allocated may only just - * be large enough to contain the block of data (typically samples), and - * is not guaranteed to be constant. - * - * Plugin writers should be aware that the host may elect to use the - * same buffer for more than one port and even use the same buffer for - * both input and output (see lv2:inPlaceBroken in lv2.ttl). - * However, overlapped buffers or use of a single buffer for both - * audio and control data may result in unexpected behaviour. - * - * If the plugin has the feature lv2:hardRTCapable then there are - * various things that the plugin MUST NOT do within the connect_port() - * function (see lv2.ttl). */ - void (*connect_port)(LV2_Handle instance, - uint32_t port, - void * data_location); - - /** Function pointer that initialises a plugin instance and activates - * it for use. - * - * This is separated from instantiate() to aid real-time support and so - * that hosts can reinitialise a plugin instance by calling deactivate() - * and then activate(). In this case the plugin instance must reset all - * state information dependent on the history of the plugin instance - * except for any data locations provided by connect_port(). If there - * is nothing for activate() to do then the plugin writer may provide - * a NULL rather than an empty function. - * - * When present, hosts MUST call this function once before run() - * is called for the first time. This call SHOULD be made as close - * to the run() call as possible and indicates to real-time plugins - * that they are now live, however plugins MUST NOT rely on a prompt - * call to run() after activate(). activate() may not be called again - * unless deactivate() is called first (after which activate() may be - * called again, followed by deactivate, etc. etc.). If a host calls - * activate, it MUST call deactivate at some point in the future. - * - * Note that connect_port() may be called before or after a call to - * activate(). */ - void (*activate)(LV2_Handle instance); - - /** Function pointer that runs a plugin instance for a block. - * - * Two parameters are required: the first is a handle to the particular - * instance to be run and the second indicates the block size (in - * samples) for which the plugin instance may run. - * - * Note that if an activate() function exists then it must be called - * before run(). If deactivate() is called for a plugin instance then - * the plugin instance may not be reused until activate() has been - * called again. - * - * If the plugin has the feature lv2:hardRTCapable then there are - * various things that the plugin MUST NOT do within the run() - * function (see lv2.ttl). */ - void (*run)(LV2_Handle instance, - uint32_t sample_count); - - /** This is the counterpart to activate() (see above). If there is - * nothing for deactivate() to do then the plugin writer may provide - * a NULL rather than an empty function. - * - * Hosts must deactivate all activated units after they have been run() - * for the last time. This call SHOULD be made as close to the last - * run() call as possible and indicates to real-time plugins that - * they are no longer live, however plugins MUST NOT rely on prompt - * deactivation. Note that connect_port() may be called before or - * after a call to deactivate(). - * - * Note that deactivation is not similar to pausing as the plugin - * instance will be reinitialised when activate() is called to reuse it. - * Hosts MUST NOT call deactivate() unless activate() was previously - * called. */ - void (*deactivate)(LV2_Handle instance); - - /** This is the counterpart to instantiate() (see above). Once an instance - * of a plugin has been finished with it can be deleted using this - * function. The instance handle passed ceases to be valid after - * this call. - * - * If activate() was called for a plugin instance then a corresponding - * call to deactivate() MUST be made before cleanup() is called. - * Hosts MUST NOT call cleanup() unless instantiate() was previously - * called. */ - void (*cleanup)(LV2_Handle instance); - - /** Function pointer that can be used to return additional instance data for - * a plugin defined by some extenion (e.g. a struct containing additional - * function pointers). - * - * The actual type and meaning of the returned object MUST be specified - * precisely by the extension if it defines any extra data. If a particular - * extension does not define extra instance data, this function MUST return - * NULL for that extension's URI. If a plugin does not support any - * extensions that define extra instance data, this function pointer may be - * set to NULL rather than providing an empty function. - * - * The only parameter is the URI of the extension. The plugin MUST return - * NULL if it does not support the extension, but hosts SHOULD NOT use this - * as a discovery method (e.g. hosts should only call this function for - * extensions known to be supported by the plugin from the data file). - * - * The host is never responsible for freeing the returned value. - * - * NOTE: This function should return a struct (likely containing function - * pointers) and NOT a direct function pointer. Standard C and C++ do not - * allow type casts from void* to a function pointer type. To provide - * additional functions a struct should be returned containing the extra - * function pointers (which is valid standard code, and a much better idea - * for extensibility anyway). */ - const void* (*extension_data)(const char * uri); - -} LV2_Descriptor; - - -/* ****************************************************************** */ - - -/** Accessing Plugin Types. - * - * The exact mechanism by which plugins are loaded is host-dependent, - * however all most hosts will need to know is the URI of the plugin they - * wish to load. The environment variable LV2_PATH, if present, should - * contain a colon-separated path indicating directories (containing - * plugin bundle subdirectories) that should be searched (in order) - * for plugins. It is expected that hosts will use a library to provide - * this functionality. - * - * A plugin programmer must include a function called "lv2_descriptor" - * with the following function prototype within the shared object - * file. This function will have C-style linkage (if you are using - * C++ this is taken care of by the 'extern "C"' clause at the top of - * the file). - * - * A host will find the plugin shared object file by one means or another, - * find the lv2_descriptor() function, call it, and proceed from there. - * - * Plugin types are accessed by index (not ID) using values from 0 - * upwards. Out of range indexes must result in this function returning - * NULL, so the plugin count can be determined by checking for the least - * index that results in NULL being returned. Index has no meaning, - * hosts MUST NOT depend on it remaining constant (ie when serialising) - * in any way. */ -const LV2_Descriptor * lv2_descriptor(uint32_t index); - - -/** Datatype corresponding to the lv2_descriptor() function. */ -typedef const LV2_Descriptor * -(*LV2_Descriptor_Function)(uint32_t index); - - -/* ******************************************************************** */ - - -/* Put this (LV2_SYMBOL_EXPORT) before any functions that are to be loaded - * by the host as a symbol from the dynamic library. - */ -#ifdef WIN32 -#define LV2_SYMBOL_EXPORT __declspec(dllexport) -#else -#define LV2_SYMBOL_EXPORT -#endif - - -#ifdef __cplusplus -} -#endif - -#endif /* LV2_H_INCLUDED */ - diff --git a/interface/external/gverb/src/gverb.c b/interface/external/gverb/src/gverb.c deleted file mode 100644 index e3980232bc..0000000000 --- a/interface/external/gverb/src/gverb.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - - Copyright (C) 1999 Juhana Sadeharju - kouhia at nic.funet.fi - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - - -#include -#include -#include -#include -#include "gverbdsp.h" -#include "gverb.h" -#include "../include/ladspa-util.h" - -ty_gverb *gverb_new(int srate, float maxroomsize, float roomsize, - float revtime, - float damping, float spread, - float inputbandwidth, float earlylevel, - float taillevel) -{ - ty_gverb *p; - float ga,gb,gt; - int i,n; - float r; - float diffscale; - int a,b,c,cc,d,dd,e; - float spread1,spread2; - - p = (ty_gverb *)malloc(sizeof(ty_gverb)); - p->rate = srate; - p->fdndamping = damping; - p->maxroomsize = maxroomsize; - p->roomsize = roomsize; - p->revtime = revtime; - p->earlylevel = earlylevel; - p->taillevel = taillevel; - - p->maxdelay = p->rate*p->maxroomsize/340.0; - p->largestdelay = p->rate*p->roomsize/340.0; - - - /* Input damper */ - - p->inputbandwidth = inputbandwidth; - p->inputdamper = damper_make(1.0 - p->inputbandwidth); - - - /* FDN section */ - - - p->fdndels = (ty_fixeddelay **)calloc(FDNORDER, sizeof(ty_fixeddelay *)); - for(i = 0; i < FDNORDER; i++) { - p->fdndels[i] = fixeddelay_make((int)p->maxdelay+1000); - } - p->fdngains = (float *)calloc(FDNORDER, sizeof(float)); - p->fdnlens = (int *)calloc(FDNORDER, sizeof(int)); - - p->fdndamps = (ty_damper **)calloc(FDNORDER, sizeof(ty_damper *)); - for(i = 0; i < FDNORDER; i++) { - p->fdndamps[i] = damper_make(p->fdndamping); - } - - ga = 60.0; - gt = p->revtime; - ga = powf(10.0f,-ga/20.0f); - n = p->rate*gt; - p->alpha = pow((double)ga, 1.0/(double)n); - - gb = 0.0; - for(i = 0; i < FDNORDER; i++) { - if (i == 0) gb = 1.000000*p->largestdelay; - if (i == 1) gb = 0.816490*p->largestdelay; - if (i == 2) gb = 0.707100*p->largestdelay; - if (i == 3) gb = 0.632450*p->largestdelay; - -#if 0 - p->fdnlens[i] = nearest_prime((int)gb, 0.5); -#else - p->fdnlens[i] = f_round(gb); -#endif - p->fdngains[i] = -powf((float)p->alpha,p->fdnlens[i]); - } - - p->d = (float *)calloc(FDNORDER, sizeof(float)); - p->u = (float *)calloc(FDNORDER, sizeof(float)); - p->f = (float *)calloc(FDNORDER, sizeof(float)); - - /* Diffuser section */ - - diffscale = (float)p->fdnlens[3]/(210+159+562+410); - spread1 = spread; - spread2 = 3.0*spread; - - b = 210; - r = 0.125541; - a = spread1*r; - c = 210+159+a; - cc = c-b; - r = 0.854046; - a = spread2*r; - d = 210+159+562+a; - dd = d-c; - e = 1341-d; - - p->ldifs = (ty_diffuser **)calloc(4, sizeof(ty_diffuser *)); - p->ldifs[0] = diffuser_make((int)(diffscale*b),0.75); - p->ldifs[1] = diffuser_make((int)(diffscale*cc),0.75); - p->ldifs[2] = diffuser_make((int)(diffscale*dd),0.625); - p->ldifs[3] = diffuser_make((int)(diffscale*e),0.625); - - b = 210; - r = -0.568366; - a = spread1*r; - c = 210+159+a; - cc = c-b; - r = -0.126815; - a = spread2*r; - d = 210+159+562+a; - dd = d-c; - e = 1341-d; - - p->rdifs = (ty_diffuser **)calloc(4, sizeof(ty_diffuser *)); - p->rdifs[0] = diffuser_make((int)(diffscale*b),0.75); - p->rdifs[1] = diffuser_make((int)(diffscale*cc),0.75); - p->rdifs[2] = diffuser_make((int)(diffscale*dd),0.625); - p->rdifs[3] = diffuser_make((int)(diffscale*e),0.625); - - - - /* Tapped delay section */ - - p->tapdelay = fixeddelay_make(44000); - p->taps = (int *)calloc(FDNORDER, sizeof(int)); - p->tapgains = (float *)calloc(FDNORDER, sizeof(float)); - - p->taps[0] = 5+0.410*p->largestdelay; - p->taps[1] = 5+0.300*p->largestdelay; - p->taps[2] = 5+0.155*p->largestdelay; - p->taps[3] = 5+0.000*p->largestdelay; - - for(i = 0; i < FDNORDER; i++) { - p->tapgains[i] = pow(p->alpha,(double)p->taps[i]); - } - - return(p); -} - -void gverb_free(ty_gverb *p) -{ - int i; - - damper_free(p->inputdamper); - for(i = 0; i < FDNORDER; i++) { - fixeddelay_free(p->fdndels[i]); - damper_free(p->fdndamps[i]); - diffuser_free(p->ldifs[i]); - diffuser_free(p->rdifs[i]); - } - free(p->fdndels); - free(p->fdngains); - free(p->fdnlens); - free(p->fdndamps); - free(p->d); - free(p->u); - free(p->f); - free(p->ldifs); - free(p->rdifs); - free(p->taps); - free(p->tapgains); - fixeddelay_free(p->tapdelay); - free(p); -} - -void gverb_flush(ty_gverb *p) -{ - int i; - - damper_flush(p->inputdamper); - for(i = 0; i < FDNORDER; i++) { - fixeddelay_flush(p->fdndels[i]); - damper_flush(p->fdndamps[i]); - diffuser_flush(p->ldifs[i]); - diffuser_flush(p->rdifs[i]); - } - memset(p->d, 0, FDNORDER * sizeof(float)); - memset(p->u, 0, FDNORDER * sizeof(float)); - memset(p->f, 0, FDNORDER * sizeof(float)); - fixeddelay_flush(p->tapdelay); -} - -/* swh: other functions are now in the .h file for inlining */ diff --git a/interface/external/gverb/src/gverb.h b/interface/external/gverb/src/gverb.h deleted file mode 100644 index 21bc1c3fef..0000000000 --- a/interface/external/gverb/src/gverb.h +++ /dev/null @@ -1,234 +0,0 @@ -/* - - Copyright (C) 1999 Juhana Sadeharju - kouhia at nic.funet.fi - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - -#ifndef GVERB_H -#define GVERB_H - -#include -#include -#include -#include "gverbdsp.h" -#include "gverb.h" -#include "../include/ladspa-util.h" - -#define FDNORDER 4 - -typedef struct { - int rate; - float inputbandwidth; - float taillevel; - float earlylevel; - ty_damper *inputdamper; - float maxroomsize; - float roomsize; - float revtime; - float maxdelay; - float largestdelay; - ty_fixeddelay **fdndels; - float *fdngains; - int *fdnlens; - ty_damper **fdndamps; - float fdndamping; - ty_diffuser **ldifs; - ty_diffuser **rdifs; - ty_fixeddelay *tapdelay; - int *taps; - float *tapgains; - float *d; - float *u; - float *f; - double alpha; -} ty_gverb; - - -ty_gverb *gverb_new(int, float, float, float, float, float, float, float, float); -void gverb_free(ty_gverb *); -void gverb_flush(ty_gverb *); -static void gverb_do(ty_gverb *, float, float *, float *); -static void gverb_set_roomsize(ty_gverb *, float); -static void gverb_set_revtime(ty_gverb *, float); -static void gverb_set_damping(ty_gverb *, float); -static void gverb_set_inputbandwidth(ty_gverb *, float); -static void gverb_set_earlylevel(ty_gverb *, float); -static void gverb_set_taillevel(ty_gverb *, float); - -/* - * This FDN reverb can be made smoother by setting matrix elements at the - * diagonal and near of it to zero or nearly zero. By setting diagonals to zero - * means we remove the effect of the parallel comb structure from the - * reverberation. A comb generates uniform impulse stream to the reverberation - * impulse response, and thus it is not good. By setting near diagonal elements - * to zero means we remove delay sequences having consequtive delays of the - * similar lenths, when the delays are in sorted in length with respect to - * matrix element index. The matrix described here could be generated by - * differencing Rocchesso's circulant matrix at max diffuse value and at low - * diffuse value (approaching parallel combs). - * - * Example 1: - * Set a(k,k), for all k, equal to 0. - * - * Example 2: - * Set a(k,k), a(k,k-1) and a(k,k+1) equal to 0. - * - * Example 3: The transition to zero gains could be smooth as well. - * a(k,k-1) and a(k,k+1) could be 0.3, and a(k,k-2) and a(k,k+2) could - * be 0.5, say. - */ - -static inline void gverb_fdnmatrix(float *a, float *b) -{ - const float dl0 = a[0], dl1 = a[1], dl2 = a[2], dl3 = a[3]; - - b[0] = 0.5f*(+dl0 + dl1 - dl2 - dl3); - b[1] = 0.5f*(+dl0 - dl1 - dl2 + dl3); - b[2] = 0.5f*(-dl0 + dl1 - dl2 + dl3); - b[3] = 0.5f*(+dl0 + dl1 + dl2 + dl3); -} - -static inline void gverb_do(ty_gverb *p, float x, float *yl, float *yr) -{ - float z; - unsigned int i; - float lsum,rsum,sum,sign; - - if ((x != x) || fabsf(x) > 100000.0f) { - x = 0.0f; - } - - z = damper_do(p->inputdamper, x); - - z = diffuser_do(p->ldifs[0],z); - - for(i = 0; i < FDNORDER; i++) { - p->u[i] = p->tapgains[i]*fixeddelay_read(p->tapdelay,p->taps[i]); - } - fixeddelay_write(p->tapdelay,z); - - for(i = 0; i < FDNORDER; i++) { - p->d[i] = damper_do(p->fdndamps[i], - p->fdngains[i]*fixeddelay_read(p->fdndels[i], - p->fdnlens[i])); - } - - sum = 0.0f; - sign = 1.0f; - for(i = 0; i < FDNORDER; i++) { - sum += sign*(p->taillevel*p->d[i] + p->earlylevel*p->u[i]); - sign = -sign; - } - sum += x*p->earlylevel; - lsum = sum; - rsum = sum; - - gverb_fdnmatrix(p->d,p->f); - - for(i = 0; i < FDNORDER; i++) { - fixeddelay_write(p->fdndels[i],p->u[i]+p->f[i]); - } - - lsum = diffuser_do(p->ldifs[1],lsum); - lsum = diffuser_do(p->ldifs[2],lsum); - lsum = diffuser_do(p->ldifs[3],lsum); - rsum = diffuser_do(p->rdifs[1],rsum); - rsum = diffuser_do(p->rdifs[2],rsum); - rsum = diffuser_do(p->rdifs[3],rsum); - - *yl = lsum; - *yr = rsum; -} - -static inline void gverb_set_roomsize(ty_gverb *p, const float a) -{ - unsigned int i; - - if (a <= 1.0 || (a != a)) { - p->roomsize = 1.0; - } else { - p->roomsize = a; - } - p->largestdelay = p->rate * p->roomsize * 0.00294f; - - p->fdnlens[0] = f_round(1.000000f*p->largestdelay); - p->fdnlens[1] = f_round(0.816490f*p->largestdelay); - p->fdnlens[2] = f_round(0.707100f*p->largestdelay); - p->fdnlens[3] = f_round(0.632450f*p->largestdelay); - for(i = 0; i < FDNORDER; i++) { - p->fdngains[i] = -powf((float)p->alpha, p->fdnlens[i]); - } - - p->taps[0] = 5+f_round(0.410f*p->largestdelay); - p->taps[1] = 5+f_round(0.300f*p->largestdelay); - p->taps[2] = 5+f_round(0.155f*p->largestdelay); - p->taps[3] = 5+f_round(0.000f*p->largestdelay); - - for(i = 0; i < FDNORDER; i++) { - p->tapgains[i] = powf((float)p->alpha, p->taps[i]); - } - -} - -static inline void gverb_set_revtime(ty_gverb *p,float a) -{ - float ga,gt; - double n; - unsigned int i; - - p->revtime = a; - - ga = 60.0; - gt = p->revtime; - ga = powf(10.0f,-ga/20.0f); - n = p->rate*gt; - p->alpha = (double)powf(ga,1.0f/n); - - for(i = 0; i < FDNORDER; i++) { - p->fdngains[i] = -powf((float)p->alpha, p->fdnlens[i]); - } - -} - -static inline void gverb_set_damping(ty_gverb *p,float a) -{ - unsigned int i; - - p->fdndamping = a; - for(i = 0; i < FDNORDER; i++) { - damper_set(p->fdndamps[i],p->fdndamping); - } -} - -static inline void gverb_set_inputbandwidth(ty_gverb *p,float a) -{ - p->inputbandwidth = a; - damper_set(p->inputdamper,1.0 - p->inputbandwidth); -} - -static inline void gverb_set_earlylevel(ty_gverb *p,float a) -{ - p->earlylevel = a; -} - -static inline void gverb_set_taillevel(ty_gverb *p,float a) -{ - p->taillevel = a; -} - -#endif diff --git a/interface/external/gverb/src/gverbdsp.c b/interface/external/gverb/src/gverbdsp.c deleted file mode 100644 index 05a90f897e..0000000000 --- a/interface/external/gverb/src/gverbdsp.c +++ /dev/null @@ -1,130 +0,0 @@ - - -/* - - Copyright (C) 1999 Juhana Sadeharju - kouhia at nic.funet.fi - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - -#include -#include -#include -#include - -#include "gverbdsp.h" - -#define TRUE 1 -#define FALSE 0 - -ty_diffuser *diffuser_make(int size, float coeff) -{ - ty_diffuser *p; - int i; - - p = (ty_diffuser *)malloc(sizeof(ty_diffuser)); - p->size = size; - p->coeff = coeff; - p->idx = 0; - p->buf = (float *)malloc(size*sizeof(float)); - for (i = 0; i < size; i++) p->buf[i] = 0.0; - return(p); -} - -void diffuser_free(ty_diffuser *p) -{ - free(p->buf); - free(p); -} - -void diffuser_flush(ty_diffuser *p) -{ - memset(p->buf, 0, p->size * sizeof(float)); -} - -ty_damper *damper_make(float damping) -{ - ty_damper *p; - - p = (ty_damper *)malloc(sizeof(ty_damper)); - p->damping = damping; - p->delay = 0.0f; - return(p); -} - -void damper_free(ty_damper *p) -{ - free(p); -} - -void damper_flush(ty_damper *p) -{ - p->delay = 0.0f; -} - -ty_fixeddelay *fixeddelay_make(int size) -{ - ty_fixeddelay *p; - int i; - - p = (ty_fixeddelay *)malloc(sizeof(ty_fixeddelay)); - p->size = size; - p->idx = 0; - p->buf = (float *)malloc(size*sizeof(float)); - for (i = 0; i < size; i++) p->buf[i] = 0.0; - return(p); -} - -void fixeddelay_free(ty_fixeddelay *p) -{ - free(p->buf); - free(p); -} - -void fixeddelay_flush(ty_fixeddelay *p) -{ - memset(p->buf, 0, p->size * sizeof(float)); -} - -int isprime(int n) -{ - unsigned int i; - const unsigned int lim = (int)sqrtf((float)n); - - if (n == 2) return(TRUE); - if ((n & 1) == 0) return(FALSE); - for(i = 3; i <= lim; i += 2) - if ((n % i) == 0) return(FALSE); - return(TRUE); -} - -int nearest_prime(int n, float rerror) - /* relative error; new prime will be in range - * [n-n*rerror, n+n*rerror]; - */ -{ - int bound,k; - - if (isprime(n)) return(n); - /* assume n is large enough and n*rerror enough smaller than n */ - bound = n*rerror; - for(k = 1; k <= bound; k++) { - if (isprime(n+k)) return(n+k); - if (isprime(n-k)) return(n-k); - } - return(-1); -} diff --git a/interface/external/gverb/src/gverbdsp.h b/interface/external/gverb/src/gverbdsp.h deleted file mode 100644 index 8b8b41d169..0000000000 --- a/interface/external/gverb/src/gverbdsp.h +++ /dev/null @@ -1,85 +0,0 @@ - -#ifndef GVERBDSP_H -#define GVERBDSP_H - -#include "../include/ladspa-util.h" - -typedef struct { - int size; - int idx; - float *buf; -} ty_fixeddelay; - -typedef struct { - int size; - float coeff; - int idx; - float *buf; -} ty_diffuser; - -typedef struct { - float damping; - float delay; -} ty_damper; - -ty_diffuser *diffuser_make(int, float); -void diffuser_free(ty_diffuser *); -void diffuser_flush(ty_diffuser *); -//float diffuser_do(ty_diffuser *, float); - -ty_damper *damper_make(float); -void damper_free(ty_damper *); -void damper_flush(ty_damper *); -//void damper_set(ty_damper *, float); -//float damper_do(ty_damper *, float); - -ty_fixeddelay *fixeddelay_make(int); -void fixeddelay_free(ty_fixeddelay *); -void fixeddelay_flush(ty_fixeddelay *); -//float fixeddelay_read(ty_fixeddelay *, int); -//void fixeddelay_write(ty_fixeddelay *, float); - -int isprime(int); -int nearest_prime(int, float); - -static inline float diffuser_do(ty_diffuser *p, float x) -{ - float y,w; - - w = x - p->buf[p->idx]*p->coeff; - w = flush_to_zero(w); - y = p->buf[p->idx] + w*p->coeff; - p->buf[p->idx] = w; - p->idx = (p->idx + 1) % p->size; - return(y); -} - -static inline float fixeddelay_read(ty_fixeddelay *p, int n) -{ - int i; - - i = (p->idx - n + p->size) % p->size; - return(p->buf[i]); -} - -static inline void fixeddelay_write(ty_fixeddelay *p, float x) -{ - p->buf[p->idx] = x; - p->idx = (p->idx + 1) % p->size; -} - -static inline void damper_set(ty_damper *p, float damping) -{ - p->damping = damping; -} - -static inline float damper_do(ty_damper *p, float x) -{ - float y; - - y = x*(1.0-p->damping) + p->delay*p->damping; - p->delay = y; - return(y); -} - -#endif From a3707a09ae7b5cc799962d1909af133a7c0c8917 Mon Sep 17 00:00:00 2001 From: stojce Date: Wed, 22 Oct 2014 09:42:55 +0200 Subject: [PATCH 023/119] fix mirror ratio on retina --- interface/src/Application.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 145222cd3c..306ca2f4b9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3083,7 +3083,6 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) { // if not rendering the billboard, the region is in device independent coordinates; must convert to device QSize size = getTextureCache()->getFrameBufferSize(); float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio(); - ratio = size.height() / (float)_glWidget->getDeviceHeight(); int x = region.x() * ratio, y = region.y() * ratio, width = region.width() * ratio, height = region.height() * ratio; glViewport(x, size.height() - y - height, width, height); glScissor(x, size.height() - y - height, width, height); From e9d3729238b24a87318ae1549d4d14f414070464 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 10:30:46 -0700 Subject: [PATCH 024/119] Remove unnecessary header --- interface/src/Audio.h | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 900b6ce0d6..3b7c2eef03 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -49,7 +49,6 @@ extern "C" { #include - #include } static const int NUM_AUDIO_CHANNELS = 2; From 52dacaab02468e6c806b7df05ac17a88ccc49c6c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 22 Oct 2014 10:36:44 -0700 Subject: [PATCH 025/119] Update entity editing to force SPACE_LOCAL for single-selection --- examples/libraries/entitySelectionTool.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index b70c2187c2..7815946fd1 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -78,6 +78,8 @@ SelectionManager = (function() { that.worldDimensions = null; that.worldPosition = null; } else if (that.selections.length == 1) { + SelectionDisplay.setSpaceMode(SPACE_LOCAL); + var properties = Entities.getEntityProperties(that.selections[0]); that.localDimensions = properties.dimensions; that.localPosition = properties.position; From 078d14ae58d560f9d36f2157d7f8f39e6931cb87 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 22 Oct 2014 10:36:58 -0700 Subject: [PATCH 026/119] Fix rotation overlay size with multi-selection --- examples/libraries/entitySelectionTool.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 7815946fd1..0153f7fc3d 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -624,8 +624,8 @@ SelectionDisplay = (function () { } - var diagonal = (Vec3.length(properties.dimensions) / 2) * 1.1; - var halfDimensions = Vec3.multiply(properties.dimensions, 0.5); + var diagonal = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1; + var halfDimensions = Vec3.multiply(selectionManager.worldDimensions, 0.5); innerRadius = diagonal; outerRadius = diagonal * 1.15; var innerActive = false; From 5b9806dc0dd9bb419421c4345f45c2d2e0902309 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 22 Oct 2014 10:37:17 -0700 Subject: [PATCH 027/119] Fix deletion with multi-selection --- examples/libraries/entitySelectionTool.js | 2 +- examples/newEditEntities.js | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 0153f7fc3d..f4f068742f 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -927,7 +927,7 @@ SelectionDisplay = (function () { }; that.updateHandles = function(entityID) { - if (!entitySelected) { + if (SelectionManager.selections.length == 0) { that.setOverlaysVisible(false); return; } diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index 9b46cdaf3f..402ad94417 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -608,9 +608,12 @@ function handeMenuEvent(menuItem) { } else if (menuItem == "Delete") { if (entitySelected) { print(" Delete Entity.... selectedEntityID="+ selectedEntityID); - Entities.deleteEntity(selectedEntityID); + for (var i = 0; i < selectionManager.selections.length; i++) { + Entities.deleteEntity(selectionManager.selections[i]); + } selectionDisplay.unselect(selectedEntityID); entitySelected = false; + selectionManager.clearSelections(); } else { print(" Delete Entity.... not holding..."); } @@ -653,7 +656,7 @@ Controller.keyReleaseEvent.connect(function (event) { if (event.text == "`") { handeMenuEvent("Edit Properties..."); } - if (event.text == "BACKSPACE") { + if (event.text == "BACKSPACE" || event.text == "DELETE") { handeMenuEvent("Delete"); } else if (event.text == "TAB") { selectionDisplay.toggleSpaceMode(); From 0bda7699a66d5c0dc53f15a4182715a3397d67e9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 22 Oct 2014 10:38:24 -0700 Subject: [PATCH 028/119] Disable properties menu with multi-selection --- examples/newEditEntities.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index 402ad94417..ae0d018b14 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -621,7 +621,7 @@ function handeMenuEvent(menuItem) { // good place to put the properties dialog editModelID = -1; - if (entitySelected) { + if (selectionManager.selections.length == 1) { print(" Edit Properties.... selectedEntityID="+ selectedEntityID); editModelID = selectedEntityID; } else { From 1739cf019d0a0d2ad104f24a2c7aee572bae1708 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 11:35:51 -0700 Subject: [PATCH 029/119] Gverb library CMakeLists --- interface/external/gverb/CMakeLists.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 interface/external/gverb/CMakeLists.txt diff --git a/interface/external/gverb/CMakeLists.txt b/interface/external/gverb/CMakeLists.txt new file mode 100644 index 0000000000..7913348e1d --- /dev/null +++ b/interface/external/gverb/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 2.8) + +set(TARGET_NAME gverb) +project(${TARGET_NAME}) + +# grab the implementation and header files +file(GLOB GVERB_SRCS src/*.c) + +include_directories(include) + +add_library(${TARGET_NAME} ${GVERB_SRCS}) From e496304f7ef1e96bef4c49ebd9cfbffeb37f5d21 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 11:36:23 -0700 Subject: [PATCH 030/119] Changed include dir --- cmake/modules/FindGverb.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/modules/FindGverb.cmake b/cmake/modules/FindGverb.cmake index 80aca29b93..8990009b59 100644 --- a/cmake/modules/FindGverb.cmake +++ b/cmake/modules/FindGverb.cmake @@ -19,7 +19,7 @@ if (GVERB_INCLUDE_DIRS) # in cache already set(GVERB_FOUND TRUE) else () - find_path(GVERB_INCLUDE_DIRS gverb.h ${GVERB_ROOT_DIR}/src) + find_path(GVERB_INCLUDE_DIRS gverb.h ${GVERB_ROOT_DIR}/include) if (GVERB_INCLUDE_DIRS) set(GVERB_FOUND TRUE) From e97aef581a462dc4126372c000706a4b3bbe61fc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Oct 2014 12:07:00 -0700 Subject: [PATCH 031/119] use InvokeMethod so that texture change happens on the right thread --- interface/src/renderer/Model.h | 2 +- interface/src/ui/overlays/ModelOverlay.cpp | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 3618d8103e..272844ac4a 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -183,7 +183,7 @@ public: void inverseKinematics(int jointIndex, glm::vec3 position, const glm::quat& rotation, float priority); - void setTextureWithNameToURL(const QString& name, const QUrl& url) + Q_INVOKABLE void setTextureWithNameToURL(const QString& name, const QUrl& url) { _geometry->setTextureWithNameToURL(name, url); } protected: diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index ac3d7b8a2b..0169bf40cd 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -107,9 +107,13 @@ void ModelOverlay::setProperties(const QScriptValue &properties) { if (texturesValue.isValid()) { QVariantMap textureMap = texturesValue.toVariant().toMap(); foreach(const QString& key, textureMap.keys()) { + QUrl newTextureURL = textureMap[key].toUrl(); qDebug() << "Updating texture named" << key << "to texture at URL" << newTextureURL; - _model.setTextureWithNameToURL(key, newTextureURL); + + QMetaObject::invokeMethod(&_model, "setTextureWithNameToURL", Qt::AutoConnection, + Q_ARG(const QString&, key), + Q_ARG(const QUrl&, newTextureURL)); } } From ccc8e0d876c9addf5d0470aa269d2d736dd6c170 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 12:56:44 -0700 Subject: [PATCH 032/119] Statically link gverb --- cmake/modules/FindGverb.cmake | 29 +++++++++++++------------ interface/CMakeLists.txt | 14 +++++++----- interface/external/gverb/CMakeLists.txt | 11 ---------- interface/src/Audio.h | 1 + 4 files changed, 24 insertions(+), 31 deletions(-) delete mode 100644 interface/external/gverb/CMakeLists.txt diff --git a/cmake/modules/FindGverb.cmake b/cmake/modules/FindGverb.cmake index 8990009b59..f71e1256a2 100644 --- a/cmake/modules/FindGverb.cmake +++ b/cmake/modules/FindGverb.cmake @@ -13,26 +13,27 @@ # # Distributed under the Apache License, Version 2.0. # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -# +# if (GVERB_INCLUDE_DIRS) # in cache already set(GVERB_FOUND TRUE) else () - find_path(GVERB_INCLUDE_DIRS gverb.h ${GVERB_ROOT_DIR}/include) - if (GVERB_INCLUDE_DIRS) - set(GVERB_FOUND TRUE) - endif (GVERB_INCLUDE_DIRS) +include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") +hifi_library_search_hints("gverb") - if (GVERB_FOUND) - if (NOT GVERB_FIND_QUIETLY) - message(STATUS "Found Gverb: ${GVERB_INCLUDE_DIRS}") - endif (NOT GVERB_FIND_QUIETLY) - else () - if (GVERB_FIND_REQUIRED) - message(FATAL_ERROR "Could NOT find Gverb") - endif (GVERB_FIND_REQUIRED) - endif () +find_path(GVERB_INCLUDE_DIRS gverb.h PATH_SUFFIXES include HINTS ${GVERB_SEARCH_DIRS}) +find_path(GVERB_SRC_DIRS gverb.c PATH_SUFFIXES src HINTS ${GVERB_SEARCH_DIRS}) + +if (GVERB_INCLUDE_DIRS) + set(GVERB_FOUND TRUE) +endif (GVERB_INCLUDE_DIRS) + +if (GVERB_FOUND) + message(STATUS "Found Gverb: ${GVERB_INCLUDE_DIRS}") +else () + message(FATAL_ERROR "Could NOT find Gverb. Read ./interface/externals/gverb/readme.txt") +endif () endif () diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 1c9c68ec5f..d0868aebcd 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -14,9 +14,17 @@ endforeach() find_package(Qt5LinguistTools REQUIRED) find_package(Qt5LinguistToolsMacros) + # As Gverb is currently the only reverb library, it's required. find_package(Gverb REQUIRED) +if (GVERB_FOUND) + file(GLOB GVERB_SRCS ${GVERB_SRC_DIRS}/*.c) + include_directories(${GVERB_INCLUDE_DIRS}) + add_library(Gverb ${GVERB_SRCS}) +message(STATUS "Gverb srcs: ${GVERB_SRCS}") +endif (GVERB_FOUND) + if (DEFINED ENV{JOB_ID}) set(BUILD_SEQ $ENV{JOB_ID}) else () @@ -169,12 +177,6 @@ if (QXMPP_FOUND AND NOT DISABLE_QXMPP AND WIN32) add_definitions(-DQXMPP_STATIC) endif () -if (GVERB_FOUND) - add_subdirectory(${GVERB_ROOT_DIR}) - include_directories(${GVERB_INCLUDE_DIRS}) - target_link_libraries(${TARGET_NAME} gverb) -endif (GVERB_FOUND) - # include headers for interface and InterfaceConfig. include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes") diff --git a/interface/external/gverb/CMakeLists.txt b/interface/external/gverb/CMakeLists.txt deleted file mode 100644 index 7913348e1d..0000000000 --- a/interface/external/gverb/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -set(TARGET_NAME gverb) -project(${TARGET_NAME}) - -# grab the implementation and header files -file(GLOB GVERB_SRCS src/*.c) - -include_directories(include) - -add_library(${TARGET_NAME} ${GVERB_SRCS}) diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 3b7c2eef03..900b6ce0d6 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -49,6 +49,7 @@ extern "C" { #include + #include } static const int NUM_AUDIO_CHANNELS = 2; From e69bc22222c1c8fc1c9b36d275ed23c0c82afe32 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 22 Oct 2014 12:56:55 -0700 Subject: [PATCH 033/119] Fix for streaming crash. --- .../metavoxels/src/DatagramSequencer.cpp | 2 +- libraries/metavoxels/src/DatagramSequencer.h | 3 ++ .../metavoxels/src/MetavoxelClientManager.cpp | 40 ++++++++++++++----- .../metavoxels/src/MetavoxelClientManager.h | 7 +++- 4 files changed, 40 insertions(+), 12 deletions(-) diff --git a/libraries/metavoxels/src/DatagramSequencer.cpp b/libraries/metavoxels/src/DatagramSequencer.cpp index be3d684a3d..d97ed67644 100644 --- a/libraries/metavoxels/src/DatagramSequencer.cpp +++ b/libraries/metavoxels/src/DatagramSequencer.cpp @@ -301,10 +301,10 @@ void DatagramSequencer::clearReliableChannel(QObject* object) { void DatagramSequencer::sendRecordAcknowledged(const SendRecord& record) { // stop acknowledging the recorded packets while (!_receiveRecords.isEmpty() && _receiveRecords.first().packetNumber <= record.lastReceivedPacketNumber) { + emit receiveAcknowledged(0); const ReceiveRecord& received = _receiveRecords.first(); _inputStream.persistReadMappings(received.mappings); _receivedHighPriorityMessages -= received.newHighPriorityMessages; - emit receiveAcknowledged(0); _receiveRecords.removeFirst(); } _outputStream.persistWriteMappings(record.mappings); diff --git a/libraries/metavoxels/src/DatagramSequencer.h b/libraries/metavoxels/src/DatagramSequencer.h index 9a1f5a4ae0..02fbd0f365 100644 --- a/libraries/metavoxels/src/DatagramSequencer.h +++ b/libraries/metavoxels/src/DatagramSequencer.h @@ -108,6 +108,9 @@ public: /// Returns the intput channel at the specified index, creating it if necessary. ReliableChannel* getReliableInputChannel(int index = 0); + /// Returns a reference to the stored receive mappings at the specified index. + const Bitstream::ReadMappings& getReadMappings(int index) const { return _receiveRecords.at(index).mappings; } + /// Adds stats for all reliable channels to the referenced variables. void addReliableChannelStats(int& sendProgress, int& sendTotal, int& receiveProgress, int& receiveTotal) const; diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index 09164d72c4..cc5d7ef29d 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -188,7 +188,9 @@ MetavoxelClient::MetavoxelClient(const SharedNodePointer& node, MetavoxelUpdater Endpoint(node, new PacketRecord(), new PacketRecord()), _updater(updater), _reliableDeltaChannel(NULL), - _reliableDeltaID(0) { + _reliableDeltaID(0), + _dummyInputStream(_dummyDataStream), + _dummyPacketNumber(0) { connect(_sequencer.getReliableInputChannel(RELIABLE_DELTA_CHANNEL_INDEX), SIGNAL(receivedMessage(const QVariant&, Bitstream&)), SLOT(handleMessage(const QVariant&, Bitstream&))); @@ -234,9 +236,9 @@ PacketRecord* MetavoxelClient::getAcknowledgedReceiveRecord(int packetNumber) co if (lastAcknowledged->getPacketNumber() == packetNumber) { return lastAcknowledged; } - foreach (PacketRecord* record, _clearedReceiveRecords) { - if (record->getPacketNumber() == packetNumber) { - return record; + foreach (const ClearedReceiveRecord& record, _clearedReceiveRecords) { + if (record.first->getPacketNumber() == packetNumber) { + return record.first; } } return NULL; @@ -257,8 +259,8 @@ void MetavoxelClient::recordReceive() { } _clearedSendRecords.clear(); - foreach (PacketRecord* record, _clearedReceiveRecords) { - delete record; + foreach (const ClearedReceiveRecord& record, _clearedReceiveRecords) { + delete record.first; } _clearedReceiveRecords.clear(); } @@ -273,10 +275,16 @@ void MetavoxelClient::clearSendRecordsBefore(int index) { } void MetavoxelClient::clearReceiveRecordsBefore(int index) { + // copy the mappings on first call per packet + if (_sequencer.getIncomingPacketNumber() > _dummyPacketNumber) { + _dummyPacketNumber = _sequencer.getIncomingPacketNumber(); + _dummyInputStream.copyPersistentMappings(_sequencer.getInputStream()); + } + // move to cleared list QList::iterator end = _receiveRecords.begin() + index + 1; for (QList::const_iterator it = _receiveRecords.begin(); it != end; it++) { - _clearedReceiveRecords.append(*it); + _clearedReceiveRecords.append(ClearedReceiveRecord(*it, _sequencer.getReadMappings(index))); } _receiveRecords.erase(_receiveRecords.begin(), end); } @@ -289,7 +297,6 @@ void MetavoxelClient::writeUpdateMessage(Bitstream& out) { void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { int userType = message.userType(); if (userType == MetavoxelDeltaMessage::Type) { - PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord(); if (_reliableDeltaChannel) { MetavoxelData reference = _remoteData; MetavoxelLOD referenceLOD = _remoteDataLOD; @@ -299,6 +306,7 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { _reliableDeltaChannel = NULL; } else { + PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord(); _remoteData.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, _remoteDataLOD = getLastAcknowledgedSendRecord()->getLOD()); in.reset(); @@ -319,8 +327,6 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { MetavoxelDeltaPendingMessage pending = message.value(); if (pending.id > _reliableDeltaID) { _reliableDeltaID = pending.id; - _reliableDeltaChannel = _sequencer.getReliableInputChannel(RELIABLE_DELTA_CHANNEL_INDEX); - _reliableDeltaChannel->getBitstream().copyPersistentMappings(_sequencer.getInputStream()); PacketRecord* sendRecord = getAcknowledgedSendRecord(pending.receivedPacketNumber); if (!sendRecord) { qWarning() << "Missing send record for delta" << pending.receivedPacketNumber; @@ -334,6 +340,20 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { } _remoteDataLOD = receiveRecord->getLOD(); _remoteData = receiveRecord->getData(); + + _reliableDeltaChannel = _sequencer.getReliableInputChannel(RELIABLE_DELTA_CHANNEL_INDEX); + if (receiveRecord == getLastAcknowledgedReceiveRecord()) { + _reliableDeltaChannel->getBitstream().copyPersistentMappings(_sequencer.getInputStream()); + + } else { + _reliableDeltaChannel->getBitstream().copyPersistentMappings(_dummyInputStream); + foreach (const ClearedReceiveRecord& record, _clearedReceiveRecords) { + _reliableDeltaChannel->getBitstream().persistReadMappings(record.second); + if (record.first == receiveRecord) { + break; + } + } + } } } else { Endpoint::handleMessage(message, in); diff --git a/libraries/metavoxels/src/MetavoxelClientManager.h b/libraries/metavoxels/src/MetavoxelClientManager.h index 0a32f2986d..adab59e0ff 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.h +++ b/libraries/metavoxels/src/MetavoxelClientManager.h @@ -145,8 +145,13 @@ protected: MetavoxelData _dataCopy; QReadWriteLock _dataCopyLock; + QDataStream _dummyDataStream; + Bitstream _dummyInputStream; + int _dummyPacketNumber; QList _clearedSendRecords; - QList _clearedReceiveRecords; + + typedef QPair ClearedReceiveRecord; + QList _clearedReceiveRecords; }; #endif // hifi_MetavoxelClientManager_h From ad2eb0896432a8f35dd719b69ca736a9de0c20da Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 13:11:45 -0700 Subject: [PATCH 034/119] Correctly link in cmake --- cmake/modules/FindGverb.cmake | 5 ++--- interface/CMakeLists.txt | 14 +++++++------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/cmake/modules/FindGverb.cmake b/cmake/modules/FindGverb.cmake index f71e1256a2..175c216359 100644 --- a/cmake/modules/FindGverb.cmake +++ b/cmake/modules/FindGverb.cmake @@ -32,8 +32,7 @@ endif (GVERB_INCLUDE_DIRS) if (GVERB_FOUND) message(STATUS "Found Gverb: ${GVERB_INCLUDE_DIRS}") -else () +else (GVERB_FOUND) message(FATAL_ERROR "Could NOT find Gverb. Read ./interface/externals/gverb/readme.txt") -endif () +endif (GVERB_FOUND) -endif () diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index d0868aebcd..a150a308e0 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -18,13 +18,6 @@ find_package(Qt5LinguistToolsMacros) # As Gverb is currently the only reverb library, it's required. find_package(Gverb REQUIRED) -if (GVERB_FOUND) - file(GLOB GVERB_SRCS ${GVERB_SRC_DIRS}/*.c) - include_directories(${GVERB_INCLUDE_DIRS}) - add_library(Gverb ${GVERB_SRCS}) -message(STATUS "Gverb srcs: ${GVERB_SRCS}") -endif (GVERB_FOUND) - if (DEFINED ENV{JOB_ID}) set(BUILD_SEQ $ENV{JOB_ID}) else () @@ -177,6 +170,13 @@ if (QXMPP_FOUND AND NOT DISABLE_QXMPP AND WIN32) add_definitions(-DQXMPP_STATIC) endif () +if (GVERB_FOUND) + file(GLOB GVERB_SRCS ${GVERB_SRC_DIRS}/*.c) + include_directories(${GVERB_INCLUDE_DIRS}) + add_library(gverb STATIC ${GVERB_SRCS}) + target_link_libraries(${TARGET_NAME} gverb) +endif (GVERB_FOUND) + # include headers for interface and InterfaceConfig. include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes") From fc9010dd6b218246a9cb2b0f8064951131d9bfa1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 13:38:49 -0700 Subject: [PATCH 035/119] missing endif --- cmake/modules/FindGverb.cmake | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/cmake/modules/FindGverb.cmake b/cmake/modules/FindGverb.cmake index 175c216359..1d234b69e2 100644 --- a/cmake/modules/FindGverb.cmake +++ b/cmake/modules/FindGverb.cmake @@ -18,21 +18,22 @@ if (GVERB_INCLUDE_DIRS) # in cache already set(GVERB_FOUND TRUE) -else () +else (GVERB_INCLUDE_DIRS) -include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") -hifi_library_search_hints("gverb") + include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") + hifi_library_search_hints("gverb") -find_path(GVERB_INCLUDE_DIRS gverb.h PATH_SUFFIXES include HINTS ${GVERB_SEARCH_DIRS}) -find_path(GVERB_SRC_DIRS gverb.c PATH_SUFFIXES src HINTS ${GVERB_SEARCH_DIRS}) + find_path(GVERB_INCLUDE_DIRS gverb.h PATH_SUFFIXES include HINTS ${GVERB_SEARCH_DIRS}) + find_path(GVERB_SRC_DIRS gverb.c PATH_SUFFIXES src HINTS ${GVERB_SEARCH_DIRS}) -if (GVERB_INCLUDE_DIRS) - set(GVERB_FOUND TRUE) -endif (GVERB_INCLUDE_DIRS) + if (GVERB_INCLUDE_DIRS) + set(GVERB_FOUND TRUE) + endif (GVERB_INCLUDE_DIRS) -if (GVERB_FOUND) - message(STATUS "Found Gverb: ${GVERB_INCLUDE_DIRS}") -else (GVERB_FOUND) - message(FATAL_ERROR "Could NOT find Gverb. Read ./interface/externals/gverb/readme.txt") -endif (GVERB_FOUND) + if (GVERB_FOUND) + message(STATUS "Found Gverb: ${GVERB_INCLUDE_DIRS}") + else (GVERB_FOUND) + message(FATAL_ERROR "Could NOT find Gverb. Read ./interface/externals/gverb/readme.txt") + endif (GVERB_FOUND) +endif(GVERB_INCLUDE_DIR) \ No newline at end of file From bd4e8a172d0d67489f11b42d2b2ab17a396e66ed Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 13:40:58 -0700 Subject: [PATCH 036/119] typo --- cmake/modules/FindGverb.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/modules/FindGverb.cmake b/cmake/modules/FindGverb.cmake index 1d234b69e2..549c23c8a9 100644 --- a/cmake/modules/FindGverb.cmake +++ b/cmake/modules/FindGverb.cmake @@ -36,4 +36,4 @@ else (GVERB_INCLUDE_DIRS) message(FATAL_ERROR "Could NOT find Gverb. Read ./interface/externals/gverb/readme.txt") endif (GVERB_FOUND) -endif(GVERB_INCLUDE_DIR) \ No newline at end of file +endif(GVERB_INCLUDE_DIRS) \ No newline at end of file From d13283192fe41e8068e2e3c3303d514b7b00bf57 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 22 Oct 2014 14:07:15 -0700 Subject: [PATCH 037/119] Fix the bug happening on mac due to order in which parmaeters are evaluated for all of the gl calls, now fixed with an order independant code --- interface/src/gpu/Batch.cpp | 301 ++++++++++++++++++++++--------- interface/src/gpu/Batch.h | 86 ++++----- interface/src/renderer/Model.cpp | 2 +- 3 files changed, 260 insertions(+), 129 deletions(-) diff --git a/interface/src/gpu/Batch.cpp b/interface/src/gpu/Batch.cpp index 8a094d1024..8b36ef8b33 100644 --- a/interface/src/gpu/Batch.cpp +++ b/interface/src/gpu/Batch.cpp @@ -17,6 +17,8 @@ //#define DO_IT_NOW(call, offset) runLastCommand(); #define DO_IT_NOW(call, offset) +#define CHECK_GL_ERROR() ::gpu::backend::checkGLError() + using namespace gpu; Batch::Batch() : @@ -158,8 +160,9 @@ void Batch::_glEnable(GLenum cap) { DO_IT_NOW(_glEnable, 1); } -void Batch::do_glEnable(uint32& paramOffset) { - glEnable(_params[paramOffset++]._uint); +void Batch::do_glEnable(uint32 paramOffset) { + glEnable(_params[paramOffset]._uint); + CHECK_GL_ERROR(); } void Batch::_glDisable(GLenum cap) { @@ -169,8 +172,9 @@ void Batch::_glDisable(GLenum cap) { DO_IT_NOW(_glDisable, 1); } -void Batch::do_glDisable(uint32& paramOffset) { - glDisable(_params[paramOffset++]._uint); +void Batch::do_glDisable(uint32 paramOffset) { + glDisable(_params[paramOffset]._uint); + CHECK_GL_ERROR(); } void Batch::_glEnableClientState(GLenum array) { @@ -180,8 +184,9 @@ void Batch::_glEnableClientState(GLenum array) { DO_IT_NOW(_glEnableClientState, 1 ); } -void Batch::do_glEnableClientState(uint32& paramOffset) { - glEnableClientState(_params[paramOffset++]._uint); +void Batch::do_glEnableClientState(uint32 paramOffset) { + glEnableClientState(_params[paramOffset]._uint); + CHECK_GL_ERROR(); } void Batch::_glDisableClientState(GLenum array) { @@ -191,8 +196,9 @@ void Batch::_glDisableClientState(GLenum array) { DO_IT_NOW(_glDisableClientState, 1); } -void Batch::do_glDisableClientState(uint32& paramOffset) { - glDisableClientState(_params[paramOffset++]._uint); +void Batch::do_glDisableClientState(uint32 paramOffset) { + glDisableClientState(_params[paramOffset]._uint); + CHECK_GL_ERROR(); } void Batch::_glCullFace(GLenum mode) { @@ -202,8 +208,9 @@ void Batch::_glCullFace(GLenum mode) { DO_IT_NOW(_glCullFace, 1); } -void Batch::do_glCullFace(uint32& paramOffset) { - glCullFace(_params[paramOffset++]._uint); +void Batch::do_glCullFace(uint32 paramOffset) { + glCullFace(_params[paramOffset]._uint); + CHECK_GL_ERROR(); } void Batch::_glAlphaFunc(GLenum func, GLclampf ref) { @@ -214,8 +221,11 @@ void Batch::_glAlphaFunc(GLenum func, GLclampf ref) { DO_IT_NOW(_glAlphaFunc, 2); } -void Batch::do_glAlphaFunc(uint32& paramOffset) { - glAlphaFunc(_params[paramOffset++]._uint, _params[paramOffset++]._float); +void Batch::do_glAlphaFunc(uint32 paramOffset) { + glAlphaFunc( + _params[paramOffset + 1]._uint, + _params[paramOffset + 0]._float); + CHECK_GL_ERROR(); } void Batch::_glDepthFunc(GLenum func) { @@ -225,8 +235,9 @@ void Batch::_glDepthFunc(GLenum func) { DO_IT_NOW(_glDepthFunc, 1); } -void Batch::do_glDepthFunc(uint32& paramOffset) { - glDepthFunc(_params[paramOffset++]._uint); +void Batch::do_glDepthFunc(uint32 paramOffset) { + glDepthFunc(_params[paramOffset]._uint); + CHECK_GL_ERROR(); } void Batch::_glDepthMask(GLboolean flag) { @@ -236,8 +247,9 @@ void Batch::_glDepthMask(GLboolean flag) { DO_IT_NOW(_glDepthMask, 1); } -void Batch::do_glDepthMask(uint32& paramOffset) { - glDepthMask(_params[paramOffset++]._uint); +void Batch::do_glDepthMask(uint32 paramOffset) { + glDepthMask(_params[paramOffset]._uint); + CHECK_GL_ERROR(); } void Batch::_glDepthRange(GLclampd zNear, GLclampd zFar) { @@ -248,8 +260,11 @@ void Batch::_glDepthRange(GLclampd zNear, GLclampd zFar) { DO_IT_NOW(_glDepthRange, 2); } -void Batch::do_glDepthRange(uint32& paramOffset) { - glDepthRange(_params[paramOffset++]._double, _params[paramOffset++]._double); +void Batch::do_glDepthRange(uint32 paramOffset) { + glDepthRange( + _params[paramOffset + 1]._double, + _params[paramOffset + 0]._double); + CHECK_GL_ERROR(); } void Batch::_glBindBuffer(GLenum target, GLuint buffer) { @@ -260,8 +275,11 @@ void Batch::_glBindBuffer(GLenum target, GLuint buffer) { DO_IT_NOW(_glBindBuffer, 2); } -void Batch::do_glBindBuffer(uint32& paramOffset) { - glBindBuffer(_params[paramOffset++]._uint, _params[paramOffset++]._uint); +void Batch::do_glBindBuffer(uint32 paramOffset) { + glBindBuffer( + _params[paramOffset + 1]._uint, + _params[paramOffset + 0]._uint); + CHECK_GL_ERROR(); } void Batch::_glBindTexture(GLenum target, GLuint texture) { @@ -272,8 +290,11 @@ void Batch::_glBindTexture(GLenum target, GLuint texture) { DO_IT_NOW(_glBindTexture, 2); } -void Batch::do_glBindTexture(uint32& paramOffset) { - glBindTexture(_params[paramOffset++]._uint, _params[paramOffset++]._uint); +void Batch::do_glBindTexture(uint32 paramOffset) { + glBindTexture( + _params[paramOffset + 1]._uint, + _params[paramOffset + 0]._uint); + CHECK_GL_ERROR(); } void Batch::_glActiveTexture(GLenum texture) { @@ -283,8 +304,9 @@ void Batch::_glActiveTexture(GLenum texture) { DO_IT_NOW(_glActiveTexture, 1); } -void Batch::do_glActiveTexture(uint32& paramOffset) { - glActiveTexture(_params[paramOffset++]._uint); +void Batch::do_glActiveTexture(uint32 paramOffset) { + glActiveTexture(_params[paramOffset]._uint); + CHECK_GL_ERROR(); } void Batch::_glDrawBuffers(GLsizei n, const GLenum* bufs) { @@ -295,8 +317,11 @@ void Batch::_glDrawBuffers(GLsizei n, const GLenum* bufs) { DO_IT_NOW(_glDrawBuffers, 2); } -void Batch::do_glDrawBuffers(uint32& paramOffset) { - glDrawBuffers(_params[paramOffset++]._uint, (const GLenum*) editData(_params[paramOffset++]._uint)); +void Batch::do_glDrawBuffers(uint32 paramOffset) { + glDrawBuffers( + _params[paramOffset + 1]._uint, + (const GLenum*) editData(_params[paramOffset + 0]._uint)); + CHECK_GL_ERROR(); } void Batch::_glUseProgram(GLuint program) { @@ -306,8 +331,9 @@ void Batch::_glUseProgram(GLuint program) { DO_IT_NOW(_glUseProgram, 1); } -void Batch::do_glUseProgram(uint32& paramOffset) { - glUseProgram(_params[paramOffset++]._uint); +void Batch::do_glUseProgram(uint32 paramOffset) { + glUseProgram(_params[paramOffset]._uint); + CHECK_GL_ERROR(); } void Batch::_glUniform1f(GLint location, GLfloat v0) { @@ -318,8 +344,11 @@ void Batch::_glUniform1f(GLint location, GLfloat v0) { DO_IT_NOW(_glUniform1f, 1); } -void Batch::do_glUniform1f(uint32& paramOffset) { - glUniform1f(_params[paramOffset++]._int, _params[paramOffset++]._float); +void Batch::do_glUniform1f(uint32 paramOffset) { + glUniform1f( + _params[paramOffset + 1]._int, + _params[paramOffset + 0]._float); + CHECK_GL_ERROR(); } void Batch::_glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { @@ -333,9 +362,13 @@ void Batch::_glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpo DO_IT_NOW(_glUniformMatrix4fv, 4); } -void Batch::do_glUniformMatrix4fv(uint32& paramOffset) { - glUniformMatrix4fv(_params[paramOffset++]._int, _params[paramOffset++]._uint, - _params[paramOffset++]._uint, (const GLfloat*) editData(_params[paramOffset++]._uint)); +void Batch::do_glUniformMatrix4fv(uint32 paramOffset) { + glUniformMatrix4fv( + _params[paramOffset + 3]._int, + _params[paramOffset + 2]._uint, + _params[paramOffset + 1]._uint, + (const GLfloat*) editData(_params[paramOffset + 0]._uint)); + CHECK_GL_ERROR(); } void Batch::_glMatrixMode(GLenum mode) { @@ -345,8 +378,9 @@ void Batch::_glMatrixMode(GLenum mode) { DO_IT_NOW(_glMatrixMode, 1); } -void Batch::do_glMatrixMode(uint32& paramOffset) { - glMatrixMode(_params[paramOffset++]._uint); +void Batch::do_glMatrixMode(uint32 paramOffset) { + glMatrixMode(_params[paramOffset]._uint); + CHECK_GL_ERROR(); } void Batch::_glPushMatrix() { @@ -354,8 +388,9 @@ void Batch::_glPushMatrix() { DO_IT_NOW(_glPushMatrix, 0); } -void Batch::do_glPushMatrix(uint32& paramOffset) { +void Batch::do_glPushMatrix(uint32 paramOffset) { glPushMatrix(); + CHECK_GL_ERROR(); } void Batch::_glPopMatrix() { @@ -363,8 +398,9 @@ void Batch::_glPopMatrix() { DO_IT_NOW(_glPopMatrix, 0); } -void Batch::do_glPopMatrix(uint32& paramOffset) { +void Batch::do_glPopMatrix(uint32 paramOffset) { glPopMatrix(); + CHECK_GL_ERROR(); } void Batch::_glMultMatrixf(const GLfloat *m) { @@ -375,8 +411,9 @@ void Batch::_glMultMatrixf(const GLfloat *m) { DO_IT_NOW(_glMultMatrixf, 1); } -void Batch::do_glMultMatrixf(uint32& paramOffset) { - glMultMatrixf((const GLfloat*) editData(_params[paramOffset++]._uint)); +void Batch::do_glMultMatrixf(uint32 paramOffset) { + glMultMatrixf((const GLfloat*) editData(_params[paramOffset]._uint)); + CHECK_GL_ERROR(); } void Batch::_glLoadMatrixf(const GLfloat *m) { @@ -387,8 +424,9 @@ void Batch::_glLoadMatrixf(const GLfloat *m) { DO_IT_NOW(_glLoadMatrixf, 1); } -void Batch::do_glLoadMatrixf(uint32& paramOffset) { - glLoadMatrixf((const GLfloat*)editData(_params[paramOffset++]._uint)); +void Batch::do_glLoadMatrixf(uint32 paramOffset) { + glLoadMatrixf((const GLfloat*)editData(_params[paramOffset]._uint)); + CHECK_GL_ERROR(); } void Batch::_glLoadIdentity(void) { @@ -396,8 +434,9 @@ void Batch::_glLoadIdentity(void) { DO_IT_NOW(_glLoadIdentity, 0); } -void Batch::do_glLoadIdentity(uint32& paramOffset) { +void Batch::do_glLoadIdentity(uint32 paramOffset) { glLoadIdentity(); + CHECK_GL_ERROR(); } void Batch::_glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { @@ -410,8 +449,13 @@ void Batch::_glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { DO_IT_NOW(_glRotatef, 4); } -void Batch::do_glRotatef(uint32& paramOffset) { - glRotatef(_params[paramOffset++]._float, _params[paramOffset++]._float, _params[paramOffset++]._float, _params[paramOffset++]._float); +void Batch::do_glRotatef(uint32 paramOffset) { + glRotatef( + _params[paramOffset + 3]._float, + _params[paramOffset + 2]._float, + _params[paramOffset + 1]._float, + _params[paramOffset + 0]._float); + CHECK_GL_ERROR(); } void Batch::_glScalef(GLfloat x, GLfloat y, GLfloat z) { @@ -423,8 +467,12 @@ void Batch::_glScalef(GLfloat x, GLfloat y, GLfloat z) { DO_IT_NOW(_glScalef, 3); } -void Batch::do_glScalef(uint32& paramOffset) { - glScalef(_params[paramOffset++]._float, _params[paramOffset++]._float, _params[paramOffset++]._float); +void Batch::do_glScalef(uint32 paramOffset) { + glScalef( + _params[paramOffset + 2]._float, + _params[paramOffset + 1]._float, + _params[paramOffset + 0]._float); + CHECK_GL_ERROR(); } void Batch::_glTranslatef(GLfloat x, GLfloat y, GLfloat z) { @@ -436,8 +484,12 @@ void Batch::_glTranslatef(GLfloat x, GLfloat y, GLfloat z) { DO_IT_NOW(_glTranslatef, 3); } -void Batch::do_glTranslatef(uint32& paramOffset) { - glTranslatef(_params[paramOffset++]._float, _params[paramOffset++]._float, _params[paramOffset++]._float); +void Batch::do_glTranslatef(uint32 paramOffset) { + glTranslatef( + _params[paramOffset + 2]._float, + _params[paramOffset + 1]._float, + _params[paramOffset + 0]._float); + CHECK_GL_ERROR(); } void Batch::_glDrawArrays(GLenum mode, GLint first, GLsizei count) { @@ -449,8 +501,12 @@ void Batch::_glDrawArrays(GLenum mode, GLint first, GLsizei count) { DO_IT_NOW(_glDrawArrays, 3); } -void Batch::do_glDrawArrays(uint32& paramOffset) { - glDrawArrays(_params[paramOffset++]._uint, _params[paramOffset++]._int, _params[paramOffset++]._int); +void Batch::do_glDrawArrays(uint32 paramOffset) { + glDrawArrays( + _params[paramOffset + 2]._uint, + _params[paramOffset + 1]._int, + _params[paramOffset + 0]._int); + CHECK_GL_ERROR(); } void Batch::_glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices) { @@ -463,14 +519,17 @@ void Batch::_glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei _params.push_back(start); _params.push_back(mode); - //do_glDrawRangeElements(_commandOffsets.back()); - // runCommand(_commands.size() - 1); DO_IT_NOW(_glDrawRangeElements, 6); } -void Batch::do_glDrawRangeElements(uint32& paramOffset) { - glDrawRangeElements(_params[paramOffset++]._uint, _params[paramOffset++]._uint, - _params[paramOffset++]._uint, _params[paramOffset++]._int, - _params[paramOffset++]._uint, editResource(_params[paramOffset++]._uint)->_pointer); +void Batch::do_glDrawRangeElements(uint32 paramOffset) { + glDrawRangeElements( + _params[paramOffset + 5]._uint, + _params[paramOffset + 4]._uint, + _params[paramOffset + 3]._uint, + _params[paramOffset + 2]._int, + _params[paramOffset + 1]._uint, + editResource(_params[paramOffset + 0]._uint)->_pointer); + CHECK_GL_ERROR(); } void Batch::_glColorPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) { @@ -483,9 +542,13 @@ void Batch::_glColorPointer(GLint size, GLenum type, GLsizei stride, const void DO_IT_NOW(_glColorPointer, 4); } -void Batch::do_glColorPointer(uint32& paramOffset) { - glColorPointer(_params[paramOffset++]._int, _params[paramOffset++]._uint, - _params[paramOffset++]._int, editResource(_params[paramOffset++]._uint)->_pointer); +void Batch::do_glColorPointer(uint32 paramOffset) { + glColorPointer( + _params[paramOffset + 3]._int, + _params[paramOffset + 2]._uint, + _params[paramOffset + 1]._int, + editResource(_params[paramOffset + 0]._uint)->_pointer); + CHECK_GL_ERROR(); } void Batch::_glNormalPointer(GLenum type, GLsizei stride, const void *pointer) { @@ -497,9 +560,12 @@ void Batch::_glNormalPointer(GLenum type, GLsizei stride, const void *pointer) { DO_IT_NOW(_glNormalPointer, 3); } -void Batch::do_glNormalPointer(uint32& paramOffset) { - glNormalPointer(_params[paramOffset++]._uint, _params[paramOffset++]._int, - editResource(_params[paramOffset++]._uint)->_pointer); +void Batch::do_glNormalPointer(uint32 paramOffset) { + glNormalPointer( + _params[paramOffset + 2]._uint, + _params[paramOffset + 1]._int, + editResource(_params[paramOffset + 0]._uint)->_pointer); + CHECK_GL_ERROR(); } void Batch::_glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) { @@ -512,9 +578,13 @@ void Batch::_glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const vo DO_IT_NOW(_glTexCoordPointer, 4); } -void Batch::do_glTexCoordPointer(uint32& paramOffset) { - glTexCoordPointer(_params[paramOffset++]._int, _params[paramOffset++]._uint, - _params[paramOffset++]._int, editResource(_params[paramOffset++]._uint)->_pointer); +void Batch::do_glTexCoordPointer(uint32 paramOffset) { + glTexCoordPointer( + _params[paramOffset + 3]._int, + _params[paramOffset + 2]._uint, + _params[paramOffset + 1]._int, + editResource(_params[paramOffset + 0]._uint)->_pointer); + CHECK_GL_ERROR(); } void Batch::_glVertexPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) { @@ -527,9 +597,13 @@ void Batch::_glVertexPointer(GLint size, GLenum type, GLsizei stride, const voi DO_IT_NOW(_glVertexPointer, 4); } -void Batch::do_glVertexPointer(uint32& paramOffset) { - glVertexPointer(_params[paramOffset++]._int, _params[paramOffset++]._uint, - _params[paramOffset++]._int, editResource(_params[paramOffset++]._uint)->_pointer); +void Batch::do_glVertexPointer(uint32 paramOffset) { + glVertexPointer( + _params[paramOffset + 3]._int, + _params[paramOffset + 2]._uint, + _params[paramOffset + 1]._int, + editResource(_params[paramOffset + 0]._uint)->_pointer); + CHECK_GL_ERROR(); } @@ -545,14 +619,17 @@ void Batch::_glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLbool DO_IT_NOW(_glVertexAttribPointer, 6); } -void Batch::do_glVertexAttribPointer(uint32& paramOffset) { - glVertexAttribPointer(_params[paramOffset++]._uint, _params[paramOffset++]._int, - _params[paramOffset++]._uint, _params[paramOffset++]._uint, - _params[paramOffset++]._int, editResource(_params[paramOffset++]._uint)->_pointer); +void Batch::do_glVertexAttribPointer(uint32 paramOffset) { + glVertexAttribPointer( + _params[paramOffset + 5]._uint, + _params[paramOffset + 4]._int, + _params[paramOffset + 3]._uint, + _params[paramOffset + 2]._uint, + _params[paramOffset + 1]._int, + editResource(_params[paramOffset + 0]._uint)->_pointer); + CHECK_GL_ERROR(); } - - void Batch::_glEnableVertexAttribArray(GLint location) { ADD_COMMAND(glEnableVertexAttribArray); @@ -560,8 +637,9 @@ void Batch::_glEnableVertexAttribArray(GLint location) { DO_IT_NOW(_glEnableVertexAttribArray, 1); } -void Batch::do_glEnableVertexAttribArray(uint32& paramOffset) { - glEnableVertexAttribArray(_params[paramOffset++]._uint); +void Batch::do_glEnableVertexAttribArray(uint32 paramOffset) { + glEnableVertexAttribArray(_params[paramOffset]._uint); + CHECK_GL_ERROR(); } void Batch::_glDisableVertexAttribArray(GLint location) { @@ -571,8 +649,9 @@ void Batch::_glDisableVertexAttribArray(GLint location) { DO_IT_NOW(_glDisableVertexAttribArray, 1); } -void Batch::do_glDisableVertexAttribArray(uint32& paramOffset) { - glDisableVertexAttribArray(_params[paramOffset++]._uint); +void Batch::do_glDisableVertexAttribArray(uint32 paramOffset) { + glDisableVertexAttribArray(_params[paramOffset]._uint); + CHECK_GL_ERROR(); } void Batch::_glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { @@ -585,8 +664,13 @@ void Batch::_glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) DO_IT_NOW(_glColor4f, 4); } -void Batch::do_glColor4f(uint32& paramOffset) { - glColor4f(_params[paramOffset++]._float, _params[paramOffset++]._float, _params[paramOffset++]._float, _params[paramOffset++]._float); +void Batch::do_glColor4f(uint32 paramOffset) { + glColor4f( + _params[paramOffset + 3]._float, + _params[paramOffset + 2]._float, + _params[paramOffset + 1]._float, + _params[paramOffset + 0]._float); + CHECK_GL_ERROR(); } void Batch::_glMaterialf(GLenum face, GLenum pname, GLfloat param) { @@ -598,8 +682,12 @@ void Batch::_glMaterialf(GLenum face, GLenum pname, GLfloat param) { DO_IT_NOW(_glMaterialf, 3); } -void Batch::do_glMaterialf(uint32& paramOffset) { - glMaterialf(_params[paramOffset++]._uint, _params[paramOffset++]._uint, _params[paramOffset++]._float); +void Batch::do_glMaterialf(uint32 paramOffset) { + glMaterialf( + _params[paramOffset + 2]._uint, + _params[paramOffset + 1]._uint, + _params[paramOffset + 0]._float); + CHECK_GL_ERROR(); } void Batch::_glMaterialfv(GLenum face, GLenum pname, const GLfloat *params) { @@ -611,14 +699,55 @@ void Batch::_glMaterialfv(GLenum face, GLenum pname, const GLfloat *params) { DO_IT_NOW(_glMaterialfv, 3); } -void Batch::do_glMaterialfv(uint32& paramOffset) { - glMaterialfv(_params[paramOffset++]._uint, _params[paramOffset++]._uint, (const GLfloat*) editData(_params[paramOffset++]._uint)); +void Batch::do_glMaterialfv(uint32 paramOffset) { + glMaterialfv( + _params[paramOffset + 2]._uint, + _params[paramOffset + 1]._uint, + (const GLfloat*) editData(_params[paramOffset + 0]._uint)); + CHECK_GL_ERROR(); } void backend::renderBatch(Batch& batch) { - for (int i = 0; i < batch._commands.size(); i++) { - batch.runCommand(i); + uint32 numCommands = batch._commands.size(); + Batch::CommandCall* call = batch._commandCalls.data(); + Batch::CommandOffsets::value_type* offset = batch._commandOffsets.data(); + + for (int i = 0; i < numCommands; i++) { + (batch.*(*call))(*offset); + call++; + offset++; } } + +void backend::checkGLError() { + GLenum error = glGetError(); + if (!error) { + return; + } else { + switch (error) { + case GL_INVALID_ENUM: + qDebug() << "An unacceptable value is specified for an enumerated argument.The offending command is ignored and has no other side effect than to set the error flag."; + break; + case GL_INVALID_VALUE: + qDebug() << "A numeric argument is out of range.The offending command is ignored and has no other side effect than to set the error flag"; + break; + case GL_INVALID_OPERATION: + qDebug() << "The specified operation is not allowed in the current state.The offending command is ignored and has no other side effect than to set the error flag.."; + break; + case GL_INVALID_FRAMEBUFFER_OPERATION: + qDebug() << "The framebuffer object is not complete.The offending command is ignored and has no other side effect than to set the error flag."; + break; + case GL_OUT_OF_MEMORY: + qDebug() << "There is not enough memory left to execute the command.The state of the GL is undefined, except for the state of the error flags, after this error is recorded."; + break; + case GL_STACK_UNDERFLOW: + qDebug() << "An attempt has been made to perform an operation that would cause an internal stack to underflow."; + break; + case GL_STACK_OVERFLOW: + qDebug() << "An attempt has been made to perform an operation that would cause an internal stack to overflow."; + break; + } + } +} \ No newline at end of file diff --git a/interface/src/gpu/Batch.h b/interface/src/gpu/Batch.h index 60c9c2d645..ad5246f9b6 100644 --- a/interface/src/gpu/Batch.h +++ b/interface/src/gpu/Batch.h @@ -23,6 +23,8 @@ class Batch; namespace backend { void renderBatch(Batch& batch); + + void checkGLError(); }; class Buffer; @@ -179,7 +181,7 @@ protected: COMMAND_glMaterialfv, }; typedef std::vector Commands; - typedef void (Batch::*CommandCall)(uint32&); + typedef void (Batch::*CommandCall)(uint32); typedef std::vector CommandCalls; typedef std::vector CommandOffsets; @@ -249,64 +251,64 @@ protected: void runCommand(Command com, uint32 offset); - void do_draw(uint32& paramOffset) {} - void do_drawIndexed(uint32& paramOffset) {} - void do_drawInstanced(uint32& paramOffset) {} - void do_drawIndexedInstanced(uint32& paramOffset) {} + void do_draw(uint32 paramOffset) {} + void do_drawIndexed(uint32 paramOffset) {} + void do_drawInstanced(uint32 paramOffset) {} + void do_drawIndexedInstanced(uint32 paramOffset) {} // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long // term strategy is to get rid of any GL calls in favor of the HIFI GPU API - void do_glEnable(uint32& paramOffset); - void do_glDisable(uint32& paramOffset); + void do_glEnable(uint32 paramOffset); + void do_glDisable(uint32 paramOffset); - void do_glEnableClientState(uint32& paramOffset); - void do_glDisableClientState(uint32& paramOffset); + void do_glEnableClientState(uint32 paramOffset); + void do_glDisableClientState(uint32 paramOffset); - void do_glCullFace(uint32& paramOffset); - void do_glAlphaFunc(uint32& paramOffset); + void do_glCullFace(uint32 paramOffset); + void do_glAlphaFunc(uint32 paramOffset); - void do_glDepthFunc(uint32& paramOffset); - void do_glDepthMask(uint32& paramOffset); - void do_glDepthRange(uint32& paramOffset); + void do_glDepthFunc(uint32 paramOffset); + void do_glDepthMask(uint32 paramOffset); + void do_glDepthRange(uint32 paramOffset); - void do_glBindBuffer(uint32& paramOffset); + void do_glBindBuffer(uint32 paramOffset); - void do_glBindTexture(uint32& paramOffset); - void do_glActiveTexture(uint32& paramOffset); + void do_glBindTexture(uint32 paramOffset); + void do_glActiveTexture(uint32 paramOffset); - void do_glDrawBuffers(uint32& paramOffset); + void do_glDrawBuffers(uint32 paramOffset); - void do_glUseProgram(uint32& paramOffset); - void do_glUniform1f(uint32& paramOffset); - void do_glUniformMatrix4fv(uint32& paramOffset); + void do_glUseProgram(uint32 paramOffset); + void do_glUniform1f(uint32 paramOffset); + void do_glUniformMatrix4fv(uint32 paramOffset); - void do_glMatrixMode(uint32& paramOffset); - void do_glPushMatrix(uint32& paramOffset); - void do_glPopMatrix(uint32& paramOffset); - void do_glMultMatrixf(uint32& paramOffset); - void do_glLoadMatrixf(uint32& paramOffset); - void do_glLoadIdentity(uint32& paramOffset); - void do_glRotatef(uint32& paramOffset); - void do_glScalef(uint32& paramOffset); - void do_glTranslatef(uint32& paramOffset); + void do_glMatrixMode(uint32 paramOffset); + void do_glPushMatrix(uint32 paramOffset); + void do_glPopMatrix(uint32 paramOffset); + void do_glMultMatrixf(uint32 paramOffset); + void do_glLoadMatrixf(uint32 paramOffset); + void do_glLoadIdentity(uint32 paramOffset); + void do_glRotatef(uint32 paramOffset); + void do_glScalef(uint32 paramOffset); + void do_glTranslatef(uint32 paramOffset); - void do_glDrawArrays(uint32& paramOffset); - void do_glDrawRangeElements(uint32& paramOffset); + void do_glDrawArrays(uint32 paramOffset); + void do_glDrawRangeElements(uint32 paramOffset); - void do_glColorPointer(uint32& paramOffset); - void do_glNormalPointer(uint32& paramOffset); - void do_glTexCoordPointer(uint32& paramOffset); - void do_glVertexPointer(uint32& paramOffset); + void do_glColorPointer(uint32 paramOffset); + void do_glNormalPointer(uint32 paramOffset); + void do_glTexCoordPointer(uint32 paramOffset); + void do_glVertexPointer(uint32 paramOffset); - void do_glVertexAttribPointer(uint32& paramOffset); - void do_glEnableVertexAttribArray(uint32& paramOffset); - void do_glDisableVertexAttribArray(uint32& paramOffset); + void do_glVertexAttribPointer(uint32 paramOffset); + void do_glEnableVertexAttribArray(uint32 paramOffset); + void do_glDisableVertexAttribArray(uint32 paramOffset); - void do_glColor4f(uint32& paramOffset); + void do_glColor4f(uint32 paramOffset); - void do_glMaterialf(uint32& paramOffset); - void do_glMaterialfv(uint32& paramOffset); + void do_glMaterialf(uint32 paramOffset); + void do_glMaterialfv(uint32 paramOffset); friend void backend::renderBatch(Batch& batch); }; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 739f5d75b1..0dd31c1785 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1819,7 +1819,7 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl GLBATCH(glMaterialfv)(GL_FRONT, GL_AMBIENT, (const float*)&diffuse); GLBATCH(glMaterialfv)(GL_FRONT, GL_DIFFUSE, (const float*)&diffuse); GLBATCH(glMaterialfv)(GL_FRONT, GL_SPECULAR, (const float*)&specular); - GLBATCH(glMaterialf)(GL_FRONT, GL_SHININESS, part.shininess); + GLBATCH(glMaterialf)(GL_FRONT, GL_SHININESS, (part.shininess > 128.f ? 128.f: part.shininess)); Texture* diffuseMap = networkPart.diffuseTexture.data(); if (mesh.isEye && diffuseMap) { From 345a9f02f78c43502dfecc5a2bde1f9e66072386 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 22 Oct 2014 14:30:20 -0700 Subject: [PATCH 038/119] Upload fix. --- assignment-client/src/metavoxels/MetavoxelServer.cpp | 6 +++--- assignment-client/src/metavoxels/MetavoxelServer.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index 3cf01bdc9f..81e86dbf11 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -237,8 +237,7 @@ void MetavoxelSession::update() { // go back to the beginning with the current packet and note that there's a delta pending _sequencer.getOutputStream().getUnderlying().device()->seek(start); - MetavoxelDeltaPendingMessage msg = { ++_reliableDeltaID, sendRecord->getPacketNumber(), - _sequencer.getIncomingPacketNumber() }; + MetavoxelDeltaPendingMessage msg = { ++_reliableDeltaID, sendRecord->getPacketNumber(), _lodPacketNumber }; out << (_reliableDeltaMessage = QVariant::fromValue(msg)); _sequencer.endPacket(); @@ -265,7 +264,8 @@ void MetavoxelSession::handleMessage(const QVariant& message) { if (userType == ClientStateMessage::Type) { ClientStateMessage state = message.value(); _lod = state.lod; - + _lodPacketNumber = _sequencer.getIncomingPacketNumber(); + } else if (userType == MetavoxelEditMessage::Type) { QMetaObject::invokeMethod(_sender->getServer(), "applyEdit", Q_ARG(const MetavoxelEditMessage&, message.value())); diff --git a/assignment-client/src/metavoxels/MetavoxelServer.h b/assignment-client/src/metavoxels/MetavoxelServer.h index 840041e0f0..a4facb5426 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.h +++ b/assignment-client/src/metavoxels/MetavoxelServer.h @@ -127,6 +127,7 @@ private: MetavoxelSender* _sender; MetavoxelLOD _lod; + int _lodPacketNumber; ReliableChannel* _reliableDeltaChannel; int _reliableDeltaReceivedOffset; From 14555c4534a2b96607c9ccdc7e40f011180bdc2f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 22 Oct 2014 14:54:04 -0700 Subject: [PATCH 039/119] Add UndoStackScriptingInterface and support when editing entities --- examples/libraries/entitySelectionTool.js | 59 +++++++++++++++++-- examples/newEditEntities.js | 2 +- interface/src/Application.cpp | 4 ++ interface/src/Application.h | 4 ++ .../src/UndoStackScriptingInterface.cpp | 46 +++++++++++++++ .../src/UndoStackScriptingInterface.h | 47 +++++++++++++++ 6 files changed, 156 insertions(+), 6 deletions(-) create mode 100644 libraries/script-engine/src/UndoStackScriptingInterface.cpp create mode 100644 libraries/script-engine/src/UndoStackScriptingInterface.h diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index f4f068742f..f1a94dbdd7 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -845,7 +845,7 @@ SelectionDisplay = (function () { Overlays.editOverlay(grabberMoveUp, { visible: translateHandlesVisible, position: { x: boundsCenter.x, y: top + grabberMoveUpOffset, z: boundsCenter.z } }); - that.updateHandles(entityID); + that.updateHandles(); Overlays.editOverlay(baseOfEntityProjectionOverlay, @@ -926,18 +926,17 @@ SelectionDisplay = (function () { entitySelected = false; }; - that.updateHandles = function(entityID) { + that.updateHandles = function() { + // print("Updating handles"); if (SelectionManager.selections.length == 0) { that.setOverlaysVisible(false); return; } - var properties = Entities.getEntityProperties(entityID); - var rotation, dimensions, position; if (spaceMode == SPACE_LOCAL) { - rotation = properties.rotation; + rotation = SelectionManager.localRotation; dimensions = SelectionManager.localDimensions; position = SelectionManager.localPosition; } else { @@ -1097,6 +1096,44 @@ SelectionDisplay = (function () { entitySelected = false; }; + function applyEntityProperties(data) { + for (var i = 0; i < data.length; i++) { + var entityID = data[i].entityID; + var properties = data[i].properties; + Entities.editEntity(entityID, properties); + } + selectionManager._update(); + }; + + // For currently selected entities, push a command to the UndoStack that uses the current entity properties for the + // redo command, and the saved properties for the undo command. + function pushCommandForSelections() { + var undoData = []; + var redoData = []; + for (var i = 0; i < SelectionManager.selections.length; i++) { + var entityID = SelectionManager.selections[i]; + var initialProperties = SelectionManager.savedProperties[entityID.id]; + var currentProperties = Entities.getEntityProperties(entityID); + undoData.push({ + entityID: entityID, + properties: { + position: initialProperties.position, + rotation: initialProperties.rotation, + dimensions: initialProperties.dimensions, + }, + }); + redoData.push({ + entityID: entityID, + properties: { + position: currentProperties.position, + rotation: currentProperties.rotation, + dimensions: currentProperties.dimensions, + }, + }); + } + UndoStack.pushCommand(applyEntityProperties, undoData, applyEntityProperties, redoData); + } + var lastXZPick = null; var translateXZTool = { mode: 'TRANSLATE_XZ', @@ -1116,6 +1153,8 @@ SelectionDisplay = (function () { var initialProperties = SelectionManager.savedProperties[entityID.id]; Entities.editEntity(entityID, initialProperties); } + } else { + pushCommandForSelections(); } }, onMove: function(event) { @@ -1174,6 +1213,8 @@ SelectionDisplay = (function () { var initialProperties = SelectionManager.savedProperties[entityID.id]; Entities.editEntity(entityID, initialProperties); } + } else { + pushCommandForSelections(); } }, onMove: function(event) { @@ -1336,6 +1377,8 @@ SelectionDisplay = (function () { var initialProperties = SelectionManager.savedProperties[entityID.id]; Entities.editEntity(entityID, initialProperties); } + } else { + pushCommandForSelections(); } }; @@ -1498,6 +1541,8 @@ SelectionDisplay = (function () { var initialProperties = SelectionManager.savedProperties[entityID.id]; Entities.editEntity(entityID, initialProperties); } + } else { + pushCommandForSelections(); } }, onMove: function(event) { @@ -1604,6 +1649,8 @@ SelectionDisplay = (function () { var initialProperties = SelectionManager.savedProperties[entityID.id]; Entities.editEntity(entityID, initialProperties); } + } else { + pushCommandForSelections(); } }, onMove: function(event) { @@ -1708,6 +1755,8 @@ SelectionDisplay = (function () { var initialProperties = SelectionManager.savedProperties[entityID.id]; Entities.editEntity(entityID, initialProperties); } + } else { + pushCommandForSelections(); } }, onMove: function(event) { diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index ae0d018b14..4d5abaf254 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -35,7 +35,7 @@ var entityPropertyDialogBox = EntityPropertyDialogBox; Script.include("libraries/entityCameraTool.js"); var entityCameraTool = new EntityCameraTool(); -selectionManager.setEventListener(selectionDisplay.updateHandles()); +selectionManager.setEventListener(selectionDisplay.updateHandles); var windowDimensions = Controller.getViewportDimensions(); var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/"; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 145222cd3c..6cd9d00364 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -172,6 +172,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _nodeBoundsDisplay(this), _previousScriptLocation(), _applicationOverlay(), + _undoStack(), + _undoStackScriptingInterface(&_undoStack), _runningScriptsWidget(NULL), _runningScriptsWidgetWasVisible(false), _trayIcon(new QSystemTrayIcon(_window)), @@ -3810,6 +3812,8 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser scriptEngine->registerGlobalObject("Joysticks", &JoystickScriptingInterface::getInstance()); qScriptRegisterMetaType(scriptEngine, joystickToScriptValue, joystickFromScriptValue); + scriptEngine->registerGlobalObject("UndoStack", &_undoStackScriptingInterface); + #ifdef HAVE_RTMIDI scriptEngine->registerGlobalObject("MIDI", &MIDIManager::getInstance()); #endif diff --git a/interface/src/Application.h b/interface/src/Application.h index 64c7032403..4779f9c810 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -91,6 +91,9 @@ #include "voxels/VoxelSystem.h" +#include "UndoStackScriptingInterface.h" + + class QAction; class QActionGroup; class QGLWidget; @@ -450,6 +453,7 @@ private: int _numChangedSettings; QUndoStack _undoStack; + UndoStackScriptingInterface _undoStackScriptingInterface; glm::vec3 _gravity; diff --git a/libraries/script-engine/src/UndoStackScriptingInterface.cpp b/libraries/script-engine/src/UndoStackScriptingInterface.cpp new file mode 100644 index 0000000000..42efe99c92 --- /dev/null +++ b/libraries/script-engine/src/UndoStackScriptingInterface.cpp @@ -0,0 +1,46 @@ +// +// UndoStackScriptingInterface.cpp +// libraries/script-engine/src +// +// Created by Ryan Huffman on 10/22/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include +#include + +#include "UndoStackScriptingInterface.h" + +UndoStackScriptingInterface::UndoStackScriptingInterface(QUndoStack* undoStack) : _undoStack(undoStack) { +} + +void UndoStackScriptingInterface::pushCommand(QScriptValue undoFunction, QScriptValue undoData, + QScriptValue redoFunction, QScriptValue redoData) { + ScriptUndoCommand* undoCommand = new ScriptUndoCommand(undoFunction, undoData, redoFunction, redoData); + qDebug() << "Pushing command"; + _undoStack->push(undoCommand); +} + +ScriptUndoCommand::ScriptUndoCommand(QScriptValue undoFunction, QScriptValue undoData, + QScriptValue redoFunction, QScriptValue redoData) : + _undoFunction(undoFunction), + _undoData(undoData), + _redoFunction(redoFunction), + _redoData(redoData) { +} + +void ScriptUndoCommand::undo() { + QScriptValueList args; + args << _undoData; + _undoFunction.call(QScriptValue(), args); +} + +void ScriptUndoCommand::redo() { + QScriptValueList args; + args << _redoData; + _redoFunction.call(QScriptValue(), args); +} diff --git a/libraries/script-engine/src/UndoStackScriptingInterface.h b/libraries/script-engine/src/UndoStackScriptingInterface.h new file mode 100644 index 0000000000..9ab822ff80 --- /dev/null +++ b/libraries/script-engine/src/UndoStackScriptingInterface.h @@ -0,0 +1,47 @@ +// +// UndoStackScriptingInterface.h +// libraries/script-engine/src +// +// Created by Ryan Huffman on 10/22/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_UndoStackScriptingInterface_h +#define hifi_UndoStackScriptingInterface_h + +#include +#include +#include + +class UndoStackScriptingInterface : public QObject { + Q_OBJECT +public: + UndoStackScriptingInterface(QUndoStack* undoStack); + +public slots: + void pushCommand(QScriptValue undoFunction, QScriptValue undoData, QScriptValue redoFunction, QScriptValue redoData); + +private: + QUndoStack* _undoStack; +}; + +class ScriptUndoCommand : public QUndoCommand { +public: + ScriptUndoCommand(QScriptValue undoFunction, QScriptValue undoData, QScriptValue redoFunction, QScriptValue redoData); + + virtual void undo(); + virtual void redo(); + virtual bool mergeWith(const QUndoCommand* command) { return false; } + virtual int id() const { return -1; } + +private: + QScriptValue _undoFunction; + QScriptValue _undoData; + QScriptValue _redoFunction; + QScriptValue _redoData; +}; + +#endif // hifi_UndoStackScriptingInterface_h From 70f72f94042a4a655046896cfdfe7ccc974dfbf6 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 22 Oct 2014 15:09:43 -0700 Subject: [PATCH 040/119] can warp at any yaw angle --- examples/headMove.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/headMove.js b/examples/headMove.js index 236130e23d..831e77a723 100644 --- a/examples/headMove.js +++ b/examples/headMove.js @@ -64,7 +64,6 @@ function activateWarp() { var TRIGGER_PULLBACK_DISTANCE = 0.04; var WATCH_AVATAR_DISTANCE = 1.5; -var MAX_WARP_YAW = 40.0; var MAX_PULLBACK_YAW = 5.0; var sound = new Sound("http://public.highfidelity.io/sounds/Footsteps/FootstepW2Right-12db.wav"); @@ -72,7 +71,7 @@ function playSound() { var options = new AudioInjectionOptions(); var position = MyAvatar.position; options.position = position; - options.volume = 0.5; + options.volume = 1.0; Audio.playSound(sound, options); } @@ -89,7 +88,7 @@ function updateWarp() { var deltaPitch = MyAvatar.getHeadFinalPitch() - headStartFinalPitch; deltaYaw = MyAvatar.getHeadFinalYaw() - headStartYaw; - willMove = (!watchAvatar && (Math.abs(deltaYaw) < MAX_WARP_YAW) && (keyDownTime > WARP_START_TIME)); + willMove = (!watchAvatar && (keyDownTime > WARP_START_TIME)); if (willMove) { //var distance = Math.pow((deltaPitch - WARP_PITCH_DEAD_ZONE) * WARP_SENSITIVITY, 2.0); From ac8d947cb1d38db06b92b00cfc29517b75381c23 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 22 Oct 2014 15:18:49 -0700 Subject: [PATCH 041/119] Update ScriptUndoCommand to run on ScriptEngine thread --- .../src/UndoStackScriptingInterface.cpp | 20 +++++++++++++++---- .../src/UndoStackScriptingInterface.h | 7 ++++++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/libraries/script-engine/src/UndoStackScriptingInterface.cpp b/libraries/script-engine/src/UndoStackScriptingInterface.cpp index 42efe99c92..ed0f4d563d 100644 --- a/libraries/script-engine/src/UndoStackScriptingInterface.cpp +++ b/libraries/script-engine/src/UndoStackScriptingInterface.cpp @@ -10,6 +10,7 @@ // #include +#include #include #include @@ -20,9 +21,11 @@ UndoStackScriptingInterface::UndoStackScriptingInterface(QUndoStack* undoStack) void UndoStackScriptingInterface::pushCommand(QScriptValue undoFunction, QScriptValue undoData, QScriptValue redoFunction, QScriptValue redoData) { - ScriptUndoCommand* undoCommand = new ScriptUndoCommand(undoFunction, undoData, redoFunction, redoData); - qDebug() << "Pushing command"; - _undoStack->push(undoCommand); + if (undoFunction.engine()) { + ScriptUndoCommand* undoCommand = new ScriptUndoCommand(undoFunction, undoData, redoFunction, redoData); + undoCommand->moveToThread(undoFunction.engine()->thread()); + _undoStack->push(undoCommand); + } } ScriptUndoCommand::ScriptUndoCommand(QScriptValue undoFunction, QScriptValue undoData, @@ -34,12 +37,21 @@ ScriptUndoCommand::ScriptUndoCommand(QScriptValue undoFunction, QScriptValue und } void ScriptUndoCommand::undo() { + QMetaObject::invokeMethod(this, "doUndo"); +} + +void ScriptUndoCommand::redo() { + QMetaObject::invokeMethod(this, "doRedo"); +} + +void ScriptUndoCommand::doUndo() { QScriptValueList args; args << _undoData; _undoFunction.call(QScriptValue(), args); } -void ScriptUndoCommand::redo() { + +void ScriptUndoCommand::doRedo() { QScriptValueList args; args << _redoData; _redoFunction.call(QScriptValue(), args); diff --git a/libraries/script-engine/src/UndoStackScriptingInterface.h b/libraries/script-engine/src/UndoStackScriptingInterface.h index 9ab822ff80..835e5dfff4 100644 --- a/libraries/script-engine/src/UndoStackScriptingInterface.h +++ b/libraries/script-engine/src/UndoStackScriptingInterface.h @@ -28,7 +28,8 @@ private: QUndoStack* _undoStack; }; -class ScriptUndoCommand : public QUndoCommand { +class ScriptUndoCommand : public QObject, public QUndoCommand { + Q_OBJECT public: ScriptUndoCommand(QScriptValue undoFunction, QScriptValue undoData, QScriptValue redoFunction, QScriptValue redoData); @@ -37,6 +38,10 @@ public: virtual bool mergeWith(const QUndoCommand* command) { return false; } virtual int id() const { return -1; } +public slots: + void doUndo(); + void doRedo(); + private: QScriptValue _undoFunction; QScriptValue _undoData; From a48811777e0db7297df1e6e17e29a31cede93f13 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 15:26:16 -0700 Subject: [PATCH 042/119] Script engine audio dependency --- libraries/script-engine/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 7073280ee5..166ee8c50e 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -5,7 +5,7 @@ setup_hifi_library(Gui Network Script Widgets) include_glm() -link_hifi_libraries(shared octree voxels fbx entities animation) +link_hifi_libraries(shared octree voxels fbx entities animation audio) # call macro to link our dependencies and bubble them up via a property on our target link_shared_dependencies() From 7b0f1477a1a3d5b29f1eeab56f43612175a65baf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Oct 2014 15:28:04 -0700 Subject: [PATCH 043/119] expose AvatarList to Interface SE, add avatarWithDisplayName method --- interface/src/Application.cpp | 3 ++- libraries/avatars/src/AvatarData.h | 2 ++ libraries/avatars/src/AvatarHashMap.cpp | 10 +++++++--- libraries/avatars/src/AvatarHashMap.h | 2 ++ libraries/script-engine/src/ScriptEngine.cpp | 12 ++++++++++-- 5 files changed, 23 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 145222cd3c..99c23f526b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3766,8 +3766,9 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser // AvatarManager has some custom types AvatarManager::registerMetaTypes(scriptEngine); - // hook our avatar object into this script engine + // hook our avatar and avatar hash map object into this script engine scriptEngine->setAvatarData(_myAvatar, "MyAvatar"); // leave it as a MyAvatar class to expose thrust features + scriptEngine->setAvatarHashMap(&_avatarManager, "AvatarList"); CameraScriptableObject* cameraScriptable = new CameraScriptableObject(&_myCamera, &_viewFrustum); scriptEngine->registerGlobalObject("Camera", cameraScriptable); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 1fd4052974..29682da286 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -381,6 +381,8 @@ private: AvatarData& operator= (const AvatarData&); }; +Q_DECLARE_METATYPE(AvatarData*) + class JointData { public: bool valid; diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index f996fc2bad..b74205c6b6 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -21,6 +21,7 @@ AvatarHashMap::AvatarHashMap() : connect(NodeList::getInstance(), &NodeList::uuidChanged, this, &AvatarHashMap::sessionUUIDChanged); } + AvatarHash::iterator AvatarHashMap::erase(const AvatarHash::iterator& iterator) { qDebug() << "Removing Avatar with UUID" << iterator.key() << "from AvatarHashMap."; return _avatarHash.erase(iterator); @@ -53,7 +54,10 @@ void AvatarHashMap::processAvatarMixerDatagram(const QByteArray& datagram, const } bool AvatarHashMap::containsAvatarWithDisplayName(const QString& displayName) { - + return avatarWithDisplayName(displayName) == NULL ? false : true; +} + +AvatarData* AvatarHashMap::avatarWithDisplayName(const QString& displayName) { AvatarHash::iterator avatarIterator = _avatarHash.begin(); while (avatarIterator != _avatarHash.end()) { AvatarSharedPointer sharedAvatar = avatarIterator.value(); @@ -62,7 +66,7 @@ bool AvatarHashMap::containsAvatarWithDisplayName(const QString& displayName) { // check if this avatar should still be around if (!shouldKillAvatar(sharedAvatar)) { // we have a match, return true - return true; + return sharedAvatar.data(); } else { // we should remove this avatar, do that now erase(avatarIterator); @@ -75,7 +79,7 @@ bool AvatarHashMap::containsAvatarWithDisplayName(const QString& displayName) { } // return false, no match - return false; + return NULL; } AvatarSharedPointer AvatarHashMap::newSharedAvatar() { diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h index d52c656bc1..03b0bf887c 100644 --- a/libraries/avatars/src/AvatarHashMap.h +++ b/libraries/avatars/src/AvatarHashMap.h @@ -21,6 +21,7 @@ #include "AvatarData.h" typedef QSharedPointer AvatarSharedPointer; +typedef QWeakPointer AvatarWeakPointer; typedef QHash AvatarHash; class AvatarHashMap : public QObject { @@ -34,6 +35,7 @@ public: public slots: void processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer& mixerWeakPointer); bool containsAvatarWithDisplayName(const QString& displayName); + AvatarData* avatarWithDisplayName(const QString& displayname); private slots: void sessionUUIDChanged(const QUuid& sessionUUID, const QUuid& oldUUID); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index eb5dd07ffb..93da900055 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -63,7 +63,15 @@ static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){ return QScriptValue(); } -QScriptValue injectorToScriptValue(QScriptEngine *engine, AudioInjector* const &in) { +QScriptValue avatarDataToScriptValue(QScriptEngine* engine, AvatarData* const &in) { + return engine->newQObject(in); +} + +void avatarDataFromScriptValue(const QScriptValue &object, AvatarData* &out) { + out = qobject_cast(object.toQObject()); +} + +QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const &in) { return engine->newQObject(in); } @@ -272,7 +280,7 @@ void ScriptEngine::init() { qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue); qScriptRegisterMetaType(this, inputControllerToScriptValue, inputControllerFromScriptValue); - + qScriptRegisterMetaType(this, avatarDataToScriptValue, avatarDataFromScriptValue); qScriptRegisterMetaType(this, animationDetailsToScriptValue, animationDetailsFromScriptValue); registerGlobalObject("Script", this); From 8ccbfcf69581182faf1f2888610916a38cc89386 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 16:41:41 -0700 Subject: [PATCH 044/119] code cleanup --- assignment-client/src/audio/AudioMixer.cpp | 5 ++--- interface/src/Audio.cpp | 8 ++------ 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 9b91dd8c1e..fbd414f6c1 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -732,7 +732,8 @@ void AudioMixer::run() { // Pack stream properties for (int i = 0; i < _zoneReverbSettings.size(); ++i) { - glm::vec3 streamPosition = static_cast(node->getLinkedData())->getAvatarAudioStream()->getPosition(); + AudioMixerClientData* data = static_cast(node->getLinkedData()); + glm::vec3 streamPosition = data->getAvatarAudioStream()->getPosition(); if (_audioZones[_zoneReverbSettings[i].zone].contains(streamPosition)) { bool hasReverb = true; float reverbTime = _zoneReverbSettings[i].reverbTime; @@ -751,7 +752,6 @@ void AudioMixer::run() { } } - // pack mixed audio samples memcpy(dataAt, _mixSamples, NETWORK_BUFFER_LENGTH_BYTES_STEREO); dataAt += NETWORK_BUFFER_LENGTH_BYTES_STEREO; @@ -1076,7 +1076,6 @@ void AudioMixer::parseSettingsObject(const QJsonObject &settingsObject) { float wetLevel = reverbObject.value(WET_LEVEL).toString().toFloat(&okWetLevel); if (okReverbTime && okWetLevel && _audioZones.contains(zone)) { - ReverbSettings settings; settings.zone = zone; settings.reverbTime = reverbTime; diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 527703f7a4..dd84eb3211 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -544,15 +544,11 @@ void Audio::addReverb(int16_t* samplesData, int numSamples, QAudioFormat& audioF for (unsigned int j = sample; j < sample + audioFormat.channelCount(); j++) { if (j == sample) { // left channel - int lResult = (int)(samplesData[j] * dryFraction + lValue * wetFraction); - if (lResult > 32767) lResult = 32767; - if (lResult < -32768) lResult = -32768; + int lResult = glm::clamp((int)(samplesData[j] * dryFraction + lValue * wetFraction), -32768, 32767); samplesData[j] = (int16_t)lResult; } else if (j == (sample + 1)) { // right channel - int rResult = (int)(samplesData[j] * dryFraction + rValue * wetFraction); - if (rResult > 32767) rResult = 32767; - if (rResult < -32768) rResult = -32768; + int rResult = glm::clamp((int)(samplesData[j] * dryFraction + rValue * wetFraction), -32768, 32767); samplesData[j] = (int16_t)rResult; } else { // ignore channels above 2 From 38d50a76ebae9dc7a15aecdb1632ab62491eb92c Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 22 Oct 2014 16:47:40 -0700 Subject: [PATCH 045/119] Add IsFacingAvatar getter and setter to Text3DOverlay --- interface/src/ui/overlays/Text3DOverlay.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/ui/overlays/Text3DOverlay.h b/interface/src/ui/overlays/Text3DOverlay.h index 855890e493..c49116ee0c 100644 --- a/interface/src/ui/overlays/Text3DOverlay.h +++ b/interface/src/ui/overlays/Text3DOverlay.h @@ -32,6 +32,7 @@ public: float getTopMargin() const { return _topMargin; } float getRightMargin() const { return _rightMargin; } float getBottomMargin() const { return _bottomMargin; } + bool getIsFacingAvatar() const { return _isFacingAvatar; } xColor getBackgroundColor(); // setters @@ -41,6 +42,7 @@ public: void setTopMargin(float margin) { _topMargin = margin; } void setRightMargin(float margin) { _rightMargin = margin; } void setBottomMargin(float margin) { _bottomMargin = margin; } + void setIsFacingAvatar(bool isFacingAvatar) { _isFacingAvatar = isFacingAvatar; } virtual void setProperties(const QScriptValue& properties); From 93a0eb18bd4c1db02c5af2ab652cd737b12cdab1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 16:50:02 -0700 Subject: [PATCH 046/119] Added readme --- interface/external/gverb/readme.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 interface/external/gverb/readme.txt diff --git a/interface/external/gverb/readme.txt b/interface/external/gverb/readme.txt new file mode 100644 index 0000000000..aa2fe8a602 --- /dev/null +++ b/interface/external/gverb/readme.txt @@ -0,0 +1,15 @@ + +Instructions for adding the Gverb library to Interface +(This is a required library) +Clément Brisset, Octobre 22nd, 2014 + +1. Go to https://github.com/highfidelity/gverb + Or download the sources directly via this link: + https://github.com/highfidelity/gverb/archive/master.zip + +2. Extract the archive + +3. Place the directories “include” and “src” in interface/external/gverb + (Normally next to this readme) + +4. Clear your build directory, run cmake, build and you should be all set. \ No newline at end of file From 0e3495986de948e588f98792683ea72349448e04 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 22 Oct 2014 16:58:10 -0700 Subject: [PATCH 047/119] Add countdown to HMD calibration billboard --- interface/src/devices/OculusManager.cpp | 19 +++++++++++-------- interface/src/devices/OculusManager.h | 6 ++---- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 62894510c2..709080e354 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -66,8 +66,6 @@ glm::vec3 OculusManager::_calibrationPosition; glm::quat OculusManager::_calibrationOrientation; quint64 OculusManager::_calibrationStartTime; int OculusManager::_calibrationMessage = NULL; -QString OculusManager::CALIBRATION_BILLBOARD_URL = "http://hifi-public.s3.amazonaws.com/images/hold-to-calibrate.svg"; -float OculusManager::CALIBRATION_BILLBOARD_SCALE = 2.f; #endif @@ -191,7 +189,7 @@ void OculusManager::disconnect() { } #ifdef HAVE_LIBOVR -void OculusManager::positionCalibrationBillboard(BillboardOverlay* billboard) { +void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) { glm::quat headOrientation = Application::getInstance()->getAvatar()->getHeadOrientation(); headOrientation.x = 0; headOrientation.z = 0; @@ -204,8 +202,9 @@ void OculusManager::positionCalibrationBillboard(BillboardOverlay* billboard) { #ifdef HAVE_LIBOVR void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { + static QString instructionMessage = "Hold still to calibrate"; static QString progressMessage; - static BillboardOverlay* billboard; + static Text3DOverlay* billboard; switch (_calibrationState) { @@ -235,9 +234,13 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { if (!_calibrationMessage) { qDebug() << "Hold still to calibrate HMD"; - billboard = new BillboardOverlay(); - billboard->setURL(CALIBRATION_BILLBOARD_URL); - billboard->setScale(CALIBRATION_BILLBOARD_SCALE); + billboard = new Text3DOverlay(); + billboard->setDimensions(glm::vec2(2.0f, 1.25f)); + billboard->setTopMargin(0.35f); + billboard->setLeftMargin(0.28f); + billboard->setText(instructionMessage); + billboard->setAlpha(0.5f); + billboard->setLineHeight(0.1f); billboard->setIsFacingAvatar(false); positionCalibrationBillboard(billboard); @@ -275,7 +278,7 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { } else { progressMessage += "."; } - //qDebug() << progressMessage; // Progress message ready for 3D text overlays. + billboard->setText(instructionMessage + "\n\n" + progressMessage); } } } else { diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index dfe4a212b6..20e43d572c 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -18,7 +18,7 @@ #endif #include "renderer/ProgramObject.h" -#include "ui/overlays/BillboardOverlay.h" +#include "ui/overlays/Text3DOverlay.h" const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f; @@ -111,7 +111,7 @@ private: WAITING_FOR_ZERO_HELD, CALIBRATED }; - static void positionCalibrationBillboard(BillboardOverlay* billboard); + static void positionCalibrationBillboard(Text3DOverlay* message); static float CALIBRATION_DELTA_MINIMUM_LENGTH; static float CALIBRATION_DELTA_MINIMUM_ANGLE; static float CALIBRATION_ZERO_MAXIMUM_LENGTH; @@ -123,8 +123,6 @@ private: static glm::quat _calibrationOrientation; static quint64 _calibrationStartTime; static int _calibrationMessage; - static QString CALIBRATION_BILLBOARD_URL; - static float CALIBRATION_BILLBOARD_SCALE; #endif From 04416ff40cd8ae334a4acac9a869a5e9849c71c9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Oct 2014 17:27:42 -0700 Subject: [PATCH 048/119] fix for DataWebPage hifi link handling --- interface/src/ui/DataWebPage.cpp | 18 +++++++++++++++--- interface/src/ui/DataWebPage.h | 1 + 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/DataWebPage.cpp b/interface/src/ui/DataWebPage.cpp index 812489a34d..b8b6649276 100644 --- a/interface/src/ui/DataWebPage.cpp +++ b/interface/src/ui/DataWebPage.cpp @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + +#include #include #include "DataWebPage.h" @@ -19,13 +22,22 @@ DataWebPage::DataWebPage(QObject* 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; +} + +bool DataWebPage::acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, QWebPage::NavigationType type) { + + if (!request.url().toString().startsWith(HIFI_URL_SCHEME)) { + return true; + } else { + // this is a hifi URL - have the AddressManager handle it + QMetaObject::invokeMethod(&AddressManager::getInstance(), "handleLookupString", + Qt::AutoConnection, Q_ARG(const QString&, request.url().toString())); + return false; + } } \ No newline at end of file diff --git a/interface/src/ui/DataWebPage.h b/interface/src/ui/DataWebPage.h index 72fcbb5992..6d89077a33 100644 --- a/interface/src/ui/DataWebPage.h +++ b/interface/src/ui/DataWebPage.h @@ -19,6 +19,7 @@ public: DataWebPage(QObject* parent = 0); protected: void javaScriptConsoleMessage(const QString & message, int lineNumber, const QString & sourceID); + bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, QWebPage::NavigationType type); }; #endif // hifi_DataWebPage_h \ No newline at end of file From 8e67c5f53485b016d66dc5d47f7f06d69cc26267 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Oct 2014 17:35:28 -0700 Subject: [PATCH 049/119] don't erase from the AvatarHashMap on the wrong thread --- libraries/avatars/src/AvatarHashMap.cpp | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index b74205c6b6..4f69eb2e3d 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -58,27 +58,21 @@ bool AvatarHashMap::containsAvatarWithDisplayName(const QString& displayName) { } AvatarData* AvatarHashMap::avatarWithDisplayName(const QString& displayName) { - AvatarHash::iterator avatarIterator = _avatarHash.begin(); - while (avatarIterator != _avatarHash.end()) { - AvatarSharedPointer sharedAvatar = avatarIterator.value(); - if (avatarIterator.value()->getDisplayName() == displayName) { + foreach(const AvatarSharedPointer& sharedAvatar, _avatarHash) { + if (sharedAvatar->getDisplayName() == displayName) { // this is a match // check if this avatar should still be around if (!shouldKillAvatar(sharedAvatar)) { - // we have a match, return true + // we have a match, return the AvatarData return sharedAvatar.data(); } else { - // we should remove this avatar, do that now - erase(avatarIterator); + // we should remove this avatar, but we might not be on a thread that is allowed + // so we just return NULL to the caller + return NULL; } - - break; - } else { - ++avatarIterator; } } - - // return false, no match + return NULL; } From 271c01ad030dd4c2b24953320297c2f8d0d7aa40 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 22 Oct 2014 17:44:56 -0700 Subject: [PATCH 050/119] Fix for digging into converted heightfields. --- libraries/metavoxels/src/MetavoxelMessages.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index 299ffbbb80..d9c60f3f12 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -701,8 +701,7 @@ int VoxelMaterialSpannerEditVisitor::visit(MetavoxelInfo& info) { int sizeY = (int)overlap.maximum.y - minY + 1; int sizeZ = (int)overlap.maximum.z - minZ + 1; - QRgb rgb = _color.rgba(); - bool flipped = (qAlpha(rgb) == 0); + bool flipped = false; float step = 1.0f / scale; glm::vec3 position(0.0f, 0.0f, info.minimum.z + minZ * step); if (_spanner->hasOwnColors()) { @@ -720,6 +719,8 @@ int VoxelMaterialSpannerEditVisitor::visit(MetavoxelInfo& info) { } } } else { + QRgb rgb = _color.rgba(); + flipped = (qAlpha(rgb) == 0); for (QRgb* destZ = colorContents.data() + minZ * VOXEL_BLOCK_AREA + minY * VOXEL_BLOCK_SAMPLES + minX, *endZ = destZ + sizeZ * VOXEL_BLOCK_AREA; destZ != endZ; destZ += VOXEL_BLOCK_AREA, position.z += step) { position.y = info.minimum.y + minY * step; From 631419d23c62739f7927593fe7e67b32e1de0723 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 22 Oct 2014 18:22:21 -0700 Subject: [PATCH 051/119] Tweaks to heightfield conversion. --- .../shaders/metavoxel_heightfield_base.vert | 13 +++--- .../metavoxels/src/MetavoxelMessages.cpp | 43 ++++++++++++------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/interface/resources/shaders/metavoxel_heightfield_base.vert b/interface/resources/shaders/metavoxel_heightfield_base.vert index f097426e13..5486f5fa67 100644 --- a/interface/resources/shaders/metavoxel_heightfield_base.vert +++ b/interface/resources/shaders/metavoxel_heightfield_base.vert @@ -26,11 +26,14 @@ varying vec4 normal; void main(void) { // transform and store the normal for interpolation vec2 heightCoord = gl_MultiTexCoord0.st; - float deltaX = texture2D(heightMap, heightCoord - vec2(heightScale, 0.0)).r - - texture2D(heightMap, heightCoord + vec2(heightScale, 0.0)).r; - float deltaZ = texture2D(heightMap, heightCoord - vec2(0.0, heightScale)).r - - texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r; - normal = normalize(gl_ModelViewMatrix * vec4(deltaX, heightScale, deltaZ, 0.0)); + vec4 neighborHeights = vec4(texture2D(heightMap, heightCoord - vec2(heightScale, 0.0)).r, + texture2D(heightMap, heightCoord + vec2(heightScale, 0.0)).r, + texture2D(heightMap, heightCoord - vec2(0.0, heightScale)).r, + texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r); + vec4 neighborsZero = step(1.0 / 255.0, neighborHeights); + normal = normalize(gl_ModelViewMatrix * vec4( + (neighborHeights.x - neighborHeights.y) * neighborsZero.x * neighborsZero.y, heightScale, + (neighborHeights.z - neighborHeights.w) * neighborsZero.z * neighborsZero.w, 0.0)); // add the height to the position float height = texture2D(heightMap, heightCoord).r; diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index d9c60f3f12..2d1e03fc69 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -1062,6 +1062,13 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) { HeightfieldHeightDataPointer newHeightPointer(new HeightfieldHeightData(contents)); info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(newHeightPointer)); + // allow a border for what we clear in terms of color/material + innerBounds.minimum.x += increment; + innerBounds.minimum.z += increment; + innerBounds.maximum.x -= increment; + innerBounds.maximum.z -= increment; + innerOverlap = bounds.getIntersection(innerBounds); + HeightfieldColorDataPointer colorPointer = info.inputValues.at(1).getInlineValue(); if (colorPointer) { contents = colorPointer->getContents(); @@ -1087,14 +1094,16 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) { destY = (innerOverlap.minimum.z - info.minimum.z) * heightScale; destWidth = glm::ceil((innerOverlap.maximum.x - innerOverlap.minimum.x) * heightScale); destHeight = glm::ceil((innerOverlap.maximum.z - innerOverlap.minimum.z) * heightScale); - dest = contents.data() + (destY * size + destX) * DataBlock::COLOR_BYTES; - - for (int y = 0; y < destHeight; y++, dest += size * DataBlock::COLOR_BYTES) { - memset(dest, 0, destWidth * DataBlock::COLOR_BYTES); + if (destWidth > 0 && destHeight > 0) { + dest = contents.data() + (destY * size + destX) * DataBlock::COLOR_BYTES; + + for (int y = 0; y < destHeight; y++, dest += size * DataBlock::COLOR_BYTES) { + memset(dest, 0, destWidth * DataBlock::COLOR_BYTES); + } + + HeightfieldColorDataPointer newColorPointer(new HeightfieldColorData(contents)); + info.outputValues[1] = AttributeValue(_outputs.at(1), encodeInline(newColorPointer)); } - - HeightfieldColorDataPointer newColorPointer(new HeightfieldColorData(contents)); - info.outputValues[1] = AttributeValue(_outputs.at(1), encodeInline(newColorPointer)); } HeightfieldMaterialDataPointer materialPointer = info.inputValues.at(2).getInlineValue(); @@ -1134,16 +1143,18 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) { destY = (innerOverlap.minimum.z - info.minimum.z) * heightScale; destWidth = glm::ceil((innerOverlap.maximum.x - innerOverlap.minimum.x) * heightScale); destHeight = glm::ceil((innerOverlap.maximum.z - innerOverlap.minimum.z) * heightScale); - dest = (uchar*)contents.data() + destY * size + destX; - - for (int y = 0; y < destHeight; y++, dest += size) { - memset(dest, 0, destWidth); + if (destWidth > 0 && destHeight > 0) { + dest = (uchar*)contents.data() + destY * size + destX; + + for (int y = 0; y < destHeight; y++, dest += size) { + memset(dest, 0, destWidth); + } + + clearUnusedMaterials(materials, contents); + HeightfieldMaterialDataPointer newMaterialPointer(new HeightfieldMaterialData(contents, materials)); + info.outputValues[2] = AttributeValue(_outputs.at(2), + encodeInline(newMaterialPointer)); } - - clearUnusedMaterials(materials, contents); - HeightfieldMaterialDataPointer newMaterialPointer(new HeightfieldMaterialData(contents, materials)); - info.outputValues[2] = AttributeValue(_outputs.at(2), - encodeInline(newMaterialPointer)); } return STOP_RECURSION; From b1b7114e66f437ee23fbd20d62164b94ca2d4348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Brisset?= Date: Wed, 22 Oct 2014 22:46:37 -0700 Subject: [PATCH 052/119] Revert "Reverb" --- assignment-client/src/audio/AudioMixer.cpp | 58 +--------- assignment-client/src/audio/AudioMixer.h | 8 +- cmake/modules/FindGverb.cmake | 39 ------- .../resources/describe-settings.json | 27 ----- examples/audioReverbOn.js | 39 ------- interface/CMakeLists.txt | 13 +-- interface/external/gverb/readme.txt | 15 --- interface/src/Audio.cpp | 102 +---------------- interface/src/Audio.h | 19 ---- .../AudioDeviceScriptingInterface.cpp | 8 -- .../scripting/AudioDeviceScriptingInterface.h | 2 - libraries/audio/src/AudioEffectOptions.cpp | 88 --------------- libraries/audio/src/AudioEffectOptions.h | 106 ------------------ libraries/audio/src/InboundAudioStream.cpp | 20 +--- libraries/audio/src/InboundAudioStream.h | 9 -- libraries/script-engine/CMakeLists.txt | 2 +- libraries/script-engine/src/ScriptEngine.cpp | 4 - 17 files changed, 13 insertions(+), 546 deletions(-) delete mode 100644 cmake/modules/FindGverb.cmake delete mode 100644 examples/audioReverbOn.js delete mode 100644 interface/external/gverb/readme.txt delete mode 100644 libraries/audio/src/AudioEffectOptions.cpp delete mode 100644 libraries/audio/src/AudioEffectOptions.h diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index fbd414f6c1..8caf4ddf09 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -428,8 +428,8 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l } int AudioMixer::prepareMixForListeningNode(Node* node) { - AvatarAudioStream* nodeAudioStream = static_cast(node->getLinkedData())->getAvatarAudioStream(); - AudioMixerClientData* listenerNodeData = static_cast(node->getLinkedData()); + AvatarAudioStream* nodeAudioStream = ((AudioMixerClientData*) node->getLinkedData())->getAvatarAudioStream(); + AudioMixerClientData* listenerNodeData = (AudioMixerClientData*)node->getLinkedData(); // zero out the client mix for this node memset(_preMixSamples, 0, sizeof(_preMixSamples)); @@ -730,28 +730,6 @@ void AudioMixer::run() { memcpy(dataAt, &sequence, sizeof(quint16)); dataAt += sizeof(quint16); - // Pack stream properties - for (int i = 0; i < _zoneReverbSettings.size(); ++i) { - AudioMixerClientData* data = static_cast(node->getLinkedData()); - glm::vec3 streamPosition = data->getAvatarAudioStream()->getPosition(); - if (_audioZones[_zoneReverbSettings[i].zone].contains(streamPosition)) { - bool hasReverb = true; - float reverbTime = _zoneReverbSettings[i].reverbTime; - float wetLevel = _zoneReverbSettings[i].wetLevel; - - memcpy(dataAt, &hasReverb, sizeof(bool)); - dataAt += sizeof(bool); - memcpy(dataAt, &reverbTime, sizeof(float)); - dataAt += sizeof(float); - memcpy(dataAt, &wetLevel, sizeof(float)); - dataAt += sizeof(float); - } else { - bool hasReverb = false; - memcpy(dataAt, &hasReverb, sizeof(bool)); - dataAt += sizeof(bool); - } - } - // pack mixed audio samples memcpy(dataAt, _mixSamples, NETWORK_BUFFER_LENGTH_BYTES_STEREO); dataAt += NETWORK_BUFFER_LENGTH_BYTES_STEREO; @@ -1055,38 +1033,6 @@ void AudioMixer::parseSettingsObject(const QJsonObject &settingsObject) { } } } - - const QString REVERB = "reverb"; - if (audioEnvGroupObject[REVERB].isArray()) { - const QJsonArray& reverb = audioEnvGroupObject[REVERB].toArray(); - - const QString ZONE = "zone"; - const QString REVERB_TIME = "reverb_time"; - const QString WET_LEVEL = "wet_level"; - for (int i = 0; i < reverb.count(); ++i) { - QJsonObject reverbObject = reverb[i].toObject(); - - if (reverbObject.contains(ZONE) && - reverbObject.contains(REVERB_TIME) && - reverbObject.contains(WET_LEVEL)) { - - bool okReverbTime, okWetLevel; - QString zone = reverbObject.value(ZONE).toString(); - float reverbTime = reverbObject.value(REVERB_TIME).toString().toFloat(&okReverbTime); - float wetLevel = reverbObject.value(WET_LEVEL).toString().toFloat(&okWetLevel); - - if (okReverbTime && okWetLevel && _audioZones.contains(zone)) { - ReverbSettings settings; - settings.zone = zone; - settings.reverbTime = reverbTime; - settings.wetLevel = wetLevel; - - _zoneReverbSettings.push_back(settings); - qDebug() << "Added Reverb:" << zone << reverbTime << wetLevel; - } - } - } - } } } diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index ff976dec61..3cfa5443a8 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -82,13 +82,7 @@ private: float coefficient; }; QVector _zonesSettings; - struct ReverbSettings { - QString zone; - float reverbTime; - float wetLevel; - }; - QVector _zoneReverbSettings; - + static InboundAudioStream::Settings _streamSettings; static bool _printStreamStats; diff --git a/cmake/modules/FindGverb.cmake b/cmake/modules/FindGverb.cmake deleted file mode 100644 index 549c23c8a9..0000000000 --- a/cmake/modules/FindGverb.cmake +++ /dev/null @@ -1,39 +0,0 @@ -# FindGVerb.cmake -# -# Try to find the Gverb library. -# -# You must provide a GVERB_ROOT_DIR which contains src and include directories -# -# Once done this will define -# -# GVERB_FOUND - system found Gverb -# GVERB_INCLUDE_DIRS - the Gverb include directory -# -# 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 -# - -if (GVERB_INCLUDE_DIRS) - # in cache already - set(GVERB_FOUND TRUE) -else (GVERB_INCLUDE_DIRS) - - include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") - hifi_library_search_hints("gverb") - - find_path(GVERB_INCLUDE_DIRS gverb.h PATH_SUFFIXES include HINTS ${GVERB_SEARCH_DIRS}) - find_path(GVERB_SRC_DIRS gverb.c PATH_SUFFIXES src HINTS ${GVERB_SEARCH_DIRS}) - - if (GVERB_INCLUDE_DIRS) - set(GVERB_FOUND TRUE) - endif (GVERB_INCLUDE_DIRS) - - if (GVERB_FOUND) - message(STATUS "Found Gverb: ${GVERB_INCLUDE_DIRS}") - else (GVERB_FOUND) - message(FATAL_ERROR "Could NOT find Gverb. Read ./interface/externals/gverb/readme.txt") - endif (GVERB_FOUND) - -endif(GVERB_INCLUDE_DIRS) \ No newline at end of file diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 026fe252b2..2c33897d07 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -154,33 +154,6 @@ "placeholder": "0.18" } ] - }, - { - "name": "reverb", - "type": "table", - "label": "Reverb Settings", - "help": "In this table you can set custom reverb values for each audio zones", - "numbered": true, - "columns": [ - { - "name": "zone", - "label": "Zone", - "can_set": true, - "placeholder": "Audio_Zone" - }, - { - "name": "reverb_time", - "label": "Reverb Decay Time", - "can_set": true, - "placeholder": "(in sec)" - }, - { - "name": "wet_level", - "label": "Wet Level", - "can_set": true, - "placeholder": "(in db)" - } - ] } ] }, diff --git a/examples/audioReverbOn.js b/examples/audioReverbOn.js deleted file mode 100644 index 479f5bba74..0000000000 --- a/examples/audioReverbOn.js +++ /dev/null @@ -1,39 +0,0 @@ -// -// audioReverbOn.js -// examples -// -// 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 - -// http://wiki.audacityteam.org/wiki/GVerb#Instant_reverb_settings -var audioOptions = new AudioEffectOptions({ - // Square Meters - maxRoomSize: 50, - roomSize: 50, - - // Seconds - reverbTime: 4, - - // Between 0 - 1 - damping: 0.50, - inputBandwidth: 0.75, - - // dB - earlyLevel: -22, - tailLevel: -28, - dryLevel: 0, - wetLevel: 6 -}); - -AudioDevice.setReverbOptions(audioOptions); -AudioDevice.setReverb(true); -print("Reverb is now on with the updated options."); - -function scriptEnding() { - AudioDevice.setReverb(false); - print("Reberb is now off."); -} - -Script.scriptEnding.connect(scriptEnding); \ No newline at end of file diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index a150a308e0..db5aa64210 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -2,7 +2,7 @@ set(TARGET_NAME interface) project(${TARGET_NAME}) # set a default root dir for each of our optional externals if it was not passed -set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "Gverb") +set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp" "SDL2") foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE) if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR) @@ -14,10 +14,6 @@ endforeach() find_package(Qt5LinguistTools REQUIRED) find_package(Qt5LinguistToolsMacros) - -# As Gverb is currently the only reverb library, it's required. -find_package(Gverb REQUIRED) - if (DEFINED ENV{JOB_ID}) set(BUILD_SEQ $ENV{JOB_ID}) else () @@ -170,13 +166,6 @@ if (QXMPP_FOUND AND NOT DISABLE_QXMPP AND WIN32) add_definitions(-DQXMPP_STATIC) endif () -if (GVERB_FOUND) - file(GLOB GVERB_SRCS ${GVERB_SRC_DIRS}/*.c) - include_directories(${GVERB_INCLUDE_DIRS}) - add_library(gverb STATIC ${GVERB_SRCS}) - target_link_libraries(${TARGET_NAME} gverb) -endif (GVERB_FOUND) - # include headers for interface and InterfaceConfig. include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes") diff --git a/interface/external/gverb/readme.txt b/interface/external/gverb/readme.txt deleted file mode 100644 index aa2fe8a602..0000000000 --- a/interface/external/gverb/readme.txt +++ /dev/null @@ -1,15 +0,0 @@ - -Instructions for adding the Gverb library to Interface -(This is a required library) -Clément Brisset, Octobre 22nd, 2014 - -1. Go to https://github.com/highfidelity/gverb - Or download the sources directly via this link: - https://github.com/highfidelity/gverb/archive/master.zip - -2. Extract the archive - -3. Place the directories “include” and “src” in interface/external/gverb - (Normally next to this readme) - -4. Clear your build directory, run cmake, build and you should be all set. \ No newline at end of file diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index dd84eb3211..365064e979 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -92,8 +92,6 @@ Audio::Audio(QObject* parent) : _collisionSoundDuration(0.0f), _proceduralEffectSample(0), _muted(false), - _reverb(false), - _reverbOptions(&_scriptReverbOptions), _processSpatialAudio(false), _spatialAudioStart(0), _spatialAudioFinish(0), @@ -125,14 +123,11 @@ Audio::Audio(QObject* parent) : memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL); // Create the noise sample array _noiseSampleFrames = new float[NUMBER_OF_NOISE_SAMPLE_FRAMES]; - + connect(&_receivedAudioStream, &MixedProcessedAudioStream::addedSilence, this, &Audio::addStereoSilenceToScope, Qt::DirectConnection); connect(&_receivedAudioStream, &MixedProcessedAudioStream::addedLastFrameRepeatedWithFade, this, &Audio::addLastFrameRepeatedWithFadeToScope, Qt::DirectConnection); connect(&_receivedAudioStream, &MixedProcessedAudioStream::addedStereoSamples, this, &Audio::addStereoSamplesToScope, Qt::DirectConnection); connect(&_receivedAudioStream, &MixedProcessedAudioStream::processSamples, this, &Audio::processReceivedSamples, Qt::DirectConnection); - - // Initialize GVerb - initGverb(); } void Audio::init(QGLWidget *parent) { @@ -494,69 +489,6 @@ bool Audio::switchOutputToAudioDevice(const QString& outputDeviceName) { return switchOutputToAudioDevice(getNamedAudioDeviceForMode(QAudio::AudioOutput, outputDeviceName)); } -void Audio::initGverb() { - // Initialize a new gverb instance - _gverb = gverb_new(_outputFormat.sampleRate(), _reverbOptions->getMaxRoomSize(), _reverbOptions->getRoomSize(), - _reverbOptions->getReverbTime(), _reverbOptions->getDamping(), _reverbOptions->getSpread(), - _reverbOptions->getInputBandwidth(), _reverbOptions->getEarlyLevel(), - _reverbOptions->getTailLevel()); - - // Configure the instance (these functions are not super well named - they actually set several internal variables) - gverb_set_roomsize(_gverb, _reverbOptions->getRoomSize()); - gverb_set_revtime(_gverb, _reverbOptions->getReverbTime()); - gverb_set_damping(_gverb, _reverbOptions->getDamping()); - gverb_set_inputbandwidth(_gverb, _reverbOptions->getInputBandwidth()); - gverb_set_earlylevel(_gverb, DB_CO(_reverbOptions->getEarlyLevel())); - gverb_set_taillevel(_gverb, DB_CO(_reverbOptions->getTailLevel())); -} - -void Audio::setReverbOptions(const AudioEffectOptions* options) { - // Save the new options - _scriptReverbOptions.setMaxRoomSize(options->getMaxRoomSize()); - _scriptReverbOptions.setRoomSize(options->getRoomSize()); - _scriptReverbOptions.setReverbTime(options->getReverbTime()); - _scriptReverbOptions.setDamping(options->getDamping()); - _scriptReverbOptions.setSpread(options->getSpread()); - _scriptReverbOptions.setInputBandwidth(options->getInputBandwidth()); - _scriptReverbOptions.setEarlyLevel(options->getEarlyLevel()); - _scriptReverbOptions.setTailLevel(options->getTailLevel()); - - _scriptReverbOptions.setDryLevel(options->getDryLevel()); - _scriptReverbOptions.setWetLevel(options->getWetLevel()); - - if (_reverbOptions == &_scriptReverbOptions) { - // Apply them to the reverb instance(s) - initGverb(); - } -} - -void Audio::addReverb(int16_t* samplesData, int numSamples, QAudioFormat& audioFormat) { - float dryFraction = DB_CO(_reverbOptions->getDryLevel()); - float wetFraction = DB_CO(_reverbOptions->getWetLevel()); - - float lValue,rValue; - for (int sample = 0; sample < numSamples; sample += audioFormat.channelCount()) { - // Run GVerb - float value = (float)samplesData[sample]; - gverb_do(_gverb, value, &lValue, &rValue); - - // Mix, accounting for clipping, the left and right channels. Ignore the rest. - for (unsigned int j = sample; j < sample + audioFormat.channelCount(); j++) { - if (j == sample) { - // left channel - int lResult = glm::clamp((int)(samplesData[j] * dryFraction + lValue * wetFraction), -32768, 32767); - samplesData[j] = (int16_t)lResult; - } else if (j == (sample + 1)) { - // right channel - int rResult = glm::clamp((int)(samplesData[j] * dryFraction + rValue * wetFraction), -32768, 32767); - samplesData[j] = (int16_t)rResult; - } else { - // ignore channels above 2 - } - } - } -} - void Audio::handleAudioInput() { static char audioDataPacket[MAX_PACKET_SIZE]; @@ -788,6 +720,7 @@ void Audio::handleAudioInput() { NodeList* nodeList = NodeList::getInstance(); SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer); + if (_recorder && _recorder.data()->isRecording()) { _recorder.data()->record(reinterpret_cast(networkAudioSamples), numNetworkBytes); } @@ -907,10 +840,12 @@ void Audio::addLastFrameRepeatedWithFadeToScope(int samplesPerChannel) { } void Audio::processReceivedSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer) { + const int numNetworkOutputSamples = inputBuffer.size() / sizeof(int16_t); const int numDeviceOutputSamples = numNetworkOutputSamples * (_outputFormat.sampleRate() * _outputFormat.channelCount()) / (_desiredOutputFormat.sampleRate() * _desiredOutputFormat.channelCount()); + outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t)); const int16_t* receivedSamples; @@ -949,37 +884,10 @@ void Audio::processReceivedSamples(const QByteArray& inputBuffer, QByteArray& ou numNetworkOutputSamples, numDeviceOutputSamples, _desiredOutputFormat, _outputFormat); - - if(_reverb || _receivedAudioStream.hasReverb()) { - bool reverbChanged = false; - if (_receivedAudioStream.hasReverb()) { - - if (_zoneReverbOptions.getReverbTime() != _receivedAudioStream.getRevebTime()) { - _zoneReverbOptions.setReverbTime(_receivedAudioStream.getRevebTime()); - reverbChanged = true; - } - if (_zoneReverbOptions.getWetLevel() != _receivedAudioStream.getWetLevel()) { - _zoneReverbOptions.setWetLevel(_receivedAudioStream.getWetLevel()); - reverbChanged = true; - } - - if (_reverbOptions != &_zoneReverbOptions) { - _reverbOptions = &_zoneReverbOptions; - reverbChanged = true; - } - } else if (_reverbOptions != &_scriptReverbOptions) { - _reverbOptions = &_scriptReverbOptions; - reverbChanged = true; - } - - if (reverbChanged) { - initGverb(); - } - addReverb((int16_t*)outputBuffer.data(), numDeviceOutputSamples, _outputFormat); - } } void Audio::addReceivedAudioToStream(const QByteArray& audioByteArray) { + if (_audioOutput) { // Audio output must exist and be correctly set up if we're going to process received audio _receivedAudioStream.parseData(audioByteArray); diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 900b6ce0d6..e397f9564b 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -43,14 +43,6 @@ #include #include "MixedProcessedAudioStream.h" -#include "AudioEffectOptions.h" -#include -#include - -extern "C" { - #include - #include -} static const int NUM_AUDIO_CHANNELS = 2; @@ -167,8 +159,6 @@ public slots: float getInputVolume() const { return (_audioInput) ? _audioInput->volume() : 0.0f; } void setInputVolume(float volume) { if (_audioInput) _audioInput->setVolume(volume); } - void setReverb(bool reverb) { _reverb = reverb; } - void setReverbOptions(const AudioEffectOptions* options); const AudioStreamStats& getAudioMixerAvatarStreamAudioStats() const { return _audioMixerAvatarStreamAudioStats; } const QHash& getAudioMixerInjectedStreamAudioStatsMap() const { return _audioMixerInjectedStreamAudioStatsMap; } @@ -240,11 +230,6 @@ private: int _proceduralEffectSample; bool _muted; bool _localEcho; - bool _reverb; - AudioEffectOptions _scriptReverbOptions; - AudioEffectOptions _zoneReverbOptions; - AudioEffectOptions* _reverbOptions; - ty_gverb *_gverb; GLuint _micTextureId; GLuint _muteTextureId; GLuint _boxTextureId; @@ -264,10 +249,6 @@ private: // 2. Mix with the audio input void processProceduralAudio(int16_t* monoInput, int numSamples); - // Adds Reverb - void initGverb(); - void addReverb(int16_t* samples, int numSamples, QAudioFormat& format); - // Add sounds that we want the user to not hear themselves, by adding on top of mic input signal void addProceduralSounds(int16_t* monoInput, int numSamples); diff --git a/interface/src/scripting/AudioDeviceScriptingInterface.cpp b/interface/src/scripting/AudioDeviceScriptingInterface.cpp index bcb5fc308d..688b0942d5 100644 --- a/interface/src/scripting/AudioDeviceScriptingInterface.cpp +++ b/interface/src/scripting/AudioDeviceScriptingInterface.cpp @@ -70,11 +70,3 @@ float AudioDeviceScriptingInterface::getInputVolume() { void AudioDeviceScriptingInterface::setInputVolume(float volume) { Application::getInstance()->getAudio()->setInputVolume(volume); } - -void AudioDeviceScriptingInterface::setReverb(bool reverb) { - Application::getInstance()->getAudio()->setReverb(reverb); -} - -void AudioDeviceScriptingInterface::setReverbOptions(const AudioEffectOptions* options) { - Application::getInstance()->getAudio()->setReverbOptions(options); -} diff --git a/interface/src/scripting/AudioDeviceScriptingInterface.h b/interface/src/scripting/AudioDeviceScriptingInterface.h index 45bdbc92e2..62f1153a0b 100644 --- a/interface/src/scripting/AudioDeviceScriptingInterface.h +++ b/interface/src/scripting/AudioDeviceScriptingInterface.h @@ -39,8 +39,6 @@ public slots: float getInputVolume(); void setInputVolume(float volume); - void setReverb(bool reverb); - void setReverbOptions(const AudioEffectOptions* options); }; #endif // hifi_AudioDeviceScriptingInterface_h diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp deleted file mode 100644 index 480779afd2..0000000000 --- a/libraries/audio/src/AudioEffectOptions.cpp +++ /dev/null @@ -1,88 +0,0 @@ -// -// AudioEffectOptions.cpp -// libraries/audio/src -// -// 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 "AudioEffectOptions.h" - -static const QString MAX_ROOM_SIZE_HANDLE = "maxRoomSize"; -static const QString ROOM_SIZE_HANDLE = "roomSize"; -static const QString REVERB_TIME_HANDLE = "reverbTime"; -static const QString DAMPIMG_HANDLE = "damping"; -static const QString SPREAD_HANDLE = "spread"; -static const QString INPUT_BANDWIDTH_HANDLE = "inputBandwidth"; -static const QString EARLY_LEVEL_HANDLE = "earlyLevel"; -static const QString TAIL_LEVEL_HANDLE = "tailLevel"; -static const QString DRY_LEVEL_HANDLE = "dryLevel"; -static const QString WET_LEVEL_HANDLE = "wetLevel"; - -AudioEffectOptions::AudioEffectOptions(QScriptValue arguments) : - _maxRoomSize(50.0f), - _roomSize(50.0f), - _reverbTime(4.0f), - _damping(0.5f), - _spread(15.0f), - _inputBandwidth(0.75f), - _earlyLevel(-22.0f), - _tailLevel(-28.0f), - _dryLevel(0.0f), - _wetLevel(6.0f) { - if (arguments.property(MAX_ROOM_SIZE_HANDLE).isNumber()) { - _maxRoomSize = arguments.property(MAX_ROOM_SIZE_HANDLE).toNumber(); - } - if (arguments.property(ROOM_SIZE_HANDLE).isNumber()) { - _roomSize = arguments.property(ROOM_SIZE_HANDLE).toNumber(); - } - if (arguments.property(REVERB_TIME_HANDLE).isNumber()) { - _reverbTime = arguments.property(REVERB_TIME_HANDLE).toNumber(); - } - if (arguments.property(DAMPIMG_HANDLE).isNumber()) { - _damping = arguments.property(DAMPIMG_HANDLE).toNumber(); - } - if (arguments.property(SPREAD_HANDLE).isNumber()) { - _spread = arguments.property(SPREAD_HANDLE).toNumber(); - } - if (arguments.property(INPUT_BANDWIDTH_HANDLE).isNumber()) { - _inputBandwidth = arguments.property(INPUT_BANDWIDTH_HANDLE).toNumber(); - } - if (arguments.property(EARLY_LEVEL_HANDLE).isNumber()) { - _earlyLevel = arguments.property(EARLY_LEVEL_HANDLE).toNumber(); - } - if (arguments.property(TAIL_LEVEL_HANDLE).isNumber()) { - _tailLevel = arguments.property(TAIL_LEVEL_HANDLE).toNumber(); - } - if (arguments.property(DRY_LEVEL_HANDLE).isNumber()) { - _dryLevel = arguments.property(DRY_LEVEL_HANDLE).toNumber(); - } - if (arguments.property(WET_LEVEL_HANDLE).isNumber()) { - _wetLevel = arguments.property(WET_LEVEL_HANDLE).toNumber(); - } -} - -AudioEffectOptions::AudioEffectOptions(const AudioEffectOptions &other) { - *this = other; -} - -AudioEffectOptions& AudioEffectOptions::operator=(const AudioEffectOptions &other) { - _maxRoomSize = other._maxRoomSize; - _roomSize = other._roomSize; - _reverbTime = other._reverbTime; - _damping = other._damping; - _spread = other._spread; - _inputBandwidth = other._inputBandwidth; - _earlyLevel = other._earlyLevel; - _tailLevel = other._tailLevel; - _dryLevel = other._dryLevel; - _wetLevel = other._wetLevel; - - return *this; -} - -QScriptValue AudioEffectOptions::constructor(QScriptContext* context, QScriptEngine* engine) { - return engine->newQObject(new AudioEffectOptions(context->argument(0))); -} diff --git a/libraries/audio/src/AudioEffectOptions.h b/libraries/audio/src/AudioEffectOptions.h deleted file mode 100644 index 97aac7c82c..0000000000 --- a/libraries/audio/src/AudioEffectOptions.h +++ /dev/null @@ -1,106 +0,0 @@ -// -// AudioEffectOptions.h -// libraries/audio/src -// -// 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_AudioEffectOptions_h -#define hifi_AudioEffectOptions_h - -#include -#include -#include - -class AudioEffectOptions : public QObject { - Q_OBJECT - - // Meters Square - Q_PROPERTY(float maxRoomSize READ getMaxRoomSize WRITE setMaxRoomSize) - Q_PROPERTY(float roomSize READ getRoomSize WRITE setRoomSize) - - // Seconds - Q_PROPERTY(float reverbTime READ getReverbTime WRITE setReverbTime) - - // Ratio between 0 and 1 - Q_PROPERTY(float damping READ getDamping WRITE setDamping) - - // (?) Does not appear to be set externally very often - Q_PROPERTY(float spread READ getSpread WRITE setSpread) - - // Ratio between 0 and 1 - Q_PROPERTY(float inputBandwidth READ getInputBandwidth WRITE setInputBandwidth) - - // in dB - Q_PROPERTY(float earlyLevel READ getEarlyLevel WRITE setEarlyLevel) - Q_PROPERTY(float tailLevel READ getTailLevel WRITE setTailLevel) - Q_PROPERTY(float dryLevel READ getDryLevel WRITE setDryLevel) - Q_PROPERTY(float wetLevel READ getWetLevel WRITE setWetLevel) - -public: - AudioEffectOptions(QScriptValue arguments = QScriptValue()); - AudioEffectOptions(const AudioEffectOptions &other); - AudioEffectOptions& operator=(const AudioEffectOptions &other); - - static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); - - float getRoomSize() const { return _roomSize; } - void setRoomSize(float roomSize ) { _roomSize = roomSize; } - - float getMaxRoomSize() const { return _maxRoomSize; } - void setMaxRoomSize(float maxRoomSize ) { _maxRoomSize = maxRoomSize; } - - float getReverbTime() const { return _reverbTime; } - void setReverbTime(float reverbTime ) { _reverbTime = reverbTime; } - - float getDamping() const { return _damping; } - void setDamping(float damping ) { _damping = damping; } - - float getSpread() const { return _spread; } - void setSpread(float spread ) { _spread = spread; } - - float getInputBandwidth() const { return _inputBandwidth; } - void setInputBandwidth(float inputBandwidth ) { _inputBandwidth = inputBandwidth; } - - float getEarlyLevel() const { return _earlyLevel; } - void setEarlyLevel(float earlyLevel ) { _earlyLevel = earlyLevel; } - - float getTailLevel() const { return _tailLevel; } - void setTailLevel(float tailLevel ) { _tailLevel = tailLevel; } - - float getDryLevel() const { return _dryLevel; } - void setDryLevel(float dryLevel) { _dryLevel = dryLevel; } - - float getWetLevel() const { return _wetLevel; } - void setWetLevel(float wetLevel) { _wetLevel = wetLevel; } - -private: - // http://wiki.audacityteam.org/wiki/GVerb#Instant_Reverberb_settings - - // Meters Square - float _maxRoomSize; - float _roomSize; - - // Seconds - float _reverbTime; - - // Ratio between 0 and 1 - float _damping; - - // ? (Does not appear to be set externally very often) - float _spread; - - // Ratio between 0 and 1 - float _inputBandwidth; - - // dB - float _earlyLevel; - float _tailLevel; - float _dryLevel; - float _wetLevel; -}; - -#endif // hifi_AudioEffectOptions_h diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index 59578951f8..dda57d87da 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -44,8 +44,7 @@ InboundAudioStream::InboundAudioStream(int numFrameSamples, int numFramesCapacit _framesAvailableStat(), _currentJitterBufferFrames(0), _timeGapStatsForStatsPacket(0, STATS_FOR_STATS_PACKET_WINDOW_SECONDS), - _repetitionWithFade(settings._repetitionWithFade), - _hasReverb(false) + _repetitionWithFade(settings._repetitionWithFade) { } @@ -163,22 +162,9 @@ int InboundAudioStream::parseData(const QByteArray& packet) { } int InboundAudioStream::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) { - int read = 0; - if (type == PacketTypeMixedAudio) { - memcpy(&_hasReverb, packetAfterSeqNum.data() + read, sizeof(bool)); - read += sizeof(bool); - - if (_hasReverb) { - memcpy(&_reverbTime, packetAfterSeqNum.data() + read, sizeof(float)); - read += sizeof(float); - memcpy(&_wetLevel, packetAfterSeqNum.data() + read, sizeof(float)); - read += sizeof(float); - } - } - // mixed audio packets do not have any info between the seq num and the audio data. - numAudioSamples = (packetAfterSeqNum.size() - read) / sizeof(int16_t); - return read; + numAudioSamples = packetAfterSeqNum.size() / sizeof(int16_t); + return 0; } int InboundAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) { diff --git a/libraries/audio/src/InboundAudioStream.h b/libraries/audio/src/InboundAudioStream.h index 3e69db0afb..a395b1c6c8 100644 --- a/libraries/audio/src/InboundAudioStream.h +++ b/libraries/audio/src/InboundAudioStream.h @@ -154,10 +154,6 @@ public: int getOverflowCount() const { return _ringBuffer.getOverflowCount(); } int getPacketsReceived() const { return _incomingSequenceNumberStats.getReceived(); } - - bool hasReverb() const { return _hasReverb; } - float getRevebTime() const { return _reverbTime; } - float getWetLevel() const { return _wetLevel; } public slots: /// This function should be called every second for all the stats to function properly. If dynamic jitter buffers @@ -247,11 +243,6 @@ protected: MovingMinMaxAvg _timeGapStatsForStatsPacket; bool _repetitionWithFade; - - // Reverb properties - bool _hasReverb; - float _reverbTime; - float _wetLevel; }; float calculateRepeatedFrameFadeFactor(int indexOfRepeat); diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 166ee8c50e..7073280ee5 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -5,7 +5,7 @@ setup_hifi_library(Gui Network Script Widgets) include_glm() -link_hifi_libraries(shared octree voxels fbx entities animation audio) +link_hifi_libraries(shared octree voxels fbx entities animation) # call macro to link our dependencies and bubble them up via a property on our target link_shared_dependencies() diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 660a6ec560..93da900055 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -17,7 +17,6 @@ #include #include -#include #include #include #include @@ -278,9 +277,6 @@ void ScriptEngine::init() { QScriptValue localVoxelsValue = scriptValueFromQMetaObject(); globalObject().setProperty("LocalVoxels", localVoxelsValue); - - QScriptValue audioEffectOptionsConstructorValue = newFunction(AudioEffectOptions::constructor); - globalObject().setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue); qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue); qScriptRegisterMetaType(this, inputControllerToScriptValue, inputControllerFromScriptValue); From 9c45055aebec9f61ffd6997f7988783770d25e1c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 23:32:07 -0700 Subject: [PATCH 053/119] Fixed for no/multiple reverb zones --- assignment-client/src/audio/AudioMixer.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index fbd414f6c1..8d87638434 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -731,6 +731,7 @@ void AudioMixer::run() { dataAt += sizeof(quint16); // Pack stream properties + bool inAZone = false; for (int i = 0; i < _zoneReverbSettings.size(); ++i) { AudioMixerClientData* data = static_cast(node->getLinkedData()); glm::vec3 streamPosition = data->getAvatarAudioStream()->getPosition(); @@ -745,12 +746,16 @@ void AudioMixer::run() { dataAt += sizeof(float); memcpy(dataAt, &wetLevel, sizeof(float)); dataAt += sizeof(float); - } else { - bool hasReverb = false; - memcpy(dataAt, &hasReverb, sizeof(bool)); - dataAt += sizeof(bool); + + inAZone = true; + break; } } + if (!inAZone) { + bool hasReverb = false; + memcpy(dataAt, &hasReverb, sizeof(bool)); + dataAt += sizeof(bool); + } // pack mixed audio samples memcpy(dataAt, _mixSamples, NETWORK_BUFFER_LENGTH_BYTES_STEREO); From 9debef6128630cf9a4f4195bb3f1169e61952f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Brisset?= Date: Wed, 22 Oct 2014 23:40:50 -0700 Subject: [PATCH 054/119] Revert "Revert "Reverb"" --- assignment-client/src/audio/AudioMixer.cpp | 58 +++++++++- assignment-client/src/audio/AudioMixer.h | 8 +- cmake/modules/FindGverb.cmake | 39 +++++++ .../resources/describe-settings.json | 27 +++++ examples/audioReverbOn.js | 39 +++++++ interface/CMakeLists.txt | 13 ++- interface/external/gverb/readme.txt | 15 +++ interface/src/Audio.cpp | 102 ++++++++++++++++- interface/src/Audio.h | 19 ++++ .../AudioDeviceScriptingInterface.cpp | 8 ++ .../scripting/AudioDeviceScriptingInterface.h | 2 + libraries/audio/src/AudioEffectOptions.cpp | 88 +++++++++++++++ libraries/audio/src/AudioEffectOptions.h | 106 ++++++++++++++++++ libraries/audio/src/InboundAudioStream.cpp | 20 +++- libraries/audio/src/InboundAudioStream.h | 9 ++ libraries/script-engine/CMakeLists.txt | 2 +- libraries/script-engine/src/ScriptEngine.cpp | 4 + 17 files changed, 546 insertions(+), 13 deletions(-) create mode 100644 cmake/modules/FindGverb.cmake create mode 100644 examples/audioReverbOn.js create mode 100644 interface/external/gverb/readme.txt create mode 100644 libraries/audio/src/AudioEffectOptions.cpp create mode 100644 libraries/audio/src/AudioEffectOptions.h diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 8caf4ddf09..fbd414f6c1 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -428,8 +428,8 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l } int AudioMixer::prepareMixForListeningNode(Node* node) { - AvatarAudioStream* nodeAudioStream = ((AudioMixerClientData*) node->getLinkedData())->getAvatarAudioStream(); - AudioMixerClientData* listenerNodeData = (AudioMixerClientData*)node->getLinkedData(); + AvatarAudioStream* nodeAudioStream = static_cast(node->getLinkedData())->getAvatarAudioStream(); + AudioMixerClientData* listenerNodeData = static_cast(node->getLinkedData()); // zero out the client mix for this node memset(_preMixSamples, 0, sizeof(_preMixSamples)); @@ -730,6 +730,28 @@ void AudioMixer::run() { memcpy(dataAt, &sequence, sizeof(quint16)); dataAt += sizeof(quint16); + // Pack stream properties + for (int i = 0; i < _zoneReverbSettings.size(); ++i) { + AudioMixerClientData* data = static_cast(node->getLinkedData()); + glm::vec3 streamPosition = data->getAvatarAudioStream()->getPosition(); + if (_audioZones[_zoneReverbSettings[i].zone].contains(streamPosition)) { + bool hasReverb = true; + float reverbTime = _zoneReverbSettings[i].reverbTime; + float wetLevel = _zoneReverbSettings[i].wetLevel; + + memcpy(dataAt, &hasReverb, sizeof(bool)); + dataAt += sizeof(bool); + memcpy(dataAt, &reverbTime, sizeof(float)); + dataAt += sizeof(float); + memcpy(dataAt, &wetLevel, sizeof(float)); + dataAt += sizeof(float); + } else { + bool hasReverb = false; + memcpy(dataAt, &hasReverb, sizeof(bool)); + dataAt += sizeof(bool); + } + } + // pack mixed audio samples memcpy(dataAt, _mixSamples, NETWORK_BUFFER_LENGTH_BYTES_STEREO); dataAt += NETWORK_BUFFER_LENGTH_BYTES_STEREO; @@ -1033,6 +1055,38 @@ void AudioMixer::parseSettingsObject(const QJsonObject &settingsObject) { } } } + + const QString REVERB = "reverb"; + if (audioEnvGroupObject[REVERB].isArray()) { + const QJsonArray& reverb = audioEnvGroupObject[REVERB].toArray(); + + const QString ZONE = "zone"; + const QString REVERB_TIME = "reverb_time"; + const QString WET_LEVEL = "wet_level"; + for (int i = 0; i < reverb.count(); ++i) { + QJsonObject reverbObject = reverb[i].toObject(); + + if (reverbObject.contains(ZONE) && + reverbObject.contains(REVERB_TIME) && + reverbObject.contains(WET_LEVEL)) { + + bool okReverbTime, okWetLevel; + QString zone = reverbObject.value(ZONE).toString(); + float reverbTime = reverbObject.value(REVERB_TIME).toString().toFloat(&okReverbTime); + float wetLevel = reverbObject.value(WET_LEVEL).toString().toFloat(&okWetLevel); + + if (okReverbTime && okWetLevel && _audioZones.contains(zone)) { + ReverbSettings settings; + settings.zone = zone; + settings.reverbTime = reverbTime; + settings.wetLevel = wetLevel; + + _zoneReverbSettings.push_back(settings); + qDebug() << "Added Reverb:" << zone << reverbTime << wetLevel; + } + } + } + } } } diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 3cfa5443a8..ff976dec61 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -82,7 +82,13 @@ private: float coefficient; }; QVector _zonesSettings; - + struct ReverbSettings { + QString zone; + float reverbTime; + float wetLevel; + }; + QVector _zoneReverbSettings; + static InboundAudioStream::Settings _streamSettings; static bool _printStreamStats; diff --git a/cmake/modules/FindGverb.cmake b/cmake/modules/FindGverb.cmake new file mode 100644 index 0000000000..549c23c8a9 --- /dev/null +++ b/cmake/modules/FindGverb.cmake @@ -0,0 +1,39 @@ +# FindGVerb.cmake +# +# Try to find the Gverb library. +# +# You must provide a GVERB_ROOT_DIR which contains src and include directories +# +# Once done this will define +# +# GVERB_FOUND - system found Gverb +# GVERB_INCLUDE_DIRS - the Gverb include directory +# +# 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 +# + +if (GVERB_INCLUDE_DIRS) + # in cache already + set(GVERB_FOUND TRUE) +else (GVERB_INCLUDE_DIRS) + + include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") + hifi_library_search_hints("gverb") + + find_path(GVERB_INCLUDE_DIRS gverb.h PATH_SUFFIXES include HINTS ${GVERB_SEARCH_DIRS}) + find_path(GVERB_SRC_DIRS gverb.c PATH_SUFFIXES src HINTS ${GVERB_SEARCH_DIRS}) + + if (GVERB_INCLUDE_DIRS) + set(GVERB_FOUND TRUE) + endif (GVERB_INCLUDE_DIRS) + + if (GVERB_FOUND) + message(STATUS "Found Gverb: ${GVERB_INCLUDE_DIRS}") + else (GVERB_FOUND) + message(FATAL_ERROR "Could NOT find Gverb. Read ./interface/externals/gverb/readme.txt") + endif (GVERB_FOUND) + +endif(GVERB_INCLUDE_DIRS) \ No newline at end of file diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 2c33897d07..026fe252b2 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -154,6 +154,33 @@ "placeholder": "0.18" } ] + }, + { + "name": "reverb", + "type": "table", + "label": "Reverb Settings", + "help": "In this table you can set custom reverb values for each audio zones", + "numbered": true, + "columns": [ + { + "name": "zone", + "label": "Zone", + "can_set": true, + "placeholder": "Audio_Zone" + }, + { + "name": "reverb_time", + "label": "Reverb Decay Time", + "can_set": true, + "placeholder": "(in sec)" + }, + { + "name": "wet_level", + "label": "Wet Level", + "can_set": true, + "placeholder": "(in db)" + } + ] } ] }, diff --git a/examples/audioReverbOn.js b/examples/audioReverbOn.js new file mode 100644 index 0000000000..479f5bba74 --- /dev/null +++ b/examples/audioReverbOn.js @@ -0,0 +1,39 @@ +// +// audioReverbOn.js +// examples +// +// 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 + +// http://wiki.audacityteam.org/wiki/GVerb#Instant_reverb_settings +var audioOptions = new AudioEffectOptions({ + // Square Meters + maxRoomSize: 50, + roomSize: 50, + + // Seconds + reverbTime: 4, + + // Between 0 - 1 + damping: 0.50, + inputBandwidth: 0.75, + + // dB + earlyLevel: -22, + tailLevel: -28, + dryLevel: 0, + wetLevel: 6 +}); + +AudioDevice.setReverbOptions(audioOptions); +AudioDevice.setReverb(true); +print("Reverb is now on with the updated options."); + +function scriptEnding() { + AudioDevice.setReverb(false); + print("Reberb is now off."); +} + +Script.scriptEnding.connect(scriptEnding); \ No newline at end of file diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index db5aa64210..a150a308e0 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -2,7 +2,7 @@ set(TARGET_NAME interface) project(${TARGET_NAME}) # set a default root dir for each of our optional externals if it was not passed -set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp" "SDL2") +set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "Gverb") foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE) if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR) @@ -14,6 +14,10 @@ endforeach() find_package(Qt5LinguistTools REQUIRED) find_package(Qt5LinguistToolsMacros) + +# As Gverb is currently the only reverb library, it's required. +find_package(Gverb REQUIRED) + if (DEFINED ENV{JOB_ID}) set(BUILD_SEQ $ENV{JOB_ID}) else () @@ -166,6 +170,13 @@ if (QXMPP_FOUND AND NOT DISABLE_QXMPP AND WIN32) add_definitions(-DQXMPP_STATIC) endif () +if (GVERB_FOUND) + file(GLOB GVERB_SRCS ${GVERB_SRC_DIRS}/*.c) + include_directories(${GVERB_INCLUDE_DIRS}) + add_library(gverb STATIC ${GVERB_SRCS}) + target_link_libraries(${TARGET_NAME} gverb) +endif (GVERB_FOUND) + # include headers for interface and InterfaceConfig. include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes") diff --git a/interface/external/gverb/readme.txt b/interface/external/gverb/readme.txt new file mode 100644 index 0000000000..aa2fe8a602 --- /dev/null +++ b/interface/external/gverb/readme.txt @@ -0,0 +1,15 @@ + +Instructions for adding the Gverb library to Interface +(This is a required library) +Clément Brisset, Octobre 22nd, 2014 + +1. Go to https://github.com/highfidelity/gverb + Or download the sources directly via this link: + https://github.com/highfidelity/gverb/archive/master.zip + +2. Extract the archive + +3. Place the directories “include” and “src” in interface/external/gverb + (Normally next to this readme) + +4. Clear your build directory, run cmake, build and you should be all set. \ No newline at end of file diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 365064e979..dd84eb3211 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -92,6 +92,8 @@ Audio::Audio(QObject* parent) : _collisionSoundDuration(0.0f), _proceduralEffectSample(0), _muted(false), + _reverb(false), + _reverbOptions(&_scriptReverbOptions), _processSpatialAudio(false), _spatialAudioStart(0), _spatialAudioFinish(0), @@ -123,11 +125,14 @@ Audio::Audio(QObject* parent) : memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL); // Create the noise sample array _noiseSampleFrames = new float[NUMBER_OF_NOISE_SAMPLE_FRAMES]; - + connect(&_receivedAudioStream, &MixedProcessedAudioStream::addedSilence, this, &Audio::addStereoSilenceToScope, Qt::DirectConnection); connect(&_receivedAudioStream, &MixedProcessedAudioStream::addedLastFrameRepeatedWithFade, this, &Audio::addLastFrameRepeatedWithFadeToScope, Qt::DirectConnection); connect(&_receivedAudioStream, &MixedProcessedAudioStream::addedStereoSamples, this, &Audio::addStereoSamplesToScope, Qt::DirectConnection); connect(&_receivedAudioStream, &MixedProcessedAudioStream::processSamples, this, &Audio::processReceivedSamples, Qt::DirectConnection); + + // Initialize GVerb + initGverb(); } void Audio::init(QGLWidget *parent) { @@ -489,6 +494,69 @@ bool Audio::switchOutputToAudioDevice(const QString& outputDeviceName) { return switchOutputToAudioDevice(getNamedAudioDeviceForMode(QAudio::AudioOutput, outputDeviceName)); } +void Audio::initGverb() { + // Initialize a new gverb instance + _gverb = gverb_new(_outputFormat.sampleRate(), _reverbOptions->getMaxRoomSize(), _reverbOptions->getRoomSize(), + _reverbOptions->getReverbTime(), _reverbOptions->getDamping(), _reverbOptions->getSpread(), + _reverbOptions->getInputBandwidth(), _reverbOptions->getEarlyLevel(), + _reverbOptions->getTailLevel()); + + // Configure the instance (these functions are not super well named - they actually set several internal variables) + gverb_set_roomsize(_gverb, _reverbOptions->getRoomSize()); + gverb_set_revtime(_gverb, _reverbOptions->getReverbTime()); + gverb_set_damping(_gverb, _reverbOptions->getDamping()); + gverb_set_inputbandwidth(_gverb, _reverbOptions->getInputBandwidth()); + gverb_set_earlylevel(_gverb, DB_CO(_reverbOptions->getEarlyLevel())); + gverb_set_taillevel(_gverb, DB_CO(_reverbOptions->getTailLevel())); +} + +void Audio::setReverbOptions(const AudioEffectOptions* options) { + // Save the new options + _scriptReverbOptions.setMaxRoomSize(options->getMaxRoomSize()); + _scriptReverbOptions.setRoomSize(options->getRoomSize()); + _scriptReverbOptions.setReverbTime(options->getReverbTime()); + _scriptReverbOptions.setDamping(options->getDamping()); + _scriptReverbOptions.setSpread(options->getSpread()); + _scriptReverbOptions.setInputBandwidth(options->getInputBandwidth()); + _scriptReverbOptions.setEarlyLevel(options->getEarlyLevel()); + _scriptReverbOptions.setTailLevel(options->getTailLevel()); + + _scriptReverbOptions.setDryLevel(options->getDryLevel()); + _scriptReverbOptions.setWetLevel(options->getWetLevel()); + + if (_reverbOptions == &_scriptReverbOptions) { + // Apply them to the reverb instance(s) + initGverb(); + } +} + +void Audio::addReverb(int16_t* samplesData, int numSamples, QAudioFormat& audioFormat) { + float dryFraction = DB_CO(_reverbOptions->getDryLevel()); + float wetFraction = DB_CO(_reverbOptions->getWetLevel()); + + float lValue,rValue; + for (int sample = 0; sample < numSamples; sample += audioFormat.channelCount()) { + // Run GVerb + float value = (float)samplesData[sample]; + gverb_do(_gverb, value, &lValue, &rValue); + + // Mix, accounting for clipping, the left and right channels. Ignore the rest. + for (unsigned int j = sample; j < sample + audioFormat.channelCount(); j++) { + if (j == sample) { + // left channel + int lResult = glm::clamp((int)(samplesData[j] * dryFraction + lValue * wetFraction), -32768, 32767); + samplesData[j] = (int16_t)lResult; + } else if (j == (sample + 1)) { + // right channel + int rResult = glm::clamp((int)(samplesData[j] * dryFraction + rValue * wetFraction), -32768, 32767); + samplesData[j] = (int16_t)rResult; + } else { + // ignore channels above 2 + } + } + } +} + void Audio::handleAudioInput() { static char audioDataPacket[MAX_PACKET_SIZE]; @@ -720,7 +788,6 @@ void Audio::handleAudioInput() { NodeList* nodeList = NodeList::getInstance(); SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer); - if (_recorder && _recorder.data()->isRecording()) { _recorder.data()->record(reinterpret_cast(networkAudioSamples), numNetworkBytes); } @@ -840,12 +907,10 @@ void Audio::addLastFrameRepeatedWithFadeToScope(int samplesPerChannel) { } void Audio::processReceivedSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer) { - const int numNetworkOutputSamples = inputBuffer.size() / sizeof(int16_t); const int numDeviceOutputSamples = numNetworkOutputSamples * (_outputFormat.sampleRate() * _outputFormat.channelCount()) / (_desiredOutputFormat.sampleRate() * _desiredOutputFormat.channelCount()); - outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t)); const int16_t* receivedSamples; @@ -884,10 +949,37 @@ void Audio::processReceivedSamples(const QByteArray& inputBuffer, QByteArray& ou numNetworkOutputSamples, numDeviceOutputSamples, _desiredOutputFormat, _outputFormat); + + if(_reverb || _receivedAudioStream.hasReverb()) { + bool reverbChanged = false; + if (_receivedAudioStream.hasReverb()) { + + if (_zoneReverbOptions.getReverbTime() != _receivedAudioStream.getRevebTime()) { + _zoneReverbOptions.setReverbTime(_receivedAudioStream.getRevebTime()); + reverbChanged = true; + } + if (_zoneReverbOptions.getWetLevel() != _receivedAudioStream.getWetLevel()) { + _zoneReverbOptions.setWetLevel(_receivedAudioStream.getWetLevel()); + reverbChanged = true; + } + + if (_reverbOptions != &_zoneReverbOptions) { + _reverbOptions = &_zoneReverbOptions; + reverbChanged = true; + } + } else if (_reverbOptions != &_scriptReverbOptions) { + _reverbOptions = &_scriptReverbOptions; + reverbChanged = true; + } + + if (reverbChanged) { + initGverb(); + } + addReverb((int16_t*)outputBuffer.data(), numDeviceOutputSamples, _outputFormat); + } } void Audio::addReceivedAudioToStream(const QByteArray& audioByteArray) { - if (_audioOutput) { // Audio output must exist and be correctly set up if we're going to process received audio _receivedAudioStream.parseData(audioByteArray); diff --git a/interface/src/Audio.h b/interface/src/Audio.h index e397f9564b..900b6ce0d6 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -43,6 +43,14 @@ #include #include "MixedProcessedAudioStream.h" +#include "AudioEffectOptions.h" +#include +#include + +extern "C" { + #include + #include +} static const int NUM_AUDIO_CHANNELS = 2; @@ -159,6 +167,8 @@ public slots: float getInputVolume() const { return (_audioInput) ? _audioInput->volume() : 0.0f; } void setInputVolume(float volume) { if (_audioInput) _audioInput->setVolume(volume); } + void setReverb(bool reverb) { _reverb = reverb; } + void setReverbOptions(const AudioEffectOptions* options); const AudioStreamStats& getAudioMixerAvatarStreamAudioStats() const { return _audioMixerAvatarStreamAudioStats; } const QHash& getAudioMixerInjectedStreamAudioStatsMap() const { return _audioMixerInjectedStreamAudioStatsMap; } @@ -230,6 +240,11 @@ private: int _proceduralEffectSample; bool _muted; bool _localEcho; + bool _reverb; + AudioEffectOptions _scriptReverbOptions; + AudioEffectOptions _zoneReverbOptions; + AudioEffectOptions* _reverbOptions; + ty_gverb *_gverb; GLuint _micTextureId; GLuint _muteTextureId; GLuint _boxTextureId; @@ -249,6 +264,10 @@ private: // 2. Mix with the audio input void processProceduralAudio(int16_t* monoInput, int numSamples); + // Adds Reverb + void initGverb(); + void addReverb(int16_t* samples, int numSamples, QAudioFormat& format); + // Add sounds that we want the user to not hear themselves, by adding on top of mic input signal void addProceduralSounds(int16_t* monoInput, int numSamples); diff --git a/interface/src/scripting/AudioDeviceScriptingInterface.cpp b/interface/src/scripting/AudioDeviceScriptingInterface.cpp index 688b0942d5..bcb5fc308d 100644 --- a/interface/src/scripting/AudioDeviceScriptingInterface.cpp +++ b/interface/src/scripting/AudioDeviceScriptingInterface.cpp @@ -70,3 +70,11 @@ float AudioDeviceScriptingInterface::getInputVolume() { void AudioDeviceScriptingInterface::setInputVolume(float volume) { Application::getInstance()->getAudio()->setInputVolume(volume); } + +void AudioDeviceScriptingInterface::setReverb(bool reverb) { + Application::getInstance()->getAudio()->setReverb(reverb); +} + +void AudioDeviceScriptingInterface::setReverbOptions(const AudioEffectOptions* options) { + Application::getInstance()->getAudio()->setReverbOptions(options); +} diff --git a/interface/src/scripting/AudioDeviceScriptingInterface.h b/interface/src/scripting/AudioDeviceScriptingInterface.h index 62f1153a0b..45bdbc92e2 100644 --- a/interface/src/scripting/AudioDeviceScriptingInterface.h +++ b/interface/src/scripting/AudioDeviceScriptingInterface.h @@ -39,6 +39,8 @@ public slots: float getInputVolume(); void setInputVolume(float volume); + void setReverb(bool reverb); + void setReverbOptions(const AudioEffectOptions* options); }; #endif // hifi_AudioDeviceScriptingInterface_h diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp new file mode 100644 index 0000000000..480779afd2 --- /dev/null +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -0,0 +1,88 @@ +// +// AudioEffectOptions.cpp +// libraries/audio/src +// +// 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 "AudioEffectOptions.h" + +static const QString MAX_ROOM_SIZE_HANDLE = "maxRoomSize"; +static const QString ROOM_SIZE_HANDLE = "roomSize"; +static const QString REVERB_TIME_HANDLE = "reverbTime"; +static const QString DAMPIMG_HANDLE = "damping"; +static const QString SPREAD_HANDLE = "spread"; +static const QString INPUT_BANDWIDTH_HANDLE = "inputBandwidth"; +static const QString EARLY_LEVEL_HANDLE = "earlyLevel"; +static const QString TAIL_LEVEL_HANDLE = "tailLevel"; +static const QString DRY_LEVEL_HANDLE = "dryLevel"; +static const QString WET_LEVEL_HANDLE = "wetLevel"; + +AudioEffectOptions::AudioEffectOptions(QScriptValue arguments) : + _maxRoomSize(50.0f), + _roomSize(50.0f), + _reverbTime(4.0f), + _damping(0.5f), + _spread(15.0f), + _inputBandwidth(0.75f), + _earlyLevel(-22.0f), + _tailLevel(-28.0f), + _dryLevel(0.0f), + _wetLevel(6.0f) { + if (arguments.property(MAX_ROOM_SIZE_HANDLE).isNumber()) { + _maxRoomSize = arguments.property(MAX_ROOM_SIZE_HANDLE).toNumber(); + } + if (arguments.property(ROOM_SIZE_HANDLE).isNumber()) { + _roomSize = arguments.property(ROOM_SIZE_HANDLE).toNumber(); + } + if (arguments.property(REVERB_TIME_HANDLE).isNumber()) { + _reverbTime = arguments.property(REVERB_TIME_HANDLE).toNumber(); + } + if (arguments.property(DAMPIMG_HANDLE).isNumber()) { + _damping = arguments.property(DAMPIMG_HANDLE).toNumber(); + } + if (arguments.property(SPREAD_HANDLE).isNumber()) { + _spread = arguments.property(SPREAD_HANDLE).toNumber(); + } + if (arguments.property(INPUT_BANDWIDTH_HANDLE).isNumber()) { + _inputBandwidth = arguments.property(INPUT_BANDWIDTH_HANDLE).toNumber(); + } + if (arguments.property(EARLY_LEVEL_HANDLE).isNumber()) { + _earlyLevel = arguments.property(EARLY_LEVEL_HANDLE).toNumber(); + } + if (arguments.property(TAIL_LEVEL_HANDLE).isNumber()) { + _tailLevel = arguments.property(TAIL_LEVEL_HANDLE).toNumber(); + } + if (arguments.property(DRY_LEVEL_HANDLE).isNumber()) { + _dryLevel = arguments.property(DRY_LEVEL_HANDLE).toNumber(); + } + if (arguments.property(WET_LEVEL_HANDLE).isNumber()) { + _wetLevel = arguments.property(WET_LEVEL_HANDLE).toNumber(); + } +} + +AudioEffectOptions::AudioEffectOptions(const AudioEffectOptions &other) { + *this = other; +} + +AudioEffectOptions& AudioEffectOptions::operator=(const AudioEffectOptions &other) { + _maxRoomSize = other._maxRoomSize; + _roomSize = other._roomSize; + _reverbTime = other._reverbTime; + _damping = other._damping; + _spread = other._spread; + _inputBandwidth = other._inputBandwidth; + _earlyLevel = other._earlyLevel; + _tailLevel = other._tailLevel; + _dryLevel = other._dryLevel; + _wetLevel = other._wetLevel; + + return *this; +} + +QScriptValue AudioEffectOptions::constructor(QScriptContext* context, QScriptEngine* engine) { + return engine->newQObject(new AudioEffectOptions(context->argument(0))); +} diff --git a/libraries/audio/src/AudioEffectOptions.h b/libraries/audio/src/AudioEffectOptions.h new file mode 100644 index 0000000000..97aac7c82c --- /dev/null +++ b/libraries/audio/src/AudioEffectOptions.h @@ -0,0 +1,106 @@ +// +// AudioEffectOptions.h +// libraries/audio/src +// +// 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_AudioEffectOptions_h +#define hifi_AudioEffectOptions_h + +#include +#include +#include + +class AudioEffectOptions : public QObject { + Q_OBJECT + + // Meters Square + Q_PROPERTY(float maxRoomSize READ getMaxRoomSize WRITE setMaxRoomSize) + Q_PROPERTY(float roomSize READ getRoomSize WRITE setRoomSize) + + // Seconds + Q_PROPERTY(float reverbTime READ getReverbTime WRITE setReverbTime) + + // Ratio between 0 and 1 + Q_PROPERTY(float damping READ getDamping WRITE setDamping) + + // (?) Does not appear to be set externally very often + Q_PROPERTY(float spread READ getSpread WRITE setSpread) + + // Ratio between 0 and 1 + Q_PROPERTY(float inputBandwidth READ getInputBandwidth WRITE setInputBandwidth) + + // in dB + Q_PROPERTY(float earlyLevel READ getEarlyLevel WRITE setEarlyLevel) + Q_PROPERTY(float tailLevel READ getTailLevel WRITE setTailLevel) + Q_PROPERTY(float dryLevel READ getDryLevel WRITE setDryLevel) + Q_PROPERTY(float wetLevel READ getWetLevel WRITE setWetLevel) + +public: + AudioEffectOptions(QScriptValue arguments = QScriptValue()); + AudioEffectOptions(const AudioEffectOptions &other); + AudioEffectOptions& operator=(const AudioEffectOptions &other); + + static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); + + float getRoomSize() const { return _roomSize; } + void setRoomSize(float roomSize ) { _roomSize = roomSize; } + + float getMaxRoomSize() const { return _maxRoomSize; } + void setMaxRoomSize(float maxRoomSize ) { _maxRoomSize = maxRoomSize; } + + float getReverbTime() const { return _reverbTime; } + void setReverbTime(float reverbTime ) { _reverbTime = reverbTime; } + + float getDamping() const { return _damping; } + void setDamping(float damping ) { _damping = damping; } + + float getSpread() const { return _spread; } + void setSpread(float spread ) { _spread = spread; } + + float getInputBandwidth() const { return _inputBandwidth; } + void setInputBandwidth(float inputBandwidth ) { _inputBandwidth = inputBandwidth; } + + float getEarlyLevel() const { return _earlyLevel; } + void setEarlyLevel(float earlyLevel ) { _earlyLevel = earlyLevel; } + + float getTailLevel() const { return _tailLevel; } + void setTailLevel(float tailLevel ) { _tailLevel = tailLevel; } + + float getDryLevel() const { return _dryLevel; } + void setDryLevel(float dryLevel) { _dryLevel = dryLevel; } + + float getWetLevel() const { return _wetLevel; } + void setWetLevel(float wetLevel) { _wetLevel = wetLevel; } + +private: + // http://wiki.audacityteam.org/wiki/GVerb#Instant_Reverberb_settings + + // Meters Square + float _maxRoomSize; + float _roomSize; + + // Seconds + float _reverbTime; + + // Ratio between 0 and 1 + float _damping; + + // ? (Does not appear to be set externally very often) + float _spread; + + // Ratio between 0 and 1 + float _inputBandwidth; + + // dB + float _earlyLevel; + float _tailLevel; + float _dryLevel; + float _wetLevel; +}; + +#endif // hifi_AudioEffectOptions_h diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index dda57d87da..59578951f8 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -44,7 +44,8 @@ InboundAudioStream::InboundAudioStream(int numFrameSamples, int numFramesCapacit _framesAvailableStat(), _currentJitterBufferFrames(0), _timeGapStatsForStatsPacket(0, STATS_FOR_STATS_PACKET_WINDOW_SECONDS), - _repetitionWithFade(settings._repetitionWithFade) + _repetitionWithFade(settings._repetitionWithFade), + _hasReverb(false) { } @@ -162,9 +163,22 @@ int InboundAudioStream::parseData(const QByteArray& packet) { } int InboundAudioStream::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) { + int read = 0; + if (type == PacketTypeMixedAudio) { + memcpy(&_hasReverb, packetAfterSeqNum.data() + read, sizeof(bool)); + read += sizeof(bool); + + if (_hasReverb) { + memcpy(&_reverbTime, packetAfterSeqNum.data() + read, sizeof(float)); + read += sizeof(float); + memcpy(&_wetLevel, packetAfterSeqNum.data() + read, sizeof(float)); + read += sizeof(float); + } + } + // mixed audio packets do not have any info between the seq num and the audio data. - numAudioSamples = packetAfterSeqNum.size() / sizeof(int16_t); - return 0; + numAudioSamples = (packetAfterSeqNum.size() - read) / sizeof(int16_t); + return read; } int InboundAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) { diff --git a/libraries/audio/src/InboundAudioStream.h b/libraries/audio/src/InboundAudioStream.h index a395b1c6c8..3e69db0afb 100644 --- a/libraries/audio/src/InboundAudioStream.h +++ b/libraries/audio/src/InboundAudioStream.h @@ -154,6 +154,10 @@ public: int getOverflowCount() const { return _ringBuffer.getOverflowCount(); } int getPacketsReceived() const { return _incomingSequenceNumberStats.getReceived(); } + + bool hasReverb() const { return _hasReverb; } + float getRevebTime() const { return _reverbTime; } + float getWetLevel() const { return _wetLevel; } public slots: /// This function should be called every second for all the stats to function properly. If dynamic jitter buffers @@ -243,6 +247,11 @@ protected: MovingMinMaxAvg _timeGapStatsForStatsPacket; bool _repetitionWithFade; + + // Reverb properties + bool _hasReverb; + float _reverbTime; + float _wetLevel; }; float calculateRepeatedFrameFadeFactor(int indexOfRepeat); diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 7073280ee5..166ee8c50e 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -5,7 +5,7 @@ setup_hifi_library(Gui Network Script Widgets) include_glm() -link_hifi_libraries(shared octree voxels fbx entities animation) +link_hifi_libraries(shared octree voxels fbx entities animation audio) # call macro to link our dependencies and bubble them up via a property on our target link_shared_dependencies() diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 93da900055..660a6ec560 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -277,6 +278,9 @@ void ScriptEngine::init() { QScriptValue localVoxelsValue = scriptValueFromQMetaObject(); globalObject().setProperty("LocalVoxels", localVoxelsValue); + + QScriptValue audioEffectOptionsConstructorValue = newFunction(AudioEffectOptions::constructor); + globalObject().setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue); qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue); qScriptRegisterMetaType(this, inputControllerToScriptValue, inputControllerFromScriptValue); From 06d528fce5687df0b6296aacacdb4d660ec7dec5 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Oct 2014 09:28:48 -0700 Subject: [PATCH 055/119] bump audio version number --- libraries/networking/src/PacketHeaders.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 7f81a4c59e..8ce379b203 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -53,7 +53,7 @@ PacketVersion versionForPacketType(PacketType type) { case PacketTypeSilentAudioFrame: return 4; case PacketTypeMixedAudio: - return 1; + return 2; case PacketTypeAvatarData: return 3; case PacketTypeAvatarIdentity: From 1d68413b663475e633ab90a2b6d58877b3bcd5be Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 23 Oct 2014 11:43:13 -0700 Subject: [PATCH 056/119] Audio-only mouth uses multiple blend shapes --- interface/src/avatar/Head.cpp | 19 +++++++++++++++++++ interface/src/avatar/Head.h | 3 +++ interface/src/devices/Faceshift.cpp | 12 ++++++++++-- interface/src/devices/Faceshift.h | 10 ++++++++-- 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index bc557bdb57..31f08d9eae 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -166,6 +166,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { } // use data to update fake Faceshift blendshape coefficients + const float JAW_OPEN_SCALE = 0.015f; const float JAW_OPEN_RATE = 0.9f; const float JAW_CLOSE_RATE = 0.90f; @@ -177,10 +178,28 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { } _audioJawOpen = glm::clamp(_audioJawOpen, 0.0f, 1.0f); + // _mouth2 = "mmmm" shape + // _mouth3 = "funnel" shape + // _mouth4 = "smile" shape + const float FUNNEL_PERIOD = 0.985f; + const float FUNNEL_RANDOM_PERIOD = 0.01f; + const float MMMM_POWER = 0.25f; + const float MMMM_PERIOD = 0.91f; + const float MMMM_RANDOM_PERIOD = 0.15f; + const float SMILE_PERIOD = 0.925f; + const float SMILE_RANDOM_PERIOD = 0.05f; + + _mouth3 = glm::mix(_audioJawOpen, _mouth3, FUNNEL_PERIOD + randFloat() * FUNNEL_RANDOM_PERIOD); + _mouth2 = glm::mix(_audioJawOpen * MMMM_POWER, _mouth2, MMMM_PERIOD + randFloat() * MMMM_RANDOM_PERIOD); + _mouth4 = glm::mix(_audioJawOpen, _mouth4, SMILE_PERIOD + randFloat() * SMILE_RANDOM_PERIOD); + Application::getInstance()->getFaceshift()->updateFakeCoefficients(_leftEyeBlink, _rightEyeBlink, _browAudioLift, _audioJawOpen, + _mouth2, + _mouth3, + _mouth4, _blendshapeCoefficients); } diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index bc4142eab0..57d74adaf0 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -129,6 +129,9 @@ private: float _longTermAverageLoudness; float _audioAttack; float _audioJawOpen; + float _mouth2; + float _mouth3; + float _mouth4; glm::vec3 _angularVelocity; bool _renderLookatVectors; glm::vec3 _saccade; diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 74e36a98d1..0f1f792157 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -125,8 +125,13 @@ void Faceshift::reset() { } void Faceshift::updateFakeCoefficients(float leftBlink, float rightBlink, float browUp, - float jawOpen, QVector& coefficients) const { - coefficients.resize(max((int)coefficients.size(), _jawOpenIndex + 1)); + float jawOpen, float mouth2, float mouth3, float mouth4, QVector& coefficients) const { + const int MMMM_BLENDSHAPE = 34; + const int FUNNEL_BLENDSHAPE = 40; + const int SMILE_LEFT_BLENDSHAPE = 28; + const int SMILE_RIGHT_BLENDSHAPE = 29; + coefficients.resize(max((int)coefficients.size(), FUNNEL_BLENDSHAPE + 1)); + coefficients.resize(max((int)coefficients.size(), 48)); qFill(coefficients.begin(), coefficients.end(), 0.0f); coefficients[_leftBlinkIndex] = leftBlink; coefficients[_rightBlinkIndex] = rightBlink; @@ -134,6 +139,9 @@ void Faceshift::updateFakeCoefficients(float leftBlink, float rightBlink, float coefficients[_browUpLeftIndex] = browUp; coefficients[_browUpRightIndex] = browUp; coefficients[_jawOpenIndex] = jawOpen; + coefficients[SMILE_LEFT_BLENDSHAPE] = coefficients[SMILE_RIGHT_BLENDSHAPE] = mouth4; + coefficients[MMMM_BLENDSHAPE] = mouth2; + coefficients[FUNNEL_BLENDSHAPE] = mouth3; } void Faceshift::setTCPEnabled(bool enabled) { diff --git a/interface/src/devices/Faceshift.h b/interface/src/devices/Faceshift.h index e7d87827eb..3b4092c099 100644 --- a/interface/src/devices/Faceshift.h +++ b/interface/src/devices/Faceshift.h @@ -61,8 +61,14 @@ public: void update(); void reset(); - void updateFakeCoefficients(float leftBlink, float rightBlink, float browUp, - float jawOpen, QVector& coefficients) const; + void updateFakeCoefficients(float leftBlink, + float rightBlink, + float browUp, + float jawOpen, + float mouth2, + float mouth3, + float mouth4, + QVector& coefficients) const; signals: From 9364c3b3423696b5af1cfffc007a6c73bd770308 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Oct 2014 11:54:30 -0700 Subject: [PATCH 057/119] fix for delete of last row in array table --- domain-server/resources/web/js/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/web/js/settings.js b/domain-server/resources/web/js/settings.js index 21a4d99977..a27965abce 100644 --- a/domain-server/resources/web/js/settings.js +++ b/domain-server/resources/web/js/settings.js @@ -529,7 +529,7 @@ function deleteTableRow(delete_glyphicon) { row.html(""); } else { - if (table.find('.' + Settings.DATA_ROW_CLASS).length) { + if (table.find('.' + Settings.DATA_ROW_CLASS).length > 1) { updateDataChangedForSiblingRows(row) // this isn't the last row - we can just remove it From 9394f72b18353e6c6ea887176af8dc286c22d483 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 23 Oct 2014 11:55:06 -0700 Subject: [PATCH 058/119] clarify fake blendshape array size --- interface/src/devices/Faceshift.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 0f1f792157..fb74f416a9 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -130,8 +130,9 @@ void Faceshift::updateFakeCoefficients(float leftBlink, float rightBlink, float const int FUNNEL_BLENDSHAPE = 40; const int SMILE_LEFT_BLENDSHAPE = 28; const int SMILE_RIGHT_BLENDSHAPE = 29; - coefficients.resize(max((int)coefficients.size(), FUNNEL_BLENDSHAPE + 1)); - coefficients.resize(max((int)coefficients.size(), 48)); + const int MAX_FAKE_BLENDSHAPE = 40; // Largest modified blendshape from above and below + + coefficients.resize(max((int)coefficients.size(), MAX_FAKE_BLENDSHAPE + 1)); qFill(coefficients.begin(), coefficients.end(), 0.0f); coefficients[_leftBlinkIndex] = leftBlink; coefficients[_rightBlinkIndex] = rightBlink; From a4965e7f60d5ab1b279126838c325390343f4d39 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Thu, 23 Oct 2014 13:59:08 -0600 Subject: [PATCH 059/119] No need for https when downloading assets --- examples/libraries/globals.js | 2 +- interface/src/ScriptsModel.cpp | 2 +- interface/src/ui/ModelsBrowser.cpp | 2 +- tests/octree/src/ModelTests.cpp | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/libraries/globals.js b/examples/libraries/globals.js index 1bd851af77..0c382314c9 100644 --- a/examples/libraries/globals.js +++ b/examples/libraries/globals.js @@ -8,4 +8,4 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -HIFI_PUBLIC_BUCKET = "https://s3.amazonaws.com/hifi-public/"; +HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; diff --git a/interface/src/ScriptsModel.cpp b/interface/src/ScriptsModel.cpp index b95b6ae735..41ce16c229 100644 --- a/interface/src/ScriptsModel.cpp +++ b/interface/src/ScriptsModel.cpp @@ -21,7 +21,7 @@ #include "ScriptsModel.h" -static const QString S3_URL = "https://s3.amazonaws.com/hifi-public"; +static const QString S3_URL = "http://s3.amazonaws.com/hifi-public"; static const QString PUBLIC_URL = "http://public.highfidelity.io"; static const QString MODELS_LOCATION = "scripts/"; diff --git a/interface/src/ui/ModelsBrowser.cpp b/interface/src/ui/ModelsBrowser.cpp index 7a76bc2d7d..a39d9b9a19 100644 --- a/interface/src/ui/ModelsBrowser.cpp +++ b/interface/src/ui/ModelsBrowser.cpp @@ -26,7 +26,7 @@ const char* MODEL_TYPE_NAMES[] = { "entities", "heads", "skeletons", "attachments" }; -static const QString S3_URL = "https://s3.amazonaws.com/hifi-public"; +static const QString S3_URL = "http://s3.amazonaws.com/hifi-public"; static const QString PUBLIC_URL = "http://public.highfidelity.io"; static const QString MODELS_LOCATION = "models/"; diff --git a/tests/octree/src/ModelTests.cpp b/tests/octree/src/ModelTests.cpp index f6bef3e533..3666759de4 100644 --- a/tests/octree/src/ModelTests.cpp +++ b/tests/octree/src/ModelTests.cpp @@ -62,7 +62,7 @@ void EntityTests::entityTreeTests(bool verbose) { properties.setPosition(positionAtCenterInMeters); // TODO: Fix these unit tests. //properties.setRadius(halfMeter); - //properties.setModelURL("https://s3.amazonaws.com/hifi-public/ozan/theater.fbx"); + //properties.setModelURL("http://s3.amazonaws.com/hifi-public/ozan/theater.fbx"); tree.addEntity(entityID, properties); @@ -269,7 +269,7 @@ void EntityTests::entityTreeTests(bool verbose) { // TODO: fix these unit tests //properties.setRadius(halfMeter); - //properties.setModelURL("https://s3.amazonaws.com/hifi-public/ozan/theater.fbx"); + //properties.setModelURL("http://s3.amazonaws.com/hifi-public/ozan/theater.fbx"); if (extraVerbose) { qDebug() << "iteration:" << i From 34cba5c031b404b2812f186080ca02d95994aaab Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 23 Oct 2014 13:16:43 -0700 Subject: [PATCH 060/119] Added options to selectively toggle heightfield/dual contour surface rendering. --- interface/src/Menu.cpp | 2 ++ interface/src/Menu.h | 2 ++ interface/src/MetavoxelSystem.cpp | 53 +++++++++++++++---------------- 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 11ab5769cb..d7b47a549d 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -432,6 +432,8 @@ Menu::Menu() : QMenu* metavoxelOptionsMenu = developerMenu->addMenu("Metavoxels"); addCheckableActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::DisplayHermiteData, 0, false, Application::getInstance()->getMetavoxels(), SLOT(refreshVoxelData())); + addCheckableActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::RenderHeightfields, 0, true); + addCheckableActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::RenderDualContourSurfaces, 0, true); addActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::NetworkSimulator, 0, this, SLOT(showMetavoxelNetworkSimulator())); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 80f7f1e006..66755f0e5b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -446,8 +446,10 @@ namespace MenuOption { const QString Quit = "Quit"; const QString ReloadAllScripts = "Reload All Scripts"; const QString RenderBoundingCollisionShapes = "Show Bounding Collision Shapes"; + const QString RenderDualContourSurfaces = "Render Dual Contour Surfaces"; const QString RenderFocusIndicator = "Show Eye Focus"; const QString RenderHeadCollisionShapes = "Show Head Collision Shapes"; + const QString RenderHeightfields = "Render Heightfields"; const QString RenderLookAtVectors = "Show Look-at Vectors"; const QString RenderSkeletonCollisionShapes = "Show Skeleton Collision Shapes"; const QString RenderResolution = "Scale Resolution"; diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 8166c3938c..2071ea8c3d 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -2772,40 +2772,39 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - _baseHeightfieldProgram.bind(); - - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute()); - data.guide(heightfieldRenderVisitor); - - _baseHeightfieldProgram.release(); - - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); + if (Menu::getInstance()->isOptionChecked(MenuOption::RenderHeightfields)) { + _baseHeightfieldProgram.bind(); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute()); + data.guide(heightfieldRenderVisitor); + + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + _baseHeightfieldProgram.release(); + } - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - - _baseVoxelProgram.bind(); - - BufferRenderVisitor voxelRenderVisitor(Application::getInstance()->getMetavoxels()->getVoxelBufferAttribute()); - data.guide(voxelRenderVisitor); - - _baseVoxelProgram.release(); + if (Menu::getInstance()->isOptionChecked(MenuOption::RenderDualContourSurfaces)) { + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + + _baseVoxelProgram.bind(); + + BufferRenderVisitor voxelRenderVisitor(Application::getInstance()->getMetavoxels()->getVoxelBufferAttribute()); + data.guide(voxelRenderVisitor); + + _baseVoxelProgram.release(); + + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + } glDisable(GL_ALPHA_TEST); glDisable(GL_CULL_FACE); glEnable(GL_BLEND); - + glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false); } From ac269e16c02fa81c39f2ec7f0be5d3602f44f175 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 23 Oct 2014 13:19:34 -0700 Subject: [PATCH 061/119] start working on the target framerate control --- interface/src/Application.cpp | 33 +++++++++++++++++++++++++++++++-- interface/src/Application.h | 2 ++ interface/src/GLCanvas.cpp | 2 +- interface/src/Menu.cpp | 10 ++++++++++ interface/src/Menu.h | 2 ++ 5 files changed, 46 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 145222cd3c..8b3b448eb5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -94,6 +94,10 @@ #include "devices/Leapmotion.h" +#ifdef WIN32 +#include +#endif + using namespace std; // Starfield information @@ -177,8 +181,17 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _trayIcon(new QSystemTrayIcon(_window)), _lastNackTime(usecTimestampNow()), _lastSendDownstreamAudioStats(usecTimestampNow()), + _renderTargetFramerate(60), _renderResolutionScale(1.0f) { + + + /* QGLFormat trueFormat = _glWidget->format(); + trueFormat.setSwapInterval(0); + _glWidget->setFormat(trueFormat);*/ + int swapInterval = _glWidget->format().swapInterval(); + swapInterval++; + // read the ApplicationInfo.ini file for Name/Version/Domain information QSettings applicationInfo(Application::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); @@ -518,9 +531,16 @@ void Application::initializeGL() { qDebug("Error: %s\n", glewGetErrorString(err)); } qDebug("Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); + + if (wglewGetExtension("WGL_EXT_swap_control")) { + wglSwapIntervalEXT(0); + int swapInterval = wglGetSwapIntervalEXT(); + swapInterval++; + } #endif + // Before we render anything, let's set up our viewFrustumOffsetCamera with a sufficiently large // field of view and near and far clip to make it interesting. //viewFrustumOffsetCamera.setFieldOfView(90.0); @@ -1391,9 +1411,14 @@ void Application::idle() { PerformanceWarning warn(showWarnings, "idle()"); // Only run simulation code if more than IDLE_SIMULATE_MSECS have passed since last time we ran - + double targetFramePeriod = 0.0; + if (_renderTargetFramerate > 0) { + targetFramePeriod = 1000.0 / _renderTargetFramerate; + } else if (_renderTargetFramerate < 0) { + targetFramePeriod = IDLE_SIMULATE_MSECS; + } double timeSinceLastUpdate = (double)_lastTimeUpdated.nsecsElapsed() / 1000000.0; - if (timeSinceLastUpdate > IDLE_SIMULATE_MSECS) { + if (timeSinceLastUpdate > targetFramePeriod) { _lastTimeUpdated.start(); { PerformanceTimer perfTimer("update"); @@ -4138,6 +4163,10 @@ void Application::takeSnapshot() { _snapshotShareDialog->show(); } +void Application::setRenderTargetFramerate(int framerate) { + _renderTargetFramerate = framerate; +} + void Application::setRenderResolutionScale(float scale) { _renderResolutionScale = scale; } diff --git a/interface/src/Application.h b/interface/src/Application.h index 64c7032403..aeda706c42 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -358,6 +358,7 @@ public slots: void domainSettingsReceived(const QJsonObject& domainSettingsObject); + void setRenderTargetFramerate(int framerate); void setRenderResolutionScale(float scale); void resetSensors(); @@ -609,6 +610,7 @@ private: quint64 _lastNackTime; quint64 _lastSendDownstreamAudioStats; + int _renderTargetFramerate; float _renderResolutionScale; }; diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 108b9ba829..cec3f62b7d 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -20,7 +20,7 @@ const int MSECS_PER_FRAME_WHEN_THROTTLED = 66; -GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer)), +GLCanvas::GLCanvas() : QGLWidget(QGL::NoDepthBuffer | QGL::NoStencilBuffer), _throttleRendering(false), _idleRenderInterval(MSECS_PER_FRAME_WHEN_THROTTLED) { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 3a213cb64f..2abfc7c94e 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -372,6 +372,8 @@ Menu::Menu() : shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false)); shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false)); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::RenderUnleashFramerate, 0, false, this, SLOT(toggleUnleashFramerate())); + QMenu* resolutionMenu = renderOptionsMenu->addMenu(MenuOption::RenderResolution); QActionGroup* resolutionGroup = new QActionGroup(resolutionMenu); resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionOne, 0, false)); @@ -1230,6 +1232,14 @@ void Menu::muteEnvironment() { free(packet); } +void Menu::toggleUnleashFramerate() { + if (isOptionChecked(MenuOption::RenderUnleashFramerate)) { + Application::getInstance()->setRenderTargetFramerate(0); + } else { + Application::getInstance()->setRenderTargetFramerate(-1); + } +} + void Menu::changeRenderResolution(QAction* action) { QString text = action->text(); if (text == MenuOption::RenderResolutionOne) { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index a1936050ff..6977d61d6e 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -227,6 +227,7 @@ private slots: void displayAddressOfflineMessage(); void displayAddressNotFoundMessage(); void muteEnvironment(); + void toggleUnleashFramerate(); void changeRenderResolution(QAction* action); private: @@ -446,6 +447,7 @@ namespace MenuOption { const QString RenderHeadCollisionShapes = "Show Head Collision Shapes"; const QString RenderLookAtVectors = "Show Look-at Vectors"; const QString RenderSkeletonCollisionShapes = "Show Skeleton Collision Shapes"; + const QString RenderUnleashFramerate = "Unleash Framerate"; const QString RenderResolution = "Scale Resolution"; const QString RenderResolutionOne = "1"; const QString RenderResolutionTwoThird = "2/3"; From ef0a400dcbd18d9b45eb8b4086f29154dae7e53a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 23 Oct 2014 13:37:11 -0700 Subject: [PATCH 062/119] Fix for clearing empty nodes. --- .../metavoxels/src/MetavoxelMessages.cpp | 78 ++++++++++--------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index 2d1e03fc69..d92dc4bd5a 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -1049,19 +1049,14 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) { } // if all is gone, clear the node - if (!foundNonZero) { - info.outputValues[0] = AttributeValue(_outputs.at(0), - encodeInline(HeightfieldHeightDataPointer())); - info.outputValues[1] = AttributeValue(_outputs.at(1), - encodeInline(HeightfieldColorDataPointer())); - info.outputValues[2] = AttributeValue(_outputs.at(2), - encodeInline(HeightfieldMaterialDataPointer())); - return STOP_RECURSION; + if (foundNonZero) { + HeightfieldHeightDataPointer newHeightPointer(new HeightfieldHeightData(contents)); + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(newHeightPointer)); + + } else { + info.outputValues[0] = AttributeValue(_outputs.at(0)); } - HeightfieldHeightDataPointer newHeightPointer(new HeightfieldHeightData(contents)); - info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(newHeightPointer)); - // allow a border for what we clear in terms of color/material innerBounds.minimum.x += increment; innerBounds.minimum.z += increment; @@ -1090,19 +1085,24 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) { memcpy(dest, src, destWidth * DataBlock::COLOR_BYTES); } - destX = (innerOverlap.minimum.x - info.minimum.x) * heightScale; - destY = (innerOverlap.minimum.z - info.minimum.z) * heightScale; - destWidth = glm::ceil((innerOverlap.maximum.x - innerOverlap.minimum.x) * heightScale); - destHeight = glm::ceil((innerOverlap.maximum.z - innerOverlap.minimum.z) * heightScale); - if (destWidth > 0 && destHeight > 0) { - dest = contents.data() + (destY * size + destX) * DataBlock::COLOR_BYTES; - - for (int y = 0; y < destHeight; y++, dest += size * DataBlock::COLOR_BYTES) { - memset(dest, 0, destWidth * DataBlock::COLOR_BYTES); + if (foundNonZero) { + destX = (innerOverlap.minimum.x - info.minimum.x) * heightScale; + destY = (innerOverlap.minimum.z - info.minimum.z) * heightScale; + destWidth = glm::ceil((innerOverlap.maximum.x - innerOverlap.minimum.x) * heightScale); + destHeight = glm::ceil((innerOverlap.maximum.z - innerOverlap.minimum.z) * heightScale); + if (destWidth > 0 && destHeight > 0) { + dest = contents.data() + (destY * size + destX) * DataBlock::COLOR_BYTES; + + for (int y = 0; y < destHeight; y++, dest += size * DataBlock::COLOR_BYTES) { + memset(dest, 0, destWidth * DataBlock::COLOR_BYTES); + } + + HeightfieldColorDataPointer newColorPointer(new HeightfieldColorData(contents)); + info.outputValues[1] = AttributeValue(_outputs.at(1), + encodeInline(newColorPointer)); } - - HeightfieldColorDataPointer newColorPointer(new HeightfieldColorData(contents)); - info.outputValues[1] = AttributeValue(_outputs.at(1), encodeInline(newColorPointer)); + } else { + info.outputValues[1] = AttributeValue(_outputs.at(1)); } } @@ -1139,21 +1139,25 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) { } } - destX = (innerOverlap.minimum.x - info.minimum.x) * heightScale; - destY = (innerOverlap.minimum.z - info.minimum.z) * heightScale; - destWidth = glm::ceil((innerOverlap.maximum.x - innerOverlap.minimum.x) * heightScale); - destHeight = glm::ceil((innerOverlap.maximum.z - innerOverlap.minimum.z) * heightScale); - if (destWidth > 0 && destHeight > 0) { - dest = (uchar*)contents.data() + destY * size + destX; - - for (int y = 0; y < destHeight; y++, dest += size) { - memset(dest, 0, destWidth); + if (foundNonZero) { + destX = (innerOverlap.minimum.x - info.minimum.x) * heightScale; + destY = (innerOverlap.minimum.z - info.minimum.z) * heightScale; + destWidth = glm::ceil((innerOverlap.maximum.x - innerOverlap.minimum.x) * heightScale); + destHeight = glm::ceil((innerOverlap.maximum.z - innerOverlap.minimum.z) * heightScale); + if (destWidth > 0 && destHeight > 0) { + dest = (uchar*)contents.data() + destY * size + destX; + + for (int y = 0; y < destHeight; y++, dest += size) { + memset(dest, 0, destWidth); + } + + clearUnusedMaterials(materials, contents); + HeightfieldMaterialDataPointer newMaterialPointer(new HeightfieldMaterialData(contents, materials)); + info.outputValues[2] = AttributeValue(_outputs.at(2), + encodeInline(newMaterialPointer)); } - - clearUnusedMaterials(materials, contents); - HeightfieldMaterialDataPointer newMaterialPointer(new HeightfieldMaterialData(contents, materials)); - info.outputValues[2] = AttributeValue(_outputs.at(2), - encodeInline(newMaterialPointer)); + } else { + info.outputValues[2] = AttributeValue(_outputs.at(2)); } } From 20c862d199b80d01eecbf157453d987240d6ab0e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Oct 2014 14:35:24 -0700 Subject: [PATCH 063/119] Fix player loop --- libraries/avatars/src/Player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/avatars/src/Player.cpp b/libraries/avatars/src/Player.cpp index 35a822f11b..47d1b04421 100644 --- a/libraries/avatars/src/Player.cpp +++ b/libraries/avatars/src/Player.cpp @@ -212,7 +212,7 @@ void Player::loadRecording(RecordingPointer recording) { void Player::play() { computeCurrentFrame(); - if (_currentFrame < 0 || (_currentFrame >= _recording->getFrameNumber() - 1)) { + if (_currentFrame < 0 || (_currentFrame >= _recording->getFrameNumber() - 2)) { // -2 because of interpolation if (_loop) { loopRecording(); } else { From 5b5a1745fd15a55212f161c3b784073d15b2f90d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Oct 2014 14:46:39 -0700 Subject: [PATCH 064/119] Add camera move tool --- examples/libraries/entityCameraTool.js | 389 +++++++++++++++++++++- examples/libraries/entitySelectionTool.js | 1 - 2 files changed, 380 insertions(+), 10 deletions(-) diff --git a/examples/libraries/entityCameraTool.js b/examples/libraries/entityCameraTool.js index 63121d88a9..b6bb6e149e 100644 --- a/examples/libraries/entityCameraTool.js +++ b/examples/libraries/entityCameraTool.js @@ -34,7 +34,7 @@ var EASING_MULTIPLIER = 8; var INITIAL_ZOOM_DISTANCE = 2; var INITIAL_ZOOM_DISTANCE_FIRST_PERSON = 3; -EntityCameraTool = function() { +CameraManager = function() { var that = {}; that.enabled = false; @@ -85,24 +85,28 @@ EntityCameraTool = function() { Camera.setMode("independent"); that.updateCamera(); + + cameraTool.setVisible(true); } - that.disable = function() { + that.disable = function(ignoreCamera) { if (!that.enabled) return; that.enabled = false; that.mode = MODE_INACTIVE; - Camera.setMode(that.previousCameraMode); + if (!ignoreCamera) { + Camera.setMode(that.previousCameraMode); + } + cameraTool.setVisible(false); } that.focus = function(entityProperties) { - var dim = entityProperties.dimensions; - dim = SelectionManager.worldDimensions; + var dim = SelectionManager.worldDimensions; var size = Math.max(dim.x, Math.max(dim.y, dim.z)); that.targetZoomDistance = Math.max(size * FOCUS_ZOOM_SCALE, FOCUS_MIN_ZOOM); - that.setFocalPoint(SelectionManager.worldPosition);//entityProperties.position); + that.setFocalPoint(SelectionManager.worldPosition); that.updateCamera(); } @@ -116,6 +120,42 @@ EntityCameraTool = function() { that.updateCamera(); } + that.addYaw = function(yaw) { + that.targetYaw += yaw; + that.updateCamera(); + } + + that.addPitch = function(pitch) { + that.targetPitch += pitch; + that.updateCamera(); + } + + that.addZoom = function(zoom) { + zoom *= that.targetZoomDistance * ZOOM_SCALING; + that.targetZoomDistance = Math.min(Math.max(that.targetZoomDistance + zoom, MIN_ZOOM_DISTANCE), MAX_ZOOM_DISTANCE); + that.updateCamera(); + } + + that.getZoomPercentage = function() { + return (that.zoomDistance - MIN_ZOOM_DISTANCE) / MAX_ZOOM_DISTANCE; + } + + that.setZoomPercentage = function(pct) { + that.targetZoomDistance = pct * (MAX_ZOOM_DISTANCE - MIN_ZOOM_DISTANCE); + } + + that.pan = function(offset) { + var up = Quat.getUp(Camera.getOrientation()); + var right = Quat.getRight(Camera.getOrientation()); + + up = Vec3.multiply(up, offset.y * 0.01 * PAN_ZOOM_SCALE_RATIO * that.zoomDistance); + right = Vec3.multiply(right, offset.x * 0.01 * PAN_ZOOM_SCALE_RATIO * that.zoomDistance); + + var dPosition = Vec3.sum(up, right); + + that.moveFocalPoint(dPosition); + } + that.mouseMoveEvent = function(event) { if (that.enabled && that.mode != MODE_INACTIVE) { if (that.mode == MODE_ORBIT) { @@ -168,7 +208,7 @@ EntityCameraTool = function() { return true; } - return false; + return cameraTool.mousePressEvent(event); } that.mouseReleaseEvent = function(event) { @@ -185,13 +225,13 @@ EntityCameraTool = function() { // Scale based on current zoom level dZoom *= that.targetZoomDistance * ZOOM_SCALING; - that.targetZoomDistance = Math.max(that.targetZoomDistance + dZoom, MIN_ZOOM_DISTANCE); + that.targetZoomDistance = Math.min(Math.max(that.targetZoomDistance + dZoom, MIN_ZOOM_DISTANCE), MAX_ZOOM_DISTANCE); that.updateCamera(); } that.updateCamera = function() { - if (!that.enabled) return; + if (!that.enabled || Camera.getMode() != "independent") return; var yRot = Quat.angleAxis(that.yaw, { x: 0, y: 1, z: 0 }); var xRot = Quat.angleAxis(that.pitch, { x: 1, y: 0, z: 0 }); @@ -215,6 +255,10 @@ EntityCameraTool = function() { // Ease the position and orbit of the camera that.update = function(dt) { + if (Camera.getMode() != "independent") { + return; + } + var scale = Math.min(dt * EASING_MULTIPLIER, 1.0); var dYaw = that.targetYaw - that.yaw; @@ -239,9 +283,336 @@ EntityCameraTool = function() { that.updateCamera(); } + // Last mode that was first or third person + var lastAvatarCameraMode = "first person"; + Camera.modeUpdated.connect(function(newMode) { + print("Camera mode has been updated: " + newMode); + if (newMode == "first person" || newMode == "third person") { + lastAvatarCameraMode = newMode; + that.disable(true); + } else { + that.enable(); + } + }); + + Controller.keyReleaseEvent.connect(function (event) { + if (event.text == "ESC" && that.enabled) { + Camera.setMode(lastAvatarCameraMode); + cameraManager.disable(true); + } + }); + Script.update.connect(that.update); Controller.wheelEvent.connect(that.wheelEvent); + var cameraTool = new CameraTool(that); + return that; } + +var ZoomTool = function(opts) { + var that = {}; + + var position = opts.position || { x: 0, y: 0 }; + var height = opts.height || 200; + var color = opts.color || { red: 255, green: 0, blue: 0 }; + var arrowButtonSize = opts.buttonSize || 20; + var arrowButtonBackground = opts.arrowBackground || { red: 255, green: 255, blue: 255 }; + var zoomBackground = { red: 128, green: 0, blue: 0 }; + var zoomHeight = height - (arrowButtonSize * 2); + var zoomBarY = position.y + arrowButtonSize, + + var onIncreasePressed = opts.onIncreasePressed; + var onDecreasePressed = opts.onDecreasePressed; + var onPercentageSet = opts.onPercentageSet; + + var increaseButton = Overlays.addOverlay("text", { + x: position.x, + y: position.y, + width: arrowButtonSize, + height: arrowButtonSize, + color: color, + backgroundColor: arrowButtonBackground, + topMargin: 4, + leftMargin: 4, + text: "+", + alpha: 1.0, + visible: true, + }); + var decreaseButton = Overlays.addOverlay("text", { + x: position.x, + y: position.y + arrowButtonSize + zoomHeight, + width: arrowButtonSize, + height: arrowButtonSize, + color: color, + backgroundColor: arrowButtonBackground, + topMargin: 4, + leftMargin: 4, + text: "-", + alpha: 1.0, + visible: true, + }); + var zoomBar = Overlays.addOverlay("text", { + x: position.x + 5, + y: zoomBarY, + width: 10, + height: zoomHeight, + color: { red: 0, green: 255, blue: 0 }, + backgroundColor: zoomBackground, + topMargin: 4, + leftMargin: 4, + text: "", + alpha: 1.0, + visible: true, + }); + var zoomHandle = Overlays.addOverlay("text", { + x: position.x, + y: position.y + arrowButtonSize, + width: arrowButtonSize, + height: 10, + backgroundColor: { red: 0, green: 255, blue: 0 }, + topMargin: 4, + leftMargin: 4, + text: "", + alpha: 1.0, + visible: true, + }); + + var allOverlays = [ + increaseButton, + decreaseButton, + zoomBar, + zoomHandle, + ]; + + that.destroy = function() { + for (var i = 0; i < allOverlays.length; i++) { + Overlays.deleteOverlay(allOverlays[i]); + } + }; + + that.setVisible = function(visible) { + for (var i = 0; i < allOverlays.length; i++) { + Overlays.editOverlay(allOverlays[i], { visible: visible }); + } + } + + that.setZoomPercentage = function(pct) { + var yOffset = (zoomHeight - 10) * pct; + Overlays.editOverlay(zoomHandle, { + y: position.y + arrowButtonSize + yOffset, + }); + } + + that.mouseReleaseEvent = function(event) { + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + var clicked = false; + if (clickedOverlay == increaseButton) { + if (onIncreasePressed) onIncreasePressed(); + clicked = true; + } else if (clickedOverlay == decreaseButton) { + if (onDecreasePressed) onDecreasePressed(); + clicked = true; + } else if (clickedOverlay == zoomBar) { + if (onPercentageSet) onPercentageSet((event.y - zoomBarY) / zoomHeight); + clicked = true; + } + return clicked; + } + + return that; +}; + +var ArrowTool = function(opts) { + var that = {}; + + var position = opts.position || { x: 0, y: 0 }; + var arrowButtonSize = opts.buttonSize || 20; + var color = opts.color || { red: 255, green: 0, blue: 0 }; + var arrowButtonBackground = opts.arrowBackground || { red: 255, green: 255, blue: 255 }; + var centerButtonBackground = opts.centerBackground || { red: 255, green: 255, blue: 255 }; + var onUpPressed = opts.onUpPressed; + var onDownPressed = opts.onDownPressed; + var onLeftPressed = opts.onLeftPressed; + var onRightPressed = opts.onRightPressed; + var onCenterPressed = opts.onCenterPressed; + + var upButton = Overlays.addOverlay("text", { + x: position.x + arrowButtonSize, + y: position.y, + width: arrowButtonSize, + height: arrowButtonSize, + color: color, + backgroundColor: arrowButtonBackground, + topMargin: 4, + leftMargin: 4, + text: "^", + alpha: 1.0, + visible: true, + }); + var leftButton = Overlays.addOverlay("text", { + x: position.x, + y: position.y + arrowButtonSize, + width: arrowButtonSize, + height: arrowButtonSize, + color: color, + backgroundColor: arrowButtonBackground, + topMargin: 4, + leftMargin: 4, + text: "<", + alpha: 1.0, + visible: true, + }); + var rightButton = Overlays.addOverlay("text", { + x: position.x + (arrowButtonSize * 2), + y: position.y + arrowButtonSize, + width: arrowButtonSize, + height: arrowButtonSize, + color: color, + backgroundColor: arrowButtonBackground, + topMargin: 4, + leftMargin: 4, + text: ">", + alpha: 1.0, + visible: true, + }); + var downButton = Overlays.addOverlay("text", { + x: position.x + arrowButtonSize, + y: position.y + (arrowButtonSize * 2), + width: arrowButtonSize, + height: arrowButtonSize, + color: color, + backgroundColor: arrowButtonBackground, + topMargin: 4, + leftMargin: 4, + text: "v", + alpha: 1.0, + visible: true, + }); + var centerButton = Overlays.addOverlay("text", { + x: position.x + arrowButtonSize, + y: position.y + arrowButtonSize, + width: arrowButtonSize, + height: arrowButtonSize, + color: color, + backgroundColor: centerButtonBackground, + topMargin: 4, + leftMargin: 4, + text: "", + alpha: 1.0, + visible: true, + }); + + var allOverlays = [ + upButton, + downButton, + leftButton, + rightButton, + centerButton, + ]; + + that.destroy = function() { + for (var i = 0; i < allOverlays.length; i++) { + Overlays.deleteOverlay(allOverlays[i]); + } + }; + + that.setVisible = function(visible) { + for (var i = 0; i < allOverlays.length; i++) { + Overlays.editOverlay(allOverlays[i], { visible: visible }); + } + } + + that.mouseReleaseEvent = function(event) { + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + var clicked = false; + if (clickedOverlay == leftButton) { + if (onLeftPressed) onLeftPressed(); + clicked = true; + } else if (clickedOverlay == rightButton) { + if (onRightPressed) onRightPressed(); + clicked = true; + } else if (clickedOverlay == upButton) { + if (onUpPressed) onUpPressed(); + clicked = true; + } else if (clickedOverlay == downButton) { + if (onDownPressed) onDownPressed(); + clicked = true; + } else if (clickedOverlay == centerButton) { + if (onCenterPressed) onCenterPressed(); + clicked = true; + } + return clicked; + } + + return that; +} + + +CameraTool = function(cameraManager) { + var that = {}; + + var toolsPosition = { x: 20, y: 280 }; + var orbitToolPosition = toolsPosition; + var panToolPosition = { x: toolsPosition.x + 80, y: toolsPosition.y }; + var zoomToolPosition = { x: toolsPosition.x + 20, y: toolsPosition.y + 80 }; + + var orbitIncrement = 15; + orbitTool = ArrowTool({ + position: orbitToolPosition, + arrowBackground: { red: 192, green: 192, blue: 192 }, + centerBackground: { red: 128, green: 128, blue: 255 }, + color: { red: 0, green: 0, blue: 0 }, + onUpPressed: function() { cameraManager.addPitch(orbitIncrement); }, + onDownPressed: function() { cameraManager.addPitch(-orbitIncrement); }, + onLeftPressed: function() { cameraManager.addYaw(-orbitIncrement); }, + onRightPressed: function() { cameraManager.addYaw(orbitIncrement); }, + onCenterPressed: function() { cameraManager.focus(); }, + }); + panTool = ArrowTool({ + position: panToolPosition, + arrowBackground: { red: 192, green: 192, blue: 192 }, + centerBackground: { red: 128, green: 128, blue: 255 }, + color: { red: 0, green: 0, blue: 0 }, + onUpPressed: function() { cameraManager.pan({ x: 0, y: 15 }); }, + onDownPressed: function() { cameraManager.pan({ x: 0, y: -15 }); }, + onLeftPressed: function() { cameraManager.pan({ x: -15, y: 0 }); }, + onRightPressed: function() { cameraManager.pan({ x: 15, y: 0 }); }, + }); + zoomTool = ZoomTool({ + position: zoomToolPosition, + arrowBackground: { red: 192, green: 192, blue: 192 }, + color: { red: 0, green: 0, blue: 0 }, + onIncreasePressed: function() { cameraManager.addZoom(-10); }, + onDecreasePressed: function() { cameraManager.addZoom(10); }, + onPercentageSet: function(pct) { cameraManager.setZoomPercentage(pct); } + }); + + Script.scriptEnding.connect(function() { + orbitTool.destroy(); + panTool.destroy(); + zoomTool.destroy(); + }); + + that.mousePressEvent = function(event) { + return orbitTool.mouseReleaseEvent(event) + || panTool.mouseReleaseEvent(event) + || zoomTool.mouseReleaseEvent(event); + }; + + that.setVisible = function(visible) { + orbitTool.setVisible(visible); + panTool.setVisible(visible); + zoomTool.setVisible(visible); + }; + + Script.update.connect(function() { + cameraManager.getZoomPercentage(); + zoomTool.setZoomPercentage(cameraManager.getZoomPercentage()); + }); + + that.setVisible(false); + + return that; +}; diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index f1a94dbdd7..486ba41ee7 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -19,7 +19,6 @@ SPACE_WORLD = "world"; SelectionManager = (function() { var that = {}; - that.savedProperties = {}; that.eventListener = null; From 28095e9972ac0bf8b36d4f6f1c98035b206f053a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Oct 2014 14:47:07 -0700 Subject: [PATCH 065/119] Remove print statements in edit entities --- examples/libraries/entitySelectionTool.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 486ba41ee7..70d1c7c918 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -926,7 +926,6 @@ SelectionDisplay = (function () { }; that.updateHandles = function() { - // print("Updating handles"); if (SelectionManager.selections.length == 0) { that.setOverlaysVisible(false); return; @@ -1287,7 +1286,6 @@ SelectionDisplay = (function () { var rotation = null; var onBegin = function(event) { - print("STARTING: " + stretchMode); var properties = Entities.getEntityProperties(currentSelection); initialProperties = properties; rotation = spaceMode == SPACE_LOCAL ? properties.rotation : Quat.fromPitchYawRollDegrees(0, 0, 0); @@ -1365,7 +1363,6 @@ SelectionDisplay = (function () { }; var onEnd = function(event, reason) { - print("ENDING: " + stretchMode); Overlays.editOverlay(xRailOverlay, { visible: false }); Overlays.editOverlay(yRailOverlay, { visible: false }); Overlays.editOverlay(zRailOverlay, { visible: false }); @@ -1414,7 +1411,6 @@ SelectionDisplay = (function () { var absX = Math.abs(changeInDimensions.x); var absY = Math.abs(changeInDimensions.y); var absZ = Math.abs(changeInDimensions.z); - print('abs: ' + absX + ', ' + absY + ', ' + absZ); var pctChange = 0; if (absX > absY && absX > absZ) { pctChange = changeInDimensions.x / initialProperties.dimensions.x; @@ -1426,7 +1422,6 @@ SelectionDisplay = (function () { pctChange = changeInDimensions.z / initialProperties.dimensions.z; pctChange = changeInDimensions.z / initialDimensions.z; } - print('change: ' + pctChange); pctChange += 1.0; newDimensions = Vec3.multiply(pctChange, initialDimensions); } else { @@ -1880,7 +1875,6 @@ SelectionDisplay = (function () { var tool = grabberTools[result.overlayID]; if (tool) { - print("FOUND TOOL! " + tool.mode); activeTool = tool; mode = tool.mode; somethingClicked = true; @@ -1980,7 +1974,6 @@ SelectionDisplay = (function () { if (result.intersects) { var tool = grabberTools[result.overlayID]; if (tool) { - print("FOUND TOOL! " + tool.mode); activeTool = tool; mode = tool.mode; somethingClicked = true; From fde7b30501dd8fd41259f37c75cebcf4ad13bbfa Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Oct 2014 14:47:41 -0700 Subject: [PATCH 066/119] Add Camera::modeUpdated() --- examples/newEditEntities.js | 21 ++++++++------- interface/src/Camera.cpp | 51 ++++++++++++++++++++++++------------- interface/src/Camera.h | 14 +++++++++- 3 files changed, 58 insertions(+), 28 deletions(-) diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index 4d5abaf254..f80af7912e 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -33,7 +33,7 @@ Script.include("libraries/entityPropertyDialogBox.js"); var entityPropertyDialogBox = EntityPropertyDialogBox; Script.include("libraries/entityCameraTool.js"); -var entityCameraTool = new EntityCameraTool(); +var cameraManager = new CameraManager(); selectionManager.setEventListener(selectionDisplay.updateHandles); @@ -247,9 +247,9 @@ var toolBar = (function () { isActive = !isActive; if (!isActive) { selectionDisplay.unselectAll(); - entityCameraTool.disable(); + cameraManager.disable(); } else { - entityCameraTool.enable(); + cameraManager.enable(); } return true; } @@ -374,7 +374,7 @@ function mousePressEvent(event) { var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); if (toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event) - || entityCameraTool.mousePressEvent(event) || selectionDisplay.mousePressEvent(event)) { + || cameraManager.mousePressEvent(event) || selectionDisplay.mousePressEvent(event)) { // Event handled; do nothing. return; } else { @@ -482,8 +482,8 @@ function mouseMoveEvent(event) { return; } - // allow the selectionDisplay and entityCameraTool to handle the event first, if it doesn't handle it, then do our own thing - if (selectionDisplay.mouseMoveEvent(event) || entityCameraTool.mouseMoveEvent(event)) { + // allow the selectionDisplay and cameraManager to handle the event first, if it doesn't handle it, then do our own thing + if (selectionDisplay.mouseMoveEvent(event) || cameraManager.mouseMoveEvent(event)) { return; } @@ -522,7 +522,7 @@ function mouseReleaseEvent(event) { if (entitySelected) { tooltip.show(false); } - entityCameraTool.mouseReleaseEvent(event); + cameraManager.mouseReleaseEvent(event); } Controller.mousePressEvent.connect(mousePressEvent); @@ -652,7 +652,6 @@ Menu.menuItemEvent.connect(handeMenuEvent); Controller.keyReleaseEvent.connect(function (event) { // since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items - print(event.text); if (event.text == "`") { handeMenuEvent("Edit Properties..."); } @@ -666,7 +665,11 @@ Controller.keyReleaseEvent.connect(function (event) { if (entitySelected) { // Get latest properties var properties = Entities.getEntityProperties(selectedEntityID); - entityCameraTool.focus(properties); + cameraManager.focus(properties); + } + } else if (event.text == '[') { + if (isActive) { + cameraManager.enable(); } } }); diff --git a/interface/src/Camera.cpp b/interface/src/Camera.cpp index a8138363fa..ceb4cb09a0 100644 --- a/interface/src/Camera.cpp +++ b/interface/src/Camera.cpp @@ -21,6 +21,32 @@ #include "devices/OculusManager.h" +CameraMode stringToMode(const QString& mode) { + if (mode == "third person") { + return CAMERA_MODE_THIRD_PERSON; + } else if (mode == "first person") { + return CAMERA_MODE_FIRST_PERSON; + } else if (mode == "mirror") { + return CAMERA_MODE_MIRROR; + } else if (mode == "independent") { + return CAMERA_MODE_INDEPENDENT; + } + return CAMERA_MODE_NULL; +} + +QString modeToString(CameraMode mode) { + if (mode == CAMERA_MODE_THIRD_PERSON) { + return "third person"; + } else if (mode == CAMERA_MODE_FIRST_PERSON) { + return "first person"; + } else if (mode == CAMERA_MODE_MIRROR) { + return "mirror"; + } else if (mode == CAMERA_MODE_INDEPENDENT) { + return "independent"; + } + return "unknown"; +} + Camera::Camera() : _mode(CAMERA_MODE_THIRD_PERSON), _position(0.0f, 0.0f, 0.0f), @@ -48,6 +74,7 @@ float Camera::getFarClip() const { void Camera::setMode(CameraMode m) { _mode = m; + emit modeUpdated(m); } @@ -70,6 +97,7 @@ void Camera::setFarClip(float f) { CameraScriptableObject::CameraScriptableObject(Camera* camera, ViewFrustum* viewFrustum) : _camera(camera), _viewFrustum(viewFrustum) { + connect(_camera, &Camera::modeUpdated, this, &CameraScriptableObject::onModeUpdated); } PickRay CameraScriptableObject::computePickRay(float x, float y) { @@ -86,24 +114,7 @@ PickRay CameraScriptableObject::computePickRay(float x, float y) { } QString CameraScriptableObject::getMode() const { - QString mode("unknown"); - switch(_camera->getMode()) { - case CAMERA_MODE_THIRD_PERSON: - mode = "third person"; - break; - case CAMERA_MODE_FIRST_PERSON: - mode = "first person"; - break; - case CAMERA_MODE_MIRROR: - mode = "mirror"; - break; - case CAMERA_MODE_INDEPENDENT: - mode = "independent"; - break; - default: - break; - } - return mode; + return modeToString(_camera->getMode()); } void CameraScriptableObject::setMode(const QString& mode) { @@ -131,5 +142,9 @@ void CameraScriptableObject::setMode(const QString& mode) { } } +void CameraScriptableObject::onModeUpdated(CameraMode m) { + emit modeUpdated(modeToString(m)); +} + diff --git a/interface/src/Camera.h b/interface/src/Camera.h index 80454a969e..e876f70e3a 100644 --- a/interface/src/Camera.h +++ b/interface/src/Camera.h @@ -27,8 +27,11 @@ enum CameraMode NUM_CAMERA_MODES }; -class Camera { +Q_DECLARE_METATYPE(CameraMode); +static int cameraModeId = qRegisterMetaType(); +class Camera : public QObject { + Q_OBJECT public: Camera(); @@ -63,6 +66,9 @@ public: const glm::vec3& getEyeOffsetPosition() const { return _eyeOffsetPosition; } const glm::quat& getEyeOffsetOrientation() const { return _eyeOffsetOrientation; } float getScale() const { return _scale; } + +signals: + void modeUpdated(CameraMode newMode); private: @@ -100,6 +106,12 @@ public slots: PickRay computePickRay(float x, float y); +signals: + void modeUpdated(const QString& newMode); + +private slots: + void onModeUpdated(CameraMode m); + private: Camera* _camera; ViewFrustum* _viewFrustum; From d92c03364ad0a401e37c8f048bbc8639d74d8b46 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 23 Oct 2014 14:53:43 -0700 Subject: [PATCH 067/119] Improve comment regarding the replacement of the QGLProgram->bind() --- interface/src/renderer/Model.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 0dd31c1785..131c600dc1 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1649,20 +1649,11 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl ProgramObject* activeProgram = program; Locations* activeLocations = locations; - // Try to use the Batch - //gpu::Batch batch; - - /*if (isSkinned) { - skinProgram->bind(); - activeProgram = skinProgram; - activeLocations = skinLocations; - } else { - program->bind(); - }*/ if (isSkinned) { activeProgram = skinProgram; activeLocations = skinLocations; } + // This code replace the "bind()" on the QGLProgram if (!activeProgram->isLinked()) { activeProgram->link(); } From e556886c72b9b0135c2c342f9660e093eded3c8f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Oct 2014 15:28:16 -0700 Subject: [PATCH 068/119] Add entity copying and axis constraining to entity tools --- examples/libraries/entitySelectionTool.js | 62 ++++++++++++++++++----- examples/newEditEntities.js | 2 +- 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 70d1c7c918..c503ab82a4 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -1132,17 +1132,30 @@ SelectionDisplay = (function () { UndoStack.pushCommand(applyEntityProperties, undoData, applyEntityProperties, redoData); } - var lastXZPick = null; + var initialXZPick = null; + var isConstrained = false; + var startPosition = null; var translateXZTool = { mode: 'TRANSLATE_XZ', onBegin: function(event) { SelectionManager.saveProperties(); - var position = SelectionManager.worldPosition; + startPosition = SelectionManager.worldPosition; var dimensions = SelectionManager.worldDimensions; - var bottom = position.y - (dimensions.y / 2) var pickRay = Camera.computePickRay(event.x, event.y); - lastXZPick = rayPlaneIntersection(pickRay, position, { x: 0, y: 1, z: 0 }); + initialXZPick = rayPlaneIntersection(pickRay, startPosition, { x: 0, y: 1, z: 0 }); + + // Duplicate entities if alt is pressed. This will make a + // copy of the selected entities and move the _original_ entities, not + // the new ones. + if (event.isAlt) { + for (var otherEntityID in SelectionManager.savedProperties) { + var properties = SelectionManager.savedProperties[otherEntityID]; + var entityID = Entities.addEntity(properties); + } + } + + isConstrained = false; }, onEnd: function(event, reason) { if (reason == 'cancel') { @@ -1154,6 +1167,8 @@ SelectionDisplay = (function () { } else { pushCommandForSelections(); } + Overlays.editOverlay(xRailOverlay, { visible: false }); + Overlays.editOverlay(zRailOverlay, { visible: false }); }, onMove: function(event) { if (!entitySelected || mode !== "TRANSLATE_XZ") { @@ -1168,26 +1183,47 @@ SelectionDisplay = (function () { Quat.getFront(lastCameraOrientation)); var vector = Vec3.subtract(newIntersection, lastPlaneIntersection); - - var pickRay = Camera.computePickRay(event.x, event.y); var pick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, { x: 0, y: 1, z: 0 }); - vector = Vec3.subtract(pick, lastXZPick); - lastXZPick = pick; + var vector = Vec3.subtract(pick, initialXZPick); + // initialXZPick = pick; + + // If shifted, constrain to one axis + if (event.isShifted) { + if (Math.abs(vector.x) > Math.abs(vector.z)) { + vector.z = 0; + } else { + vector.x = 0; + } + if (!isConstrained) { + Overlays.editOverlay(xRailOverlay, { visible: true }); + var xStart = Vec3.sum(startPosition, { x: -10000, y: 0, z: 0 }); + var xEnd = Vec3.sum(startPosition, { x: 10000, y: 0, z: 0 }); + var zStart = Vec3.sum(startPosition, { x: 0, y: 0, z: -10000 }); + var zEnd = Vec3.sum(startPosition, { x: 0, y: 0, z: 10000 }); + Overlays.editOverlay(xRailOverlay, { start: xStart, end: xEnd, visible: true }); + Overlays.editOverlay(zRailOverlay, { start: zStart, end: zEnd, visible: true }); + isConstrained = true; + } + } else { + if (isConstrained) { + Overlays.editOverlay(xRailOverlay, { visible: false }); + Overlays.editOverlay(zRailOverlay, { visible: false }); + } + } var wantDebug = false; for (var i = 0; i < SelectionManager.selections.length; i++) { - var properties = Entities.getEntityProperties(SelectionManager.selections[i]); - var original = properties.position; - properties.position = Vec3.sum(properties.position, vector); - Entities.editEntity(SelectionManager.selections[i], properties); + var properties = SelectionManager.savedProperties[SelectionManager.selections[i].id]; + Entities.editEntity(SelectionManager.selections[i], { + position: Vec3.sum(properties.position, vector), + }); if (wantDebug) { print("translateXZ... "); Vec3.print(" lastPlaneIntersection:", lastPlaneIntersection); Vec3.print(" newIntersection:", newIntersection); Vec3.print(" vector:", vector); - Vec3.print(" originalPosition:", original); Vec3.print(" newPosition:", properties.position); Vec3.print(" newPosition:", newPosition); } diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index f80af7912e..aa38baf9e2 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -178,7 +178,7 @@ var toolBar = (function () { position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); if (position.x > 0 && position.y > 0 && position.z > 0) { - Entities.addEntity({ + var entityId = Entities.addEntity({ type: "Model", position: position, dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION }, From 27d9de0cba6fbdc862a165161a09e56fc89a3246 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 23 Oct 2014 16:01:51 -0700 Subject: [PATCH 069/119] More gradual improvements to heightfield voxelization. --- libraries/metavoxels/src/MetavoxelData.cpp | 35 +++++++++++++++++-- .../metavoxels/src/MetavoxelMessages.cpp | 9 +++-- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 5b00c6531f..2bd28de784 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -2486,8 +2486,39 @@ bool Heightfield::intersects(const glm::vec3& start, const glm::vec3& end, float if (!getBounds().findRayIntersection(start, direction, rayDistance) || rayDistance > 1.0f) { return false; } - glm::vec3 entry = (start + direction * rayDistance - getBounds().minimum) / _increment; - direction /= _increment; + glm::vec3 entry = start + direction * rayDistance; + const float DISTANCE_THRESHOLD = 0.001f; + if (glm::abs(entry.x - getBounds().minimum.x) < DISTANCE_THRESHOLD) { + normal = glm::vec3(-1.0f, 0.0f, 0.0f); + distance = rayDistance; + return true; + + } else if (glm::abs(entry.x - getBounds().maximum.x) < DISTANCE_THRESHOLD) { + normal = glm::vec3(1.0f, 0.0f, 0.0f); + distance = rayDistance; + return true; + + } else if (glm::abs(entry.y - getBounds().minimum.y) < DISTANCE_THRESHOLD) { + normal = glm::vec3(0.0f, -1.0f, 0.0f); + distance = rayDistance; + return true; + + } else if (glm::abs(entry.y - getBounds().maximum.y) < DISTANCE_THRESHOLD) { + normal = glm::vec3(0.0f, 1.0f, 0.0f); + distance = rayDistance; + return true; + + } else if (glm::abs(entry.z - getBounds().minimum.z) < DISTANCE_THRESHOLD) { + normal = glm::vec3(0.0f, 0.0f, -1.0f); + distance = rayDistance; + return true; + + } else if (glm::abs(entry.z - getBounds().maximum.z) < DISTANCE_THRESHOLD) { + normal = glm::vec3(0.0f, 0.0f, 1.0f); + distance = rayDistance; + return true; + } + entry = (entry - getBounds().minimum) / _increment; glm::vec3 floors = glm::floor(entry); glm::vec3 ceils = glm::ceil(entry); if (floors.x == ceils.x) { diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index d92dc4bd5a..549931e030 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -998,10 +998,13 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) { _spannerBounds.maximum = (glm::ceil(_bounds.maximum / increment) + glm::vec3(1.0f, 0.0f, 1.0f)) * increment; _spannerBounds.minimum.y = bounds.minimum.y; _spannerBounds.maximum.y = bounds.maximum.y; - _heightfieldWidth = (int)glm::round((_spannerBounds.maximum.x - _spannerBounds.minimum.x) / increment) + 1; - _heightfieldHeight = (int)glm::round((_spannerBounds.maximum.z - _spannerBounds.minimum.z) / increment) + 1; + _heightfieldWidth = (int)glm::round((_spannerBounds.maximum.x - _spannerBounds.minimum.x) / increment); + _heightfieldHeight = (int)glm::round((_spannerBounds.maximum.z - _spannerBounds.minimum.z) / increment); int heightfieldArea = _heightfieldWidth * _heightfieldHeight; - _spanner = spanner = new Heightfield(_spannerBounds, increment, QByteArray(heightfieldArea, 0), + Box innerBounds = _spannerBounds; + innerBounds.maximum.x -= increment; + innerBounds.maximum.z -= increment; + _spanner = spanner = new Heightfield(innerBounds, increment, QByteArray(heightfieldArea, 0), QByteArray(heightfieldArea * DataBlock::COLOR_BYTES, 0), QByteArray(heightfieldArea, 0), QVector()); } From fd23fb66abeaa7c67829d7ec3b51cf9713b08204 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Oct 2014 10:42:29 -0700 Subject: [PATCH 070/119] bubble up ATL_INCLUDE_DIRS from FindATL module --- cmake/modules/FindATL.cmake | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cmake/modules/FindATL.cmake b/cmake/modules/FindATL.cmake index f95b0267eb..24a21643d6 100644 --- a/cmake/modules/FindATL.cmake +++ b/cmake/modules/FindATL.cmake @@ -16,8 +16,11 @@ # if (WIN32) - find_library(ATL_LIBRARY_RELEASE atls PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS "C:\\WinDDK") - find_library(ATL_LIBRARY_DEBUG atlsd PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS "C:\\WinDDK") + set(ATL_SEARCH_DIRS "C:\\WinDDK") + find_path(ATL_INCLUDE_DIRS atlbase.h PATH_SUFFIXES "7600.16385.1/inc/atl71" HINTS ${ATL_SEARCH_DIRS}) + + find_library(ATL_LIBRARY_RELEASE atls PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS ${ATL_SEARCH_DIRS}) + find_library(ATL_LIBRARY_DEBUG atlsd PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS ${ATL_SEARCH_DIRS}) include(SelectLibraryConfigurations) select_library_configurations(ATL) @@ -26,4 +29,4 @@ endif () set(ATL_LIBRARIES "${ATL_LIBRARY}") include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(ATL DEFAULT_MSG ATL_LIBRARIES) \ No newline at end of file +find_package_handle_standard_args(ATL DEFAULT_MSG ATL_LIBRARIES ATL_INCLUDE_DIRS) \ No newline at end of file From 30aa23e5cd91c6055f469b6c795504d76ab1f977 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Oct 2014 10:45:06 -0700 Subject: [PATCH 071/119] message include dir for ATL when found --- cmake/modules/FindATL.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/modules/FindATL.cmake b/cmake/modules/FindATL.cmake index 24a21643d6..b32a2a4c70 100644 --- a/cmake/modules/FindATL.cmake +++ b/cmake/modules/FindATL.cmake @@ -29,4 +29,4 @@ endif () set(ATL_LIBRARIES "${ATL_LIBRARY}") include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(ATL DEFAULT_MSG ATL_LIBRARIES ATL_INCLUDE_DIRS) \ No newline at end of file +find_package_handle_standard_args(ATL DEFAULT_MSG ATL_INCLUDE_DIRS ATL_LIBRARIES) \ No newline at end of file From c172f628fc85d1bbe8b39f755f5dfd5dc9378055 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Oct 2014 11:12:55 -0700 Subject: [PATCH 072/119] repairs to FindATL indenting --- cmake/modules/FindATL.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/modules/FindATL.cmake b/cmake/modules/FindATL.cmake index b32a2a4c70..ecb9078d82 100644 --- a/cmake/modules/FindATL.cmake +++ b/cmake/modules/FindATL.cmake @@ -19,7 +19,7 @@ if (WIN32) set(ATL_SEARCH_DIRS "C:\\WinDDK") find_path(ATL_INCLUDE_DIRS atlbase.h PATH_SUFFIXES "7600.16385.1/inc/atl71" HINTS ${ATL_SEARCH_DIRS}) - find_library(ATL_LIBRARY_RELEASE atls PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS ${ATL_SEARCH_DIRS}) + find_library(ATL_LIBRARY_RELEASE atls PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS ${ATL_SEARCH_DIRS}) find_library(ATL_LIBRARY_DEBUG atlsd PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS ${ATL_SEARCH_DIRS}) include(SelectLibraryConfigurations) From ab557447f236c868c153f1b75dbb10b3ddbf0a2b Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 24 Oct 2014 12:51:54 -0700 Subject: [PATCH 073/119] fix uninitialized mouth blending variables --- interface/src/avatar/Head.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 31f08d9eae..3b6922d0d1 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -35,6 +35,9 @@ Head::Head(Avatar* owningAvatar) : _longTermAverageLoudness(-1.0f), _audioAttack(0.0f), _audioJawOpen(0.0f), + _mouth2(0.0f), + _mouth3(0.0f), + _mouth4(0.0f), _angularVelocity(0,0,0), _renderLookatVectors(false), _saccade(0.0f, 0.0f, 0.0f), From 9289249df5cda81a0d89dc5c0776920b28d02da1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Oct 2014 15:06:18 -0700 Subject: [PATCH 074/119] add a guard in case SDL somehow forgets about axes --- interface/src/devices/Joystick.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/interface/src/devices/Joystick.cpp b/interface/src/devices/Joystick.cpp index 25b8bc142d..a01b84e098 100644 --- a/interface/src/devices/Joystick.cpp +++ b/interface/src/devices/Joystick.cpp @@ -45,10 +45,12 @@ void Joystick::closeJoystick() { #ifdef HAVE_SDL2 void Joystick::handleAxisEvent(const SDL_ControllerAxisEvent& event) { - float oldValue = _axes[event.axis]; - float newValue = event.value / MAX_AXIS; - _axes[event.axis] = newValue; - emit axisValueChanged(event.axis, newValue, oldValue); + if (event.axis < _axes.size() - 1) { + float oldValue = _axes[event.axis]; + float newValue = event.value / MAX_AXIS; + _axes[event.axis] = newValue; + emit axisValueChanged(event.axis, newValue, oldValue); + } } void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) { From c57fc314f08b0725c891bdd144edcd9836b658a2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Oct 2014 15:13:54 -0700 Subject: [PATCH 075/119] just resize axis vector is sdl decides to lie about the number of axes --- interface/src/devices/Joystick.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/interface/src/devices/Joystick.cpp b/interface/src/devices/Joystick.cpp index a01b84e098..8b225437c2 100644 --- a/interface/src/devices/Joystick.cpp +++ b/interface/src/devices/Joystick.cpp @@ -45,12 +45,15 @@ void Joystick::closeJoystick() { #ifdef HAVE_SDL2 void Joystick::handleAxisEvent(const SDL_ControllerAxisEvent& event) { - if (event.axis < _axes.size() - 1) { - float oldValue = _axes[event.axis]; - float newValue = event.value / MAX_AXIS; - _axes[event.axis] = newValue; - emit axisValueChanged(event.axis, newValue, oldValue); + if (_axes.size() <= event.axis) { + _axes.resize(event.axis + 1); } + + float oldValue = _axes[event.axis]; + float newValue = event.value / MAX_AXIS; + _axes[event.axis] = newValue; + + emit axisValueChanged(event.axis, newValue, oldValue); } void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) { From d5d0fbd9d8ecb58101fe960f875fd9d24d4af544 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 24 Oct 2014 16:08:01 -0700 Subject: [PATCH 076/119] Hair gravity always the same --- interface/src/Hair.cpp | 6 +++--- interface/src/Hair.h | 4 ++-- interface/src/avatar/Avatar.cpp | 1 - interface/src/avatar/MyAvatar.cpp | 1 - 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/interface/src/Hair.cpp b/interface/src/Hair.cpp index 6ca0d4a899..acc00c14b0 100644 --- a/interface/src/Hair.cpp +++ b/interface/src/Hair.cpp @@ -38,7 +38,7 @@ Hair::Hair(int strands, _acceleration(0.0f), _angularVelocity(0.0f), _angularAcceleration(0.0f), - _gravity(0.0f), + _gravity(DEFAULT_GRAVITY), _loudness(0.0f) { _hairPosition = new glm::vec3[_strands * _links]; @@ -53,7 +53,7 @@ Hair::Hair(int strands, for (int strand = 0; strand < _strands; strand++) { float strandAngle = randFloat() * PI; float azimuth; - float elevation = PI_OVER_TWO - (randFloat() * 0.10f * PI); + float elevation = - (randFloat() * PI); azimuth = PI_OVER_TWO; if (randFloat() < 0.5f) { azimuth *= -1.0f; @@ -127,7 +127,7 @@ void Hair::simulate(float deltaTime) { _hairPosition[vertexIndex] += randVector() * (QUIESCENT_LOUDNESS + loudnessFactor) * ((float)link / (float)_links); // Add gravity - const float SCALE_GRAVITY = 0.13f; + const float SCALE_GRAVITY = 0.001f; _hairPosition[vertexIndex] += _gravity * deltaTime * SCALE_GRAVITY; // Add linear acceleration diff --git a/interface/src/Hair.h b/interface/src/Hair.h index f799140c53..94378dfd6a 100644 --- a/interface/src/Hair.h +++ b/interface/src/Hair.h @@ -25,9 +25,10 @@ const int HAIR_CONSTRAINTS = 2; const int DEFAULT_HAIR_STRANDS = 20; const int DEFAULT_HAIR_LINKS = 10; -const float DEFAULT_HAIR_RADIUS = 0.15f; +const float DEFAULT_HAIR_RADIUS = 0.075f; const float DEFAULT_HAIR_LINK_LENGTH = 0.06f; const float DEFAULT_HAIR_THICKNESS = 0.025f; +const glm::vec3 DEFAULT_GRAVITY(0.0f, -9.8f, 0.0f); class Hair { public: @@ -41,7 +42,6 @@ public: void setAcceleration(const glm::vec3& acceleration) { _acceleration = acceleration; } void setAngularVelocity(const glm::vec3& angularVelocity) { _angularVelocity = angularVelocity; } void setAngularAcceleration(const glm::vec3& angularAcceleration) { _angularAcceleration = angularAcceleration; } - void setGravity(const glm::vec3& gravity) { _gravity = gravity; } void setLoudness(const float loudness) { _loudness = loudness; } private: diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 169583b14b..b1c4b44104 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -191,7 +191,6 @@ void Avatar::simulate(float deltaTime) { _hair.setAcceleration(getAcceleration() * getHead()->getFinalOrientationInWorldFrame()); _hair.setAngularVelocity((getAngularVelocity() + getHead()->getAngularVelocity()) * getHead()->getFinalOrientationInWorldFrame()); _hair.setAngularAcceleration(getAngularAcceleration() * getHead()->getFinalOrientationInWorldFrame()); - _hair.setGravity(Application::getInstance()->getEnvironment()->getGravity(getPosition()) * getHead()->getFinalOrientationInWorldFrame()); _hair.setLoudness((float) getHeadData()->getAudioLoudness()); _hair.simulate(deltaTime); } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4751abfd84..7576d42325 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -217,7 +217,6 @@ void MyAvatar::simulate(float deltaTime) { _hair.setAcceleration(getAcceleration() * getHead()->getFinalOrientationInWorldFrame()); _hair.setAngularVelocity((getAngularVelocity() + getHead()->getAngularVelocity()) * getHead()->getFinalOrientationInWorldFrame()); _hair.setAngularAcceleration(getAngularAcceleration() * getHead()->getFinalOrientationInWorldFrame()); - _hair.setGravity(Application::getInstance()->getEnvironment()->getGravity(getPosition()) * getHead()->getFinalOrientationInWorldFrame()); _hair.setLoudness((float)getHeadData()->getAudioLoudness()); _hair.simulate(deltaTime); } From f8b423ced6c8f67c3ddf7e3ee2e9f4babf8455f7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Oct 2014 16:12:15 -0700 Subject: [PATCH 077/119] bubble up isAutoRepeat state for KeyEvent --- libraries/script-engine/src/EventTypes.cpp | 12 +++++++++--- libraries/script-engine/src/EventTypes.h | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/libraries/script-engine/src/EventTypes.cpp b/libraries/script-engine/src/EventTypes.cpp index 75b3eba1a3..de3ec231ae 100644 --- a/libraries/script-engine/src/EventTypes.cpp +++ b/libraries/script-engine/src/EventTypes.cpp @@ -30,7 +30,8 @@ KeyEvent::KeyEvent() : isMeta(false), isAlt(false), isKeypad(false), - isValid(false) + isValid(false), + isAutoRepeat(false) { }; @@ -44,6 +45,7 @@ KeyEvent::KeyEvent(const QKeyEvent& event) { isAlt = event.modifiers().testFlag(Qt::AltModifier); isKeypad = event.modifiers().testFlag(Qt::KeypadModifier); isValid = true; + isAutoRepeat = event.isAutoRepeat(); // handle special text for special characters... if (key == Qt::Key_F1) { @@ -127,7 +129,8 @@ bool KeyEvent::operator==(const KeyEvent& other) const { && other.isControl == isControl && other.isMeta == isMeta && other.isAlt == isAlt - && other.isKeypad == isKeypad; + && other.isKeypad == isKeypad + && other.isAutoRepeat == isAutoRepeat; } @@ -163,6 +166,7 @@ QScriptValue keyEventToScriptValue(QScriptEngine* engine, const KeyEvent& event) obj.setProperty("isControl", event.isControl); obj.setProperty("isAlt", event.isAlt); obj.setProperty("isKeypad", event.isKeypad); + obj.setProperty("isAutoRepeat", event.isAutoRepeat); return obj; } @@ -173,6 +177,7 @@ void keyEventFromScriptValue(const QScriptValue& object, KeyEvent& event) { event.isControl = object.property("isControl").toVariant().toBool(); event.isAlt = object.property("isAlt").toVariant().toBool(); event.isKeypad = object.property("isKeypad").toVariant().toBool(); + event.isAutoRepeat = object.property("isAutoRepeat").toVariant().toBool(); QScriptValue key = object.property("key"); if (key.isValid()) { @@ -286,7 +291,8 @@ void keyEventFromScriptValue(const QScriptValue& object, KeyEvent& event) { << " event.isControl=" << event.isControl << " event.isMeta=" << event.isMeta << " event.isAlt=" << event.isAlt - << " event.isKeypad=" << event.isKeypad; + << " event.isKeypad=" << event.isKeypad + << " event.isAutoRepeat=" << event.isAutoRepeat; } } diff --git a/libraries/script-engine/src/EventTypes.h b/libraries/script-engine/src/EventTypes.h index 7d4076dbf0..959292039b 100644 --- a/libraries/script-engine/src/EventTypes.h +++ b/libraries/script-engine/src/EventTypes.h @@ -38,6 +38,7 @@ public: bool isAlt; bool isKeypad; bool isValid; + bool isAutoRepeat; }; From 8ae1f980f50edd37ea8527fd5f450b935dc7b79e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Oct 2014 16:13:01 -0700 Subject: [PATCH 078/119] don't make headMove changes if key is auto repeating --- examples/headMove.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/headMove.js b/examples/headMove.js index 831e77a723..b9330153fc 100644 --- a/examples/headMove.js +++ b/examples/headMove.js @@ -142,7 +142,7 @@ function update(deltaTime) { } Controller.keyPressEvent.connect(function(event) { - if (event.text == "SPACE" && !movingWithHead) { + if (event.text == "SPACE" && !event.isAutoRepeat && !movingWithHead) { keyDownTime = 0.0; movingWithHead = true; headStartPosition = MyAvatar.getTrackedHeadPosition(); @@ -161,7 +161,7 @@ var TIME_FOR_TURN = 0.25; var TURN_AROUND = 180.0; Controller.keyReleaseEvent.connect(function(event) { - if (event.text == "SPACE") { + if (event.text == "SPACE" && !event.isAutoRepeat) { movingWithHead = false; if (keyDownTime < TIME_FOR_TURN_AROUND) { if (keyDownTime < TIME_FOR_TURN) { From 1e832e7bbbe34a755a7c86de2006c2682600b45a Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 24 Oct 2014 16:38:24 -0700 Subject: [PATCH 079/119] Tour guide script --- examples/guidedTour.js | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 examples/guidedTour.js diff --git a/examples/guidedTour.js b/examples/guidedTour.js new file mode 100644 index 0000000000..fe31e1db30 --- /dev/null +++ b/examples/guidedTour.js @@ -0,0 +1,47 @@ +// +// TourGuide.js +// +// This script will follow another person, if their display name is "Tour Guide" +// +var leaderName = "Tour Guide"; + +var guide; +var isGuide = false; +var lastGuidePosition = { x:0, y:0, z:0 }; +var MIN_CHANGE = 2.0; +var LANDING_DISTANCE = 2.0; +var LANDING_RANDOM = 0.2; + +function update(deltaTime) { + + if (Math.random() < deltaTime) { + guide = AvatarList.avatarWithDisplayName(leaderName); + if (guide && !isGuide) { + print("found a guide!"); + isGuide = true; + } else if (!isGuide) { + print("Lost My Guide"); + isguide = false; + } + } + + if (guide) { + // Check whether guide has moved, update if so + if (Vec3.length(lastGuidePosition) == 0.0) { + lastGuidePosition = guide.position; + } else { + if (Vec3.length(Vec3.subtract(lastGuidePosition, guide.position)) > MIN_CHANGE) { + var meToGuide = Vec3.multiply(Vec3.normalize(Vec3.subtract(guide.position, MyAvatar.position)), LANDING_DISTANCE); + var newPosition = Vec3.subtract(guide.position, meToGuide); + newPosition = Vec3.sum(newPosition, { x: Math.random() * LANDING_RANDOM - LANDING_RANDOM / 2.0, + y: 0, + z: Math.random() * LANDING_RANDOM - LANDING_RANDOM / 2.0 }); + MyAvatar.position = newPosition; + + lastGuidePosition = guide.position; + MyAvatar.orientation = guide.orientation; + } + } + } +} +Script.update.connect(update); \ No newline at end of file From 8684384316aae72442230ff48495ed80b099457d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 24 Oct 2014 16:38:57 -0700 Subject: [PATCH 080/119] Disconnect metavoxel LOD from avatar LOD. --- interface/src/MetavoxelSystem.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 2071ea8c3d..a9bdad8148 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -110,11 +110,9 @@ int SimulateVisitor::visit(MetavoxelInfo& info) { void MetavoxelSystem::simulate(float deltaTime) { // update the lod { - // the LOD threshold is temporarily tied to the avatar LOD parameter QWriteLocker locker(&_lodLock); - const float BASE_LOD_THRESHOLD = 0.01f; - _lod = MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(), - BASE_LOD_THRESHOLD * Menu::getInstance()->getAvatarLODDistanceMultiplier()); + const float DEFAULT_LOD_THRESHOLD = 0.01f; + _lod = MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(), DEFAULT_LOD_THRESHOLD); } SimulateVisitor simulateVisitor(deltaTime, getLOD()); From 54197b2c2304948add3bc17c259473f34284432c Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 24 Oct 2014 17:10:46 -0700 Subject: [PATCH 081/119] fix for spacing --- examples/guidedTour.js | 50 +++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/examples/guidedTour.js b/examples/guidedTour.js index fe31e1db30..3416e55d1c 100644 --- a/examples/guidedTour.js +++ b/examples/guidedTour.js @@ -14,34 +14,34 @@ var LANDING_RANDOM = 0.2; function update(deltaTime) { - if (Math.random() < deltaTime) { - guide = AvatarList.avatarWithDisplayName(leaderName); - if (guide && !isGuide) { - print("found a guide!"); - isGuide = true; - } else if (!isGuide) { - print("Lost My Guide"); - isguide = false; - } + if (Math.random() < deltaTime) { + guide = AvatarList.avatarWithDisplayName(leaderName); + if (guide && !isGuide) { + print("found a guide!"); + isGuide = true; + } else if (!isGuide) { + print("Lost My Guide"); + isguide = false; } + } - if (guide) { - // Check whether guide has moved, update if so - if (Vec3.length(lastGuidePosition) == 0.0) { - lastGuidePosition = guide.position; - } else { - if (Vec3.length(Vec3.subtract(lastGuidePosition, guide.position)) > MIN_CHANGE) { - var meToGuide = Vec3.multiply(Vec3.normalize(Vec3.subtract(guide.position, MyAvatar.position)), LANDING_DISTANCE); - var newPosition = Vec3.subtract(guide.position, meToGuide); - newPosition = Vec3.sum(newPosition, { x: Math.random() * LANDING_RANDOM - LANDING_RANDOM / 2.0, - y: 0, - z: Math.random() * LANDING_RANDOM - LANDING_RANDOM / 2.0 }); - MyAvatar.position = newPosition; + if (guide) { + // Check whether guide has moved, update if so + if (Vec3.length(lastGuidePosition) == 0.0) { + lastGuidePosition = guide.position; + } else { + if (Vec3.length(Vec3.subtract(lastGuidePosition, guide.position)) > MIN_CHANGE) { + var meToGuide = Vec3.multiply(Vec3.normalize(Vec3.subtract(guide.position, MyAvatar.position)), LANDING_DISTANCE); + var newPosition = Vec3.subtract(guide.position, meToGuide); + newPosition = Vec3.sum(newPosition, { x: Math.random() * LANDING_RANDOM - LANDING_RANDOM / 2.0, + y: 0, + z: Math.random() * LANDING_RANDOM - LANDING_RANDOM / 2.0 }); + MyAvatar.position = newPosition; - lastGuidePosition = guide.position; - MyAvatar.orientation = guide.orientation; - } - } + lastGuidePosition = guide.position; + MyAvatar.orientation = guide.orientation; + } } + } } Script.update.connect(update); \ No newline at end of file From 80a87b3b447efff8bdebdb5686c2233b7d1c3167 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Fri, 24 Oct 2014 17:50:31 -0700 Subject: [PATCH 082/119] framerate is as fast as the display can go --- interface/CMakeLists.txt | 2 +- interface/src/Application.cpp | 70 +++++++++++++++++++++++++++-------- interface/src/Application.h | 7 +++- interface/src/Menu.cpp | 47 ++++++++++++++++++++--- interface/src/Menu.h | 12 +++++- interface/src/gpu/Batch.cpp | 3 +- 6 files changed, 114 insertions(+), 27 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index a150a308e0..9c4eeff65b 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -33,7 +33,7 @@ elseif (WIN32) add_definitions(-D_USE_MATH_DEFINES) # apparently needed to get M_PI and other defines from cmath/math.h add_definitions(-DWINDOWS_LEAN_AND_MEAN) # needed to make sure windows doesn't go to crazy with its defines - set(GL_HEADERS "#include \n#include \n#include ") + set(GL_HEADERS "#include \n#include \n#include \n#include ") endif () # set up the external glm library diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1239615b27..bb29bfb244 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -94,10 +94,6 @@ #include "devices/Leapmotion.h" -#ifdef WIN32 -#include -#endif - using namespace std; // Starfield information @@ -183,17 +179,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _trayIcon(new QSystemTrayIcon(_window)), _lastNackTime(usecTimestampNow()), _lastSendDownstreamAudioStats(usecTimestampNow()), - _renderTargetFramerate(60), + _renderTargetFramerate(0), + _isVSyncOn(true), _renderResolutionScale(1.0f) { - - /* QGLFormat trueFormat = _glWidget->format(); - trueFormat.setSwapInterval(0); - _glWidget->setFormat(trueFormat);*/ - int swapInterval = _glWidget->format().swapInterval(); - swapInterval++; - // read the ApplicationInfo.ini file for Name/Version/Domain information QSettings applicationInfo(Application::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); @@ -535,13 +525,18 @@ void Application::initializeGL() { qDebug("Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); if (wglewGetExtension("WGL_EXT_swap_control")) { - wglSwapIntervalEXT(0); int swapInterval = wglGetSwapIntervalEXT(); - swapInterval++; + qDebug("V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF")); } #endif - +#if defined(Q_OS_LINUX) + // TODO: Write the correct code for Linux... + /* if (wglewGetExtension("WGL_EXT_swap_control")) { + int swapInterval = wglGetSwapIntervalEXT(); + qDebug("V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF")); + }*/ +#endif // Before we render anything, let's set up our viewFrustumOffsetCamera with a sufficiently large // field of view and near and far clip to make it interesting. @@ -4168,10 +4163,53 @@ void Application::takeSnapshot() { _snapshotShareDialog->show(); } -void Application::setRenderTargetFramerate(int framerate) { +void Application::setRenderTargetFramerate(unsigned int framerate, bool vsyncOn) { + if (vsyncOn != _isVSyncOn) { +#if defined(Q_OS_WIN) + if (wglewGetExtension("WGL_EXT_swap_control")) { + wglSwapIntervalEXT(vsyncOn); + int swapInterval = wglGetSwapIntervalEXT(); + _isVSyncOn = swapInterval; + qDebug("V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF")); + } else { + qDebug("V-Sync is FORCED ON on this system\n"); + } +#elif defined(Q_OS_LINUX) + // TODO: write the poper code for linux + /* + if (glQueryExtension.... ("GLX_EXT_swap_control")) { + glxSwapIntervalEXT(vsyncOn); + int swapInterval = xglGetSwapIntervalEXT(); + _isVSyncOn = swapInterval; + qDebug("V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF")); + } else { + qDebug("V-Sync is FORCED ON on this system\n"); + } + */ +#else + qDebug("V-Sync is FORCED ON on this system\n"); +#endif + } _renderTargetFramerate = framerate; } +bool Application::isVSyncEditable() { +#if defined(Q_OS_WIN) + if (wglewGetExtension("WGL_EXT_swap_control")) { + return true; + } +#elif defined(Q_OS_LINUX) + // TODO: write the poper code for linux + /* + if (glQueryExtension.... ("GLX_EXT_swap_control")) { + return true; + } + */ +#else +#endif + return false; +} + void Application::setRenderResolutionScale(float scale) { _renderResolutionScale = scale; } diff --git a/interface/src/Application.h b/interface/src/Application.h index 60d19f74be..e85c4f4db5 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -361,7 +361,11 @@ public slots: void domainSettingsReceived(const QJsonObject& domainSettingsObject); - void setRenderTargetFramerate(int framerate); + void setRenderTargetFramerate(unsigned int framerate, bool vsyncOn = true); + bool isVSyncOn() { return _isVSyncOn; } + bool isVSyncEditable(); + unsigned int getRenderTargetFramerate() const { return _renderTargetFramerate; } + void setRenderResolutionScale(float scale); void resetSensors(); @@ -615,6 +619,7 @@ private: quint64 _lastSendDownstreamAudioStats; int _renderTargetFramerate; + bool _isVSyncOn; float _renderResolutionScale; }; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 44afd13bc9..6538aee644 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -373,7 +373,23 @@ Menu::Menu() : shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false)); shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false)); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::RenderUnleashFramerate, 0, false, this, SLOT(toggleUnleashFramerate())); + { + QMenu* framerateMenu = renderOptionsMenu->addMenu(MenuOption::RenderTargetFramerate); + QActionGroup* framerateGroup = new QActionGroup(framerateMenu); + + framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerateUnlimited, 0, true)); + framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerate60, 0, false)); + framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerate50, 0, false)); + framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerate40, 0, false)); + framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerate30, 0, false)); + connect(framerateMenu, SIGNAL(triggered(QAction*)), this, SLOT(changeRenderTargetFramerate(QAction*))); + +#if defined(Q_OS_MAC) +#else + QAction* vsyncAction = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::RenderTargetFramerateVSyncOn, 0, true, this, SLOT(changeVSync())); +#endif + } + QMenu* resolutionMenu = renderOptionsMenu->addMenu(MenuOption::RenderResolution); QActionGroup* resolutionGroup = new QActionGroup(resolutionMenu); @@ -1237,11 +1253,30 @@ void Menu::muteEnvironment() { free(packet); } -void Menu::toggleUnleashFramerate() { - if (isOptionChecked(MenuOption::RenderUnleashFramerate)) { - Application::getInstance()->setRenderTargetFramerate(0); - } else { - Application::getInstance()->setRenderTargetFramerate(-1); +void Menu::changeVSync() { + Application::getInstance()->setRenderTargetFramerate( + Application::getInstance()->getRenderTargetFramerate(), + isOptionChecked(MenuOption::RenderTargetFramerateVSyncOn)); +} +void Menu::changeRenderTargetFramerate(QAction* action) { + bool vsynOn = Application::getInstance()->isVSyncOn(); + unsigned int framerate = Application::getInstance()->getRenderTargetFramerate(); + + QString text = action->text(); + if (text == MenuOption::RenderTargetFramerateUnlimited) { + Application::getInstance()->setRenderTargetFramerate(0, vsynOn); + } + else if (text == MenuOption::RenderTargetFramerate60) { + Application::getInstance()->setRenderTargetFramerate(60, vsynOn); + } + else if (text == MenuOption::RenderTargetFramerate50) { + Application::getInstance()->setRenderTargetFramerate(50, vsynOn); + } + else if (text == MenuOption::RenderTargetFramerate40) { + Application::getInstance()->setRenderTargetFramerate(40, vsynOn); + } + else if (text == MenuOption::RenderTargetFramerate30) { + Application::getInstance()->setRenderTargetFramerate(30, vsynOn); } } diff --git a/interface/src/Menu.h b/interface/src/Menu.h index b9878ec9fa..3c96fd0dcd 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -229,7 +229,8 @@ private slots: void displayAddressOfflineMessage(); void displayAddressNotFoundMessage(); void muteEnvironment(); - void toggleUnleashFramerate(); + void changeRenderTargetFramerate(QAction* action); + void changeVSync(); void changeRenderResolution(QAction* action); private: @@ -453,7 +454,14 @@ namespace MenuOption { const QString RenderHeightfields = "Render Heightfields"; const QString RenderLookAtVectors = "Show Look-at Vectors"; const QString RenderSkeletonCollisionShapes = "Show Skeleton Collision Shapes"; - const QString RenderUnleashFramerate = "Unleash Framerate"; + const QString RenderTargetFramerate = "Framerate"; + const QString RenderTargetFramerateUnlimited = "Unlimited"; + const QString RenderTargetFramerate60 = "60"; + const QString RenderTargetFramerate50 = "50"; + const QString RenderTargetFramerate40 = "40"; + const QString RenderTargetFramerate30 = "30"; + const QString RenderTargetFramerateVSyncOn = "V-Sync On"; + const QString RenderResolution = "Scale Resolution"; const QString RenderResolutionOne = "1"; const QString RenderResolutionTwoThird = "2/3"; diff --git a/interface/src/gpu/Batch.cpp b/interface/src/gpu/Batch.cpp index 8b36ef8b33..054bc09846 100644 --- a/interface/src/gpu/Batch.cpp +++ b/interface/src/gpu/Batch.cpp @@ -17,7 +17,8 @@ //#define DO_IT_NOW(call, offset) runLastCommand(); #define DO_IT_NOW(call, offset) -#define CHECK_GL_ERROR() ::gpu::backend::checkGLError() +//#define CHECK_GL_ERROR() ::gpu::backend::checkGLError() +#define CHECK_GL_ERROR() using namespace gpu; From 8158733a27d5c99ac0666cc5e49596b7f7efe7e6 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 24 Oct 2014 20:21:57 -0700 Subject: [PATCH 083/119] double click to turn around --- examples/headMove.js | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/examples/headMove.js b/examples/headMove.js index b9330153fc..6a020a8c9a 100644 --- a/examples/headMove.js +++ b/examples/headMove.js @@ -43,8 +43,10 @@ var movingWithHead = false; var headStartPosition, headStartDeltaPitch, headStartFinalPitch, headStartRoll, headStartYaw; var deltaYaw = 0.0; var keyDownTime = 0.0; +var timeSinceLastUp = 0.0; var watchAvatar = false; var oldMode; +var lastYawTurned = 0.0; function saveCameraState() { oldMode = Camera.getMode(); @@ -134,7 +136,7 @@ function finishWarp() { } function update(deltaTime) { - + timeSinceLastUp += deltaTime; if (movingWithHead) { keyDownTime += deltaTime; updateWarp(); @@ -156,22 +158,26 @@ Controller.keyPressEvent.connect(function(event) { } }); -var TIME_FOR_TURN_AROUND = 0.50; var TIME_FOR_TURN = 0.25; +var DOUBLE_CLICK_TIME = 0.50; var TURN_AROUND = 180.0; Controller.keyReleaseEvent.connect(function(event) { if (event.text == "SPACE" && !event.isAutoRepeat) { movingWithHead = false; - if (keyDownTime < TIME_FOR_TURN_AROUND) { - if (keyDownTime < TIME_FOR_TURN) { - var currentYaw = MyAvatar.getHeadFinalYaw(); - MyAvatar.orientation = Quat.multiply(Quat.fromPitchYawRollDegrees(0, currentYaw, 0), MyAvatar.orientation); - } else { - MyAvatar.orientation = Quat.multiply(Quat.fromPitchYawRollDegrees(0, TURN_AROUND, 0), MyAvatar.orientation); - } + if (timeSinceLastUp < DOUBLE_CLICK_TIME) { + // Turn all the way around + var turnRemaining = TURN_AROUND - lastYawTurned; + lastYawTurned = 0.0; + MyAvatar.orientation = Quat.multiply(Quat.fromPitchYawRollDegrees(0, TURN_AROUND, 0), MyAvatar.orientation); + playSound(); + } else if (keyDownTime < TIME_FOR_TURN) { + var currentYaw = MyAvatar.getHeadFinalYaw(); + lastYawTurned = currentYaw; + MyAvatar.orientation = Quat.multiply(Quat.fromPitchYawRollDegrees(0, currentYaw, 0), MyAvatar.orientation); playSound(); } + timeSinceLastUp = 0.0; finishWarp(); if (watchAvatar) { restoreCameraState(); From c6463abfb83df2a7473175c7dafe09e9df1ae1ac Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 25 Oct 2014 09:22:30 -0700 Subject: [PATCH 084/119] Prevent keys captured by script from being used as menu shortcuts --- interface/src/Application.cpp | 15 +++++++++++++++ interface/src/Application.h | 1 + 2 files changed, 16 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index da7693ed7a..a91718fa0e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -414,6 +414,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : MIDIManager& midiManagerInstance = MIDIManager::getInstance(); midiManagerInstance.openDefaultPort(); #endif + + this->installEventFilter(this); } Application::~Application() { @@ -836,6 +838,19 @@ bool Application::event(QEvent* event) { return QApplication::event(event); } +bool Application::eventFilter(QObject* object, QEvent* event) { + + if (event->type() == QEvent::ShortcutOverride) { + // Filter out captured keys before they're used for shortcut actions. + if (_controllerScriptingInterface.isKeyCaptured(static_cast(event))) { + event->accept(); + return true; + } + } + + return false; +} + void Application::keyPressEvent(QKeyEvent* event) { _keysPressed.insert(event->key()); diff --git a/interface/src/Application.h b/interface/src/Application.h index e85c4f4db5..feb9ee8fc3 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -172,6 +172,7 @@ public: void dropEvent(QDropEvent *event); bool event(QEvent* event); + bool eventFilter(QObject* object, QEvent* event); void makeVoxel(glm::vec3 position, float scale, From 0fdcf381fa04e6934b540b7eb3710b63e44ed71d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 25 Oct 2014 09:23:37 -0700 Subject: [PATCH 085/119] Code tidy --- interface/src/scripting/ControllerScriptingInterface.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index f2e65a6e28..1ca99ed2c5 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -213,10 +213,7 @@ bool ControllerScriptingInterface::isKeyCaptured(QKeyEvent* event) const { bool ControllerScriptingInterface::isKeyCaptured(const KeyEvent& event) const { // if we've captured some combination of this key it will be in the map - if (_capturedKeys.contains(event.key, event)) { - return true; - } - return false; + return _capturedKeys.contains(event.key, event); } void ControllerScriptingInterface::captureKeyEvents(const KeyEvent& event) { From 8d97a20bd984a72a01a74050b44e1a1936b2f968 Mon Sep 17 00:00:00 2001 From: Pete Date: Sun, 26 Oct 2014 21:14:20 -0700 Subject: [PATCH 086/119] Worklist #20074 - Add new Preferences item for Oculus Max FPS, defaults to 75, range is [30, 95] - Load and save this value appropriately - When VR mode is enabled/disabled, set the Render Target Framerate to this value/unlimited --- interface/src/Application.cpp | 3 + interface/src/Menu.cpp | 6 ++ interface/src/Menu.h | 3 + interface/src/devices/OculusManager.h | 1 + interface/src/ui/PreferencesDialog.cpp | 4 + interface/ui/preferencesDialog.ui | 113 +++++++++++++++++++++---- 6 files changed, 113 insertions(+), 17 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bb29bfb244..5b93636e93 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1494,9 +1494,12 @@ void Application::setEnableVRMode(bool enableVRMode) { OculusManager::disconnect(); OculusManager::connect(); } + int oculusMaxFPS = Menu::getInstance()->getOculusUIMaxFPS(); + setRenderTargetFramerate(oculusMaxFPS); OculusManager::recalibrate(); } else { OculusManager::abandonCalibration(); + setRenderTargetFramerate(0); } resizeGL(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight()); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 6538aee644..274afd4bca 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -105,6 +105,7 @@ Menu::Menu() : _maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM), _voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE), _oculusUIAngularSize(DEFAULT_OCULUS_UI_ANGULAR_SIZE), + _oculusUIMaxFPS(DEFAULT_OCULUS_UI_MAX_FPS), _sixenseReticleMoveSpeed(DEFAULT_SIXENSE_RETICLE_MOVE_SPEED), _invertSixenseButtons(DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS), _automaticAvatarLOD(true), @@ -782,6 +783,8 @@ void Menu::loadSettings(QSettings* settings) { settings->endGroup(); _walletPrivateKey = settings->value("privateKey").toByteArray(); + + _oculusUIMaxFPS = loadSetting(settings, "oculusUIMaxFPS", 0.0f); scanMenuBar(&loadAction, settings); Application::getInstance()->getAvatar()->loadData(settings); @@ -843,6 +846,9 @@ void Menu::saveSettings(QSettings* settings) { settings->setValue("viewFrustumOffsetUp", _viewFrustumOffset.up); settings->endGroup(); settings->setValue("privateKey", _walletPrivateKey); + + // Oculus Rift settings + settings->setValue("oculusUIMaxFPS", _oculusUIMaxFPS); scanMenuBar(&saveAction, settings); Application::getInstance()->getAvatar()->saveData(settings); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 3c96fd0dcd..abcbfb51ad 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -100,6 +100,8 @@ public: void setRealWorldFieldOfView(float realWorldFieldOfView) { _realWorldFieldOfView = realWorldFieldOfView; bumpSettings(); } float getOculusUIAngularSize() const { return _oculusUIAngularSize; } void setOculusUIAngularSize(float oculusUIAngularSize) { _oculusUIAngularSize = oculusUIAngularSize; bumpSettings(); } + int getOculusUIMaxFPS() const { return _oculusUIMaxFPS; } + void setOculusUIMaxFPS(int oculusUIMaxFPS) { _oculusUIMaxFPS = oculusUIMaxFPS; bumpSettings(); } float getSixenseReticleMoveSpeed() const { return _sixenseReticleMoveSpeed; } void setSixenseReticleMoveSpeed(float sixenseReticleMoveSpeed) { _sixenseReticleMoveSpeed = sixenseReticleMoveSpeed; bumpSettings(); } bool getInvertSixenseButtons() const { return _invertSixenseButtons; } @@ -292,6 +294,7 @@ private: int _maxVoxels; float _voxelSizeScale; float _oculusUIAngularSize; + int _oculusUIMaxFPS; float _sixenseReticleMoveSpeed; bool _invertSixenseButtons; bool _automaticAvatarLOD; diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index 20e43d572c..94521dc927 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -21,6 +21,7 @@ #include "ui/overlays/Text3DOverlay.h" const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f; +const int DEFAULT_OCULUS_UI_MAX_FPS = 75; class Camera; class PalmData; diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 61cc9718b3..42256bc498 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -147,6 +147,8 @@ void PreferencesDialog::loadPreferences() { ui.maxVoxelsPPSSpin->setValue(menuInstance->getMaxVoxelPacketsPerSecond()); ui.oculusUIAngularSizeSpin->setValue(menuInstance->getOculusUIAngularSize()); + + ui.oculusUIMaxFPSSpin->setValue(menuInstance->getOculusUIMaxFPS()); ui.sixenseReticleMoveSpeedSpin->setValue(menuInstance->getSixenseReticleMoveSpeed()); @@ -229,6 +231,8 @@ void PreferencesDialog::savePreferences() { Menu::getInstance()->setMaxVoxelPacketsPerSecond(ui.maxVoxelsPPSSpin->value()); Menu::getInstance()->setOculusUIAngularSize(ui.oculusUIAngularSizeSpin->value()); + + Menu::getInstance()->setOculusUIMaxFPS(ui.oculusUIMaxFPSSpin->value()); Menu::getInstance()->setSixenseReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value()); diff --git a/interface/ui/preferencesDialog.ui b/interface/ui/preferencesDialog.ui index 0108437c1f..2dda1a24b1 100644 --- a/interface/ui/preferencesDialog.ui +++ b/interface/ui/preferencesDialog.ui @@ -61,7 +61,7 @@ 0 0 500 - 1386 + 1459 @@ -1772,24 +1772,24 @@ - - - Arial - - - - Qt::LeftToRight - - - - - - localhost - - + + + Arial + + + + Qt::LeftToRight + + + + + + localhost + + - + @@ -2084,6 +2084,85 @@ + + + + 0 + + + 7 + + + 0 + + + 7 + + + + + + Arial + + + + Oculus Rift FPS + + + 0 + + + maxVoxelsSpin + + + + + + + + Arial + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 100 + 0 + + + + + Arial + + + + 30 + + + 95 + + + 1 + + + 75 + + + + + From fde85bb4d28994cc99fe8f3ee6b01281f3c65fca Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Sun, 26 Oct 2014 21:18:54 -0700 Subject: [PATCH 087/119] don't spam --- examples/guidedTour.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/guidedTour.js b/examples/guidedTour.js index 3416e55d1c..1882b527d7 100644 --- a/examples/guidedTour.js +++ b/examples/guidedTour.js @@ -17,9 +17,9 @@ function update(deltaTime) { if (Math.random() < deltaTime) { guide = AvatarList.avatarWithDisplayName(leaderName); if (guide && !isGuide) { - print("found a guide!"); + print("Found a tour guide!"); isGuide = true; - } else if (!isGuide) { + } else if (!guide && isGuide) { print("Lost My Guide"); isguide = false; } From 4b7eb682b3ea69eb55a9687371cb475a38146834 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 27 Oct 2014 08:44:45 -0700 Subject: [PATCH 088/119] Easier to get out of body and move from there with target --- examples/headMove.js | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/examples/headMove.js b/examples/headMove.js index 6a020a8c9a..f377409cb8 100644 --- a/examples/headMove.js +++ b/examples/headMove.js @@ -17,6 +17,8 @@ var willMove = false; var warpActive = false; var warpPosition = { x: 0, y: 0, z: 0 }; +var hipsToEyes; + // Overlays to show target location var WARP_SPHERE_SIZE = 0.15; @@ -47,6 +49,7 @@ var timeSinceLastUp = 0.0; var watchAvatar = false; var oldMode; var lastYawTurned = 0.0; +var startPullbackPosition; function saveCameraState() { oldMode = Camera.getMode(); @@ -67,6 +70,7 @@ function activateWarp() { var TRIGGER_PULLBACK_DISTANCE = 0.04; var WATCH_AVATAR_DISTANCE = 1.5; var MAX_PULLBACK_YAW = 5.0; +var MAX_PULLBACK_PITCH = 5.0; var sound = new Sound("http://public.highfidelity.io/sounds/Footsteps/FootstepW2Right-12db.wav"); function playSound() { @@ -76,35 +80,44 @@ function playSound() { options.volume = 1.0; Audio.playSound(sound, options); } - var WARP_SMOOTHING = 0.90; var WARP_START_TIME = 0.50; -var WARP_START_DISTANCE = 1.0; +var WARP_START_DISTANCE = 1.5; var WARP_SENSITIVITY = 0.15; +var fixedHeight = true; + function updateWarp() { if (!warpActive) return; - var look = Quat.getFront(Camera.getOrientation()); + var viewEulers = Quat.safeEulerAngles(Camera.getOrientation()); var deltaPosition = Vec3.subtract(MyAvatar.getTrackedHeadPosition(), headStartPosition); var deltaPitch = MyAvatar.getHeadFinalPitch() - headStartFinalPitch; deltaYaw = MyAvatar.getHeadFinalYaw() - headStartYaw; + viewEulers.x -= deltaPitch; + var look = Quat.getFront(Quat.fromVec3Degrees(viewEulers)); - willMove = (!watchAvatar && (keyDownTime > WARP_START_TIME)); + willMove = (keyDownTime > WARP_START_TIME); if (willMove) { - //var distance = Math.pow((deltaPitch - WARP_PITCH_DEAD_ZONE) * WARP_SENSITIVITY, 2.0); var distance = Math.exp(deltaPitch * WARP_SENSITIVITY) * WARP_START_DISTANCE; - var warpDirection = Vec3.normalize({ x: look.x, y: 0, z: look.z }); - warpPosition = Vec3.mix(Vec3.sum(MyAvatar.position, Vec3.multiply(warpDirection, distance)), warpPosition, WARP_SMOOTHING); + var warpDirection = Vec3.normalize({ x: look.x, y: (fixedHeight ? 0 : look.y), z: look.z }); + var startPosition = (watchAvatar ? Camera.getPosition(): MyAvatar.getEyePosition()); + warpPosition = Vec3.mix(Vec3.sum(startPosition, Vec3.multiply(warpDirection, distance)), warpPosition, WARP_SMOOTHING); } var height = MyAvatar.getEyePosition().y - MyAvatar.position.y; + var cameraPosition; - if (!watchAvatar && (Math.abs(deltaYaw) < MAX_PULLBACK_YAW) && (deltaPosition.z > TRIGGER_PULLBACK_DISTANCE)) { + if (!watchAvatar && + (Math.abs(deltaYaw) < MAX_PULLBACK_YAW) && + (Math.abs(deltaPitch) < MAX_PULLBACK_PITCH) && + (Vec3.length(deltaPosition) > TRIGGER_PULLBACK_DISTANCE)) { saveCameraState(); - var cameraPosition = Vec3.subtract(MyAvatar.position, Vec3.multiplyQbyV(Camera.getOrientation(), { x: 0, y: -height, z: -height * WATCH_AVATAR_DISTANCE })); + cameraPosition = Vec3.subtract(MyAvatar.position, Vec3.multiplyQbyV(Camera.getOrientation(), { x: 0, y: -height, z: -height * WATCH_AVATAR_DISTANCE })); Camera.setPosition(cameraPosition); + cameraPosition = Camera.getPosition(); + startPullbackPosition = cameraPosition; watchAvatar = true; } @@ -130,6 +143,7 @@ function finishWarp() { visible: false, }); if (willMove) { + warpPosition.y -= hipsToEyes; MyAvatar.position = warpPosition; playSound(); } @@ -147,6 +161,7 @@ Controller.keyPressEvent.connect(function(event) { if (event.text == "SPACE" && !event.isAutoRepeat && !movingWithHead) { keyDownTime = 0.0; movingWithHead = true; + hipsToEyes = MyAvatar.getEyePosition().y - MyAvatar.position.y; headStartPosition = MyAvatar.getTrackedHeadPosition(); headStartDeltaPitch = MyAvatar.getHeadDeltaPitch(); headStartFinalPitch = MyAvatar.getHeadFinalPitch(); @@ -154,6 +169,7 @@ Controller.keyPressEvent.connect(function(event) { headStartYaw = MyAvatar.getHeadFinalYaw(); deltaYaw = 0.0; warpPosition = MyAvatar.position; + warpPosition.y += hipsToEyes; activateWarp(); } }); From f25cfc0c7f3f81ce889f889932b509b694e6c4c5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 27 Oct 2014 10:22:40 -0700 Subject: [PATCH 089/119] remove debug code --- interface/src/avatar/Avatar.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index d21bdcfd4d..3fcc05d7c7 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -24,7 +24,6 @@ #include #include #include -#include // adebug #include "Application.h" #include "Avatar.h" @@ -773,7 +772,6 @@ void Avatar::setSkeletonOffset(const glm::vec3& offset) { } else { _skeletonOffset = offset; } - std::cout << "adebug set offset = " << offset << std::endl; // adebug } glm::vec3 Avatar::getSkeletonPosition() const { From b7ebc9e902a238a9ac810f94ec6ee63e822ceb6b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 10:51:48 -0700 Subject: [PATCH 090/119] add a class for custom HFActionEvent --- interface/src/HFActionEvent.cpp | 26 ++++++++++++++++++++++++++ interface/src/HFActionEvent.h | 24 ++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 interface/src/HFActionEvent.cpp create mode 100644 interface/src/HFActionEvent.h diff --git a/interface/src/HFActionEvent.cpp b/interface/src/HFActionEvent.cpp new file mode 100644 index 0000000000..dfa08a94c5 --- /dev/null +++ b/interface/src/HFActionEvent.cpp @@ -0,0 +1,26 @@ +// +// HFActionEvent.cpp +// interface/src +// +// Created by Stephen Birarda on 2014-10-27. +// 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 "HFActionEvent.h" + +HFActionEvent::HFActionEvent() : + QEvent(HFActionEvent::type()) +{ + +} + +QEvent::Type HFActionEvent::type() { + static QEvent::Type hfActionType = QEvent::None; + if (hfActionType == QEvent::None) { + hfActionType = static_cast(QEvent::registerEventType()); + } + return hfActionType; +} \ No newline at end of file diff --git a/interface/src/HFActionEvent.h b/interface/src/HFActionEvent.h new file mode 100644 index 0000000000..68bef6ca50 --- /dev/null +++ b/interface/src/HFActionEvent.h @@ -0,0 +1,24 @@ +// +// HFActionEvent.h +// interface/src +// +// Created by Stephen Birarda on 2014-10-27. +// 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_HFActionEvent_h +#define hifi_HFActionEvent_h + +#include + +class HFActionEvent : public QEvent { +public: + HFActionEvent(); + + static QEvent::Type type(); +}; + +#endif // hifi_HFActionEvent_h \ No newline at end of file From d09c9233d8b4d859992baa07c16d9e376e860fea Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 10:55:16 -0700 Subject: [PATCH 091/119] add position to HFActionEvent --- interface/src/HFActionEvent.cpp | 5 +++-- interface/src/HFActionEvent.h | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/interface/src/HFActionEvent.cpp b/interface/src/HFActionEvent.cpp index dfa08a94c5..6f98e2963f 100644 --- a/interface/src/HFActionEvent.cpp +++ b/interface/src/HFActionEvent.cpp @@ -11,8 +11,9 @@ #include "HFActionEvent.h" -HFActionEvent::HFActionEvent() : - QEvent(HFActionEvent::type()) +HFActionEvent::HFActionEvent(const QPointF& localPosition) : + QEvent(HFActionEvent::type()), + _localPosition(localPosition) { } diff --git a/interface/src/HFActionEvent.h b/interface/src/HFActionEvent.h index 68bef6ca50..19b6dc8469 100644 --- a/interface/src/HFActionEvent.h +++ b/interface/src/HFActionEvent.h @@ -16,9 +16,11 @@ class HFActionEvent : public QEvent { public: - HFActionEvent(); + HFActionEvent(const QPointF& localPosition); static QEvent::Type type(); +private: + QPointF _localPosition; }; #endif // hifi_HFActionEvent_h \ No newline at end of file From 55735a3f0dab52c233c4c5a9eb9d9ac08e96613a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 11:11:23 -0700 Subject: [PATCH 092/119] add start and end to HFActionEvent --- interface/src/HFActionEvent.cpp | 21 ++++++++++++--------- interface/src/HFActionEvent.h | 5 +++-- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/interface/src/HFActionEvent.cpp b/interface/src/HFActionEvent.cpp index 6f98e2963f..2ab2001ba4 100644 --- a/interface/src/HFActionEvent.cpp +++ b/interface/src/HFActionEvent.cpp @@ -11,17 +11,20 @@ #include "HFActionEvent.h" -HFActionEvent::HFActionEvent(const QPointF& localPosition) : - QEvent(HFActionEvent::type()), +HFActionEvent::HFActionEvent(QEvent::Type type, const QPointF& localPosition) : + QEvent(type), _localPosition(localPosition) { } -QEvent::Type HFActionEvent::type() { - static QEvent::Type hfActionType = QEvent::None; - if (hfActionType == QEvent::None) { - hfActionType = static_cast(QEvent::registerEventType()); - } - return hfActionType; -} \ No newline at end of file +QEvent::Type HFActionEvent::startType() { + static QEvent::Type startType = static_cast(QEvent::registerEventType()); + return startType; +} + +QEvent::Type HFActionEvent::endType() { + static QEvent::Type endType = static_cast(QEvent::registerEventType()); + return endType; +} + diff --git a/interface/src/HFActionEvent.h b/interface/src/HFActionEvent.h index 19b6dc8469..2c7d323dc9 100644 --- a/interface/src/HFActionEvent.h +++ b/interface/src/HFActionEvent.h @@ -16,9 +16,10 @@ class HFActionEvent : public QEvent { public: - HFActionEvent(const QPointF& localPosition); + HFActionEvent(QEvent::Type type, const QPointF& localPosition); - static QEvent::Type type(); + static QEvent::Type startType(); + static QEvent::Type endType(); private: QPointF _localPosition; }; From 6626787ae59bd9082842d96769a7a43915a8e340 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 11:40:33 -0700 Subject: [PATCH 093/119] have mouse press/release fire HFActionEvent --- interface/src/Application.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index da7693ed7a..22371ce7d0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -67,14 +67,17 @@ #include #include "Application.h" -#include "ui/DataWebDialog.h" +#include "HFActionEvent.h" #include "InterfaceVersion.h" #include "Menu.h" #include "ModelUploader.h" #include "Util.h" + +#include "devices/Leapmotion.h" #include "devices/MIDIManager.h" #include "devices/OculusManager.h" #include "devices/TV3DManager.h" + #include "renderer/ProgramObject.h" #include "scripting/AccountScriptingInterface.h" @@ -87,12 +90,12 @@ #include "scripting/SettingsScriptingInterface.h" #include "scripting/WindowScriptingInterface.h" +#include "ui/DataWebDialog.h" #include "ui/InfoView.h" #include "ui/Snapshot.h" #include "ui/Stats.h" #include "ui/TextRenderer.h" -#include "devices/Leapmotion.h" using namespace std; @@ -1239,6 +1242,10 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { // stop propagation return; } + + // nobody handled this - make it an action event on the _window object + HFActionEvent actionEvent(HFActionEvent::startType(), event->localPos()); + sendEvent(_window, &actionEvent); } else if (event->button() == Qt::RightButton) { // right click items here @@ -1259,12 +1266,17 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { _mouseX = event->x(); _mouseY = event->y(); _mousePressed = false; + checkBandwidthMeterClick(); if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { // let's set horizontal offset to give stats some margin to mirror int horizontalOffset = MIRROR_VIEW_WIDTH; Stats::getInstance()->checkClick(_mouseX, _mouseY, _mouseDragStartedX, _mouseDragStartedY, horizontalOffset); } + + // fire an action end event + HFActionEvent actionEvent(HFActionEvent::endType(), event->localPos()); + sendEvent(_window, &actionEvent); } } } From ff44a460d66270d42db2191f2202c6ec9384de62 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 27 Oct 2014 11:40:52 -0700 Subject: [PATCH 094/119] Add NSIGHT Profiliing capability --- interface/CMakeLists.txt | 12 +++++++++--- interface/src/gpu/Batch.h | 17 +++++++++++++++++ interface/src/renderer/Model.cpp | 9 +++++++-- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 9c4eeff65b..194558e580 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -226,11 +226,17 @@ else (APPLE) if (WIN32) find_package(GLEW REQUIRED) include_directories(${GLEW_INCLUDE_DIRS}) - + # we're using static GLEW, so define GLEW_STATIC add_definitions(-DGLEW_STATIC) - - target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" wsock32.lib opengl32.lib) + + find_package(NSIGHT) + if (NSIGHT_FOUND) + include_directories(${NSIGHT_INCLUDE_DIRS}) + add_definitions(-DNSIGHT_FOUND) + endif () + + target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" "${NSIGHT_LIBRARIES}" wsock32.lib opengl32.lib) endif() endif (APPLE) diff --git a/interface/src/gpu/Batch.h b/interface/src/gpu/Batch.h index ad5246f9b6..cceb41be76 100644 --- a/interface/src/gpu/Batch.h +++ b/interface/src/gpu/Batch.h @@ -16,6 +16,23 @@ #include +#if defined(NSIGHT_FOUND) + #include "nvToolsExt.h" + class ProfileRange { + public: + ProfileRange(const char *name) { + nvtxRangePush(name); + } + ~ProfileRange() { + nvtxRangePop(); + } + }; + + #define PROFILE_SCOPE(name) ProfileRange profileRangeThis(name); +#else + #define PROFILE_SCOPE(name) +#endif + namespace gpu { class Batch; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 131c600dc1..c2893c79ce 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -395,6 +395,7 @@ void Model::setJointStates(QVector states) { } bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { + PROFILE_SCOPE(__FUNCTION__); // render the attachments foreach (Model* attachment, _attachments) { attachment->render(alpha, mode); @@ -560,8 +561,11 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0); // Render! - ::gpu::backend::renderBatch(batch); - batch.clear(); + { + PROFILE_SCOPE("render Batch"); + ::gpu::backend::renderBatch(batch); + batch.clear(); + } // restore all the default material settings Application::getInstance()->setupWorldLight(); @@ -1551,6 +1555,7 @@ void Model::segregateMeshGroups() { int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args) { + PROFILE_SCOPE(__FUNCTION__); bool dontCullOutOfViewMeshParts = Menu::getInstance()->isOptionChecked(MenuOption::DontCullOutOfViewMeshParts); bool cullTooSmallMeshParts = !Menu::getInstance()->isOptionChecked(MenuOption::DontCullTooSmallMeshParts); bool dontReduceMaterialSwitches = Menu::getInstance()->isOptionChecked(MenuOption::DontReduceMaterialSwitches); From 541e528e57c234e8c6a80de23ac26de411b87013 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 27 Oct 2014 11:41:39 -0700 Subject: [PATCH 095/119] Add NSIGHT Profiliing capability --- cmake/modules/FindNSIGHT.cmake | 49 ++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 cmake/modules/FindNSIGHT.cmake diff --git a/cmake/modules/FindNSIGHT.cmake b/cmake/modules/FindNSIGHT.cmake new file mode 100644 index 0000000000..4df0686ebe --- /dev/null +++ b/cmake/modules/FindNSIGHT.cmake @@ -0,0 +1,49 @@ +# +# FindNSIGHT.cmake +# +# Try to find NSIGHT NvToolsExt library and include path. +# Once done this will define +# +# NSIGHT_FOUND +# NSIGHT_INCLUDE_DIRS +# NSIGHT_LIBRARIES +# +# Created on 10/27/2014 by Sam Gateau +# 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 +# + +if (WIN32) + + find_path(NSIGHT_INCLUDE_DIRS + NAMES + nvToolsExt.h + PATH_SUFFIXES + include + PATHS + "C:/Program Files/NVIDIA Corporation/NvToolsExt") + + find_library(NSIGHT_LIBRARY_RELEASE nvToolsExt32_1 + PATH_SUFFIXES + "lib/Win32" "lib" + PATHS + "C:/Program Files/NVIDIA Corporation/NvToolsExt") + find_library(NSIGHT_LIBRARY_DEBUG nvToolsExt32_1 + PATH_SUFFIXES + "lib/Win32" "lib" + PATHS + "C:/Program Files/NVIDIA Corporation/NvToolsExt") + + include(SelectLibraryConfigurations) + select_library_configurations(NSIGHT) +endif () + +set(NSIGHT_LIBRARIES "${NSIGHT_LIBRARY}") + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(NSIGHT DEFAULT_MSG NSIGHT_INCLUDE_DIRS NSIGHT_LIBRARIES) + +mark_as_advanced(NSIGHT_INCLUDE_DIRS NSIGHT_LIBRARIES NSIGHT_SEARCH_DIRS) + From 89f9e5b01bd64ff69649e0d3ec735ac17e6ec1fe Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 27 Oct 2014 11:49:51 -0700 Subject: [PATCH 096/119] try to get more coherent names --- interface/src/gpu/Batch.h | 4 ++-- interface/src/renderer/Model.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/interface/src/gpu/Batch.h b/interface/src/gpu/Batch.h index cceb41be76..b0bf30bae5 100644 --- a/interface/src/gpu/Batch.h +++ b/interface/src/gpu/Batch.h @@ -28,9 +28,9 @@ } }; - #define PROFILE_SCOPE(name) ProfileRange profileRangeThis(name); + #define PROFILE_RANGE(name) ProfileRange profileRangeThis(name); #else - #define PROFILE_SCOPE(name) +#define PROFILE_RANGE(name) #endif namespace gpu { diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index c2893c79ce..e949e9a811 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -395,7 +395,7 @@ void Model::setJointStates(QVector states) { } bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { - PROFILE_SCOPE(__FUNCTION__); + PROFILE_RANGE(__FUNCTION__); // render the attachments foreach (Model* attachment, _attachments) { attachment->render(alpha, mode); @@ -562,7 +562,7 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { // Render! { - PROFILE_SCOPE("render Batch"); + PROFILE_RANGE("render Batch"); ::gpu::backend::renderBatch(batch); batch.clear(); } @@ -1555,7 +1555,7 @@ void Model::segregateMeshGroups() { int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args) { - PROFILE_SCOPE(__FUNCTION__); + PROFILE_RANGE(__FUNCTION__); bool dontCullOutOfViewMeshParts = Menu::getInstance()->isOptionChecked(MenuOption::DontCullOutOfViewMeshParts); bool cullTooSmallMeshParts = !Menu::getInstance()->isOptionChecked(MenuOption::DontCullTooSmallMeshParts); bool dontReduceMaterialSwitches = Menu::getInstance()->isOptionChecked(MenuOption::DontReduceMaterialSwitches); From 5af52df55823cf3332895bad6e62000098ce9b10 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 27 Oct 2014 12:11:07 -0700 Subject: [PATCH 097/119] Put some debugging in to track down a streaming crash. --- assignment-client/src/metavoxels/MetavoxelServer.cpp | 5 +++++ libraries/metavoxels/src/MetavoxelClientManager.cpp | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index 81e86dbf11..43fd5f5c16 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -223,7 +223,11 @@ void MetavoxelSession::update() { _sender->getData().writeDelta(sendRecord->getData(), sendRecord->getLOD(), out, _lod); out.flush(); int end = _sequencer.getOutputStream().getUnderlying().device()->pos(); + QDebug debug = qDebug() << "from" << sendRecord->getLOD().position.x << sendRecord->getLOD().position.y << sendRecord->getLOD().position.z << "to" << + _lod.position.x << _lod.position.y << _lod.position.z << _lodPacketNumber << (_sequencer.getOutgoingPacketNumber() + 1); if (end > _sequencer.getMaxPacketSize()) { + debug << "reliable" << (_reliableDeltaID + 1); + // we need to send the delta on the reliable channel _reliableDeltaChannel = _sequencer.getReliableOutputChannel(RELIABLE_DELTA_CHANNEL_INDEX); _reliableDeltaChannel->startMessage(); @@ -242,6 +246,7 @@ void MetavoxelSession::update() { _sequencer.endPacket(); } else { + debug << "unreliable"; _sequencer.endPacket(); } diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index cc5d7ef29d..af83fdc869 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -297,7 +297,10 @@ void MetavoxelClient::writeUpdateMessage(Bitstream& out) { void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { int userType = message.userType(); if (userType == MetavoxelDeltaMessage::Type) { - if (_reliableDeltaChannel) { + if (_reliableDeltaChannel) { + qDebug() << "from" << _remoteDataLOD.position.x << _remoteDataLOD.position.y << _remoteDataLOD.position.z << + "to" << _reliableDeltaLOD.position.x << _reliableDeltaLOD.position.y << _reliableDeltaLOD.position.z << + _sequencer.getIncomingPacketNumber() << "reliable" << _reliableDeltaID; MetavoxelData reference = _remoteData; MetavoxelLOD referenceLOD = _remoteDataLOD; _remoteData.readDelta(reference, referenceLOD, in, _remoteDataLOD = _reliableDeltaLOD); @@ -307,6 +310,9 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { } else { PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord(); + qDebug() << "from" << receiveRecord->getLOD().position.x << receiveRecord->getLOD().position.y << receiveRecord->getLOD().position.z << + "to" << getLastAcknowledgedSendRecord()->getLOD().position.x << getLastAcknowledgedSendRecord()->getLOD().position.y << getLastAcknowledgedSendRecord()->getLOD().position.z << + _sequencer.getIncomingPacketNumber() << "unreliable"; _remoteData.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, _remoteDataLOD = getLastAcknowledgedSendRecord()->getLOD()); in.reset(); From 0ddf665b86d4e6f6481817b7dd4a4bd83e218e5b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 12:56:48 -0700 Subject: [PATCH 098/119] add an HFMetaEvent class as super class for meta events --- interface/CMakeLists.txt | 2 +- interface/src/Application.cpp | 13 +++++----- interface/src/{ => events}/HFActionEvent.cpp | 8 +++--- interface/src/{ => events}/HFActionEvent.h | 6 ++--- interface/src/events/HFMetaEvent.cpp | 20 +++++++++++++++ interface/src/events/HFMetaEvent.h | 27 ++++++++++++++++++++ 6 files changed, 62 insertions(+), 14 deletions(-) rename interface/src/{ => events}/HFActionEvent.cpp (71%) rename interface/src/{ => events}/HFActionEvent.h (85%) create mode 100644 interface/src/events/HFMetaEvent.cpp create mode 100644 interface/src/events/HFMetaEvent.h diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 9c4eeff65b..0867f15ac8 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -45,7 +45,7 @@ configure_file(InterfaceVersion.h.in "${PROJECT_BINARY_DIR}/includes/InterfaceVe # grab the implementation and header files from src dirs file(GLOB INTERFACE_SRCS src/*.cpp src/*.h) -foreach(SUBDIR avatar devices renderer ui starfield location scripting voxels particles entities gpu) +foreach(SUBDIR avatar devices events renderer ui starfield location scripting voxels particles entities gpu) file(GLOB_RECURSE SUBDIR_SRCS src/${SUBDIR}/*.cpp src/${SUBDIR}/*.h) set(INTERFACE_SRCS ${INTERFACE_SRCS} "${SUBDIR_SRCS}") endforeach(SUBDIR) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 22371ce7d0..91ff7c3563 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -67,7 +67,6 @@ #include #include "Application.h" -#include "HFActionEvent.h" #include "InterfaceVersion.h" #include "Menu.h" #include "ModelUploader.h" @@ -78,6 +77,8 @@ #include "devices/OculusManager.h" #include "devices/TV3DManager.h" +#include "events/HFActionEvent.h" + #include "renderer/ProgramObject.h" #include "scripting/AccountScriptingInterface.h" @@ -139,6 +140,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _glWidget(new GLCanvas()), _nodeThread(new QThread(this)), _datagramProcessor(), + _undoStack(), + _undoStackScriptingInterface(&_undoStack), _frameCount(0), _fps(60.0f), _justStarted(true), @@ -175,8 +178,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _nodeBoundsDisplay(this), _previousScriptLocation(), _applicationOverlay(), - _undoStack(), - _undoStackScriptingInterface(&_undoStack), _runningScriptsWidget(NULL), _runningScriptsWidgetWasVisible(false), _trayIcon(new QSystemTrayIcon(_window)), @@ -835,7 +836,7 @@ bool Application::event(QEvent* event) { return false; } - + return QApplication::event(event); } @@ -1245,7 +1246,7 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { // nobody handled this - make it an action event on the _window object HFActionEvent actionEvent(HFActionEvent::startType(), event->localPos()); - sendEvent(_window, &actionEvent); + sendEvent(this, &actionEvent); } else if (event->button() == Qt::RightButton) { // right click items here @@ -1276,7 +1277,7 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { // fire an action end event HFActionEvent actionEvent(HFActionEvent::endType(), event->localPos()); - sendEvent(_window, &actionEvent); + sendEvent(this, &actionEvent); } } } diff --git a/interface/src/HFActionEvent.cpp b/interface/src/events/HFActionEvent.cpp similarity index 71% rename from interface/src/HFActionEvent.cpp rename to interface/src/events/HFActionEvent.cpp index 2ab2001ba4..e393a2f332 100644 --- a/interface/src/HFActionEvent.cpp +++ b/interface/src/events/HFActionEvent.cpp @@ -1,6 +1,6 @@ // // HFActionEvent.cpp -// interface/src +// interface/src/events // // Created by Stephen Birarda on 2014-10-27. // Copyright 2014 High Fidelity, Inc. @@ -12,19 +12,19 @@ #include "HFActionEvent.h" HFActionEvent::HFActionEvent(QEvent::Type type, const QPointF& localPosition) : - QEvent(type), + HFMetaEvent(type), _localPosition(localPosition) { } QEvent::Type HFActionEvent::startType() { - static QEvent::Type startType = static_cast(QEvent::registerEventType()); + static QEvent::Type startType = HFMetaEvent::newEventType(); return startType; } QEvent::Type HFActionEvent::endType() { - static QEvent::Type endType = static_cast(QEvent::registerEventType()); + static QEvent::Type endType = HFMetaEvent::newEventType(); return endType; } diff --git a/interface/src/HFActionEvent.h b/interface/src/events/HFActionEvent.h similarity index 85% rename from interface/src/HFActionEvent.h rename to interface/src/events/HFActionEvent.h index 2c7d323dc9..3371312755 100644 --- a/interface/src/HFActionEvent.h +++ b/interface/src/events/HFActionEvent.h @@ -1,6 +1,6 @@ // // HFActionEvent.h -// interface/src +// interface/src/events // // Created by Stephen Birarda on 2014-10-27. // Copyright 2014 High Fidelity, Inc. @@ -12,9 +12,9 @@ #ifndef hifi_HFActionEvent_h #define hifi_HFActionEvent_h -#include +#include "HFMetaEvent.h" -class HFActionEvent : public QEvent { +class HFActionEvent : public HFMetaEvent { public: HFActionEvent(QEvent::Type type, const QPointF& localPosition); diff --git a/interface/src/events/HFMetaEvent.cpp b/interface/src/events/HFMetaEvent.cpp new file mode 100644 index 0000000000..c9d77868cd --- /dev/null +++ b/interface/src/events/HFMetaEvent.cpp @@ -0,0 +1,20 @@ +// +// HFMetaEvent.cpp +// interface/src/events +// +// Created by Stephen Birarda on 2014-10-27. +// 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 "HFMetaEvent.h" + +QSet HFMetaEvent::_types = QSet(); + +QEvent::Type HFMetaEvent::newEventType() { + QEvent::Type newType = static_cast(QEvent::registerEventType()); + _types.insert(newType); + return newType; +} \ No newline at end of file diff --git a/interface/src/events/HFMetaEvent.h b/interface/src/events/HFMetaEvent.h new file mode 100644 index 0000000000..8fbdfab1fa --- /dev/null +++ b/interface/src/events/HFMetaEvent.h @@ -0,0 +1,27 @@ +// +// HFMetaEvent.h +// interface/src/events +// +// Created by Stephen Birarda on 2014-10-27. +// 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_HFMetaEvent_h +#define hifi_HFMetaEvent_h + +#include + +class HFMetaEvent : public QEvent { +public: + HFMetaEvent(QEvent::Type type) : QEvent(type) {}; + static const QSet& types() { return HFMetaEvent::_types; } +protected: + static QEvent::Type newEventType(); + + static QSet _types; +}; + +#endif // hifi_HFMetaEvent_h \ No newline at end of file From d38dd2c53a368f14d5dcc5b50d208d7f97359753 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 14:18:23 -0700 Subject: [PATCH 099/119] repairs for recursive source files, move HF meta events to SE --- cmake/macros/SetupHifiLibrary.cmake | 2 +- interface/CMakeLists.txt | 6 +----- interface/src/Application.cpp | 3 +-- interface/src/scripting/ControllerScriptingInterface.h | 2 +- .../src/AbstractControllerScriptingInterface.h | 3 +++ .../script-engine/src}/HFActionEvent.cpp | 0 .../events => libraries/script-engine/src}/HFActionEvent.h | 0 .../events => libraries/script-engine/src}/HFMetaEvent.cpp | 0 .../events => libraries/script-engine/src}/HFMetaEvent.h | 0 libraries/script-engine/src/ScriptEngine.cpp | 3 ++- 10 files changed, 9 insertions(+), 10 deletions(-) rename {interface/src/events => libraries/script-engine/src}/HFActionEvent.cpp (100%) rename {interface/src/events => libraries/script-engine/src}/HFActionEvent.h (100%) rename {interface/src/events => libraries/script-engine/src}/HFMetaEvent.cpp (100%) rename {interface/src/events => libraries/script-engine/src}/HFMetaEvent.h (100%) diff --git a/cmake/macros/SetupHifiLibrary.cmake b/cmake/macros/SetupHifiLibrary.cmake index 7bb85f68f5..950286ce45 100644 --- a/cmake/macros/SetupHifiLibrary.cmake +++ b/cmake/macros/SetupHifiLibrary.cmake @@ -12,7 +12,7 @@ macro(SETUP_HIFI_LIBRARY) project(${TARGET_NAME}) # grab the implemenation and header files - file(GLOB LIB_SRCS src/*.h src/*.cpp) + file(GLOB_RECURSE LIB_SRCS "src/*.h" "src/*.cpp") set(LIB_SRCS ${LIB_SRCS}) # create a library and set the property so it can be referenced later diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 0867f15ac8..c75d210103 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -44,11 +44,7 @@ configure_file(InterfaceConfig.h.in "${PROJECT_BINARY_DIR}/includes/InterfaceCon configure_file(InterfaceVersion.h.in "${PROJECT_BINARY_DIR}/includes/InterfaceVersion.h") # grab the implementation and header files from src dirs -file(GLOB INTERFACE_SRCS src/*.cpp src/*.h) -foreach(SUBDIR avatar devices events renderer ui starfield location scripting voxels particles entities gpu) - file(GLOB_RECURSE SUBDIR_SRCS src/${SUBDIR}/*.cpp src/${SUBDIR}/*.h) - set(INTERFACE_SRCS ${INTERFACE_SRCS} "${SUBDIR_SRCS}") -endforeach(SUBDIR) +file(GLOB_RECURSE INTERFACE_SRCS "src/*.cpp" "src/*.h") # Add SpeechRecognizer if on OS X, otherwise remove if (APPLE) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 91ff7c3563..81d8098002 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -77,8 +78,6 @@ #include "devices/OculusManager.h" #include "devices/TV3DManager.h" -#include "events/HFActionEvent.h" - #include "renderer/ProgramObject.h" #include "scripting/AccountScriptingInterface.h" diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h index 62ef2e9b24..916c87d85c 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -46,7 +46,7 @@ private: signals: }; - + /// handles scripting of input controller commands from JS class ControllerScriptingInterface : public AbstractControllerScriptingInterface { diff --git a/libraries/script-engine/src/AbstractControllerScriptingInterface.h b/libraries/script-engine/src/AbstractControllerScriptingInterface.h index 78e36a3740..1e9647c5d5 100644 --- a/libraries/script-engine/src/AbstractControllerScriptingInterface.h +++ b/libraries/script-engine/src/AbstractControllerScriptingInterface.h @@ -88,6 +88,9 @@ public slots: signals: void keyPressEvent(const KeyEvent& event); void keyReleaseEvent(const KeyEvent& event); +// +// void actionStartEvent(const HFActionEvent& event); +// void actionEndEvent(const HFActionEvent& event); void mouseMoveEvent(const MouseEvent& event, unsigned int deviceID = 0); void mousePressEvent(const MouseEvent& event, unsigned int deviceID = 0); diff --git a/interface/src/events/HFActionEvent.cpp b/libraries/script-engine/src/HFActionEvent.cpp similarity index 100% rename from interface/src/events/HFActionEvent.cpp rename to libraries/script-engine/src/HFActionEvent.cpp diff --git a/interface/src/events/HFActionEvent.h b/libraries/script-engine/src/HFActionEvent.h similarity index 100% rename from interface/src/events/HFActionEvent.h rename to libraries/script-engine/src/HFActionEvent.h diff --git a/interface/src/events/HFMetaEvent.cpp b/libraries/script-engine/src/HFMetaEvent.cpp similarity index 100% rename from interface/src/events/HFMetaEvent.cpp rename to libraries/script-engine/src/HFMetaEvent.cpp diff --git a/interface/src/events/HFMetaEvent.h b/libraries/script-engine/src/HFMetaEvent.h similarity index 100% rename from interface/src/events/HFMetaEvent.h rename to libraries/script-engine/src/HFMetaEvent.h diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 660a6ec560..3ccd0a74c3 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -36,12 +36,13 @@ #include "ArrayBufferViewClass.h" #include "DataViewClass.h" #include "MenuItemProperties.h" -#include "MIDIEvent.h" #include "LocalVoxels.h" #include "ScriptEngine.h" #include "TypedArrays.h" #include "XMLHttpRequestClass.h" +#include "MIDIEvent.h" + VoxelsScriptingInterface ScriptEngine::_voxelsScriptingInterface; EntityScriptingInterface ScriptEngine::_entityScriptingInterface; From 5a390da509e1b19e74a42c826d518aa1f65731b5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 14:24:32 -0700 Subject: [PATCH 100/119] move KeyEvent from EventTypes to its own file --- .../AbstractControllerScriptingInterface.h | 1 + libraries/script-engine/src/EventTypes.cpp | 277 +---------------- libraries/script-engine/src/EventTypes.h | 24 -- libraries/script-engine/src/KeyEvent.cpp | 290 ++++++++++++++++++ libraries/script-engine/src/KeyEvent.h | 41 +++ .../script-engine/src/MenuItemProperties.cpp | 2 +- .../script-engine/src/MenuItemProperties.h | 2 +- 7 files changed, 338 insertions(+), 299 deletions(-) create mode 100644 libraries/script-engine/src/KeyEvent.cpp create mode 100644 libraries/script-engine/src/KeyEvent.h diff --git a/libraries/script-engine/src/AbstractControllerScriptingInterface.h b/libraries/script-engine/src/AbstractControllerScriptingInterface.h index 1e9647c5d5..9f583b94d8 100644 --- a/libraries/script-engine/src/AbstractControllerScriptingInterface.h +++ b/libraries/script-engine/src/AbstractControllerScriptingInterface.h @@ -18,6 +18,7 @@ #include #include "EventTypes.h" +#include "KeyEvent.h" class AbstractInputController : public QObject { Q_OBJECT diff --git a/libraries/script-engine/src/EventTypes.cpp b/libraries/script-engine/src/EventTypes.cpp index de3ec231ae..49c82796a2 100644 --- a/libraries/script-engine/src/EventTypes.cpp +++ b/libraries/script-engine/src/EventTypes.cpp @@ -11,291 +11,22 @@ #include #include + +#include "KeyEvent.h" + #include "EventTypes.h" void registerEventTypes(QScriptEngine* engine) { - qScriptRegisterMetaType(engine, keyEventToScriptValue, keyEventFromScriptValue); + qScriptRegisterMetaType(engine, KeyEvent::toScriptValue, KeyEvent::fromScriptValue); qScriptRegisterMetaType(engine, mouseEventToScriptValue, mouseEventFromScriptValue); qScriptRegisterMetaType(engine, touchEventToScriptValue, touchEventFromScriptValue); qScriptRegisterMetaType(engine, wheelEventToScriptValue, wheelEventFromScriptValue); qScriptRegisterMetaType(engine, spatialEventToScriptValue, spatialEventFromScriptValue); } -KeyEvent::KeyEvent() : - key(0), - text(""), - isShifted(false), - isControl(false), - isMeta(false), - isAlt(false), - isKeypad(false), - isValid(false), - isAutoRepeat(false) -{ -}; -KeyEvent::KeyEvent(const QKeyEvent& event) { - key = event.key(); - text = event.text(); - isShifted = event.modifiers().testFlag(Qt::ShiftModifier); - isMeta = event.modifiers().testFlag(Qt::MetaModifier); - isControl = event.modifiers().testFlag(Qt::ControlModifier); - isAlt = event.modifiers().testFlag(Qt::AltModifier); - isKeypad = event.modifiers().testFlag(Qt::KeypadModifier); - isValid = true; - isAutoRepeat = event.isAutoRepeat(); - - // handle special text for special characters... - if (key == Qt::Key_F1) { - text = "F1"; - } else if (key == Qt::Key_F2) { - text = "F2"; - } else if (key == Qt::Key_F3) { - text = "F3"; - } else if (key == Qt::Key_F4) { - text = "F4"; - } else if (key == Qt::Key_F5) { - text = "F5"; - } else if (key == Qt::Key_F6) { - text = "F6"; - } else if (key == Qt::Key_F7) { - text = "F7"; - } else if (key == Qt::Key_F8) { - text = "F8"; - } else if (key == Qt::Key_F9) { - text = "F9"; - } else if (key == Qt::Key_F10) { - text = "F10"; - } else if (key == Qt::Key_F11) { - text = "F11"; - } else if (key == Qt::Key_F12) { - text = "F12"; - } else if (key == Qt::Key_Up) { - text = "UP"; - } else if (key == Qt::Key_Down) { - text = "DOWN"; - } else if (key == Qt::Key_Left) { - text = "LEFT"; - } else if (key == Qt::Key_Right) { - text = "RIGHT"; - } else if (key == Qt::Key_Space) { - text = "SPACE"; - } else if (key == Qt::Key_Escape) { - text = "ESC"; - } else if (key == Qt::Key_Tab) { - text = "TAB"; - } else if (key == Qt::Key_Delete) { - text = "DELETE"; - } else if (key == Qt::Key_Backspace) { - text = "BACKSPACE"; - } else if (key == Qt::Key_Shift) { - text = "SHIFT"; - } else if (key == Qt::Key_Alt) { - text = "ALT"; - } else if (key == Qt::Key_Control) { - text = "CONTROL"; - } else if (key == Qt::Key_Meta) { - text = "META"; - } else if (key == Qt::Key_PageDown) { - text = "PAGE DOWN"; - } else if (key == Qt::Key_PageUp) { - text = "PAGE UP"; - } else if (key == Qt::Key_Home) { - text = "HOME"; - } else if (key == Qt::Key_End) { - text = "END"; - } else if (key == Qt::Key_Help) { - text = "HELP"; - } else if (key == Qt::Key_CapsLock) { - text = "CAPS LOCK"; - } else if (key >= Qt::Key_A && key <= Qt::Key_Z && (isMeta || isControl || isAlt)) { - // this little bit of hackery will fix the text character keys like a-z in cases of control/alt/meta where - // qt doesn't always give you the key characters and will sometimes give you crazy non-printable characters - const int lowerCaseAdjust = 0x20; - QString unicode; - if (isShifted) { - text = QString(QChar(key)); - } else { - text = QString(QChar(key + lowerCaseAdjust)); - } - } -} - -bool KeyEvent::operator==(const KeyEvent& other) const { - return other.key == key - && other.isShifted == isShifted - && other.isControl == isControl - && other.isMeta == isMeta - && other.isAlt == isAlt - && other.isKeypad == isKeypad - && other.isAutoRepeat == isAutoRepeat; -} - - -KeyEvent::operator QKeySequence() const { - int resultCode = 0; - if (text.size() == 1 && text >= "a" && text <= "z") { - resultCode = text.toUpper().at(0).unicode(); - } else { - resultCode = key; - } - - if (isMeta) { - resultCode |= Qt::META; - } - if (isAlt) { - resultCode |= Qt::ALT; - } - if (isControl) { - resultCode |= Qt::CTRL; - } - if (isShifted) { - resultCode |= Qt::SHIFT; - } - return QKeySequence(resultCode); -} - -QScriptValue keyEventToScriptValue(QScriptEngine* engine, const KeyEvent& event) { - QScriptValue obj = engine->newObject(); - obj.setProperty("key", event.key); - obj.setProperty("text", event.text); - obj.setProperty("isShifted", event.isShifted); - obj.setProperty("isMeta", event.isMeta); - obj.setProperty("isControl", event.isControl); - obj.setProperty("isAlt", event.isAlt); - obj.setProperty("isKeypad", event.isKeypad); - obj.setProperty("isAutoRepeat", event.isAutoRepeat); - return obj; -} - -void keyEventFromScriptValue(const QScriptValue& object, KeyEvent& event) { - - event.isValid = false; // assume the worst - event.isMeta = object.property("isMeta").toVariant().toBool(); - event.isControl = object.property("isControl").toVariant().toBool(); - event.isAlt = object.property("isAlt").toVariant().toBool(); - event.isKeypad = object.property("isKeypad").toVariant().toBool(); - event.isAutoRepeat = object.property("isAutoRepeat").toVariant().toBool(); - - QScriptValue key = object.property("key"); - if (key.isValid()) { - event.key = key.toVariant().toInt(); - event.text = QString(QChar(event.key)); - event.isValid = true; - } else { - QScriptValue text = object.property("text"); - if (text.isValid()) { - event.text = object.property("text").toVariant().toString(); - - // if the text is a special command, then map it here... - // TODO: come up with more elegant solution here, a map? is there a Qt function that gives nice names for keys? - if (event.text.toUpper() == "F1") { - event.key = Qt::Key_F1; - } else if (event.text.toUpper() == "F2") { - event.key = Qt::Key_F2; - } else if (event.text.toUpper() == "F3") { - event.key = Qt::Key_F3; - } else if (event.text.toUpper() == "F4") { - event.key = Qt::Key_F4; - } else if (event.text.toUpper() == "F5") { - event.key = Qt::Key_F5; - } else if (event.text.toUpper() == "F6") { - event.key = Qt::Key_F6; - } else if (event.text.toUpper() == "F7") { - event.key = Qt::Key_F7; - } else if (event.text.toUpper() == "F8") { - event.key = Qt::Key_F8; - } else if (event.text.toUpper() == "F9") { - event.key = Qt::Key_F9; - } else if (event.text.toUpper() == "F10") { - event.key = Qt::Key_F10; - } else if (event.text.toUpper() == "F11") { - event.key = Qt::Key_F11; - } else if (event.text.toUpper() == "F12") { - event.key = Qt::Key_F12; - } else if (event.text.toUpper() == "UP") { - event.key = Qt::Key_Up; - event.isKeypad = true; - } else if (event.text.toUpper() == "DOWN") { - event.key = Qt::Key_Down; - event.isKeypad = true; - } else if (event.text.toUpper() == "LEFT") { - event.key = Qt::Key_Left; - event.isKeypad = true; - } else if (event.text.toUpper() == "RIGHT") { - event.key = Qt::Key_Right; - event.isKeypad = true; - } else if (event.text.toUpper() == "SPACE") { - event.key = Qt::Key_Space; - } else if (event.text.toUpper() == "ESC") { - event.key = Qt::Key_Escape; - } else if (event.text.toUpper() == "TAB") { - event.key = Qt::Key_Tab; - } else if (event.text.toUpper() == "DELETE") { - event.key = Qt::Key_Delete; - } else if (event.text.toUpper() == "BACKSPACE") { - event.key = Qt::Key_Backspace; - } else if (event.text.toUpper() == "SHIFT") { - event.key = Qt::Key_Shift; - } else if (event.text.toUpper() == "ALT") { - event.key = Qt::Key_Alt; - } else if (event.text.toUpper() == "CONTROL") { - event.key = Qt::Key_Control; - } else if (event.text.toUpper() == "META") { - event.key = Qt::Key_Meta; - } else if (event.text.toUpper() == "PAGE DOWN") { - event.key = Qt::Key_PageDown; - } else if (event.text.toUpper() == "PAGE UP") { - event.key = Qt::Key_PageUp; - } else if (event.text.toUpper() == "HOME") { - event.key = Qt::Key_Home; - } else if (event.text.toUpper() == "END") { - event.key = Qt::Key_End; - } else if (event.text.toUpper() == "HELP") { - event.key = Qt::Key_Help; - } else if (event.text.toUpper() == "CAPS LOCK") { - event.key = Qt::Key_CapsLock; - } else { - // Key values do not distinguish between uppercase and lowercase - // and use the uppercase key value. - event.key = event.text.toUpper().at(0).unicode(); - } - event.isValid = true; - } - } - - QScriptValue isShifted = object.property("isShifted"); - if (isShifted.isValid()) { - event.isShifted = isShifted.toVariant().toBool(); - } else { - // if no isShifted was included, get it from the text - QChar character = event.text.at(0); - if (character.isLetter() && character.isUpper()) { - event.isShifted = true; - } else { - // if it's a symbol, then attempt to detect shifted-ness - if (QString("~!@#$%^&*()_+{}|:\"<>?").contains(character)) { - event.isShifted = true; - } - } - } - - - const bool wantDebug = false; - if (wantDebug) { - qDebug() << "event.key=" << event.key - << " event.text=" << event.text - << " event.isShifted=" << event.isShifted - << " event.isControl=" << event.isControl - << " event.isMeta=" << event.isMeta - << " event.isAlt=" << event.isAlt - << " event.isKeypad=" << event.isKeypad - << " event.isAutoRepeat=" << event.isAutoRepeat; - } -} - MouseEvent::MouseEvent() : x(0.0f), y(0.0f), diff --git a/libraries/script-engine/src/EventTypes.h b/libraries/script-engine/src/EventTypes.h index 959292039b..121c321cf6 100644 --- a/libraries/script-engine/src/EventTypes.h +++ b/libraries/script-engine/src/EventTypes.h @@ -17,31 +17,11 @@ #include -#include #include #include #include -class KeyEvent { -public: - KeyEvent(); - KeyEvent(const QKeyEvent& event); - bool operator==(const KeyEvent& other) const; - operator QKeySequence() const; - - int key; - QString text; - bool isShifted; - bool isControl; - bool isMeta; - bool isAlt; - bool isKeypad; - bool isValid; - bool isAutoRepeat; -}; - - class MouseEvent { public: MouseEvent(); @@ -123,8 +103,6 @@ public: private: }; - -Q_DECLARE_METATYPE(KeyEvent) Q_DECLARE_METATYPE(MouseEvent) Q_DECLARE_METATYPE(TouchEvent) Q_DECLARE_METATYPE(WheelEvent) @@ -132,8 +110,6 @@ Q_DECLARE_METATYPE(SpatialEvent) void registerEventTypes(QScriptEngine* engine); -QScriptValue keyEventToScriptValue(QScriptEngine* engine, const KeyEvent& event); -void keyEventFromScriptValue(const QScriptValue& object, KeyEvent& event); QScriptValue mouseEventToScriptValue(QScriptEngine* engine, const MouseEvent& event); void mouseEventFromScriptValue(const QScriptValue& object, MouseEvent& event); diff --git a/libraries/script-engine/src/KeyEvent.cpp b/libraries/script-engine/src/KeyEvent.cpp new file mode 100644 index 0000000000..b7564db1b6 --- /dev/null +++ b/libraries/script-engine/src/KeyEvent.cpp @@ -0,0 +1,290 @@ +// +// KeyEvent.cpp +// script-engine/src +// +// Created by Stephen Birarda on 2014-10-27. +// 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 +#include + +#include "KeyEvent.h" + +KeyEvent::KeyEvent() : + key(0), + text(""), + isShifted(false), + isControl(false), + isMeta(false), + isAlt(false), + isKeypad(false), + isValid(false), + isAutoRepeat(false) +{ + +} + +KeyEvent::KeyEvent(const QKeyEvent& event) { + key = event.key(); + text = event.text(); + isShifted = event.modifiers().testFlag(Qt::ShiftModifier); + isMeta = event.modifiers().testFlag(Qt::MetaModifier); + isControl = event.modifiers().testFlag(Qt::ControlModifier); + isAlt = event.modifiers().testFlag(Qt::AltModifier); + isKeypad = event.modifiers().testFlag(Qt::KeypadModifier); + isValid = true; + isAutoRepeat = event.isAutoRepeat(); + + // handle special text for special characters... + if (key == Qt::Key_F1) { + text = "F1"; + } else if (key == Qt::Key_F2) { + text = "F2"; + } else if (key == Qt::Key_F3) { + text = "F3"; + } else if (key == Qt::Key_F4) { + text = "F4"; + } else if (key == Qt::Key_F5) { + text = "F5"; + } else if (key == Qt::Key_F6) { + text = "F6"; + } else if (key == Qt::Key_F7) { + text = "F7"; + } else if (key == Qt::Key_F8) { + text = "F8"; + } else if (key == Qt::Key_F9) { + text = "F9"; + } else if (key == Qt::Key_F10) { + text = "F10"; + } else if (key == Qt::Key_F11) { + text = "F11"; + } else if (key == Qt::Key_F12) { + text = "F12"; + } else if (key == Qt::Key_Up) { + text = "UP"; + } else if (key == Qt::Key_Down) { + text = "DOWN"; + } else if (key == Qt::Key_Left) { + text = "LEFT"; + } else if (key == Qt::Key_Right) { + text = "RIGHT"; + } else if (key == Qt::Key_Space) { + text = "SPACE"; + } else if (key == Qt::Key_Escape) { + text = "ESC"; + } else if (key == Qt::Key_Tab) { + text = "TAB"; + } else if (key == Qt::Key_Delete) { + text = "DELETE"; + } else if (key == Qt::Key_Backspace) { + text = "BACKSPACE"; + } else if (key == Qt::Key_Shift) { + text = "SHIFT"; + } else if (key == Qt::Key_Alt) { + text = "ALT"; + } else if (key == Qt::Key_Control) { + text = "CONTROL"; + } else if (key == Qt::Key_Meta) { + text = "META"; + } else if (key == Qt::Key_PageDown) { + text = "PAGE DOWN"; + } else if (key == Qt::Key_PageUp) { + text = "PAGE UP"; + } else if (key == Qt::Key_Home) { + text = "HOME"; + } else if (key == Qt::Key_End) { + text = "END"; + } else if (key == Qt::Key_Help) { + text = "HELP"; + } else if (key == Qt::Key_CapsLock) { + text = "CAPS LOCK"; + } else if (key >= Qt::Key_A && key <= Qt::Key_Z && (isMeta || isControl || isAlt)) { + // this little bit of hackery will fix the text character keys like a-z in cases of control/alt/meta where + // qt doesn't always give you the key characters and will sometimes give you crazy non-printable characters + const int lowerCaseAdjust = 0x20; + QString unicode; + if (isShifted) { + text = QString(QChar(key)); + } else { + text = QString(QChar(key + lowerCaseAdjust)); + } + } +} + +bool KeyEvent::operator==(const KeyEvent& other) const { + return other.key == key + && other.isShifted == isShifted + && other.isControl == isControl + && other.isMeta == isMeta + && other.isAlt == isAlt + && other.isKeypad == isKeypad + && other.isAutoRepeat == isAutoRepeat; +} + + +KeyEvent::operator QKeySequence() const { + int resultCode = 0; + if (text.size() == 1 && text >= "a" && text <= "z") { + resultCode = text.toUpper().at(0).unicode(); + } else { + resultCode = key; + } + + if (isMeta) { + resultCode |= Qt::META; + } + if (isAlt) { + resultCode |= Qt::ALT; + } + if (isControl) { + resultCode |= Qt::CTRL; + } + if (isShifted) { + resultCode |= Qt::SHIFT; + } + return QKeySequence(resultCode); +} + +QScriptValue KeyEvent::toScriptValue(QScriptEngine* engine, const KeyEvent& event) { + QScriptValue obj = engine->newObject(); + obj.setProperty("key", event.key); + obj.setProperty("text", event.text); + obj.setProperty("isShifted", event.isShifted); + obj.setProperty("isMeta", event.isMeta); + obj.setProperty("isControl", event.isControl); + obj.setProperty("isAlt", event.isAlt); + obj.setProperty("isKeypad", event.isKeypad); + obj.setProperty("isAutoRepeat", event.isAutoRepeat); + return obj; +} + +void KeyEvent::fromScriptValue(const QScriptValue& object, KeyEvent& event) { + + event.isValid = false; // assume the worst + event.isMeta = object.property("isMeta").toVariant().toBool(); + event.isControl = object.property("isControl").toVariant().toBool(); + event.isAlt = object.property("isAlt").toVariant().toBool(); + event.isKeypad = object.property("isKeypad").toVariant().toBool(); + event.isAutoRepeat = object.property("isAutoRepeat").toVariant().toBool(); + + QScriptValue key = object.property("key"); + if (key.isValid()) { + event.key = key.toVariant().toInt(); + event.text = QString(QChar(event.key)); + event.isValid = true; + } else { + QScriptValue text = object.property("text"); + if (text.isValid()) { + event.text = object.property("text").toVariant().toString(); + + // if the text is a special command, then map it here... + // TODO: come up with more elegant solution here, a map? is there a Qt function that gives nice names for keys? + if (event.text.toUpper() == "F1") { + event.key = Qt::Key_F1; + } else if (event.text.toUpper() == "F2") { + event.key = Qt::Key_F2; + } else if (event.text.toUpper() == "F3") { + event.key = Qt::Key_F3; + } else if (event.text.toUpper() == "F4") { + event.key = Qt::Key_F4; + } else if (event.text.toUpper() == "F5") { + event.key = Qt::Key_F5; + } else if (event.text.toUpper() == "F6") { + event.key = Qt::Key_F6; + } else if (event.text.toUpper() == "F7") { + event.key = Qt::Key_F7; + } else if (event.text.toUpper() == "F8") { + event.key = Qt::Key_F8; + } else if (event.text.toUpper() == "F9") { + event.key = Qt::Key_F9; + } else if (event.text.toUpper() == "F10") { + event.key = Qt::Key_F10; + } else if (event.text.toUpper() == "F11") { + event.key = Qt::Key_F11; + } else if (event.text.toUpper() == "F12") { + event.key = Qt::Key_F12; + } else if (event.text.toUpper() == "UP") { + event.key = Qt::Key_Up; + event.isKeypad = true; + } else if (event.text.toUpper() == "DOWN") { + event.key = Qt::Key_Down; + event.isKeypad = true; + } else if (event.text.toUpper() == "LEFT") { + event.key = Qt::Key_Left; + event.isKeypad = true; + } else if (event.text.toUpper() == "RIGHT") { + event.key = Qt::Key_Right; + event.isKeypad = true; + } else if (event.text.toUpper() == "SPACE") { + event.key = Qt::Key_Space; + } else if (event.text.toUpper() == "ESC") { + event.key = Qt::Key_Escape; + } else if (event.text.toUpper() == "TAB") { + event.key = Qt::Key_Tab; + } else if (event.text.toUpper() == "DELETE") { + event.key = Qt::Key_Delete; + } else if (event.text.toUpper() == "BACKSPACE") { + event.key = Qt::Key_Backspace; + } else if (event.text.toUpper() == "SHIFT") { + event.key = Qt::Key_Shift; + } else if (event.text.toUpper() == "ALT") { + event.key = Qt::Key_Alt; + } else if (event.text.toUpper() == "CONTROL") { + event.key = Qt::Key_Control; + } else if (event.text.toUpper() == "META") { + event.key = Qt::Key_Meta; + } else if (event.text.toUpper() == "PAGE DOWN") { + event.key = Qt::Key_PageDown; + } else if (event.text.toUpper() == "PAGE UP") { + event.key = Qt::Key_PageUp; + } else if (event.text.toUpper() == "HOME") { + event.key = Qt::Key_Home; + } else if (event.text.toUpper() == "END") { + event.key = Qt::Key_End; + } else if (event.text.toUpper() == "HELP") { + event.key = Qt::Key_Help; + } else if (event.text.toUpper() == "CAPS LOCK") { + event.key = Qt::Key_CapsLock; + } else { + // Key values do not distinguish between uppercase and lowercase + // and use the uppercase key value. + event.key = event.text.toUpper().at(0).unicode(); + } + event.isValid = true; + } + } + + QScriptValue isShifted = object.property("isShifted"); + if (isShifted.isValid()) { + event.isShifted = isShifted.toVariant().toBool(); + } else { + // if no isShifted was included, get it from the text + QChar character = event.text.at(0); + if (character.isLetter() && character.isUpper()) { + event.isShifted = true; + } else { + // if it's a symbol, then attempt to detect shifted-ness + if (QString("~!@#$%^&*()_+{}|:\"<>?").contains(character)) { + event.isShifted = true; + } + } + } + + + const bool wantDebug = false; + if (wantDebug) { + qDebug() << "event.key=" << event.key + << " event.text=" << event.text + << " event.isShifted=" << event.isShifted + << " event.isControl=" << event.isControl + << " event.isMeta=" << event.isMeta + << " event.isAlt=" << event.isAlt + << " event.isKeypad=" << event.isKeypad + << " event.isAutoRepeat=" << event.isAutoRepeat; + } +} + diff --git a/libraries/script-engine/src/KeyEvent.h b/libraries/script-engine/src/KeyEvent.h new file mode 100644 index 0000000000..bdadcec374 --- /dev/null +++ b/libraries/script-engine/src/KeyEvent.h @@ -0,0 +1,41 @@ +// +// KeyEvent.h +// script-engine/src +// +// Created by Stephen Birarda on 2014-10-27. +// 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_KeyEvent_h +#define hifi_KeyEvent_h + +#include +#include + +class KeyEvent { +public: + KeyEvent(); + KeyEvent(const QKeyEvent& event); + bool operator==(const KeyEvent& other) const; + operator QKeySequence() const; + + static QScriptValue toScriptValue(QScriptEngine* engine, const KeyEvent& event); + static void fromScriptValue(const QScriptValue& object, KeyEvent& event); + + int key; + QString text; + bool isShifted; + bool isControl; + bool isMeta; + bool isAlt; + bool isKeypad; + bool isValid; + bool isAutoRepeat; +}; + +Q_DECLARE_METATYPE(KeyEvent) + +#endif // hifi_KeyEvent_h \ No newline at end of file diff --git a/libraries/script-engine/src/MenuItemProperties.cpp b/libraries/script-engine/src/MenuItemProperties.cpp index c1f3e92447..97fbdef1fa 100644 --- a/libraries/script-engine/src/MenuItemProperties.cpp +++ b/libraries/script-engine/src/MenuItemProperties.cpp @@ -82,7 +82,7 @@ void menuItemPropertiesFromScriptValue(const QScriptValue& object, MenuItemPrope } else { QScriptValue shortcutKeyEventValue = object.property("shortcutKeyEvent"); if (shortcutKeyEventValue.isValid()) { - keyEventFromScriptValue(shortcutKeyEventValue, properties.shortcutKeyEvent); + KeyEvent::fromScriptValue(shortcutKeyEventValue, properties.shortcutKeyEvent); properties.shortcutKeySequence = properties.shortcutKeyEvent; } } diff --git a/libraries/script-engine/src/MenuItemProperties.h b/libraries/script-engine/src/MenuItemProperties.h index 9dd3c6107c..889fb3855a 100644 --- a/libraries/script-engine/src/MenuItemProperties.h +++ b/libraries/script-engine/src/MenuItemProperties.h @@ -14,7 +14,7 @@ #include -#include "EventTypes.h" +#include "KeyEvent.h" const int UNSPECIFIED_POSITION = -1; From 3aa7c3c7dc0f1fc6836fbefcd7aae49a7967acd3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 14:30:20 -0700 Subject: [PATCH 101/119] move MouseEvent out of EventTypes into its own file --- .../AbstractControllerScriptingInterface.h | 1 + libraries/script-engine/src/EventTypes.cpp | 73 +--------------- libraries/script-engine/src/EventTypes.h | 21 ----- libraries/script-engine/src/MouseEvent.cpp | 83 +++++++++++++++++++ libraries/script-engine/src/MouseEvent.h | 40 +++++++++ 5 files changed, 126 insertions(+), 92 deletions(-) create mode 100644 libraries/script-engine/src/MouseEvent.cpp create mode 100644 libraries/script-engine/src/MouseEvent.h diff --git a/libraries/script-engine/src/AbstractControllerScriptingInterface.h b/libraries/script-engine/src/AbstractControllerScriptingInterface.h index 9f583b94d8..050a555ff5 100644 --- a/libraries/script-engine/src/AbstractControllerScriptingInterface.h +++ b/libraries/script-engine/src/AbstractControllerScriptingInterface.h @@ -19,6 +19,7 @@ #include "EventTypes.h" #include "KeyEvent.h" +#include "MouseEvent.h" class AbstractInputController : public QObject { Q_OBJECT diff --git a/libraries/script-engine/src/EventTypes.cpp b/libraries/script-engine/src/EventTypes.cpp index 49c82796a2..e70e3302a5 100644 --- a/libraries/script-engine/src/EventTypes.cpp +++ b/libraries/script-engine/src/EventTypes.cpp @@ -13,87 +13,18 @@ #include #include "KeyEvent.h" +#include "MouseEvent.h" #include "EventTypes.h" - void registerEventTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, KeyEvent::toScriptValue, KeyEvent::fromScriptValue); - qScriptRegisterMetaType(engine, mouseEventToScriptValue, mouseEventFromScriptValue); + qScriptRegisterMetaType(engine, MouseEvent::toScriptValue, MouseEvent::fromScriptValue); qScriptRegisterMetaType(engine, touchEventToScriptValue, touchEventFromScriptValue); qScriptRegisterMetaType(engine, wheelEventToScriptValue, wheelEventFromScriptValue); qScriptRegisterMetaType(engine, spatialEventToScriptValue, spatialEventFromScriptValue); } - - -MouseEvent::MouseEvent() : - x(0.0f), - y(0.0f), - isLeftButton(false), - isRightButton(false), - isMiddleButton(false), - isShifted(false), - isControl(false), - isMeta(false), - isAlt(false) -{ -}; - - -MouseEvent::MouseEvent(const QMouseEvent& event, const unsigned int deviceID) : - x(event.x()), - y(event.y()), - deviceID(deviceID), - isLeftButton(event.buttons().testFlag(Qt::LeftButton)), - isRightButton(event.buttons().testFlag(Qt::RightButton)), - isMiddleButton(event.buttons().testFlag(Qt::MiddleButton)), - isShifted(event.modifiers().testFlag(Qt::ShiftModifier)), - isControl(event.modifiers().testFlag(Qt::ControlModifier)), - isMeta(event.modifiers().testFlag(Qt::MetaModifier)), - isAlt(event.modifiers().testFlag(Qt::AltModifier)) -{ - // single button that caused the event - switch (event.button()) { - case Qt::LeftButton: - button = "LEFT"; - isLeftButton = true; - break; - case Qt::RightButton: - button = "RIGHT"; - isRightButton = true; - break; - case Qt::MiddleButton: - button = "MIDDLE"; - isMiddleButton = true; - break; - default: - button = "NONE"; - break; - } -} - -QScriptValue mouseEventToScriptValue(QScriptEngine* engine, const MouseEvent& event) { - QScriptValue obj = engine->newObject(); - obj.setProperty("x", event.x); - obj.setProperty("y", event.y); - obj.setProperty("button", event.button); - obj.setProperty("deviceID", event.deviceID); - obj.setProperty("isLeftButton", event.isLeftButton); - obj.setProperty("isRightButton", event.isRightButton); - obj.setProperty("isMiddleButton", event.isMiddleButton); - obj.setProperty("isShifted", event.isShifted); - obj.setProperty("isMeta", event.isMeta); - obj.setProperty("isControl", event.isControl); - obj.setProperty("isAlt", event.isAlt); - - return obj; -} - -void mouseEventFromScriptValue(const QScriptValue& object, MouseEvent& event) { - // nothing for now... -} - TouchEvent::TouchEvent() : x(0.0f), y(0.0f), diff --git a/libraries/script-engine/src/EventTypes.h b/libraries/script-engine/src/EventTypes.h index 121c321cf6..0cec3fe20d 100644 --- a/libraries/script-engine/src/EventTypes.h +++ b/libraries/script-engine/src/EventTypes.h @@ -22,23 +22,6 @@ #include -class MouseEvent { -public: - MouseEvent(); - MouseEvent(const QMouseEvent& event, const unsigned int deviceID = 0); - int x; - int y; - unsigned int deviceID; - QString button; - bool isLeftButton; - bool isRightButton; - bool isMiddleButton; - bool isShifted; - bool isControl; - bool isMeta; - bool isAlt; -}; - class TouchEvent { public: TouchEvent(); @@ -103,7 +86,6 @@ public: private: }; -Q_DECLARE_METATYPE(MouseEvent) Q_DECLARE_METATYPE(TouchEvent) Q_DECLARE_METATYPE(WheelEvent) Q_DECLARE_METATYPE(SpatialEvent) @@ -111,9 +93,6 @@ Q_DECLARE_METATYPE(SpatialEvent) void registerEventTypes(QScriptEngine* engine); -QScriptValue mouseEventToScriptValue(QScriptEngine* engine, const MouseEvent& event); -void mouseEventFromScriptValue(const QScriptValue& object, MouseEvent& event); - QScriptValue touchEventToScriptValue(QScriptEngine* engine, const TouchEvent& event); void touchEventFromScriptValue(const QScriptValue& object, TouchEvent& event); diff --git a/libraries/script-engine/src/MouseEvent.cpp b/libraries/script-engine/src/MouseEvent.cpp new file mode 100644 index 0000000000..34b3eb693e --- /dev/null +++ b/libraries/script-engine/src/MouseEvent.cpp @@ -0,0 +1,83 @@ +// +// MouseEvent.cpp +// script-engine/src +// +// Created by Stephen Birarda on 2014-10-27. +// 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 +#include + +#include "MouseEvent.h" + +MouseEvent::MouseEvent() : + x(0.0f), + y(0.0f), + isLeftButton(false), + isRightButton(false), + isMiddleButton(false), + isShifted(false), + isControl(false), + isMeta(false), + isAlt(false) +{ + +} + + +MouseEvent::MouseEvent(const QMouseEvent& event, const unsigned int deviceID) : + x(event.x()), + y(event.y()), + deviceID(deviceID), + isLeftButton(event.buttons().testFlag(Qt::LeftButton)), + isRightButton(event.buttons().testFlag(Qt::RightButton)), + isMiddleButton(event.buttons().testFlag(Qt::MiddleButton)), + isShifted(event.modifiers().testFlag(Qt::ShiftModifier)), + isControl(event.modifiers().testFlag(Qt::ControlModifier)), + isMeta(event.modifiers().testFlag(Qt::MetaModifier)), + isAlt(event.modifiers().testFlag(Qt::AltModifier)) +{ + // single button that caused the event + switch (event.button()) { + case Qt::LeftButton: + button = "LEFT"; + isLeftButton = true; + break; + case Qt::RightButton: + button = "RIGHT"; + isRightButton = true; + break; + case Qt::MiddleButton: + button = "MIDDLE"; + isMiddleButton = true; + break; + default: + button = "NONE"; + break; + } +} + +QScriptValue MouseEvent::toScriptValue(QScriptEngine* engine, const MouseEvent& event) { + QScriptValue obj = engine->newObject(); + obj.setProperty("x", event.x); + obj.setProperty("y", event.y); + obj.setProperty("button", event.button); + obj.setProperty("deviceID", event.deviceID); + obj.setProperty("isLeftButton", event.isLeftButton); + obj.setProperty("isRightButton", event.isRightButton); + obj.setProperty("isMiddleButton", event.isMiddleButton); + obj.setProperty("isShifted", event.isShifted); + obj.setProperty("isMeta", event.isMeta); + obj.setProperty("isControl", event.isControl); + obj.setProperty("isAlt", event.isAlt); + + return obj; +} + +void MouseEvent::fromScriptValue(const QScriptValue& object, MouseEvent& event) { + // nothing for now... +} \ No newline at end of file diff --git a/libraries/script-engine/src/MouseEvent.h b/libraries/script-engine/src/MouseEvent.h new file mode 100644 index 0000000000..7555f2ea5a --- /dev/null +++ b/libraries/script-engine/src/MouseEvent.h @@ -0,0 +1,40 @@ +// +// MouseEvent.h +// script-engine/src +// +// Created by Stephen Birarda on 2014-10-27. +// 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_MouseEvent_h +#define hifi_MouseEvent_h + +#include + +class MouseEvent { +public: + MouseEvent(); + MouseEvent(const QMouseEvent& event, const unsigned int deviceID = 0); + + static QScriptValue toScriptValue(QScriptEngine* engine, const MouseEvent& event); + static void fromScriptValue(const QScriptValue& object, MouseEvent& event); + + int x; + int y; + unsigned int deviceID; + QString button; + bool isLeftButton; + bool isRightButton; + bool isMiddleButton; + bool isShifted; + bool isControl; + bool isMeta; + bool isAlt; +}; + +Q_DECLARE_METATYPE(MouseEvent) + +#endif // hifi_MouseEvent_h \ No newline at end of file From e72409bf395e0e49879839d332fa7729e662039e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 14:37:04 -0700 Subject: [PATCH 102/119] move TouchEvent out of EventTypes to its own file --- .../AbstractControllerScriptingInterface.h | 1 + libraries/script-engine/src/EventTypes.cpp | 195 +--------------- libraries/script-engine/src/EventTypes.h | 42 ---- libraries/script-engine/src/TouchEvent.cpp | 211 ++++++++++++++++++ libraries/script-engine/src/TouchEvent.h | 56 +++++ 5 files changed, 270 insertions(+), 235 deletions(-) create mode 100644 libraries/script-engine/src/TouchEvent.cpp create mode 100644 libraries/script-engine/src/TouchEvent.h diff --git a/libraries/script-engine/src/AbstractControllerScriptingInterface.h b/libraries/script-engine/src/AbstractControllerScriptingInterface.h index 050a555ff5..b594d07f3e 100644 --- a/libraries/script-engine/src/AbstractControllerScriptingInterface.h +++ b/libraries/script-engine/src/AbstractControllerScriptingInterface.h @@ -20,6 +20,7 @@ #include "EventTypes.h" #include "KeyEvent.h" #include "MouseEvent.h" +#include "TouchEvent.h" class AbstractInputController : public QObject { Q_OBJECT diff --git a/libraries/script-engine/src/EventTypes.cpp b/libraries/script-engine/src/EventTypes.cpp index e70e3302a5..0bb4d2fd9c 100644 --- a/libraries/script-engine/src/EventTypes.cpp +++ b/libraries/script-engine/src/EventTypes.cpp @@ -14,209 +14,18 @@ #include "KeyEvent.h" #include "MouseEvent.h" +#include "TouchEvent.h" #include "EventTypes.h" void registerEventTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, KeyEvent::toScriptValue, KeyEvent::fromScriptValue); qScriptRegisterMetaType(engine, MouseEvent::toScriptValue, MouseEvent::fromScriptValue); - qScriptRegisterMetaType(engine, touchEventToScriptValue, touchEventFromScriptValue); + qScriptRegisterMetaType(engine, TouchEvent::toScriptValue, TouchEvent::fromScriptValue); qScriptRegisterMetaType(engine, wheelEventToScriptValue, wheelEventFromScriptValue); qScriptRegisterMetaType(engine, spatialEventToScriptValue, spatialEventFromScriptValue); } -TouchEvent::TouchEvent() : - x(0.0f), - y(0.0f), - isPressed(false), - isMoved(false), - isStationary(false), - isReleased(false), - isShifted(false), - isControl(false), - isMeta(false), - isAlt(false), - touchPoints(0), - points(), - radius(0.0f), - isPinching(false), - isPinchOpening(false), - angles(), - angle(0.0f), - deltaAngle(0.0f), - isRotating(false), - rotating("none") -{ -}; - -TouchEvent::TouchEvent(const QTouchEvent& event) : - // these values are not set by initWithQTouchEvent() because they only apply to comparing to other events - isPinching(false), - isPinchOpening(false), - deltaAngle(0.0f), - isRotating(false), - rotating("none") -{ - initWithQTouchEvent(event); -} - -TouchEvent::TouchEvent(const QTouchEvent& event, const TouchEvent& other) { - initWithQTouchEvent(event); - calculateMetaAttributes(other); -} - -// returns the angle (in degrees) between two points (note: 0 degrees is 'east') -float angleBetweenPoints(const glm::vec2& a, const glm::vec2& b ) { - glm::vec2 length = b - a; - float angle = DEGREES_PER_RADIAN * std::atan2(length.y, length.x); - if (angle < 0) { - angle += 360.0f; - }; - return angle; -} - -void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) { - // convert the touch points into an average - const QList& tPoints = event.touchPoints(); - float touchAvgX = 0.0f; - float touchAvgY = 0.0f; - touchPoints = tPoints.count(); - if (touchPoints > 1) { - for (int i = 0; i < touchPoints; ++i) { - touchAvgX += tPoints[i].pos().x(); - touchAvgY += tPoints[i].pos().y(); - - // add it to our points vector - glm::vec2 thisPoint(tPoints[i].pos().x(), tPoints[i].pos().y()); - points << thisPoint; - } - touchAvgX /= (float)(touchPoints); - touchAvgY /= (float)(touchPoints); - } else { - // I'm not sure this should ever happen, why would Qt send us a touch event for only one point? - // maybe this happens in the case of a multi-touch where all but the last finger is released? - touchAvgX = tPoints[0].pos().x(); - touchAvgY = tPoints[0].pos().y(); - } - x = touchAvgX; - y = touchAvgY; - - // after calculating the center point (average touch point), determine the maximum radius - // also calculate the rotation angle for each point - float maxRadius = 0.0f; - glm::vec2 center(x,y); - for (int i = 0; i < touchPoints; ++i) { - glm::vec2 touchPoint(tPoints[i].pos().x(), tPoints[i].pos().y()); - float thisRadius = glm::distance(center,touchPoint); - if (thisRadius > maxRadius) { - maxRadius = thisRadius; - } - - // calculate the angle for this point - float thisAngle = angleBetweenPoints(center,touchPoint); - angles << thisAngle; - } - radius = maxRadius; - - // after calculating the angles for each touch point, determine the average angle - float totalAngle = 0.0f; - for (int i = 0; i < touchPoints; ++i) { - totalAngle += angles[i]; - } - angle = totalAngle/(float)touchPoints; - - isPressed = event.touchPointStates().testFlag(Qt::TouchPointPressed); - isMoved = event.touchPointStates().testFlag(Qt::TouchPointMoved); - isStationary = event.touchPointStates().testFlag(Qt::TouchPointStationary); - isReleased = event.touchPointStates().testFlag(Qt::TouchPointReleased); - - // keyboard modifiers - isShifted = event.modifiers().testFlag(Qt::ShiftModifier); - isMeta = event.modifiers().testFlag(Qt::MetaModifier); - isControl = event.modifiers().testFlag(Qt::ControlModifier); - isAlt = event.modifiers().testFlag(Qt::AltModifier); -} - -void TouchEvent::calculateMetaAttributes(const TouchEvent& other) { - // calculate comparative event attributes... - if (other.radius > radius) { - isPinching = true; - isPinchOpening = false; - } else if (other.radius < radius) { - isPinchOpening = true; - isPinching = false; - } else { - isPinching = other.isPinching; - isPinchOpening = other.isPinchOpening; - } - - // determine if the points are rotating... - // note: if the number of touch points change between events, then we don't consider ourselves to be rotating - if (touchPoints == other.touchPoints) { - deltaAngle = angle - other.angle; - if (other.angle < angle) { - isRotating = true; - rotating = "clockwise"; - } else if (other.angle > angle) { - isRotating = true; - rotating = "counterClockwise"; - } else { - isRotating = false; - rotating = "none"; - } - } else { - deltaAngle = 0.0f; - isRotating = false; - rotating = "none"; - } -} - - -QScriptValue touchEventToScriptValue(QScriptEngine* engine, const TouchEvent& event) { - QScriptValue obj = engine->newObject(); - obj.setProperty("x", event.x); - obj.setProperty("y", event.y); - obj.setProperty("isPressed", event.isPressed); - obj.setProperty("isMoved", event.isMoved); - obj.setProperty("isStationary", event.isStationary); - obj.setProperty("isReleased", event.isReleased); - obj.setProperty("isShifted", event.isShifted); - obj.setProperty("isMeta", event.isMeta); - obj.setProperty("isControl", event.isControl); - obj.setProperty("isAlt", event.isAlt); - obj.setProperty("touchPoints", event.touchPoints); - - QScriptValue pointsObj = engine->newArray(); - int index = 0; - foreach (glm::vec2 point, event.points) { - QScriptValue thisPoint = vec2toScriptValue(engine, point); - pointsObj.setProperty(index, thisPoint); - index++; - } - obj.setProperty("points", pointsObj); - obj.setProperty("radius", event.radius); - obj.setProperty("isPinching", event.isPinching); - obj.setProperty("isPinchOpening", event.isPinchOpening); - - obj.setProperty("angle", event.angle); - obj.setProperty("deltaAngle", event.deltaAngle); - QScriptValue anglesObj = engine->newArray(); - index = 0; - foreach (float angle, event.angles) { - anglesObj.setProperty(index, angle); - index++; - } - obj.setProperty("angles", anglesObj); - - obj.setProperty("isRotating", event.isRotating); - obj.setProperty("rotating", event.rotating); - return obj; -} - -void touchEventFromScriptValue(const QScriptValue& object, TouchEvent& event) { - // nothing for now... -} - WheelEvent::WheelEvent() : x(0.0f), y(0.0f), diff --git a/libraries/script-engine/src/EventTypes.h b/libraries/script-engine/src/EventTypes.h index 0cec3fe20d..54c2934c42 100644 --- a/libraries/script-engine/src/EventTypes.h +++ b/libraries/script-engine/src/EventTypes.h @@ -12,50 +12,12 @@ #ifndef hifi_EventTypes_h #define hifi_EventTypes_h -#include #include #include -#include -#include #include - -class TouchEvent { -public: - TouchEvent(); - TouchEvent(const QTouchEvent& event); - TouchEvent(const QTouchEvent& event, const TouchEvent& other); - - float x; - float y; - bool isPressed; - bool isMoved; - bool isStationary; - bool isReleased; - bool isShifted; - bool isControl; - bool isMeta; - bool isAlt; - int touchPoints; - QVector points; - float radius; - bool isPinching; - bool isPinchOpening; - - // angles are in degrees - QVector angles; // angle from center to each point - float angle; // the average of the angles - float deltaAngle; // the change in average angle from last event - bool isRotating; - QString rotating; - -private: - void initWithQTouchEvent(const QTouchEvent& event); - void calculateMetaAttributes(const TouchEvent& other); -}; - class WheelEvent { public: WheelEvent(); @@ -86,16 +48,12 @@ public: private: }; -Q_DECLARE_METATYPE(TouchEvent) Q_DECLARE_METATYPE(WheelEvent) Q_DECLARE_METATYPE(SpatialEvent) void registerEventTypes(QScriptEngine* engine); -QScriptValue touchEventToScriptValue(QScriptEngine* engine, const TouchEvent& event); -void touchEventFromScriptValue(const QScriptValue& object, TouchEvent& event); - QScriptValue wheelEventToScriptValue(QScriptEngine* engine, const WheelEvent& event); void wheelEventFromScriptValue(const QScriptValue& object, WheelEvent& event); diff --git a/libraries/script-engine/src/TouchEvent.cpp b/libraries/script-engine/src/TouchEvent.cpp new file mode 100644 index 0000000000..b1cbbc2f15 --- /dev/null +++ b/libraries/script-engine/src/TouchEvent.cpp @@ -0,0 +1,211 @@ +// +// TouchEvent.cpp +// script-engine/src +// +// Created by Stephen Birarda on 2014-10-27. +// 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 +#include +#include + +#include +#include + +#include "TouchEvent.h" + +TouchEvent::TouchEvent() : + x(0.0f), + y(0.0f), + isPressed(false), + isMoved(false), + isStationary(false), + isReleased(false), + isShifted(false), + isControl(false), + isMeta(false), + isAlt(false), + touchPoints(0), + points(), + radius(0.0f), + isPinching(false), + isPinchOpening(false), + angles(), + angle(0.0f), + deltaAngle(0.0f), + isRotating(false), + rotating("none") +{ + +} + +TouchEvent::TouchEvent(const QTouchEvent& event) : + // these values are not set by initWithQTouchEvent() because they only apply to comparing to other events + isPinching(false), + isPinchOpening(false), + deltaAngle(0.0f), + isRotating(false), + rotating("none") +{ + initWithQTouchEvent(event); +} + +TouchEvent::TouchEvent(const QTouchEvent& event, const TouchEvent& other) { + initWithQTouchEvent(event); + calculateMetaAttributes(other); +} + +// returns the angle (in degrees) between two points (note: 0 degrees is 'east') +float angleBetweenPoints(const glm::vec2& a, const glm::vec2& b ) { + glm::vec2 length = b - a; + float angle = DEGREES_PER_RADIAN * std::atan2(length.y, length.x); + if (angle < 0) { + angle += 360.0f; + }; + return angle; +} + +void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) { + // convert the touch points into an average + const QList& tPoints = event.touchPoints(); + float touchAvgX = 0.0f; + float touchAvgY = 0.0f; + touchPoints = tPoints.count(); + if (touchPoints > 1) { + for (int i = 0; i < touchPoints; ++i) { + touchAvgX += tPoints[i].pos().x(); + touchAvgY += tPoints[i].pos().y(); + + // add it to our points vector + glm::vec2 thisPoint(tPoints[i].pos().x(), tPoints[i].pos().y()); + points << thisPoint; + } + touchAvgX /= (float)(touchPoints); + touchAvgY /= (float)(touchPoints); + } else { + // I'm not sure this should ever happen, why would Qt send us a touch event for only one point? + // maybe this happens in the case of a multi-touch where all but the last finger is released? + touchAvgX = tPoints[0].pos().x(); + touchAvgY = tPoints[0].pos().y(); + } + x = touchAvgX; + y = touchAvgY; + + // after calculating the center point (average touch point), determine the maximum radius + // also calculate the rotation angle for each point + float maxRadius = 0.0f; + glm::vec2 center(x,y); + for (int i = 0; i < touchPoints; ++i) { + glm::vec2 touchPoint(tPoints[i].pos().x(), tPoints[i].pos().y()); + float thisRadius = glm::distance(center,touchPoint); + if (thisRadius > maxRadius) { + maxRadius = thisRadius; + } + + // calculate the angle for this point + float thisAngle = angleBetweenPoints(center,touchPoint); + angles << thisAngle; + } + radius = maxRadius; + + // after calculating the angles for each touch point, determine the average angle + float totalAngle = 0.0f; + for (int i = 0; i < touchPoints; ++i) { + totalAngle += angles[i]; + } + angle = totalAngle/(float)touchPoints; + + isPressed = event.touchPointStates().testFlag(Qt::TouchPointPressed); + isMoved = event.touchPointStates().testFlag(Qt::TouchPointMoved); + isStationary = event.touchPointStates().testFlag(Qt::TouchPointStationary); + isReleased = event.touchPointStates().testFlag(Qt::TouchPointReleased); + + // keyboard modifiers + isShifted = event.modifiers().testFlag(Qt::ShiftModifier); + isMeta = event.modifiers().testFlag(Qt::MetaModifier); + isControl = event.modifiers().testFlag(Qt::ControlModifier); + isAlt = event.modifiers().testFlag(Qt::AltModifier); +} + +void TouchEvent::calculateMetaAttributes(const TouchEvent& other) { + // calculate comparative event attributes... + if (other.radius > radius) { + isPinching = true; + isPinchOpening = false; + } else if (other.radius < radius) { + isPinchOpening = true; + isPinching = false; + } else { + isPinching = other.isPinching; + isPinchOpening = other.isPinchOpening; + } + + // determine if the points are rotating... + // note: if the number of touch points change between events, then we don't consider ourselves to be rotating + if (touchPoints == other.touchPoints) { + deltaAngle = angle - other.angle; + if (other.angle < angle) { + isRotating = true; + rotating = "clockwise"; + } else if (other.angle > angle) { + isRotating = true; + rotating = "counterClockwise"; + } else { + isRotating = false; + rotating = "none"; + } + } else { + deltaAngle = 0.0f; + isRotating = false; + rotating = "none"; + } +} + +QScriptValue TouchEvent::toScriptValue(QScriptEngine* engine, const TouchEvent& event) { + QScriptValue obj = engine->newObject(); + obj.setProperty("x", event.x); + obj.setProperty("y", event.y); + obj.setProperty("isPressed", event.isPressed); + obj.setProperty("isMoved", event.isMoved); + obj.setProperty("isStationary", event.isStationary); + obj.setProperty("isReleased", event.isReleased); + obj.setProperty("isShifted", event.isShifted); + obj.setProperty("isMeta", event.isMeta); + obj.setProperty("isControl", event.isControl); + obj.setProperty("isAlt", event.isAlt); + obj.setProperty("touchPoints", event.touchPoints); + + QScriptValue pointsObj = engine->newArray(); + int index = 0; + foreach (glm::vec2 point, event.points) { + QScriptValue thisPoint = vec2toScriptValue(engine, point); + pointsObj.setProperty(index, thisPoint); + index++; + } + obj.setProperty("points", pointsObj); + obj.setProperty("radius", event.radius); + obj.setProperty("isPinching", event.isPinching); + obj.setProperty("isPinchOpening", event.isPinchOpening); + + obj.setProperty("angle", event.angle); + obj.setProperty("deltaAngle", event.deltaAngle); + QScriptValue anglesObj = engine->newArray(); + index = 0; + foreach (float angle, event.angles) { + anglesObj.setProperty(index, angle); + index++; + } + obj.setProperty("angles", anglesObj); + + obj.setProperty("isRotating", event.isRotating); + obj.setProperty("rotating", event.rotating); + return obj; +} + +void TouchEvent::fromScriptValue(const QScriptValue& object, TouchEvent& event) { + // nothing for now... +} diff --git a/libraries/script-engine/src/TouchEvent.h b/libraries/script-engine/src/TouchEvent.h new file mode 100644 index 0000000000..9c1147fecf --- /dev/null +++ b/libraries/script-engine/src/TouchEvent.h @@ -0,0 +1,56 @@ +// +// TouchEvent.h +// script-engine/src +// +// Created by Stephen Birarda on 2014-10-27. +// 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_TouchEvent_h +#define hifi_TouchEvent_h + +#include + +class TouchEvent { +public: + TouchEvent(); + TouchEvent(const QTouchEvent& event); + TouchEvent(const QTouchEvent& event, const TouchEvent& other); + + static QScriptValue toScriptValue(QScriptEngine* engine, const TouchEvent& event); + static void fromScriptValue(const QScriptValue& object, TouchEvent& event); + + float x; + float y; + bool isPressed; + bool isMoved; + bool isStationary; + bool isReleased; + bool isShifted; + bool isControl; + bool isMeta; + bool isAlt; + int touchPoints; + QVector points; + float radius; + bool isPinching; + bool isPinchOpening; + + // angles are in degrees + QVector angles; // angle from center to each point + float angle; // the average of the angles + float deltaAngle; // the change in average angle from last event + bool isRotating; + QString rotating; + +private: + void initWithQTouchEvent(const QTouchEvent& event); + void calculateMetaAttributes(const TouchEvent& other); +}; + +Q_DECLARE_METATYPE(TouchEvent) + +#endif // hifi_TouchEvent_h \ No newline at end of file From 818c97fcafcce411e8d4b0c9a943f97a3916c968 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 14:41:23 -0700 Subject: [PATCH 103/119] move WheelEvent out of EventTypes into its own file --- .../AbstractControllerScriptingInterface.h | 1 + libraries/script-engine/src/EventTypes.cpp | 64 +--------------- libraries/script-engine/src/EventTypes.h | 21 ------ libraries/script-engine/src/WheelEvent.cpp | 75 +++++++++++++++++++ libraries/script-engine/src/WheelEvent.h | 40 ++++++++++ 5 files changed, 118 insertions(+), 83 deletions(-) create mode 100644 libraries/script-engine/src/WheelEvent.cpp create mode 100644 libraries/script-engine/src/WheelEvent.h diff --git a/libraries/script-engine/src/AbstractControllerScriptingInterface.h b/libraries/script-engine/src/AbstractControllerScriptingInterface.h index b594d07f3e..589cbbb089 100644 --- a/libraries/script-engine/src/AbstractControllerScriptingInterface.h +++ b/libraries/script-engine/src/AbstractControllerScriptingInterface.h @@ -21,6 +21,7 @@ #include "KeyEvent.h" #include "MouseEvent.h" #include "TouchEvent.h" +#include "WheelEvent.h" class AbstractInputController : public QObject { Q_OBJECT diff --git a/libraries/script-engine/src/EventTypes.cpp b/libraries/script-engine/src/EventTypes.cpp index 0bb4d2fd9c..e2a868eb8d 100644 --- a/libraries/script-engine/src/EventTypes.cpp +++ b/libraries/script-engine/src/EventTypes.cpp @@ -15,6 +15,7 @@ #include "KeyEvent.h" #include "MouseEvent.h" #include "TouchEvent.h" +#include "WheelEvent.h" #include "EventTypes.h" @@ -22,71 +23,10 @@ void registerEventTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, KeyEvent::toScriptValue, KeyEvent::fromScriptValue); qScriptRegisterMetaType(engine, MouseEvent::toScriptValue, MouseEvent::fromScriptValue); qScriptRegisterMetaType(engine, TouchEvent::toScriptValue, TouchEvent::fromScriptValue); - qScriptRegisterMetaType(engine, wheelEventToScriptValue, wheelEventFromScriptValue); + qScriptRegisterMetaType(engine, WheelEvent::toScriptValue, WheelEvent::fromScriptValue); qScriptRegisterMetaType(engine, spatialEventToScriptValue, spatialEventFromScriptValue); } -WheelEvent::WheelEvent() : - x(0.0f), - y(0.0f), - delta(0.0f), - orientation("UNKNOwN"), - isLeftButton(false), - isRightButton(false), - isMiddleButton(false), - isShifted(false), - isControl(false), - isMeta(false), - isAlt(false) -{ -}; - -WheelEvent::WheelEvent(const QWheelEvent& event) { - x = event.x(); - y = event.y(); - - delta = event.delta(); - if (event.orientation() == Qt::Horizontal) { - orientation = "HORIZONTAL"; - } else { - orientation = "VERTICAL"; - } - - // button pressed state - isLeftButton = (event.buttons().testFlag(Qt::LeftButton)); - isRightButton = (event.buttons().testFlag(Qt::RightButton)); - isMiddleButton = (event.buttons().testFlag(Qt::MiddleButton)); - - // keyboard modifiers - isShifted = event.modifiers().testFlag(Qt::ShiftModifier); - isMeta = event.modifiers().testFlag(Qt::MetaModifier); - isControl = event.modifiers().testFlag(Qt::ControlModifier); - isAlt = event.modifiers().testFlag(Qt::AltModifier); -} - - -QScriptValue wheelEventToScriptValue(QScriptEngine* engine, const WheelEvent& event) { - QScriptValue obj = engine->newObject(); - obj.setProperty("x", event.x); - obj.setProperty("y", event.y); - obj.setProperty("delta", event.delta); - obj.setProperty("orientation", event.orientation); - obj.setProperty("isLeftButton", event.isLeftButton); - obj.setProperty("isRightButton", event.isRightButton); - obj.setProperty("isMiddleButton", event.isMiddleButton); - obj.setProperty("isShifted", event.isShifted); - obj.setProperty("isMeta", event.isMeta); - obj.setProperty("isControl", event.isControl); - obj.setProperty("isAlt", event.isAlt); - return obj; -} - -void wheelEventFromScriptValue(const QScriptValue& object, WheelEvent& event) { - // nothing for now... -} - - - SpatialEvent::SpatialEvent() : locTranslation(0.0f), locRotation(), diff --git a/libraries/script-engine/src/EventTypes.h b/libraries/script-engine/src/EventTypes.h index 54c2934c42..d08d704587 100644 --- a/libraries/script-engine/src/EventTypes.h +++ b/libraries/script-engine/src/EventTypes.h @@ -18,23 +18,6 @@ #include -class WheelEvent { -public: - WheelEvent(); - WheelEvent(const QWheelEvent& event); - int x; - int y; - int delta; - QString orientation; - bool isLeftButton; - bool isRightButton; - bool isMiddleButton; - bool isShifted; - bool isControl; - bool isMeta; - bool isAlt; -}; - class SpatialEvent { public: SpatialEvent(); @@ -48,15 +31,11 @@ public: private: }; -Q_DECLARE_METATYPE(WheelEvent) Q_DECLARE_METATYPE(SpatialEvent) void registerEventTypes(QScriptEngine* engine); -QScriptValue wheelEventToScriptValue(QScriptEngine* engine, const WheelEvent& event); -void wheelEventFromScriptValue(const QScriptValue& object, WheelEvent& event); - QScriptValue spatialEventToScriptValue(QScriptEngine* engine, const SpatialEvent& event); void spatialEventFromScriptValue(const QScriptValue& object, SpatialEvent& event); diff --git a/libraries/script-engine/src/WheelEvent.cpp b/libraries/script-engine/src/WheelEvent.cpp new file mode 100644 index 0000000000..b329ef58c8 --- /dev/null +++ b/libraries/script-engine/src/WheelEvent.cpp @@ -0,0 +1,75 @@ +// +// WheelEvent.cpp +// script-engine/src +// +// Created by Stephen Birarda on 2014-10-27. +// 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 +#include + +#include "WheelEvent.h" + +WheelEvent::WheelEvent() : + x(0.0f), + y(0.0f), + delta(0.0f), + orientation("UNKNOwN"), + isLeftButton(false), + isRightButton(false), + isMiddleButton(false), + isShifted(false), + isControl(false), + isMeta(false), + isAlt(false) +{ + +} + +WheelEvent::WheelEvent(const QWheelEvent& event) { + x = event.x(); + y = event.y(); + + delta = event.delta(); + if (event.orientation() == Qt::Horizontal) { + orientation = "HORIZONTAL"; + } else { + orientation = "VERTICAL"; + } + + // button pressed state + isLeftButton = (event.buttons().testFlag(Qt::LeftButton)); + isRightButton = (event.buttons().testFlag(Qt::RightButton)); + isMiddleButton = (event.buttons().testFlag(Qt::MiddleButton)); + + // keyboard modifiers + isShifted = event.modifiers().testFlag(Qt::ShiftModifier); + isMeta = event.modifiers().testFlag(Qt::MetaModifier); + isControl = event.modifiers().testFlag(Qt::ControlModifier); + isAlt = event.modifiers().testFlag(Qt::AltModifier); +} + + +QScriptValue WheelEvent::toScriptValue(QScriptEngine* engine, const WheelEvent& event) { + QScriptValue obj = engine->newObject(); + obj.setProperty("x", event.x); + obj.setProperty("y", event.y); + obj.setProperty("delta", event.delta); + obj.setProperty("orientation", event.orientation); + obj.setProperty("isLeftButton", event.isLeftButton); + obj.setProperty("isRightButton", event.isRightButton); + obj.setProperty("isMiddleButton", event.isMiddleButton); + obj.setProperty("isShifted", event.isShifted); + obj.setProperty("isMeta", event.isMeta); + obj.setProperty("isControl", event.isControl); + obj.setProperty("isAlt", event.isAlt); + return obj; +} + +void WheelEvent::fromScriptValue(const QScriptValue& object, WheelEvent& event) { + // nothing for now... +} \ No newline at end of file diff --git a/libraries/script-engine/src/WheelEvent.h b/libraries/script-engine/src/WheelEvent.h new file mode 100644 index 0000000000..edac4bc3c3 --- /dev/null +++ b/libraries/script-engine/src/WheelEvent.h @@ -0,0 +1,40 @@ +// +// WheelEvent.h +// script-engine/src +// +// Created by Stephen Birarda on 2014-10-27. +// 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_WheelEvent_h +#define hifi_WheelEvent_h + +#include + +class WheelEvent { +public: + WheelEvent(); + WheelEvent(const QWheelEvent& event); + + static QScriptValue toScriptValue(QScriptEngine* engine, const WheelEvent& event); + static void fromScriptValue(const QScriptValue& object, WheelEvent& event); + + int x; + int y; + int delta; + QString orientation; + bool isLeftButton; + bool isRightButton; + bool isMiddleButton; + bool isShifted; + bool isControl; + bool isMeta; + bool isAlt; +}; + +Q_DECLARE_METATYPE(WheelEvent) + +#endif // hifi_WheelEvent_h \ No newline at end of file From 15f8b3006b30146f0802f0fa3843957a46134649 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 27 Oct 2014 14:45:34 -0700 Subject: [PATCH 104/119] Remove debugging, fix streaming bug. --- assignment-client/src/metavoxels/MetavoxelServer.cpp | 5 ----- libraries/metavoxels/src/MetavoxelClientManager.cpp | 8 +------- libraries/metavoxels/src/MetavoxelData.cpp | 3 +++ 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index 43fd5f5c16..81e86dbf11 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -223,11 +223,7 @@ void MetavoxelSession::update() { _sender->getData().writeDelta(sendRecord->getData(), sendRecord->getLOD(), out, _lod); out.flush(); int end = _sequencer.getOutputStream().getUnderlying().device()->pos(); - QDebug debug = qDebug() << "from" << sendRecord->getLOD().position.x << sendRecord->getLOD().position.y << sendRecord->getLOD().position.z << "to" << - _lod.position.x << _lod.position.y << _lod.position.z << _lodPacketNumber << (_sequencer.getOutgoingPacketNumber() + 1); if (end > _sequencer.getMaxPacketSize()) { - debug << "reliable" << (_reliableDeltaID + 1); - // we need to send the delta on the reliable channel _reliableDeltaChannel = _sequencer.getReliableOutputChannel(RELIABLE_DELTA_CHANNEL_INDEX); _reliableDeltaChannel->startMessage(); @@ -246,7 +242,6 @@ void MetavoxelSession::update() { _sequencer.endPacket(); } else { - debug << "unreliable"; _sequencer.endPacket(); } diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index af83fdc869..cc5d7ef29d 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -297,10 +297,7 @@ void MetavoxelClient::writeUpdateMessage(Bitstream& out) { void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { int userType = message.userType(); if (userType == MetavoxelDeltaMessage::Type) { - if (_reliableDeltaChannel) { - qDebug() << "from" << _remoteDataLOD.position.x << _remoteDataLOD.position.y << _remoteDataLOD.position.z << - "to" << _reliableDeltaLOD.position.x << _reliableDeltaLOD.position.y << _reliableDeltaLOD.position.z << - _sequencer.getIncomingPacketNumber() << "reliable" << _reliableDeltaID; + if (_reliableDeltaChannel) { MetavoxelData reference = _remoteData; MetavoxelLOD referenceLOD = _remoteDataLOD; _remoteData.readDelta(reference, referenceLOD, in, _remoteDataLOD = _reliableDeltaLOD); @@ -310,9 +307,6 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { } else { PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord(); - qDebug() << "from" << receiveRecord->getLOD().position.x << receiveRecord->getLOD().position.y << receiveRecord->getLOD().position.z << - "to" << getLastAcknowledgedSendRecord()->getLOD().position.x << getLastAcknowledgedSendRecord()->getLOD().position.y << getLastAcknowledgedSendRecord()->getLOD().position.z << - _sequencer.getIncomingPacketNumber() << "unreliable"; _remoteData.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, _remoteDataLOD = getLastAcknowledgedSendRecord()->getLOD()); in.reset(); diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 2bd28de784..2f43f8f4ae 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -1040,6 +1040,9 @@ MetavoxelNode* MetavoxelNode::readSubdivision(MetavoxelStreamState& state) { } void MetavoxelNode::writeSubdivision(MetavoxelStreamState& state) const { + if (!state.shouldSubdivide()) { + return; + } bool leaf = isLeaf(); if (!state.shouldSubdivideReference()) { state.base.stream << leaf; From fd514ccfc9fd14cc06b7204dca53c55ada9b8497 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 27 Oct 2014 14:47:31 -0700 Subject: [PATCH 105/119] Fixed the cmake so if NSIGHT is not available then no problem --- interface/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 194558e580..d9cf40baa3 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -230,13 +230,16 @@ else (APPLE) # we're using static GLEW, so define GLEW_STATIC add_definitions(-DGLEW_STATIC) + target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" "${NSIGHT_LIBRARIES}" wsock32.lib opengl32.lib) + + # try to find the Nsight package and add it to the build if we find it find_package(NSIGHT) if (NSIGHT_FOUND) include_directories(${NSIGHT_INCLUDE_DIRS}) add_definitions(-DNSIGHT_FOUND) + target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}") endif () - target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" "${NSIGHT_LIBRARIES}" wsock32.lib opengl32.lib) endif() endif (APPLE) From 76493597dadf72e6bb1a5f7e6d91bbd055225296 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 14:47:44 -0700 Subject: [PATCH 106/119] move SpatialEvent from EventTypes to its own file --- .../AbstractControllerScriptingInterface.h | 1 + libraries/script-engine/src/EventTypes.cpp | 37 +-------------- libraries/script-engine/src/EventTypes.h | 25 +--------- libraries/script-engine/src/SpatialEvent.cpp | 46 +++++++++++++++++++ libraries/script-engine/src/SpatialEvent.h | 36 +++++++++++++++ 5 files changed, 86 insertions(+), 59 deletions(-) create mode 100644 libraries/script-engine/src/SpatialEvent.cpp create mode 100644 libraries/script-engine/src/SpatialEvent.h diff --git a/libraries/script-engine/src/AbstractControllerScriptingInterface.h b/libraries/script-engine/src/AbstractControllerScriptingInterface.h index 589cbbb089..a71ab5332b 100644 --- a/libraries/script-engine/src/AbstractControllerScriptingInterface.h +++ b/libraries/script-engine/src/AbstractControllerScriptingInterface.h @@ -20,6 +20,7 @@ #include "EventTypes.h" #include "KeyEvent.h" #include "MouseEvent.h" +#include "SpatialEvent.h" #include "TouchEvent.h" #include "WheelEvent.h" diff --git a/libraries/script-engine/src/EventTypes.cpp b/libraries/script-engine/src/EventTypes.cpp index e2a868eb8d..84838cfd33 100644 --- a/libraries/script-engine/src/EventTypes.cpp +++ b/libraries/script-engine/src/EventTypes.cpp @@ -9,11 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include - #include "KeyEvent.h" #include "MouseEvent.h" +#include "SpatialEvent.h" #include "TouchEvent.h" #include "WheelEvent.h" @@ -24,36 +22,5 @@ void registerEventTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, MouseEvent::toScriptValue, MouseEvent::fromScriptValue); qScriptRegisterMetaType(engine, TouchEvent::toScriptValue, TouchEvent::fromScriptValue); qScriptRegisterMetaType(engine, WheelEvent::toScriptValue, WheelEvent::fromScriptValue); - qScriptRegisterMetaType(engine, spatialEventToScriptValue, spatialEventFromScriptValue); -} - -SpatialEvent::SpatialEvent() : - locTranslation(0.0f), - locRotation(), - absTranslation(0.0f), - absRotation() -{ -}; - -SpatialEvent::SpatialEvent(const SpatialEvent& event) { - locTranslation = event.locTranslation; - locRotation = event.locRotation; - absTranslation = event.absTranslation; - absRotation = event.absRotation; -} - - -QScriptValue spatialEventToScriptValue(QScriptEngine* engine, const SpatialEvent& event) { - QScriptValue obj = engine->newObject(); - - obj.setProperty("locTranslation", vec3toScriptValue(engine, event.locTranslation) ); - obj.setProperty("locRotation", quatToScriptValue(engine, event.locRotation) ); - obj.setProperty("absTranslation", vec3toScriptValue(engine, event.absTranslation) ); - obj.setProperty("absRotation", quatToScriptValue(engine, event.absRotation) ); - - return obj; -} - -void spatialEventFromScriptValue(const QScriptValue& object,SpatialEvent& event) { - // nothing for now... + qScriptRegisterMetaType(engine, SpatialEvent::toScriptValue, SpatialEvent::fromScriptValue); } diff --git a/libraries/script-engine/src/EventTypes.h b/libraries/script-engine/src/EventTypes.h index d08d704587..fc808ea560 100644 --- a/libraries/script-engine/src/EventTypes.h +++ b/libraries/script-engine/src/EventTypes.h @@ -12,31 +12,8 @@ #ifndef hifi_EventTypes_h #define hifi_EventTypes_h -#include - -#include - -#include - -class SpatialEvent { -public: - SpatialEvent(); - SpatialEvent(const SpatialEvent& other); - - glm::vec3 locTranslation; - glm::quat locRotation; - glm::vec3 absTranslation; - glm::quat absRotation; - -private: -}; - -Q_DECLARE_METATYPE(SpatialEvent) +#include void registerEventTypes(QScriptEngine* engine); - -QScriptValue spatialEventToScriptValue(QScriptEngine* engine, const SpatialEvent& event); -void spatialEventFromScriptValue(const QScriptValue& object, SpatialEvent& event); - #endif // hifi_EventTypes_h diff --git a/libraries/script-engine/src/SpatialEvent.cpp b/libraries/script-engine/src/SpatialEvent.cpp new file mode 100644 index 0000000000..f20a0c2b1e --- /dev/null +++ b/libraries/script-engine/src/SpatialEvent.cpp @@ -0,0 +1,46 @@ +// +// SpatialEvent.cpp +// script-engine/src +// +// Created by Stephen Birarda on 2014-10-27. +// 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 + +#include "SpatialEvent.h" + +SpatialEvent::SpatialEvent() : + locTranslation(0.0f), + locRotation(), + absTranslation(0.0f), + absRotation() +{ + +} + +SpatialEvent::SpatialEvent(const SpatialEvent& event) { + locTranslation = event.locTranslation; + locRotation = event.locRotation; + absTranslation = event.absTranslation; + absRotation = event.absRotation; +} + + +QScriptValue SpatialEvent::toScriptValue(QScriptEngine* engine, const SpatialEvent& event) { + QScriptValue obj = engine->newObject(); + + obj.setProperty("locTranslation", vec3toScriptValue(engine, event.locTranslation) ); + obj.setProperty("locRotation", quatToScriptValue(engine, event.locRotation) ); + obj.setProperty("absTranslation", vec3toScriptValue(engine, event.absTranslation) ); + obj.setProperty("absRotation", quatToScriptValue(engine, event.absRotation) ); + + return obj; +} + +void SpatialEvent::fromScriptValue(const QScriptValue& object,SpatialEvent& event) { + // nothing for now... +} \ No newline at end of file diff --git a/libraries/script-engine/src/SpatialEvent.h b/libraries/script-engine/src/SpatialEvent.h new file mode 100644 index 0000000000..e0fcc03824 --- /dev/null +++ b/libraries/script-engine/src/SpatialEvent.h @@ -0,0 +1,36 @@ +// +// SpatialEvent.h +// script-engine/src +// +// Created by Stephen Birarda on 2014-10-27. +// 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_SpatialEvent_h +#define hifi_SpatialEvent_h + +#include +#include + +#include + +class SpatialEvent { +public: + SpatialEvent(); + SpatialEvent(const SpatialEvent& other); + + static QScriptValue toScriptValue(QScriptEngine* engine, const SpatialEvent& event); + static void fromScriptValue(const QScriptValue& object, SpatialEvent& event); + + glm::vec3 locTranslation; + glm::quat locRotation; + glm::vec3 absTranslation; + glm::quat absRotation; +}; + +Q_DECLARE_METATYPE(SpatialEvent) + +#endif // hifi_SpatialEvent_h \ No newline at end of file From 7bcc267cb5c87d16a0e49e08ae7639f1061e666f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 27 Oct 2014 15:01:06 -0700 Subject: [PATCH 107/119] Fix for crash on exit. --- interface/src/MetavoxelSystem.cpp | 6 ++++++ interface/src/MetavoxelSystem.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index a9bdad8148..8e5ae8d9b1 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -48,6 +48,12 @@ MetavoxelSystem::NetworkSimulation::NetworkSimulation(float dropRate, float repe bandwidthLimit(bandwidthLimit) { } +MetavoxelSystem::~MetavoxelSystem() { + // kill the updater before we delete our network simulation objects + _updater->thread()->quit(); + _updater->thread()->wait(); +} + void MetavoxelSystem::init() { MetavoxelClientManager::init(); DefaultMetavoxelRendererImplementation::init(); diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 14a24eea59..08cc1098ca 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -43,6 +43,8 @@ public: int maximumDelay = 0, int bandwidthLimit = 0); }; + virtual ~MetavoxelSystem(); + virtual void init(); virtual MetavoxelLOD getLOD(); From 4ab90ce49ce81dd6f3e8b8ce88a19610f69779b5 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 27 Oct 2014 15:04:03 -0700 Subject: [PATCH 108/119] Avoid killing the updater twice. --- interface/src/MetavoxelSystem.cpp | 1 + libraries/metavoxels/src/MetavoxelClientManager.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 8e5ae8d9b1..20e05e779e 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -52,6 +52,7 @@ MetavoxelSystem::~MetavoxelSystem() { // kill the updater before we delete our network simulation objects _updater->thread()->quit(); _updater->thread()->wait(); + _updater = NULL; } void MetavoxelSystem::init() { diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index cc5d7ef29d..f1c086da67 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -27,8 +27,10 @@ MetavoxelClientManager::MetavoxelClientManager() : } MetavoxelClientManager::~MetavoxelClientManager() { - _updater->thread()->quit(); - _updater->thread()->wait(); + if (_updater) { + _updater->thread()->quit(); + _updater->thread()->wait(); + } } void MetavoxelClientManager::init() { From c3fe7c74976528dc31d2f100096fca44660f4001 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 15:21:47 -0700 Subject: [PATCH 109/119] send global HFActionEvent from ControllerScriptingInterface --- interface/src/Application.cpp | 4 ++++ .../src/scripting/ControllerScriptingInterface.cpp | 8 ++++++++ .../src/scripting/ControllerScriptingInterface.h | 4 ++++ .../src/AbstractControllerScriptingInterface.h | 8 ++++---- libraries/script-engine/src/EventTypes.cpp | 2 ++ libraries/script-engine/src/HFActionEvent.cpp | 13 ++++++++++++- libraries/script-engine/src/HFActionEvent.h | 12 ++++++++++-- libraries/script-engine/src/HFMetaEvent.h | 1 + libraries/script-engine/src/ScriptEngine.cpp | 1 + 9 files changed, 46 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 81d8098002..02fdbbb534 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -835,6 +835,10 @@ bool Application::event(QEvent* event) { return false; } + + if (HFActionEvent::types().contains(event->type())) { + _controllerScriptingInterface.handleMetaEvent(static_cast(event)); + } return QApplication::event(event); } diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index f2e65a6e28..b2389e3df2 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -20,8 +20,16 @@ ControllerScriptingInterface::ControllerScriptingInterface() : _touchCaptured(false), _wheelCaptured(false) { + } +void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) { + if (event->type() == HFActionEvent::startType()) { + emitActionStartEvent(static_cast(event)); + } else if (event->type() == HFActionEvent::endType()) { + emitActionEndEvent(static_cast(event)); + } +} const PalmData* ControllerScriptingInterface::getPrimaryPalm() const { int leftPalmIndex, rightPalmIndex; diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h index 916c87d85c..c38ac888e4 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -56,6 +56,10 @@ public: ControllerScriptingInterface(); void emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); } void emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); } + + void handleMetaEvent(HFMetaEvent* event); + void emitActionStartEvent(HFActionEvent* event) { emit actionStartEvent(*event); } + void emitActionEndEvent(HFActionEvent* event) { emit actionEndEvent(*event); } void emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseMoveEvent(MouseEvent(*event, deviceID)); } void emitMousePressEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mousePressEvent(MouseEvent(*event, deviceID)); } diff --git a/libraries/script-engine/src/AbstractControllerScriptingInterface.h b/libraries/script-engine/src/AbstractControllerScriptingInterface.h index a71ab5332b..cfb7d6bb89 100644 --- a/libraries/script-engine/src/AbstractControllerScriptingInterface.h +++ b/libraries/script-engine/src/AbstractControllerScriptingInterface.h @@ -17,7 +17,7 @@ #include #include -#include "EventTypes.h" +#include "HFActionEvent.h" #include "KeyEvent.h" #include "MouseEvent.h" #include "SpatialEvent.h" @@ -93,9 +93,9 @@ public slots: signals: void keyPressEvent(const KeyEvent& event); void keyReleaseEvent(const KeyEvent& event); -// -// void actionStartEvent(const HFActionEvent& event); -// void actionEndEvent(const HFActionEvent& event); + + void actionStartEvent(const HFActionEvent& event); + void actionEndEvent(const HFActionEvent& event); void mouseMoveEvent(const MouseEvent& event, unsigned int deviceID = 0); void mousePressEvent(const MouseEvent& event, unsigned int deviceID = 0); diff --git a/libraries/script-engine/src/EventTypes.cpp b/libraries/script-engine/src/EventTypes.cpp index 84838cfd33..ce3c82e121 100644 --- a/libraries/script-engine/src/EventTypes.cpp +++ b/libraries/script-engine/src/EventTypes.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "HFActionEvent.h" #include "KeyEvent.h" #include "MouseEvent.h" #include "SpatialEvent.h" @@ -18,6 +19,7 @@ #include "EventTypes.h" void registerEventTypes(QScriptEngine* engine) { + qScriptRegisterMetaType(engine, HFActionEvent::toScriptValue, HFActionEvent::fromScriptValue); qScriptRegisterMetaType(engine, KeyEvent::toScriptValue, KeyEvent::fromScriptValue); qScriptRegisterMetaType(engine, MouseEvent::toScriptValue, MouseEvent::fromScriptValue); qScriptRegisterMetaType(engine, TouchEvent::toScriptValue, TouchEvent::fromScriptValue); diff --git a/libraries/script-engine/src/HFActionEvent.cpp b/libraries/script-engine/src/HFActionEvent.cpp index e393a2f332..e73b0787d2 100644 --- a/libraries/script-engine/src/HFActionEvent.cpp +++ b/libraries/script-engine/src/HFActionEvent.cpp @@ -13,7 +13,7 @@ HFActionEvent::HFActionEvent(QEvent::Type type, const QPointF& localPosition) : HFMetaEvent(type), - _localPosition(localPosition) + localPosition(localPosition) { } @@ -28,3 +28,14 @@ QEvent::Type HFActionEvent::endType() { return endType; } +QScriptValue HFActionEvent::toScriptValue(QScriptEngine* engine, const HFActionEvent& event) { + QScriptValue obj = engine->newObject(); + obj.setProperty("x", event.localPosition.x()); + obj.setProperty("y", event.localPosition.y()); + return obj; +} + +void HFActionEvent::fromScriptValue(const QScriptValue& object, HFActionEvent& event) { + // not yet implemented +} + diff --git a/libraries/script-engine/src/HFActionEvent.h b/libraries/script-engine/src/HFActionEvent.h index 3371312755..7b13160199 100644 --- a/libraries/script-engine/src/HFActionEvent.h +++ b/libraries/script-engine/src/HFActionEvent.h @@ -14,14 +14,22 @@ #include "HFMetaEvent.h" +#include + class HFActionEvent : public HFMetaEvent { public: + HFActionEvent() {}; HFActionEvent(QEvent::Type type, const QPointF& localPosition); static QEvent::Type startType(); static QEvent::Type endType(); -private: - QPointF _localPosition; + + static QScriptValue toScriptValue(QScriptEngine* engine, const HFActionEvent& event); + static void fromScriptValue(const QScriptValue& object, HFActionEvent& event); + + QPointF localPosition; }; +Q_DECLARE_METATYPE(HFActionEvent) + #endif // hifi_HFActionEvent_h \ No newline at end of file diff --git a/libraries/script-engine/src/HFMetaEvent.h b/libraries/script-engine/src/HFMetaEvent.h index 8fbdfab1fa..56db32d7aa 100644 --- a/libraries/script-engine/src/HFMetaEvent.h +++ b/libraries/script-engine/src/HFMetaEvent.h @@ -16,6 +16,7 @@ class HFMetaEvent : public QEvent { public: + HFMetaEvent() : QEvent(HFMetaEvent::newEventType()) {}; HFMetaEvent(QEvent::Type type) : QEvent(type) {}; static const QSet& types() { return HFMetaEvent::_types; } protected: diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 3ccd0a74c3..fb98124fc9 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -35,6 +35,7 @@ #include "AnimationObject.h" #include "ArrayBufferViewClass.h" #include "DataViewClass.h" +#include "EventTypes.h" #include "MenuItemProperties.h" #include "LocalVoxels.h" #include "ScriptEngine.h" From a12e0dd0dc02fae636facfdfc655ccb09c377942 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 15:27:27 -0700 Subject: [PATCH 110/119] fix HFActionEvent headers for new placement --- libraries/script-engine/src/HFActionEvent.cpp | 2 +- libraries/script-engine/src/HFActionEvent.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/script-engine/src/HFActionEvent.cpp b/libraries/script-engine/src/HFActionEvent.cpp index e73b0787d2..8a966a3fb3 100644 --- a/libraries/script-engine/src/HFActionEvent.cpp +++ b/libraries/script-engine/src/HFActionEvent.cpp @@ -1,6 +1,6 @@ // // HFActionEvent.cpp -// interface/src/events +// script-engine/src // // Created by Stephen Birarda on 2014-10-27. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/script-engine/src/HFActionEvent.h b/libraries/script-engine/src/HFActionEvent.h index 7b13160199..c094161053 100644 --- a/libraries/script-engine/src/HFActionEvent.h +++ b/libraries/script-engine/src/HFActionEvent.h @@ -1,6 +1,6 @@ // // HFActionEvent.h -// interface/src/events +// script-engine/src // // Created by Stephen Birarda on 2014-10-27. // Copyright 2014 High Fidelity, Inc. From 8556b8b95de299ec22455c391b466a03bd69a94b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 15:28:02 -0700 Subject: [PATCH 111/119] fix HFMetaEvent headers for new placement --- libraries/script-engine/src/HFMetaEvent.cpp | 2 +- libraries/script-engine/src/HFMetaEvent.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/script-engine/src/HFMetaEvent.cpp b/libraries/script-engine/src/HFMetaEvent.cpp index c9d77868cd..f06c349996 100644 --- a/libraries/script-engine/src/HFMetaEvent.cpp +++ b/libraries/script-engine/src/HFMetaEvent.cpp @@ -1,6 +1,6 @@ // // HFMetaEvent.cpp -// interface/src/events +// script-engine/src // // Created by Stephen Birarda on 2014-10-27. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/script-engine/src/HFMetaEvent.h b/libraries/script-engine/src/HFMetaEvent.h index 56db32d7aa..2fd71b8a3b 100644 --- a/libraries/script-engine/src/HFMetaEvent.h +++ b/libraries/script-engine/src/HFMetaEvent.h @@ -1,6 +1,6 @@ // // HFMetaEvent.h -// interface/src/events +// script-engine/src // // Created by Stephen Birarda on 2014-10-27. // Copyright 2014 High Fidelity, Inc. From 7b5115c35ff6e680336ddfa8d40863ba4c2cdc1d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 15:37:31 -0700 Subject: [PATCH 112/119] add a new meta event, HFCancelEvent --- .../ControllerScriptingInterface.cpp | 13 +++++++-- .../scripting/ControllerScriptingInterface.h | 2 -- .../AbstractControllerScriptingInterface.h | 3 ++ libraries/script-engine/src/HFCancelEvent.cpp | 28 ++++++++++++++++++ libraries/script-engine/src/HFCancelEvent.h | 29 +++++++++++++++++++ 5 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 libraries/script-engine/src/HFCancelEvent.cpp create mode 100644 libraries/script-engine/src/HFCancelEvent.h diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index b2389e3df2..090bbea66e 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -10,10 +10,13 @@ // #include +#include + #include "Application.h" +#include "devices/MotionTracker.h" #include "devices/SixenseManager.h" #include "ControllerScriptingInterface.h" -#include "devices/MotionTracker.h" + ControllerScriptingInterface::ControllerScriptingInterface() : _mouseCaptured(false), @@ -25,9 +28,13 @@ ControllerScriptingInterface::ControllerScriptingInterface() : void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) { if (event->type() == HFActionEvent::startType()) { - emitActionStartEvent(static_cast(event)); + emit actionStartEvent(static_cast(*event)); } else if (event->type() == HFActionEvent::endType()) { - emitActionEndEvent(static_cast(event)); + emit actionEndEvent(static_cast(*event)); + } else if (event->type() == HFCancelEvent::startType()) { + emit cancelStartEvent(); + } else if (event->type() == HFCancelEvent::endType()) { + emit cancelEndEvent(); } } diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h index c38ac888e4..29921008e6 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -58,8 +58,6 @@ public: void emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); } void handleMetaEvent(HFMetaEvent* event); - void emitActionStartEvent(HFActionEvent* event) { emit actionStartEvent(*event); } - void emitActionEndEvent(HFActionEvent* event) { emit actionEndEvent(*event); } void emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseMoveEvent(MouseEvent(*event, deviceID)); } void emitMousePressEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mousePressEvent(MouseEvent(*event, deviceID)); } diff --git a/libraries/script-engine/src/AbstractControllerScriptingInterface.h b/libraries/script-engine/src/AbstractControllerScriptingInterface.h index cfb7d6bb89..1eff64eb42 100644 --- a/libraries/script-engine/src/AbstractControllerScriptingInterface.h +++ b/libraries/script-engine/src/AbstractControllerScriptingInterface.h @@ -96,6 +96,9 @@ signals: void actionStartEvent(const HFActionEvent& event); void actionEndEvent(const HFActionEvent& event); + + void cancelStartEvent(); + void cancelEndEvent(); void mouseMoveEvent(const MouseEvent& event, unsigned int deviceID = 0); void mousePressEvent(const MouseEvent& event, unsigned int deviceID = 0); diff --git a/libraries/script-engine/src/HFCancelEvent.cpp b/libraries/script-engine/src/HFCancelEvent.cpp new file mode 100644 index 0000000000..f6462eea49 --- /dev/null +++ b/libraries/script-engine/src/HFCancelEvent.cpp @@ -0,0 +1,28 @@ +// +// HFCancelEvent.cpp +// script-engine/src +// +// Created by Stephen Birarda on 2014-10-27. +// 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 "HFCancelEvent.h" + +HFCancelEvent::HFCancelEvent(QEvent::Type type) : + HFMetaEvent(type) +{ + +} + +QEvent::Type HFCancelEvent::startType() { + static QEvent::Type startType = HFMetaEvent::newEventType(); + return startType; +} + +QEvent::Type HFCancelEvent::endType() { + static QEvent::Type endType = HFMetaEvent::newEventType(); + return endType; +} diff --git a/libraries/script-engine/src/HFCancelEvent.h b/libraries/script-engine/src/HFCancelEvent.h new file mode 100644 index 0000000000..8e3a761296 --- /dev/null +++ b/libraries/script-engine/src/HFCancelEvent.h @@ -0,0 +1,29 @@ +// +// HFCancelEvent.h +// script-engine/src +// +// Created by Stephen Birarda on 2014-10-27. +// 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_HFCancelEvent_h +#define hifi_HFCancelEvent_h + +#include +#include + +#include "HFMetaEvent.h" + +class HFCancelEvent : public HFMetaEvent { +public: + HFCancelEvent() {}; + HFCancelEvent(QEvent::Type type); + + static QEvent::Type startType(); + static QEvent::Type endType(); +}; + +#endif // hifi_HFCancelEvent_h \ No newline at end of file From 04e7e979aa8b1a7b14f439c953208230aa9c2830 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 15:42:40 -0700 Subject: [PATCH 113/119] bubble up HFCancelEvent from ESC key --- interface/src/Application.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 02fdbbb534..9b83e6211c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -1101,9 +1102,15 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_Equal: _myAvatar->resetSize(); break; - case Qt::Key_Escape: + case Qt::Key_Escape: { OculusManager::abandonCalibration(); + + // this fires the HFCancelEvent + HFCancelEvent startCancelEvent(HFCancelEvent::startType()); + sendEvent(this, &startCancelEvent); + break; + } default: event->ignore(); break; @@ -1174,6 +1181,13 @@ void Application::keyReleaseEvent(QKeyEvent* event) { case Qt::Key_Alt: _myAvatar->clearDriveKeys(); break; + case Qt::Key_Escape: { + // this ends the HFCancelEvent + HFCancelEvent endCancelEvent(HFCancelEvent::endType()); + sendEvent(this, &endCancelEvent); + + break; + } default: event->ignore(); break; From 8a9f2d172a638affb774f923c23c853d6a776a63 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 15:51:59 -0700 Subject: [PATCH 114/119] rename HFCancelEvent to HFBackEvent, fire from joystick --- interface/src/Application.cpp | 10 +++++----- .../src/scripting/ControllerScriptingInterface.cpp | 6 +++--- .../src/scripting/JoystickScriptingInterface.cpp | 13 +++++++++++++ .../src/{HFCancelEvent.cpp => HFBackEvent.cpp} | 10 +++++----- .../src/{HFCancelEvent.h => HFBackEvent.h} | 14 +++++++------- 5 files changed, 33 insertions(+), 20 deletions(-) rename libraries/script-engine/src/{HFCancelEvent.cpp => HFBackEvent.cpp} (72%) rename libraries/script-engine/src/{HFCancelEvent.h => HFBackEvent.h} (66%) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9b83e6211c..b1f694671e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -56,7 +56,7 @@ #include #include #include -#include +#include #include #include #include @@ -1106,8 +1106,8 @@ void Application::keyPressEvent(QKeyEvent* event) { OculusManager::abandonCalibration(); // this fires the HFCancelEvent - HFCancelEvent startCancelEvent(HFCancelEvent::startType()); - sendEvent(this, &startCancelEvent); + HFBackEvent startBackEvent(HFBackEvent::startType()); + sendEvent(this, &startBackEvent); break; } @@ -1183,8 +1183,8 @@ void Application::keyReleaseEvent(QKeyEvent* event) { break; case Qt::Key_Escape: { // this ends the HFCancelEvent - HFCancelEvent endCancelEvent(HFCancelEvent::endType()); - sendEvent(this, &endCancelEvent); + HFBackEvent endBackEvent(HFBackEvent::endType()); + sendEvent(this, &endBackEvent); break; } diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index 090bbea66e..d2cc847ab5 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -10,7 +10,7 @@ // #include -#include +#include #include "Application.h" #include "devices/MotionTracker.h" @@ -31,9 +31,9 @@ void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) { emit actionStartEvent(static_cast(*event)); } else if (event->type() == HFActionEvent::endType()) { emit actionEndEvent(static_cast(*event)); - } else if (event->type() == HFCancelEvent::startType()) { + } else if (event->type() == HFBackEvent::startType()) { emit cancelStartEvent(); - } else if (event->type() == HFCancelEvent::endType()) { + } else if (event->type() == HFBackEvent::endType()) { emit cancelEndEvent(); } } diff --git a/interface/src/scripting/JoystickScriptingInterface.cpp b/interface/src/scripting/JoystickScriptingInterface.cpp index ced063c8fe..9375f80045 100644 --- a/interface/src/scripting/JoystickScriptingInterface.cpp +++ b/interface/src/scripting/JoystickScriptingInterface.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #include @@ -17,6 +18,7 @@ #undef main #endif +#include #include #include "JoystickScriptingInterface.h" @@ -108,6 +110,17 @@ void JoystickScriptingInterface::update() { if (joystick) { joystick->handleButtonEvent(event.cbutton); } + + if (event.cbutton.button == SDL_CONTROLLER_BUTTON_BACK) { + // this will either start or stop a cancel event + QEvent::Type backType = (event.type == SDL_CONTROLLERBUTTONDOWN) + ? HFBackEvent::startType() + : HFBackEvent::endType(); + HFBackEvent backEvent(backType); + + qApp->sendEvent(qApp, &backEvent); + } + } else if (event.type == SDL_CONTROLLERDEVICEADDED) { SDL_GameController* controller = SDL_GameControllerOpen(event.cdevice.which); diff --git a/libraries/script-engine/src/HFCancelEvent.cpp b/libraries/script-engine/src/HFBackEvent.cpp similarity index 72% rename from libraries/script-engine/src/HFCancelEvent.cpp rename to libraries/script-engine/src/HFBackEvent.cpp index f6462eea49..c67b2e3431 100644 --- a/libraries/script-engine/src/HFCancelEvent.cpp +++ b/libraries/script-engine/src/HFBackEvent.cpp @@ -1,5 +1,5 @@ // -// HFCancelEvent.cpp +// HFBackEvent.cpp // script-engine/src // // Created by Stephen Birarda on 2014-10-27. @@ -9,20 +9,20 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "HFCancelEvent.h" +#include "HFBackEvent.h" -HFCancelEvent::HFCancelEvent(QEvent::Type type) : +HFBackEvent::HFBackEvent(QEvent::Type type) : HFMetaEvent(type) { } -QEvent::Type HFCancelEvent::startType() { +QEvent::Type HFBackEvent::startType() { static QEvent::Type startType = HFMetaEvent::newEventType(); return startType; } -QEvent::Type HFCancelEvent::endType() { +QEvent::Type HFBackEvent::endType() { static QEvent::Type endType = HFMetaEvent::newEventType(); return endType; } diff --git a/libraries/script-engine/src/HFCancelEvent.h b/libraries/script-engine/src/HFBackEvent.h similarity index 66% rename from libraries/script-engine/src/HFCancelEvent.h rename to libraries/script-engine/src/HFBackEvent.h index 8e3a761296..bb7b348ea7 100644 --- a/libraries/script-engine/src/HFCancelEvent.h +++ b/libraries/script-engine/src/HFBackEvent.h @@ -1,5 +1,5 @@ // -// HFCancelEvent.h +// HFBackEvent.h // script-engine/src // // Created by Stephen Birarda on 2014-10-27. @@ -9,21 +9,21 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_HFCancelEvent_h -#define hifi_HFCancelEvent_h +#ifndef hifi_HFBackEvent_h +#define hifi_HFBackEvent_h #include #include #include "HFMetaEvent.h" -class HFCancelEvent : public HFMetaEvent { +class HFBackEvent : public HFMetaEvent { public: - HFCancelEvent() {}; - HFCancelEvent(QEvent::Type type); + HFBackEvent() {}; + HFBackEvent(QEvent::Type type); static QEvent::Type startType(); static QEvent::Type endType(); }; -#endif // hifi_HFCancelEvent_h \ No newline at end of file +#endif // hifi_HFBackEvent_h \ No newline at end of file From 8e6b6d529439ec21d15f8ca6cc0b6638baab630d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 15:58:42 -0700 Subject: [PATCH 115/119] have controller A button fire action at center of screen --- interface/src/Application.h | 2 ++ .../src/scripting/JoystickScriptingInterface.cpp | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.h b/interface/src/Application.h index e85c4f4db5..9930f5debc 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -283,6 +283,8 @@ public: PointShader& getPointShader() { return _pointShader; } FileLogger* getLogger() { return _logger; } + QPointF getViewportCenter() const + { return QPointF(_glWidget->getDeviceWidth() / 2.0f, _glWidget->getDeviceHeight() / 2.0f); } glm::vec2 getViewportDimensions() const { return glm::vec2(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight()); } NodeToJurisdictionMap& getVoxelServerJurisdictions() { return _voxelServerJurisdictions; } NodeToJurisdictionMap& getEntityServerJurisdictions() { return _entityServerJurisdictions; } diff --git a/interface/src/scripting/JoystickScriptingInterface.cpp b/interface/src/scripting/JoystickScriptingInterface.cpp index 9375f80045..f2c7ef4579 100644 --- a/interface/src/scripting/JoystickScriptingInterface.cpp +++ b/interface/src/scripting/JoystickScriptingInterface.cpp @@ -18,9 +18,12 @@ #undef main #endif +#include #include #include +#include "Application.h" + #include "JoystickScriptingInterface.h" #ifdef HAVE_SDL2 @@ -112,13 +115,24 @@ void JoystickScriptingInterface::update() { } if (event.cbutton.button == SDL_CONTROLLER_BUTTON_BACK) { - // this will either start or stop a cancel event + // this will either start or stop a global back event QEvent::Type backType = (event.type == SDL_CONTROLLERBUTTONDOWN) ? HFBackEvent::startType() : HFBackEvent::endType(); HFBackEvent backEvent(backType); qApp->sendEvent(qApp, &backEvent); + } else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_A) { + // this will either start or stop a global action event + QEvent::Type actionType = (event.type == SDL_CONTROLLERBUTTONDOWN) + ? HFActionEvent::startType() + : HFActionEvent::endType(); + + // global action events fire in the center of the screen + QPointF centerPoint = Application::getInstance()->getViewportCenter(); + HFActionEvent actionEvent(actionType, centerPoint); + + qApp->sendEvent(qApp, &actionEvent); } } else if (event.type == SDL_CONTROLLERDEVICEADDED) { From bb652c078491365a295a967f3f23d6ad348aeb8e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 16:01:39 -0700 Subject: [PATCH 116/119] rename signal in AbstractControllerScriptingInterface from cancel to back --- interface/src/scripting/ControllerScriptingInterface.cpp | 4 ++-- .../script-engine/src/AbstractControllerScriptingInterface.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index d2cc847ab5..a330cbc611 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -32,9 +32,9 @@ void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) { } else if (event->type() == HFActionEvent::endType()) { emit actionEndEvent(static_cast(*event)); } else if (event->type() == HFBackEvent::startType()) { - emit cancelStartEvent(); + emit backStartEvent(); } else if (event->type() == HFBackEvent::endType()) { - emit cancelEndEvent(); + emit backEndEvent(); } } diff --git a/libraries/script-engine/src/AbstractControllerScriptingInterface.h b/libraries/script-engine/src/AbstractControllerScriptingInterface.h index 1eff64eb42..11755add8e 100644 --- a/libraries/script-engine/src/AbstractControllerScriptingInterface.h +++ b/libraries/script-engine/src/AbstractControllerScriptingInterface.h @@ -97,8 +97,8 @@ signals: void actionStartEvent(const HFActionEvent& event); void actionEndEvent(const HFActionEvent& event); - void cancelStartEvent(); - void cancelEndEvent(); + void backStartEvent(); + void backEndEvent(); void mouseMoveEvent(const MouseEvent& event, unsigned int deviceID = 0); void mousePressEvent(const MouseEvent& event, unsigned int deviceID = 0); From 209c12cb1ca3e3d619606339de5b5b0d85b63ab0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 16:52:22 -0700 Subject: [PATCH 117/119] repairs for texture replacement by name --- interface/src/renderer/GeometryCache.cpp | 19 +++++++++++++------ interface/src/renderer/GeometryCache.h | 3 +++ interface/src/renderer/TextureCache.h | 4 ---- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index 35765c50b8..f1d4d712e5 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -620,12 +620,19 @@ void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& u NetworkMeshPart& part = mesh.parts[j]; QSharedPointer matchingTexture = QSharedPointer(); - if (part.diffuseTexture->getName() == name) { + if (part.diffuseTextureName == name) { part.diffuseTexture = Application::getInstance()->getTextureCache()->getTexture(url, DEFAULT_TEXTURE, - _geometry.meshes[i].isEye, QByteArray()); - part.diffuseTexture->setName(name); + _geometry.meshes[i].isEye, QByteArray()); part.diffuseTexture->setLoadPriorities(_loadPriorities); + } else if (part.normalTextureName == name) { + part.normalTexture = Application::getInstance()->getTextureCache()->getTexture(url, DEFAULT_TEXTURE, + false, QByteArray()); + part.normalTexture->setLoadPriorities(_loadPriorities); + } else if (part.specularTextureName == name) { + part.specularTexture = Application::getInstance()->getTextureCache()->getTexture(url, DEFAULT_TEXTURE, + false, QByteArray()); + part.specularTexture->setLoadPriorities(_loadPriorities); } } } @@ -746,21 +753,21 @@ void NetworkGeometry::setGeometry(const FBXGeometry& geometry) { networkPart.diffuseTexture = Application::getInstance()->getTextureCache()->getTexture( _textureBase.resolved(QUrl(part.diffuseTexture.filename)), DEFAULT_TEXTURE, mesh.isEye, part.diffuseTexture.content); - networkPart.diffuseTexture->setName(part.diffuseTexture.name); + networkPart.diffuseTextureName = part.diffuseTexture.name; networkPart.diffuseTexture->setLoadPriorities(_loadPriorities); } if (!part.normalTexture.filename.isEmpty()) { networkPart.normalTexture = Application::getInstance()->getTextureCache()->getTexture( _textureBase.resolved(QUrl(part.normalTexture.filename)), NORMAL_TEXTURE, false, part.normalTexture.content); - networkPart.normalTexture->setName(part.normalTexture.name); + networkPart.normalTextureName = part.normalTexture.name; networkPart.normalTexture->setLoadPriorities(_loadPriorities); } if (!part.specularTexture.filename.isEmpty()) { networkPart.specularTexture = Application::getInstance()->getTextureCache()->getTexture( _textureBase.resolved(QUrl(part.specularTexture.filename)), SPECULAR_TEXTURE, false, part.specularTexture.content); - networkPart.specularTexture->setName(part.specularTexture.name); + networkPart.specularTextureName = part.specularTexture.name; networkPart.specularTexture->setLoadPriorities(_loadPriorities); } networkMesh.parts.append(networkPart); diff --git a/interface/src/renderer/GeometryCache.h b/interface/src/renderer/GeometryCache.h index 461d622a02..4ed6c9943d 100644 --- a/interface/src/renderer/GeometryCache.h +++ b/interface/src/renderer/GeometryCache.h @@ -140,8 +140,11 @@ private: class NetworkMeshPart { public: + QString diffuseTextureName; QSharedPointer diffuseTexture; + QString normalTextureName; QSharedPointer normalTexture; + QString specularTextureName; QSharedPointer specularTexture; bool isTranslucent() const; diff --git a/interface/src/renderer/TextureCache.h b/interface/src/renderer/TextureCache.h index 29740621e3..fd9131fe23 100644 --- a/interface/src/renderer/TextureCache.h +++ b/interface/src/renderer/TextureCache.h @@ -145,9 +145,6 @@ public: /// Returns the lazily-computed average texture color. const QColor& getAverageColor() const { return _averageColor; } - - const QString& getName() const { return _name; } - void setName(const QString& name) { _name = name; } protected: @@ -159,7 +156,6 @@ protected: virtual void imageLoaded(const QImage& image); private: - QString _name; TextureType _type; bool _translucent; QColor _averageColor; From 80d90147268092f4f354dd9897642b96802e7cec Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 16:54:28 -0700 Subject: [PATCH 118/119] have spacebar fire an action event at center of screen --- interface/src/Application.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b1f694671e..b54c3145e8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1102,15 +1102,23 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_Equal: _myAvatar->resetSize(); break; + case Qt::Key_Space: { + // this starts an HFActionEvent + HFActionEvent startActionEvent(HFActionEvent::startType(), getViewportCenter()); + sendEvent(this, &startActionEvent); + + break; + } case Qt::Key_Escape: { OculusManager::abandonCalibration(); - // this fires the HFCancelEvent + // this starts the HFCancelEvent HFBackEvent startBackEvent(HFBackEvent::startType()); sendEvent(this, &startBackEvent); break; } + default: event->ignore(); break; @@ -1181,6 +1189,13 @@ void Application::keyReleaseEvent(QKeyEvent* event) { case Qt::Key_Alt: _myAvatar->clearDriveKeys(); break; + case Qt::Key_Space: { + // this ends the HFActionEvent + HFActionEvent endActionEvent(HFActionEvent::endType(), getViewportCenter()); + sendEvent(this, &endActionEvent); + + break; + } case Qt::Key_Escape: { // this ends the HFCancelEvent HFBackEvent endBackEvent(HFBackEvent::endType()); From e2536dd3f85527166c3726b12f59f2c9fcc07a26 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Oct 2014 16:55:24 -0700 Subject: [PATCH 119/119] remove a debug line --- interface/src/renderer/GeometryCache.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index f1d4d712e5..c3b0a58263 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -405,7 +405,6 @@ void GeometryCache::renderGrid(int xDivisions, int yDivisions) { } QSharedPointer GeometryCache::getGeometry(const QUrl& url, const QUrl& fallback, bool delayLoad) { - qDebug() << "Getting a resource at" << url; return getResource(url, fallback, delayLoad).staticCast(); }