mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 18:23:54 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi
This commit is contained in:
commit
5c465198c5
30 changed files with 646 additions and 272 deletions
|
@ -46,6 +46,7 @@
|
|||
#include <NetworkAccessManager.h>
|
||||
#include <NodeList.h>
|
||||
#include <Node.h>
|
||||
#include <OctreeConstants.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <SharedUtil.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 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) {
|
||||
if (!newNode->getLinkedData()) {
|
||||
|
@ -87,8 +90,6 @@ AudioMixer::AudioMixer(const QByteArray& packet) :
|
|||
_numStatFrames(0),
|
||||
_sumListeners(0),
|
||||
_sumMixes(0),
|
||||
_sourceUnattenuatedZone(NULL),
|
||||
_listenerUnattenuatedZone(NULL),
|
||||
_lastPerSecondCallbackTime(usecTimestampNow()),
|
||||
_sendAudioStreamStats(false),
|
||||
_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
|
||||
}
|
||||
|
||||
AudioMixer::~AudioMixer() {
|
||||
delete _sourceUnattenuatedZone;
|
||||
delete _listenerUnattenuatedZone;
|
||||
}
|
||||
|
||||
const float ATTENUATION_BEGINS_AT_DISTANCE = 1.0f;
|
||||
const float RADIUS_OF_HEAD = 0.076f;
|
||||
|
||||
int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* listenerNodeData,
|
||||
const QUuid& streamUUID,
|
||||
PositionalAudioStream* streamToAdd,
|
||||
AvatarAudioStream* listeningNodeStream) {
|
||||
const QUuid& streamUUID,
|
||||
PositionalAudioStream* streamToAdd,
|
||||
AvatarAudioStream* listeningNodeStream) {
|
||||
// If repetition with fade is enabled:
|
||||
// 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.
|
||||
|
@ -120,9 +116,9 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l
|
|||
// This improves the perceived quality of the audio slightly.
|
||||
|
||||
bool showDebug = false; // (randFloat() < 0.05f);
|
||||
|
||||
|
||||
float repeatedFrameFadeFactor = 1.0f;
|
||||
|
||||
|
||||
if (!streamToAdd->lastPopSucceeded()) {
|
||||
if (_streamSettings._repetitionWithFade && !streamToAdd->getLastPopOutput().isNull()) {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// at this point, we know streamToAdd's last pop output is valid
|
||||
|
||||
|
||||
// if the frame we're about to mix is silent, bail
|
||||
if (streamToAdd->getLastPopOutputLoudness() == 0.0f) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
float bearingRelativeAngleToSource = 0.0f;
|
||||
float attenuationCoefficient = 1.0f;
|
||||
int numSamplesDelay = 0;
|
||||
float weakChannelAmplitudeRatio = 1.0f;
|
||||
|
||||
bool shouldDistanceAttenuate = true;
|
||||
|
||||
// Is the source that I am mixing my own?
|
||||
bool sourceIsSelf = (streamToAdd == listeningNodeStream);
|
||||
|
||||
|
@ -169,10 +163,6 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l
|
|||
|
||||
++_sumMixes;
|
||||
|
||||
if (streamToAdd->getListenerUnattenuatedZone()) {
|
||||
shouldDistanceAttenuate = !streamToAdd->getListenerUnattenuatedZone()->contains(listeningNodeStream->getPosition());
|
||||
}
|
||||
|
||||
if (streamToAdd->getType() == PositionalAudioStream::Injector) {
|
||||
attenuationCoefficient *= reinterpret_cast<InjectedAudioStream*>(streamToAdd)->getAttenuationRatio();
|
||||
if (showDebug) {
|
||||
|
@ -207,11 +197,28 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l
|
|||
|
||||
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
|
||||
float distanceCoefficient = 1 - (logf(distanceBetween / ATTENUATION_BEGINS_AT_DISTANCE) / logf(2.0f)
|
||||
* _attenuationPerDoublingInDistance);
|
||||
* attenuationPerDoublingInDistance);
|
||||
|
||||
if (distanceCoefficient < 0) {
|
||||
distanceCoefficient = 0;
|
||||
|
@ -637,120 +644,7 @@ void AudioMixer::run() {
|
|||
const QJsonObject& settingsObject = domainHandler.getSettingsObject();
|
||||
|
||||
// check the settings object to see if we have anything we can parse out
|
||||
const QString AUDIO_GROUP_KEY = "audio";
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
parseSettingsObject(settingsObject);
|
||||
|
||||
int nextFrame = 0;
|
||||
QElapsedTimer timer;
|
||||
|
@ -829,7 +723,7 @@ void AudioMixer::run() {
|
|||
// 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.
|
||||
// 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()
|
||||
&& 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) + "%";
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ class AudioMixer : public ThreadedAssignment {
|
|||
Q_OBJECT
|
||||
public:
|
||||
AudioMixer(const QByteArray& packet);
|
||||
~AudioMixer();
|
||||
public slots:
|
||||
/// threaded run of assignment
|
||||
void run();
|
||||
|
@ -66,6 +65,8 @@ private:
|
|||
QString getReadPendingDatagramsTimeStatsString() const;
|
||||
QString getReadPendingDatagramsHashMatchTimeStatsString() const;
|
||||
|
||||
void parseSettingsObject(const QJsonObject& settingsObject);
|
||||
|
||||
float _trailingSleepRatio;
|
||||
float _minAudibilityThreshold;
|
||||
float _performanceThrottlingRatio;
|
||||
|
@ -73,8 +74,8 @@ private:
|
|||
int _numStatFrames;
|
||||
int _sumListeners;
|
||||
int _sumMixes;
|
||||
AABox* _sourceUnattenuatedZone;
|
||||
AABox* _listenerUnattenuatedZone;
|
||||
QHash<QString, AABox> _audioZones;
|
||||
QHash<QString, QHash<QString, float> > _attenuationCoefficients;
|
||||
|
||||
static InboundAudioStream::Settings _streamSettings;
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ int AudioMixerClientData::parseData(const QByteArray& packet) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void AudioMixerClientData::checkBuffersBeforeFrameSend(AABox* checkSourceZone, AABox* listenerZone) {
|
||||
void AudioMixerClientData::checkBuffersBeforeFrameSend() {
|
||||
QHash<QUuid, PositionalAudioStream*>::ConstIterator i;
|
||||
for (i = _audioStreams.constBegin(); i != _audioStreams.constEnd(); i++) {
|
||||
PositionalAudioStream* stream = i.value();
|
||||
|
@ -114,12 +114,6 @@ void AudioMixerClientData::checkBuffersBeforeFrameSend(AABox* checkSourceZone, A
|
|||
if (stream->popFrames(1, true) > 0) {
|
||||
stream->updateLastPopOutputLoudnessAndTrailingLoudness();
|
||||
}
|
||||
|
||||
if (checkSourceZone && checkSourceZone->contains(stream->getPosition())) {
|
||||
stream->setListenerUnattenuatedZone(listenerZone);
|
||||
} else {
|
||||
stream->setListenerUnattenuatedZone(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ public:
|
|||
|
||||
int parseData(const QByteArray& packet);
|
||||
|
||||
void checkBuffersBeforeFrameSend(AABox* checkSourceZone, AABox* listenerZone);
|
||||
void checkBuffersBeforeFrameSend();
|
||||
|
||||
void removeDeadInjectedStreams();
|
||||
|
||||
|
|
|
@ -63,10 +63,24 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"name": "audio",
|
||||
"label": "Audio",
|
||||
"name": "audio_env",
|
||||
"label": "Audio Environment",
|
||||
"assignment-types": [0],
|
||||
"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",
|
||||
"type": "table",
|
||||
|
@ -76,7 +90,7 @@
|
|||
"key": {
|
||||
"name": "name",
|
||||
"label": "Name",
|
||||
"placeholder": "Zone name"
|
||||
"placeholder": "Zone_Name"
|
||||
},
|
||||
"columns": [
|
||||
{
|
||||
|
@ -125,28 +139,14 @@
|
|||
"placeholder": "0.18"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "enable_filter",
|
||||
"type": "checkbox",
|
||||
"label": "Positional filter",
|
||||
"help": "positional audio stream uses lowpass filter",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"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": "audio_buffer",
|
||||
"label": "Audio Buffer",
|
||||
"assignment-types": [0],
|
||||
"settings": [
|
||||
{
|
||||
"name": "dynamic_jitter_buffer",
|
||||
"type": "checkbox",
|
||||
|
|
|
@ -35,7 +35,9 @@ var viewHelpers = {
|
|||
+ " " + Settings.TRIGGER_CHANGE_CLASS + "' data-short-name='" + setting.name + "' name='" + setting_name + "' "
|
||||
|
||||
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 += "<label for='" + setting_name + "'>"
|
||||
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);
|
||||
} else {
|
||||
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') {
|
||||
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) {
|
||||
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 += "<table class='table table-bordered' data-short-name='" + setting.name + "' name='" + setting_name
|
||||
+ "' data-setting-type='" + (isArray ? 'array' : 'hash') + "'>"
|
||||
|
@ -317,7 +321,7 @@ function makeTableInputs(setting) {
|
|||
|
||||
_.each(setting.columns, function(col) {
|
||||
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>"
|
||||
})
|
||||
|
||||
|
@ -487,7 +491,7 @@ function deleteTableRow(delete_glyphicon) {
|
|||
|
||||
row.removeClass(Settings.DATA_ROW_CLASS).removeClass(Settings.NEW_ROW_CLASS)
|
||||
row.addClass('empty-array-row')
|
||||
|
||||
|
||||
row.html("<input type='hidden' class='form-control' name='" + table.attr("name").replace('[]', '')
|
||||
+ "' data-changed='true' value=''>");
|
||||
}
|
||||
|
|
|
@ -1312,7 +1312,6 @@ var toolBar = (function () {
|
|||
if (clickedOverlay === loadFileMenuItem) {
|
||||
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 ...",
|
||||
Settings.getValue("LastModelUploadLocation").path(),
|
||||
"Model files (*.fst *.fbx)");
|
||||
|
|
|
@ -60,9 +60,17 @@ SelectionDisplay = (function () {
|
|||
var rotateHandleColor = { red: 0, green: 0, blue: 0 };
|
||||
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 grabberSizeEdge = 0.015;
|
||||
var grabberSizeFace = 0.025;
|
||||
var grabberAlpha = 1;
|
||||
var grabberColorCorner = { red: 120, green: 120, blue: 120 };
|
||||
var grabberColorEdge = { red: 0, green: 0, blue: 0 };
|
||||
var grabberColorFace = { red: 120, green: 120, blue: 120 };
|
||||
|
@ -2320,7 +2328,96 @@ SelectionDisplay = (function () {
|
|||
that.stretchLEFT(event);
|
||||
break;
|
||||
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 true;
|
||||
|
|
41
examples/metavoxels.js
Normal file
41
examples/metavoxels.js
Normal 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);
|
||||
|
|
@ -238,7 +238,6 @@ var toolBar = (function () {
|
|||
if (clickedOverlay === loadFileMenuItem) {
|
||||
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 ...",
|
||||
Settings.getValue("LastModelUploadLocation").path(),
|
||||
"Model files (*.fst *.fbx)");
|
||||
|
|
|
@ -187,8 +187,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
// set the associated application properties
|
||||
applicationInfo.beginGroup("INFO");
|
||||
|
||||
qDebug() << "[VERSION] Build sequence: " << qPrintable(applicationVersion());
|
||||
|
||||
setApplicationName(applicationInfo.value("name").toString());
|
||||
setApplicationVersion(BUILD_VERSION);
|
||||
setOrganizationName(applicationInfo.value("organizationName").toString());
|
||||
|
@ -207,6 +205,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
|
||||
qInstallMessageHandler(messageHandler);
|
||||
|
||||
qDebug() << "[VERSION] Build sequence: " << qPrintable(applicationVersion());
|
||||
|
||||
// call Menu getInstance static method to set up the menu
|
||||
_window->setMenuBar(Menu::getInstance());
|
||||
|
||||
|
|
|
@ -158,7 +158,7 @@ Menu::Menu() :
|
|||
addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScriptURL,
|
||||
Qt::CTRL | Qt::SHIFT | Qt::Key_O, appInstance, SLOT(loadScriptURLDialog()));
|
||||
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()));
|
||||
addActionToQMenuAndActionHash(fileMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J,
|
||||
appInstance, SLOT(toggleRunningScriptsWidget()));
|
||||
|
@ -246,10 +246,16 @@ Menu::Menu() :
|
|||
#endif
|
||||
|
||||
addActionToQMenuAndActionHash(toolsMenu,
|
||||
MenuOption::Console,
|
||||
Qt::CTRL | Qt::ALT | Qt::Key_J,
|
||||
this,
|
||||
SLOT(toggleConsole()));
|
||||
MenuOption::Console,
|
||||
Qt::CTRL | Qt::ALT | Qt::Key_J,
|
||||
this,
|
||||
SLOT(toggleConsole()));
|
||||
|
||||
addActionToQMenuAndActionHash(toolsMenu,
|
||||
MenuOption::ResetSensors,
|
||||
Qt::Key_Apostrophe,
|
||||
appInstance,
|
||||
SLOT(resetSensors()));
|
||||
|
||||
QMenu* avatarMenu = addMenu("Avatar");
|
||||
|
||||
|
|
|
@ -442,6 +442,7 @@ namespace MenuOption {
|
|||
const QString RenderLookAtVectors = "Show Look-at Vectors";
|
||||
const QString RenderSkeletonCollisionShapes = "Show Skeleton Collision Shapes";
|
||||
const QString ResetAvatarSize = "Reset Avatar Size";
|
||||
const QString ResetSensors = "Reset Sensors";
|
||||
const QString RunningScripts = "Running Scripts";
|
||||
const QString RunTimingTests = "Run Timing Tests";
|
||||
const QString ScriptEditor = "Script Editor...";
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include <MetavoxelMessages.h>
|
||||
#include <MetavoxelUtil.h>
|
||||
#include <ScriptCache.h>
|
||||
|
||||
|
@ -454,6 +455,36 @@ float MetavoxelSystem::getHeightfieldHeight(const glm::vec3& location) {
|
|||
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 {
|
||||
public:
|
||||
|
||||
|
@ -563,6 +594,55 @@ void MetavoxelSystem::deleteTextures(int heightID, int colorID, int 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) {
|
||||
return new MetavoxelSystemClient(node, _updater);
|
||||
}
|
||||
|
|
|
@ -54,6 +54,18 @@ public:
|
|||
|
||||
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);
|
||||
|
||||
signals:
|
||||
|
@ -66,6 +78,8 @@ public slots:
|
|||
|
||||
protected:
|
||||
|
||||
Q_INVOKABLE void applyMaterialEdit(const MetavoxelEditMessage& message, bool reliable = false);
|
||||
|
||||
virtual MetavoxelClient* createClient(const SharedNodePointer& node);
|
||||
|
||||
private:
|
||||
|
@ -81,6 +95,15 @@ private:
|
|||
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.
|
||||
class BufferPoint {
|
||||
public:
|
||||
|
|
|
@ -78,6 +78,8 @@ void OculusManager::connect() {
|
|||
#ifdef HAVE_LIBOVR
|
||||
_calibrationState = UNCALIBRATED;
|
||||
|
||||
qDebug() << "Oculus SDK" << OVR_VERSION_STRING;
|
||||
|
||||
ovr_Initialize();
|
||||
|
||||
_ovrHmd = ovrHmd_Create(0);
|
||||
|
|
|
@ -22,6 +22,9 @@ QVariant SettingsScriptingInterface::getValue(const QString& setting) {
|
|||
QSettings* settings = Application::getInstance()->lockSettings();
|
||||
QVariant value = settings->value(setting);
|
||||
Application::getInstance()->unlockSettings();
|
||||
if (!value.isValid()) {
|
||||
value = "";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -29,6 +32,9 @@ QVariant SettingsScriptingInterface::getValue(const QString& setting, const QVar
|
|||
QSettings* settings = Application::getInstance()->lockSettings();
|
||||
QVariant value = settings->value(setting, defaultValue);
|
||||
Application::getInstance()->unlockSettings();
|
||||
if (!value.isValid()) {
|
||||
value = "";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
|
|
@ -1392,16 +1392,14 @@ void VoxelMaterialBoxTool::applyValue(const glm::vec3& minimum, const glm::vec3&
|
|||
} else {
|
||||
material = SharedObjectPointer();
|
||||
}
|
||||
QColor color = _color->getColor();
|
||||
color.setAlphaF(color.alphaF() > 0.5f ? 1.0f : 0.0f);
|
||||
|
||||
Cuboid* cuboid = new Cuboid();
|
||||
cuboid->setTranslation((maximum + minimum) * 0.5f);
|
||||
glm::vec3 vector = (maximum - minimum) * 0.5f;
|
||||
cuboid->setScale(vector.x);
|
||||
cuboid->setAspectY(vector.y / 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);
|
||||
}
|
||||
|
||||
|
@ -1489,9 +1487,7 @@ void VoxelMaterialSpannerTool::applyEdit(const AttributePointer& attribute, cons
|
|||
} else {
|
||||
material = SharedObjectPointer();
|
||||
}
|
||||
QColor color = _color->getColor();
|
||||
color.setAlphaF(color.alphaF() > 0.5f ? 1.0f : 0.0f);
|
||||
MetavoxelEditMessage message = { QVariant::fromValue(VoxelMaterialSpannerEdit(spanner, material, color)) };
|
||||
MetavoxelEditMessage message = { QVariant::fromValue(VoxelMaterialSpannerEdit(spanner, material, _color->getColor())) };
|
||||
Application::getInstance()->getMetavoxels()->applyEdit(message, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,9 @@ RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) :
|
|||
connect(&_proxyModel, &QSortFilterProxyModel::modelReset,
|
||||
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.sort(0, Qt::AscendingOrder);
|
||||
_proxyModel.setDynamicSortFilter(true);
|
||||
|
@ -86,7 +89,7 @@ void RunningScriptsWidget::setBoundary(const QRect& rect) {
|
|||
void RunningScriptsWidget::setRunningScripts(const QStringList& list) {
|
||||
setUpdatesEnabled(false);
|
||||
QLayoutItem* widget;
|
||||
while ((widget = ui->scrollAreaWidgetContents->layout()->takeAt(0)) != NULL) {
|
||||
while ((widget = ui->scriptListWidget->layout()->takeAt(0)) != NULL) {
|
||||
delete widget->widget();
|
||||
delete widget;
|
||||
}
|
||||
|
@ -96,7 +99,7 @@ void RunningScriptsWidget::setRunningScripts(const QStringList& list) {
|
|||
if (!hash.contains(list.at(i))) {
|
||||
hash.insert(list.at(i), 1);
|
||||
}
|
||||
QWidget* row = new QWidget(ui->scrollAreaWidgetContents);
|
||||
QWidget* row = new QWidget(ui->scriptListWidget);
|
||||
row->setLayout(new QHBoxLayout(row));
|
||||
|
||||
QUrl url = QUrl(list.at(i));
|
||||
|
@ -130,17 +133,16 @@ void RunningScriptsWidget::setRunningScripts(const QStringList& list) {
|
|||
line->setFrameShape(QFrame::HLine);
|
||||
line->setStyleSheet("color: #E1E1E1; margin-left: 6px; margin-right: 6px;");
|
||||
|
||||
ui->scrollAreaWidgetContents->layout()->addWidget(row);
|
||||
ui->scrollAreaWidgetContents->layout()->addWidget(line);
|
||||
ui->scriptListWidget->layout()->addWidget(row);
|
||||
ui->scriptListWidget->layout()->addWidget(line);
|
||||
}
|
||||
|
||||
|
||||
ui->noRunningScriptsLabel->setVisible(list.isEmpty());
|
||||
ui->runningScriptsList->setVisible(!list.isEmpty());
|
||||
ui->reloadAllButton->setVisible(!list.isEmpty());
|
||||
ui->stopAllButton->setVisible(!list.isEmpty());
|
||||
|
||||
ui->scrollAreaWidgetContents->updateGeometry();
|
||||
ui->scriptListWidget->updateGeometry();
|
||||
setUpdatesEnabled(true);
|
||||
Application::processEvents();
|
||||
repaint();
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>319</width>
|
||||
<height>481</height>
|
||||
<width>364</width>
|
||||
<height>728</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -16,19 +16,7 @@
|
|||
<property name="styleSheet">
|
||||
<string notr="true">* { font-family: Helvetica, Arial, sans-serif; }</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_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>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="3,2">
|
||||
<item>
|
||||
<widget class="QWidget" name="runningScriptsArea" native="true">
|
||||
<property name="sizePolicy">
|
||||
|
@ -195,6 +183,25 @@ font: bold 16px;
|
|||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</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>
|
||||
<widget class="QScrollArea" name="runningScriptsList">
|
||||
<property name="sizePolicy">
|
||||
|
@ -219,10 +226,10 @@ font: bold 16px;
|
|||
<number>0</number>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustToContents</enum>
|
||||
|
@ -238,8 +245,8 @@ font: bold 16px;
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>264</width>
|
||||
<height>16</height>
|
||||
<width>328</width>
|
||||
<height>18</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -254,7 +261,7 @@ font: bold 16px;
|
|||
<property name="styleSheet">
|
||||
<string notr="true">font-size: 14px;</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
|
@ -270,29 +277,41 @@ font: bold 16px;
|
|||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</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>
|
||||
</widget>
|
||||
</widget>
|
||||
</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>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -30,8 +30,7 @@ PositionalAudioStream::PositionalAudioStream(PositionalAudioStream::Type type, b
|
|||
_shouldLoopbackForNode(false),
|
||||
_isStereo(isStereo),
|
||||
_lastPopOutputTrailingLoudness(0.0f),
|
||||
_lastPopOutputLoudness(0.0f),
|
||||
_listenerUnattenuatedZone(NULL)
|
||||
_lastPopOutputLoudness(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -42,9 +42,6 @@ public:
|
|||
PositionalAudioStream::Type getType() const { return _type; }
|
||||
const glm::vec3& getPosition() const { return _position; }
|
||||
const glm::quat& getOrientation() const { return _orientation; }
|
||||
AABox* getListenerUnattenuatedZone() const { return _listenerUnattenuatedZone; }
|
||||
|
||||
void setListenerUnattenuatedZone(AABox* listenerUnattenuatedZone) { _listenerUnattenuatedZone = listenerUnattenuatedZone; }
|
||||
|
||||
protected:
|
||||
// disallow copying of PositionalAudioStream objects
|
||||
|
@ -63,7 +60,6 @@ protected:
|
|||
|
||||
float _lastPopOutputTrailingLoudness;
|
||||
float _lastPopOutputLoudness;
|
||||
AABox* _listenerUnattenuatedZone;
|
||||
};
|
||||
|
||||
#endif // hifi_PositionalAudioStream_h
|
||||
|
|
|
@ -74,6 +74,11 @@ void MetavoxelClientManager::setSpanner(const SharedObjectPointer& object, bool
|
|||
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) {
|
||||
QMetaObject::invokeMethod(_updater, "applyEdit", Q_ARG(const MetavoxelEditMessage&, edit), Q_ARG(bool, reliable));
|
||||
}
|
||||
|
|
|
@ -41,6 +41,8 @@ public:
|
|||
|
||||
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);
|
||||
|
||||
/// Returns the current LOD. This must be thread-safe, as it will be called from the updater thread.
|
||||
|
|
|
@ -18,6 +18,10 @@ void MetavoxelEditMessage::apply(MetavoxelData& data, const WeakSharedObjectHash
|
|||
MetavoxelEdit::~MetavoxelEdit() {
|
||||
}
|
||||
|
||||
void MetavoxelEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
// nothing by default
|
||||
}
|
||||
|
||||
BoxSetEdit::BoxSetEdit(const Box& region, float granularity, const OwnedAttributeValue& value) :
|
||||
region(region), granularity(granularity), value(value) {
|
||||
}
|
||||
|
@ -408,6 +412,11 @@ void PaintHeightfieldHeightEdit::apply(MetavoxelData& data, const WeakSharedObje
|
|||
data.guide(visitor);
|
||||
}
|
||||
|
||||
MaterialEdit::MaterialEdit(const SharedObjectPointer& material, const QColor& averageColor) :
|
||||
material(material),
|
||||
averageColor(averageColor) {
|
||||
}
|
||||
|
||||
class PaintHeightfieldMaterialEditVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
|
@ -595,10 +604,9 @@ int PaintHeightfieldMaterialEditVisitor::visit(MetavoxelInfo& info) {
|
|||
|
||||
PaintHeightfieldMaterialEdit::PaintHeightfieldMaterialEdit(const glm::vec3& position, float radius,
|
||||
const SharedObjectPointer& material, const QColor& averageColor) :
|
||||
MaterialEdit(material, averageColor),
|
||||
position(position),
|
||||
radius(radius),
|
||||
material(material),
|
||||
averageColor(averageColor) {
|
||||
radius(radius) {
|
||||
}
|
||||
|
||||
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,
|
||||
const SharedObjectPointer& material, const QColor& averageColor) :
|
||||
spanner(spanner),
|
||||
material(material),
|
||||
averageColor(averageColor) {
|
||||
MaterialEdit(material, averageColor),
|
||||
spanner(spanner) {
|
||||
}
|
||||
|
||||
class VoxelMaterialSpannerEditVisitor : public MetavoxelVisitor {
|
||||
|
@ -845,16 +852,18 @@ void VoxelMaterialSpannerEdit::apply(MetavoxelData& data, const WeakSharedObject
|
|||
while (!data.getBounds().contains(spanner->getBounds())) {
|
||||
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);
|
||||
}
|
||||
|
||||
PaintVoxelMaterialEdit::PaintVoxelMaterialEdit(const glm::vec3& position, float radius,
|
||||
const SharedObjectPointer& material, const QColor& averageColor) :
|
||||
MaterialEdit(material, averageColor),
|
||||
position(position),
|
||||
radius(radius),
|
||||
material(material),
|
||||
averageColor(averageColor) {
|
||||
radius(radius) {
|
||||
}
|
||||
|
||||
class PaintVoxelMaterialEditVisitor : public MetavoxelVisitor {
|
||||
|
@ -950,6 +959,9 @@ int PaintVoxelMaterialEditVisitor::visit(MetavoxelInfo& info) {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ public:
|
|||
|
||||
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.
|
||||
|
@ -224,16 +224,28 @@ public:
|
|||
|
||||
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.
|
||||
class PaintHeightfieldMaterialEdit : public MetavoxelEdit {
|
||||
class PaintHeightfieldMaterialEdit : STREAM public MaterialEdit {
|
||||
STREAMABLE
|
||||
|
||||
public:
|
||||
|
||||
STREAM glm::vec3 position;
|
||||
STREAM float radius;
|
||||
STREAM SharedObjectPointer material;
|
||||
STREAM QColor averageColor;
|
||||
|
||||
PaintHeightfieldMaterialEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f,
|
||||
const SharedObjectPointer& material = SharedObjectPointer(), const QColor& averageColor = QColor());
|
||||
|
@ -244,14 +256,12 @@ public:
|
|||
DECLARE_STREAMABLE_METATYPE(PaintHeightfieldMaterialEdit)
|
||||
|
||||
/// An edit that sets the materials of voxels within a spanner to a value.
|
||||
class VoxelMaterialSpannerEdit : public MetavoxelEdit {
|
||||
class VoxelMaterialSpannerEdit : STREAM public MaterialEdit {
|
||||
STREAMABLE
|
||||
|
||||
public:
|
||||
|
||||
STREAM SharedObjectPointer spanner;
|
||||
STREAM SharedObjectPointer material;
|
||||
STREAM QColor averageColor;
|
||||
|
||||
VoxelMaterialSpannerEdit(const SharedObjectPointer& spanner = SharedObjectPointer(),
|
||||
const SharedObjectPointer& material = SharedObjectPointer(), const QColor& averageColor = QColor());
|
||||
|
@ -262,15 +272,13 @@ public:
|
|||
DECLARE_STREAMABLE_METATYPE(VoxelMaterialSpannerEdit)
|
||||
|
||||
/// An edit that sets a region of a voxel material.
|
||||
class PaintVoxelMaterialEdit : public MetavoxelEdit {
|
||||
class PaintVoxelMaterialEdit : STREAM public MaterialEdit {
|
||||
STREAMABLE
|
||||
|
||||
public:
|
||||
|
||||
STREAM glm::vec3 position;
|
||||
STREAM float radius;
|
||||
STREAM SharedObjectPointer material;
|
||||
STREAM QColor averageColor;
|
||||
|
||||
PaintVoxelMaterialEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f,
|
||||
const SharedObjectPointer& material = SharedObjectPointer(), const QColor& averageColor = QColor());
|
||||
|
|
|
@ -85,7 +85,7 @@ PacketVersion versionForPacketType(PacketType type) {
|
|||
case PacketTypeAudioStreamStats:
|
||||
return 1;
|
||||
case PacketTypeMetavoxelData:
|
||||
return 6;
|
||||
return 7;
|
||||
case PacketTypeVoxelData:
|
||||
return VERSION_VOXELS_HAS_FILE_BREAKS;
|
||||
default:
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
//
|
||||
|
||||
#include <QColor>
|
||||
#include <QUrl>
|
||||
#include <QUuid>
|
||||
|
||||
#include "RegisteredMetaTypes.h"
|
||||
|
@ -29,6 +30,7 @@ void registerMetaTypes(QScriptEngine* engine) {
|
|||
qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, xColorToScriptValue, xColorFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, qColorToScriptValue, qColorFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, qURLToScriptValue, qURLFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, pickRayToScriptValue, pickRayFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, collisionToScriptValue, collisionFromScriptValue);
|
||||
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 obj = engine->newObject();
|
||||
QScriptValue origin = vec3toScriptValue(engine, pickRay.origin);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "SharedUtil.h"
|
||||
|
||||
class QColor;
|
||||
class QUrl;
|
||||
|
||||
Q_DECLARE_METATYPE(glm::vec4)
|
||||
Q_DECLARE_METATYPE(glm::vec3)
|
||||
|
@ -47,6 +48,9 @@ void xColorFromScriptValue(const QScriptValue &object, xColor& color);
|
|||
QScriptValue qColorToScriptValue(QScriptEngine* engine, const 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 {
|
||||
public:
|
||||
PickRay() : origin(0), direction(0) { };
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <QtScript/QScriptEngine>
|
||||
|
||||
#include <AACube.h>
|
||||
#include <OctreeConstants.h>
|
||||
#include <SharedUtil.h>
|
||||
#include "VoxelConstants.h"
|
||||
|
||||
|
@ -53,8 +54,6 @@ void rayToVoxelIntersectionResultFromScriptValue(const QScriptValue& object, Ray
|
|||
|
||||
|
||||
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[ ("
|
||||
<< details.x * (float)TREE_SCALE << "," << details.y * (float)TREE_SCALE << "," << details.z * (float)TREE_SCALE
|
||||
<< " ) to ("
|
||||
|
|
Loading…
Reference in a new issue