Merge branch 'master' of https://github.com/highfidelity/hifi into stretchableEntities

This commit is contained in:
ZappoMan 2014-09-09 10:33:24 -07:00
commit 3cb1d29cf4
39 changed files with 1021 additions and 233 deletions

View file

@ -13,4 +13,5 @@ Script.load("editVoxels.js");
Script.load("editModels.js");
Script.load("selectAudioDevice.js");
Script.load("hydraMove.js");
Script.load("headMove.js");
Script.load("inspect.js");

View file

@ -1147,10 +1147,10 @@ var toolBar = (function () {
}, true, false);
browseModelsButton = toolBar.addTool({
imageURL: toolIconUrl + "list-icon.png",
imageURL: toolIconUrl + "list-icon.svg",
width: toolWidth,
height: toolHeight,
alpha: 0.7,
alpha: 0.9,
visible: true
});

77
examples/headMove.js Normal file
View file

@ -0,0 +1,77 @@
//
// headMove.js
// examples
//
// Created by Philip Rosedale on September 8, 2014
// Copyright 2014 High Fidelity, Inc.
//
// Press the spacebar and move/turn your head to move around.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var debug = false;
var movingWithHead = false;
var headStartPosition, headStartDeltaPitch, headStartFinalPitch, headStartRoll, headStartYaw;
var HEAD_MOVE_DEAD_ZONE = 0.0;
var HEAD_STRAFE_DEAD_ZONE = 0.0;
var HEAD_ROTATE_DEAD_ZONE = 0.0;
var HEAD_THRUST_FWD_SCALE = 12000.0;
var HEAD_THRUST_STRAFE_SCALE = 1000.0;
var HEAD_YAW_RATE = 2.0;
var HEAD_PITCH_RATE = 1.0;
var HEAD_ROLL_THRUST_SCALE = 75.0;
var HEAD_PITCH_LIFT_THRUST = 3.0;
function moveWithHead(deltaTime) {
if (movingWithHead) {
var deltaYaw = MyAvatar.getHeadFinalYaw() - headStartYaw;
var deltaPitch = MyAvatar.getHeadDeltaPitch() - headStartDeltaPitch;
var bodyLocalCurrentHeadVector = Vec3.subtract(MyAvatar.getHeadPosition(), MyAvatar.position);
bodyLocalCurrentHeadVector = Vec3.multiplyQbyV(Quat.angleAxis(-deltaYaw, {x:0, y: 1, z:0}), bodyLocalCurrentHeadVector);
var headDelta = Vec3.subtract(bodyLocalCurrentHeadVector, headStartPosition);
headDelta = Vec3.multiplyQbyV(Quat.inverse(Camera.getOrientation()), headDelta);
headDelta.y = 0.0; // Don't respond to any of the vertical component of head motion
// Thrust based on leaning forward and side-to-side
if (Math.abs(headDelta.z) > HEAD_MOVE_DEAD_ZONE) {
MyAvatar.addThrust(Vec3.multiply(Quat.getFront(Camera.getOrientation()), -headDelta.z * HEAD_THRUST_FWD_SCALE * deltaTime));
}
if (Math.abs(headDelta.x) > HEAD_STRAFE_DEAD_ZONE) {
MyAvatar.addThrust(Vec3.multiply(Quat.getRight(Camera.getOrientation()), headDelta.x * HEAD_THRUST_STRAFE_SCALE * deltaTime));
}
if (Math.abs(deltaYaw) > HEAD_ROTATE_DEAD_ZONE) {
var orientation = Quat.multiply(Quat.angleAxis(deltaYaw * HEAD_YAW_RATE * deltaTime, {x:0, y: 1, z:0}), MyAvatar.orientation);
MyAvatar.orientation = orientation;
}
// Thrust Up/Down based on head pitch
MyAvatar.addThrust(Vec3.multiply({ x:0, y:1, z:0 }, (MyAvatar.getHeadFinalPitch() - headStartFinalPitch) * HEAD_PITCH_LIFT_THRUST * deltaTime));
// For head trackers, adjust pitch by head pitch
MyAvatar.headPitch += deltaPitch * HEAD_PITCH_RATE * deltaTime;
// Thrust strafe based on roll ange
MyAvatar.addThrust(Vec3.multiply(Quat.getRight(Camera.getOrientation()), -(MyAvatar.getHeadFinalRoll() - headStartRoll) * HEAD_ROLL_THRUST_SCALE * deltaTime));
}
}
Controller.keyPressEvent.connect(function(event) {
if (event.text == "SPACE" && !movingWithHead) {
movingWithHead = true;
headStartPosition = Vec3.subtract(MyAvatar.getHeadPosition(), MyAvatar.position);
headStartDeltaPitch = MyAvatar.getHeadDeltaPitch();
headStartFinalPitch = MyAvatar.getHeadFinalPitch();
headStartRoll = MyAvatar.getHeadFinalRoll();
headStartYaw = MyAvatar.getHeadFinalYaw();
}
});
Controller.keyReleaseEvent.connect(function(event) {
if (event.text == "SPACE") {
movingWithHead = false;
}
});
Script.update.connect(moveWithHead);

View file

@ -2,7 +2,9 @@
// hydraMove.js
// examples
//
// Created by Brad Hefta-Gaub on 2/10/14.
// Created by Brad Hefta-Gaub on February 10, 2014
// Updated by Philip Rosedale on September 8, 2014
//
// Copyright 2014 High Fidelity, Inc.
//
// This is an example script that demonstrates use of the Controller and MyAvatar classes to implement
@ -34,8 +36,7 @@ var grabbingWithRightHand = false;
var wasGrabbingWithRightHand = false;
var grabbingWithLeftHand = false;
var wasGrabbingWithLeftHand = false;
var movingWithHead = false;
var headStartPosition, headStartDeltaPitch, headStartFinalPitch, headStartRoll, headStartYaw;
var EPSILON = 0.000001;
var velocity = { x: 0, y: 0, z: 0};
var THRUST_MAG_UP = 100.0;
@ -243,47 +244,6 @@ function handleGrabBehavior(deltaTime) {
wasGrabbingWithLeftHand = grabbingWithLeftHand;
}
var HEAD_MOVE_DEAD_ZONE = 0.0;
var HEAD_STRAFE_DEAD_ZONE = 0.0;
var HEAD_ROTATE_DEAD_ZONE = 0.0;
var HEAD_THRUST_FWD_SCALE = 12000.0;
var HEAD_THRUST_STRAFE_SCALE = 1000.0;
var HEAD_YAW_RATE = 2.0;
var HEAD_PITCH_RATE = 1.0;
var HEAD_ROLL_THRUST_SCALE = 75.0;
var HEAD_PITCH_LIFT_THRUST = 3.0;
function moveWithHead(deltaTime) {
if (movingWithHead) {
var deltaYaw = MyAvatar.getHeadFinalYaw() - headStartYaw;
var deltaPitch = MyAvatar.getHeadDeltaPitch() - headStartDeltaPitch;
var bodyLocalCurrentHeadVector = Vec3.subtract(MyAvatar.getHeadPosition(), MyAvatar.position);
bodyLocalCurrentHeadVector = Vec3.multiplyQbyV(Quat.angleAxis(-deltaYaw, {x:0, y: 1, z:0}), bodyLocalCurrentHeadVector);
var headDelta = Vec3.subtract(bodyLocalCurrentHeadVector, headStartPosition);
headDelta = Vec3.multiplyQbyV(Quat.inverse(Camera.getOrientation()), headDelta);
headDelta.y = 0.0; // Don't respond to any of the vertical component of head motion
// Thrust based on leaning forward and side-to-side
if (Math.abs(headDelta.z) > HEAD_MOVE_DEAD_ZONE) {
MyAvatar.addThrust(Vec3.multiply(Quat.getFront(Camera.getOrientation()), -headDelta.z * HEAD_THRUST_FWD_SCALE * deltaTime));
}
if (Math.abs(headDelta.x) > HEAD_STRAFE_DEAD_ZONE) {
MyAvatar.addThrust(Vec3.multiply(Quat.getRight(Camera.getOrientation()), headDelta.x * HEAD_THRUST_STRAFE_SCALE * deltaTime));
}
if (Math.abs(deltaYaw) > HEAD_ROTATE_DEAD_ZONE) {
var orientation = Quat.multiply(Quat.angleAxis(deltaYaw * HEAD_YAW_RATE * deltaTime, {x:0, y: 1, z:0}), MyAvatar.orientation);
MyAvatar.orientation = orientation;
}
// Thrust Up/Down based on head pitch
MyAvatar.addThrust(Vec3.multiply({ x:0, y:1, z:0 }, (MyAvatar.getHeadFinalPitch() - headStartFinalPitch) * HEAD_PITCH_LIFT_THRUST * deltaTime));
// For head trackers, adjust pitch by head pitch
MyAvatar.headPitch += deltaPitch * HEAD_PITCH_RATE * deltaTime;
// Thrust strafe based on roll ange
MyAvatar.addThrust(Vec3.multiply(Quat.getRight(Camera.getOrientation()), -(MyAvatar.getHeadFinalRoll() - headStartRoll) * HEAD_ROLL_THRUST_SCALE * deltaTime));
}
}
// Update for joysticks and move button
function flyWithHydra(deltaTime) {
var thrustJoystickPosition = Controller.getJoystickPosition(THRUST_CONTROLLER);
@ -318,12 +278,10 @@ function flyWithHydra(deltaTime) {
MyAvatar.orientation = Quat.multiply(orientation, deltaOrientation);
// change the headPitch based on our x controller
//pitch += viewJoystickPosition.y * JOYSTICK_PITCH_MAG * deltaTime;
var newPitch = MyAvatar.headPitch + (viewJoystickPosition.y * JOYSTICK_PITCH_MAG * deltaTime);
MyAvatar.headPitch = newPitch;
}
handleGrabBehavior(deltaTime);
moveWithHead(deltaTime);
displayDebug();
}
@ -340,19 +298,4 @@ function scriptEnding() {
}
Script.scriptEnding.connect(scriptEnding);
Controller.keyPressEvent.connect(function(event) {
if (event.text == "SPACE" && !movingWithHead) {
movingWithHead = true;
headStartPosition = Vec3.subtract(MyAvatar.getHeadPosition(), MyAvatar.position);
headStartDeltaPitch = MyAvatar.getHeadDeltaPitch();
headStartFinalPitch = MyAvatar.getHeadFinalPitch();
headStartRoll = MyAvatar.getHeadFinalRoll();
headStartYaw = MyAvatar.getHeadFinalYaw();
}
});
Controller.keyReleaseEvent.connect(function(event) {
if (event.text == "SPACE") {
movingWithHead = false;
}
});

