mirror of
https://github.com/Armored-Dragon/overte.git
synced 2025-03-11 16:13:16 +01:00
Merge branch 'master' of github.com:/worklist/hifi
This commit is contained in:
commit
a9c294099e
24 changed files with 242 additions and 153 deletions
|
@ -238,6 +238,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
_window->setCentralWidget(_glWidget);
|
_window->setCentralWidget(_glWidget);
|
||||||
|
|
||||||
restoreSizeAndPosition();
|
restoreSizeAndPosition();
|
||||||
|
loadScripts();
|
||||||
_window->setVisible(true);
|
_window->setVisible(true);
|
||||||
_glWidget->setFocusPolicy(Qt::StrongFocus);
|
_glWidget->setFocusPolicy(Qt::StrongFocus);
|
||||||
_glWidget->setFocus();
|
_glWidget->setFocus();
|
||||||
|
@ -277,7 +278,7 @@ Application::~Application() {
|
||||||
_audio.thread()->wait();
|
_audio.thread()->wait();
|
||||||
|
|
||||||
storeSizeAndPosition();
|
storeSizeAndPosition();
|
||||||
|
saveScripts();
|
||||||
_sharedVoxelSystem.changeTree(new VoxelTree);
|
_sharedVoxelSystem.changeTree(new VoxelTree);
|
||||||
|
|
||||||
VoxelTreeElement::removeDeleteHook(&_voxels); // we don't need to do this processing on shutdown
|
VoxelTreeElement::removeDeleteHook(&_voxels); // we don't need to do this processing on shutdown
|
||||||
|
@ -4245,13 +4246,38 @@ void Application::packetSentNotification(ssize_t length) {
|
||||||
_bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(length);
|
_bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::loadScript() {
|
void Application::loadScripts(){
|
||||||
// shut down and stop any existing script
|
// loads all saved scripts
|
||||||
QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
QSettings* settings = new QSettings(this);
|
||||||
QString suggestedName = desktopLocation.append("/script.js");
|
int size = settings->beginReadArray("Settings");
|
||||||
|
for(int i=0; i<size; ++i){
|
||||||
|
settings->setArrayIndex(i);
|
||||||
|
QString string = settings->value("script").toString();
|
||||||
|
loadScript(string);
|
||||||
|
}
|
||||||
|
settings->endArray();
|
||||||
|
|
||||||
QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Open Script"), suggestedName,
|
}
|
||||||
tr("JavaScript Files (*.js)"));
|
|
||||||
|
void Application::saveScripts(){
|
||||||
|
// saves all current running scripts
|
||||||
|
QSettings* settings = new QSettings(this);
|
||||||
|
settings->beginWriteArray("Settings");
|
||||||
|
for(int i=0; i<_activeScripts.size(); ++i){
|
||||||
|
settings->setArrayIndex(i);
|
||||||
|
settings->setValue("script", _activeScripts.at(i));
|
||||||
|
}
|
||||||
|
settings->endArray();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::removeScriptName(const QString& fileNameString)
|
||||||
|
{
|
||||||
|
_activeScripts.removeOne(fileNameString);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::loadScript(const QString& fileNameString){
|
||||||
|
_activeScripts.append(fileNameString);
|
||||||
QByteArray fileNameAscii = fileNameString.toLocal8Bit();
|
QByteArray fileNameAscii = fileNameString.toLocal8Bit();
|
||||||
const char* fileName = fileNameAscii.data();
|
const char* fileName = fileNameAscii.data();
|
||||||
|
|
||||||
|
@ -4278,9 +4304,7 @@ void Application::loadScript() {
|
||||||
// start the script on a new thread...
|
// start the script on a new thread...
|
||||||
bool wantMenuItems = true; // tells the ScriptEngine object to add menu items for itself
|
bool wantMenuItems = true; // tells the ScriptEngine object to add menu items for itself
|
||||||
|
|
||||||
|
ScriptEngine* scriptEngine = new ScriptEngine(script, wantMenuItems, fileName, Menu::getInstance(), &_controllerScriptingInterface);
|
||||||
ScriptEngine* scriptEngine = new ScriptEngine(script, wantMenuItems, fileName, Menu::getInstance(),
|
|
||||||
&_controllerScriptingInterface);
|
|
||||||
scriptEngine->setupMenuItems();
|
scriptEngine->setupMenuItems();
|
||||||
|
|
||||||
// setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so
|
// setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so
|
||||||
|
@ -4294,8 +4318,9 @@ void Application::loadScript() {
|
||||||
connect(workerThread, SIGNAL(started()), scriptEngine, SLOT(run()));
|
connect(workerThread, SIGNAL(started()), scriptEngine, SLOT(run()));
|
||||||
|
|
||||||
// when the thread is terminated, add both scriptEngine and thread to the deleteLater queue
|
// when the thread is terminated, add both scriptEngine and thread to the deleteLater queue
|
||||||
connect(scriptEngine, SIGNAL(finished()), scriptEngine, SLOT(deleteLater()));
|
connect(scriptEngine, SIGNAL(finished(const QString&)), scriptEngine, SLOT(deleteLater()));
|
||||||
connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
|
connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
|
||||||
|
connect(scriptEngine, SIGNAL(finished(const QString&)), this, SLOT(removeScriptName(const QString&)));
|
||||||
|
|
||||||
// when the application is about to quit, stop our script engine so it unwinds properly
|
// when the application is about to quit, stop our script engine so it unwinds properly
|
||||||
connect(this, SIGNAL(aboutToQuit()), scriptEngine, SLOT(stop()));
|
connect(this, SIGNAL(aboutToQuit()), scriptEngine, SLOT(stop()));
|
||||||
|
@ -4309,6 +4334,17 @@ void Application::loadScript() {
|
||||||
_window->activateWindow();
|
_window->activateWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::loadDialog() {
|
||||||
|
// shut down and stop any existing script
|
||||||
|
QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||||
|
QString suggestedName = desktopLocation.append("/script.js");
|
||||||
|
|
||||||
|
QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Open Script"), suggestedName,
|
||||||
|
tr("JavaScript Files (*.js)"));
|
||||||
|
|
||||||
|
loadScript(fileNameString);
|
||||||
|
}
|
||||||
|
|
||||||
void Application::toggleLogDialog() {
|
void Application::toggleLogDialog() {
|
||||||
if (! _logDialog) {
|
if (! _logDialog) {
|
||||||
_logDialog = new LogDialog(_glWidget, getLogger());
|
_logDialog = new LogDialog(_glWidget, getLogger());
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QTouchEvent>
|
#include <QTouchEvent>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
#include <QStringList>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
|
||||||
#include <NetworkPacket.h>
|
#include <NetworkPacket.h>
|
||||||
|
@ -104,7 +105,10 @@ public:
|
||||||
~Application();
|
~Application();
|
||||||
|
|
||||||
void restoreSizeAndPosition();
|
void restoreSizeAndPosition();
|
||||||
|
void loadScript(const QString& fileNameString);
|
||||||
|
void loadScripts();
|
||||||
void storeSizeAndPosition();
|
void storeSizeAndPosition();
|
||||||
|
void saveScripts();
|
||||||
void initializeGL();
|
void initializeGL();
|
||||||
void paintGL();
|
void paintGL();
|
||||||
void resizeGL(int width, int height);
|
void resizeGL(int width, int height);
|
||||||
|
@ -225,7 +229,7 @@ public slots:
|
||||||
void doKillLocalVoxels();
|
void doKillLocalVoxels();
|
||||||
void decreaseVoxelSize();
|
void decreaseVoxelSize();
|
||||||
void increaseVoxelSize();
|
void increaseVoxelSize();
|
||||||
void loadScript();
|
void loadDialog();
|
||||||
void toggleLogDialog();
|
void toggleLogDialog();
|
||||||
void initAvatarAndViewFrustum();
|
void initAvatarAndViewFrustum();
|
||||||
|
|
||||||
|
@ -256,6 +260,8 @@ private slots:
|
||||||
|
|
||||||
void parseVersionXml();
|
void parseVersionXml();
|
||||||
|
|
||||||
|
void removeScriptName(const QString& fileNameString);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void resetCamerasOnResizeGL(Camera& camera, int width, int height);
|
void resetCamerasOnResizeGL(Camera& camera, int width, int height);
|
||||||
void updateProjectionMatrix();
|
void updateProjectionMatrix();
|
||||||
|
@ -379,6 +385,7 @@ private:
|
||||||
Faceshift _faceshift;
|
Faceshift _faceshift;
|
||||||
|
|
||||||
SixenseManager _sixenseManager;
|
SixenseManager _sixenseManager;
|
||||||
|
QStringList _activeScripts;
|
||||||
|
|
||||||
Camera _myCamera; // My view onto the world
|
Camera _myCamera; // My view onto the world
|
||||||
Camera _viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode
|
Camera _viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
|
|
||||||
#include <AbstractControllerScriptingInterface.h>
|
#include <AbstractControllerScriptingInterface.h>
|
||||||
|
class PalmData;
|
||||||
|
|
||||||
/// handles scripting of input controller commands from JS
|
/// handles scripting of input controller commands from JS
|
||||||
class ControllerScriptingInterface : public AbstractControllerScriptingInterface {
|
class ControllerScriptingInterface : public AbstractControllerScriptingInterface {
|
||||||
|
|
|
@ -91,7 +91,7 @@ Menu::Menu() :
|
||||||
SLOT(login())));
|
SLOT(login())));
|
||||||
|
|
||||||
addDisabledActionAndSeparator(fileMenu, "Scripts");
|
addDisabledActionAndSeparator(fileMenu, "Scripts");
|
||||||
addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, appInstance, SLOT(loadScript()));
|
addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, appInstance, SLOT(loadDialog()));
|
||||||
_activeScriptsMenu = fileMenu->addMenu("Running Scripts");
|
_activeScriptsMenu = fileMenu->addMenu("Running Scripts");
|
||||||
|
|
||||||
addDisabledActionAndSeparator(fileMenu, "Voxels");
|
addDisabledActionAndSeparator(fileMenu, "Voxels");
|
||||||
|
|
|
@ -32,7 +32,7 @@ void ParticleTreeRenderer::renderElement(OctreeElement* element, RenderArgs* arg
|
||||||
// we need to iterate the actual particles of the element
|
// we need to iterate the actual particles of the element
|
||||||
ParticleTreeElement* particleTreeElement = (ParticleTreeElement*)element;
|
ParticleTreeElement* particleTreeElement = (ParticleTreeElement*)element;
|
||||||
|
|
||||||
const std::vector<Particle>& particles = particleTreeElement->getParticles();
|
const QList<Particle>& particles = particleTreeElement->getParticles();
|
||||||
|
|
||||||
uint16_t numberOfParticles = particles.size();
|
uint16_t numberOfParticles = particles.size();
|
||||||
|
|
||||||
|
|
|
@ -124,10 +124,6 @@ glm::vec3 Avatar::getChestPosition() const {
|
||||||
return _skeletonModel.getNeckPosition(neckPosition) ? (_position + neckPosition) * 0.5f : _position;
|
return _skeletonModel.getNeckPosition(neckPosition) ? (_position + neckPosition) * 0.5f : _position;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::quat Avatar::getOrientation() const {
|
|
||||||
return glm::quat(glm::radians(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll)));
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::quat Avatar::getWorldAlignedOrientation () const {
|
glm::quat Avatar::getWorldAlignedOrientation () const {
|
||||||
return computeRotationFromBodyToWorldUp() * getOrientation();
|
return computeRotationFromBodyToWorldUp() * getOrientation();
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,6 @@ public:
|
||||||
const glm::vec3& getVelocity() const { return _velocity; }
|
const glm::vec3& getVelocity() const { return _velocity; }
|
||||||
Head& getHead() { return _head; }
|
Head& getHead() { return _head; }
|
||||||
Hand& getHand() { return _hand; }
|
Hand& getHand() { return _hand; }
|
||||||
glm::quat getOrientation() const;
|
|
||||||
glm::quat getWorldAlignedOrientation() const;
|
glm::quat getWorldAlignedOrientation() const;
|
||||||
|
|
||||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
|
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
|
||||||
|
|
|
@ -262,15 +262,6 @@ void Hand::simulate(float deltaTime, bool isMine) {
|
||||||
|
|
||||||
if (isMine) {
|
if (isMine) {
|
||||||
_buckyBalls.simulate(deltaTime);
|
_buckyBalls.simulate(deltaTime);
|
||||||
}
|
|
||||||
|
|
||||||
const glm::vec3 leapHandsOffsetFromFace(0.0, -0.2, -0.3); // place the hand in front of the face where we can see it
|
|
||||||
|
|
||||||
Head& head = _owningAvatar->getHead();
|
|
||||||
_baseOrientation = _owningAvatar->getOrientation();
|
|
||||||
_basePosition = head.calculateAverageEyePosition() + _baseOrientation * leapHandsOffsetFromFace * head.getScale();
|
|
||||||
|
|
||||||
if (isMine) {
|
|
||||||
updateCollisions();
|
updateCollisions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,7 +456,7 @@ void Hand::calculateGeometry() {
|
||||||
const float standardBallRadius = FINGERTIP_COLLISION_RADIUS;
|
const float standardBallRadius = FINGERTIP_COLLISION_RADIUS;
|
||||||
_leapFingerTipBalls.resize(_leapFingerTipBalls.size() + 1);
|
_leapFingerTipBalls.resize(_leapFingerTipBalls.size() + 1);
|
||||||
HandBall& ball = _leapFingerTipBalls.back();
|
HandBall& ball = _leapFingerTipBalls.back();
|
||||||
ball.rotation = _baseOrientation;
|
ball.rotation = getBaseOrientation();
|
||||||
ball.position = finger.getTipPosition();
|
ball.position = finger.getTipPosition();
|
||||||
ball.radius = standardBallRadius;
|
ball.radius = standardBallRadius;
|
||||||
ball.touchForce = 0.0;
|
ball.touchForce = 0.0;
|
||||||
|
@ -487,7 +478,7 @@ void Hand::calculateGeometry() {
|
||||||
const float standardBallRadius = 0.005f;
|
const float standardBallRadius = 0.005f;
|
||||||
_leapFingerRootBalls.resize(_leapFingerRootBalls.size() + 1);
|
_leapFingerRootBalls.resize(_leapFingerRootBalls.size() + 1);
|
||||||
HandBall& ball = _leapFingerRootBalls.back();
|
HandBall& ball = _leapFingerRootBalls.back();
|
||||||
ball.rotation = _baseOrientation;
|
ball.rotation = getBaseOrientation();
|
||||||
ball.position = finger.getRootPosition();
|
ball.position = finger.getRootPosition();
|
||||||
ball.radius = standardBallRadius;
|
ball.radius = standardBallRadius;
|
||||||
ball.touchForce = 0.0;
|
ball.touchForce = 0.0;
|
||||||
|
|
|
@ -798,7 +798,10 @@ bool Model::restoreJointPosition(int jointIndex, float percent) {
|
||||||
const QVector<int>& freeLineage = geometry.joints.at(jointIndex).freeLineage;
|
const QVector<int>& freeLineage = geometry.joints.at(jointIndex).freeLineage;
|
||||||
|
|
||||||
foreach (int index, freeLineage) {
|
foreach (int index, freeLineage) {
|
||||||
_jointStates[index].rotation = safeMix(_jointStates[index].rotation, geometry.joints.at(index).rotation, percent);
|
JointState& state = _jointStates[index];
|
||||||
|
const FBXJoint& joint = geometry.joints.at(index);
|
||||||
|
state.rotation = safeMix(state.rotation, joint.rotation, percent);
|
||||||
|
state.translation = glm::mix(state.translation, joint.translation, percent);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,15 @@ AvatarData::~AvatarData() {
|
||||||
delete _handData;
|
delete _handData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec3 AvatarData::getHandPosition() const {
|
||||||
|
return getOrientation() * _handPosition + _position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvatarData::setHandPosition(const glm::vec3& handPosition) {
|
||||||
|
// store relative to position/orientation
|
||||||
|
_handPosition = glm::inverse(getOrientation()) * (handPosition - _position);
|
||||||
|
}
|
||||||
|
|
||||||
int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
|
int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
|
||||||
unsigned char* bufferStart = destinationBuffer;
|
unsigned char* bufferStart = destinationBuffer;
|
||||||
|
|
||||||
|
|
|
@ -76,8 +76,8 @@ public:
|
||||||
const glm::vec3& getPosition() const { return _position; }
|
const glm::vec3& getPosition() const { return _position; }
|
||||||
void setPosition(const glm::vec3 position) { _position = position; }
|
void setPosition(const glm::vec3 position) { _position = position; }
|
||||||
|
|
||||||
const glm::vec3& getHandPosition() const { return _handPosition; }
|
glm::vec3 getHandPosition() const;
|
||||||
void setHandPosition(const glm::vec3 handPosition) { _handPosition = handPosition; }
|
void setHandPosition(const glm::vec3& handPosition);
|
||||||
|
|
||||||
int getBroadcastData(unsigned char* destinationBuffer);
|
int getBroadcastData(unsigned char* destinationBuffer);
|
||||||
int parseData(unsigned char* sourceBuffer, int numBytes);
|
int parseData(unsigned char* sourceBuffer, int numBytes);
|
||||||
|
@ -93,6 +93,8 @@ public:
|
||||||
float getBodyRoll() const { return _bodyRoll; }
|
float getBodyRoll() const { return _bodyRoll; }
|
||||||
void setBodyRoll(float bodyRoll) { _bodyRoll = bodyRoll; }
|
void setBodyRoll(float bodyRoll) { _bodyRoll = bodyRoll; }
|
||||||
|
|
||||||
|
glm::quat getOrientation() const { return glm::quat(glm::radians(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll))); }
|
||||||
|
|
||||||
// Scale
|
// Scale
|
||||||
float getTargetScale() const { return _targetScale; }
|
float getTargetScale() const { return _targetScale; }
|
||||||
void setTargetScale(float targetScale) { _targetScale = targetScale; }
|
void setTargetScale(float targetScale) { _targetScale = targetScale; }
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
const int fingerVectorRadix = 4;
|
const int fingerVectorRadix = 4;
|
||||||
|
|
||||||
HandData::HandData(AvatarData* owningAvatar) :
|
HandData::HandData(AvatarData* owningAvatar) :
|
||||||
_basePosition(0.0f, 0.0f, 0.0f),
|
|
||||||
_baseOrientation(0.0f, 0.0f, 0.0f, 1.0f),
|
|
||||||
_owningAvatarData(owningAvatar)
|
_owningAvatarData(owningAvatar)
|
||||||
{
|
{
|
||||||
// Start with two palms
|
// Start with two palms
|
||||||
|
@ -26,11 +24,11 @@ HandData::HandData(AvatarData* owningAvatar) :
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 HandData::worldPositionToLeapPosition(const glm::vec3& worldPosition) const {
|
glm::vec3 HandData::worldPositionToLeapPosition(const glm::vec3& worldPosition) const {
|
||||||
return glm::inverse(_baseOrientation) * (worldPosition - _basePosition) / LEAP_UNIT_SCALE;
|
return glm::inverse(getBaseOrientation()) * (worldPosition - getBasePosition()) / LEAP_UNIT_SCALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 HandData::worldVectorToLeapVector(const glm::vec3& worldVector) const {
|
glm::vec3 HandData::worldVectorToLeapVector(const glm::vec3& worldVector) const {
|
||||||
return glm::inverse(_baseOrientation) * worldVector / LEAP_UNIT_SCALE;
|
return glm::inverse(getBaseOrientation()) * worldVector / LEAP_UNIT_SCALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
PalmData& HandData::addNewPalm() {
|
PalmData& HandData::addNewPalm() {
|
||||||
|
@ -254,6 +252,15 @@ bool HandData::findSpherePenetration(const glm::vec3& penetratorCenter, float pe
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::quat HandData::getBaseOrientation() const {
|
||||||
|
return _owningAvatarData->getOrientation();
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 HandData::getBasePosition() const {
|
||||||
|
const glm::vec3 LEAP_HANDS_OFFSET_FROM_TORSO(0.0, 0.3, -0.3);
|
||||||
|
return _owningAvatarData->getPosition() + getBaseOrientation() * LEAP_HANDS_OFFSET_FROM_TORSO *
|
||||||
|
_owningAvatarData->getTargetScale();
|
||||||
|
}
|
||||||
|
|
||||||
void FingerData::setTrailLength(unsigned int length) {
|
void FingerData::setTrailLength(unsigned int length) {
|
||||||
_tipTrailPositions.resize(length);
|
_tipTrailPositions.resize(length);
|
||||||
|
|
|
@ -50,10 +50,10 @@ public:
|
||||||
|
|
||||||
// position conversion
|
// position conversion
|
||||||
glm::vec3 leapPositionToWorldPosition(const glm::vec3& leapPosition) {
|
glm::vec3 leapPositionToWorldPosition(const glm::vec3& leapPosition) {
|
||||||
return _basePosition + _baseOrientation * (leapPosition * LEAP_UNIT_SCALE);
|
return getBasePosition() + getBaseOrientation() * (leapPosition * LEAP_UNIT_SCALE);
|
||||||
}
|
}
|
||||||
glm::vec3 leapDirectionToWorldDirection(const glm::vec3& leapDirection) {
|
glm::vec3 leapDirectionToWorldDirection(const glm::vec3& leapDirection) {
|
||||||
return _baseOrientation * leapDirection;
|
return getBaseOrientation() * leapDirection;
|
||||||
}
|
}
|
||||||
glm::vec3 worldPositionToLeapPosition(const glm::vec3& worldPosition) const;
|
glm::vec3 worldPositionToLeapPosition(const glm::vec3& worldPosition) const;
|
||||||
glm::vec3 worldVectorToLeapVector(const glm::vec3& worldVector) const;
|
glm::vec3 worldVectorToLeapVector(const glm::vec3& worldVector) const;
|
||||||
|
@ -86,10 +86,12 @@ public:
|
||||||
|
|
||||||
friend class AvatarData;
|
friend class AvatarData;
|
||||||
protected:
|
protected:
|
||||||
glm::vec3 _basePosition; // Hands are placed relative to this
|
|
||||||
glm::quat _baseOrientation; // Hands are placed relative to this
|
|
||||||
AvatarData* _owningAvatarData;
|
AvatarData* _owningAvatarData;
|
||||||
std::vector<PalmData> _palms;
|
std::vector<PalmData> _palms;
|
||||||
|
|
||||||
|
glm::quat getBaseOrientation() const;
|
||||||
|
glm::vec3 getBasePosition() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// privatize copy ctor and assignment operator so copies of this object cannot be made
|
// privatize copy ctor and assignment operator so copies of this object cannot be made
|
||||||
HandData(const HandData&);
|
HandData(const HandData&);
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#ifndef __hifi__HTTPConnection__
|
#ifndef __hifi__HTTPConnection__
|
||||||
#define __hifi__HTTPConnection__
|
#define __hifi__HTTPConnection__
|
||||||
|
|
||||||
|
#include <QDataStream>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
#include <QIODevice>
|
#include <QIODevice>
|
||||||
|
|
|
@ -8,13 +8,14 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cm
|
||||||
|
|
||||||
set(TARGET_NAME octree-server)
|
set(TARGET_NAME octree-server)
|
||||||
|
|
||||||
|
find_package(Qt5Network REQUIRED)
|
||||||
find_package(Qt5Widgets REQUIRED)
|
find_package(Qt5Widgets REQUIRED)
|
||||||
|
|
||||||
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
||||||
|
|
||||||
setup_hifi_library(${TARGET_NAME} ${OPTIONAL_SRCS})
|
setup_hifi_library(${TARGET_NAME} ${OPTIONAL_SRCS})
|
||||||
|
|
||||||
qt5_use_modules(${TARGET_NAME} Widgets)
|
qt5_use_modules(${TARGET_NAME} Network Widgets)
|
||||||
|
|
||||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||||
include_glm(${TARGET_NAME} ${ROOT_DIR})
|
include_glm(${TARGET_NAME} ${ROOT_DIR})
|
||||||
|
@ -32,4 +33,4 @@ link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
||||||
link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR})
|
link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR})
|
||||||
|
|
||||||
# link the embedded webserver
|
# link the embedded webserver
|
||||||
link_hifi_library(embedded-webserver ${TARGET_NAME} ${ROOT_DIR})
|
link_hifi_library(embedded-webserver ${TARGET_NAME} ${ROOT_DIR})
|
||||||
|
|
|
@ -474,21 +474,21 @@ void Particle::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssiz
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MIN_VALID_SPEED is obtained by computing speed gained at one gravity during the shortest expected frame period
|
||||||
|
const float MIN_EXPECTED_FRAME_PERIOD = 0.005f; // 1/200th of a second
|
||||||
|
const float MIN_VALID_SPEED = 9.8 * MIN_EXPECTED_FRAME_PERIOD / (float)(TREE_SCALE);
|
||||||
|
|
||||||
void Particle::update() {
|
void Particle::update(const uint64_t& now) {
|
||||||
uint64_t now = usecTimestampNow();
|
float timeElapsed = (float)(now - _lastUpdated) / (float)(USECS_PER_SECOND);
|
||||||
float elapsed = static_cast<float>(now - _lastUpdated);
|
|
||||||
_lastUpdated = now;
|
_lastUpdated = now;
|
||||||
float timeElapsed = elapsed / static_cast<float>(USECS_PER_SECOND);
|
|
||||||
|
|
||||||
// calculate our default shouldDie state... then allow script to change it if it wants...
|
// calculate our default shouldDie state... then allow script to change it if it wants...
|
||||||
float velocityScalar = glm::length(getVelocity());
|
float speed = glm::length(_velocity);
|
||||||
const float STILL_MOVING = 0.05f / static_cast<float>(TREE_SCALE);
|
bool isStopped = (speed < MIN_VALID_SPEED);
|
||||||
bool isStillMoving = (velocityScalar > STILL_MOVING);
|
const uint64_t REALLY_OLD = 30 * USECS_PER_SECOND; // 30 seconds
|
||||||
const float REALLY_OLD = 30.0f; // 30 seconds
|
bool isReallyOld = ((now - _created) > REALLY_OLD);
|
||||||
bool isReallyOld = (getLifetime() > REALLY_OLD);
|
|
||||||
bool isInHand = getInHand();
|
bool isInHand = getInHand();
|
||||||
bool shouldDie = getShouldDie() || (!isInHand && !isStillMoving && isReallyOld);
|
bool shouldDie = getShouldDie() || (!isInHand && isStopped && isReallyOld);
|
||||||
setShouldDie(shouldDie);
|
setShouldDie(shouldDie);
|
||||||
|
|
||||||
runUpdateScript(); // allow the javascript to alter our state
|
runUpdateScript(); // allow the javascript to alter our state
|
||||||
|
|
|
@ -117,7 +117,7 @@ public:
|
||||||
|
|
||||||
static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew);
|
static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew);
|
||||||
|
|
||||||
void update();
|
void update(const uint64_t& now);
|
||||||
void collisionWithParticle(Particle* other);
|
void collisionWithParticle(Particle* other);
|
||||||
void collisionWithVoxel(VoxelDetail* voxel);
|
void collisionWithVoxel(VoxelDetail* voxel);
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
#include <AbstractAudioInterface.h>
|
#include <AbstractAudioInterface.h>
|
||||||
#include <VoxelTree.h>
|
#include <VoxelTree.h>
|
||||||
#include <AvatarData.h>
|
#include <AvatarData.h>
|
||||||
#include <CollisionInfo.h>
|
|
||||||
#include <HeadData.h>
|
#include <HeadData.h>
|
||||||
#include <HandData.h>
|
#include <HandData.h>
|
||||||
|
|
||||||
|
@ -43,7 +42,7 @@ bool ParticleCollisionSystem::updateOperation(OctreeElement* element, void* extr
|
||||||
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
|
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
|
||||||
|
|
||||||
// iterate the particles...
|
// iterate the particles...
|
||||||
std::vector<Particle>& particles = particleTreeElement->getParticles();
|
QList<Particle>& particles = particleTreeElement->getParticles();
|
||||||
uint16_t numberOfParticles = particles.size();
|
uint16_t numberOfParticles = particles.size();
|
||||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||||
Particle* particle = &particles[i];
|
Particle* particle = &particles[i];
|
||||||
|
@ -72,18 +71,18 @@ void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) {
|
||||||
glm::vec3 center = particle->getPosition() * (float)(TREE_SCALE);
|
glm::vec3 center = particle->getPosition() * (float)(TREE_SCALE);
|
||||||
float radius = particle->getRadius() * (float)(TREE_SCALE);
|
float radius = particle->getRadius() * (float)(TREE_SCALE);
|
||||||
const float ELASTICITY = 0.4f;
|
const float ELASTICITY = 0.4f;
|
||||||
const float DAMPING = 0.0f;
|
const float DAMPING = 0.05f;
|
||||||
const float COLLISION_FREQUENCY = 0.5f;
|
const float COLLISION_FREQUENCY = 0.5f;
|
||||||
glm::vec3 penetration;
|
CollisionInfo collisionInfo;
|
||||||
VoxelDetail* voxelDetails = NULL;
|
VoxelDetail* voxelDetails = NULL;
|
||||||
if (_voxels->findSpherePenetration(center, radius, penetration, (void**)&voxelDetails)) {
|
if (_voxels->findSpherePenetration(center, radius, collisionInfo._penetration, (void**)&voxelDetails)) {
|
||||||
|
|
||||||
// let the particles run their collision scripts if they have them
|
// let the particles run their collision scripts if they have them
|
||||||
particle->collisionWithVoxel(voxelDetails);
|
particle->collisionWithVoxel(voxelDetails);
|
||||||
|
|
||||||
penetration /= (float)(TREE_SCALE);
|
collisionInfo._penetration /= (float)(TREE_SCALE);
|
||||||
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
|
updateCollisionSound(particle, collisionInfo._penetration, COLLISION_FREQUENCY);
|
||||||
applyHardCollision(particle, penetration, ELASTICITY, DAMPING);
|
applyHardCollision(particle, ELASTICITY, DAMPING, collisionInfo);
|
||||||
|
|
||||||
delete voxelDetails; // cleanup returned details
|
delete voxelDetails; // cleanup returned details
|
||||||
}
|
}
|
||||||
|
@ -136,6 +135,10 @@ void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particleA)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MIN_VALID_SPEED is obtained by computing speed gained at one gravity after the shortest expected frame
|
||||||
|
const float MIN_EXPECTED_FRAME_PERIOD = 0.0167f; // 1/60th of a second
|
||||||
|
const float HALTING_SPEED = 9.8 * MIN_EXPECTED_FRAME_PERIOD / (float)(TREE_SCALE);
|
||||||
|
|
||||||
void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
|
void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
|
||||||
|
|
||||||
// particles that are in hand, don't collide with avatars
|
// particles that are in hand, don't collide with avatars
|
||||||
|
@ -146,18 +149,18 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
|
||||||
glm::vec3 center = particle->getPosition() * (float)(TREE_SCALE);
|
glm::vec3 center = particle->getPosition() * (float)(TREE_SCALE);
|
||||||
float radius = particle->getRadius() * (float)(TREE_SCALE);
|
float radius = particle->getRadius() * (float)(TREE_SCALE);
|
||||||
const float ELASTICITY = 0.9f;
|
const float ELASTICITY = 0.9f;
|
||||||
const float DAMPING = 0.0f;
|
const float DAMPING = 0.1f;
|
||||||
const float COLLISION_FREQUENCY = 0.5f;
|
const float COLLISION_FREQUENCY = 0.5f;
|
||||||
glm::vec3 penetration;
|
glm::vec3 penetration;
|
||||||
|
|
||||||
// first check the selfAvatar if set...
|
// first check the selfAvatar if set...
|
||||||
if (_selfAvatar) {
|
if (_selfAvatar) {
|
||||||
AvatarData* avatar = (AvatarData*)_selfAvatar;
|
AvatarData* avatar = (AvatarData*)_selfAvatar;
|
||||||
CollisionInfo collision;
|
CollisionInfo collisionInfo;
|
||||||
if (avatar->findSphereCollision(center, radius, collision)) {
|
if (avatar->findSphereCollision(center, radius, collisionInfo)) {
|
||||||
collision._addedVelocity /= (float)(TREE_SCALE);
|
collisionInfo._addedVelocity /= (float)(TREE_SCALE);
|
||||||
glm::vec3 relativeVelocity = collision._addedVelocity - particle->getVelocity();
|
glm::vec3 relativeVelocity = collisionInfo._addedVelocity - particle->getVelocity();
|
||||||
if (glm::dot(relativeVelocity, collision._penetration) < 0.f) {
|
if (glm::dot(relativeVelocity, collisionInfo._penetration) < 0.f) {
|
||||||
// only collide when particle and collision point are moving toward each other
|
// only collide when particle and collision point are moving toward each other
|
||||||
// (doing this prevents some "collision snagging" when particle penetrates the object)
|
// (doing this prevents some "collision snagging" when particle penetrates the object)
|
||||||
|
|
||||||
|
@ -165,17 +168,20 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
|
||||||
// NOTE: the physics are wrong (particles cannot roll) but it IS possible to catch a slow moving particle.
|
// NOTE: the physics are wrong (particles cannot roll) but it IS possible to catch a slow moving particle.
|
||||||
// TODO: make this less hacky when we have more per-collision details
|
// TODO: make this less hacky when we have more per-collision details
|
||||||
float elasticity = ELASTICITY;
|
float elasticity = ELASTICITY;
|
||||||
float SLOW_PADDLE_SPEED = 5.0e-5f;
|
float attenuationFactor = glm::length(collisionInfo._addedVelocity) / HALTING_SPEED;
|
||||||
float attenuationFactor = glm::length(collision._addedVelocity) / SLOW_PADDLE_SPEED;
|
float damping = DAMPING;
|
||||||
if (attenuationFactor < 1.f) {
|
if (attenuationFactor < 1.f) {
|
||||||
collision._addedVelocity *= attenuationFactor;
|
collisionInfo._addedVelocity *= attenuationFactor;
|
||||||
elasticity *= attenuationFactor;
|
elasticity *= attenuationFactor;
|
||||||
|
// NOTE: the math below keeps the damping piecewise continuous,
|
||||||
|
// while ramping it up to 1.0 when attenuationFactor = 0
|
||||||
|
damping = DAMPING + (1.f - attenuationFactor) * (1.f - DAMPING);
|
||||||
}
|
}
|
||||||
// HACK END
|
// HACK END
|
||||||
|
|
||||||
collision._penetration /= (float)(TREE_SCALE);
|
collisionInfo._penetration /= (float)(TREE_SCALE);
|
||||||
updateCollisionSound(particle, collision._penetration, COLLISION_FREQUENCY);
|
updateCollisionSound(particle, collisionInfo._penetration, COLLISION_FREQUENCY);
|
||||||
applyHardCollision(particle, collision._penetration, elasticity, DAMPING, collision._addedVelocity);
|
applyHardCollision(particle, elasticity, damping, collisionInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,36 +191,37 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
|
||||||
//qDebug() << "updateCollisionWithAvatars()... node:" << *node << "\n";
|
//qDebug() << "updateCollisionWithAvatars()... node:" << *node << "\n";
|
||||||
if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) {
|
if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) {
|
||||||
AvatarData* avatar = static_cast<AvatarData*>(node->getLinkedData());
|
AvatarData* avatar = static_cast<AvatarData*>(node->getLinkedData());
|
||||||
CollisionInfo collision;
|
CollisionInfo collisionInfo;
|
||||||
if (avatar->findSphereCollision(center, radius, collision)) {
|
if (avatar->findSphereCollision(center, radius, collisionInfo)) {
|
||||||
collision._addedVelocity /= (float)(TREE_SCALE);
|
collisionInfo._addedVelocity /= (float)(TREE_SCALE);
|
||||||
glm::vec3 relativeVelocity = collision._addedVelocity - particle->getVelocity();
|
glm::vec3 relativeVelocity = collisionInfo._addedVelocity - particle->getVelocity();
|
||||||
if (glm::dot(relativeVelocity, collision._penetration) < 0.f) {
|
if (glm::dot(relativeVelocity, collisionInfo._penetration) < 0.f) {
|
||||||
// HACK BEGIN: to allow paddle hands to "hold" particles we attenuate soft collisions against the avatar.
|
// HACK BEGIN: to allow paddle hands to "hold" particles we attenuate soft collisions against the avatar.
|
||||||
// NOTE: the physics are wrong (particles cannot roll) but it IS possible to catch a slow moving particle.
|
// NOTE: the physics are wrong (particles cannot roll) but it IS possible to catch a slow moving particle.
|
||||||
// TODO: make this less hacky when we have more per-collision details
|
// TODO: make this less hacky when we have more per-collision details
|
||||||
float elasticity = ELASTICITY;
|
float elasticity = ELASTICITY;
|
||||||
float SLOW_PADDLE_SPEED = 5.0e-5f;
|
float attenuationFactor = glm::length(collisionInfo._addedVelocity) / HALTING_SPEED;
|
||||||
float attenuationFactor = glm::length(collision._addedVelocity) / SLOW_PADDLE_SPEED;
|
float damping = DAMPING;
|
||||||
if (attenuationFactor < 1.f) {
|
if (attenuationFactor < 1.f) {
|
||||||
collision._addedVelocity *= attenuationFactor;
|
collisionInfo._addedVelocity *= attenuationFactor;
|
||||||
elasticity *= attenuationFactor;
|
elasticity *= attenuationFactor;
|
||||||
|
// NOTE: the math below keeps the damping piecewise continuous,
|
||||||
|
// while ramping it up to 1.0 when attenuationFactor = 0
|
||||||
|
damping = DAMPING + (1.f - attenuationFactor) * (1.f - DAMPING);
|
||||||
}
|
}
|
||||||
// HACK END
|
// HACK END
|
||||||
|
|
||||||
collision._penetration /= (float)(TREE_SCALE);
|
collisionInfo._penetration /= (float)(TREE_SCALE);
|
||||||
updateCollisionSound(particle, collision._penetration, COLLISION_FREQUENCY);
|
updateCollisionSound(particle, collisionInfo._penetration, COLLISION_FREQUENCY);
|
||||||
applyHardCollision(particle, collision._penetration, ELASTICITY, DAMPING, collision._addedVelocity);
|
applyHardCollision(particle, ELASTICITY, damping, collisionInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: convert applyHardCollision() to take a CollisionInfo& instead of penetration + addedVelocity
|
// TODO: convert applyHardCollision() to take a CollisionInfo& instead of penetration + addedVelocity
|
||||||
void ParticleCollisionSystem::applyHardCollision(Particle* particle, const glm::vec3& penetration,
|
void ParticleCollisionSystem::applyHardCollision(Particle* particle, float elasticity, float damping, const CollisionInfo& collisionInfo) {
|
||||||
float elasticity, float damping, const glm::vec3& addedVelocity) {
|
|
||||||
//
|
//
|
||||||
// Update the particle in response to a hard collision. Position will be reset exactly
|
// Update the particle in response to a hard collision. Position will be reset exactly
|
||||||
// to outside the colliding surface. Velocity will be modified according to elasticity.
|
// to outside the colliding surface. Velocity will be modified according to elasticity.
|
||||||
|
@ -226,20 +233,19 @@ void ParticleCollisionSystem::applyHardCollision(Particle* particle, const glm::
|
||||||
glm::vec3 velocity = particle->getVelocity();
|
glm::vec3 velocity = particle->getVelocity();
|
||||||
|
|
||||||
const float EPSILON = 0.0f;
|
const float EPSILON = 0.0f;
|
||||||
float velocityDotPenetration = glm::dot(velocity, penetration);
|
glm::vec3 relativeVelocity = collisionInfo._addedVelocity - velocity;
|
||||||
if (velocityDotPenetration > EPSILON) {
|
float velocityDotPenetration = glm::dot(relativeVelocity, collisionInfo._penetration);
|
||||||
position -= penetration;
|
if (velocityDotPenetration < EPSILON) {
|
||||||
static float HALTING_VELOCITY = 0.2f / (float)(TREE_SCALE);
|
// particle is moving into collision surface
|
||||||
// cancel out the velocity component in the direction of penetration
|
position -= collisionInfo._penetration;
|
||||||
|
|
||||||
float penetrationLength = glm::length(penetration);
|
if (glm::length(relativeVelocity) < HALTING_SPEED) {
|
||||||
glm::vec3 direction = penetration / penetrationLength;
|
// static friction kicks in and particle moves with colliding object
|
||||||
velocity -= (glm::dot(velocity, direction) * (1.0f + elasticity)) * direction;
|
velocity = collisionInfo._addedVelocity;
|
||||||
velocity += addedVelocity;
|
} else {
|
||||||
velocity *= glm::clamp(1.f - damping, 0.0f, 1.0f);
|
glm::vec3 direction = glm::normalize(collisionInfo._penetration);
|
||||||
if (glm::length(velocity) < HALTING_VELOCITY) {
|
velocity += glm::dot(relativeVelocity, direction) * (1.0f + elasticity) * direction; // dynamic reflection
|
||||||
// If moving really slowly after a collision, and not applying forces, stop altogether
|
velocity += glm::clamp(damping, 0.0f, 1.0f) * (relativeVelocity - glm::dot(relativeVelocity, direction) * direction); // dynamic friction
|
||||||
velocity *= 0.f;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const bool wantDebug = false;
|
const bool wantDebug = false;
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <QtScript/QScriptEngine>
|
#include <QtScript/QScriptEngine>
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
|
|
||||||
|
#include <CollisionInfo.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
#include <OctreePacketData.h>
|
#include <OctreePacketData.h>
|
||||||
|
|
||||||
|
@ -46,8 +47,7 @@ public:
|
||||||
void updateCollisionWithVoxels(Particle* particle);
|
void updateCollisionWithVoxels(Particle* particle);
|
||||||
void updateCollisionWithParticles(Particle* particle);
|
void updateCollisionWithParticles(Particle* particle);
|
||||||
void updateCollisionWithAvatars(Particle* particle);
|
void updateCollisionWithAvatars(Particle* particle);
|
||||||
void applyHardCollision(Particle* particle, const glm::vec3& penetration, float elasticity, float damping,
|
void applyHardCollision(Particle* particle, float elasticity, float damping, const CollisionInfo& collisionInfo);
|
||||||
const glm::vec3& addedVelocity = NO_ADDED_VELOCITY);
|
|
||||||
void updateCollisionSound(Particle* particle, const glm::vec3 &penetration, float frequency);
|
void updateCollisionSound(Particle* particle, const glm::vec3 &penetration, float frequency);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -11,12 +11,14 @@
|
||||||
#include "ParticleTree.h"
|
#include "ParticleTree.h"
|
||||||
#include "ParticleTreeElement.h"
|
#include "ParticleTreeElement.h"
|
||||||
|
|
||||||
ParticleTreeElement::ParticleTreeElement(unsigned char* octalCode) : OctreeElement() {
|
ParticleTreeElement::ParticleTreeElement(unsigned char* octalCode) : OctreeElement(), _particles(NULL) {
|
||||||
init(octalCode);
|
init(octalCode);
|
||||||
};
|
};
|
||||||
|
|
||||||
ParticleTreeElement::~ParticleTreeElement() {
|
ParticleTreeElement::~ParticleTreeElement() {
|
||||||
_voxelMemoryUsage -= sizeof(ParticleTreeElement);
|
_voxelMemoryUsage -= sizeof(ParticleTreeElement);
|
||||||
|
delete _particles;
|
||||||
|
_particles = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This will be called primarily on addChildAt(), which means we're adding a child of our
|
// This will be called primarily on addChildAt(), which means we're adding a child of our
|
||||||
|
@ -31,6 +33,7 @@ OctreeElement* ParticleTreeElement::createNewElement(unsigned char* octalCode) c
|
||||||
|
|
||||||
void ParticleTreeElement::init(unsigned char* octalCode) {
|
void ParticleTreeElement::init(unsigned char* octalCode) {
|
||||||
OctreeElement::init(octalCode);
|
OctreeElement::init(octalCode);
|
||||||
|
_particles = new QList<Particle>;
|
||||||
_voxelMemoryUsage += sizeof(ParticleTreeElement);
|
_voxelMemoryUsage += sizeof(ParticleTreeElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,12 +48,12 @@ bool ParticleTreeElement::appendElementData(OctreePacketData* packetData) const
|
||||||
bool success = true; // assume the best...
|
bool success = true; // assume the best...
|
||||||
|
|
||||||
// write our particles out...
|
// write our particles out...
|
||||||
uint16_t numberOfParticles = _particles.size();
|
uint16_t numberOfParticles = _particles->size();
|
||||||
success = packetData->appendValue(numberOfParticles);
|
success = packetData->appendValue(numberOfParticles);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||||
const Particle& particle = _particles[i];
|
const Particle& particle = (*_particles)[i];
|
||||||
success = particle.appendParticleData(packetData);
|
success = particle.appendParticleData(packetData);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
break;
|
break;
|
||||||
|
@ -62,35 +65,42 @@ bool ParticleTreeElement::appendElementData(OctreePacketData* packetData) const
|
||||||
|
|
||||||
void ParticleTreeElement::update(ParticleTreeUpdateArgs& args) {
|
void ParticleTreeElement::update(ParticleTreeUpdateArgs& args) {
|
||||||
markWithChangedTime();
|
markWithChangedTime();
|
||||||
|
// TODO: early exit when _particles is empty
|
||||||
|
|
||||||
// update our contained particles
|
// update our contained particles
|
||||||
uint16_t numberOfParticles = _particles.size();
|
QList<Particle>::iterator particleItr = _particles->begin();
|
||||||
|
while(particleItr != _particles->end()) {
|
||||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
Particle& particle = (*particleItr);
|
||||||
_particles[i].update();
|
particle.update(_lastChanged);
|
||||||
|
|
||||||
// If the particle wants to die, or if it's left our bounding box, then move it
|
// If the particle wants to die, or if it's left our bounding box, then move it
|
||||||
// into the arguments moving particles. These will be added back or deleted completely
|
// into the arguments moving particles. These will be added back or deleted completely
|
||||||
if (_particles[i].getShouldDie() || !_box.contains(_particles[i].getPosition())) {
|
if (particle.getShouldDie() || !_box.contains(particle.getPosition())) {
|
||||||
args._movingParticles.push_back(_particles[i]);
|
args._movingParticles.push_back(particle);
|
||||||
|
|
||||||
// erase this particle
|
// erase this particle
|
||||||
_particles.erase(_particles.begin()+i);
|
particleItr = _particles->erase(particleItr);
|
||||||
|
}
|
||||||
// reduce our index since we just removed this item
|
else
|
||||||
i--;
|
{
|
||||||
numberOfParticles--;
|
++particleItr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO: if _particles is empty after while loop consider freeing memory in _particles if
|
||||||
|
// internal array is too big (QList internal array does not decrease size except in dtor and
|
||||||
|
// assignment operator). Otherwise _particles could become a "resource leak" for large
|
||||||
|
// roaming piles of particles.
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ParticleTreeElement::findSpherePenetration(const glm::vec3& center, float radius,
|
bool ParticleTreeElement::findSpherePenetration(const glm::vec3& center, float radius,
|
||||||
glm::vec3& penetration, void** penetratedObject) const {
|
glm::vec3& penetration, void** penetratedObject) const {
|
||||||
|
|
||||||
uint16_t numberOfParticles = _particles.size();
|
QList<Particle>::iterator particleItr = _particles->begin();
|
||||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
QList<Particle>::const_iterator particleEnd = _particles->end();
|
||||||
glm::vec3 particleCenter = _particles[i].getPosition();
|
while(particleItr != particleEnd) {
|
||||||
float particleRadius = _particles[i].getRadius();
|
Particle& particle = (*particleItr);
|
||||||
|
glm::vec3 particleCenter = particle.getPosition();
|
||||||
|
float particleRadius = particle.getRadius();
|
||||||
|
|
||||||
// don't penetrate yourself
|
// don't penetrate yourself
|
||||||
if (particleCenter == center && particleRadius == radius) {
|
if (particleCenter == center && particleRadius == radius) {
|
||||||
|
@ -102,23 +112,28 @@ bool ParticleTreeElement::findSpherePenetration(const glm::vec3& center, float r
|
||||||
const bool IN_HAND_PARTICLES_DONT_COLLIDE = false;
|
const bool IN_HAND_PARTICLES_DONT_COLLIDE = false;
|
||||||
if (IN_HAND_PARTICLES_DONT_COLLIDE) {
|
if (IN_HAND_PARTICLES_DONT_COLLIDE) {
|
||||||
// don't penetrate if the particle is "inHand" -- they don't collide
|
// don't penetrate if the particle is "inHand" -- they don't collide
|
||||||
if (_particles[i].getInHand()) {
|
if (particle.getInHand()) {
|
||||||
return false;
|
++particleItr;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (findSphereSpherePenetration(center, radius, particleCenter, particleRadius, penetration)) {
|
if (findSphereSpherePenetration(center, radius, particleCenter, particleRadius, penetration)) {
|
||||||
*penetratedObject = (void*)&_particles[i];
|
// return true on first valid particle penetration
|
||||||
|
*penetratedObject = (void*)(&particle);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
++particleItr;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ParticleTreeElement::containsParticle(const Particle& particle) const {
|
bool ParticleTreeElement::containsParticle(const Particle& particle) const {
|
||||||
uint16_t numberOfParticles = _particles.size();
|
// TODO: remove this method and force callers to use getParticleWithID() instead
|
||||||
|
uint16_t numberOfParticles = _particles->size();
|
||||||
|
uint32_t particleID = particle.getID();
|
||||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||||
if (_particles[i].getID() == particle.getID()) {
|
if ((*_particles)[i].getID() == particleID) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,13 +141,17 @@ bool ParticleTreeElement::containsParticle(const Particle& particle) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ParticleTreeElement::updateParticle(const Particle& particle) {
|
bool ParticleTreeElement::updateParticle(const Particle& particle) {
|
||||||
|
// NOTE: this method must first lookup the particle by ID, hence it is O(N)
|
||||||
|
// and "particle is not found" is worst-case (full N) but maybe we don't care?
|
||||||
|
// (guaranteed that num particles per elemen is small?)
|
||||||
const bool wantDebug = false;
|
const bool wantDebug = false;
|
||||||
uint16_t numberOfParticles = _particles.size();
|
uint16_t numberOfParticles = _particles->size();
|
||||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||||
if (_particles[i].getID() == particle.getID()) {
|
Particle& thisParticle = (*_particles)[i];
|
||||||
int difference = _particles[i].getLastUpdated() - particle.getLastUpdated();
|
if (thisParticle.getID() == particle.getID()) {
|
||||||
bool changedOnServer = _particles[i].getLastEdited() < particle.getLastEdited();
|
int difference = thisParticle.getLastUpdated() - particle.getLastUpdated();
|
||||||
bool localOlder = _particles[i].getLastUpdated() < particle.getLastUpdated();
|
bool changedOnServer = thisParticle.getLastEdited() < particle.getLastEdited();
|
||||||
|
bool localOlder = thisParticle.getLastUpdated() < particle.getLastUpdated();
|
||||||
if (changedOnServer || localOlder) {
|
if (changedOnServer || localOlder) {
|
||||||
if (wantDebug) {
|
if (wantDebug) {
|
||||||
printf("local particle [id:%d] %s and %s than server particle by %d, particle.isNewlyCreated()=%s\n",
|
printf("local particle [id:%d] %s and %s than server particle by %d, particle.isNewlyCreated()=%s\n",
|
||||||
|
@ -140,7 +159,7 @@ bool ParticleTreeElement::updateParticle(const Particle& particle) {
|
||||||
(localOlder ? "OLDER" : "NEWER"),
|
(localOlder ? "OLDER" : "NEWER"),
|
||||||
difference, debug::valueOf(particle.isNewlyCreated()) );
|
difference, debug::valueOf(particle.isNewlyCreated()) );
|
||||||
}
|
}
|
||||||
_particles[i].copyChangedProperties(particle);
|
thisParticle.copyChangedProperties(particle);
|
||||||
} else {
|
} else {
|
||||||
if (wantDebug) {
|
if (wantDebug) {
|
||||||
printf(">>> IGNORING SERVER!!! Would've caused jutter! <<< "
|
printf(">>> IGNORING SERVER!!! Would've caused jutter! <<< "
|
||||||
|
@ -159,22 +178,23 @@ bool ParticleTreeElement::updateParticle(const Particle& particle) {
|
||||||
const Particle* ParticleTreeElement::getClosestParticle(glm::vec3 position) const {
|
const Particle* ParticleTreeElement::getClosestParticle(glm::vec3 position) const {
|
||||||
const Particle* closestParticle = NULL;
|
const Particle* closestParticle = NULL;
|
||||||
float closestParticleDistance = FLT_MAX;
|
float closestParticleDistance = FLT_MAX;
|
||||||
uint16_t numberOfParticles = _particles.size();
|
uint16_t numberOfParticles = _particles->size();
|
||||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||||
float distanceToParticle = glm::distance(position, _particles[i].getPosition());
|
float distanceToParticle = glm::distance(position, (*_particles)[i].getPosition());
|
||||||
if (distanceToParticle < closestParticleDistance) {
|
if (distanceToParticle < closestParticleDistance) {
|
||||||
closestParticle = &_particles[i];
|
closestParticle = &(*_particles)[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return closestParticle;
|
return closestParticle;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Particle* ParticleTreeElement::getParticleWithID(uint32_t id) const {
|
const Particle* ParticleTreeElement::getParticleWithID(uint32_t id) const {
|
||||||
|
// NOTE: this lookup is O(N) but maybe we don't care? (guaranteed that num particles per elemen is small?)
|
||||||
const Particle* foundParticle = NULL;
|
const Particle* foundParticle = NULL;
|
||||||
uint16_t numberOfParticles = _particles.size();
|
uint16_t numberOfParticles = _particles->size();
|
||||||
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
for (uint16_t i = 0; i < numberOfParticles; i++) {
|
||||||
if (_particles[i].getID() == id) {
|
if ((*_particles)[i].getID() == id) {
|
||||||
foundParticle = &_particles[i];
|
foundParticle = &(*_particles)[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,7 +249,7 @@ bool ParticleTreeElement::collapseChildren() {
|
||||||
|
|
||||||
|
|
||||||
void ParticleTreeElement::storeParticle(const Particle& particle, Node* senderNode) {
|
void ParticleTreeElement::storeParticle(const Particle& particle, Node* senderNode) {
|
||||||
_particles.push_back(particle);
|
_particles->push_back(particle);
|
||||||
markWithChangedTime();
|
markWithChangedTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,10 @@
|
||||||
#ifndef __hifi__ParticleTreeElement__
|
#ifndef __hifi__ParticleTreeElement__
|
||||||
#define __hifi__ParticleTreeElement__
|
#define __hifi__ParticleTreeElement__
|
||||||
|
|
||||||
#include <vector>
|
//#include <vector>
|
||||||
|
|
||||||
#include <OctreeElement.h>
|
#include <OctreeElement.h>
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
#include "Particle.h"
|
#include "Particle.h"
|
||||||
#include "ParticleTree.h"
|
#include "ParticleTree.h"
|
||||||
|
@ -22,7 +23,7 @@ class ParticleTreeElement;
|
||||||
|
|
||||||
class ParticleTreeUpdateArgs {
|
class ParticleTreeUpdateArgs {
|
||||||
public:
|
public:
|
||||||
std::vector<Particle> _movingParticles;
|
QList<Particle> _movingParticles;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ParticleTreeElement : public OctreeElement {
|
class ParticleTreeElement : public OctreeElement {
|
||||||
|
@ -34,7 +35,6 @@ class ParticleTreeElement : public OctreeElement {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~ParticleTreeElement();
|
virtual ~ParticleTreeElement();
|
||||||
virtual void init(unsigned char * octalCode);
|
|
||||||
|
|
||||||
// type safe versions of OctreeElement methods
|
// type safe versions of OctreeElement methods
|
||||||
ParticleTreeElement* getChildAtIndex(int index) { return (ParticleTreeElement*)OctreeElement::getChildAtIndex(index); }
|
ParticleTreeElement* getChildAtIndex(int index) { return (ParticleTreeElement*)OctreeElement::getChildAtIndex(index); }
|
||||||
|
@ -79,9 +79,9 @@ public:
|
||||||
virtual bool findSpherePenetration(const glm::vec3& center, float radius,
|
virtual bool findSpherePenetration(const glm::vec3& center, float radius,
|
||||||
glm::vec3& penetration, void** penetratedObject) const;
|
glm::vec3& penetration, void** penetratedObject) const;
|
||||||
|
|
||||||
const std::vector<Particle>& getParticles() const { return _particles; }
|
const QList<Particle>& getParticles() const { return *_particles; }
|
||||||
std::vector<Particle>& getParticles() { return _particles; }
|
QList<Particle>& getParticles() { return *_particles; }
|
||||||
bool hasParticles() const { return _particles.size() > 0; }
|
bool hasParticles() const { return _particles->size() > 0; }
|
||||||
|
|
||||||
void update(ParticleTreeUpdateArgs& args);
|
void update(ParticleTreeUpdateArgs& args);
|
||||||
void setTree(ParticleTree* tree) { _myTree = tree; }
|
void setTree(ParticleTree* tree) { _myTree = tree; }
|
||||||
|
@ -93,10 +93,12 @@ public:
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual void init(unsigned char * octalCode);
|
||||||
|
|
||||||
void storeParticle(const Particle& particle, Node* senderNode = NULL);
|
void storeParticle(const Particle& particle, Node* senderNode = NULL);
|
||||||
|
|
||||||
ParticleTree* _myTree;
|
ParticleTree* _myTree;
|
||||||
std::vector<Particle> _particles;
|
QList<Particle>* _particles;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__hifi__ParticleTreeElement__) */
|
#endif /* defined(__hifi__ParticleTreeElement__) */
|
||||||
|
|
|
@ -38,17 +38,20 @@ static QScriptValue soundConstructor(QScriptContext* context, QScriptEngine* eng
|
||||||
return soundScriptValue;
|
return soundScriptValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems,
|
ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, const QString& fileNameString, AbstractMenuInterface* menu,
|
||||||
const char* scriptMenuName, AbstractMenuInterface* menu,
|
|
||||||
AbstractControllerScriptingInterface* controllerScriptingInterface) {
|
AbstractControllerScriptingInterface* controllerScriptingInterface) {
|
||||||
_scriptContents = scriptContents;
|
_scriptContents = scriptContents;
|
||||||
_isFinished = false;
|
_isFinished = false;
|
||||||
_isRunning = false;
|
_isRunning = false;
|
||||||
_isInitialized = false;
|
_isInitialized = false;
|
||||||
|
_fileNameString = fileNameString;
|
||||||
|
|
||||||
|
QByteArray fileNameAscii = fileNameString.toLocal8Bit();
|
||||||
|
const char* scriptMenuName = fileNameAscii.data();
|
||||||
|
|
||||||
// some clients will use these menu features
|
// some clients will use these menu features
|
||||||
_wantMenuItems = wantMenuItems;
|
_wantMenuItems = wantMenuItems;
|
||||||
if (scriptMenuName) {
|
if (!fileNameString.isEmpty()) {
|
||||||
_scriptMenuName = "Stop ";
|
_scriptMenuName = "Stop ";
|
||||||
_scriptMenuName.append(scriptMenuName);
|
_scriptMenuName.append(scriptMenuName);
|
||||||
_scriptMenuName.append(QString(" [%1]").arg(_scriptNumber));
|
_scriptMenuName.append(QString(" [%1]").arg(_scriptNumber));
|
||||||
|
@ -233,9 +236,11 @@ void ScriptEngine::run() {
|
||||||
thread()->quit();
|
thread()->quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
emit finished();
|
emit finished(_fileNameString);
|
||||||
|
|
||||||
_isRunning = false;
|
_isRunning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::stop() {
|
void ScriptEngine::stop() {
|
||||||
_isFinished = true;
|
_isFinished = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ class ScriptEngine : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
ScriptEngine(const QString& scriptContents = NO_SCRIPT, bool wantMenuItems = false,
|
ScriptEngine(const QString& scriptContents = NO_SCRIPT, bool wantMenuItems = false,
|
||||||
const char* scriptMenuName = NULL, AbstractMenuInterface* menu = NULL,
|
const QString& scriptMenuName = QString(""), AbstractMenuInterface* menu = NULL,
|
||||||
AbstractControllerScriptingInterface* controllerScriptingInterface = NULL);
|
AbstractControllerScriptingInterface* controllerScriptingInterface = NULL);
|
||||||
|
|
||||||
~ScriptEngine();
|
~ScriptEngine();
|
||||||
|
@ -58,7 +58,7 @@ signals:
|
||||||
void willSendAudioDataCallback();
|
void willSendAudioDataCallback();
|
||||||
void willSendVisualDataCallback();
|
void willSendVisualDataCallback();
|
||||||
void scriptEnding();
|
void scriptEnding();
|
||||||
void finished();
|
void finished(const QString& fileNameString);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QString _scriptContents;
|
QString _scriptContents;
|
||||||
|
@ -74,6 +74,7 @@ private:
|
||||||
AudioScriptingInterface _audioScriptingInterface;
|
AudioScriptingInterface _audioScriptingInterface;
|
||||||
bool _wantMenuItems;
|
bool _wantMenuItems;
|
||||||
QString _scriptMenuName;
|
QString _scriptMenuName;
|
||||||
|
QString _fileNameString;
|
||||||
AbstractMenuInterface* _menu;
|
AbstractMenuInterface* _menu;
|
||||||
static int _scriptNumber;
|
static int _scriptNumber;
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,7 +20,7 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) {
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
case PACKET_TYPE_HEAD_DATA:
|
case PACKET_TYPE_HEAD_DATA:
|
||||||
return 14;
|
return 15;
|
||||||
|
|
||||||
case PACKET_TYPE_AVATAR_URLS:
|
case PACKET_TYPE_AVATAR_URLS:
|
||||||
return 2;
|
return 2;
|
||||||
|
|
Loading…
Reference in a new issue