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

This commit is contained in:
Andrzej Kapolka 2014-02-13 16:51:44 -08:00
commit 1fba28d45e
12 changed files with 259 additions and 215 deletions

View file

@ -7,9 +7,11 @@
//
// Captures mouse clicks and edits voxels accordingly.
//
// click = create a new voxel on this face, same color as old
// Alt + click = delete this voxel
// click = create a new voxel on this face, same color as old (default color picker state)
// right click or control + click = delete this voxel
// shift + click = recolor this voxel
// 1 - 8 = pick new color from palette
// 9 = create a new voxel in front of the camera
//
// Click and drag to create more new voxels in the same direction
//
@ -18,15 +20,41 @@ function vLength(v) {
return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
}
function vMinus(a, b) {
var rval = { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z };
return rval;
}
var NEW_VOXEL_SIZE = 1.0;
var NEW_VOXEL_DISTANCE_FROM_CAMERA = 3.0;
var ORBIT_RATE_ALTITUDE = 200.0;
var ORBIT_RATE_AZIMUTH = 90.0;
var PIXELS_PER_EXTRUDE_VOXEL = 16;
var oldMode = Camera.getMode();
var key_alt = false;
var key_shift = false;
var isAdding = false;
var isExtruding = false;
var isOrbiting = false;
var orbitAzimuth = 0.0;
var orbitAltitude = 0.0;
var orbitCenter = { x: 0, y: 0, z: 0 };
var orbitPosition = { x: 0, y: 0, z: 0 };
var orbitRadius = 0.0;
var extrudeDirection = { x: 0, y: 0, z: 0 };
var extrudeScale = 0.0;
var lastVoxelPosition = { x: 0, y: 0, z: 0 };
var lastVoxelColor = { red: 0, green: 0, blue: 0 };
var lastVoxelScale = 0;
var dragStart = { x: 0, y: 0 };
var mouseX = 0;
var mouseY = 0;
// Create a table of the different colors you can choose
var colors = new Array();
colors[0] = { red: 237, green: 175, blue: 0 };
@ -37,31 +65,70 @@ colors[4] = { red: 193, green: 99, blue: 122 };
colors[5] = { red: 255, green: 54, blue: 69 };
colors[6] = { red: 124, green: 36, blue: 36 };
colors[7] = { red: 63, green: 35, blue: 19 };
var numColors = 6;
var whichColor = 0;
var numColors = 8;
var whichColor = -1; // Starting color is 'Copy' mode
// Create sounds for adding, deleting, recoloring voxels
var addSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Electronic/ElectronicBurst1.raw");
var deleteSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Bubbles/bubbles1.raw");
var changeColorSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Electronic/ElectronicBurst6.raw");
var addSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+create.raw");
var deleteSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+delete.raw");
var changeColorSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+edit.raw");
var clickSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Switches+and+sliders/toggle+switch+-+medium.raw");
var audioOptions = new AudioInjectionOptions();
audioOptions.volume = 0.5;
function setAudioPosition() {
var camera = Camera.getPosition();
var forwardVector = Quat.getFront(MyAvatar.orientation);
audioOptions.position = Vec3.sum(camera, forwardVector);
}
function getNewVoxelPosition() {
var camera = Camera.getPosition();
var forwardVector = Quat.getFront(MyAvatar.orientation);
var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, NEW_VOXEL_DISTANCE_FROM_CAMERA));
return newPosition;
}
function fixEulerAngles(eulers) {
var rVal = { x: 0, y: 0, z: eulers.z };
if (eulers.x >= 90.0) {
rVal.x = 180.0 - eulers.x;
rVal.y = eulers.y - 180.0;
} else if (eulers.x <= -90.0) {
rVal.x = 180.0 - eulers.x;
rVal.y = eulers.y - 180.0;
}
return rVal;
}
function mousePressEvent(event) {
mouseX = event.x;
mouseY = event.y;
var pickRay = Camera.computePickRay(event.x, event.y);
var intersection = Voxels.findRayIntersection(pickRay);
audioOptions.volume = 1.0;
audioOptions.position = { x: intersection.voxel.x, y: intersection.voxel.y, z: intersection.voxel.z };
audioOptions.position = Vec3.sum(pickRay.origin, pickRay.direction);
if (intersection.intersects) {
if (key_alt) {
if (event.isAlt) {
// start orbit camera!
var cameraPosition = Camera.getPosition();
oldMode = Camera.getMode();
Camera.setMode("independent");
isOrbiting = true;
Camera.keepLookingAt(intersection.intersection);
// get position for initial azimuth, elevation
orbitCenter = intersection.intersection;
var orbitVector = Vec3.subtract(cameraPosition, orbitCenter);
orbitRadius = vLength(orbitVector);
orbitAzimuth = Math.atan2(orbitVector.z, orbitVector.x);
orbitAltitude = Math.asin(orbitVector.y / Vec3.length(orbitVector));
} else if (event.isRightButton || event.isControl) {
// Delete voxel
Voxels.eraseVoxel(intersection.voxel.x, intersection.voxel.y, intersection.voxel.z, intersection.voxel.s);
Audio.playSound(deleteSound, audioOptions);
} else if (key_shift) {
} else if (event.isShifted) {
// Recolor Voxel
whichColor++;
if (whichColor == numColors) whichColor = 0;
Voxels.setVoxel(intersection.voxel.x,
intersection.voxel.y,
intersection.voxel.z,
@ -70,7 +137,9 @@ function mousePressEvent(event) {
Audio.playSound(changeColorSound, audioOptions);
} else {
// Add voxel on face
var newVoxel = {
if (whichColor == -1) {
// Copy mode - use clicked voxel color
var newVoxel = {
x: intersection.voxel.x,
y: intersection.voxel.y,
z: intersection.voxel.z,
@ -78,6 +147,16 @@ function mousePressEvent(event) {
red: intersection.voxel.red,
green: intersection.voxel.green,
blue: intersection.voxel.blue };
} else {
var newVoxel = {
x: intersection.voxel.x,
y: intersection.voxel.y,
z: intersection.voxel.z,
s: intersection.voxel.s,
red: colors[whichColor].red,
green: colors[whichColor].green,
blue: colors[whichColor].blue };
}
if (intersection.face == "MIN_X_FACE") {
newVoxel.x -= newVoxel.s;
@ -108,55 +187,113 @@ function mousePressEvent(event) {
function keyPressEvent(event) {
key_alt = event.isAlt;
key_shift = event.isShifted;
var nVal = parseInt(event.text);
if (event.text == "0") {
print("Color = Copy");
whichColor = -1;
Audio.playSound(clickSound, audioOptions);
} else if ((nVal > 0) && (nVal <= numColors)) {
whichColor = nVal - 1;
print("Color = " + (whichColor + 1));
Audio.playSound(clickSound, audioOptions);
} else if (event.text == "9") {
// Create a brand new 1 meter voxel in front of your avatar
var color = whichColor;
if (color == -1) color = 0;
var newPosition = getNewVoxelPosition();
var newVoxel = {
x: newPosition.x,
y: newPosition.y ,
z: newPosition.z,
s: NEW_VOXEL_SIZE,
red: colors[color].red,
green: colors[color].green,
blue: colors[color].blue };
Voxels.setVoxel(newVoxel.x, newVoxel.y, newVoxel.z, newVoxel.s, newVoxel.red, newVoxel.green, newVoxel.blue);
setAudioPosition();
Audio.playSound(addSound, audioOptions);
} else if (event.text == " ") {
// Reset my orientation!
var orientation = { x:0, y:0, z:0, w:1 };
Camera.setOrientation(orientation);
MyAvatar.orientation = orientation;
}
}
function keyReleaseEvent(event) {
key_alt = false;
key_shift = false;
}
function mouseMoveEvent(event) {
if (isOrbiting) {
var cameraOrientation = Camera.getOrientation();
var origEulers = Quat.safeEulerAngles(cameraOrientation);
var newEulers = fixEulerAngles(Quat.safeEulerAngles(cameraOrientation));
var dx = event.x - mouseX;
var dy = event.y - mouseY;
orbitAzimuth += dx / ORBIT_RATE_AZIMUTH;
orbitAltitude += dy / ORBIT_RATE_ALTITUDE;
var orbitVector = { x:(Math.cos(orbitAltitude) * Math.cos(orbitAzimuth)) * orbitRadius,
y:Math.sin(orbitAltitude) * orbitRadius,
z:(Math.cos(orbitAltitude) * Math.sin(orbitAzimuth)) * orbitRadius };
orbitPosition = Vec3.sum(orbitCenter, orbitVector);
Camera.setPosition(orbitPosition);
mouseX = event.x;
mouseY = event.y;
}
if (isAdding) {
var pickRay = Camera.computePickRay(event.x, event.y);
var lastVoxelDistance = { x: pickRay.origin.x - lastVoxelPosition.x,
// Watch the drag direction to tell which way to 'extrude' this voxel
if (!isExtruding) {
var pickRay = Camera.computePickRay(event.x, event.y);
var lastVoxelDistance = { x: pickRay.origin.x - lastVoxelPosition.x,
y: pickRay.origin.y - lastVoxelPosition.y,
z: pickRay.origin.z - lastVoxelPosition.z };
var distance = vLength(lastVoxelDistance);
var mouseSpot = { x: pickRay.direction.x * distance, y: pickRay.direction.y * distance, z: pickRay.direction.z * distance };
mouseSpot.x += pickRay.origin.x;
mouseSpot.y += pickRay.origin.y;
mouseSpot.z += pickRay.origin.z;
var dx = mouseSpot.x - lastVoxelPosition.x;
var dy = mouseSpot.y - lastVoxelPosition.y;
var dz = mouseSpot.z - lastVoxelPosition.z;
if (dx > lastVoxelScale) {
lastVoxelPosition.x += lastVoxelScale;
Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z,
lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue);
} else if (dx < -lastVoxelScale) {
lastVoxelPosition.x -= lastVoxelScale;
Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z,
lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue);
} else if (dy > lastVoxelScale) {
lastVoxelPosition.y += lastVoxelScale;
Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z,
lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue);
} else if (dy < -lastVoxelScale) {
lastVoxelPosition.y -= lastVoxelScale;
Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z,
lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue);
} else if (dz > lastVoxelScale) {
lastVoxelPosition.z += lastVoxelScale;
Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z,
lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue);
} else if (dz < -lastVoxelScale) {
lastVoxelPosition.z -= lastVoxelScale;
Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z,
lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue);
var distance = vLength(lastVoxelDistance);
var mouseSpot = { x: pickRay.direction.x * distance, y: pickRay.direction.y * distance, z: pickRay.direction.z * distance };
mouseSpot.x += pickRay.origin.x;
mouseSpot.y += pickRay.origin.y;
mouseSpot.z += pickRay.origin.z;
var dx = mouseSpot.x - lastVoxelPosition.x;
var dy = mouseSpot.y - lastVoxelPosition.y;
var dz = mouseSpot.z - lastVoxelPosition.z;
extrudeScale = lastVoxelScale;
extrudeDirection = { x: 0, y: 0, z: 0 };
isExtruding = true;
if (dx > lastVoxelScale) extrudeDirection.x = extrudeScale;
else if (dx < -lastVoxelScale) extrudeDirection.x = -extrudeScale;
else if (dy > lastVoxelScale) extrudeDirection.y = extrudeScale;
else if (dy < -lastVoxelScale) extrudeDirection.y = -extrudeScale;
else if (dz > lastVoxelScale) extrudeDirection.z = extrudeScale;
else if (dz < -lastVoxelScale) extrudeDirection.z = -extrudeScale;
else isExtruding = false;
} else {
// We have got an extrusion direction, now look for mouse move beyond threshold to add new voxel
var dx = event.x - mouseX;
var dy = event.y - mouseY;
if (Math.sqrt(dx*dx + dy*dy) > PIXELS_PER_EXTRUDE_VOXEL) {
lastVoxelPosition = Vec3.sum(lastVoxelPosition, extrudeDirection);
Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z,
extrudeScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue);
mouseX = event.x;
mouseY = event.y;
}
}
}
}
function mouseReleaseEvent(event) {
if (isOrbiting) {
var cameraOrientation = Camera.getOrientation();
var eulers = Quat.safeEulerAngles(cameraOrientation);
MyAvatar.position = Camera.getPosition();
MyAvatar.orientation = cameraOrientation;
Camera.stopLooking();
Camera.setMode(oldMode);
Camera.setOrientation(cameraOrientation);
}
isAdding = false;
isOrbiting = false;
isExtruding = false;
}
Controller.mousePressEvent.connect(mousePressEvent);

View file

@ -2146,15 +2146,6 @@ void Application::updateThreads(float deltaTime) {
}
}
void Application::updateParticles(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateParticles()");
if (Menu::getInstance()->isOptionChecked(MenuOption::ParticleCloud)) {
_cloud.simulate(deltaTime);
}
}
void Application::updateMetavoxels(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateMetavoxels()");
@ -2276,7 +2267,6 @@ void Application::update(float deltaTime) {
updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
_avatarManager.updateOtherAvatars(deltaTime); //loop through all the other avatars and simulate them...
updateParticles(deltaTime); // Simulate particle cloud movements
updateMetavoxels(deltaTime); // update metavoxels
updateCamera(deltaTime); // handle various camera tweaks like off axis projection
updateDialogs(deltaTime); // update various stats dialogs if present
@ -2711,10 +2701,6 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
// disable specular lighting for ground and voxels
glMaterialfv(GL_FRONT, GL_SPECULAR, NO_SPECULAR_COLOR);
// Draw Cloud Particles
if (Menu::getInstance()->isOptionChecked(MenuOption::ParticleCloud)) {
_cloud.render();
}
// Draw voxels
if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),

View file

@ -32,7 +32,6 @@
#include "BandwidthMeter.h"
#include "Camera.h"
#include "Cloud.h"
#include "DatagramProcessor.h"
#include "Environment.h"
#include "GLCanvas.h"
@ -285,7 +284,6 @@ private:
void updateSixense(float deltaTime);
void updateSerialDevices(float deltaTime);
void updateThreads(float deltaTime);
void updateParticles(float deltaTime);
void updateMetavoxels(float deltaTime);
void updateCamera(float deltaTime);
void updateDialogs(float deltaTime);
@ -352,8 +350,6 @@ private:
Stars _stars;
Cloud _cloud;
VoxelSystem _voxels;
VoxelTree _clipboard; // if I copy/paste
VoxelImporter* _voxelImporter;

View file

@ -37,6 +37,8 @@ static const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_LENGTH_MSECS * NUM_AUDI
static const float AUDIO_CALLBACK_MSECS = (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float)SAMPLE_RATE * 1000.0;
static const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 300;
// Mute icon configration
static const int ICON_SIZE = 24;
static const int ICON_LEFT = 0;
@ -65,7 +67,8 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* p
_measuredJitter(0),
_jitterBufferSamples(initialJitterBufferSamples),
_lastInputLoudness(0),
_averageInputLoudness(0),
_noiseGateMeasuredFloor(0),
_noiseGateSampleCounter(0),
_noiseGateOpen(false),
_noiseGateEnabled(true),
_noiseGateFramesToClose(0),
@ -82,6 +85,8 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* p
{
// clear the array of locally injected samples
memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL);
// Create the noise sample array
_noiseSampleFrames = new float[NUMBER_OF_NOISE_SAMPLE_FRAMES];
}
void Audio::init(QGLWidget *parent) {
@ -351,26 +356,66 @@ void Audio::handleAudioInput() {
NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL,
_inputFormat, _desiredInputFormat);
//
// Impose Noise Gate
//
// The Noise Gate is used to reject constant background noise by measuring the noise
// floor observed at the microphone and then opening the 'gate' to allow microphone
// signals to be transmitted when the microphone samples average level exceeds a multiple
// of the noise floor.
//
// NOISE_GATE_HEIGHT: How loud you have to speak relative to noise background to open the gate.
// Make this value lower for more sensitivity and less rejection of noise.
// NOISE_GATE_WIDTH: The number of samples in an audio frame for which the height must be exceeded
// to open the gate.
// NOISE_GATE_CLOSE_FRAME_DELAY: Once the noise is below the gate height for the frame, how many frames
// will we wait before closing the gate.
// NOISE_GATE_FRAMES_TO_AVERAGE: How many audio frames should we average together to compute noise floor.
// More means better rejection but also can reject continuous things like singing.
// NUMBER_OF_NOISE_SAMPLE_FRAMES: How often should we re-evaluate the noise floor?
float loudness = 0;
float thisSample = 0;
int samplesOverNoiseGate = 0;
const float NOISE_GATE_HEIGHT = 3.f;
const float NOISE_GATE_HEIGHT = 7.f;
const int NOISE_GATE_WIDTH = 5;
const int NOISE_GATE_CLOSE_FRAME_DELAY = 30;
const int NOISE_GATE_CLOSE_FRAME_DELAY = 5;
const int NOISE_GATE_FRAMES_TO_AVERAGE = 5;
for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) {
thisSample = fabsf(monoAudioSamples[i]);
loudness += thisSample;
// Noise Reduction: Count peaks above the average loudness
if (thisSample > (_averageInputLoudness * NOISE_GATE_HEIGHT)) {
if (thisSample > (_noiseGateMeasuredFloor * NOISE_GATE_HEIGHT)) {
samplesOverNoiseGate++;
}
}
_lastInputLoudness = loudness / NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
const float LOUDNESS_AVERAGING_FRAMES = 1000.f; // This will be about 10 seconds
_averageInputLoudness = (1.f - 1.f / LOUDNESS_AVERAGING_FRAMES) * _averageInputLoudness + (1.f / LOUDNESS_AVERAGING_FRAMES) * _lastInputLoudness;
float averageOfAllSampleFrames = 0.f;
_noiseSampleFrames[_noiseGateSampleCounter++] = _lastInputLoudness;
if (_noiseGateSampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) {
float smallestSample = FLT_MAX;
for (int i = 0; i <= NUMBER_OF_NOISE_SAMPLE_FRAMES - NOISE_GATE_FRAMES_TO_AVERAGE; i+= NOISE_GATE_FRAMES_TO_AVERAGE) {
float thisAverage = 0.0f;
for (int j = i; j < i + NOISE_GATE_FRAMES_TO_AVERAGE; j++) {
thisAverage += _noiseSampleFrames[j];
averageOfAllSampleFrames += _noiseSampleFrames[j];
}
thisAverage /= NOISE_GATE_FRAMES_TO_AVERAGE;
if (thisAverage < smallestSample) {
smallestSample = thisAverage;
}
}
averageOfAllSampleFrames /= NUMBER_OF_NOISE_SAMPLE_FRAMES;
_noiseGateMeasuredFloor = smallestSample;
_noiseGateSampleCounter = 0;
//qDebug("smallest sample = %.1f, avg of all = %.1f", _noiseGateMeasuredFloor, averageOfAllSampleFrames);
}
if (_noiseGateEnabled) {
if (samplesOverNoiseGate > NOISE_GATE_WIDTH) {
_noiseGateOpen = true;
@ -487,7 +532,7 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) {
if (!_ringBuffer.isStarved() && _audioOutput->bytesFree() == _audioOutput->bufferSize()) {
// we don't have any audio data left in the output buffer
// we just starved
qDebug() << "Audio output just starved.";
//qDebug() << "Audio output just starved.";
_ringBuffer.setIsStarved(true);
_numFramesDisplayStarve = 10;
}
@ -505,7 +550,7 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) {
if (!_ringBuffer.isNotStarvedOrHasMinimumSamples(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO
+ (_jitterBufferSamples * 2))) {
// starved and we don't have enough to start, keep waiting
qDebug() << "Buffer is starved and doesn't have enough samples to start. Held back.";
//qDebug() << "Buffer is starved and doesn't have enough samples to start. Held back.";
} else {
// We are either already playing back, or we have enough audio to start playing back.
_ringBuffer.setIsStarved(false);

View file

@ -45,7 +45,7 @@ public:
void render(int screenWidth, int screenHeight);
float getLastInputLoudness() const { return glm::max(_lastInputLoudness - _averageInputLoudness, 0.f); }
float getLastInputLoudness() const { return glm::max(_lastInputLoudness - _noiseGateMeasuredFloor, 0.f); }
void setNoiseGateEnabled(bool noiseGateEnabled) { _noiseGateEnabled = noiseGateEnabled; }
@ -109,7 +109,9 @@ private:
float _measuredJitter;
int16_t _jitterBufferSamples;
float _lastInputLoudness;
float _averageInputLoudness;
float _noiseGateMeasuredFloor;
float* _noiseSampleFrames;
int _noiseGateSampleCounter;
bool _noiseGateOpen;
bool _noiseGateEnabled;
int _noiseGateFramesToClose;

View file

@ -1,85 +0,0 @@
//
// Cloud.cpp
// interface
//
// Created by Philip Rosedale on 11/17/12.
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
//
#include <iostream>
#include <InterfaceConfig.h>
#include "Cloud.h"
#include "Util.h"
#include "Field.h"
const int NUM_PARTICLES = 100000;
const float FIELD_COUPLE = 0.001f;
const bool RENDER_FIELD = false;
Cloud::Cloud() {
glm::vec3 box = glm::vec3(PARTICLE_WORLD_SIZE);
_bounds = box;
_count = NUM_PARTICLES;
_particles = new Particle[_count];
_field = new Field(PARTICLE_WORLD_SIZE, FIELD_COUPLE);
for (unsigned int i = 0; i < _count; i++) {
_particles[i].position = randVector() * box;
const float INIT_VEL_SCALE = 0.03f;
_particles[i].velocity = randVector() * ((float)PARTICLE_WORLD_SIZE * INIT_VEL_SCALE);
_particles[i].color = randVector();
}
}
void Cloud::render() {
if (RENDER_FIELD) {
_field->render();
}
glPointSize(3.0f);
glDisable(GL_TEXTURE_2D);
glEnable(GL_POINT_SMOOTH);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(3, GL_FLOAT, 3 * sizeof(glm::vec3), &_particles[0].position);
glColorPointer(3, GL_FLOAT, 3 * sizeof(glm::vec3), &_particles[0].color);
glDrawArrays(GL_POINTS, 0, NUM_PARTICLES);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
}
void Cloud::simulate (float deltaTime) {
unsigned int i;
_field->simulate(deltaTime);
for (i = 0; i < _count; ++i) {
// Update position
_particles[i].position += _particles[i].velocity * deltaTime;
// Decay Velocity (Drag)
const float CONSTANT_DAMPING = 0.15f;
_particles[i].velocity *= (1.f - CONSTANT_DAMPING * deltaTime);
// Interact with Field
_field->interact(deltaTime, _particles[i].position, _particles[i].velocity);
// Update color to velocity
_particles[i].color = (glm::normalize(_particles[i].velocity) * 0.5f) + 0.5f;
// Bounce at bounds
if ((_particles[i].position.x > _bounds.x) || (_particles[i].position.x < 0.f)) {
_particles[i].position.x = glm::clamp(_particles[i].position.x, 0.f, _bounds.x);
_particles[i].velocity.x *= -1.f;
}
if ((_particles[i].position.y > _bounds.y) || (_particles[i].position.y < 0.f)) {
_particles[i].position.y = glm::clamp(_particles[i].position.y, 0.f, _bounds.y);
_particles[i].velocity.y *= -1.f;
}
if ((_particles[i].position.z > _bounds.z) || (_particles[i].position.z < 0.f)) {
_particles[i].position.z = glm::clamp(_particles[i].position.z, 0.f, _bounds.z);
_particles[i].velocity.z *= -1.f;
}
}
}

View file

@ -1,32 +0,0 @@
//
// Cloud.h
// interface
//
// Created by Philip Rosedale on 11/17/12.
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__Cloud__
#define __interface__Cloud__
#include "Field.h"
#define PARTICLE_WORLD_SIZE 256.0
class Cloud {
public:
Cloud();
void simulate(float deltaTime);
void render();
private:
struct Particle {
glm::vec3 position, velocity, color;
}* _particles;
unsigned int _count;
glm::vec3 _bounds;
Field* _field;
};
#endif

View file

@ -161,7 +161,7 @@ Menu::Menu() :
#endif
addDisabledActionAndSeparator(editMenu, "Physics");
addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::Gravity, Qt::SHIFT | Qt::Key_G, true);
addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::Gravity, Qt::SHIFT | Qt::Key_G, false);
addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::ClickToFly);
@ -238,9 +238,9 @@ Menu::Menu() :
SLOT(setFullscreen(bool)));
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, Qt::Key_P, true,
appInstance,SLOT(cameraMenuChanged()));
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H);
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H,false,
appInstance,SLOT(cameraMenuChanged()));
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H, true);
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false,
appInstance, SLOT(cameraMenuChanged()));
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Enable3DTVMode, 0,
false,
@ -266,14 +266,8 @@ Menu::Menu() :
appInstance->getAvatar(),
SLOT(resetSize()));
addCheckableActionToQMenuAndActionHash(viewMenu,
MenuOption::OffAxisProjection,
0,
true);
addCheckableActionToQMenuAndActionHash(viewMenu,
MenuOption::TurnWithHead,
0,
true);
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::OffAxisProjection, 0, false);
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false);
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::MoveWithLean, 0, false);
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HeadMouse, 0, false);
@ -298,7 +292,6 @@ Menu::Menu() :
appInstance->getGlowEffect(),
SLOT(cycleRenderMode()));
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ParticleCloud, 0, false);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Shadows, 0, false);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, false);
@ -339,14 +332,14 @@ Menu::Menu() :
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Avatars, 0, true);
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::CollisionProxies);
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::LookAtVectors, 0, true);
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::LookAtVectors, 0, false);
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu,
MenuOption::FaceshiftTCP,
0,
false,
appInstance->getFaceshift(),
SLOT(setTCPEnabled(bool)));
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, true);
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, false);
QMenu* handOptionsMenu = developerMenu->addMenu("Hand Options");
@ -356,7 +349,7 @@ Menu::Menu() :
true,
appInstance->getSixenseManager(),
SLOT(setFilter(bool)));
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayLeapHands, 0, true);
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHands, 0, true);
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false);
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::VoxelDrumming, 0, false);
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::PlaySlaps, 0, false);

