Unified · Split
| @@ -49,7 +49,7 @@ if (WIN32) · 48 unmodified lines | ||
| 49 | 49 | else () |
| 50 | 50 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -fno-strict-aliasing -Wno-unused-parameter") |
| 51 | 51 | if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) |
| 52 | − set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb") | |
| 52 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -Woverloaded-virtual -Wdouble-promotion") | |
| 53 | 53 | endif () |
| 54 | 54 | endif(WIN32) |
| 55 | 55 | |
| @@ -295,10 +295,10 @@ void AudioMixerClientData::printUpstreamDownstreamStats() const { · 294 unmodified lines | ||
| 295 | 295 | |
| 296 | 296 | void AudioMixerClientData::printAudioStreamStats(const AudioStreamStats& streamStats) const { |
| 297 | 297 | printf(" Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)\n", |
| 298 | − streamStats._packetStreamStats.getLostRate() * 100.0f, | |
| 299 | − streamStats._packetStreamStats._lost, | |
| 300 | − streamStats._packetStreamWindowStats.getLostRate() * 100.0f, | |
| 301 | − streamStats._packetStreamWindowStats._lost); | |
| 298 | + (double)(streamStats._packetStreamStats.getLostRate() * 100.0f), | |
| 299 | + streamStats._packetStreamStats._lost, | |
| 300 | + (double)(streamStats._packetStreamWindowStats.getLostRate() * 100.0f), | |
| 301 | + streamStats._packetStreamWindowStats._lost); | |
| 302 | 302 | |
| 303 | 303 | printf(" Ringbuffer frames | desired: %u, avg_available(10s): %u, available: %u\n", |
| 304 | 304 | streamStats._desiredJitterBufferFrames, |
| @@ -127,7 +127,7 @@ void OctreeServer::resetSendingStats() { · 126 unmodified lines | ||
| 127 | 127 | _noProcessWait = 0; |
| 128 | 128 | } |
| 129 | 129 | |
| 130 | −void OctreeServer::trackEncodeTime(float time) { | |
| 130 | +void OctreeServer::trackEncodeTime(float time) { | |
| 131 | 131 | const float MAX_SHORT_TIME = 10.0f; |
| 132 | 132 | const float MAX_LONG_TIME = 100.0f; |
| 133 | 133 | |
| @@ -144,10 +144,10 @@ void OctreeServer::trackEncodeTime(float time) { · 10 unmodified lines | ||
| 144 | 144 | _extraLongEncode++; |
| 145 | 145 | _averageExtraLongEncodeTime.updateAverage(time); |
| 146 | 146 | } |
| 147 | − _averageEncodeTime.updateAverage(time); | |
| 147 | + _averageEncodeTime.updateAverage(time); | |
| 148 | 148 | } |
| 149 | 149 | |
| 150 | −void OctreeServer::trackTreeWaitTime(float time) { | |
| 150 | +void OctreeServer::trackTreeWaitTime(float time) { | |
| 151 | 151 | const float MAX_SHORT_TIME = 10.0f; |
| 152 | 152 | const float MAX_LONG_TIME = 100.0f; |
| 153 | 153 | if (time == SKIP_TIME) { |
| @@ -166,7 +166,7 @@ void OctreeServer::trackTreeWaitTime(float time) { · 12 unmodified lines | ||
| 166 | 166 | _averageTreeWaitTime.updateAverage(time); |
| 167 | 167 | } |
| 168 | 168 | |
| 169 | −void OctreeServer::trackCompressAndWriteTime(float time) { | |
| 169 | +void OctreeServer::trackCompressAndWriteTime(float time) { | |
| 170 | 170 | const float MAX_SHORT_TIME = 10.0f; |
| 171 | 171 | const float MAX_LONG_TIME = 100.0f; |
| 172 | 172 | if (time == SKIP_TIME) { |
| @@ -182,19 +182,19 @@ void OctreeServer::trackCompressAndWriteTime(float time) { · 9 unmodified lines | ||
| 182 | 182 | _extraLongCompress++; |
| 183 | 183 | _averageExtraLongCompressTime.updateAverage(time); |
| 184 | 184 | } |
| 185 | − _averageCompressAndWriteTime.updateAverage(time); | |
| 185 | + _averageCompressAndWriteTime.updateAverage(time); | |
| 186 | 186 | } |
| 187 | 187 | |
| 188 | −void OctreeServer::trackPacketSendingTime(float time) { | |
| 188 | +void OctreeServer::trackPacketSendingTime(float time) { | |
| 189 | 189 | if (time == SKIP_TIME) { |
| 190 | 190 | _noSend++; |
| 191 | 191 | time = 0.0f; |
| 192 | 192 | } |
| 193 | − _averagePacketSendingTime.updateAverage(time); | |
| 193 | + _averagePacketSendingTime.updateAverage(time); | |
| 194 | 194 | } |
| 195 | 195 | |
| 196 | 196 | |
| 197 | −void OctreeServer::trackProcessWaitTime(float time) { | |
| 197 | +void OctreeServer::trackProcessWaitTime(float time) { | |
| 198 | 198 | const float MAX_SHORT_TIME = 10.0f; |
| 199 | 199 | const float MAX_LONG_TIME = 100.0f; |
| 200 | 200 | if (time == SKIP_TIME) { |
| @@ -243,9 +243,9 @@ OctreeServer::OctreeServer(const QByteArray& packet) : · 42 unmodified lines | ||
| 243 | 243 | |
| 244 | 244 | _averageLoopTime.updateAverage(0); |
| 245 | 245 | qDebug() << "Octree server starting... [" << this << "]"; |
| 246 | − | |
| 246 | + | |
| 247 | 247 | // make sure the AccountManager has an Auth URL for payment redemptions |
| 248 | − | |
| 248 | + | |
| 249 | 249 | AccountManager::getInstance().setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL); |
| 250 | 250 | } |
| 251 | 251 | |
| @@ -278,13 +278,13 @@ OctreeServer::~OctreeServer() { · 26 unmodified lines | ||
| 278 | 278 | |
| 279 | 279 | delete _jurisdiction; |
| 280 | 280 | _jurisdiction = NULL; |
| 281 | − | |
| 281 | + | |
| 282 | 282 | // cleanup our tree here... |
| 283 | 283 | qDebug() << qPrintable(_safeServerName) << "server START cleaning up octree... [" << this << "]"; |
| 284 | 284 | delete _tree; |
| 285 | 285 | _tree = NULL; |
| 286 | 286 | qDebug() << qPrintable(_safeServerName) << "server DONE cleaning up octree... [" << this << "]"; |
| 287 | − | |
| 287 | + | |
| 288 | 288 | if (_instance == this) { |
| 289 | 289 | _instance = NULL; // we are gone |
| 290 | 290 | } |
| @@ -400,10 +400,10 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 109 unmodified lines | ||
| 400 | 400 | statsString += QString().sprintf(" Internal Elements: %s nodes (%5.2f%%)\r\n", |
| 401 | 401 | locale.toString((uint)internalNodeCount).rightJustified(16, |
| 402 | 402 | ' ').toLocal8Bit().constData(), |
| 403 | − ((float)internalNodeCount / (float)nodeCount) * AS_PERCENT); | |
| 403 | + (double)((internalNodeCount / (float)nodeCount) * AS_PERCENT)); | |
| 404 | 404 | statsString += QString().sprintf(" Leaf Elements: %s nodes (%5.2f%%)\r\n", |
| 405 | 405 | locale.toString((uint)leafNodeCount).rightJustified(16, ' ').toLocal8Bit().constData(), |
| 406 | − ((float)leafNodeCount / (float)nodeCount) * AS_PERCENT); | |
| 406 | + (double)((leafNodeCount / (float)nodeCount) * AS_PERCENT)); | |
| 407 | 407 | statsString += "\r\n"; |
| 408 | 408 | statsString += "\r\n"; |
| 409 | 409 | |
| @@ -422,7 +422,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 12 unmodified lines | ||
| 422 | 422 | .arg(locale.toString((uint)getCurrentClientCount()).rightJustified(COLUMN_WIDTH, ' ')); |
| 423 | 423 | |
| 424 | 424 | quint64 oneSecondAgo = usecTimestampNow() - USECS_PER_SECOND; |
| 425 | − | |
| 425 | + | |
| 426 | 426 | statsString += QString(" process() last second: %1 clients\r\n") |
| 427 | 427 | .arg(locale.toString((uint)howManyThreadsDidProcess(oneSecondAgo)).rightJustified(COLUMN_WIDTH, ' ')); |
| 428 | 428 | statsString += QString(" packetDistributor() last second: %1 clients\r\n") |
| @@ -434,13 +434,13 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 5 unmodified lines | ||
| 434 | 434 | |
| 435 | 435 | float averageLoopTime = getAverageLoopTime(); |
| 436 | 436 | statsString += QString().sprintf(" Average packetLoop() time: %7.2f msecs" |
| 437 | − " samples: %12d \r\n", | |
| 438 | − averageLoopTime, _averageLoopTime.getSampleCount()); | |
| 437 | + " samples: %12d \r\n", | |
| 438 | + (double)averageLoopTime, _averageLoopTime.getSampleCount()); | |
| 439 | 439 | |
| 440 | 440 | float averageInsideTime = getAverageInsideTime(); |
| 441 | 441 | statsString += QString().sprintf(" Average 'inside' time: %9.2f usecs" |
| 442 | − " samples: %12d \r\n\r\n", | |
| 443 | − averageInsideTime, _averageInsideTime.getSampleCount()); | |
| 442 | + " samples: %12d \r\n\r\n", | |
| 443 | + (double)averageInsideTime, _averageInsideTime.getSampleCount()); | |
| 444 | 444 | |
| 445 | 445 | |
| 446 | 446 | // Process Wait |
| @@ -450,30 +450,30 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 3 unmodified lines | ||
| 450 | 450 | float averageProcessWaitTime = getAverageProcessWaitTime(); |
| 451 | 451 | statsString += QString().sprintf(" Average process lock wait time:" |
| 452 | 452 | " %9.2f usecs samples: %12d \r\n", |
| 453 | − averageProcessWaitTime, allWaitTimes); | |
| 453 | + (double)averageProcessWaitTime, allWaitTimes); | |
| 454 | 454 | |
| 455 | 455 | float zeroVsTotal = (allWaitTimes > 0) ? ((float)_noProcessWait / (float)allWaitTimes) : 0.0f; |
| 456 | 456 | statsString += QString().sprintf(" No Lock Wait:" |
| 457 | 457 | " (%6.2f%%) samples: %12d \r\n", |
| 458 | − zeroVsTotal * AS_PERCENT, _noProcessWait); | |
| 458 | + (double)(zeroVsTotal * AS_PERCENT), _noProcessWait); | |
| 459 | 459 | |
| 460 | 460 | float shortVsTotal = (allWaitTimes > 0) ? ((float)_shortProcessWait / (float)allWaitTimes) : 0.0f; |
| 461 | 461 | statsString += QString().sprintf(" Avg process lock short wait time:" |
| 462 | 462 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", |
| 463 | − _averageProcessShortWaitTime.getAverage(), | |
| 464 | − shortVsTotal * AS_PERCENT, _shortProcessWait); | |
| 463 | + (double)_averageProcessShortWaitTime.getAverage(), | |
| 464 | + (double)(shortVsTotal * AS_PERCENT), _shortProcessWait); | |
| 465 | 465 | |
| 466 | 466 | float longVsTotal = (allWaitTimes > 0) ? ((float)_longProcessWait / (float)allWaitTimes) : 0.0f; |
| 467 | 467 | statsString += QString().sprintf(" Avg process lock long wait time:" |
| 468 | 468 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", |
| 469 | − _averageProcessLongWaitTime.getAverage(), | |
| 470 | − longVsTotal * AS_PERCENT, _longProcessWait); | |
| 469 | + (double)_averageProcessLongWaitTime.getAverage(), | |
| 470 | + (double)(longVsTotal * AS_PERCENT), _longProcessWait); | |
| 471 | 471 | |
| 472 | 472 | float extraLongVsTotal = (allWaitTimes > 0) ? ((float)_extraLongProcessWait / (float)allWaitTimes) : 0.0f; |
| 473 | 473 | statsString += QString().sprintf("Avg process lock extralong wait time:" |
| 474 | 474 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n", |
| 475 | − _averageProcessExtraLongWaitTime.getAverage(), | |
| 476 | − extraLongVsTotal * AS_PERCENT, _extraLongProcessWait); | |
| 475 | + (double)_averageProcessExtraLongWaitTime.getAverage(), | |
| 476 | + (double)(extraLongVsTotal * AS_PERCENT), _extraLongProcessWait); | |
| 477 | 477 | } |
| 478 | 478 | |
| 479 | 479 | // Tree Wait |
| @@ -482,122 +482,125 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 2 unmodified lines | ||
| 482 | 482 | float averageTreeWaitTime = getAverageTreeWaitTime(); |
| 483 | 483 | statsString += QString().sprintf(" Average tree lock wait time:" |
| 484 | 484 | " %9.2f usecs samples: %12d \r\n", |
| 485 | − averageTreeWaitTime, allWaitTimes); | |
| 485 | + (double)averageTreeWaitTime, allWaitTimes); | |
| 486 | 486 | |
| 487 | 487 | float zeroVsTotal = (allWaitTimes > 0) ? ((float)_noTreeWait / (float)allWaitTimes) : 0.0f; |
| 488 | 488 | statsString += QString().sprintf(" No Lock Wait:" |
| 489 | 489 | " (%6.2f%%) samples: %12d \r\n", |
| 490 | − zeroVsTotal * AS_PERCENT, _noTreeWait); | |
| 490 | + (double)(zeroVsTotal * AS_PERCENT), _noTreeWait); | |
| 491 | 491 | |
| 492 | 492 | float shortVsTotal = (allWaitTimes > 0) ? ((float)_shortTreeWait / (float)allWaitTimes) : 0.0f; |
| 493 | 493 | statsString += QString().sprintf(" Avg tree lock short wait time:" |
| 494 | 494 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", |
| 495 | − _averageTreeShortWaitTime.getAverage(), | |
| 496 | − shortVsTotal * AS_PERCENT, _shortTreeWait); | |
| 495 | + (double)_averageTreeShortWaitTime.getAverage(), | |
| 496 | + (double)(shortVsTotal * AS_PERCENT), _shortTreeWait); | |
| 497 | 497 | |
| 498 | 498 | float longVsTotal = (allWaitTimes > 0) ? ((float)_longTreeWait / (float)allWaitTimes) : 0.0f; |
| 499 | 499 | statsString += QString().sprintf(" Avg tree lock long wait time:" |
| 500 | 500 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", |
| 501 | − _averageTreeLongWaitTime.getAverage(), | |
| 502 | − longVsTotal * AS_PERCENT, _longTreeWait); | |
| 501 | + (double)_averageTreeLongWaitTime.getAverage(), | |
| 502 | + (double)(longVsTotal * AS_PERCENT), _longTreeWait); | |
| 503 | 503 | |
| 504 | 504 | float extraLongVsTotal = (allWaitTimes > 0) ? ((float)_extraLongTreeWait / (float)allWaitTimes) : 0.0f; |
| 505 | 505 | statsString += QString().sprintf(" Avg tree lock extra long wait time:" |
| 506 | 506 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n", |
| 507 | − _averageTreeExtraLongWaitTime.getAverage(), | |
| 508 | − extraLongVsTotal * AS_PERCENT, _extraLongTreeWait); | |
| 507 | + (double)_averageTreeExtraLongWaitTime.getAverage(), | |
| 508 | + (double)(extraLongVsTotal * AS_PERCENT), _extraLongTreeWait); | |
| 509 | 509 | |
| 510 | 510 | // encode |
| 511 | 511 | float averageEncodeTime = getAverageEncodeTime(); |
| 512 | − statsString += QString().sprintf(" Average encode time: %9.2f usecs\r\n", averageEncodeTime); | |
| 513 | − | |
| 512 | + statsString += QString().sprintf(" Average encode time: %9.2f usecs\r\n", (double)averageEncodeTime); | |
| 513 | + | |
| 514 | 514 | int allEncodeTimes = _noEncode + _shortEncode + _longEncode + _extraLongEncode; |
| 515 | 515 | |
| 516 | 516 | float zeroVsTotalEncode = (allEncodeTimes > 0) ? ((float)_noEncode / (float)allEncodeTimes) : 0.0f; |
| 517 | 517 | statsString += QString().sprintf(" No Encode:" |
| 518 | 518 | " (%6.2f%%) samples: %12d \r\n", |
| 519 | − zeroVsTotalEncode * AS_PERCENT, _noEncode); | |
| 519 | + (double)(zeroVsTotalEncode * AS_PERCENT), _noEncode); | |
| 520 | 520 | |
| 521 | 521 | float shortVsTotalEncode = (allEncodeTimes > 0) ? ((float)_shortEncode / (float)allEncodeTimes) : 0.0f; |
| 522 | 522 | statsString += QString().sprintf(" Avg short encode time:" |
| 523 | 523 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", |
| 524 | − _averageShortEncodeTime.getAverage(), | |
| 525 | − shortVsTotalEncode * AS_PERCENT, _shortEncode); | |
| 524 | + (double)_averageShortEncodeTime.getAverage(), | |
| 525 | + (double)(shortVsTotalEncode * AS_PERCENT), _shortEncode); | |
| 526 | 526 | |
| 527 | 527 | float longVsTotalEncode = (allEncodeTimes > 0) ? ((float)_longEncode / (float)allEncodeTimes) : 0.0f; |
| 528 | 528 | statsString += QString().sprintf(" Avg long encode time:" |
| 529 | 529 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", |
| 530 | − _averageLongEncodeTime.getAverage(), | |
| 531 | − longVsTotalEncode * AS_PERCENT, _longEncode); | |
| 530 | + (double)_averageLongEncodeTime.getAverage(), | |
| 531 | + (double)(longVsTotalEncode * AS_PERCENT), _longEncode); | |
| 532 | 532 | |
| 533 | 533 | float extraLongVsTotalEncode = (allEncodeTimes > 0) ? ((float)_extraLongEncode / (float)allEncodeTimes) : 0.0f; |
| 534 | 534 | statsString += QString().sprintf(" Avg extra long encode time:" |
| 535 | 535 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n", |
| 536 | − _averageExtraLongEncodeTime.getAverage(), | |
| 537 | − extraLongVsTotalEncode * AS_PERCENT, _extraLongEncode); | |
| 536 | + (double)_averageExtraLongEncodeTime.getAverage(), | |
| 537 | + (double)(extraLongVsTotalEncode * AS_PERCENT), _extraLongEncode); | |
| 538 | 538 | |
| 539 | 539 | |
| 540 | 540 | float averageCompressAndWriteTime = getAverageCompressAndWriteTime(); |
| 541 | − statsString += QString().sprintf(" Average compress and write time: %9.2f usecs\r\n", | |
| 542 | − averageCompressAndWriteTime); | |
| 541 | + statsString += QString().sprintf(" Average compress and write time: %9.2f usecs\r\n", | |
| 542 | + (double)averageCompressAndWriteTime); | |
| 543 | 543 | |
| 544 | 544 | int allCompressTimes = _noCompress + _shortCompress + _longCompress + _extraLongCompress; |
| 545 | 545 | |
| 546 | 546 | float zeroVsTotalCompress = (allCompressTimes > 0) ? ((float)_noCompress / (float)allCompressTimes) : 0.0f; |
| 547 | 547 | statsString += QString().sprintf(" No compression:" |
| 548 | 548 | " (%6.2f%%) samples: %12d \r\n", |
| 549 | − zeroVsTotalCompress * AS_PERCENT, _noCompress); | |
| 549 | + (double)(zeroVsTotalCompress * AS_PERCENT), _noCompress); | |
| 550 | 550 | |
| 551 | 551 | float shortVsTotalCompress = (allCompressTimes > 0) ? ((float)_shortCompress / (float)allCompressTimes) : 0.0f; |
| 552 | 552 | statsString += QString().sprintf(" Avg short compress time:" |
| 553 | 553 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", |
| 554 | − _averageShortCompressTime.getAverage(), | |
| 555 | − shortVsTotalCompress * AS_PERCENT, _shortCompress); | |
| 554 | + (double)_averageShortCompressTime.getAverage(), | |
| 555 | + (double)(shortVsTotalCompress * AS_PERCENT), _shortCompress); | |
| 556 | 556 | |
| 557 | 557 | float longVsTotalCompress = (allCompressTimes > 0) ? ((float)_longCompress / (float)allCompressTimes) : 0.0f; |
| 558 | 558 | statsString += QString().sprintf(" Avg long compress time:" |
| 559 | 559 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", |
| 560 | − _averageLongCompressTime.getAverage(), | |
| 561 | − longVsTotalCompress * AS_PERCENT, _longCompress); | |
| 560 | + (double)_averageLongCompressTime.getAverage(), | |
| 561 | + (double)(longVsTotalCompress * AS_PERCENT), _longCompress); | |
| 562 | 562 | |
| 563 | 563 | float extraLongVsTotalCompress = (allCompressTimes > 0) ? ((float)_extraLongCompress / (float)allCompressTimes) : 0.0f; |
| 564 | 564 | statsString += QString().sprintf(" Avg extra long compress time:" |
| 565 | 565 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n", |
| 566 | − _averageExtraLongCompressTime.getAverage(), | |
| 567 | − extraLongVsTotalCompress * AS_PERCENT, _extraLongCompress); | |
| 566 | + (double)_averageExtraLongCompressTime.getAverage(), | |
| 567 | + (double)(extraLongVsTotalCompress * AS_PERCENT), _extraLongCompress); | |
| 568 | 568 | |
| 569 | 569 | float averagePacketSendingTime = getAveragePacketSendingTime(); |
| 570 | − statsString += QString().sprintf(" Average packet sending time: %9.2f usecs (includes node lock)\r\n", | |
| 571 | − averagePacketSendingTime); | |
| 570 | + statsString += QString().sprintf(" Average packet sending time: %9.2f usecs (includes node lock)\r\n", | |
| 571 | + (double)averagePacketSendingTime); | |
| 572 | 572 | |
| 573 | − float noVsTotalSend = (_averagePacketSendingTime.getSampleCount() > 0) ? | |
| 573 | + float noVsTotalSend = (_averagePacketSendingTime.getSampleCount() > 0) ? | |
| 574 | 574 | ((float)_noSend / (float)_averagePacketSendingTime.getSampleCount()) : 0.0f; |
| 575 | 575 | statsString += QString().sprintf(" Not sending:" |
| 576 | 576 | " (%6.2f%%) samples: %12d \r\n", |
| 577 | − noVsTotalSend * AS_PERCENT, _noSend); | |
| 578 | − | |
| 577 | + (double)(noVsTotalSend * AS_PERCENT), _noSend); | |
| 578 | + | |
| 579 | 579 | float averageNodeWaitTime = getAverageNodeWaitTime(); |
| 580 | − statsString += QString().sprintf(" Average node lock wait time: %9.2f usecs\r\n", averageNodeWaitTime); | |
| 580 | + statsString += QString().sprintf(" Average node lock wait time: %9.2f usecs\r\n", | |
| 581 | + (double)averageNodeWaitTime); | |
| 581 | 582 | |
| 582 | 583 | statsString += QString().sprintf("--------------------------------------------------------------\r\n"); |
| 583 | 584 | |
| 584 | 585 | float encodeToInsidePercent = averageInsideTime == 0.0f ? 0.0f : (averageEncodeTime / averageInsideTime) * AS_PERCENT; |
| 585 | − statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n", | |
| 586 | − encodeToInsidePercent); | |
| 586 | + statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n", | |
| 587 | + (double)encodeToInsidePercent); | |
| 587 | 588 | |
| 588 | − float waitToInsidePercent = averageInsideTime == 0.0f ? 0.0f | |
| 589 | + float waitToInsidePercent = averageInsideTime == 0.0f ? 0.0f | |
| 589 | 590 | : ((averageTreeWaitTime + averageNodeWaitTime) / averageInsideTime) * AS_PERCENT; |
| 590 | − statsString += QString().sprintf(" waiting ratio: %5.2f%%\r\n", waitToInsidePercent); | |
| 591 | + statsString += QString().sprintf(" waiting ratio: %5.2f%%\r\n", | |
| 592 | + (double)waitToInsidePercent); | |
| 591 | 593 | |
| 592 | − float compressAndWriteToInsidePercent = averageInsideTime == 0.0f ? 0.0f | |
| 594 | + float compressAndWriteToInsidePercent = averageInsideTime == 0.0f ? 0.0f | |
| 593 | 595 | : (averageCompressAndWriteTime / averageInsideTime) * AS_PERCENT; |
| 594 | − statsString += QString().sprintf(" compress and write ratio: %5.2f%%\r\n", | |
| 595 | − compressAndWriteToInsidePercent); | |
| 596 | + statsString += QString().sprintf(" compress and write ratio: %5.2f%%\r\n", | |
| 597 | + (double)compressAndWriteToInsidePercent); | |
| 596 | 598 | |
| 597 | − float sendingToInsidePercent = averageInsideTime == 0.0f ? 0.0f | |
| 599 | + float sendingToInsidePercent = averageInsideTime == 0.0f ? 0.0f | |
| 598 | 600 | : (averagePacketSendingTime / averageInsideTime) * AS_PERCENT; |
| 599 | − statsString += QString().sprintf(" sending ratio: %5.2f%%\r\n", sendingToInsidePercent); | |
| 600 | − | |
| 601 | + statsString += QString().sprintf(" sending ratio: %5.2f%%\r\n", | |
| 602 | + (double)sendingToInsidePercent); | |
| 603 | + | |
| 601 | 604 | |
| 602 | 605 | |
| 603 | 606 | statsString += QString("\r\n"); |
| @@ -610,13 +613,13 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 6 unmodified lines | ||
| 610 | 613 | .arg(locale.toString((uint)totalWastedBytes).rightJustified(COLUMN_WIDTH, ' ')); |
| 611 | 614 | statsString += QString().sprintf(" Total OctalCode Bytes: %s bytes (%5.2f%%)\r\n", |
| 612 | 615 | locale.toString((uint)totalBytesOfOctalCodes).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(), |
| 613 | − ((float)totalBytesOfOctalCodes / (float)totalOutboundBytes) * AS_PERCENT); | |
| 616 | + (double)((totalBytesOfOctalCodes / (float)totalOutboundBytes) * AS_PERCENT)); | |
| 614 | 617 | statsString += QString().sprintf(" Total BitMasks Bytes: %s bytes (%5.2f%%)\r\n", |
| 615 | 618 | locale.toString((uint)totalBytesOfBitMasks).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(), |
| 616 | − ((float)totalBytesOfBitMasks / (float)totalOutboundBytes) * AS_PERCENT); | |
| 619 | + (double)(((float)totalBytesOfBitMasks / (float)totalOutboundBytes) * AS_PERCENT)); | |
| 617 | 620 | statsString += QString().sprintf(" Total Color Bytes: %s bytes (%5.2f%%)\r\n", |
| 618 | 621 | locale.toString((uint)totalBytesOfColor).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(), |
| 619 | − ((float)totalBytesOfColor / (float)totalOutboundBytes) * AS_PERCENT); | |
| 622 | + (double)((totalBytesOfColor / (float)totalOutboundBytes) * AS_PERCENT)); | |
| 620 | 623 | |
| 621 | 624 | statsString += "\r\n"; |
| 622 | 625 | statsString += "\r\n"; |
| @@ -638,7 +641,8 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 15 unmodified lines | ||
| 638 | 641 | .arg(locale.toString((uint)totalPacketsProcessed).rightJustified(COLUMN_WIDTH, ' ')); |
| 639 | 642 | statsString += QString(" Total Inbound Elements: %1 elements\r\n") |
| 640 | 643 | .arg(locale.toString((uint)totalElementsProcessed).rightJustified(COLUMN_WIDTH, ' ')); |
| 641 | − statsString += QString().sprintf(" Average Inbound Elements/Packet: %f elements/packet\r\n", averageElementsPerPacket); | |
| 644 | + statsString += QString().sprintf(" Average Inbound Elements/Packet: %f elements/packet\r\n", | |
| 645 | + (double)averageElementsPerPacket); | |
| 642 | 646 | statsString += QString(" Average Transit Time/Packet: %1 usecs\r\n") |
| 643 | 647 | .arg(locale.toString((uint)averageTransitTimePerPacket).rightJustified(COLUMN_WIDTH, ' ')); |
| 644 | 648 | statsString += QString(" Average Process Time/Packet: %1 usecs\r\n") |
| @@ -676,7 +680,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 31 unmodified lines | ||
| 676 | 680 | statsString += QString(" Total Inbound Elements: %1 elements\r\n") |
| 677 | 681 | .arg(locale.toString((uint)totalElementsProcessed).rightJustified(COLUMN_WIDTH, ' ')); |
| 678 | 682 | statsString += QString().sprintf(" Average Inbound Elements/Packet: %f elements/packet\r\n", |
| 679 | − averageElementsPerPacket); | |
| 683 | + (double)averageElementsPerPacket); | |
| 680 | 684 | statsString += QString(" Average Transit Time/Packet: %1 usecs\r\n") |
| 681 | 685 | .arg(locale.toString((uint)averageTransitTimePerPacket).rightJustified(COLUMN_WIDTH, ' ')); |
| 682 | 686 | statsString += QString(" Average Process Time/Packet: %1 usecs\r\n") |
| @@ -710,14 +714,15 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 27 unmodified lines | ||
| 710 | 714 | } |
| 711 | 715 | |
| 712 | 716 | statsString += QString().sprintf("Element Node Memory Usage: %8.2f %s\r\n", |
| 713 | − OctreeElement::getOctreeMemoryUsage() / memoryScale, memoryScaleLabel); | |
| 717 | + OctreeElement::getOctreeMemoryUsage() / (double)memoryScale, memoryScaleLabel); | |
| 714 | 718 | statsString += QString().sprintf("Octcode Memory Usage: %8.2f %s\r\n", |
| 715 | − OctreeElement::getOctcodeMemoryUsage() / memoryScale, memoryScaleLabel); | |
| 719 | + OctreeElement::getOctcodeMemoryUsage() / (double)memoryScale, memoryScaleLabel); | |
| 716 | 720 | statsString += QString().sprintf("External Children Memory Usage: %8.2f %s\r\n", |
| 717 | − OctreeElement::getExternalChildrenMemoryUsage() / memoryScale, memoryScaleLabel); | |
| 721 | + OctreeElement::getExternalChildrenMemoryUsage() / (double)memoryScale, | |
| 722 | + memoryScaleLabel); | |
| 718 | 723 | statsString += " -----------\r\n"; |
| 719 | 724 | statsString += QString().sprintf(" Total: %8.2f %s\r\n", |
| 720 | − OctreeElement::getTotalMemoryUsage() / memoryScale, memoryScaleLabel); | |
| 725 | + OctreeElement::getTotalMemoryUsage() / (double)memoryScale, memoryScaleLabel); | |
| 721 | 726 | statsString += "\r\n"; |
| 722 | 727 | |
| 723 | 728 | statsString += "OctreeElement Children Population Statistics...\r\n"; |
| @@ -726,7 +731,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 2 unmodified lines | ||
| 726 | 731 | checkSum += OctreeElement::getChildrenCount(i); |
| 727 | 732 | statsString += QString().sprintf(" Nodes with %d children: %s nodes (%5.2f%%)\r\n", i, |
| 728 | 733 | locale.toString((uint)OctreeElement::getChildrenCount(i)).rightJustified(16, ' ').toLocal8Bit().constData(), |
| 729 | − ((float)OctreeElement::getChildrenCount(i) / (float)nodeCount) * AS_PERCENT); | |
| 734 | + (double)(((float)OctreeElement::getChildrenCount(i) / (float)nodeCount) * AS_PERCENT)); | |
| 730 | 735 | } |
| 731 | 736 | statsString += " ----------------------\r\n"; |
| 732 | 737 | statsString += QString(" Total: %1 nodes\r\n") |
| @@ -831,7 +836,7 @@ void OctreeServer::readPendingDatagram(const QByteArray& receivedPacket, const H · 98 unmodified lines | ||
| 831 | 836 | |
| 832 | 837 | // If we know we're shutting down we just drop these packets on the floor. |
| 833 | 838 | // This stops us from initializing send threads we just shut down. |
| 834 | − | |
| 839 | + | |
| 835 | 840 | if (!_isShuttingDown) { |
| 836 | 841 | if (nodeList->packetVersionAndHashMatch(receivedPacket)) { |
| 837 | 842 | PacketType packetType = packetTypeForPacket(receivedPacket); |
| @@ -841,7 +846,7 @@ void OctreeServer::readPendingDatagram(const QByteArray& receivedPacket, const H · 3 unmodified lines | ||
| 841 | 846 | // need to make sure we have it in our nodeList. |
| 842 | 847 | if (matchingNode) { |
| 843 | 848 | nodeList->updateNodeWithDataFromPacket(matchingNode, receivedPacket); |
| 844 | − | |
| 849 | + | |
| 845 | 850 | OctreeQueryNode* nodeData = (OctreeQueryNode*) matchingNode->getLinkedData(); |
| 846 | 851 | if (nodeData && !nodeData->isOctreeSendThreadInitalized()) { |
| 847 | 852 | nodeData->initializeOctreeSendThread(this, matchingNode); |
| @@ -870,33 +875,33 @@ void OctreeServer::readPendingDatagram(const QByteArray& receivedPacket, const H · 22 unmodified lines | ||
| 870 | 875 | |
| 871 | 876 | void OctreeServer::setupDatagramProcessingThread() { |
| 872 | 877 | auto nodeList = DependencyManager::get<NodeList>(); |
| 873 | − | |
| 878 | + | |
| 874 | 879 | // we do not want this event loop to be the handler for UDP datagrams, so disconnect |
| 875 | 880 | disconnect(&nodeList->getNodeSocket(), 0, this, 0); |
| 876 | − | |
| 881 | + | |
| 877 | 882 | // setup a QThread with us as parent that will house the OctreeServerDatagramProcessor |
| 878 | 883 | _datagramProcessingThread = new QThread(this); |
| 879 | 884 | _datagramProcessingThread->setObjectName("Octree Datagram Processor"); |
| 880 | − | |
| 885 | + | |
| 881 | 886 | // create an OctreeServerDatagramProcessor and move it to that thread |
| 882 | 887 | OctreeServerDatagramProcessor* datagramProcessor = new OctreeServerDatagramProcessor(nodeList->getNodeSocket(), thread()); |
| 883 | 888 | datagramProcessor->moveToThread(_datagramProcessingThread); |
| 884 | − | |
| 889 | + | |
| 885 | 890 | // remove the NodeList as the parent of the node socket |
| 886 | 891 | nodeList->getNodeSocket().setParent(NULL); |
| 887 | 892 | nodeList->getNodeSocket().moveToThread(_datagramProcessingThread); |
| 888 | − | |
| 893 | + | |
| 889 | 894 | // let the datagram processor handle readyRead from node socket |
| 890 | 895 | connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, |
| 891 | 896 | datagramProcessor, &OctreeServerDatagramProcessor::readPendingDatagrams); |
| 892 | − | |
| 897 | + | |
| 893 | 898 | // connect to the datagram processing thread signal that tells us we have to handle a packet |
| 894 | 899 | connect(datagramProcessor, &OctreeServerDatagramProcessor::packetRequiresProcessing, this, &OctreeServer::readPendingDatagram); |
| 895 | − | |
| 900 | + | |
| 896 | 901 | // delete the datagram processor and the associated thread when the QThread quits |
| 897 | 902 | connect(_datagramProcessingThread, &QThread::finished, datagramProcessor, &QObject::deleteLater); |
| 898 | 903 | connect(datagramProcessor, &QObject::destroyed, _datagramProcessingThread, &QThread::deleteLater); |
| 899 | − | |
| 904 | + | |
| 900 | 905 | // start the datagram processing thread |
| 901 | 906 | _datagramProcessingThread->start(); |
| 902 | 907 | } |
| @@ -961,16 +966,16 @@ void OctreeServer::readConfiguration() { · 58 unmodified lines | ||
| 961 | 966 | // wait until we have the domain-server settings, otherwise we bail |
| 962 | 967 | auto nodeList = DependencyManager::get<NodeList>(); |
| 963 | 968 | DomainHandler& domainHandler = nodeList->getDomainHandler(); |
| 964 | − | |
| 969 | + | |
| 965 | 970 | qDebug() << "Waiting for domain settings from domain-server."; |
| 966 | − | |
| 971 | + | |
| 967 | 972 | // block until we get the settingsRequestComplete signal |
| 968 | 973 | QEventLoop loop; |
| 969 | 974 | connect(&domainHandler, &DomainHandler::settingsReceived, &loop, &QEventLoop::quit); |
| 970 | 975 | connect(&domainHandler, &DomainHandler::settingsReceiveFail, &loop, &QEventLoop::quit); |
| 971 | 976 | domainHandler.requestDomainSettings(); |
| 972 | 977 | loop.exec(); |
| 973 | − | |
| 978 | + | |
| 974 | 979 | if (domainHandler.getSettingsObject().isEmpty()) { |
| 975 | 980 | qDebug() << "No settings object from domain-server."; |
| 976 | 981 | } |
| @@ -978,7 +983,7 @@ void OctreeServer::readConfiguration() { · 1 unmodified line | ||
| 978 | 983 | QString settingsKey = getMyDomainSettingsKey(); |
| 979 | 984 | QJsonObject settingsSectionObject = settingsObject[settingsKey].toObject(); |
| 980 | 985 | _settings = settingsSectionObject; // keep this for later |
| 981 | − | |
| 986 | + | |
| 982 | 987 | if (!readOptionString(QString("statusHost"), settingsSectionObject, _statusHost) || _statusHost.isEmpty()) { |
| 983 | 988 | _statusHost = getLocalAddress().toString(); |
| 984 | 989 | } |
| @@ -1002,7 +1007,7 @@ void OctreeServer::readConfiguration() { · 17 unmodified lines | ||
| 1002 | 1007 | bool hasRoot = readOptionString(QString("jurisdictionRoot"), settingsSectionObject, jurisdictionRoot); |
| 1003 | 1008 | QString jurisdictionEndNodes; |
| 1004 | 1009 | bool hasEndNodes = readOptionString(QString("jurisdictionEndNodes"), settingsSectionObject, jurisdictionEndNodes); |
| 1005 | − | |
| 1010 | + | |
| 1006 | 1011 | if (hasRoot || hasEndNodes) { |
| 1007 | 1012 | _jurisdiction = new JurisdictionMap(qPrintable(jurisdictionRoot), qPrintable(jurisdictionEndNodes)); |
| 1008 | 1013 | } |
| @@ -1050,7 +1055,7 @@ void OctreeServer::readConfiguration() { · 41 unmodified lines | ||
| 1050 | 1055 | qDebug() << "wantBackup=" << _wantBackup; |
| 1051 | 1056 | |
| 1052 | 1057 | //qDebug() << "settingsSectionObject:" << settingsSectionObject; |
| 1053 | − | |
| 1058 | + | |
| 1054 | 1059 | } else { |
| 1055 | 1060 | qDebug("persistFilename= DISABLED"); |
| 1056 | 1061 | } |
| @@ -1072,7 +1077,7 @@ void OctreeServer::readConfiguration() { · 15 unmodified lines | ||
| 1072 | 1077 | _packetsPerClientPerInterval = 1; |
| 1073 | 1078 | } |
| 1074 | 1079 | } |
| 1075 | − qDebug("packetsPerSecondPerClientMax=%d _packetsPerClientPerInterval=%d", | |
| 1080 | + qDebug("packetsPerSecondPerClientMax=%d _packetsPerClientPerInterval=%d", | |
| 1076 | 1081 | packetsPerSecondPerClientMax, _packetsPerClientPerInterval); |
| 1077 | 1082 | |
| 1078 | 1083 | // Check to see if the user passed in a command line option for setting packet send rate |
| @@ -1083,10 +1088,10 @@ void OctreeServer::readConfiguration() { · 4 unmodified lines | ||
| 1083 | 1088 | _packetsTotalPerInterval = 1; |
| 1084 | 1089 | } |
| 1085 | 1090 | } |
| 1086 | − qDebug("packetsPerSecondTotalMax=%d _packetsTotalPerInterval=%d", | |
| 1091 | + qDebug("packetsPerSecondTotalMax=%d _packetsTotalPerInterval=%d", | |
| 1087 | 1092 | packetsPerSecondTotalMax, _packetsTotalPerInterval); |
| 1088 | − | |
| 1089 | − | |
| 1093 | + | |
| 1094 | + | |
| 1090 | 1095 | readAdditionalConfiguration(settingsSectionObject); |
| 1091 | 1096 | } |
| 1092 | 1097 | |
| @@ -1101,8 +1106,8 @@ void OctreeServer::run() { · 8 unmodified lines | ||
| 1101 | 1106 | // make sure our NodeList knows what type we are |
| 1102 | 1107 | auto nodeList = DependencyManager::get<NodeList>(); |
| 1103 | 1108 | nodeList->setOwnerType(getMyNodeType()); |
| 1104 | − | |
| 1105 | − | |
| 1109 | + | |
| 1110 | + | |
| 1106 | 1111 | // use common init to setup common timers and logging |
| 1107 | 1112 | commonInit(getMyLoggingServerTargetName(), getMyNodeType()); |
| 1108 | 1113 | |
| @@ -1110,7 +1115,7 @@ void OctreeServer::run() { · 1 unmodified line | ||
| 1110 | 1115 | |
| 1111 | 1116 | // read the configuration from either the payload or the domain server configuration |
| 1112 | 1117 | readConfiguration(); |
| 1113 | − | |
| 1118 | + | |
| 1114 | 1119 | beforeRun(); // after payload has been processed |
| 1115 | 1120 | |
| 1116 | 1121 | connect(nodeList.data(), SIGNAL(nodeAdded(SharedNodePointer)), SLOT(nodeAdded(SharedNodePointer))); |
| @@ -1119,7 +1124,7 @@ void OctreeServer::run() { · 2 unmodified lines | ||
| 1119 | 1124 | |
| 1120 | 1125 | // we need to ask the DS about agents so we can ping/reply with them |
| 1121 | 1126 | nodeList->addNodeTypeToInterestSet(NodeType::Agent); |
| 1122 | − | |
| 1127 | + | |
| 1123 | 1128 | #ifndef WIN32 |
| 1124 | 1129 | setvbuf(stdout, NULL, _IOLBF, 0); |
| 1125 | 1130 | #endif |
| @@ -1209,7 +1214,7 @@ void OctreeServer::forceNodeShutdown(SharedNodePointer node) { · 83 unmodified lines | ||
| 1209 | 1214 | |
| 1210 | 1215 | quint64 end = usecTimestampNow(); |
| 1211 | 1216 | quint64 usecsElapsed = (end - start); |
| 1212 | − qDebug() << qPrintable(_safeServerName) << "server forceNodeShutdown() took: " | |
| 1217 | + qDebug() << qPrintable(_safeServerName) << "server forceNodeShutdown() took: " | |
| 1213 | 1218 | << usecsElapsed << " usecs for node:" << *node; |
| 1214 | 1219 | } |
| 1215 | 1220 | |
| @@ -1225,7 +1230,7 @@ void OctreeServer::aboutToFinish() { · 9 unmodified lines | ||
| 1225 | 1230 | // This ensures that when we forceNodeShutdown below for each node we don't get any more newly connecting nodes |
| 1226 | 1231 | auto nodeList = DependencyManager::get<NodeList>(); |
| 1227 | 1232 | nodeList->linkedDataCreateCallback = NULL; |
| 1228 | − | |
| 1233 | + | |
| 1229 | 1234 | if (_octreeInboundPacketProcessor) { |
| 1230 | 1235 | _octreeInboundPacketProcessor->terminating(); |
| 1231 | 1236 | } |
| @@ -1240,7 +1245,7 @@ void OctreeServer::aboutToFinish() { · 8 unmodified lines | ||
| 1240 | 1245 | qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node; |
| 1241 | 1246 | forceNodeShutdown(node); |
| 1242 | 1247 | }); |
| 1243 | − | |
| 1248 | + | |
| 1244 | 1249 | if (_persistThread) { |
| 1245 | 1250 | _persistThread->aboutToFinish(); |
| 1246 | 1251 | _persistThread->terminating(); |
| @@ -1282,7 +1287,7 @@ QString OctreeServer::getUptime() { · 35 unmodified lines | ||
| 1282 | 1287 | if (hours > 0 || minutes > 0) { |
| 1283 | 1288 | formattedUptime += QString(" "); |
| 1284 | 1289 | } |
| 1285 | − formattedUptime += QString().sprintf("%.3f seconds", seconds); | |
| 1290 | + formattedUptime += QString().sprintf("%.3f seconds", (double)seconds); | |
| 1286 | 1291 | } |
| 1287 | 1292 | return formattedUptime; |
| 1288 | 1293 | } |
| @@ -1290,13 +1295,13 @@ QString OctreeServer::getUptime() { · 1 unmodified line | ||
| 1290 | 1295 | QString OctreeServer::getFileLoadTime() { |
| 1291 | 1296 | QString result; |
| 1292 | 1297 | if (isInitialLoadComplete()) { |
| 1293 | − | |
| 1298 | + | |
| 1294 | 1299 | const int USECS_PER_MSEC = 1000; |
| 1295 | 1300 | const int MSECS_PER_SEC = 1000; |
| 1296 | 1301 | const int SECS_PER_MIN = 60; |
| 1297 | 1302 | const int MIN_PER_HOUR = 60; |
| 1298 | 1303 | const int MSECS_PER_MIN = MSECS_PER_SEC * SECS_PER_MIN; |
| 1299 | − | |
| 1304 | + | |
| 1300 | 1305 | quint64 msecsElapsed = getLoadElapsedTime() / USECS_PER_MSEC;; |
| 1301 | 1306 | float seconds = (msecsElapsed % MSECS_PER_MIN)/(float)MSECS_PER_SEC; |
| 1302 | 1307 | int minutes = (msecsElapsed/(MSECS_PER_MIN)) % MIN_PER_HOUR; |
| @@ -1321,7 +1326,7 @@ QString OctreeServer::getFileLoadTime() { · 18 unmodified lines | ||
| 1321 | 1326 | if (hours > 0 || minutes > 0) { |
| 1322 | 1327 | result += QString(" "); |
| 1323 | 1328 | } |
| 1324 | − result += QString().sprintf("%.3f seconds", seconds); | |
| 1329 | + result += QString().sprintf("%.3f seconds", (double)seconds); | |
| 1325 | 1330 | } |
| 1326 | 1331 | } else { |
| 1327 | 1332 | result = "Not yet loaded..."; |
| @@ -1356,27 +1361,27 @@ void OctreeServer::sendStatsPacket() { · 28 unmodified lines | ||
| 1356 | 1361 | // 2) only send new data |
| 1357 | 1362 | // 3) automatically break up into multiple packets |
| 1358 | 1363 | static QJsonObject statsObject1; |
| 1359 | − | |
| 1364 | + | |
| 1360 | 1365 | QString baseName = getMyServerName() + QString("Server"); |
| 1361 | − | |
| 1366 | + | |
| 1362 | 1367 | statsObject1[baseName + QString(".0.1.configuration")] = getConfiguration(); |
| 1363 | − | |
| 1368 | + | |
| 1364 | 1369 | statsObject1[baseName + QString(".0.2.detailed_stats_url")] = getStatusLink(); |
| 1365 | − | |
| 1370 | + | |
| 1366 | 1371 | statsObject1[baseName + QString(".0.3.uptime")] = getUptime(); |
| 1367 | 1372 | statsObject1[baseName + QString(".0.4.persistFileLoadTime")] = getFileLoadTime(); |
| 1368 | 1373 | statsObject1[baseName + QString(".0.5.clients")] = getCurrentClientCount(); |
| 1369 | − | |
| 1374 | + | |
| 1370 | 1375 | quint64 oneSecondAgo = usecTimestampNow() - USECS_PER_SECOND; |
| 1371 | − | |
| 1376 | + | |
| 1372 | 1377 | statsObject1[baseName + QString(".0.6.threads.1.processing")] = (double)howManyThreadsDidProcess(oneSecondAgo); |
| 1373 | − statsObject1[baseName + QString(".0.6.threads.2.packetDistributor")] = | |
| 1378 | + statsObject1[baseName + QString(".0.6.threads.2.packetDistributor")] = | |
| 1374 | 1379 | (double)howManyThreadsDidPacketDistributor(oneSecondAgo); |
| 1375 | − statsObject1[baseName + QString(".0.6.threads.3.handlePacektSend")] = | |
| 1380 | + statsObject1[baseName + QString(".0.6.threads.3.handlePacektSend")] = | |
| 1376 | 1381 | (double)howManyThreadsDidHandlePacketSend(oneSecondAgo); |
| 1377 | − statsObject1[baseName + QString(".0.6.threads.4.writeDatagram")] = | |
| 1378 | − (double)howManyThreadsDidCallWriteDatagram(oneSecondAgo); | |
| 1379 | − | |
| 1382 | + statsObject1[baseName + QString(".0.6.threads.4.writeDatagram")] = | |
| 1383 | + (double)howManyThreadsDidCallWriteDatagram(oneSecondAgo); | |
| 1384 | + | |
| 1380 | 1385 | statsObject1[baseName + QString(".1.1.octree.elementCount")] = (double)OctreeElement::getNodeCount(); |
| 1381 | 1386 | statsObject1[baseName + QString(".1.2.octree.internalElementCount")] = (double)OctreeElement::getInternalNodeCount(); |
| 1382 | 1387 | statsObject1[baseName + QString(".1.3.octree.leafElementCount")] = (double)OctreeElement::getLeafNodeCount(); |
| @@ -1388,9 +1393,9 @@ void OctreeServer::sendStatsPacket() { · 5 unmodified lines | ||
| 1388 | 1393 | statsObject2[baseName + QString(".2.outbound.data.totalPackets")] = (double)OctreeSendThread::_totalPackets; |
| 1389 | 1394 | statsObject2[baseName + QString(".2.outbound.data.totalBytes")] = (double)OctreeSendThread::_totalBytes; |
| 1390 | 1395 | statsObject2[baseName + QString(".2.outbound.data.totalBytesWasted")] = (double)OctreeSendThread::_totalWastedBytes; |
| 1391 | − statsObject2[baseName + QString(".2.outbound.data.totalBytesOctalCodes")] = | |
| 1396 | + statsObject2[baseName + QString(".2.outbound.data.totalBytesOctalCodes")] = | |
| 1392 | 1397 | (double)OctreePacketData::getTotalBytesOfOctalCodes(); |
| 1393 | − statsObject2[baseName + QString(".2.outbound.data.totalBytesBitMasks")] = | |
| 1398 | + statsObject2[baseName + QString(".2.outbound.data.totalBytesBitMasks")] = | |
| 1394 | 1399 | (double)OctreePacketData::getTotalBytesOfBitMasks(); |
| 1395 | 1400 | statsObject2[baseName + QString(".2.outbound.data.totalBytesBitMasks")] = (double)OctreePacketData::getTotalBytesOfColor(); |
| 1396 | 1401 | |
| @@ -1406,19 +1411,19 @@ void OctreeServer::sendStatsPacket() { · 9 unmodified lines | ||
| 1406 | 1411 | |
| 1407 | 1412 | static QJsonObject statsObject3; |
| 1408 | 1413 | |
| 1409 | − statsObject3[baseName + QString(".3.inbound.data.1.totalPackets")] = | |
| 1414 | + statsObject3[baseName + QString(".3.inbound.data.1.totalPackets")] = | |
| 1410 | 1415 | (double)_octreeInboundPacketProcessor->getTotalPacketsProcessed(); |
| 1411 | − statsObject3[baseName + QString(".3.inbound.data.2.totalElements")] = | |
| 1416 | + statsObject3[baseName + QString(".3.inbound.data.2.totalElements")] = | |
| 1412 | 1417 | (double)_octreeInboundPacketProcessor->getTotalElementsProcessed(); |
| 1413 | − statsObject3[baseName + QString(".3.inbound.timing.1.avgTransitTimePerPacket")] = | |
| 1418 | + statsObject3[baseName + QString(".3.inbound.timing.1.avgTransitTimePerPacket")] = | |
| 1414 | 1419 | (double)_octreeInboundPacketProcessor->getAverageTransitTimePerPacket(); |
| 1415 | − statsObject3[baseName + QString(".3.inbound.timing.2.avgProcessTimePerPacket")] = | |
| 1420 | + statsObject3[baseName + QString(".3.inbound.timing.2.avgProcessTimePerPacket")] = | |
| 1416 | 1421 | (double)_octreeInboundPacketProcessor->getAverageProcessTimePerPacket(); |
| 1417 | − statsObject3[baseName + QString(".3.inbound.timing.3.avgLockWaitTimePerPacket")] = | |
| 1422 | + statsObject3[baseName + QString(".3.inbound.timing.3.avgLockWaitTimePerPacket")] = | |
| 1418 | 1423 | (double)_octreeInboundPacketProcessor->getAverageLockWaitTimePerPacket(); |
| 1419 | − statsObject3[baseName + QString(".3.inbound.timing.4.avgProcessTimePerElement")] = | |
| 1424 | + statsObject3[baseName + QString(".3.inbound.timing.4.avgProcessTimePerElement")] = | |
| 1420 | 1425 | (double)_octreeInboundPacketProcessor->getAverageProcessTimePerElement(); |
| 1421 | − statsObject3[baseName + QString(".3.inbound.timing.5.avgLockWaitTimePerElement")] = | |
| 1426 | + statsObject3[baseName + QString(".3.inbound.timing.5.avgLockWaitTimePerElement")] = | |
| 1422 | 1427 | (double)_octreeInboundPacketProcessor->getAverageLockWaitTimePerElement(); |
| 1423 | 1428 | |
| 1424 | 1429 | DependencyManager::get<NodeList>()->sendStatsToDomainServer(statsObject3); |
| @@ -9,8 +9,8 @@ if (WIN32) · 8 unmodified lines | ||
| 9 | 9 | |
| 10 | 10 | ExternalProject_Add( |
| 11 | 11 | ${EXTERNAL_NAME} |
| 12 | − URL http://static.oculus.com/sdk-downloads/ovr_sdk_win_0.5.0.1.zip | |
| 13 | − URL_MD5 d3fc4c02db9be5ff08af4ef4c97b32f9 | |
| 12 | + URL http://static.oculus.com/sdk-downloads/0.6.0.0/1431634088/ovr_sdk_win_0.6.0.0.zip | |
| 13 | + URL_MD5 a3dfdab037a854fdcf7e6033fa8d7028 | |
| 14 | 14 | CONFIGURE_COMMAND "" |
| 15 | 15 | BUILD_COMMAND "" |
| 16 | 16 | INSTALL_COMMAND "" |
| @@ -21,7 +21,11 @@ if (WIN32) · 4 unmodified lines | ||
| 21 | 21 | |
| 22 | 22 | # FIXME need to account for different architectures |
| 23 | 23 | set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/LibOVR/Include CACHE TYPE INTERNAL) |
| 24 | − set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/LibOVR/Lib/Windows/Win32/Release/VS2013/LibOVR.lib CACHE TYPE INTERNAL) | |
| 24 | + if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") | |
| 25 | + set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/LibOVR/Lib/Windows/x64/Release/VS2013/LibOVR.lib CACHE TYPE INTERNAL) | |
| 26 | + else() | |
| 27 | + set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/LibOVR/Lib/Windows/Win32/Release/VS2013/LibOVR.lib CACHE TYPE INTERNAL) | |
| 28 | + endif() | |
| 25 | 29 | |
| 26 | 30 | elseif(APPLE) |
| 27 | 31 | |
| @@ -3,13 +3,13 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) · 2 unmodified lines | ||
| 3 | 3 | |
| 4 | 4 | include(ExternalProject) |
| 5 | 5 | ExternalProject_Add( |
| 6 | − ${EXTERNAL_NAME} | |
| 7 | − URL https://github.com/boostorg/config/archive/boost-1.58.0.zip | |
| 8 | − URL_MD5 42fa673bae2b7645a22736445e80eb8d | |
| 9 | − CONFIGURE_COMMAND "" | |
| 10 | − BUILD_COMMAND "" | |
| 11 | − INSTALL_COMMAND "" | |
| 12 | − LOG_DOWNLOAD 1 | |
| 6 | + ${EXTERNAL_NAME} | |
| 7 | + URL https://github.com/boostorg/config/archive/boost-1.58.0.zip | |
| 8 | + URL_MD5 42fa673bae2b7645a22736445e80eb8d | |
| 9 | + CONFIGURE_COMMAND "" | |
| 10 | + BUILD_COMMAND "" | |
| 11 | + INSTALL_COMMAND "" | |
| 12 | + LOG_DOWNLOAD 1 | |
| 13 | 13 | ) |
| 14 | 14 | |
| 15 | 15 | ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) |
| @@ -16,11 +16,16 @@ if (WIN32) · 15 unmodified lines | ||
| 16 | 16 | |
| 17 | 17 | string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) |
| 18 | 18 | set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE PATH "List of glew include directories") |
| 19 | − | |
| 20 | − set(_LIB_DIR ${SOURCE_DIR}/lib/Release/Win32) | |
| 21 | − | |
| 19 | + | |
| 20 | + if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") | |
| 21 | + set(_LIB_DIR ${SOURCE_DIR}/lib/Release/x64) | |
| 22 | + set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${SOURCE_DIR}/bin/Release/x64 CACHE FILEPATH "Location of GLEW DLL") | |
| 23 | + else() | |
| 24 | + set(_LIB_DIR ${SOURCE_DIR}/lib/Release/Win32) | |
| 25 | + set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${SOURCE_DIR}/bin/Release/Win32 CACHE FILEPATH "Location of GLEW DLL") | |
| 26 | + endif() | |
| 27 | + | |
| 22 | 28 | set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${_LIB_DIR}/glew32.lib CACHE FILEPATH "Location of GLEW release library") |
| 23 | 29 | set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "Location of GLEW debug library") |
| 24 | − | |
| 25 | − set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${SOURCE_DIR}/bin/Release/Win32 CACHE FILEPATH "Location of GLEW DLL") | |
| 30 | + | |
| 26 | 31 | endif () |
| @@ -3,13 +3,13 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) · 2 unmodified lines | ||
| 3 | 3 | |
| 4 | 4 | include(ExternalProject) |
| 5 | 5 | ExternalProject_Add( |
| 6 | − ${EXTERNAL_NAME} | |
| 7 | − URL http://softlayer-dal.dl.sourceforge.net/project/oglplus/oglplus-0.61.x/oglplus-0.61.0.zip | |
| 8 | − URL_MD5 bb55038c36c660d2b6c7be380414fa60 | |
| 9 | − CONFIGURE_COMMAND "" | |
| 10 | − BUILD_COMMAND "" | |
| 11 | − INSTALL_COMMAND "" | |
| 12 | − LOG_DOWNLOAD 1 | |
| 6 | + ${EXTERNAL_NAME} | |
| 7 | + GIT_REPOSITORY https://github.com/matus-chochlik/oglplus.git | |
| 8 | + GIT_TAG a2681383928b1166f176512cbe0f95e96fe68d08 | |
| 9 | + CONFIGURE_COMMAND "" | |
| 10 | + BUILD_COMMAND "" | |
| 11 | + INSTALL_COMMAND "" | |
| 12 | + LOG_DOWNLOAD 1 | |
| 13 | 13 | ) |
| 14 | 14 | |
| 15 | 15 | ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) |
| @@ -73,9 +73,14 @@ if (APPLE) · 72 unmodified lines | ||
| 73 | 73 | ) |
| 74 | 74 | |
| 75 | 75 | elseif (WIN32) |
| 76 | − set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/ia32/vc12") | |
| 76 | + if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") | |
| 77 | + set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/intel64/vc12") | |
| 78 | + set(${EXTERNAL_NAME_UPPER}_DLL_PATH "${SOURCE_DIR}/bin/intel64/vc12" CACHE PATH "Path to TBB DLLs") | |
| 79 | + else() | |
| 80 | + set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/ia32/vc12") | |
| 81 | + set(${EXTERNAL_NAME_UPPER}_DLL_PATH "${SOURCE_DIR}/bin/ia32/vc12" CACHE PATH "Path to TBB DLLs") | |
| 82 | + endif() | |
| 77 | 83 | set(_LIB_EXT "lib") |
| 78 | − set(${EXTERNAL_NAME_UPPER}_DLL_PATH "${SOURCE_DIR}/bin/ia32/vc12" CACHE PATH "Path to TBB DLLs") | |
| 79 | 84 | elseif (ANDROID) |
| 80 | 85 | set(_TBB_LIB_DIR "${SOURCE_DIR}/lib") |
| 81 | 86 | set(_LIB_PREFIX "lib") |
| @@ -0,0 +1,43 @@ | ||
| 1 | + | |
| 2 | + | |
| 3 | +macro(SETUP_HIFI_OPENGL) | |
| 4 | + | |
| 5 | + if (APPLE) | |
| 6 | + | |
| 7 | + # link in required OS X frameworks and include the right GL headers | |
| 8 | + find_library(OpenGL OpenGL) | |
| 9 | + target_link_libraries(${TARGET_NAME} ${OpenGL}) | |
| 10 | + | |
| 11 | + elseif (WIN32) | |
| 12 | + | |
| 13 | + add_dependency_external_projects(glew) | |
| 14 | + find_package(GLEW REQUIRED) | |
| 15 | + target_include_directories(${TARGET_NAME} PUBLIC ${GLEW_INCLUDE_DIRS}) | |
| 16 | + target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARIES} opengl32.lib) | |
| 17 | + | |
| 18 | + if (USE_NSIGHT) | |
| 19 | + # try to find the Nsight package and add it to the build if we find it | |
| 20 | + find_package(NSIGHT) | |
| 21 | + if (NSIGHT_FOUND) | |
| 22 | + include_directories(${NSIGHT_INCLUDE_DIRS}) | |
| 23 | + add_definitions(-DNSIGHT_FOUND) | |
| 24 | + target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}") | |
| 25 | + endif() | |
| 26 | + endif() | |
| 27 | + | |
| 28 | + elseif(ANDROID) | |
| 29 | + | |
| 30 | + target_link_libraries(${TARGET_NAME} "-lGLESv3" "-lEGL") | |
| 31 | + | |
| 32 | + else() | |
| 33 | + | |
| 34 | + find_package(OpenGL REQUIRED) | |
| 35 | + if (${OPENGL_INCLUDE_DIR}) | |
| 36 | + include_directories(SYSTEM "${OPENGL_INCLUDE_DIR}") | |
| 37 | + endif() | |
| 38 | + target_link_libraries(${TARGET_NAME} "${OPENGL_LIBRARY}") | |
| 39 | + target_include_directories(${TARGET_NAME} PUBLIC ${OPENGL_INCLUDE_DIR}) | |
| 40 | + | |
| 41 | + endif() | |
| 42 | + | |
| 43 | +endmacro() | |
| @@ -28,7 +28,11 @@ if (APPLE) · 27 unmodified lines | ||
| 28 | 28 | elseif (UNIX) |
| 29 | 29 | set(ARCH_DIR "UNIX") |
| 30 | 30 | elseif (WIN32) |
| 31 | − set(ARCH_DIR "Win32") | |
| 31 | + if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") | |
| 32 | + set(ARCH_DIR "x64") | |
| 33 | + else() | |
| 34 | + set(ARCH_DIR "Win32") | |
| 35 | + endif() | |
| 32 | 36 | endif () |
| 33 | 37 | |
| 34 | 38 | find_library(FACESHIFT_LIBRARY_RELEASE NAME faceshift PATH_SUFFIXES lib/${ARCH_DIR} HINTS ${FACESHIFT_SEARCH_DIRS}) |
| @@ -16,7 +16,16 @@ · 15 unmodified lines | ||
| 16 | 16 | # |
| 17 | 17 | |
| 18 | 18 | if (WIN32) |
| 19 | − | |
| 19 | + | |
| 20 | + if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") | |
| 21 | + set(ARCH_DIR "x64") | |
| 22 | + set(ARCH_NAME "64") | |
| 23 | + else() | |
| 24 | + set(ARCH_DIR "Win32") | |
| 25 | + set(ARCH_NAME "32") | |
| 26 | + endif() | |
| 27 | + | |
| 28 | + | |
| 20 | 29 | find_path(NSIGHT_INCLUDE_DIRS |
| 21 | 30 | NAMES |
| 22 | 31 | nvToolsExt.h |
| @@ -25,17 +34,18 @@ if (WIN32) · 2 unmodified lines | ||
| 25 | 34 | PATHS |
| 26 | 35 | "C:/Program Files/NVIDIA Corporation/NvToolsExt") |
| 27 | 36 | |
| 28 | − find_library(NSIGHT_LIBRARY_RELEASE nvToolsExt32_1 | |
| 37 | + find_library(NSIGHT_LIBRARY_RELEASE "nvToolsExt${ARCH_NAME}_1" | |
| 29 | 38 | PATH_SUFFIXES |
| 30 | − "lib/Win32" "lib" | |
| 39 | + "lib/${ARCH_DIR}" "lib" | |
| 31 | 40 | PATHS |
| 32 | 41 | "C:/Program Files/NVIDIA Corporation/NvToolsExt") |
| 33 | − find_library(NSIGHT_LIBRARY_DEBUG nvToolsExt32_1 | |
| 42 | + find_library(NSIGHT_LIBRARY_DEBUG "nvToolsExt${ARCH_NAME}_1" | |
| 34 | 43 | PATH_SUFFIXES |
| 35 | − "lib/Win32" "lib" | |
| 44 | + "lib/${ARCH_DIR}" "lib" | |
| 36 | 45 | PATHS |
| 37 | 46 | "C:/Program Files/NVIDIA Corporation/NvToolsExt") |
| 38 | − | |
| 47 | + | |
| 48 | + add_paths_to_fixup_libs("C:/Program Files/NVIDIA Corporation/NvToolsExt/bin/${ARCH_DIR}") | |
| 39 | 49 | include(SelectLibraryConfigurations) |
| 40 | 50 | select_library_configurations(NSIGHT) |
| 41 | 51 | endif () |
| @@ -30,12 +30,20 @@ elseif (UNIX) · 29 unmodified lines | ||
| 30 | 30 | find_library(SIXENSE_LIBRARY_RELEASE lib/linux_x64/release/libsixense_x64.so HINTS ${SIXENSE_SEARCH_DIRS}) |
| 31 | 31 | # find_library(SIXENSE_LIBRARY_DEBUG lib/linux_x64/debug/libsixensed_x64.so HINTS ${SIXENSE_SEARCH_DIRS}) |
| 32 | 32 | elseif (WIN32) |
| 33 | − find_library(SIXENSE_LIBRARY_RELEASE lib/win32/release_dll/sixense.lib HINTS ${SIXENSE_SEARCH_DIRS}) | |
| 34 | − find_library(SIXENSE_LIBRARY_DEBUG lib/win32/debug_dll/sixensed.lib HINTS ${SIXENSE_SEARCH_DIRS}) | |
| 33 | + if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") | |
| 34 | + set(ARCH_DIR "x64") | |
| 35 | + set(ARCH_SUFFIX "_x64") | |
| 36 | + else() | |
| 37 | + set(ARCH_DIR "Win32") | |
| 38 | + set(ARCH_SUFFIX "") | |
| 39 | + endif() | |
| 40 | + | |
| 41 | + find_library(SIXENSE_LIBRARY_RELEASE "lib/${ARCH_DIR}/release_dll/sixense${ARCH_SUFFIX}.lib" HINTS ${SIXENSE_SEARCH_DIRS}) | |
| 42 | + find_library(SIXENSE_LIBRARY_DEBUG "lib/${ARCH_DIR}/debug_dll/sixensed.lib" HINTS ${SIXENSE_SEARCH_DIRS}) | |
| 35 | 43 | |
| 36 | − find_path(SIXENSE_DEBUG_DLL_PATH sixensed.dll PATH_SUFFIXES bin/win32/debug_dll HINTS ${SIXENSE_SEARCH_DIRS}) | |
| 37 | − find_path(SIXENSE_RELEASE_DLL_PATH sixense.dll PATH_SUFFIXES bin/win32/release_dll HINTS ${SIXENSE_SEARCH_DIRS}) | |
| 38 | − find_path(SIXENSE_DEVICE_DLL_PATH DeviceDLL.dll PATH_SUFFIXES samples/win32/sixense_simple3d HINTS ${SIXENSE_SEARCH_DIRS}) | |
| 44 | + find_path(SIXENSE_DEBUG_DLL_PATH "sixensed${ARCH_SUFFIX}.dll" PATH_SUFFIXES bin/${ARCH_DIR}/debug_dll HINTS ${SIXENSE_SEARCH_DIRS}) | |
| 45 | + find_path(SIXENSE_RELEASE_DLL_PATH "sixense${ARCH_SUFFIX}.dll" PATH_SUFFIXES bin/${ARCH_DIR}/release_dll HINTS ${SIXENSE_SEARCH_DIRS}) | |
| 46 | + find_path(SIXENSE_DEVICE_DLL_PATH DeviceDLL.dll PATH_SUFFIXES samples/${ARCH_DIR}/sixense_simple3d HINTS ${SIXENSE_SEARCH_DIRS}) | |
| 39 | 47 | endif () |
| 40 | 48 | |
| 41 | 49 | include(SelectLibraryConfigurations) |
| @@ -49,7 +49,7 @@ elseif (UNIX AND NOT ANDROID) · 48 unmodified lines | ||
| 49 | 49 | endif () |
| 50 | 50 | |
| 51 | 51 | elseif (WIN32) |
| 52 | − if (CMAKE_CL_64) | |
| 52 | + if(CMAKE_SIZEOF_VOID_P EQUAL 8) | |
| 53 | 53 | set(_TBB_ARCH_DIR "intel64") |
| 54 | 54 | else() |
| 55 | 55 | set(_TBB_ARCH_DIR "ia32") |
| @@ -100,12 +100,12 @@ var NUM_BUTTONS = 3; · 99 unmodified lines | ||
| 100 | 100 | var screenSize = Controller.getViewportDimensions(); |
| 101 | 101 | var startX = screenSize.x / 2 - (NUM_BUTTONS * (BUTTON_SIZE + PADDING)) / 2; |
| 102 | 102 | Script.include(["../../libraries/toolBars.js"]); |
| 103 | −const persistKey = "highfidelity.gun.toolbar.position"; | |
| 104 | −var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL); | |
| 105 | −toolBar.save = function () { | |
| 106 | − Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y])); | |
| 107 | −}; | |
| 108 | −var old = JSON.parse(Settings.getValue(persistKey) || '0'); | |
| 103 | +var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.gun.toolbar", function (screenSize) { | |
| 104 | + return { | |
| 105 | + x: startX, | |
| 106 | + y: (screenSize.y - (BUTTON_SIZE + PADDING)), | |
| 107 | + }; | |
| 108 | +}); | |
| 109 | 109 | var reticle = Overlays.addOverlay("image", { |
| 110 | 110 | x: screenSize.x / 2 - (BUTTON_SIZE / 2), |
| 111 | 111 | y: screenSize.y / 2 - (BUTTON_SIZE / 2), |
| @@ -116,8 +116,6 @@ var reticle = Overlays.addOverlay("image", { · 4 unmodified lines | ||
| 116 | 116 | }); |
| 117 | 117 | |
| 118 | 118 | var offButton = toolBar.addOverlay("image", { |
| 119 | − x: old ? old[0] : startX, | |
| 120 | − y: old ? old[1] : (screenSize.y - (BUTTON_SIZE + PADDING)), | |
| 121 | 119 | width: BUTTON_SIZE, |
| 122 | 120 | height: BUTTON_SIZE, |
| 123 | 121 | imageURL: HIFI_PUBLIC_BUCKET + "images/gun/close.svg", |
| @@ -181,7 +179,7 @@ function entityCollisionWithEntity(entity1, entity2, collision) { · 57 unmodified lines | ||
| 181 | 179 | } |
| 182 | 180 | |
| 183 | 181 | function shootBullet(position, velocity, grenade) { |
| 184 | − var BULLET_SIZE = 0.10; | |
| 182 | + var BULLET_SIZE = .09; | |
| 185 | 183 | var BULLET_LIFETIME = 10.0; |
| 186 | 184 | var BULLET_GRAVITY = -0.25; |
| 187 | 185 | var GRENADE_VELOCITY = 15.0; |
| @@ -16,7 +16,6 @@ Script.load("lobby.js"); · 15 unmodified lines | ||
| 16 | 16 | Script.load("notifications.js"); |
| 17 | 17 | Script.load("users.js"); |
| 18 | 18 | Script.load("grab.js"); |
| 19 | −Script.load("pointer.js"); | |
| 20 | 19 | Script.load("directory.js"); |
| 21 | 20 | Script.load("mouseLook.js"); |
| 22 | 21 | Script.load("hmdControls.js"); |
| @@ -33,15 +33,13 @@ var BUTTON_SIZE = 32; · 32 unmodified lines | ||
| 33 | 33 | var PADDING = 3; |
| 34 | 34 | |
| 35 | 35 | Script.include(["libraries/toolBars.js"]); |
| 36 | −var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL); | |
| 37 | −const persistKey = "highfidelity.dice.toolbar.position"; | |
| 38 | −toolBar.save = function () { | |
| 39 | − Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y])); | |
| 40 | −}; | |
| 41 | −var old = JSON.parse(Settings.getValue(persistKey) || '0'); | |
| 36 | +var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.dice.toolbar", function (screenSize) { | |
| 37 | + return { | |
| 38 | + x: (screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING), | |
| 39 | + y: (screenSize.y - (BUTTON_SIZE + PADDING)) | |
| 40 | + }; | |
| 41 | +}); | |
| 42 | 42 | var offButton = toolBar.addOverlay("image", { |
| 43 | − x: old ? old[0] : (screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING), | |
| 44 | − y: old ? old[1] : (screenSize.y - (BUTTON_SIZE + PADDING)), | |
| 45 | 43 | width: BUTTON_SIZE, |
| 46 | 44 | height: BUTTON_SIZE, |
| 47 | 45 | imageURL: HIFI_PUBLIC_BUCKET + "images/close.png", |
| @@ -49,7 +49,6 @@ selectionManager.addEventListener(function() { · 48 unmodified lines | ||
| 49 | 49 | lightOverlayManager.updatePositions(); |
| 50 | 50 | }); |
| 51 | 51 | |
| 52 | −var windowDimensions = Controller.getViewportDimensions(); | |
| 53 | 52 | var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/"; |
| 54 | 53 | var toolHeight = 50; |
| 55 | 54 | var toolWidth = 50; |
| @@ -143,7 +142,12 @@ var toolBar = (function () { · 87 unmodified lines | ||
| 143 | 142 | browseMarketplaceButton; |
| 144 | 143 | |
| 145 | 144 | function initialize() { |
| 146 | − toolBar = new ToolBar(0, 0, ToolBar.VERTICAL); | |
| 145 | + toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.edit.toolbar", function (windowDimensions, toolbar) { | |
| 146 | + return { | |
| 147 | + x: windowDimensions.x - 8 - toolbar.width, | |
| 148 | + y: (windowDimensions.y - toolbar.height) / 2 | |
| 149 | + }; | |
| 150 | + }); | |
| 147 | 151 | |
| 148 | 152 | browseMarketplaceButton = toolBar.addTool({ |
| 149 | 153 | imageURL: toolIconUrl + "marketplace.svg", |
| @@ -321,38 +325,6 @@ var toolBar = (function () { · 171 unmodified lines | ||
| 321 | 325 | } |
| 322 | 326 | } |
| 323 | 327 | |
| 324 | − const persistKey = "highfidelity.edit.toolbar.position"; | |
| 325 | − that.move = function () { | |
| 326 | − var newViewPort, | |
| 327 | − toolsX, | |
| 328 | − toolsY; | |
| 329 | − | |
| 330 | − newViewPort = Controller.getViewportDimensions(); | |
| 331 | − | |
| 332 | − if (toolBar === undefined) { | |
| 333 | − initialize(); | |
| 334 | − | |
| 335 | − toolBar.save = function () { | |
| 336 | − Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y])); | |
| 337 | − }; | |
| 338 | − var old = JSON.parse(Settings.getValue(persistKey) || '0'); | |
| 339 | − if (old) { | |
| 340 | − windowDimensions = newViewPort; | |
| 341 | − toolBar.move(old[0], old[1]); | |
| 342 | − return; | |
| 343 | − } | |
| 344 | − } else if (windowDimensions.x === newViewPort.x && | |
| 345 | − windowDimensions.y === newViewPort.y) { | |
| 346 | − return; | |
| 347 | − } | |
| 348 | − | |
| 349 | − windowDimensions = newViewPort; | |
| 350 | − toolsX = windowDimensions.x - 8 - toolBar.width; | |
| 351 | − toolsY = (windowDimensions.y - toolBar.height) / 2; | |
| 352 | − | |
| 353 | − toolBar.move(toolsX, toolsY); | |
| 354 | − }; | |
| 355 | − | |
| 356 | 328 | var newModelButtonDown = false; |
| 357 | 329 | var browseMarketplaceButtonDown = false; |
| 358 | 330 | that.mousePressEvent = function (event) { |
| @@ -552,6 +524,7 @@ var toolBar = (function () { · 193 unmodified lines | ||
| 552 | 524 | toolBar.cleanup(); |
| 553 | 525 | }; |
| 554 | 526 | |
| 527 | + initialize(); | |
| 555 | 528 | return that; |
| 556 | 529 | }()); |
| 557 | 530 | |
| @@ -931,7 +904,6 @@ var lastPosition = null; · 373 unmodified lines | ||
| 931 | 904 | |
| 932 | 905 | // Do some stuff regularly, like check for placement of various overlays |
| 933 | 906 | Script.update.connect(function (deltaTime) { |
| 934 | − toolBar.move(); | |
| 935 | 907 | progressDialog.move(); |
| 936 | 908 | selectionDisplay.checkMove(); |
| 937 | 909 | var dOrientation = Math.abs(Quat.dot(Camera.orientation, lastOrientation) - 1); |
| @@ -8,7 +8,7 @@ body { · 7 unmodified lines | ||
| 8 | 8 | background-color: rgb(76, 76, 76); |
| 9 | 9 | color: rgb(204, 204, 204); |
| 10 | 10 | font-family: Arial; |
| 11 | − font-size: 8.25pt; | |
| 11 | + font-size: 9.0pt; | |
| 12 | 12 | |
| 13 | 13 | -webkit-touch-callout: none; |
| 14 | 14 | -webkit-user-select: none; |
| @@ -58,6 +58,7 @@ body { · 43 unmodified lines | ||
| 58 | 58 | |
| 59 | 59 | .multi-property-section { |
| 60 | 60 | } |
| 61 | + | |
| 61 | 62 | .property-section { |
| 62 | 63 | display: block; |
| 63 | 64 | margin: 10 10; |
| @@ -132,7 +133,7 @@ input.no-spin::-webkit-inner-spin-button { · 68 unmodified lines | ||
| 132 | 133 | table#entity-table { |
| 133 | 134 | border-collapse: collapse; |
| 134 | 135 | font-family: Sans-Serif; |
| 135 | − font-size: 7.5pt; | |
| 136 | + font-size: 9pt; | |
| 136 | 137 | width: 100%; |
| 137 | 138 | } |
| 138 | 139 | |
| @@ -156,7 +157,7 @@ table#entity-table { · 17 unmodified lines | ||
| 156 | 157 | } |
| 157 | 158 | |
| 158 | 159 | #entity-table td { |
| 159 | − font-size: 8.25pt; | |
| 160 | + font-size: 9.0pt; | |
| 160 | 161 | border: 0pt black solid; |
| 161 | 162 | word-wrap: nowrap; |
| 162 | 163 | white-space: nowrap; |
| @@ -176,14 +177,14 @@ th#entity-type { · 13 unmodified lines | ||
| 176 | 177 | |
| 177 | 178 | div.input-area { |
| 178 | 179 | display: inline-block; |
| 179 | − font-size: 7.5pt; | |
| 180 | + font-size: 9pt; | |
| 180 | 181 | } |
| 181 | 182 | |
| 182 | 183 | input { |
| 183 | 184 | } |
| 184 | 185 | |
| 185 | 186 | #type { |
| 186 | − font-size: 10.5pt; | |
| 187 | + font-size: 9.0pt; | |
| 187 | 188 | } |
| 188 | 189 | |
| 189 | 190 | #type label { |
| @@ -191,14 +192,14 @@ input { · 1 unmodified line | ||
| 191 | 192 | } |
| 192 | 193 | |
| 193 | 194 | input, textarea { |
| 194 | − background-color: rgb(102, 102, 102); | |
| 195 | − color: rgb(204, 204, 204); | |
| 195 | + background-color: rgb(63, 63, 63); | |
| 196 | + color: rgb(255, 255, 255); | |
| 196 | 197 | border: none; |
| 197 | − font-size: 7.5pt; | |
| 198 | + font-size: 9pt; | |
| 198 | 199 | } |
| 199 | 200 | |
| 200 | 201 | input:disabled, textarea:disabled { |
| 201 | − background-color: rgb(102, 102, 102); | |
| 202 | + background-color: rgb(63, 63, 63); | |
| 202 | 203 | color: rgb(160, 160, 160); |
| 203 | 204 | } |
| 204 | 205 | |
| @@ -224,7 +225,7 @@ input:disabled, textarea:disabled { · 19 unmodified lines | ||
| 224 | 225 | #properties-list .property { |
| 225 | 226 | padding: 4pt; |
| 226 | 227 | border-bottom: 0.75pt solid rgb(63, 63, 63); |
| 227 | − min-height: 1em; | |
| 228 | + min-height: 12pt; | |
| 228 | 229 | } |
| 229 | 230 | |
| 230 | 231 | |
| @@ -245,7 +246,6 @@ table#properties-list { · 14 unmodified lines | ||
| 245 | 246 | font-weight: bold; |
| 246 | 247 | overflow: hidden; |
| 247 | 248 | text-overflow: ellipsis; |
| 248 | − | |
| 249 | 249 | vertical-align: middle; |
| 250 | 250 | height: 1.2em; |
| 251 | 251 | } |
| @@ -270,9 +270,7 @@ div.inner { · 18 unmodified lines | ||
| 270 | 270 | } |
| 271 | 271 | |
| 272 | 272 | td { |
| 273 | − | |
| 274 | − | |
| 275 | − vertical-align: top; | |
| 273 | + vertical-align: top; | |
| 276 | 274 | } |
| 277 | 275 | |
| 278 | 276 | #no-entities { |
| @@ -126,7 +126,7 @@ Tool.prototype = new Overlay2D; · 125 unmodified lines | ||
| 126 | 126 | Tool.IMAGE_HEIGHT = 50; |
| 127 | 127 | Tool.IMAGE_WIDTH = 50; |
| 128 | 128 | |
| 129 | −ToolBar = function(x, y, direction) { | |
| 129 | +ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPositionFunction) { | |
| 130 | 130 | this.tools = new Array(); |
| 131 | 131 | this.x = x; |
| 132 | 132 | this.y = y; |
| @@ -336,7 +336,7 @@ ToolBar = function(x, y, direction) { · 203 unmodified lines | ||
| 336 | 336 | return (that.x <= x) && (x <= (that.x + that.width)) && |
| 337 | 337 | (that.y <= y) && (y <= (that.y + that.height)); |
| 338 | 338 | } |
| 339 | − that.hover = function (enable) { | |
| 339 | + that.hover = function (enable) { // Can be overriden or extended by clients. | |
| 340 | 340 | that.isHovering = enable; |
| 341 | 341 | if (that.back) { |
| 342 | 342 | if (enable) { |
| @@ -348,6 +348,26 @@ ToolBar = function(x, y, direction) { · 5 unmodified lines | ||
| 348 | 348 | }); |
| 349 | 349 | } |
| 350 | 350 | }; |
| 351 | + that.windowDimensions = Controller.getViewportDimensions(); | |
| 352 | + // Maybe fixme: Keeping the same percent of the window size isn't always the right thing. | |
| 353 | + // For example, maybe we want "keep the same percentage to whatever two edges are closest to the edge of screen". | |
| 354 | + // If we change that, the places to do so are onResizeViewport, save (maybe), and the initial move based on Settings, below. | |
| 355 | + that.onResizeViewport = function (newSize) { // Can be overridden or extended by clients. | |
| 356 | + var fractionX = that.x / that.windowDimensions.x; | |
| 357 | + var fractionY = that.y / that.windowDimensions.y; | |
| 358 | + that.windowDimensions = newSize || Controller.getViewportDimensions(); | |
| 359 | + that.move(fractionX * that.windowDimensions.x, fractionY * that.windowDimensions.y); | |
| 360 | + }; | |
| 361 | + if (optionalPersistenceKey) { | |
| 362 | + this.fractionKey = optionalPersistenceKey + '.fraction'; | |
| 363 | + this.save = function () { | |
| 364 | + var screenSize = Controller.getViewportDimensions(); | |
| 365 | + var fraction = {x: that.x / screenSize.x, y: that.y / screenSize.y}; | |
| 366 | + Settings.setValue(this.fractionKey, JSON.stringify(fraction)); | |
| 367 | + } | |
| 368 | + } else { | |
| 369 | + this.save = function () { }; // Called on move. Can be overriden or extended by clients. | |
| 370 | + } | |
| 351 | 371 | // These are currently only doing that which is necessary for toolbar hover and toolbar drag. |
| 352 | 372 | // They have not yet been extended to tool hover/click/release, etc. |
| 353 | 373 | this.mousePressEvent = function (event) { |
| @@ -375,15 +395,19 @@ ToolBar = function(x, y, direction) { · 21 unmodified lines | ||
| 375 | 395 | } |
| 376 | 396 | that.move(that.dragOffsetX + event.x, that.dragOffsetY + event.y); |
| 377 | 397 | }; |
| 398 | + that.checkResize = function () { // Can be overriden or extended, but usually not. See onResizeViewport. | |
| 399 | + var currentWindowSize = Controller.getViewportDimensions(); | |
| 400 | + if ((currentWindowSize.x !== that.windowDimensions.x) || (currentWindowSize.y !== that.windowDimensions.y)) { | |
| 401 | + that.onResizeViewport(currentWindowSize); | |
| 402 | + } | |
| 403 | + }; | |
| 378 | 404 | Controller.mousePressEvent.connect(this.mousePressEvent); |
| 379 | 405 | Controller.mouseMoveEvent.connect(this.mouseMove); |
| 380 | − // Called on move. A different approach would be to have all this on the prototype, | |
| 381 | − // and let apps extend where needed. Ex. app defines its toolbar.move() to call this.__proto__.move and then save. | |
| 382 | − this.save = function () { }; | |
| 406 | + Script.update.connect(that.checkResize); | |
| 383 | 407 | // This compatability hack breaks the model, but makes converting existing scripts easier: |
| 384 | 408 | this.addOverlay = function (ignored, oldSchoolProperties) { |
| 385 | 409 | var properties = JSON.parse(JSON.stringify(oldSchoolProperties)); // a copy |
| 386 | − if (that.numberOfTools() === 0) { | |
| 410 | + if ((that.numberOfTools() === 0) && (properties.x != undefined) && (properties.y != undefined)) { | |
| 387 | 411 | that.move(properties.x, properties.y); |
| 388 | 412 | } |
| 389 | 413 | delete properties.x; |
| @@ -392,6 +416,23 @@ ToolBar = function(x, y, direction) { · 2 unmodified lines | ||
| 392 | 416 | var id = that.tools[index].overlay(); |
| 393 | 417 | return id; |
| 394 | 418 | } |
| 419 | + if (this.fractionKey || optionalInitialPositionFunction) { | |
| 420 | + var savedFraction = JSON.parse(Settings.getValue(this.fractionKey) || '0'); // getValue can answer empty string | |
| 421 | + var screenSize = Controller.getViewportDimensions(); | |
| 422 | + if (savedFraction) { | |
| 423 | + // If we have saved data, keep the toolbar at the same proportion of the screen width/height. | |
| 424 | + that.move(savedFraction.x * screenSize.x, savedFraction.y * screenSize.y); | |
| 425 | + } else if (!optionalInitialPositionFunction) { | |
| 426 | + print("No initPosition(screenSize, intializedToolbar) specified for ToolBar"); | |
| 427 | + } else { | |
| 428 | + // Call the optionalInitialPositionFunctinon() AFTER the client has had a chance to set up. | |
| 429 | + var that = this; | |
| 430 | + Script.setTimeout(function () { | |
| 431 | + var position = optionalInitialPositionFunction(screenSize, that); | |
| 432 | + that.move(position.x, position.y); | |
| 433 | + }, 0); | |
| 434 | + } | |
| 435 | + } | |
| 395 | 436 | } |
| 396 | 437 | ToolBar.SPACING = 4; |
| 397 | 438 | ToolBar.VERTICAL = 0; |
| @@ -9,8 +9,6 @@ · 8 unmodified lines | ||
| 9 | 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html |
| 10 | 10 | // |
| 11 | 11 | |
| 12 | −HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; | |
| 13 | − | |
| 14 | 12 | var lastX = Window.getCursorPositionX(); |
| 15 | 13 | var lastY = Window.getCursorPositionY(); |
| 16 | 14 | var yawFromMouse = 0; |
| @@ -46,6 +44,28 @@ var mouseLook = (function () { · 29 unmodified lines | ||
| 46 | 44 | } |
| 47 | 45 | } |
| 48 | 46 | |
| 47 | + function findInput(name) { | |
| 48 | + var availableInputs = Controller.getAvailableInputs(keyboardID); | |
| 49 | + for (i = 0; i < availableInputs.length; i++) { | |
| 50 | + if (availableInputs[i].inputName == name) { | |
| 51 | + return availableInputs[i].input; | |
| 52 | + } | |
| 53 | + } | |
| 54 | + // If the input isn't found, it will default to the first available input | |
| 55 | + return availableInputs[0].input; | |
| 56 | + } | |
| 57 | + | |
| 58 | + function findAction(name) { | |
| 59 | + var actions = Controller.getAllActions(); | |
| 60 | + for (var i = 0; i < actions.length; i++) { | |
| 61 | + if (actions[i].actionName == name) { | |
| 62 | + return i; | |
| 63 | + } | |
| 64 | + } | |
| 65 | + // If the action isn't found, it will default to the first available action | |
| 66 | + return 0; | |
| 67 | + } | |
| 68 | + | |
| 49 | 69 | function updateMapping() { |
| 50 | 70 | if (keyboardID != 0) { |
| 51 | 71 | if (active) { |
| @@ -55,41 +75,40 @@ var mouseLook = (function () { · 3 unmodified lines | ||
| 55 | 75 | yawSpeed = 0; |
| 56 | 76 | pitchSpeed = 0; |
| 57 | 77 | |
| 58 | − var a = Controller.getAvailableInputs(keyboardID)[10].input.channel; | |
| 59 | − var d = Controller.getAvailableInputs(keyboardID)[13].input.channel; | |
| 60 | − var left = Controller.getAvailableInputs(keyboardID)[36].input.channel; | |
| 61 | − var right = Controller.getAvailableInputs(keyboardID)[38].input.channel; | |
| 62 | − var shift = Controller.getAvailableInputs(keyboardID)[41].input.channel; | |
| 78 | + var a = findInput("A").channel; | |
| 79 | + var d = findInput("D").channel; | |
| 80 | + var left = findInput("Left").channel; | |
| 81 | + var right = findInput("Right").channel; | |
| 82 | + var shift = findInput("Shift").channel; | |
| 63 | 83 | |
| 64 | − for (i = 6; i <= 9; i++) { | |
| 84 | + for (var i = findAction("YAW_LEFT"); i <= findAction("YAW_RIGHT"); i++) { | |
| 65 | 85 | var inputChannels = Controller.getAllActions()[i].inputChannels; |
| 66 | − for (j = 0; j < inputChannels.length; j++) { | |
| 86 | + for (var j = 0; j < inputChannels.length; j++) { | |
| 67 | 87 | var inputChannel = inputChannels[j]; |
| 68 | − | |
| 69 | 88 | // make a, d, left, and right strafe |
| 70 | 89 | if ((inputChannel.input.channel == a || inputChannel.input.channel == left) && inputChannel.modifier.device == 0) { |
| 71 | 90 | Controller.removeInputChannel(inputChannel); |
| 72 | − inputChannel.action = 2; | |
| 91 | + inputChannel.action = findAction("LATERAL_LEFT"); | |
| 73 | 92 | Controller.addInputChannel(inputChannel); |
| 74 | 93 | } else if ((inputChannel.input.channel == d || inputChannel.input.channel == right) && inputChannel.modifier.device == 0) { |
| 75 | 94 | Controller.removeInputChannel(inputChannel); |
| 76 | − inputChannel.action = 3; | |
| 95 | + inputChannel.action = findAction("LATERAL_RIGHT"); | |
| 77 | 96 | Controller.addInputChannel(inputChannel); |
| 78 | 97 | } |
| 79 | 98 | } |
| 80 | 99 | } |
| 81 | − // make shift + a/d/left/right change yaw/pitch | |
| 82 | − for (i = 2; i <= 3; i++) { | |
| 100 | + for (var i = findAction("LATERAL_LEFT"); i <= findAction("LATERAL_RIGHT"); i++) { | |
| 83 | 101 | var inputChannels = Controller.getAllActions()[i].inputChannels; |
| 84 | − for (j = 0; j < inputChannels.length; j++) { | |
| 102 | + for (var j = 0; j < inputChannels.length; j++) { | |
| 85 | 103 | var inputChannel = inputChannels[j]; |
| 104 | + // make shift + a/d/left/right change yaw/pitch | |
| 86 | 105 | if ((inputChannel.input.channel == a || inputChannel.input.channel == left) && inputChannel.modifier.channel == shift) { |
| 87 | 106 | Controller.removeInputChannel(inputChannel); |
| 88 | − inputChannel.action = 6; | |
| 107 | + inputChannel.action = findAction("YAW_LEFT"); | |
| 89 | 108 | Controller.addInputChannel(inputChannel); |
| 90 | 109 | } else if ((inputChannel.input.channel == d || inputChannel.input.channel == right) && inputChannel.modifier.channel == shift) { |
| 91 | 110 | Controller.removeInputChannel(inputChannel); |
| 92 | − inputChannel.action = 7; | |
| 111 | + inputChannel.action = findAction("YAW_RIGHT"); | |
| 93 | 112 | Controller.addInputChannel(inputChannel); |
| 94 | 113 | } |
| 95 | 114 | } |
| @@ -134,8 +153,8 @@ var mouseLook = (function () { · 38 unmodified lines | ||
| 134 | 153 | } |
| 135 | 154 | |
| 136 | 155 | function resetCursorPosition() { |
| 137 | − var newX = Window.x + Window.innerWidth / 2; | |
| 138 | − var newY = Window.y + Window.innerHeight / 2; | |
| 156 | + var newX = Window.x + Window.innerWidth / 2.0; | |
| 157 | + var newY = Window.y + Window.innerHeight / 2.0; | |
| 139 | 158 | Window.setCursorPosition(newX, newY); |
| 140 | 159 | lastX = newX; |
| 141 | 160 | lastY = newY; |
| @@ -10,17 +10,16 @@ · 9 unmodified lines | ||
| 10 | 10 | // |
| 11 | 11 | // Distributed under the Apache License, Version 2.0. |
| 12 | 12 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html |
| 13 | −// | |
| 14 | −Script.include('lineRider.js') | |
| 15 | −var MAX_POINTS_PER_LINE = 30; | |
| 16 | −var LINE_LIFETIME = 60 * 5 //5 minute lifetime | |
| 13 | + | |
| 14 | +var LINE_DIMENSIONS = 5; | |
| 15 | +var LIFETIME = 6000; | |
| 17 | 16 | |
| 18 | 17 | var colorPalette = [{ |
| 19 | 18 | red: 236, |
| 20 | 19 | green: 208, |
| 21 | 20 | blue: 120 |
| 22 | 21 | }, { |
| 23 | − red: 217, | |
| 22 | + red: 214, | |
| 24 | 23 | green: 91, |
| 25 | 24 | blue: 67 |
| 26 | 25 | }, { |
| @@ -40,15 +39,6 @@ var colorPalette = [{ · 13 unmodified lines | ||
| 40 | 39 | var currentColorIndex = 0; |
| 41 | 40 | var currentColor = colorPalette[currentColorIndex]; |
| 42 | 41 | |
| 43 | − | |
| 44 | − | |
| 45 | −if (hydraCheck() === true) { | |
| 46 | − HydraPaint(); | |
| 47 | −} else { | |
| 48 | − MousePaint(); | |
| 49 | −} | |
| 50 | − | |
| 51 | − | |
| 52 | 42 | function cycleColor() { |
| 53 | 43 | currentColor = colorPalette[++currentColorIndex]; |
| 54 | 44 | if (currentColorIndex === colorPalette.length - 1) { |
| @@ -57,42 +47,17 @@ function cycleColor() { · 2 unmodified lines | ||
| 57 | 47 | |
| 58 | 48 | } |
| 59 | 49 | |
| 60 | −function hydraCheck() { | |
| 61 | − var numberOfButtons = Controller.getNumberOfButtons(); | |
| 62 | − var numberOfTriggers = Controller.getNumberOfTriggers(); | |
| 63 | − var numberOfSpatialControls = Controller.getNumberOfSpatialControls(); | |
| 64 | − var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers; | |
| 65 | − hydrasConnected = (numberOfButtons == 12 && numberOfTriggers == 2 && controllersPerTrigger == 2); | |
| 66 | − return hydrasConnected; //hydrasConnected; | |
| 67 | −} | |
| 68 | − | |
| 69 | −//************ Mouse Paint ************************** | |
| 50 | +MousePaint(); | |
| 70 | 51 | |
| 71 | 52 | function MousePaint() { |
| 72 | − var DRAWING_DISTANCE = 2; | |
| 53 | + var DRAWING_DISTANCE = 5; | |
| 73 | 54 | var lines = []; |
| 74 | − var deletedLines = []; | |
| 75 | 55 | var isDrawing = false; |
| 76 | − var path = []; | |
| 77 | − | |
| 78 | − var lineRider = new LineRider(); | |
| 79 | − lineRider.addStartHandler(function() { | |
| 80 | − var points = []; | |
| 81 | − //create points array from list of all points in path | |
| 82 | − path.forEach(function(point) { | |
| 83 | − points.push(point); | |
| 84 | − }); | |
| 85 | − lineRider.setPath(points); | |
| 86 | − }); | |
| 87 | − | |
| 88 | − | |
| 89 | 56 | |
| 90 | 57 | var LINE_WIDTH = 7; |
| 91 | − var line; | |
| 92 | − var points = []; | |
| 93 | − | |
| 58 | + var line, linePosition; | |
| 94 | 59 | |
| 95 | − var BRUSH_SIZE = 0.02; | |
| 60 | + var BRUSH_SIZE = .05; | |
| 96 | 61 | |
| 97 | 62 | var brush = Entities.addEntity({ |
| 98 | 63 | type: 'Sphere', |
| @@ -110,51 +75,42 @@ function MousePaint() { · 11 unmodified lines | ||
| 110 | 75 | }); |
| 111 | 76 | |
| 112 | 77 | |
| 113 | − function newLine(point) { | |
| 78 | + function newLine(position) { | |
| 79 | + linePosition = position; | |
| 114 | 80 | line = Entities.addEntity({ |
| 115 | − position: MyAvatar.position, | |
| 81 | + position: position, | |
| 116 | 82 | type: "Line", |
| 117 | 83 | color: currentColor, |
| 118 | 84 | dimensions: { |
| 119 | − x: 10, | |
| 120 | − y: 10, | |
| 121 | − z: 10 | |
| 85 | + x: LINE_DIMENSIONS, | |
| 86 | + y: LINE_DIMENSIONS, | |
| 87 | + z: LINE_DIMENSIONS | |
| 122 | 88 | }, |
| 89 | + linePoints: [], | |
| 123 | 90 | lineWidth: LINE_WIDTH, |
| 124 | − lifetime: LINE_LIFETIME | |
| 91 | + lifetime: LIFETIME | |
| 125 | 92 | }); |
| 126 | − points = []; | |
| 127 | − if (point) { | |
| 128 | − | |
| 129 | − points.push(point); | |
| 130 | − path.push(point); | |
| 131 | − } | |
| 132 | 93 | lines.push(line); |
| 133 | 94 | } |
| 134 | 95 | |
| 135 | 96 | |
| 136 | 97 | function mouseMoveEvent(event) { |
| 137 | 98 | |
| 99 | + var worldPoint = computeWorldPoint(event); | |
| 100 | + Entities.editEntity(brush, { | |
| 101 | + position: worldPoint | |
| 102 | + }); | |
| 103 | + | |
| 138 | 104 | if (!isDrawing) { |
| 139 | 105 | return; |
| 140 | 106 | } |
| 141 | 107 | |
| 142 | − var pickRay = Camera.computePickRay(event.x, event.y); | |
| 143 | − var addVector = Vec3.multiply(Vec3.normalize(pickRay.direction), DRAWING_DISTANCE); | |
| 144 | − var point = Vec3.sum(Camera.getPosition(), addVector); | |
| 145 | − points.push(point); | |
| 146 | − path.push(point); | |
| 147 | − Entities.editEntity(line, { | |
| 148 | − linePoints: points | |
| 149 | − }); | |
| 150 | − Entities.editEntity(brush, { | |
| 151 | − position: point | |
| 152 | − }); | |
| 153 | − | |
| 108 | + var localPoint = computeLocalPoint(event) | |
| 109 | + var success = Entities.appendPoint(line, localPoint); | |
| 154 | 110 | |
| 155 | − if (points.length === MAX_POINTS_PER_LINE) { | |
| 156 | − //We need to start a new line! | |
| 157 | − newLine(point); | |
| 111 | + if (!success) { | |
| 112 | + newLine(worldPoint); | |
| 113 | + Entities.appendPoint(line, computeLocalPoint(event)); | |
| 158 | 114 | } |
| 159 | 115 | } |
| 160 | 116 | |
| @@ -171,17 +127,26 @@ function MousePaint() { · 10 unmodified lines | ||
| 171 | 127 | lines.push(restoredLine); |
| 172 | 128 | } |
| 173 | 129 | |
| 130 | + function computeWorldPoint(event) { | |
| 131 | + var pickRay = Camera.computePickRay(event.x, event.y); | |
| 132 | + var addVector = Vec3.multiply(Vec3.normalize(pickRay.direction), DRAWING_DISTANCE); | |
| 133 | + return Vec3.sum(Camera.getPosition(), addVector); | |
| 134 | + } | |
| 135 | + | |
| 136 | + function computeLocalPoint(event) { | |
| 137 | + | |
| 138 | + var localPoint = Vec3.subtract(computeWorldPoint(event), linePosition); | |
| 139 | + return localPoint; | |
| 140 | + } | |
| 141 | + | |
| 174 | 142 | function mousePressEvent(event) { |
| 175 | − if(!event.isLeftButton) { | |
| 143 | + if (!event.isLeftButton) { | |
| 176 | 144 | isDrawing = false; |
| 177 | 145 | return; |
| 178 | 146 | } |
| 179 | − lineRider.mousePressEvent(event); | |
| 180 | − path = []; | |
| 181 | − newLine(); | |
| 147 | + newLine(computeWorldPoint(event)); | |
| 182 | 148 | isDrawing = true; |
| 183 | 149 | |
| 184 | − | |
| 185 | 150 | } |
| 186 | 151 | |
| 187 | 152 | function mouseReleaseEvent() { |
| @@ -198,21 +163,21 @@ function MousePaint() { · 10 unmodified lines | ||
| 198 | 163 | if (event.text === "z") { |
| 199 | 164 | undoStroke(); |
| 200 | 165 | } |
| 201 | − if(event.text === "x") { | |
| 166 | + if (event.text === "x") { | |
| 202 | 167 | redoStroke(); |
| 203 | 168 | } |
| 204 | 169 | } |
| 205 | 170 | |
| 171 | + | |
| 172 | + | |
| 206 | 173 | function cleanup() { |
| 207 | 174 | lines.forEach(function(line) { |
| 208 | − Entities.deleteEntity(line); | |
| 175 | + // Entities.deleteEntity(line); | |
| 209 | 176 | }); |
| 210 | 177 | Entities.deleteEntity(brush); |
| 211 | − lineRider.cleanup(); | |
| 212 | 178 | |
| 213 | 179 | } |
| 214 | 180 | |
| 215 | − | |
| 216 | 181 | Controller.mousePressEvent.connect(mousePressEvent); |
| 217 | 182 | Controller.mouseReleaseEvent.connect(mouseReleaseEvent); |
| 218 | 183 | Controller.mouseMoveEvent.connect(mouseMoveEvent); |
| @@ -222,266 +187,6 @@ function MousePaint() { · 3 unmodified lines | ||
| 222 | 187 | } |
| 223 | 188 | |
| 224 | 189 | |
| 225 | − | |
| 226 | −//*****************HYDRA PAINT ******************************************* | |
| 227 | − | |
| 228 | − | |
| 229 | − | |
| 230 | −function HydraPaint() { | |
| 231 | − | |
| 232 | − | |
| 233 | − | |
| 234 | − var lineRider = new LineRider(); | |
| 235 | − lineRider.addStartHandler(function() { | |
| 236 | − var points = []; | |
| 237 | − //create points array from list of all points in path | |
| 238 | − rightController.path.forEach(function(point) { | |
| 239 | − points.push(point); | |
| 240 | − }); | |
| 241 | − lineRider.setPath(points); | |
| 242 | − }); | |
| 243 | − | |
| 244 | − var LEFT = 0; | |
| 245 | − var RIGHT = 1; | |
| 246 | − | |
| 247 | − var currentTime = 0; | |
| 248 | − | |
| 249 | − | |
| 250 | − var minBrushSize = .02; | |
| 251 | − var maxBrushSize = .04 | |
| 252 | − | |
| 253 | − | |
| 254 | − var minLineWidth = 5; | |
| 255 | − var maxLineWidth = 10; | |
| 256 | − var currentLineWidth = minLineWidth; | |
| 257 | − var MIN_PAINT_TRIGGER_THRESHOLD = .01; | |
| 258 | − var COLOR_CHANGE_TIME_FACTOR = 0.1; | |
| 259 | − | |
| 260 | − var RIGHT_BUTTON_1 = 7 | |
| 261 | − var RIGHT_BUTTON_2 = 8 | |
| 262 | − var RIGHT_BUTTON_3 = 9; | |
| 263 | − var RIGHT_BUTTON_4 = 10 | |
| 264 | − | |
| 265 | − var LEFT_BUTTON_1 = 1; | |
| 266 | − var LEFT_BUTTON_2 = 2; | |
| 267 | − var LEFT_BUTTON_3 = 3; | |
| 268 | − var LEFT_BUTTON_4 = 4; | |
| 269 | − | |
| 270 | − var STROKE_SMOOTH_FACTOR = 1; | |
| 271 | − | |
| 272 | − var MIN_DRAW_DISTANCE = 0.2; | |
| 273 | − var MAX_DRAW_DISTANCE = 0.4; | |
| 274 | − | |
| 275 | − function controller(side, undoButton, redoButton, cycleColorButton, startRideButton) { | |
| 276 | − this.triggerHeld = false; | |
| 277 | − this.triggerThreshold = 0.9; | |
| 278 | − this.side = side; | |
| 279 | − this.palm = 2 * side; | |
| 280 | − this.tip = 2 * side + 1; | |
| 281 | − this.trigger = side; | |
| 282 | − this.lines = []; | |
| 283 | − this.deletedLines = [] //just an array of properties objects | |
| 284 | − this.isPainting = false; | |
| 285 | − | |
| 286 | − this.undoButton = undoButton; | |
| 287 | − this.undoButtonPressed = false; | |
| 288 | − this.prevUndoButtonPressed = false; | |
| 289 | − | |
| 290 | − this.redoButton = redoButton; | |
| 291 | − this.redoButtonPressed = false; | |
| 292 | − this.prevRedoButtonPressed = false; | |
| 293 | − | |
| 294 | − this.cycleColorButton = cycleColorButton; | |
| 295 | − this.cycleColorButtonPressed = false; | |
| 296 | − this.prevColorCycleButtonPressed = false; | |
| 297 | − | |
| 298 | − this.startRideButton = startRideButton; | |
| 299 | − this.startRideButtonPressed = false; | |
| 300 | − this.prevStartRideButtonPressed = false; | |
| 301 | − | |
| 302 | − this.strokeCount = 0; | |
| 303 | − this.currentBrushSize = minBrushSize; | |
| 304 | − this.points = []; | |
| 305 | − this.path = []; | |
| 306 | − | |
| 307 | − this.brush = Entities.addEntity({ | |
| 308 | − type: 'Sphere', | |
| 309 | − position: { | |
| 310 | − x: 0, | |
| 311 | − y: 0, | |
| 312 | − z: 0 | |
| 313 | − }, | |
| 314 | − color: currentColor, | |
| 315 | − dimensions: { | |
| 316 | − x: minBrushSize, | |
| 317 | − y: minBrushSize, | |
| 318 | − z: minBrushSize | |
| 319 | − } | |
| 320 | − }); | |
| 321 | − | |
| 322 | − | |
| 323 | − this.newLine = function(point) { | |
| 324 | − this.line = Entities.addEntity({ | |
| 325 | − position: MyAvatar.position, | |
| 326 | − type: "Line", | |
| 327 | − color: currentColor, | |
| 328 | − dimensions: { | |
| 329 | − x: 10, | |
| 330 | − y: 10, | |
| 331 | − z: 10 | |
| 332 | − }, | |
| 333 | − lineWidth: 5, | |
| 334 | − lifetime: LINE_LIFETIME | |
| 335 | − }); | |
| 336 | − this.points = []; | |
| 337 | − if (point) { | |
| 338 | − this.points.push(point); | |
| 339 | − this.path.push(point); | |
| 340 | − } | |
| 341 | − this.lines.push(this.line); | |
| 342 | − } | |
| 343 | − | |
| 344 | − this.update = function(deltaTime) { | |
| 345 | − this.updateControllerState(); | |
| 346 | − this.avatarPalmOffset = Vec3.subtract(this.palmPosition, MyAvatar.position); | |
| 347 | − this.projectedForwardDistance = Vec3.dot(Quat.getFront(Camera.getOrientation()), this.avatarPalmOffset); | |
| 348 | − this.mappedPalmOffset = map(this.projectedForwardDistance, -.5, .5, MIN_DRAW_DISTANCE, MAX_DRAW_DISTANCE); | |
| 349 | − this.tipDirection = Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)); | |
| 350 | − this.offsetVector = Vec3.multiply(this.mappedPalmOffset, this.tipDirection); | |
| 351 | − this.drawPoint = Vec3.sum(this.palmPosition, this.offsetVector); | |
| 352 | − this.currentBrushSize = map(this.triggerValue, 0, 1, minBrushSize, maxBrushSize); | |
| 353 | − Entities.editEntity(this.brush, { | |
| 354 | − position: this.drawPoint, | |
| 355 | − dimensions: { | |
| 356 | − x: this.currentBrushSize, | |
| 357 | − y: this.currentBrushSize, | |
| 358 | − z: this.currentBrushSize | |
| 359 | − }, | |
| 360 | − color: currentColor | |
| 361 | − }); | |
| 362 | − if (this.triggerValue > MIN_PAINT_TRIGGER_THRESHOLD) { | |
| 363 | − if (!this.isPainting) { | |
| 364 | − this.isPainting = true; | |
| 365 | − this.newLine(); | |
| 366 | − this.path = []; | |
| 367 | − } | |
| 368 | − if (this.strokeCount % STROKE_SMOOTH_FACTOR === 0) { | |
| 369 | − this.paint(this.drawPoint); | |
| 370 | − } | |
| 371 | − this.strokeCount++; | |
| 372 | − } else if (this.triggerValue < MIN_PAINT_TRIGGER_THRESHOLD && this.isPainting) { | |
| 373 | − this.releaseTrigger(); | |
| 374 | − } | |
| 375 | − | |
| 376 | − this.oldPalmPosition = this.palmPosition; | |
| 377 | − this.oldTipPosition = this.tipPosition; | |
| 378 | − } | |
| 379 | − | |
| 380 | − this.releaseTrigger = function() { | |
| 381 | − this.isPainting = false; | |
| 382 | − | |
| 383 | − } | |
| 384 | − | |
| 385 | − | |
| 386 | − this.updateControllerState = function() { | |
| 387 | − this.undoButtonPressed = Controller.isButtonPressed(this.undoButton); | |
| 388 | − this.redoButtonPressed = Controller.isButtonPressed(this.redoButton); | |
| 389 | − this.cycleColorButtonPressed = Controller.isButtonPressed(this.cycleColorButton); | |
| 390 | − this.startRideButtonPressed = Controller.isButtonPressed(this.startRideButton); | |
| 391 | − | |
| 392 | − //This logic gives us button release | |
| 393 | − if (this.prevUndoButtonPressed === true && this.undoButtonPressed === false) { | |
| 394 | − //User released undo button, so undo | |
| 395 | − this.undoStroke(); | |
| 396 | − } | |
| 397 | − if (this.prevRedoButtonPressed === true && this.redoButtonPressed === false) { | |
| 398 | − this.redoStroke(); | |
| 399 | − } | |
| 400 | − | |
| 401 | − if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) { | |
| 402 | − cycleColor(); | |
| 403 | − Entities.editEntity(this.brush, { | |
| 404 | − color: currentColor | |
| 405 | − }); | |
| 406 | − } | |
| 407 | − if (this.prevStartRideButtonPressed === true && this.startRideButtonPressed === false) { | |
| 408 | − lineRider.toggleRide(); | |
| 409 | − } | |
| 410 | − this.prevRedoButtonPressed = this.redoButtonPressed; | |
| 411 | − this.prevUndoButtonPressed = this.undoButtonPressed; | |
| 412 | − this.prevCycleColorButtonPressed = this.cycleColorButtonPressed; | |
| 413 | − this.prevStartRideButtonPressed = this.startRideButtonPressed; | |
| 414 | − | |
| 415 | − this.palmPosition = Controller.getSpatialControlPosition(this.palm); | |
| 416 | − this.tipPosition = Controller.getSpatialControlPosition(this.tip); | |
| 417 | − this.triggerValue = Controller.getTriggerValue(this.trigger); | |
| 418 | − } | |
| 419 | − | |
| 420 | − this.undoStroke = function() { | |
| 421 | − var deletedLine = this.lines.pop(); | |
| 422 | − var deletedLineProps = Entities.getEntityProperties(deletedLine); | |
| 423 | − this.deletedLines.push(deletedLineProps); | |
| 424 | − Entities.deleteEntity(deletedLine); | |
| 425 | − } | |
| 426 | − | |
| 427 | − this.redoStroke = function() { | |
| 428 | − var restoredLine = Entities.addEntity(this.deletedLines.pop()); | |
| 429 | − Entities.addEntity(restoredLine); | |
| 430 | − this.lines.push(restoredLine); | |
| 431 | − } | |
| 432 | − | |
| 433 | − this.paint = function(point) { | |
| 434 | − | |
| 435 | − currentLineWidth = map(this.triggerValue, 0, 1, minLineWidth, maxLineWidth); | |
| 436 | − this.points.push(point); | |
| 437 | − this.path.push(point); | |
| 438 | − Entities.editEntity(this.line, { | |
| 439 | − linePoints: this.points, | |
| 440 | − lineWidth: currentLineWidth, | |
| 441 | − }); | |
| 442 | − if (this.points.length > MAX_POINTS_PER_LINE) { | |
| 443 | − this.newLine(point); | |
| 444 | − } | |
| 445 | − } | |
| 446 | − | |
| 447 | − this.cleanup = function() { | |
| 448 | − Entities.deleteEntity(this.brush); | |
| 449 | − this.lines.forEach(function(line) { | |
| 450 | − Entities.deleteEntity(line); | |
| 451 | − }); | |
| 452 | − } | |
| 453 | − } | |
| 454 | − | |
| 455 | − function update(deltaTime) { | |
| 456 | − rightController.update(deltaTime); | |
| 457 | − leftController.update(deltaTime); | |
| 458 | − currentTime += deltaTime; | |
| 459 | − } | |
| 460 | − | |
| 461 | − function cleanup() { | |
| 462 | − rightController.cleanup(); | |
| 463 | − leftController.cleanup(); | |
| 464 | − lineRider.cleanup(); | |
| 465 | − } | |
| 466 | − | |
| 467 | − function mousePressEvent(event) { | |
| 468 | − lineRider.mousePressEvent(event); | |
| 469 | − } | |
| 470 | − | |
| 471 | − function vectorIsZero(v) { | |
| 472 | − return v.x === 0 && v.y === 0 && v.z === 0; | |
| 473 | − } | |
| 474 | − | |
| 475 | − | |
| 476 | − var rightController = new controller(RIGHT, RIGHT_BUTTON_3, RIGHT_BUTTON_4, RIGHT_BUTTON_1, RIGHT_BUTTON_2); | |
| 477 | − var leftController = new controller(LEFT, LEFT_BUTTON_3, LEFT_BUTTON_4, LEFT_BUTTON_1, LEFT_BUTTON_2); | |
| 478 | − | |
| 479 | − Script.update.connect(update); | |
| 480 | − Script.scriptEnding.connect(cleanup); | |
| 481 | − Controller.mousePressEvent.connect(mousePressEvent); | |
| 482 | − | |
| 483 | −} | |
| 484 | − | |
| 485 | 190 | function randFloat(low, high) { |
| 486 | 191 | return low + Math.random() * (high - low); |
| 487 | 192 | } |
| @@ -29,19 +29,13 @@ var buttonOnColor = { · 28 unmodified lines | ||
| 29 | 29 | }; |
| 30 | 30 | |
| 31 | 31 | HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; |
| 32 | −var screenSize = Controller.getViewportDimensions(); | |
| 33 | 32 | |
| 34 | 33 | var userCanPoint = false; |
| 35 | 34 | Script.include(["libraries/toolBars.js"]); |
| 36 | −const persistKey = "highfidelity.pointer.toolbar.position"; | |
| 37 | −var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL); | |
| 38 | −toolBar.save = function () { | |
| 39 | − Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y])); | |
| 40 | −}; | |
| 41 | −var old = JSON.parse(Settings.getValue(persistKey) || '0'); | |
| 35 | +var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.pointer.toolbar", function (screenSize) { | |
| 36 | + return {x: screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING, y: screenSize.y - (BUTTON_SIZE + PADDING)}, | |
| 37 | +}); | |
| 42 | 38 | var pointerButton = toolBar.addOverlay("image", { |
| 43 | − x: old ? old[0] : screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING, | |
| 44 | − y: old ? old[1] : screenSize.y - (BUTTON_SIZE + PADDING), | |
| 45 | 39 | width: BUTTON_SIZE, |
| 46 | 40 | height: BUTTON_SIZE, |
| 47 | 41 | imageURL: HIFI_PUBLIC_BUCKET + "images/laser.png", |
| @@ -22,10 +22,12 @@ Script.setTimeout(function() { · 21 unmodified lines | ||
| 22 | 22 | type: "Model", |
| 23 | 23 | modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.fbx", |
| 24 | 24 | compoundShapeURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.obj", |
| 25 | − dimensions: {x: .11, y: .11, z: .59}, | |
| 25 | + dimensions: {x: .11, y: .11, z: 1.0}, | |
| 26 | 26 | position: MyAvatar.getRightPalmPosition(), // initial position doesn't matter, as long as it's close |
| 27 | 27 | rotation: MyAvatar.orientation, |
| 28 | 28 | damping: .1, |
| 29 | + collisionSoundURL: "http://public.highfidelity.io/sounds/Collisions-hitsandslaps/67LCollision07.wav", | |
| 30 | + restitution: 0.01, | |
| 29 | 31 | collisionsWillMove: true |
| 30 | 32 | }); |
| 31 | 33 | actionID = Entities.addAction("hold", stickID, {relativePosition: {x: 0.0, y: 0.0, z: -0.9}, |
| @@ -9,48 +9,52 @@ · 8 unmodified lines | ||
| 9 | 9 | // Distributed under the Apache License, Version 2.0. |
| 10 | 10 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html |
| 11 | 11 | |
| 12 | −function hslToRgb(hslColor) { | |
| 13 | − var h = hslColor.hue; | |
| 14 | − var s = hslColor.sat; | |
| 15 | − var l = hslColor.light; | |
| 16 | − var r, g, b; | |
| 17 | − | |
| 18 | − if (s == 0) { | |
| 19 | − r = g = b = l; // achromatic | |
| 20 | − } else { | |
| 21 | − var hue2rgb = function hue2rgb(p, q, t) { | |
| 22 | − if (t < 0) t += 1; | |
| 23 | − if (t > 1) t -= 1; | |
| 24 | − if (t < 1 / 6) return p + (q - p) * 6 * t; | |
| 25 | − if (t < 1 / 2) return q; | |
| 26 | − if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; | |
| 27 | − return p; | |
| 28 | − } | |
| 29 | − | |
| 30 | − var q = l < 0.5 ? l * (1 + s) : l + s - l * s; | |
| 31 | − var p = 2 * l - q; | |
| 32 | − r = hue2rgb(p, q, h + 1 / 3); | |
| 33 | − g = hue2rgb(p, q, h); | |
| 34 | − b = hue2rgb(p, q, h - 1 / 3); | |
| 35 | − } | |
| 36 | 12 | |
| 37 | − return { | |
| 38 | − red: Math.round(r * 255), | |
| 39 | − green: Math.round(g * 255), | |
| 40 | − blue: Math.round(b * 255) | |
| 41 | − }; | |
| 42 | 13 | |
| 14 | +map = function(value, min1, max1, min2, max2) { | |
| 15 | + return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); | |
| 43 | 16 | } |
| 44 | 17 | |
| 45 | −function map(value, min1, max1, min2, max2) { | |
| 46 | − return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); | |
| 18 | +hslToRgb = function(hslColor) { | |
| 19 | + var h = hslColor.hue; | |
| 20 | + var s = hslColor.sat; | |
| 21 | + var l = hslColor.light; | |
| 22 | + var r, g, b; | |
| 23 | + | |
| 24 | + if (s == 0) { | |
| 25 | + r = g = b = l; // achromatic | |
| 26 | + } else { | |
| 27 | + var hue2rgb = function hue2rgb(p, q, t) { | |
| 28 | + if (t < 0) t += 1; | |
| 29 | + if (t > 1) t -= 1; | |
| 30 | + if (t < 1 / 6) return p + (q - p) * 6 * t; | |
| 31 | + if (t < 1 / 2) return q; | |
| 32 | + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; | |
| 33 | + return p; | |
| 34 | + } | |
| 35 | + | |
| 36 | + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; | |
| 37 | + var p = 2 * l - q; | |
| 38 | + r = hue2rgb(p, q, h + 1 / 3); | |
| 39 | + g = hue2rgb(p, q, h); | |
| 40 | + b = hue2rgb(p, q, h - 1 / 3); | |
| 41 | + } | |
| 42 | + | |
| 43 | + return { | |
| 44 | + red: Math.round(r * 255), | |
| 45 | + green: Math.round(g * 255), | |
| 46 | + blue: Math.round(b * 255) | |
| 47 | + }; | |
| 48 | + | |
| 47 | 49 | } |
| 48 | 50 | |
| 49 | −function randFloat(low, high) { | |
| 50 | − return low + Math.random() * (high - low); | |
| 51 | + | |
| 52 | + | |
| 53 | +randFloat = function(low, high) { | |
| 54 | + return low + Math.random() * (high - low); | |
| 51 | 55 | } |
| 52 | 56 | |
| 53 | 57 | |
| 54 | −function randInt(low, high) { | |
| 55 | − return Math.floor(randFloat(low, high)); | |
| 58 | +randInt = function(low, high) { | |
| 59 | + return Math.floor(randFloat(low, high)); | |
| 56 | 60 | } |
| @@ -120,6 +120,23 @@ Slider = function(x,y,width,thumbSize) { · 119 unmodified lines | ||
| 120 | 120 | |
| 121 | 121 | this.onValueChanged = function(value) {}; |
| 122 | 122 | |
| 123 | + this.setMaxValue = function(maxValue) { | |
| 124 | + if (this.maxValue == maxValue) { | |
| 125 | + return; | |
| 126 | + } | |
| 127 | + var currentVal = this.getValue(); | |
| 128 | + this.maxValue = maxValue; | |
| 129 | + this.setValue(currentVal); | |
| 130 | + } | |
| 131 | + this.setMinValue = function(minValue) { | |
| 132 | + if (this.minValue == minValue) { | |
| 133 | + return; | |
| 134 | + } | |
| 135 | + var currentVal = this.getValue(); | |
| 136 | + this.minValue = minValue; | |
| 137 | + this.setValue(currentVal); | |
| 138 | + } | |
| 139 | + | |
| 123 | 140 | this.destroy = function() { |
| 124 | 141 | Overlays.deleteOverlay(this.background); |
| 125 | 142 | Overlays.deleteOverlay(this.thumb); |
| @@ -613,6 +630,14 @@ Panel = function(x, y) { · 487 unmodified lines | ||
| 613 | 630 | return null; |
| 614 | 631 | } |
| 615 | 632 | |
| 633 | + this.getWidget = function(name) { | |
| 634 | + var item = this.items[name]; | |
| 635 | + if (item != null) { | |
| 636 | + return item.widget; | |
| 637 | + } | |
| 638 | + return null; | |
| 639 | + } | |
| 640 | + | |
| 616 | 641 | this.update = function(name) { |
| 617 | 642 | var item = this.items[name]; |
| 618 | 643 | if (item != null) { |
| @@ -10,25 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | |
| 11 | 11 | Script.include("cookies.js"); |
| 12 | 12 | |
| 13 | −var panel = new Panel(10, 400); | |
| 14 | − | |
| 15 | −panel.newCheckbox("Enable Cull Opaque", | |
| 16 | − function(value) { Scene.setEngineCullOpaque((value != 0)); }, | |
| 17 | − function() { return Scene.doEngineCullOpaque(); }, | |
| 18 | − function(value) { return (value); } | |
| 19 | −); | |
| 20 | − | |
| 21 | −panel.newCheckbox("Enable Sort Opaque", | |
| 22 | − function(value) { Scene.setEngineSortOpaque((value != 0)); }, | |
| 23 | − function() { return Scene.doEngineSortOpaque(); }, | |
| 24 | − function(value) { return (value); } | |
| 25 | −); | |
| 26 | − | |
| 27 | −panel.newCheckbox("Enable Render Opaque", | |
| 28 | − function(value) { Scene.setEngineRenderOpaque((value != 0)); }, | |
| 29 | − function() { return Scene.doEngineRenderOpaque(); }, | |
| 30 | − function(value) { return (value); } | |
| 31 | −); | |
| 13 | +var panel = new Panel(10, 800); | |
| 32 | 14 | |
| 33 | 15 | panel.newSlider("Num Feed Opaques", 0, 1000, |
| 34 | 16 | function(value) { }, |
| @@ -48,49 +30,70 @@ panel.newSlider("Max Drawn Opaques", -1, 1000, · 13 unmodified lines | ||
| 48 | 30 | function(value) { return (value); } |
| 49 | 31 | ); |
| 50 | 32 | |
| 51 | −panel.newCheckbox("Enable Cull Transparent", | |
| 52 | − function(value) { Scene.setEngineCullTransparent((value != 0)); }, | |
| 53 | − function() { return Scene.doEngineCullTransparent(); }, | |
| 33 | +panel.newSlider("Num Feed Transparents", 0, 100, | |
| 34 | + function(value) { }, | |
| 35 | + function() { return Scene.getEngineNumFeedTransparentItems(); }, | |
| 54 | 36 | function(value) { return (value); } |
| 55 | 37 | ); |
| 56 | 38 | |
| 57 | −panel.newCheckbox("Enable Sort Transparent", | |
| 58 | − function(value) { Scene.setEngineSortTransparent((value != 0)); }, | |
| 59 | − function() { return Scene.doEngineSortTransparent(); }, | |
| 39 | +panel.newSlider("Num Drawn Transparents", 0, 100, | |
| 40 | + function(value) { }, | |
| 41 | + function() { return Scene.getEngineNumDrawnTransparentItems(); }, | |
| 60 | 42 | function(value) { return (value); } |
| 61 | 43 | ); |
| 62 | 44 | |
| 63 | −panel.newCheckbox("Enable Render Transparent", | |
| 64 | − function(value) { Scene.setEngineRenderTransparent((value != 0)); }, | |
| 65 | − function() { return Scene.doEngineRenderTransparent(); }, | |
| 45 | +panel.newSlider("Max Drawn Transparents", -1, 100, | |
| 46 | + function(value) { Scene.setEngineMaxDrawnTransparentItems(value); }, | |
| 47 | + function() { return Scene.getEngineMaxDrawnTransparentItems(); }, | |
| 66 | 48 | function(value) { return (value); } |
| 67 | 49 | ); |
| 68 | 50 | |
| 69 | −panel.newSlider("Num Feed Transparents", 0, 100, | |
| 51 | +panel.newSlider("Num Feed Overlay3Ds", 0, 100, | |
| 70 | 52 | function(value) { }, |
| 71 | − function() { return Scene.getEngineNumFeedTransparentItems(); }, | |
| 53 | + function() { return Scene.getEngineNumFeedOverlay3DItems(); }, | |
| 72 | 54 | function(value) { return (value); } |
| 73 | 55 | ); |
| 74 | 56 | |
| 75 | −panel.newSlider("Num Drawn Transparents", 0, 100, | |
| 57 | +panel.newSlider("Num Drawn Overlay3Ds", 0, 100, | |
| 76 | 58 | function(value) { }, |
| 77 | − function() { return Scene.getEngineNumDrawnTransparentItems(); }, | |
| 59 | + function() { return Scene.getEngineNumDrawnOverlay3DItems(); }, | |
| 78 | 60 | function(value) { return (value); } |
| 79 | 61 | ); |
| 80 | 62 | |
| 81 | −panel.newSlider("Max Drawn Transparents", -1, 100, | |
| 82 | − function(value) { Scene.setEngineMaxDrawnTransparentItems(value); }, | |
| 83 | − function() { return Scene.getEngineMaxDrawnTransparentItems(); }, | |
| 63 | +panel.newSlider("Max Drawn Overlay3Ds", -1, 100, | |
| 64 | + function(value) { Scene.setEngineMaxDrawnOverlay3DItems(value); }, | |
| 65 | + function() { return Scene.getEngineMaxDrawnOverlay3DItems(); }, | |
| 84 | 66 | function(value) { return (value); } |
| 85 | 67 | ); |
| 86 | 68 | |
| 87 | 69 | var tickTackPeriod = 500; |
| 88 | 70 | |
| 89 | 71 | function updateCounters() { |
| 90 | − panel.set("Num Feed Opaques", panel.get("Num Feed Opaques")); | |
| 91 | − panel.set("Num Drawn Opaques", panel.get("Num Drawn Opaques")); | |
| 92 | − panel.set("Num Feed Transparents", panel.get("Num Feed Transparents")); | |
| 93 | − panel.set("Num Drawn Transparents", panel.get("Num Drawn Transparents")); | |
| 72 | + var numFeedOpaques = panel.get("Num Feed Opaques"); | |
| 73 | + var numFeedTransparents = panel.get("Num Feed Transparents"); | |
| 74 | + var numFeedOverlay3Ds = panel.get("Num Feed Overlay3Ds"); | |
| 75 | + | |
| 76 | + panel.set("Num Feed Opaques", numFeedOpaques); | |
| 77 | + panel.set("Num Drawn Opaques", panel.get("Num Drawn Opaques")); | |
| 78 | + panel.set("Num Feed Transparents", numFeedTransparents); | |
| 79 | + panel.set("Num Drawn Transparents", panel.get("Num Drawn Transparents")); | |
| 80 | + panel.set("Num Feed Overlay3Ds", numFeedOverlay3Ds); | |
| 81 | + panel.set("Num Drawn Overlay3Ds", panel.get("Num Drawn Overlay3Ds")); | |
| 82 | + | |
| 83 | + var numMax = Math.max(numFeedOpaques * 1.2, 1); | |
| 84 | + panel.getWidget("Num Feed Opaques").setMaxValue(numMax); | |
| 85 | + panel.getWidget("Num Drawn Opaques").setMaxValue(numMax); | |
| 86 | + panel.getWidget("Max Drawn Opaques").setMaxValue(numMax); | |
| 87 | + | |
| 88 | + numMax = Math.max(numFeedTransparents * 1.2, 1); | |
| 89 | + panel.getWidget("Num Feed Transparents").setMaxValue(numMax); | |
| 90 | + panel.getWidget("Num Drawn Transparents").setMaxValue(numMax); | |
| 91 | + panel.getWidget("Max Drawn Transparents").setMaxValue(numMax); | |
| 92 | + | |
| 93 | + numMax = Math.max(numFeedOverlay3Ds * 1.2, 1); | |
| 94 | + panel.getWidget("Num Feed Overlay3Ds").setMaxValue(numMax); | |
| 95 | + panel.getWidget("Num Drawn Overlay3Ds").setMaxValue(numMax); | |
| 96 | + panel.getWidget("Max Drawn Overlay3Ds").setMaxValue(numMax); | |
| 94 | 97 | } |
| 95 | 98 | Script.setInterval(updateCounters, tickTackPeriod); |
| 96 | 99 | |
| @@ -15,7 +15,7 @@ · 14 unmodified lines | ||
| 15 | 15 | viewBox="0 0 1440 200" |
| 16 | 16 | id="svg4136" |
| 17 | 17 | inkscape:version="0.91 r13725" |
| 18 | − sodipodi:docname="address-bar.svg"> | |
| 18 | + sodipodi:docname="address-bar.002.svg"> | |
| 19 | 19 | <metadata |
| 20 | 20 | id="metadata4144"> |
| 21 | 21 | <rdf:RDF> |
| @@ -39,14 +39,14 @@ · 17 unmodified lines | ||
| 39 | 39 | guidetolerance="10" |
| 40 | 40 | inkscape:pageopacity="0" |
| 41 | 41 | inkscape:pageshadow="2" |
| 42 | − inkscape:window-width="1840" | |
| 42 | + inkscape:window-width="1835" | |
| 43 | 43 | inkscape:window-height="1057" |
| 44 | 44 | id="namedview4140" |
| 45 | 45 | showgrid="false" |
| 46 | − inkscape:zoom="0.8671875" | |
| 47 | − inkscape:cx="707.02439" | |
| 46 | + inkscape:zoom="0.61319416" | |
| 47 | + inkscape:cx="132.58366" | |
| 48 | 48 | inkscape:cy="52.468468" |
| 49 | − inkscape:window-x="72" | |
| 49 | + inkscape:window-x="77" | |
| 50 | 50 | inkscape:window-y="-8" |
| 51 | 51 | inkscape:window-maximized="1" |
| 52 | 52 | inkscape:current-layer="svg4136" /> |
| @@ -59,6 +59,15 @@ · 6 unmodified lines | ||
| 59 | 59 | y="30" |
| 60 | 60 | rx="16.025024" |
| 61 | 61 | ry="17.019567" /> |
| 62 | + <rect | |
| 63 | + style="fill:#dadada;fill-opacity:1;stroke:#cbcbcb;stroke-width:0.33821851;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1" | |
| 64 | + id="rect4135" | |
| 65 | + width="292.86267" | |
| 66 | + height="139.66179" | |
| 67 | + x="150.32542" | |
| 68 | + y="30.169102" | |
| 69 | + rx="16.817432" | |
| 70 | + ry="20.612938" /> | |
| 62 | 71 | <circle |
| 63 | 72 | style="fill:#b8b8b8;fill-opacity:1;stroke:none;stroke-opacity:1" |
| 64 | 73 | id="path4146" |
| @@ -69,4 +78,11 @@ · 4 unmodified lines | ||
| 69 | 78 | d="m 100,36.000005 c -22.1,0 -40,17.9 -40,39.999995 0,30 40,88 40,88 0,0 40,-58 40,-88 0,-22.099995 -17.9,-39.999995 -40,-39.999995 z m 0,22 c 9.9,0 18,8.099995 18,17.999995 0,9.9 -8.1,18 -18,18 -9.9,0 -18,-8.1 -18,-18 0,-9.9 8.1,-17.999995 18,-17.999995 z" |
| 70 | 79 | id="path4138" |
| 71 | 80 | inkscape:connector-curvature="0" /> |
| 81 | + <rect | |
| 82 | + style="fill:#bdbdbd;fill-opacity:1;stroke:none;stroke-width:0.30000001;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1" | |
| 83 | + id="rect4136" | |
| 84 | + width="4" | |
| 85 | + height="100" | |
| 86 | + x="310.12924" | |
| 87 | + y="50" /> | |
| 72 | 88 | </svg> |
Binary file not shown.
| @@ -0,0 +1,50 @@ | ||
| 1 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |
| 2 | +<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> | |
| 3 | + | |
| 4 | +<svg | |
| 5 | + xmlns:dc="http://purl.org/dc/elements/1.1/" | |
| 6 | + xmlns:cc="http://creativecommons.org/ns#" | |
| 7 | + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |
| 8 | + xmlns:svg="http://www.w3.org/2000/svg" | |
| 9 | + xmlns="http://www.w3.org/2000/svg" | |
| 10 | + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |
| 11 | + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |
| 12 | + version="1.1" | |
| 13 | + id="Layer_1" | |
| 14 | + x="0px" | |
| 15 | + y="0px" | |
| 16 | + viewBox="133.1 714.2 21.3 33.4" | |
| 17 | + enable-background="new 133.1 714.2 21.3 33.4" | |
| 18 | + xml:space="preserve" | |
| 19 | + inkscape:version="0.91 r13725" | |
| 20 | + sodipodi:docname="left-arrow.svg"><metadata | |
| 21 | + id="metadata13"><rdf:RDF><cc:Work | |
| 22 | + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type | |
| 23 | + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs | |
| 24 | + id="defs11" /><sodipodi:namedview | |
| 25 | + pagecolor="#ffffff" | |
| 26 | + bordercolor="#666666" | |
| 27 | + borderopacity="1" | |
| 28 | + objecttolerance="10" | |
| 29 | + gridtolerance="10" | |
| 30 | + guidetolerance="10" | |
| 31 | + inkscape:pageopacity="0" | |
| 32 | + inkscape:pageshadow="2" | |
| 33 | + inkscape:window-width="1835" | |
| 34 | + inkscape:window-height="1057" | |
| 35 | + id="namedview9" | |
| 36 | + showgrid="false" | |
| 37 | + inkscape:zoom="7.0658679" | |
| 38 | + inkscape:cx="10.65" | |
| 39 | + inkscape:cy="16.700001" | |
| 40 | + inkscape:window-x="77" | |
| 41 | + inkscape:window-y="-8" | |
| 42 | + inkscape:window-maximized="1" | |
| 43 | + inkscape:current-layer="Layer_1" /><g | |
| 44 | + id="g3" | |
| 45 | + transform="matrix(-1,0,0,1,287.5,0)"><g | |
| 46 | + id="g5"><path | |
| 47 | + d="m 133.1,714.2 21.3,16.7 -21.3,16.7 0,-33.4 z" | |
| 48 | + id="path7" | |
| 49 | + inkscape:connector-curvature="0" | |
| 50 | + style="fill:#535353" /></g></g></svg> | |
| @@ -0,0 +1,11 @@ | ||
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> | |
| 3 | +<svg version="1.1" id="Layer_1" xmlns:xl="http://www.w3.org/1999/xlink" | |
| 4 | + xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="133.1 714.2 21.3 33.4" | |
| 5 | + enable-background="new 133.1 714.2 21.3 33.4" xml:space="preserve"> | |
| 6 | +<g> | |
| 7 | + <g> | |
| 8 | + <path fill="#FF5353" d="M133.1,714.2l21.3,16.7l-21.3,16.7V714.2z"/> | |
| 9 | + </g> | |
| 10 | +</g> | |
| 11 | +</svg> | |
| @@ -0,0 +1,11 @@ | ||
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> | |
| 3 | +<svg version="1.1" id="Layer_1" xmlns:xl="http://www.w3.org/1999/xlink" | |
| 4 | + xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="225.8 714.2 326.5 512" | |
| 5 | + enable-background="new 225.8 714.2 326.5 512" xml:space="preserve"> | |
| 6 | +<g> | |
| 7 | + <g> | |
| 8 | + <path fill="#FF5353" d="M552.4,1226.2l-326.5-256l326.5-256V1226.2z"/> | |
| 9 | + </g> | |
| 10 | +</g> | |
| 11 | +</svg> | |
| @@ -0,0 +1,11 @@ | ||
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> | |
| 3 | +<svg version="1.1" id="Layer_1" xmlns:xl="http://www.w3.org/1999/xlink" | |
| 4 | + xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="133.1 714.2 21.3 33.4" | |
| 5 | + enable-background="new 133.1 714.2 21.3 33.4" xml:space="preserve"> | |
| 6 | +<g> | |
| 7 | + <g> | |
| 8 | + <path fill="#535353" d="M133.1,714.2l21.3,16.7l-21.3,16.7V714.2z"/> | |
| 9 | + </g> | |
| 10 | +</g> | |
| 11 | +</svg> | |
| @@ -30,6 +30,7 @@ DialogContainer { · 29 unmodified lines | ||
| 30 | 30 | property int maximumX: parent ? parent.width - width : 0 |
| 31 | 31 | property int maximumY: parent ? parent.height - height : 0 |
| 32 | 32 | |
| 33 | + | |
| 33 | 34 | AddressBarDialog { |
| 34 | 35 | id: addressBarDialog |
| 35 | 36 | |
| @@ -45,28 +46,6 @@ DialogContainer { · 9 unmodified lines | ||
| 45 | 46 | property int inputAreaHeight: 56.0 * root.scale // Height of the background's input area |
| 46 | 47 | property int inputAreaStep: (height - inputAreaHeight) / 2 |
| 47 | 48 | |
| 48 | − TextInput { | |
| 49 | − id: addressLine | |
| 50 | − | |
| 51 | − anchors { | |
| 52 | − fill: parent | |
| 53 | − leftMargin: parent.height + hifi.layout.spacing * 2 | |
| 54 | − rightMargin: hifi.layout.spacing * 2 | |
| 55 | − topMargin: parent.inputAreaStep + hifi.layout.spacing | |
| 56 | − bottomMargin: parent.inputAreaStep + hifi.layout.spacing | |
| 57 | − | |
| 58 | − } | |
| 59 | − | |
| 60 | − font.pixelSize: hifi.fonts.pixelSize * root.scale | |
| 61 | − | |
| 62 | − helperText: "Go to: place, @user, /path, network address" | |
| 63 | − | |
| 64 | − onAccepted: { | |
| 65 | − event.accepted = true // Generates erroneous error in program log, "ReferenceError: event is not defined". | |
| 66 | − addressBarDialog.loadAddress(addressLine.text) | |
| 67 | − } | |
| 68 | − } | |
| 69 | − | |
| 70 | 49 | MouseArea { |
| 71 | 50 | // Drag the icon |
| 72 | 51 | width: parent.height |
| @@ -96,6 +75,73 @@ DialogContainer { · 23 unmodified lines | ||
| 96 | 75 | maximumY: root.parent ? root.maximumY + parent.inputAreaStep : 0 |
| 97 | 76 | } |
| 98 | 77 | } |
| 78 | + | |
| 79 | + Image { | |
| 80 | + id: backArrow | |
| 81 | + | |
| 82 | + source: addressBarDialog.backEnabled ? "../images/left-arrow.svg" : "../images/redarrow_reversed.svg" | |
| 83 | + | |
| 84 | + anchors { | |
| 85 | + fill: parent | |
| 86 | + leftMargin: parent.height + hifi.layout.spacing + 6 | |
| 87 | + rightMargin: parent.height + hifi.layout.spacing * 60 | |
| 88 | + topMargin: parent.inputAreaStep + parent.inputAreaStep + hifi.layout.spacing | |
| 89 | + bottomMargin: parent.inputAreaStep + parent.inputAreaStep + hifi.layout.spacing | |
| 90 | + } | |
| 91 | + | |
| 92 | + MouseArea { | |
| 93 | + anchors.fill: parent | |
| 94 | + acceptedButtons: Qt.LeftButton | |
| 95 | + onClicked: { | |
| 96 | + addressBarDialog.loadBack() | |
| 97 | + } | |
| 98 | + } | |
| 99 | + } | |
| 100 | + | |
| 101 | + Image { | |
| 102 | + id: forwardArrow | |
| 103 | + | |
| 104 | + source: addressBarDialog.forwardEnabled ? "../images/right-arrow.svg" : "../images/redarrow.svg" | |
| 105 | + | |
| 106 | + anchors { | |
| 107 | + fill: parent | |
| 108 | + leftMargin: parent.height + hifi.layout.spacing * 9 | |
| 109 | + rightMargin: parent.height + hifi.layout.spacing * 53 | |
| 110 | + topMargin: parent.inputAreaStep + parent.inputAreaStep + hifi.layout.spacing | |
| 111 | + bottomMargin: parent.inputAreaStep + parent.inputAreaStep + hifi.layout.spacing | |
| 112 | + } | |
| 113 | + | |
| 114 | + MouseArea { | |
| 115 | + anchors.fill: parent | |
| 116 | + acceptedButtons: Qt.LeftButton | |
| 117 | + onClicked: { | |
| 118 | + addressBarDialog.loadForward() | |
| 119 | + } | |
| 120 | + } | |
| 121 | + } | |
| 122 | + | |
| 123 | + TextInput { | |
| 124 | + id: addressLine | |
| 125 | + | |
| 126 | + anchors { | |
| 127 | + fill: parent | |
| 128 | + leftMargin: parent.height + parent.height + hifi.layout.spacing * 5 | |
| 129 | + rightMargin: hifi.layout.spacing * 2 | |
| 130 | + topMargin: parent.inputAreaStep + hifi.layout.spacing | |
| 131 | + bottomMargin: parent.inputAreaStep + hifi.layout.spacing | |
| 132 | + | |
| 133 | + } | |
| 134 | + | |
| 135 | + font.pixelSize: hifi.fonts.pixelSize * root.scale * 0.75 | |
| 136 | + | |
| 137 | + helperText: "Go to: place, @user, /path, network address" | |
| 138 | + | |
| 139 | + onAccepted: { | |
| 140 | + event.accepted = true // Generates erroneous error in program log, "ReferenceError: event is not defined". | |
| 141 | + addressBarDialog.loadAddress(addressLine.text) | |
| 142 | + } | |
| 143 | + } | |
| 144 | + | |
| 99 | 145 | } |
| 100 | 146 | } |
| 101 | 147 | |
| @@ -0,0 +1,177 @@ | ||
| 1 | +// | |
| 2 | +// Created by Bradley Austin Davis on 2015/06/19 | |
| 3 | +// Copyright 2015 High Fidelity, Inc. | |
| 4 | +// | |
| 5 | +// Distributed under the Apache License, Version 2.0. | |
| 6 | +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 7 | +// | |
| 8 | + | |
| 9 | +import Hifi 1.0 as Hifi | |
| 10 | +import QtQuick 2.4 | |
| 11 | +import QtQuick.Controls 1.3 | |
| 12 | +import QtGraphicalEffects 1.0 | |
| 13 | + | |
| 14 | +Hifi.AvatarInputs { | |
| 15 | + id: root | |
| 16 | + objectName: "AvatarInputs" | |
| 17 | + anchors.fill: parent | |
| 18 | + | |
| 19 | +// width: 800 | |
| 20 | +// height: 600 | |
| 21 | +// color: "black" | |
| 22 | + readonly property int iconPadding: 5 | |
| 23 | + readonly property int mirrorHeight: 215 | |
| 24 | + readonly property int mirrorWidth: 265 | |
| 25 | + readonly property int mirrorTopPad: iconPadding | |
| 26 | + readonly property int mirrorLeftPad: 10 | |
| 27 | + readonly property int iconSize: 24 | |
| 28 | + | |
| 29 | + Item { | |
| 30 | + id: mirror | |
| 31 | + width: root.mirrorWidth | |
| 32 | + height: root.mirrorVisible ? root.mirrorHeight : 0 | |
| 33 | + visible: root.mirrorVisible | |
| 34 | + anchors.left: parent.left | |
| 35 | + anchors.leftMargin: root.mirrorLeftPad | |
| 36 | + anchors.top: parent.top | |
| 37 | + anchors.topMargin: root.mirrorTopPad | |
| 38 | + clip: true | |
| 39 | + | |
| 40 | + MouseArea { | |
| 41 | + id: hover | |
| 42 | + anchors.fill: parent | |
| 43 | + hoverEnabled: true | |
| 44 | + propagateComposedEvents: true | |
| 45 | + } | |
| 46 | + | |
| 47 | + Image { | |
| 48 | + id: closeMirror | |
| 49 | + visible: hover.containsMouse | |
| 50 | + width: root.iconSize | |
| 51 | + height: root.iconSize | |
| 52 | + anchors.top: parent.top | |
| 53 | + anchors.topMargin: root.iconPadding | |
| 54 | + anchors.left: parent.left | |
| 55 | + anchors.leftMargin: root.iconPadding | |
| 56 | + source: "../images/close.svg" | |
| 57 | + MouseArea { | |
| 58 | + anchors.fill: parent | |
| 59 | + onClicked: { | |
| 60 | + root.closeMirror(); | |
| 61 | + } | |
| 62 | + } | |
| 63 | + } | |
| 64 | + | |
| 65 | + Image { | |
| 66 | + id: zoomIn | |
| 67 | + visible: hover.containsMouse | |
| 68 | + width: root.iconSize | |
| 69 | + height: root.iconSize | |
| 70 | + anchors.bottom: parent.bottom | |
| 71 | + anchors.bottomMargin: root.iconPadding | |
| 72 | + anchors.left: parent.left | |
| 73 | + anchors.leftMargin: root.iconPadding | |
| 74 | + source: root.mirrorZoomed ? "../images/minus.svg" : "../images/plus.svg" | |
| 75 | + MouseArea { | |
| 76 | + anchors.fill: parent | |
| 77 | + onClicked: { | |
| 78 | + root.toggleZoom(); | |
| 79 | + } | |
| 80 | + } | |
| 81 | + } | |
| 82 | + } | |
| 83 | + | |
| 84 | + Item { | |
| 85 | + width: root.mirrorWidth | |
| 86 | + height: 44 | |
| 87 | + | |
| 88 | + x: root.mirrorLeftPad | |
| 89 | + y: root.mirrorVisible ? root.mirrorTopPad + root.mirrorHeight : 5 | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + Rectangle { | |
| 94 | + anchors.fill: parent | |
| 95 | + color: root.mirrorVisible ? (root.audioClipping ? "red" : "#696969") : "#00000000" | |
| 96 | + | |
| 97 | + Image { | |
| 98 | + id: faceMute | |
| 99 | + width: root.iconSize | |
| 100 | + height: root.iconSize | |
| 101 | + visible: root.cameraEnabled | |
| 102 | + anchors.left: parent.left | |
| 103 | + anchors.leftMargin: root.iconPadding | |
| 104 | + anchors.verticalCenter: parent.verticalCenter | |
| 105 | + source: root.cameraMuted ? "../images/face-mute.svg" : "../images/face.svg" | |
| 106 | + MouseArea { | |
| 107 | + anchors.fill: parent | |
| 108 | + onClicked: { | |
| 109 | + root.toggleCameraMute() | |
| 110 | + } | |
| 111 | + onDoubleClicked: { | |
| 112 | + root.resetSensors(); | |
| 113 | + } | |
| 114 | + } | |
| 115 | + } | |
| 116 | + | |
| 117 | + Image { | |
| 118 | + id: micMute | |
| 119 | + width: root.iconSize | |
| 120 | + height: root.iconSize | |
| 121 | + anchors.left: root.cameraEnabled ? faceMute.right : parent.left | |
| 122 | + anchors.leftMargin: root.iconPadding | |
| 123 | + anchors.verticalCenter: parent.verticalCenter | |
| 124 | + source: root.audioMuted ? "../images/mic-mute.svg" : "../images/mic.svg" | |
| 125 | + MouseArea { | |
| 126 | + anchors.fill: parent | |
| 127 | + onClicked: { | |
| 128 | + root.toggleAudioMute() | |
| 129 | + } | |
| 130 | + } | |
| 131 | + } | |
| 132 | + | |
| 133 | + Item { | |
| 134 | + id: audioMeter | |
| 135 | + anchors.verticalCenter: parent.verticalCenter | |
| 136 | + anchors.left: micMute.right | |
| 137 | + anchors.leftMargin: root.iconPadding | |
| 138 | + anchors.right: parent.right | |
| 139 | + anchors.rightMargin: root.iconPadding | |
| 140 | + height: 8 | |
| 141 | + Rectangle { | |
| 142 | + id: blueRect | |
| 143 | + color: "blue" | |
| 144 | + anchors.top: parent.top | |
| 145 | + anchors.bottom: parent.bottom | |
| 146 | + anchors.left: parent.left | |
| 147 | + width: parent.width / 4 | |
| 148 | + } | |
| 149 | + Rectangle { | |
| 150 | + id: greenRect | |
| 151 | + color: "green" | |
| 152 | + anchors.top: parent.top | |
| 153 | + anchors.bottom: parent.bottom | |
| 154 | + anchors.left: blueRect.right | |
| 155 | + anchors.right: redRect.left | |
| 156 | + } | |
| 157 | + Rectangle { | |
| 158 | + id: redRect | |
| 159 | + color: "red" | |
| 160 | + anchors.top: parent.top | |
| 161 | + anchors.bottom: parent.bottom | |
| 162 | + anchors.right: parent.right | |
| 163 | + width: parent.width / 5 | |
| 164 | + } | |
| 165 | + Rectangle { | |
| 166 | + z: 100 | |
| 167 | + anchors.top: parent.top | |
| 168 | + anchors.bottom: parent.bottom | |
| 169 | + anchors.right: parent.right | |
| 170 | + width: (1.0 - root.audioLevel) * parent.width | |
| 171 | + color: "black" | |
| 172 | + } | |
| 173 | + } | |
| 174 | + } | |
| 175 | + } | |
| 176 | +} | |
| 177 | + | |
| @@ -0,0 +1,258 @@ | ||
| 1 | +import Hifi 1.0 as Hifi | |
| 2 | +import QtQuick 2.3 | |
| 3 | +import QtQuick.Controls 1.2 | |
| 4 | + | |
| 5 | +Item { | |
| 6 | + anchors.fill: parent | |
| 7 | + anchors.leftMargin: 300 | |
| 8 | + Hifi.Stats { | |
| 9 | + id: root | |
| 10 | + objectName: "Stats" | |
| 11 | + implicitHeight: row.height | |
| 12 | + implicitWidth: row.width | |
| 13 | + | |
| 14 | + anchors.horizontalCenter: parent.horizontalCenter | |
| 15 | + | |
| 16 | + readonly property int sTATS_GENERAL_MIN_WIDTH: 165 | |
| 17 | + readonly property int sTATS_PING_MIN_WIDTH: 190 | |
| 18 | + readonly property int sTATS_GEO_MIN_WIDTH: 240 | |
| 19 | + readonly property int sTATS_OCTREE_MIN_WIDTH: 410 | |
| 20 | + readonly property int fontSize: 12 | |
| 21 | + readonly property string fontColor: "white" | |
| 22 | + readonly property string bgColor: "#99333333" | |
| 23 | + | |
| 24 | + Row { | |
| 25 | + id: row | |
| 26 | + spacing: 8 | |
| 27 | + Rectangle { | |
| 28 | + width: generalCol.width + 8; | |
| 29 | + height: generalCol.height + 8; | |
| 30 | + color: root.bgColor; | |
| 31 | + | |
| 32 | + MouseArea { | |
| 33 | + anchors.fill: parent | |
| 34 | + onClicked: { root.expanded = !root.expanded; } | |
| 35 | + } | |
| 36 | + | |
| 37 | + Column { | |
| 38 | + id: generalCol | |
| 39 | + spacing: 4; x: 4; y: 4; | |
| 40 | + width: sTATS_GENERAL_MIN_WIDTH | |
| 41 | + Text { | |
| 42 | + color: root.fontColor; | |
| 43 | + font.pixelSize: root.fontSize | |
| 44 | + text: "Servers: " + root.serverCount | |
| 45 | + } | |
| 46 | + Text { | |
| 47 | + color: root.fontColor; | |
| 48 | + font.pixelSize: root.fontSize | |
| 49 | + text: "Avatars: " + root.avatarCount | |
| 50 | + } | |
| 51 | + Text { | |
| 52 | + color: root.fontColor; | |
| 53 | + font.pixelSize: root.fontSize | |
| 54 | + text: "Framerate: " + root.framerate | |
| 55 | + } | |
| 56 | + Text { | |
| 57 | + color: root.fontColor; | |
| 58 | + font.pixelSize: root.fontSize | |
| 59 | + text: "Packets In/Out: " + root.packetInCount + "/" + root.packetOutCount | |
| 60 | + } | |
| 61 | + Text { | |
| 62 | + color: root.fontColor; | |
| 63 | + font.pixelSize: root.fontSize | |
| 64 | + text: "Mbps In/Out: " + root.mbpsIn.toFixed(2) + "/" + root.mbpsOut.toFixed(2) | |
| 65 | + } | |
| 66 | + } | |
| 67 | + } | |
| 68 | + | |
| 69 | + Rectangle { | |
| 70 | + width: pingCol.width + 8 | |
| 71 | + height: pingCol.height + 8 | |
| 72 | + color: root.bgColor; | |
| 73 | + visible: root.audioPing != -2 | |
| 74 | + MouseArea { | |
| 75 | + anchors.fill: parent | |
| 76 | + onClicked: { root.expanded = !root.expanded; } | |
| 77 | + } | |
| 78 | + Column { | |
| 79 | + id: pingCol | |
| 80 | + spacing: 4; x: 4; y: 4; | |
| 81 | + width: sTATS_PING_MIN_WIDTH | |
| 82 | + Text { | |
| 83 | + color: root.fontColor | |
| 84 | + font.pixelSize: root.fontSize | |
| 85 | + text: "Audio ping: " + root.audioPing | |
| 86 | + } | |
| 87 | + Text { | |
| 88 | + color: root.fontColor | |
| 89 | + font.pixelSize: root.fontSize | |
| 90 | + text: "Avatar ping: " + root.avatarPing | |
| 91 | + } | |
| 92 | + Text { | |
| 93 | + color: root.fontColor | |
| 94 | + font.pixelSize: root.fontSize | |
| 95 | + text: "Entities avg ping: " + root.entitiesPing | |
| 96 | + } | |
| 97 | + Text { | |
| 98 | + color: root.fontColor | |
| 99 | + font.pixelSize: root.fontSize | |
| 100 | + visible: root.expanded; | |
| 101 | + text: "Voxel max ping: " + 0 | |
| 102 | + } | |
| 103 | + } | |
| 104 | + } | |
| 105 | + | |
| 106 | + Rectangle { | |
| 107 | + width: geoCol.width + 8 | |
| 108 | + height: geoCol.height + 8 | |
| 109 | + color: root.bgColor; | |
| 110 | + MouseArea { | |
| 111 | + anchors.fill: parent | |
| 112 | + onClicked: { root.expanded = !root.expanded; } | |
| 113 | + } | |
| 114 | + Column { | |
| 115 | + id: geoCol | |
| 116 | + spacing: 4; x: 4; y: 4; | |
| 117 | + width: sTATS_GEO_MIN_WIDTH | |
| 118 | + Text { | |
| 119 | + color: root.fontColor; | |
| 120 | + font.pixelSize: root.fontSize | |
| 121 | + text: "Position: " + root.position.x.toFixed(1) + ", " + | |
| 122 | + root.position.y.toFixed(1) + ", " + root.position.z.toFixed(1) | |
| 123 | + } | |
| 124 | + Text { | |
| 125 | + color: root.fontColor; | |
| 126 | + font.pixelSize: root.fontSize | |
| 127 | + text: "Velocity: " + root.velocity.toFixed(1) | |
| 128 | + } | |
| 129 | + Text { | |
| 130 | + color: root.fontColor; | |
| 131 | + font.pixelSize: root.fontSize | |
| 132 | + text: "Yaw: " + root.yaw.toFixed(1) | |
| 133 | + } | |
| 134 | + Text { | |
| 135 | + color: root.fontColor; | |
| 136 | + font.pixelSize: root.fontSize | |
| 137 | + visible: root.expanded; | |
| 138 | + text: "Avatar Mixer: " + root.avatarMixerKbps + " kbps, " + | |
| 139 | + root.avatarMixerPps + "pps"; | |
| 140 | + } | |
| 141 | + Text { | |
| 142 | + color: root.fontColor; | |
| 143 | + font.pixelSize: root.fontSize | |
| 144 | + visible: root.expanded; | |
| 145 | + text: "Downloads: "; | |
| 146 | + } | |
| 147 | + } | |
| 148 | + } | |
| 149 | + Rectangle { | |
| 150 | + width: octreeCol.width + 8 | |
| 151 | + height: octreeCol.height + 8 | |
| 152 | + color: root.bgColor; | |
| 153 | + MouseArea { | |
| 154 | + anchors.fill: parent | |
| 155 | + onClicked: { root.expanded = !root.expanded; } | |
| 156 | + } | |
| 157 | + Column { | |
| 158 | + id: octreeCol | |
| 159 | + spacing: 4; x: 4; y: 4; | |
| 160 | + width: sTATS_OCTREE_MIN_WIDTH | |
| 161 | + Text { | |
| 162 | + color: root.fontColor; | |
| 163 | + font.pixelSize: root.fontSize | |
| 164 | + text: "Triangles: " + root.triangles + | |
| 165 | + " / Quads: " + root.quads + " / Material Switches: " + root.materialSwitches | |
| 166 | + } | |
| 167 | + Text { | |
| 168 | + color: root.fontColor; | |
| 169 | + font.pixelSize: root.fontSize | |
| 170 | + visible: root.expanded; | |
| 171 | + text: "\tMesh Parts Rendered Opaque: " + root.meshOpaque + | |
| 172 | + " / Translucent: " + root.meshTranslucent; | |
| 173 | + } | |
| 174 | + Text { | |
| 175 | + color: root.fontColor; | |
| 176 | + font.pixelSize: root.fontSize | |
| 177 | + visible: root.expanded; | |
| 178 | + text: "\tOpaque considered: " + root.opaqueConsidered + | |
| 179 | + " / Out of view: " + root.opaqueOutOfView + " / Too small: " + root.opaqueTooSmall; | |
| 180 | + } | |
| 181 | + Text { | |
| 182 | + color: root.fontColor; | |
| 183 | + font.pixelSize: root.fontSize | |
| 184 | + visible: !root.expanded | |
| 185 | + text: "Octree Elements Server: " + root.serverElements + | |
| 186 | + " Local: " + root.localElements; | |
| 187 | + } | |
| 188 | + Text { | |
| 189 | + color: root.fontColor; | |
| 190 | + font.pixelSize: root.fontSize | |
| 191 | + visible: root.expanded | |
| 192 | + text: "Octree Sending Mode: " + root.sendingMode; | |
| 193 | + } | |
| 194 | + Text { | |
| 195 | + color: root.fontColor; | |
| 196 | + font.pixelSize: root.fontSize | |
| 197 | + visible: root.expanded | |
| 198 | + text: "Octree Packets to Process: " + root.packetStats; | |
| 199 | + } | |
| 200 | + Text { | |
| 201 | + color: root.fontColor; | |
| 202 | + font.pixelSize: root.fontSize | |
| 203 | + visible: root.expanded | |
| 204 | + text: "Octree Elements - "; | |
| 205 | + } | |
| 206 | + Text { | |
| 207 | + color: root.fontColor; | |
| 208 | + font.pixelSize: root.fontSize | |
| 209 | + visible: root.expanded | |
| 210 | + text: "\tServer: " + root.serverElements + | |
| 211 | + " Internal: " + root.serverInternal + | |
| 212 | + " Leaves: " + root.serverLeaves; | |
| 213 | + } | |
| 214 | + Text { | |
| 215 | + color: root.fontColor; | |
| 216 | + font.pixelSize: root.fontSize | |
| 217 | + visible: root.expanded | |
| 218 | + text: "\tLocal: " + root.localElements + | |
| 219 | + " Internal: " + root.localInternal + | |
| 220 | + " Leaves: " + root.localLeaves; | |
| 221 | + } | |
| 222 | + Text { | |
| 223 | + color: root.fontColor; | |
| 224 | + font.pixelSize: root.fontSize | |
| 225 | + visible: root.expanded | |
| 226 | + text: "LOD: " + root.lodStatus; | |
| 227 | + } | |
| 228 | + } | |
| 229 | + } | |
| 230 | + } | |
| 231 | + | |
| 232 | + Rectangle { | |
| 233 | + y: 250 | |
| 234 | + visible: root.timingExpanded | |
| 235 | + width: perfText.width + 8 | |
| 236 | + height: perfText.height + 8 | |
| 237 | + color: root.bgColor; | |
| 238 | + Text { | |
| 239 | + x: 4; y: 4 | |
| 240 | + id: perfText | |
| 241 | + color: root.fontColor | |
| 242 | + font.family: root.monospaceFont | |
| 243 | + font.pixelSize: 12 | |
| 244 | + text: "------------------------------------------ Function " + | |
| 245 | + "--------------------------------------- --msecs- -calls--\n" + | |
| 246 | + root.timingStats; | |
| 247 | + } | |
| 248 | + } | |
| 249 | + | |
| 250 | + Connections { | |
| 251 | + target: root.parent | |
| 252 | + onWidthChanged: { | |
| 253 | + root.x = root.parent.width - root.width; | |
| 254 | + } | |
| 255 | + } | |
| 256 | + } | |
| 257 | + | |
| 258 | +} | |
| @@ -0,0 +1,31 @@ | ||
| 1 | +import Hifi 1.0 as Hifi | |
| 2 | +import QtQuick 2.3 as Original | |
| 3 | +import "controls" | |
| 4 | +import "styles" | |
| 5 | + | |
| 6 | +Hifi.Tooltip { | |
| 7 | + id: root | |
| 8 | + HifiConstants { id: hifi } | |
| 9 | + // FIXME adjust position based on the edges of the screen | |
| 10 | + x: (lastMousePosition.x > surfaceSize.width/2) ? lastMousePosition.x - 140 : lastMousePosition.x + 20 | |
| 11 | + //y: lastMousePosition.y + 5 | |
| 12 | + y: (lastMousePosition.y > surfaceSize.height/2) ? lastMousePosition.y - 70 : lastMousePosition.y + 5 | |
| 13 | + implicitWidth: border.implicitWidth | |
| 14 | + implicitHeight: border.implicitHeight | |
| 15 | + | |
| 16 | + Border { | |
| 17 | + id: border | |
| 18 | + anchors.fill: parent | |
| 19 | + implicitWidth: text.implicitWidth | |
| 20 | + implicitHeight: Math.max(text.implicitHeight, 64) | |
| 21 | + | |
| 22 | + Text { | |
| 23 | + id: text | |
| 24 | + anchors.fill: parent | |
| 25 | + anchors.margins: 16 | |
| 26 | + font.pixelSize: hifi.fonts.pixelSize / 2 | |
| 27 | + text: root.text | |
| 28 | + wrapMode: Original.Text.WordWrap | |
| 29 | + } | |
| 30 | + } | |
| 31 | +} | |
| @@ -66,6 +66,9 @@ · 65 unmodified lines | ||
| 66 | 66 | #include <EntityScriptingInterface.h> |
| 67 | 67 | #include <ErrorDialog.h> |
| 68 | 68 | #include <GlowEffect.h> |
| 69 | +#include <gpu/Batch.h> | |
| 70 | +#include <gpu/Context.h> | |
| 71 | +#include <gpu/GLBackend.h> | |
| 69 | 72 | #include <HFActionEvent.h> |
| 70 | 73 | #include <HFBackEvent.h> |
| 71 | 74 | #include <InfoView.h> |
| @@ -83,12 +86,14 @@ · 11 unmodified lines | ||
| 83 | 86 | #include <PerfStat.h> |
| 84 | 87 | #include <PhysicsEngine.h> |
| 85 | 88 | #include <ProgramObject.h> |
| 89 | +#include <RenderDeferredTask.h> | |
| 86 | 90 | #include <ResourceCache.h> |
| 87 | 91 | #include <SceneScriptingInterface.h> |
| 88 | 92 | #include <ScriptCache.h> |
| 89 | 93 | #include <SettingHandle.h> |
| 90 | 94 | #include <SoundCache.h> |
| 91 | 95 | #include <TextRenderer.h> |
| 96 | +#include <Tooltip.h> | |
| 92 | 97 | #include <UserActivityLogger.h> |
| 93 | 98 | #include <UUID.h> |
| 94 | 99 | #include <VrMenu.h> |
| @@ -106,11 +111,9 @@ · 11 unmodified lines | ||
| 106 | 111 | |
| 107 | 112 | #include "avatar/AvatarManager.h" |
| 108 | 113 | |
| 109 | −#include "audio/AudioToolBox.h" | |
| 110 | 114 | #include "audio/AudioIOStatsRenderer.h" |
| 111 | 115 | #include "audio/AudioScope.h" |
| 112 | 116 | |
| 113 | −#include "devices/CameraToolBox.h" | |
| 114 | 117 | #include "devices/DdeFaceTracker.h" |
| 115 | 118 | #include "devices/Faceshift.h" |
| 116 | 119 | #include "devices/Leapmotion.h" |
| @@ -120,12 +123,6 @@ · 3 unmodified lines | ||
| 120 | 123 | #include "devices/OculusManager.h" |
| 121 | 124 | #include "devices/TV3DManager.h" |
| 122 | 125 | |
| 123 | −#include "gpu/Batch.h" | |
| 124 | −#include "gpu/Context.h" | |
| 125 | −#include "gpu/GLBackend.h" | |
| 126 | − | |
| 127 | −#include "RenderDeferredTask.h" | |
| 128 | − | |
| 129 | 126 | #include "scripting/AccountScriptingInterface.h" |
| 130 | 127 | #include "scripting/AudioDeviceScriptingInterface.h" |
| 131 | 128 | #include "scripting/ClipboardScriptingInterface.h" |
| @@ -141,6 +138,7 @@ · 9 unmodified lines | ||
| 141 | 138 | #include "SpeechRecognizer.h" |
| 142 | 139 | #endif |
| 143 | 140 | |
| 141 | +#include "ui/AvatarInputs.h" | |
| 144 | 142 | #include "ui/DataWebDialog.h" |
| 145 | 143 | #include "ui/DialogsManager.h" |
| 146 | 144 | #include "ui/LoginDialog.h" |
| @@ -281,8 +279,6 @@ bool setupEssentials(int& argc, char** argv) { · 134 unmodified lines | ||
| 281 | 279 | auto animationCache = DependencyManager::set<AnimationCache>(); |
| 282 | 280 | auto ddeFaceTracker = DependencyManager::set<DdeFaceTracker>(); |
| 283 | 281 | auto modelBlender = DependencyManager::set<ModelBlender>(); |
| 284 | − auto audioToolBox = DependencyManager::set<AudioToolBox>(); | |
| 285 | − auto cameraToolBox = DependencyManager::set<CameraToolBox>(); | |
| 286 | 282 | auto avatarManager = DependencyManager::set<AvatarManager>(); |
| 287 | 283 | auto lodManager = DependencyManager::set<LODManager>(); |
| 288 | 284 | auto jsConsole = DependencyManager::set<StandAloneJSConsole>(); |
| @@ -335,8 +331,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : · 46 unmodified lines | ||
| 335 | 331 | _cursorVisible(true), |
| 336 | 332 | _lastMouseMove(usecTimestampNow()), |
| 337 | 333 | _lastMouseMoveWasSimulated(false), |
| 338 | − _touchAvgX(0.0f), | |
| 339 | − _touchAvgY(0.0f), | |
| 340 | 334 | _isTouchPressed(false), |
| 341 | 335 | _mousePressed(false), |
| 342 | 336 | _enableProcessOctreeThread(true), |
| @@ -814,9 +808,9 @@ void Application::initializeGL() { · 471 unmodified lines | ||
| 814 | 808 | _idleLoopStdev.reset(); |
| 815 | 809 | |
| 816 | 810 | if (_justStarted) { |
| 817 | − float startupTime = (float)_applicationStartupTime.elapsed() / 1000.0; | |
| 811 | + float startupTime = (float)_applicationStartupTime.elapsed() / 1000.0f; | |
| 818 | 812 | _justStarted = false; |
| 819 | − qCDebug(interfaceapp, "Startup time: %4.2f seconds.", startupTime); | |
| 813 | + qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTime); | |
| 820 | 814 | } |
| 821 | 815 | |
| 822 | 816 | // update before the first render |
| @@ -831,6 +825,7 @@ void Application::initializeUi() { · 8 unmodified lines | ||
| 831 | 825 | LoginDialog::registerType(); |
| 832 | 826 | MessageDialog::registerType(); |
| 833 | 827 | VrMenu::registerType(); |
| 828 | + Tooltip::registerType(); | |
| 834 | 829 | UpdateDialog::registerType(); |
| 835 | 830 | |
| 836 | 831 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); |
| @@ -844,7 +839,7 @@ void Application::initializeUi() { · 7 unmodified lines | ||
| 844 | 839 | VrMenu::executeQueuedLambdas(); |
| 845 | 840 | offscreenUi->setMouseTranslator([this](const QPointF& p){ |
| 846 | 841 | if (OculusManager::isConnected()) { |
| 847 | − glm::vec2 pos = _applicationOverlay.screenToOverlay(toGlm(p)); | |
| 842 | + glm::vec2 pos = _compositor.screenToOverlay(toGlm(p)); | |
| 848 | 843 | return QPointF(pos.x, pos.y); |
| 849 | 844 | } |
| 850 | 845 | return QPointF(p); |
| @@ -877,6 +872,7 @@ void Application::paintGL() { · 26 unmodified lines | ||
| 877 | 872 | OculusManager::beginFrameTiming(); |
| 878 | 873 | } |
| 879 | 874 | |
| 875 | + | |
| 880 | 876 | PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings)); |
| 881 | 877 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 882 | 878 | PerformanceWarning warn(showWarnings, "Application::paintGL()"); |
| @@ -884,6 +880,12 @@ void Application::paintGL() { · 1 unmodified line | ||
| 884 | 880 | |
| 885 | 881 | { |
| 886 | 882 | PerformanceTimer perfTimer("renderOverlay"); |
| 883 | + /* | |
| 884 | + gpu::Context context(new gpu::GLBackend()); | |
| 885 | + RenderArgs renderArgs(&context, nullptr, getViewFrustum(), lodManager->getOctreeSizeScale(), | |
| 886 | + lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE, | |
| 887 | + RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE); | |
| 888 | + */ | |
| 887 | 889 | _applicationOverlay.renderOverlay(&renderArgs); |
| 888 | 890 | } |
| 889 | 891 | |
| @@ -912,13 +914,18 @@ void Application::paintGL() { · 22 unmodified lines | ||
| 912 | 914 | } |
| 913 | 915 | |
| 914 | 916 | } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { |
| 915 | − _myCamera.setPosition(_myAvatar->getDefaultEyePosition() + | |
| 916 | − _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, 1.0f) * _myAvatar->getBoomLength() * _myAvatar->getScale()); | |
| 917 | 917 | if (OculusManager::isConnected()) { |
| 918 | 918 | _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation()); |
| 919 | 919 | } else { |
| 920 | 920 | _myCamera.setRotation(_myAvatar->getHead()->getOrientation()); |
| 921 | 921 | } |
| 922 | + if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { | |
| 923 | + _myCamera.setPosition(_myAvatar->getDefaultEyePosition() + | |
| 924 | + _myCamera.getRotation() * glm::vec3(0.0f, 0.0f, 1.0f) * _myAvatar->getBoomLength() * _myAvatar->getScale()); | |
| 925 | + } else { | |
| 926 | + _myCamera.setPosition(_myAvatar->getDefaultEyePosition() + | |
| 927 | + _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, 1.0f) * _myAvatar->getBoomLength() * _myAvatar->getScale()); | |
| 928 | + } | |
| 922 | 929 | |
| 923 | 930 | } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { |
| 924 | 931 | _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); |
| @@ -967,9 +974,7 @@ void Application::paintGL() { · 42 unmodified lines | ||
| 967 | 974 | glPopMatrix(); |
| 968 | 975 | |
| 969 | 976 | renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; |
| 970 | − if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { | |
| 971 | − _rearMirrorTools->render(&renderArgs, true, _glWidget->mapFromGlobal(QCursor::pos())); | |
| 972 | − } else if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { | |
| 977 | + if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { | |
| 973 | 978 | renderRearViewMirror(&renderArgs, _mirrorViewRect); |
| 974 | 979 | } |
| 975 | 980 | |
| @@ -977,6 +982,7 @@ void Application::paintGL() { · 1 unmodified line | ||
| 977 | 982 | |
| 978 | 983 | auto finalFbo = DependencyManager::get<GlowEffect>()->render(&renderArgs); |
| 979 | 984 | |
| 985 | + | |
| 980 | 986 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); |
| 981 | 987 | glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo)); |
| 982 | 988 | glBlitFramebuffer(0, 0, _renderResolution.x, _renderResolution.y, |
| @@ -984,9 +990,10 @@ void Application::paintGL() { · 1 unmodified line | ||
| 984 | 990 | GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| 985 | 991 | glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); |
| 986 | 992 | |
| 987 | − _applicationOverlay.displayOverlayTexture(); | |
| 993 | + _compositor.displayOverlayTexture(&renderArgs); | |
| 988 | 994 | } |
| 989 | 995 | |
| 996 | + | |
| 990 | 997 | if (!OculusManager::isConnected() || OculusManager::allowSwap()) { |
| 991 | 998 | _glWidget->swapBuffers(); |
| 992 | 999 | } |
| @@ -1044,27 +1051,24 @@ void Application::resizeGL() { · 51 unmodified lines | ||
| 1044 | 1051 | } else { |
| 1045 | 1052 | renderSize = _glWidget->getDeviceSize() * getRenderResolutionScale(); |
| 1046 | 1053 | } |
| 1047 | − if (_renderResolution == toGlm(renderSize)) { | |
| 1048 | − return; | |
| 1049 | − } | |
| 1050 | 1054 | |
| 1051 | − _renderResolution = toGlm(renderSize); | |
| 1052 | − DependencyManager::get<TextureCache>()->setFrameBufferSize(renderSize); | |
| 1053 | − resetCamerasOnResizeGL(_myCamera, _renderResolution); | |
| 1055 | + if (_renderResolution != toGlm(renderSize)) { | |
| 1056 | + _renderResolution = toGlm(renderSize); | |
| 1057 | + DependencyManager::get<TextureCache>()->setFrameBufferSize(renderSize); | |
| 1058 | + resetCamerasOnResizeGL(_myCamera, _renderResolution); | |
| 1054 | 1059 | |
| 1055 | − glViewport(0, 0, _renderResolution.x, _renderResolution.y); // shouldn't this account for the menu??? | |
| 1060 | + glViewport(0, 0, _renderResolution.x, _renderResolution.y); // shouldn't this account for the menu??? | |
| 1056 | 1061 | |
| 1057 | − updateProjectionMatrix(); | |
| 1058 | − glLoadIdentity(); | |
| 1062 | + updateProjectionMatrix(); | |
| 1063 | + glLoadIdentity(); | |
| 1064 | + } | |
| 1059 | 1065 | |
| 1060 | 1066 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); |
| 1061 | − offscreenUi->resize(_glWidget->size()); | |
| 1067 | + | |
| 1068 | + auto canvasSize = _glWidget->size(); | |
| 1069 | + offscreenUi->resize(canvasSize); | |
| 1062 | 1070 | _glWidget->makeCurrent(); |
| 1063 | 1071 | |
| 1064 | − // update Stats width | |
| 1065 | − // let's set horizontal offset to give stats some margin to mirror | |
| 1066 | − int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2; | |
| 1067 | − Stats::getInstance()->resetWidth(_renderResolution.x, horizontalOffset); | |
| 1068 | 1072 | } |
| 1069 | 1073 | |
| 1070 | 1074 | void Application::updateProjectionMatrix() { |
| @@ -1568,27 +1572,9 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { · 497 unmodified lines | ||
| 1568 | 1572 | _keyboardMouseDevice.mousePressEvent(event); |
| 1569 | 1573 | |
| 1570 | 1574 | if (event->button() == Qt::LeftButton) { |
| 1571 | − _mouseDragStartedX = getTrueMouseX(); | |
| 1572 | − _mouseDragStartedY = getTrueMouseY(); | |
| 1575 | + _mouseDragStarted = getTrueMouse(); | |
| 1573 | 1576 | _mousePressed = true; |
| 1574 | 1577 | |
| 1575 | − if (mouseOnScreen()) { | |
| 1576 | − if (DependencyManager::get<AudioToolBox>()->mousePressEvent(getMouseX(), getMouseY())) { | |
| 1577 | − // stop propagation | |
| 1578 | − return; | |
| 1579 | − } | |
| 1580 | − | |
| 1581 | − if (DependencyManager::get<CameraToolBox>()->mousePressEvent(getMouseX(), getMouseY())) { | |
| 1582 | − // stop propagation | |
| 1583 | − return; | |
| 1584 | − } | |
| 1585 | − | |
| 1586 | − if (_rearMirrorTools->mousePressEvent(getMouseX(), getMouseY())) { | |
| 1587 | − // stop propagation | |
| 1588 | − return; | |
| 1589 | − } | |
| 1590 | − } | |
| 1591 | − | |
| 1592 | 1578 | // nobody handled this - make it an action event on the _window object |
| 1593 | 1579 | HFActionEvent actionEvent(HFActionEvent::startType(), |
| 1594 | 1580 | computePickRay(event->x(), event->y())); |
| @@ -1606,16 +1592,7 @@ void Application::mouseDoublePressEvent(QMouseEvent* event, unsigned int deviceI · 11 unmodified lines | ||
| 1606 | 1592 | return; |
| 1607 | 1593 | } |
| 1608 | 1594 | |
| 1609 | − if (activeWindow() == _window) { | |
| 1610 | − if (event->button() == Qt::LeftButton) { | |
| 1611 | − if (mouseOnScreen()) { | |
| 1612 | − if (DependencyManager::get<CameraToolBox>()->mouseDoublePressEvent(getMouseX(), getMouseY())) { | |
| 1613 | − // stop propagation | |
| 1614 | − return; | |
| 1615 | − } | |
| 1616 | − } | |
| 1617 | − } | |
| 1618 | − } | |
| 1595 | + _controllerScriptingInterface.emitMouseDoublePressEvent(event); | |
| 1619 | 1596 | } |
| 1620 | 1597 | |
| 1621 | 1598 | void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { |
| @@ -1637,13 +1614,6 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { · 15 unmodified lines | ||
| 1637 | 1614 | if (event->button() == Qt::LeftButton) { |
| 1638 | 1615 | _mousePressed = false; |
| 1639 | 1616 | |
| 1640 | − if (Menu::getInstance()->isOptionChecked(MenuOption::Stats) && mouseOnScreen()) { | |
| 1641 | − // let's set horizontal offset to give stats some margin to mirror | |
| 1642 | − int horizontalOffset = MIRROR_VIEW_WIDTH; | |
| 1643 | − Stats::getInstance()->checkClick(getMouseX(), getMouseY(), | |
| 1644 | − getMouseDragStartedX(), getMouseDragStartedY(), horizontalOffset); | |
| 1645 | − } | |
| 1646 | − | |
| 1647 | 1617 | // fire an action end event |
| 1648 | 1618 | HFActionEvent actionEvent(HFActionEvent::endType(), |
| 1649 | 1619 | computePickRay(event->x(), event->y())); |
| @@ -1671,22 +1641,18 @@ void Application::touchUpdateEvent(QTouchEvent* event) { · 21 unmodified lines | ||
| 1671 | 1641 | bool validTouch = false; |
| 1672 | 1642 | if (activeWindow() == _window) { |
| 1673 | 1643 | const QList<QTouchEvent::TouchPoint>& tPoints = event->touchPoints(); |
| 1674 | − _touchAvgX = 0.0f; | |
| 1675 | − _touchAvgY = 0.0f; | |
| 1644 | + _touchAvg = vec2(); | |
| 1676 | 1645 | int numTouches = tPoints.count(); |
| 1677 | 1646 | if (numTouches > 1) { |
| 1678 | 1647 | for (int i = 0; i < numTouches; ++i) { |
| 1679 | − _touchAvgX += tPoints[i].pos().x(); | |
| 1680 | − _touchAvgY += tPoints[i].pos().y(); | |
| 1648 | + _touchAvg += toGlm(tPoints[i].pos()); | |
| 1681 | 1649 | } |
| 1682 | − _touchAvgX /= (float)(numTouches); | |
| 1683 | − _touchAvgY /= (float)(numTouches); | |
| 1650 | + _touchAvg /= (float)(numTouches); | |
| 1684 | 1651 | validTouch = true; |
| 1685 | 1652 | } |
| 1686 | 1653 | } |
| 1687 | 1654 | if (!_isTouchPressed) { |
| 1688 | − _touchDragStartedAvgX = _touchAvgX; | |
| 1689 | − _touchDragStartedAvgY = _touchAvgY; | |
| 1655 | + _touchDragStartedAvg = _touchAvg; | |
| 1690 | 1656 | } |
| 1691 | 1657 | _isTouchPressed = validTouch; |
| 1692 | 1658 | } |
| @@ -1722,8 +1688,7 @@ void Application::touchEndEvent(QTouchEvent* event) { · 29 unmodified lines | ||
| 1722 | 1688 | _keyboardMouseDevice.touchEndEvent(event); |
| 1723 | 1689 | |
| 1724 | 1690 | // put any application specific touch behavior below here.. |
| 1725 | − _touchDragStartedAvgX = _touchAvgX; | |
| 1726 | − _touchDragStartedAvgY = _touchAvgY; | |
| 1691 | + _touchDragStartedAvg = _touchAvg; | |
| 1727 | 1692 | _isTouchPressed = false; |
| 1728 | 1693 | |
| 1729 | 1694 | } |
| @@ -1872,9 +1837,9 @@ void Application::setFullscreen(bool fullscreen) { · 142 unmodified lines | ||
| 1872 | 1837 | Menu::getInstance()->getActionForOption(MenuOption::Fullscreen)->setChecked(fullscreen); |
| 1873 | 1838 | } |
| 1874 | 1839 | |
| 1875 | −// The following code block is useful on platforms that can have a visible | |
| 1876 | −// app menu in a fullscreen window. However the OSX mechanism hides the | |
| 1877 | −// application menu for fullscreen apps, so the check is not required. | |
| 1840 | + // The following code block is useful on platforms that can have a visible | |
| 1841 | + // app menu in a fullscreen window. However the OSX mechanism hides the | |
| 1842 | + // application menu for fullscreen apps, so the check is not required. | |
| 1878 | 1843 | #ifndef Q_OS_MAC |
| 1879 | 1844 | if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) { |
| 1880 | 1845 | if (fullscreen) { |
| @@ -1939,16 +1904,15 @@ void Application::setEnableVRMode(bool enableVRMode) { · 58 unmodified lines | ||
| 1939 | 1904 | // attempt to reconnect the Oculus manager - it's possible this was a workaround |
| 1940 | 1905 | // for the sixense crash |
| 1941 | 1906 | OculusManager::disconnect(); |
| 1942 | − OculusManager::connect(); | |
| 1907 | + OculusManager::connect(_glWidget->context()->contextHandle()); | |
| 1908 | + _glWidget->setFocus(); | |
| 1909 | + _glWidget->makeCurrent(); | |
| 1910 | + glClear(GL_COLOR_BUFFER_BIT); | |
| 1943 | 1911 | } |
| 1944 | 1912 | OculusManager::recalibrate(); |
| 1945 | 1913 | } else { |
| 1946 | 1914 | OculusManager::abandonCalibration(); |
| 1947 | − | |
| 1948 | − _mirrorCamera.setHmdPosition(glm::vec3()); | |
| 1949 | − _mirrorCamera.setHmdRotation(glm::quat()); | |
| 1950 | − _myCamera.setHmdPosition(glm::vec3()); | |
| 1951 | − _myCamera.setHmdRotation(glm::quat()); | |
| 1915 | + OculusManager::disconnect(); | |
| 1952 | 1916 | } |
| 1953 | 1917 | |
| 1954 | 1918 | resizeGL(); |
| @@ -1960,44 +1924,34 @@ void Application::setLowVelocityFilter(bool lowVelocityFilter) { · 5 unmodified lines | ||
| 1960 | 1924 | |
| 1961 | 1925 | bool Application::mouseOnScreen() const { |
| 1962 | 1926 | if (OculusManager::isConnected()) { |
| 1963 | − return getMouseX() >= 0 && getMouseX() <= _glWidget->getDeviceWidth() && | |
| 1964 | − getMouseY() >= 0 && getMouseY() <= _glWidget->getDeviceHeight(); | |
| 1927 | + ivec2 mouse = getMouse(); | |
| 1928 | + if (!glm::all(glm::greaterThanEqual(mouse, ivec2()))) { | |
| 1929 | + return false; | |
| 1930 | + } | |
| 1931 | + ivec2 size = toGlm(_glWidget->getDeviceSize()); | |
| 1932 | + if (!glm::all(glm::lessThanEqual(mouse, size))) { | |
| 1933 | + return false; | |
| 1934 | + } | |
| 1965 | 1935 | } |
| 1966 | 1936 | return true; |
| 1967 | 1937 | } |
| 1968 | 1938 | |
| 1969 | −int Application::getMouseX() const { | |
| 1970 | − if (OculusManager::isConnected()) { | |
| 1971 | − glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseX(), getTrueMouseY())); | |
| 1972 | − return pos.x; | |
| 1973 | − } | |
| 1974 | − return getTrueMouseX(); | |
| 1975 | −} | |
| 1976 | − | |
| 1977 | −int Application::getMouseY() const { | |
| 1939 | +ivec2 Application::getMouse() const { | |
| 1978 | 1940 | if (OculusManager::isConnected()) { |
| 1979 | − glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseX(), getTrueMouseY())); | |
| 1980 | − return pos.y; | |
| 1941 | + return _compositor.screenToOverlay(getTrueMouse()); | |
| 1981 | 1942 | } |
| 1982 | − return getTrueMouseY(); | |
| 1943 | + return getTrueMouse(); | |
| 1983 | 1944 | } |
| 1984 | 1945 | |
| 1985 | −int Application::getMouseDragStartedX() const { | |
| 1946 | +ivec2 Application::getMouseDragStarted() const { | |
| 1986 | 1947 | if (OculusManager::isConnected()) { |
| 1987 | − glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseDragStartedX(), | |
| 1988 | − getTrueMouseDragStartedY())); | |
| 1989 | − return pos.x; | |
| 1948 | + return _compositor.screenToOverlay(getTrueMouseDragStarted()); | |
| 1990 | 1949 | } |
| 1991 | − return getTrueMouseDragStartedX(); | |
| 1950 | + return getTrueMouseDragStarted(); | |
| 1992 | 1951 | } |
| 1993 | 1952 | |
| 1994 | −int Application::getMouseDragStartedY() const { | |
| 1995 | − if (OculusManager::isConnected()) { | |
| 1996 | − glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseDragStartedX(), | |
| 1997 | − getTrueMouseDragStartedY())); | |
| 1998 | − return pos.y; | |
| 1999 | − } | |
| 2000 | − return getTrueMouseDragStartedY(); | |
| 1953 | +ivec2 Application::getTrueMouseDragStarted() const { | |
| 1954 | + return _mouseDragStarted; | |
| 2001 | 1955 | } |
| 2002 | 1956 | |
| 2003 | 1957 | FaceTracker* Application::getActiveFaceTracker() { |
| @@ -2179,13 +2133,6 @@ void Application::init() { · 175 unmodified lines | ||
| 2179 | 2133 | |
| 2180 | 2134 | _mirrorCamera.setMode(CAMERA_MODE_MIRROR); |
| 2181 | 2135 | |
| 2182 | − OculusManager::connect(); | |
| 2183 | − if (OculusManager::isConnected()) { | |
| 2184 | − QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen), | |
| 2185 | − "trigger", | |
| 2186 | − Qt::QueuedConnection); | |
| 2187 | − } | |
| 2188 | − | |
| 2189 | 2136 | TV3DManager::connect(); |
| 2190 | 2137 | if (TV3DManager::isConnected()) { |
| 2191 | 2138 | QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen), |
| @@ -2249,13 +2196,6 @@ void Application::init() { · 57 unmodified lines | ||
| 2249 | 2196 | _entityClipboardRenderer.setViewFrustum(getViewFrustum()); |
| 2250 | 2197 | _entityClipboardRenderer.setTree(&_entityClipboard); |
| 2251 | 2198 | |
| 2252 | − _rearMirrorTools = new RearMirrorTools(_mirrorViewRect); | |
| 2253 | − | |
| 2254 | − connect(_rearMirrorTools, SIGNAL(closeView()), SLOT(closeMirrorView())); | |
| 2255 | − connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView())); | |
| 2256 | − connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView())); | |
| 2257 | − connect(_rearMirrorTools, SIGNAL(resetView()), SLOT(resetSensors())); | |
| 2258 | − | |
| 2259 | 2199 | // initialize the GlowEffect with our widget |
| 2260 | 2200 | bool glow = Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect); |
| 2261 | 2201 | DependencyManager::get<GlowEffect>()->init(glow); |
| @@ -2434,6 +2374,12 @@ void Application::cameraMenuChanged() { · 172 unmodified lines | ||
| 2434 | 2374 | } |
| 2435 | 2375 | } |
| 2436 | 2376 | |
| 2377 | +void Application::rotationModeChanged() { | |
| 2378 | + if (!Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { | |
| 2379 | + _myAvatar->setHeadPitch(0); | |
| 2380 | + } | |
| 2381 | +} | |
| 2382 | + | |
| 2437 | 2383 | void Application::updateCamera(float deltaTime) { |
| 2438 | 2384 | PerformanceTimer perfTimer("updateCamera"); |
| 2439 | 2385 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| @@ -3155,7 +3101,7 @@ PickRay Application::computePickRay(float x, float y) const { · 715 unmodified lines | ||
| 3155 | 3101 | y /= size.y; |
| 3156 | 3102 | PickRay result; |
| 3157 | 3103 | if (isHMDMode()) { |
| 3158 | − getApplicationOverlay().computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction); | |
| 3104 | + getApplicationCompositor().computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction); | |
| 3159 | 3105 | } else { |
| 3160 | 3106 | if (QThread::currentThread() == activeRenderingThread) { |
| 3161 | 3107 | getDisplayViewFrustum()->computePickRay(x, y, result.origin, result.direction); |
| @@ -3184,13 +3130,11 @@ QImage Application::renderAvatarBillboard(RenderArgs* renderArgs) { · 22 unmodified lines | ||
| 3184 | 3130 | renderRearViewMirror(renderArgs, QRect(0, _glWidget->getDeviceHeight() - BILLBOARD_SIZE, |
| 3185 | 3131 | BILLBOARD_SIZE, BILLBOARD_SIZE), |
| 3186 | 3132 | true); |
| 3187 | − | |
| 3188 | 3133 | QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32); |
| 3189 | 3134 | glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits()); |
| 3190 | 3135 | glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| 3191 | 3136 | |
| 3192 | 3137 | glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| 3193 | − | |
| 3194 | 3138 | return image; |
| 3195 | 3139 | } |
| 3196 | 3140 | |
| @@ -3386,9 +3330,8 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 189 unmodified lines | ||
| 3386 | 3330 | |
| 3387 | 3331 | // flip x if in mirror mode (also requires reversing winding order for backface culling) |
| 3388 | 3332 | if (theCamera.getMode() == CAMERA_MODE_MIRROR) { |
| 3389 | − glScalef(-1.0f, 1.0f, 1.0f); | |
| 3390 | − glFrontFace(GL_CW); | |
| 3391 | − | |
| 3333 | + //glScalef(-1.0f, 1.0f, 1.0f); | |
| 3334 | + //glFrontFace(GL_CW); | |
| 3392 | 3335 | } else { |
| 3393 | 3336 | glFrontFace(GL_CCW); |
| 3394 | 3337 | } |
| @@ -3411,7 +3354,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 16 unmodified lines | ||
| 3411 | 3354 | viewTransform.setTranslation(theCamera.getPosition()); |
| 3412 | 3355 | viewTransform.setRotation(rotation); |
| 3413 | 3356 | if (theCamera.getMode() == CAMERA_MODE_MIRROR) { |
| 3414 | − viewTransform.setScale(Transform::Vec3(-1.0f, 1.0f, 1.0f)); | |
| 3357 | +// viewTransform.setScale(Transform::Vec3(-1.0f, 1.0f, 1.0f)); | |
| 3415 | 3358 | } |
| 3416 | 3359 | if (renderArgs->_renderSide != RenderArgs::MONO) { |
| 3417 | 3360 | glm::mat4 invView = glm::inverse(_untranslatedViewMatrix); |
| @@ -3548,6 +3491,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 130 unmodified lines | ||
| 3548 | 3491 | |
| 3549 | 3492 | renderContext._maxDrawnOpaqueItems = sceneInterface->getEngineMaxDrawnOpaqueItems(); |
| 3550 | 3493 | renderContext._maxDrawnTransparentItems = sceneInterface->getEngineMaxDrawnTransparentItems(); |
| 3494 | + renderContext._maxDrawnOverlay3DItems = sceneInterface->getEngineMaxDrawnOverlay3DItems(); | |
| 3551 | 3495 | |
| 3552 | 3496 | renderArgs->_shouldRender = LODManager::shouldRender; |
| 3553 | 3497 | |
| @@ -3564,7 +3508,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 10 unmodified lines | ||
| 3564 | 3508 | |
| 3565 | 3509 | sceneInterface->setEngineFeedTransparentItems(engineRC->_numFeedTransparentItems); |
| 3566 | 3510 | sceneInterface->setEngineDrawnTransparentItems(engineRC->_numDrawnTransparentItems); |
| 3567 | − | |
| 3511 | + | |
| 3512 | + sceneInterface->setEngineFeedOverlay3DItems(engineRC->_numFeedOverlay3DItems); | |
| 3513 | + sceneInterface->setEngineDrawnOverlay3DItems(engineRC->_numDrawnOverlay3DItems); | |
| 3568 | 3514 | } |
| 3569 | 3515 | //Render the sixense lasers |
| 3570 | 3516 | if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) { |
| @@ -3672,8 +3618,8 @@ glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) { · 101 unmodified lines | ||
| 3672 | 3618 | // +-----------------------+ |
| 3673 | 3619 | // -1,-1 1,-1 |
| 3674 | 3620 | |
| 3675 | − glm::vec2 screenPoint((projectedPoint.x + 1.0) * horizontalScale, | |
| 3676 | − ((projectedPoint.y + 1.0) * -verticalScale) + _glWidget->getDeviceHeight()); | |
| 3621 | + glm::vec2 screenPoint((projectedPoint.x + 1.0f) * horizontalScale, | |
| 3622 | + ((projectedPoint.y + 1.0f) * -verticalScale) + _glWidget->getDeviceHeight()); | |
| 3677 | 3623 | |
| 3678 | 3624 | return screenPoint; |
| 3679 | 3625 | } |
| @@ -3691,7 +3637,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi · 11 unmodified lines | ||
| 3691 | 3637 | _mirrorCamera.setPosition(_myAvatar->getPosition() + |
| 3692 | 3638 | _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * BILLBOARD_DISTANCE * _myAvatar->getScale()); |
| 3693 | 3639 | |
| 3694 | − } else if (RearMirrorTools::rearViewZoomLevel.get() == BODY) { | |
| 3640 | + } else if (!AvatarInputs::getInstance()->mirrorZoomed()) { | |
| 3695 | 3641 | _mirrorCamera.setPosition(_myAvatar->getChestPosition() + |
| 3696 | 3642 | _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_REARVIEW_BODY_DISTANCE * _myAvatar->getScale()); |
| 3697 | 3643 | |
| @@ -3726,7 +3672,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi · 28 unmodified lines | ||
| 3726 | 3672 | } else { |
| 3727 | 3673 | // if not rendering the billboard, the region is in device independent coordinates; must convert to device |
| 3728 | 3674 | QSize size = DependencyManager::get<TextureCache>()->getFrameBufferSize(); |
| 3729 | − float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale(); | |
| 3675 | + float ratio = (float)QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale(); | |
| 3730 | 3676 | int x = region.x() * ratio, y = region.y() * ratio, width = region.width() * ratio, height = region.height() * ratio; |
| 3731 | 3677 | glViewport(x, size.height() - y - height, width, height); |
| 3732 | 3678 | glScissor(x, size.height() - y - height, width, height); |
| @@ -3741,10 +3687,6 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi · 8 unmodified lines | ||
| 3741 | 3687 | displaySide(renderArgs, _mirrorCamera, true, billboard); |
| 3742 | 3688 | glPopMatrix(); |
| 3743 | 3689 | |
| 3744 | − if (!billboard) { | |
| 3745 | − _rearMirrorTools->render(renderArgs, false, _glWidget->mapFromGlobal(QCursor::pos())); | |
| 3746 | − } | |
| 3747 | − | |
| 3748 | 3690 | // reset Viewport and projection matrix |
| 3749 | 3691 | glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); |
| 3750 | 3692 | glDisable(GL_SCISSOR_TEST); |
| @@ -3884,7 +3826,7 @@ void Application::nodeKilled(SharedNodePointer node) { · 133 unmodified lines | ||
| 3884 | 3826 | _entityServerJurisdictions.unlock(); |
| 3885 | 3827 | |
| 3886 | 3828 | qCDebug(interfaceapp, "model server going away...... v[%f, %f, %f, %f]", |
| 3887 | − rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s); | |
| 3829 | + (double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s); | |
| 3888 | 3830 | |
| 3889 | 3831 | // Add the jurisditionDetails object to the list of "fade outs" |
| 3890 | 3832 | if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnOctreeServerChanges)) { |
| @@ -3970,7 +3912,8 @@ int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePoin · 79 unmodified lines | ||
| 3970 | 3912 | jurisdiction->unlock(); |
| 3971 | 3913 | |
| 3972 | 3914 | qCDebug(interfaceapp, "stats from new %s server... [%f, %f, %f, %f]", |
| 3973 | − qPrintable(serverType), rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s); | |
| 3915 | + qPrintable(serverType), | |
| 3916 | + (double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s); | |
| 3974 | 3917 | |
| 3975 | 3918 | // Add the jurisditionDetails object to the list of "fade outs" |
| 3976 | 3919 | if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnOctreeServerChanges)) { |
| @@ -4750,11 +4693,9 @@ void Application::postLambdaEvent(std::function<void()> f) { · 773 unmodified lines | ||
| 4750 | 4693 | } |
| 4751 | 4694 | |
| 4752 | 4695 | void Application::initPlugins() { |
| 4753 | − OculusManager::init(); | |
| 4754 | 4696 | } |
| 4755 | 4697 | |
| 4756 | 4698 | void Application::shutdownPlugins() { |
| 4757 | − OculusManager::deinit(); | |
| 4758 | 4699 | } |
| 4759 | 4700 | |
| 4760 | 4701 | glm::vec3 Application::getHeadPosition() const { |
| @@ -4774,12 +4715,8 @@ QSize Application::getDeviceSize() const { · 13 unmodified lines | ||
| 4774 | 4715 | return _glWidget->getDeviceSize(); |
| 4775 | 4716 | } |
| 4776 | 4717 | |
| 4777 | −int Application::getTrueMouseX() const { | |
| 4778 | − return _glWidget->mapFromGlobal(QCursor::pos()).x(); | |
| 4779 | −} | |
| 4780 | − | |
| 4781 | −int Application::getTrueMouseY() const { | |
| 4782 | − return _glWidget->mapFromGlobal(QCursor::pos()).y(); | |
| 4718 | +ivec2 Application::getTrueMouse() const { | |
| 4719 | + return toGlm(_glWidget->mapFromGlobal(QCursor::pos())); | |
| 4783 | 4720 | } |
| 4784 | 4721 | |
| 4785 | 4722 | bool Application::isThrottleRendering() const { |
| @@ -4809,3 +4746,25 @@ qreal Application::getDevicePixelRatio() { · 23 unmodified lines | ||
| 4809 | 4746 | return _window ? _window->windowHandle()->devicePixelRatio() : 1.0; |
| 4810 | 4747 | } |
| 4811 | 4748 | |
| 4749 | +mat4 Application::getEyeProjection(int eye) const { | |
| 4750 | + if (isHMDMode()) { | |
| 4751 | + return OculusManager::getEyeProjection(eye); | |
| 4752 | + } | |
| 4753 | + | |
| 4754 | + return _viewFrustum.getProjection(); | |
| 4755 | +} | |
| 4756 | + | |
| 4757 | +mat4 Application::getEyePose(int eye) const { | |
| 4758 | + if (isHMDMode()) { | |
| 4759 | + return OculusManager::getEyePose(eye); | |
| 4760 | + } | |
| 4761 | + | |
| 4762 | + return mat4(); | |
| 4763 | +} | |
| 4764 | + | |
| 4765 | +mat4 Application::getHeadPose() const { | |
| 4766 | + if (isHMDMode()) { | |
| 4767 | + return OculusManager::getHeadPose(); | |
| 4768 | + } | |
| 4769 | + return mat4(); | |
| 4770 | +} | |
| @@ -62,12 +62,12 @@ · 61 unmodified lines | ||
| 62 | 62 | #include "ui/ModelsBrowser.h" |
| 63 | 63 | #include "ui/NodeBounds.h" |
| 64 | 64 | #include "ui/OctreeStatsDialog.h" |
| 65 | −#include "ui/RearMirrorTools.h" | |
| 66 | 65 | #include "ui/SnapshotShareDialog.h" |
| 67 | 66 | #include "ui/LodToolsDialog.h" |
| 68 | 67 | #include "ui/LogDialog.h" |
| 69 | 68 | #include "ui/overlays/Overlays.h" |
| 70 | 69 | #include "ui/ApplicationOverlay.h" |
| 70 | +#include "ui/ApplicationCompositor.h" | |
| 71 | 71 | #include "ui/RunningScriptsWidget.h" |
| 72 | 72 | #include "ui/ToolWindow.h" |
| 73 | 73 | #include "ui/UserInputMapper.h" |
| @@ -221,15 +221,21 @@ public: · 147 unmodified lines | ||
| 221 | 221 | const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; } |
| 222 | 222 | const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; } |
| 223 | 223 | bool mouseOnScreen() const; |
| 224 | − int getMouseX() const; | |
| 225 | − int getMouseY() const; | |
| 226 | − glm::ivec2 getTrueMousePosition() const; | |
| 227 | − int getTrueMouseX() const; | |
| 228 | − int getTrueMouseY() const; | |
| 229 | − int getMouseDragStartedX() const; | |
| 230 | − int getMouseDragStartedY() const; | |
| 231 | − int getTrueMouseDragStartedX() const { return _mouseDragStartedX; } | |
| 232 | − int getTrueMouseDragStartedY() const { return _mouseDragStartedY; } | |
| 224 | + | |
| 225 | + ivec2 getMouse() const; | |
| 226 | + ivec2 getTrueMouse() const; | |
| 227 | + ivec2 getMouseDragStarted() const; | |
| 228 | + ivec2 getTrueMouseDragStarted() const; | |
| 229 | + | |
| 230 | + // TODO get rid of these and use glm types directly | |
| 231 | + int getMouseX() const { return getMouse().x; } | |
| 232 | + int getMouseY() const { return getMouse().y; } | |
| 233 | + int getTrueMouseX() const { return getTrueMouse().x; } | |
| 234 | + int getTrueMouseY() const { return getTrueMouse().y; } | |
| 235 | + int getMouseDragStartedX() const { return getMouseDragStarted().x; } | |
| 236 | + int getMouseDragStartedY() const { return getMouseDragStarted().y; } | |
| 237 | + int getTrueMouseDragStartedX() const { return getTrueMouseDragStarted().x; } | |
| 238 | + int getTrueMouseDragStartedY() const { return getTrueMouseDragStarted().y; } | |
| 233 | 239 | bool getLastMouseMoveWasSimulated() const { return _lastMouseMoveWasSimulated; } |
| 234 | 240 | |
| 235 | 241 | FaceTracker* getActiveFaceTracker(); |
| @@ -238,6 +244,8 @@ public: · 2 unmodified lines | ||
| 238 | 244 | QSystemTrayIcon* getTrayIcon() { return _trayIcon; } |
| 239 | 245 | ApplicationOverlay& getApplicationOverlay() { return _applicationOverlay; } |
| 240 | 246 | const ApplicationOverlay& getApplicationOverlay() const { return _applicationOverlay; } |
| 247 | + ApplicationCompositor& getApplicationCompositor() { return _compositor; } | |
| 248 | + const ApplicationCompositor& getApplicationCompositor() const { return _compositor; } | |
| 241 | 249 | Overlays& getOverlays() { return _overlays; } |
| 242 | 250 | |
| 243 | 251 | float getFps() const { return _fps; } |
| @@ -330,6 +338,9 @@ public: · 86 unmodified lines | ||
| 330 | 338 | bool isHMDMode() const; |
| 331 | 339 | glm::quat getHeadOrientation() const; |
| 332 | 340 | glm::vec3 getHeadPosition() const; |
| 341 | + glm::mat4 getHeadPose() const; | |
| 342 | + glm::mat4 getEyePose(int eye) const; | |
| 343 | + glm::mat4 getEyeProjection(int eye) const; | |
| 333 | 344 | |
| 334 | 345 | QRect getDesirableApplicationGeometry(); |
| 335 | 346 | RunningScriptsWidget* getRunningScriptsWidget() { return _runningScriptsWidget; } |
| @@ -451,6 +462,8 @@ private slots: · 115 unmodified lines | ||
| 451 | 462 | void setFullscreen(bool fullscreen); |
| 452 | 463 | void setEnable3DTVMode(bool enable3DTVMode); |
| 453 | 464 | void setEnableVRMode(bool enableVRMode); |
| 465 | + | |
| 466 | + void rotationModeChanged(); | |
| 454 | 467 | |
| 455 | 468 | glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint); |
| 456 | 469 | |
| @@ -548,21 +561,17 @@ private: · 91 unmodified lines | ||
| 548 | 561 | |
| 549 | 562 | OctreeQuery _octreeQuery; // NodeData derived class for querying octee cells from octree servers |
| 550 | 563 | |
| 551 | − KeyboardMouseDevice _keyboardMouseDevice; // Default input device, the good old keyboard mouse and maybe touchpad | |
| 552 | − | |
| 553 | − UserInputMapper _userInputMapper; // User input mapper allowing to mapp different real devices to the action channels that the application has to offer | |
| 554 | − | |
| 555 | − MyAvatar* _myAvatar; // TODO: move this and relevant code to AvatarManager (or MyAvatar as the case may be) | |
| 556 | − | |
| 557 | − Camera _myCamera; // My view onto the world | |
| 564 | + KeyboardMouseDevice _keyboardMouseDevice; // Default input device, the good old keyboard mouse and maybe touchpad | |
| 565 | + UserInputMapper _userInputMapper; // User input mapper allowing to mapp different real devices to the action channels that the application has to offer | |
| 566 | + MyAvatar* _myAvatar; // TODO: move this and relevant code to AvatarManager (or MyAvatar as the case may be) | |
| 567 | + Camera _myCamera; // My view onto the world | |
| 558 | 568 | Camera _mirrorCamera; // Cammera for mirror view |
| 559 | 569 | QRect _mirrorViewRect; |
| 560 | − RearMirrorTools* _rearMirrorTools; | |
| 561 | 570 | |
| 562 | − Setting::Handle<bool> _firstRun; | |
| 563 | − Setting::Handle<QString> _previousScriptLocation; | |
| 564 | − Setting::Handle<QString> _scriptsLocationHandle; | |
| 565 | − Setting::Handle<float> _fieldOfView; | |
| 571 | + Setting::Handle<bool> _firstRun; | |
| 572 | + Setting::Handle<QString> _previousScriptLocation; | |
| 573 | + Setting::Handle<QString> _scriptsLocationHandle; | |
| 574 | + Setting::Handle<float> _fieldOfView; | |
| 566 | 575 | |
| 567 | 576 | Transform _viewTransform; |
| 568 | 577 | glm::mat4 _untranslatedViewMatrix; |
| @@ -580,18 +589,17 @@ private: · 11 unmodified lines | ||
| 580 | 589 | Environment _environment; |
| 581 | 590 | |
| 582 | 591 | bool _cursorVisible; |
| 583 | − int _mouseDragStartedX; | |
| 584 | − int _mouseDragStartedY; | |
| 592 | + ivec2 _mouseDragStarted; | |
| 593 | + | |
| 585 | 594 | quint64 _lastMouseMove; |
| 586 | 595 | bool _lastMouseMoveWasSimulated; |
| 587 | 596 | |
| 588 | 597 | glm::vec3 _mouseRayOrigin; |
| 589 | 598 | glm::vec3 _mouseRayDirection; |
| 590 | 599 | |
| 591 | − float _touchAvgX; | |
| 592 | − float _touchAvgY; | |
| 593 | − float _touchDragStartedAvgX; | |
| 594 | − float _touchDragStartedAvgY; | |
| 600 | + vec2 _touchAvg; | |
| 601 | + vec2 _touchDragStartedAvg; | |
| 602 | + | |
| 595 | 603 | bool _isTouchPressed; // true if multitouch has been pressed (clear when finished) |
| 596 | 604 | |
| 597 | 605 | bool _mousePressed; // true if mouse has been pressed (clear when finished) |
| @@ -669,6 +677,7 @@ private: · 71 unmodified lines | ||
| 669 | 677 | |
| 670 | 678 | Overlays _overlays; |
| 671 | 679 | ApplicationOverlay _applicationOverlay; |
| 680 | + ApplicationCompositor _compositor; | |
| 672 | 681 | }; |
| 673 | 682 | |
| 674 | 683 | #endif // hifi_Application_h |
| @@ -49,8 +49,6 @@ Camera::Camera() : · 48 unmodified lines | ||
| 49 | 49 | _mode(CAMERA_MODE_THIRD_PERSON), |
| 50 | 50 | _position(0.0f, 0.0f, 0.0f), |
| 51 | 51 | _projection(glm::perspective(glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES), 16.0f/9.0f, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP)), |
| 52 | − _hmdPosition(), | |
| 53 | − _hmdRotation(), | |
| 54 | 52 | _isKeepLookingAt(false), |
| 55 | 53 | _lookingAt(0.0f, 0.0f, 0.0f) |
| 56 | 54 | { |
| @@ -74,20 +72,6 @@ void Camera::setRotation(const glm::quat& rotation) { · 17 unmodified lines | ||
| 74 | 72 | } |
| 75 | 73 | } |
| 76 | 74 | |
| 77 | −void Camera::setHmdPosition(const glm::vec3& hmdPosition) { | |
| 78 | − _hmdPosition = hmdPosition; | |
| 79 | − if (_isKeepLookingAt) { | |
| 80 | − lookAt(_lookingAt); | |
| 81 | − } | |
| 82 | −} | |
| 83 | − | |
| 84 | −void Camera::setHmdRotation(const glm::quat& hmdRotation) { | |
| 85 | − _hmdRotation = hmdRotation; | |
| 86 | − if (_isKeepLookingAt) { | |
| 87 | − lookAt(_lookingAt); | |
| 88 | − } | |
| 89 | −} | |
| 90 | − | |
| 91 | 75 | void Camera::setMode(CameraMode mode) { |
| 92 | 76 | _mode = mode; |
| 93 | 77 | emit modeUpdated(modeToString(mode)); |
| @@ -45,26 +45,22 @@ public: · 44 unmodified lines | ||
| 45 | 45 | |
| 46 | 46 | void setRotation(const glm::quat& rotation); |
| 47 | 47 | void setProjection(const glm::mat4 & projection); |
| 48 | − void setHmdPosition(const glm::vec3& hmdPosition); | |
| 49 | − void setHmdRotation(const glm::quat& hmdRotation); | |
| 50 | 48 | void setMode(CameraMode m); |
| 51 | 49 | |
| 52 | − glm::quat getRotation() const { return _rotation * _hmdRotation; } | |
| 50 | + glm::quat getRotation() const { return _rotation; } | |
| 53 | 51 | const glm::mat4& getProjection() const { return _projection; } |
| 54 | − const glm::vec3& getHmdPosition() const { return _hmdPosition; } | |
| 55 | − const glm::quat& getHmdRotation() const { return _hmdRotation; } | |
| 56 | 52 | CameraMode getMode() const { return _mode; } |
| 57 | 53 | |
| 58 | 54 | public slots: |
| 59 | 55 | QString getModeString() const; |
| 60 | 56 | void setModeString(const QString& mode); |
| 61 | 57 | |
| 62 | − glm::vec3 getPosition() const { return _position + _hmdPosition; } | |
| 58 | + glm::vec3 getPosition() const { return _position; } | |
| 63 | 59 | void setPosition(const glm::vec3& position); |
| 64 | 60 | |
| 65 | − void setOrientation(const glm::quat& orientation) { setRotation(orientation); } | |
| 66 | 61 | glm::quat getOrientation() const { return getRotation(); } |
| 67 | − | |
| 62 | + void setOrientation(const glm::quat& orientation) { setRotation(orientation); } | |
| 63 | + | |
| 68 | 64 | PickRay computePickRay(float x, float y); |
| 69 | 65 | |
| 70 | 66 | // These only work on independent cameras |
| @@ -86,8 +82,6 @@ private: · 15 unmodified lines | ||
| 86 | 82 | glm::vec3 _position; |
| 87 | 83 | glm::quat _rotation; |
| 88 | 84 | glm::mat4 _projection; |
| 89 | − glm::vec3 _hmdPosition; | |
| 90 | − glm::quat _hmdRotation; | |
| 91 | 85 | bool _isKeepLookingAt; |
| 92 | 86 | glm::vec3 _lookingAt; |
| 93 | 87 | }; |
| @@ -39,11 +39,11 @@ bool GLCanvas::isThrottleRendering() const { · 38 unmodified lines | ||
| 39 | 39 | } |
| 40 | 40 | |
| 41 | 41 | int GLCanvas::getDeviceWidth() const { |
| 42 | − return width() * (windowHandle() ? windowHandle()->devicePixelRatio() : 1.0f); | |
| 42 | + return width() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f); | |
| 43 | 43 | } |
| 44 | 44 | |
| 45 | 45 | int GLCanvas::getDeviceHeight() const { |
| 46 | − return height() * (windowHandle() ? windowHandle()->devicePixelRatio() : 1.0f); | |
| 46 | + return height() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f); | |
| 47 | 47 | } |
| 48 | 48 | |
| 49 | 49 | void GLCanvas::initializeGL() { |
| @@ -12,7 +12,7 @@ · 11 unmodified lines | ||
| 12 | 12 | |
| 13 | 13 | |
| 14 | 14 | #include <avatar/AvatarActionHold.h> |
| 15 | −#include <ObjectActionPullToPoint.h> | |
| 15 | +#include <ObjectActionOffset.h> | |
| 16 | 16 | #include <ObjectActionSpring.h> |
| 17 | 17 | |
| 18 | 18 | #include "InterfaceActionFactory.h" |
| @@ -27,8 +27,8 @@ EntityActionPointer InterfaceActionFactory::factory(EntitySimulation* simulation · 8 unmodified lines | ||
| 27 | 27 | switch (type) { |
| 28 | 28 | case ACTION_TYPE_NONE: |
| 29 | 29 | return nullptr; |
| 30 | − case ACTION_TYPE_PULL_TO_POINT: | |
| 31 | − action = (EntityActionPointer) new ObjectActionPullToPoint(id, ownerEntity); | |
| 30 | + case ACTION_TYPE_OFFSET: | |
| 31 | + action = (EntityActionPointer) new ObjectActionOffset(id, ownerEntity); | |
| 32 | 32 | break; |
| 33 | 33 | case ACTION_TYPE_SPRING: |
| 34 | 34 | action = (EntityActionPointer) new ObjectActionSpring(id, ownerEntity); |
| @@ -205,11 +205,11 @@ QString LODManager::getLODFeedbackText() { · 204 unmodified lines | ||
| 205 | 205 | int relativeToTwentyTwenty = 20 / relativeToDefault; |
| 206 | 206 | |
| 207 | 207 | QString result; |
| 208 | − if (relativeToDefault > 1.01) { | |
| 208 | + if (relativeToDefault > 1.01f) { | |
| 209 | 209 | result = QString("20:%1 or %2 times further than average vision%3").arg(relativeToTwentyTwenty).arg(relativeToDefault,0,'f',2).arg(granularityFeedback); |
| 210 | − } else if (relativeToDefault > 0.99) { | |
| 210 | + } else if (relativeToDefault > 0.99f) { | |
| 211 | 211 | result = QString("20:20 or the default distance for average vision%1").arg(granularityFeedback); |
| 212 | − } else if (relativeToDefault > 0.01) { | |
| 212 | + } else if (relativeToDefault > 0.01f) { | |
| 213 | 213 | result = QString("20:%1 or %2 of default distance for average vision%3").arg(relativeToTwentyTwenty).arg(relativeToDefault,0,'f',3).arg(granularityFeedback); |
| 214 | 214 | } else { |
| 215 | 215 | result = QString("%2 of default distance for average vision%3").arg(relativeToDefault,0,'f',3).arg(granularityFeedback); |
| @@ -287,6 +287,12 @@ Menu::Menu() { · 286 unmodified lines | ||
| 287 | 287 | addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, |
| 288 | 288 | 0, //QML Qt::SHIFT | Qt::Key_H, |
| 289 | 289 | true); |
| 290 | + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, | |
| 291 | + 0, // QML Qt::Key_H, | |
| 292 | + false, qApp, SLOT(cameraMenuChanged())); | |
| 293 | + | |
| 294 | + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::CenterPlayerInView, | |
| 295 | + 0, false, qApp, SLOT(rotationModeChanged())); | |
| 290 | 296 | |
| 291 | 297 | addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, |
| 292 | 298 | #ifdef Q_OS_MAC |
| @@ -201,6 +201,7 @@ namespace MenuOption { · 200 unmodified lines | ||
| 201 | 201 | const QString FrameTimer = "Show Timer"; |
| 202 | 202 | const QString Fullscreen = "Fullscreen"; |
| 203 | 203 | const QString FullscreenMirror = "Fullscreen Mirror"; |
| 204 | + const QString CenterPlayerInView = "Center Player In View"; | |
| 204 | 205 | const QString GlowWhenSpeaking = "Glow When Speaking"; |
| 205 | 206 | const QString NamesAboveHeads = "Names Above Heads"; |
| 206 | 207 | const QString HMDTools = "HMD Tools"; |
| @@ -33,19 +33,19 @@ _basePath(basePath), · 32 unmodified lines | ||
| 33 | 33 | _geometry(geometry) |
| 34 | 34 | { |
| 35 | 35 | setWindowTitle("Set Model Properties"); |
| 36 | − | |
| 36 | + | |
| 37 | 37 | QFormLayout* form = new QFormLayout(); |
| 38 | 38 | setLayout(form); |
| 39 | − | |
| 39 | + | |
| 40 | 40 | form->addRow("Name:", _name = new QLineEdit()); |
| 41 | − | |
| 41 | + | |
| 42 | 42 | form->addRow("Texture Directory:", _textureDirectory = new QPushButton()); |
| 43 | 43 | connect(_textureDirectory, SIGNAL(clicked(bool)), SLOT(chooseTextureDirectory())); |
| 44 | − | |
| 44 | + | |
| 45 | 45 | form->addRow("Scale:", _scale = new QDoubleSpinBox()); |
| 46 | 46 | _scale->setMaximum(FLT_MAX); |
| 47 | 47 | _scale->setSingleStep(0.01); |
| 48 | − | |
| 48 | + | |
| 49 | 49 | if (_modelType != FSTReader::ENTITY_MODEL) { |
| 50 | 50 | if (_modelType == FSTReader::ATTACHMENT_MODEL) { |
| 51 | 51 | QHBoxLayout* translation = new QHBoxLayout(); |
| @@ -57,7 +57,7 @@ _geometry(geometry) · 5 unmodified lines | ||
| 57 | 57 | form->addRow("Pivot Joint:", _pivotJoint = createJointBox()); |
| 58 | 58 | connect(_pivotAboutCenter, SIGNAL(toggled(bool)), SLOT(updatePivotJoint())); |
| 59 | 59 | _pivotAboutCenter->setChecked(true); |
| 60 | − | |
| 60 | + | |
| 61 | 61 | } else { |
| 62 | 62 | form->addRow("Left Eye Joint:", _leftEyeJoint = createJointBox()); |
| 63 | 63 | form->addRow("Right Eye Joint:", _rightEyeJoint = createJointBox()); |
| @@ -69,22 +69,22 @@ _geometry(geometry) · 5 unmodified lines | ||
| 69 | 69 | form->addRow("Head Joint:", _headJoint = createJointBox()); |
| 70 | 70 | form->addRow("Left Hand Joint:", _leftHandJoint = createJointBox()); |
| 71 | 71 | form->addRow("Right Hand Joint:", _rightHandJoint = createJointBox()); |
| 72 | − | |
| 72 | + | |
| 73 | 73 | form->addRow("Free Joints:", _freeJoints = new QVBoxLayout()); |
| 74 | 74 | QPushButton* newFreeJoint = new QPushButton("New Free Joint"); |
| 75 | 75 | _freeJoints->addWidget(newFreeJoint); |
| 76 | 76 | connect(newFreeJoint, SIGNAL(clicked(bool)), SLOT(createNewFreeJoint())); |
| 77 | 77 | } |
| 78 | 78 | } |
| 79 | − | |
| 79 | + | |
| 80 | 80 | QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | |
| 81 | 81 | QDialogButtonBox::Cancel | QDialogButtonBox::Reset); |
| 82 | 82 | connect(buttons, SIGNAL(accepted()), SLOT(accept())); |
| 83 | 83 | connect(buttons, SIGNAL(rejected()), SLOT(reject())); |
| 84 | 84 | connect(buttons->button(QDialogButtonBox::Reset), SIGNAL(clicked(bool)), SLOT(reset())); |
| 85 | − | |
| 85 | + | |
| 86 | 86 | form->addRow(buttons); |
| 87 | − | |
| 87 | + | |
| 88 | 88 | // reset to initialize the fields |
| 89 | 89 | reset(); |
| 90 | 90 | } |
| @@ -100,42 +100,42 @@ QVariantHash ModelPropertiesDialog::getMapping() const { · 9 unmodified lines | ||
| 100 | 100 | mapping.insert(NAME_FIELD, _name->text()); |
| 101 | 101 | mapping.insert(TEXDIR_FIELD, _textureDirectory->text()); |
| 102 | 102 | mapping.insert(SCALE_FIELD, QString::number(_scale->value())); |
| 103 | − | |
| 103 | + | |
| 104 | 104 | // update the joint indices |
| 105 | 105 | QVariantHash jointIndices; |
| 106 | 106 | for (int i = 0; i < _geometry.joints.size(); i++) { |
| 107 | 107 | jointIndices.insert(_geometry.joints.at(i).name, QString::number(i)); |
| 108 | 108 | } |
| 109 | 109 | mapping.insert(JOINT_INDEX_FIELD, jointIndices); |
| 110 | − | |
| 110 | + | |
| 111 | 111 | if (_modelType != FSTReader::ENTITY_MODEL) { |
| 112 | 112 | QVariantHash joints = mapping.value(JOINT_FIELD).toHash(); |
| 113 | 113 | if (_modelType == FSTReader::ATTACHMENT_MODEL) { |
| 114 | 114 | glm::vec3 pivot; |
| 115 | 115 | if (_pivotAboutCenter->isChecked()) { |
| 116 | 116 | pivot = (_geometry.meshExtents.minimum + _geometry.meshExtents.maximum) * 0.5f; |
| 117 | − | |
| 117 | + | |
| 118 | 118 | } else if (_pivotJoint->currentIndex() != 0) { |
| 119 | 119 | pivot = extractTranslation(_geometry.joints.at(_pivotJoint->currentIndex() - 1).transform); |
| 120 | 120 | } |
| 121 | − mapping.insert(TRANSLATION_X_FIELD, -pivot.x * _scale->value() + _translationX->value()); | |
| 122 | − mapping.insert(TRANSLATION_Y_FIELD, -pivot.y * _scale->value() + _translationY->value()); | |
| 123 | − mapping.insert(TRANSLATION_Z_FIELD, -pivot.z * _scale->value() + _translationZ->value()); | |
| 124 | − | |
| 121 | + mapping.insert(TRANSLATION_X_FIELD, -pivot.x * (float)_scale->value() + (float)_translationX->value()); | |
| 122 | + mapping.insert(TRANSLATION_Y_FIELD, -pivot.y * (float)_scale->value() + (float)_translationY->value()); | |
| 123 | + mapping.insert(TRANSLATION_Z_FIELD, -pivot.z * (float)_scale->value() + (float)_translationZ->value()); | |
| 124 | + | |
| 125 | 125 | } else { |
| 126 | 126 | insertJointMapping(joints, "jointEyeLeft", _leftEyeJoint->currentText()); |
| 127 | 127 | insertJointMapping(joints, "jointEyeRight", _rightEyeJoint->currentText()); |
| 128 | 128 | insertJointMapping(joints, "jointNeck", _neckJoint->currentText()); |
| 129 | 129 | } |
| 130 | − | |
| 131 | − | |
| 130 | + | |
| 131 | + | |
| 132 | 132 | if (_modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL) { |
| 133 | 133 | insertJointMapping(joints, "jointRoot", _rootJoint->currentText()); |
| 134 | 134 | insertJointMapping(joints, "jointLean", _leanJoint->currentText()); |
| 135 | 135 | insertJointMapping(joints, "jointHead", _headJoint->currentText()); |
| 136 | 136 | insertJointMapping(joints, "jointLeftHand", _leftHandJoint->currentText()); |
| 137 | 137 | insertJointMapping(joints, "jointRightHand", _rightHandJoint->currentText()); |
| 138 | − | |
| 138 | + | |
| 139 | 139 | mapping.remove(FREE_JOINT_FIELD); |
| 140 | 140 | for (int i = 0; i < _freeJoints->count() - 1; i++) { |
| 141 | 141 | QComboBox* box = static_cast<QComboBox*>(_freeJoints->itemAt(i)->widget()->layout()->itemAt(0)->widget()); |
| @@ -144,7 +144,7 @@ QVariantHash ModelPropertiesDialog::getMapping() const { · 2 unmodified lines | ||
| 144 | 144 | } |
| 145 | 145 | mapping.insert(JOINT_FIELD, joints); |
| 146 | 146 | } |
| 147 | − | |
| 147 | + | |
| 148 | 148 | return mapping; |
| 149 | 149 | } |
| 150 | 150 | |
| @@ -156,9 +156,9 @@ void ModelPropertiesDialog::reset() { · 5 unmodified lines | ||
| 156 | 156 | _name->setText(_originalMapping.value(NAME_FIELD).toString()); |
| 157 | 157 | _textureDirectory->setText(_originalMapping.value(TEXDIR_FIELD).toString()); |
| 158 | 158 | _scale->setValue(_originalMapping.value(SCALE_FIELD).toDouble()); |
| 159 | − | |
| 159 | + | |
| 160 | 160 | QVariantHash jointHash = _originalMapping.value(JOINT_FIELD).toHash(); |
| 161 | − | |
| 161 | + | |
| 162 | 162 | if (_modelType != FSTReader::ENTITY_MODEL) { |
| 163 | 163 | if (_modelType == FSTReader::ATTACHMENT_MODEL) { |
| 164 | 164 | _translationX->setValue(_originalMapping.value(TRANSLATION_X_FIELD).toDouble()); |
| @@ -166,20 +166,20 @@ void ModelPropertiesDialog::reset() { · 1 unmodified line | ||
| 166 | 166 | _translationZ->setValue(_originalMapping.value(TRANSLATION_Z_FIELD).toDouble()); |
| 167 | 167 | _pivotAboutCenter->setChecked(true); |
| 168 | 168 | _pivotJoint->setCurrentIndex(0); |
| 169 | − | |
| 169 | + | |
| 170 | 170 | } else { |
| 171 | 171 | setJointText(_leftEyeJoint, jointHash.value("jointEyeLeft").toString()); |
| 172 | 172 | setJointText(_rightEyeJoint, jointHash.value("jointEyeRight").toString()); |
| 173 | 173 | setJointText(_neckJoint, jointHash.value("jointNeck").toString()); |
| 174 | 174 | } |
| 175 | − | |
| 175 | + | |
| 176 | 176 | if (_modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL) { |
| 177 | 177 | setJointText(_rootJoint, jointHash.value("jointRoot").toString()); |
| 178 | 178 | setJointText(_leanJoint, jointHash.value("jointLean").toString()); |
| 179 | 179 | setJointText(_headJoint, jointHash.value("jointHead").toString()); |
| 180 | 180 | setJointText(_leftHandJoint, jointHash.value("jointLeftHand").toString()); |
| 181 | 181 | setJointText(_rightHandJoint, jointHash.value("jointRightHand").toString()); |
| 182 | − | |
| 182 | + | |
| 183 | 183 | while (_freeJoints->count() > 1) { |
| 184 | 184 | delete _freeJoints->itemAt(0)->widget(); |
| 185 | 185 | } |
| @@ -16,13 +16,13 @@ · 15 unmodified lines | ||
| 16 | 16 | #include "InterfaceConfig.h" |
| 17 | 17 | #include "starfield/Controller.h" |
| 18 | 18 | |
| 19 | −Stars::Stars() : | |
| 19 | +Stars::Stars() : | |
| 20 | 20 | _controller(0l), _starsLoaded(false) { |
| 21 | 21 | _controller = new starfield::Controller; |
| 22 | 22 | } |
| 23 | 23 | |
| 24 | −Stars::~Stars() { | |
| 25 | − delete _controller; | |
| 24 | +Stars::~Stars() { | |
| 25 | + delete _controller; | |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | 28 | bool Stars::generate(unsigned numStars, unsigned seed) { |
| @@ -30,22 +30,20 @@ bool Stars::generate(unsigned numStars, unsigned seed) { · 1 unmodified line | ||
| 30 | 30 | return _starsLoaded; |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | −bool Stars::setResolution(unsigned k) { | |
| 34 | − return _controller->setResolution(k); | |
| 33 | +bool Stars::setResolution(unsigned k) { | |
| 34 | + return _controller->setResolution(k); | |
| 35 | 35 | } |
| 36 | 36 | |
| 37 | 37 | void Stars::render(float fovY, float aspect, float nearZ, float alpha) { |
| 38 | 38 | // determine length of screen diagonal from quadrant height and aspect ratio |
| 39 | − float quadrantHeight = nearZ * tan(RADIANS_PER_DEGREE * fovY * 0.5f); | |
| 39 | + float quadrantHeight = nearZ * tanf(RADIANS_PER_DEGREE * fovY * 0.5f); | |
| 40 | 40 | float halfDiagonal = sqrt(quadrantHeight * quadrantHeight * (1.0f + aspect * aspect)); |
| 41 | 41 | |
| 42 | 42 | // determine fov angle in respect to the diagonal |
| 43 | − float fovDiagonal = atan(halfDiagonal / nearZ) * 2.0f; | |
| 43 | + float fovDiagonal = atanf(halfDiagonal / nearZ) * 2.0f; | |
| 44 | 44 | |
| 45 | 45 | // pull the modelview matrix off the GL stack |
| 46 | − glm::mat4 view; glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view)); | |
| 46 | + glm::mat4 view; glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view)); | |
| 47 | 47 | |
| 48 | 48 | _controller->render(fovDiagonal, aspect, glm::affineInverse(view), alpha); |
| 49 | 49 | } |
| 50 | − | |
| 51 | − | |
| @@ -70,6 +70,6 @@ void UIUtil::internalScaleWidgetFontSizes(QWidget* widget, float scale) { · 69 unmodified lines | ||
| 70 | 70 | } |
| 71 | 71 | |
| 72 | 72 | QFont font = widget->font(); |
| 73 | − font.setPointSizeF(font.pointSizeF() * scale); | |
| 73 | + font.setPointSizeF(font.pointSizeF() * (double)scale); | |
| 74 | 74 | widget->setFont(font); |
| 75 | 75 | } |
| @@ -41,7 +41,7 @@ void renderWorldBox(gpu::Batch& batch) { · 40 unmodified lines | ||
| 41 | 41 | static const glm::vec3 green(0.0f, 1.0f, 0.0f); |
| 42 | 42 | static const glm::vec3 blue(0.0f, 0.0f, 1.0f); |
| 43 | 43 | static const glm::vec3 grey(0.5f, 0.5f, 0.5f); |
| 44 | − | |
| 44 | + | |
| 45 | 45 | auto transform = Transform{}; |
| 46 | 46 | batch.setModelTransform(transform); |
| 47 | 47 | geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(TREE_SCALE, 0.0f, 0.0f), red); |
| @@ -49,13 +49,13 @@ void renderWorldBox(gpu::Batch& batch) { · 1 unmodified line | ||
| 49 | 49 | geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, TREE_SCALE), blue); |
| 50 | 50 | geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, TREE_SCALE), glm::vec3(TREE_SCALE, 0.0f, TREE_SCALE), grey); |
| 51 | 51 | geometryCache->renderLine(batch, glm::vec3(TREE_SCALE, 0.0f, TREE_SCALE), glm::vec3(TREE_SCALE, 0.0f, 0.0f), grey); |
| 52 | − | |
| 52 | + | |
| 53 | 53 | // Draw meter markers along the 3 axis to help with measuring things |
| 54 | 54 | const float MARKER_DISTANCE = 1.0f; |
| 55 | 55 | const float MARKER_RADIUS = 0.05f; |
| 56 | − | |
| 56 | + | |
| 57 | 57 | geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, red); |
| 58 | − | |
| 58 | + | |
| 59 | 59 | transform.setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, 0.0f)); |
| 60 | 60 | batch.setModelTransform(transform); |
| 61 | 61 | geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, red); |
| @@ -79,10 +79,10 @@ const glm::vec3 randVector() { · 17 unmodified lines | ||
| 79 | 79 | } |
| 80 | 80 | |
| 81 | 81 | static TextRenderer* textRenderer(int mono) { |
| 82 | − static TextRenderer* monoRenderer = TextRenderer::getInstance(MONO_FONT_FAMILY); | |
| 82 | + static TextRenderer* monoRenderer = TextRenderer::getInstance(MONO_FONT_FAMILY); | |
| 83 | 83 | static TextRenderer* proportionalRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, |
| 84 | 84 | -1, -1, false, TextRenderer::SHADOW_EFFECT); |
| 85 | − static TextRenderer* inconsolataRenderer = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, -1, INCONSOLATA_FONT_WEIGHT, | |
| 85 | + static TextRenderer* inconsolataRenderer = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, -1, INCONSOLATA_FONT_WEIGHT, | |
| 86 | 86 | false); |
| 87 | 87 | switch (mono) { |
| 88 | 88 | case 1: |
| @@ -133,46 +133,46 @@ void runTimingTests() { · 44 unmodified lines | ||
| 133 | 133 | QElapsedTimer startTime; |
| 134 | 134 | startTime.start(); |
| 135 | 135 | float elapsedUsecs; |
| 136 | − | |
| 136 | + | |
| 137 | 137 | float NSEC_TO_USEC = 1.0f / 1000.0f; |
| 138 | 138 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 139 | − qCDebug(interfaceapp, "QElapsedTimer::nsecElapsed() usecs: %f", elapsedUsecs); | |
| 140 | − | |
| 139 | + qCDebug(interfaceapp, "QElapsedTimer::nsecElapsed() usecs: %f", (double)elapsedUsecs); | |
| 140 | + | |
| 141 | 141 | // Test sleep functions for accuracy |
| 142 | 142 | startTime.start(); |
| 143 | 143 | QThread::msleep(1); |
| 144 | 144 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 145 | − qCDebug(interfaceapp, "QThread::msleep(1) ms: %f", elapsedUsecs / 1000.0f); | |
| 145 | + qCDebug(interfaceapp, "QThread::msleep(1) ms: %f", (double)(elapsedUsecs / 1000.0f)); | |
| 146 | 146 | |
| 147 | 147 | startTime.start(); |
| 148 | 148 | QThread::sleep(1); |
| 149 | 149 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 150 | − qCDebug(interfaceapp, "QThread::sleep(1) ms: %f", elapsedUsecs / 1000.0f); | |
| 150 | + qCDebug(interfaceapp, "QThread::sleep(1) ms: %f", (double)(elapsedUsecs / 1000.0f)); | |
| 151 | 151 | |
| 152 | 152 | startTime.start(); |
| 153 | 153 | usleep(1); |
| 154 | 154 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 155 | − qCDebug(interfaceapp, "usleep(1) ms: %f", elapsedUsecs / 1000.0f); | |
| 155 | + qCDebug(interfaceapp, "usleep(1) ms: %f", (double)(elapsedUsecs / 1000.0f)); | |
| 156 | 156 | |
| 157 | 157 | startTime.start(); |
| 158 | 158 | usleep(10); |
| 159 | 159 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 160 | − qCDebug(interfaceapp, "usleep(10) ms: %f", elapsedUsecs / 1000.0f); | |
| 160 | + qCDebug(interfaceapp, "usleep(10) ms: %f", (double)(elapsedUsecs / 1000.0f)); | |
| 161 | 161 | |
| 162 | 162 | startTime.start(); |
| 163 | 163 | usleep(100); |
| 164 | 164 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 165 | − qCDebug(interfaceapp, "usleep(100) ms: %f", elapsedUsecs / 1000.0f); | |
| 165 | + qCDebug(interfaceapp, "usleep(100) ms: %f", (double)(elapsedUsecs / 1000.0f)); | |
| 166 | 166 | |
| 167 | 167 | startTime.start(); |
| 168 | 168 | usleep(1000); |
| 169 | 169 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 170 | − qCDebug(interfaceapp, "usleep(1000) ms: %f", elapsedUsecs / 1000.0f); | |
| 170 | + qCDebug(interfaceapp, "usleep(1000) ms: %f", (double)(elapsedUsecs / 1000.0f)); | |
| 171 | 171 | |
| 172 | 172 | startTime.start(); |
| 173 | 173 | usleep(15000); |
| 174 | 174 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 175 | − qCDebug(interfaceapp, "usleep(15000) ms: %f", elapsedUsecs / 1000.0f); | |
| 175 | + qCDebug(interfaceapp, "usleep(15000) ms: %f", (double)(elapsedUsecs / 1000.0f)); | |
| 176 | 176 | |
| 177 | 177 | // Random number generation |
| 178 | 178 | startTime.start(); |
| @@ -180,7 +180,8 @@ void runTimingTests() { · 1 unmodified line | ||
| 180 | 180 | iResults[i] = rand(); |
| 181 | 181 | } |
| 182 | 182 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 183 | − qCDebug(interfaceapp, "rand() stored in array usecs: %f, first result:%d", elapsedUsecs / (float) numTests, iResults[0]); | |
| 183 | + qCDebug(interfaceapp, "rand() stored in array usecs: %f, first result:%d", | |
| 184 | + (double)(elapsedUsecs / numTests), iResults[0]); | |
| 184 | 185 | |
| 185 | 186 | // Random number generation using randFloat() |
| 186 | 187 | startTime.start(); |
| @@ -188,7 +189,8 @@ void runTimingTests() { · 1 unmodified line | ||
| 188 | 189 | fResults[i] = randFloat(); |
| 189 | 190 | } |
| 190 | 191 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 191 | − qCDebug(interfaceapp, "randFloat() stored in array usecs: %f, first result: %f", elapsedUsecs / (float) numTests, fResults[0]); | |
| 192 | + qCDebug(interfaceapp, "randFloat() stored in array usecs: %f, first result: %f", | |
| 193 | + (double)(elapsedUsecs / numTests), (double)(fResults[0])); | |
| 192 | 194 | |
| 193 | 195 | free(iResults); |
| 194 | 196 | free(fResults); |
| @@ -200,7 +202,7 @@ void runTimingTests() { · 5 unmodified lines | ||
| 200 | 202 | fTest = powf(fTest, 0.5f); |
| 201 | 203 | } |
| 202 | 204 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 203 | − qCDebug(interfaceapp, "powf(f, 0.5) usecs: %f", elapsedUsecs / (float) numTests); | |
| 205 | + qCDebug(interfaceapp, "powf(f, 0.5) usecs: %f", (double)(elapsedUsecs / (float) numTests)); | |
| 204 | 206 | |
| 205 | 207 | // Vector Math |
| 206 | 208 | float distance; |
| @@ -213,19 +215,20 @@ void runTimingTests() { · 6 unmodified lines | ||
| 213 | 215 | } |
| 214 | 216 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 215 | 217 | qCDebug(interfaceapp, "vector math usecs: %f [%f usecs total for %d tests], last result:%f", |
| 216 | − elapsedUsecs / (float) numTests, elapsedUsecs, numTests, distance); | |
| 218 | + (double)(elapsedUsecs / (float) numTests), (double)elapsedUsecs, numTests, (double)distance); | |
| 217 | 219 | |
| 218 | 220 | // Vec3 test |
| 219 | 221 | glm::vec3 vecA(randVector()), vecB(randVector()); |
| 220 | 222 | float result; |
| 221 | − | |
| 223 | + | |
| 222 | 224 | startTime.start(); |
| 223 | 225 | for (int i = 0; i < numTests; i++) { |
| 224 | 226 | glm::vec3 temp = vecA-vecB; |
| 225 | 227 | result = glm::dot(temp,temp); |
| 226 | 228 | } |
| 227 | 229 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 228 | − qCDebug(interfaceapp, "vec3 assign and dot() usecs: %f, last result:%f", elapsedUsecs / (float) numTests, result); | |
| 230 | + qCDebug(interfaceapp, "vec3 assign and dot() usecs: %f, last result:%f", | |
| 231 | + (double)(elapsedUsecs / numTests), (double)result); | |
| 229 | 232 | } |
| 230 | 233 | |
| 231 | 234 | bool rayIntersectsSphere(const glm::vec3& rayStarting, const glm::vec3& rayNormalizedDirection, |
| @@ -41,32 +41,32 @@ void AudioIOStatsRenderer::render(const float* color, int width, int height) { · 40 unmodified lines | ||
| 41 | 41 | if (!_isEnabled) { |
| 42 | 42 | return; |
| 43 | 43 | } |
| 44 | − | |
| 44 | + | |
| 45 | 45 | const int linesWhenCentered = _shouldShowInjectedStreams ? 34 : 27; |
| 46 | 46 | const int CENTERED_BACKGROUND_HEIGHT = STATS_HEIGHT_PER_LINE * linesWhenCentered; |
| 47 | − | |
| 47 | + | |
| 48 | 48 | int lines = _shouldShowInjectedStreams ? _stats->getMixerInjectedStreamStatsMap().size() * 7 + 27 : 27; |
| 49 | 49 | int statsHeight = STATS_HEIGHT_PER_LINE * lines; |
| 50 | − | |
| 51 | − | |
| 50 | + | |
| 51 | + | |
| 52 | 52 | static const glm::vec4 backgroundColor = { 0.2f, 0.2f, 0.2f, 0.6f }; |
| 53 | 53 | int x = std::max((width - (int)STATS_WIDTH) / 2, 0); |
| 54 | 54 | int y = std::max((height - CENTERED_BACKGROUND_HEIGHT) / 2, 0); |
| 55 | 55 | int w = STATS_WIDTH; |
| 56 | 56 | int h = statsHeight; |
| 57 | 57 | DependencyManager::get<GeometryCache>()->renderQuad(x, y, w, h, backgroundColor); |
| 58 | − | |
| 58 | + | |
| 59 | 59 | int horizontalOffset = x + 5; |
| 60 | 60 | int verticalOffset = y; |
| 61 | − | |
| 61 | + | |
| 62 | 62 | float scale = 0.10f; |
| 63 | 63 | float rotation = 0.0f; |
| 64 | 64 | int font = 2; |
| 65 | − | |
| 65 | + | |
| 66 | 66 | char latencyStatString[512]; |
| 67 | − | |
| 67 | + | |
| 68 | 68 | float audioInputBufferLatency = 0.0f, inputRingBufferLatency = 0.0f, networkRoundtripLatency = 0.0f, mixerRingBufferLatency = 0.0f, outputRingBufferLatency = 0.0f, audioOutputBufferLatency = 0.0f; |
| 69 | − | |
| 69 | + | |
| 70 | 70 | AudioStreamStats downstreamAudioStreamStats = _stats->getMixerDownstreamStats(); |
| 71 | 71 | SharedNodePointer audioMixerNodePointer = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::AudioMixer); |
| 72 | 72 | if (!audioMixerNodePointer.isNull()) { |
| @@ -78,48 +78,62 @@ void AudioIOStatsRenderer::render(const float* color, int width, int height) { · 5 unmodified lines | ||
| 78 | 78 | audioOutputBufferLatency = _stats->getAudioOutputMsecsUnplayedStats().getWindowAverage(); |
| 79 | 79 | } |
| 80 | 80 | float totalLatency = audioInputBufferLatency + inputRingBufferLatency + networkRoundtripLatency + mixerRingBufferLatency + outputRingBufferLatency + audioOutputBufferLatency; |
| 81 | − | |
| 82 | − sprintf(latencyStatString, " Audio input buffer: %7.2fms - avg msecs of samples read to the input ring buffer in last 10s", audioInputBufferLatency); | |
| 81 | + | |
| 82 | + sprintf(latencyStatString, | |
| 83 | + " Audio input buffer: %7.2fms - avg msecs of samples read to the input ring buffer in last 10s", | |
| 84 | + (double)audioInputBufferLatency); | |
| 83 | 85 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 84 | 86 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 85 | − | |
| 86 | − sprintf(latencyStatString, " Input ring buffer: %7.2fms - avg msecs of samples in input ring buffer in last 10s", inputRingBufferLatency); | |
| 87 | + | |
| 88 | + sprintf(latencyStatString, | |
| 89 | + " Input ring buffer: %7.2fms - avg msecs of samples in input ring buffer in last 10s", | |
| 90 | + (double)inputRingBufferLatency); | |
| 87 | 91 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 88 | 92 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 89 | − | |
| 90 | − sprintf(latencyStatString, " Network to mixer: %7.2fms - half of last ping value calculated by the node list", networkRoundtripLatency / 2.0f); | |
| 93 | + | |
| 94 | + sprintf(latencyStatString, | |
| 95 | + " Network to mixer: %7.2fms - half of last ping value calculated by the node list", | |
| 96 | + (double)(networkRoundtripLatency / 2.0f)); | |
| 91 | 97 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 92 | 98 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 93 | − | |
| 94 | − sprintf(latencyStatString, " AudioMixer ring buffer: %7.2fms - avg msecs of samples in audio mixer's ring buffer in last 10s", mixerRingBufferLatency); | |
| 99 | + | |
| 100 | + sprintf(latencyStatString, | |
| 101 | + " AudioMixer ring buffer: %7.2fms - avg msecs of samples in audio mixer's ring buffer in last 10s", | |
| 102 | + (double)mixerRingBufferLatency); | |
| 95 | 103 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 96 | 104 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 97 | − | |
| 98 | − sprintf(latencyStatString, " Network to client: %7.2fms - half of last ping value calculated by the node list", networkRoundtripLatency / 2.0f); | |
| 105 | + | |
| 106 | + sprintf(latencyStatString, | |
| 107 | + " Network to client: %7.2fms - half of last ping value calculated by the node list", | |
| 108 | + (double)(networkRoundtripLatency / 2.0f)); | |
| 99 | 109 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 100 | 110 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 101 | − | |
| 102 | − sprintf(latencyStatString, " Output ring buffer: %7.2fms - avg msecs of samples in output ring buffer in last 10s", outputRingBufferLatency); | |
| 111 | + | |
| 112 | + sprintf(latencyStatString, | |
| 113 | + " Output ring buffer: %7.2fms - avg msecs of samples in output ring buffer in last 10s", | |
| 114 | + (double)outputRingBufferLatency); | |
| 103 | 115 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 104 | 116 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 105 | − | |
| 106 | − sprintf(latencyStatString, " Audio output buffer: %7.2fms - avg msecs of samples in audio output buffer in last 10s", audioOutputBufferLatency); | |
| 117 | + | |
| 118 | + sprintf(latencyStatString, | |
| 119 | + " Audio output buffer: %7.2fms - avg msecs of samples in audio output buffer in last 10s", | |
| 120 | + (double)audioOutputBufferLatency); | |
| 107 | 121 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 108 | 122 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 109 | − | |
| 110 | − sprintf(latencyStatString, " TOTAL: %7.2fms\n", totalLatency); | |
| 123 | + | |
| 124 | + sprintf(latencyStatString, " TOTAL: %7.2fms\n", (double)totalLatency); | |
| 111 | 125 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 112 | 126 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 113 | − | |
| 114 | − | |
| 127 | + | |
| 128 | + | |
| 115 | 129 | verticalOffset += STATS_HEIGHT_PER_LINE; // blank line |
| 116 | − | |
| 130 | + | |
| 117 | 131 | char clientUpstreamMicLabelString[] = "Upstream Mic Audio Packets Sent Gaps (by client):"; |
| 118 | 132 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 119 | 133 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, clientUpstreamMicLabelString, color); |
| 120 | − | |
| 134 | + | |
| 121 | 135 | const MovingMinMaxAvg<quint64>& packetSentTimeGaps = _stats->getPacketSentTimeGaps(); |
| 122 | − | |
| 136 | + | |
| 123 | 137 | char stringBuffer[512]; |
| 124 | 138 | sprintf(stringBuffer, " Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s", |
| 125 | 139 | formatUsecTime(packetSentTimeGaps.getMin()).toLatin1().data(), |
| @@ -127,47 +141,47 @@ void AudioIOStatsRenderer::render(const float* color, int width, int height) { · 1 unmodified line | ||
| 127 | 141 | formatUsecTime(packetSentTimeGaps.getAverage()).toLatin1().data()); |
| 128 | 142 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 129 | 143 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); |
| 130 | − | |
| 144 | + | |
| 131 | 145 | sprintf(stringBuffer, " Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s", |
| 132 | 146 | formatUsecTime(packetSentTimeGaps.getWindowMin()).toLatin1().data(), |
| 133 | 147 | formatUsecTime(packetSentTimeGaps.getWindowMax()).toLatin1().data(), |
| 134 | 148 | formatUsecTime(packetSentTimeGaps.getWindowAverage()).toLatin1().data()); |
| 135 | 149 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 136 | 150 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); |
| 137 | − | |
| 151 | + | |
| 138 | 152 | verticalOffset += STATS_HEIGHT_PER_LINE; // blank line |
| 139 | − | |
| 153 | + | |
| 140 | 154 | char upstreamMicLabelString[] = "Upstream mic audio stats (received and reported by audio-mixer):"; |
| 141 | 155 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 142 | 156 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamMicLabelString, color); |
| 143 | − | |
| 157 | + | |
| 144 | 158 | renderAudioStreamStats(&_stats->getMixerAvatarStreamStats(), horizontalOffset, verticalOffset, |
| 145 | 159 | scale, rotation, font, color); |
| 146 | − | |
| 147 | − | |
| 160 | + | |
| 161 | + | |
| 148 | 162 | verticalOffset += STATS_HEIGHT_PER_LINE; // blank line |
| 149 | − | |
| 163 | + | |
| 150 | 164 | char downstreamLabelString[] = "Downstream mixed audio stats:"; |
| 151 | 165 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 152 | 166 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, downstreamLabelString, color); |
| 153 | − | |
| 167 | + | |
| 154 | 168 | AudioStreamStats downstreamStats = _stats->getMixerDownstreamStats(); |
| 155 | 169 | renderAudioStreamStats(&downstreamStats, horizontalOffset, verticalOffset, |
| 156 | 170 | scale, rotation, font, color, true); |
| 157 | − | |
| 158 | − | |
| 171 | + | |
| 172 | + | |
| 159 | 173 | if (_shouldShowInjectedStreams) { |
| 160 | − | |
| 174 | + | |
| 161 | 175 | foreach(const AudioStreamStats& injectedStreamAudioStats, _stats->getMixerInjectedStreamStatsMap()) { |
| 162 | − | |
| 176 | + | |
| 163 | 177 | verticalOffset += STATS_HEIGHT_PER_LINE; // blank line |
| 164 | − | |
| 178 | + | |
| 165 | 179 | char upstreamInjectedLabelString[512]; |
| 166 | 180 | sprintf(upstreamInjectedLabelString, "Upstream injected audio stats: stream ID: %s", |
| 167 | 181 | injectedStreamAudioStats._streamIdentifier.toString().toLatin1().data()); |
| 168 | 182 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 169 | 183 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamInjectedLabelString, color); |
| 170 | − | |
| 184 | + | |
| 171 | 185 | renderAudioStreamStats(&injectedStreamAudioStats, horizontalOffset, verticalOffset, scale, rotation, font, color); |
| 172 | 186 | } |
| 173 | 187 | } |
| @@ -175,22 +189,22 @@ void AudioIOStatsRenderer::render(const float* color, int width, int height) { · 1 unmodified line | ||
| 175 | 189 | |
| 176 | 190 | void AudioIOStatsRenderer::renderAudioStreamStats(const AudioStreamStats* streamStats, int horizontalOffset, int& verticalOffset, |
| 177 | 191 | float scale, float rotation, int font, const float* color, bool isDownstreamStats) { |
| 178 | − | |
| 192 | + | |
| 179 | 193 | char stringBuffer[512]; |
| 180 | − | |
| 194 | + | |
| 181 | 195 | sprintf(stringBuffer, " Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)", |
| 182 | − streamStats->_packetStreamStats.getLostRate() * 100.0f, | |
| 196 | + (double)(streamStats->_packetStreamStats.getLostRate() * 100.0f), | |
| 183 | 197 | streamStats->_packetStreamStats._lost, |
| 184 | − streamStats->_packetStreamWindowStats.getLostRate() * 100.0f, | |
| 198 | + (double)(streamStats->_packetStreamWindowStats.getLostRate() * 100.0f), | |
| 185 | 199 | streamStats->_packetStreamWindowStats._lost); |
| 186 | 200 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 187 | 201 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); |
| 188 | − | |
| 202 | + | |
| 189 | 203 | if (isDownstreamStats) { |
| 190 | 204 | sprintf(stringBuffer, " Ringbuffer frames | desired: %u, avg_available(10s): %u+%d, available: %u+%d", |
| 191 | 205 | streamStats->_desiredJitterBufferFrames, |
| 192 | 206 | streamStats->_framesAvailableAverage, |
| 193 | − (int)(_stats->getAudioInputMsecsReadStats().getWindowAverage() / AudioConstants::NETWORK_FRAME_MSECS), | |
| 207 | + (int)((float)_stats->getAudioInputMsecsReadStats().getWindowAverage() / AudioConstants::NETWORK_FRAME_MSECS), | |
| 194 | 208 | streamStats->_framesAvailable, |
| 195 | 209 | (int)(_stats->getAudioOutputMsecsUnplayedStats().getCurrentIntervalLastSample() |
| 196 | 210 | / AudioConstants::NETWORK_FRAME_MSECS)); |
| @@ -200,10 +214,10 @@ void AudioIOStatsRenderer::renderAudioStreamStats(const AudioStreamStats* stream · 3 unmodified lines | ||
| 200 | 214 | streamStats->_framesAvailableAverage, |
| 201 | 215 | streamStats->_framesAvailable); |
| 202 | 216 | } |
| 203 | − | |
| 217 | + | |
| 204 | 218 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 205 | 219 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); |
| 206 | − | |
| 220 | + | |
| 207 | 221 | sprintf(stringBuffer, " Ringbuffer stats | starves: %u, prev_starve_lasted: %u, frames_dropped: %u, overflows: %u", |
| 208 | 222 | streamStats->_starveCount, |
| 209 | 223 | streamStats->_consecutiveNotMixedCount, |
| @@ -211,18 +225,18 @@ void AudioIOStatsRenderer::renderAudioStreamStats(const AudioStreamStats* stream · 1 unmodified line | ||
| 211 | 225 | streamStats->_overflowCount); |
| 212 | 226 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 213 | 227 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); |
| 214 | − | |
| 228 | + | |
| 215 | 229 | sprintf(stringBuffer, " Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s", |
| 216 | 230 | formatUsecTime(streamStats->_timeGapMin).toLatin1().data(), |
| 217 | 231 | formatUsecTime(streamStats->_timeGapMax).toLatin1().data(), |
| 218 | 232 | formatUsecTime(streamStats->_timeGapAverage).toLatin1().data()); |
| 219 | 233 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 220 | 234 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); |
| 221 | − | |
| 235 | + | |
| 222 | 236 | sprintf(stringBuffer, " Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s", |
| 223 | 237 | formatUsecTime(streamStats->_timeGapWindowMin).toLatin1().data(), |
| 224 | 238 | formatUsecTime(streamStats->_timeGapWindowMax).toLatin1().data(), |
| 225 | 239 | formatUsecTime(streamStats->_timeGapWindowAverage).toLatin1().data()); |
| 226 | 240 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 227 | 241 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); |
| 228 | −} | |
| 242 | +} | |
| @@ -1,114 +0,0 @@ | ||
| 1 | −// | |
| 2 | −// AudioToolBox.cpp | |
| 3 | −// interface/src/audio | |
| 4 | −// | |
| 5 | −// Created by Stephen Birarda on 2014-12-16. | |
| 6 | −// Copyright 2014 High Fidelity, Inc. | |
| 7 | −// | |
| 8 | −// Distributed under the Apache License, Version 2.0. | |
| 9 | −// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 10 | −// | |
| 11 | − | |
| 12 | −#include "InterfaceConfig.h" | |
| 13 | − | |
| 14 | −#include <AudioClient.h> | |
| 15 | −#include <GLCanvas.h> | |
| 16 | −#include <PathUtils.h> | |
| 17 | −#include <GeometryCache.h> | |
| 18 | −#include <gpu/GLBackend.h> | |
| 19 | − | |
| 20 | −#include "Application.h" | |
| 21 | −#include "AudioToolBox.h" | |
| 22 | − | |
| 23 | −// Mute icon configration | |
| 24 | −const int MUTE_ICON_SIZE = 24; | |
| 25 | − | |
| 26 | −AudioToolBox::AudioToolBox() : | |
| 27 | − _iconPulseTimeReference(usecTimestampNow()) | |
| 28 | −{ | |
| 29 | −} | |
| 30 | − | |
| 31 | −bool AudioToolBox::mousePressEvent(int x, int y) { | |
| 32 | − if (_iconBounds.contains(x, y)) { | |
| 33 | − DependencyManager::get<AudioClient>()->toggleMute(); | |
| 34 | − return true; | |
| 35 | − } | |
| 36 | − return false; | |
| 37 | −} | |
| 38 | − | |
| 39 | −void AudioToolBox::render(int x, int y, int padding, bool boxed) { | |
| 40 | − glEnable(GL_TEXTURE_2D); | |
| 41 | − | |
| 42 | − if (!_micTexture) { | |
| 43 | − _micTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/mic.svg"); | |
| 44 | − } | |
| 45 | − if (!_muteTexture) { | |
| 46 | − _muteTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/mic-mute.svg"); | |
| 47 | − } | |
| 48 | − if (_boxTexture) { | |
| 49 | − _boxTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/audio-box.svg"); | |
| 50 | − } | |
| 51 | − | |
| 52 | − auto audioIO = DependencyManager::get<AudioClient>(); | |
| 53 | − | |
| 54 | − if (boxed) { | |
| 55 | − bool isClipping = ((audioIO->getTimeSinceLastClip() > 0.0f) && (audioIO->getTimeSinceLastClip() < 1.0f)); | |
| 56 | − const int BOX_LEFT_PADDING = 5; | |
| 57 | − const int BOX_TOP_PADDING = 10; | |
| 58 | − const int BOX_WIDTH = 266; | |
| 59 | − const int BOX_HEIGHT = 44; | |
| 60 | − | |
| 61 | − QRect boxBounds = QRect(x - BOX_LEFT_PADDING, y - BOX_TOP_PADDING, BOX_WIDTH, BOX_HEIGHT); | |
| 62 | − glm::vec4 quadColor; | |
| 63 | − | |
| 64 | − if (isClipping) { | |
| 65 | − quadColor = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f); | |
| 66 | − } else { | |
| 67 | − quadColor = glm::vec4(0.41f, 0.41f, 0.41f, 1.0f); | |
| 68 | − } | |
| 69 | − glm::vec2 topLeft(boxBounds.left(), boxBounds.top()); | |
| 70 | − glm::vec2 bottomRight(boxBounds.right(), boxBounds.bottom()); | |
| 71 | − static const glm::vec2 texCoordTopLeft(1,1); | |
| 72 | − static const glm::vec2 texCoordBottomRight(0, 0); | |
| 73 | − glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_boxTexture)); | |
| 74 | − DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor); | |
| 75 | − } | |
| 76 | − | |
| 77 | − float iconColor = 1.0f; | |
| 78 | − | |
| 79 | − _iconBounds = QRect(x + padding, y, MUTE_ICON_SIZE, MUTE_ICON_SIZE); | |
| 80 | − if (!audioIO->isMuted()) { | |
| 81 | − glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_micTexture)); | |
| 82 | − iconColor = 1.0f; | |
| 83 | − } else { | |
| 84 | − glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_muteTexture)); | |
| 85 | − | |
| 86 | − // Make muted icon pulsate | |
| 87 | − static const float PULSE_MIN = 0.4f; | |
| 88 | − static const float PULSE_MAX = 1.0f; | |
| 89 | − static const float PULSE_FREQUENCY = 1.0f; // in Hz | |
| 90 | − qint64 now = usecTimestampNow(); | |
| 91 | − if (now - _iconPulseTimeReference > (qint64)USECS_PER_SECOND) { | |
| 92 | − // Prevents t from getting too big, which would diminish glm::cos precision | |
| 93 | − _iconPulseTimeReference = now - ((now - _iconPulseTimeReference) % USECS_PER_SECOND); | |
| 94 | − } | |
| 95 | − float t = (float)(now - _iconPulseTimeReference) / (float)USECS_PER_SECOND; | |
| 96 | − float pulseFactor = (glm::cos(t * PULSE_FREQUENCY * 2.0f * PI) + 1.0f) / 2.0f; | |
| 97 | − iconColor = PULSE_MIN + (PULSE_MAX - PULSE_MIN) * pulseFactor; | |
| 98 | − } | |
| 99 | − | |
| 100 | − glm::vec4 quadColor(iconColor, iconColor, iconColor, 1.0f); | |
| 101 | − | |
| 102 | − glm::vec2 topLeft(_iconBounds.left(), _iconBounds.top()); | |
| 103 | − glm::vec2 bottomRight(_iconBounds.right(), _iconBounds.bottom()); | |
| 104 | − glm::vec2 texCoordTopLeft(1,1); | |
| 105 | − glm::vec2 texCoordBottomRight(0,0); | |
| 106 | − | |
| 107 | − if (_boxQuadID == GeometryCache::UNKNOWN_ID) { | |
| 108 | − _boxQuadID = DependencyManager::get<GeometryCache>()->allocateID(); | |
| 109 | − } | |
| 110 | − | |
| 111 | − DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor, _boxQuadID); | |
| 112 | − glBindTexture(GL_TEXTURE_2D, 0); | |
| 113 | − glDisable(GL_TEXTURE_2D); | |
| 114 | −} | |
| @@ -1,36 +0,0 @@ | ||
| 1 | −// | |
| 2 | −// AudioToolBox.h | |
| 3 | −// interface/src/audio | |
| 4 | −// | |
| 5 | −// Created by Stephen Birarda on 2014-12-16. | |
| 6 | −// Copyright 2014 High Fidelity, Inc. | |
| 7 | −// | |
| 8 | −// Distributed under the Apache License, Version 2.0. | |
| 9 | −// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 10 | −// | |
| 11 | − | |
| 12 | −#ifndef hifi_AudioToolBox_h | |
| 13 | −#define hifi_AudioToolBox_h | |
| 14 | − | |
| 15 | −#include <DependencyManager.h> | |
| 16 | −#include <GeometryCache.h> | |
| 17 | −#include <QOpenGLTexture> | |
| 18 | − | |
| 19 | −class AudioToolBox : public Dependency { | |
| 20 | − SINGLETON_DEPENDENCY | |
| 21 | −public: | |
| 22 | − void render(int x, int y, int padding, bool boxed); | |
| 23 | − | |
| 24 | − bool mousePressEvent(int x, int y); | |
| 25 | −protected: | |
| 26 | − AudioToolBox(); | |
| 27 | −private: | |
| 28 | − gpu::TexturePointer _micTexture; | |
| 29 | − gpu::TexturePointer _muteTexture; | |
| 30 | − gpu::TexturePointer _boxTexture; | |
| 31 | − int _boxQuadID = GeometryCache::UNKNOWN_ID; | |
| 32 | − QRect _iconBounds; | |
| 33 | − qint64 _iconPulseTimeReference = 0; | |
| 34 | −}; | |
| 35 | − | |
| 36 | −#endif // hifi_AudioToolBox_h | |
| @@ -57,7 +57,7 @@ const float CHAT_MESSAGE_SCALE = 0.0015f; · 56 unmodified lines | ||
| 57 | 57 | const float CHAT_MESSAGE_HEIGHT = 0.1f; |
| 58 | 58 | const float DISPLAYNAME_FADE_TIME = 0.5f; |
| 59 | 59 | const float DISPLAYNAME_FADE_FACTOR = pow(0.01f, 1.0f / DISPLAYNAME_FADE_TIME); |
| 60 | −const float DISPLAYNAME_ALPHA = 0.95f; | |
| 60 | +const float DISPLAYNAME_ALPHA = 1.0f; | |
| 61 | 61 | const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f; |
| 62 | 62 | |
| 63 | 63 | namespace render { |
| @@ -107,6 +107,7 @@ Avatar::Avatar() : · 43 unmodified lines | ||
| 107 | 107 | } |
| 108 | 108 | |
| 109 | 109 | Avatar::~Avatar() { |
| 110 | + assert(_motionState == nullptr); | |
| 110 | 111 | for(auto attachment : _unusedAttachments) { |
| 111 | 112 | delete attachment; |
| 112 | 113 | } |
| @@ -280,9 +281,9 @@ enum TextRendererType { · 167 unmodified lines | ||
| 280 | 281 | }; |
| 281 | 282 | |
| 282 | 283 | static TextRenderer3D* textRenderer(TextRendererType type) { |
| 283 | − static TextRenderer3D* chatRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, 24, -1, | |
| 284 | + static TextRenderer3D* chatRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, -1, | |
| 284 | 285 | false, TextRenderer3D::SHADOW_EFFECT); |
| 285 | − static TextRenderer3D* displayNameRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, 12); | |
| 286 | + static TextRenderer3D* displayNameRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY); | |
| 286 | 287 | |
| 287 | 288 | switch(type) { |
| 288 | 289 | case CHAT: |
| @@ -323,7 +324,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 34 unmodified lines | ||
| 323 | 324 | _referential->update(); |
| 324 | 325 | } |
| 325 | 326 | |
| 326 | − auto batch = renderArgs->_batch; | |
| 327 | + auto& batch = *renderArgs->_batch; | |
| 327 | 328 | |
| 328 | 329 | if (postLighting && |
| 329 | 330 | glm::distance(DependencyManager::get<AvatarManager>()->getMyAvatar()->getPosition(), _position) < 10.0f) { |
| @@ -354,9 +355,9 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 24 unmodified lines | ||
| 354 | 355 | Transform pointerTransform; |
| 355 | 356 | pointerTransform.setTranslation(position); |
| 356 | 357 | pointerTransform.setRotation(rotation); |
| 357 | − batch->setModelTransform(pointerTransform); | |
| 358 | − deferredLighting->bindSimpleProgram(*batch); | |
| 359 | − geometryCache->renderLine(*batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor); | |
| 358 | + batch.setModelTransform(pointerTransform); | |
| 359 | + deferredLighting->bindSimpleProgram(batch); | |
| 360 | + geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor); | |
| 360 | 361 | } |
| 361 | 362 | } |
| 362 | 363 | |
| @@ -377,9 +378,9 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 14 unmodified lines | ||
| 377 | 378 | Transform pointerTransform; |
| 378 | 379 | pointerTransform.setTranslation(position); |
| 379 | 380 | pointerTransform.setRotation(rotation); |
| 380 | − batch->setModelTransform(pointerTransform); | |
| 381 | − deferredLighting->bindSimpleProgram(*batch); | |
| 382 | − geometryCache->renderLine(*batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor); | |
| 381 | + batch.setModelTransform(pointerTransform); | |
| 382 | + deferredLighting->bindSimpleProgram(batch); | |
| 383 | + geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor); | |
| 383 | 384 | } |
| 384 | 385 | } |
| 385 | 386 | } |
| @@ -464,8 +465,8 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 78 unmodified lines | ||
| 464 | 465 | } |
| 465 | 466 | Transform transform; |
| 466 | 467 | transform.setTranslation(position); |
| 467 | − batch->setModelTransform(transform); | |
| 468 | − DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(*batch, LOOK_AT_INDICATOR_RADIUS | |
| 468 | + batch.setModelTransform(transform); | |
| 469 | + DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(batch, LOOK_AT_INDICATOR_RADIUS | |
| 469 | 470 | , 15, 15, LOOK_AT_INDICATOR_COLOR); |
| 470 | 471 | } |
| 471 | 472 | } |
| @@ -492,14 +493,14 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 20 unmodified lines | ||
| 492 | 493 | Transform transform; |
| 493 | 494 | transform.setTranslation(_position); |
| 494 | 495 | transform.setScale(height); |
| 495 | − batch->setModelTransform(transform); | |
| 496 | + batch.setModelTransform(transform); | |
| 496 | 497 | |
| 497 | 498 | if (_voiceSphereID == GeometryCache::UNKNOWN_ID) { |
| 498 | 499 | _voiceSphereID = DependencyManager::get<GeometryCache>()->allocateID(); |
| 499 | 500 | } |
| 500 | 501 | |
| 501 | − DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(*batch); | |
| 502 | − DependencyManager::get<GeometryCache>()->renderSphere(*batch, sphereRadius, 15, 15, | |
| 502 | + DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch); | |
| 503 | + DependencyManager::get<GeometryCache>()->renderSphere(batch, sphereRadius, 15, 15, | |
| 503 | 504 | glm::vec4(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE), true, |
| 504 | 505 | _voiceSphereID); |
| 505 | 506 | } |
| @@ -507,14 +508,12 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 1 unmodified line | ||
| 507 | 508 | } |
| 508 | 509 | |
| 509 | 510 | const float DISPLAYNAME_DISTANCE = 20.0f; |
| 510 | − setShowDisplayName(renderArgs->_renderMode == RenderArgs::NORMAL_RENDER_MODE && distanceToTarget < DISPLAYNAME_DISTANCE); | |
| 511 | + setShowDisplayName(distanceToTarget < DISPLAYNAME_DISTANCE); | |
| 511 | 512 | |
| 512 | − if (renderArgs->_renderMode != RenderArgs::NORMAL_RENDER_MODE || (isMyAvatar() && | |
| 513 | − Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON)) { | |
| 514 | − return; | |
| 513 | + auto cameraMode = Application::getInstance()->getCamera()->getMode(); | |
| 514 | + if (!isMyAvatar() || cameraMode != CAMERA_MODE_FIRST_PERSON) { | |
| 515 | + renderDisplayName(batch, *renderArgs->_viewFrustum); | |
| 515 | 516 | } |
| 516 | − | |
| 517 | − renderDisplayName(renderArgs); | |
| 518 | 517 | } |
| 519 | 518 | |
| 520 | 519 | glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { |
| @@ -654,8 +653,8 @@ float Avatar::getBillboardSize() const { · 133 unmodified lines | ||
| 654 | 653 | return _scale * BILLBOARD_DISTANCE * tanf(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); |
| 655 | 654 | } |
| 656 | 655 | |
| 657 | −glm::vec3 Avatar::getDisplayNamePosition() { | |
| 658 | − glm::vec3 namePosition; | |
| 656 | +glm::vec3 Avatar::getDisplayNamePosition() const { | |
| 657 | + glm::vec3 namePosition(0.0f); | |
| 659 | 658 | if (getSkeletonModel().getNeckPosition(namePosition)) { |
| 660 | 659 | namePosition += getBodyUpDirection() * getHeadHeight() * 1.1f; |
| 661 | 660 | } else { |
| @@ -665,81 +664,73 @@ glm::vec3 Avatar::getDisplayNamePosition() { · 3 unmodified lines | ||
| 665 | 664 | return namePosition; |
| 666 | 665 | } |
| 667 | 666 | |
| 668 | −float Avatar::calculateDisplayNameScaleFactor(const glm::vec3& textPosition, bool inHMD) { | |
| 669 | − | |
| 670 | − // We need to compute the scale factor such as the text remains with fixed size respect to window coordinates | |
| 671 | − // We project a unit vector and check the difference in screen coordinates, to check which is the | |
| 672 | − // correction scale needed | |
| 673 | − // save the matrices for later scale correction factor | |
| 674 | − // The up vector must be relative to the rotation current rotation matrix: | |
| 675 | − // we set the identity | |
| 667 | +Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& frustum, float fontSize) const { | |
| 668 | + Transform result; | |
| 669 | + // We assume textPosition is whithin the frustum | |
| 670 | + glm::vec3 textPosition = getDisplayNamePosition(); | |
| 671 | + | |
| 672 | + // Compute viewProjection matrix | |
| 673 | + glm::mat4 projMat, viewMat; | |
| 674 | + Transform view; | |
| 675 | + frustum.evalProjectionMatrix(projMat); | |
| 676 | + frustum.evalViewTransform(view); | |
| 677 | + glm::mat4 viewProj = projMat * view.getInverseMatrix(viewMat); | |
| 678 | + | |
| 679 | + // Used to determine correct scale | |
| 676 | 680 | glm::vec3 testPoint0 = textPosition; |
| 677 | − glm::vec3 testPoint1 = textPosition + (Application::getInstance()->getCamera()->getRotation() * IDENTITY_UP); | |
| 678 | − | |
| 679 | − double textWindowHeight; | |
| 680 | − | |
| 681 | + glm::vec3 testPoint1 = testPoint0 + glm::normalize(frustum.getUp()); | |
| 682 | + // testPoints projections | |
| 683 | + glm::vec4 p0 = viewProj * glm::vec4(testPoint0, 1.0); | |
| 684 | + glm::vec4 p1 = viewProj * glm::vec4(testPoint1, 1.0); | |
| 685 | + | |
| 686 | + // TODO REMOVE vvv | |
| 681 | 687 | GLint viewportMatrix[4]; |
| 682 | 688 | glGetIntegerv(GL_VIEWPORT, viewportMatrix); |
| 683 | 689 | glm::dmat4 modelViewMatrix; |
| 684 | − float windowSizeX = viewportMatrix[2] - viewportMatrix[0]; | |
| 685 | 690 | float windowSizeY = viewportMatrix[3] - viewportMatrix[1]; |
| 691 | + // TODO REMOVE ^^^ | |
| 692 | + | |
| 693 | + const float DESIRED_HIGHT_ON_SCREEN = 20; // In pixels (this is double on retinas) | |
| 694 | + | |
| 695 | + // Projected point are between -1.0f and 1.0f, hence 0.5f * windowSizeY | |
| 696 | + double pixelHeight = 0.5f * windowSizeY * glm::abs((p1.y / p1.w) - (p0.y / p0.w)); // | |
| 697 | + // Handles pixel density (especially for macs retina displays) | |
| 698 | + double devicePixelRatio = qApp->getDevicePixelRatio() * qApp->getRenderResolutionScale(); // pixels / unit | |
| 699 | + | |
| 700 | + // Compute correct scale to apply | |
| 701 | + float scale = DESIRED_HIGHT_ON_SCREEN / (fontSize * pixelHeight) * devicePixelRatio; | |
| 702 | + | |
| 703 | + // Compute pixel alignment offset | |
| 704 | + float clipToPix = 0.5f * windowSizeY / p1.w; // Got from clip to pixel coordinates | |
| 705 | + glm::vec4 screenPos = clipToPix * p1; // in pixels coords | |
| 706 | + glm::vec4 screenOffset = (glm::round(screenPos) - screenPos) / clipToPix; // in clip coords | |
| 707 | + glm::vec3 worldOffset = glm::vec3(screenOffset.x, screenOffset.y, 0.0f) / (float)pixelHeight; | |
| 708 | + | |
| 709 | + // Compute orientation | |
| 710 | + glm::vec3 eulerAngles = ::safeEulerAngles(frustum.getOrientation()); | |
| 711 | + eulerAngles.z = 0.0f; // Cancel roll | |
| 712 | + glm::quat orientation(eulerAngles); // back to quaternions | |
| 713 | + | |
| 714 | + // Set transform (The order IS important) | |
| 715 | + result.setTranslation(textPosition); | |
| 716 | + result.setRotation(orientation); // Always face the screen | |
| 717 | + result.postTranslate(worldOffset); // Pixel alignment | |
| 718 | + result.setScale(scale); | |
| 719 | + return result; | |
| 686 | 720 | |
| 687 | − glm::dmat4 projectionMatrix; | |
| 688 | − Application::getInstance()->getModelViewMatrix(&modelViewMatrix); | |
| 689 | − Application::getInstance()->getProjectionMatrix(&projectionMatrix); | |
| 690 | − | |
| 691 | − | |
| 692 | − glm::dvec4 p0 = modelViewMatrix * glm::dvec4(testPoint0, 1.0); | |
| 693 | − p0 = projectionMatrix * p0; | |
| 694 | − glm::dvec2 result0 = glm::vec2(windowSizeX * (p0.x / p0.w + 1.0f) * 0.5f, windowSizeY * (p0.y / p0.w + 1.0f) * 0.5f); | |
| 695 | − | |
| 696 | − glm::dvec4 p1 = modelViewMatrix * glm::dvec4(testPoint1, 1.0); | |
| 697 | − p1 = projectionMatrix * p1; | |
| 698 | − glm::vec2 result1 = glm::vec2(windowSizeX * (p1.x / p1.w + 1.0f) * 0.5f, windowSizeY * (p1.y / p1.w + 1.0f) * 0.5f); | |
| 699 | − textWindowHeight = abs(result1.y - result0.y); | |
| 700 | − | |
| 701 | − // need to scale to compensate for the font resolution due to the device | |
| 702 | − float scaleFactor = QApplication::desktop()->windowHandle()->devicePixelRatio() * | |
| 703 | − ((textWindowHeight > EPSILON) ? 1.0f / textWindowHeight : 1.0f); | |
| 704 | − if (inHMD) { | |
| 705 | − const float HMDMODE_NAME_SCALE = 0.65f; | |
| 706 | − scaleFactor *= HMDMODE_NAME_SCALE; | |
| 707 | − } else { | |
| 708 | − scaleFactor *= Application::getInstance()->getRenderResolutionScale(); | |
| 709 | − } | |
| 710 | − return scaleFactor; | |
| 711 | 721 | } |
| 712 | 722 | |
| 713 | −void Avatar::renderDisplayName(RenderArgs* renderArgs) { | |
| 714 | − auto batch = renderArgs->_batch; | |
| 715 | − | |
| 723 | +void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) const { | |
| 716 | 724 | bool shouldShowReceiveStats = DependencyManager::get<AvatarManager>()->shouldShowReceiveStats() && !isMyAvatar(); |
| 717 | 725 | |
| 726 | + // If we have nothing to draw, or it's tottaly transparent, return | |
| 718 | 727 | if ((_displayName.isEmpty() && !shouldShowReceiveStats) || _displayNameAlpha == 0.0f) { |
| 719 | 728 | return; |
| 720 | 729 | } |
| 721 | − | |
| 722 | − // which viewing mode? | |
| 723 | − bool inHMD = Application::getInstance()->isHMDMode(); | |
| 724 | − | |
| 725 | − glm::vec3 textPosition = getDisplayNamePosition(); | |
| 726 | − | |
| 727 | − // we need "always facing camera": we must remove the camera rotation from the stac | |
| 728 | − glm::quat rotation = Application::getInstance()->getCamera()->getRotation(); | |
| 729 | − | |
| 730 | − // TODO: Fix scaling - at some point this or the text rendering changed in scale. | |
| 731 | − float scaleFactor = calculateDisplayNameScaleFactor(textPosition, inHMD); | |
| 732 | − scaleFactor /= 3.5f; | |
| 733 | − | |
| 734 | − Transform textTransform; | |
| 735 | − textTransform.setTranslation(textPosition); | |
| 736 | − textTransform.setRotation(rotation); | |
| 737 | − textTransform.setScale(scaleFactor); | |
| 730 | + auto renderer = textRenderer(DISPLAYNAME); | |
| 738 | 731 | |
| 739 | 732 | // optionally render timing stats for this avatar with the display name |
| 740 | 733 | QString renderedDisplayName = _displayName; |
| 741 | − QRect nameDynamicRect = _displayNameBoundingRect; | |
| 742 | − | |
| 743 | 734 | if (shouldShowReceiveStats) { |
| 744 | 735 | float kilobitsPerSecond = getAverageBytesReceivedPerSecond() / (float) BYTES_PER_KILOBIT; |
| 745 | 736 | |
| @@ -747,42 +738,43 @@ void Avatar::renderDisplayName(RenderArgs* renderArgs) { · 1 unmodified line | ||
| 747 | 738 | if (!renderedDisplayName.isEmpty()) { |
| 748 | 739 | statsFormat.prepend(" - "); |
| 749 | 740 | } |
| 750 | − | |
| 751 | − QString statsText = statsFormat.arg(QString::number(kilobitsPerSecond, 'f', 2)).arg(getReceiveRate()); | |
| 752 | − renderedDisplayName += statsText; | |
| 753 | − | |
| 754 | − glm::vec2 extent = textRenderer(DISPLAYNAME)->computeExtent(renderedDisplayName); | |
| 755 | − nameDynamicRect = QRect(0, 0, (int)extent.x, (int)extent.y); | |
| 741 | + renderedDisplayName += statsFormat.arg(QString::number(kilobitsPerSecond, 'f', 2)).arg(getReceiveRate()); | |
| 756 | 742 | } |
| 757 | − | |
| 758 | − int text_x = -nameDynamicRect.width() / 2; | |
| 759 | − int text_y = -nameDynamicRect.height() / 2; | |
| 760 | − | |
| 761 | − // draw a gray background | |
| 762 | − int left = text_x; | |
| 763 | − int right = left + nameDynamicRect.width(); | |
| 764 | − int bottom = text_y; | |
| 765 | − int top = bottom + nameDynamicRect.height(); | |
| 766 | − const int border = 8; | |
| 767 | − bottom -= border; | |
| 768 | − left -= border; | |
| 769 | − top += border; | |
| 770 | − right += border; | |
| 771 | 743 | |
| 744 | + // Compute display name extent/position offset | |
| 745 | + glm::vec2 extent = renderer->computeExtent(renderedDisplayName); | |
| 746 | + QRect nameDynamicRect = QRect(0, 0, (int)extent.x, (int)extent.y); | |
| 747 | + const int text_x = -nameDynamicRect.width() / 2; | |
| 748 | + const int text_y = -nameDynamicRect.height() / 2; | |
| 749 | + | |
| 750 | + // Compute background position/size | |
| 751 | + static const float SLIGHTLY_BEHIND = -0.05f; | |
| 752 | + const int border = 0.1f * nameDynamicRect.height(); | |
| 753 | + const int left = text_x - border; | |
| 754 | + const int bottom = text_y - border; | |
| 755 | + const int width = nameDynamicRect.width() + 2.0f * border; | |
| 756 | + const int height = nameDynamicRect.height() + 2.0f * border; | |
| 757 | + const int bevelDistance = 0.1f * height; | |
| 758 | + | |
| 759 | + // Display name and background colors | |
| 772 | 760 | glm::vec4 textColor(0.93f, 0.93f, 0.93f, _displayNameAlpha); |
| 773 | 761 | glm::vec4 backgroundColor(0.2f, 0.2f, 0.2f, |
| 774 | − _displayNameAlpha * DISPLAYNAME_BACKGROUND_ALPHA / DISPLAYNAME_ALPHA); | |
| 762 | + (_displayNameAlpha / DISPLAYNAME_ALPHA) * DISPLAYNAME_BACKGROUND_ALPHA); | |
| 763 | + | |
| 764 | + // Compute display name transform | |
| 765 | + auto textTransform = calculateDisplayNameTransform(frustum, renderer->getFontSize()); | |
| 775 | 766 | |
| 767 | + // Render background slightly behind to avoid z-fighting | |
| 776 | 768 | auto backgroundTransform = textTransform; |
| 777 | − backgroundTransform.postTranslate(glm::vec3(0.0f, 0.0f, -0.001f)); | |
| 778 | − batch->setModelTransform(backgroundTransform); | |
| 779 | − DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(*batch); | |
| 780 | − DependencyManager::get<GeometryCache>()->renderBevelCornersRect(*batch, left, bottom, right - left, top - bottom, 3, | |
| 781 | − backgroundColor); | |
| 769 | + backgroundTransform.postTranslate(glm::vec3(0.0f, 0.0f, SLIGHTLY_BEHIND)); | |
| 770 | + batch.setModelTransform(backgroundTransform); | |
| 771 | + DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch); | |
| 772 | + DependencyManager::get<GeometryCache>()->renderBevelCornersRect(batch, left, bottom, width, height, | |
| 773 | + bevelDistance, backgroundColor); | |
| 774 | + // Render actual name | |
| 782 | 775 | QByteArray nameUTF8 = renderedDisplayName.toLocal8Bit(); |
| 783 | − | |
| 784 | − batch->setModelTransform(textTransform); | |
| 785 | − textRenderer(DISPLAYNAME)->draw(*batch, text_x, -text_y, nameUTF8.data(), textColor); | |
| 776 | + batch.setModelTransform(textTransform); | |
| 777 | + renderer->draw(batch, text_x, -text_y, nameUTF8.data(), textColor); | |
| 786 | 778 | } |
| 787 | 779 | |
| 788 | 780 | bool Avatar::findRayIntersection(RayIntersectionInfo& intersection) const { |
| @@ -987,13 +979,6 @@ void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) { · 198 unmodified lines | ||
| 987 | 979 | } |
| 988 | 980 | } |
| 989 | 981 | |
| 990 | −void Avatar::setDisplayName(const QString& displayName) { | |
| 991 | − AvatarData::setDisplayName(displayName); | |
| 992 | − // FIXME is this a sufficient replacement for tightBoundingRect? | |
| 993 | − glm::vec2 extent = textRenderer(DISPLAYNAME)->computeExtent(displayName); | |
| 994 | − _displayNameBoundingRect = QRect(0, 0, (int)extent.x, (int)extent.y); | |
| 995 | −} | |
| 996 | − | |
| 997 | 982 | void Avatar::setBillboard(const QByteArray& billboard) { |
| 998 | 983 | AvatarData::setBillboard(billboard); |
| 999 | 984 | |
| @@ -1092,7 +1077,12 @@ float Avatar::getSkeletonHeight() const { · 92 unmodified lines | ||
| 1092 | 1077 | float Avatar::getHeadHeight() const { |
| 1093 | 1078 | Extents extents = getHead()->getFaceModel().getMeshExtents(); |
| 1094 | 1079 | if (!extents.isEmpty() && extents.isValid()) { |
| 1095 | − return extents.maximum.y - extents.minimum.y; | |
| 1080 | + | |
| 1081 | + // HACK: We have a really odd case when fading out for some models where this value explodes | |
| 1082 | + float result = extents.maximum.y - extents.minimum.y; | |
| 1083 | + if (result >= 0.0f && result < 100.0f * _scale ) { | |
| 1084 | + return result; | |
| 1085 | + } | |
| 1096 | 1086 | } |
| 1097 | 1087 | |
| 1098 | 1088 | extents = _skeletonModel.getMeshExtents(); |
| @@ -1116,7 +1106,7 @@ void Avatar::setShowDisplayName(bool showDisplayName) { · 17 unmodified lines | ||
| 1116 | 1106 | } |
| 1117 | 1107 | |
| 1118 | 1108 | // For myAvatar, the alpha update is not done (called in simulate for other avatars) |
| 1119 | − if (DependencyManager::get<AvatarManager>()->getMyAvatar() == this) { | |
| 1109 | + if (isMyAvatar()) { | |
| 1120 | 1110 | if (showDisplayName) { |
| 1121 | 1111 | _displayNameAlpha = DISPLAYNAME_ALPHA; |
| 1122 | 1112 | } else { |
| @@ -1129,7 +1119,6 @@ void Avatar::setShowDisplayName(bool showDisplayName) { · 6 unmodified lines | ||
| 1129 | 1119 | } else { |
| 1130 | 1120 | _displayNameTargetAlpha = 0.0f; |
| 1131 | 1121 | } |
| 1132 | − | |
| 1133 | 1122 | } |
| 1134 | 1123 | |
| 1135 | 1124 | // virtual |
| @@ -98,6 +98,7 @@ public: · 97 unmodified lines | ||
| 98 | 98 | //getters |
| 99 | 99 | bool isInitialized() const { return _initialized; } |
| 100 | 100 | SkeletonModel& getSkeletonModel() { return _skeletonModel; } |
| 101 | + const SkeletonModel& getSkeletonModel() const { return _skeletonModel; } | |
| 101 | 102 | const QVector<Model*>& getAttachmentModels() const { return _attachmentModels; } |
| 102 | 103 | glm::vec3 getChestPosition() const; |
| 103 | 104 | float getScale() const { return _scale; } |
| @@ -131,7 +132,7 @@ public: · 27 unmodified lines | ||
| 131 | 132 | /// \return whether or not the plane penetrated |
| 132 | 133 | bool findPlaneCollisions(const glm::vec4& plane, CollisionList& collisions); |
| 133 | 134 | |
| 134 | − virtual bool isMyAvatar() { return false; } | |
| 135 | + virtual bool isMyAvatar() const { return false; } | |
| 135 | 136 | |
| 136 | 137 | virtual QVector<glm::quat> getJointRotations() const; |
| 137 | 138 | virtual glm::quat getJointRotation(int index) const; |
| @@ -141,7 +142,6 @@ public: · 3 unmodified lines | ||
| 141 | 142 | virtual void setFaceModelURL(const QUrl& faceModelURL); |
| 142 | 143 | virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); |
| 143 | 144 | virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData); |
| 144 | − virtual void setDisplayName(const QString& displayName); | |
| 145 | 145 | virtual void setBillboard(const QByteArray& billboard); |
| 146 | 146 | |
| 147 | 147 | void setShowDisplayName(bool showDisplayName); |
| @@ -232,10 +232,10 @@ protected: · 84 unmodified lines | ||
| 232 | 232 | float getSkeletonHeight() const; |
| 233 | 233 | float getHeadHeight() const; |
| 234 | 234 | float getPelvisFloatingHeight() const; |
| 235 | − glm::vec3 getDisplayNamePosition(); | |
| 235 | + glm::vec3 getDisplayNamePosition() const; | |
| 236 | 236 | |
| 237 | − float calculateDisplayNameScaleFactor(const glm::vec3& textPosition, bool inHMD); | |
| 238 | − void renderDisplayName(RenderArgs* renderArgs); | |
| 237 | + Transform calculateDisplayNameTransform(const ViewFrustum& frustum, float fontSize) const; | |
| 238 | + void renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) const; | |
| 239 | 239 | virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel = 0.0f); |
| 240 | 240 | virtual bool shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const; |
| 241 | 241 | virtual void fixupModelsInScene(); |
| @@ -29,6 +29,12 @@ AvatarActionHold::~AvatarActionHold() { · 28 unmodified lines | ||
| 29 | 29 | |
| 30 | 30 | void AvatarActionHold::updateActionWorker(float deltaTimeStep) { |
| 31 | 31 | auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); |
| 32 | + | |
| 33 | + if (!tryLockForRead()) { | |
| 34 | + // don't risk hanging the thread running the physics simulation | |
| 35 | + return; | |
| 36 | + } | |
| 37 | + | |
| 32 | 38 | glm::vec3 palmPosition; |
| 33 | 39 | if (_hand == "right") { |
| 34 | 40 | palmPosition = myAvatar->getRightPalmPosition(); |
| @@ -40,8 +46,11 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { · 5 unmodified lines | ||
| 40 | 46 | auto offset = rotation * _relativePosition; |
| 41 | 47 | auto position = palmPosition + offset; |
| 42 | 48 | rotation *= _relativeRotation; |
| 49 | + unlock(); | |
| 43 | 50 | |
| 44 | − lockForWrite(); | |
| 51 | + if (!tryLockForWrite()) { | |
| 52 | + return; | |
| 53 | + } | |
| 45 | 54 | _positionalTarget = position; |
| 46 | 55 | _rotationalTarget = rotation; |
| 47 | 56 | unlock(); |
| @@ -13,8 +13,18 @@ · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | #include <QScriptEngine> |
| 15 | 15 | |
| 16 | +#ifdef __GNUC__ | |
| 17 | +#pragma GCC diagnostic push | |
| 18 | +#pragma GCC diagnostic ignored "-Wdouble-promotion" | |
| 19 | +#endif | |
| 20 | + | |
| 16 | 21 | #include <glm/gtx/string_cast.hpp> |
| 17 | 22 | |
| 23 | +#ifdef __GNUC__ | |
| 24 | +#pragma GCC diagnostic pop | |
| 25 | +#endif | |
| 26 | + | |
| 27 | + | |
| 18 | 28 | #include <GlowEffect.h> |
| 19 | 29 | #include <PerfStat.h> |
| 20 | 30 | #include <RegisteredMetaTypes.h> |
| @@ -104,6 +114,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { · 83 unmodified lines | ||
| 104 | 114 | // DO NOT update or fade out uninitialized Avatars |
| 105 | 115 | ++avatarIterator; |
| 106 | 116 | } else if (avatar->shouldDie()) { |
| 117 | + removeAvatarMotionState(avatar); | |
| 107 | 118 | _avatarFades.push_back(avatarIterator.value()); |
| 108 | 119 | avatarIterator = _avatarHash.erase(avatarIterator); |
| 109 | 120 | } else { |
| @@ -153,12 +164,13 @@ AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWe · 43 unmodified lines | ||
| 153 | 164 | } |
| 154 | 165 | |
| 155 | 166 | // protected |
| 156 | −void AvatarManager::removeAvatarMotionState(Avatar* avatar) { | |
| 157 | − AvatarMotionState* motionState= avatar->_motionState; | |
| 167 | +void AvatarManager::removeAvatarMotionState(AvatarSharedPointer avatar) { | |
| 168 | + auto rawPointer = std::static_pointer_cast<Avatar>(avatar); | |
| 169 | + AvatarMotionState* motionState= rawPointer->_motionState; | |
| 158 | 170 | if (motionState) { |
| 159 | 171 | // clean up physics stuff |
| 160 | 172 | motionState->clearObjectBackPointer(); |
| 161 | − avatar->_motionState = nullptr; | |
| 173 | + rawPointer->_motionState = nullptr; | |
| 162 | 174 | _avatarMotionStates.remove(motionState); |
| 163 | 175 | _motionStatesToAdd.remove(motionState); |
| 164 | 176 | _motionStatesToDelete.push_back(motionState); |
| @@ -171,7 +183,7 @@ void AvatarManager::removeAvatar(const QUuid& sessionUUID) { · 6 unmodified lines | ||
| 171 | 183 | if (avatarIterator != _avatarHash.end()) { |
| 172 | 184 | std::shared_ptr<Avatar> avatar = std::dynamic_pointer_cast<Avatar>(avatarIterator.value()); |
| 173 | 185 | if (avatar != _myAvatar && avatar->isInitialized()) { |
| 174 | − removeAvatarMotionState(avatar.get()); | |
| 186 | + removeAvatarMotionState(avatar); | |
| 175 | 187 | _avatarFades.push_back(avatarIterator.value()); |
| 176 | 188 | _avatarHash.erase(avatarIterator); |
| 177 | 189 | } |
| @@ -187,7 +199,7 @@ void AvatarManager::clearOtherAvatars() { · 9 unmodified lines | ||
| 187 | 199 | // don't remove myAvatar or uninitialized avatars from the list |
| 188 | 200 | ++avatarIterator; |
| 189 | 201 | } else { |
| 190 | − removeAvatarMotionState(avatar.get()); | |
| 202 | + removeAvatarMotionState(avatar); | |
| 191 | 203 | _avatarFades.push_back(avatarIterator.value()); |
| 192 | 204 | avatarIterator = _avatarHash.erase(avatarIterator); |
| 193 | 205 | } |
| @@ -73,7 +73,7 @@ private: · 72 unmodified lines | ||
| 73 | 73 | // virtual overrides |
| 74 | 74 | virtual AvatarSharedPointer newSharedAvatar(); |
| 75 | 75 | virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer); |
| 76 | − void removeAvatarMotionState(Avatar* avatar); | |
| 76 | + void removeAvatarMotionState(AvatarSharedPointer avatar); | |
| 77 | 77 | virtual void removeAvatar(const QUuid& sessionUUID); |
| 78 | 78 | |
| 79 | 79 | QVector<AvatarSharedPointer> _avatarFades; |
| @@ -77,7 +77,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { · 76 unmodified lines | ||
| 77 | 77 | const float AUDIO_LONG_TERM_AVERAGING_SECS = 30.0f; |
| 78 | 78 | _averageLoudness = glm::mix(_averageLoudness, _audioLoudness, glm::min(deltaTime / AUDIO_AVERAGING_SECS, 1.0f)); |
| 79 | 79 | |
| 80 | − if (_longTermAverageLoudness == -1.0) { | |
| 80 | + if (_longTermAverageLoudness == -1.0f) { | |
| 81 | 81 | _longTermAverageLoudness = _averageLoudness; |
| 82 | 82 | } else { |
| 83 | 83 | _longTermAverageLoudness = glm::mix(_longTermAverageLoudness, _averageLoudness, glm::min(deltaTime / AUDIO_LONG_TERM_AVERAGING_SECS, 1.0f)); |
| @@ -124,18 +124,25 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { · 40 unmodified lines | ||
| 124 | 124 | |
| 125 | 125 | if (!(_isFaceTrackerConnected || billboard)) { |
| 126 | 126 | // Update eye saccades |
| 127 | − const float AVERAGE_MICROSACCADE_INTERVAL = 0.50f; | |
| 128 | − const float AVERAGE_SACCADE_INTERVAL = 4.0f; | |
| 127 | + const float AVERAGE_MICROSACCADE_INTERVAL = 1.0f; | |
| 128 | + const float AVERAGE_SACCADE_INTERVAL = 6.0f; | |
| 129 | 129 | const float MICROSACCADE_MAGNITUDE = 0.002f; |
| 130 | 130 | const float SACCADE_MAGNITUDE = 0.04f; |
| 131 | − | |
| 131 | + const float MAXIMUM_SACCADE_SPEED = 0.8f; | |
| 132 | + | |
| 132 | 133 | if (randFloat() < deltaTime / AVERAGE_MICROSACCADE_INTERVAL) { |
| 133 | 134 | _saccadeTarget = MICROSACCADE_MAGNITUDE * randVector(); |
| 134 | 135 | } else if (randFloat() < deltaTime / AVERAGE_SACCADE_INTERVAL) { |
| 135 | 136 | _saccadeTarget = SACCADE_MAGNITUDE * randVector(); |
| 136 | 137 | } |
| 137 | − _saccade += (_saccadeTarget - _saccade) * 0.50f; | |
| 138 | − | |
| 138 | + | |
| 139 | + glm::vec3 saccadeDelta = (_saccadeTarget - _saccade) * 0.5f; | |
| 140 | + float speed = glm::length(saccadeDelta) / deltaTime; | |
| 141 | + if (speed > MAXIMUM_SACCADE_SPEED) { | |
| 142 | + saccadeDelta = saccadeDelta * MAXIMUM_SACCADE_SPEED / speed; | |
| 143 | + } | |
| 144 | + _saccade += saccadeDelta; | |
| 145 | + | |
| 139 | 146 | // Detect transition from talking to not; force blink after that and a delay |
| 140 | 147 | bool forceBlink = false; |
| 141 | 148 | const float TALKING_LOUDNESS = 100.0f; |
| @@ -59,10 +59,10 @@ const float MAX_WALKING_SPEED = 2.5f; // human walking speed · 58 unmodified lines | ||
| 59 | 59 | const float MAX_BOOST_SPEED = 0.5f * MAX_WALKING_SPEED; // keyboard motor gets additive boost below this speed |
| 60 | 60 | const float MIN_AVATAR_SPEED = 0.05f; // speed is set to zero below this |
| 61 | 61 | |
| 62 | −// TODO: normalize avatar speed for standard avatar size, then scale all motion logic | |
| 62 | +// TODO: normalize avatar speed for standard avatar size, then scale all motion logic | |
| 63 | 63 | // to properly follow avatar size. |
| 64 | 64 | float MAX_AVATAR_SPEED = 300.0f; |
| 65 | −float MAX_KEYBOARD_MOTOR_SPEED = MAX_AVATAR_SPEED; | |
| 65 | +float MAX_KEYBOARD_MOTOR_SPEED = MAX_AVATAR_SPEED; | |
| 66 | 66 | float DEFAULT_KEYBOARD_MOTOR_TIMESCALE = 0.25f; |
| 67 | 67 | float MIN_SCRIPTED_MOTOR_TIMESCALE = 0.005f; |
| 68 | 68 | float DEFAULT_SCRIPTED_MOTOR_TIMESCALE = 1.0e6f; |
| @@ -146,7 +146,7 @@ void MyAvatar::update(float deltaTime) { · 77 unmodified lines | ||
| 146 | 146 | if (_referential) { |
| 147 | 147 | _referential->update(); |
| 148 | 148 | } |
| 149 | − | |
| 149 | + | |
| 150 | 150 | Head* head = getHead(); |
| 151 | 151 | head->relaxLean(deltaTime); |
| 152 | 152 | updateFromTrackers(deltaTime); |
| @@ -163,12 +163,12 @@ void MyAvatar::update(float deltaTime) { · 10 unmodified lines | ||
| 163 | 163 | |
| 164 | 164 | void MyAvatar::simulate(float deltaTime) { |
| 165 | 165 | PerformanceTimer perfTimer("simulate"); |
| 166 | − | |
| 166 | + | |
| 167 | 167 | // Play back recording |
| 168 | 168 | if (_player && _player->isPlaying()) { |
| 169 | 169 | _player->play(); |
| 170 | 170 | } |
| 171 | − | |
| 171 | + | |
| 172 | 172 | if (_scale != _targetScale) { |
| 173 | 173 | float scale = (1.0f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale; |
| 174 | 174 | setScale(scale); |
| @@ -179,7 +179,7 @@ void MyAvatar::simulate(float deltaTime) { · 4 unmodified lines | ||
| 179 | 179 | updateOrientation(deltaTime); |
| 180 | 180 | updatePosition(deltaTime); |
| 181 | 181 | } |
| 182 | − | |
| 182 | + | |
| 183 | 183 | { |
| 184 | 184 | PerformanceTimer perfTimer("hand"); |
| 185 | 185 | // update avatar skeleton and simulate hand and head |
| @@ -222,12 +222,12 @@ void MyAvatar::simulate(float deltaTime) { · 36 unmodified lines | ||
| 222 | 222 | head->setScale(_scale); |
| 223 | 223 | head->simulate(deltaTime, true); |
| 224 | 224 | } |
| 225 | − | |
| 225 | + | |
| 226 | 226 | // Record avatars movements. |
| 227 | 227 | if (_recorder && _recorder->isRecording()) { |
| 228 | 228 | _recorder->record(); |
| 229 | 229 | } |
| 230 | − | |
| 230 | + | |
| 231 | 231 | // consider updating our billboard |
| 232 | 232 | maybeUpdateBillboard(); |
| 233 | 233 | } |
| @@ -235,18 +235,18 @@ void MyAvatar::simulate(float deltaTime) { · 1 unmodified line | ||
| 235 | 235 | // Update avatar head rotation with sensor data |
| 236 | 236 | void MyAvatar::updateFromTrackers(float deltaTime) { |
| 237 | 237 | glm::vec3 estimatedPosition, estimatedRotation; |
| 238 | − | |
| 238 | + | |
| 239 | 239 | bool inHmd = qApp->isHMDMode(); |
| 240 | − | |
| 240 | + | |
| 241 | 241 | if (isPlaying() && inHmd) { |
| 242 | 242 | return; |
| 243 | 243 | } |
| 244 | 244 | |
| 245 | 245 | if (inHmd) { |
| 246 | − estimatedPosition = qApp->getHeadPosition(); | |
| 246 | + estimatedPosition = qApp->getHeadPosition(); | |
| 247 | 247 | estimatedPosition.x *= -1.0f; |
| 248 | 248 | _trackedHeadPosition = estimatedPosition; |
| 249 | − | |
| 249 | + | |
| 250 | 250 | const float OCULUS_LEAN_SCALE = 0.05f; |
| 251 | 251 | estimatedPosition /= OCULUS_LEAN_SCALE; |
| 252 | 252 | } else { |
| @@ -257,7 +257,7 @@ void MyAvatar::updateFromTrackers(float deltaTime) { · 4 unmodified lines | ||
| 257 | 257 | estimatedRotation = glm::degrees(safeEulerAngles(tracker->getHeadRotation())); |
| 258 | 258 | } |
| 259 | 259 | } |
| 260 | − | |
| 260 | + | |
| 261 | 261 | // Rotate the body if the head is turned beyond the screen |
| 262 | 262 | if (Menu::getInstance()->isOptionChecked(MenuOption::TurnWithHead)) { |
| 263 | 263 | const float TRACKER_YAW_TURN_SENSITIVITY = 0.5f; |
| @@ -317,7 +317,7 @@ void MyAvatar::renderDebugBodyPoints() { · 53 unmodified lines | ||
| 317 | 317 | glm::vec3 headPosition(getHead()->getEyePosition()); |
| 318 | 318 | float torsoToHead = glm::length(headPosition - torsoPosition); |
| 319 | 319 | glm::vec3 position; |
| 320 | − qCDebug(interfaceapp, "head-above-torso %.2f, scale = %0.2f", torsoToHead, getScale()); | |
| 320 | + qCDebug(interfaceapp, "head-above-torso %.2f, scale = %0.2f", (double)torsoToHead, (double)getScale()); | |
| 321 | 321 | |
| 322 | 322 | // Torso Sphere |
| 323 | 323 | position = torsoPosition; |
| @@ -433,7 +433,7 @@ void MyAvatar::startRecording() { · 109 unmodified lines | ||
| 433 | 433 | auto audioClient = DependencyManager::get<AudioClient>(); |
| 434 | 434 | connect(audioClient.data(), &AudioClient::inputReceived, _recorder.data(), |
| 435 | 435 | &Recorder::recordAudio, Qt::BlockingQueuedConnection); |
| 436 | − | |
| 436 | + | |
| 437 | 437 | _recorder->startRecording(); |
| 438 | 438 | } |
| 439 | 439 | |
| @@ -449,7 +449,7 @@ void MyAvatar::stopRecording() { · 9 unmodified lines | ||
| 449 | 449 | // stop grabbing audio from the AudioClient |
| 450 | 450 | auto audioClient = DependencyManager::get<AudioClient>(); |
| 451 | 451 | disconnect(audioClient.data(), 0, _recorder.data(), 0); |
| 452 | − | |
| 452 | + | |
| 453 | 453 | _recorder->stopRecording(); |
| 454 | 454 | } |
| 455 | 455 | } |
| @@ -481,7 +481,7 @@ void MyAvatar::loadLastRecording() { · 25 unmodified lines | ||
| 481 | 481 | if (!_player) { |
| 482 | 482 | _player = PlayerPointer(new Player(this)); |
| 483 | 483 | } |
| 484 | − | |
| 484 | + | |
| 485 | 485 | _player->loadRecording(_recorder->getRecording()); |
| 486 | 486 | } |
| 487 | 487 | |
| @@ -573,7 +573,7 @@ AnimationDetails MyAvatar::getAnimationDetailsByRole(const QString& role) { · 85 unmodified lines | ||
| 573 | 573 | AnimationDetails result; |
| 574 | 574 | if (QThread::currentThread() != thread()) { |
| 575 | 575 | QMetaObject::invokeMethod(this, "getAnimationDetailsByRole", Qt::BlockingQueuedConnection, |
| 576 | − Q_RETURN_ARG(AnimationDetails, result), | |
| 576 | + Q_RETURN_ARG(AnimationDetails, result), | |
| 577 | 577 | Q_ARG(const QString&, role)); |
| 578 | 578 | return result; |
| 579 | 579 | } |
| @@ -590,7 +590,7 @@ AnimationDetails MyAvatar::getAnimationDetails(const QString& url) { · 10 unmodified lines | ||
| 590 | 590 | AnimationDetails result; |
| 591 | 591 | if (QThread::currentThread() != thread()) { |
| 592 | 592 | QMetaObject::invokeMethod(this, "getAnimationDetails", Qt::BlockingQueuedConnection, |
| 593 | − Q_RETURN_ARG(AnimationDetails, result), | |
| 593 | + Q_RETURN_ARG(AnimationDetails, result), | |
| 594 | 594 | Q_ARG(const QString&, url)); |
| 595 | 595 | return result; |
| 596 | 596 | } |
| @@ -638,7 +638,7 @@ void MyAvatar::saveData() { · 41 unmodified lines | ||
| 638 | 638 | settings.setValue("scale", attachment.scale); |
| 639 | 639 | } |
| 640 | 640 | settings.endArray(); |
| 641 | − | |
| 641 | + | |
| 642 | 642 | settings.beginWriteArray("animationHandles"); |
| 643 | 643 | for (int i = 0; i < _animationHandles.size(); i++) { |
| 644 | 644 | settings.setArrayIndex(i); |
| @@ -655,7 +655,7 @@ void MyAvatar::saveData() { · 10 unmodified lines | ||
| 655 | 655 | settings.setValue("maskedJoints", pointer->getMaskedJoints()); |
| 656 | 656 | } |
| 657 | 657 | settings.endArray(); |
| 658 | − | |
| 658 | + | |
| 659 | 659 | settings.setValue("displayName", _displayName); |
| 660 | 660 | |
| 661 | 661 | settings.endGroup(); |
| @@ -681,7 +681,7 @@ void MyAvatar::loadData() { · 19 unmodified lines | ||
| 681 | 681 | _targetScale = loadSetting(settings, "scale", 1.0f); |
| 682 | 682 | setScale(_scale); |
| 683 | 683 | |
| 684 | − // The old preferences only stored the face and skeleton URLs, we didn't track if the user wanted to use 1 or 2 urls | |
| 684 | + // The old preferences only stored the face and skeleton URLs, we didn't track if the user wanted to use 1 or 2 urls | |
| 685 | 685 | // for their avatar, So we need to attempt to detect this old case and set our new preferences accordingly. If |
| 686 | 686 | // the head URL is empty, then we will assume they are using a full url... |
| 687 | 687 | bool isOldSettings = !(settings.contains("useFullAvatar") || settings.contains("fullAvatarURL")); |
| @@ -693,7 +693,7 @@ void MyAvatar::loadData() { · 5 unmodified lines | ||
| 693 | 693 | _headModelName = settings.value("headModelName", DEFAULT_HEAD_MODEL_NAME).toString(); |
| 694 | 694 | _bodyModelName = settings.value("bodyModelName", DEFAULT_BODY_MODEL_NAME).toString(); |
| 695 | 695 | _fullAvatarModelName = settings.value("fullAvatarModelName", DEFAULT_FULL_AVATAR_MODEL_NAME).toString(); |
| 696 | − | |
| 696 | + | |
| 697 | 697 | if (isOldSettings) { |
| 698 | 698 | bool assumeFullAvatar = _headURLFromPreferences.isEmpty(); |
| 699 | 699 | _useFullAvatar = assumeFullAvatar; |
| @@ -719,14 +719,14 @@ void MyAvatar::loadData() { · 19 unmodified lines | ||
| 719 | 719 | QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString()); |
| 720 | 720 | _bodyModelName = bodyFST["name"].toString(); |
| 721 | 721 | } |
| 722 | − | |
| 722 | + | |
| 723 | 723 | if (_headURLFromPreferences == DEFAULT_HEAD_MODEL_URL) { |
| 724 | 724 | _headModelName = DEFAULT_HEAD_MODEL_NAME; |
| 725 | 725 | } else { |
| 726 | 726 | QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString()); |
| 727 | 727 | _headModelName = headFST["name"].toString(); |
| 728 | 728 | } |
| 729 | − | |
| 729 | + | |
| 730 | 730 | _fullAvatarModelName = "Default"; |
| 731 | 731 | } |
| 732 | 732 | } |
| @@ -736,7 +736,7 @@ void MyAvatar::loadData() { · 3 unmodified lines | ||
| 736 | 736 | } else { |
| 737 | 737 | useHeadAndBodyURLs(_headURLFromPreferences, _skeletonURLFromPreferences, _headModelName, _bodyModelName); |
| 738 | 738 | } |
| 739 | − | |
| 739 | + | |
| 740 | 740 | QVector<AttachmentData> attachmentData; |
| 741 | 741 | int attachmentCount = settings.beginReadArray("attachmentData"); |
| 742 | 742 | for (int i = 0; i < attachmentCount; i++) { |
| @@ -757,7 +757,7 @@ void MyAvatar::loadData() { · 14 unmodified lines | ||
| 757 | 757 | } |
| 758 | 758 | settings.endArray(); |
| 759 | 759 | setAttachmentData(attachmentData); |
| 760 | − | |
| 760 | + | |
| 761 | 761 | int animationCount = settings.beginReadArray("animationHandles"); |
| 762 | 762 | while (_animationHandles.size() > animationCount) { |
| 763 | 763 | _animationHandles.takeLast()->stop(); |
| @@ -780,7 +780,7 @@ void MyAvatar::loadData() { · 16 unmodified lines | ||
| 780 | 780 | handle->setStartAutomatically(settings.value("startAutomatically", true).toBool()); |
| 781 | 781 | } |
| 782 | 782 | settings.endArray(); |
| 783 | − | |
| 783 | + | |
| 784 | 784 | setDisplayName(settings.value("displayName").toString()); |
| 785 | 785 | |
| 786 | 786 | settings.endGroup(); |
| @@ -792,7 +792,7 @@ void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const { · 5 unmodified lines | ||
| 792 | 792 | settings.beginGroup(_skeletonModel.getURL().toString()); |
| 793 | 793 | settings.beginGroup(attachment.modelURL.toString()); |
| 794 | 794 | settings.setValue("jointName", attachment.jointName); |
| 795 | − | |
| 795 | + | |
| 796 | 796 | settings.beginGroup(attachment.jointName); |
| 797 | 797 | settings.setValue("translation_x", attachment.translation.x); |
| 798 | 798 | settings.setValue("translation_y", attachment.translation.y); |
| @@ -802,7 +802,7 @@ void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const { · 3 unmodified lines | ||
| 802 | 802 | settings.setValue("rotation_y", eulers.y); |
| 803 | 803 | settings.setValue("rotation_z", eulers.z); |
| 804 | 804 | settings.setValue("scale", attachment.scale); |
| 805 | − | |
| 805 | + | |
| 806 | 806 | settings.endGroup(); |
| 807 | 807 | settings.endGroup(); |
| 808 | 808 | settings.endGroup(); |
| @@ -814,7 +814,7 @@ AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString& · 5 unmodified lines | ||
| 814 | 814 | settings.beginGroup("savedAttachmentData"); |
| 815 | 815 | settings.beginGroup(_skeletonModel.getURL().toString()); |
| 816 | 816 | settings.beginGroup(modelURL.toString()); |
| 817 | − | |
| 817 | + | |
| 818 | 818 | AttachmentData attachment; |
| 819 | 819 | attachment.modelURL = modelURL; |
| 820 | 820 | if (jointName.isEmpty()) { |
| @@ -836,18 +836,18 @@ AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString& · 15 unmodified lines | ||
| 836 | 836 | } else { |
| 837 | 837 | attachment = AttachmentData(); |
| 838 | 838 | } |
| 839 | − | |
| 839 | + | |
| 840 | 840 | settings.endGroup(); |
| 841 | 841 | settings.endGroup(); |
| 842 | 842 | settings.endGroup(); |
| 843 | 843 | settings.endGroup(); |
| 844 | − | |
| 844 | + | |
| 845 | 845 | return attachment; |
| 846 | 846 | } |
| 847 | 847 | |
| 848 | 848 | int MyAvatar::parseDataAtOffset(const QByteArray& packet, int offset) { |
| 849 | 849 | qCDebug(interfaceapp) << "Error: ignoring update packet for MyAvatar" |
| 850 | − << " packetLength = " << packet.size() | |
| 850 | + << " packetLength = " << packet.size() | |
| 851 | 851 | << " offset = " << offset; |
| 852 | 852 | // this packet is just bad, so we pretend that we unpacked it ALL |
| 853 | 853 | return packet.size() - offset; |
| @@ -865,14 +865,14 @@ void MyAvatar::updateLookAtTargetAvatar() { · 11 unmodified lines | ||
| 865 | 865 | // |
| 866 | 866 | _lookAtTargetAvatar.reset(); |
| 867 | 867 | _targetAvatarPosition = glm::vec3(0.0f); |
| 868 | − | |
| 868 | + | |
| 869 | 869 | glm::vec3 lookForward = getHead()->getFinalOrientationInWorldFrame() * IDENTITY_FRONT; |
| 870 | 870 | glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition(); |
| 871 | − | |
| 871 | + | |
| 872 | 872 | float smallestAngleTo = glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES) / 2.0f; |
| 873 | 873 | const float KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR = 1.3f; |
| 874 | 874 | const float GREATEST_LOOKING_AT_DISTANCE = 10.0f; |
| 875 | − | |
| 875 | + | |
| 876 | 876 | int howManyLookingAtMe = 0; |
| 877 | 877 | foreach (const AvatarSharedPointer& avatarPointer, DependencyManager::get<AvatarManager>()->getAvatarHash()) { |
| 878 | 878 | Avatar* avatar = static_cast<Avatar*>(avatarPointer.get()); |
| @@ -1004,13 +1004,13 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN · 125 unmodified lines | ||
| 1004 | 1004 | } |
| 1005 | 1005 | |
| 1006 | 1006 | _useFullAvatar = true; |
| 1007 | − | |
| 1007 | + | |
| 1008 | 1008 | if (_fullAvatarURLFromPreferences != fullAvatarURL) { |
| 1009 | 1009 | _fullAvatarURLFromPreferences = fullAvatarURL; |
| 1010 | 1010 | if (modelName.isEmpty()) { |
| 1011 | 1011 | QVariantHash fullAvatarFST = FSTReader::downloadMapping(_fullAvatarURLFromPreferences.toString()); |
| 1012 | 1012 | _fullAvatarModelName = fullAvatarFST["name"].toString(); |
| 1013 | − } else { | |
| 1013 | + } else { | |
| 1014 | 1014 | _fullAvatarModelName = modelName; |
| 1015 | 1015 | } |
| 1016 | 1016 | } |
| @@ -1051,7 +1051,7 @@ void MyAvatar::useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, cons · 34 unmodified lines | ||
| 1051 | 1051 | if (headName.isEmpty()) { |
| 1052 | 1052 | QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString()); |
| 1053 | 1053 | _headModelName = headFST["name"].toString(); |
| 1054 | − } else { | |
| 1054 | + } else { | |
| 1055 | 1055 | _headModelName = headName; |
| 1056 | 1056 | } |
| 1057 | 1057 | } |
| @@ -1061,7 +1061,7 @@ void MyAvatar::useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, cons · 3 unmodified lines | ||
| 1061 | 1061 | if (bodyName.isEmpty()) { |
| 1062 | 1062 | QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString()); |
| 1063 | 1063 | _bodyModelName = bodyFST["name"].toString(); |
| 1064 | − } else { | |
| 1064 | + } else { | |
| 1065 | 1065 | _bodyModelName = bodyName; |
| 1066 | 1066 | } |
| 1067 | 1067 | } |
| @@ -1092,7 +1092,7 @@ void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) · 24 unmodified lines | ||
| 1092 | 1092 | glm::vec3 MyAvatar::getSkeletonPosition() const { |
| 1093 | 1093 | CameraMode mode = Application::getInstance()->getCamera()->getMode(); |
| 1094 | 1094 | if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) { |
| 1095 | − // The avatar is rotated PI about the yAxis, so we have to correct for it | |
| 1095 | + // The avatar is rotated PI about the yAxis, so we have to correct for it | |
| 1096 | 1096 | // to get the skeleton offset contribution in the world-frame. |
| 1097 | 1097 | const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); |
| 1098 | 1098 | glm::vec3 skeletonOffset = _skeletonOffset; |
| @@ -1135,9 +1135,9 @@ void MyAvatar::setScriptedMotorVelocity(const glm::vec3& velocity) { · 36 unmodified lines | ||
| 1135 | 1135 | } |
| 1136 | 1136 | |
| 1137 | 1137 | void MyAvatar::setScriptedMotorTimescale(float timescale) { |
| 1138 | − // we clamp the timescale on the large side (instead of just the low side) to prevent | |
| 1138 | + // we clamp the timescale on the large side (instead of just the low side) to prevent | |
| 1139 | 1139 | // obnoxiously large values from introducing NaN into avatar's velocity |
| 1140 | − _scriptedMotorTimescale = glm::clamp(timescale, MIN_SCRIPTED_MOTOR_TIMESCALE, | |
| 1140 | + _scriptedMotorTimescale = glm::clamp(timescale, MIN_SCRIPTED_MOTOR_TIMESCALE, | |
| 1141 | 1141 | DEFAULT_SCRIPTED_MOTOR_TIMESCALE); |
| 1142 | 1142 | } |
| 1143 | 1143 | |
| @@ -1155,14 +1155,14 @@ void MyAvatar::clearScriptableSettings() { · 11 unmodified lines | ||
| 1155 | 1155 | clearJointAnimationPriorities(); |
| 1156 | 1156 | _scriptedMotorVelocity = glm::vec3(0.0f); |
| 1157 | 1157 | _scriptedMotorTimescale = DEFAULT_SCRIPTED_MOTOR_TIMESCALE; |
| 1158 | −} | |
| 1158 | +} | |
| 1159 | 1159 | |
| 1160 | 1160 | void MyAvatar::attach(const QString& modelURL, const QString& jointName, const glm::vec3& translation, |
| 1161 | 1161 | const glm::quat& rotation, float scale, bool allowDuplicates, bool useSaved) { |
| 1162 | − if (QThread::currentThread() != thread()) { | |
| 1162 | + if (QThread::currentThread() != thread()) { | |
| 1163 | 1163 | Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved); |
| 1164 | 1164 | return; |
| 1165 | − } | |
| 1165 | + } | |
| 1166 | 1166 | if (useSaved) { |
| 1167 | 1167 | AttachmentData attachment = loadAttachmentData(modelURL, jointName); |
| 1168 | 1168 | if (attachment.isValid()) { |
| @@ -1199,7 +1199,7 @@ const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f; · 30 unmodified lines | ||
| 1199 | 1199 | |
| 1200 | 1200 | bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const { |
| 1201 | 1201 | const Head* head = getHead(); |
| 1202 | − return (renderArgs->_renderMode != RenderArgs::NORMAL_RENDER_MODE) || (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON) || | |
| 1202 | + return (renderArgs->_renderMode != RenderArgs::NORMAL_RENDER_MODE) || (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON) || | |
| 1203 | 1203 | (glm::length(cameraPosition - head->getEyePosition()) > RENDER_HEAD_CUTOFF_DISTANCE * _scale); |
| 1204 | 1204 | } |
| 1205 | 1205 | |
| @@ -1230,10 +1230,10 @@ void MyAvatar::updateOrientation(float deltaTime) { · 24 unmodified lines | ||
| 1230 | 1230 | |
| 1231 | 1231 | //Invert yaw and roll when in mirror mode |
| 1232 | 1232 | if (Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_MIRROR) { |
| 1233 | − YAW(euler) *= -1.0; | |
| 1234 | − ROLL(euler) *= -1.0; | |
| 1233 | + YAW(euler) *= -1.0f; | |
| 1234 | + ROLL(euler) *= -1.0f; | |
| 1235 | 1235 | } |
| 1236 | − | |
| 1236 | + | |
| 1237 | 1237 | Head* head = getHead(); |
| 1238 | 1238 | head->setBaseYaw(YAW(euler)); |
| 1239 | 1239 | head->setBasePitch(PITCH(euler)); |
| @@ -1246,9 +1246,9 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe · 6 unmodified lines | ||
| 1246 | 1246 | return localVelocity; |
| 1247 | 1247 | } |
| 1248 | 1248 | // compute motor efficiency |
| 1249 | − // The timescale of the motor is the approximate time it takes for the motor to | |
| 1250 | − // accomplish its intended localVelocity. A short timescale makes the motor strong, | |
| 1251 | − // and a long timescale makes it weak. The value of timescale to use depends | |
| 1249 | + // The timescale of the motor is the approximate time it takes for the motor to | |
| 1250 | + // accomplish its intended localVelocity. A short timescale makes the motor strong, | |
| 1251 | + // and a long timescale makes it weak. The value of timescale to use depends | |
| 1252 | 1252 | // on what the motor is doing: |
| 1253 | 1253 | // |
| 1254 | 1254 | // (1) braking --> short timescale (aggressive motor assertion) |
| @@ -1259,8 +1259,8 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe · 4 unmodified lines | ||
| 1259 | 1259 | float MIN_KEYBOARD_BRAKE_SPEED = 0.3f; |
| 1260 | 1260 | float timescale = MAX_KEYBOARD_MOTOR_TIMESCALE; |
| 1261 | 1261 | bool isThrust = (glm::length2(_thrust) > EPSILON); |
| 1262 | − if (_isPushing || isThrust || | |
| 1263 | − (_scriptedMotorTimescale < MAX_KEYBOARD_MOTOR_TIMESCALE && | |
| 1262 | + if (_isPushing || isThrust || | |
| 1263 | + (_scriptedMotorTimescale < MAX_KEYBOARD_MOTOR_TIMESCALE && | |
| 1264 | 1264 | _motionBehaviors | AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED)) { |
| 1265 | 1265 | // we don't want to brake if something is pushing the avatar around |
| 1266 | 1266 | timescale = _keyboardMotorTimescale; |
| @@ -1277,18 +1277,18 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe · 10 unmodified lines | ||
| 1277 | 1277 | float motorEfficiency = glm::clamp(deltaTime / timescale, 0.0f, 1.0f); |
| 1278 | 1278 | |
| 1279 | 1279 | glm::vec3 newLocalVelocity = localVelocity; |
| 1280 | − float keyboardInput = fabsf(_driveKeys[FWD] - _driveKeys[BACK]) + | |
| 1281 | − (fabsf(_driveKeys[RIGHT] - _driveKeys[LEFT])) + | |
| 1280 | + float keyboardInput = fabsf(_driveKeys[FWD] - _driveKeys[BACK]) + | |
| 1281 | + (fabsf(_driveKeys[RIGHT] - _driveKeys[LEFT])) + | |
| 1282 | 1282 | fabsf(_driveKeys[UP] - _driveKeys[DOWN]); |
| 1283 | 1283 | if (keyboardInput) { |
| 1284 | 1284 | // Compute keyboard input |
| 1285 | 1285 | glm::vec3 front = (_driveKeys[FWD] - _driveKeys[BACK]) * IDENTITY_FRONT; |
| 1286 | 1286 | glm::vec3 right = (_driveKeys[RIGHT] - _driveKeys[LEFT]) * IDENTITY_RIGHT; |
| 1287 | 1287 | glm::vec3 up = (_driveKeys[UP] - _driveKeys[DOWN]) * IDENTITY_UP; |
| 1288 | − | |
| 1288 | + | |
| 1289 | 1289 | glm::vec3 direction = front + right + up; |
| 1290 | 1290 | float directionLength = glm::length(direction); |
| 1291 | − | |
| 1291 | + | |
| 1292 | 1292 | // Compute motor magnitude |
| 1293 | 1293 | if (directionLength > EPSILON) { |
| 1294 | 1294 | direction /= directionLength; |
| @@ -1318,7 +1318,7 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe · 23 unmodified lines | ||
| 1318 | 1318 | motorEfficiency = glm::clamp(deltaTime / WALK_ACCELERATION_TIMESCALE, 0.0f, 1.0f); |
| 1319 | 1319 | } |
| 1320 | 1320 | _isPushing = true; |
| 1321 | − } | |
| 1321 | + } | |
| 1322 | 1322 | newLocalVelocity = localVelocity + motorEfficiency * (_keyboardMotorVelocity - localVelocity); |
| 1323 | 1323 | } else { |
| 1324 | 1324 | _keyboardMotorVelocity = glm::vec3(0.0f); |
| @@ -1382,13 +1382,13 @@ void MyAvatar::updatePosition(float deltaTime) { · 57 unmodified lines | ||
| 1382 | 1382 | _targetVelocity *= MAX_AVATAR_SPEED / speed; |
| 1383 | 1383 | speed = MAX_AVATAR_SPEED; |
| 1384 | 1384 | } |
| 1385 | − | |
| 1385 | + | |
| 1386 | 1386 | if (speed > MIN_AVATAR_SPEED && !_characterController.isEnabled()) { |
| 1387 | 1387 | // update position ourselves |
| 1388 | 1388 | applyPositionDelta(deltaTime * _targetVelocity); |
| 1389 | 1389 | measureMotionDerivatives(deltaTime); |
| 1390 | 1390 | } // else physics will move avatar later |
| 1391 | − | |
| 1391 | + | |
| 1392 | 1392 | // update _moving flag based on speed |
| 1393 | 1393 | const float MOVING_SPEED_THRESHOLD = 0.01f; |
| 1394 | 1394 | _moving = speed > MOVING_SPEED_THRESHOLD; |
| @@ -1405,7 +1405,7 @@ bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float · 10 unmodified lines | ||
| 1405 | 1405 | float xzDistance = sqrt(positionBA.x * positionBA.x + positionBA.z * positionBA.z); |
| 1406 | 1406 | if (xzDistance < (radiusA + radiusB)) { |
| 1407 | 1407 | float yDistance = fabs(positionBA.y); |
| 1408 | − float halfHeights = 0.5 * (heightA + heightB); | |
| 1408 | + float halfHeights = 0.5f * (heightA + heightB); | |
| 1409 | 1409 | if (yDistance < halfHeights) { |
| 1410 | 1410 | // cylinders collide |
| 1411 | 1411 | if (xzDistance > 0.0f) { |
| @@ -1448,60 +1448,60 @@ void MyAvatar::maybeUpdateBillboard() { · 36 unmodified lines | ||
| 1448 | 1448 | } |
| 1449 | 1449 | gpu::Context context(new gpu::GLBackend()); |
| 1450 | 1450 | RenderArgs renderArgs(&context); |
| 1451 | − QImage image = Application::getInstance()->renderAvatarBillboard(&renderArgs); | |
| 1451 | + QImage image = qApp->renderAvatarBillboard(&renderArgs); | |
| 1452 | 1452 | _billboard.clear(); |
| 1453 | 1453 | QBuffer buffer(&_billboard); |
| 1454 | 1454 | buffer.open(QIODevice::WriteOnly); |
| 1455 | 1455 | image.save(&buffer, "PNG"); |
| 1456 | 1456 | _billboardValid = true; |
| 1457 | − | |
| 1457 | + | |
| 1458 | 1458 | sendBillboardPacket(); |
| 1459 | 1459 | } |
| 1460 | 1460 | |
| 1461 | 1461 | void MyAvatar::increaseSize() { |
| 1462 | 1462 | if ((1.0f + SCALING_RATIO) * _targetScale < MAX_AVATAR_SCALE) { |
| 1463 | 1463 | _targetScale *= (1.0f + SCALING_RATIO); |
| 1464 | − qCDebug(interfaceapp, "Changed scale to %f", _targetScale); | |
| 1464 | + qCDebug(interfaceapp, "Changed scale to %f", (double)_targetScale); | |
| 1465 | 1465 | } |
| 1466 | 1466 | } |
| 1467 | 1467 | |
| 1468 | 1468 | void MyAvatar::decreaseSize() { |
| 1469 | 1469 | if (MIN_AVATAR_SCALE < (1.0f - SCALING_RATIO) * _targetScale) { |
| 1470 | 1470 | _targetScale *= (1.0f - SCALING_RATIO); |
| 1471 | − qCDebug(interfaceapp, "Changed scale to %f", _targetScale); | |
| 1471 | + qCDebug(interfaceapp, "Changed scale to %f", (double)_targetScale); | |
| 1472 | 1472 | } |
| 1473 | 1473 | } |
| 1474 | 1474 | |
| 1475 | 1475 | void MyAvatar::resetSize() { |
| 1476 | 1476 | _targetScale = 1.0f; |
| 1477 | − qCDebug(interfaceapp, "Reseted scale to %f", _targetScale); | |
| 1477 | + qCDebug(interfaceapp, "Reseted scale to %f", (double)_targetScale); | |
| 1478 | 1478 | } |
| 1479 | 1479 | |
| 1480 | 1480 | void MyAvatar::goToLocation(const glm::vec3& newPosition, |
| 1481 | 1481 | bool hasOrientation, const glm::quat& newOrientation, |
| 1482 | 1482 | bool shouldFaceLocation) { |
| 1483 | − | |
| 1483 | + | |
| 1484 | 1484 | qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - moving to " << newPosition.x << ", " |
| 1485 | 1485 | << newPosition.y << ", " << newPosition.z; |
| 1486 | − | |
| 1486 | + | |
| 1487 | 1487 | glm::vec3 shiftedPosition = newPosition; |
| 1488 | − | |
| 1488 | + | |
| 1489 | 1489 | if (hasOrientation) { |
| 1490 | 1490 | qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - new orientation is " |
| 1491 | 1491 | << newOrientation.x << ", " << newOrientation.y << ", " << newOrientation.z << ", " << newOrientation.w; |
| 1492 | − | |
| 1492 | + | |
| 1493 | 1493 | // orient the user to face the target |
| 1494 | 1494 | glm::quat quatOrientation = newOrientation; |
| 1495 | − | |
| 1495 | + | |
| 1496 | 1496 | if (shouldFaceLocation) { |
| 1497 | − | |
| 1497 | + | |
| 1498 | 1498 | quatOrientation = newOrientation * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); |
| 1499 | − | |
| 1499 | + | |
| 1500 | 1500 | // move the user a couple units away |
| 1501 | 1501 | const float DISTANCE_TO_USER = 2.0f; |
| 1502 | 1502 | shiftedPosition = newPosition - quatOrientation * IDENTITY_FRONT * DISTANCE_TO_USER; |
| 1503 | 1503 | } |
| 1504 | − | |
| 1504 | + | |
| 1505 | 1505 | setOrientation(quatOrientation); |
| 1506 | 1506 | } |
| 1507 | 1507 | |
| @@ -1547,7 +1547,6 @@ void MyAvatar::renderLaserPointers() { · 39 unmodified lines | ||
| 1547 | 1547 | |
| 1548 | 1548 | //Gets the tip position for the laser pointer |
| 1549 | 1549 | glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) { |
| 1550 | − const ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay(); | |
| 1551 | 1550 | glm::vec3 direction = glm::normalize(palm->getTipPosition() - palm->getPosition()); |
| 1552 | 1551 | |
| 1553 | 1552 | glm::vec3 position = palm->getPosition(); |
| @@ -1556,7 +1555,8 @@ glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) { · 2 unmodified lines | ||
| 1556 | 1555 | |
| 1557 | 1556 | |
| 1558 | 1557 | glm::vec3 result; |
| 1559 | − if (applicationOverlay.calculateRayUICollisionPoint(position, direction, result)) { | |
| 1558 | + const auto& compositor = qApp->getApplicationCompositor(); | |
| 1559 | + if (compositor.calculateRayUICollisionPoint(position, direction, result)) { | |
| 1560 | 1560 | return result; |
| 1561 | 1561 | } |
| 1562 | 1562 | |
| @@ -1569,8 +1569,8 @@ void MyAvatar::clearDriveKeys() { · 6 unmodified lines | ||
| 1569 | 1569 | } |
| 1570 | 1570 | } |
| 1571 | 1571 | |
| 1572 | −void MyAvatar::relayDriveKeysToCharacterController() { | |
| 1572 | +void MyAvatar::relayDriveKeysToCharacterController() { | |
| 1573 | 1573 | if (_driveKeys[UP] > 0.0f) { |
| 1574 | − _characterController.jump(); | |
| 1574 | + _characterController.jump(); | |
| 1575 | 1575 | } |
| 1576 | 1576 | } |
| @@ -90,7 +90,7 @@ public: · 89 unmodified lines | ||
| 90 | 90 | |
| 91 | 91 | void relayDriveKeysToCharacterController(); |
| 92 | 92 | |
| 93 | − bool isMyAvatar() { return true; } | |
| 93 | + bool isMyAvatar() const { return true; } | |
| 94 | 94 | |
| 95 | 95 | bool isLookingAtLeftEye(); |
| 96 | 96 | |
| @@ -1,121 +0,0 @@ | ||
| 1 | −// | |
| 2 | −// CameraToolBox.cpp | |
| 3 | −// interface/src/devices | |
| 4 | −// | |
| 5 | −// Created by David Rowe on 30 Apr 2015. | |
| 6 | −// Copyright 2015 High Fidelity, Inc. | |
| 7 | −// | |
| 8 | −// Distributed under the Apache License, Version 2.0. | |
| 9 | −// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 10 | −// | |
| 11 | − | |
| 12 | −#include "InterfaceConfig.h" | |
| 13 | − | |
| 14 | −#include <GLCanvas.h> | |
| 15 | −#include <PathUtils.h> | |
| 16 | − | |
| 17 | −#include "gpu/GLBackend.h" | |
| 18 | −#include "Application.h" | |
| 19 | −#include "CameraToolBox.h" | |
| 20 | −#include "FaceTracker.h" | |
| 21 | − | |
| 22 | − | |
| 23 | −CameraToolBox::CameraToolBox() : | |
| 24 | − _iconPulseTimeReference(usecTimestampNow()), | |
| 25 | − _doubleClickTimer(NULL) | |
| 26 | −{ | |
| 27 | −} | |
| 28 | − | |
| 29 | −CameraToolBox::~CameraToolBox() { | |
| 30 | − if (_doubleClickTimer) { | |
| 31 | − _doubleClickTimer->stop(); | |
| 32 | − delete _doubleClickTimer; | |
| 33 | − } | |
| 34 | −} | |
| 35 | − | |
| 36 | −bool CameraToolBox::mousePressEvent(int x, int y) { | |
| 37 | − if (_iconBounds.contains(x, y)) { | |
| 38 | − if (!_doubleClickTimer) { | |
| 39 | − // Toggle mute after waiting to check that it's not a double-click. | |
| 40 | − const int DOUBLE_CLICK_WAIT = 200; // ms | |
| 41 | − _doubleClickTimer = new QTimer(this); | |
| 42 | − connect(_doubleClickTimer, SIGNAL(timeout()), this, SLOT(toggleMute())); | |
| 43 | − _doubleClickTimer->setSingleShot(true); | |
| 44 | − _doubleClickTimer->setInterval(DOUBLE_CLICK_WAIT); | |
| 45 | − _doubleClickTimer->start(); | |
| 46 | − } | |
| 47 | − return true; | |
| 48 | − } | |
| 49 | − return false; | |
| 50 | −} | |
| 51 | − | |
| 52 | −bool CameraToolBox::mouseDoublePressEvent(int x, int y) { | |
| 53 | − if (_iconBounds.contains(x, y)) { | |
| 54 | − if (_doubleClickTimer) { | |
| 55 | − _doubleClickTimer->stop(); | |
| 56 | − delete _doubleClickTimer; | |
| 57 | − _doubleClickTimer = NULL; | |
| 58 | − } | |
| 59 | − Application::getInstance()->resetSensors(); | |
| 60 | − return true; | |
| 61 | − } | |
| 62 | − return false; | |
| 63 | −} | |
| 64 | − | |
| 65 | −void CameraToolBox::toggleMute() { | |
| 66 | − delete _doubleClickTimer; | |
| 67 | − _doubleClickTimer = NULL; | |
| 68 | − | |
| 69 | − FaceTracker* faceTracker = Application::getInstance()->getSelectedFaceTracker(); | |
| 70 | − if (faceTracker) { | |
| 71 | − faceTracker->toggleMute(); | |
| 72 | − } | |
| 73 | −} | |
| 74 | − | |
| 75 | −void CameraToolBox::render(int x, int y, bool boxed) { | |
| 76 | − glEnable(GL_TEXTURE_2D); | |
| 77 | − | |
| 78 | − if (!_enabledTexture) { | |
| 79 | − _enabledTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/face.svg"); | |
| 80 | − } | |
| 81 | − if (!_mutedTexture) { | |
| 82 | − _mutedTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/face-mute.svg"); | |
| 83 | − } | |
| 84 | − | |
| 85 | − const int MUTE_ICON_SIZE = 24; | |
| 86 | − _iconBounds = QRect(x, y, MUTE_ICON_SIZE, MUTE_ICON_SIZE); | |
| 87 | − float iconColor = 1.0f; | |
| 88 | − if (!Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking)) { | |
| 89 | − glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_enabledTexture)); | |
| 90 | − } else { | |
| 91 | − glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_mutedTexture)); | |
| 92 | − | |
| 93 | − // Make muted icon pulsate | |
| 94 | − static const float PULSE_MIN = 0.4f; | |
| 95 | − static const float PULSE_MAX = 1.0f; | |
| 96 | − static const float PULSE_FREQUENCY = 1.0f; // in Hz | |
| 97 | − qint64 now = usecTimestampNow(); | |
| 98 | − if (now - _iconPulseTimeReference > (qint64)USECS_PER_SECOND) { | |
| 99 | − // Prevents t from getting too big, which would diminish glm::cos precision | |
| 100 | − _iconPulseTimeReference = now - ((now - _iconPulseTimeReference) % USECS_PER_SECOND); | |
| 101 | − } | |
| 102 | − float t = (float)(now - _iconPulseTimeReference) / (float)USECS_PER_SECOND; | |
| 103 | − float pulseFactor = (glm::cos(t * PULSE_FREQUENCY * 2.0f * PI) + 1.0f) / 2.0f; | |
| 104 | − iconColor = PULSE_MIN + (PULSE_MAX - PULSE_MIN) * pulseFactor; | |
| 105 | − } | |
| 106 | − | |
| 107 | − glm::vec4 quadColor(iconColor, iconColor, iconColor, 1.0f); | |
| 108 | − | |
| 109 | − glm::vec2 topLeft(_iconBounds.left(), _iconBounds.top()); | |
| 110 | − glm::vec2 bottomRight(_iconBounds.right(), _iconBounds.bottom()); | |
| 111 | − glm::vec2 texCoordTopLeft(1,1); | |
| 112 | − glm::vec2 texCoordBottomRight(0,0); | |
| 113 | − | |
| 114 | − if (_boxQuadID == GeometryCache::UNKNOWN_ID) { | |
| 115 | − _boxQuadID = DependencyManager::get<GeometryCache>()->allocateID(); | |
| 116 | − } | |
| 117 | − | |
| 118 | − DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor, _boxQuadID); | |
| 119 | − | |
| 120 | − glDisable(GL_TEXTURE_2D); | |
| 121 | −} | |
| @@ -1,45 +0,0 @@ | ||
| 1 | −// | |
| 2 | −// CameraToolBox.h | |
| 3 | −// interface/src/devices | |
| 4 | −// | |
| 5 | −// Created by David Rowe on 30 Apr 2015. | |
| 6 | −// Copyright 2015 High Fidelity, Inc. | |
| 7 | −// | |
| 8 | −// Distributed under the Apache License, Version 2.0. | |
| 9 | −// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 10 | −// | |
| 11 | − | |
| 12 | −#ifndef hifi_CameraToolBox_h | |
| 13 | −#define hifi_CameraToolBox_h | |
| 14 | − | |
| 15 | −#include <QObject> | |
| 16 | − | |
| 17 | −#include <DependencyManager.h> | |
| 18 | −#include <GeometryCache.h> | |
| 19 | − | |
| 20 | −class CameraToolBox : public QObject, public Dependency { | |
| 21 | − Q_OBJECT | |
| 22 | − SINGLETON_DEPENDENCY | |
| 23 | − | |
| 24 | −public: | |
| 25 | − void render(int x, int y, bool boxed); | |
| 26 | − bool mousePressEvent(int x, int y); | |
| 27 | − bool mouseDoublePressEvent(int x, int y); | |
| 28 | − | |
| 29 | −protected: | |
| 30 | − CameraToolBox(); | |
| 31 | − ~CameraToolBox(); | |
| 32 | − | |
| 33 | −private slots: | |
| 34 | − void toggleMute(); | |
| 35 | − | |
| 36 | −private: | |
| 37 | − gpu::TexturePointer _enabledTexture; | |
| 38 | − gpu::TexturePointer _mutedTexture; | |
| 39 | − int _boxQuadID = GeometryCache::UNKNOWN_ID; | |
| 40 | − QRect _iconBounds; | |
| 41 | − qint64 _iconPulseTimeReference = 0; | |
| 42 | − QTimer* _doubleClickTimer; | |
| 43 | −}; | |
| 44 | − | |
| 45 | −#endif // hifi_CameraToolBox_h | |
| @@ -415,7 +415,7 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { · 414 unmodified lines | ||
| 415 | 415 | float browUp = _coefficients[_browUpCenterIndex]; |
| 416 | 416 | if (isFiltering) { |
| 417 | 417 | const float BROW_VELOCITY_FILTER_STRENGTH = 0.5f; |
| 418 | − float velocity = fabs(browUp - _lastBrowUp) / _averageMessageTime; | |
| 418 | + float velocity = fabsf(browUp - _lastBrowUp) / _averageMessageTime; | |
| 419 | 419 | float velocityFilter = glm::clamp(velocity * BROW_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f); |
| 420 | 420 | _filteredBrowUp = velocityFilter * browUp + (1.0f - velocityFilter) * _filteredBrowUp; |
| 421 | 421 | _lastBrowUp = browUp; |
| @@ -438,11 +438,12 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { · 16 unmodified lines | ||
| 438 | 438 | |
| 439 | 439 | // Velocity filter EyeBlink values |
| 440 | 440 | const float DDE_EYEBLINK_SCALE = 3.0f; |
| 441 | − float eyeBlinks[] = { DDE_EYEBLINK_SCALE * _coefficients[_leftBlinkIndex], DDE_EYEBLINK_SCALE * _coefficients[_rightBlinkIndex] }; | |
| 441 | + float eyeBlinks[] = { DDE_EYEBLINK_SCALE * _coefficients[_leftBlinkIndex], | |
| 442 | + DDE_EYEBLINK_SCALE * _coefficients[_rightBlinkIndex] }; | |
| 442 | 443 | if (isFiltering) { |
| 443 | 444 | const float BLINK_VELOCITY_FILTER_STRENGTH = 0.3f; |
| 444 | 445 | for (int i = 0; i < 2; i++) { |
| 445 | − float velocity = fabs(eyeBlinks[i] - _lastEyeBlinks[i]) / _averageMessageTime; | |
| 446 | + float velocity = fabsf(eyeBlinks[i] - _lastEyeBlinks[i]) / _averageMessageTime; | |
| 446 | 447 | float velocityFilter = glm::clamp(velocity * BLINK_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f); |
| 447 | 448 | _filteredEyeBlinks[i] = velocityFilter * eyeBlinks[i] + (1.0f - velocityFilter) * _filteredEyeBlinks[i]; |
| 448 | 449 | _lastEyeBlinks[i] = eyeBlinks[i]; |
| @@ -479,9 +480,9 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { · 30 unmodified lines | ||
| 479 | 480 | if (_eyeStates[i] == EYE_CLOSING) { |
| 480 | 481 | // Close eyelid until it's fully closed |
| 481 | 482 | float closingValue = _lastEyeCoefficients[i] + EYELID_MOVEMENT_RATE * _averageMessageTime; |
| 482 | − if (closingValue >= 1.0) { | |
| 483 | + if (closingValue >= 1.0f) { | |
| 483 | 484 | _eyeStates[i] = EYE_CLOSED; |
| 484 | − eyeCoefficients[i] = 1.0; | |
| 485 | + eyeCoefficients[i] = 1.0f; | |
| 485 | 486 | } else { |
| 486 | 487 | eyeCoefficients[i] = closingValue; |
| 487 | 488 | } |
| @@ -11,13 +11,13 @@ · 10 unmodified lines | ||
| 11 | 11 | // |
| 12 | 12 | |
| 13 | 13 | #include "InterfaceConfig.h" |
| 14 | − | |
| 15 | 14 | #include "OculusManager.h" |
| 16 | 15 | #include "ui/overlays/Text3DOverlay.h" |
| 17 | 16 | |
| 17 | +#include <CursorManager.h> | |
| 18 | 18 | #include <QDesktopWidget> |
| 19 | 19 | #include <QGuiApplication> |
| 20 | −#include <QScreen> | |
| 20 | +#include <QScreen> | |
| 21 | 21 | #include <QOpenGLTimerQuery> |
| 22 | 22 | |
| 23 | 23 | #include <glm/glm.hpp> |
| @@ -25,6 +25,9 @@ · 1 unmodified line | ||
| 25 | 25 | #include <avatar/AvatarManager.h> |
| 26 | 26 | #include <avatar/MyAvatar.h> |
| 27 | 27 | #include <GlowEffect.h> |
| 28 | +#include <GlWindow.h> | |
| 29 | +#include <gpu/GLBackend.h> | |
| 30 | +#include <OglplusHelpers.h> | |
| 28 | 31 | #include <PathUtils.h> |
| 29 | 32 | #include <SharedUtil.h> |
| 30 | 33 | #include <UserActivityLogger.h> |
| @@ -34,8 +37,6 @@ · 3 unmodified lines | ||
| 34 | 37 | #include "InterfaceLogging.h" |
| 35 | 38 | #include "Application.h" |
| 36 | 39 | |
| 37 | −#include <gpu/GLBackend.h> | |
| 38 | − | |
| 39 | 40 | template <typename Function> |
| 40 | 41 | void for_each_eye(Function function) { |
| 41 | 42 | for (ovrEyeType eye = ovrEyeType::ovrEye_Left; |
| @@ -52,202 +53,413 @@ void for_each_eye(const ovrHmd & hmd, Function function) { · 10 unmodified lines | ||
| 52 | 53 | function(eye); |
| 53 | 54 | } |
| 54 | 55 | } |
| 56 | +enum CalibrationState { | |
| 57 | + UNCALIBRATED, | |
| 58 | + WAITING_FOR_DELTA, | |
| 59 | + WAITING_FOR_ZERO, | |
| 60 | + WAITING_FOR_ZERO_HELD, | |
| 61 | + CALIBRATED | |
| 62 | +}; | |
| 63 | + | |
| 64 | +inline glm::mat4 toGlm(const ovrMatrix4f & om) { | |
| 65 | + return glm::transpose(glm::make_mat4(&om.M[0][0])); | |
| 66 | +} | |
| 55 | 67 | |
| 56 | −#ifdef OVR_CLIENT_DISTORTION | |
| 57 | −ProgramObject OculusManager::_program; | |
| 58 | −int OculusManager::_textureLocation; | |
| 59 | −int OculusManager::_eyeToSourceUVScaleLocation; | |
| 60 | −int OculusManager::_eyeToSourceUVOffsetLocation; | |
| 61 | −int OculusManager::_eyeRotationStartLocation; | |
| 62 | −int OculusManager::_eyeRotationEndLocation; | |
| 63 | −int OculusManager::_positionAttributeLocation; | |
| 64 | −int OculusManager::_colorAttributeLocation; | |
| 65 | −int OculusManager::_texCoord0AttributeLocation; | |
| 66 | −int OculusManager::_texCoord1AttributeLocation; | |
| 67 | −int OculusManager::_texCoord2AttributeLocation; | |
| 68 | −ovrVector2f OculusManager::_UVScaleOffset[ovrEye_Count][2]; | |
| 69 | −GLuint OculusManager::_vertices[ovrEye_Count] = { 0, 0 }; | |
| 70 | −GLuint OculusManager::_indices[ovrEye_Count] = { 0, 0 }; | |
| 71 | −GLsizei OculusManager::_meshSize[ovrEye_Count] = { 0, 0 }; | |
| 72 | −ovrFrameTiming OculusManager::_hmdFrameTiming; | |
| 73 | −bool OculusManager::_programInitialized = false; | |
| 74 | −#endif | |
| 68 | +inline glm::mat4 toGlm(const ovrFovPort & fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) { | |
| 69 | + return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true)); | |
| 70 | +} | |
| 75 | 71 | |
| 76 | −ovrTexture OculusManager::_eyeTextures[ovrEye_Count]; | |
| 77 | −bool OculusManager::_isConnected = false; | |
| 78 | −ovrHmd OculusManager::_ovrHmd; | |
| 79 | −ovrFovPort OculusManager::_eyeFov[ovrEye_Count]; | |
| 80 | −ovrVector3f OculusManager::_eyeOffset[ovrEye_Count]; | |
| 81 | −ovrEyeRenderDesc OculusManager::_eyeRenderDesc[ovrEye_Count]; | |
| 82 | −ovrSizei OculusManager::_renderTargetSize; | |
| 83 | −glm::mat4 OculusManager::_eyeProjection[ovrEye_Count]; | |
| 84 | −unsigned int OculusManager::_frameIndex = 0; | |
| 85 | −bool OculusManager::_frameTimingActive = false; | |
| 86 | −Camera* OculusManager::_camera = NULL; | |
| 87 | −ovrEyeType OculusManager::_activeEye = ovrEye_Count; | |
| 88 | −bool OculusManager::_hswDismissed = false; | |
| 89 | − | |
| 90 | −float OculusManager::CALIBRATION_DELTA_MINIMUM_LENGTH = 0.02f; | |
| 91 | −float OculusManager::CALIBRATION_DELTA_MINIMUM_ANGLE = 5.0f * RADIANS_PER_DEGREE; | |
| 92 | −float OculusManager::CALIBRATION_ZERO_MAXIMUM_LENGTH = 0.01f; | |
| 93 | −float OculusManager::CALIBRATION_ZERO_MAXIMUM_ANGLE = 2.0f * RADIANS_PER_DEGREE; | |
| 94 | −quint64 OculusManager::CALIBRATION_ZERO_HOLD_TIME = 3000000; // usec | |
| 95 | −float OculusManager::CALIBRATION_MESSAGE_DISTANCE = 2.5f; | |
| 96 | −OculusManager::CalibrationState OculusManager::_calibrationState; | |
| 97 | −glm::vec3 OculusManager::_calibrationPosition; | |
| 98 | −glm::quat OculusManager::_calibrationOrientation; | |
| 99 | −quint64 OculusManager::_calibrationStartTime; | |
| 100 | −int OculusManager::_calibrationMessage = 0; | |
| 101 | −glm::vec3 OculusManager::_eyePositions[ovrEye_Count]; | |
| 102 | −// TODO expose this as a developer toggle | |
| 103 | −bool OculusManager::_eyePerFrameMode = false; | |
| 104 | −ovrEyeType OculusManager::_lastEyeRendered = ovrEye_Count; | |
| 105 | −ovrSizei OculusManager::_recommendedTexSize = { 0, 0 }; | |
| 106 | −float OculusManager::_offscreenRenderScale = 1.0; | |
| 72 | +inline glm::vec3 toGlm(const ovrVector3f & ov) { | |
| 73 | + return glm::make_vec3(&ov.x); | |
| 74 | +} | |
| 107 | 75 | |
| 76 | +inline glm::vec2 toGlm(const ovrVector2f & ov) { | |
| 77 | + return glm::make_vec2(&ov.x); | |
| 78 | +} | |
| 108 | 79 | |
| 109 | −void OculusManager::initSdk() { | |
| 110 | − ovr_Initialize(); | |
| 111 | − _ovrHmd = ovrHmd_Create(0); | |
| 112 | − if (!_ovrHmd) { | |
| 113 | − _ovrHmd = ovrHmd_CreateDebug(ovrHmd_DK2); | |
| 114 | − } | |
| 80 | +inline glm::ivec2 toGlm(const ovrVector2i & ov) { | |
| 81 | + return glm::ivec2(ov.x, ov.y); | |
| 115 | 82 | } |
| 116 | 83 | |
| 117 | −void OculusManager::shutdownSdk() { | |
| 118 | − if (_ovrHmd) { | |
| 119 | − ovrHmd_Destroy(_ovrHmd); | |
| 120 | − _ovrHmd = nullptr; | |
| 121 | − ovr_Shutdown(); | |
| 122 | − } | |
| 84 | +inline glm::uvec2 toGlm(const ovrSizei & ov) { | |
| 85 | + return glm::uvec2(ov.w, ov.h); | |
| 123 | 86 | } |
| 124 | 87 | |
| 125 | −void OculusManager::init() { | |
| 126 | −#ifdef OVR_DIRECT_MODE | |
| 127 | − initSdk(); | |
| 128 | −#endif | |
| 88 | +inline glm::quat toGlm(const ovrQuatf & oq) { | |
| 89 | + return glm::make_quat(&oq.x); | |
| 129 | 90 | } |
| 130 | 91 | |
| 131 | −void OculusManager::deinit() { | |
| 132 | −#ifdef OVR_DIRECT_MODE | |
| 133 | − shutdownSdk(); | |
| 134 | −#endif | |
| 92 | +inline glm::mat4 toGlm(const ovrPosef & op) { | |
| 93 | + glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation)); | |
| 94 | + glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position)); | |
| 95 | + return translation * orientation; | |
| 135 | 96 | } |
| 136 | 97 | |
| 137 | −void OculusManager::connect() { | |
| 138 | −#ifndef OVR_DIRECT_MODE | |
| 139 | − initSdk(); | |
| 140 | −#endif | |
| 141 | − _calibrationState = UNCALIBRATED; | |
| 142 | − qCDebug(interfaceapp) << "Oculus SDK" << OVR_VERSION_STRING; | |
| 143 | − if (_ovrHmd) { | |
| 144 | − if (!_isConnected) { | |
| 145 | − UserActivityLogger::getInstance().connectedDevice("hmd", "oculus"); | |
| 98 | +inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) { | |
| 99 | + ovrMatrix4f result; | |
| 100 | + glm::mat4 transposed(glm::transpose(m)); | |
| 101 | + memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16); | |
| 102 | + return result; | |
| 103 | +} | |
| 104 | + | |
| 105 | +inline ovrVector3f ovrFromGlm(const glm::vec3 & v) { | |
| 106 | + return{ v.x, v.y, v.z }; | |
| 107 | +} | |
| 108 | + | |
| 109 | +inline ovrVector2f ovrFromGlm(const glm::vec2 & v) { | |
| 110 | + return{ v.x, v.y }; | |
| 111 | +} | |
| 112 | + | |
| 113 | +inline ovrSizei ovrFromGlm(const glm::uvec2 & v) { | |
| 114 | + return{ (int)v.x, (int)v.y }; | |
| 115 | +} | |
| 116 | + | |
| 117 | +inline ovrQuatf ovrFromGlm(const glm::quat & q) { | |
| 118 | + return{ q.x, q.y, q.z, q.w }; | |
| 119 | +} | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | +#ifdef Q_OS_WIN | |
| 124 | + | |
| 125 | +// A base class for FBO wrappers that need to use the Oculus C | |
| 126 | +// API to manage textures via ovrHmd_CreateSwapTextureSetGL, | |
| 127 | +// ovrHmd_CreateMirrorTextureGL, etc | |
| 128 | +template <typename C> | |
| 129 | +struct RiftFramebufferWrapper : public FramebufferWrapper<C, char> { | |
| 130 | + ovrHmd hmd; | |
| 131 | + RiftFramebufferWrapper(const ovrHmd & hmd) : hmd(hmd) { | |
| 132 | + color = 0; | |
| 133 | + depth = 0; | |
| 134 | + }; | |
| 135 | + | |
| 136 | + void Resize(const uvec2 & size) { | |
| 137 | + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oglplus::GetName(fbo)); | |
| 138 | + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | |
| 139 | + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); | |
| 140 | + this->size = size; | |
| 141 | + initColor(); | |
| 142 | + initDone(); | |
| 143 | + } | |
| 144 | + | |
| 145 | +protected: | |
| 146 | + virtual void initDepth() override final { | |
| 147 | + } | |
| 148 | +}; | |
| 149 | + | |
| 150 | +// A wrapper for constructing and using a swap texture set, | |
| 151 | +// where each frame you draw to a texture via the FBO, | |
| 152 | +// then submit it and increment to the next texture. | |
| 153 | +// The Oculus SDK manages the creation and destruction of | |
| 154 | +// the textures | |
| 155 | +struct SwapFramebufferWrapper : public RiftFramebufferWrapper<ovrSwapTextureSet*> { | |
| 156 | + SwapFramebufferWrapper(const ovrHmd & hmd) | |
| 157 | + : RiftFramebufferWrapper(hmd) { | |
| 158 | + } | |
| 159 | + | |
| 160 | + ~SwapFramebufferWrapper() { | |
| 161 | + if (color) { | |
| 162 | + ovrHmd_DestroySwapTextureSet(hmd, color); | |
| 163 | + color = nullptr; | |
| 146 | 164 | } |
| 147 | − _isConnected = true; | |
| 148 | − | |
| 149 | − for_each_eye([&](ovrEyeType eye) { | |
| 150 | − _eyeFov[eye] = _ovrHmd->DefaultEyeFov[eye]; | |
| 151 | − }); | |
| 152 | − | |
| 153 | − ovrGLConfig cfg; | |
| 154 | − memset(&cfg, 0, sizeof(cfg)); | |
| 155 | − cfg.OGL.Header.API = ovrRenderAPI_OpenGL; | |
| 156 | − cfg.OGL.Header.BackBufferSize = _ovrHmd->Resolution; | |
| 157 | − cfg.OGL.Header.Multisample = 1; | |
| 158 | − | |
| 159 | − int distortionCaps = 0 | |
| 160 | − | ovrDistortionCap_Vignette | |
| 161 | − | ovrDistortionCap_Overdrive | |
| 162 | − | ovrDistortionCap_TimeWarp; | |
| 163 | − | |
| 164 | − int configResult = ovrHmd_ConfigureRendering(_ovrHmd, &cfg.Config, | |
| 165 | − distortionCaps, _eyeFov, _eyeRenderDesc); | |
| 166 | − assert(configResult); | |
| 167 | − | |
| 168 | − | |
| 169 | − _recommendedTexSize = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left, _eyeFov[ovrEye_Left], 1.0f); | |
| 170 | − _renderTargetSize = { _recommendedTexSize.w * 2, _recommendedTexSize.h }; | |
| 171 | − for_each_eye([&](ovrEyeType eye) { | |
| 172 | − //Get texture size | |
| 173 | − _eyeTextures[eye].Header.API = ovrRenderAPI_OpenGL; | |
| 174 | − _eyeTextures[eye].Header.TextureSize = _renderTargetSize; | |
| 175 | − _eyeTextures[eye].Header.RenderViewport.Pos = { 0, 0 }; | |
| 176 | − }); | |
| 177 | − _eyeTextures[ovrEye_Right].Header.RenderViewport.Pos.x = _recommendedTexSize.w; | |
| 178 | − | |
| 179 | − ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction); | |
| 180 | − | |
| 181 | − ovrHmd_ConfigureTracking(_ovrHmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position | | |
| 182 | − ovrTrackingCap_MagYawCorrection, | |
| 183 | − ovrTrackingCap_Orientation); | |
| 184 | − | |
| 185 | − if (!_camera) { | |
| 186 | − _camera = new Camera; | |
| 187 | − configureCamera(*_camera); // no need to use screen dimensions; they're ignored | |
| 165 | + } | |
| 166 | + | |
| 167 | + void Increment() { | |
| 168 | + ++color->CurrentIndex; | |
| 169 | + color->CurrentIndex %= color->TextureCount; | |
| 170 | + } | |
| 171 | + | |
| 172 | +protected: | |
| 173 | + virtual void initColor() override { | |
| 174 | + if (color) { | |
| 175 | + ovrHmd_DestroySwapTextureSet(hmd, color); | |
| 176 | + color = nullptr; | |
| 177 | + } | |
| 178 | + | |
| 179 | + ovrResult result = ovrHmd_CreateSwapTextureSetGL(hmd, GL_RGBA, size.x, size.y, &color); | |
| 180 | + Q_ASSERT(OVR_SUCCESS(result)); | |
| 181 | + | |
| 182 | + for (int i = 0; i < color->TextureCount; ++i) { | |
| 183 | + ovrGLTexture& ovrTex = (ovrGLTexture&)color->Textures[i]; | |
| 184 | + glBindTexture(GL_TEXTURE_2D, ovrTex.OGL.TexId); | |
| 185 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
| 186 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| 187 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| 188 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| 189 | + } | |
| 190 | + glBindTexture(GL_TEXTURE_2D, 0); | |
| 191 | + } | |
| 192 | + | |
| 193 | + virtual void initDone() override { | |
| 194 | + } | |
| 195 | + | |
| 196 | + virtual void onBind(oglplus::Framebuffer::Target target) override { | |
| 197 | + ovrGLTexture& tex = (ovrGLTexture&)(color->Textures[color->CurrentIndex]); | |
| 198 | + glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.OGL.TexId, 0); | |
| 199 | + } | |
| 200 | + | |
| 201 | + virtual void onUnbind(oglplus::Framebuffer::Target target) override { | |
| 202 | + glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | |
| 203 | + } | |
| 204 | +}; | |
| 205 | + | |
| 206 | + | |
| 207 | +// We use a FBO to wrap the mirror texture because it makes it easier to | |
| 208 | +// render to the screen via glBlitFramebuffer | |
| 209 | +struct MirrorFramebufferWrapper : public RiftFramebufferWrapper<ovrGLTexture*> { | |
| 210 | + MirrorFramebufferWrapper(const ovrHmd & hmd) | |
| 211 | + : RiftFramebufferWrapper(hmd) { | |
| 212 | + } | |
| 213 | + | |
| 214 | + virtual ~MirrorFramebufferWrapper() { | |
| 215 | + if (color) { | |
| 216 | + ovrHmd_DestroyMirrorTexture(hmd, (ovrTexture*)color); | |
| 217 | + color = nullptr; | |
| 188 | 218 | } |
| 189 | −#ifdef OVR_CLIENT_DISTORTION | |
| 190 | − if (!_programInitialized) { | |
| 191 | − // Shader program | |
| 192 | − _programInitialized = true; | |
| 193 | − _program.addShaderFromSourceFile(QGLShader::Vertex, PathUtils::resourcesPath() + "shaders/oculus.vert"); | |
| 194 | − _program.addShaderFromSourceFile(QGLShader::Fragment, PathUtils::resourcesPath() + "shaders/oculus.frag"); | |
| 195 | − _program.link(); | |
| 196 | − | |
| 197 | − // Uniforms | |
| 198 | − _textureLocation = _program.uniformLocation("texture"); | |
| 199 | − _eyeToSourceUVScaleLocation = _program.uniformLocation("EyeToSourceUVScale"); | |
| 200 | − _eyeToSourceUVOffsetLocation = _program.uniformLocation("EyeToSourceUVOffset"); | |
| 201 | − _eyeRotationStartLocation = _program.uniformLocation("EyeRotationStart"); | |
| 202 | − _eyeRotationEndLocation = _program.uniformLocation("EyeRotationEnd"); | |
| 203 | − | |
| 204 | − // Attributes | |
| 205 | − _positionAttributeLocation = _program.attributeLocation("position"); | |
| 206 | − _colorAttributeLocation = _program.attributeLocation("color"); | |
| 207 | − _texCoord0AttributeLocation = _program.attributeLocation("texCoord0"); | |
| 208 | − _texCoord1AttributeLocation = _program.attributeLocation("texCoord1"); | |
| 209 | − _texCoord2AttributeLocation = _program.attributeLocation("texCoord2"); | |
| 219 | + } | |
| 220 | + | |
| 221 | +private: | |
| 222 | + void initColor() override { | |
| 223 | + if (color) { | |
| 224 | + ovrHmd_DestroyMirrorTexture(hmd, (ovrTexture*)color); | |
| 225 | + color = nullptr; | |
| 210 | 226 | } |
| 227 | + ovrResult result = ovrHmd_CreateMirrorTextureGL(hmd, GL_RGBA, size.x, size.y, (ovrTexture**)&color); | |
| 228 | + Q_ASSERT(OVR_SUCCESS(result)); | |
| 229 | + } | |
| 230 | + | |
| 231 | + void initDone() override { | |
| 232 | + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oglplus::GetName(fbo)); | |
| 233 | + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color->OGL.TexId, 0); | |
| 234 | + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); | |
| 235 | + } | |
| 236 | +}; | |
| 237 | + | |
| 238 | +static SwapFramebufferWrapper* _swapFbo{ nullptr }; | |
| 239 | +static MirrorFramebufferWrapper* _mirrorFbo{ nullptr }; | |
| 240 | +static ovrLayerEyeFov _sceneLayer; | |
| 241 | + | |
| 242 | +#else | |
| 243 | + | |
| 244 | +static ovrTexture _eyeTextures[ovrEye_Count]; | |
| 245 | +static GlWindow* _outputWindow{ nullptr }; | |
| 211 | 246 | |
| 212 | − //Generate the distortion VBOs | |
| 213 | − generateDistortionMesh(); | |
| 214 | 247 | #endif |
| 215 | − } else { | |
| 248 | + | |
| 249 | +static bool _isConnected = false; | |
| 250 | +static ovrHmd _ovrHmd; | |
| 251 | +static ovrFovPort _eyeFov[ovrEye_Count]; | |
| 252 | +static ovrVector3f _eyeOffset[ovrEye_Count]; | |
| 253 | +static ovrEyeRenderDesc _eyeRenderDesc[ovrEye_Count]; | |
| 254 | +static ovrSizei _renderTargetSize; | |
| 255 | +static glm::mat4 _eyeProjection[ovrEye_Count]; | |
| 256 | +static unsigned int _frameIndex = 0; | |
| 257 | +static bool _frameTimingActive = false; | |
| 258 | +static Camera* _camera = NULL; | |
| 259 | +static ovrEyeType _activeEye = ovrEye_Count; | |
| 260 | +static bool _hswDismissed = false; | |
| 261 | + | |
| 262 | +static const float CALIBRATION_DELTA_MINIMUM_LENGTH = 0.02f; | |
| 263 | +static const float CALIBRATION_DELTA_MINIMUM_ANGLE = 5.0f * RADIANS_PER_DEGREE; | |
| 264 | +static const float CALIBRATION_ZERO_MAXIMUM_LENGTH = 0.01f; | |
| 265 | +static const float CALIBRATION_ZERO_MAXIMUM_ANGLE = 2.0f * RADIANS_PER_DEGREE; | |
| 266 | +static const quint64 CALIBRATION_ZERO_HOLD_TIME = 3000000; // usec | |
| 267 | +static const float CALIBRATION_MESSAGE_DISTANCE = 2.5f; | |
| 268 | +static CalibrationState _calibrationState; | |
| 269 | +static glm::vec3 _calibrationPosition; | |
| 270 | +static glm::quat _calibrationOrientation; | |
| 271 | +static quint64 _calibrationStartTime; | |
| 272 | +static int _calibrationMessage = 0; | |
| 273 | +static glm::vec3 _eyePositions[ovrEye_Count]; | |
| 274 | +// TODO expose this as a developer toggle | |
| 275 | +static bool _eyePerFrameMode = false; | |
| 276 | +static ovrEyeType _lastEyeRendered = ovrEye_Count; | |
| 277 | +static ovrSizei _recommendedTexSize = { 0, 0 }; | |
| 278 | +static float _offscreenRenderScale = 1.0; | |
| 279 | +static glm::mat4 _combinedProjection; | |
| 280 | +static ovrPosef _eyeRenderPoses[ovrEye_Count]; | |
| 281 | +static ovrRecti _eyeViewports[ovrEye_Count]; | |
| 282 | +static ovrVector3f _eyeOffsets[ovrEye_Count]; | |
| 283 | + | |
| 284 | +glm::vec3 OculusManager::getLeftEyePosition() { return _eyePositions[ovrEye_Left]; } | |
| 285 | +glm::vec3 OculusManager::getRightEyePosition() { return _eyePositions[ovrEye_Right]; } | |
| 286 | + | |
| 287 | +void OculusManager::connect(QOpenGLContext* shareContext) { | |
| 288 | + qCDebug(interfaceapp) << "Oculus SDK" << OVR_VERSION_STRING; | |
| 289 | + | |
| 290 | + ovrInitParams initParams; memset(&initParams, 0, sizeof(initParams)); | |
| 291 | + | |
| 292 | +#ifdef DEBUG | |
| 293 | + initParams.Flags |= ovrInit_Debug; | |
| 294 | +#endif | |
| 295 | + | |
| 296 | + ovr_Initialize(&initParams); | |
| 297 | + | |
| 298 | +#ifdef Q_OS_WIN | |
| 299 | + | |
| 300 | + ovrResult res = ovrHmd_Create(0, &_ovrHmd); | |
| 301 | +#ifdef DEBUG | |
| 302 | + if (!OVR_SUCCESS(res)) { | |
| 303 | + res = ovrHmd_CreateDebug(ovrHmd_DK2, &_ovrHmd); | |
| 304 | + Q_ASSERT(OVR_SUCCESS(res)); | |
| 305 | + } | |
| 306 | +#endif | |
| 307 | + | |
| 308 | +#else | |
| 309 | + | |
| 310 | + _ovrHmd = ovrHmd_Create(0); | |
| 311 | +#ifdef DEBUG | |
| 312 | + if (!_ovrHmd) { | |
| 313 | + _ovrHmd = ovrHmd_CreateDebug(ovrHmd_DK2); | |
| 314 | + } | |
| 315 | +#endif | |
| 316 | + | |
| 317 | +#endif | |
| 318 | + | |
| 319 | + if (!_ovrHmd) { | |
| 216 | 320 | _isConnected = false; |
| 217 | − | |
| 321 | + | |
| 218 | 322 | // we're definitely not in "VR mode" so tell the menu that |
| 219 | 323 | Menu::getInstance()->getActionForOption(MenuOption::EnableVRMode)->setChecked(false); |
| 324 | + ovr_Shutdown(); | |
| 325 | + return; | |
| 326 | + } | |
| 327 | + | |
| 328 | + _calibrationState = UNCALIBRATED; | |
| 329 | + if (!_isConnected) { | |
| 330 | + UserActivityLogger::getInstance().connectedDevice("hmd", "oculus"); | |
| 331 | + } | |
| 332 | + _isConnected = true; | |
| 333 | + | |
| 334 | + for_each_eye([&](ovrEyeType eye) { | |
| 335 | + _eyeFov[eye] = _ovrHmd->DefaultEyeFov[eye]; | |
| 336 | + _eyeProjection[eye] = toGlm(ovrMatrix4f_Projection(_eyeFov[eye], | |
| 337 | + DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded)); | |
| 338 | + ovrEyeRenderDesc erd = ovrHmd_GetRenderDesc(_ovrHmd, eye, _eyeFov[eye]); | |
| 339 | + _eyeOffsets[eye] = erd.HmdToEyeViewOffset; | |
| 340 | + }); | |
| 341 | + ovrFovPort combinedFov = _ovrHmd->MaxEyeFov[0]; | |
| 342 | + combinedFov.RightTan = _ovrHmd->MaxEyeFov[1].RightTan; | |
| 343 | + _combinedProjection = toGlm(ovrMatrix4f_Projection(combinedFov, | |
| 344 | + DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded)); | |
| 345 | + | |
| 346 | + _recommendedTexSize = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left, _eyeFov[ovrEye_Left], 1.0f); | |
| 347 | + _renderTargetSize = { _recommendedTexSize.w * 2, _recommendedTexSize.h }; | |
| 348 | + | |
| 349 | +#ifdef Q_OS_WIN | |
| 350 | + | |
| 351 | + _mirrorFbo = new MirrorFramebufferWrapper(_ovrHmd); | |
| 352 | + _swapFbo = new SwapFramebufferWrapper(_ovrHmd); | |
| 353 | + _swapFbo->Init(toGlm(_renderTargetSize)); | |
| 354 | + _sceneLayer.ColorTexture[0] = _swapFbo->color; | |
| 355 | + _sceneLayer.ColorTexture[1] = nullptr; | |
| 356 | + _sceneLayer.Viewport[0].Pos = { 0, 0 }; | |
| 357 | + _sceneLayer.Viewport[0].Size = _recommendedTexSize; | |
| 358 | + _sceneLayer.Viewport[1].Pos = { _recommendedTexSize.w, 0 }; | |
| 359 | + _sceneLayer.Viewport[1].Size = _recommendedTexSize; | |
| 360 | + _sceneLayer.Header.Type = ovrLayerType_EyeFov; | |
| 361 | + _sceneLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft; | |
| 362 | + for_each_eye([&](ovrEyeType eye) { | |
| 363 | + _eyeViewports[eye] = _sceneLayer.Viewport[eye]; | |
| 364 | + _sceneLayer.Fov[eye] = _eyeFov[eye]; | |
| 365 | + }); | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | +#else | |
| 370 | + _outputWindow = new GlWindow(shareContext); | |
| 371 | + _outputWindow->show(); | |
| 372 | +// _outputWindow->setFlags(Qt::FramelessWindowHint ); | |
| 373 | +// _outputWindow->resize(_ovrHmd->Resolution.w, _ovrHmd->Resolution.h); | |
| 374 | +// _outputWindow->setPosition(_ovrHmd->WindowsPos.x, _ovrHmd->WindowsPos.y); | |
| 375 | + ivec2 desiredPosition = toGlm(_ovrHmd->WindowsPos); | |
| 376 | + foreach(QScreen* screen, qGuiApp->screens()) { | |
| 377 | + ivec2 screenPosition = toGlm(screen->geometry().topLeft()); | |
| 378 | + if (screenPosition == desiredPosition) { | |
| 379 | + _outputWindow->setScreen(screen); | |
| 380 | + break; | |
| 381 | + } | |
| 382 | + } | |
| 383 | + _outputWindow->showFullScreen(); | |
| 384 | + _outputWindow->makeCurrent(); | |
| 385 | + | |
| 386 | + ovrGLConfig cfg; | |
| 387 | + memset(&cfg, 0, sizeof(cfg)); | |
| 388 | + cfg.OGL.Header.API = ovrRenderAPI_OpenGL; | |
| 389 | + cfg.OGL.Header.BackBufferSize = _ovrHmd->Resolution; | |
| 390 | + cfg.OGL.Header.Multisample = 0; | |
| 391 | + | |
| 392 | + int distortionCaps = 0 | |
| 393 | + | ovrDistortionCap_Vignette | |
| 394 | + | ovrDistortionCap_Overdrive | |
| 395 | + | ovrDistortionCap_TimeWarp; | |
| 396 | + | |
| 397 | + int configResult = ovrHmd_ConfigureRendering(_ovrHmd, &cfg.Config, | |
| 398 | + distortionCaps, _eyeFov, _eyeRenderDesc); | |
| 399 | + assert(configResult); | |
| 400 | + _outputWindow->doneCurrent(); | |
| 401 | + | |
| 402 | + for_each_eye([&](ovrEyeType eye) { | |
| 403 | + //Get texture size | |
| 404 | + _eyeTextures[eye].Header.API = ovrRenderAPI_OpenGL; | |
| 405 | + _eyeTextures[eye].Header.TextureSize = _renderTargetSize; | |
| 406 | + _eyeTextures[eye].Header.RenderViewport.Pos = { 0, 0 }; | |
| 407 | + _eyeTextures[eye].Header.RenderViewport.Size = _renderTargetSize; | |
| 408 | + _eyeTextures[eye].Header.RenderViewport.Size.w /= 2; | |
| 409 | + }); | |
| 410 | + _eyeTextures[ovrEye_Right].Header.RenderViewport.Pos.x = _recommendedTexSize.w; | |
| 411 | + for_each_eye([&](ovrEyeType eye) { | |
| 412 | + _eyeViewports[eye] = _eyeTextures[eye].Header.RenderViewport; | |
| 413 | + }); | |
| 414 | +#endif | |
| 415 | + | |
| 416 | + ovrHmd_SetEnabledCaps(_ovrHmd, | |
| 417 | + ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction); | |
| 418 | + | |
| 419 | + ovrHmd_ConfigureTracking(_ovrHmd, | |
| 420 | + ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, | |
| 421 | + ovrTrackingCap_Orientation); | |
| 422 | + | |
| 423 | + if (!_camera) { | |
| 424 | + _camera = new Camera; | |
| 425 | + configureCamera(*_camera); // no need to use screen dimensions; they're ignored | |
| 220 | 426 | } |
| 221 | 427 | } |
| 222 | 428 | |
| 223 | 429 | //Disconnects and deallocates the OR |
| 224 | 430 | void OculusManager::disconnect() { |
| 225 | 431 | if (_isConnected) { |
| 432 | + | |
| 433 | +#ifdef Q_OS_WIN | |
| 434 | + if (_swapFbo) { | |
| 435 | + delete _swapFbo; | |
| 436 | + _swapFbo = nullptr; | |
| 437 | + } | |
| 438 | + | |
| 439 | + if (_mirrorFbo) { | |
| 440 | + delete _mirrorFbo; | |
| 441 | + _mirrorFbo = nullptr; | |
| 442 | + } | |
| 443 | +#else | |
| 444 | + _outputWindow->showNormal(); | |
| 445 | + _outputWindow->deleteLater(); | |
| 446 | + _outputWindow = nullptr; | |
| 447 | +#endif | |
| 448 | + | |
| 449 | + if (_ovrHmd) { | |
| 450 | + ovrHmd_Destroy(_ovrHmd); | |
| 451 | + _ovrHmd = nullptr; | |
| 452 | + } | |
| 453 | + ovr_Shutdown(); | |
| 454 | + | |
| 226 | 455 | _isConnected = false; |
| 227 | 456 | // Prepare to potentially have to dismiss the HSW again |
| 228 | 457 | // if the user re-enables VR |
| 229 | 458 | _hswDismissed = false; |
| 230 | −#ifndef OVR_DIRECT_MODE | |
| 231 | − shutdownSdk(); | |
| 232 | −#endif | |
| 233 | − | |
| 234 | −#ifdef OVR_CLIENT_DISTORTION | |
| 235 | − //Free the distortion mesh data | |
| 236 | − for (int i = 0; i < ovrEye_Count; i++) { | |
| 237 | − if (_vertices[i] != 0) { | |
| 238 | − glDeleteBuffers(1, &(_vertices[i])); | |
| 239 | − _vertices[i] = 0; | |
| 240 | − } | |
| 241 | − if (_indices[i] != 0) { | |
| 242 | − glDeleteBuffers(1, &(_indices[i])); | |
| 243 | − _indices[i] = 0; | |
| 244 | − } | |
| 245 | − } | |
| 246 | −#endif | |
| 247 | 459 | } |
| 248 | 460 | } |
| 249 | 461 | |
| 250 | −void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) { | |
| 462 | +void positionCalibrationBillboard(Text3DOverlay* billboard) { | |
| 251 | 463 | MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); |
| 252 | 464 | glm::quat headOrientation = myAvatar->getHeadOrientation(); |
| 253 | 465 | headOrientation.x = 0; |
| @@ -258,7 +470,7 @@ void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) { · 4 unmodified lines | ||
| 258 | 470 | billboard->setRotation(headOrientation); |
| 259 | 471 | } |
| 260 | 472 | |
| 261 | −void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { | |
| 473 | +void calibrate(const glm::vec3& position, const glm::quat& orientation) { | |
| 262 | 474 | static QString instructionMessage = "Hold still to calibrate"; |
| 263 | 475 | static QString progressMessage; |
| 264 | 476 | static Text3DOverlay* billboard; |
| @@ -346,7 +558,7 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { · 81 unmodified lines | ||
| 346 | 558 | break; |
| 347 | 559 | default: |
| 348 | 560 | break; |
| 349 | − | |
| 561 | + | |
| 350 | 562 | } |
| 351 | 563 | } |
| 352 | 564 | |
| @@ -363,64 +575,9 @@ void OculusManager::abandonCalibration() { · 10 unmodified lines | ||
| 363 | 575 | } |
| 364 | 576 | } |
| 365 | 577 | |
| 366 | −#ifdef OVR_CLIENT_DISTORTION | |
| 367 | −void OculusManager::generateDistortionMesh() { | |
| 368 | − | |
| 369 | − //Check if we already have the distortion mesh | |
| 370 | − if (_vertices[0] != 0) { | |
| 371 | − printf("WARNING: Tried to generate Oculus distortion mesh twice without freeing the VBOs."); | |
| 372 | − return; | |
| 373 | − } | |
| 374 | − | |
| 375 | − for (int eyeNum = 0; eyeNum < ovrEye_Count; eyeNum++) { | |
| 376 | − // Allocate and generate distortion mesh vertices | |
| 377 | − ovrDistortionMesh meshData; | |
| 378 | − ovrHmd_CreateDistortionMesh(_ovrHmd, _eyeRenderDesc[eyeNum].Eye, _eyeRenderDesc[eyeNum].Fov, _ovrHmd->DistortionCaps, &meshData); | |
| 379 | − | |
| 380 | − // Parse the vertex data and create a render ready vertex buffer | |
| 381 | − DistortionVertex* pVBVerts = new DistortionVertex[meshData.VertexCount]; | |
| 382 | − _meshSize[eyeNum] = meshData.IndexCount; | |
| 383 | − | |
| 384 | − // Convert the oculus vertex data to the DistortionVertex format. | |
| 385 | − DistortionVertex* v = pVBVerts; | |
| 386 | − ovrDistortionVertex* ov = meshData.pVertexData; | |
| 387 | − for (unsigned int vertNum = 0; vertNum < meshData.VertexCount; vertNum++) { | |
| 388 | − v->pos.x = ov->ScreenPosNDC.x; | |
| 389 | − v->pos.y = ov->ScreenPosNDC.y; | |
| 390 | − v->texR.x = ov->TanEyeAnglesR.x; | |
| 391 | − v->texR.y = ov->TanEyeAnglesR.y; | |
| 392 | − v->texG.x = ov->TanEyeAnglesG.x; | |
| 393 | − v->texG.y = ov->TanEyeAnglesG.y; | |
| 394 | − v->texB.x = ov->TanEyeAnglesB.x; | |
| 395 | − v->texB.y = ov->TanEyeAnglesB.y; | |
| 396 | − v->color.r = v->color.g = v->color.b = (GLubyte)(ov->VignetteFactor * 255.99f); | |
| 397 | − v->color.a = (GLubyte)(ov->TimeWarpFactor * 255.99f); | |
| 398 | − v++; | |
| 399 | − ov++; | |
| 400 | − } | |
| 401 | − | |
| 402 | − //vertices | |
| 403 | − glGenBuffers(1, &(_vertices[eyeNum])); | |
| 404 | − glBindBuffer(GL_ARRAY_BUFFER, _vertices[eyeNum]); | |
| 405 | − glBufferData(GL_ARRAY_BUFFER, sizeof(DistortionVertex) * meshData.VertexCount, pVBVerts, GL_STATIC_DRAW); | |
| 406 | − glBindBuffer(GL_ARRAY_BUFFER, 0); | |
| 407 | − | |
| 408 | − //indices | |
| 409 | − glGenBuffers(1, &(_indices[eyeNum])); | |
| 410 | − glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indices[eyeNum]); | |
| 411 | − glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short) * meshData.IndexCount, meshData.pIndexData, GL_STATIC_DRAW); | |
| 412 | − glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); | |
| 413 | − | |
| 414 | − //Now that we have the VBOs we can get rid of the mesh data | |
| 415 | − delete [] pVBVerts; | |
| 416 | − ovrHmd_DestroyDistortionMesh(&meshData); | |
| 417 | − } | |
| 418 | − | |
| 419 | −} | |
| 420 | −#endif | |
| 421 | 578 | |
| 422 | 579 | bool OculusManager::isConnected() { |
| 423 | − return _isConnected && Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode); | |
| 580 | + return _isConnected; | |
| 424 | 581 | } |
| 425 | 582 | |
| 426 | 583 | //Begins the frame timing for oculus prediction purposes |
| @@ -428,10 +585,6 @@ void OculusManager::beginFrameTiming() { · 1 unmodified line | ||
| 428 | 585 | if (_frameTimingActive) { |
| 429 | 586 | printf("WARNING: Called OculusManager::beginFrameTiming() twice in a row, need to call OculusManager::endFrameTiming()."); |
| 430 | 587 | } |
| 431 | − | |
| 432 | −#ifdef OVR_CLIENT_DISTORTION | |
| 433 | − _hmdFrameTiming = ovrHmd_BeginFrameTiming(_ovrHmd, _frameIndex); | |
| 434 | −#endif | |
| 435 | 588 | _frameTimingActive = true; |
| 436 | 589 | } |
| 437 | 590 | |
| @@ -441,27 +594,18 @@ bool OculusManager::allowSwap() { · 3 unmodified lines | ||
| 441 | 594 | |
| 442 | 595 | //Ends frame timing |
| 443 | 596 | void OculusManager::endFrameTiming() { |
| 444 | −#ifdef OVR_CLIENT_DISTORTION | |
| 445 | − ovrHmd_EndFrameTiming(_ovrHmd); | |
| 446 | −#endif | |
| 447 | 597 | _frameIndex++; |
| 448 | 598 | _frameTimingActive = false; |
| 449 | 599 | } |
| 450 | 600 | |
| 451 | 601 | //Sets the camera FoV and aspect ratio |
| 452 | 602 | void OculusManager::configureCamera(Camera& camera) { |
| 453 | − ovrFovPort fov; | |
| 454 | 603 | if (_activeEye == ovrEye_Count) { |
| 455 | 604 | // When not rendering, provide a FOV encompasing both eyes |
| 456 | − fov = _eyeFov[0]; | |
| 457 | − fov.RightTan = _eyeFov[1].RightTan; | |
| 458 | − } else { | |
| 459 | − // When rendering, provide the exact FOV | |
| 460 | − fov = _eyeFov[_activeEye]; | |
| 461 | − } | |
| 462 | − // Convert the FOV to the correct projection matrix | |
| 463 | − glm::mat4 projection = toGlm(ovrMatrix4f_Projection(fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded)); | |
| 464 | − camera.setProjection(projection); | |
| 605 | + camera.setProjection(_combinedProjection); | |
| 606 | + return; | |
| 607 | + } | |
| 608 | + camera.setProjection(_eyeProjection[_activeEye]); | |
| 465 | 609 | } |
| 466 | 610 | |
| 467 | 611 | //Displays everything for the oculus, frame timing must be active |
| @@ -473,40 +617,9 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 5 unmodified lines | ||
| 473 | 617 | assert(oldFrameIndex == -1 || (unsigned int)oldFrameIndex == _frameIndex - 1); |
| 474 | 618 | oldFrameIndex = _frameIndex; |
| 475 | 619 | #endif |
| 476 | − | |
| 477 | − // Every so often do some additional timing calculations and debug output | |
| 478 | − bool debugFrame = 0 == _frameIndex % 400; | |
| 479 | 620 | |
| 480 | −#if 0 | |
| 481 | − // Try to measure the amount of time taken to do the distortion | |
| 482 | − // (does not seem to work on OSX with SDK based distortion) | |
| 483 | − // FIXME can't use a static object here, because it will cause a crash when the | |
| 484 | − // query attempts deconstruct after the GL context is gone. | |
| 485 | − static bool timerActive = false; | |
| 486 | − static QOpenGLTimerQuery timerQuery; | |
| 487 | − if (!timerQuery.isCreated()) { | |
| 488 | − timerQuery.create(); | |
| 489 | − } | |
| 490 | − | |
| 491 | − if (timerActive && timerQuery.isResultAvailable()) { | |
| 492 | − auto result = timerQuery.waitForResult(); | |
| 493 | − if (result) { qCDebug(interfaceapp) << "Distortion took " << result << "ns"; }; | |
| 494 | − timerActive = false; | |
| 495 | − } | |
| 496 | −#endif | |
| 497 | − | |
| 498 | −#ifdef OVR_DIRECT_MODE | |
| 499 | − static bool attached = false; | |
| 500 | − if (!attached) { | |
| 501 | − attached = true; | |
| 502 | − void * nativeWindowHandle = (void*)(size_t)glCanvas->effectiveWinId(); | |
| 503 | − if (nullptr != nativeWindowHandle) { | |
| 504 | − ovrHmd_AttachToWindow(_ovrHmd, nativeWindowHandle, nullptr, nullptr); | |
| 505 | − } | |
| 506 | − } | |
| 507 | −#endif | |
| 508 | − | |
| 509 | −#ifndef OVR_CLIENT_DISTORTION | |
| 621 | +#ifndef Q_OS_WIN | |
| 622 | + | |
| 510 | 623 | // FIXME: we need a better way of responding to the HSW. In particular |
| 511 | 624 | // we need to ensure that it's only displayed once per session, rather than |
| 512 | 625 | // every time the user toggles VR mode, and we need to hook it up to actual |
| @@ -522,7 +635,7 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 9 unmodified lines | ||
| 522 | 635 | } |
| 523 | 636 | } |
| 524 | 637 | #endif |
| 525 | − | |
| 638 | + | |
| 526 | 639 | |
| 527 | 640 | //beginFrameTiming must be called before display |
| 528 | 641 | if (!_frameTimingActive) { |
| @@ -545,14 +658,14 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 16 unmodified lines | ||
| 545 | 658 | |
| 546 | 659 | glMatrixMode(GL_MODELVIEW); |
| 547 | 660 | glPushMatrix(); |
| 548 | − | |
| 661 | + | |
| 549 | 662 | glm::quat orientation; |
| 550 | 663 | glm::vec3 trackerPosition; |
| 551 | 664 | auto deviceSize = qApp->getDeviceSize(); |
| 552 | 665 | |
| 553 | 666 | ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); |
| 554 | 667 | ovrVector3f ovrHeadPosition = ts.HeadPose.ThePose.Position; |
| 555 | − | |
| 668 | + | |
| 556 | 669 | trackerPosition = glm::vec3(ovrHeadPosition.x, ovrHeadPosition.y, ovrHeadPosition.z); |
| 557 | 670 | |
| 558 | 671 | if (_calibrationState != CALIBRATED) { |
| @@ -562,11 +675,11 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 3 unmodified lines | ||
| 562 | 675 | } |
| 563 | 676 | |
| 564 | 677 | trackerPosition = bodyOrientation * trackerPosition; |
| 565 | − static ovrVector3f eyeOffsets[2] = { { 0, 0, 0 }, { 0, 0, 0 } }; | |
| 566 | 678 | ovrPosef eyePoses[ovrEye_Count]; |
| 567 | − ovrHmd_GetEyePoses(_ovrHmd, _frameIndex, eyeOffsets, eyePoses, nullptr); | |
| 679 | + ovrHmd_GetEyePoses(_ovrHmd, _frameIndex, _eyeOffsets, eyePoses, nullptr); | |
| 680 | +#ifndef Q_OS_WIN | |
| 568 | 681 | ovrHmd_BeginFrame(_ovrHmd, _frameIndex); |
| 569 | − static ovrPosef eyeRenderPose[ovrEye_Count]; | |
| 682 | +#endif | |
| 570 | 683 | //Render each eye into an fbo |
| 571 | 684 | for_each_eye(_ovrHmd, [&](ovrEyeType eye){ |
| 572 | 685 | // If we're in eye-per-frame mode, only render one eye |
| @@ -576,29 +689,17 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 3 unmodified lines | ||
| 576 | 689 | return; |
| 577 | 690 | } |
| 578 | 691 | _lastEyeRendered = _activeEye = eye; |
| 579 | − eyeRenderPose[eye] = eyePoses[eye]; | |
| 692 | + _eyeRenderPoses[eye] = eyePoses[eye]; | |
| 580 | 693 | // Set the camera rotation for this eye |
| 581 | − orientation.x = eyeRenderPose[eye].Orientation.x; | |
| 582 | − orientation.y = eyeRenderPose[eye].Orientation.y; | |
| 583 | − orientation.z = eyeRenderPose[eye].Orientation.z; | |
| 584 | − orientation.w = eyeRenderPose[eye].Orientation.w; | |
| 585 | − | |
| 586 | − // Update the application camera with the latest HMD position | |
| 587 | − whichCamera.setHmdPosition(trackerPosition); | |
| 588 | − whichCamera.setHmdRotation(orientation); | |
| 589 | − | |
| 590 | 694 | |
| 695 | + vec3 eyePosition = toGlm(_eyeRenderPoses[eye].Position); | |
| 696 | + eyePosition = whichCamera.getRotation() * eyePosition; | |
| 697 | + quat eyeRotation = toGlm(_eyeRenderPoses[eye].Orientation); | |
| 698 | + | |
| 591 | 699 | // Update our camera to what the application camera is doing |
| 592 | − _camera->setRotation(whichCamera.getRotation()); | |
| 593 | − _camera->setPosition(whichCamera.getPosition()); | |
| 700 | + _camera->setRotation(whichCamera.getRotation() * eyeRotation); | |
| 701 | + _camera->setPosition(whichCamera.getPosition() + eyePosition); | |
| 594 | 702 | configureCamera(*_camera); |
| 595 | − | |
| 596 | − // Store the latest left and right eye render locations for things that need to know | |
| 597 | − glm::vec3 thisEyePosition = position + trackerPosition + | |
| 598 | − (bodyOrientation * glm::quat(orientation.x, orientation.y, orientation.z, orientation.w) * | |
| 599 | − glm::vec3(_eyeRenderDesc[eye].HmdToEyeViewOffset.x, _eyeRenderDesc[eye].HmdToEyeViewOffset.y, _eyeRenderDesc[eye].HmdToEyeViewOffset.z)); | |
| 600 | − | |
| 601 | − _eyePositions[eye] = thisEyePosition; | |
| 602 | 703 | _camera->update(1.0f / Application::getInstance()->getFps()); |
| 603 | 704 | |
| 604 | 705 | glMatrixMode(GL_PROJECTION); |
| @@ -607,15 +708,14 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 2 unmodified lines | ||
| 607 | 708 | glMatrixMode(GL_MODELVIEW); |
| 608 | 709 | glLoadIdentity(); |
| 609 | 710 | |
| 610 | − ovrRecti & vp = _eyeTextures[eye].Header.RenderViewport; | |
| 711 | + ovrRecti & vp = _eyeViewports[eye]; | |
| 611 | 712 | vp.Size.h = _recommendedTexSize.h * _offscreenRenderScale; |
| 612 | 713 | vp.Size.w = _recommendedTexSize.w * _offscreenRenderScale; |
| 613 | − | |
| 614 | 714 | glViewport(vp.Pos.x, vp.Pos.y, vp.Size.w, vp.Size.h); |
| 615 | 715 | |
| 616 | 716 | renderArgs->_renderSide = RenderArgs::MONO; |
| 617 | − qApp->displaySide(renderArgs, *_camera, false); | |
| 618 | − qApp->getApplicationOverlay().displayOverlayTextureHmd(*_camera); | |
| 717 | + qApp->displaySide(renderArgs, *_camera); | |
| 718 | + qApp->getApplicationCompositor().displayOverlayTextureHmd(renderArgs, eye); | |
| 619 | 719 | }); |
| 620 | 720 | _activeEye = ovrEye_Count; |
| 621 | 721 | |
| @@ -628,7 +728,7 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 6 unmodified lines | ||
| 628 | 728 | glViewport(0, 0, _renderTargetSize.w, _renderTargetSize.h); |
| 629 | 729 | finalFbo = DependencyManager::get<GlowEffect>()->render(renderArgs); |
| 630 | 730 | } else { |
| 631 | − finalFbo = DependencyManager::get<TextureCache>()->getPrimaryFramebuffer(); | |
| 731 | + finalFbo = DependencyManager::get<TextureCache>()->getPrimaryFramebuffer(); | |
| 632 | 732 | glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| 633 | 733 | } |
| 634 | 734 | |
| @@ -638,141 +738,73 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 3 unmodified lines | ||
| 638 | 738 | // restore our normal viewport |
| 639 | 739 | glViewport(0, 0, deviceSize.width(), deviceSize.height()); |
| 640 | 740 | |
| 641 | −#if 0 | |
| 642 | − if (debugFrame && !timerActive) { | |
| 643 | − timerQuery.begin(); | |
| 644 | − } | |
| 645 | −#endif | |
| 741 | +#ifdef Q_OS_WIN | |
| 742 | + auto srcFboSize = finalFbo->getSize(); | |
| 646 | 743 | |
| 647 | −#ifdef OVR_CLIENT_DISTORTION | |
| 648 | − | |
| 649 | − //Wait till time-warp to reduce latency | |
| 650 | − ovr_WaitTillTime(_hmdFrameTiming.TimewarpPointSeconds); | |
| 651 | 744 | |
| 652 | −#ifdef DEBUG_RENDER_WITHOUT_DISTORTION | |
| 653 | − auto fboSize = finalFbo->getSize(); | |
| 745 | + // Blit to the oculus provided texture | |
| 654 | 746 | glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo)); |
| 747 | + _swapFbo->Bound(oglplus::Framebuffer::Target::Draw, [&] { | |
| 748 | + glBlitFramebuffer( | |
| 749 | + 0, 0, srcFboSize.x, srcFboSize.y, | |
| 750 | + 0, 0, _swapFbo->size.x, _swapFbo->size.y, | |
| 751 | + GL_COLOR_BUFFER_BIT, GL_NEAREST); | |
| 752 | + }); | |
| 753 | + | |
| 754 | + // Blit to the onscreen window | |
| 755 | + auto destWindowSize = qApp->getDeviceSize(); | |
| 655 | 756 | glBlitFramebuffer( |
| 656 | − 0, 0, fboSize.x, fboSize.y, | |
| 657 | − 0, 0, deviceSize.width(), deviceSize.height(), | |
| 757 | + 0, 0, srcFboSize.x, srcFboSize.y, | |
| 758 | + 0, 0, destWindowSize.width(), destWindowSize.height(), | |
| 658 | 759 | GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| 760 | + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); | |
| 761 | + | |
| 762 | + // Submit the frame to the Oculus SDK for timewarp and distortion | |
| 763 | + for_each_eye([&](ovrEyeType eye) { | |
| 764 | + _sceneLayer.RenderPose[eye] = _eyeRenderPoses[eye]; | |
| 765 | + }); | |
| 766 | + auto header = &_sceneLayer.Header; | |
| 767 | + ovrResult res = ovrHmd_SubmitFrame(_ovrHmd, _frameIndex, nullptr, &header, 1); | |
| 768 | + Q_ASSERT(OVR_SUCCESS(res)); | |
| 769 | + _swapFbo->Increment(); | |
| 659 | 770 | #else |
| 660 | − //Clear the color buffer to ensure that there isnt any residual color | |
| 661 | − //Left over from when OR was not connected. | |
| 662 | − glClear(GL_COLOR_BUFFER_BIT); | |
| 663 | − glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(finalFbo->getRenderBuffer(0))); | |
| 664 | − //Renders the distorted mesh onto the screen | |
| 665 | − renderDistortionMesh(eyeRenderPose); | |
| 666 | − glBindTexture(GL_TEXTURE_2D, 0); | |
| 667 | −#endif | |
| 668 | − glCanvas->swapBuffers(); | |
| 771 | + GLsync syncObject = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); | |
| 772 | + glFlush(); | |
| 669 | 773 | |
| 670 | −#else | |
| 671 | 774 | |
| 775 | + _outputWindow->makeCurrent(); | |
| 776 | + // force the compositing context to wait for the texture | |
| 777 | + // rendering to complete before it starts the distortion rendering, | |
| 778 | + // but without triggering a CPU/GPU synchronization | |
| 779 | + glWaitSync(syncObject, 0, GL_TIMEOUT_IGNORED); | |
| 780 | + glDeleteSync(syncObject); | |
| 781 | + | |
| 782 | + GLuint textureId = gpu::GLBackend::getTextureID(finalFbo->getRenderBuffer(0)); | |
| 672 | 783 | for_each_eye([&](ovrEyeType eye) { |
| 673 | 784 | ovrGLTexture & glEyeTexture = reinterpret_cast<ovrGLTexture&>(_eyeTextures[eye]); |
| 674 | − glEyeTexture.OGL.TexId = finalFbo->texture(); | |
| 675 | − | |
| 676 | − }); | |
| 785 | + glEyeTexture.OGL.TexId = textureId; | |
| 677 | 786 | |
| 678 | − ovrHmd_EndFrame(_ovrHmd, eyeRenderPose, _eyeTextures); | |
| 787 | + }); | |
| 679 | 788 | |
| 789 | + // restore our normal viewport | |
| 790 | + ovrHmd_EndFrame(_ovrHmd, _eyeRenderPoses, _eyeTextures); | |
| 791 | + glCanvas->makeCurrent(); | |
| 680 | 792 | #endif |
| 681 | 793 | |
| 682 | −#if 0 | |
| 683 | − if (debugFrame && !timerActive) { | |
| 684 | − timerQuery.end(); | |
| 685 | − timerActive = true; | |
| 686 | − } | |
| 687 | −#endif | |
| 688 | 794 | |
| 689 | − // No DK2, no message. | |
| 795 | + // in order to account account for changes in the pick ray caused by head movement | |
| 796 | + // we need to force a mouse move event on every frame (perhaps we could change this | |
| 797 | + // to based on the head moving a minimum distance from the last position in which we | |
| 798 | + // sent?) | |
| 690 | 799 | { |
| 691 | − float latencies[5] = {}; | |
| 692 | − if (debugFrame && ovrHmd_GetFloatArray(_ovrHmd, "DK2Latency", latencies, 5) == 5) | |
| 693 | − { | |
| 694 | − bool nonZero = false; | |
| 695 | − for (int i = 0; i < 5; ++i) | |
| 696 | − { | |
| 697 | − nonZero |= (latencies[i] != 0.f); | |
| 698 | − } | |
| 699 | − | |
| 700 | − if (nonZero) | |
| 701 | − { | |
| 702 | − qCDebug(interfaceapp) << QString().sprintf("M2P Latency: Ren: %4.2fms TWrp: %4.2fms PostPresent: %4.2fms Err: %4.2fms %4.2fms", | |
| 703 | − latencies[0], latencies[1], latencies[2], latencies[3], latencies[4]); | |
| 704 | − } | |
| 705 | − } | |
| 800 | + QMouseEvent mouseEvent(QEvent::MouseMove, glCanvas->mapFromGlobal(QCursor::pos()), | |
| 801 | + Qt::NoButton, Qt::NoButton, 0); | |
| 802 | + qApp->mouseMoveEvent(&mouseEvent, 0); | |
| 706 | 803 | } |
| 707 | − | |
| 708 | −} | |
| 709 | − | |
| 710 | −#ifdef OVR_CLIENT_DISTORTION | |
| 711 | −void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) { | |
| 712 | 804 | |
| 713 | − glLoadIdentity(); | |
| 714 | − auto deviceSize = qApp->getDeviceSize(); | |
| 715 | − glOrtho(0, deviceSize.width(), 0, deviceSize.height(), -1.0, 1.0); | |
| 716 | − | |
| 717 | − glDisable(GL_DEPTH_TEST); | |
| 718 | − | |
| 719 | − glDisable(GL_BLEND); | |
| 720 | − _program.bind(); | |
| 721 | − _program.setUniformValue(_textureLocation, 0); | |
| 722 | − | |
| 723 | − _program.enableAttributeArray(_positionAttributeLocation); | |
| 724 | − _program.enableAttributeArray(_colorAttributeLocation); | |
| 725 | − _program.enableAttributeArray(_texCoord0AttributeLocation); | |
| 726 | − _program.enableAttributeArray(_texCoord1AttributeLocation); | |
| 727 | − _program.enableAttributeArray(_texCoord2AttributeLocation); | |
| 728 | − | |
| 729 | − //Render the distortion meshes for each eye | |
| 730 | − for (int eyeNum = 0; eyeNum < ovrEye_Count; eyeNum++) { | |
| 731 | − | |
| 732 | − ovrHmd_GetRenderScaleAndOffset(_eyeRenderDesc[eyeNum].Fov, _renderTargetSize, _eyeTextures[eyeNum].Header.RenderViewport, | |
| 733 | − _UVScaleOffset[eyeNum]); | |
| 734 | − | |
| 735 | − GLfloat uvScale[2] = { _UVScaleOffset[eyeNum][0].x, _UVScaleOffset[eyeNum][0].y }; | |
| 736 | − _program.setUniformValueArray(_eyeToSourceUVScaleLocation, uvScale, 1, 2); | |
| 737 | − GLfloat uvOffset[2] = { _UVScaleOffset[eyeNum][1].x, 1.0f - _UVScaleOffset[eyeNum][1].y }; | |
| 738 | − _program.setUniformValueArray(_eyeToSourceUVOffsetLocation, uvOffset, 1, 2); | |
| 739 | − | |
| 740 | − ovrMatrix4f timeWarpMatrices[2]; | |
| 741 | − glm::mat4 transposeMatrices[2]; | |
| 742 | − //Grabs the timewarp matrices to be used in the shader | |
| 743 | − ovrHmd_GetEyeTimewarpMatrices(_ovrHmd, (ovrEyeType)eyeNum, eyeRenderPose[eyeNum], timeWarpMatrices); | |
| 744 | − //Have to transpose the matrices before using them | |
| 745 | − transposeMatrices[0] = glm::transpose(toGlm(timeWarpMatrices[0])); | |
| 746 | − transposeMatrices[1] = glm::transpose(toGlm(timeWarpMatrices[1])); | |
| 747 | 805 | |
| 748 | − glUniformMatrix4fv(_eyeRotationStartLocation, 1, GL_FALSE, (GLfloat *)&transposeMatrices[0][0][0]); | |
| 749 | − glUniformMatrix4fv(_eyeRotationEndLocation, 1, GL_FALSE, (GLfloat *)&transposeMatrices[1][0][0]); | |
| 750 | 806 | |
| 751 | − glBindBuffer(GL_ARRAY_BUFFER, _vertices[eyeNum]); | |
| 752 | − | |
| 753 | − //Set vertex attribute pointers | |
| 754 | − glVertexAttribPointer(_positionAttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)0); | |
| 755 | − glVertexAttribPointer(_texCoord0AttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)8); | |
| 756 | − glVertexAttribPointer(_texCoord1AttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)16); | |
| 757 | − glVertexAttribPointer(_texCoord2AttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)24); | |
| 758 | − glVertexAttribPointer(_colorAttributeLocation, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(DistortionVertex), (void *)32); | |
| 759 | − | |
| 760 | − glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indices[eyeNum]); | |
| 761 | − glDrawElements(GL_TRIANGLES, _meshSize[eyeNum], GL_UNSIGNED_SHORT, 0); | |
| 762 | − } | |
| 763 | − | |
| 764 | − _program.disableAttributeArray(_positionAttributeLocation); | |
| 765 | − _program.disableAttributeArray(_colorAttributeLocation); | |
| 766 | − _program.disableAttributeArray(_texCoord0AttributeLocation); | |
| 767 | − _program.disableAttributeArray(_texCoord1AttributeLocation); | |
| 768 | − _program.disableAttributeArray(_texCoord2AttributeLocation); | |
| 769 | − | |
| 770 | − glEnable(GL_BLEND); | |
| 771 | − glEnable(GL_DEPTH_TEST); | |
| 772 | − _program.release(); | |
| 773 | − glBindBuffer(GL_ARRAY_BUFFER, 0); | |
| 774 | 807 | } |
| 775 | −#endif | |
| 776 | 808 | |
| 777 | 809 | //Tries to reconnect to the sensors |
| 778 | 810 | void OculusManager::reset() { |
| @@ -781,21 +813,6 @@ void OculusManager::reset() { · 2 unmodified lines | ||
| 781 | 813 | } |
| 782 | 814 | } |
| 783 | 815 | |
| 784 | −//Gets the current predicted angles from the oculus sensors | |
| 785 | −void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { | |
| 786 | − ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); | |
| 787 | − if (ts.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { | |
| 788 | − glm::vec3 euler = glm::eulerAngles(toGlm(ts.HeadPose.ThePose.Orientation)); | |
| 789 | − yaw = euler.y; | |
| 790 | − pitch = euler.x; | |
| 791 | − roll = euler.z; | |
| 792 | − } else { | |
| 793 | − yaw = 0.0f; | |
| 794 | − pitch = 0.0f; | |
| 795 | − roll = 0.0f; | |
| 796 | − } | |
| 797 | −} | |
| 798 | − | |
| 799 | 816 | glm::vec3 OculusManager::getRelativePosition() { |
| 800 | 817 | ovrTrackingState trackingState = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); |
| 801 | 818 | return toGlm(trackingState.HeadPose.ThePose.Position); |
| @@ -826,6 +843,9 @@ void OculusManager::overrideOffAxisFrustum(float& left, float& right, float& bot · 24 unmodified lines | ||
| 826 | 843 | } |
| 827 | 844 | |
| 828 | 845 | int OculusManager::getHMDScreen() { |
| 846 | +#ifdef Q_OS_WIN | |
| 847 | + return -1; | |
| 848 | +#else | |
| 829 | 849 | int hmdScreenIndex = -1; // unknown |
| 830 | 850 | // TODO: it might be smarter to handle multiple HMDs connected in this case. but for now, |
| 831 | 851 | // we will simply assume the initialization code that set up _ovrHmd picked the best hmd |
| @@ -844,7 +864,7 @@ int OculusManager::getHMDScreen() { · 12 unmodified lines | ||
| 844 | 864 | const int SIMILAR_NAMES = 10; |
| 845 | 865 | const int EXACT_LOCATION_MATCH = 50; |
| 846 | 866 | const int EXACT_RESOLUTION_MATCH = 25; |
| 847 | − | |
| 867 | + | |
| 848 | 868 | int bestMatchScore = 0; |
| 849 | 869 | |
| 850 | 870 | // look at the display list and see if we can find the best match |
| @@ -853,7 +873,7 @@ int OculusManager::getHMDScreen() { · 2 unmodified lines | ||
| 853 | 873 | foreach (QScreen* screen, QGuiApplication::screens()) { |
| 854 | 874 | QString screenName = screen->name(); |
| 855 | 875 | QRect screenRect = desktop->screenGeometry(screenNumber); |
| 856 | − | |
| 876 | + | |
| 857 | 877 | int screenScore = 0; |
| 858 | 878 | if (screenName == productNameFromOVR) { |
| 859 | 879 | screenScore += EXACT_NAME_MATCH; |
| @@ -876,5 +896,18 @@ int OculusManager::getHMDScreen() { · 16 unmodified lines | ||
| 876 | 896 | } |
| 877 | 897 | } |
| 878 | 898 | return hmdScreenIndex; |
| 899 | +#endif | |
| 900 | +} | |
| 901 | + | |
| 902 | +mat4 OculusManager::getEyeProjection(int eye) { | |
| 903 | + return _eyeProjection[eye]; | |
| 879 | 904 | } |
| 880 | 905 | |
| 906 | +mat4 OculusManager::getEyePose(int eye) { | |
| 907 | + return toGlm(_eyeRenderPoses[eye]); | |
| 908 | +} | |
| 909 | + | |
| 910 | +mat4 OculusManager::getHeadPose() { | |
| 911 | + ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); | |
| 912 | + return toGlm(ts.HeadPose.ThePose); | |
| 913 | +} | |
| @@ -13,8 +13,6 @@ · 12 unmodified lines | ||
| 13 | 13 | #ifndef hifi_OculusManager_h |
| 14 | 14 | #define hifi_OculusManager_h |
| 15 | 15 | |
| 16 | −#include <OVR_CAPI.h> | |
| 17 | − | |
| 18 | 16 | #include <ProgramObject.h> |
| 19 | 17 | #include <glm/glm.hpp> |
| 20 | 18 | #include <glm/gtc/matrix_transform.hpp> |
| @@ -22,39 +20,13 @@ · 1 unmodified line | ||
| 22 | 20 | |
| 23 | 21 | #include "RenderArgs.h" |
| 24 | 22 | |
| 23 | +class QOpenGLContext; | |
| 25 | 24 | class Camera; |
| 26 | −class PalmData; | |
| 27 | −class Text3DOverlay; | |
| 28 | − | |
| 29 | −// Uncomment this to enable client side distortion. NOT recommended since | |
| 30 | −// the Oculus SDK will ideally provide the best practices for distortion in | |
| 31 | −// in terms of performance and quality, and by using it we will get updated | |
| 32 | −// best practices for free with new runtime releases. | |
| 33 | −#define OVR_CLIENT_DISTORTION 1 | |
| 34 | − | |
| 35 | − | |
| 36 | −// Direct HMD mode is currently only supported on windows and some linux systems will | |
| 37 | −// misbehave if we try to enable the Oculus SDK at all, so isolate support for Direct | |
| 38 | −// mode only to windows for now | |
| 39 | −#ifdef Q_OS_WIN | |
| 40 | −// On Win32 platforms, enabling Direct HMD requires that the SDK be | |
| 41 | −// initialized before the GL context is set up, but this breaks v-sync | |
| 42 | −// for any application that has a Direct mode enable Rift connected | |
| 43 | −// but is not rendering to it. For the time being I'm setting this as | |
| 44 | −// a macro enabled mechanism which changes where the SDK is initialized. | |
| 45 | −// To enable Direct HMD mode, you can un-comment this, but with the | |
| 46 | −// caveat that it will break v-sync in NON-VR mode if you have an Oculus | |
| 47 | −// Rift connect and in Direct mode | |
| 48 | −#define OVR_DIRECT_MODE 1 | |
| 49 | −#endif | |
| 50 | − | |
| 51 | 25 | |
| 52 | 26 | /// Handles interaction with the Oculus Rift. |
| 53 | 27 | class OculusManager { |
| 54 | 28 | public: |
| 55 | − static void init(); | |
| 56 | − static void deinit(); | |
| 57 | − static void connect(); | |
| 29 | + static void connect(QOpenGLContext* shareContext); | |
| 58 | 30 | static void disconnect(); |
| 59 | 31 | static bool isConnected(); |
| 60 | 32 | static void recalibrate(); |
| @@ -66,10 +38,6 @@ public: · 5 unmodified lines | ||
| 66 | 38 | static void display(QGLWidget * glCanvas, RenderArgs* renderArgs, const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera); |
| 67 | 39 | static void reset(); |
| 68 | 40 | |
| 69 | − /// param \yaw[out] yaw in radians | |
| 70 | − /// param \pitch[out] pitch in radians | |
| 71 | − /// param \roll[out] roll in radians | |
| 72 | − static void getEulerAngles(float& yaw, float& pitch, float& roll); | |
| 73 | 41 | static glm::vec3 getRelativePosition(); |
| 74 | 42 | static glm::quat getOrientation(); |
| 75 | 43 | static QSize getRenderTargetSize(); |
| @@ -77,145 +45,14 @@ public: · 1 unmodified line | ||
| 77 | 45 | static void overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal, |
| 78 | 46 | float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane); |
| 79 | 47 | |
| 80 | − static glm::vec3 getLeftEyePosition() { return _eyePositions[ovrEye_Left]; } | |
| 81 | − static glm::vec3 getRightEyePosition() { return _eyePositions[ovrEye_Right]; } | |
| 48 | + static glm::vec3 getLeftEyePosition(); | |
| 49 | + static glm::vec3 getRightEyePosition(); | |
| 82 | 50 | |
| 83 | 51 | static int getHMDScreen(); |
| 84 | − | |
| 85 | −private: | |
| 86 | − static void initSdk(); | |
| 87 | − static void shutdownSdk(); | |
| 88 | −#ifdef OVR_CLIENT_DISTORTION | |
| 89 | − static void generateDistortionMesh(); | |
| 90 | − static void renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]); | |
| 91 | − struct DistortionVertex { | |
| 92 | − glm::vec2 pos; | |
| 93 | − glm::vec2 texR; | |
| 94 | − glm::vec2 texG; | |
| 95 | − glm::vec2 texB; | |
| 96 | − struct { | |
| 97 | − GLubyte r; | |
| 98 | − GLubyte g; | |
| 99 | − GLubyte b; | |
| 100 | − GLubyte a; | |
| 101 | − } color; | |
| 102 | − }; | |
| 103 | 52 | |
| 104 | − static ProgramObject _program; | |
| 105 | − //Uniforms | |
| 106 | − static int _textureLocation; | |
| 107 | − static int _eyeToSourceUVScaleLocation; | |
| 108 | − static int _eyeToSourceUVOffsetLocation; | |
| 109 | − static int _eyeRotationStartLocation; | |
| 110 | − static int _eyeRotationEndLocation; | |
| 111 | − //Attributes | |
| 112 | − static int _positionAttributeLocation; | |
| 113 | − static int _colorAttributeLocation; | |
| 114 | − static int _texCoord0AttributeLocation; | |
| 115 | − static int _texCoord1AttributeLocation; | |
| 116 | − static int _texCoord2AttributeLocation; | |
| 117 | − static ovrVector2f _UVScaleOffset[ovrEye_Count][2]; | |
| 118 | − static GLuint _vertices[ovrEye_Count]; | |
| 119 | − static GLuint _indices[ovrEye_Count]; | |
| 120 | − static GLsizei _meshSize[ovrEye_Count]; | |
| 121 | − static ovrFrameTiming _hmdFrameTiming; | |
| 122 | − static bool _programInitialized; | |
| 123 | −#endif | |
| 124 | − | |
| 125 | − static ovrTexture _eyeTextures[ovrEye_Count]; | |
| 126 | − static bool _isConnected; | |
| 127 | − static glm::vec3 _eyePositions[ovrEye_Count]; | |
| 128 | − static ovrHmd _ovrHmd; | |
| 129 | − static ovrFovPort _eyeFov[ovrEye_Count]; | |
| 130 | − static ovrVector3f _eyeOffset[ovrEye_Count]; | |
| 131 | − static glm::mat4 _eyeProjection[ovrEye_Count]; | |
| 132 | − static ovrEyeRenderDesc _eyeRenderDesc[ovrEye_Count]; | |
| 133 | − static ovrSizei _renderTargetSize; | |
| 134 | − static unsigned int _frameIndex; | |
| 135 | − static bool _frameTimingActive; | |
| 136 | − static Camera* _camera; | |
| 137 | − static ovrEyeType _activeEye; | |
| 138 | − static bool _hswDismissed; | |
| 139 | − | |
| 140 | − static void calibrate(const glm::vec3 position, const glm::quat orientation); | |
| 141 | − enum CalibrationState { | |
| 142 | − UNCALIBRATED, | |
| 143 | − WAITING_FOR_DELTA, | |
| 144 | − WAITING_FOR_ZERO, | |
| 145 | − WAITING_FOR_ZERO_HELD, | |
| 146 | − CALIBRATED | |
| 147 | − }; | |
| 148 | − static void positionCalibrationBillboard(Text3DOverlay* message); | |
| 149 | − static float CALIBRATION_DELTA_MINIMUM_LENGTH; | |
| 150 | − static float CALIBRATION_DELTA_MINIMUM_ANGLE; | |
| 151 | − static float CALIBRATION_ZERO_MAXIMUM_LENGTH; | |
| 152 | − static float CALIBRATION_ZERO_MAXIMUM_ANGLE; | |
| 153 | − static quint64 CALIBRATION_ZERO_HOLD_TIME; | |
| 154 | − static float CALIBRATION_MESSAGE_DISTANCE; | |
| 155 | − static CalibrationState _calibrationState; | |
| 156 | − static glm::vec3 _calibrationPosition; | |
| 157 | − static glm::quat _calibrationOrientation; | |
| 158 | − static quint64 _calibrationStartTime; | |
| 159 | − static int _calibrationMessage; | |
| 160 | − // TODO drop this variable and use the existing 'Developer | Render | Scale Resolution' value | |
| 161 | − static ovrSizei _recommendedTexSize; | |
| 162 | − static float _offscreenRenderScale; | |
| 163 | − static bool _eyePerFrameMode; | |
| 164 | − static ovrEyeType _lastEyeRendered; | |
| 53 | + static glm::mat4 getEyeProjection(int eye); | |
| 54 | + static glm::mat4 getEyePose(int eye); | |
| 55 | + static glm::mat4 getHeadPose(); | |
| 165 | 56 | }; |
| 166 | 57 | |
| 167 | − | |
| 168 | −inline glm::mat4 toGlm(const ovrMatrix4f & om) { | |
| 169 | − return glm::transpose(glm::make_mat4(&om.M[0][0])); | |
| 170 | −} | |
| 171 | − | |
| 172 | −inline glm::mat4 toGlm(const ovrFovPort & fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) { | |
| 173 | − return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true)); | |
| 174 | −} | |
| 175 | − | |
| 176 | −inline glm::vec3 toGlm(const ovrVector3f & ov) { | |
| 177 | − return glm::make_vec3(&ov.x); | |
| 178 | −} | |
| 179 | − | |
| 180 | −inline glm::vec2 toGlm(const ovrVector2f & ov) { | |
| 181 | − return glm::make_vec2(&ov.x); | |
| 182 | −} | |
| 183 | − | |
| 184 | −inline glm::uvec2 toGlm(const ovrSizei & ov) { | |
| 185 | − return glm::uvec2(ov.w, ov.h); | |
| 186 | −} | |
| 187 | − | |
| 188 | −inline glm::quat toGlm(const ovrQuatf & oq) { | |
| 189 | − return glm::make_quat(&oq.x); | |
| 190 | −} | |
| 191 | − | |
| 192 | −inline glm::mat4 toGlm(const ovrPosef & op) { | |
| 193 | − glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation)); | |
| 194 | − glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position)); | |
| 195 | − return translation * orientation; | |
| 196 | −} | |
| 197 | − | |
| 198 | −inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) { | |
| 199 | − ovrMatrix4f result; | |
| 200 | − glm::mat4 transposed(glm::transpose(m)); | |
| 201 | − memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16); | |
| 202 | − return result; | |
| 203 | −} | |
| 204 | − | |
| 205 | −inline ovrVector3f ovrFromGlm(const glm::vec3 & v) { | |
| 206 | − return{ v.x, v.y, v.z }; | |
| 207 | −} | |
| 208 | − | |
| 209 | −inline ovrVector2f ovrFromGlm(const glm::vec2 & v) { | |
| 210 | − return{ v.x, v.y }; | |
| 211 | −} | |
| 212 | − | |
| 213 | −inline ovrSizei ovrFromGlm(const glm::uvec2 & v) { | |
| 214 | − return{ (int)v.x, (int)v.y }; | |
| 215 | −} | |
| 216 | − | |
| 217 | −inline ovrQuatf ovrFromGlm(const glm::quat & q) { | |
| 218 | − return{ q.x, q.y, q.z, q.w }; | |
| 219 | −} | |
| 220 | − | |
| 221 | 58 | #endif // hifi_OculusManager_h |
| @@ -74,9 +74,11 @@ SDL2Manager* SDL2Manager::getInstance() { · 73 unmodified lines | ||
| 74 | 74 | } |
| 75 | 75 | |
| 76 | 76 | void SDL2Manager::focusOutEvent() { |
| 77 | +#ifdef HAVE_SDL2 | |
| 77 | 78 | for (auto joystick : _openJoysticks) { |
| 78 | 79 | joystick->focusOutEvent(); |
| 79 | 80 | } |
| 81 | +#endif | |
| 80 | 82 | } |
| 81 | 83 | |
| 82 | 84 | void SDL2Manager::update() { |
| @@ -36,6 +36,8 @@ const float NECK_X = 0.25f; // meters · 35 unmodified lines | ||
| 36 | 36 | const float NECK_Y = 0.3f; // meters |
| 37 | 37 | const float NECK_Z = 0.3f; // meters |
| 38 | 38 | |
| 39 | +const float CONTROLLER_THRESHOLD = 0.35f; | |
| 40 | + | |
| 39 | 41 | #ifdef __APPLE__ |
| 40 | 42 | typedef int (*SixenseBaseFunction)(); |
| 41 | 43 | typedef int (*SixenseTakeIntFunction)(int); |
| @@ -71,25 +73,25 @@ SixenseManager::SixenseManager() : · 29 unmodified lines | ||
| 71 | 73 | |
| 72 | 74 | SixenseManager::~SixenseManager() { |
| 73 | 75 | #ifdef HAVE_SIXENSE_ |
| 74 | − | |
| 76 | + | |
| 75 | 77 | if (_isInitialized) { |
| 76 | 78 | #ifdef __APPLE__ |
| 77 | 79 | SixenseBaseFunction sixenseExit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseExit"); |
| 78 | 80 | #endif |
| 79 | − | |
| 81 | + | |
| 80 | 82 | sixenseExit(); |
| 81 | 83 | } |
| 82 | − | |
| 84 | + | |
| 83 | 85 | #ifdef __APPLE__ |
| 84 | 86 | delete _sixenseLibrary; |
| 85 | 87 | #endif |
| 86 | − | |
| 88 | + | |
| 87 | 89 | #endif |
| 88 | 90 | } |
| 89 | 91 | |
| 90 | 92 | void SixenseManager::initialize() { |
| 91 | 93 | #ifdef HAVE_SIXENSE |
| 92 | − | |
| 94 | + | |
| 93 | 95 | if (!_isInitialized) { |
| 94 | 96 | _lowVelocityFilter = false; |
| 95 | 97 | _controllersAtBase = true; |
| @@ -97,22 +99,22 @@ void SixenseManager::initialize() { · 1 unmodified line | ||
| 97 | 99 | // By default we assume the _neckBase (in orb frame) is as high above the orb |
| 98 | 100 | // as the "torso" is below it. |
| 99 | 101 | _neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z); |
| 100 | − | |
| 102 | + | |
| 101 | 103 | #ifdef __APPLE__ |
| 102 | − | |
| 104 | + | |
| 103 | 105 | if (!_sixenseLibrary) { |
| 104 | − | |
| 106 | + | |
| 105 | 107 | #ifdef SIXENSE_LIB_FILENAME |
| 106 | 108 | _sixenseLibrary = new QLibrary(SIXENSE_LIB_FILENAME); |
| 107 | 109 | #else |
| 108 | 110 | const QString SIXENSE_LIBRARY_NAME = "libsixense_x64"; |
| 109 | 111 | QString frameworkSixenseLibrary = QCoreApplication::applicationDirPath() + "/../Frameworks/" |
| 110 | 112 | + SIXENSE_LIBRARY_NAME; |
| 111 | − | |
| 113 | + | |
| 112 | 114 | _sixenseLibrary = new QLibrary(frameworkSixenseLibrary); |
| 113 | 115 | #endif |
| 114 | 116 | } |
| 115 | − | |
| 117 | + | |
| 116 | 118 | if (_sixenseLibrary->load()){ |
| 117 | 119 | qCDebug(interfaceapp) << "Loaded sixense library for hydra support -" << _sixenseLibrary->fileName(); |
| 118 | 120 | } else { |
| @@ -120,14 +122,14 @@ void SixenseManager::initialize() { · 1 unmodified line | ||
| 120 | 122 | << "Continuing without hydra support."; |
| 121 | 123 | return; |
| 122 | 124 | } |
| 123 | − | |
| 125 | + | |
| 124 | 126 | SixenseBaseFunction sixenseInit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseInit"); |
| 125 | 127 | #endif |
| 126 | 128 | sixenseInit(); |
| 127 | − | |
| 129 | + | |
| 128 | 130 | _isInitialized = true; |
| 129 | 131 | } |
| 130 | − | |
| 132 | + | |
| 131 | 133 | #endif |
| 132 | 134 | } |
| 133 | 135 | |
| @@ -138,7 +140,7 @@ void SixenseManager::setFilter(bool filter) { · 4 unmodified lines | ||
| 138 | 140 | #ifdef __APPLE__ |
| 139 | 141 | SixenseTakeIntFunction sixenseSetFilterEnabled = (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseSetFilterEnabled"); |
| 140 | 142 | #endif |
| 141 | − | |
| 143 | + | |
| 142 | 144 | if (filter) { |
| 143 | 145 | sixenseSetFilterEnabled(1); |
| 144 | 146 | } else { |
| @@ -158,7 +160,7 @@ void SixenseManager::update(float deltaTime) { · 13 unmodified lines | ||
| 158 | 160 | SixenseBaseFunction sixenseGetNumActiveControllers = |
| 159 | 161 | (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetNumActiveControllers"); |
| 160 | 162 | #endif |
| 161 | − | |
| 163 | + | |
| 162 | 164 | if (sixenseGetNumActiveControllers() == 0) { |
| 163 | 165 | _hydrasConnected = false; |
| 164 | 166 | if (_deviceID != 0) { |
| @@ -173,7 +175,7 @@ void SixenseManager::update(float deltaTime) { · 8 unmodified lines | ||
| 173 | 175 | } |
| 174 | 176 | return; |
| 175 | 177 | } |
| 176 | − | |
| 178 | + | |
| 177 | 179 | PerformanceTimer perfTimer("sixense"); |
| 178 | 180 | if (!_hydrasConnected) { |
| 179 | 181 | _hydrasConnected = true; |
| @@ -181,21 +183,21 @@ void SixenseManager::update(float deltaTime) { · 1 unmodified line | ||
| 181 | 183 | getInstance().assignDefaultInputMapping(*Application::getUserInputMapper()); |
| 182 | 184 | UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra"); |
| 183 | 185 | } |
| 184 | − | |
| 186 | + | |
| 185 | 187 | #ifdef __APPLE__ |
| 186 | 188 | SixenseBaseFunction sixenseGetMaxControllers = |
| 187 | 189 | (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetMaxControllers"); |
| 188 | 190 | #endif |
| 189 | − | |
| 191 | + | |
| 190 | 192 | int maxControllers = sixenseGetMaxControllers(); |
| 191 | − | |
| 193 | + | |
| 192 | 194 | // we only support two controllers |
| 193 | 195 | sixenseControllerData controllers[2]; |
| 194 | − | |
| 196 | + | |
| 195 | 197 | #ifdef __APPLE__ |
| 196 | 198 | SixenseTakeIntFunction sixenseIsControllerEnabled = |
| 197 | 199 | (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseIsControllerEnabled"); |
| 198 | − | |
| 200 | + | |
| 199 | 201 | SixenseTakeIntAndSixenseControllerData sixenseGetNewestData = |
| 200 | 202 | (SixenseTakeIntAndSixenseControllerData) _sixenseLibrary->resolve("sixenseGetNewestData"); |
| 201 | 203 | #endif |
| @@ -208,9 +210,9 @@ void SixenseManager::update(float deltaTime) { · 6 unmodified lines | ||
| 208 | 210 | sixenseControllerData* data = controllers + numActiveControllers; |
| 209 | 211 | ++numActiveControllers; |
| 210 | 212 | sixenseGetNewestData(i, data); |
| 211 | − | |
| 213 | + | |
| 212 | 214 | // Set palm position and normal based on Hydra position/orientation |
| 213 | − | |
| 215 | + | |
| 214 | 216 | // Either find a palm matching the sixense controller, or make a new one |
| 215 | 217 | PalmData* palm; |
| 216 | 218 | bool foundHand = false; |
| @@ -229,47 +231,47 @@ void SixenseManager::update(float deltaTime) { · 12 unmodified lines | ||
| 229 | 231 | _prevPalms[numActiveControllers - 1] = palm; |
| 230 | 232 | qCDebug(interfaceapp, "Found new Sixense controller, ID %i", data->controller_index); |
| 231 | 233 | } |
| 232 | − | |
| 234 | + | |
| 233 | 235 | // Disable the hands (and return to default pose) if both controllers are at base station |
| 234 | 236 | if (foundHand) { |
| 235 | 237 | palm->setActive(!_controllersAtBase); |
| 236 | 238 | } else { |
| 237 | 239 | palm->setActive(false); // if this isn't a Sixsense ID palm, always make it inactive |
| 238 | 240 | } |
| 239 | − | |
| 241 | + | |
| 240 | 242 | // Read controller buttons and joystick into the hand |
| 241 | 243 | palm->setControllerButtons(data->buttons); |
| 242 | 244 | palm->setTrigger(data->trigger); |
| 243 | 245 | palm->setJoystick(data->joystick_x, data->joystick_y); |
| 244 | − | |
| 246 | + | |
| 245 | 247 | handleButtonEvent(data->buttons, numActiveControllers - 1); |
| 246 | 248 | handleAxisEvent(data->joystick_x, data->joystick_y, data->trigger, numActiveControllers - 1); |
| 247 | − | |
| 249 | + | |
| 248 | 250 | // Emulate the mouse so we can use scripts |
| 249 | 251 | if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput) && !_controllersAtBase) { |
| 250 | 252 | emulateMouse(palm, numActiveControllers - 1); |
| 251 | 253 | } |
| 252 | − | |
| 254 | + | |
| 253 | 255 | // NOTE: Sixense API returns pos data in millimeters but we IMMEDIATELY convert to meters. |
| 254 | 256 | glm::vec3 position(data->pos[0], data->pos[1], data->pos[2]); |
| 255 | 257 | position *= METERS_PER_MILLIMETER; |
| 256 | − | |
| 258 | + | |
| 257 | 259 | // Check to see if this hand/controller is on the base |
| 258 | 260 | const float CONTROLLER_AT_BASE_DISTANCE = 0.075f; |
| 259 | 261 | if (glm::length(position) < CONTROLLER_AT_BASE_DISTANCE) { |
| 260 | 262 | numControllersAtBase++; |
| 261 | 263 | } |
| 262 | − | |
| 264 | + | |
| 263 | 265 | // Transform the measured position into body frame. |
| 264 | 266 | glm::vec3 neck = _neckBase; |
| 265 | 267 | // Zeroing y component of the "neck" effectively raises the measured position a little bit. |
| 266 | 268 | neck.y = 0.0f; |
| 267 | 269 | position = _orbRotation * (position - neck); |
| 268 | − | |
| 270 | + | |
| 269 | 271 | // Rotation of Palm |
| 270 | 272 | glm::quat rotation(data->rot_quat[3], -data->rot_quat[0], data->rot_quat[1], -data->rot_quat[2]); |
| 271 | 273 | rotation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)) * _orbRotation * rotation; |
| 272 | − | |
| 274 | + | |
| 273 | 275 | // Compute current velocity from position change |
| 274 | 276 | glm::vec3 rawVelocity; |
| 275 | 277 | if (deltaTime > 0.0f) { |
| @@ -278,11 +280,11 @@ void SixenseManager::update(float deltaTime) { · 2 unmodified lines | ||
| 278 | 280 | rawVelocity = glm::vec3(0.0f); |
| 279 | 281 | } |
| 280 | 282 | palm->setRawVelocity(rawVelocity); // meters/sec |
| 281 | − | |
| 283 | + | |
| 282 | 284 | // adjustment for hydra controllers fit into hands |
| 283 | 285 | float sign = (i == 0) ? -1.0f : 1.0f; |
| 284 | 286 | rotation *= glm::angleAxis(sign * PI/4.0f, glm::vec3(0.0f, 0.0f, 1.0f)); |
| 285 | − | |
| 287 | + | |
| 286 | 288 | // Angular Velocity of Palm |
| 287 | 289 | glm::quat deltaRotation = rotation * glm::inverse(palm->getRawRotation()); |
| 288 | 290 | glm::vec3 angularVelocity(0.0f); |
| @@ -294,7 +296,7 @@ void SixenseManager::update(float deltaTime) { · 5 unmodified lines | ||
| 294 | 296 | } else { |
| 295 | 297 | palm->setRawAngularVelocity(glm::vec3(0.0f)); |
| 296 | 298 | } |
| 297 | − | |
| 299 | + | |
| 298 | 300 | if (_lowVelocityFilter) { |
| 299 | 301 | // Use a velocity sensitive filter to damp small motions and preserve large ones with |
| 300 | 302 | // no latency. |
| @@ -307,7 +309,7 @@ void SixenseManager::update(float deltaTime) { · 6 unmodified lines | ||
| 307 | 309 | palm->setRawPosition(position); |
| 308 | 310 | palm->setRawRotation(rotation); |
| 309 | 311 | } |
| 310 | − | |
| 312 | + | |
| 311 | 313 | // Store the one fingertip in the palm structure so we can track velocity |
| 312 | 314 | const float FINGER_LENGTH = 0.3f; // meters |
| 313 | 315 | const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, FINGER_LENGTH); |
| @@ -320,19 +322,25 @@ void SixenseManager::update(float deltaTime) { · 6 unmodified lines | ||
| 320 | 322 | } |
| 321 | 323 | palm->setTipPosition(newTipPosition); |
| 322 | 324 | } |
| 323 | − | |
| 325 | + | |
| 324 | 326 | if (numActiveControllers == 2) { |
| 325 | 327 | updateCalibration(controllers); |
| 326 | 328 | } |
| 327 | 329 | _controllersAtBase = (numControllersAtBase == 2); |
| 328 | 330 | } |
| 331 | + | |
| 332 | + for (auto axisState : _axisStateMap) { | |
| 333 | + if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) { | |
| 334 | + _axisStateMap[axisState.first] = 0.0f; | |
| 335 | + } | |
| 336 | + } | |
| 329 | 337 | #endif // HAVE_SIXENSE |
| 330 | 338 | } |
| 331 | 339 | |
| 332 | 340 | //Constants for getCursorPixelRangeMultiplier() |
| 333 | 341 | const float MIN_PIXEL_RANGE_MULT = 0.4f; |
| 334 | 342 | const float MAX_PIXEL_RANGE_MULT = 2.0f; |
| 335 | −const float RANGE_MULT = (MAX_PIXEL_RANGE_MULT - MIN_PIXEL_RANGE_MULT) * 0.01; | |
| 343 | +const float RANGE_MULT = (MAX_PIXEL_RANGE_MULT - MIN_PIXEL_RANGE_MULT) * 0.01f; | |
| 336 | 344 | |
| 337 | 345 | //Returns a multiplier to be applied to the cursor range for the controllers |
| 338 | 346 | float SixenseManager::getCursorPixelRangeMult() const { |
| @@ -421,7 +429,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 82 unmodified lines | ||
| 421 | 429 | _calibrationState = CALIBRATION_STATE_X; |
| 422 | 430 | } |
| 423 | 431 | return; |
| 424 | − } | |
| 432 | + } | |
| 425 | 433 | |
| 426 | 434 | quint64 now = usecTimestampNow() + LOCK_DURATION; |
| 427 | 435 | // these are weighted running averages |
| @@ -431,7 +439,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 3 unmodified lines | ||
| 431 | 439 | if (_calibrationState == CALIBRATION_STATE_X) { |
| 432 | 440 | // compute new sliding average |
| 433 | 441 | float distance = glm::distance(_averageLeft, _averageRight); |
| 434 | − if (fabs(distance - _lastDistance) > MAXIMUM_NOISE_LEVEL) { | |
| 442 | + if (fabsf(distance - _lastDistance) > MAXIMUM_NOISE_LEVEL) { | |
| 435 | 443 | // distance is increasing so acquire the data and push the expiry out |
| 436 | 444 | _reachLeft = _averageLeft; |
| 437 | 445 | _reachRight = _averageRight; |
| @@ -450,7 +458,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 12 unmodified lines | ||
| 450 | 458 | glm::vec3 torso = 0.5f * (_reachLeft + _reachRight); |
| 451 | 459 | glm::vec3 averagePosition = 0.5f * (_averageLeft + _averageRight); |
| 452 | 460 | float distance = (averagePosition - torso).y; |
| 453 | − if (fabs(distance) > fabs(_lastDistance) + MAXIMUM_NOISE_LEVEL) { | |
| 461 | + if (fabsf(distance) > fabsf(_lastDistance) + MAXIMUM_NOISE_LEVEL) { | |
| 454 | 462 | // distance is increasing so acquire the data and push the expiry out |
| 455 | 463 | _reachUp = averagePosition; |
| 456 | 464 | _lastDistance = distance; |
| @@ -481,11 +489,11 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 24 unmodified lines | ||
| 481 | 489 | _lastDistance = distance; |
| 482 | 490 | _lockExpiry = now + LOCK_DURATION; |
| 483 | 491 | } else if (now > _lockExpiry) { |
| 484 | − if (fabs(_lastDistance) > 0.05f * MINIMUM_ARM_REACH) { | |
| 492 | + if (fabsf(_lastDistance) > 0.05f * MINIMUM_ARM_REACH) { | |
| 485 | 493 | // lock has expired so clamp the data and move on |
| 486 | 494 | _calibrationState = CALIBRATION_STATE_COMPLETE; |
| 487 | 495 | qCDebug(interfaceapp, "success: sixense calibration: forward"); |
| 488 | − // TODO: it is theoretically possible to detect that the controllers have been | |
| 496 | + // TODO: it is theoretically possible to detect that the controllers have been | |
| 489 | 497 | // accidentally switched (left hand is holding right controller) and to swap the order. |
| 490 | 498 | } |
| 491 | 499 | } |
| @@ -496,7 +504,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 4 unmodified lines | ||
| 496 | 504 | void SixenseManager::emulateMouse(PalmData* palm, int index) { |
| 497 | 505 | MyAvatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); |
| 498 | 506 | QPoint pos; |
| 499 | − | |
| 507 | + | |
| 500 | 508 | Qt::MouseButton bumperButton; |
| 501 | 509 | Qt::MouseButton triggerButton; |
| 502 | 510 | |
| @@ -510,16 +518,16 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { · 7 unmodified lines | ||
| 510 | 518 | triggerButton = Qt::LeftButton; |
| 511 | 519 | } |
| 512 | 520 | |
| 513 | − if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers) | |
| 521 | + if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers) | |
| 514 | 522 | || Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) { |
| 515 | − pos = qApp->getApplicationOverlay().getPalmClickLocation(palm); | |
| 523 | + pos = qApp->getApplicationCompositor().getPalmClickLocation(palm); | |
| 516 | 524 | } else { |
| 517 | 525 | // Get directon relative to avatar orientation |
| 518 | 526 | glm::vec3 direction = glm::inverse(avatar->getOrientation()) * palm->getFingerDirection(); |
| 519 | 527 | |
| 520 | 528 | // Get the angles, scaled between (-0.5,0.5) |
| 521 | 529 | float xAngle = (atan2(direction.z, direction.x) + M_PI_2); |
| 522 | − float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2)); | |
| 530 | + float yAngle = 0.5f - ((atan2f(direction.z, direction.y) + (float)M_PI_2)); | |
| 523 | 531 | auto canvasSize = qApp->getCanvasSize(); |
| 524 | 532 | // Get the pixel range over which the xAngle and yAngle are scaled |
| 525 | 533 | float cursorRange = canvasSize.x * getCursorPixelRangeMult(); |
| @@ -562,11 +570,11 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { · 36 unmodified lines | ||
| 562 | 570 | if (!_bumperPressed[(int)(!index)]) { |
| 563 | 571 | qApp->mouseMoveEvent(&mouseEvent, deviceID); |
| 564 | 572 | } |
| 565 | − } | |
| 573 | + } | |
| 566 | 574 | } |
| 567 | 575 | _oldX[index] = pos.x(); |
| 568 | 576 | _oldY[index] = pos.y(); |
| 569 | − | |
| 577 | + | |
| 570 | 578 | |
| 571 | 579 | //We need separate coordinates for clicks, since we need to check if |
| 572 | 580 | //a magnification window was clicked on |
| @@ -580,7 +588,7 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { · 7 unmodified lines | ||
| 580 | 588 | if (palm->getControllerButtons() & BUTTON_FWD) { |
| 581 | 589 | if (!_bumperPressed[index]) { |
| 582 | 590 | _bumperPressed[index] = true; |
| 583 | − | |
| 591 | + | |
| 584 | 592 | QMouseEvent mouseEvent(QEvent::MouseButtonPress, pos, bumperButton, bumperButton, 0); |
| 585 | 593 | |
| 586 | 594 | qApp->mousePressEvent(&mouseEvent, deviceID); |
| @@ -12,6 +12,7 @@ · 11 unmodified lines | ||
| 12 | 12 | #include "InterfaceConfig.h" |
| 13 | 13 | |
| 14 | 14 | #include <glm/glm.hpp> |
| 15 | +#include <glm/gtc/type_ptr.hpp> | |
| 15 | 16 | |
| 16 | 17 | #include <GlowEffect.h> |
| 17 | 18 | #include "gpu/GLBackend.h" |
| @@ -106,21 +107,20 @@ void TV3DManager::display(RenderArgs* renderArgs, Camera& whichCamera) { · 88 unmodified lines | ||
| 106 | 107 | _activeEye = &eye; |
| 107 | 108 | glViewport(portalX, portalY, portalW, portalH); |
| 108 | 109 | glScissor(portalX, portalY, portalW, portalH); |
| 110 | + | |
| 111 | + glm::mat4 projection = glm::frustum<float>(eye.left, eye.right, eye.bottom, eye.top, nearZ, farZ); | |
| 112 | + float fov = atan(1.0f / projection[1][1]); | |
| 113 | + projection = glm::translate(projection, vec3(eye.modelTranslation, 0, 0)); | |
| 114 | + eyeCamera.setProjection(projection); | |
| 115 | + | |
| 109 | 116 | glMatrixMode(GL_PROJECTION); |
| 110 | 117 | glLoadIdentity(); // reset projection matrix |
| 111 | − glFrustum(eye.left, eye.right, eye.bottom, eye.top, nearZ, farZ); // set left view frustum | |
| 112 | − GLfloat p[4][4]; | |
| 113 | − // Really? | |
| 114 | − glGetFloatv(GL_PROJECTION_MATRIX, &(p[0][0])); | |
| 115 | − float cotangent = p[1][1]; | |
| 116 | − GLfloat fov = atan(1.0f / cotangent); | |
| 117 | − glTranslatef(eye.modelTranslation, 0.0, 0.0); // translate to cancel parallax | |
| 118 | − | |
| 118 | + glLoadMatrixf(glm::value_ptr(projection)); | |
| 119 | 119 | glMatrixMode(GL_MODELVIEW); |
| 120 | 120 | glLoadIdentity(); |
| 121 | 121 | renderArgs->_renderSide = RenderArgs::MONO; |
| 122 | 122 | qApp->displaySide(renderArgs, eyeCamera, false); |
| 123 | − qApp->getApplicationOverlay().displayOverlayTextureStereo(whichCamera, _aspect, fov); | |
| 123 | + qApp->getApplicationCompositor().displayOverlayTexture(renderArgs); | |
| 124 | 124 | _activeEye = NULL; |
| 125 | 125 | }, [&]{ |
| 126 | 126 | // render right side view |
| @@ -23,7 +23,7 @@ · 22 unmodified lines | ||
| 23 | 23 | #ifdef Q_OS_WIN |
| 24 | 24 | static BOOL CALLBACK enumWindowsCallback(HWND hWnd, LPARAM lParam) { |
| 25 | 25 | const UINT TIMEOUT = 200; // ms |
| 26 | − DWORD response; | |
| 26 | + DWORD_PTR response; | |
| 27 | 27 | LRESULT result = SendMessageTimeout(hWnd, UWM_IDENTIFY_INSTANCES, 0, 0, SMTO_BLOCK | SMTO_ABORTIFHUNG, TIMEOUT, &response); |
| 28 | 28 | if (result == 0) { // Timeout; continue search. |
| 29 | 29 | return TRUE; |
| @@ -463,7 +463,7 @@ void ControllerScriptingInterface::resetDevice(unsigned int device) { · 462 unmodified lines | ||
| 463 | 463 | } |
| 464 | 464 | |
| 465 | 465 | int ControllerScriptingInterface::findDevice(QString name) { |
| 466 | − Application::getUserInputMapper()->findDevice(name); | |
| 466 | + return Application::getUserInputMapper()->findDevice(name); | |
| 467 | 467 | } |
| 468 | 468 | |
| 469 | 469 | InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) : |
| @@ -65,6 +65,7 @@ public: · 64 unmodified lines | ||
| 65 | 65 | |
| 66 | 66 | void emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseMoveEvent(MouseEvent(*event, deviceID)); } |
| 67 | 67 | void emitMousePressEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mousePressEvent(MouseEvent(*event, deviceID)); } |
| 68 | + void emitMouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseDoublePressEvent(MouseEvent(*event, deviceID)); } | |
| 68 | 69 | void emitMouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseReleaseEvent(MouseEvent(*event, deviceID)); } |
| 69 | 70 | |
| 70 | 71 | void emitTouchBeginEvent(const TouchEvent& event) { emit touchBeginEvent(event); } |
| @@ -25,9 +25,9 @@ bool HMDScriptingInterface::getHUDLookAtPosition3D(glm::vec3& result) const { · 24 unmodified lines | ||
| 25 | 25 | |
| 26 | 26 | glm::vec3 direction = orientation * glm::vec3(0.0f, 0.0f, -1.0f); |
| 27 | 27 | |
| 28 | − ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay(); | |
| 28 | + const auto& compositor = Application::getInstance()->getApplicationCompositor(); | |
| 29 | 29 | |
| 30 | − return applicationOverlay.calculateRayUICollisionPoint(position, direction, result); | |
| 30 | + return compositor.calculateRayUICollisionPoint(position, direction, result); | |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | 33 | QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) { |
| @@ -40,7 +40,7 @@ QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* conte · 6 unmodified lines | ||
| 40 | 40 | glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * (hudIntersection - sphereCenter); |
| 41 | 41 | glm::quat rotation = ::rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), direction); |
| 42 | 42 | glm::vec3 eulers = ::safeEulerAngles(rotation); |
| 43 | − return qScriptValueFromValue<glm::vec2>(engine, Application::getInstance()->getApplicationOverlay() | |
| 43 | + return qScriptValueFromValue<glm::vec2>(engine, Application::getInstance()->getApplicationCompositor() | |
| 44 | 44 | .sphericalToOverlay(glm::vec2(eulers.y, -eulers.x))); |
| 45 | 45 | } |
| 46 | 46 | return QScriptValue::NullValue; |
| @@ -27,11 +27,11 @@ public: · 26 unmodified lines | ||
| 27 | 27 | static QScriptValue getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine); |
| 28 | 28 | |
| 29 | 29 | public slots: |
| 30 | − void toggleMagnifier() { Application::getInstance()->getApplicationOverlay().toggleMagnifier(); }; | |
| 30 | + void toggleMagnifier() { Application::getInstance()->getApplicationCompositor().toggleMagnifier(); }; | |
| 31 | 31 | |
| 32 | 32 | private: |
| 33 | 33 | HMDScriptingInterface() {}; |
| 34 | − bool getMagnifier() const { return Application::getInstance()->getApplicationOverlay().hasMagnifier(); }; | |
| 34 | + bool getMagnifier() const { return Application::getInstance()->getApplicationCompositor().hasMagnifier(); }; | |
| 35 | 35 | bool isHMDMode() const { return Application::getInstance()->isHMDMode(); } |
| 36 | 36 | |
| 37 | 37 | bool getHUDLookAtPosition3D(glm::vec3& result) const; |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | ||
| 11 | 11 | // |
| 12 | 12 | |
| 13 | 13 | #include "starfield/renderer/Renderer.h" |
| 14 | +#include "Application.h" | |
| 14 | 15 | |
| 15 | 16 | using namespace starfield; |
| 16 | 17 | |
| @@ -52,6 +53,10 @@ void Renderer::render(float perspective, float aspect, mat4 const& orientation, · 35 unmodified lines | ||
| 52 | 53 | matrix[3][1] = 0.0f; |
| 53 | 54 | matrix[3][2] = 0.0f; |
| 54 | 55 | |
| 56 | + glMatrixMode(GL_PROJECTION); | |
| 57 | + glPushMatrix(); | |
| 58 | + glLoadMatrixf(glm::value_ptr(qApp->getDisplayViewFrustum()->getProjection())); | |
| 59 | + glMatrixMode(GL_MODELVIEW); | |
| 55 | 60 | // extract local z vector |
| 56 | 61 | vec3 ahead = vec3(matrix[2]); |
| 57 | 62 | |
| @@ -74,6 +79,10 @@ void Renderer::render(float perspective, float aspect, mat4 const& orientation, · 16 unmodified lines | ||
| 74 | 79 | floodFill(cursor, TileSelection(*this, _tileArray, _tileArray + _tiling.getTileCount(), (TileSelection::Cursor*) _batchCountArray)); |
| 75 | 80 | |
| 76 | 81 | this->glBatch(glm::value_ptr(matrix), prepareBatch((unsigned*) _batchOffs, _outIndexPos), alpha); |
| 82 | + glMatrixMode(GL_PROJECTION); | |
| 83 | + glPopMatrix(); | |
| 84 | + glMatrixMode(GL_MODELVIEW); | |
| 85 | + | |
| 77 | 86 | } |
| 78 | 87 | |
| 79 | 88 | // renderer construction |
| @@ -22,6 +22,20 @@ AddressBarDialog::AddressBarDialog(QQuickItem* parent) : OffscreenQmlDialog(pare · 21 unmodified lines | ||
| 22 | 22 | connect(addressManager.data(), &AddressManager::lookupResultIsOffline, this, &AddressBarDialog::displayAddressOfflineMessage); |
| 23 | 23 | connect(addressManager.data(), &AddressManager::lookupResultIsNotFound, this, &AddressBarDialog::displayAddressNotFoundMessage); |
| 24 | 24 | connect(addressManager.data(), &AddressManager::lookupResultsFinished, this, &AddressBarDialog::hide); |
| 25 | + connect(addressManager.data(), &AddressManager::goBackPossible, this, [this] (bool isPossible) { | |
| 26 | + if (isPossible != _backEnabled) { | |
| 27 | + _backEnabled = isPossible; | |
| 28 | + emit backEnabledChanged(); | |
| 29 | + } | |
| 30 | + }); | |
| 31 | + connect(addressManager.data(), &AddressManager::goForwardPossible, this, [this] (bool isPossible) { | |
| 32 | + if (isPossible != _forwardEnabled) { | |
| 33 | + _forwardEnabled = isPossible; | |
| 34 | + emit forwardEnabledChanged(); | |
| 35 | + } | |
| 36 | + }); | |
| 37 | + _backEnabled = !(DependencyManager::get<AddressManager>()->getBackStack().isEmpty()); | |
| 38 | + _forwardEnabled = !(DependencyManager::get<AddressManager>()->getForwardStack().isEmpty()); | |
| 25 | 39 | } |
| 26 | 40 | |
| 27 | 41 | void AddressBarDialog::hide() { |
| @@ -35,6 +49,16 @@ void AddressBarDialog::loadAddress(const QString& address) { · 7 unmodified lines | ||
| 35 | 49 | } |
| 36 | 50 | } |
| 37 | 51 | |
| 52 | +void AddressBarDialog::loadBack() { | |
| 53 | + qDebug() << "Called LoadBack"; | |
| 54 | + DependencyManager::get<AddressManager>()->goBack(); | |
| 55 | +} | |
| 56 | + | |
| 57 | +void AddressBarDialog::loadForward() { | |
| 58 | + qDebug() << "Called LoadForward"; | |
| 59 | + DependencyManager::get<AddressManager>()->goForward(); | |
| 60 | +} | |
| 61 | + | |
| 38 | 62 | void AddressBarDialog::displayAddressOfflineMessage() { |
| 39 | 63 | OffscreenUi::error("That user or place is currently offline"); |
| 40 | 64 | } |
| @@ -18,9 +18,17 @@ class AddressBarDialog : public OffscreenQmlDialog · 17 unmodified lines | ||
| 18 | 18 | { |
| 19 | 19 | Q_OBJECT |
| 20 | 20 | HIFI_QML_DECL |
| 21 | + Q_PROPERTY(bool backEnabled READ backEnabled NOTIFY backEnabledChanged) | |
| 22 | + Q_PROPERTY(bool forwardEnabled READ forwardEnabled NOTIFY forwardEnabledChanged) | |
| 21 | 23 | |
| 22 | 24 | public: |
| 23 | 25 | AddressBarDialog(QQuickItem* parent = nullptr); |
| 26 | + bool backEnabled() { return _backEnabled; } | |
| 27 | + bool forwardEnabled() { return _forwardEnabled; } | |
| 28 | + | |
| 29 | +signals: | |
| 30 | + void backEnabledChanged(); | |
| 31 | + void forwardEnabledChanged(); | |
| 24 | 32 | |
| 25 | 33 | protected: |
| 26 | 34 | void displayAddressOfflineMessage(); |
| @@ -28,6 +36,11 @@ protected: · 1 unmodified line | ||
| 28 | 36 | void hide(); |
| 29 | 37 | |
| 30 | 38 | Q_INVOKABLE void loadAddress(const QString& address); |
| 39 | + Q_INVOKABLE void loadBack(); | |
| 40 | + Q_INVOKABLE void loadForward(); | |
| 41 | + | |
| 42 | + bool _backEnabled; | |
| 43 | + bool _forwardEnabled; | |
| 31 | 44 | }; |
| 32 | 45 | |
| 33 | 46 | #endif |
| @@ -0,0 +1,761 @@ | ||
| 1 | +// | |
| 2 | +// ApplicationCompositor.cpp | |
| 3 | +// interface/src/ui/overlays | |
| 4 | +// | |
| 5 | +// Created by Benjamin Arnold on 5/27/14. | |
| 6 | +// Copyright 2014 High Fidelity, Inc. | |
| 7 | +// | |
| 8 | +// Distributed under the Apache License, Version 2.0. | |
| 9 | +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 10 | +// | |
| 11 | + | |
| 12 | +#include "InterfaceConfig.h" | |
| 13 | + | |
| 14 | +#include "ApplicationCompositor.h" | |
| 15 | + | |
| 16 | +#include <glm/gtc/type_ptr.hpp> | |
| 17 | + | |
| 18 | +#include <avatar/AvatarManager.h> | |
| 19 | +#include <gpu/GLBackend.h> | |
| 20 | +#include <CursorManager.h> | |
| 21 | +#include <Tooltip.h> | |
| 22 | + | |
| 23 | +#include "Application.h" | |
| 24 | + | |
| 25 | + | |
| 26 | +// Used to animate the magnification windows | |
| 27 | +static const float MAG_SPEED = 0.08f; | |
| 28 | + | |
| 29 | +static const quint64 MSECS_TO_USECS = 1000ULL; | |
| 30 | +static const quint64 TOOLTIP_DELAY = 500 * MSECS_TO_USECS; | |
| 31 | + | |
| 32 | +static const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f }; | |
| 33 | +static const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f }; | |
| 34 | +static const float reticleSize = TWO_PI / 100.0f; | |
| 35 | + | |
| 36 | +static const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f }; | |
| 37 | +static const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f; | |
| 38 | + | |
| 39 | +static const float CURSOR_PIXEL_SIZE = 32.0f; | |
| 40 | +static const float MOUSE_PITCH_RANGE = 1.0f * PI; | |
| 41 | +static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI; | |
| 42 | +static const glm::vec2 MOUSE_RANGE(MOUSE_YAW_RANGE, MOUSE_PITCH_RANGE); | |
| 43 | + | |
| 44 | +static gpu::BufferPointer _hemiVertices; | |
| 45 | +static gpu::BufferPointer _hemiIndices; | |
| 46 | +static int _hemiIndexCount{ 0 }; | |
| 47 | +EntityItemID ApplicationCompositor::_noItemId; | |
| 48 | +static QString _tooltipId; | |
| 49 | + | |
| 50 | +// Return a point's cartesian coordinates on a sphere from pitch and yaw | |
| 51 | +glm::vec3 getPoint(float yaw, float pitch) { | |
| 52 | + return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)), | |
| 53 | + glm::sin(-pitch), | |
| 54 | + glm::cos(-pitch) * (-glm::cos(yaw))); | |
| 55 | +} | |
| 56 | + | |
| 57 | +//Checks if the given ray intersects the sphere at the origin. result will store a multiplier that should | |
| 58 | +//be multiplied by dir and added to origin to get the location of the collision | |
| 59 | +bool raySphereIntersect(const glm::vec3 &dir, const glm::vec3 &origin, float r, float* result) | |
| 60 | +{ | |
| 61 | + //Source: http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection | |
| 62 | + | |
| 63 | + //Compute A, B and C coefficients | |
| 64 | + float a = glm::dot(dir, dir); | |
| 65 | + float b = 2 * glm::dot(dir, origin); | |
| 66 | + float c = glm::dot(origin, origin) - (r * r); | |
| 67 | + | |
| 68 | + //Find discriminant | |
| 69 | + float disc = b * b - 4 * a * c; | |
| 70 | + | |
| 71 | + // if discriminant is negative there are no real roots, so return | |
| 72 | + // false as ray misses sphere | |
| 73 | + if (disc < 0) { | |
| 74 | + return false; | |
| 75 | + } | |
| 76 | + | |
| 77 | + // compute q as described above | |
| 78 | + float distSqrt = sqrtf(disc); | |
| 79 | + float q; | |
| 80 | + if (b < 0) { | |
| 81 | + q = (-b - distSqrt) / 2.0f; | |
| 82 | + } else { | |
| 83 | + q = (-b + distSqrt) / 2.0f; | |
| 84 | + } | |
| 85 | + | |
| 86 | + // compute t0 and t1 | |
| 87 | + float t0 = q / a; | |
| 88 | + float t1 = c / q; | |
| 89 | + | |
| 90 | + // make sure t0 is smaller than t1 | |
| 91 | + if (t0 > t1) { | |
| 92 | + // if t0 is bigger than t1 swap them around | |
| 93 | + float temp = t0; | |
| 94 | + t0 = t1; | |
| 95 | + t1 = temp; | |
| 96 | + } | |
| 97 | + | |
| 98 | + // if t1 is less than zero, the object is in the ray's negative direction | |
| 99 | + // and consequently the ray misses the sphere | |
| 100 | + if (t1 < 0) { | |
| 101 | + return false; | |
| 102 | + } | |
| 103 | + | |
| 104 | + // if t0 is less than zero, the intersection point is at t1 | |
| 105 | + if (t0 < 0) { | |
| 106 | + *result = t1; | |
| 107 | + return true; | |
| 108 | + } else { // else the intersection point is at t0 | |
| 109 | + *result = t0; | |
| 110 | + return true; | |
| 111 | + } | |
| 112 | +} | |
| 113 | + | |
| 114 | +ApplicationCompositor::ApplicationCompositor() { | |
| 115 | + memset(_reticleActive, 0, sizeof(_reticleActive)); | |
| 116 | + memset(_magActive, 0, sizeof(_reticleActive)); | |
| 117 | + memset(_magSizeMult, 0, sizeof(_magSizeMult)); | |
| 118 | + | |
| 119 | + auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 120 | + | |
| 121 | + _reticleQuad = geometryCache->allocateID(); | |
| 122 | + _magnifierQuad = geometryCache->allocateID(); | |
| 123 | + _magnifierBorder = geometryCache->allocateID(); | |
| 124 | + | |
| 125 | + auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); | |
| 126 | + connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity, [=](const EntityItemID& entityItemID, const MouseEvent& event) { | |
| 127 | + if (_hoverItemId != entityItemID) { | |
| 128 | + _hoverItemId = entityItemID; | |
| 129 | + _hoverItemEnterUsecs = usecTimestampNow(); | |
| 130 | + auto properties = entityScriptingInterface->getEntityProperties(_hoverItemId); | |
| 131 | + _hoverItemHref = properties.getHref(); | |
| 132 | + auto cursor = Cursor::Manager::instance().getCursor(); | |
| 133 | + if (!_hoverItemHref.isEmpty()) { | |
| 134 | + cursor->setIcon(Cursor::Icon::LINK); | |
| 135 | + } else { | |
| 136 | + cursor->setIcon(Cursor::Icon::DEFAULT); | |
| 137 | + } | |
| 138 | + } | |
| 139 | + }); | |
| 140 | + | |
| 141 | + connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, [=](const EntityItemID& entityItemID, const MouseEvent& event) { | |
| 142 | + if (_hoverItemId == entityItemID) { | |
| 143 | + _hoverItemId = _noItemId; | |
| 144 | + _hoverItemHref.clear(); | |
| 145 | + auto cursor = Cursor::Manager::instance().getCursor(); | |
| 146 | + cursor->setIcon(Cursor::Icon::DEFAULT); | |
| 147 | + if (!_tooltipId.isEmpty()) { | |
| 148 | + qDebug() << "Closing tooltip " << _tooltipId; | |
| 149 | + Tooltip::closeTip(_tooltipId); | |
| 150 | + _tooltipId.clear(); | |
| 151 | + } | |
| 152 | + } | |
| 153 | + }); | |
| 154 | +} | |
| 155 | + | |
| 156 | +ApplicationCompositor::~ApplicationCompositor() { | |
| 157 | +} | |
| 158 | + | |
| 159 | + | |
| 160 | +void ApplicationCompositor::bindCursorTexture(gpu::Batch& batch, uint8_t cursorIndex) { | |
| 161 | + auto& cursorManager = Cursor::Manager::instance(); | |
| 162 | + auto cursor = cursorManager.getCursor(cursorIndex); | |
| 163 | + auto iconId = cursor->getIcon(); | |
| 164 | + if (!_cursors.count(iconId)) { | |
| 165 | + auto iconPath = cursorManager.getIconImage(cursor->getIcon()); | |
| 166 | + _cursors[iconId] = DependencyManager::get<TextureCache>()-> | |
| 167 | + getImageTexture(iconPath); | |
| 168 | + } | |
| 169 | + batch.setUniformTexture(0, _cursors[iconId]); | |
| 170 | +} | |
| 171 | + | |
| 172 | +// Draws the FBO texture for the screen | |
| 173 | +void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) { | |
| 174 | + if (_alpha == 0.0f) { | |
| 175 | + return; | |
| 176 | + } | |
| 177 | + | |
| 178 | + GLuint texture = qApp->getApplicationOverlay().getOverlayTexture(); | |
| 179 | + if (!texture) { | |
| 180 | + return; | |
| 181 | + } | |
| 182 | + | |
| 183 | + updateTooltips(); | |
| 184 | + | |
| 185 | + vec2 canvasSize = qApp->getCanvasSize(); | |
| 186 | + | |
| 187 | + //Handle fading and deactivation/activation of UI | |
| 188 | + gpu::Batch batch; | |
| 189 | + | |
| 190 | + renderArgs->_context->syncCache(); | |
| 191 | + auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 192 | + | |
| 193 | + geometryCache->useSimpleDrawPipeline(batch); | |
| 194 | + batch.setModelTransform(Transform()); | |
| 195 | + batch.setViewTransform(Transform()); | |
| 196 | + batch.setProjectionTransform(mat4()); | |
| 197 | + batch._glBindTexture(GL_TEXTURE_2D, texture); | |
| 198 | + batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| 199 | + batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
| 200 | + geometryCache->renderUnitQuad(batch, vec4(vec3(1), _alpha)); | |
| 201 | + | |
| 202 | + // Doesn't actually render | |
| 203 | + renderPointers(batch); | |
| 204 | + | |
| 205 | + //draw the mouse pointer | |
| 206 | + // Get the mouse coordinates and convert to NDC [-1, 1] | |
| 207 | + vec2 mousePosition = toNormalizedDeviceScale(vec2(qApp->getMouse()), canvasSize); | |
| 208 | + // Invert the Y axis | |
| 209 | + mousePosition.y *= -1.0f; | |
| 210 | + | |
| 211 | + Transform model; | |
| 212 | + model.setTranslation(vec3(mousePosition, 0)); | |
| 213 | + vec2 mouseSize = CURSOR_PIXEL_SIZE / canvasSize; | |
| 214 | + model.setScale(vec3(mouseSize, 1.0f)); | |
| 215 | + batch.setModelTransform(model); | |
| 216 | + bindCursorTexture(batch); | |
| 217 | + vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f }; | |
| 218 | + geometryCache->renderUnitQuad(batch, vec4(1)); | |
| 219 | + renderArgs->_context->render(batch); | |
| 220 | +} | |
| 221 | + | |
| 222 | + | |
| 223 | +vec2 getPolarCoordinates(const PalmData& palm) { | |
| 224 | + MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 225 | + auto avatarOrientation = myAvatar->getOrientation(); | |
| 226 | + auto eyePos = myAvatar->getDefaultEyePosition(); | |
| 227 | + glm::vec3 tip = myAvatar->getLaserPointerTipPosition(&palm); | |
| 228 | + // Direction of the tip relative to the eye | |
| 229 | + glm::vec3 tipDirection = tip - eyePos; | |
| 230 | + // orient into avatar space | |
| 231 | + tipDirection = glm::inverse(avatarOrientation) * tipDirection; | |
| 232 | + // Normalize for trig functions | |
| 233 | + tipDirection = glm::normalize(tipDirection); | |
| 234 | + // Convert to polar coordinates | |
| 235 | + glm::vec2 polar(glm::atan(tipDirection.x, -tipDirection.z), glm::asin(tipDirection.y)); | |
| 236 | + return polar; | |
| 237 | +} | |
| 238 | + | |
| 239 | +// Draws the FBO texture for Oculus rift. | |
| 240 | +void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int eye) { | |
| 241 | + if (_alpha == 0.0f) { | |
| 242 | + return; | |
| 243 | + } | |
| 244 | + | |
| 245 | + GLuint texture = qApp->getApplicationOverlay().getOverlayTexture(); | |
| 246 | + if (!texture) { | |
| 247 | + return; | |
| 248 | + } | |
| 249 | + | |
| 250 | + updateTooltips(); | |
| 251 | + | |
| 252 | + vec2 canvasSize = qApp->getCanvasSize(); | |
| 253 | + _textureAspectRatio = aspect(canvasSize); | |
| 254 | + | |
| 255 | + renderArgs->_context->syncCache(); | |
| 256 | + auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 257 | + | |
| 258 | + gpu::Batch batch; | |
| 259 | + geometryCache->useSimpleDrawPipeline(batch); | |
| 260 | + batch._glDisable(GL_DEPTH_TEST); | |
| 261 | + batch._glDisable(GL_CULL_FACE); | |
| 262 | + batch._glBindTexture(GL_TEXTURE_2D, texture); | |
| 263 | + batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| 264 | + batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
| 265 | + batch.setViewTransform(Transform()); | |
| 266 | + batch.setProjectionTransform(qApp->getEyeProjection(eye)); | |
| 267 | + | |
| 268 | + mat4 eyePose = qApp->getEyePose(eye); | |
| 269 | + glm::mat4 overlayXfm = glm::inverse(eyePose); | |
| 270 | + | |
| 271 | +#ifdef DEBUG_OVERLAY | |
| 272 | + { | |
| 273 | + batch.setModelTransform(glm::translate(mat4(), vec3(0, 0, -2))); | |
| 274 | + geometryCache->renderUnitQuad(batch, glm::vec4(1)); | |
| 275 | + } | |
| 276 | +#else | |
| 277 | + { | |
| 278 | + batch.setModelTransform(overlayXfm); | |
| 279 | + drawSphereSection(batch); | |
| 280 | + } | |
| 281 | +#endif | |
| 282 | + | |
| 283 | + // Doesn't actually render | |
| 284 | + renderPointers(batch); | |
| 285 | + vec3 reticleScale = vec3(Cursor::Manager::instance().getScale() * reticleSize); | |
| 286 | + | |
| 287 | + bindCursorTexture(batch); | |
| 288 | + | |
| 289 | + MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 290 | + //Controller Pointers | |
| 291 | + for (int i = 0; i < (int)myAvatar->getHand()->getNumPalms(); i++) { | |
| 292 | + PalmData& palm = myAvatar->getHand()->getPalms()[i]; | |
| 293 | + if (palm.isActive()) { | |
| 294 | + glm::vec2 polar = getPolarCoordinates(palm); | |
| 295 | + // Convert to quaternion | |
| 296 | + mat4 pointerXfm = glm::mat4_cast(quat(vec3(polar.y, -polar.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1)); | |
| 297 | + mat4 reticleXfm = overlayXfm * pointerXfm; | |
| 298 | + reticleXfm = glm::scale(reticleXfm, reticleScale); | |
| 299 | + batch.setModelTransform(reticleXfm); | |
| 300 | + // Render reticle at location | |
| 301 | + geometryCache->renderUnitQuad(batch, glm::vec4(1), _reticleQuad); | |
| 302 | + } | |
| 303 | + } | |
| 304 | + | |
| 305 | + //Mouse Pointer | |
| 306 | + if (_reticleActive[MOUSE]) { | |
| 307 | + glm::vec2 projection = screenToSpherical(glm::vec2(_reticlePosition[MOUSE].x(), | |
| 308 | + _reticlePosition[MOUSE].y())); | |
| 309 | + mat4 pointerXfm = glm::mat4_cast(quat(vec3(-projection.y, projection.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1)); | |
| 310 | + mat4 reticleXfm = overlayXfm * pointerXfm; | |
| 311 | + reticleXfm = glm::scale(reticleXfm, reticleScale); | |
| 312 | + batch.setModelTransform(reticleXfm); | |
| 313 | + geometryCache->renderUnitQuad(batch, glm::vec4(1), _reticleQuad); | |
| 314 | + } | |
| 315 | + | |
| 316 | + renderArgs->_context->render(batch); | |
| 317 | +} | |
| 318 | + | |
| 319 | + | |
| 320 | +void ApplicationCompositor::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const { | |
| 321 | + cursorPos *= qApp->getCanvasSize(); | |
| 322 | + const glm::vec2 projection = screenToSpherical(cursorPos); | |
| 323 | + // The overlay space orientation of the mouse coordinates | |
| 324 | + const glm::quat orientation(glm::vec3(-projection.y, projection.x, 0.0f)); | |
| 325 | + // FIXME We now have the direction of the ray FROM THE DEFAULT HEAD POSE. | |
| 326 | + // Now we need to account for the actual camera position relative to the overlay | |
| 327 | + glm::vec3 overlaySpaceDirection = glm::normalize(orientation * IDENTITY_FRONT); | |
| 328 | + | |
| 329 | + | |
| 330 | + // We need the RAW camera orientation and position, because this is what the overlay is | |
| 331 | + // rendered relative to | |
| 332 | + const glm::vec3 overlayPosition = qApp->getCamera()->getPosition(); | |
| 333 | + const glm::quat overlayOrientation = qApp->getCamera()->getRotation(); | |
| 334 | + | |
| 335 | + // Intersection UI overlay space | |
| 336 | + glm::vec3 worldSpaceDirection = overlayOrientation * overlaySpaceDirection; | |
| 337 | + glm::vec3 worldSpaceIntersection = (glm::normalize(worldSpaceDirection) * _oculusUIRadius) + overlayPosition; | |
| 338 | + glm::vec3 worldSpaceHeadPosition = (overlayOrientation * glm::vec3(qApp->getHeadPose()[3])) + overlayPosition; | |
| 339 | + | |
| 340 | + // Intersection in world space | |
| 341 | + origin = worldSpaceHeadPosition; | |
| 342 | + direction = glm::normalize(worldSpaceIntersection - worldSpaceHeadPosition); | |
| 343 | +} | |
| 344 | + | |
| 345 | +//Caculate the click location using one of the sixense controllers. Scale is not applied | |
| 346 | +QPoint ApplicationCompositor::getPalmClickLocation(const PalmData *palm) const { | |
| 347 | + QPoint rv; | |
| 348 | + auto canvasSize = qApp->getCanvasSize(); | |
| 349 | + if (qApp->isHMDMode()) { | |
| 350 | + glm::vec2 polar = getPolarCoordinates(*palm); | |
| 351 | + glm::vec2 point = sphericalToScreen(-polar); | |
| 352 | + rv.rx() = point.x; | |
| 353 | + rv.ry() = point.y; | |
| 354 | + } else { | |
| 355 | + MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 356 | + glm::dmat4 projection; | |
| 357 | + qApp->getProjectionMatrix(&projection); | |
| 358 | + glm::quat invOrientation = glm::inverse(myAvatar->getOrientation()); | |
| 359 | + glm::vec3 eyePos = myAvatar->getDefaultEyePosition(); | |
| 360 | + glm::vec3 tip = myAvatar->getLaserPointerTipPosition(palm); | |
| 361 | + glm::vec3 tipPos = invOrientation * (tip - eyePos); | |
| 362 | + | |
| 363 | + glm::vec4 clipSpacePos = glm::vec4(projection * glm::dvec4(tipPos, 1.0)); | |
| 364 | + glm::vec3 ndcSpacePos; | |
| 365 | + if (clipSpacePos.w != 0) { | |
| 366 | + ndcSpacePos = glm::vec3(clipSpacePos) / clipSpacePos.w; | |
| 367 | + } | |
| 368 | + | |
| 369 | + rv.setX(((ndcSpacePos.x + 1.0) / 2.0) * canvasSize.x); | |
| 370 | + rv.setY((1.0 - ((ndcSpacePos.y + 1.0) / 2.0)) * canvasSize.y); | |
| 371 | + } | |
| 372 | + return rv; | |
| 373 | +} | |
| 374 | + | |
| 375 | +//Finds the collision point of a world space ray | |
| 376 | +bool ApplicationCompositor::calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const { | |
| 377 | + MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 378 | + | |
| 379 | + glm::quat inverseOrientation = glm::inverse(myAvatar->getOrientation()); | |
| 380 | + | |
| 381 | + glm::vec3 relativePosition = inverseOrientation * (position - myAvatar->getDefaultEyePosition()); | |
| 382 | + glm::vec3 relativeDirection = glm::normalize(inverseOrientation * direction); | |
| 383 | + | |
| 384 | + float t; | |
| 385 | + if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getScale(), &t)){ | |
| 386 | + result = position + direction * t; | |
| 387 | + return true; | |
| 388 | + } | |
| 389 | + | |
| 390 | + return false; | |
| 391 | +} | |
| 392 | + | |
| 393 | +//Renders optional pointers | |
| 394 | +void ApplicationCompositor::renderPointers(gpu::Batch& batch) { | |
| 395 | + if (qApp->isHMDMode() && !qApp->getLastMouseMoveWasSimulated() && !qApp->isMouseHidden()) { | |
| 396 | + //If we are in oculus, render reticle later | |
| 397 | + QPoint position = QPoint(qApp->getTrueMouseX(), qApp->getTrueMouseY()); | |
| 398 | + _reticlePosition[MOUSE] = position; | |
| 399 | + _reticleActive[MOUSE] = true; | |
| 400 | + _magActive[MOUSE] = _magnifier; | |
| 401 | + _reticleActive[LEFT_CONTROLLER] = false; | |
| 402 | + _reticleActive[RIGHT_CONTROLLER] = false; | |
| 403 | + } else if (qApp->getLastMouseMoveWasSimulated() && Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) { | |
| 404 | + //only render controller pointer if we aren't already rendering a mouse pointer | |
| 405 | + _reticleActive[MOUSE] = false; | |
| 406 | + _magActive[MOUSE] = false; | |
| 407 | + renderControllerPointers(batch); | |
| 408 | + } | |
| 409 | +} | |
| 410 | + | |
| 411 | + | |
| 412 | +void ApplicationCompositor::renderControllerPointers(gpu::Batch& batch) { | |
| 413 | + MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 414 | + | |
| 415 | + //Static variables used for storing controller state | |
| 416 | + static quint64 pressedTime[NUMBER_OF_RETICLES] = { 0ULL, 0ULL, 0ULL }; | |
| 417 | + static bool isPressed[NUMBER_OF_RETICLES] = { false, false, false }; | |
| 418 | + static bool stateWhenPressed[NUMBER_OF_RETICLES] = { false, false, false }; | |
| 419 | + | |
| 420 | + const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData(); | |
| 421 | + | |
| 422 | + for (unsigned int palmIndex = 2; palmIndex < 4; palmIndex++) { | |
| 423 | + const int index = palmIndex - 1; | |
| 424 | + | |
| 425 | + const PalmData* palmData = NULL; | |
| 426 | + | |
| 427 | + if (palmIndex >= handData->getPalms().size()) { | |
| 428 | + return; | |
| 429 | + } | |
| 430 | + | |
| 431 | + if (handData->getPalms()[palmIndex].isActive()) { | |
| 432 | + palmData = &handData->getPalms()[palmIndex]; | |
| 433 | + } else { | |
| 434 | + continue; | |
| 435 | + } | |
| 436 | + | |
| 437 | + int controllerButtons = palmData->getControllerButtons(); | |
| 438 | + | |
| 439 | + //Check for if we should toggle or drag the magnification window | |
| 440 | + if (controllerButtons & BUTTON_3) { | |
| 441 | + if (isPressed[index] == false) { | |
| 442 | + //We are now dragging the window | |
| 443 | + isPressed[index] = true; | |
| 444 | + //set the pressed time in us | |
| 445 | + pressedTime[index] = usecTimestampNow(); | |
| 446 | + stateWhenPressed[index] = _magActive[index]; | |
| 447 | + } | |
| 448 | + } else if (isPressed[index]) { | |
| 449 | + isPressed[index] = false; | |
| 450 | + //If the button was only pressed for < 250 ms | |
| 451 | + //then disable it. | |
| 452 | + | |
| 453 | + const int MAX_BUTTON_PRESS_TIME = 250 * MSECS_TO_USECS; | |
| 454 | + if (usecTimestampNow() < pressedTime[index] + MAX_BUTTON_PRESS_TIME) { | |
| 455 | + _magActive[index] = !stateWhenPressed[index]; | |
| 456 | + } | |
| 457 | + } | |
| 458 | + | |
| 459 | + //if we have the oculus, we should make the cursor smaller since it will be | |
| 460 | + //magnified | |
| 461 | + if (qApp->isHMDMode()) { | |
| 462 | + | |
| 463 | + QPoint point = getPalmClickLocation(palmData); | |
| 464 | + | |
| 465 | + _reticlePosition[index] = point; | |
| 466 | + | |
| 467 | + //When button 2 is pressed we drag the mag window | |
| 468 | + if (isPressed[index]) { | |
| 469 | + _magActive[index] = true; | |
| 470 | + } | |
| 471 | + | |
| 472 | + // If oculus is enabled, we draw the crosshairs later | |
| 473 | + continue; | |
| 474 | + } | |
| 475 | + | |
| 476 | + auto canvasSize = qApp->getCanvasSize(); | |
| 477 | + int mouseX, mouseY; | |
| 478 | + if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) { | |
| 479 | + QPoint res = getPalmClickLocation(palmData); | |
| 480 | + mouseX = res.x(); | |
| 481 | + mouseY = res.y(); | |
| 482 | + } else { | |
| 483 | + // Get directon relative to avatar orientation | |
| 484 | + glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * palmData->getFingerDirection(); | |
| 485 | + | |
| 486 | + // Get the angles, scaled between (-0.5,0.5) | |
| 487 | + float xAngle = (atan2(direction.z, direction.x) + M_PI_2); | |
| 488 | + float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2)); | |
| 489 | + | |
| 490 | + // Get the pixel range over which the xAngle and yAngle are scaled | |
| 491 | + float cursorRange = canvasSize.x * SixenseManager::getInstance().getCursorPixelRangeMult(); | |
| 492 | + | |
| 493 | + mouseX = (canvasSize.x / 2.0f + cursorRange * xAngle); | |
| 494 | + mouseY = (canvasSize.y / 2.0f + cursorRange * yAngle); | |
| 495 | + } | |
| 496 | + | |
| 497 | + //If the cursor is out of the screen then don't render it | |
| 498 | + if (mouseX < 0 || mouseX >= (int)canvasSize.x || mouseY < 0 || mouseY >= (int)canvasSize.y) { | |
| 499 | + _reticleActive[index] = false; | |
| 500 | + continue; | |
| 501 | + } | |
| 502 | + _reticleActive[index] = true; | |
| 503 | + | |
| 504 | + | |
| 505 | + const float reticleSize = 40.0f; | |
| 506 | + | |
| 507 | + mouseX -= reticleSize / 2.0f; | |
| 508 | + mouseY += reticleSize / 2.0f; | |
| 509 | + | |
| 510 | + | |
| 511 | + glm::vec2 topLeft(mouseX, mouseY); | |
| 512 | + glm::vec2 bottomRight(mouseX + reticleSize, mouseY - reticleSize); | |
| 513 | + glm::vec2 texCoordTopLeft(0.0f, 0.0f); | |
| 514 | + glm::vec2 texCoordBottomRight(1.0f, 1.0f); | |
| 515 | + | |
| 516 | + DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, | |
| 517 | + glm::vec4(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f)); | |
| 518 | + | |
| 519 | + } | |
| 520 | +} | |
| 521 | + | |
| 522 | +//Renders a small magnification of the currently bound texture at the coordinates | |
| 523 | +void ApplicationCompositor::renderMagnifier(gpu::Batch& batch, const glm::vec2& magPos, float sizeMult, bool showBorder) { | |
| 524 | + if (!_magnifier) { | |
| 525 | + return; | |
| 526 | + } | |
| 527 | + auto canvasSize = qApp->getCanvasSize(); | |
| 528 | + | |
| 529 | + const int widgetWidth = canvasSize.x; | |
| 530 | + const int widgetHeight = canvasSize.y; | |
| 531 | + | |
| 532 | + const float halfWidth = (MAGNIFY_WIDTH / _textureAspectRatio) * sizeMult / 2.0f; | |
| 533 | + const float halfHeight = MAGNIFY_HEIGHT * sizeMult / 2.0f; | |
| 534 | + // Magnification Texture Coordinates | |
| 535 | + const float magnifyULeft = (magPos.x - halfWidth) / (float)widgetWidth; | |
| 536 | + const float magnifyURight = (magPos.x + halfWidth) / (float)widgetWidth; | |
| 537 | + const float magnifyVTop = 1.0f - (magPos.y - halfHeight) / (float)widgetHeight; | |
| 538 | + const float magnifyVBottom = 1.0f - (magPos.y + halfHeight) / (float)widgetHeight; | |
| 539 | + | |
| 540 | + const float newHalfWidth = halfWidth * MAGNIFY_MULT; | |
| 541 | + const float newHalfHeight = halfHeight * MAGNIFY_MULT; | |
| 542 | + //Get yaw / pitch value for the corners | |
| 543 | + const glm::vec2 topLeftYawPitch = overlayToSpherical(glm::vec2(magPos.x - newHalfWidth, | |
| 544 | + magPos.y - newHalfHeight)); | |
| 545 | + const glm::vec2 bottomRightYawPitch = overlayToSpherical(glm::vec2(magPos.x + newHalfWidth, | |
| 546 | + magPos.y + newHalfHeight)); | |
| 547 | + | |
| 548 | + const glm::vec3 bottomLeft = getPoint(topLeftYawPitch.x, bottomRightYawPitch.y); | |
| 549 | + const glm::vec3 bottomRight = getPoint(bottomRightYawPitch.x, bottomRightYawPitch.y); | |
| 550 | + const glm::vec3 topLeft = getPoint(topLeftYawPitch.x, topLeftYawPitch.y); | |
| 551 | + const glm::vec3 topRight = getPoint(bottomRightYawPitch.x, topLeftYawPitch.y); | |
| 552 | + | |
| 553 | + auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 554 | + | |
| 555 | + if (bottomLeft != _previousMagnifierBottomLeft || bottomRight != _previousMagnifierBottomRight | |
| 556 | + || topLeft != _previousMagnifierTopLeft || topRight != _previousMagnifierTopRight) { | |
| 557 | + QVector<glm::vec3> border; | |
| 558 | + border << topLeft; | |
| 559 | + border << bottomLeft; | |
| 560 | + border << bottomRight; | |
| 561 | + border << topRight; | |
| 562 | + border << topLeft; | |
| 563 | + geometryCache->updateVertices(_magnifierBorder, border, glm::vec4(1.0f, 0.0f, 0.0f, _alpha)); | |
| 564 | + | |
| 565 | + _previousMagnifierBottomLeft = bottomLeft; | |
| 566 | + _previousMagnifierBottomRight = bottomRight; | |
| 567 | + _previousMagnifierTopLeft = topLeft; | |
| 568 | + _previousMagnifierTopRight = topRight; | |
| 569 | + } | |
| 570 | + | |
| 571 | + glPushMatrix(); { | |
| 572 | + if (showBorder) { | |
| 573 | + glDisable(GL_TEXTURE_2D); | |
| 574 | + glLineWidth(1.0f); | |
| 575 | + //Outer Line | |
| 576 | + geometryCache->renderVertices(gpu::LINE_STRIP, _magnifierBorder); | |
| 577 | + glEnable(GL_TEXTURE_2D); | |
| 578 | + } | |
| 579 | + glm::vec4 magnifierColor = { 1.0f, 1.0f, 1.0f, _alpha }; | |
| 580 | + | |
| 581 | + DependencyManager::get<GeometryCache>()->renderQuad(bottomLeft, bottomRight, topRight, topLeft, | |
| 582 | + glm::vec2(magnifyULeft, magnifyVBottom), | |
| 583 | + glm::vec2(magnifyURight, magnifyVBottom), | |
| 584 | + glm::vec2(magnifyURight, magnifyVTop), | |
| 585 | + glm::vec2(magnifyULeft, magnifyVTop), | |
| 586 | + magnifierColor, _magnifierQuad); | |
| 587 | + | |
| 588 | + } glPopMatrix(); | |
| 589 | +} | |
| 590 | + | |
| 591 | +void ApplicationCompositor::buildHemiVertices( | |
| 592 | + const float fov, const float aspectRatio, const int slices, const int stacks) { | |
| 593 | + static float textureFOV = 0.0f, textureAspectRatio = 1.0f; | |
| 594 | + if (textureFOV == fov && textureAspectRatio == aspectRatio) { | |
| 595 | + return; | |
| 596 | + } | |
| 597 | + | |
| 598 | + textureFOV = fov; | |
| 599 | + textureAspectRatio = aspectRatio; | |
| 600 | + | |
| 601 | + auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 602 | + | |
| 603 | + _hemiVertices = gpu::BufferPointer(new gpu::Buffer()); | |
| 604 | + _hemiIndices = gpu::BufferPointer(new gpu::Buffer()); | |
| 605 | + | |
| 606 | + | |
| 607 | + if (fov >= PI) { | |
| 608 | + qDebug() << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues"; | |
| 609 | + } | |
| 610 | + | |
| 611 | + //UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm | |
| 612 | + | |
| 613 | + vec3 pos; | |
| 614 | + vec2 uv; | |
| 615 | + // Compute vertices positions and texture UV coordinate | |
| 616 | + // Create and write to buffer | |
| 617 | + for (int i = 0; i < stacks; i++) { | |
| 618 | + uv.y = (float)i / (float)(stacks - 1); // First stack is 0.0f, last stack is 1.0f | |
| 619 | + // abs(theta) <= fov / 2.0f | |
| 620 | + float pitch = -fov * (uv.y - 0.5f); | |
| 621 | + for (int j = 0; j < slices; j++) { | |
| 622 | + uv.x = (float)j / (float)(slices - 1); // First slice is 0.0f, last slice is 1.0f | |
| 623 | + // abs(phi) <= fov * aspectRatio / 2.0f | |
| 624 | + float yaw = -fov * aspectRatio * (uv.x - 0.5f); | |
| 625 | + pos = getPoint(yaw, pitch); | |
| 626 | + static const vec4 color(1); | |
| 627 | + _hemiVertices->append(sizeof(pos), (gpu::Byte*)&pos); | |
| 628 | + _hemiVertices->append(sizeof(vec2), (gpu::Byte*)&uv); | |
| 629 | + _hemiVertices->append(sizeof(vec4), (gpu::Byte*)&color); | |
| 630 | + } | |
| 631 | + } | |
| 632 | + | |
| 633 | + // Compute number of indices needed | |
| 634 | + static const int VERTEX_PER_TRANGLE = 3; | |
| 635 | + static const int TRIANGLE_PER_RECTANGLE = 2; | |
| 636 | + int numberOfRectangles = (slices - 1) * (stacks - 1); | |
| 637 | + _hemiIndexCount = numberOfRectangles * TRIANGLE_PER_RECTANGLE * VERTEX_PER_TRANGLE; | |
| 638 | + | |
| 639 | + // Compute indices order | |
| 640 | + std::vector<GLushort> indices; | |
| 641 | + for (int i = 0; i < stacks - 1; i++) { | |
| 642 | + for (int j = 0; j < slices - 1; j++) { | |
| 643 | + GLushort bottomLeftIndex = i * slices + j; | |
| 644 | + GLushort bottomRightIndex = bottomLeftIndex + 1; | |
| 645 | + GLushort topLeftIndex = bottomLeftIndex + slices; | |
| 646 | + GLushort topRightIndex = topLeftIndex + 1; | |
| 647 | + // FIXME make a z-order curve for better vertex cache locality | |
| 648 | + indices.push_back(topLeftIndex); | |
| 649 | + indices.push_back(bottomLeftIndex); | |
| 650 | + indices.push_back(topRightIndex); | |
| 651 | + | |
| 652 | + indices.push_back(topRightIndex); | |
| 653 | + indices.push_back(bottomLeftIndex); | |
| 654 | + indices.push_back(bottomRightIndex); | |
| 655 | + } | |
| 656 | + } | |
| 657 | + _hemiIndices->append(sizeof(GLushort) * indices.size(), (gpu::Byte*)&indices[0]); | |
| 658 | +} | |
| 659 | + | |
| 660 | + | |
| 661 | +void ApplicationCompositor::drawSphereSection(gpu::Batch& batch) { | |
| 662 | + buildHemiVertices(_textureFov, _textureAspectRatio, 80, 80); | |
| 663 | + static const int VERTEX_DATA_SLOT = 0; | |
| 664 | + static const int TEXTURE_DATA_SLOT = 1; | |
| 665 | + static const int COLOR_DATA_SLOT = 2; | |
| 666 | + gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format()); // 1 for everyone | |
| 667 | + streamFormat->setAttribute(gpu::Stream::POSITION, VERTEX_DATA_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); | |
| 668 | + streamFormat->setAttribute(gpu::Stream::TEXCOORD, TEXTURE_DATA_SLOT, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV)); | |
| 669 | + streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_DATA_SLOT, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::RGBA)); | |
| 670 | + batch.setInputFormat(streamFormat); | |
| 671 | + | |
| 672 | + static const int VERTEX_STRIDE = sizeof(vec3) + sizeof(vec2) + sizeof(vec4); | |
| 673 | + gpu::BufferView posView(_hemiVertices, 0, _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::POSITION)._element); | |
| 674 | + gpu::BufferView uvView(_hemiVertices, sizeof(vec3), _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::TEXCOORD)._element); | |
| 675 | + gpu::BufferView colView(_hemiVertices, sizeof(vec3) + sizeof(vec2), _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element); | |
| 676 | + batch.setInputBuffer(VERTEX_DATA_SLOT, posView); | |
| 677 | + batch.setInputBuffer(TEXTURE_DATA_SLOT, uvView); | |
| 678 | + batch.setInputBuffer(COLOR_DATA_SLOT, colView); | |
| 679 | + batch.setIndexBuffer(gpu::UINT16, _hemiIndices, 0); | |
| 680 | + batch.drawIndexed(gpu::TRIANGLES, _hemiIndexCount); | |
| 681 | +} | |
| 682 | + | |
| 683 | +glm::vec2 ApplicationCompositor::directionToSpherical(const glm::vec3& direction) { | |
| 684 | + glm::vec2 result; | |
| 685 | + // Compute yaw | |
| 686 | + glm::vec3 normalProjection = glm::normalize(glm::vec3(direction.x, 0.0f, direction.z)); | |
| 687 | + result.x = glm::acos(glm::dot(IDENTITY_FRONT, normalProjection)); | |
| 688 | + if (glm::dot(IDENTITY_RIGHT, normalProjection) > 0.0f) { | |
| 689 | + result.x = -glm::abs(result.x); | |
| 690 | + } else { | |
| 691 | + result.x = glm::abs(result.x); | |
| 692 | + } | |
| 693 | + // Compute pitch | |
| 694 | + result.y = angleBetween(IDENTITY_UP, direction) - PI_OVER_TWO; | |
| 695 | + | |
| 696 | + return result; | |
| 697 | +} | |
| 698 | + | |
| 699 | +glm::vec3 ApplicationCompositor::sphericalToDirection(const glm::vec2& sphericalPos) { | |
| 700 | + glm::quat rotation(glm::vec3(sphericalPos.y, sphericalPos.x, 0.0f)); | |
| 701 | + return rotation * IDENTITY_FRONT; | |
| 702 | +} | |
| 703 | + | |
| 704 | +glm::vec2 ApplicationCompositor::screenToSpherical(const glm::vec2& screenPos) { | |
| 705 | + auto screenSize = qApp->getCanvasSize(); | |
| 706 | + glm::vec2 result; | |
| 707 | + result.x = -(screenPos.x / screenSize.x - 0.5f); | |
| 708 | + result.y = (screenPos.y / screenSize.y - 0.5f); | |
| 709 | + result.x *= MOUSE_YAW_RANGE; | |
| 710 | + result.y *= MOUSE_PITCH_RANGE; | |
| 711 | + | |
| 712 | + return result; | |
| 713 | +} | |
| 714 | + | |
| 715 | +glm::vec2 ApplicationCompositor::sphericalToScreen(const glm::vec2& sphericalPos) { | |
| 716 | + glm::vec2 result = sphericalPos; | |
| 717 | + result.x *= -1.0; | |
| 718 | + result /= MOUSE_RANGE; | |
| 719 | + result += 0.5f; | |
| 720 | + result *= qApp->getCanvasSize(); | |
| 721 | + return result; | |
| 722 | +} | |
| 723 | + | |
| 724 | +glm::vec2 ApplicationCompositor::sphericalToOverlay(const glm::vec2& sphericalPos) const { | |
| 725 | + glm::vec2 result = sphericalPos; | |
| 726 | + result.x *= -1.0; | |
| 727 | + result /= _textureFov; | |
| 728 | + result.x /= _textureAspectRatio; | |
| 729 | + result += 0.5f; | |
| 730 | + result *= qApp->getCanvasSize(); | |
| 731 | + return result; | |
| 732 | +} | |
| 733 | + | |
| 734 | +glm::vec2 ApplicationCompositor::overlayToSpherical(const glm::vec2& overlayPos) const { | |
| 735 | + glm::vec2 result = overlayPos; | |
| 736 | + result /= qApp->getCanvasSize(); | |
| 737 | + result -= 0.5f; | |
| 738 | + result *= _textureFov; | |
| 739 | + result.x *= _textureAspectRatio; | |
| 740 | + result.x *= -1.0f; | |
| 741 | + return result; | |
| 742 | +} | |
| 743 | + | |
| 744 | +glm::vec2 ApplicationCompositor::screenToOverlay(const glm::vec2& screenPos) const { | |
| 745 | + return sphericalToOverlay(screenToSpherical(screenPos)); | |
| 746 | +} | |
| 747 | + | |
| 748 | +glm::vec2 ApplicationCompositor::overlayToScreen(const glm::vec2& overlayPos) const { | |
| 749 | + return sphericalToScreen(overlayToSpherical(overlayPos)); | |
| 750 | +} | |
| 751 | + | |
| 752 | +void ApplicationCompositor::updateTooltips() { | |
| 753 | + if (_hoverItemId != _noItemId) { | |
| 754 | + quint64 hoverDuration = usecTimestampNow() - _hoverItemEnterUsecs; | |
| 755 | + if (_hoverItemEnterUsecs != UINT64_MAX && !_hoverItemHref.isEmpty() && hoverDuration > TOOLTIP_DELAY) { | |
| 756 | + // TODO Enable and position the tooltip | |
| 757 | + _hoverItemEnterUsecs = UINT64_MAX; | |
| 758 | + _tooltipId = Tooltip::showTip("URL: " + _hoverItemHref); | |
| 759 | + } | |
| 760 | + } | |
| 761 | +} | |
| @@ -0,0 +1,120 @@ | ||
| 1 | +// | |
| 2 | +// Created by Bradley Austin Davis Arnold on 2015/06/13 | |
| 3 | +// Copyright 2015 High Fidelity, Inc. | |
| 4 | +// | |
| 5 | +// Distributed under the Apache License, Version 2.0. | |
| 6 | +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 7 | +// | |
| 8 | + | |
| 9 | +#ifndef hifi_ApplicationCompositor_h | |
| 10 | +#define hifi_ApplicationCompositor_h | |
| 11 | + | |
| 12 | +#include <QObject> | |
| 13 | +#include <cstdint> | |
| 14 | + | |
| 15 | +#include <EntityItemID.h> | |
| 16 | +#include <GeometryCache.h> | |
| 17 | +#include <GLMHelpers.h> | |
| 18 | +#include <gpu/Batch.h> | |
| 19 | +#include <gpu/Texture.h> | |
| 20 | + | |
| 21 | +class Camera; | |
| 22 | +class PalmData; | |
| 23 | +class RenderArgs; | |
| 24 | + | |
| 25 | +const float MAGNIFY_WIDTH = 220.0f; | |
| 26 | +const float MAGNIFY_HEIGHT = 100.0f; | |
| 27 | +const float MAGNIFY_MULT = 2.0f; | |
| 28 | + | |
| 29 | +const float DEFAULT_HMD_UI_ANGULAR_SIZE = 72.0f; | |
| 30 | + | |
| 31 | +// Handles the drawing of the overlays to the screen | |
| 32 | +// TODO, move divide up the rendering, displaying and input handling | |
| 33 | +// facilities of this class | |
| 34 | +class ApplicationCompositor : public QObject { | |
| 35 | + Q_OBJECT | |
| 36 | +public: | |
| 37 | + ApplicationCompositor(); | |
| 38 | + ~ApplicationCompositor(); | |
| 39 | + | |
| 40 | + void displayOverlayTexture(RenderArgs* renderArgs); | |
| 41 | + void displayOverlayTextureHmd(RenderArgs* renderArgs, int eye); | |
| 42 | + | |
| 43 | + QPoint getPalmClickLocation(const PalmData *palm) const; | |
| 44 | + bool calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const; | |
| 45 | + | |
| 46 | + bool hasMagnifier() const { return _magnifier; } | |
| 47 | + void toggleMagnifier() { _magnifier = !_magnifier; } | |
| 48 | + | |
| 49 | + float getHmdUIAngularSize() const { return _hmdUIAngularSize; } | |
| 50 | + void setHmdUIAngularSize(float hmdUIAngularSize) { _hmdUIAngularSize = hmdUIAngularSize; } | |
| 51 | + | |
| 52 | + // Converter from one frame of reference to another. | |
| 53 | + // Frame of reference: | |
| 54 | + // Direction: Ray that represents the spherical values | |
| 55 | + // Screen: Position on the screen (x,y) | |
| 56 | + // Spherical: Pitch and yaw that gives the position on the sphere we project on (yaw,pitch) | |
| 57 | + // Overlay: Position on the overlay (x,y) | |
| 58 | + // (x,y) in Overlay are similar than (x,y) in Screen except they can be outside of the bound of te screen. | |
| 59 | + // This allows for picking outside of the screen projection in 3D. | |
| 60 | + glm::vec2 sphericalToOverlay(const glm::vec2 & sphericalPos) const; | |
| 61 | + glm::vec2 overlayToSpherical(const glm::vec2 & overlayPos) const; | |
| 62 | + glm::vec2 screenToOverlay(const glm::vec2 & screenPos) const; | |
| 63 | + glm::vec2 overlayToScreen(const glm::vec2 & overlayPos) const; | |
| 64 | + void computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const; | |
| 65 | + GLuint getOverlayTexture() const; | |
| 66 | + | |
| 67 | + static glm::vec2 directionToSpherical(const glm::vec3 & direction); | |
| 68 | + static glm::vec3 sphericalToDirection(const glm::vec2 & sphericalPos); | |
| 69 | + static glm::vec2 screenToSpherical(const glm::vec2 & screenPos); | |
| 70 | + static glm::vec2 sphericalToScreen(const glm::vec2 & sphericalPos); | |
| 71 | + | |
| 72 | +private: | |
| 73 | + void displayOverlayTextureStereo(RenderArgs* renderArgs, float aspectRatio, float fov); | |
| 74 | + void bindCursorTexture(gpu::Batch& batch, uint8_t cursorId = 0); | |
| 75 | + void buildHemiVertices(const float fov, const float aspectRatio, const int slices, const int stacks); | |
| 76 | + void drawSphereSection(gpu::Batch& batch); | |
| 77 | + void updateTooltips(); | |
| 78 | + | |
| 79 | + void renderPointers(gpu::Batch& batch); | |
| 80 | + void renderMagnifier(gpu::Batch& batch, const glm::vec2& magPos, float sizeMult, bool showBorder); | |
| 81 | + void renderControllerPointers(gpu::Batch& batch); | |
| 82 | + void renderPointersOculus(gpu::Batch& batch); | |
| 83 | + | |
| 84 | + // Support for hovering and tooltips | |
| 85 | + static EntityItemID _noItemId; | |
| 86 | + EntityItemID _hoverItemId{ _noItemId }; | |
| 87 | + QString _hoverItemHref; | |
| 88 | + quint64 _hoverItemEnterUsecs{ 0 }; | |
| 89 | + | |
| 90 | + float _hmdUIAngularSize = DEFAULT_HMD_UI_ANGULAR_SIZE; | |
| 91 | + float _textureFov{ glm::radians(DEFAULT_HMD_UI_ANGULAR_SIZE) }; | |
| 92 | + float _textureAspectRatio{ 1.0f }; | |
| 93 | + int _hemiVerticesID{ GeometryCache::UNKNOWN_ID }; | |
| 94 | + | |
| 95 | + enum Reticles { MOUSE, LEFT_CONTROLLER, RIGHT_CONTROLLER, NUMBER_OF_RETICLES }; | |
| 96 | + bool _reticleActive[NUMBER_OF_RETICLES]; | |
| 97 | + QPoint _reticlePosition[NUMBER_OF_RETICLES]; | |
| 98 | + bool _magActive[NUMBER_OF_RETICLES]; | |
| 99 | + float _magSizeMult[NUMBER_OF_RETICLES]; | |
| 100 | + bool _magnifier{ true }; | |
| 101 | + | |
| 102 | + float _alpha{ 1.0f }; | |
| 103 | + float _oculusUIRadius{ 1.0f }; | |
| 104 | + | |
| 105 | + QMap<uint16_t, gpu::TexturePointer> _cursors; | |
| 106 | + | |
| 107 | + int _reticleQuad; | |
| 108 | + int _magnifierQuad; | |
| 109 | + int _magnifierBorder; | |
| 110 | + | |
| 111 | + int _previousBorderWidth{ -1 }; | |
| 112 | + int _previousBorderHeight{ -1 }; | |
| 113 | + | |
| 114 | + glm::vec3 _previousMagnifierBottomLeft; | |
| 115 | + glm::vec3 _previousMagnifierBottomRight; | |
| 116 | + glm::vec3 _previousMagnifierTopLeft; | |
| 117 | + glm::vec3 _previousMagnifierTopRight; | |
| 118 | +}; | |
| 119 | + | |
| 120 | +#endif // hifi_ApplicationCompositor_h | |
| @@ -14,166 +14,58 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <QOpenGLFramebufferObject> |
| 15 | 15 | #include <QOpenGLTexture> |
| 16 | 16 | |
| 17 | +#include <glm/gtc/type_ptr.hpp> | |
| 18 | + | |
| 17 | 19 | #include <avatar/AvatarManager.h> |
| 20 | +#include <DeferredLightingEffect.h> | |
| 18 | 21 | #include <GLMHelpers.h> |
| 19 | −#include <PathUtils.h> | |
| 20 | 22 | #include <gpu/GLBackend.h> |
| 23 | +#include <gpu/GLBackendShared.h> | |
| 21 | 24 | #include <GLMHelpers.h> |
| 22 | −#include <PerfStat.h> | |
| 23 | 25 | #include <OffscreenUi.h> |
| 26 | +#include <CursorManager.h> | |
| 27 | +#include <PerfStat.h> | |
| 24 | 28 | |
| 25 | 29 | #include "AudioClient.h" |
| 26 | 30 | #include "audio/AudioIOStatsRenderer.h" |
| 27 | 31 | #include "audio/AudioScope.h" |
| 28 | −#include "audio/AudioToolBox.h" | |
| 29 | 32 | #include "Application.h" |
| 30 | 33 | #include "ApplicationOverlay.h" |
| 31 | −#include "devices/CameraToolBox.h" | |
| 32 | 34 | |
| 33 | 35 | #include "Util.h" |
| 34 | 36 | #include "ui/Stats.h" |
| 35 | − | |
| 36 | −// Used to animate the magnification windows | |
| 37 | −const float MAG_SPEED = 0.08f; | |
| 38 | − | |
| 39 | −const quint64 MSECS_TO_USECS = 1000ULL; | |
| 37 | +#include "ui/AvatarInputs.h" | |
| 40 | 38 | |
| 41 | 39 | const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f }; |
| 42 | −const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f }; | |
| 43 | −const float reticleSize = TWO_PI / 100.0f; | |
| 44 | − | |
| 45 | − | |
| 46 | −const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f }; | |
| 40 | +const int AUDIO_METER_GAP = 5; | |
| 41 | +const int MUTE_ICON_PADDING = 10; | |
| 42 | +const vec4 CONNECTION_STATUS_BORDER_COLOR{ 1.0f, 0.0f, 0.0f, 0.8f }; | |
| 47 | 43 | const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f; |
| 44 | +static const float ORTHO_NEAR_CLIP = -10000; | |
| 45 | +static const float ORTHO_FAR_CLIP = 10000; | |
| 48 | 46 | |
| 49 | −static const float MOUSE_PITCH_RANGE = 1.0f * PI; | |
| 50 | −static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI; | |
| 51 | −static const glm::vec2 MOUSE_RANGE(MOUSE_YAW_RANGE, MOUSE_PITCH_RANGE); | |
| 52 | − | |
| 53 | −// Return a point's cartesian coordinates on a sphere from pitch and yaw | |
| 54 | −glm::vec3 getPoint(float yaw, float pitch) { | |
| 55 | − return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)), | |
| 56 | − glm::sin(-pitch), | |
| 57 | − glm::cos(-pitch) * (-glm::cos(yaw))); | |
| 47 | +// TODO move somewhere useful | |
| 48 | +static void fboViewport(QOpenGLFramebufferObject* fbo) { | |
| 49 | + auto size = fbo->size(); | |
| 50 | + glViewport(0, 0, size.width(), size.height()); | |
| 58 | 51 | } |
| 59 | 52 | |
| 60 | −//Checks if the given ray intersects the sphere at the origin. result will store a multiplier that should | |
| 61 | −//be multiplied by dir and added to origin to get the location of the collision | |
| 62 | −bool raySphereIntersect(const glm::vec3 &dir, const glm::vec3 &origin, float r, float* result) | |
| 53 | +ApplicationOverlay::ApplicationOverlay() | |
| 63 | 54 | { |
| 64 | − //Source: http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection | |
| 65 | − | |
| 66 | − //Compute A, B and C coefficients | |
| 67 | − float a = glm::dot(dir, dir); | |
| 68 | − float b = 2 * glm::dot(dir, origin); | |
| 69 | − float c = glm::dot(origin, origin) - (r * r); | |
| 70 | − | |
| 71 | − //Find discriminant | |
| 72 | − float disc = b * b - 4 * a * c; | |
| 73 | − | |
| 74 | − // if discriminant is negative there are no real roots, so return | |
| 75 | − // false as ray misses sphere | |
| 76 | − if (disc < 0) { | |
| 77 | − return false; | |
| 78 | − } | |
| 79 | − | |
| 80 | − // compute q as described above | |
| 81 | − float distSqrt = sqrtf(disc); | |
| 82 | − float q; | |
| 83 | − if (b < 0) { | |
| 84 | − q = (-b - distSqrt) / 2.0; | |
| 85 | − } else { | |
| 86 | − q = (-b + distSqrt) / 2.0; | |
| 87 | − } | |
| 88 | − | |
| 89 | − // compute t0 and t1 | |
| 90 | − float t0 = q / a; | |
| 91 | − float t1 = c / q; | |
| 92 | − | |
| 93 | − // make sure t0 is smaller than t1 | |
| 94 | − if (t0 > t1) { | |
| 95 | − // if t0 is bigger than t1 swap them around | |
| 96 | − float temp = t0; | |
| 97 | − t0 = t1; | |
| 98 | − t1 = temp; | |
| 99 | − } | |
| 100 | − | |
| 101 | − // if t1 is less than zero, the object is in the ray's negative direction | |
| 102 | − // and consequently the ray misses the sphere | |
| 103 | − if (t1 < 0) { | |
| 104 | − return false; | |
| 105 | − } | |
| 106 | − | |
| 107 | − // if t0 is less than zero, the intersection point is at t1 | |
| 108 | − if (t0 < 0) { | |
| 109 | − *result = t1; | |
| 110 | − return true; | |
| 111 | − } else { // else the intersection point is at t0 | |
| 112 | − *result = t0; | |
| 113 | − return true; | |
| 114 | − } | |
| 115 | −} | |
| 116 | − | |
| 117 | −void ApplicationOverlay::renderReticle(glm::quat orientation, float alpha) { | |
| 118 | − glPushMatrix(); { | |
| 119 | − glm::vec3 axis = glm::axis(orientation); | |
| 120 | − glRotatef(glm::degrees(glm::angle(orientation)), axis.x, axis.y, axis.z); | |
| 121 | − glm::vec3 topLeft = getPoint(reticleSize / 2.0f, -reticleSize / 2.0f); | |
| 122 | − glm::vec3 topRight = getPoint(-reticleSize / 2.0f, -reticleSize / 2.0f); | |
| 123 | − glm::vec3 bottomLeft = getPoint(reticleSize / 2.0f, reticleSize / 2.0f); | |
| 124 | − glm::vec3 bottomRight = getPoint(-reticleSize / 2.0f, reticleSize / 2.0f); | |
| 125 | − | |
| 126 | − // TODO: this version of renderQuad() needs to take a color | |
| 127 | − glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], alpha }; | |
| 128 | − | |
| 129 | − | |
| 130 | − | |
| 131 | − DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomLeft, bottomRight, topRight, | |
| 132 | − glm::vec2(0.0f, 0.0f), glm::vec2(1.0f, 0.0f), | |
| 133 | − glm::vec2(1.0f, 1.0f), glm::vec2(0.0f, 1.0f), | |
| 134 | − reticleColor, _reticleQuad); | |
| 135 | − } glPopMatrix(); | |
| 136 | −} | |
| 137 | − | |
| 138 | −ApplicationOverlay::ApplicationOverlay() : | |
| 139 | − _textureFov(glm::radians(DEFAULT_HMD_UI_ANGULAR_SIZE)), | |
| 140 | − _textureAspectRatio(1.0f), | |
| 141 | − _lastMouseMove(0), | |
| 142 | − _magnifier(true), | |
| 143 | − _alpha(1.0f), | |
| 144 | − _oculusUIRadius(1.0f), | |
| 145 | − _trailingAudioLoudness(0.0f), | |
| 146 | − _previousBorderWidth(-1), | |
| 147 | − _previousBorderHeight(-1), | |
| 148 | − _previousMagnifierBottomLeft(), | |
| 149 | − _previousMagnifierBottomRight(), | |
| 150 | − _previousMagnifierTopLeft(), | |
| 151 | − _previousMagnifierTopRight() | |
| 152 | −{ | |
| 153 | − memset(_reticleActive, 0, sizeof(_reticleActive)); | |
| 154 | − memset(_magActive, 0, sizeof(_reticleActive)); | |
| 155 | − memset(_magSizeMult, 0, sizeof(_magSizeMult)); | |
| 156 | − | |
| 157 | 55 | auto geometryCache = DependencyManager::get<GeometryCache>(); |
| 158 | − | |
| 159 | − _reticleQuad = geometryCache->allocateID(); | |
| 160 | − _magnifierQuad = geometryCache->allocateID(); | |
| 161 | − _audioRedQuad = geometryCache->allocateID(); | |
| 162 | − _audioGreenQuad = geometryCache->allocateID(); | |
| 163 | − _audioBlueQuad = geometryCache->allocateID(); | |
| 164 | 56 | _domainStatusBorder = geometryCache->allocateID(); |
| 165 | 57 | _magnifierBorder = geometryCache->allocateID(); |
| 166 | − | |
| 58 | + | |
| 167 | 59 | // Once we move UI rendering and screen rendering to different |
| 168 | 60 | // threads, we need to use a sync object to deteremine when |
| 169 | − // the current UI texture is no longer being read from, and only | |
| 61 | + // the current UI texture is no longer being read from, and only | |
| 170 | 62 | // then release it back to the UI for re-use |
| 171 | 63 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); |
| 172 | 64 | connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [&](GLuint textureId) { |
| 173 | 65 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); |
| 174 | 66 | offscreenUi->lockTexture(textureId); |
| 175 | 67 | assert(!glGetError()); |
| 176 | − std::swap(_newUiTexture, textureId); | |
| 68 | + std::swap(_uiTexture, textureId); | |
| 177 | 69 | if (textureId) { |
| 178 | 70 | offscreenUi->releaseTexture(textureId); |
| 179 | 71 | } |
| @@ -185,846 +77,81 @@ ApplicationOverlay::~ApplicationOverlay() { · 5 unmodified lines | ||
| 185 | 77 | |
| 186 | 78 | // Renders the overlays either to a texture or to the screen |
| 187 | 79 | void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { |
| 80 | + CHECK_GL_ERROR(); | |
| 188 | 81 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()"); |
| 189 | − Overlays& overlays = qApp->getOverlays(); | |
| 190 | − | |
| 191 | − _textureFov = glm::radians(_hmdUIAngularSize); | |
| 192 | − glm::vec2 size = qApp->getCanvasSize(); | |
| 193 | − _textureAspectRatio = aspect(size); | |
| 194 | 82 | |
| 195 | − //Handle fading and deactivation/activation of UI | |
| 196 | − | |
| 197 | − // Render 2D overlay | |
| 198 | − glMatrixMode(GL_PROJECTION); | |
| 199 | − glDisable(GL_DEPTH_TEST); | |
| 200 | − glDisable(GL_LIGHTING); | |
| 201 | − glEnable(GL_BLEND); | |
| 202 | − glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 203 | − _overlays.buildFramebufferObject(); | |
| 204 | − _overlays.bind(); | |
| 205 | − glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
| 206 | − glViewport(0, 0, size.x, size.y); | |
| 83 | + // TODO move to Application::idle()? | |
| 84 | + Stats::getInstance()->updateStats(); | |
| 85 | + AvatarInputs::getInstance()->update(); | |
| 207 | 86 | |
| 208 | − glPushMatrix(); { | |
| 209 | − const float NEAR_CLIP = -10000; | |
| 210 | − const float FAR_CLIP = 10000; | |
| 211 | − glLoadIdentity(); | |
| 212 | − glOrtho(0, size.x, size.y, 0, NEAR_CLIP, FAR_CLIP); | |
| 87 | + buildFramebufferObject(); | |
| 213 | 88 | |
| 214 | − glMatrixMode(GL_MODELVIEW); | |
| 215 | − | |
| 216 | − renderAudioMeter(); | |
| 217 | − renderCameraToggle(); | |
| 218 | − | |
| 219 | − renderStatsAndLogs(); | |
| 220 | − | |
| 221 | − // give external parties a change to hook in | |
| 222 | − emit qApp->renderingOverlay(); | |
| 223 | − | |
| 224 | − overlays.renderHUD(renderArgs); | |
| 225 | − | |
| 226 | − renderPointers(); | |
| 227 | − | |
| 228 | − renderDomainConnectionStatusBorder(); | |
| 229 | − | |
| 230 | − glMatrixMode(GL_PROJECTION); | |
| 231 | − } glPopMatrix(); | |
| 232 | − | |
| 233 | − glMatrixMode(GL_MODELVIEW); | |
| 234 | − glEnable(GL_DEPTH_TEST); | |
| 235 | − glEnable(GL_LIGHTING); | |
| 236 | − glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 237 | − | |
| 238 | − _overlays.release(); | |
| 239 | −} | |
| 89 | + // Execute the batch into our framebuffer | |
| 90 | + _overlayFramebuffer->bind(); | |
| 91 | + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
| 92 | + fboViewport(_overlayFramebuffer); | |
| 240 | 93 | |
| 241 | −// A quick and dirty solution for compositing the old overlay | |
| 242 | −// texture with the new one | |
| 243 | −template <typename F> | |
| 244 | −void with_each_texture(GLuint firstPassTexture, GLuint secondPassTexture, F f) { | |
| 245 | − glEnable(GL_TEXTURE_2D); | |
| 246 | − glActiveTexture(GL_TEXTURE0); | |
| 247 | − if (firstPassTexture) { | |
| 248 | − glBindTexture(GL_TEXTURE_2D, firstPassTexture); | |
| 249 | − f(); | |
| 250 | − } | |
| 251 | − if (secondPassTexture) { | |
| 252 | − glBindTexture(GL_TEXTURE_2D, secondPassTexture); | |
| 253 | − f(); | |
| 254 | − } | |
| 255 | − glBindTexture(GL_TEXTURE_2D, 0); | |
| 256 | − glDisable(GL_TEXTURE_2D); | |
| 94 | + // Now render the overlay components together into a single texture | |
| 95 | + renderOverlays(renderArgs); | |
| 96 | + renderStatsAndLogs(renderArgs); | |
| 97 | + renderDomainConnectionStatusBorder(renderArgs); | |
| 98 | + renderQmlUi(renderArgs); | |
| 99 | + _overlayFramebuffer->release(); | |
| 100 | + CHECK_GL_ERROR(); | |
| 257 | 101 | } |
| 258 | 102 | |
| 259 | −// Draws the FBO texture for the screen | |
| 260 | −void ApplicationOverlay::displayOverlayTexture() { | |
| 261 | − if (_alpha == 0.0f) { | |
| 262 | − return; | |
| 103 | +void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) { | |
| 104 | + if (_uiTexture) { | |
| 105 | + gpu::Batch batch; | |
| 106 | + auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 107 | + geometryCache->useSimpleDrawPipeline(batch); | |
| 108 | + batch.setProjectionTransform(mat4()); | |
| 109 | + batch.setModelTransform(mat4()); | |
| 110 | + batch._glBindTexture(GL_TEXTURE_2D, _uiTexture); | |
| 111 | + geometryCache->renderUnitQuad(batch, glm::vec4(1)); | |
| 112 | + renderArgs->_context->syncCache(); | |
| 113 | + renderArgs->_context->render(batch); | |
| 263 | 114 | } |
| 264 | − glMatrixMode(GL_PROJECTION); | |
| 265 | − glPushMatrix(); { | |
| 266 | − glLoadIdentity(); | |
| 267 | − glDisable(GL_DEPTH_TEST); | |
| 268 | − glDisable(GL_LIGHTING); | |
| 269 | − glEnable(GL_BLEND); | |
| 270 | − glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 271 | − glViewport(0, 0, qApp->getDeviceSize().width(), qApp->getDeviceSize().height()); | |
| 272 | − | |
| 273 | − static const glm::vec2 topLeft(-1, 1); | |
| 274 | − static const glm::vec2 bottomRight(1, -1); | |
| 275 | − static const glm::vec2 texCoordTopLeft(0.0f, 1.0f); | |
| 276 | − static const glm::vec2 texCoordBottomRight(1.0f, 0.0f); | |
| 277 | − with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { | |
| 278 | − DependencyManager::get<GeometryCache>()->renderQuad( | |
| 279 | − topLeft, bottomRight, | |
| 280 | − texCoordTopLeft, texCoordBottomRight, | |
| 281 | − glm::vec4(1.0f, 1.0f, 1.0f, _alpha)); | |
| 282 | − }); | |
| 283 | − | |
| 284 | − if (!_crosshairTexture) { | |
| 285 | − _crosshairTexture = DependencyManager::get<TextureCache>()-> | |
| 286 | − getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png"); | |
| 287 | − } | |
| 288 | − | |
| 289 | − //draw the mouse pointer | |
| 290 | − glm::vec2 canvasSize = qApp->getCanvasSize(); | |
| 291 | − glm::vec2 mouseSize = 32.0f / canvasSize; | |
| 292 | − auto mouseTopLeft = topLeft * mouseSize; | |
| 293 | − auto mouseBottomRight = bottomRight * mouseSize; | |
| 294 | − vec2 mousePosition = vec2(qApp->getMouseX(), qApp->getMouseY()); | |
| 295 | − mousePosition /= canvasSize; | |
| 296 | − mousePosition *= 2.0f; | |
| 297 | − mousePosition -= 1.0f; | |
| 298 | − mousePosition.y *= -1.0f; | |
| 299 | − | |
| 300 | − glEnable(GL_TEXTURE_2D); | |
| 301 | − glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 302 | − glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture)); | |
| 303 | − glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f }; | |
| 304 | − DependencyManager::get<GeometryCache>()->renderQuad( | |
| 305 | − mouseTopLeft + mousePosition, mouseBottomRight + mousePosition, | |
| 306 | − texCoordTopLeft, texCoordBottomRight, | |
| 307 | − reticleColor); | |
| 308 | − glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 309 | − glDisable(GL_TEXTURE_2D); | |
| 310 | − } glPopMatrix(); | |
| 311 | 115 | } |
| 312 | 116 | |
| 313 | −// Draws the FBO texture for Oculus rift. | |
| 314 | −void ApplicationOverlay::displayOverlayTextureHmd(Camera& whichCamera) { | |
| 315 | − if (_alpha == 0.0f) { | |
| 316 | − return; | |
| 317 | − } | |
| 318 | − | |
| 319 | − glEnable(GL_BLEND); | |
| 320 | − glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 321 | − glEnable(GL_DEPTH_TEST); | |
| 322 | − glDepthMask(GL_TRUE); | |
| 323 | − glDisable(GL_LIGHTING); | |
| 324 | − glEnable(GL_ALPHA_TEST); | |
| 325 | − glAlphaFunc(GL_GREATER, 0.01f); | |
| 326 | − | |
| 117 | +void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) { | |
| 118 | + glm::vec2 size = qApp->getCanvasSize(); | |
| 327 | 119 | |
| 328 | − //Update and draw the magnifiers | |
| 329 | − MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 330 | − const glm::quat& orientation = myAvatar->getOrientation(); | |
| 331 | − // Always display the HMD overlay relative to the camera position but | |
| 332 | − // remove the HMD pose offset. This results in an overlay that sticks with you | |
| 333 | − // even in third person mode, but isn't drawn at a fixed distance. | |
| 334 | − glm::vec3 position = whichCamera.getPosition(); | |
| 335 | − position -= qApp->getCamera()->getHmdPosition(); | |
| 336 | − const float scale = myAvatar->getScale() * _oculusUIRadius; | |
| 337 | − | |
| 338 | −// glm::vec3 eyeOffset = setEyeOffsetPosition; | |
| 120 | + mat4 legacyProjection = glm::ortho<float>(0, size.x, size.y, 0, ORTHO_NEAR_CLIP, ORTHO_FAR_CLIP); | |
| 121 | + glMatrixMode(GL_PROJECTION); | |
| 122 | + glPushMatrix(); | |
| 123 | + glLoadMatrixf(glm::value_ptr(legacyProjection)); | |
| 339 | 124 | glMatrixMode(GL_MODELVIEW); |
| 340 | − glPushMatrix(); { | |
| 341 | − glTranslatef(position.x, position.y, position.z); | |
| 342 | − glm::mat4 rotation = glm::toMat4(orientation); | |
| 343 | − glMultMatrixf(&rotation[0][0]); | |
| 344 | − glScalef(scale, scale, scale); | |
| 345 | − for (int i = 0; i < NUMBER_OF_RETICLES; i++) { | |
| 346 | − | |
| 347 | − if (_magActive[i]) { | |
| 348 | − _magSizeMult[i] += MAG_SPEED; | |
| 349 | − if (_magSizeMult[i] > 1.0f) { | |
| 350 | − _magSizeMult[i] = 1.0f; | |
| 351 | − } | |
| 352 | − } else { | |
| 353 | − _magSizeMult[i] -= MAG_SPEED; | |
| 354 | − if (_magSizeMult[i] < 0.0f) { | |
| 355 | − _magSizeMult[i] = 0.0f; | |
| 356 | − } | |
| 357 | − } | |
| 358 | − | |
| 359 | − if (_magSizeMult[i] > 0.0f) { | |
| 360 | − //Render magnifier, but dont show border for mouse magnifier | |
| 361 | − glm::vec2 projection = screenToOverlay(glm::vec2(_reticlePosition[MOUSE].x(), | |
| 362 | − _reticlePosition[MOUSE].y())); | |
| 363 | − with_each_texture(_overlays.getTexture(), 0, [&] { | |
| 364 | − renderMagnifier(projection, _magSizeMult[i], i != MOUSE); | |
| 365 | − }); | |
| 366 | − } | |
| 367 | − } | |
| 368 | − | |
| 369 | − glDepthMask(GL_FALSE); | |
| 370 | − glDisable(GL_ALPHA_TEST); | |
| 371 | − | |
| 372 | − static float textureFOV = 0.0f, textureAspectRatio = 1.0f; | |
| 373 | − if (textureFOV != _textureFov || | |
| 374 | − textureAspectRatio != _textureAspectRatio) { | |
| 375 | − textureFOV = _textureFov; | |
| 376 | − textureAspectRatio = _textureAspectRatio; | |
| 377 | − | |
| 378 | − _overlays.buildVBO(_textureFov, _textureAspectRatio, 80, 80); | |
| 379 | − } | |
| 380 | 125 | |
| 381 | − with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { | |
| 382 | − _overlays.render(); | |
| 383 | − }); | |
| 384 | − | |
| 385 | − if (!Application::getInstance()->isMouseHidden()) { | |
| 386 | − renderPointersOculus(); | |
| 387 | − } | |
| 388 | − glDepthMask(GL_TRUE); | |
| 389 | − glDisable(GL_TEXTURE_2D); | |
| 390 | − | |
| 391 | − glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 392 | − glEnable(GL_LIGHTING); | |
| 393 | − } glPopMatrix(); | |
| 394 | −} | |
| 395 | − | |
| 396 | −// Draws the FBO texture for 3DTV. | |
| 397 | −void ApplicationOverlay::displayOverlayTextureStereo(Camera& whichCamera, float aspectRatio, float fov) { | |
| 398 | − if (_alpha == 0.0f) { | |
| 399 | − return; | |
| 400 | − } | |
| 401 | − | |
| 402 | − MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 403 | − const glm::vec3& viewMatrixTranslation = qApp->getViewMatrixTranslation(); | |
| 404 | − | |
| 405 | − glEnable(GL_BLEND); | |
| 406 | − glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 407 | − glEnable(GL_DEPTH_TEST); | |
| 408 | − glDisable(GL_LIGHTING); | |
| 409 | − | |
| 410 | − glMatrixMode(GL_MODELVIEW); | |
| 411 | − | |
| 412 | − glPushMatrix(); | |
| 413 | − glLoadIdentity(); | |
| 414 | − // Transform to world space | |
| 415 | − glm::quat rotation = whichCamera.getRotation(); | |
| 416 | − glm::vec3 axis2 = glm::axis(rotation); | |
| 417 | − glRotatef(-glm::degrees(glm::angle(rotation)), axis2.x, axis2.y, axis2.z); | |
| 418 | − glTranslatef(viewMatrixTranslation.x, viewMatrixTranslation.y, viewMatrixTranslation.z); | |
| 419 | − | |
| 420 | − // Translate to the front of the camera | |
| 421 | − glm::vec3 pos = whichCamera.getPosition(); | |
| 422 | − glm::quat rot = myAvatar->getOrientation(); | |
| 423 | − glm::vec3 axis = glm::axis(rot); | |
| 424 | − | |
| 425 | − glTranslatef(pos.x, pos.y, pos.z); | |
| 426 | − glRotatef(glm::degrees(glm::angle(rot)), axis.x, axis.y, axis.z); | |
| 427 | − | |
| 428 | − glm::vec4 overlayColor = {1.0f, 1.0f, 1.0f, _alpha}; | |
| 429 | − | |
| 430 | − //Render | |
| 431 | − const GLfloat distance = 1.0f; | |
| 432 | − | |
| 433 | − const GLfloat halfQuadHeight = distance * tan(fov); | |
| 434 | − const GLfloat halfQuadWidth = halfQuadHeight * aspectRatio; | |
| 435 | − const GLfloat quadWidth = halfQuadWidth * 2.0f; | |
| 436 | − const GLfloat quadHeight = halfQuadHeight * 2.0f; | |
| 437 | − | |
| 438 | − GLfloat x = -halfQuadWidth; | |
| 439 | − GLfloat y = -halfQuadHeight; | |
| 440 | 126 | glDisable(GL_DEPTH_TEST); |
| 441 | − | |
| 442 | − with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { | |
| 443 | − DependencyManager::get<GeometryCache>()->renderQuad(glm::vec3(x, y + quadHeight, -distance), | |
| 444 | − glm::vec3(x + quadWidth, y + quadHeight, -distance), | |
| 445 | − glm::vec3(x + quadWidth, y, -distance), | |
| 446 | − glm::vec3(x, y, -distance), | |
| 447 | − glm::vec2(0.0f, 1.0f), glm::vec2(1.0f, 1.0f), | |
| 448 | − glm::vec2(1.0f, 0.0f), glm::vec2(0.0f, 0.0f), | |
| 449 | − overlayColor); | |
| 450 | − }); | |
| 451 | − | |
| 452 | − if (!_crosshairTexture) { | |
| 453 | − _crosshairTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + | |
| 454 | − "images/sixense-reticle.png"); | |
| 455 | − } | |
| 456 | − | |
| 457 | − //draw the mouse pointer | |
| 127 | + glDisable(GL_LIGHTING); | |
| 458 | 128 | glEnable(GL_BLEND); |
| 459 | 129 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
| 460 | − glEnable(GL_TEXTURE_2D); | |
| 461 | − glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture)); | |
| 462 | − glm::vec2 canvasSize = qApp->getCanvasSize(); | |
| 463 | − const float reticleSize = 40.0f / canvasSize.x * quadWidth; | |
| 464 | − x -= reticleSize / 2.0f; | |
| 465 | − y += reticleSize / 2.0f; | |
| 466 | − const float mouseX = (qApp->getMouseX() / (float)canvasSize.x) * quadWidth; | |
| 467 | − const float mouseY = (1.0 - (qApp->getMouseY() / (float)canvasSize.y)) * quadHeight; | |
| 468 | − | |
| 469 | − glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f }; | |
| 470 | 130 | |
| 471 | − DependencyManager::get<GeometryCache>()->renderQuad(glm::vec3(x + mouseX, y + mouseY, -distance), | |
| 472 | − glm::vec3(x + mouseX + reticleSize, y + mouseY, -distance), | |
| 473 | − glm::vec3(x + mouseX + reticleSize, y + mouseY - reticleSize, -distance), | |
| 474 | − glm::vec3(x + mouseX, y + mouseY - reticleSize, -distance), | |
| 475 | − glm::vec2(0.0f, 0.0f), glm::vec2(1.0f, 0.0f), | |
| 476 | − glm::vec2(1.0f, 1.0f), glm::vec2(0.0f, 1.0f), | |
| 477 | − reticleColor, _reticleQuad); | |
| 131 | + // give external parties a change to hook in | |
| 132 | + emit qApp->renderingOverlay(); | |
| 133 | + qApp->getOverlays().renderHUD(renderArgs); | |
| 478 | 134 | |
| 479 | − glEnable(GL_DEPTH_TEST); | |
| 480 | − | |
| 135 | + glMatrixMode(GL_PROJECTION); | |
| 481 | 136 | glPopMatrix(); |
| 482 | − | |
| 483 | − glDepthMask(GL_TRUE); | |
| 484 | − glBindTexture(GL_TEXTURE_2D, 0); | |
| 485 | − glDisable(GL_TEXTURE_2D); | |
| 486 | − | |
| 487 | − glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 488 | − glEnable(GL_LIGHTING); | |
| 489 | −} | |
| 490 | − | |
| 491 | −void ApplicationOverlay::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const { | |
| 492 | − cursorPos *= qApp->getCanvasSize(); | |
| 493 | − const glm::vec2 projection = screenToSpherical(cursorPos); | |
| 494 | − // The overlay space orientation of the mouse coordinates | |
| 495 | − const glm::quat orientation(glm::vec3(-projection.y, projection.x, 0.0f)); | |
| 496 | − // FIXME We now have the direction of the ray FROM THE DEFAULT HEAD POSE. | |
| 497 | − // Now we need to account for the actual camera position relative to the overlay | |
| 498 | − glm::vec3 overlaySpaceDirection = glm::normalize(orientation * IDENTITY_FRONT); | |
| 499 | − | |
| 500 | − | |
| 501 | − const glm::vec3& hmdPosition = qApp->getCamera()->getHmdPosition(); | |
| 502 | − const glm::quat& hmdOrientation = qApp->getCamera()->getHmdRotation(); | |
| 503 | − | |
| 504 | − // We need the RAW camera orientation and position, because this is what the overlay is | |
| 505 | − // rendered relative to | |
| 506 | − const glm::vec3 overlayPosition = qApp->getCamera()->getPosition() - hmdPosition; | |
| 507 | − const glm::quat overlayOrientation = qApp->getCamera()->getRotation() * glm::inverse(hmdOrientation); | |
| 508 | − | |
| 509 | − // Intersection UI overlay space | |
| 510 | − glm::vec3 worldSpaceDirection = overlayOrientation * overlaySpaceDirection; | |
| 511 | − glm::vec3 intersectionWithUi = glm::normalize(worldSpaceDirection) * _oculusUIRadius; | |
| 512 | − intersectionWithUi += overlayPosition; | |
| 513 | − | |
| 514 | − // Intersection in world space | |
| 515 | − origin = overlayPosition + hmdPosition; | |
| 516 | − direction = glm::normalize(intersectionWithUi - origin); | |
| 517 | −} | |
| 518 | − | |
| 519 | −glm::vec2 getPolarCoordinates(const PalmData& palm) { | |
| 520 | − MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 521 | − auto avatarOrientation = myAvatar->getOrientation(); | |
| 522 | − auto eyePos = myAvatar->getDefaultEyePosition(); | |
| 523 | − glm::vec3 tip = myAvatar->getLaserPointerTipPosition(&palm); | |
| 524 | − // Direction of the tip relative to the eye | |
| 525 | − glm::vec3 tipDirection = tip - eyePos; | |
| 526 | − // orient into avatar space | |
| 527 | − tipDirection = glm::inverse(avatarOrientation) * tipDirection; | |
| 528 | − // Normalize for trig functions | |
| 529 | − tipDirection = glm::normalize(tipDirection); | |
| 530 | − // Convert to polar coordinates | |
| 531 | − glm::vec2 polar(glm::atan(tipDirection.x, -tipDirection.z), glm::asin(tipDirection.y)); | |
| 532 | − return polar; | |
| 533 | −} | |
| 534 | − | |
| 535 | −//Caculate the click location using one of the sixense controllers. Scale is not applied | |
| 536 | −QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const { | |
| 537 | − QPoint rv; | |
| 538 | − auto canvasSize = qApp->getCanvasSize(); | |
| 539 | − if (qApp->isHMDMode()) { | |
| 540 | − glm::vec2 polar = getPolarCoordinates(*palm); | |
| 541 | − glm::vec2 point = sphericalToScreen(-polar); | |
| 542 | − rv.rx() = point.x; | |
| 543 | − rv.ry() = point.y; | |
| 544 | − } else { | |
| 545 | − MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 546 | − glm::dmat4 projection; | |
| 547 | − qApp->getProjectionMatrix(&projection); | |
| 548 | − glm::quat invOrientation = glm::inverse(myAvatar->getOrientation()); | |
| 549 | − glm::vec3 eyePos = myAvatar->getDefaultEyePosition(); | |
| 550 | − glm::vec3 tip = myAvatar->getLaserPointerTipPosition(palm); | |
| 551 | − glm::vec3 tipPos = invOrientation * (tip - eyePos); | |
| 552 | − | |
| 553 | − glm::vec4 clipSpacePos = glm::vec4(projection * glm::dvec4(tipPos, 1.0)); | |
| 554 | − glm::vec3 ndcSpacePos; | |
| 555 | − if (clipSpacePos.w != 0) { | |
| 556 | − ndcSpacePos = glm::vec3(clipSpacePos) / clipSpacePos.w; | |
| 557 | − } | |
| 558 | − | |
| 559 | − rv.setX(((ndcSpacePos.x + 1.0) / 2.0) * canvasSize.x); | |
| 560 | − rv.setY((1.0 - ((ndcSpacePos.y + 1.0) / 2.0)) * canvasSize.y); | |
| 561 | − } | |
| 562 | − return rv; | |
| 563 | −} | |
| 564 | − | |
| 565 | −//Finds the collision point of a world space ray | |
| 566 | −bool ApplicationOverlay::calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const { | |
| 567 | − MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 568 | − | |
| 569 | − glm::quat inverseOrientation = glm::inverse(myAvatar->getOrientation()); | |
| 570 | − | |
| 571 | − glm::vec3 relativePosition = inverseOrientation * (position - myAvatar->getDefaultEyePosition()); | |
| 572 | − glm::vec3 relativeDirection = glm::normalize(inverseOrientation * direction); | |
| 573 | − | |
| 574 | − float t; | |
| 575 | − if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getScale(), &t)){ | |
| 576 | − result = position + direction * t; | |
| 577 | − return true; | |
| 578 | − } | |
| 579 | − | |
| 580 | − return false; | |
| 581 | −} | |
| 582 | − | |
| 583 | −//Renders optional pointers | |
| 584 | −void ApplicationOverlay::renderPointers() { | |
| 585 | − //lazily load crosshair texture | |
| 586 | − if (_crosshairTexture == 0) { | |
| 587 | − _crosshairTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png"); | |
| 588 | − } | |
| 589 | − glEnable(GL_TEXTURE_2D); | |
| 590 | − glEnable(GL_BLEND); | |
| 591 | − glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 592 | − | |
| 593 | − //glActiveTexture(GL_TEXTURE0); | |
| 594 | − //bindCursorTexture(); | |
| 595 | − | |
| 596 | − if (qApp->isHMDMode() && !qApp->getLastMouseMoveWasSimulated() && !qApp->isMouseHidden()) { | |
| 597 | − //If we are in oculus, render reticle later | |
| 598 | − if (_lastMouseMove == 0) { | |
| 599 | − _lastMouseMove = usecTimestampNow(); | |
| 600 | − } | |
| 601 | − QPoint position = QPoint(qApp->getTrueMouseX(), qApp->getTrueMouseY()); | |
| 602 | − | |
| 603 | − static const int MAX_IDLE_TIME = 3; | |
| 604 | − if (_reticlePosition[MOUSE] != position) { | |
| 605 | − _lastMouseMove = usecTimestampNow(); | |
| 606 | − } else if (usecTimestampNow() - _lastMouseMove > MAX_IDLE_TIME * USECS_PER_SECOND) { | |
| 607 | − //float pitch = 0.0f, yaw = 0.0f, roll = 0.0f; // radians | |
| 608 | − //OculusManager::getEulerAngles(yaw, pitch, roll); | |
| 609 | − glm::quat orientation = qApp->getHeadOrientation(); // (glm::vec3(pitch, yaw, roll)); | |
| 610 | − glm::vec3 result; | |
| 611 | − | |
| 612 | − MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 613 | − if (calculateRayUICollisionPoint(myAvatar->getEyePosition(), | |
| 614 | − myAvatar->getOrientation() * orientation * IDENTITY_FRONT, | |
| 615 | − result)) { | |
| 616 | − glm::vec3 lookAtDirection = glm::inverse(myAvatar->getOrientation()) * (result - myAvatar->getDefaultEyePosition()); | |
| 617 | − glm::vec2 spericalPos = directionToSpherical(glm::normalize(lookAtDirection)); | |
| 618 | − glm::vec2 screenPos = sphericalToScreen(spericalPos); | |
| 619 | − position = QPoint(screenPos.x, screenPos.y); | |
| 620 | − // FIXME | |
| 621 | − //glCanvas->cursor().setPos(glCanvas->mapToGlobal(position)); | |
| 622 | − } else { | |
| 623 | − qDebug() << "No collision point"; | |
| 624 | − } | |
| 625 | − } | |
| 626 | − | |
| 627 | − _reticlePosition[MOUSE] = position; | |
| 628 | − _reticleActive[MOUSE] = true; | |
| 629 | − _magActive[MOUSE] = _magnifier; | |
| 630 | − _reticleActive[LEFT_CONTROLLER] = false; | |
| 631 | − _reticleActive[RIGHT_CONTROLLER] = false; | |
| 632 | − } else if (qApp->getLastMouseMoveWasSimulated() && Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) { | |
| 633 | − _lastMouseMove = 0; | |
| 634 | − //only render controller pointer if we aren't already rendering a mouse pointer | |
| 635 | − _reticleActive[MOUSE] = false; | |
| 636 | − _magActive[MOUSE] = false; | |
| 637 | − renderControllerPointers(); | |
| 638 | − } | |
| 639 | − //glBindTexture(GL_TEXTURE_2D, 0); | |
| 640 | − //glDisable(GL_TEXTURE_2D); | |
| 641 | −} | |
| 642 | − | |
| 643 | −void ApplicationOverlay::renderControllerPointers() { | |
| 644 | − MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 645 | − | |
| 646 | − //Static variables used for storing controller state | |
| 647 | − static quint64 pressedTime[NUMBER_OF_RETICLES] = { 0ULL, 0ULL, 0ULL }; | |
| 648 | − static bool isPressed[NUMBER_OF_RETICLES] = { false, false, false }; | |
| 649 | − static bool stateWhenPressed[NUMBER_OF_RETICLES] = { false, false, false }; | |
| 650 | − | |
| 651 | − const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData(); | |
| 652 | − | |
| 653 | − for (unsigned int palmIndex = 2; palmIndex < 4; palmIndex++) { | |
| 654 | − const int index = palmIndex - 1; | |
| 655 | − | |
| 656 | − const PalmData* palmData = NULL; | |
| 657 | − | |
| 658 | − if (palmIndex >= handData->getPalms().size()) { | |
| 659 | − return; | |
| 660 | − } | |
| 661 | − | |
| 662 | − if (handData->getPalms()[palmIndex].isActive()) { | |
| 663 | − palmData = &handData->getPalms()[palmIndex]; | |
| 664 | − } else { | |
| 665 | − continue; | |
| 666 | − } | |
| 667 | − | |
| 668 | − int controllerButtons = palmData->getControllerButtons(); | |
| 669 | − | |
| 670 | − //Check for if we should toggle or drag the magnification window | |
| 671 | − if (controllerButtons & BUTTON_3) { | |
| 672 | − if (isPressed[index] == false) { | |
| 673 | − //We are now dragging the window | |
| 674 | − isPressed[index] = true; | |
| 675 | − //set the pressed time in us | |
| 676 | − pressedTime[index] = usecTimestampNow(); | |
| 677 | − stateWhenPressed[index] = _magActive[index]; | |
| 678 | − } | |
| 679 | − } else if (isPressed[index]) { | |
| 680 | − isPressed[index] = false; | |
| 681 | − //If the button was only pressed for < 250 ms | |
| 682 | − //then disable it. | |
| 683 | − | |
| 684 | − const int MAX_BUTTON_PRESS_TIME = 250 * MSECS_TO_USECS; | |
| 685 | − if (usecTimestampNow() < pressedTime[index] + MAX_BUTTON_PRESS_TIME) { | |
| 686 | − _magActive[index] = !stateWhenPressed[index]; | |
| 687 | − } | |
| 688 | − } | |
| 689 | − | |
| 690 | − //if we have the oculus, we should make the cursor smaller since it will be | |
| 691 | − //magnified | |
| 692 | − if (qApp->isHMDMode()) { | |
| 693 | − | |
| 694 | − QPoint point = getPalmClickLocation(palmData); | |
| 695 | − | |
| 696 | − _reticlePosition[index] = point; | |
| 697 | − | |
| 698 | − //When button 2 is pressed we drag the mag window | |
| 699 | − if (isPressed[index]) { | |
| 700 | − _magActive[index] = true; | |
| 701 | − } | |
| 702 | − | |
| 703 | − // If oculus is enabled, we draw the crosshairs later | |
| 704 | − continue; | |
| 705 | − } | |
| 706 | − | |
| 707 | − auto canvasSize = qApp->getCanvasSize(); | |
| 708 | − int mouseX, mouseY; | |
| 709 | − if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) { | |
| 710 | − QPoint res = getPalmClickLocation(palmData); | |
| 711 | − mouseX = res.x(); | |
| 712 | − mouseY = res.y(); | |
| 713 | − } else { | |
| 714 | − // Get directon relative to avatar orientation | |
| 715 | − glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * palmData->getFingerDirection(); | |
| 716 | − | |
| 717 | − // Get the angles, scaled between (-0.5,0.5) | |
| 718 | − float xAngle = (atan2(direction.z, direction.x) + M_PI_2); | |
| 719 | − float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2)); | |
| 720 | − | |
| 721 | − // Get the pixel range over which the xAngle and yAngle are scaled | |
| 722 | − float cursorRange = canvasSize.x * SixenseManager::getInstance().getCursorPixelRangeMult(); | |
| 723 | − | |
| 724 | − mouseX = (canvasSize.x / 2.0f + cursorRange * xAngle); | |
| 725 | − mouseY = (canvasSize.y / 2.0f + cursorRange * yAngle); | |
| 726 | − } | |
| 727 | − | |
| 728 | − //If the cursor is out of the screen then don't render it | |
| 729 | − if (mouseX < 0 || mouseX >= (int)canvasSize.x || mouseY < 0 || mouseY >= (int)canvasSize.y) { | |
| 730 | − _reticleActive[index] = false; | |
| 731 | − continue; | |
| 732 | − } | |
| 733 | − _reticleActive[index] = true; | |
| 734 | − | |
| 735 | − | |
| 736 | − const float reticleSize = 40.0f; | |
| 737 | − | |
| 738 | − mouseX -= reticleSize / 2.0f; | |
| 739 | − mouseY += reticleSize / 2.0f; | |
| 740 | − | |
| 741 | − | |
| 742 | − glm::vec2 topLeft(mouseX, mouseY); | |
| 743 | − glm::vec2 bottomRight(mouseX + reticleSize, mouseY - reticleSize); | |
| 744 | − glm::vec2 texCoordTopLeft(0.0f, 0.0f); | |
| 745 | − glm::vec2 texCoordBottomRight(1.0f, 1.0f); | |
| 746 | − | |
| 747 | − DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, | |
| 748 | − glm::vec4(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f)); | |
| 749 | − | |
| 750 | − } | |
| 751 | −} | |
| 752 | − | |
| 753 | −void ApplicationOverlay::renderPointersOculus() { | |
| 754 | − | |
| 755 | − glEnable(GL_BLEND); | |
| 756 | − glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 757 | − glEnable(GL_TEXTURE_2D); | |
| 758 | − | |
| 759 | − glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture)); | |
| 760 | − glDisable(GL_DEPTH_TEST); | |
| 761 | − | |
| 762 | 137 | glMatrixMode(GL_MODELVIEW); |
| 763 | − | |
| 764 | − //Controller Pointers | |
| 765 | − MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 766 | − for (int i = 0; i < (int)myAvatar->getHand()->getNumPalms(); i++) { | |
| 767 | − PalmData& palm = myAvatar->getHand()->getPalms()[i]; | |
| 768 | − if (palm.isActive()) { | |
| 769 | − glm::vec2 polar = getPolarCoordinates(palm); | |
| 770 | − // Convert to quaternion | |
| 771 | − glm::quat orientation = glm::quat(glm::vec3(polar.y, -polar.x, 0.0f)); | |
| 772 | − // Render reticle at location | |
| 773 | − renderReticle(orientation, _alpha); | |
| 774 | − } | |
| 775 | − } | |
| 776 | − | |
| 777 | − //Mouse Pointer | |
| 778 | − if (_reticleActive[MOUSE]) { | |
| 779 | − glm::vec2 projection = screenToSpherical(glm::vec2(_reticlePosition[MOUSE].x(), | |
| 780 | − _reticlePosition[MOUSE].y())); | |
| 781 | − glm::quat orientation(glm::vec3(-projection.y, projection.x, 0.0f)); | |
| 782 | − renderReticle(orientation, _alpha); | |
| 783 | − } | |
| 784 | 138 | |
| 785 | − glEnable(GL_DEPTH_TEST); | |
| 786 | − glDisable(GL_TEXTURE_2D); | |
| 787 | − glDisable(GL_BLEND); | |
| 139 | + renderArgs->_context->syncCache(); | |
| 140 | + fboViewport(_overlayFramebuffer); | |
| 788 | 141 | } |
| 789 | 142 | |
| 790 | −//Renders a small magnification of the currently bound texture at the coordinates | |
| 791 | −void ApplicationOverlay::renderMagnifier(glm::vec2 magPos, float sizeMult, bool showBorder) { | |
| 792 | − if (!_magnifier) { | |
| 793 | − return; | |
| 794 | − } | |
| 795 | − auto canvasSize = qApp->getCanvasSize(); | |
| 796 | − | |
| 797 | − const int widgetWidth = canvasSize.x; | |
| 798 | − const int widgetHeight = canvasSize.y; | |
| 799 | − | |
| 800 | − const float halfWidth = (MAGNIFY_WIDTH / _textureAspectRatio) * sizeMult / 2.0f; | |
| 801 | − const float halfHeight = MAGNIFY_HEIGHT * sizeMult / 2.0f; | |
| 802 | − // Magnification Texture Coordinates | |
| 803 | − const float magnifyULeft = (magPos.x - halfWidth) / (float)widgetWidth; | |
| 804 | − const float magnifyURight = (magPos.x + halfWidth) / (float)widgetWidth; | |
| 805 | − const float magnifyVTop = 1.0f - (magPos.y - halfHeight) / (float)widgetHeight; | |
| 806 | − const float magnifyVBottom = 1.0f - (magPos.y + halfHeight) / (float)widgetHeight; | |
| 807 | − | |
| 808 | − const float newHalfWidth = halfWidth * MAGNIFY_MULT; | |
| 809 | − const float newHalfHeight = halfHeight * MAGNIFY_MULT; | |
| 810 | − //Get yaw / pitch value for the corners | |
| 811 | − const glm::vec2 topLeftYawPitch = overlayToSpherical(glm::vec2(magPos.x - newHalfWidth, | |
| 812 | − magPos.y - newHalfHeight)); | |
| 813 | − const glm::vec2 bottomRightYawPitch = overlayToSpherical(glm::vec2(magPos.x + newHalfWidth, | |
| 814 | − magPos.y + newHalfHeight)); | |
| 815 | − | |
| 816 | − const glm::vec3 bottomLeft = getPoint(topLeftYawPitch.x, bottomRightYawPitch.y); | |
| 817 | − const glm::vec3 bottomRight = getPoint(bottomRightYawPitch.x, bottomRightYawPitch.y); | |
| 818 | − const glm::vec3 topLeft = getPoint(topLeftYawPitch.x, topLeftYawPitch.y); | |
| 819 | − const glm::vec3 topRight = getPoint(bottomRightYawPitch.x, topLeftYawPitch.y); | |
| 820 | − | |
| 821 | − auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 822 | − | |
| 823 | − if (bottomLeft != _previousMagnifierBottomLeft || bottomRight != _previousMagnifierBottomRight | |
| 824 | − || topLeft != _previousMagnifierTopLeft || topRight != _previousMagnifierTopRight) { | |
| 825 | − QVector<glm::vec3> border; | |
| 826 | − border << topLeft; | |
| 827 | − border << bottomLeft; | |
| 828 | − border << bottomRight; | |
| 829 | − border << topRight; | |
| 830 | − border << topLeft; | |
| 831 | − geometryCache->updateVertices(_magnifierBorder, border, glm::vec4(1.0f, 0.0f, 0.0f, _alpha)); | |
| 832 | − | |
| 833 | − _previousMagnifierBottomLeft = bottomLeft; | |
| 834 | − _previousMagnifierBottomRight = bottomRight; | |
| 835 | − _previousMagnifierTopLeft = topLeft; | |
| 836 | − _previousMagnifierTopRight = topRight; | |
| 837 | − } | |
| 838 | − | |
| 839 | − glPushMatrix(); { | |
| 840 | − if (showBorder) { | |
| 841 | − glDisable(GL_TEXTURE_2D); | |
| 842 | − glLineWidth(1.0f); | |
| 843 | − //Outer Line | |
| 844 | − geometryCache->renderVertices(gpu::LINE_STRIP, _magnifierBorder); | |
| 845 | − glEnable(GL_TEXTURE_2D); | |
| 846 | − } | |
| 847 | − glm::vec4 magnifierColor = { 1.0f, 1.0f, 1.0f, _alpha }; | |
| 848 | − | |
| 849 | − DependencyManager::get<GeometryCache>()->renderQuad(bottomLeft, bottomRight, topRight, topLeft, | |
| 850 | − glm::vec2(magnifyULeft, magnifyVBottom), | |
| 851 | − glm::vec2(magnifyURight, magnifyVBottom), | |
| 852 | − glm::vec2(magnifyURight, magnifyVTop), | |
| 853 | − glm::vec2(magnifyULeft, magnifyVTop), | |
| 854 | − magnifierColor, _magnifierQuad); | |
| 855 | − | |
| 856 | − } glPopMatrix(); | |
| 143 | +void ApplicationOverlay::renderRearViewToFbo(RenderArgs* renderArgs) { | |
| 857 | 144 | } |
| 858 | 145 | |
| 859 | −const int AUDIO_METER_GAP = 5; | |
| 860 | −const int MUTE_ICON_PADDING = 10; | |
| 861 | − | |
| 862 | −void ApplicationOverlay::renderCameraToggle() { | |
| 863 | − if (Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking)) { | |
| 864 | − return; | |
| 865 | − } | |
| 866 | − | |
| 867 | − int audioMeterY; | |
| 868 | − bool smallMirrorVisible = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !qApp->isHMDMode(); | |
| 869 | − bool boxed = smallMirrorVisible && | |
| 870 | − !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror); | |
| 871 | − if (boxed) { | |
| 872 | − audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_GAP + MUTE_ICON_PADDING; | |
| 873 | − } else { | |
| 874 | − audioMeterY = AUDIO_METER_GAP + MUTE_ICON_PADDING; | |
| 875 | − } | |
| 876 | − | |
| 877 | − DependencyManager::get<CameraToolBox>()->render(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP, audioMeterY, boxed); | |
| 146 | +void ApplicationOverlay::renderRearView(RenderArgs* renderArgs) { | |
| 878 | 147 | } |
| 879 | 148 | |
| 880 | −void ApplicationOverlay::renderAudioMeter() { | |
| 881 | − auto audio = DependencyManager::get<AudioClient>(); | |
| 882 | − | |
| 883 | − // Audio VU Meter and Mute Icon | |
| 884 | − const int MUTE_ICON_SIZE = 24; | |
| 885 | − const int AUDIO_METER_HEIGHT = 8; | |
| 886 | − const int INTER_ICON_GAP = 2; | |
| 887 | − | |
| 888 | − int cameraSpace = 0; | |
| 889 | − int audioMeterWidth = MIRROR_VIEW_WIDTH - MUTE_ICON_SIZE - MUTE_ICON_PADDING; | |
| 890 | − int audioMeterScaleWidth = audioMeterWidth - 2; | |
| 891 | − int audioMeterX = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_GAP; | |
| 892 | − if (!Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking)) { | |
| 893 | − cameraSpace = MUTE_ICON_SIZE + INTER_ICON_GAP; | |
| 894 | − audioMeterWidth -= cameraSpace; | |
| 895 | − audioMeterScaleWidth -= cameraSpace; | |
| 896 | − audioMeterX += cameraSpace; | |
| 897 | − } | |
| 898 | − | |
| 899 | − int audioMeterY; | |
| 900 | − bool smallMirrorVisible = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !qApp->isHMDMode(); | |
| 901 | − bool boxed = smallMirrorVisible && | |
| 902 | − !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror); | |
| 903 | − if (boxed) { | |
| 904 | − audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_GAP + MUTE_ICON_PADDING; | |
| 905 | − } else { | |
| 906 | − audioMeterY = AUDIO_METER_GAP + MUTE_ICON_PADDING; | |
| 907 | − } | |
| 908 | − | |
| 909 | − const glm::vec4 AUDIO_METER_BLUE = { 0.0, 0.0, 1.0, 1.0 }; | |
| 910 | − const glm::vec4 AUDIO_METER_GREEN = { 0.0, 1.0, 0.0, 1.0 }; | |
| 911 | − const glm::vec4 AUDIO_METER_RED = { 1.0, 0.0, 0.0, 1.0 }; | |
| 912 | − const float CLIPPING_INDICATOR_TIME = 1.0f; | |
| 913 | − const float AUDIO_METER_AVERAGING = 0.5; | |
| 914 | − const float LOG2 = log(2.0f); | |
| 915 | − const float METER_LOUDNESS_SCALE = 2.8f / 5.0f; | |
| 916 | − const float LOG2_LOUDNESS_FLOOR = 11.0f; | |
| 917 | − float audioGreenStart = 0.25f * audioMeterScaleWidth; | |
| 918 | − float audioRedStart = 0.8f * audioMeterScaleWidth; | |
| 919 | − float audioLevel = 0.0f; | |
| 920 | − float loudness = audio->getLastInputLoudness() + 1.0f; | |
| 921 | − | |
| 922 | − _trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.0f - AUDIO_METER_AVERAGING) * loudness; | |
| 923 | − float log2loudness = log(_trailingAudioLoudness) / LOG2; | |
| 924 | − | |
| 925 | − if (log2loudness <= LOG2_LOUDNESS_FLOOR) { | |
| 926 | − audioLevel = (log2loudness / LOG2_LOUDNESS_FLOOR) * METER_LOUDNESS_SCALE * audioMeterScaleWidth; | |
| 927 | − } else { | |
| 928 | − audioLevel = (log2loudness - (LOG2_LOUDNESS_FLOOR - 1.0f)) * METER_LOUDNESS_SCALE * audioMeterScaleWidth; | |
| 929 | − } | |
| 930 | − if (audioLevel > audioMeterScaleWidth) { | |
| 931 | − audioLevel = audioMeterScaleWidth; | |
| 932 | − } | |
| 933 | − bool isClipping = ((audio->getTimeSinceLastClip() > 0.0f) && (audio->getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME)); | |
| 934 | − | |
| 935 | − DependencyManager::get<AudioToolBox>()->render(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP, audioMeterY, cameraSpace, boxed); | |
| 936 | − | |
| 937 | − auto canvasSize = qApp->getCanvasSize(); | |
| 938 | − DependencyManager::get<AudioScope>()->render(canvasSize.x, canvasSize.y); | |
| 939 | − DependencyManager::get<AudioIOStatsRenderer>()->render(WHITE_TEXT, canvasSize.x, canvasSize.y); | |
| 940 | − | |
| 941 | − audioMeterY += AUDIO_METER_HEIGHT; | |
| 942 | − | |
| 943 | − // Draw audio meter background Quad | |
| 944 | − DependencyManager::get<GeometryCache>()->renderQuad(audioMeterX, audioMeterY, audioMeterWidth, AUDIO_METER_HEIGHT, | |
| 945 | − glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); | |
| 946 | − | |
| 947 | − if (audioLevel > audioRedStart) { | |
| 948 | − glm::vec4 quadColor; | |
| 949 | − if (!isClipping) { | |
| 950 | − quadColor = AUDIO_METER_RED; | |
| 951 | − } else { | |
| 952 | − quadColor = glm::vec4(1, 1, 1, 1); | |
| 953 | − } | |
| 954 | − // Draw Red Quad | |
| 955 | − DependencyManager::get<GeometryCache>()->renderQuad(audioMeterX + audioRedStart, | |
| 956 | − audioMeterY, | |
| 957 | − audioLevel - audioRedStart, | |
| 958 | − AUDIO_METER_HEIGHT, quadColor, | |
| 959 | − _audioRedQuad); | |
| 960 | − | |
| 961 | − audioLevel = audioRedStart; | |
| 962 | − } | |
| 963 | − | |
| 964 | − if (audioLevel > audioGreenStart) { | |
| 965 | − glm::vec4 quadColor; | |
| 966 | − if (!isClipping) { | |
| 967 | − quadColor = AUDIO_METER_GREEN; | |
| 968 | − } else { | |
| 969 | − quadColor = glm::vec4(1, 1, 1, 1); | |
| 970 | − } | |
| 971 | − // Draw Green Quad | |
| 972 | − DependencyManager::get<GeometryCache>()->renderQuad(audioMeterX + audioGreenStart, | |
| 973 | − audioMeterY, | |
| 974 | − audioLevel - audioGreenStart, | |
| 975 | − AUDIO_METER_HEIGHT, quadColor, | |
| 976 | − _audioGreenQuad); | |
| 977 | − | |
| 978 | − audioLevel = audioGreenStart; | |
| 979 | − } | |
| 980 | − | |
| 981 | − if (audioLevel >= 0) { | |
| 982 | − glm::vec4 quadColor; | |
| 983 | − if (!isClipping) { | |
| 984 | − quadColor = AUDIO_METER_BLUE; | |
| 985 | − } else { | |
| 986 | − quadColor = glm::vec4(1, 1, 1, 1); | |
| 987 | − } | |
| 988 | − // Draw Blue (low level) quad | |
| 989 | − DependencyManager::get<GeometryCache>()->renderQuad(audioMeterX, | |
| 990 | − audioMeterY, | |
| 991 | − audioLevel, AUDIO_METER_HEIGHT, quadColor, | |
| 992 | − _audioBlueQuad); | |
| 993 | − } | |
| 994 | −} | |
| 995 | − | |
| 996 | −void ApplicationOverlay::renderStatsAndLogs() { | |
| 997 | − Application* application = Application::getInstance(); | |
| 998 | − QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>(); | |
| 999 | − | |
| 1000 | − const OctreePacketProcessor& octreePacketProcessor = application->getOctreePacketProcessor(); | |
| 1001 | − NodeBounds& nodeBoundsDisplay = application->getNodeBoundsDisplay(); | |
| 1002 | − | |
| 149 | +void ApplicationOverlay::renderStatsAndLogs(RenderArgs* renderArgs) { | |
| 1003 | 150 | // Display stats and log text onscreen |
| 1004 | − glLineWidth(1.0f); | |
| 1005 | − glPointSize(1.0f); | |
| 1006 | 151 | |
| 1007 | 152 | // Determine whether to compute timing details |
| 1008 | − bool shouldDisplayTimingDetail = Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) && | |
| 1009 | − Menu::getInstance()->isOptionChecked(MenuOption::Stats) && | |
| 1010 | − Stats::getInstance()->isExpanded(); | |
| 1011 | − if (shouldDisplayTimingDetail != PerformanceTimer::isActive()) { | |
| 1012 | − PerformanceTimer::setActive(shouldDisplayTimingDetail); | |
| 1013 | − } | |
| 1014 | − | |
| 1015 | − if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { | |
| 1016 | − // let's set horizontal offset to give stats some margin to mirror | |
| 1017 | − int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2; | |
| 1018 | − int voxelPacketsToProcess = octreePacketProcessor.packetsToProcessCount(); | |
| 1019 | − // Onscreen text about position, servers, etc | |
| 1020 | − Stats::getInstance()->display(WHITE_TEXT, horizontalOffset, application->getFps(), | |
| 1021 | − bandwidthRecorder->getCachedTotalAverageInputPacketsPerSecond(), | |
| 1022 | − bandwidthRecorder->getCachedTotalAverageOutputPacketsPerSecond(), | |
| 1023 | − bandwidthRecorder->getCachedTotalAverageInputKilobitsPerSecond(), | |
| 1024 | − bandwidthRecorder->getCachedTotalAverageOutputKilobitsPerSecond(), | |
| 1025 | − voxelPacketsToProcess); | |
| 1026 | − } | |
| 1027 | 153 | |
| 154 | + /* | |
| 1028 | 155 | // Show on-screen msec timer |
| 1029 | 156 | if (Menu::getInstance()->isOptionChecked(MenuOption::FrameTimer)) { |
| 1030 | 157 | auto canvasSize = qApp->getCanvasSize(); |
| @@ -1036,159 +163,77 @@ void ApplicationOverlay::renderStatsAndLogs() { · 5 unmodified lines | ||
| 1036 | 163 | drawText(canvasSize.x - 100, canvasSize.y - timerBottom, |
| 1037 | 164 | 0.30f, 0.0f, 0, frameTimer.toUtf8().constData(), WHITE_TEXT); |
| 1038 | 165 | } |
| 166 | + | |
| 167 | + glPointSize(1.0f); | |
| 168 | + glDisable(GL_DEPTH_TEST); | |
| 169 | + glDisable(GL_LIGHTING); | |
| 170 | + glEnable(GL_BLEND); | |
| 171 | + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 172 | + NodeBounds& nodeBoundsDisplay = qApp->getNodeBoundsDisplay(); | |
| 1039 | 173 | nodeBoundsDisplay.drawOverlay(); |
| 174 | + glEnable(GL_DEPTH_TEST); | |
| 175 | + glEnable(GL_LIGHTING); | |
| 176 | + glEnable(GL_BLEND); | |
| 177 | + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 178 | + fboViewport(_overlayFramebuffer); | |
| 179 | + */ | |
| 1040 | 180 | } |
| 1041 | 181 | |
| 1042 | −void ApplicationOverlay::renderDomainConnectionStatusBorder() { | |
| 182 | +void ApplicationOverlay::renderDomainConnectionStatusBorder(RenderArgs* renderArgs) { | |
| 183 | + auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 184 | + static std::once_flag once; | |
| 185 | + std::call_once(once, [&] { | |
| 186 | + QVector<vec2> points; | |
| 187 | + static const float B = 0.99f; | |
| 188 | + points.push_back(vec2(-B)); | |
| 189 | + points.push_back(vec2(B, -B)); | |
| 190 | + points.push_back(vec2(B)); | |
| 191 | + points.push_back(vec2(-B, B)); | |
| 192 | + points.push_back(vec2(-B)); | |
| 193 | + geometryCache->updateVertices(_domainStatusBorder, points, CONNECTION_STATUS_BORDER_COLOR); | |
| 194 | + }); | |
| 1043 | 195 | auto nodeList = DependencyManager::get<NodeList>(); |
| 1044 | − | |
| 1045 | 196 | if (nodeList && !nodeList->getDomainHandler().isConnected()) { |
| 197 | + gpu::Batch batch; | |
| 1046 | 198 | auto geometryCache = DependencyManager::get<GeometryCache>(); |
| 1047 | − auto canvasSize = qApp->getCanvasSize(); | |
| 1048 | − if ((int)canvasSize.x != _previousBorderWidth || (int)canvasSize.y != _previousBorderHeight) { | |
| 1049 | − glm::vec4 color(CONNECTION_STATUS_BORDER_COLOR[0], | |
| 1050 | − CONNECTION_STATUS_BORDER_COLOR[1], | |
| 1051 | − CONNECTION_STATUS_BORDER_COLOR[2], 1.0f); | |
| 1052 | − | |
| 1053 | − QVector<glm::vec2> border; | |
| 1054 | − border << glm::vec2(0, 0); | |
| 1055 | − border << glm::vec2(0, canvasSize.y); | |
| 1056 | − border << glm::vec2(canvasSize.x, canvasSize.y); | |
| 1057 | − border << glm::vec2(canvasSize.x, 0); | |
| 1058 | − border << glm::vec2(0, 0); | |
| 1059 | − geometryCache->updateVertices(_domainStatusBorder, border, color); | |
| 1060 | − _previousBorderWidth = canvasSize.x; | |
| 1061 | − _previousBorderHeight = canvasSize.y; | |
| 1062 | − } | |
| 1063 | − | |
| 1064 | − glLineWidth(CONNECTION_STATUS_BORDER_LINE_WIDTH); | |
| 1065 | − | |
| 1066 | − geometryCache->renderVertices(gpu::LINE_STRIP, _domainStatusBorder); | |
| 1067 | − } | |
| 1068 | −} | |
| 199 | + geometryCache->useSimpleDrawPipeline(batch); | |
| 200 | + batch.setProjectionTransform(mat4()); | |
| 201 | + batch.setModelTransform(mat4()); | |
| 202 | + batch.setUniformTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture()); | |
| 203 | + batch._glLineWidth(CONNECTION_STATUS_BORDER_LINE_WIDTH); | |
| 1069 | 204 | |
| 1070 | −ApplicationOverlay::TexturedHemisphere::TexturedHemisphere() : | |
| 1071 | − _vertices(0), | |
| 1072 | − _indices(0), | |
| 1073 | − _framebufferObject(NULL), | |
| 1074 | − _vbo(0, 0) { | |
| 1075 | −} | |
| 1076 | − | |
| 1077 | −ApplicationOverlay::TexturedHemisphere::~TexturedHemisphere() { | |
| 1078 | − cleanupVBO(); | |
| 1079 | − if (_framebufferObject != NULL) { | |
| 1080 | − delete _framebufferObject; | |
| 1081 | − } | |
| 1082 | −} | |
| 1083 | − | |
| 1084 | −void ApplicationOverlay::TexturedHemisphere::bind() { | |
| 1085 | − _framebufferObject->bind(); | |
| 1086 | −} | |
| 1087 | − | |
| 1088 | −void ApplicationOverlay::TexturedHemisphere::release() { | |
| 1089 | − _framebufferObject->release(); | |
| 1090 | −} | |
| 205 | + // TODO animate the disconnect border for some excitement while not connected? | |
| 206 | + //double usecs = usecTimestampNow(); | |
| 207 | + //double secs = usecs / 1000000.0; | |
| 208 | + //float scaleAmount = 1.0f + (0.01f * sin(secs * 5.0f)); | |
| 209 | + //batch.setModelTransform(glm::scale(mat4(), vec3(scaleAmount))); | |
| 1091 | 210 | |
| 1092 | −void ApplicationOverlay::TexturedHemisphere::buildVBO(const float fov, | |
| 1093 | − const float aspectRatio, | |
| 1094 | − const int slices, | |
| 1095 | − const int stacks) { | |
| 1096 | − if (fov >= PI) { | |
| 1097 | − qDebug() << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues"; | |
| 1098 | − } | |
| 1099 | − // Cleanup old VBO if necessary | |
| 1100 | − cleanupVBO(); | |
| 1101 | − | |
| 1102 | − //UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm | |
| 1103 | − | |
| 1104 | − // Compute number of vertices needed | |
| 1105 | − _vertices = slices * stacks; | |
| 1106 | − | |
| 1107 | − // Compute vertices positions and texture UV coordinate | |
| 1108 | − TextureVertex* vertexData = new TextureVertex[_vertices]; | |
| 1109 | − TextureVertex* vertexPtr = &vertexData[0]; | |
| 1110 | − for (int i = 0; i < stacks; i++) { | |
| 1111 | − float stacksRatio = (float)i / (float)(stacks - 1); // First stack is 0.0f, last stack is 1.0f | |
| 1112 | − // abs(theta) <= fov / 2.0f | |
| 1113 | − float pitch = -fov * (stacksRatio - 0.5f); | |
| 1114 | − | |
| 1115 | − for (int j = 0; j < slices; j++) { | |
| 1116 | − float slicesRatio = (float)j / (float)(slices - 1); // First slice is 0.0f, last slice is 1.0f | |
| 1117 | − // abs(phi) <= fov * aspectRatio / 2.0f | |
| 1118 | − float yaw = -fov * aspectRatio * (slicesRatio - 0.5f); | |
| 1119 | − | |
| 1120 | − vertexPtr->position = getPoint(yaw, pitch); | |
| 1121 | − vertexPtr->uv.x = slicesRatio; | |
| 1122 | − vertexPtr->uv.y = stacksRatio; | |
| 1123 | − vertexPtr++; | |
| 1124 | − } | |
| 1125 | − } | |
| 1126 | − // Create and write to buffer | |
| 1127 | − glGenBuffers(1, &_vbo.first); | |
| 1128 | − glBindBuffer(GL_ARRAY_BUFFER, _vbo.first); | |
| 1129 | − static const int BYTES_PER_VERTEX = sizeof(TextureVertex); | |
| 1130 | − glBufferData(GL_ARRAY_BUFFER, _vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW); | |
| 1131 | − delete[] vertexData; | |
| 1132 | − | |
| 1133 | − | |
| 1134 | − // Compute number of indices needed | |
| 1135 | − static const int VERTEX_PER_TRANGLE = 3; | |
| 1136 | − static const int TRIANGLE_PER_RECTANGLE = 2; | |
| 1137 | − int numberOfRectangles = (slices - 1) * (stacks - 1); | |
| 1138 | − _indices = numberOfRectangles * TRIANGLE_PER_RECTANGLE * VERTEX_PER_TRANGLE; | |
| 1139 | − | |
| 1140 | − // Compute indices order | |
| 1141 | − GLushort* indexData = new GLushort[_indices]; | |
| 1142 | − GLushort* indexPtr = indexData; | |
| 1143 | − for (int i = 0; i < stacks - 1; i++) { | |
| 1144 | − for (int j = 0; j < slices - 1; j++) { | |
| 1145 | − GLushort bottomLeftIndex = i * slices + j; | |
| 1146 | − GLushort bottomRightIndex = bottomLeftIndex + 1; | |
| 1147 | − GLushort topLeftIndex = bottomLeftIndex + slices; | |
| 1148 | − GLushort topRightIndex = topLeftIndex + 1; | |
| 1149 | − | |
| 1150 | − *(indexPtr++) = topLeftIndex; | |
| 1151 | − *(indexPtr++) = bottomLeftIndex; | |
| 1152 | − *(indexPtr++) = topRightIndex; | |
| 1153 | − | |
| 1154 | − *(indexPtr++) = topRightIndex; | |
| 1155 | − *(indexPtr++) = bottomLeftIndex; | |
| 1156 | − *(indexPtr++) = bottomRightIndex; | |
| 1157 | − } | |
| 211 | + geometryCache->renderVertices(batch, gpu::LINE_STRIP, _domainStatusBorder); | |
| 212 | + renderArgs->_context->syncCache(); | |
| 213 | + renderArgs->_context->render(batch); | |
| 1158 | 214 | } |
| 1159 | − // Create and write to buffer | |
| 1160 | − glGenBuffers(1, &_vbo.second); | |
| 1161 | − glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vbo.second); | |
| 1162 | − static const int BYTES_PER_INDEX = sizeof(GLushort); | |
| 1163 | − glBufferData(GL_ELEMENT_ARRAY_BUFFER, _indices * BYTES_PER_INDEX, indexData, GL_STATIC_DRAW); | |
| 1164 | − delete[] indexData; | |
| 1165 | 215 | } |
| 1166 | 216 | |
| 1167 | −void ApplicationOverlay::TexturedHemisphere::cleanupVBO() { | |
| 1168 | − if (_vbo.first != 0) { | |
| 1169 | − glDeleteBuffers(1, &_vbo.first); | |
| 1170 | − _vbo.first = 0; | |
| 1171 | − } | |
| 1172 | − if (_vbo.second != 0) { | |
| 1173 | − glDeleteBuffers(1, &_vbo.second); | |
| 1174 | − _vbo.second = 0; | |
| 217 | +GLuint ApplicationOverlay::getOverlayTexture() { | |
| 218 | + if (!_overlayFramebuffer) { | |
| 219 | + return 0; | |
| 1175 | 220 | } |
| 221 | + return _overlayFramebuffer->texture(); | |
| 1176 | 222 | } |
| 1177 | 223 | |
| 1178 | −void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() { | |
| 1179 | − auto canvasSize = qApp->getCanvasSize(); | |
| 1180 | − QSize fboSize = QSize(canvasSize.x, canvasSize.y); | |
| 1181 | − if (_framebufferObject != NULL && fboSize == _framebufferObject->size()) { | |
| 1182 | − // Already build | |
| 224 | +void ApplicationOverlay::buildFramebufferObject() { | |
| 225 | + QSize fboSize = qApp->getDeviceSize(); | |
| 226 | + if (_overlayFramebuffer && fboSize == _overlayFramebuffer->size()) { | |
| 227 | + // Already built | |
| 1183 | 228 | return; |
| 1184 | 229 | } |
| 1185 | 230 | |
| 1186 | − if (_framebufferObject != NULL) { | |
| 1187 | − delete _framebufferObject; | |
| 231 | + if (_overlayFramebuffer) { | |
| 232 | + delete _overlayFramebuffer; | |
| 1188 | 233 | } |
| 1189 | 234 | |
| 1190 | − _framebufferObject = new QOpenGLFramebufferObject(fboSize, QOpenGLFramebufferObject::Depth); | |
| 1191 | − glBindTexture(GL_TEXTURE_2D, getTexture()); | |
| 235 | + _overlayFramebuffer = new QOpenGLFramebufferObject(fboSize, QOpenGLFramebufferObject::Depth); | |
| 236 | + glBindTexture(GL_TEXTURE_2D, getOverlayTexture()); | |
| 1192 | 237 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| 1193 | 238 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 1194 | 239 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); |
| @@ -1197,104 +242,3 @@ void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() { · 2 unmodified lines | ||
| 1197 | 242 | glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); |
| 1198 | 243 | glBindTexture(GL_TEXTURE_2D, 0); |
| 1199 | 244 | } |
| 1200 | − | |
| 1201 | −//Renders a hemisphere with texture coordinates. | |
| 1202 | −void ApplicationOverlay::TexturedHemisphere::render() { | |
| 1203 | − if (_framebufferObject == NULL || _vbo.first == 0 || _vbo.second == 0) { | |
| 1204 | − qDebug() << "TexturedHemisphere::render(): Incorrect initialisation"; | |
| 1205 | − return; | |
| 1206 | − } | |
| 1207 | − | |
| 1208 | − glBindBuffer(GL_ARRAY_BUFFER, _vbo.first); | |
| 1209 | − glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vbo.second); | |
| 1210 | − | |
| 1211 | − glEnableClientState(GL_VERTEX_ARRAY); | |
| 1212 | − glEnableClientState(GL_TEXTURE_COORD_ARRAY); | |
| 1213 | − | |
| 1214 | − static const int STRIDE = sizeof(TextureVertex); | |
| 1215 | − static const void* VERTEX_POINTER = 0; | |
| 1216 | − static const void* TEX_COORD_POINTER = (void*)sizeof(glm::vec3); | |
| 1217 | − glVertexPointer(3, GL_FLOAT, STRIDE, VERTEX_POINTER); | |
| 1218 | − glTexCoordPointer(2, GL_FLOAT, STRIDE, TEX_COORD_POINTER); | |
| 1219 | − | |
| 1220 | − glDrawRangeElements(GL_TRIANGLES, 0, _vertices - 1, _indices, GL_UNSIGNED_SHORT, 0); | |
| 1221 | − | |
| 1222 | − glDisableClientState(GL_VERTEX_ARRAY); | |
| 1223 | − glDisableClientState(GL_TEXTURE_COORD_ARRAY); | |
| 1224 | − | |
| 1225 | − glBindBuffer(GL_ARRAY_BUFFER, 0); | |
| 1226 | − glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); | |
| 1227 | −} | |
| 1228 | − | |
| 1229 | −GLuint ApplicationOverlay::TexturedHemisphere::getTexture() { | |
| 1230 | − return _framebufferObject->texture(); | |
| 1231 | −} | |
| 1232 | − | |
| 1233 | −glm::vec2 ApplicationOverlay::directionToSpherical(const glm::vec3& direction) { | |
| 1234 | − glm::vec2 result; | |
| 1235 | − // Compute yaw | |
| 1236 | − glm::vec3 normalProjection = glm::normalize(glm::vec3(direction.x, 0.0f, direction.z)); | |
| 1237 | − result.x = glm::acos(glm::dot(IDENTITY_FRONT, normalProjection)); | |
| 1238 | − if (glm::dot(IDENTITY_RIGHT, normalProjection) > 0.0f) { | |
| 1239 | − result.x = -glm::abs(result.x); | |
| 1240 | − } else { | |
| 1241 | − result.x = glm::abs(result.x); | |
| 1242 | − } | |
| 1243 | − // Compute pitch | |
| 1244 | − result.y = angleBetween(IDENTITY_UP, direction) - PI_OVER_TWO; | |
| 1245 | − | |
| 1246 | − return result; | |
| 1247 | −} | |
| 1248 | − | |
| 1249 | −glm::vec3 ApplicationOverlay::sphericalToDirection(const glm::vec2& sphericalPos) { | |
| 1250 | − glm::quat rotation(glm::vec3(sphericalPos.y, sphericalPos.x, 0.0f)); | |
| 1251 | − return rotation * IDENTITY_FRONT; | |
| 1252 | −} | |
| 1253 | − | |
| 1254 | −glm::vec2 ApplicationOverlay::screenToSpherical(const glm::vec2& screenPos) { | |
| 1255 | − auto screenSize = qApp->getCanvasSize(); | |
| 1256 | − glm::vec2 result; | |
| 1257 | − result.x = -(screenPos.x / screenSize.x - 0.5f); | |
| 1258 | − result.y = (screenPos.y / screenSize.y - 0.5f); | |
| 1259 | − result.x *= MOUSE_YAW_RANGE; | |
| 1260 | − result.y *= MOUSE_PITCH_RANGE; | |
| 1261 | − | |
| 1262 | − return result; | |
| 1263 | −} | |
| 1264 | − | |
| 1265 | −glm::vec2 ApplicationOverlay::sphericalToScreen(const glm::vec2& sphericalPos) { | |
| 1266 | − glm::vec2 result = sphericalPos; | |
| 1267 | − result.x *= -1.0; | |
| 1268 | − result /= MOUSE_RANGE; | |
| 1269 | − result += 0.5f; | |
| 1270 | − result *= qApp->getCanvasSize(); | |
| 1271 | − return result; | |
| 1272 | −} | |
| 1273 | − | |
| 1274 | −glm::vec2 ApplicationOverlay::sphericalToOverlay(const glm::vec2& sphericalPos) const { | |
| 1275 | − glm::vec2 result = sphericalPos; | |
| 1276 | − result.x *= -1.0; | |
| 1277 | − result /= _textureFov; | |
| 1278 | − result.x /= _textureAspectRatio; | |
| 1279 | − result += 0.5f; | |
| 1280 | − result *= qApp->getCanvasSize(); | |
| 1281 | − return result; | |
| 1282 | −} | |
| 1283 | − | |
| 1284 | −glm::vec2 ApplicationOverlay::overlayToSpherical(const glm::vec2& overlayPos) const { | |
| 1285 | − glm::vec2 result = overlayPos; | |
| 1286 | − result /= qApp->getCanvasSize(); | |
| 1287 | − result -= 0.5f; | |
| 1288 | − result *= _textureFov; | |
| 1289 | − result.x *= _textureAspectRatio; | |
| 1290 | − result.x *= -1.0f; | |
| 1291 | − return result; | |
| 1292 | −} | |
| 1293 | − | |
| 1294 | −glm::vec2 ApplicationOverlay::screenToOverlay(const glm::vec2& screenPos) const { | |
| 1295 | − return sphericalToOverlay(screenToSpherical(screenPos)); | |
| 1296 | −} | |
| 1297 | − | |
| 1298 | −glm::vec2 ApplicationOverlay::overlayToScreen(const glm::vec2& overlayPos) const { | |
| 1299 | − return sphericalToScreen(overlayToSpherical(overlayPos)); | |
| 1300 | −} | |
| @@ -13,16 +13,8 @@ · 12 unmodified lines | ||
| 13 | 13 | #define hifi_ApplicationOverlay_h |
| 14 | 14 | |
| 15 | 15 | #include <gpu/Texture.h> |
| 16 | −class Camera; | |
| 17 | −class Overlays; | |
| 18 | 16 | class QOpenGLFramebufferObject; |
| 19 | 17 | |
| 20 | −const float MAGNIFY_WIDTH = 220.0f; | |
| 21 | −const float MAGNIFY_HEIGHT = 100.0f; | |
| 22 | −const float MAGNIFY_MULT = 2.0f; | |
| 23 | − | |
| 24 | −const float DEFAULT_HMD_UI_ANGULAR_SIZE = 72.0f; | |
| 25 | − | |
| 26 | 18 | // Handles the drawing of the overlays to the screen |
| 27 | 19 | // TODO, move divide up the rendering, displaying and input handling |
| 28 | 20 | // facilities of this class |
| @@ -33,122 +25,26 @@ public: · 4 unmodified lines | ||
| 33 | 25 | ~ApplicationOverlay(); |
| 34 | 26 | |
| 35 | 27 | void renderOverlay(RenderArgs* renderArgs); |
| 36 | − void displayOverlayTexture(); | |
| 37 | − void displayOverlayTextureStereo(Camera& whichCamera, float aspectRatio, float fov); | |
| 38 | − void displayOverlayTextureHmd(Camera& whichCamera); | |
| 39 | − | |
| 40 | − QPoint getPalmClickLocation(const PalmData *palm) const; | |
| 41 | − bool calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const; | |
| 42 | − | |
| 43 | − bool hasMagnifier() const { return _magnifier; } | |
| 44 | − void toggleMagnifier() { _magnifier = !_magnifier; } | |
| 28 | + GLuint getOverlayTexture(); | |
| 45 | 29 | |
| 46 | − float getHmdUIAngularSize() const { return _hmdUIAngularSize; } | |
| 47 | − void setHmdUIAngularSize(float hmdUIAngularSize) { _hmdUIAngularSize = hmdUIAngularSize; } | |
| 48 | − | |
| 49 | − // Converter from one frame of reference to another. | |
| 50 | − // Frame of reference: | |
| 51 | − // Direction: Ray that represents the spherical values | |
| 52 | − // Screen: Position on the screen (x,y) | |
| 53 | − // Spherical: Pitch and yaw that gives the position on the sphere we project on (yaw,pitch) | |
| 54 | − // Overlay: Position on the overlay (x,y) | |
| 55 | − // (x,y) in Overlay are similar than (x,y) in Screen except they can be outside of the bound of te screen. | |
| 56 | − // This allows for picking outside of the screen projection in 3D. | |
| 57 | − glm::vec2 sphericalToOverlay(const glm::vec2 & sphericalPos) const; | |
| 58 | − glm::vec2 overlayToSpherical(const glm::vec2 & overlayPos) const; | |
| 59 | − glm::vec2 screenToOverlay(const glm::vec2 & screenPos) const; | |
| 60 | − glm::vec2 overlayToScreen(const glm::vec2 & overlayPos) const; | |
| 61 | − void computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const; | |
| 62 | − | |
| 63 | − static glm::vec2 directionToSpherical(const glm::vec3 & direction); | |
| 64 | − static glm::vec3 sphericalToDirection(const glm::vec2 & sphericalPos); | |
| 65 | − static glm::vec2 screenToSpherical(const glm::vec2 & screenPos); | |
| 66 | − static glm::vec2 sphericalToScreen(const glm::vec2 & sphericalPos); | |
| 67 | − | |
| 68 | 30 | private: |
| 69 | − // Interleaved vertex data | |
| 70 | − struct TextureVertex { | |
| 71 | − glm::vec3 position; | |
| 72 | − glm::vec2 uv; | |
| 73 | − }; | |
| 74 | − | |
| 75 | − typedef QPair<GLuint, GLuint> VerticesIndices; | |
| 76 | − class TexturedHemisphere { | |
| 77 | − public: | |
| 78 | − TexturedHemisphere(); | |
| 79 | − ~TexturedHemisphere(); | |
| 80 | − | |
| 81 | − void bind(); | |
| 82 | − void release(); | |
| 83 | − GLuint getTexture(); | |
| 84 | − | |
| 85 | − void buildFramebufferObject(); | |
| 86 | − void buildVBO(const float fov, const float aspectRatio, const int slices, const int stacks); | |
| 87 | − void render(); | |
| 88 | − | |
| 89 | − private: | |
| 90 | − void cleanupVBO(); | |
| 91 | − | |
| 92 | − GLuint _vertices; | |
| 93 | − GLuint _indices; | |
| 94 | − QOpenGLFramebufferObject* _framebufferObject; | |
| 95 | − VerticesIndices _vbo; | |
| 96 | − }; | |
| 97 | − | |
| 98 | − float _hmdUIAngularSize = DEFAULT_HMD_UI_ANGULAR_SIZE; | |
| 99 | − void renderReticle(glm::quat orientation, float alpha); | |
| 100 | − void renderPointers();; | |
| 101 | − void renderMagnifier(glm::vec2 magPos, float sizeMult, bool showBorder); | |
| 102 | − | |
| 103 | − void renderControllerPointers(); | |
| 104 | − void renderPointersOculus(); | |
| 105 | − | |
| 106 | − void renderAudioMeter(); | |
| 107 | − void renderCameraToggle(); | |
| 108 | − void renderStatsAndLogs(); | |
| 109 | − void renderDomainConnectionStatusBorder(); | |
| 110 | − void bindCursorTexture(gpu::Batch& batch, uint8_t cursorId = 0); | |
| 31 | + void renderStatsAndLogs(RenderArgs* renderArgs); | |
| 32 | + void renderDomainConnectionStatusBorder(RenderArgs* renderArgs); | |
| 33 | + void renderRearViewToFbo(RenderArgs* renderArgs); | |
| 34 | + void renderRearView(RenderArgs* renderArgs); | |
| 35 | + void renderQmlUi(RenderArgs* renderArgs); | |
| 36 | + void renderOverlays(RenderArgs* renderArgs); | |
| 37 | + void buildFramebufferObject(); | |
| 38 | + | |
| 39 | + float _alpha{ 1.0f }; | |
| 40 | + float _trailingAudioLoudness{ 0.0f }; | |
| 41 | + GLuint _uiTexture{ 0 }; | |
| 111 | 42 | |
| 112 | − TexturedHemisphere _overlays; | |
| 113 | − | |
| 114 | − float _textureFov; | |
| 115 | − float _textureAspectRatio; | |
| 116 | − | |
| 117 | − enum Reticles { MOUSE, LEFT_CONTROLLER, RIGHT_CONTROLLER, NUMBER_OF_RETICLES }; | |
| 118 | − bool _reticleActive[NUMBER_OF_RETICLES]; | |
| 119 | − QPoint _reticlePosition[NUMBER_OF_RETICLES]; | |
| 120 | − bool _magActive[NUMBER_OF_RETICLES]; | |
| 121 | − float _magSizeMult[NUMBER_OF_RETICLES]; | |
| 122 | − quint64 _lastMouseMove; | |
| 123 | − bool _magnifier; | |
| 124 | − | |
| 125 | − float _alpha = 1.0f; | |
| 126 | − float _oculusUIRadius; | |
| 127 | − float _trailingAudioLoudness; | |
| 128 | − | |
| 129 | − gpu::TexturePointer _crosshairTexture; | |
| 130 | − | |
| 131 | − | |
| 132 | − QMap<uint16_t, gpu::TexturePointer> _cursors; | |
| 133 | − | |
| 134 | − GLuint _newUiTexture{ 0 }; | |
| 135 | − | |
| 136 | − int _reticleQuad; | |
| 137 | − int _magnifierQuad; | |
| 138 | − int _audioRedQuad; | |
| 139 | − int _audioGreenQuad; | |
| 140 | − int _audioBlueQuad; | |
| 141 | 43 | int _domainStatusBorder; |
| 142 | 44 | int _magnifierBorder; |
| 143 | 45 | |
| 144 | − int _previousBorderWidth; | |
| 145 | − int _previousBorderHeight; | |
| 146 | − | |
| 147 | − glm::vec3 _previousMagnifierBottomLeft; | |
| 148 | − glm::vec3 _previousMagnifierBottomRight; | |
| 149 | − glm::vec3 _previousMagnifierTopLeft; | |
| 150 | − glm::vec3 _previousMagnifierTopRight; | |
| 151 | − | |
| 46 | + ivec2 _previousBorderSize{ -1 }; | |
| 47 | + QOpenGLFramebufferObject* _overlayFramebuffer{ nullptr }; | |
| 152 | 48 | }; |
| 153 | 49 | |
| 154 | 50 | #endif // hifi_ApplicationOverlay_h |
| @@ -0,0 +1,134 @@ | ||
| 1 | +// | |
| 2 | +// Created by Bradley Austin Davis 2015/06/19 | |
| 3 | +// Copyright 2013 High Fidelity, Inc. | |
| 4 | +// | |
| 5 | +// Distributed under the Apache License, Version 2.0. | |
| 6 | +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 7 | +// | |
| 8 | + | |
| 9 | + | |
| 10 | +#include "Application.h" | |
| 11 | +#include "AvatarInputs.h" | |
| 12 | + | |
| 13 | +#include <SettingHandle.h> | |
| 14 | + | |
| 15 | +#include "Menu.h" | |
| 16 | +#include "devices/FaceTracker.h" | |
| 17 | + | |
| 18 | +HIFI_QML_DEF(AvatarInputs) | |
| 19 | + | |
| 20 | + | |
| 21 | +static AvatarInputs* INSTANCE{ nullptr }; | |
| 22 | +static const char SETTINGS_GROUP_NAME[] = "Rear View Tools"; | |
| 23 | +static const char ZOOM_LEVEL_SETTINGS[] = "ZoomLevel"; | |
| 24 | + | |
| 25 | +static Setting::Handle<int> rearViewZoomLevel(QStringList() << SETTINGS_GROUP_NAME << ZOOM_LEVEL_SETTINGS, 0); | |
| 26 | + | |
| 27 | +AvatarInputs* AvatarInputs::getInstance() { | |
| 28 | + if (!INSTANCE) { | |
| 29 | + AvatarInputs::registerType(); | |
| 30 | + AvatarInputs::show(); | |
| 31 | + Q_ASSERT(INSTANCE); | |
| 32 | + } | |
| 33 | + return INSTANCE; | |
| 34 | +} | |
| 35 | + | |
| 36 | +AvatarInputs::AvatarInputs(QQuickItem* parent) : QQuickItem(parent) { | |
| 37 | + INSTANCE = this; | |
| 38 | + int zoomSetting = rearViewZoomLevel.get(); | |
| 39 | + _mirrorZoomed = zoomSetting == 0; | |
| 40 | +} | |
| 41 | + | |
| 42 | +#define AI_UPDATE(name, src) \ | |
| 43 | + { \ | |
| 44 | + auto val = src; \ | |
| 45 | + if (_##name != val) { \ | |
| 46 | + _##name = val; \ | |
| 47 | + emit name##Changed(); \ | |
| 48 | + } \ | |
| 49 | + } | |
| 50 | + | |
| 51 | +#define AI_UPDATE_FLOAT(name, src, epsilon) \ | |
| 52 | + { \ | |
| 53 | + float val = src; \ | |
| 54 | + if (fabs(_##name - val) >= epsilon) { \ | |
| 55 | + _##name = val; \ | |
| 56 | + emit name##Changed(); \ | |
| 57 | + } \ | |
| 58 | + } | |
| 59 | + | |
| 60 | +void AvatarInputs::update() { | |
| 61 | + if (!Menu::getInstance()) { | |
| 62 | + return; | |
| 63 | + } | |
| 64 | + AI_UPDATE(mirrorVisible, Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !qApp->isHMDMode() | |
| 65 | + && !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)); | |
| 66 | + AI_UPDATE(cameraEnabled, !Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking)); | |
| 67 | + AI_UPDATE(cameraMuted, Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking)); | |
| 68 | + | |
| 69 | + auto audioIO = DependencyManager::get<AudioClient>(); | |
| 70 | + const float CLIPPING_INDICATOR_TIME = 1.0f; | |
| 71 | + const float AUDIO_METER_AVERAGING = 0.5; | |
| 72 | + const float LOG2 = log(2.0f); | |
| 73 | + const float METER_LOUDNESS_SCALE = 2.8f / 5.0f; | |
| 74 | + const float LOG2_LOUDNESS_FLOOR = 11.0f; | |
| 75 | + float audioLevel = 0.0f; | |
| 76 | + auto audio = DependencyManager::get<AudioClient>(); | |
| 77 | + float loudness = audio->getLastInputLoudness() + 1.0f; | |
| 78 | + | |
| 79 | + _trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.0f - AUDIO_METER_AVERAGING) * loudness; | |
| 80 | + | |
| 81 | + float log2loudness = logf(_trailingAudioLoudness) / LOG2; | |
| 82 | + | |
| 83 | + if (log2loudness <= LOG2_LOUDNESS_FLOOR) { | |
| 84 | + audioLevel = (log2loudness / LOG2_LOUDNESS_FLOOR) * METER_LOUDNESS_SCALE; | |
| 85 | + } else { | |
| 86 | + audioLevel = (log2loudness - (LOG2_LOUDNESS_FLOOR - 1.0f)) * METER_LOUDNESS_SCALE; | |
| 87 | + } | |
| 88 | + if (audioLevel > 1.0) { | |
| 89 | + audioLevel = 1.0; | |
| 90 | + } | |
| 91 | + AI_UPDATE_FLOAT(audioLevel, audioLevel, 0.01); | |
| 92 | + AI_UPDATE(audioClipping, ((audioIO->getTimeSinceLastClip() > 0.0f) && (audioIO->getTimeSinceLastClip() < 1.0f))); | |
| 93 | + AI_UPDATE(audioMuted, audioIO->isMuted()); | |
| 94 | + | |
| 95 | + //// Make muted icon pulsate | |
| 96 | + //static const float PULSE_MIN = 0.4f; | |
| 97 | + //static const float PULSE_MAX = 1.0f; | |
| 98 | + //static const float PULSE_FREQUENCY = 1.0f; // in Hz | |
| 99 | + //qint64 now = usecTimestampNow(); | |
| 100 | + //if (now - _iconPulseTimeReference > (qint64)USECS_PER_SECOND) { | |
| 101 | + // // Prevents t from getting too big, which would diminish glm::cos precision | |
| 102 | + // _iconPulseTimeReference = now - ((now - _iconPulseTimeReference) % USECS_PER_SECOND); | |
| 103 | + //} | |
| 104 | + //float t = (float)(now - _iconPulseTimeReference) / (float)USECS_PER_SECOND; | |
| 105 | + //float pulseFactor = (glm::cos(t * PULSE_FREQUENCY * 2.0f * PI) + 1.0f) / 2.0f; | |
| 106 | + //iconColor = PULSE_MIN + (PULSE_MAX - PULSE_MIN) * pulseFactor; | |
| 107 | +} | |
| 108 | + | |
| 109 | +void AvatarInputs::toggleCameraMute() { | |
| 110 | + FaceTracker* faceTracker = Application::getInstance()->getSelectedFaceTracker(); | |
| 111 | + if (faceTracker) { | |
| 112 | + faceTracker->toggleMute(); | |
| 113 | + } | |
| 114 | +} | |
| 115 | + | |
| 116 | +void AvatarInputs::toggleAudioMute() { | |
| 117 | + DependencyManager::get<AudioClient>()->toggleMute(); | |
| 118 | +} | |
| 119 | + | |
| 120 | +void AvatarInputs::resetSensors() { | |
| 121 | + qApp->resetSensors(); | |
| 122 | +} | |
| 123 | + | |
| 124 | +void AvatarInputs::toggleZoom() { | |
| 125 | + _mirrorZoomed = !_mirrorZoomed; | |
| 126 | + rearViewZoomLevel.set(_mirrorZoomed ? 0 : 1); | |
| 127 | + emit mirrorZoomedChanged(); | |
| 128 | +} | |
| 129 | + | |
| 130 | +void AvatarInputs::closeMirror() { | |
| 131 | + if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { | |
| 132 | + Menu::getInstance()->triggerOption(MenuOption::Mirror); | |
| 133 | + } | |
| 134 | +} | |
| @@ -0,0 +1,59 @@ | ||
| 1 | +// | |
| 2 | +// Created by Bradley Austin Davis 2015/06/19 | |
| 3 | +// Copyright 2013 High Fidelity, Inc. | |
| 4 | +// | |
| 5 | +// Distributed under the Apache License, Version 2.0. | |
| 6 | +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 7 | +// | |
| 8 | + | |
| 9 | +#ifndef hifi_AvatarInputs_h | |
| 10 | +#define hifi_AvatarInputs_h | |
| 11 | + | |
| 12 | +#include <QQuickItem> | |
| 13 | +#include <OffscreenUi.h> | |
| 14 | + | |
| 15 | +#define AI_PROPERTY(type, name, initialValue) \ | |
| 16 | + Q_PROPERTY(type name READ name NOTIFY name##Changed) \ | |
| 17 | +public: \ | |
| 18 | + type name() { return _##name; }; \ | |
| 19 | +private: \ | |
| 20 | + type _##name{ initialValue }; | |
| 21 | + | |
| 22 | +class AvatarInputs : public QQuickItem { | |
| 23 | + Q_OBJECT | |
| 24 | + HIFI_QML_DECL | |
| 25 | + | |
| 26 | + AI_PROPERTY(bool, cameraEnabled, false) | |
| 27 | + AI_PROPERTY(bool, cameraMuted, false) | |
| 28 | + AI_PROPERTY(bool, audioMuted, false) | |
| 29 | + AI_PROPERTY(bool, audioClipping, false) | |
| 30 | + AI_PROPERTY(float, audioLevel, 0) | |
| 31 | + AI_PROPERTY(bool, mirrorVisible, false) | |
| 32 | + AI_PROPERTY(bool, mirrorZoomed, true) | |
| 33 | + | |
| 34 | +public: | |
| 35 | + static AvatarInputs* getInstance(); | |
| 36 | + AvatarInputs(QQuickItem* parent = nullptr); | |
| 37 | + void update(); | |
| 38 | + | |
| 39 | +signals: | |
| 40 | + void cameraEnabledChanged(); | |
| 41 | + void cameraMutedChanged(); | |
| 42 | + void audioMutedChanged(); | |
| 43 | + void audioClippingChanged(); | |
| 44 | + void audioLevelChanged(); | |
| 45 | + void mirrorVisibleChanged(); | |
| 46 | + void mirrorZoomedChanged(); | |
| 47 | + | |
| 48 | +protected: | |
| 49 | + Q_INVOKABLE void resetSensors(); | |
| 50 | + Q_INVOKABLE void toggleCameraMute(); | |
| 51 | + Q_INVOKABLE void toggleAudioMute(); | |
| 52 | + Q_INVOKABLE void toggleZoom(); | |
| 53 | + Q_INVOKABLE void closeMirror(); | |
| 54 | + | |
| 55 | +private: | |
| 56 | + float _trailingAudioLoudness{ 0 }; | |
| 57 | +}; | |
| 58 | + | |
| 59 | +#endif // hifi_AvatarInputs_h | |
| @@ -38,8 +38,17 @@ · 37 unmodified lines | ||
| 38 | 38 | ** |
| 39 | 39 | ****************************************************************************/ |
| 40 | 40 | |
| 41 | +#ifdef __GNUC__ | |
| 42 | +#pragma GCC diagnostic push | |
| 43 | +#pragma GCC diagnostic ignored "-Wdouble-promotion" | |
| 44 | +#endif | |
| 45 | + | |
| 41 | 46 | #include <QtWidgets> |
| 42 | 47 | |
| 48 | +#ifdef __GNUC__ | |
| 49 | +#pragma GCC diagnostic pop | |
| 50 | +#endif | |
| 51 | + | |
| 43 | 52 | #include "FlowLayout.h" |
| 44 | 53 | //! [1] |
| 45 | 54 | FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing) |
| @@ -56,8 +56,6 @@ HMDToolsDialog::HMDToolsDialog(QWidget* parent) : · 55 unmodified lines | ||
| 56 | 56 | |
| 57 | 57 | this->QDialog::setLayout(form); |
| 58 | 58 | |
| 59 | − _wasMoved = false; | |
| 60 | − _previousRect = Application::getInstance()->getWindow()->rect(); | |
| 61 | 59 | Application::getInstance()->getWindow()->activateWindow(); |
| 62 | 60 | |
| 63 | 61 | // watch for our application window moving screens. If it does we want to update our screen details |
| @@ -136,24 +134,6 @@ void HMDToolsDialog::enterHDMMode() { · 72 unmodified lines | ||
| 136 | 134 | if (!_inHDMMode) { |
| 137 | 135 | _switchModeButton->setText("Leave HMD Mode"); |
| 138 | 136 | _debugDetails->setText(getDebugDetails()); |
| 139 | − | |
| 140 | − _hmdScreenNumber = OculusManager::getHMDScreen(); | |
| 141 | − | |
| 142 | − if (_hmdScreenNumber >= 0) { | |
| 143 | − QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle(); | |
| 144 | − _hmdScreen = QGuiApplication::screens()[_hmdScreenNumber]; | |
| 145 | − | |
| 146 | − _previousRect = Application::getInstance()->getWindow()->rect(); | |
| 147 | − _previousRect = QRect(mainWindow->mapToGlobal(_previousRect.topLeft()), | |
| 148 | − mainWindow->mapToGlobal(_previousRect.bottomRight())); | |
| 149 | − _previousScreen = mainWindow->screen(); | |
| 150 | − QRect rect = QApplication::desktop()->screenGeometry(_hmdScreenNumber); | |
| 151 | − mainWindow->setScreen(_hmdScreen); | |
| 152 | − mainWindow->setGeometry(rect); | |
| 153 | − | |
| 154 | − _wasMoved = true; | |
| 155 | − } | |
| 156 | − | |
| 157 | 137 | |
| 158 | 138 | // if we're on a single screen setup, then hide our tools window when entering HMD mode |
| 159 | 139 | if (QApplication::desktop()->screenCount() == 1) { |
| @@ -161,58 +141,21 @@ void HMDToolsDialog::enterHDMMode() { · 1 unmodified line | ||
| 161 | 141 | } |
| 162 | 142 | |
| 163 | 143 | Application::getInstance()->setEnableVRMode(true); |
| 164 | − | |
| 165 | − const int SLIGHT_DELAY = 500; | |
| 166 | − // If we go to fullscreen immediately, it ends up on the primary monitor, | |
| 167 | − // even though we've already moved the window. By adding this delay, the | |
| 168 | − // fullscreen target screen ends up correct. | |
| 169 | − QTimer::singleShot(SLIGHT_DELAY, this, [&]{ | |
| 170 | − Application::getInstance()->setFullscreen(true); | |
| 171 | − activateWindowAfterEnterMode(); | |
| 172 | − }); | |
| 173 | − | |
| 144 | + | |
| 174 | 145 | _inHDMMode = true; |
| 175 | 146 | } |
| 176 | 147 | } |
| 177 | 148 | |
| 178 | −void HMDToolsDialog::activateWindowAfterEnterMode() { | |
| 179 | − Application::getInstance()->getWindow()->activateWindow(); | |
| 180 | − | |
| 181 | − // center the cursor on the main application window | |
| 182 | − centerCursorOnWidget(Application::getInstance()->getWindow()); | |
| 183 | −} | |
| 184 | − | |
| 185 | 149 | void HMDToolsDialog::leaveHDMMode() { |
| 186 | 150 | if (_inHDMMode) { |
| 187 | 151 | _switchModeButton->setText("Enter HMD Mode"); |
| 188 | 152 | _debugDetails->setText(getDebugDetails()); |
| 189 | − | |
| 190 | 153 | Application::getInstance()->setEnableVRMode(false); |
| 191 | − Application::getInstance()->setFullscreen(false); | |
| 192 | 154 | Application::getInstance()->getWindow()->activateWindow(); |
| 193 | − | |
| 194 | − if (_wasMoved) { | |
| 195 | − QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle(); | |
| 196 | − mainWindow->setScreen(_previousScreen); | |
| 197 | − mainWindow->setGeometry(_previousRect); | |
| 198 | − | |
| 199 | − const int SLIGHT_DELAY = 1500; | |
| 200 | − QTimer::singleShot(SLIGHT_DELAY, this, SLOT(moveWindowAfterLeaveMode())); | |
| 201 | − } | |
| 202 | − _wasMoved = false; | |
| 203 | 155 | _inHDMMode = false; |
| 204 | 156 | } |
| 205 | 157 | } |
| 206 | 158 | |
| 207 | −void HMDToolsDialog::moveWindowAfterLeaveMode() { | |
| 208 | − QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle(); | |
| 209 | − mainWindow->setScreen(_previousScreen); | |
| 210 | − mainWindow->setGeometry(_previousRect); | |
| 211 | − Application::getInstance()->getWindow()->activateWindow(); | |
| 212 | − Application::getInstance()->resetSensors(); | |
| 213 | −} | |
| 214 | − | |
| 215 | − | |
| 216 | 159 | void HMDToolsDialog::reject() { |
| 217 | 160 | // Just regularly close upon ESC |
| 218 | 161 | close(); |
| @@ -244,13 +187,15 @@ void HMDToolsDialog::hideEvent(QHideEvent* event) { · 25 unmodified lines | ||
| 244 | 187 | |
| 245 | 188 | void HMDToolsDialog::aboutToQuit() { |
| 246 | 189 | if (_inHDMMode) { |
| 190 | + // FIXME this is ineffective because it doesn't trigger the menu to | |
| 191 | + // save the fact that VR Mode is not checked. | |
| 247 | 192 | leaveHDMMode(); |
| 248 | 193 | } |
| 249 | 194 | } |
| 250 | 195 | |
| 251 | 196 | void HMDToolsDialog::screenCountChanged(int newCount) { |
| 252 | 197 | if (!OculusManager::isConnected()) { |
| 253 | − OculusManager::connect(); | |
| 198 | + //OculusManager::connect(); | |
| 254 | 199 | } |
| 255 | 200 | int hmdScreenNumber = OculusManager::getHMDScreen(); |
| 256 | 201 | |
| @@ -35,8 +35,6 @@ signals: · 34 unmodified lines | ||
| 35 | 35 | public slots: |
| 36 | 36 | void reject(); |
| 37 | 37 | void switchModeClicked(bool checked); |
| 38 | − void activateWindowAfterEnterMode(); | |
| 39 | − void moveWindowAfterLeaveMode(); | |
| 40 | 38 | void applicationWindowScreenChanged(QScreen* screen); |
| 41 | 39 | void aboutToQuit(); |
| 42 | 40 | void screenCountChanged(int newCount); |
| @@ -51,8 +49,6 @@ private: · 8 unmodified lines | ||
| 51 | 49 | void enterHDMMode(); |
| 52 | 50 | void leaveHDMMode(); |
| 53 | 51 | |
| 54 | − bool _wasMoved; | |
| 55 | − QRect _previousRect; | |
| 56 | 52 | QScreen* _previousScreen; |
| 57 | 53 | QScreen* _hmdScreen; |
| 58 | 54 | int _hmdScreenNumber; |
| @@ -11,10 +11,19 @@ · 10 unmodified lines | ||
| 11 | 11 | |
| 12 | 12 | #include "InterfaceConfig.h" |
| 13 | 13 | |
| 14 | +#ifdef __GNUC__ | |
| 15 | +#pragma GCC diagnostic push | |
| 16 | +#pragma GCC diagnostic ignored "-Wdouble-promotion" | |
| 17 | +#endif | |
| 18 | + | |
| 14 | 19 | #include <QDesktopWidget> |
| 15 | 20 | #include <QTextBlock> |
| 16 | 21 | #include <QtGui> |
| 17 | 22 | |
| 23 | +#ifdef __GNUC__ | |
| 24 | +#pragma GCC diagnostic pop | |
| 25 | +#endif | |
| 26 | + | |
| 18 | 27 | #include <PathUtils.h> |
| 19 | 28 | #include <SharedUtil.h> |
| 20 | 29 | |
| @@ -175,7 +175,7 @@ void PreferencesDialog::loadPreferences() { · 174 unmodified lines | ||
| 175 | 175 | |
| 176 | 176 | ui.maxOctreePPSSpin->setValue(qApp->getMaxOctreePacketsPerSecond()); |
| 177 | 177 | |
| 178 | − ui.oculusUIAngularSizeSpin->setValue(qApp->getApplicationOverlay().getHmdUIAngularSize()); | |
| 178 | + ui.oculusUIAngularSizeSpin->setValue(qApp->getApplicationCompositor().getHmdUIAngularSize()); | |
| 179 | 179 | |
| 180 | 180 | SixenseManager& sixense = SixenseManager::getInstance(); |
| 181 | 181 | ui.sixenseReticleMoveSpeedSpin->setValue(sixense.getReticleMoveSpeed()); |
| @@ -239,7 +239,7 @@ void PreferencesDialog::savePreferences() { · 57 unmodified lines | ||
| 239 | 239 | |
| 240 | 240 | qApp->setMaxOctreePacketsPerSecond(ui.maxOctreePPSSpin->value()); |
| 241 | 241 | |
| 242 | − qApp->getApplicationOverlay().setHmdUIAngularSize(ui.oculusUIAngularSizeSpin->value()); | |
| 242 | + qApp->getApplicationCompositor().setHmdUIAngularSize(ui.oculusUIAngularSizeSpin->value()); | |
| 243 | 243 | |
| 244 | 244 | SixenseManager& sixense = SixenseManager::getInstance(); |
| 245 | 245 | sixense.setReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value()); |
| @@ -1,134 +0,0 @@ | ||
| 1 | −// | |
| 2 | −// RearMirrorTools.cpp | |
| 3 | −// interface/src/ui | |
| 4 | −// | |
| 5 | −// Created by Stojce Slavkovski on 10/23/2013. | |
| 6 | −// Copyright 2013 High Fidelity, Inc. | |
| 7 | −// | |
| 8 | −// Distributed under the Apache License, Version 2.0. | |
| 9 | −// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 10 | −// | |
| 11 | − | |
| 12 | −#include "InterfaceConfig.h" | |
| 13 | − | |
| 14 | −#include <QMouseEvent> | |
| 15 | − | |
| 16 | −#include <PathUtils.h> | |
| 17 | −#include <SharedUtil.h> | |
| 18 | −#include <gpu/GLBackend.h> | |
| 19 | − | |
| 20 | −#include "Application.h" | |
| 21 | −#include "RearMirrorTools.h" | |
| 22 | −#include "Util.h" | |
| 23 | − | |
| 24 | −const int ICON_SIZE = 24; | |
| 25 | −const int ICON_PADDING = 5; | |
| 26 | − | |
| 27 | −const char SETTINGS_GROUP_NAME[] = "Rear View Tools"; | |
| 28 | −const char ZOOM_LEVEL_SETTINGS[] = "ZoomLevel"; | |
| 29 | −Setting::Handle<int> RearMirrorTools::rearViewZoomLevel(QStringList() << SETTINGS_GROUP_NAME << ZOOM_LEVEL_SETTINGS, | |
| 30 | − ZoomLevel::HEAD); | |
| 31 | − | |
| 32 | −RearMirrorTools::RearMirrorTools(QRect& bounds) : | |
| 33 | − _bounds(bounds), | |
| 34 | − _windowed(false), | |
| 35 | − _fullScreen(false) | |
| 36 | −{ | |
| 37 | − _closeTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/close.svg"); | |
| 38 | − | |
| 39 | − _zoomHeadTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/plus.svg"); | |
| 40 | − _zoomBodyTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/minus.svg"); | |
| 41 | − | |
| 42 | − _shrinkIconRect = QRect(ICON_PADDING, ICON_PADDING, ICON_SIZE, ICON_SIZE); | |
| 43 | − _closeIconRect = QRect(_bounds.left() + ICON_PADDING, _bounds.top() + ICON_PADDING, ICON_SIZE, ICON_SIZE); | |
| 44 | − _resetIconRect = QRect(_bounds.width() - ICON_SIZE - ICON_PADDING, _bounds.top() + ICON_PADDING, ICON_SIZE, ICON_SIZE); | |
| 45 | − _bodyZoomIconRect = QRect(_bounds.width() - ICON_SIZE - ICON_PADDING, _bounds.bottom() - ICON_PADDING - ICON_SIZE, ICON_SIZE, ICON_SIZE); | |
| 46 | − _headZoomIconRect = QRect(_bounds.left() + ICON_PADDING, _bounds.bottom() - ICON_PADDING - ICON_SIZE, ICON_SIZE, ICON_SIZE); | |
| 47 | −} | |
| 48 | − | |
| 49 | −void RearMirrorTools::render(RenderArgs* renderArgs, bool fullScreen, const QPoint & mousePosition) { | |
| 50 | − if (fullScreen) { | |
| 51 | − _fullScreen = true; | |
| 52 | − displayIcon(QRect(QPoint(), qApp->getDeviceSize()), _shrinkIconRect, _closeTexture); | |
| 53 | − } else { | |
| 54 | − // render rear view tools if mouse is in the bounds | |
| 55 | − _windowed = _bounds.contains(mousePosition); | |
| 56 | − if (_windowed) { | |
| 57 | − displayIcon(_bounds, _closeIconRect, _closeTexture); | |
| 58 | − | |
| 59 | − ZoomLevel zoomLevel = (ZoomLevel)rearViewZoomLevel.get(); | |
| 60 | − displayIcon(_bounds, _headZoomIconRect, _zoomHeadTexture, zoomLevel == HEAD); | |
| 61 | − displayIcon(_bounds, _bodyZoomIconRect, _zoomBodyTexture, zoomLevel == BODY); | |
| 62 | − } | |
| 63 | − } | |
| 64 | −} | |
| 65 | − | |
| 66 | −bool RearMirrorTools::mousePressEvent(int x, int y) { | |
| 67 | − if (_windowed) { | |
| 68 | − if (_closeIconRect.contains(x, y)) { | |
| 69 | − _windowed = false; | |
| 70 | − emit closeView(); | |
| 71 | − return true; | |
| 72 | − } | |
| 73 | − | |
| 74 | − if (_headZoomIconRect.contains(x, y)) { | |
| 75 | − rearViewZoomLevel.set(HEAD); | |
| 76 | − return true; | |
| 77 | − } | |
| 78 | − | |
| 79 | − if (_bodyZoomIconRect.contains(x, y)) { | |
| 80 | − rearViewZoomLevel.set(BODY); | |
| 81 | − return true; | |
| 82 | − } | |
| 83 | − | |
| 84 | − if (_bounds.contains(x, y)) { | |
| 85 | − _windowed = false; | |
| 86 | − emit restoreView(); | |
| 87 | − return true; | |
| 88 | − } | |
| 89 | − } | |
| 90 | − | |
| 91 | − if (_fullScreen) { | |
| 92 | − if (_shrinkIconRect.contains(x, y)) { | |
| 93 | − _fullScreen = false; | |
| 94 | − emit shrinkView(); | |
| 95 | − return true; | |
| 96 | − } | |
| 97 | − } | |
| 98 | − return false; | |
| 99 | −} | |
| 100 | − | |
| 101 | −void RearMirrorTools::displayIcon(QRect bounds, QRect iconBounds, const gpu::TexturePointer& texture, bool selected) { | |
| 102 | − | |
| 103 | − glMatrixMode(GL_PROJECTION); | |
| 104 | − glPushMatrix(); | |
| 105 | − glLoadIdentity(); | |
| 106 | − | |
| 107 | − glOrtho(bounds.left(), bounds.right(), bounds.bottom(), bounds.top(), -1.0, 1.0); | |
| 108 | − glDisable(GL_DEPTH_TEST); | |
| 109 | − glDisable(GL_LIGHTING); | |
| 110 | − glEnable(GL_TEXTURE_2D); | |
| 111 | − | |
| 112 | − glm::vec4 quadColor; | |
| 113 | − if (selected) { | |
| 114 | − quadColor = glm::vec4(.5f, .5f, .5f, 1.0f); | |
| 115 | − } else { | |
| 116 | − quadColor = glm::vec4(1, 1, 1, 1); | |
| 117 | − } | |
| 118 | − | |
| 119 | − glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(texture)); | |
| 120 | − | |
| 121 | − glm::vec2 topLeft(iconBounds.left(), iconBounds.top()); | |
| 122 | − glm::vec2 bottomRight(iconBounds.right(), iconBounds.bottom()); | |
| 123 | − static const glm::vec2 texCoordTopLeft(0.0f, 1.0f); | |
| 124 | − static const glm::vec2 texCoordBottomRight(1.0f, 0.0f); | |
| 125 | − | |
| 126 | − DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor); | |
| 127 | − | |
| 128 | − glPopMatrix(); | |
| 129 | − | |
| 130 | − glMatrixMode(GL_MODELVIEW); | |
| 131 | − | |
| 132 | − glBindTexture(GL_TEXTURE_2D, 0); | |
| 133 | − glDisable(GL_TEXTURE_2D); | |
| 134 | −} | |
| @@ -1,56 +0,0 @@ | ||
| 1 | −// | |
| 2 | −// RearMirrorTools.h | |
| 3 | −// interface/src/ui | |
| 4 | −// | |
| 5 | −// Created by Stojce Slavkovski on 10/23/2013. | |
| 6 | −// Copyright 2013 High Fidelity, Inc. | |
| 7 | −// | |
| 8 | −// Distributed under the Apache License, Version 2.0. | |
| 9 | −// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 10 | −// | |
| 11 | − | |
| 12 | −#ifndef hifi_RearMirrorTools_h | |
| 13 | −#define hifi_RearMirrorTools_h | |
| 14 | − | |
| 15 | −#include <gpu/Texture.h> | |
| 16 | −#include <SettingHandle.h> | |
| 17 | − | |
| 18 | −enum ZoomLevel { | |
| 19 | − HEAD = 0, | |
| 20 | − BODY = 1 | |
| 21 | −}; | |
| 22 | − | |
| 23 | −class RearMirrorTools : public QObject { | |
| 24 | − Q_OBJECT | |
| 25 | −public: | |
| 26 | − RearMirrorTools(QRect& bounds); | |
| 27 | − void render(RenderArgs* renderArgs, bool fullScreen, const QPoint & mousePos); | |
| 28 | − bool mousePressEvent(int x, int y); | |
| 29 | − | |
| 30 | − static Setting::Handle<int> rearViewZoomLevel; | |
| 31 | − | |
| 32 | −signals: | |
| 33 | − void closeView(); | |
| 34 | − void shrinkView(); | |
| 35 | − void resetView(); | |
| 36 | − void restoreView(); | |
| 37 | − | |
| 38 | −private: | |
| 39 | − QRect _bounds; | |
| 40 | − gpu::TexturePointer _closeTexture; | |
| 41 | − gpu::TexturePointer _zoomBodyTexture; | |
| 42 | − gpu::TexturePointer _zoomHeadTexture; | |
| 43 | − | |
| 44 | − QRect _closeIconRect; | |
| 45 | − QRect _resetIconRect; | |
| 46 | − QRect _shrinkIconRect; | |
| 47 | − QRect _headZoomIconRect; | |
| 48 | − QRect _bodyZoomIconRect; | |
| 49 | − | |
| 50 | − bool _windowed; | |
| 51 | − bool _fullScreen; | |
| 52 | − | |
| 53 | − void displayIcon(QRect bounds, QRect iconBounds, const gpu::TexturePointer& texture, bool selected = false); | |
| 54 | −}; | |
| 55 | − | |
| 56 | −#endif // hifi_RearMirrorTools_h | |
| @@ -1,17 +1,17 @@ | ||
| 1 | 1 | // |
| 2 | −// Stats.cpp | |
| 3 | −// interface/src/ui | |
| 4 | −// | |
| 5 | −// Created by Lucas Crisman on 22/03/14. | |
| 2 | +// Created by Bradley Austin Davis 2015/06/17 | |
| 6 | 3 | // Copyright 2013 High Fidelity, Inc. |
| 7 | 4 | // |
| 8 | 5 | // Distributed under the Apache License, Version 2.0. |
| 9 | 6 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html |
| 10 | 7 | // |
| 11 | 8 | |
| 12 | −#include <sstream> | |
| 9 | +#include <gpu/GPUConfig.h> | |
| 13 | 10 | |
| 14 | −#include <stdlib.h> | |
| 11 | +#include "Stats.h" | |
| 12 | + | |
| 13 | +#include <sstream> | |
| 14 | +#include <QFontDatabase> | |
| 15 | 15 | |
| 16 | 16 | #include <glm/glm.hpp> |
| 17 | 17 | #include <glm/gtx/component_wise.hpp> |
| @@ -25,147 +25,31 @@ · 7 unmodified lines | ||
| 25 | 25 | #include <LODManager.h> |
| 26 | 26 | #include <PerfStat.h> |
| 27 | 27 | |
| 28 | −#include "Stats.h" | |
| 29 | 28 | #include "BandwidthRecorder.h" |
| 30 | 29 | #include "InterfaceConfig.h" |
| 31 | 30 | #include "Menu.h" |
| 32 | 31 | #include "Util.h" |
| 33 | 32 | #include "SequenceNumberStats.h" |
| 34 | 33 | |
| 35 | −using namespace std; | |
| 34 | +HIFI_QML_DEF(Stats) | |
| 36 | 35 | |
| 37 | −const int STATS_PELS_PER_LINE = 16; | |
| 38 | −const int STATS_PELS_INITIALOFFSET = 12; | |
| 36 | +using namespace std; | |
| 39 | 37 | |
| 40 | −const int STATS_GENERAL_MIN_WIDTH = 165; | |
| 41 | −const int STATS_PING_MIN_WIDTH = 190; | |
| 42 | −const int STATS_GEO_MIN_WIDTH = 240; | |
| 43 | −const int STATS_OCTREE_MIN_WIDTH = 410; | |
| 38 | +static Stats* INSTANCE{ nullptr }; | |
| 44 | 39 | |
| 45 | 40 | Stats* Stats::getInstance() { |
| 46 | − static Stats stats; | |
| 47 | − return &stats; | |
| 48 | −} | |
| 49 | − | |
| 50 | −Stats::Stats(): | |
| 51 | − _expanded(false), | |
| 52 | − _recentMaxPackets(0), | |
| 53 | − _resetRecentMaxPacketsSoon(true), | |
| 54 | − _generalStatsWidth(STATS_GENERAL_MIN_WIDTH), | |
| 55 | − _pingStatsWidth(STATS_PING_MIN_WIDTH), | |
| 56 | − _geoStatsWidth(STATS_GEO_MIN_WIDTH), | |
| 57 | − _octreeStatsWidth(STATS_OCTREE_MIN_WIDTH), | |
| 58 | − _lastHorizontalOffset(0) | |
| 59 | −{ | |
| 60 | − auto canvasSize = Application::getInstance()->getCanvasSize(); | |
| 61 | − resetWidth(canvasSize.x, 0); | |
| 62 | −} | |
| 63 | − | |
| 64 | −void Stats::toggleExpanded() { | |
| 65 | − _expanded = !_expanded; | |
| 66 | −} | |
| 67 | − | |
| 68 | −// called on mouse click release | |
| 69 | −// check for clicks over stats in order to expand or contract them | |
| 70 | −void Stats::checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseDragStartedY, int horizontalOffset) { | |
| 71 | − auto canvasSize = Application::getInstance()->getCanvasSize(); | |
| 72 | − | |
| 73 | − if (0 != glm::compMax(glm::abs(glm::ivec2(mouseX - mouseDragStartedX, mouseY - mouseDragStartedY)))) { | |
| 74 | − // not worried about dragging on stats | |
| 75 | − return; | |
| 76 | − } | |
| 77 | − | |
| 78 | − int statsHeight = 0, | |
| 79 | − statsWidth = 0, | |
| 80 | − statsX = 0, | |
| 81 | − statsY = 0, | |
| 82 | − lines = 0; | |
| 83 | − | |
| 84 | − statsX = horizontalOffset; | |
| 85 | − | |
| 86 | − // top-left stats click | |
| 87 | − lines = _expanded ? 5 : 3; | |
| 88 | − statsHeight = lines * STATS_PELS_PER_LINE + 10; | |
| 89 | − if (mouseX > statsX && mouseX < statsX + _generalStatsWidth && mouseY > statsY && mouseY < statsY + statsHeight) { | |
| 90 | − toggleExpanded(); | |
| 91 | − return; | |
| 92 | − } | |
| 93 | − statsX += _generalStatsWidth; | |
| 94 | − | |
| 95 | − // ping stats click | |
| 96 | − if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { | |
| 97 | − lines = _expanded ? 4 : 3; | |
| 98 | − statsHeight = lines * STATS_PELS_PER_LINE + 10; | |
| 99 | − if (mouseX > statsX && mouseX < statsX + _pingStatsWidth && mouseY > statsY && mouseY < statsY + statsHeight) { | |
| 100 | − toggleExpanded(); | |
| 101 | − return; | |
| 102 | − } | |
| 103 | − statsX += _pingStatsWidth; | |
| 104 | − } | |
| 105 | − | |
| 106 | − // geo stats panel click | |
| 107 | − lines = _expanded ? 4 : 3; | |
| 108 | − statsHeight = lines * STATS_PELS_PER_LINE + 10; | |
| 109 | − if (mouseX > statsX && mouseX < statsX + _geoStatsWidth && mouseY > statsY && mouseY < statsY + statsHeight) { | |
| 110 | − toggleExpanded(); | |
| 111 | − return; | |
| 112 | − } | |
| 113 | − statsX += _geoStatsWidth; | |
| 114 | − | |
| 115 | − // top-right stats click | |
| 116 | − lines = _expanded ? 11 : 3; | |
| 117 | − statsHeight = lines * STATS_PELS_PER_LINE + 10; | |
| 118 | − statsWidth = canvasSize.x - statsX; | |
| 119 | − if (mouseX > statsX && mouseX < statsX + statsWidth && mouseY > statsY && mouseY < statsY + statsHeight) { | |
| 120 | − toggleExpanded(); | |
| 121 | − return; | |
| 122 | − } | |
| 123 | −} | |
| 124 | − | |
| 125 | −void Stats::resetWidth(int width, int horizontalOffset) { | |
| 126 | − auto canvasSize = Application::getInstance()->getCanvasSize(); | |
| 127 | − int extraSpace = canvasSize.x - horizontalOffset - 2 | |
| 128 | − - STATS_GENERAL_MIN_WIDTH | |
| 129 | − - (Menu::getInstance()->isOptionChecked(MenuOption::TestPing) ? STATS_PING_MIN_WIDTH -1 : 0) | |
| 130 | − - STATS_GEO_MIN_WIDTH | |
| 131 | − - STATS_OCTREE_MIN_WIDTH; | |
| 132 | − | |
| 133 | − int panels = 4; | |
| 134 | − | |
| 135 | − _generalStatsWidth = STATS_GENERAL_MIN_WIDTH; | |
| 136 | − if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { | |
| 137 | − _pingStatsWidth = STATS_PING_MIN_WIDTH; | |
| 138 | − } else { | |
| 139 | − _pingStatsWidth = 0; | |
| 140 | − panels = 3; | |
| 141 | − } | |
| 142 | − _geoStatsWidth = STATS_GEO_MIN_WIDTH; | |
| 143 | − _octreeStatsWidth = STATS_OCTREE_MIN_WIDTH; | |
| 144 | − | |
| 145 | − if (extraSpace > panels) { | |
| 146 | − _generalStatsWidth += (int) extraSpace / panels; | |
| 147 | − if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { | |
| 148 | − _pingStatsWidth += (int) extraSpace / panels; | |
| 149 | − } | |
| 150 | − _geoStatsWidth += (int) extraSpace / panels; | |
| 151 | − _octreeStatsWidth += canvasSize.x - | |
| 152 | − (_generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3); | |
| 41 | + if (!INSTANCE) { | |
| 42 | + Stats::registerType(); | |
| 43 | + Stats::show(); | |
| 44 | + Q_ASSERT(INSTANCE); | |
| 153 | 45 | } |
| 46 | + return INSTANCE; | |
| 154 | 47 | } |
| 155 | 48 | |
| 156 | − | |
| 157 | −// translucent background box that makes stats more readable | |
| 158 | −void Stats::drawBackground(unsigned int rgba, int x, int y, int width, int height) { | |
| 159 | − glm::vec4 color(((rgba >> 24) & 0xff) / 255.0f, | |
| 160 | − ((rgba >> 16) & 0xff) / 255.0f, | |
| 161 | − ((rgba >> 8) & 0xff) / 255.0f, | |
| 162 | − (rgba & 0xff) / 255.0f); | |
| 163 | − | |
| 164 | − // FIX ME: is this correct? It seems to work to fix textures bleeding into us... | |
| 165 | − glBindTexture(GL_TEXTURE_2D, 0); | |
| 166 | − glDisable(GL_TEXTURE_2D); | |
| 167 | − | |
| 168 | − DependencyManager::get<GeometryCache>()->renderQuad(x, y, width, height, color); | |
| 49 | +Stats::Stats(QQuickItem* parent) : QQuickItem(parent) { | |
| 50 | + INSTANCE = this; | |
| 51 | + const QFont font = QFontDatabase::systemFont(QFontDatabase::FixedFont); | |
| 52 | + _monospaceFont = font.family(); | |
| 169 | 53 | } |
| 170 | 54 | |
| 171 | 55 | bool Stats::includeTimingRecord(const QString& name) { |
| @@ -190,161 +74,70 @@ bool Stats::includeTimingRecord(const QString& name) { · 18 unmodified lines | ||
| 190 | 74 | return false; |
| 191 | 75 | } |
| 192 | 76 | |
| 193 | −// display expanded or contracted stats | |
| 194 | −void Stats::display( | |
| 195 | − const float* color, | |
| 196 | − int horizontalOffset, | |
| 197 | − float fps, | |
| 198 | − int inPacketsPerSecond, | |
| 199 | − int outPacketsPerSecond, | |
| 200 | − int inKbitsPerSecond, | |
| 201 | − int outKbitsPerSecond, | |
| 202 | − int voxelPacketsToProcess) | |
| 203 | −{ | |
| 204 | − auto canvasSize = Application::getInstance()->getCanvasSize(); | |
| 205 | − | |
| 206 | − unsigned int backgroundColor = 0x33333399; | |
| 207 | − int verticalOffset = 0, lines = 0; | |
| 208 | − float scale = 0.10f; | |
| 209 | − float rotation = 0.0f; | |
| 210 | − int font = 2; | |
| 211 | − | |
| 212 | − QLocale locale(QLocale::English); | |
| 213 | − std::stringstream octreeStats; | |
| 214 | − | |
| 215 | − QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>(); | |
| 216 | − | |
| 217 | − if (_lastHorizontalOffset != horizontalOffset) { | |
| 218 | − resetWidth(canvasSize.x, horizontalOffset); | |
| 219 | − _lastHorizontalOffset = horizontalOffset; | |
| 77 | +#define STAT_UPDATE(name, src) \ | |
| 78 | + { \ | |
| 79 | + auto val = src; \ | |
| 80 | + if (_##name != val) { \ | |
| 81 | + _##name = val; \ | |
| 82 | + emit name##Changed(); \ | |
| 83 | + } \ | |
| 220 | 84 | } |
| 221 | 85 | |
| 222 | − glPointSize(1.0f); | |
| 223 | − | |
| 224 | − // we need to take one avatar out so we don't include ourselves | |
| 225 | − int totalAvatars = DependencyManager::get<AvatarManager>()->size() - 1; | |
| 226 | − int totalServers = DependencyManager::get<NodeList>()->size(); | |
| 227 | − | |
| 228 | − lines = 5; | |
| 229 | − int columnOneWidth = _generalStatsWidth; | |
| 230 | − | |
| 231 | − bool performanceTimerIsActive = PerformanceTimer::isActive(); | |
| 232 | − bool displayPerf = _expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails); | |
| 233 | − if (displayPerf && performanceTimerIsActive) { | |
| 234 | − PerformanceTimer::tallyAllTimerRecords(); // do this even if we're not displaying them, so they don't stack up | |
| 235 | − | |
| 236 | − columnOneWidth = _generalStatsWidth + _pingStatsWidth + _geoStatsWidth; // 3 columns wide... | |
| 237 | − // we will also include room for 1 line per timing record and a header of 4 lines | |
| 238 | − lines += 4; | |
| 239 | − | |
| 240 | − const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords(); | |
| 241 | − QMapIterator<QString, PerformanceTimerRecord> i(allRecords); | |
| 242 | − bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen); | |
| 243 | − int statsLines = 0; | |
| 244 | − while (i.hasNext()) { | |
| 245 | − i.next(); | |
| 246 | − if (includeTimingRecord(i.key())) { | |
| 247 | − lines++; | |
| 248 | − statsLines++; | |
| 249 | − if (onlyDisplayTopTen && statsLines == 10) { | |
| 250 | − break; | |
| 251 | − } | |
| 252 | − } | |
| 253 | − } | |
| 86 | +#define STAT_UPDATE_FLOAT(name, src, epsilon) \ | |
| 87 | + { \ | |
| 88 | + float val = src; \ | |
| 89 | + if (fabs(_##name - val) >= epsilon) { \ | |
| 90 | + _##name = val; \ | |
| 91 | + emit name##Changed(); \ | |
| 92 | + } \ | |
| 254 | 93 | } |
| 255 | − | |
| 256 | − drawBackground(backgroundColor, horizontalOffset, 0, columnOneWidth, (lines + 1) * STATS_PELS_PER_LINE); | |
| 257 | − horizontalOffset += 5; | |
| 258 | − | |
| 259 | − int columnOneHorizontalOffset = horizontalOffset; | |
| 260 | − | |
| 261 | − QString serverNodes = QString("Servers: %1").arg(totalServers); | |
| 262 | − QString avatarNodes = QString("Avatars: %1").arg(totalAvatars); | |
| 263 | − QString framesPerSecond = QString("Framerate: %1 FPS").arg(fps, 3, 'f', 0); | |
| 264 | − | |
| 265 | − verticalOffset = STATS_PELS_INITIALOFFSET; // first one is offset by less than a line | |
| 266 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, serverNodes.toUtf8().constData(), color); | |
| 267 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 268 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarNodes.toUtf8().constData(), color); | |
| 269 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 270 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, framesPerSecond.toUtf8().constData(), color); | |
| 271 | − | |
| 272 | − QString packetsPerSecondString = QString("Packets In/Out: %1/%2").arg(inPacketsPerSecond).arg(outPacketsPerSecond); | |
| 273 | − QString averageMegabitsPerSecond = QString("Mbps In/Out: %1/%2"). | |
| 274 | − arg((float)inKbitsPerSecond * 1.0f / 1000.0f). | |
| 275 | − arg((float)outKbitsPerSecond * 1.0f / 1000.0f); | |
| 276 | − | |
| 277 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 278 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, packetsPerSecondString.toUtf8().constData(), color); | |
| 279 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 280 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, averageMegabitsPerSecond.toUtf8().constData(), color); | |
| 281 | 94 | |
| 282 | − | |
| 283 | − // TODO: the display of these timing details should all be moved to JavaScript | |
| 284 | − if (displayPerf && performanceTimerIsActive) { | |
| 285 | − bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen); | |
| 286 | − // Timing details... | |
| 287 | − verticalOffset += STATS_PELS_PER_LINE * 4; // skip 3 lines to be under the other columns | |
| 288 | − drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font, | |
| 289 | − "-------------------------------------------------------- Function " | |
| 290 | − "------------------------------------------------------- --msecs- -calls--", color); | |
| 291 | − | |
| 292 | − // First iterate all the records, and for the ones that should be included, insert them into | |
| 293 | − // a new Map sorted by average time... | |
| 294 | − QMap<float, QString> sortedRecords; | |
| 295 | − const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords(); | |
| 296 | − QMapIterator<QString, PerformanceTimerRecord> i(allRecords); | |
| 297 | 95 | |
| 298 | − while (i.hasNext()) { | |
| 299 | − i.next(); | |
| 300 | − if (includeTimingRecord(i.key())) { | |
| 301 | − float averageTime = (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC; | |
| 302 | − sortedRecords.insertMulti(averageTime, i.key()); | |
| 303 | − } | |
| 96 | +void Stats::updateStats() { | |
| 97 | + if (!Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { | |
| 98 | + if (isVisible()) { | |
| 99 | + setVisible(false); | |
| 304 | 100 | } |
| 305 | − | |
| 306 | − int linesDisplayed = 0; | |
| 307 | − QMapIterator<float, QString> j(sortedRecords); | |
| 308 | − j.toBack(); | |
| 309 | − while (j.hasPrevious()) { | |
| 310 | − j.previous(); | |
| 311 | − QChar noBreakingSpace = QChar::Nbsp; | |
| 312 | − QString functionName = j.value(); | |
| 313 | − const PerformanceTimerRecord& record = allRecords.value(functionName); | |
| 314 | − | |
| 315 | − QString perfLine = QString("%1: %2 [%3]"). | |
| 316 | − arg(QString(qPrintable(functionName)), 120, noBreakingSpace). | |
| 317 | − arg((float)record.getMovingAverage() / (float)USECS_PER_MSEC, 8, 'f', 3, noBreakingSpace). | |
| 318 | − arg((int)record.getCount(), 6, 10, noBreakingSpace); | |
| 319 | − | |
| 320 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 321 | − drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font, perfLine.toUtf8().constData(), color); | |
| 322 | − linesDisplayed++; | |
| 323 | − if (onlyDisplayTopTen && linesDisplayed == 10) { | |
| 324 | − break; | |
| 325 | − } | |
| 101 | + return; | |
| 102 | + } else { | |
| 103 | + if (!isVisible()) { | |
| 104 | + setVisible(true); | |
| 326 | 105 | } |
| 327 | 106 | } |
| 328 | 107 | |
| 108 | + bool shouldDisplayTimingDetail = Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) && | |
| 109 | + Menu::getInstance()->isOptionChecked(MenuOption::Stats) && isExpanded(); | |
| 110 | + if (shouldDisplayTimingDetail != PerformanceTimer::isActive()) { | |
| 111 | + PerformanceTimer::setActive(shouldDisplayTimingDetail); | |
| 112 | + } | |
| 329 | 113 | |
| 330 | − verticalOffset = STATS_PELS_INITIALOFFSET; | |
| 331 | − horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + 1; | |
| 332 | 114 | |
| 333 | − if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { | |
| 334 | − int pingAudio = -1, pingAvatar = -1, pingVoxel = -1, pingOctreeMax = -1; | |
| 115 | + auto nodeList = DependencyManager::get<NodeList>(); | |
| 116 | + auto avatarManager = DependencyManager::get<AvatarManager>(); | |
| 117 | + // we need to take one avatar out so we don't include ourselves | |
| 118 | + STAT_UPDATE(avatarCount, avatarManager->size() - 1); | |
| 119 | + STAT_UPDATE(serverCount, nodeList->size()); | |
| 120 | + STAT_UPDATE(framerate, (int)qApp->getFps()); | |
| 121 | + | |
| 122 | + auto bandwidthRecorder = DependencyManager::get<BandwidthRecorder>(); | |
| 123 | + STAT_UPDATE(packetInCount, bandwidthRecorder->getCachedTotalAverageInputPacketsPerSecond()); | |
| 124 | + STAT_UPDATE(packetOutCount, bandwidthRecorder->getCachedTotalAverageOutputPacketsPerSecond()); | |
| 125 | + STAT_UPDATE_FLOAT(mbpsIn, (float)bandwidthRecorder->getCachedTotalAverageOutputKilobitsPerSecond() / 1000.0f, 0.01f); | |
| 126 | + STAT_UPDATE_FLOAT(mbpsOut, (float)bandwidthRecorder->getCachedTotalAverageInputKilobitsPerSecond() / 1000.0f, 0.01f); | |
| 335 | 127 | |
| 336 | − auto nodeList = DependencyManager::get<NodeList>(); | |
| 128 | + // Second column: ping | |
| 129 | + if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { | |
| 337 | 130 | SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer); |
| 338 | 131 | SharedNodePointer avatarMixerNode = nodeList->soloNodeOfType(NodeType::AvatarMixer); |
| 132 | + STAT_UPDATE(audioPing, audioMixerNode ? audioMixerNode->getPingMs() : -1); | |
| 133 | + STAT_UPDATE(avatarPing, avatarMixerNode ? avatarMixerNode->getPingMs() : -1); | |
| 339 | 134 | |
| 340 | − pingAudio = audioMixerNode ? audioMixerNode->getPingMs() : -1; | |
| 341 | − pingAvatar = avatarMixerNode ? avatarMixerNode->getPingMs() : -1; | |
| 342 | − | |
| 343 | − // Now handle voxel servers, since there could be more than one, we average their ping times | |
| 135 | + //// Now handle voxel servers, since there could be more than one, we average their ping times | |
| 344 | 136 | unsigned long totalPingOctree = 0; |
| 345 | 137 | int octreeServerCount = 0; |
| 346 | − | |
| 347 | − nodeList->eachNode([&totalPingOctree, &pingOctreeMax, &octreeServerCount](const SharedNodePointer& node){ | |
| 138 | + int pingOctreeMax = 0; | |
| 139 | + int pingVoxel; | |
| 140 | + nodeList->eachNode([&](const SharedNodePointer& node) { | |
| 348 | 141 | // TODO: this should also support entities |
| 349 | 142 | if (node->getType() == NodeType::EntityServer) { |
| 350 | 143 | totalPingOctree += node->getPingMs(); |
| @@ -359,168 +152,85 @@ void Stats::display( · 8 unmodified lines | ||
| 359 | 152 | pingVoxel = totalPingOctree / octreeServerCount; |
| 360 | 153 | } |
| 361 | 154 | |
| 362 | − lines = _expanded ? 4 : 3; | |
| 363 | − | |
| 364 | − // only draw our background if column one didn't draw a wide background | |
| 365 | − if (columnOneWidth == _generalStatsWidth) { | |
| 366 | − drawBackground(backgroundColor, horizontalOffset, 0, _pingStatsWidth, (lines + 1) * STATS_PELS_PER_LINE); | |
| 367 | − } | |
| 368 | − horizontalOffset += 5; | |
| 369 | − | |
| 370 | − | |
| 371 | − QString audioPing; | |
| 372 | − if (pingAudio >= 0) { | |
| 373 | − audioPing = QString("Audio ping: %1").arg(pingAudio); | |
| 374 | − } else { | |
| 375 | − audioPing = QString("Audio ping: --"); | |
| 376 | − } | |
| 377 | − | |
| 378 | − QString avatarPing; | |
| 379 | − if (pingAvatar >= 0) { | |
| 380 | − avatarPing = QString("Avatar ping: %1").arg(pingAvatar); | |
| 381 | − } else { | |
| 382 | − avatarPing = QString("Avatar ping: --"); | |
| 383 | − } | |
| 384 | − | |
| 385 | − QString voxelAvgPing; | |
| 386 | − if (pingVoxel >= 0) { | |
| 387 | − voxelAvgPing = QString("Entities avg ping: %1").arg(pingVoxel); | |
| 388 | − } else { | |
| 389 | − voxelAvgPing = QString("Entities avg ping: --"); | |
| 390 | − } | |
| 391 | − | |
| 392 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, audioPing.toUtf8().constData(), color); | |
| 393 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 394 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarPing.toUtf8().constData(), color); | |
| 395 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 396 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, voxelAvgPing.toUtf8().constData(), color); | |
| 397 | − | |
| 398 | − if (_expanded) { | |
| 399 | − QString voxelMaxPing; | |
| 400 | − if (pingVoxel >= 0) { // Average is only meaningful if pingVoxel is valid. | |
| 401 | − voxelMaxPing = QString("Voxel max ping: %1").arg(pingOctreeMax); | |
| 402 | − } else { | |
| 403 | − voxelMaxPing = QString("Voxel max ping: --"); | |
| 404 | − } | |
| 405 | − | |
| 406 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 407 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, voxelMaxPing.toUtf8().constData(), color); | |
| 408 | − } | |
| 409 | − | |
| 410 | − verticalOffset = STATS_PELS_INITIALOFFSET; | |
| 411 | − horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + _pingStatsWidth + 2; | |
| 155 | + //STAT_UPDATE(entitiesPing, pingVoxel); | |
| 156 | + //if (_expanded) { | |
| 157 | + // QString voxelMaxPing; | |
| 158 | + // if (pingVoxel >= 0) { // Average is only meaningful if pingVoxel is valid. | |
| 159 | + // voxelMaxPing = QString("Voxel max ping: %1").arg(pingOctreeMax); | |
| 160 | + // } else { | |
| 161 | + // voxelMaxPing = QString("Voxel max ping: --"); | |
| 162 | + // } | |
| 163 | + } else { | |
| 164 | + // -2 causes the QML to hide the ping column | |
| 165 | + STAT_UPDATE(audioPing, -2); | |
| 412 | 166 | } |
| 413 | 167 | |
| 414 | − MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 415 | − glm::vec3 avatarPos = myAvatar->getPosition(); | |
| 416 | − | |
| 417 | − lines = _expanded ? 7 : 3; | |
| 418 | − | |
| 419 | − if (columnOneWidth == _generalStatsWidth) { | |
| 420 | − drawBackground(backgroundColor, horizontalOffset, 0, _geoStatsWidth, (lines + 1) * STATS_PELS_PER_LINE); | |
| 421 | − } | |
| 422 | − horizontalOffset += 5; | |
| 423 | − | |
| 424 | − QString avatarPosition = QString("Position: %1, %2, %3"). | |
| 425 | − arg(avatarPos.x, -1, 'f', 1). | |
| 426 | − arg(avatarPos.y, -1, 'f', 1). | |
| 427 | − arg(avatarPos.z, -1, 'f', 1); | |
| 428 | − QString avatarVelocity = QString("Velocity: %1").arg(glm::length(myAvatar->getVelocity()), -1, 'f', 1); | |
| 429 | − QString avatarBodyYaw = QString("Yaw: %1").arg(myAvatar->getBodyYaw(), -1, 'f', 1); | |
| 430 | − QString avatarMixerStats; | |
| 431 | − | |
| 432 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarPosition.toUtf8().constData(), color); | |
| 433 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 434 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarVelocity.toUtf8().constData(), color); | |
| 435 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 436 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarBodyYaw.toUtf8().constData(), color); | |
| 437 | 168 | |
| 169 | + // Third column, avatar stats | |
| 170 | + MyAvatar* myAvatar = avatarManager->getMyAvatar(); | |
| 171 | + glm::vec3 avatarPos = myAvatar->getPosition(); | |
| 172 | + STAT_UPDATE(position, QVector3D(avatarPos.x, avatarPos.y, avatarPos.z)); | |
| 173 | + STAT_UPDATE_FLOAT(velocity, glm::length(myAvatar->getVelocity()), 0.1f); | |
| 174 | + STAT_UPDATE_FLOAT(yaw, myAvatar->getBodyYaw(), 0.1f); | |
| 438 | 175 | if (_expanded) { |
| 439 | − SharedNodePointer avatarMixer = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::AvatarMixer); | |
| 176 | + SharedNodePointer avatarMixer = nodeList->soloNodeOfType(NodeType::AvatarMixer); | |
| 440 | 177 | if (avatarMixer) { |
| 441 | − avatarMixerStats = QString("Avatar Mixer: %1 kbps, %2 pps"). | |
| 442 | − arg(roundf(bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer) + | |
| 443 | − bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AudioMixer))). | |
| 444 | − arg(roundf(bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer) + | |
| 445 | − bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer))); | |
| 178 | + STAT_UPDATE(avatarMixerKbps, roundf( | |
| 179 | + bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AvatarMixer) + | |
| 180 | + bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AvatarMixer))); | |
| 181 | + STAT_UPDATE(avatarMixerPps, roundf( | |
| 182 | + bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AvatarMixer) + | |
| 183 | + bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AvatarMixer))); | |
| 446 | 184 | } else { |
| 447 | − avatarMixerStats = QString("No Avatar Mixer"); | |
| 185 | + STAT_UPDATE(avatarMixerKbps, -1); | |
| 186 | + STAT_UPDATE(avatarMixerPps, -1); | |
| 448 | 187 | } |
| 449 | − | |
| 450 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 451 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarMixerStats.toUtf8().constData(), color); | |
| 452 | − | |
| 453 | − stringstream downloads; | |
| 454 | − downloads << "Downloads: "; | |
| 455 | − foreach (Resource* resource, ResourceCache::getLoadingRequests()) { | |
| 456 | − downloads << (int)(resource->getProgress() * 100.0f) << "% "; | |
| 188 | + SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer); | |
| 189 | + if (audioMixerNode) { | |
| 190 | + STAT_UPDATE(audioMixerKbps, roundf( | |
| 191 | + bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer) + | |
| 192 | + bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AudioMixer))); | |
| 193 | + STAT_UPDATE(audioMixerPps, roundf( | |
| 194 | + bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer) + | |
| 195 | + bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer))); | |
| 196 | + } else { | |
| 197 | + STAT_UPDATE(audioMixerKbps, -1); | |
| 198 | + STAT_UPDATE(audioMixerPps, -1); | |
| 457 | 199 | } |
| 458 | − downloads << "(" << ResourceCache::getPendingRequestCount() << " pending)"; | |
| 459 | − | |
| 460 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 461 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, downloads.str().c_str(), color); | |
| 462 | − } | |
| 463 | 200 | |
| 464 | − verticalOffset = STATS_PELS_INITIALOFFSET; | |
| 465 | − horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3; | |
| 466 | − | |
| 467 | − lines = _expanded ? 10 : 3; | |
| 468 | − | |
| 469 | − drawBackground(backgroundColor, horizontalOffset, 0, canvasSize.x - horizontalOffset, | |
| 470 | − (lines + 1) * STATS_PELS_PER_LINE); | |
| 471 | − horizontalOffset += 5; | |
| 472 | − | |
| 473 | − // Model/Entity render details | |
| 474 | − octreeStats.str(""); | |
| 475 | − octreeStats << "Triangles: " << _renderDetails._trianglesRendered | |
| 476 | − << " / Quads:" << _renderDetails._quadsRendered | |
| 477 | − << " / Material Switches:" << _renderDetails._materialSwitches; | |
| 478 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 479 | − | |
| 480 | − if (_expanded) { | |
| 481 | − octreeStats.str(""); | |
| 482 | − octreeStats << " Mesh Parts Rendered Opaque: " << _renderDetails._opaque._rendered | |
| 483 | − << " / Translucent:" << _renderDetails._translucent._rendered; | |
| 484 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 485 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 486 | − | |
| 487 | − octreeStats.str(""); | |
| 488 | − octreeStats << " Opaque considered: " << _renderDetails._opaque._considered | |
| 489 | − << " / Out of view:" << _renderDetails._opaque._outOfView | |
| 490 | − << " / Too small:" << _renderDetails._opaque._tooSmall; | |
| 491 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 492 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 493 | − | |
| 494 | − octreeStats.str(""); | |
| 495 | − octreeStats << " Translucent considered: " << _renderDetails._translucent._considered | |
| 496 | − << " / Out of view:" << _renderDetails._translucent._outOfView | |
| 497 | − << " / Too small:" << _renderDetails._translucent._tooSmall; | |
| 498 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 499 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 500 | − } | |
| 501 | − | |
| 502 | − // iterate all the current voxel stats, and list their sending modes, and total voxel counts | |
| 503 | − std::stringstream sendingMode(""); | |
| 504 | − sendingMode << "Octree Sending Mode: ["; | |
| 201 | + STAT_UPDATE(downloads, ResourceCache::getLoadingRequests().size()); | |
| 202 | + STAT_UPDATE(downloadsPending, ResourceCache::getPendingRequestCount()); | |
| 203 | + // TODO fix to match original behavior | |
| 204 | + //stringstream downloads; | |
| 205 | + //downloads << "Downloads: "; | |
| 206 | + //foreach(Resource* resource, ) { | |
| 207 | + // downloads << (int)(resource->getProgress() * 100.0f) << "% "; | |
| 208 | + //} | |
| 209 | + //downloads << "(" << << " pending)"; | |
| 210 | + } // expanded avatar column | |
| 211 | + | |
| 212 | + // Fourth column, octree stats | |
| 505 | 213 | int serverCount = 0; |
| 506 | 214 | int movingServerCount = 0; |
| 507 | 215 | unsigned long totalNodes = 0; |
| 508 | 216 | unsigned long totalInternal = 0; |
| 509 | 217 | unsigned long totalLeaves = 0; |
| 218 | + std::stringstream sendingModeStream(""); | |
| 219 | + sendingModeStream << "["; | |
| 510 | 220 | NodeToOctreeSceneStats* octreeServerSceneStats = Application::getInstance()->getOcteeSceneStats(); |
| 511 | − for(NodeToOctreeSceneStatsIterator i = octreeServerSceneStats->begin(); i != octreeServerSceneStats->end(); i++) { | |
| 221 | + for (NodeToOctreeSceneStatsIterator i = octreeServerSceneStats->begin(); i != octreeServerSceneStats->end(); i++) { | |
| 512 | 222 | //const QUuid& uuid = i->first; |
| 513 | 223 | OctreeSceneStats& stats = i->second; |
| 514 | 224 | serverCount++; |
| 515 | 225 | if (_expanded) { |
| 516 | 226 | if (serverCount > 1) { |
| 517 | − sendingMode << ","; | |
| 227 | + sendingModeStream << ","; | |
| 518 | 228 | } |
| 519 | 229 | if (stats.isMoving()) { |
| 520 | − sendingMode << "M"; | |
| 230 | + sendingModeStream << "M"; | |
| 521 | 231 | movingServerCount++; |
| 522 | 232 | } else { |
| 523 | − sendingMode << "S"; | |
| 233 | + sendingModeStream << "S"; | |
| 524 | 234 | } |
| 525 | 235 | } |
| 526 | 236 | |
| @@ -528,32 +238,35 @@ void Stats::display( · 1 unmodified line | ||
| 528 | 238 | totalNodes += stats.getTotalElements(); |
| 529 | 239 | if (_expanded) { |
| 530 | 240 | totalInternal += stats.getTotalInternal(); |
| 531 | − totalLeaves += stats.getTotalLeaves(); | |
| 241 | + totalLeaves += stats.getTotalLeaves(); | |
| 532 | 242 | } |
| 533 | 243 | } |
| 534 | 244 | if (_expanded) { |
| 535 | 245 | if (serverCount == 0) { |
| 536 | − sendingMode << "---"; | |
| 246 | + sendingModeStream << "---"; | |
| 537 | 247 | } |
| 538 | − sendingMode << "] " << serverCount << " servers"; | |
| 248 | + sendingModeStream << "] " << serverCount << " servers"; | |
| 539 | 249 | if (movingServerCount > 0) { |
| 540 | − sendingMode << " <SCENE NOT STABLE>"; | |
| 250 | + sendingModeStream << " <SCENE NOT STABLE>"; | |
| 541 | 251 | } else { |
| 542 | − sendingMode << " <SCENE STABLE>"; | |
| 252 | + sendingModeStream << " <SCENE STABLE>"; | |
| 543 | 253 | } |
| 544 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 545 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)sendingMode.str().c_str(), color); | |
| 254 | + QString sendingModeResult = sendingModeStream.str().c_str(); | |
| 255 | + STAT_UPDATE(sendingMode, sendingModeResult); | |
| 546 | 256 | } |
| 547 | 257 | |
| 548 | 258 | // Incoming packets |
| 259 | + QLocale locale(QLocale::English); | |
| 260 | + auto voxelPacketsToProcess = qApp->getOctreePacketProcessor().packetsToProcessCount(); | |
| 549 | 261 | if (_expanded) { |
| 550 | − octreeStats.str(""); | |
| 262 | + std::stringstream octreeStats; | |
| 551 | 263 | QString packetsString = locale.toString((int)voxelPacketsToProcess); |
| 552 | 264 | QString maxString = locale.toString((int)_recentMaxPackets); |
| 553 | 265 | octreeStats << "Octree Packets to Process: " << qPrintable(packetsString) |
| 554 | − << " [Recent Max: " << qPrintable(maxString) << "]"; | |
| 555 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 556 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 266 | + << " [Recent Max: " << qPrintable(maxString) << "]"; | |
| 267 | + QString str = octreeStats.str().c_str(); | |
| 268 | + STAT_UPDATE(packetStats, str); | |
| 269 | + // drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 557 | 270 | } |
| 558 | 271 | |
| 559 | 272 | if (_resetRecentMaxPacketsSoon && voxelPacketsToProcess > 0) { |
| @@ -562,60 +275,102 @@ void Stats::display( · 2 unmodified lines | ||
| 562 | 275 | } |
| 563 | 276 | if (voxelPacketsToProcess == 0) { |
| 564 | 277 | _resetRecentMaxPacketsSoon = true; |
| 565 | − } else { | |
| 566 | − if (voxelPacketsToProcess > _recentMaxPackets) { | |
| 567 | − _recentMaxPackets = voxelPacketsToProcess; | |
| 568 | − } | |
| 278 | + } else if (voxelPacketsToProcess > _recentMaxPackets) { | |
| 279 | + _recentMaxPackets = voxelPacketsToProcess; | |
| 569 | 280 | } |
| 570 | 281 | |
| 571 | − QString serversTotalString = locale.toString((uint)totalNodes); // consider adding: .rightJustified(10, ' '); | |
| 572 | − unsigned long localTotal = OctreeElement::getNodeCount(); | |
| 573 | − QString localTotalString = locale.toString((uint)localTotal); // consider adding: .rightJustified(10, ' '); | |
| 574 | − | |
| 575 | 282 | // Server Octree Elements |
| 576 | − if (!_expanded) { | |
| 577 | − octreeStats.str(""); | |
| 578 | − octreeStats << "Octree Elements Server: " << qPrintable(serversTotalString) | |
| 579 | − << " Local:" << qPrintable(localTotalString); | |
| 580 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 581 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 582 | − } | |
| 283 | + STAT_UPDATE(serverElements, totalNodes); | |
| 284 | + STAT_UPDATE(localElements, OctreeElement::getNodeCount()); | |
| 583 | 285 | |
| 584 | 286 | if (_expanded) { |
| 585 | − octreeStats.str(""); | |
| 586 | − octreeStats << "Octree Elements -"; | |
| 587 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 588 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 287 | + STAT_UPDATE(serverInternal, totalInternal); | |
| 288 | + STAT_UPDATE(serverLeaves, totalLeaves); | |
| 289 | + // Local Voxels | |
| 290 | + STAT_UPDATE(localInternal, OctreeElement::getInternalNodeCount()); | |
| 291 | + STAT_UPDATE(localLeaves, OctreeElement::getLeafNodeCount()); | |
| 292 | + // LOD Details | |
| 293 | + STAT_UPDATE(lodStatus, "You can see " + DependencyManager::get<LODManager>()->getLODFeedbackText()); | |
| 294 | + } | |
| 589 | 295 | |
| 590 | − QString serversInternalString = locale.toString((uint)totalInternal); | |
| 591 | − QString serversLeavesString = locale.toString((uint)totalLeaves); | |
| 296 | + bool performanceTimerIsActive = PerformanceTimer::isActive(); | |
| 297 | + bool displayPerf = _expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails); | |
| 298 | + if (displayPerf && performanceTimerIsActive) { | |
| 299 | + if (!_timingExpanded) { | |
| 300 | + _timingExpanded = true; | |
| 301 | + emit timingExpandedChanged(); | |
| 302 | + } | |
| 303 | + PerformanceTimer::tallyAllTimerRecords(); // do this even if we're not displaying them, so they don't stack up | |
| 592 | 304 | |
| 593 | − octreeStats.str(""); | |
| 594 | − octreeStats << " Server: " << qPrintable(serversTotalString) << | |
| 595 | − " Internal: " << qPrintable(serversInternalString) << | |
| 596 | − " Leaves: " << qPrintable(serversLeavesString); | |
| 597 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 598 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 305 | + // we will also include room for 1 line per timing record and a header of 4 lines | |
| 306 | + // Timing details... | |
| 599 | 307 | |
| 600 | − // Local Voxels | |
| 601 | − unsigned long localInternal = OctreeElement::getInternalNodeCount(); | |
| 602 | − unsigned long localLeaves = OctreeElement::getLeafNodeCount(); | |
| 603 | − QString localInternalString = locale.toString((uint)localInternal); | |
| 604 | − QString localLeavesString = locale.toString((uint)localLeaves); | |
| 605 | − | |
| 606 | − octreeStats.str(""); | |
| 607 | − octreeStats << " Local: " << qPrintable(serversTotalString) << | |
| 608 | − " Internal: " << qPrintable(localInternalString) << | |
| 609 | − " Leaves: " << qPrintable(localLeavesString) << ""; | |
| 610 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 611 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 308 | + // First iterate all the records, and for the ones that should be included, insert them into | |
| 309 | + // a new Map sorted by average time... | |
| 310 | + bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen); | |
| 311 | + QMap<float, QString> sortedRecords; | |
| 312 | + const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords(); | |
| 313 | + QMapIterator<QString, PerformanceTimerRecord> i(allRecords); | |
| 314 | + | |
| 315 | + while (i.hasNext()) { | |
| 316 | + i.next(); | |
| 317 | + if (includeTimingRecord(i.key())) { | |
| 318 | + float averageTime = (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC; | |
| 319 | + sortedRecords.insertMulti(averageTime, i.key()); | |
| 320 | + } | |
| 321 | + } | |
| 322 | + | |
| 323 | + int linesDisplayed = 0; | |
| 324 | + QMapIterator<float, QString> j(sortedRecords); | |
| 325 | + j.toBack(); | |
| 326 | + QString perfLines; | |
| 327 | + while (j.hasPrevious()) { | |
| 328 | + j.previous(); | |
| 329 | + static const QChar noBreakingSpace = QChar::Nbsp; | |
| 330 | + QString functionName = j.value(); | |
| 331 | + const PerformanceTimerRecord& record = allRecords.value(functionName); | |
| 332 | + perfLines += QString("%1: %2 [%3]\n"). | |
| 333 | + arg(QString(qPrintable(functionName)), 90, noBreakingSpace). | |
| 334 | + arg((float)record.getMovingAverage() / (float)USECS_PER_MSEC, 8, 'f', 3, noBreakingSpace). | |
| 335 | + arg((int)record.getCount(), 6, 10, noBreakingSpace); | |
| 336 | + linesDisplayed++; | |
| 337 | + if (onlyDisplayTopTen && linesDisplayed == 10) { | |
| 338 | + break; | |
| 339 | + } | |
| 340 | + } | |
| 341 | + _timingStats = perfLines; | |
| 342 | + emit timingStatsChanged(); | |
| 343 | + } else if (_timingExpanded) { | |
| 344 | + _timingExpanded = false; | |
| 345 | + emit timingExpandedChanged(); | |
| 612 | 346 | } |
| 347 | +} | |
| 348 | + | |
| 349 | +void Stats::setRenderDetails(const RenderDetails& details) { | |
| 350 | + STAT_UPDATE(triangles, details._trianglesRendered); | |
| 351 | + STAT_UPDATE(quads, details._quadsRendered); | |
| 352 | + STAT_UPDATE(materialSwitches, details._materialSwitches); | |
| 353 | + if (_expanded) { | |
| 354 | + STAT_UPDATE(meshOpaque, details._opaque._rendered); | |
| 355 | + STAT_UPDATE(meshTranslucent, details._opaque._rendered); | |
| 356 | + STAT_UPDATE(opaqueConsidered, details._opaque._considered); | |
| 357 | + STAT_UPDATE(opaqueOutOfView, details._opaque._outOfView); | |
| 358 | + STAT_UPDATE(opaqueTooSmall, details._opaque._tooSmall); | |
| 359 | + STAT_UPDATE(translucentConsidered, details._translucent._considered); | |
| 360 | + STAT_UPDATE(translucentOutOfView, details._translucent._outOfView); | |
| 361 | + STAT_UPDATE(translucentTooSmall, details._translucent._tooSmall); | |
| 362 | + } | |
| 363 | +} | |
| 364 | + | |
| 365 | + | |
| 366 | +/* | |
| 367 | +// display expanded or contracted stats | |
| 368 | +void Stats::display( | |
| 369 | + int voxelPacketsToProcess) | |
| 370 | +{ | |
| 371 | + // iterate all the current voxel stats, and list their sending modes, and total voxel counts | |
| 613 | 372 | |
| 614 | − // LOD Details | |
| 615 | − octreeStats.str(""); | |
| 616 | − QString displayLODDetails = DependencyManager::get<LODManager>()->getLODFeedbackText(); | |
| 617 | − octreeStats << "LOD: You can see " << qPrintable(displayLODDetails.trimmed()); | |
| 618 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 619 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 620 | 373 | } |
| 621 | 374 | |
| 375 | + | |
| 376 | +*/ | |
| @@ -1,8 +1,5 @@ | ||
| 1 | 1 | // |
| 2 | −// Stats.h | |
| 3 | −// interface/src/ui | |
| 4 | −// | |
| 5 | −// Created by Lucas Crisman on 22/03/14. | |
| 2 | +// Created by Bradley Austin Davis 2015/06/17 | |
| 6 | 3 | // Copyright 2013 High Fidelity, Inc. |
| 7 | 4 | // |
| 8 | 5 | // Distributed under the Apache License, Version 2.0. |
| @@ -13,47 +10,139 @@ · 4 unmodified lines | ||
| 13 | 10 | #define hifi_Stats_h |
| 14 | 11 | |
| 15 | 12 | #include <QObject> |
| 13 | +#include <QQuickItem> | |
| 14 | +#include <QVector3D> | |
| 16 | 15 | |
| 16 | +#include <OffscreenUi.h> | |
| 17 | 17 | #include <RenderArgs.h> |
| 18 | 18 | |
| 19 | −class Stats: public QObject { | |
| 19 | +#define STATS_PROPERTY(type, name, initialValue) \ | |
| 20 | + Q_PROPERTY(type name READ name NOTIFY name##Changed) \ | |
| 21 | +public: \ | |
| 22 | + type name() { return _##name; }; \ | |
| 23 | +private: \ | |
| 24 | + type _##name{ initialValue }; | |
| 25 | + | |
| 26 | + | |
| 27 | +class Stats : public QQuickItem { | |
| 20 | 28 | Q_OBJECT |
| 29 | + HIFI_QML_DECL | |
| 30 | + Q_PROPERTY(bool expanded READ isExpanded WRITE setExpanded NOTIFY expandedChanged) | |
| 31 | + Q_PROPERTY(bool timingExpanded READ isTimingExpanded NOTIFY timingExpandedChanged) | |
| 32 | + Q_PROPERTY(QString monospaceFont READ monospaceFont) | |
| 33 | + | |
| 34 | + STATS_PROPERTY(int, serverCount, 0) | |
| 35 | + STATS_PROPERTY(int, framerate, 0) | |
| 36 | + STATS_PROPERTY(int, avatarCount, 0) | |
| 37 | + STATS_PROPERTY(int, packetInCount, 0) | |
| 38 | + STATS_PROPERTY(int, packetOutCount, 0) | |
| 39 | + STATS_PROPERTY(float, mbpsIn, 0) | |
| 40 | + STATS_PROPERTY(float, mbpsOut, 0) | |
| 41 | + STATS_PROPERTY(int, audioPing, 0) | |
| 42 | + STATS_PROPERTY(int, avatarPing, 0) | |
| 43 | + STATS_PROPERTY(int, entitiesPing, 0) | |
| 44 | + STATS_PROPERTY(QVector3D, position, QVector3D(0, 0, 0) ) | |
| 45 | + STATS_PROPERTY(float, velocity, 0) | |
| 46 | + STATS_PROPERTY(float, yaw, 0) | |
| 47 | + STATS_PROPERTY(int, avatarMixerKbps, 0) | |
| 48 | + STATS_PROPERTY(int, avatarMixerPps, 0) | |
| 49 | + STATS_PROPERTY(int, audioMixerKbps, 0) | |
| 50 | + STATS_PROPERTY(int, audioMixerPps, 0) | |
| 51 | + STATS_PROPERTY(int, downloads, 0) | |
| 52 | + STATS_PROPERTY(int, downloadsPending, 0) | |
| 53 | + STATS_PROPERTY(int, triangles, 0) | |
| 54 | + STATS_PROPERTY(int, quads, 0) | |
| 55 | + STATS_PROPERTY(int, materialSwitches, 0) | |
| 56 | + STATS_PROPERTY(int, meshOpaque, 0) | |
| 57 | + STATS_PROPERTY(int, meshTranslucent, 0) | |
| 58 | + STATS_PROPERTY(int, opaqueConsidered, 0) | |
| 59 | + STATS_PROPERTY(int, opaqueOutOfView, 0) | |
| 60 | + STATS_PROPERTY(int, opaqueTooSmall, 0) | |
| 61 | + STATS_PROPERTY(int, translucentConsidered, 0) | |
| 62 | + STATS_PROPERTY(int, translucentOutOfView, 0) | |
| 63 | + STATS_PROPERTY(int, translucentTooSmall, 0) | |
| 64 | + STATS_PROPERTY(QString, sendingMode, QString()) | |
| 65 | + STATS_PROPERTY(QString, packetStats, QString()) | |
| 66 | + STATS_PROPERTY(QString, lodStatus, QString()) | |
| 67 | + STATS_PROPERTY(QString, timingStats, QString()) | |
| 68 | + STATS_PROPERTY(int, serverElements, 0) | |
| 69 | + STATS_PROPERTY(int, serverInternal, 0) | |
| 70 | + STATS_PROPERTY(int, serverLeaves, 0) | |
| 71 | + STATS_PROPERTY(int, localElements, 0) | |
| 72 | + STATS_PROPERTY(int, localInternal, 0) | |
| 73 | + STATS_PROPERTY(int, localLeaves, 0) | |
| 21 | 74 | |
| 22 | 75 | public: |
| 23 | 76 | static Stats* getInstance(); |
| 24 | 77 | |
| 25 | − Stats(); | |
| 26 | − | |
| 27 | − static void drawBackground(unsigned int rgba, int x, int y, int width, int height); | |
| 28 | − | |
| 29 | − void toggleExpanded(); | |
| 30 | − bool isExpanded() { return _expanded; } | |
| 31 | − | |
| 32 | − void checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseDragStartedY, int horizontalOffset); | |
| 33 | − void resetWidth(int width, int horizontalOffset); | |
| 34 | − void display(const float* color, int horizontalOffset, float fps, int inPacketsPerSecond, int outPacketsPerSecond, | |
| 35 | − int inKbitsPerSecond, int outKbitsPerSecond, int voxelPacketsToProcess); | |
| 78 | + Stats(QQuickItem* parent = nullptr); | |
| 36 | 79 | bool includeTimingRecord(const QString& name); |
| 37 | − | |
| 38 | − void setRenderDetails(const RenderDetails& details) { _renderDetails = details; } | |
| 39 | − | |
| 40 | −private: | |
| 41 | − static Stats* _sharedInstance; | |
| 80 | + void setRenderDetails(const RenderDetails& details); | |
| 81 | + const QString& monospaceFont() { | |
| 82 | + return _monospaceFont; | |
| 83 | + } | |
| 84 | + void updateStats(); | |
| 42 | 85 | |
| 43 | − bool _expanded; | |
| 86 | + bool isExpanded() { return _expanded; } | |
| 87 | + bool isTimingExpanded() { return _timingExpanded; } | |
| 44 | 88 | |
| 45 | − int _recentMaxPackets; // recent max incoming voxel packets to process | |
| 46 | − bool _resetRecentMaxPacketsSoon; | |
| 89 | + void setExpanded(bool expanded) { | |
| 90 | + if (_expanded != expanded) { | |
| 91 | + _expanded = expanded; | |
| 92 | + emit expandedChanged(); | |
| 93 | + } | |
| 94 | + } | |
| 47 | 95 | |
| 48 | − int _generalStatsWidth; | |
| 49 | − int _bandwidthStatsWidth; | |
| 50 | − int _pingStatsWidth; | |
| 51 | − int _geoStatsWidth; | |
| 52 | − int _octreeStatsWidth; | |
| 96 | +signals: | |
| 97 | + void expandedChanged(); | |
| 98 | + void timingExpandedChanged(); | |
| 99 | + void serverCountChanged(); | |
| 100 | + void framerateChanged(); | |
| 101 | + void avatarCountChanged(); | |
| 102 | + void packetInCountChanged(); | |
| 103 | + void packetOutCountChanged(); | |
| 104 | + void mbpsInChanged(); | |
| 105 | + void mbpsOutChanged(); | |
| 106 | + void audioPingChanged(); | |
| 107 | + void avatarPingChanged(); | |
| 108 | + void entitiesPingChanged(); | |
| 109 | + void positionChanged(); | |
| 110 | + void velocityChanged(); | |
| 111 | + void yawChanged(); | |
| 112 | + void avatarMixerKbpsChanged(); | |
| 113 | + void avatarMixerPpsChanged(); | |
| 114 | + void audioMixerKbpsChanged(); | |
| 115 | + void audioMixerPpsChanged(); | |
| 116 | + void downloadsChanged(); | |
| 117 | + void downloadsPendingChanged(); | |
| 118 | + void trianglesChanged(); | |
| 119 | + void quadsChanged(); | |
| 120 | + void materialSwitchesChanged(); | |
| 121 | + void meshOpaqueChanged(); | |
| 122 | + void meshTranslucentChanged(); | |
| 123 | + void opaqueConsideredChanged(); | |
| 124 | + void opaqueOutOfViewChanged(); | |
| 125 | + void opaqueTooSmallChanged(); | |
| 126 | + void translucentConsideredChanged(); | |
| 127 | + void translucentOutOfViewChanged(); | |
| 128 | + void translucentTooSmallChanged(); | |
| 129 | + void sendingModeChanged(); | |
| 130 | + void packetStatsChanged(); | |
| 131 | + void lodStatusChanged(); | |
| 132 | + void serverElementsChanged(); | |
| 133 | + void serverInternalChanged(); | |
| 134 | + void serverLeavesChanged(); | |
| 135 | + void localElementsChanged(); | |
| 136 | + void localInternalChanged(); | |
| 137 | + void localLeavesChanged(); | |
| 138 | + void timingStatsChanged(); | |
| 53 | 139 | |
| 54 | − int _lastHorizontalOffset; | |
| 55 | − | |
| 56 | − RenderDetails _renderDetails; | |
| 140 | +private: | |
| 141 | + int _recentMaxPackets{ 0 } ; // recent max incoming voxel packets to process | |
| 142 | + bool _resetRecentMaxPacketsSoon{ true }; | |
| 143 | + bool _expanded{ false }; | |
| 144 | + bool _timingExpanded{ false }; | |
| 145 | + QString _monospaceFont; | |
| 57 | 146 | }; |
| 58 | 147 | |
| 59 | 148 | #endif // hifi_Stats_h |
| @@ -53,7 +53,7 @@ void UserInputMapper::resetDevice(uint16 deviceID) { · 52 unmodified lines | ||
| 53 | 53 | |
| 54 | 54 | int UserInputMapper::findDevice(QString name) { |
| 55 | 55 | for (auto device : _registeredDevices) { |
| 56 | − if (device.second->_name == name) { | |
| 56 | + if (device.second->_name.split(" (")[0] == name) { | |
| 57 | 57 | return device.first; |
| 58 | 58 | } |
| 59 | 59 | } |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | ||
| 11 | 11 | // include this before QGLWidget, which includes an earlier version of OpenGL |
| 12 | 12 | #include "InterfaceConfig.h" |
| 13 | 13 | |
| 14 | +#include <DeferredLightingEffect.h> | |
| 14 | 15 | #include <GeometryCache.h> |
| 15 | 16 | #include <GlowEffect.h> |
| 16 | 17 | #include <SharedUtil.h> |
| @@ -75,20 +76,20 @@ void Circle3DOverlay::render(RenderArgs* args) { · 58 unmodified lines | ||
| 75 | 76 | |
| 76 | 77 | float alpha = getAlpha(); |
| 77 | 78 | |
| 78 | − if (alpha == 0.0) { | |
| 79 | + if (alpha == 0.0f) { | |
| 79 | 80 | return; // do nothing if our alpha is 0, we're not visible |
| 80 | 81 | } |
| 81 | − | |
| 82 | + | |
| 82 | 83 | // Create the circle in the coordinates origin |
| 83 | 84 | float outerRadius = getOuterRadius(); |
| 84 | 85 | float innerRadius = getInnerRadius(); // only used in solid case |
| 85 | 86 | float startAt = getStartAt(); |
| 86 | 87 | float endAt = getEndAt(); |
| 87 | − | |
| 88 | + | |
| 88 | 89 | bool geometryChanged = (startAt != _lastStartAt || endAt != _lastEndAt || |
| 89 | 90 | innerRadius != _lastInnerRadius || outerRadius != _lastOuterRadius); |
| 90 | 91 | |
| 91 | − | |
| 92 | + | |
| 92 | 93 | const float FULL_CIRCLE = 360.0f; |
| 93 | 94 | const float SLICES = 180.0f; // The amount of segment to create the circle |
| 94 | 95 | const float SLICE_ANGLE = FULL_CIRCLE / SLICES; |
| @@ -101,195 +102,178 @@ void Circle3DOverlay::render(RenderArgs* args) { · 6 unmodified lines | ||
| 101 | 102 | bool colorChanged = colorX.red != _lastColor.red || colorX.green != _lastColor.green || colorX.blue != _lastColor.blue; |
| 102 | 103 | _lastColor = colorX; |
| 103 | 104 | |
| 104 | − glDisable(GL_LIGHTING); | |
| 105 | − | |
| 106 | − glm::vec3 position = getPosition(); | |
| 107 | − glm::vec3 center = getCenter(); | |
| 108 | − glm::vec2 dimensions = getDimensions(); | |
| 109 | − glm::quat rotation = getRotation(); | |
| 110 | − | |
| 111 | − float glowLevel = getGlowLevel(); | |
| 112 | − Glower* glower = NULL; | |
| 113 | − if (glowLevel > 0.0f) { | |
| 114 | − glower = new Glower(glowLevel); | |
| 115 | − } | |
| 116 | − | |
| 117 | − glPushMatrix(); | |
| 118 | − glTranslatef(position.x, position.y, position.z); | |
| 119 | − glm::vec3 axis = glm::axis(rotation); | |
| 120 | − glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); | |
| 121 | − glPushMatrix(); | |
| 122 | − glm::vec3 positionToCenter = center - position; | |
| 123 | − glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); | |
| 124 | − glScalef(dimensions.x / 2.0f, dimensions.y / 2.0f, 1.0f); | |
| 105 | + auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 125 | 106 | |
| 126 | − glLineWidth(_lineWidth); | |
| 127 | − | |
| 128 | − auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 107 | + Transform transform; | |
| 108 | + transform.setTranslation(getCenter()); | |
| 109 | + transform.setRotation(getRotation()); | |
| 110 | + transform.setScale(glm::vec3(getDimensions(), 0.01f)); | |
| 111 | + | |
| 112 | + | |
| 113 | + auto& batch = *args->_batch; | |
| 114 | + batch._glLineWidth(_lineWidth); | |
| 115 | + batch.setModelTransform(transform); | |
| 116 | + DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, false, false); | |
| 117 | + | |
| 118 | + // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise | |
| 119 | + // we just draw a line... | |
| 120 | + if (getIsSolid()) { | |
| 121 | + if (_quadVerticesID == GeometryCache::UNKNOWN_ID) { | |
| 122 | + _quadVerticesID = geometryCache->allocateID(); | |
| 123 | + } | |
| 124 | + | |
| 125 | + if (geometryChanged || colorChanged) { | |
| 129 | 126 | |
| 130 | − // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise | |
| 131 | − // we just draw a line... | |
| 132 | − if (getIsSolid()) { | |
| 133 | − if (_quadVerticesID == GeometryCache::UNKNOWN_ID) { | |
| 134 | − _quadVerticesID = geometryCache->allocateID(); | |
| 135 | − } | |
| 127 | + QVector<glm::vec2> points; | |
| 128 | + | |
| 129 | + float angle = startAt; | |
| 130 | + float angleInRadians = glm::radians(angle); | |
| 131 | + glm::vec2 firstInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius); | |
| 132 | + glm::vec2 firstOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); | |
| 133 | + | |
| 134 | + points << firstInnerPoint << firstOuterPoint; | |
| 135 | + | |
| 136 | + while (angle < endAt) { | |
| 137 | + angleInRadians = glm::radians(angle); | |
| 138 | + glm::vec2 thisInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius); | |
| 139 | + glm::vec2 thisOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); | |
| 136 | 140 | |
| 137 | − if (geometryChanged || colorChanged) { | |
| 138 | − | |
| 139 | − QVector<glm::vec2> points; | |
| 140 | − | |
| 141 | − float angle = startAt; | |
| 142 | − float angleInRadians = glm::radians(angle); | |
| 143 | − glm::vec2 firstInnerPoint(cos(angleInRadians) * innerRadius, sin(angleInRadians) * innerRadius); | |
| 144 | − glm::vec2 firstOuterPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); | |
| 145 | − | |
| 146 | − points << firstInnerPoint << firstOuterPoint; | |
| 147 | − | |
| 148 | − while (angle < endAt) { | |
| 149 | − angleInRadians = glm::radians(angle); | |
| 150 | − glm::vec2 thisInnerPoint(cos(angleInRadians) * innerRadius, sin(angleInRadians) * innerRadius); | |
| 151 | − glm::vec2 thisOuterPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); | |
| 152 | − | |
| 153 | − points << thisOuterPoint << thisInnerPoint; | |
| 141 | + points << thisOuterPoint << thisInnerPoint; | |
| 154 | 142 | |
| 155 | − angle += SLICE_ANGLE; | |
| 156 | − } | |
| 143 | + angle += SLICE_ANGLE; | |
| 144 | + } | |
| 157 | 145 | |
| 158 | − // get the last slice portion.... | |
| 159 | − angle = endAt; | |
| 160 | − angleInRadians = glm::radians(angle); | |
| 161 | − glm::vec2 lastInnerPoint(cos(angleInRadians) * innerRadius, sin(angleInRadians) * innerRadius); | |
| 162 | − glm::vec2 lastOuterPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); | |
| 146 | + // get the last slice portion.... | |
| 147 | + angle = endAt; | |
| 148 | + angleInRadians = glm::radians(angle); | |
| 149 | + glm::vec2 lastInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius); | |
| 150 | + glm::vec2 lastOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); | |
| 163 | 151 | |
| 164 | − points << lastOuterPoint << lastInnerPoint; | |
| 165 | − | |
| 166 | − geometryCache->updateVertices(_quadVerticesID, points, color); | |
| 167 | − } | |
| 168 | − | |
| 169 | − geometryCache->renderVertices(gpu::QUAD_STRIP, _quadVerticesID); | |
| 170 | − | |
| 171 | − } else { | |
| 172 | − if (_lineVerticesID == GeometryCache::UNKNOWN_ID) { | |
| 173 | − _lineVerticesID = geometryCache->allocateID(); | |
| 174 | − } | |
| 175 | − | |
| 176 | − if (geometryChanged || colorChanged) { | |
| 177 | − QVector<glm::vec2> points; | |
| 178 | − | |
| 179 | − float angle = startAt; | |
| 180 | − float angleInRadians = glm::radians(angle); | |
| 181 | − glm::vec2 firstPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); | |
| 182 | − points << firstPoint; | |
| 183 | − | |
| 184 | − while (angle < endAt) { | |
| 185 | − angle += SLICE_ANGLE; | |
| 186 | − angleInRadians = glm::radians(angle); | |
| 187 | − glm::vec2 thisPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); | |
| 188 | − points << thisPoint; | |
| 189 | − | |
| 190 | − if (getIsDashedLine()) { | |
| 191 | − angle += SLICE_ANGLE / 2.0f; // short gap | |
| 192 | − angleInRadians = glm::radians(angle); | |
| 193 | − glm::vec2 dashStartPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); | |
| 194 | − points << dashStartPoint; | |
| 195 | − } | |
| 196 | − } | |
| 152 | + points << lastOuterPoint << lastInnerPoint; | |
| 197 | 153 | |
| 198 | − // get the last slice portion.... | |
| 199 | − angle = endAt; | |
| 200 | − angleInRadians = glm::radians(angle); | |
| 201 | − glm::vec2 lastPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); | |
| 202 | − points << lastPoint; | |
| 203 | − | |
| 204 | − geometryCache->updateVertices(_lineVerticesID, points, color); | |
| 205 | − } | |
| 206 | − | |
| 154 | + geometryCache->updateVertices(_quadVerticesID, points, color); | |
| 155 | + } | |
| 156 | + | |
| 157 | + geometryCache->renderVertices(batch, gpu::QUAD_STRIP, _quadVerticesID); | |
| 158 | + | |
| 159 | + } else { | |
| 160 | + if (_lineVerticesID == GeometryCache::UNKNOWN_ID) { | |
| 161 | + _lineVerticesID = geometryCache->allocateID(); | |
| 162 | + } | |
| 163 | + | |
| 164 | + if (geometryChanged || colorChanged) { | |
| 165 | + QVector<glm::vec2> points; | |
| 166 | + | |
| 167 | + float angle = startAt; | |
| 168 | + float angleInRadians = glm::radians(angle); | |
| 169 | + glm::vec2 firstPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); | |
| 170 | + points << firstPoint; | |
| 171 | + | |
| 172 | + while (angle < endAt) { | |
| 173 | + angle += SLICE_ANGLE; | |
| 174 | + angleInRadians = glm::radians(angle); | |
| 175 | + glm::vec2 thisPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); | |
| 176 | + points << thisPoint; | |
| 177 | + | |
| 207 | 178 | if (getIsDashedLine()) { |
| 208 | − geometryCache->renderVertices(gpu::LINES, _lineVerticesID); | |
| 209 | − } else { | |
| 210 | − geometryCache->renderVertices(gpu::LINE_STRIP, _lineVerticesID); | |
| 179 | + angle += SLICE_ANGLE / 2.0f; // short gap | |
| 180 | + angleInRadians = glm::radians(angle); | |
| 181 | + glm::vec2 dashStartPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); | |
| 182 | + points << dashStartPoint; | |
| 211 | 183 | } |
| 212 | 184 | } |
| 213 | 185 | |
| 214 | − // draw our tick marks | |
| 215 | − // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise | |
| 216 | − // we just draw a line... | |
| 217 | − if (getHasTickMarks()) { | |
| 218 | − | |
| 219 | − if (_majorTicksVerticesID == GeometryCache::UNKNOWN_ID) { | |
| 220 | − _majorTicksVerticesID = geometryCache->allocateID(); | |
| 221 | − } | |
| 222 | − if (_minorTicksVerticesID == GeometryCache::UNKNOWN_ID) { | |
| 223 | − _minorTicksVerticesID = geometryCache->allocateID(); | |
| 224 | − } | |
| 225 | − | |
| 226 | − if (geometryChanged) { | |
| 227 | − QVector<glm::vec2> majorPoints; | |
| 228 | − QVector<glm::vec2> minorPoints; | |
| 229 | − | |
| 230 | − // draw our major tick marks | |
| 231 | − if (getMajorTickMarksAngle() > 0.0f && getMajorTickMarksLength() != 0.0f) { | |
| 186 | + // get the last slice portion.... | |
| 187 | + angle = endAt; | |
| 188 | + angleInRadians = glm::radians(angle); | |
| 189 | + glm::vec2 lastPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); | |
| 190 | + points << lastPoint; | |
| 191 | + | |
| 192 | + geometryCache->updateVertices(_lineVerticesID, points, color); | |
| 193 | + } | |
| 194 | + | |
| 195 | + if (getIsDashedLine()) { | |
| 196 | + geometryCache->renderVertices(batch, gpu::LINES, _lineVerticesID); | |
| 197 | + } else { | |
| 198 | + geometryCache->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID); | |
| 199 | + } | |
| 200 | + } | |
| 201 | + | |
| 202 | + // draw our tick marks | |
| 203 | + // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise | |
| 204 | + // we just draw a line... | |
| 205 | + if (getHasTickMarks()) { | |
| 206 | + | |
| 207 | + if (_majorTicksVerticesID == GeometryCache::UNKNOWN_ID) { | |
| 208 | + _majorTicksVerticesID = geometryCache->allocateID(); | |
| 209 | + } | |
| 210 | + if (_minorTicksVerticesID == GeometryCache::UNKNOWN_ID) { | |
| 211 | + _minorTicksVerticesID = geometryCache->allocateID(); | |
| 212 | + } | |
| 213 | + | |
| 214 | + if (geometryChanged) { | |
| 215 | + QVector<glm::vec2> majorPoints; | |
| 216 | + QVector<glm::vec2> minorPoints; | |
| 217 | + | |
| 218 | + // draw our major tick marks | |
| 219 | + if (getMajorTickMarksAngle() > 0.0f && getMajorTickMarksLength() != 0.0f) { | |
| 232 | 220 | |
| 233 | − float tickMarkAngle = getMajorTickMarksAngle(); | |
| 234 | − float angle = startAt - fmod(startAt, tickMarkAngle) + tickMarkAngle; | |
| 235 | − float angleInRadians = glm::radians(angle); | |
| 236 | − float tickMarkLength = getMajorTickMarksLength(); | |
| 237 | − float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; | |
| 238 | − float endRadius = startRadius + tickMarkLength; | |
| 239 | − | |
| 240 | − while (angle <= endAt) { | |
| 241 | − angleInRadians = glm::radians(angle); | |
| 242 | − | |
| 243 | − glm::vec2 thisPointA(cos(angleInRadians) * startRadius, sin(angleInRadians) * startRadius); | |
| 244 | − glm::vec2 thisPointB(cos(angleInRadians) * endRadius, sin(angleInRadians) * endRadius); | |
| 245 | − | |
| 246 | − majorPoints << thisPointA << thisPointB; | |
| 221 | + float tickMarkAngle = getMajorTickMarksAngle(); | |
| 222 | + float angle = startAt - fmodf(startAt, tickMarkAngle) + tickMarkAngle; | |
| 223 | + float angleInRadians = glm::radians(angle); | |
| 224 | + float tickMarkLength = getMajorTickMarksLength(); | |
| 225 | + float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; | |
| 226 | + float endRadius = startRadius + tickMarkLength; | |
| 247 | 227 | |
| 248 | − angle += tickMarkAngle; | |
| 249 | − } | |
| 250 | − } | |
| 251 | − | |
| 252 | − // draw our minor tick marks | |
| 253 | − if (getMinorTickMarksAngle() > 0.0f && getMinorTickMarksLength() != 0.0f) { | |
| 228 | + while (angle <= endAt) { | |
| 229 | + angleInRadians = glm::radians(angle); | |
| 230 | + | |
| 231 | + glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius); | |
| 232 | + glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius); | |
| 233 | + | |
| 234 | + majorPoints << thisPointA << thisPointB; | |
| 235 | + | |
| 236 | + angle += tickMarkAngle; | |
| 237 | + } | |
| 238 | + } | |
| 239 | + | |
| 240 | + // draw our minor tick marks | |
| 241 | + if (getMinorTickMarksAngle() > 0.0f && getMinorTickMarksLength() != 0.0f) { | |
| 254 | 242 | |
| 255 | − float tickMarkAngle = getMinorTickMarksAngle(); | |
| 256 | − float angle = startAt - fmod(startAt, tickMarkAngle) + tickMarkAngle; | |
| 257 | − float angleInRadians = glm::radians(angle); | |
| 258 | − float tickMarkLength = getMinorTickMarksLength(); | |
| 259 | − float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; | |
| 260 | − float endRadius = startRadius + tickMarkLength; | |
| 261 | − | |
| 262 | − while (angle <= endAt) { | |
| 263 | − angleInRadians = glm::radians(angle); | |
| 264 | − | |
| 265 | − glm::vec2 thisPointA(cos(angleInRadians) * startRadius, sin(angleInRadians) * startRadius); | |
| 266 | − glm::vec2 thisPointB(cos(angleInRadians) * endRadius, sin(angleInRadians) * endRadius); | |
| 267 | − | |
| 268 | − minorPoints << thisPointA << thisPointB; | |
| 243 | + float tickMarkAngle = getMinorTickMarksAngle(); | |
| 244 | + float angle = startAt - fmodf(startAt, tickMarkAngle) + tickMarkAngle; | |
| 245 | + float angleInRadians = glm::radians(angle); | |
| 246 | + float tickMarkLength = getMinorTickMarksLength(); | |
| 247 | + float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; | |
| 248 | + float endRadius = startRadius + tickMarkLength; | |
| 269 | 249 | |
| 270 | − angle += tickMarkAngle; | |
| 271 | − } | |
| 272 | − } | |
| 273 | − | |
| 274 | − xColor majorColorX = getMajorTickMarksColor(); | |
| 275 | − glm::vec4 majorColor(majorColorX.red / MAX_COLOR, majorColorX.green / MAX_COLOR, majorColorX.blue / MAX_COLOR, alpha); | |
| 276 | − | |
| 277 | − geometryCache->updateVertices(_majorTicksVerticesID, majorPoints, majorColor); | |
| 278 | − | |
| 279 | − xColor minorColorX = getMinorTickMarksColor(); | |
| 280 | − glm::vec4 minorColor(minorColorX.red / MAX_COLOR, minorColorX.green / MAX_COLOR, minorColorX.blue / MAX_COLOR, alpha); | |
| 281 | − | |
| 282 | − geometryCache->updateVertices(_minorTicksVerticesID, minorPoints, minorColor); | |
| 250 | + while (angle <= endAt) { | |
| 251 | + angleInRadians = glm::radians(angle); | |
| 252 | + | |
| 253 | + glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius); | |
| 254 | + glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius); | |
| 255 | + | |
| 256 | + minorPoints << thisPointA << thisPointB; | |
| 257 | + | |
| 258 | + angle += tickMarkAngle; | |
| 283 | 259 | } |
| 284 | − | |
| 285 | − geometryCache->renderVertices(gpu::LINES, _majorTicksVerticesID); | |
| 286 | − | |
| 287 | − geometryCache->renderVertices(gpu::LINES, _minorTicksVerticesID); | |
| 288 | 260 | } |
| 289 | 261 | |
| 290 | − | |
| 291 | − glPopMatrix(); | |
| 292 | − glPopMatrix(); | |
| 262 | + xColor majorColorX = getMajorTickMarksColor(); | |
| 263 | + glm::vec4 majorColor(majorColorX.red / MAX_COLOR, majorColorX.green / MAX_COLOR, majorColorX.blue / MAX_COLOR, alpha); | |
| 264 | + | |
| 265 | + geometryCache->updateVertices(_majorTicksVerticesID, majorPoints, majorColor); | |
| 266 | + | |
| 267 | + xColor minorColorX = getMinorTickMarksColor(); | |
| 268 | + glm::vec4 minorColor(minorColorX.red / MAX_COLOR, minorColorX.green / MAX_COLOR, minorColorX.blue / MAX_COLOR, alpha); | |
| 269 | + | |
| 270 | + geometryCache->updateVertices(_minorTicksVerticesID, minorPoints, minorColor); | |
| 271 | + } | |
| 272 | + | |
| 273 | + geometryCache->renderVertices(batch, gpu::LINES, _majorTicksVerticesID); | |
| 274 | + | |
| 275 | + geometryCache->renderVertices(batch, gpu::LINES, _minorTicksVerticesID); | |
| 276 | + } | |
| 293 | 277 | |
| 294 | 278 | if (geometryChanged) { |
| 295 | 279 | _lastStartAt = startAt; |
| @@ -297,15 +281,11 @@ void Circle3DOverlay::render(RenderArgs* args) { · 1 unmodified line | ||
| 297 | 281 | _lastInnerRadius = innerRadius; |
| 298 | 282 | _lastOuterRadius = outerRadius; |
| 299 | 283 | } |
| 300 | − | |
| 301 | − if (glower) { | |
| 302 | − delete glower; | |
| 303 | − } | |
| 304 | 284 | } |
| 305 | 285 | |
| 306 | 286 | void Circle3DOverlay::setProperties(const QScriptValue &properties) { |
| 307 | 287 | Planar3DOverlay::setProperties(properties); |
| 308 | − | |
| 288 | + | |
| 309 | 289 | QScriptValue startAt = properties.property("startAt"); |
| 310 | 290 | if (startAt.isValid()) { |
| 311 | 291 | setStartAt(startAt.toVariant().toFloat()); |
| @@ -415,7 +395,7 @@ QScriptValue Circle3DOverlay::getProperty(const QString& property) { · 103 unmodified lines | ||
| 415 | 395 | } |
| 416 | 396 | |
| 417 | 397 | |
| 418 | −bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin, | |
| 398 | +bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin, | |
| 419 | 399 | const glm::vec3& direction, float& distance, BoxFace& face) { |
| 420 | 400 | |
| 421 | 401 | bool intersects = Planar3DOverlay::findRayIntersection(origin, direction, distance, face); |
| @@ -32,6 +32,16 @@ Line3DOverlay::Line3DOverlay(const Line3DOverlay* line3DOverlay) : · 31 unmodified lines | ||
| 32 | 32 | Line3DOverlay::~Line3DOverlay() { |
| 33 | 33 | } |
| 34 | 34 | |
| 35 | +AABox Line3DOverlay::getBounds() const { | |
| 36 | + auto start = _position + _start; | |
| 37 | + auto end = _position + _end; | |
| 38 | + | |
| 39 | + auto min = glm::min(start, end); | |
| 40 | + auto max = glm::max(start, end); | |
| 41 | + | |
| 42 | + return AABox(min, max - min); | |
| 43 | +} | |
| 44 | + | |
| 35 | 45 | void Line3DOverlay::render(RenderArgs* args) { |
| 36 | 46 | if (!_visible) { |
| 37 | 47 | return; // do nothing if we're not visible |
| @@ -21,6 +21,7 @@ public: · 20 unmodified lines | ||
| 21 | 21 | Line3DOverlay(const Line3DOverlay* line3DOverlay); |
| 22 | 22 | ~Line3DOverlay(); |
| 23 | 23 | virtual void render(RenderArgs* args); |
| 24 | + virtual AABox getBounds() const override; | |
| 24 | 25 | |
| 25 | 26 | // getters |
| 26 | 27 | const glm::vec3& getStart() const { return _start; } |
| @@ -258,7 +258,7 @@ void Overlays::deleteOverlay(unsigned int id) { · 257 unmodified lines | ||
| 258 | 258 | unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) { |
| 259 | 259 | glm::vec2 pointCopy = point; |
| 260 | 260 | if (qApp->isHMDMode()) { |
| 261 | − pointCopy = qApp->getApplicationOverlay().screenToOverlay(point); | |
| 261 | + pointCopy = qApp->getApplicationCompositor().screenToOverlay(point); | |
| 262 | 262 | } |
| 263 | 263 | |
| 264 | 264 | QReadLocker lock(&_lock); |
| @@ -80,6 +80,7 @@ void TextOverlay::render(RenderArgs* args) { · 79 unmodified lines | ||
| 80 | 80 | |
| 81 | 81 | glm::vec2 topLeft(left, top); |
| 82 | 82 | glm::vec2 bottomRight(right, bottom); |
| 83 | + glBindTexture(GL_TEXTURE_2D, 0); | |
| 83 | 84 | DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, quadColor); |
| 84 | 85 | |
| 85 | 86 | const int leftAdjust = -1; // required to make text render relative to left edge of bounds |
| @@ -33,11 +33,20 @@ · 32 unmodified lines | ||
| 33 | 33 | #include <QtMultimedia/QAudioInput> |
| 34 | 34 | #include <QtMultimedia/QAudioOutput> |
| 35 | 35 | |
| 36 | +#ifdef __GNUC__ | |
| 37 | +#pragma GCC diagnostic push | |
| 38 | +#pragma GCC diagnostic ignored "-Wdouble-promotion" | |
| 39 | +#endif | |
| 40 | + | |
| 36 | 41 | extern "C" { |
| 37 | 42 | #include <gverb/gverb.h> |
| 38 | 43 | #include <gverb/gverbdsp.h> |
| 39 | 44 | } |
| 40 | 45 | |
| 46 | +#ifdef __GNUC__ | |
| 47 | +#pragma GCC diagnostic pop | |
| 48 | +#endif | |
| 49 | + | |
| 41 | 50 | #include <soxr.h> |
| 42 | 51 | |
| 43 | 52 | #include <NodeList.h> |
| @@ -786,6 +795,11 @@ void AudioClient::handleAudioInput() { · 742 unmodified lines | ||
| 786 | 795 | |
| 787 | 796 | delete[] inputAudioSamples; |
| 788 | 797 | |
| 798 | + // Remove DC offset | |
| 799 | + if (!_isStereoInput && !_audioSourceInjectEnabled) { | |
| 800 | + _inputGate.removeDCOffset(networkAudioSamples, numNetworkSamples); | |
| 801 | + } | |
| 802 | + | |
| 789 | 803 | // only impose the noise gate and perform tone injection if we are sending mono audio |
| 790 | 804 | if (!_isStereoInput && !_audioSourceInjectEnabled && _isNoiseGateEnabled) { |
| 791 | 805 | _inputGate.gateSamples(networkAudioSamples, numNetworkSamples); |
| @@ -1011,7 +1025,10 @@ bool AudioClient::outputLocalInjector(bool isStereo, AudioInjector* injector) { · 219 unmodified lines | ||
| 1011 | 1025 | localOutput->moveToThread(injector->getLocalBuffer()->thread()); |
| 1012 | 1026 | |
| 1013 | 1027 | // have it be stopped when that local buffer is about to close |
| 1014 | − connect(injector->getLocalBuffer(), &AudioInjectorLocalBuffer::bufferEmpty, localOutput, &QAudioOutput::stop); | |
| 1028 | + connect(localOutput, &QAudioOutput::stateChanged, this, &AudioClient::audioStateChanged); | |
| 1029 | + connect(this, &AudioClient::audioFinished, localOutput, &QAudioOutput::stop); | |
| 1030 | + connect(this, &AudioClient::audioFinished, injector, &AudioInjector::stop); | |
| 1031 | + | |
| 1015 | 1032 | connect(injector->getLocalBuffer(), &QIODevice::aboutToClose, localOutput, &QAudioOutput::stop); |
| 1016 | 1033 | |
| 1017 | 1034 | qCDebug(audioclient) << "Starting QAudioOutput for local injector" << localOutput; |
| @@ -1329,3 +1346,9 @@ void AudioClient::saveSettings() { · 311 unmodified lines | ||
| 1329 | 1346 | windowSecondsForDesiredReduction.set(_receivedAudioStream.getWindowSecondsForDesiredReduction()); |
| 1330 | 1347 | repetitionWithFade.set(_receivedAudioStream.getRepetitionWithFade()); |
| 1331 | 1348 | } |
| 1349 | + | |
| 1350 | +void AudioClient::audioStateChanged(QAudio::State state) { | |
| 1351 | + if (state == QAudio::IdleState) { | |
| 1352 | + emit audioFinished(); | |
| 1353 | + } | |
| 1354 | +} | |
| @@ -167,7 +167,7 @@ public slots: · 166 unmodified lines | ||
| 167 | 167 | QString getDefaultDeviceName(QAudio::Mode mode); |
| 168 | 168 | QVector<QString> getDeviceNames(QAudio::Mode mode); |
| 169 | 169 | |
| 170 | − float getInputVolume() const { return (_audioInput) ? _audioInput->volume() : 0.0f; } | |
| 170 | + float getInputVolume() const { return (_audioInput) ? (float)_audioInput->volume() : 0.0f; } | |
| 171 | 171 | void setInputVolume(float volume) { if (_audioInput) _audioInput->setVolume(volume); } |
| 172 | 172 | void setReverb(bool reverb); |
| 173 | 173 | void setReverbOptions(const AudioEffectOptions* options); |
| @@ -188,6 +188,8 @@ signals: · 14 unmodified lines | ||
| 188 | 188 | void receivedFirstPacket(); |
| 189 | 189 | void disconnected(); |
| 190 | 190 | |
| 191 | + void audioFinished(); | |
| 192 | + | |
| 191 | 193 | protected: |
| 192 | 194 | AudioClient(); |
| 193 | 195 | ~AudioClient(); |
| @@ -196,6 +198,9 @@ protected: · 2 unmodified lines | ||
| 196 | 198 | deleteLater(); |
| 197 | 199 | } |
| 198 | 200 | |
| 201 | +private slots: | |
| 202 | + void audioStateChanged(QAudio::State state); | |
| 203 | + | |
| 199 | 204 | private: |
| 200 | 205 | void outputFormatChanged(); |
| 201 | 206 | |
| @@ -33,6 +33,32 @@ AudioNoiseGate::AudioNoiseGate() : · 32 unmodified lines | ||
| 33 | 33 | |
| 34 | 34 | } |
| 35 | 35 | |
| 36 | +void AudioNoiseGate::removeDCOffset(int16_t* samples, int numSamples) { | |
| 37 | + // | |
| 38 | + // DC Offset correction | |
| 39 | + // | |
| 40 | + // Measure the DC offset over a trailing number of frames, and remove it from the input signal. | |
| 41 | + // This causes the noise background measurements and server muting to be more accurate. Many off-board | |
| 42 | + // ADC's have a noticeable DC offset. | |
| 43 | + // | |
| 44 | + const float DC_OFFSET_AVERAGING = 0.99f; | |
| 45 | + float measuredDcOffset = 0.0f; | |
| 46 | + // Remove trailing DC offset from samples | |
| 47 | + for (int i = 0; i < numSamples; i++) { | |
| 48 | + measuredDcOffset += samples[i]; | |
| 49 | + samples[i] -= (int16_t) _dcOffset; | |
| 50 | + } | |
| 51 | + // Update measured DC offset | |
| 52 | + measuredDcOffset /= numSamples; | |
| 53 | + if (_dcOffset == 0.0f) { | |
| 54 | + // On first frame, copy over measured offset | |
| 55 | + _dcOffset = measuredDcOffset; | |
| 56 | + } else { | |
| 57 | + _dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset; | |
| 58 | + } | |
| 59 | +} | |
| 60 | + | |
| 61 | + | |
| 36 | 62 | void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { |
| 37 | 63 | // |
| 38 | 64 | // Impose Noise Gate |
| @@ -61,17 +87,12 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { · 22 unmodified lines | ||
| 61 | 87 | const int NOISE_GATE_WIDTH = 5; |
| 62 | 88 | const int NOISE_GATE_CLOSE_FRAME_DELAY = 5; |
| 63 | 89 | const int NOISE_GATE_FRAMES_TO_AVERAGE = 5; |
| 64 | − const float DC_OFFSET_AVERAGING = 0.99f; | |
| 65 | − | |
| 66 | − // Check clipping, adjust DC offset, and check if should open noise gate | |
| 67 | − float measuredDcOffset = 0.0f; | |
| 90 | + | |
| 91 | + // Check clipping, and check if should open noise gate | |
| 68 | 92 | _didClipInLastFrame = false; |
| 69 | 93 | |
| 70 | 94 | for (int i = 0; i < numSamples; i++) { |
| 71 | − measuredDcOffset += samples[i]; | |
| 72 | − samples[i] -= (int16_t) _dcOffset; | |
| 73 | 95 | thisSample = std::abs(samples[i]); |
| 74 | − | |
| 75 | 96 | if (thisSample >= ((float) AudioConstants::MAX_SAMPLE_VALUE * CLIPPING_THRESHOLD)) { |
| 76 | 97 | _didClipInLastFrame = true; |
| 77 | 98 | } |
| @@ -83,14 +104,6 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { · 5 unmodified lines | ||
| 83 | 104 | } |
| 84 | 105 | } |
| 85 | 106 | |
| 86 | − measuredDcOffset /= numSamples; | |
| 87 | − if (_dcOffset == 0.0f) { | |
| 88 | − // On first frame, copy over measured offset | |
| 89 | − _dcOffset = measuredDcOffset; | |
| 90 | − } else { | |
| 91 | − _dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset; | |
| 92 | − } | |
| 93 | − | |
| 94 | 107 | _lastLoudness = fabs(loudness / numSamples); |
| 95 | 108 | |
| 96 | 109 | if (_quietestFrame > _lastLoudness) { |
| @@ -21,6 +21,7 @@ public: · 20 unmodified lines | ||
| 21 | 21 | AudioNoiseGate(); |
| 22 | 22 | |
| 23 | 23 | void gateSamples(int16_t* samples, int numSamples); |
| 24 | + void removeDCOffset(int16_t* samples, int numSamples); | |
| 24 | 25 | |
| 25 | 26 | bool clippedInLastFrame() const { return _didClipInLastFrame; } |
| 26 | 27 | float getMeasuredFloor() const { return _measuredFloor; } |
| @@ -7,4 +7,10 @@ add_dependency_external_projects(glm) · 6 unmodified lines | ||
| 7 | 7 | find_package(GLM REQUIRED) |
| 8 | 8 | target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) |
| 9 | 9 | |
| 10 | −link_hifi_libraries(networking shared) | |
| 10 | +# we use libsoxr for resampling | |
| 11 | +add_dependency_external_projects(soxr) | |
| 12 | +find_package(Soxr REQUIRED) | |
| 13 | +target_link_libraries(${TARGET_NAME} ${SOXR_LIBRARIES}) | |
| 14 | +target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SOXR_INCLUDE_DIRS}) | |
| 15 | + | |
| 16 | +link_hifi_libraries(networking shared) | |
| @@ -16,10 +16,12 @@ · 15 unmodified lines | ||
| 16 | 16 | #include <PacketHeaders.h> |
| 17 | 17 | #include <SharedUtil.h> |
| 18 | 18 | #include <UUID.h> |
| 19 | +#include <soxr.h> | |
| 19 | 20 | |
| 20 | 21 | #include "AbstractAudioInterface.h" |
| 21 | 22 | #include "AudioRingBuffer.h" |
| 22 | 23 | #include "AudioLogging.h" |
| 24 | +#include "SoundCache.h" | |
| 23 | 25 | |
| 24 | 26 | #include "AudioInjector.h" |
| 25 | 27 | |
| @@ -60,7 +62,6 @@ void AudioInjector::setIsFinished(bool isFinished) { · 34 unmodified lines | ||
| 60 | 62 | |
| 61 | 63 | if (_shouldDeleteAfterFinish) { |
| 62 | 64 | // we've been asked to delete after finishing, trigger a queued deleteLater here |
| 63 | − qCDebug(audio) << "AudioInjector triggering delete from setIsFinished"; | |
| 64 | 65 | QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection); |
| 65 | 66 | } |
| 66 | 67 | } |
| @@ -122,9 +123,6 @@ void AudioInjector::injectLocally() { · 55 unmodified lines | ||
| 122 | 123 | |
| 123 | 124 | success = _localAudioInterface->outputLocalInjector(_options.stereo, this); |
| 124 | 125 | |
| 125 | − // if we're not looping and the buffer tells us it is empty then emit finished | |
| 126 | − connect(_localBuffer, &AudioInjectorLocalBuffer::bufferEmpty, this, &AudioInjector::stop); | |
| 127 | − | |
| 128 | 126 | if (!success) { |
| 129 | 127 | qCDebug(audio) << "AudioInjector::injectLocally could not output locally via _localAudioInterface"; |
| 130 | 128 | } |
| @@ -288,3 +286,66 @@ void AudioInjector::stopAndDeleteLater() { · 157 unmodified lines | ||
| 288 | 286 | stop(); |
| 289 | 287 | QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection); |
| 290 | 288 | } |
| 289 | + | |
| 290 | +AudioInjector* AudioInjector::playSound(const QString& soundUrl, const float volume, const float stretchFactor, const glm::vec3 position) { | |
| 291 | + if (soundUrl.isEmpty()) { | |
| 292 | + return NULL; | |
| 293 | + } | |
| 294 | + auto soundCache = DependencyManager::get<SoundCache>(); | |
| 295 | + if (soundCache.isNull()) { | |
| 296 | + return NULL; | |
| 297 | + } | |
| 298 | + SharedSoundPointer sound = soundCache.data()->getSound(QUrl(soundUrl)); | |
| 299 | + if (sound.isNull() || !sound->isReady()) { | |
| 300 | + return NULL; | |
| 301 | + } | |
| 302 | + | |
| 303 | + AudioInjectorOptions options; | |
| 304 | + options.stereo = sound->isStereo(); | |
| 305 | + options.position = position; | |
| 306 | + options.volume = volume; | |
| 307 | + | |
| 308 | + QByteArray samples = sound->getByteArray(); | |
| 309 | + if (stretchFactor == 1.0f) { | |
| 310 | + return playSound(samples, options, NULL); | |
| 311 | + } | |
| 312 | + | |
| 313 | + soxr_io_spec_t spec = soxr_io_spec(SOXR_INT16_I, SOXR_INT16_I); | |
| 314 | + soxr_quality_spec_t qualitySpec = soxr_quality_spec(SOXR_MQ, 0); | |
| 315 | + const int channelCount = sound->isStereo() ? 2 : 1; | |
| 316 | + const int standardRate = AudioConstants::SAMPLE_RATE; | |
| 317 | + const int resampledRate = standardRate * stretchFactor; | |
| 318 | + const int nInputSamples = samples.size() / sizeof(int16_t); | |
| 319 | + const int nOutputSamples = nInputSamples * stretchFactor; | |
| 320 | + QByteArray resampled(nOutputSamples * sizeof(int16_t), '\0'); | |
| 321 | + const int16_t* receivedSamples = reinterpret_cast<const int16_t*>(samples.data()); | |
| 322 | + soxr_error_t soxError = soxr_oneshot(standardRate, resampledRate, channelCount, | |
| 323 | + receivedSamples, nInputSamples, NULL, | |
| 324 | + reinterpret_cast<int16_t*>(resampled.data()), nOutputSamples, NULL, | |
| 325 | + &spec, &qualitySpec, 0); | |
| 326 | + if (soxError) { | |
| 327 | + qCDebug(audio) << "Unable to resample" << soundUrl << "from" << nInputSamples << "@" << standardRate << "to" << nOutputSamples << "@" << resampledRate; | |
| 328 | + resampled = samples; | |
| 329 | + } | |
| 330 | + return playSound(resampled, options, NULL); | |
| 331 | +} | |
| 332 | + | |
| 333 | +AudioInjector* AudioInjector::playSound(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface) { | |
| 334 | + QThread* injectorThread = new QThread(); | |
| 335 | + injectorThread->setObjectName("Audio Injector Thread"); | |
| 336 | + | |
| 337 | + AudioInjector* injector = new AudioInjector(buffer, options); | |
| 338 | + injector->setLocalAudioInterface(localInterface); | |
| 339 | + | |
| 340 | + injector->moveToThread(injectorThread); | |
| 341 | + | |
| 342 | + // start injecting when the injector thread starts | |
| 343 | + connect(injectorThread, &QThread::started, injector, &AudioInjector::injectAudio); | |
| 344 | + | |
| 345 | + // connect the right slots and signals for AudioInjector and thread cleanup | |
| 346 | + connect(injector, &AudioInjector::destroyed, injectorThread, &QThread::quit); | |
| 347 | + connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater); | |
| 348 | + | |
| 349 | + injectorThread->start(); | |
| 350 | + return injector; | |
| 351 | +} | |
| @@ -45,6 +45,10 @@ public: · 44 unmodified lines | ||
| 45 | 45 | bool isLocalOnly() const { return _options.localOnly; } |
| 46 | 46 | |
| 47 | 47 | void setLocalAudioInterface(AbstractAudioInterface* localAudioInterface) { _localAudioInterface = localAudioInterface; } |
| 48 | + | |
| 49 | + static AudioInjector* playSound(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface); | |
| 50 | + static AudioInjector* playSound(const QString& soundUrl, const float volume, const float stretchFactor, const glm::vec3 position); | |
| 51 | + | |
| 48 | 52 | public slots: |
| 49 | 53 | void injectAudio(); |
| 50 | 54 | void restart(); |
| @@ -69,10 +69,7 @@ qint64 AudioInjectorLocalBuffer::readData(char* data, qint64 maxSize) { · 68 unmodified lines | ||
| 69 | 69 | _currentOffset += bytesRead; |
| 70 | 70 | } |
| 71 | 71 | |
| 72 | − if (!_shouldLoop && bytesRead == bytesToEnd) { | |
| 73 | − // we hit the end of the buffer, emit a signal | |
| 74 | − emit bufferEmpty(); | |
| 75 | − } else if (_shouldLoop && _currentOffset == _rawAudioArray.size()) { | |
| 72 | + if (_shouldLoop && _currentOffset == _rawAudioArray.size()) { | |
| 76 | 73 | _currentOffset = 0; |
| 77 | 74 | } |
| 78 | 75 | |
| @@ -32,9 +32,6 @@ public: · 31 unmodified lines | ||
| 32 | 32 | void setCurrentOffset(int currentOffset) { _currentOffset = currentOffset; } |
| 33 | 33 | void setVolume(float volume) { _volume = glm::clamp(volume, 0.0f, 1.0f); } |
| 34 | 34 | |
| 35 | −signals: | |
| 36 | − void bufferEmpty(); | |
| 37 | − | |
| 38 | 35 | private: |
| 39 | 36 | qint64 recursiveReadFromFront(char* data, qint64 maxSize); |
| 40 | 37 | |
| @@ -211,7 +211,7 @@ float AudioRingBuffer::getFrameLoudness(const int16_t* frameStart) const { · 210 unmodified lines | ||
| 211 | 211 | const int16_t* _bufferLastAt = _buffer + _bufferLength - 1; |
| 212 | 212 | |
| 213 | 213 | for (int i = 0; i < _numFrameSamples; ++i) { |
| 214 | − loudness += std::abs(*sampleAt); | |
| 214 | + loudness += (float) std::abs(*sampleAt); | |
| 215 | 215 | sampleAt = sampleAt == _bufferLastAt ? _buffer : sampleAt + 1; |
| 216 | 216 | } |
| 217 | 217 | loudness /= _numFrameSamples; |
| @@ -52,9 +52,8 @@ AvatarData::AvatarData() : · 51 unmodified lines | ||
| 52 | 52 | _headData(NULL), |
| 53 | 53 | _handData(NULL), |
| 54 | 54 | _faceModelURL("http://invalid.com"), |
| 55 | − _displayNameBoundingRect(), | |
| 56 | − _displayNameTargetAlpha(0.0f), | |
| 57 | − _displayNameAlpha(0.0f), | |
| 55 | + _displayNameTargetAlpha(1.0f), | |
| 56 | + _displayNameAlpha(1.0f), | |
| 58 | 57 | _billboard(), |
| 59 | 58 | _errorLogExpiry(0), |
| 60 | 59 | _owningAvatarMixer(), |
| @@ -163,7 +163,7 @@ public: · 162 unmodified lines | ||
| 163 | 163 | AvatarData(); |
| 164 | 164 | virtual ~AvatarData(); |
| 165 | 165 | |
| 166 | − virtual bool isMyAvatar() { return false; } | |
| 166 | + virtual bool isMyAvatar() const { return false; } | |
| 167 | 167 | |
| 168 | 168 | const QUuid& getSessionUUID() const { return _sessionUUID; } |
| 169 | 169 | |
| @@ -378,7 +378,6 @@ protected: · 208 unmodified lines | ||
| 378 | 378 | QVector<AttachmentData> _attachmentData; |
| 379 | 379 | QString _displayName; |
| 380 | 380 | |
| 381 | − QRect _displayNameBoundingRect; | |
| 382 | 381 | float _displayNameTargetAlpha; |
| 383 | 382 | float _displayNameAlpha; |
| 384 | 383 | |
| @@ -17,10 +17,4 @@ find_package(PolyVox REQUIRED) · 16 unmodified lines | ||
| 17 | 17 | target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${POLYVOX_INCLUDE_DIRS}) |
| 18 | 18 | target_link_libraries(${TARGET_NAME} ${POLYVOX_LIBRARIES}) |
| 19 | 19 | |
| 20 | −# for changing the pitch of collision sounds | |
| 21 | −add_dependency_external_projects(soxr) | |
| 22 | −find_package(Soxr REQUIRED) | |
| 23 | −target_link_libraries(${TARGET_NAME} ${SOXR_LIBRARIES}) | |
| 24 | −target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SOXR_INCLUDE_DIRS}) | |
| 25 | − | |
| 26 | 20 | link_hifi_libraries(shared gpu script-engine render render-utils) |
| @@ -27,10 +27,6 @@ · 26 unmodified lines | ||
| 27 | 27 | #include <SceneScriptingInterface.h> |
| 28 | 28 | #include <ScriptEngine.h> |
| 29 | 29 | #include <TextureCache.h> |
| 30 | −#include <SoundCache.h> | |
| 31 | −#include <soxr.h> | |
| 32 | −#include <AudioConstants.h> | |
| 33 | − | |
| 34 | 30 | |
| 35 | 31 | #include "EntityTreeRenderer.h" |
| 36 | 32 | |
| @@ -54,7 +50,6 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf · 17 unmodified lines | ||
| 54 | 50 | _wantScripts(wantScripts), |
| 55 | 51 | _entitiesScriptEngine(NULL), |
| 56 | 52 | _sandboxScriptEngine(NULL), |
| 57 | − _localAudioInterface(NULL), | |
| 58 | 53 | _lastMouseEventValid(false), |
| 59 | 54 | _viewState(viewState), |
| 60 | 55 | _scriptingServices(scriptingServices), |
| @@ -911,15 +906,13 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI · 850 unmodified lines | ||
| 911 | 906 | bool precisionPicking = false; // for mouse moves we do not do precision picking |
| 912 | 907 | RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking); |
| 913 | 908 | if (rayPickResult.intersects) { |
| 909 | + //qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID; | |
| 914 | 910 | QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); |
| 915 | − | |
| 916 | 911 | // load the entity script if needed... |
| 917 | 912 | QScriptValue entityScript = loadEntityScript(rayPickResult.entity); |
| 918 | 913 | if (entityScript.property("mouseMoveEvent").isValid()) { |
| 919 | 914 | entityScript.property("mouseMoveEvent").call(entityScript, entityScriptArgs); |
| 920 | 915 | } |
| 921 | − | |
| 922 | − //qCDebug(entitiesrenderer) << "mouseMoveEvent over entity:" << rayPickResult.entityID; | |
| 923 | 916 | emit mouseMoveOnEntity(rayPickResult, event, deviceID); |
| 924 | 917 | if (entityScript.property("mouseMoveOnEntity").isValid()) { |
| 925 | 918 | entityScript.property("mouseMoveOnEntity").call(entityScript, entityScriptArgs); |
| @@ -1056,7 +1049,6 @@ void EntityTreeRenderer::checkAndCallUnload(const EntityItemID& entityID) { · 130 unmodified lines | ||
| 1056 | 1049 | } |
| 1057 | 1050 | } |
| 1058 | 1051 | |
| 1059 | − | |
| 1060 | 1052 | void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision) { |
| 1061 | 1053 | EntityItemPointer entity = entityTree->findEntityByEntityItemID(id); |
| 1062 | 1054 | if (!entity) { |
| @@ -1099,61 +1091,15 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT · 36 unmodified lines | ||
| 1099 | 1091 | if (energyFactorOfFull < COLLISION_MINIMUM_VOLUME) { |
| 1100 | 1092 | return; |
| 1101 | 1093 | } |
| 1102 | − | |
| 1103 | − auto soundCache = DependencyManager::get<SoundCache>(); | |
| 1104 | − if (soundCache.isNull()) { | |
| 1105 | − return; | |
| 1106 | − } | |
| 1107 | − SharedSoundPointer sound = soundCache.data()->getSound(QUrl(collisionSoundURL)); | |
| 1108 | − if (sound.isNull() || !sound->isReady()) { | |
| 1109 | − return; | |
| 1110 | − } | |
| 1111 | − | |
| 1112 | − // This is a hack. Quiet sound aren't really heard at all, so we compress everything to the range [1-c, 1], if we play it all. | |
| 1094 | + // Quiet sound aren't really heard at all, so we can compress everything to the range [1-c, 1], if we play it all. | |
| 1113 | 1095 | const float COLLISION_SOUND_COMPRESSION_RANGE = 1.0f; // This section could be removed when the value is 1, but let's see how it goes. |
| 1114 | − float volume = energyFactorOfFull; | |
| 1115 | − volume = (volume * COLLISION_SOUND_COMPRESSION_RANGE) + (1.0f - COLLISION_SOUND_COMPRESSION_RANGE); | |
| 1116 | − | |
| 1117 | − // This is quite similar to AudioScriptingInterface::playSound() and should probably be refactored. | |
| 1118 | − AudioInjectorOptions options; | |
| 1119 | − options.stereo = sound->isStereo(); | |
| 1120 | − options.position = position; | |
| 1121 | − options.volume = volume; | |
| 1096 | + const float volume = (energyFactorOfFull * COLLISION_SOUND_COMPRESSION_RANGE) + (1.0f - COLLISION_SOUND_COMPRESSION_RANGE); | |
| 1097 | + | |
| 1122 | 1098 | |
| 1123 | 1099 | // Shift the pitch down by ln(1 + (size / COLLISION_SIZE_FOR_STANDARD_PITCH)) / ln(2) |
| 1124 | 1100 | const float COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f; |
| 1125 | − QByteArray samples = sound->getByteArray(); | |
| 1126 | − soxr_io_spec_t spec = soxr_io_spec(SOXR_INT16_I, SOXR_INT16_I); | |
| 1127 | − soxr_quality_spec_t qualitySpec = soxr_quality_spec(SOXR_MQ, 0); | |
| 1128 | − const int channelCount = sound->isStereo() ? 2 : 1; | |
| 1129 | − const float factor = log(1.0f + (entity->getMinimumAACube().getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2); | |
| 1130 | − const int standardRate = AudioConstants::SAMPLE_RATE; | |
| 1131 | − const int resampledRate = standardRate * factor; | |
| 1132 | − const int nInputSamples = samples.size() / sizeof(int16_t); | |
| 1133 | − const int nOutputSamples = nInputSamples * factor; | |
| 1134 | − QByteArray resampled(nOutputSamples * sizeof(int16_t), '\0'); | |
| 1135 | − const int16_t* receivedSamples = reinterpret_cast<const int16_t*>(samples.data()); | |
| 1136 | − soxr_error_t soxError = soxr_oneshot(standardRate, resampledRate, channelCount, | |
| 1137 | − receivedSamples, nInputSamples, NULL, | |
| 1138 | − reinterpret_cast<int16_t*>(resampled.data()), nOutputSamples, NULL, | |
| 1139 | − &spec, &qualitySpec, 0); | |
| 1140 | − if (soxError) { | |
| 1141 | − qCDebug(entitiesrenderer) << "Unable to resample" << collisionSoundURL << "from" << nInputSamples << "@" << standardRate << "to" << nOutputSamples << "@" << resampledRate; | |
| 1142 | − resampled = samples; | |
| 1143 | − } | |
| 1144 | − | |
| 1145 | − AudioInjector* injector = new AudioInjector(resampled, options); | |
| 1146 | − injector->setLocalAudioInterface(_localAudioInterface); | |
| 1147 | − injector->triggerDeleteAfterFinish(); | |
| 1148 | − QThread* injectorThread = new QThread(); | |
| 1149 | − injectorThread->setObjectName("Audio Injector Thread"); | |
| 1150 | − injector->moveToThread(injectorThread); | |
| 1151 | − // start injecting when the injector thread starts | |
| 1152 | − connect(injectorThread, &QThread::started, injector, &AudioInjector::injectAudio); | |
| 1153 | − // connect the right slots and signals for AudioInjector and thread cleanup | |
| 1154 | − connect(injector, &AudioInjector::destroyed, injectorThread, &QThread::quit); | |
| 1155 | − connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater); | |
| 1156 | − injectorThread->start(); | |
| 1101 | + const float stretchFactor = log(1.0f + (entity->getMinimumAACube().getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2); | |
| 1102 | + AudioInjector::playSound(collisionSoundURL, volume, stretchFactor, position); | |
| 1157 | 1103 | } |
| 1158 | 1104 | |
| 1159 | 1105 | void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, |
| @@ -158,7 +158,6 @@ private: · 157 unmodified lines | ||
| 158 | 158 | QHash<EntityItemID, EntityScriptDetails> _entityScripts; |
| 159 | 159 | |
| 160 | 160 | void playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision); |
| 161 | − AbstractAudioInterface* _localAudioInterface; // So we can render collision sounds | |
| 162 | 161 | |
| 163 | 162 | bool _lastMouseEventValid; |
| 164 | 163 | MouseEvent _lastMouseEvent; |
| @@ -43,9 +43,9 @@ void RenderableLineEntityItem::render(RenderArgs* args) { · 42 unmodified lines | ||
| 43 | 43 | |
| 44 | 44 | Q_ASSERT(args->_batch); |
| 45 | 45 | gpu::Batch& batch = *args->_batch; |
| 46 | − // TODO: Figure out clean , efficient way to do relative line positioning. For now we'll just use absolute positioning. | |
| 47 | − //batch.setModelTransform(getTransformToCenter()); | |
| 48 | − batch.setModelTransform(Transform()); | |
| 46 | + Transform transform = Transform(); | |
| 47 | + transform.setTranslation(getPosition()); | |
| 48 | + batch.setModelTransform(transform); | |
| 49 | 49 | |
| 50 | 50 | batch._glLineWidth(getLineWidth()); |
| 51 | 51 | if (getLinePoints().size() > 1) { |
| @@ -11,10 +11,18 @@ · 10 unmodified lines | ||
| 11 | 11 | |
| 12 | 12 | #include <QByteArray> |
| 13 | 13 | |
| 14 | +#ifdef __GNUC__ | |
| 15 | +#pragma GCC diagnostic push | |
| 16 | +#pragma GCC diagnostic ignored "-Wdouble-promotion" | |
| 17 | +#endif | |
| 14 | 18 | |
| 15 | 19 | #include <glm/gtx/quaternion.hpp> |
| 16 | 20 | #include <glm/gtx/string_cast.hpp> |
| 17 | 21 | |
| 22 | +#ifdef __GNUC__ | |
| 23 | +#pragma GCC diagnostic pop | |
| 24 | +#endif | |
| 25 | + | |
| 18 | 26 | #include <gpu/GPUConfig.h> |
| 19 | 27 | |
| 20 | 28 | #include <DeferredLightingEffect.h> |
| @@ -141,11 +149,7 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) · 120 unmodified lines | ||
| 141 | 149 | decompressVolumeData(); |
| 142 | 150 | } |
| 143 | 151 | |
| 144 | −void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { | |
| 145 | − if (voxelSurfaceStyle == _voxelSurfaceStyle) { | |
| 146 | − return; | |
| 147 | − } | |
| 148 | − | |
| 152 | +void RenderablePolyVoxEntityItem::updateVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { | |
| 149 | 153 | // if we are switching to or from "edged" we need to force a resize of _volData. |
| 150 | 154 | if (voxelSurfaceStyle == SURFACE_EDGED_CUBIC || |
| 151 | 155 | _voxelSurfaceStyle == SURFACE_EDGED_CUBIC) { |
| @@ -153,10 +157,10 @@ void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxel · 1 unmodified line | ||
| 153 | 157 | delete _volData; |
| 154 | 158 | } |
| 155 | 159 | _volData = nullptr; |
| 156 | − PolyVoxEntityItem::setVoxelSurfaceStyle(voxelSurfaceStyle); | |
| 160 | + _voxelSurfaceStyle = voxelSurfaceStyle; | |
| 157 | 161 | setVoxelVolumeSize(_voxelVolumeSize); |
| 158 | 162 | } else { |
| 159 | − PolyVoxEntityItem::setVoxelSurfaceStyle(voxelSurfaceStyle); | |
| 163 | + _voxelSurfaceStyle = voxelSurfaceStyle; | |
| 160 | 164 | } |
| 161 | 165 | _needsModelReload = true; |
| 162 | 166 | } |
| @@ -36,17 +36,15 @@ public: · 35 unmodified lines | ||
| 36 | 36 | |
| 37 | 37 | virtual uint8_t getVoxel(int x, int y, int z); |
| 38 | 38 | virtual void setVoxel(int x, int y, int z, uint8_t toValue); |
| 39 | − | |
| 39 | + | |
| 40 | 40 | void updateOnCount(int x, int y, int z, uint8_t new_value); |
| 41 | 41 | |
| 42 | 42 | void render(RenderArgs* args); |
| 43 | 43 | virtual bool supportsDetailedRayIntersection() const { return true; } |
| 44 | 44 | virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, |
| 45 | − bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, | |
| 45 | + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, | |
| 46 | 46 | void** intersectedObject, bool precisionPicking) const; |
| 47 | 47 | |
| 48 | − virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle); | |
| 49 | − | |
| 50 | 48 | void getModel(); |
| 51 | 49 | |
| 52 | 50 | virtual void setVoxelData(QByteArray voxelData); |
| @@ -74,6 +72,9 @@ public: · 21 unmodified lines | ||
| 74 | 72 | |
| 75 | 73 | SIMPLE_RENDERABLE(); |
| 76 | 74 | |
| 75 | +protected: | |
| 76 | + virtual void updateVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle); | |
| 77 | + | |
| 77 | 78 | private: |
| 78 | 79 | // The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions |
| 79 | 80 | // may not match _voxelVolumeSize. |
| @@ -82,6 +83,7 @@ private: · 2 unmodified lines | ||
| 82 | 83 | void compressVolumeData(); |
| 83 | 84 | void decompressVolumeData(); |
| 84 | 85 | |
| 86 | + | |
| 85 | 87 | PolyVox::SimpleVolume<uint8_t>* _volData = nullptr; |
| 86 | 88 | model::Geometry _modelGeometry; |
| 87 | 89 | bool _needsModelReload = true; |
| @@ -95,6 +95,7 @@ bool DeleteEntityOperator::preRecursion(OctreeElement* element) { · 94 unmodified lines | ||
| 95 | 95 | EntityItemPointer theEntity = details.entity; |
| 96 | 96 | bool entityDeleted = entityTreeElement->removeEntityItem(theEntity); // remove it from the element |
| 97 | 97 | assert(entityDeleted); |
| 98 | + (void)entityDeleted; // quite warning | |
| 98 | 99 | _tree->setContainingElement(details.entity->getEntityItemID(), NULL); // update or id to element lookup |
| 99 | 100 | _foundCount++; |
| 100 | 101 | } |
| @@ -19,8 +19,8 @@ EntityActionType EntityActionInterface::actionTypeFromString(QString actionTypeS · 18 unmodified lines | ||
| 19 | 19 | if (normalizedActionTypeString == "none") { |
| 20 | 20 | return ACTION_TYPE_NONE; |
| 21 | 21 | } |
| 22 | − if (normalizedActionTypeString == "pulltopoint") { | |
| 23 | − return ACTION_TYPE_PULL_TO_POINT; | |
| 22 | + if (normalizedActionTypeString == "offset") { | |
| 23 | + return ACTION_TYPE_OFFSET; | |
| 24 | 24 | } |
| 25 | 25 | if (normalizedActionTypeString == "spring") { |
| 26 | 26 | return ACTION_TYPE_SPRING; |
| @@ -37,8 +37,8 @@ QString EntityActionInterface::actionTypeToString(EntityActionType actionType) { · 10 unmodified lines | ||
| 37 | 37 | switch(actionType) { |
| 38 | 38 | case ACTION_TYPE_NONE: |
| 39 | 39 | return "none"; |
| 40 | − case ACTION_TYPE_PULL_TO_POINT: | |
| 41 | − return "pullToPoint"; | |
| 40 | + case ACTION_TYPE_OFFSET: | |
| 41 | + return "offset"; | |
| 42 | 42 | case ACTION_TYPE_SPRING: |
| 43 | 43 | return "spring"; |
| 44 | 44 | case ACTION_TYPE_HOLD: |
| @@ -21,7 +21,7 @@ class EntitySimulation; · 20 unmodified lines | ||
| 21 | 21 | enum EntityActionType { |
| 22 | 22 | // keep these synchronized with actionTypeFromString and actionTypeToString |
| 23 | 23 | ACTION_TYPE_NONE, |
| 24 | − ACTION_TYPE_PULL_TO_POINT, | |
| 24 | + ACTION_TYPE_OFFSET, | |
| 25 | 25 | ACTION_TYPE_SPRING, |
| 26 | 26 | ACTION_TYPE_HOLD |
| 27 | 27 | }; |
| @@ -639,8 +639,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef · 638 unmodified lines | ||
| 639 | 639 | void EntityItem::debugDump() const { |
| 640 | 640 | auto position = getPosition(); |
| 641 | 641 | qCDebug(entities) << "EntityItem id:" << getEntityItemID(); |
| 642 | − qCDebug(entities, " edited ago:%f", getEditedAgo()); | |
| 643 | − qCDebug(entities, " position:%f,%f,%f", position.x, position.y, position.z); | |
| 642 | + qCDebug(entities, " edited ago:%f", (double)getEditedAgo()); | |
| 643 | + qCDebug(entities, " position:%f,%f,%f", (double)position.x, (double)position.y, (double)position.z); | |
| 644 | 644 | qCDebug(entities) << " dimensions:" << getDimensions(); |
| 645 | 645 | } |
| 646 | 646 | |
| @@ -14,7 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | |
| 15 | 15 | #include <stdint.h> |
| 16 | 16 | |
| 17 | − | |
| 17 | +#include <QDebug> | |
| 18 | 18 | #include <QObject> |
| 19 | 19 | #include <QHash> |
| 20 | 20 | #include <QScriptEngine> |
| @@ -197,6 +197,8 @@ public: · 196 unmodified lines | ||
| 197 | 197 | QString getSimulatorIDAsString() const { return _simulatorID.toString().mid(1,36).toUpper(); } |
| 198 | 198 | |
| 199 | 199 | void setVoxelDataDirty() { _voxelDataChanged = true; } |
| 200 | + | |
| 201 | + void setLinePointsDirty() {_linePointsChanged = true; } | |
| 200 | 202 | |
| 201 | 203 | void setCreated(QDateTime& v); |
| 202 | 204 | |
| @@ -442,6 +442,43 @@ bool EntityScriptingInterface::setVoxels(QUuid entityID, · 441 unmodified lines | ||
| 442 | 442 | return true; |
| 443 | 443 | } |
| 444 | 444 | |
| 445 | +bool EntityScriptingInterface::setPoints(QUuid entityID, std::function<bool(LineEntityItem&)> actor) { | |
| 446 | + if (!_entityTree) { | |
| 447 | + return false; | |
| 448 | + } | |
| 449 | + | |
| 450 | + EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID)); | |
| 451 | + if (!entity) { | |
| 452 | + qCDebug(entities) << "EntityScriptingInterface::setPoints no entity with ID" << entityID; | |
| 453 | + } | |
| 454 | + | |
| 455 | + EntityTypes::EntityType entityType = entity->getType(); | |
| 456 | + | |
| 457 | + if (entityType != EntityTypes::Line) { | |
| 458 | + return false; | |
| 459 | + } | |
| 460 | + | |
| 461 | + auto now = usecTimestampNow(); | |
| 462 | + | |
| 463 | + LineEntityItem* lineEntity = static_cast<LineEntityItem*>(entity.get()); | |
| 464 | + _entityTree->lockForWrite(); | |
| 465 | + bool success = actor(*lineEntity); | |
| 466 | + entity->setLastEdited(now); | |
| 467 | + entity->setLastBroadcast(now); | |
| 468 | + _entityTree->unlock(); | |
| 469 | + | |
| 470 | + _entityTree->lockForRead(); | |
| 471 | + EntityItemProperties properties = entity->getProperties(); | |
| 472 | + _entityTree->unlock(); | |
| 473 | + | |
| 474 | + properties.setLinePointsDirty(); | |
| 475 | + properties.setLastEdited(now); | |
| 476 | + | |
| 477 | + | |
| 478 | + queueEntityMessage(PacketTypeEntityEdit, entityID, properties); | |
| 479 | + return success; | |
| 480 | +} | |
| 481 | + | |
| 445 | 482 | bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) { |
| 446 | 483 | return setVoxels(entityID, [center, radius, value](PolyVoxEntityItem& polyVoxEntity) { |
| 447 | 484 | polyVoxEntity.setSphere(center, radius, value); |
| @@ -460,6 +497,21 @@ bool EntityScriptingInterface::setAllVoxels(QUuid entityID, int value) { · 12 unmodified lines | ||
| 460 | 497 | }); |
| 461 | 498 | } |
| 462 | 499 | |
| 500 | +bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector<glm::vec3>& points) { | |
| 501 | + return setPoints(entityID, [points](LineEntityItem& lineEntity) -> bool | |
| 502 | + { | |
| 503 | + return lineEntity.setLinePoints(points); | |
| 504 | + }); | |
| 505 | +} | |
| 506 | + | |
| 507 | +bool EntityScriptingInterface::appendPoint(QUuid entityID, const glm::vec3& point) { | |
| 508 | + return setPoints(entityID, [point](LineEntityItem& lineEntity) -> bool | |
| 509 | + { | |
| 510 | + return lineEntity.appendPoint(point); | |
| 511 | + }); | |
| 512 | + | |
| 513 | +} | |
| 514 | + | |
| 463 | 515 | |
| 464 | 516 | bool EntityScriptingInterface::actionWorker(const QUuid& entityID, |
| 465 | 517 | std::function<bool(EntitySimulation*, EntityItemPointer)> actor) { |
| @@ -22,6 +22,7 @@ · 21 unmodified lines | ||
| 22 | 22 | #include <OctreeScriptingInterface.h> |
| 23 | 23 | #include <RegisteredMetaTypes.h> |
| 24 | 24 | #include "PolyVoxEntityItem.h" |
| 25 | +#include "LineEntityItem.h" | |
| 25 | 26 | |
| 26 | 27 | #include "EntityEditPacketSender.h" |
| 27 | 28 | |
| @@ -121,6 +122,9 @@ public slots: · 93 unmodified lines | ||
| 121 | 122 | Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value); |
| 122 | 123 | Q_INVOKABLE bool setVoxel(QUuid entityID, const glm::vec3& position, int value); |
| 123 | 124 | Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value); |
| 125 | + | |
| 126 | + Q_INVOKABLE bool setAllPoints(QUuid entityID, const QVector<glm::vec3>& points); | |
| 127 | + Q_INVOKABLE bool appendPoint(QUuid entityID, const glm::vec3& point); | |
| 124 | 128 | |
| 125 | 129 | Q_INVOKABLE void dumpTree() const; |
| 126 | 130 | |
| @@ -157,6 +161,7 @@ signals: · 30 unmodified lines | ||
| 157 | 161 | private: |
| 158 | 162 | bool actionWorker(const QUuid& entityID, std::function<bool(EntitySimulation*, EntityItemPointer)> actor); |
| 159 | 163 | bool setVoxels(QUuid entityID, std::function<void(PolyVoxEntityItem&)> actor); |
| 164 | + bool setPoints(QUuid entityID, std::function<bool(LineEntityItem&)> actor); | |
| 160 | 165 | void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties); |
| 161 | 166 | |
| 162 | 167 | /// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode |
| @@ -23,6 +23,7 @@ · 22 unmodified lines | ||
| 23 | 23 | |
| 24 | 24 | |
| 25 | 25 | const float LineEntityItem::DEFAULT_LINE_WIDTH = 2.0f; |
| 26 | +const int LineEntityItem::MAX_POINTS_PER_LINE = 70; | |
| 26 | 27 | |
| 27 | 28 | |
| 28 | 29 | EntityItemPointer LineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { |
| @@ -85,24 +86,38 @@ bool LineEntityItem::setProperties(const EntityItemProperties& properties) { · 56 unmodified lines | ||
| 85 | 86 | return somethingChanged; |
| 86 | 87 | } |
| 87 | 88 | |
| 88 | −void LineEntityItem::setLinePoints(const QVector<glm::vec3>& points) { | |
| 89 | − QVector<glm::vec3> sanitizedPoints; | |
| 90 | − int invalidPoints = 0; | |
| 89 | +bool LineEntityItem::appendPoint(const glm::vec3& point) { | |
| 90 | + if (_points.size() > MAX_POINTS_PER_LINE - 1) { | |
| 91 | + qDebug() << "MAX POINTS REACHED!"; | |
| 92 | + return false; | |
| 93 | + } | |
| 94 | + glm::vec3 halfBox = getDimensions() * 0.5f; | |
| 95 | + if ( (point.x < - halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < - halfBox.z || point.z > halfBox.z) ) { | |
| 96 | + qDebug() << "Point is outside entity's bounding box"; | |
| 97 | + return false; | |
| 98 | + } | |
| 99 | + _points << point; | |
| 100 | + _pointsChanged = true; | |
| 101 | + return true; | |
| 102 | +} | |
| 103 | + | |
| 104 | +bool LineEntityItem::setLinePoints(const QVector<glm::vec3>& points) { | |
| 105 | + if (points.size() > MAX_POINTS_PER_LINE) { | |
| 106 | + return false; | |
| 107 | + } | |
| 91 | 108 | for (int i = 0; i < points.size(); i++) { |
| 92 | 109 | glm::vec3 point = points.at(i); |
| 93 | − // Make sure all of our points are valid numbers. | |
| 94 | − // Must be greater than 0 because vector component is set to 0 if it is invalid data. Also should never be greater than TREE_SCALE | |
| 95 | − if ( (point.x > 0 && point.x < TREE_SCALE) && (point.y > 0 && point.y < TREE_SCALE) && (point.z > 0 && point.z < TREE_SCALE) ) { | |
| 96 | − sanitizedPoints << point; | |
| 97 | − } else { | |
| 98 | − ++invalidPoints; | |
| 110 | + glm::vec3 pos = getPosition(); | |
| 111 | + glm::vec3 halfBox = getDimensions() * 0.5f; | |
| 112 | + if ( (point.x < - halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < - halfBox.z || point.z > halfBox.z) ) { | |
| 113 | + qDebug() << "Point is outside entity's bounding box"; | |
| 114 | + return false; | |
| 99 | 115 | } |
| 116 | + | |
| 100 | 117 | } |
| 101 | − if (invalidPoints > 0) { | |
| 102 | − qDebug() << "Line with" << invalidPoints << "INVALID POINTS"; | |
| 103 | − } | |
| 104 | − _points = sanitizedPoints; | |
| 118 | + _points = points; | |
| 105 | 119 | _pointsChanged = true; |
| 120 | + return true; | |
| 106 | 121 | } |
| 107 | 122 | |
| 108 | 123 | int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, |
| @@ -54,7 +54,8 @@ class LineEntityItem : public EntityItem { · 53 unmodified lines | ||
| 54 | 54 | void setLineWidth(float lineWidth){ _lineWidth = lineWidth; } |
| 55 | 55 | float getLineWidth() const{ return _lineWidth; } |
| 56 | 56 | |
| 57 | − void setLinePoints(const QVector<glm::vec3>& points); | |
| 57 | + bool setLinePoints(const QVector<glm::vec3>& points); | |
| 58 | + bool appendPoint(const glm::vec3& point); | |
| 58 | 59 | |
| 59 | 60 | const QVector<glm::vec3>& getLinePoints() const{ return _points; } |
| 60 | 61 | |
| @@ -68,6 +69,7 @@ class LineEntityItem : public EntityItem { · 7 unmodified lines | ||
| 68 | 69 | |
| 69 | 70 | virtual void debugDump() const; |
| 70 | 71 | static const float DEFAULT_LINE_WIDTH; |
| 72 | + static const int MAX_POINTS_PER_LINE; | |
| 71 | 73 | |
| 72 | 74 | protected: |
| 73 | 75 | rgbColor _color; |
| @@ -168,3 +168,10 @@ void PolyVoxEntityItem::debugDump() const { · 167 unmodified lines | ||
| 168 | 168 | qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions()); |
| 169 | 169 | qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); |
| 170 | 170 | } |
| 171 | + | |
| 172 | +void PolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { | |
| 173 | + if (voxelSurfaceStyle == _voxelSurfaceStyle) { | |
| 174 | + return; | |
| 175 | + } | |
| 176 | + updateVoxelSurfaceStyle(voxelSurfaceStyle); | |
| 177 | +} | |
| @@ -61,10 +61,9 @@ class PolyVoxEntityItem : public EntityItem { · 60 unmodified lines | ||
| 61 | 61 | SURFACE_EDGED_CUBIC |
| 62 | 62 | }; |
| 63 | 63 | |
| 64 | − virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { _voxelSurfaceStyle = voxelSurfaceStyle; } | |
| 65 | − virtual void setVoxelSurfaceStyle(uint16_t voxelSurfaceStyle) { | |
| 66 | − setVoxelSurfaceStyle((PolyVoxSurfaceStyle) voxelSurfaceStyle); | |
| 67 | − } | |
| 64 | + void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle); | |
| 65 | + // this other version of setVoxelSurfaceStyle is needed for SET_ENTITY_PROPERTY_FROM_PROPERTIES | |
| 66 | + void setVoxelSurfaceStyle(uint16_t voxelSurfaceStyle) { setVoxelSurfaceStyle((PolyVoxSurfaceStyle) voxelSurfaceStyle); } | |
| 68 | 67 | virtual PolyVoxSurfaceStyle getVoxelSurfaceStyle() const { return _voxelSurfaceStyle; } |
| 69 | 68 | |
| 70 | 69 | static const glm::vec3 DEFAULT_VOXEL_VOLUME_SIZE; |
| @@ -89,6 +88,10 @@ class PolyVoxEntityItem : public EntityItem { · 18 unmodified lines | ||
| 89 | 88 | static QByteArray makeEmptyVoxelData(quint16 voxelXSize = 16, quint16 voxelYSize = 16, quint16 voxelZSize = 16); |
| 90 | 89 | |
| 91 | 90 | protected: |
| 91 | + virtual void updateVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { | |
| 92 | + _voxelSurfaceStyle = voxelSurfaceStyle; | |
| 93 | + } | |
| 94 | + | |
| 92 | 95 | glm::vec3 _voxelVolumeSize; // this is always 3 bytes |
| 93 | 96 | QByteArray _voxelData; |
| 94 | 97 | PolyVoxSurfaceStyle _voxelSurfaceStyle; |
| @@ -506,7 +506,7 @@ FBXNode parseFBX(QIODevice* device) { · 505 unmodified lines | ||
| 506 | 506 | |
| 507 | 507 | QVector<glm::vec4> createVec4Vector(const QVector<double>& doubleVector) { |
| 508 | 508 | QVector<glm::vec4> values; |
| 509 | − for (const double* it = doubleVector.constData(), *end = it + (doubleVector.size() / 4 * 4); it != end; ) { | |
| 509 | + for (const double* it = doubleVector.constData(), *end = it + ((doubleVector.size() / 4) * 4); it != end; ) { | |
| 510 | 510 | float x = *it++; |
| 511 | 511 | float y = *it++; |
| 512 | 512 | float z = *it++; |
| @@ -516,9 +516,27 @@ QVector<glm::vec4> createVec4Vector(const QVector<double>& doubleVector) { · 3 unmodified lines | ||
| 516 | 516 | return values; |
| 517 | 517 | } |
| 518 | 518 | |
| 519 | + | |
| 520 | +QVector<glm::vec4> createVec4VectorRGBA(const QVector<double>& doubleVector, glm::vec4& average) { | |
| 521 | + QVector<glm::vec4> values; | |
| 522 | + for (const double* it = doubleVector.constData(), *end = it + ((doubleVector.size() / 4) * 4); it != end; ) { | |
| 523 | + float x = *it++; | |
| 524 | + float y = *it++; | |
| 525 | + float z = *it++; | |
| 526 | + float w = *it++; | |
| 527 | + auto val = glm::vec4(x, y, z, w); | |
| 528 | + values.append(val); | |
| 529 | + average += val; | |
| 530 | + } | |
| 531 | + if (!values.isEmpty()) { | |
| 532 | + average *= (1.0f / float(values.size())); | |
| 533 | + } | |
| 534 | + return values; | |
| 535 | +} | |
| 536 | + | |
| 519 | 537 | QVector<glm::vec3> createVec3Vector(const QVector<double>& doubleVector) { |
| 520 | 538 | QVector<glm::vec3> values; |
| 521 | − for (const double* it = doubleVector.constData(), *end = it + (doubleVector.size() / 3 * 3); it != end; ) { | |
| 539 | + for (const double* it = doubleVector.constData(), *end = it + ((doubleVector.size() / 3) * 3); it != end; ) { | |
| 522 | 540 | float x = *it++; |
| 523 | 541 | float y = *it++; |
| 524 | 542 | float z = *it++; |
| @@ -529,7 +547,7 @@ QVector<glm::vec3> createVec3Vector(const QVector<double>& doubleVector) { · 4 unmodified lines | ||
| 529 | 547 | |
| 530 | 548 | QVector<glm::vec2> createVec2Vector(const QVector<double>& doubleVector) { |
| 531 | 549 | QVector<glm::vec2> values; |
| 532 | − for (const double* it = doubleVector.constData(), *end = it + (doubleVector.size() / 2 * 2); it != end; ) { | |
| 550 | + for (const double* it = doubleVector.constData(), *end = it + ((doubleVector.size() / 2) * 2); it != end; ) { | |
| 533 | 551 | float s = *it++; |
| 534 | 552 | float t = *it++; |
| 535 | 553 | values.append(glm::vec2(s, -t)); |
| @@ -799,6 +817,7 @@ public: · 263 unmodified lines | ||
| 799 | 817 | QVector<int> normalIndices; |
| 800 | 818 | |
| 801 | 819 | bool colorsByVertex; |
| 820 | + glm::vec4 averageColor{1.0f, 1.0f, 1.0f, 1.0f}; | |
| 802 | 821 | QVector<glm::vec4> colors; |
| 803 | 822 | QVector<int> colorIndices; |
| 804 | 823 | |
| @@ -940,8 +959,7 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) { · 135 unmodified lines | ||
| 940 | 959 | bool indexToDirect = false; |
| 941 | 960 | foreach (const FBXNode& subdata, child.children) { |
| 942 | 961 | if (subdata.name == "Colors") { |
| 943 | − data.colors = createVec4Vector(getDoubleVector(subdata)); | |
| 944 | − | |
| 962 | + data.colors = createVec4VectorRGBA(getDoubleVector(subdata), data.averageColor); | |
| 945 | 963 | } else if (subdata.name == "ColorsIndex") { |
| 946 | 964 | data.colorIndices = getIntVector(subdata); |
| 947 | 965 | |
| @@ -956,6 +974,19 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) { · 8 unmodified lines | ||
| 956 | 974 | // hack to work around wacky Makehuman exports |
| 957 | 975 | data.colorsByVertex = true; |
| 958 | 976 | } |
| 977 | + | |
| 978 | +#if defined(FBXREADER_KILL_BLACK_COLOR_ATTRIBUTE) | |
| 979 | + // Potential feature where we decide to kill the color attribute is to dark? | |
| 980 | + // Tested with the model: | |
| 981 | + // https://hifi-public.s3.amazonaws.com/ryan/gardenLight2.fbx | |
| 982 | + // let's check if we did have true data ? | |
| 983 | + if (glm::all(glm::lessThanEqual(data.averageColor, glm::vec4(0.09f)))) { | |
| 984 | + data.colors.clear(); | |
| 985 | + data.colorIndices.clear(); | |
| 986 | + data.colorsByVertex = false; | |
| 987 | + qCDebug(modelformat) << "LayerElementColor has an average value of 0.0f... let's forget it."; | |
| 988 | + } | |
| 989 | +#endif | |
| 959 | 990 | |
| 960 | 991 | } else if (child.name == "LayerElementUV") { |
| 961 | 992 | if (child.properties.at(0).toInt() == 0) { |
| @@ -1251,7 +1282,7 @@ FBXLight extractLight(const FBXNode& object) { · 289 unmodified lines | ||
| 1251 | 1282 | if (property.name == "P") { |
| 1252 | 1283 | QString propname = property.properties.at(0).toString(); |
| 1253 | 1284 | if (propname == "Intensity") { |
| 1254 | − light.intensity = 0.01f * property.properties.at(valIndex).value<double>(); | |
| 1285 | + light.intensity = 0.01f * property.properties.at(valIndex).value<float>(); | |
| 1255 | 1286 | } else if (propname == "Color") { |
| 1256 | 1287 | light.color = getVec3(property.properties, valIndex); |
| 1257 | 1288 | } |
| @@ -70,7 +70,7 @@ public: · 69 unmodified lines | ||
| 70 | 70 | typedef Stream::Slot Slot; |
| 71 | 71 | |
| 72 | 72 | Batch(); |
| 73 | − Batch(const Batch& batch); | |
| 73 | + explicit Batch(const Batch& batch); | |
| 74 | 74 | ~Batch(); |
| 75 | 75 | |
| 76 | 76 | void clear(); |
| @@ -148,6 +148,7 @@ public: · 71 unmodified lines | ||
| 148 | 148 | void _glDrawBuffers(GLsizei n, const GLenum* bufs); |
| 149 | 149 | |
| 150 | 150 | void _glUseProgram(GLuint program); |
| 151 | + void _glUniform1i(GLint location, GLint v0); | |
| 151 | 152 | void _glUniform1f(GLint location, GLfloat v0); |
| 152 | 153 | void _glUniform2f(GLint location, GLfloat v0, GLfloat v1); |
| 153 | 154 | void _glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); |
| @@ -210,6 +211,7 @@ public: · 56 unmodified lines | ||
| 210 | 211 | COMMAND_glDrawBuffers, |
| 211 | 212 | |
| 212 | 213 | COMMAND_glUseProgram, |
| 214 | + COMMAND_glUniform1i, | |
| 213 | 215 | COMMAND_glUniform1f, |
| 214 | 216 | COMMAND_glUniform2f, |
| 215 | 217 | COMMAND_glUniform3f, |
| @@ -12,6 +12,8 @@ · 11 unmodified lines | ||
| 12 | 12 | #include "GLBackendShared.h" |
| 13 | 13 | #include <glm/gtc/type_ptr.hpp> |
| 14 | 14 | |
| 15 | +using namespace gpu; | |
| 16 | + | |
| 15 | 17 | GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = |
| 16 | 18 | { |
| 17 | 19 | (&::gpu::GLBackend::do_draw), |
| @@ -59,6 +61,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = · 41 unmodified lines | ||
| 59 | 61 | (&::gpu::GLBackend::do_glDrawBuffers), |
| 60 | 62 | |
| 61 | 63 | (&::gpu::GLBackend::do_glUseProgram), |
| 64 | + (&::gpu::GLBackend::do_glUniform1i), | |
| 62 | 65 | (&::gpu::GLBackend::do_glUniform1f), |
| 63 | 66 | (&::gpu::GLBackend::do_glUniform2f), |
| 64 | 67 | (&::gpu::GLBackend::do_glUniform3f), |
| @@ -141,6 +144,14 @@ bool GLBackend::checkGLError(const char* name) { · 76 unmodified lines | ||
| 141 | 144 | } |
| 142 | 145 | } |
| 143 | 146 | |
| 147 | +bool GLBackend::checkGLErrorDebug(const char* name) { | |
| 148 | +#ifdef DEBUG | |
| 149 | + return checkGLError(name); | |
| 150 | +#else | |
| 151 | + Q_UNUSED(name); | |
| 152 | + return false; | |
| 153 | +#endif | |
| 154 | +} | |
| 144 | 155 | |
| 145 | 156 | void GLBackend::syncCache() { |
| 146 | 157 | syncTransformStateCache(); |
| @@ -433,6 +444,29 @@ void GLBackend::do_glUseProgram(Batch& batch, uint32 paramOffset) { · 286 unmodified lines | ||
| 433 | 444 | (void) CHECK_GL_ERROR(); |
| 434 | 445 | } |
| 435 | 446 | |
| 447 | +void Batch::_glUniform1i(GLint location, GLint v0) { | |
| 448 | + if (location < 0) { | |
| 449 | + return; | |
| 450 | + } | |
| 451 | + ADD_COMMAND_GL(glUniform1i); | |
| 452 | + _params.push_back(v0); | |
| 453 | + _params.push_back(location); | |
| 454 | + | |
| 455 | + DO_IT_NOW(_glUniform1i, 1); | |
| 456 | +} | |
| 457 | +void GLBackend::do_glUniform1i(Batch& batch, uint32 paramOffset) { | |
| 458 | + if (_pipeline._program == 0) { | |
| 459 | + // We should call updatePipeline() to bind the program but we are not doing that | |
| 460 | + // because these uniform setters are deprecated and we don;t want to create side effect | |
| 461 | + return; | |
| 462 | + } | |
| 463 | + updatePipeline(); | |
| 464 | + glUniform1f( | |
| 465 | + batch._params[paramOffset + 1]._int, | |
| 466 | + batch._params[paramOffset + 0]._int); | |
| 467 | + (void) CHECK_GL_ERROR(); | |
| 468 | +} | |
| 469 | + | |
| 436 | 470 | void Batch::_glUniform1f(GLint location, GLfloat v0) { |
| 437 | 471 | if (location < 0) { |
| 438 | 472 | return; |
| @@ -449,6 +483,8 @@ void GLBackend::do_glUniform1f(Batch& batch, uint32 paramOffset) { · 10 unmodified lines | ||
| 449 | 483 | // because these uniform setters are deprecated and we don;t want to create side effect |
| 450 | 484 | return; |
| 451 | 485 | } |
| 486 | + updatePipeline(); | |
| 487 | + | |
| 452 | 488 | glUniform1f( |
| 453 | 489 | batch._params[paramOffset + 1]._int, |
| 454 | 490 | batch._params[paramOffset + 0]._float); |
| @@ -471,6 +507,7 @@ void GLBackend::do_glUniform2f(Batch& batch, uint32 paramOffset) { · 16 unmodified lines | ||
| 471 | 507 | // because these uniform setters are deprecated and we don;t want to create side effect |
| 472 | 508 | return; |
| 473 | 509 | } |
| 510 | + updatePipeline(); | |
| 474 | 511 | glUniform2f( |
| 475 | 512 | batch._params[paramOffset + 2]._int, |
| 476 | 513 | batch._params[paramOffset + 1]._float, |
| @@ -495,6 +532,7 @@ void GLBackend::do_glUniform3f(Batch& batch, uint32 paramOffset) { · 18 unmodified lines | ||
| 495 | 532 | // because these uniform setters are deprecated and we don;t want to create side effect |
| 496 | 533 | return; |
| 497 | 534 | } |
| 535 | + updatePipeline(); | |
| 498 | 536 | glUniform3f( |
| 499 | 537 | batch._params[paramOffset + 3]._int, |
| 500 | 538 | batch._params[paramOffset + 2]._float, |
| @@ -519,6 +557,7 @@ void GLBackend::do_glUniform3fv(Batch& batch, uint32 paramOffset) { · 18 unmodified lines | ||
| 519 | 557 | // because these uniform setters are deprecated and we don;t want to create side effect |
| 520 | 558 | return; |
| 521 | 559 | } |
| 560 | + updatePipeline(); | |
| 522 | 561 | glUniform3fv( |
| 523 | 562 | batch._params[paramOffset + 2]._int, |
| 524 | 563 | batch._params[paramOffset + 1]._uint, |
| @@ -544,6 +583,7 @@ void GLBackend::do_glUniform4fv(Batch& batch, uint32 paramOffset) { · 19 unmodified lines | ||
| 544 | 583 | // because these uniform setters are deprecated and we don;t want to create side effect |
| 545 | 584 | return; |
| 546 | 585 | } |
| 586 | + updatePipeline(); | |
| 547 | 587 | glUniform4fv( |
| 548 | 588 | batch._params[paramOffset + 2]._int, |
| 549 | 589 | batch._params[paramOffset + 1]._uint, |
| @@ -569,6 +609,7 @@ void GLBackend::do_glUniformMatrix4fv(Batch& batch, uint32 paramOffset) { · 19 unmodified lines | ||
| 569 | 609 | // because these uniform setters are deprecated and we don;t want to create side effect |
| 570 | 610 | return; |
| 571 | 611 | } |
| 612 | + updatePipeline(); | |
| 572 | 613 | glUniformMatrix4fv( |
| 573 | 614 | batch._params[paramOffset + 3]._int, |
| 574 | 615 | batch._params[paramOffset + 2]._uint, |
| @@ -656,4 +697,20 @@ void GLBackend::fetchMatrix(GLenum target, glm::mat4 & m) { · 81 unmodified lines | ||
| 656 | 697 | glGetFloatv(target, glm::value_ptr(m)); |
| 657 | 698 | } |
| 658 | 699 | |
| 700 | +void GLBackend::checkGLStackStable(std::function<void()> f) { | |
| 701 | +#ifdef DEBUG | |
| 702 | + GLint mvDepth, prDepth; | |
| 703 | + glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &mvDepth); | |
| 704 | + glGetIntegerv(GL_PROJECTION_STACK_DEPTH, &prDepth); | |
| 705 | +#endif | |
| 706 | + | |
| 707 | + f(); | |
| 659 | 708 | |
| 709 | +#ifdef DEBUG | |
| 710 | + GLint mvDepthFinal, prDepthFinal; | |
| 711 | + glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &mvDepthFinal); | |
| 712 | + glGetIntegerv(GL_PROJECTION_STACK_DEPTH, &prDepthFinal); | |
| 713 | + Q_ASSERT(mvDepth == mvDepthFinal); | |
| 714 | + Q_ASSERT(prDepth == prDepthFinal); | |
| 715 | +#endif | |
| 716 | +} | |
| @@ -12,11 +12,13 @@ · 11 unmodified lines | ||
| 12 | 12 | #define hifi_gpu_GLBackend_h |
| 13 | 13 | |
| 14 | 14 | #include <assert.h> |
| 15 | +#include <functional> | |
| 16 | +#include <bitset> | |
| 17 | + | |
| 15 | 18 | #include "GPUConfig.h" |
| 16 | 19 | |
| 17 | 20 | #include "Context.h" |
| 18 | 21 | #include "Batch.h" |
| 19 | −#include <bitset> | |
| 20 | 22 | |
| 21 | 23 | |
| 22 | 24 | namespace gpu { |
| @@ -47,6 +49,11 @@ public: · 24 unmodified lines | ||
| 47 | 49 | |
| 48 | 50 | static bool checkGLError(const char* name = nullptr); |
| 49 | 51 | |
| 52 | + // Only checks in debug builds | |
| 53 | + static bool checkGLErrorDebug(const char* name = nullptr); | |
| 54 | + | |
| 55 | + static void checkGLStackStable(std::function<void()> f); | |
| 56 | + | |
| 50 | 57 | static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet()); |
| 51 | 58 | |
| 52 | 59 | |
| @@ -377,6 +384,7 @@ protected: · 324 unmodified lines | ||
| 377 | 384 | void do_glDrawBuffers(Batch& batch, uint32 paramOffset); |
| 378 | 385 | |
| 379 | 386 | void do_glUseProgram(Batch& batch, uint32 paramOffset); |
| 387 | + void do_glUniform1i(Batch& batch, uint32 paramOffset); | |
| 380 | 388 | void do_glUniform1f(Batch& batch, uint32 paramOffset); |
| 381 | 389 | void do_glUniform2f(Batch& batch, uint32 paramOffset); |
| 382 | 390 | void do_glUniform3f(Batch& batch, uint32 paramOffset); |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | ||
| 11 | 11 | #include "GPULogging.h" |
| 12 | 12 | #include "GLBackendShared.h" |
| 13 | 13 | |
| 14 | +using namespace gpu; | |
| 14 | 15 | |
| 15 | 16 | GLBackend::GLFramebuffer::GLFramebuffer() {} |
| 16 | 17 | |
| @@ -17,9 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | |
| 18 | 18 | #include "Batch.h" |
| 19 | 19 | |
| 20 | −using namespace gpu; | |
| 21 | − | |
| 22 | −static const GLenum _primitiveToGLmode[NUM_PRIMITIVES] = { | |
| 20 | +static const GLenum _primitiveToGLmode[gpu::NUM_PRIMITIVES] = { | |
| 23 | 21 | GL_POINTS, |
| 24 | 22 | GL_LINES, |
| 25 | 23 | GL_LINE_STRIP, |
| @@ -30,7 +28,7 @@ static const GLenum _primitiveToGLmode[NUM_PRIMITIVES] = { · 4 unmodified lines | ||
| 30 | 28 | GL_QUAD_STRIP, |
| 31 | 29 | }; |
| 32 | 30 | |
| 33 | −static const GLenum _elementTypeToGLType[NUM_TYPES]= { | |
| 31 | +static const GLenum _elementTypeToGLType[gpu::NUM_TYPES] = { | |
| 34 | 32 | GL_FLOAT, |
| 35 | 33 | GL_INT, |
| 36 | 34 | GL_UNSIGNED_INT, |
| @@ -49,10 +47,12 @@ static const GLenum _elementTypeToGLType[NUM_TYPES]= { · 12 unmodified lines | ||
| 49 | 47 | GL_UNSIGNED_BYTE |
| 50 | 48 | }; |
| 51 | 49 | |
| 52 | −#if _DEBUG | |
| 53 | −#define CHECK_GL_ERROR() ::gpu::GLBackend::checkGLError(__FUNCTION__) | |
| 54 | −#else | |
| 55 | −#define CHECK_GL_ERROR() false | |
| 56 | −#endif | |
| 50 | +// Stupid preprocessor trick to turn the line macro into a string | |
| 51 | +#define CHECK_GL_ERROR_HELPER(x) #x | |
| 52 | +// FIXME doesn't build on Linux or Mac. Hmmmm | |
| 53 | +// #define CHECK_GL_ERROR() gpu::GLBackend::checkGLErrorDebug(__FUNCTION__ ":" CHECK_GL_ERROR_HELPER(__LINE__)) | |
| 54 | +#define CHECK_GL_ERROR() gpu::GLBackend::checkGLErrorDebug(__FUNCTION__) | |
| 55 | + | |
| 56 | +#define CHECK_GL_STACK_STABLE(f) gpu::GLBackend::checkGLStackStable(f) | |
| 57 | 57 | |
| 58 | 58 | #endif |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | ||
| 11 | 11 | #include "GPULogging.h" |
| 12 | 12 | #include "GLBackendShared.h" |
| 13 | 13 | |
| 14 | +using namespace gpu; | |
| 14 | 15 | |
| 15 | 16 | GLBackend::GLTexture::GLTexture() : |
| 16 | 17 | _storageStamp(0), |
| @@ -343,10 +344,10 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { · 326 unmodified lines | ||
| 343 | 344 | if (bytes && texture.isAutogenerateMips()) { |
| 344 | 345 | glGenerateMipmap(GL_TEXTURE_2D); |
| 345 | 346 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); |
| 346 | − } else { | |
| 347 | + }/* else { | |
| 347 | 348 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| 348 | 349 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| 349 | − } | |
| 350 | + }*/ | |
| 350 | 351 | |
| 351 | 352 | object->_target = GL_TEXTURE_2D; |
| 352 | 353 | |
| @@ -75,6 +75,8 @@ void GLBackend::syncTransformStateCache() { · 74 unmodified lines | ||
| 75 | 75 | } |
| 76 | 76 | |
| 77 | 77 | void GLBackend::updateTransform() { |
| 78 | + GLint originalMatrixMode; | |
| 79 | + glGetIntegerv(GL_MATRIX_MODE, &originalMatrixMode); | |
| 78 | 80 | // Check all the dirty flags and update the state accordingly |
| 79 | 81 | if (_transform._invalidProj) { |
| 80 | 82 | _transform._transformCamera._projection = _transform._projection; |
| @@ -132,12 +134,13 @@ void GLBackend::updateTransform() { · 51 unmodified lines | ||
| 132 | 134 | (void) CHECK_GL_ERROR(); |
| 133 | 135 | } |
| 134 | 136 | |
| 137 | + | |
| 135 | 138 | if (_transform._invalidModel || _transform._invalidView) { |
| 139 | + if (_transform._lastMode != GL_MODELVIEW) { | |
| 140 | + glMatrixMode(GL_MODELVIEW); | |
| 141 | + _transform._lastMode = GL_MODELVIEW; | |
| 142 | + } | |
| 136 | 143 | if (!_transform._model.isIdentity()) { |
| 137 | − if (_transform._lastMode != GL_MODELVIEW) { | |
| 138 | − glMatrixMode(GL_MODELVIEW); | |
| 139 | − _transform._lastMode = GL_MODELVIEW; | |
| 140 | − } | |
| 141 | 144 | Transform::Mat4 modelView; |
| 142 | 145 | if (!_transform._view.isIdentity()) { |
| 143 | 146 | Transform mvx; |
| @@ -147,19 +150,12 @@ void GLBackend::updateTransform() { · 3 unmodified lines | ||
| 147 | 150 | _transform._model.getMatrix(modelView); |
| 148 | 151 | } |
| 149 | 152 | glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); |
| 153 | + } else if (!_transform._view.isIdentity()) { | |
| 154 | + Transform::Mat4 modelView; | |
| 155 | + _transform._view.getInverseMatrix(modelView); | |
| 156 | + glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); | |
| 150 | 157 | } else { |
| 151 | − if (!_transform._view.isIdentity()) { | |
| 152 | − if (_transform._lastMode != GL_MODELVIEW) { | |
| 153 | − glMatrixMode(GL_MODELVIEW); | |
| 154 | − _transform._lastMode = GL_MODELVIEW; | |
| 155 | − } | |
| 156 | − Transform::Mat4 modelView; | |
| 157 | − _transform._view.getInverseMatrix(modelView); | |
| 158 | − glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); | |
| 159 | − } else { | |
| 160 | − // TODO: eventually do something about the matrix when neither view nor model is specified? | |
| 161 | − // glLoadIdentity(); | |
| 162 | − } | |
| 158 | + glLoadIdentity(); | |
| 163 | 159 | } |
| 164 | 160 | (void) CHECK_GL_ERROR(); |
| 165 | 161 | } |
| @@ -167,6 +163,7 @@ void GLBackend::updateTransform() { · 1 unmodified line | ||
| 167 | 163 | |
| 168 | 164 | // Flags are clean |
| 169 | 165 | _transform._invalidView = _transform._invalidProj = _transform._invalidModel = false; |
| 166 | + glMatrixMode(originalMatrixMode); | |
| 170 | 167 | } |
| 171 | 168 | |
| 172 | 169 | |
| @@ -581,20 +581,20 @@ void sphericalHarmonicsScale(float * result, int order, const float * input, flo · 580 unmodified lines | ||
| 581 | 581 | void sphericalHarmonicsEvaluateDirection(float * result, int order, const glm::vec3 & dir) { |
| 582 | 582 | // calculate coefficients for first 3 bands of spherical harmonics |
| 583 | 583 | double P_0_0 = 0.282094791773878140; |
| 584 | − double P_1_0 = 0.488602511902919920 * dir.z; | |
| 584 | + double P_1_0 = 0.488602511902919920 * (double)dir.z; | |
| 585 | 585 | double P_1_1 = -0.488602511902919920; |
| 586 | − double P_2_0 = 0.946174695757560080 * dir.z * dir.z - 0.315391565252520050; | |
| 587 | − double P_2_1 = -1.092548430592079200 * dir.z; | |
| 586 | + double P_2_0 = 0.946174695757560080 * (double)dir.z * (double)dir.z - 0.315391565252520050; | |
| 587 | + double P_2_1 = -1.092548430592079200 * (double)dir.z; | |
| 588 | 588 | double P_2_2 = 0.546274215296039590; |
| 589 | 589 | result[0] = P_0_0; |
| 590 | − result[1] = P_1_1 * dir.y; | |
| 590 | + result[1] = P_1_1 * (double)dir.y; | |
| 591 | 591 | result[2] = P_1_0; |
| 592 | − result[3] = P_1_1 * dir.x; | |
| 593 | − result[4] = P_2_2 * (dir.x * dir.y + dir.y * dir.x); | |
| 594 | − result[5] = P_2_1 * dir.y; | |
| 592 | + result[3] = P_1_1 * (double)dir.x; | |
| 593 | + result[4] = P_2_2 * ((double)dir.x * (double)dir.y + (double)dir.y * (double)dir.x); | |
| 594 | + result[5] = P_2_1 * (double)dir.y; | |
| 595 | 595 | result[6] = P_2_0; |
| 596 | − result[7] = P_2_1 * dir.x; | |
| 597 | − result[8] = P_2_2 * (dir.x * dir.x - dir.y * dir.y); | |
| 596 | + result[7] = P_2_1 * (double)dir.x; | |
| 597 | + result[8] = P_2_2 * ((double)dir.x * (double)dir.x - (double)dir.y * (double)dir.y); | |
| 598 | 598 | } |
| 599 | 599 | |
| 600 | 600 | bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<glm::vec3> & output, const uint order) { |
| @@ -767,4 +767,4 @@ void SphericalHarmonics::evalFromTexture(const Texture& texture) { · 166 unmodified lines | ||
| 767 | 767 | L21 = coefs[7]; |
| 768 | 768 | L22 = coefs[8]; |
| 769 | 769 | } |
| 770 | −} | |
| 770 | +} | |
| @@ -73,7 +73,7 @@ void Light::setMaximumRadius(float radius) { · 72 unmodified lines | ||
| 73 | 73 | radius = 1.0f; |
| 74 | 74 | } |
| 75 | 75 | float CutOffIntensityRatio = 0.05f; |
| 76 | − float surfaceRadius = radius / (sqrt(1.0f / CutOffIntensityRatio) - 1.f); | |
| 76 | + float surfaceRadius = radius / (sqrtf(1.0f / CutOffIntensityRatio) - 1.0f); | |
| 77 | 77 | editSchema()._attenuation = Vec4(surfaceRadius, 1.0f/surfaceRadius, CutOffIntensityRatio, radius); |
| 78 | 78 | } |
| 79 | 79 | |
| @@ -72,7 +72,7 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky · 71 unmodified lines | ||
| 72 | 72 | |
| 73 | 73 | thePipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, skyState)); |
| 74 | 74 | |
| 75 | − const float CLIP = 1.0; | |
| 75 | + const float CLIP = 1.0f; | |
| 76 | 76 | const glm::vec2 vertices[4] = { {-CLIP, -CLIP}, {CLIP, -CLIP}, {-CLIP, CLIP}, {CLIP, CLIP}}; |
| 77 | 77 | theBuffer.reset(new gpu::Buffer(sizeof(vertices), (const gpu::Byte*) vertices)); |
| 78 | 78 | |
| @@ -110,7 +110,7 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky · 31 unmodified lines | ||
| 110 | 110 | } else { |
| 111 | 111 | // skybox has no cubemap, just clear the color buffer |
| 112 | 112 | auto color = skybox.getColor(); |
| 113 | − batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(color, 0.0f), 0.f, 0); | |
| 113 | + batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(color, 0.0f), 0.0f, 0); | |
| 114 | 114 | } |
| 115 | 115 | } |
| 116 | 116 | |
| @@ -42,9 +42,9 @@ Mat4d EarthSunModel::evalWorldToGeoLocationMat(double longitude, double latitude · 41 unmodified lines | ||
| 42 | 42 | |
| 43 | 43 | void EarthSunModel::updateWorldToSurface() const { |
| 44 | 44 | // Check if the final position is too close to the earth center ? |
| 45 | − double absAltitude = _earthRadius + _altitude; | |
| 46 | − if ( absAltitude < 0.01) { | |
| 47 | − absAltitude = 0.01; | |
| 45 | + float absAltitude = _earthRadius + _altitude; | |
| 46 | + if ( absAltitude < 0.01f) { | |
| 47 | + absAltitude = 0.01f; | |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | 50 | // Final world to local Frame |
| @@ -263,8 +263,8 @@ double evalSunDeclinaison(double dayNumber) { · 212 unmodified lines | ||
| 263 | 263 | void SunSkyStage::updateGraphicsObject() const { |
| 264 | 264 | // Always update the sunLongitude based on the current dayTime and the current origin |
| 265 | 265 | // The day time is supposed to be local at the origin |
| 266 | − double signedNormalizedDayTime = (_dayTime - NUM_HOURS_PER_HALF_DAY) / NUM_HOURS_PER_HALF_DAY; | |
| 267 | − double sunLongitude = _earthSunModel.getLongitude() + (MAX_LONGITUDE * signedNormalizedDayTime); | |
| 266 | + float signedNormalizedDayTime = (_dayTime - NUM_HOURS_PER_HALF_DAY) / NUM_HOURS_PER_HALF_DAY; | |
| 267 | + float sunLongitude = _earthSunModel.getLongitude() + (MAX_LONGITUDE * signedNormalizedDayTime); | |
| 268 | 268 | _earthSunModel.setSunLongitude(sunLongitude); |
| 269 | 269 | |
| 270 | 270 | // And update the sunLAtitude as the declinaison depending of the time of the year |
| @@ -302,4 +302,4 @@ void SunSkyStage::setBackgroundMode(BackgroundMode mode) { · 31 unmodified lines | ||
| 302 | 302 | void SunSkyStage::setSkybox(const SkyboxPointer& skybox) { |
| 303 | 303 | _skybox = skybox; |
| 304 | 304 | invalidate(); |
| 305 | −} | |
| 305 | +} | |
| @@ -72,7 +72,7 @@ public: · 71 unmodified lines | ||
| 72 | 72 | |
| 73 | 73 | protected: |
| 74 | 74 | float _scale = 1000.0f; //Km |
| 75 | − double _earthRadius = 6360.0; | |
| 75 | + float _earthRadius = 6360.0; | |
| 76 | 76 | |
| 77 | 77 | Quat _surfaceOrientation; |
| 78 | 78 | |
| @@ -308,6 +308,9 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const · 307 unmodified lines | ||
| 308 | 308 | handlePath(returnedPath, trigger); |
| 309 | 309 | } |
| 310 | 310 | } else { |
| 311 | + // we're going to hit the index path, set that as the _newHostLookupPath | |
| 312 | + _newHostLookupPath = INDEX_PATH; | |
| 313 | + | |
| 311 | 314 | // we didn't override the path or get one back - ask the DS for the viewpoint of its index path |
| 312 | 315 | // which we will jump to if it exists |
| 313 | 316 | emit pathChangeRequired(INDEX_PATH); |
| @@ -479,6 +482,7 @@ bool AddressManager::handleViewpoint(const QString& viewpointString, bool should · 165 unmodified lines | ||
| 479 | 482 | // We use _newHostLookupPath to determine if the client has already stored its last address |
| 480 | 483 | // before moving to a new host thanks to the information in the same lookup URL. |
| 481 | 484 | |
| 485 | + | |
| 482 | 486 | if (definitelyPathOnly || (!pathString.isEmpty() && pathString != _newHostLookupPath)) { |
| 483 | 487 | addCurrentAddressToHistory(LookupTrigger::UserInput); |
| 484 | 488 | } |
| @@ -62,6 +62,9 @@ public: · 61 unmodified lines | ||
| 62 | 62 | |
| 63 | 63 | void loadSettings(const QString& lookupString = QString()); |
| 64 | 64 | |
| 65 | + const QStack<QUrl>& getBackStack() const { return _backStack; } | |
| 66 | + const QStack<QUrl>& getForwardStack() const { return _forwardStack; } | |
| 67 | + | |
| 65 | 68 | public slots: |
| 66 | 69 | void handleLookupString(const QString& lookupString); |
| 67 | 70 | |
| @@ -21,7 +21,7 @@ BandwidthRecorder::Channel::Channel() { · 20 unmodified lines | ||
| 21 | 21 | float BandwidthRecorder::Channel::getAverageInputPacketsPerSecond() { |
| 22 | 22 | float delt = _input.getEventDeltaAverage(); |
| 23 | 23 | if (delt > 0.0f) { |
| 24 | − return (1.0 / delt); | |
| 24 | + return (1.0f / delt); | |
| 25 | 25 | } |
| 26 | 26 | return 0.0f; |
| 27 | 27 | } |
| @@ -29,7 +29,7 @@ float BandwidthRecorder::Channel::getAverageInputPacketsPerSecond() { · 1 unmodified line | ||
| 29 | 29 | float BandwidthRecorder::Channel::getAverageOutputPacketsPerSecond() { |
| 30 | 30 | float delt = _input.getEventDeltaAverage(); |
| 31 | 31 | if (delt > 0.0f) { |
| 32 | − return (1.0 / _output.getEventDeltaAverage()); | |
| 32 | + return (1.0f / _output.getEventDeltaAverage()); | |
| 33 | 33 | } |
| 34 | 34 | return 0.0f; |
| 35 | 35 | } |
| @@ -75,7 +75,7 @@ CoverageMap::~CoverageMap() { · 74 unmodified lines | ||
| 75 | 75 | |
| 76 | 76 | void CoverageMap::printStats() { |
| 77 | 77 | qCDebug(octree, "CoverageMap::printStats()..."); |
| 78 | − qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f",MINIMUM_POLYGON_AREA_TO_STORE); | |
| 78 | + qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f", (double)MINIMUM_POLYGON_AREA_TO_STORE); | |
| 79 | 79 | qCDebug(octree, "_mapCount=%d",_mapCount); |
| 80 | 80 | qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls); |
| 81 | 81 | qCDebug(octree, "_notAllInView=%d",_notAllInView); |
| @@ -82,7 +82,7 @@ void CoverageMapV2::erase() { · 81 unmodified lines | ||
| 82 | 82 | |
| 83 | 83 | if (_isRoot && wantDebugging) { |
| 84 | 84 | qCDebug(octree, "CoverageMapV2 last to be deleted..."); |
| 85 | − qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f",MINIMUM_POLYGON_AREA_TO_STORE); | |
| 85 | + qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f", (double)MINIMUM_POLYGON_AREA_TO_STORE); | |
| 86 | 86 | qCDebug(octree, "_mapCount=%d",_mapCount); |
| 87 | 87 | qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls); |
| 88 | 88 | qCDebug(octree, "_notAllInView=%d",_notAllInView); |
| @@ -69,8 +69,8 @@ void OctreeElement::init(unsigned char * octalCode) { · 68 unmodified lines | ||
| 69 | 69 | // set up the _children union |
| 70 | 70 | _childBitmask = 0; |
| 71 | 71 | _childrenExternal = false; |
| 72 | − | |
| 73 | − | |
| 72 | + | |
| 73 | + | |
| 74 | 74 | #ifdef BLENDED_UNION_CHILDREN |
| 75 | 75 | _children.external = NULL; |
| 76 | 76 | _singleChildrenCount++; |
| @@ -662,7 +662,7 @@ void OctreeElement::deleteAllChildren() { · 585 unmodified lines | ||
| 662 | 662 | delete childAt; |
| 663 | 663 | } |
| 664 | 664 | } |
| 665 | − | |
| 665 | + | |
| 666 | 666 | if (_childrenExternal) { |
| 667 | 667 | // if the children_t union represents _children.external we need to delete it here |
| 668 | 668 | delete[] _children.external; |
| @@ -764,7 +764,7 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) { · 95 unmodified lines | ||
| 764 | 764 | memset(_children.external, 0, sizeof(OctreeElement*) * NUMBER_OF_CHILDREN); |
| 765 | 765 | _children.external[firstIndex] = previousChild; |
| 766 | 766 | _children.external[childIndex] = child; |
| 767 | − | |
| 767 | + | |
| 768 | 768 | _childrenExternal = true; |
| 769 | 769 | |
| 770 | 770 | _externalChildrenMemoryUsage += NUMBER_OF_CHILDREN * sizeof(OctreeElement*); |
| @@ -776,7 +776,7 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) { · 5 unmodified lines | ||
| 776 | 776 | |
| 777 | 777 | delete[] _children.external; |
| 778 | 778 | _childrenExternal = false; |
| 779 | − | |
| 779 | + | |
| 780 | 780 | _externalChildrenMemoryUsage -= NUMBER_OF_CHILDREN * sizeof(OctreeElement*); |
| 781 | 781 | if (childIndex == firstIndex) { |
| 782 | 782 | _children.single = previousSecondChild; |
| @@ -1203,12 +1203,13 @@ void OctreeElement::printDebugDetails(const char* label) const { · 420 unmodified lines | ||
| 1203 | 1203 | setAtBit(childBits,i); |
| 1204 | 1204 | } |
| 1205 | 1205 | } |
| 1206 | − | |
| 1206 | + | |
| 1207 | 1207 | QDebug elementDebug = qDebug().nospace(); |
| 1208 | 1208 | |
| 1209 | 1209 | QString resultString; |
| 1210 | 1210 | resultString.sprintf("%s - Voxel at corner=(%f,%f,%f) size=%f\n isLeaf=%s isDirty=%s shouldRender=%s\n children=", label, |
| 1211 | − _cube.getCorner().x, _cube.getCorner().y, _cube.getCorner().z, _cube.getScale(), | |
| 1211 | + (double)_cube.getCorner().x, (double)_cube.getCorner().y, (double)_cube.getCorner().z, | |
| 1212 | + (double)_cube.getScale(), | |
| 1212 | 1213 | debug::valueOf(isLeaf()), debug::valueOf(isDirty()), debug::valueOf(getShouldRender())); |
| 1213 | 1214 | elementDebug << resultString; |
| 1214 | 1215 | |
| @@ -1236,7 +1237,7 @@ ViewFrustum::location OctreeElement::inFrustum(const ViewFrustum& viewFrustum) c · 21 unmodified lines | ||
| 1236 | 1237 | // By doing this, we don't need to test each child voxel's position vs the LOD boundary |
| 1237 | 1238 | bool OctreeElement::calculateShouldRender(const ViewFrustum* viewFrustum, float voxelScaleSize, int boundaryLevelAdjust) const { |
| 1238 | 1239 | bool shouldRender = false; |
| 1239 | − | |
| 1240 | + | |
| 1240 | 1241 | if (hasContent()) { |
| 1241 | 1242 | float furthestDistance = furthestDistanceToCamera(*viewFrustum); |
| 1242 | 1243 | float childBoundary = boundaryDistanceForRenderLevel(getLevel() + 1 + boundaryLevelAdjust, voxelScaleSize); |
| @@ -1330,7 +1331,7 @@ void OctreeElement::notifyUpdateHooks() { · 87 unmodified lines | ||
| 1330 | 1331 | } |
| 1331 | 1332 | |
| 1332 | 1333 | bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, |
| 1333 | − bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, | |
| 1334 | + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, | |
| 1334 | 1335 | void** intersectedObject, bool precisionPicking) { |
| 1335 | 1336 | |
| 1336 | 1337 | keepSearching = true; // assume that we will continue searching after this. |
| @@ -1354,7 +1355,7 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 · 17 unmodified lines | ||
| 1354 | 1355 | // for any details inside the cube to be closer so we don't need to consider them. |
| 1355 | 1356 | if (_cube.contains(origin) || distanceToElementCube < distance) { |
| 1356 | 1357 | |
| 1357 | − if (findDetailedRayIntersection(origin, direction, keepSearching, element, distanceToElementDetails, | |
| 1358 | + if (findDetailedRayIntersection(origin, direction, keepSearching, element, distanceToElementDetails, | |
| 1358 | 1359 | face, intersectedObject, precisionPicking, distanceToElementCube)) { |
| 1359 | 1360 | |
| 1360 | 1361 | if (distanceToElementDetails < distance) { |
| @@ -1368,10 +1369,10 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 · 7 unmodified lines | ||
| 1368 | 1369 | } |
| 1369 | 1370 | |
| 1370 | 1371 | bool OctreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, |
| 1371 | − bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, | |
| 1372 | + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, | |
| 1372 | 1373 | void** intersectedObject, bool precisionPicking, float distanceToElementCube) { |
| 1373 | 1374 | |
| 1374 | − // we did hit this element, so calculate appropriate distances | |
| 1375 | + // we did hit this element, so calculate appropriate distances | |
| 1375 | 1376 | if (hasContent()) { |
| 1376 | 1377 | element = this; |
| 1377 | 1378 | distance = distanceToElementCube; |
| @@ -1399,7 +1400,8 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float · 21 unmodified lines | ||
| 1399 | 1400 | float halfOurScale = ourScale / 2.0f; |
| 1400 | 1401 | |
| 1401 | 1402 | if(s > ourScale) { |
| 1402 | − qCDebug(octree, "UNEXPECTED -- OctreeElement::getOrCreateChildElementAt() s=[%f] > ourScale=[%f] ", s, ourScale); | |
| 1403 | + qCDebug(octree, "UNEXPECTED -- OctreeElement::getOrCreateChildElementAt() s=[%f] > ourScale=[%f] ", | |
| 1404 | + (double)s, (double)ourScale); | |
| 1403 | 1405 | } |
| 1404 | 1406 | |
| 1405 | 1407 | if (s > halfOurScale) { |
| @@ -1466,21 +1468,21 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float · 60 unmodified lines | ||
| 1466 | 1468 | |
| 1467 | 1469 | OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AACube& cube) { |
| 1468 | 1470 | OctreeElement* child = NULL; |
| 1469 | − | |
| 1471 | + | |
| 1470 | 1472 | int childIndex = getMyChildContaining(cube); |
| 1471 | − | |
| 1473 | + | |
| 1472 | 1474 | // If getMyChildContaining() returns CHILD_UNKNOWN then it means that our level |
| 1473 | 1475 | // is the correct level for this cube |
| 1474 | 1476 | if (childIndex == CHILD_UNKNOWN) { |
| 1475 | 1477 | return this; |
| 1476 | 1478 | } |
| 1477 | − | |
| 1479 | + | |
| 1478 | 1480 | // Now, check if we have a child at that location |
| 1479 | 1481 | child = getChildAtIndex(childIndex); |
| 1480 | 1482 | if (!child) { |
| 1481 | 1483 | child = addChildAtIndex(childIndex); |
| 1482 | 1484 | } |
| 1483 | − | |
| 1485 | + | |
| 1484 | 1486 | // if we've made a really small child, then go ahead and use that one. |
| 1485 | 1487 | if (child->getScale() <= SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE) { |
| 1486 | 1488 | return child; |
| @@ -1492,21 +1494,21 @@ OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AACube& cu · 5 unmodified lines | ||
| 1492 | 1494 | |
| 1493 | 1495 | OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AABox& box) { |
| 1494 | 1496 | OctreeElement* child = NULL; |
| 1495 | − | |
| 1497 | + | |
| 1496 | 1498 | int childIndex = getMyChildContaining(box); |
| 1497 | − | |
| 1499 | + | |
| 1498 | 1500 | // If getMyChildContaining() returns CHILD_UNKNOWN then it means that our level |
| 1499 | 1501 | // is the correct level for this cube |
| 1500 | 1502 | if (childIndex == CHILD_UNKNOWN) { |
| 1501 | 1503 | return this; |
| 1502 | 1504 | } |
| 1503 | − | |
| 1505 | + | |
| 1504 | 1506 | // Now, check if we have a child at that location |
| 1505 | 1507 | child = getChildAtIndex(childIndex); |
| 1506 | 1508 | if (!child) { |
| 1507 | 1509 | child = addChildAtIndex(childIndex); |
| 1508 | 1510 | } |
| 1509 | − | |
| 1511 | + | |
| 1510 | 1512 | // if we've made a really small child, then go ahead and use that one. |
| 1511 | 1513 | if (child->getScale() <= SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE) { |
| 1512 | 1514 | return child; |
| @@ -1542,7 +1544,7 @@ int OctreeElement::getMyChildContaining(const AACube& cube) const { · 29 unmodified lines | ||
| 1542 | 1544 | if (childIndexCubeMinimum != childIndexCubeMaximum) { |
| 1543 | 1545 | return CHILD_UNKNOWN; |
| 1544 | 1546 | } |
| 1545 | − | |
| 1547 | + | |
| 1546 | 1548 | return childIndexCubeMinimum; // either would do, they are the same |
| 1547 | 1549 | } |
| 1548 | 1550 | return CHILD_UNKNOWN; // since cube is not contained in our element, it can't be in one of our children |
| @@ -1555,7 +1557,7 @@ int OctreeElement::getMyChildContaining(const AABox& box) const { · 6 unmodified lines | ||
| 1555 | 1557 | // TODO: consider changing this to assert() |
| 1556 | 1558 | if(boxLargestScale > ourScale) { |
| 1557 | 1559 | qCDebug(octree, "UNEXPECTED -- OctreeElement::getMyChildContaining() " |
| 1558 | − "boxLargestScale=[%f] > ourScale=[%f] ", boxLargestScale, ourScale); | |
| 1560 | + "boxLargestScale=[%f] > ourScale=[%f] ", (double)boxLargestScale, (double)ourScale); | |
| 1559 | 1561 | } |
| 1560 | 1562 | |
| 1561 | 1563 | // Determine which of our children the minimum and maximum corners of the cube live in... |
| @@ -1566,7 +1568,7 @@ int OctreeElement::getMyChildContaining(const AABox& box) const { · 4 unmodified lines | ||
| 1566 | 1568 | int childIndexCubeMinimum = getMyChildContainingPoint(cubeCornerMinimum); |
| 1567 | 1569 | int childIndexCubeMaximum = getMyChildContainingPoint(cubeCornerMaximum); |
| 1568 | 1570 | |
| 1569 | − // If the minimum and maximum corners of the cube are in two different children's cubes, | |
| 1571 | + // If the minimum and maximum corners of the cube are in two different children's cubes, | |
| 1570 | 1572 | // then we are the containing element |
| 1571 | 1573 | if (childIndexCubeMinimum != childIndexCubeMaximum) { |
| 1572 | 1574 | return CHILD_UNKNOWN; |
| @@ -1579,12 +1581,12 @@ int OctreeElement::getMyChildContaining(const AABox& box) const { · 6 unmodified lines | ||
| 1579 | 1581 | int OctreeElement::getMyChildContainingPoint(const glm::vec3& point) const { |
| 1580 | 1582 | glm::vec3 ourCenter = _cube.calcCenter(); |
| 1581 | 1583 | int childIndex = CHILD_UNKNOWN; |
| 1582 | − | |
| 1584 | + | |
| 1583 | 1585 | // since point is not contained in our element, it can't be in one of our children |
| 1584 | 1586 | if (!_cube.contains(point)) { |
| 1585 | 1587 | return CHILD_UNKNOWN; |
| 1586 | 1588 | } |
| 1587 | − | |
| 1589 | + | |
| 1588 | 1590 | // left half |
| 1589 | 1591 | if (point.x > ourCenter.x) { |
| 1590 | 1592 | if (point.y > ourCenter.y) { |
| @@ -384,10 +384,12 @@ bool OctreePacketData::appendValue(const glm::vec3& value) { · 383 unmodified lines | ||
| 384 | 384 | bool OctreePacketData::appendValue(const QVector<glm::vec3>& value) { |
| 385 | 385 | uint16_t qVecSize = value.size(); |
| 386 | 386 | bool success = appendValue(qVecSize); |
| 387 | − success = append((const unsigned char*)value.constData(), qVecSize * sizeof(glm::vec3)); | |
| 388 | 387 | if (success) { |
| 389 | − _bytesOfValues += qVecSize * sizeof(glm::vec3); | |
| 390 | − _totalBytesOfValues += qVecSize * sizeof(glm::vec3); | |
| 388 | + success = append((const unsigned char*)value.constData(), qVecSize * sizeof(glm::vec3)); | |
| 389 | + if (success) { | |
| 390 | + _bytesOfValues += qVecSize * sizeof(glm::vec3); | |
| 391 | + _totalBytesOfValues += qVecSize * sizeof(glm::vec3); | |
| 392 | + } | |
| 391 | 393 | } |
| 392 | 394 | return success; |
| 393 | 395 | } |
| @@ -350,6 +350,19 @@ void OctreePersistThread::rollOldBackupVersions(const BackupRule& rule) { · 349 unmodified lines | ||
| 350 | 350 | if (rule.extensionFormat.contains("%N")) { |
| 351 | 351 | if (rule.maxBackupVersions > 0) { |
| 352 | 352 | qCDebug(octree) << "Rolling old backup versions for rule" << rule.name << "..."; |
| 353 | + | |
| 354 | + // Delete maximum rolling file because rename() fails on Windows if target exists | |
| 355 | + QString backupMaxExtensionN = rule.extensionFormat; | |
| 356 | + backupMaxExtensionN.replace(QString("%N"), QString::number(rule.maxBackupVersions)); | |
| 357 | + QString backupMaxFilenameN = _filename + backupMaxExtensionN; | |
| 358 | + QFile backupMaxFileN(backupMaxFilenameN); | |
| 359 | + if (backupMaxFileN.exists()) { | |
| 360 | + int result = remove(qPrintable(backupMaxFilenameN)); | |
| 361 | + if (result != 0) { | |
| 362 | + qCDebug(octree) << "ERROR deleting old backup file " << backupMaxFilenameN; | |
| 363 | + } | |
| 364 | + } | |
| 365 | + | |
| 353 | 366 | for(int n = rule.maxBackupVersions - 1; n > 0; n--) { |
| 354 | 367 | QString backupExtensionN = rule.extensionFormat; |
| 355 | 368 | QString backupExtensionNplusOne = rule.extensionFormat; |
| @@ -96,8 +96,9 @@ void BoundingBox::explandToInclude(const BoundingBox& box) { · 95 unmodified lines | ||
| 96 | 96 | |
| 97 | 97 | void BoundingBox::printDebugDetails(const char* label) const { |
| 98 | 98 | qCDebug(octree, "%s _set=%s\n corner=%f,%f size=%f,%f\n bounds=[(%f,%f) to (%f,%f)]", |
| 99 | − (label ? label : "BoundingBox"), | |
| 100 | − debug::valueOf(_set), corner.x, corner.y, size.x, size.y, corner.x, corner.y, corner.x+size.x, corner.y+size.y); | |
| 99 | + (label ? label : "BoundingBox"), | |
| 100 | + debug::valueOf(_set), (double)corner.x, (double)corner.y, (double)size.x, (double)size.y, | |
| 101 | + (double)corner.x, (double)corner.y, (double)(corner.x+size.x), (double)(corner.y+size.y)); | |
| 101 | 102 | } |
| 102 | 103 | |
| 103 | 104 | |
| @@ -107,7 +108,7 @@ long OctreeProjectedPolygon::intersects_calls = 0; · 3 unmodified lines | ||
| 107 | 108 | |
| 108 | 109 | |
| 109 | 110 | OctreeProjectedPolygon::OctreeProjectedPolygon(const BoundingBox& box) : |
| 110 | − _vertexCount(4), | |
| 111 | + _vertexCount(4), | |
| 111 | 112 | _maxX(-FLT_MAX), _maxY(-FLT_MAX), _minX(FLT_MAX), _minY(FLT_MAX), |
| 112 | 113 | _distance(0) |
| 113 | 114 | { |
| @@ -117,9 +118,9 @@ OctreeProjectedPolygon::OctreeProjectedPolygon(const BoundingBox& box) : · 3 unmodified lines | ||
| 117 | 118 | } |
| 118 | 119 | |
| 119 | 120 | |
| 120 | −void OctreeProjectedPolygon::setVertex(int vertex, const glm::vec2& point) { | |
| 121 | +void OctreeProjectedPolygon::setVertex(int vertex, const glm::vec2& point) { | |
| 121 | 122 | _vertices[vertex] = point; |
| 122 | − | |
| 123 | + | |
| 123 | 124 | // keep track of our bounding box |
| 124 | 125 | if (point.x > _maxX) { |
| 125 | 126 | _maxX = point.x; |
| @@ -133,14 +134,14 @@ void OctreeProjectedPolygon::setVertex(int vertex, const glm::vec2& point) { · 7 unmodified lines | ||
| 133 | 134 | if (point.y < _minY) { |
| 134 | 135 | _minY = point.y; |
| 135 | 136 | } |
| 136 | − | |
| 137 | + | |
| 137 | 138 | } |
| 138 | 139 | |
| 139 | 140 | // can be optimized with new pointInside() |
| 140 | 141 | bool OctreeProjectedPolygon::occludes(const OctreeProjectedPolygon& occludee, bool checkAllInView) const { |
| 141 | 142 | |
| 142 | 143 | OctreeProjectedPolygon::occludes_calls++; |
| 143 | − | |
| 144 | + | |
| 144 | 145 | // if we are completely out of view, then we definitely don't occlude! |
| 145 | 146 | // if the occludee is completely out of view, then we also don't occlude it |
| 146 | 147 | // |
| @@ -158,7 +159,7 @@ bool OctreeProjectedPolygon::occludes(const OctreeProjectedPolygon& occludee, bo · 11 unmodified lines | ||
| 158 | 159 | (occludee.getMinY() < getMinY())) { |
| 159 | 160 | return false; |
| 160 | 161 | } |
| 161 | − | |
| 162 | + | |
| 162 | 163 | // we need to test for identity as well, because in the case of identity, none of the points |
| 163 | 164 | // will be "inside" but we don't want to bail early on the first non-inside point |
| 164 | 165 | bool potentialIdenity = false; |
| @@ -171,7 +172,7 @@ bool OctreeProjectedPolygon::occludes(const OctreeProjectedPolygon& occludee, bo · 6 unmodified lines | ||
| 171 | 172 | for(int i = 0; i < occludee.getVertexCount(); i++) { |
| 172 | 173 | bool vertexMatched = false; |
| 173 | 174 | if (!pointInside(occludee.getVertex(i), &vertexMatched)) { |
| 174 | − | |
| 175 | + | |
| 175 | 176 | // so the point we just tested isn't inside, but it might have matched a vertex |
| 176 | 177 | // if it didn't match a vertext, then we bail because we can't be an identity |
| 177 | 178 | // or if we're not expecting identity, then we also bail early, no matter what |
| @@ -182,7 +183,7 @@ bool OctreeProjectedPolygon::occludes(const OctreeProjectedPolygon& occludee, bo · 4 unmodified lines | ||
| 182 | 183 | pointsInside++; |
| 183 | 184 | } |
| 184 | 185 | } |
| 185 | − | |
| 186 | + | |
| 186 | 187 | // we're only here if all points are inside matched and/or we had a potentialIdentity we need to check |
| 187 | 188 | if (pointsInside == occludee.getVertexCount()) { |
| 188 | 189 | return true; |
| @@ -192,7 +193,7 @@ bool OctreeProjectedPolygon::occludes(const OctreeProjectedPolygon& occludee, bo · 3 unmodified lines | ||
| 192 | 193 | if (potentialIdenity) { |
| 193 | 194 | return matches(occludee); |
| 194 | 195 | } |
| 195 | − | |
| 196 | + | |
| 196 | 197 | return false; // if we got this far, then we're not occluded |
| 197 | 198 | } |
| 198 | 199 | |
| @@ -211,7 +212,7 @@ bool OctreeProjectedPolygon::matches(const OctreeProjectedPolygon& testee) const · 12 unmodified lines | ||
| 211 | 212 | int originIndex = 0; |
| 212 | 213 | for(int i = 0; i < vertextCount; i++) { |
| 213 | 214 | glm::vec2 testeeVertex = testee.getVertex(i); |
| 214 | − | |
| 215 | + | |
| 215 | 216 | // if they match, we found our origin. |
| 216 | 217 | if (testeeVertex == polygonVertex) { |
| 217 | 218 | originIndex = i; |
| @@ -224,10 +225,10 @@ bool OctreeProjectedPolygon::matches(const OctreeProjectedPolygon& testee) const · 6 unmodified lines | ||
| 224 | 225 | glm::vec2 testeeVertex = testee.getVertex((i + originIndex) % vertextCount); |
| 225 | 226 | glm::vec2 polygonVertex = getVertex(i); |
| 226 | 227 | if (testeeVertex != polygonVertex) { |
| 227 | − return false; // we don't match, therefore we're not the same | |
| 228 | − } | |
| 229 | − } | |
| 230 | − return true; // all of our vertices match, therefore we're the same | |
| 228 | + return false; // we don't match, therefore we're not the same | |
| 229 | + } | |
| 230 | + } | |
| 231 | + return true; // all of our vertices match, therefore we're the same | |
| 231 | 232 | } |
| 232 | 233 | |
| 233 | 234 | bool OctreeProjectedPolygon::matches(const BoundingBox& box) const { |
| @@ -259,17 +260,17 @@ bool OctreeProjectedPolygon::pointInside(const glm::vec2& point, bool* matchesVe · 25 unmodified lines | ||
| 259 | 260 | return false; |
| 260 | 261 | } |
| 261 | 262 | } |
| 262 | − | |
| 263 | + | |
| 263 | 264 | return true; |
| 264 | 265 | } |
| 265 | − | |
| 266 | + | |
| 266 | 267 | void OctreeProjectedPolygon::printDebugDetails() const { |
| 267 | 268 | qCDebug(octree, "OctreeProjectedPolygon..." |
| 268 | − " minX=%f maxX=%f minY=%f maxY=%f", getMinX(), getMaxX(), getMinY(), getMaxY()); | |
| 269 | − qCDebug(octree, " vertex count=%d distance=%f", getVertexCount(), getDistance()); | |
| 269 | + " minX=%f maxX=%f minY=%f maxY=%f", (double)getMinX(), (double)getMaxX(), (double)getMinY(), (double)getMaxY()); | |
| 270 | + qCDebug(octree, " vertex count=%d distance=%f", getVertexCount(), (double)getDistance()); | |
| 270 | 271 | for (int i = 0; i < getVertexCount(); i++) { |
| 271 | 272 | glm::vec2 point = getVertex(i); |
| 272 | − qCDebug(octree, " vertex[%d] = %f, %f ", i, point.x, point.y); | |
| 273 | + qCDebug(octree, " vertex[%d] = %f, %f ", i, (double)point.x, (double)point.y); | |
| 273 | 274 | } |
| 274 | 275 | } |
| 275 | 276 | |
| @@ -291,7 +292,7 @@ bool OctreeProjectedPolygon::intersects(const OctreeProjectedPolygon& testee) co · 15 unmodified lines | ||
| 291 | 292 | // intersect on all axes. |
| 292 | 293 | // |
| 293 | 294 | // Note: this only works on convex polygons |
| 294 | −// | |
| 295 | +// | |
| 295 | 296 | // |
| 296 | 297 | bool OctreeProjectedPolygon::intersectsOnAxes(const OctreeProjectedPolygon& testee) const { |
| 297 | 298 | |
| @@ -307,11 +308,11 @@ bool OctreeProjectedPolygon::intersectsOnAxes(const OctreeProjectedPolygon& test · 9 unmodified lines | ||
| 307 | 308 | // points that are ON the edge, are considered to be "outside" |
| 308 | 309 | for (int j = 0; j < testee.getVertexCount(); j++) { |
| 309 | 310 | glm::vec2 testeeVertex = testee.getVertex(j); |
| 310 | − | |
| 311 | + | |
| 311 | 312 | // in comparison below: |
| 312 | 313 | // >= will cause points on edge to be considered inside |
| 313 | 314 | // > will cause points on edge to be considered outside |
| 314 | − | |
| 315 | + | |
| 315 | 316 | float c2 = a * testeeVertex.x + b * testeeVertex.y; |
| 316 | 317 | if (c2 >= c) { |
| 317 | 318 | goto CONTINUE_OUTER; |
| @@ -328,11 +329,11 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 10 unmodified lines | ||
| 328 | 329 | // RIGHT/NEAR |
| 329 | 330 | // LEFT/NEAR |
| 330 | 331 | if ( |
| 331 | − (getProjectionType() == that.getProjectionType()) && | |
| 332 | + (getProjectionType() == that.getProjectionType()) && | |
| 332 | 333 | ( |
| 333 | 334 | getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR) || |
| 334 | 335 | getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR) |
| 335 | − ) | |
| 336 | + ) | |
| 336 | 337 | ) { |
| 337 | 338 | if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(5)) { |
| 338 | 339 | return true; |
| @@ -350,10 +351,10 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 11 unmodified lines | ||
| 350 | 351 | |
| 351 | 352 | // NEAR/BOTTOM |
| 352 | 353 | if ( |
| 353 | − (getProjectionType() == that.getProjectionType()) && | |
| 354 | + (getProjectionType() == that.getProjectionType()) && | |
| 354 | 355 | ( |
| 355 | 356 | getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM) |
| 356 | − ) | |
| 357 | + ) | |
| 357 | 358 | ) { |
| 358 | 359 | if (getVertex(0) == that.getVertex(5) && getVertex(3) == that.getVertex(4)) { |
| 359 | 360 | return true; |
| @@ -371,10 +372,10 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 11 unmodified lines | ||
| 371 | 372 | |
| 372 | 373 | // NEAR/TOP |
| 373 | 374 | if ( |
| 374 | − (getProjectionType() == that.getProjectionType()) && | |
| 375 | + (getProjectionType() == that.getProjectionType()) && | |
| 375 | 376 | ( |
| 376 | 377 | getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP) |
| 377 | − ) | |
| 378 | + ) | |
| 378 | 379 | ) { |
| 379 | 380 | if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) { |
| 380 | 381 | return true; |
| @@ -393,11 +394,11 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 12 unmodified lines | ||
| 393 | 394 | // RIGHT/NEAR & NEAR/RIGHT/TOP |
| 394 | 395 | // LEFT/NEAR & NEAR/LEFT/TOP |
| 395 | 396 | if ( |
| 396 | − ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) && | |
| 397 | − (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | |
| 397 | + ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) && | |
| 398 | + (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | |
| 398 | 399 | || |
| 399 | − ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) && | |
| 400 | − (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | |
| 400 | + ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) && | |
| 401 | + (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | |
| 401 | 402 | ) |
| 402 | 403 | { |
| 403 | 404 | if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) { |
| @@ -407,12 +408,12 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 3 unmodified lines | ||
| 407 | 408 | // RIGHT/NEAR & NEAR/RIGHT/TOP |
| 408 | 409 | // LEFT/NEAR & NEAR/LEFT/TOP |
| 409 | 410 | if ( |
| 410 | − ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) && | |
| 411 | − (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | |
| 411 | + ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) && | |
| 412 | + (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | |
| 412 | 413 | || |
| 413 | − ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) && | |
| 414 | − (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | |
| 415 | − | |
| 414 | + ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) && | |
| 415 | + (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | |
| 416 | + | |
| 416 | 417 | ) |
| 417 | 418 | { |
| 418 | 419 | if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) { |
| @@ -423,12 +424,12 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines | ||
| 423 | 424 | // RIGHT/NEAR & NEAR/RIGHT/BOTTOM |
| 424 | 425 | // NEAR/LEFT & NEAR/LEFT/BOTTOM |
| 425 | 426 | if ( |
| 426 | − ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | |
| 427 | − (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | |
| 427 | + ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | |
| 428 | + (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | |
| 428 | 429 | || |
| 429 | − ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | |
| 430 | − (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | |
| 431 | − | |
| 430 | + ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | |
| 431 | + (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | |
| 432 | + | |
| 432 | 433 | ) |
| 433 | 434 | { |
| 434 | 435 | if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) { |
| @@ -438,11 +439,11 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 3 unmodified lines | ||
| 438 | 439 | // RIGHT/NEAR & NEAR/RIGHT/BOTTOM |
| 439 | 440 | // NEAR/LEFT & NEAR/LEFT/BOTTOM |
| 440 | 441 | if ( |
| 441 | − ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | |
| 442 | − (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | |
| 442 | + ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | |
| 443 | + (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | |
| 443 | 444 | || |
| 444 | − ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | |
| 445 | − (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | |
| 445 | + ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | |
| 446 | + (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | |
| 446 | 447 | ) |
| 447 | 448 | { |
| 448 | 449 | if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) { |
| @@ -453,7 +454,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines | ||
| 453 | 454 | // NEAR/TOP & NEAR |
| 454 | 455 | if ( |
| 455 | 456 | (getProjectionType() == (PROJECTION_NEAR )) && |
| 456 | − (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) | |
| 457 | + (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) | |
| 457 | 458 | ) |
| 458 | 459 | { |
| 459 | 460 | if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) { |
| @@ -464,7 +465,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines | ||
| 464 | 465 | // NEAR/TOP & NEAR |
| 465 | 466 | if ( |
| 466 | 467 | (that.getProjectionType() == (PROJECTION_NEAR )) && |
| 467 | − (getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) | |
| 468 | + (getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) | |
| 468 | 469 | ) |
| 469 | 470 | { |
| 470 | 471 | if (getVertex(5) == that.getVertex(0) && getVertex(2) == that.getVertex(1)) { |
| @@ -475,7 +476,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines | ||
| 475 | 476 | // NEAR/BOTTOM & NEAR |
| 476 | 477 | if ( |
| 477 | 478 | (getProjectionType() == (PROJECTION_NEAR )) && |
| 478 | − (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) | |
| 479 | + (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) | |
| 479 | 480 | ) |
| 480 | 481 | { |
| 481 | 482 | if (getVertex(2) == that.getVertex(3) && getVertex(3) == that.getVertex(0)) { |
| @@ -486,7 +487,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines | ||
| 486 | 487 | // NEAR/BOTTOM & NEAR |
| 487 | 488 | if ( |
| 488 | 489 | (that.getProjectionType() == (PROJECTION_NEAR )) && |
| 489 | − (getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) | |
| 490 | + (getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) | |
| 490 | 491 | ) |
| 491 | 492 | { |
| 492 | 493 | if (getVertex(3) == that.getVertex(2) && getVertex(0) == that.getVertex(3)) { |
| @@ -497,7 +498,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines | ||
| 497 | 498 | // NEAR/RIGHT & NEAR |
| 498 | 499 | if ( |
| 499 | 500 | (getProjectionType() == (PROJECTION_NEAR )) && |
| 500 | − (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) | |
| 501 | + (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) | |
| 501 | 502 | ) |
| 502 | 503 | { |
| 503 | 504 | if (getVertex(0) == that.getVertex(1) && getVertex(3) == that.getVertex(4)) { |
| @@ -508,18 +509,18 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines | ||
| 508 | 509 | // NEAR/RIGHT & NEAR |
| 509 | 510 | if ( |
| 510 | 511 | (that.getProjectionType() == (PROJECTION_NEAR )) && |
| 511 | − (getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) | |
| 512 | + (getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) | |
| 512 | 513 | ) |
| 513 | 514 | { |
| 514 | 515 | if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) { |
| 515 | 516 | return true; |
| 516 | 517 | } |
| 517 | 518 | } |
| 518 | − | |
| 519 | + | |
| 519 | 520 | // NEAR/LEFT & NEAR |
| 520 | 521 | if ( |
| 521 | 522 | (getProjectionType() == (PROJECTION_NEAR )) && |
| 522 | − (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) | |
| 523 | + (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) | |
| 523 | 524 | ) |
| 524 | 525 | { |
| 525 | 526 | if (getVertex(1) == that.getVertex(1) && getVertex(2) == that.getVertex(4)) { |
| @@ -530,7 +531,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines | ||
| 530 | 531 | // NEAR/LEFT & NEAR |
| 531 | 532 | if ( |
| 532 | 533 | (that.getProjectionType() == (PROJECTION_NEAR )) && |
| 533 | − (getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) | |
| 534 | + (getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) | |
| 534 | 535 | ) |
| 535 | 536 | { |
| 536 | 537 | if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) { |
| @@ -559,7 +560,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 22 unmodified lines | ||
| 559 | 560 | return true; |
| 560 | 561 | } |
| 561 | 562 | } |
| 562 | − | |
| 563 | + | |
| 563 | 564 | |
| 564 | 565 | // NEAR/RIGHT/BOTTOM & NEAR/BOTTOM |
| 565 | 566 | if ( |
| @@ -582,7 +583,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 16 unmodified lines | ||
| 582 | 583 | return true; |
| 583 | 584 | } |
| 584 | 585 | } |
| 585 | − | |
| 586 | + | |
| 586 | 587 | // NEAR/LEFT/BOTTOM & NEAR/BOTTOM |
| 587 | 588 | if ( |
| 588 | 589 | ((getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) && |
| @@ -592,12 +593,12 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 3 unmodified lines | ||
| 592 | 593 | if (getVertex(2) == that.getVertex(0) && getVertex(4) == that.getVertex(4)) { |
| 593 | 594 | return true; |
| 594 | 595 | } |
| 595 | − } | |
| 596 | + } | |
| 596 | 597 | |
| 597 | 598 | // NEAR/LEFT/BOTTOM & NEAR/BOTTOM |
| 598 | 599 | if ( |
| 599 | 600 | ((that.getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) && |
| 600 | − (getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR | PROJECTION_LEFT ))) | |
| 601 | + (getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR | PROJECTION_LEFT ))) | |
| 601 | 602 | ) |
| 602 | 603 | { |
| 603 | 604 | if (getVertex(0) == that.getVertex(2) && getVertex(4) == that.getVertex(4)) { |
| @@ -609,7 +610,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 5 unmodified lines | ||
| 609 | 610 | // LEFT/NEAR/BOTTOM |
| 610 | 611 | // LEFT/NEAR/TOP |
| 611 | 612 | if ( |
| 612 | − (getProjectionType() == that.getProjectionType()) && | |
| 613 | + (getProjectionType() == that.getProjectionType()) && | |
| 613 | 614 | ( |
| 614 | 615 | getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM ) || |
| 615 | 616 | getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP ) || |
| @@ -646,11 +647,11 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 30 unmodified lines | ||
| 646 | 647 | // RIGHT/NEAR |
| 647 | 648 | // LEFT/NEAR |
| 648 | 649 | if ( |
| 649 | − (getProjectionType() == that.getProjectionType()) && | |
| 650 | + (getProjectionType() == that.getProjectionType()) && | |
| 650 | 651 | ( |
| 651 | − getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR) || | |
| 652 | + getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR) || | |
| 652 | 653 | getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR) |
| 653 | − ) | |
| 654 | + ) | |
| 654 | 655 | ) { |
| 655 | 656 | if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(5)) { |
| 656 | 657 | //setVertex(0, this.getVertex(0)); // no change |
| @@ -689,13 +690,13 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 32 unmodified lines | ||
| 689 | 690 | return; // done |
| 690 | 691 | } |
| 691 | 692 | } |
| 692 | − | |
| 693 | + | |
| 693 | 694 | // NEAR/BOTTOM |
| 694 | 695 | if ( |
| 695 | − (getProjectionType() == that.getProjectionType()) && | |
| 696 | + (getProjectionType() == that.getProjectionType()) && | |
| 696 | 697 | ( |
| 697 | 698 | getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM) |
| 698 | − ) | |
| 699 | + ) | |
| 699 | 700 | ) { |
| 700 | 701 | if (getVertex(0) == that.getVertex(5) && getVertex(3) == that.getVertex(4)) { |
| 701 | 702 | setVertex(0, that.getVertex(0)); |
| @@ -737,10 +738,10 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 35 unmodified lines | ||
| 737 | 738 | |
| 738 | 739 | // NEAR/TOP |
| 739 | 740 | if ( |
| 740 | − (getProjectionType() == that.getProjectionType()) && | |
| 741 | + (getProjectionType() == that.getProjectionType()) && | |
| 741 | 742 | ( |
| 742 | 743 | getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP) |
| 743 | − ) | |
| 744 | + ) | |
| 744 | 745 | ) { |
| 745 | 746 | if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) { |
| 746 | 747 | setVertex(0, that.getVertex(0)); |
| @@ -779,16 +780,16 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 32 unmodified lines | ||
| 779 | 780 | return; // done |
| 780 | 781 | } |
| 781 | 782 | } |
| 782 | − | |
| 783 | + | |
| 783 | 784 | |
| 784 | 785 | // RIGHT/NEAR & NEAR/RIGHT/TOP |
| 785 | 786 | // LEFT/NEAR & NEAR/LEFT/TOP |
| 786 | 787 | if ( |
| 787 | − ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) && | |
| 788 | − (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | |
| 788 | + ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) && | |
| 789 | + (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | |
| 789 | 790 | || |
| 790 | − ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) && | |
| 791 | − (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | |
| 791 | + ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) && | |
| 792 | + (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | |
| 792 | 793 | ) |
| 793 | 794 | { |
| 794 | 795 | if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) { |
| @@ -806,12 +807,12 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 11 unmodified lines | ||
| 806 | 807 | // RIGHT/NEAR & NEAR/RIGHT/TOP |
| 807 | 808 | // LEFT/NEAR & NEAR/LEFT/TOP |
| 808 | 809 | if ( |
| 809 | − ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) && | |
| 810 | − (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | |
| 810 | + ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) && | |
| 811 | + (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | |
| 811 | 812 | || |
| 812 | − ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) && | |
| 813 | − (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | |
| 814 | − | |
| 813 | + ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) && | |
| 814 | + (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | |
| 815 | + | |
| 815 | 816 | ) |
| 816 | 817 | { |
| 817 | 818 | if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) { |
| @@ -829,12 +830,12 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 11 unmodified lines | ||
| 829 | 830 | // RIGHT/NEAR & NEAR/RIGHT/BOTTOM |
| 830 | 831 | // NEAR/LEFT & NEAR/LEFT/BOTTOM |
| 831 | 832 | if ( |
| 832 | − ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | |
| 833 | − (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | |
| 833 | + ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | |
| 834 | + (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | |
| 834 | 835 | || |
| 835 | − ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | |
| 836 | − (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | |
| 837 | − | |
| 836 | + ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | |
| 837 | + (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | |
| 838 | + | |
| 838 | 839 | ) |
| 839 | 840 | { |
| 840 | 841 | if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) { |
| @@ -851,11 +852,11 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 10 unmodified lines | ||
| 851 | 852 | // RIGHT/NEAR & NEAR/RIGHT/BOTTOM |
| 852 | 853 | // NEAR/LEFT & NEAR/LEFT/BOTTOM |
| 853 | 854 | if ( |
| 854 | − ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | |
| 855 | − (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | |
| 855 | + ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | |
| 856 | + (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | |
| 856 | 857 | || |
| 857 | − ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | |
| 858 | − (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | |
| 858 | + ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | |
| 859 | + (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | |
| 859 | 860 | ) |
| 860 | 861 | { |
| 861 | 862 | if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) { |
| @@ -865,16 +866,16 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 3 unmodified lines | ||
| 865 | 866 | //setVertex(3, this.getVertex(3)); // no change |
| 866 | 867 | //setVertex(4, this.getVertex(4)); // no change |
| 867 | 868 | //setVertex(5, this.getVertex(5)); // no change |
| 868 | − setProjectionType((PROJECTION_RIGHT | PROJECTION_NEAR)); | |
| 869 | + setProjectionType((PROJECTION_RIGHT | PROJECTION_NEAR)); | |
| 869 | 870 | return; // done |
| 870 | 871 | } |
| 871 | 872 | } |
| 872 | − | |
| 873 | − | |
| 873 | + | |
| 874 | + | |
| 874 | 875 | // NEAR/TOP & NEAR |
| 875 | 876 | if ( |
| 876 | 877 | (getProjectionType() == (PROJECTION_NEAR )) && |
| 877 | − (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) | |
| 878 | + (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) | |
| 878 | 879 | ) |
| 879 | 880 | { |
| 880 | 881 | if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) { |
| @@ -891,7 +892,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 10 unmodified lines | ||
| 891 | 892 | // NEAR/TOP & NEAR |
| 892 | 893 | if ( |
| 893 | 894 | (that.getProjectionType() == (PROJECTION_NEAR )) && |
| 894 | − (getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) | |
| 895 | + (getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) | |
| 895 | 896 | ) |
| 896 | 897 | { |
| 897 | 898 | if (getVertex(5) == that.getVertex(0) && getVertex(2) == that.getVertex(1)) { |
| @@ -904,11 +905,11 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 6 unmodified lines | ||
| 904 | 905 | return; // done |
| 905 | 906 | } |
| 906 | 907 | } |
| 907 | − | |
| 908 | + | |
| 908 | 909 | // NEAR/BOTTOM & NEAR |
| 909 | 910 | if ( |
| 910 | 911 | (getProjectionType() == (PROJECTION_NEAR )) && |
| 911 | − (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) | |
| 912 | + (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) | |
| 912 | 913 | ) |
| 913 | 914 | { |
| 914 | 915 | if (getVertex(2) == that.getVertex(3) && getVertex(3) == that.getVertex(0)) { |
| @@ -924,7 +925,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 9 unmodified lines | ||
| 924 | 925 | // NEAR/BOTTOM & NEAR |
| 925 | 926 | if ( |
| 926 | 927 | (that.getProjectionType() == (PROJECTION_NEAR )) && |
| 927 | − (getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) | |
| 928 | + (getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) | |
| 928 | 929 | ) |
| 929 | 930 | { |
| 930 | 931 | if (getVertex(3) == that.getVertex(2) && getVertex(0) == that.getVertex(3)) { |
| @@ -941,7 +942,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 10 unmodified lines | ||
| 941 | 942 | // NEAR/RIGHT & NEAR |
| 942 | 943 | if ( |
| 943 | 944 | (getProjectionType() == (PROJECTION_NEAR )) && |
| 944 | − (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) | |
| 945 | + (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) | |
| 945 | 946 | ) |
| 946 | 947 | { |
| 947 | 948 | if (getVertex(0) == that.getVertex(1) && getVertex(3) == that.getVertex(4)) { |
| @@ -957,7 +958,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 9 unmodified lines | ||
| 957 | 958 | // NEAR/RIGHT & NEAR |
| 958 | 959 | if ( |
| 959 | 960 | (that.getProjectionType() == (PROJECTION_NEAR )) && |
| 960 | − (getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) | |
| 961 | + (getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) | |
| 961 | 962 | ) |
| 962 | 963 | { |
| 963 | 964 | if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) { |
| @@ -974,7 +975,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 10 unmodified lines | ||
| 974 | 975 | // NEAR/LEFT & NEAR |
| 975 | 976 | if ( |
| 976 | 977 | (getProjectionType() == (PROJECTION_NEAR )) && |
| 977 | − (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) | |
| 978 | + (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) | |
| 978 | 979 | ) |
| 979 | 980 | { |
| 980 | 981 | if (getVertex(1) == that.getVertex(1) && getVertex(2) == that.getVertex(4)) { |
| @@ -991,7 +992,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 10 unmodified lines | ||
| 991 | 992 | // NEAR/LEFT & NEAR |
| 992 | 993 | if ( |
| 993 | 994 | (that.getProjectionType() == (PROJECTION_NEAR )) && |
| 994 | − (getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) | |
| 995 | + (getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) | |
| 995 | 996 | ) |
| 996 | 997 | { |
| 997 | 998 | if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) { |
| @@ -1096,7 +1097,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 98 unmodified lines | ||
| 1096 | 1097 | // NEAR/LEFT/BOTTOM & NEAR/BOTTOM |
| 1097 | 1098 | if ( |
| 1098 | 1099 | ((that.getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) && |
| 1099 | − (getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR | PROJECTION_LEFT ))) | |
| 1100 | + (getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR | PROJECTION_LEFT ))) | |
| 1100 | 1101 | ) |
| 1101 | 1102 | { |
| 1102 | 1103 | if (getVertex(0) == that.getVertex(2) && getVertex(4) == that.getVertex(4)) { |
| @@ -1118,7 +1119,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 15 unmodified lines | ||
| 1118 | 1119 | // LEFT/NEAR/BOTTOM |
| 1119 | 1120 | // LEFT/NEAR/TOP |
| 1120 | 1121 | if ( |
| 1121 | − (getProjectionType() == that.getProjectionType()) && | |
| 1122 | + (getProjectionType() == that.getProjectionType()) && | |
| 1122 | 1123 | ( |
| 1123 | 1124 | getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM ) || |
| 1124 | 1125 | getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP ) || |
| @@ -707,8 +707,8 @@ const char* OctreeSceneStats::getItemValue(Item item) { · 706 unmodified lines | ||
| 707 | 707 | float elapsedAverage = _elapsedAverage.getAverage(); |
| 708 | 708 | calcAverageFPS = (float)USECS_PER_SECOND / (float)elapsedAverage; |
| 709 | 709 | |
| 710 | − sprintf(_itemValueBuffer, "%llu usecs (%d fps) Average: %.0f usecs (%d fps)", | |
| 711 | − (long long unsigned int)_elapsed, calcFPS, elapsedAverage, calcAverageFPS); | |
| 710 | + sprintf(_itemValueBuffer, "%llu usecs (%d fps) Average: %.0f usecs (%d fps)", | |
| 711 | + (long long unsigned int)_elapsed, calcFPS, (double)elapsedAverage, calcAverageFPS); | |
| 712 | 712 | break; |
| 713 | 713 | } |
| 714 | 714 | case ITEM_ENCODE: |
| @@ -733,7 +733,7 @@ const char* OctreeSceneStats::getItemValue(Item item) { · 18 unmodified lines | ||
| 733 | 733 | float calculatedBPV = total == 0 ? 0 : (_bytes * 8) / total; |
| 734 | 734 | float averageBPV = _bitsPerOctreeAverage.getAverage(); |
| 735 | 735 | sprintf(_itemValueBuffer, "%lu (%.2f bits/octree Average: %.2f bits/octree) %lu internal %lu leaves", |
| 736 | − total, calculatedBPV, averageBPV, | |
| 736 | + total, (double)calculatedBPV, (double)averageBPV, | |
| 737 | 737 | (long unsigned int)_existsInPacketBitsWritten, |
| 738 | 738 | (long unsigned int)_colorSent); |
| 739 | 739 | break; |
| @@ -66,5 +66,6 @@ float Plane::distance(const glm::vec3 &point) const { · 65 unmodified lines | ||
| 66 | 66 | |
| 67 | 67 | void Plane::print() const { |
| 68 | 68 | qCDebug(octree, "Plane - point (x=%f y=%f z=%f) normal (x=%f y=%f z=%f) d=%f", |
| 69 | − _point.x, _point.y, _point.z, _normal.x, _normal.y, _normal.z, _dCoefficient); | |
| 69 | + (double)_point.x, (double)_point.y, (double)_point.z, | |
| 70 | + (double)_normal.x, (double)_normal.y, (double)_normal.z, (double)_dCoefficient); | |
| 70 | 71 | } |
| @@ -65,9 +65,10 @@ void ViewFrustum::setProjection(const glm::mat4& projection) { · 64 unmodified lines | ||
| 65 | 65 | _farClip = -_corners[BOTTOM_LEFT_FAR].z; |
| 66 | 66 | _aspectRatio = (_corners[TOP_RIGHT_NEAR].x - _corners[BOTTOM_LEFT_NEAR].x) / |
| 67 | 67 | (_corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_LEFT_NEAR].y); |
| 68 | − glm::vec3 right = glm::normalize(glm::vec3(_corners[TOP_RIGHT_NEAR])); | |
| 69 | − glm::vec3 left = glm::normalize(glm::vec3(_corners[TOP_LEFT_NEAR])); | |
| 70 | − _fieldOfView = abs(glm::degrees(glm::angle(right, left))); | |
| 68 | + | |
| 69 | + glm::vec4 top = _inverseProjection * vec4(0, 1, -1, 1); | |
| 70 | + top /= top.w; | |
| 71 | + _fieldOfView = abs(glm::degrees(2.0f * abs(glm::angle(vec3(0, 0, -1), glm::normalize(vec3(top)))))); | |
| 71 | 72 | } |
| 72 | 73 | |
| 73 | 74 | // ViewFrustum::calculateViewFrustum() |
| @@ -387,36 +388,36 @@ bool ViewFrustum::matches(const ViewFrustum& compareTo, bool debug) const { · 313 unmodified lines | ||
| 387 | 388 | if (!result && debug) { |
| 388 | 389 | qCDebug(octree, "ViewFrustum::matches()... result=%s", debug::valueOf(result)); |
| 389 | 390 | qCDebug(octree, "%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f", |
| 390 | − (testMatches(compareTo._position,_position) ? "MATCHES " : "NO MATCH"), | |
| 391 | − compareTo._position.x, compareTo._position.y, compareTo._position.z, | |
| 392 | − _position.x, _position.y, _position.z ); | |
| 391 | + (testMatches(compareTo._position,_position) ? "MATCHES " : "NO MATCH"), | |
| 392 | + (double)compareTo._position.x, (double)compareTo._position.y, (double)compareTo._position.z, | |
| 393 | + (double)_position.x, (double)_position.y, (double)_position.z); | |
| 393 | 394 | qCDebug(octree, "%s -- compareTo._direction=%f,%f,%f _direction=%f,%f,%f", |
| 394 | − (testMatches(compareTo._direction, _direction) ? "MATCHES " : "NO MATCH"), | |
| 395 | − compareTo._direction.x, compareTo._direction.y, compareTo._direction.z, | |
| 396 | − _direction.x, _direction.y, _direction.z ); | |
| 395 | + (testMatches(compareTo._direction, _direction) ? "MATCHES " : "NO MATCH"), | |
| 396 | + (double)compareTo._direction.x, (double)compareTo._direction.y, (double)compareTo._direction.z, | |
| 397 | + (double)_direction.x, (double)_direction.y, (double)_direction.z ); | |
| 397 | 398 | qCDebug(octree, "%s -- compareTo._up=%f,%f,%f _up=%f,%f,%f", |
| 398 | − (testMatches(compareTo._up, _up) ? "MATCHES " : "NO MATCH"), | |
| 399 | − compareTo._up.x, compareTo._up.y, compareTo._up.z, | |
| 400 | − _up.x, _up.y, _up.z ); | |
| 399 | + (testMatches(compareTo._up, _up) ? "MATCHES " : "NO MATCH"), | |
| 400 | + (double)compareTo._up.x, (double)compareTo._up.y, (double)compareTo._up.z, | |
| 401 | + (double)_up.x, (double)_up.y, (double)_up.z ); | |
| 401 | 402 | qCDebug(octree, "%s -- compareTo._right=%f,%f,%f _right=%f,%f,%f", |
| 402 | − (testMatches(compareTo._right, _right) ? "MATCHES " : "NO MATCH"), | |
| 403 | − compareTo._right.x, compareTo._right.y, compareTo._right.z, | |
| 404 | − _right.x, _right.y, _right.z ); | |
| 403 | + (testMatches(compareTo._right, _right) ? "MATCHES " : "NO MATCH"), | |
| 404 | + (double)compareTo._right.x, (double)compareTo._right.y, (double)compareTo._right.z, | |
| 405 | + (double)_right.x, (double)_right.y, (double)_right.z ); | |
| 405 | 406 | qCDebug(octree, "%s -- compareTo._fieldOfView=%f _fieldOfView=%f", |
| 406 | − (testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"), | |
| 407 | − compareTo._fieldOfView, _fieldOfView); | |
| 407 | + (testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"), | |
| 408 | + (double)compareTo._fieldOfView, (double)_fieldOfView); | |
| 408 | 409 | qCDebug(octree, "%s -- compareTo._aspectRatio=%f _aspectRatio=%f", |
| 409 | − (testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"), | |
| 410 | − compareTo._aspectRatio, _aspectRatio); | |
| 410 | + (testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"), | |
| 411 | + (double)compareTo._aspectRatio, (double)_aspectRatio); | |
| 411 | 412 | qCDebug(octree, "%s -- compareTo._nearClip=%f _nearClip=%f", |
| 412 | − (testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"), | |
| 413 | − compareTo._nearClip, _nearClip); | |
| 413 | + (testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"), | |
| 414 | + (double)compareTo._nearClip, (double)_nearClip); | |
| 414 | 415 | qCDebug(octree, "%s -- compareTo._farClip=%f _farClip=%f", |
| 415 | − (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"), | |
| 416 | − compareTo._farClip, _farClip); | |
| 416 | + (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"), | |
| 417 | + (double)compareTo._farClip, (double)_farClip); | |
| 417 | 418 | qCDebug(octree, "%s -- compareTo._focalLength=%f _focalLength=%f", |
| 418 | − (testMatches(compareTo._focalLength, _focalLength) ? "MATCHES " : "NO MATCH"), | |
| 419 | − compareTo._focalLength, _focalLength); | |
| 419 | + (testMatches(compareTo._focalLength, _focalLength) ? "MATCHES " : "NO MATCH"), | |
| 420 | + (double)compareTo._focalLength, (double)_focalLength); | |
| 420 | 421 | } |
| 421 | 422 | return result; |
| 422 | 423 | } |
| @@ -448,33 +449,34 @@ bool ViewFrustum::isVerySimilar(const ViewFrustum& compareTo, bool debug) const · 25 unmodified lines | ||
| 448 | 449 | if (!result && debug) { |
| 449 | 450 | qCDebug(octree, "ViewFrustum::isVerySimilar()... result=%s\n", debug::valueOf(result)); |
| 450 | 451 | qCDebug(octree, "%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f", |
| 451 | − (testMatches(compareTo._position,_position, POSITION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"), | |
| 452 | − compareTo._position.x, compareTo._position.y, compareTo._position.z, | |
| 453 | − _position.x, _position.y, _position.z ); | |
| 452 | + (testMatches(compareTo._position,_position, POSITION_SIMILAR_ENOUGH) ? | |
| 453 | + "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"), | |
| 454 | + (double)compareTo._position.x, (double)compareTo._position.y, (double)compareTo._position.z, | |
| 455 | + (double)_position.x, (double)_position.y, (double)_position.z ); | |
| 454 | 456 | |
| 455 | 457 | qCDebug(octree, "%s -- positionDistance=%f", |
| 456 | − (testMatches(0,positionDistance, POSITION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"), | |
| 457 | − positionDistance); | |
| 458 | + (testMatches(0,positionDistance, POSITION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"), | |
| 459 | + (double)positionDistance); | |
| 458 | 460 | |
| 459 | 461 | qCDebug(octree, "%s -- angleOrientation=%f", |
| 460 | − (testMatches(0, angleOrientation, ORIENTATION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"), | |
| 461 | − angleOrientation); | |
| 462 | − | |
| 462 | + (testMatches(0, angleOrientation, ORIENTATION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"), | |
| 463 | + (double)angleOrientation); | |
| 464 | + | |
| 463 | 465 | qCDebug(octree, "%s -- compareTo._fieldOfView=%f _fieldOfView=%f", |
| 464 | − (testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"), | |
| 465 | − compareTo._fieldOfView, _fieldOfView); | |
| 466 | + (testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"), | |
| 467 | + (double)compareTo._fieldOfView, (double)_fieldOfView); | |
| 466 | 468 | qCDebug(octree, "%s -- compareTo._aspectRatio=%f _aspectRatio=%f", |
| 467 | − (testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"), | |
| 468 | − compareTo._aspectRatio, _aspectRatio); | |
| 469 | + (testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"), | |
| 470 | + (double)compareTo._aspectRatio, (double)_aspectRatio); | |
| 469 | 471 | qCDebug(octree, "%s -- compareTo._nearClip=%f _nearClip=%f", |
| 470 | − (testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"), | |
| 471 | − compareTo._nearClip, _nearClip); | |
| 472 | + (testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"), | |
| 473 | + (double)compareTo._nearClip, (double)_nearClip); | |
| 472 | 474 | qCDebug(octree, "%s -- compareTo._farClip=%f _farClip=%f", |
| 473 | − (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"), | |
| 474 | − compareTo._farClip, _farClip); | |
| 475 | + (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"), | |
| 476 | + (double)compareTo._farClip, (double)_farClip); | |
| 475 | 477 | qCDebug(octree, "%s -- compareTo._focalLength=%f _focalLength=%f", |
| 476 | − (testMatches(compareTo._focalLength, _focalLength) ? "MATCHES " : "NO MATCH"), | |
| 477 | − compareTo._focalLength, _focalLength); | |
| 478 | + (testMatches(compareTo._focalLength, _focalLength) ? "MATCHES " : "NO MATCH"), | |
| 479 | + (double)compareTo._focalLength, (double)_focalLength); | |
| 478 | 480 | } |
| 479 | 481 | return result; |
| 480 | 482 | } |
| @@ -531,23 +533,23 @@ void ViewFrustum::computeOffAxisFrustum(float& left, float& right, float& bottom · 50 unmodified lines | ||
| 531 | 533 | |
| 532 | 534 | void ViewFrustum::printDebugDetails() const { |
| 533 | 535 | qCDebug(octree, "ViewFrustum::printDebugDetails()..."); |
| 534 | − qCDebug(octree, "_position=%f,%f,%f", _position.x, _position.y, _position.z ); | |
| 535 | − qCDebug(octree, "_direction=%f,%f,%f", _direction.x, _direction.y, _direction.z ); | |
| 536 | − qCDebug(octree, "_up=%f,%f,%f", _up.x, _up.y, _up.z ); | |
| 537 | − qCDebug(octree, "_right=%f,%f,%f", _right.x, _right.y, _right.z ); | |
| 538 | − qCDebug(octree, "_fieldOfView=%f", _fieldOfView); | |
| 539 | − qCDebug(octree, "_aspectRatio=%f", _aspectRatio); | |
| 540 | − qCDebug(octree, "_keyHoleRadius=%f", _keyholeRadius); | |
| 541 | − qCDebug(octree, "_nearClip=%f", _nearClip); | |
| 542 | − qCDebug(octree, "_farClip=%f", _farClip); | |
| 543 | − qCDebug(octree, "_focalLength=%f", _focalLength); | |
| 536 | + qCDebug(octree, "_position=%f,%f,%f", (double)_position.x, (double)_position.y, (double)_position.z ); | |
| 537 | + qCDebug(octree, "_direction=%f,%f,%f", (double)_direction.x, (double)_direction.y, (double)_direction.z ); | |
| 538 | + qCDebug(octree, "_up=%f,%f,%f", (double)_up.x, (double)_up.y, (double)_up.z ); | |
| 539 | + qCDebug(octree, "_right=%f,%f,%f", (double)_right.x, (double)_right.y, (double)_right.z ); | |
| 540 | + qCDebug(octree, "_fieldOfView=%f", (double)_fieldOfView); | |
| 541 | + qCDebug(octree, "_aspectRatio=%f", (double)_aspectRatio); | |
| 542 | + qCDebug(octree, "_keyHoleRadius=%f", (double)_keyholeRadius); | |
| 543 | + qCDebug(octree, "_nearClip=%f", (double)_nearClip); | |
| 544 | + qCDebug(octree, "_farClip=%f", (double)_farClip); | |
| 545 | + qCDebug(octree, "_focalLength=%f", (double)_focalLength); | |
| 544 | 546 | } |
| 545 | 547 | |
| 546 | 548 | glm::vec2 ViewFrustum::projectPoint(glm::vec3 point, bool& pointInView) const { |
| 547 | 549 | |
| 548 | − glm::vec4 pointVec4 = glm::vec4(point,1); | |
| 550 | + glm::vec4 pointVec4 = glm::vec4(point, 1.0f); | |
| 549 | 551 | glm::vec4 projectedPointVec4 = _ourModelViewProjectionMatrix * pointVec4; |
| 550 | − pointInView = (projectedPointVec4.w > 0); // math! If the w result is negative then the point is behind the viewer | |
| 552 | + pointInView = (projectedPointVec4.w > 0.0f); // math! If the w result is negative then the point is behind the viewer | |
| 551 | 553 | |
| 552 | 554 | // what happens with w is 0??? |
| 553 | 555 | float x = projectedPointVec4.x / projectedPointVec4.w; |
| @@ -245,7 +245,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { · 244 unmodified lines | ||
| 245 | 245 | |
| 246 | 246 | float dx2 = glm::distance2(position, _serverPosition); |
| 247 | 247 | |
| 248 | − const float MAX_POSITION_ERROR_SQUARED = 0.001f; // 0.001 m^2 ~~> 0.03 m | |
| 248 | + const float MAX_POSITION_ERROR_SQUARED = 0.000004f; // Sqrt() - corresponds to 2 millimeters | |
| 249 | 249 | if (dx2 > MAX_POSITION_ERROR_SQUARED) { |
| 250 | 250 | |
| 251 | 251 | #ifdef WANT_DEBUG |
| @@ -270,7 +270,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { · 18 unmodified lines | ||
| 270 | 270 | _serverRotation = glm::normalize(computeBulletRotationStep(_serverAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP) * _serverRotation); |
| 271 | 271 | } |
| 272 | 272 | } |
| 273 | − const float MIN_ROTATION_DOT = 0.99f; // 0.99 dot threshold coresponds to about 16 degrees of slop | |
| 273 | + const float MIN_ROTATION_DOT = 0.99999f; // This corresponds to about 0.5 degrees of rotation | |
| 274 | 274 | glm::quat actualRotation = bulletToGLM(worldTrans.getRotation()); |
| 275 | 275 | |
| 276 | 276 | #ifdef WANT_DEBUG |
| @@ -270,7 +270,9 @@ void MeshMassProperties::computeMassProperties(const VectorOfPoints& points, con · 269 unmodified lines | ||
| 270 | 270 | } |
| 271 | 271 | |
| 272 | 272 | // create some variables to hold temporary results |
| 273 | + #ifndef NDEBUG | |
| 273 | 274 | uint32_t numPoints = points.size(); |
| 275 | + #endif | |
| 274 | 276 | const btVector3 p0(0.0f, 0.0f, 0.0f); |
| 275 | 277 | btMatrix3x3 tetraInertia; |
| 276 | 278 | btMatrix3x3 doubleDebugInertia; |
| @@ -281,9 +283,11 @@ void MeshMassProperties::computeMassProperties(const VectorOfPoints& points, con · 4 unmodified lines | ||
| 281 | 283 | uint32_t numTriangles = triangleIndices.size() / 3; |
| 282 | 284 | for (uint32_t i = 0; i < numTriangles; ++i) { |
| 283 | 285 | uint32_t t = 3 * i; |
| 286 | + #ifndef NDEBUG | |
| 284 | 287 | assert(triangleIndices[t] < numPoints); |
| 285 | 288 | assert(triangleIndices[t + 1] < numPoints); |
| 286 | 289 | assert(triangleIndices[t + 2] < numPoints); |
| 290 | + #endif | |
| 287 | 291 | |
| 288 | 292 | // extract raw vertices |
| 289 | 293 | tetraPoints[0] = p0; |
| @@ -28,7 +28,7 @@ void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar delta · 27 unmodified lines | ||
| 28 | 28 | return; |
| 29 | 29 | } |
| 30 | 30 | if (!_ownerEntity) { |
| 31 | − qDebug() << "ObjectActionPullToPoint::updateAction no owner entity"; | |
| 31 | + qDebug() << "ObjectAction::updateAction no owner entity"; | |
| 32 | 32 | return; |
| 33 | 33 | } |
| 34 | 34 | updateActionWorker(deltaTimeStep); |
| @@ -59,6 +59,7 @@ protected: · 58 unmodified lines | ||
| 59 | 59 | |
| 60 | 60 | bool tryLockForRead() { return _lock.tryLockForRead(); } |
| 61 | 61 | void lockForWrite() { _lock.lockForWrite(); } |
| 62 | + bool tryLockForWrite() { return _lock.tryLockForWrite(); } | |
| 62 | 63 | void unlock() { _lock.unlock(); } |
| 63 | 64 | |
| 64 | 65 | bool _active; |
| @@ -0,0 +1,109 @@ | ||
| 1 | +// | |
| 2 | +// ObjectActionOffset.cpp | |
| 3 | +// libraries/physics/src | |
| 4 | +// | |
| 5 | +// Created by Seth Alves 2015-6-17 | |
| 6 | +// Copyright 2015 High Fidelity, Inc. | |
| 7 | +// | |
| 8 | +// Distributed under the Apache License, Version 2.0. | |
| 9 | +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 10 | +// | |
| 11 | + | |
| 12 | +#include "ObjectActionOffset.h" | |
| 13 | + | |
| 14 | +ObjectActionOffset::ObjectActionOffset(QUuid id, EntityItemPointer ownerEntity) : | |
| 15 | + ObjectAction(id, ownerEntity) { | |
| 16 | + #if WANT_DEBUG | |
| 17 | + qDebug() << "ObjectActionOffset::ObjectActionOffset"; | |
| 18 | + #endif | |
| 19 | +} | |
| 20 | + | |
| 21 | +ObjectActionOffset::~ObjectActionOffset() { | |
| 22 | + #if WANT_DEBUG | |
| 23 | + qDebug() << "ObjectActionOffset::~ObjectActionOffset"; | |
| 24 | + #endif | |
| 25 | +} | |
| 26 | + | |
| 27 | +void ObjectActionOffset::updateActionWorker(btScalar deltaTimeStep) { | |
| 28 | + if (!tryLockForRead()) { | |
| 29 | + // don't risk hanging the thread running the physics simulation | |
| 30 | + return; | |
| 31 | + } | |
| 32 | + | |
| 33 | + void* physicsInfo = _ownerEntity->getPhysicsInfo(); | |
| 34 | + if (!physicsInfo) { | |
| 35 | + unlock(); | |
| 36 | + return; | |
| 37 | + } | |
| 38 | + ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo); | |
| 39 | + btRigidBody* rigidBody = motionState->getRigidBody(); | |
| 40 | + if (!rigidBody) { | |
| 41 | + unlock(); | |
| 42 | + qDebug() << "ObjectActionOffset::updateActionWorker no rigidBody"; | |
| 43 | + return; | |
| 44 | + } | |
| 45 | + | |
| 46 | + if (_positionalTargetSet) { | |
| 47 | + glm::vec3 offset = _pointToOffsetFrom - bulletToGLM(rigidBody->getCenterOfMassPosition()); | |
| 48 | + float offsetLength = glm::length(offset); | |
| 49 | + float offsetError = _linearDistance - offsetLength; | |
| 50 | + | |
| 51 | + // if (glm::abs(offsetError) > IGNORE_POSITION_DELTA) { | |
| 52 | + if (glm::abs(offsetError) > 0.0f) { | |
| 53 | + float offsetErrorAbs = glm::abs(offsetError); | |
| 54 | + float offsetErrorDirection = - offsetError / offsetErrorAbs; | |
| 55 | + glm::vec3 previousVelocity = bulletToGLM(rigidBody->getLinearVelocity()); | |
| 56 | + | |
| 57 | + glm::vec3 velocityAdjustment = glm::normalize(offset) * offsetErrorDirection * offsetErrorAbs / _linearTimeScale; | |
| 58 | + rigidBody->setLinearVelocity(glmToBullet(previousVelocity + velocityAdjustment)); | |
| 59 | + // rigidBody->setLinearVelocity(glmToBullet(velocityAdjustment)); | |
| 60 | + rigidBody->activate(); | |
| 61 | + } | |
| 62 | + } | |
| 63 | + | |
| 64 | + unlock(); | |
| 65 | +} | |
| 66 | + | |
| 67 | + | |
| 68 | +bool ObjectActionOffset::updateArguments(QVariantMap arguments) { | |
| 69 | + bool pOk0 = true; | |
| 70 | + glm::vec3 pointToOffsetFrom = | |
| 71 | + EntityActionInterface::extractVec3Argument("offset action", arguments, "pointToOffsetFrom", pOk0, true); | |
| 72 | + | |
| 73 | + bool pOk1 = true; | |
| 74 | + float linearTimeScale = | |
| 75 | + EntityActionInterface::extractFloatArgument("offset action", arguments, "linearTimeScale", pOk1, false); | |
| 76 | + | |
| 77 | + bool pOk2 = true; | |
| 78 | + float linearDistance = | |
| 79 | + EntityActionInterface::extractFloatArgument("offset action", arguments, "linearDistance", pOk2, false); | |
| 80 | + | |
| 81 | + if (!pOk0) { | |
| 82 | + return false; | |
| 83 | + } | |
| 84 | + if (pOk1 && linearTimeScale <= 0.0f) { | |
| 85 | + qDebug() << "offset action -- linearTimeScale must be greater than zero."; | |
| 86 | + return false; | |
| 87 | + } | |
| 88 | + | |
| 89 | + lockForWrite(); | |
| 90 | + | |
| 91 | + _pointToOffsetFrom = pointToOffsetFrom; | |
| 92 | + _positionalTargetSet = true; | |
| 93 | + | |
| 94 | + if (pOk1) { | |
| 95 | + _linearTimeScale = linearTimeScale; | |
| 96 | + } else { | |
| 97 | + _linearTimeScale = 0.1f; | |
| 98 | + } | |
| 99 | + | |
| 100 | + if (pOk2) { | |
| 101 | + _linearDistance = linearDistance; | |
| 102 | + } else { | |
| 103 | + _linearDistance = 1.0f; | |
| 104 | + } | |
| 105 | + | |
| 106 | + _active = true; | |
| 107 | + unlock(); | |
| 108 | + return true; | |
| 109 | +} | |
| @@ -0,0 +1,35 @@ | ||
| 1 | +// | |
| 2 | +// ObjectActionOffset.h | |
| 3 | +// libraries/physics/src | |
| 4 | +// | |
| 5 | +// Created by Seth Alves 2015-6-17 | |
| 6 | +// Copyright 2015 High Fidelity, Inc. | |
| 7 | +// | |
| 8 | +// Distributed under the Apache License, Version 2.0. | |
| 9 | +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 10 | +// | |
| 11 | + | |
| 12 | +#ifndef hifi_ObjectActionOffset_h | |
| 13 | +#define hifi_ObjectActionOffset_h | |
| 14 | + | |
| 15 | +#include <QUuid> | |
| 16 | + | |
| 17 | +#include <EntityItem.h> | |
| 18 | +#include "ObjectAction.h" | |
| 19 | + | |
| 20 | +class ObjectActionOffset : public ObjectAction { | |
| 21 | +public: | |
| 22 | + ObjectActionOffset(QUuid id, EntityItemPointer ownerEntity); | |
| 23 | + virtual ~ObjectActionOffset(); | |
| 24 | + | |
| 25 | + virtual bool updateArguments(QVariantMap arguments); | |
| 26 | + virtual void updateActionWorker(float deltaTimeStep); | |
| 27 | + | |
| 28 | +private: | |
| 29 | + glm::vec3 _pointToOffsetFrom; | |
| 30 | + float _linearDistance; | |
| 31 | + float _linearTimeScale; | |
| 32 | + bool _positionalTargetSet; | |
| 33 | +}; | |
| 34 | + | |
| 35 | +#endif // hifi_ObjectActionOffset_h | |
| @@ -1,72 +0,0 @@ | ||
| 1 | −// | |
| 2 | −// ObjectActionPullToPoint.cpp | |
| 3 | −// libraries/physics/src | |
| 4 | −// | |
| 5 | −// Created by Seth Alves 2015-6-2 | |
| 6 | −// Copyright 2015 High Fidelity, Inc. | |
| 7 | −// | |
| 8 | −// Distributed under the Apache License, Version 2.0. | |
| 9 | −// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 10 | −// | |
| 11 | − | |
| 12 | −#include "ObjectActionPullToPoint.h" | |
| 13 | − | |
| 14 | −ObjectActionPullToPoint::ObjectActionPullToPoint(QUuid id, EntityItemPointer ownerEntity) : | |
| 15 | − ObjectAction(id, ownerEntity) { | |
| 16 | − #if WANT_DEBUG | |
| 17 | − qDebug() << "ObjectActionPullToPoint::ObjectActionPullToPoint"; | |
| 18 | − #endif | |
| 19 | −} | |
| 20 | − | |
| 21 | −ObjectActionPullToPoint::~ObjectActionPullToPoint() { | |
| 22 | − #if WANT_DEBUG | |
| 23 | − qDebug() << "ObjectActionPullToPoint::~ObjectActionPullToPoint"; | |
| 24 | − #endif | |
| 25 | −} | |
| 26 | − | |
| 27 | −void ObjectActionPullToPoint::updateActionWorker(btScalar deltaTimeStep) { | |
| 28 | − if (!tryLockForRead()) { | |
| 29 | − // don't risk hanging the thread running the physics simulation | |
| 30 | − return; | |
| 31 | − } | |
| 32 | − | |
| 33 | − void* physicsInfo = _ownerEntity->getPhysicsInfo(); | |
| 34 | − if (!physicsInfo) { | |
| 35 | − unlock(); | |
| 36 | − return; | |
| 37 | − } | |
| 38 | − ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo); | |
| 39 | − btRigidBody* rigidBody = motionState->getRigidBody(); | |
| 40 | − if (!rigidBody) { | |
| 41 | − unlock(); | |
| 42 | − return; | |
| 43 | − } | |
| 44 | − | |
| 45 | − glm::vec3 offset = _target - bulletToGLM(rigidBody->getCenterOfMassPosition()); | |
| 46 | − float offsetLength = glm::length(offset); | |
| 47 | − if (offsetLength > IGNORE_POSITION_DELTA) { | |
| 48 | − glm::vec3 newVelocity = glm::normalize(offset) * _speed; | |
| 49 | − rigidBody->setLinearVelocity(glmToBullet(newVelocity)); | |
| 50 | − rigidBody->activate(); | |
| 51 | − } else { | |
| 52 | − rigidBody->setLinearVelocity(glmToBullet(glm::vec3())); | |
| 53 | − } | |
| 54 | − | |
| 55 | − unlock(); | |
| 56 | −} | |
| 57 | − | |
| 58 | − | |
| 59 | −bool ObjectActionPullToPoint::updateArguments(QVariantMap arguments) { | |
| 60 | − bool ok = true; | |
| 61 | − glm::vec3 target = EntityActionInterface::extractVec3Argument("pull-to-point action", arguments, "target", ok); | |
| 62 | − float speed = EntityActionInterface::extractFloatArgument("pull-to-point action", arguments, "speed", ok); | |
| 63 | − if (ok) { | |
| 64 | − lockForWrite(); | |
| 65 | − _target = target; | |
| 66 | − _speed = speed; | |
| 67 | − _active = true; | |
| 68 | − unlock(); | |
| 69 | − return true; | |
| 70 | − } | |
| 71 | − return false; | |
| 72 | −} | |
| @@ -1,34 +0,0 @@ | ||
| 1 | −// | |
| 2 | −// ObjectActionPullToPoint.h | |
| 3 | −// libraries/physics/src | |
| 4 | −// | |
| 5 | −// Created by Seth Alves 2015-6-3 | |
| 6 | −// Copyright 2015 High Fidelity, Inc. | |
| 7 | −// | |
| 8 | −// Distributed under the Apache License, Version 2.0. | |
| 9 | −// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 10 | −// | |
| 11 | − | |
| 12 | −#ifndef hifi_ObjectActionPullToPoint_h | |
| 13 | −#define hifi_ObjectActionPullToPoint_h | |
| 14 | − | |
| 15 | −#include <QUuid> | |
| 16 | − | |
| 17 | −#include <EntityItem.h> | |
| 18 | −#include "ObjectAction.h" | |
| 19 | − | |
| 20 | −class ObjectActionPullToPoint : public ObjectAction { | |
| 21 | −public: | |
| 22 | − ObjectActionPullToPoint(QUuid id, EntityItemPointer ownerEntity); | |
| 23 | − virtual ~ObjectActionPullToPoint(); | |
| 24 | − | |
| 25 | − virtual bool updateArguments(QVariantMap arguments); | |
| 26 | − virtual void updateActionWorker(float deltaTimeStep); | |
| 27 | − | |
| 28 | −private: | |
| 29 | − | |
| 30 | − glm::vec3 _target; | |
| 31 | − float _speed; | |
| 32 | −}; | |
| 33 | − | |
| 34 | −#endif // hifi_ObjectActionPullToPoint_h | |
| @@ -1,27 +1,37 @@ | ||
| 1 | −set(TARGET_NAME render-utils) | |
| 2 | − | |
| 3 | −AUTOSCRIBE_SHADER_LIB(gpu model render) | |
| 4 | − | |
| 5 | −# pull in the resources.qrc file | |
| 6 | −qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc") | |
| 7 | − | |
| 8 | −# use setup_hifi_library macro to setup our project and link appropriate Qt modules | |
| 9 | −setup_hifi_library(Widgets OpenGL Network Qml Quick Script) | |
| 10 | − | |
| 11 | −add_dependency_external_projects(glm) | |
| 12 | −find_package(GLM REQUIRED) | |
| 13 | −target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) | |
| 14 | − | |
| 15 | −if (WIN32) | |
| 16 | − if (USE_NSIGHT) | |
| 17 | − # try to find the Nsight package and add it to the build if we find it | |
| 18 | − find_package(NSIGHT) | |
| 19 | − if (NSIGHT_FOUND) | |
| 20 | − include_directories(${NSIGHT_INCLUDE_DIRS}) | |
| 21 | − add_definitions(-DNSIGHT_FOUND) | |
| 22 | − target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}") | |
| 23 | − endif () | |
| 24 | − endif() | |
| 25 | −endif (WIN32) | |
| 26 | − | |
| 27 | −link_hifi_libraries(animation fbx shared gpu model render) | |
| 1 | +set(TARGET_NAME render-utils) | |
| 2 | + | |
| 3 | +AUTOSCRIBE_SHADER_LIB(gpu model render) | |
| 4 | + | |
| 5 | +# pull in the resources.qrc file | |
| 6 | +qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc") | |
| 7 | + | |
| 8 | +# use setup_hifi_library macro to setup our project and link appropriate Qt modules | |
| 9 | +setup_hifi_library(Widgets OpenGL Network Qml Quick Script) | |
| 10 | + | |
| 11 | +setup_hifi_opengl() | |
| 12 | + | |
| 13 | +add_dependency_external_projects(glm) | |
| 14 | +find_package(GLM REQUIRED) | |
| 15 | +target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) | |
| 16 | + | |
| 17 | +if (WIN32) | |
| 18 | + if (USE_NSIGHT) | |
| 19 | + # try to find the Nsight package and add it to the build if we find it | |
| 20 | + find_package(NSIGHT) | |
| 21 | + if (NSIGHT_FOUND) | |
| 22 | + include_directories(${NSIGHT_INCLUDE_DIRS}) | |
| 23 | + add_definitions(-DNSIGHT_FOUND) | |
| 24 | + target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}") | |
| 25 | + endif () | |
| 26 | + endif() | |
| 27 | + | |
| 28 | + add_dependency_external_projects(boostconfig) | |
| 29 | + find_package(BoostConfig REQUIRED) | |
| 30 | + target_include_directories(${TARGET_NAME} PUBLIC ${BOOSTCONFIG_INCLUDE_DIRS}) | |
| 31 | + | |
| 32 | + add_dependency_external_projects(oglplus) | |
| 33 | + find_package(OGLPLUS REQUIRED) | |
| 34 | + target_include_directories(${TARGET_NAME} PUBLIC ${OGLPLUS_INCLUDE_DIRS}) | |
| 35 | +endif (WIN32) | |
| 36 | + | |
| 37 | +link_hifi_libraries(animation fbx shared gpu model render) | |
| @@ -61,15 +61,26 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { · 60 unmodified lines | ||
| 61 | 61 | gpu::Shader::BindingSet slotBindings; |
| 62 | 62 | gpu::Shader::makeProgram(*program, slotBindings); |
| 63 | 63 | gpu::Shader::makeProgram(*programTextured, slotBindings); |
| 64 | − | |
| 64 | + | |
| 65 | 65 | gpu::StatePointer state = gpu::StatePointer(new gpu::State()); |
| 66 | 66 | state->setCullMode(gpu::State::CULL_BACK); |
| 67 | 67 | state->setDepthTest(true, true, gpu::LESS_EQUAL); |
| 68 | 68 | state->setBlendFunction(false, |
| 69 | 69 | gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, |
| 70 | 70 | gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); |
| 71 | + | |
| 72 | + | |
| 73 | + gpu::StatePointer stateCullNone = gpu::StatePointer(new gpu::State()); | |
| 74 | + stateCullNone->setCullMode(gpu::State::CULL_NONE); | |
| 75 | + stateCullNone->setDepthTest(true, true, gpu::LESS_EQUAL); | |
| 76 | + stateCullNone->setBlendFunction(false, | |
| 77 | + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, | |
| 78 | + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); | |
| 79 | + | |
| 71 | 80 | _simpleProgram = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); |
| 81 | + _simpleProgramCullNone = gpu::PipelinePointer(gpu::Pipeline::create(program, stateCullNone)); | |
| 72 | 82 | _simpleProgramTextured = gpu::PipelinePointer(gpu::Pipeline::create(programTextured, state)); |
| 83 | + _simpleProgramTexturedCullNone = gpu::PipelinePointer(gpu::Pipeline::create(programTextured, stateCullNone)); | |
| 73 | 84 | |
| 74 | 85 | _viewState = viewState; |
| 75 | 86 | loadLightProgram(directional_light_frag, false, _directionalLight, _directionalLightLocations); |
| @@ -106,13 +117,21 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { · 30 unmodified lines | ||
| 106 | 117 | lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET)); |
| 107 | 118 | } |
| 108 | 119 | |
| 109 | −void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured) { | |
| 120 | +void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled) { | |
| 110 | 121 | // DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(batch, true, true, true); |
| 111 | 122 | |
| 112 | 123 | if (textured) { |
| 113 | − batch.setPipeline(_simpleProgramTextured); | |
| 124 | + if (culled) { | |
| 125 | + batch.setPipeline(_simpleProgramTextured); | |
| 126 | + } else { | |
| 127 | + batch.setPipeline(_simpleProgramTexturedCullNone); | |
| 128 | + } | |
| 114 | 129 | } else { |
| 115 | − batch.setPipeline(_simpleProgram); | |
| 130 | + if (culled) { | |
| 131 | + batch.setPipeline(_simpleProgram); | |
| 132 | + } else { | |
| 133 | + batch.setPipeline(_simpleProgramCullNone); | |
| 134 | + } | |
| 116 | 135 | } |
| 117 | 136 | } |
| 118 | 137 | |
| @@ -191,7 +210,7 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu · 72 unmodified lines | ||
| 191 | 210 | } |
| 192 | 211 | } |
| 193 | 212 | |
| 194 | −void DeferredLightingEffect::prepare() { | |
| 213 | +void DeferredLightingEffect::prepare(RenderArgs* args) { | |
| 195 | 214 | // clear the normal and specular buffers |
| 196 | 215 | auto textureCache = DependencyManager::get<TextureCache>(); |
| 197 | 216 | textureCache->setPrimaryDrawBuffers(false, true, false); |
| @@ -205,7 +224,7 @@ void DeferredLightingEffect::prepare() { · 7 unmodified lines | ||
| 205 | 224 | textureCache->setPrimaryDrawBuffers(true, false, false); |
| 206 | 225 | } |
| 207 | 226 | |
| 208 | −void DeferredLightingEffect::render() { | |
| 227 | +void DeferredLightingEffect::render(RenderArgs* args) { | |
| 209 | 228 | // perform deferred lighting, rendering to free fbo |
| 210 | 229 | glDisable(GL_BLEND); |
| 211 | 230 | glDisable(GL_LIGHTING); |
| @@ -34,7 +34,7 @@ public: · 33 unmodified lines | ||
| 34 | 34 | void init(AbstractViewStateInterface* viewState); |
| 35 | 35 | |
| 36 | 36 | /// Sets up the state necessary to render static untextured geometry with the simple program. |
| 37 | − void bindSimpleProgram(gpu::Batch& batch, bool textured = false); | |
| 37 | + void bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true); | |
| 38 | 38 | |
| 39 | 39 | /// Tears down the state necessary to render static untextured geometry with the simple program. |
| 40 | 40 | void releaseSimpleProgram(gpu::Batch& batch); |
| @@ -66,8 +66,8 @@ public: · 25 unmodified lines | ||
| 66 | 66 | void addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f), |
| 67 | 67 | float intensity = 0.5f, const glm::quat& orientation = glm::quat(), float exponent = 0.0f, float cutoff = PI); |
| 68 | 68 | |
| 69 | − void prepare(); | |
| 70 | − void render(); | |
| 69 | + void prepare(RenderArgs* args); | |
| 70 | + void render(RenderArgs* args); | |
| 71 | 71 | void copyBack(RenderArgs* args); |
| 72 | 72 | |
| 73 | 73 | void setupTransparent(RenderArgs* args, int lightBufferUnit); |
| @@ -100,7 +100,9 @@ private: · 26 unmodified lines | ||
| 100 | 100 | static void loadLightProgram(const char* fragSource, bool limited, ProgramObject& program, LightLocations& locations); |
| 101 | 101 | |
| 102 | 102 | gpu::PipelinePointer _simpleProgram; |
| 103 | + gpu::PipelinePointer _simpleProgramCullNone; | |
| 103 | 104 | gpu::PipelinePointer _simpleProgramTextured; |
| 105 | + gpu::PipelinePointer _simpleProgramTexturedCullNone; | |
| 104 | 106 | |
| 105 | 107 | ProgramObject _directionalSkyboxLight; |
| 106 | 108 | LightLocations _directionalSkyboxLightLocations; |
| @@ -28,6 +28,9 @@ · 27 unmodified lines | ||
| 28 | 28 | #include "RenderUtilsLogging.h" |
| 29 | 29 | #include "GeometryCache.h" |
| 30 | 30 | |
| 31 | +#include "standardTransformPNTC_vert.h" | |
| 32 | +#include "standardDrawTexture_frag.h" | |
| 33 | + | |
| 31 | 34 | //#define WANT_DEBUG |
| 32 | 35 | |
| 33 | 36 | const int GeometryCache::UNKNOWN_ID = -1; |
| @@ -1025,13 +1028,13 @@ void GeometryCache::renderBevelCornersRect(gpu::Batch& batch, int x, int y, int · 991 unmodified lines | ||
| 1025 | 1028 | #endif // def WANT_DEBUG |
| 1026 | 1029 | } |
| 1027 | 1030 | |
| 1028 | − const int FLOATS_PER_VERTEX = 2; // vertices | |
| 1029 | − const int vertices = 8; | |
| 1030 | − | |
| 1031 | 1031 | if (!details.isCreated) { |
| 1032 | − | |
| 1032 | + static const int FLOATS_PER_VERTEX = 2; // vertices | |
| 1033 | + static const int NUM_VERTICES = 8; | |
| 1034 | + static const int NUM_FLOATS = NUM_VERTICES * FLOATS_PER_VERTEX; | |
| 1035 | + | |
| 1033 | 1036 | details.isCreated = true; |
| 1034 | − details.vertices = vertices; | |
| 1037 | + details.vertices = NUM_VERTICES; | |
| 1035 | 1038 | details.vertexSize = FLOATS_PER_VERTEX; |
| 1036 | 1039 | |
| 1037 | 1040 | gpu::BufferPointer verticesBuffer(new gpu::Buffer()); |
| @@ -1044,62 +1047,65 @@ void GeometryCache::renderBevelCornersRect(gpu::Batch& batch, int x, int y, int · 6 unmodified lines | ||
| 1044 | 1047 | details.streamFormat = streamFormat; |
| 1045 | 1048 | details.stream = stream; |
| 1046 | 1049 | |
| 1047 | − details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0); | |
| 1050 | + details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ)); | |
| 1048 | 1051 | details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA)); |
| 1049 | 1052 | |
| 1050 | 1053 | details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride); |
| 1051 | 1054 | details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride); |
| 1052 | 1055 | |
| 1053 | 1056 | |
| 1054 | − int vertexPoints = vertices * FLOATS_PER_VERTEX; | |
| 1055 | − GLfloat* vertexBuffer = new GLfloat[vertexPoints]; // only vertices, no normals because we're a 2D quad | |
| 1056 | − GLfloat* vertex = vertexBuffer; | |
| 1057 | + GLfloat vertexBuffer[NUM_FLOATS]; // only vertices, no normals because we're a 2D quad | |
| 1057 | 1058 | int vertexPoint = 0; |
| 1058 | 1059 | |
| 1059 | − // left side | |
| 1060 | − vertex[vertexPoint++] = x; | |
| 1061 | − vertex[vertexPoint++] = y + bevelDistance; | |
| 1060 | + // Triangle strip points | |
| 1061 | + // 3 ------ 5 | |
| 1062 | + // / \ | |
| 1063 | + // 1 7 | |
| 1064 | + // | | | |
| 1065 | + // 2 8 | |
| 1066 | + // \ / | |
| 1067 | + // 4 ------ 6 | |
| 1062 | 1068 | |
| 1063 | − vertex[vertexPoint++] = x; | |
| 1064 | − vertex[vertexPoint++] = y + height - bevelDistance; | |
| 1065 | − | |
| 1066 | − // top side | |
| 1067 | − vertex[vertexPoint++] = x + bevelDistance; | |
| 1068 | − vertex[vertexPoint++] = y + height; | |
| 1069 | + // 1 | |
| 1070 | + vertexBuffer[vertexPoint++] = x; | |
| 1071 | + vertexBuffer[vertexPoint++] = y + height - bevelDistance; | |
| 1072 | + // 2 | |
| 1073 | + vertexBuffer[vertexPoint++] = x; | |
| 1074 | + vertexBuffer[vertexPoint++] = y + bevelDistance; | |
| 1075 | + // 3 | |
| 1076 | + vertexBuffer[vertexPoint++] = x + bevelDistance; | |
| 1077 | + vertexBuffer[vertexPoint++] = y + height; | |
| 1078 | + // 4 | |
| 1079 | + vertexBuffer[vertexPoint++] = x + bevelDistance; | |
| 1080 | + vertexBuffer[vertexPoint++] = y; | |
| 1081 | + // 5 | |
| 1082 | + vertexBuffer[vertexPoint++] = x + width - bevelDistance; | |
| 1083 | + vertexBuffer[vertexPoint++] = y + height; | |
| 1084 | + // 6 | |
| 1085 | + vertexBuffer[vertexPoint++] = x + width - bevelDistance; | |
| 1086 | + vertexBuffer[vertexPoint++] = y; | |
| 1087 | + // 7 | |
| 1088 | + vertexBuffer[vertexPoint++] = x + width; | |
| 1089 | + vertexBuffer[vertexPoint++] = y + height - bevelDistance; | |
| 1090 | + // 8 | |
| 1091 | + vertexBuffer[vertexPoint++] = x + width; | |
| 1092 | + vertexBuffer[vertexPoint++] = y + bevelDistance; | |
| 1069 | 1093 | |
| 1070 | − vertex[vertexPoint++] = x + width - bevelDistance; | |
| 1071 | − vertex[vertexPoint++] = y + height; | |
| 1072 | − | |
| 1073 | − // right | |
| 1074 | − vertex[vertexPoint++] = x + width; | |
| 1075 | − vertex[vertexPoint++] = y + height - bevelDistance; | |
| 1076 | − vertex[vertexPoint++] = x + width; | |
| 1077 | − vertex[vertexPoint++] = y + bevelDistance; | |
| 1078 | − | |
| 1079 | − // bottom | |
| 1080 | − vertex[vertexPoint++] = x + width - bevelDistance; | |
| 1081 | − vertex[vertexPoint++] = y; | |
| 1082 | − vertex[vertexPoint++] = x +bevelDistance; | |
| 1083 | − vertex[vertexPoint++] = y; | |
| 1084 | − | |
| 1085 | − const int NUM_COLOR_SCALARS_PER_QUAD = 8; | |
| 1086 | 1094 | int compactColor = ((int(color.x * 255.0f) & 0xFF)) | |
| 1087 | 1095 | ((int(color.y * 255.0f) & 0xFF) << 8) | |
| 1088 | 1096 | ((int(color.z * 255.0f) & 0xFF) << 16) | |
| 1089 | 1097 | ((int(color.w * 255.0f) & 0xFF) << 24); |
| 1090 | − int colors[NUM_COLOR_SCALARS_PER_QUAD] = { compactColor, compactColor, compactColor, compactColor, | |
| 1091 | − compactColor, compactColor, compactColor, compactColor }; | |
| 1098 | + int colors[NUM_VERTICES] = { compactColor, compactColor, compactColor, compactColor, | |
| 1099 | + compactColor, compactColor, compactColor, compactColor }; | |
| 1092 | 1100 | |
| 1093 | 1101 | |
| 1094 | 1102 | details.verticesBuffer->append(sizeof(vertexBuffer), (gpu::Byte*) vertexBuffer); |
| 1095 | 1103 | details.colorBuffer->append(sizeof(colors), (gpu::Byte*) colors); |
| 1096 | − | |
| 1097 | − delete[] vertexBuffer; | |
| 1098 | 1104 | } |
| 1099 | 1105 | |
| 1100 | 1106 | batch.setInputFormat(details.streamFormat); |
| 1101 | 1107 | batch.setInputStream(0, *details.stream); |
| 1102 | − batch.draw(gpu::QUADS, 4, 0); | |
| 1108 | + batch.draw(gpu::TRIANGLE_STRIP, details.vertices, 0); | |
| 1103 | 1109 | } |
| 1104 | 1110 | |
| 1105 | 1111 | void GeometryCache::renderQuad(const glm::vec2& minCorner, const glm::vec2& maxCorner, const glm::vec4& color, int id) { |
| @@ -1179,6 +1185,26 @@ void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, co · 73 unmodified lines | ||
| 1179 | 1185 | batch.draw(gpu::QUADS, 4, 0); |
| 1180 | 1186 | } |
| 1181 | 1187 | |
| 1188 | +void GeometryCache::renderUnitCube(gpu::Batch& batch) { | |
| 1189 | + static const glm::vec4 color(1); | |
| 1190 | + renderSolidCube(batch, 1, color); | |
| 1191 | +} | |
| 1192 | + | |
| 1193 | +void GeometryCache::renderUnitQuad(const glm::vec4& color, int id) { | |
| 1194 | + gpu::Batch batch; | |
| 1195 | + renderUnitQuad(batch, color, id); | |
| 1196 | + gpu::GLBackend::renderBatch(batch); | |
| 1197 | +} | |
| 1198 | + | |
| 1199 | +void GeometryCache::renderUnitQuad(gpu::Batch& batch, const glm::vec4& color, int id) { | |
| 1200 | + static const glm::vec2 topLeft(-1, 1); | |
| 1201 | + static const glm::vec2 bottomRight(1, -1); | |
| 1202 | + static const glm::vec2 texCoordTopLeft(0.0f, 1.0f); | |
| 1203 | + static const glm::vec2 texCoordBottomRight(1.0f, 0.0f); | |
| 1204 | + renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color, id); | |
| 1205 | +} | |
| 1206 | + | |
| 1207 | + | |
| 1182 | 1208 | void GeometryCache::renderQuad(const glm::vec2& minCorner, const glm::vec2& maxCorner, |
| 1183 | 1209 | const glm::vec2& texCoordMinCorner, const glm::vec2& texCoordMaxCorner, |
| 1184 | 1210 | const glm::vec4& color, int id) { |
| @@ -1802,6 +1828,23 @@ QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url, const QS · 617 unmodified lines | ||
| 1802 | 1828 | return geometry.staticCast<Resource>(); |
| 1803 | 1829 | } |
| 1804 | 1830 | |
| 1831 | +void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch) { | |
| 1832 | + if (!_standardDrawPipeline) { | |
| 1833 | + auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(standardTransformPNTC_vert))); | |
| 1834 | + auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(standardDrawTexture_frag))); | |
| 1835 | + auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); | |
| 1836 | + gpu::Shader::makeProgram((*program)); | |
| 1837 | + | |
| 1838 | + auto state = gpu::StatePointer(new gpu::State()); | |
| 1839 | + | |
| 1840 | + // enable decal blend | |
| 1841 | + state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); | |
| 1842 | + | |
| 1843 | + _standardDrawPipeline.reset(gpu::Pipeline::create(program, state)); | |
| 1844 | + } | |
| 1845 | + batch.setPipeline(_standardDrawPipeline); | |
| 1846 | +} | |
| 1847 | + | |
| 1805 | 1848 | const float NetworkGeometry::NO_HYSTERESIS = -1.0f; |
| 1806 | 1849 | |
| 1807 | 1850 | NetworkGeometry::NetworkGeometry(const QUrl& url, const QSharedPointer<NetworkGeometry>& fallback, bool delayLoad, |
| @@ -155,6 +155,10 @@ public: · 154 unmodified lines | ||
| 155 | 155 | void renderBevelCornersRect(int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID); |
| 156 | 156 | void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID); |
| 157 | 157 | |
| 158 | + void renderUnitCube(gpu::Batch& batch); | |
| 159 | + void renderUnitQuad(const glm::vec4& color = glm::vec4(1), int id = UNKNOWN_ID); | |
| 160 | + void renderUnitQuad(gpu::Batch& batch, const glm::vec4& color = glm::vec4(1), int id = UNKNOWN_ID); | |
| 161 | + | |
| 158 | 162 | void renderQuad(int x, int y, int width, int height, const glm::vec4& color, int id = UNKNOWN_ID) |
| 159 | 163 | { renderQuad(glm::vec2(x,y), glm::vec2(x + width, y + height), color, id); } |
| 160 | 164 | void renderQuad(gpu::Batch& batch, int x, int y, int width, int height, const glm::vec4& color, int id = UNKNOWN_ID) |
| @@ -249,6 +253,9 @@ public: · 88 unmodified lines | ||
| 249 | 253 | /// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested |
| 250 | 254 | QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false); |
| 251 | 255 | |
| 256 | + /// Set a batch to the simple pipeline, returning the previous pipeline | |
| 257 | + void useSimpleDrawPipeline(gpu::Batch& batch); | |
| 258 | + | |
| 252 | 259 | protected: |
| 253 | 260 | |
| 254 | 261 | virtual QSharedPointer<Resource> createResource(const QUrl& url, |
| @@ -266,6 +273,7 @@ private: · 11 unmodified lines | ||
| 266 | 273 | int vertexSize; |
| 267 | 274 | }; |
| 268 | 275 | |
| 276 | + gpu::PipelinePointer _standardDrawPipeline; | |
| 269 | 277 | QHash<float, gpu::BufferPointer> _cubeVerticies; |
| 270 | 278 | QHash<Vec2Pair, gpu::BufferPointer> _cubeColors; |
| 271 | 279 | gpu::BufferPointer _wireCubeIndexBuffer; |
| @@ -273,7 +281,7 @@ private: · 1 unmodified line | ||
| 273 | 281 | QHash<float, gpu::BufferPointer> _solidCubeVertices; |
| 274 | 282 | QHash<Vec2Pair, gpu::BufferPointer> _solidCubeColors; |
| 275 | 283 | gpu::BufferPointer _solidCubeIndexBuffer; |
| 276 | − | |
| 284 | + | |
| 277 | 285 | class BatchItemDetails { |
| 278 | 286 | public: |
| 279 | 287 | static int population; |
| @@ -545,11 +545,6 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g · 544 unmodified lines | ||
| 545 | 545 | // we can use the AABox's ray intersection by mapping our origin and direction into the model frame |
| 546 | 546 | // and testing intersection there. |
| 547 | 547 | if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face)) { |
| 548 | − | |
| 549 | − if (!_calculatedMeshBoxesValid) { | |
| 550 | − recalculateMeshBoxes(pickAgainstTriangles); | |
| 551 | − } | |
| 552 | − | |
| 553 | 548 | float bestDistance = std::numeric_limits<float>::max(); |
| 554 | 549 | |
| 555 | 550 | float distanceToSubMesh; |
| @@ -560,6 +555,11 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g · 4 unmodified lines | ||
| 560 | 555 | |
| 561 | 556 | // If we hit the models box, then consider the submeshes... |
| 562 | 557 | _mutex.lock(); |
| 558 | + | |
| 559 | + if (!_calculatedMeshBoxesValid) { | |
| 560 | + recalculateMeshBoxes(pickAgainstTriangles); | |
| 561 | + } | |
| 562 | + | |
| 563 | 563 | foreach(const AABox& subMeshBox, _calculatedMeshBoxes) { |
| 564 | 564 | |
| 565 | 565 | if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace)) { |
| @@ -1804,13 +1804,16 @@ AABox Model::getPartBounds(int meshIndex, int partIndex) { · 1238 unmodified lines | ||
| 1804 | 1804 | } |
| 1805 | 1805 | |
| 1806 | 1806 | void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent) { |
| 1807 | + PerformanceTimer perfTimer("Model::renderPart"); | |
| 1807 | 1808 | if (!_readyWhenAdded) { |
| 1808 | 1809 | return; // bail asap |
| 1809 | 1810 | } |
| 1810 | 1811 | |
| 1811 | 1812 | // We need to make sure we have valid offsets calculated before we can render |
| 1812 | 1813 | if (!_calculatedMeshPartOffsetValid) { |
| 1814 | + _mutex.lock(); | |
| 1813 | 1815 | recalculateMeshPartOffsets(); |
| 1816 | + _mutex.unlock(); | |
| 1814 | 1817 | } |
| 1815 | 1818 | auto textureCache = DependencyManager::get<TextureCache>(); |
| 1816 | 1819 | |
| @@ -2018,7 +2021,9 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran · 201 unmodified lines | ||
| 2018 | 2021 | } |
| 2019 | 2022 | } |
| 2020 | 2023 | |
| 2024 | + _mutex.lock(); | |
| 2021 | 2025 | qint64 offset = _calculatedMeshPartOffset[QPair<int,int>(meshIndex, partIndex)]; |
| 2026 | + _mutex.unlock(); | |
| 2022 | 2027 | |
| 2023 | 2028 | if (part.quadIndices.size() > 0) { |
| 2024 | 2029 | batch.drawIndexed(gpu::QUADS, part.quadIndices.size(), offset); |
| @@ -11,6 +11,9 @@ · 10 unmodified lines | ||
| 11 | 11 | #include <QOpenGLDebugLogger> |
| 12 | 12 | #include <QGLWidget> |
| 13 | 13 | #include <QtQml> |
| 14 | + | |
| 15 | +#include <PerfStat.h> | |
| 16 | + | |
| 14 | 17 | #include "AbstractViewStateInterface.h" |
| 15 | 18 | |
| 16 | 19 | Q_DECLARE_LOGGING_CATEGORY(offscreenFocus) |
| @@ -91,6 +94,7 @@ void OffscreenQmlSurface::resize(const QSize& newSize) { · 74 unmodified lines | ||
| 91 | 94 | // Qt bug in 5.4 forces this check of pixel ratio, |
| 92 | 95 | // even though we're rendering offscreen. |
| 93 | 96 | qreal pixelRatio = 1.0; |
| 97 | + _qmlEngine->rootContext()->setContextProperty("surfaceSize", newSize); | |
| 94 | 98 | if (_renderControl && _renderControl->_renderWindow) { |
| 95 | 99 | pixelRatio = _renderControl->_renderWindow->devicePixelRatio(); |
| 96 | 100 | } else { |
| @@ -111,7 +115,6 @@ void OffscreenQmlSurface::resize(const QSize& newSize) { · 14 unmodified lines | ||
| 111 | 115 | _quickWindow->contentItem()->setSize(newSize); |
| 112 | 116 | } |
| 113 | 117 | |
| 114 | − | |
| 115 | 118 | // Update our members |
| 116 | 119 | if (_rootItem) { |
| 117 | 120 | _rootItem->setSize(newSize); |
| @@ -212,6 +215,7 @@ QObject* OffscreenQmlSurface::finishQmlLoad(std::function<void(QQmlContext*, QOb · 94 unmodified lines | ||
| 212 | 215 | |
| 213 | 216 | |
| 214 | 217 | void OffscreenQmlSurface::updateQuick() { |
| 218 | + PerformanceTimer perfTimer("qmlUpdate"); | |
| 215 | 219 | if (_paused) { |
| 216 | 220 | return; |
| 217 | 221 | } |
| @@ -376,4 +380,4 @@ void OffscreenQmlSurface::setProxyWindow(QWindow* window) { · 158 unmodified lines | ||
| 376 | 380 | |
| 377 | 381 | QQuickWindow* OffscreenQmlSurface::getWindow() { |
| 378 | 382 | return _quickWindow; |
| 379 | −} | |
| 383 | +} | |
| @@ -0,0 +1,325 @@ | ||
| 1 | +#ifdef Q_OS_WIN | |
| 2 | + | |
| 3 | +// | |
| 4 | +// Created by Bradley Austin Davis on 2015/05/29 | |
| 5 | +// Copyright 2015 High Fidelity, Inc. | |
| 6 | +// | |
| 7 | +// Distributed under the Apache License, Version 2.0. | |
| 8 | +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 9 | +// | |
| 10 | +#include "OglplusHelpers.h" | |
| 11 | + | |
| 12 | +using namespace oglplus; | |
| 13 | +using namespace oglplus::shapes; | |
| 14 | + | |
| 15 | +static const char * SIMPLE_TEXTURED_VS = R"VS(#version 410 core | |
| 16 | +#pragma line __LINE__ | |
| 17 | + | |
| 18 | +uniform mat4 Projection = mat4(1); | |
| 19 | +uniform mat4 ModelView = mat4(1); | |
| 20 | + | |
| 21 | +layout(location = 0) in vec3 Position; | |
| 22 | +layout(location = 1) in vec2 TexCoord; | |
| 23 | + | |
| 24 | +out vec2 vTexCoord; | |
| 25 | + | |
| 26 | +void main() { | |
| 27 | + gl_Position = Projection * ModelView * vec4(Position, 1); | |
| 28 | + vTexCoord = TexCoord; | |
| 29 | +} | |
| 30 | + | |
| 31 | +)VS"; | |
| 32 | + | |
| 33 | +static const char * SIMPLE_TEXTURED_FS = R"FS(#version 410 core | |
| 34 | +#pragma line __LINE__ | |
| 35 | + | |
| 36 | +uniform sampler2D sampler; | |
| 37 | +uniform float Alpha = 1.0; | |
| 38 | + | |
| 39 | +in vec2 vTexCoord; | |
| 40 | +out vec4 vFragColor; | |
| 41 | + | |
| 42 | +void main() { | |
| 43 | + vec4 c = texture(sampler, vTexCoord); | |
| 44 | + c.a = min(Alpha, c.a); | |
| 45 | + vFragColor = c; | |
| 46 | +} | |
| 47 | + | |
| 48 | +)FS"; | |
| 49 | + | |
| 50 | + | |
| 51 | +ProgramPtr loadDefaultShader() { | |
| 52 | + ProgramPtr result; | |
| 53 | + compileProgram(result, SIMPLE_TEXTURED_VS, SIMPLE_TEXTURED_FS); | |
| 54 | + return result; | |
| 55 | +} | |
| 56 | + | |
| 57 | +void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs) { | |
| 58 | + using namespace oglplus; | |
| 59 | + try { | |
| 60 | + result = ProgramPtr(new Program()); | |
| 61 | + // attach the shaders to the program | |
| 62 | + result->AttachShader( | |
| 63 | + VertexShader() | |
| 64 | + .Source(GLSLSource(vs)) | |
| 65 | + .Compile() | |
| 66 | + ); | |
| 67 | + result->AttachShader( | |
| 68 | + FragmentShader() | |
| 69 | + .Source(GLSLSource(fs)) | |
| 70 | + .Compile() | |
| 71 | + ); | |
| 72 | + result->Link(); | |
| 73 | + } catch (ProgramBuildError & err) { | |
| 74 | + Q_UNUSED(err); | |
| 75 | + Q_ASSERT_X(false, "compileProgram", "Failed to build shader program"); | |
| 76 | + qFatal((const char*)err.Message); | |
| 77 | + result.reset(); | |
| 78 | + } | |
| 79 | +} | |
| 80 | + | |
| 81 | + | |
| 82 | +ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect) { | |
| 83 | + using namespace oglplus; | |
| 84 | + Vec3f a(1, 0, 0); | |
| 85 | + Vec3f b(0, 1, 0); | |
| 86 | + if (aspect > 1) { | |
| 87 | + b[1] /= aspect; | |
| 88 | + } else { | |
| 89 | + a[0] *= aspect; | |
| 90 | + } | |
| 91 | + return ShapeWrapperPtr( | |
| 92 | + new shapes::ShapeWrapper({ "Position", "TexCoord" }, shapes::Plane(a, b), *program) | |
| 93 | + ); | |
| 94 | +} | |
| 95 | + | |
| 96 | +// Return a point's cartesian coordinates on a sphere from pitch and yaw | |
| 97 | +static glm::vec3 getPoint(float yaw, float pitch) { | |
| 98 | + return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)), | |
| 99 | + glm::sin(-pitch), | |
| 100 | + glm::cos(-pitch) * (-glm::cos(yaw))); | |
| 101 | +} | |
| 102 | + | |
| 103 | + | |
| 104 | +class SphereSection : public DrawingInstructionWriter, public DrawMode { | |
| 105 | +public: | |
| 106 | + using IndexArray = std::vector<GLuint>; | |
| 107 | + using PosArray = std::vector<float>; | |
| 108 | + using TexArray = std::vector<float>; | |
| 109 | + /// The type of the index container returned by Indices() | |
| 110 | + // vertex positions | |
| 111 | + PosArray _pos_data; | |
| 112 | + // vertex tex coords | |
| 113 | + TexArray _tex_data; | |
| 114 | + IndexArray _idx_data; | |
| 115 | + unsigned int _prim_count{ 0 }; | |
| 116 | + | |
| 117 | +public: | |
| 118 | + SphereSection( | |
| 119 | + const float fov, | |
| 120 | + const float aspectRatio, | |
| 121 | + const int slices_, | |
| 122 | + const int stacks_) { | |
| 123 | + //UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm | |
| 124 | + if (fov >= PI) { | |
| 125 | + qDebug() << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues"; | |
| 126 | + } | |
| 127 | + | |
| 128 | + int gridSize = std::max(slices_, stacks_); | |
| 129 | + int gridSizeLog2 = 1; | |
| 130 | + while (1 << gridSizeLog2 < gridSize) { | |
| 131 | + ++gridSizeLog2; | |
| 132 | + } | |
| 133 | + gridSize = (1 << gridSizeLog2) + 1; | |
| 134 | + // Compute number of vertices needed | |
| 135 | + int vertices = gridSize * gridSize; | |
| 136 | + _pos_data.resize(vertices * 3); | |
| 137 | + _tex_data.resize(vertices * 2); | |
| 138 | + | |
| 139 | + // Compute vertices positions and texture UV coordinate | |
| 140 | + for (int y = 0; y <= gridSize; ++y) { | |
| 141 | + for (int x = 0; x <= gridSize; ++x) { | |
| 142 | + | |
| 143 | + } | |
| 144 | + } | |
| 145 | + for (int i = 0; i < gridSize; i++) { | |
| 146 | + float stacksRatio = (float)i / (float)(gridSize - 1); // First stack is 0.0f, last stack is 1.0f | |
| 147 | + // abs(theta) <= fov / 2.0f | |
| 148 | + float pitch = -fov * (stacksRatio - 0.5f); | |
| 149 | + for (int j = 0; j < gridSize; j++) { | |
| 150 | + float slicesRatio = (float)j / (float)(gridSize - 1); // First slice is 0.0f, last slice is 1.0f | |
| 151 | + // abs(phi) <= fov * aspectRatio / 2.0f | |
| 152 | + float yaw = -fov * aspectRatio * (slicesRatio - 0.5f); | |
| 153 | + int vertex = i * gridSize + j; | |
| 154 | + int posOffset = vertex * 3; | |
| 155 | + int texOffset = vertex * 2; | |
| 156 | + vec3 pos = getPoint(yaw, pitch); | |
| 157 | + _pos_data[posOffset] = pos.x; | |
| 158 | + _pos_data[posOffset + 1] = pos.y; | |
| 159 | + _pos_data[posOffset + 2] = pos.z; | |
| 160 | + _tex_data[texOffset] = slicesRatio; | |
| 161 | + _tex_data[texOffset + 1] = stacksRatio; | |
| 162 | + } | |
| 163 | + } // done with vertices | |
| 164 | + | |
| 165 | + int rowLen = gridSize; | |
| 166 | + | |
| 167 | + // gridsize now refers to the triangles, not the vertices, so reduce by one | |
| 168 | + // or die by fencepost error http://en.wikipedia.org/wiki/Off-by-one_error | |
| 169 | + --gridSize; | |
| 170 | + int quads = gridSize * gridSize; | |
| 171 | + for (int t = 0; t < quads; ++t) { | |
| 172 | + int x = | |
| 173 | + ((t & 0x0001) >> 0) | | |
| 174 | + ((t & 0x0004) >> 1) | | |
| 175 | + ((t & 0x0010) >> 2) | | |
| 176 | + ((t & 0x0040) >> 3) | | |
| 177 | + ((t & 0x0100) >> 4) | | |
| 178 | + ((t & 0x0400) >> 5) | | |
| 179 | + ((t & 0x1000) >> 6) | | |
| 180 | + ((t & 0x4000) >> 7); | |
| 181 | + int y = | |
| 182 | + ((t & 0x0002) >> 1) | | |
| 183 | + ((t & 0x0008) >> 2) | | |
| 184 | + ((t & 0x0020) >> 3) | | |
| 185 | + ((t & 0x0080) >> 4) | | |
| 186 | + ((t & 0x0200) >> 5) | | |
| 187 | + ((t & 0x0800) >> 6) | | |
| 188 | + ((t & 0x2000) >> 7) | | |
| 189 | + ((t & 0x8000) >> 8); | |
| 190 | + int i = x * (rowLen) + y; | |
| 191 | + | |
| 192 | + _idx_data.push_back(i); | |
| 193 | + _idx_data.push_back(i + 1); | |
| 194 | + _idx_data.push_back(i + rowLen + 1); | |
| 195 | + | |
| 196 | + _idx_data.push_back(i + rowLen + 1); | |
| 197 | + _idx_data.push_back(i + rowLen); | |
| 198 | + _idx_data.push_back(i); | |
| 199 | + } | |
| 200 | + _prim_count = quads * 2; | |
| 201 | + } | |
| 202 | + | |
| 203 | + /// Returns the winding direction of faces | |
| 204 | + FaceOrientation FaceWinding(void) const { | |
| 205 | + return FaceOrientation::CCW; | |
| 206 | + } | |
| 207 | + | |
| 208 | + typedef GLuint(SphereSection::*VertexAttribFunc)(std::vector<GLfloat>&) const; | |
| 209 | + | |
| 210 | + /// Makes the vertex positions and returns the number of values per vertex | |
| 211 | + template <typename T> | |
| 212 | + GLuint Positions(std::vector<T>& dest) const { | |
| 213 | + dest.clear(); | |
| 214 | + dest.insert(dest.begin(), _pos_data.begin(), _pos_data.end()); | |
| 215 | + return 3; | |
| 216 | + } | |
| 217 | + | |
| 218 | + /// Makes the vertex normals and returns the number of values per vertex | |
| 219 | + template <typename T> | |
| 220 | + GLuint Normals(std::vector<T>& dest) const { | |
| 221 | + dest.clear(); | |
| 222 | + return 3; | |
| 223 | + } | |
| 224 | + | |
| 225 | + /// Makes the vertex tangents and returns the number of values per vertex | |
| 226 | + template <typename T> | |
| 227 | + GLuint Tangents(std::vector<T>& dest) const { | |
| 228 | + dest.clear(); | |
| 229 | + return 3; | |
| 230 | + } | |
| 231 | + | |
| 232 | + /// Makes the vertex bi-tangents and returns the number of values per vertex | |
| 233 | + template <typename T> | |
| 234 | + GLuint Bitangents(std::vector<T>& dest) const { | |
| 235 | + dest.clear(); | |
| 236 | + return 3; | |
| 237 | + } | |
| 238 | + | |
| 239 | + /// Makes the texture coordinates returns the number of values per vertex | |
| 240 | + template <typename T> | |
| 241 | + GLuint TexCoordinates(std::vector<T>& dest) const { | |
| 242 | + dest.clear(); | |
| 243 | + dest.insert(dest.begin(), _tex_data.begin(), _tex_data.end()); | |
| 244 | + return 2; | |
| 245 | + } | |
| 246 | + | |
| 247 | + typedef VertexAttribsInfo< | |
| 248 | + SphereSection, | |
| 249 | + std::tuple< | |
| 250 | + VertexPositionsTag, | |
| 251 | + VertexNormalsTag, | |
| 252 | + VertexTangentsTag, | |
| 253 | + VertexBitangentsTag, | |
| 254 | + VertexTexCoordinatesTag | |
| 255 | + > | |
| 256 | + > VertexAttribs; | |
| 257 | + | |
| 258 | + Spheref MakeBoundingSphere(void) const { | |
| 259 | + GLfloat min_x = _pos_data[3], max_x = _pos_data[3]; | |
| 260 | + GLfloat min_y = _pos_data[4], max_y = _pos_data[4]; | |
| 261 | + GLfloat min_z = _pos_data[5], max_z = _pos_data[5]; | |
| 262 | + for (std::size_t v = 0, vn = _pos_data.size() / 3; v != vn; ++v) { | |
| 263 | + GLfloat x = _pos_data[v * 3 + 0]; | |
| 264 | + GLfloat y = _pos_data[v * 3 + 1]; | |
| 265 | + GLfloat z = _pos_data[v * 3 + 2]; | |
| 266 | + | |
| 267 | + if (min_x > x) min_x = x; | |
| 268 | + if (min_y > y) min_y = y; | |
| 269 | + if (min_z > z) min_z = z; | |
| 270 | + if (max_x < x) max_x = x; | |
| 271 | + if (max_y < y) max_y = y; | |
| 272 | + if (max_z < z) max_z = z; | |
| 273 | + } | |
| 274 | + | |
| 275 | + Vec3f c( | |
| 276 | + (min_x + max_x) * 0.5f, | |
| 277 | + (min_y + max_y) * 0.5f, | |
| 278 | + (min_z + max_z) * 0.5f | |
| 279 | + ); | |
| 280 | + | |
| 281 | + return Spheref( | |
| 282 | + c.x(), c.y(), c.z(), | |
| 283 | + Distance(c, Vec3f(min_x, min_y, min_z)) | |
| 284 | + ); | |
| 285 | + } | |
| 286 | + | |
| 287 | + /// Queries the bounding sphere coordinates and dimensions | |
| 288 | + template <typename T> | |
| 289 | + void BoundingSphere(oglplus::Sphere<T>& bounding_sphere) const { | |
| 290 | + bounding_sphere = oglplus::Sphere<T>(MakeBoundingSphere()); | |
| 291 | + } | |
| 292 | + | |
| 293 | + | |
| 294 | + /// Returns element indices that are used with the drawing instructions | |
| 295 | + const IndexArray & Indices(Default = Default()) const { | |
| 296 | + return _idx_data; | |
| 297 | + } | |
| 298 | + | |
| 299 | + /// Returns the instructions for rendering of faces | |
| 300 | + DrawingInstructions Instructions(PrimitiveType primitive) const { | |
| 301 | + DrawingInstructions instr = this->MakeInstructions(); | |
| 302 | + DrawOperation operation; | |
| 303 | + operation.method = DrawOperation::Method::DrawElements; | |
| 304 | + operation.mode = primitive; | |
| 305 | + operation.first = 0; | |
| 306 | + operation.count = _prim_count * 3; | |
| 307 | + operation.restart_index = DrawOperation::NoRestartIndex(); | |
| 308 | + operation.phase = 0; | |
| 309 | + this->AddInstruction(instr, operation); | |
| 310 | + return std::move(instr); | |
| 311 | + } | |
| 312 | + | |
| 313 | + /// Returns the instructions for rendering of faces | |
| 314 | + DrawingInstructions Instructions(Default = Default()) const { | |
| 315 | + return Instructions(PrimitiveType::Triangles); | |
| 316 | + } | |
| 317 | +}; | |
| 318 | + | |
| 319 | +ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov, float aspect, int slices, int stacks) { | |
| 320 | + using namespace oglplus; | |
| 321 | + return ShapeWrapperPtr( | |
| 322 | + new shapes::ShapeWrapper({ "Position", "TexCoord" }, SphereSection(fov, aspect, slices, stacks), *program) | |
| 323 | + ); | |
| 324 | +} | |
| 325 | +#endif | |
| @@ -0,0 +1,173 @@ | ||
| 1 | +// | |
| 2 | +// Created by Bradley Austin Davis on 2015/05/26 | |
| 3 | +// Copyright 2015 High Fidelity, Inc. | |
| 4 | +// | |
| 5 | +// Distributed under the Apache License, Version 2.0. | |
| 6 | +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 7 | +// | |
| 8 | +#pragma once | |
| 9 | + | |
| 10 | +// FIXME support oglplus on all platforms | |
| 11 | +// For now it's a convenient helper for Windows | |
| 12 | + | |
| 13 | +#include <QtGlobal> | |
| 14 | + | |
| 15 | +#ifdef Q_OS_WIN | |
| 16 | +#include "GLMHelpers.h" | |
| 17 | + | |
| 18 | +#define OGLPLUS_USE_GLCOREARB_H 0 | |
| 19 | + | |
| 20 | +#if defined(__APPLE__) | |
| 21 | + | |
| 22 | +#define OGLPLUS_USE_GL3_H 1 | |
| 23 | + | |
| 24 | +#elif defined(WIN32) | |
| 25 | + | |
| 26 | +#define OGLPLUS_USE_GLEW 1 | |
| 27 | +#pragma warning(disable : 4068) | |
| 28 | + | |
| 29 | +#elif defined(ANDROID) | |
| 30 | + | |
| 31 | +#else | |
| 32 | + | |
| 33 | +#define OGLPLUS_USE_GLCOREARB_H 1 | |
| 34 | + | |
| 35 | +#endif | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | +#define OGLPLUS_USE_BOOST_CONFIG 1 | |
| 40 | +#define OGLPLUS_NO_SITE_CONFIG 1 | |
| 41 | +#define OGLPLUS_LOW_PROFILE 1 | |
| 42 | +#include <oglplus/gl.hpp> | |
| 43 | + | |
| 44 | +#include <oglplus/all.hpp> | |
| 45 | +#include <oglplus/interop/glm.hpp> | |
| 46 | +#include <oglplus/bound/texture.hpp> | |
| 47 | +#include <oglplus/bound/framebuffer.hpp> | |
| 48 | +#include <oglplus/bound/renderbuffer.hpp> | |
| 49 | +#include <oglplus/shapes/wrapper.hpp> | |
| 50 | +#include <oglplus/shapes/plane.hpp> | |
| 51 | + | |
| 52 | +#include "NumericalConstants.h" | |
| 53 | + | |
| 54 | +using FramebufferPtr = std::shared_ptr<oglplus::Framebuffer>; | |
| 55 | +using ShapeWrapperPtr = std::shared_ptr<oglplus::shapes::ShapeWrapper>; | |
| 56 | +using BufferPtr = std::shared_ptr<oglplus::Buffer>; | |
| 57 | +using VertexArrayPtr = std::shared_ptr<oglplus::VertexArray>; | |
| 58 | +using ProgramPtr = std::shared_ptr<oglplus::Program>; | |
| 59 | +using Mat4Uniform = oglplus::Uniform<mat4>; | |
| 60 | + | |
| 61 | +ProgramPtr loadDefaultShader(); | |
| 62 | +void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs); | |
| 63 | +ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect = 1.0f); | |
| 64 | +ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov = PI / 3.0f * 2.0f, float aspect = 16.0f / 9.0f, int slices = 32, int stacks = 32); | |
| 65 | + | |
| 66 | + | |
| 67 | +// A basic wrapper for constructing a framebuffer with a renderbuffer | |
| 68 | +// for the depth attachment and an undefined type for the color attachement | |
| 69 | +// This allows us to reuse the basic framebuffer code for both the Mirror | |
| 70 | +// FBO as well as the Oculus swap textures we will use to render the scene | |
| 71 | +// Though we don't really need depth at all for the mirror FBO, or even an | |
| 72 | +// FBO, but using one means I can just use a glBlitFramebuffer to get it onto | |
| 73 | +// the screen. | |
| 74 | +template < | |
| 75 | + typename C, | |
| 76 | + typename D | |
| 77 | +> | |
| 78 | +struct FramebufferWrapper { | |
| 79 | + uvec2 size; | |
| 80 | + oglplus::Framebuffer fbo; | |
| 81 | + C color; | |
| 82 | + D depth; | |
| 83 | + | |
| 84 | + FramebufferWrapper() {} | |
| 85 | + | |
| 86 | + virtual ~FramebufferWrapper() { | |
| 87 | + } | |
| 88 | + | |
| 89 | + virtual void Init(const uvec2 & size) { | |
| 90 | + this->size = size; | |
| 91 | + initColor(); | |
| 92 | + initDepth(); | |
| 93 | + initDone(); | |
| 94 | + } | |
| 95 | + | |
| 96 | + template <typename F> | |
| 97 | + void Bound(F f) { | |
| 98 | + Bound(oglplus::Framebuffer::Target::Draw, f); | |
| 99 | + } | |
| 100 | + | |
| 101 | + template <typename F> | |
| 102 | + void Bound(oglplus::Framebuffer::Target target , F f) { | |
| 103 | + fbo.Bind(target); | |
| 104 | + onBind(target); | |
| 105 | + f(); | |
| 106 | + onUnbind(target); | |
| 107 | + oglplus::DefaultFramebuffer().Bind(target); | |
| 108 | + } | |
| 109 | + | |
| 110 | + void Viewport() { | |
| 111 | + oglplus::Context::Viewport(size.x, size.y); | |
| 112 | + } | |
| 113 | + | |
| 114 | +protected: | |
| 115 | + virtual void onBind(oglplus::Framebuffer::Target target) {} | |
| 116 | + virtual void onUnbind(oglplus::Framebuffer::Target target) {} | |
| 117 | + | |
| 118 | + static GLenum toEnum(oglplus::Framebuffer::Target target) { | |
| 119 | + switch (target) { | |
| 120 | + case oglplus::Framebuffer::Target::Draw: | |
| 121 | + return GL_DRAW_FRAMEBUFFER; | |
| 122 | + case oglplus::Framebuffer::Target::Read: | |
| 123 | + return GL_READ_FRAMEBUFFER; | |
| 124 | + default: | |
| 125 | + Q_ASSERT(false); | |
| 126 | + return GL_FRAMEBUFFER; | |
| 127 | + } | |
| 128 | + } | |
| 129 | + | |
| 130 | + virtual void initDepth() {} | |
| 131 | + | |
| 132 | + virtual void initColor() {} | |
| 133 | + | |
| 134 | + virtual void initDone() = 0; | |
| 135 | +}; | |
| 136 | + | |
| 137 | +struct BasicFramebufferWrapper : public FramebufferWrapper <oglplus::Texture, oglplus::Renderbuffer> { | |
| 138 | +protected: | |
| 139 | + virtual void initDepth() override { | |
| 140 | + using namespace oglplus; | |
| 141 | + Context::Bound(Renderbuffer::Target::Renderbuffer, depth) | |
| 142 | + .Storage( | |
| 143 | + PixelDataInternalFormat::DepthComponent, | |
| 144 | + size.x, size.y); | |
| 145 | + } | |
| 146 | + | |
| 147 | + virtual void initColor() override { | |
| 148 | + using namespace oglplus; | |
| 149 | + Context::Bound(oglplus::Texture::Target::_2D, color) | |
| 150 | + .MinFilter(TextureMinFilter::Linear) | |
| 151 | + .MagFilter(TextureMagFilter::Linear) | |
| 152 | + .WrapS(TextureWrap::ClampToEdge) | |
| 153 | + .WrapT(TextureWrap::ClampToEdge) | |
| 154 | + .Image2D( | |
| 155 | + 0, PixelDataInternalFormat::RGBA8, | |
| 156 | + size.x, size.y, | |
| 157 | + 0, PixelDataFormat::RGB, PixelDataType::UnsignedByte, nullptr | |
| 158 | + ); | |
| 159 | + } | |
| 160 | + | |
| 161 | + virtual void initDone() override { | |
| 162 | + using namespace oglplus; | |
| 163 | + static const Framebuffer::Target target = Framebuffer::Target::Draw; | |
| 164 | + Bound(target, [&] { | |
| 165 | + fbo.AttachTexture(target, FramebufferAttachment::Color, color, 0); | |
| 166 | + fbo.AttachRenderbuffer(target, FramebufferAttachment::Depth, depth); | |
| 167 | + fbo.Complete(target); | |
| 168 | + }); | |
| 169 | + } | |
| 170 | +}; | |
| 171 | + | |
| 172 | +using BasicFramebufferWrapperPtr = std::shared_ptr<BasicFramebufferWrapper>; | |
| 173 | +#endif | |
| @@ -12,22 +12,31 @@ · 11 unmodified lines | ||
| 12 | 12 | #ifndef hifi_ProgramObject_h |
| 13 | 13 | #define hifi_ProgramObject_h |
| 14 | 14 | |
| 15 | +#ifdef __GNUC__ | |
| 16 | +#pragma GCC diagnostic push | |
| 17 | +#pragma GCC diagnostic ignored "-Wdouble-promotion" | |
| 18 | +#endif | |
| 19 | + | |
| 15 | 20 | #include <QGLShaderProgram> |
| 16 | 21 | |
| 22 | +#ifdef __GNUC__ | |
| 23 | +#pragma GCC diagnostic pop | |
| 24 | +#endif | |
| 25 | + | |
| 17 | 26 | #include <glm/glm.hpp> |
| 18 | 27 | |
| 19 | 28 | class ProgramObject : public QGLShaderProgram { |
| 20 | 29 | public: |
| 21 | − | |
| 30 | + | |
| 22 | 31 | ProgramObject(QObject* parent = 0); |
| 23 | − | |
| 32 | + | |
| 24 | 33 | void setUniform(int location, const glm::vec2& value); |
| 25 | 34 | void setUniform(const char* name, const glm::vec2& value); |
| 26 | 35 | void setUniform(int location, const glm::vec3& value); |
| 27 | 36 | void setUniform(const char* name, const glm::vec3& value); |
| 28 | 37 | void setUniform(int location, const glm::vec4& value); |
| 29 | 38 | void setUniform(const char* name, const glm::vec4& value); |
| 30 | − void setUniformArray(const char* name, const glm::vec3* values, int count); | |
| 39 | + void setUniformArray(const char* name, const glm::vec3* values, int count); | |
| 31 | 40 | }; |
| 32 | 41 | |
| 33 | 42 | #endif // hifi_ProgramObject_h |
| @@ -19,42 +19,54 @@ · 18 unmodified lines | ||
| 19 | 19 | |
| 20 | 20 | #include <PerfStat.h> |
| 21 | 21 | |
| 22 | −#include "overlay3D_vert.h" | |
| 22 | +#include "overlay3D_vert.h" | |
| 23 | 23 | #include "overlay3D_frag.h" |
| 24 | 24 | |
| 25 | 25 | using namespace render; |
| 26 | 26 | |
| 27 | −template <> void render::jobRun(const PrepareDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 28 | − PerformanceTimer perfTimer("PrepareDeferred"); | |
| 29 | − DependencyManager::get<DeferredLightingEffect>()->prepare(); | |
| 27 | +void PrepareDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 28 | + DependencyManager::get<DeferredLightingEffect>()->prepare(renderContext->args); | |
| 30 | 29 | } |
| 31 | 30 | |
| 32 | −template <> void render::jobRun(const RenderDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 33 | − PerformanceTimer perfTimer("RenderDeferred"); | |
| 34 | − DependencyManager::get<DeferredLightingEffect>()->render(); | |
| 35 | −// renderContext->args->_context->syncCache(); | |
| 31 | +void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 32 | + DependencyManager::get<DeferredLightingEffect>()->render(renderContext->args); | |
| 36 | 33 | } |
| 37 | 34 | |
| 38 | −template <> void render::jobRun(const ResolveDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 35 | +void ResolveDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 39 | 36 | PerformanceTimer perfTimer("ResolveDeferred"); |
| 40 | 37 | DependencyManager::get<DeferredLightingEffect>()->copyBack(renderContext->args); |
| 41 | − renderContext->args->_context->syncCache(); | |
| 42 | − | |
| 43 | 38 | } |
| 44 | 39 | |
| 45 | − | |
| 46 | − | |
| 47 | 40 | RenderDeferredTask::RenderDeferredTask() : Task() { |
| 48 | − _jobs.push_back(Job(PrepareDeferred())); | |
| 49 | − _jobs.push_back(Job(DrawBackground())); | |
| 50 | − _jobs.push_back(Job(DrawOpaqueDeferred())); | |
| 51 | − _jobs.push_back(Job(DrawLight())); | |
| 52 | − _jobs.push_back(Job(ResetGLState())); | |
| 53 | − _jobs.push_back(Job(RenderDeferred())); | |
| 54 | − _jobs.push_back(Job(ResolveDeferred())); | |
| 55 | − _jobs.push_back(Job(DrawTransparentDeferred())); | |
| 56 | − _jobs.push_back(Job(DrawOverlay3D())); | |
| 57 | − _jobs.push_back(Job(ResetGLState())); | |
| 41 | + _jobs.push_back(Job(new PrepareDeferred::JobModel("PrepareDeferred"))); | |
| 42 | + _jobs.push_back(Job(new DrawBackground::JobModel("DrawBackground"))); | |
| 43 | + _jobs.push_back(Job(new FetchItems::JobModel("FetchOpaque", | |
| 44 | + FetchItems( | |
| 45 | + [] (const RenderContextPointer& context, int count) { | |
| 46 | + context->_numFeedOpaqueItems = count; | |
| 47 | + } | |
| 48 | + ) | |
| 49 | + ))); | |
| 50 | + _jobs.push_back(Job(new CullItems::JobModel("CullOpaque", _jobs.back().getOutput()))); | |
| 51 | + _jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortOpaque", _jobs.back().getOutput()))); | |
| 52 | + _jobs.push_back(Job(new DrawOpaqueDeferred::JobModel("DrawOpaqueDeferred", _jobs.back().getOutput()))); | |
| 53 | + _jobs.push_back(Job(new DrawLight::JobModel("DrawLight"))); | |
| 54 | + _jobs.push_back(Job(new ResetGLState::JobModel())); | |
| 55 | + _jobs.push_back(Job(new RenderDeferred::JobModel("RenderDeferred"))); | |
| 56 | + _jobs.push_back(Job(new ResolveDeferred::JobModel("ResolveDeferred"))); | |
| 57 | + _jobs.push_back(Job(new FetchItems::JobModel("FetchTransparent", | |
| 58 | + FetchItems( | |
| 59 | + ItemFilter::Builder::transparentShape().withoutLayered(), | |
| 60 | + [] (const RenderContextPointer& context, int count) { | |
| 61 | + context->_numFeedTransparentItems = count; | |
| 62 | + } | |
| 63 | + ) | |
| 64 | + ))); | |
| 65 | + _jobs.push_back(Job(new CullItems::JobModel("CullTransparent", _jobs.back().getOutput()))); | |
| 66 | + _jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false)))); | |
| 67 | + _jobs.push_back(Job(new DrawTransparentDeferred::JobModel("TransparentDeferred", _jobs.back().getOutput()))); | |
| 68 | + _jobs.push_back(Job(new DrawOverlay3D::JobModel("DrawOverlay3D"))); | |
| 69 | + _jobs.push_back(Job(new ResetGLState::JobModel())); | |
| 58 | 70 | } |
| 59 | 71 | |
| 60 | 72 | RenderDeferredTask::~RenderDeferredTask() { |
| @@ -80,181 +92,104 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend · 19 unmodified lines | ||
| 80 | 92 | } |
| 81 | 93 | }; |
| 82 | 94 | |
| 83 | − | |
| 84 | − | |
| 85 | −template <> void render::jobRun(const DrawOpaqueDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 86 | − PerformanceTimer perfTimer("DrawOpaqueDeferred"); | |
| 95 | +void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) { | |
| 87 | 96 | assert(renderContext->args); |
| 88 | 97 | assert(renderContext->args->_viewFrustum); |
| 89 | 98 | |
| 90 | − // render opaques | |
| 91 | − auto& scene = sceneContext->_scene; | |
| 92 | − auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape().withoutLayered()); | |
| 93 | − auto& renderDetails = renderContext->args->_details; | |
| 94 | − | |
| 95 | − ItemIDsBounds inItems; | |
| 96 | − inItems.reserve(items.size()); | |
| 97 | − for (auto id : items) { | |
| 98 | − inItems.emplace_back(ItemIDAndBounds(id)); | |
| 99 | − } | |
| 100 | − ItemIDsBounds& renderedItems = inItems; | |
| 101 | − | |
| 102 | − renderContext->_numFeedOpaqueItems = renderedItems.size(); | |
| 103 | − | |
| 104 | − ItemIDsBounds culledItems; | |
| 105 | − culledItems.reserve(inItems.size()); | |
| 106 | − if (renderContext->_cullOpaque) { | |
| 107 | − renderDetails.pointTo(RenderDetails::OPAQUE_ITEM); | |
| 108 | − cullItems(sceneContext, renderContext, renderedItems, culledItems); | |
| 109 | − renderDetails.pointTo(RenderDetails::OTHER_ITEM); | |
| 110 | − renderedItems = culledItems; | |
| 111 | − } | |
| 112 | − | |
| 113 | − renderContext->_numDrawnOpaqueItems = renderedItems.size(); | |
| 99 | + RenderArgs* args = renderContext->args; | |
| 100 | + gpu::Batch batch; | |
| 101 | + args->_batch = &batch; | |
| 114 | 102 | |
| 103 | + renderContext->_numDrawnOpaqueItems = inItems.size(); | |
| 115 | 104 | |
| 116 | − ItemIDsBounds sortedItems; | |
| 117 | − sortedItems.reserve(culledItems.size()); | |
| 118 | − if (renderContext->_sortOpaque) { | |
| 119 | − depthSortItems(sceneContext, renderContext, true, renderedItems, sortedItems); // Sort Front to back opaque items! | |
| 120 | − renderedItems = sortedItems; | |
| 105 | + glm::mat4 projMat; | |
| 106 | + Transform viewMat; | |
| 107 | + args->_viewFrustum->evalProjectionMatrix(projMat); | |
| 108 | + args->_viewFrustum->evalViewTransform(viewMat); | |
| 109 | + if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { | |
| 110 | + viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f)); | |
| 121 | 111 | } |
| 112 | + batch.setProjectionTransform(projMat); | |
| 113 | + batch.setViewTransform(viewMat); | |
| 122 | 114 | |
| 123 | − // ItemIDsBounds sortedItems; | |
| 124 | − /* ItemMaterialBucketMap stateSortedItems; | |
| 125 | − stateSortedItems.allocateStandardMaterialBuckets(); | |
| 126 | − if (true) { | |
| 127 | − for (auto& itemIDAndBound : renderedItems) { | |
| 128 | − stateSortedItems.insert(itemIDAndBound.id, scene->getItem(itemIDAndBound.id).getMaterialKey()); | |
| 129 | − } | |
| 115 | + { | |
| 116 | + GLenum buffers[3]; | |
| 117 | + int bufferCount = 0; | |
| 118 | + buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; | |
| 119 | + buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; | |
| 120 | + buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; | |
| 121 | + batch._glDrawBuffers(bufferCount, buffers); | |
| 122 | + const float OPAQUE_ALPHA_THRESHOLD = 0.5f; | |
| 123 | + args->_alphaThreshold = OPAQUE_ALPHA_THRESHOLD; | |
| 130 | 124 | } |
| 131 | −*/ | |
| 132 | − | |
| 133 | − if (renderContext->_renderOpaque) { | |
| 134 | − RenderArgs* args = renderContext->args; | |
| 135 | − gpu::Batch batch; | |
| 136 | − args->_batch = &batch; | |
| 137 | − | |
| 138 | − glm::mat4 projMat; | |
| 139 | − Transform viewMat; | |
| 140 | − args->_viewFrustum->evalProjectionMatrix(projMat); | |
| 141 | − args->_viewFrustum->evalViewTransform(viewMat); | |
| 142 | − if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { | |
| 143 | − viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f)); | |
| 144 | − } | |
| 145 | − batch.setProjectionTransform(projMat); | |
| 146 | − batch.setViewTransform(viewMat); | |
| 147 | − | |
| 148 | − { | |
| 149 | − GLenum buffers[3]; | |
| 150 | − int bufferCount = 0; | |
| 151 | − buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; | |
| 152 | − buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; | |
| 153 | − buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; | |
| 154 | − batch._glDrawBuffers(bufferCount, buffers); | |
| 155 | − } | |
| 156 | 125 | |
| 157 | − renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnOpaqueItems); | |
| 126 | + renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnOpaqueItems); | |
| 158 | 127 | |
| 159 | − args->_context->render((*args->_batch)); | |
| 160 | − args->_batch = nullptr; | |
| 161 | − } | |
| 128 | + // Before rendering the batch make sure we re in sync with gl state | |
| 129 | + args->_context->syncCache(); | |
| 130 | + renderContext->args->_context->syncCache(); | |
| 131 | + args->_context->render((*args->_batch)); | |
| 132 | + args->_batch = nullptr; | |
| 162 | 133 | } |
| 163 | 134 | |
| 164 | − | |
| 165 | −template <> void render::jobRun(const DrawTransparentDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 166 | − PerformanceTimer perfTimer("DrawTransparentDeferred"); | |
| 135 | +void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) { | |
| 167 | 136 | assert(renderContext->args); |
| 168 | 137 | assert(renderContext->args->_viewFrustum); |
| 169 | − | |
| 170 | − // render transparents | |
| 171 | − auto& scene = sceneContext->_scene; | |
| 172 | − auto& items = scene->getMasterBucket().at(ItemFilter::Builder::transparentShape().withoutLayered()); | |
| 173 | 138 | auto& renderDetails = renderContext->args->_details; |
| 174 | − | |
| 175 | − ItemIDsBounds inItems; | |
| 176 | − inItems.reserve(items.size()); | |
| 177 | − for (auto id : items) { | |
| 178 | − inItems.push_back(id); | |
| 179 | − } | |
| 180 | − ItemIDsBounds& renderedItems = inItems; | |
| 181 | 139 | |
| 182 | − renderContext->_numFeedTransparentItems = renderedItems.size(); | |
| 140 | + RenderArgs* args = renderContext->args; | |
| 141 | + gpu::Batch batch; | |
| 142 | + args->_batch = &batch; | |
| 143 | + | |
| 144 | + renderContext->_numDrawnTransparentItems = inItems.size(); | |
| 183 | 145 | |
| 184 | − ItemIDsBounds culledItems; | |
| 185 | − if (renderContext->_cullTransparent) { | |
| 186 | − renderDetails.pointTo(RenderDetails::TRANSLUCENT_ITEM); | |
| 187 | − cullItems(sceneContext, renderContext, inItems, culledItems); | |
| 188 | − renderDetails.pointTo(RenderDetails::OTHER_ITEM); | |
| 189 | − renderedItems = culledItems; | |
| 146 | + glm::mat4 projMat; | |
| 147 | + Transform viewMat; | |
| 148 | + args->_viewFrustum->evalProjectionMatrix(projMat); | |
| 149 | + args->_viewFrustum->evalViewTransform(viewMat); | |
| 150 | + if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { | |
| 151 | + viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f)); | |
| 190 | 152 | } |
| 153 | + batch.setProjectionTransform(projMat); | |
| 154 | + batch.setViewTransform(viewMat); | |
| 155 | + const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f; | |
| 191 | 156 | |
| 192 | − renderContext->_numDrawnTransparentItems = renderedItems.size(); | |
| 193 | − | |
| 194 | − ItemIDsBounds sortedItems; | |
| 195 | − if (renderContext->_sortTransparent) { | |
| 196 | − depthSortItems(sceneContext, renderContext, false, renderedItems, sortedItems); // Sort Back to front transparent items! | |
| 197 | − renderedItems = sortedItems; | |
| 157 | + { | |
| 158 | + GLenum buffers[3]; | |
| 159 | + int bufferCount = 0; | |
| 160 | + buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; | |
| 161 | + batch._glDrawBuffers(bufferCount, buffers); | |
| 162 | + args->_alphaThreshold = TRANSPARENT_ALPHA_THRESHOLD; | |
| 198 | 163 | } |
| 164 | + | |
| 165 | + | |
| 166 | + renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnTransparentItems); | |
| 167 | + | |
| 168 | + // Before rendering the batch make sure we re in sync with gl state | |
| 169 | + args->_context->syncCache(); | |
| 170 | + args->_context->render((*args->_batch)); | |
| 171 | + args->_batch = nullptr; | |
| 172 | + | |
| 173 | + // reset blend function to standard... | |
| 174 | + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 175 | +} | |
| 199 | 176 | |
| 200 | − if (renderContext->_renderTransparent) { | |
| 201 | − RenderArgs* args = renderContext->args; | |
| 202 | − gpu::Batch batch; | |
| 203 | − args->_batch = &batch; | |
| 204 | − | |
| 177 | +const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() const { | |
| 178 | + if (!_opaquePipeline) { | |
| 179 | + auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(overlay3D_vert))); | |
| 180 | + auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(overlay3D_frag))); | |
| 205 | 181 | |
| 182 | + auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); | |
| 206 | 183 | |
| 184 | + auto state = gpu::StatePointer(new gpu::State()); | |
| 185 | + state->setDepthTest(true, true, gpu::LESS_EQUAL); | |
| 207 | 186 | |
| 208 | − glm::mat4 projMat; | |
| 209 | − Transform viewMat; | |
| 210 | − args->_viewFrustum->evalProjectionMatrix(projMat); | |
| 211 | − args->_viewFrustum->evalViewTransform(viewMat); | |
| 212 | − if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { | |
| 213 | − viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f)); | |
| 214 | − } | |
| 215 | − batch.setProjectionTransform(projMat); | |
| 216 | − batch.setViewTransform(viewMat); | |
| 217 | − | |
| 218 | − const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f; | |
| 219 | − | |
| 220 | − { | |
| 221 | − GLenum buffers[3]; | |
| 222 | − int bufferCount = 0; | |
| 223 | − buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; | |
| 224 | − batch._glDrawBuffers(bufferCount, buffers); | |
| 225 | − args->_alphaThreshold = TRANSPARENT_ALPHA_THRESHOLD; | |
| 226 | − } | |
| 227 | − | |
| 228 | − | |
| 229 | − renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnTransparentItems); | |
| 230 | − | |
| 231 | − // Before rendering the batch make sure we re in sync with gl state | |
| 232 | − args->_context->syncCache(); | |
| 233 | − args->_context->render((*args->_batch)); | |
| 234 | − args->_batch = nullptr; | |
| 235 | − | |
| 236 | − // reset blend function to standard... | |
| 237 | − // glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 187 | + _opaquePipeline.reset(gpu::Pipeline::create(program, state)); | |
| 238 | 188 | } |
| 189 | + return _opaquePipeline; | |
| 239 | 190 | } |
| 240 | 191 | |
| 241 | −const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() const { | |
| 242 | − if (!_opaquePipeline) { | |
| 243 | − auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(overlay3D_vert))); | |
| 244 | − auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(overlay3D_frag))); | |
| 245 | − | |
| 246 | − auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); | |
| 247 | − | |
| 248 | − auto state = gpu::StatePointer(new gpu::State()); | |
| 249 | − state->setDepthTest(true, true, gpu::LESS_EQUAL); | |
| 250 | − | |
| 251 | − _opaquePipeline.reset(gpu::Pipeline::create(program, state)); | |
| 252 | − } | |
| 253 | − return _opaquePipeline; | |
| 254 | −} | |
| 255 | − | |
| 256 | −template <> void render::jobRun(const DrawOverlay3D& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 257 | − PerformanceTimer perfTimer("DrawOverlay3D"); | |
| 192 | +void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 258 | 193 | assert(renderContext->args); |
| 259 | 194 | assert(renderContext->args->_viewFrustum); |
| 260 | 195 | |
| @@ -271,13 +206,14 @@ template <> void render::jobRun(const DrawOverlay3D& job, const SceneContextPoin · 10 unmodified lines | ||
| 271 | 206 | inItems.emplace_back(id); |
| 272 | 207 | } |
| 273 | 208 | } |
| 274 | − | |
| 209 | + renderContext->_numFeedOverlay3DItems = inItems.size(); | |
| 210 | + renderContext->_numDrawnOverlay3DItems = inItems.size(); | |
| 211 | + | |
| 275 | 212 | RenderArgs* args = renderContext->args; |
| 276 | 213 | gpu::Batch batch; |
| 277 | 214 | args->_batch = &batch; |
| 278 | 215 | args->_whiteTexture = DependencyManager::get<TextureCache>()->getWhiteTexture(); |
| 279 | 216 | |
| 280 | − | |
| 281 | 217 | glm::mat4 projMat; |
| 282 | 218 | Transform viewMat; |
| 283 | 219 | args->_viewFrustum->evalProjectionMatrix(projMat); |
| @@ -287,12 +223,13 @@ template <> void render::jobRun(const DrawOverlay3D& job, const SceneContextPoin · 3 unmodified lines | ||
| 287 | 223 | } |
| 288 | 224 | batch.setProjectionTransform(projMat); |
| 289 | 225 | batch.setViewTransform(viewMat); |
| 290 | − batch.setPipeline(job.getOpaquePipeline()); | |
| 226 | + | |
| 227 | + batch.setPipeline(getOpaquePipeline()); | |
| 291 | 228 | batch.setUniformTexture(0, args->_whiteTexture); |
| 292 | 229 | |
| 293 | 230 | if (!inItems.empty()) { |
| 294 | − batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0); | |
| 295 | − renderItems(sceneContext, renderContext, inItems); | |
| 231 | + batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0); | |
| 232 | + renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnOverlay3DItems); | |
| 296 | 233 | } |
| 297 | 234 | |
| 298 | 235 | // Before rendering the batch make sure we re in sync with gl state |
| @@ -301,3 +238,4 @@ template <> void render::jobRun(const DrawOverlay3D& job, const SceneContextPoin · 2 unmodified lines | ||
| 301 | 238 | args->_batch = nullptr; |
| 302 | 239 | args->_whiteTexture.reset(); |
| 303 | 240 | } |
| 241 | + | |
| @@ -18,48 +18,49 @@ · 17 unmodified lines | ||
| 18 | 18 | |
| 19 | 19 | class PrepareDeferred { |
| 20 | 20 | public: |
| 21 | + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); | |
| 22 | + | |
| 23 | + typedef render::Job::Model<PrepareDeferred> JobModel; | |
| 21 | 24 | }; |
| 22 | −namespace render { | |
| 23 | −template <> void jobRun(const PrepareDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); | |
| 24 | −} | |
| 25 | + | |
| 25 | 26 | |
| 26 | 27 | class RenderDeferred { |
| 27 | 28 | public: |
| 29 | + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); | |
| 30 | + | |
| 31 | + typedef render::Job::Model<RenderDeferred> JobModel; | |
| 28 | 32 | }; |
| 29 | −namespace render { | |
| 30 | −template <> void jobRun(const RenderDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); | |
| 31 | −} | |
| 32 | 33 | |
| 33 | 34 | class ResolveDeferred { |
| 34 | 35 | public: |
| 35 | −}; | |
| 36 | −namespace render { | |
| 37 | −template <> void jobRun(const ResolveDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); | |
| 38 | −} | |
| 36 | + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); | |
| 39 | 37 | |
| 38 | + typedef render::Job::Model<ResolveDeferred> JobModel; | |
| 39 | +}; | |
| 40 | 40 | |
| 41 | 41 | class DrawOpaqueDeferred { |
| 42 | 42 | public: |
| 43 | + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems); | |
| 44 | + | |
| 45 | + typedef render::Job::ModelI<DrawOpaqueDeferred, render::ItemIDsBounds> JobModel; | |
| 43 | 46 | }; |
| 44 | −namespace render { | |
| 45 | −template <> void jobRun(const DrawOpaqueDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); | |
| 46 | −} | |
| 47 | 47 | |
| 48 | 48 | class DrawTransparentDeferred { |
| 49 | 49 | public: |
| 50 | + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems); | |
| 51 | + | |
| 52 | + typedef render::Job::ModelI<DrawTransparentDeferred, render::ItemIDsBounds> JobModel; | |
| 50 | 53 | }; |
| 51 | −namespace render { | |
| 52 | −template <> void jobRun(const DrawTransparentDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); | |
| 53 | −} | |
| 54 | − | |
| 55 | −class DrawOverlay3D { | |
| 56 | − mutable gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable | |
| 57 | −public: | |
| 58 | − const gpu::PipelinePointer& getOpaquePipeline() const; | |
| 54 | + | |
| 55 | +class DrawOverlay3D { | |
| 56 | + mutable gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable | |
| 57 | +public: | |
| 58 | + const gpu::PipelinePointer& getOpaquePipeline() const; | |
| 59 | + | |
| 60 | + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); | |
| 61 | + | |
| 62 | + typedef render::Job::Model<DrawOverlay3D> JobModel; | |
| 59 | 63 | }; |
| 60 | −namespace render { | |
| 61 | −template <> void jobRun(const DrawOverlay3D& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); | |
| 62 | −} | |
| 63 | 64 | |
| 64 | 65 | class RenderDeferredTask : public render::Task { |
| 65 | 66 | public: |
| @@ -18,12 +18,21 @@ · 17 unmodified lines | ||
| 18 | 18 | #include <QBuffer> |
| 19 | 19 | #include <QFile> |
| 20 | 20 | |
| 21 | +#ifdef __GNUC__ | |
| 22 | +#pragma GCC diagnostic push | |
| 23 | +#pragma GCC diagnostic ignored "-Wdouble-promotion" | |
| 24 | +#endif | |
| 25 | + | |
| 21 | 26 | // FIXME, decouple from the GL headers |
| 22 | 27 | #include <QOpenGLShaderProgram> |
| 23 | 28 | #include <QOpenGLTexture> |
| 24 | 29 | #include <QOpenGLVertexArrayObject> |
| 25 | 30 | #include <QOpenGLBuffer> |
| 26 | 31 | |
| 32 | +#ifdef __GNUC__ | |
| 33 | +#pragma GCC diagnostic pop | |
| 34 | +#endif | |
| 35 | + | |
| 27 | 36 | #include <glm/glm.hpp> |
| 28 | 37 | #include <glm/gtc/matrix_transform.hpp> |
| 29 | 38 | |
| @@ -30,11 +30,6 @@ · 29 unmodified lines | ||
| 30 | 30 | #include "GeometryCache.h" |
| 31 | 31 | #include "DeferredLightingEffect.h" |
| 32 | 32 | |
| 33 | −// FIXME support the shadow effect, or remove it from the API | |
| 34 | −// FIXME figure out how to improve the anti-aliasing on the | |
| 35 | −// interior of the outline fonts | |
| 36 | −const float DEFAULT_POINT_SIZE = 12; | |
| 37 | − | |
| 38 | 33 | // Helper functions for reading binary data from an IO device |
| 39 | 34 | template<class T> |
| 40 | 35 | void readStream(QIODevice& in, T& t) { |
| @@ -117,7 +112,7 @@ public: · 76 unmodified lines | ||
| 117 | 112 | |
| 118 | 113 | // Render string to batch |
| 119 | 114 | void drawString(gpu::Batch& batch, float x, float y, const QString& str, |
| 120 | − const glm::vec4& color, TextRenderer3D::EffectType effectType, | |
| 115 | + const glm::vec4* color, TextRenderer3D::EffectType effectType, | |
| 121 | 116 | const glm::vec2& bound); |
| 122 | 117 | |
| 123 | 118 | private: |
| @@ -367,7 +362,7 @@ void Font3D::setupGPU() { · 243 unmodified lines | ||
| 367 | 362 | } |
| 368 | 363 | } |
| 369 | 364 | |
| 370 | −void Font3D::drawString(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4& color, | |
| 365 | +void Font3D::drawString(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4* color, | |
| 371 | 366 | TextRenderer3D::EffectType effectType, const glm::vec2& bounds) { |
| 372 | 367 | if (str == "") { |
| 373 | 368 | return; |
| @@ -429,40 +424,33 @@ void Font3D::drawString(gpu::Batch& batch, float x, float y, const QString& str, · 55 unmodified lines | ||
| 429 | 424 | setupGPU(); |
| 430 | 425 | batch.setPipeline(_pipeline); |
| 431 | 426 | batch.setUniformTexture(_fontLoc, _texture); |
| 432 | − batch._glUniform1f(_outlineLoc, (effectType == TextRenderer3D::OUTLINE_EFFECT) ? 1.0f : 0.0f); | |
| 433 | − batch._glUniform4fv(_colorLoc, 1, (const GLfloat*)&color); | |
| 427 | + batch._glUniform1i(_outlineLoc, (effectType == TextRenderer3D::OUTLINE_EFFECT)); | |
| 428 | + batch._glUniform4fv(_colorLoc, 1, (const GLfloat*)color); | |
| 434 | 429 | |
| 435 | 430 | batch.setInputFormat(_format); |
| 436 | 431 | batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride); |
| 437 | 432 | batch.draw(gpu::QUADS, _numVertices, 0); |
| 438 | 433 | } |
| 439 | 434 | |
| 440 | −TextRenderer3D* TextRenderer3D::getInstance(const char* family, float pointSize, | |
| 441 | − int weight, bool italic, EffectType effect, int effectThickness, | |
| 442 | − const QColor& color) { | |
| 443 | − if (pointSize < 0) { | |
| 444 | − pointSize = DEFAULT_POINT_SIZE; | |
| 445 | − } | |
| 446 | − return new TextRenderer3D(family, pointSize, weight, italic, effect, | |
| 447 | − effectThickness, color); | |
| 435 | +TextRenderer3D* TextRenderer3D::getInstance(const char* family, | |
| 436 | + int weight, bool italic, EffectType effect, int effectThickness) { | |
| 437 | + return new TextRenderer3D(family, weight, italic, effect, effectThickness); | |
| 448 | 438 | } |
| 449 | 439 | |
| 450 | −TextRenderer3D::TextRenderer3D(const char* family, float pointSize, int weight, bool italic, | |
| 451 | − EffectType effect, int effectThickness, const QColor& color) : | |
| 440 | +TextRenderer3D::TextRenderer3D(const char* family, int weight, bool italic, | |
| 441 | + EffectType effect, int effectThickness) : | |
| 452 | 442 | _effectType(effect), |
| 453 | 443 | _effectThickness(effectThickness), |
| 454 | − _pointSize(pointSize), | |
| 455 | − _color(toGlm(color)), | |
| 456 | 444 | _font(loadFont3D(family)) { |
| 457 | 445 | if (!_font) { |
| 458 | 446 | qWarning() << "Unable to load font with family " << family; |
| 459 | 447 | _font = loadFont3D("Courier"); |
| 460 | 448 | } |
| 461 | 449 | if (1 != _effectThickness) { |
| 462 | − qWarning() << "Effect thickness not current supported"; | |
| 450 | + qWarning() << "Effect thickness not currently supported"; | |
| 463 | 451 | } |
| 464 | 452 | if (NO_EFFECT != _effectType && OUTLINE_EFFECT != _effectType) { |
| 465 | − qWarning() << "Effect thickness not current supported"; | |
| 453 | + qWarning() << "Effect type not currently supported"; | |
| 466 | 454 | } |
| 467 | 455 | } |
| 468 | 456 | |
| @@ -487,11 +475,9 @@ void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const QString& st · 18 unmodified lines | ||
| 487 | 475 | const glm::vec2& bounds) { |
| 488 | 476 | // The font does all the OpenGL work |
| 489 | 477 | if (_font) { |
| 490 | − glm::vec4 actualColor(color); | |
| 491 | − if (actualColor.r < 0) { | |
| 492 | − actualColor = _color; | |
| 493 | − } | |
| 494 | − _font->drawString(batch, x, y, str, actualColor, _effectType, bounds); | |
| 478 | + // Cache color so that the pointer stays valid. | |
| 479 | + _color = color; | |
| 480 | + _font->drawString(batch, x, y, str, &_color, _effectType, bounds); | |
| 495 | 481 | } |
| 496 | 482 | } |
| 497 | 483 | |
| @@ -39,25 +39,24 @@ class Batch; · 38 unmodified lines | ||
| 39 | 39 | class Font3D; |
| 40 | 40 | |
| 41 | 41 | // TextRenderer3D is actually a fairly thin wrapper around a Font class |
| 42 | −// defined in the cpp file. | |
| 42 | +// defined in the cpp file. | |
| 43 | 43 | class TextRenderer3D { |
| 44 | 44 | public: |
| 45 | 45 | enum EffectType { NO_EFFECT, SHADOW_EFFECT, OUTLINE_EFFECT }; |
| 46 | 46 | |
| 47 | − static TextRenderer3D* getInstance(const char* family, float pointSize = -1, int weight = -1, bool italic = false, | |
| 48 | − EffectType effect = NO_EFFECT, int effectThickness = 1, const QColor& color = QColor(255, 255, 255)); | |
| 49 | − | |
| 47 | + static TextRenderer3D* getInstance(const char* family, int weight = -1, bool italic = false, | |
| 48 | + EffectType effect = NO_EFFECT, int effectThickness = 1); | |
| 50 | 49 | ~TextRenderer3D(); |
| 51 | 50 | |
| 52 | 51 | glm::vec2 computeExtent(const QString& str) const; |
| 53 | − float getFontSize() const; | |
| 52 | + float getFontSize() const; // Pixel size | |
| 54 | 53 | |
| 55 | − void draw(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4& color = glm::vec4(-1.0f), | |
| 56 | − const glm::vec2& bounds = glm::vec2(-1.0f)); | |
| 54 | + void draw(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4& color = glm::vec4(1.0f), | |
| 55 | + const glm::vec2& bounds = glm::vec2(-1.0f)); | |
| 57 | 56 | |
| 58 | 57 | private: |
| 59 | − TextRenderer3D(const char* family, float pointSize = -1, int weight = -1, bool italic = false, | |
| 60 | − EffectType effect = NO_EFFECT, int effectThickness = 1, const QColor& color = QColor(255, 255, 255)); | |
| 58 | + TextRenderer3D(const char* family, int weight = -1, bool italic = false, | |
| 59 | + EffectType effect = NO_EFFECT, int effectThickness = 1); | |
| 61 | 60 | |
| 62 | 61 | // the type of effect to apply |
| 63 | 62 | const EffectType _effectType; |
| @@ -65,10 +64,8 @@ private: · 1 unmodified line | ||
| 65 | 64 | // the thickness of the effect |
| 66 | 65 | const int _effectThickness; |
| 67 | 66 | |
| 68 | − const float _pointSize; | |
| 69 | − | |
| 70 | 67 | // text color |
| 71 | − const glm::vec4 _color; | |
| 68 | + glm::vec4 _color; | |
| 72 | 69 | |
| 73 | 70 | Font3D* _font; |
| 74 | 71 | }; |
| @@ -11,18 +11,21 @@ · 10 unmodified lines | ||
| 11 | 11 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html |
| 12 | 12 | |
| 13 | 13 | uniform sampler2D Font; |
| 14 | −uniform float Outline; | |
| 14 | +uniform bool Outline; | |
| 15 | 15 | uniform vec4 Color; |
| 16 | 16 | |
| 17 | −const float gamma = 2.6; | |
| 18 | −const float smoothing = 100.0; | |
| 17 | +// the interpolated normal | |
| 18 | +varying vec4 interpolatedNormal; | |
| 19 | + | |
| 20 | +const float gamma = 2.2; | |
| 21 | +const float smoothing = 64.0; | |
| 19 | 22 | const float interiorCutoff = 0.8; |
| 20 | 23 | const float outlineExpansion = 0.2; |
| 21 | 24 | |
| 22 | 25 | void main() { |
| 23 | 26 | // retrieve signed distance |
| 24 | 27 | float sdf = texture2D(Font, gl_TexCoord[0].xy).g; |
| 25 | − if (Outline == 1.0f) { | |
| 28 | + if (Outline) { | |
| 26 | 29 | if (sdf > interiorCutoff) { |
| 27 | 30 | sdf = 1.0 - sdf; |
| 28 | 31 | } else { |
| @@ -31,7 +34,7 @@ void main() { · 2 unmodified lines | ||
| 31 | 34 | } |
| 32 | 35 | // perform adaptive anti-aliasing of the edges |
| 33 | 36 | // The larger we're rendering, the less anti-aliasing we need |
| 34 | − float s = smoothing * length(fwidth(gl_TexCoord[0])); | |
| 37 | + float s = smoothing * length(fwidth(gl_TexCoord[0].xy)); | |
| 35 | 38 | float w = clamp( s, 0.0, 0.5); |
| 36 | 39 | float a = smoothstep(0.5 - w, 0.5 + w, sdf); |
| 37 | 40 | |
| @@ -43,5 +46,7 @@ void main() { · 5 unmodified lines | ||
| 43 | 46 | } |
| 44 | 47 | |
| 45 | 48 | // final color |
| 46 | − gl_FragColor = vec4(Color.rgb, a); | |
| 49 | + gl_FragData[0] = vec4(Color.rgb, Color.a * a); | |
| 50 | + gl_FragData[1] = vec4(interpolatedNormal.xyz, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0); | |
| 51 | + gl_FragData[2] = vec4(0.0); | |
| 47 | 52 | } |
| @@ -13,6 +13,9 @@ · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | <$declareStandardTransform()$> |
| 15 | 15 | |
| 16 | +// the interpolated normal | |
| 17 | +varying vec4 interpolatedNormal; | |
| 18 | + | |
| 16 | 19 | void main() { |
| 17 | 20 | gl_TexCoord[0] = gl_MultiTexCoord0; |
| 18 | 21 | |
| @@ -20,4 +23,7 @@ void main() { · 1 unmodified line | ||
| 20 | 23 | TransformCamera cam = getTransformCamera(); |
| 21 | 24 | TransformObject obj = getTransformObject(); |
| 22 | 25 | <$transformModelToClipPos(cam, obj, gl_Vertex, gl_Position)$> |
| 26 | + <$transformModelToEyeDir(cam, obj, gl_Normal, interpolatedNormal.xyz)$> | |
| 27 | + | |
| 28 | + interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0); | |
| 23 | 29 | } |
| @@ -0,0 +1,24 @@ | ||
| 1 | +<@include gpu/Config.slh@> | |
| 2 | +<$VERSION_HEADER$> | |
| 3 | +// Generated on <$_SCRIBE_DATE$> | |
| 4 | +// standardDrawTexture.frag | |
| 5 | +// fragment shader | |
| 6 | +// | |
| 7 | +// Created by Sam Gateau on 6/10/15. | |
| 8 | +// Copyright 2015 High Fidelity, Inc. | |
| 9 | +// | |
| 10 | +// Distributed under the Apache License, Version 2.0. | |
| 11 | +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 12 | +// | |
| 13 | + | |
| 14 | +// the texture | |
| 15 | +uniform sampler2D colorMap; | |
| 16 | + | |
| 17 | +varying vec2 varTexcoord; | |
| 18 | +varying vec4 varColor; | |
| 19 | + | |
| 20 | + | |
| 21 | +void main(void) { | |
| 22 | + vec4 color = texture2D(colorMap, varTexcoord); | |
| 23 | + gl_FragColor = color * varColor; | |
| 24 | +} | |
| @@ -0,0 +1,35 @@ | ||
| 1 | +<@include gpu/Config.slh@> | |
| 2 | +<$VERSION_HEADER$> | |
| 3 | +// Generated on <$_SCRIBE_DATE$> | |
| 4 | +// | |
| 5 | +// standardTransformPNTC.slv | |
| 6 | +// vertex shader | |
| 7 | +// | |
| 8 | +// Created by Sam Gateau on 6/10/2015. | |
| 9 | +// Copyright 2015 High Fidelity, Inc. | |
| 10 | +// | |
| 11 | +// Distributed under the Apache License, Version 2.0. | |
| 12 | +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 13 | +// | |
| 14 | + | |
| 15 | +<@include gpu/Transform.slh@> | |
| 16 | + | |
| 17 | +<$declareStandardTransform()$> | |
| 18 | + | |
| 19 | +varying vec3 varPosition; | |
| 20 | +varying vec3 varNormal; | |
| 21 | +varying vec2 varTexcoord; | |
| 22 | +varying vec4 varColor; | |
| 23 | + | |
| 24 | +void main(void) { | |
| 25 | + varTexcoord = gl_MultiTexCoord0.xy; | |
| 26 | + varColor = gl_Color; | |
| 27 | + | |
| 28 | + // standard transform | |
| 29 | + TransformCamera cam = getTransformCamera(); | |
| 30 | + TransformObject obj = getTransformObject(); | |
| 31 | + <$transformModelToClipPos(cam, obj, gl_Vertex, gl_Position)$> | |
| 32 | + <$transformModelToEyeDir(cam, obj, gl_Normal, varNormal)$> | |
| 33 | + varNormal = normalize(varNormal); | |
| 34 | + varPosition = gl_Vertex.xyz; | |
| 35 | +} | |
| @@ -0,0 +1,76 @@ | ||
| 1 | +<@include gpu/Config.slh@> | |
| 2 | +<$VERSION_HEADER$> | |
| 3 | +// Generated on <$_SCRIBE_DATE$> | |
| 4 | +// stars.frag | |
| 5 | +// fragment shader | |
| 6 | +// | |
| 7 | +// Created by Bradley Austin Davis on 2015/06/19 | |
| 8 | + | |
| 9 | +varying vec2 varTexcoord; | |
| 10 | +varying vec3 varNomral; | |
| 11 | +varying vec3 varPosition; | |
| 12 | + | |
| 13 | + | |
| 14 | +const int star_iterations = 14; | |
| 15 | +const float time_scale = 0.2; | |
| 16 | +const vec3 col_star = vec3( 1.0, 0.7, 0.5 ); | |
| 17 | + | |
| 18 | +float hash( float n ) { return fract(sin(n)*123.456789); } | |
| 19 | + | |
| 20 | +vec2 rotate( in vec2 uv, float a) | |
| 21 | +{ | |
| 22 | + float c = cos( a ); | |
| 23 | + float s = sin( a ); | |
| 24 | + return vec2( c * uv.x - s * uv.y, s * uv.x + c * uv.y ); | |
| 25 | +} | |
| 26 | + | |
| 27 | +float noise( in vec3 p ) | |
| 28 | +{ | |
| 29 | + vec3 fl = floor( p ); | |
| 30 | + vec3 fr = fract( p ); | |
| 31 | + fr = fr * fr * ( 3.0 - 2.0 * fr ); | |
| 32 | + | |
| 33 | + float n = fl.x + fl.y * 157.0 + 113.0 * fl.z; | |
| 34 | + return mix( mix( mix( hash( n + 0.0), hash( n + 1.0 ), fr.x ), | |
| 35 | + mix( hash( n + 157.0), hash( n + 158.0 ), fr.x ), fr.y ), | |
| 36 | + mix( mix( hash( n + 113.0), hash( n + 114.0 ), fr.x ), | |
| 37 | + mix( hash( n + 270.0), hash( n + 271.0 ), fr.x ), fr.y ), fr.z ); | |
| 38 | +} | |
| 39 | + | |
| 40 | +float fbm( in vec2 p, float t ) | |
| 41 | +{ | |
| 42 | + float f; | |
| 43 | + f = 0.5000 * noise( vec3( p, t ) ); p *= 2.1; | |
| 44 | + f += 0.2500 * noise( vec3( p, t ) ); p *= 2.2; | |
| 45 | + f += 0.1250 * noise( vec3( p, t ) ); p *= 2.3; | |
| 46 | + f += 0.0625 * noise( vec3( p, t ) ); | |
| 47 | + return f; | |
| 48 | +} | |
| 49 | + | |
| 50 | +vec3 doBackgroundStars( in vec3 dir ) | |
| 51 | +{ | |
| 52 | + vec3 n = abs( dir ); | |
| 53 | + vec2 uv = ( n.x > n.y && n.x > n.z ) ? dir.yz / dir.x: | |
| 54 | + ( n.y > n.x && n.y > n.z ) ? dir.zx / dir.y: | |
| 55 | + dir.xy / dir.z; | |
| 56 | + | |
| 57 | + float f = 0.0; | |
| 58 | + | |
| 59 | + for( int i = 0 ; i < star_iterations; ++i ) | |
| 60 | + { | |
| 61 | + uv = rotate( 1.07 * uv + vec2( 0.7 ), 0.5 ); | |
| 62 | + | |
| 63 | + float t = 10. * uv.x * uv.y; | |
| 64 | + vec2 u = cos( 100. * uv ) * fbm( 10. * uv, 0.0 ); | |
| 65 | + f += smoothstep( 0.5, 0.55, u.x * u.y ) * ( 0.25 * sin( t ) + 0.75 ); | |
| 66 | + } | |
| 67 | + | |
| 68 | + return f * col_star; | |
| 69 | +} | |
| 70 | + | |
| 71 | +void main(void) { | |
| 72 | + vec3 c = doBackgroundStars( normalize(varPosition) ); | |
| 73 | + c = pow( c, vec3( 0.4545 ) ); | |
| 74 | + gl_FragColor = vec4( c, 1.0 ); | |
| 75 | +} | |
| 76 | + | |
| @@ -25,11 +25,6 @@ · 24 unmodified lines | ||
| 25 | 25 | using namespace render; |
| 26 | 26 | |
| 27 | 27 | DrawSceneTask::DrawSceneTask() : Task() { |
| 28 | − | |
| 29 | − _jobs.push_back(Job(DrawOpaque())); | |
| 30 | − _jobs.push_back(Job(DrawLight())); | |
| 31 | − _jobs.push_back(Job(DrawTransparent())); | |
| 32 | − _jobs.push_back(Job(ResetGLState())); | |
| 33 | 28 | } |
| 34 | 29 | |
| 35 | 30 | DrawSceneTask::~DrawSceneTask() { |
| @@ -56,8 +51,11 @@ void DrawSceneTask::run(const SceneContextPointer& sceneContext, const RenderCon · 20 unmodified lines | ||
| 56 | 51 | Job::~Job() { |
| 57 | 52 | } |
| 58 | 53 | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 59 | 58 | void render::cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { |
| 60 | − PerformanceTimer perfTimer("cullItems"); | |
| 61 | 59 | assert(renderContext->args); |
| 62 | 60 | assert(renderContext->args->_viewFrustum); |
| 63 | 61 | |
| @@ -68,17 +66,9 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont · 4 unmodified lines | ||
| 68 | 66 | renderDetails->_considered += inItems.size(); |
| 69 | 67 | |
| 70 | 68 | // Culling / LOD |
| 71 | − for (auto itemDetails : inItems) { | |
| 72 | − auto item = scene->getItem(itemDetails.id); | |
| 73 | − AABox bound; | |
| 74 | − { | |
| 75 | − PerformanceTimer perfTimer("getBound"); | |
| 76 | − | |
| 77 | − bound = item.getBound(); | |
| 78 | − } | |
| 79 | − | |
| 80 | − if (bound.isNull()) { | |
| 81 | − outItems.emplace_back(ItemIDAndBounds(itemDetails.id)); // One more Item to render | |
| 69 | + for (auto item : inItems) { | |
| 70 | + if (item.bounds.isNull()) { | |
| 71 | + outItems.emplace_back(item); // One more Item to render | |
| 82 | 72 | continue; |
| 83 | 73 | } |
| 84 | 74 | |
| @@ -87,16 +77,16 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont · 2 unmodified lines | ||
| 87 | 77 | bool outOfView; |
| 88 | 78 | { |
| 89 | 79 | PerformanceTimer perfTimer("boxInFrustum"); |
| 90 | − outOfView = args->_viewFrustum->boxInFrustum(bound) == ViewFrustum::OUTSIDE; | |
| 80 | + outOfView = args->_viewFrustum->boxInFrustum(item.bounds) == ViewFrustum::OUTSIDE; | |
| 91 | 81 | } |
| 92 | 82 | if (!outOfView) { |
| 93 | 83 | bool bigEnoughToRender; |
| 94 | 84 | { |
| 95 | 85 | PerformanceTimer perfTimer("shouldRender"); |
| 96 | − bigEnoughToRender = (args->_shouldRender) ? args->_shouldRender(args, bound) : true; | |
| 86 | + bigEnoughToRender = (args->_shouldRender) ? args->_shouldRender(args, item.bounds) : true; | |
| 97 | 87 | } |
| 98 | 88 | if (bigEnoughToRender) { |
| 99 | − outItems.emplace_back(ItemIDAndBounds(itemDetails.id, bound)); // One more Item to render | |
| 89 | + outItems.emplace_back(item); // One more Item to render | |
| 100 | 90 | } else { |
| 101 | 91 | renderDetails->_tooSmall++; |
| 102 | 92 | } |
| @@ -107,6 +97,32 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont · 4 unmodified lines | ||
| 107 | 97 | renderDetails->_rendered += outItems.size(); |
| 108 | 98 | } |
| 109 | 99 | |
| 100 | + | |
| 101 | +void FetchItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems) { | |
| 102 | + auto& scene = sceneContext->_scene; | |
| 103 | + auto& items = scene->getMasterBucket().at(_filter); | |
| 104 | + auto& renderDetails = renderContext->args->_details; | |
| 105 | + | |
| 106 | + outItems.clear(); | |
| 107 | + outItems.reserve(items.size()); | |
| 108 | + for (auto id : items) { | |
| 109 | + auto& item = scene->getItem(id); | |
| 110 | + outItems.emplace_back(ItemIDAndBounds(id, item.getBound())); | |
| 111 | + } | |
| 112 | + | |
| 113 | + if (_probeNumItems) { | |
| 114 | + _probeNumItems(renderContext, outItems.size()); | |
| 115 | + } | |
| 116 | +} | |
| 117 | + | |
| 118 | +void CullItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { | |
| 119 | + | |
| 120 | + outItems.clear(); | |
| 121 | + outItems.reserve(inItems.size()); | |
| 122 | + cullItems(sceneContext, renderContext, inItems, outItems); | |
| 123 | +} | |
| 124 | + | |
| 125 | + | |
| 110 | 126 | struct ItemBound { |
| 111 | 127 | float _centerDepth = 0.0f; |
| 112 | 128 | float _nearDepth = 0.0f; |
| @@ -130,7 +146,6 @@ struct BackToFrontSort { · 17 unmodified lines | ||
| 130 | 146 | }; |
| 131 | 147 | |
| 132 | 148 | void render::depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { |
| 133 | − PerformanceTimer perfTimer("depthSortItems"); | |
| 134 | 149 | assert(renderContext->args); |
| 135 | 150 | assert(renderContext->args->_viewFrustum); |
| 136 | 151 | |
| @@ -139,9 +154,10 @@ void render::depthSortItems(const SceneContextPointer& sceneContext, const Rende · 2 unmodified lines | ||
| 139 | 154 | |
| 140 | 155 | |
| 141 | 156 | // Allocate and simply copy |
| 157 | + outItems.clear(); | |
| 142 | 158 | outItems.reserve(inItems.size()); |
| 143 | 159 | |
| 144 | − | |
| 160 | + | |
| 145 | 161 | // Make a local dataset of the center distance and closest point distance |
| 146 | 162 | std::vector<ItemBound> itemBounds; |
| 147 | 163 | itemBounds.reserve(outItems.size()); |
| @@ -169,8 +185,14 @@ void render::depthSortItems(const SceneContextPointer& sceneContext, const Rende · 21 unmodified lines | ||
| 169 | 185 | } |
| 170 | 186 | } |
| 171 | 187 | |
| 188 | + | |
| 189 | +void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { | |
| 190 | + outItems.clear(); | |
| 191 | + outItems.reserve(inItems.size()); | |
| 192 | + depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems); | |
| 193 | +} | |
| 194 | + | |
| 172 | 195 | void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems) { |
| 173 | − PerformanceTimer perfTimer("renderItems"); | |
| 174 | 196 | auto& scene = sceneContext->_scene; |
| 175 | 197 | RenderArgs* args = renderContext->args; |
| 176 | 198 | // render |
| @@ -183,6 +205,10 @@ void render::renderItems(const SceneContextPointer& sceneContext, const RenderCo · 6 unmodified lines | ||
| 183 | 205 | int numItems = 0; |
| 184 | 206 | for (auto itemDetails : inItems) { |
| 185 | 207 | auto item = scene->getItem(itemDetails.id); |
| 208 | + if (numItems + 1 >= maxDrawnItems) { | |
| 209 | + item.render(args); | |
| 210 | + return; | |
| 211 | + } | |
| 186 | 212 | item.render(args); |
| 187 | 213 | numItems++; |
| 188 | 214 | if (numItems >= maxDrawnItems) { |
| @@ -224,8 +250,7 @@ void addClearStateCommands(gpu::Batch& batch) { · 35 unmodified lines | ||
| 224 | 250 | // Back to no program |
| 225 | 251 | batch._glUseProgram(0); |
| 226 | 252 | } |
| 227 | − | |
| 228 | −template <> void render::jobRun(const ResetGLState& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 253 | +void ResetGLState::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 229 | 254 | |
| 230 | 255 | gpu::Batch theBatch; |
| 231 | 256 | addClearStateCommands(theBatch); |
| @@ -233,160 +258,7 @@ template <> void render::jobRun(const ResetGLState& job, const SceneContextPoint · 1 unmodified line | ||
| 233 | 258 | renderContext->args->_context->render(theBatch); |
| 234 | 259 | } |
| 235 | 260 | |
| 236 | −template <> void render::jobRun(const DrawOpaque& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 237 | − PerformanceTimer perfTimer("DrawOpaque"); | |
| 238 | − assert(renderContext->args); | |
| 239 | − assert(renderContext->args->_viewFrustum); | |
| 240 | − | |
| 241 | − // render opaques | |
| 242 | − auto& scene = sceneContext->_scene; | |
| 243 | − auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape()); | |
| 244 | − auto& renderDetails = renderContext->args->_details; | |
| 245 | − | |
| 246 | − ItemIDsBounds inItems; | |
| 247 | − inItems.reserve(items.size()); | |
| 248 | − for (auto id : items) { | |
| 249 | − inItems.emplace_back(ItemIDAndBounds(id)); | |
| 250 | − } | |
| 251 | − ItemIDsBounds& renderedItems = inItems; | |
| 252 | − | |
| 253 | − renderContext->_numFeedOpaqueItems = renderedItems.size(); | |
| 254 | − | |
| 255 | − ItemIDsBounds culledItems; | |
| 256 | − culledItems.reserve(inItems.size()); | |
| 257 | − if (renderContext->_cullOpaque) { | |
| 258 | − renderDetails.pointTo(RenderDetails::OPAQUE_ITEM); | |
| 259 | − cullItems(sceneContext, renderContext, renderedItems, culledItems); | |
| 260 | − renderDetails.pointTo(RenderDetails::OTHER_ITEM); | |
| 261 | − renderedItems = culledItems; | |
| 262 | − } | |
| 263 | − | |
| 264 | − renderContext->_numDrawnOpaqueItems = renderedItems.size(); | |
| 265 | − | |
| 266 | − ItemIDsBounds sortedItems; | |
| 267 | − sortedItems.reserve(culledItems.size()); | |
| 268 | − if (renderContext->_sortOpaque) { | |
| 269 | − depthSortItems(sceneContext, renderContext, true, renderedItems, sortedItems); // Sort Front to back opaque items! | |
| 270 | − renderedItems = sortedItems; | |
| 271 | − } | |
| 272 | − | |
| 273 | − if (renderContext->_renderOpaque) { | |
| 274 | − RenderArgs* args = renderContext->args; | |
| 275 | − gpu::Batch batch; | |
| 276 | − args->_batch = &batch; | |
| 277 | − | |
| 278 | − glm::mat4 projMat; | |
| 279 | − Transform viewMat; | |
| 280 | − args->_viewFrustum->evalProjectionMatrix(projMat); | |
| 281 | − args->_viewFrustum->evalViewTransform(viewMat); | |
| 282 | − if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { | |
| 283 | − viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f)); | |
| 284 | − } | |
| 285 | − batch.setProjectionTransform(projMat); | |
| 286 | − batch.setViewTransform(viewMat); | |
| 287 | − | |
| 288 | − { | |
| 289 | − GLenum buffers[3]; | |
| 290 | − int bufferCount = 0; | |
| 291 | − buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; | |
| 292 | − buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; | |
| 293 | − buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; | |
| 294 | − batch._glDrawBuffers(bufferCount, buffers); | |
| 295 | − } | |
| 296 | − | |
| 297 | − renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnOpaqueItems); | |
| 298 | − | |
| 299 | − args->_context->render((*args->_batch)); | |
| 300 | − args->_batch = nullptr; | |
| 301 | − } | |
| 302 | −} | |
| 303 | − | |
| 304 | − | |
| 305 | −template <> void render::jobRun(const DrawTransparent& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 306 | − PerformanceTimer perfTimer("DrawTransparent"); | |
| 307 | − assert(renderContext->args); | |
| 308 | − assert(renderContext->args->_viewFrustum); | |
| 309 | − | |
| 310 | − // render transparents | |
| 311 | − auto& scene = sceneContext->_scene; | |
| 312 | − auto& items = scene->getMasterBucket().at(ItemFilter::Builder::transparentShape()); | |
| 313 | − auto& renderDetails = renderContext->args->_details; | |
| 314 | − | |
| 315 | − ItemIDsBounds inItems; | |
| 316 | − inItems.reserve(items.size()); | |
| 317 | − for (auto id : items) { | |
| 318 | − inItems.emplace_back(id); | |
| 319 | − } | |
| 320 | − ItemIDsBounds& renderedItems = inItems; | |
| 321 | − | |
| 322 | − renderContext->_numFeedTransparentItems = renderedItems.size(); | |
| 323 | − | |
| 324 | − ItemIDsBounds culledItems; | |
| 325 | − culledItems.reserve(inItems.size()); | |
| 326 | − if (renderContext->_cullTransparent) { | |
| 327 | − renderDetails.pointTo(RenderDetails::TRANSLUCENT_ITEM); | |
| 328 | − cullItems(sceneContext, renderContext, inItems, culledItems); | |
| 329 | − renderDetails.pointTo(RenderDetails::OTHER_ITEM); | |
| 330 | − renderedItems = culledItems; | |
| 331 | − } | |
| 332 | − | |
| 333 | − renderContext->_numDrawnTransparentItems = renderedItems.size(); | |
| 334 | − | |
| 335 | − ItemIDsBounds sortedItems; | |
| 336 | − sortedItems.reserve(culledItems.size()); | |
| 337 | − if (renderContext->_sortTransparent) { | |
| 338 | − depthSortItems(sceneContext, renderContext, false, renderedItems, sortedItems); // Sort Back to front transparent items! | |
| 339 | − renderedItems = sortedItems; | |
| 340 | − } | |
| 341 | − | |
| 342 | − if (renderContext->_renderTransparent) { | |
| 343 | − RenderArgs* args = renderContext->args; | |
| 344 | − gpu::Batch batch; | |
| 345 | − args->_batch = &batch; | |
| 346 | − | |
| 347 | − glm::mat4 projMat; | |
| 348 | − Transform viewMat; | |
| 349 | − args->_viewFrustum->evalProjectionMatrix(projMat); | |
| 350 | − args->_viewFrustum->evalViewTransform(viewMat); | |
| 351 | − if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { | |
| 352 | − viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f)); | |
| 353 | − } | |
| 354 | − batch.setProjectionTransform(projMat); | |
| 355 | − batch.setViewTransform(viewMat); | |
| 356 | − | |
| 357 | − const float MOSTLY_OPAQUE_THRESHOLD = 0.75f; | |
| 358 | − const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f; | |
| 359 | − | |
| 360 | − // render translucent meshes afterwards | |
| 361 | − { | |
| 362 | − GLenum buffers[2]; | |
| 363 | − int bufferCount = 0; | |
| 364 | − buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; | |
| 365 | − buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; | |
| 366 | − batch._glDrawBuffers(bufferCount, buffers); | |
| 367 | − args->_alphaThreshold = MOSTLY_OPAQUE_THRESHOLD; | |
| 368 | − } | |
| 369 | − | |
| 370 | − renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnTransparentItems); | |
| 371 | − | |
| 372 | − { | |
| 373 | − GLenum buffers[3]; | |
| 374 | − int bufferCount = 0; | |
| 375 | − buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; | |
| 376 | − batch._glDrawBuffers(bufferCount, buffers); | |
| 377 | − args->_alphaThreshold = TRANSPARENT_ALPHA_THRESHOLD; | |
| 378 | − } | |
| 379 | − | |
| 380 | − | |
| 381 | − renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnTransparentItems); | |
| 382 | − | |
| 383 | − args->_context->render((*args->_batch)); | |
| 384 | − args->_batch = nullptr; | |
| 385 | − } | |
| 386 | −} | |
| 387 | − | |
| 388 | −template <> void render::jobRun(const DrawLight& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 389 | − PerformanceTimer perfTimer("DrawLight"); | |
| 261 | +void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 390 | 262 | assert(renderContext->args); |
| 391 | 263 | assert(renderContext->args->_viewFrustum); |
| 392 | 264 | |
| @@ -398,7 +270,8 @@ template <> void render::jobRun(const DrawLight& job, const SceneContextPointer& · 5 unmodified lines | ||
| 398 | 270 | ItemIDsBounds inItems; |
| 399 | 271 | inItems.reserve(items.size()); |
| 400 | 272 | for (auto id : items) { |
| 401 | − inItems.emplace_back(id); | |
| 273 | + auto item = scene->getItem(id); | |
| 274 | + inItems.emplace_back(ItemIDAndBounds(id, item.getBound())); | |
| 402 | 275 | } |
| 403 | 276 | |
| 404 | 277 | ItemIDsBounds culledItems; |
| @@ -413,8 +286,7 @@ template <> void render::jobRun(const DrawLight& job, const SceneContextPointer& · 8 unmodified lines | ||
| 413 | 286 | args->_batch = nullptr; |
| 414 | 287 | } |
| 415 | 288 | |
| 416 | −template <> void render::jobRun(const DrawBackground& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 417 | − PerformanceTimer perfTimer("DrawBackground"); | |
| 289 | +void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 418 | 290 | assert(renderContext->args); |
| 419 | 291 | assert(renderContext->args->_viewFrustum); |
| 420 | 292 | |
| @@ -450,53 +322,6 @@ template <> void render::jobRun(const DrawBackground& job, const SceneContextPoi · 29 unmodified lines | ||
| 450 | 322 | args->_context->syncCache(); |
| 451 | 323 | } |
| 452 | 324 | |
| 453 | −template <> void render::jobRun(const DrawPostLayered& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 454 | − PerformanceTimer perfTimer("DrawPostLayered"); | |
| 455 | − assert(renderContext->args); | |
| 456 | − assert(renderContext->args->_viewFrustum); | |
| 457 | − | |
| 458 | − // render backgrounds | |
| 459 | − auto& scene = sceneContext->_scene; | |
| 460 | − auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape().withLayered()); | |
| 461 | − | |
| 462 | − | |
| 463 | − ItemIDsBounds inItems; | |
| 464 | − inItems.reserve(items.size()); | |
| 465 | − for (auto id : items) { | |
| 466 | − auto& item = scene->getItem(id); | |
| 467 | − if (item.getKey().isVisible() && (item.getLayer() > 0)) { | |
| 468 | − inItems.emplace_back(id); | |
| 469 | − } | |
| 470 | − } | |
| 471 | − if (inItems.empty()) { | |
| 472 | − return; | |
| 473 | − } | |
| 474 | − | |
| 475 | − RenderArgs* args = renderContext->args; | |
| 476 | − gpu::Batch batch; | |
| 477 | − args->_batch = &batch; | |
| 478 | − | |
| 479 | − glm::mat4 projMat; | |
| 480 | − Transform viewMat; | |
| 481 | − args->_viewFrustum->evalProjectionMatrix(projMat); | |
| 482 | − args->_viewFrustum->evalViewTransform(viewMat); | |
| 483 | − if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { | |
| 484 | − viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f)); | |
| 485 | − } | |
| 486 | − batch.setProjectionTransform(projMat); | |
| 487 | − batch.setViewTransform(viewMat); | |
| 488 | − | |
| 489 | − batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0); | |
| 490 | − | |
| 491 | − renderItems(sceneContext, renderContext, inItems); | |
| 492 | − args->_context->render((*args->_batch)); | |
| 493 | − args->_batch = nullptr; | |
| 494 | − | |
| 495 | − // Force the context sync | |
| 496 | − args->_context->syncCache(); | |
| 497 | −} | |
| 498 | − | |
| 499 | − | |
| 500 | 325 | void ItemMaterialBucketMap::insert(const ItemID& id, const model::MaterialKey& key) { |
| 501 | 326 | // Insert the itemID in every bucket where it filters true |
| 502 | 327 | for (auto& bucket : (*this)) { |
| @@ -13,42 +13,173 @@ · 12 unmodified lines | ||
| 13 | 13 | #define hifi_render_Task_h |
| 14 | 14 | |
| 15 | 15 | #include "Engine.h" |
| 16 | +#include "gpu/Batch.h" | |
| 17 | +#include <PerfStat.h> | |
| 18 | + | |
| 16 | 19 | |
| 17 | 20 | namespace render { |
| 18 | 21 | |
| 19 | −template <class T> void jobRun(const T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { } | |
| 22 | +template <class T> void jobRun(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 23 | + jobModel.run(sceneContext, renderContext); | |
| 24 | +} | |
| 25 | +template <class T, class I> void jobRunI(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const I& input) { | |
| 26 | + jobModel.run(sceneContext, renderContext, input); | |
| 27 | +} | |
| 28 | +template <class T, class O> void jobRunO(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, O& output) { | |
| 29 | + jobModel.run(sceneContext, renderContext, output); | |
| 30 | +} | |
| 31 | +template <class T, class I, class O> void jobRunIO(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const I& input, O& output) { | |
| 32 | + jobModel.run(sceneContext, renderContext, input, output); | |
| 33 | +} | |
| 20 | 34 | |
| 21 | 35 | class Job { |
| 22 | 36 | public: |
| 23 | 37 | |
| 24 | − template <class T> | |
| 25 | − Job(T data) : _concept(new Model<T>(data)) {} | |
| 38 | + // Varying represent a varying piece of data | |
| 39 | + class Varying { | |
| 40 | + public: | |
| 41 | + | |
| 42 | + Varying(const Varying& var): _concept(var._concept) {} | |
| 43 | + | |
| 44 | + Varying() {} | |
| 45 | + template <class T> | |
| 46 | + Varying(const T& data) : _concept(new Job::Varying::Model<T>(data)) {} | |
| 47 | + | |
| 48 | + // Access the _data contained win the concept explicitely | |
| 49 | + template <class T> T& edit() { return (static_cast<Model<T>*> (_concept.get())->_data); } | |
| 50 | + template <class T> const T& get() const { return (static_cast<const Model<T>*> (_concept.get())->_data); } | |
| 51 | + | |
| 52 | + protected: | |
| 53 | + friend class Job; | |
| 54 | + | |
| 55 | + std::vector<std::weak_ptr<Job>> _consumerJobs; | |
| 56 | + | |
| 57 | + void addJobConsumer(const std::shared_ptr<Job>& job) { | |
| 58 | + _consumerJobs.push_back(job); | |
| 59 | + } | |
| 60 | + | |
| 61 | + class Concept { | |
| 62 | + public: | |
| 63 | + virtual ~Concept() = default; | |
| 64 | + }; | |
| 65 | + template <class T> class Model : public Concept { | |
| 66 | + public: | |
| 67 | + typedef T Data; | |
| 68 | + Data _data; | |
| 69 | + Model(const Model& source): _data(source.data) {} | |
| 70 | + Model(const Data& data): _data(data) {} | |
| 71 | + virtual ~Model() {} | |
| 72 | + }; | |
| 73 | + | |
| 74 | + std::shared_ptr<Concept> _concept; | |
| 75 | + }; | |
| 76 | + | |
| 26 | 77 | Job(const Job& other) : _concept(other._concept) {} |
| 27 | 78 | ~Job(); |
| 28 | 79 | |
| 29 | − virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 30 | − if (_concept) { | |
| 31 | − _concept->run(sceneContext, renderContext); | |
| 32 | − } | |
| 80 | + const std::string& getName() const { return _concept->getName(); } | |
| 81 | + const Varying getInput() const { return _concept->getInput(); } | |
| 82 | + const Varying getOutput() const { return _concept->getOutput(); } | |
| 83 | + | |
| 84 | + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 85 | + PerformanceTimer perfTimer(getName().c_str()); | |
| 86 | + PROFILE_RANGE(getName().c_str()); | |
| 87 | + _concept->run(sceneContext, renderContext); | |
| 33 | 88 | } |
| 34 | 89 | |
| 35 | 90 | protected: |
| 91 | +public: | |
| 92 | + | |
| 36 | 93 | class Concept { |
| 94 | + std::string _name; | |
| 37 | 95 | public: |
| 96 | + Concept() : _name() {} | |
| 97 | + Concept(const std::string& name) : _name(name) {} | |
| 38 | 98 | virtual ~Concept() = default; |
| 99 | + | |
| 100 | + void setName(const std::string& name) { _name = name; } | |
| 101 | + const std::string& getName() const { return _name; } | |
| 102 | + | |
| 103 | + virtual const Varying getInput() const { return Varying(); } | |
| 104 | + virtual const Varying getOutput() const { return Varying(); } | |
| 39 | 105 | virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) = 0; |
| 40 | 106 | }; |
| 41 | 107 | |
| 108 | + Job(Concept* concept) : _concept(concept) {} | |
| 109 | + | |
| 110 | +public: | |
| 42 | 111 | template <class T> class Model : public Concept { |
| 43 | 112 | public: |
| 44 | 113 | typedef T Data; |
| 45 | − | |
| 114 | + | |
| 46 | 115 | Data _data; |
| 116 | + | |
| 117 | + Model() {} | |
| 118 | + Model(const std::string& name): Concept(name) {} | |
| 47 | 119 | Model(Data data): _data(data) {} |
| 120 | + Model(Data data, const std::string& name): Concept(name), _data(data) {} | |
| 48 | 121 | |
| 49 | 122 | void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { jobRun(_data, sceneContext, renderContext); } |
| 50 | 123 | }; |
| 51 | 124 | |
| 125 | + template <class T, class I> class ModelI : public Concept { | |
| 126 | + public: | |
| 127 | + typedef T Data; | |
| 128 | + typedef I Input; | |
| 129 | + | |
| 130 | + Data _data; | |
| 131 | + Varying _input; | |
| 132 | + | |
| 133 | + const Varying getInput() const { return _input; } | |
| 134 | + | |
| 135 | + ModelI(const std::string& name, const Varying& input): Concept(name), _input(input) {} | |
| 136 | + ModelI(const std::string& name, Data data): Concept(name), _data(data) {} | |
| 137 | + | |
| 138 | + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { jobRunI(_data, sceneContext, renderContext, _input.get<I>()); } | |
| 139 | + }; | |
| 140 | + | |
| 141 | + template <class T, class O> class ModelO : public Concept { | |
| 142 | + public: | |
| 143 | + typedef T Data; | |
| 144 | + typedef O Output; | |
| 145 | + | |
| 146 | + Data _data; | |
| 147 | + Varying _output; | |
| 148 | + | |
| 149 | + const Varying getOutput() const { return _output; } | |
| 150 | + | |
| 151 | + ModelO(const std::string& name): Concept(name), _output(Output()) { | |
| 152 | + | |
| 153 | + } | |
| 154 | + | |
| 155 | + ModelO(const std::string& name, Data data): Concept(name), _data(data), _output(Output()) {} | |
| 156 | + | |
| 157 | + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 158 | + jobRunO(_data, sceneContext, renderContext, _output.edit<O>()); | |
| 159 | + } | |
| 160 | + }; | |
| 161 | + | |
| 162 | + template <class T, class I, class O> class ModelIO : public Concept { | |
| 163 | + public: | |
| 164 | + typedef T Data; | |
| 165 | + typedef I Input; | |
| 166 | + typedef O Output; | |
| 167 | + | |
| 168 | + Data _data; | |
| 169 | + Varying _input; | |
| 170 | + Varying _output; | |
| 171 | + | |
| 172 | + const Varying getInput() const { return _input; } | |
| 173 | + const Varying getOutput() const { return _output; } | |
| 174 | + | |
| 175 | + ModelIO(const std::string& name, const Varying& input, Data data = Data()): Concept(name), _data(data), _input(input), _output(Output()) {} | |
| 176 | + ModelIO(const std::string& name, Data data, Output output): Concept(name), _data(data), _output(output) {} | |
| 177 | + | |
| 178 | + void setInput(const Varying& input) { _input = input; } | |
| 179 | + | |
| 180 | + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { jobRunIO(_data, sceneContext, renderContext, _input.get<I>(), _output.edit<O>()); } | |
| 181 | + }; | |
| 182 | + | |
| 52 | 183 | std::shared_ptr<Concept> _concept; |
| 53 | 184 | }; |
| 54 | 185 | |
| @@ -62,43 +193,59 @@ void depthSortItems(const SceneContextPointer& sceneContext, const RenderContext · 7 unmodified lines | ||
| 62 | 193 | void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); |
| 63 | 194 | |
| 64 | 195 | |
| 196 | +class FetchItems { | |
| 197 | +public: | |
| 198 | + typedef std::function<void (const RenderContextPointer& context, int count)> ProbeNumItems; | |
| 199 | + FetchItems(const ProbeNumItems& probe): _probeNumItems(probe) {} | |
| 200 | + FetchItems(const ItemFilter& filter, const ProbeNumItems& probe): _filter(filter), _probeNumItems(probe) {} | |
| 65 | 201 | |
| 66 | −void materialSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); | |
| 202 | + ItemFilter _filter = ItemFilter::Builder::opaqueShape().withoutLayered(); | |
| 203 | + ProbeNumItems _probeNumItems; | |
| 67 | 204 | |
| 205 | + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems); | |
| 68 | 206 | |
| 69 | −class DrawOpaque { | |
| 70 | −public: | |
| 207 | + typedef Job::ModelO<FetchItems, ItemIDsBounds> JobModel; | |
| 71 | 208 | }; |
| 72 | −template <> void jobRun(const DrawOpaque& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); | |
| 73 | 209 | |
| 210 | +class CullItems { | |
| 211 | +public: | |
| 212 | + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); | |
| 74 | 213 | |
| 75 | −class DrawTransparent { | |
| 214 | + typedef Job::ModelIO<CullItems, ItemIDsBounds, ItemIDsBounds> JobModel; | |
| 215 | +}; | |
| 216 | + | |
| 217 | +class DepthSortItems { | |
| 76 | 218 | public: |
| 219 | + bool _frontToBack = true; | |
| 220 | + | |
| 221 | + DepthSortItems(bool frontToBack = true) : _frontToBack(frontToBack) {} | |
| 222 | + | |
| 223 | + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); | |
| 224 | + | |
| 225 | + typedef Job::ModelIO<DepthSortItems, ItemIDsBounds, ItemIDsBounds> JobModel; | |
| 77 | 226 | }; |
| 78 | −template <> void jobRun(const DrawTransparent& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); | |
| 79 | 227 | |
| 80 | 228 | class DrawLight { |
| 81 | 229 | public: |
| 230 | + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); | |
| 231 | + | |
| 232 | + typedef Job::Model<DrawLight> JobModel; | |
| 82 | 233 | }; |
| 83 | −template <> void jobRun(const DrawLight& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); | |
| 84 | 234 | |
| 85 | 235 | class DrawBackground { |
| 86 | 236 | public: |
| 87 | −}; | |
| 88 | −template <> void jobRun(const DrawBackground& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); | |
| 89 | − | |
| 237 | + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); | |
| 90 | 238 | |
| 91 | −class DrawPostLayered { | |
| 92 | −public: | |
| 239 | + typedef Job::Model<DrawBackground> JobModel; | |
| 93 | 240 | }; |
| 94 | −template <> void jobRun(const DrawPostLayered& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); | |
| 95 | − | |
| 96 | − | |
| 97 | 241 | |
| 98 | 242 | class ResetGLState { |
| 99 | 243 | public: |
| 244 | + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); | |
| 245 | + | |
| 246 | + typedef Job::Model<ResetGLState> JobModel; | |
| 100 | 247 | }; |
| 101 | −template <> void jobRun(const ResetGLState& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); | |
| 248 | + | |
| 102 | 249 | |
| 103 | 250 | |
| 104 | 251 | class DrawSceneTask : public Task { |
| @@ -126,6 +273,7 @@ public: · 21 unmodified lines | ||
| 126 | 273 | // standard builders allocating the main buckets |
| 127 | 274 | void allocateStandardMaterialBuckets(); |
| 128 | 275 | }; |
| 276 | +void materialSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); | |
| 129 | 277 | |
| 130 | 278 | } |
| 131 | 279 | |
| @@ -45,6 +45,10 @@ public: · 44 unmodified lines | ||
| 45 | 45 | int _numDrawnTransparentItems = 0; |
| 46 | 46 | int _maxDrawnTransparentItems = -1; |
| 47 | 47 | |
| 48 | + int _numFeedOverlay3DItems = 0; | |
| 49 | + int _numDrawnOverlay3DItems = 0; | |
| 50 | + int _maxDrawnOverlay3DItems = -1; | |
| 51 | + | |
| 48 | 52 | RenderContext() {} |
| 49 | 53 | }; |
| 50 | 54 | typedef std::shared_ptr<RenderContext> RenderContextPointer; |
| @@ -107,6 +107,7 @@ signals: · 106 unmodified lines | ||
| 107 | 107 | |
| 108 | 108 | void mouseMoveEvent(const MouseEvent& event, unsigned int deviceID = 0); |
| 109 | 109 | void mousePressEvent(const MouseEvent& event, unsigned int deviceID = 0); |
| 110 | + void mouseDoublePressEvent(const MouseEvent& event, unsigned int deviceID = 0); | |
| 110 | 111 | void mouseReleaseEvent(const MouseEvent& event, unsigned int deviceID = 0); |
| 111 | 112 | |
| 112 | 113 | void touchBeginEvent(const TouchEvent& event); |
| @@ -46,24 +46,7 @@ ScriptAudioInjector* AudioScriptingInterface::playSound(Sound* sound, const Audi · 45 unmodified lines | ||
| 46 | 46 | AudioInjectorOptions optionsCopy = injectorOptions; |
| 47 | 47 | optionsCopy.stereo = sound->isStereo(); |
| 48 | 48 | |
| 49 | − QThread* injectorThread = new QThread(); | |
| 50 | − injectorThread->setObjectName("Audio Injector Thread"); | |
| 51 | − | |
| 52 | − AudioInjector* injector = new AudioInjector(sound, optionsCopy); | |
| 53 | − injector->setLocalAudioInterface(_localAudioInterface); | |
| 54 | − | |
| 55 | − injector->moveToThread(injectorThread); | |
| 56 | − | |
| 57 | − // start injecting when the injector thread starts | |
| 58 | − connect(injectorThread, &QThread::started, injector, &AudioInjector::injectAudio); | |
| 59 | − | |
| 60 | − // connect the right slots and signals for AudioInjector and thread cleanup | |
| 61 | − connect(injector, &AudioInjector::destroyed, injectorThread, &QThread::quit); | |
| 62 | − connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater); | |
| 63 | − | |
| 64 | − injectorThread->start(); | |
| 65 | − | |
| 66 | − return new ScriptAudioInjector(injector); | |
| 49 | + return new ScriptAudioInjector(AudioInjector::playSound(sound->getByteArray(), optionsCopy, _localAudioInterface)); | |
| 67 | 50 | |
| 68 | 51 | } else { |
| 69 | 52 | qCDebug(scriptengine) << "AudioScriptingInterface::playSound called with null Sound object."; |
| @@ -159,4 +159,6 @@ void SceneScriptingInterface::clearEngineCounters() { · 158 unmodified lines | ||
| 159 | 159 | _numDrawnOpaqueItems = 0; |
| 160 | 160 | _numFeedTransparentItems = 0; |
| 161 | 161 | _numDrawnTransparentItems = 0; |
| 162 | + _numFeedOverlay3DItems = 0; | |
| 163 | + _numDrawnOverlay3DItems = 0; | |
| 162 | 164 | } |
| @@ -90,17 +90,22 @@ public: · 89 unmodified lines | ||
| 90 | 90 | Q_INVOKABLE int getEngineNumDrawnOpaqueItems() { return _numDrawnOpaqueItems; } |
| 91 | 91 | void setEngineDrawnTransparentItems(int count) { _numDrawnTransparentItems = count; } |
| 92 | 92 | Q_INVOKABLE int getEngineNumDrawnTransparentItems() { return _numDrawnTransparentItems; } |
| 93 | + void setEngineDrawnOverlay3DItems(int count) { _numDrawnOverlay3DItems = count; } | |
| 94 | + Q_INVOKABLE int getEngineNumDrawnOverlay3DItems() { return _numDrawnOverlay3DItems; } | |
| 93 | 95 | |
| 94 | 96 | void setEngineFeedOpaqueItems(int count) { _numFeedOpaqueItems = count; } |
| 95 | 97 | Q_INVOKABLE int getEngineNumFeedOpaqueItems() { return _numFeedOpaqueItems; } |
| 96 | 98 | void setEngineFeedTransparentItems(int count) { _numFeedTransparentItems = count; } |
| 97 | 99 | Q_INVOKABLE int getEngineNumFeedTransparentItems() { return _numFeedTransparentItems; } |
| 100 | + void setEngineFeedOverlay3DItems(int count) { _numFeedOverlay3DItems = count; } | |
| 101 | + Q_INVOKABLE int getEngineNumFeedOverlay3DItems() { return _numFeedOverlay3DItems; } | |
| 98 | 102 | |
| 99 | 103 | Q_INVOKABLE void setEngineMaxDrawnOpaqueItems(int count) { _maxDrawnOpaqueItems = count; } |
| 100 | 104 | Q_INVOKABLE int getEngineMaxDrawnOpaqueItems() { return _maxDrawnOpaqueItems; } |
| 101 | 105 | Q_INVOKABLE void setEngineMaxDrawnTransparentItems(int count) { _maxDrawnTransparentItems = count; } |
| 102 | 106 | Q_INVOKABLE int getEngineMaxDrawnTransparentItems() { return _maxDrawnTransparentItems; } |
| 103 | − | |
| 107 | + Q_INVOKABLE void setEngineMaxDrawnOverlay3DItems(int count) { _maxDrawnOverlay3DItems = count; } | |
| 108 | + Q_INVOKABLE int getEngineMaxDrawnOverlay3DItems() { return _maxDrawnOverlay3DItems; } | |
| 104 | 109 | signals: |
| 105 | 110 | void shouldRenderAvatarsChanged(bool shouldRenderAvatars); |
| 106 | 111 | void shouldRenderEntitiesChanged(bool shouldRenderEntities); |
| @@ -124,9 +129,12 @@ protected: · 17 unmodified lines | ||
| 124 | 129 | int _numDrawnOpaqueItems = 0; |
| 125 | 130 | int _numFeedTransparentItems = 0; |
| 126 | 131 | int _numDrawnTransparentItems = 0; |
| 132 | + int _numFeedOverlay3DItems = 0; | |
| 133 | + int _numDrawnOverlay3DItems = 0; | |
| 127 | 134 | |
| 128 | 135 | int _maxDrawnOpaqueItems = -1; |
| 129 | 136 | int _maxDrawnTransparentItems = -1; |
| 137 | + int _maxDrawnOverlay3DItems = -1; | |
| 130 | 138 | |
| 131 | 139 | }; |
| 132 | 140 | |
| @@ -317,7 +317,10 @@ void ScriptEngine::init() { · 316 unmodified lines | ||
| 317 | 317 | registerAnimationTypes(this); |
| 318 | 318 | registerAvatarTypes(this); |
| 319 | 319 | registerAudioMetaTypes(this); |
| 320 | − _controllerScriptingInterface->registerControllerTypes(this); | |
| 320 | + | |
| 321 | + if (_controllerScriptingInterface) { | |
| 322 | + _controllerScriptingInterface->registerControllerTypes(this); | |
| 323 | + } | |
| 321 | 324 | |
| 322 | 325 | qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly); |
| 323 | 326 | qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue); |
| @@ -35,7 +35,7 @@ · 34 unmodified lines | ||
| 35 | 35 | |
| 36 | 36 | const QString NO_SCRIPT(""); |
| 37 | 37 | |
| 38 | −const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0 / 60.0f) * 1000 * 1000) + 0.5); | |
| 38 | +const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0f / 60.0f) * 1000 * 1000) + 0.5f); | |
| 39 | 39 | |
| 40 | 40 | typedef QHash<QString, QScriptValueList> RegisteredEventHandlers; |
| 41 | 41 | |
| @@ -40,7 +40,7 @@ TouchEvent::TouchEvent() : · 39 unmodified lines | ||
| 40 | 40 | isRotating(false), |
| 41 | 41 | rotating("none") |
| 42 | 42 | { |
| 43 | − | |
| 43 | + | |
| 44 | 44 | } |
| 45 | 45 | |
| 46 | 46 | TouchEvent::TouchEvent(const QTouchEvent& event) : |
| @@ -77,9 +77,9 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) { · 30 unmodified lines | ||
| 77 | 77 | touchPoints = tPoints.count(); |
| 78 | 78 | if (touchPoints > 1) { |
| 79 | 79 | for (int i = 0; i < touchPoints; ++i) { |
| 80 | − touchAvgX += tPoints[i].pos().x(); | |
| 81 | − touchAvgY += tPoints[i].pos().y(); | |
| 82 | − | |
| 80 | + touchAvgX += (float)tPoints[i].pos().x(); | |
| 81 | + touchAvgY += (float)tPoints[i].pos().y(); | |
| 82 | + | |
| 83 | 83 | // add it to our points vector |
| 84 | 84 | glm::vec2 thisPoint(tPoints[i].pos().x(), tPoints[i].pos().y()); |
| 85 | 85 | points << thisPoint; |
| @@ -94,7 +94,7 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) { · 8 unmodified lines | ||
| 94 | 94 | } |
| 95 | 95 | x = touchAvgX; |
| 96 | 96 | y = touchAvgY; |
| 97 | − | |
| 97 | + | |
| 98 | 98 | // after calculating the center point (average touch point), determine the maximum radius |
| 99 | 99 | // also calculate the rotation angle for each point |
| 100 | 100 | float maxRadius = 0.0f; |
| @@ -105,25 +105,25 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) { · 4 unmodified lines | ||
| 105 | 105 | if (thisRadius > maxRadius) { |
| 106 | 106 | maxRadius = thisRadius; |
| 107 | 107 | } |
| 108 | − | |
| 108 | + | |
| 109 | 109 | // calculate the angle for this point |
| 110 | 110 | float thisAngle = angleBetweenPoints(center,touchPoint); |
| 111 | 111 | angles << thisAngle; |
| 112 | 112 | } |
| 113 | 113 | radius = maxRadius; |
| 114 | − | |
| 114 | + | |
| 115 | 115 | // after calculating the angles for each touch point, determine the average angle |
| 116 | 116 | float totalAngle = 0.0f; |
| 117 | 117 | for (int i = 0; i < touchPoints; ++i) { |
| 118 | 118 | totalAngle += angles[i]; |
| 119 | 119 | } |
| 120 | 120 | angle = totalAngle/(float)touchPoints; |
| 121 | − | |
| 121 | + | |
| 122 | 122 | isPressed = event.touchPointStates().testFlag(Qt::TouchPointPressed); |
| 123 | 123 | isMoved = event.touchPointStates().testFlag(Qt::TouchPointMoved); |
| 124 | 124 | isStationary = event.touchPointStates().testFlag(Qt::TouchPointStationary); |
| 125 | 125 | isReleased = event.touchPointStates().testFlag(Qt::TouchPointReleased); |
| 126 | − | |
| 126 | + | |
| 127 | 127 | // keyboard modifiers |
| 128 | 128 | isShifted = event.modifiers().testFlag(Qt::ShiftModifier); |
| 129 | 129 | isMeta = event.modifiers().testFlag(Qt::MetaModifier); |
| @@ -143,7 +143,7 @@ void TouchEvent::calculateMetaAttributes(const TouchEvent& other) { · 13 unmodified lines | ||
| 143 | 143 | isPinching = other.isPinching; |
| 144 | 144 | isPinchOpening = other.isPinchOpening; |
| 145 | 145 | } |
| 146 | − | |
| 146 | + | |
| 147 | 147 | // determine if the points are rotating... |
| 148 | 148 | // note: if the number of touch points change between events, then we don't consider ourselves to be rotating |
| 149 | 149 | if (touchPoints == other.touchPoints) { |
| @@ -178,7 +178,7 @@ QScriptValue TouchEvent::toScriptValue(QScriptEngine* engine, const TouchEvent& · 28 unmodified lines | ||
| 178 | 178 | obj.setProperty("isControl", event.isControl); |
| 179 | 179 | obj.setProperty("isAlt", event.isAlt); |
| 180 | 180 | obj.setProperty("touchPoints", event.touchPoints); |
| 181 | − | |
| 181 | + | |
| 182 | 182 | QScriptValue pointsObj = engine->newArray(); |
| 183 | 183 | int index = 0; |
| 184 | 184 | foreach (glm::vec2 point, event.points) { |
| @@ -190,7 +190,7 @@ QScriptValue TouchEvent::toScriptValue(QScriptEngine* engine, const TouchEvent& · 5 unmodified lines | ||
| 190 | 190 | obj.setProperty("radius", event.radius); |
| 191 | 191 | obj.setProperty("isPinching", event.isPinching); |
| 192 | 192 | obj.setProperty("isPinchOpening", event.isPinchOpening); |
| 193 | − | |
| 193 | + | |
| 194 | 194 | obj.setProperty("angle", event.angle); |
| 195 | 195 | obj.setProperty("deltaAngle", event.deltaAngle); |
| 196 | 196 | QScriptValue anglesObj = engine->newArray(); |
| @@ -200,7 +200,7 @@ QScriptValue TouchEvent::toScriptValue(QScriptEngine* engine, const TouchEvent& · 3 unmodified lines | ||
| 200 | 200 | index++; |
| 201 | 201 | } |
| 202 | 202 | obj.setProperty("angles", anglesObj); |
| 203 | − | |
| 203 | + | |
| 204 | 204 | obj.setProperty("isRotating", event.isRotating); |
| 205 | 205 | obj.setProperty("rotating", event.rotating); |
| 206 | 206 | return obj; |
| @@ -6,4 +6,5 @@ setup_hifi_library(Gui Network Script Widgets) · 5 unmodified lines | ||
| 6 | 6 | |
| 7 | 7 | add_dependency_external_projects(glm) |
| 8 | 8 | find_package(GLM REQUIRED) |
| 9 | −target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) | |
| 9 | +target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) | |
| 10 | + | |
| @@ -16,20 +16,20 @@ · 15 unmodified lines | ||
| 16 | 16 | #include "GeometryUtil.h" |
| 17 | 17 | #include "NumericalConstants.h" |
| 18 | 18 | |
| 19 | −AABox::AABox(const AACube& other) : | |
| 19 | +AABox::AABox(const AACube& other) : | |
| 20 | 20 | _corner(other.getCorner()), _scale(other.getScale(), other.getScale(), other.getScale()) { |
| 21 | 21 | } |
| 22 | 22 | |
| 23 | −AABox::AABox(const Extents& other) : | |
| 23 | +AABox::AABox(const Extents& other) : | |
| 24 | 24 | _corner(other.minimum), |
| 25 | 25 | _scale(other.maximum - other.minimum) { |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | −AABox::AABox(const glm::vec3& corner, float size) : | |
| 28 | +AABox::AABox(const glm::vec3& corner, float size) : | |
| 29 | 29 | _corner(corner), _scale(size, size, size) { |
| 30 | 30 | }; |
| 31 | 31 | |
| 32 | −AABox::AABox(const glm::vec3& corner, const glm::vec3& dimensions) : | |
| 32 | +AABox::AABox(const glm::vec3& corner, const glm::vec3& dimensions) : | |
| 33 | 33 | _corner(corner), _scale(dimensions) { |
| 34 | 34 | }; |
| 35 | 35 | |
| @@ -39,7 +39,7 @@ AABox::AABox() : _corner(std::numeric_limits<float>::infinity()), _scale(0.0f) { · 3 unmodified lines | ||
| 39 | 39 | glm::vec3 AABox::calcCenter() const { |
| 40 | 40 | glm::vec3 center(_corner); |
| 41 | 41 | center += (_scale * 0.5f); |
| 42 | − return center; | |
| 42 | + return center; | |
| 43 | 43 | } |
| 44 | 44 | |
| 45 | 45 | void AABox::scale(float scale) { |
| @@ -134,12 +134,12 @@ bool AABox::contains(const AABox& otherBox) const { · 88 unmodified lines | ||
| 134 | 134 | |
| 135 | 135 | bool AABox::touches(const AABox& otherBox) const { |
| 136 | 136 | glm::vec3 relativeCenter = _corner - otherBox._corner + ((_scale - otherBox._scale) * 0.5f); |
| 137 | − | |
| 137 | + | |
| 138 | 138 | glm::vec3 totalHalfScale = (_scale + otherBox._scale) * 0.5f; |
| 139 | − | |
| 140 | − return fabs(relativeCenter.x) <= totalHalfScale.x && | |
| 141 | − fabs(relativeCenter.y) <= totalHalfScale.y && | |
| 142 | − fabs(relativeCenter.z) <= totalHalfScale.z; | |
| 139 | + | |
| 140 | + return fabsf(relativeCenter.x) <= totalHalfScale.x && | |
| 141 | + fabsf(relativeCenter.y) <= totalHalfScale.y && | |
| 142 | + fabsf(relativeCenter.z) <= totalHalfScale.z; | |
| 143 | 143 | } |
| 144 | 144 | |
| 145 | 145 | bool AABox::contains(const AACube& otherCube) const { |
| @@ -154,12 +154,12 @@ bool AABox::contains(const AACube& otherCube) const { · 8 unmodified lines | ||
| 154 | 154 | |
| 155 | 155 | bool AABox::touches(const AACube& otherCube) const { |
| 156 | 156 | glm::vec3 relativeCenter = _corner - otherCube.getCorner() + ((_scale - otherCube.getDimensions()) * 0.5f); |
| 157 | − | |
| 157 | + | |
| 158 | 158 | glm::vec3 totalHalfScale = (_scale + otherCube.getDimensions()) * 0.5f; |
| 159 | − | |
| 160 | − return fabs(relativeCenter.x) <= totalHalfScale.x && | |
| 161 | − fabs(relativeCenter.y) <= totalHalfScale.y && | |
| 162 | − fabs(relativeCenter.z) <= totalHalfScale.z; | |
| 159 | + | |
| 160 | + return fabsf(relativeCenter.x) <= totalHalfScale.x && | |
| 161 | + fabsf(relativeCenter.y) <= totalHalfScale.y && | |
| 162 | + fabsf(relativeCenter.z) <= totalHalfScale.z; | |
| 163 | 163 | } |
| 164 | 164 | |
| 165 | 165 | // determines whether a value is within the expanded extents |
| @@ -244,14 +244,14 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct · 78 unmodified lines | ||
| 244 | 244 | isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale.y) && |
| 245 | 245 | isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x))) { |
| 246 | 246 | distance = axisDistance; |
| 247 | − face = direction.z > 0 ? MAX_Z_FACE : MIN_Z_FACE; | |
| 247 | + face = direction.z > 0 ? MAX_Z_FACE : MIN_Z_FACE; | |
| 248 | 248 | return true; |
| 249 | 249 | } |
| 250 | 250 | // This case is unexpected, but mimics the previous behavior for inside out intersections |
| 251 | 251 | distance = 0; |
| 252 | 252 | return true; |
| 253 | 253 | } |
| 254 | − | |
| 254 | + | |
| 255 | 255 | // check each axis |
| 256 | 256 | float axisDistance; |
| 257 | 257 | if ((findIntersection(origin.x, direction.x, _corner.x, _scale.x, axisDistance) && axisDistance >= 0 && |
| @@ -272,7 +272,7 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct · 14 unmodified lines | ||
| 272 | 272 | isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale.y) && |
| 273 | 273 | isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x))) { |
| 274 | 274 | distance = axisDistance; |
| 275 | − face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE; | |
| 275 | + face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE; | |
| 276 | 276 | return true; |
| 277 | 277 | } |
| 278 | 278 | return false; |
| @@ -280,7 +280,7 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct · 1 unmodified line | ||
| 280 | 280 | |
| 281 | 281 | bool AABox::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const { |
| 282 | 282 | glm::vec4 center4 = glm::vec4(center, 1.0f); |
| 283 | − | |
| 283 | + | |
| 284 | 284 | float minPenetrationLength = FLT_MAX; |
| 285 | 285 | for (int i = 0; i < FACE_COUNT; i++) { |
| 286 | 286 | glm::vec4 facePlane = getPlane((BoxFace)i); |
| @@ -297,7 +297,7 @@ bool AABox::findSpherePenetration(const glm::vec3& center, float radius, glm::ve · 10 unmodified lines | ||
| 297 | 297 | minPenetrationLength = vectorLength; |
| 298 | 298 | } |
| 299 | 299 | } |
| 300 | − | |
| 300 | + | |
| 301 | 301 | return true; |
| 302 | 302 | } |
| 303 | 303 | |
| @@ -305,7 +305,7 @@ bool AABox::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, · 1 unmodified line | ||
| 305 | 305 | glm::vec4 start4 = glm::vec4(start, 1.0f); |
| 306 | 306 | glm::vec4 end4 = glm::vec4(end, 1.0f); |
| 307 | 307 | glm::vec4 startToEnd = glm::vec4(end - start, 0.0f); |
| 308 | − | |
| 308 | + | |
| 309 | 309 | float minPenetrationLength = FLT_MAX; |
| 310 | 310 | for (int i = 0; i < FACE_COUNT; i++) { |
| 311 | 311 | // find the vector from the segment to the closest point on the face (starting from deeper end) |
| @@ -324,8 +324,8 @@ bool AABox::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, · 12 unmodified lines | ||
| 324 | 324 | vector * ((vectorLength + radius) / -vectorLength); |
| 325 | 325 | minPenetrationLength = vectorLength; |
| 326 | 326 | } |
| 327 | − } | |
| 328 | − | |
| 327 | + } | |
| 328 | + | |
| 329 | 329 | return true; |
| 330 | 330 | } |
| 331 | 331 | |
| @@ -334,23 +334,23 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec3& point, BoxFace face) con · 2 unmodified lines | ||
| 334 | 334 | case MIN_X_FACE: |
| 335 | 335 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), |
| 336 | 336 | glm::vec3(_corner.x, _corner.y + _scale.y, _corner.z + _scale.z)); |
| 337 | − | |
| 337 | + | |
| 338 | 338 | case MAX_X_FACE: |
| 339 | 339 | return glm::clamp(point, glm::vec3(_corner.x + _scale.x, _corner.y, _corner.z), |
| 340 | 340 | glm::vec3(_corner.x + _scale.x, _corner.y + _scale.y, _corner.z + _scale.z)); |
| 341 | − | |
| 341 | + | |
| 342 | 342 | case MIN_Y_FACE: |
| 343 | 343 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), |
| 344 | 344 | glm::vec3(_corner.x + _scale.x, _corner.y, _corner.z + _scale.z)); |
| 345 | − | |
| 345 | + | |
| 346 | 346 | case MAX_Y_FACE: |
| 347 | 347 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _scale.y, _corner.z), |
| 348 | 348 | glm::vec3(_corner.x + _scale.x, _corner.y + _scale.y, _corner.z + _scale.z)); |
| 349 | − | |
| 349 | + | |
| 350 | 350 | case MIN_Z_FACE: |
| 351 | 351 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), |
| 352 | 352 | glm::vec3(_corner.x + _scale.z, _corner.y + _scale.y, _corner.z)); |
| 353 | − | |
| 353 | + | |
| 354 | 354 | default: //quiet windows warnings |
| 355 | 355 | case MAX_Z_FACE: |
| 356 | 356 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _scale.z), |
| @@ -373,7 +373,7 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& · 16 unmodified lines | ||
| 373 | 373 | } |
| 374 | 374 | anyOutside = true; |
| 375 | 375 | float divisor = glm::dot(direction, iPlane); |
| 376 | − if (fabs(divisor) < EPSILON) { | |
| 376 | + if (fabsf(divisor) < EPSILON) { | |
| 377 | 377 | continue; // segment is parallel to plane |
| 378 | 378 | } |
| 379 | 379 | // find intersection and see if it lies within face bounds |
| @@ -389,29 +389,29 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& · 9 unmodified lines | ||
| 389 | 389 | } |
| 390 | 390 | } |
| 391 | 391 | return getClosestPointOnFace(glm::vec3(intersection), face); |
| 392 | − | |
| 392 | + | |
| 393 | 393 | outerContinue: ; |
| 394 | 394 | } |
| 395 | − | |
| 395 | + | |
| 396 | 396 | // if we were outside any of the sides, we must check against the diagonals |
| 397 | 397 | if (anyOutside) { |
| 398 | 398 | int faceAxis = face / 2; |
| 399 | 399 | int secondAxis = (faceAxis + 1) % 3; |
| 400 | 400 | int thirdAxis = (faceAxis + 2) % 3; |
| 401 | − | |
| 401 | + | |
| 402 | 402 | glm::vec4 secondAxisMinPlane = getPlane((BoxFace)(secondAxis * 2)); |
| 403 | 403 | glm::vec4 secondAxisMaxPlane = getPlane((BoxFace)(secondAxis * 2 + 1)); |
| 404 | 404 | glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1)); |
| 405 | − | |
| 405 | + | |
| 406 | 406 | glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f, |
| 407 | 407 | glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), _scale) * 0.5f); |
| 408 | 408 | glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset, |
| 409 | 409 | secondAxisMaxPlane + thirdAxisMaxPlane + offset }; |
| 410 | − | |
| 410 | + | |
| 411 | 411 | float minDistance = FLT_MAX; |
| 412 | 412 | for (size_t i = 0; i < sizeof(diagonals) / sizeof(diagonals[0]); i++) { |
| 413 | 413 | float divisor = glm::dot(direction, diagonals[i]); |
| 414 | − if (fabs(divisor) < EPSILON) { | |
| 414 | + if (fabsf(divisor) < EPSILON) { | |
| 415 | 415 | continue; // segment is parallel to diagonal plane |
| 416 | 416 | } |
| 417 | 417 | minDistance = glm::min(-glm::dot(origin, diagonals[i]) / divisor, minDistance); |
| @@ -420,7 +420,7 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& · 2 unmodified lines | ||
| 420 | 420 | return getClosestPointOnFace(glm::vec3(origin + direction * minDistance), face); |
| 421 | 421 | } |
| 422 | 422 | } |
| 423 | − | |
| 423 | + | |
| 424 | 424 | // last resort or all inside: clamp origin to face |
| 425 | 425 | return getClosestPointOnFace(glm::vec3(origin), face); |
| 426 | 426 | } |
| @@ -453,7 +453,7 @@ AABox AABox::clamp(const glm::vec3& min, const glm::vec3& max) const { · 26 unmodified lines | ||
| 453 | 453 | glm::vec3 clampedCorner = glm::clamp(_corner, min, max); |
| 454 | 454 | glm::vec3 clampedTopFarLeft = glm::clamp(calcTopFarLeft(), min, max); |
| 455 | 455 | glm::vec3 clampedScale = clampedTopFarLeft - clampedCorner; |
| 456 | − | |
| 456 | + | |
| 457 | 457 | return AABox(clampedCorner, clampedScale); |
| 458 | 458 | } |
| 459 | 459 | |
| @@ -461,7 +461,7 @@ AABox AABox::clamp(float min, float max) const { · 1 unmodified line | ||
| 461 | 461 | glm::vec3 clampedCorner = glm::clamp(_corner, min, max); |
| 462 | 462 | glm::vec3 clampedTopFarLeft = glm::clamp(calcTopFarLeft(), min, max); |
| 463 | 463 | glm::vec3 clampedScale = clampedTopFarLeft - clampedCorner; |
| 464 | − | |
| 464 | + | |
| 465 | 465 | return AABox(clampedCorner, clampedScale); |
| 466 | 466 | } |
| 467 | 467 | |
| @@ -21,14 +21,14 @@ AACube::AACube(const AABox& other) : · 20 unmodified lines | ||
| 21 | 21 | _corner(other.getCorner()), _scale(other.getLargestDimension()) { |
| 22 | 22 | } |
| 23 | 23 | |
| 24 | −AACube::AACube(const Extents& other) : | |
| 25 | − _corner(other.minimum) | |
| 24 | +AACube::AACube(const Extents& other) : | |
| 25 | + _corner(other.minimum) | |
| 26 | 26 | { |
| 27 | 27 | glm::vec3 dimensions = other.maximum - other.minimum; |
| 28 | 28 | _scale = glm::max(dimensions.x, dimensions.y, dimensions.z); |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | −AACube::AACube(const glm::vec3& corner, float size) : | |
| 31 | +AACube::AACube(const glm::vec3& corner, float size) : | |
| 32 | 32 | _corner(corner), _scale(size) { |
| 33 | 33 | }; |
| 34 | 34 | |
| @@ -38,13 +38,13 @@ AACube::AACube() : _corner(0,0,0), _scale(0) { · 3 unmodified lines | ||
| 38 | 38 | glm::vec3 AACube::calcCenter() const { |
| 39 | 39 | glm::vec3 center(_corner); |
| 40 | 40 | center += (glm::vec3(_scale, _scale, _scale) * 0.5f); |
| 41 | − return center; | |
| 41 | + return center; | |
| 42 | 42 | } |
| 43 | 43 | |
| 44 | −glm::vec3 AACube::calcTopFarLeft() const { | |
| 44 | +glm::vec3 AACube::calcTopFarLeft() const { | |
| 45 | 45 | glm::vec3 topFarLeft(_corner); |
| 46 | 46 | topFarLeft += glm::vec3(_scale, _scale, _scale); |
| 47 | − return topFarLeft; | |
| 47 | + return topFarLeft; | |
| 48 | 48 | }; |
| 49 | 49 | |
| 50 | 50 | void AACube::scale(float scale) { |
| @@ -135,9 +135,9 @@ bool AACube::contains(const AACube& otherCube) const { · 84 unmodified lines | ||
| 135 | 135 | bool AACube::touches(const AACube& otherCube) const { |
| 136 | 136 | glm::vec3 relativeCenter = _corner - otherCube._corner + (glm::vec3(_scale - otherCube._scale) * 0.5f); |
| 137 | 137 | float totalHalfScale = 0.5f * (_scale + otherCube._scale); |
| 138 | − return fabs(relativeCenter.x) <= totalHalfScale && | |
| 139 | − fabs(relativeCenter.y) <= totalHalfScale && | |
| 140 | − fabs(relativeCenter.z) <= totalHalfScale; | |
| 138 | + return fabsf(relativeCenter.x) <= totalHalfScale && | |
| 139 | + fabsf(relativeCenter.y) <= totalHalfScale && | |
| 140 | + fabsf(relativeCenter.z) <= totalHalfScale; | |
| 141 | 141 | } |
| 142 | 142 | |
| 143 | 143 | bool AACube::contains(const AABox& otherBox) const { |
| @@ -154,10 +154,10 @@ bool AACube::touches(const AABox& otherBox) const { · 10 unmodified lines | ||
| 154 | 154 | glm::vec3 myDimensions = glm::vec3(_scale); |
| 155 | 155 | glm::vec3 relativeCenter = _corner - otherBox.getCorner() + ((myDimensions - otherBox.getScale()) * 0.5f); |
| 156 | 156 | glm::vec3 totalHalfScale = (myDimensions + otherBox.getDimensions()) * 0.5f; |
| 157 | − | |
| 158 | − return fabs(relativeCenter.x) <= totalHalfScale.x && | |
| 159 | − fabs(relativeCenter.y) <= totalHalfScale.y && | |
| 160 | − fabs(relativeCenter.z) <= totalHalfScale.z; | |
| 157 | + | |
| 158 | + return fabsf(relativeCenter.x) <= totalHalfScale.x && | |
| 159 | + fabsf(relativeCenter.y) <= totalHalfScale.y && | |
| 160 | + fabsf(relativeCenter.z) <= totalHalfScale.z; | |
| 161 | 161 | } |
| 162 | 162 | |
| 163 | 163 | // determines whether a value is within the expanded extents |
| @@ -222,7 +222,7 @@ bool AACube::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& · 58 unmodified lines | ||
| 222 | 222 | bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const { |
| 223 | 223 | // handle the trivial case where the box contains the origin |
| 224 | 224 | if (contains(origin)) { |
| 225 | − | |
| 225 | + | |
| 226 | 226 | // We still want to calculate the distance from the origin to the inside out plane |
| 227 | 227 | float axisDistance; |
| 228 | 228 | if ((findInsideOutIntersection(origin.x, direction.x, _corner.x, _scale, axisDistance) && axisDistance >= 0 && |
| @@ -243,14 +243,14 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc · 14 unmodified lines | ||
| 243 | 243 | isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) && |
| 244 | 244 | isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) { |
| 245 | 245 | distance = axisDistance; |
| 246 | − face = direction.z > 0 ? MAX_Z_FACE : MIN_Z_FACE; | |
| 246 | + face = direction.z > 0 ? MAX_Z_FACE : MIN_Z_FACE; | |
| 247 | 247 | return true; |
| 248 | 248 | } |
| 249 | 249 | // This case is unexpected, but mimics the previous behavior for inside out intersections |
| 250 | 250 | distance = 0; |
| 251 | 251 | return true; |
| 252 | 252 | } |
| 253 | − | |
| 253 | + | |
| 254 | 254 | // check each axis |
| 255 | 255 | float axisDistance; |
| 256 | 256 | if ((findIntersection(origin.x, direction.x, _corner.x, _scale, axisDistance) && axisDistance >= 0 && |
| @@ -271,7 +271,7 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc · 14 unmodified lines | ||
| 271 | 271 | isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) && |
| 272 | 272 | isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) { |
| 273 | 273 | distance = axisDistance; |
| 274 | − face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE; | |
| 274 | + face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE; | |
| 275 | 275 | return true; |
| 276 | 276 | } |
| 277 | 277 | return false; |
| @@ -279,7 +279,7 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc · 1 unmodified line | ||
| 279 | 279 | |
| 280 | 280 | bool AACube::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const { |
| 281 | 281 | glm::vec4 center4 = glm::vec4(center, 1.0f); |
| 282 | − | |
| 282 | + | |
| 283 | 283 | float minPenetrationLength = FLT_MAX; |
| 284 | 284 | for (int i = 0; i < FACE_COUNT; i++) { |
| 285 | 285 | glm::vec4 facePlane = getPlane((BoxFace)i); |
| @@ -296,7 +296,7 @@ bool AACube::findSpherePenetration(const glm::vec3& center, float radius, glm::v · 10 unmodified lines | ||
| 296 | 296 | minPenetrationLength = vectorLength; |
| 297 | 297 | } |
| 298 | 298 | } |
| 299 | − | |
| 299 | + | |
| 300 | 300 | return true; |
| 301 | 301 | } |
| 302 | 302 | |
| @@ -304,7 +304,7 @@ bool AACube::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end · 1 unmodified line | ||
| 304 | 304 | glm::vec4 start4 = glm::vec4(start, 1.0f); |
| 305 | 305 | glm::vec4 end4 = glm::vec4(end, 1.0f); |
| 306 | 306 | glm::vec4 startToEnd = glm::vec4(end - start, 0.0f); |
| 307 | − | |
| 307 | + | |
| 308 | 308 | float minPenetrationLength = FLT_MAX; |
| 309 | 309 | for (int i = 0; i < FACE_COUNT; i++) { |
| 310 | 310 | // find the vector from the segment to the closest point on the face (starting from deeper end) |
| @@ -323,8 +323,8 @@ bool AACube::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end · 12 unmodified lines | ||
| 323 | 323 | vector * ((vectorLength + radius) / -vectorLength); |
| 324 | 324 | minPenetrationLength = vectorLength; |
| 325 | 325 | } |
| 326 | − } | |
| 327 | − | |
| 326 | + } | |
| 327 | + | |
| 328 | 328 | return true; |
| 329 | 329 | } |
| 330 | 330 | |
| @@ -333,23 +333,23 @@ glm::vec3 AACube::getClosestPointOnFace(const glm::vec3& point, BoxFace face) co · 2 unmodified lines | ||
| 333 | 333 | case MIN_X_FACE: |
| 334 | 334 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), |
| 335 | 335 | glm::vec3(_corner.x, _corner.y + _scale, _corner.z + _scale)); |
| 336 | − | |
| 336 | + | |
| 337 | 337 | case MAX_X_FACE: |
| 338 | 338 | return glm::clamp(point, glm::vec3(_corner.x + _scale, _corner.y, _corner.z), |
| 339 | 339 | glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale)); |
| 340 | − | |
| 340 | + | |
| 341 | 341 | case MIN_Y_FACE: |
| 342 | 342 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), |
| 343 | 343 | glm::vec3(_corner.x + _scale, _corner.y, _corner.z + _scale)); |
| 344 | − | |
| 344 | + | |
| 345 | 345 | case MAX_Y_FACE: |
| 346 | 346 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _scale, _corner.z), |
| 347 | 347 | glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale)); |
| 348 | − | |
| 348 | + | |
| 349 | 349 | case MIN_Z_FACE: |
| 350 | 350 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), |
| 351 | 351 | glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z)); |
| 352 | − | |
| 352 | + | |
| 353 | 353 | default: //quiet windows warnings |
| 354 | 354 | case MAX_Z_FACE: |
| 355 | 355 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _scale), |
| @@ -372,7 +372,7 @@ glm::vec3 AACube::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4 · 16 unmodified lines | ||
| 372 | 372 | } |
| 373 | 373 | anyOutside = true; |
| 374 | 374 | float divisor = glm::dot(direction, iPlane); |
| 375 | − if (fabs(divisor) < EPSILON) { | |
| 375 | + if (fabsf(divisor) < EPSILON) { | |
| 376 | 376 | continue; // segment is parallel to plane |
| 377 | 377 | } |
| 378 | 378 | // find intersection and see if it lies within face bounds |
| @@ -388,29 +388,29 @@ glm::vec3 AACube::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4 · 9 unmodified lines | ||
| 388 | 388 | } |
| 389 | 389 | } |
| 390 | 390 | return getClosestPointOnFace(glm::vec3(intersection), face); |
| 391 | − | |
| 391 | + | |
| 392 | 392 | outerContinue: ; |
| 393 | 393 | } |
| 394 | − | |
| 394 | + | |
| 395 | 395 | // if we were outside any of the sides, we must check against the diagonals |
| 396 | 396 | if (anyOutside) { |
| 397 | 397 | int faceAxis = face / 2; |
| 398 | 398 | int secondAxis = (faceAxis + 1) % 3; |
| 399 | 399 | int thirdAxis = (faceAxis + 2) % 3; |
| 400 | − | |
| 400 | + | |
| 401 | 401 | glm::vec4 secondAxisMinPlane = getPlane((BoxFace)(secondAxis * 2)); |
| 402 | 402 | glm::vec4 secondAxisMaxPlane = getPlane((BoxFace)(secondAxis * 2 + 1)); |
| 403 | 403 | glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1)); |
| 404 | − | |
| 404 | + | |
| 405 | 405 | glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f, |
| 406 | 406 | glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), glm::vec3(_scale, _scale, _scale)) * 0.5f); |
| 407 | 407 | glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset, |
| 408 | 408 | secondAxisMaxPlane + thirdAxisMaxPlane + offset }; |
| 409 | − | |
| 409 | + | |
| 410 | 410 | float minDistance = FLT_MAX; |
| 411 | 411 | for (size_t i = 0; i < sizeof(diagonals) / sizeof(diagonals[0]); i++) { |
| 412 | 412 | float divisor = glm::dot(direction, diagonals[i]); |
| 413 | − if (fabs(divisor) < EPSILON) { | |
| 413 | + if (fabsf(divisor) < EPSILON) { | |
| 414 | 414 | continue; // segment is parallel to diagonal plane |
| 415 | 415 | } |
| 416 | 416 | minDistance = glm::min(-glm::dot(origin, diagonals[i]) / divisor, minDistance); |
| @@ -419,7 +419,7 @@ glm::vec3 AACube::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4 · 2 unmodified lines | ||
| 419 | 419 | return getClosestPointOnFace(glm::vec3(origin + direction * minDistance), face); |
| 420 | 420 | } |
| 421 | 421 | } |
| 422 | − | |
| 422 | + | |
| 423 | 423 | // last resort or all inside: clamp origin to face |
| 424 | 424 | return getClosestPointOnFace(glm::vec3(origin), face); |
| 425 | 425 | } |
| @@ -120,7 +120,7 @@ bool HingeConstraint::clamp(glm::quat& rotation) const { · 119 unmodified lines | ||
| 120 | 120 | forward /= length; |
| 121 | 121 | float sign = (glm::dot(glm::cross(_forwardAxis, forward), _rotationAxis) > 0.0f ? 1.0f : -1.0f); |
| 122 | 122 | //float angle = sign * acos(glm::dot(forward, _forwardAxis) / length); |
| 123 | − float angle = sign * acos(glm::dot(forward, _forwardAxis)); | |
| 123 | + float angle = sign * acosf(glm::dot(forward, _forwardAxis)); | |
| 124 | 124 | glm::quat newRotation = glm::angleAxis(clampAngle(angle, _minAngle, _maxAngle), _rotationAxis); |
| 125 | 125 | if (fabsf(1.0f - glm::dot(newRotation, rotation)) > EPSILON * EPSILON) { |
| 126 | 126 | rotation = newRotation; |
| @@ -238,7 +238,7 @@ glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) { · 237 unmodified lines | ||
| 238 | 238 | float sd10 = previous[0][1] * previous[2][2] - previous[2][1] * previous[0][2]; |
| 239 | 239 | float sd20 = previous[0][1] * previous[1][2] - previous[1][1] * previous[0][2]; |
| 240 | 240 | float det = previous[0][0] * sd00 + previous[2][0] * sd20 - previous[1][0] * sd10; |
| 241 | − if (fabs(det) == 0.0f) { | |
| 241 | + if (fabsf(det) == 0.0f) { | |
| 242 | 242 | // determinant is zero; matrix is not invertible |
| 243 | 243 | break; |
| 244 | 244 | } |
| @@ -28,10 +28,19 @@ using glm::vec3; · 27 unmodified lines | ||
| 28 | 28 | using glm::vec4; |
| 29 | 29 | using glm::quat; |
| 30 | 30 | |
| 31 | +#ifdef __GNUC__ | |
| 32 | +#pragma GCC diagnostic push | |
| 33 | +#pragma GCC diagnostic ignored "-Wdouble-promotion" | |
| 34 | +#endif | |
| 35 | + | |
| 31 | 36 | #include <QtCore/QByteArray> |
| 32 | 37 | #include <QtGui/QMatrix4x4> |
| 33 | 38 | #include <QtGui/QColor> |
| 34 | 39 | |
| 40 | +#ifdef __GNUC__ | |
| 41 | +#pragma GCC diagnostic pop | |
| 42 | +#endif | |
| 43 | + | |
| 35 | 44 | #include "SharedUtil.h" |
| 36 | 45 | |
| 37 | 46 | // this is where the coordinate system is represented |
| @@ -122,6 +131,21 @@ float aspect(const T& t) { · 84 unmodified lines | ||
| 122 | 131 | return (float)t.x / (float)t.y; |
| 123 | 132 | } |
| 124 | 133 | |
| 134 | +// Take values in an arbitrary range [0, size] and convert them to the range [0, 1] | |
| 135 | +template <typename T> | |
| 136 | +T toUnitScale(const T& value, const T& size) { | |
| 137 | + return value / size; | |
| 138 | +} | |
| 139 | + | |
| 140 | +// Take values in an arbitrary range [0, size] and convert them to the range [0, 1] | |
| 141 | +template <typename T> | |
| 142 | +T toNormalizedDeviceScale(const T& value, const T& size) { | |
| 143 | + vec2 result = toUnitScale(value, size); | |
| 144 | + result *= 2.0f; | |
| 145 | + result -= 1.0f; | |
| 146 | + return result; | |
| 147 | +} | |
| 148 | + | |
| 125 | 149 | #define YAW(euler) euler.y |
| 126 | 150 | #define PITCH(euler) euler.x |
| 127 | 151 | #define ROLL(euler) euler.z |
| @@ -118,11 +118,15 @@ public: · 117 unmodified lines | ||
| 118 | 118 | |
| 119 | 119 | template <typename Function> |
| 120 | 120 | void withPush(Function f) { |
| 121 | + #ifndef NDEBUG | |
| 121 | 122 | size_t startingDepth = size(); |
| 123 | + #endif | |
| 122 | 124 | push(); |
| 123 | 125 | f(); |
| 124 | 126 | pop(); |
| 125 | − assert(startingDepth = size()); | |
| 127 | + #ifndef NDEBUG | |
| 128 | + assert(startingDepth == size()); | |
| 129 | + #endif | |
| 126 | 130 | } |
| 127 | 131 | |
| 128 | 132 | template <typename Function> |
| @@ -47,7 +47,7 @@ void printOctalCode(const unsigned char* octalCode) { · 46 unmodified lines | ||
| 47 | 47 | |
| 48 | 48 | char sectionValue(const unsigned char* startByte, char startIndexInByte) { |
| 49 | 49 | char rightShift = 8 - startIndexInByte - 3; |
| 50 | − | |
| 50 | + | |
| 51 | 51 | if (rightShift < 0) { |
| 52 | 52 | return ((startByte[0] << -rightShift) & 7) + (startByte[1] >> (8 + rightShift)); |
| 53 | 53 | } else { |
| @@ -65,7 +65,7 @@ size_t bytesRequiredForCodeLength(unsigned char threeBitCodes) { · 11 unmodified lines | ||
| 65 | 65 | |
| 66 | 66 | int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsigned char* descendantOctalCode) { |
| 67 | 67 | int parentSections = numberOfThreeBitSectionsInCode(ancestorOctalCode); |
| 68 | − | |
| 68 | + | |
| 69 | 69 | int branchStartBit = parentSections * 3; |
| 70 | 70 | // Note: this does not appear to be "multi-byte length code" safe. When octal codes are larger than 255 bytes |
| 71 | 71 | // long, the length code is stored in two bytes. The "1" below appears to assume that the length is always one |
| @@ -74,45 +74,45 @@ int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsi · 2 unmodified lines | ||
| 74 | 74 | } |
| 75 | 75 | |
| 76 | 76 | unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNumber) { |
| 77 | − | |
| 77 | + | |
| 78 | 78 | // find the length (in number of three bit code sequences) |
| 79 | 79 | // in the parent |
| 80 | 80 | int parentCodeSections = parentOctalCode |
| 81 | 81 | ? numberOfThreeBitSectionsInCode(parentOctalCode) |
| 82 | 82 | : 0; |
| 83 | − | |
| 83 | + | |
| 84 | 84 | // get the number of bytes used by the parent octal code |
| 85 | 85 | size_t parentCodeBytes = bytesRequiredForCodeLength(parentCodeSections); |
| 86 | − | |
| 86 | + | |
| 87 | 87 | // child code will have one more section than the parent |
| 88 | 88 | size_t childCodeBytes = bytesRequiredForCodeLength(parentCodeSections + 1); |
| 89 | − | |
| 89 | + | |
| 90 | 90 | // create a new buffer to hold the new octal code |
| 91 | 91 | unsigned char* newCode = new unsigned char[childCodeBytes]; |
| 92 | − | |
| 92 | + | |
| 93 | 93 | // copy the parent code to the child |
| 94 | 94 | if (parentOctalCode) { |
| 95 | 95 | memcpy(newCode, parentOctalCode, parentCodeBytes); |
| 96 | − } | |
| 97 | − | |
| 96 | + } | |
| 97 | + | |
| 98 | 98 | // the child octal code has one more set of three bits |
| 99 | 99 | *newCode = parentCodeSections + 1; |
| 100 | − | |
| 100 | + | |
| 101 | 101 | if (childCodeBytes > parentCodeBytes) { |
| 102 | 102 | // we have a new byte due to the addition of the child code |
| 103 | 103 | // so set it to zero for correct results when shifting later |
| 104 | 104 | newCode[childCodeBytes - 1] = 0; |
| 105 | 105 | } |
| 106 | − | |
| 106 | + | |
| 107 | 107 | // add the child code bits to newCode |
| 108 | − | |
| 108 | + | |
| 109 | 109 | // find the start bit index |
| 110 | 110 | int startBit = parentCodeSections * 3; |
| 111 | − | |
| 111 | + | |
| 112 | 112 | // calculate the amount of left shift required |
| 113 | 113 | // this will be -1 or -2 if there's wrap |
| 114 | 114 | char leftShift = 8 - (startBit % 8) - 3; |
| 115 | − | |
| 115 | + | |
| 116 | 116 | if (leftShift < 0) { |
| 117 | 117 | // we have a wrap-around to accomodate |
| 118 | 118 | // right shift for the end of first byte |
| @@ -123,7 +123,7 @@ unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNu · 4 unmodified lines | ||
| 123 | 123 | // no wraparound, left shift and add |
| 124 | 124 | newCode[(startBit / 8) + 1] += (childNumber << leftShift); |
| 125 | 125 | } |
| 126 | − | |
| 126 | + | |
| 127 | 127 | return newCode; |
| 128 | 128 | } |
| 129 | 129 | |
| @@ -135,9 +135,9 @@ void voxelDetailsForCode(const unsigned char* octalCode, VoxelPositionSize& voxe · 5 unmodified lines | ||
| 135 | 135 | if (octalCode) { |
| 136 | 136 | for (int i = 0; i < numberOfThreeBitSectionsInCode(octalCode); i++) { |
| 137 | 137 | currentScale *= 0.5f; |
| 138 | − int sectionIndex = sectionValue(octalCode + 1 + (BITS_IN_OCTAL * i / BITS_IN_BYTE), | |
| 138 | + int sectionIndex = sectionValue(octalCode + 1 + (BITS_IN_OCTAL * i / BITS_IN_BYTE), | |
| 139 | 139 | (BITS_IN_OCTAL * i) % BITS_IN_BYTE); |
| 140 | − | |
| 140 | + | |
| 141 | 141 | for (int j = 0; j < BITS_IN_OCTAL; j++) { |
| 142 | 142 | output[j] += currentScale * (float)oneAtBit(sectionIndex, (BITS_IN_BYTE - BITS_IN_OCTAL) + j); |
| 143 | 143 | } |
| @@ -151,17 +151,17 @@ void voxelDetailsForCode(const unsigned char* octalCode, VoxelPositionSize& voxe · 7 unmodified lines | ||
| 151 | 151 | |
| 152 | 152 | void copyFirstVertexForCode(const unsigned char* octalCode, float* output) { |
| 153 | 153 | memset(output, 0, 3 * sizeof(float)); |
| 154 | − | |
| 154 | + | |
| 155 | 155 | float currentScale = 0.5f; |
| 156 | − | |
| 156 | + | |
| 157 | 157 | for (int i = 0; i < numberOfThreeBitSectionsInCode(octalCode); i++) { |
| 158 | 158 | int sectionIndex = sectionValue(octalCode + 1 + (3 * i / 8), (3 * i) % 8); |
| 159 | − | |
| 159 | + | |
| 160 | 160 | for (int j = 0; j < 3; j++) { |
| 161 | 161 | output[j] += currentScale * (int)oneAtBit(sectionIndex, 5 + j); |
| 162 | 162 | } |
| 163 | − | |
| 164 | − currentScale *= 0.5; | |
| 163 | + | |
| 164 | + currentScale *= 0.5f; | |
| 165 | 165 | } |
| 166 | 166 | } |
| 167 | 167 | |
| @@ -171,7 +171,7 @@ OctalCodeComparison compareOctalCodes(const unsigned char* codeA, const unsigned · 3 unmodified lines | ||
| 171 | 171 | } |
| 172 | 172 | |
| 173 | 173 | OctalCodeComparison result = LESS_THAN; // assume it's shallower |
| 174 | − | |
| 174 | + | |
| 175 | 175 | size_t numberOfBytes = std::min(bytesRequiredForCodeLength(*codeA), bytesRequiredForCodeLength(*codeB)); |
| 176 | 176 | int compare = memcmp(codeA, codeB, numberOfBytes); |
| 177 | 177 | |
| @@ -205,7 +205,7 @@ char getOctalCodeSectionValue(const unsigned char* octalCode, int section) { · 27 unmodified lines | ||
| 205 | 205 | int startAtByte = 1 + (BITS_IN_OCTAL * section / BITS_IN_BYTE); |
| 206 | 206 | char startIndexInByte = (BITS_IN_OCTAL * section) % BITS_IN_BYTE; |
| 207 | 207 | const unsigned char* startByte = octalCode + startAtByte; |
| 208 | − | |
| 208 | + | |
| 209 | 209 | return sectionValue(startByte, startIndexInByte); |
| 210 | 210 | } |
| 211 | 211 | |
| @@ -227,7 +227,7 @@ void setOctalCodeSectionValue(unsigned char* octalCode, int section, char sectio · 15 unmodified lines | ||
| 227 | 227 | unsigned char oldValue = *byteAt & ~shiftedMask; |
| 228 | 228 | unsigned char newValue = oldValue | shiftedValue; |
| 229 | 229 | *byteAt = newValue; |
| 230 | − | |
| 230 | + | |
| 231 | 231 | // If the requested section is partially in the byte, then we |
| 232 | 232 | // need to also set the portion of the section value in the next byte |
| 233 | 233 | // there's only two cases where this happens, if the bit in byte is |
| @@ -255,7 +255,7 @@ unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLev · 21 unmodified lines | ||
| 255 | 255 | int newLength = codeLength - chopLevels; |
| 256 | 256 | newCode = new unsigned char[newLength+1]; |
| 257 | 257 | *newCode = newLength; // set the length byte |
| 258 | − | |
| 258 | + | |
| 259 | 259 | for (int section = chopLevels; section < codeLength; section++) { |
| 260 | 260 | char sectionValue = getOctalCodeSectionValue(originalOctalCode, section); |
| 261 | 261 | setOctalCodeSectionValue(newCode, section - chopLevels, sectionValue); |
| @@ -264,9 +264,9 @@ unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLev · 2 unmodified lines | ||
| 264 | 264 | return newCode; |
| 265 | 265 | } |
| 266 | 266 | |
| 267 | −unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode, | |
| 267 | +unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode, | |
| 268 | 268 | bool includeColorSpace) { |
| 269 | − | |
| 269 | + | |
| 270 | 270 | int oldCodeLength = numberOfThreeBitSectionsInCode(originalOctalCode); |
| 271 | 271 | int newParentCodeLength = numberOfThreeBitSectionsInCode(newParentOctalCode); |
| 272 | 272 | int newCodeLength = newParentCodeLength + oldCodeLength; |
| @@ -298,12 +298,12 @@ bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* po · 25 unmodified lines | ||
| 298 | 298 | } |
| 299 | 299 | |
| 300 | 300 | int descendentCodeLength = numberOfThreeBitSectionsInCode(possibleDescendent); |
| 301 | − | |
| 301 | + | |
| 302 | 302 | // if the caller also include a child, then our descendent length is actually one extra! |
| 303 | 303 | if (descendentsChild != CHECK_NODE_ONLY) { |
| 304 | 304 | descendentCodeLength++; |
| 305 | 305 | } |
| 306 | − | |
| 306 | + | |
| 307 | 307 | if (ancestorCodeLength > descendentCodeLength) { |
| 308 | 308 | return false; // if the descendent is shorter, it can't be a descendent |
| 309 | 309 | } |
| @@ -322,7 +322,7 @@ bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* po · 12 unmodified lines | ||
| 322 | 322 | return false; // first non-match, means they don't match |
| 323 | 323 | } |
| 324 | 324 | } |
| 325 | − | |
| 325 | + | |
| 326 | 326 | // they all match, so we are an ancestor |
| 327 | 327 | return true; |
| 328 | 328 | } |
| @@ -335,7 +335,7 @@ unsigned char* hexStringToOctalCode(const QString& input) { · 6 unmodified lines | ||
| 335 | 335 | |
| 336 | 336 | // allocate byte array based on half of string length |
| 337 | 337 | unsigned char* bytes = new unsigned char[(input.length()) / HEX_BYTE_SIZE]; |
| 338 | − | |
| 338 | + | |
| 339 | 339 | // loop through the string - 2 bytes at a time converting |
| 340 | 340 | // it to decimal equivalent and store in byte array |
| 341 | 341 | bool ok = false; |
| @@ -348,7 +348,7 @@ unsigned char* hexStringToOctalCode(const QString& input) { · 6 unmodified lines | ||
| 348 | 348 | stringIndex += HEX_BYTE_SIZE; |
| 349 | 349 | byteArrayIndex++; |
| 350 | 350 | } |
| 351 | − | |
| 351 | + | |
| 352 | 352 | // something went wrong |
| 353 | 353 | if (!ok) { |
| 354 | 354 | delete[] bytes; |
| @@ -55,7 +55,7 @@ const int16_t COLLISION_GROUP_COLLISIONLESS = 1 << 15; · 54 unmodified lines | ||
| 55 | 55 | const int16_t COLLISION_MASK_DEFAULT = ~ COLLISION_GROUP_COLLISIONLESS; |
| 56 | 56 | |
| 57 | 57 | // STATIC also doesn't collide with other STATIC |
| 58 | −const int16_t COLLISION_MASK_STATIC = ~ (COLLISION_GROUP_COLLISIONLESS | COLLISION_MASK_STATIC); | |
| 58 | +const int16_t COLLISION_MASK_STATIC = ~ (COLLISION_GROUP_COLLISIONLESS | COLLISION_GROUP_STATIC); | |
| 59 | 59 | |
| 60 | 60 | const int16_t COLLISION_MASK_KINEMATIC = COLLISION_MASK_DEFAULT; |
| 61 | 61 | |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | ||
| 20 | 20 | |
| 21 | 21 | static int vec4MetaTypeId = qRegisterMetaType<glm::vec4>(); |
| 22 | 22 | static int vec3MetaTypeId = qRegisterMetaType<glm::vec3>(); |
| 23 | +static int qVectorVec3MetaTypeId = qRegisterMetaType<QVector<glm::vec3>>(); | |
| 23 | 24 | static int vec2MetaTypeId = qRegisterMetaType<glm::vec2>(); |
| 24 | 25 | static int quatMetaTypeId = qRegisterMetaType<glm::quat>(); |
| 25 | 26 | static int xColorMetaTypeId = qRegisterMetaType<xColor>(); |
| @@ -31,6 +32,7 @@ static int collisionMetaTypeId = qRegisterMetaType<Collision>(); · 5 unmodified lines | ||
| 31 | 32 | void registerMetaTypes(QScriptEngine* engine) { |
| 32 | 33 | qScriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue); |
| 33 | 34 | qScriptRegisterMetaType(engine, vec3toScriptValue, vec3FromScriptValue); |
| 35 | + qScriptRegisterMetaType(engine, qVectorVec3ToScriptValue, qVectorVec3FromScriptValue); | |
| 34 | 36 | qScriptRegisterMetaType(engine, vec2toScriptValue, vec2FromScriptValue); |
| 35 | 37 | qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue); |
| 36 | 38 | qScriptRegisterMetaType(engine, qRectToScriptValue, qRectFromScriptValue); |
| @@ -93,6 +95,16 @@ QVector<glm::vec3> qVectorVec3FromScriptValue(const QScriptValue& array){ · 56 unmodified lines | ||
| 93 | 95 | return newVector; |
| 94 | 96 | } |
| 95 | 97 | |
| 98 | +void qVectorVec3FromScriptValue(const QScriptValue& array, QVector<glm::vec3>& vector ) { | |
| 99 | + int length = array.property("length").toInteger(); | |
| 100 | + | |
| 101 | + for (int i = 0; i < length; i++) { | |
| 102 | + glm::vec3 newVec3 = glm::vec3(); | |
| 103 | + vec3FromScriptValue(array.property(i), newVec3); | |
| 104 | + vector << newVec3; | |
| 105 | + } | |
| 106 | +} | |
| 107 | + | |
| 96 | 108 | QScriptValue vec2toScriptValue(QScriptEngine* engine, const glm::vec2 &vec2) { |
| 97 | 109 | QScriptValue obj = engine->newObject(); |
| 98 | 110 | obj.setProperty("x", vec2.x); |
| @@ -57,6 +57,7 @@ QScriptValue qURLToScriptValue(QScriptEngine* engine, const QUrl& url); · 56 unmodified lines | ||
| 57 | 57 | void qURLFromScriptValue(const QScriptValue& object, QUrl& url); |
| 58 | 58 | |
| 59 | 59 | QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector<glm::vec3>& vector); |
| 60 | +void qVectorVec3FromScriptValue(const QScriptValue& array, QVector<glm::vec3>& vector); | |
| 60 | 61 | QVector<glm::vec3> qVectorVec3FromScriptValue( const QScriptValue& array); |
| 61 | 62 | |
| 62 | 63 | class PickRay { |
| @@ -881,7 +881,7 @@ bool capsuleVsAACube(const Shape* shapeA, const Shape* shapeB, CollisionList& co · 880 unmodified lines | ||
| 881 | 881 | faceNormal = glm::vec3(0.0f, 0.0f, signs.z); |
| 882 | 882 | } |
| 883 | 883 | |
| 884 | − if (fabs(glm::dot(faceNormal, capsuleAxis)) < EPSILON) { | |
| 884 | + if (fabsf(glm::dot(faceNormal, capsuleAxis)) < EPSILON) { | |
| 885 | 885 | if (glm::dot(nearestApproach, faceNormal) > cubeB->getScale() + capsuleA->getRadius()) { |
| 886 | 886 | return false; |
| 887 | 887 | } |
| @@ -29,7 +29,7 @@ inline bool isValidScale(glm::vec3 scale) { · 28 unmodified lines | ||
| 29 | 29 | } |
| 30 | 30 | |
| 31 | 31 | inline bool isValidScale(float scale) { |
| 32 | − bool result = scale != 0.0f; | |
| 32 | + bool result = scale != 0.0f && !glm::isnan(scale) && !glm::isinf(scale); | |
| 33 | 33 | assert(result); |
| 34 | 34 | return result; |
| 35 | 35 | } |
| @@ -323,7 +323,7 @@ inline void Transform::setScale(const Vec3& scale) { · 287 unmodified lines | ||
| 323 | 323 | } |
| 324 | 324 | |
| 325 | 325 | inline void Transform::postScale(float scale) { |
| 326 | − if (isValidScale(scale) || scale == 1.0f) { | |
| 326 | + if (!isValidScale(scale) || scale == 1.0f) { | |
| 327 | 327 | return; |
| 328 | 328 | } |
| 329 | 329 | if (isScaling()) { |
| @@ -13,35 +13,61 @@ · 12 unmodified lines | ||
| 13 | 13 | #include "SharedLogging.h" |
| 14 | 14 | #include "VariantMapToScriptValue.h" |
| 15 | 15 | |
| 16 | −QScriptValue variantMapToScriptValue(QVariantMap& variantMap, QScriptEngine& scriptEngine) { | |
| 17 | − QScriptValue scriptValue = scriptEngine.newObject(); | |
| 18 | − | |
| 19 | − for (QVariantMap::const_iterator iter = variantMap.begin(); iter != variantMap.end(); ++iter) { | |
| 20 | − QString key = iter.key(); | |
| 21 | − QVariant qValue = iter.value(); | |
| 22 | 16 | |
| 23 | − switch(qValue.type()) { | |
| 17 | +QScriptValue variantToScriptValue(QVariant& qValue, QScriptEngine& scriptEngine) { | |
| 18 | + switch(qValue.type()) { | |
| 24 | 19 | case QVariant::Bool: |
| 25 | − scriptValue.setProperty(key, qValue.toBool()); | |
| 20 | + return qValue.toBool(); | |
| 26 | 21 | break; |
| 27 | 22 | case QVariant::Int: |
| 28 | − scriptValue.setProperty(key, qValue.toInt()); | |
| 23 | + return qValue.toInt(); | |
| 29 | 24 | break; |
| 30 | 25 | case QVariant::Double: |
| 31 | − scriptValue.setProperty(key, qValue.toDouble()); | |
| 26 | + return qValue.toDouble(); | |
| 32 | 27 | break; |
| 33 | 28 | case QVariant::String: { |
| 34 | − scriptValue.setProperty(key, scriptEngine.newVariant(qValue)); | |
| 29 | + return scriptEngine.newVariant(qValue); | |
| 35 | 30 | break; |
| 36 | 31 | } |
| 37 | 32 | case QVariant::Map: { |
| 38 | 33 | QVariantMap childMap = qValue.toMap(); |
| 39 | − scriptValue.setProperty(key, variantMapToScriptValue(childMap, scriptEngine)); | |
| 34 | + return variantMapToScriptValue(childMap, scriptEngine); | |
| 35 | + break; | |
| 36 | + } | |
| 37 | + case QVariant::List: { | |
| 38 | + QVariantList childList = qValue.toList(); | |
| 39 | + return variantListToScriptValue(childList, scriptEngine); | |
| 40 | 40 | break; |
| 41 | 41 | } |
| 42 | 42 | default: |
| 43 | 43 | qCDebug(shared) << "unhandled QScript type" << qValue.type(); |
| 44 | − } | |
| 44 | + break; | |
| 45 | + } | |
| 46 | + | |
| 47 | + return QScriptValue(); | |
| 48 | +} | |
| 49 | + | |
| 50 | + | |
| 51 | +QScriptValue variantMapToScriptValue(QVariantMap& variantMap, QScriptEngine& scriptEngine) { | |
| 52 | + QScriptValue scriptValue = scriptEngine.newObject(); | |
| 53 | + | |
| 54 | + for (QVariantMap::const_iterator iter = variantMap.begin(); iter != variantMap.end(); ++iter) { | |
| 55 | + QString key = iter.key(); | |
| 56 | + QVariant qValue = iter.value(); | |
| 57 | + scriptValue.setProperty(key, variantToScriptValue(qValue, scriptEngine)); | |
| 58 | + } | |
| 59 | + | |
| 60 | + return scriptValue; | |
| 61 | +} | |
| 62 | + | |
| 63 | + | |
| 64 | +QScriptValue variantListToScriptValue(QVariantList& variantList, QScriptEngine& scriptEngine) { | |
| 65 | + QScriptValue scriptValue = scriptEngine.newObject(); | |
| 66 | + | |
| 67 | + scriptValue.setProperty("length", variantList.size()); | |
| 68 | + int i = 0; | |
| 69 | + foreach (QVariant v, variantList) { | |
| 70 | + scriptValue.setProperty(i++, variantToScriptValue(v, scriptEngine)); | |
| 45 | 71 | } |
| 46 | 72 | |
| 47 | 73 | return scriptValue; |
| @@ -13,4 +13,6 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <QScriptValue> |
| 14 | 14 | #include <QScriptEngine> |
| 15 | 15 | |
| 16 | +QScriptValue variantToScriptValue(QVariant& qValue, QScriptEngine& scriptEngine); | |
| 16 | 17 | QScriptValue variantMapToScriptValue(QVariantMap& variantMap, QScriptEngine& scriptEngine); |
| 18 | +QScriptValue variantListToScriptValue(QVariantList& variantList, QScriptEngine& scriptEngine); | |
| @@ -0,0 +1,51 @@ | ||
| 1 | +// | |
| 2 | +// Tooltip.cpp | |
| 3 | +// | |
| 4 | +// Created by Bradley Austin Davis on 2015/04/14 | |
| 5 | +// Copyright 2015 High Fidelity, Inc. | |
| 6 | +// | |
| 7 | +// Distributed under the Apache License, Version 2.0. | |
| 8 | +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 9 | +// | |
| 10 | +#include "Tooltip.h" | |
| 11 | +#include <QUuid> | |
| 12 | + | |
| 13 | +HIFI_QML_DEF(Tooltip) | |
| 14 | + | |
| 15 | +Tooltip::Tooltip(QQuickItem* parent) : QQuickItem(parent) { | |
| 16 | +} | |
| 17 | + | |
| 18 | +Tooltip::~Tooltip() { | |
| 19 | +} | |
| 20 | + | |
| 21 | +QString Tooltip::text() const { | |
| 22 | + return _text; | |
| 23 | +} | |
| 24 | + | |
| 25 | +void Tooltip::setText(const QString& arg) { | |
| 26 | + if (arg != _text) { | |
| 27 | + _text = arg; | |
| 28 | + emit textChanged(); | |
| 29 | + } | |
| 30 | +} | |
| 31 | + | |
| 32 | +void Tooltip::setVisible(bool visible) { | |
| 33 | + QQuickItem::setVisible(visible); | |
| 34 | +} | |
| 35 | + | |
| 36 | +QString Tooltip::showTip(const QString& text) { | |
| 37 | + const QString newTipId = QUuid().createUuid().toString(); | |
| 38 | + Tooltip::show([&](QQmlContext*, QObject* object) { | |
| 39 | + object->setObjectName(newTipId); | |
| 40 | + object->setProperty("text", text); | |
| 41 | + }); | |
| 42 | + return newTipId; | |
| 43 | +} | |
| 44 | + | |
| 45 | +void Tooltip::closeTip(const QString& tipId) { | |
| 46 | + auto rootItem = DependencyManager::get<OffscreenUi>()->getRootItem(); | |
| 47 | + QQuickItem* that = rootItem->findChild<QQuickItem*>(tipId); | |
| 48 | + if (that) { | |
| 49 | + that->deleteLater(); | |
| 50 | + } | |
| 51 | +} | |
| @@ -0,0 +1,45 @@ | ||
| 1 | +// | |
| 2 | +// Tooltip.h | |
| 3 | +// | |
| 4 | +// Created by Bradley Austin Davis on 2015/04/14 | |
| 5 | +// Copyright 2015 High Fidelity, Inc. | |
| 6 | +// | |
| 7 | +// Distributed under the Apache License, Version 2.0. | |
| 8 | +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 9 | +// | |
| 10 | + | |
| 11 | +#pragma once | |
| 12 | +#ifndef hifi_Tooltip_h | |
| 13 | +#define hifi_Tooltip_h | |
| 14 | + | |
| 15 | +#include "OffscreenQmlDialog.h" | |
| 16 | + | |
| 17 | +class Tooltip : public QQuickItem | |
| 18 | +{ | |
| 19 | + Q_OBJECT | |
| 20 | + HIFI_QML_DECL | |
| 21 | + | |
| 22 | +private: | |
| 23 | + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) | |
| 24 | + | |
| 25 | +public: | |
| 26 | + Tooltip(QQuickItem* parent = 0); | |
| 27 | + virtual ~Tooltip(); | |
| 28 | + | |
| 29 | + QString text() const; | |
| 30 | + | |
| 31 | + static QString showTip(const QString& text); | |
| 32 | + static void closeTip(const QString& tipId); | |
| 33 | + | |
| 34 | +public slots: | |
| 35 | + virtual void setVisible(bool v); | |
| 36 | + void setText(const QString& arg); | |
| 37 | + | |
| 38 | +signals: | |
| 39 | + void textChanged(); | |
| 40 | + | |
| 41 | +private: | |
| 42 | + QString _text; | |
| 43 | +}; | |
| 44 | + | |
| 45 | +#endif // hifi_Tooltip_h | |
| @@ -135,8 +135,8 @@ void VrMenu::setRootMenu(QObject* rootMenu) { · 134 unmodified lines | ||
| 135 | 135 | |
| 136 | 136 | void VrMenu::addMenu(QMenu* menu) { |
| 137 | 137 | Q_ASSERT(!MenuUserData::forObject(menu)); |
| 138 | − QObject * parent = menu->parent(); | |
| 139 | − QObject * qmlParent; | |
| 138 | + QObject* parent = menu->parent(); | |
| 139 | + QObject* qmlParent = nullptr; | |
| 140 | 140 | if (dynamic_cast<QMenu*>(parent)) { |
| 141 | 141 | MenuUserData* userData = MenuUserData::forObject(parent); |
| 142 | 142 | qmlParent = findMenuObject(userData->uuid.toString()); |
| @@ -116,20 +116,20 @@ void ShapeColliderTests::sphereTouchesSphere() { · 115 unmodified lines | ||
| 116 | 116 | << " ERROR: null collision" << std::endl; |
| 117 | 117 | return; |
| 118 | 118 | } |
| 119 | − | |
| 119 | + | |
| 120 | 120 | // penetration points from sphereA into sphereB |
| 121 | 121 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 122 | − if (fabs(inaccuracy) > EPSILON) { | |
| 122 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 123 | 123 | std::cout << __FILE__ << ":" << __LINE__ |
| 124 | 124 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 125 | 125 | << " actual = " << collision->_penetration << std::endl; |
| 126 | 126 | } |
| 127 | − | |
| 127 | + | |
| 128 | 128 | // contactPoint is on surface of sphereA |
| 129 | 129 | glm::vec3 AtoB = sphereB.getTranslation() - sphereA.getTranslation(); |
| 130 | 130 | glm::vec3 expectedContactPoint = sphereA.getTranslation() + radiusA * glm::normalize(AtoB); |
| 131 | 131 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 132 | − if (fabs(inaccuracy) > EPSILON) { | |
| 132 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 133 | 133 | std::cout << __FILE__ << ":" << __LINE__ |
| 134 | 134 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 135 | 135 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -145,21 +145,21 @@ void ShapeColliderTests::sphereTouchesSphere() { · 9 unmodified lines | ||
| 145 | 145 | } else { |
| 146 | 146 | ++numCollisions; |
| 147 | 147 | } |
| 148 | − | |
| 148 | + | |
| 149 | 149 | // penetration points from sphereA into sphereB |
| 150 | 150 | CollisionInfo* collision = collisions.getCollision(numCollisions - 1); |
| 151 | 151 | float inaccuracy = glm::length(collision->_penetration + expectedPenetration); |
| 152 | − if (fabs(inaccuracy) > EPSILON) { | |
| 152 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 153 | 153 | std::cout << __FILE__ << ":" << __LINE__ |
| 154 | 154 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 155 | 155 | << " actual = " << collision->_penetration << std::endl; |
| 156 | 156 | } |
| 157 | − | |
| 157 | + | |
| 158 | 158 | // contactPoint is on surface of sphereA |
| 159 | 159 | glm::vec3 BtoA = sphereA.getTranslation() - sphereB.getTranslation(); |
| 160 | 160 | glm::vec3 expectedContactPoint = sphereB.getTranslation() + radiusB * glm::normalize(BtoA); |
| 161 | 161 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 162 | − if (fabs(inaccuracy) > EPSILON) { | |
| 162 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 163 | 163 | std::cout << __FILE__ << ":" << __LINE__ |
| 164 | 164 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 165 | 165 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -175,7 +175,7 @@ void ShapeColliderTests::sphereMissesCapsule() { · 9 unmodified lines | ||
| 175 | 175 | float halfHeightB = 1.7f; |
| 176 | 176 | float axialOffset = totalRadius + 1.1f * halfHeightB; |
| 177 | 177 | float radialOffset = 1.2f * radiusA + 1.3f * radiusB; |
| 178 | − | |
| 178 | + | |
| 179 | 179 | SphereShape sphereA(radiusA); |
| 180 | 180 | CapsuleShape capsuleB(radiusB, halfHeightB); |
| 181 | 181 | |
| @@ -228,7 +228,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 46 unmodified lines | ||
| 228 | 228 | float alpha = 0.5f; |
| 229 | 229 | float beta = 0.5f; |
| 230 | 230 | float radialOffset = alpha * radiusA + beta * radiusB; |
| 231 | − | |
| 231 | + | |
| 232 | 232 | SphereShape sphereA(radiusA); |
| 233 | 233 | CapsuleShape capsuleB(radiusB, halfHeightB); |
| 234 | 234 | |
| @@ -245,21 +245,21 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 10 unmodified lines | ||
| 245 | 245 | } else { |
| 246 | 246 | ++numCollisions; |
| 247 | 247 | } |
| 248 | − | |
| 248 | + | |
| 249 | 249 | // penetration points from sphereA into capsuleB |
| 250 | 250 | CollisionInfo* collision = collisions.getCollision(numCollisions - 1); |
| 251 | 251 | glm::vec3 expectedPenetration = (radialOffset - totalRadius) * xAxis; |
| 252 | 252 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 253 | − if (fabs(inaccuracy) > EPSILON) { | |
| 253 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 254 | 254 | std::cout << __FILE__ << ":" << __LINE__ |
| 255 | 255 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 256 | 256 | << " actual = " << collision->_penetration << std::endl; |
| 257 | 257 | } |
| 258 | − | |
| 258 | + | |
| 259 | 259 | // contactPoint is on surface of sphereA |
| 260 | 260 | glm::vec3 expectedContactPoint = sphereA.getTranslation() - radiusA * xAxis; |
| 261 | 261 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 262 | − if (fabs(inaccuracy) > EPSILON) { | |
| 262 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 263 | 263 | std::cout << __FILE__ << ":" << __LINE__ |
| 264 | 264 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 265 | 265 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -273,7 +273,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 7 unmodified lines | ||
| 273 | 273 | } else { |
| 274 | 274 | ++numCollisions; |
| 275 | 275 | } |
| 276 | − | |
| 276 | + | |
| 277 | 277 | // penetration points from sphereA into capsuleB |
| 278 | 278 | collision = collisions.getCollision(numCollisions - 1); |
| 279 | 279 | expectedPenetration = - (radialOffset - totalRadius) * xAxis; |
| @@ -282,12 +282,12 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 2 unmodified lines | ||
| 282 | 282 | expectedPenetration *= -1.0f; |
| 283 | 283 | } |
| 284 | 284 | inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 285 | − if (fabs(inaccuracy) > EPSILON) { | |
| 285 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 286 | 286 | std::cout << __FILE__ << ":" << __LINE__ |
| 287 | 287 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 288 | 288 | << " actual = " << collision->_penetration << std::endl; |
| 289 | 289 | } |
| 290 | − | |
| 290 | + | |
| 291 | 291 | // contactPoint is on surface of capsuleB |
| 292 | 292 | glm::vec3 BtoA = sphereA.getTranslation() - capsuleB.getTranslation(); |
| 293 | 293 | glm::vec3 closestApproach = capsuleB.getTranslation() + glm::dot(BtoA, yAxis) * yAxis; |
| @@ -298,7 +298,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 4 unmodified lines | ||
| 298 | 298 | expectedContactPoint = closestApproach - radiusB * glm::normalize(BtoA - closestApproach); |
| 299 | 299 | } |
| 300 | 300 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 301 | − if (fabs(inaccuracy) > EPSILON) { | |
| 301 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 302 | 302 | std::cout << __FILE__ << ":" << __LINE__ |
| 303 | 303 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 304 | 304 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -307,7 +307,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 2 unmodified lines | ||
| 307 | 307 | { // sphereA hits end cap at axis |
| 308 | 308 | glm::vec3 axialOffset = (halfHeightB + alpha * radiusA + beta * radiusB) * yAxis; |
| 309 | 309 | sphereA.setTranslation(axialOffset); |
| 310 | − | |
| 310 | + | |
| 311 | 311 | if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions)) |
| 312 | 312 | { |
| 313 | 313 | std::cout << __FILE__ << ":" << __LINE__ |
| @@ -315,21 +315,21 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 1 unmodified line | ||
| 315 | 315 | } else { |
| 316 | 316 | ++numCollisions; |
| 317 | 317 | } |
| 318 | − | |
| 318 | + | |
| 319 | 319 | // penetration points from sphereA into capsuleB |
| 320 | 320 | CollisionInfo* collision = collisions.getCollision(numCollisions - 1); |
| 321 | 321 | glm::vec3 expectedPenetration = - ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; |
| 322 | 322 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 323 | − if (fabs(inaccuracy) > EPSILON) { | |
| 323 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 324 | 324 | std::cout << __FILE__ << ":" << __LINE__ |
| 325 | 325 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 326 | 326 | << " actual = " << collision->_penetration << std::endl; |
| 327 | 327 | } |
| 328 | − | |
| 328 | + | |
| 329 | 329 | // contactPoint is on surface of sphereA |
| 330 | 330 | glm::vec3 expectedContactPoint = sphereA.getTranslation() - radiusA * yAxis; |
| 331 | 331 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 332 | − if (fabs(inaccuracy) > EPSILON) { | |
| 332 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 333 | 333 | std::cout << __FILE__ << ":" << __LINE__ |
| 334 | 334 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 335 | 335 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -343,7 +343,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 7 unmodified lines | ||
| 343 | 343 | } else { |
| 344 | 344 | ++numCollisions; |
| 345 | 345 | } |
| 346 | − | |
| 346 | + | |
| 347 | 347 | // penetration points from sphereA into capsuleB |
| 348 | 348 | collision = collisions.getCollision(numCollisions - 1); |
| 349 | 349 | expectedPenetration = ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; |
| @@ -352,12 +352,12 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 2 unmodified lines | ||
| 352 | 352 | expectedPenetration *= -1.0f; |
| 353 | 353 | } |
| 354 | 354 | inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 355 | − if (fabs(inaccuracy) > EPSILON) { | |
| 355 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 356 | 356 | std::cout << __FILE__ << ":" << __LINE__ |
| 357 | 357 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 358 | 358 | << " actual = " << collision->_penetration << std::endl; |
| 359 | 359 | } |
| 360 | − | |
| 360 | + | |
| 361 | 361 | // contactPoint is on surface of capsuleB |
| 362 | 362 | glm::vec3 endPoint; |
| 363 | 363 | capsuleB.getEndPoint(endPoint); |
| @@ -367,7 +367,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 3 unmodified lines | ||
| 367 | 367 | expectedContactPoint = axialOffset - radiusA * yAxis; |
| 368 | 368 | } |
| 369 | 369 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 370 | − if (fabs(inaccuracy) > EPSILON) { | |
| 370 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 371 | 371 | std::cout << __FILE__ << ":" << __LINE__ |
| 372 | 372 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 373 | 373 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -376,7 +376,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 2 unmodified lines | ||
| 376 | 376 | { // sphereA hits start cap at axis |
| 377 | 377 | glm::vec3 axialOffset = - (halfHeightB + alpha * radiusA + beta * radiusB) * yAxis; |
| 378 | 378 | sphereA.setTranslation(axialOffset); |
| 379 | − | |
| 379 | + | |
| 380 | 380 | if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions)) |
| 381 | 381 | { |
| 382 | 382 | std::cout << __FILE__ << ":" << __LINE__ |
| @@ -384,21 +384,21 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 1 unmodified line | ||
| 384 | 384 | } else { |
| 385 | 385 | ++numCollisions; |
| 386 | 386 | } |
| 387 | − | |
| 387 | + | |
| 388 | 388 | // penetration points from sphereA into capsuleB |
| 389 | 389 | CollisionInfo* collision = collisions.getCollision(numCollisions - 1); |
| 390 | 390 | glm::vec3 expectedPenetration = ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; |
| 391 | 391 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 392 | − if (fabs(inaccuracy) > EPSILON) { | |
| 392 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 393 | 393 | std::cout << __FILE__ << ":" << __LINE__ |
| 394 | 394 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 395 | 395 | << " actual = " << collision->_penetration << std::endl; |
| 396 | 396 | } |
| 397 | − | |
| 397 | + | |
| 398 | 398 | // contactPoint is on surface of sphereA |
| 399 | 399 | glm::vec3 expectedContactPoint = sphereA.getTranslation() + radiusA * yAxis; |
| 400 | 400 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 401 | − if (fabs(inaccuracy) > EPSILON) { | |
| 401 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 402 | 402 | std::cout << __FILE__ << ":" << __LINE__ |
| 403 | 403 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 404 | 404 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -412,7 +412,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 7 unmodified lines | ||
| 412 | 412 | } else { |
| 413 | 413 | ++numCollisions; |
| 414 | 414 | } |
| 415 | − | |
| 415 | + | |
| 416 | 416 | // penetration points from sphereA into capsuleB |
| 417 | 417 | collision = collisions.getCollision(numCollisions - 1); |
| 418 | 418 | expectedPenetration = - ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; |
| @@ -421,12 +421,12 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 2 unmodified lines | ||
| 421 | 421 | expectedPenetration *= -1.0f; |
| 422 | 422 | } |
| 423 | 423 | inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 424 | − if (fabs(inaccuracy) > EPSILON) { | |
| 424 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 425 | 425 | std::cout << __FILE__ << ":" << __LINE__ |
| 426 | 426 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 427 | 427 | << " actual = " << collision->_penetration << std::endl; |
| 428 | 428 | } |
| 429 | − | |
| 429 | + | |
| 430 | 430 | // contactPoint is on surface of capsuleB |
| 431 | 431 | glm::vec3 startPoint; |
| 432 | 432 | capsuleB.getStartPoint(startPoint); |
| @@ -436,7 +436,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 3 unmodified lines | ||
| 436 | 436 | expectedContactPoint = axialOffset + radiusA * yAxis; |
| 437 | 437 | } |
| 438 | 438 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 439 | − if (fabs(inaccuracy) > EPSILON) { | |
| 439 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 440 | 440 | std::cout << __FILE__ << ":" << __LINE__ |
| 441 | 441 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 442 | 442 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -600,19 +600,19 @@ void ShapeColliderTests::capsuleTouchesCapsule() { · 157 unmodified lines | ||
| 600 | 600 | } else { |
| 601 | 601 | ++numCollisions; |
| 602 | 602 | } |
| 603 | − | |
| 603 | + | |
| 604 | 604 | CollisionInfo* collision = collisions.getCollision(numCollisions - 1); |
| 605 | 605 | glm::vec3 expectedPenetration = overlap * xAxis; |
| 606 | 606 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 607 | − if (fabs(inaccuracy) > EPSILON) { | |
| 607 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 608 | 608 | std::cout << __FILE__ << ":" << __LINE__ |
| 609 | 609 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 610 | 610 | << " actual = " << collision->_penetration << std::endl; |
| 611 | 611 | } |
| 612 | − | |
| 612 | + | |
| 613 | 613 | glm::vec3 expectedContactPoint = capsuleA.getTranslation() + radiusA * xAxis; |
| 614 | 614 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 615 | − if (fabs(inaccuracy) > EPSILON) { | |
| 615 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 616 | 616 | std::cout << __FILE__ << ":" << __LINE__ |
| 617 | 617 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 618 | 618 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -626,19 +626,19 @@ void ShapeColliderTests::capsuleTouchesCapsule() { · 7 unmodified lines | ||
| 626 | 626 | } else { |
| 627 | 627 | ++numCollisions; |
| 628 | 628 | } |
| 629 | − | |
| 629 | + | |
| 630 | 630 | collision = collisions.getCollision(numCollisions - 1); |
| 631 | 631 | expectedPenetration = - overlap * xAxis; |
| 632 | 632 | inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 633 | − if (fabs(inaccuracy) > EPSILON) { | |
| 633 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 634 | 634 | std::cout << __FILE__ << ":" << __LINE__ |
| 635 | 635 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 636 | 636 | << " actual = " << collision->_penetration << std::endl; |
| 637 | 637 | } |
| 638 | − | |
| 638 | + | |
| 639 | 639 | expectedContactPoint = capsuleB.getTranslation() - (radiusB + halfHeightB) * xAxis; |
| 640 | 640 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 641 | − if (fabs(inaccuracy) > EPSILON) { | |
| 641 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 642 | 642 | std::cout << __FILE__ << ":" << __LINE__ |
| 643 | 643 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 644 | 644 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -661,19 +661,19 @@ void ShapeColliderTests::capsuleTouchesCapsule() { · 16 unmodified lines | ||
| 661 | 661 | } else { |
| 662 | 662 | ++numCollisions; |
| 663 | 663 | } |
| 664 | − | |
| 664 | + | |
| 665 | 665 | CollisionInfo* collision = collisions.getCollision(numCollisions - 1); |
| 666 | 666 | glm::vec3 expectedPenetration = overlap * zAxis; |
| 667 | 667 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 668 | − if (fabs(inaccuracy) > EPSILON) { | |
| 668 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 669 | 669 | std::cout << __FILE__ << ":" << __LINE__ |
| 670 | 670 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 671 | 671 | << " actual = " << collision->_penetration << std::endl; |
| 672 | 672 | } |
| 673 | − | |
| 673 | + | |
| 674 | 674 | glm::vec3 expectedContactPoint = capsuleA.getTranslation() + radiusA * zAxis + shift * yAxis; |
| 675 | 675 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 676 | − if (fabs(inaccuracy) > EPSILON) { | |
| 676 | + if (fabsf(inaccuracy) > EPSILON) { | |
| 677 | 677 | std::cout << __FILE__ << ":" << __LINE__ |
| 678 | 678 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 679 | 679 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -683,7 +683,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() { · 3 unmodified lines | ||
| 683 | 683 | |
| 684 | 684 | void ShapeColliderTests::sphereMissesAACube() { |
| 685 | 685 | CollisionList collisions(16); |
| 686 | − | |
| 686 | + | |
| 687 | 687 | float sphereRadius = 1.0f; |
| 688 | 688 | glm::vec3 sphereCenter(0.0f); |
| 689 | 689 | |
| @@ -702,7 +702,7 @@ void ShapeColliderTests::sphereMissesAACube() { · 12 unmodified lines | ||
| 702 | 702 | |
| 703 | 703 | sphereCenter = cubeCenter + (0.5f * cubeSide + sphereRadius + offset) * faceNormal; |
| 704 | 704 | |
| 705 | − CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, | |
| 705 | + CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, | |
| 706 | 706 | cubeCenter, cubeSide, collisions); |
| 707 | 707 | |
| 708 | 708 | if (collision) { |
| @@ -742,9 +742,9 @@ void ShapeColliderTests::sphereMissesAACube() { · 33 unmodified lines | ||
| 742 | 742 | for (int m = 0; m < numSteps; ++m) { |
| 743 | 743 | sphereCenter = startPosition + ((float)m * delta) * thirdNormal + (sphereRadius + offset) * edgeNormal; |
| 744 | 744 | |
| 745 | − CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, | |
| 745 | + CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, | |
| 746 | 746 | cubeCenter, cubeSide, collisions); |
| 747 | − | |
| 747 | + | |
| 748 | 748 | if (collision) { |
| 749 | 749 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube edge." |
| 750 | 750 | << " edgeNormal = " << edgeNormal << std::endl; |
| @@ -779,10 +779,10 @@ void ShapeColliderTests::sphereMissesAACube() { · 28 unmodified lines | ||
| 779 | 779 | glm::quat rotation = glm::angleAxis(angle, cornerNormal); |
| 780 | 780 | glm::vec3 offsetAxis = rotation * nearbyAxis; |
| 781 | 781 | sphereCenter = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide) * cornerNormal + (sphereRadius + offset) * offsetAxis; |
| 782 | − | |
| 783 | − CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, | |
| 782 | + | |
| 783 | + CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, | |
| 784 | 784 | cubeCenter, cubeSide, collisions); |
| 785 | − | |
| 785 | + | |
| 786 | 786 | if (collision) { |
| 787 | 787 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube corner." |
| 788 | 788 | << " cornerNormal = " << cornerNormal << std::endl; |
| @@ -796,7 +796,7 @@ void ShapeColliderTests::sphereMissesAACube() { · 7 unmodified lines | ||
| 796 | 796 | |
| 797 | 797 | void ShapeColliderTests::sphereTouchesAACubeFaces() { |
| 798 | 798 | CollisionList collisions(16); |
| 799 | − | |
| 799 | + | |
| 800 | 800 | float sphereRadius = 1.13f; |
| 801 | 801 | glm::vec3 sphereCenter(0.0f); |
| 802 | 802 | |
| @@ -817,38 +817,38 @@ void ShapeColliderTests::sphereTouchesAACubeFaces() { · 14 unmodified lines | ||
| 817 | 817 | float parallelOffset = 0.5f * cubeSide + sphereRadius - overlap; |
| 818 | 818 | float perpOffset = 0.25f * cubeSide; |
| 819 | 819 | glm::vec3 expectedPenetration = - overlap * faceNormal; |
| 820 | − | |
| 821 | − // We rotate the position of the sphereCenter about a circle on the cube face so that | |
| 822 | − // it hits the same face in multiple spots. The penetration should be invarient for | |
| 820 | + | |
| 821 | + // We rotate the position of the sphereCenter about a circle on the cube face so that | |
| 822 | + // it hits the same face in multiple spots. The penetration should be invarient for | |
| 823 | 823 | // all collisions. |
| 824 | 824 | float delta = TWO_PI / 4.0f; |
| 825 | 825 | for (float angle = 0; angle < TWO_PI + EPSILON; angle += delta) { |
| 826 | 826 | glm::quat rotation = glm::angleAxis(angle, faceNormal); |
| 827 | 827 | glm::vec3 perpAxis = rotation * faceNormals[(i + 1) % numDirections]; |
| 828 | − | |
| 828 | + | |
| 829 | 829 | sphereCenter = cubeCenter + parallelOffset * faceNormal + perpOffset * perpAxis; |
| 830 | − | |
| 831 | − CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, | |
| 830 | + | |
| 831 | + CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, | |
| 832 | 832 | cubeCenter, cubeSide, collisions); |
| 833 | − | |
| 833 | + | |
| 834 | 834 | if (!collision) { |
| 835 | 835 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide outside cube face." |
| 836 | − << " faceNormal = " << faceNormal | |
| 836 | + << " faceNormal = " << faceNormal | |
| 837 | 837 | << std::endl; |
| 838 | 838 | break; |
| 839 | 839 | } |
| 840 | − | |
| 840 | + | |
| 841 | 841 | if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) { |
| 842 | − std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration | |
| 842 | + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration | |
| 843 | 843 | << " expected " << expectedPenetration << " faceNormal = " << faceNormal << std::endl; |
| 844 | 844 | } |
| 845 | − | |
| 845 | + | |
| 846 | 846 | glm::vec3 expectedContact = sphereCenter - sphereRadius * faceNormal; |
| 847 | 847 | if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) { |
| 848 | − std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint | |
| 848 | + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint | |
| 849 | 849 | << " expected " << expectedContact << " faceNormal = " << faceNormal << std::endl; |
| 850 | 850 | } |
| 851 | − | |
| 851 | + | |
| 852 | 852 | if (collision->getShapeA()) { |
| 853 | 853 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: collision->_shapeA should be NULL" << std::endl; |
| 854 | 854 | } |
| @@ -857,32 +857,32 @@ void ShapeColliderTests::sphereTouchesAACubeFaces() { · 2 unmodified lines | ||
| 857 | 857 | } |
| 858 | 858 | } |
| 859 | 859 | } |
| 860 | − | |
| 860 | + | |
| 861 | 861 | // inside |
| 862 | 862 | { |
| 863 | 863 | collisions.clear(); |
| 864 | 864 | float overlap = 1.25f * sphereRadius; |
| 865 | 865 | float sphereOffset = 0.5f * cubeSide + sphereRadius - overlap; |
| 866 | 866 | sphereCenter = cubeCenter + sphereOffset * faceNormal; |
| 867 | − | |
| 868 | − CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, | |
| 867 | + | |
| 868 | + CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, | |
| 869 | 869 | cubeCenter, cubeSide, collisions); |
| 870 | − | |
| 870 | + | |
| 871 | 871 | if (!collision) { |
| 872 | − std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide inside cube face." | |
| 872 | + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide inside cube face." | |
| 873 | 873 | << " faceNormal = " << faceNormal << std::endl; |
| 874 | 874 | break; |
| 875 | 875 | } |
| 876 | − | |
| 876 | + | |
| 877 | 877 | glm::vec3 expectedPenetration = - overlap * faceNormal; |
| 878 | 878 | if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) { |
| 879 | − std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration | |
| 879 | + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration | |
| 880 | 880 | << " expected " << expectedPenetration << " faceNormal = " << faceNormal << std::endl; |
| 881 | 881 | } |
| 882 | − | |
| 882 | + | |
| 883 | 883 | glm::vec3 expectedContact = sphereCenter - sphereRadius * faceNormal; |
| 884 | 884 | if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) { |
| 885 | − std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint | |
| 885 | + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint | |
| 886 | 886 | << " expected " << expectedContact << " faceNormal = " << faceNormal << std::endl; |
| 887 | 887 | } |
| 888 | 888 | } |
| @@ -892,14 +892,14 @@ void ShapeColliderTests::sphereTouchesAACubeFaces() { · 3 unmodified lines | ||
| 892 | 892 | |
| 893 | 893 | void ShapeColliderTests::sphereTouchesAACubeEdges() { |
| 894 | 894 | CollisionList collisions(20); |
| 895 | − | |
| 895 | + | |
| 896 | 896 | float sphereRadius = 1.37f; |
| 897 | 897 | glm::vec3 sphereCenter(0.0f); |
| 898 | 898 | |
| 899 | 899 | glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f); |
| 900 | 900 | float cubeSide = 2.98f; |
| 901 | 901 | |
| 902 | − float overlap = 0.25 * sphereRadius; | |
| 902 | + float overlap = 0.25f * sphereRadius; | |
| 903 | 903 | int numSteps = 5; |
| 904 | 904 | |
| 905 | 905 | glm::vec3 faceNormals[] = {xAxis, yAxis, zAxis}; |
| @@ -935,23 +935,23 @@ void ShapeColliderTests::sphereTouchesAACubeEdges() { · 29 unmodified lines | ||
| 935 | 935 | for (int m = 0; m < numSteps; ++m) { |
| 936 | 936 | sphereCenter = startPosition + ((float)m * delta) * thirdNormal + (sphereRadius - overlap) * edgeNormal; |
| 937 | 937 | |
| 938 | − CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, | |
| 938 | + CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, | |
| 939 | 939 | cubeCenter, cubeSide, collisions); |
| 940 | − | |
| 940 | + | |
| 941 | 941 | if (!collision) { |
| 942 | 942 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube edge." |
| 943 | 943 | << " edgeNormal = " << edgeNormal << std::endl; |
| 944 | 944 | break; |
| 945 | 945 | } |
| 946 | − | |
| 946 | + | |
| 947 | 947 | if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) { |
| 948 | − std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration | |
| 948 | + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration | |
| 949 | 949 | << " expected " << expectedPenetration << " edgeNormal = " << edgeNormal << std::endl; |
| 950 | 950 | } |
| 951 | − | |
| 951 | + | |
| 952 | 952 | glm::vec3 expectedContact = sphereCenter - sphereRadius * edgeNormal; |
| 953 | 953 | if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) { |
| 954 | − std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint | |
| 954 | + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint | |
| 955 | 955 | << " expected " << expectedContact << " edgeNormal = " << edgeNormal << std::endl; |
| 956 | 956 | } |
| 957 | 957 | } |
| @@ -963,14 +963,14 @@ void ShapeColliderTests::sphereTouchesAACubeEdges() { · 5 unmodified lines | ||
| 963 | 963 | |
| 964 | 964 | void ShapeColliderTests::sphereTouchesAACubeCorners() { |
| 965 | 965 | CollisionList collisions(20); |
| 966 | − | |
| 966 | + | |
| 967 | 967 | float sphereRadius = 1.37f; |
| 968 | 968 | glm::vec3 sphereCenter(0.0f); |
| 969 | 969 | |
| 970 | 970 | glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f); |
| 971 | 971 | float cubeSide = 2.98f; |
| 972 | 972 | |
| 973 | − float overlap = 0.25 * sphereRadius; | |
| 973 | + float overlap = 0.25f * sphereRadius; | |
| 974 | 974 | int numSteps = 5; |
| 975 | 975 | |
| 976 | 976 | glm::vec3 faceNormals[] = {xAxis, yAxis, zAxis}; |
| @@ -997,25 +997,25 @@ void ShapeColliderTests::sphereTouchesAACubeCorners() { · 20 unmodified lines | ||
| 997 | 997 | glm::quat rotation = glm::angleAxis(angle, cornerNormal); |
| 998 | 998 | glm::vec3 offsetAxis = rotation * nearbyAxis; |
| 999 | 999 | sphereCenter = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide) * cornerNormal + (sphereRadius - overlap) * offsetAxis; |
| 1000 | − | |
| 1001 | − CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, | |
| 1000 | + | |
| 1001 | + CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, | |
| 1002 | 1002 | cubeCenter, cubeSide, collisions); |
| 1003 | − | |
| 1003 | + | |
| 1004 | 1004 | if (!collision) { |
| 1005 | 1005 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube corner." |
| 1006 | 1006 | << " cornerNormal = " << cornerNormal << std::endl; |
| 1007 | 1007 | break; |
| 1008 | 1008 | } |
| 1009 | − | |
| 1009 | + | |
| 1010 | 1010 | glm::vec3 expectedPenetration = - overlap * offsetAxis; |
| 1011 | 1011 | if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) { |
| 1012 | − std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration | |
| 1012 | + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration | |
| 1013 | 1013 | << " expected " << expectedPenetration << " cornerNormal = " << cornerNormal << std::endl; |
| 1014 | 1014 | } |
| 1015 | − | |
| 1015 | + | |
| 1016 | 1016 | glm::vec3 expectedContact = sphereCenter - sphereRadius * offsetAxis; |
| 1017 | 1017 | if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) { |
| 1018 | − std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint | |
| 1018 | + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint | |
| 1019 | 1019 | << " expected " << expectedContact << " cornerNormal = " << cornerNormal << std::endl; |
| 1020 | 1020 | } |
| 1021 | 1021 | } |
| @@ -1026,7 +1026,7 @@ void ShapeColliderTests::sphereTouchesAACubeCorners() { · 4 unmodified lines | ||
| 1026 | 1026 | |
| 1027 | 1027 | void ShapeColliderTests::capsuleMissesAACube() { |
| 1028 | 1028 | CollisionList collisions(16); |
| 1029 | − | |
| 1029 | + | |
| 1030 | 1030 | float capsuleRadius = 1.0f; |
| 1031 | 1031 | |
| 1032 | 1032 | glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f); |
| @@ -1046,7 +1046,7 @@ void ShapeColliderTests::capsuleMissesAACube() { · 13 unmodified lines | ||
| 1046 | 1046 | glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections]; |
| 1047 | 1047 | |
| 1048 | 1048 | // pick a random point somewhere above the face |
| 1049 | − glm::vec3 startPoint = cubeCenter + (cubeSide + capsuleRadius) * faceNormal + | |
| 1049 | + glm::vec3 startPoint = cubeCenter + (cubeSide + capsuleRadius) * faceNormal + | |
| 1050 | 1050 | (cubeSide * (randFloat() - 0.5f)) * secondNormal + |
| 1051 | 1051 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1052 | 1052 | |
| @@ -1097,23 +1097,23 @@ void ShapeColliderTests::capsuleMissesAACube() { · 44 unmodified lines | ||
| 1097 | 1097 | glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal); |
| 1098 | 1098 | |
| 1099 | 1099 | // pick a random point somewhere above the edge |
| 1100 | − glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_2 * cubeSide + capsuleRadius) * edgeNormal + | |
| 1100 | + glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_2 * cubeSide + capsuleRadius) * edgeNormal + | |
| 1101 | 1101 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1102 | − | |
| 1102 | + | |
| 1103 | 1103 | // pick a second random point slightly more than one radius above the edge |
| 1104 | 1104 | glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide + capsuleRadius + offset) * edgeNormal + |
| 1105 | 1105 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1106 | − | |
| 1106 | + | |
| 1107 | 1107 | // randomly swap the points so capsule axis may point toward or away from edge |
| 1108 | 1108 | if (randFloat() > 0.5f) { |
| 1109 | 1109 | glm::vec3 temp = startPoint; |
| 1110 | 1110 | startPoint = endPoint; |
| 1111 | 1111 | endPoint = temp; |
| 1112 | 1112 | } |
| 1113 | − | |
| 1113 | + | |
| 1114 | 1114 | // create a capsule between the points |
| 1115 | 1115 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); |
| 1116 | − | |
| 1116 | + | |
| 1117 | 1117 | // collide capsule with cube |
| 1118 | 1118 | bool hit = ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions); |
| 1119 | 1119 | if (hit) { |
| @@ -1138,24 +1138,24 @@ void ShapeColliderTests::capsuleMissesAACube() { · 18 unmodified lines | ||
| 1138 | 1138 | glm::vec3 cornerNormal = glm::normalize(firstNormal + secondNormal + thirdNormal); |
| 1139 | 1139 | |
| 1140 | 1140 | // pick a random point somewhere above the corner |
| 1141 | − glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_3 * cubeSide + capsuleRadius) * cornerNormal + | |
| 1141 | + glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_3 * cubeSide + capsuleRadius) * cornerNormal + | |
| 1142 | 1142 | (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal + |
| 1143 | 1143 | (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal + |
| 1144 | 1144 | (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1145 | − | |
| 1145 | + | |
| 1146 | 1146 | // pick a second random point slightly more than one radius above the corner |
| 1147 | 1147 | glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide + capsuleRadius + offset) * cornerNormal; |
| 1148 | − | |
| 1148 | + | |
| 1149 | 1149 | // randomly swap the points so capsule axis may point toward or away from corner |
| 1150 | 1150 | if (randFloat() > 0.5f) { |
| 1151 | 1151 | glm::vec3 temp = startPoint; |
| 1152 | 1152 | startPoint = endPoint; |
| 1153 | 1153 | endPoint = temp; |
| 1154 | 1154 | } |
| 1155 | − | |
| 1155 | + | |
| 1156 | 1156 | // create a capsule between the points |
| 1157 | 1157 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); |
| 1158 | − | |
| 1158 | + | |
| 1159 | 1159 | // collide capsule with cube |
| 1160 | 1160 | if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { |
| 1161 | 1161 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube face." |
| @@ -1190,7 +1190,7 @@ void ShapeColliderTests::capsuleMissesAACube() { · 28 unmodified lines | ||
| 1190 | 1190 | glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal); |
| 1191 | 1191 | |
| 1192 | 1192 | // pick a random point somewhere along the edge |
| 1193 | − glm::vec3 edgePoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide) * edgeNormal + | |
| 1193 | + glm::vec3 edgePoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide) * edgeNormal + | |
| 1194 | 1194 | ((cubeSide - 2.0f * offset) * (randFloat() - 0.5f)) * thirdNormal; |
| 1195 | 1195 | |
| 1196 | 1196 | // pick a random normal that is deflected slightly from edgeNormal |
| @@ -1207,10 +1207,10 @@ void ShapeColliderTests::capsuleMissesAACube() { · 10 unmodified lines | ||
| 1207 | 1207 | // now we can compute the capsule endpoints |
| 1208 | 1208 | glm::vec3 endPoint = axisPoint + (0.5f * capsuleLength * randFloat()) * axisDirection; |
| 1209 | 1209 | glm::vec3 startPoint = axisPoint - (0.5f * capsuleLength * randFloat()) * axisDirection; |
| 1210 | − | |
| 1210 | + | |
| 1211 | 1211 | // create a capsule between the points |
| 1212 | 1212 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); |
| 1213 | − | |
| 1213 | + | |
| 1214 | 1214 | // collide capsule with cube |
| 1215 | 1215 | if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { |
| 1216 | 1216 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube" |
| @@ -1241,7 +1241,7 @@ void ShapeColliderTests::capsuleMissesAACube() { · 24 unmodified lines | ||
| 1241 | 1241 | |
| 1242 | 1242 | // pick a random point somewhere above the corner |
| 1243 | 1243 | glm::vec3 corner = cubeCenter + (0.5f * cubeSide) * (firstNormal + secondNormal + thirdNormal); |
| 1244 | − glm::vec3 startPoint = corner + (3.0f * cubeSide) * cornerNormal + | |
| 1244 | + glm::vec3 startPoint = corner + (3.0f * cubeSide) * cornerNormal + | |
| 1245 | 1245 | (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal + |
| 1246 | 1246 | (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal + |
| 1247 | 1247 | (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| @@ -1256,10 +1256,10 @@ void ShapeColliderTests::capsuleMissesAACube() { · 8 unmodified lines | ||
| 1256 | 1256 | startPoint = endPoint; |
| 1257 | 1257 | endPoint = temp; |
| 1258 | 1258 | } |
| 1259 | − | |
| 1259 | + | |
| 1260 | 1260 | // create a capsule between the points |
| 1261 | 1261 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); |
| 1262 | − | |
| 1262 | + | |
| 1263 | 1263 | // collide capsule with cube |
| 1264 | 1264 | if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { |
| 1265 | 1265 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube" |
| @@ -1269,7 +1269,7 @@ void ShapeColliderTests::capsuleMissesAACube() { · 3 unmodified lines | ||
| 1269 | 1269 | } |
| 1270 | 1270 | } |
| 1271 | 1271 | |
| 1272 | − // capsule sides almost hit cube faces | |
| 1272 | + // capsule sides almost hit cube faces | |
| 1273 | 1273 | // these are the steps along the capsuleAxis where we'll put the capsule endpoints |
| 1274 | 1274 | float steps[] = { -1.0f, 2.0f, 0.25f, 0.75f, -1.0f }; |
| 1275 | 1275 | |
| @@ -1280,9 +1280,9 @@ void ShapeColliderTests::capsuleMissesAACube() { · 4 unmodified lines | ||
| 1280 | 1280 | glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections]; |
| 1281 | 1281 | |
| 1282 | 1282 | // pick two random point on opposite edges of the face |
| 1283 | − glm::vec3 firstEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal + secondNormal) + | |
| 1283 | + glm::vec3 firstEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal + secondNormal) + | |
| 1284 | 1284 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1285 | − glm::vec3 secondEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal - secondNormal) + | |
| 1285 | + glm::vec3 secondEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal - secondNormal) + | |
| 1286 | 1286 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1287 | 1287 | |
| 1288 | 1288 | // compute the un-normalized axis for the capsule |
| @@ -1309,7 +1309,7 @@ void ShapeColliderTests::capsuleMissesAACube() { · 20 unmodified lines | ||
| 1309 | 1309 | |
| 1310 | 1310 | void ShapeColliderTests::capsuleTouchesAACube() { |
| 1311 | 1311 | CollisionList collisions(16); |
| 1312 | − | |
| 1312 | + | |
| 1313 | 1313 | float capsuleRadius = 1.0f; |
| 1314 | 1314 | |
| 1315 | 1315 | glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f); |
| @@ -1330,12 +1330,12 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 14 unmodified lines | ||
| 1330 | 1330 | glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections]; |
| 1331 | 1331 | |
| 1332 | 1332 | // pick a random point somewhere above the face |
| 1333 | − glm::vec3 startPoint = cubeCenter + (cubeSide + capsuleRadius) * faceNormal + | |
| 1333 | + glm::vec3 startPoint = cubeCenter + (cubeSide + capsuleRadius) * faceNormal + | |
| 1334 | 1334 | (cubeSide * (randFloat() - 0.5f)) * secondNormal + |
| 1335 | 1335 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1336 | 1336 | |
| 1337 | 1337 | // pick a second random point slightly less than one radius above the face |
| 1338 | − // (but reduce width of range by 2*overlap to prevent the penetration from | |
| 1338 | + // (but reduce width of range by 2*overlap to prevent the penetration from | |
| 1339 | 1339 | // registering against other faces) |
| 1340 | 1340 | glm::vec3 endPoint = cubeCenter + (0.5f * cubeSide + capsuleRadius - overlap) * faceNormal + |
| 1341 | 1341 | ((cubeSide - 2.0f * overlap) * (randFloat() - 0.5f)) * secondNormal + |
| @@ -1365,25 +1365,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 23 unmodified lines | ||
| 1365 | 1365 | << " ERROR: null collision with faceNormal = " << faceNormal << std::endl; |
| 1366 | 1366 | return; |
| 1367 | 1367 | } |
| 1368 | − | |
| 1369 | − // penetration points from capsule into cube | |
| 1368 | + | |
| 1369 | + // penetration points from capsule into cube | |
| 1370 | 1370 | glm::vec3 expectedPenetration = - overlap * faceNormal; |
| 1371 | 1371 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 1372 | − if (fabs(inaccuracy) > allowableError) { | |
| 1372 | + if (fabsf(inaccuracy) > allowableError) { | |
| 1373 | 1373 | std::cout << __FILE__ << ":" << __LINE__ |
| 1374 | 1374 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 1375 | − << " actual = " << collision->_penetration | |
| 1375 | + << " actual = " << collision->_penetration | |
| 1376 | 1376 | << " faceNormal = " << faceNormal |
| 1377 | 1377 | << std::endl; |
| 1378 | 1378 | } |
| 1379 | − | |
| 1379 | + | |
| 1380 | 1380 | // contactPoint is on surface of capsule |
| 1381 | 1381 | glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * faceNormal; |
| 1382 | 1382 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 1383 | − if (fabs(inaccuracy) > allowableError) { | |
| 1383 | + if (fabsf(inaccuracy) > allowableError) { | |
| 1384 | 1384 | std::cout << __FILE__ << ":" << __LINE__ |
| 1385 | 1385 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 1386 | − << " actual = " << collision->_contactPoint | |
| 1386 | + << " actual = " << collision->_contactPoint | |
| 1387 | 1387 | << " faceNormal = " << faceNormal |
| 1388 | 1388 | << std::endl; |
| 1389 | 1389 | } |
| @@ -1414,24 +1414,24 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 24 unmodified lines | ||
| 1414 | 1414 | glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal); |
| 1415 | 1415 | |
| 1416 | 1416 | // pick a random point somewhere above the edge |
| 1417 | − glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_2 * cubeSide + capsuleRadius) * edgeNormal + | |
| 1417 | + glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_2 * cubeSide + capsuleRadius) * edgeNormal + | |
| 1418 | 1418 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1419 | − | |
| 1419 | + | |
| 1420 | 1420 | // pick a second random point slightly less than one radius above the edge |
| 1421 | 1421 | glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide + capsuleRadius - overlap) * edgeNormal + |
| 1422 | 1422 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1423 | 1423 | glm::vec3 collidingPoint = endPoint; |
| 1424 | − | |
| 1424 | + | |
| 1425 | 1425 | // randomly swap the points so capsule axis may point toward or away from edge |
| 1426 | 1426 | if (randFloat() > 0.5f) { |
| 1427 | 1427 | glm::vec3 temp = startPoint; |
| 1428 | 1428 | startPoint = endPoint; |
| 1429 | 1429 | endPoint = temp; |
| 1430 | 1430 | } |
| 1431 | − | |
| 1431 | + | |
| 1432 | 1432 | // create a capsule between the points |
| 1433 | 1433 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); |
| 1434 | − | |
| 1434 | + | |
| 1435 | 1435 | // collide capsule with cube |
| 1436 | 1436 | if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { |
| 1437 | 1437 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" |
| @@ -1444,25 +1444,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 6 unmodified lines | ||
| 1444 | 1444 | << " ERROR: null collision with edgeNormal = " << edgeNormal << std::endl; |
| 1445 | 1445 | return; |
| 1446 | 1446 | } |
| 1447 | − | |
| 1448 | − // penetration points from capsule into cube | |
| 1447 | + | |
| 1448 | + // penetration points from capsule into cube | |
| 1449 | 1449 | glm::vec3 expectedPenetration = - overlap * edgeNormal; |
| 1450 | 1450 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 1451 | − if (fabs(inaccuracy) > allowableError) { | |
| 1451 | + if (fabsf(inaccuracy) > allowableError) { | |
| 1452 | 1452 | std::cout << __FILE__ << ":" << __LINE__ |
| 1453 | 1453 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 1454 | − << " actual = " << collision->_penetration | |
| 1454 | + << " actual = " << collision->_penetration | |
| 1455 | 1455 | << " edgeNormal = " << edgeNormal |
| 1456 | 1456 | << std::endl; |
| 1457 | 1457 | } |
| 1458 | − | |
| 1458 | + | |
| 1459 | 1459 | // contactPoint is on surface of capsule |
| 1460 | 1460 | glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * edgeNormal; |
| 1461 | 1461 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 1462 | − if (fabs(inaccuracy) > allowableError) { | |
| 1462 | + if (fabsf(inaccuracy) > allowableError) { | |
| 1463 | 1463 | std::cout << __FILE__ << ":" << __LINE__ |
| 1464 | 1464 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 1465 | − << " actual = " << collision->_contactPoint | |
| 1465 | + << " actual = " << collision->_contactPoint | |
| 1466 | 1466 | << " edgeNormal = " << edgeNormal |
| 1467 | 1467 | << std::endl; |
| 1468 | 1468 | } |
| @@ -1484,25 +1484,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 15 unmodified lines | ||
| 1484 | 1484 | glm::vec3 cornerNormal = glm::normalize(firstNormal + secondNormal + thirdNormal); |
| 1485 | 1485 | |
| 1486 | 1486 | // pick a random point somewhere above the corner |
| 1487 | − glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_3 * cubeSide + capsuleRadius) * cornerNormal + | |
| 1487 | + glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_3 * cubeSide + capsuleRadius) * cornerNormal + | |
| 1488 | 1488 | (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal + |
| 1489 | 1489 | (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal + |
| 1490 | 1490 | (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1491 | − | |
| 1491 | + | |
| 1492 | 1492 | // pick a second random point slightly less than one radius above the corner |
| 1493 | 1493 | glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide + capsuleRadius - overlap) * cornerNormal; |
| 1494 | 1494 | glm::vec3 collidingPoint = endPoint; |
| 1495 | − | |
| 1495 | + | |
| 1496 | 1496 | // randomly swap the points so capsule axis may point toward or away from corner |
| 1497 | 1497 | if (randFloat() > 0.5f) { |
| 1498 | 1498 | glm::vec3 temp = startPoint; |
| 1499 | 1499 | startPoint = endPoint; |
| 1500 | 1500 | endPoint = temp; |
| 1501 | 1501 | } |
| 1502 | − | |
| 1502 | + | |
| 1503 | 1503 | // create a capsule between the points |
| 1504 | 1504 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); |
| 1505 | − | |
| 1505 | + | |
| 1506 | 1506 | // collide capsule with cube |
| 1507 | 1507 | if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { |
| 1508 | 1508 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" |
| @@ -1515,25 +1515,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 6 unmodified lines | ||
| 1515 | 1515 | << " ERROR: null collision with cornerNormal = " << cornerNormal << std::endl; |
| 1516 | 1516 | return; |
| 1517 | 1517 | } |
| 1518 | − | |
| 1519 | − // penetration points from capsule into cube | |
| 1518 | + | |
| 1519 | + // penetration points from capsule into cube | |
| 1520 | 1520 | glm::vec3 expectedPenetration = - overlap * cornerNormal; |
| 1521 | 1521 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 1522 | − if (fabs(inaccuracy) > allowableError) { | |
| 1522 | + if (fabsf(inaccuracy) > allowableError) { | |
| 1523 | 1523 | std::cout << __FILE__ << ":" << __LINE__ |
| 1524 | 1524 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 1525 | − << " actual = " << collision->_penetration | |
| 1525 | + << " actual = " << collision->_penetration | |
| 1526 | 1526 | << " cornerNormal = " << cornerNormal |
| 1527 | 1527 | << std::endl; |
| 1528 | 1528 | } |
| 1529 | − | |
| 1529 | + | |
| 1530 | 1530 | // contactPoint is on surface of capsule |
| 1531 | 1531 | glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * cornerNormal; |
| 1532 | 1532 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 1533 | − if (fabs(inaccuracy) > allowableError) { | |
| 1533 | + if (fabsf(inaccuracy) > allowableError) { | |
| 1534 | 1534 | std::cout << __FILE__ << ":" << __LINE__ |
| 1535 | 1535 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 1536 | − << " actual = " << collision->_contactPoint | |
| 1536 | + << " actual = " << collision->_contactPoint | |
| 1537 | 1537 | << " cornerNormal = " << cornerNormal |
| 1538 | 1538 | << std::endl; |
| 1539 | 1539 | } |
| @@ -1566,7 +1566,7 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 26 unmodified lines | ||
| 1566 | 1566 | glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal); |
| 1567 | 1567 | |
| 1568 | 1568 | // pick a random point somewhere along the edge |
| 1569 | − glm::vec3 edgePoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide) * edgeNormal + | |
| 1569 | + glm::vec3 edgePoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide) * edgeNormal + | |
| 1570 | 1570 | ((cubeSide - 2.0f * overlap) * (randFloat() - 0.5f)) * thirdNormal; |
| 1571 | 1571 | |
| 1572 | 1572 | // pick a random normal that is deflected slightly from edgeNormal |
| @@ -1583,10 +1583,10 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 10 unmodified lines | ||
| 1583 | 1583 | // now we can compute the capsule endpoints |
| 1584 | 1584 | glm::vec3 endPoint = axisPoint + (0.5f * capsuleLength * randFloat()) * axisDirection; |
| 1585 | 1585 | glm::vec3 startPoint = axisPoint - (0.5f * capsuleLength * randFloat()) * axisDirection; |
| 1586 | − | |
| 1586 | + | |
| 1587 | 1587 | // create a capsule between the points |
| 1588 | 1588 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); |
| 1589 | − | |
| 1589 | + | |
| 1590 | 1590 | // collide capsule with cube |
| 1591 | 1591 | if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { |
| 1592 | 1592 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" |
| @@ -1599,25 +1599,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 6 unmodified lines | ||
| 1599 | 1599 | << " ERROR: null collision with edgeNormal = " << edgeNormal << std::endl; |
| 1600 | 1600 | return; |
| 1601 | 1601 | } |
| 1602 | − | |
| 1603 | − // penetration points from capsule into cube | |
| 1602 | + | |
| 1603 | + // penetration points from capsule into cube | |
| 1604 | 1604 | glm::vec3 expectedPenetration = - overlap * deflectedNormal; |
| 1605 | 1605 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 1606 | − if (fabs(inaccuracy) > allowableError / capsuleLength) { | |
| 1606 | + if (fabsf(inaccuracy) > allowableError / capsuleLength) { | |
| 1607 | 1607 | std::cout << __FILE__ << ":" << __LINE__ |
| 1608 | 1608 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 1609 | − << " actual = " << collision->_penetration | |
| 1609 | + << " actual = " << collision->_penetration | |
| 1610 | 1610 | << " edgeNormal = " << edgeNormal |
| 1611 | 1611 | << std::endl; |
| 1612 | 1612 | } |
| 1613 | − | |
| 1613 | + | |
| 1614 | 1614 | // contactPoint is on surface of capsule |
| 1615 | 1615 | glm::vec3 expectedContactPoint = axisPoint - capsuleRadius * deflectedNormal; |
| 1616 | 1616 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 1617 | − if (fabs(inaccuracy) > allowableError / capsuleLength) { | |
| 1617 | + if (fabsf(inaccuracy) > allowableError / capsuleLength) { | |
| 1618 | 1618 | std::cout << __FILE__ << ":" << __LINE__ |
| 1619 | 1619 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 1620 | − << " actual = " << collision->_contactPoint | |
| 1620 | + << " actual = " << collision->_contactPoint | |
| 1621 | 1621 | << " edgeNormal = " << edgeNormal |
| 1622 | 1622 | << std::endl; |
| 1623 | 1623 | } |
| @@ -1646,7 +1646,7 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 22 unmodified lines | ||
| 1646 | 1646 | |
| 1647 | 1647 | // pick a random point somewhere above the corner |
| 1648 | 1648 | glm::vec3 corner = cubeCenter + (0.5f * cubeSide) * (firstNormal + secondNormal + thirdNormal); |
| 1649 | − glm::vec3 startPoint = corner + (3.0f * cubeSide) * cornerNormal + | |
| 1649 | + glm::vec3 startPoint = corner + (3.0f * cubeSide) * cornerNormal + | |
| 1650 | 1650 | (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal + |
| 1651 | 1651 | (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal + |
| 1652 | 1652 | (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| @@ -1662,10 +1662,10 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 9 unmodified lines | ||
| 1662 | 1662 | startPoint = endPoint; |
| 1663 | 1663 | endPoint = temp; |
| 1664 | 1664 | } |
| 1665 | − | |
| 1665 | + | |
| 1666 | 1666 | // create a capsule between the points |
| 1667 | 1667 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); |
| 1668 | − | |
| 1668 | + | |
| 1669 | 1669 | // collide capsule with cube |
| 1670 | 1670 | if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { |
| 1671 | 1671 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" |
| @@ -1678,25 +1678,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 6 unmodified lines | ||
| 1678 | 1678 | << " ERROR: null collision with cornerNormal = " << cornerNormal << std::endl; |
| 1679 | 1679 | return; |
| 1680 | 1680 | } |
| 1681 | − | |
| 1682 | − // penetration points from capsule into cube | |
| 1681 | + | |
| 1682 | + // penetration points from capsule into cube | |
| 1683 | 1683 | glm::vec3 expectedPenetration = overlap * penetrationNormal; |
| 1684 | 1684 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 1685 | − if (fabs(inaccuracy) > allowableError) { | |
| 1685 | + if (fabsf(inaccuracy) > allowableError) { | |
| 1686 | 1686 | std::cout << __FILE__ << ":" << __LINE__ |
| 1687 | 1687 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 1688 | − << " actual = " << collision->_penetration | |
| 1688 | + << " actual = " << collision->_penetration | |
| 1689 | 1689 | << " cornerNormal = " << cornerNormal |
| 1690 | 1690 | << std::endl; |
| 1691 | 1691 | } |
| 1692 | − | |
| 1692 | + | |
| 1693 | 1693 | // contactPoint is on surface of capsule |
| 1694 | 1694 | glm::vec3 expectedContactPoint = collidingPoint + capsuleRadius * penetrationNormal; |
| 1695 | 1695 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 1696 | − if (fabs(inaccuracy) > allowableError) { | |
| 1696 | + if (fabsf(inaccuracy) > allowableError) { | |
| 1697 | 1697 | std::cout << __FILE__ << ":" << __LINE__ |
| 1698 | 1698 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 1699 | − << " actual = " << collision->_contactPoint | |
| 1699 | + << " actual = " << collision->_contactPoint | |
| 1700 | 1700 | << " cornerNormal = " << cornerNormal |
| 1701 | 1701 | << std::endl; |
| 1702 | 1702 | } |
| @@ -1704,7 +1704,7 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 1 unmodified line | ||
| 1704 | 1704 | } |
| 1705 | 1705 | } |
| 1706 | 1706 | |
| 1707 | − // capsule sides hit cube faces | |
| 1707 | + // capsule sides hit cube faces | |
| 1708 | 1708 | // these are the steps along the capsuleAxis where we'll put the capsule endpoints |
| 1709 | 1709 | float steps[] = { -1.0f, 2.0f, 0.25f, 0.75f, -1.0f }; |
| 1710 | 1710 | |
| @@ -1715,9 +1715,9 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 4 unmodified lines | ||
| 1715 | 1715 | glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections]; |
| 1716 | 1716 | |
| 1717 | 1717 | // pick two random point on opposite edges of the face |
| 1718 | − glm::vec3 firstEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal + secondNormal) + | |
| 1718 | + glm::vec3 firstEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal + secondNormal) + | |
| 1719 | 1719 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1720 | − glm::vec3 secondEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal - secondNormal) + | |
| 1720 | + glm::vec3 secondEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal - secondNormal) + | |
| 1721 | 1721 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1722 | 1722 | |
| 1723 | 1723 | // compute the un-normalized axis for the capsule |
| @@ -1742,7 +1742,7 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 18 unmodified lines | ||
| 1742 | 1742 | if (numCollisions != 2) { |
| 1743 | 1743 | std::cout << __FILE__ << ":" << __LINE__ |
| 1744 | 1744 | << " ERROR: capsule should hit cube face at two spots." |
| 1745 | − << " Expected collisions size of 2 but is actually " << numCollisions | |
| 1745 | + << " Expected collisions size of 2 but is actually " << numCollisions | |
| 1746 | 1746 | << ". faceNormal = " << faceNormal << std::endl; |
| 1747 | 1747 | break; |
| 1748 | 1748 | } |
| @@ -1764,33 +1764,33 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 15 unmodified lines | ||
| 1764 | 1764 | expectedContactPoints[0] = startPoint - capsuleRadius * faceNormal; |
| 1765 | 1765 | expectedContactPoints[1] = firstEdgeIntersection - overlap * faceNormal; |
| 1766 | 1766 | } |
| 1767 | − | |
| 1767 | + | |
| 1768 | 1768 | // verify each contact |
| 1769 | 1769 | for (int k = 0; k < 2; ++k) { |
| 1770 | 1770 | CollisionInfo* collision = collisions.getCollision(k); |
| 1771 | − // penetration points from capsule into cube | |
| 1771 | + // penetration points from capsule into cube | |
| 1772 | 1772 | glm::vec3 expectedPenetration = - overlap * faceNormal; |
| 1773 | 1773 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 1774 | − if (fabs(inaccuracy) > allowableError) { | |
| 1774 | + if (fabsf(inaccuracy) > allowableError) { | |
| 1775 | 1775 | std::cout << __FILE__ << ":" << __LINE__ |
| 1776 | 1776 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 1777 | − << " actual = " << collision->_penetration | |
| 1777 | + << " actual = " << collision->_penetration | |
| 1778 | 1778 | << " faceNormal = " << faceNormal |
| 1779 | 1779 | << std::endl; |
| 1780 | 1780 | } |
| 1781 | − | |
| 1782 | − // the order of the final contact points is undefined, so we | |
| 1783 | − // figure out which expected contact point is the closest to the real one | |
| 1781 | + | |
| 1782 | + // the order of the final contact points is undefined, so we | |
| 1783 | + // figure out which expected contact point is the closest to the real one | |
| 1784 | 1784 | // and then verify accuracy on that |
| 1785 | 1785 | float length0 = glm::length(collision->_contactPoint - expectedContactPoints[0]); |
| 1786 | 1786 | float length1 = glm::length(collision->_contactPoint - expectedContactPoints[1]); |
| 1787 | 1787 | glm::vec3 expectedContactPoint = (length0 < length1) ? expectedContactPoints[0] : expectedContactPoints[1]; |
| 1788 | 1788 | // contactPoint is on surface of capsule |
| 1789 | 1789 | inaccuracy = (length0 < length1) ? length0 : length1; |
| 1790 | − if (fabs(inaccuracy) > allowableError) { | |
| 1790 | + if (fabsf(inaccuracy) > allowableError) { | |
| 1791 | 1791 | std::cout << __FILE__ << ":" << __LINE__ |
| 1792 | 1792 | << " ERROR: bad contact: expectedContactPoint[" << k << "] = " << expectedContactPoint |
| 1793 | − << " actual = " << collision->_contactPoint | |
| 1793 | + << " actual = " << collision->_contactPoint | |
| 1794 | 1794 | << " faceNormal = " << faceNormal |
| 1795 | 1795 | << std::endl; |
| 1796 | 1796 | } |
| @@ -1817,14 +1817,14 @@ void ShapeColliderTests::rayHitsSphere() { · 20 unmodified lines | ||
| 1817 | 1817 | if (!sphere.findRayIntersection(intersection)) { |
| 1818 | 1818 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl; |
| 1819 | 1819 | } |
| 1820 | − | |
| 1820 | + | |
| 1821 | 1821 | float expectedDistance = startDistance - radius; |
| 1822 | 1822 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; |
| 1823 | 1823 | if (relativeError > EPSILON) { |
| 1824 | 1824 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray sphere intersection distance error = " << relativeError << std::endl; |
| 1825 | 1825 | } |
| 1826 | 1826 | if (intersection._hitShape != &sphere) { |
| 1827 | − std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at sphere" | |
| 1827 | + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at sphere" | |
| 1828 | 1828 | << std::endl; |
| 1829 | 1829 | } |
| 1830 | 1830 | } |
| @@ -1834,11 +1834,11 @@ void ShapeColliderTests::rayHitsSphere() { · 3 unmodified lines | ||
| 1834 | 1834 | RayIntersectionInfo intersection; |
| 1835 | 1835 | intersection._rayStart = glm::vec3(startDistance, startDistance, 0.0f); |
| 1836 | 1836 | intersection._rayDirection = - glm::normalize(intersection._rayStart); |
| 1837 | − | |
| 1837 | + | |
| 1838 | 1838 | if (!sphere.findRayIntersection(intersection)) { |
| 1839 | 1839 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl; |
| 1840 | 1840 | } |
| 1841 | − | |
| 1841 | + | |
| 1842 | 1842 | float expectedDistance = SQUARE_ROOT_OF_2 * startDistance - radius; |
| 1843 | 1843 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; |
| 1844 | 1844 | if (relativeError > EPSILON) { |
| @@ -1864,15 +1864,15 @@ void ShapeColliderTests::rayHitsSphere() { · 19 unmodified lines | ||
| 1864 | 1864 | |
| 1865 | 1865 | sphere.setRadius(radius); |
| 1866 | 1866 | sphere.setTranslation(rotation * translation); |
| 1867 | − | |
| 1867 | + | |
| 1868 | 1868 | if (!sphere.findRayIntersection(intersection)) { |
| 1869 | 1869 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl; |
| 1870 | 1870 | } |
| 1871 | − | |
| 1871 | + | |
| 1872 | 1872 | float expectedDistance = startDistance - radius; |
| 1873 | 1873 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; |
| 1874 | 1874 | if (relativeError > EPSILON) { |
| 1875 | − std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray sphere intersection distance error = " | |
| 1875 | + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray sphere intersection distance error = " | |
| 1876 | 1876 | << relativeError << std::endl; |
| 1877 | 1877 | } |
| 1878 | 1878 | } |
| @@ -1890,29 +1890,29 @@ void ShapeColliderTests::rayBarelyHitsSphere() { · 11 unmodified lines | ||
| 1890 | 1890 | RayIntersectionInfo intersection; |
| 1891 | 1891 | intersection._rayStart = glm::vec3(-startDistance, radius - delta, 0.0f); |
| 1892 | 1892 | intersection._rayDirection = xAxis; |
| 1893 | − | |
| 1893 | + | |
| 1894 | 1894 | // very simple ray along xAxis |
| 1895 | 1895 | if (!sphere.findRayIntersection(intersection)) { |
| 1896 | 1896 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely hit sphere" << std::endl; |
| 1897 | 1897 | } |
| 1898 | 1898 | if (intersection._hitShape != &sphere) { |
| 1899 | − std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at sphere" | |
| 1899 | + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at sphere" | |
| 1900 | 1900 | << std::endl; |
| 1901 | 1901 | } |
| 1902 | 1902 | } |
| 1903 | 1903 | |
| 1904 | 1904 | { |
| 1905 | − // translate and rotate the whole system... | |
| 1905 | + // translate and rotate the whole system... | |
| 1906 | 1906 | glm::vec3 axis = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f)); |
| 1907 | 1907 | glm::quat rotation = glm::angleAxis(0.987654321f, axis); |
| 1908 | 1908 | glm::vec3 translation(35.7f, 0.46f, -1.97f); |
| 1909 | − | |
| 1909 | + | |
| 1910 | 1910 | RayIntersectionInfo intersection; |
| 1911 | 1911 | intersection._rayStart = rotation * (intersection._rayStart + translation); |
| 1912 | 1912 | intersection._rayDirection = rotation * intersection._rayDirection; |
| 1913 | − | |
| 1913 | + | |
| 1914 | 1914 | sphere.setTranslation(rotation * translation); |
| 1915 | − | |
| 1915 | + | |
| 1916 | 1916 | // ...and test again |
| 1917 | 1917 | if (!sphere.findRayIntersection(intersection)) { |
| 1918 | 1918 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely hit sphere" << std::endl; |
| @@ -1934,19 +1934,19 @@ void ShapeColliderTests::rayBarelyMissesSphere() { · 15 unmodified lines | ||
| 1934 | 1934 | RayIntersectionInfo intersection; |
| 1935 | 1935 | intersection._rayStart = glm::vec3(-startDistance, radius + delta, 0.0f); |
| 1936 | 1936 | intersection._rayDirection = xAxis; |
| 1937 | − | |
| 1937 | + | |
| 1938 | 1938 | // very simple ray along xAxis |
| 1939 | 1939 | if (sphere.findRayIntersection(intersection)) { |
| 1940 | 1940 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely miss sphere" << std::endl; |
| 1941 | 1941 | } |
| 1942 | 1942 | if (intersection._hitDistance != FLT_MAX) { |
| 1943 | − std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" | |
| 1943 | + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" | |
| 1944 | 1944 | << std::endl; |
| 1945 | 1945 | } |
| 1946 | 1946 | } |
| 1947 | 1947 | |
| 1948 | 1948 | { |
| 1949 | − // translate and rotate the whole system... | |
| 1949 | + // translate and rotate the whole system... | |
| 1950 | 1950 | float angle = 0.987654321f; |
| 1951 | 1951 | glm::vec3 axis = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f)); |
| 1952 | 1952 | glm::quat rotation = glm::angleAxis(angle, axis); |
| @@ -1956,13 +1956,13 @@ void ShapeColliderTests::rayBarelyMissesSphere() { · 3 unmodified lines | ||
| 1956 | 1956 | intersection._rayStart = rotation * (glm::vec3(-startDistance, radius + delta, 0.0f) + translation); |
| 1957 | 1957 | intersection._rayDirection = rotation * xAxis; |
| 1958 | 1958 | sphere.setTranslation(rotation * translation); |
| 1959 | − | |
| 1959 | + | |
| 1960 | 1960 | // ...and test again |
| 1961 | 1961 | if (sphere.findRayIntersection(intersection)) { |
| 1962 | 1962 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely miss sphere" << std::endl; |
| 1963 | 1963 | } |
| 1964 | 1964 | if (intersection._hitDistance != FLT_MAX) { |
| 1965 | − std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" | |
| 1965 | + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" | |
| 1966 | 1966 | << std::endl; |
| 1967 | 1967 | } |
| 1968 | 1968 | if (intersection._hitShape != NULL) { |
| @@ -1978,7 +1978,7 @@ void ShapeColliderTests::rayHitsCapsule() { · 9 unmodified lines | ||
| 1978 | 1978 | glm::vec3 center(0.0f); |
| 1979 | 1979 | CapsuleShape capsule(radius, halfHeight); |
| 1980 | 1980 | |
| 1981 | − // simple tests along xAxis | |
| 1981 | + // simple tests along xAxis | |
| 1982 | 1982 | { // toward capsule center |
| 1983 | 1983 | RayIntersectionInfo intersection; |
| 1984 | 1984 | intersection._rayStart = glm::vec3(startDistance, 0.0f, 0.0f); |
| @@ -1989,11 +1989,11 @@ void ShapeColliderTests::rayHitsCapsule() { · 4 unmodified lines | ||
| 1989 | 1989 | float expectedDistance = startDistance - radius; |
| 1990 | 1990 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; |
| 1991 | 1991 | if (relativeError > EPSILON) { |
| 1992 | − std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " | |
| 1992 | + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " | |
| 1993 | 1993 | << relativeError << std::endl; |
| 1994 | 1994 | } |
| 1995 | 1995 | if (intersection._hitShape != &capsule) { |
| 1996 | − std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at capsule" | |
| 1996 | + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at capsule" | |
| 1997 | 1997 | << std::endl; |
| 1998 | 1998 | } |
| 1999 | 1999 | } |
| @@ -2008,7 +2008,7 @@ void ShapeColliderTests::rayHitsCapsule() { · 8 unmodified lines | ||
| 2008 | 2008 | float expectedDistance = startDistance - radius; |
| 2009 | 2009 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; |
| 2010 | 2010 | if (relativeError > EPSILON) { |
| 2011 | − std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " | |
| 2011 | + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " | |
| 2012 | 2012 | << relativeError << std::endl; |
| 2013 | 2013 | } |
| 2014 | 2014 | } |
| @@ -2024,7 +2024,7 @@ void ShapeColliderTests::rayHitsCapsule() { · 9 unmodified lines | ||
| 2024 | 2024 | float expectedDistance = startDistance - radius; |
| 2025 | 2025 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; |
| 2026 | 2026 | if (relativeError > EPSILON) { |
| 2027 | − std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " | |
| 2027 | + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " | |
| 2028 | 2028 | << relativeError << std::endl; |
| 2029 | 2029 | } |
| 2030 | 2030 | } |
| @@ -2041,7 +2041,7 @@ void ShapeColliderTests::rayHitsCapsule() { · 10 unmodified lines | ||
| 2041 | 2041 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; |
| 2042 | 2042 | // for edge cases we allow a LOT of error |
| 2043 | 2043 | if (relativeError > EDGE_CASE_SLOP_FACTOR * EPSILON) { |
| 2044 | − std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " | |
| 2044 | + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " | |
| 2045 | 2045 | << relativeError << std::endl; |
| 2046 | 2046 | } |
| 2047 | 2047 | } |
| @@ -2057,7 +2057,7 @@ void ShapeColliderTests::rayHitsCapsule() { · 9 unmodified lines | ||
| 2057 | 2057 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; |
| 2058 | 2058 | // for edge cases we allow a LOT of error |
| 2059 | 2059 | if (relativeError > EDGE_CASE_SLOP_FACTOR * EPSILON) { |
| 2060 | − std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " | |
| 2060 | + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " | |
| 2061 | 2061 | << relativeError << std::endl; |
299 more lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.