Merge branch 'master' of https://github.com/worklist/hifi into 19361

This commit is contained in:
Geenz 2013-06-07 16:00:33 -04:00
commit c79bd71fe7
14 changed files with 178 additions and 141 deletions

View file

@ -531,7 +531,7 @@ float billboardGradientIncrement = 0.01f;
const float BILLBOARD_MAX_GRADIENT = 1.0f; const float BILLBOARD_MAX_GRADIENT = 1.0f;
const float BILLBOARD_MIN_GRADIENT = 0.0f; const float BILLBOARD_MIN_GRADIENT = 0.0f;
const float BILLBOARD_LIGHT_SIZE = 0.125f / TREE_SCALE; // approximately 1/8 meter per light const float BILLBOARD_LIGHT_SIZE = 0.125f / TREE_SCALE; // approximately 1/8 meter per light
const int VOXELS_PER_PACKET = 100; const int VOXELS_PER_PACKET = 81;
const int PACKETS_PER_BILLBOARD = VOXELS_PER_PACKET / (BILLBOARD_HEIGHT * BILLBOARD_WIDTH); const int PACKETS_PER_BILLBOARD = VOXELS_PER_PACKET / (BILLBOARD_HEIGHT * BILLBOARD_WIDTH);

View file

@ -87,13 +87,19 @@ find_package(GLM REQUIRED)
find_package(LodePNG REQUIRED) find_package(LodePNG REQUIRED)
find_package(LibOVR) find_package(LibOVR)
# include headers for external libraries and InterfaceConfig. # include headers for interface and InterfaceConfig.
include_directories( include_directories(
${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/src
${PROJECT_BINARY_DIR}/includes ${PROJECT_BINARY_DIR}/includes
${GLM_INCLUDE_DIRS} )
${LODEPNG_INCLUDE_DIRS}
${LIBOVR_INCLUDE_DIRS} # include external library headers
# use system flag so warnings are supressed
include_directories(
SYSTEM
${GLM_INCLUDE_DIRS}
${LODEPNG_INCLUDE_DIRS}
${LIBOVR_INCLUDE_DIRS}
) )
target_link_libraries(${TARGET_NAME} ${QT_LIBRARIES}) target_link_libraries(${TARGET_NAME} ${QT_LIBRARIES})

View file

@ -26,6 +26,7 @@
#include <QColorDialog> #include <QColorDialog>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QDesktopWidget> #include <QDesktopWidget>
#include <QDoubleSpinBox>
#include <QFormLayout> #include <QFormLayout>
#include <QGLWidget> #include <QGLWidget>
#include <QKeyEvent> #include <QKeyEvent>
@ -311,11 +312,11 @@ void Application::paintGL() {
} else if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { } else if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
_myCamera.setTightness(0.0f); // In first person, camera follows head exactly without delay _myCamera.setTightness(0.0f); // In first person, camera follows head exactly without delay
_myCamera.setTargetPosition(_myAvatar.getBallPosition(AVATAR_JOINT_HEAD_BASE)); _myCamera.setTargetPosition(_myAvatar.getBallPosition(AVATAR_JOINT_HEAD_BASE));
_myCamera.setTargetRotation(_myAvatar.getHead().getWorldAlignedOrientation()); _myCamera.setTargetRotation(_myAvatar.getHead().getCameraOrientation(_headCameraPitchYawScale));
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
_myCamera.setTargetPosition(_myAvatar.getHeadJointPosition()); _myCamera.setTargetPosition(_myAvatar.getHeadJointPosition());
_myCamera.setTargetRotation(_myAvatar.getHead().getWorldAlignedOrientation()); _myCamera.setTargetRotation(_myAvatar.getHead().getCameraOrientation(_headCameraPitchYawScale));
} }
// Update camera position // Update camera position
@ -1039,6 +1040,10 @@ void Application::editPreferences() {
avatarURL->setMinimumWidth(400); avatarURL->setMinimumWidth(400);
form->addRow("Avatar URL:", avatarURL); form->addRow("Avatar URL:", avatarURL);
QDoubleSpinBox* headCameraPitchYawScale = new QDoubleSpinBox();
headCameraPitchYawScale->setValue(_headCameraPitchYawScale);
form->addRow("Head Camera Pitch/Yaw Scale:", headCameraPitchYawScale);
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept())); dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept()));
dialog.connect(buttons, SIGNAL(rejected()), SLOT(reject())); dialog.connect(buttons, SIGNAL(rejected()), SLOT(reject()));
@ -1051,6 +1056,8 @@ void Application::editPreferences() {
_settings->setValue("avatarURL", url); _settings->setValue("avatarURL", url);
_myAvatar.getVoxels()->setVoxelURL(url); _myAvatar.getVoxels()->setVoxelURL(url);
sendAvatarVoxelURLMessage(url); sendAvatarVoxelURLMessage(url);
_headCameraPitchYawScale = headCameraPitchYawScale->value();
} }
void Application::pair() { void Application::pair() {
@ -1157,33 +1164,10 @@ static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) {
if (createVoxelEditMessage(header, 0, 1, &detail, bufferOut, sizeOut)){ if (createVoxelEditMessage(header, 0, 1, &detail, bufferOut, sizeOut)){
AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1); AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1);
delete bufferOut; delete[] bufferOut;
} }
} }
void Application::addVoxelInFrontOfAvatar() {
VoxelDetail detail;
glm::vec3 position = (_myAvatar.getPosition() + _myAvatar.calculateCameraDirection()) * (1.0f / TREE_SCALE);
detail.s = _mouseVoxelScale;
detail.x = detail.s * floor(position.x / detail.s);
detail.y = detail.s * floor(position.y / detail.s);
detail.z = detail.s * floor(position.z / detail.s);
QColor paintColor = _voxelPaintColor->data().value<QColor>();
detail.red = paintColor.red();
detail.green = paintColor.green();
detail.blue = paintColor.blue();
PACKET_HEADER message = (_destructiveAddVoxel->isChecked() ?
PACKET_HEADER_SET_VOXEL_DESTRUCTIVE : PACKET_HEADER_SET_VOXEL);
sendVoxelEditMessage(message, detail);
// create the voxel locally so it appears immediately
_voxels.createVoxel(detail.x, detail.y, detail.z, detail.s,
detail.red, detail.green, detail.blue, _destructiveAddVoxel->isChecked());
}
void Application::decreaseVoxelSize() { void Application::decreaseVoxelSize() {
_mouseVoxelScale /= 2; _mouseVoxelScale /= 2;
} }
@ -1316,7 +1300,7 @@ void Application::importVoxels() {
} }
if (calculatedOctCode) { if (calculatedOctCode) {
delete calculatedOctCode; delete[] calculatedOctCode;
} }
// restore the main window's active state // restore the main window's active state
@ -1368,7 +1352,7 @@ void Application::pasteVoxels() {
} }
if (calculatedOctCode) { if (calculatedOctCode) {
delete calculatedOctCode; delete[] calculatedOctCode;
} }
} }
@ -1450,7 +1434,6 @@ void Application::initMenu() {
"Get Color Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::Key_G))->setCheckable(true); "Get Color Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::Key_G))->setCheckable(true);
_voxelModeActions->addAction(_eyedropperMode); _voxelModeActions->addAction(_eyedropperMode);
voxelMenu->addAction("Place New Voxel", this, SLOT(addVoxelInFrontOfAvatar()), Qt::CTRL | Qt::Key_N);
voxelMenu->addAction("Decrease Voxel Size", this, SLOT(decreaseVoxelSize()), QKeySequence::ZoomOut); voxelMenu->addAction("Decrease Voxel Size", this, SLOT(decreaseVoxelSize()), QKeySequence::ZoomOut);
voxelMenu->addAction("Increase Voxel Size", this, SLOT(increaseVoxelSize()), QKeySequence::ZoomIn); voxelMenu->addAction("Increase Voxel Size", this, SLOT(increaseVoxelSize()), QKeySequence::ZoomIn);
@ -1467,7 +1450,9 @@ void Application::initMenu() {
voxelMenu->addAction("Copy Voxels", this, SLOT(copyVoxels()), Qt::CTRL | Qt::Key_C); voxelMenu->addAction("Copy Voxels", this, SLOT(copyVoxels()), Qt::CTRL | Qt::Key_C);
voxelMenu->addAction("Paste Voxels", this, SLOT(pasteVoxels()), Qt::CTRL | Qt::Key_V); voxelMenu->addAction("Paste Voxels", this, SLOT(pasteVoxels()), Qt::CTRL | Qt::Key_V);
QMenu* frustumMenu = menuBar->addMenu("Frustum"); QMenu* debugMenu = menuBar->addMenu("Debug");
QMenu* frustumMenu = debugMenu->addMenu("View Frustum Debugging Tools");
(_frustumOn = frustumMenu->addAction("Display Frustum"))->setCheckable(true); (_frustumOn = frustumMenu->addAction("Display Frustum"))->setCheckable(true);
_frustumOn->setShortcut(Qt::SHIFT | Qt::Key_F); _frustumOn->setShortcut(Qt::SHIFT | Qt::Key_F);
(_viewFrustumFromOffset = frustumMenu->addAction( (_viewFrustumFromOffset = frustumMenu->addAction(
@ -1479,16 +1464,19 @@ void Application::initMenu() {
"Render Mode", this, SLOT(cycleFrustumRenderMode()), Qt::SHIFT | Qt::Key_R); "Render Mode", this, SLOT(cycleFrustumRenderMode()), Qt::SHIFT | Qt::Key_R);
updateFrustumRenderModeAction(); updateFrustumRenderModeAction();
QMenu* debugMenu = menuBar->addMenu("Debug"); debugMenu->addAction("Run Timing Tests", this, SLOT(runTests()));
debugMenu->addAction("Show Render Pipeline Warnings", this, SLOT(setRenderWarnings(bool)))->setCheckable(true);
debugMenu->addAction("Kill Local Voxels", this, SLOT(doKillLocalVoxels()));
debugMenu->addAction("Randomize Voxel TRUE Colors", this, SLOT(doRandomizeVoxelColors()), Qt::CTRL | Qt::Key_R);
debugMenu->addAction("FALSE Color Voxels Randomly", this, SLOT(doFalseRandomizeVoxelColors()));
debugMenu->addAction("FALSE Color Voxel Every Other Randomly", this, SLOT(doFalseRandomizeEveryOtherVoxelColors()));
debugMenu->addAction("FALSE Color Voxels by Distance", this, SLOT(doFalseColorizeByDistance()));
debugMenu->addAction("FALSE Color Voxel Out of View", this, SLOT(doFalseColorizeInView()));
debugMenu->addAction("Show TRUE Colors", this, SLOT(doTrueVoxelColors()));
debugMenu->addAction("Calculate Tree Stats", this, SLOT(doTreeStats()), Qt::SHIFT | Qt::Key_S); debugMenu->addAction("Calculate Tree Stats", this, SLOT(doTreeStats()), Qt::SHIFT | Qt::Key_S);
QMenu* renderDebugMenu = debugMenu->addMenu("Render Debugging Tools");
renderDebugMenu->addAction("Show Render Pipeline Warnings", this, SLOT(setRenderWarnings(bool)))->setCheckable(true);
renderDebugMenu->addAction("Kill Local Voxels", this, SLOT(doKillLocalVoxels()), Qt::CTRL | Qt::Key_K);
renderDebugMenu->addAction("Randomize Voxel TRUE Colors", this, SLOT(doRandomizeVoxelColors()), Qt::CTRL | Qt::Key_R);
renderDebugMenu->addAction("FALSE Color Voxels Randomly", this, SLOT(doFalseRandomizeVoxelColors()));
renderDebugMenu->addAction("FALSE Color Voxel Every Other Randomly", this, SLOT(doFalseRandomizeEveryOtherVoxelColors()));
renderDebugMenu->addAction("FALSE Color Voxels by Distance", this, SLOT(doFalseColorizeByDistance()));
renderDebugMenu->addAction("FALSE Color Voxel Out of View", this, SLOT(doFalseColorizeInView()));
renderDebugMenu->addAction("Show TRUE Colors", this, SLOT(doTrueVoxelColors()));
debugMenu->addAction("Wants Res-In", this, SLOT(setWantsResIn(bool)))->setCheckable(true); debugMenu->addAction("Wants Res-In", this, SLOT(setWantsResIn(bool)))->setCheckable(true);
debugMenu->addAction("Wants Monochrome", this, SLOT(setWantsMonochrome(bool)))->setCheckable(true); debugMenu->addAction("Wants Monochrome", this, SLOT(setWantsMonochrome(bool)))->setCheckable(true);
debugMenu->addAction("Wants View Delta Sending", this, SLOT(setWantsDelta(bool)))->setCheckable(true); debugMenu->addAction("Wants View Delta Sending", this, SLOT(setWantsDelta(bool)))->setCheckable(true);
@ -1526,6 +1514,10 @@ void Application::updateFrustumRenderModeAction() {
} }
} }
void Application::runTests() {
runTimingTests();
}
void Application::initDisplay() { void Application::initDisplay() {
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@ -2552,15 +2544,19 @@ void Application::setAutosave(bool wantsAutosave) {
void Application::loadSettings(QSettings* set) { void Application::loadSettings(QSettings* set) {
if (!set) set = getSettings(); if (!set) set = getSettings();
_headCameraPitchYawScale = set->value("headCameraPitchYawScale", 0.0f).toFloat();
scanMenuBar(&Application::loadAction, set); scanMenuBar(&Application::loadAction, set);
getAvatar()->loadData(set); getAvatar()->loadData(set);
} }
void Application::saveSettings(QSettings* set) { void Application::saveSettings(QSettings* set) {
if (!set) set = getSettings(); if (!set) set = getSettings();
set->setValue("headCameraPitchYawScale", _headCameraPitchYawScale);
scanMenuBar(&Application::saveAction, set); scanMenuBar(&Application::saveAction, set);
getAvatar()->saveData(set); getAvatar()->saveData(set);
set->sync();
} }
void Application::importSettings() { void Application::importSettings() {

View file

@ -109,7 +109,6 @@ private slots:
void setWantsResIn(bool wantsResIn); void setWantsResIn(bool wantsResIn);
void setWantsDelta(bool wantsDelta); void setWantsDelta(bool wantsDelta);
void updateVoxelModeActions(); void updateVoxelModeActions();
void addVoxelInFrontOfAvatar();
void decreaseVoxelSize(); void decreaseVoxelSize();
void increaseVoxelSize(); void increaseVoxelSize();
void chooseVoxelPaintColor(); void chooseVoxelPaintColor();
@ -123,6 +122,7 @@ private slots:
void cutVoxels(); void cutVoxels();
void copyVoxels(); void copyVoxels();
void pasteVoxels(); void pasteVoxels();
void runTests();
private: private:
static bool sendVoxelsOperation(VoxelNode* node, void* extraData); static bool sendVoxelsOperation(VoxelNode* node, void* extraData);
@ -248,6 +248,7 @@ private:
int _headMouseX, _headMouseY; int _headMouseX, _headMouseY;
bool _manualFirstPerson; bool _manualFirstPerson;
float _headCameraPitchYawScale;
HandControl _handControl; HandControl _handControl;

View file

@ -62,37 +62,35 @@ float chatMessageScale = 0.0015;
float chatMessageHeight = 0.20; float chatMessageHeight = 0.20;
Avatar::Avatar(Agent* owningAgent) : Avatar::Avatar(Agent* owningAgent) :
AvatarData(owningAgent), AvatarData(owningAgent),
_initialized(false), _initialized(false),
_head(this), _head(this),
_ballSpringsInitialized(false), _ballSpringsInitialized(false),
_TEST_bigSphereRadius(0.5f), _TEST_bigSphereRadius(0.5f),
_TEST_bigSpherePosition(5.0f, _TEST_bigSphereRadius, 5.0f), _TEST_bigSpherePosition(5.0f, _TEST_bigSphereRadius, 5.0f),
_mousePressed(false), _mousePressed(false),
_bodyPitchDelta(0.0f), _bodyPitchDelta(0.0f),
_bodyYawDelta(0.0f), _bodyYawDelta(0.0f),
_bodyRollDelta(0.0f), _bodyRollDelta(0.0f),
_movedHandOffset(0.0f, 0.0f, 0.0f), _movedHandOffset(0.0f, 0.0f, 0.0f),
_mode(AVATAR_MODE_STANDING), _mode(AVATAR_MODE_STANDING),
_cameraPosition(0.0f, 0.0f, 0.0f), _cameraPosition(0.0f, 0.0f, 0.0f),
_handHoldingPosition(0.0f, 0.0f, 0.0f), _handHoldingPosition(0.0f, 0.0f, 0.0f),
_velocity(0.0f, 0.0f, 0.0f), _velocity(0.0f, 0.0f, 0.0f),
_thrust(0.0f, 0.0f, 0.0f), _thrust(0.0f, 0.0f, 0.0f),
_speed(0.0f), _speed(0.0f),
_maxArmLength(0.0f), _maxArmLength(0.0f),
_pelvisStandingHeight(0.0f), _pelvisStandingHeight(0.0f),
_pelvisFloatingHeight(0.0f), _pelvisFloatingHeight(0.0f),
_distanceToNearestAvatar(std::numeric_limits<float>::max()), _distanceToNearestAvatar(std::numeric_limits<float>::max()),
_gravity(0.0f, -1.0f, 0.0f), _gravity(0.0f, -1.0f, 0.0f),
_worldUpDirection(DEFAULT_UP_DIRECTION), _worldUpDirection(DEFAULT_UP_DIRECTION),
_mouseRayOrigin(0.0f, 0.0f, 0.0f), _mouseRayOrigin(0.0f, 0.0f, 0.0f),
_mouseRayDirection(0.0f, 0.0f, 0.0f), _mouseRayDirection(0.0f, 0.0f, 0.0f),
_interactingOther(NULL), _interactingOther(NULL),
_isMouseTurningRight(false), _isMouseTurningRight(false),
_voxels(this) _voxels(this)
{ {
// give the pointer to our head to inherited _headData variable from AvatarData // give the pointer to our head to inherited _headData variable from AvatarData
_headData = &_head; _headData = &_head;
@ -319,9 +317,9 @@ glm::quat Avatar::getWorldAlignedOrientation () const {
void Avatar::updateFromMouse(int mouseX, int mouseY, int screenWidth, int screenHeight) { void Avatar::updateFromMouse(int mouseX, int mouseY, int screenWidth, int screenHeight) {
// Update head yaw and pitch based on mouse input // Update head yaw and pitch based on mouse input
const float MOUSE_MOVE_RADIUS = 0.15f; const float MOUSE_MOVE_RADIUS = 0.3f;
const float MOUSE_ROTATE_SPEED = 4.0f; const float MOUSE_ROTATE_SPEED = 4.0f;
const float MOUSE_PITCH_SPEED = 1.5f; const float MOUSE_PITCH_SPEED = 2.0f;
const int TITLE_BAR_HEIGHT = 46; const int TITLE_BAR_HEIGHT = 46;
float mouseLocationX = (float)mouseX / (float)screenWidth - 0.5f; float mouseLocationX = (float)mouseX / (float)screenWidth - 0.5f;
float mouseLocationY = (float)mouseY / (float)screenHeight - 0.5f; float mouseLocationY = (float)mouseY / (float)screenHeight - 0.5f;
@ -659,7 +657,7 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
//loop through all the other avatars for potential interactions... //loop through all the other avatars for potential interactions...
AgentList* agentList = AgentList::getInstance(); AgentList* agentList = AgentList::getInstance();
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) { if (agent->getLinkedData() && agent->getType() == AGENT_TYPE_AVATAR) {
Avatar *otherAvatar = (Avatar *)agent->getLinkedData(); Avatar *otherAvatar = (Avatar *)agent->getLinkedData();
// test whether shoulders are close enough to allow for reaching to touch hands // test whether shoulders are close enough to allow for reaching to touch hands
@ -828,7 +826,7 @@ void Avatar::updateAvatarCollisions(float deltaTime) {
// loop through all the other avatars for potential interactions... // loop through all the other avatars for potential interactions...
AgentList* agentList = AgentList::getInstance(); AgentList* agentList = AgentList::getInstance();
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) { if (agent->getLinkedData() && agent->getType() == AGENT_TYPE_AVATAR) {
Avatar *otherAvatar = (Avatar *)agent->getLinkedData(); Avatar *otherAvatar = (Avatar *)agent->getLinkedData();
// check if the bounding spheres of the two avatars are colliding // check if the bounding spheres of the two avatars are colliding

View file

@ -314,10 +314,10 @@ glm::quat Head::getOrientation() const {
glm::vec3(_pitch, -_yaw, -_roll) : glm::vec3(_pitch, _yaw, _roll))); glm::vec3(_pitch, -_yaw, -_roll) : glm::vec3(_pitch, _yaw, _roll)));
} }
glm::quat Head::getWorldAlignedOrientation () const { glm::quat Head::getCameraOrientation (float pitchYawScale) const {
Avatar* owningAvatar = static_cast<Avatar*>(_owningAvatar); Avatar* owningAvatar = static_cast<Avatar*>(_owningAvatar);
return owningAvatar->getWorldAlignedOrientation() * glm::quat(glm::radians(_lookingInMirror ? return owningAvatar->getWorldAlignedOrientation() * glm::quat(glm::radians(glm::vec3(
glm::vec3(_pitch, -_yaw, -_roll) : glm::vec3(_pitch, _yaw, _roll))); _pitch * pitchYawScale, _yaw * pitchYawScale, 0.0f)));
} }
void Head::renderHeadSphere() { void Head::renderHeadSphere() {

View file

@ -47,7 +47,7 @@ public:
void setRenderLookatVectors(bool onOff ) { _renderLookatVectors = onOff; } void setRenderLookatVectors(bool onOff ) { _renderLookatVectors = onOff; }
glm::quat getOrientation() const; glm::quat getOrientation() const;
glm::quat getWorldAlignedOrientation () const; glm::quat getCameraOrientation (float pitchYawScale) const;
glm::vec3 getRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } glm::vec3 getRightDirection() const { return getOrientation() * IDENTITY_RIGHT; }
glm::vec3 getUpDirection () const { return getOrientation() * IDENTITY_UP; } glm::vec3 getUpDirection () const { return getOrientation() * IDENTITY_UP; }

View file

@ -6,6 +6,7 @@
// //
#include "SerialInterface.h" #include "SerialInterface.h"
#include "Util.h"
#include <glm/gtx/vector_angle.hpp> #include <glm/gtx/vector_angle.hpp>
#include <math.h> #include <math.h>
@ -17,7 +18,7 @@
const short NO_READ_MAXIMUM_MSECS = 3000; const short NO_READ_MAXIMUM_MSECS = 3000;
const int GRAVITY_SAMPLES = 60; // Use the first few samples to baseline values const int GRAVITY_SAMPLES = 60; // Use the first few samples to baseline values
const int SENSOR_FUSION_SAMPLES = 200; const int SENSOR_FUSION_SAMPLES = 20;
const int LONG_TERM_RATE_SAMPLES = 1000; const int LONG_TERM_RATE_SAMPLES = 1000;
const bool USING_INVENSENSE_MPU9150 = 1; const bool USING_INVENSENSE_MPU9150 = 1;
@ -214,7 +215,7 @@ void SerialInterface::readData(float deltaTime) {
// From MPU-9150 register map, with setting on // From MPU-9150 register map, with setting on
// highest resolution = +/- 2G // highest resolution = +/- 2G
_lastAcceleration = glm::vec3(accelXRate, accelYRate, -accelZRate) * LSB_TO_METERS_PER_SECOND2; _lastAcceleration = glm::vec3(-accelXRate, -accelYRate, -accelZRate) * LSB_TO_METERS_PER_SECOND2;
int rollRate, yawRate, pitchRate; int rollRate, yawRate, pitchRate;
@ -229,8 +230,8 @@ void SerialInterface::readData(float deltaTime) {
_lastRotationRates[2] = ((float) -rollRate) * LSB_TO_DEGREES_PER_SECOND; _lastRotationRates[2] = ((float) -rollRate) * LSB_TO_DEGREES_PER_SECOND;
// Update raw rotation estimates // Update raw rotation estimates
_estimatedRotation += deltaTime * (_lastRotationRates - _averageRotationRates); glm::quat estimatedRotation = glm::quat(glm::radians(_estimatedRotation)) *
glm::quat(glm::radians(deltaTime * (_lastRotationRates - _averageRotationRates)));
// Update estimated position and velocity // Update estimated position and velocity
float const DECAY_VELOCITY = 0.95f; float const DECAY_VELOCITY = 0.95f;
@ -258,29 +259,19 @@ void SerialInterface::readData(float deltaTime) {
1.f/(float)GRAVITY_SAMPLES * _lastAcceleration; 1.f/(float)GRAVITY_SAMPLES * _lastAcceleration;
} else { } else {
// Use gravity reading to do sensor fusion on the pitch and roll estimation // Use gravity reading to do sensor fusion on the pitch and roll estimation
float truePitchAngle = glm::angle(glm::normalize(glm::vec3(0, _gravity.y, _gravity.z)), estimatedRotation = safeMix(estimatedRotation,
glm::normalize(glm::vec3(0, _lastAcceleration.y, _lastAcceleration.z))) rotationBetween(estimatedRotation * _lastAcceleration, _gravity) * estimatedRotation,
* ((_lastAcceleration.z > _gravity.z) ? -1.0 : 1.0); 1.0f / SENSOR_FUSION_SAMPLES);
float trueRollAngle = glm::angle(glm::normalize(glm::vec3(_gravity.x, _gravity.y, 0)),
glm::normalize(glm::vec3(_lastAcceleration.x, _lastAcceleration.y, 0)))
* ((_lastAcceleration.x > _gravity.x) ? -1.0 : 1.0);
// PER: BUG: This is bizarre, because glm::angle() SOMETIMES returns NaN for what seem to
// be perfectly valid inputs. So I added these NaN tests, gotta fix.
if (!glm::isnan(truePitchAngle) && !glm::isnan(trueRollAngle)) {
_estimatedRotation.x = (1.f - 1.f/(float)SENSOR_FUSION_SAMPLES) * _estimatedRotation.x
+ 1.f/(float)SENSOR_FUSION_SAMPLES * truePitchAngle;
_estimatedRotation.z = (1.f - 1.f/(float)SENSOR_FUSION_SAMPLES) * _estimatedRotation.z
+ 1.f/(float)SENSOR_FUSION_SAMPLES * trueRollAngle;
// Without a compass heading, always decay estimated Yaw slightly
const float YAW_DECAY = 0.995;
_estimatedRotation.y *= YAW_DECAY;
}
// Without a compass heading, always decay estimated Yaw slightly
const float YAW_DECAY = 0.999f;
glm::vec3 forward = estimatedRotation * glm::vec3(0.0f, 0.0f, -1.0f);
estimatedRotation = safeMix(glm::angleAxis(glm::degrees(atan2f(forward.x, -forward.z)),
glm::vec3(0.0f, 1.0f, 0.0f)) * estimatedRotation, estimatedRotation, YAW_DECAY);
} }
} }
_estimatedRotation = safeEulerAngles(estimatedRotation);
totalSamples++; totalSamples++;
} }

View file

@ -9,6 +9,8 @@
#include "InterfaceConfig.h" #include "InterfaceConfig.h"
#include <iostream> #include <iostream>
#include <cstring> #include <cstring>
#include <time.h>
#include <math.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/noise.hpp> #include <glm/gtc/noise.hpp>
@ -21,6 +23,7 @@
#include "world.h" #include "world.h"
#include "Util.h" #include "Util.h"
#include "VoxelConstants.h" #include "VoxelConstants.h"
using namespace std; using namespace std;
@ -448,6 +451,53 @@ bool closeEnoughForGovernmentWork(float a, float b) {
return (distance < 0.00001f); return (distance < 0.00001f);
} }
// Do some basic timing tests and report the results
void runTimingTests() {
// How long does it take to make a call to get the time?
const int numTests = 1000000;
int iResults[numTests];
float fTest = 1.0;
float fResults[numTests];
timeval startTime, endTime;
float elapsedMsecs;
gettimeofday(&startTime, NULL);
for (int i = 1; i < numTests; i++) {
gettimeofday(&endTime, NULL);
}
elapsedMsecs = diffclock(&startTime, &endTime);
printLog("gettimeofday() usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests);
// Random number generation
gettimeofday(&startTime, NULL);
for (int i = 1; i < numTests; i++) {
iResults[i] = rand();
}
gettimeofday(&endTime, NULL);
elapsedMsecs = diffclock(&startTime, &endTime);
printLog("rand() stored in array usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests);
// Random number generation using randFloat()
gettimeofday(&startTime, NULL);
for (int i = 1; i < numTests; i++) {
fResults[i] = randFloat();
}
gettimeofday(&endTime, NULL);
elapsedMsecs = diffclock(&startTime, &endTime);
printLog("randFloat() stored in array usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests);
// PowF function
fTest = 1145323.2342f;
gettimeofday(&startTime, NULL);
for (int i = 1; i < numTests; i++) {
fTest = powf(fTest, 0.5f);
}
gettimeofday(&endTime, NULL);
elapsedMsecs = diffclock(&startTime, &endTime);
printLog("powf(f, 0.5) usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests);
}

View file

@ -64,4 +64,6 @@ void renderOrientationDirections( glm::vec3 position, const glm::quat& orientati
void renderSphereOutline(glm::vec3 position, float radius, int numSides, glm::vec3 cameraPosition); void renderSphereOutline(glm::vec3 position, float radius, int numSides, glm::vec3 cameraPosition);
void renderCircle(glm::vec3 position, float radius, glm::vec3 surfaceNormal, int numSides ); void renderCircle(glm::vec3 position, float radius, glm::vec3 surfaceNormal, int numSides );
void runTimingTests();
#endif #endif

View file

@ -18,8 +18,6 @@
#include "Application.h" #include "Application.h"
#include "Log.h" #include "Log.h"
#include <OctalCode.h>
int main(int argc, const char * argv[]) { int main(int argc, const char * argv[]) {
timeval startup_time; timeval startup_time;
gettimeofday(&startup_time, NULL); gettimeofday(&startup_time, NULL);

View file

@ -223,7 +223,7 @@ bool createVoxelEditMessage(unsigned char command, short int sequence,
actualMessageSize+=lengthOfVoxelData; actualMessageSize+=lengthOfVoxelData;
} }
// cleanup // cleanup
delete voxelData; delete[] voxelData;
} }
if (success) { if (success) {

View file

@ -260,8 +260,7 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int
void VoxelTree::deleteVoxelAt(float x, float y, float z, float s, bool stage) { void VoxelTree::deleteVoxelAt(float x, float y, float z, float s, bool stage) {
unsigned char* octalCode = pointToVoxel(x,y,z,s,0,0,0); unsigned char* octalCode = pointToVoxel(x,y,z,s,0,0,0);
deleteVoxelCodeFromTree(octalCode, stage); deleteVoxelCodeFromTree(octalCode, stage);
delete octalCode; // cleanup memory delete[] octalCode; // cleanup memory
reaverageVoxelColors(rootNode);
} }
@ -365,9 +364,6 @@ void VoxelTree::deleteVoxelCodeFromTreeRecursion(VoxelNode* node, void* extraDat
childNode->stageForDeletion(); childNode->stageForDeletion();
} else { } else {
node->deleteChildAtIndex(childIndex); // note: this will track dirtiness and lastChanged for this node node->deleteChildAtIndex(childIndex); // note: this will track dirtiness and lastChanged for this node
if (_shouldReaverage) {
node->setColorFromAverageOfChildren();
}
} }
// track our tree dirtiness // track our tree dirtiness
@ -503,7 +499,6 @@ void VoxelTree::processRemoveVoxelBitstream(unsigned char * bitstream, int buffe
voxelCode+=voxelDataSize; voxelCode+=voxelDataSize;
atByte+=voxelDataSize; atByte+=voxelDataSize;
} }
reaverageVoxelColors(rootNode); // Fix our colors!! Need to call it on rootNode
} }
void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { void VoxelTree::printTreeForDebugging(VoxelNode *startNode) {
@ -552,6 +547,7 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) {
} }
} }
// Note: this is an expensive call. Don't call it unless you really need to reaverage the entire tree (from startNode)
void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) { void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) {
// if our tree is a reaveraging tree, then we do this, otherwise we don't do anything // if our tree is a reaveraging tree, then we do this, otherwise we don't do anything
if (_shouldReaverage) { if (_shouldReaverage) {
@ -631,7 +627,7 @@ VoxelNode* VoxelTree::getVoxelAt(float x, float y, float z, float s) const {
if (*node->getOctalCode() != *octalCode) { if (*node->getOctalCode() != *octalCode) {
node = NULL; node = NULL;
} }
delete octalCode; // cleanup memory delete[] octalCode; // cleanup memory
return node; return node;
} }
@ -639,7 +635,7 @@ void VoxelTree::createVoxel(float x, float y, float z, float s,
unsigned char red, unsigned char green, unsigned char blue, bool destructive) { unsigned char red, unsigned char green, unsigned char blue, bool destructive) {
unsigned char* voxelData = pointToVoxel(x,y,z,s,red,green,blue); unsigned char* voxelData = pointToVoxel(x,y,z,s,red,green,blue);
this->readCodeColorBufferToTree(voxelData, destructive); this->readCodeColorBufferToTree(voxelData, destructive);
delete voxelData; delete[] voxelData;
} }
@ -785,7 +781,6 @@ void VoxelTree::createSphere(float radius, float xc, float yc, float zc, float v
thisRadius += thisVoxelSize; thisRadius += thisVoxelSize;
thisVoxelSize = std::max(voxelSize, thisVoxelSize / 2.0f); thisVoxelSize = std::max(voxelSize, thisVoxelSize / 2.0f);
} }
this->reaverageVoxelColors(this->rootNode);
} }
int VoxelTree::searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag, int VoxelTree::searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag,

View file

@ -51,7 +51,7 @@ const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4;
const int ENVIRONMENT_SEND_INTERVAL_USECS = 1000000; const int ENVIRONMENT_SEND_INTERVAL_USECS = 1000000;
VoxelTree randomTree(false); // this is NOT a reaveraging tree VoxelTree serverTree(true); // this IS a reaveraging tree
bool wantVoxelPersist = true; bool wantVoxelPersist = true;
bool wantLocalDomain = false; bool wantLocalDomain = false;
@ -98,7 +98,7 @@ void randomlyFillVoxelTree(int levelsToGo, VoxelNode *currentRootNode) {
void eraseVoxelTreeAndCleanupAgentVisitData() { void eraseVoxelTreeAndCleanupAgentVisitData() {
// As our tree to erase all it's voxels // As our tree to erase all it's voxels
::randomTree.eraseAllVoxels(); ::serverTree.eraseAllVoxels();
// enumerate the agents clean up their marker nodes // enumerate the agents clean up their marker nodes
for (AgentList::iterator agent = AgentList::getInstance()->begin(); agent != AgentList::getInstance()->end(); agent++) { for (AgentList::iterator agent = AgentList::getInstance()->begin(); agent != AgentList::getInstance()->end(); agent++) {
VoxelAgentData* agentData = (VoxelAgentData*) agent->getLinkedData(); VoxelAgentData* agentData = (VoxelAgentData*) agent->getLinkedData();
@ -123,7 +123,7 @@ void resInVoxelDistributor(AgentList* agentList,
searchLoops++; searchLoops++;
searchLevelWas = agentData->getMaxSearchLevel(); searchLevelWas = agentData->getMaxSearchLevel();
int maxLevelReached = randomTree.searchForColoredNodes(agentData->getMaxSearchLevel(), randomTree.rootNode, int maxLevelReached = serverTree.searchForColoredNodes(agentData->getMaxSearchLevel(), serverTree.rootNode,
viewFrustum, agentData->nodeBag); viewFrustum, agentData->nodeBag);
agentData->setMaxLevelReached(maxLevelReached); agentData->setMaxLevelReached(maxLevelReached);
@ -167,7 +167,7 @@ void resInVoxelDistributor(AgentList* agentList,
while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) { while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) {
if (!agentData->nodeBag.isEmpty()) { if (!agentData->nodeBag.isEmpty()) {
VoxelNode* subTree = agentData->nodeBag.extract(); VoxelNode* subTree = agentData->nodeBag.extract();
bytesWritten = randomTree.encodeTreeBitstream(agentData->getMaxSearchLevel(), subTree, bytesWritten = serverTree.encodeTreeBitstream(agentData->getMaxSearchLevel(), subTree,
&tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1,
agentData->nodeBag, &viewFrustum, agentData->nodeBag, &viewFrustum,
agentData->getWantColor(), WANT_EXISTS_BITS); agentData->getWantColor(), WANT_EXISTS_BITS);
@ -268,16 +268,16 @@ void deepestLevelVoxelDistributor(AgentList* agentList,
// helps improve overall bitrate performance. // helps improve overall bitrate performance.
if (::wantSearchForColoredNodes) { if (::wantSearchForColoredNodes) {
// If the bag was empty, then send everything in view, not just the delta // If the bag was empty, then send everything in view, not just the delta
maxLevelReached = randomTree.searchForColoredNodes(INT_MAX, randomTree.rootNode, agentData->getCurrentViewFrustum(), maxLevelReached = serverTree.searchForColoredNodes(INT_MAX, serverTree.rootNode, agentData->getCurrentViewFrustum(),
agentData->nodeBag, wantDelta, lastViewFrustum); agentData->nodeBag, wantDelta, lastViewFrustum);
// if nothing was found in view, send the root node. // if nothing was found in view, send the root node.
if (agentData->nodeBag.isEmpty()){ if (agentData->nodeBag.isEmpty()){
agentData->nodeBag.insert(randomTree.rootNode); agentData->nodeBag.insert(serverTree.rootNode);
} }
agentData->setViewSent(false); agentData->setViewSent(false);
} else { } else {
agentData->nodeBag.insert(randomTree.rootNode); agentData->nodeBag.insert(serverTree.rootNode);
} }
} }
@ -310,7 +310,7 @@ void deepestLevelVoxelDistributor(AgentList* agentList,
while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) { while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) {
if (!agentData->nodeBag.isEmpty()) { if (!agentData->nodeBag.isEmpty()) {
VoxelNode* subTree = agentData->nodeBag.extract(); VoxelNode* subTree = agentData->nodeBag.extract();
bytesWritten = randomTree.encodeTreeBitstream(INT_MAX, subTree, bytesWritten = serverTree.encodeTreeBitstream(INT_MAX, subTree,
&tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1,
agentData->nodeBag, &agentData->getCurrentViewFrustum(), agentData->nodeBag, &agentData->getCurrentViewFrustum(),
agentData->getWantColor(), WANT_EXISTS_BITS, agentData->getWantColor(), WANT_EXISTS_BITS,
@ -386,14 +386,14 @@ void persistVoxelsWhenDirty() {
double sinceLastTime = (now - ::lastPersistVoxels) / 1000.0; double sinceLastTime = (now - ::lastPersistVoxels) / 1000.0;
// check the dirty bit and persist here... // check the dirty bit and persist here...
if (::wantVoxelPersist && ::randomTree.isDirty() && sinceLastTime > VOXEL_PERSIST_INTERVAL) { if (::wantVoxelPersist && ::serverTree.isDirty() && sinceLastTime > VOXEL_PERSIST_INTERVAL) {
{ {
PerformanceWarning warn(::shouldShowAnimationDebug, PerformanceWarning warn(::shouldShowAnimationDebug,
"persistVoxelsWhenDirty() - reaverageVoxelColors()", ::shouldShowAnimationDebug); "persistVoxelsWhenDirty() - reaverageVoxelColors()", ::shouldShowAnimationDebug);
// after done inserting all these voxels, then reaverage colors // after done inserting all these voxels, then reaverage colors
randomTree.reaverageVoxelColors(randomTree.rootNode); serverTree.reaverageVoxelColors(serverTree.rootNode);
} }
@ -402,8 +402,8 @@ void persistVoxelsWhenDirty() {
"persistVoxelsWhenDirty() - writeToSVOFile()", ::shouldShowAnimationDebug); "persistVoxelsWhenDirty() - writeToSVOFile()", ::shouldShowAnimationDebug);
printf("saving voxels to file...\n"); printf("saving voxels to file...\n");
randomTree.writeToSVOFile(::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE); serverTree.writeToSVOFile(::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE);
randomTree.clearDirtyBit(); // tree is clean after saving serverTree.clearDirtyBit(); // tree is clean after saving
printf("DONE saving voxels to file...\n"); printf("DONE saving voxels to file...\n");
} }
::lastPersistVoxels = usecTimestampNow(); ::lastPersistVoxels = usecTimestampNow();
@ -505,10 +505,10 @@ int main(int argc, const char * argv[]) {
bool persistantFileRead = false; bool persistantFileRead = false;
if (::wantVoxelPersist) { if (::wantVoxelPersist) {
printf("loading voxels from file...\n"); printf("loading voxels from file...\n");
persistantFileRead = ::randomTree.readFromSVOFile(::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE); persistantFileRead = ::serverTree.readFromSVOFile(::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE);
::randomTree.clearDirtyBit(); // the tree is clean since we just loaded it ::serverTree.clearDirtyBit(); // the tree is clean since we just loaded it
printf("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead)); printf("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead));
unsigned long nodeCount = ::randomTree.getVoxelCount(); unsigned long nodeCount = ::serverTree.getVoxelCount();
printf("Nodes after loading scene %ld nodes\n", nodeCount); printf("Nodes after loading scene %ld nodes\n", nodeCount);
} }
@ -517,7 +517,7 @@ int main(int argc, const char * argv[]) {
const char* INPUT_FILE = "-i"; const char* INPUT_FILE = "-i";
const char* voxelsFilename = getCmdOption(argc, argv, INPUT_FILE); const char* voxelsFilename = getCmdOption(argc, argv, INPUT_FILE);
if (voxelsFilename) { if (voxelsFilename) {
randomTree.readFromSVOFile(voxelsFilename); serverTree.readFromSVOFile(voxelsFilename);
} }
// Check to see if the user passed in a command line option for setting packet send rate // Check to see if the user passed in a command line option for setting packet send rate
@ -535,7 +535,7 @@ int main(int argc, const char * argv[]) {
if (cmdOptionExists(argc, argv, ADD_RANDOM_VOXELS)) { if (cmdOptionExists(argc, argv, ADD_RANDOM_VOXELS)) {
// create an octal code buffer and load it with 0 so that the recursive tree fill can give // create an octal code buffer and load it with 0 so that the recursive tree fill can give
// octal codes to the tree nodes that it is creating // octal codes to the tree nodes that it is creating
randomlyFillVoxelTree(MAX_VOXEL_TREE_DEPTH_LEVELS, randomTree.rootNode); randomlyFillVoxelTree(MAX_VOXEL_TREE_DEPTH_LEVELS, serverTree.rootNode);
} }
const char* ADD_SCENE = "--AddScene"; const char* ADD_SCENE = "--AddScene";
@ -554,7 +554,7 @@ int main(int argc, const char * argv[]) {
// TEMPORARILY DISABLED!!! // TEMPORARILY DISABLED!!!
bool actuallyAddScene = false; // !noAddScene && (addScene || (::wantVoxelPersist && !persistantFileRead)); bool actuallyAddScene = false; // !noAddScene && (addScene || (::wantVoxelPersist && !persistantFileRead));
if (actuallyAddScene) { if (actuallyAddScene) {
addSphereScene(&randomTree); addSphereScene(&serverTree);
} }
// for now, initialize the environments with fixed values // for now, initialize the environments with fixed values
@ -633,7 +633,7 @@ int main(int argc, const char * argv[]) {
delete []vertices; delete []vertices;
} }
randomTree.readCodeColorBufferToTree(voxelData, destructive); serverTree.readCodeColorBufferToTree(voxelData, destructive);
// skip to next // skip to next
voxelData += voxelDataSize; voxelData += voxelDataSize;
atByte += voxelDataSize; atByte += voxelDataSize;
@ -643,7 +643,7 @@ int main(int argc, const char * argv[]) {
// Send these bits off to the VoxelTree class to process them // Send these bits off to the VoxelTree class to process them
pthread_mutex_lock(&::treeLock); pthread_mutex_lock(&::treeLock);
randomTree.processRemoveVoxelBitstream((unsigned char*)packetData, receivedBytes); serverTree.processRemoveVoxelBitstream((unsigned char*)packetData, receivedBytes);
pthread_mutex_unlock(&::treeLock); pthread_mutex_unlock(&::treeLock);
} }
if (packetData[0] == PACKET_HEADER_Z_COMMAND) { if (packetData[0] == PACKET_HEADER_Z_COMMAND) {
@ -664,7 +664,7 @@ int main(int argc, const char * argv[]) {
} }
if (strcmp(command, ADD_SCENE_COMMAND) == 0) { if (strcmp(command, ADD_SCENE_COMMAND) == 0) {
printf("got Z message == add scene\n"); printf("got Z message == add scene\n");
addSphereScene(&randomTree); addSphereScene(&serverTree);
rebroadcast = false; rebroadcast = false;
} }
if (strcmp(command, TEST_COMMAND) == 0) { if (strcmp(command, TEST_COMMAND) == 0) {