mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-05-30 20:39:59 +02:00
merge upstream/master into andrew/inertia
This commit is contained in:
commit
f3ead98624
49 changed files with 1535 additions and 560 deletions
|
@ -16,7 +16,7 @@
|
||||||
#include <AccountManager.h>
|
#include <AccountManager.h>
|
||||||
#include <Assignment.h>
|
#include <Assignment.h>
|
||||||
#include <HifiConfigVariantMap.h>
|
#include <HifiConfigVariantMap.h>
|
||||||
#include <Logging.h>
|
#include <LogHandler.h>
|
||||||
#include <LogUtils.h>
|
#include <LogUtils.h>
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
|
@ -51,7 +51,7 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
||||||
connect(&_shutdownEventListener, SIGNAL(receivedCloseEvent()), SLOT(quit()));
|
connect(&_shutdownEventListener, SIGNAL(receivedCloseEvent()), SLOT(quit()));
|
||||||
|
|
||||||
// set the logging target to the the CHILD_TARGET_NAME
|
// set the logging target to the the CHILD_TARGET_NAME
|
||||||
Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME);
|
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME);
|
||||||
|
|
||||||
const QVariantMap argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments());
|
const QVariantMap argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments());
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ void AssignmentClient::handleAuthenticationRequest() {
|
||||||
|
|
||||||
void AssignmentClient::assignmentCompleted() {
|
void AssignmentClient::assignmentCompleted() {
|
||||||
// reset the logging target to the the CHILD_TARGET_NAME
|
// reset the logging target to the the CHILD_TARGET_NAME
|
||||||
Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME);
|
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME);
|
||||||
|
|
||||||
qDebug("Assignment finished or never started - waiting for new assignment.");
|
qDebug("Assignment finished or never started - waiting for new assignment.");
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <Logging.h>
|
#include <LogHandler.h>
|
||||||
|
|
||||||
#include "AssignmentClientMonitor.h"
|
#include "AssignmentClientMonitor.h"
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(int &argc, char **argv, int num
|
||||||
QCoreApplication(argc, argv)
|
QCoreApplication(argc, argv)
|
||||||
{
|
{
|
||||||
// start the Logging class with the parent's target name
|
// start the Logging class with the parent's target name
|
||||||
Logging::setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME);
|
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME);
|
||||||
|
|
||||||
_childArguments = arguments();
|
_childArguments = arguments();
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
#include <QtNetwork/QNetworkRequest>
|
#include <QtNetwork/QNetworkRequest>
|
||||||
#include <QtNetwork/QNetworkReply>
|
#include <QtNetwork/QNetworkReply>
|
||||||
|
|
||||||
#include <Logging.h>
|
#include <LogHandler.h>
|
||||||
#include <NetworkAccessManager.h>
|
#include <NetworkAccessManager.h>
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
#include <Node.h>
|
#include <Node.h>
|
||||||
|
@ -640,6 +640,7 @@ void AudioMixer::run() {
|
||||||
timer.start();
|
timer.start();
|
||||||
|
|
||||||
char clientMixBuffer[MAX_PACKET_SIZE];
|
char clientMixBuffer[MAX_PACKET_SIZE];
|
||||||
|
char clientEnvBuffer[MAX_PACKET_SIZE];
|
||||||
|
|
||||||
int usecToSleep = BUFFER_SEND_INTERVAL_USECS;
|
int usecToSleep = BUFFER_SEND_INTERVAL_USECS;
|
||||||
|
|
||||||
|
@ -719,65 +720,90 @@ void AudioMixer::run() {
|
||||||
|
|
||||||
int streamsMixed = prepareMixForListeningNode(node.data());
|
int streamsMixed = prepareMixForListeningNode(node.data());
|
||||||
|
|
||||||
char* dataAt;
|
char* mixDataAt;
|
||||||
if (streamsMixed > 0) {
|
if (streamsMixed > 0) {
|
||||||
// pack header
|
// pack header
|
||||||
int numBytesPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeMixedAudio);
|
int numBytesMixPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeMixedAudio);
|
||||||
dataAt = clientMixBuffer + numBytesPacketHeader;
|
mixDataAt = clientMixBuffer + numBytesMixPacketHeader;
|
||||||
|
|
||||||
// pack sequence number
|
// pack sequence number
|
||||||
quint16 sequence = nodeData->getOutgoingSequenceNumber();
|
quint16 sequence = nodeData->getOutgoingSequenceNumber();
|
||||||
memcpy(dataAt, &sequence, sizeof(quint16));
|
memcpy(mixDataAt, &sequence, sizeof(quint16));
|
||||||
dataAt += sizeof(quint16);
|
mixDataAt += sizeof(quint16);
|
||||||
|
|
||||||
|
// pack mixed audio samples
|
||||||
|
memcpy(mixDataAt, _mixSamples, NETWORK_BUFFER_LENGTH_BYTES_STEREO);
|
||||||
|
mixDataAt += NETWORK_BUFFER_LENGTH_BYTES_STEREO;
|
||||||
|
|
||||||
// Pack stream properties
|
// Send stream properties
|
||||||
bool inAZone = false;
|
bool hasReverb = false;
|
||||||
|
float reverbTime, wetLevel;
|
||||||
|
// find reverb properties
|
||||||
for (int i = 0; i < _zoneReverbSettings.size(); ++i) {
|
for (int i = 0; i < _zoneReverbSettings.size(); ++i) {
|
||||||
AudioMixerClientData* data = static_cast<AudioMixerClientData*>(node->getLinkedData());
|
AudioMixerClientData* data = static_cast<AudioMixerClientData*>(node->getLinkedData());
|
||||||
glm::vec3 streamPosition = data->getAvatarAudioStream()->getPosition();
|
glm::vec3 streamPosition = data->getAvatarAudioStream()->getPosition();
|
||||||
if (_audioZones[_zoneReverbSettings[i].zone].contains(streamPosition)) {
|
if (_audioZones[_zoneReverbSettings[i].zone].contains(streamPosition)) {
|
||||||
bool hasReverb = true;
|
hasReverb = true;
|
||||||
float reverbTime = _zoneReverbSettings[i].reverbTime;
|
reverbTime = _zoneReverbSettings[i].reverbTime;
|
||||||
float wetLevel = _zoneReverbSettings[i].wetLevel;
|
wetLevel = _zoneReverbSettings[i].wetLevel;
|
||||||
|
|
||||||
memcpy(dataAt, &hasReverb, sizeof(bool));
|
|
||||||
dataAt += sizeof(bool);
|
|
||||||
memcpy(dataAt, &reverbTime, sizeof(float));
|
|
||||||
dataAt += sizeof(float);
|
|
||||||
memcpy(dataAt, &wetLevel, sizeof(float));
|
|
||||||
dataAt += sizeof(float);
|
|
||||||
|
|
||||||
inAZone = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!inAZone) {
|
AvatarAudioStream* stream = nodeData->getAvatarAudioStream();
|
||||||
bool hasReverb = false;
|
bool dataChanged = (stream->hasReverb() != hasReverb) ||
|
||||||
memcpy(dataAt, &hasReverb, sizeof(bool));
|
(stream->hasReverb() && (stream->getRevebTime() != reverbTime ||
|
||||||
dataAt += sizeof(bool);
|
stream->getWetLevel() != wetLevel));
|
||||||
|
if (dataChanged) {
|
||||||
|
// Update stream
|
||||||
|
if (hasReverb) {
|
||||||
|
stream->setReverb(reverbTime, wetLevel);
|
||||||
|
} else {
|
||||||
|
stream->clearReverb();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pack mixed audio samples
|
// Send at change or every so often
|
||||||
memcpy(dataAt, _mixSamples, NETWORK_BUFFER_LENGTH_BYTES_STEREO);
|
float CHANCE_OF_SEND = 0.01f;
|
||||||
dataAt += NETWORK_BUFFER_LENGTH_BYTES_STEREO;
|
bool sendData = dataChanged || (randFloat() < CHANCE_OF_SEND);
|
||||||
|
|
||||||
|
if (sendData) {
|
||||||
|
int numBytesEnvPacketHeader = populatePacketHeader(clientEnvBuffer, PacketTypeAudioEnvironment);
|
||||||
|
char* envDataAt = clientEnvBuffer + numBytesEnvPacketHeader;
|
||||||
|
|
||||||
|
unsigned char bitset = 0;
|
||||||
|
if (hasReverb) {
|
||||||
|
setAtBit(bitset, HAS_REVERB_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(envDataAt, &bitset, sizeof(unsigned char));
|
||||||
|
envDataAt += sizeof(unsigned char);
|
||||||
|
|
||||||
|
if (hasReverb) {
|
||||||
|
memcpy(envDataAt, &reverbTime, sizeof(float));
|
||||||
|
envDataAt += sizeof(float);
|
||||||
|
memcpy(envDataAt, &wetLevel, sizeof(float));
|
||||||
|
envDataAt += sizeof(float);
|
||||||
|
}
|
||||||
|
nodeList->writeDatagram(clientEnvBuffer, envDataAt - clientEnvBuffer, node);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// pack header
|
// pack header
|
||||||
int numBytesPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeSilentAudioFrame);
|
int numBytesPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeSilentAudioFrame);
|
||||||
dataAt = clientMixBuffer + numBytesPacketHeader;
|
mixDataAt = clientMixBuffer + numBytesPacketHeader;
|
||||||
|
|
||||||
// pack sequence number
|
// pack sequence number
|
||||||
quint16 sequence = nodeData->getOutgoingSequenceNumber();
|
quint16 sequence = nodeData->getOutgoingSequenceNumber();
|
||||||
memcpy(dataAt, &sequence, sizeof(quint16));
|
memcpy(mixDataAt, &sequence, sizeof(quint16));
|
||||||
dataAt += sizeof(quint16);
|
mixDataAt += sizeof(quint16);
|
||||||
|
|
||||||
// pack number of silent audio samples
|
// pack number of silent audio samples
|
||||||
quint16 numSilentSamples = NETWORK_BUFFER_LENGTH_SAMPLES_STEREO;
|
quint16 numSilentSamples = NETWORK_BUFFER_LENGTH_SAMPLES_STEREO;
|
||||||
memcpy(dataAt, &numSilentSamples, sizeof(quint16));
|
memcpy(mixDataAt, &numSilentSamples, sizeof(quint16));
|
||||||
dataAt += sizeof(quint16);
|
mixDataAt += sizeof(quint16);
|
||||||
}
|
}
|
||||||
|
|
||||||
// send mixed audio packet
|
// send mixed audio packet
|
||||||
nodeList->writeDatagram(clientMixBuffer, dataAt - clientMixBuffer, node);
|
nodeList->writeDatagram(clientMixBuffer, mixDataAt - clientMixBuffer, node);
|
||||||
nodeData->incrementOutgoingMixedAudioSequenceNumber();
|
nodeData->incrementOutgoingMixedAudioSequenceNumber();
|
||||||
|
|
||||||
// send an audio stream stats packet if it's time
|
// send an audio stream stats packet if it's time
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#include <QtCore/QTimer>
|
#include <QtCore/QTimer>
|
||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
|
|
||||||
#include <Logging.h>
|
#include <LogHandler.h>
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <Logging.h>
|
#include <LogHandler.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
|
||||||
#include "Assignment.h"
|
#include "Assignment.h"
|
||||||
|
@ -22,7 +22,7 @@ int main(int argc, char* argv[]) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// use the verbose message handler in Logging
|
// use the verbose message handler in Logging
|
||||||
qInstallMessageHandler(Logging::verboseMessageHandler);
|
qInstallMessageHandler(LogHandler::verboseMessageHandler);
|
||||||
|
|
||||||
const char* numForksString = getCmdOption(argc, (const char**)argv, NUM_FORKS_PARAMETER);
|
const char* numForksString = getCmdOption(argc, (const char**)argv, NUM_FORKS_PARAMETER);
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
#include <AccountManager.h>
|
#include <AccountManager.h>
|
||||||
#include <HTTPConnection.h>
|
#include <HTTPConnection.h>
|
||||||
#include <Logging.h>
|
#include <LogHandler.h>
|
||||||
#include <UUID.h>
|
#include <UUID.h>
|
||||||
|
|
||||||
#include "../AssignmentClient.h"
|
#include "../AssignmentClient.h"
|
||||||
|
@ -923,7 +923,7 @@ void OctreeServer::run() {
|
||||||
|
|
||||||
beforeRun(); // after payload has been processed
|
beforeRun(); // after payload has been processed
|
||||||
|
|
||||||
qInstallMessageHandler(Logging::verboseMessageHandler);
|
qInstallMessageHandler(LogHandler::verboseMessageHandler);
|
||||||
|
|
||||||
const char* STATUS_PORT = "--statusPort";
|
const char* STATUS_PORT = "--statusPort";
|
||||||
const char* statusPort = getCmdOption(_argc, _argv, STATUS_PORT);
|
const char* statusPort = getCmdOption(_argc, _argv, STATUS_PORT);
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
|
|
||||||
#include <Logging.h>
|
#include <LogHandler.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
|
||||||
#include "DomainServer.h"
|
#include "DomainServer.h"
|
||||||
|
@ -27,7 +27,7 @@ int main(int argc, char* argv[]) {
|
||||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
qInstallMessageHandler(Logging::verboseMessageHandler);
|
qInstallMessageHandler(LogHandler::verboseMessageHandler);
|
||||||
|
|
||||||
int currentExitCode = 0;
|
int currentExitCode = 0;
|
||||||
|
|
||||||
|
|
|
@ -143,6 +143,41 @@ EntityPropertyDialogBox = (function () {
|
||||||
array.push({ label: "Blue:", value: properties.color.blue });
|
array.push({ label: "Blue:", value: properties.color.blue });
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (properties.type == "Light") {
|
||||||
|
array.push({ label: "Light Properties:", type: "header" });
|
||||||
|
index++;
|
||||||
|
array.push({ label: "Is Spot Light:", value: properties.isSpotlight });
|
||||||
|
index++;
|
||||||
|
array.push({ label: "Diffuse Red:", value: properties.diffuseColor.red });
|
||||||
|
index++;
|
||||||
|
array.push({ label: "Diffuse Green:", value: properties.diffuseColor.green });
|
||||||
|
index++;
|
||||||
|
array.push({ label: "Diffuse Blue:", value: properties.diffuseColor.blue });
|
||||||
|
index++;
|
||||||
|
array.push({ label: "Ambient Red:", value: properties.ambientColor.red });
|
||||||
|
index++;
|
||||||
|
array.push({ label: "Ambient Green:", value: properties.ambientColor.green });
|
||||||
|
index++;
|
||||||
|
array.push({ label: "Ambient Blue:", value: properties.ambientColor.blue });
|
||||||
|
index++;
|
||||||
|
array.push({ label: "Specular Red:", value: properties.specularColor.red });
|
||||||
|
index++;
|
||||||
|
array.push({ label: "Specular Green:", value: properties.specularColor.green });
|
||||||
|
index++;
|
||||||
|
array.push({ label: "Specular Blue:", value: properties.specularColor.blue });
|
||||||
|
index++;
|
||||||
|
array.push({ label: "Constant Attenuation:", value: properties.constantAttenuation });
|
||||||
|
index++;
|
||||||
|
array.push({ label: "Linear Attenuation:", value: properties.linearAttenuation });
|
||||||
|
index++;
|
||||||
|
array.push({ label: "Quadratic Attenuation:", value: properties.quadraticAttenuation });
|
||||||
|
index++;
|
||||||
|
array.push({ label: "Exponent:", value: properties.exponent });
|
||||||
|
index++;
|
||||||
|
array.push({ label: "Cutoff (in degrees):", value: properties.cutoff });
|
||||||
|
index++;
|
||||||
|
}
|
||||||
array.push({ button: "Cancel" });
|
array.push({ button: "Cancel" });
|
||||||
index++;
|
index++;
|
||||||
|
|
||||||
|
@ -243,6 +278,25 @@ EntityPropertyDialogBox = (function () {
|
||||||
properties.color.green = array[index++].value;
|
properties.color.green = array[index++].value;
|
||||||
properties.color.blue = array[index++].value;
|
properties.color.blue = array[index++].value;
|
||||||
}
|
}
|
||||||
|
if (properties.type == "Light") {
|
||||||
|
index++; // skip header
|
||||||
|
properties.isSpotlight = array[index++].value;
|
||||||
|
properties.diffuseColor.red = array[index++].value;
|
||||||
|
properties.diffuseColor.green = array[index++].value;
|
||||||
|
properties.diffuseColor.blue = array[index++].value;
|
||||||
|
properties.ambientColor.red = array[index++].value;
|
||||||
|
properties.ambientColor.green = array[index++].value;
|
||||||
|
properties.ambientColor.blue = array[index++].value;
|
||||||
|
properties.specularColor.red = array[index++].value;
|
||||||
|
properties.specularColor.green = array[index++].value;
|
||||||
|
properties.specularColor.blue = array[index++].value;
|
||||||
|
properties.constantAttenuation = array[index++].value;
|
||||||
|
properties.linearAttenuation = array[index++].value;
|
||||||
|
properties.quadraticAttenuation = array[index++].value;
|
||||||
|
properties.exponent = array[index++].value;
|
||||||
|
properties.cutoff = array[index++].value;
|
||||||
|
}
|
||||||
|
|
||||||
Entities.editEntity(editModelID, properties);
|
Entities.editEntity(editModelID, properties);
|
||||||
selectionDisplay.select(editModelID, false);
|
selectionDisplay.select(editModelID, false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,15 @@ SPACE_WORLD = "world";
|
||||||
SelectionManager = (function() {
|
SelectionManager = (function() {
|
||||||
var that = {};
|
var that = {};
|
||||||
|
|
||||||
|
var PENDING_SELECTION_CHECK_INTERVAL = 50;
|
||||||
|
|
||||||
that.savedProperties = {};
|
that.savedProperties = {};
|
||||||
|
|
||||||
that.eventListener = null;
|
that.eventListener = null;
|
||||||
that.selections = [];
|
that.selections = [];
|
||||||
|
// These are selections that don't have a known ID yet
|
||||||
|
that.pendingSelections = [];
|
||||||
|
var pendingSelectionTimer = null;
|
||||||
|
|
||||||
that.localRotation = Quat.fromPitchYawRollDegrees(0, 0, 0);
|
that.localRotation = Quat.fromPitchYawRollDegrees(0, 0, 0);
|
||||||
that.localPosition = { x: 0, y: 0, z: 0 };
|
that.localPosition = { x: 0, y: 0, z: 0 };
|
||||||
|
@ -45,11 +50,58 @@ SelectionManager = (function() {
|
||||||
that.eventListener = func;
|
that.eventListener = func;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
that.hasSelection = function() {
|
||||||
|
return that.selections.length > 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
that.setSelections = function(entityIDs) {
|
||||||
|
that.selections = [];
|
||||||
|
for (var i = 0; i < entityIDs.length; i++) {
|
||||||
|
var entityID = entityIDs[i];
|
||||||
|
if (entityID.isKnownID) {
|
||||||
|
that.selections.push(entityID);
|
||||||
|
} else {
|
||||||
|
that.pendingSelections.push(entityID);
|
||||||
|
if (pendingSelectionTimer == null) {
|
||||||
|
pendingSelectionTimer = Script.setInterval(that._checkPendingSelections, PENDING_SELECTION_CHECK_INTERVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
that._update();
|
||||||
|
};
|
||||||
|
|
||||||
|
that._checkPendingSelections = function() {
|
||||||
|
for (var i = 0; i < that.pendingSelections.length; i++) {
|
||||||
|
var entityID = that.pendingSelections[i];
|
||||||
|
var newEntityID = Entities.identifyEntity(entityID);
|
||||||
|
if (newEntityID.isKnownID) {
|
||||||
|
that.pendingSelections.splice(i, 1);
|
||||||
|
that.addEntity(newEntityID);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (that.pendingSelections.length == 0) {
|
||||||
|
Script.clearInterval(pendingSelectionTimer);
|
||||||
|
pendingSelectionTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
that.addEntity = function(entityID) {
|
that.addEntity = function(entityID) {
|
||||||
print("Adding: " + entityID.id);
|
if (entityID.isKnownID) {
|
||||||
var idx = that.selections.indexOf(entityID);
|
var idx = that.selections.indexOf(entityID);
|
||||||
if (idx == -1) {
|
if (idx == -1) {
|
||||||
that.selections.push(entityID);
|
that.selections.push(entityID);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var idx = that.pendingSelections.indexOf(entityID);
|
||||||
|
if (idx == -1) {
|
||||||
|
that.pendingSelections.push(entityID);
|
||||||
|
if (pendingSelectionTimer == null) {
|
||||||
|
pendingSelectionTimer = Script.setInterval(that._checkPendingSelections, PENDING_SELECTION_CHECK_INTERVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
that._update();
|
that._update();
|
||||||
|
@ -61,11 +113,22 @@ SelectionManager = (function() {
|
||||||
that.selections.splice(idx, 1);
|
that.selections.splice(idx, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var idx = that.pendingSelections.indexOf(entityID);
|
||||||
|
if (idx >= 0) {
|
||||||
|
that.pendingSelections.splice(idx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
that._update();
|
that._update();
|
||||||
};
|
};
|
||||||
|
|
||||||
that.clearSelections = function() {
|
that.clearSelections = function() {
|
||||||
that.selections = [];
|
that.selections = [];
|
||||||
|
that.pendingSelections = [];
|
||||||
|
|
||||||
|
if (pendingSelectionTimer !== null) {
|
||||||
|
Script.clearInterval(pendingSelectionTimer);
|
||||||
|
pendingSelectionTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
that._update();
|
that._update();
|
||||||
};
|
};
|
||||||
|
@ -77,8 +140,6 @@ SelectionManager = (function() {
|
||||||
that.worldDimensions = null;
|
that.worldDimensions = null;
|
||||||
that.worldPosition = null;
|
that.worldPosition = null;
|
||||||
} else if (that.selections.length == 1) {
|
} else if (that.selections.length == 1) {
|
||||||
SelectionDisplay.setSpaceMode(SPACE_LOCAL);
|
|
||||||
|
|
||||||
var properties = Entities.getEntityProperties(that.selections[0]);
|
var properties = Entities.getEntityProperties(that.selections[0]);
|
||||||
that.localDimensions = properties.dimensions;
|
that.localDimensions = properties.dimensions;
|
||||||
that.localPosition = properties.position;
|
that.localPosition = properties.position;
|
||||||
|
@ -86,10 +147,9 @@ SelectionManager = (function() {
|
||||||
|
|
||||||
that.worldDimensions = properties.boundingBox.dimensions;
|
that.worldDimensions = properties.boundingBox.dimensions;
|
||||||
that.worldPosition = properties.boundingBox.center;
|
that.worldPosition = properties.boundingBox.center;
|
||||||
} else {
|
|
||||||
// For 1+ selections we can only modify selections in world space
|
|
||||||
SelectionDisplay.setSpaceMode(SPACE_WORLD);
|
|
||||||
|
|
||||||
|
SelectionDisplay.setSpaceMode(SPACE_LOCAL);
|
||||||
|
} else {
|
||||||
that.localRotation = null;
|
that.localRotation = null;
|
||||||
that.localDimensions = null;
|
that.localDimensions = null;
|
||||||
that.localPosition = null;
|
that.localPosition = null;
|
||||||
|
@ -122,6 +182,9 @@ SelectionManager = (function() {
|
||||||
y: brn.y + (that.worldDimensions.y / 2),
|
y: brn.y + (that.worldDimensions.y / 2),
|
||||||
z: brn.z + (that.worldDimensions.z / 2),
|
z: brn.z + (that.worldDimensions.z / 2),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// For 1+ selections we can only modify selections in world space
|
||||||
|
SelectionDisplay.setSpaceMode(SPACE_WORLD);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (that.eventListener) {
|
if (that.eventListener) {
|
||||||
|
@ -600,7 +663,7 @@ SelectionDisplay = (function () {
|
||||||
currentSelection = entityID;
|
currentSelection = entityID;
|
||||||
entitySelected = true;
|
entitySelected = true;
|
||||||
|
|
||||||
lastCameraPosition = Camera.getPosition();
|
// lastCameraPosition = Camera.getPosition();
|
||||||
lastCameraOrientation = Camera.getOrientation();
|
lastCameraOrientation = Camera.getOrientation();
|
||||||
|
|
||||||
if (event !== false) {
|
if (event !== false) {
|
||||||
|
@ -623,10 +686,15 @@ SelectionDisplay = (function () {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Entities.editEntity(entityID, { localRenderAlpha: 0.1 });
|
||||||
|
Overlays.editOverlay(highlightBox, { visible: false });
|
||||||
|
|
||||||
|
that.updateHandles();
|
||||||
|
}
|
||||||
|
|
||||||
|
that.updateRotationHandles = function() {
|
||||||
var diagonal = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1;
|
var diagonal = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1;
|
||||||
var halfDimensions = Vec3.multiply(selectionManager.worldDimensions, 0.5);
|
var halfDimensions = Vec3.multiply(selectionManager.worldDimensions, 0.5);
|
||||||
innerRadius = diagonal;
|
|
||||||
outerRadius = diagonal * 1.15;
|
|
||||||
var innerActive = false;
|
var innerActive = false;
|
||||||
var innerAlpha = 0.2;
|
var innerAlpha = 0.2;
|
||||||
var outerAlpha = 0.2;
|
var outerAlpha = 0.2;
|
||||||
|
@ -637,22 +705,18 @@ SelectionDisplay = (function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
var rotateHandleOffset = 0.05;
|
var rotateHandleOffset = 0.05;
|
||||||
var grabberMoveUpOffset = 0.1;
|
|
||||||
|
|
||||||
var top, far, left, bottom, near, right, boundsCenter, objectCenter, BLN, BRN, BLF, TLN, TRN, TLF, TRF;
|
var top, far, left, bottom, near, right, boundsCenter, objectCenter, BLN, BRN, BLF, TLN, TRN, TLF, TRF;
|
||||||
|
|
||||||
// objectCenter = { x: properties.position.x, y: properties.position.y, z: properties.position.z };
|
var dimensions, rotation;
|
||||||
|
|
||||||
var dimensions;
|
|
||||||
if (spaceMode == SPACE_LOCAL) {
|
if (spaceMode == SPACE_LOCAL) {
|
||||||
objectCenter = SelectionManager.localPosition;
|
rotation = SelectionManager.localRotation;
|
||||||
dimensions = SelectionManager.localDimensions;
|
|
||||||
} else {
|
} else {
|
||||||
objectCenter = SelectionManager.worldPosition;
|
rotation = SelectionManager.worldRotation;
|
||||||
dimensions = SelectionManager.worldDimensions;
|
|
||||||
}
|
}
|
||||||
objectCenter = SelectionManager.worldPosition;
|
objectCenter = SelectionManager.worldPosition;
|
||||||
dimensions = SelectionManager.worldDimensions;
|
dimensions = SelectionManager.worldDimensions;
|
||||||
|
var position = objectCenter;
|
||||||
|
|
||||||
top = objectCenter.y + (dimensions.y / 2);
|
top = objectCenter.y + (dimensions.y / 2);
|
||||||
far = objectCenter.z + (dimensions.z / 2);
|
far = objectCenter.z + (dimensions.z / 2);
|
||||||
|
@ -662,7 +726,6 @@ SelectionDisplay = (function () {
|
||||||
near = objectCenter.z - (dimensions.z / 2);
|
near = objectCenter.z - (dimensions.z / 2);
|
||||||
right = objectCenter.x - (dimensions.x / 2);
|
right = objectCenter.x - (dimensions.x / 2);
|
||||||
|
|
||||||
// boundsCenter = { x: properties.boundingBox.center.x, y: properties.boundingBox.center.y, z: properties.boundingBox.center.z };
|
|
||||||
boundsCenter = objectCenter;
|
boundsCenter = objectCenter;
|
||||||
|
|
||||||
var yawCorner;
|
var yawCorner;
|
||||||
|
@ -812,10 +875,12 @@ SelectionDisplay = (function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
var rotateHandlesVisible = true;
|
var rotateHandlesVisible = true;
|
||||||
|
var rotationOverlaysVisible = false;
|
||||||
var translateHandlesVisible = true;
|
var translateHandlesVisible = true;
|
||||||
var stretchHandlesVisible = true;
|
var stretchHandlesVisible = true;
|
||||||
var selectionBoxVisible = true;
|
var selectionBoxVisible = true;
|
||||||
if (mode == "ROTATE_YAW" || mode == "ROTATE_PITCH" || mode == "ROTATE_ROLL" || mode == "TRANSLATE_X in case they Z") {
|
if (mode == "ROTATE_YAW" || mode == "ROTATE_PITCH" || mode == "ROTATE_ROLL" || mode == "TRANSLATE_X in case they Z") {
|
||||||
|
rotationOverlaysVisible = true;
|
||||||
rotateHandlesVisible = false;
|
rotateHandlesVisible = false;
|
||||||
translateHandlesVisible = false;
|
translateHandlesVisible = false;
|
||||||
stretchHandlesVisible = false;
|
stretchHandlesVisible = false;
|
||||||
|
@ -828,77 +893,33 @@ SelectionDisplay = (function () {
|
||||||
rotateHandlesVisible = false;
|
rotateHandlesVisible = false;
|
||||||
translateHandlesVisible = false;
|
translateHandlesVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Overlays.editOverlay(highlightBox, { visible: false });
|
|
||||||
|
|
||||||
var dimensions, rotation, position;
|
var rotation = SelectionManager.worldRotation;
|
||||||
if (spaceMode == SPACE_LOCAL) {
|
var dimensions = SelectionManager.worldDimensions;
|
||||||
rotation = SelectionManager.localRotation;
|
var position = SelectionManager.worldPosition;
|
||||||
dimensions = SelectionManager.localDimensions;
|
|
||||||
position = SelectionManager.localPosition;
|
|
||||||
} else {
|
|
||||||
rotation = SelectionManager.worldRotation;
|
|
||||||
dimensions = SelectionManager.worldDimensions;
|
|
||||||
position = SelectionManager.worldPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
Overlays.editOverlay(grabberMoveUp, { visible: translateHandlesVisible, position: { x: boundsCenter.x, y: top + grabberMoveUpOffset, z: boundsCenter.z } });
|
|
||||||
|
|
||||||
that.updateHandles();
|
|
||||||
|
|
||||||
|
|
||||||
Overlays.editOverlay(baseOfEntityProjectionOverlay,
|
Overlays.editOverlay(baseOfEntityProjectionOverlay,
|
||||||
{
|
{
|
||||||
visible: true,
|
visible: true,
|
||||||
solid:true,
|
solid:true,
|
||||||
lineWidth: 2.0,
|
lineWidth: 2.0,
|
||||||
position: { x: properties.position.x,
|
position: { x: position.x,
|
||||||
y: 0,
|
y: 0,
|
||||||
z: properties.position.z },
|
z: position.z },
|
||||||
|
|
||||||
dimensions: { x: properties.dimensions.x, y: properties.dimensions.z },
|
dimensions: { x: dimensions.x, y: 0, z: dimensions.z },
|
||||||
rotation: properties.rotation,
|
rotation: rotation,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
Overlays.editOverlay(rotateOverlayTarget, { visible: false });
|
Overlays.editOverlay(rotateOverlayTarget, { visible: rotationOverlaysVisible });
|
||||||
|
Overlays.editOverlay(rotateZeroOverlay, { visible: rotationOverlaysVisible });
|
||||||
Overlays.editOverlay(rotateOverlayInner,
|
Overlays.editOverlay(rotateCurrentOverlay, { visible: rotationOverlaysVisible });
|
||||||
{
|
|
||||||
visible: false,
|
|
||||||
size: innerRadius,
|
|
||||||
innerRadius: 0.9,
|
|
||||||
alpha: innerAlpha
|
|
||||||
});
|
|
||||||
|
|
||||||
Overlays.editOverlay(rotateOverlayOuter,
|
|
||||||
{
|
|
||||||
visible: false,
|
|
||||||
size: outerRadius,
|
|
||||||
innerRadius: 0.9,
|
|
||||||
startAt: 0,
|
|
||||||
endAt: 360,
|
|
||||||
alpha: outerAlpha,
|
|
||||||
});
|
|
||||||
|
|
||||||
Overlays.editOverlay(rotateOverlayCurrent,
|
|
||||||
{
|
|
||||||
visible: false,
|
|
||||||
size: outerRadius,
|
|
||||||
startAt: 0,
|
|
||||||
endAt: 0,
|
|
||||||
innerRadius: 0.9,
|
|
||||||
});
|
|
||||||
|
|
||||||
Overlays.editOverlay(rotateZeroOverlay, { visible: false });
|
|
||||||
Overlays.editOverlay(rotateCurrentOverlay, { visible: false });
|
|
||||||
|
|
||||||
// TODO: we have not implemented the rotating handle/controls yet... so for now, these handles are hidden
|
// TODO: we have not implemented the rotating handle/controls yet... so for now, these handles are hidden
|
||||||
Overlays.editOverlay(yawHandle, { visible: rotateHandlesVisible, position: yawCorner, rotation: yawHandleRotation});
|
Overlays.editOverlay(yawHandle, { visible: rotateHandlesVisible, position: yawCorner, rotation: yawHandleRotation});
|
||||||
Overlays.editOverlay(pitchHandle, { visible: rotateHandlesVisible, position: pitchCorner, rotation: pitchHandleRotation});
|
Overlays.editOverlay(pitchHandle, { visible: rotateHandlesVisible, position: pitchCorner, rotation: pitchHandleRotation});
|
||||||
Overlays.editOverlay(rollHandle, { visible: rotateHandlesVisible, position: rollCorner, rotation: rollHandleRotation});
|
Overlays.editOverlay(rollHandle, { visible: rotateHandlesVisible, position: rollCorner, rotation: rollHandleRotation});
|
||||||
|
|
||||||
Entities.editEntity(entityID, { localRenderAlpha: 0.1 });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
that.setSpaceMode = function(newSpaceMode) {
|
that.setSpaceMode = function(newSpaceMode) {
|
||||||
|
@ -931,6 +952,8 @@ SelectionDisplay = (function () {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
that.updateRotationHandles();
|
||||||
|
|
||||||
var rotation, dimensions, position;
|
var rotation, dimensions, position;
|
||||||
|
|
||||||
if (spaceMode == SPACE_LOCAL) {
|
if (spaceMode == SPACE_LOCAL) {
|
||||||
|
@ -945,12 +968,14 @@ SelectionDisplay = (function () {
|
||||||
|
|
||||||
var halfDimensions = Vec3.multiply(0.5, dimensions);
|
var halfDimensions = Vec3.multiply(0.5, dimensions);
|
||||||
|
|
||||||
left = -halfDimensions.x;
|
var left = -halfDimensions.x;
|
||||||
right = halfDimensions.x;
|
var right = halfDimensions.x;
|
||||||
top = halfDimensions.y;
|
var top = halfDimensions.y;
|
||||||
bottom = -halfDimensions.y;
|
var bottom = -halfDimensions.y;
|
||||||
var front = far = halfDimensions.z;
|
var front = far = halfDimensions.z;
|
||||||
near = -halfDimensions.z;
|
var near = -halfDimensions.z;
|
||||||
|
|
||||||
|
var worldTop = SelectionManager.worldDimensions.y / 2;
|
||||||
|
|
||||||
var LBN = { x: left, y: bottom, z: near };
|
var LBN = { x: left, y: bottom, z: near };
|
||||||
var RBN = { x: right, y: bottom, z: near };
|
var RBN = { x: right, y: bottom, z: near };
|
||||||
|
@ -1060,7 +1085,7 @@ SelectionDisplay = (function () {
|
||||||
position: position,
|
position: position,
|
||||||
dimensions: dimensions,
|
dimensions: dimensions,
|
||||||
rotation: rotation,
|
rotation: rotation,
|
||||||
visible: true,
|
visible: !(mode == "ROTATE_YAW" || mode == "ROTATE_PITCH" || mode == "ROTATE_ROLL"),
|
||||||
});
|
});
|
||||||
|
|
||||||
Overlays.editOverlay(grabberEdgeTR, { visible: stretchHandlesVisible, rotation: rotation, position: EdgeTR });
|
Overlays.editOverlay(grabberEdgeTR, { visible: stretchHandlesVisible, rotation: rotation, position: EdgeTR });
|
||||||
|
@ -1076,6 +1101,8 @@ SelectionDisplay = (function () {
|
||||||
Overlays.editOverlay(grabberEdgeFR, { visible: stretchHandlesVisible, rotation: rotation, position: EdgeFR });
|
Overlays.editOverlay(grabberEdgeFR, { visible: stretchHandlesVisible, rotation: rotation, position: EdgeFR });
|
||||||
Overlays.editOverlay(grabberEdgeFL, { visible: stretchHandlesVisible, rotation: rotation, position: EdgeFL });
|
Overlays.editOverlay(grabberEdgeFL, { visible: stretchHandlesVisible, rotation: rotation, position: EdgeFL });
|
||||||
|
|
||||||
|
var grabberMoveUpOffset = 0.1;
|
||||||
|
Overlays.editOverlay(grabberMoveUp, { visible: activeTool == null || mode == "TRANSLATE_UP_DOWN", position: { x: position.x, y: position.y + worldTop + grabberMoveUpOffset, z: position.z } });
|
||||||
};
|
};
|
||||||
|
|
||||||
that.setOverlaysVisible = function(isVisible) {
|
that.setOverlaysVisible = function(isVisible) {
|
||||||
|
@ -1094,47 +1121,10 @@ SelectionDisplay = (function () {
|
||||||
entitySelected = false;
|
entitySelected = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
function applyEntityProperties(data) {
|
|
||||||
for (var i = 0; i < data.length; i++) {
|
|
||||||
var entityID = data[i].entityID;
|
|
||||||
var properties = data[i].properties;
|
|
||||||
Entities.editEntity(entityID, properties);
|
|
||||||
}
|
|
||||||
selectionManager._update();
|
|
||||||
};
|
|
||||||
|
|
||||||
// For currently selected entities, push a command to the UndoStack that uses the current entity properties for the
|
|
||||||
// redo command, and the saved properties for the undo command.
|
|
||||||
function pushCommandForSelections() {
|
|
||||||
var undoData = [];
|
|
||||||
var redoData = [];
|
|
||||||
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
|
||||||
var entityID = SelectionManager.selections[i];
|
|
||||||
var initialProperties = SelectionManager.savedProperties[entityID.id];
|
|
||||||
var currentProperties = Entities.getEntityProperties(entityID);
|
|
||||||
undoData.push({
|
|
||||||
entityID: entityID,
|
|
||||||
properties: {
|
|
||||||
position: initialProperties.position,
|
|
||||||
rotation: initialProperties.rotation,
|
|
||||||
dimensions: initialProperties.dimensions,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
redoData.push({
|
|
||||||
entityID: entityID,
|
|
||||||
properties: {
|
|
||||||
position: currentProperties.position,
|
|
||||||
rotation: currentProperties.rotation,
|
|
||||||
dimensions: currentProperties.dimensions,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
UndoStack.pushCommand(applyEntityProperties, undoData, applyEntityProperties, redoData);
|
|
||||||
}
|
|
||||||
|
|
||||||
var initialXZPick = null;
|
var initialXZPick = null;
|
||||||
var isConstrained = false;
|
var isConstrained = false;
|
||||||
var startPosition = null;
|
var startPosition = null;
|
||||||
|
var duplicatedEntityIDs = null;
|
||||||
var translateXZTool = {
|
var translateXZTool = {
|
||||||
mode: 'TRANSLATE_XZ',
|
mode: 'TRANSLATE_XZ',
|
||||||
onBegin: function(event) {
|
onBegin: function(event) {
|
||||||
|
@ -1149,43 +1139,32 @@ SelectionDisplay = (function () {
|
||||||
// copy of the selected entities and move the _original_ entities, not
|
// copy of the selected entities and move the _original_ entities, not
|
||||||
// the new ones.
|
// the new ones.
|
||||||
if (event.isAlt) {
|
if (event.isAlt) {
|
||||||
|
duplicatedEntityIDs = [];
|
||||||
for (var otherEntityID in SelectionManager.savedProperties) {
|
for (var otherEntityID in SelectionManager.savedProperties) {
|
||||||
var properties = SelectionManager.savedProperties[otherEntityID];
|
var properties = SelectionManager.savedProperties[otherEntityID];
|
||||||
var entityID = Entities.addEntity(properties);
|
var entityID = Entities.addEntity(properties);
|
||||||
|
duplicatedEntityIDs.push({
|
||||||
|
entityID: entityID,
|
||||||
|
properties: properties,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
duplicatedEntityIDs = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstrained = false;
|
isConstrained = false;
|
||||||
},
|
},
|
||||||
onEnd: function(event, reason) {
|
onEnd: function(event, reason) {
|
||||||
if (reason == 'cancel') {
|
pushCommandForSelections(duplicatedEntityIDs);
|
||||||
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
|
||||||
var entityID = SelectionManager.selections[i];
|
|
||||||
var initialProperties = SelectionManager.savedProperties[entityID.id];
|
|
||||||
Entities.editEntity(entityID, initialProperties);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pushCommandForSelections();
|
|
||||||
}
|
|
||||||
Overlays.editOverlay(xRailOverlay, { visible: false });
|
Overlays.editOverlay(xRailOverlay, { visible: false });
|
||||||
Overlays.editOverlay(zRailOverlay, { visible: false });
|
Overlays.editOverlay(zRailOverlay, { visible: false });
|
||||||
},
|
},
|
||||||
onMove: function(event) {
|
onMove: function(event) {
|
||||||
if (!entitySelected || mode !== "TRANSLATE_XZ") {
|
|
||||||
return; // not allowed
|
|
||||||
}
|
|
||||||
|
|
||||||
pickRay = Camera.computePickRay(event.x, event.y);
|
pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
|
|
||||||
// translate mode left/right based on view toward entity
|
|
||||||
var newIntersection = rayPlaneIntersection(pickRay,
|
|
||||||
selectedEntityPropertiesOriginalPosition,
|
|
||||||
Quat.getFront(lastCameraOrientation));
|
|
||||||
|
|
||||||
var vector = Vec3.subtract(newIntersection, lastPlaneIntersection);
|
|
||||||
var pick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, { x: 0, y: 1, z: 0 });
|
var pick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, { x: 0, y: 1, z: 0 });
|
||||||
var vector = Vec3.subtract(pick, initialXZPick);
|
var vector = Vec3.subtract(pick, initialXZPick);
|
||||||
// initialXZPick = pick;
|
|
||||||
|
|
||||||
// If shifted, constrain to one axis
|
// If shifted, constrain to one axis
|
||||||
if (event.isShifted) {
|
if (event.isShifted) {
|
||||||
|
@ -1222,7 +1201,6 @@ SelectionDisplay = (function () {
|
||||||
if (wantDebug) {
|
if (wantDebug) {
|
||||||
print("translateXZ... ");
|
print("translateXZ... ");
|
||||||
Vec3.print(" lastPlaneIntersection:", lastPlaneIntersection);
|
Vec3.print(" lastPlaneIntersection:", lastPlaneIntersection);
|
||||||
Vec3.print(" newIntersection:", newIntersection);
|
|
||||||
Vec3.print(" vector:", vector);
|
Vec3.print(" vector:", vector);
|
||||||
Vec3.print(" newPosition:", properties.position);
|
Vec3.print(" newPosition:", properties.position);
|
||||||
Vec3.print(" newPosition:", newPosition);
|
Vec3.print(" newPosition:", newPosition);
|
||||||
|
@ -1239,22 +1217,28 @@ SelectionDisplay = (function () {
|
||||||
mode: "TRANSLATE_UP_DOWN",
|
mode: "TRANSLATE_UP_DOWN",
|
||||||
onBegin: function(event) {
|
onBegin: function(event) {
|
||||||
SelectionManager.saveProperties();
|
SelectionManager.saveProperties();
|
||||||
},
|
|
||||||
onEnd: function(event, reason) {
|
// Duplicate entities if alt is pressed. This will make a
|
||||||
if (reason == 'cancel') {
|
// copy of the selected entities and move the _original_ entities, not
|
||||||
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
// the new ones.
|
||||||
var entityID = SelectionManager.selections[i];
|
if (event.isAlt) {
|
||||||
var initialProperties = SelectionManager.savedProperties[entityID.id];
|
duplicatedEntityIDs = [];
|
||||||
Entities.editEntity(entityID, initialProperties);
|
for (var otherEntityID in SelectionManager.savedProperties) {
|
||||||
|
var properties = SelectionManager.savedProperties[otherEntityID];
|
||||||
|
var entityID = Entities.addEntity(properties);
|
||||||
|
duplicatedEntityIDs.push({
|
||||||
|
entityID: entityID,
|
||||||
|
properties: properties,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pushCommandForSelections();
|
duplicatedEntityIDs = null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onEnd: function(event, reason) {
|
||||||
|
pushCommandForSelections(duplicatedEntityIDs);
|
||||||
|
},
|
||||||
onMove: function(event) {
|
onMove: function(event) {
|
||||||
if (!entitySelected || mode !== "TRANSLATE_UP_DOWN") {
|
|
||||||
return; // not allowed
|
|
||||||
}
|
|
||||||
pickRay = Camera.computePickRay(event.x, event.y);
|
pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
|
|
||||||
// translate mode left/right based on view toward entity
|
// translate mode left/right based on view toward entity
|
||||||
|
@ -1403,21 +1387,10 @@ SelectionDisplay = (function () {
|
||||||
Overlays.editOverlay(yRailOverlay, { visible: false });
|
Overlays.editOverlay(yRailOverlay, { visible: false });
|
||||||
Overlays.editOverlay(zRailOverlay, { visible: false });
|
Overlays.editOverlay(zRailOverlay, { visible: false });
|
||||||
|
|
||||||
if (reason == 'cancel') {
|
pushCommandForSelections();
|
||||||
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
|
||||||
var entityID = SelectionManager.selections[i];
|
|
||||||
var initialProperties = SelectionManager.savedProperties[entityID.id];
|
|
||||||
Entities.editEntity(entityID, initialProperties);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pushCommandForSelections();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var onMove = function(event) {
|
var onMove = function(event) {
|
||||||
if (!entitySelected || mode !== stretchMode) {
|
|
||||||
return; // not allowed
|
|
||||||
}
|
|
||||||
var proportional = spaceMode == SPACE_WORLD || event.isShifted;
|
var proportional = spaceMode == SPACE_WORLD || event.isShifted;
|
||||||
|
|
||||||
var position, dimensions, rotation;
|
var position, dimensions, rotation;
|
||||||
|
@ -1510,14 +1483,6 @@ SelectionDisplay = (function () {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
that.cancelTool = function() {
|
|
||||||
if (activeTool) {
|
|
||||||
activeTool.onEnd(null, 'cancel');
|
|
||||||
activeTool = null;
|
|
||||||
SelectionManager._update();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function addStretchTool(overlay, mode, pivot, direction) {
|
function addStretchTool(overlay, mode, pivot, direction) {
|
||||||
if (!pivot) {
|
if (!pivot) {
|
||||||
pivot = Vec3.multiply(-1, direction);
|
pivot = Vec3.multiply(-1, direction);
|
||||||
|
@ -1563,23 +1528,49 @@ SelectionDisplay = (function () {
|
||||||
onBegin: function(event) {
|
onBegin: function(event) {
|
||||||
SelectionManager.saveProperties();
|
SelectionManager.saveProperties();
|
||||||
initialPosition = SelectionManager.worldPosition;
|
initialPosition = SelectionManager.worldPosition;
|
||||||
|
|
||||||
|
// Size the overlays to the current selection size
|
||||||
|
var diagonal = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1;
|
||||||
|
var halfDimensions = Vec3.multiply(selectionManager.worldDimensions, 0.5);
|
||||||
|
innerRadius = diagonal;
|
||||||
|
outerRadius = diagonal * 1.15;
|
||||||
|
var innerAlpha = 0.2;
|
||||||
|
var outerAlpha = 0.2;
|
||||||
|
Overlays.editOverlay(rotateOverlayInner,
|
||||||
|
{
|
||||||
|
visible: true,
|
||||||
|
size: innerRadius,
|
||||||
|
innerRadius: 0.9,
|
||||||
|
alpha: innerAlpha
|
||||||
|
});
|
||||||
|
|
||||||
|
Overlays.editOverlay(rotateOverlayOuter,
|
||||||
|
{
|
||||||
|
visible: true,
|
||||||
|
size: outerRadius,
|
||||||
|
innerRadius: 0.9,
|
||||||
|
startAt: 0,
|
||||||
|
endAt: 360,
|
||||||
|
alpha: outerAlpha,
|
||||||
|
});
|
||||||
|
|
||||||
|
Overlays.editOverlay(rotateOverlayCurrent,
|
||||||
|
{
|
||||||
|
visible: true,
|
||||||
|
size: outerRadius,
|
||||||
|
startAt: 0,
|
||||||
|
endAt: 0,
|
||||||
|
innerRadius: 0.9,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
onEnd: function(event, reason) {
|
onEnd: function(event, reason) {
|
||||||
if (reason == 'cancel') {
|
Overlays.editOverlay(rotateOverlayInner, { visible: false });
|
||||||
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
Overlays.editOverlay(rotateOverlayOuter, { visible: false });
|
||||||
var entityID = SelectionManager.selections[i];
|
Overlays.editOverlay(rotateOverlayCurrent, { visible: false });
|
||||||
var initialProperties = SelectionManager.savedProperties[entityID.id];
|
|
||||||
Entities.editEntity(entityID, initialProperties);
|
pushCommandForSelections();
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pushCommandForSelections();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
onMove: function(event) {
|
onMove: function(event) {
|
||||||
if (!entitySelected || mode !== "ROTATE_YAW") {
|
|
||||||
return; // not allowed
|
|
||||||
}
|
|
||||||
|
|
||||||
var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems");
|
var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems");
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
|
@ -1591,9 +1582,6 @@ SelectionDisplay = (function () {
|
||||||
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 });
|
||||||
Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false });
|
Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false });
|
||||||
Overlays.editOverlay(rotateOverlayInner, { ignoreRayIntersection: true });
|
|
||||||
Overlays.editOverlay(rotateOverlayOuter, { ignoreRayIntersection: true });
|
|
||||||
Overlays.editOverlay(rotateOverlayCurrent, { ignoreRayIntersection: true });
|
|
||||||
|
|
||||||
var result = Overlays.findRayIntersection(pickRay);
|
var result = Overlays.findRayIntersection(pickRay);
|
||||||
|
|
||||||
|
@ -1611,6 +1599,7 @@ SelectionDisplay = (function () {
|
||||||
|
|
||||||
var distanceFromCenter = Vec3.distance(center, result.intersection);
|
var distanceFromCenter = Vec3.distance(center, result.intersection);
|
||||||
var snapToInner = false;
|
var snapToInner = false;
|
||||||
|
// var innerRadius = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1;
|
||||||
if (distanceFromCenter < innerRadius) {
|
if (distanceFromCenter < innerRadius) {
|
||||||
angleFromZero = Math.floor(angleFromZero/innerSnapAngle) * innerSnapAngle;
|
angleFromZero = Math.floor(angleFromZero/innerSnapAngle) * innerSnapAngle;
|
||||||
snapToInner = true;
|
snapToInner = true;
|
||||||
|
@ -1671,22 +1660,49 @@ SelectionDisplay = (function () {
|
||||||
onBegin: function(event) {
|
onBegin: function(event) {
|
||||||
SelectionManager.saveProperties();
|
SelectionManager.saveProperties();
|
||||||
initialPosition = SelectionManager.worldPosition;
|
initialPosition = SelectionManager.worldPosition;
|
||||||
|
|
||||||
|
// Size the overlays to the current selection size
|
||||||
|
var diagonal = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1;
|
||||||
|
var halfDimensions = Vec3.multiply(selectionManager.worldDimensions, 0.5);
|
||||||
|
var innerRadius = diagonal;
|
||||||
|
var outerRadius = diagonal * 1.15;
|
||||||
|
var innerAlpha = 0.2;
|
||||||
|
var outerAlpha = 0.2;
|
||||||
|
Overlays.editOverlay(rotateOverlayInner,
|
||||||
|
{
|
||||||
|
visible: true,
|
||||||
|
size: innerRadius,
|
||||||
|
innerRadius: 0.9,
|
||||||
|
alpha: innerAlpha
|
||||||
|
});
|
||||||
|
|
||||||
|
Overlays.editOverlay(rotateOverlayOuter,
|
||||||
|
{
|
||||||
|
visible: true,
|
||||||
|
size: outerRadius,
|
||||||
|
innerRadius: 0.9,
|
||||||
|
startAt: 0,
|
||||||
|
endAt: 360,
|
||||||
|
alpha: outerAlpha,
|
||||||
|
});
|
||||||
|
|
||||||
|
Overlays.editOverlay(rotateOverlayCurrent,
|
||||||
|
{
|
||||||
|
visible: true,
|
||||||
|
size: outerRadius,
|
||||||
|
startAt: 0,
|
||||||
|
endAt: 0,
|
||||||
|
innerRadius: 0.9,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
onEnd: function(event, reason) {
|
onEnd: function(event, reason) {
|
||||||
if (reason == 'cancel') {
|
Overlays.editOverlay(rotateOverlayInner, { visible: false });
|
||||||
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
Overlays.editOverlay(rotateOverlayOuter, { visible: false });
|
||||||
var entityID = SelectionManager.selections[i];
|
Overlays.editOverlay(rotateOverlayCurrent, { visible: false });
|
||||||
var initialProperties = SelectionManager.savedProperties[entityID.id];
|
|
||||||
Entities.editEntity(entityID, initialProperties);
|
pushCommandForSelections();
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pushCommandForSelections();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
onMove: function(event) {
|
onMove: function(event) {
|
||||||
if (!entitySelected || mode !== "ROTATE_PITCH") {
|
|
||||||
return; // not allowed
|
|
||||||
}
|
|
||||||
var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems");
|
var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems");
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
|
@ -1698,9 +1714,6 @@ SelectionDisplay = (function () {
|
||||||
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 });
|
||||||
Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false });
|
Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false });
|
||||||
Overlays.editOverlay(rotateOverlayInner, { ignoreRayIntersection: true });
|
|
||||||
Overlays.editOverlay(rotateOverlayOuter, { ignoreRayIntersection: true });
|
|
||||||
Overlays.editOverlay(rotateOverlayCurrent, { ignoreRayIntersection: true });
|
|
||||||
var result = Overlays.findRayIntersection(pickRay);
|
var result = Overlays.findRayIntersection(pickRay);
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
|
@ -1777,22 +1790,49 @@ SelectionDisplay = (function () {
|
||||||
onBegin: function(event) {
|
onBegin: function(event) {
|
||||||
SelectionManager.saveProperties();
|
SelectionManager.saveProperties();
|
||||||
initialPosition = SelectionManager.worldPosition;
|
initialPosition = SelectionManager.worldPosition;
|
||||||
|
|
||||||
|
// Size the overlays to the current selection size
|
||||||
|
var diagonal = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1;
|
||||||
|
var halfDimensions = Vec3.multiply(selectionManager.worldDimensions, 0.5);
|
||||||
|
var innerRadius = diagonal;
|
||||||
|
var outerRadius = diagonal * 1.15;
|
||||||
|
var innerAlpha = 0.2;
|
||||||
|
var outerAlpha = 0.2;
|
||||||
|
Overlays.editOverlay(rotateOverlayInner,
|
||||||
|
{
|
||||||
|
visible: true,
|
||||||
|
size: innerRadius,
|
||||||
|
innerRadius: 0.9,
|
||||||
|
alpha: innerAlpha
|
||||||
|
});
|
||||||
|
|
||||||
|
Overlays.editOverlay(rotateOverlayOuter,
|
||||||
|
{
|
||||||
|
visible: true,
|
||||||
|
size: outerRadius,
|
||||||
|
innerRadius: 0.9,
|
||||||
|
startAt: 0,
|
||||||
|
endAt: 360,
|
||||||
|
alpha: outerAlpha,
|
||||||
|
});
|
||||||
|
|
||||||
|
Overlays.editOverlay(rotateOverlayCurrent,
|
||||||
|
{
|
||||||
|
visible: true,
|
||||||
|
size: outerRadius,
|
||||||
|
startAt: 0,
|
||||||
|
endAt: 0,
|
||||||
|
innerRadius: 0.9,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
onEnd: function(event, reason) {
|
onEnd: function(event, reason) {
|
||||||
if (reason == 'cancel') {
|
Overlays.editOverlay(rotateOverlayInner, { visible: false });
|
||||||
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
Overlays.editOverlay(rotateOverlayOuter, { visible: false });
|
||||||
var entityID = SelectionManager.selections[i];
|
Overlays.editOverlay(rotateOverlayCurrent, { visible: false });
|
||||||
var initialProperties = SelectionManager.savedProperties[entityID.id];
|
|
||||||
Entities.editEntity(entityID, initialProperties);
|
pushCommandForSelections();
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pushCommandForSelections();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
onMove: function(event) {
|
onMove: function(event) {
|
||||||
if (!entitySelected || mode !== "ROTATE_ROLL") {
|
|
||||||
return; // not allowed
|
|
||||||
}
|
|
||||||
var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems");
|
var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems");
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
|
@ -1804,9 +1844,6 @@ SelectionDisplay = (function () {
|
||||||
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 });
|
||||||
Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false });
|
Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false });
|
||||||
Overlays.editOverlay(rotateOverlayInner, { ignoreRayIntersection: true });
|
|
||||||
Overlays.editOverlay(rotateOverlayOuter, { ignoreRayIntersection: true });
|
|
||||||
Overlays.editOverlay(rotateOverlayCurrent, { ignoreRayIntersection: true });
|
|
||||||
var result = Overlays.findRayIntersection(pickRay);
|
var result = Overlays.findRayIntersection(pickRay);
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//
|
|
||||||
// newEditEntities.js
|
// newEditEntities.js
|
||||||
// examples
|
// examples
|
||||||
//
|
//
|
||||||
|
@ -73,6 +73,7 @@ var toolBar = (function () {
|
||||||
newModelButton,
|
newModelButton,
|
||||||
newCubeButton,
|
newCubeButton,
|
||||||
newSphereButton,
|
newSphereButton,
|
||||||
|
newLightButton,
|
||||||
browseModelsButton,
|
browseModelsButton,
|
||||||
loadURLMenuItem,
|
loadURLMenuItem,
|
||||||
loadFileMenuItem,
|
loadFileMenuItem,
|
||||||
|
@ -157,6 +158,15 @@ var toolBar = (function () {
|
||||||
visible: true
|
visible: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
newLightButton = toolBar.addTool({
|
||||||
|
imageURL: toolIconUrl + "light.svg",
|
||||||
|
subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
||||||
|
width: toolWidth,
|
||||||
|
height: toolHeight,
|
||||||
|
alpha: 0.9,
|
||||||
|
visible: true
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleNewModelButton(active) {
|
function toggleNewModelButton(active) {
|
||||||
|
@ -272,7 +282,7 @@ var toolBar = (function () {
|
||||||
toggleNewModelButton(false);
|
toggleNewModelButton(false);
|
||||||
|
|
||||||
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)");
|
||||||
//"Model files (*.fst *.fbx *.svo)");
|
//"Model files (*.fst *.fbx *.svo)");
|
||||||
if (file !== null) {
|
if (file !== null) {
|
||||||
|
@ -295,7 +305,7 @@ var toolBar = (function () {
|
||||||
var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE));
|
var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE));
|
||||||
|
|
||||||
if (position.x > 0 && position.y > 0 && position.z > 0) {
|
if (position.x > 0 && position.y > 0 && position.z > 0) {
|
||||||
Entities.addEntity({
|
Entities.addEntity({
|
||||||
type: "Box",
|
type: "Box",
|
||||||
position: position,
|
position: position,
|
||||||
dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION },
|
dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION },
|
||||||
|
@ -312,14 +322,39 @@ var toolBar = (function () {
|
||||||
var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE));
|
var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE));
|
||||||
|
|
||||||
if (position.x > 0 && position.y > 0 && position.z > 0) {
|
if (position.x > 0 && position.y > 0 && position.z > 0) {
|
||||||
Entities.addEntity({
|
Entities.addEntity({
|
||||||
type: "Sphere",
|
type: "Sphere",
|
||||||
position: position,
|
position: position,
|
||||||
dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION },
|
dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION },
|
||||||
color: { red: 255, green: 0, blue: 0 }
|
color: { red: 255, green: 0, blue: 0 }
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
print("Can't create box: Box would be out of bounds.");
|
print("Can't create sphere: Sphere would be out of bounds.");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newLightButton === toolBar.clicked(clickedOverlay)) {
|
||||||
|
var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE));
|
||||||
|
|
||||||
|
if (position.x > 0 && position.y > 0 && position.z > 0) {
|
||||||
|
Entities.addEntity({
|
||||||
|
type: "Light",
|
||||||
|
position: position,
|
||||||
|
dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION },
|
||||||
|
isSpotlight: false,
|
||||||
|
diffuseColor: { red: 255, green: 255, blue: 255 },
|
||||||
|
ambientColor: { red: 255, green: 255, blue: 255 },
|
||||||
|
specularColor: { red: 0, green: 0, blue: 0 },
|
||||||
|
|
||||||
|
constantAttenuation: 1,
|
||||||
|
linearAttenuation: 0,
|
||||||
|
quadraticAttenuation: 0,
|
||||||
|
exponent: 0,
|
||||||
|
cutoff: 180, // in degrees
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
print("Can't create Light: Light would be out of bounds.");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -433,7 +468,7 @@ function mousePressEvent(event) {
|
||||||
|
|
||||||
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14;
|
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14;
|
||||||
|
|
||||||
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
|
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
|
||||||
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
|
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
|
||||||
|
|
||||||
if (0 < x && sizeOK) {
|
if (0 < x && sizeOK) {
|
||||||
|
@ -467,7 +502,7 @@ function mousePressEvent(event) {
|
||||||
w: selectedEntityProperties.rotation.w,
|
w: selectedEntityProperties.rotation.w,
|
||||||
};
|
};
|
||||||
selectedEntityProperties.glowLevel = 0.0;
|
selectedEntityProperties.glowLevel = 0.0;
|
||||||
|
|
||||||
print("Clicked on " + selectedEntityID.id + " " + entitySelected);
|
print("Clicked on " + selectedEntityID.id + " " + entitySelected);
|
||||||
tooltip.updateText(selectedEntityProperties);
|
tooltip.updateText(selectedEntityProperties);
|
||||||
tooltip.show(true);
|
tooltip.show(true);
|
||||||
|
@ -481,7 +516,7 @@ function mouseMoveEvent(event) {
|
||||||
if (!isActive) {
|
if (!isActive) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow the selectionDisplay and cameraManager to handle the event first, if it doesn't handle it, then do our own thing
|
// allow the selectionDisplay and cameraManager to handle the event first, if it doesn't handle it, then do our own thing
|
||||||
if (selectionDisplay.mouseMoveEvent(event) || cameraManager.mouseMoveEvent(event)) {
|
if (selectionDisplay.mouseMoveEvent(event) || cameraManager.mouseMoveEvent(event)) {
|
||||||
return;
|
return;
|
||||||
|
@ -496,11 +531,11 @@ function mouseMoveEvent(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var halfDiagonal = Vec3.length(entityIntersection.properties.dimensions) / 2.0;
|
var halfDiagonal = Vec3.length(entityIntersection.properties.dimensions) / 2.0;
|
||||||
|
|
||||||
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(),
|
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(),
|
||||||
entityIntersection.properties.position)) * 180 / 3.14;
|
entityIntersection.properties.position)) * 180 / 3.14;
|
||||||
|
|
||||||
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
|
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
|
||||||
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
|
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
|
||||||
|
|
||||||
if (entityIntersection.entityID.isKnownID && sizeOK) {
|
if (entityIntersection.entityID.isKnownID && sizeOK) {
|
||||||
|
@ -510,7 +545,7 @@ function mouseMoveEvent(event) {
|
||||||
highlightedEntityID = entityIntersection.entityID;
|
highlightedEntityID = entityIntersection.entityID;
|
||||||
selectionDisplay.highlightSelectable(entityIntersection.entityID);
|
selectionDisplay.highlightSelectable(entityIntersection.entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -550,9 +585,9 @@ function setupModelMenus() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Edit Properties..." });
|
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Edit Properties..." });
|
||||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Large Models", shortcutKey: "CTRL+META+L",
|
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Large Models", shortcutKey: "CTRL+META+L",
|
||||||
afterItem: "Paste Models", isCheckable: true });
|
afterItem: "Paste Models", isCheckable: true });
|
||||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Small Models", shortcutKey: "CTRL+META+S",
|
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Small Models", shortcutKey: "CTRL+META+S",
|
||||||
afterItem: "Allow Select Large Models", isCheckable: true });
|
afterItem: "Allow Select Large Models", isCheckable: true });
|
||||||
|
|
||||||
Menu.addMenuItem({ menuName: "File", menuItemName: "Models", isSeparator: true, beforeItem: "Settings" });
|
Menu.addMenuItem({ menuName: "File", menuItemName: "Models", isSeparator: true, beforeItem: "Settings" });
|
||||||
|
@ -606,14 +641,24 @@ function handeMenuEvent(menuItem) {
|
||||||
} else if (menuItem == "Allow Select Large Models") {
|
} else if (menuItem == "Allow Select Large Models") {
|
||||||
allowLargeModels = Menu.isOptionChecked("Allow Select Large Models");
|
allowLargeModels = Menu.isOptionChecked("Allow Select Large Models");
|
||||||
} else if (menuItem == "Delete") {
|
} else if (menuItem == "Delete") {
|
||||||
if (entitySelected) {
|
if (SelectionManager.hasSelection()) {
|
||||||
print(" Delete Entity.... selectedEntityID="+ selectedEntityID);
|
print(" Delete Entity.... selectedEntityID="+ selectedEntityID);
|
||||||
|
SelectionManager.saveProperties();
|
||||||
|
var savedProperties = [];
|
||||||
for (var i = 0; i < selectionManager.selections.length; i++) {
|
for (var i = 0; i < selectionManager.selections.length; i++) {
|
||||||
Entities.deleteEntity(selectionManager.selections[i]);
|
var entityID = SelectionManager.selections[i];
|
||||||
|
var initialProperties = SelectionManager.savedProperties[entityID.id];
|
||||||
|
SelectionManager.savedProperties[entityID.id];
|
||||||
|
savedProperties.push({
|
||||||
|
entityID: entityID,
|
||||||
|
properties: initialProperties
|
||||||
|
});
|
||||||
|
Entities.deleteEntity(entityID);
|
||||||
}
|
}
|
||||||
|
SelectionManager.clearSelections();
|
||||||
|
pushCommandForSelections([], savedProperties);
|
||||||
selectionDisplay.unselect(selectedEntityID);
|
selectionDisplay.unselect(selectedEntityID);
|
||||||
entitySelected = false;
|
entitySelected = false;
|
||||||
selectionManager.clearSelections();
|
|
||||||
} else {
|
} else {
|
||||||
print(" Delete Entity.... not holding...");
|
print(" Delete Entity.... not holding...");
|
||||||
}
|
}
|
||||||
|
@ -623,15 +668,16 @@ function handeMenuEvent(menuItem) {
|
||||||
editModelID = -1;
|
editModelID = -1;
|
||||||
if (selectionManager.selections.length == 1) {
|
if (selectionManager.selections.length == 1) {
|
||||||
print(" Edit Properties.... selectedEntityID="+ selectedEntityID);
|
print(" Edit Properties.... selectedEntityID="+ selectedEntityID);
|
||||||
editModelID = selectedEntityID;
|
editModelID = selectionManager.selections[0];
|
||||||
} else {
|
} else {
|
||||||
print(" Edit Properties.... not holding...");
|
print(" Edit Properties.... not holding...");
|
||||||
}
|
}
|
||||||
if (editModelID != -1) {
|
if (editModelID != -1) {
|
||||||
print(" Edit Properties.... about to edit properties...");
|
print(" Edit Properties.... about to edit properties...");
|
||||||
entityPropertyDialogBox.openDialog(editModelID);
|
entityPropertyDialogBox.openDialog(editModelID);
|
||||||
|
selectionManager._update();
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (menuItem == "Paste Models") {
|
} else if (menuItem == "Paste Models") {
|
||||||
modelImporter.paste();
|
modelImporter.paste();
|
||||||
} else if (menuItem == "Export Models") {
|
} else if (menuItem == "Export Models") {
|
||||||
|
@ -659,8 +705,6 @@ Controller.keyReleaseEvent.connect(function (event) {
|
||||||
handeMenuEvent("Delete");
|
handeMenuEvent("Delete");
|
||||||
} else if (event.text == "TAB") {
|
} else if (event.text == "TAB") {
|
||||||
selectionDisplay.toggleSpaceMode();
|
selectionDisplay.toggleSpaceMode();
|
||||||
} else if (event.text == "ESC") {
|
|
||||||
selectionDisplay.cancelTool();
|
|
||||||
} else if (event.text == "f") {
|
} else if (event.text == "f") {
|
||||||
if (entitySelected) {
|
if (entitySelected) {
|
||||||
// Get latest properties
|
// Get latest properties
|
||||||
|
@ -671,8 +715,130 @@ Controller.keyReleaseEvent.connect(function (event) {
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
cameraManager.enable();
|
cameraManager.enable();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
var delta = null;
|
||||||
|
|
||||||
|
if (event.text == 'UP') {
|
||||||
|
if (event.isControl || event.isAlt) {
|
||||||
|
delta = { x: 0, y: 1, z: 0 };
|
||||||
|
} else {
|
||||||
|
delta = { x: 0, y: 0, z: -1 };
|
||||||
|
}
|
||||||
|
} else if (event.text == 'DOWN') {
|
||||||
|
if (event.isControl || event.isAlt) {
|
||||||
|
delta = { x: 0, y: -1, z: 0 };
|
||||||
|
} else {
|
||||||
|
delta = { x: 0, y: 0, z: 1 };
|
||||||
|
}
|
||||||
|
} else if (event.text == 'LEFT') {
|
||||||
|
delta = { x: -1, y: 0, z: 0 };
|
||||||
|
} else if (event.text == 'RIGHT') {
|
||||||
|
delta = { x: 1, y: 0, z: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delta != null) {
|
||||||
|
// Adjust delta so that movements are relative to the current camera orientation
|
||||||
|
var lookDirection = Quat.getFront(Camera.getOrientation());
|
||||||
|
lookDirection.z *= -1;
|
||||||
|
|
||||||
|
var angle = Math.atan2(lookDirection.z, lookDirection.x);
|
||||||
|
angle -= (Math.PI / 4);
|
||||||
|
|
||||||
|
var rotation = Math.floor(angle / (Math.PI / 2)) * (Math.PI / 2);
|
||||||
|
var rotator = Quat.fromPitchYawRollRadians(0, rotation, 0);
|
||||||
|
|
||||||
|
delta = Vec3.multiplyQbyV(rotator, delta);
|
||||||
|
|
||||||
|
SelectionManager.saveProperties();
|
||||||
|
|
||||||
|
for (var i = 0; i < selectionManager.selections.length; i++) {
|
||||||
|
var entityID = selectionManager.selections[i];
|
||||||
|
var properties = Entities.getEntityProperties(entityID);
|
||||||
|
Entities.editEntity(entityID, {
|
||||||
|
position: Vec3.sum(properties.position, delta)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pushCommandForSelections();
|
||||||
|
|
||||||
|
selectionManager._update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// When an entity has been deleted we need a way to "undo" this deletion. Because it's not currently
|
||||||
|
// possible to create an entity with a specific id, earlier undo commands to the deleted entity
|
||||||
|
// will fail if there isn't a way to find the new entity id.
|
||||||
|
DELETED_ENTITY_MAP = {
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyEntityProperties(data) {
|
||||||
|
var properties = data.setProperties;
|
||||||
|
var selectedEntityIDs = [];
|
||||||
|
for (var i = 0; i < properties.length; i++) {
|
||||||
|
var entityID = properties[i].entityID;
|
||||||
|
if (DELETED_ENTITY_MAP[entityID.id] !== undefined) {
|
||||||
|
entityID = DELETED_ENTITY_MAP[entityID.id];
|
||||||
|
}
|
||||||
|
Entities.editEntity(entityID, properties[i].properties);
|
||||||
|
selectedEntityIDs.push(entityID);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < data.createEntities.length; i++) {
|
||||||
|
var entityID = data.createEntities[i].entityID;
|
||||||
|
var properties = data.createEntities[i].properties;
|
||||||
|
var newEntityID = Entities.addEntity(properties);
|
||||||
|
DELETED_ENTITY_MAP[entityID.id] = newEntityID;
|
||||||
|
print(newEntityID.isKnownID);
|
||||||
|
if (data.selectCreated) {
|
||||||
|
selectedEntityIDs.push(newEntityID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var i = 0; i < data.deleteEntities.length; i++) {
|
||||||
|
var entityID = data.deleteEntities[i].entityID;
|
||||||
|
if (DELETED_ENTITY_MAP[entityID.id] !== undefined) {
|
||||||
|
entityID = DELETED_ENTITY_MAP[entityID.id];
|
||||||
|
}
|
||||||
|
Entities.deleteEntity(entityID);
|
||||||
|
}
|
||||||
|
|
||||||
|
selectionManager.setSelections(selectedEntityIDs);
|
||||||
|
};
|
||||||
|
|
||||||
|
// For currently selected entities, push a command to the UndoStack that uses the current entity properties for the
|
||||||
|
// redo command, and the saved properties for the undo command. Also, include create and delete entity data.
|
||||||
|
function pushCommandForSelections(createdEntityData, deletedEntityData) {
|
||||||
|
var undoData = {
|
||||||
|
setProperties: [],
|
||||||
|
createEntities: deletedEntityData || [],
|
||||||
|
deleteEntities: createdEntityData || [],
|
||||||
|
selectCreated: true,
|
||||||
|
};
|
||||||
|
var redoData = {
|
||||||
|
setProperties: [],
|
||||||
|
createEntities: createdEntityData || [],
|
||||||
|
deleteEntities: deletedEntityData || [],
|
||||||
|
selectCreated: false,
|
||||||
|
};
|
||||||
|
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
||||||
|
var entityID = SelectionManager.selections[i];
|
||||||
|
var initialProperties = SelectionManager.savedProperties[entityID.id];
|
||||||
|
var currentProperties = Entities.getEntityProperties(entityID);
|
||||||
|
undoData.setProperties.push({
|
||||||
|
entityID: entityID,
|
||||||
|
properties: {
|
||||||
|
position: initialProperties.position,
|
||||||
|
rotation: initialProperties.rotation,
|
||||||
|
dimensions: initialProperties.dimensions,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
redoData.setProperties.push({
|
||||||
|
entityID: entityID,
|
||||||
|
properties: {
|
||||||
|
position: currentProperties.position,
|
||||||
|
rotation: currentProperties.rotation,
|
||||||
|
dimensions: currentProperties.dimensions,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
UndoStack.pushCommand(applyEntityProperties, undoData, applyEntityProperties, redoData);
|
||||||
|
}
|
||||||
|
|
37
examples/spotlightExample.js
Normal file
37
examples/spotlightExample.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
//
|
||||||
|
// spotlightExample.js
|
||||||
|
// examples
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 10/28/14.
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// This is an example script that demonstrates creating and editing a particle
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
var lightProperties = {
|
||||||
|
type: "Light",
|
||||||
|
position: { x: 0, y: 0, z: 0 },
|
||||||
|
dimensions: { x: 1000, y: 1000, z: 1000 },
|
||||||
|
angularVelocity: { x: 0, y: 10, z: 0 },
|
||||||
|
angularDamping: 0,
|
||||||
|
|
||||||
|
isSpotlight: true,
|
||||||
|
diffuseColor: { red: 255, green: 255, blue: 255 },
|
||||||
|
ambientColor: { red: 255, green: 255, blue: 255 },
|
||||||
|
specularColor: { red: 255, green: 255, blue: 255 },
|
||||||
|
|
||||||
|
constantAttenuation: 1,
|
||||||
|
linearAttenuation: 0,
|
||||||
|
quadraticAttenuation: 0,
|
||||||
|
exponent: 0,
|
||||||
|
cutoff: 180, // in degrees
|
||||||
|
};
|
||||||
|
|
||||||
|
var spotlightID = Entities.addEntity(lightProperties);
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(function() {
|
||||||
|
Entities.deleteEntity(spotlightID);
|
||||||
|
});
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
|
|
||||||
#include <Logging.h>
|
#include <LogHandler.h>
|
||||||
|
|
||||||
#include "IceServer.h"
|
#include "IceServer.h"
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ int main(int argc, char* argv[]) {
|
||||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
qInstallMessageHandler(Logging::verboseMessageHandler);
|
qInstallMessageHandler(LogHandler::verboseMessageHandler);
|
||||||
|
|
||||||
IceServer iceServer(argc, argv);
|
IceServer iceServer(argc, argv);
|
||||||
return iceServer.exec();
|
return iceServer.exec();
|
||||||
|
|
2
interface/external/gverb/readme.txt
vendored
2
interface/external/gverb/readme.txt
vendored
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
Instructions for adding the Gverb library to Interface
|
Instructions for adding the Gverb library to Interface
|
||||||
(This is a required library)
|
(This is a required library)
|
||||||
Clément Brisset, Octobre 22nd, 2014
|
Clément Brisset, October 22nd, 2014
|
||||||
|
|
||||||
1. Go to https://github.com/highfidelity/gverb
|
1. Go to https://github.com/highfidelity/gverb
|
||||||
Or download the sources directly via this link:
|
Or download the sources directly via this link:
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
#include <HFActionEvent.h>
|
#include <HFActionEvent.h>
|
||||||
#include <HFBackEvent.h>
|
#include <HFBackEvent.h>
|
||||||
#include <LocalVoxelsList.h>
|
#include <LocalVoxelsList.h>
|
||||||
#include <Logging.h>
|
#include <LogHandler.h>
|
||||||
#include <NetworkAccessManager.h>
|
#include <NetworkAccessManager.h>
|
||||||
#include <OctalCode.h>
|
#include <OctalCode.h>
|
||||||
#include <OctreeSceneStats.h>
|
#include <OctreeSceneStats.h>
|
||||||
|
@ -116,12 +116,10 @@ const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::D
|
||||||
const QString DEFAULT_SCRIPTS_JS_URL = "http://public.highfidelity.io/scripts/defaultScripts.js";
|
const QString DEFAULT_SCRIPTS_JS_URL = "http://public.highfidelity.io/scripts/defaultScripts.js";
|
||||||
|
|
||||||
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||||
if (message.size() > 0) {
|
QString logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message);
|
||||||
QString dateString = QDateTime::currentDateTime().toTimeSpec(Qt::LocalTime).toString(Qt::ISODate);
|
|
||||||
QString formattedMessage = QString("[%1] %2\n").arg(dateString).arg(message);
|
if (!logMessage.isEmpty()) {
|
||||||
|
Application::getInstance()->getLogger()->addMessage(qPrintable(logMessage));
|
||||||
fprintf(stdout, "%s", qPrintable(formattedMessage));
|
|
||||||
Application::getInstance()->getLogger()->addMessage(qPrintable(formattedMessage));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -581,10 +579,6 @@ void Application::initializeGL() {
|
||||||
float startupTime = (float)_applicationStartupTime.elapsed() / 1000.0;
|
float startupTime = (float)_applicationStartupTime.elapsed() / 1000.0;
|
||||||
_justStarted = false;
|
_justStarted = false;
|
||||||
qDebug("Startup time: %4.2f seconds.", startupTime);
|
qDebug("Startup time: %4.2f seconds.", startupTime);
|
||||||
const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time";
|
|
||||||
|
|
||||||
// ask the Logstash class to record the startup time
|
|
||||||
Logging::stashValue(STAT_TYPE_TIMER, LOGSTASH_INTERFACE_START_TIME_KEY, startupTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update before the first render
|
// update before the first render
|
||||||
|
@ -3175,7 +3169,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
|
||||||
} 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();
|
QSize size = getTextureCache()->getFrameBufferSize();
|
||||||
float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio();
|
float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio() * _renderResolutionScale;
|
||||||
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, size.height() - y - height, width, height);
|
glViewport(x, size.height() - y - height, width, height);
|
||||||
glScissor(x, size.height() - y - height, width, height);
|
glScissor(x, size.height() - y - height, width, height);
|
||||||
|
|
|
@ -1018,6 +1018,27 @@ void Audio::parseAudioStreamStatsPacket(const QByteArray& packet) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Audio::parseAudioEnvironmentData(const QByteArray &packet) {
|
||||||
|
int numBytesPacketHeader = numBytesForPacketHeader(packet);
|
||||||
|
const char* dataAt = packet.constData() + numBytesPacketHeader;
|
||||||
|
|
||||||
|
char bitset;
|
||||||
|
memcpy(&bitset, dataAt, sizeof(char));
|
||||||
|
dataAt += sizeof(char);
|
||||||
|
|
||||||
|
bool hasReverb = oneAtBit(bitset, HAS_REVERB_BIT);;
|
||||||
|
if (hasReverb) {
|
||||||
|
float reverbTime, wetLevel;
|
||||||
|
memcpy(&reverbTime, dataAt, sizeof(float));
|
||||||
|
dataAt += sizeof(float);
|
||||||
|
memcpy(&wetLevel, dataAt, sizeof(float));
|
||||||
|
dataAt += sizeof(float);
|
||||||
|
_receivedAudioStream.setReverb(reverbTime, wetLevel);
|
||||||
|
} else {
|
||||||
|
_receivedAudioStream.clearReverb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Audio::sendDownstreamAudioStatsPacket() {
|
void Audio::sendDownstreamAudioStatsPacket() {
|
||||||
|
|
||||||
// since this function is called every second, we'll sample for some of our stats here
|
// since this function is called every second, we'll sample for some of our stats here
|
||||||
|
|
|
@ -125,6 +125,7 @@ public slots:
|
||||||
void stop();
|
void stop();
|
||||||
void addReceivedAudioToStream(const QByteArray& audioByteArray);
|
void addReceivedAudioToStream(const QByteArray& audioByteArray);
|
||||||
void parseAudioStreamStatsPacket(const QByteArray& packet);
|
void parseAudioStreamStatsPacket(const QByteArray& packet);
|
||||||
|
void parseAudioEnvironmentData(const QByteArray& packet);
|
||||||
void addSpatialAudioToBuffer(unsigned int sampleTime, const QByteArray& spatialAudio, unsigned int numSamples);
|
void addSpatialAudioToBuffer(unsigned int sampleTime, const QByteArray& spatialAudio, unsigned int numSamples);
|
||||||
void handleAudioInput();
|
void handleAudioInput();
|
||||||
void reset();
|
void reset();
|
||||||
|
|
|
@ -49,14 +49,18 @@ void DatagramProcessor::processDatagrams() {
|
||||||
PacketType incomingType = packetTypeForPacket(incomingPacket);
|
PacketType incomingType = packetTypeForPacket(incomingPacket);
|
||||||
// only process this packet if we have a match on the packet version
|
// only process this packet if we have a match on the packet version
|
||||||
switch (incomingType) {
|
switch (incomingType) {
|
||||||
|
case PacketTypeAudioEnvironment:
|
||||||
|
case PacketTypeAudioStreamStats:
|
||||||
case PacketTypeMixedAudio:
|
case PacketTypeMixedAudio:
|
||||||
case PacketTypeSilentAudioFrame:
|
case PacketTypeSilentAudioFrame: {
|
||||||
case PacketTypeAudioStreamStats: {
|
if (incomingType == PacketTypeAudioStreamStats) {
|
||||||
if (incomingType != PacketTypeAudioStreamStats) {
|
QMetaObject::invokeMethod(&application->_audio, "parseAudioStreamStatsPacket", Qt::QueuedConnection,
|
||||||
QMetaObject::invokeMethod(&application->_audio, "addReceivedAudioToStream", Qt::QueuedConnection,
|
Q_ARG(QByteArray, incomingPacket));
|
||||||
|
} else if (incomingType == PacketTypeAudioEnvironment) {
|
||||||
|
QMetaObject::invokeMethod(&application->_audio, "parseAudioEnvironmentData", Qt::QueuedConnection,
|
||||||
Q_ARG(QByteArray, incomingPacket));
|
Q_ARG(QByteArray, incomingPacket));
|
||||||
} else {
|
} else {
|
||||||
QMetaObject::invokeMethod(&application->_audio, "parseAudioStreamStatsPacket", Qt::QueuedConnection,
|
QMetaObject::invokeMethod(&application->_audio, "addReceivedAudioToStream", Qt::QueuedConnection,
|
||||||
Q_ARG(QByteArray, incomingPacket));
|
Q_ARG(QByteArray, incomingPacket));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1266,7 +1266,6 @@ void Menu::changeVSync() {
|
||||||
}
|
}
|
||||||
void Menu::changeRenderTargetFramerate(QAction* action) {
|
void Menu::changeRenderTargetFramerate(QAction* action) {
|
||||||
bool vsynOn = Application::getInstance()->isVSyncOn();
|
bool vsynOn = Application::getInstance()->isVSyncOn();
|
||||||
unsigned int framerate = Application::getInstance()->getRenderTargetFramerate();
|
|
||||||
|
|
||||||
QString text = action->text();
|
QString text = action->text();
|
||||||
if (text == MenuOption::RenderTargetFramerateUnlimited) {
|
if (text == MenuOption::RenderTargetFramerateUnlimited) {
|
||||||
|
@ -1315,7 +1314,7 @@ void Menu::displayNameLocationResponse(const QString& errorString) {
|
||||||
void Menu::toggleLocationList() {
|
void Menu::toggleLocationList() {
|
||||||
if (!_userLocationsDialog) {
|
if (!_userLocationsDialog) {
|
||||||
JavascriptObjectMap locationObjectMap;
|
JavascriptObjectMap locationObjectMap;
|
||||||
locationObjectMap.insert("InterfaceLocation", LocationScriptingInterface::getInstance());
|
locationObjectMap.insert("InterfaceLocation", &AddressManager::getInstance());
|
||||||
_userLocationsDialog = DataWebDialog::dialogForPath("/user/locations", locationObjectMap);
|
_userLocationsDialog = DataWebDialog::dialogForPath("/user/locations", locationObjectMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1359,7 +1358,7 @@ void Menu::nameLocation() {
|
||||||
|
|
||||||
if (!_newLocationDialog) {
|
if (!_newLocationDialog) {
|
||||||
JavascriptObjectMap locationObjectMap;
|
JavascriptObjectMap locationObjectMap;
|
||||||
locationObjectMap.insert("InterfaceLocation", LocationScriptingInterface::getInstance());
|
locationObjectMap.insert("InterfaceLocation", &AddressManager::getInstance());
|
||||||
_newLocationDialog = DataWebDialog::dialogForPath("/user/locations/new", locationObjectMap);
|
_newLocationDialog = DataWebDialog::dialogForPath("/user/locations/new", locationObjectMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -871,7 +871,7 @@ const float SCRIPT_PRIORITY = DEFAULT_PRIORITY + 1.0f;
|
||||||
void Avatar::setJointModelPositionAndOrientation(int index, glm::vec3 position, const glm::quat& rotation) {
|
void Avatar::setJointModelPositionAndOrientation(int index, glm::vec3 position, const glm::quat& rotation) {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(const_cast<Avatar*>(this), "setJointModelPositionAndOrientation",
|
QMetaObject::invokeMethod(const_cast<Avatar*>(this), "setJointModelPositionAndOrientation",
|
||||||
Qt::BlockingQueuedConnection, Q_ARG(const int, index), Q_ARG(const glm::vec3, position),
|
Qt::AutoConnection, Q_ARG(const int, index), Q_ARG(const glm::vec3, position),
|
||||||
Q_ARG(const glm::quat&, rotation));
|
Q_ARG(const glm::quat&, rotation));
|
||||||
} else {
|
} else {
|
||||||
_skeletonModel.inverseKinematics(index, position, rotation, SCRIPT_PRIORITY);
|
_skeletonModel.inverseKinematics(index, position, rotation, SCRIPT_PRIORITY);
|
||||||
|
@ -881,7 +881,7 @@ void Avatar::setJointModelPositionAndOrientation(int index, glm::vec3 position,
|
||||||
void Avatar::setJointModelPositionAndOrientation(const QString& name, glm::vec3 position, const glm::quat& rotation) {
|
void Avatar::setJointModelPositionAndOrientation(const QString& name, glm::vec3 position, const glm::quat& rotation) {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(const_cast<Avatar*>(this), "setJointModelPositionAndOrientation",
|
QMetaObject::invokeMethod(const_cast<Avatar*>(this), "setJointModelPositionAndOrientation",
|
||||||
Qt::BlockingQueuedConnection, Q_ARG(const QString&, name), Q_ARG(const glm::vec3, position),
|
Qt::AutoConnection, Q_ARG(const QString&, name), Q_ARG(const glm::vec3, position),
|
||||||
Q_ARG(const glm::quat&, rotation));
|
Q_ARG(const glm::quat&, rotation));
|
||||||
} else {
|
} else {
|
||||||
_skeletonModel.inverseKinematics(getJointIndex(name), position, rotation, SCRIPT_PRIORITY);
|
_skeletonModel.inverseKinematics(getJointIndex(name), position, rotation, SCRIPT_PRIORITY);
|
||||||
|
|
|
@ -49,8 +49,9 @@ const float PITCH_SPEED = 100.0f; // degrees/sec
|
||||||
const float COLLISION_RADIUS_SCALAR = 1.2f; // pertains to avatar-to-avatar collisions
|
const float COLLISION_RADIUS_SCALAR = 1.2f; // pertains to avatar-to-avatar collisions
|
||||||
const float COLLISION_RADIUS_SCALE = 0.125f;
|
const float COLLISION_RADIUS_SCALE = 0.125f;
|
||||||
|
|
||||||
const float MIN_KEYBOARD_CONTROL_SPEED = 0.50f;
|
|
||||||
const float MAX_WALKING_SPEED = 4.5f;
|
const float MAX_WALKING_SPEED = 4.5f;
|
||||||
|
const float MAX_BOOST_SPEED = 0.5f * MAX_WALKING_SPEED; // keyboard motor gets additive boost below this speed
|
||||||
|
const float MIN_AVATAR_SPEED = 0.05f; // speed is set to zero below this
|
||||||
|
|
||||||
// TODO: normalize avatar speed for standard avatar size, then scale all motion logic
|
// TODO: normalize avatar speed for standard avatar size, then scale all motion logic
|
||||||
// to properly follow avatar size.
|
// to properly follow avatar size.
|
||||||
|
@ -1286,19 +1287,21 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe
|
||||||
|
|
||||||
// Compute the target keyboard velocity (which ramps up slowly, and damps very quickly)
|
// Compute the target keyboard velocity (which ramps up slowly, and damps very quickly)
|
||||||
// the max magnitude of which depends on what we're doing:
|
// the max magnitude of which depends on what we're doing:
|
||||||
float motorLength = glm::length(_keyboardMotorVelocity);
|
float motorSpeed = glm::length(_keyboardMotorVelocity);
|
||||||
float finalMaxMotorSpeed = hasFloor ? _scale * MAX_WALKING_SPEED : _scale * MAX_KEYBOARD_MOTOR_SPEED;
|
float finalMaxMotorSpeed = hasFloor ? _scale * MAX_WALKING_SPEED : _scale * MAX_KEYBOARD_MOTOR_SPEED;
|
||||||
float speedGrowthTimescale = 2.0f;
|
float speedGrowthTimescale = 2.0f;
|
||||||
float speedIncreaseFactor = 1.8f;
|
float speedIncreaseFactor = 1.8f;
|
||||||
motorLength *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale , 0.0f, 1.0f) * speedIncreaseFactor;
|
motorSpeed *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale , 0.0f, 1.0f) * speedIncreaseFactor;
|
||||||
if (motorLength < _scale * MIN_KEYBOARD_CONTROL_SPEED) {
|
const float maxBoostSpeed = _scale * MAX_BOOST_SPEED;
|
||||||
|
if (motorSpeed < maxBoostSpeed) {
|
||||||
// an active keyboard motor should never be slower than this
|
// an active keyboard motor should never be slower than this
|
||||||
motorLength = _scale * MIN_KEYBOARD_CONTROL_SPEED;
|
float boostCoefficient = (maxBoostSpeed - motorSpeed) / maxBoostSpeed;
|
||||||
motorEfficiency = 1.0f;
|
motorSpeed += MIN_AVATAR_SPEED * boostCoefficient;
|
||||||
} else if (motorLength > finalMaxMotorSpeed) {
|
motorEfficiency += (1.0f - motorEfficiency) * boostCoefficient;
|
||||||
motorLength = finalMaxMotorSpeed;
|
} else if (motorSpeed > finalMaxMotorSpeed) {
|
||||||
|
motorSpeed = finalMaxMotorSpeed;
|
||||||
}
|
}
|
||||||
_keyboardMotorVelocity = motorLength * direction;
|
_keyboardMotorVelocity = motorSpeed * direction;
|
||||||
_isPushing = true;
|
_isPushing = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1430,7 +1433,6 @@ void MyAvatar::updatePosition(float deltaTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// update position
|
// update position
|
||||||
const float MIN_AVATAR_SPEED = 0.075f;
|
|
||||||
if (speed > MIN_AVATAR_SPEED) {
|
if (speed > MIN_AVATAR_SPEED) {
|
||||||
applyPositionDelta(deltaTime * velocity);
|
applyPositionDelta(deltaTime * velocity);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "EntityTreeRenderer.h"
|
#include "EntityTreeRenderer.h"
|
||||||
|
|
||||||
#include "RenderableBoxEntityItem.h"
|
#include "RenderableBoxEntityItem.h"
|
||||||
|
#include "RenderableLightEntityItem.h"
|
||||||
#include "RenderableModelEntityItem.h"
|
#include "RenderableModelEntityItem.h"
|
||||||
#include "RenderableSphereEntityItem.h"
|
#include "RenderableSphereEntityItem.h"
|
||||||
|
|
||||||
|
@ -39,6 +40,7 @@ EntityTreeRenderer::EntityTreeRenderer() :
|
||||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Model, RenderableModelEntityItem::factory)
|
REGISTER_ENTITY_TYPE_WITH_FACTORY(Model, RenderableModelEntityItem::factory)
|
||||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Box, RenderableBoxEntityItem::factory)
|
REGISTER_ENTITY_TYPE_WITH_FACTORY(Box, RenderableBoxEntityItem::factory)
|
||||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Sphere, RenderableSphereEntityItem::factory)
|
REGISTER_ENTITY_TYPE_WITH_FACTORY(Sphere, RenderableSphereEntityItem::factory)
|
||||||
|
REGISTER_ENTITY_TYPE_WITH_FACTORY(Light, RenderableLightEntityItem::factory)
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityTreeRenderer::~EntityTreeRenderer() {
|
EntityTreeRenderer::~EntityTreeRenderer() {
|
||||||
|
|
89
interface/src/entities/RenderableLightEntityItem.cpp
Normal file
89
interface/src/entities/RenderableLightEntityItem.cpp
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
//
|
||||||
|
// RenderableLightEntityItem.cpp
|
||||||
|
// interface/src
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 8/6/14.
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <glm/gtx/quaternion.hpp>
|
||||||
|
|
||||||
|
#include <FBXReader.h>
|
||||||
|
|
||||||
|
#include "InterfaceConfig.h"
|
||||||
|
|
||||||
|
#include <PerfStat.h>
|
||||||
|
#include <LightEntityItem.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include "Menu.h"
|
||||||
|
#include "EntityTreeRenderer.h"
|
||||||
|
#include "RenderableLightEntityItem.h"
|
||||||
|
|
||||||
|
|
||||||
|
EntityItem* RenderableLightEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||||
|
return new RenderableLightEntityItem(entityID, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderableLightEntityItem::render(RenderArgs* args) {
|
||||||
|
PerformanceTimer perfTimer("RenderableLightEntityItem::render");
|
||||||
|
assert(getType() == EntityTypes::Light);
|
||||||
|
glm::vec3 position = getPositionInMeters();
|
||||||
|
glm::vec3 center = getCenterInMeters();
|
||||||
|
glm::vec3 dimensions = getDimensions() * (float)TREE_SCALE;
|
||||||
|
glm::quat rotation = getRotation();
|
||||||
|
float largestDiameter = glm::max(dimensions.x, dimensions.y, dimensions.z);
|
||||||
|
|
||||||
|
const float MAX_COLOR = 255.0f;
|
||||||
|
float diffuseR = getDiffuseColor()[RED_INDEX] / MAX_COLOR;
|
||||||
|
float diffuseG = getDiffuseColor()[GREEN_INDEX] / MAX_COLOR;
|
||||||
|
float diffuseB = getDiffuseColor()[BLUE_INDEX] / MAX_COLOR;
|
||||||
|
|
||||||
|
float ambientR = getAmbientColor()[RED_INDEX] / MAX_COLOR;
|
||||||
|
float ambientG = getAmbientColor()[GREEN_INDEX] / MAX_COLOR;
|
||||||
|
float ambientB = getAmbientColor()[BLUE_INDEX] / MAX_COLOR;
|
||||||
|
|
||||||
|
float specularR = getSpecularColor()[RED_INDEX] / MAX_COLOR;
|
||||||
|
float specularG = getSpecularColor()[GREEN_INDEX] / MAX_COLOR;
|
||||||
|
float specularB = getSpecularColor()[BLUE_INDEX] / MAX_COLOR;
|
||||||
|
|
||||||
|
glm::vec3 ambient = glm::vec3(ambientR, ambientG, ambientB);
|
||||||
|
glm::vec3 diffuse = glm::vec3(diffuseR, diffuseG, diffuseB);
|
||||||
|
glm::vec3 specular = glm::vec3(specularR, specularG, specularB);
|
||||||
|
glm::vec3 direction = IDENTITY_FRONT * rotation;
|
||||||
|
float constantAttenuation = getConstantAttenuation();
|
||||||
|
float linearAttenuation = getLinearAttenuation();
|
||||||
|
float quadraticAttenuation = getQuadraticAttenuation();
|
||||||
|
float exponent = getExponent();
|
||||||
|
float cutoff = glm::radians(getCutoff());
|
||||||
|
|
||||||
|
if (_isSpotlight) {
|
||||||
|
Application::getInstance()->getDeferredLightingEffect()->addSpotLight(position, largestDiameter / 2.0f,
|
||||||
|
ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation,
|
||||||
|
direction, exponent, cutoff);
|
||||||
|
} else {
|
||||||
|
Application::getInstance()->getDeferredLightingEffect()->addPointLight(position, largestDiameter / 2.0f,
|
||||||
|
ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wantDebug = false;
|
||||||
|
if (wantDebug) {
|
||||||
|
glColor4f(diffuseR, diffuseG, diffuseB, 1.0f);
|
||||||
|
glPushMatrix();
|
||||||
|
glTranslatef(position.x, position.y, position.z);
|
||||||
|
glm::vec3 axis = glm::axis(rotation);
|
||||||
|
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||||
|
glPushMatrix();
|
||||||
|
glm::vec3 positionToCenter = center - position;
|
||||||
|
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||||
|
|
||||||
|
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||||
|
Application::getInstance()->getDeferredLightingEffect()->renderWireSphere(0.5f, 15, 15);
|
||||||
|
glPopMatrix();
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
};
|
40
interface/src/entities/RenderableLightEntityItem.h
Normal file
40
interface/src/entities/RenderableLightEntityItem.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
//
|
||||||
|
// RenderableLightEntityItem.h
|
||||||
|
// interface/src/entities
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 8/6/14.
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_RenderableLightEntityItem_h
|
||||||
|
#define hifi_RenderableLightEntityItem_h
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <EntityTree.h>
|
||||||
|
#include <Octree.h>
|
||||||
|
#include <OctreePacketData.h>
|
||||||
|
#include <OctreeRenderer.h>
|
||||||
|
#include <PacketHeaders.h>
|
||||||
|
#include <SharedUtil.h>
|
||||||
|
#include <ViewFrustum.h>
|
||||||
|
|
||||||
|
#include <LightEntityItem.h>
|
||||||
|
|
||||||
|
class RenderableLightEntityItem : public LightEntityItem {
|
||||||
|
public:
|
||||||
|
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||||
|
|
||||||
|
RenderableLightEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
||||||
|
LightEntityItem(entityItemID, properties)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
virtual void render(RenderArgs* args);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // hifi_RenderableLightEntityItem_h
|
|
@ -111,6 +111,8 @@ void Batch::runCommand(Command com, uint32 offset) {
|
||||||
CASE_COMMAND(glColor4f);
|
CASE_COMMAND(glColor4f);
|
||||||
CASE_COMMAND(glMaterialf);
|
CASE_COMMAND(glMaterialf);
|
||||||
CASE_COMMAND(glMaterialfv);
|
CASE_COMMAND(glMaterialfv);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -122,21 +122,36 @@ void Model::setOffset(const glm::vec3& offset) {
|
||||||
|
|
||||||
void Model::initProgram(ProgramObject& program, Model::Locations& locations, int specularTextureUnit) {
|
void Model::initProgram(ProgramObject& program, Model::Locations& locations, int specularTextureUnit) {
|
||||||
program.bind();
|
program.bind();
|
||||||
locations.tangent = program.attributeLocation("tangent");
|
|
||||||
locations.alphaThreshold = program.uniformLocation("alphaThreshold");
|
|
||||||
program.setUniformValue("diffuseMap", 0);
|
|
||||||
program.setUniformValue("normalMap", 1);
|
|
||||||
program.setUniformValue("specularMap", specularTextureUnit);
|
|
||||||
program.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations, int specularTextureUnit) {
|
#ifdef Q_OS_MAC
|
||||||
initProgram(program, locations, specularTextureUnit);
|
// HACK: Assign explicitely the attribute channel to avoid a bug on Yosemite
|
||||||
|
glBindAttribLocation(program.programId(), 4, "tangent");
|
||||||
program.bind();
|
glLinkProgram(program.programId());
|
||||||
locations.clusterMatrices = program.uniformLocation("clusterMatrices");
|
#endif
|
||||||
locations.clusterIndices = program.attributeLocation("clusterIndices");
|
|
||||||
locations.clusterWeights = program.attributeLocation("clusterWeights");
|
locations.tangent = program.attributeLocation("tangent");
|
||||||
|
locations.alphaThreshold = program.uniformLocation("alphaThreshold");
|
||||||
|
program.setUniformValue("diffuseMap", 0);
|
||||||
|
program.setUniformValue("normalMap", 1);
|
||||||
|
program.setUniformValue("specularMap", specularTextureUnit);
|
||||||
|
program.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations, int specularTextureUnit) {
|
||||||
|
initProgram(program, locations, specularTextureUnit);
|
||||||
|
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
// HACK: Assign explicitely the attribute channel to avoid a bug on Yosemite
|
||||||
|
glBindAttribLocation(program.programId(), 5, "clusterIndices");
|
||||||
|
glBindAttribLocation(program.programId(), 6, "clusterWeights");
|
||||||
|
glLinkProgram(program.programId());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
program.bind();
|
||||||
|
locations.clusterMatrices = program.uniformLocation("clusterMatrices");
|
||||||
|
|
||||||
|
locations.clusterIndices = program.attributeLocation("clusterIndices");
|
||||||
|
locations.clusterWeights = program.attributeLocation("clusterWeights");
|
||||||
program.release();
|
program.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1737,7 +1752,8 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl
|
||||||
mesh.texCoords.size() * sizeof(glm::vec2) +
|
mesh.texCoords.size() * sizeof(glm::vec2) +
|
||||||
(mesh.blendshapes.isEmpty() ? vertexCount * 2 * sizeof(glm::vec3) : 0);
|
(mesh.blendshapes.isEmpty() ? vertexCount * 2 * sizeof(glm::vec3) : 0);
|
||||||
//skinProgram->setAttributeBuffer(skinLocations->clusterIndices, GL_FLOAT, offset, 4);
|
//skinProgram->setAttributeBuffer(skinLocations->clusterIndices, GL_FLOAT, offset, 4);
|
||||||
GLBATCH(glVertexAttribPointer)(skinLocations->clusterIndices, 4, GL_FLOAT, GL_TRUE, 0, (const void*) offset);
|
GLBATCH(glVertexAttribPointer)(skinLocations->clusterIndices, 4, GL_FLOAT, GL_TRUE, 0,
|
||||||
|
reinterpret_cast<const void*>(offset));
|
||||||
//skinProgram->setAttributeBuffer(skinLocations->clusterWeights, GL_FLOAT,
|
//skinProgram->setAttributeBuffer(skinLocations->clusterWeights, GL_FLOAT,
|
||||||
// offset + vertexCount * sizeof(glm::vec4), 4);
|
// offset + vertexCount * sizeof(glm::vec4), 4);
|
||||||
GLBATCH(glVertexAttribPointer)(skinLocations->clusterWeights, 4, GL_FLOAT, GL_TRUE, 0, (const void*) (offset + vertexCount * sizeof(glm::vec4)));
|
GLBATCH(glVertexAttribPointer)(skinLocations->clusterWeights, 4, GL_FLOAT, GL_TRUE, 0, (const void*) (offset + vertexCount * sizeof(glm::vec4)));
|
||||||
|
|
|
@ -83,6 +83,12 @@ void InboundAudioStream::clearBuffer() {
|
||||||
_currentJitterBufferFrames = 0;
|
_currentJitterBufferFrames = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InboundAudioStream::setReverb(float reverbTime, float wetLevel) {
|
||||||
|
_hasReverb = true;
|
||||||
|
_reverbTime = reverbTime;
|
||||||
|
_wetLevel = wetLevel;
|
||||||
|
}
|
||||||
|
|
||||||
void InboundAudioStream::perSecondCallbackForUpdatingStats() {
|
void InboundAudioStream::perSecondCallbackForUpdatingStats() {
|
||||||
_incomingSequenceNumberStats.pushStatsToHistory();
|
_incomingSequenceNumberStats.pushStatsToHistory();
|
||||||
_timeGapStatsForDesiredCalcOnTooManyStarves.currentIntervalComplete();
|
_timeGapStatsForDesiredCalcOnTooManyStarves.currentIntervalComplete();
|
||||||
|
@ -163,22 +169,9 @@ int InboundAudioStream::parseData(const QByteArray& packet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int InboundAudioStream::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) {
|
int InboundAudioStream::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) {
|
||||||
int read = 0;
|
|
||||||
if (type == PacketTypeMixedAudio) {
|
|
||||||
memcpy(&_hasReverb, packetAfterSeqNum.data() + read, sizeof(bool));
|
|
||||||
read += sizeof(bool);
|
|
||||||
|
|
||||||
if (_hasReverb) {
|
|
||||||
memcpy(&_reverbTime, packetAfterSeqNum.data() + read, sizeof(float));
|
|
||||||
read += sizeof(float);
|
|
||||||
memcpy(&_wetLevel, packetAfterSeqNum.data() + read, sizeof(float));
|
|
||||||
read += sizeof(float);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// mixed audio packets do not have any info between the seq num and the audio data.
|
// mixed audio packets do not have any info between the seq num and the audio data.
|
||||||
numAudioSamples = (packetAfterSeqNum.size() - read) / sizeof(int16_t);
|
numAudioSamples = packetAfterSeqNum.size() / sizeof(int16_t);
|
||||||
return read;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int InboundAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) {
|
int InboundAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) {
|
||||||
|
|
|
@ -45,6 +45,9 @@ const int DEFAULT_WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES = 50;
|
||||||
const int DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION = 10;
|
const int DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION = 10;
|
||||||
const bool DEFAULT_REPETITION_WITH_FADE = true;
|
const bool DEFAULT_REPETITION_WITH_FADE = true;
|
||||||
|
|
||||||
|
// Audio Env bitset
|
||||||
|
const int HAS_REVERB_BIT = 0; // 1st bit
|
||||||
|
|
||||||
class InboundAudioStream : public NodeData {
|
class InboundAudioStream : public NodeData {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -158,6 +161,8 @@ public:
|
||||||
bool hasReverb() const { return _hasReverb; }
|
bool hasReverb() const { return _hasReverb; }
|
||||||
float getRevebTime() const { return _reverbTime; }
|
float getRevebTime() const { return _reverbTime; }
|
||||||
float getWetLevel() const { return _wetLevel; }
|
float getWetLevel() const { return _wetLevel; }
|
||||||
|
void setReverb(float reverbTime, float wetLevel);
|
||||||
|
void clearReverb() { _hasReverb = false; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
/// This function should be called every second for all the stats to function properly. If dynamic jitter buffers
|
/// This function should be called every second for all the stats to function properly. If dynamic jitter buffers
|
||||||
|
|
|
@ -68,8 +68,8 @@ EntityItemProperties::EntityItemProperties() :
|
||||||
_animationFPS(ModelEntityItem::DEFAULT_ANIMATION_FPS),
|
_animationFPS(ModelEntityItem::DEFAULT_ANIMATION_FPS),
|
||||||
_glowLevel(0.0f),
|
_glowLevel(0.0f),
|
||||||
_localRenderAlpha(1.0f),
|
_localRenderAlpha(1.0f),
|
||||||
|
_isSpotlight(false),
|
||||||
|
|
||||||
_naturalDimensions(1.0f, 1.0f, 1.0f),
|
|
||||||
_colorChanged(false),
|
_colorChanged(false),
|
||||||
_modelURLChanged(false),
|
_modelURLChanged(false),
|
||||||
_animationURLChanged(false),
|
_animationURLChanged(false),
|
||||||
|
@ -78,11 +78,51 @@ EntityItemProperties::EntityItemProperties() :
|
||||||
_animationFPSChanged(false),
|
_animationFPSChanged(false),
|
||||||
_glowLevelChanged(false),
|
_glowLevelChanged(false),
|
||||||
_localRenderAlphaChanged(false),
|
_localRenderAlphaChanged(false),
|
||||||
|
_isSpotlightChanged(false),
|
||||||
|
|
||||||
_defaultSettings(true)
|
_diffuseColor(),
|
||||||
|
_ambientColor(),
|
||||||
|
_specularColor(),
|
||||||
|
_constantAttenuation(1.0f),
|
||||||
|
_linearAttenuation(0.0f),
|
||||||
|
_quadraticAttenuation(0.0f),
|
||||||
|
_exponent(0.0f),
|
||||||
|
_cutoff(PI),
|
||||||
|
|
||||||
|
_diffuseColorChanged(false),
|
||||||
|
_ambientColorChanged(false),
|
||||||
|
_specularColorChanged(false),
|
||||||
|
_constantAttenuationChanged(false),
|
||||||
|
_linearAttenuationChanged(false),
|
||||||
|
_quadraticAttenuationChanged(false),
|
||||||
|
_exponentChanged(false),
|
||||||
|
_cutoffChanged(false),
|
||||||
|
|
||||||
|
_defaultSettings(true),
|
||||||
|
_sittingPoints(NULL),
|
||||||
|
_naturalDimensions(1.0f, 1.0f, 1.0f)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EntityItemProperties::~EntityItemProperties() {
|
||||||
|
if (_sittingPoints) {
|
||||||
|
delete _sittingPoints;
|
||||||
|
_sittingPoints = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityItemProperties::setSittingPoints(const QVector<SittingPoint>& sittingPoints) {
|
||||||
|
if (!_sittingPoints) {
|
||||||
|
_sittingPoints = new QVector<SittingPoint>;
|
||||||
|
}
|
||||||
|
_sittingPoints->clear();
|
||||||
|
|
||||||
|
foreach (SittingPoint sitPoint, sittingPoints) {
|
||||||
|
_sittingPoints->append(sitPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void EntityItemProperties::debugDump() const {
|
void EntityItemProperties::debugDump() const {
|
||||||
qDebug() << "EntityItemProperties...";
|
qDebug() << "EntityItemProperties...";
|
||||||
qDebug() << " _type=" << EntityTypes::getEntityTypeName(_type);
|
qDebug() << " _type=" << EntityTypes::getEntityTypeName(_type);
|
||||||
|
@ -120,6 +160,15 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
||||||
CHECK_PROPERTY_CHANGE(PROP_ANGULAR_DAMPING, angularDamping);
|
CHECK_PROPERTY_CHANGE(PROP_ANGULAR_DAMPING, angularDamping);
|
||||||
CHECK_PROPERTY_CHANGE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions);
|
CHECK_PROPERTY_CHANGE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions);
|
||||||
CHECK_PROPERTY_CHANGE(PROP_COLLISIONS_WILL_MOVE, collisionsWillMove);
|
CHECK_PROPERTY_CHANGE(PROP_COLLISIONS_WILL_MOVE, collisionsWillMove);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_IS_SPOTLIGHT, isSpotlight);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_DIFFUSE_COLOR, diffuseColor);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_AMBIENT_COLOR, ambientColor);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_SPECULAR_COLOR, specularColor);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_CONSTANT_ATTENUATION, constantAttenuation);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_LINEAR_ATTENUATION, linearAttenuation);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_QUADRATIC_ATTENUATION, quadraticAttenuation);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_EXPONENT, exponent);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_CUTOFF, cutoff);
|
||||||
|
|
||||||
return changedProperties;
|
return changedProperties;
|
||||||
}
|
}
|
||||||
|
@ -161,17 +210,30 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha);
|
COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha);
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE(ignoreForCollisions);
|
COPY_PROPERTY_TO_QSCRIPTVALUE(ignoreForCollisions);
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE(collisionsWillMove);
|
COPY_PROPERTY_TO_QSCRIPTVALUE(collisionsWillMove);
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE(isSpotlight);
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(diffuseColor, getDiffuseColor());
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(ambientColor, getAmbientColor());
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(specularColor, getSpecularColor());
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE(constantAttenuation);
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE(linearAttenuation);
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE(quadraticAttenuation);
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE(exponent);
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE(cutoff);
|
||||||
|
|
||||||
// Sitting properties support
|
// Sitting properties support
|
||||||
QScriptValue sittingPoints = engine->newObject();
|
QScriptValue sittingPoints = engine->newObject();
|
||||||
for (int i = 0; i < _sittingPoints.size(); ++i) {
|
if (_sittingPoints) {
|
||||||
QScriptValue sittingPoint = engine->newObject();
|
for (int i = 0; i < _sittingPoints->size(); ++i) {
|
||||||
sittingPoint.setProperty("name", _sittingPoints[i].name);
|
QScriptValue sittingPoint = engine->newObject();
|
||||||
sittingPoint.setProperty("position", vec3toScriptValue(engine, _sittingPoints[i].position));
|
sittingPoint.setProperty("name", _sittingPoints->at(i).name);
|
||||||
sittingPoint.setProperty("rotation", quatToScriptValue(engine, _sittingPoints[i].rotation));
|
sittingPoint.setProperty("position", vec3toScriptValue(engine, _sittingPoints->at(i).position));
|
||||||
sittingPoints.setProperty(i, sittingPoint);
|
sittingPoint.setProperty("rotation", quatToScriptValue(engine, _sittingPoints->at(i).rotation));
|
||||||
|
sittingPoints.setProperty(i, sittingPoint);
|
||||||
|
}
|
||||||
|
sittingPoints.setProperty("length", _sittingPoints->size());
|
||||||
|
} else {
|
||||||
|
sittingPoints.setProperty("length", 0);
|
||||||
}
|
}
|
||||||
sittingPoints.setProperty("length", _sittingPoints.size());
|
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(sittingPoints, sittingPoints); // gettable, but not settable
|
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(sittingPoints, sittingPoints); // gettable, but not settable
|
||||||
|
|
||||||
AABox aaBox = getAABoxInMeters();
|
AABox aaBox = getAABoxInMeters();
|
||||||
|
@ -220,6 +282,15 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(localRenderAlpha, setLocalRenderAlpha);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(localRenderAlpha, setLocalRenderAlpha);
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(ignoreForCollisions, setIgnoreForCollisions);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(ignoreForCollisions, setIgnoreForCollisions);
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(collisionsWillMove, setCollisionsWillMove);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(collisionsWillMove, setCollisionsWillMove);
|
||||||
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(isSpotlight, setIsSpotlight);
|
||||||
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(diffuseColor, setDiffuseColor);
|
||||||
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(ambientColor, setAmbientColor);
|
||||||
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(specularColor, setSpecularColor);
|
||||||
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(constantAttenuation, setConstantAttenuation);
|
||||||
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(linearAttenuation, setLinearAttenuation);
|
||||||
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(quadraticAttenuation, setQuadraticAttenuation);
|
||||||
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(exponent, setExponent);
|
||||||
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(cutoff, setCutoff);
|
||||||
|
|
||||||
_lastEdited = usecTimestampNow();
|
_lastEdited = usecTimestampNow();
|
||||||
}
|
}
|
||||||
|
@ -370,6 +441,15 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
|
||||||
APPEND_ENTITY_PROPERTY(PROP_VISIBLE, appendValue, properties.getVisible());
|
APPEND_ENTITY_PROPERTY(PROP_VISIBLE, appendValue, properties.getVisible());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, appendValue, properties.getIgnoreForCollisions());
|
APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, appendValue, properties.getIgnoreForCollisions());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, appendValue, properties.getCollisionsWillMove());
|
APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, appendValue, properties.getCollisionsWillMove());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, appendValue, properties.getIsSpotlight());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_DIFFUSE_COLOR, appendColor, properties.getDiffuseColor());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_COLOR, appendColor, properties.getAmbientColor());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_SPECULAR_COLOR, appendColor, properties.getSpecularColor());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_CONSTANT_ATTENUATION, appendValue, properties.getConstantAttenuation());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_LINEAR_ATTENUATION, appendValue, properties.getLinearAttenuation());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_QUADRATIC_ATTENUATION, appendValue, properties.getQuadraticAttenuation());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_EXPONENT, appendValue, properties.getExponent());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_CUTOFF, appendValue, properties.getCutoff());
|
||||||
}
|
}
|
||||||
if (propertyCount > 0) {
|
if (propertyCount > 0) {
|
||||||
int endOfEntityItemData = packetData->getUncompressedByteOffset();
|
int endOfEntityItemData = packetData->getUncompressedByteOffset();
|
||||||
|
@ -568,6 +648,15 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE, bool, setVisible);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE, bool, setVisible);
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IGNORE_FOR_COLLISIONS, bool, setIgnoreForCollisions);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IGNORE_FOR_COLLISIONS, bool, setIgnoreForCollisions);
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISIONS_WILL_MOVE, bool, setCollisionsWillMove);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISIONS_WILL_MOVE, bool, setCollisionsWillMove);
|
||||||
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IS_SPOTLIGHT, bool, setIsSpotlight);
|
||||||
|
READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_DIFFUSE_COLOR, setDiffuseColor);
|
||||||
|
READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_AMBIENT_COLOR, setAmbientColor);
|
||||||
|
READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_SPECULAR_COLOR, setSpecularColor);
|
||||||
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CONSTANT_ATTENUATION, float, setConstantAttenuation);
|
||||||
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINEAR_ATTENUATION, float, setLinearAttenuation);
|
||||||
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_QUADRATIC_ATTENUATION, float, setQuadraticAttenuation);
|
||||||
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EXPONENT, float, setExponent);
|
||||||
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CUTOFF, float, setCutoff);
|
||||||
|
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
@ -622,6 +711,16 @@ void EntityItemProperties::markAllChanged() {
|
||||||
_animationFPSChanged = true;
|
_animationFPSChanged = true;
|
||||||
_glowLevelChanged = true;
|
_glowLevelChanged = true;
|
||||||
_localRenderAlphaChanged = true;
|
_localRenderAlphaChanged = true;
|
||||||
|
_isSpotlightChanged = true;
|
||||||
|
|
||||||
|
_diffuseColorChanged = true;
|
||||||
|
_ambientColorChanged = true;
|
||||||
|
_specularColorChanged = true;
|
||||||
|
_constantAttenuationChanged = true;
|
||||||
|
_linearAttenuationChanged = true;
|
||||||
|
_quadraticAttenuationChanged = true;
|
||||||
|
_exponentChanged = true;
|
||||||
|
_cutoffChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AACube EntityItemProperties::getMaximumAACubeInTreeUnits() const {
|
AACube EntityItemProperties::getMaximumAACubeInTreeUnits() const {
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
#include "EntityItemPropertiesMacros.h"
|
#include "EntityItemPropertiesMacros.h"
|
||||||
#include "EntityTypes.h"
|
#include "EntityTypes.h"
|
||||||
|
|
||||||
// PropertyFlags support
|
|
||||||
enum EntityPropertyList {
|
enum EntityPropertyList {
|
||||||
PROP_PAGED_PROPERTY,
|
PROP_PAGED_PROPERTY,
|
||||||
PROP_CUSTOM_PROPERTIES_INCLUDED,
|
PROP_CUSTOM_PROPERTIES_INCLUDED,
|
||||||
|
@ -65,7 +64,18 @@ enum EntityPropertyList {
|
||||||
PROP_IGNORE_FOR_COLLISIONS,
|
PROP_IGNORE_FOR_COLLISIONS,
|
||||||
PROP_COLLISIONS_WILL_MOVE,
|
PROP_COLLISIONS_WILL_MOVE,
|
||||||
|
|
||||||
PROP_LAST_ITEM = PROP_COLLISIONS_WILL_MOVE
|
// property used by Light entity
|
||||||
|
PROP_IS_SPOTLIGHT,
|
||||||
|
PROP_DIFFUSE_COLOR,
|
||||||
|
PROP_AMBIENT_COLOR,
|
||||||
|
PROP_SPECULAR_COLOR,
|
||||||
|
PROP_CONSTANT_ATTENUATION,
|
||||||
|
PROP_LINEAR_ATTENUATION,
|
||||||
|
PROP_QUADRATIC_ATTENUATION,
|
||||||
|
PROP_EXPONENT,
|
||||||
|
PROP_CUTOFF,
|
||||||
|
|
||||||
|
PROP_LAST_ITEM = PROP_CUTOFF
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef PropertyFlags<EntityPropertyList> EntityPropertyFlags;
|
typedef PropertyFlags<EntityPropertyList> EntityPropertyFlags;
|
||||||
|
@ -83,9 +93,10 @@ class EntityItemProperties {
|
||||||
friend class ModelEntityItem; // TODO: consider removing this friend relationship and use public methods
|
friend class ModelEntityItem; // TODO: consider removing this friend relationship and use public methods
|
||||||
friend class BoxEntityItem; // TODO: consider removing this friend relationship and use public methods
|
friend class BoxEntityItem; // TODO: consider removing this friend relationship and use public methods
|
||||||
friend class SphereEntityItem; // TODO: consider removing this friend relationship and use public methods
|
friend class SphereEntityItem; // TODO: consider removing this friend relationship and use public methods
|
||||||
|
friend class LightEntityItem; // TODO: consider removing this friend relationship and use public methods
|
||||||
public:
|
public:
|
||||||
EntityItemProperties();
|
EntityItemProperties();
|
||||||
virtual ~EntityItemProperties() { };
|
virtual ~EntityItemProperties();
|
||||||
|
|
||||||
virtual QScriptValue copyToScriptValue(QScriptEngine* engine) const;
|
virtual QScriptValue copyToScriptValue(QScriptEngine* engine) const;
|
||||||
virtual void copyFromScriptValue(const QScriptValue& object);
|
virtual void copyFromScriptValue(const QScriptValue& object);
|
||||||
|
@ -209,8 +220,7 @@ public:
|
||||||
void clearID() { _id = UNKNOWN_ENTITY_ID; _idSet = false; }
|
void clearID() { _id = UNKNOWN_ENTITY_ID; _idSet = false; }
|
||||||
void markAllChanged();
|
void markAllChanged();
|
||||||
|
|
||||||
QVector<SittingPoint> getSittingPoints() const { return _sittingPoints; }
|
void setSittingPoints(const QVector<SittingPoint>& sittingPoints);
|
||||||
void setSittingPoints(QVector<SittingPoint> sittingPoints) { _sittingPoints = sittingPoints; }
|
|
||||||
|
|
||||||
const glm::vec3& getNaturalDimensions() const { return _naturalDimensions; }
|
const glm::vec3& getNaturalDimensions() const { return _naturalDimensions; }
|
||||||
void setNaturalDimensions(const glm::vec3& value) { _naturalDimensions = value; }
|
void setNaturalDimensions(const glm::vec3& value) { _naturalDimensions = value; }
|
||||||
|
@ -233,6 +243,36 @@ public:
|
||||||
bool getCollisionsWillMove() const { return _collisionsWillMove; }
|
bool getCollisionsWillMove() const { return _collisionsWillMove; }
|
||||||
void setCollisionsWillMove(bool value) { _collisionsWillMove = value; _collisionsWillMoveChanged = true; }
|
void setCollisionsWillMove(bool value) { _collisionsWillMove = value; _collisionsWillMoveChanged = true; }
|
||||||
|
|
||||||
|
bool getIsSpotlight() const { return _isSpotlight; }
|
||||||
|
void setIsSpotlight(bool value) { _isSpotlight = value; _isSpotlightChanged = true; }
|
||||||
|
|
||||||
|
xColor getDiffuseColor() const { return _diffuseColor; }
|
||||||
|
xColor getAmbientColor() const { return _ambientColor; }
|
||||||
|
xColor getSpecularColor() const { return _specularColor; }
|
||||||
|
|
||||||
|
void setDiffuseColor(const xColor& value) { _diffuseColor = value; _diffuseColorChanged = true; }
|
||||||
|
void setAmbientColor(const xColor& value) { _ambientColor = value; _ambientColorChanged = true; }
|
||||||
|
void setSpecularColor(const xColor& value) { _specularColor = value; _specularColorChanged = true; }
|
||||||
|
|
||||||
|
bool diffuseColorChanged() const { return _colorChanged; }
|
||||||
|
bool ambientColorChanged() const { return _ambientColorChanged; }
|
||||||
|
bool specularColorChanged() const { return _specularColorChanged; }
|
||||||
|
|
||||||
|
bool getConstantAttenuation() const { return _constantAttenuation; }
|
||||||
|
void setConstantAttenuation(float value) { _constantAttenuation = value; _constantAttenuationChanged = true; }
|
||||||
|
|
||||||
|
bool getLinearAttenuation() const { return _linearAttenuation; }
|
||||||
|
void setLinearAttenuation(float value) { _linearAttenuation = value; _linearAttenuationChanged = true; }
|
||||||
|
|
||||||
|
bool getQuadraticAttenuation() const { return _quadraticAttenuation; }
|
||||||
|
void setQuadraticAttenuation(float value) { _quadraticAttenuation = value; _quadraticAttenuationChanged = true; }
|
||||||
|
|
||||||
|
bool getExponent() const { return _exponent; }
|
||||||
|
void setExponent(bool value) { _exponent = value; _exponentChanged = true; }
|
||||||
|
|
||||||
|
bool getCutoff() const { return _cutoff; }
|
||||||
|
void setCutoff(bool value) { _cutoff = value; _cutoffChanged = true; }
|
||||||
|
|
||||||
void setLastEdited(quint64 usecTime) { _lastEdited = usecTime; }
|
void setLastEdited(quint64 usecTime) { _lastEdited = usecTime; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -288,8 +328,7 @@ private:
|
||||||
float _animationFPS;
|
float _animationFPS;
|
||||||
float _glowLevel;
|
float _glowLevel;
|
||||||
float _localRenderAlpha;
|
float _localRenderAlpha;
|
||||||
QVector<SittingPoint> _sittingPoints;
|
bool _isSpotlight;
|
||||||
glm::vec3 _naturalDimensions;
|
|
||||||
|
|
||||||
bool _colorChanged;
|
bool _colorChanged;
|
||||||
bool _modelURLChanged;
|
bool _modelURLChanged;
|
||||||
|
@ -299,8 +338,32 @@ private:
|
||||||
bool _animationFPSChanged;
|
bool _animationFPSChanged;
|
||||||
bool _glowLevelChanged;
|
bool _glowLevelChanged;
|
||||||
bool _localRenderAlphaChanged;
|
bool _localRenderAlphaChanged;
|
||||||
|
bool _isSpotlightChanged;
|
||||||
|
|
||||||
|
xColor _diffuseColor;
|
||||||
|
xColor _ambientColor;
|
||||||
|
xColor _specularColor;
|
||||||
|
float _constantAttenuation;
|
||||||
|
float _linearAttenuation;
|
||||||
|
float _quadraticAttenuation;
|
||||||
|
float _exponent;
|
||||||
|
float _cutoff;
|
||||||
|
|
||||||
|
bool _diffuseColorChanged;
|
||||||
|
bool _ambientColorChanged;
|
||||||
|
bool _specularColorChanged;
|
||||||
|
bool _constantAttenuationChanged;
|
||||||
|
bool _linearAttenuationChanged;
|
||||||
|
bool _quadraticAttenuationChanged;
|
||||||
|
bool _exponentChanged;
|
||||||
|
bool _cutoffChanged;
|
||||||
|
|
||||||
bool _defaultSettings;
|
bool _defaultSettings;
|
||||||
|
|
||||||
|
// NOTE: The following are pseudo client only properties. They are only used in clients which can access
|
||||||
|
// properties of model geometry. But these properties are not serialized like other properties.
|
||||||
|
QVector<SittingPoint>* _sittingPoints;
|
||||||
|
glm::vec3 _naturalDimensions;
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(EntityItemProperties);
|
Q_DECLARE_METATYPE(EntityItemProperties);
|
||||||
QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties);
|
QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties);
|
||||||
|
|
|
@ -147,6 +147,10 @@
|
||||||
QScriptValue P = xColorToScriptValue(engine, _##P); \
|
QScriptValue P = xColorToScriptValue(engine, _##P); \
|
||||||
properties.setProperty(#P, P);
|
properties.setProperty(#P, P);
|
||||||
|
|
||||||
|
#define COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(P,G) \
|
||||||
|
QScriptValue P = xColorToScriptValue(engine, G); \
|
||||||
|
properties.setProperty(#P, P);
|
||||||
|
|
||||||
#define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(P, G) \
|
#define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(P, G) \
|
||||||
properties.setProperty(#P, G);
|
properties.setProperty(#P, G);
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "EntityTypes.h"
|
#include "EntityTypes.h"
|
||||||
|
|
||||||
#include "BoxEntityItem.h"
|
#include "BoxEntityItem.h"
|
||||||
|
#include "LightEntityItem.h"
|
||||||
#include "ModelEntityItem.h"
|
#include "ModelEntityItem.h"
|
||||||
#include "SphereEntityItem.h"
|
#include "SphereEntityItem.h"
|
||||||
|
|
||||||
|
@ -33,6 +34,7 @@ const QString ENTITY_TYPE_NAME_UNKNOWN = "Unknown";
|
||||||
REGISTER_ENTITY_TYPE(Model)
|
REGISTER_ENTITY_TYPE(Model)
|
||||||
REGISTER_ENTITY_TYPE(Box)
|
REGISTER_ENTITY_TYPE(Box)
|
||||||
REGISTER_ENTITY_TYPE(Sphere)
|
REGISTER_ENTITY_TYPE(Sphere)
|
||||||
|
REGISTER_ENTITY_TYPE(Light)
|
||||||
|
|
||||||
|
|
||||||
const QString& EntityTypes::getEntityTypeName(EntityType entityType) {
|
const QString& EntityTypes::getEntityTypeName(EntityType entityType) {
|
||||||
|
|
|
@ -33,7 +33,8 @@ public:
|
||||||
Model,
|
Model,
|
||||||
Box,
|
Box,
|
||||||
Sphere,
|
Sphere,
|
||||||
LAST = Sphere
|
Light,
|
||||||
|
LAST = Light
|
||||||
} EntityType;
|
} EntityType;
|
||||||
|
|
||||||
static const QString& getEntityTypeName(EntityType entityType);
|
static const QString& getEntityTypeName(EntityType entityType);
|
||||||
|
|
148
libraries/entities/src/LightEntityItem.cpp
Normal file
148
libraries/entities/src/LightEntityItem.cpp
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
//
|
||||||
|
// LightEntityItem.cpp
|
||||||
|
// libraries/entities/src
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 12/4/13.
|
||||||
|
// Copyright 2013 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include <ByteCountCoding.h>
|
||||||
|
|
||||||
|
#include "EntityTree.h"
|
||||||
|
#include "EntityTreeElement.h"
|
||||||
|
#include "LightEntityItem.h"
|
||||||
|
|
||||||
|
|
||||||
|
EntityItem* LightEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||||
|
return new LightEntityItem(entityID, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
// our non-pure virtual subclass for now...
|
||||||
|
LightEntityItem::LightEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
||||||
|
EntityItem(entityItemID, properties)
|
||||||
|
{
|
||||||
|
_type = EntityTypes::Light;
|
||||||
|
|
||||||
|
// default property values
|
||||||
|
const quint8 MAX_COLOR = 255;
|
||||||
|
_ambientColor[RED_INDEX] = _ambientColor[GREEN_INDEX] = _ambientColor[BLUE_INDEX] = 0;
|
||||||
|
_diffuseColor[RED_INDEX] = _diffuseColor[GREEN_INDEX] = _diffuseColor[BLUE_INDEX] = MAX_COLOR;
|
||||||
|
_specularColor[RED_INDEX] = _specularColor[GREEN_INDEX] = _specularColor[BLUE_INDEX] = MAX_COLOR;
|
||||||
|
_constantAttenuation = 1.0f;
|
||||||
|
_linearAttenuation = 0.0f;
|
||||||
|
_quadraticAttenuation = 0.0f;
|
||||||
|
_exponent = 0.0f;
|
||||||
|
_cutoff = PI;
|
||||||
|
|
||||||
|
setProperties(properties, true);
|
||||||
|
|
||||||
|
// a light is not collide-able so we make it's shape be a tiny sphere at origin
|
||||||
|
_emptyShape.setTranslation(glm::vec3(0.0f, 0.0f, 0.0f));
|
||||||
|
_emptyShape.setRadius(0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityItemProperties LightEntityItem::getProperties() const {
|
||||||
|
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
|
||||||
|
|
||||||
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(isSpotlight, getIsSpotlight);
|
||||||
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(diffuseColor, getDiffuseXColor);
|
||||||
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(ambientColor, getAmbientXColor);
|
||||||
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(specularColor, getSpecularXColor);
|
||||||
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(constantAttenuation, getConstantAttenuation);
|
||||||
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(linearAttenuation, getLinearAttenuation);
|
||||||
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(quadraticAttenuation, getQuadraticAttenuation);
|
||||||
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(exponent, getExponent);
|
||||||
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(cutoff, getCutoff);
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LightEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) {
|
||||||
|
bool somethingChanged = EntityItem::setProperties(properties, forceCopy); // set the properties in our base class
|
||||||
|
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(isSpotlight, setIsSpotlight);
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(diffuseColor, setDiffuseColor);
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ambientColor, setAmbientColor);
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(specularColor, setSpecularColor);
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(isSpotlight, setIsSpotlight);
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(constantAttenuation, setConstantAttenuation);
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(linearAttenuation, setLinearAttenuation);
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(quadraticAttenuation, setQuadraticAttenuation);
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(exponent, setExponent);
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(cutoff, setCutoff);
|
||||||
|
|
||||||
|
|
||||||
|
if (somethingChanged) {
|
||||||
|
bool wantDebug = false;
|
||||||
|
if (wantDebug) {
|
||||||
|
uint64_t now = usecTimestampNow();
|
||||||
|
int elapsed = now - getLastEdited();
|
||||||
|
qDebug() << "LightEntityItem::setProperties() AFTER update... edited AGO=" << elapsed <<
|
||||||
|
"now=" << now << " getLastEdited()=" << getLastEdited();
|
||||||
|
}
|
||||||
|
setLastEdited(properties.getLastEdited());
|
||||||
|
}
|
||||||
|
return somethingChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||||
|
ReadBitstreamToTreeParams& args,
|
||||||
|
EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
|
||||||
|
|
||||||
|
int bytesRead = 0;
|
||||||
|
const unsigned char* dataAt = data;
|
||||||
|
|
||||||
|
READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, _isSpotlight);
|
||||||
|
READ_ENTITY_PROPERTY_COLOR(PROP_DIFFUSE_COLOR, _diffuseColor);
|
||||||
|
READ_ENTITY_PROPERTY_COLOR(PROP_AMBIENT_COLOR, _ambientColor);
|
||||||
|
READ_ENTITY_PROPERTY_COLOR(PROP_SPECULAR_COLOR, _specularColor);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_CONSTANT_ATTENUATION, float, _constantAttenuation);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_LINEAR_ATTENUATION, float, _linearAttenuation);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_QUADRATIC_ATTENUATION, float, _quadraticAttenuation);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_EXPONENT, float, _exponent);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_CUTOFF, float, _cutoff);
|
||||||
|
|
||||||
|
return bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time
|
||||||
|
EntityPropertyFlags LightEntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
|
||||||
|
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
|
||||||
|
requestedProperties += PROP_IS_SPOTLIGHT;
|
||||||
|
requestedProperties += PROP_DIFFUSE_COLOR;
|
||||||
|
requestedProperties += PROP_AMBIENT_COLOR;
|
||||||
|
requestedProperties += PROP_SPECULAR_COLOR;
|
||||||
|
requestedProperties += PROP_CONSTANT_ATTENUATION;
|
||||||
|
requestedProperties += PROP_LINEAR_ATTENUATION;
|
||||||
|
requestedProperties += PROP_QUADRATIC_ATTENUATION;
|
||||||
|
requestedProperties += PROP_EXPONENT;
|
||||||
|
requestedProperties += PROP_CUTOFF;
|
||||||
|
return requestedProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LightEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
|
||||||
|
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
|
||||||
|
EntityPropertyFlags& requestedProperties,
|
||||||
|
EntityPropertyFlags& propertyFlags,
|
||||||
|
EntityPropertyFlags& propertiesDidntFit,
|
||||||
|
int& propertyCount,
|
||||||
|
OctreeElement::AppendState& appendState) const {
|
||||||
|
|
||||||
|
bool successPropertyFits = true;
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, appendValue, getIsSpotlight());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_DIFFUSE_COLOR, appendColor, getDiffuseColor());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_COLOR, appendColor, getAmbientColor());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_SPECULAR_COLOR, appendColor, getSpecularColor());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_CONSTANT_ATTENUATION, appendValue, getConstantAttenuation());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_LINEAR_ATTENUATION, appendValue, getLinearAttenuation());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_QUADRATIC_ATTENUATION, appendValue, getQuadraticAttenuation());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_EXPONENT, appendValue, getExponent());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_CUTOFF, appendValue, getCutoff());
|
||||||
|
}
|
118
libraries/entities/src/LightEntityItem.h
Normal file
118
libraries/entities/src/LightEntityItem.h
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
//
|
||||||
|
// LightEntityItem.h
|
||||||
|
// libraries/entities/src
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 12/4/13.
|
||||||
|
// Copyright 2013 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_LightEntityItem_h
|
||||||
|
#define hifi_LightEntityItem_h
|
||||||
|
|
||||||
|
#include <SphereShape.h>
|
||||||
|
#include "EntityItem.h"
|
||||||
|
|
||||||
|
class LightEntityItem : public EntityItem {
|
||||||
|
public:
|
||||||
|
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||||
|
|
||||||
|
LightEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
|
||||||
|
|
||||||
|
ALLOW_INSTANTIATION // This class can be instantiated
|
||||||
|
|
||||||
|
// methods for getting/setting all properties of an entity
|
||||||
|
virtual EntityItemProperties getProperties() const;
|
||||||
|
virtual bool setProperties(const EntityItemProperties& properties, bool forceCopy = false);
|
||||||
|
|
||||||
|
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;
|
||||||
|
|
||||||
|
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
|
||||||
|
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
|
||||||
|
EntityPropertyFlags& requestedProperties,
|
||||||
|
EntityPropertyFlags& propertyFlags,
|
||||||
|
EntityPropertyFlags& propertiesDidntFit,
|
||||||
|
int& propertyCount,
|
||||||
|
OctreeElement::AppendState& appendState) const;
|
||||||
|
|
||||||
|
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||||
|
ReadBitstreamToTreeParams& args,
|
||||||
|
EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
|
||||||
|
|
||||||
|
const rgbColor& getAmbientColor() const { return _ambientColor; }
|
||||||
|
xColor getAmbientXColor() const {
|
||||||
|
xColor color = { _ambientColor[RED_INDEX], _ambientColor[GREEN_INDEX], _ambientColor[BLUE_INDEX] }; return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setAmbientColor(const rgbColor& value) { memcpy(_ambientColor, value, sizeof(_ambientColor)); }
|
||||||
|
void setAmbientColor(const xColor& value) {
|
||||||
|
_ambientColor[RED_INDEX] = value.red;
|
||||||
|
_ambientColor[GREEN_INDEX] = value.green;
|
||||||
|
_ambientColor[BLUE_INDEX] = value.blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rgbColor& getDiffuseColor() const { return _diffuseColor; }
|
||||||
|
xColor getDiffuseXColor() const {
|
||||||
|
xColor color = { _diffuseColor[RED_INDEX], _diffuseColor[GREEN_INDEX], _diffuseColor[BLUE_INDEX] }; return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDiffuseColor(const rgbColor& value) { memcpy(_diffuseColor, value, sizeof(_diffuseColor)); }
|
||||||
|
void setDiffuseColor(const xColor& value) {
|
||||||
|
_diffuseColor[RED_INDEX] = value.red;
|
||||||
|
_diffuseColor[GREEN_INDEX] = value.green;
|
||||||
|
_diffuseColor[BLUE_INDEX] = value.blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rgbColor& getSpecularColor() const { return _specularColor; }
|
||||||
|
xColor getSpecularXColor() const {
|
||||||
|
xColor color = { _specularColor[RED_INDEX], _specularColor[GREEN_INDEX], _specularColor[BLUE_INDEX] }; return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSpecularColor(const rgbColor& value) { memcpy(_specularColor, value, sizeof(_specularColor)); }
|
||||||
|
void setSpecularColor(const xColor& value) {
|
||||||
|
_specularColor[RED_INDEX] = value.red;
|
||||||
|
_specularColor[GREEN_INDEX] = value.green;
|
||||||
|
_specularColor[BLUE_INDEX] = value.blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getIsSpotlight() const { return _isSpotlight; }
|
||||||
|
void setIsSpotlight(bool value) { _isSpotlight = value; }
|
||||||
|
|
||||||
|
float getConstantAttenuation() const { return _constantAttenuation; }
|
||||||
|
void setConstantAttenuation(float value) { _constantAttenuation = value; }
|
||||||
|
|
||||||
|
float getLinearAttenuation() const { return _linearAttenuation; }
|
||||||
|
void setLinearAttenuation(float value) { _linearAttenuation = value; }
|
||||||
|
|
||||||
|
float getQuadraticAttenuation() const { return _quadraticAttenuation; }
|
||||||
|
void setQuadraticAttenuation(float value) { _quadraticAttenuation = value; }
|
||||||
|
|
||||||
|
float getExponent() const { return _exponent; }
|
||||||
|
void setExponent(float value) { _exponent = value; }
|
||||||
|
|
||||||
|
float getCutoff() const { return _cutoff; }
|
||||||
|
void setCutoff(float value) { _cutoff = value; }
|
||||||
|
|
||||||
|
virtual const Shape& getCollisionShapeInMeters() const { return _emptyShape; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void recalculateCollisionShape() { /* nothing to do */ }
|
||||||
|
|
||||||
|
// properties of a light
|
||||||
|
rgbColor _ambientColor;
|
||||||
|
rgbColor _diffuseColor;
|
||||||
|
rgbColor _specularColor;
|
||||||
|
bool _isSpotlight;
|
||||||
|
float _constantAttenuation;
|
||||||
|
float _linearAttenuation;
|
||||||
|
float _quadraticAttenuation;
|
||||||
|
float _exponent;
|
||||||
|
float _cutoff;
|
||||||
|
|
||||||
|
// used for collision detection
|
||||||
|
SphereShape _emptyShape;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_LightEntityItem_h
|
|
@ -33,10 +33,7 @@ SphereEntityItem::SphereEntityItem(const EntityItemID& entityItemID, const Entit
|
||||||
|
|
||||||
EntityItemProperties SphereEntityItem::getProperties() const {
|
EntityItemProperties SphereEntityItem::getProperties() const {
|
||||||
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
|
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
|
||||||
|
|
||||||
properties.setColor(getXColor());
|
properties.setColor(getXColor());
|
||||||
properties.setGlowLevel(getGlowLevel());
|
|
||||||
|
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <qstringlist.h>
|
#include <qstringlist.h>
|
||||||
|
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
|
#include <UUID.h>
|
||||||
|
|
||||||
#include "NodeList.h"
|
#include "NodeList.h"
|
||||||
|
|
||||||
|
@ -71,6 +72,11 @@ const QString AddressManager::currentPath(bool withOrientation) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString AddressManager::getDomainID() const {
|
||||||
|
const QUuid& domainID = NodeList::getInstance()->getDomainHandler().getUUID();
|
||||||
|
return domainID.isNull() ? "" : uuidStringWithoutCurlyBraces(domainID);
|
||||||
|
}
|
||||||
|
|
||||||
const JSONCallbackParameters& AddressManager::apiCallbackParameters() {
|
const JSONCallbackParameters& AddressManager::apiCallbackParameters() {
|
||||||
static bool hasSetupParameters = false;
|
static bool hasSetupParameters = false;
|
||||||
static JSONCallbackParameters callbackParams;
|
static JSONCallbackParameters callbackParams;
|
||||||
|
|
|
@ -31,6 +31,7 @@ class AddressManager : public QObject {
|
||||||
Q_PROPERTY(QString protocol READ getProtocol)
|
Q_PROPERTY(QString protocol READ getProtocol)
|
||||||
Q_PROPERTY(QString hostname READ getCurrentDomain)
|
Q_PROPERTY(QString hostname READ getCurrentDomain)
|
||||||
Q_PROPERTY(QString pathname READ currentPath)
|
Q_PROPERTY(QString pathname READ currentPath)
|
||||||
|
Q_PROPERTY(QString domainID READ getDomainID)
|
||||||
public:
|
public:
|
||||||
static AddressManager& getInstance();
|
static AddressManager& getInstance();
|
||||||
|
|
||||||
|
@ -41,6 +42,7 @@ public:
|
||||||
const QString currentPath(bool withOrientation = true) const;
|
const QString currentPath(bool withOrientation = true) const;
|
||||||
|
|
||||||
const QString& getCurrentDomain() const { return _currentDomain; }
|
const QString& getCurrentDomain() const { return _currentDomain; }
|
||||||
|
QString getDomainID() const;
|
||||||
|
|
||||||
void attemptPlaceNameLookup(const QString& lookupString);
|
void attemptPlaceNameLookup(const QString& lookupString);
|
||||||
|
|
||||||
|
|
|
@ -19,10 +19,11 @@
|
||||||
#include <QtCore/QUrl>
|
#include <QtCore/QUrl>
|
||||||
#include <QtNetwork/QHostInfo>
|
#include <QtNetwork/QHostInfo>
|
||||||
|
|
||||||
|
#include <LogHandler.h>
|
||||||
|
|
||||||
#include "AccountManager.h"
|
#include "AccountManager.h"
|
||||||
#include "Assignment.h"
|
#include "Assignment.h"
|
||||||
#include "HifiSockAddr.h"
|
#include "HifiSockAddr.h"
|
||||||
#include "Logging.h"
|
|
||||||
#include "LimitedNodeList.h"
|
#include "LimitedNodeList.h"
|
||||||
#include "PacketHeaders.h"
|
#include "PacketHeaders.h"
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
|
@ -211,8 +212,11 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) {
|
||||||
<< uuidFromPacketHeader(packet);
|
<< uuidFromPacketHeader(packet);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
static QString repeatedMessage
|
||||||
|
= LogHandler::getInstance().addRepeatedMessageRegex("Packet of type \\d+ received from unknown node with UUID");
|
||||||
|
|
||||||
qDebug() << "Packet of type" << checkType << "received from unknown node with UUID"
|
qDebug() << "Packet of type" << checkType << "received from unknown node with UUID"
|
||||||
<< uuidFromPacketHeader(packet);
|
<< qPrintable(uuidStringWithoutCurlyBraces(uuidFromPacketHeader(packet)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1,126 +0,0 @@
|
||||||
//
|
|
||||||
// Logging.cpp
|
|
||||||
// libraries/networking/src
|
|
||||||
//
|
|
||||||
// Created by Stephen Birarda on 6/11/13.
|
|
||||||
// Copyright 2013 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <iostream>
|
|
||||||
#include <ctime>
|
|
||||||
//#include <netdb.h> // not available on windows, apparently not needed on mac
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <process.h>
|
|
||||||
#define getpid _getpid
|
|
||||||
#define getppid _getpid // hack to build
|
|
||||||
#define pid_t int // hack to build
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <QtNetwork/QHostInfo>
|
|
||||||
|
|
||||||
#include "HifiSockAddr.h"
|
|
||||||
#include "SharedUtil.h"
|
|
||||||
#include "NodeList.h"
|
|
||||||
|
|
||||||
#include "Logging.h"
|
|
||||||
|
|
||||||
HifiSockAddr Logging::_logstashSocket = HifiSockAddr();
|
|
||||||
QString Logging::_targetName = QString();
|
|
||||||
|
|
||||||
const HifiSockAddr& Logging::socket() {
|
|
||||||
|
|
||||||
if (_logstashSocket.getAddress().isNull()) {
|
|
||||||
// we need to construct the socket object
|
|
||||||
// use the constant port
|
|
||||||
_logstashSocket.setPort(htons(LOGSTASH_UDP_PORT));
|
|
||||||
|
|
||||||
// lookup the IP address for the constant hostname
|
|
||||||
QHostInfo hostInfo = QHostInfo::fromName(LOGSTASH_HOSTNAME);
|
|
||||||
if (!hostInfo.addresses().isEmpty()) {
|
|
||||||
// use the first IP address
|
|
||||||
_logstashSocket.setAddress(hostInfo.addresses().first());
|
|
||||||
} else {
|
|
||||||
qDebug("Failed to lookup logstash IP - will try again on next log attempt.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return _logstashSocket;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Logging::shouldSendStats() {
|
|
||||||
static bool shouldSendStats = isInEnvironment("production");
|
|
||||||
return shouldSendStats;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logging::stashValue(char statType, const char* key, float value) {
|
|
||||||
static char logstashPacket[MAX_PACKET_SIZE];
|
|
||||||
|
|
||||||
// load up the logstash packet with the key and the passed float value
|
|
||||||
// send it to 4 decimal places
|
|
||||||
int numPacketBytes = sprintf(logstashPacket, "%c %s %.4f", statType, key, value);
|
|
||||||
|
|
||||||
NodeList *nodeList = NodeList::getInstance();
|
|
||||||
|
|
||||||
if (nodeList) {
|
|
||||||
nodeList->getNodeSocket().writeDatagram(logstashPacket, numPacketBytes,
|
|
||||||
_logstashSocket.getAddress(), _logstashSocket.getPort());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* stringForLogType(QtMsgType msgType) {
|
|
||||||
switch (msgType) {
|
|
||||||
case QtDebugMsg:
|
|
||||||
return "DEBUG";
|
|
||||||
case QtCriticalMsg:
|
|
||||||
return "CRITICAL";
|
|
||||||
case QtFatalMsg:
|
|
||||||
return "FATAL";
|
|
||||||
case QtWarningMsg:
|
|
||||||
return "WARNING";
|
|
||||||
default:
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// the following will produce 2000-10-02 13:55:36 -0700
|
|
||||||
const char DATE_STRING_FORMAT[] = "%Y-%m-%d %H:%M:%S %z";
|
|
||||||
|
|
||||||
void Logging::verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
|
||||||
if (message.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// log prefix is in the following format
|
|
||||||
// [DEBUG] [TIMESTAMP] [PID:PARENT_PID] [TARGET] logged string
|
|
||||||
|
|
||||||
QString prefixString = QString("[%1]").arg(stringForLogType(type));
|
|
||||||
|
|
||||||
time_t rawTime;
|
|
||||||
time(&rawTime);
|
|
||||||
struct tm* localTime = localtime(&rawTime);
|
|
||||||
|
|
||||||
char dateString[100];
|
|
||||||
strftime(dateString, sizeof(dateString), DATE_STRING_FORMAT, localTime);
|
|
||||||
|
|
||||||
prefixString.append(QString(" [%1]").arg(dateString));
|
|
||||||
|
|
||||||
prefixString.append(QString(" [%1").arg(getpid()));
|
|
||||||
|
|
||||||
pid_t parentProcessID = getppid();
|
|
||||||
if (parentProcessID != 0) {
|
|
||||||
prefixString.append(QString(":%1]").arg(parentProcessID));
|
|
||||||
} else {
|
|
||||||
prefixString.append("]");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_targetName.isEmpty()) {
|
|
||||||
prefixString.append(QString(" [%1]").arg(_targetName));
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stdout, "%s %s\n", prefixString.toLocal8Bit().constData(), message.toLocal8Bit().constData());
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
//
|
|
||||||
// Logging.h
|
|
||||||
// libraries/networking/src
|
|
||||||
//
|
|
||||||
// Created by Stephen Birarda on 6/11/13.
|
|
||||||
// Copyright 2013 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef hifi_Logging_h
|
|
||||||
#define hifi_Logging_h
|
|
||||||
|
|
||||||
#include <QtCore/QString>
|
|
||||||
|
|
||||||
const int LOGSTASH_UDP_PORT = 9500;
|
|
||||||
const char LOGSTASH_HOSTNAME[] = "graphite.highfidelity.io";
|
|
||||||
|
|
||||||
const char STAT_TYPE_TIMER = 't';
|
|
||||||
const char STAT_TYPE_COUNTER = 'c';
|
|
||||||
const char STAT_TYPE_GAUGE = 'g';
|
|
||||||
|
|
||||||
class HifiSockAddr;
|
|
||||||
|
|
||||||
/// Handles custom message handling and sending of stats/logs to Logstash instance
|
|
||||||
class Logging {
|
|
||||||
public:
|
|
||||||
/// \return the socket used to send stats to logstash
|
|
||||||
static const HifiSockAddr& socket();
|
|
||||||
|
|
||||||
/// checks if this target should send stats to logstash, given its current environment
|
|
||||||
/// \return true if the caller should send stats to logstash
|
|
||||||
static bool shouldSendStats();
|
|
||||||
|
|
||||||
/// stashes a float value to Logstash instance
|
|
||||||
/// \param statType a stat type from the constants in this file
|
|
||||||
/// \param key the key at which to store the stat
|
|
||||||
/// \param value the value to store
|
|
||||||
static void stashValue(char statType, const char* key, float value);
|
|
||||||
|
|
||||||
/// sets the target name to output via the verboseMessageHandler, called once before logging begins
|
|
||||||
/// \param targetName the desired target name to output in logs
|
|
||||||
static void setTargetName(const QString& targetName) { _targetName = targetName; }
|
|
||||||
|
|
||||||
/// a qtMessageHandler that can be hooked up to a target that links to Qt
|
|
||||||
/// prints various process, message type, and time information
|
|
||||||
static void verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message);
|
|
||||||
private:
|
|
||||||
static HifiSockAddr _logstashSocket;
|
|
||||||
static QString _targetName;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // hifi_Logging_h
|
|
|
@ -15,10 +15,11 @@
|
||||||
#include <QtCore/QUrl>
|
#include <QtCore/QUrl>
|
||||||
#include <QtNetwork/QHostInfo>
|
#include <QtNetwork/QHostInfo>
|
||||||
|
|
||||||
|
#include <LogHandler.h>
|
||||||
|
|
||||||
#include "AccountManager.h"
|
#include "AccountManager.h"
|
||||||
#include "Assignment.h"
|
#include "Assignment.h"
|
||||||
#include "HifiSockAddr.h"
|
#include "HifiSockAddr.h"
|
||||||
#include "Logging.h"
|
|
||||||
#include "NodeList.h"
|
#include "NodeList.h"
|
||||||
#include "PacketHeaders.h"
|
#include "PacketHeaders.h"
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
|
|
|
@ -53,7 +53,7 @@ PacketVersion versionForPacketType(PacketType type) {
|
||||||
case PacketTypeSilentAudioFrame:
|
case PacketTypeSilentAudioFrame:
|
||||||
return 4;
|
return 4;
|
||||||
case PacketTypeMixedAudio:
|
case PacketTypeMixedAudio:
|
||||||
return 2;
|
return 1;
|
||||||
case PacketTypeAvatarData:
|
case PacketTypeAvatarData:
|
||||||
return 3;
|
return 3;
|
||||||
case PacketTypeAvatarIdentity:
|
case PacketTypeAvatarIdentity:
|
||||||
|
@ -71,11 +71,9 @@ PacketVersion versionForPacketType(PacketType type) {
|
||||||
return 1;
|
return 1;
|
||||||
case PacketTypeOctreeStats:
|
case PacketTypeOctreeStats:
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
case PacketTypeEntityAddOrEdit:
|
case PacketTypeEntityAddOrEdit:
|
||||||
case PacketTypeEntityData:
|
case PacketTypeEntityData:
|
||||||
return VERSION_ENTITIES_SUPPORT_DIMENSIONS;
|
return VERSION_ENTITIES_SUPPORT_DIMENSIONS;
|
||||||
|
|
||||||
case PacketTypeEntityErase:
|
case PacketTypeEntityErase:
|
||||||
return 2;
|
return 2;
|
||||||
case PacketTypeAudioStreamStats:
|
case PacketTypeAudioStreamStats:
|
||||||
|
@ -135,8 +133,13 @@ QString nameForPacketType(PacketType type) {
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAddResponse);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAddResponse);
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeOctreeDataNack);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeOctreeDataNack);
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeVoxelEditNack);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeVoxelEditNack);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeAudioEnvironment);
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityEditNack);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityEditNack);
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeSignedTransactionPayment);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeSignedTransactionPayment);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeIceServerHeartbeat);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeIceServerHeartbeatResponse);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPing);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPingReply);
|
||||||
default:
|
default:
|
||||||
return QString("Type: ") + QString::number((int)type);
|
return QString("Type: ") + QString::number((int)type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ enum PacketType {
|
||||||
PacketTypeEntityAddResponse,
|
PacketTypeEntityAddResponse,
|
||||||
PacketTypeOctreeDataNack, // 45
|
PacketTypeOctreeDataNack, // 45
|
||||||
PacketTypeVoxelEditNack,
|
PacketTypeVoxelEditNack,
|
||||||
UNUSED_6,
|
PacketTypeAudioEnvironment,
|
||||||
PacketTypeEntityEditNack, // 48
|
PacketTypeEntityEditNack, // 48
|
||||||
PacketTypeSignedTransactionPayment,
|
PacketTypeSignedTransactionPayment,
|
||||||
PacketTypeIceServerHeartbeat,
|
PacketTypeIceServerHeartbeat,
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
#include <QtCore/QTimer>
|
#include <QtCore/QTimer>
|
||||||
|
|
||||||
#include "Logging.h"
|
#include <LogHandler.h>
|
||||||
|
|
||||||
#include "ThreadedAssignment.h"
|
#include "ThreadedAssignment.h"
|
||||||
|
|
||||||
ThreadedAssignment::ThreadedAssignment(const QByteArray& packet) :
|
ThreadedAssignment::ThreadedAssignment(const QByteArray& packet) :
|
||||||
|
@ -54,7 +55,7 @@ void ThreadedAssignment::setFinished(bool isFinished) {
|
||||||
|
|
||||||
void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats) {
|
void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats) {
|
||||||
// change the logging target name while the assignment is running
|
// change the logging target name while the assignment is running
|
||||||
Logging::setTargetName(targetName);
|
LogHandler::getInstance().setTargetName(targetName);
|
||||||
|
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
nodeList->setOwnerType(nodeType);
|
nodeList->setOwnerType(nodeType);
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#include "OctreeProjectedPolygon.h"
|
#include "OctreeProjectedPolygon.h"
|
||||||
|
|
||||||
const float DEFAULT_KEYHOLE_RADIUS = 3.0f;
|
const float DEFAULT_KEYHOLE_RADIUS = 3.0f;
|
||||||
const float DEFAULT_FIELD_OF_VIEW_DEGREES = 90.0f;
|
const float DEFAULT_FIELD_OF_VIEW_DEGREES = 45.0f;
|
||||||
const float DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES = 30.f;
|
const float DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES = 30.f;
|
||||||
const float DEFAULT_ASPECT_RATIO = 16.f/9.f;
|
const float DEFAULT_ASPECT_RATIO = 16.f/9.f;
|
||||||
const float DEFAULT_NEAR_CLIP = 0.08f;
|
const float DEFAULT_NEAR_CLIP = 0.08f;
|
||||||
|
|
|
@ -30,6 +30,7 @@ void UndoStackScriptingInterface::pushCommand(QScriptValue undoFunction, QScript
|
||||||
|
|
||||||
ScriptUndoCommand::ScriptUndoCommand(QScriptValue undoFunction, QScriptValue undoData,
|
ScriptUndoCommand::ScriptUndoCommand(QScriptValue undoFunction, QScriptValue undoData,
|
||||||
QScriptValue redoFunction, QScriptValue redoData) :
|
QScriptValue redoFunction, QScriptValue redoData) :
|
||||||
|
_hasRedone(false),
|
||||||
_undoFunction(undoFunction),
|
_undoFunction(undoFunction),
|
||||||
_undoData(undoData),
|
_undoData(undoData),
|
||||||
_redoFunction(redoFunction),
|
_redoFunction(redoFunction),
|
||||||
|
@ -41,7 +42,15 @@ void ScriptUndoCommand::undo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptUndoCommand::redo() {
|
void ScriptUndoCommand::redo() {
|
||||||
QMetaObject::invokeMethod(this, "doRedo");
|
// QUndoStack will call `redo()` when adding a command to the stack. This
|
||||||
|
// makes it difficult to work with commands that span a period of time - for instance,
|
||||||
|
// the entity duplicate + move command that duplicates an entity and then moves it.
|
||||||
|
// A better implementation might be to properly implement `mergeWith()` and `id()`
|
||||||
|
// so that the two actions in the example would be merged.
|
||||||
|
if (_hasRedone) {
|
||||||
|
QMetaObject::invokeMethod(this, "doRedo");
|
||||||
|
}
|
||||||
|
_hasRedone = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptUndoCommand::doUndo() {
|
void ScriptUndoCommand::doUndo() {
|
||||||
|
@ -50,7 +59,6 @@ void ScriptUndoCommand::doUndo() {
|
||||||
_undoFunction.call(QScriptValue(), args);
|
_undoFunction.call(QScriptValue(), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ScriptUndoCommand::doRedo() {
|
void ScriptUndoCommand::doRedo() {
|
||||||
QScriptValueList args;
|
QScriptValueList args;
|
||||||
args << _redoData;
|
args << _redoData;
|
||||||
|
|
|
@ -43,6 +43,7 @@ public slots:
|
||||||
void doRedo();
|
void doRedo();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool _hasRedone;
|
||||||
QScriptValue _undoFunction;
|
QScriptValue _undoFunction;
|
||||||
QScriptValue _undoData;
|
QScriptValue _undoData;
|
||||||
QScriptValue _redoFunction;
|
QScriptValue _redoFunction;
|
||||||
|
|
146
libraries/shared/src/LogHandler.cpp
Normal file
146
libraries/shared/src/LogHandler.cpp
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
//
|
||||||
|
// LogHandler.cpp
|
||||||
|
// libraries/shared/src
|
||||||
|
//
|
||||||
|
// Created by Stephen Birarda on 2014-10-28.
|
||||||
|
// Migrated from Logging.cpp created on 6/11/13
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <process.h>
|
||||||
|
#define getpid _getpid
|
||||||
|
#define getppid _getpid // hack to build
|
||||||
|
#define pid_t int // hack to build
|
||||||
|
#else
|
||||||
|
#include <unistd.h> // for getpid() on linux
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <qdebug.h>
|
||||||
|
#include <qtimer.h>
|
||||||
|
|
||||||
|
#include "LogHandler.h"
|
||||||
|
|
||||||
|
LogHandler& LogHandler::getInstance() {
|
||||||
|
static LogHandler staticInstance;
|
||||||
|
return staticInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogHandler::LogHandler() :
|
||||||
|
_shouldOutputPID(false)
|
||||||
|
{
|
||||||
|
// setup our timer to flush the verbose logs every 5 seconds
|
||||||
|
QTimer* logFlushTimer = new QTimer(this);
|
||||||
|
connect(logFlushTimer, &QTimer::timeout, this, &LogHandler::flushRepeatedMessages);
|
||||||
|
logFlushTimer->start(VERBOSE_LOG_INTERVAL_SECONDS * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* stringForLogType(LogMsgType msgType) {
|
||||||
|
switch (msgType) {
|
||||||
|
case QtDebugMsg:
|
||||||
|
return "DEBUG";
|
||||||
|
case QtCriticalMsg:
|
||||||
|
return "CRITICAL";
|
||||||
|
case QtFatalMsg:
|
||||||
|
return "FATAL";
|
||||||
|
case QtWarningMsg:
|
||||||
|
return "WARNING";
|
||||||
|
case LogSuppressed:
|
||||||
|
return "SUPPRESS";
|
||||||
|
default:
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the following will produce 2000-10-02 13:55:36 -0700
|
||||||
|
const char DATE_STRING_FORMAT[] = "%Y-%m-%d %H:%M:%S %z";
|
||||||
|
|
||||||
|
void LogHandler::flushRepeatedMessages() {
|
||||||
|
QHash<QString, int>::iterator message = _repeatMessageCountHash.begin();
|
||||||
|
while (message != _repeatMessageCountHash.end()) {
|
||||||
|
|
||||||
|
if (message.value() > 0) {
|
||||||
|
QString repeatMessage = QString("%1 repeated log entries matching \"%2\" - Last entry: \"%3\"")
|
||||||
|
.arg(message.value()).arg(message.key()).arg(_lastRepeatedMessage.value(message.key()));
|
||||||
|
|
||||||
|
QMessageLogContext emptyContext;
|
||||||
|
printMessage(LogSuppressed, emptyContext, repeatMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
_lastRepeatedMessage.remove(message.key());
|
||||||
|
message = _repeatMessageCountHash.erase(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||||
|
|
||||||
|
if (message.isEmpty()) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == LogDebug) {
|
||||||
|
// for debug messages, check if this matches any of our regexes for repeated log messages
|
||||||
|
foreach(const QString& regexString, getInstance()._repeatedMessageRegexes) {
|
||||||
|
QRegExp repeatRegex(regexString);
|
||||||
|
if (repeatRegex.indexIn(message) != -1) {
|
||||||
|
|
||||||
|
if (!_repeatMessageCountHash.contains(regexString)) {
|
||||||
|
// we have a match but didn't have this yet - output the first one
|
||||||
|
_repeatMessageCountHash[regexString] = 0;
|
||||||
|
|
||||||
|
// break the foreach so we output the first match
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// we have a match - add 1 to the count of repeats for this message and set this as the last repeated message
|
||||||
|
_repeatMessageCountHash[regexString] += 1;
|
||||||
|
_lastRepeatedMessage[regexString] = message;
|
||||||
|
|
||||||
|
// return out, we're not printing this one
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// log prefix is in the following format
|
||||||
|
// [DEBUG] [TIMESTAMP] [PID:PARENT_PID] [TARGET] logged string
|
||||||
|
|
||||||
|
QString prefixString = QString("[%1]").arg(stringForLogType(type));
|
||||||
|
|
||||||
|
time_t rawTime;
|
||||||
|
time(&rawTime);
|
||||||
|
struct tm* localTime = localtime(&rawTime);
|
||||||
|
|
||||||
|
char dateString[100];
|
||||||
|
strftime(dateString, sizeof(dateString), DATE_STRING_FORMAT, localTime);
|
||||||
|
|
||||||
|
prefixString.append(QString(" [%1]").arg(dateString));
|
||||||
|
|
||||||
|
if (_shouldOutputPID) {
|
||||||
|
prefixString.append(QString(" [%1").arg(getpid()));
|
||||||
|
|
||||||
|
pid_t parentProcessID = getppid();
|
||||||
|
if (parentProcessID != 0) {
|
||||||
|
prefixString.append(QString(":%1]").arg(parentProcessID));
|
||||||
|
} else {
|
||||||
|
prefixString.append("]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_targetName.isEmpty()) {
|
||||||
|
prefixString.append(QString(" [%1]").arg(_targetName));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString logMessage = QString("%1 %2").arg(prefixString, message);
|
||||||
|
fprintf(stdout, "%s\n", qPrintable(logMessage));
|
||||||
|
return logMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogHandler::verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||||
|
getInstance().printMessage((LogMsgType) type, context, message);
|
||||||
|
}
|
63
libraries/shared/src/LogHandler.h
Normal file
63
libraries/shared/src/LogHandler.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
//
|
||||||
|
// LogHandler.cpp
|
||||||
|
// libraries/shared/src
|
||||||
|
//
|
||||||
|
// Created by Stephen Birarda on 2014-10-28.
|
||||||
|
// Migrated from Logging.cpp created on 6/11/13
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_LogHandler_h
|
||||||
|
#define hifi_LogHandler_h
|
||||||
|
|
||||||
|
#include <qhash.h>
|
||||||
|
#include <qobject.h>
|
||||||
|
#include <qregexp.h>
|
||||||
|
#include <qset.h>
|
||||||
|
#include <qstring.h>
|
||||||
|
|
||||||
|
const int VERBOSE_LOG_INTERVAL_SECONDS = 5;
|
||||||
|
|
||||||
|
enum LogMsgType {
|
||||||
|
LogDebug,
|
||||||
|
LogWarning,
|
||||||
|
LogCritical,
|
||||||
|
LogFatal,
|
||||||
|
LogSuppressed
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Handles custom message handling and sending of stats/logs to Logstash instance
|
||||||
|
class LogHandler : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
static LogHandler& getInstance();
|
||||||
|
|
||||||
|
/// sets the target name to output via the verboseMessageHandler, called once before logging begins
|
||||||
|
/// \param targetName the desired target name to output in logs
|
||||||
|
void setTargetName(const QString& targetName) { _targetName = targetName; }
|
||||||
|
|
||||||
|
void setShouldOutputPID(bool shouldOutputPID) { _shouldOutputPID = shouldOutputPID; }
|
||||||
|
|
||||||
|
QString printMessage(LogMsgType type, const QMessageLogContext& context, const QString &message);
|
||||||
|
|
||||||
|
/// a qtMessageHandler that can be hooked up to a target that links to Qt
|
||||||
|
/// prints various process, message type, and time information
|
||||||
|
static void verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message);
|
||||||
|
|
||||||
|
const QString& addRepeatedMessageRegex(const QString& regexString) { return *_repeatedMessageRegexes.insert(regexString); }
|
||||||
|
private:
|
||||||
|
LogHandler();
|
||||||
|
|
||||||
|
void flushRepeatedMessages();
|
||||||
|
|
||||||
|
QString _targetName;
|
||||||
|
bool _shouldOutputPID;
|
||||||
|
QSet<QString> _repeatedMessageRegexes;
|
||||||
|
QHash<QString, int> _repeatMessageCountHash;
|
||||||
|
QHash<QString, QString> _lastRepeatedMessage;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_LogHandler_h
|
Loading…
Reference in a new issue