History

resolve conflicts on merge with upstream master

Stephen Birarda committed 12 years ago

Commit efcf5062 parents 45d796e 72d09a576 files · +5243 −2058Browse files

Showing the changes to interface/src/Application.cpp (1 of 76 files). Show all

Unified · Split

interface/src/Application.cpp+305−593
@@ -49,7 +49,7 @@ · 48 unmodified lines
4949 #include <QXmlStreamReader>
5050 #include <QXmlStreamAttributes>
5151 #include <QMediaPlayer>
52−#include <QMimeData>
52+#include <QMimeData>
5353 #include <QMessageBox>
5454
5555 #include <AccountManager.h>
@@ -63,7 +63,7 @@ · 7 unmodified lines
6363 #include <UUID.h>
6464 #include <OctreeSceneStats.h>
6565 #include <LocalVoxelsList.h>
66−#include <FstReader.h>
66+#include <ModelUploader.h>
6767
6868 #include "Application.h"
6969 #include "InterfaceVersion.h"
@@ -81,6 +81,7 @@ · 11 unmodified lines
8181 #include "ui/InfoView.h"
8282 #include "ui/Snapshot.h"
8383 #include "ui/TextRenderer.h"
84+#include "ui/Stats.h"
8485
8586 using namespace std;
8687
@@ -110,15 +111,11 @@ const float MIRROR_FIELD_OF_VIEW = 30.0f; · 23 unmodified lines
110111 const QString CHECK_VERSION_URL = "http://highfidelity.io/latestVersion.xml";
111112 const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/hifi.skipversion";
112113
113−const int STATS_PELS_PER_LINE = 20;
114−
115−const QString CUSTOM_URL_SCHEME = "hifi:";
116−
117114 void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
118115 if (message.size() > 0) {
119116 QString dateString = QDateTime::currentDateTime().toTimeSpec(Qt::LocalTime).toString(Qt::ISODate);
120117 QString formattedMessage = QString("[%1] %2\n").arg(dateString).arg(message);
121−
118+
122119 fprintf(stdout, "%s", qPrintable(formattedMessage));
123120 Application::getInstance()->getLogger()->addMessage(qPrintable(formattedMessage));
124121 }
@@ -137,7 +134,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 12 unmodified lines
137134 QApplication(argc, argv),
138135 _window(new QMainWindow(desktop())),
139136 _glWidget(new GLCanvas()),
140− _statsExpanded(false),
141137 _nodeThread(new QThread(this)),
142138 _datagramProcessor(),
143139 _frameCount(0),
@@ -167,8 +163,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 23 unmodified lines
167163 _voxelHideShowThread(&_voxels),
168164 _packetsPerSecond(0),
169165 _bytesPerSecond(0),
170− _recentMaxPackets(0),
171− _resetRecentMaxPacketsSoon(true),
166+ _previousScriptLocation(),
172167 _logger(new FileLogger(this))
173168 {
174169 // init GnuTLS for DTLS with domain-servers
@@ -176,23 +171,23 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 1 unmodified line
176171
177172 // read the ApplicationInfo.ini file for Name/Version/Domain information
178173 QSettings applicationInfo(Application::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat);
179−
174+
180175 // set the associated application properties
181176 applicationInfo.beginGroup("INFO");
182−
177+
183178 qDebug() << "[VERSION] Build sequence: " << qPrintable(applicationVersion());
184−
179+
185180 setApplicationName(applicationInfo.value("name").toString());
186181 setApplicationVersion(BUILD_VERSION);
187182 setOrganizationName(applicationInfo.value("organizationName").toString());
188183 setOrganizationDomain(applicationInfo.value("organizationDomain").toString());
189−
184+
190185 QSettings::setDefaultFormat(QSettings::IniFormat);
191−
186+
192187 _myAvatar = _avatarManager.getMyAvatar();
193188
194189 _applicationStartupTime = startup_time;
195−
190+
196191 QFontDatabase::addApplicationFont(Application::resourcesPath() + "styles/Inconsolata.otf");
197192 _window->setWindowTitle("Interface");
198193
@@ -207,19 +202,19 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 8 unmodified lines
207202 if (portStr) {
208203 listenPort = atoi(portStr);
209204 }
210−
205+
211206 // start the nodeThread so its event loop is running
212207 _nodeThread->start();
213−
208+
214209 // make sure the node thread is given highest priority
215210 _nodeThread->setPriority(QThread::TimeCriticalPriority);
216−
211+
217212 // put the NodeList and datagram processing on the node thread
218213 NodeList* nodeList = NodeList::createInstance(NodeType::Agent, listenPort);
219−
214+
220215 nodeList->moveToThread(_nodeThread);
221216 _datagramProcessor.moveToThread(_nodeThread);
222−
217+
223218 // connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal
224219 connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), &_datagramProcessor, SLOT(processDatagrams()));
225220
@@ -241,20 +236,20 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 15 unmodified lines
241236 connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), &_voxels, SLOT(nodeKilled(SharedNodePointer)));
242237 connect(nodeList, &NodeList::uuidChanged, this, &Application::updateWindowTitle);
243238 connect(nodeList, &NodeList::limitOfSilentDomainCheckInsReached, nodeList, &NodeList::reset);
244−
239+
245240 // connect to appropriate slots on AccountManager
246241 AccountManager& accountManager = AccountManager::getInstance();
247242 connect(&accountManager, &AccountManager::authRequired, Menu::getInstance(), &Menu::loginForCurrentDomain);
248243 connect(&accountManager, &AccountManager::usernameChanged, this, &Application::updateWindowTitle);
249−
244+
250245 // set the account manager's root URL and trigger a login request if we don't have the access token
251246 accountManager.setAuthURL(DEFAULT_NODE_AUTH_URL);
252−
247+
253248 // once the event loop has started, check and signal for an access token
254249 QMetaObject::invokeMethod(&accountManager, "checkAndSignalForAccessToken", Qt::QueuedConnection);
255250
256251 _settings = new QSettings(this);
257−
252+
258253 // Check to see if the user passed in a command line option for loading a local
259254 // Voxel File.
260255 _voxelsFilename = getCmdOption(argc, constArgv, "-i");
@@ -268,7 +263,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 7 unmodified lines
268263 nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer
269264 << NodeType::VoxelServer << NodeType::ParticleServer
270265 << NodeType::MetavoxelServer);
271−
266+
272267 // connect to the packet sent signal of the _voxelEditSender and the _particleEditSender
273268 connect(&_voxelEditSender, &VoxelEditPacketSender::packetSent, this, &Application::packetSent);
274269 connect(&_particleEditSender, &ParticleEditPacketSender::packetSent, this, &Application::packetSent);
@@ -278,7 +273,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 3 unmodified lines
278273 connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
279274 silentNodeTimer->moveToThread(_nodeThread);
280275 silentNodeTimer->start(NODE_SILENCE_THRESHOLD_MSECS);
281−
276+
282277 // send the identity packet for our avatar each second to our avatar mixer
283278 QTimer* identityPacketTimer = new QTimer();
284279 connect(identityPacketTimer, &QTimer::timeout, _myAvatar, &MyAvatar::sendIdentityPacket);
@@ -326,14 +321,18 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 41 unmodified lines
326321
327322 // Set the sixense filtering
328323 _sixenseManager.setFilter(Menu::getInstance()->isOptionChecked(MenuOption::FilterSixense));
329−
324+
330325 checkVersion();
331−
326+
332327 _overlays.init(_glWidget); // do this before scripts load
333−
328+
334329 LocalVoxelsList::getInstance()->addPersistantTree(DOMAIN_TREE_NAME, _voxels.getTree());
335330 LocalVoxelsList::getInstance()->addPersistantTree(CLIPBOARD_TREE_NAME, &_clipboard);
336331
332+ _window->addDockWidget(Qt::NoDockWidgetArea, _runningScriptsWidget = new RunningScriptsWidget());
333+ _runningScriptsWidget->setRunningScripts(getRunningScripts());
334+ connect(_runningScriptsWidget, &RunningScriptsWidget::stopScriptName, this, &Application::stopScript);
335+
337336 // check first run...
338337 QVariant firstRunValue = _settings->value("firstRun",QVariant(true));
339338 if (firstRunValue.isValid() && firstRunValue.toBool()) {
@@ -341,7 +340,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 1 unmodified line
341340 // clear the scripts, and set out script to our default scripts
342341 clearScriptsBeforeRunning();
343342 loadScript("http://public.highfidelity.io/scripts/defaultScripts.js");
344−
343+
345344 _settings->setValue("firstRun",QVariant(false));
346345 } else {
347346 // do this as late as possible so that all required subsystems are inialized
@@ -352,31 +351,34 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 4 unmodified lines
352351 Application::~Application() {
353352
354353 qInstallMessageHandler(NULL);
355−
354+
356355 // make sure we don't call the idle timer any more
357356 delete idleTimer;
358−
357+
359358 Menu::getInstance()->saveSettings();
360359 _rearMirrorTools->saveSettings(_settings);
361−
360+
362361 _sharedVoxelSystem.changeTree(new VoxelTree);
363362 if (_voxelImporter) {
364363 _voxelImporter->saveSettings(_settings);
365364 delete _voxelImporter;
366365 }
367366 _settings->sync();
368−
367+
369368 // let the avatar mixer know we're out
370369 MyAvatar::sendKillAvatar();
371−
370+
372371 // ask the datagram processing thread to quit and wait until it is done
373372 _nodeThread->quit();
374373 _nodeThread->wait();
375−
374+
375+ // stop the audio process
376+ QMetaObject::invokeMethod(&_audio, "stop");
377+
376378 // ask the audio thread to quit and wait until it is done
377379 _audio.thread()->quit();
378380 _audio.thread()->wait();
379−
381+
380382 _voxelProcessor.terminate();
381383 _voxelHideShowThread.terminate();
382384 _voxelEditSender.terminate();
@@ -389,9 +391,9 @@ Application::~Application() { · 6 unmodified lines
389391 Menu::getInstance()->deleteLater();
390392
391393 _myAvatar = NULL;
392−
394+
393395 delete _glWidget;
394−
396+
395397 AccountManager::getInstance().destroy();
396398
397399 gnutls_global_deinit();
@@ -513,7 +515,7 @@ void Application::paintGL() { · 115 unmodified lines
513515 _myCamera.setDistance(0.0f);
514516 _myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing
515517 _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition());
516− _myCamera.setTargetRotation(_myAvatar->getHead()->getOrientation());
518+ _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation());
517519
518520 } else if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
519521 _myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay
@@ -585,7 +587,7 @@ void Application::paintGL() { · 65 unmodified lines
585587
586588 if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
587589 renderRearViewMirror(_mirrorViewRect);
588−
590+
589591 } else if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
590592 _rearMirrorTools->render(true);
591593 }
@@ -615,6 +617,14 @@ void Application::resizeGL(int width, int height) { · 23 unmodified lines
615617
616618 updateProjectionMatrix();
617619 glLoadIdentity();
620+
621+ // update Stats width
622+ int horizontalOffset = 0;
623+ if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
624+ // mirror is enabled, let's set horizontal offset to give stats some margin
625+ horizontalOffset += MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2;
626+ }
627+ Stats::getInstance()->resetWidth(width, horizontalOffset);
618628 }
619629
620630 void Application::updateProjectionMatrix() {
@@ -658,10 +668,10 @@ void Application::controlledBroadcastToNodes(const QByteArray& packet, const Nod · 37 unmodified lines
658668 if (type == NodeType::VoxelServer && !Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
659669 continue;
660670 }
661−
671+
662672 // Perform the broadcast for one type
663673 int nReceivingNodes = NodeList::getInstance()->broadcastToNodes(packet, NodeSet() << type);
664−
674+
665675 // Feed number of bytes to corresponding channel of the bandwidth meter, if any (done otherwise)
666676 BandwidthMeter::ChannelIndex channel;
667677 switch (type) {
@@ -680,32 +690,15 @@ void Application::controlledBroadcastToNodes(const QByteArray& packet, const Nod · 12 unmodified lines
680690 }
681691
682692 bool Application::event(QEvent* event) {
683−
693+
684694 // handle custom URL
685695 if (event->type() == QEvent::FileOpen) {
686696 QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event);
687− if (!fileEvent->url().isEmpty() && fileEvent->url().toLocalFile().startsWith(CUSTOM_URL_SCHEME)) {
688− QString destination = fileEvent->url().toLocalFile().remove(CUSTOM_URL_SCHEME);
689− QStringList urlParts = destination.split('/', QString::SkipEmptyParts);
690−
691− if (urlParts.count() > 1) {
692− // if url has 2 or more parts, the first one is domain name
693− Menu::getInstance()->goToDomain(urlParts[0]);
694−
695− // location coordinates
696− Menu::getInstance()->goToDestination(urlParts[1]);
697− if (urlParts.count() > 2) {
698−
699− // location orientation
700− Menu::getInstance()->goToOrientation(urlParts[2]);
701− }
702− } else if (urlParts.count() == 1) {
703−
704− // location coordinates
705− Menu::getInstance()->goToDestination(urlParts[0]);
706− }
697+ bool isHifiSchemeURL = !fileEvent->url().isEmpty() && fileEvent->url().toLocalFile().startsWith(CUSTOM_URL_SCHEME);
698+ if (isHifiSchemeURL) {
699+ Menu::getInstance()->goTo(fileEvent->url().toString());
707700 }
708−
701+
709702 return false;
710703 }
711704 return QApplication::event(event);
@@ -716,7 +709,7 @@ void Application::keyPressEvent(QKeyEvent* event) { · 4 unmodified lines
716709 _keysPressed.insert(event->key());
717710
718711 _controllerScriptingInterface.emitKeyPressEvent(event); // send events to any registered scripts
719−
712+
720713 // if one of our scripts have asked to capture this event, then stop processing it
721714 if (_controllerScriptingInterface.isKeyCaptured(event)) {
722715 return;
@@ -1074,8 +1067,12 @@ void Application::mouseReleaseEvent(QMouseEvent* event) { · 351 unmodified lines
10741067 _mousePressed = false;
10751068 checkBandwidthMeterClick();
10761069 if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
1077− checkStatsClick();
1078− }
1070+ int horizontalOffset = 0;
1071+ if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
1072+ horizontalOffset = MIRROR_VIEW_WIDTH;
1073+ }
1074+ Stats::getInstance()->checkClick(_mouseX, _mouseY, _mouseDragStartedX, _mouseDragStartedY, horizontalOffset);
1075+ }
10791076 }
10801077 }
10811078 }
@@ -1124,7 +1121,7 @@ void Application::touchBeginEvent(QTouchEvent* event) { · 42 unmodified lines
11241121 if (_controllerScriptingInterface.isTouchCaptured()) {
11251122 return;
11261123 }
1127−
1124+
11281125 // put any application specific touch behavior below here..
11291126 _lastTouchAvgX = _touchAvgX;
11301127 _lastTouchAvgY = _touchAvgY;
@@ -1167,13 +1164,13 @@ void Application::dropEvent(QDropEvent *event) { · 36 unmodified lines
11671164 break;
11681165 }
11691166 }
1170−
1167+
11711168 SnapshotMetaData* snapshotData = Snapshot::parseSnapshotData(snapshotPath);
11721169 if (snapshotData) {
11731170 if (!snapshotData->getDomain().isEmpty()) {
11741171 Menu::getInstance()->goToDomain(snapshotData->getDomain());
11751172 }
1176−
1173+
11771174 _myAvatar->setPosition(snapshotData->getLocation());
11781175 _myAvatar->setOrientation(snapshotData->getOrientation());
11791176 } else {
@@ -1201,19 +1198,19 @@ void Application::timer() { · 21 unmodified lines
12011198 }
12021199
12031200 _fps = (float)_frameCount / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
1204−
1201+
12051202 _packetsPerSecond = (float) _datagramProcessor.getPacketCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
12061203 _bytesPerSecond = (float) _datagramProcessor.getByteCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
12071204 _frameCount = 0;
1208−
1205+
12091206 _datagramProcessor.resetCounters();
12101207
12111208 gettimeofday(&_timerStart, NULL);
12121209
12131210 // ask the node list to check in with the domain server
12141211 NodeList::getInstance()->sendDomainServerCheckIn();
1215−
1216−
1212+
1213+
12171214 }
12181215
12191216 void Application::idle() {
@@ -1250,11 +1247,11 @@ void Application::idle() { · 30 unmodified lines
12501247 _idleLoopMeasuredJitter = _idleLoopStdev.getStDev();
12511248 _idleLoopStdev.reset();
12521249 }
1253−
1250+
12541251 if (Menu::getInstance()->isOptionChecked(MenuOption::BuckyBalls)) {
12551252 _buckyBalls.simulate(timeSinceLastUpdate / 1000.f, Application::getInstance()->getAvatar()->getHandData());
12561253 }
1257−
1254+
12581255 // After finishing all of the above work, restart the idle timer, allowing 2ms to process events.
12591256 idleTimer->start(2);
12601257 }
@@ -1386,7 +1383,7 @@ void Application::exportVoxels(const VoxelDetail& sourceVoxel) { · 125 unmodified lines
13861383 tr("Sparse Voxel Octree Files (*.svo)"));
13871384 QByteArray fileNameAscii = fileNameString.toLocal8Bit();
13881385 const char* fileName = fileNameAscii.data();
1389−
1386+
13901387 VoxelTreeElement* selectedNode = _voxels.getTree()->getVoxelAt(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s);
13911388 if (selectedNode) {
13921389 VoxelTree exportTree;
@@ -1400,12 +1397,12 @@ void Application::exportVoxels(const VoxelDetail& sourceVoxel) { · 7 unmodified lines
14001397
14011398 void Application::importVoxels() {
14021399 _importSucceded = false;
1403−
1400+
14041401 if (!_voxelImporter) {
14051402 _voxelImporter = new VoxelImporter(_window);
14061403 _voxelImporter->loadSettings(_settings);
14071404 }
1408−
1405+
14091406 if (!_voxelImporter->exec()) {
14101407 qDebug() << "[DEBUG] Import succeeded." << endl;
14111408 _importSucceded = true;
@@ -1419,7 +1416,7 @@ void Application::importVoxels() { · 7 unmodified lines
14191416
14201417 // restore the main window's active state
14211418 _window->activateWindow();
1422−
1419+
14231420 emit importDone();
14241421 }
14251422
@@ -1475,7 +1472,7 @@ void Application::pasteVoxels(const VoxelDetail& sourceVoxel) { · 49 unmodified lines
14751472 }
14761473
14771474 pasteVoxelsToOctalCode(octalCodeDestination);
1478−
1475+
14791476 if (calculatedOctCode) {
14801477 delete[] calculatedOctCode;
14811478 }
@@ -1512,9 +1509,9 @@ void Application::init() { · 30 unmodified lines
15121509
15131510 // Cleanup of the original shared tree
15141511 _sharedVoxelSystem.init();
1515−
1512+
15161513 _voxelImporter = new VoxelImporter(_window);
1517−
1514+
15181515 _environment.init();
15191516
15201517 _glowEffect.init();
@@ -1556,11 +1553,11 @@ void Application::init() { · 35 unmodified lines
15561553 _audio.setJitterBufferSamples(Menu::getInstance()->getAudioJitterBufferSamples());
15571554 }
15581555 qDebug("Loaded settings");
1559−
1556+
15601557 // initialize Visage and Faceshift after loading the menu settings
15611558 _faceshift.init();
15621559 _visage.init();
1563−
1560+
15641561 // fire off an immediate domain-server check in now that settings are loaded
15651562 NodeList::getInstance()->sendDomainServerCheckIn();
15661563
@@ -1579,20 +1576,20 @@ void Application::init() { · 12 unmodified lines
15791576 _particleCollisionSystem.init(&_particleEditSender, _particles.getTree(), _voxels.getTree(), &_audio, &_avatarManager);
15801577
15811578 // connect the _particleCollisionSystem to our script engine's ParticleScriptingInterface
1582− connect(&_particleCollisionSystem,
1579+ connect(&_particleCollisionSystem,
15831580 SIGNAL(particleCollisionWithVoxel(const ParticleID&, const VoxelDetail&, const glm::vec3&)),
1584− ScriptEngine::getParticlesScriptingInterface(),
1581+ ScriptEngine::getParticlesScriptingInterface(),
15851582 SLOT(forwardParticleCollisionWithVoxel(const ParticleID&, const VoxelDetail&, const glm::vec3&)));
15861583
1587− connect(&_particleCollisionSystem,
1584+ connect(&_particleCollisionSystem,
15881585 SIGNAL(particleCollisionWithParticle(const ParticleID&, const ParticleID&, const glm::vec3&)),
1589− ScriptEngine::getParticlesScriptingInterface(),
1586+ ScriptEngine::getParticlesScriptingInterface(),
15901587 SLOT(forwardParticleCollisionWithParticle(const ParticleID&, const ParticleID&, const glm::vec3&)));
1591−
1588+
15921589 _audio.init(_glWidget);
15931590
15941591 _rearMirrorTools = new RearMirrorTools(_glWidget, _mirrorViewRect, _settings);
1595−
1592+
15961593 connect(_rearMirrorTools, SIGNAL(closeView()), SLOT(closeMirrorView()));
15971594 connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView()));
15981595 connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView()));
@@ -1715,7 +1712,7 @@ void Application::updateMyAvatarLookAtPosition() { · 116 unmodified lines
17151712 float distance = TREE_SCALE;
17161713 if (_myAvatar->getLookAtTargetAvatar() && _myAvatar != _myAvatar->getLookAtTargetAvatar()) {
17171714 distance = glm::distance(_mouseRayOrigin,
1718− static_cast<Avatar*>(_myAvatar->getLookAtTargetAvatar())->getHead()->calculateAverageEyePosition());
1715+ static_cast<Avatar*>(_myAvatar->getLookAtTargetAvatar())->getHead()->calculateAverageEyePosition());
17191716 }
17201717 const float FIXED_MIN_EYE_DISTANCE = 0.3f;
17211718 float minEyeDistance = FIXED_MIN_EYE_DISTANCE + (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON ? 0.0f :
@@ -1728,7 +1725,7 @@ void Application::updateMyAvatarLookAtPosition() { · 6 unmodified lines
17281725 eyePitch = _faceshift.getEstimatedEyePitch();
17291726 eyeYaw = _faceshift.getEstimatedEyeYaw();
17301727 trackerActive = true;
1731−
1728+
17321729 } else if (_visage.isActive()) {
17331730 eyePitch = _visage.getEstimatedEyePitch();
17341731 eyeYaw = _visage.getEstimatedEyeYaw();
@@ -1849,15 +1846,6 @@ void Application::updateDialogs(float deltaTime) { · 114 unmodified lines
18491846 }
18501847 }
18511848
1852−void Application::updateAudio(float deltaTime) {
1853− bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
1854− PerformanceWarning warn(showWarnings, "Application::updateAudio()");
1855−
1856− // Update audio stats for procedural sounds
1857− _audio.setLastAcceleration(_myAvatar->getThrust());
1858− _audio.setLastVelocity(_myAvatar->getVelocity());
1859−}
1860−
18611849 void Application::updateCursor(float deltaTime) {
18621850 bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
18631851 PerformanceWarning warn(showWarnings, "Application::updateCursor()");
@@ -1906,14 +1894,13 @@ void Application::update(float deltaTime) { · 42 unmodified lines
19061894 updateMetavoxels(deltaTime); // update metavoxels
19071895 updateCamera(deltaTime); // handle various camera tweaks like off axis projection
19081896 updateDialogs(deltaTime); // update various stats dialogs if present
1909− updateAudio(deltaTime); // Update audio stats for procedural sounds
19101897 updateCursor(deltaTime); // Handle cursor updates
19111898
19121899 _particles.update(); // update the particles...
19131900 _particleCollisionSystem.update(); // collide the particles...
1914−
1901+
19151902 _overlays.update(deltaTime);
1916−
1903+
19171904 // let external parties know we're updating
19181905 emit simulating(deltaTime);
19191906 }
@@ -1937,7 +1924,7 @@ void Application::updateMyAvatar(float deltaTime) { · 17 unmodified lines
19371924 // actually need to calculate the view frustum planes to send these details
19381925 // to the server.
19391926 loadViewFrustum(_myCamera, _viewFrustum);
1940−
1927+
19411928 // Update my voxel servers with my current voxel query...
19421929 quint64 now = usecTimestampNow();
19431930 quint64 sinceLastQuery = now - _lastQueriedTime;
@@ -2213,7 +2200,7 @@ void Application::updateShadowMap() { · 269 unmodified lines
22132200 }
22142201 center = inverseRotation * center;
22152202 glm::vec3 minima(center.x - radius, center.y - radius, center.z - radius);
2216− glm::vec3 maxima(center.x + radius, center.y + radius, center.z + radius);
2203+ glm::vec3 maxima(center.x + radius, center.y + radius, center.z + radius);
22172204
22182205 // stretch out our extents in z so that we get all of the avatars
22192206 minima.z -= _viewFrustum.getFarClip() * 0.5f;
@@ -2234,7 +2221,7 @@ void Application::updateShadowMap() { · 14 unmodified lines
22342221 _shadowViewFrustum.setEyeOffsetPosition(glm::vec3());
22352222 _shadowViewFrustum.setEyeOffsetOrientation(glm::quat());
22362223 _shadowViewFrustum.calculate();
2237−
2224+
22382225 glMatrixMode(GL_PROJECTION);
22392226 glPushMatrix();
22402227 glLoadIdentity();
@@ -2289,19 +2276,19 @@ void Application::setupWorldLight() { · 48 unmodified lines
22892276
22902277 QImage Application::renderAvatarBillboard() {
22912278 _textureCache.getPrimaryFramebufferObject()->bind();
2292−
2279+
22932280 glDisable(GL_BLEND);
22942281
22952282 const int BILLBOARD_SIZE = 64;
22962283 renderRearViewMirror(QRect(0, _glWidget->height() - BILLBOARD_SIZE, BILLBOARD_SIZE, BILLBOARD_SIZE), true);
2297−
2284+
22982285 QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32);
22992286 glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
2300−
2287+
23012288 glEnable(GL_BLEND);
2302−
2289+
23032290 _textureCache.getPrimaryFramebufferObject()->release();
2304−
2291+
23052292 return image;
23062293 }
23072294
@@ -2402,7 +2389,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { · 94 unmodified lines
24022389 "Application::displaySide() ... metavoxels...");
24032390 _metavoxels.render();
24042391 }
2405−
2392+
24062393 if (Menu::getInstance()->isOptionChecked(MenuOption::BuckyBalls)) {
24072394 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
24082395 "Application::displaySide() ... bucky balls...");
@@ -2415,7 +2402,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { · 6 unmodified lines
24152402 "Application::displaySide() ... particles...");
24162403 _particles.render();
24172404 }
2418−
2405+
24192406 // render the ambient occlusion effect if enabled
24202407 if (Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion)) {
24212408 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
@@ -2459,7 +2446,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { · 37 unmodified lines
24592446
24602447 // give external parties a change to hook in
24612448 emit renderingInWorldInterface();
2462−
2449+
24632450 // render JS/scriptable overlays
24642451 _overlays.render3D();
24652452 }
@@ -2509,14 +2496,111 @@ void Application::displayOverlay() { · 43 unmodified lines
25092496 }
25102497 }
25112498
2499+ // Audio Scope
2500+ const int AUDIO_SCOPE_Y_OFFSET = 135;
25122501 if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
2513− _audio.renderMuteIcon(1, _glWidget->height() - 50);
25142502 if (Menu::getInstance()->isOptionChecked(MenuOption::Oscilloscope)) {
2515− int oscilloscopeTop = _glWidget->height() - 135;
2516− _audioScope.render(25, oscilloscopeTop);
2503+ int oscilloscopeTop = _glWidget->height() - AUDIO_SCOPE_Y_OFFSET;
2504+ _audioScope.render(MIRROR_VIEW_LEFT_PADDING, oscilloscopeTop);
25172505 }
25182506 }
25192507
2508+ // Audio VU Meter and Mute Icon
2509+ const int MUTE_ICON_SIZE = 24;
2510+ const int AUDIO_METER_INSET = 2;
2511+ const int AUDIO_METER_WIDTH = MIRROR_VIEW_WIDTH - MUTE_ICON_SIZE - AUDIO_METER_INSET;
2512+ const int AUDIO_METER_SCALE_WIDTH = AUDIO_METER_WIDTH - 2 * AUDIO_METER_INSET;
2513+ const int AUDIO_METER_HEIGHT = 8;
2514+ const int AUDIO_METER_Y_GAP = 8;
2515+ const int AUDIO_METER_X = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_INSET;
2516+
2517+ int audioMeterY;
2518+ if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
2519+ audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_Y_GAP;
2520+ } else {
2521+ audioMeterY = AUDIO_METER_Y_GAP;
2522+ }
2523+ _audio.renderMuteIcon(MIRROR_VIEW_LEFT_PADDING, audioMeterY);
2524+
2525+
2526+ const float AUDIO_METER_BLUE[] = {0.0, 0.0, 1.0};
2527+ const float AUDIO_METER_GREEN[] = {0.0, 1.0, 0.0};
2528+ const float AUDIO_METER_RED[] = {1.0, 0.0, 0.0};
2529+ const float AUDIO_GREEN_START = 0.25 * AUDIO_METER_SCALE_WIDTH;
2530+ const float AUDIO_RED_START = 0.80 * AUDIO_METER_SCALE_WIDTH;
2531+ const float CLIPPING_INDICATOR_TIME = 1.0f;
2532+ const float AUDIO_METER_AVERAGING = 0.5;
2533+ const float LOG2 = log(2.f);
2534+ const float METER_LOUDNESS_SCALE = 2.8f / 5.f;
2535+ const float LOG2_LOUDNESS_FLOOR = 11.f;
2536+ float audioLevel = 0.f;
2537+ float loudness = _audio.getLastInputLoudness() + 1.f;
2538+
2539+ _trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.f - AUDIO_METER_AVERAGING) * loudness;
2540+ float log2loudness = log(_trailingAudioLoudness) / LOG2;
2541+
2542+ if (log2loudness <= LOG2_LOUDNESS_FLOOR) {
2543+ audioLevel = (log2loudness / LOG2_LOUDNESS_FLOOR) * METER_LOUDNESS_SCALE * AUDIO_METER_SCALE_WIDTH;
2544+ } else {
2545+ audioLevel = (log2loudness - (LOG2_LOUDNESS_FLOOR - 1.f)) * METER_LOUDNESS_SCALE * AUDIO_METER_SCALE_WIDTH;
2546+ }
2547+ if (audioLevel > AUDIO_METER_SCALE_WIDTH) {
2548+ audioLevel = AUDIO_METER_SCALE_WIDTH;
2549+ }
2550+
2551+ bool isClipping = ((_audio.getTimeSinceLastClip() > 0.f) && (_audio.getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME));
2552+
2553+ glBegin(GL_QUADS);
2554+ if (isClipping) {
2555+ glColor3f(1, 0, 0);
2556+ } else {
2557+ glColor3f(0, 0, 0);
2558+ }
2559+ // Draw audio meter background Quad
2560+ glVertex2i(AUDIO_METER_X, audioMeterY);
2561+ glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY);
2562+ glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY + AUDIO_METER_HEIGHT);
2563+ glVertex2i(AUDIO_METER_X, audioMeterY + AUDIO_METER_HEIGHT);
2564+
2565+ if (audioLevel > AUDIO_RED_START) {
2566+ if (!isClipping) {
2567+ glColor3fv(AUDIO_METER_RED);
2568+ } else {
2569+ glColor3f(1, 1, 1);
2570+ }
2571+ // Draw Red Quad
2572+ glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_RED_START, audioMeterY + AUDIO_METER_INSET);
2573+ glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET);
2574+ glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
2575+ glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_RED_START, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
2576+ audioLevel = AUDIO_RED_START;
2577+ }
2578+ if (audioLevel > AUDIO_GREEN_START) {
2579+ if (!isClipping) {
2580+ glColor3fv(AUDIO_METER_GREEN);
2581+ } else {
2582+ glColor3f(1, 1, 1);
2583+ }
2584+ // Draw Green Quad
2585+ glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_GREEN_START, audioMeterY + AUDIO_METER_INSET);
2586+ glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET);
2587+ glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
2588+ glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_GREEN_START, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
2589+ audioLevel = AUDIO_GREEN_START;
2590+ }
2591+ // Draw Blue Quad
2592+ if (!isClipping) {
2593+ glColor3fv(AUDIO_METER_BLUE);
2594+ } else {
2595+ glColor3f(1, 1, 1);
2596+ }
2597+ // Draw Blue (low level) quad
2598+ glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, audioMeterY + AUDIO_METER_INSET);
2599+ glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET);
2600+ glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
2601+ glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
2602+ glEnd();
2603+
25202604 if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) {
25212605 _myAvatar->renderHeadMouse();
25222606 }
@@ -2526,11 +2610,17 @@ void Application::displayOverlay() { · 3 unmodified lines
25262610 glPointSize(1.0f);
25272611
25282612 if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
2613+ int horizontalOffset = 0;
2614+ if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
2615+ // mirror is enabled, let's set horizontal offset to give stats some margin
2616+ horizontalOffset += MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2;
2617+ }
2618+ int voxelPacketsToProcess = _voxelProcessor.packetsToProcessCount();
25292619 // Onscreen text about position, servers, etc
2530− displayStats();
2620+ Stats::getInstance()->display(WHITE_TEXT, horizontalOffset, _fps, _packetsPerSecond, _bytesPerSecond, voxelPacketsToProcess);
25312621 // Bandwidth meter
25322622 if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) {
2533− displayStatsBackground(0x33333399, _glWidget->width() - 296, _glWidget->height() - 68, 296, 68);
2623+ Stats::drawBackground(0x33333399, _glWidget->width() - 296, _glWidget->height() - 68, 296, 68);
25342624 _bandwidthMeter.render(_glWidget->width(), _glWidget->height());
25352625 }
25362626 }
@@ -2540,8 +2630,8 @@ void Application::displayOverlay() { · 3 unmodified lines
25402630 char frameTimer[10];
25412631 quint64 mSecsNow = floor(usecTimestampNow() / 1000.0 + 0.5);
25422632 sprintf(frameTimer, "%d\n", (int)(mSecsNow % 1000));
2543− int timerBottom =
2544− (Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
2633+ int timerBottom =
2634+ (Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
25452635 Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth))
25462636 ? 80 : 20;
25472637 drawText(_glWidget->width() - 100, _glWidget->height() - timerBottom, 0.30f, 1.0f, 0.f, frameTimer, WHITE_TEXT);
@@ -2552,415 +2642,6 @@ void Application::displayOverlay() { · 4 unmodified lines
25522642 glPopMatrix();
25532643 }
25542644
2555−// translucent background box that makes stats more readable
2556−void Application::displayStatsBackground(unsigned int rgba, int x, int y, int width, int height) {
2557− glBegin(GL_QUADS);
2558− glColor4f(((rgba >> 24) & 0xff) / 255.0f,
2559− ((rgba >> 16) & 0xff) / 255.0f,
2560− ((rgba >> 8) & 0xff) / 255.0f,
2561− (rgba & 0xff) / 255.0f);
2562− glVertex3f(x, y, 0);
2563− glVertex3f(x + width, y, 0);
2564− glVertex3f(x + width, y + height, 0);
2565− glVertex3f(x , y + height, 0);
2566− glEnd();
2567− glColor4f(1, 1, 1, 1);
2568−}
2569−
2570−// display expanded or contracted stats
2571−
2572−void Application::displayStats() {
2573− unsigned int backgroundColor = 0x33333399;
2574− int verticalOffset = 0, horizontalOffset = 0, lines = 0;
2575− bool mirrorEnabled = Menu::getInstance()->isOptionChecked(MenuOption::Mirror);
2576−
2577− QLocale locale(QLocale::English);
2578− std::stringstream voxelStats;
2579−
2580− glPointSize(1.0f);
2581−
2582− // we need to take one avatar out so we don't include ourselves
2583− int totalAvatars = _avatarManager.size() - 1;
2584− int totalServers = NodeList::getInstance()->size();
2585−
2586− if (mirrorEnabled) {
2587− horizontalOffset += MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2;
2588− }
2589−
2590− lines = _statsExpanded ? 5 : 3;
2591− displayStatsBackground(backgroundColor, horizontalOffset, 0, 165, lines * STATS_PELS_PER_LINE + 10);
2592− horizontalOffset += 5;
2593−
2594− char serverNodes[30];
2595− sprintf(serverNodes, "Servers: %d", totalServers);
2596− char avatarNodes[30];
2597− sprintf(avatarNodes, "Avatars: %d", totalAvatars);
2598− char framesPerSecond[30];
2599− sprintf(framesPerSecond, "Framerate: %3.0f FPS", _fps);
2600−
2601− verticalOffset += STATS_PELS_PER_LINE;
2602− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, serverNodes, WHITE_TEXT);
2603− verticalOffset += STATS_PELS_PER_LINE;
2604− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarNodes, WHITE_TEXT);
2605− verticalOffset += STATS_PELS_PER_LINE;
2606− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, framesPerSecond, WHITE_TEXT);
2607−
2608− if (_statsExpanded) {
2609− char packetsPerSecond[30];
2610− sprintf(packetsPerSecond, "Pkts/sec: %d", _packetsPerSecond);
2611− char averageMegabitsPerSecond[30];
2612− sprintf(averageMegabitsPerSecond, "Mbps: %3.2f", (float)_bytesPerSecond * 8.f / 1000000.f);
2613−
2614− verticalOffset += STATS_PELS_PER_LINE;
2615− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, packetsPerSecond, WHITE_TEXT);
2616− verticalOffset += STATS_PELS_PER_LINE;
2617− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, averageMegabitsPerSecond, WHITE_TEXT);
2618− }
2619−
2620− verticalOffset = 0;
2621− horizontalOffset += 161;
2622−
2623− if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
2624− int pingAudio = 0, pingAvatar = 0, pingVoxel = 0, pingVoxelMax = 0;
2625−
2626− NodeList* nodeList = NodeList::getInstance();
2627− SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer);
2628− SharedNodePointer avatarMixerNode = nodeList->soloNodeOfType(NodeType::AvatarMixer);
2629−
2630− pingAudio = audioMixerNode ? audioMixerNode->getPingMs() : 0;
2631− pingAvatar = avatarMixerNode ? avatarMixerNode->getPingMs() : 0;
2632−
2633− // Now handle voxel servers, since there could be more than one, we average their ping times
2634− unsigned long totalPingVoxel = 0;
2635− int voxelServerCount = 0;
2636−
2637− foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
2638− if (node->getType() == NodeType::VoxelServer) {
2639− totalPingVoxel += node->getPingMs();
2640− voxelServerCount++;
2641− if (pingVoxelMax < node->getPingMs()) {
2642− pingVoxelMax = node->getPingMs();
2643− }
2644− }
2645− }
2646−
2647− if (voxelServerCount) {
2648− pingVoxel = totalPingVoxel/voxelServerCount;
2649− }
2650−
2651− lines = _statsExpanded ? 4 : 3;
2652− displayStatsBackground(backgroundColor, horizontalOffset, 0, 175, lines * STATS_PELS_PER_LINE + 10);
2653− horizontalOffset += 5;
2654−
2655− char audioJitter[30];
2656− sprintf(audioJitter,
2657− "Buffer msecs %.1f",
2658− (float) (_audio.getNetworkBufferLengthSamplesPerChannel() + (float) _audio.getJitterBufferSamples()) /
2659− (float)_audio.getNetworkSampleRate() * 1000.f);
2660− drawText(30, _glWidget->height() - 22, 0.10f, 0.f, 2.f, audioJitter, WHITE_TEXT);
2661−
2662−
2663− char audioPing[30];
2664− sprintf(audioPing, "Audio ping: %d", pingAudio);
2665−
2666−
2667− char avatarPing[30];
2668− sprintf(avatarPing, "Avatar ping: %d", pingAvatar);
2669− char voxelAvgPing[30];
2670− sprintf(voxelAvgPing, "Voxel avg ping: %d", pingVoxel);
2671−
2672− verticalOffset += STATS_PELS_PER_LINE;
2673− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, audioPing, WHITE_TEXT);
2674− verticalOffset += STATS_PELS_PER_LINE;
2675− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarPing, WHITE_TEXT);
2676− verticalOffset += STATS_PELS_PER_LINE;
2677− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, voxelAvgPing, WHITE_TEXT);
2678−
2679− if (_statsExpanded) {
2680− char voxelMaxPing[30];
2681− sprintf(voxelMaxPing, "Voxel max ping: %d", pingVoxelMax);
2682−
2683− verticalOffset += STATS_PELS_PER_LINE;
2684− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, voxelMaxPing, WHITE_TEXT);
2685− }
2686−
2687− verticalOffset = 0;
2688− horizontalOffset += 171;
2689− }
2690−
2691− glm::vec3 avatarPos = _myAvatar->getPosition();
2692−
2693− lines = _statsExpanded ? 5 : 3;
2694− displayStatsBackground(backgroundColor, horizontalOffset, 0, _glWidget->width() - (mirrorEnabled ? 301 : 411) - horizontalOffset, lines * STATS_PELS_PER_LINE + 10);
2695− horizontalOffset += 5;
2696−
2697− char avatarPosition[200];
2698− if (mirrorEnabled) {
2699− // shorthand formatting
2700− sprintf(avatarPosition, "Pos: %.0f,%.0f,%.0f", avatarPos.x, avatarPos.y, avatarPos.z);
2701− } else {
2702− // longhand way
2703− sprintf(avatarPosition, "Position: %.1f, %.1f, %.1f", avatarPos.x, avatarPos.y, avatarPos.z);
2704− }
2705− char avatarVelocity[30];
2706− sprintf(avatarVelocity, "Velocity: %.1f", glm::length(_myAvatar->getVelocity()));
2707− char avatarBodyYaw[30];
2708− sprintf(avatarBodyYaw, "Yaw: %.1f", _myAvatar->getBodyYaw());
2709− char avatarMixerStats[200];
2710−
2711− verticalOffset += STATS_PELS_PER_LINE;
2712− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarPosition, WHITE_TEXT);
2713− verticalOffset += STATS_PELS_PER_LINE;
2714− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarVelocity, WHITE_TEXT);
2715− verticalOffset += STATS_PELS_PER_LINE;
2716− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarBodyYaw, WHITE_TEXT);
2717−
2718− if (_statsExpanded) {
2719− SharedNodePointer avatarMixer = NodeList::getInstance()->soloNodeOfType(NodeType::AvatarMixer);
2720− if (avatarMixer) {
2721− sprintf(avatarMixerStats, "Avatar Mixer: %.f kbps, %.f pps",
2722− roundf(avatarMixer->getAverageKilobitsPerSecond()),
2723− roundf(avatarMixer->getAveragePacketsPerSecond()));
2724− } else {
2725− sprintf(avatarMixerStats, "No Avatar Mixer");
2726− }
2727−
2728− verticalOffset += STATS_PELS_PER_LINE;
2729− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarMixerStats, WHITE_TEXT);
2730−
2731− stringstream downloadStats;
2732− downloadStats << "Downloads: ";
2733− foreach (Resource* resource, ResourceCache::getLoadingRequests()) {
2734− const float MAXIMUM_PERCENTAGE = 100.0f;
2735− downloadStats << roundf(resource->getProgress() * MAXIMUM_PERCENTAGE) << "% ";
2736− }
2737− downloadStats << "(" << ResourceCache::getPendingRequestCount() << " pending)";
2738−
2739− verticalOffset += STATS_PELS_PER_LINE;
2740− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, downloadStats.str().c_str(), WHITE_TEXT);
2741− }
2742−
2743− verticalOffset = 0;
2744− horizontalOffset = _glWidget->width() - (mirrorEnabled ? 300 : 410);
2745−
2746− lines = _statsExpanded ? 12 : 3;
2747− displayStatsBackground(backgroundColor, horizontalOffset, 0, _glWidget->width() - horizontalOffset, lines * STATS_PELS_PER_LINE + 10);
2748− horizontalOffset += 5;
2749−
2750− if (_statsExpanded) {
2751− // Local Voxel Memory Usage
2752− voxelStats.str("");
2753− voxelStats << "Voxels Memory Nodes: " << VoxelTreeElement::getTotalMemoryUsage() / 1000000.f << "MB";
2754− verticalOffset += STATS_PELS_PER_LINE;
2755− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
2756−
2757− voxelStats.str("");
2758− voxelStats <<
2759− "Geometry RAM: " << _voxels.getVoxelMemoryUsageRAM() / 1000000.f << "MB / " <<
2760− "VBO: " << _voxels.getVoxelMemoryUsageVBO() / 1000000.f << "MB";
2761− if (_voxels.hasVoxelMemoryUsageGPU()) {
2762− voxelStats << " / GPU: " << _voxels.getVoxelMemoryUsageGPU() / 1000000.f << "MB";
2763− }
2764− verticalOffset += STATS_PELS_PER_LINE;
2765− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
2766−
2767− // Voxel Rendering
2768− voxelStats.str("");
2769− voxelStats.precision(4);
2770− voxelStats << "Voxel Rendering Slots Max: " << _voxels.getMaxVoxels() / 1000.f << "K";
2771− verticalOffset += STATS_PELS_PER_LINE;
2772− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
2773− }
2774−
2775− voxelStats.str("");
2776− voxelStats.precision(4);
2777− voxelStats << "Drawn: " << _voxels.getVoxelsWritten() / 1000.f << "K " <<
2778− "Abandoned: " << _voxels.getAbandonedVoxels() / 1000.f << "K ";
2779− verticalOffset += STATS_PELS_PER_LINE;
2780− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
2781−
2782− // iterate all the current voxel stats, and list their sending modes, and total voxel counts
2783− std::stringstream sendingMode("");
2784− sendingMode << "Octree Sending Mode: [";
2785− int serverCount = 0;
2786− int movingServerCount = 0;
2787− unsigned long totalNodes = 0;
2788− unsigned long totalInternal = 0;
2789− unsigned long totalLeaves = 0;
2790− for(NodeToOctreeSceneStatsIterator i = _octreeServerSceneStats.begin(); i != _octreeServerSceneStats.end(); i++) {
2791− //const QUuid& uuid = i->first;
2792− OctreeSceneStats& stats = i->second;
2793− serverCount++;
2794− if (_statsExpanded) {
2795− if (serverCount > 1) {
2796− sendingMode << ",";
2797− }
2798− if (stats.isMoving()) {
2799− sendingMode << "M";
2800− movingServerCount++;
2801− } else {
2802− sendingMode << "S";
2803− }
2804− }
2805−
2806− // calculate server node totals
2807− totalNodes += stats.getTotalElements();
2808− if (_statsExpanded) {
2809− totalInternal += stats.getTotalInternal();
2810− totalLeaves += stats.getTotalLeaves();
2811− }
2812− }
2813− if (_statsExpanded) {
2814− if (serverCount == 0) {
2815− sendingMode << "---";
2816− }
2817− sendingMode << "] " << serverCount << " servers";
2818− if (movingServerCount > 0) {
2819− sendingMode << " <SCENE NOT STABLE>";
2820− } else {
2821− sendingMode << " <SCENE STABLE>";
2822− }
2823− verticalOffset += STATS_PELS_PER_LINE;
2824− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)sendingMode.str().c_str(), WHITE_TEXT);
2825− }
2826−
2827− // Incoming packets
2828− int voxelPacketsToProcess = _voxelProcessor.packetsToProcessCount();
2829− if (_statsExpanded) {
2830− voxelStats.str("");
2831− QString packetsString = locale.toString((int)voxelPacketsToProcess);
2832− QString maxString = locale.toString((int)_recentMaxPackets);
2833− voxelStats << "Voxel Packets to Process: " << qPrintable(packetsString)
2834− << " [Recent Max: " << qPrintable(maxString) << "]";
2835− verticalOffset += STATS_PELS_PER_LINE;
2836− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
2837− }
2838−
2839− if (_resetRecentMaxPacketsSoon && voxelPacketsToProcess > 0) {
2840− _recentMaxPackets = 0;
2841− _resetRecentMaxPacketsSoon = false;
2842− }
2843− if (voxelPacketsToProcess == 0) {
2844− _resetRecentMaxPacketsSoon = true;
2845− } else {
2846− if (voxelPacketsToProcess > _recentMaxPackets) {
2847− _recentMaxPackets = voxelPacketsToProcess;
2848− }
2849− }
2850−
2851− verticalOffset += (_statsExpanded ? STATS_PELS_PER_LINE : 0);
2852−
2853− QString serversTotalString = locale.toString((uint)totalNodes); // consider adding: .rightJustified(10, ' ');
2854−
2855− // Server Voxels
2856− voxelStats.str("");
2857− voxelStats << "Server voxels: " << qPrintable(serversTotalString);
2858− verticalOffset += STATS_PELS_PER_LINE;
2859− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
2860−
2861− if (_statsExpanded) {
2862− QString serversInternalString = locale.toString((uint)totalInternal);
2863− QString serversLeavesString = locale.toString((uint)totalLeaves);
2864−
2865− voxelStats.str("");
2866− voxelStats <<
2867− "Internal: " << qPrintable(serversInternalString) << " " <<
2868− "Leaves: " << qPrintable(serversLeavesString) << "";
2869− verticalOffset += STATS_PELS_PER_LINE;
2870− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
2871− }
2872−
2873− unsigned long localTotal = VoxelTreeElement::getNodeCount();
2874− QString localTotalString = locale.toString((uint)localTotal); // consider adding: .rightJustified(10, ' ');
2875−
2876− // Local Voxels
2877− voxelStats.str("");
2878− voxelStats << "Local voxels: " << qPrintable(localTotalString);
2879− verticalOffset += STATS_PELS_PER_LINE;
2880− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
2881−
2882− if (_statsExpanded) {
2883− unsigned long localInternal = VoxelTreeElement::getInternalNodeCount();
2884− unsigned long localLeaves = VoxelTreeElement::getLeafNodeCount();
2885− QString localInternalString = locale.toString((uint)localInternal);
2886− QString localLeavesString = locale.toString((uint)localLeaves);
2887−
2888− voxelStats.str("");
2889− voxelStats <<
2890− "Internal: " << qPrintable(localInternalString) << " " <<
2891− "Leaves: " << qPrintable(localLeavesString) << "";
2892− verticalOffset += STATS_PELS_PER_LINE;
2893− drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT);
2894− }
2895−
2896− // LOD Details
2897− if (_statsExpanded) {
2898− voxelStats.str("");
2899− QString displayLODDetails = Menu::getInstance()->getLODFeedbackText();
2900− voxelStats << "LOD: You can see " << qPrintable(displayLODDetails.trimmed());
2901− verticalOffset += STATS_PELS_PER_LINE;
2902− drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
2903− }
2904−}
2905−
2906−// called on mouse click release
2907−// check for clicks over stats in order to expand or contract them
2908−void Application::checkStatsClick() {
2909− if (0 != glm::compMax(glm::abs(glm::ivec2(_mouseX - _mouseDragStartedX, _mouseY - _mouseDragStartedY)))) {
2910− // not worried about dragging on stats
2911− return;
2912− }
2913−
2914− int statsHeight = 0, statsWidth = 0, statsX = 0, statsY = 0, lines = 0;
2915−
2916− if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
2917− statsX += MIRROR_VIEW_WIDTH;
2918− }
2919−
2920− // top-left stats click
2921− lines = _statsExpanded ? 5 : 3;
2922− statsHeight = lines * STATS_PELS_PER_LINE + 10;
2923− statsWidth = 165;
2924− if (_mouseX > statsX && _mouseX < statsX + statsWidth && _mouseY > statsY && _mouseY < statsY + statsHeight) {
2925− toggleStatsExpanded();
2926− return;
2927− }
2928−
2929− // ping stats click
2930− lines = _statsExpanded ? 4 : 3;
2931− statsX += statsWidth;
2932− statsHeight = lines * STATS_PELS_PER_LINE + 10;
2933− statsWidth = 175;
2934− if (_mouseX > statsX && _mouseX < statsX + statsWidth && _mouseY > statsY && _mouseY < statsY + statsHeight) {
2935− toggleStatsExpanded();
2936− return;
2937− }
2938−
2939− // top-center stats panel click
2940− lines = _statsExpanded ? 4 : 3;
2941− statsX += statsWidth;
2942− statsHeight = lines * STATS_PELS_PER_LINE + 10;
2943− statsWidth = _glWidget->width() - 411 - statsX;
2944− if (_mouseX > statsX && _mouseX < statsX + statsWidth && _mouseY > statsY && _mouseY < statsY + statsHeight) {
2945− toggleStatsExpanded();
2946− return;
2947− }
2948−
2949− // top-right stats click
2950− lines = _statsExpanded ? 11 : 3;
2951− statsX = _glWidget->width() - 410;
2952− statsHeight = lines * STATS_PELS_PER_LINE + 10;
2953− statsWidth = _glWidget->width() - statsX;
2954− if (_mouseX > statsX && _mouseX < statsX + statsWidth && _mouseY > statsY && _mouseY < statsY + statsHeight) {
2955− toggleStatsExpanded();
2956− return;
2957− }
2958−}
2959−
2960−void Application::toggleStatsExpanded() {
2961− _statsExpanded = !_statsExpanded;
2962−}
2963−
29642645 glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) {
29652646 float horizontalScale = _glWidget->width() / 2.0f;
29662647 float verticalScale = _glWidget->height() / 2.0f;
@@ -2993,12 +2674,12 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) { · 26 unmodified lines
29932674 _mirrorCamera.setFieldOfView(BILLBOARD_FIELD_OF_VIEW); // degees
29942675 _mirrorCamera.setDistance(BILLBOARD_DISTANCE * _myAvatar->getScale());
29952676 _mirrorCamera.setTargetPosition(_myAvatar->getPosition());
2996−
2677+
29972678 } else if (_rearMirrorTools->getZoomLevel() == BODY) {
29982679 _mirrorCamera.setFieldOfView(MIRROR_FIELD_OF_VIEW); // degrees
29992680 _mirrorCamera.setDistance(MIRROR_REARVIEW_BODY_DISTANCE * _myAvatar->getScale());
30002681 _mirrorCamera.setTargetPosition(_myAvatar->getChestPosition());
3001−
2682+
30022683 } else { // HEAD zoom level
30032684 _mirrorCamera.setFieldOfView(MIRROR_FIELD_OF_VIEW); // degrees
30042685 _mirrorCamera.setDistance(MIRROR_REARVIEW_DISTANCE * _myAvatar->getScale());
@@ -3013,7 +2694,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) { · 8 unmodified lines
30132694 }
30142695 }
30152696 _mirrorCamera.setAspectRatio((float)region.width() / region.height());
3016−
2697+
30172698 _mirrorCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f)));
30182699 _mirrorCamera.update(1.0f/_fps);
30192700
@@ -3058,7 +2739,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) { · 38 unmodified lines
30582739 if (!billboard) {
30592740 _rearMirrorTools->render(false);
30602741 }
3061−
2742+
30622743 // reset Viewport and projection matrix
30632744 glViewport(0, 0, _glWidget->width(), _glWidget->height());
30642745 glDisable(GL_SCISSOR_TEST);
@@ -3278,14 +2959,13 @@ void Application::setMenuShortcutsEnabled(bool enabled) { · 213 unmodified lines
32782959 }
32792960
32802961 void Application::updateWindowTitle(){
3281−
2962+
32822963 QString buildVersion = " (build " + applicationVersion() + ")";
32832964 NodeList* nodeList = NodeList::getInstance();
3284−
2965+
32852966 QString username = AccountManager::getInstance().getUsername();
32862967 QString title = QString() + (!username.isEmpty() ? username + " " : QString()) + nodeList->getSessionUUID().toString()
32872968 + " @ " + nodeList->getDomainHandler().getHostname() + buildVersion;
3288−
32892969 qDebug("Application title set to: %s", title.toStdString().c_str());
32902970 _window->setWindowTitle(title);
32912971 }
@@ -3300,7 +2980,7 @@ void Application::domainChanged(const QString& domainHostname) { · 8 unmodified lines
33002980 _voxelServerJurisdictions.clear();
33012981 _octreeServerSceneStats.clear();
33022982 _particleServerJurisdictions.clear();
3303−
2983+
33042984 // reset the particle renderer
33052985 _particles.clear();
33062986
@@ -3310,12 +2990,12 @@ void Application::domainChanged(const QString& domainHostname) { · 3 unmodified lines
33102990
33112991 void Application::connectedToDomain(const QString& hostname) {
33122992 AccountManager& accountManager = AccountManager::getInstance();
3313−
2993+
33142994 if (accountManager.isLoggedIn()) {
33152995 // update our domain-server with the data-server we're logged in with
3316−
2996+
33172997 QString domainPutJsonString = "{\"address\":{\"domain\":\"" + hostname + "\"}}";
3318−
2998+
33192999 accountManager.authenticatedRequest("/api/v1/users/address", QNetworkAccessManager::PutOperation,
33203000 JSONCallbackParameters(), domainPutJsonString.toUtf8());
33213001 }
@@ -3480,13 +3160,13 @@ void Application::loadScripts() { · 158 unmodified lines
34803160 // loads all saved scripts
34813161 QSettings* settings = new QSettings(this);
34823162 int size = settings->beginReadArray("Settings");
3483−
3163+
34843164 for (int i = 0; i < size; ++i){
34853165 settings->setArrayIndex(i);
34863166 QString string = settings->value("script").toString();
34873167 loadScript(string);
34883168 }
3489−
3169+
34903170 settings->endArray();
34913171 }
34923172
@@ -3501,72 +3181,98 @@ void Application::saveScripts() { · 8 unmodified lines
35013181 // saves all current running scripts
35023182 QSettings* settings = new QSettings(this);
35033183 settings->beginWriteArray("Settings");
3504− for (int i = 0; i < _activeScripts.size(); ++i){
3184+ for (int i = 0; i < getRunningScripts().size(); ++i){
35053185 settings->setArrayIndex(i);
3506− settings->setValue("script", _activeScripts.at(i));
3186+ settings->setValue("script", getRunningScripts().at(i));
35073187 }
3508−
3188+
35093189 settings->endArray();
35103190 }
35113191
35123192 void Application::stopAllScripts() {
35133193 // stops all current running scripts
3514− QList<QAction*> scriptActions = Menu::getInstance()->getActiveScriptsMenu()->actions();
3515− foreach (QAction* scriptAction, scriptActions) {
3516− scriptAction->activate(QAction::Trigger);
3517− qDebug() << "stopping script..." << scriptAction->text();
3194+ for (int i = 0; i < _scriptEnginesHash.size(); ++i) {
3195+ _scriptEnginesHash.values().at(i)->stop();
3196+ qDebug() << "stopping script..." << getRunningScripts().at(i);
35183197 }
3519− _activeScripts.clear();
3198+ _scriptEnginesHash.clear();
3199+ _runningScriptsWidget->setRunningScripts(getRunningScripts());
3200+}
3201+
3202+void Application::stopScript(const QString &scriptName)
3203+{
3204+ _scriptEnginesHash.value(scriptName)->stop();
3205+ qDebug() << "stopping script..." << scriptName;
3206+ _scriptEnginesHash.remove(scriptName);
3207+ _runningScriptsWidget->setRunningScripts(getRunningScripts());
35203208 }
35213209
35223210 void Application::reloadAllScripts() {
35233211 // remember all the current scripts so we can reload them
3524− QStringList reloadList = _activeScripts;
3212+ QStringList reloadList = getRunningScripts();
35253213 // reloads all current running scripts
3526− QList<QAction*> scriptActions = Menu::getInstance()->getActiveScriptsMenu()->actions();
3527− foreach (QAction* scriptAction, scriptActions) {
3528− scriptAction->activate(QAction::Trigger);
3529− qDebug() << "stopping script..." << scriptAction->text();
3530− }
3214+ stopAllScripts();
35313215
3532− // NOTE: we don't need to clear the _activeScripts list because that is handled on script shutdown.
3533−
35343216 foreach (QString scriptName, reloadList){
35353217 qDebug() << "reloading script..." << scriptName;
35363218 loadScript(scriptName);
35373219 }
35383220 }
35393221
3540−void Application::uploadFST() {
3541− FstReader reader;
3542− if (reader.zip()) {
3543− reader.send();
3222+void Application::toggleRunningScriptsWidget()
3223+{
3224+ if (!_runningScriptsWidget->toggleViewAction()->isChecked()) {
3225+ _runningScriptsWidget->move(_window->geometry().topLeft().x(), _window->geometry().topLeft().y());
3226+ _runningScriptsWidget->resize(0, _window->height());
3227+ _runningScriptsWidget->toggleViewAction()->trigger();
3228+ _runningScriptsWidget->grabKeyboard();
3229+
3230+ QPropertyAnimation* slideAnimation = new QPropertyAnimation(_runningScriptsWidget, "geometry", _runningScriptsWidget);
3231+ slideAnimation->setStartValue(_runningScriptsWidget->geometry());
3232+ slideAnimation->setEndValue(QRect(_window->geometry().topLeft().x(), _window->geometry().topLeft().y(),
3233+ 310, _runningScriptsWidget->height()));
3234+ slideAnimation->setDuration(250);
3235+ slideAnimation->start(QAbstractAnimation::DeleteWhenStopped);
3236+ } else {
3237+ _runningScriptsWidget->releaseKeyboard();
3238+
3239+ QPropertyAnimation* slideAnimation = new QPropertyAnimation(_runningScriptsWidget, "geometry", _runningScriptsWidget);
3240+ slideAnimation->setStartValue(_runningScriptsWidget->geometry());
3241+ slideAnimation->setEndValue(QRect(_window->geometry().topLeft().x(), _window->geometry().topLeft().y(),
3242+ 0, _runningScriptsWidget->height()));
3243+ slideAnimation->setDuration(250);
3244+ slideAnimation->start(QAbstractAnimation::DeleteWhenStopped);
3245+
3246+ QTimer::singleShot(260, _runningScriptsWidget->toggleViewAction(), SLOT(trigger()));
3247+ }
3248+}
3249+
3250+void Application::uploadFST(bool isHead) {
3251+ ModelUploader* uploader = new ModelUploader(isHead);
3252+ if (uploader->zip()) {
3253+ uploader->send();
35443254 }
35453255 }
35463256
3547−void Application::removeScriptName(const QString& fileNameString) {
3548− _activeScripts.removeOne(fileNameString);
3257+void Application::uploadHead() {
3258+ uploadFST(true);
35493259 }
35503260
3551−void Application::cleanupScriptMenuItem(const QString& scriptMenuName) {
3552− Menu::getInstance()->removeAction(Menu::getInstance()->getActiveScriptsMenu(), scriptMenuName);
3261+void Application::uploadSkeleton() {
3262+ uploadFST(false);
35533263 }
35543264
35553265 void Application::loadScript(const QString& scriptName) {
35563266
35573267 // start the script on a new thread...
3558− bool wantMenuItems = true; // tells the ScriptEngine object to add menu items for itself
3559− ScriptEngine* scriptEngine = new ScriptEngine(QUrl(scriptName), wantMenuItems, &_controllerScriptingInterface);
3268+ ScriptEngine* scriptEngine = new ScriptEngine(QUrl(scriptName), &_controllerScriptingInterface);
3269+ _scriptEnginesHash.insert(scriptName, scriptEngine);
35603270
35613271 if (!scriptEngine->hasScript()) {
35623272 qDebug() << "Application::loadScript(), script failed to load...";
35633273 return;
35643274 }
3565− _activeScripts.append(scriptName);
3566−
3567− // add a stop menu item
3568− Menu::getInstance()->addActionToQMenuAndActionHash(Menu::getInstance()->getActiveScriptsMenu(),
3569− scriptEngine->getScriptMenuName(), 0, scriptEngine, SLOT(stop()));
3275+ _runningScriptsWidget->setRunningScripts(getRunningScripts());
35703276
35713277 // setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so
35723278 // we can use the same ones from the application.
@@ -3574,7 +3280,7 @@ void Application::loadScript(const QString& scriptName) { · 1 unmodified line
35743280 scriptEngine->getVoxelsScriptingInterface()->setVoxelTree(_voxels.getTree());
35753281 scriptEngine->getParticlesScriptingInterface()->setPacketSender(&_particleEditSender);
35763282 scriptEngine->getParticlesScriptingInterface()->setParticleTree(_particles.getTree());
3577−
3283+
35783284 // hook our avatar object into this script engine
35793285 scriptEngine->setAvatarData(_myAvatar, "MyAvatar"); // leave it as a MyAvatar class to expose thrust features
35803286
@@ -3599,8 +3305,6 @@ void Application::loadScript(const QString& scriptName) { · 18 unmodified lines
35993305 // when the thread is terminated, add both scriptEngine and thread to the deleteLater queue
36003306 connect(scriptEngine, SIGNAL(finished(const QString&)), scriptEngine, SLOT(deleteLater()));
36013307 connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
3602− connect(scriptEngine, SIGNAL(finished(const QString&)), this, SLOT(removeScriptName(const QString&)));
3603− connect(scriptEngine, SIGNAL(cleanupMenuItem(const QString&)), this, SLOT(cleanupScriptMenuItem(const QString&)));
36043308
36053309 // when the application is about to quit, stop our script engine so it unwinds properly
36063310 connect(this, SIGNAL(aboutToQuit()), scriptEngine, SLOT(stop()));
@@ -3615,13 +3319,21 @@ void Application::loadScript(const QString& scriptName) { · 8 unmodified lines
36153319 }
36163320
36173321 void Application::loadDialog() {
3618− // shut down and stop any existing script
3619− QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
3620− QString suggestedName = desktopLocation.append("/script.js");
3322+ QString suggestedName;
3323+
3324+ if (_previousScriptLocation.isEmpty()) {
3325+ QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
3326+ suggestedName = desktopLocation.append("/script.js");
3327+ } else {
3328+ suggestedName = _previousScriptLocation;
3329+ }
36213330
3622− QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Open Script"), suggestedName,
3331+ QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Open Script"), suggestedName,
36233332 tr("JavaScript Files (*.js)"));
3624−
3333+ if (!fileNameString.isEmpty()) {
3334+ _previousScriptLocation = fileNameString;
3335+ }
3336+
36253337 loadScript(fileNameString);
36263338 }
36273339
@@ -3632,7 +3344,7 @@ void Application::loadScriptURLDialog() { · 4 unmodified lines
36323344 scriptURLDialog.setLabelText("Script:");
36333345 scriptURLDialog.setWindowFlags(Qt::Sheet);
36343346 const float DIALOG_RATIO_OF_WINDOW = 0.30f;
3635− scriptURLDialog.resize(scriptURLDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW,
3347+ scriptURLDialog.resize(scriptURLDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW,
36363348 scriptURLDialog.size().height());
36373349
36383350 int dialogReturn = scriptURLDialog.exec();
@@ -3670,29 +3382,29 @@ void Application::checkVersion() { · 31 unmodified lines
36703382 }
36713383
36723384 void Application::parseVersionXml() {
3673−
3385+
36743386 #ifdef Q_OS_WIN32
36753387 QString operatingSystem("win");
36763388 #endif
3677−
3389+
36783390 #ifdef Q_OS_MAC
36793391 QString operatingSystem("mac");
36803392 #endif
3681−
3393+
36823394 #ifdef Q_OS_LINUX
36833395 QString operatingSystem("ubuntu");
36843396 #endif
3685−
3397+
36863398 QString releaseDate;
36873399 QString releaseNotes;
36883400 QString latestVersion;
36893401 QUrl downloadUrl;
36903402 QObject* sender = QObject::sender();
3691−
3403+
36923404 QXmlStreamReader xml(qobject_cast<QNetworkReply*>(sender));
36933405 while (!xml.atEnd() && !xml.hasError()) {
36943406 QXmlStreamReader::TokenType token = xml.readNext();
3695−
3407+
36963408 if (token == QXmlStreamReader::StartElement) {
36973409 if (xml.name() == "ReleaseDate") {
36983410 xml.readNext();

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t