View file

@ -41,6 +41,7 @@
#include <QShortcut>
#include <QTimer>
#include <QUrl>
#include <QWindow>
#include <QtDebug>
#include <QFileDialog>
#include <QDesktopServices>
@ -1152,8 +1153,7 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
showMouse = false;
}
QMouseEvent deviceEvent = getDeviceEvent(event, deviceID);
_controllerScriptingInterface.emitMouseMoveEvent(&deviceEvent, deviceID); // send events to any registered scripts
_controllerScriptingInterface.emitMouseMoveEvent(event, deviceID); // send events to any registered scripts
// if one of our scripts have asked to capture this event, then stop processing it
if (_controllerScriptingInterface.isMouseCaptured()) {
@ -1168,13 +1168,12 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
_seenMouseMove = true;
}
_mouseX = deviceEvent.x();
_mouseY = deviceEvent.y();
_mouseX = event->x();
_mouseY = event->y();
}
void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
QMouseEvent deviceEvent = getDeviceEvent(event, deviceID);
_controllerScriptingInterface.emitMousePressEvent(&deviceEvent); // send events to any registered scripts
_controllerScriptingInterface.emitMousePressEvent(event); // send events to any registered scripts
// if one of our scripts have asked to capture this event, then stop processing it
if (_controllerScriptingInterface.isMouseCaptured()) {
@ -1184,8 +1183,8 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
if (activeWindow() == _window) {
if (event->button() == Qt::LeftButton) {
_mouseX = deviceEvent.x();
_mouseY = deviceEvent.y();
_mouseX = event->x();
_mouseY = event->y();
_mouseDragStartedX = _mouseX;
_mouseDragStartedY = _mouseY;
_mousePressed = true;
@ -1207,8 +1206,7 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
}
void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) {
QMouseEvent deviceEvent = getDeviceEvent(event, deviceID);
_controllerScriptingInterface.emitMouseReleaseEvent(&deviceEvent); // send events to any registered scripts
_controllerScriptingInterface.emitMouseReleaseEvent(event); // send events to any registered scripts
// if one of our scripts have asked to capture this event, then stop processing it
if (_controllerScriptingInterface.isMouseCaptured()) {
@ -1217,8 +1215,8 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) {
if (activeWindow() == _window) {
if (event->button() == Qt::LeftButton) {
_mouseX = deviceEvent.x();
_mouseY = deviceEvent.y();
_mouseX = event->x();
_mouseY = event->y();
_mousePressed = false;
checkBandwidthMeterClick();
if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
@ -1417,7 +1415,7 @@ void Application::checkBandwidthMeterClick() {
if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth) &&
glm::compMax(glm::abs(glm::ivec2(_mouseX - _mouseDragStartedX, _mouseY - _mouseDragStartedY)))
<= BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH
&& _bandwidthMeter.isWithinArea(_mouseX, _mouseY, _glWidget->getDeviceWidth(), _glWidget->getDeviceHeight())) {
&& _bandwidthMeter.isWithinArea(_mouseX, _mouseY, _glWidget->width(), _glWidget->height())) {
// The bandwidth meter is visible, the click didn't get dragged too far and
// we actually hit the bandwidth meter
@ -1735,8 +1733,8 @@ void Application::init() {
_voxelShader.init();
_pointShader.init();
_mouseX = _glWidget->getDeviceWidth() / 2;
_mouseY = _glWidget->getDeviceHeight() / 2;
_mouseX = _glWidget->width() / 2;
_mouseY = _glWidget->height() / 2;
QCursor::setPos(_mouseX, _mouseY);
// TODO: move _myAvatar out of Application. Move relevant code to MyAvataar or AvatarManager
@ -1891,8 +1889,8 @@ void Application::updateMouseRay() {
// if the mouse pointer isn't visible, act like it's at the center of the screen
float x = 0.5f, y = 0.5f;
if (!_mouseHidden) {
x = _mouseX / (float)_glWidget->getDeviceWidth();
y = _mouseY / (float)_glWidget->getDeviceHeight();
x = _mouseX / (float)_glWidget->width();
y = _mouseY / (float)_glWidget->height();
}
_viewFrustum.computePickRay(x, y, _mouseRayOrigin, _mouseRayDirection);
@ -2332,14 +2330,6 @@ int Application::sendNackPackets() {
return packetsSent;
}
QMouseEvent Application::getDeviceEvent(QMouseEvent* event, unsigned int deviceID) {
if (deviceID > 0) {
return *event;
}
return QMouseEvent(event->type(), QPointF(_glWidget->getDeviceX(event->x()), _glWidget->getDeviceY(event->y())),
event->windowPos(), event->screenPos(), event->button(), event->buttons(), event->modifiers());
}
void Application::queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions) {
//qDebug() << ">>> inside... queryOctree()... _viewFrustum.getFieldOfView()=" << _viewFrustum.getFieldOfView();
@ -3041,8 +3031,16 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
_mirrorCamera.update(1.0f/_fps);
// set the bounds of rear mirror view
glViewport(region.x(), _glWidget->getDeviceHeight() - region.y() - region.height(), region.width(), region.height());
glScissor(region.x(), _glWidget->getDeviceHeight() - region.y() - region.height(), region.width(), region.height());
if (billboard) {
glViewport(region.x(), _glWidget->getDeviceHeight() - region.y() - region.height(), region.width(), region.height());
glScissor(region.x(), _glWidget->getDeviceHeight() - region.y() - region.height(), region.width(), region.height());
} else {
// if not rendering the billboard, the region is in device independent coordinates; must convert to device
float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio();
int x = region.x() * ratio, y = region.y() * ratio, width = region.width() * ratio, height = region.height() * ratio;
glViewport(x, _glWidget->getDeviceHeight() - y - height, width, height);
glScissor(x, _glWidget->getDeviceHeight() - y - height, width, height);
}
bool updateViewFrustum = false;
updateProjectionMatrix(_mirrorCamera, updateViewFrustum);
glEnable(GL_SCISSOR_TEST);
@ -3291,8 +3289,8 @@ void Application::deleteVoxelAt(const VoxelDetail& voxel) {
void Application::resetSensors() {
_mouseX = _glWidget->getDeviceWidth() / 2;
_mouseY = _glWidget->getDeviceHeight() / 2;
_mouseX = _glWidget->width() / 2;
_mouseY = _glWidget->height() / 2;
_faceplus.reset();
_faceshift.reset();

View file

@ -436,8 +436,6 @@ private:
int sendNackPackets();
QMouseEvent getDeviceEvent(QMouseEvent* event, unsigned int deviceID);
MainWindow* _window;
GLCanvas* _glWidget; // our GLCanvas has a couple extra features

View file

@ -40,6 +40,7 @@
#include <glm/glm.hpp>
#include "Audio.h"
#include "Menu.h"
#include "Util.h"
#include "PositionalAudioStream.h"
@ -82,7 +83,7 @@ Audio::Audio(QObject* parent) :
_noiseGateSampleCounter(0),
_noiseGateOpen(false),
_noiseGateEnabled(true),
_toneInjectionEnabled(false),
_audioSourceInjectEnabled(false),
_noiseGateFramesToClose(0),
_totalInputAudioSamples(0),
_collisionSoundMagnitude(0.0f),
@ -102,6 +103,8 @@ Audio::Audio(QObject* parent) :
_framesPerScope(DEFAULT_FRAMES_PER_SCOPE),
_samplesPerScope(NETWORK_SAMPLES_PER_FRAME * _framesPerScope),
_peqEnabled(false),
_noiseSourceEnabled(false),
_toneSourceEnabled(true),
_scopeInput(0),
_scopeOutputLeft(0),
_scopeOutputRight(0),
@ -137,6 +140,10 @@ void Audio::reset() {
_receivedAudioStream.reset();
resetStats();
_peq.reset();
_noiseSource.reset();
_toneSource.reset();
_sourceGain.reset();
_inputGain.reset();
}
void Audio::resetStats() {
@ -424,14 +431,25 @@ void Audio::start() {
qDebug() << "Unable to set up audio output because of a problem with output format.";
}
_peq.initialize( _inputFormat.sampleRate(), _audioInput->bufferSize() );
_inputFrameBuffer.initialize( _inputFormat.channelCount(), _audioInput->bufferSize() * 4 );
_peq.initialize( _inputFormat.sampleRate() );
_inputGain.initialize();
_sourceGain.initialize();
_noiseSource.initialize();
_toneSource.initialize();
_sourceGain.setParameters(0.25f,0.0f);
_inputGain.setParameters(1.0f,0.0f);
}
void Audio::stop() {
_inputFrameBuffer.finalize();
_peq.finalize();
_inputGain.finalize();
_sourceGain.finalize();
_noiseSource.finalize();
_toneSource.finalize();
// "switch" to invalid devices in order to shut down the state
switchInputToAudioDevice(QAudioDeviceInfo());
switchOutputToAudioDevice(QAudioDeviceInfo());
@ -477,14 +495,30 @@ void Audio::handleAudioInput() {
QByteArray inputByteArray = _inputDevice->readAll();
int16_t* inputFrameData = (int16_t*)inputByteArray.data();
const int inputFrameCount = inputByteArray.size() / sizeof(int16_t);
_inputFrameBuffer.copyFrames(1, inputFrameCount, inputFrameData, false /*copy in*/);
_inputGain.render(_inputFrameBuffer); // input/mic gain+mute
// Add audio source injection if enabled
if (_audioSourceInjectEnabled && !_muted) {
if (_toneSourceEnabled) { // sine generator
_toneSource.render(_inputFrameBuffer);
}
else if(_noiseSourceEnabled) { // pink noise generator
_noiseSource.render(_inputFrameBuffer);
}
_sourceGain.render(_inputFrameBuffer); // post gain
}
if (_peqEnabled && !_muted) {
// we wish to pre-filter our captured input, prior to loopback
int16_t* ioBuffer = (int16_t*)inputByteArray.data();
_peq.render(ioBuffer, ioBuffer, inputByteArray.size() / sizeof(int16_t));
_peq.render(_inputFrameBuffer); // 3-band parametric eq
}
_inputFrameBuffer.copyFrames(1, inputFrameCount, inputFrameData, true /*copy out*/);
if (Menu::getInstance()->isOptionChecked(MenuOption::EchoLocalAudio) && !_muted && _audioOutput) {
// if this person wants local loopback add that to the locally injected audio
@ -522,7 +556,7 @@ void Audio::handleAudioInput() {
int16_t* inputAudioSamples = new int16_t[inputSamplesRequired];
_inputRingBuffer.readSamples(inputAudioSamples, inputSamplesRequired);
const int numNetworkBytes = _isStereoInput ? NETWORK_BUFFER_LENGTH_BYTES_STEREO : NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL;
const int numNetworkSamples = _isStereoInput ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
@ -599,20 +633,8 @@ void Audio::handleAudioInput() {
_dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset;
}
// Add tone injection if enabled
const float TONE_FREQ = 220.0f / SAMPLE_RATE * TWO_PI;
const float QUARTER_VOLUME = 8192.0f;
if (_toneInjectionEnabled) {
loudness = 0.0f;
for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) {
networkAudioSamples[i] = QUARTER_VOLUME * sinf(TONE_FREQ * (float)(i + _proceduralEffectSample));
loudness += fabsf(networkAudioSamples[i]);
}
}
_lastInputLoudness = fabs(loudness / NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
// If Noise Gate is enabled, check and turn the gate on and off
if (!_toneInjectionEnabled && _noiseGateEnabled) {
if (!_audioSourceInjectEnabled && _noiseGateEnabled) {
float averageOfAllSampleFrames = 0.0f;
_noiseSampleFrames[_noiseGateSampleCounter++] = _lastInputLoudness;
if (_noiseGateSampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) {
@ -1041,8 +1063,18 @@ void Audio::processProceduralAudio(int16_t* monoInput, int numSamples) {
}
}
void Audio::toggleToneInjection() {
_toneInjectionEnabled = !_toneInjectionEnabled;
void Audio::toggleAudioSourceInject() {
_audioSourceInjectEnabled = !_audioSourceInjectEnabled;
}
void Audio::selectAudioSourcePinkNoise() {
_noiseSourceEnabled = Menu::getInstance()->isOptionChecked(MenuOption::AudioSourcePinkNoise);
_toneSourceEnabled = !_noiseSourceEnabled;
}
void Audio::selectAudioSourceSine440() {
_toneSourceEnabled = Menu::getInstance()->isOptionChecked(MenuOption::AudioSourceSine440);
_noiseSourceEnabled = !_toneSourceEnabled;
}
void Audio::toggleAudioSpatialProcessing() {

View file

@ -20,6 +20,12 @@
#include "Recorder.h"
#include "RingBufferHistory.h"
#include "MovingMinMaxAvg.h"
#include "AudioRingBuffer.h"
#include "AudioFormat.h"
#include "AudioBuffer.h"
#include "AudioSourceTone.h"
#include "AudioSourceNoise.h"
#include "AudioGain.h"
#include "AudioFilter.h"
#include "AudioFilterBank.h"
@ -116,7 +122,9 @@ public slots:
void audioMixerKilled();
void toggleMute();
void toggleAudioNoiseReduction();
void toggleToneInjection();
void toggleAudioSourceInject();
void selectAudioSourcePinkNoise();
void selectAudioSourceSine440();
void toggleScope();
void toggleScopePause();
void toggleStats();
@ -199,7 +207,8 @@ private:
int _noiseGateSampleCounter;
bool _noiseGateOpen;
bool _noiseGateEnabled;
bool _toneInjectionEnabled;
bool _audioSourceInjectEnabled;
int _noiseGateFramesToClose;
int _totalInputAudioSamples;
@ -282,10 +291,27 @@ private:
int _framesPerScope;
int _samplesPerScope;
// Multi-band parametric EQ
bool _peqEnabled;
AudioFilterPEQ3m _peq;
// Input framebuffer
AudioBufferFloat32 _inputFrameBuffer;
// Input gain
AudioGain _inputGain;
// Post tone/pink noise generator gain
AudioGain _sourceGain;
// Pink noise source
bool _noiseSourceEnabled;
AudioSourcePinkNoise _noiseSource;
// Tone source
bool _toneSourceEnabled;
AudioSourceTone _toneSource;
// Multi-band parametric EQ
bool _peqEnabled;
AudioFilterPEQ3m _peq;
QMutex _guard;
QByteArray* _scopeInput;
QByteArray* _scopeOutputLeft;

View file

@ -262,8 +262,8 @@ CameraScriptableObject::CameraScriptableObject(Camera* camera, ViewFrustum* view
}
PickRay CameraScriptableObject::computePickRay(float x, float y) {
float screenWidth = Application::getInstance()->getGLWidget()->getDeviceWidth();
float screenHeight = Application::getInstance()->getGLWidget()->getDeviceHeight();
float screenWidth = Application::getInstance()->getGLWidget()->width();
float screenHeight = Application::getInstance()->getGLWidget()->height();
PickRay result;
if (OculusManager::isConnected()) {
result.origin = _camera->getPosition();

View file

@ -43,14 +43,6 @@ int GLCanvas::getDeviceHeight() const {
return height() * (windowHandle() ? windowHandle()->devicePixelRatio() : 1.0f);
}
int GLCanvas::getDeviceX(int x) const {
return x * getDeviceWidth() / width();
}
int GLCanvas::getDeviceY(int y) const {
return y * getDeviceHeight() / height();
}
void GLCanvas::initializeGL() {
Application::getInstance()->initializeGL();
setAttribute(Qt::WA_AcceptTouchEvents);

View file

@ -26,9 +26,6 @@ public:
int getDeviceHeight() const;
QSize getDeviceSize() const { return QSize(getDeviceWidth(), getDeviceHeight()); }
int getDeviceX(int x) const;
int getDeviceY(int y) const;
protected:
QTimer _frameTimer;

View file

@ -545,11 +545,31 @@ Menu::Menu() :
0,
this,
SLOT(muteEnvironment()));
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioToneInjection,
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioSourceInject,
0,
false,
appInstance->getAudio(),
SLOT(toggleToneInjection()));
SLOT(toggleAudioSourceInject()));
QMenu* audioSourceMenu = audioDebugMenu->addMenu("Generated Audio Source");
{
QAction *pinkNoise = addCheckableActionToQMenuAndActionHash(audioSourceMenu, MenuOption::AudioSourcePinkNoise,
0,
false,
appInstance->getAudio(),
SLOT(selectAudioSourcePinkNoise()));
QAction *sine440 = addCheckableActionToQMenuAndActionHash(audioSourceMenu, MenuOption::AudioSourceSine440,
0,
true,
appInstance->getAudio(),
SLOT(selectAudioSourceSine440()));
QActionGroup* audioSourceGroup = new QActionGroup(audioSourceMenu);
audioSourceGroup->addAction(pinkNoise);
audioSourceGroup->addAction(sine440);
}
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioScope,
Qt::CTRL | Qt::Key_P, false,
appInstance->getAudio(),

View file

@ -347,7 +347,9 @@ namespace MenuOption {
const QString AudioSpatialProcessingSlightlyRandomSurfaces = "Slightly Random Surfaces";
const QString AudioSpatialProcessingStereoSource = "Stereo Source";
const QString AudioSpatialProcessingWithDiffusions = "With Diffusions";
const QString AudioToneInjection = "Inject Test Tone";
const QString AudioSourceInject = "Generated Audio";
const QString AudioSourcePinkNoise = "Pink Noise";
const QString AudioSourceSine440 = "Sine 440hz";
const QString Avatars = "Avatars";
const QString AvatarsReceiveShadows = "Avatars Receive Shadows";
const QString Bandwidth = "Bandwidth Display";

View file

@ -11,6 +11,9 @@
#include <vector>
#include <QDesktopWidget>
#include <QWindow>
#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
#include <glm/gtx/vector_angle.hpp>
@ -50,7 +53,7 @@ Avatar::Avatar() :
AvatarData(),
_skeletonModel(this),
_bodyYawDelta(0.0f),
_lastPosition(0.0f),
_lastPosition(_position),
_velocity(0.0f),
_lastVelocity(0.0f),
_acceleration(0.0f),
@ -204,7 +207,9 @@ void Avatar::simulate(float deltaTime) {
_displayNameAlpha = abs(_displayNameAlpha - _displayNameTargetAlpha) < 0.01f ? _displayNameTargetAlpha : _displayNameAlpha;
}
_position += _velocity * deltaTime;
// NOTE: we shouldn't extrapolate an Avatar instance forward in time...
// until velocity is in AvatarData update message.
//_position += _velocity * deltaTime;
measureMotionDerivatives(deltaTime);
}
@ -223,20 +228,6 @@ void Avatar::measureMotionDerivatives(float deltaTime) {
_lastOrientation = getOrientation();
}
void Avatar::setPosition(const glm::vec3 position, bool overideReferential) {
AvatarData::setPosition(position, overideReferential);
_lastPosition = position;
_velocity = glm::vec3(0.0f);
_lastVelocity = glm::vec3(0.0f);
}
void Avatar::slamPosition(const glm::vec3& newPosition) {
_position = newPosition;
_lastPosition = newPosition;
_velocity = glm::vec3(0.0f);
_lastVelocity = glm::vec3(0.0f);
}
void Avatar::setMouseRay(const glm::vec3 &origin, const glm::vec3 &direction) {
_mouseRayOrigin = origin;
_mouseRayDirection = direction;
@ -667,7 +658,8 @@ void Avatar::renderDisplayName() {
if (success) {
double textWindowHeight = abs(result1[1] - result0[1]);
float scaleFactor = (textWindowHeight > EPSILON) ? 1.0f / textWindowHeight : 1.0f;
float scaleFactor = QApplication::desktop()->windowHandle()->devicePixelRatio() *
((textWindowHeight > EPSILON) ? 1.0f / textWindowHeight : 1.0f);
glScalef(scaleFactor, scaleFactor, 1.0);
glScalef(1.0f, -1.0f, 1.0f); // TextRenderer::draw paints the text upside down in y axis

View file

@ -161,9 +161,6 @@ public:
/// \param vector position to be scaled. Will store the result
void scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const;
void setPosition(const glm::vec3 position, bool overideReferential = false);
void slamPosition(const glm::vec3& newPosition);
public slots:
void updateCollisionGroups();

View file

@ -609,6 +609,13 @@ void MyAvatar::setGravity(const glm::vec3& gravity) {
// so it continues to point opposite to the previous gravity setting.
}
void MyAvatar::slamPosition(const glm::vec3& newPosition) {
AvatarData::setPosition(newPosition);
_lastPosition = _position;
_velocity = glm::vec3(0.0f);
_lastVelocity = glm::vec3(0.0f);
}
AnimationHandlePointer MyAvatar::addAnimationHandle() {
AnimationHandlePointer handle = _skeletonModel.createAnimationHandle();
_animationHandles.append(handle);
@ -797,9 +804,11 @@ void MyAvatar::loadData(QSettings* settings) {
getHead()->setBasePitch(loadSetting(settings, "headPitch", 0.0f));
_position.x = loadSetting(settings, "position_x", START_LOCATION.x);
_position.y = loadSetting(settings, "position_y", START_LOCATION.y);
_position.z = loadSetting(settings, "position_z", START_LOCATION.z);
glm::vec3 newPosition;
newPosition.x = loadSetting(settings, "position_x", START_LOCATION.x);
newPosition.y = loadSetting(settings, "position_y", START_LOCATION.y);
newPosition.z = loadSetting(settings, "position_z", START_LOCATION.z);
slamPosition(newPosition);
getHead()->setPupilDilation(loadSetting(settings, "pupilDilation", 0.0f));

View file

@ -57,6 +57,7 @@ public:
void setLeanScale(float scale) { _leanScale = scale; }
void setLocalGravity(glm::vec3 gravity);
void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; }
void slamPosition(const glm::vec3& position);
// getters
float getLeanScale() const { return _leanScale; }

View file

@ -209,8 +209,8 @@ void PrioVR::renderCalibrationCountdown() {
}
static TextRenderer textRenderer(MONO_FONT_FAMILY, 18, QFont::Bold, false, TextRenderer::OUTLINE_EFFECT, 2);
QByteArray text = "Assume T-Pose in " + QByteArray::number(secondsRemaining) + "...";
textRenderer.draw((Application::getInstance()->getGLWidget()->getDeviceWidth() -
textRenderer.computeWidth(text.constData())) / 2, Application::getInstance()->getGLWidget()->getDeviceHeight() / 2,
textRenderer.draw((Application::getInstance()->getGLWidget()->width() -
textRenderer.computeWidth(text.constData())) / 2, Application::getInstance()->getGLWidget()->height() / 2,
text);
#endif
}

View file

@ -396,10 +396,10 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) {
float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2));
// Get the pixel range over which the xAngle and yAngle are scaled
float cursorRange = widget->getDeviceWidth() * getCursorPixelRangeMult();
float cursorRange = widget->width() * getCursorPixelRangeMult();
pos.setX(widget->getDeviceWidth() / 2.0f + cursorRange * xAngle);
pos.setY(widget->getDeviceHeight() / 2.0f + cursorRange * yAngle);
pos.setX(widget->width() / 2.0f + cursorRange * xAngle);
pos.setY(widget->height() / 2.0f + cursorRange * yAngle);
}

View file

@ -205,7 +205,7 @@ bool LocationManager::goToDestination(QString destination) {
MyAvatar::sendKillAvatar();
qDebug("Going To Location: %f, %f, %f...", x, y, z);
myAvatar->setPosition(newAvatarPos);
myAvatar->slamPosition(newAvatarPos);
emit myAvatar->transformChanged();
}

View file

@ -257,7 +257,7 @@ void ControllerScriptingInterface::releaseJoystick(int joystickIndex) {
glm::vec2 ControllerScriptingInterface::getViewportDimensions() const {
GLCanvas* widget = Application::getInstance()->getGLWidget();
return glm::vec2(widget->getDeviceWidth(), widget->getDeviceHeight());
return glm::vec2(widget->width(), widget->height());
}
AbstractInputController* ControllerScriptingInterface::createInputController(const QString& deviceName, const QString& tracker) {

View file

@ -99,14 +99,14 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) {
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, glWidget->getDeviceWidth(), glWidget->getDeviceHeight(), 0);
gluOrtho2D(0, glWidget->width(), glWidget->height(), 0);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
renderAudioMeter();
if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) {
myAvatar->renderHeadMouse(glWidget->getDeviceWidth(), glWidget->getDeviceHeight());
myAvatar->renderHeadMouse(glWidget->width(), glWidget->height());
}
renderStatsAndLogs();
@ -305,8 +305,8 @@ QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const {
float u = asin(collisionPos.x) / (_textureFov)+0.5f;
float v = 1.0 - (asin(collisionPos.y) / (_textureFov)+0.5f);
rv.setX(u * glWidget->getDeviceWidth());
rv.setY(v * glWidget->getDeviceHeight());
rv.setX(u * glWidget->width());
rv.setY(v * glWidget->height());
}
} else {
//if they did not click on the overlay, just set the coords to INT_MAX
@ -323,8 +323,8 @@ QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const {
ndcSpacePos = glm::vec3(clipSpacePos) / clipSpacePos.w;
}
rv.setX(((ndcSpacePos.x + 1.0) / 2.0) * glWidget->getDeviceWidth());
rv.setY((1.0 - ((ndcSpacePos.y + 1.0) / 2.0)) * glWidget->getDeviceHeight());
rv.setX(((ndcSpacePos.x + 1.0) / 2.0) * glWidget->width());
rv.setY((1.0 - ((ndcSpacePos.y + 1.0) / 2.0)) * glWidget->height());
}
return rv;
}
@ -496,11 +496,11 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as
//draw the mouse pointer
glBindTexture(GL_TEXTURE_2D, _crosshairTexture);
const float reticleSize = 40.0f / application->getGLWidget()->getDeviceWidth() * quadWidth;
const float reticleSize = 40.0f / application->getGLWidget()->width() * quadWidth;
x -= reticleSize / 2.0f;
y += reticleSize / 2.0f;
const float mouseX = (application->getMouseX() / (float)application->getGLWidget()->getDeviceWidth()) * quadWidth;
const float mouseY = (1.0 - (application->getMouseY() / (float)application->getGLWidget()->getDeviceHeight())) * quadHeight;
const float mouseX = (application->getMouseX() / (float)application->getGLWidget()->width()) * quadWidth;
const float mouseY = (1.0 - (application->getMouseY() / (float)application->getGLWidget()->height())) * quadHeight;
glBegin(GL_QUADS);
@ -671,14 +671,14 @@ void ApplicationOverlay::renderControllerPointers() {
float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2));
// Get the pixel range over which the xAngle and yAngle are scaled
float cursorRange = glWidget->getDeviceWidth() * application->getSixenseManager()->getCursorPixelRangeMult();
float cursorRange = glWidget->width() * application->getSixenseManager()->getCursorPixelRangeMult();
mouseX = (glWidget->getDeviceWidth() / 2.0f + cursorRange * xAngle);
mouseY = (glWidget->getDeviceHeight() / 2.0f + cursorRange * yAngle);
mouseX = (glWidget->width() / 2.0f + cursorRange * xAngle);
mouseY = (glWidget->height() / 2.0f + cursorRange * yAngle);
}
//If the cursor is out of the screen then don't render it
if (mouseX < 0 || mouseX >= glWidget->getDeviceWidth() || mouseY < 0 || mouseY >= glWidget->getDeviceHeight()) {
if (mouseX < 0 || mouseX >= glWidget->width() || mouseY < 0 || mouseY >= glWidget->height()) {
_reticleActive[index] = false;
continue;
}
@ -709,8 +709,8 @@ void ApplicationOverlay::renderPointersOculus(const glm::vec3& eyePos) {
GLCanvas* glWidget = application->getGLWidget();
glm::vec3 cursorVerts[4];
const int widgetWidth = glWidget->getDeviceWidth();
const int widgetHeight = glWidget->getDeviceHeight();
const int widgetWidth = glWidget->width();
const int widgetHeight = glWidget->height();
const float reticleSize = 50.0f;
@ -850,8 +850,8 @@ void ApplicationOverlay::renderMagnifier(int mouseX, int mouseY, float sizeMult,
Application* application = Application::getInstance();
GLCanvas* glWidget = application->getGLWidget();
const int widgetWidth = glWidget->getDeviceWidth();
const int widgetHeight = glWidget->getDeviceHeight();
const int widgetWidth = glWidget->width();
const int widgetHeight = glWidget->height();
const float magnifyWidth = MAGNIFY_WIDTH * sizeMult;
const float magnifyHeight = MAGNIFY_HEIGHT * sizeMult;
@ -968,7 +968,7 @@ void ApplicationOverlay::renderAudioMeter() {
float collisionSoundMagnitude = audio->getCollisionSoundMagnitude();
const float VISIBLE_COLLISION_SOUND_MAGNITUDE = 0.5f;
if (collisionSoundMagnitude > VISIBLE_COLLISION_SOUND_MAGNITUDE) {
renderCollisionOverlay(glWidget->getDeviceWidth(), glWidget->getDeviceHeight(),
renderCollisionOverlay(glWidget->width(), glWidget->height(),
audio->getCollisionSoundMagnitude());
}
}
@ -1019,16 +1019,16 @@ void ApplicationOverlay::renderAudioMeter() {
if ((audio->getTimeSinceLastClip() > 0.f) && (audio->getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME)) {
const float MAX_MAGNITUDE = 0.7f;
float magnitude = MAX_MAGNITUDE * (1 - audio->getTimeSinceLastClip() / CLIPPING_INDICATOR_TIME);
renderCollisionOverlay(glWidget->getDeviceWidth(), glWidget->getDeviceHeight(), magnitude, 1.0f);
renderCollisionOverlay(glWidget->width(), glWidget->height(), magnitude, 1.0f);
}
audio->renderToolBox(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP,
audioMeterY,
Menu::getInstance()->isOptionChecked(MenuOption::Mirror));
audio->renderScope(glWidget->getDeviceWidth(), glWidget->getDeviceHeight());
audio->renderScope(glWidget->width(), glWidget->height());
audio->renderStats(WHITE_TEXT, glWidget->getDeviceWidth(), glWidget->getDeviceHeight());
audio->renderStats(WHITE_TEXT, glWidget->width(), glWidget->height());
glBegin(GL_QUADS);
if (isClipping) {
@ -1108,8 +1108,8 @@ void ApplicationOverlay::renderStatsAndLogs() {
application->getPacketsPerSecond(), application->getBytesPerSecond(), voxelPacketsToProcess);
// Bandwidth meter
if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) {
Stats::drawBackground(0x33333399, glWidget->getDeviceWidth() - 296, glWidget->getDeviceHeight() - 68, 296, 68);
bandwidthMeter->render(glWidget->getDeviceWidth(), glWidget->getDeviceHeight());
Stats::drawBackground(0x33333399, glWidget->width() - 296, glWidget->height() - 68, 296, 68);
bandwidthMeter->render(glWidget->width(), glWidget->height());
}
}
@ -1122,7 +1122,7 @@ void ApplicationOverlay::renderStatsAndLogs() {
(Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth))
? 80 : 20;
drawText(glWidget->getDeviceWidth() - 100, glWidget->getDeviceHeight() - timerBottom,
drawText(glWidget->width() - 100, glWidget->height() - timerBottom,
0.30f, 0.0f, 0, frameTimer, WHITE_TEXT);
}
nodeBoundsDisplay.drawOverlay();
@ -1247,8 +1247,8 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder() {
if (nodeList && !nodeList->getDomainHandler().isConnected()) {
GLCanvas* glWidget = Application::getInstance()->getGLWidget();
int right = glWidget->getDeviceWidth();
int bottom = glWidget->getDeviceHeight();
int right = glWidget->width();
int bottom = glWidget->height();
glColor3f(CONNECTION_STATUS_BORDER_COLOR[0],
CONNECTION_STATUS_BORDER_COLOR[1],

View file

@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <limits>
// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL
#include "InterfaceConfig.h"
@ -37,6 +39,8 @@
#include "Application.h"
#include "MetavoxelEditor.h"
using namespace std;
enum GridPlane {
GRID_PLANE_XY, GRID_PLANE_XZ, GRID_PLANE_YZ
};
@ -959,7 +963,8 @@ void HeightfieldTool::render() {
}
ImportHeightfieldTool::ImportHeightfieldTool(MetavoxelEditor* editor) :
HeightfieldTool(editor, "Import Heightfield") {
HeightfieldTool(editor, "Import Heightfield"),
_loadingImage(false) {
_form->addRow("Block Size:", _blockSize = new QSpinBox());
_blockSize->setPrefix("2^");
@ -970,6 +975,32 @@ ImportHeightfieldTool::ImportHeightfieldTool(MetavoxelEditor* editor) :
&ImportHeightfieldTool::updatePreview);
_form->addRow("Height:", _height = new QPushButton());
connect(_height, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectHeightFile);
_form->addRow(_rawOptions = new QWidget());
QHBoxLayout* rawLayout = new QHBoxLayout();
_rawOptions->setLayout(rawLayout);
_rawOptions->setVisible(false);
rawLayout->addStretch(1);
rawLayout->addWidget(new QLabel("Scale:"));
rawLayout->addWidget(_heightScale = new QDoubleSpinBox());
const double MAX_OFFSET_SCALE = 100000.0;
_heightScale->setMaximum(MAX_OFFSET_SCALE);
_heightScale->setSingleStep(0.0001);
_heightScale->setDecimals(4);
_heightScale->setValue(1.0);
connect(_heightScale, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this,
&ImportHeightfieldTool::updateHeightImage);
rawLayout->addSpacing(15);
rawLayout->addWidget(new QLabel("Offset:"));
rawLayout->addWidget(_heightOffset = new QDoubleSpinBox());
_heightOffset->setMinimum(-MAX_OFFSET_SCALE);
_heightOffset->setMaximum(MAX_OFFSET_SCALE);
_heightOffset->setDecimals(4);
connect(_heightOffset, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this,
&ImportHeightfieldTool::updateHeightImage);
_form->addRow("Color:", _color = new QPushButton());
connect(_color, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectColorFile);
@ -1012,22 +1043,50 @@ void ImportHeightfieldTool::apply() {
}
}
const float EIGHT_BIT_MAXIMUM = 255.0f;
void ImportHeightfieldTool::selectHeightFile() {
QString filename = QFileDialog::getOpenFileName(this, "Select Height Image", QString(), "Images (*.png *.jpg)");
QString filename = QFileDialog::getOpenFileName(this, "Select Height Image", QString(),
"Images (*.png *.jpg *.bmp *.raw)");
if (filename.isNull()) {
return;
}
if (filename.toLower().endsWith(".raw")) {
QFile input(filename);
input.open(QIODevice::ReadOnly);
QDataStream in(&input);
in.setByteOrder(QDataStream::LittleEndian);
_rawHeight.clear();
int minHeight = numeric_limits<quint16>::max();
int maxHeight = numeric_limits<quint16>::min();
while (!in.atEnd()) {
quint16 height;
in >> height;
_rawHeight.append(height);
minHeight = qMin(minHeight, (int)height);
maxHeight = qMax(maxHeight, (int)height);
}
_height->setText(filename);
_rawOptions->setVisible(true);
_loadingImage = true;
_heightScale->setValue((EIGHT_BIT_MAXIMUM - 1.0f) / (maxHeight - minHeight));
_heightOffset->setValue(-minHeight * _heightScale->value() + 1.0);
_loadingImage = false;
updateHeightImage();
return;
}
if (!_heightImage.load(filename)) {
QMessageBox::warning(this, "Invalid Image", "The selected image could not be read.");
return;
}
_rawOptions->setVisible(false);
_heightImage = _heightImage.convertToFormat(QImage::Format_RGB888);
_height->setText(filename);
updatePreview();
}
void ImportHeightfieldTool::selectColorFile() {
QString filename = QFileDialog::getOpenFileName(this, "Select Color Image", QString(), "Images (*.png *.jpg)");
QString filename = QFileDialog::getOpenFileName(this, "Select Color Image", QString(), "Images (*.png *.jpg *.bmp)");
if (filename.isNull()) {
return;
}
@ -1040,6 +1099,26 @@ void ImportHeightfieldTool::selectColorFile() {
updatePreview();
}
void ImportHeightfieldTool::updateHeightImage() {
if (_loadingImage) {
return;
}
int size = glm::sqrt(_rawHeight.size());
_heightImage = QImage(size, size, QImage::Format_RGB888);
const quint16* src = _rawHeight.constData();
float scale = _heightScale->value(), offset = _heightOffset->value();
for (int y = 0; y < size; y++) {
uchar* dest = _heightImage.scanLine(y);
for (const quint16* end = src + size; src != end; src++) {
uchar height = glm::clamp(*src * scale + offset, 1.0f, EIGHT_BIT_MAXIMUM);
*dest++ = height;
*dest++ = height;
*dest++ = height;
}
}
updatePreview();
}
void ImportHeightfieldTool::updatePreview() {
QVector<BufferDataPointer> buffers;
if (_heightImage.width() > 0 && _heightImage.height() > 0) {
@ -1061,7 +1140,7 @@ void ImportHeightfieldTool::updatePreview() {
uchar* src = _heightImage.scanLine(extendedI + y) + extendedJ * DataBlock::COLOR_BYTES;
char* dest = height.data() + (y + offsetY) * heightSize + offsetX;
for (int x = 0; x < columns; x++) {
*dest++ = *src;
*dest++ = qMax((uchar)1, *src);
src += DataBlock::COLOR_BYTES;
}
}

View file

@ -291,6 +291,7 @@ private slots:
void selectHeightFile();
void selectColorFile();
void updateHeightImage();
void updatePreview();
void renderPreview();
@ -299,8 +300,14 @@ private:
QSpinBox* _blockSize;
QPushButton* _height;
QWidget* _rawOptions;
QDoubleSpinBox* _heightScale;
QDoubleSpinBox* _heightOffset;
bool _loadingImage;
QPushButton* _color;
QVector<quint16> _rawHeight;
QImage _heightImage;
QImage _colorImage;

View file

@ -41,8 +41,8 @@ void NodeBounds::draw() {
// itself after the cursor disappears.
Application* application = Application::getInstance();
GLCanvas* glWidget = application->getGLWidget();
float mouseX = application->getMouseX() / (float)glWidget->getDeviceWidth();
float mouseY = application->getMouseY() / (float)glWidget->getDeviceHeight();
float mouseX = application->getMouseX() / (float)glWidget->width();
float mouseY = application->getMouseY() / (float)glWidget->height();
glm::vec3 mouseRayOrigin;
glm::vec3 mouseRayDirection;
application->getViewFrustum()->computePickRay(mouseX, mouseY, mouseRayOrigin, mouseRayDirection);

View file

@ -57,7 +57,7 @@ Stats::Stats():
_metavoxelReceiveTotal(0)
{
GLCanvas* glWidget = Application::getInstance()->getGLWidget();
resetWidth(glWidget->getDeviceWidth(), 0);
resetWidth(glWidget->width(), 0);
}
void Stats::toggleExpanded() {
@ -114,7 +114,7 @@ void Stats::checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseD
// top-right stats click
lines = _expanded ? 11 : 3;
statsHeight = lines * STATS_PELS_PER_LINE + 10;
statsWidth = glWidget->getDeviceWidth() - statsX;
statsWidth = glWidget->width() - statsX;
if (mouseX > statsX && mouseX < statsX + statsWidth && mouseY > statsY && mouseY < statsY + statsHeight) {
toggleExpanded();
return;
@ -123,7 +123,7 @@ void Stats::checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseD
void Stats::resetWidth(int width, int horizontalOffset) {
GLCanvas* glWidget = Application::getInstance()->getGLWidget();
int extraSpace = glWidget->getDeviceWidth() - horizontalOffset -2
int extraSpace = glWidget->width() - horizontalOffset -2
- STATS_GENERAL_MIN_WIDTH
- (Menu::getInstance()->isOptionChecked(MenuOption::TestPing) ? STATS_PING_MIN_WIDTH -1 : 0)
- STATS_GEO_MIN_WIDTH
@ -147,7 +147,7 @@ void Stats::resetWidth(int width, int horizontalOffset) {
_pingStatsWidth += (int) extraSpace / panels;
}
_geoStatsWidth += (int) extraSpace / panels;
_voxelStatsWidth += glWidget->getDeviceWidth() - (_generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3);
_voxelStatsWidth += glWidget->width() - (_generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3);
}
}
@ -210,7 +210,7 @@ void Stats::display(
std::stringstream voxelStats;
if (_lastHorizontalOffset != horizontalOffset) {
resetWidth(glWidget->getDeviceWidth(), horizontalOffset);
resetWidth(glWidget->width(), horizontalOffset);
_lastHorizontalOffset = horizontalOffset;
}
@ -410,7 +410,7 @@ void Stats::display(
}
}
drawBackground(backgroundColor, horizontalOffset, 0, glWidget->getDeviceWidth() - horizontalOffset,
drawBackground(backgroundColor, horizontalOffset, 0, glWidget->width() - horizontalOffset,
lines * STATS_PELS_PER_LINE + 10);
horizontalOffset += 5;

View file

@ -9,11 +9,14 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QApplication>
#include <QDesktopWidget>
#include <QFont>
#include <QPaintEngine>
#include <QtDebug>
#include <QString>
#include <QStringList>
#include <QWindow>
#include "InterfaceConfig.h"
#include "TextRenderer.h"
@ -25,10 +28,17 @@ Glyph::Glyph(int textureID, const QPoint& location, const QRect& bounds, int wid
_textureID(textureID), _location(location), _bounds(bounds), _width(width) {
}
TextRenderer::TextRenderer(const char* family, int pointSize, int weight,
bool italic, EffectType effectType, int effectThickness, QColor color)
: _font(family, pointSize, weight, italic), _metrics(_font), _effectType(effectType),
_effectThickness(effectThickness), _x(IMAGE_SIZE), _y(IMAGE_SIZE), _rowHeight(0), _color(color) {
TextRenderer::TextRenderer(const char* family, int pointSize, int weight, bool italic,
EffectType effectType, int effectThickness, QColor color) :
_font(family, pointSize, weight, italic),
_metrics(_font),
_effectType(effectType),
_effectThickness(effectThickness),
_x(IMAGE_SIZE),
_y(IMAGE_SIZE),
_rowHeight(0),
_color(color) {
_font.setKerning(false);
}
@ -73,7 +83,7 @@ int TextRenderer::draw(int x, int y, const char* str) {
int bottom = y + glyph.bounds().y();
int top = y + glyph.bounds().y() + glyph.bounds().height();
float scale = 1.0 / IMAGE_SIZE;
float scale = QApplication::desktop()->windowHandle()->devicePixelRatio() / IMAGE_SIZE;
float ls = glyph.location().x() * scale;
float rs = (glyph.location().x() + glyph.bounds().width()) * scale;
float bt = glyph.location().y() * scale;
@ -119,21 +129,25 @@ const Glyph& TextRenderer::getGlyph(char c) {
}
// we use 'J' as a representative size for the solid block character
QChar ch = (c == SOLID_BLOCK_CHAR) ? QChar('J') : QChar(c);
QRect bounds = _metrics.boundingRect(ch);
if (bounds.isEmpty()) {
QRect baseBounds = _metrics.boundingRect(ch);
if (baseBounds.isEmpty()) {
glyph = Glyph(0, QPoint(), QRect(), _metrics.width(ch));
return glyph;
}
// grow the bounds to account for effect, if any
if (_effectType == SHADOW_EFFECT) {
bounds.adjust(-_effectThickness, 0, 0, _effectThickness);
baseBounds.adjust(-_effectThickness, 0, 0, _effectThickness);
} else if (_effectType == OUTLINE_EFFECT) {
bounds.adjust(-_effectThickness, -_effectThickness, _effectThickness, _effectThickness);
baseBounds.adjust(-_effectThickness, -_effectThickness, _effectThickness, _effectThickness);
}
// grow the bounds to account for antialiasing
bounds.adjust(-1, -1, 1, 1);
baseBounds.adjust(-1, -1, 1, 1);
// adjust bounds for device pixel scaling
float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio();
QRect bounds(baseBounds.x() * ratio, baseBounds.y() * ratio, baseBounds.width() * ratio, baseBounds.height() * ratio);
if (_x + bounds.width() > IMAGE_SIZE) {
// we can't fit it on the current row; move to next
@ -162,9 +176,16 @@ const Glyph& TextRenderer::getGlyph(char c) {
} else {
image.fill(0);
QPainter painter(&image);
painter.setFont(_font);
QFont font = _font;
if (ratio == 1.0f) {
painter.setFont(_font);
} else {
QFont enlargedFont = _font;
enlargedFont.setPointSize(_font.pointSize() * ratio);
painter.setFont(enlargedFont);
}
if (_effectType == SHADOW_EFFECT) {
for (int i = 0; i < _effectThickness; i++) {
for (int i = 0; i < _effectThickness * ratio; i++) {
painter.drawText(-bounds.x() - 1 - i, -bounds.y() + 1 + i, ch);
}
} else if (_effectType == OUTLINE_EFFECT) {
@ -173,7 +194,7 @@ const Glyph& TextRenderer::getGlyph(char c) {
font.setStyleStrategy(QFont::ForceOutline);
path.addText(-bounds.x() - 0.5, -bounds.y() + 0.5, font, ch);
QPen pen;
pen.setWidth(_effectThickness);
pen.setWidth(_effectThickness * ratio);
pen.setJoinStyle(Qt::RoundJoin);
pen.setCapStyle(Qt::RoundCap);
painter.setPen(pen);
@ -185,7 +206,7 @@ const Glyph& TextRenderer::getGlyph(char c) {
}
glTexSubImage2D(GL_TEXTURE_2D, 0, _x, _y, bounds.width(), bounds.height(), GL_RGBA, GL_UNSIGNED_BYTE, image.constBits());
glyph = Glyph(_currentTextureID, QPoint(_x, _y), bounds, _metrics.width(ch));
glyph = Glyph(_currentTextureID, QPoint(_x / ratio, _y / ratio), baseBounds, _metrics.width(ch));
_x += bounds.width();
_rowHeight = qMax(_rowHeight, bounds.height());

View file

@ -0,0 +1,180 @@
//
// AudioBuffer.h
// hifi
//
// Created by Craig Hansen-Sturm on 8/29/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_AudioBuffer_h
#define hifi_AudioBuffer_h
#include <typeinfo>
template< typename T >
class AudioFrameBuffer {
uint16_t _channelCount;
uint16_t _channelCountMax;
uint16_t _frameCount;
uint16_t _frameCountMax;
T** _frameBuffer;
void allocateFrames() {
_frameBuffer = new T*[_channelCountMax];
if (_frameBuffer) {
for (uint16_t i = 0; i < _channelCountMax; ++i) {
_frameBuffer[i] = new T[_frameCountMax];
}
}
}
void deallocateFrames() {
if (_frameBuffer) {
for (uint16_t i = 0; i < _channelCountMax; ++i) {
delete _frameBuffer[i];
}
delete _frameBuffer;
}
_frameBuffer = NULL;
}
public:
AudioFrameBuffer() :
_channelCount(0),
_frameCount(0),
_frameCountMax(0),
_frameBuffer(NULL) {
}
AudioFrameBuffer(const uint16_t channelCount, const uint16_t frameCount) :
_channelCount(channelCount),
_channelCountMax(channelCount),
_frameCount(frameCount),
_frameCountMax(frameCount),
_frameBuffer(NULL) {
allocateFrames();
}
~AudioFrameBuffer() {
finalize();
}
void initialize(const uint16_t channelCount, const uint16_t frameCount) {
if (_frameBuffer) {
finalize();
}
_channelCount = channelCount;
_channelCountMax = channelCount;
_frameCount = frameCount;
_frameCountMax = frameCount;
allocateFrames();
}
void finalize() {
deallocateFrames();
_channelCount = 0;
_channelCountMax = 0;
_frameCount = 0;
_frameCountMax = 0;
}
T**& getFrameData() {
return _frameBuffer;
}
uint16_t getChannelCount() {
return _channelCount;
}
uint16_t getFrameCount() {
return _frameCount;
}
void zeroFrames() {
if (!_frameBuffer) {
return;
}
for (uint16_t i = 0; i < _channelCountMax; ++i) {
memset(_frameBuffer[i], 0, sizeof(T)*_frameCountMax);
}
}
template< typename S >
void copyFrames(uint16_t channelCount, const uint16_t frameCount, S* frames, const bool copyOut = false) {
if ( !_frameBuffer || !frames) {
return;
}
assert(channelCount <= _channelCountMax);
assert(frameCount <= _frameCountMax);
_frameCount = frameCount; // we allow copying fewer frames than we've allocated
_channelCount = channelCount; // we allow copying fewer channels that we've allocated
if (copyOut) {
S* dst = frames;
if(typeid(T) == typeid(S)) { // source and destination types are the same
for (int i = 0; i < _frameCount; ++i) {
for (int j = 0; j < _channelCount; ++j) {
*dst++ = _frameBuffer[j][i];
}
}
}
else {
if(typeid(T) == typeid(float32_t) &&
typeid(S) == typeid(int16_t)) {
const int scale = (2 << ((8 * sizeof(S)) - 1));
for (int i = 0; i < _frameCount; ++i) {
for (int j = 0; j < _channelCount; ++j) {
*dst++ = (S)(_frameBuffer[j][i] * scale);
}
}
}
else {
assert(0); // currently unsupported conversion
}
}
}
else { // copyIn
S* src = frames;
if(typeid(T) == typeid(S)) { // source and destination types are the same
for (int i = 0; i < _frameCount; ++i) {
for (int j = 0; j < _channelCount; ++j) {
_frameBuffer[j][i] = *src++;
}
}
}
else {
if(typeid(T) == typeid(float32_t) &&
typeid(S) == typeid(int16_t)) {
const int scale = (2 << ((8 * sizeof(S)) - 1));
for (int i = 0; i < _frameCount; ++i) {
for (int j = 0; j < _channelCount; ++j) {
_frameBuffer[j][i] = ((T)(*src++)) / scale;
}
}
}
else {
assert(0); // currently unsupported conversion
}
}
}
}
};
typedef AudioFrameBuffer< float32_t > AudioBufferFloat32;
typedef AudioFrameBuffer< int32_t > AudioBufferSInt32;
#endif // hifi_AudioBuffer_h

View file

@ -37,11 +37,11 @@ public:
//
// ctor/dtor
//
AudioBiquad()
: _xm1(0.)
, _xm2(0.)
, _ym1(0.)
, _ym2(0.) {
AudioBiquad() :
_xm1(0.),
_xm2(0.),
_ym1(0.),
_ym2(0.) {
setParameters(0.,0.,0.,0.,0.);
}

View file

@ -9,9 +9,12 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <assert.h>
#include <math.h>
#include <SharedUtil.h>
#include "AudioRingBuffer.h"
#include "AudioFormat.h"
#include "AudioBuffer.h"
#include "AudioFilter.h"
#include "AudioFilterBank.h"

View file

@ -49,9 +49,9 @@ public:
//
// ctor/dtor
//
AudioFilterBank()
: _sampleRate(0.)
, _frameCount(0) {
AudioFilterBank() :
_sampleRate(0.0f),
_frameCount(0) {
for (int i = 0; i < _channelCount; ++i) {
_buffer[ i ] = NULL;
}
@ -64,7 +64,7 @@ public:
//
// public interface
//
void initialize(const float sampleRate, const int frameCount) {
void initialize(const float sampleRate, const int frameCount = 0) {
finalize();
for (int i = 0; i < _channelCount; ++i) {
@ -141,6 +141,16 @@ public:
}
}
void render(AudioBufferFloat32& frameBuffer) {
float32_t** samples = frameBuffer.getFrameData();
for (uint16_t j = 0; j < frameBuffer.getChannelCount(); ++j) {
for (int i = 0; i < _filterCount; ++i) {
_filters[i][j].render( samples[j], samples[j], frameBuffer.getFrameCount() );
}
}
}
void reset() {
for (int i = 0; i < _filterCount; ++i) {
for (int j = 0; j < _channelCount; ++j) {

View file

@ -0,0 +1,85 @@
//
// AudioFormat.h
// hifi
//
// Created by Craig Hansen-Sturm on 8/28/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_AudioFormat_h
#define hifi_AudioFormat_h
#ifndef _FLOAT32_T
#define _FLOAT32_T
typedef float float32_t;
#endif
#ifndef _FLOAT64_T
#define _FLOAT64_T
typedef double float64_t;
#endif
//
// Audio format structure (currently for uncompressed streams only)
//
struct AudioFormat {
struct Flags {
uint32_t _isFloat : 1;
uint32_t _isSigned : 1;
uint32_t _isInterleaved : 1;
uint32_t _isBigEndian : 1;
uint32_t _isPacked : 1;
uint32_t _reserved : 27;
} _flags;
uint32_t _bytesPerFrame;
uint32_t _channelsPerFrame;
uint32_t _bitsPerChannel;
float64_t _sampleRate;
AudioFormat() {
memset(this, 0, sizeof(*this));
}
~AudioFormat() { }
AudioFormat& operator=(const AudioFormat& fmt) {
memcpy(this, &fmt, sizeof(*this));
return *this;
}
bool operator==(const AudioFormat& fmt) {
return memcmp(this, &fmt, sizeof(*this)) == 0;
}
bool operator!=(const AudioFormat& fmt) {
return memcmp(this, &fmt, sizeof(*this)) != 0;
}
void setCanonicalFloat32(uint32_t channels) {
assert(channels > 0 && channels <= 2);
_sampleRate = SAMPLE_RATE; // todo: create audio constants header
_bitsPerChannel = sizeof(float32_t) * 8;
_channelsPerFrame = channels;
_bytesPerFrame = _channelsPerFrame * _bitsPerChannel / 8;
_flags._isFloat = true;
_flags._isInterleaved = _channelsPerFrame > 1;
}
void setCanonicalInt16(uint32_t channels) {
assert(channels > 0 && channels <= 2);
_sampleRate = SAMPLE_RATE; // todo: create audio constants header
_bitsPerChannel = sizeof(int16_t) * 8;
_channelsPerFrame = channels;
_bytesPerFrame = _channelsPerFrame * _bitsPerChannel / 8;
_flags._isSigned = true;
_flags._isInterleaved = _channelsPerFrame > 1;
}
};
#endif // hifi_AudioFormat_h

View file

@ -0,0 +1,99 @@
//
// AudioGain.h
// hifi
//
// Created by Craig Hansen-Sturm on 9/1/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_AudioGain_h
#define hifi_AudioGain_h
class AudioGain
{
float32_t _gain;
bool _mute;
public:
AudioGain() {
initialize();
}
~AudioGain() {
finalize();
}
void initialize() {
setParameters(1.0f,0.0f);
}
void finalize() {
}
void reset() {
initialize();
}
void setParameters(const float gain, const float mute) {
_gain = std::min(std::max(gain, 0.0f), 1.0f);
_mute = mute != 0.0f;
}
void getParameters(float& gain, float& mute) {
gain = _gain;
mute = _mute ? 1.0f : 0.0f;
}
void render(AudioBufferFloat32& frameBuffer) {
if (_mute) {
frameBuffer.zeroFrames();
return;
}
float32_t** samples = frameBuffer.getFrameData();
for (uint16_t j = 0; j < frameBuffer.getChannelCount(); ++j) {
for (uint16_t i = 0; i < frameBuffer.getFrameCount(); i += 32) {
samples[j][i + 0] *= _gain;
samples[j][i + 1] *= _gain;
samples[j][i + 2] *= _gain;
samples[j][i + 3] *= _gain;
samples[j][i + 4] *= _gain;
samples[j][i + 5] *= _gain;
samples[j][i + 6] *= _gain;
samples[j][i + 7] *= _gain;
samples[j][i + 8] *= _gain;
samples[j][i + 9] *= _gain;
samples[j][i + 10] *= _gain;
samples[j][i + 11] *= _gain;
samples[j][i + 12] *= _gain;
samples[j][i + 13] *= _gain;
samples[j][i + 14] *= _gain;
samples[j][i + 15] *= _gain;
samples[j][i + 16] *= _gain;
samples[j][i + 17] *= _gain;
samples[j][i + 18] *= _gain;
samples[j][i + 19] *= _gain;
samples[j][i + 20] *= _gain;
samples[j][i + 21] *= _gain;
samples[j][i + 22] *= _gain;
samples[j][i + 23] *= _gain;
samples[j][i + 24] *= _gain;
samples[j][i + 25] *= _gain;
samples[j][i + 26] *= _gain;
samples[j][i + 27] *= _gain;
samples[j][i + 28] *= _gain;
samples[j][i + 29] *= _gain;
samples[j][i + 30] *= _gain;
samples[j][i + 31] *= _gain;
}
}
}
};
#endif // AudioGain_h

View file

@ -0,0 +1,21 @@
//
// AudioSourceNoise.cpp
// hifi
//
// Created by Craig Hansen-Sturm on 8/10/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 <assert.h>
#include <math.h>
#include <SharedUtil.h>
#include "AudioRingBuffer.h"
#include "AudioFormat.h"
#include "AudioBuffer.h"
#include "AudioSourceNoise.h"
template<>
uint32_t AudioSourcePinkNoise::_randomSeed = 1974; // a truly random number

View file

@ -0,0 +1,103 @@
//
// AudioSourceNoise.h
// hifi
//
// Created by Craig Hansen-Sturm on 9/1/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// Adapted from code by Phil Burk http://www.firstpr.com.au/dsp/pink-noise/
//
#ifndef hifi_AudioSourceNoise_h
#define hifi_AudioSourceNoise_h
template< const uint16_t N = 30>
class AudioSourceNoise
{
static const uint16_t _randomRows = N;
static const uint16_t _randomBits = 24;
static const uint16_t _randomShift = (sizeof(int32_t) * 8) - _randomBits;
static uint32_t _randomSeed;
int32_t _rows[_randomRows];
int32_t _runningSum; // used to optimize summing of generators.
uint16_t _index; // incremented each sample.
uint16_t _indexMask; // index wrapped by ANDing with this mask.
float32_t _scale; // used to scale within range of -1.0 to +1.0
static uint32_t generateRandomNumber() {
_randomSeed = (_randomSeed * 196314165) + 907633515;
return _randomSeed >> _randomShift;
}
public:
AudioSourceNoise() {
initialize();
}
~AudioSourceNoise() {
finalize();
}
void initialize() {
memset(_rows, 0, _randomRows * sizeof(int32_t));
_runningSum = 0;
_index = 0;
_indexMask = (1 << _randomRows) - 1;
_scale = 1.0f / ((_randomRows + 1) * (1 << (_randomBits - 1)));
}
void finalize() {
}
void reset() {
initialize();
}
void setParameters(void) {
}
void getParameters(void) {
}
void render(AudioBufferFloat32& frameBuffer) {
uint32_t randomNumber;
float32_t** samples = frameBuffer.getFrameData();
for (uint16_t i = 0; i < frameBuffer.getFrameCount(); ++i) {
for (uint16_t j = 0; j < frameBuffer.getChannelCount(); ++j) {
_index = (_index + 1) & _indexMask; // increment and mask index.
if (_index != 0) { // if index is zero, don't update any random values.
uint32_t numZeros = 0; // determine how many trailing zeros in _index
uint32_t tmp = _index;
while ((tmp & 1) == 0) {
tmp >>= 1;
numZeros++;
}
// replace the indexed _rows random value. subtract and add back to _runningSum instead
// of adding all the random values together. only one value changes each time.
_runningSum -= _rows[numZeros];
randomNumber = generateRandomNumber();
_runningSum += randomNumber;
_rows[numZeros] = randomNumber;
}
// add extra white noise value and scale between -1.0 and +1.0
samples[j][i] = (_runningSum + generateRandomNumber()) * _scale;
}
}
}
};
typedef AudioSourceNoise<> AudioSourcePinkNoise;
#endif // AudioSourceNoise_h

View file

@ -0,0 +1,20 @@
//
// AudioSourceTone.cpp
// hifi
//
// Created by Craig Hansen-Sturm on 8/10/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 <assert.h>
#include <math.h>
#include <SharedUtil.h>
#include "AudioRingBuffer.h"
#include "AudioFormat.h"
#include "AudioBuffer.h"
#include "AudioSourceTone.h"
uint32_t AudioSourceTone::_frameOffset = 0;

View file

@ -0,0 +1,72 @@
//
// AudioSourceTone.h
// hifi
//
// Created by Craig Hansen-Sturm on 9/1/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_AudioSourceTone_h
#define hifi_AudioSourceTone_h
class AudioSourceTone
{
static uint32_t _frameOffset;
float32_t _frequency;
float32_t _amplitude;
float32_t _sampleRate;
float32_t _omega;
public:
AudioSourceTone() {
initialize();
}
~AudioSourceTone() {
finalize();
}
void initialize() {
_frameOffset = 0;
setParameters(SAMPLE_RATE, 220.0f, 0.9f);
}
void finalize() {
}
void reset() {
_frameOffset = 0;
}
void setParameters(const float32_t sampleRate, const float32_t frequency, const float32_t amplitude) {
_sampleRate = std::max(sampleRate, 1.0f);
_frequency = std::max(frequency, 1.0f);
_amplitude = std::max(amplitude, 1.0f);
_omega = _frequency / _sampleRate * TWO_PI;
}
void getParameters(float32_t& sampleRate, float32_t& frequency, float32_t& amplitude) {
sampleRate = _sampleRate;
frequency = _frequency;
amplitude = _amplitude;
}
void render(AudioBufferFloat32& frameBuffer) {
// note: this is a placeholder implementation. final version will not include any transcendental ops in our render loop
float32_t** samples = frameBuffer.getFrameData();
for (uint16_t i = 0; i < frameBuffer.getFrameCount(); ++i) {
for (uint16_t j = 0; j < frameBuffer.getChannelCount(); ++j) {
samples[j][i] = sinf((i + _frameOffset) * _omega);
}
}
_frameOffset += frameBuffer.getFrameCount();
}
};
#endif

View file

@ -16,6 +16,8 @@
#include <AABox.h>
#include "InboundAudioStream.h"
#include "AudioFormat.h"
#include "AudioBuffer.h"
#include "AudioFilter.h"
#include "AudioFilterBank.h"

View file

@ -35,7 +35,8 @@ using namespace std;
AvatarData::AvatarData() :
_sessionUUID(),
_handPosition(0,0,0),
_position(0.0f),
_handPosition(0.0f),
_referential(NULL),
_bodyYaw(-90.f),
_bodyPitch(0.0f),
@ -326,7 +327,7 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
}
return maxAvailableSize;
}
_position = position;
setPosition(position);
// rotation (NOTE: This needs to become a quaternion to save two bytes)
float yaw, pitch, roll;