diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 635e5c16d7..64a50a5b99 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -67,14 +68,14 @@ using namespace std; static unsigned STARFIELD_NUM_STARS = 50000; static unsigned STARFIELD_SEED = 1; -static const int BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH = 6; // farther dragged clicks are ignored +static const int BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH = 6; // farther dragged clicks are ignored const int IDLE_SIMULATE_MSECS = 16; // How often should call simulate and other stuff // in the idle loop? (60 FPS is default) static QTimer* idleTimer = NULL; const int STARTUP_JITTER_SAMPLES = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / 2; - // Startup optimistically with small jitter buffer that + // Startup optimistically with small jitter buffer that // will start playback on the second received audio packet. const int MIRROR_VIEW_TOP_PADDING = 5; @@ -129,7 +130,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _perfStatsOn(false), _chatEntryOn(false), _audio(&_audioScope, STARTUP_JITTER_SAMPLES), - _stopNetworkReceiveThread(false), + _stopNetworkReceiveThread(false), _voxelProcessor(), _voxelHideShowThread(&_voxels), _voxelEditSender(this), @@ -156,24 +157,24 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _window->setMenuBar(Menu::getInstance()); qDebug("[VERSION] Build sequence: %i\n", BUILD_VERSION); - + unsigned int listenPort = 0; // bind to an ephemeral port by default const char** constArgv = const_cast(argv); const char* portStr = getCmdOption(argc, constArgv, "--listenPort"); if (portStr) { listenPort = atoi(portStr); } - + NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AGENT, listenPort); - + // put the audio processing on a separate thread QThread* audioThread = new QThread(this); - + _audio.moveToThread(audioThread); connect(audioThread, SIGNAL(started()), &_audio, SLOT(start())); - + audioThread->start(); - + nodeList->addHook(&_voxels); nodeList->addHook(this); nodeList->addDomainListener(this); @@ -184,10 +185,10 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : // read the ApplicationInfo.ini file for Name/Version/Domain information QSettings applicationInfo("resources/info/ApplicationInfo.ini", QSettings::IniFormat); - + // set the associated application properties applicationInfo.beginGroup("INFO"); - + setApplicationName(applicationInfo.value("name").toString()); setApplicationVersion(applicationInfo.value("version").toString()); setOrganizationName(applicationInfo.value("organizationName").toString()); @@ -198,52 +199,55 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : // Check to see if the user passed in a command line option for loading a local // Voxel File. _voxelsFilename = getCmdOption(argc, constArgv, "-i"); - + // the callback for our instance of NodeList is attachNewHeadToNode nodeList->linkedDataCreateCallback = &attachNewHeadToNode; - + #ifdef _WIN32 WSADATA WsaData; int wsaresult = WSAStartup(MAKEWORD(2,2), &WsaData); #endif - + // tell the NodeList instance who to tell the domain server we care about - const char nodeTypesOfInterest[] = {NODE_TYPE_AUDIO_MIXER, NODE_TYPE_AVATAR_MIXER, NODE_TYPE_VOXEL_SERVER, + const char nodeTypesOfInterest[] = {NODE_TYPE_AUDIO_MIXER, NODE_TYPE_AVATAR_MIXER, NODE_TYPE_VOXEL_SERVER, NODE_TYPE_PARTICLE_SERVER}; nodeList->setNodeTypesOfInterest(nodeTypesOfInterest, sizeof(nodeTypesOfInterest)); QTimer* silentNodeTimer = new QTimer(this); connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000); - + QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); - + _networkAccessManager = new QNetworkAccessManager(this); QNetworkDiskCache* cache = new QNetworkDiskCache(_networkAccessManager); cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "interfaceCache"); _networkAccessManager->setCache(cache); - + _window->setCentralWidget(_glWidget); - + restoreSizeAndPosition(); _window->setVisible(true); _glWidget->setFocusPolicy(Qt::StrongFocus); _glWidget->setFocus(); - + // enable mouse tracking; otherwise, we only get drag events _glWidget->setMouseTracking(true); - + // initialization continues in initializeGL when OpenGL context is ready - + // Tell our voxel edit sender about our known jurisdictions _voxelEditSender.setVoxelServerJurisdictions(&_voxelServerJurisdictions); _particleEditSender.setServerJurisdictions(&_particleServerJurisdictions); + Particle::setVoxelEditPacketSender(&_voxelEditSender); + Particle::setParticleEditPacketSender(&_particleEditSender); + // For now we're going to set the PPS for outbound packets to be super high, this is - // probably not the right long term solution. But for now, we're going to do this to + // probably not the right long term solution. But for now, we're going to do this to // allow you to move a particle around in your hand _particleEditSender.setPacketsPerSecond(3000); // super high!! - + // Set the sixense filtering _sixenseManager.setFilter(Menu::getInstance()->isOptionChecked(MenuOption::FilterSixense)); } @@ -251,14 +255,14 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : Application::~Application() { qInstallMessageHandler(NULL); - + // make sure we don't call the idle timer any more delete idleTimer; // ask the audio thread to quit and wait until it is done _audio.thread()->quit(); _audio.thread()->wait(); - + storeSizeAndPosition(); NodeList::getInstance()->removeHook(&_voxels); NodeList::getInstance()->removeHook(this); @@ -278,59 +282,59 @@ Application::~Application() { void Application::restoreSizeAndPosition() { QSettings* settings = new QSettings(this); QRect available = desktop()->availableGeometry(); - + settings->beginGroup("Window"); - + int x = (int)loadSetting(settings, "x", 0); int y = (int)loadSetting(settings, "y", 0); _window->move(x, y); - + int width = (int)loadSetting(settings, "width", available.width()); int height = (int)loadSetting(settings, "height", available.height()); _window->resize(width, height); - + settings->endGroup(); } void Application::storeSizeAndPosition() { QSettings* settings = new QSettings(this); - + settings->beginGroup("Window"); - + settings->setValue("width", _window->rect().width()); settings->setValue("height", _window->rect().height()); - + settings->setValue("x", _window->pos().x()); settings->setValue("y", _window->pos().y()); - + settings->endGroup(); } void Application::initializeGL() { qDebug( "Created Display Window.\n" ); - + // initialize glut for shape drawing; Qt apparently initializes it on OS X #ifndef __APPLE__ int argc = 0; glutInit(&argc, 0); #endif - + // Before we render anything, let's set up our viewFrustumOffsetCamera with a sufficiently large // field of view and near and far clip to make it interesting. //viewFrustumOffsetCamera.setFieldOfView(90.0); _viewFrustumOffsetCamera.setNearClip(0.1); _viewFrustumOffsetCamera.setFarClip(500.0 * TREE_SCALE); - + initDisplay(); qDebug( "Initialized Display.\n" ); - + init(); qDebug( "Init() complete.\n" ); - + // create thread for receipt of data via UDP if (_enableNetworkThread) { pthread_create(&_networkReceiveThread, NULL, networkReceive, NULL); - qDebug("Network receive thread created.\n"); + qDebug("Network receive thread created.\n"); } // create thread for parsing of voxel data independent of the main network and rendering threads @@ -341,21 +345,21 @@ void Application::initializeGL() { if (_enableProcessVoxelsThread) { qDebug("Voxel parsing thread created.\n"); } - + // call terminate before exiting connect(this, SIGNAL(aboutToQuit()), SLOT(terminate())); - + // call our timer function every second QTimer* timer = new QTimer(this); connect(timer, SIGNAL(timeout()), SLOT(timer())); timer->start(1000); - + // call our idle function whenever we can idleTimer = new QTimer(this); connect(idleTimer, SIGNAL(timeout()), SLOT(idle())); idleTimer->start(0); _idleLoopStdev.reset(); - + if (_justStarted) { float startupTime = (usecTimestampNow() - usecTimestamp(&_applicationStartupTime)) / 1000000.0; _justStarted = false; @@ -363,14 +367,14 @@ void Application::initializeGL() { sprintf(title, "Interface: %4.2f seconds\n", startupTime); qDebug("%s", title); const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time"; - + // ask the Logstash class to record the startup time Logging::stashValue(STAT_TYPE_TIMER, LOGSTASH_INTERFACE_START_TIME_KEY, startupTime); } - + // update before the first render update(0.0f); - + InfoView::showFirstTime(); } @@ -378,7 +382,7 @@ void Application::paintGL() { PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings)); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::paintGL()"); - + glEnable(GL_LINE_SMOOTH); if (OculusManager::isConnected()) { @@ -387,17 +391,17 @@ void Application::paintGL() { _myCamera.setTightness (0.0f); // Camera is directly connected to head without smoothing _myCamera.setTargetPosition(_myAvatar.getHead().calculateAverageEyePosition()); _myCamera.setTargetRotation(_myAvatar.getHead().getOrientation()); - + } else if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { _myCamera.setTightness(0.0f); // In first person, camera follows head exactly without delay _myCamera.setTargetPosition(_myAvatar.getHead().calculateAverageEyePosition()); _myCamera.setTargetRotation(_myAvatar.getHead().getCameraOrientation()); - + } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { _myCamera.setTightness (0.0f); // Camera is directly connected to head without smoothing _myCamera.setTargetPosition(_myAvatar.getUprightHeadPosition()); _myCamera.setTargetRotation(_myAvatar.getHead().getCameraOrientation()); - + } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _myCamera.setTightness(0.0f); float headHeight = _myAvatar.getHead().calculateAverageEyePosition().y - _myAvatar.getPosition().y; @@ -408,9 +412,9 @@ void Application::paintGL() { // Update camera position _myCamera.update( 1.f/_fps ); - - - // Note: whichCamera is used to pick between the normal camera myCamera for our + + + // Note: whichCamera is used to pick between the normal camera myCamera for our // main camera, vs, an alternate camera. The alternate camera we support right now // is the viewFrustumOffsetCamera. But theoretically, we could use this same mechanism // to add other cameras. @@ -421,7 +425,7 @@ void Application::paintGL() { Camera whichCamera = _myCamera; if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum)) { - + ViewFrustumOffset viewFrustumOffset = Menu::getInstance()->getViewFrustumOffset(); // set the camera to third-person view but offset so we can see the frustum @@ -433,7 +437,7 @@ void Application::paintGL() { _viewFrustumOffsetCamera.initialize(); // force immediate snap to ideal position and orientation _viewFrustumOffsetCamera.update(1.f/_fps); whichCamera = _viewFrustumOffsetCamera; - } + } if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) { updateShadowMap(); @@ -442,22 +446,22 @@ void Application::paintGL() { if (OculusManager::isConnected()) { OculusManager::display(whichCamera); } else if (TV3DManager::isConnected()) { - _glowEffect.prepare(); + _glowEffect.prepare(); TV3DManager::display(whichCamera); _glowEffect.render(); } else { - _glowEffect.prepare(); - + _glowEffect.prepare(); + glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); displaySide(whichCamera); glPopMatrix(); - + _glowEffect.render(); - + if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { - + bool eyeRelativeCamera = false; if (_rearMirrorTools->getZoomLevel() == BODY) { _mirrorCamera.setDistance(MIRROR_REARVIEW_BODY_DISTANCE * _myAvatar.getScale()); @@ -469,47 +473,47 @@ void Application::paintGL() { // face/body so that the average eye position lies at the origin eyeRelativeCamera = true; _mirrorCamera.setTargetPosition(glm::vec3()); - + } else { _mirrorCamera.setTargetPosition(_myAvatar.getHead().calculateAverageEyePosition()); } } - + _mirrorCamera.setTargetRotation(_myAvatar.getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f))); _mirrorCamera.update(1.0f/_fps); - + // set the bounds of rear mirror view - glViewport(_mirrorViewRect.x(), _glWidget->height() - _mirrorViewRect.y() - _mirrorViewRect.height(), + glViewport(_mirrorViewRect.x(), _glWidget->height() - _mirrorViewRect.y() - _mirrorViewRect.height(), _mirrorViewRect.width(), _mirrorViewRect.height()); - glScissor(_mirrorViewRect.x(), _glWidget->height() - _mirrorViewRect.y() - _mirrorViewRect.height(), + glScissor(_mirrorViewRect.x(), _glWidget->height() - _mirrorViewRect.y() - _mirrorViewRect.height(), _mirrorViewRect.width(), _mirrorViewRect.height()); bool updateViewFrustum = false; updateProjectionMatrix(_mirrorCamera, updateViewFrustum); glEnable(GL_SCISSOR_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - + // render rear mirror view glPushMatrix(); if (eyeRelativeCamera) { // save absolute translations glm::vec3 absoluteSkeletonTranslation = _myAvatar.getSkeletonModel().getTranslation(); glm::vec3 absoluteFaceTranslation = _myAvatar.getHead().getFaceModel().getTranslation(); - + // get the eye positions relative to the neck and use them to set the face translation glm::vec3 leftEyePosition, rightEyePosition; _myAvatar.getHead().getFaceModel().setTranslation(glm::vec3()); _myAvatar.getHead().getFaceModel().getEyePositions(leftEyePosition, rightEyePosition); _myAvatar.getHead().getFaceModel().setTranslation((leftEyePosition + rightEyePosition) * -0.5f); - + // get the neck position relative to the body and use it to set the skeleton translation glm::vec3 neckPosition; _myAvatar.getSkeletonModel().setTranslation(glm::vec3()); _myAvatar.getSkeletonModel().getNeckPosition(neckPosition); _myAvatar.getSkeletonModel().setTranslation(_myAvatar.getHead().getFaceModel().getTranslation() - neckPosition); - + displaySide(_mirrorCamera, true); - + // restore absolute translations _myAvatar.getSkeletonModel().setTranslation(absoluteSkeletonTranslation); _myAvatar.getHead().getFaceModel().setTranslation(absoluteFaceTranslation); @@ -517,9 +521,9 @@ void Application::paintGL() { displaySide(_mirrorCamera, true); } glPopMatrix(); - + _rearMirrorTools->render(false); - + // reset Viewport and projection matrix glViewport(0, 0, _glWidget->width(), _glWidget->height()); glDisable(GL_SCISSOR_TEST); @@ -527,10 +531,10 @@ void Application::paintGL() { } else if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { _rearMirrorTools->render(true); } - + displayOverlay(); } - + _frameCount++; } @@ -548,7 +552,7 @@ void Application::resetCamerasOnResizeGL(Camera& camera, int width, int height) void Application::resizeGL(int width, int height) { resetCamerasOnResizeGL(_viewFrustumOffsetCamera, width, height); resetCamerasOnResizeGL(_myCamera, width, height); - + glViewport(0, 0, width, height); // shouldn't this account for the menu??? updateProjectionMatrix(); @@ -565,12 +569,12 @@ void Application::updateProjectionMatrix(Camera& camera, bool updateViewFrustum) float left, right, bottom, top, nearVal, farVal; glm::vec4 nearClipPlane, farClipPlane; - + // Tell our viewFrustum about this change, using the application camera if (updateViewFrustum) { loadViewFrustum(camera, _viewFrustum); computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); - + // If we're in Display Frustum mode, then we want to use the slightly adjust near/far clip values of the // _viewFrustumOffsetCamera, so that we can see more of the application content in the application's frustum if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum)) { @@ -583,7 +587,7 @@ void Application::updateProjectionMatrix(Camera& camera, bool updateViewFrustum) tempViewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); } glFrustum(left, right, bottom, top, nearVal, farVal); - + glMatrixMode(GL_MODELVIEW); } @@ -594,7 +598,7 @@ void Application::resetProfile(const QString& username) { updateWindowTitle(); } -void Application::controlledBroadcastToNodes(unsigned char* broadcastData, size_t dataBytes, +void Application::controlledBroadcastToNodes(unsigned char* broadcastData, size_t dataBytes, const char* nodeTypes, int numNodeTypes) { Application* self = getInstance(); for (int i = 0; i < numNodeTypes; ++i) { @@ -603,7 +607,7 @@ void Application::controlledBroadcastToNodes(unsigned char* broadcastData, size_ if (nodeTypes[i] == NODE_TYPE_VOXEL_SERVER && !Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { continue; } - + // Perform the broadcast for one type int nReceivingNodes = NodeList::getInstance()->broadcastToNodes(broadcastData, dataBytes, & nodeTypes[i], 1); @@ -620,7 +624,7 @@ void Application::controlledBroadcastToNodes(unsigned char* broadcastData, size_ default: continue; } - self->_bandwidthMeter.outputStream(channel).updateValue(nReceivingNodes * dataBytes); + self->_bandwidthMeter.outputStream(channel).updateValue(nReceivingNodes * dataBytes); } } @@ -631,7 +635,7 @@ void Application::keyPressEvent(QKeyEvent* event) { _myAvatar.setKeyState(event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete ? DELETE_KEY_DOWN : INSERT_KEY_DOWN); _myAvatar.setChatMessage(string(_chatEntry.getContents().size(), SOLID_BLOCK_CHAR)); - + } else { _myAvatar.setChatMessage(_chatEntry.getContents()); _chatEntry.clear(); @@ -666,7 +670,7 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_Apostrophe: _audioScope.inputPaused = !_audioScope.inputPaused; - break; + break; case Qt::Key_L: if (!isShifted && !isMeta) { _displayLevels = !_displayLevels; @@ -676,7 +680,7 @@ void Application::keyPressEvent(QKeyEvent* event) { Menu::getInstance()->triggerOption(MenuOption::Log); } break; - + case Qt::Key_E: if (_nudgeStarted) { _nudgeGuidePosition.y += _mouseVoxel.s; @@ -684,14 +688,14 @@ void Application::keyPressEvent(QKeyEvent* event) { if (!_myAvatar.getDriveKeys(UP)) { _myAvatar.jump(); } - _myAvatar.setDriveKeys(UP, 1); + _myAvatar.setDriveKeys(UP, 1); } break; case Qt::Key_Asterisk: Menu::getInstance()->triggerOption(MenuOption::Stars); break; - + case Qt::Key_C: if (_nudgeStarted) { _nudgeGuidePosition.y -= _mouseVoxel.s; @@ -699,7 +703,7 @@ void Application::keyPressEvent(QKeyEvent* event) { _myAvatar.setDriveKeys(DOWN, 1); } break; - + case Qt::Key_W: if (_nudgeStarted) { if (_lookingAlongX) { @@ -719,7 +723,7 @@ void Application::keyPressEvent(QKeyEvent* event) { _myAvatar.setDriveKeys(FWD, 1); } break; - + case Qt::Key_S: if (isShifted && !isMeta) { _voxels.collectStatsForTreesAndVBOs(); @@ -743,11 +747,11 @@ void Application::keyPressEvent(QKeyEvent* event) { _myAvatar.setDriveKeys(BACK, 1); } break; - + case Qt::Key_Space: resetSensors(); break; - + case Qt::Key_G: if (isShifted) { Menu::getInstance()->triggerOption(MenuOption::Gravity); @@ -755,7 +759,7 @@ void Application::keyPressEvent(QKeyEvent* event) { Menu::getInstance()->triggerOption(MenuOption::VoxelGetColorMode); } break; - + case Qt::Key_A: if (isShifted) { Menu::getInstance()->triggerOption(MenuOption::Atmosphere); @@ -777,7 +781,7 @@ void Application::keyPressEvent(QKeyEvent* event) { _myAvatar.setDriveKeys(ROT_LEFT, 1); } break; - + case Qt::Key_D: if (_nudgeStarted) { if (_lookingAlongX) { @@ -797,7 +801,7 @@ void Application::keyPressEvent(QKeyEvent* event) { _myAvatar.setDriveKeys(ROT_RIGHT, 1); } break; - + case Qt::Key_Return: case Qt::Key_Enter: if (_nudgeStarted) { @@ -809,7 +813,7 @@ void Application::keyPressEvent(QKeyEvent* event) { setMenuShortcutsEnabled(false); } break; - + case Qt::Key_Up: if (_nudgeStarted && !isShifted) { if (_lookingAlongX) { @@ -831,7 +835,7 @@ void Application::keyPressEvent(QKeyEvent* event) { _myAvatar.setDriveKeys(isShifted ? UP : FWD, 1); } break; - + case Qt::Key_Down: if (_nudgeStarted && !isShifted) { if (_lookingAlongX) { @@ -853,7 +857,7 @@ void Application::keyPressEvent(QKeyEvent* event) { _myAvatar.setDriveKeys(isShifted ? DOWN : BACK, 1); } break; - + case Qt::Key_Left: if (_nudgeStarted) { if (_lookingAlongX) { @@ -873,7 +877,7 @@ void Application::keyPressEvent(QKeyEvent* event) { _myAvatar.setDriveKeys(isShifted ? LEFT : ROT_LEFT, 1); } break; - + case Qt::Key_Right: if (_nudgeStarted) { if (_lookingAlongX) { @@ -893,7 +897,7 @@ void Application::keyPressEvent(QKeyEvent* event) { _myAvatar.setDriveKeys(isShifted ? RIGHT : ROT_RIGHT, 1); } break; - + case Qt::Key_I: if (isShifted) { _myCamera.setEyeOffsetOrientation(glm::normalize( @@ -903,7 +907,7 @@ void Application::keyPressEvent(QKeyEvent* event) { } updateProjectionMatrix(); break; - + case Qt::Key_K: if (isShifted) { _myCamera.setEyeOffsetOrientation(glm::normalize( @@ -913,7 +917,7 @@ void Application::keyPressEvent(QKeyEvent* event) { } updateProjectionMatrix(); break; - + case Qt::Key_J: if (isShifted) { _viewFrustum.setFocalLength(_viewFrustum.getFocalLength() - 0.1f); @@ -925,20 +929,20 @@ void Application::keyPressEvent(QKeyEvent* event) { } updateProjectionMatrix(); break; - + case Qt::Key_M: if (isShifted) { _viewFrustum.setFocalLength(_viewFrustum.getFocalLength() + 0.1f); if (TV3DManager::isConnected()) { TV3DManager::configureCamera(_myCamera, _glWidget->width(),_glWidget->height()); } - + } else { _myCamera.setEyeOffsetPosition(_myCamera.getEyeOffsetPosition() + glm::vec3(0.001, 0, 0)); } updateProjectionMatrix(); break; - + case Qt::Key_U: if (isShifted) { _myCamera.setEyeOffsetOrientation(glm::normalize( @@ -948,7 +952,7 @@ void Application::keyPressEvent(QKeyEvent* event) { } updateProjectionMatrix(); break; - + case Qt::Key_Y: if (isShifted) { _myCamera.setEyeOffsetOrientation(glm::normalize( @@ -1040,7 +1044,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) { _myAvatar.setKeyState(NO_KEY_DOWN); return; } - + switch (event->key()) { case Qt::Key_Shift: _pasteMode = false; @@ -1048,47 +1052,47 @@ void Application::keyReleaseEvent(QKeyEvent* event) { case Qt::Key_E: _myAvatar.setDriveKeys(UP, 0); break; - + case Qt::Key_C: _myAvatar.setDriveKeys(DOWN, 0); break; - + case Qt::Key_W: _myAvatar.setDriveKeys(FWD, 0); break; - + case Qt::Key_S: _myAvatar.setDriveKeys(BACK, 0); break; - + case Qt::Key_A: _myAvatar.setDriveKeys(ROT_LEFT, 0); break; - + case Qt::Key_D: _myAvatar.setDriveKeys(ROT_RIGHT, 0); break; - + case Qt::Key_Up: _myAvatar.setDriveKeys(FWD, 0); _myAvatar.setDriveKeys(UP, 0); break; - + case Qt::Key_Down: _myAvatar.setDriveKeys(BACK, 0); _myAvatar.setDriveKeys(DOWN, 0); break; - + case Qt::Key_Left: _myAvatar.setDriveKeys(LEFT, 0); _myAvatar.setDriveKeys(ROT_LEFT, 0); break; - + case Qt::Key_Right: _myAvatar.setDriveKeys(RIGHT, 0); _myAvatar.setDriveKeys(ROT_RIGHT, 0); break; - + default: event->ignore(); break; @@ -1107,7 +1111,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) { if (activeWindow() == _window) { int deltaX = event->x() - _mouseX; int deltaY = event->y() - _mouseY; - + _mouseX = event->x(); _mouseY = event->y(); @@ -1128,7 +1132,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) { if (!_justEditedVoxel && mouseVoxelPos != _lastMouseVoxelPos) { if (event->buttons().testFlag(Qt::LeftButton)) { maybeEditVoxelUnderCursor(); - + } else if (event->buttons().testFlag(Qt::RightButton) && Menu::getInstance()->isVoxelModeActionChecked()) { deleteVoxelUnderCursor(); } @@ -1154,17 +1158,17 @@ void Application::mousePressEvent(QMouseEvent* event) { _mousePressed = true; maybeEditVoxelUnderCursor(); - + if (_audio.mousePressEvent(_mouseX, _mouseY)) { // stop propagation return; } - + if (_rearMirrorTools->mousePressEvent(_mouseX, _mouseY)) { // stop propagation return; } - + if (!_palette.isActive() && (!_isHoverVoxel || _lookatTargetAvatar)) { // disable for now // _pieMenu.mousePressEvent(_mouseX, _mouseY); @@ -1183,18 +1187,18 @@ void Application::mousePressEvent(QMouseEvent* event) { const float GREEN_CLICK_FREQUENCY = 1250.f; const float BLUE_CLICK_FREQUENCY = 1330.f; const float MIDDLE_A_FREQUENCY = 440.f; - float frequency = MIDDLE_A_FREQUENCY + + float frequency = MIDDLE_A_FREQUENCY + (_hoverVoxel.red / 255.f * RED_CLICK_FREQUENCY + _hoverVoxel.green / 255.f * GREEN_CLICK_FREQUENCY + _hoverVoxel.blue / 255.f * BLUE_CLICK_FREQUENCY) / 3.f; - + _audio.startCollisionSound(1.0, frequency, 0.0, HOVER_VOXEL_DECAY, false); _isHoverVoxelSounding = true; - + const float PERCENTAGE_TO_MOVE_TOWARD = 0.90f; glm::vec3 newTarget = getMouseVoxelWorldCoordinates(_hoverVoxel); glm::vec3 myPosition = _myAvatar.getPosition(); - + // If there is not an action tool set (add, delete, color), move to this voxel if (Menu::getInstance()->isOptionChecked(MenuOption::ClickToFly) && !(Menu::getInstance()->isOptionChecked(MenuOption::VoxelAddMode) || @@ -1203,7 +1207,7 @@ void Application::mousePressEvent(QMouseEvent* event) { _myAvatar.setMoveTarget(myPosition + (newTarget - myPosition) * PERCENTAGE_TO_MOVE_TOWARD); } } - + } else if (event->button() == Qt::RightButton && Menu::getInstance()->isVoxelModeActionChecked()) { deleteVoxelUnderCursor(); } @@ -1259,9 +1263,9 @@ void Application::touchEndEvent(QTouchEvent* event) { _isTouchPressed = false; } -const bool USE_MOUSEWHEEL = false; +const bool USE_MOUSEWHEEL = false; void Application::wheelEvent(QWheelEvent* event) { - // Wheel Events disabled for now because they are also activated by touch look pitch up/down. + // Wheel Events disabled for now because they are also activated by touch look pitch up/down. if (USE_MOUSEWHEEL && (activeWindow() == _window)) { if (!Menu::getInstance()->isVoxelModeActionChecked()) { event->ignore(); @@ -1277,7 +1281,7 @@ void Application::wheelEvent(QWheelEvent* event) { void Application::sendPingPackets() { - const char nodesToPing[] = {NODE_TYPE_VOXEL_SERVER, NODE_TYPE_PARTICLE_SERVER, + const char nodesToPing[] = {NODE_TYPE_VOXEL_SERVER, NODE_TYPE_PARTICLE_SERVER, NODE_TYPE_AUDIO_MIXER, NODE_TYPE_AVATAR_MIXER}; unsigned char pingPacket[MAX_PACKET_SIZE]; @@ -1290,24 +1294,24 @@ void Application::sendPingPackets() { void Application::sendAvatarFaceVideoMessage(int frameCount, const QByteArray& data) { unsigned char packet[MAX_PACKET_SIZE]; unsigned char* packetPosition = packet; - + packetPosition += populateTypeAndVersion(packetPosition, PACKET_TYPE_AVATAR_FACE_VIDEO); - + QByteArray rfcUUID = NodeList::getInstance()->getOwnerUUID().toRfc4122(); memcpy(packetPosition, rfcUUID.constData(), rfcUUID.size()); packetPosition += rfcUUID.size(); - + *(uint32_t*)packetPosition = frameCount; packetPosition += sizeof(uint32_t); - + *(uint32_t*)packetPosition = data.size(); packetPosition += sizeof(uint32_t); - + uint32_t* offsetPosition = (uint32_t*)packetPosition; packetPosition += sizeof(uint32_t); - + int headerSize = packetPosition - packet; - + // break the data up into submessages of the maximum size (at least one, for zero-length packets) *offsetPosition = 0; do { @@ -1315,7 +1319,7 @@ void Application::sendAvatarFaceVideoMessage(int frameCount, const QByteArray& d memcpy(packetPosition, data.constData() + *offsetPosition, payloadSize); getInstance()->controlledBroadcastToNodes(packet, headerSize + payloadSize, &NODE_TYPE_AVATAR_MIXER, 1); *offsetPosition += payloadSize; - + } while (*offsetPosition < data.size()); } @@ -1326,24 +1330,24 @@ void Application::timer() { if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { sendPingPackets(); } - + _fps = (float)_frameCount / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f); _packetsPerSecond = (float)_packetCount / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f); _bytesPerSecond = (float)_bytesCount / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f); _frameCount = 0; _packetCount = 0; _bytesCount = 0; - + gettimeofday(&_timerStart, NULL); - + // if we haven't detected gyros, check for them now if (!_serialHeadSensor.isActive()) { _serialHeadSensor.pair(); } - + // ask the node list to check in with the domain server NodeList::getInstance()->sendDomainServerCheckIn(); - + // give the MyAvatar object position to the Profile so it can propagate to the data-server _profile.updatePosition(_myAvatar.getPosition()); } @@ -1352,34 +1356,34 @@ static glm::vec3 getFaceVector(BoxFace face) { switch (face) { case MIN_X_FACE: return glm::vec3(-1, 0, 0); - + case MAX_X_FACE: return glm::vec3(1, 0, 0); - + case MIN_Y_FACE: return glm::vec3(0, -1, 0); - + case MAX_Y_FACE: return glm::vec3(0, 1, 0); - + case MIN_Z_FACE: return glm::vec3(0, 0, -1); - + case MAX_Z_FACE: return glm::vec3(0, 0, 1); } } void Application::idle() { - // Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing - // details if we're in ExtraDebugging mode. However, the ::update() and it's subcomponents will show their timing + // Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing + // details if we're in ExtraDebugging mode. However, the ::update() and it's subcomponents will show their timing // details normally. bool showWarnings = getLogger()->extraDebugging(); PerformanceWarning warn(showWarnings, "Application::idle()"); - + timeval check; gettimeofday(&check, NULL); - + // Only run simulation code if more than IDLE_SIMULATE_MSECS have passed since last time we ran double timeSinceLastUpdate = diffclock(&_lastTimeUpdated, &check); @@ -1397,7 +1401,7 @@ void Application::idle() { PerformanceWarning warn(showWarnings, "Application::idle()... rest of it"); _lastTimeUpdated = check; _idleLoopStdev.addValue(timeSinceLastUpdate); - + // Record standard deviation and reset counter if needed const int STDEV_SAMPLES = 500; if (_idleLoopStdev.getSamples() > STDEV_SAMPLES) { @@ -1413,7 +1417,7 @@ void Application::idle() { void Application::terminate() { // Close serial port // close(serial_fd); - + LeapManager::terminate(); Menu::getInstance()->saveSettings(); _rearMirrorTools->saveSettings(_settings); @@ -1424,7 +1428,7 @@ void Application::terminate() { if (_enableNetworkThread) { _stopNetworkReceiveThread = true; - pthread_join(_networkReceiveThread, NULL); + pthread_join(_networkReceiveThread, NULL); } printf(""); @@ -1441,18 +1445,18 @@ static Avatar* processAvatarMessageHeader(unsigned char*& packetData, size_t& da if (avatarMixerNode) { avatarMixerNode->recordBytesReceived(dataBytes); } - + // skip the header int numBytesPacketHeader = numBytesForPacketHeader(packetData); packetData += numBytesPacketHeader; dataBytes -= numBytesPacketHeader; - + // read the node id QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*) packetData, NUM_BYTES_RFC4122_UUID)); - + packetData += NUM_BYTES_RFC4122_UUID; dataBytes -= NUM_BYTES_RFC4122_UUID; - + // make sure the node exists Node* node = NodeList::getInstance()->nodeWithUUID(nodeUUID); if (!node || !node->getLinkedData()) { @@ -1473,11 +1477,11 @@ void Application::processAvatarURLsMessage(unsigned char* packetData, size_t dat // don't ask over and over again. Instead use this message to // Tell the other avatars that your dataserver data has // changed. - + //QDataStream in(QByteArray((char*)packetData, dataBytes)); //QUrl voxelURL; //in >> voxelURL; - + // use this timing to as the data-server for an updated mesh for this avatar (if we have UUID) DataServerClient::getValuesForKeysAndUUID(QStringList() << DataServerKey::FaceMeshURL << DataServerKey::SkeletonURL, avatar->getUUID()); @@ -1529,7 +1533,7 @@ void Application::removeVoxel(glm::vec3 position, voxel.z = position.z / TREE_SCALE; voxel.s = scale / TREE_SCALE; _voxelEditSender.sendVoxelEditMessage(PACKET_TYPE_VOXEL_ERASE, voxel); - + // delete it locally to see the effect immediately (and in case no voxel server is present) _voxels.deleteVoxelAt(voxel.x, voxel.y, voxel.z, voxel.s); } @@ -1547,21 +1551,25 @@ void Application::shootParticle() { glm::vec3 gravity = DEFAULT_GRAVITY * 0.f; float damping = DEFAULT_DAMPING * 0.01f; QString script( - " function collisionWithVoxel(voxel) { " - " print('collisionWithVoxel(voxel)... '); " - " print('myID=' + Particle.getID() + '\\n'); " - " var voxelColor = voxel.getColor();" - " print('voxelColor=' + voxelColor.red + ', ' + voxelColor.green + ', ' + voxelColor.blue + '\\n'); " - " var myColor = Particle.getColor();" - " print('myColor=' + myColor.red + ', ' + myColor.green + ', ' + myColor.blue + '\\n'); " - " Particle.setColor(voxelColor); " - " } " + " function collisionWithVoxel(voxel) { " + " print('collisionWithVoxel(voxel)... '); " + " print('myID=' + Particle.getID() + '\\n'); " + " var voxelColor = voxel.getColor();" + " print('voxelColor=' + voxelColor.red + ', ' + voxelColor.green + ', ' + voxelColor.blue + '\\n'); " + " var myColor = Particle.getColor();" + " print('myColor=' + myColor.red + ', ' + myColor.green + ', ' + myColor.blue + '\\n'); " + " Particle.setColor(voxelColor); " + " var voxelAt = voxel.getPosition();" + " var voxelScale = voxel.getScale();" + " Voxels.queueVoxelDelete(voxelAt.x, voxelAt.y, voxelAt.z, voxelScale); " + " print('Voxels.queueVoxelDelete(' + voxelAt.x + ', ' + voxelAt.y + ', ' + voxelAt.z + ', ' + voxelScale + ')... \\n'); " + " } " " Particle.collisionWithVoxel.connect(collisionWithVoxel); " ); - - ParticleEditHandle* particleEditHandle = makeParticle(position / (float)TREE_SCALE, radius, color, + + ParticleEditHandle* particleEditHandle = makeParticle(position / (float)TREE_SCALE, radius, color, velocity / (float)TREE_SCALE, gravity, damping, NOT_IN_HAND, script); - + // If we wanted to be able to edit this particle after shooting, then we could store this value // and use it for editing later. But we don't care about that for "shooting" and therefore we just // clean up our memory now. deleting a ParticleEditHandle does not effect the underlying particle, @@ -1576,14 +1584,14 @@ ParticleEditHandle* Application::newParticleEditHandle(uint32_t id) { } // Caller is responsible for managing this EditableParticle -ParticleEditHandle* Application::makeParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, +ParticleEditHandle* Application::makeParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, bool inHand, QString updateScript) { ParticleEditHandle* particleEditHandle = newParticleEditHandle(); particleEditHandle->createParticle(position, radius, color, velocity, gravity, damping, inHand, updateScript); return particleEditHandle; } - + void Application::makeVoxel(glm::vec3 position, float scale, @@ -1601,9 +1609,9 @@ void Application::makeVoxel(glm::vec3 position, voxel.blue = blue; PACKET_TYPE message = isDestructive ? PACKET_TYPE_VOXEL_SET_DESTRUCTIVE : PACKET_TYPE_VOXEL_SET; _voxelEditSender.sendVoxelEditMessage(message, voxel); - + // create the voxel locally so it appears immediately - + _voxels.createVoxel(voxel.x, voxel.y, voxel.z, voxel.s, voxel.red, voxel.green, voxel.blue, isDestructive); @@ -1670,9 +1678,9 @@ bool Application::sendVoxelsOperation(OctreeElement* element, void* extraData) { codeColorBuffer[bytesInCode + RED_INDEX] = voxel->getColor()[RED_INDEX]; codeColorBuffer[bytesInCode + GREEN_INDEX] = voxel->getColor()[GREEN_INDEX]; codeColorBuffer[bytesInCode + BLUE_INDEX] = voxel->getColor()[BLUE_INDEX]; - getInstance()->_voxelEditSender.queueVoxelEditMessage(PACKET_TYPE_VOXEL_SET_DESTRUCTIVE, + getInstance()->_voxelEditSender.queueVoxelEditMessage(PACKET_TYPE_VOXEL_SET_DESTRUCTIVE, codeColorBuffer, codeAndColorLength); - + delete[] codeColorBuffer; } return true; // keep going @@ -1682,7 +1690,7 @@ void Application::exportVoxels() { QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); QString suggestedName = desktopLocation.append("/voxels.svo"); - QString fileNameString = QFileDialog::getSaveFileName(_glWidget, tr("Export Voxels"), suggestedName, + QString fileNameString = QFileDialog::getSaveFileName(_glWidget, tr("Export Voxels"), suggestedName, tr("Sparse Voxel Octree Files (*.svo)")); QByteArray fileNameAscii = fileNameString.toLocal8Bit(); const char* fileName = fileNameAscii.data(); @@ -1729,7 +1737,7 @@ void Application::copyVoxels() { } void Application::pasteVoxelsToOctalCode(const unsigned char* octalCodeDestination) { - // Recurse the clipboard tree, where everything is root relative, and send all the colored voxels to + // Recurse the clipboard tree, where everything is root relative, and send all the colored voxels to // the server as an set voxel message, this will also rebase the voxels to the new location SendVoxelsOperationArgs args; args.newBaseOctCode = octalCodeDestination; @@ -1748,7 +1756,7 @@ void Application::pasteVoxels() { VoxelTreeElement* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); // we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the - // voxel size/position details. If we don't have an actual selectedNode then use the mouseVoxel to create a + // voxel size/position details. If we don't have an actual selectedNode then use the mouseVoxel to create a // target octalCode for where the user is pointing. const unsigned char* octalCodeDestination; if (selectedNode) { @@ -1758,7 +1766,7 @@ void Application::pasteVoxels() { } pasteVoxelsToOctalCode(octalCodeDestination); - + if (calculatedOctCode) { delete[] calculatedOctCode; } @@ -1788,7 +1796,7 @@ void Application::nudgeVoxels() { if (!Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode) && selectedNode) { Menu::getInstance()->triggerOption(MenuOption::VoxelSelectMode); } - + if (!_nudgeStarted && selectedNode) { _nudgeVoxel = _mouseVoxel; _nudgeStarted = true; @@ -1839,14 +1847,14 @@ void Application::init() { delete tmpTree; _voxelImporter.init(); - + _environment.init(); _glowEffect.init(); _ambientOcclusionEffect.init(); _voxelShader.init(); _pointShader.init(); - + _headMouseX = _mouseX = _glWidget->width() / 2; _headMouseY = _mouseY = _glWidget->height() / 2; QCursor::setPos(_headMouseX, _headMouseY); @@ -1856,11 +1864,11 @@ void Application::init() { _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); _myCamera.setModeShiftRate(1.0f); _myAvatar.setDisplayingLookatVectors(false); - + _mirrorCamera.setMode(CAMERA_MODE_MIRROR); _mirrorCamera.setAspectRatio((float)MIRROR_VIEW_WIDTH / (float)MIRROR_VIEW_HEIGHT); _mirrorCamera.setFieldOfView(30); - + OculusManager::connect(); if (OculusManager::isConnected()) { QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen), @@ -1874,9 +1882,9 @@ void Application::init() { "trigger", Qt::QueuedConnection); } - + LeapManager::initialize(); - + gettimeofday(&_timerStart, NULL); gettimeofday(&_lastTimeUpdated, NULL); @@ -1885,14 +1893,14 @@ void Application::init() { _audio.setJitterBufferSamples(Menu::getInstance()->getAudioJitterBufferSamples()); } qDebug("Loaded settings.\n"); - + if (!_profile.getUsername().isEmpty()) { // we have a username for this avatar, ask the data-server for the mesh URL for this avatar DataServerClient::getClientValueForKey(DataServerKey::FaceMeshURL); DataServerClient::getClientValueForKey(DataServerKey::SkeletonURL); } - // Set up VoxelSystem after loading preferences so we can get the desired max voxel count + // Set up VoxelSystem after loading preferences so we can get the desired max voxel count _voxels.setMaxVoxels(Menu::getInstance()->getMaxVoxels()); _voxels.setUseVoxelShader(Menu::getInstance()->isOptionChecked(MenuOption::UseVoxelShader)); _voxels.setVoxelsAsPoints(Menu::getInstance()->isOptionChecked(MenuOption::VoxelsAsPoints)); @@ -1901,11 +1909,11 @@ void Application::init() { _particles.init(); _particles.setViewFrustum(getViewFrustum()); - + _metavoxels.init(); - + _particleCollisionSystem.init(&_particleEditSender, _particles.getTree(), _voxels.getTree(), &_audio, &_myAvatar); - + _palette.init(_glWidget->width(), _glWidget->height()); _palette.addAction(Menu::getInstance()->getActionForOption(MenuOption::VoxelAddMode), 0, 0); _palette.addAction(Menu::getInstance()->getActionForOption(MenuOption::VoxelDeleteMode), 0, 1); @@ -1923,7 +1931,7 @@ void Application::init() { _pieMenu.addAction(_followMode); _audio.init(_glWidget); - + _rearMirrorTools = new RearMirrorTools(_glWidget, _mirrorViewRect, _settings); connect(_rearMirrorTools, SIGNAL(closeView()), SLOT(closeMirrorView())); connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView())); @@ -1941,7 +1949,7 @@ void Application::restoreMirrorView() { if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { Menu::getInstance()->triggerOption(MenuOption::Mirror);; } - + if (!Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { Menu::getInstance()->triggerOption(MenuOption::FullscreenMirror); } @@ -1951,7 +1959,7 @@ void Application::shrinkMirrorView() { if (!Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { Menu::getInstance()->triggerOption(MenuOption::Mirror);; } - + if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { Menu::getInstance()->triggerOption(MenuOption::FullscreenMirror); } @@ -1967,15 +1975,15 @@ void Application::updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, cons glm::vec3& eyePosition) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateLookatTargetAvatar()"); - + if (!_mousePressed) { _lookatTargetAvatar = findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePosition, DEFAULT_NODE_ID_REF); } } - + Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection, glm::vec3& eyePosition, QUuid& nodeUUID = DEFAULT_NODE_ID_REF) { - + NodeList* nodeList = NodeList::getInstance(); for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) { @@ -1985,7 +1993,7 @@ Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, con // rescale to compensate for head embiggening eyePosition = (avatar->getHead().calculateAverageEyePosition() - avatar->getHead().getScalePivot()) * (avatar->getScale() / avatar->getHead().getScale()) + avatar->getHead().getScalePivot(); - + _lookatIndicatorScale = avatar->getHead().getScale(); _lookatOtherPosition = avatar->getHead().getPosition(); nodeUUID = avatar->getOwningNode()->getUUID(); @@ -1999,7 +2007,7 @@ Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, con bool Application::isLookingAtMyAvatar(Avatar* avatar) { glm::vec3 theirLookat = avatar->getHead().getLookAtPosition(); glm::vec3 myHeadPosition = _myAvatar.getHead().getPosition(); - + if (pointInSphere(theirLookat, myHeadPosition, HEAD_SPHERE_RADIUS * _myAvatar.getScale())) { return true; } @@ -2100,7 +2108,7 @@ void Application::updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm:: bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateAvatars()"); NodeList* nodeList = NodeList::getInstance(); - + for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { node->lock(); if (node->getLinkedData()) { @@ -2113,7 +2121,7 @@ void Application::updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm:: } node->unlock(); } - + // simulate avatar fades for (vector::iterator fade = _avatarFades.begin(); fade != _avatarFades.end(); fade++) { Avatar* avatar = *fade; @@ -2123,7 +2131,7 @@ void Application::updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm:: if (avatar->getNewScale() < MINIMUM_SCALE) { delete avatar; _avatarFades.erase(fade--); - + } else { avatar->simulate(deltaTime, NULL); } @@ -2135,7 +2143,7 @@ void Application::updateMouseRay(float deltaTime, glm::vec3& mouseRayOrigin, glm bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateMouseRay()"); - _viewFrustum.computePickRay(_mouseX / (float)_glWidget->width(), _mouseY / (float)_glWidget->height(), + _viewFrustum.computePickRay(_mouseX / (float)_glWidget->width(), _mouseY / (float)_glWidget->height(), mouseRayOrigin, mouseRayDirection); // adjust for mirroring @@ -2150,7 +2158,7 @@ void Application::updateMouseRay(float deltaTime, glm::vec3& mouseRayOrigin, glm // tell my avatar if the mouse is being pressed... _myAvatar.setMousePressed(_mousePressed); - // tell my avatar the posiion and direction of the ray projected ino the world based on the mouse position + // tell my avatar the posiion and direction of the ray projected ino the world based on the mouse position _myAvatar.setMouseRay(mouseRayOrigin, mouseRayDirection); } @@ -2158,30 +2166,30 @@ void Application::updateFaceshift() { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateFaceshift()"); - + // Update faceshift _faceshift.update(); - + // Copy angular velocity if measured by faceshift, to the head if (_faceshift.isActive()) { _myAvatar.getHead().setAngularVelocity(_faceshift.getHeadAngularVelocity()); } } -void Application::updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3& lookAtRayOrigin, +void Application::updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3& lookAtRayOrigin, glm::vec3& lookAtRayDirection) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateMyAvatarLookAtPosition()"); - + if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { lookAtSpot = _myCamera.getPosition(); - + } else if (!_lookatTargetAvatar) { if (_isHoverVoxel) { // Look at the hovered voxel lookAtSpot = getMouseVoxelWorldCoordinates(_hoverVoxel); - + } else { // Just look in direction of the mouse ray const float FAR_AWAY_STARE = TREE_SCALE; @@ -2200,7 +2208,7 @@ void Application::updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3& _myAvatar.getHead().setLookAtPosition(lookAtSpot); } -void Application::updateHoverVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection, +void Application::updateHoverVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection, float& distance, BoxFace& face) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); @@ -2222,21 +2230,21 @@ void Application::updateHoverVoxels(float deltaTime, glm::vec3& mouseRayOrigin, } else { // Voxel is not found, clear all _isHoverVoxelSounding = false; - _isHoverVoxel = false; + _isHoverVoxel = false; } } else { // Check for a new hover voxel glm::vec4 oldVoxel(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s); - // only do this work if MAKE_SOUND_ON_VOXEL_HOVER or MAKE_SOUND_ON_VOXEL_CLICK is enabled, + // only do this work if MAKE_SOUND_ON_VOXEL_HOVER or MAKE_SOUND_ON_VOXEL_CLICK is enabled, // and make sure the tree is not already busy... because otherwise you'll have to wait. if (!(_voxels.treeIsBusy() || _mousePressed)) { { PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels() _voxels.findRayIntersection()"); _isHoverVoxel = _voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _hoverVoxel, distance, face); } - if (MAKE_SOUND_ON_VOXEL_HOVER && _isHoverVoxel && + if (MAKE_SOUND_ON_VOXEL_HOVER && _isHoverVoxel && glm::vec4(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s) != oldVoxel) { - + _hoverVoxelOriginalColor[0] = _hoverVoxel.red; _hoverVoxelOriginalColor[1] = _hoverVoxel.green; _hoverVoxelOriginalColor[2] = _hoverVoxel.blue; @@ -2269,7 +2277,7 @@ void Application::updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin, _mouseVoxelScale = _mouseVoxel.s; } _mouseVoxelScaleInitialized = true; - + // find the nearest voxel with the desired scale if (_mouseVoxelScale > _mouseVoxel.s) { // choose the larger voxel that encompasses the one selected @@ -2277,7 +2285,7 @@ void Application::updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin, _mouseVoxel.y = _mouseVoxelScale * floorf(_mouseVoxel.y / _mouseVoxelScale); _mouseVoxel.z = _mouseVoxelScale * floorf(_mouseVoxel.z / _mouseVoxelScale); _mouseVoxel.s = _mouseVoxelScale; - + } else { glm::vec3 faceVector = getFaceVector(face); if (_mouseVoxelScale < _mouseVoxel.s) { @@ -2309,7 +2317,7 @@ void Application::updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin, _mouseVoxel.z = _mouseVoxelScale * floorf(pt.z / worldMouseVoxelScale); _mouseVoxel.s = _mouseVoxelScale; } - + if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelDeleteMode)) { // red indicates deletion _mouseVoxel.red = 255; @@ -2328,7 +2336,7 @@ void Application::updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin, _mouseVoxel.green = paintColor.green(); _mouseVoxel.blue = paintColor.blue(); } - + // if we just edited, use the currently selected voxel as the "last" for drag detection if (_justEditedVoxel) { _lastMouseVoxelPos = glm::vec3(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z); @@ -2364,7 +2372,7 @@ void Application::updateLeap(float deltaTime) { void Application::updateSixense(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateSixense()"); - + _sixenseManager.update(deltaTime); } @@ -2440,7 +2448,7 @@ void Application::updateTransmitter(float deltaTime) { _transmitterPickStart = _myAvatar.getSkeleton().joint[AVATAR_JOINT_CHEST].position; glm::vec3 direction = _myAvatar.getOrientation() * glm::quat(glm::radians(_myTransmitter.getEstimatedRotation())) * IDENTITY_FRONT; - + // check against voxels, avatars const float MAX_PICK_DISTANCE = 100.0f; float minDistance = MAX_PICK_DISTANCE; @@ -2451,7 +2459,7 @@ void Application::updateTransmitter(float deltaTime) { minDistance = min(minDistance, distance); } _transmitterPickEnd = _transmitterPickStart + direction * minDistance; - + } else { _transmitterPickStart = _transmitterPickEnd = glm::vec3(); } @@ -2461,7 +2469,7 @@ void Application::updateCamera(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateCamera()"); - if (!OculusManager::isConnected() && !TV3DManager::isConnected()) { + if (!OculusManager::isConnected() && !TV3DManager::isConnected()) { if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { if (_myCamera.getMode() != CAMERA_MODE_MIRROR) { _myCamera.setMode(CAMERA_MODE_MIRROR); @@ -2478,15 +2486,15 @@ void Application::updateCamera(float deltaTime) { _myCamera.setModeShiftRate(1.0f); } } - + if (Menu::getInstance()->isOptionChecked(MenuOption::OffAxisProjection)) { float xSign = _myCamera.getMode() == CAMERA_MODE_MIRROR ? 1.0f : -1.0f; if (_faceshift.isActive()) { const float EYE_OFFSET_SCALE = 0.025f; glm::vec3 position = _faceshift.getHeadTranslation() * EYE_OFFSET_SCALE; - _myCamera.setEyeOffsetPosition(glm::vec3(position.x * xSign, position.y, -position.z)); + _myCamera.setEyeOffsetPosition(glm::vec3(position.x * xSign, position.y, -position.z)); updateProjectionMatrix(); - + } else if (_webcam.isActive()) { const float EYE_OFFSET_SCALE = 0.5f; glm::vec3 position = _webcam.getEstimatedPosition() * EYE_OFFSET_SCALE; @@ -2506,7 +2514,7 @@ void Application::updateDialogs(float deltaTime) { if (bandwidthDialog) { bandwidthDialog->update(); } - + VoxelStatsDialog* voxelStatsDialog = Menu::getInstance()->getVoxelStatsDialog(); if (voxelStatsDialog) { voxelStatsDialog->update(); @@ -2549,22 +2557,22 @@ void Application::updateCursor(float deltaTime) { void Application::update(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::update()"); - + // check what's under the mouse and update the mouse voxel glm::vec3 mouseRayOrigin, mouseRayDirection; updateMouseRay(deltaTime, mouseRayOrigin, mouseRayDirection); - + // Set where I am looking based on my mouse ray (so that other people can see) glm::vec3 lookAtSpot; - + updateFaceshift(); updateLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, lookAtSpot); updateMyAvatarLookAtPosition(lookAtSpot, mouseRayOrigin, mouseRayDirection); - + // Find the voxel we are hovering over, and respond if clicked float distance; BoxFace face; - + updateHoverVoxels(deltaTime, mouseRayOrigin, mouseRayDirection, distance, face); // clicking on voxels and making sounds updateMouseVoxels(deltaTime, mouseRayOrigin, mouseRayDirection, distance, face); // UI/UX related to voxels updateHandAndTouch(deltaTime); // Update state for touch sensors @@ -2582,7 +2590,7 @@ void Application::update(float deltaTime) { updateDialogs(deltaTime); // update various stats dialogs if present updateAudio(deltaTime); // Update audio stats for procedural sounds updateCursor(deltaTime); // Handle cursor updates - + _particles.update(); // update the particles... _particleCollisionSystem.update(); // handle collisions for the particles... } @@ -2590,39 +2598,39 @@ void Application::update(float deltaTime) { void Application::updateAvatar(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateAvatar()"); - + // rotate body yaw for yaw received from multitouch _myAvatar.setOrientation(_myAvatar.getOrientation() * glm::quat(glm::vec3(0, _yawFromTouch, 0))); _yawFromTouch = 0.f; - + // apply pitch from touch _myAvatar.getHead().setMousePitch(_myAvatar.getHead().getMousePitch() + _myAvatar.getHand().getPitchUpdate() + _pitchFromTouch); _myAvatar.getHand().setPitchUpdate(0.f); _pitchFromTouch = 0.0f; - + // Update my avatar's state from gyros and/or webcam _myAvatar.updateFromGyrosAndOrWebcam(Menu::getInstance()->isOptionChecked(MenuOption::TurnWithHead)); - + // Update head mouse from faceshift if active if (_faceshift.isActive()) { glm::vec3 headVelocity = _faceshift.getHeadAngularVelocity(); - + // sets how quickly head angular rotation moves the head mouse const float HEADMOUSE_FACESHIFT_YAW_SCALE = 40.f; const float HEADMOUSE_FACESHIFT_PITCH_SCALE = 30.f; _headMouseX -= headVelocity.y * HEADMOUSE_FACESHIFT_YAW_SCALE; _headMouseY -= headVelocity.x * HEADMOUSE_FACESHIFT_PITCH_SCALE; } - + if (_serialHeadSensor.isActive()) { // Grab latest readings from the gyros float measuredPitchRate = _serialHeadSensor.getLastPitchRate(); float measuredYawRate = _serialHeadSensor.getLastYawRate(); - + // Update gyro-based mouse (X,Y on screen) const float MIN_MOUSE_RATE = 3.0; const float HORIZONTAL_PIXELS_PER_DEGREE = 2880.f / 45.f; @@ -2634,7 +2642,7 @@ void Application::updateAvatar(float deltaTime) { } const float MIDPOINT_OF_SCREEN = 0.5; - + // Only use gyro to set lookAt if mouse hasn't selected an avatar if (!_lookatTargetAvatar) { @@ -2651,7 +2659,7 @@ void Application::updateAvatar(float deltaTime) { } } - + // Constrain head-driven mouse to edges of screen _headMouseX = glm::clamp(_headMouseX, 0, _glWidget->width()); _headMouseY = glm::clamp(_headMouseY, 0, _glWidget->height()); @@ -2659,33 +2667,33 @@ void Application::updateAvatar(float deltaTime) { if (OculusManager::isConnected()) { float yaw, pitch, roll; OculusManager::getEulerAngles(yaw, pitch, roll); - + _myAvatar.getHead().setYaw(yaw); _myAvatar.getHead().setPitch(pitch); _myAvatar.getHead().setRoll(roll); } - + // Get audio loudness data from audio input device _myAvatar.getHead().setAudioLoudness(_audio.getLastInputLoudness()); - + NodeList* nodeList = NodeList::getInstance(); - + // send head/hand data to the avatar mixer and voxel server unsigned char broadcastString[MAX_PACKET_SIZE]; unsigned char* endOfBroadcastStringWrite = broadcastString; - + endOfBroadcastStringWrite += populateTypeAndVersion(endOfBroadcastStringWrite, PACKET_TYPE_HEAD_DATA); - + QByteArray ownerUUID = nodeList->getOwnerUUID().toRfc4122(); memcpy(endOfBroadcastStringWrite, ownerUUID.constData(), ownerUUID.size()); endOfBroadcastStringWrite += ownerUUID.size(); - + endOfBroadcastStringWrite += _myAvatar.getBroadcastData(endOfBroadcastStringWrite); - + const char nodeTypesOfInterest[] = { NODE_TYPE_AVATAR_MIXER }; controlledBroadcastToNodes(broadcastString, endOfBroadcastStringWrite - broadcastString, nodeTypesOfInterest, sizeof(nodeTypesOfInterest)); - + const float AVATAR_URLS_SEND_INTERVAL = 1.0f; if (shouldDo(AVATAR_URLS_SEND_INTERVAL, deltaTime)) { QUrl empty; @@ -2695,10 +2703,10 @@ void Application::updateAvatar(float deltaTime) { // NOTE: we get this from the view frustum, to make it simpler, since the // loadViewFrumstum() method will get the correct details from the camera // We could optimize this to not actually load the viewFrustum, since we don't - // actually need to calculate the view frustum planes to send these details + // actually need to calculate the view frustum planes to send these details // to the server. loadViewFrustum(_myCamera, _viewFrustum); - + // Update my voxel servers with my current voxel query... queryOctree(NODE_TYPE_VOXEL_SERVER, PACKET_TYPE_VOXEL_QUERY, _voxelServerJurisdictions); queryOctree(NODE_TYPE_PARTICLE_SERVER, PACKET_TYPE_PARTICLE_QUERY, _particleServerJurisdictions); @@ -2710,16 +2718,16 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node if (!Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { return; } - + bool wantExtraDebugging = getLogger()->extraDebugging(); - + // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _voxelQuery.setWantLowResMoving(!Menu::getInstance()->isOptionChecked(MenuOption::DisableLowRes)); _voxelQuery.setWantColor(!Menu::getInstance()->isOptionChecked(MenuOption::DisableColorVoxels)); _voxelQuery.setWantDelta(!Menu::getInstance()->isOptionChecked(MenuOption::DisableDeltaSending)); _voxelQuery.setWantOcclusionCulling(Menu::getInstance()->isOptionChecked(MenuOption::EnableOcclusionCulling)); _voxelQuery.setWantCompression(Menu::getInstance()->isOptionChecked(MenuOption::EnableVoxelPacketCompression)); - + _voxelQuery.setCameraPosition(_viewFrustum.getPosition()); _voxelQuery.setCameraOrientation(_viewFrustum.getOrientation()); _voxelQuery.setCameraFov(_viewFrustum.getFieldOfView()); @@ -2738,7 +2746,7 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node int totalServers = 0; int inViewServers = 0; int unknownJurisdictionServers = 0; - + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { // only send to the NodeTypes that are serverType @@ -2747,7 +2755,7 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node // get the server bounds for this server QUuid nodeUUID = node->getUUID(); - + // if we haven't heard from this voxel server, go ahead and send it a query, so we // can get the jurisdiction... if (jurisdictions.find(nodeUUID) == jurisdictions.end()) { @@ -2756,7 +2764,7 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node const JurisdictionMap& map = (jurisdictions)[nodeUUID]; unsigned char* rootCode = map.getRootOctalCode(); - + if (rootCode) { VoxelPositionSize rootDetails; voxelDetailsForCode(rootCode, rootDetails); @@ -2774,7 +2782,7 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node } if (wantExtraDebugging && unknownJurisdictionServers > 0) { - qDebug("Servers: total %d, in view %d, unknown jurisdiction %d \n", + qDebug("Servers: total %d, in view %d, unknown jurisdiction %d \n", totalServers, inViewServers, unknownJurisdictionServers); } @@ -2793,11 +2801,11 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node perUnknownServer = (totalPPS / unknownJurisdictionServers); } } - + if (wantExtraDebugging && unknownJurisdictionServers > 0) { qDebug("perServerPPS: %d perUnknownServer: %d\n", perServerPPS, perUnknownServer); } - + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { // only send to the NodeTypes that are serverType if (node->getActiveSocket() != NULL && node->getType() == serverType) { @@ -2808,7 +2816,7 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node bool inView = false; bool unknownView = false; - + // if we haven't heard from this voxel server, go ahead and send it a query, so we // can get the jurisdiction... if (jurisdictions.find(nodeUUID) == jurisdictions.end()) { @@ -2820,7 +2828,7 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node const JurisdictionMap& map = (jurisdictions)[nodeUUID]; unsigned char* rootCode = map.getRootOctalCode(); - + if (rootCode) { VoxelPositionSize rootDetails; voxelDetailsForCode(rootCode, rootDetails); @@ -2839,17 +2847,17 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node } } } - + if (inView) { _voxelQuery.setMaxOctreePacketsPerSecond(perServerPPS); } else if (unknownView) { if (wantExtraDebugging) { - qDebug() << "no known jurisdiction for node " << *node << ", give it budget of " + qDebug() << "no known jurisdiction for node " << *node << ", give it budget of " << perUnknownServer << " to send us jurisdiction.\n"; } - + // set the query's position/orientation to be degenerate in a manner that will get the scene quickly - // If there's only one server, then don't do this, and just let the normal voxel query pass through + // If there's only one server, then don't do this, and just let the normal voxel query pass through // as expected... this way, we will actually get a valid scene if there is one to be seen if (totalServers > 1) { _voxelQuery.setCameraPosition(glm::vec3(-0.1,-0.1,-0.1)); @@ -2880,7 +2888,7 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node // encode the query data... endOfVoxelQueryPacket += _voxelQuery.getBroadcastData(endOfVoxelQueryPacket); - + int packetLength = endOfVoxelQueryPacket - voxelQueryPacket; // make sure we still have an active socket @@ -2899,10 +2907,10 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node // loadViewFrustum() // // Description: this will load the view frustum bounds for EITHER the head -// or the "myCamera". +// or the "myCamera". // void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { - // We will use these below, from either the camera or head vectors calculated above + // We will use these below, from either the camera or head vectors calculated above glm::vec3 position(camera.getPosition()); float fov = camera.getFieldOfView(); float nearClip = camera.getNearClip(); @@ -2911,10 +2919,10 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { glm::quat rotation = camera.getRotation(); - // Set the viewFrustum up with the correct position and orientation of the camera + // Set the viewFrustum up with the correct position and orientation of the camera viewFrustum.setPosition(position); viewFrustum.setOrientation(rotation); - + // Also make sure it's got the correct lens details from the camera viewFrustum.setAspectRatio(aspectRatio); viewFrustum.setFieldOfView(fov); @@ -2936,9 +2944,9 @@ void Application::updateShadowMap() { fbo->bind(); glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - + glViewport(0, 0, fbo->width(), fbo->height()); - + glm::vec3 lightDirection = -getSunDirection(); glm::quat rotation = glm::inverse(rotationBetween(IDENTITY_FRONT, lightDirection)); glm::vec3 translation = glm::vec3(); @@ -2960,57 +2968,57 @@ void Application::updateShadowMap() { minima = glm::min(minima, points[i]); maxima = glm::max(maxima, points[i]); } - + // stretch out our extents in z so that we get all of the avatars minima.z -= _viewFrustum.getFarClip() * 0.5f; maxima.z += _viewFrustum.getFarClip() * 0.5f; - + // save the combined matrix for rendering _shadowMatrix = glm::transpose(glm::translate(0.5f, 0.5f, 0.5f) * glm::scale(0.5f, 0.5f, 0.5f) * glm::ortho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z) * glm::mat4_cast(rotation) * glm::translate(translation)); - + glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z); - + glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); - + // store view matrix without translation, which we'll use for precision-sensitive objects glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix); _viewMatrixTranslation = translation; - + glTranslatef(translation.x, translation.y, translation.z); - + renderAvatars(true); - _particles.render(); - + _particles.render(); + glPopMatrix(); - + glMatrixMode(GL_PROJECTION); glPopMatrix(); - + glMatrixMode(GL_MODELVIEW); - + fbo->release(); - + glViewport(0, 0, _glWidget->width(), _glWidget->height()); } - + const GLfloat WHITE_SPECULAR_COLOR[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat NO_SPECULAR_COLOR[] = { 0.0f, 0.0f, 0.0f, 1.0f }; void Application::setupWorldLight() { - + // Setup 3D lights (after the camera transform, so that they are positioned in world space) glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); - + glm::vec3 sunDirection = getSunDirection(); GLfloat light_position0[] = { sunDirection.x, sunDirection.y, sunDirection.z, 0.0 }; glLightfv(GL_LIGHT0, GL_POSITION, light_position0); @@ -3018,8 +3026,8 @@ void Application::setupWorldLight() { glLightfv(GL_LIGHT0, GL_AMBIENT, ambient_color); GLfloat diffuse_color[] = { 0.8, 0.7, 0.7 }; glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse_color); - - glLightfv(GL_LIGHT0, GL_SPECULAR, WHITE_SPECULAR_COLOR); + + glLightfv(GL_LIGHT0, GL_SPECULAR, WHITE_SPECULAR_COLOR); glMaterialfv(GL_FRONT, GL_SPECULAR, WHITE_SPECULAR_COLOR); glMateriali(GL_FRONT, GL_SHININESS, 96); } @@ -3032,7 +3040,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { if (whichCamera.getMode() == CAMERA_MODE_MIRROR) { glScalef(-1.0f, 1.0f, 1.0f); glFrontFace(GL_CW); - + } else { glFrontFace(GL_CCW); } @@ -3059,9 +3067,9 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // Setup 3D lights (after the camera transform, so that they are positioned in world space) setupWorldLight(); - + if (!selfAvatarOnly && Menu::getInstance()->isOptionChecked(MenuOption::Stars)) { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... stars..."); if (!_stars.isStarsLoaded()) { _stars.generate(STARFIELD_NUM_STARS, STARFIELD_SEED); @@ -3075,7 +3083,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { float height = glm::distance(whichCamera.getPosition(), closestData.getAtmosphereCenter()); if (height < closestData.getAtmosphereInnerRadius()) { alpha = 0.0f; - + } else if (height < closestData.getAtmosphereOuterRadius()) { alpha = (height - closestData.getAtmosphereInnerRadius()) / (closestData.getAtmosphereOuterRadius() - closestData.getAtmosphereInnerRadius()); @@ -3088,20 +3096,20 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // draw the sky dome if (!selfAvatarOnly && Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... atmosphere..."); _environment.renderAtmospheres(whichCamera); } - + glEnable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); - + // Enable to show line from me to the voxel I am touching //renderLineToTouchedVoxel(); //renderThrustAtVoxel(_voxelThrust); - + if (!selfAvatarOnly) { - // draw a red sphere + // draw a red sphere float sphereRadius = 0.25f; glColor3f(1,0,0); glPushMatrix(); @@ -3117,33 +3125,33 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { } // Draw voxels if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... voxels..."); if (!Menu::getInstance()->isOptionChecked(MenuOption::DontRenderVoxels)) { _voxels.render(Menu::getInstance()->isOptionChecked(MenuOption::VoxelTextures)); } } - + // also, metavoxels if (Menu::getInstance()->isOptionChecked(MenuOption::Metavoxels)) { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... metavoxels..."); _metavoxels.render(); - } + } // render particles... _particles.render(); - + // render the ambient occlusion effect if enabled if (Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion)) { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... AmbientOcclusion..."); _ambientOcclusionEffect.render(); } - + // restore default, white specular glMaterialfv(GL_FRONT, GL_SPECULAR, WHITE_SPECULAR_COLOR); - + // Render the highlighted voxel if (_isHighlightVoxel) { renderHighlightVoxel(_highlightVoxel); @@ -3151,7 +3159,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // indicate what we'll be adding/removing in mouse mode, if anything if (_mouseVoxel.s != 0 && whichCamera.getMode() != CAMERA_MODE_MIRROR) { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... voxels TOOLS UX..."); glDisable(GL_LIGHTING); @@ -3172,14 +3180,14 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { } else { renderMouseVoxelGrid(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); } - + if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelAddMode)) { // use a contrasting color so that we can see what we're doing glColor3ub(_mouseVoxel.red + 128, _mouseVoxel.green + 128, _mouseVoxel.blue + 128); } else { glColor3ub(_mouseVoxel.red, _mouseVoxel.green, _mouseVoxel.blue); } - + if (_nudgeStarted) { // render nudge guide cube glTranslatef(_nudgeGuidePosition.x + _nudgeVoxel.s*0.5f, @@ -3198,9 +3206,9 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { glPopMatrix(); glEnable(GL_LIGHTING); } - + if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode) && _pasteMode && whichCamera.getMode() != CAMERA_MODE_MIRROR) { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... PASTE Preview..."); glPushMatrix(); @@ -3223,17 +3231,17 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { if (whichCamera.getMode() != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { renderWorldBox(); } - + // brad's frustum for debugging if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum) && whichCamera.getMode() != CAMERA_MODE_MIRROR) { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... renderViewFrustum..."); renderViewFrustum(_viewFrustum); } // render voxel fades if they exist if (_voxelFades.size() > 0) { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... voxel fades..."); for(std::vector::iterator fade = _voxelFades.begin(); fade != _voxelFades.end();) { fade->render(); @@ -3245,15 +3253,15 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { } } - { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... renderFollowIndicator..."); renderFollowIndicator(); } - + // render transmitter pick ray, if non-empty if (_transmitterPickStart != _transmitterPickEnd) { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... transmitter pick ray..."); Glower glower; @@ -3265,13 +3273,13 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { glVertex3f(_transmitterPickEnd.x, _transmitterPickEnd.y, _transmitterPickEnd.z); glEnd(); glLineWidth(1.0f); - + glPushMatrix(); glTranslatef(_transmitterPickEnd.x, _transmitterPickEnd.y, _transmitterPickEnd.z); - + const float PICK_END_RADIUS = 0.025f; glutSolidSphere(PICK_END_RADIUS, 8, 8); - + glPopMatrix(); } } @@ -3285,21 +3293,21 @@ void Application::loadTranslatedViewMatrix(const glm::vec3& translation) { void Application::computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& near, float& far, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const { - + _viewFrustum.computeOffAxisFrustum(left, right, bottom, top, near, far, nearClipPlane, farClipPlane); } void Application::displayOverlay() { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displayOverlay()"); - // Render 2D overlay: I/O level bar graphs and text + // Render 2D overlay: I/O level bar graphs and text glMatrixMode(GL_PROJECTION); glPushMatrix(); - glLoadIdentity(); + glLoadIdentity(); gluOrtho2D(0, _glWidget->width(), _glWidget->height(), 0); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); - + // Display a single screen-size quad to create an alpha blended 'collision' flash if (_audio.getCollisionFlashesScreen()) { float collisionSoundMagnitude = _audio.getCollisionSoundMagnitude(); @@ -3308,7 +3316,7 @@ void Application::displayOverlay() { renderCollisionOverlay(_glWidget->width(), _glWidget->height(), _audio.getCollisionSoundMagnitude()); } } - + if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { _audio.render(_glWidget->width(), _glWidget->height()); if (Menu::getInstance()->isOptionChecked(MenuOption::Oscilloscope)) { @@ -3317,7 +3325,7 @@ void Application::displayOverlay() { } //noiseTest(_glWidget->width(), _glWidget->height()); - + if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse) && USING_INVENSENSE_MPU9150) { // Display small target box at center or head mouse target that can also be used to measure LOD @@ -3329,7 +3337,7 @@ void Application::displayOverlay() { glVertex2f(_headMouseX + PIXEL_BOX/2, _headMouseY); glVertex2f(_headMouseX, _headMouseY - PIXEL_BOX/2); glVertex2f(_headMouseX, _headMouseY + PIXEL_BOX/2); - glEnd(); + glEnd(); glEnable(GL_LINE_SMOOTH); glColor3f(1.f, 0.f, 0.f); glPointSize(3.0f); @@ -3342,7 +3350,7 @@ void Application::displayOverlay() { const float EYE_TARGET_PIXELS_PER_DEGREE = 40.0; int eyeTargetX = (_glWidget->width() / 2) - _faceshift.getEstimatedEyeYaw() * EYE_TARGET_PIXELS_PER_DEGREE; int eyeTargetY = (_glWidget->height() / 2) - _faceshift.getEstimatedEyePitch() * EYE_TARGET_PIXELS_PER_DEGREE; - + glColor3f(0.0, 1.0, 1.0); glDisable(GL_LINE_SMOOTH); glBegin(GL_LINES); @@ -3354,10 +3362,10 @@ void Application::displayOverlay() { } } - + // Show detected levels from the serial I/O ADC channel sensors if (_displayLevels) _serialHeadSensor.renderLevels(_glWidget->width(), _glWidget->height()); - + // Show hand transmitter data if detected if (_myTransmitter.isConnected()) { _myTransmitter.renderLevels(_glWidget->width(), _glWidget->height()); @@ -3365,21 +3373,21 @@ void Application::displayOverlay() { // Display stats and log text onscreen glLineWidth(1.0f); glPointSize(1.0f); - + if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { - // Onscreen text about position, servers, etc + // Onscreen text about position, servers, etc displayStats(); - // Bandwidth meter + // Bandwidth meter if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) { _bandwidthMeter.render(_glWidget->width(), _glWidget->height()); } // Stats at upper right of screen about who domain server is telling us about glPointSize(1.0f); char nodes[100]; - + NodeList* nodeList = NodeList::getInstance(); int totalAvatars = 0, totalServers = 0; - + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { node->getType() == NODE_TYPE_AGENT ? totalAvatars++ : totalServers++; } @@ -3391,7 +3399,7 @@ void Application::displayOverlay() { if (Menu::getInstance()->isOptionChecked(MenuOption::CoverageMapV2)) { renderCoverageMapV2(); } - + if (Menu::getInstance()->isOptionChecked(MenuOption::CoverageMap)) { renderCoverageMap(); } @@ -3400,7 +3408,7 @@ void Application::displayOverlay() { if (_chatEntryOn) { _chatEntry.render(_glWidget->width(), _glWidget->height()); } - + // Show on-screen msec timer if (Menu::getInstance()->isOptionChecked(MenuOption::FrameTimer)) { char frameTimer[10]; @@ -3410,7 +3418,7 @@ void Application::displayOverlay() { drawtext(_glWidget->width() - 102, _glWidget->height() - 22, 0.30, 0, 1.0, 0, frameTimer, 1, 1, 1); } - + // render the webcam input frame _webcam.renderPreview(_glWidget->width(), _glWidget->height()); @@ -3465,7 +3473,7 @@ void Application::displayOverlay() { if (_pieMenu.isDisplayed()) { _pieMenu.render(); } - + glPopMatrix(); } @@ -3474,7 +3482,7 @@ void Application::displayStats() { const int PELS_PER_LINE = 15; char stats[200]; statsVerticalOffset += PELS_PER_LINE; - sprintf(stats, "%3.0f FPS, %d Pkts/sec, %3.2f Mbps ", + sprintf(stats, "%3.0f FPS, %d Pkts/sec, %3.2f Mbps ", _fps, _packetsPerSecond, (float)_bytesPerSecond * 8.f / 1000000.f); drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, stats); @@ -3510,7 +3518,7 @@ void Application::displayStats() { sprintf(pingStats, "Ping audio/avatar/voxel: %d / %d / %d avg %d max ", pingAudio, pingAvatar, pingVoxel, pingVoxelMax); drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, pingStats); } - + char avatarStats[200]; statsVerticalOffset += PELS_PER_LINE; glm::vec3 avatarPos = _myAvatar.getPosition(); @@ -3530,7 +3538,7 @@ void Application::displayStats() { drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, avatarMixerStats); - // Used for formatting voxel stats details + // Used for formatting voxel stats details statsVerticalOffset += PELS_PER_LINE; // skip a line for voxels QLocale locale(QLocale::English); std::stringstream voxelStats; @@ -3578,7 +3586,7 @@ void Application::displayStats() { // Server Voxels voxelStats.str(""); - voxelStats << + voxelStats << "Server Voxels Total: " << serversTotalString.toLocal8Bit().constData() << " / " << "Internal: " << serversInternalString.toLocal8Bit().constData() << " / " << "Leaves: " << serversLeavesString.toLocal8Bit().constData() << ""; @@ -3594,7 +3602,7 @@ void Application::displayStats() { // Local Voxels voxelStats.str(""); - voxelStats << + voxelStats << "Local Voxels Total: " << localTotalString.toLocal8Bit().constData() << " / " << "Internal: " << localInternalString.toLocal8Bit().constData() << " / " << "Leaves: " << localLeavesString.toLocal8Bit().constData() << ""; @@ -3603,7 +3611,7 @@ void Application::displayStats() { // Local Voxel Memory Usage voxelStats.str(""); - voxelStats << + voxelStats << "Voxels Memory Nodes: " << VoxelTreeElement::getTotalMemoryUsage() / 1000000.f << "MB " "Geometry RAM: " << _voxels.getVoxelMemoryUsageRAM() / 1000000.f << "MB " << "VBO: " << _voxels.getVoxelMemoryUsageVBO() / 1000000.f << "MB "; @@ -3616,8 +3624,8 @@ void Application::displayStats() { // Voxel Rendering voxelStats.str(""); voxelStats.precision(4); - voxelStats << "Voxel Rendering Slots " << - "Max: " << _voxels.getMaxVoxels() / 1000.f << "K " << + voxelStats << "Voxel Rendering Slots " << + "Max: " << _voxels.getMaxVoxels() / 1000.f << "K " << "Drawn: " << _voxels.getVoxelsWritten() / 1000.f << "K " << "Abandoned: " << _voxels.getAbandonedVoxels() / 1000.f << "K "; statsVerticalOffset += PELS_PER_LINE; @@ -3632,9 +3640,9 @@ void Application::displayStats() { int voxelPacketsToProcess = _voxelProcessor.packetsToProcessCount(); QString packetsString = locale.toString((int)voxelPacketsToProcess); QString maxString = locale.toString((int)_recentMaxPackets); - voxelStats << "Voxel Packets to Process: " << packetsString.toLocal8Bit().constData() + voxelStats << "Voxel Packets to Process: " << packetsString.toLocal8Bit().constData() << " [Recent Max: " << maxString.toLocal8Bit().constData() << "]"; - + if (_resetRecentMaxPacketsSoon && voxelPacketsToProcess > 0) { _recentMaxPackets = 0; _resetRecentMaxPacketsSoon = false; @@ -3650,15 +3658,15 @@ void Application::displayStats() { drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); - // Leap data + // Leap data statsVerticalOffset += PELS_PER_LINE; drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)LeapManager::statusString().c_str()); - + if (_perfStatsOn) { // Get the PerfStats group details. We need to allocate and array of char* long enough to hold 1+groups char** perfStatLinesArray = new char*[PerfStat::getGroupCount()+1]; int lines = PerfStat::DumpStats(perfStatLinesArray); - + for (int line=0; line < lines; line++) { statsVerticalOffset += PELS_PER_LINE; drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, perfStatLinesArray[line]); @@ -3699,12 +3707,12 @@ void Application::renderLineToTouchedVoxel() { glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) { float horizontalScale = _glWidget->width() / 2.0f; float verticalScale = _glWidget->height() / 2.0f; - - // -1,-1 is 0,windowHeight + + // -1,-1 is 0,windowHeight // 1,1 is windowWidth,0 - + // -1,1 1,1 - // +-----------------------+ + // +-----------------------+ // | | | // | | | // | -1,0 | | @@ -3715,23 +3723,23 @@ glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) { // | | | // +-----------------------+ // -1,-1 1,-1 - - glm::vec2 screenPoint((projectedPoint.x + 1.0) * horizontalScale, + + glm::vec2 screenPoint((projectedPoint.x + 1.0) * horizontalScale, ((projectedPoint.y + 1.0) * -verticalScale) + _glWidget->height()); - + return screenPoint; } // render the coverage map on screen void Application::renderCoverageMapV2() { - + //qDebug("renderCoverageMap()\n"); - + glDisable(GL_LIGHTING); glLineWidth(2.0); glBegin(GL_LINES); glColor3f(0,1,1); - + renderCoverageMapsV2Recursively(&_voxels.myCoverageMapV2); glEnd(); @@ -3745,7 +3753,7 @@ void Application::renderCoverageMapsV2Recursively(CoverageMapV2* map) { glm::vec2 firstPoint = getScaledScreenPoint(box.getVertex(0)); glm::vec2 lastPoint(firstPoint); - + for (int i = 1; i < box.getVertexCount(); i++) { glm::vec2 thisPoint = getScaledScreenPoint(box.getVertex(i)); @@ -3769,14 +3777,14 @@ void Application::renderCoverageMapsV2Recursively(CoverageMapV2* map) { // render the coverage map on screen void Application::renderCoverageMap() { - + //qDebug("renderCoverageMap()\n"); - + glDisable(GL_LIGHTING); glLineWidth(2.0); glBegin(GL_LINES); glColor3f(0,0,1); - + renderCoverageMapsRecursively(&_voxels.myCoverageMap); glEnd(); @@ -3785,9 +3793,9 @@ void Application::renderCoverageMap() { void Application::renderCoverageMapsRecursively(CoverageMap* map) { for (int i = 0; i < map->getPolygonCount(); i++) { - + OctreeProjectedPolygon* polygon = map->getPolygon(i); - + if (polygon->getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) { glColor3f(.5,0,0); // dark red } else if (polygon->getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT)) { @@ -3814,7 +3822,7 @@ void Application::renderCoverageMapsRecursively(CoverageMap* map) { glm::vec2 firstPoint = getScaledScreenPoint(polygon->getVertex(0)); glm::vec2 lastPoint(firstPoint); - + for (int i = 1; i < polygon->getVertexCount(); i++) { glm::vec2 thisPoint = getScaledScreenPoint(polygon->getVertex(i)); @@ -3840,16 +3848,16 @@ void Application::renderAvatars(bool forceRenderHead, bool selfAvatarOnly) { if (!Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) { return; } - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::renderAvatars()"); if (!selfAvatarOnly) { // Render avatars of other nodes NodeList* nodeList = NodeList::getInstance(); - + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { node->lock(); - + if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) { Avatar *avatar = (Avatar *)node->getLinkedData(); if (!avatar->isInitialized()) { @@ -3858,17 +3866,17 @@ void Application::renderAvatars(bool forceRenderHead, bool selfAvatarOnly) { avatar->render(false); avatar->setDisplayingLookatVectors(Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors)); } - + node->unlock(); } - + // render avatar fades Glower glower; for (vector::iterator fade = _avatarFades.begin(); fade != _avatarFades.end(); fade++) { (*fade)->render(false); } } - + // Render my own Avatar _myAvatar.render(forceRenderHead); _myAvatar.setDisplayingLookatVectors(Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors)); @@ -3881,7 +3889,7 @@ void Application::renderAvatars(bool forceRenderHead, bool selfAvatarOnly) { // renderViewFrustum() // // Description: this will render the view frustum bounds for EITHER the head -// or the "myCamera". +// or the "myCamera". // // Frustum rendering mode. For debug purposes, we allow drawing the frustum in a couple of different ways. // We can draw it with each of these parts: @@ -3898,12 +3906,12 @@ void Application::renderAvatars(bool forceRenderHead, bool selfAvatarOnly) { void Application::renderViewFrustum(ViewFrustum& viewFrustum) { // Load it with the latest details! loadViewFrustum(_myCamera, viewFrustum); - + glm::vec3 position = viewFrustum.getOffsetPosition(); glm::vec3 direction = viewFrustum.getOffsetDirection(); glm::vec3 up = viewFrustum.getOffsetUp(); glm::vec3 right = viewFrustum.getOffsetRight(); - + // Get ready to draw some lines glDisable(GL_LIGHTING); glColor4f(1.0, 1.0, 1.0, 1.0); @@ -3937,7 +3945,7 @@ void Application::renderViewFrustum(ViewFrustum& viewFrustum) { || Menu::getInstance()->getFrustumDrawMode() == FRUSTUM_DRAW_MODE_PLANES || Menu::getInstance()->getFrustumDrawMode() == FRUSTUM_DRAW_MODE_NEAR_PLANE) { // Drawing the bounds of the frustum - // viewFrustum.getNear plane - bottom edge + // viewFrustum.getNear plane - bottom edge glColor3f(1,0,0); glVertex3f(viewFrustum.getNearBottomLeft().x, viewFrustum.getNearBottomLeft().y, viewFrustum.getNearBottomLeft().z); glVertex3f(viewFrustum.getNearBottomRight().x, viewFrustum.getNearBottomRight().y, viewFrustum.getNearBottomRight().z); @@ -3958,7 +3966,7 @@ void Application::renderViewFrustum(ViewFrustum& viewFrustum) { if (Menu::getInstance()->getFrustumDrawMode() == FRUSTUM_DRAW_MODE_ALL || Menu::getInstance()->getFrustumDrawMode() == FRUSTUM_DRAW_MODE_PLANES || Menu::getInstance()->getFrustumDrawMode() == FRUSTUM_DRAW_MODE_FAR_PLANE) { - // viewFrustum.getFar plane - bottom edge + // viewFrustum.getFar plane - bottom edge glColor3f(0,1,0); glVertex3f(viewFrustum.getFarBottomLeft().x, viewFrustum.getFarBottomLeft().y, viewFrustum.getFarBottomLeft().z); glVertex3f(viewFrustum.getFarBottomRight().x, viewFrustum.getFarBottomRight().y, viewFrustum.getFarBottomRight().z); @@ -3979,7 +3987,7 @@ void Application::renderViewFrustum(ViewFrustum& viewFrustum) { if (Menu::getInstance()->getFrustumDrawMode() == FRUSTUM_DRAW_MODE_ALL || Menu::getInstance()->getFrustumDrawMode() == FRUSTUM_DRAW_MODE_PLANES) { // RIGHT PLANE IS CYAN - // right plane - bottom edge - viewFrustum.getNear to distant + // right plane - bottom edge - viewFrustum.getNear to distant glColor3f(0,1,1); glVertex3f(viewFrustum.getNearBottomRight().x, viewFrustum.getNearBottomRight().y, viewFrustum.getNearBottomRight().z); glVertex3f(viewFrustum.getFarBottomRight().x, viewFrustum.getFarBottomRight().y, viewFrustum.getFarBottomRight().z); @@ -3997,7 +4005,7 @@ void Application::renderViewFrustum(ViewFrustum& viewFrustum) { // left plane - top edge - viewFrustum.getNear to distant glVertex3f(viewFrustum.getNearTopLeft().x, viewFrustum.getNearTopLeft().y, viewFrustum.getNearTopLeft().z); glVertex3f(viewFrustum.getFarTopLeft().x, viewFrustum.getFarTopLeft().y, viewFrustum.getFarTopLeft().z); - + // focal plane - bottom edge glColor3f(1.0f, 0.0f, 1.0f); float focalProportion = (viewFrustum.getFocalLength() - viewFrustum.getNearClip()) / @@ -4051,10 +4059,10 @@ bool Application::maybeEditVoxelUnderCursor() { _mouseVoxel.green, _mouseVoxel.blue, Menu::getInstance()->isOptionChecked(MenuOption::DestructiveAddVoxel)); - + // remember the position for drag detection _justEditedVoxel = true; - + } } else if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelDeleteMode)) { deleteVoxelUnderCursor(); @@ -4066,7 +4074,7 @@ bool Application::maybeEditVoxelUnderCursor() { fade.voxelDetails.z = _mouseVoxel.z - slightlyBigger; fade.voxelDetails.s = _mouseVoxel.s + slightlyBigger + slightlyBigger; _voxelFades.push_back(fade); - + } else if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelGetColorMode)) { eyedropperVoxelUnderCursor(); } else { @@ -4092,8 +4100,8 @@ void Application::deleteVoxelUnderCursor() { void Application::eyedropperVoxelUnderCursor() { VoxelTreeElement* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); if (selectedNode && selectedNode->isColored()) { - QColor selectedColor(selectedNode->getColor()[RED_INDEX], - selectedNode->getColor()[GREEN_INDEX], + QColor selectedColor(selectedNode->getColor()[RED_INDEX], + selectedNode->getColor()[GREEN_INDEX], selectedNode->getColor()[BLUE_INDEX]); if (selectedColor.isValid()) { @@ -4119,14 +4127,14 @@ void Application::toggleFollowMode() { void Application::resetSensors() { _headMouseX = _mouseX = _glWidget->width() / 2; _headMouseY = _mouseY = _glWidget->height() / 2; - + if (_serialHeadSensor.isActive()) { _serialHeadSensor.resetAverages(); } _webcam.reset(); _faceshift.reset(); LeapManager::reset(); - + if (OculusManager::isConnected()) { OculusManager::reset(); } @@ -4136,7 +4144,7 @@ void Application::resetSensors() { _myTransmitter.resetLevels(); _myAvatar.setVelocity(glm::vec3(0,0,0)); _myAvatar.setThrust(glm::vec3(0,0,0)); - + QMetaObject::invokeMethod(&_audio, "reset", Qt::QueuedConnection); } @@ -4183,12 +4191,12 @@ void Application::updateWindowTitle(){ void Application::domainChanged(QString domain) { // update the user's last domain in their Profile (which will propagate to data-server) _profile.updateDomain(domain); - + updateWindowTitle(); // reset the environment so that we don't erroneously end up with multiple _environment.resetToDefault(); - + // reset our node to stats and node to jurisdiction maps... since these must be changing... _voxelServerJurisdictions.clear(); _octreeServerSceneStats.clear(); @@ -4196,7 +4204,7 @@ void Application::domainChanged(QString domain) { } void Application::nodeAdded(Node* node) { - + } void Application::nodeKilled(Node* node) { @@ -4210,7 +4218,7 @@ void Application::nodeKilled(Node* node) { printf("voxel server going away...... v[%f, %f, %f, %f]\n", rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s); - + // Add the jurisditionDetails object to the list of "fade outs" if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnVoxelServerChanges)) { VoxelFade fade(VoxelFade::FADE_OUT, NODE_KILLED_RED, NODE_KILLED_GREEN, NODE_KILLED_BLUE); @@ -4219,18 +4227,18 @@ void Application::nodeKilled(Node* node) { fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller; _voxelFades.push_back(fade); } - + // If the voxel server is going away, remove it from our jurisdiction map so we don't send voxels to a dead server _voxelServerJurisdictions.erase(nodeUUID); } - + // also clean up scene stats for that server _voxelSceneStatsLock.lockForWrite(); if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) { _octreeServerSceneStats.erase(nodeUUID); } _voxelSceneStatsLock.unlock(); - + } else if (node->getType() == NODE_TYPE_PARTICLE_SERVER) { QUuid nodeUUID = node->getUUID(); // see if this is the first we've heard of this node... @@ -4241,7 +4249,7 @@ void Application::nodeKilled(Node* node) { printf("particle server going away...... v[%f, %f, %f, %f]\n", rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s); - + // Add the jurisditionDetails object to the list of "fade outs" if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnVoxelServerChanges)) { VoxelFade fade(VoxelFade::FADE_OUT, NODE_KILLED_RED, NODE_KILLED_GREEN, NODE_KILLED_BLUE); @@ -4250,39 +4258,39 @@ void Application::nodeKilled(Node* node) { fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller; _voxelFades.push_back(fade); } - + // If the voxel server is going away, remove it from our jurisdiction map so we don't send voxels to a dead server _particleServerJurisdictions.erase(nodeUUID); } - + // also clean up scene stats for that server _voxelSceneStatsLock.lockForWrite(); if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) { _octreeServerSceneStats.erase(nodeUUID); } _voxelSceneStatsLock.unlock(); - + } else if (node->getType() == NODE_TYPE_AGENT) { Avatar* avatar = static_cast(node->getLinkedData()); if (avatar == _lookatTargetAvatar) { _lookatTargetAvatar = NULL; } - + // take over the avatar in order to fade it out node->setLinkedData(NULL); - + _avatarFades.push_back(avatar); } } -void Application::trackIncomingVoxelPacket(unsigned char* messageData, ssize_t messageLength, +void Application::trackIncomingVoxelPacket(unsigned char* messageData, ssize_t messageLength, const HifiSockAddr& senderSockAddr, bool wasStatsPacket) { - + // Attempt to identify the sender from it's address. Node* serverNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr); if (serverNode) { QUuid nodeUUID = serverNode->getUUID(); - + // now that we know the node ID, let's add these stats to the stats for that node... _voxelSceneStatsLock.lockForWrite(); if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) { @@ -4297,16 +4305,16 @@ int Application::parseOctreeStats(unsigned char* messageData, ssize_t messageLen // But, also identify the sender, and keep track of the contained jurisdiction root for this server Node* server = NodeList::getInstance()->nodeWithAddress(senderSockAddr); - - // parse the incoming stats datas stick it in a temporary object for now, while we + + // parse the incoming stats datas stick it in a temporary object for now, while we // determine which server it belongs to VoxelSceneStats temp; int statsMessageLength = temp.unpackFromMessage(messageData, messageLength); - + // quick fix for crash... why would voxelServer be NULL? if (server) { QUuid nodeUUID = server->getUUID(); - + // now that we know the node ID, let's add these stats to the stats for that node... _voxelSceneStatsLock.lockForWrite(); if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) { @@ -4315,10 +4323,10 @@ int Application::parseOctreeStats(unsigned char* messageData, ssize_t messageLen _octreeServerSceneStats[nodeUUID] = temp; } _voxelSceneStatsLock.unlock(); - + VoxelPositionSize rootDetails; voxelDetailsForCode(temp.getJurisdictionRoot(), rootDetails); - + // see if this is the first we've heard of this node... NodeToJurisdictionMap* jurisdiction = NULL; if (server->getType() == NODE_TYPE_VOXEL_SERVER) { @@ -4326,8 +4334,8 @@ int Application::parseOctreeStats(unsigned char* messageData, ssize_t messageLen } else { jurisdiction = &_particleServerJurisdictions; } - - + + if (jurisdiction->find(nodeUUID) == jurisdiction->end()) { printf("stats from new server... v[%f, %f, %f, %f]\n", rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s); @@ -4354,12 +4362,12 @@ int Application::parseOctreeStats(unsigned char* messageData, ssize_t messageLen // Receive packets from other nodes/servers and decide what to do with them! void* Application::networkReceive(void* args) { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::networkReceive()"); HifiSockAddr senderSockAddr; ssize_t bytesReceived; - + Application* app = Application::getInstance(); while (!app->_stopNetworkReceiveThread) { if (NodeList::getInstance()->getNodeSocket().hasPendingDatagrams() && @@ -4367,36 +4375,36 @@ void* Application::networkReceive(void* args) { MAX_PACKET_SIZE, senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer()))) { - + app->_packetCount++; app->_bytesCount += bytesReceived; - + if (packetVersionMatch(app->_incomingPacket)) { // only process this packet if we have a match on the packet version switch (app->_incomingPacket[0]) { case PACKET_TYPE_TRANSMITTER_DATA_V2: // V2 = IOS transmitter app app->_myTransmitter.processIncomingData(app->_incomingPacket, bytesReceived); - + break; case PACKET_TYPE_MIXED_AUDIO: QMetaObject::invokeMethod(&app->_audio, "addReceivedAudioToBuffer", Qt::QueuedConnection, Q_ARG(QByteArray, QByteArray((char*) app->_incomingPacket, bytesReceived))); break; - + case PACKET_TYPE_PARTICLE_ADD_RESPONSE: // look up our ParticleEditHanders.... ParticleEditHandle::handleAddResponse(app->_incomingPacket, bytesReceived); break; - + case PACKET_TYPE_PARTICLE_DATA: case PACKET_TYPE_VOXEL_DATA: case PACKET_TYPE_VOXEL_ERASE: case PACKET_TYPE_OCTREE_STATS: case PACKET_TYPE_ENVIRONMENT_DATA: { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::networkReceive()... _voxelProcessor.queueReceivedPacket()"); - + bool wantExtraDebugging = app->getLogger()->extraDebugging(); if (wantExtraDebugging && app->_incomingPacket[0] == PACKET_TYPE_VOXEL_DATA) { int numBytesPacketHeader = numBytesForPacketHeader(app->_incomingPacket); @@ -4408,10 +4416,10 @@ void* Application::networkReceive(void* args) { dataAt += sizeof(VOXEL_PACKET_SENT_TIME); VOXEL_PACKET_SENT_TIME arrivedAt = usecTimestampNow(); int flightTime = arrivedAt - sentAt; - + printf("got PACKET_TYPE_VOXEL_DATA, sequence:%d flightTime:%d\n", sequence, flightTime); - } - + } + // add this packet to our list of voxel packets and process them on the voxel processing app->_voxelProcessor.queueReceivedPacket(senderSockAddr, app->_incomingPacket, bytesReceived); break; @@ -4443,15 +4451,15 @@ void* Application::networkReceive(void* args) { break; } } - + if (app->_enableNetworkThread) { - pthread_exit(0); + pthread_exit(0); } - return NULL; + return NULL; } void Application::packetSentNotification(ssize_t length) { - _bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(length); + _bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(length); } void Application::loadScript() { @@ -4459,11 +4467,11 @@ void Application::loadScript() { QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); QString suggestedName = desktopLocation.append("/script.js"); - QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Open Script"), suggestedName, + QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Open Script"), suggestedName, tr("JavaScript Files (*.js)")); QByteArray fileNameAscii = fileNameString.toLocal8Bit(); const char* fileName = fileNameAscii.data(); - + printf("fileName:%s\n",fileName); std::ifstream file(fileName, std::ios::in|std::ios::binary|std::ios::ate); @@ -4481,7 +4489,7 @@ void Application::loadScript() { char* entireFile = new char[fileLength+1]; file.read((char*)entireFile, fileLength); file.close(); - + entireFile[fileLength] = 0;// null terminate QString script(entireFile); delete[] entireFile; @@ -4490,10 +4498,10 @@ void Application::loadScript() { bool wantMenuItems = true; // tells the ScriptEngine object to add menu items for itself - ScriptEngine* scriptEngine = new ScriptEngine(script, wantMenuItems, fileName, Menu::getInstance(), + ScriptEngine* scriptEngine = new ScriptEngine(script, wantMenuItems, fileName, Menu::getInstance(), &_controllerScriptingInterface); scriptEngine->setupMenuItems(); - + // setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so // we can use the same ones from the application. scriptEngine->getVoxelsScriptingInterface()->setPacketSender(&_voxelEditSender); @@ -4501,7 +4509,7 @@ void Application::loadScript() { QThread* workerThread = new QThread(this); - // when the worker thread is started, call our engine's run.. + // when the worker thread is started, call our engine's run.. connect(workerThread, SIGNAL(started()), scriptEngine, SLOT(run())); // when the thread is terminated, add both scriptEngine and thread to the deleteLater queue @@ -4510,9 +4518,9 @@ void Application::loadScript() { // when the application is about to quit, stop our script engine so it unwinds properly connect(this, SIGNAL(aboutToQuit()), scriptEngine, SLOT(stop())); - + scriptEngine->moveToThread(workerThread); - + // Starts an event loop, and emits workerThread->started() workerThread->start(); diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index edca3a1fc0..668c12637d 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -7,39 +7,43 @@ // // -#include #include +#include #include #include // usecTimestampNow() -#include - #include -#include "ParticlesScriptingInterface.h" +// This is not ideal, but adding script-engine as a linked library, will cause a circular reference +// I'm open to other potential solutions. Could we change cmake to allow libraries to reference each others +// headers, but not link to each other, this is essentially what this construct is doing, but would be +// better to add includes to the include path, but not link +#include "../../script-engine/src/ScriptEngine.h" + +#include "ParticlesScriptingInterface.h" #include "Particle.h" uint32_t Particle::_nextID = 0; -VoxelsScriptingInterface* Particle::_voxelsScriptingInterface = NULL; -ParticlesScriptingInterface* Particle::_particlesScriptingInterface = NULL; +VoxelEditPacketSender* Particle::_voxelEditSender = NULL; +ParticleEditPacketSender* Particle::_particleEditSender = NULL; -Particle::Particle(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, glm::vec3 gravity, +Particle::Particle(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, bool inHand, QString updateScript, uint32_t id) { - + init(position, radius, color, velocity, gravity, damping, inHand, updateScript, id); } Particle::Particle() { rgbColor noColor = { 0, 0, 0 }; - init(glm::vec3(0,0,0), 0, noColor, glm::vec3(0,0,0), + init(glm::vec3(0,0,0), 0, noColor, glm::vec3(0,0,0), DEFAULT_GRAVITY, DEFAULT_DAMPING, NOT_IN_HAND, DEFAULT_SCRIPT, NEW_PARTICLE); } Particle::~Particle() { } -void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, glm::vec3 gravity, +void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, bool inHand, QString updateScript, uint32_t id) { if (id == NEW_PARTICLE) { _id = _nextID; @@ -51,7 +55,7 @@ void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3 _lastEdited = now; _lastUpdated = now; _created = now; // will get updated as appropriate in setLifetime() - + _position = position; _radius = radius; memcpy(_color, color, sizeof(_color)); @@ -215,7 +219,7 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef _script = tempString; dataAt += scriptLength; bytesRead += scriptLength; - + //printf("Particle::readParticleDataFromBuffer()... "); debugDump(); } return bytesRead; @@ -227,11 +231,11 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe unsigned char* dataAt = data; processedBytes = 0; - // the first part of the data is our octcode... + // the first part of the data is our octcode... int octets = numberOfThreeBitSectionsInCode(data); int lengthOfOctcode = bytesRequiredForCodeLength(octets); - - // we don't actually do anything with this octcode... + + // we don't actually do anything with this octcode... dataAt += lengthOfOctcode; processedBytes += lengthOfOctcode; @@ -240,7 +244,7 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe memcpy(&editID, dataAt, sizeof(editID)); dataAt += sizeof(editID); processedBytes += sizeof(editID); - + // special case for handling "new" particles if (editID == NEW_PARTICLE) { // If this is a NEW_PARTICLE, then we assume that there's an additional uint32_t creatorToken, that @@ -251,19 +255,19 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe processedBytes += sizeof(creatorTokenID); newParticle.setCreatorTokenID(creatorTokenID); newParticle._newlyCreated = true; - + newParticle.setLifetime(0); // this guy is new! } else { newParticle._id = editID; newParticle._newlyCreated = false; - } + } // lastEdited memcpy(&newParticle._lastEdited, dataAt, sizeof(newParticle._lastEdited)); dataAt += sizeof(newParticle._lastEdited); processedBytes += sizeof(newParticle._lastEdited); - + // radius memcpy(&newParticle._radius, dataAt, sizeof(newParticle._radius)); dataAt += sizeof(newParticle._radius); @@ -283,12 +287,12 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe memcpy(&newParticle._velocity, dataAt, sizeof(newParticle._velocity)); dataAt += sizeof(newParticle._velocity); processedBytes += sizeof(newParticle._velocity); - + // gravity memcpy(&newParticle._gravity, dataAt, sizeof(newParticle._gravity)); dataAt += sizeof(newParticle._gravity); processedBytes += sizeof(newParticle._gravity); - + // damping memcpy(&newParticle._damping, dataAt, sizeof(newParticle._damping)); dataAt += sizeof(newParticle._damping); @@ -311,11 +315,11 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe const bool wantDebugging = false; if (wantDebugging) { - printf("Particle::fromEditPacket()...\n"); + printf("Particle::fromEditPacket()...\n"); printf(" Particle id in packet:%u\n", editID); newParticle.debugDump(); } - + return newParticle; } @@ -329,7 +333,7 @@ void Particle::debugDump() const { printf(" color:%d,%d,%d\n", _color[0], _color[1], _color[2]); } -bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, const ParticleDetail* details, +bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, const ParticleDetail* details, unsigned char* bufferOut, int sizeIn, int& sizeOut) { bool success = true; // assume the best @@ -338,13 +342,13 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, for (int i = 0; i < count && success; i++) { // get the octal code for the particle - unsigned char* octcode = pointToOctalCode(details[i].position.x, details[i].position.y, + unsigned char* octcode = pointToOctalCode(details[i].position.x, details[i].position.y, details[i].position.z, details[i].radius); int octets = numberOfThreeBitSectionsInCode(octcode); int lengthOfOctcode = bytesRequiredForCodeLength(octets); int lenfthOfEditData = lengthOfOctcode + expectedEditMessageBytes(); - + // make sure we have room to copy this particle if (sizeOut + lenfthOfEditData > sizeIn) { success = false; @@ -353,9 +357,9 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, memcpy(copyAt, octcode, lengthOfOctcode); copyAt += lengthOfOctcode; sizeOut += lengthOfOctcode; - + // Now add our edit content details... - + // id memcpy(copyAt, &details[i].id, sizeof(details[i].id)); copyAt += sizeof(details[i].id); @@ -419,7 +423,7 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, sizeOut += scriptLength; bool wantDebugging = false; - if (wantDebugging) { + if (wantDebugging) { printf("encodeParticleEditMessageDetails()....\n"); printf("Particle id :%u\n", details[i].id); printf(" nextID:%u\n", _nextID); @@ -433,7 +437,7 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, } // adjust any internal timestamps to fix clock skew for this server -void Particle::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) { +void Particle::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) { unsigned char* dataAt = codeColorBuffer; int octets = numberOfThreeBitSectionsInCode(dataAt); int lengthOfOctcode = bytesRequiredForCodeLength(octets); @@ -456,7 +460,7 @@ void Particle::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssiz uint64_t lastEditedInServerTime = lastEditedInLocalTime + clockSkew; memcpy(dataAt, &lastEditedInServerTime, sizeof(lastEditedInServerTime)); const bool wantDebug = false; - if (wantDebug) { + if (wantDebug) { qDebug("Particle::adjustEditPacketForClockSkew()...\n"); qDebug() << " lastEditedInLocalTime: " << lastEditedInLocalTime << "\n"; qDebug() << " clockSkew: " << clockSkew << "\n"; @@ -470,7 +474,7 @@ void Particle::update() { float elapsed = static_cast(now - _lastUpdated); _lastUpdated = now; float timeElapsed = elapsed / static_cast(USECS_PER_SECOND); - + // calculate our default shouldDie state... then allow script to change it if it wants... float velocityScalar = glm::length(getVelocity()); const float STILL_MOVING = 0.05f / static_cast(TREE_SCALE); @@ -480,13 +484,13 @@ void Particle::update() { bool isInHand = getInHand(); bool shouldDie = getShouldDie() || (!isInHand && !isStillMoving && isReallyOld); setShouldDie(shouldDie); - + runUpdateScript(); // allow the javascript to alter our state - + // If the ball is in hand, it doesn't move or have gravity effect it if (!isInHand) { _position += _velocity * timeElapsed; - + // handle bounces off the ground... if (_position.y <= 0) { _velocity = _velocity * glm::vec3(1,-1,1); @@ -507,21 +511,21 @@ void Particle::runUpdateScript() { if (!_script.isEmpty()) { QScriptEngine engine; - + // register meta-type for glm::vec3 and rgbColor conversions registerMetaTypes(&engine); - + ParticleScriptObject particleScriptable(this); QScriptValue particleValue = engine.newQObject(&particleScriptable); engine.globalObject().setProperty("Particle", particleValue); - + QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE)); engine.globalObject().setProperty("TREE_SCALE", TREE_SCALE); - + QScriptValue result = engine.evaluate(_script); - + particleScriptable.emitUpdate(); - + if (engine.hasUncaughtException()) { int line = engine.uncaughtExceptionLineNumber(); qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n"; @@ -532,45 +536,30 @@ void Particle::runUpdateScript() { void Particle::collisionWithParticle(Particle* other) { if (!_script.isEmpty()) { - QScriptEngine engine; - - // register meta-type for glm::vec3 and rgbColor conversions - registerMetaTypes(&engine); - + ScriptEngine engine(_script); // no menu or controller interface... + + if (_voxelEditSender) { + engine.getVoxelsScriptingInterface()->setPacketSender(_voxelEditSender); + } + if (_particleEditSender) { + engine.getParticlesScriptingInterface()->setPacketSender(_particleEditSender); + } + + // Add the Particle object ParticleScriptObject particleScriptable(this); - QScriptValue particleValue = engine.newQObject(&particleScriptable); - engine.globalObject().setProperty("Particle", particleValue); - - QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE)); - engine.globalObject().setProperty("TREE_SCALE", TREE_SCALE); + engine.registerGlobalObject("Particle", &particleScriptable); + // init and evaluate the script, but return so we can emit the collision + engine.evaluate(); - if (getVoxelsScriptingInterface()) { - QScriptValue voxelScripterValue = engine.newQObject(getVoxelsScriptingInterface()); - engine.globalObject().setProperty("Voxels", voxelScripterValue); - } - - if (getParticlesScriptingInterface()) { - QScriptValue particleScripterValue = engine.newQObject(getParticlesScriptingInterface()); - engine.globalObject().setProperty("Particles", particleScripterValue); - } - - QScriptValue result = engine.evaluate(_script); - ParticleScriptObject otherParticleScriptable(other); particleScriptable.emitCollisionWithParticle(&otherParticleScriptable); - if (getVoxelsScriptingInterface()) { - getVoxelsScriptingInterface()->getPacketSender()->releaseQueuedMessages(); + if (_voxelEditSender) { + _voxelEditSender->releaseQueuedMessages(); } - - if (getParticlesScriptingInterface()) { - getParticlesScriptingInterface()->getPacketSender()->releaseQueuedMessages(); - } - - if (engine.hasUncaughtException()) { - int line = engine.uncaughtExceptionLineNumber(); - qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n"; + if (_particleEditSender) { + _particleEditSender->releaseQueuedMessages(); } } } @@ -578,45 +567,32 @@ void Particle::collisionWithParticle(Particle* other) { void Particle::collisionWithVoxel(VoxelDetail* voxelDetails) { if (!_script.isEmpty()) { - QScriptEngine engine; - - // register meta-type for glm::vec3 and rgbColor conversions - registerMetaTypes(&engine); - + ScriptEngine engine(_script); // no menu or controller interface... + + // setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so + // we can use the same ones as our context. + if (_voxelEditSender) { + engine.getVoxelsScriptingInterface()->setPacketSender(_voxelEditSender); + } + if (_particleEditSender) { + engine.getParticlesScriptingInterface()->setPacketSender(_particleEditSender); + } + + // Add the Particle object ParticleScriptObject particleScriptable(this); - QScriptValue particleValue = engine.newQObject(&particleScriptable); - engine.globalObject().setProperty("Particle", particleValue); - - QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE)); - engine.globalObject().setProperty("TREE_SCALE", TREE_SCALE); + engine.registerGlobalObject("Particle", &particleScriptable); + // init and evaluate the script, but return so we can emit the collision + engine.evaluate(); - if (getVoxelsScriptingInterface()) { - QScriptValue voxelScripterValue = engine.newQObject(getVoxelsScriptingInterface()); - engine.globalObject().setProperty("Voxels", voxelScripterValue); - } - - if (getParticlesScriptingInterface()) { - QScriptValue particleScripterValue = engine.newQObject(getParticlesScriptingInterface()); - engine.globalObject().setProperty("Particles", particleScripterValue); - } - - QScriptValue result = engine.evaluate(_script); - VoxelDetailScriptObject voxelDetailsScriptable(voxelDetails); particleScriptable.emitCollisionWithVoxel(&voxelDetailsScriptable); - if (getVoxelsScriptingInterface()) { - getVoxelsScriptingInterface()->getPacketSender()->releaseQueuedMessages(); + if (_voxelEditSender) { + _voxelEditSender->releaseQueuedMessages(); } - - if (getParticlesScriptingInterface()) { - getParticlesScriptingInterface()->getPacketSender()->releaseQueuedMessages(); - } - - if (engine.hasUncaughtException()) { - int line = engine.uncaughtExceptionLineNumber(); - qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n"; + if (_particleEditSender) { + _particleEditSender->releaseQueuedMessages(); } } } @@ -625,7 +601,7 @@ void Particle::collisionWithVoxel(VoxelDetail* voxelDetails) { void Particle::setLifetime(float lifetime) { uint64_t lifetimeInUsecs = lifetime * USECS_PER_SECOND; - _created = usecTimestampNow() - lifetimeInUsecs; + _created = usecTimestampNow() - lifetimeInUsecs; } void Particle::copyChangedProperties(const Particle& other) { diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index 9c92d0ec48..e93790eab7 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -21,6 +21,8 @@ class VoxelsScriptingInterface; class ParticlesScriptingInterface; +class VoxelEditPacketSender; +class ParticleEditPacketSender; const uint32_t NEW_PARTICLE = 0xFFFFFFFF; @@ -48,19 +50,19 @@ const bool IN_HAND = true; // it's in a hand const bool NOT_IN_HAND = !IN_HAND; // it's not in a hand class Particle { - + public: Particle(); - Particle(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, - glm::vec3 gravity = DEFAULT_GRAVITY, float damping = DEFAULT_DAMPING, bool inHand = NOT_IN_HAND, + Particle(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, + glm::vec3 gravity = DEFAULT_GRAVITY, float damping = DEFAULT_DAMPING, bool inHand = NOT_IN_HAND, QString updateScript = DEFAULT_SCRIPT, uint32_t id = NEW_PARTICLE); - + /// creates an NEW particle from an PACKET_TYPE_PARTICLE_ADD_OR_EDIT edit data buffer - static Particle fromEditPacket(unsigned char* data, int length, int& processedBytes); - + static Particle fromEditPacket(unsigned char* data, int length, int& processedBytes); + virtual ~Particle(); - virtual void init(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, - glm::vec3 gravity = DEFAULT_GRAVITY, float damping = DEFAULT_DAMPING, bool inHand = NOT_IN_HAND, + virtual void init(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, + glm::vec3 gravity = DEFAULT_GRAVITY, float damping = DEFAULT_DAMPING, bool inHand = NOT_IN_HAND, QString updateScript = DEFAULT_SCRIPT, uint32_t id = NEW_PARTICLE); const glm::vec3& getPosition() const { return _position; } @@ -71,7 +73,7 @@ public: const glm::vec3& getGravity() const { return _gravity; } bool getInHand() const { return _inHand; } float getDamping() const { return _damping; } - + /// The last updated/simulated time of this particle from the time perspective of the authoritative server/source uint64_t getLastUpdated() const { return _lastUpdated; } @@ -91,9 +93,9 @@ public: void setVelocity(const glm::vec3& value) { _velocity = value; } void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); } void setColor(const xColor& value) { - _color[RED_INDEX] = value.red; - _color[GREEN_INDEX] = value.green; - _color[BLUE_INDEX] = value.blue; + _color[RED_INDEX] = value.red; + _color[GREEN_INDEX] = value.green; + _color[BLUE_INDEX] = value.blue; } void setRadius(float value) { _radius = value; } void setGravity(const glm::vec3& value) { _gravity = value; } @@ -102,15 +104,15 @@ public: void setShouldDie(bool shouldDie) { _shouldDie = shouldDie; } void setScript(QString updateScript) { _script = updateScript; } void setCreatorTokenID(uint32_t creatorTokenID) { _creatorTokenID = creatorTokenID; } - + bool appendParticleData(OctreePacketData* packetData) const; int readParticleDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); static int expectedBytes(); static int expectedEditMessageBytes(); - static bool encodeParticleEditMessageDetails(PACKET_TYPE command, int count, const ParticleDetail* details, + static bool encodeParticleEditMessageDetails(PACKET_TYPE command, int count, const ParticleDetail* details, unsigned char* bufferOut, int sizeIn, int& sizeOut); - + static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew); void update(); @@ -118,22 +120,23 @@ public: void collisionWithVoxel(VoxelDetail* voxel); void debugDump() const; - + // similar to assignment/copy, but it handles keeping lifetime accurate void copyChangedProperties(const Particle& other); - - static VoxelsScriptingInterface* getVoxelsScriptingInterface() { return _voxelsScriptingInterface; } - static ParticlesScriptingInterface* getParticlesScriptingInterface() { return _particlesScriptingInterface; } - static void setVoxelsScriptingInterface(VoxelsScriptingInterface* interface) - { _voxelsScriptingInterface = interface; } - - static void setParticlesScriptingInterface(ParticlesScriptingInterface* interface) - { _particlesScriptingInterface = interface; } - + static VoxelEditPacketSender* getVoxelEditPacketSender() { return _voxelEditSender; } + static ParticleEditPacketSender* getParticleEditPacketSender() { return _particleEditSender; } + + static void setVoxelEditPacketSender(VoxelEditPacketSender* interface) + { _voxelEditSender = interface; } + + static void setParticleEditPacketSender(ParticleEditPacketSender* interface) + { _particleEditSender = interface; } + + protected: - static VoxelsScriptingInterface* _voxelsScriptingInterface; - static ParticlesScriptingInterface* _particlesScriptingInterface; + static VoxelEditPacketSender* _voxelEditSender; + static ParticleEditPacketSender* _particleEditSender; void runUpdateScript(); static QScriptValue vec3toScriptValue(QScriptEngine *engine, const glm::vec3 &vec3); @@ -141,8 +144,8 @@ protected: static QScriptValue xColorToScriptValue(QScriptEngine *engine, const xColor& color); static void xColorFromScriptValue(const QScriptValue &object, xColor& color); - void setLifetime(float lifetime); - + void setLifetime(float lifetime); + glm::vec3 _position; rgbColor _color; float _radius; @@ -184,7 +187,7 @@ public slots: float getRadius() const { return _particle->getRadius(); } bool getShouldDie() { return _particle->getShouldDie(); } float getLifetime() const { return _particle->getLifetime(); } - + void setPosition(glm::vec3 value) { _particle->setPosition(value); } void setVelocity(glm::vec3 value) { _particle->setVelocity(value); } void setGravity(glm::vec3 value) { _particle->setGravity(value); } diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 64bcb93696..86b6e8884e 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -19,11 +19,14 @@ #include #include #include +#include #include #include "ScriptEngine.h" +const unsigned int VISUAL_DATA_CALLBACK_USECS = (1.0 / 60.0) * 1000 * 1000; + int ScriptEngine::_scriptNumber = 1; VoxelsScriptingInterface ScriptEngine::_voxelsScriptingInterface; ParticlesScriptingInterface ScriptEngine::_particlesScriptingInterface; @@ -31,7 +34,7 @@ ParticlesScriptingInterface ScriptEngine::_particlesScriptingInterface; static QScriptValue soundConstructor(QScriptContext* context, QScriptEngine* engine) { QUrl soundURL = QUrl(context->argument(0).toString()); QScriptValue soundScriptValue = engine->newQObject(new Sound(soundURL), QScriptEngine::ScriptOwnership); - + return soundScriptValue; } @@ -41,7 +44,8 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, _scriptContents = scriptContents; _isFinished = false; _isRunning = false; - + _isInitialized = false; + // some clients will use these menu features _wantMenuItems = wantMenuItems; if (scriptMenuName) { @@ -54,15 +58,6 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, } _menu = menu; _controllerScriptingInterface = controllerScriptingInterface; - - // hook up our interfaces - if (!Particle::getVoxelsScriptingInterface()) { - Particle::setVoxelsScriptingInterface(getVoxelsScriptingInterface()); - } - - if (!Particle::getParticlesScriptingInterface()) { - Particle::setParticlesScriptingInterface(getParticlesScriptingInterface()); - } } ScriptEngine::~ScriptEngine() { @@ -92,63 +87,89 @@ bool ScriptEngine::setScriptContents(const QString& scriptContents) { Q_SCRIPT_DECLARE_QMETAOBJECT(AudioInjectorOptions, QObject*) -void ScriptEngine::run() { - _isRunning = true; - QScriptEngine engine; - +void ScriptEngine::init() { + if (_isInitialized) { + return; // only initialize once + } + + _isInitialized = true; + _voxelsScriptingInterface.init(); _particlesScriptingInterface.init(); - - // register meta-type for glm::vec3 conversions - registerMetaTypes(&engine); - - QScriptValue agentValue = engine.newQObject(this); - engine.globalObject().setProperty("Agent", agentValue); - - QScriptValue voxelScripterValue = engine.newQObject(&_voxelsScriptingInterface); - engine.globalObject().setProperty("Voxels", voxelScripterValue); - QScriptValue particleScripterValue = engine.newQObject(&_particlesScriptingInterface); - engine.globalObject().setProperty("Particles", particleScripterValue); - - - QScriptValue soundConstructorValue = engine.newFunction(soundConstructor); - QScriptValue soundMetaObject = engine.newQMetaObject(&Sound::staticMetaObject, soundConstructorValue); - engine.globalObject().setProperty("Sound", soundMetaObject); - - QScriptValue injectionOptionValue = engine.scriptValueFromQMetaObject(); - engine.globalObject().setProperty("AudioInjectionOptions", injectionOptionValue); - - QScriptValue audioScriptingInterfaceValue = engine.newQObject(&_audioScriptingInterface); - engine.globalObject().setProperty("Audio", audioScriptingInterfaceValue); - + // register meta-type for glm::vec3 conversions + registerMetaTypes(&_engine); + + QScriptValue agentValue = _engine.newQObject(this); + _engine.globalObject().setProperty("Agent", agentValue); + + QScriptValue voxelScripterValue = _engine.newQObject(&_voxelsScriptingInterface); + _engine.globalObject().setProperty("Voxels", voxelScripterValue); + + QScriptValue particleScripterValue = _engine.newQObject(&_particlesScriptingInterface); + _engine.globalObject().setProperty("Particles", particleScripterValue); + + QScriptValue soundConstructorValue = _engine.newFunction(soundConstructor); + QScriptValue soundMetaObject = _engine.newQMetaObject(&Sound::staticMetaObject, soundConstructorValue); + _engine.globalObject().setProperty("Sound", soundMetaObject); + + QScriptValue injectionOptionValue = _engine.scriptValueFromQMetaObject(); + _engine.globalObject().setProperty("AudioInjectionOptions", injectionOptionValue); + + QScriptValue audioScriptingInterfaceValue = _engine.newQObject(&_audioScriptingInterface); + _engine.globalObject().setProperty("Audio", audioScriptingInterfaceValue); + if (_controllerScriptingInterface) { - QScriptValue controllerScripterValue = engine.newQObject(_controllerScriptingInterface); - engine.globalObject().setProperty("Controller", controllerScripterValue); + QScriptValue controllerScripterValue = _engine.newQObject(_controllerScriptingInterface); + _engine.globalObject().setProperty("Controller", controllerScripterValue); } - - QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE)); - engine.globalObject().setProperty("TREE_SCALE", treeScaleValue); - - const unsigned int VISUAL_DATA_CALLBACK_USECS = (1.0 / 60.0) * 1000 * 1000; - + + QScriptValue treeScaleValue = _engine.newVariant(QVariant(TREE_SCALE)); + _engine.globalObject().setProperty("TREE_SCALE", treeScaleValue); + // let the VoxelPacketSender know how frequently we plan to call it _voxelsScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); _particlesScriptingInterface.getParticlePacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); //qDebug() << "Script:\n" << _scriptContents << "\n"; - - QScriptValue result = engine.evaluate(_scriptContents); +} + +void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) { + QScriptValue value = _engine.newQObject(object); + _engine.globalObject().setProperty(name, value); +} + +void ScriptEngine::evaluate() { + if (!_isInitialized) { + init(); + } + + QScriptValue result = _engine.evaluate(_scriptContents); qDebug() << "Evaluated script.\n"; - - if (engine.hasUncaughtException()) { - int line = engine.uncaughtExceptionLineNumber(); + + if (_engine.hasUncaughtException()) { + int line = _engine.uncaughtExceptionLineNumber(); qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n"; } - +} + +void ScriptEngine::run() { + if (!_isInitialized) { + init(); + } + _isRunning = true; + + QScriptValue result = _engine.evaluate(_scriptContents); + qDebug() << "Evaluated script.\n"; + + if (_engine.hasUncaughtException()) { + int line = _engine.uncaughtExceptionLineNumber(); + qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n"; + } + timeval startTime; gettimeofday(&startTime, NULL); - + int thisFrame = 0; while (!_isFinished) { @@ -166,15 +187,15 @@ void ScriptEngine::run() { if (_isFinished) { break; } - + bool willSendVisualDataCallBack = false; - if (_voxelsScriptingInterface.getVoxelPacketSender()->serversExist()) { + if (_voxelsScriptingInterface.getVoxelPacketSender()->serversExist()) { // allow the scripter's call back to setup visual data willSendVisualDataCallBack = true; - + // release the queue of edit voxel messages. _voxelsScriptingInterface.getVoxelPacketSender()->releaseQueuedMessages(); - + // since we're in non-threaded mode, call process so that the packets are sent if (!_voxelsScriptingInterface.getVoxelPacketSender()->isThreaded()) { _voxelsScriptingInterface.getVoxelPacketSender()->process(); @@ -184,23 +205,23 @@ void ScriptEngine::run() { if (_particlesScriptingInterface.getParticlePacketSender()->serversExist()) { // allow the scripter's call back to setup visual data willSendVisualDataCallBack = true; - + // release the queue of edit voxel messages. _particlesScriptingInterface.getParticlePacketSender()->releaseQueuedMessages(); - + // since we're in non-threaded mode, call process so that the packets are sent if (!_particlesScriptingInterface.getParticlePacketSender()->isThreaded()) { _particlesScriptingInterface.getParticlePacketSender()->process(); } } - + if (willSendVisualDataCallBack) { emit willSendVisualDataCallback(); } - if (engine.hasUncaughtException()) { - int line = engine.uncaughtExceptionLineNumber(); - qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n"; + if (_engine.hasUncaughtException()) { + int line = _engine.uncaughtExceptionLineNumber(); + qDebug() << "Uncaught exception at line" << line << ":" << _engine.uncaughtException().toString() << "\n"; } } cleanMenuItems(); @@ -213,9 +234,8 @@ void ScriptEngine::run() { emit finished(); _isRunning = false; } - -void ScriptEngine::stop() { - _isFinished = true; +void ScriptEngine::stop() { + _isFinished = true; } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 49ed913744..842b902fcf 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -17,9 +17,10 @@ #include #include -#include #include +class ParticlesScriptingInterface; + #include "AbstractControllerScriptingInterface.h" const QString NO_SCRIPT(""); @@ -27,12 +28,12 @@ const QString NO_SCRIPT(""); class ScriptEngine : public QObject { Q_OBJECT 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, AbstractControllerScriptingInterface* controllerScriptingInterface = NULL); ~ScriptEngine(); - + /// Access the VoxelsScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener VoxelsScriptingInterface* getVoxelsScriptingInterface() { return &_voxelsScriptingInterface; } @@ -44,11 +45,15 @@ public: void setupMenuItems(); void cleanMenuItems(); - + + void registerGlobalObject(const QString& name, QObject* object); /// registers a global object by name + public slots: - void run(); + void init(); + void run(); /// runs continuously until Agent.stop() is called void stop(); - + void evaluate(); /// initializes the engine, and evaluates the script, but then returns control to caller + signals: void willSendAudioDataCallback(); void willSendVisualDataCallback(); @@ -57,7 +62,8 @@ protected: QString _scriptContents; bool _isFinished; bool _isRunning; - + bool _isInitialized; + QScriptEngine _engine; private: static VoxelsScriptingInterface _voxelsScriptingInterface;