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

This commit is contained in:
Atlante45 2014-10-14 14:54:27 -07:00
commit 4a3f72ab0b
36 changed files with 792 additions and 405 deletions

View file

@ -46,6 +46,7 @@
#include <NetworkAccessManager.h> #include <NetworkAccessManager.h>
#include <NodeList.h> #include <NodeList.h>
#include <Node.h> #include <Node.h>
#include <OctreeConstants.h>
#include <PacketHeaders.h> #include <PacketHeaders.h>
#include <SharedUtil.h> #include <SharedUtil.h>
#include <StdDev.h> #include <StdDev.h>
@ -65,6 +66,8 @@ const float LOUDNESS_TO_DISTANCE_RATIO = 0.00001f;
const float DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE = 0.18; const float DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE = 0.18;
const QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer"; const QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer";
const QString AUDIO_ENV_GROUP_KEY = "audio_env";
const QString AUDIO_BUFFER_GROUP_KEY = "audio_buffer";
void attachNewNodeDataToNode(Node *newNode) { void attachNewNodeDataToNode(Node *newNode) {
if (!newNode->getLinkedData()) { if (!newNode->getLinkedData()) {
@ -87,8 +90,6 @@ AudioMixer::AudioMixer(const QByteArray& packet) :
_numStatFrames(0), _numStatFrames(0),
_sumListeners(0), _sumListeners(0),
_sumMixes(0), _sumMixes(0),
_sourceUnattenuatedZone(NULL),
_listenerUnattenuatedZone(NULL),
_lastPerSecondCallbackTime(usecTimestampNow()), _lastPerSecondCallbackTime(usecTimestampNow()),
_sendAudioStreamStats(false), _sendAudioStreamStats(false),
_datagramsReadPerCallStats(0, READ_DATAGRAMS_STATS_WINDOW_SECONDS), _datagramsReadPerCallStats(0, READ_DATAGRAMS_STATS_WINDOW_SECONDS),
@ -100,18 +101,13 @@ AudioMixer::AudioMixer(const QByteArray& packet) :
// we will soon find a better common home for these audio-related constants // we will soon find a better common home for these audio-related constants
} }
AudioMixer::~AudioMixer() {
delete _sourceUnattenuatedZone;
delete _listenerUnattenuatedZone;
}
const float ATTENUATION_BEGINS_AT_DISTANCE = 1.0f; const float ATTENUATION_BEGINS_AT_DISTANCE = 1.0f;
const float RADIUS_OF_HEAD = 0.076f; const float RADIUS_OF_HEAD = 0.076f;
int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* listenerNodeData, int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* listenerNodeData,
const QUuid& streamUUID, const QUuid& streamUUID,
PositionalAudioStream* streamToAdd, PositionalAudioStream* streamToAdd,
AvatarAudioStream* listeningNodeStream) { AvatarAudioStream* listeningNodeStream) {
// If repetition with fade is enabled: // If repetition with fade is enabled:
// If streamToAdd could not provide a frame (it was starved), then we'll mix its previously-mixed frame // If streamToAdd could not provide a frame (it was starved), then we'll mix its previously-mixed frame
// This is preferable to not mixing it at all since that's equivalent to inserting silence. // This is preferable to not mixing it at all since that's equivalent to inserting silence.
@ -120,9 +116,9 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l
// This improves the perceived quality of the audio slightly. // This improves the perceived quality of the audio slightly.
bool showDebug = false; // (randFloat() < 0.05f); bool showDebug = false; // (randFloat() < 0.05f);
float repeatedFrameFadeFactor = 1.0f; float repeatedFrameFadeFactor = 1.0f;
if (!streamToAdd->lastPopSucceeded()) { if (!streamToAdd->lastPopSucceeded()) {
if (_streamSettings._repetitionWithFade && !streamToAdd->getLastPopOutput().isNull()) { if (_streamSettings._repetitionWithFade && !streamToAdd->getLastPopOutput().isNull()) {
// reptition with fade is enabled, and we do have a valid previous frame to repeat. // reptition with fade is enabled, and we do have a valid previous frame to repeat.
@ -135,21 +131,19 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l
return 0; return 0;
} }
} }
// at this point, we know streamToAdd's last pop output is valid // at this point, we know streamToAdd's last pop output is valid
// if the frame we're about to mix is silent, bail // if the frame we're about to mix is silent, bail
if (streamToAdd->getLastPopOutputLoudness() == 0.0f) { if (streamToAdd->getLastPopOutputLoudness() == 0.0f) {
return 0; return 0;
} }
float bearingRelativeAngleToSource = 0.0f; float bearingRelativeAngleToSource = 0.0f;
float attenuationCoefficient = 1.0f; float attenuationCoefficient = 1.0f;
int numSamplesDelay = 0; int numSamplesDelay = 0;
float weakChannelAmplitudeRatio = 1.0f; float weakChannelAmplitudeRatio = 1.0f;
bool shouldDistanceAttenuate = true;
// Is the source that I am mixing my own? // Is the source that I am mixing my own?
bool sourceIsSelf = (streamToAdd == listeningNodeStream); bool sourceIsSelf = (streamToAdd == listeningNodeStream);
@ -169,10 +163,6 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l
++_sumMixes; ++_sumMixes;
if (streamToAdd->getListenerUnattenuatedZone()) {
shouldDistanceAttenuate = !streamToAdd->getListenerUnattenuatedZone()->contains(listeningNodeStream->getPosition());
}
if (streamToAdd->getType() == PositionalAudioStream::Injector) { if (streamToAdd->getType() == PositionalAudioStream::Injector) {
attenuationCoefficient *= reinterpret_cast<InjectedAudioStream*>(streamToAdd)->getAttenuationRatio(); attenuationCoefficient *= reinterpret_cast<InjectedAudioStream*>(streamToAdd)->getAttenuationRatio();
if (showDebug) { if (showDebug) {
@ -207,11 +197,28 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l
attenuationCoefficient *= offAxisCoefficient; attenuationCoefficient *= offAxisCoefficient;
} }
bool wantBreak = false;
float attenuationPerDoublingInDistance = _attenuationPerDoublingInDistance;
foreach (const QString& source, _attenuationCoefficients.keys()) {
if (_audioZones[source].contains(streamToAdd->getPosition())) {
foreach (const QString& listener, _attenuationCoefficients[source].keys()) {
if (_audioZones[listener].contains(listeningNodeStream->getPosition())) {
attenuationPerDoublingInDistance = _attenuationCoefficients[source][listener];
wantBreak = true;
break;
}
}
}
if (wantBreak) {
break;
}
}
if (shouldDistanceAttenuate && (distanceBetween >= ATTENUATION_BEGINS_AT_DISTANCE)) { if (distanceBetween >= ATTENUATION_BEGINS_AT_DISTANCE) {
// calculate the distance coefficient using the distance to this node // calculate the distance coefficient using the distance to this node
float distanceCoefficient = 1 - (logf(distanceBetween / ATTENUATION_BEGINS_AT_DISTANCE) / logf(2.0f) float distanceCoefficient = 1 - (logf(distanceBetween / ATTENUATION_BEGINS_AT_DISTANCE) / logf(2.0f)
* _attenuationPerDoublingInDistance); * attenuationPerDoublingInDistance);
if (distanceCoefficient < 0) { if (distanceCoefficient < 0) {
distanceCoefficient = 0; distanceCoefficient = 0;
@ -637,120 +644,7 @@ void AudioMixer::run() {
const QJsonObject& settingsObject = domainHandler.getSettingsObject(); const QJsonObject& settingsObject = domainHandler.getSettingsObject();
// check the settings object to see if we have anything we can parse out // check the settings object to see if we have anything we can parse out
const QString AUDIO_GROUP_KEY = "audio"; parseSettingsObject(settingsObject);
if (settingsObject.contains(AUDIO_GROUP_KEY)) {
QJsonObject audioGroupObject = settingsObject[AUDIO_GROUP_KEY].toObject();
// check the payload to see if we have asked for dynamicJitterBuffer support
const QString DYNAMIC_JITTER_BUFFER_JSON_KEY = "dynamic_jitter_buffer";
_streamSettings._dynamicJitterBuffers = audioGroupObject[DYNAMIC_JITTER_BUFFER_JSON_KEY].toBool();
if (_streamSettings._dynamicJitterBuffers) {
qDebug() << "Enable dynamic jitter buffers.";
} else {
qDebug() << "Dynamic jitter buffers disabled.";
}
bool ok;
const QString DESIRED_JITTER_BUFFER_FRAMES_KEY = "static_desired_jitter_buffer_frames";
_streamSettings._staticDesiredJitterBufferFrames = audioGroupObject[DESIRED_JITTER_BUFFER_FRAMES_KEY].toString().toInt(&ok);
if (!ok) {
_streamSettings._staticDesiredJitterBufferFrames = DEFAULT_STATIC_DESIRED_JITTER_BUFFER_FRAMES;
}
qDebug() << "Static desired jitter buffer frames:" << _streamSettings._staticDesiredJitterBufferFrames;
const QString MAX_FRAMES_OVER_DESIRED_JSON_KEY = "max_frames_over_desired";
_streamSettings._maxFramesOverDesired = audioGroupObject[MAX_FRAMES_OVER_DESIRED_JSON_KEY].toString().toInt(&ok);
if (!ok) {
_streamSettings._maxFramesOverDesired = DEFAULT_MAX_FRAMES_OVER_DESIRED;
}
qDebug() << "Max frames over desired:" << _streamSettings._maxFramesOverDesired;
const QString USE_STDEV_FOR_DESIRED_CALC_JSON_KEY = "use_stdev_for_desired_calc";
_streamSettings._useStDevForJitterCalc = audioGroupObject[USE_STDEV_FOR_DESIRED_CALC_JSON_KEY].toBool();
if (_streamSettings._useStDevForJitterCalc) {
qDebug() << "Using Philip's stdev method for jitter calc if dynamic jitter buffers enabled";
} else {
qDebug() << "Using Fred's max-gap method for jitter calc if dynamic jitter buffers enabled";
}
const QString WINDOW_STARVE_THRESHOLD_JSON_KEY = "window_starve_threshold";
_streamSettings._windowStarveThreshold = audioGroupObject[WINDOW_STARVE_THRESHOLD_JSON_KEY].toString().toInt(&ok);
if (!ok) {
_streamSettings._windowStarveThreshold = DEFAULT_WINDOW_STARVE_THRESHOLD;
}
qDebug() << "Window A starve threshold:" << _streamSettings._windowStarveThreshold;
const QString WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES_JSON_KEY = "window_seconds_for_desired_calc_on_too_many_starves";
_streamSettings._windowSecondsForDesiredCalcOnTooManyStarves = audioGroupObject[WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES_JSON_KEY].toString().toInt(&ok);
if (!ok) {
_streamSettings._windowSecondsForDesiredCalcOnTooManyStarves = DEFAULT_WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES;
}
qDebug() << "Window A length:" << _streamSettings._windowSecondsForDesiredCalcOnTooManyStarves << "seconds";
const QString WINDOW_SECONDS_FOR_DESIRED_REDUCTION_JSON_KEY = "window_seconds_for_desired_reduction";
_streamSettings._windowSecondsForDesiredReduction = audioGroupObject[WINDOW_SECONDS_FOR_DESIRED_REDUCTION_JSON_KEY].toString().toInt(&ok);
if (!ok) {
_streamSettings._windowSecondsForDesiredReduction = DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION;
}
qDebug() << "Window B length:" << _streamSettings._windowSecondsForDesiredReduction << "seconds";
const QString REPETITION_WITH_FADE_JSON_KEY = "repetition_with_fade";
_streamSettings._repetitionWithFade = audioGroupObject[REPETITION_WITH_FADE_JSON_KEY].toBool();
if (_streamSettings._repetitionWithFade) {
qDebug() << "Repetition with fade enabled";
} else {
qDebug() << "Repetition with fade disabled";
}
const QString PRINT_STREAM_STATS_JSON_KEY = "print_stream_stats";
_printStreamStats = audioGroupObject[PRINT_STREAM_STATS_JSON_KEY].toBool();
if (_printStreamStats) {
qDebug() << "Stream stats will be printed to stdout";
}
const QString FILTER_KEY = "enable_filter";
if (audioGroupObject[FILTER_KEY].isBool()) {
_enableFilter = audioGroupObject[FILTER_KEY].toBool();
}
if (_enableFilter) {
qDebug() << "Filter enabled";
}
const QString UNATTENUATED_ZONE_KEY = "unattenuated_zone";
QString unattenuatedZoneString = audioGroupObject[UNATTENUATED_ZONE_KEY].toString();
if (!unattenuatedZoneString.isEmpty()) {
QStringList zoneStringList = unattenuatedZoneString.split(',');
glm::vec3 sourceCorner(zoneStringList[0].toFloat(), zoneStringList[1].toFloat(), zoneStringList[2].toFloat());
glm::vec3 sourceDimensions(zoneStringList[3].toFloat(), zoneStringList[4].toFloat(), zoneStringList[5].toFloat());
glm::vec3 listenerCorner(zoneStringList[6].toFloat(), zoneStringList[7].toFloat(), zoneStringList[8].toFloat());
glm::vec3 listenerDimensions(zoneStringList[9].toFloat(), zoneStringList[10].toFloat(), zoneStringList[11].toFloat());
_sourceUnattenuatedZone = new AABox(sourceCorner, sourceDimensions);
_listenerUnattenuatedZone = new AABox(listenerCorner, listenerDimensions);
glm::vec3 sourceCenter = _sourceUnattenuatedZone->calcCenter();
glm::vec3 destinationCenter = _listenerUnattenuatedZone->calcCenter();
qDebug() << "There is an unattenuated zone with source center at"
<< QString("%1, %2, %3").arg(sourceCenter.x).arg(sourceCenter.y).arg(sourceCenter.z);
qDebug() << "Buffers inside this zone will not be attenuated inside a box with center at"
<< QString("%1, %2, %3").arg(destinationCenter.x).arg(destinationCenter.y).arg(destinationCenter.z);
}
const QString ATTENATION_PER_DOULING_IN_DISTANCE = "attenuation_per_doubling_in_distance";
if (audioGroupObject[ATTENATION_PER_DOULING_IN_DISTANCE].isString()) {
bool ok = false;
float attenuation = audioGroupObject[ATTENATION_PER_DOULING_IN_DISTANCE].toString().toFloat(&ok);
if (ok) {
_attenuationPerDoublingInDistance = attenuation;
qDebug() << "Attenuation per doubling in distance changed to" << _attenuationPerDoublingInDistance;
}
}
}
int nextFrame = 0; int nextFrame = 0;
QElapsedTimer timer; QElapsedTimer timer;
@ -829,7 +723,7 @@ void AudioMixer::run() {
// this function will attempt to pop a frame from each audio stream. // this function will attempt to pop a frame from each audio stream.
// a pointer to the popped data is stored as a member in InboundAudioStream. // a pointer to the popped data is stored as a member in InboundAudioStream.
// That's how the popped audio data will be read for mixing (but only if the pop was successful) // That's how the popped audio data will be read for mixing (but only if the pop was successful)
nodeData->checkBuffersBeforeFrameSend(_sourceUnattenuatedZone, _listenerUnattenuatedZone); nodeData->checkBuffersBeforeFrameSend();
if (node->getType() == NodeType::Agent && node->getActiveSocket() if (node->getType() == NodeType::Agent && node->getActiveSocket()
&& nodeData->getAvatarAudioStream()) { && nodeData->getAvatarAudioStream()) {
@ -982,3 +876,178 @@ QString AudioMixer::getReadPendingDatagramsHashMatchTimeStatsString() const {
+ " prct_time_in_hashmatch_1s: " + QString::number(_timeSpentPerHashMatchCallStats.getLastCompleteIntervalStats().getSum() / USECS_PER_SECOND * 100.0, 'f', 6) + "%"; + " prct_time_in_hashmatch_1s: " + QString::number(_timeSpentPerHashMatchCallStats.getLastCompleteIntervalStats().getSum() / USECS_PER_SECOND * 100.0, 'f', 6) + "%";
return result; return result;
} }
void AudioMixer::parseSettingsObject(const QJsonObject &settingsObject) {
if (settingsObject.contains(AUDIO_BUFFER_GROUP_KEY)) {
QJsonObject audioBufferGroupObject = settingsObject[AUDIO_BUFFER_GROUP_KEY].toObject();
// check the payload to see if we have asked for dynamicJitterBuffer support
const QString DYNAMIC_JITTER_BUFFER_JSON_KEY = "dynamic_jitter_buffer";
_streamSettings._dynamicJitterBuffers = audioBufferGroupObject[DYNAMIC_JITTER_BUFFER_JSON_KEY].toBool();
if (_streamSettings._dynamicJitterBuffers) {
qDebug() << "Enable dynamic jitter buffers.";
} else {
qDebug() << "Dynamic jitter buffers disabled.";
}
bool ok;
const QString DESIRED_JITTER_BUFFER_FRAMES_KEY = "static_desired_jitter_buffer_frames";
_streamSettings._staticDesiredJitterBufferFrames = audioBufferGroupObject[DESIRED_JITTER_BUFFER_FRAMES_KEY].toString().toInt(&ok);
if (!ok) {
_streamSettings._staticDesiredJitterBufferFrames = DEFAULT_STATIC_DESIRED_JITTER_BUFFER_FRAMES;
}
qDebug() << "Static desired jitter buffer frames:" << _streamSettings._staticDesiredJitterBufferFrames;
const QString MAX_FRAMES_OVER_DESIRED_JSON_KEY = "max_frames_over_desired";
_streamSettings._maxFramesOverDesired = audioBufferGroupObject[MAX_FRAMES_OVER_DESIRED_JSON_KEY].toString().toInt(&ok);
if (!ok) {
_streamSettings._maxFramesOverDesired = DEFAULT_MAX_FRAMES_OVER_DESIRED;
}
qDebug() << "Max frames over desired:" << _streamSettings._maxFramesOverDesired;
const QString USE_STDEV_FOR_DESIRED_CALC_JSON_KEY = "use_stdev_for_desired_calc";
_streamSettings._useStDevForJitterCalc = audioBufferGroupObject[USE_STDEV_FOR_DESIRED_CALC_JSON_KEY].toBool();
if (_streamSettings._useStDevForJitterCalc) {
qDebug() << "Using Philip's stdev method for jitter calc if dynamic jitter buffers enabled";
} else {
qDebug() << "Using Fred's max-gap method for jitter calc if dynamic jitter buffers enabled";
}
const QString WINDOW_STARVE_THRESHOLD_JSON_KEY = "window_starve_threshold";
_streamSettings._windowStarveThreshold = audioBufferGroupObject[WINDOW_STARVE_THRESHOLD_JSON_KEY].toString().toInt(&ok);
if (!ok) {
_streamSettings._windowStarveThreshold = DEFAULT_WINDOW_STARVE_THRESHOLD;
}
qDebug() << "Window A starve threshold:" << _streamSettings._windowStarveThreshold;
const QString WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES_JSON_KEY = "window_seconds_for_desired_calc_on_too_many_starves";
_streamSettings._windowSecondsForDesiredCalcOnTooManyStarves = audioBufferGroupObject[WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES_JSON_KEY].toString().toInt(&ok);
if (!ok) {
_streamSettings._windowSecondsForDesiredCalcOnTooManyStarves = DEFAULT_WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES;
}
qDebug() << "Window A length:" << _streamSettings._windowSecondsForDesiredCalcOnTooManyStarves << "seconds";
const QString WINDOW_SECONDS_FOR_DESIRED_REDUCTION_JSON_KEY = "window_seconds_for_desired_reduction";
_streamSettings._windowSecondsForDesiredReduction = audioBufferGroupObject[WINDOW_SECONDS_FOR_DESIRED_REDUCTION_JSON_KEY].toString().toInt(&ok);
if (!ok) {
_streamSettings._windowSecondsForDesiredReduction = DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION;
}
qDebug() << "Window B length:" << _streamSettings._windowSecondsForDesiredReduction << "seconds";
const QString REPETITION_WITH_FADE_JSON_KEY = "repetition_with_fade";
_streamSettings._repetitionWithFade = audioBufferGroupObject[REPETITION_WITH_FADE_JSON_KEY].toBool();
if (_streamSettings._repetitionWithFade) {
qDebug() << "Repetition with fade enabled";
} else {
qDebug() << "Repetition with fade disabled";
}
const QString PRINT_STREAM_STATS_JSON_KEY = "print_stream_stats";
_printStreamStats = audioBufferGroupObject[PRINT_STREAM_STATS_JSON_KEY].toBool();
if (_printStreamStats) {
qDebug() << "Stream stats will be printed to stdout";
}
}
if (settingsObject.contains(AUDIO_ENV_GROUP_KEY)) {
QJsonObject audioEnvGroupObject = settingsObject[AUDIO_ENV_GROUP_KEY].toObject();
const QString ATTENATION_PER_DOULING_IN_DISTANCE = "attenuation_per_doubling_in_distance";
if (audioEnvGroupObject[ATTENATION_PER_DOULING_IN_DISTANCE].isString()) {
bool ok = false;
float attenuation = audioEnvGroupObject[ATTENATION_PER_DOULING_IN_DISTANCE].toString().toFloat(&ok);
if (ok) {
_attenuationPerDoublingInDistance = attenuation;
qDebug() << "Attenuation per doubling in distance changed to" << _attenuationPerDoublingInDistance;
}
}
const QString FILTER_KEY = "enable_filter";
if (audioEnvGroupObject[FILTER_KEY].isBool()) {
_enableFilter = audioEnvGroupObject[FILTER_KEY].toBool();
}
if (_enableFilter) {
qDebug() << "Filter enabled";
}
const QString AUDIO_ZONES = "zones";
if (audioEnvGroupObject[AUDIO_ZONES].isObject()) {
const QJsonObject& zones = audioEnvGroupObject[AUDIO_ZONES].toObject();
const QString X_RANGE = "x_range";
const QString Y_RANGE = "y_range";
const QString Z_RANGE = "z_range";
foreach (const QString& zone, zones.keys()) {
QJsonObject zoneObject = zones[zone].toObject();
if (zoneObject.contains(X_RANGE) && zoneObject.contains(Y_RANGE) && zoneObject.contains(Z_RANGE)) {
QStringList xRange = zoneObject.value(X_RANGE).toString().split("-", QString::SkipEmptyParts);
QStringList yRange = zoneObject.value(Y_RANGE).toString().split("-", QString::SkipEmptyParts);
QStringList zRange = zoneObject.value(Z_RANGE).toString().split("-", QString::SkipEmptyParts);
if (xRange.size() == 2 && yRange.size() == 2 && zRange.size() == 2) {
float xMin, xMax, yMin, yMax, zMin, zMax;
bool ok, allOk = true;
xMin = xRange[0].toFloat(&ok);
allOk &= ok;
xMax = xRange[1].toFloat(&ok);
allOk &= ok;
yMin = yRange[0].toFloat(&ok);
allOk &= ok;
yMax = yRange[1].toFloat(&ok);
allOk &= ok;
zMin = zRange[0].toFloat(&ok);
allOk &= ok;
zMax = zRange[1].toFloat(&ok);
allOk &= ok;
if (allOk) {
glm::vec3 corner(xMin, yMin, zMin);
glm::vec3 dimensions(xMax - xMin, yMax - yMin, zMax - zMin);
AABox zoneAABox(corner, dimensions);
_audioZones.insert(zone, zoneAABox);
qDebug() << "Added zone:" << zone << "(corner:" << corner
<< ", dimensions:" << dimensions << ")";
}
}
}
}
}
const QString ATTENUATION_COEFFICIENTS = "attenuation_coefficients";
if (audioEnvGroupObject[ATTENUATION_COEFFICIENTS].isArray()) {
const QJsonArray& coefficients = audioEnvGroupObject[ATTENUATION_COEFFICIENTS].toArray();
const QString SOURCE = "source";
const QString LISTENER = "listener";
const QString COEFFICIENT = "coefficient";
for (int i = 0; i < coefficients.count(); ++i) {
QJsonObject coefficientObject = coefficients[i].toObject();
if (coefficientObject.contains(SOURCE) &&
coefficientObject.contains(LISTENER) &&
coefficientObject.contains(COEFFICIENT)) {
bool ok;
QString source = coefficientObject.value(SOURCE).toString();
QString listener = coefficientObject.value(LISTENER).toString();
float coefficient = coefficientObject.value(COEFFICIENT).toString().toFloat(&ok);
if (ok && coefficient >= 0.0f && coefficient <= 1.0f &&
_audioZones.contains(source) && _audioZones.contains(listener)) {
if (!_attenuationCoefficients.contains(source)) {
_attenuationCoefficients.insert(source, QHash<QString, float>());
}
if (!_attenuationCoefficients[source].contains(listener)) {
_attenuationCoefficients[source].insert(listener, coefficient);
qDebug() << "Added Coefficient:" << source << listener << coefficient;
}
}
}
}
}
}
}

View file

@ -29,7 +29,6 @@ class AudioMixer : public ThreadedAssignment {
Q_OBJECT Q_OBJECT
public: public:
AudioMixer(const QByteArray& packet); AudioMixer(const QByteArray& packet);
~AudioMixer();
public slots: public slots:
/// threaded run of assignment /// threaded run of assignment
void run(); void run();
@ -66,6 +65,8 @@ private:
QString getReadPendingDatagramsTimeStatsString() const; QString getReadPendingDatagramsTimeStatsString() const;
QString getReadPendingDatagramsHashMatchTimeStatsString() const; QString getReadPendingDatagramsHashMatchTimeStatsString() const;
void parseSettingsObject(const QJsonObject& settingsObject);
float _trailingSleepRatio; float _trailingSleepRatio;
float _minAudibilityThreshold; float _minAudibilityThreshold;
float _performanceThrottlingRatio; float _performanceThrottlingRatio;
@ -73,8 +74,8 @@ private:
int _numStatFrames; int _numStatFrames;
int _sumListeners; int _sumListeners;
int _sumMixes; int _sumMixes;
AABox* _sourceUnattenuatedZone; QHash<QString, AABox> _audioZones;
AABox* _listenerUnattenuatedZone; QHash<QString, QHash<QString, float> > _attenuationCoefficients;
static InboundAudioStream::Settings _streamSettings; static InboundAudioStream::Settings _streamSettings;

View file

@ -106,7 +106,7 @@ int AudioMixerClientData::parseData(const QByteArray& packet) {
return 0; return 0;
} }
void AudioMixerClientData::checkBuffersBeforeFrameSend(AABox* checkSourceZone, AABox* listenerZone) { void AudioMixerClientData::checkBuffersBeforeFrameSend() {
QHash<QUuid, PositionalAudioStream*>::ConstIterator i; QHash<QUuid, PositionalAudioStream*>::ConstIterator i;
for (i = _audioStreams.constBegin(); i != _audioStreams.constEnd(); i++) { for (i = _audioStreams.constBegin(); i != _audioStreams.constEnd(); i++) {
PositionalAudioStream* stream = i.value(); PositionalAudioStream* stream = i.value();
@ -114,12 +114,6 @@ void AudioMixerClientData::checkBuffersBeforeFrameSend(AABox* checkSourceZone, A
if (stream->popFrames(1, true) > 0) { if (stream->popFrames(1, true) > 0) {
stream->updateLastPopOutputLoudnessAndTrailingLoudness(); stream->updateLastPopOutputLoudnessAndTrailingLoudness();
} }
if (checkSourceZone && checkSourceZone->contains(stream->getPosition())) {
stream->setListenerUnattenuatedZone(listenerZone);
} else {
stream->setListenerUnattenuatedZone(NULL);
}
} }
} }

View file

@ -42,7 +42,7 @@ public:
int parseData(const QByteArray& packet); int parseData(const QByteArray& packet);
void checkBuffersBeforeFrameSend(AABox* checkSourceZone, AABox* listenerZone); void checkBuffersBeforeFrameSend();
void removeDeadInjectedStreams(); void removeDeadInjectedStreams();

View file

@ -6,7 +6,7 @@
{ {
"name": "access_token", "name": "access_token",
"label": "Access Token", "label": "Access Token",
"help": "This is an access token generated on the <a href='https://data.highfidelity.io/tokens' target='_blank'>My Tokens</a> page of your High Fidelity account.<br/>Generate a token with the 'domains' scope and paste it here.<br/>This is required to associate this domain-server with a domain in your account." "help": "This is an access token generated on the <a href='https://data.highfidelity.io/user/security' target='_blank'>My Security</a> page of your High Fidelity account.<br/>Generate a token with the 'domains' scope and paste it here.<br/>This is required to associate this domain-server with a domain in your account."
}, },
{ {
"name": "id", "name": "id",
@ -63,10 +63,24 @@
] ]
}, },
{ {
"name": "audio", "name": "audio_env",
"label": "Audio", "label": "Audio Environment",
"assignment-types": [0], "assignment-types": [0],
"settings": [ "settings": [
{
"name": "attenuation_per_doubling_in_distance",
"label": "Default Domain Attenuation",
"help": "Factor between 0 and 1.0 (0: No attenuation, 1.0: extreme attenuation)",
"placeholder": "0.18",
"default": "0.18",
"advanced": false
},
{
"name": "enable_filter",
"type": "checkbox",
"help": "positional audio stream uses lowpass filter",
"default": true
},
{ {
"name": "zones", "name": "zones",
"type": "table", "type": "table",
@ -76,7 +90,7 @@
"key": { "key": {
"name": "name", "name": "name",
"label": "Name", "label": "Name",
"placeholder": "Zone name" "placeholder": "Zone_Name"
}, },
"columns": [ "columns": [
{ {
@ -125,28 +139,14 @@
"placeholder": "0.18" "placeholder": "0.18"
} }
] ]
}, }
{ ]
"name": "enable_filter", },
"type": "checkbox", {
"label": "Positional filter", "name": "audio_buffer",
"help": "positional audio stream uses lowpass filter", "label": "Audio Buffer",
"default": true "assignment-types": [0],
}, "settings": [
{
"name": "unattenuated_zone",
"label": "Unattenuated Zone",
"help": "Boxes for source and listener (corner x, corner y, corner z, size x, size y, size z, corner x, corner y, corner z, size x, size y, size z)",
"placeholder": "no zone"
},
{
"name": "attenuation_per_doubling_in_distance",
"label": "Attenuation per doubling in distance",
"help": "Factor between 0.0 and 1.0 (0.0: No attenuation, 1.0: extreme attenuation)",
"placeholder": "0.18",
"default": "0.18",
"advanced": false
},
{ {
"name": "dynamic_jitter_buffer", "name": "dynamic_jitter_buffer",
"type": "checkbox", "type": "checkbox",

View file

@ -35,7 +35,9 @@ var viewHelpers = {
+ " " + Settings.TRIGGER_CHANGE_CLASS + "' data-short-name='" + setting.name + "' name='" + setting_name + "' " + " " + Settings.TRIGGER_CHANGE_CLASS + "' data-short-name='" + setting.name + "' name='" + setting_name + "' "
if (setting.type === 'checkbox') { if (setting.type === 'checkbox') {
form_group += "<label class='" + label_class + "'>" + setting.label + "</label>" if (setting.label) {
form_group += "<label class='" + label_class + "'>" + setting.label + "</label>"
}
form_group += "<div class='checkbox" + (isLocked ? " disabled" : "") + "'>" form_group += "<div class='checkbox" + (isLocked ? " disabled" : "") + "'>"
form_group += "<label for='" + setting_name + "'>" form_group += "<label for='" + setting_name + "'>"
form_group += "<input type='checkbox'" + common_attrs + (setting_value ? "checked" : "") + (isLocked ? " disabled" : "") + "/>" form_group += "<input type='checkbox'" + common_attrs + (setting_value ? "checked" : "") + (isLocked ? " disabled" : "") + "/>"
@ -45,8 +47,10 @@ var viewHelpers = {
form_group += makeTable(setting, setting_name, setting_value); form_group += makeTable(setting, setting_name, setting_value);
} else { } else {
input_type = _.has(setting, 'type') ? setting.type : "text" input_type = _.has(setting, 'type') ? setting.type : "text"
form_group += "<label for='" + setting_name + "' class='" + label_class + "'>" + setting.label + "</label>"; if (setting.label) {
form_group += "<label for='" + setting_name + "' class='" + label_class + "'>" + setting.label + "</label>";
}
if (setting.type === 'select') { if (setting.type === 'select') {
form_group += "<select class='form-control' data-hidden-input='" + setting_name + "'>'" form_group += "<select class='form-control' data-hidden-input='" + setting_name + "'>'"
@ -235,7 +239,7 @@ $('body').on('click', '.save-button', function(e){
function makeTable(setting, setting_name, setting_value) { function makeTable(setting, setting_name, setting_value) {
var isArray = !_.has(setting, 'key') var isArray = !_.has(setting, 'key')
var html = "<label class='control-label'>" + setting.label + "</label>" var html = (setting.label) ? "<label class='control-label'>" + setting.label + "</label>" : ""
html += "<span class='help-block'>" + setting.help + "</span>" html += "<span class='help-block'>" + setting.help + "</span>"
html += "<table class='table table-bordered' data-short-name='" + setting.name + "' name='" + setting_name html += "<table class='table table-bordered' data-short-name='" + setting.name + "' name='" + setting_name
+ "' data-setting-type='" + (isArray ? 'array' : 'hash') + "'>" + "' data-setting-type='" + (isArray ? 'array' : 'hash') + "'>"
@ -317,7 +321,7 @@ function makeTableInputs(setting) {
_.each(setting.columns, function(col) { _.each(setting.columns, function(col) {
html += "<td class='" + Settings.DATA_COL_CLASS + "'name='" + col.name + "'>\ html += "<td class='" + Settings.DATA_COL_CLASS + "'name='" + col.name + "'>\
<input type='text' class='form-control' placeholder='" + (col.key ? col.key : "") + "' value=''>\ <input type='text' class='form-control' placeholder='" + (col.placeholder ? col.placeholder : "") + "' value=''>\
</td>" </td>"
}) })
@ -487,7 +491,7 @@ function deleteTableRow(delete_glyphicon) {
row.removeClass(Settings.DATA_ROW_CLASS).removeClass(Settings.NEW_ROW_CLASS) row.removeClass(Settings.DATA_ROW_CLASS).removeClass(Settings.NEW_ROW_CLASS)
row.addClass('empty-array-row') row.addClass('empty-array-row')
row.html("<input type='hidden' class='form-control' name='" + table.attr("name").replace('[]', '') row.html("<input type='hidden' class='form-control' name='" + table.attr("name").replace('[]', '')
+ "' data-changed='true' value=''>"); + "' data-changed='true' value=''>");
} }

View file

@ -1312,7 +1312,6 @@ var toolBar = (function () {
if (clickedOverlay === loadFileMenuItem) { if (clickedOverlay === loadFileMenuItem) {
toggleNewModelButton(false); toggleNewModelButton(false);
// TODO BUG: this is bug, if the user has never uploaded a model, this will throw an JS exception
file = Window.browse("Select your model file ...", file = Window.browse("Select your model file ...",
Settings.getValue("LastModelUploadLocation").path(), Settings.getValue("LastModelUploadLocation").path(),
"Model files (*.fst *.fbx)"); "Model files (*.fst *.fbx)");

View file

@ -60,9 +60,17 @@ SelectionDisplay = (function () {
var rotateHandleColor = { red: 0, green: 0, blue: 0 }; var rotateHandleColor = { red: 0, green: 0, blue: 0 };
var rotateHandleAlpha = 0.7; var rotateHandleAlpha = 0.7;
var highlightedHandleColor = { red: 255, green: 0, blue: 0 };
var highlightedHandleAlpha = 0.7;
var previousHandle = false;
var previousHandleColor;
var previousHandleAlpha;
var grabberSizeCorner = 0.025; var grabberSizeCorner = 0.025;
var grabberSizeEdge = 0.015; var grabberSizeEdge = 0.015;
var grabberSizeFace = 0.025; var grabberSizeFace = 0.025;
var grabberAlpha = 1;
var grabberColorCorner = { red: 120, green: 120, blue: 120 }; var grabberColorCorner = { red: 120, green: 120, blue: 120 };
var grabberColorEdge = { red: 0, green: 0, blue: 0 }; var grabberColorEdge = { red: 0, green: 0, blue: 0 };
var grabberColorFace = { red: 120, green: 120, blue: 120 }; var grabberColorFace = { red: 120, green: 120, blue: 120 };
@ -1706,6 +1714,13 @@ SelectionDisplay = (function () {
if (!entitySelected || mode !== "ROTATE_YAW") { if (!entitySelected || mode !== "ROTATE_YAW") {
return; // not allowed return; // not allowed
} }
var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems");
if (debug) {
print("rotateYaw()...");
print(" event.x,y:" + event.x + "," + event.y);
}
var pickRay = Camera.computePickRay(event.x, event.y); var pickRay = Camera.computePickRay(event.x, event.y);
Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false}); Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false});
@ -1716,7 +1731,14 @@ SelectionDisplay = (function () {
Overlays.editOverlay(rotateOverlayCurrent, { ignoreRayIntersection: true }); Overlays.editOverlay(rotateOverlayCurrent, { ignoreRayIntersection: true });
var result = Overlays.findRayIntersection(pickRay); var result = Overlays.findRayIntersection(pickRay);
if (debug) {
print(" findRayIntersection() .... result.intersects:" + result.intersects);
}
if (result.intersects) { if (result.intersects) {
var properties = Entities.getEntityProperties(currentSelection); var properties = Entities.getEntityProperties(currentSelection);
var center = yawCenter; var center = yawCenter;
var zero = yawZero; var zero = yawZero;
@ -1732,7 +1754,11 @@ SelectionDisplay = (function () {
} }
// for debugging // for debugging
//Overlays.editOverlay(rotateCurrentOverlay, { visible: true, start: center, end: result.intersection }); if (debug) {
Vec3.print(" result.intersection:",result.intersection);
Overlays.editOverlay(rotateCurrentOverlay, { visible: true, start: center, end: result.intersection });
print(" angleFromZero:" + angleFromZero);
}
var yawChange = Quat.fromVec3Degrees({ x: 0, y: angleFromZero, z: 0 }); var yawChange = Quat.fromVec3Degrees({ x: 0, y: angleFromZero, z: 0 });
var newRotation = Quat.multiply(yawChange, originalRotation); var newRotation = Quat.multiply(yawChange, originalRotation);
@ -1771,6 +1797,13 @@ SelectionDisplay = (function () {
if (!entitySelected || mode !== "ROTATE_PITCH") { if (!entitySelected || mode !== "ROTATE_PITCH") {
return; // not allowed return; // not allowed
} }
var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems");
if (debug) {
print("rotatePitch()...");
print(" event.x,y:" + event.x + "," + event.y);
}
var pickRay = Camera.computePickRay(event.x, event.y); var pickRay = Camera.computePickRay(event.x, event.y);
Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false}); Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false});
Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false }); Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false });
@ -1779,7 +1812,11 @@ SelectionDisplay = (function () {
Overlays.editOverlay(rotateOverlayOuter, { ignoreRayIntersection: true }); Overlays.editOverlay(rotateOverlayOuter, { ignoreRayIntersection: true });
Overlays.editOverlay(rotateOverlayCurrent, { ignoreRayIntersection: true }); Overlays.editOverlay(rotateOverlayCurrent, { ignoreRayIntersection: true });
var result = Overlays.findRayIntersection(pickRay); var result = Overlays.findRayIntersection(pickRay);
if (debug) {
print(" findRayIntersection() .... result.intersects:" + result.intersects);
}
if (result.intersects) { if (result.intersects) {
var properties = Entities.getEntityProperties(currentSelection); var properties = Entities.getEntityProperties(currentSelection);
var center = pitchCenter; var center = pitchCenter;
@ -1796,7 +1833,11 @@ SelectionDisplay = (function () {
} }
// for debugging // for debugging
//Overlays.editOverlay(rotateCurrentOverlay, { visible: true, start: center, end: result.intersection }); if (debug) {
Vec3.print(" result.intersection:",result.intersection);
Overlays.editOverlay(rotateCurrentOverlay, { visible: true, start: center, end: result.intersection });
print(" angleFromZero:" + angleFromZero);
}
var pitchChange = Quat.fromVec3Degrees({ x: angleFromZero, y: 0, z: 0 }); var pitchChange = Quat.fromVec3Degrees({ x: angleFromZero, y: 0, z: 0 });
var newRotation = Quat.multiply(pitchChange, originalRotation); var newRotation = Quat.multiply(pitchChange, originalRotation);
@ -1834,6 +1875,13 @@ SelectionDisplay = (function () {
if (!entitySelected || mode !== "ROTATE_ROLL") { if (!entitySelected || mode !== "ROTATE_ROLL") {
return; // not allowed return; // not allowed
} }
var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems");
if (debug) {
print("rotateRoll()...");
print(" event.x,y:" + event.x + "," + event.y);
}
var pickRay = Camera.computePickRay(event.x, event.y); var pickRay = Camera.computePickRay(event.x, event.y);
Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false}); Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false});
Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false }); Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false });
@ -1842,6 +1890,11 @@ SelectionDisplay = (function () {
Overlays.editOverlay(rotateOverlayOuter, { ignoreRayIntersection: true }); Overlays.editOverlay(rotateOverlayOuter, { ignoreRayIntersection: true });
Overlays.editOverlay(rotateOverlayCurrent, { ignoreRayIntersection: true }); Overlays.editOverlay(rotateOverlayCurrent, { ignoreRayIntersection: true });
var result = Overlays.findRayIntersection(pickRay); var result = Overlays.findRayIntersection(pickRay);
if (debug) {
print(" findRayIntersection() .... result.intersects:" + result.intersects);
}
if (result.intersects) { if (result.intersects) {
var properties = Entities.getEntityProperties(currentSelection); var properties = Entities.getEntityProperties(currentSelection);
var center = rollCenter; var center = rollCenter;
@ -1858,7 +1911,11 @@ SelectionDisplay = (function () {
} }
// for debugging // for debugging
//Overlays.editOverlay(rotateCurrentOverlay, { visible: true, start: center, end: result.intersection }); if (debug) {
Vec3.print(" result.intersection:",result.intersection);
Overlays.editOverlay(rotateCurrentOverlay, { visible: true, start: center, end: result.intersection });
print(" angleFromZero:" + angleFromZero);
}
var rollChange = Quat.fromVec3Degrees({ x: 0, y: 0, z: angleFromZero }); var rollChange = Quat.fromVec3Degrees({ x: 0, y: 0, z: angleFromZero });
var newRotation = Quat.multiply(rollChange, originalRotation); var newRotation = Quat.multiply(rollChange, originalRotation);
@ -2124,8 +2181,11 @@ SelectionDisplay = (function () {
Overlays.editOverlay(rotateOverlayCurrent, { visible: true, rotation: overlayOrientation, position: overlayCenter, startAt: 0, endAt: 0 }); Overlays.editOverlay(rotateOverlayCurrent, { visible: true, rotation: overlayOrientation, position: overlayCenter, startAt: 0, endAt: 0 });
// for debugging // for debugging
//Overlays.editOverlay(rotateZeroOverlay, { visible: true, start: overlayCenter, end: result.intersection }); var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems");
//Overlays.editOverlay(rotateCurrentOverlay, { visible: true, start: overlayCenter, end: result.intersection }); if (debug) {
Overlays.editOverlay(rotateZeroOverlay, { visible: true, start: overlayCenter, end: result.intersection });
Overlays.editOverlay(rotateCurrentOverlay, { visible: true, start: overlayCenter, end: result.intersection });
}
Overlays.editOverlay(yawHandle, { visible: false }); Overlays.editOverlay(yawHandle, { visible: false });
Overlays.editOverlay(pitchHandle, { visible: false }); Overlays.editOverlay(pitchHandle, { visible: false });
@ -2268,7 +2328,96 @@ SelectionDisplay = (function () {
that.stretchLEFT(event); that.stretchLEFT(event);
break; break;
default: default:
// nothing to do by default // if not in any specific mode, then just look for handles to highlight...
var pickRay = Camera.computePickRay(event.x, event.y);
var result = Overlays.findRayIntersection(pickRay);
var pickedColor;
var pickedAlpha;
var highlightNeeded = false;
if (result.intersects) {
switch(result.overlayID) {
case yawHandle:
case pitchHandle:
case rollHandle:
pickedColor = rotateHandleColor;
pickedAlpha = rotateHandleAlpha;
highlightNeeded = true;
break;
case grabberMoveUp:
pickedColor = rotateHandleColor;
pickedAlpha = rotateHandleAlpha;
highlightNeeded = true;
break;
case grabberLBN:
case grabberLBF:
case grabberRBN:
case grabberRBF:
case grabberLTN:
case grabberLTF:
case grabberRTN:
case grabberRTF:
pickedColor = grabberColorCorner;
pickedAlpha = grabberAlpha;
highlightNeeded = true;
break;
case grabberTOP:
case grabberBOTTOM:
case grabberLEFT:
case grabberRIGHT:
case grabberNEAR:
case grabberFAR:
pickedColor = grabberColorFace;
pickedAlpha = grabberAlpha;
highlightNeeded = true;
break;
case grabberEdgeTR:
case grabberEdgeTL:
case grabberEdgeTF:
case grabberEdgeTN:
case grabberEdgeBR:
case grabberEdgeBL:
case grabberEdgeBF:
case grabberEdgeBN:
case grabberEdgeNR:
case grabberEdgeNL:
case grabberEdgeFR:
case grabberEdgeFL:
pickedColor = grabberColorEdge;
pickedAlpha = grabberAlpha;
highlightNeeded = true;
break;
default:
if (previousHandle) {
Overlays.editOverlay(previousHandle, { color: previousHandleColor, alpha: previousHandleAlpha });
previousHandle = false;
}
break;
}
if (highlightNeeded) {
if (previousHandle) {
Overlays.editOverlay(previousHandle, { color: previousHandleColor, alpha: previousHandleAlpha });
previousHandle = false;
}
Overlays.editOverlay(result.overlayID, { color: highlightedHandleColor, alpha: highlightedHandleAlpha });
previousHandle = result.overlayID;
previousHandleColor = pickedColor;
previousHandleAlpha = pickedAlpha;
}
} else {
if (previousHandle) {
Overlays.editOverlay(previousHandle, { color: previousHandleColor, alpha: previousHandleAlpha });
previousHandle = false;
}
}
return false; return false;
} }
return true; return true;

41
examples/metavoxels.js Normal file
View file

@ -0,0 +1,41 @@
//
// metavoxels.js
// examples
//
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.setInterval(function() {
var spanner;
if (Math.random() < 0.5) {
spanner = new Sphere();
} else {
spanner = new Cuboid();
spanner.aspectX = 0.1 + Math.random() * 1.9;
spanner.aspectY = 0.1 + Math.random() * 1.9;
}
spanner.scale = 0.1 + Math.random() * 1.9;
spanner.rotation = Quat.fromPitchYawRollDegrees(Math.random() * 360.0, Math.random() * 360.0, Math.random() * 360.0);
spanner.translation = { x: 10.0 + Math.random() * 10.0, y: 10.0 + Math.random() * 10.0, z: 10.0 + Math.random() * 10.0 };
if (Math.random() < 0.5) {
var material = new MaterialObject();
if (Math.random() < 0.5) {
material.diffuse = "http://www.fungibleinsight.com/faces/grass.jpg";
} else {
material.diffuse = "http://www.fungibleinsight.com/faces/soil.jpg";
}
Metavoxels.setVoxelMaterial(spanner, material);
} else if (Math.random() < 0.5) {
Metavoxels.setVoxelColor(spanner, { red: Math.random() * 255.0, green: Math.random() * 255.0,
blue: Math.random() * 255.0 });
} else {
Metavoxels.setVoxelColor(spanner, { red: 0, green: 0, blue: 0, alpha: 0 });
}
}, 1000);

View file

@ -238,7 +238,6 @@ var toolBar = (function () {
if (clickedOverlay === loadFileMenuItem) { if (clickedOverlay === loadFileMenuItem) {
toggleNewModelButton(false); toggleNewModelButton(false);
// TODO BUG: this is bug, if the user has never uploaded a model, this will throw an JS exception
file = Window.browse("Select your model file ...", file = Window.browse("Select your model file ...",
Settings.getValue("LastModelUploadLocation").path(), Settings.getValue("LastModelUploadLocation").path(),
"Model files (*.fst *.fbx)"); "Model files (*.fst *.fbx)");
@ -518,6 +517,7 @@ function setupModelMenus() {
Menu.addMenuItem({ menuName: "File", menuItemName: "Models", isSeparator: true, beforeItem: "Settings" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Models", isSeparator: true, beforeItem: "Settings" });
Menu.addMenuItem({ menuName: "File", menuItemName: "Export Models", shortcutKey: "CTRL+META+E", afterItem: "Models" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Export Models", shortcutKey: "CTRL+META+E", afterItem: "Models" });
Menu.addMenuItem({ menuName: "File", menuItemName: "Import Models", shortcutKey: "CTRL+META+I", afterItem: "Export Models" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Import Models", shortcutKey: "CTRL+META+I", afterItem: "Export Models" });
Menu.addMenuItem({ menuName: "Developer", menuItemName: "Debug Ryans Rotation Problems", isCheckable: true });
} }
setupModelMenus(); // do this when first running our script. setupModelMenus(); // do this when first running our script.
@ -537,6 +537,7 @@ function cleanupModelMenus() {
Menu.removeSeparator("File", "Models"); Menu.removeSeparator("File", "Models");
Menu.removeMenuItem("File", "Export Models"); Menu.removeMenuItem("File", "Export Models");
Menu.removeMenuItem("File", "Import Models"); Menu.removeMenuItem("File", "Import Models");
Menu.removeMenuItem("Developer", "Debug Ryans Rotation Problems");
} }
Script.scriptEnding.connect(function() { Script.scriptEnding.connect(function() {

View file

@ -179,7 +179,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
_runningScriptsWidgetWasVisible(false), _runningScriptsWidgetWasVisible(false),
_trayIcon(new QSystemTrayIcon(_window)), _trayIcon(new QSystemTrayIcon(_window)),
_lastNackTime(usecTimestampNow()), _lastNackTime(usecTimestampNow()),
_lastSendDownstreamAudioStats(usecTimestampNow()) _lastSendDownstreamAudioStats(usecTimestampNow()),
_renderResolutionScale(1.0f)
{ {
// read the ApplicationInfo.ini file for Name/Version/Domain information // read the ApplicationInfo.ini file for Name/Version/Domain information
QSettings applicationInfo(Application::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); QSettings applicationInfo(Application::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat);
@ -187,8 +188,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
// set the associated application properties // set the associated application properties
applicationInfo.beginGroup("INFO"); applicationInfo.beginGroup("INFO");
qDebug() << "[VERSION] Build sequence: " << qPrintable(applicationVersion());
setApplicationName(applicationInfo.value("name").toString()); setApplicationName(applicationInfo.value("name").toString());
setApplicationVersion(BUILD_VERSION); setApplicationVersion(BUILD_VERSION);
setOrganizationName(applicationInfo.value("organizationName").toString()); setOrganizationName(applicationInfo.value("organizationName").toString());
@ -207,6 +206,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
qInstallMessageHandler(messageHandler); qInstallMessageHandler(messageHandler);
qDebug() << "[VERSION] Build sequence: " << qPrintable(applicationVersion());
// call Menu getInstance static method to set up the menu // call Menu getInstance static method to set up the menu
_window->setMenuBar(Menu::getInstance()); _window->setMenuBar(Menu::getInstance());
@ -598,7 +599,8 @@ void Application::paintGL() {
if (OculusManager::isConnected()) { if (OculusManager::isConnected()) {
_textureCache.setFrameBufferSize(OculusManager::getRenderTargetSize()); _textureCache.setFrameBufferSize(OculusManager::getRenderTargetSize());
} else { } else {
_textureCache.setFrameBufferSize(_glWidget->getDeviceSize()); QSize fbSize = _glWidget->getDeviceSize() * _renderResolutionScale;
_textureCache.setFrameBufferSize(fbSize);
} }
glEnable(GL_LINE_SMOOTH); glEnable(GL_LINE_SMOOTH);
@ -696,6 +698,10 @@ void Application::paintGL() {
} else { } else {
_glowEffect.prepare(); _glowEffect.prepare();
// Viewport is assigned to the size of the framebuffer
QSize size = Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject()->size();
glViewport(0, 0, size.width(), size.height());
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glPushMatrix(); glPushMatrix();
glLoadIdentity(); glLoadIdentity();
@ -3087,6 +3093,10 @@ glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) {
} }
void Application::renderRearViewMirror(const QRect& region, bool billboard) { void Application::renderRearViewMirror(const QRect& region, bool billboard) {
// Grab current viewport to reset it at the end
int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
bool eyeRelativeCamera = false; bool eyeRelativeCamera = false;
if (billboard) { if (billboard) {
_mirrorCamera.setFieldOfView(BILLBOARD_FIELD_OF_VIEW); // degees _mirrorCamera.setFieldOfView(BILLBOARD_FIELD_OF_VIEW); // degees
@ -3118,14 +3128,17 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
// set the bounds of rear mirror view // set the bounds of rear mirror view
if (billboard) { if (billboard) {
glViewport(region.x(), _glWidget->getDeviceHeight() - region.y() - region.height(), region.width(), region.height()); QSize size = getTextureCache()->getFrameBufferSize();
glScissor(region.x(), _glWidget->getDeviceHeight() - region.y() - region.height(), region.width(), region.height()); glViewport(region.x(), size.height() - region.y() - region.height(), region.width(), region.height());
glScissor(region.x(), size.height() - region.y() - region.height(), region.width(), region.height());
} else { } else {
// if not rendering the billboard, the region is in device independent coordinates; must convert to device // if not rendering the billboard, the region is in device independent coordinates; must convert to device
QSize size = getTextureCache()->getFrameBufferSize();
float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio(); float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio();
ratio = size.height() / (float)_glWidget->getDeviceHeight();
int x = region.x() * ratio, y = region.y() * ratio, width = region.width() * ratio, height = region.height() * ratio; 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); glViewport(x, size.height() - y - height, width, height);
glScissor(x, _glWidget->getDeviceHeight() - y - height, width, height); glScissor(x, size.height() - y - height, width, height);
} }
bool updateViewFrustum = false; bool updateViewFrustum = false;
updateProjectionMatrix(_mirrorCamera, updateViewFrustum); updateProjectionMatrix(_mirrorCamera, updateViewFrustum);
@ -3193,7 +3206,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
} }
// reset Viewport and projection matrix // reset Viewport and projection matrix
glViewport(0, 0, _glWidget->getDeviceWidth(), _glWidget->getDeviceHeight()); glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
updateProjectionMatrix(_myCamera, updateViewFrustum); updateProjectionMatrix(_myCamera, updateViewFrustum);
} }
@ -4230,3 +4243,7 @@ void Application::takeSnapshot() {
} }
_snapshotShareDialog->show(); _snapshotShareDialog->show();
} }
void Application::setRenderResolutionScale(float scale) {
_renderResolutionScale = scale;
}

View file

@ -301,6 +301,8 @@ public:
bool isLookingAtMyAvatar(Avatar* avatar); bool isLookingAtMyAvatar(Avatar* avatar);
float getRenderResolutionScale() const { return _renderResolutionScale; }
signals: signals:
/// Fired when we're simulating; allows external parties to hook in. /// Fired when we're simulating; allows external parties to hook in.
@ -363,6 +365,8 @@ public slots:
void domainSettingsReceived(const QJsonObject& domainSettingsObject); void domainSettingsReceived(const QJsonObject& domainSettingsObject);
void setRenderResolutionScale(float scale);
void resetSensors(); void resetSensors();
private slots: private slots:
@ -618,6 +622,8 @@ private:
quint64 _lastNackTime; quint64 _lastNackTime;
quint64 _lastSendDownstreamAudioStats; quint64 _lastSendDownstreamAudioStats;
float _renderResolutionScale;
}; };
#endif // hifi_Application_h #endif // hifi_Application_h

View file

@ -158,7 +158,7 @@ Menu::Menu() :
addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScriptURL, addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScriptURL,
Qt::CTRL | Qt::SHIFT | Qt::Key_O, appInstance, SLOT(loadScriptURLDialog())); Qt::CTRL | Qt::SHIFT | Qt::Key_O, appInstance, SLOT(loadScriptURLDialog()));
addActionToQMenuAndActionHash(fileMenu, MenuOption::StopAllScripts, 0, appInstance, SLOT(stopAllScripts())); addActionToQMenuAndActionHash(fileMenu, MenuOption::StopAllScripts, 0, appInstance, SLOT(stopAllScripts()));
addActionToQMenuAndActionHash(fileMenu, MenuOption::ReloadAllScripts, Qt::CTRL | Qt::SHIFT | Qt::Key_R, addActionToQMenuAndActionHash(fileMenu, MenuOption::ReloadAllScripts, Qt::CTRL | Qt::Key_R,
appInstance, SLOT(reloadAllScripts())); appInstance, SLOT(reloadAllScripts()));
addActionToQMenuAndActionHash(fileMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J, addActionToQMenuAndActionHash(fileMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J,
appInstance, SLOT(toggleRunningScriptsWidget())); appInstance, SLOT(toggleRunningScriptsWidget()));
@ -246,10 +246,16 @@ Menu::Menu() :
#endif #endif
addActionToQMenuAndActionHash(toolsMenu, addActionToQMenuAndActionHash(toolsMenu,
MenuOption::Console, MenuOption::Console,
Qt::CTRL | Qt::ALT | Qt::Key_J, Qt::CTRL | Qt::ALT | Qt::Key_J,
this, this,
SLOT(toggleConsole())); SLOT(toggleConsole()));
addActionToQMenuAndActionHash(toolsMenu,
MenuOption::ResetSensors,
Qt::Key_Apostrophe,
appInstance,
SLOT(resetSensors()));
QMenu* avatarMenu = addMenu("Avatar"); QMenu* avatarMenu = addMenu("Avatar");
@ -371,7 +377,15 @@ Menu::Menu() :
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false)); shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false));
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false)); shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false));
QMenu* resolutionMenu = renderOptionsMenu->addMenu(MenuOption::RenderResolution);
QActionGroup* resolutionGroup = new QActionGroup(resolutionMenu);
resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionOne, 0, false));
resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionTwoThird, 0, false));
resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionHalf, 0, false));
resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionThird, 0, true));
resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionQuarter, 0, false));
connect(resolutionMenu, SIGNAL(triggered(QAction*)), this, SLOT(changeRenderResolution(QAction*)));
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, Qt::Key_Asterisk, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, Qt::Key_Asterisk, true);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, addCheckableActionToQMenuAndActionHash(renderOptionsMenu,
MenuOption::Voxels, MenuOption::Voxels,
@ -380,11 +394,7 @@ Menu::Menu() :
appInstance, appInstance,
SLOT(setRenderVoxels(bool))); SLOT(setRenderVoxels(bool)));
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::EnableGlowEffect, 0, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::EnableGlowEffect, 0, true);
addActionToQMenuAndActionHash(renderOptionsMenu,
MenuOption::GlowMode,
0,
appInstance->getGlowEffect(),
SLOT(cycleRenderMode()));
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Wireframe, Qt::ALT | Qt::Key_W, false); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Wireframe, Qt::ALT | Qt::Key_W, false);
addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L, this, SLOT(lodTools())); addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L, this, SLOT(lodTools()));
@ -1225,6 +1235,23 @@ void Menu::muteEnvironment() {
free(packet); free(packet);
} }
void Menu::changeRenderResolution(QAction* action) {
QString text = action->text();
if (text == MenuOption::RenderResolutionOne) {
Application::getInstance()->setRenderResolutionScale(1.f);
} else if (text == MenuOption::RenderResolutionTwoThird) {
Application::getInstance()->setRenderResolutionScale(0.666f);
} else if (text == MenuOption::RenderResolutionHalf) {
Application::getInstance()->setRenderResolutionScale(0.5f);
} else if (text == MenuOption::RenderResolutionThird) {
Application::getInstance()->setRenderResolutionScale(0.333f);
} else if (text == MenuOption::RenderResolutionQuarter) {
Application::getInstance()->setRenderResolutionScale(0.25f);
} else {
Application::getInstance()->setRenderResolutionScale(1.f);
}
}
void Menu::displayNameLocationResponse(const QString& errorString) { void Menu::displayNameLocationResponse(const QString& errorString) {
if (!errorString.isEmpty()) { if (!errorString.isEmpty()) {

View file

@ -225,6 +225,7 @@ private slots:
void displayAddressOfflineMessage(); void displayAddressOfflineMessage();
void displayAddressNotFoundMessage(); void displayAddressNotFoundMessage();
void muteEnvironment(); void muteEnvironment();
void changeRenderResolution(QAction* action);
private: private:
static Menu* _instance; static Menu* _instance;
@ -398,7 +399,6 @@ namespace MenuOption {
const QString FrustumRenderMode = "Render Mode"; const QString FrustumRenderMode = "Render Mode";
const QString Fullscreen = "Fullscreen"; const QString Fullscreen = "Fullscreen";
const QString FullscreenMirror = "Fullscreen Mirror"; const QString FullscreenMirror = "Fullscreen Mirror";
const QString GlowMode = "Cycle Glow Mode";
const QString GlowWhenSpeaking = "Glow When Speaking"; const QString GlowWhenSpeaking = "Glow When Speaking";
const QString NamesAboveHeads = "Names Above Heads"; const QString NamesAboveHeads = "Names Above Heads";
const QString GoToUser = "Go To User"; const QString GoToUser = "Go To User";
@ -441,7 +441,14 @@ namespace MenuOption {
const QString RenderHeadCollisionShapes = "Show Head Collision Shapes"; const QString RenderHeadCollisionShapes = "Show Head Collision Shapes";
const QString RenderLookAtVectors = "Show Look-at Vectors"; const QString RenderLookAtVectors = "Show Look-at Vectors";
const QString RenderSkeletonCollisionShapes = "Show Skeleton Collision Shapes"; const QString RenderSkeletonCollisionShapes = "Show Skeleton Collision Shapes";
const QString RenderResolution = "Scale Resolution";
const QString RenderResolutionOne = "1";
const QString RenderResolutionTwoThird = "2/3";
const QString RenderResolutionHalf = "1/2";
const QString RenderResolutionThird = "1/3";
const QString RenderResolutionQuarter = "1/4";
const QString ResetAvatarSize = "Reset Avatar Size"; const QString ResetAvatarSize = "Reset Avatar Size";
const QString ResetSensors = "Reset Sensors";
const QString RunningScripts = "Running Scripts"; const QString RunningScripts = "Running Scripts";
const QString RunTimingTests = "Run Timing Tests"; const QString RunTimingTests = "Run Timing Tests";
const QString ScriptEditor = "Script Editor..."; const QString ScriptEditor = "Script Editor...";

View file

@ -23,6 +23,7 @@
#include <SharedUtil.h> #include <SharedUtil.h>
#include <MetavoxelMessages.h>
#include <MetavoxelUtil.h> #include <MetavoxelUtil.h>
#include <ScriptCache.h> #include <ScriptCache.h>
@ -454,6 +455,36 @@ float MetavoxelSystem::getHeightfieldHeight(const glm::vec3& location) {
return visitor.height; return visitor.height;
} }
void MetavoxelSystem::paintHeightfieldColor(const glm::vec3& position, float radius, const QColor& color) {
MetavoxelEditMessage edit = { QVariant::fromValue(PaintHeightfieldMaterialEdit(position, radius, SharedObjectPointer(), color)) };
applyEdit(edit, true);
}
void MetavoxelSystem::paintHeightfieldMaterial(const glm::vec3& position, float radius, const SharedObjectPointer& material) {
MetavoxelEditMessage edit = { QVariant::fromValue(PaintHeightfieldMaterialEdit(position, radius, material)) };
applyMaterialEdit(edit, true);
}
void MetavoxelSystem::paintVoxelColor(const glm::vec3& position, float radius, const QColor& color) {
MetavoxelEditMessage edit = { QVariant::fromValue(PaintVoxelMaterialEdit(position, radius, SharedObjectPointer(), color)) };
applyEdit(edit, true);
}
void MetavoxelSystem::paintVoxelMaterial(const glm::vec3& position, float radius, const SharedObjectPointer& material) {
MetavoxelEditMessage edit = { QVariant::fromValue(PaintVoxelMaterialEdit(position, radius, material)) };
applyMaterialEdit(edit, true);
}
void MetavoxelSystem::setVoxelColor(const SharedObjectPointer& spanner, const QColor& color) {
MetavoxelEditMessage edit = { QVariant::fromValue(VoxelMaterialSpannerEdit(spanner, SharedObjectPointer(), color)) };
applyEdit(edit, true);
}
void MetavoxelSystem::setVoxelMaterial(const SharedObjectPointer& spanner, const SharedObjectPointer& material) {
MetavoxelEditMessage edit = { QVariant::fromValue(VoxelMaterialSpannerEdit(spanner, material)) };
applyMaterialEdit(edit, true);
}
class CursorRenderVisitor : public MetavoxelVisitor { class CursorRenderVisitor : public MetavoxelVisitor {
public: public:
@ -563,6 +594,55 @@ void MetavoxelSystem::deleteTextures(int heightID, int colorID, int textureID) {
glDeleteTextures(1, (GLuint*)&textureID); glDeleteTextures(1, (GLuint*)&textureID);
} }
class MaterialEditApplier : public SignalHandler {
public:
MaterialEditApplier(const MetavoxelEditMessage& message, const QSharedPointer<NetworkTexture> texture);
virtual void handle();
protected:
MetavoxelEditMessage _message;
QSharedPointer<NetworkTexture> _texture;
};
MaterialEditApplier::MaterialEditApplier(const MetavoxelEditMessage& message, const QSharedPointer<NetworkTexture> texture) :
_message(message),
_texture(texture) {
}
void MaterialEditApplier::handle() {
static_cast<MaterialEdit*>(_message.edit.data())->averageColor = _texture->getAverageColor();
Application::getInstance()->getMetavoxels()->applyEdit(_message, true);
deleteLater();
}
void MetavoxelSystem::applyMaterialEdit(const MetavoxelEditMessage& message, bool reliable) {
const MaterialEdit* edit = static_cast<const MaterialEdit*>(message.edit.constData());
MaterialObject* material = static_cast<MaterialObject*>(edit->material.data());
if (material && material->getDiffuse().isValid()) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "applyMaterialEdit", Q_ARG(const MetavoxelEditMessage&, message),
Q_ARG(bool, reliable));
return;
}
QSharedPointer<NetworkTexture> texture = Application::getInstance()->getTextureCache()->getTexture(
material->getDiffuse(), SPLAT_TEXTURE);
if (texture->isLoaded()) {
MetavoxelEditMessage newMessage = message;
static_cast<MaterialEdit*>(newMessage.edit.data())->averageColor = texture->getAverageColor();
applyEdit(newMessage, true);
} else {
MaterialEditApplier* applier = new MaterialEditApplier(message, texture);
connect(texture.data(), &Resource::loaded, applier, &SignalHandler::handle);
}
} else {
applyEdit(message, true);
}
}
MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) { MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) {
return new MetavoxelSystemClient(node, _updater); return new MetavoxelSystemClient(node, _updater);
} }

View file

@ -54,6 +54,18 @@ public:
Q_INVOKABLE float getHeightfieldHeight(const glm::vec3& location); Q_INVOKABLE float getHeightfieldHeight(const glm::vec3& location);
Q_INVOKABLE void paintHeightfieldColor(const glm::vec3& position, float radius, const QColor& color);
Q_INVOKABLE void paintHeightfieldMaterial(const glm::vec3& position, float radius, const SharedObjectPointer& material);
Q_INVOKABLE void paintVoxelColor(const glm::vec3& position, float radius, const QColor& color);
Q_INVOKABLE void paintVoxelMaterial(const glm::vec3& position, float radius, const SharedObjectPointer& material);
Q_INVOKABLE void setVoxelColor(const SharedObjectPointer& spanner, const QColor& color);
Q_INVOKABLE void setVoxelMaterial(const SharedObjectPointer& spanner, const SharedObjectPointer& material);
Q_INVOKABLE void deleteTextures(int heightID, int colorID, int textureID); Q_INVOKABLE void deleteTextures(int heightID, int colorID, int textureID);
signals: signals:
@ -66,6 +78,8 @@ public slots:
protected: protected:
Q_INVOKABLE void applyMaterialEdit(const MetavoxelEditMessage& message, bool reliable = false);
virtual MetavoxelClient* createClient(const SharedNodePointer& node); virtual MetavoxelClient* createClient(const SharedNodePointer& node);
private: private:
@ -81,6 +95,15 @@ private:
Frustum _frustum; Frustum _frustum;
}; };
/// Generic abstract base class for objects that handle a signal.
class SignalHandler : public QObject {
Q_OBJECT
public slots:
virtual void handle() = 0;
};
/// Describes contents of a point in a point buffer. /// Describes contents of a point in a point buffer.
class BufferPoint { class BufferPoint {
public: public:

View file

@ -694,7 +694,7 @@ void Avatar::renderDisplayName() {
if (success) { if (success) {
double textWindowHeight = abs(result1[1] - result0[1]); double textWindowHeight = abs(result1[1] - result0[1]);
float scaleFactor = QApplication::desktop()->windowHandle()->devicePixelRatio() * float scaleFactor = Application::getInstance()->getRenderResolutionScale() *
((textWindowHeight > EPSILON) ? 1.0f / textWindowHeight : 1.0f); ((textWindowHeight > EPSILON) ? 1.0f / textWindowHeight : 1.0f);
glScalef(scaleFactor, scaleFactor, 1.0); glScalef(scaleFactor, scaleFactor, 1.0);

View file

@ -78,6 +78,8 @@ void OculusManager::connect() {
#ifdef HAVE_LIBOVR #ifdef HAVE_LIBOVR
_calibrationState = UNCALIBRATED; _calibrationState = UNCALIBRATED;
qDebug() << "Oculus SDK" << OVR_VERSION_STRING;
ovr_Initialize(); ovr_Initialize();
_ovrHmd = ovrHmd_Create(0); _ovrHmd = ovrHmd_Create(0);

View file

@ -23,7 +23,6 @@
GlowEffect::GlowEffect() GlowEffect::GlowEffect()
: _initialized(false), : _initialized(false),
_renderMode(DIFFUSE_ADD_MODE),
_isOddFrame(false), _isOddFrame(false),
_isFirstFrame(true), _isFirstFrame(true),
_intensity(0.0f) { _intensity(0.0f) {
@ -41,9 +40,9 @@ GlowEffect::~GlowEffect() {
} }
QOpenGLFramebufferObject* GlowEffect::getFreeFramebufferObject() const { QOpenGLFramebufferObject* GlowEffect::getFreeFramebufferObject() const {
return (_renderMode == DIFFUSE_ADD_MODE && !_isOddFrame) ? return (_isOddFrame ?
Application::getInstance()->getTextureCache()->getTertiaryFramebufferObject() : Application::getInstance()->getTextureCache()->getSecondaryFramebufferObject():
Application::getInstance()->getTextureCache()->getSecondaryFramebufferObject(); Application::getInstance()->getTextureCache()->getTertiaryFramebufferObject());
} }
static ProgramObject* createProgram(const QString& name) { static ProgramObject* createProgram(const QString& name) {
@ -137,31 +136,28 @@ QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) {
glDisable(GL_BLEND); glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE); glDepthMask(GL_FALSE);
QOpenGLFramebufferObject* destFBO = toTexture ? QOpenGLFramebufferObject* destFBO = toTexture ?
Application::getInstance()->getTextureCache()->getSecondaryFramebufferObject() : NULL; Application::getInstance()->getTextureCache()->getSecondaryFramebufferObject() : NULL;
if (!Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect) || (_isEmpty && _renderMode != DIFFUSE_ADD_MODE)) { if (!Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect) || _isEmpty) {
// copy the primary to the screen // copy the primary to the screen
if (QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) { if (destFBO && QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) {
QOpenGLFramebufferObject::blitFramebuffer(destFBO, primaryFBO); QOpenGLFramebufferObject::blitFramebuffer(destFBO, primaryFBO);
} else { } else {
maybeBind(destFBO); maybeBind(destFBO);
if (!destFBO) {
glViewport(0, 0, Application::getInstance()->getGLWidget()->getDeviceWidth(),
Application::getInstance()->getGLWidget()->getDeviceHeight());
}
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING); glDisable(GL_LIGHTING);
glColor3f(1.0f, 1.0f, 1.0f); glColor3f(1.0f, 1.0f, 1.0f);
renderFullscreenQuad(); renderFullscreenQuad();
glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING); glEnable(GL_LIGHTING);
maybeRelease(destFBO); maybeRelease(destFBO);
} }
} else if (_renderMode == ADD_MODE) { } else {
maybeBind(destFBO);
_addProgram->bind();
renderFullscreenQuad();
_addProgram->release();
maybeRelease(destFBO);
} else if (_renderMode == DIFFUSE_ADD_MODE) {
// diffuse into the secondary/tertiary (alternating between frames) // diffuse into the secondary/tertiary (alternating between frames)
QOpenGLFramebufferObject* oldDiffusedFBO = QOpenGLFramebufferObject* oldDiffusedFBO =
Application::getInstance()->getTextureCache()->getSecondaryFramebufferObject(); Application::getInstance()->getTextureCache()->getSecondaryFramebufferObject();
@ -197,6 +193,11 @@ QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) {
destFBO = oldDiffusedFBO; destFBO = oldDiffusedFBO;
} }
maybeBind(destFBO); maybeBind(destFBO);
if (!destFBO) {
glViewport(0, 0,
Application::getInstance()->getGLWidget()->getDeviceWidth(),
Application::getInstance()->getGLWidget()->getDeviceHeight());
}
_addSeparateProgram->bind(); _addSeparateProgram->bind();
renderFullscreenQuad(); renderFullscreenQuad();
_addSeparateProgram->release(); _addSeparateProgram->release();
@ -205,70 +206,6 @@ QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) {
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
} else { // _renderMode == BLUR_ADD_MODE || _renderMode == BLUR_PERSIST_ADD_MODE
// render the primary to the secondary with the horizontal blur
QOpenGLFramebufferObject* secondaryFBO =
Application::getInstance()->getTextureCache()->getSecondaryFramebufferObject();
secondaryFBO->bind();
_horizontalBlurProgram->bind();
renderFullscreenQuad();
_horizontalBlurProgram->release();
secondaryFBO->release();
if (_renderMode == BLUR_ADD_MODE) {
// render the secondary to the screen with the vertical blur
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, secondaryFBO->texture());
if (toTexture) {
destFBO = Application::getInstance()->getTextureCache()->getTertiaryFramebufferObject();
}
maybeBind(destFBO);
_verticalBlurAddProgram->bind();
renderFullscreenQuad();
_verticalBlurAddProgram->release();
maybeRelease(destFBO);
} else { // _renderMode == BLUR_PERSIST_ADD_MODE
// render the secondary to the tertiary with vertical blur and persistence
QOpenGLFramebufferObject* tertiaryFBO =
Application::getInstance()->getTextureCache()->getTertiaryFramebufferObject();
tertiaryFBO->bind();
glEnable(GL_BLEND);
glBlendFunc(GL_ONE_MINUS_CONSTANT_ALPHA, GL_CONSTANT_ALPHA);
const float PERSISTENCE_SMOOTHING = 0.9f;
glBlendColor(0.0f, 0.0f, 0.0f, _isFirstFrame ? 0.0f : PERSISTENCE_SMOOTHING);
glBindTexture(GL_TEXTURE_2D, secondaryFBO->texture());
_verticalBlurProgram->bind();
renderFullscreenQuad();
_verticalBlurProgram->release();
glBlendColor(0.0f, 0.0f, 0.0f, 0.0f);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
glDisable(GL_BLEND);
// now add the tertiary to the primary buffer
tertiaryFBO->release();
glBindTexture(GL_TEXTURE_2D, primaryFBO->texture());
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, tertiaryFBO->texture());
maybeBind(destFBO);
_addSeparateProgram->bind();
renderFullscreenQuad();
_addSeparateProgram->release();
maybeRelease(destFBO);
}
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
} }
glPopMatrix(); glPopMatrix();
@ -286,28 +223,6 @@ QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) {
return destFBO; return destFBO;
} }
void GlowEffect::cycleRenderMode() {
switch(_renderMode = (RenderMode)((_renderMode + 1) % RENDER_MODE_COUNT)) {
case ADD_MODE:
qDebug() << "Glow mode: Add";
break;
case BLUR_ADD_MODE:
qDebug() << "Glow mode: Blur/add";
break;
case BLUR_PERSIST_ADD_MODE:
qDebug() << "Glow mode: Blur/persist/add";
break;
default:
case DIFFUSE_ADD_MODE:
qDebug() << "Glow mode: Diffuse/add";
break;
}
_isFirstFrame = true;
}
Glower::Glower(float amount) { Glower::Glower(float amount) {
Application::getInstance()->getGlowEffect()->begin(amount); Application::getInstance()->getGlowEffect()->begin(amount);
} }

View file

@ -51,17 +51,10 @@ public:
/// \return the framebuffer object to which we rendered, or NULL if to the frame buffer /// \return the framebuffer object to which we rendered, or NULL if to the frame buffer
QOpenGLFramebufferObject* render(bool toTexture = false); QOpenGLFramebufferObject* render(bool toTexture = false);
public slots:
void cycleRenderMode();
private: private:
enum RenderMode { ADD_MODE, BLUR_ADD_MODE, BLUR_PERSIST_ADD_MODE, DIFFUSE_ADD_MODE, RENDER_MODE_COUNT };
bool _initialized; bool _initialized;
RenderMode _renderMode;
ProgramObject* _addProgram; ProgramObject* _addProgram;
ProgramObject* _horizontalBlurProgram; ProgramObject* _horizontalBlurProgram;
ProgramObject* _verticalBlurAddProgram; ProgramObject* _verticalBlurAddProgram;

View file

@ -210,7 +210,7 @@ QOpenGLFramebufferObject* TextureCache::getPrimaryFramebufferObject() {
if (!_primaryFramebufferObject) { if (!_primaryFramebufferObject) {
_primaryFramebufferObject = createFramebufferObject(); _primaryFramebufferObject = createFramebufferObject();
glGenTextures(1, &_primaryDepthTextureID); glGenTextures(1, &_primaryDepthTextureID);
glBindTexture(GL_TEXTURE_2D, _primaryDepthTextureID); glBindTexture(GL_TEXTURE_2D, _primaryDepthTextureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, _frameBufferSize.width(), _frameBufferSize.height(), glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, _frameBufferSize.width(), _frameBufferSize.height(),

View file

@ -38,6 +38,7 @@ public:
/// Sets the desired texture resolution for the framebuffer objects. /// Sets the desired texture resolution for the framebuffer objects.
void setFrameBufferSize(QSize frameBufferSize); void setFrameBufferSize(QSize frameBufferSize);
const QSize& getFrameBufferSize() const { return _frameBufferSize; }
/// Returns the ID of the permutation/normal texture used for Perlin noise shader programs. This texture /// Returns the ID of the permutation/normal texture used for Perlin noise shader programs. This texture
/// has two lines: the first, a set of random numbers in [0, 255] to be used as permutation offsets, and /// has two lines: the first, a set of random numbers in [0, 255] to be used as permutation offsets, and

View file

@ -22,6 +22,9 @@ QVariant SettingsScriptingInterface::getValue(const QString& setting) {
QSettings* settings = Application::getInstance()->lockSettings(); QSettings* settings = Application::getInstance()->lockSettings();
QVariant value = settings->value(setting); QVariant value = settings->value(setting);
Application::getInstance()->unlockSettings(); Application::getInstance()->unlockSettings();
if (!value.isValid()) {
value = "";
}
return value; return value;
} }
@ -29,6 +32,9 @@ QVariant SettingsScriptingInterface::getValue(const QString& setting, const QVar
QSettings* settings = Application::getInstance()->lockSettings(); QSettings* settings = Application::getInstance()->lockSettings();
QVariant value = settings->value(setting, defaultValue); QVariant value = settings->value(setting, defaultValue);
Application::getInstance()->unlockSettings(); Application::getInstance()->unlockSettings();
if (!value.isValid()) {
value = "";
}
return value; return value;
} }

View file

@ -1392,16 +1392,14 @@ void VoxelMaterialBoxTool::applyValue(const glm::vec3& minimum, const glm::vec3&
} else { } else {
material = SharedObjectPointer(); material = SharedObjectPointer();
} }
QColor color = _color->getColor();
color.setAlphaF(color.alphaF() > 0.5f ? 1.0f : 0.0f);
Cuboid* cuboid = new Cuboid(); Cuboid* cuboid = new Cuboid();
cuboid->setTranslation((maximum + minimum) * 0.5f); cuboid->setTranslation((maximum + minimum) * 0.5f);
glm::vec3 vector = (maximum - minimum) * 0.5f; glm::vec3 vector = (maximum - minimum) * 0.5f;
cuboid->setScale(vector.x); cuboid->setScale(vector.x);
cuboid->setAspectY(vector.y / vector.x); cuboid->setAspectY(vector.y / vector.x);
cuboid->setAspectZ(vector.z / vector.x); cuboid->setAspectZ(vector.z / vector.x);
MetavoxelEditMessage message = { QVariant::fromValue(VoxelMaterialSpannerEdit(SharedObjectPointer(cuboid), material, color)) }; MetavoxelEditMessage message = { QVariant::fromValue(VoxelMaterialSpannerEdit(SharedObjectPointer(cuboid),
material, _color->getColor())) };
Application::getInstance()->getMetavoxels()->applyEdit(message, true); Application::getInstance()->getMetavoxels()->applyEdit(message, true);
} }
@ -1489,9 +1487,7 @@ void VoxelMaterialSpannerTool::applyEdit(const AttributePointer& attribute, cons
} else { } else {
material = SharedObjectPointer(); material = SharedObjectPointer();
} }
QColor color = _color->getColor(); MetavoxelEditMessage message = { QVariant::fromValue(VoxelMaterialSpannerEdit(spanner, material, _color->getColor())) };
color.setAlphaF(color.alphaF() > 0.5f ? 1.0f : 0.0f);
MetavoxelEditMessage message = { QVariant::fromValue(VoxelMaterialSpannerEdit(spanner, material, color)) };
Application::getInstance()->getMetavoxels()->applyEdit(message, true); Application::getInstance()->getMetavoxels()->applyEdit(message, true);
} }

View file

@ -40,6 +40,9 @@ RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) :
connect(&_proxyModel, &QSortFilterProxyModel::modelReset, connect(&_proxyModel, &QSortFilterProxyModel::modelReset,
this, &RunningScriptsWidget::selectFirstInList); this, &RunningScriptsWidget::selectFirstInList);
QString shortcutText = Menu::getInstance()->getActionForOption(MenuOption::ReloadAllScripts)->shortcut().toString(QKeySequence::NativeText);
ui->tipLabel->setText("Tip: Use " + shortcutText + " to reload all scripts.");
_proxyModel.setSourceModel(&_scriptsModel); _proxyModel.setSourceModel(&_scriptsModel);
_proxyModel.sort(0, Qt::AscendingOrder); _proxyModel.sort(0, Qt::AscendingOrder);
_proxyModel.setDynamicSortFilter(true); _proxyModel.setDynamicSortFilter(true);
@ -86,7 +89,7 @@ void RunningScriptsWidget::setBoundary(const QRect& rect) {
void RunningScriptsWidget::setRunningScripts(const QStringList& list) { void RunningScriptsWidget::setRunningScripts(const QStringList& list) {
setUpdatesEnabled(false); setUpdatesEnabled(false);
QLayoutItem* widget; QLayoutItem* widget;
while ((widget = ui->scrollAreaWidgetContents->layout()->takeAt(0)) != NULL) { while ((widget = ui->scriptListWidget->layout()->takeAt(0)) != NULL) {
delete widget->widget(); delete widget->widget();
delete widget; delete widget;
} }
@ -96,7 +99,7 @@ void RunningScriptsWidget::setRunningScripts(const QStringList& list) {
if (!hash.contains(list.at(i))) { if (!hash.contains(list.at(i))) {
hash.insert(list.at(i), 1); hash.insert(list.at(i), 1);
} }
QWidget* row = new QWidget(ui->scrollAreaWidgetContents); QWidget* row = new QWidget(ui->scriptListWidget);
row->setLayout(new QHBoxLayout(row)); row->setLayout(new QHBoxLayout(row));
QUrl url = QUrl(list.at(i)); QUrl url = QUrl(list.at(i));
@ -130,17 +133,16 @@ void RunningScriptsWidget::setRunningScripts(const QStringList& list) {
line->setFrameShape(QFrame::HLine); line->setFrameShape(QFrame::HLine);
line->setStyleSheet("color: #E1E1E1; margin-left: 6px; margin-right: 6px;"); line->setStyleSheet("color: #E1E1E1; margin-left: 6px; margin-right: 6px;");
ui->scrollAreaWidgetContents->layout()->addWidget(row); ui->scriptListWidget->layout()->addWidget(row);
ui->scrollAreaWidgetContents->layout()->addWidget(line); ui->scriptListWidget->layout()->addWidget(line);
} }
ui->noRunningScriptsLabel->setVisible(list.isEmpty()); ui->noRunningScriptsLabel->setVisible(list.isEmpty());
ui->runningScriptsList->setVisible(!list.isEmpty());
ui->reloadAllButton->setVisible(!list.isEmpty()); ui->reloadAllButton->setVisible(!list.isEmpty());
ui->stopAllButton->setVisible(!list.isEmpty()); ui->stopAllButton->setVisible(!list.isEmpty());
ui->scrollAreaWidgetContents->updateGeometry(); ui->scriptListWidget->updateGeometry();
setUpdatesEnabled(true); setUpdatesEnabled(true);
Application::processEvents(); Application::processEvents();
repaint(); repaint();

View file

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>319</width> <width>364</width>
<height>481</height> <height>728</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -16,19 +16,7 @@
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">* { font-family: Helvetica, Arial, sans-serif; }</string> <string notr="true">* { font-family: Helvetica, Arial, sans-serif; }</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2" stretch="3,2">
<property name="leftMargin">
<number>14</number>
</property>
<property name="topMargin">
<number>20</number>
</property>
<property name="rightMargin">
<number>14</number>
</property>
<property name="bottomMargin">
<number>20</number>
</property>
<item> <item>
<widget class="QWidget" name="runningScriptsArea" native="true"> <widget class="QWidget" name="runningScriptsArea" native="true">
<property name="sizePolicy"> <property name="sizePolicy">
@ -195,6 +183,25 @@ font: bold 16px;
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item>
<widget class="QLabel" name="noRunningScriptsLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">font: 14px; color: #5f5f5f; margin: 2px;</string>
</property>
<property name="text">
<string>There are no scripts running.</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item> <item>
<widget class="QScrollArea" name="runningScriptsList"> <widget class="QScrollArea" name="runningScriptsList">
<property name="sizePolicy"> <property name="sizePolicy">
@ -219,10 +226,10 @@ font: bold 16px;
<number>0</number> <number>0</number>
</property> </property>
<property name="verticalScrollBarPolicy"> <property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum> <enum>Qt::ScrollBarAsNeeded</enum>
</property> </property>
<property name="horizontalScrollBarPolicy"> <property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum> <enum>Qt::ScrollBarAlwaysOff</enum>
</property> </property>
<property name="sizeAdjustPolicy"> <property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum> <enum>QAbstractScrollArea::AdjustToContents</enum>
@ -238,8 +245,8 @@ font: bold 16px;
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>264</width> <width>328</width>
<height>16</height> <height>18</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -254,7 +261,7 @@ font: bold 16px;
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">font-size: 14px;</string> <string notr="true">font-size: 14px;</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_5"> <layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing"> <property name="spacing">
<number>0</number> <number>0</number>
</property> </property>
@ -270,29 +277,41 @@ font: bold 16px;
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item>
<widget class="QWidget" name="scriptListWidget" native="true">
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="tipLabel">
<property name="styleSheet">
<string notr="true">font: 14px; color: #5f5f5f; margin: 2px;</string>
</property>
<property name="text">
<string>Tip</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</widget> </widget>
</item> </item>
<item>
<widget class="QLabel" name="noRunningScriptsLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">font: 14px; color: #5f5f5f;</string>
</property>
<property name="text">
<string>There are no scripts running.</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View file

@ -30,8 +30,7 @@ PositionalAudioStream::PositionalAudioStream(PositionalAudioStream::Type type, b
_shouldLoopbackForNode(false), _shouldLoopbackForNode(false),
_isStereo(isStereo), _isStereo(isStereo),
_lastPopOutputTrailingLoudness(0.0f), _lastPopOutputTrailingLoudness(0.0f),
_lastPopOutputLoudness(0.0f), _lastPopOutputLoudness(0.0f)
_listenerUnattenuatedZone(NULL)
{ {
} }

View file

@ -42,9 +42,6 @@ public:
PositionalAudioStream::Type getType() const { return _type; } PositionalAudioStream::Type getType() const { return _type; }
const glm::vec3& getPosition() const { return _position; } const glm::vec3& getPosition() const { return _position; }
const glm::quat& getOrientation() const { return _orientation; } const glm::quat& getOrientation() const { return _orientation; }
AABox* getListenerUnattenuatedZone() const { return _listenerUnattenuatedZone; }
void setListenerUnattenuatedZone(AABox* listenerUnattenuatedZone) { _listenerUnattenuatedZone = listenerUnattenuatedZone; }
protected: protected:
// disallow copying of PositionalAudioStream objects // disallow copying of PositionalAudioStream objects
@ -63,7 +60,6 @@ protected:
float _lastPopOutputTrailingLoudness; float _lastPopOutputTrailingLoudness;
float _lastPopOutputLoudness; float _lastPopOutputLoudness;
AABox* _listenerUnattenuatedZone;
}; };
#endif // hifi_PositionalAudioStream_h #endif // hifi_PositionalAudioStream_h

View file

@ -74,6 +74,11 @@ void MetavoxelClientManager::setSpanner(const SharedObjectPointer& object, bool
applyEdit(edit, reliable); applyEdit(edit, reliable);
} }
void MetavoxelClientManager::paintHeightfieldHeight(const glm::vec3& position, float radius, float height) {
MetavoxelEditMessage edit = { QVariant::fromValue(PaintHeightfieldHeightEdit(position, radius, height)) };
applyEdit(edit, true);
}
void MetavoxelClientManager::applyEdit(const MetavoxelEditMessage& edit, bool reliable) { void MetavoxelClientManager::applyEdit(const MetavoxelEditMessage& edit, bool reliable) {
QMetaObject::invokeMethod(_updater, "applyEdit", Q_ARG(const MetavoxelEditMessage&, edit), Q_ARG(bool, reliable)); QMetaObject::invokeMethod(_updater, "applyEdit", Q_ARG(const MetavoxelEditMessage&, edit), Q_ARG(bool, reliable));
} }

View file

@ -41,6 +41,8 @@ public:
Q_INVOKABLE void setSpanner(const SharedObjectPointer& object, bool reliable = false); Q_INVOKABLE void setSpanner(const SharedObjectPointer& object, bool reliable = false);
Q_INVOKABLE void paintHeightfieldHeight(const glm::vec3& position, float radius, float height);
Q_INVOKABLE void applyEdit(const MetavoxelEditMessage& edit, bool reliable = false); Q_INVOKABLE void applyEdit(const MetavoxelEditMessage& edit, bool reliable = false);
/// Returns the current LOD. This must be thread-safe, as it will be called from the updater thread. /// Returns the current LOD. This must be thread-safe, as it will be called from the updater thread.

View file

@ -18,6 +18,10 @@ void MetavoxelEditMessage::apply(MetavoxelData& data, const WeakSharedObjectHash
MetavoxelEdit::~MetavoxelEdit() { MetavoxelEdit::~MetavoxelEdit() {
} }
void MetavoxelEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
// nothing by default
}
BoxSetEdit::BoxSetEdit(const Box& region, float granularity, const OwnedAttributeValue& value) : BoxSetEdit::BoxSetEdit(const Box& region, float granularity, const OwnedAttributeValue& value) :
region(region), granularity(granularity), value(value) { region(region), granularity(granularity), value(value) {
} }
@ -408,6 +412,11 @@ void PaintHeightfieldHeightEdit::apply(MetavoxelData& data, const WeakSharedObje
data.guide(visitor); data.guide(visitor);
} }
MaterialEdit::MaterialEdit(const SharedObjectPointer& material, const QColor& averageColor) :
material(material),
averageColor(averageColor) {
}
class PaintHeightfieldMaterialEditVisitor : public MetavoxelVisitor { class PaintHeightfieldMaterialEditVisitor : public MetavoxelVisitor {
public: public:
@ -595,10 +604,9 @@ int PaintHeightfieldMaterialEditVisitor::visit(MetavoxelInfo& info) {
PaintHeightfieldMaterialEdit::PaintHeightfieldMaterialEdit(const glm::vec3& position, float radius, PaintHeightfieldMaterialEdit::PaintHeightfieldMaterialEdit(const glm::vec3& position, float radius,
const SharedObjectPointer& material, const QColor& averageColor) : const SharedObjectPointer& material, const QColor& averageColor) :
MaterialEdit(material, averageColor),
position(position), position(position),
radius(radius), radius(radius) {
material(material),
averageColor(averageColor) {
} }
void PaintHeightfieldMaterialEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { void PaintHeightfieldMaterialEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
@ -613,9 +621,8 @@ const int VOXEL_BLOCK_VOLUME = VOXEL_BLOCK_AREA * VOXEL_BLOCK_SAMPLES;
VoxelMaterialSpannerEdit::VoxelMaterialSpannerEdit(const SharedObjectPointer& spanner, VoxelMaterialSpannerEdit::VoxelMaterialSpannerEdit(const SharedObjectPointer& spanner,
const SharedObjectPointer& material, const QColor& averageColor) : const SharedObjectPointer& material, const QColor& averageColor) :
spanner(spanner), MaterialEdit(material, averageColor),
material(material), spanner(spanner) {
averageColor(averageColor) {
} }
class VoxelMaterialSpannerEditVisitor : public MetavoxelVisitor { class VoxelMaterialSpannerEditVisitor : public MetavoxelVisitor {
@ -845,16 +852,18 @@ void VoxelMaterialSpannerEdit::apply(MetavoxelData& data, const WeakSharedObject
while (!data.getBounds().contains(spanner->getBounds())) { while (!data.getBounds().contains(spanner->getBounds())) {
data.expand(); data.expand();
} }
VoxelMaterialSpannerEditVisitor visitor(spanner, material, averageColor); // make sure it's either 100% transparent or 100% opaque
QColor color = averageColor;
color.setAlphaF(color.alphaF() > 0.5f ? 1.0f : 0.0f);
VoxelMaterialSpannerEditVisitor visitor(spanner, material, color);
data.guide(visitor); data.guide(visitor);
} }
PaintVoxelMaterialEdit::PaintVoxelMaterialEdit(const glm::vec3& position, float radius, PaintVoxelMaterialEdit::PaintVoxelMaterialEdit(const glm::vec3& position, float radius,
const SharedObjectPointer& material, const QColor& averageColor) : const SharedObjectPointer& material, const QColor& averageColor) :
MaterialEdit(material, averageColor),
position(position), position(position),
radius(radius), radius(radius) {
material(material),
averageColor(averageColor) {
} }
class PaintVoxelMaterialEditVisitor : public MetavoxelVisitor { class PaintVoxelMaterialEditVisitor : public MetavoxelVisitor {
@ -950,6 +959,9 @@ int PaintVoxelMaterialEditVisitor::visit(MetavoxelInfo& info) {
} }
void PaintVoxelMaterialEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { void PaintVoxelMaterialEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
PaintVoxelMaterialEditVisitor visitor(position, radius, material, averageColor); // make sure it's 100% opaque
QColor color = averageColor;
color.setAlphaF(1.0f);
PaintVoxelMaterialEditVisitor visitor(position, radius, material, color);
data.guide(visitor); data.guide(visitor);
} }

View file

@ -91,7 +91,7 @@ public:
virtual ~MetavoxelEdit(); virtual ~MetavoxelEdit();
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const = 0; virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
}; };
/// An edit that sets the region within a box to a value. /// An edit that sets the region within a box to a value.
@ -224,16 +224,28 @@ public:
DECLARE_STREAMABLE_METATYPE(PaintHeightfieldHeightEdit) DECLARE_STREAMABLE_METATYPE(PaintHeightfieldHeightEdit)
/// Base class for edits that have materials.
class MaterialEdit : public MetavoxelEdit {
STREAMABLE
public:
STREAM SharedObjectPointer material;
STREAM QColor averageColor;
MaterialEdit(const SharedObjectPointer& material = SharedObjectPointer(), const QColor& averageColor = QColor());
};
DECLARE_STREAMABLE_METATYPE(MaterialEdit)
/// An edit that sets a region of a heightfield material. /// An edit that sets a region of a heightfield material.
class PaintHeightfieldMaterialEdit : public MetavoxelEdit { class PaintHeightfieldMaterialEdit : STREAM public MaterialEdit {
STREAMABLE STREAMABLE
public: public:
STREAM glm::vec3 position; STREAM glm::vec3 position;
STREAM float radius; STREAM float radius;
STREAM SharedObjectPointer material;
STREAM QColor averageColor;
PaintHeightfieldMaterialEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f, PaintHeightfieldMaterialEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f,
const SharedObjectPointer& material = SharedObjectPointer(), const QColor& averageColor = QColor()); const SharedObjectPointer& material = SharedObjectPointer(), const QColor& averageColor = QColor());
@ -244,14 +256,12 @@ public:
DECLARE_STREAMABLE_METATYPE(PaintHeightfieldMaterialEdit) DECLARE_STREAMABLE_METATYPE(PaintHeightfieldMaterialEdit)
/// An edit that sets the materials of voxels within a spanner to a value. /// An edit that sets the materials of voxels within a spanner to a value.
class VoxelMaterialSpannerEdit : public MetavoxelEdit { class VoxelMaterialSpannerEdit : STREAM public MaterialEdit {
STREAMABLE STREAMABLE
public: public:
STREAM SharedObjectPointer spanner; STREAM SharedObjectPointer spanner;
STREAM SharedObjectPointer material;
STREAM QColor averageColor;
VoxelMaterialSpannerEdit(const SharedObjectPointer& spanner = SharedObjectPointer(), VoxelMaterialSpannerEdit(const SharedObjectPointer& spanner = SharedObjectPointer(),
const SharedObjectPointer& material = SharedObjectPointer(), const QColor& averageColor = QColor()); const SharedObjectPointer& material = SharedObjectPointer(), const QColor& averageColor = QColor());
@ -262,15 +272,13 @@ public:
DECLARE_STREAMABLE_METATYPE(VoxelMaterialSpannerEdit) DECLARE_STREAMABLE_METATYPE(VoxelMaterialSpannerEdit)
/// An edit that sets a region of a voxel material. /// An edit that sets a region of a voxel material.
class PaintVoxelMaterialEdit : public MetavoxelEdit { class PaintVoxelMaterialEdit : STREAM public MaterialEdit {
STREAMABLE STREAMABLE
public: public:
STREAM glm::vec3 position; STREAM glm::vec3 position;
STREAM float radius; STREAM float radius;
STREAM SharedObjectPointer material;
STREAM QColor averageColor;
PaintVoxelMaterialEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f, PaintVoxelMaterialEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f,
const SharedObjectPointer& material = SharedObjectPointer(), const QColor& averageColor = QColor()); const SharedObjectPointer& material = SharedObjectPointer(), const QColor& averageColor = QColor());

View file

@ -85,7 +85,7 @@ PacketVersion versionForPacketType(PacketType type) {
case PacketTypeAudioStreamStats: case PacketTypeAudioStreamStats:
return 1; return 1;
case PacketTypeMetavoxelData: case PacketTypeMetavoxelData:
return 6; return 7;
case PacketTypeVoxelData: case PacketTypeVoxelData:
return VERSION_VOXELS_HAS_FILE_BREAKS; return VERSION_VOXELS_HAS_FILE_BREAKS;
default: default:

View file

@ -10,6 +10,7 @@
// //
#include <QColor> #include <QColor>
#include <QUrl>
#include <QUuid> #include <QUuid>
#include "RegisteredMetaTypes.h" #include "RegisteredMetaTypes.h"
@ -29,6 +30,7 @@ void registerMetaTypes(QScriptEngine* engine) {
qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue); qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue);
qScriptRegisterMetaType(engine, xColorToScriptValue, xColorFromScriptValue); qScriptRegisterMetaType(engine, xColorToScriptValue, xColorFromScriptValue);
qScriptRegisterMetaType(engine, qColorToScriptValue, qColorFromScriptValue); qScriptRegisterMetaType(engine, qColorToScriptValue, qColorFromScriptValue);
qScriptRegisterMetaType(engine, qURLToScriptValue, qURLFromScriptValue);
qScriptRegisterMetaType(engine, pickRayToScriptValue, pickRayFromScriptValue); qScriptRegisterMetaType(engine, pickRayToScriptValue, pickRayFromScriptValue);
qScriptRegisterMetaType(engine, collisionToScriptValue, collisionFromScriptValue); qScriptRegisterMetaType(engine, collisionToScriptValue, collisionFromScriptValue);
qScriptRegisterMetaType(engine, quuidToScriptValue, quuidFromScriptValue); qScriptRegisterMetaType(engine, quuidToScriptValue, quuidFromScriptValue);
@ -129,6 +131,14 @@ void qColorFromScriptValue(const QScriptValue& object, QColor& color) {
} }
} }
QScriptValue qURLToScriptValue(QScriptEngine* engine, const QUrl& url) {
return url.toString();
}
void qURLFromScriptValue(const QScriptValue& object, QUrl& url) {
url = object.toString();
}
QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay) { QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay) {
QScriptValue obj = engine->newObject(); QScriptValue obj = engine->newObject();
QScriptValue origin = vec3toScriptValue(engine, pickRay.origin); QScriptValue origin = vec3toScriptValue(engine, pickRay.origin);

View file

@ -20,6 +20,7 @@
#include "SharedUtil.h" #include "SharedUtil.h"
class QColor; class QColor;
class QUrl;
Q_DECLARE_METATYPE(glm::vec4) Q_DECLARE_METATYPE(glm::vec4)
Q_DECLARE_METATYPE(glm::vec3) Q_DECLARE_METATYPE(glm::vec3)
@ -47,6 +48,9 @@ void xColorFromScriptValue(const QScriptValue &object, xColor& color);
QScriptValue qColorToScriptValue(QScriptEngine* engine, const QColor& color); QScriptValue qColorToScriptValue(QScriptEngine* engine, const QColor& color);
void qColorFromScriptValue(const QScriptValue& object, QColor& color); void qColorFromScriptValue(const QScriptValue& object, QColor& color);
QScriptValue qURLToScriptValue(QScriptEngine* engine, const QUrl& url);
void qURLFromScriptValue(const QScriptValue& object, QUrl& url);
class PickRay { class PickRay {
public: public:
PickRay() : origin(0), direction(0) { }; PickRay() : origin(0), direction(0) { };

View file

@ -15,6 +15,7 @@
#include <QtScript/QScriptEngine> #include <QtScript/QScriptEngine>
#include <AACube.h> #include <AACube.h>
#include <OctreeConstants.h>
#include <SharedUtil.h> #include <SharedUtil.h>
#include "VoxelConstants.h" #include "VoxelConstants.h"
@ -53,8 +54,6 @@ void rayToVoxelIntersectionResultFromScriptValue(const QScriptValue& object, Ray
inline QDebug operator<<(QDebug debug, const VoxelDetail& details) { inline QDebug operator<<(QDebug debug, const VoxelDetail& details) {
const int TREE_SCALE = 16384; // ~10 miles.. This is the number of meters of the 0.0 to 1.0 voxel universe
debug << "VoxelDetail[ (" debug << "VoxelDetail[ ("
<< details.x * (float)TREE_SCALE << "," << details.y * (float)TREE_SCALE << "," << details.z * (float)TREE_SCALE << details.x * (float)TREE_SCALE << "," << details.y * (float)TREE_SCALE << "," << details.z * (float)TREE_SCALE
<< " ) to (" << " ) to ("