View file

@ -183,7 +183,7 @@ namespace MenuOption {
const QString DisableDeltaSending = "Disable Delta Sending";
const QString DisableLowRes = "Disable Lower Resolution While Moving";
const QString DisplayFrustum = "Display Frustum";
const QString DisplayLeapHands = "Display Leap Hands";
const QString DisplayHands = "Display Hands";
const QString DisplayHandTargets = "Display Hand Targets";
const QString FilterSixense = "Smooth Sixense Movement";
const QString DontRenderVoxels = "Don't call _voxels.render()";
@ -223,7 +223,6 @@ namespace MenuOption {
const QString KillLocalVoxels = "Kill Local Voxels";
const QString GoHome = "Go Home";
const QString Gravity = "Use Gravity";
const QString ParticleCloud = "Particle Cloud";
const QString LodTools = "LOD Tools";
const QString Log = "Log";
const QString Login = "Login";

View file

@ -304,7 +304,7 @@ void Hand::render(bool isMine) {
}
}
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayLeapHands)) {
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayHands)) {
renderLeapHands(isMine);
}

View file

@ -26,7 +26,9 @@ glm::vec3 Vec3::multiplyQbyV(const glm::quat& q, const glm::vec3& v) {
glm::vec3 Vec3::sum(const glm::vec3& v1, const glm::vec3& v2) {
return v1 + v2;
}
glm::vec3 Vec3::subtract(const glm::vec3& v1, const glm::vec3& v2) {
return v1 - v2;
}
float Vec3::length(const glm::vec3& v) {
return glm::length(v);
}

View file

@ -25,6 +25,7 @@ public slots:
glm::vec3 multiply(const glm::vec3& v1, float f);
glm::vec3 multiplyQbyV(const glm::quat& q, const glm::vec3& v);
glm::vec3 sum(const glm::vec3& v1, const glm::vec3& v2);
glm::vec3 subtract(const glm::vec3& v1, const glm::vec3& v2);
float length(const glm::vec3& v);
};