Unified · Split
| @@ -49,7 +49,7 @@ if (WIN32) · 48 unmodified lines | |||
| 49 | else () | 49 | else () |
| 50 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -fno-strict-aliasing -Wno-unused-parameter") | 50 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -fno-strict-aliasing -Wno-unused-parameter") |
| 51 | if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) | 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 | endif () | 53 | endif () |
| 54 | endif(WIN32) | 54 | endif(WIN32) |
| 55 | 55 | ||
| @@ -295,10 +295,10 @@ void AudioMixerClientData::printUpstreamDownstreamStats() const { · 294 unmodified lines | |||
| 295 | 295 | ||
| 296 | void AudioMixerClientData::printAudioStreamStats(const AudioStreamStats& streamStats) const { | 296 | void AudioMixerClientData::printAudioStreamStats(const AudioStreamStats& streamStats) const { |
| 297 | printf(" Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)\n", | 297 | printf(" Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)\n", |
| 298 | streamStats._packetStreamStats.getLostRate() * 100.0f, | 298 | (double)(streamStats._packetStreamStats.getLostRate() * 100.0f), |
| 299 | streamStats._packetStreamStats._lost, | 299 | streamStats._packetStreamStats._lost, |
| 300 | streamStats._packetStreamWindowStats.getLostRate() * 100.0f, | 300 | (double)(streamStats._packetStreamWindowStats.getLostRate() * 100.0f), |
| 301 | streamStats._packetStreamWindowStats._lost); | 301 | streamStats._packetStreamWindowStats._lost); |
| 302 | 302 | ||
| 303 | printf(" Ringbuffer frames | desired: %u, avg_available(10s): %u, available: %u\n", | 303 | printf(" Ringbuffer frames | desired: %u, avg_available(10s): %u, available: %u\n", |
| 304 | streamStats._desiredJitterBufferFrames, | 304 | streamStats._desiredJitterBufferFrames, |
| @@ -127,7 +127,7 @@ void OctreeServer::resetSendingStats() { · 126 unmodified lines | |||
| 127 | _noProcessWait = 0; | 127 | _noProcessWait = 0; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | void OctreeServer::trackEncodeTime(float time) { | 130 | void OctreeServer::trackEncodeTime(float time) { |
| 131 | const float MAX_SHORT_TIME = 10.0f; | 131 | const float MAX_SHORT_TIME = 10.0f; |
| 132 | const float MAX_LONG_TIME = 100.0f; | 132 | const float MAX_LONG_TIME = 100.0f; |
| 133 | 133 | ||
| @@ -144,10 +144,10 @@ void OctreeServer::trackEncodeTime(float time) { · 10 unmodified lines | |||
| 144 | _extraLongEncode++; | 144 | _extraLongEncode++; |
| 145 | _averageExtraLongEncodeTime.updateAverage(time); | 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 | const float MAX_SHORT_TIME = 10.0f; | 151 | const float MAX_SHORT_TIME = 10.0f; |
| 152 | const float MAX_LONG_TIME = 100.0f; | 152 | const float MAX_LONG_TIME = 100.0f; |
| 153 | if (time == SKIP_TIME) { | 153 | if (time == SKIP_TIME) { |
| @@ -166,7 +166,7 @@ void OctreeServer::trackTreeWaitTime(float time) { · 12 unmodified lines | |||
| 166 | _averageTreeWaitTime.updateAverage(time); | 166 | _averageTreeWaitTime.updateAverage(time); |
| 167 | } | 167 | } |
| 168 | 168 | ||
| 169 | void OctreeServer::trackCompressAndWriteTime(float time) { | 169 | void OctreeServer::trackCompressAndWriteTime(float time) { |
| 170 | const float MAX_SHORT_TIME = 10.0f; | 170 | const float MAX_SHORT_TIME = 10.0f; |
| 171 | const float MAX_LONG_TIME = 100.0f; | 171 | const float MAX_LONG_TIME = 100.0f; |
| 172 | if (time == SKIP_TIME) { | 172 | if (time == SKIP_TIME) { |
| @@ -182,19 +182,19 @@ void OctreeServer::trackCompressAndWriteTime(float time) { · 9 unmodified lines | |||
| 182 | _extraLongCompress++; | 182 | _extraLongCompress++; |
| 183 | _averageExtraLongCompressTime.updateAverage(time); | 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 | if (time == SKIP_TIME) { | 189 | if (time == SKIP_TIME) { |
| 190 | _noSend++; | 190 | _noSend++; |
| 191 | time = 0.0f; | 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 | const float MAX_SHORT_TIME = 10.0f; | 198 | const float MAX_SHORT_TIME = 10.0f; |
| 199 | const float MAX_LONG_TIME = 100.0f; | 199 | const float MAX_LONG_TIME = 100.0f; |
| 200 | if (time == SKIP_TIME) { | 200 | if (time == SKIP_TIME) { |
| @@ -243,9 +243,9 @@ OctreeServer::OctreeServer(const QByteArray& packet) : · 42 unmodified lines | |||
| 243 | 243 | ||
| 244 | _averageLoopTime.updateAverage(0); | 244 | _averageLoopTime.updateAverage(0); |
| 245 | qDebug() << "Octree server starting... [" << this << "]"; | 245 | qDebug() << "Octree server starting... [" << this << "]"; |
| 246 | 246 | ||
| 247 | // make sure the AccountManager has an Auth URL for payment redemptions | 247 | // make sure the AccountManager has an Auth URL for payment redemptions |
| 248 | 248 | ||
| 249 | AccountManager::getInstance().setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL); | 249 | AccountManager::getInstance().setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL); |
| 250 | } | 250 | } |
| 251 | 251 | ||
| @@ -278,13 +278,13 @@ OctreeServer::~OctreeServer() { · 26 unmodified lines | |||
| 278 | 278 | ||
| 279 | delete _jurisdiction; | 279 | delete _jurisdiction; |
| 280 | _jurisdiction = NULL; | 280 | _jurisdiction = NULL; |
| 281 | 281 | ||
| 282 | // cleanup our tree here... | 282 | // cleanup our tree here... |
| 283 | qDebug() << qPrintable(_safeServerName) << "server START cleaning up octree... [" << this << "]"; | 283 | qDebug() << qPrintable(_safeServerName) << "server START cleaning up octree... [" << this << "]"; |
| 284 | delete _tree; | 284 | delete _tree; |
| 285 | _tree = NULL; | 285 | _tree = NULL; |
| 286 | qDebug() << qPrintable(_safeServerName) << "server DONE cleaning up octree... [" << this << "]"; | 286 | qDebug() << qPrintable(_safeServerName) << "server DONE cleaning up octree... [" << this << "]"; |
| 287 | 287 | ||
| 288 | if (_instance == this) { | 288 | if (_instance == this) { |
| 289 | _instance = NULL; // we are gone | 289 | _instance = NULL; // we are gone |
| 290 | } | 290 | } |
| @@ -400,10 +400,10 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 109 unmodified lines | |||
| 400 | statsString += QString().sprintf(" Internal Elements: %s nodes (%5.2f%%)\r\n", | 400 | statsString += QString().sprintf(" Internal Elements: %s nodes (%5.2f%%)\r\n", |
| 401 | locale.toString((uint)internalNodeCount).rightJustified(16, | 401 | locale.toString((uint)internalNodeCount).rightJustified(16, |
| 402 | ' ').toLocal8Bit().constData(), | 402 | ' ').toLocal8Bit().constData(), |
| 403 | ((float)internalNodeCount / (float)nodeCount) * AS_PERCENT); | 403 | (double)((internalNodeCount / (float)nodeCount) * AS_PERCENT)); |
| 404 | statsString += QString().sprintf(" Leaf Elements: %s nodes (%5.2f%%)\r\n", | 404 | statsString += QString().sprintf(" Leaf Elements: %s nodes (%5.2f%%)\r\n", |
| 405 | locale.toString((uint)leafNodeCount).rightJustified(16, ' ').toLocal8Bit().constData(), | 405 | locale.toString((uint)leafNodeCount).rightJustified(16, ' ').toLocal8Bit().constData(), |
| 406 | ((float)leafNodeCount / (float)nodeCount) * AS_PERCENT); | 406 | (double)((leafNodeCount / (float)nodeCount) * AS_PERCENT)); |
| 407 | statsString += "\r\n"; | 407 | statsString += "\r\n"; |
| 408 | statsString += "\r\n"; | 408 | statsString += "\r\n"; |
| 409 | 409 | ||
| @@ -422,7 +422,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 12 unmodified lines | |||
| 422 | .arg(locale.toString((uint)getCurrentClientCount()).rightJustified(COLUMN_WIDTH, ' ')); | 422 | .arg(locale.toString((uint)getCurrentClientCount()).rightJustified(COLUMN_WIDTH, ' ')); |
| 423 | 423 | ||
| 424 | quint64 oneSecondAgo = usecTimestampNow() - USECS_PER_SECOND; | 424 | quint64 oneSecondAgo = usecTimestampNow() - USECS_PER_SECOND; |
| 425 | 425 | ||
| 426 | statsString += QString(" process() last second: %1 clients\r\n") | 426 | statsString += QString(" process() last second: %1 clients\r\n") |
| 427 | .arg(locale.toString((uint)howManyThreadsDidProcess(oneSecondAgo)).rightJustified(COLUMN_WIDTH, ' ')); | 427 | .arg(locale.toString((uint)howManyThreadsDidProcess(oneSecondAgo)).rightJustified(COLUMN_WIDTH, ' ')); |
| 428 | statsString += QString(" packetDistributor() last second: %1 clients\r\n") | 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 | float averageLoopTime = getAverageLoopTime(); | 435 | float averageLoopTime = getAverageLoopTime(); |
| 436 | statsString += QString().sprintf(" Average packetLoop() time: %7.2f msecs" | 436 | statsString += QString().sprintf(" Average packetLoop() time: %7.2f msecs" |
| 437 | " samples: %12d \r\n", | 437 | " samples: %12d \r\n", |
| 438 | averageLoopTime, _averageLoopTime.getSampleCount()); | 438 | (double)averageLoopTime, _averageLoopTime.getSampleCount()); |
| 439 | 439 | ||
| 440 | float averageInsideTime = getAverageInsideTime(); | 440 | float averageInsideTime = getAverageInsideTime(); |
| 441 | statsString += QString().sprintf(" Average 'inside' time: %9.2f usecs" | 441 | statsString += QString().sprintf(" Average 'inside' time: %9.2f usecs" |
| 442 | " samples: %12d \r\n\r\n", | 442 | " samples: %12d \r\n\r\n", |
| 443 | averageInsideTime, _averageInsideTime.getSampleCount()); | 443 | (double)averageInsideTime, _averageInsideTime.getSampleCount()); |
| 444 | 444 | ||
| 445 | 445 | ||
| 446 | // Process Wait | 446 | // Process Wait |
| @@ -450,30 +450,30 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 3 unmodified lines | |||
| 450 | float averageProcessWaitTime = getAverageProcessWaitTime(); | 450 | float averageProcessWaitTime = getAverageProcessWaitTime(); |
| 451 | statsString += QString().sprintf(" Average process lock wait time:" | 451 | statsString += QString().sprintf(" Average process lock wait time:" |
| 452 | " %9.2f usecs samples: %12d \r\n", | 452 | " %9.2f usecs samples: %12d \r\n", |
| 453 | averageProcessWaitTime, allWaitTimes); | 453 | (double)averageProcessWaitTime, allWaitTimes); |
| 454 | 454 | ||
| 455 | float zeroVsTotal = (allWaitTimes > 0) ? ((float)_noProcessWait / (float)allWaitTimes) : 0.0f; | 455 | float zeroVsTotal = (allWaitTimes > 0) ? ((float)_noProcessWait / (float)allWaitTimes) : 0.0f; |
| 456 | statsString += QString().sprintf(" No Lock Wait:" | 456 | statsString += QString().sprintf(" No Lock Wait:" |
| 457 | " (%6.2f%%) samples: %12d \r\n", | 457 | " (%6.2f%%) samples: %12d \r\n", |
| 458 | zeroVsTotal * AS_PERCENT, _noProcessWait); | 458 | (double)(zeroVsTotal * AS_PERCENT), _noProcessWait); |
| 459 | 459 | ||
| 460 | float shortVsTotal = (allWaitTimes > 0) ? ((float)_shortProcessWait / (float)allWaitTimes) : 0.0f; | 460 | float shortVsTotal = (allWaitTimes > 0) ? ((float)_shortProcessWait / (float)allWaitTimes) : 0.0f; |
| 461 | statsString += QString().sprintf(" Avg process lock short wait time:" | 461 | statsString += QString().sprintf(" Avg process lock short wait time:" |
| 462 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", | 462 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", |
| 463 | _averageProcessShortWaitTime.getAverage(), | 463 | (double)_averageProcessShortWaitTime.getAverage(), |
| 464 | shortVsTotal * AS_PERCENT, _shortProcessWait); | 464 | (double)(shortVsTotal * AS_PERCENT), _shortProcessWait); |
| 465 | 465 | ||
| 466 | float longVsTotal = (allWaitTimes > 0) ? ((float)_longProcessWait / (float)allWaitTimes) : 0.0f; | 466 | float longVsTotal = (allWaitTimes > 0) ? ((float)_longProcessWait / (float)allWaitTimes) : 0.0f; |
| 467 | statsString += QString().sprintf(" Avg process lock long wait time:" | 467 | statsString += QString().sprintf(" Avg process lock long wait time:" |
| 468 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", | 468 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", |
| 469 | _averageProcessLongWaitTime.getAverage(), | 469 | (double)_averageProcessLongWaitTime.getAverage(), |
| 470 | longVsTotal * AS_PERCENT, _longProcessWait); | 470 | (double)(longVsTotal * AS_PERCENT), _longProcessWait); |
| 471 | 471 | ||
| 472 | float extraLongVsTotal = (allWaitTimes > 0) ? ((float)_extraLongProcessWait / (float)allWaitTimes) : 0.0f; | 472 | float extraLongVsTotal = (allWaitTimes > 0) ? ((float)_extraLongProcessWait / (float)allWaitTimes) : 0.0f; |
| 473 | statsString += QString().sprintf("Avg process lock extralong wait time:" | 473 | statsString += QString().sprintf("Avg process lock extralong wait time:" |
| 474 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n", | 474 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n", |
| 475 | _averageProcessExtraLongWaitTime.getAverage(), | 475 | (double)_averageProcessExtraLongWaitTime.getAverage(), |
| 476 | extraLongVsTotal * AS_PERCENT, _extraLongProcessWait); | 476 | (double)(extraLongVsTotal * AS_PERCENT), _extraLongProcessWait); |
| 477 | } | 477 | } |
| 478 | 478 | ||
| 479 | // Tree Wait | 479 | // Tree Wait |
| @@ -482,122 +482,125 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 2 unmodified lines | |||
| 482 | float averageTreeWaitTime = getAverageTreeWaitTime(); | 482 | float averageTreeWaitTime = getAverageTreeWaitTime(); |
| 483 | statsString += QString().sprintf(" Average tree lock wait time:" | 483 | statsString += QString().sprintf(" Average tree lock wait time:" |
| 484 | " %9.2f usecs samples: %12d \r\n", | 484 | " %9.2f usecs samples: %12d \r\n", |
| 485 | averageTreeWaitTime, allWaitTimes); | 485 | (double)averageTreeWaitTime, allWaitTimes); |
| 486 | 486 | ||
| 487 | float zeroVsTotal = (allWaitTimes > 0) ? ((float)_noTreeWait / (float)allWaitTimes) : 0.0f; | 487 | float zeroVsTotal = (allWaitTimes > 0) ? ((float)_noTreeWait / (float)allWaitTimes) : 0.0f; |
| 488 | statsString += QString().sprintf(" No Lock Wait:" | 488 | statsString += QString().sprintf(" No Lock Wait:" |
| 489 | " (%6.2f%%) samples: %12d \r\n", | 489 | " (%6.2f%%) samples: %12d \r\n", |
| 490 | zeroVsTotal * AS_PERCENT, _noTreeWait); | 490 | (double)(zeroVsTotal * AS_PERCENT), _noTreeWait); |
| 491 | 491 | ||
| 492 | float shortVsTotal = (allWaitTimes > 0) ? ((float)_shortTreeWait / (float)allWaitTimes) : 0.0f; | 492 | float shortVsTotal = (allWaitTimes > 0) ? ((float)_shortTreeWait / (float)allWaitTimes) : 0.0f; |
| 493 | statsString += QString().sprintf(" Avg tree lock short wait time:" | 493 | statsString += QString().sprintf(" Avg tree lock short wait time:" |
| 494 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", | 494 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", |
| 495 | _averageTreeShortWaitTime.getAverage(), | 495 | (double)_averageTreeShortWaitTime.getAverage(), |
| 496 | shortVsTotal * AS_PERCENT, _shortTreeWait); | 496 | (double)(shortVsTotal * AS_PERCENT), _shortTreeWait); |
| 497 | 497 | ||
| 498 | float longVsTotal = (allWaitTimes > 0) ? ((float)_longTreeWait / (float)allWaitTimes) : 0.0f; | 498 | float longVsTotal = (allWaitTimes > 0) ? ((float)_longTreeWait / (float)allWaitTimes) : 0.0f; |
| 499 | statsString += QString().sprintf(" Avg tree lock long wait time:" | 499 | statsString += QString().sprintf(" Avg tree lock long wait time:" |
| 500 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", | 500 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", |
| 501 | _averageTreeLongWaitTime.getAverage(), | 501 | (double)_averageTreeLongWaitTime.getAverage(), |
| 502 | longVsTotal * AS_PERCENT, _longTreeWait); | 502 | (double)(longVsTotal * AS_PERCENT), _longTreeWait); |
| 503 | 503 | ||
| 504 | float extraLongVsTotal = (allWaitTimes > 0) ? ((float)_extraLongTreeWait / (float)allWaitTimes) : 0.0f; | 504 | float extraLongVsTotal = (allWaitTimes > 0) ? ((float)_extraLongTreeWait / (float)allWaitTimes) : 0.0f; |
| 505 | statsString += QString().sprintf(" Avg tree lock extra long wait time:" | 505 | statsString += QString().sprintf(" Avg tree lock extra long wait time:" |
| 506 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n", | 506 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n", |
| 507 | _averageTreeExtraLongWaitTime.getAverage(), | 507 | (double)_averageTreeExtraLongWaitTime.getAverage(), |
| 508 | extraLongVsTotal * AS_PERCENT, _extraLongTreeWait); | 508 | (double)(extraLongVsTotal * AS_PERCENT), _extraLongTreeWait); |
| 509 | 509 | ||
| 510 | // encode | 510 | // encode |
| 511 | float averageEncodeTime = getAverageEncodeTime(); | 511 | float averageEncodeTime = getAverageEncodeTime(); |
| 512 | statsString += QString().sprintf(" Average encode time: %9.2f usecs\r\n", averageEncodeTime); | 512 | statsString += QString().sprintf(" Average encode time: %9.2f usecs\r\n", (double)averageEncodeTime); |
| 513 | 513 | ||
| 514 | int allEncodeTimes = _noEncode + _shortEncode + _longEncode + _extraLongEncode; | 514 | int allEncodeTimes = _noEncode + _shortEncode + _longEncode + _extraLongEncode; |
| 515 | 515 | ||
| 516 | float zeroVsTotalEncode = (allEncodeTimes > 0) ? ((float)_noEncode / (float)allEncodeTimes) : 0.0f; | 516 | float zeroVsTotalEncode = (allEncodeTimes > 0) ? ((float)_noEncode / (float)allEncodeTimes) : 0.0f; |
| 517 | statsString += QString().sprintf(" No Encode:" | 517 | statsString += QString().sprintf(" No Encode:" |
| 518 | " (%6.2f%%) samples: %12d \r\n", | 518 | " (%6.2f%%) samples: %12d \r\n", |
| 519 | zeroVsTotalEncode * AS_PERCENT, _noEncode); | 519 | (double)(zeroVsTotalEncode * AS_PERCENT), _noEncode); |
| 520 | 520 | ||
| 521 | float shortVsTotalEncode = (allEncodeTimes > 0) ? ((float)_shortEncode / (float)allEncodeTimes) : 0.0f; | 521 | float shortVsTotalEncode = (allEncodeTimes > 0) ? ((float)_shortEncode / (float)allEncodeTimes) : 0.0f; |
| 522 | statsString += QString().sprintf(" Avg short encode time:" | 522 | statsString += QString().sprintf(" Avg short encode time:" |
| 523 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", | 523 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", |
| 524 | _averageShortEncodeTime.getAverage(), | 524 | (double)_averageShortEncodeTime.getAverage(), |
| 525 | shortVsTotalEncode * AS_PERCENT, _shortEncode); | 525 | (double)(shortVsTotalEncode * AS_PERCENT), _shortEncode); |
| 526 | 526 | ||
| 527 | float longVsTotalEncode = (allEncodeTimes > 0) ? ((float)_longEncode / (float)allEncodeTimes) : 0.0f; | 527 | float longVsTotalEncode = (allEncodeTimes > 0) ? ((float)_longEncode / (float)allEncodeTimes) : 0.0f; |
| 528 | statsString += QString().sprintf(" Avg long encode time:" | 528 | statsString += QString().sprintf(" Avg long encode time:" |
| 529 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", | 529 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", |
| 530 | _averageLongEncodeTime.getAverage(), | 530 | (double)_averageLongEncodeTime.getAverage(), |
| 531 | longVsTotalEncode * AS_PERCENT, _longEncode); | 531 | (double)(longVsTotalEncode * AS_PERCENT), _longEncode); |
| 532 | 532 | ||
| 533 | float extraLongVsTotalEncode = (allEncodeTimes > 0) ? ((float)_extraLongEncode / (float)allEncodeTimes) : 0.0f; | 533 | float extraLongVsTotalEncode = (allEncodeTimes > 0) ? ((float)_extraLongEncode / (float)allEncodeTimes) : 0.0f; |
| 534 | statsString += QString().sprintf(" Avg extra long encode time:" | 534 | statsString += QString().sprintf(" Avg extra long encode time:" |
| 535 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n", | 535 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n", |
| 536 | _averageExtraLongEncodeTime.getAverage(), | 536 | (double)_averageExtraLongEncodeTime.getAverage(), |
| 537 | extraLongVsTotalEncode * AS_PERCENT, _extraLongEncode); | 537 | (double)(extraLongVsTotalEncode * AS_PERCENT), _extraLongEncode); |
| 538 | 538 | ||
| 539 | 539 | ||
| 540 | float averageCompressAndWriteTime = getAverageCompressAndWriteTime(); | 540 | float averageCompressAndWriteTime = getAverageCompressAndWriteTime(); |
| 541 | statsString += QString().sprintf(" Average compress and write time: %9.2f usecs\r\n", | 541 | statsString += QString().sprintf(" Average compress and write time: %9.2f usecs\r\n", |
| 542 | averageCompressAndWriteTime); | 542 | (double)averageCompressAndWriteTime); |
| 543 | 543 | ||
| 544 | int allCompressTimes = _noCompress + _shortCompress + _longCompress + _extraLongCompress; | 544 | int allCompressTimes = _noCompress + _shortCompress + _longCompress + _extraLongCompress; |
| 545 | 545 | ||
| 546 | float zeroVsTotalCompress = (allCompressTimes > 0) ? ((float)_noCompress / (float)allCompressTimes) : 0.0f; | 546 | float zeroVsTotalCompress = (allCompressTimes > 0) ? ((float)_noCompress / (float)allCompressTimes) : 0.0f; |
| 547 | statsString += QString().sprintf(" No compression:" | 547 | statsString += QString().sprintf(" No compression:" |
| 548 | " (%6.2f%%) samples: %12d \r\n", | 548 | " (%6.2f%%) samples: %12d \r\n", |
| 549 | zeroVsTotalCompress * AS_PERCENT, _noCompress); | 549 | (double)(zeroVsTotalCompress * AS_PERCENT), _noCompress); |
| 550 | 550 | ||
| 551 | float shortVsTotalCompress = (allCompressTimes > 0) ? ((float)_shortCompress / (float)allCompressTimes) : 0.0f; | 551 | float shortVsTotalCompress = (allCompressTimes > 0) ? ((float)_shortCompress / (float)allCompressTimes) : 0.0f; |
| 552 | statsString += QString().sprintf(" Avg short compress time:" | 552 | statsString += QString().sprintf(" Avg short compress time:" |
| 553 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", | 553 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", |
| 554 | _averageShortCompressTime.getAverage(), | 554 | (double)_averageShortCompressTime.getAverage(), |
| 555 | shortVsTotalCompress * AS_PERCENT, _shortCompress); | 555 | (double)(shortVsTotalCompress * AS_PERCENT), _shortCompress); |
| 556 | 556 | ||
| 557 | float longVsTotalCompress = (allCompressTimes > 0) ? ((float)_longCompress / (float)allCompressTimes) : 0.0f; | 557 | float longVsTotalCompress = (allCompressTimes > 0) ? ((float)_longCompress / (float)allCompressTimes) : 0.0f; |
| 558 | statsString += QString().sprintf(" Avg long compress time:" | 558 | statsString += QString().sprintf(" Avg long compress time:" |
| 559 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", | 559 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n", |
| 560 | _averageLongCompressTime.getAverage(), | 560 | (double)_averageLongCompressTime.getAverage(), |
| 561 | longVsTotalCompress * AS_PERCENT, _longCompress); | 561 | (double)(longVsTotalCompress * AS_PERCENT), _longCompress); |
| 562 | 562 | ||
| 563 | float extraLongVsTotalCompress = (allCompressTimes > 0) ? ((float)_extraLongCompress / (float)allCompressTimes) : 0.0f; | 563 | float extraLongVsTotalCompress = (allCompressTimes > 0) ? ((float)_extraLongCompress / (float)allCompressTimes) : 0.0f; |
| 564 | statsString += QString().sprintf(" Avg extra long compress time:" | 564 | statsString += QString().sprintf(" Avg extra long compress time:" |
| 565 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n", | 565 | " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n", |
| 566 | _averageExtraLongCompressTime.getAverage(), | 566 | (double)_averageExtraLongCompressTime.getAverage(), |
| 567 | extraLongVsTotalCompress * AS_PERCENT, _extraLongCompress); | 567 | (double)(extraLongVsTotalCompress * AS_PERCENT), _extraLongCompress); |
| 568 | 568 | ||
| 569 | float averagePacketSendingTime = getAveragePacketSendingTime(); | 569 | float averagePacketSendingTime = getAveragePacketSendingTime(); |
| 570 | statsString += QString().sprintf(" Average packet sending time: %9.2f usecs (includes node lock)\r\n", | 570 | statsString += QString().sprintf(" Average packet sending time: %9.2f usecs (includes node lock)\r\n", |
| 571 | averagePacketSendingTime); | 571 | (double)averagePacketSendingTime); |
| 572 | 572 | ||
| 573 | float noVsTotalSend = (_averagePacketSendingTime.getSampleCount() > 0) ? | 573 | float noVsTotalSend = (_averagePacketSendingTime.getSampleCount() > 0) ? |
| 574 | ((float)_noSend / (float)_averagePacketSendingTime.getSampleCount()) : 0.0f; | 574 | ((float)_noSend / (float)_averagePacketSendingTime.getSampleCount()) : 0.0f; |
| 575 | statsString += QString().sprintf(" Not sending:" | 575 | statsString += QString().sprintf(" Not sending:" |
| 576 | " (%6.2f%%) samples: %12d \r\n", | 576 | " (%6.2f%%) samples: %12d \r\n", |
| 577 | noVsTotalSend * AS_PERCENT, _noSend); | 577 | (double)(noVsTotalSend * AS_PERCENT), _noSend); |
| 578 | 578 | ||
| 579 | float averageNodeWaitTime = getAverageNodeWaitTime(); | 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 | statsString += QString().sprintf("--------------------------------------------------------------\r\n"); | 583 | statsString += QString().sprintf("--------------------------------------------------------------\r\n"); |
| 583 | 584 | ||
| 584 | float encodeToInsidePercent = averageInsideTime == 0.0f ? 0.0f : (averageEncodeTime / averageInsideTime) * AS_PERCENT; | 585 | float encodeToInsidePercent = averageInsideTime == 0.0f ? 0.0f : (averageEncodeTime / averageInsideTime) * AS_PERCENT; |
| 585 | statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n", | 586 | statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n", |
| 586 | encodeToInsidePercent); | 587 | (double)encodeToInsidePercent); |
| 587 | 588 | ||
| 588 | float waitToInsidePercent = averageInsideTime == 0.0f ? 0.0f | 589 | float waitToInsidePercent = averageInsideTime == 0.0f ? 0.0f |
| 589 | : ((averageTreeWaitTime + averageNodeWaitTime) / averageInsideTime) * AS_PERCENT; | 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 | : (averageCompressAndWriteTime / averageInsideTime) * AS_PERCENT; | 595 | : (averageCompressAndWriteTime / averageInsideTime) * AS_PERCENT; |
| 594 | statsString += QString().sprintf(" compress and write ratio: %5.2f%%\r\n", | 596 | statsString += QString().sprintf(" compress and write ratio: %5.2f%%\r\n", |
| 595 | compressAndWriteToInsidePercent); | 597 | (double)compressAndWriteToInsidePercent); |
| 596 | 598 | ||
| 597 | float sendingToInsidePercent = averageInsideTime == 0.0f ? 0.0f | 599 | float sendingToInsidePercent = averageInsideTime == 0.0f ? 0.0f |
| 598 | : (averagePacketSendingTime / averageInsideTime) * AS_PERCENT; | 600 | : (averagePacketSendingTime / averageInsideTime) * AS_PERCENT; |
| 599 | statsString += QString().sprintf(" sending ratio: %5.2f%%\r\n", sendingToInsidePercent); | 601 | statsString += QString().sprintf(" sending ratio: %5.2f%%\r\n", |
| 600 | 602 | (double)sendingToInsidePercent); | |
| 603 | |||
| 601 | 604 | ||
| 602 | 605 | ||
| 603 | statsString += QString("\r\n"); | 606 | statsString += QString("\r\n"); |
| @@ -610,13 +613,13 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 6 unmodified lines | |||
| 610 | .arg(locale.toString((uint)totalWastedBytes).rightJustified(COLUMN_WIDTH, ' ')); | 613 | .arg(locale.toString((uint)totalWastedBytes).rightJustified(COLUMN_WIDTH, ' ')); |
| 611 | statsString += QString().sprintf(" Total OctalCode Bytes: %s bytes (%5.2f%%)\r\n", | 614 | statsString += QString().sprintf(" Total OctalCode Bytes: %s bytes (%5.2f%%)\r\n", |
| 612 | locale.toString((uint)totalBytesOfOctalCodes).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(), | 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 | statsString += QString().sprintf(" Total BitMasks Bytes: %s bytes (%5.2f%%)\r\n", | 617 | statsString += QString().sprintf(" Total BitMasks Bytes: %s bytes (%5.2f%%)\r\n", |
| 615 | locale.toString((uint)totalBytesOfBitMasks).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(), | 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 | statsString += QString().sprintf(" Total Color Bytes: %s bytes (%5.2f%%)\r\n", | 620 | statsString += QString().sprintf(" Total Color Bytes: %s bytes (%5.2f%%)\r\n", |
| 618 | locale.toString((uint)totalBytesOfColor).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(), | 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 | statsString += "\r\n"; | 624 | statsString += "\r\n"; |
| 622 | statsString += "\r\n"; | 625 | statsString += "\r\n"; |
| @@ -638,7 +641,8 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 15 unmodified lines | |||
| 638 | .arg(locale.toString((uint)totalPacketsProcessed).rightJustified(COLUMN_WIDTH, ' ')); | 641 | .arg(locale.toString((uint)totalPacketsProcessed).rightJustified(COLUMN_WIDTH, ' ')); |
| 639 | statsString += QString(" Total Inbound Elements: %1 elements\r\n") | 642 | statsString += QString(" Total Inbound Elements: %1 elements\r\n") |
| 640 | .arg(locale.toString((uint)totalElementsProcessed).rightJustified(COLUMN_WIDTH, ' ')); | 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 | statsString += QString(" Average Transit Time/Packet: %1 usecs\r\n") | 646 | statsString += QString(" Average Transit Time/Packet: %1 usecs\r\n") |
| 643 | .arg(locale.toString((uint)averageTransitTimePerPacket).rightJustified(COLUMN_WIDTH, ' ')); | 647 | .arg(locale.toString((uint)averageTransitTimePerPacket).rightJustified(COLUMN_WIDTH, ' ')); |
| 644 | statsString += QString(" Average Process Time/Packet: %1 usecs\r\n") | 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 | statsString += QString(" Total Inbound Elements: %1 elements\r\n") | 680 | statsString += QString(" Total Inbound Elements: %1 elements\r\n") |
| 677 | .arg(locale.toString((uint)totalElementsProcessed).rightJustified(COLUMN_WIDTH, ' ')); | 681 | .arg(locale.toString((uint)totalElementsProcessed).rightJustified(COLUMN_WIDTH, ' ')); |
| 678 | statsString += QString().sprintf(" Average Inbound Elements/Packet: %f elements/packet\r\n", | 682 | statsString += QString().sprintf(" Average Inbound Elements/Packet: %f elements/packet\r\n", |
| 679 | averageElementsPerPacket); | 683 | (double)averageElementsPerPacket); |
| 680 | statsString += QString(" Average Transit Time/Packet: %1 usecs\r\n") | 684 | statsString += QString(" Average Transit Time/Packet: %1 usecs\r\n") |
| 681 | .arg(locale.toString((uint)averageTransitTimePerPacket).rightJustified(COLUMN_WIDTH, ' ')); | 685 | .arg(locale.toString((uint)averageTransitTimePerPacket).rightJustified(COLUMN_WIDTH, ' ')); |
| 682 | statsString += QString(" Average Process Time/Packet: %1 usecs\r\n") | 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 | statsString += QString().sprintf("Element Node Memory Usage: %8.2f %s\r\n", | 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 | statsString += QString().sprintf("Octcode Memory Usage: %8.2f %s\r\n", | 718 | statsString += QString().sprintf("Octcode Memory Usage: %8.2f %s\r\n", |
| 715 | OctreeElement::getOctcodeMemoryUsage() / memoryScale, memoryScaleLabel); | 719 | OctreeElement::getOctcodeMemoryUsage() / (double)memoryScale, memoryScaleLabel); |
| 716 | statsString += QString().sprintf("External Children Memory Usage: %8.2f %s\r\n", | 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 | statsString += " -----------\r\n"; | 723 | statsString += " -----------\r\n"; |
| 719 | statsString += QString().sprintf(" Total: %8.2f %s\r\n", | 724 | statsString += QString().sprintf(" Total: %8.2f %s\r\n", |
| 720 | OctreeElement::getTotalMemoryUsage() / memoryScale, memoryScaleLabel); | 725 | OctreeElement::getTotalMemoryUsage() / (double)memoryScale, memoryScaleLabel); |
| 721 | statsString += "\r\n"; | 726 | statsString += "\r\n"; |
| 722 | 727 | ||
| 723 | statsString += "OctreeElement Children Population Statistics...\r\n"; | 728 | statsString += "OctreeElement Children Population Statistics...\r\n"; |
| @@ -726,7 +731,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 2 unmodified lines | |||
| 726 | checkSum += OctreeElement::getChildrenCount(i); | 731 | checkSum += OctreeElement::getChildrenCount(i); |
| 727 | statsString += QString().sprintf(" Nodes with %d children: %s nodes (%5.2f%%)\r\n", i, | 732 | statsString += QString().sprintf(" Nodes with %d children: %s nodes (%5.2f%%)\r\n", i, |
| 728 | locale.toString((uint)OctreeElement::getChildrenCount(i)).rightJustified(16, ' ').toLocal8Bit().constData(), | 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 | statsString += " ----------------------\r\n"; | 736 | statsString += " ----------------------\r\n"; |
| 732 | statsString += QString(" Total: %1 nodes\r\n") | 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 | // If we know we're shutting down we just drop these packets on the floor. | 837 | // If we know we're shutting down we just drop these packets on the floor. |
| 833 | // This stops us from initializing send threads we just shut down. | 838 | // This stops us from initializing send threads we just shut down. |
| 834 | 839 | ||
| 835 | if (!_isShuttingDown) { | 840 | if (!_isShuttingDown) { |
| 836 | if (nodeList->packetVersionAndHashMatch(receivedPacket)) { | 841 | if (nodeList->packetVersionAndHashMatch(receivedPacket)) { |
| 837 | PacketType packetType = packetTypeForPacket(receivedPacket); | 842 | PacketType packetType = packetTypeForPacket(receivedPacket); |
| @@ -841,7 +846,7 @@ void OctreeServer::readPendingDatagram(const QByteArray& receivedPacket, const H · 3 unmodified lines | |||
| 841 | // need to make sure we have it in our nodeList. | 846 | // need to make sure we have it in our nodeList. |
| 842 | if (matchingNode) { | 847 | if (matchingNode) { |
| 843 | nodeList->updateNodeWithDataFromPacket(matchingNode, receivedPacket); | 848 | nodeList->updateNodeWithDataFromPacket(matchingNode, receivedPacket); |
| 844 | 849 | ||
| 845 | OctreeQueryNode* nodeData = (OctreeQueryNode*) matchingNode->getLinkedData(); | 850 | OctreeQueryNode* nodeData = (OctreeQueryNode*) matchingNode->getLinkedData(); |
| 846 | if (nodeData && !nodeData->isOctreeSendThreadInitalized()) { | 851 | if (nodeData && !nodeData->isOctreeSendThreadInitalized()) { |
| 847 | nodeData->initializeOctreeSendThread(this, matchingNode); | 852 | nodeData->initializeOctreeSendThread(this, matchingNode); |
| @@ -870,33 +875,33 @@ void OctreeServer::readPendingDatagram(const QByteArray& receivedPacket, const H · 22 unmodified lines | |||
| 870 | 875 | ||
| 871 | void OctreeServer::setupDatagramProcessingThread() { | 876 | void OctreeServer::setupDatagramProcessingThread() { |
| 872 | auto nodeList = DependencyManager::get<NodeList>(); | 877 | auto nodeList = DependencyManager::get<NodeList>(); |
| 873 | 878 | ||
| 874 | // we do not want this event loop to be the handler for UDP datagrams, so disconnect | 879 | // we do not want this event loop to be the handler for UDP datagrams, so disconnect |
| 875 | disconnect(&nodeList->getNodeSocket(), 0, this, 0); | 880 | disconnect(&nodeList->getNodeSocket(), 0, this, 0); |
| 876 | 881 | ||
| 877 | // setup a QThread with us as parent that will house the OctreeServerDatagramProcessor | 882 | // setup a QThread with us as parent that will house the OctreeServerDatagramProcessor |
| 878 | _datagramProcessingThread = new QThread(this); | 883 | _datagramProcessingThread = new QThread(this); |
| 879 | _datagramProcessingThread->setObjectName("Octree Datagram Processor"); | 884 | _datagramProcessingThread->setObjectName("Octree Datagram Processor"); |
| 880 | 885 | ||
| 881 | // create an OctreeServerDatagramProcessor and move it to that thread | 886 | // create an OctreeServerDatagramProcessor and move it to that thread |
| 882 | OctreeServerDatagramProcessor* datagramProcessor = new OctreeServerDatagramProcessor(nodeList->getNodeSocket(), thread()); | 887 | OctreeServerDatagramProcessor* datagramProcessor = new OctreeServerDatagramProcessor(nodeList->getNodeSocket(), thread()); |
| 883 | datagramProcessor->moveToThread(_datagramProcessingThread); | 888 | datagramProcessor->moveToThread(_datagramProcessingThread); |
| 884 | 889 | ||
| 885 | // remove the NodeList as the parent of the node socket | 890 | // remove the NodeList as the parent of the node socket |
| 886 | nodeList->getNodeSocket().setParent(NULL); | 891 | nodeList->getNodeSocket().setParent(NULL); |
| 887 | nodeList->getNodeSocket().moveToThread(_datagramProcessingThread); | 892 | nodeList->getNodeSocket().moveToThread(_datagramProcessingThread); |
| 888 | 893 | ||
| 889 | // let the datagram processor handle readyRead from node socket | 894 | // let the datagram processor handle readyRead from node socket |
| 890 | connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, | 895 | connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, |
| 891 | datagramProcessor, &OctreeServerDatagramProcessor::readPendingDatagrams); | 896 | datagramProcessor, &OctreeServerDatagramProcessor::readPendingDatagrams); |
| 892 | 897 | ||
| 893 | // connect to the datagram processing thread signal that tells us we have to handle a packet | 898 | // connect to the datagram processing thread signal that tells us we have to handle a packet |
| 894 | connect(datagramProcessor, &OctreeServerDatagramProcessor::packetRequiresProcessing, this, &OctreeServer::readPendingDatagram); | 899 | connect(datagramProcessor, &OctreeServerDatagramProcessor::packetRequiresProcessing, this, &OctreeServer::readPendingDatagram); |
| 895 | 900 | ||
| 896 | // delete the datagram processor and the associated thread when the QThread quits | 901 | // delete the datagram processor and the associated thread when the QThread quits |
| 897 | connect(_datagramProcessingThread, &QThread::finished, datagramProcessor, &QObject::deleteLater); | 902 | connect(_datagramProcessingThread, &QThread::finished, datagramProcessor, &QObject::deleteLater); |
| 898 | connect(datagramProcessor, &QObject::destroyed, _datagramProcessingThread, &QThread::deleteLater); | 903 | connect(datagramProcessor, &QObject::destroyed, _datagramProcessingThread, &QThread::deleteLater); |
| 899 | 904 | ||
| 900 | // start the datagram processing thread | 905 | // start the datagram processing thread |
| 901 | _datagramProcessingThread->start(); | 906 | _datagramProcessingThread->start(); |
| 902 | } | 907 | } |
| @@ -961,16 +966,16 @@ void OctreeServer::readConfiguration() { · 58 unmodified lines | |||
| 961 | // wait until we have the domain-server settings, otherwise we bail | 966 | // wait until we have the domain-server settings, otherwise we bail |
| 962 | auto nodeList = DependencyManager::get<NodeList>(); | 967 | auto nodeList = DependencyManager::get<NodeList>(); |
| 963 | DomainHandler& domainHandler = nodeList->getDomainHandler(); | 968 | DomainHandler& domainHandler = nodeList->getDomainHandler(); |
| 964 | 969 | ||
| 965 | qDebug() << "Waiting for domain settings from domain-server."; | 970 | qDebug() << "Waiting for domain settings from domain-server."; |
| 966 | 971 | ||
| 967 | // block until we get the settingsRequestComplete signal | 972 | // block until we get the settingsRequestComplete signal |
| 968 | QEventLoop loop; | 973 | QEventLoop loop; |
| 969 | connect(&domainHandler, &DomainHandler::settingsReceived, &loop, &QEventLoop::quit); | 974 | connect(&domainHandler, &DomainHandler::settingsReceived, &loop, &QEventLoop::quit); |
| 970 | connect(&domainHandler, &DomainHandler::settingsReceiveFail, &loop, &QEventLoop::quit); | 975 | connect(&domainHandler, &DomainHandler::settingsReceiveFail, &loop, &QEventLoop::quit); |
| 971 | domainHandler.requestDomainSettings(); | 976 | domainHandler.requestDomainSettings(); |
| 972 | loop.exec(); | 977 | loop.exec(); |
| 973 | 978 | ||
| 974 | if (domainHandler.getSettingsObject().isEmpty()) { | 979 | if (domainHandler.getSettingsObject().isEmpty()) { |
| 975 | qDebug() << "No settings object from domain-server."; | 980 | qDebug() << "No settings object from domain-server."; |
| 976 | } | 981 | } |
| @@ -978,7 +983,7 @@ void OctreeServer::readConfiguration() { · 1 unmodified line | |||
| 978 | QString settingsKey = getMyDomainSettingsKey(); | 983 | QString settingsKey = getMyDomainSettingsKey(); |
| 979 | QJsonObject settingsSectionObject = settingsObject[settingsKey].toObject(); | 984 | QJsonObject settingsSectionObject = settingsObject[settingsKey].toObject(); |
| 980 | _settings = settingsSectionObject; // keep this for later | 985 | _settings = settingsSectionObject; // keep this for later |
| 981 | 986 | ||
| 982 | if (!readOptionString(QString("statusHost"), settingsSectionObject, _statusHost) || _statusHost.isEmpty()) { | 987 | if (!readOptionString(QString("statusHost"), settingsSectionObject, _statusHost) || _statusHost.isEmpty()) { |
| 983 | _statusHost = getLocalAddress().toString(); | 988 | _statusHost = getLocalAddress().toString(); |
| 984 | } | 989 | } |
| @@ -1002,7 +1007,7 @@ void OctreeServer::readConfiguration() { · 17 unmodified lines | |||
| 1002 | bool hasRoot = readOptionString(QString("jurisdictionRoot"), settingsSectionObject, jurisdictionRoot); | 1007 | bool hasRoot = readOptionString(QString("jurisdictionRoot"), settingsSectionObject, jurisdictionRoot); |
| 1003 | QString jurisdictionEndNodes; | 1008 | QString jurisdictionEndNodes; |
| 1004 | bool hasEndNodes = readOptionString(QString("jurisdictionEndNodes"), settingsSectionObject, jurisdictionEndNodes); | 1009 | bool hasEndNodes = readOptionString(QString("jurisdictionEndNodes"), settingsSectionObject, jurisdictionEndNodes); |
| 1005 | 1010 | ||
| 1006 | if (hasRoot || hasEndNodes) { | 1011 | if (hasRoot || hasEndNodes) { |
| 1007 | _jurisdiction = new JurisdictionMap(qPrintable(jurisdictionRoot), qPrintable(jurisdictionEndNodes)); | 1012 | _jurisdiction = new JurisdictionMap(qPrintable(jurisdictionRoot), qPrintable(jurisdictionEndNodes)); |
| 1008 | } | 1013 | } |
| @@ -1050,7 +1055,7 @@ void OctreeServer::readConfiguration() { · 41 unmodified lines | |||
| 1050 | qDebug() << "wantBackup=" << _wantBackup; | 1055 | qDebug() << "wantBackup=" << _wantBackup; |
| 1051 | 1056 | ||
| 1052 | //qDebug() << "settingsSectionObject:" << settingsSectionObject; | 1057 | //qDebug() << "settingsSectionObject:" << settingsSectionObject; |
| 1053 | 1058 | ||
| 1054 | } else { | 1059 | } else { |
| 1055 | qDebug("persistFilename= DISABLED"); | 1060 | qDebug("persistFilename= DISABLED"); |
| 1056 | } | 1061 | } |
| @@ -1072,7 +1077,7 @@ void OctreeServer::readConfiguration() { · 15 unmodified lines | |||
| 1072 | _packetsPerClientPerInterval = 1; | 1077 | _packetsPerClientPerInterval = 1; |
| 1073 | } | 1078 | } |
| 1074 | } | 1079 | } |
| 1075 | qDebug("packetsPerSecondPerClientMax=%d _packetsPerClientPerInterval=%d", | 1080 | qDebug("packetsPerSecondPerClientMax=%d _packetsPerClientPerInterval=%d", |
| 1076 | packetsPerSecondPerClientMax, _packetsPerClientPerInterval); | 1081 | packetsPerSecondPerClientMax, _packetsPerClientPerInterval); |
| 1077 | 1082 | ||
| 1078 | // Check to see if the user passed in a command line option for setting packet send rate | 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 | _packetsTotalPerInterval = 1; | 1088 | _packetsTotalPerInterval = 1; |
| 1084 | } | 1089 | } |
| 1085 | } | 1090 | } |
| 1086 | qDebug("packetsPerSecondTotalMax=%d _packetsTotalPerInterval=%d", | 1091 | qDebug("packetsPerSecondTotalMax=%d _packetsTotalPerInterval=%d", |
| 1087 | packetsPerSecondTotalMax, _packetsTotalPerInterval); | 1092 | packetsPerSecondTotalMax, _packetsTotalPerInterval); |
| 1088 | 1093 | ||
| 1089 | 1094 | ||
| 1090 | readAdditionalConfiguration(settingsSectionObject); | 1095 | readAdditionalConfiguration(settingsSectionObject); |
| 1091 | } | 1096 | } |
| 1092 | 1097 | ||
| @@ -1101,8 +1106,8 @@ void OctreeServer::run() { · 8 unmodified lines | |||
| 1101 | // make sure our NodeList knows what type we are | 1106 | // make sure our NodeList knows what type we are |
| 1102 | auto nodeList = DependencyManager::get<NodeList>(); | 1107 | auto nodeList = DependencyManager::get<NodeList>(); |
| 1103 | nodeList->setOwnerType(getMyNodeType()); | 1108 | nodeList->setOwnerType(getMyNodeType()); |
| 1104 | 1109 | ||
| 1105 | 1110 | ||
| 1106 | // use common init to setup common timers and logging | 1111 | // use common init to setup common timers and logging |
| 1107 | commonInit(getMyLoggingServerTargetName(), getMyNodeType()); | 1112 | commonInit(getMyLoggingServerTargetName(), getMyNodeType()); |
| 1108 | 1113 | ||
| @@ -1110,7 +1115,7 @@ void OctreeServer::run() { · 1 unmodified line | |||
| 1110 | 1115 | ||
| 1111 | // read the configuration from either the payload or the domain server configuration | 1116 | // read the configuration from either the payload or the domain server configuration |
| 1112 | readConfiguration(); | 1117 | readConfiguration(); |
| 1113 | 1118 | ||
| 1114 | beforeRun(); // after payload has been processed | 1119 | beforeRun(); // after payload has been processed |
| 1115 | 1120 | ||
| 1116 | connect(nodeList.data(), SIGNAL(nodeAdded(SharedNodePointer)), SLOT(nodeAdded(SharedNodePointer))); | 1121 | connect(nodeList.data(), SIGNAL(nodeAdded(SharedNodePointer)), SLOT(nodeAdded(SharedNodePointer))); |
| @@ -1119,7 +1124,7 @@ void OctreeServer::run() { · 2 unmodified lines | |||
| 1119 | 1124 | ||
| 1120 | // we need to ask the DS about agents so we can ping/reply with them | 1125 | // we need to ask the DS about agents so we can ping/reply with them |
| 1121 | nodeList->addNodeTypeToInterestSet(NodeType::Agent); | 1126 | nodeList->addNodeTypeToInterestSet(NodeType::Agent); |
| 1122 | 1127 | ||
| 1123 | #ifndef WIN32 | 1128 | #ifndef WIN32 |
| 1124 | setvbuf(stdout, NULL, _IOLBF, 0); | 1129 | setvbuf(stdout, NULL, _IOLBF, 0); |
| 1125 | #endif | 1130 | #endif |
| @@ -1209,7 +1214,7 @@ void OctreeServer::forceNodeShutdown(SharedNodePointer node) { · 83 unmodified lines | |||
| 1209 | 1214 | ||
| 1210 | quint64 end = usecTimestampNow(); | 1215 | quint64 end = usecTimestampNow(); |
| 1211 | quint64 usecsElapsed = (end - start); | 1216 | quint64 usecsElapsed = (end - start); |
| 1212 | qDebug() << qPrintable(_safeServerName) << "server forceNodeShutdown() took: " | 1217 | qDebug() << qPrintable(_safeServerName) << "server forceNodeShutdown() took: " |
| 1213 | << usecsElapsed << " usecs for node:" << *node; | 1218 | << usecsElapsed << " usecs for node:" << *node; |
| 1214 | } | 1219 | } |
| 1215 | 1220 | ||
| @@ -1225,7 +1230,7 @@ void OctreeServer::aboutToFinish() { · 9 unmodified lines | |||
| 1225 | // This ensures that when we forceNodeShutdown below for each node we don't get any more newly connecting nodes | 1230 | // This ensures that when we forceNodeShutdown below for each node we don't get any more newly connecting nodes |
| 1226 | auto nodeList = DependencyManager::get<NodeList>(); | 1231 | auto nodeList = DependencyManager::get<NodeList>(); |
| 1227 | nodeList->linkedDataCreateCallback = NULL; | 1232 | nodeList->linkedDataCreateCallback = NULL; |
| 1228 | 1233 | ||
| 1229 | if (_octreeInboundPacketProcessor) { | 1234 | if (_octreeInboundPacketProcessor) { |
| 1230 | _octreeInboundPacketProcessor->terminating(); | 1235 | _octreeInboundPacketProcessor->terminating(); |
| 1231 | } | 1236 | } |
| @@ -1240,7 +1245,7 @@ void OctreeServer::aboutToFinish() { · 8 unmodified lines | |||
| 1240 | qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node; | 1245 | qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node; |
| 1241 | forceNodeShutdown(node); | 1246 | forceNodeShutdown(node); |
| 1242 | }); | 1247 | }); |
| 1243 | 1248 | ||
| 1244 | if (_persistThread) { | 1249 | if (_persistThread) { |
| 1245 | _persistThread->aboutToFinish(); | 1250 | _persistThread->aboutToFinish(); |
| 1246 | _persistThread->terminating(); | 1251 | _persistThread->terminating(); |
| @@ -1282,7 +1287,7 @@ QString OctreeServer::getUptime() { · 35 unmodified lines | |||
| 1282 | if (hours > 0 || minutes > 0) { | 1287 | if (hours > 0 || minutes > 0) { |
| 1283 | formattedUptime += QString(" "); | 1288 | formattedUptime += QString(" "); |
| 1284 | } | 1289 | } |
| 1285 | formattedUptime += QString().sprintf("%.3f seconds", seconds); | 1290 | formattedUptime += QString().sprintf("%.3f seconds", (double)seconds); |
| 1286 | } | 1291 | } |
| 1287 | return formattedUptime; | 1292 | return formattedUptime; |
| 1288 | } | 1293 | } |
| @@ -1290,13 +1295,13 @@ QString OctreeServer::getUptime() { · 1 unmodified line | |||
| 1290 | QString OctreeServer::getFileLoadTime() { | 1295 | QString OctreeServer::getFileLoadTime() { |
| 1291 | QString result; | 1296 | QString result; |
| 1292 | if (isInitialLoadComplete()) { | 1297 | if (isInitialLoadComplete()) { |
| 1293 | 1298 | ||
| 1294 | const int USECS_PER_MSEC = 1000; | 1299 | const int USECS_PER_MSEC = 1000; |
| 1295 | const int MSECS_PER_SEC = 1000; | 1300 | const int MSECS_PER_SEC = 1000; |
| 1296 | const int SECS_PER_MIN = 60; | 1301 | const int SECS_PER_MIN = 60; |
| 1297 | const int MIN_PER_HOUR = 60; | 1302 | const int MIN_PER_HOUR = 60; |
| 1298 | const int MSECS_PER_MIN = MSECS_PER_SEC * SECS_PER_MIN; | 1303 | const int MSECS_PER_MIN = MSECS_PER_SEC * SECS_PER_MIN; |
| 1299 | 1304 | ||
| 1300 | quint64 msecsElapsed = getLoadElapsedTime() / USECS_PER_MSEC;; | 1305 | quint64 msecsElapsed = getLoadElapsedTime() / USECS_PER_MSEC;; |
| 1301 | float seconds = (msecsElapsed % MSECS_PER_MIN)/(float)MSECS_PER_SEC; | 1306 | float seconds = (msecsElapsed % MSECS_PER_MIN)/(float)MSECS_PER_SEC; |
| 1302 | int minutes = (msecsElapsed/(MSECS_PER_MIN)) % MIN_PER_HOUR; | 1307 | int minutes = (msecsElapsed/(MSECS_PER_MIN)) % MIN_PER_HOUR; |
| @@ -1321,7 +1326,7 @@ QString OctreeServer::getFileLoadTime() { · 18 unmodified lines | |||
| 1321 | if (hours > 0 || minutes > 0) { | 1326 | if (hours > 0 || minutes > 0) { |
| 1322 | result += QString(" "); | 1327 | result += QString(" "); |
| 1323 | } | 1328 | } |
| 1324 | result += QString().sprintf("%.3f seconds", seconds); | 1329 | result += QString().sprintf("%.3f seconds", (double)seconds); |
| 1325 | } | 1330 | } |
| 1326 | } else { | 1331 | } else { |
| 1327 | result = "Not yet loaded..."; | 1332 | result = "Not yet loaded..."; |
| @@ -1356,27 +1361,27 @@ void OctreeServer::sendStatsPacket() { · 28 unmodified lines | |||
| 1356 | // 2) only send new data | 1361 | // 2) only send new data |
| 1357 | // 3) automatically break up into multiple packets | 1362 | // 3) automatically break up into multiple packets |
| 1358 | static QJsonObject statsObject1; | 1363 | static QJsonObject statsObject1; |
| 1359 | 1364 | ||
| 1360 | QString baseName = getMyServerName() + QString("Server"); | 1365 | QString baseName = getMyServerName() + QString("Server"); |
| 1361 | 1366 | ||
| 1362 | statsObject1[baseName + QString(".0.1.configuration")] = getConfiguration(); | 1367 | statsObject1[baseName + QString(".0.1.configuration")] = getConfiguration(); |
| 1363 | 1368 | ||
| 1364 | statsObject1[baseName + QString(".0.2.detailed_stats_url")] = getStatusLink(); | 1369 | statsObject1[baseName + QString(".0.2.detailed_stats_url")] = getStatusLink(); |
| 1365 | 1370 | ||
| 1366 | statsObject1[baseName + QString(".0.3.uptime")] = getUptime(); | 1371 | statsObject1[baseName + QString(".0.3.uptime")] = getUptime(); |
| 1367 | statsObject1[baseName + QString(".0.4.persistFileLoadTime")] = getFileLoadTime(); | 1372 | statsObject1[baseName + QString(".0.4.persistFileLoadTime")] = getFileLoadTime(); |
| 1368 | statsObject1[baseName + QString(".0.5.clients")] = getCurrentClientCount(); | 1373 | statsObject1[baseName + QString(".0.5.clients")] = getCurrentClientCount(); |
| 1369 | 1374 | ||
| 1370 | quint64 oneSecondAgo = usecTimestampNow() - USECS_PER_SECOND; | 1375 | quint64 oneSecondAgo = usecTimestampNow() - USECS_PER_SECOND; |
| 1371 | 1376 | ||
| 1372 | statsObject1[baseName + QString(".0.6.threads.1.processing")] = (double)howManyThreadsDidProcess(oneSecondAgo); | 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 | (double)howManyThreadsDidPacketDistributor(oneSecondAgo); | 1379 | (double)howManyThreadsDidPacketDistributor(oneSecondAgo); |
| 1375 | statsObject1[baseName + QString(".0.6.threads.3.handlePacektSend")] = | 1380 | statsObject1[baseName + QString(".0.6.threads.3.handlePacektSend")] = |
| 1376 | (double)howManyThreadsDidHandlePacketSend(oneSecondAgo); | 1381 | (double)howManyThreadsDidHandlePacketSend(oneSecondAgo); |
| 1377 | statsObject1[baseName + QString(".0.6.threads.4.writeDatagram")] = | 1382 | statsObject1[baseName + QString(".0.6.threads.4.writeDatagram")] = |
| 1378 | (double)howManyThreadsDidCallWriteDatagram(oneSecondAgo); | 1383 | (double)howManyThreadsDidCallWriteDatagram(oneSecondAgo); |
| 1379 | 1384 | ||
| 1380 | statsObject1[baseName + QString(".1.1.octree.elementCount")] = (double)OctreeElement::getNodeCount(); | 1385 | statsObject1[baseName + QString(".1.1.octree.elementCount")] = (double)OctreeElement::getNodeCount(); |
| 1381 | statsObject1[baseName + QString(".1.2.octree.internalElementCount")] = (double)OctreeElement::getInternalNodeCount(); | 1386 | statsObject1[baseName + QString(".1.2.octree.internalElementCount")] = (double)OctreeElement::getInternalNodeCount(); |
| 1382 | statsObject1[baseName + QString(".1.3.octree.leafElementCount")] = (double)OctreeElement::getLeafNodeCount(); | 1387 | statsObject1[baseName + QString(".1.3.octree.leafElementCount")] = (double)OctreeElement::getLeafNodeCount(); |
| @@ -1388,9 +1393,9 @@ void OctreeServer::sendStatsPacket() { · 5 unmodified lines | |||
| 1388 | statsObject2[baseName + QString(".2.outbound.data.totalPackets")] = (double)OctreeSendThread::_totalPackets; | 1393 | statsObject2[baseName + QString(".2.outbound.data.totalPackets")] = (double)OctreeSendThread::_totalPackets; |
| 1389 | statsObject2[baseName + QString(".2.outbound.data.totalBytes")] = (double)OctreeSendThread::_totalBytes; | 1394 | statsObject2[baseName + QString(".2.outbound.data.totalBytes")] = (double)OctreeSendThread::_totalBytes; |
| 1390 | statsObject2[baseName + QString(".2.outbound.data.totalBytesWasted")] = (double)OctreeSendThread::_totalWastedBytes; | 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 | (double)OctreePacketData::getTotalBytesOfOctalCodes(); | 1397 | (double)OctreePacketData::getTotalBytesOfOctalCodes(); |
| 1393 | statsObject2[baseName + QString(".2.outbound.data.totalBytesBitMasks")] = | 1398 | statsObject2[baseName + QString(".2.outbound.data.totalBytesBitMasks")] = |
| 1394 | (double)OctreePacketData::getTotalBytesOfBitMasks(); | 1399 | (double)OctreePacketData::getTotalBytesOfBitMasks(); |
| 1395 | statsObject2[baseName + QString(".2.outbound.data.totalBytesBitMasks")] = (double)OctreePacketData::getTotalBytesOfColor(); | 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 | static QJsonObject statsObject3; | 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 | (double)_octreeInboundPacketProcessor->getTotalPacketsProcessed(); | 1415 | (double)_octreeInboundPacketProcessor->getTotalPacketsProcessed(); |
| 1411 | statsObject3[baseName + QString(".3.inbound.data.2.totalElements")] = | 1416 | statsObject3[baseName + QString(".3.inbound.data.2.totalElements")] = |
| 1412 | (double)_octreeInboundPacketProcessor->getTotalElementsProcessed(); | 1417 | (double)_octreeInboundPacketProcessor->getTotalElementsProcessed(); |
| 1413 | statsObject3[baseName + QString(".3.inbound.timing.1.avgTransitTimePerPacket")] = | 1418 | statsObject3[baseName + QString(".3.inbound.timing.1.avgTransitTimePerPacket")] = |
| 1414 | (double)_octreeInboundPacketProcessor->getAverageTransitTimePerPacket(); | 1419 | (double)_octreeInboundPacketProcessor->getAverageTransitTimePerPacket(); |
| 1415 | statsObject3[baseName + QString(".3.inbound.timing.2.avgProcessTimePerPacket")] = | 1420 | statsObject3[baseName + QString(".3.inbound.timing.2.avgProcessTimePerPacket")] = |
| 1416 | (double)_octreeInboundPacketProcessor->getAverageProcessTimePerPacket(); | 1421 | (double)_octreeInboundPacketProcessor->getAverageProcessTimePerPacket(); |
| 1417 | statsObject3[baseName + QString(".3.inbound.timing.3.avgLockWaitTimePerPacket")] = | 1422 | statsObject3[baseName + QString(".3.inbound.timing.3.avgLockWaitTimePerPacket")] = |
| 1418 | (double)_octreeInboundPacketProcessor->getAverageLockWaitTimePerPacket(); | 1423 | (double)_octreeInboundPacketProcessor->getAverageLockWaitTimePerPacket(); |
| 1419 | statsObject3[baseName + QString(".3.inbound.timing.4.avgProcessTimePerElement")] = | 1424 | statsObject3[baseName + QString(".3.inbound.timing.4.avgProcessTimePerElement")] = |
| 1420 | (double)_octreeInboundPacketProcessor->getAverageProcessTimePerElement(); | 1425 | (double)_octreeInboundPacketProcessor->getAverageProcessTimePerElement(); |
| 1421 | statsObject3[baseName + QString(".3.inbound.timing.5.avgLockWaitTimePerElement")] = | 1426 | statsObject3[baseName + QString(".3.inbound.timing.5.avgLockWaitTimePerElement")] = |
| 1422 | (double)_octreeInboundPacketProcessor->getAverageLockWaitTimePerElement(); | 1427 | (double)_octreeInboundPacketProcessor->getAverageLockWaitTimePerElement(); |
| 1423 | 1428 | ||
| 1424 | DependencyManager::get<NodeList>()->sendStatsToDomainServer(statsObject3); | 1429 | DependencyManager::get<NodeList>()->sendStatsToDomainServer(statsObject3); |
| @@ -9,8 +9,8 @@ if (WIN32) · 8 unmodified lines | |||
| 9 | 9 | ||
| 10 | ExternalProject_Add( | 10 | ExternalProject_Add( |
| 11 | ${EXTERNAL_NAME} | 11 | ${EXTERNAL_NAME} |
| 12 | URL http://static.oculus.com/sdk-downloads/ovr_sdk_win_0.5.0.1.zip | 12 | URL http://static.oculus.com/sdk-downloads/0.6.0.0/1431634088/ovr_sdk_win_0.6.0.0.zip |
| 13 | URL_MD5 d3fc4c02db9be5ff08af4ef4c97b32f9 | 13 | URL_MD5 a3dfdab037a854fdcf7e6033fa8d7028 |
| 14 | CONFIGURE_COMMAND "" | 14 | CONFIGURE_COMMAND "" |
| 15 | BUILD_COMMAND "" | 15 | BUILD_COMMAND "" |
| 16 | INSTALL_COMMAND "" | 16 | INSTALL_COMMAND "" |
| @@ -21,7 +21,11 @@ if (WIN32) · 4 unmodified lines | |||
| 21 | 21 | ||
| 22 | # FIXME need to account for different architectures | 22 | # FIXME need to account for different architectures |
| 23 | set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/LibOVR/Include CACHE TYPE INTERNAL) | 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 | elseif(APPLE) | 30 | elseif(APPLE) |
| 27 | 31 | ||
| @@ -3,13 +3,13 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) · 2 unmodified lines | |||
| 3 | 3 | ||
| 4 | include(ExternalProject) | 4 | include(ExternalProject) |
| 5 | ExternalProject_Add( | 5 | ExternalProject_Add( |
| 6 | ${EXTERNAL_NAME} | 6 | ${EXTERNAL_NAME} |
| 7 | URL https://github.com/boostorg/config/archive/boost-1.58.0.zip | 7 | URL https://github.com/boostorg/config/archive/boost-1.58.0.zip |
| 8 | URL_MD5 42fa673bae2b7645a22736445e80eb8d | 8 | URL_MD5 42fa673bae2b7645a22736445e80eb8d |
| 9 | CONFIGURE_COMMAND "" | 9 | CONFIGURE_COMMAND "" |
| 10 | BUILD_COMMAND "" | 10 | BUILD_COMMAND "" |
| 11 | INSTALL_COMMAND "" | 11 | INSTALL_COMMAND "" |
| 12 | LOG_DOWNLOAD 1 | 12 | LOG_DOWNLOAD 1 |
| 13 | ) | 13 | ) |
| 14 | 14 | ||
| 15 | ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) | 15 | ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) |
| @@ -16,11 +16,16 @@ if (WIN32) · 15 unmodified lines | |||
| 16 | 16 | ||
| 17 | string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) | 17 | string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) |
| 18 | set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE PATH "List of glew include directories") | 18 | set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE PATH "List of glew include directories") |
| 19 | 19 | ||
| 20 | set(_LIB_DIR ${SOURCE_DIR}/lib/Release/Win32) | 20 | if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") |
| 21 | 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 | set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${_LIB_DIR}/glew32.lib CACHE FILEPATH "Location of GLEW release library") | 28 | set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${_LIB_DIR}/glew32.lib CACHE FILEPATH "Location of GLEW release library") |
| 23 | set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "Location of GLEW debug library") | 29 | set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "Location of GLEW debug library") |
| 24 | 30 | ||
| 25 | set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${SOURCE_DIR}/bin/Release/Win32 CACHE FILEPATH "Location of GLEW DLL") | ||
| 26 | endif () | 31 | endif () |
| @@ -3,13 +3,13 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) · 2 unmodified lines | |||
| 3 | 3 | ||
| 4 | include(ExternalProject) | 4 | include(ExternalProject) |
| 5 | ExternalProject_Add( | 5 | ExternalProject_Add( |
| 6 | ${EXTERNAL_NAME} | 6 | ${EXTERNAL_NAME} |
| 7 | URL http://softlayer-dal.dl.sourceforge.net/project/oglplus/oglplus-0.61.x/oglplus-0.61.0.zip | 7 | GIT_REPOSITORY https://github.com/matus-chochlik/oglplus.git |
| 8 | URL_MD5 bb55038c36c660d2b6c7be380414fa60 | 8 | GIT_TAG a2681383928b1166f176512cbe0f95e96fe68d08 |
| 9 | CONFIGURE_COMMAND "" | 9 | CONFIGURE_COMMAND "" |
| 10 | BUILD_COMMAND "" | 10 | BUILD_COMMAND "" |
| 11 | INSTALL_COMMAND "" | 11 | INSTALL_COMMAND "" |
| 12 | LOG_DOWNLOAD 1 | 12 | LOG_DOWNLOAD 1 |
| 13 | ) | 13 | ) |
| 14 | 14 | ||
| 15 | ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) | 15 | ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) |
| @@ -73,9 +73,14 @@ if (APPLE) · 72 unmodified lines | |||
| 73 | ) | 73 | ) |
| 74 | 74 | ||
| 75 | elseif (WIN32) | 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 | set(_LIB_EXT "lib") | 83 | set(_LIB_EXT "lib") |
| 78 | set(${EXTERNAL_NAME_UPPER}_DLL_PATH "${SOURCE_DIR}/bin/ia32/vc12" CACHE PATH "Path to TBB DLLs") | ||
| 79 | elseif (ANDROID) | 84 | elseif (ANDROID) |
| 80 | set(_TBB_LIB_DIR "${SOURCE_DIR}/lib") | 85 | set(_TBB_LIB_DIR "${SOURCE_DIR}/lib") |
| 81 | set(_LIB_PREFIX "lib") | 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 | elseif (UNIX) | 28 | elseif (UNIX) |
| 29 | set(ARCH_DIR "UNIX") | 29 | set(ARCH_DIR "UNIX") |
| 30 | elseif (WIN32) | 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 | endif () | 36 | endif () |
| 33 | 37 | ||
| 34 | find_library(FACESHIFT_LIBRARY_RELEASE NAME faceshift PATH_SUFFIXES lib/${ARCH_DIR} HINTS ${FACESHIFT_SEARCH_DIRS}) | 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 | if (WIN32) | 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 | find_path(NSIGHT_INCLUDE_DIRS | 29 | find_path(NSIGHT_INCLUDE_DIRS |
| 21 | NAMES | 30 | NAMES |
| 22 | nvToolsExt.h | 31 | nvToolsExt.h |
| @@ -25,17 +34,18 @@ if (WIN32) · 2 unmodified lines | |||
| 25 | PATHS | 34 | PATHS |
| 26 | "C:/Program Files/NVIDIA Corporation/NvToolsExt") | 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 | PATH_SUFFIXES | 38 | PATH_SUFFIXES |
| 30 | "lib/Win32" "lib" | 39 | "lib/${ARCH_DIR}" "lib" |
| 31 | PATHS | 40 | PATHS |
| 32 | "C:/Program Files/NVIDIA Corporation/NvToolsExt") | 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 | PATH_SUFFIXES | 43 | PATH_SUFFIXES |
| 35 | "lib/Win32" "lib" | 44 | "lib/${ARCH_DIR}" "lib" |
| 36 | PATHS | 45 | PATHS |
| 37 | "C:/Program Files/NVIDIA Corporation/NvToolsExt") | 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 | include(SelectLibraryConfigurations) | 49 | include(SelectLibraryConfigurations) |
| 40 | select_library_configurations(NSIGHT) | 50 | select_library_configurations(NSIGHT) |
| 41 | endif () | 51 | endif () |
| @@ -30,12 +30,20 @@ elseif (UNIX) · 29 unmodified lines | |||
| 30 | find_library(SIXENSE_LIBRARY_RELEASE lib/linux_x64/release/libsixense_x64.so HINTS ${SIXENSE_SEARCH_DIRS}) | 30 | find_library(SIXENSE_LIBRARY_RELEASE lib/linux_x64/release/libsixense_x64.so HINTS ${SIXENSE_SEARCH_DIRS}) |
| 31 | # find_library(SIXENSE_LIBRARY_DEBUG lib/linux_x64/debug/libsixensed_x64.so HINTS ${SIXENSE_SEARCH_DIRS}) | 31 | # find_library(SIXENSE_LIBRARY_DEBUG lib/linux_x64/debug/libsixensed_x64.so HINTS ${SIXENSE_SEARCH_DIRS}) |
| 32 | elseif (WIN32) | 32 | elseif (WIN32) |
| 33 | find_library(SIXENSE_LIBRARY_RELEASE lib/win32/release_dll/sixense.lib HINTS ${SIXENSE_SEARCH_DIRS}) | 33 | if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") |
| 34 | find_library(SIXENSE_LIBRARY_DEBUG lib/win32/debug_dll/sixensed.lib HINTS ${SIXENSE_SEARCH_DIRS}) | 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}) | 44 | find_path(SIXENSE_DEBUG_DLL_PATH "sixensed${ARCH_SUFFIX}.dll" PATH_SUFFIXES bin/${ARCH_DIR}/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}) | 45 | find_path(SIXENSE_RELEASE_DLL_PATH "sixense${ARCH_SUFFIX}.dll" PATH_SUFFIXES bin/${ARCH_DIR}/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}) | 46 | find_path(SIXENSE_DEVICE_DLL_PATH DeviceDLL.dll PATH_SUFFIXES samples/${ARCH_DIR}/sixense_simple3d HINTS ${SIXENSE_SEARCH_DIRS}) |
| 39 | endif () | 47 | endif () |
| 40 | 48 | ||
| 41 | include(SelectLibraryConfigurations) | 49 | include(SelectLibraryConfigurations) |
| @@ -49,7 +49,7 @@ elseif (UNIX AND NOT ANDROID) · 48 unmodified lines | |||
| 49 | endif () | 49 | endif () |
| 50 | 50 | ||
| 51 | elseif (WIN32) | 51 | elseif (WIN32) |
| 52 | if (CMAKE_CL_64) | 52 | if(CMAKE_SIZEOF_VOID_P EQUAL 8) |
| 53 | set(_TBB_ARCH_DIR "intel64") | 53 | set(_TBB_ARCH_DIR "intel64") |
| 54 | else() | 54 | else() |
| 55 | set(_TBB_ARCH_DIR "ia32") | 55 | set(_TBB_ARCH_DIR "ia32") |
| @@ -100,12 +100,12 @@ var NUM_BUTTONS = 3; · 99 unmodified lines | |||
| 100 | var screenSize = Controller.getViewportDimensions(); | 100 | var screenSize = Controller.getViewportDimensions(); |
| 101 | var startX = screenSize.x / 2 - (NUM_BUTTONS * (BUTTON_SIZE + PADDING)) / 2; | 101 | var startX = screenSize.x / 2 - (NUM_BUTTONS * (BUTTON_SIZE + PADDING)) / 2; |
| 102 | Script.include(["../../libraries/toolBars.js"]); | 102 | Script.include(["../../libraries/toolBars.js"]); |
| 103 | const persistKey = "highfidelity.gun.toolbar.position"; | 103 | var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.gun.toolbar", function (screenSize) { |
| 104 | var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL); | 104 | return { |
| 105 | toolBar.save = function () { | 105 | x: startX, |
| 106 | Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y])); | 106 | y: (screenSize.y - (BUTTON_SIZE + PADDING)), |
| 107 | }; | 107 | }; |
| 108 | var old = JSON.parse(Settings.getValue(persistKey) || '0'); | 108 | }); |
| 109 | var reticle = Overlays.addOverlay("image", { | 109 | var reticle = Overlays.addOverlay("image", { |
| 110 | x: screenSize.x / 2 - (BUTTON_SIZE / 2), | 110 | x: screenSize.x / 2 - (BUTTON_SIZE / 2), |
| 111 | y: screenSize.y / 2 - (BUTTON_SIZE / 2), | 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 | var offButton = toolBar.addOverlay("image", { | 118 | var offButton = toolBar.addOverlay("image", { |
| 119 | x: old ? old[0] : startX, | ||
| 120 | y: old ? old[1] : (screenSize.y - (BUTTON_SIZE + PADDING)), | ||
| 121 | width: BUTTON_SIZE, | 119 | width: BUTTON_SIZE, |
| 122 | height: BUTTON_SIZE, | 120 | height: BUTTON_SIZE, |
| 123 | imageURL: HIFI_PUBLIC_BUCKET + "images/gun/close.svg", | 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 | function shootBullet(position, velocity, grenade) { | 181 | function shootBullet(position, velocity, grenade) { |
| 184 | var BULLET_SIZE = 0.10; | 182 | var BULLET_SIZE = .09; |
| 185 | var BULLET_LIFETIME = 10.0; | 183 | var BULLET_LIFETIME = 10.0; |
| 186 | var BULLET_GRAVITY = -0.25; | 184 | var BULLET_GRAVITY = -0.25; |
| 187 | var GRENADE_VELOCITY = 15.0; | 185 | var GRENADE_VELOCITY = 15.0; |
| @@ -16,7 +16,6 @@ Script.load("lobby.js"); · 15 unmodified lines | |||
| 16 | Script.load("notifications.js"); | 16 | Script.load("notifications.js"); |
| 17 | Script.load("users.js"); | 17 | Script.load("users.js"); |
| 18 | Script.load("grab.js"); | 18 | Script.load("grab.js"); |
| 19 | Script.load("pointer.js"); | ||
| 20 | Script.load("directory.js"); | 19 | Script.load("directory.js"); |
| 21 | Script.load("mouseLook.js"); | 20 | Script.load("mouseLook.js"); |
| 22 | Script.load("hmdControls.js"); | 21 | Script.load("hmdControls.js"); |
| @@ -33,15 +33,13 @@ var BUTTON_SIZE = 32; · 32 unmodified lines | |||
| 33 | var PADDING = 3; | 33 | var PADDING = 3; |
| 34 | 34 | ||
| 35 | Script.include(["libraries/toolBars.js"]); | 35 | Script.include(["libraries/toolBars.js"]); |
| 36 | var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL); | 36 | var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.dice.toolbar", function (screenSize) { |
| 37 | const persistKey = "highfidelity.dice.toolbar.position"; | 37 | return { |
| 38 | toolBar.save = function () { | 38 | x: (screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING), |
| 39 | Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y])); | 39 | y: (screenSize.y - (BUTTON_SIZE + PADDING)) |
| 40 | }; | 40 | }; |
| 41 | var old = JSON.parse(Settings.getValue(persistKey) || '0'); | 41 | }); |
| 42 | var offButton = toolBar.addOverlay("image", { | 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 | width: BUTTON_SIZE, | 43 | width: BUTTON_SIZE, |
| 46 | height: BUTTON_SIZE, | 44 | height: BUTTON_SIZE, |
| 47 | imageURL: HIFI_PUBLIC_BUCKET + "images/close.png", | 45 | imageURL: HIFI_PUBLIC_BUCKET + "images/close.png", |
| @@ -49,7 +49,6 @@ selectionManager.addEventListener(function() { · 48 unmodified lines | |||
| 49 | lightOverlayManager.updatePositions(); | 49 | lightOverlayManager.updatePositions(); |
| 50 | }); | 50 | }); |
| 51 | 51 | ||
| 52 | var windowDimensions = Controller.getViewportDimensions(); | ||
| 53 | var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/"; | 52 | var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/"; |
| 54 | var toolHeight = 50; | 53 | var toolHeight = 50; |
| 55 | var toolWidth = 50; | 54 | var toolWidth = 50; |
| @@ -143,7 +142,12 @@ var toolBar = (function () { · 87 unmodified lines | |||
| 143 | browseMarketplaceButton; | 142 | browseMarketplaceButton; |
| 144 | 143 | ||
| 145 | function initialize() { | 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 | browseMarketplaceButton = toolBar.addTool({ | 152 | browseMarketplaceButton = toolBar.addTool({ |
| 149 | imageURL: toolIconUrl + "marketplace.svg", | 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 | var newModelButtonDown = false; | 328 | var newModelButtonDown = false; |
| 357 | var browseMarketplaceButtonDown = false; | 329 | var browseMarketplaceButtonDown = false; |
| 358 | that.mousePressEvent = function (event) { | 330 | that.mousePressEvent = function (event) { |
| @@ -552,6 +524,7 @@ var toolBar = (function () { · 193 unmodified lines | |||
| 552 | toolBar.cleanup(); | 524 | toolBar.cleanup(); |
| 553 | }; | 525 | }; |
| 554 | 526 | ||
| 527 | initialize(); | ||
| 555 | return that; | 528 | return that; |
| 556 | }()); | 529 | }()); |
| 557 | 530 | ||
| @@ -931,7 +904,6 @@ var lastPosition = null; · 373 unmodified lines | |||
| 931 | 904 | ||
| 932 | // Do some stuff regularly, like check for placement of various overlays | 905 | // Do some stuff regularly, like check for placement of various overlays |
| 933 | Script.update.connect(function (deltaTime) { | 906 | Script.update.connect(function (deltaTime) { |
| 934 | toolBar.move(); | ||
| 935 | progressDialog.move(); | 907 | progressDialog.move(); |
| 936 | selectionDisplay.checkMove(); | 908 | selectionDisplay.checkMove(); |
| 937 | var dOrientation = Math.abs(Quat.dot(Camera.orientation, lastOrientation) - 1); | 909 | var dOrientation = Math.abs(Quat.dot(Camera.orientation, lastOrientation) - 1); |
| @@ -8,7 +8,7 @@ body { · 7 unmodified lines | |||
| 8 | background-color: rgb(76, 76, 76); | 8 | background-color: rgb(76, 76, 76); |
| 9 | color: rgb(204, 204, 204); | 9 | color: rgb(204, 204, 204); |
| 10 | font-family: Arial; | 10 | font-family: Arial; |
| 11 | font-size: 8.25pt; | 11 | font-size: 9.0pt; |
| 12 | 12 | ||
| 13 | -webkit-touch-callout: none; | 13 | -webkit-touch-callout: none; |
| 14 | -webkit-user-select: none; | 14 | -webkit-user-select: none; |
| @@ -58,6 +58,7 @@ body { · 43 unmodified lines | |||
| 58 | 58 | ||
| 59 | .multi-property-section { | 59 | .multi-property-section { |
| 60 | } | 60 | } |
| 61 | |||
| 61 | .property-section { | 62 | .property-section { |
| 62 | display: block; | 63 | display: block; |
| 63 | margin: 10 10; | 64 | margin: 10 10; |
| @@ -132,7 +133,7 @@ input.no-spin::-webkit-inner-spin-button { · 68 unmodified lines | |||
| 132 | table#entity-table { | 133 | table#entity-table { |
| 133 | border-collapse: collapse; | 134 | border-collapse: collapse; |
| 134 | font-family: Sans-Serif; | 135 | font-family: Sans-Serif; |
| 135 | font-size: 7.5pt; | 136 | font-size: 9pt; |
| 136 | width: 100%; | 137 | width: 100%; |
| 137 | } | 138 | } |
| 138 | 139 | ||
| @@ -156,7 +157,7 @@ table#entity-table { · 17 unmodified lines | |||
| 156 | } | 157 | } |
| 157 | 158 | ||
| 158 | #entity-table td { | 159 | #entity-table td { |
| 159 | font-size: 8.25pt; | 160 | font-size: 9.0pt; |
| 160 | border: 0pt black solid; | 161 | border: 0pt black solid; |
| 161 | word-wrap: nowrap; | 162 | word-wrap: nowrap; |
| 162 | white-space: nowrap; | 163 | white-space: nowrap; |
| @@ -176,14 +177,14 @@ th#entity-type { · 13 unmodified lines | |||
| 176 | 177 | ||
| 177 | div.input-area { | 178 | div.input-area { |
| 178 | display: inline-block; | 179 | display: inline-block; |
| 179 | font-size: 7.5pt; | 180 | font-size: 9pt; |
| 180 | } | 181 | } |
| 181 | 182 | ||
| 182 | input { | 183 | input { |
| 183 | } | 184 | } |
| 184 | 185 | ||
| 185 | #type { | 186 | #type { |
| 186 | font-size: 10.5pt; | 187 | font-size: 9.0pt; |
| 187 | } | 188 | } |
| 188 | 189 | ||
| 189 | #type label { | 190 | #type label { |
| @@ -191,14 +192,14 @@ input { · 1 unmodified line | |||
| 191 | } | 192 | } |
| 192 | 193 | ||
| 193 | input, textarea { | 194 | input, textarea { |
| 194 | background-color: rgb(102, 102, 102); | 195 | background-color: rgb(63, 63, 63); |
| 195 | color: rgb(204, 204, 204); | 196 | color: rgb(255, 255, 255); |
| 196 | border: none; | 197 | border: none; |
| 197 | font-size: 7.5pt; | 198 | font-size: 9pt; |
| 198 | } | 199 | } |
| 199 | 200 | ||
| 200 | input:disabled, textarea:disabled { | 201 | input:disabled, textarea:disabled { |
| 201 | background-color: rgb(102, 102, 102); | 202 | background-color: rgb(63, 63, 63); |
| 202 | color: rgb(160, 160, 160); | 203 | color: rgb(160, 160, 160); |
| 203 | } | 204 | } |
| 204 | 205 | ||
| @@ -224,7 +225,7 @@ input:disabled, textarea:disabled { · 19 unmodified lines | |||
| 224 | #properties-list .property { | 225 | #properties-list .property { |
| 225 | padding: 4pt; | 226 | padding: 4pt; |
| 226 | border-bottom: 0.75pt solid rgb(63, 63, 63); | 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 | font-weight: bold; | 246 | font-weight: bold; |
| 246 | overflow: hidden; | 247 | overflow: hidden; |
| 247 | text-overflow: ellipsis; | 248 | text-overflow: ellipsis; |
| 248 | |||
| 249 | vertical-align: middle; | 249 | vertical-align: middle; |
| 250 | height: 1.2em; | 250 | height: 1.2em; |
| 251 | } | 251 | } |
| @@ -270,9 +270,7 @@ div.inner { · 18 unmodified lines | |||
| 270 | } | 270 | } |
| 271 | 271 | ||
| 272 | td { | 272 | td { |
| 273 | 273 | vertical-align: top; | |
| 274 | |||
| 275 | vertical-align: top; | ||
| 276 | } | 274 | } |
| 277 | 275 | ||
| 278 | #no-entities { | 276 | #no-entities { |
| @@ -126,7 +126,7 @@ Tool.prototype = new Overlay2D; · 125 unmodified lines | |||
| 126 | Tool.IMAGE_HEIGHT = 50; | 126 | Tool.IMAGE_HEIGHT = 50; |
| 127 | Tool.IMAGE_WIDTH = 50; | 127 | Tool.IMAGE_WIDTH = 50; |
| 128 | 128 | ||
| 129 | ToolBar = function(x, y, direction) { | 129 | ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPositionFunction) { |
| 130 | this.tools = new Array(); | 130 | this.tools = new Array(); |
| 131 | this.x = x; | 131 | this.x = x; |
| 132 | this.y = y; | 132 | this.y = y; |
| @@ -336,7 +336,7 @@ ToolBar = function(x, y, direction) { · 203 unmodified lines | |||
| 336 | return (that.x <= x) && (x <= (that.x + that.width)) && | 336 | return (that.x <= x) && (x <= (that.x + that.width)) && |
| 337 | (that.y <= y) && (y <= (that.y + that.height)); | 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 | that.isHovering = enable; | 340 | that.isHovering = enable; |
| 341 | if (that.back) { | 341 | if (that.back) { |
| 342 | if (enable) { | 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 | // These are currently only doing that which is necessary for toolbar hover and toolbar drag. | 371 | // These are currently only doing that which is necessary for toolbar hover and toolbar drag. |
| 352 | // They have not yet been extended to tool hover/click/release, etc. | 372 | // They have not yet been extended to tool hover/click/release, etc. |
| 353 | this.mousePressEvent = function (event) { | 373 | this.mousePressEvent = function (event) { |
| @@ -375,15 +395,19 @@ ToolBar = function(x, y, direction) { · 21 unmodified lines | |||
| 375 | } | 395 | } |
| 376 | that.move(that.dragOffsetX + event.x, that.dragOffsetY + event.y); | 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 | Controller.mousePressEvent.connect(this.mousePressEvent); | 404 | Controller.mousePressEvent.connect(this.mousePressEvent); |
| 379 | Controller.mouseMoveEvent.connect(this.mouseMove); | 405 | Controller.mouseMoveEvent.connect(this.mouseMove); |
| 380 | // Called on move. A different approach would be to have all this on the prototype, | 406 | Script.update.connect(that.checkResize); |
| 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 () { }; | ||
| 383 | // This compatability hack breaks the model, but makes converting existing scripts easier: | 407 | // This compatability hack breaks the model, but makes converting existing scripts easier: |
| 384 | this.addOverlay = function (ignored, oldSchoolProperties) { | 408 | this.addOverlay = function (ignored, oldSchoolProperties) { |
| 385 | var properties = JSON.parse(JSON.stringify(oldSchoolProperties)); // a copy | 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 | that.move(properties.x, properties.y); | 411 | that.move(properties.x, properties.y); |
| 388 | } | 412 | } |
| 389 | delete properties.x; | 413 | delete properties.x; |
| @@ -392,6 +416,23 @@ ToolBar = function(x, y, direction) { · 2 unmodified lines | |||
| 392 | var id = that.tools[index].overlay(); | 416 | var id = that.tools[index].overlay(); |
| 393 | return id; | 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 | ToolBar.SPACING = 4; | 437 | ToolBar.SPACING = 4; |
| 397 | ToolBar.VERTICAL = 0; | 438 | ToolBar.VERTICAL = 0; |
| @@ -9,8 +9,6 @@ · 8 unmodified lines | |||
| 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | 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 | var lastX = Window.getCursorPositionX(); | 12 | var lastX = Window.getCursorPositionX(); |
| 15 | var lastY = Window.getCursorPositionY(); | 13 | var lastY = Window.getCursorPositionY(); |
| 16 | var yawFromMouse = 0; | 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 | function updateMapping() { | 69 | function updateMapping() { |
| 50 | if (keyboardID != 0) { | 70 | if (keyboardID != 0) { |
| 51 | if (active) { | 71 | if (active) { |
| @@ -55,41 +75,40 @@ var mouseLook = (function () { · 3 unmodified lines | |||
| 55 | yawSpeed = 0; | 75 | yawSpeed = 0; |
| 56 | pitchSpeed = 0; | 76 | pitchSpeed = 0; |
| 57 | 77 | ||
| 58 | var a = Controller.getAvailableInputs(keyboardID)[10].input.channel; | 78 | var a = findInput("A").channel; |
| 59 | var d = Controller.getAvailableInputs(keyboardID)[13].input.channel; | 79 | var d = findInput("D").channel; |
| 60 | var left = Controller.getAvailableInputs(keyboardID)[36].input.channel; | 80 | var left = findInput("Left").channel; |
| 61 | var right = Controller.getAvailableInputs(keyboardID)[38].input.channel; | 81 | var right = findInput("Right").channel; |
| 62 | var shift = Controller.getAvailableInputs(keyboardID)[41].input.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 | var inputChannels = Controller.getAllActions()[i].inputChannels; | 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 | var inputChannel = inputChannels[j]; | 87 | var inputChannel = inputChannels[j]; |
| 68 | |||
| 69 | // make a, d, left, and right strafe | 88 | // make a, d, left, and right strafe |
| 70 | if ((inputChannel.input.channel == a || inputChannel.input.channel == left) && inputChannel.modifier.device == 0) { | 89 | if ((inputChannel.input.channel == a || inputChannel.input.channel == left) && inputChannel.modifier.device == 0) { |
| 71 | Controller.removeInputChannel(inputChannel); | 90 | Controller.removeInputChannel(inputChannel); |
| 72 | inputChannel.action = 2; | 91 | inputChannel.action = findAction("LATERAL_LEFT"); |
| 73 | Controller.addInputChannel(inputChannel); | 92 | Controller.addInputChannel(inputChannel); |
| 74 | } else if ((inputChannel.input.channel == d || inputChannel.input.channel == right) && inputChannel.modifier.device == 0) { | 93 | } else if ((inputChannel.input.channel == d || inputChannel.input.channel == right) && inputChannel.modifier.device == 0) { |
| 75 | Controller.removeInputChannel(inputChannel); | 94 | Controller.removeInputChannel(inputChannel); |
| 76 | inputChannel.action = 3; | 95 | inputChannel.action = findAction("LATERAL_RIGHT"); |
| 77 | Controller.addInputChannel(inputChannel); | 96 | Controller.addInputChannel(inputChannel); |
| 78 | } | 97 | } |
| 79 | } | 98 | } |
| 80 | } | 99 | } |
| 81 | // make shift + a/d/left/right change yaw/pitch | 100 | for (var i = findAction("LATERAL_LEFT"); i <= findAction("LATERAL_RIGHT"); i++) { |
| 82 | for (i = 2; i <= 3; i++) { | ||
| 83 | var inputChannels = Controller.getAllActions()[i].inputChannels; | 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 | var inputChannel = inputChannels[j]; | 103 | var inputChannel = inputChannels[j]; |
| 104 | // make shift + a/d/left/right change yaw/pitch | ||
| 86 | if ((inputChannel.input.channel == a || inputChannel.input.channel == left) && inputChannel.modifier.channel == shift) { | 105 | if ((inputChannel.input.channel == a || inputChannel.input.channel == left) && inputChannel.modifier.channel == shift) { |
| 87 | Controller.removeInputChannel(inputChannel); | 106 | Controller.removeInputChannel(inputChannel); |
| 88 | inputChannel.action = 6; | 107 | inputChannel.action = findAction("YAW_LEFT"); |
| 89 | Controller.addInputChannel(inputChannel); | 108 | Controller.addInputChannel(inputChannel); |
| 90 | } else if ((inputChannel.input.channel == d || inputChannel.input.channel == right) && inputChannel.modifier.channel == shift) { | 109 | } else if ((inputChannel.input.channel == d || inputChannel.input.channel == right) && inputChannel.modifier.channel == shift) { |
| 91 | Controller.removeInputChannel(inputChannel); | 110 | Controller.removeInputChannel(inputChannel); |
| 92 | inputChannel.action = 7; | 111 | inputChannel.action = findAction("YAW_RIGHT"); |
| 93 | Controller.addInputChannel(inputChannel); | 112 | Controller.addInputChannel(inputChannel); |
| 94 | } | 113 | } |
| 95 | } | 114 | } |
| @@ -134,8 +153,8 @@ var mouseLook = (function () { · 38 unmodified lines | |||
| 134 | } | 153 | } |
| 135 | 154 | ||
| 136 | function resetCursorPosition() { | 155 | function resetCursorPosition() { |
| 137 | var newX = Window.x + Window.innerWidth / 2; | 156 | var newX = Window.x + Window.innerWidth / 2.0; |
| 138 | var newY = Window.y + Window.innerHeight / 2; | 157 | var newY = Window.y + Window.innerHeight / 2.0; |
| 139 | Window.setCursorPosition(newX, newY); | 158 | Window.setCursorPosition(newX, newY); |
| 140 | lastX = newX; | 159 | lastX = newX; |
| 141 | lastY = newY; | 160 | lastY = newY; |
| @@ -10,17 +10,16 @@ · 9 unmodified lines | |||
| 10 | // | 10 | // |
| 11 | // Distributed under the Apache License, Version 2.0. | 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 | 12 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html |
| 13 | // | 13 | |
| 14 | Script.include('lineRider.js') | 14 | var LINE_DIMENSIONS = 5; |
| 15 | var MAX_POINTS_PER_LINE = 30; | 15 | var LIFETIME = 6000; |
| 16 | var LINE_LIFETIME = 60 * 5 //5 minute lifetime | ||
| 17 | 16 | ||
| 18 | var colorPalette = [{ | 17 | var colorPalette = [{ |
| 19 | red: 236, | 18 | red: 236, |
| 20 | green: 208, | 19 | green: 208, |
| 21 | blue: 120 | 20 | blue: 120 |
| 22 | }, { | 21 | }, { |
| 23 | red: 217, | 22 | red: 214, |
| 24 | green: 91, | 23 | green: 91, |
| 25 | blue: 67 | 24 | blue: 67 |
| 26 | }, { | 25 | }, { |
| @@ -40,15 +39,6 @@ var colorPalette = [{ · 13 unmodified lines | |||
| 40 | var currentColorIndex = 0; | 39 | var currentColorIndex = 0; |
| 41 | var currentColor = colorPalette[currentColorIndex]; | 40 | var currentColor = colorPalette[currentColorIndex]; |
| 42 | 41 | ||
| 43 | |||
| 44 | |||
| 45 | if (hydraCheck() === true) { | ||
| 46 | HydraPaint(); | ||
| 47 | } else { | ||
| 48 | MousePaint(); | ||
| 49 | } | ||
| 50 | |||
| 51 | |||
| 52 | function cycleColor() { | 42 | function cycleColor() { |
| 53 | currentColor = colorPalette[++currentColorIndex]; | 43 | currentColor = colorPalette[++currentColorIndex]; |
| 54 | if (currentColorIndex === colorPalette.length - 1) { | 44 | if (currentColorIndex === colorPalette.length - 1) { |
| @@ -57,42 +47,17 @@ function cycleColor() { · 2 unmodified lines | |||
| 57 | 47 | ||
| 58 | } | 48 | } |
| 59 | 49 | ||
| 60 | function hydraCheck() { | 50 | MousePaint(); |
| 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 ************************** | ||
| 70 | 51 | ||
| 71 | function MousePaint() { | 52 | function MousePaint() { |
| 72 | var DRAWING_DISTANCE = 2; | 53 | var DRAWING_DISTANCE = 5; |
| 73 | var lines = []; | 54 | var lines = []; |
| 74 | var deletedLines = []; | ||
| 75 | var isDrawing = false; | 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 | var LINE_WIDTH = 7; | 57 | var LINE_WIDTH = 7; |
| 91 | var line; | 58 | var line, linePosition; |
| 92 | var points = []; | ||
| 93 | |||
| 94 | 59 | ||
| 95 | var BRUSH_SIZE = 0.02; | 60 | var BRUSH_SIZE = .05; |
| 96 | 61 | ||
| 97 | var brush = Entities.addEntity({ | 62 | var brush = Entities.addEntity({ |
| 98 | type: 'Sphere', | 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 | line = Entities.addEntity({ | 80 | line = Entities.addEntity({ |
| 115 | position: MyAvatar.position, | 81 | position: position, |
| 116 | type: "Line", | 82 | type: "Line", |
| 117 | color: currentColor, | 83 | color: currentColor, |
| 118 | dimensions: { | 84 | dimensions: { |
| 119 | x: 10, | 85 | x: LINE_DIMENSIONS, |
| 120 | y: 10, | 86 | y: LINE_DIMENSIONS, |
| 121 | z: 10 | 87 | z: LINE_DIMENSIONS |
| 122 | }, | 88 | }, |
| 89 | linePoints: [], | ||
| 123 | lineWidth: LINE_WIDTH, | 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 | lines.push(line); | 93 | lines.push(line); |
| 133 | } | 94 | } |
| 134 | 95 | ||
| 135 | 96 | ||
| 136 | function mouseMoveEvent(event) { | 97 | function mouseMoveEvent(event) { |
| 137 | 98 | ||
| 99 | var worldPoint = computeWorldPoint(event); | ||
| 100 | Entities.editEntity(brush, { | ||
| 101 | position: worldPoint | ||
| 102 | }); | ||
| 103 | |||
| 138 | if (!isDrawing) { | 104 | if (!isDrawing) { |
| 139 | return; | 105 | return; |
| 140 | } | 106 | } |
| 141 | 107 | ||
| 142 | var pickRay = Camera.computePickRay(event.x, event.y); | 108 | var localPoint = computeLocalPoint(event) |
| 143 | var addVector = Vec3.multiply(Vec3.normalize(pickRay.direction), DRAWING_DISTANCE); | 109 | var success = Entities.appendPoint(line, localPoint); |
| 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 | |||
| 154 | 110 | ||
| 155 | if (points.length === MAX_POINTS_PER_LINE) { | 111 | if (!success) { |
| 156 | //We need to start a new line! | 112 | newLine(worldPoint); |
| 157 | newLine(point); | 113 | Entities.appendPoint(line, computeLocalPoint(event)); |
| 158 | } | 114 | } |
| 159 | } | 115 | } |
| 160 | 116 | ||
| @@ -171,17 +127,26 @@ function MousePaint() { · 10 unmodified lines | |||
| 171 | lines.push(restoredLine); | 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 | function mousePressEvent(event) { | 142 | function mousePressEvent(event) { |
| 175 | if(!event.isLeftButton) { | 143 | if (!event.isLeftButton) { |
| 176 | isDrawing = false; | 144 | isDrawing = false; |
| 177 | return; | 145 | return; |
| 178 | } | 146 | } |
| 179 | lineRider.mousePressEvent(event); | 147 | newLine(computeWorldPoint(event)); |
| 180 | path = []; | ||
| 181 | newLine(); | ||
| 182 | isDrawing = true; | 148 | isDrawing = true; |
| 183 | 149 | ||
| 184 | |||
| 185 | } | 150 | } |
| 186 | 151 | ||
| 187 | function mouseReleaseEvent() { | 152 | function mouseReleaseEvent() { |
| @@ -198,21 +163,21 @@ function MousePaint() { · 10 unmodified lines | |||
| 198 | if (event.text === "z") { | 163 | if (event.text === "z") { |
| 199 | undoStroke(); | 164 | undoStroke(); |
| 200 | } | 165 | } |
| 201 | if(event.text === "x") { | 166 | if (event.text === "x") { |
| 202 | redoStroke(); | 167 | redoStroke(); |
| 203 | } | 168 | } |
| 204 | } | 169 | } |
| 205 | 170 | ||
| 171 | |||
| 172 | |||
| 206 | function cleanup() { | 173 | function cleanup() { |
| 207 | lines.forEach(function(line) { | 174 | lines.forEach(function(line) { |
| 208 | Entities.deleteEntity(line); | 175 | // Entities.deleteEntity(line); |
| 209 | }); | 176 | }); |
| 210 | Entities.deleteEntity(brush); | 177 | Entities.deleteEntity(brush); |
| 211 | lineRider.cleanup(); | ||
| 212 | 178 | ||
| 213 | } | 179 | } |
| 214 | 180 | ||
| 215 | |||
| 216 | Controller.mousePressEvent.connect(mousePressEvent); | 181 | Controller.mousePressEvent.connect(mousePressEvent); |
| 217 | Controller.mouseReleaseEvent.connect(mouseReleaseEvent); | 182 | Controller.mouseReleaseEvent.connect(mouseReleaseEvent); |
| 218 | Controller.mouseMoveEvent.connect(mouseMoveEvent); | 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 | function randFloat(low, high) { | 190 | function randFloat(low, high) { |
| 486 | return low + Math.random() * (high - low); | 191 | return low + Math.random() * (high - low); |
| 487 | } | 192 | } |
| @@ -29,19 +29,13 @@ var buttonOnColor = { · 28 unmodified lines | |||
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| 31 | HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; | 31 | HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; |
| 32 | var screenSize = Controller.getViewportDimensions(); | ||
| 33 | 32 | ||
| 34 | var userCanPoint = false; | 33 | var userCanPoint = false; |
| 35 | Script.include(["libraries/toolBars.js"]); | 34 | Script.include(["libraries/toolBars.js"]); |
| 36 | const persistKey = "highfidelity.pointer.toolbar.position"; | 35 | var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.pointer.toolbar", function (screenSize) { |
| 37 | var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL); | 36 | return {x: screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING, y: screenSize.y - (BUTTON_SIZE + PADDING)}, |
| 38 | toolBar.save = function () { | 37 | }); |
| 39 | Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y])); | ||
| 40 | }; | ||
| 41 | var old = JSON.parse(Settings.getValue(persistKey) || '0'); | ||
| 42 | var pointerButton = toolBar.addOverlay("image", { | 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 | width: BUTTON_SIZE, | 39 | width: BUTTON_SIZE, |
| 46 | height: BUTTON_SIZE, | 40 | height: BUTTON_SIZE, |
| 47 | imageURL: HIFI_PUBLIC_BUCKET + "images/laser.png", | 41 | imageURL: HIFI_PUBLIC_BUCKET + "images/laser.png", |
| @@ -22,10 +22,12 @@ Script.setTimeout(function() { · 21 unmodified lines | |||
| 22 | type: "Model", | 22 | type: "Model", |
| 23 | modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.fbx", | 23 | modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.fbx", |
| 24 | compoundShapeURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.obj", | 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 | position: MyAvatar.getRightPalmPosition(), // initial position doesn't matter, as long as it's close | 26 | position: MyAvatar.getRightPalmPosition(), // initial position doesn't matter, as long as it's close |
| 27 | rotation: MyAvatar.orientation, | 27 | rotation: MyAvatar.orientation, |
| 28 | damping: .1, | 28 | damping: .1, |
| 29 | collisionSoundURL: "http://public.highfidelity.io/sounds/Collisions-hitsandslaps/67LCollision07.wav", | ||
| 30 | restitution: 0.01, | ||
| 29 | collisionsWillMove: true | 31 | collisionsWillMove: true |
| 30 | }); | 32 | }); |
| 31 | actionID = Entities.addAction("hold", stickID, {relativePosition: {x: 0.0, y: 0.0, z: -0.9}, | 33 | actionID = Entities.addAction("hold", stickID, {relativePosition: {x: 0.0, y: 0.0, z: -0.9}, |
| @@ -9,48 +9,52 @@ · 8 unmodified lines | |||
| 9 | // Distributed under the Apache License, Version 2.0. | 9 | // Distributed under the Apache License, Version 2.0. |
| 10 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | 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) { | 18 | hslToRgb = function(hslColor) { |
| 46 | return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); | 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) { | 51 | |
| 50 | return low + Math.random() * (high - low); | 52 | |
| 53 | randFloat = function(low, high) { | ||
| 54 | return low + Math.random() * (high - low); | ||
| 51 | } | 55 | } |
| 52 | 56 | ||
| 53 | 57 | ||
| 54 | function randInt(low, high) { | 58 | randInt = function(low, high) { |
| 55 | return Math.floor(randFloat(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 | this.onValueChanged = function(value) {}; | 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 | this.destroy = function() { | 140 | this.destroy = function() { |
| 124 | Overlays.deleteOverlay(this.background); | 141 | Overlays.deleteOverlay(this.background); |
| 125 | Overlays.deleteOverlay(this.thumb); | 142 | Overlays.deleteOverlay(this.thumb); |
| @@ -613,6 +630,14 @@ Panel = function(x, y) { · 487 unmodified lines | |||
| 613 | return null; | 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 | this.update = function(name) { | 641 | this.update = function(name) { |
| 617 | var item = this.items[name]; | 642 | var item = this.items[name]; |
| 618 | if (item != null) { | 643 | if (item != null) { |
| @@ -10,25 +10,7 @@ · 9 unmodified lines | |||
| 10 | 10 | ||
| 11 | Script.include("cookies.js"); | 11 | Script.include("cookies.js"); |
| 12 | 12 | ||
| 13 | var panel = new Panel(10, 400); | 13 | var panel = new Panel(10, 800); |
| 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 | ); | ||
| 32 | 14 | ||
| 33 | panel.newSlider("Num Feed Opaques", 0, 1000, | 15 | panel.newSlider("Num Feed Opaques", 0, 1000, |
| 34 | function(value) { }, | 16 | function(value) { }, |
| @@ -48,49 +30,70 @@ panel.newSlider("Max Drawn Opaques", -1, 1000, · 13 unmodified lines | |||
| 48 | function(value) { return (value); } | 30 | function(value) { return (value); } |
| 49 | ); | 31 | ); |
| 50 | 32 | ||
| 51 | panel.newCheckbox("Enable Cull Transparent", | 33 | panel.newSlider("Num Feed Transparents", 0, 100, |
| 52 | function(value) { Scene.setEngineCullTransparent((value != 0)); }, | 34 | function(value) { }, |
| 53 | function() { return Scene.doEngineCullTransparent(); }, | 35 | function() { return Scene.getEngineNumFeedTransparentItems(); }, |
| 54 | function(value) { return (value); } | 36 | function(value) { return (value); } |
| 55 | ); | 37 | ); |
| 56 | 38 | ||
| 57 | panel.newCheckbox("Enable Sort Transparent", | 39 | panel.newSlider("Num Drawn Transparents", 0, 100, |
| 58 | function(value) { Scene.setEngineSortTransparent((value != 0)); }, | 40 | function(value) { }, |
| 59 | function() { return Scene.doEngineSortTransparent(); }, | 41 | function() { return Scene.getEngineNumDrawnTransparentItems(); }, |
| 60 | function(value) { return (value); } | 42 | function(value) { return (value); } |
| 61 | ); | 43 | ); |
| 62 | 44 | ||
| 63 | panel.newCheckbox("Enable Render Transparent", | 45 | panel.newSlider("Max Drawn Transparents", -1, 100, |
| 64 | function(value) { Scene.setEngineRenderTransparent((value != 0)); }, | 46 | function(value) { Scene.setEngineMaxDrawnTransparentItems(value); }, |
| 65 | function() { return Scene.doEngineRenderTransparent(); }, | 47 | function() { return Scene.getEngineMaxDrawnTransparentItems(); }, |
| 66 | function(value) { return (value); } | 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 | function(value) { }, | 52 | function(value) { }, |
| 71 | function() { return Scene.getEngineNumFeedTransparentItems(); }, | 53 | function() { return Scene.getEngineNumFeedOverlay3DItems(); }, |
| 72 | function(value) { return (value); } | 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 | function(value) { }, | 58 | function(value) { }, |
| 77 | function() { return Scene.getEngineNumDrawnTransparentItems(); }, | 59 | function() { return Scene.getEngineNumDrawnOverlay3DItems(); }, |
| 78 | function(value) { return (value); } | 60 | function(value) { return (value); } |
| 79 | ); | 61 | ); |
| 80 | 62 | ||
| 81 | panel.newSlider("Max Drawn Transparents", -1, 100, | 63 | panel.newSlider("Max Drawn Overlay3Ds", -1, 100, |
| 82 | function(value) { Scene.setEngineMaxDrawnTransparentItems(value); }, | 64 | function(value) { Scene.setEngineMaxDrawnOverlay3DItems(value); }, |
| 83 | function() { return Scene.getEngineMaxDrawnTransparentItems(); }, | 65 | function() { return Scene.getEngineMaxDrawnOverlay3DItems(); }, |
| 84 | function(value) { return (value); } | 66 | function(value) { return (value); } |
| 85 | ); | 67 | ); |
| 86 | 68 | ||
| 87 | var tickTackPeriod = 500; | 69 | var tickTackPeriod = 500; |
| 88 | 70 | ||
| 89 | function updateCounters() { | 71 | function updateCounters() { |
| 90 | panel.set("Num Feed Opaques", panel.get("Num Feed Opaques")); | 72 | var numFeedOpaques = panel.get("Num Feed Opaques"); |
| 91 | panel.set("Num Drawn Opaques", panel.get("Num Drawn Opaques")); | 73 | var numFeedTransparents = panel.get("Num Feed Transparents"); |
| 92 | panel.set("Num Feed Transparents", panel.get("Num Feed Transparents")); | 74 | var numFeedOverlay3Ds = panel.get("Num Feed Overlay3Ds"); |
| 93 | panel.set("Num Drawn Transparents", panel.get("Num Drawn Transparents")); | 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 | Script.setInterval(updateCounters, tickTackPeriod); | 98 | Script.setInterval(updateCounters, tickTackPeriod); |
| 96 | 99 | ||
| @@ -15,7 +15,7 @@ · 14 unmodified lines | |||
| 15 | viewBox="0 0 1440 200" | 15 | viewBox="0 0 1440 200" |
| 16 | id="svg4136" | 16 | id="svg4136" |
| 17 | inkscape:version="0.91 r13725" | 17 | inkscape:version="0.91 r13725" |
| 18 | sodipodi:docname="address-bar.svg"> | 18 | sodipodi:docname="address-bar.002.svg"> |
| 19 | <metadata | 19 | <metadata |
| 20 | id="metadata4144"> | 20 | id="metadata4144"> |
| 21 | <rdf:RDF> | 21 | <rdf:RDF> |
| @@ -39,14 +39,14 @@ · 17 unmodified lines | |||
| 39 | guidetolerance="10" | 39 | guidetolerance="10" |
| 40 | inkscape:pageopacity="0" | 40 | inkscape:pageopacity="0" |
| 41 | inkscape:pageshadow="2" | 41 | inkscape:pageshadow="2" |
| 42 | inkscape:window-width="1840" | 42 | inkscape:window-width="1835" |
| 43 | inkscape:window-height="1057" | 43 | inkscape:window-height="1057" |
| 44 | id="namedview4140" | 44 | id="namedview4140" |
| 45 | showgrid="false" | 45 | showgrid="false" |
| 46 | inkscape:zoom="0.8671875" | 46 | inkscape:zoom="0.61319416" |
| 47 | inkscape:cx="707.02439" | 47 | inkscape:cx="132.58366" |
| 48 | inkscape:cy="52.468468" | 48 | inkscape:cy="52.468468" |
| 49 | inkscape:window-x="72" | 49 | inkscape:window-x="77" |
| 50 | inkscape:window-y="-8" | 50 | inkscape:window-y="-8" |
| 51 | inkscape:window-maximized="1" | 51 | inkscape:window-maximized="1" |
| 52 | inkscape:current-layer="svg4136" /> | 52 | inkscape:current-layer="svg4136" /> |
| @@ -59,6 +59,15 @@ · 6 unmodified lines | |||
| 59 | y="30" | 59 | y="30" |
| 60 | rx="16.025024" | 60 | rx="16.025024" |
| 61 | ry="17.019567" /> | 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 | <circle | 71 | <circle |
| 63 | style="fill:#b8b8b8;fill-opacity:1;stroke:none;stroke-opacity:1" | 72 | style="fill:#b8b8b8;fill-opacity:1;stroke:none;stroke-opacity:1" |
| 64 | id="path4146" | 73 | id="path4146" |
| @@ -69,4 +78,11 @@ · 4 unmodified lines | |||
| 69 | 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" | 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 | id="path4138" | 79 | id="path4138" |
| 71 | inkscape:connector-curvature="0" /> | 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 | </svg> | 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 | property int maximumX: parent ? parent.width - width : 0 | 30 | property int maximumX: parent ? parent.width - width : 0 |
| 31 | property int maximumY: parent ? parent.height - height : 0 | 31 | property int maximumY: parent ? parent.height - height : 0 |
| 32 | 32 | ||
| 33 | |||
| 33 | AddressBarDialog { | 34 | AddressBarDialog { |
| 34 | id: addressBarDialog | 35 | id: addressBarDialog |
| 35 | 36 | ||
| @@ -45,28 +46,6 @@ DialogContainer { · 9 unmodified lines | |||
| 45 | property int inputAreaHeight: 56.0 * root.scale // Height of the background's input area | 46 | property int inputAreaHeight: 56.0 * root.scale // Height of the background's input area |
| 46 | property int inputAreaStep: (height - inputAreaHeight) / 2 | 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 | MouseArea { | 49 | MouseArea { |
| 71 | // Drag the icon | 50 | // Drag the icon |
| 72 | width: parent.height | 51 | width: parent.height |
| @@ -96,6 +75,73 @@ DialogContainer { · 23 unmodified lines | |||
| 96 | maximumY: root.parent ? root.maximumY + parent.inputAreaStep : 0 | 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 | #include <EntityScriptingInterface.h> | 66 | #include <EntityScriptingInterface.h> |
| 67 | #include <ErrorDialog.h> | 67 | #include <ErrorDialog.h> |
| 68 | #include <GlowEffect.h> | 68 | #include <GlowEffect.h> |
| 69 | #include <gpu/Batch.h> | ||
| 70 | #include <gpu/Context.h> | ||
| 71 | #include <gpu/GLBackend.h> | ||
| 69 | #include <HFActionEvent.h> | 72 | #include <HFActionEvent.h> |
| 70 | #include <HFBackEvent.h> | 73 | #include <HFBackEvent.h> |
| 71 | #include <InfoView.h> | 74 | #include <InfoView.h> |
| @@ -83,12 +86,14 @@ · 11 unmodified lines | |||
| 83 | #include <PerfStat.h> | 86 | #include <PerfStat.h> |
| 84 | #include <PhysicsEngine.h> | 87 | #include <PhysicsEngine.h> |
| 85 | #include <ProgramObject.h> | 88 | #include <ProgramObject.h> |
| 89 | #include <RenderDeferredTask.h> | ||
| 86 | #include <ResourceCache.h> | 90 | #include <ResourceCache.h> |
| 87 | #include <SceneScriptingInterface.h> | 91 | #include <SceneScriptingInterface.h> |
| 88 | #include <ScriptCache.h> | 92 | #include <ScriptCache.h> |
| 89 | #include <SettingHandle.h> | 93 | #include <SettingHandle.h> |
| 90 | #include <SoundCache.h> | 94 | #include <SoundCache.h> |
| 91 | #include <TextRenderer.h> | 95 | #include <TextRenderer.h> |
| 96 | #include <Tooltip.h> | ||
| 92 | #include <UserActivityLogger.h> | 97 | #include <UserActivityLogger.h> |
| 93 | #include <UUID.h> | 98 | #include <UUID.h> |
| 94 | #include <VrMenu.h> | 99 | #include <VrMenu.h> |
| @@ -106,11 +111,9 @@ · 11 unmodified lines | |||
| 106 | 111 | ||
| 107 | #include "avatar/AvatarManager.h" | 112 | #include "avatar/AvatarManager.h" |
| 108 | 113 | ||
| 109 | #include "audio/AudioToolBox.h" | ||
| 110 | #include "audio/AudioIOStatsRenderer.h" | 114 | #include "audio/AudioIOStatsRenderer.h" |
| 111 | #include "audio/AudioScope.h" | 115 | #include "audio/AudioScope.h" |
| 112 | 116 | ||
| 113 | #include "devices/CameraToolBox.h" | ||
| 114 | #include "devices/DdeFaceTracker.h" | 117 | #include "devices/DdeFaceTracker.h" |
| 115 | #include "devices/Faceshift.h" | 118 | #include "devices/Faceshift.h" |
| 116 | #include "devices/Leapmotion.h" | 119 | #include "devices/Leapmotion.h" |
| @@ -120,12 +123,6 @@ · 3 unmodified lines | |||
| 120 | #include "devices/OculusManager.h" | 123 | #include "devices/OculusManager.h" |
| 121 | #include "devices/TV3DManager.h" | 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 | #include "scripting/AccountScriptingInterface.h" | 126 | #include "scripting/AccountScriptingInterface.h" |
| 130 | #include "scripting/AudioDeviceScriptingInterface.h" | 127 | #include "scripting/AudioDeviceScriptingInterface.h" |
| 131 | #include "scripting/ClipboardScriptingInterface.h" | 128 | #include "scripting/ClipboardScriptingInterface.h" |
| @@ -141,6 +138,7 @@ · 9 unmodified lines | |||
| 141 | #include "SpeechRecognizer.h" | 138 | #include "SpeechRecognizer.h" |
| 142 | #endif | 139 | #endif |
| 143 | 140 | ||
| 141 | #include "ui/AvatarInputs.h" | ||
| 144 | #include "ui/DataWebDialog.h" | 142 | #include "ui/DataWebDialog.h" |
| 145 | #include "ui/DialogsManager.h" | 143 | #include "ui/DialogsManager.h" |
| 146 | #include "ui/LoginDialog.h" | 144 | #include "ui/LoginDialog.h" |
| @@ -281,8 +279,6 @@ bool setupEssentials(int& argc, char** argv) { · 134 unmodified lines | |||
| 281 | auto animationCache = DependencyManager::set<AnimationCache>(); | 279 | auto animationCache = DependencyManager::set<AnimationCache>(); |
| 282 | auto ddeFaceTracker = DependencyManager::set<DdeFaceTracker>(); | 280 | auto ddeFaceTracker = DependencyManager::set<DdeFaceTracker>(); |
| 283 | auto modelBlender = DependencyManager::set<ModelBlender>(); | 281 | auto modelBlender = DependencyManager::set<ModelBlender>(); |
| 284 | auto audioToolBox = DependencyManager::set<AudioToolBox>(); | ||
| 285 | auto cameraToolBox = DependencyManager::set<CameraToolBox>(); | ||
| 286 | auto avatarManager = DependencyManager::set<AvatarManager>(); | 282 | auto avatarManager = DependencyManager::set<AvatarManager>(); |
| 287 | auto lodManager = DependencyManager::set<LODManager>(); | 283 | auto lodManager = DependencyManager::set<LODManager>(); |
| 288 | auto jsConsole = DependencyManager::set<StandAloneJSConsole>(); | 284 | auto jsConsole = DependencyManager::set<StandAloneJSConsole>(); |
| @@ -335,8 +331,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : · 46 unmodified lines | |||
| 335 | _cursorVisible(true), | 331 | _cursorVisible(true), |
| 336 | _lastMouseMove(usecTimestampNow()), | 332 | _lastMouseMove(usecTimestampNow()), |
| 337 | _lastMouseMoveWasSimulated(false), | 333 | _lastMouseMoveWasSimulated(false), |
| 338 | _touchAvgX(0.0f), | ||
| 339 | _touchAvgY(0.0f), | ||
| 340 | _isTouchPressed(false), | 334 | _isTouchPressed(false), |
| 341 | _mousePressed(false), | 335 | _mousePressed(false), |
| 342 | _enableProcessOctreeThread(true), | 336 | _enableProcessOctreeThread(true), |
| @@ -814,9 +808,9 @@ void Application::initializeGL() { · 471 unmodified lines | |||
| 814 | _idleLoopStdev.reset(); | 808 | _idleLoopStdev.reset(); |
| 815 | 809 | ||
| 816 | if (_justStarted) { | 810 | if (_justStarted) { |
| 817 | float startupTime = (float)_applicationStartupTime.elapsed() / 1000.0; | 811 | float startupTime = (float)_applicationStartupTime.elapsed() / 1000.0f; |
| 818 | _justStarted = false; | 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 | // update before the first render | 816 | // update before the first render |
| @@ -831,6 +825,7 @@ void Application::initializeUi() { · 8 unmodified lines | |||
| 831 | LoginDialog::registerType(); | 825 | LoginDialog::registerType(); |
| 832 | MessageDialog::registerType(); | 826 | MessageDialog::registerType(); |
| 833 | VrMenu::registerType(); | 827 | VrMenu::registerType(); |
| 828 | Tooltip::registerType(); | ||
| 834 | UpdateDialog::registerType(); | 829 | UpdateDialog::registerType(); |
| 835 | 830 | ||
| 836 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); | 831 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); |
| @@ -844,7 +839,7 @@ void Application::initializeUi() { · 7 unmodified lines | |||
| 844 | VrMenu::executeQueuedLambdas(); | 839 | VrMenu::executeQueuedLambdas(); |
| 845 | offscreenUi->setMouseTranslator([this](const QPointF& p){ | 840 | offscreenUi->setMouseTranslator([this](const QPointF& p){ |
| 846 | if (OculusManager::isConnected()) { | 841 | if (OculusManager::isConnected()) { |
| 847 | glm::vec2 pos = _applicationOverlay.screenToOverlay(toGlm(p)); | 842 | glm::vec2 pos = _compositor.screenToOverlay(toGlm(p)); |
| 848 | return QPointF(pos.x, pos.y); | 843 | return QPointF(pos.x, pos.y); |
| 849 | } | 844 | } |
| 850 | return QPointF(p); | 845 | return QPointF(p); |
| @@ -877,6 +872,7 @@ void Application::paintGL() { · 26 unmodified lines | |||
| 877 | OculusManager::beginFrameTiming(); | 872 | OculusManager::beginFrameTiming(); |
| 878 | } | 873 | } |
| 879 | 874 | ||
| 875 | |||
| 880 | PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings)); | 876 | PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings)); |
| 881 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); | 877 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 882 | PerformanceWarning warn(showWarnings, "Application::paintGL()"); | 878 | PerformanceWarning warn(showWarnings, "Application::paintGL()"); |
| @@ -884,6 +880,12 @@ void Application::paintGL() { · 1 unmodified line | |||
| 884 | 880 | ||
| 885 | { | 881 | { |
| 886 | PerformanceTimer perfTimer("renderOverlay"); | 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 | _applicationOverlay.renderOverlay(&renderArgs); | 889 | _applicationOverlay.renderOverlay(&renderArgs); |
| 888 | } | 890 | } |
| 889 | 891 | ||
| @@ -912,13 +914,18 @@ void Application::paintGL() { · 22 unmodified lines | |||
| 912 | } | 914 | } |
| 913 | 915 | ||
| 914 | } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { | 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 | if (OculusManager::isConnected()) { | 917 | if (OculusManager::isConnected()) { |
| 918 | _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation()); | 918 | _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation()); |
| 919 | } else { | 919 | } else { |
| 920 | _myCamera.setRotation(_myAvatar->getHead()->getOrientation()); | 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 | } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { | 930 | } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { |
| 924 | _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); | 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 | glPopMatrix(); | 974 | glPopMatrix(); |
| 968 | 975 | ||
| 969 | renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; | 976 | renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; |
| 970 | if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { | 977 | if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { |
| 971 | _rearMirrorTools->render(&renderArgs, true, _glWidget->mapFromGlobal(QCursor::pos())); | ||
| 972 | } else if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { | ||
| 973 | renderRearViewMirror(&renderArgs, _mirrorViewRect); | 978 | renderRearViewMirror(&renderArgs, _mirrorViewRect); |
| 974 | } | 979 | } |
| 975 | 980 | ||
| @@ -977,6 +982,7 @@ void Application::paintGL() { · 1 unmodified line | |||
| 977 | 982 | ||
| 978 | auto finalFbo = DependencyManager::get<GlowEffect>()->render(&renderArgs); | 983 | auto finalFbo = DependencyManager::get<GlowEffect>()->render(&renderArgs); |
| 979 | 984 | ||
| 985 | |||
| 980 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); | 986 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); |
| 981 | glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo)); | 987 | glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo)); |
| 982 | glBlitFramebuffer(0, 0, _renderResolution.x, _renderResolution.y, | 988 | glBlitFramebuffer(0, 0, _renderResolution.x, _renderResolution.y, |
| @@ -984,9 +990,10 @@ void Application::paintGL() { · 1 unmodified line | |||
| 984 | GL_COLOR_BUFFER_BIT, GL_NEAREST); | 990 | GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| 985 | glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); | 991 | glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); |
| 986 | 992 | ||
| 987 | _applicationOverlay.displayOverlayTexture(); | 993 | _compositor.displayOverlayTexture(&renderArgs); |
| 988 | } | 994 | } |
| 989 | 995 | ||
| 996 | |||
| 990 | if (!OculusManager::isConnected() || OculusManager::allowSwap()) { | 997 | if (!OculusManager::isConnected() || OculusManager::allowSwap()) { |
| 991 | _glWidget->swapBuffers(); | 998 | _glWidget->swapBuffers(); |
| 992 | } | 999 | } |
| @@ -1044,27 +1051,24 @@ void Application::resizeGL() { · 51 unmodified lines | |||
| 1044 | } else { | 1051 | } else { |
| 1045 | renderSize = _glWidget->getDeviceSize() * getRenderResolutionScale(); | 1052 | renderSize = _glWidget->getDeviceSize() * getRenderResolutionScale(); |
| 1046 | } | 1053 | } |
| 1047 | if (_renderResolution == toGlm(renderSize)) { | ||
| 1048 | return; | ||
| 1049 | } | ||
| 1050 | 1054 | ||
| 1051 | _renderResolution = toGlm(renderSize); | 1055 | if (_renderResolution != toGlm(renderSize)) { |
| 1052 | DependencyManager::get<TextureCache>()->setFrameBufferSize(renderSize); | 1056 | _renderResolution = toGlm(renderSize); |
| 1053 | resetCamerasOnResizeGL(_myCamera, _renderResolution); | 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(); | 1062 | updateProjectionMatrix(); |
| 1058 | glLoadIdentity(); | 1063 | glLoadIdentity(); |
| 1064 | } | ||
| 1059 | 1065 | ||
| 1060 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); | 1066 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); |
| 1061 | offscreenUi->resize(_glWidget->size()); | 1067 | |
| 1068 | auto canvasSize = _glWidget->size(); | ||
| 1069 | offscreenUi->resize(canvasSize); | ||
| 1062 | _glWidget->makeCurrent(); | 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 | void Application::updateProjectionMatrix() { | 1074 | void Application::updateProjectionMatrix() { |
| @@ -1568,27 +1572,9 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { · 497 unmodified lines | |||
| 1568 | _keyboardMouseDevice.mousePressEvent(event); | 1572 | _keyboardMouseDevice.mousePressEvent(event); |
| 1569 | 1573 | ||
| 1570 | if (event->button() == Qt::LeftButton) { | 1574 | if (event->button() == Qt::LeftButton) { |
| 1571 | _mouseDragStartedX = getTrueMouseX(); | 1575 | _mouseDragStarted = getTrueMouse(); |
| 1572 | _mouseDragStartedY = getTrueMouseY(); | ||
| 1573 | _mousePressed = true; | 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 | // nobody handled this - make it an action event on the _window object | 1578 | // nobody handled this - make it an action event on the _window object |
| 1593 | HFActionEvent actionEvent(HFActionEvent::startType(), | 1579 | HFActionEvent actionEvent(HFActionEvent::startType(), |
| 1594 | computePickRay(event->x(), event->y())); | 1580 | computePickRay(event->x(), event->y())); |
| @@ -1606,16 +1592,7 @@ void Application::mouseDoublePressEvent(QMouseEvent* event, unsigned int deviceI · 11 unmodified lines | |||
| 1606 | return; | 1592 | return; |
| 1607 | } | 1593 | } |
| 1608 | 1594 | ||
| 1609 | if (activeWindow() == _window) { | 1595 | _controllerScriptingInterface.emitMouseDoublePressEvent(event); |
| 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 | } | ||
| 1619 | } | 1596 | } |
| 1620 | 1597 | ||
| 1621 | void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { | 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 | if (event->button() == Qt::LeftButton) { | 1614 | if (event->button() == Qt::LeftButton) { |
| 1638 | _mousePressed = false; | 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 | // fire an action end event | 1617 | // fire an action end event |
| 1648 | HFActionEvent actionEvent(HFActionEvent::endType(), | 1618 | HFActionEvent actionEvent(HFActionEvent::endType(), |
| 1649 | computePickRay(event->x(), event->y())); | 1619 | computePickRay(event->x(), event->y())); |
| @@ -1671,22 +1641,18 @@ void Application::touchUpdateEvent(QTouchEvent* event) { · 21 unmodified lines | |||
| 1671 | bool validTouch = false; | 1641 | bool validTouch = false; |
| 1672 | if (activeWindow() == _window) { | 1642 | if (activeWindow() == _window) { |
| 1673 | const QList<QTouchEvent::TouchPoint>& tPoints = event->touchPoints(); | 1643 | const QList<QTouchEvent::TouchPoint>& tPoints = event->touchPoints(); |
| 1674 | _touchAvgX = 0.0f; | 1644 | _touchAvg = vec2(); |
| 1675 | _touchAvgY = 0.0f; | ||
| 1676 | int numTouches = tPoints.count(); | 1645 | int numTouches = tPoints.count(); |
| 1677 | if (numTouches > 1) { | 1646 | if (numTouches > 1) { |
| 1678 | for (int i = 0; i < numTouches; ++i) { | 1647 | for (int i = 0; i < numTouches; ++i) { |
| 1679 | _touchAvgX += tPoints[i].pos().x(); | 1648 | _touchAvg += toGlm(tPoints[i].pos()); |
| 1680 | _touchAvgY += tPoints[i].pos().y(); | ||
| 1681 | } | 1649 | } |
| 1682 | _touchAvgX /= (float)(numTouches); | 1650 | _touchAvg /= (float)(numTouches); |
| 1683 | _touchAvgY /= (float)(numTouches); | ||
| 1684 | validTouch = true; | 1651 | validTouch = true; |
| 1685 | } | 1652 | } |
| 1686 | } | 1653 | } |
| 1687 | if (!_isTouchPressed) { | 1654 | if (!_isTouchPressed) { |
| 1688 | _touchDragStartedAvgX = _touchAvgX; | 1655 | _touchDragStartedAvg = _touchAvg; |
| 1689 | _touchDragStartedAvgY = _touchAvgY; | ||
| 1690 | } | 1656 | } |
| 1691 | _isTouchPressed = validTouch; | 1657 | _isTouchPressed = validTouch; |
| 1692 | } | 1658 | } |
| @@ -1722,8 +1688,7 @@ void Application::touchEndEvent(QTouchEvent* event) { · 29 unmodified lines | |||
| 1722 | _keyboardMouseDevice.touchEndEvent(event); | 1688 | _keyboardMouseDevice.touchEndEvent(event); |
| 1723 | 1689 | ||
| 1724 | // put any application specific touch behavior below here.. | 1690 | // put any application specific touch behavior below here.. |
| 1725 | _touchDragStartedAvgX = _touchAvgX; | 1691 | _touchDragStartedAvg = _touchAvg; |
| 1726 | _touchDragStartedAvgY = _touchAvgY; | ||
| 1727 | _isTouchPressed = false; | 1692 | _isTouchPressed = false; |
| 1728 | 1693 | ||
| 1729 | } | 1694 | } |
| @@ -1872,9 +1837,9 @@ void Application::setFullscreen(bool fullscreen) { · 142 unmodified lines | |||
| 1872 | Menu::getInstance()->getActionForOption(MenuOption::Fullscreen)->setChecked(fullscreen); | 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 | 1840 | // 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 | 1841 | // app menu in a fullscreen window. However the OSX mechanism hides the |
| 1877 | // application menu for fullscreen apps, so the check is not required. | 1842 | // application menu for fullscreen apps, so the check is not required. |
| 1878 | #ifndef Q_OS_MAC | 1843 | #ifndef Q_OS_MAC |
| 1879 | if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) { | 1844 | if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) { |
| 1880 | if (fullscreen) { | 1845 | if (fullscreen) { |
| @@ -1939,16 +1904,15 @@ void Application::setEnableVRMode(bool enableVRMode) { · 58 unmodified lines | |||
| 1939 | // attempt to reconnect the Oculus manager - it's possible this was a workaround | 1904 | // attempt to reconnect the Oculus manager - it's possible this was a workaround |
| 1940 | // for the sixense crash | 1905 | // for the sixense crash |
| 1941 | OculusManager::disconnect(); | 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 | OculusManager::recalibrate(); | 1912 | OculusManager::recalibrate(); |
| 1945 | } else { | 1913 | } else { |
| 1946 | OculusManager::abandonCalibration(); | 1914 | OculusManager::abandonCalibration(); |
| 1947 | 1915 | OculusManager::disconnect(); | |
| 1948 | _mirrorCamera.setHmdPosition(glm::vec3()); | ||
| 1949 | _mirrorCamera.setHmdRotation(glm::quat()); | ||
| 1950 | _myCamera.setHmdPosition(glm::vec3()); | ||
| 1951 | _myCamera.setHmdRotation(glm::quat()); | ||
| 1952 | } | 1916 | } |
| 1953 | 1917 | ||
| 1954 | resizeGL(); | 1918 | resizeGL(); |
| @@ -1960,44 +1924,34 @@ void Application::setLowVelocityFilter(bool lowVelocityFilter) { · 5 unmodified lines | |||
| 1960 | 1924 | ||
| 1961 | bool Application::mouseOnScreen() const { | 1925 | bool Application::mouseOnScreen() const { |
| 1962 | if (OculusManager::isConnected()) { | 1926 | if (OculusManager::isConnected()) { |
| 1963 | return getMouseX() >= 0 && getMouseX() <= _glWidget->getDeviceWidth() && | 1927 | ivec2 mouse = getMouse(); |
| 1964 | getMouseY() >= 0 && getMouseY() <= _glWidget->getDeviceHeight(); | 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 | return true; | 1936 | return true; |
| 1967 | } | 1937 | } |
| 1968 | 1938 | ||
| 1969 | int Application::getMouseX() const { | 1939 | ivec2 Application::getMouse() 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 { | ||
| 1978 | if (OculusManager::isConnected()) { | 1940 | if (OculusManager::isConnected()) { |
| 1979 | glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseX(), getTrueMouseY())); | 1941 | return _compositor.screenToOverlay(getTrueMouse()); |
| 1980 | return pos.y; | ||
| 1981 | } | 1942 | } |
| 1982 | return getTrueMouseY(); | 1943 | return getTrueMouse(); |
| 1983 | } | 1944 | } |
| 1984 | 1945 | ||
| 1985 | int Application::getMouseDragStartedX() const { | 1946 | ivec2 Application::getMouseDragStarted() const { |
| 1986 | if (OculusManager::isConnected()) { | 1947 | if (OculusManager::isConnected()) { |
| 1987 | glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseDragStartedX(), | 1948 | return _compositor.screenToOverlay(getTrueMouseDragStarted()); |
| 1988 | getTrueMouseDragStartedY())); | ||
| 1989 | return pos.x; | ||
| 1990 | } | 1949 | } |
| 1991 | return getTrueMouseDragStartedX(); | 1950 | return getTrueMouseDragStarted(); |
| 1992 | } | 1951 | } |
| 1993 | 1952 | ||
| 1994 | int Application::getMouseDragStartedY() const { | 1953 | ivec2 Application::getTrueMouseDragStarted() const { |
| 1995 | if (OculusManager::isConnected()) { | 1954 | return _mouseDragStarted; |
| 1996 | glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseDragStartedX(), | ||
| 1997 | getTrueMouseDragStartedY())); | ||
| 1998 | return pos.y; | ||
| 1999 | } | ||
| 2000 | return getTrueMouseDragStartedY(); | ||
| 2001 | } | 1955 | } |
| 2002 | 1956 | ||
| 2003 | FaceTracker* Application::getActiveFaceTracker() { | 1957 | FaceTracker* Application::getActiveFaceTracker() { |
| @@ -2179,13 +2133,6 @@ void Application::init() { · 175 unmodified lines | |||
| 2179 | 2133 | ||
| 2180 | _mirrorCamera.setMode(CAMERA_MODE_MIRROR); | 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 | TV3DManager::connect(); | 2136 | TV3DManager::connect(); |
| 2190 | if (TV3DManager::isConnected()) { | 2137 | if (TV3DManager::isConnected()) { |
| 2191 | QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen), | 2138 | QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen), |
| @@ -2249,13 +2196,6 @@ void Application::init() { · 57 unmodified lines | |||
| 2249 | _entityClipboardRenderer.setViewFrustum(getViewFrustum()); | 2196 | _entityClipboardRenderer.setViewFrustum(getViewFrustum()); |
| 2250 | _entityClipboardRenderer.setTree(&_entityClipboard); | 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 | // initialize the GlowEffect with our widget | 2199 | // initialize the GlowEffect with our widget |
| 2260 | bool glow = Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect); | 2200 | bool glow = Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect); |
| 2261 | DependencyManager::get<GlowEffect>()->init(glow); | 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 | void Application::updateCamera(float deltaTime) { | 2383 | void Application::updateCamera(float deltaTime) { |
| 2438 | PerformanceTimer perfTimer("updateCamera"); | 2384 | PerformanceTimer perfTimer("updateCamera"); |
| 2439 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); | 2385 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| @@ -3155,7 +3101,7 @@ PickRay Application::computePickRay(float x, float y) const { · 715 unmodified lines | |||
| 3155 | y /= size.y; | 3101 | y /= size.y; |
| 3156 | PickRay result; | 3102 | PickRay result; |
| 3157 | if (isHMDMode()) { | 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 | } else { | 3105 | } else { |
| 3160 | if (QThread::currentThread() == activeRenderingThread) { | 3106 | if (QThread::currentThread() == activeRenderingThread) { |
| 3161 | getDisplayViewFrustum()->computePickRay(x, y, result.origin, result.direction); | 3107 | getDisplayViewFrustum()->computePickRay(x, y, result.origin, result.direction); |
| @@ -3184,13 +3130,11 @@ QImage Application::renderAvatarBillboard(RenderArgs* renderArgs) { · 22 unmodified lines | |||
| 3184 | renderRearViewMirror(renderArgs, QRect(0, _glWidget->getDeviceHeight() - BILLBOARD_SIZE, | 3130 | renderRearViewMirror(renderArgs, QRect(0, _glWidget->getDeviceHeight() - BILLBOARD_SIZE, |
| 3185 | BILLBOARD_SIZE, BILLBOARD_SIZE), | 3131 | BILLBOARD_SIZE, BILLBOARD_SIZE), |
| 3186 | true); | 3132 | true); |
| 3187 | |||
| 3188 | QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32); | 3133 | QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32); |
| 3189 | glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits()); | 3134 | glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits()); |
| 3190 | glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | 3135 | glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| 3191 | 3136 | ||
| 3192 | glBindFramebuffer(GL_FRAMEBUFFER, 0); | 3137 | glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| 3193 | |||
| 3194 | return image; | 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 | // flip x if in mirror mode (also requires reversing winding order for backface culling) | 3331 | // flip x if in mirror mode (also requires reversing winding order for backface culling) |
| 3388 | if (theCamera.getMode() == CAMERA_MODE_MIRROR) { | 3332 | if (theCamera.getMode() == CAMERA_MODE_MIRROR) { |
| 3389 | glScalef(-1.0f, 1.0f, 1.0f); | 3333 | //glScalef(-1.0f, 1.0f, 1.0f); |
| 3390 | glFrontFace(GL_CW); | 3334 | //glFrontFace(GL_CW); |
| 3391 | |||
| 3392 | } else { | 3335 | } else { |
| 3393 | glFrontFace(GL_CCW); | 3336 | glFrontFace(GL_CCW); |
| 3394 | } | 3337 | } |
| @@ -3411,7 +3354,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 16 unmodified lines | |||
| 3411 | viewTransform.setTranslation(theCamera.getPosition()); | 3354 | viewTransform.setTranslation(theCamera.getPosition()); |
| 3412 | viewTransform.setRotation(rotation); | 3355 | viewTransform.setRotation(rotation); |
| 3413 | if (theCamera.getMode() == CAMERA_MODE_MIRROR) { | 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 | if (renderArgs->_renderSide != RenderArgs::MONO) { | 3359 | if (renderArgs->_renderSide != RenderArgs::MONO) { |
| 3417 | glm::mat4 invView = glm::inverse(_untranslatedViewMatrix); | 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 | renderContext._maxDrawnOpaqueItems = sceneInterface->getEngineMaxDrawnOpaqueItems(); | 3492 | renderContext._maxDrawnOpaqueItems = sceneInterface->getEngineMaxDrawnOpaqueItems(); |
| 3550 | renderContext._maxDrawnTransparentItems = sceneInterface->getEngineMaxDrawnTransparentItems(); | 3493 | renderContext._maxDrawnTransparentItems = sceneInterface->getEngineMaxDrawnTransparentItems(); |
| 3494 | renderContext._maxDrawnOverlay3DItems = sceneInterface->getEngineMaxDrawnOverlay3DItems(); | ||
| 3551 | 3495 | ||
| 3552 | renderArgs->_shouldRender = LODManager::shouldRender; | 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 | sceneInterface->setEngineFeedTransparentItems(engineRC->_numFeedTransparentItems); | 3509 | sceneInterface->setEngineFeedTransparentItems(engineRC->_numFeedTransparentItems); |
| 3566 | sceneInterface->setEngineDrawnTransparentItems(engineRC->_numDrawnTransparentItems); | 3510 | sceneInterface->setEngineDrawnTransparentItems(engineRC->_numDrawnTransparentItems); |
| 3567 | 3511 | ||
| 3512 | sceneInterface->setEngineFeedOverlay3DItems(engineRC->_numFeedOverlay3DItems); | ||
| 3513 | sceneInterface->setEngineDrawnOverlay3DItems(engineRC->_numDrawnOverlay3DItems); | ||
| 3568 | } | 3514 | } |
| 3569 | //Render the sixense lasers | 3515 | //Render the sixense lasers |
| 3570 | if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) { | 3516 | if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) { |
| @@ -3672,8 +3618,8 @@ glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) { · 101 unmodified lines | |||
| 3672 | // +-----------------------+ | 3618 | // +-----------------------+ |
| 3673 | // -1,-1 1,-1 | 3619 | // -1,-1 1,-1 |
| 3674 | 3620 | ||
| 3675 | glm::vec2 screenPoint((projectedPoint.x + 1.0) * horizontalScale, | 3621 | glm::vec2 screenPoint((projectedPoint.x + 1.0f) * horizontalScale, |
| 3676 | ((projectedPoint.y + 1.0) * -verticalScale) + _glWidget->getDeviceHeight()); | 3622 | ((projectedPoint.y + 1.0f) * -verticalScale) + _glWidget->getDeviceHeight()); |
| 3677 | 3623 | ||
| 3678 | return screenPoint; | 3624 | return screenPoint; |
| 3679 | } | 3625 | } |
| @@ -3691,7 +3637,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi · 11 unmodified lines | |||
| 3691 | _mirrorCamera.setPosition(_myAvatar->getPosition() + | 3637 | _mirrorCamera.setPosition(_myAvatar->getPosition() + |
| 3692 | _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * BILLBOARD_DISTANCE * _myAvatar->getScale()); | 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 | _mirrorCamera.setPosition(_myAvatar->getChestPosition() + | 3641 | _mirrorCamera.setPosition(_myAvatar->getChestPosition() + |
| 3696 | _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_REARVIEW_BODY_DISTANCE * _myAvatar->getScale()); | 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 | } else { | 3672 | } else { |
| 3727 | // if not rendering the billboard, the region is in device independent coordinates; must convert to device | 3673 | // if not rendering the billboard, the region is in device independent coordinates; must convert to device |
| 3728 | QSize size = DependencyManager::get<TextureCache>()->getFrameBufferSize(); | 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 | int x = region.x() * ratio, y = region.y() * ratio, width = region.width() * ratio, height = region.height() * ratio; | 3676 | int x = region.x() * ratio, y = region.y() * ratio, width = region.width() * ratio, height = region.height() * ratio; |
| 3731 | glViewport(x, size.height() - y - height, width, height); | 3677 | glViewport(x, size.height() - y - height, width, height); |
| 3732 | glScissor(x, size.height() - y - height, width, height); | 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 | displaySide(renderArgs, _mirrorCamera, true, billboard); | 3687 | displaySide(renderArgs, _mirrorCamera, true, billboard); |
| 3742 | glPopMatrix(); | 3688 | glPopMatrix(); |
| 3743 | 3689 | ||
| 3744 | if (!billboard) { | ||
| 3745 | _rearMirrorTools->render(renderArgs, false, _glWidget->mapFromGlobal(QCursor::pos())); | ||
| 3746 | } | ||
| 3747 | |||
| 3748 | // reset Viewport and projection matrix | 3690 | // reset Viewport and projection matrix |
| 3749 | glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); | 3691 | glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); |
| 3750 | glDisable(GL_SCISSOR_TEST); | 3692 | glDisable(GL_SCISSOR_TEST); |
| @@ -3884,7 +3826,7 @@ void Application::nodeKilled(SharedNodePointer node) { · 133 unmodified lines | |||
| 3884 | _entityServerJurisdictions.unlock(); | 3826 | _entityServerJurisdictions.unlock(); |
| 3885 | 3827 | ||
| 3886 | qCDebug(interfaceapp, "model server going away...... v[%f, %f, %f, %f]", | 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 | // Add the jurisditionDetails object to the list of "fade outs" | 3831 | // Add the jurisditionDetails object to the list of "fade outs" |
| 3890 | if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnOctreeServerChanges)) { | 3832 | if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnOctreeServerChanges)) { |
| @@ -3970,7 +3912,8 @@ int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePoin · 79 unmodified lines | |||
| 3970 | jurisdiction->unlock(); | 3912 | jurisdiction->unlock(); |
| 3971 | 3913 | ||
| 3972 | qCDebug(interfaceapp, "stats from new %s server... [%f, %f, %f, %f]", | 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 | // Add the jurisditionDetails object to the list of "fade outs" | 3918 | // Add the jurisditionDetails object to the list of "fade outs" |
| 3976 | if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnOctreeServerChanges)) { | 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 | void Application::initPlugins() { | 4695 | void Application::initPlugins() { |
| 4753 | OculusManager::init(); | ||
| 4754 | } | 4696 | } |
| 4755 | 4697 | ||
| 4756 | void Application::shutdownPlugins() { | 4698 | void Application::shutdownPlugins() { |
| 4757 | OculusManager::deinit(); | ||
| 4758 | } | 4699 | } |
| 4759 | 4700 | ||
| 4760 | glm::vec3 Application::getHeadPosition() const { | 4701 | glm::vec3 Application::getHeadPosition() const { |
| @@ -4774,12 +4715,8 @@ QSize Application::getDeviceSize() const { · 13 unmodified lines | |||
| 4774 | return _glWidget->getDeviceSize(); | 4715 | return _glWidget->getDeviceSize(); |
| 4775 | } | 4716 | } |
| 4776 | 4717 | ||
| 4777 | int Application::getTrueMouseX() const { | 4718 | ivec2 Application::getTrueMouse() const { |
| 4778 | return _glWidget->mapFromGlobal(QCursor::pos()).x(); | 4719 | return toGlm(_glWidget->mapFromGlobal(QCursor::pos())); |
| 4779 | } | ||
| 4780 | |||
| 4781 | int Application::getTrueMouseY() const { | ||
| 4782 | return _glWidget->mapFromGlobal(QCursor::pos()).y(); | ||
| 4783 | } | 4720 | } |
| 4784 | 4721 | ||
| 4785 | bool Application::isThrottleRendering() const { | 4722 | bool Application::isThrottleRendering() const { |
| @@ -4809,3 +4746,25 @@ qreal Application::getDevicePixelRatio() { · 23 unmodified lines | |||
| 4809 | return _window ? _window->windowHandle()->devicePixelRatio() : 1.0; | 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 | #include "ui/ModelsBrowser.h" | 62 | #include "ui/ModelsBrowser.h" |
| 63 | #include "ui/NodeBounds.h" | 63 | #include "ui/NodeBounds.h" |
| 64 | #include "ui/OctreeStatsDialog.h" | 64 | #include "ui/OctreeStatsDialog.h" |
| 65 | #include "ui/RearMirrorTools.h" | ||
| 66 | #include "ui/SnapshotShareDialog.h" | 65 | #include "ui/SnapshotShareDialog.h" |
| 67 | #include "ui/LodToolsDialog.h" | 66 | #include "ui/LodToolsDialog.h" |
| 68 | #include "ui/LogDialog.h" | 67 | #include "ui/LogDialog.h" |
| 69 | #include "ui/overlays/Overlays.h" | 68 | #include "ui/overlays/Overlays.h" |
| 70 | #include "ui/ApplicationOverlay.h" | 69 | #include "ui/ApplicationOverlay.h" |
| 70 | #include "ui/ApplicationCompositor.h" | ||
| 71 | #include "ui/RunningScriptsWidget.h" | 71 | #include "ui/RunningScriptsWidget.h" |
| 72 | #include "ui/ToolWindow.h" | 72 | #include "ui/ToolWindow.h" |
| 73 | #include "ui/UserInputMapper.h" | 73 | #include "ui/UserInputMapper.h" |
| @@ -221,15 +221,21 @@ public: · 147 unmodified lines | |||
| 221 | const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; } | 221 | const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; } |
| 222 | const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; } | 222 | const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; } |
| 223 | bool mouseOnScreen() const; | 223 | bool mouseOnScreen() const; |
| 224 | int getMouseX() const; | 224 | |
| 225 | int getMouseY() const; | 225 | ivec2 getMouse() const; |
| 226 | glm::ivec2 getTrueMousePosition() const; | 226 | ivec2 getTrueMouse() const; |
| 227 | int getTrueMouseX() const; | 227 | ivec2 getMouseDragStarted() const; |
| 228 | int getTrueMouseY() const; | 228 | ivec2 getTrueMouseDragStarted() const; |
| 229 | int getMouseDragStartedX() const; | 229 | |
| 230 | int getMouseDragStartedY() const; | 230 | // TODO get rid of these and use glm types directly |
| 231 | int getTrueMouseDragStartedX() const { return _mouseDragStartedX; } | 231 | int getMouseX() const { return getMouse().x; } |
| 232 | int getTrueMouseDragStartedY() const { return _mouseDragStartedY; } | 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 | bool getLastMouseMoveWasSimulated() const { return _lastMouseMoveWasSimulated; } | 239 | bool getLastMouseMoveWasSimulated() const { return _lastMouseMoveWasSimulated; } |
| 234 | 240 | ||
| 235 | FaceTracker* getActiveFaceTracker(); | 241 | FaceTracker* getActiveFaceTracker(); |
| @@ -238,6 +244,8 @@ public: · 2 unmodified lines | |||
| 238 | QSystemTrayIcon* getTrayIcon() { return _trayIcon; } | 244 | QSystemTrayIcon* getTrayIcon() { return _trayIcon; } |
| 239 | ApplicationOverlay& getApplicationOverlay() { return _applicationOverlay; } | 245 | ApplicationOverlay& getApplicationOverlay() { return _applicationOverlay; } |
| 240 | const ApplicationOverlay& getApplicationOverlay() const { return _applicationOverlay; } | 246 | const ApplicationOverlay& getApplicationOverlay() const { return _applicationOverlay; } |
| 247 | ApplicationCompositor& getApplicationCompositor() { return _compositor; } | ||
| 248 | const ApplicationCompositor& getApplicationCompositor() const { return _compositor; } | ||
| 241 | Overlays& getOverlays() { return _overlays; } | 249 | Overlays& getOverlays() { return _overlays; } |
| 242 | 250 | ||
| 243 | float getFps() const { return _fps; } | 251 | float getFps() const { return _fps; } |
| @@ -330,6 +338,9 @@ public: · 86 unmodified lines | |||
| 330 | bool isHMDMode() const; | 338 | bool isHMDMode() const; |
| 331 | glm::quat getHeadOrientation() const; | 339 | glm::quat getHeadOrientation() const; |
| 332 | glm::vec3 getHeadPosition() const; | 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 | QRect getDesirableApplicationGeometry(); | 345 | QRect getDesirableApplicationGeometry(); |
| 335 | RunningScriptsWidget* getRunningScriptsWidget() { return _runningScriptsWidget; } | 346 | RunningScriptsWidget* getRunningScriptsWidget() { return _runningScriptsWidget; } |
| @@ -451,6 +462,8 @@ private slots: · 115 unmodified lines | |||
| 451 | void setFullscreen(bool fullscreen); | 462 | void setFullscreen(bool fullscreen); |
| 452 | void setEnable3DTVMode(bool enable3DTVMode); | 463 | void setEnable3DTVMode(bool enable3DTVMode); |
| 453 | void setEnableVRMode(bool enableVRMode); | 464 | void setEnableVRMode(bool enableVRMode); |
| 465 | |||
| 466 | void rotationModeChanged(); | ||
| 454 | 467 | ||
| 455 | glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint); | 468 | glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint); |
| 456 | 469 | ||
| @@ -548,21 +561,17 @@ private: · 91 unmodified lines | |||
| 548 | 561 | ||
| 549 | OctreeQuery _octreeQuery; // NodeData derived class for querying octee cells from octree servers | 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 | 564 | KeyboardMouseDevice _keyboardMouseDevice; // Default input device, the good old keyboard mouse and maybe touchpad |
| 552 | 565 | UserInputMapper _userInputMapper; // User input mapper allowing to mapp different real devices to the action channels that the application has to offer | |
| 553 | 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) |
| 554 | 567 | Camera _myCamera; // My view onto the world | |
| 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 | ||
| 558 | Camera _mirrorCamera; // Cammera for mirror view | 568 | Camera _mirrorCamera; // Cammera for mirror view |
| 559 | QRect _mirrorViewRect; | 569 | QRect _mirrorViewRect; |
| 560 | RearMirrorTools* _rearMirrorTools; | ||
| 561 | 570 | ||
| 562 | Setting::Handle<bool> _firstRun; | 571 | Setting::Handle<bool> _firstRun; |
| 563 | Setting::Handle<QString> _previousScriptLocation; | 572 | Setting::Handle<QString> _previousScriptLocation; |
| 564 | Setting::Handle<QString> _scriptsLocationHandle; | 573 | Setting::Handle<QString> _scriptsLocationHandle; |
| 565 | Setting::Handle<float> _fieldOfView; | 574 | Setting::Handle<float> _fieldOfView; |
| 566 | 575 | ||
| 567 | Transform _viewTransform; | 576 | Transform _viewTransform; |
| 568 | glm::mat4 _untranslatedViewMatrix; | 577 | glm::mat4 _untranslatedViewMatrix; |
| @@ -580,18 +589,17 @@ private: · 11 unmodified lines | |||
| 580 | Environment _environment; | 589 | Environment _environment; |
| 581 | 590 | ||
| 582 | bool _cursorVisible; | 591 | bool _cursorVisible; |
| 583 | int _mouseDragStartedX; | 592 | ivec2 _mouseDragStarted; |
| 584 | int _mouseDragStartedY; | 593 | |
| 585 | quint64 _lastMouseMove; | 594 | quint64 _lastMouseMove; |
| 586 | bool _lastMouseMoveWasSimulated; | 595 | bool _lastMouseMoveWasSimulated; |
| 587 | 596 | ||
| 588 | glm::vec3 _mouseRayOrigin; | 597 | glm::vec3 _mouseRayOrigin; |
| 589 | glm::vec3 _mouseRayDirection; | 598 | glm::vec3 _mouseRayDirection; |
| 590 | 599 | ||
| 591 | float _touchAvgX; | 600 | vec2 _touchAvg; |
| 592 | float _touchAvgY; | 601 | vec2 _touchDragStartedAvg; |
| 593 | float _touchDragStartedAvgX; | 602 | |
| 594 | float _touchDragStartedAvgY; | ||
| 595 | bool _isTouchPressed; // true if multitouch has been pressed (clear when finished) | 603 | bool _isTouchPressed; // true if multitouch has been pressed (clear when finished) |
| 596 | 604 | ||
| 597 | bool _mousePressed; // true if mouse has been pressed (clear when finished) | 605 | bool _mousePressed; // true if mouse has been pressed (clear when finished) |
| @@ -669,6 +677,7 @@ private: · 71 unmodified lines | |||
| 669 | 677 | ||
| 670 | Overlays _overlays; | 678 | Overlays _overlays; |
| 671 | ApplicationOverlay _applicationOverlay; | 679 | ApplicationOverlay _applicationOverlay; |
| 680 | ApplicationCompositor _compositor; | ||
| 672 | }; | 681 | }; |
| 673 | 682 | ||
| 674 | #endif // hifi_Application_h | 683 | #endif // hifi_Application_h |
| @@ -49,8 +49,6 @@ Camera::Camera() : · 48 unmodified lines | |||
| 49 | _mode(CAMERA_MODE_THIRD_PERSON), | 49 | _mode(CAMERA_MODE_THIRD_PERSON), |
| 50 | _position(0.0f, 0.0f, 0.0f), | 50 | _position(0.0f, 0.0f, 0.0f), |
| 51 | _projection(glm::perspective(glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES), 16.0f/9.0f, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP)), | 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 | _isKeepLookingAt(false), | 52 | _isKeepLookingAt(false), |
| 55 | _lookingAt(0.0f, 0.0f, 0.0f) | 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 | void Camera::setMode(CameraMode mode) { | 75 | void Camera::setMode(CameraMode mode) { |
| 92 | _mode = mode; | 76 | _mode = mode; |
| 93 | emit modeUpdated(modeToString(mode)); | 77 | emit modeUpdated(modeToString(mode)); |
| @@ -45,26 +45,22 @@ public: · 44 unmodified lines | |||
| 45 | 45 | ||
| 46 | void setRotation(const glm::quat& rotation); | 46 | void setRotation(const glm::quat& rotation); |
| 47 | void setProjection(const glm::mat4 & projection); | 47 | void setProjection(const glm::mat4 & projection); |
| 48 | void setHmdPosition(const glm::vec3& hmdPosition); | ||
| 49 | void setHmdRotation(const glm::quat& hmdRotation); | ||
| 50 | void setMode(CameraMode m); | 48 | void setMode(CameraMode m); |
| 51 | 49 | ||
| 52 | glm::quat getRotation() const { return _rotation * _hmdRotation; } | 50 | glm::quat getRotation() const { return _rotation; } |
| 53 | const glm::mat4& getProjection() const { return _projection; } | 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 | CameraMode getMode() const { return _mode; } | 52 | CameraMode getMode() const { return _mode; } |
| 57 | 53 | ||
| 58 | public slots: | 54 | public slots: |
| 59 | QString getModeString() const; | 55 | QString getModeString() const; |
| 60 | void setModeString(const QString& mode); | 56 | void setModeString(const QString& mode); |
| 61 | 57 | ||
| 62 | glm::vec3 getPosition() const { return _position + _hmdPosition; } | 58 | glm::vec3 getPosition() const { return _position; } |
| 63 | void setPosition(const glm::vec3& position); | 59 | void setPosition(const glm::vec3& position); |
| 64 | 60 | ||
| 65 | void setOrientation(const glm::quat& orientation) { setRotation(orientation); } | ||
| 66 | glm::quat getOrientation() const { return getRotation(); } | 61 | glm::quat getOrientation() const { return getRotation(); } |
| 67 | 62 | void setOrientation(const glm::quat& orientation) { setRotation(orientation); } | |
| 63 | |||
| 68 | PickRay computePickRay(float x, float y); | 64 | PickRay computePickRay(float x, float y); |
| 69 | 65 | ||
| 70 | // These only work on independent cameras | 66 | // These only work on independent cameras |
| @@ -86,8 +82,6 @@ private: · 15 unmodified lines | |||
| 86 | glm::vec3 _position; | 82 | glm::vec3 _position; |
| 87 | glm::quat _rotation; | 83 | glm::quat _rotation; |
| 88 | glm::mat4 _projection; | 84 | glm::mat4 _projection; |
| 89 | glm::vec3 _hmdPosition; | ||
| 90 | glm::quat _hmdRotation; | ||
| 91 | bool _isKeepLookingAt; | 85 | bool _isKeepLookingAt; |
| 92 | glm::vec3 _lookingAt; | 86 | glm::vec3 _lookingAt; |
| 93 | }; | 87 | }; |
| @@ -39,11 +39,11 @@ bool GLCanvas::isThrottleRendering() const { · 38 unmodified lines | |||
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | int GLCanvas::getDeviceWidth() const { | 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 | int GLCanvas::getDeviceHeight() const { | 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 | void GLCanvas::initializeGL() { | 49 | void GLCanvas::initializeGL() { |
| @@ -12,7 +12,7 @@ · 11 unmodified lines | |||
| 12 | 12 | ||
| 13 | 13 | ||
| 14 | #include <avatar/AvatarActionHold.h> | 14 | #include <avatar/AvatarActionHold.h> |
| 15 | #include <ObjectActionPullToPoint.h> | 15 | #include <ObjectActionOffset.h> |
| 16 | #include <ObjectActionSpring.h> | 16 | #include <ObjectActionSpring.h> |
| 17 | 17 | ||
| 18 | #include "InterfaceActionFactory.h" | 18 | #include "InterfaceActionFactory.h" |
| @@ -27,8 +27,8 @@ EntityActionPointer InterfaceActionFactory::factory(EntitySimulation* simulation · 8 unmodified lines | |||
| 27 | switch (type) { | 27 | switch (type) { |
| 28 | case ACTION_TYPE_NONE: | 28 | case ACTION_TYPE_NONE: |
| 29 | return nullptr; | 29 | return nullptr; |
| 30 | case ACTION_TYPE_PULL_TO_POINT: | 30 | case ACTION_TYPE_OFFSET: |
| 31 | action = (EntityActionPointer) new ObjectActionPullToPoint(id, ownerEntity); | 31 | action = (EntityActionPointer) new ObjectActionOffset(id, ownerEntity); |
| 32 | break; | 32 | break; |
| 33 | case ACTION_TYPE_SPRING: | 33 | case ACTION_TYPE_SPRING: |
| 34 | action = (EntityActionPointer) new ObjectActionSpring(id, ownerEntity); | 34 | action = (EntityActionPointer) new ObjectActionSpring(id, ownerEntity); |
| @@ -205,11 +205,11 @@ QString LODManager::getLODFeedbackText() { · 204 unmodified lines | |||
| 205 | int relativeToTwentyTwenty = 20 / relativeToDefault; | 205 | int relativeToTwentyTwenty = 20 / relativeToDefault; |
| 206 | 206 | ||
| 207 | QString result; | 207 | QString result; |
| 208 | if (relativeToDefault > 1.01) { | 208 | if (relativeToDefault > 1.01f) { |
| 209 | result = QString("20:%1 or %2 times further than average vision%3").arg(relativeToTwentyTwenty).arg(relativeToDefault,0,'f',2).arg(granularityFeedback); | 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 | result = QString("20:20 or the default distance for average vision%1").arg(granularityFeedback); | 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 | result = QString("20:%1 or %2 of default distance for average vision%3").arg(relativeToTwentyTwenty).arg(relativeToDefault,0,'f',3).arg(granularityFeedback); | 213 | result = QString("20:%1 or %2 of default distance for average vision%3").arg(relativeToTwentyTwenty).arg(relativeToDefault,0,'f',3).arg(granularityFeedback); |
| 214 | } else { | 214 | } else { |
| 215 | result = QString("%2 of default distance for average vision%3").arg(relativeToDefault,0,'f',3).arg(granularityFeedback); | 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 | addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, | 287 | addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, |
| 288 | 0, //QML Qt::SHIFT | Qt::Key_H, | 288 | 0, //QML Qt::SHIFT | Qt::Key_H, |
| 289 | true); | 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 | addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, | 297 | addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, |
| 292 | #ifdef Q_OS_MAC | 298 | #ifdef Q_OS_MAC |
| @@ -201,6 +201,7 @@ namespace MenuOption { · 200 unmodified lines | |||
| 201 | const QString FrameTimer = "Show Timer"; | 201 | const QString FrameTimer = "Show Timer"; |
| 202 | const QString Fullscreen = "Fullscreen"; | 202 | const QString Fullscreen = "Fullscreen"; |
| 203 | const QString FullscreenMirror = "Fullscreen Mirror"; | 203 | const QString FullscreenMirror = "Fullscreen Mirror"; |
| 204 | const QString CenterPlayerInView = "Center Player In View"; | ||
| 204 | const QString GlowWhenSpeaking = "Glow When Speaking"; | 205 | const QString GlowWhenSpeaking = "Glow When Speaking"; |
| 205 | const QString NamesAboveHeads = "Names Above Heads"; | 206 | const QString NamesAboveHeads = "Names Above Heads"; |
| 206 | const QString HMDTools = "HMD Tools"; | 207 | const QString HMDTools = "HMD Tools"; |
| @@ -33,19 +33,19 @@ _basePath(basePath), · 32 unmodified lines | |||
| 33 | _geometry(geometry) | 33 | _geometry(geometry) |
| 34 | { | 34 | { |
| 35 | setWindowTitle("Set Model Properties"); | 35 | setWindowTitle("Set Model Properties"); |
| 36 | 36 | ||
| 37 | QFormLayout* form = new QFormLayout(); | 37 | QFormLayout* form = new QFormLayout(); |
| 38 | setLayout(form); | 38 | setLayout(form); |
| 39 | 39 | ||
| 40 | form->addRow("Name:", _name = new QLineEdit()); | 40 | form->addRow("Name:", _name = new QLineEdit()); |
| 41 | 41 | ||
| 42 | form->addRow("Texture Directory:", _textureDirectory = new QPushButton()); | 42 | form->addRow("Texture Directory:", _textureDirectory = new QPushButton()); |
| 43 | connect(_textureDirectory, SIGNAL(clicked(bool)), SLOT(chooseTextureDirectory())); | 43 | connect(_textureDirectory, SIGNAL(clicked(bool)), SLOT(chooseTextureDirectory())); |
| 44 | 44 | ||
| 45 | form->addRow("Scale:", _scale = new QDoubleSpinBox()); | 45 | form->addRow("Scale:", _scale = new QDoubleSpinBox()); |
| 46 | _scale->setMaximum(FLT_MAX); | 46 | _scale->setMaximum(FLT_MAX); |
| 47 | _scale->setSingleStep(0.01); | 47 | _scale->setSingleStep(0.01); |
| 48 | 48 | ||
| 49 | if (_modelType != FSTReader::ENTITY_MODEL) { | 49 | if (_modelType != FSTReader::ENTITY_MODEL) { |
| 50 | if (_modelType == FSTReader::ATTACHMENT_MODEL) { | 50 | if (_modelType == FSTReader::ATTACHMENT_MODEL) { |
| 51 | QHBoxLayout* translation = new QHBoxLayout(); | 51 | QHBoxLayout* translation = new QHBoxLayout(); |
| @@ -57,7 +57,7 @@ _geometry(geometry) · 5 unmodified lines | |||
| 57 | form->addRow("Pivot Joint:", _pivotJoint = createJointBox()); | 57 | form->addRow("Pivot Joint:", _pivotJoint = createJointBox()); |
| 58 | connect(_pivotAboutCenter, SIGNAL(toggled(bool)), SLOT(updatePivotJoint())); | 58 | connect(_pivotAboutCenter, SIGNAL(toggled(bool)), SLOT(updatePivotJoint())); |
| 59 | _pivotAboutCenter->setChecked(true); | 59 | _pivotAboutCenter->setChecked(true); |
| 60 | 60 | ||
| 61 | } else { | 61 | } else { |
| 62 | form->addRow("Left Eye Joint:", _leftEyeJoint = createJointBox()); | 62 | form->addRow("Left Eye Joint:", _leftEyeJoint = createJointBox()); |
| 63 | form->addRow("Right Eye Joint:", _rightEyeJoint = createJointBox()); | 63 | form->addRow("Right Eye Joint:", _rightEyeJoint = createJointBox()); |
| @@ -69,22 +69,22 @@ _geometry(geometry) · 5 unmodified lines | |||
| 69 | form->addRow("Head Joint:", _headJoint = createJointBox()); | 69 | form->addRow("Head Joint:", _headJoint = createJointBox()); |
| 70 | form->addRow("Left Hand Joint:", _leftHandJoint = createJointBox()); | 70 | form->addRow("Left Hand Joint:", _leftHandJoint = createJointBox()); |
| 71 | form->addRow("Right Hand Joint:", _rightHandJoint = createJointBox()); | 71 | form->addRow("Right Hand Joint:", _rightHandJoint = createJointBox()); |
| 72 | 72 | ||
| 73 | form->addRow("Free Joints:", _freeJoints = new QVBoxLayout()); | 73 | form->addRow("Free Joints:", _freeJoints = new QVBoxLayout()); |
| 74 | QPushButton* newFreeJoint = new QPushButton("New Free Joint"); | 74 | QPushButton* newFreeJoint = new QPushButton("New Free Joint"); |
| 75 | _freeJoints->addWidget(newFreeJoint); | 75 | _freeJoints->addWidget(newFreeJoint); |
| 76 | connect(newFreeJoint, SIGNAL(clicked(bool)), SLOT(createNewFreeJoint())); | 76 | connect(newFreeJoint, SIGNAL(clicked(bool)), SLOT(createNewFreeJoint())); |
| 77 | } | 77 | } |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | | 80 | QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | |
| 81 | QDialogButtonBox::Cancel | QDialogButtonBox::Reset); | 81 | QDialogButtonBox::Cancel | QDialogButtonBox::Reset); |
| 82 | connect(buttons, SIGNAL(accepted()), SLOT(accept())); | 82 | connect(buttons, SIGNAL(accepted()), SLOT(accept())); |
| 83 | connect(buttons, SIGNAL(rejected()), SLOT(reject())); | 83 | connect(buttons, SIGNAL(rejected()), SLOT(reject())); |
| 84 | connect(buttons->button(QDialogButtonBox::Reset), SIGNAL(clicked(bool)), SLOT(reset())); | 84 | connect(buttons->button(QDialogButtonBox::Reset), SIGNAL(clicked(bool)), SLOT(reset())); |
| 85 | 85 | ||
| 86 | form->addRow(buttons); | 86 | form->addRow(buttons); |
| 87 | 87 | ||
| 88 | // reset to initialize the fields | 88 | // reset to initialize the fields |
| 89 | reset(); | 89 | reset(); |
| 90 | } | 90 | } |
| @@ -100,42 +100,42 @@ QVariantHash ModelPropertiesDialog::getMapping() const { · 9 unmodified lines | |||
| 100 | mapping.insert(NAME_FIELD, _name->text()); | 100 | mapping.insert(NAME_FIELD, _name->text()); |
| 101 | mapping.insert(TEXDIR_FIELD, _textureDirectory->text()); | 101 | mapping.insert(TEXDIR_FIELD, _textureDirectory->text()); |
| 102 | mapping.insert(SCALE_FIELD, QString::number(_scale->value())); | 102 | mapping.insert(SCALE_FIELD, QString::number(_scale->value())); |
| 103 | 103 | ||
| 104 | // update the joint indices | 104 | // update the joint indices |
| 105 | QVariantHash jointIndices; | 105 | QVariantHash jointIndices; |
| 106 | for (int i = 0; i < _geometry.joints.size(); i++) { | 106 | for (int i = 0; i < _geometry.joints.size(); i++) { |
| 107 | jointIndices.insert(_geometry.joints.at(i).name, QString::number(i)); | 107 | jointIndices.insert(_geometry.joints.at(i).name, QString::number(i)); |
| 108 | } | 108 | } |
| 109 | mapping.insert(JOINT_INDEX_FIELD, jointIndices); | 109 | mapping.insert(JOINT_INDEX_FIELD, jointIndices); |
| 110 | 110 | ||
| 111 | if (_modelType != FSTReader::ENTITY_MODEL) { | 111 | if (_modelType != FSTReader::ENTITY_MODEL) { |
| 112 | QVariantHash joints = mapping.value(JOINT_FIELD).toHash(); | 112 | QVariantHash joints = mapping.value(JOINT_FIELD).toHash(); |
| 113 | if (_modelType == FSTReader::ATTACHMENT_MODEL) { | 113 | if (_modelType == FSTReader::ATTACHMENT_MODEL) { |
| 114 | glm::vec3 pivot; | 114 | glm::vec3 pivot; |
| 115 | if (_pivotAboutCenter->isChecked()) { | 115 | if (_pivotAboutCenter->isChecked()) { |
| 116 | pivot = (_geometry.meshExtents.minimum + _geometry.meshExtents.maximum) * 0.5f; | 116 | pivot = (_geometry.meshExtents.minimum + _geometry.meshExtents.maximum) * 0.5f; |
| 117 | 117 | ||
| 118 | } else if (_pivotJoint->currentIndex() != 0) { | 118 | } else if (_pivotJoint->currentIndex() != 0) { |
| 119 | pivot = extractTranslation(_geometry.joints.at(_pivotJoint->currentIndex() - 1).transform); | 119 | pivot = extractTranslation(_geometry.joints.at(_pivotJoint->currentIndex() - 1).transform); |
| 120 | } | 120 | } |
| 121 | mapping.insert(TRANSLATION_X_FIELD, -pivot.x * _scale->value() + _translationX->value()); | 121 | mapping.insert(TRANSLATION_X_FIELD, -pivot.x * (float)_scale->value() + (float)_translationX->value()); |
| 122 | mapping.insert(TRANSLATION_Y_FIELD, -pivot.y * _scale->value() + _translationY->value()); | 122 | mapping.insert(TRANSLATION_Y_FIELD, -pivot.y * (float)_scale->value() + (float)_translationY->value()); |
| 123 | mapping.insert(TRANSLATION_Z_FIELD, -pivot.z * _scale->value() + _translationZ->value()); | 123 | mapping.insert(TRANSLATION_Z_FIELD, -pivot.z * (float)_scale->value() + (float)_translationZ->value()); |
| 124 | 124 | ||
| 125 | } else { | 125 | } else { |
| 126 | insertJointMapping(joints, "jointEyeLeft", _leftEyeJoint->currentText()); | 126 | insertJointMapping(joints, "jointEyeLeft", _leftEyeJoint->currentText()); |
| 127 | insertJointMapping(joints, "jointEyeRight", _rightEyeJoint->currentText()); | 127 | insertJointMapping(joints, "jointEyeRight", _rightEyeJoint->currentText()); |
| 128 | insertJointMapping(joints, "jointNeck", _neckJoint->currentText()); | 128 | insertJointMapping(joints, "jointNeck", _neckJoint->currentText()); |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | 131 | ||
| 132 | if (_modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL) { | 132 | if (_modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL) { |
| 133 | insertJointMapping(joints, "jointRoot", _rootJoint->currentText()); | 133 | insertJointMapping(joints, "jointRoot", _rootJoint->currentText()); |
| 134 | insertJointMapping(joints, "jointLean", _leanJoint->currentText()); | 134 | insertJointMapping(joints, "jointLean", _leanJoint->currentText()); |
| 135 | insertJointMapping(joints, "jointHead", _headJoint->currentText()); | 135 | insertJointMapping(joints, "jointHead", _headJoint->currentText()); |
| 136 | insertJointMapping(joints, "jointLeftHand", _leftHandJoint->currentText()); | 136 | insertJointMapping(joints, "jointLeftHand", _leftHandJoint->currentText()); |
| 137 | insertJointMapping(joints, "jointRightHand", _rightHandJoint->currentText()); | 137 | insertJointMapping(joints, "jointRightHand", _rightHandJoint->currentText()); |
| 138 | 138 | ||
| 139 | mapping.remove(FREE_JOINT_FIELD); | 139 | mapping.remove(FREE_JOINT_FIELD); |
| 140 | for (int i = 0; i < _freeJoints->count() - 1; i++) { | 140 | for (int i = 0; i < _freeJoints->count() - 1; i++) { |
| 141 | QComboBox* box = static_cast<QComboBox*>(_freeJoints->itemAt(i)->widget()->layout()->itemAt(0)->widget()); | 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 | mapping.insert(JOINT_FIELD, joints); | 145 | mapping.insert(JOINT_FIELD, joints); |
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | return mapping; | 148 | return mapping; |
| 149 | } | 149 | } |
| 150 | 150 | ||
| @@ -156,9 +156,9 @@ void ModelPropertiesDialog::reset() { · 5 unmodified lines | |||
| 156 | _name->setText(_originalMapping.value(NAME_FIELD).toString()); | 156 | _name->setText(_originalMapping.value(NAME_FIELD).toString()); |
| 157 | _textureDirectory->setText(_originalMapping.value(TEXDIR_FIELD).toString()); | 157 | _textureDirectory->setText(_originalMapping.value(TEXDIR_FIELD).toString()); |
| 158 | _scale->setValue(_originalMapping.value(SCALE_FIELD).toDouble()); | 158 | _scale->setValue(_originalMapping.value(SCALE_FIELD).toDouble()); |
| 159 | 159 | ||
| 160 | QVariantHash jointHash = _originalMapping.value(JOINT_FIELD).toHash(); | 160 | QVariantHash jointHash = _originalMapping.value(JOINT_FIELD).toHash(); |
| 161 | 161 | ||
| 162 | if (_modelType != FSTReader::ENTITY_MODEL) { | 162 | if (_modelType != FSTReader::ENTITY_MODEL) { |
| 163 | if (_modelType == FSTReader::ATTACHMENT_MODEL) { | 163 | if (_modelType == FSTReader::ATTACHMENT_MODEL) { |
| 164 | _translationX->setValue(_originalMapping.value(TRANSLATION_X_FIELD).toDouble()); | 164 | _translationX->setValue(_originalMapping.value(TRANSLATION_X_FIELD).toDouble()); |
| @@ -166,20 +166,20 @@ void ModelPropertiesDialog::reset() { · 1 unmodified line | |||
| 166 | _translationZ->setValue(_originalMapping.value(TRANSLATION_Z_FIELD).toDouble()); | 166 | _translationZ->setValue(_originalMapping.value(TRANSLATION_Z_FIELD).toDouble()); |
| 167 | _pivotAboutCenter->setChecked(true); | 167 | _pivotAboutCenter->setChecked(true); |
| 168 | _pivotJoint->setCurrentIndex(0); | 168 | _pivotJoint->setCurrentIndex(0); |
| 169 | 169 | ||
| 170 | } else { | 170 | } else { |
| 171 | setJointText(_leftEyeJoint, jointHash.value("jointEyeLeft").toString()); | 171 | setJointText(_leftEyeJoint, jointHash.value("jointEyeLeft").toString()); |
| 172 | setJointText(_rightEyeJoint, jointHash.value("jointEyeRight").toString()); | 172 | setJointText(_rightEyeJoint, jointHash.value("jointEyeRight").toString()); |
| 173 | setJointText(_neckJoint, jointHash.value("jointNeck").toString()); | 173 | setJointText(_neckJoint, jointHash.value("jointNeck").toString()); |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | if (_modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL) { | 176 | if (_modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL) { |
| 177 | setJointText(_rootJoint, jointHash.value("jointRoot").toString()); | 177 | setJointText(_rootJoint, jointHash.value("jointRoot").toString()); |
| 178 | setJointText(_leanJoint, jointHash.value("jointLean").toString()); | 178 | setJointText(_leanJoint, jointHash.value("jointLean").toString()); |
| 179 | setJointText(_headJoint, jointHash.value("jointHead").toString()); | 179 | setJointText(_headJoint, jointHash.value("jointHead").toString()); |
| 180 | setJointText(_leftHandJoint, jointHash.value("jointLeftHand").toString()); | 180 | setJointText(_leftHandJoint, jointHash.value("jointLeftHand").toString()); |
| 181 | setJointText(_rightHandJoint, jointHash.value("jointRightHand").toString()); | 181 | setJointText(_rightHandJoint, jointHash.value("jointRightHand").toString()); |
| 182 | 182 | ||
| 183 | while (_freeJoints->count() > 1) { | 183 | while (_freeJoints->count() > 1) { |
| 184 | delete _freeJoints->itemAt(0)->widget(); | 184 | delete _freeJoints->itemAt(0)->widget(); |
| 185 | } | 185 | } |
| @@ -16,13 +16,13 @@ · 15 unmodified lines | |||
| 16 | #include "InterfaceConfig.h" | 16 | #include "InterfaceConfig.h" |
| 17 | #include "starfield/Controller.h" | 17 | #include "starfield/Controller.h" |
| 18 | 18 | ||
| 19 | Stars::Stars() : | 19 | Stars::Stars() : |
| 20 | _controller(0l), _starsLoaded(false) { | 20 | _controller(0l), _starsLoaded(false) { |
| 21 | _controller = new starfield::Controller; | 21 | _controller = new starfield::Controller; |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | Stars::~Stars() { | 24 | Stars::~Stars() { |
| 25 | delete _controller; | 25 | delete _controller; |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | bool Stars::generate(unsigned numStars, unsigned seed) { | 28 | bool Stars::generate(unsigned numStars, unsigned seed) { |
| @@ -30,22 +30,20 @@ bool Stars::generate(unsigned numStars, unsigned seed) { · 1 unmodified line | |||
| 30 | return _starsLoaded; | 30 | return _starsLoaded; |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | bool Stars::setResolution(unsigned k) { | 33 | bool Stars::setResolution(unsigned k) { |
| 34 | return _controller->setResolution(k); | 34 | return _controller->setResolution(k); |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | void Stars::render(float fovY, float aspect, float nearZ, float alpha) { | 37 | void Stars::render(float fovY, float aspect, float nearZ, float alpha) { |
| 38 | // determine length of screen diagonal from quadrant height and aspect ratio | 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 | float halfDiagonal = sqrt(quadrantHeight * quadrantHeight * (1.0f + aspect * aspect)); | 40 | float halfDiagonal = sqrt(quadrantHeight * quadrantHeight * (1.0f + aspect * aspect)); |
| 41 | 41 | ||
| 42 | // determine fov angle in respect to the diagonal | 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 | // pull the modelview matrix off the GL stack | 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 | _controller->render(fovDiagonal, aspect, glm::affineInverse(view), alpha); | 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 | QFont font = widget->font(); | 72 | QFont font = widget->font(); |
| 73 | font.setPointSizeF(font.pointSizeF() * scale); | 73 | font.setPointSizeF(font.pointSizeF() * (double)scale); |
| 74 | widget->setFont(font); | 74 | widget->setFont(font); |
| 75 | } | 75 | } |
| @@ -41,7 +41,7 @@ void renderWorldBox(gpu::Batch& batch) { · 40 unmodified lines | |||
| 41 | static const glm::vec3 green(0.0f, 1.0f, 0.0f); | 41 | static const glm::vec3 green(0.0f, 1.0f, 0.0f); |
| 42 | static const glm::vec3 blue(0.0f, 0.0f, 1.0f); | 42 | static const glm::vec3 blue(0.0f, 0.0f, 1.0f); |
| 43 | static const glm::vec3 grey(0.5f, 0.5f, 0.5f); | 43 | static const glm::vec3 grey(0.5f, 0.5f, 0.5f); |
| 44 | 44 | ||
| 45 | auto transform = Transform{}; | 45 | auto transform = Transform{}; |
| 46 | batch.setModelTransform(transform); | 46 | batch.setModelTransform(transform); |
| 47 | geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(TREE_SCALE, 0.0f, 0.0f), red); | 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 | geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, TREE_SCALE), blue); | 49 | geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, TREE_SCALE), blue); |
| 50 | geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, TREE_SCALE), glm::vec3(TREE_SCALE, 0.0f, TREE_SCALE), grey); | 50 | geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, TREE_SCALE), glm::vec3(TREE_SCALE, 0.0f, TREE_SCALE), grey); |
| 51 | geometryCache->renderLine(batch, glm::vec3(TREE_SCALE, 0.0f, TREE_SCALE), glm::vec3(TREE_SCALE, 0.0f, 0.0f), grey); | 51 | geometryCache->renderLine(batch, glm::vec3(TREE_SCALE, 0.0f, TREE_SCALE), glm::vec3(TREE_SCALE, 0.0f, 0.0f), grey); |
| 52 | 52 | ||
| 53 | // Draw meter markers along the 3 axis to help with measuring things | 53 | // Draw meter markers along the 3 axis to help with measuring things |
| 54 | const float MARKER_DISTANCE = 1.0f; | 54 | const float MARKER_DISTANCE = 1.0f; |
| 55 | const float MARKER_RADIUS = 0.05f; | 55 | const float MARKER_RADIUS = 0.05f; |
| 56 | 56 | ||
| 57 | geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, red); | 57 | geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, red); |
| 58 | 58 | ||
| 59 | transform.setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, 0.0f)); | 59 | transform.setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, 0.0f)); |
| 60 | batch.setModelTransform(transform); | 60 | batch.setModelTransform(transform); |
| 61 | geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, red); | 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 | static TextRenderer* textRenderer(int mono) { | 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 | static TextRenderer* proportionalRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, | 83 | static TextRenderer* proportionalRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, |
| 84 | -1, -1, false, TextRenderer::SHADOW_EFFECT); | 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 | false); | 86 | false); |
| 87 | switch (mono) { | 87 | switch (mono) { |
| 88 | case 1: | 88 | case 1: |
| @@ -133,46 +133,46 @@ void runTimingTests() { · 44 unmodified lines | |||
| 133 | QElapsedTimer startTime; | 133 | QElapsedTimer startTime; |
| 134 | startTime.start(); | 134 | startTime.start(); |
| 135 | float elapsedUsecs; | 135 | float elapsedUsecs; |
| 136 | 136 | ||
| 137 | float NSEC_TO_USEC = 1.0f / 1000.0f; | 137 | float NSEC_TO_USEC = 1.0f / 1000.0f; |
| 138 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; | 138 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 139 | qCDebug(interfaceapp, "QElapsedTimer::nsecElapsed() usecs: %f", elapsedUsecs); | 139 | qCDebug(interfaceapp, "QElapsedTimer::nsecElapsed() usecs: %f", (double)elapsedUsecs); |
| 140 | 140 | ||
| 141 | // Test sleep functions for accuracy | 141 | // Test sleep functions for accuracy |
| 142 | startTime.start(); | 142 | startTime.start(); |
| 143 | QThread::msleep(1); | 143 | QThread::msleep(1); |
| 144 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; | 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 | startTime.start(); | 147 | startTime.start(); |
| 148 | QThread::sleep(1); | 148 | QThread::sleep(1); |
| 149 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; | 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 | startTime.start(); | 152 | startTime.start(); |
| 153 | usleep(1); | 153 | usleep(1); |
| 154 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; | 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 | startTime.start(); | 157 | startTime.start(); |
| 158 | usleep(10); | 158 | usleep(10); |
| 159 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; | 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 | startTime.start(); | 162 | startTime.start(); |
| 163 | usleep(100); | 163 | usleep(100); |
| 164 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; | 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 | startTime.start(); | 167 | startTime.start(); |
| 168 | usleep(1000); | 168 | usleep(1000); |
| 169 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; | 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 | startTime.start(); | 172 | startTime.start(); |
| 173 | usleep(15000); | 173 | usleep(15000); |
| 174 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; | 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 | // Random number generation | 177 | // Random number generation |
| 178 | startTime.start(); | 178 | startTime.start(); |
| @@ -180,7 +180,8 @@ void runTimingTests() { · 1 unmodified line | |||
| 180 | iResults[i] = rand(); | 180 | iResults[i] = rand(); |
| 181 | } | 181 | } |
| 182 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; | 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 | // Random number generation using randFloat() | 186 | // Random number generation using randFloat() |
| 186 | startTime.start(); | 187 | startTime.start(); |
| @@ -188,7 +189,8 @@ void runTimingTests() { · 1 unmodified line | |||
| 188 | fResults[i] = randFloat(); | 189 | fResults[i] = randFloat(); |
| 189 | } | 190 | } |
| 190 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; | 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 | free(iResults); | 195 | free(iResults); |
| 194 | free(fResults); | 196 | free(fResults); |
| @@ -200,7 +202,7 @@ void runTimingTests() { · 5 unmodified lines | |||
| 200 | fTest = powf(fTest, 0.5f); | 202 | fTest = powf(fTest, 0.5f); |
| 201 | } | 203 | } |
| 202 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; | 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 | // Vector Math | 207 | // Vector Math |
| 206 | float distance; | 208 | float distance; |
| @@ -213,19 +215,20 @@ void runTimingTests() { · 6 unmodified lines | |||
| 213 | } | 215 | } |
| 214 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; | 216 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 215 | qCDebug(interfaceapp, "vector math usecs: %f [%f usecs total for %d tests], last result:%f", | 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 | // Vec3 test | 220 | // Vec3 test |
| 219 | glm::vec3 vecA(randVector()), vecB(randVector()); | 221 | glm::vec3 vecA(randVector()), vecB(randVector()); |
| 220 | float result; | 222 | float result; |
| 221 | 223 | ||
| 222 | startTime.start(); | 224 | startTime.start(); |
| 223 | for (int i = 0; i < numTests; i++) { | 225 | for (int i = 0; i < numTests; i++) { |
| 224 | glm::vec3 temp = vecA-vecB; | 226 | glm::vec3 temp = vecA-vecB; |
| 225 | result = glm::dot(temp,temp); | 227 | result = glm::dot(temp,temp); |
| 226 | } | 228 | } |
| 227 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; | 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 | bool rayIntersectsSphere(const glm::vec3& rayStarting, const glm::vec3& rayNormalizedDirection, | 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 | if (!_isEnabled) { | 41 | if (!_isEnabled) { |
| 42 | return; | 42 | return; |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | const int linesWhenCentered = _shouldShowInjectedStreams ? 34 : 27; | 45 | const int linesWhenCentered = _shouldShowInjectedStreams ? 34 : 27; |
| 46 | const int CENTERED_BACKGROUND_HEIGHT = STATS_HEIGHT_PER_LINE * linesWhenCentered; | 46 | const int CENTERED_BACKGROUND_HEIGHT = STATS_HEIGHT_PER_LINE * linesWhenCentered; |
| 47 | 47 | ||
| 48 | int lines = _shouldShowInjectedStreams ? _stats->getMixerInjectedStreamStatsMap().size() * 7 + 27 : 27; | 48 | int lines = _shouldShowInjectedStreams ? _stats->getMixerInjectedStreamStatsMap().size() * 7 + 27 : 27; |
| 49 | int statsHeight = STATS_HEIGHT_PER_LINE * lines; | 49 | int statsHeight = STATS_HEIGHT_PER_LINE * lines; |
| 50 | 50 | ||
| 51 | 51 | ||
| 52 | static const glm::vec4 backgroundColor = { 0.2f, 0.2f, 0.2f, 0.6f }; | 52 | static const glm::vec4 backgroundColor = { 0.2f, 0.2f, 0.2f, 0.6f }; |
| 53 | int x = std::max((width - (int)STATS_WIDTH) / 2, 0); | 53 | int x = std::max((width - (int)STATS_WIDTH) / 2, 0); |
| 54 | int y = std::max((height - CENTERED_BACKGROUND_HEIGHT) / 2, 0); | 54 | int y = std::max((height - CENTERED_BACKGROUND_HEIGHT) / 2, 0); |
| 55 | int w = STATS_WIDTH; | 55 | int w = STATS_WIDTH; |
| 56 | int h = statsHeight; | 56 | int h = statsHeight; |
| 57 | DependencyManager::get<GeometryCache>()->renderQuad(x, y, w, h, backgroundColor); | 57 | DependencyManager::get<GeometryCache>()->renderQuad(x, y, w, h, backgroundColor); |
| 58 | 58 | ||
| 59 | int horizontalOffset = x + 5; | 59 | int horizontalOffset = x + 5; |
| 60 | int verticalOffset = y; | 60 | int verticalOffset = y; |
| 61 | 61 | ||
| 62 | float scale = 0.10f; | 62 | float scale = 0.10f; |
| 63 | float rotation = 0.0f; | 63 | float rotation = 0.0f; |
| 64 | int font = 2; | 64 | int font = 2; |
| 65 | 65 | ||
| 66 | char latencyStatString[512]; | 66 | char latencyStatString[512]; |
| 67 | 67 | ||
| 68 | float audioInputBufferLatency = 0.0f, inputRingBufferLatency = 0.0f, networkRoundtripLatency = 0.0f, mixerRingBufferLatency = 0.0f, outputRingBufferLatency = 0.0f, audioOutputBufferLatency = 0.0f; | 68 | float audioInputBufferLatency = 0.0f, inputRingBufferLatency = 0.0f, networkRoundtripLatency = 0.0f, mixerRingBufferLatency = 0.0f, outputRingBufferLatency = 0.0f, audioOutputBufferLatency = 0.0f; |
| 69 | 69 | ||
| 70 | AudioStreamStats downstreamAudioStreamStats = _stats->getMixerDownstreamStats(); | 70 | AudioStreamStats downstreamAudioStreamStats = _stats->getMixerDownstreamStats(); |
| 71 | SharedNodePointer audioMixerNodePointer = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::AudioMixer); | 71 | SharedNodePointer audioMixerNodePointer = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::AudioMixer); |
| 72 | if (!audioMixerNodePointer.isNull()) { | 72 | if (!audioMixerNodePointer.isNull()) { |
| @@ -78,48 +78,62 @@ void AudioIOStatsRenderer::render(const float* color, int width, int height) { · 5 unmodified lines | |||
| 78 | audioOutputBufferLatency = _stats->getAudioOutputMsecsUnplayedStats().getWindowAverage(); | 78 | audioOutputBufferLatency = _stats->getAudioOutputMsecsUnplayedStats().getWindowAverage(); |
| 79 | } | 79 | } |
| 80 | float totalLatency = audioInputBufferLatency + inputRingBufferLatency + networkRoundtripLatency + mixerRingBufferLatency + outputRingBufferLatency + audioOutputBufferLatency; | 80 | float totalLatency = audioInputBufferLatency + inputRingBufferLatency + networkRoundtripLatency + mixerRingBufferLatency + outputRingBufferLatency + audioOutputBufferLatency; |
| 81 | 81 | ||
| 82 | sprintf(latencyStatString, " Audio input buffer: %7.2fms - avg msecs of samples read to the input ring buffer in last 10s", audioInputBufferLatency); | 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 | verticalOffset += STATS_HEIGHT_PER_LINE; | 85 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 84 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); | 86 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 85 | 87 | ||
| 86 | sprintf(latencyStatString, " Input ring buffer: %7.2fms - avg msecs of samples in input ring buffer in last 10s", inputRingBufferLatency); | 88 | sprintf(latencyStatString, |
| 89 | " Input ring buffer: %7.2fms - avg msecs of samples in input ring buffer in last 10s", | ||
| 90 | (double)inputRingBufferLatency); | ||
| 87 | verticalOffset += STATS_HEIGHT_PER_LINE; | 91 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 88 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); | 92 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 89 | 93 | ||
| 90 | sprintf(latencyStatString, " Network to mixer: %7.2fms - half of last ping value calculated by the node list", networkRoundtripLatency / 2.0f); | 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 | verticalOffset += STATS_HEIGHT_PER_LINE; | 97 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 92 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); | 98 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 93 | 99 | ||
| 94 | sprintf(latencyStatString, " AudioMixer ring buffer: %7.2fms - avg msecs of samples in audio mixer's ring buffer in last 10s", mixerRingBufferLatency); | 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 | verticalOffset += STATS_HEIGHT_PER_LINE; | 103 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 96 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); | 104 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 97 | 105 | ||
| 98 | sprintf(latencyStatString, " Network to client: %7.2fms - half of last ping value calculated by the node list", networkRoundtripLatency / 2.0f); | 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 | verticalOffset += STATS_HEIGHT_PER_LINE; | 109 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 100 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); | 110 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 101 | 111 | ||
| 102 | sprintf(latencyStatString, " Output ring buffer: %7.2fms - avg msecs of samples in output ring buffer in last 10s", outputRingBufferLatency); | 112 | sprintf(latencyStatString, |
| 113 | " Output ring buffer: %7.2fms - avg msecs of samples in output ring buffer in last 10s", | ||
| 114 | (double)outputRingBufferLatency); | ||
| 103 | verticalOffset += STATS_HEIGHT_PER_LINE; | 115 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 104 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); | 116 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 105 | 117 | ||
| 106 | sprintf(latencyStatString, " Audio output buffer: %7.2fms - avg msecs of samples in audio output buffer in last 10s", audioOutputBufferLatency); | 118 | sprintf(latencyStatString, |
| 119 | " Audio output buffer: %7.2fms - avg msecs of samples in audio output buffer in last 10s", | ||
| 120 | (double)audioOutputBufferLatency); | ||
| 107 | verticalOffset += STATS_HEIGHT_PER_LINE; | 121 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 108 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); | 122 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 109 | 123 | ||
| 110 | sprintf(latencyStatString, " TOTAL: %7.2fms\n", totalLatency); | 124 | sprintf(latencyStatString, " TOTAL: %7.2fms\n", (double)totalLatency); |
| 111 | verticalOffset += STATS_HEIGHT_PER_LINE; | 125 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 112 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); | 126 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 113 | 127 | ||
| 114 | 128 | ||
| 115 | verticalOffset += STATS_HEIGHT_PER_LINE; // blank line | 129 | verticalOffset += STATS_HEIGHT_PER_LINE; // blank line |
| 116 | 130 | ||
| 117 | char clientUpstreamMicLabelString[] = "Upstream Mic Audio Packets Sent Gaps (by client):"; | 131 | char clientUpstreamMicLabelString[] = "Upstream Mic Audio Packets Sent Gaps (by client):"; |
| 118 | verticalOffset += STATS_HEIGHT_PER_LINE; | 132 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 119 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, clientUpstreamMicLabelString, color); | 133 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, clientUpstreamMicLabelString, color); |
| 120 | 134 | ||
| 121 | const MovingMinMaxAvg<quint64>& packetSentTimeGaps = _stats->getPacketSentTimeGaps(); | 135 | const MovingMinMaxAvg<quint64>& packetSentTimeGaps = _stats->getPacketSentTimeGaps(); |
| 122 | 136 | ||
| 123 | char stringBuffer[512]; | 137 | char stringBuffer[512]; |
| 124 | sprintf(stringBuffer, " Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s", | 138 | sprintf(stringBuffer, " Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s", |
| 125 | formatUsecTime(packetSentTimeGaps.getMin()).toLatin1().data(), | 139 | formatUsecTime(packetSentTimeGaps.getMin()).toLatin1().data(), |
| @@ -127,47 +141,47 @@ void AudioIOStatsRenderer::render(const float* color, int width, int height) { · 1 unmodified line | |||
| 127 | formatUsecTime(packetSentTimeGaps.getAverage()).toLatin1().data()); | 141 | formatUsecTime(packetSentTimeGaps.getAverage()).toLatin1().data()); |
| 128 | verticalOffset += STATS_HEIGHT_PER_LINE; | 142 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 129 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); | 143 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); |
| 130 | 144 | ||
| 131 | sprintf(stringBuffer, " Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s", | 145 | sprintf(stringBuffer, " Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s", |
| 132 | formatUsecTime(packetSentTimeGaps.getWindowMin()).toLatin1().data(), | 146 | formatUsecTime(packetSentTimeGaps.getWindowMin()).toLatin1().data(), |
| 133 | formatUsecTime(packetSentTimeGaps.getWindowMax()).toLatin1().data(), | 147 | formatUsecTime(packetSentTimeGaps.getWindowMax()).toLatin1().data(), |
| 134 | formatUsecTime(packetSentTimeGaps.getWindowAverage()).toLatin1().data()); | 148 | formatUsecTime(packetSentTimeGaps.getWindowAverage()).toLatin1().data()); |
| 135 | verticalOffset += STATS_HEIGHT_PER_LINE; | 149 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 136 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); | 150 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); |
| 137 | 151 | ||
| 138 | verticalOffset += STATS_HEIGHT_PER_LINE; // blank line | 152 | verticalOffset += STATS_HEIGHT_PER_LINE; // blank line |
| 139 | 153 | ||
| 140 | char upstreamMicLabelString[] = "Upstream mic audio stats (received and reported by audio-mixer):"; | 154 | char upstreamMicLabelString[] = "Upstream mic audio stats (received and reported by audio-mixer):"; |
| 141 | verticalOffset += STATS_HEIGHT_PER_LINE; | 155 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 142 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamMicLabelString, color); | 156 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamMicLabelString, color); |
| 143 | 157 | ||
| 144 | renderAudioStreamStats(&_stats->getMixerAvatarStreamStats(), horizontalOffset, verticalOffset, | 158 | renderAudioStreamStats(&_stats->getMixerAvatarStreamStats(), horizontalOffset, verticalOffset, |
| 145 | scale, rotation, font, color); | 159 | scale, rotation, font, color); |
| 146 | 160 | ||
| 147 | 161 | ||
| 148 | verticalOffset += STATS_HEIGHT_PER_LINE; // blank line | 162 | verticalOffset += STATS_HEIGHT_PER_LINE; // blank line |
| 149 | 163 | ||
| 150 | char downstreamLabelString[] = "Downstream mixed audio stats:"; | 164 | char downstreamLabelString[] = "Downstream mixed audio stats:"; |
| 151 | verticalOffset += STATS_HEIGHT_PER_LINE; | 165 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 152 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, downstreamLabelString, color); | 166 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, downstreamLabelString, color); |
| 153 | 167 | ||
| 154 | AudioStreamStats downstreamStats = _stats->getMixerDownstreamStats(); | 168 | AudioStreamStats downstreamStats = _stats->getMixerDownstreamStats(); |
| 155 | renderAudioStreamStats(&downstreamStats, horizontalOffset, verticalOffset, | 169 | renderAudioStreamStats(&downstreamStats, horizontalOffset, verticalOffset, |
| 156 | scale, rotation, font, color, true); | 170 | scale, rotation, font, color, true); |
| 157 | 171 | ||
| 158 | 172 | ||
| 159 | if (_shouldShowInjectedStreams) { | 173 | if (_shouldShowInjectedStreams) { |
| 160 | 174 | ||
| 161 | foreach(const AudioStreamStats& injectedStreamAudioStats, _stats->getMixerInjectedStreamStatsMap()) { | 175 | foreach(const AudioStreamStats& injectedStreamAudioStats, _stats->getMixerInjectedStreamStatsMap()) { |
| 162 | 176 | ||
| 163 | verticalOffset += STATS_HEIGHT_PER_LINE; // blank line | 177 | verticalOffset += STATS_HEIGHT_PER_LINE; // blank line |
| 164 | 178 | ||
| 165 | char upstreamInjectedLabelString[512]; | 179 | char upstreamInjectedLabelString[512]; |
| 166 | sprintf(upstreamInjectedLabelString, "Upstream injected audio stats: stream ID: %s", | 180 | sprintf(upstreamInjectedLabelString, "Upstream injected audio stats: stream ID: %s", |
| 167 | injectedStreamAudioStats._streamIdentifier.toString().toLatin1().data()); | 181 | injectedStreamAudioStats._streamIdentifier.toString().toLatin1().data()); |
| 168 | verticalOffset += STATS_HEIGHT_PER_LINE; | 182 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 169 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamInjectedLabelString, color); | 183 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamInjectedLabelString, color); |
| 170 | 184 | ||
| 171 | renderAudioStreamStats(&injectedStreamAudioStats, horizontalOffset, verticalOffset, scale, rotation, font, color); | 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 | void AudioIOStatsRenderer::renderAudioStreamStats(const AudioStreamStats* streamStats, int horizontalOffset, int& verticalOffset, | 190 | void AudioIOStatsRenderer::renderAudioStreamStats(const AudioStreamStats* streamStats, int horizontalOffset, int& verticalOffset, |
| 177 | float scale, float rotation, int font, const float* color, bool isDownstreamStats) { | 191 | float scale, float rotation, int font, const float* color, bool isDownstreamStats) { |
| 178 | 192 | ||
| 179 | char stringBuffer[512]; | 193 | char stringBuffer[512]; |
| 180 | 194 | ||
| 181 | sprintf(stringBuffer, " Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)", | 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 | streamStats->_packetStreamStats._lost, | 197 | streamStats->_packetStreamStats._lost, |
| 184 | streamStats->_packetStreamWindowStats.getLostRate() * 100.0f, | 198 | (double)(streamStats->_packetStreamWindowStats.getLostRate() * 100.0f), |
| 185 | streamStats->_packetStreamWindowStats._lost); | 199 | streamStats->_packetStreamWindowStats._lost); |
| 186 | verticalOffset += STATS_HEIGHT_PER_LINE; | 200 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 187 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); | 201 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); |
| 188 | 202 | ||
| 189 | if (isDownstreamStats) { | 203 | if (isDownstreamStats) { |
| 190 | sprintf(stringBuffer, " Ringbuffer frames | desired: %u, avg_available(10s): %u+%d, available: %u+%d", | 204 | sprintf(stringBuffer, " Ringbuffer frames | desired: %u, avg_available(10s): %u+%d, available: %u+%d", |
| 191 | streamStats->_desiredJitterBufferFrames, | 205 | streamStats->_desiredJitterBufferFrames, |
| 192 | streamStats->_framesAvailableAverage, | 206 | streamStats->_framesAvailableAverage, |
| 193 | (int)(_stats->getAudioInputMsecsReadStats().getWindowAverage() / AudioConstants::NETWORK_FRAME_MSECS), | 207 | (int)((float)_stats->getAudioInputMsecsReadStats().getWindowAverage() / AudioConstants::NETWORK_FRAME_MSECS), |
| 194 | streamStats->_framesAvailable, | 208 | streamStats->_framesAvailable, |
| 195 | (int)(_stats->getAudioOutputMsecsUnplayedStats().getCurrentIntervalLastSample() | 209 | (int)(_stats->getAudioOutputMsecsUnplayedStats().getCurrentIntervalLastSample() |
| 196 | / AudioConstants::NETWORK_FRAME_MSECS)); | 210 | / AudioConstants::NETWORK_FRAME_MSECS)); |
| @@ -200,10 +214,10 @@ void AudioIOStatsRenderer::renderAudioStreamStats(const AudioStreamStats* stream · 3 unmodified lines | |||
| 200 | streamStats->_framesAvailableAverage, | 214 | streamStats->_framesAvailableAverage, |
| 201 | streamStats->_framesAvailable); | 215 | streamStats->_framesAvailable); |
| 202 | } | 216 | } |
| 203 | 217 | ||
| 204 | verticalOffset += STATS_HEIGHT_PER_LINE; | 218 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 205 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); | 219 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); |
| 206 | 220 | ||
| 207 | sprintf(stringBuffer, " Ringbuffer stats | starves: %u, prev_starve_lasted: %u, frames_dropped: %u, overflows: %u", | 221 | sprintf(stringBuffer, " Ringbuffer stats | starves: %u, prev_starve_lasted: %u, frames_dropped: %u, overflows: %u", |
| 208 | streamStats->_starveCount, | 222 | streamStats->_starveCount, |
| 209 | streamStats->_consecutiveNotMixedCount, | 223 | streamStats->_consecutiveNotMixedCount, |
| @@ -211,18 +225,18 @@ void AudioIOStatsRenderer::renderAudioStreamStats(const AudioStreamStats* stream · 1 unmodified line | |||
| 211 | streamStats->_overflowCount); | 225 | streamStats->_overflowCount); |
| 212 | verticalOffset += STATS_HEIGHT_PER_LINE; | 226 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 213 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); | 227 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); |
| 214 | 228 | ||
| 215 | sprintf(stringBuffer, " Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s", | 229 | sprintf(stringBuffer, " Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s", |
| 216 | formatUsecTime(streamStats->_timeGapMin).toLatin1().data(), | 230 | formatUsecTime(streamStats->_timeGapMin).toLatin1().data(), |
| 217 | formatUsecTime(streamStats->_timeGapMax).toLatin1().data(), | 231 | formatUsecTime(streamStats->_timeGapMax).toLatin1().data(), |
| 218 | formatUsecTime(streamStats->_timeGapAverage).toLatin1().data()); | 232 | formatUsecTime(streamStats->_timeGapAverage).toLatin1().data()); |
| 219 | verticalOffset += STATS_HEIGHT_PER_LINE; | 233 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 220 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); | 234 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); |
| 221 | 235 | ||
| 222 | sprintf(stringBuffer, " Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s", | 236 | sprintf(stringBuffer, " Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s", |
| 223 | formatUsecTime(streamStats->_timeGapWindowMin).toLatin1().data(), | 237 | formatUsecTime(streamStats->_timeGapWindowMin).toLatin1().data(), |
| 224 | formatUsecTime(streamStats->_timeGapWindowMax).toLatin1().data(), | 238 | formatUsecTime(streamStats->_timeGapWindowMax).toLatin1().data(), |
| 225 | formatUsecTime(streamStats->_timeGapWindowAverage).toLatin1().data()); | 239 | formatUsecTime(streamStats->_timeGapWindowAverage).toLatin1().data()); |
| 226 | verticalOffset += STATS_HEIGHT_PER_LINE; | 240 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 227 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); | 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 | const float CHAT_MESSAGE_HEIGHT = 0.1f; | 57 | const float CHAT_MESSAGE_HEIGHT = 0.1f; |
| 58 | const float DISPLAYNAME_FADE_TIME = 0.5f; | 58 | const float DISPLAYNAME_FADE_TIME = 0.5f; |
| 59 | const float DISPLAYNAME_FADE_FACTOR = pow(0.01f, 1.0f / DISPLAYNAME_FADE_TIME); | 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 | const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f; | 61 | const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f; |
| 62 | 62 | ||
| 63 | namespace render { | 63 | namespace render { |
| @@ -107,6 +107,7 @@ Avatar::Avatar() : · 43 unmodified lines | |||
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | Avatar::~Avatar() { | 109 | Avatar::~Avatar() { |
| 110 | assert(_motionState == nullptr); | ||
| 110 | for(auto attachment : _unusedAttachments) { | 111 | for(auto attachment : _unusedAttachments) { |
| 111 | delete attachment; | 112 | delete attachment; |
| 112 | } | 113 | } |
| @@ -280,9 +281,9 @@ enum TextRendererType { · 167 unmodified lines | |||
| 280 | }; | 281 | }; |
| 281 | 282 | ||
| 282 | static TextRenderer3D* textRenderer(TextRendererType type) { | 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 | false, TextRenderer3D::SHADOW_EFFECT); | 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 | switch(type) { | 288 | switch(type) { |
| 288 | case CHAT: | 289 | case CHAT: |
| @@ -323,7 +324,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 34 unmodified lines | |||
| 323 | _referential->update(); | 324 | _referential->update(); |
| 324 | } | 325 | } |
| 325 | 326 | ||
| 326 | auto batch = renderArgs->_batch; | 327 | auto& batch = *renderArgs->_batch; |
| 327 | 328 | ||
| 328 | if (postLighting && | 329 | if (postLighting && |
| 329 | glm::distance(DependencyManager::get<AvatarManager>()->getMyAvatar()->getPosition(), _position) < 10.0f) { | 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 | Transform pointerTransform; | 355 | Transform pointerTransform; |
| 355 | pointerTransform.setTranslation(position); | 356 | pointerTransform.setTranslation(position); |
| 356 | pointerTransform.setRotation(rotation); | 357 | pointerTransform.setRotation(rotation); |
| 357 | batch->setModelTransform(pointerTransform); | 358 | batch.setModelTransform(pointerTransform); |
| 358 | deferredLighting->bindSimpleProgram(*batch); | 359 | deferredLighting->bindSimpleProgram(batch); |
| 359 | geometryCache->renderLine(*batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor); | 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 | Transform pointerTransform; | 378 | Transform pointerTransform; |
| 378 | pointerTransform.setTranslation(position); | 379 | pointerTransform.setTranslation(position); |
| 379 | pointerTransform.setRotation(rotation); | 380 | pointerTransform.setRotation(rotation); |
| 380 | batch->setModelTransform(pointerTransform); | 381 | batch.setModelTransform(pointerTransform); |
| 381 | deferredLighting->bindSimpleProgram(*batch); | 382 | deferredLighting->bindSimpleProgram(batch); |
| 382 | geometryCache->renderLine(*batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor); | 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 | Transform transform; | 466 | Transform transform; |
| 466 | transform.setTranslation(position); | 467 | transform.setTranslation(position); |
| 467 | batch->setModelTransform(transform); | 468 | batch.setModelTransform(transform); |
| 468 | DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(*batch, LOOK_AT_INDICATOR_RADIUS | 469 | DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(batch, LOOK_AT_INDICATOR_RADIUS |
| 469 | , 15, 15, LOOK_AT_INDICATOR_COLOR); | 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 | Transform transform; | 493 | Transform transform; |
| 493 | transform.setTranslation(_position); | 494 | transform.setTranslation(_position); |
| 494 | transform.setScale(height); | 495 | transform.setScale(height); |
| 495 | batch->setModelTransform(transform); | 496 | batch.setModelTransform(transform); |
| 496 | 497 | ||
| 497 | if (_voiceSphereID == GeometryCache::UNKNOWN_ID) { | 498 | if (_voiceSphereID == GeometryCache::UNKNOWN_ID) { |
| 498 | _voiceSphereID = DependencyManager::get<GeometryCache>()->allocateID(); | 499 | _voiceSphereID = DependencyManager::get<GeometryCache>()->allocateID(); |
| 499 | } | 500 | } |
| 500 | 501 | ||
| 501 | DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(*batch); | 502 | DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch); |
| 502 | DependencyManager::get<GeometryCache>()->renderSphere(*batch, sphereRadius, 15, 15, | 503 | DependencyManager::get<GeometryCache>()->renderSphere(batch, sphereRadius, 15, 15, |
| 503 | glm::vec4(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE), true, | 504 | glm::vec4(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE), true, |
| 504 | _voiceSphereID); | 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 | const float DISPLAYNAME_DISTANCE = 20.0f; | 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 | auto cameraMode = Application::getInstance()->getCamera()->getMode(); |
| 513 | Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON)) { | 514 | if (!isMyAvatar() || cameraMode != CAMERA_MODE_FIRST_PERSON) { |
| 514 | return; | 515 | renderDisplayName(batch, *renderArgs->_viewFrustum); |
| 515 | } | 516 | } |
| 516 | |||
| 517 | renderDisplayName(renderArgs); | ||
| 518 | } | 517 | } |
| 519 | 518 | ||
| 520 | glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { | 519 | glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { |
| @@ -654,8 +653,8 @@ float Avatar::getBillboardSize() const { · 133 unmodified lines | |||
| 654 | return _scale * BILLBOARD_DISTANCE * tanf(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); | 653 | return _scale * BILLBOARD_DISTANCE * tanf(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); |
| 655 | } | 654 | } |
| 656 | 655 | ||
| 657 | glm::vec3 Avatar::getDisplayNamePosition() { | 656 | glm::vec3 Avatar::getDisplayNamePosition() const { |
| 658 | glm::vec3 namePosition; | 657 | glm::vec3 namePosition(0.0f); |
| 659 | if (getSkeletonModel().getNeckPosition(namePosition)) { | 658 | if (getSkeletonModel().getNeckPosition(namePosition)) { |
| 660 | namePosition += getBodyUpDirection() * getHeadHeight() * 1.1f; | 659 | namePosition += getBodyUpDirection() * getHeadHeight() * 1.1f; |
| 661 | } else { | 660 | } else { |
| @@ -665,81 +664,73 @@ glm::vec3 Avatar::getDisplayNamePosition() { · 3 unmodified lines | |||
| 665 | return namePosition; | 664 | return namePosition; |
| 666 | } | 665 | } |
| 667 | 666 | ||
| 668 | float Avatar::calculateDisplayNameScaleFactor(const glm::vec3& textPosition, bool inHMD) { | 667 | Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& frustum, float fontSize) const { |
| 669 | 668 | Transform result; | |
| 670 | // We need to compute the scale factor such as the text remains with fixed size respect to window coordinates | 669 | // We assume textPosition is whithin the frustum |
| 671 | // We project a unit vector and check the difference in screen coordinates, to check which is the | 670 | glm::vec3 textPosition = getDisplayNamePosition(); |
| 672 | // correction scale needed | 671 | |
| 673 | // save the matrices for later scale correction factor | 672 | // Compute viewProjection matrix |
| 674 | // The up vector must be relative to the rotation current rotation matrix: | 673 | glm::mat4 projMat, viewMat; |
| 675 | // we set the identity | 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 | glm::vec3 testPoint0 = textPosition; | 680 | glm::vec3 testPoint0 = textPosition; |
| 677 | glm::vec3 testPoint1 = textPosition + (Application::getInstance()->getCamera()->getRotation() * IDENTITY_UP); | 681 | glm::vec3 testPoint1 = testPoint0 + glm::normalize(frustum.getUp()); |
| 678 | 682 | // testPoints projections | |
| 679 | double textWindowHeight; | 683 | glm::vec4 p0 = viewProj * glm::vec4(testPoint0, 1.0); |
| 680 | 684 | glm::vec4 p1 = viewProj * glm::vec4(testPoint1, 1.0); | |
| 685 | |||
| 686 | // TODO REMOVE vvv | ||
| 681 | GLint viewportMatrix[4]; | 687 | GLint viewportMatrix[4]; |
| 682 | glGetIntegerv(GL_VIEWPORT, viewportMatrix); | 688 | glGetIntegerv(GL_VIEWPORT, viewportMatrix); |
| 683 | glm::dmat4 modelViewMatrix; | 689 | glm::dmat4 modelViewMatrix; |
| 684 | float windowSizeX = viewportMatrix[2] - viewportMatrix[0]; | ||
| 685 | float windowSizeY = viewportMatrix[3] - viewportMatrix[1]; | 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) { | 723 | void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) const { |
| 714 | auto batch = renderArgs->_batch; | ||
| 715 | |||
| 716 | bool shouldShowReceiveStats = DependencyManager::get<AvatarManager>()->shouldShowReceiveStats() && !isMyAvatar(); | 724 | bool shouldShowReceiveStats = DependencyManager::get<AvatarManager>()->shouldShowReceiveStats() && !isMyAvatar(); |
| 717 | 725 | ||
| 726 | // If we have nothing to draw, or it's tottaly transparent, return | ||
| 718 | if ((_displayName.isEmpty() && !shouldShowReceiveStats) || _displayNameAlpha == 0.0f) { | 727 | if ((_displayName.isEmpty() && !shouldShowReceiveStats) || _displayNameAlpha == 0.0f) { |
| 719 | return; | 728 | return; |
| 720 | } | 729 | } |
| 721 | 730 | auto renderer = textRenderer(DISPLAYNAME); | |
| 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); | ||
| 738 | 731 | ||
| 739 | // optionally render timing stats for this avatar with the display name | 732 | // optionally render timing stats for this avatar with the display name |
| 740 | QString renderedDisplayName = _displayName; | 733 | QString renderedDisplayName = _displayName; |
| 741 | QRect nameDynamicRect = _displayNameBoundingRect; | ||
| 742 | |||
| 743 | if (shouldShowReceiveStats) { | 734 | if (shouldShowReceiveStats) { |
| 744 | float kilobitsPerSecond = getAverageBytesReceivedPerSecond() / (float) BYTES_PER_KILOBIT; | 735 | float kilobitsPerSecond = getAverageBytesReceivedPerSecond() / (float) BYTES_PER_KILOBIT; |
| 745 | 736 | ||
| @@ -747,42 +738,43 @@ void Avatar::renderDisplayName(RenderArgs* renderArgs) { · 1 unmodified line | |||
| 747 | if (!renderedDisplayName.isEmpty()) { | 738 | if (!renderedDisplayName.isEmpty()) { |
| 748 | statsFormat.prepend(" - "); | 739 | statsFormat.prepend(" - "); |
| 749 | } | 740 | } |
| 750 | 741 | renderedDisplayName += statsFormat.arg(QString::number(kilobitsPerSecond, 'f', 2)).arg(getReceiveRate()); | |
| 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); | ||
| 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 | glm::vec4 textColor(0.93f, 0.93f, 0.93f, _displayNameAlpha); | 760 | glm::vec4 textColor(0.93f, 0.93f, 0.93f, _displayNameAlpha); |
| 773 | glm::vec4 backgroundColor(0.2f, 0.2f, 0.2f, | 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 | auto backgroundTransform = textTransform; | 768 | auto backgroundTransform = textTransform; |
| 777 | backgroundTransform.postTranslate(glm::vec3(0.0f, 0.0f, -0.001f)); | 769 | backgroundTransform.postTranslate(glm::vec3(0.0f, 0.0f, SLIGHTLY_BEHIND)); |
| 778 | batch->setModelTransform(backgroundTransform); | 770 | batch.setModelTransform(backgroundTransform); |
| 779 | DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(*batch); | 771 | DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch); |
| 780 | DependencyManager::get<GeometryCache>()->renderBevelCornersRect(*batch, left, bottom, right - left, top - bottom, 3, | 772 | DependencyManager::get<GeometryCache>()->renderBevelCornersRect(batch, left, bottom, width, height, |
| 781 | backgroundColor); | 773 | bevelDistance, backgroundColor); |
| 774 | // Render actual name | ||
| 782 | QByteArray nameUTF8 = renderedDisplayName.toLocal8Bit(); | 775 | QByteArray nameUTF8 = renderedDisplayName.toLocal8Bit(); |
| 783 | 776 | batch.setModelTransform(textTransform); | |
| 784 | batch->setModelTransform(textTransform); | 777 | renderer->draw(batch, text_x, -text_y, nameUTF8.data(), textColor); |
| 785 | textRenderer(DISPLAYNAME)->draw(*batch, text_x, -text_y, nameUTF8.data(), textColor); | ||
| 786 | } | 778 | } |
| 787 | 779 | ||
| 788 | bool Avatar::findRayIntersection(RayIntersectionInfo& intersection) const { | 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 | void Avatar::setBillboard(const QByteArray& billboard) { | 982 | void Avatar::setBillboard(const QByteArray& billboard) { |
| 998 | AvatarData::setBillboard(billboard); | 983 | AvatarData::setBillboard(billboard); |
| 999 | 984 | ||
| @@ -1092,7 +1077,12 @@ float Avatar::getSkeletonHeight() const { · 92 unmodified lines | |||
| 1092 | float Avatar::getHeadHeight() const { | 1077 | float Avatar::getHeadHeight() const { |
| 1093 | Extents extents = getHead()->getFaceModel().getMeshExtents(); | 1078 | Extents extents = getHead()->getFaceModel().getMeshExtents(); |
| 1094 | if (!extents.isEmpty() && extents.isValid()) { | 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 | extents = _skeletonModel.getMeshExtents(); | 1088 | extents = _skeletonModel.getMeshExtents(); |
| @@ -1116,7 +1106,7 @@ void Avatar::setShowDisplayName(bool showDisplayName) { · 17 unmodified lines | |||
| 1116 | } | 1106 | } |
| 1117 | 1107 | ||
| 1118 | // For myAvatar, the alpha update is not done (called in simulate for other avatars) | 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 | if (showDisplayName) { | 1110 | if (showDisplayName) { |
| 1121 | _displayNameAlpha = DISPLAYNAME_ALPHA; | 1111 | _displayNameAlpha = DISPLAYNAME_ALPHA; |
| 1122 | } else { | 1112 | } else { |
| @@ -1129,7 +1119,6 @@ void Avatar::setShowDisplayName(bool showDisplayName) { · 6 unmodified lines | |||
| 1129 | } else { | 1119 | } else { |
| 1130 | _displayNameTargetAlpha = 0.0f; | 1120 | _displayNameTargetAlpha = 0.0f; |
| 1131 | } | 1121 | } |
| 1132 | |||
| 1133 | } | 1122 | } |
| 1134 | 1123 | ||
| 1135 | // virtual | 1124 | // virtual |
| @@ -98,6 +98,7 @@ public: · 97 unmodified lines | |||
| 98 | //getters | 98 | //getters |
| 99 | bool isInitialized() const { return _initialized; } | 99 | bool isInitialized() const { return _initialized; } |
| 100 | SkeletonModel& getSkeletonModel() { return _skeletonModel; } | 100 | SkeletonModel& getSkeletonModel() { return _skeletonModel; } |
| 101 | const SkeletonModel& getSkeletonModel() const { return _skeletonModel; } | ||
| 101 | const QVector<Model*>& getAttachmentModels() const { return _attachmentModels; } | 102 | const QVector<Model*>& getAttachmentModels() const { return _attachmentModels; } |
| 102 | glm::vec3 getChestPosition() const; | 103 | glm::vec3 getChestPosition() const; |
| 103 | float getScale() const { return _scale; } | 104 | float getScale() const { return _scale; } |
| @@ -131,7 +132,7 @@ public: · 27 unmodified lines | |||
| 131 | /// \return whether or not the plane penetrated | 132 | /// \return whether or not the plane penetrated |
| 132 | bool findPlaneCollisions(const glm::vec4& plane, CollisionList& collisions); | 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 | virtual QVector<glm::quat> getJointRotations() const; | 137 | virtual QVector<glm::quat> getJointRotations() const; |
| 137 | virtual glm::quat getJointRotation(int index) const; | 138 | virtual glm::quat getJointRotation(int index) const; |
| @@ -141,7 +142,6 @@ public: · 3 unmodified lines | |||
| 141 | virtual void setFaceModelURL(const QUrl& faceModelURL); | 142 | virtual void setFaceModelURL(const QUrl& faceModelURL); |
| 142 | virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); | 143 | virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); |
| 143 | virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData); | 144 | virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData); |
| 144 | virtual void setDisplayName(const QString& displayName); | ||
| 145 | virtual void setBillboard(const QByteArray& billboard); | 145 | virtual void setBillboard(const QByteArray& billboard); |
| 146 | 146 | ||
| 147 | void setShowDisplayName(bool showDisplayName); | 147 | void setShowDisplayName(bool showDisplayName); |
| @@ -232,10 +232,10 @@ protected: · 84 unmodified lines | |||
| 232 | float getSkeletonHeight() const; | 232 | float getSkeletonHeight() const; |
| 233 | float getHeadHeight() const; | 233 | float getHeadHeight() const; |
| 234 | float getPelvisFloatingHeight() const; | 234 | float getPelvisFloatingHeight() const; |
| 235 | glm::vec3 getDisplayNamePosition(); | 235 | glm::vec3 getDisplayNamePosition() const; |
| 236 | 236 | ||
| 237 | float calculateDisplayNameScaleFactor(const glm::vec3& textPosition, bool inHMD); | 237 | Transform calculateDisplayNameTransform(const ViewFrustum& frustum, float fontSize) const; |
| 238 | void renderDisplayName(RenderArgs* renderArgs); | 238 | void renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) const; |
| 239 | virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel = 0.0f); | 239 | virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel = 0.0f); |
| 240 | virtual bool shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const; | 240 | virtual bool shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const; |
| 241 | virtual void fixupModelsInScene(); | 241 | virtual void fixupModelsInScene(); |
| @@ -29,6 +29,12 @@ AvatarActionHold::~AvatarActionHold() { · 28 unmodified lines | |||
| 29 | 29 | ||
| 30 | void AvatarActionHold::updateActionWorker(float deltaTimeStep) { | 30 | void AvatarActionHold::updateActionWorker(float deltaTimeStep) { |
| 31 | auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | 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 | glm::vec3 palmPosition; | 38 | glm::vec3 palmPosition; |
| 33 | if (_hand == "right") { | 39 | if (_hand == "right") { |
| 34 | palmPosition = myAvatar->getRightPalmPosition(); | 40 | palmPosition = myAvatar->getRightPalmPosition(); |
| @@ -40,8 +46,11 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { · 5 unmodified lines | |||
| 40 | auto offset = rotation * _relativePosition; | 46 | auto offset = rotation * _relativePosition; |
| 41 | auto position = palmPosition + offset; | 47 | auto position = palmPosition + offset; |
| 42 | rotation *= _relativeRotation; | 48 | rotation *= _relativeRotation; |
| 49 | unlock(); | ||
| 43 | 50 | ||
| 44 | lockForWrite(); | 51 | if (!tryLockForWrite()) { |
| 52 | return; | ||
| 53 | } | ||
| 45 | _positionalTarget = position; | 54 | _positionalTarget = position; |
| 46 | _rotationalTarget = rotation; | 55 | _rotationalTarget = rotation; |
| 47 | unlock(); | 56 | unlock(); |
| @@ -13,8 +13,18 @@ · 12 unmodified lines | |||
| 13 | 13 | ||
| 14 | #include <QScriptEngine> | 14 | #include <QScriptEngine> |
| 15 | 15 | ||
| 16 | #ifdef __GNUC__ | ||
| 17 | #pragma GCC diagnostic push | ||
| 18 | #pragma GCC diagnostic ignored "-Wdouble-promotion" | ||
| 19 | #endif | ||
| 20 | |||
| 16 | #include <glm/gtx/string_cast.hpp> | 21 | #include <glm/gtx/string_cast.hpp> |
| 17 | 22 | ||
| 23 | #ifdef __GNUC__ | ||
| 24 | #pragma GCC diagnostic pop | ||
| 25 | #endif | ||
| 26 | |||
| 27 | |||
| 18 | #include <GlowEffect.h> | 28 | #include <GlowEffect.h> |
| 19 | #include <PerfStat.h> | 29 | #include <PerfStat.h> |
| 20 | #include <RegisteredMetaTypes.h> | 30 | #include <RegisteredMetaTypes.h> |
| @@ -104,6 +114,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { · 83 unmodified lines | |||
| 104 | // DO NOT update or fade out uninitialized Avatars | 114 | // DO NOT update or fade out uninitialized Avatars |
| 105 | ++avatarIterator; | 115 | ++avatarIterator; |
| 106 | } else if (avatar->shouldDie()) { | 116 | } else if (avatar->shouldDie()) { |
| 117 | removeAvatarMotionState(avatar); | ||
| 107 | _avatarFades.push_back(avatarIterator.value()); | 118 | _avatarFades.push_back(avatarIterator.value()); |
| 108 | avatarIterator = _avatarHash.erase(avatarIterator); | 119 | avatarIterator = _avatarHash.erase(avatarIterator); |
| 109 | } else { | 120 | } else { |
| @@ -153,12 +164,13 @@ AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWe · 43 unmodified lines | |||
| 153 | } | 164 | } |
| 154 | 165 | ||
| 155 | // protected | 166 | // protected |
| 156 | void AvatarManager::removeAvatarMotionState(Avatar* avatar) { | 167 | void AvatarManager::removeAvatarMotionState(AvatarSharedPointer avatar) { |
| 157 | AvatarMotionState* motionState= avatar->_motionState; | 168 | auto rawPointer = std::static_pointer_cast<Avatar>(avatar); |
| 169 | AvatarMotionState* motionState= rawPointer->_motionState; | ||
| 158 | if (motionState) { | 170 | if (motionState) { |
| 159 | // clean up physics stuff | 171 | // clean up physics stuff |
| 160 | motionState->clearObjectBackPointer(); | 172 | motionState->clearObjectBackPointer(); |
| 161 | avatar->_motionState = nullptr; | 173 | rawPointer->_motionState = nullptr; |
| 162 | _avatarMotionStates.remove(motionState); | 174 | _avatarMotionStates.remove(motionState); |
| 163 | _motionStatesToAdd.remove(motionState); | 175 | _motionStatesToAdd.remove(motionState); |
| 164 | _motionStatesToDelete.push_back(motionState); | 176 | _motionStatesToDelete.push_back(motionState); |
| @@ -171,7 +183,7 @@ void AvatarManager::removeAvatar(const QUuid& sessionUUID) { · 6 unmodified lines | |||
| 171 | if (avatarIterator != _avatarHash.end()) { | 183 | if (avatarIterator != _avatarHash.end()) { |
| 172 | std::shared_ptr<Avatar> avatar = std::dynamic_pointer_cast<Avatar>(avatarIterator.value()); | 184 | std::shared_ptr<Avatar> avatar = std::dynamic_pointer_cast<Avatar>(avatarIterator.value()); |
| 173 | if (avatar != _myAvatar && avatar->isInitialized()) { | 185 | if (avatar != _myAvatar && avatar->isInitialized()) { |
| 174 | removeAvatarMotionState(avatar.get()); | 186 | removeAvatarMotionState(avatar); |
| 175 | _avatarFades.push_back(avatarIterator.value()); | 187 | _avatarFades.push_back(avatarIterator.value()); |
| 176 | _avatarHash.erase(avatarIterator); | 188 | _avatarHash.erase(avatarIterator); |
| 177 | } | 189 | } |
| @@ -187,7 +199,7 @@ void AvatarManager::clearOtherAvatars() { · 9 unmodified lines | |||
| 187 | // don't remove myAvatar or uninitialized avatars from the list | 199 | // don't remove myAvatar or uninitialized avatars from the list |
| 188 | ++avatarIterator; | 200 | ++avatarIterator; |
| 189 | } else { | 201 | } else { |
| 190 | removeAvatarMotionState(avatar.get()); | 202 | removeAvatarMotionState(avatar); |
| 191 | _avatarFades.push_back(avatarIterator.value()); | 203 | _avatarFades.push_back(avatarIterator.value()); |
| 192 | avatarIterator = _avatarHash.erase(avatarIterator); | 204 | avatarIterator = _avatarHash.erase(avatarIterator); |
| 193 | } | 205 | } |
| @@ -73,7 +73,7 @@ private: · 72 unmodified lines | |||
| 73 | // virtual overrides | 73 | // virtual overrides |
| 74 | virtual AvatarSharedPointer newSharedAvatar(); | 74 | virtual AvatarSharedPointer newSharedAvatar(); |
| 75 | virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer); | 75 | virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer); |
| 76 | void removeAvatarMotionState(Avatar* avatar); | 76 | void removeAvatarMotionState(AvatarSharedPointer avatar); |
| 77 | virtual void removeAvatar(const QUuid& sessionUUID); | 77 | virtual void removeAvatar(const QUuid& sessionUUID); |
| 78 | 78 | ||
| 79 | QVector<AvatarSharedPointer> _avatarFades; | 79 | QVector<AvatarSharedPointer> _avatarFades; |
| @@ -77,7 +77,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { · 76 unmodified lines | |||
| 77 | const float AUDIO_LONG_TERM_AVERAGING_SECS = 30.0f; | 77 | const float AUDIO_LONG_TERM_AVERAGING_SECS = 30.0f; |
| 78 | _averageLoudness = glm::mix(_averageLoudness, _audioLoudness, glm::min(deltaTime / AUDIO_AVERAGING_SECS, 1.0f)); | 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 | _longTermAverageLoudness = _averageLoudness; | 81 | _longTermAverageLoudness = _averageLoudness; |
| 82 | } else { | 82 | } else { |
| 83 | _longTermAverageLoudness = glm::mix(_longTermAverageLoudness, _averageLoudness, glm::min(deltaTime / AUDIO_LONG_TERM_AVERAGING_SECS, 1.0f)); | 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 | if (!(_isFaceTrackerConnected || billboard)) { | 125 | if (!(_isFaceTrackerConnected || billboard)) { |
| 126 | // Update eye saccades | 126 | // Update eye saccades |
| 127 | const float AVERAGE_MICROSACCADE_INTERVAL = 0.50f; | 127 | const float AVERAGE_MICROSACCADE_INTERVAL = 1.0f; |
| 128 | const float AVERAGE_SACCADE_INTERVAL = 4.0f; | 128 | const float AVERAGE_SACCADE_INTERVAL = 6.0f; |
| 129 | const float MICROSACCADE_MAGNITUDE = 0.002f; | 129 | const float MICROSACCADE_MAGNITUDE = 0.002f; |
| 130 | const float SACCADE_MAGNITUDE = 0.04f; | 130 | const float SACCADE_MAGNITUDE = 0.04f; |
| 131 | 131 | const float MAXIMUM_SACCADE_SPEED = 0.8f; | |
| 132 | |||
| 132 | if (randFloat() < deltaTime / AVERAGE_MICROSACCADE_INTERVAL) { | 133 | if (randFloat() < deltaTime / AVERAGE_MICROSACCADE_INTERVAL) { |
| 133 | _saccadeTarget = MICROSACCADE_MAGNITUDE * randVector(); | 134 | _saccadeTarget = MICROSACCADE_MAGNITUDE * randVector(); |
| 134 | } else if (randFloat() < deltaTime / AVERAGE_SACCADE_INTERVAL) { | 135 | } else if (randFloat() < deltaTime / AVERAGE_SACCADE_INTERVAL) { |
| 135 | _saccadeTarget = SACCADE_MAGNITUDE * randVector(); | 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 | // Detect transition from talking to not; force blink after that and a delay | 146 | // Detect transition from talking to not; force blink after that and a delay |
| 140 | bool forceBlink = false; | 147 | bool forceBlink = false; |
| 141 | const float TALKING_LOUDNESS = 100.0f; | 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 | const float MAX_BOOST_SPEED = 0.5f * MAX_WALKING_SPEED; // keyboard motor gets additive boost below this speed | 59 | const float MAX_BOOST_SPEED = 0.5f * MAX_WALKING_SPEED; // keyboard motor gets additive boost below this speed |
| 60 | const float MIN_AVATAR_SPEED = 0.05f; // speed is set to zero below this | 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 | // to properly follow avatar size. | 63 | // to properly follow avatar size. |
| 64 | float MAX_AVATAR_SPEED = 300.0f; | 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 | float DEFAULT_KEYBOARD_MOTOR_TIMESCALE = 0.25f; | 66 | float DEFAULT_KEYBOARD_MOTOR_TIMESCALE = 0.25f; |
| 67 | float MIN_SCRIPTED_MOTOR_TIMESCALE = 0.005f; | 67 | float MIN_SCRIPTED_MOTOR_TIMESCALE = 0.005f; |
| 68 | float DEFAULT_SCRIPTED_MOTOR_TIMESCALE = 1.0e6f; | 68 | float DEFAULT_SCRIPTED_MOTOR_TIMESCALE = 1.0e6f; |
| @@ -146,7 +146,7 @@ void MyAvatar::update(float deltaTime) { · 77 unmodified lines | |||
| 146 | if (_referential) { | 146 | if (_referential) { |
| 147 | _referential->update(); | 147 | _referential->update(); |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | Head* head = getHead(); | 150 | Head* head = getHead(); |
| 151 | head->relaxLean(deltaTime); | 151 | head->relaxLean(deltaTime); |
| 152 | updateFromTrackers(deltaTime); | 152 | updateFromTrackers(deltaTime); |
| @@ -163,12 +163,12 @@ void MyAvatar::update(float deltaTime) { · 10 unmodified lines | |||
| 163 | 163 | ||
| 164 | void MyAvatar::simulate(float deltaTime) { | 164 | void MyAvatar::simulate(float deltaTime) { |
| 165 | PerformanceTimer perfTimer("simulate"); | 165 | PerformanceTimer perfTimer("simulate"); |
| 166 | 166 | ||
| 167 | // Play back recording | 167 | // Play back recording |
| 168 | if (_player && _player->isPlaying()) { | 168 | if (_player && _player->isPlaying()) { |
| 169 | _player->play(); | 169 | _player->play(); |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | if (_scale != _targetScale) { | 172 | if (_scale != _targetScale) { |
| 173 | float scale = (1.0f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale; | 173 | float scale = (1.0f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale; |
| 174 | setScale(scale); | 174 | setScale(scale); |
| @@ -179,7 +179,7 @@ void MyAvatar::simulate(float deltaTime) { · 4 unmodified lines | |||
| 179 | updateOrientation(deltaTime); | 179 | updateOrientation(deltaTime); |
| 180 | updatePosition(deltaTime); | 180 | updatePosition(deltaTime); |
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | { | 183 | { |
| 184 | PerformanceTimer perfTimer("hand"); | 184 | PerformanceTimer perfTimer("hand"); |
| 185 | // update avatar skeleton and simulate hand and head | 185 | // update avatar skeleton and simulate hand and head |
| @@ -222,12 +222,12 @@ void MyAvatar::simulate(float deltaTime) { · 36 unmodified lines | |||
| 222 | head->setScale(_scale); | 222 | head->setScale(_scale); |
| 223 | head->simulate(deltaTime, true); | 223 | head->simulate(deltaTime, true); |
| 224 | } | 224 | } |
| 225 | 225 | ||
| 226 | // Record avatars movements. | 226 | // Record avatars movements. |
| 227 | if (_recorder && _recorder->isRecording()) { | 227 | if (_recorder && _recorder->isRecording()) { |
| 228 | _recorder->record(); | 228 | _recorder->record(); |
| 229 | } | 229 | } |
| 230 | 230 | ||
| 231 | // consider updating our billboard | 231 | // consider updating our billboard |
| 232 | maybeUpdateBillboard(); | 232 | maybeUpdateBillboard(); |
| 233 | } | 233 | } |
| @@ -235,18 +235,18 @@ void MyAvatar::simulate(float deltaTime) { · 1 unmodified line | |||
| 235 | // Update avatar head rotation with sensor data | 235 | // Update avatar head rotation with sensor data |
| 236 | void MyAvatar::updateFromTrackers(float deltaTime) { | 236 | void MyAvatar::updateFromTrackers(float deltaTime) { |
| 237 | glm::vec3 estimatedPosition, estimatedRotation; | 237 | glm::vec3 estimatedPosition, estimatedRotation; |
| 238 | 238 | ||
| 239 | bool inHmd = qApp->isHMDMode(); | 239 | bool inHmd = qApp->isHMDMode(); |
| 240 | 240 | ||
| 241 | if (isPlaying() && inHmd) { | 241 | if (isPlaying() && inHmd) { |
| 242 | return; | 242 | return; |
| 243 | } | 243 | } |
| 244 | 244 | ||
| 245 | if (inHmd) { | 245 | if (inHmd) { |
| 246 | estimatedPosition = qApp->getHeadPosition(); | 246 | estimatedPosition = qApp->getHeadPosition(); |
| 247 | estimatedPosition.x *= -1.0f; | 247 | estimatedPosition.x *= -1.0f; |
| 248 | _trackedHeadPosition = estimatedPosition; | 248 | _trackedHeadPosition = estimatedPosition; |
| 249 | 249 | ||
| 250 | const float OCULUS_LEAN_SCALE = 0.05f; | 250 | const float OCULUS_LEAN_SCALE = 0.05f; |
| 251 | estimatedPosition /= OCULUS_LEAN_SCALE; | 251 | estimatedPosition /= OCULUS_LEAN_SCALE; |
| 252 | } else { | 252 | } else { |
| @@ -257,7 +257,7 @@ void MyAvatar::updateFromTrackers(float deltaTime) { · 4 unmodified lines | |||
| 257 | estimatedRotation = glm::degrees(safeEulerAngles(tracker->getHeadRotation())); | 257 | estimatedRotation = glm::degrees(safeEulerAngles(tracker->getHeadRotation())); |
| 258 | } | 258 | } |
| 259 | } | 259 | } |
| 260 | 260 | ||
| 261 | // Rotate the body if the head is turned beyond the screen | 261 | // Rotate the body if the head is turned beyond the screen |
| 262 | if (Menu::getInstance()->isOptionChecked(MenuOption::TurnWithHead)) { | 262 | if (Menu::getInstance()->isOptionChecked(MenuOption::TurnWithHead)) { |
| 263 | const float TRACKER_YAW_TURN_SENSITIVITY = 0.5f; | 263 | const float TRACKER_YAW_TURN_SENSITIVITY = 0.5f; |
| @@ -317,7 +317,7 @@ void MyAvatar::renderDebugBodyPoints() { · 53 unmodified lines | |||
| 317 | glm::vec3 headPosition(getHead()->getEyePosition()); | 317 | glm::vec3 headPosition(getHead()->getEyePosition()); |
| 318 | float torsoToHead = glm::length(headPosition - torsoPosition); | 318 | float torsoToHead = glm::length(headPosition - torsoPosition); |
| 319 | glm::vec3 position; | 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 | // Torso Sphere | 322 | // Torso Sphere |
| 323 | position = torsoPosition; | 323 | position = torsoPosition; |
| @@ -433,7 +433,7 @@ void MyAvatar::startRecording() { · 109 unmodified lines | |||
| 433 | auto audioClient = DependencyManager::get<AudioClient>(); | 433 | auto audioClient = DependencyManager::get<AudioClient>(); |
| 434 | connect(audioClient.data(), &AudioClient::inputReceived, _recorder.data(), | 434 | connect(audioClient.data(), &AudioClient::inputReceived, _recorder.data(), |
| 435 | &Recorder::recordAudio, Qt::BlockingQueuedConnection); | 435 | &Recorder::recordAudio, Qt::BlockingQueuedConnection); |
| 436 | 436 | ||
| 437 | _recorder->startRecording(); | 437 | _recorder->startRecording(); |
| 438 | } | 438 | } |
| 439 | 439 | ||
| @@ -449,7 +449,7 @@ void MyAvatar::stopRecording() { · 9 unmodified lines | |||
| 449 | // stop grabbing audio from the AudioClient | 449 | // stop grabbing audio from the AudioClient |
| 450 | auto audioClient = DependencyManager::get<AudioClient>(); | 450 | auto audioClient = DependencyManager::get<AudioClient>(); |
| 451 | disconnect(audioClient.data(), 0, _recorder.data(), 0); | 451 | disconnect(audioClient.data(), 0, _recorder.data(), 0); |
| 452 | 452 | ||
| 453 | _recorder->stopRecording(); | 453 | _recorder->stopRecording(); |
| 454 | } | 454 | } |
| 455 | } | 455 | } |
| @@ -481,7 +481,7 @@ void MyAvatar::loadLastRecording() { · 25 unmodified lines | |||
| 481 | if (!_player) { | 481 | if (!_player) { |
| 482 | _player = PlayerPointer(new Player(this)); | 482 | _player = PlayerPointer(new Player(this)); |
| 483 | } | 483 | } |
| 484 | 484 | ||
| 485 | _player->loadRecording(_recorder->getRecording()); | 485 | _player->loadRecording(_recorder->getRecording()); |
| 486 | } | 486 | } |
| 487 | 487 | ||
| @@ -573,7 +573,7 @@ AnimationDetails MyAvatar::getAnimationDetailsByRole(const QString& role) { · 85 unmodified lines | |||
| 573 | AnimationDetails result; | 573 | AnimationDetails result; |
| 574 | if (QThread::currentThread() != thread()) { | 574 | if (QThread::currentThread() != thread()) { |
| 575 | QMetaObject::invokeMethod(this, "getAnimationDetailsByRole", Qt::BlockingQueuedConnection, | 575 | QMetaObject::invokeMethod(this, "getAnimationDetailsByRole", Qt::BlockingQueuedConnection, |
| 576 | Q_RETURN_ARG(AnimationDetails, result), | 576 | Q_RETURN_ARG(AnimationDetails, result), |
| 577 | Q_ARG(const QString&, role)); | 577 | Q_ARG(const QString&, role)); |
| 578 | return result; | 578 | return result; |
| 579 | } | 579 | } |
| @@ -590,7 +590,7 @@ AnimationDetails MyAvatar::getAnimationDetails(const QString& url) { · 10 unmodified lines | |||
| 590 | AnimationDetails result; | 590 | AnimationDetails result; |
| 591 | if (QThread::currentThread() != thread()) { | 591 | if (QThread::currentThread() != thread()) { |
| 592 | QMetaObject::invokeMethod(this, "getAnimationDetails", Qt::BlockingQueuedConnection, | 592 | QMetaObject::invokeMethod(this, "getAnimationDetails", Qt::BlockingQueuedConnection, |
| 593 | Q_RETURN_ARG(AnimationDetails, result), | 593 | Q_RETURN_ARG(AnimationDetails, result), |
| 594 | Q_ARG(const QString&, url)); | 594 | Q_ARG(const QString&, url)); |
| 595 | return result; | 595 | return result; |
| 596 | } | 596 | } |
| @@ -638,7 +638,7 @@ void MyAvatar::saveData() { · 41 unmodified lines | |||
| 638 | settings.setValue("scale", attachment.scale); | 638 | settings.setValue("scale", attachment.scale); |
| 639 | } | 639 | } |
| 640 | settings.endArray(); | 640 | settings.endArray(); |
| 641 | 641 | ||
| 642 | settings.beginWriteArray("animationHandles"); | 642 | settings.beginWriteArray("animationHandles"); |
| 643 | for (int i = 0; i < _animationHandles.size(); i++) { | 643 | for (int i = 0; i < _animationHandles.size(); i++) { |
| 644 | settings.setArrayIndex(i); | 644 | settings.setArrayIndex(i); |
| @@ -655,7 +655,7 @@ void MyAvatar::saveData() { · 10 unmodified lines | |||
| 655 | settings.setValue("maskedJoints", pointer->getMaskedJoints()); | 655 | settings.setValue("maskedJoints", pointer->getMaskedJoints()); |
| 656 | } | 656 | } |
| 657 | settings.endArray(); | 657 | settings.endArray(); |
| 658 | 658 | ||
| 659 | settings.setValue("displayName", _displayName); | 659 | settings.setValue("displayName", _displayName); |
| 660 | 660 | ||
| 661 | settings.endGroup(); | 661 | settings.endGroup(); |
| @@ -681,7 +681,7 @@ void MyAvatar::loadData() { · 19 unmodified lines | |||
| 681 | _targetScale = loadSetting(settings, "scale", 1.0f); | 681 | _targetScale = loadSetting(settings, "scale", 1.0f); |
| 682 | setScale(_scale); | 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 | // for their avatar, So we need to attempt to detect this old case and set our new preferences accordingly. If | 685 | // for their avatar, So we need to attempt to detect this old case and set our new preferences accordingly. If |
| 686 | // the head URL is empty, then we will assume they are using a full url... | 686 | // the head URL is empty, then we will assume they are using a full url... |
| 687 | bool isOldSettings = !(settings.contains("useFullAvatar") || settings.contains("fullAvatarURL")); | 687 | bool isOldSettings = !(settings.contains("useFullAvatar") || settings.contains("fullAvatarURL")); |
| @@ -693,7 +693,7 @@ void MyAvatar::loadData() { · 5 unmodified lines | |||
| 693 | _headModelName = settings.value("headModelName", DEFAULT_HEAD_MODEL_NAME).toString(); | 693 | _headModelName = settings.value("headModelName", DEFAULT_HEAD_MODEL_NAME).toString(); |
| 694 | _bodyModelName = settings.value("bodyModelName", DEFAULT_BODY_MODEL_NAME).toString(); | 694 | _bodyModelName = settings.value("bodyModelName", DEFAULT_BODY_MODEL_NAME).toString(); |
| 695 | _fullAvatarModelName = settings.value("fullAvatarModelName", DEFAULT_FULL_AVATAR_MODEL_NAME).toString(); | 695 | _fullAvatarModelName = settings.value("fullAvatarModelName", DEFAULT_FULL_AVATAR_MODEL_NAME).toString(); |
| 696 | 696 | ||
| 697 | if (isOldSettings) { | 697 | if (isOldSettings) { |
| 698 | bool assumeFullAvatar = _headURLFromPreferences.isEmpty(); | 698 | bool assumeFullAvatar = _headURLFromPreferences.isEmpty(); |
| 699 | _useFullAvatar = assumeFullAvatar; | 699 | _useFullAvatar = assumeFullAvatar; |
| @@ -719,14 +719,14 @@ void MyAvatar::loadData() { · 19 unmodified lines | |||
| 719 | QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString()); | 719 | QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString()); |
| 720 | _bodyModelName = bodyFST["name"].toString(); | 720 | _bodyModelName = bodyFST["name"].toString(); |
| 721 | } | 721 | } |
| 722 | 722 | ||
| 723 | if (_headURLFromPreferences == DEFAULT_HEAD_MODEL_URL) { | 723 | if (_headURLFromPreferences == DEFAULT_HEAD_MODEL_URL) { |
| 724 | _headModelName = DEFAULT_HEAD_MODEL_NAME; | 724 | _headModelName = DEFAULT_HEAD_MODEL_NAME; |
| 725 | } else { | 725 | } else { |
| 726 | QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString()); | 726 | QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString()); |
| 727 | _headModelName = headFST["name"].toString(); | 727 | _headModelName = headFST["name"].toString(); |
| 728 | } | 728 | } |
| 729 | 729 | ||
| 730 | _fullAvatarModelName = "Default"; | 730 | _fullAvatarModelName = "Default"; |
| 731 | } | 731 | } |
| 732 | } | 732 | } |
| @@ -736,7 +736,7 @@ void MyAvatar::loadData() { · 3 unmodified lines | |||
| 736 | } else { | 736 | } else { |
| 737 | useHeadAndBodyURLs(_headURLFromPreferences, _skeletonURLFromPreferences, _headModelName, _bodyModelName); | 737 | useHeadAndBodyURLs(_headURLFromPreferences, _skeletonURLFromPreferences, _headModelName, _bodyModelName); |
| 738 | } | 738 | } |
| 739 | 739 | ||
| 740 | QVector<AttachmentData> attachmentData; | 740 | QVector<AttachmentData> attachmentData; |
| 741 | int attachmentCount = settings.beginReadArray("attachmentData"); | 741 | int attachmentCount = settings.beginReadArray("attachmentData"); |
| 742 | for (int i = 0; i < attachmentCount; i++) { | 742 | for (int i = 0; i < attachmentCount; i++) { |
| @@ -757,7 +757,7 @@ void MyAvatar::loadData() { · 14 unmodified lines | |||
| 757 | } | 757 | } |
| 758 | settings.endArray(); | 758 | settings.endArray(); |
| 759 | setAttachmentData(attachmentData); | 759 | setAttachmentData(attachmentData); |
| 760 | 760 | ||
| 761 | int animationCount = settings.beginReadArray("animationHandles"); | 761 | int animationCount = settings.beginReadArray("animationHandles"); |
| 762 | while (_animationHandles.size() > animationCount) { | 762 | while (_animationHandles.size() > animationCount) { |
| 763 | _animationHandles.takeLast()->stop(); | 763 | _animationHandles.takeLast()->stop(); |
| @@ -780,7 +780,7 @@ void MyAvatar::loadData() { · 16 unmodified lines | |||
| 780 | handle->setStartAutomatically(settings.value("startAutomatically", true).toBool()); | 780 | handle->setStartAutomatically(settings.value("startAutomatically", true).toBool()); |
| 781 | } | 781 | } |
| 782 | settings.endArray(); | 782 | settings.endArray(); |
| 783 | 783 | ||
| 784 | setDisplayName(settings.value("displayName").toString()); | 784 | setDisplayName(settings.value("displayName").toString()); |
| 785 | 785 | ||
| 786 | settings.endGroup(); | 786 | settings.endGroup(); |
| @@ -792,7 +792,7 @@ void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const { · 5 unmodified lines | |||
| 792 | settings.beginGroup(_skeletonModel.getURL().toString()); | 792 | settings.beginGroup(_skeletonModel.getURL().toString()); |
| 793 | settings.beginGroup(attachment.modelURL.toString()); | 793 | settings.beginGroup(attachment.modelURL.toString()); |
| 794 | settings.setValue("jointName", attachment.jointName); | 794 | settings.setValue("jointName", attachment.jointName); |
| 795 | 795 | ||
| 796 | settings.beginGroup(attachment.jointName); | 796 | settings.beginGroup(attachment.jointName); |
| 797 | settings.setValue("translation_x", attachment.translation.x); | 797 | settings.setValue("translation_x", attachment.translation.x); |
| 798 | settings.setValue("translation_y", attachment.translation.y); | 798 | settings.setValue("translation_y", attachment.translation.y); |
| @@ -802,7 +802,7 @@ void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const { · 3 unmodified lines | |||
| 802 | settings.setValue("rotation_y", eulers.y); | 802 | settings.setValue("rotation_y", eulers.y); |
| 803 | settings.setValue("rotation_z", eulers.z); | 803 | settings.setValue("rotation_z", eulers.z); |
| 804 | settings.setValue("scale", attachment.scale); | 804 | settings.setValue("scale", attachment.scale); |
| 805 | 805 | ||
| 806 | settings.endGroup(); | 806 | settings.endGroup(); |
| 807 | settings.endGroup(); | 807 | settings.endGroup(); |
| 808 | settings.endGroup(); | 808 | settings.endGroup(); |
| @@ -814,7 +814,7 @@ AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString& · 5 unmodified lines | |||
| 814 | settings.beginGroup("savedAttachmentData"); | 814 | settings.beginGroup("savedAttachmentData"); |
| 815 | settings.beginGroup(_skeletonModel.getURL().toString()); | 815 | settings.beginGroup(_skeletonModel.getURL().toString()); |
| 816 | settings.beginGroup(modelURL.toString()); | 816 | settings.beginGroup(modelURL.toString()); |
| 817 | 817 | ||
| 818 | AttachmentData attachment; | 818 | AttachmentData attachment; |
| 819 | attachment.modelURL = modelURL; | 819 | attachment.modelURL = modelURL; |
| 820 | if (jointName.isEmpty()) { | 820 | if (jointName.isEmpty()) { |
| @@ -836,18 +836,18 @@ AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString& · 15 unmodified lines | |||
| 836 | } else { | 836 | } else { |
| 837 | attachment = AttachmentData(); | 837 | attachment = AttachmentData(); |
| 838 | } | 838 | } |
| 839 | 839 | ||
| 840 | settings.endGroup(); | 840 | settings.endGroup(); |
| 841 | settings.endGroup(); | 841 | settings.endGroup(); |
| 842 | settings.endGroup(); | 842 | settings.endGroup(); |
| 843 | settings.endGroup(); | 843 | settings.endGroup(); |
| 844 | 844 | ||
| 845 | return attachment; | 845 | return attachment; |
| 846 | } | 846 | } |
| 847 | 847 | ||
| 848 | int MyAvatar::parseDataAtOffset(const QByteArray& packet, int offset) { | 848 | int MyAvatar::parseDataAtOffset(const QByteArray& packet, int offset) { |
| 849 | qCDebug(interfaceapp) << "Error: ignoring update packet for MyAvatar" | 849 | qCDebug(interfaceapp) << "Error: ignoring update packet for MyAvatar" |
| 850 | << " packetLength = " << packet.size() | 850 | << " packetLength = " << packet.size() |
| 851 | << " offset = " << offset; | 851 | << " offset = " << offset; |
| 852 | // this packet is just bad, so we pretend that we unpacked it ALL | 852 | // this packet is just bad, so we pretend that we unpacked it ALL |
| 853 | return packet.size() - offset; | 853 | return packet.size() - offset; |
| @@ -865,14 +865,14 @@ void MyAvatar::updateLookAtTargetAvatar() { · 11 unmodified lines | |||
| 865 | // | 865 | // |
| 866 | _lookAtTargetAvatar.reset(); | 866 | _lookAtTargetAvatar.reset(); |
| 867 | _targetAvatarPosition = glm::vec3(0.0f); | 867 | _targetAvatarPosition = glm::vec3(0.0f); |
| 868 | 868 | ||
| 869 | glm::vec3 lookForward = getHead()->getFinalOrientationInWorldFrame() * IDENTITY_FRONT; | 869 | glm::vec3 lookForward = getHead()->getFinalOrientationInWorldFrame() * IDENTITY_FRONT; |
| 870 | glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition(); | 870 | glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition(); |
| 871 | 871 | ||
| 872 | float smallestAngleTo = glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES) / 2.0f; | 872 | float smallestAngleTo = glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES) / 2.0f; |
| 873 | const float KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR = 1.3f; | 873 | const float KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR = 1.3f; |
| 874 | const float GREATEST_LOOKING_AT_DISTANCE = 10.0f; | 874 | const float GREATEST_LOOKING_AT_DISTANCE = 10.0f; |
| 875 | 875 | ||
| 876 | int howManyLookingAtMe = 0; | 876 | int howManyLookingAtMe = 0; |
| 877 | foreach (const AvatarSharedPointer& avatarPointer, DependencyManager::get<AvatarManager>()->getAvatarHash()) { | 877 | foreach (const AvatarSharedPointer& avatarPointer, DependencyManager::get<AvatarManager>()->getAvatarHash()) { |
| 878 | Avatar* avatar = static_cast<Avatar*>(avatarPointer.get()); | 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 | _useFullAvatar = true; | 1006 | _useFullAvatar = true; |
| 1007 | 1007 | ||
| 1008 | if (_fullAvatarURLFromPreferences != fullAvatarURL) { | 1008 | if (_fullAvatarURLFromPreferences != fullAvatarURL) { |
| 1009 | _fullAvatarURLFromPreferences = fullAvatarURL; | 1009 | _fullAvatarURLFromPreferences = fullAvatarURL; |
| 1010 | if (modelName.isEmpty()) { | 1010 | if (modelName.isEmpty()) { |
| 1011 | QVariantHash fullAvatarFST = FSTReader::downloadMapping(_fullAvatarURLFromPreferences.toString()); | 1011 | QVariantHash fullAvatarFST = FSTReader::downloadMapping(_fullAvatarURLFromPreferences.toString()); |
| 1012 | _fullAvatarModelName = fullAvatarFST["name"].toString(); | 1012 | _fullAvatarModelName = fullAvatarFST["name"].toString(); |
| 1013 | } else { | 1013 | } else { |
| 1014 | _fullAvatarModelName = modelName; | 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 | if (headName.isEmpty()) { | 1051 | if (headName.isEmpty()) { |
| 1052 | QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString()); | 1052 | QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString()); |
| 1053 | _headModelName = headFST["name"].toString(); | 1053 | _headModelName = headFST["name"].toString(); |
| 1054 | } else { | 1054 | } else { |
| 1055 | _headModelName = headName; | 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 | if (bodyName.isEmpty()) { | 1061 | if (bodyName.isEmpty()) { |
| 1062 | QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString()); | 1062 | QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString()); |
| 1063 | _bodyModelName = bodyFST["name"].toString(); | 1063 | _bodyModelName = bodyFST["name"].toString(); |
| 1064 | } else { | 1064 | } else { |
| 1065 | _bodyModelName = bodyName; | 1065 | _bodyModelName = bodyName; |
| 1066 | } | 1066 | } |
| 1067 | } | 1067 | } |
| @@ -1092,7 +1092,7 @@ void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) · 24 unmodified lines | |||
| 1092 | glm::vec3 MyAvatar::getSkeletonPosition() const { | 1092 | glm::vec3 MyAvatar::getSkeletonPosition() const { |
| 1093 | CameraMode mode = Application::getInstance()->getCamera()->getMode(); | 1093 | CameraMode mode = Application::getInstance()->getCamera()->getMode(); |
| 1094 | if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) { | 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 | // to get the skeleton offset contribution in the world-frame. | 1096 | // to get the skeleton offset contribution in the world-frame. |
| 1097 | const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); | 1097 | const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); |
| 1098 | glm::vec3 skeletonOffset = _skeletonOffset; | 1098 | glm::vec3 skeletonOffset = _skeletonOffset; |
| @@ -1135,9 +1135,9 @@ void MyAvatar::setScriptedMotorVelocity(const glm::vec3& velocity) { · 36 unmodified lines | |||
| 1135 | } | 1135 | } |
| 1136 | 1136 | ||
| 1137 | void MyAvatar::setScriptedMotorTimescale(float timescale) { | 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 | // obnoxiously large values from introducing NaN into avatar's velocity | 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 | DEFAULT_SCRIPTED_MOTOR_TIMESCALE); | 1141 | DEFAULT_SCRIPTED_MOTOR_TIMESCALE); |
| 1142 | } | 1142 | } |
| 1143 | 1143 | ||
| @@ -1155,14 +1155,14 @@ void MyAvatar::clearScriptableSettings() { · 11 unmodified lines | |||
| 1155 | clearJointAnimationPriorities(); | 1155 | clearJointAnimationPriorities(); |
| 1156 | _scriptedMotorVelocity = glm::vec3(0.0f); | 1156 | _scriptedMotorVelocity = glm::vec3(0.0f); |
| 1157 | _scriptedMotorTimescale = DEFAULT_SCRIPTED_MOTOR_TIMESCALE; | 1157 | _scriptedMotorTimescale = DEFAULT_SCRIPTED_MOTOR_TIMESCALE; |
| 1158 | } | 1158 | } |
| 1159 | 1159 | ||
| 1160 | void MyAvatar::attach(const QString& modelURL, const QString& jointName, const glm::vec3& translation, | 1160 | void MyAvatar::attach(const QString& modelURL, const QString& jointName, const glm::vec3& translation, |
| 1161 | const glm::quat& rotation, float scale, bool allowDuplicates, bool useSaved) { | 1161 | const glm::quat& rotation, float scale, bool allowDuplicates, bool useSaved) { |
| 1162 | if (QThread::currentThread() != thread()) { | 1162 | if (QThread::currentThread() != thread()) { |
| 1163 | Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved); | 1163 | Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved); |
| 1164 | return; | 1164 | return; |
| 1165 | } | 1165 | } |
| 1166 | if (useSaved) { | 1166 | if (useSaved) { |
| 1167 | AttachmentData attachment = loadAttachmentData(modelURL, jointName); | 1167 | AttachmentData attachment = loadAttachmentData(modelURL, jointName); |
| 1168 | if (attachment.isValid()) { | 1168 | if (attachment.isValid()) { |
| @@ -1199,7 +1199,7 @@ const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f; · 30 unmodified lines | |||
| 1199 | 1199 | ||
| 1200 | bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const { | 1200 | bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const { |
| 1201 | const Head* head = getHead(); | 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 | (glm::length(cameraPosition - head->getEyePosition()) > RENDER_HEAD_CUTOFF_DISTANCE * _scale); | 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 | //Invert yaw and roll when in mirror mode | 1231 | //Invert yaw and roll when in mirror mode |
| 1232 | if (Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_MIRROR) { | 1232 | if (Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_MIRROR) { |
| 1233 | YAW(euler) *= -1.0; | 1233 | YAW(euler) *= -1.0f; |
| 1234 | ROLL(euler) *= -1.0; | 1234 | ROLL(euler) *= -1.0f; |
| 1235 | } | 1235 | } |
| 1236 | 1236 | ||
| 1237 | Head* head = getHead(); | 1237 | Head* head = getHead(); |
| 1238 | head->setBaseYaw(YAW(euler)); | 1238 | head->setBaseYaw(YAW(euler)); |
| 1239 | head->setBasePitch(PITCH(euler)); | 1239 | head->setBasePitch(PITCH(euler)); |
| @@ -1246,9 +1246,9 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe · 6 unmodified lines | |||
| 1246 | return localVelocity; | 1246 | return localVelocity; |
| 1247 | } | 1247 | } |
| 1248 | // compute motor efficiency | 1248 | // compute motor efficiency |
| 1249 | // The timescale of the motor is the approximate time it takes for the motor to | 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, | 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 | 1251 | // and a long timescale makes it weak. The value of timescale to use depends |
| 1252 | // on what the motor is doing: | 1252 | // on what the motor is doing: |
| 1253 | // | 1253 | // |
| 1254 | // (1) braking --> short timescale (aggressive motor assertion) | 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 | float MIN_KEYBOARD_BRAKE_SPEED = 0.3f; | 1259 | float MIN_KEYBOARD_BRAKE_SPEED = 0.3f; |
| 1260 | float timescale = MAX_KEYBOARD_MOTOR_TIMESCALE; | 1260 | float timescale = MAX_KEYBOARD_MOTOR_TIMESCALE; |
| 1261 | bool isThrust = (glm::length2(_thrust) > EPSILON); | 1261 | bool isThrust = (glm::length2(_thrust) > EPSILON); |
| 1262 | if (_isPushing || isThrust || | 1262 | if (_isPushing || isThrust || |
| 1263 | (_scriptedMotorTimescale < MAX_KEYBOARD_MOTOR_TIMESCALE && | 1263 | (_scriptedMotorTimescale < MAX_KEYBOARD_MOTOR_TIMESCALE && |
| 1264 | _motionBehaviors | AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED)) { | 1264 | _motionBehaviors | AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED)) { |
| 1265 | // we don't want to brake if something is pushing the avatar around | 1265 | // we don't want to brake if something is pushing the avatar around |
| 1266 | timescale = _keyboardMotorTimescale; | 1266 | timescale = _keyboardMotorTimescale; |
| @@ -1277,18 +1277,18 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe · 10 unmodified lines | |||
| 1277 | float motorEfficiency = glm::clamp(deltaTime / timescale, 0.0f, 1.0f); | 1277 | float motorEfficiency = glm::clamp(deltaTime / timescale, 0.0f, 1.0f); |
| 1278 | 1278 | ||
| 1279 | glm::vec3 newLocalVelocity = localVelocity; | 1279 | glm::vec3 newLocalVelocity = localVelocity; |
| 1280 | float keyboardInput = fabsf(_driveKeys[FWD] - _driveKeys[BACK]) + | 1280 | float keyboardInput = fabsf(_driveKeys[FWD] - _driveKeys[BACK]) + |
| 1281 | (fabsf(_driveKeys[RIGHT] - _driveKeys[LEFT])) + | 1281 | (fabsf(_driveKeys[RIGHT] - _driveKeys[LEFT])) + |
| 1282 | fabsf(_driveKeys[UP] - _driveKeys[DOWN]); | 1282 | fabsf(_driveKeys[UP] - _driveKeys[DOWN]); |
| 1283 | if (keyboardInput) { | 1283 | if (keyboardInput) { |
| 1284 | // Compute keyboard input | 1284 | // Compute keyboard input |
| 1285 | glm::vec3 front = (_driveKeys[FWD] - _driveKeys[BACK]) * IDENTITY_FRONT; | 1285 | glm::vec3 front = (_driveKeys[FWD] - _driveKeys[BACK]) * IDENTITY_FRONT; |
| 1286 | glm::vec3 right = (_driveKeys[RIGHT] - _driveKeys[LEFT]) * IDENTITY_RIGHT; | 1286 | glm::vec3 right = (_driveKeys[RIGHT] - _driveKeys[LEFT]) * IDENTITY_RIGHT; |
| 1287 | glm::vec3 up = (_driveKeys[UP] - _driveKeys[DOWN]) * IDENTITY_UP; | 1287 | glm::vec3 up = (_driveKeys[UP] - _driveKeys[DOWN]) * IDENTITY_UP; |
| 1288 | 1288 | ||
| 1289 | glm::vec3 direction = front + right + up; | 1289 | glm::vec3 direction = front + right + up; |
| 1290 | float directionLength = glm::length(direction); | 1290 | float directionLength = glm::length(direction); |
| 1291 | 1291 | ||
| 1292 | // Compute motor magnitude | 1292 | // Compute motor magnitude |
| 1293 | if (directionLength > EPSILON) { | 1293 | if (directionLength > EPSILON) { |
| 1294 | direction /= directionLength; | 1294 | direction /= directionLength; |
| @@ -1318,7 +1318,7 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe · 23 unmodified lines | |||
| 1318 | motorEfficiency = glm::clamp(deltaTime / WALK_ACCELERATION_TIMESCALE, 0.0f, 1.0f); | 1318 | motorEfficiency = glm::clamp(deltaTime / WALK_ACCELERATION_TIMESCALE, 0.0f, 1.0f); |
| 1319 | } | 1319 | } |
| 1320 | _isPushing = true; | 1320 | _isPushing = true; |
| 1321 | } | 1321 | } |
| 1322 | newLocalVelocity = localVelocity + motorEfficiency * (_keyboardMotorVelocity - localVelocity); | 1322 | newLocalVelocity = localVelocity + motorEfficiency * (_keyboardMotorVelocity - localVelocity); |
| 1323 | } else { | 1323 | } else { |
| 1324 | _keyboardMotorVelocity = glm::vec3(0.0f); | 1324 | _keyboardMotorVelocity = glm::vec3(0.0f); |
| @@ -1382,13 +1382,13 @@ void MyAvatar::updatePosition(float deltaTime) { · 57 unmodified lines | |||
| 1382 | _targetVelocity *= MAX_AVATAR_SPEED / speed; | 1382 | _targetVelocity *= MAX_AVATAR_SPEED / speed; |
| 1383 | speed = MAX_AVATAR_SPEED; | 1383 | speed = MAX_AVATAR_SPEED; |
| 1384 | } | 1384 | } |
| 1385 | 1385 | ||
| 1386 | if (speed > MIN_AVATAR_SPEED && !_characterController.isEnabled()) { | 1386 | if (speed > MIN_AVATAR_SPEED && !_characterController.isEnabled()) { |
| 1387 | // update position ourselves | 1387 | // update position ourselves |
| 1388 | applyPositionDelta(deltaTime * _targetVelocity); | 1388 | applyPositionDelta(deltaTime * _targetVelocity); |
| 1389 | measureMotionDerivatives(deltaTime); | 1389 | measureMotionDerivatives(deltaTime); |
| 1390 | } // else physics will move avatar later | 1390 | } // else physics will move avatar later |
| 1391 | 1391 | ||
| 1392 | // update _moving flag based on speed | 1392 | // update _moving flag based on speed |
| 1393 | const float MOVING_SPEED_THRESHOLD = 0.01f; | 1393 | const float MOVING_SPEED_THRESHOLD = 0.01f; |
| 1394 | _moving = speed > MOVING_SPEED_THRESHOLD; | 1394 | _moving = speed > MOVING_SPEED_THRESHOLD; |
| @@ -1405,7 +1405,7 @@ bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float · 10 unmodified lines | |||
| 1405 | float xzDistance = sqrt(positionBA.x * positionBA.x + positionBA.z * positionBA.z); | 1405 | float xzDistance = sqrt(positionBA.x * positionBA.x + positionBA.z * positionBA.z); |
| 1406 | if (xzDistance < (radiusA + radiusB)) { | 1406 | if (xzDistance < (radiusA + radiusB)) { |
| 1407 | float yDistance = fabs(positionBA.y); | 1407 | float yDistance = fabs(positionBA.y); |
| 1408 | float halfHeights = 0.5 * (heightA + heightB); | 1408 | float halfHeights = 0.5f * (heightA + heightB); |
| 1409 | if (yDistance < halfHeights) { | 1409 | if (yDistance < halfHeights) { |
| 1410 | // cylinders collide | 1410 | // cylinders collide |
| 1411 | if (xzDistance > 0.0f) { | 1411 | if (xzDistance > 0.0f) { |
| @@ -1448,60 +1448,60 @@ void MyAvatar::maybeUpdateBillboard() { · 36 unmodified lines | |||
| 1448 | } | 1448 | } |
| 1449 | gpu::Context context(new gpu::GLBackend()); | 1449 | gpu::Context context(new gpu::GLBackend()); |
| 1450 | RenderArgs renderArgs(&context); | 1450 | RenderArgs renderArgs(&context); |
| 1451 | QImage image = Application::getInstance()->renderAvatarBillboard(&renderArgs); | 1451 | QImage image = qApp->renderAvatarBillboard(&renderArgs); |
| 1452 | _billboard.clear(); | 1452 | _billboard.clear(); |
| 1453 | QBuffer buffer(&_billboard); | 1453 | QBuffer buffer(&_billboard); |
| 1454 | buffer.open(QIODevice::WriteOnly); | 1454 | buffer.open(QIODevice::WriteOnly); |
| 1455 | image.save(&buffer, "PNG"); | 1455 | image.save(&buffer, "PNG"); |
| 1456 | _billboardValid = true; | 1456 | _billboardValid = true; |
| 1457 | 1457 | ||
| 1458 | sendBillboardPacket(); | 1458 | sendBillboardPacket(); |
| 1459 | } | 1459 | } |
| 1460 | 1460 | ||
| 1461 | void MyAvatar::increaseSize() { | 1461 | void MyAvatar::increaseSize() { |
| 1462 | if ((1.0f + SCALING_RATIO) * _targetScale < MAX_AVATAR_SCALE) { | 1462 | if ((1.0f + SCALING_RATIO) * _targetScale < MAX_AVATAR_SCALE) { |
| 1463 | _targetScale *= (1.0f + SCALING_RATIO); | 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 | void MyAvatar::decreaseSize() { | 1468 | void MyAvatar::decreaseSize() { |
| 1469 | if (MIN_AVATAR_SCALE < (1.0f - SCALING_RATIO) * _targetScale) { | 1469 | if (MIN_AVATAR_SCALE < (1.0f - SCALING_RATIO) * _targetScale) { |
| 1470 | _targetScale *= (1.0f - SCALING_RATIO); | 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 | void MyAvatar::resetSize() { | 1475 | void MyAvatar::resetSize() { |
| 1476 | _targetScale = 1.0f; | 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 | void MyAvatar::goToLocation(const glm::vec3& newPosition, | 1480 | void MyAvatar::goToLocation(const glm::vec3& newPosition, |
| 1481 | bool hasOrientation, const glm::quat& newOrientation, | 1481 | bool hasOrientation, const glm::quat& newOrientation, |
| 1482 | bool shouldFaceLocation) { | 1482 | bool shouldFaceLocation) { |
| 1483 | 1483 | ||
| 1484 | qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - moving to " << newPosition.x << ", " | 1484 | qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - moving to " << newPosition.x << ", " |
| 1485 | << newPosition.y << ", " << newPosition.z; | 1485 | << newPosition.y << ", " << newPosition.z; |
| 1486 | 1486 | ||
| 1487 | glm::vec3 shiftedPosition = newPosition; | 1487 | glm::vec3 shiftedPosition = newPosition; |
| 1488 | 1488 | ||
| 1489 | if (hasOrientation) { | 1489 | if (hasOrientation) { |
| 1490 | qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - new orientation is " | 1490 | qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - new orientation is " |
| 1491 | << newOrientation.x << ", " << newOrientation.y << ", " << newOrientation.z << ", " << newOrientation.w; | 1491 | << newOrientation.x << ", " << newOrientation.y << ", " << newOrientation.z << ", " << newOrientation.w; |
| 1492 | 1492 | ||
| 1493 | // orient the user to face the target | 1493 | // orient the user to face the target |
| 1494 | glm::quat quatOrientation = newOrientation; | 1494 | glm::quat quatOrientation = newOrientation; |
| 1495 | 1495 | ||
| 1496 | if (shouldFaceLocation) { | 1496 | if (shouldFaceLocation) { |
| 1497 | 1497 | ||
| 1498 | quatOrientation = newOrientation * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); | 1498 | quatOrientation = newOrientation * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); |
| 1499 | 1499 | ||
| 1500 | // move the user a couple units away | 1500 | // move the user a couple units away |
| 1501 | const float DISTANCE_TO_USER = 2.0f; | 1501 | const float DISTANCE_TO_USER = 2.0f; |
| 1502 | shiftedPosition = newPosition - quatOrientation * IDENTITY_FRONT * DISTANCE_TO_USER; | 1502 | shiftedPosition = newPosition - quatOrientation * IDENTITY_FRONT * DISTANCE_TO_USER; |
| 1503 | } | 1503 | } |
| 1504 | 1504 | ||
| 1505 | setOrientation(quatOrientation); | 1505 | setOrientation(quatOrientation); |
| 1506 | } | 1506 | } |
| 1507 | 1507 | ||
| @@ -1547,7 +1547,6 @@ void MyAvatar::renderLaserPointers() { · 39 unmodified lines | |||
| 1547 | 1547 | ||
| 1548 | //Gets the tip position for the laser pointer | 1548 | //Gets the tip position for the laser pointer |
| 1549 | glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) { | 1549 | glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) { |
| 1550 | const ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay(); | ||
| 1551 | glm::vec3 direction = glm::normalize(palm->getTipPosition() - palm->getPosition()); | 1550 | glm::vec3 direction = glm::normalize(palm->getTipPosition() - palm->getPosition()); |
| 1552 | 1551 | ||
| 1553 | glm::vec3 position = palm->getPosition(); | 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 | glm::vec3 result; | 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 | return result; | 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 | if (_driveKeys[UP] > 0.0f) { | 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 | void relayDriveKeysToCharacterController(); | 91 | void relayDriveKeysToCharacterController(); |
| 92 | 92 | ||
| 93 | bool isMyAvatar() { return true; } | 93 | bool isMyAvatar() const { return true; } |
| 94 | 94 | ||
| 95 | bool isLookingAtLeftEye(); | 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 | float browUp = _coefficients[_browUpCenterIndex]; | 415 | float browUp = _coefficients[_browUpCenterIndex]; |
| 416 | if (isFiltering) { | 416 | if (isFiltering) { |
| 417 | const float BROW_VELOCITY_FILTER_STRENGTH = 0.5f; | 417 | const float BROW_VELOCITY_FILTER_STRENGTH = 0.5f; |
| 418 | float velocity = fabs(browUp - _lastBrowUp) / _averageMessageTime; | 418 | float velocity = fabsf(browUp - _lastBrowUp) / _averageMessageTime; |
| 419 | float velocityFilter = glm::clamp(velocity * BROW_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f); | 419 | float velocityFilter = glm::clamp(velocity * BROW_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f); |
| 420 | _filteredBrowUp = velocityFilter * browUp + (1.0f - velocityFilter) * _filteredBrowUp; | 420 | _filteredBrowUp = velocityFilter * browUp + (1.0f - velocityFilter) * _filteredBrowUp; |
| 421 | _lastBrowUp = browUp; | 421 | _lastBrowUp = browUp; |
| @@ -438,11 +438,12 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { · 16 unmodified lines | |||
| 438 | 438 | ||
| 439 | // Velocity filter EyeBlink values | 439 | // Velocity filter EyeBlink values |
| 440 | const float DDE_EYEBLINK_SCALE = 3.0f; | 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 | if (isFiltering) { | 443 | if (isFiltering) { |
| 443 | const float BLINK_VELOCITY_FILTER_STRENGTH = 0.3f; | 444 | const float BLINK_VELOCITY_FILTER_STRENGTH = 0.3f; |
| 444 | for (int i = 0; i < 2; i++) { | 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 | float velocityFilter = glm::clamp(velocity * BLINK_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f); | 447 | float velocityFilter = glm::clamp(velocity * BLINK_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f); |
| 447 | _filteredEyeBlinks[i] = velocityFilter * eyeBlinks[i] + (1.0f - velocityFilter) * _filteredEyeBlinks[i]; | 448 | _filteredEyeBlinks[i] = velocityFilter * eyeBlinks[i] + (1.0f - velocityFilter) * _filteredEyeBlinks[i]; |
| 448 | _lastEyeBlinks[i] = eyeBlinks[i]; | 449 | _lastEyeBlinks[i] = eyeBlinks[i]; |
| @@ -479,9 +480,9 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { · 30 unmodified lines | |||
| 479 | if (_eyeStates[i] == EYE_CLOSING) { | 480 | if (_eyeStates[i] == EYE_CLOSING) { |
| 480 | // Close eyelid until it's fully closed | 481 | // Close eyelid until it's fully closed |
| 481 | float closingValue = _lastEyeCoefficients[i] + EYELID_MOVEMENT_RATE * _averageMessageTime; | 482 | float closingValue = _lastEyeCoefficients[i] + EYELID_MOVEMENT_RATE * _averageMessageTime; |
| 482 | if (closingValue >= 1.0) { | 483 | if (closingValue >= 1.0f) { |
| 483 | _eyeStates[i] = EYE_CLOSED; | 484 | _eyeStates[i] = EYE_CLOSED; |
| 484 | eyeCoefficients[i] = 1.0; | 485 | eyeCoefficients[i] = 1.0f; |
| 485 | } else { | 486 | } else { |
| 486 | eyeCoefficients[i] = closingValue; | 487 | eyeCoefficients[i] = closingValue; |
| 487 | } | 488 | } |
| @@ -11,13 +11,13 @@ · 10 unmodified lines | |||
| 11 | // | 11 | // |
| 12 | 12 | ||
| 13 | #include "InterfaceConfig.h" | 13 | #include "InterfaceConfig.h" |
| 14 | |||
| 15 | #include "OculusManager.h" | 14 | #include "OculusManager.h" |
| 16 | #include "ui/overlays/Text3DOverlay.h" | 15 | #include "ui/overlays/Text3DOverlay.h" |
| 17 | 16 | ||
| 17 | #include <CursorManager.h> | ||
| 18 | #include <QDesktopWidget> | 18 | #include <QDesktopWidget> |
| 19 | #include <QGuiApplication> | 19 | #include <QGuiApplication> |
| 20 | #include <QScreen> | 20 | #include <QScreen> |
| 21 | #include <QOpenGLTimerQuery> | 21 | #include <QOpenGLTimerQuery> |
| 22 | 22 | ||
| 23 | #include <glm/glm.hpp> | 23 | #include <glm/glm.hpp> |
| @@ -25,6 +25,9 @@ · 1 unmodified line | |||
| 25 | #include <avatar/AvatarManager.h> | 25 | #include <avatar/AvatarManager.h> |
| 26 | #include <avatar/MyAvatar.h> | 26 | #include <avatar/MyAvatar.h> |
| 27 | #include <GlowEffect.h> | 27 | #include <GlowEffect.h> |
| 28 | #include <GlWindow.h> | ||
| 29 | #include <gpu/GLBackend.h> | ||
| 30 | #include <OglplusHelpers.h> | ||
| 28 | #include <PathUtils.h> | 31 | #include <PathUtils.h> |
| 29 | #include <SharedUtil.h> | 32 | #include <SharedUtil.h> |
| 30 | #include <UserActivityLogger.h> | 33 | #include <UserActivityLogger.h> |
| @@ -34,8 +37,6 @@ · 3 unmodified lines | |||
| 34 | #include "InterfaceLogging.h" | 37 | #include "InterfaceLogging.h" |
| 35 | #include "Application.h" | 38 | #include "Application.h" |
| 36 | 39 | ||
| 37 | #include <gpu/GLBackend.h> | ||
| 38 | |||
| 39 | template <typename Function> | 40 | template <typename Function> |
| 40 | void for_each_eye(Function function) { | 41 | void for_each_eye(Function function) { |
| 41 | for (ovrEyeType eye = ovrEyeType::ovrEye_Left; | 42 | for (ovrEyeType eye = ovrEyeType::ovrEye_Left; |
| @@ -52,202 +53,413 @@ void for_each_eye(const ovrHmd & hmd, Function function) { · 10 unmodified lines | |||
| 52 | function(eye); | 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 | 68 | inline glm::mat4 toGlm(const ovrFovPort & fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) { |
| 57 | ProgramObject OculusManager::_program; | 69 | return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true)); |
| 58 | int OculusManager::_textureLocation; | 70 | } |
| 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 | ||
| 75 | 71 | ||
| 76 | ovrTexture OculusManager::_eyeTextures[ovrEye_Count]; | 72 | inline glm::vec3 toGlm(const ovrVector3f & ov) { |
| 77 | bool OculusManager::_isConnected = false; | 73 | return glm::make_vec3(&ov.x); |
| 78 | ovrHmd OculusManager::_ovrHmd; | 74 | } |
| 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; | ||
| 107 | 75 | ||
| 76 | inline glm::vec2 toGlm(const ovrVector2f & ov) { | ||
| 77 | return glm::make_vec2(&ov.x); | ||
| 78 | } | ||
| 108 | 79 | ||
| 109 | void OculusManager::initSdk() { | 80 | inline glm::ivec2 toGlm(const ovrVector2i & ov) { |
| 110 | ovr_Initialize(); | 81 | return glm::ivec2(ov.x, ov.y); |
| 111 | _ovrHmd = ovrHmd_Create(0); | ||
| 112 | if (!_ovrHmd) { | ||
| 113 | _ovrHmd = ovrHmd_CreateDebug(ovrHmd_DK2); | ||
| 114 | } | ||
| 115 | } | 82 | } |
| 116 | 83 | ||
| 117 | void OculusManager::shutdownSdk() { | 84 | inline glm::uvec2 toGlm(const ovrSizei & ov) { |
| 118 | if (_ovrHmd) { | 85 | return glm::uvec2(ov.w, ov.h); |
| 119 | ovrHmd_Destroy(_ovrHmd); | ||
| 120 | _ovrHmd = nullptr; | ||
| 121 | ovr_Shutdown(); | ||
| 122 | } | ||
| 123 | } | 86 | } |
| 124 | 87 | ||
| 125 | void OculusManager::init() { | 88 | inline glm::quat toGlm(const ovrQuatf & oq) { |
| 126 | #ifdef OVR_DIRECT_MODE | 89 | return glm::make_quat(&oq.x); |
| 127 | initSdk(); | ||
| 128 | #endif | ||
| 129 | } | 90 | } |
| 130 | 91 | ||
| 131 | void OculusManager::deinit() { | 92 | inline glm::mat4 toGlm(const ovrPosef & op) { |
| 132 | #ifdef OVR_DIRECT_MODE | 93 | glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation)); |
| 133 | shutdownSdk(); | 94 | glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position)); |
| 134 | #endif | 95 | return translation * orientation; |
| 135 | } | 96 | } |
| 136 | 97 | ||
| 137 | void OculusManager::connect() { | 98 | inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) { |
| 138 | #ifndef OVR_DIRECT_MODE | 99 | ovrMatrix4f result; |
| 139 | initSdk(); | 100 | glm::mat4 transposed(glm::transpose(m)); |
| 140 | #endif | 101 | memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16); |
| 141 | _calibrationState = UNCALIBRATED; | 102 | return result; |
| 142 | qCDebug(interfaceapp) << "Oculus SDK" << OVR_VERSION_STRING; | 103 | } |
| 143 | if (_ovrHmd) { | 104 | |
| 144 | if (!_isConnected) { | 105 | inline ovrVector3f ovrFromGlm(const glm::vec3 & v) { |
| 145 | UserActivityLogger::getInstance().connectedDevice("hmd", "oculus"); | 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; | 165 | } |
| 148 | 166 | ||
| 149 | for_each_eye([&](ovrEyeType eye) { | 167 | void Increment() { |
| 150 | _eyeFov[eye] = _ovrHmd->DefaultEyeFov[eye]; | 168 | ++color->CurrentIndex; |
| 151 | }); | 169 | color->CurrentIndex %= color->TextureCount; |
| 152 | 170 | } | |
| 153 | ovrGLConfig cfg; | 171 | |
| 154 | memset(&cfg, 0, sizeof(cfg)); | 172 | protected: |
| 155 | cfg.OGL.Header.API = ovrRenderAPI_OpenGL; | 173 | virtual void initColor() override { |
| 156 | cfg.OGL.Header.BackBufferSize = _ovrHmd->Resolution; | 174 | if (color) { |
| 157 | cfg.OGL.Header.Multisample = 1; | 175 | ovrHmd_DestroySwapTextureSet(hmd, color); |
| 158 | 176 | color = nullptr; | |
| 159 | int distortionCaps = 0 | 177 | } |
| 160 | | ovrDistortionCap_Vignette | 178 | |
| 161 | | ovrDistortionCap_Overdrive | 179 | ovrResult result = ovrHmd_CreateSwapTextureSetGL(hmd, GL_RGBA, size.x, size.y, &color); |
| 162 | | ovrDistortionCap_TimeWarp; | 180 | Q_ASSERT(OVR_SUCCESS(result)); |
| 163 | 181 | ||
| 164 | int configResult = ovrHmd_ConfigureRendering(_ovrHmd, &cfg.Config, | 182 | for (int i = 0; i < color->TextureCount; ++i) { |
| 165 | distortionCaps, _eyeFov, _eyeRenderDesc); | 183 | ovrGLTexture& ovrTex = (ovrGLTexture&)color->Textures[i]; |
| 166 | assert(configResult); | 184 | glBindTexture(GL_TEXTURE_2D, ovrTex.OGL.TexId); |
| 167 | 185 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
| 168 | 186 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| 169 | _recommendedTexSize = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left, _eyeFov[ovrEye_Left], 1.0f); | 187 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| 170 | _renderTargetSize = { _recommendedTexSize.w * 2, _recommendedTexSize.h }; | 188 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 171 | for_each_eye([&](ovrEyeType eye) { | 189 | } |
| 172 | //Get texture size | 190 | glBindTexture(GL_TEXTURE_2D, 0); |
| 173 | _eyeTextures[eye].Header.API = ovrRenderAPI_OpenGL; | 191 | } |
| 174 | _eyeTextures[eye].Header.TextureSize = _renderTargetSize; | 192 | |
| 175 | _eyeTextures[eye].Header.RenderViewport.Pos = { 0, 0 }; | 193 | virtual void initDone() override { |
| 176 | }); | 194 | } |
| 177 | _eyeTextures[ovrEye_Right].Header.RenderViewport.Pos.x = _recommendedTexSize.w; | 195 | |
| 178 | 196 | virtual void onBind(oglplus::Framebuffer::Target target) override { | |
| 179 | ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction); | 197 | ovrGLTexture& tex = (ovrGLTexture&)(color->Textures[color->CurrentIndex]); |
| 180 | 198 | glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.OGL.TexId, 0); | |
| 181 | ovrHmd_ConfigureTracking(_ovrHmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position | | 199 | } |
| 182 | ovrTrackingCap_MagYawCorrection, | 200 | |
| 183 | ovrTrackingCap_Orientation); | 201 | virtual void onUnbind(oglplus::Framebuffer::Target target) override { |
| 184 | 202 | glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | |
| 185 | if (!_camera) { | 203 | } |
| 186 | _camera = new Camera; | 204 | }; |
| 187 | configureCamera(*_camera); // no need to use screen dimensions; they're ignored | 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 | 219 | } |
| 190 | if (!_programInitialized) { | 220 | |
| 191 | // Shader program | 221 | private: |
| 192 | _programInitialized = true; | 222 | void initColor() override { |
| 193 | _program.addShaderFromSourceFile(QGLShader::Vertex, PathUtils::resourcesPath() + "shaders/oculus.vert"); | 223 | if (color) { |
| 194 | _program.addShaderFromSourceFile(QGLShader::Fragment, PathUtils::resourcesPath() + "shaders/oculus.frag"); | 224 | ovrHmd_DestroyMirrorTexture(hmd, (ovrTexture*)color); |
| 195 | _program.link(); | 225 | color = nullptr; |
| 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"); | ||
| 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 | #endif | 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 | _isConnected = false; | 320 | _isConnected = false; |
| 217 | 321 | ||
| 218 | // we're definitely not in "VR mode" so tell the menu that | 322 | // we're definitely not in "VR mode" so tell the menu that |
| 219 | Menu::getInstance()->getActionForOption(MenuOption::EnableVRMode)->setChecked(false); | 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 | //Disconnects and deallocates the OR | 429 | //Disconnects and deallocates the OR |
| 224 | void OculusManager::disconnect() { | 430 | void OculusManager::disconnect() { |
| 225 | if (_isConnected) { | 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 | _isConnected = false; | 455 | _isConnected = false; |
| 227 | // Prepare to potentially have to dismiss the HSW again | 456 | // Prepare to potentially have to dismiss the HSW again |
| 228 | // if the user re-enables VR | 457 | // if the user re-enables VR |
| 229 | _hswDismissed = false; | 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 | MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | 463 | MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); |
| 252 | glm::quat headOrientation = myAvatar->getHeadOrientation(); | 464 | glm::quat headOrientation = myAvatar->getHeadOrientation(); |
| 253 | headOrientation.x = 0; | 465 | headOrientation.x = 0; |
| @@ -258,7 +470,7 @@ void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) { · 4 unmodified lines | |||
| 258 | billboard->setRotation(headOrientation); | 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 | static QString instructionMessage = "Hold still to calibrate"; | 474 | static QString instructionMessage = "Hold still to calibrate"; |
| 263 | static QString progressMessage; | 475 | static QString progressMessage; |
| 264 | static Text3DOverlay* billboard; | 476 | static Text3DOverlay* billboard; |
| @@ -346,7 +558,7 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { · 81 unmodified lines | |||
| 346 | break; | 558 | break; |
| 347 | default: | 559 | default: |
| 348 | break; | 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 | bool OculusManager::isConnected() { | 579 | bool OculusManager::isConnected() { |
| 423 | return _isConnected && Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode); | 580 | return _isConnected; |
| 424 | } | 581 | } |
| 425 | 582 | ||
| 426 | //Begins the frame timing for oculus prediction purposes | 583 | //Begins the frame timing for oculus prediction purposes |
| @@ -428,10 +585,6 @@ void OculusManager::beginFrameTiming() { · 1 unmodified line | |||
| 428 | if (_frameTimingActive) { | 585 | if (_frameTimingActive) { |
| 429 | printf("WARNING: Called OculusManager::beginFrameTiming() twice in a row, need to call OculusManager::endFrameTiming()."); | 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 | _frameTimingActive = true; | 588 | _frameTimingActive = true; |
| 436 | } | 589 | } |
| 437 | 590 | ||
| @@ -441,27 +594,18 @@ bool OculusManager::allowSwap() { · 3 unmodified lines | |||
| 441 | 594 | ||
| 442 | //Ends frame timing | 595 | //Ends frame timing |
| 443 | void OculusManager::endFrameTiming() { | 596 | void OculusManager::endFrameTiming() { |
| 444 | #ifdef OVR_CLIENT_DISTORTION | ||
| 445 | ovrHmd_EndFrameTiming(_ovrHmd); | ||
| 446 | #endif | ||
| 447 | _frameIndex++; | 597 | _frameIndex++; |
| 448 | _frameTimingActive = false; | 598 | _frameTimingActive = false; |
| 449 | } | 599 | } |
| 450 | 600 | ||
| 451 | //Sets the camera FoV and aspect ratio | 601 | //Sets the camera FoV and aspect ratio |
| 452 | void OculusManager::configureCamera(Camera& camera) { | 602 | void OculusManager::configureCamera(Camera& camera) { |
| 453 | ovrFovPort fov; | ||
| 454 | if (_activeEye == ovrEye_Count) { | 603 | if (_activeEye == ovrEye_Count) { |
| 455 | // When not rendering, provide a FOV encompasing both eyes | 604 | // When not rendering, provide a FOV encompasing both eyes |
| 456 | fov = _eyeFov[0]; | 605 | camera.setProjection(_combinedProjection); |
| 457 | fov.RightTan = _eyeFov[1].RightTan; | 606 | return; |
| 458 | } else { | 607 | } |
| 459 | // When rendering, provide the exact FOV | 608 | camera.setProjection(_eyeProjection[_activeEye]); |
| 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); | ||
| 465 | } | 609 | } |
| 466 | 610 | ||
| 467 | //Displays everything for the oculus, frame timing must be active | 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 | assert(oldFrameIndex == -1 || (unsigned int)oldFrameIndex == _frameIndex - 1); | 617 | assert(oldFrameIndex == -1 || (unsigned int)oldFrameIndex == _frameIndex - 1); |
| 474 | oldFrameIndex = _frameIndex; | 618 | oldFrameIndex = _frameIndex; |
| 475 | #endif | 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 | 621 | #ifndef Q_OS_WIN |
| 481 | // Try to measure the amount of time taken to do the distortion | 622 | |
| 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 | ||
| 510 | // FIXME: we need a better way of responding to the HSW. In particular | 623 | // FIXME: we need a better way of responding to the HSW. In particular |
| 511 | // we need to ensure that it's only displayed once per session, rather than | 624 | // we need to ensure that it's only displayed once per session, rather than |
| 512 | // every time the user toggles VR mode, and we need to hook it up to actual | 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 | #endif | 637 | #endif |
| 525 | 638 | ||
| 526 | 639 | ||
| 527 | //beginFrameTiming must be called before display | 640 | //beginFrameTiming must be called before display |
| 528 | if (!_frameTimingActive) { | 641 | if (!_frameTimingActive) { |
| @@ -545,14 +658,14 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 16 unmodified lines | |||
| 545 | 658 | ||
| 546 | glMatrixMode(GL_MODELVIEW); | 659 | glMatrixMode(GL_MODELVIEW); |
| 547 | glPushMatrix(); | 660 | glPushMatrix(); |
| 548 | 661 | ||
| 549 | glm::quat orientation; | 662 | glm::quat orientation; |
| 550 | glm::vec3 trackerPosition; | 663 | glm::vec3 trackerPosition; |
| 551 | auto deviceSize = qApp->getDeviceSize(); | 664 | auto deviceSize = qApp->getDeviceSize(); |
| 552 | 665 | ||
| 553 | ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); | 666 | ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); |
| 554 | ovrVector3f ovrHeadPosition = ts.HeadPose.ThePose.Position; | 667 | ovrVector3f ovrHeadPosition = ts.HeadPose.ThePose.Position; |
| 555 | 668 | ||
| 556 | trackerPosition = glm::vec3(ovrHeadPosition.x, ovrHeadPosition.y, ovrHeadPosition.z); | 669 | trackerPosition = glm::vec3(ovrHeadPosition.x, ovrHeadPosition.y, ovrHeadPosition.z); |
| 557 | 670 | ||
| 558 | if (_calibrationState != CALIBRATED) { | 671 | if (_calibrationState != CALIBRATED) { |
| @@ -562,11 +675,11 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 3 unmodified lines | |||
| 562 | } | 675 | } |
| 563 | 676 | ||
| 564 | trackerPosition = bodyOrientation * trackerPosition; | 677 | trackerPosition = bodyOrientation * trackerPosition; |
| 565 | static ovrVector3f eyeOffsets[2] = { { 0, 0, 0 }, { 0, 0, 0 } }; | ||
| 566 | ovrPosef eyePoses[ovrEye_Count]; | 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 | ovrHmd_BeginFrame(_ovrHmd, _frameIndex); | 681 | ovrHmd_BeginFrame(_ovrHmd, _frameIndex); |
| 569 | static ovrPosef eyeRenderPose[ovrEye_Count]; | 682 | #endif |
| 570 | //Render each eye into an fbo | 683 | //Render each eye into an fbo |
| 571 | for_each_eye(_ovrHmd, [&](ovrEyeType eye){ | 684 | for_each_eye(_ovrHmd, [&](ovrEyeType eye){ |
| 572 | // If we're in eye-per-frame mode, only render one eye | 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 | return; | 689 | return; |
| 577 | } | 690 | } |
| 578 | _lastEyeRendered = _activeEye = eye; | 691 | _lastEyeRendered = _activeEye = eye; |
| 579 | eyeRenderPose[eye] = eyePoses[eye]; | 692 | _eyeRenderPoses[eye] = eyePoses[eye]; |
| 580 | // Set the camera rotation for this eye | 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 | // Update our camera to what the application camera is doing | 699 | // Update our camera to what the application camera is doing |
| 592 | _camera->setRotation(whichCamera.getRotation()); | 700 | _camera->setRotation(whichCamera.getRotation() * eyeRotation); |
| 593 | _camera->setPosition(whichCamera.getPosition()); | 701 | _camera->setPosition(whichCamera.getPosition() + eyePosition); |
| 594 | configureCamera(*_camera); | 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 | _camera->update(1.0f / Application::getInstance()->getFps()); | 703 | _camera->update(1.0f / Application::getInstance()->getFps()); |
| 603 | 704 | ||
| 604 | glMatrixMode(GL_PROJECTION); | 705 | glMatrixMode(GL_PROJECTION); |
| @@ -607,15 +708,14 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 2 unmodified lines | |||
| 607 | glMatrixMode(GL_MODELVIEW); | 708 | glMatrixMode(GL_MODELVIEW); |
| 608 | glLoadIdentity(); | 709 | glLoadIdentity(); |
| 609 | 710 | ||
| 610 | ovrRecti & vp = _eyeTextures[eye].Header.RenderViewport; | 711 | ovrRecti & vp = _eyeViewports[eye]; |
| 611 | vp.Size.h = _recommendedTexSize.h * _offscreenRenderScale; | 712 | vp.Size.h = _recommendedTexSize.h * _offscreenRenderScale; |
| 612 | vp.Size.w = _recommendedTexSize.w * _offscreenRenderScale; | 713 | vp.Size.w = _recommendedTexSize.w * _offscreenRenderScale; |
| 613 | |||
| 614 | glViewport(vp.Pos.x, vp.Pos.y, vp.Size.w, vp.Size.h); | 714 | glViewport(vp.Pos.x, vp.Pos.y, vp.Size.w, vp.Size.h); |
| 615 | 715 | ||
| 616 | renderArgs->_renderSide = RenderArgs::MONO; | 716 | renderArgs->_renderSide = RenderArgs::MONO; |
| 617 | qApp->displaySide(renderArgs, *_camera, false); | 717 | qApp->displaySide(renderArgs, *_camera); |
| 618 | qApp->getApplicationOverlay().displayOverlayTextureHmd(*_camera); | 718 | qApp->getApplicationCompositor().displayOverlayTextureHmd(renderArgs, eye); |
| 619 | }); | 719 | }); |
| 620 | _activeEye = ovrEye_Count; | 720 | _activeEye = ovrEye_Count; |
| 621 | 721 | ||
| @@ -628,7 +728,7 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 6 unmodified lines | |||
| 628 | glViewport(0, 0, _renderTargetSize.w, _renderTargetSize.h); | 728 | glViewport(0, 0, _renderTargetSize.w, _renderTargetSize.h); |
| 629 | finalFbo = DependencyManager::get<GlowEffect>()->render(renderArgs); | 729 | finalFbo = DependencyManager::get<GlowEffect>()->render(renderArgs); |
| 630 | } else { | 730 | } else { |
| 631 | finalFbo = DependencyManager::get<TextureCache>()->getPrimaryFramebuffer(); | 731 | finalFbo = DependencyManager::get<TextureCache>()->getPrimaryFramebuffer(); |
| 632 | glBindFramebuffer(GL_FRAMEBUFFER, 0); | 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 | // restore our normal viewport | 738 | // restore our normal viewport |
| 639 | glViewport(0, 0, deviceSize.width(), deviceSize.height()); | 739 | glViewport(0, 0, deviceSize.width(), deviceSize.height()); |
| 640 | 740 | ||
| 641 | #if 0 | 741 | #ifdef Q_OS_WIN |
| 642 | if (debugFrame && !timerActive) { | 742 | auto srcFboSize = finalFbo->getSize(); |
| 643 | timerQuery.begin(); | ||
| 644 | } | ||
| 645 | #endif | ||
| 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 | 745 | // Blit to the oculus provided texture |
| 653 | auto fboSize = finalFbo->getSize(); | ||
| 654 | glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo)); | 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 | glBlitFramebuffer( | 756 | glBlitFramebuffer( |
| 656 | 0, 0, fboSize.x, fboSize.y, | 757 | 0, 0, srcFboSize.x, srcFboSize.y, |
| 657 | 0, 0, deviceSize.width(), deviceSize.height(), | 758 | 0, 0, destWindowSize.width(), destWindowSize.height(), |
| 658 | GL_COLOR_BUFFER_BIT, GL_NEAREST); | 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 | #else | 770 | #else |
| 660 | //Clear the color buffer to ensure that there isnt any residual color | 771 | GLsync syncObject = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); |
| 661 | //Left over from when OR was not connected. | 772 | glFlush(); |
| 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(); | ||
| 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 | for_each_eye([&](ovrEyeType eye) { | 783 | for_each_eye([&](ovrEyeType eye) { |
| 673 | ovrGLTexture & glEyeTexture = reinterpret_cast<ovrGLTexture&>(_eyeTextures[eye]); | 784 | ovrGLTexture & glEyeTexture = reinterpret_cast<ovrGLTexture&>(_eyeTextures[eye]); |
| 674 | glEyeTexture.OGL.TexId = finalFbo->texture(); | 785 | glEyeTexture.OGL.TexId = textureId; |
| 675 | |||
| 676 | }); | ||
| 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 | #endif | 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] = {}; | 800 | QMouseEvent mouseEvent(QEvent::MouseMove, glCanvas->mapFromGlobal(QCursor::pos()), |
| 692 | if (debugFrame && ovrHmd_GetFloatArray(_ovrHmd, "DK2Latency", latencies, 5) == 5) | 801 | Qt::NoButton, Qt::NoButton, 0); |
| 693 | { | 802 | qApp->mouseMoveEvent(&mouseEvent, 0); |
| 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 | } | ||
| 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 | //Tries to reconnect to the sensors | 809 | //Tries to reconnect to the sensors |
| 778 | void OculusManager::reset() { | 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 | glm::vec3 OculusManager::getRelativePosition() { | 816 | glm::vec3 OculusManager::getRelativePosition() { |
| 800 | ovrTrackingState trackingState = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); | 817 | ovrTrackingState trackingState = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); |
| 801 | return toGlm(trackingState.HeadPose.ThePose.Position); | 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 | int OculusManager::getHMDScreen() { | 845 | int OculusManager::getHMDScreen() { |
| 846 | #ifdef Q_OS_WIN | ||
| 847 | return -1; | ||
| 848 | #else | ||
| 829 | int hmdScreenIndex = -1; // unknown | 849 | int hmdScreenIndex = -1; // unknown |
| 830 | // TODO: it might be smarter to handle multiple HMDs connected in this case. but for now, | 850 | // TODO: it might be smarter to handle multiple HMDs connected in this case. but for now, |
| 831 | // we will simply assume the initialization code that set up _ovrHmd picked the best hmd | 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 | const int SIMILAR_NAMES = 10; | 864 | const int SIMILAR_NAMES = 10; |
| 845 | const int EXACT_LOCATION_MATCH = 50; | 865 | const int EXACT_LOCATION_MATCH = 50; |
| 846 | const int EXACT_RESOLUTION_MATCH = 25; | 866 | const int EXACT_RESOLUTION_MATCH = 25; |
| 847 | 867 | ||
| 848 | int bestMatchScore = 0; | 868 | int bestMatchScore = 0; |
| 849 | 869 | ||
| 850 | // look at the display list and see if we can find the best match | 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 | foreach (QScreen* screen, QGuiApplication::screens()) { | 873 | foreach (QScreen* screen, QGuiApplication::screens()) { |
| 854 | QString screenName = screen->name(); | 874 | QString screenName = screen->name(); |
| 855 | QRect screenRect = desktop->screenGeometry(screenNumber); | 875 | QRect screenRect = desktop->screenGeometry(screenNumber); |
| 856 | 876 | ||
| 857 | int screenScore = 0; | 877 | int screenScore = 0; |
| 858 | if (screenName == productNameFromOVR) { | 878 | if (screenName == productNameFromOVR) { |
| 859 | screenScore += EXACT_NAME_MATCH; | 879 | screenScore += EXACT_NAME_MATCH; |
| @@ -876,5 +896,18 @@ int OculusManager::getHMDScreen() { · 16 unmodified lines | |||
| 876 | } | 896 | } |
| 877 | } | 897 | } |
| 878 | return hmdScreenIndex; | 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 | #ifndef hifi_OculusManager_h | 13 | #ifndef hifi_OculusManager_h |
| 14 | #define hifi_OculusManager_h | 14 | #define hifi_OculusManager_h |
| 15 | 15 | ||
| 16 | #include <OVR_CAPI.h> | ||
| 17 | |||
| 18 | #include <ProgramObject.h> | 16 | #include <ProgramObject.h> |
| 19 | #include <glm/glm.hpp> | 17 | #include <glm/glm.hpp> |
| 20 | #include <glm/gtc/matrix_transform.hpp> | 18 | #include <glm/gtc/matrix_transform.hpp> |
| @@ -22,39 +20,13 @@ · 1 unmodified line | |||
| 22 | 20 | ||
| 23 | #include "RenderArgs.h" | 21 | #include "RenderArgs.h" |
| 24 | 22 | ||
| 23 | class QOpenGLContext; | ||
| 25 | class Camera; | 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 | /// Handles interaction with the Oculus Rift. | 26 | /// Handles interaction with the Oculus Rift. |
| 53 | class OculusManager { | 27 | class OculusManager { |
| 54 | public: | 28 | public: |
| 55 | static void init(); | 29 | static void connect(QOpenGLContext* shareContext); |
| 56 | static void deinit(); | ||
| 57 | static void connect(); | ||
| 58 | static void disconnect(); | 30 | static void disconnect(); |
| 59 | static bool isConnected(); | 31 | static bool isConnected(); |
| 60 | static void recalibrate(); | 32 | static void recalibrate(); |
| @@ -66,10 +38,6 @@ public: · 5 unmodified lines | |||
| 66 | static void display(QGLWidget * glCanvas, RenderArgs* renderArgs, const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera); | 38 | static void display(QGLWidget * glCanvas, RenderArgs* renderArgs, const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera); |
| 67 | static void reset(); | 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 | static glm::vec3 getRelativePosition(); | 41 | static glm::vec3 getRelativePosition(); |
| 74 | static glm::quat getOrientation(); | 42 | static glm::quat getOrientation(); |
| 75 | static QSize getRenderTargetSize(); | 43 | static QSize getRenderTargetSize(); |
| @@ -77,145 +45,14 @@ public: · 1 unmodified line | |||
| 77 | static void overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal, | 45 | static void overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal, |
| 78 | float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane); | 46 | float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane); |
| 79 | 47 | ||
| 80 | static glm::vec3 getLeftEyePosition() { return _eyePositions[ovrEye_Left]; } | 48 | static glm::vec3 getLeftEyePosition(); |
| 81 | static glm::vec3 getRightEyePosition() { return _eyePositions[ovrEye_Right]; } | 49 | static glm::vec3 getRightEyePosition(); |
| 82 | 50 | ||
| 83 | static int getHMDScreen(); | 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; | 53 | static glm::mat4 getEyeProjection(int eye); |
| 105 | //Uniforms | 54 | static glm::mat4 getEyePose(int eye); |
| 106 | static int _textureLocation; | 55 | static glm::mat4 getHeadPose(); |
| 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; | ||
| 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 | #endif // hifi_OculusManager_h | 58 | #endif // hifi_OculusManager_h |
| @@ -74,9 +74,11 @@ SDL2Manager* SDL2Manager::getInstance() { · 73 unmodified lines | |||
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | void SDL2Manager::focusOutEvent() { | 76 | void SDL2Manager::focusOutEvent() { |
| 77 | #ifdef HAVE_SDL2 | ||
| 77 | for (auto joystick : _openJoysticks) { | 78 | for (auto joystick : _openJoysticks) { |
| 78 | joystick->focusOutEvent(); | 79 | joystick->focusOutEvent(); |
| 79 | } | 80 | } |
| 81 | #endif | ||
| 80 | } | 82 | } |
| 81 | 83 | ||
| 82 | void SDL2Manager::update() { | 84 | void SDL2Manager::update() { |
| @@ -36,6 +36,8 @@ const float NECK_X = 0.25f; // meters · 35 unmodified lines | |||
| 36 | const float NECK_Y = 0.3f; // meters | 36 | const float NECK_Y = 0.3f; // meters |
| 37 | const float NECK_Z = 0.3f; // meters | 37 | const float NECK_Z = 0.3f; // meters |
| 38 | 38 | ||
| 39 | const float CONTROLLER_THRESHOLD = 0.35f; | ||
| 40 | |||
| 39 | #ifdef __APPLE__ | 41 | #ifdef __APPLE__ |
| 40 | typedef int (*SixenseBaseFunction)(); | 42 | typedef int (*SixenseBaseFunction)(); |
| 41 | typedef int (*SixenseTakeIntFunction)(int); | 43 | typedef int (*SixenseTakeIntFunction)(int); |
| @@ -71,25 +73,25 @@ SixenseManager::SixenseManager() : · 29 unmodified lines | |||
| 71 | 73 | ||
| 72 | SixenseManager::~SixenseManager() { | 74 | SixenseManager::~SixenseManager() { |
| 73 | #ifdef HAVE_SIXENSE_ | 75 | #ifdef HAVE_SIXENSE_ |
| 74 | 76 | ||
| 75 | if (_isInitialized) { | 77 | if (_isInitialized) { |
| 76 | #ifdef __APPLE__ | 78 | #ifdef __APPLE__ |
| 77 | SixenseBaseFunction sixenseExit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseExit"); | 79 | SixenseBaseFunction sixenseExit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseExit"); |
| 78 | #endif | 80 | #endif |
| 79 | 81 | ||
| 80 | sixenseExit(); | 82 | sixenseExit(); |
| 81 | } | 83 | } |
| 82 | 84 | ||
| 83 | #ifdef __APPLE__ | 85 | #ifdef __APPLE__ |
| 84 | delete _sixenseLibrary; | 86 | delete _sixenseLibrary; |
| 85 | #endif | 87 | #endif |
| 86 | 88 | ||
| 87 | #endif | 89 | #endif |
| 88 | } | 90 | } |
| 89 | 91 | ||
| 90 | void SixenseManager::initialize() { | 92 | void SixenseManager::initialize() { |
| 91 | #ifdef HAVE_SIXENSE | 93 | #ifdef HAVE_SIXENSE |
| 92 | 94 | ||
| 93 | if (!_isInitialized) { | 95 | if (!_isInitialized) { |
| 94 | _lowVelocityFilter = false; | 96 | _lowVelocityFilter = false; |
| 95 | _controllersAtBase = true; | 97 | _controllersAtBase = true; |
| @@ -97,22 +99,22 @@ void SixenseManager::initialize() { · 1 unmodified line | |||
| 97 | // By default we assume the _neckBase (in orb frame) is as high above the orb | 99 | // By default we assume the _neckBase (in orb frame) is as high above the orb |
| 98 | // as the "torso" is below it. | 100 | // as the "torso" is below it. |
| 99 | _neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z); | 101 | _neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z); |
| 100 | 102 | ||
| 101 | #ifdef __APPLE__ | 103 | #ifdef __APPLE__ |
| 102 | 104 | ||
| 103 | if (!_sixenseLibrary) { | 105 | if (!_sixenseLibrary) { |
| 104 | 106 | ||
| 105 | #ifdef SIXENSE_LIB_FILENAME | 107 | #ifdef SIXENSE_LIB_FILENAME |
| 106 | _sixenseLibrary = new QLibrary(SIXENSE_LIB_FILENAME); | 108 | _sixenseLibrary = new QLibrary(SIXENSE_LIB_FILENAME); |
| 107 | #else | 109 | #else |
| 108 | const QString SIXENSE_LIBRARY_NAME = "libsixense_x64"; | 110 | const QString SIXENSE_LIBRARY_NAME = "libsixense_x64"; |
| 109 | QString frameworkSixenseLibrary = QCoreApplication::applicationDirPath() + "/../Frameworks/" | 111 | QString frameworkSixenseLibrary = QCoreApplication::applicationDirPath() + "/../Frameworks/" |
| 110 | + SIXENSE_LIBRARY_NAME; | 112 | + SIXENSE_LIBRARY_NAME; |
| 111 | 113 | ||
| 112 | _sixenseLibrary = new QLibrary(frameworkSixenseLibrary); | 114 | _sixenseLibrary = new QLibrary(frameworkSixenseLibrary); |
| 113 | #endif | 115 | #endif |
| 114 | } | 116 | } |
| 115 | 117 | ||
| 116 | if (_sixenseLibrary->load()){ | 118 | if (_sixenseLibrary->load()){ |
| 117 | qCDebug(interfaceapp) << "Loaded sixense library for hydra support -" << _sixenseLibrary->fileName(); | 119 | qCDebug(interfaceapp) << "Loaded sixense library for hydra support -" << _sixenseLibrary->fileName(); |
| 118 | } else { | 120 | } else { |
| @@ -120,14 +122,14 @@ void SixenseManager::initialize() { · 1 unmodified line | |||
| 120 | << "Continuing without hydra support."; | 122 | << "Continuing without hydra support."; |
| 121 | return; | 123 | return; |
| 122 | } | 124 | } |
| 123 | 125 | ||
| 124 | SixenseBaseFunction sixenseInit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseInit"); | 126 | SixenseBaseFunction sixenseInit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseInit"); |
| 125 | #endif | 127 | #endif |
| 126 | sixenseInit(); | 128 | sixenseInit(); |
| 127 | 129 | ||
| 128 | _isInitialized = true; | 130 | _isInitialized = true; |
| 129 | } | 131 | } |
| 130 | 132 | ||
| 131 | #endif | 133 | #endif |
| 132 | } | 134 | } |
| 133 | 135 | ||
| @@ -138,7 +140,7 @@ void SixenseManager::setFilter(bool filter) { · 4 unmodified lines | |||
| 138 | #ifdef __APPLE__ | 140 | #ifdef __APPLE__ |
| 139 | SixenseTakeIntFunction sixenseSetFilterEnabled = (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseSetFilterEnabled"); | 141 | SixenseTakeIntFunction sixenseSetFilterEnabled = (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseSetFilterEnabled"); |
| 140 | #endif | 142 | #endif |
| 141 | 143 | ||
| 142 | if (filter) { | 144 | if (filter) { |
| 143 | sixenseSetFilterEnabled(1); | 145 | sixenseSetFilterEnabled(1); |
| 144 | } else { | 146 | } else { |
| @@ -158,7 +160,7 @@ void SixenseManager::update(float deltaTime) { · 13 unmodified lines | |||
| 158 | SixenseBaseFunction sixenseGetNumActiveControllers = | 160 | SixenseBaseFunction sixenseGetNumActiveControllers = |
| 159 | (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetNumActiveControllers"); | 161 | (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetNumActiveControllers"); |
| 160 | #endif | 162 | #endif |
| 161 | 163 | ||
| 162 | if (sixenseGetNumActiveControllers() == 0) { | 164 | if (sixenseGetNumActiveControllers() == 0) { |
| 163 | _hydrasConnected = false; | 165 | _hydrasConnected = false; |
| 164 | if (_deviceID != 0) { | 166 | if (_deviceID != 0) { |
| @@ -173,7 +175,7 @@ void SixenseManager::update(float deltaTime) { · 8 unmodified lines | |||
| 173 | } | 175 | } |
| 174 | return; | 176 | return; |
| 175 | } | 177 | } |
| 176 | 178 | ||
| 177 | PerformanceTimer perfTimer("sixense"); | 179 | PerformanceTimer perfTimer("sixense"); |
| 178 | if (!_hydrasConnected) { | 180 | if (!_hydrasConnected) { |
| 179 | _hydrasConnected = true; | 181 | _hydrasConnected = true; |
| @@ -181,21 +183,21 @@ void SixenseManager::update(float deltaTime) { · 1 unmodified line | |||
| 181 | getInstance().assignDefaultInputMapping(*Application::getUserInputMapper()); | 183 | getInstance().assignDefaultInputMapping(*Application::getUserInputMapper()); |
| 182 | UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra"); | 184 | UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra"); |
| 183 | } | 185 | } |
| 184 | 186 | ||
| 185 | #ifdef __APPLE__ | 187 | #ifdef __APPLE__ |
| 186 | SixenseBaseFunction sixenseGetMaxControllers = | 188 | SixenseBaseFunction sixenseGetMaxControllers = |
| 187 | (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetMaxControllers"); | 189 | (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetMaxControllers"); |
| 188 | #endif | 190 | #endif |
| 189 | 191 | ||
| 190 | int maxControllers = sixenseGetMaxControllers(); | 192 | int maxControllers = sixenseGetMaxControllers(); |
| 191 | 193 | ||
| 192 | // we only support two controllers | 194 | // we only support two controllers |
| 193 | sixenseControllerData controllers[2]; | 195 | sixenseControllerData controllers[2]; |
| 194 | 196 | ||
| 195 | #ifdef __APPLE__ | 197 | #ifdef __APPLE__ |
| 196 | SixenseTakeIntFunction sixenseIsControllerEnabled = | 198 | SixenseTakeIntFunction sixenseIsControllerEnabled = |
| 197 | (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseIsControllerEnabled"); | 199 | (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseIsControllerEnabled"); |
| 198 | 200 | ||
| 199 | SixenseTakeIntAndSixenseControllerData sixenseGetNewestData = | 201 | SixenseTakeIntAndSixenseControllerData sixenseGetNewestData = |
| 200 | (SixenseTakeIntAndSixenseControllerData) _sixenseLibrary->resolve("sixenseGetNewestData"); | 202 | (SixenseTakeIntAndSixenseControllerData) _sixenseLibrary->resolve("sixenseGetNewestData"); |
| 201 | #endif | 203 | #endif |
| @@ -208,9 +210,9 @@ void SixenseManager::update(float deltaTime) { · 6 unmodified lines | |||
| 208 | sixenseControllerData* data = controllers + numActiveControllers; | 210 | sixenseControllerData* data = controllers + numActiveControllers; |
| 209 | ++numActiveControllers; | 211 | ++numActiveControllers; |
| 210 | sixenseGetNewestData(i, data); | 212 | sixenseGetNewestData(i, data); |
| 211 | 213 | ||
| 212 | // Set palm position and normal based on Hydra position/orientation | 214 | // Set palm position and normal based on Hydra position/orientation |
| 213 | 215 | ||
| 214 | // Either find a palm matching the sixense controller, or make a new one | 216 | // Either find a palm matching the sixense controller, or make a new one |
| 215 | PalmData* palm; | 217 | PalmData* palm; |
| 216 | bool foundHand = false; | 218 | bool foundHand = false; |
| @@ -229,47 +231,47 @@ void SixenseManager::update(float deltaTime) { · 12 unmodified lines | |||
| 229 | _prevPalms[numActiveControllers - 1] = palm; | 231 | _prevPalms[numActiveControllers - 1] = palm; |
| 230 | qCDebug(interfaceapp, "Found new Sixense controller, ID %i", data->controller_index); | 232 | qCDebug(interfaceapp, "Found new Sixense controller, ID %i", data->controller_index); |
| 231 | } | 233 | } |
| 232 | 234 | ||
| 233 | // Disable the hands (and return to default pose) if both controllers are at base station | 235 | // Disable the hands (and return to default pose) if both controllers are at base station |
| 234 | if (foundHand) { | 236 | if (foundHand) { |
| 235 | palm->setActive(!_controllersAtBase); | 237 | palm->setActive(!_controllersAtBase); |
| 236 | } else { | 238 | } else { |
| 237 | palm->setActive(false); // if this isn't a Sixsense ID palm, always make it inactive | 239 | palm->setActive(false); // if this isn't a Sixsense ID palm, always make it inactive |
| 238 | } | 240 | } |
| 239 | 241 | ||
| 240 | // Read controller buttons and joystick into the hand | 242 | // Read controller buttons and joystick into the hand |
| 241 | palm->setControllerButtons(data->buttons); | 243 | palm->setControllerButtons(data->buttons); |
| 242 | palm->setTrigger(data->trigger); | 244 | palm->setTrigger(data->trigger); |
| 243 | palm->setJoystick(data->joystick_x, data->joystick_y); | 245 | palm->setJoystick(data->joystick_x, data->joystick_y); |
| 244 | 246 | ||
| 245 | handleButtonEvent(data->buttons, numActiveControllers - 1); | 247 | handleButtonEvent(data->buttons, numActiveControllers - 1); |
| 246 | handleAxisEvent(data->joystick_x, data->joystick_y, data->trigger, numActiveControllers - 1); | 248 | handleAxisEvent(data->joystick_x, data->joystick_y, data->trigger, numActiveControllers - 1); |
| 247 | 249 | ||
| 248 | // Emulate the mouse so we can use scripts | 250 | // Emulate the mouse so we can use scripts |
| 249 | if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput) && !_controllersAtBase) { | 251 | if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput) && !_controllersAtBase) { |
| 250 | emulateMouse(palm, numActiveControllers - 1); | 252 | emulateMouse(palm, numActiveControllers - 1); |
| 251 | } | 253 | } |
| 252 | 254 | ||
| 253 | // NOTE: Sixense API returns pos data in millimeters but we IMMEDIATELY convert to meters. | 255 | // NOTE: Sixense API returns pos data in millimeters but we IMMEDIATELY convert to meters. |
| 254 | glm::vec3 position(data->pos[0], data->pos[1], data->pos[2]); | 256 | glm::vec3 position(data->pos[0], data->pos[1], data->pos[2]); |
| 255 | position *= METERS_PER_MILLIMETER; | 257 | position *= METERS_PER_MILLIMETER; |
| 256 | 258 | ||
| 257 | // Check to see if this hand/controller is on the base | 259 | // Check to see if this hand/controller is on the base |
| 258 | const float CONTROLLER_AT_BASE_DISTANCE = 0.075f; | 260 | const float CONTROLLER_AT_BASE_DISTANCE = 0.075f; |
| 259 | if (glm::length(position) < CONTROLLER_AT_BASE_DISTANCE) { | 261 | if (glm::length(position) < CONTROLLER_AT_BASE_DISTANCE) { |
| 260 | numControllersAtBase++; | 262 | numControllersAtBase++; |
| 261 | } | 263 | } |
| 262 | 264 | ||
| 263 | // Transform the measured position into body frame. | 265 | // Transform the measured position into body frame. |
| 264 | glm::vec3 neck = _neckBase; | 266 | glm::vec3 neck = _neckBase; |
| 265 | // Zeroing y component of the "neck" effectively raises the measured position a little bit. | 267 | // Zeroing y component of the "neck" effectively raises the measured position a little bit. |
| 266 | neck.y = 0.0f; | 268 | neck.y = 0.0f; |
| 267 | position = _orbRotation * (position - neck); | 269 | position = _orbRotation * (position - neck); |
| 268 | 270 | ||
| 269 | // Rotation of Palm | 271 | // Rotation of Palm |
| 270 | glm::quat rotation(data->rot_quat[3], -data->rot_quat[0], data->rot_quat[1], -data->rot_quat[2]); | 272 | glm::quat rotation(data->rot_quat[3], -data->rot_quat[0], data->rot_quat[1], -data->rot_quat[2]); |
| 271 | rotation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)) * _orbRotation * rotation; | 273 | rotation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)) * _orbRotation * rotation; |
| 272 | 274 | ||
| 273 | // Compute current velocity from position change | 275 | // Compute current velocity from position change |
| 274 | glm::vec3 rawVelocity; | 276 | glm::vec3 rawVelocity; |
| 275 | if (deltaTime > 0.0f) { | 277 | if (deltaTime > 0.0f) { |
| @@ -278,11 +280,11 @@ void SixenseManager::update(float deltaTime) { · 2 unmodified lines | |||
| 278 | rawVelocity = glm::vec3(0.0f); | 280 | rawVelocity = glm::vec3(0.0f); |
| 279 | } | 281 | } |
| 280 | palm->setRawVelocity(rawVelocity); // meters/sec | 282 | palm->setRawVelocity(rawVelocity); // meters/sec |
| 281 | 283 | ||
| 282 | // adjustment for hydra controllers fit into hands | 284 | // adjustment for hydra controllers fit into hands |
| 283 | float sign = (i == 0) ? -1.0f : 1.0f; | 285 | float sign = (i == 0) ? -1.0f : 1.0f; |
| 284 | rotation *= glm::angleAxis(sign * PI/4.0f, glm::vec3(0.0f, 0.0f, 1.0f)); | 286 | rotation *= glm::angleAxis(sign * PI/4.0f, glm::vec3(0.0f, 0.0f, 1.0f)); |
| 285 | 287 | ||
| 286 | // Angular Velocity of Palm | 288 | // Angular Velocity of Palm |
| 287 | glm::quat deltaRotation = rotation * glm::inverse(palm->getRawRotation()); | 289 | glm::quat deltaRotation = rotation * glm::inverse(palm->getRawRotation()); |
| 288 | glm::vec3 angularVelocity(0.0f); | 290 | glm::vec3 angularVelocity(0.0f); |
| @@ -294,7 +296,7 @@ void SixenseManager::update(float deltaTime) { · 5 unmodified lines | |||
| 294 | } else { | 296 | } else { |
| 295 | palm->setRawAngularVelocity(glm::vec3(0.0f)); | 297 | palm->setRawAngularVelocity(glm::vec3(0.0f)); |
| 296 | } | 298 | } |
| 297 | 299 | ||
| 298 | if (_lowVelocityFilter) { | 300 | if (_lowVelocityFilter) { |
| 299 | // Use a velocity sensitive filter to damp small motions and preserve large ones with | 301 | // Use a velocity sensitive filter to damp small motions and preserve large ones with |
| 300 | // no latency. | 302 | // no latency. |
| @@ -307,7 +309,7 @@ void SixenseManager::update(float deltaTime) { · 6 unmodified lines | |||
| 307 | palm->setRawPosition(position); | 309 | palm->setRawPosition(position); |
| 308 | palm->setRawRotation(rotation); | 310 | palm->setRawRotation(rotation); |
| 309 | } | 311 | } |
| 310 | 312 | ||
| 311 | // Store the one fingertip in the palm structure so we can track velocity | 313 | // Store the one fingertip in the palm structure so we can track velocity |
| 312 | const float FINGER_LENGTH = 0.3f; // meters | 314 | const float FINGER_LENGTH = 0.3f; // meters |
| 313 | const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, FINGER_LENGTH); | 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 | palm->setTipPosition(newTipPosition); | 323 | palm->setTipPosition(newTipPosition); |
| 322 | } | 324 | } |
| 323 | 325 | ||
| 324 | if (numActiveControllers == 2) { | 326 | if (numActiveControllers == 2) { |
| 325 | updateCalibration(controllers); | 327 | updateCalibration(controllers); |
| 326 | } | 328 | } |
| 327 | _controllersAtBase = (numControllersAtBase == 2); | 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 | #endif // HAVE_SIXENSE | 337 | #endif // HAVE_SIXENSE |
| 330 | } | 338 | } |
| 331 | 339 | ||
| 332 | //Constants for getCursorPixelRangeMultiplier() | 340 | //Constants for getCursorPixelRangeMultiplier() |
| 333 | const float MIN_PIXEL_RANGE_MULT = 0.4f; | 341 | const float MIN_PIXEL_RANGE_MULT = 0.4f; |
| 334 | const float MAX_PIXEL_RANGE_MULT = 2.0f; | 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 | //Returns a multiplier to be applied to the cursor range for the controllers | 345 | //Returns a multiplier to be applied to the cursor range for the controllers |
| 338 | float SixenseManager::getCursorPixelRangeMult() const { | 346 | float SixenseManager::getCursorPixelRangeMult() const { |
| @@ -421,7 +429,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 82 unmodified lines | |||
| 421 | _calibrationState = CALIBRATION_STATE_X; | 429 | _calibrationState = CALIBRATION_STATE_X; |
| 422 | } | 430 | } |
| 423 | return; | 431 | return; |
| 424 | } | 432 | } |
| 425 | 433 | ||
| 426 | quint64 now = usecTimestampNow() + LOCK_DURATION; | 434 | quint64 now = usecTimestampNow() + LOCK_DURATION; |
| 427 | // these are weighted running averages | 435 | // these are weighted running averages |
| @@ -431,7 +439,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 3 unmodified lines | |||
| 431 | if (_calibrationState == CALIBRATION_STATE_X) { | 439 | if (_calibrationState == CALIBRATION_STATE_X) { |
| 432 | // compute new sliding average | 440 | // compute new sliding average |
| 433 | float distance = glm::distance(_averageLeft, _averageRight); | 441 | float distance = glm::distance(_averageLeft, _averageRight); |
| 434 | if (fabs(distance - _lastDistance) > MAXIMUM_NOISE_LEVEL) { | 442 | if (fabsf(distance - _lastDistance) > MAXIMUM_NOISE_LEVEL) { |
| 435 | // distance is increasing so acquire the data and push the expiry out | 443 | // distance is increasing so acquire the data and push the expiry out |
| 436 | _reachLeft = _averageLeft; | 444 | _reachLeft = _averageLeft; |
| 437 | _reachRight = _averageRight; | 445 | _reachRight = _averageRight; |
| @@ -450,7 +458,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 12 unmodified lines | |||
| 450 | glm::vec3 torso = 0.5f * (_reachLeft + _reachRight); | 458 | glm::vec3 torso = 0.5f * (_reachLeft + _reachRight); |
| 451 | glm::vec3 averagePosition = 0.5f * (_averageLeft + _averageRight); | 459 | glm::vec3 averagePosition = 0.5f * (_averageLeft + _averageRight); |
| 452 | float distance = (averagePosition - torso).y; | 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 | // distance is increasing so acquire the data and push the expiry out | 462 | // distance is increasing so acquire the data and push the expiry out |
| 455 | _reachUp = averagePosition; | 463 | _reachUp = averagePosition; |
| 456 | _lastDistance = distance; | 464 | _lastDistance = distance; |
| @@ -481,11 +489,11 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 24 unmodified lines | |||
| 481 | _lastDistance = distance; | 489 | _lastDistance = distance; |
| 482 | _lockExpiry = now + LOCK_DURATION; | 490 | _lockExpiry = now + LOCK_DURATION; |
| 483 | } else if (now > _lockExpiry) { | 491 | } else if (now > _lockExpiry) { |
| 484 | if (fabs(_lastDistance) > 0.05f * MINIMUM_ARM_REACH) { | 492 | if (fabsf(_lastDistance) > 0.05f * MINIMUM_ARM_REACH) { |
| 485 | // lock has expired so clamp the data and move on | 493 | // lock has expired so clamp the data and move on |
| 486 | _calibrationState = CALIBRATION_STATE_COMPLETE; | 494 | _calibrationState = CALIBRATION_STATE_COMPLETE; |
| 487 | qCDebug(interfaceapp, "success: sixense calibration: forward"); | 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 | // accidentally switched (left hand is holding right controller) and to swap the order. | 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 | void SixenseManager::emulateMouse(PalmData* palm, int index) { | 504 | void SixenseManager::emulateMouse(PalmData* palm, int index) { |
| 497 | MyAvatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | 505 | MyAvatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); |
| 498 | QPoint pos; | 506 | QPoint pos; |
| 499 | 507 | ||
| 500 | Qt::MouseButton bumperButton; | 508 | Qt::MouseButton bumperButton; |
| 501 | Qt::MouseButton triggerButton; | 509 | Qt::MouseButton triggerButton; |
| 502 | 510 | ||
| @@ -510,16 +518,16 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { · 7 unmodified lines | |||
| 510 | triggerButton = Qt::LeftButton; | 518 | triggerButton = Qt::LeftButton; |
| 511 | } | 519 | } |
| 512 | 520 | ||
| 513 | if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers) | 521 | if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers) |
| 514 | || Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) { | 522 | || Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) { |
| 515 | pos = qApp->getApplicationOverlay().getPalmClickLocation(palm); | 523 | pos = qApp->getApplicationCompositor().getPalmClickLocation(palm); |
| 516 | } else { | 524 | } else { |
| 517 | // Get directon relative to avatar orientation | 525 | // Get directon relative to avatar orientation |
| 518 | glm::vec3 direction = glm::inverse(avatar->getOrientation()) * palm->getFingerDirection(); | 526 | glm::vec3 direction = glm::inverse(avatar->getOrientation()) * palm->getFingerDirection(); |
| 519 | 527 | ||
| 520 | // Get the angles, scaled between (-0.5,0.5) | 528 | // Get the angles, scaled between (-0.5,0.5) |
| 521 | float xAngle = (atan2(direction.z, direction.x) + M_PI_2); | 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 | auto canvasSize = qApp->getCanvasSize(); | 531 | auto canvasSize = qApp->getCanvasSize(); |
| 524 | // Get the pixel range over which the xAngle and yAngle are scaled | 532 | // Get the pixel range over which the xAngle and yAngle are scaled |
| 525 | float cursorRange = canvasSize.x * getCursorPixelRangeMult(); | 533 | float cursorRange = canvasSize.x * getCursorPixelRangeMult(); |
| @@ -562,11 +570,11 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { · 36 unmodified lines | |||
| 562 | if (!_bumperPressed[(int)(!index)]) { | 570 | if (!_bumperPressed[(int)(!index)]) { |
| 563 | qApp->mouseMoveEvent(&mouseEvent, deviceID); | 571 | qApp->mouseMoveEvent(&mouseEvent, deviceID); |
| 564 | } | 572 | } |
| 565 | } | 573 | } |
| 566 | } | 574 | } |
| 567 | _oldX[index] = pos.x(); | 575 | _oldX[index] = pos.x(); |
| 568 | _oldY[index] = pos.y(); | 576 | _oldY[index] = pos.y(); |
| 569 | 577 | ||
| 570 | 578 | ||
| 571 | //We need separate coordinates for clicks, since we need to check if | 579 | //We need separate coordinates for clicks, since we need to check if |
| 572 | //a magnification window was clicked on | 580 | //a magnification window was clicked on |
| @@ -580,7 +588,7 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { · 7 unmodified lines | |||
| 580 | if (palm->getControllerButtons() & BUTTON_FWD) { | 588 | if (palm->getControllerButtons() & BUTTON_FWD) { |
| 581 | if (!_bumperPressed[index]) { | 589 | if (!_bumperPressed[index]) { |
| 582 | _bumperPressed[index] = true; | 590 | _bumperPressed[index] = true; |
| 583 | 591 | ||
| 584 | QMouseEvent mouseEvent(QEvent::MouseButtonPress, pos, bumperButton, bumperButton, 0); | 592 | QMouseEvent mouseEvent(QEvent::MouseButtonPress, pos, bumperButton, bumperButton, 0); |
| 585 | 593 | ||
| 586 | qApp->mousePressEvent(&mouseEvent, deviceID); | 594 | qApp->mousePressEvent(&mouseEvent, deviceID); |
| @@ -12,6 +12,7 @@ · 11 unmodified lines | |||
| 12 | #include "InterfaceConfig.h" | 12 | #include "InterfaceConfig.h" |
| 13 | 13 | ||
| 14 | #include <glm/glm.hpp> | 14 | #include <glm/glm.hpp> |
| 15 | #include <glm/gtc/type_ptr.hpp> | ||
| 15 | 16 | ||
| 16 | #include <GlowEffect.h> | 17 | #include <GlowEffect.h> |
| 17 | #include "gpu/GLBackend.h" | 18 | #include "gpu/GLBackend.h" |
| @@ -106,21 +107,20 @@ void TV3DManager::display(RenderArgs* renderArgs, Camera& whichCamera) { · 88 unmodified lines | |||
| 106 | _activeEye = &eye; | 107 | _activeEye = &eye; |
| 107 | glViewport(portalX, portalY, portalW, portalH); | 108 | glViewport(portalX, portalY, portalW, portalH); |
| 108 | glScissor(portalX, portalY, portalW, portalH); | 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 | glMatrixMode(GL_PROJECTION); | 116 | glMatrixMode(GL_PROJECTION); |
| 110 | glLoadIdentity(); // reset projection matrix | 117 | glLoadIdentity(); // reset projection matrix |
| 111 | glFrustum(eye.left, eye.right, eye.bottom, eye.top, nearZ, farZ); // set left view frustum | 118 | glLoadMatrixf(glm::value_ptr(projection)); |
| 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 | |||
| 119 | glMatrixMode(GL_MODELVIEW); | 119 | glMatrixMode(GL_MODELVIEW); |
| 120 | glLoadIdentity(); | 120 | glLoadIdentity(); |
| 121 | renderArgs->_renderSide = RenderArgs::MONO; | 121 | renderArgs->_renderSide = RenderArgs::MONO; |
| 122 | qApp->displaySide(renderArgs, eyeCamera, false); | 122 | qApp->displaySide(renderArgs, eyeCamera, false); |
| 123 | qApp->getApplicationOverlay().displayOverlayTextureStereo(whichCamera, _aspect, fov); | 123 | qApp->getApplicationCompositor().displayOverlayTexture(renderArgs); |
| 124 | _activeEye = NULL; | 124 | _activeEye = NULL; |
| 125 | }, [&]{ | 125 | }, [&]{ |
| 126 | // render right side view | 126 | // render right side view |
| @@ -23,7 +23,7 @@ · 22 unmodified lines | |||
| 23 | #ifdef Q_OS_WIN | 23 | #ifdef Q_OS_WIN |
| 24 | static BOOL CALLBACK enumWindowsCallback(HWND hWnd, LPARAM lParam) { | 24 | static BOOL CALLBACK enumWindowsCallback(HWND hWnd, LPARAM lParam) { |
| 25 | const UINT TIMEOUT = 200; // ms | 25 | const UINT TIMEOUT = 200; // ms |
| 26 | DWORD response; | 26 | DWORD_PTR response; |
| 27 | LRESULT result = SendMessageTimeout(hWnd, UWM_IDENTIFY_INSTANCES, 0, 0, SMTO_BLOCK | SMTO_ABORTIFHUNG, TIMEOUT, &response); | 27 | LRESULT result = SendMessageTimeout(hWnd, UWM_IDENTIFY_INSTANCES, 0, 0, SMTO_BLOCK | SMTO_ABORTIFHUNG, TIMEOUT, &response); |
| 28 | if (result == 0) { // Timeout; continue search. | 28 | if (result == 0) { // Timeout; continue search. |
| 29 | return TRUE; | 29 | return TRUE; |
| @@ -463,7 +463,7 @@ void ControllerScriptingInterface::resetDevice(unsigned int device) { · 462 unmodified lines | |||
| 463 | } | 463 | } |
| 464 | 464 | ||
| 465 | int ControllerScriptingInterface::findDevice(QString name) { | 465 | int ControllerScriptingInterface::findDevice(QString name) { |
| 466 | Application::getUserInputMapper()->findDevice(name); | 466 | return Application::getUserInputMapper()->findDevice(name); |
| 467 | } | 467 | } |
| 468 | 468 | ||
| 469 | InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) : | 469 | InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) : |
| @@ -65,6 +65,7 @@ public: · 64 unmodified lines | |||
| 65 | 65 | ||
| 66 | void emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseMoveEvent(MouseEvent(*event, deviceID)); } | 66 | void emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseMoveEvent(MouseEvent(*event, deviceID)); } |
| 67 | void emitMousePressEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mousePressEvent(MouseEvent(*event, deviceID)); } | 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 | void emitMouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseReleaseEvent(MouseEvent(*event, deviceID)); } | 69 | void emitMouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseReleaseEvent(MouseEvent(*event, deviceID)); } |
| 69 | 70 | ||
| 70 | void emitTouchBeginEvent(const TouchEvent& event) { emit touchBeginEvent(event); } | 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 | glm::vec3 direction = orientation * glm::vec3(0.0f, 0.0f, -1.0f); | 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 | QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) { | 33 | QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) { |
| @@ -40,7 +40,7 @@ QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* conte · 6 unmodified lines | |||
| 40 | glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * (hudIntersection - sphereCenter); | 40 | glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * (hudIntersection - sphereCenter); |
| 41 | glm::quat rotation = ::rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), direction); | 41 | glm::quat rotation = ::rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), direction); |
| 42 | glm::vec3 eulers = ::safeEulerAngles(rotation); | 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 | .sphericalToOverlay(glm::vec2(eulers.y, -eulers.x))); | 44 | .sphericalToOverlay(glm::vec2(eulers.y, -eulers.x))); |
| 45 | } | 45 | } |
| 46 | return QScriptValue::NullValue; | 46 | return QScriptValue::NullValue; |
| @@ -27,11 +27,11 @@ public: · 26 unmodified lines | |||
| 27 | static QScriptValue getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine); | 27 | static QScriptValue getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine); |
| 28 | 28 | ||
| 29 | public slots: | 29 | public slots: |
| 30 | void toggleMagnifier() { Application::getInstance()->getApplicationOverlay().toggleMagnifier(); }; | 30 | void toggleMagnifier() { Application::getInstance()->getApplicationCompositor().toggleMagnifier(); }; |
| 31 | 31 | ||
| 32 | private: | 32 | private: |
| 33 | HMDScriptingInterface() {}; | 33 | HMDScriptingInterface() {}; |
| 34 | bool getMagnifier() const { return Application::getInstance()->getApplicationOverlay().hasMagnifier(); }; | 34 | bool getMagnifier() const { return Application::getInstance()->getApplicationCompositor().hasMagnifier(); }; |
| 35 | bool isHMDMode() const { return Application::getInstance()->isHMDMode(); } | 35 | bool isHMDMode() const { return Application::getInstance()->isHMDMode(); } |
| 36 | 36 | ||
| 37 | bool getHUDLookAtPosition3D(glm::vec3& result) const; | 37 | bool getHUDLookAtPosition3D(glm::vec3& result) const; |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | |||
| 11 | // | 11 | // |
| 12 | 12 | ||
| 13 | #include "starfield/renderer/Renderer.h" | 13 | #include "starfield/renderer/Renderer.h" |
| 14 | #include "Application.h" | ||
| 14 | 15 | ||
| 15 | using namespace starfield; | 16 | using namespace starfield; |
| 16 | 17 | ||
| @@ -52,6 +53,10 @@ void Renderer::render(float perspective, float aspect, mat4 const& orientation, · 35 unmodified lines | |||
| 52 | matrix[3][1] = 0.0f; | 53 | matrix[3][1] = 0.0f; |
| 53 | matrix[3][2] = 0.0f; | 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 | // extract local z vector | 60 | // extract local z vector |
| 56 | vec3 ahead = vec3(matrix[2]); | 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 | floodFill(cursor, TileSelection(*this, _tileArray, _tileArray + _tiling.getTileCount(), (TileSelection::Cursor*) _batchCountArray)); | 79 | floodFill(cursor, TileSelection(*this, _tileArray, _tileArray + _tiling.getTileCount(), (TileSelection::Cursor*) _batchCountArray)); |
| 75 | 80 | ||
| 76 | this->glBatch(glm::value_ptr(matrix), prepareBatch((unsigned*) _batchOffs, _outIndexPos), alpha); | 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 | // renderer construction | 88 | // renderer construction |
| @@ -22,6 +22,20 @@ AddressBarDialog::AddressBarDialog(QQuickItem* parent) : OffscreenQmlDialog(pare · 21 unmodified lines | |||
| 22 | connect(addressManager.data(), &AddressManager::lookupResultIsOffline, this, &AddressBarDialog::displayAddressOfflineMessage); | 22 | connect(addressManager.data(), &AddressManager::lookupResultIsOffline, this, &AddressBarDialog::displayAddressOfflineMessage); |
| 23 | connect(addressManager.data(), &AddressManager::lookupResultIsNotFound, this, &AddressBarDialog::displayAddressNotFoundMessage); | 23 | connect(addressManager.data(), &AddressManager::lookupResultIsNotFound, this, &AddressBarDialog::displayAddressNotFoundMessage); |
| 24 | connect(addressManager.data(), &AddressManager::lookupResultsFinished, this, &AddressBarDialog::hide); | 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 | void AddressBarDialog::hide() { | 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 | void AddressBarDialog::displayAddressOfflineMessage() { | 62 | void AddressBarDialog::displayAddressOfflineMessage() { |
| 39 | OffscreenUi::error("That user or place is currently offline"); | 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 | Q_OBJECT | 19 | Q_OBJECT |
| 20 | HIFI_QML_DECL | 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 | public: | 24 | public: |
| 23 | AddressBarDialog(QQuickItem* parent = nullptr); | 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 | protected: | 33 | protected: |
| 26 | void displayAddressOfflineMessage(); | 34 | void displayAddressOfflineMessage(); |
| @@ -28,6 +36,11 @@ protected: · 1 unmodified line | |||
| 28 | void hide(); | 36 | void hide(); |
| 29 | 37 | ||
| 30 | Q_INVOKABLE void loadAddress(const QString& address); | 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 | #endif | 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 | #include <QOpenGLFramebufferObject> | 14 | #include <QOpenGLFramebufferObject> |
| 15 | #include <QOpenGLTexture> | 15 | #include <QOpenGLTexture> |
| 16 | 16 | ||
| 17 | #include <glm/gtc/type_ptr.hpp> | ||
| 18 | |||
| 17 | #include <avatar/AvatarManager.h> | 19 | #include <avatar/AvatarManager.h> |
| 20 | #include <DeferredLightingEffect.h> | ||
| 18 | #include <GLMHelpers.h> | 21 | #include <GLMHelpers.h> |
| 19 | #include <PathUtils.h> | ||
| 20 | #include <gpu/GLBackend.h> | 22 | #include <gpu/GLBackend.h> |
| 23 | #include <gpu/GLBackendShared.h> | ||
| 21 | #include <GLMHelpers.h> | 24 | #include <GLMHelpers.h> |
| 22 | #include <PerfStat.h> | ||
| 23 | #include <OffscreenUi.h> | 25 | #include <OffscreenUi.h> |
| 26 | #include <CursorManager.h> | ||
| 27 | #include <PerfStat.h> | ||
| 24 | 28 | ||
| 25 | #include "AudioClient.h" | 29 | #include "AudioClient.h" |
| 26 | #include "audio/AudioIOStatsRenderer.h" | 30 | #include "audio/AudioIOStatsRenderer.h" |
| 27 | #include "audio/AudioScope.h" | 31 | #include "audio/AudioScope.h" |
| 28 | #include "audio/AudioToolBox.h" | ||
| 29 | #include "Application.h" | 32 | #include "Application.h" |
| 30 | #include "ApplicationOverlay.h" | 33 | #include "ApplicationOverlay.h" |
| 31 | #include "devices/CameraToolBox.h" | ||
| 32 | 34 | ||
| 33 | #include "Util.h" | 35 | #include "Util.h" |
| 34 | #include "ui/Stats.h" | 36 | #include "ui/Stats.h" |
| 35 | 37 | #include "ui/AvatarInputs.h" | |
| 36 | // Used to animate the magnification windows | ||
| 37 | const float MAG_SPEED = 0.08f; | ||
| 38 | |||
| 39 | const quint64 MSECS_TO_USECS = 1000ULL; | ||
| 40 | 38 | ||
| 41 | const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f }; | 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 }; | 40 | const int AUDIO_METER_GAP = 5; |
| 43 | const float reticleSize = TWO_PI / 100.0f; | 41 | const int MUTE_ICON_PADDING = 10; |
| 44 | 42 | const vec4 CONNECTION_STATUS_BORDER_COLOR{ 1.0f, 0.0f, 0.0f, 0.8f }; | |
| 45 | |||
| 46 | const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f }; | ||
| 47 | const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f; | 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; | 47 | // TODO move somewhere useful |
| 50 | static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI; | 48 | static void fboViewport(QOpenGLFramebufferObject* fbo) { |
| 51 | static const glm::vec2 MOUSE_RANGE(MOUSE_YAW_RANGE, MOUSE_PITCH_RANGE); | 49 | auto size = fbo->size(); |
| 52 | 50 | glViewport(0, 0, size.width(), size.height()); | |
| 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))); | ||
| 58 | } | 51 | } |
| 59 | 52 | ||
| 60 | //Checks if the given ray intersects the sphere at the origin. result will store a multiplier that should | 53 | ApplicationOverlay::ApplicationOverlay() |
| 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) | ||
| 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 | auto geometryCache = DependencyManager::get<GeometryCache>(); | 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 | _domainStatusBorder = geometryCache->allocateID(); | 56 | _domainStatusBorder = geometryCache->allocateID(); |
| 165 | _magnifierBorder = geometryCache->allocateID(); | 57 | _magnifierBorder = geometryCache->allocateID(); |
| 166 | 58 | ||
| 167 | // Once we move UI rendering and screen rendering to different | 59 | // Once we move UI rendering and screen rendering to different |
| 168 | // threads, we need to use a sync object to deteremine when | 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 | // then release it back to the UI for re-use | 62 | // then release it back to the UI for re-use |
| 171 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); | 63 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); |
| 172 | connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [&](GLuint textureId) { | 64 | connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [&](GLuint textureId) { |
| 173 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); | 65 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); |
| 174 | offscreenUi->lockTexture(textureId); | 66 | offscreenUi->lockTexture(textureId); |
| 175 | assert(!glGetError()); | 67 | assert(!glGetError()); |
| 176 | std::swap(_newUiTexture, textureId); | 68 | std::swap(_uiTexture, textureId); |
| 177 | if (textureId) { | 69 | if (textureId) { |
| 178 | offscreenUi->releaseTexture(textureId); | 70 | offscreenUi->releaseTexture(textureId); |
| 179 | } | 71 | } |
| @@ -185,846 +77,81 @@ ApplicationOverlay::~ApplicationOverlay() { · 5 unmodified lines | |||
| 185 | 77 | ||
| 186 | // Renders the overlays either to a texture or to the screen | 78 | // Renders the overlays either to a texture or to the screen |
| 187 | void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { | 79 | void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { |
| 80 | CHECK_GL_ERROR(); | ||
| 188 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()"); | 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 | 83 | // TODO move to Application::idle()? |
| 196 | 84 | Stats::getInstance()->updateStats(); | |
| 197 | // Render 2D overlay | 85 | AvatarInputs::getInstance()->update(); |
| 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); | ||
| 207 | 86 | ||
| 208 | glPushMatrix(); { | 87 | buildFramebufferObject(); |
| 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); | ||
| 213 | 88 | ||
| 214 | glMatrixMode(GL_MODELVIEW); | 89 | // Execute the batch into our framebuffer |
| 215 | 90 | _overlayFramebuffer->bind(); | |
| 216 | renderAudioMeter(); | 91 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| 217 | renderCameraToggle(); | 92 | fboViewport(_overlayFramebuffer); |
| 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 | } | ||
| 240 | 93 | ||
| 241 | // A quick and dirty solution for compositing the old overlay | 94 | // Now render the overlay components together into a single texture |
| 242 | // texture with the new one | 95 | renderOverlays(renderArgs); |
| 243 | template <typename F> | 96 | renderStatsAndLogs(renderArgs); |
| 244 | void with_each_texture(GLuint firstPassTexture, GLuint secondPassTexture, F f) { | 97 | renderDomainConnectionStatusBorder(renderArgs); |
| 245 | glEnable(GL_TEXTURE_2D); | 98 | renderQmlUi(renderArgs); |
| 246 | glActiveTexture(GL_TEXTURE0); | 99 | _overlayFramebuffer->release(); |
| 247 | if (firstPassTexture) { | 100 | CHECK_GL_ERROR(); |
| 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); | ||
| 257 | } | 101 | } |
| 258 | 102 | ||
| 259 | // Draws the FBO texture for the screen | 103 | void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) { |
| 260 | void ApplicationOverlay::displayOverlayTexture() { | 104 | if (_uiTexture) { |
| 261 | if (_alpha == 0.0f) { | 105 | gpu::Batch batch; |
| 262 | return; | 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. | 117 | void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) { |
| 314 | void ApplicationOverlay::displayOverlayTextureHmd(Camera& whichCamera) { | 118 | glm::vec2 size = qApp->getCanvasSize(); |
| 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 | |||
| 327 | 119 | ||
| 328 | //Update and draw the magnifiers | 120 | mat4 legacyProjection = glm::ortho<float>(0, size.x, size.y, 0, ORTHO_NEAR_CLIP, ORTHO_FAR_CLIP); |
| 329 | MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | 121 | glMatrixMode(GL_PROJECTION); |
| 330 | const glm::quat& orientation = myAvatar->getOrientation(); | 122 | glPushMatrix(); |
| 331 | // Always display the HMD overlay relative to the camera position but | 123 | glLoadMatrixf(glm::value_ptr(legacyProjection)); |
| 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; | ||
| 339 | glMatrixMode(GL_MODELVIEW); | 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 | glDisable(GL_DEPTH_TEST); | 126 | glDisable(GL_DEPTH_TEST); |
| 441 | 127 | glDisable(GL_LIGHTING); | |
| 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 | ||
| 458 | glEnable(GL_BLEND); | 128 | glEnable(GL_BLEND); |
| 459 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | 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), | 131 | // give external parties a change to hook in |
| 472 | glm::vec3(x + mouseX + reticleSize, y + mouseY, -distance), | 132 | emit qApp->renderingOverlay(); |
| 473 | glm::vec3(x + mouseX + reticleSize, y + mouseY - reticleSize, -distance), | 133 | qApp->getOverlays().renderHUD(renderArgs); |
| 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); | ||
| 478 | 134 | ||
| 479 | glEnable(GL_DEPTH_TEST); | 135 | glMatrixMode(GL_PROJECTION); |
| 480 | |||
| 481 | glPopMatrix(); | 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 | glMatrixMode(GL_MODELVIEW); | 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); | 139 | renderArgs->_context->syncCache(); |
| 786 | glDisable(GL_TEXTURE_2D); | 140 | fboViewport(_overlayFramebuffer); |
| 787 | glDisable(GL_BLEND); | ||
| 788 | } | 141 | } |
| 789 | 142 | ||
| 790 | //Renders a small magnification of the currently bound texture at the coordinates | 143 | void ApplicationOverlay::renderRearViewToFbo(RenderArgs* renderArgs) { |
| 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(); | ||
| 857 | } | 144 | } |
| 858 | 145 | ||
| 859 | const int AUDIO_METER_GAP = 5; | 146 | void ApplicationOverlay::renderRearView(RenderArgs* renderArgs) { |
| 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); | ||
| 878 | } | 147 | } |
| 879 | 148 | ||
| 880 | void ApplicationOverlay::renderAudioMeter() { | 149 | void ApplicationOverlay::renderStatsAndLogs(RenderArgs* renderArgs) { |
| 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 | |||
| 1003 | // Display stats and log text onscreen | 150 | // Display stats and log text onscreen |
| 1004 | glLineWidth(1.0f); | ||
| 1005 | glPointSize(1.0f); | ||
| 1006 | 151 | ||
| 1007 | // Determine whether to compute timing details | 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 | // Show on-screen msec timer | 155 | // Show on-screen msec timer |
| 1029 | if (Menu::getInstance()->isOptionChecked(MenuOption::FrameTimer)) { | 156 | if (Menu::getInstance()->isOptionChecked(MenuOption::FrameTimer)) { |
| 1030 | auto canvasSize = qApp->getCanvasSize(); | 157 | auto canvasSize = qApp->getCanvasSize(); |
| @@ -1036,159 +163,77 @@ void ApplicationOverlay::renderStatsAndLogs() { · 5 unmodified lines | |||
| 1036 | drawText(canvasSize.x - 100, canvasSize.y - timerBottom, | 163 | drawText(canvasSize.x - 100, canvasSize.y - timerBottom, |
| 1037 | 0.30f, 0.0f, 0, frameTimer.toUtf8().constData(), WHITE_TEXT); | 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 | nodeBoundsDisplay.drawOverlay(); | 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 | auto nodeList = DependencyManager::get<NodeList>(); | 195 | auto nodeList = DependencyManager::get<NodeList>(); |
| 1044 | |||
| 1045 | if (nodeList && !nodeList->getDomainHandler().isConnected()) { | 196 | if (nodeList && !nodeList->getDomainHandler().isConnected()) { |
| 197 | gpu::Batch batch; | ||
| 1046 | auto geometryCache = DependencyManager::get<GeometryCache>(); | 198 | auto geometryCache = DependencyManager::get<GeometryCache>(); |
| 1047 | auto canvasSize = qApp->getCanvasSize(); | 199 | geometryCache->useSimpleDrawPipeline(batch); |
| 1048 | if ((int)canvasSize.x != _previousBorderWidth || (int)canvasSize.y != _previousBorderHeight) { | 200 | batch.setProjectionTransform(mat4()); |
| 1049 | glm::vec4 color(CONNECTION_STATUS_BORDER_COLOR[0], | 201 | batch.setModelTransform(mat4()); |
| 1050 | CONNECTION_STATUS_BORDER_COLOR[1], | 202 | batch.setUniformTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture()); |
| 1051 | CONNECTION_STATUS_BORDER_COLOR[2], 1.0f); | 203 | batch._glLineWidth(CONNECTION_STATUS_BORDER_LINE_WIDTH); |
| 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 | } | ||
| 1069 | 204 | ||
| 1070 | ApplicationOverlay::TexturedHemisphere::TexturedHemisphere() : | 205 | // TODO animate the disconnect border for some excitement while not connected? |
| 1071 | _vertices(0), | 206 | //double usecs = usecTimestampNow(); |
| 1072 | _indices(0), | 207 | //double secs = usecs / 1000000.0; |
| 1073 | _framebufferObject(NULL), | 208 | //float scaleAmount = 1.0f + (0.01f * sin(secs * 5.0f)); |
| 1074 | _vbo(0, 0) { | 209 | //batch.setModelTransform(glm::scale(mat4(), vec3(scaleAmount))); |
| 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 | } | ||
| 1091 | 210 | ||
| 1092 | void ApplicationOverlay::TexturedHemisphere::buildVBO(const float fov, | 211 | geometryCache->renderVertices(batch, gpu::LINE_STRIP, _domainStatusBorder); |
| 1093 | const float aspectRatio, | 212 | renderArgs->_context->syncCache(); |
| 1094 | const int slices, | 213 | renderArgs->_context->render(batch); |
| 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 | } | ||
| 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() { | 217 | GLuint ApplicationOverlay::getOverlayTexture() { |
| 1168 | if (_vbo.first != 0) { | 218 | if (!_overlayFramebuffer) { |
| 1169 | glDeleteBuffers(1, &_vbo.first); | 219 | return 0; |
| 1170 | _vbo.first = 0; | ||
| 1171 | } | ||
| 1172 | if (_vbo.second != 0) { | ||
| 1173 | glDeleteBuffers(1, &_vbo.second); | ||
| 1174 | _vbo.second = 0; | ||
| 1175 | } | 220 | } |
| 221 | return _overlayFramebuffer->texture(); | ||
| 1176 | } | 222 | } |
| 1177 | 223 | ||
| 1178 | void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() { | 224 | void ApplicationOverlay::buildFramebufferObject() { |
| 1179 | auto canvasSize = qApp->getCanvasSize(); | 225 | QSize fboSize = qApp->getDeviceSize(); |
| 1180 | QSize fboSize = QSize(canvasSize.x, canvasSize.y); | 226 | if (_overlayFramebuffer && fboSize == _overlayFramebuffer->size()) { |
| 1181 | if (_framebufferObject != NULL && fboSize == _framebufferObject->size()) { | 227 | // Already built |
| 1182 | // Already build | ||
| 1183 | return; | 228 | return; |
| 1184 | } | 229 | } |
| 1185 | 230 | ||
| 1186 | if (_framebufferObject != NULL) { | 231 | if (_overlayFramebuffer) { |
| 1187 | delete _framebufferObject; | 232 | delete _overlayFramebuffer; |
| 1188 | } | 233 | } |
| 1189 | 234 | ||
| 1190 | _framebufferObject = new QOpenGLFramebufferObject(fboSize, QOpenGLFramebufferObject::Depth); | 235 | _overlayFramebuffer = new QOpenGLFramebufferObject(fboSize, QOpenGLFramebufferObject::Depth); |
| 1191 | glBindTexture(GL_TEXTURE_2D, getTexture()); | 236 | glBindTexture(GL_TEXTURE_2D, getOverlayTexture()); |
| 1192 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 237 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| 1193 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 238 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 1194 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); | 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 | glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); | 242 | glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); |
| 1198 | glBindTexture(GL_TEXTURE_2D, 0); | 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 | #define hifi_ApplicationOverlay_h | 13 | #define hifi_ApplicationOverlay_h |
| 14 | 14 | ||
| 15 | #include <gpu/Texture.h> | 15 | #include <gpu/Texture.h> |
| 16 | class Camera; | ||
| 17 | class Overlays; | ||
| 18 | class QOpenGLFramebufferObject; | 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 | // Handles the drawing of the overlays to the screen | 18 | // Handles the drawing of the overlays to the screen |
| 27 | // TODO, move divide up the rendering, displaying and input handling | 19 | // TODO, move divide up the rendering, displaying and input handling |
| 28 | // facilities of this class | 20 | // facilities of this class |
| @@ -33,122 +25,26 @@ public: · 4 unmodified lines | |||
| 33 | ~ApplicationOverlay(); | 25 | ~ApplicationOverlay(); |
| 34 | 26 | ||
| 35 | void renderOverlay(RenderArgs* renderArgs); | 27 | void renderOverlay(RenderArgs* renderArgs); |
| 36 | void displayOverlayTexture(); | 28 | GLuint getOverlayTexture(); |
| 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; } | ||
| 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 | private: | 30 | private: |
| 69 | // Interleaved vertex data | 31 | void renderStatsAndLogs(RenderArgs* renderArgs); |
| 70 | struct TextureVertex { | 32 | void renderDomainConnectionStatusBorder(RenderArgs* renderArgs); |
| 71 | glm::vec3 position; | 33 | void renderRearViewToFbo(RenderArgs* renderArgs); |
| 72 | glm::vec2 uv; | 34 | void renderRearView(RenderArgs* renderArgs); |
| 73 | }; | 35 | void renderQmlUi(RenderArgs* renderArgs); |
| 74 | 36 | void renderOverlays(RenderArgs* renderArgs); | |
| 75 | typedef QPair<GLuint, GLuint> VerticesIndices; | 37 | void buildFramebufferObject(); |
| 76 | class TexturedHemisphere { | 38 | |
| 77 | public: | 39 | float _alpha{ 1.0f }; |
| 78 | TexturedHemisphere(); | 40 | float _trailingAudioLoudness{ 0.0f }; |
| 79 | ~TexturedHemisphere(); | 41 | GLuint _uiTexture{ 0 }; |
| 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); | ||
| 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 | int _domainStatusBorder; | 43 | int _domainStatusBorder; |
| 142 | int _magnifierBorder; | 44 | int _magnifierBorder; |
| 143 | 45 | ||
| 144 | int _previousBorderWidth; | 46 | ivec2 _previousBorderSize{ -1 }; |
| 145 | int _previousBorderHeight; | 47 | QOpenGLFramebufferObject* _overlayFramebuffer{ nullptr }; |
| 146 | |||
| 147 | glm::vec3 _previousMagnifierBottomLeft; | ||
| 148 | glm::vec3 _previousMagnifierBottomRight; | ||
| 149 | glm::vec3 _previousMagnifierTopLeft; | ||
| 150 | glm::vec3 _previousMagnifierTopRight; | ||
| 151 | |||
| 152 | }; | 48 | }; |
| 153 | 49 | ||
| 154 | #endif // hifi_ApplicationOverlay_h | 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 | #include <QtWidgets> | 46 | #include <QtWidgets> |
| 42 | 47 | ||
| 48 | #ifdef __GNUC__ | ||
| 49 | #pragma GCC diagnostic pop | ||
| 50 | #endif | ||
| 51 | |||
| 43 | #include "FlowLayout.h" | 52 | #include "FlowLayout.h" |
| 44 | //! [1] | 53 | //! [1] |
| 45 | FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing) | 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 | this->QDialog::setLayout(form); | 57 | this->QDialog::setLayout(form); |
| 58 | 58 | ||
| 59 | _wasMoved = false; | ||
| 60 | _previousRect = Application::getInstance()->getWindow()->rect(); | ||
| 61 | Application::getInstance()->getWindow()->activateWindow(); | 59 | Application::getInstance()->getWindow()->activateWindow(); |
| 62 | 60 | ||
| 63 | // watch for our application window moving screens. If it does we want to update our screen details | 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 | if (!_inHDMMode) { | 134 | if (!_inHDMMode) { |
| 137 | _switchModeButton->setText("Leave HMD Mode"); | 135 | _switchModeButton->setText("Leave HMD Mode"); |
| 138 | _debugDetails->setText(getDebugDetails()); | 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 | // if we're on a single screen setup, then hide our tools window when entering HMD mode | 138 | // if we're on a single screen setup, then hide our tools window when entering HMD mode |
| 159 | if (QApplication::desktop()->screenCount() == 1) { | 139 | if (QApplication::desktop()->screenCount() == 1) { |
| @@ -161,58 +141,21 @@ void HMDToolsDialog::enterHDMMode() { · 1 unmodified line | |||
| 161 | } | 141 | } |
| 162 | 142 | ||
| 163 | Application::getInstance()->setEnableVRMode(true); | 143 | Application::getInstance()->setEnableVRMode(true); |
| 164 | 144 | ||
| 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 | |||
| 174 | _inHDMMode = true; | 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 | void HMDToolsDialog::leaveHDMMode() { | 149 | void HMDToolsDialog::leaveHDMMode() { |
| 186 | if (_inHDMMode) { | 150 | if (_inHDMMode) { |
| 187 | _switchModeButton->setText("Enter HMD Mode"); | 151 | _switchModeButton->setText("Enter HMD Mode"); |
| 188 | _debugDetails->setText(getDebugDetails()); | 152 | _debugDetails->setText(getDebugDetails()); |
| 189 | |||
| 190 | Application::getInstance()->setEnableVRMode(false); | 153 | Application::getInstance()->setEnableVRMode(false); |
| 191 | Application::getInstance()->setFullscreen(false); | ||
| 192 | Application::getInstance()->getWindow()->activateWindow(); | 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 | _inHDMMode = false; | 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 | void HMDToolsDialog::reject() { | 159 | void HMDToolsDialog::reject() { |
| 217 | // Just regularly close upon ESC | 160 | // Just regularly close upon ESC |
| 218 | close(); | 161 | close(); |
| @@ -244,13 +187,15 @@ void HMDToolsDialog::hideEvent(QHideEvent* event) { · 25 unmodified lines | |||
| 244 | 187 | ||
| 245 | void HMDToolsDialog::aboutToQuit() { | 188 | void HMDToolsDialog::aboutToQuit() { |
| 246 | if (_inHDMMode) { | 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 | leaveHDMMode(); | 192 | leaveHDMMode(); |
| 248 | } | 193 | } |
| 249 | } | 194 | } |
| 250 | 195 | ||
| 251 | void HMDToolsDialog::screenCountChanged(int newCount) { | 196 | void HMDToolsDialog::screenCountChanged(int newCount) { |
| 252 | if (!OculusManager::isConnected()) { | 197 | if (!OculusManager::isConnected()) { |
| 253 | OculusManager::connect(); | 198 | //OculusManager::connect(); |
| 254 | } | 199 | } |
| 255 | int hmdScreenNumber = OculusManager::getHMDScreen(); | 200 | int hmdScreenNumber = OculusManager::getHMDScreen(); |
| 256 | 201 | ||
| @@ -35,8 +35,6 @@ signals: · 34 unmodified lines | |||
| 35 | public slots: | 35 | public slots: |
| 36 | void reject(); | 36 | void reject(); |
| 37 | void switchModeClicked(bool checked); | 37 | void switchModeClicked(bool checked); |
| 38 | void activateWindowAfterEnterMode(); | ||
| 39 | void moveWindowAfterLeaveMode(); | ||
| 40 | void applicationWindowScreenChanged(QScreen* screen); | 38 | void applicationWindowScreenChanged(QScreen* screen); |
| 41 | void aboutToQuit(); | 39 | void aboutToQuit(); |
| 42 | void screenCountChanged(int newCount); | 40 | void screenCountChanged(int newCount); |
| @@ -51,8 +49,6 @@ private: · 8 unmodified lines | |||
| 51 | void enterHDMMode(); | 49 | void enterHDMMode(); |
| 52 | void leaveHDMMode(); | 50 | void leaveHDMMode(); |
| 53 | 51 | ||
| 54 | bool _wasMoved; | ||
| 55 | QRect _previousRect; | ||
| 56 | QScreen* _previousScreen; | 52 | QScreen* _previousScreen; |
| 57 | QScreen* _hmdScreen; | 53 | QScreen* _hmdScreen; |
| 58 | int _hmdScreenNumber; | 54 | int _hmdScreenNumber; |
| @@ -11,10 +11,19 @@ · 10 unmodified lines | |||
| 11 | 11 | ||
| 12 | #include "InterfaceConfig.h" | 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 | #include <QDesktopWidget> | 19 | #include <QDesktopWidget> |
| 15 | #include <QTextBlock> | 20 | #include <QTextBlock> |
| 16 | #include <QtGui> | 21 | #include <QtGui> |
| 17 | 22 | ||
| 23 | #ifdef __GNUC__ | ||
| 24 | #pragma GCC diagnostic pop | ||
| 25 | #endif | ||
| 26 | |||
| 18 | #include <PathUtils.h> | 27 | #include <PathUtils.h> |
| 19 | #include <SharedUtil.h> | 28 | #include <SharedUtil.h> |
| 20 | 29 | ||
| @@ -175,7 +175,7 @@ void PreferencesDialog::loadPreferences() { · 174 unmodified lines | |||
| 175 | 175 | ||
| 176 | ui.maxOctreePPSSpin->setValue(qApp->getMaxOctreePacketsPerSecond()); | 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 | SixenseManager& sixense = SixenseManager::getInstance(); | 180 | SixenseManager& sixense = SixenseManager::getInstance(); |
| 181 | ui.sixenseReticleMoveSpeedSpin->setValue(sixense.getReticleMoveSpeed()); | 181 | ui.sixenseReticleMoveSpeedSpin->setValue(sixense.getReticleMoveSpeed()); |
| @@ -239,7 +239,7 @@ void PreferencesDialog::savePreferences() { · 57 unmodified lines | |||
| 239 | 239 | ||
| 240 | qApp->setMaxOctreePacketsPerSecond(ui.maxOctreePPSSpin->value()); | 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 | SixenseManager& sixense = SixenseManager::getInstance(); | 244 | SixenseManager& sixense = SixenseManager::getInstance(); |
| 245 | sixense.setReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value()); | 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 | 2 | // Created by Bradley Austin Davis 2015/06/17 |
| 3 | // interface/src/ui | ||
| 4 | // | ||
| 5 | // Created by Lucas Crisman on 22/03/14. | ||
| 6 | // Copyright 2013 High Fidelity, Inc. | 3 | // Copyright 2013 High Fidelity, Inc. |
| 7 | // | 4 | // |
| 8 | // Distributed under the Apache License, Version 2.0. | 5 | // Distributed under the Apache License, Version 2.0. |
| 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | 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 | #include <glm/glm.hpp> | 16 | #include <glm/glm.hpp> |
| 17 | #include <glm/gtx/component_wise.hpp> | 17 | #include <glm/gtx/component_wise.hpp> |
| @@ -25,147 +25,31 @@ · 7 unmodified lines | |||
| 25 | #include <LODManager.h> | 25 | #include <LODManager.h> |
| 26 | #include <PerfStat.h> | 26 | #include <PerfStat.h> |
| 27 | 27 | ||
| 28 | #include "Stats.h" | ||
| 29 | #include "BandwidthRecorder.h" | 28 | #include "BandwidthRecorder.h" |
| 30 | #include "InterfaceConfig.h" | 29 | #include "InterfaceConfig.h" |
| 31 | #include "Menu.h" | 30 | #include "Menu.h" |
| 32 | #include "Util.h" | 31 | #include "Util.h" |
| 33 | #include "SequenceNumberStats.h" | 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; | 36 | using namespace std; |
| 38 | const int STATS_PELS_INITIALOFFSET = 12; | ||
| 39 | 37 | ||
| 40 | const int STATS_GENERAL_MIN_WIDTH = 165; | 38 | static Stats* INSTANCE{ nullptr }; |
| 41 | const int STATS_PING_MIN_WIDTH = 190; | ||
| 42 | const int STATS_GEO_MIN_WIDTH = 240; | ||
| 43 | const int STATS_OCTREE_MIN_WIDTH = 410; | ||
| 44 | 39 | ||
| 45 | Stats* Stats::getInstance() { | 40 | Stats* Stats::getInstance() { |
| 46 | static Stats stats; | 41 | if (!INSTANCE) { |
| 47 | return &stats; | 42 | Stats::registerType(); |
| 48 | } | 43 | Stats::show(); |
| 49 | 44 | Q_ASSERT(INSTANCE); | |
| 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); | ||
| 153 | } | 45 | } |
| 46 | return INSTANCE; | ||
| 154 | } | 47 | } |
| 155 | 48 | ||
| 156 | 49 | Stats::Stats(QQuickItem* parent) : QQuickItem(parent) { | |
| 157 | // translucent background box that makes stats more readable | 50 | INSTANCE = this; |
| 158 | void Stats::drawBackground(unsigned int rgba, int x, int y, int width, int height) { | 51 | const QFont font = QFontDatabase::systemFont(QFontDatabase::FixedFont); |
| 159 | glm::vec4 color(((rgba >> 24) & 0xff) / 255.0f, | 52 | _monospaceFont = font.family(); |
| 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); | ||
| 169 | } | 53 | } |
| 170 | 54 | ||
| 171 | bool Stats::includeTimingRecord(const QString& name) { | 55 | bool Stats::includeTimingRecord(const QString& name) { |
| @@ -190,161 +74,70 @@ bool Stats::includeTimingRecord(const QString& name) { · 18 unmodified lines | |||
| 190 | return false; | 74 | return false; |
| 191 | } | 75 | } |
| 192 | 76 | ||
| 193 | // display expanded or contracted stats | 77 | #define STAT_UPDATE(name, src) \ |
| 194 | void Stats::display( | 78 | { \ |
| 195 | const float* color, | 79 | auto val = src; \ |
| 196 | int horizontalOffset, | 80 | if (_##name != val) { \ |
| 197 | float fps, | 81 | _##name = val; \ |
| 198 | int inPacketsPerSecond, | 82 | emit name##Changed(); \ |
| 199 | int outPacketsPerSecond, | 83 | } \ |
| 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; | ||
| 220 | } | 84 | } |
| 221 | 85 | ||
| 222 | glPointSize(1.0f); | 86 | #define STAT_UPDATE_FLOAT(name, src, epsilon) \ |
| 223 | 87 | { \ | |
| 224 | // we need to take one avatar out so we don't include ourselves | 88 | float val = src; \ |
| 225 | int totalAvatars = DependencyManager::get<AvatarManager>()->size() - 1; | 89 | if (fabs(_##name - val) >= epsilon) { \ |
| 226 | int totalServers = DependencyManager::get<NodeList>()->size(); | 90 | _##name = val; \ |
| 227 | 91 | emit name##Changed(); \ | |
| 228 | lines = 5; | 92 | } \ |
| 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 | } | ||
| 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()) { | 96 | void Stats::updateStats() { |
| 299 | i.next(); | 97 | if (!Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { |
| 300 | if (includeTimingRecord(i.key())) { | 98 | if (isVisible()) { |
| 301 | float averageTime = (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC; | 99 | setVisible(false); |
| 302 | sortedRecords.insertMulti(averageTime, i.key()); | ||
| 303 | } | ||
| 304 | } | 100 | } |
| 305 | 101 | return; | |
| 306 | int linesDisplayed = 0; | 102 | } else { |
| 307 | QMapIterator<float, QString> j(sortedRecords); | 103 | if (!isVisible()) { |
| 308 | j.toBack(); | 104 | setVisible(true); |
| 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 | } | ||
| 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)) { | 115 | auto nodeList = DependencyManager::get<NodeList>(); |
| 334 | int pingAudio = -1, pingAvatar = -1, pingVoxel = -1, pingOctreeMax = -1; | 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 | SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer); | 130 | SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer); |
| 338 | SharedNodePointer avatarMixerNode = nodeList->soloNodeOfType(NodeType::AvatarMixer); | 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; | 135 | //// Now handle voxel servers, since there could be more than one, we average their ping times |
| 341 | pingAvatar = avatarMixerNode ? avatarMixerNode->getPingMs() : -1; | ||
| 342 | |||
| 343 | // Now handle voxel servers, since there could be more than one, we average their ping times | ||
| 344 | unsigned long totalPingOctree = 0; | 136 | unsigned long totalPingOctree = 0; |
| 345 | int octreeServerCount = 0; | 137 | int octreeServerCount = 0; |
| 346 | 138 | int pingOctreeMax = 0; | |
| 347 | nodeList->eachNode([&totalPingOctree, &pingOctreeMax, &octreeServerCount](const SharedNodePointer& node){ | 139 | int pingVoxel; |
| 140 | nodeList->eachNode([&](const SharedNodePointer& node) { | ||
| 348 | // TODO: this should also support entities | 141 | // TODO: this should also support entities |
| 349 | if (node->getType() == NodeType::EntityServer) { | 142 | if (node->getType() == NodeType::EntityServer) { |
| 350 | totalPingOctree += node->getPingMs(); | 143 | totalPingOctree += node->getPingMs(); |
| @@ -359,168 +152,85 @@ void Stats::display( · 8 unmodified lines | |||
| 359 | pingVoxel = totalPingOctree / octreeServerCount; | 152 | pingVoxel = totalPingOctree / octreeServerCount; |
| 360 | } | 153 | } |
| 361 | 154 | ||
| 362 | lines = _expanded ? 4 : 3; | 155 | //STAT_UPDATE(entitiesPing, pingVoxel); |
| 363 | 156 | //if (_expanded) { | |
| 364 | // only draw our background if column one didn't draw a wide background | 157 | // QString voxelMaxPing; |
| 365 | if (columnOneWidth == _generalStatsWidth) { | 158 | // if (pingVoxel >= 0) { // Average is only meaningful if pingVoxel is valid. |
| 366 | drawBackground(backgroundColor, horizontalOffset, 0, _pingStatsWidth, (lines + 1) * STATS_PELS_PER_LINE); | 159 | // voxelMaxPing = QString("Voxel max ping: %1").arg(pingOctreeMax); |
| 367 | } | 160 | // } else { |
| 368 | horizontalOffset += 5; | 161 | // voxelMaxPing = QString("Voxel max ping: --"); |
| 369 | 162 | // } | |
| 370 | 163 | } else { | |
| 371 | QString audioPing; | 164 | // -2 causes the QML to hide the ping column |
| 372 | if (pingAudio >= 0) { | 165 | STAT_UPDATE(audioPing, -2); |
| 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; | ||
| 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 | if (_expanded) { | 175 | if (_expanded) { |
| 439 | SharedNodePointer avatarMixer = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::AvatarMixer); | 176 | SharedNodePointer avatarMixer = nodeList->soloNodeOfType(NodeType::AvatarMixer); |
| 440 | if (avatarMixer) { | 177 | if (avatarMixer) { |
| 441 | avatarMixerStats = QString("Avatar Mixer: %1 kbps, %2 pps"). | 178 | STAT_UPDATE(avatarMixerKbps, roundf( |
| 442 | arg(roundf(bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer) + | 179 | bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AvatarMixer) + |
| 443 | bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AudioMixer))). | 180 | bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AvatarMixer))); |
| 444 | arg(roundf(bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer) + | 181 | STAT_UPDATE(avatarMixerPps, roundf( |
| 445 | bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer))); | 182 | bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AvatarMixer) + |
| 183 | bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AvatarMixer))); | ||
| 446 | } else { | 184 | } else { |
| 447 | avatarMixerStats = QString("No Avatar Mixer"); | 185 | STAT_UPDATE(avatarMixerKbps, -1); |
| 186 | STAT_UPDATE(avatarMixerPps, -1); | ||
| 448 | } | 187 | } |
| 449 | 188 | SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer); | |
| 450 | verticalOffset += STATS_PELS_PER_LINE; | 189 | if (audioMixerNode) { |
| 451 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarMixerStats.toUtf8().constData(), color); | 190 | STAT_UPDATE(audioMixerKbps, roundf( |
| 452 | 191 | bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer) + | |
| 453 | stringstream downloads; | 192 | bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AudioMixer))); |
| 454 | downloads << "Downloads: "; | 193 | STAT_UPDATE(audioMixerPps, roundf( |
| 455 | foreach (Resource* resource, ResourceCache::getLoadingRequests()) { | 194 | bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer) + |
| 456 | downloads << (int)(resource->getProgress() * 100.0f) << "% "; | 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; | 201 | STAT_UPDATE(downloads, ResourceCache::getLoadingRequests().size()); |
| 465 | horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3; | 202 | STAT_UPDATE(downloadsPending, ResourceCache::getPendingRequestCount()); |
| 466 | 203 | // TODO fix to match original behavior | |
| 467 | lines = _expanded ? 10 : 3; | 204 | //stringstream downloads; |
| 468 | 205 | //downloads << "Downloads: "; | |
| 469 | drawBackground(backgroundColor, horizontalOffset, 0, canvasSize.x - horizontalOffset, | 206 | //foreach(Resource* resource, ) { |
| 470 | (lines + 1) * STATS_PELS_PER_LINE); | 207 | // downloads << (int)(resource->getProgress() * 100.0f) << "% "; |
| 471 | horizontalOffset += 5; | 208 | //} |
| 472 | 209 | //downloads << "(" << << " pending)"; | |
| 473 | // Model/Entity render details | 210 | } // expanded avatar column |
| 474 | octreeStats.str(""); | 211 | |
| 475 | octreeStats << "Triangles: " << _renderDetails._trianglesRendered | 212 | // Fourth column, octree stats |
| 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: ["; | ||
| 505 | int serverCount = 0; | 213 | int serverCount = 0; |
| 506 | int movingServerCount = 0; | 214 | int movingServerCount = 0; |
| 507 | unsigned long totalNodes = 0; | 215 | unsigned long totalNodes = 0; |
| 508 | unsigned long totalInternal = 0; | 216 | unsigned long totalInternal = 0; |
| 509 | unsigned long totalLeaves = 0; | 217 | unsigned long totalLeaves = 0; |
| 218 | std::stringstream sendingModeStream(""); | ||
| 219 | sendingModeStream << "["; | ||
| 510 | NodeToOctreeSceneStats* octreeServerSceneStats = Application::getInstance()->getOcteeSceneStats(); | 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 | //const QUuid& uuid = i->first; | 222 | //const QUuid& uuid = i->first; |
| 513 | OctreeSceneStats& stats = i->second; | 223 | OctreeSceneStats& stats = i->second; |
| 514 | serverCount++; | 224 | serverCount++; |
| 515 | if (_expanded) { | 225 | if (_expanded) { |
| 516 | if (serverCount > 1) { | 226 | if (serverCount > 1) { |
| 517 | sendingMode << ","; | 227 | sendingModeStream << ","; |
| 518 | } | 228 | } |
| 519 | if (stats.isMoving()) { | 229 | if (stats.isMoving()) { |
| 520 | sendingMode << "M"; | 230 | sendingModeStream << "M"; |
| 521 | movingServerCount++; | 231 | movingServerCount++; |
| 522 | } else { | 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 | totalNodes += stats.getTotalElements(); | 238 | totalNodes += stats.getTotalElements(); |
| 529 | if (_expanded) { | 239 | if (_expanded) { |
| 530 | totalInternal += stats.getTotalInternal(); | 240 | totalInternal += stats.getTotalInternal(); |
| 531 | totalLeaves += stats.getTotalLeaves(); | 241 | totalLeaves += stats.getTotalLeaves(); |
| 532 | } | 242 | } |
| 533 | } | 243 | } |
| 534 | if (_expanded) { | 244 | if (_expanded) { |
| 535 | if (serverCount == 0) { | 245 | if (serverCount == 0) { |
| 536 | sendingMode << "---"; | 246 | sendingModeStream << "---"; |
| 537 | } | 247 | } |
| 538 | sendingMode << "] " << serverCount << " servers"; | 248 | sendingModeStream << "] " << serverCount << " servers"; |
| 539 | if (movingServerCount > 0) { | 249 | if (movingServerCount > 0) { |
| 540 | sendingMode << " <SCENE NOT STABLE>"; | 250 | sendingModeStream << " <SCENE NOT STABLE>"; |
| 541 | } else { | 251 | } else { |
| 542 | sendingMode << " <SCENE STABLE>"; | 252 | sendingModeStream << " <SCENE STABLE>"; |
| 543 | } | 253 | } |
| 544 | verticalOffset += STATS_PELS_PER_LINE; | 254 | QString sendingModeResult = sendingModeStream.str().c_str(); |
| 545 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)sendingMode.str().c_str(), color); | 255 | STAT_UPDATE(sendingMode, sendingModeResult); |
| 546 | } | 256 | } |
| 547 | 257 | ||
| 548 | // Incoming packets | 258 | // Incoming packets |
| 259 | QLocale locale(QLocale::English); | ||
| 260 | auto voxelPacketsToProcess = qApp->getOctreePacketProcessor().packetsToProcessCount(); | ||
| 549 | if (_expanded) { | 261 | if (_expanded) { |
| 550 | octreeStats.str(""); | 262 | std::stringstream octreeStats; |
| 551 | QString packetsString = locale.toString((int)voxelPacketsToProcess); | 263 | QString packetsString = locale.toString((int)voxelPacketsToProcess); |
| 552 | QString maxString = locale.toString((int)_recentMaxPackets); | 264 | QString maxString = locale.toString((int)_recentMaxPackets); |
| 553 | octreeStats << "Octree Packets to Process: " << qPrintable(packetsString) | 265 | octreeStats << "Octree Packets to Process: " << qPrintable(packetsString) |
| 554 | << " [Recent Max: " << qPrintable(maxString) << "]"; | 266 | << " [Recent Max: " << qPrintable(maxString) << "]"; |
| 555 | verticalOffset += STATS_PELS_PER_LINE; | 267 | QString str = octreeStats.str().c_str(); |
| 556 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | 268 | STAT_UPDATE(packetStats, str); |
| 269 | // drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | ||
| 557 | } | 270 | } |
| 558 | 271 | ||
| 559 | if (_resetRecentMaxPacketsSoon && voxelPacketsToProcess > 0) { | 272 | if (_resetRecentMaxPacketsSoon && voxelPacketsToProcess > 0) { |
| @@ -562,60 +275,102 @@ void Stats::display( · 2 unmodified lines | |||
| 562 | } | 275 | } |
| 563 | if (voxelPacketsToProcess == 0) { | 276 | if (voxelPacketsToProcess == 0) { |
| 564 | _resetRecentMaxPacketsSoon = true; | 277 | _resetRecentMaxPacketsSoon = true; |
| 565 | } else { | 278 | } else if (voxelPacketsToProcess > _recentMaxPackets) { |
| 566 | if (voxelPacketsToProcess > _recentMaxPackets) { | 279 | _recentMaxPackets = voxelPacketsToProcess; |
| 567 | _recentMaxPackets = voxelPacketsToProcess; | ||
| 568 | } | ||
| 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 | // Server Octree Elements | 282 | // Server Octree Elements |
| 576 | if (!_expanded) { | 283 | STAT_UPDATE(serverElements, totalNodes); |
| 577 | octreeStats.str(""); | 284 | STAT_UPDATE(localElements, OctreeElement::getNodeCount()); |
| 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 | } | ||
| 583 | 285 | ||
| 584 | if (_expanded) { | 286 | if (_expanded) { |
| 585 | octreeStats.str(""); | 287 | STAT_UPDATE(serverInternal, totalInternal); |
| 586 | octreeStats << "Octree Elements -"; | 288 | STAT_UPDATE(serverLeaves, totalLeaves); |
| 587 | verticalOffset += STATS_PELS_PER_LINE; | 289 | // Local Voxels |
| 588 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | 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); | 296 | bool performanceTimerIsActive = PerformanceTimer::isActive(); |
| 591 | QString serversLeavesString = locale.toString((uint)totalLeaves); | 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(""); | 305 | // we will also include room for 1 line per timing record and a header of 4 lines |
| 594 | octreeStats << " Server: " << qPrintable(serversTotalString) << | 306 | // Timing details... |
| 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); | ||
| 599 | 307 | ||
| 600 | // Local Voxels | 308 | // First iterate all the records, and for the ones that should be included, insert them into |
| 601 | unsigned long localInternal = OctreeElement::getInternalNodeCount(); | 309 | // a new Map sorted by average time... |
| 602 | unsigned long localLeaves = OctreeElement::getLeafNodeCount(); | 310 | bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen); |
| 603 | QString localInternalString = locale.toString((uint)localInternal); | 311 | QMap<float, QString> sortedRecords; |
| 604 | QString localLeavesString = locale.toString((uint)localLeaves); | 312 | const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords(); |
| 605 | 313 | QMapIterator<QString, PerformanceTimerRecord> i(allRecords); | |
| 606 | octreeStats.str(""); | 314 | |
| 607 | octreeStats << " Local: " << qPrintable(serversTotalString) << | 315 | while (i.hasNext()) { |
| 608 | " Internal: " << qPrintable(localInternalString) << | 316 | i.next(); |
| 609 | " Leaves: " << qPrintable(localLeavesString) << ""; | 317 | if (includeTimingRecord(i.key())) { |
| 610 | verticalOffset += STATS_PELS_PER_LINE; | 318 | float averageTime = (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC; |
| 611 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | 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 | 2 | // Created by Bradley Austin Davis 2015/06/17 |
| 3 | // interface/src/ui | ||
| 4 | // | ||
| 5 | // Created by Lucas Crisman on 22/03/14. | ||
| 6 | // Copyright 2013 High Fidelity, Inc. | 3 | // Copyright 2013 High Fidelity, Inc. |
| 7 | // | 4 | // |
| 8 | // Distributed under the Apache License, Version 2.0. | 5 | // Distributed under the Apache License, Version 2.0. |
| @@ -13,47 +10,139 @@ · 4 unmodified lines | |||
| 13 | #define hifi_Stats_h | 10 | #define hifi_Stats_h |
| 14 | 11 | ||
| 15 | #include <QObject> | 12 | #include <QObject> |
| 13 | #include <QQuickItem> | ||
| 14 | #include <QVector3D> | ||
| 16 | 15 | ||
| 16 | #include <OffscreenUi.h> | ||
| 17 | #include <RenderArgs.h> | 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 | Q_OBJECT | 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 | public: | 75 | public: |
| 23 | static Stats* getInstance(); | 76 | static Stats* getInstance(); |
| 24 | 77 | ||
| 25 | Stats(); | 78 | Stats(QQuickItem* parent = nullptr); |
| 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); | ||
| 36 | bool includeTimingRecord(const QString& name); | 79 | bool includeTimingRecord(const QString& name); |
| 37 | 80 | void setRenderDetails(const RenderDetails& details); | |
| 38 | void setRenderDetails(const RenderDetails& details) { _renderDetails = details; } | 81 | const QString& monospaceFont() { |
| 39 | 82 | return _monospaceFont; | |
| 40 | private: | 83 | } |
| 41 | static Stats* _sharedInstance; | 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 | 89 | void setExpanded(bool expanded) { |
| 46 | bool _resetRecentMaxPacketsSoon; | 90 | if (_expanded != expanded) { |
| 91 | _expanded = expanded; | ||
| 92 | emit expandedChanged(); | ||
| 93 | } | ||
| 94 | } | ||
| 47 | 95 | ||
| 48 | int _generalStatsWidth; | 96 | signals: |
| 49 | int _bandwidthStatsWidth; | 97 | void expandedChanged(); |
| 50 | int _pingStatsWidth; | 98 | void timingExpandedChanged(); |
| 51 | int _geoStatsWidth; | 99 | void serverCountChanged(); |
| 52 | int _octreeStatsWidth; | 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; | 140 | private: |
| 55 | 141 | int _recentMaxPackets{ 0 } ; // recent max incoming voxel packets to process | |
| 56 | RenderDetails _renderDetails; | 142 | bool _resetRecentMaxPacketsSoon{ true }; |
| 143 | bool _expanded{ false }; | ||
| 144 | bool _timingExpanded{ false }; | ||
| 145 | QString _monospaceFont; | ||
| 57 | }; | 146 | }; |
| 58 | 147 | ||
| 59 | #endif // hifi_Stats_h | 148 | #endif // hifi_Stats_h |
| @@ -53,7 +53,7 @@ void UserInputMapper::resetDevice(uint16 deviceID) { · 52 unmodified lines | |||
| 53 | 53 | ||
| 54 | int UserInputMapper::findDevice(QString name) { | 54 | int UserInputMapper::findDevice(QString name) { |
| 55 | for (auto device : _registeredDevices) { | 55 | for (auto device : _registeredDevices) { |
| 56 | if (device.second->_name == name) { | 56 | if (device.second->_name.split(" (")[0] == name) { |
| 57 | return device.first; | 57 | return device.first; |
| 58 | } | 58 | } |
| 59 | } | 59 | } |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | |||
| 11 | // include this before QGLWidget, which includes an earlier version of OpenGL | 11 | // include this before QGLWidget, which includes an earlier version of OpenGL |
| 12 | #include "InterfaceConfig.h" | 12 | #include "InterfaceConfig.h" |
| 13 | 13 | ||
| 14 | #include <DeferredLightingEffect.h> | ||
| 14 | #include <GeometryCache.h> | 15 | #include <GeometryCache.h> |
| 15 | #include <GlowEffect.h> | 16 | #include <GlowEffect.h> |
| 16 | #include <SharedUtil.h> | 17 | #include <SharedUtil.h> |
| @@ -75,20 +76,20 @@ void Circle3DOverlay::render(RenderArgs* args) { · 58 unmodified lines | |||
| 75 | 76 | ||
| 76 | float alpha = getAlpha(); | 77 | float alpha = getAlpha(); |
| 77 | 78 | ||
| 78 | if (alpha == 0.0) { | 79 | if (alpha == 0.0f) { |
| 79 | return; // do nothing if our alpha is 0, we're not visible | 80 | return; // do nothing if our alpha is 0, we're not visible |
| 80 | } | 81 | } |
| 81 | 82 | ||
| 82 | // Create the circle in the coordinates origin | 83 | // Create the circle in the coordinates origin |
| 83 | float outerRadius = getOuterRadius(); | 84 | float outerRadius = getOuterRadius(); |
| 84 | float innerRadius = getInnerRadius(); // only used in solid case | 85 | float innerRadius = getInnerRadius(); // only used in solid case |
| 85 | float startAt = getStartAt(); | 86 | float startAt = getStartAt(); |
| 86 | float endAt = getEndAt(); | 87 | float endAt = getEndAt(); |
| 87 | 88 | ||
| 88 | bool geometryChanged = (startAt != _lastStartAt || endAt != _lastEndAt || | 89 | bool geometryChanged = (startAt != _lastStartAt || endAt != _lastEndAt || |
| 89 | innerRadius != _lastInnerRadius || outerRadius != _lastOuterRadius); | 90 | innerRadius != _lastInnerRadius || outerRadius != _lastOuterRadius); |
| 90 | 91 | ||
| 91 | 92 | ||
| 92 | const float FULL_CIRCLE = 360.0f; | 93 | const float FULL_CIRCLE = 360.0f; |
| 93 | const float SLICES = 180.0f; // The amount of segment to create the circle | 94 | const float SLICES = 180.0f; // The amount of segment to create the circle |
| 94 | const float SLICE_ANGLE = FULL_CIRCLE / SLICES; | 95 | const float SLICE_ANGLE = FULL_CIRCLE / SLICES; |
| @@ -101,195 +102,178 @@ void Circle3DOverlay::render(RenderArgs* args) { · 6 unmodified lines | |||
| 101 | bool colorChanged = colorX.red != _lastColor.red || colorX.green != _lastColor.green || colorX.blue != _lastColor.blue; | 102 | bool colorChanged = colorX.red != _lastColor.red || colorX.green != _lastColor.green || colorX.blue != _lastColor.blue; |
| 102 | _lastColor = colorX; | 103 | _lastColor = colorX; |
| 103 | 104 | ||
| 104 | glDisable(GL_LIGHTING); | 105 | auto geometryCache = DependencyManager::get<GeometryCache>(); |
| 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); | ||
| 125 | 106 | ||
| 126 | glLineWidth(_lineWidth); | 107 | Transform transform; |
| 127 | 108 | transform.setTranslation(getCenter()); | |
| 128 | auto geometryCache = DependencyManager::get<GeometryCache>(); | 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 | 127 | QVector<glm::vec2> points; |
| 131 | // we just draw a line... | 128 | |
| 132 | if (getIsSolid()) { | 129 | float angle = startAt; |
| 133 | if (_quadVerticesID == GeometryCache::UNKNOWN_ID) { | 130 | float angleInRadians = glm::radians(angle); |
| 134 | _quadVerticesID = geometryCache->allocateID(); | 131 | glm::vec2 firstInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius); |
| 135 | } | 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) { | 141 | points << thisOuterPoint << thisInnerPoint; |
| 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; | ||
| 154 | 142 | ||
| 155 | angle += SLICE_ANGLE; | 143 | angle += SLICE_ANGLE; |
| 156 | } | 144 | } |
| 157 | 145 | ||
| 158 | // get the last slice portion.... | 146 | // get the last slice portion.... |
| 159 | angle = endAt; | 147 | angle = endAt; |
| 160 | angleInRadians = glm::radians(angle); | 148 | angleInRadians = glm::radians(angle); |
| 161 | glm::vec2 lastInnerPoint(cos(angleInRadians) * innerRadius, sin(angleInRadians) * innerRadius); | 149 | glm::vec2 lastInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius); |
| 162 | glm::vec2 lastOuterPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); | 150 | glm::vec2 lastOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); |
| 163 | 151 | ||
| 164 | points << lastOuterPoint << lastInnerPoint; | 152 | 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 | } | ||
| 197 | 153 | ||
| 198 | // get the last slice portion.... | 154 | geometryCache->updateVertices(_quadVerticesID, points, color); |
| 199 | angle = endAt; | 155 | } |
| 200 | angleInRadians = glm::radians(angle); | 156 | |
| 201 | glm::vec2 lastPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); | 157 | geometryCache->renderVertices(batch, gpu::QUAD_STRIP, _quadVerticesID); |
| 202 | points << lastPoint; | 158 | |
| 203 | 159 | } else { | |
| 204 | geometryCache->updateVertices(_lineVerticesID, points, color); | 160 | if (_lineVerticesID == GeometryCache::UNKNOWN_ID) { |
| 205 | } | 161 | _lineVerticesID = geometryCache->allocateID(); |
| 206 | 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 | if (getIsDashedLine()) { | 178 | if (getIsDashedLine()) { |
| 208 | geometryCache->renderVertices(gpu::LINES, _lineVerticesID); | 179 | angle += SLICE_ANGLE / 2.0f; // short gap |
| 209 | } else { | 180 | angleInRadians = glm::radians(angle); |
| 210 | geometryCache->renderVertices(gpu::LINE_STRIP, _lineVerticesID); | 181 | glm::vec2 dashStartPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); |
| 182 | points << dashStartPoint; | ||
| 211 | } | 183 | } |
| 212 | } | 184 | } |
| 213 | 185 | ||
| 214 | // draw our tick marks | 186 | // get the last slice portion.... |
| 215 | // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise | 187 | angle = endAt; |
| 216 | // we just draw a line... | 188 | angleInRadians = glm::radians(angle); |
| 217 | if (getHasTickMarks()) { | 189 | glm::vec2 lastPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); |
| 218 | 190 | points << lastPoint; | |
| 219 | if (_majorTicksVerticesID == GeometryCache::UNKNOWN_ID) { | 191 | |
| 220 | _majorTicksVerticesID = geometryCache->allocateID(); | 192 | geometryCache->updateVertices(_lineVerticesID, points, color); |
| 221 | } | 193 | } |
| 222 | if (_minorTicksVerticesID == GeometryCache::UNKNOWN_ID) { | 194 | |
| 223 | _minorTicksVerticesID = geometryCache->allocateID(); | 195 | if (getIsDashedLine()) { |
| 224 | } | 196 | geometryCache->renderVertices(batch, gpu::LINES, _lineVerticesID); |
| 225 | 197 | } else { | |
| 226 | if (geometryChanged) { | 198 | geometryCache->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID); |
| 227 | QVector<glm::vec2> majorPoints; | 199 | } |
| 228 | QVector<glm::vec2> minorPoints; | 200 | } |
| 229 | 201 | ||
| 230 | // draw our major tick marks | 202 | // draw our tick marks |
| 231 | if (getMajorTickMarksAngle() > 0.0f && getMajorTickMarksLength() != 0.0f) { | 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(); | 221 | float tickMarkAngle = getMajorTickMarksAngle(); |
| 234 | float angle = startAt - fmod(startAt, tickMarkAngle) + tickMarkAngle; | 222 | float angle = startAt - fmodf(startAt, tickMarkAngle) + tickMarkAngle; |
| 235 | float angleInRadians = glm::radians(angle); | 223 | float angleInRadians = glm::radians(angle); |
| 236 | float tickMarkLength = getMajorTickMarksLength(); | 224 | float tickMarkLength = getMajorTickMarksLength(); |
| 237 | float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; | 225 | float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; |
| 238 | float endRadius = startRadius + tickMarkLength; | 226 | 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; | ||
| 247 | 227 | ||
| 248 | angle += tickMarkAngle; | 228 | while (angle <= endAt) { |
| 249 | } | 229 | angleInRadians = glm::radians(angle); |
| 250 | } | 230 | |
| 251 | 231 | glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius); | |
| 252 | // draw our minor tick marks | 232 | glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius); |
| 253 | if (getMinorTickMarksAngle() > 0.0f && getMinorTickMarksLength() != 0.0f) { | 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(); | 243 | float tickMarkAngle = getMinorTickMarksAngle(); |
| 256 | float angle = startAt - fmod(startAt, tickMarkAngle) + tickMarkAngle; | 244 | float angle = startAt - fmodf(startAt, tickMarkAngle) + tickMarkAngle; |
| 257 | float angleInRadians = glm::radians(angle); | 245 | float angleInRadians = glm::radians(angle); |
| 258 | float tickMarkLength = getMinorTickMarksLength(); | 246 | float tickMarkLength = getMinorTickMarksLength(); |
| 259 | float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; | 247 | float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; |
| 260 | float endRadius = startRadius + tickMarkLength; | 248 | 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; | ||
| 269 | 249 | ||
| 270 | angle += tickMarkAngle; | 250 | while (angle <= endAt) { |
| 271 | } | 251 | angleInRadians = glm::radians(angle); |
| 272 | } | 252 | |
| 273 | 253 | glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius); | |
| 274 | xColor majorColorX = getMajorTickMarksColor(); | 254 | glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius); |
| 275 | glm::vec4 majorColor(majorColorX.red / MAX_COLOR, majorColorX.green / MAX_COLOR, majorColorX.blue / MAX_COLOR, alpha); | 255 | |
| 276 | 256 | minorPoints << thisPointA << thisPointB; | |
| 277 | geometryCache->updateVertices(_majorTicksVerticesID, majorPoints, majorColor); | 257 | |
| 278 | 258 | angle += tickMarkAngle; | |
| 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); | ||
| 283 | } | 259 | } |
| 284 | |||
| 285 | geometryCache->renderVertices(gpu::LINES, _majorTicksVerticesID); | ||
| 286 | |||
| 287 | geometryCache->renderVertices(gpu::LINES, _minorTicksVerticesID); | ||
| 288 | } | 260 | } |
| 289 | 261 | ||
| 290 | 262 | xColor majorColorX = getMajorTickMarksColor(); | |
| 291 | glPopMatrix(); | 263 | glm::vec4 majorColor(majorColorX.red / MAX_COLOR, majorColorX.green / MAX_COLOR, majorColorX.blue / MAX_COLOR, alpha); |
| 292 | glPopMatrix(); | 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 | if (geometryChanged) { | 278 | if (geometryChanged) { |
| 295 | _lastStartAt = startAt; | 279 | _lastStartAt = startAt; |
| @@ -297,15 +281,11 @@ void Circle3DOverlay::render(RenderArgs* args) { · 1 unmodified line | |||
| 297 | _lastInnerRadius = innerRadius; | 281 | _lastInnerRadius = innerRadius; |
| 298 | _lastOuterRadius = outerRadius; | 282 | _lastOuterRadius = outerRadius; |
| 299 | } | 283 | } |
| 300 | |||
| 301 | if (glower) { | ||
| 302 | delete glower; | ||
| 303 | } | ||
| 304 | } | 284 | } |
| 305 | 285 | ||
| 306 | void Circle3DOverlay::setProperties(const QScriptValue &properties) { | 286 | void Circle3DOverlay::setProperties(const QScriptValue &properties) { |
| 307 | Planar3DOverlay::setProperties(properties); | 287 | Planar3DOverlay::setProperties(properties); |
| 308 | 288 | ||
| 309 | QScriptValue startAt = properties.property("startAt"); | 289 | QScriptValue startAt = properties.property("startAt"); |
| 310 | if (startAt.isValid()) { | 290 | if (startAt.isValid()) { |
| 311 | setStartAt(startAt.toVariant().toFloat()); | 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 | const glm::vec3& direction, float& distance, BoxFace& face) { | 399 | const glm::vec3& direction, float& distance, BoxFace& face) { |
| 420 | 400 | ||
| 421 | bool intersects = Planar3DOverlay::findRayIntersection(origin, direction, distance, face); | 401 | bool intersects = Planar3DOverlay::findRayIntersection(origin, direction, distance, face); |
| @@ -32,6 +32,16 @@ Line3DOverlay::Line3DOverlay(const Line3DOverlay* line3DOverlay) : · 31 unmodified lines | |||
| 32 | Line3DOverlay::~Line3DOverlay() { | 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 | void Line3DOverlay::render(RenderArgs* args) { | 45 | void Line3DOverlay::render(RenderArgs* args) { |
| 36 | if (!_visible) { | 46 | if (!_visible) { |
| 37 | return; // do nothing if we're not visible | 47 | return; // do nothing if we're not visible |
| @@ -21,6 +21,7 @@ public: · 20 unmodified lines | |||
| 21 | Line3DOverlay(const Line3DOverlay* line3DOverlay); | 21 | Line3DOverlay(const Line3DOverlay* line3DOverlay); |
| 22 | ~Line3DOverlay(); | 22 | ~Line3DOverlay(); |
| 23 | virtual void render(RenderArgs* args); | 23 | virtual void render(RenderArgs* args); |
| 24 | virtual AABox getBounds() const override; | ||
| 24 | 25 | ||
| 25 | // getters | 26 | // getters |
| 26 | const glm::vec3& getStart() const { return _start; } | 27 | const glm::vec3& getStart() const { return _start; } |
| @@ -258,7 +258,7 @@ void Overlays::deleteOverlay(unsigned int id) { · 257 unmodified lines | |||
| 258 | unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) { | 258 | unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) { |
| 259 | glm::vec2 pointCopy = point; | 259 | glm::vec2 pointCopy = point; |
| 260 | if (qApp->isHMDMode()) { | 260 | if (qApp->isHMDMode()) { |
| 261 | pointCopy = qApp->getApplicationOverlay().screenToOverlay(point); | 261 | pointCopy = qApp->getApplicationCompositor().screenToOverlay(point); |
| 262 | } | 262 | } |
| 263 | 263 | ||
| 264 | QReadLocker lock(&_lock); | 264 | QReadLocker lock(&_lock); |
| @@ -80,6 +80,7 @@ void TextOverlay::render(RenderArgs* args) { · 79 unmodified lines | |||
| 80 | 80 | ||
| 81 | glm::vec2 topLeft(left, top); | 81 | glm::vec2 topLeft(left, top); |
| 82 | glm::vec2 bottomRight(right, bottom); | 82 | glm::vec2 bottomRight(right, bottom); |
| 83 | glBindTexture(GL_TEXTURE_2D, 0); | ||
| 83 | DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, quadColor); | 84 | DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, quadColor); |
| 84 | 85 | ||
| 85 | const int leftAdjust = -1; // required to make text render relative to left edge of bounds | 86 | const int leftAdjust = -1; // required to make text render relative to left edge of bounds |
| @@ -33,11 +33,20 @@ · 32 unmodified lines | |||
| 33 | #include <QtMultimedia/QAudioInput> | 33 | #include <QtMultimedia/QAudioInput> |
| 34 | #include <QtMultimedia/QAudioOutput> | 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 | extern "C" { | 41 | extern "C" { |
| 37 | #include <gverb/gverb.h> | 42 | #include <gverb/gverb.h> |
| 38 | #include <gverb/gverbdsp.h> | 43 | #include <gverb/gverbdsp.h> |
| 39 | } | 44 | } |
| 40 | 45 | ||
| 46 | #ifdef __GNUC__ | ||
| 47 | #pragma GCC diagnostic pop | ||
| 48 | #endif | ||
| 49 | |||
| 41 | #include <soxr.h> | 50 | #include <soxr.h> |
| 42 | 51 | ||
| 43 | #include <NodeList.h> | 52 | #include <NodeList.h> |
| @@ -786,6 +795,11 @@ void AudioClient::handleAudioInput() { · 742 unmodified lines | |||
| 786 | 795 | ||
| 787 | delete[] inputAudioSamples; | 796 | delete[] inputAudioSamples; |
| 788 | 797 | ||
| 798 | // Remove DC offset | ||
| 799 | if (!_isStereoInput && !_audioSourceInjectEnabled) { | ||
| 800 | _inputGate.removeDCOffset(networkAudioSamples, numNetworkSamples); | ||
| 801 | } | ||
| 802 | |||
| 789 | // only impose the noise gate and perform tone injection if we are sending mono audio | 803 | // only impose the noise gate and perform tone injection if we are sending mono audio |
| 790 | if (!_isStereoInput && !_audioSourceInjectEnabled && _isNoiseGateEnabled) { | 804 | if (!_isStereoInput && !_audioSourceInjectEnabled && _isNoiseGateEnabled) { |
| 791 | _inputGate.gateSamples(networkAudioSamples, numNetworkSamples); | 805 | _inputGate.gateSamples(networkAudioSamples, numNetworkSamples); |
| @@ -1011,7 +1025,10 @@ bool AudioClient::outputLocalInjector(bool isStereo, AudioInjector* injector) { · 219 unmodified lines | |||
| 1011 | localOutput->moveToThread(injector->getLocalBuffer()->thread()); | 1025 | localOutput->moveToThread(injector->getLocalBuffer()->thread()); |
| 1012 | 1026 | ||
| 1013 | // have it be stopped when that local buffer is about to close | 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 | connect(injector->getLocalBuffer(), &QIODevice::aboutToClose, localOutput, &QAudioOutput::stop); | 1032 | connect(injector->getLocalBuffer(), &QIODevice::aboutToClose, localOutput, &QAudioOutput::stop); |
| 1016 | 1033 | ||
| 1017 | qCDebug(audioclient) << "Starting QAudioOutput for local injector" << localOutput; | 1034 | qCDebug(audioclient) << "Starting QAudioOutput for local injector" << localOutput; |
| @@ -1329,3 +1346,9 @@ void AudioClient::saveSettings() { · 311 unmodified lines | |||
| 1329 | windowSecondsForDesiredReduction.set(_receivedAudioStream.getWindowSecondsForDesiredReduction()); | 1346 | windowSecondsForDesiredReduction.set(_receivedAudioStream.getWindowSecondsForDesiredReduction()); |
| 1330 | repetitionWithFade.set(_receivedAudioStream.getRepetitionWithFade()); | 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 | QString getDefaultDeviceName(QAudio::Mode mode); | 167 | QString getDefaultDeviceName(QAudio::Mode mode); |
| 168 | QVector<QString> getDeviceNames(QAudio::Mode mode); | 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 | void setInputVolume(float volume) { if (_audioInput) _audioInput->setVolume(volume); } | 171 | void setInputVolume(float volume) { if (_audioInput) _audioInput->setVolume(volume); } |
| 172 | void setReverb(bool reverb); | 172 | void setReverb(bool reverb); |
| 173 | void setReverbOptions(const AudioEffectOptions* options); | 173 | void setReverbOptions(const AudioEffectOptions* options); |
| @@ -188,6 +188,8 @@ signals: · 14 unmodified lines | |||
| 188 | void receivedFirstPacket(); | 188 | void receivedFirstPacket(); |
| 189 | void disconnected(); | 189 | void disconnected(); |
| 190 | 190 | ||
| 191 | void audioFinished(); | ||
| 192 | |||
| 191 | protected: | 193 | protected: |
| 192 | AudioClient(); | 194 | AudioClient(); |
| 193 | ~AudioClient(); | 195 | ~AudioClient(); |
| @@ -196,6 +198,9 @@ protected: · 2 unmodified lines | |||
| 196 | deleteLater(); | 198 | deleteLater(); |
| 197 | } | 199 | } |
| 198 | 200 | ||
| 201 | private slots: | ||
| 202 | void audioStateChanged(QAudio::State state); | ||
| 203 | |||
| 199 | private: | 204 | private: |
| 200 | void outputFormatChanged(); | 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 | void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { | 62 | void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { |
| 37 | // | 63 | // |
| 38 | // Impose Noise Gate | 64 | // Impose Noise Gate |
| @@ -61,17 +87,12 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { · 22 unmodified lines | |||
| 61 | const int NOISE_GATE_WIDTH = 5; | 87 | const int NOISE_GATE_WIDTH = 5; |
| 62 | const int NOISE_GATE_CLOSE_FRAME_DELAY = 5; | 88 | const int NOISE_GATE_CLOSE_FRAME_DELAY = 5; |
| 63 | const int NOISE_GATE_FRAMES_TO_AVERAGE = 5; | 89 | const int NOISE_GATE_FRAMES_TO_AVERAGE = 5; |
| 64 | const float DC_OFFSET_AVERAGING = 0.99f; | 90 | |
| 65 | 91 | // Check clipping, and check if should open noise gate | |
| 66 | // Check clipping, adjust DC offset, and check if should open noise gate | ||
| 67 | float measuredDcOffset = 0.0f; | ||
| 68 | _didClipInLastFrame = false; | 92 | _didClipInLastFrame = false; |
| 69 | 93 | ||
| 70 | for (int i = 0; i < numSamples; i++) { | 94 | for (int i = 0; i < numSamples; i++) { |
| 71 | measuredDcOffset += samples[i]; | ||
| 72 | samples[i] -= (int16_t) _dcOffset; | ||
| 73 | thisSample = std::abs(samples[i]); | 95 | thisSample = std::abs(samples[i]); |
| 74 | |||
| 75 | if (thisSample >= ((float) AudioConstants::MAX_SAMPLE_VALUE * CLIPPING_THRESHOLD)) { | 96 | if (thisSample >= ((float) AudioConstants::MAX_SAMPLE_VALUE * CLIPPING_THRESHOLD)) { |
| 76 | _didClipInLastFrame = true; | 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 | _lastLoudness = fabs(loudness / numSamples); | 107 | _lastLoudness = fabs(loudness / numSamples); |
| 95 | 108 | ||
| 96 | if (_quietestFrame > _lastLoudness) { | 109 | if (_quietestFrame > _lastLoudness) { |
| @@ -21,6 +21,7 @@ public: · 20 unmodified lines | |||
| 21 | AudioNoiseGate(); | 21 | AudioNoiseGate(); |
| 22 | 22 | ||
| 23 | void gateSamples(int16_t* samples, int numSamples); | 23 | void gateSamples(int16_t* samples, int numSamples); |
| 24 | void removeDCOffset(int16_t* samples, int numSamples); | ||
| 24 | 25 | ||
| 25 | bool clippedInLastFrame() const { return _didClipInLastFrame; } | 26 | bool clippedInLastFrame() const { return _didClipInLastFrame; } |
| 26 | float getMeasuredFloor() const { return _measuredFloor; } | 27 | float getMeasuredFloor() const { return _measuredFloor; } |
| @@ -7,4 +7,10 @@ add_dependency_external_projects(glm) · 6 unmodified lines | |||
| 7 | find_package(GLM REQUIRED) | 7 | find_package(GLM REQUIRED) |
| 8 | target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) | 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 | #include <PacketHeaders.h> | 16 | #include <PacketHeaders.h> |
| 17 | #include <SharedUtil.h> | 17 | #include <SharedUtil.h> |
| 18 | #include <UUID.h> | 18 | #include <UUID.h> |
| 19 | #include <soxr.h> | ||
| 19 | 20 | ||
| 20 | #include "AbstractAudioInterface.h" | 21 | #include "AbstractAudioInterface.h" |
| 21 | #include "AudioRingBuffer.h" | 22 | #include "AudioRingBuffer.h" |
| 22 | #include "AudioLogging.h" | 23 | #include "AudioLogging.h" |
| 24 | #include "SoundCache.h" | ||
| 23 | 25 | ||
| 24 | #include "AudioInjector.h" | 26 | #include "AudioInjector.h" |
| 25 | 27 | ||
| @@ -60,7 +62,6 @@ void AudioInjector::setIsFinished(bool isFinished) { · 34 unmodified lines | |||
| 60 | 62 | ||
| 61 | if (_shouldDeleteAfterFinish) { | 63 | if (_shouldDeleteAfterFinish) { |
| 62 | // we've been asked to delete after finishing, trigger a queued deleteLater here | 64 | // we've been asked to delete after finishing, trigger a queued deleteLater here |
| 63 | qCDebug(audio) << "AudioInjector triggering delete from setIsFinished"; | ||
| 64 | QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection); | 65 | QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection); |
| 65 | } | 66 | } |
| 66 | } | 67 | } |
| @@ -122,9 +123,6 @@ void AudioInjector::injectLocally() { · 55 unmodified lines | |||
| 122 | 123 | ||
| 123 | success = _localAudioInterface->outputLocalInjector(_options.stereo, this); | 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 | if (!success) { | 126 | if (!success) { |
| 129 | qCDebug(audio) << "AudioInjector::injectLocally could not output locally via _localAudioInterface"; | 127 | qCDebug(audio) << "AudioInjector::injectLocally could not output locally via _localAudioInterface"; |
| 130 | } | 128 | } |
| @@ -288,3 +286,66 @@ void AudioInjector::stopAndDeleteLater() { · 157 unmodified lines | |||
| 288 | stop(); | 286 | stop(); |
| 289 | QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection); | 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 | bool isLocalOnly() const { return _options.localOnly; } | 45 | bool isLocalOnly() const { return _options.localOnly; } |
| 46 | 46 | ||
| 47 | void setLocalAudioInterface(AbstractAudioInterface* localAudioInterface) { _localAudioInterface = localAudioInterface; } | 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 | public slots: | 52 | public slots: |
| 49 | void injectAudio(); | 53 | void injectAudio(); |
| 50 | void restart(); | 54 | void restart(); |
| @@ -69,10 +69,7 @@ qint64 AudioInjectorLocalBuffer::readData(char* data, qint64 maxSize) { · 68 unmodified lines | |||
| 69 | _currentOffset += bytesRead; | 69 | _currentOffset += bytesRead; |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | if (!_shouldLoop && bytesRead == bytesToEnd) { | 72 | if (_shouldLoop && _currentOffset == _rawAudioArray.size()) { |
| 73 | // we hit the end of the buffer, emit a signal | ||
| 74 | emit bufferEmpty(); | ||
| 75 | } else if (_shouldLoop && _currentOffset == _rawAudioArray.size()) { | ||
| 76 | _currentOffset = 0; | 73 | _currentOffset = 0; |
| 77 | } | 74 | } |
| 78 | 75 | ||
| @@ -32,9 +32,6 @@ public: · 31 unmodified lines | |||
| 32 | void setCurrentOffset(int currentOffset) { _currentOffset = currentOffset; } | 32 | void setCurrentOffset(int currentOffset) { _currentOffset = currentOffset; } |
| 33 | void setVolume(float volume) { _volume = glm::clamp(volume, 0.0f, 1.0f); } | 33 | void setVolume(float volume) { _volume = glm::clamp(volume, 0.0f, 1.0f); } |
| 34 | 34 | ||
| 35 | signals: | ||
| 36 | void bufferEmpty(); | ||
| 37 | |||
| 38 | private: | 35 | private: |
| 39 | qint64 recursiveReadFromFront(char* data, qint64 maxSize); | 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 | const int16_t* _bufferLastAt = _buffer + _bufferLength - 1; | 211 | const int16_t* _bufferLastAt = _buffer + _bufferLength - 1; |
| 212 | 212 | ||
| 213 | for (int i = 0; i < _numFrameSamples; ++i) { | 213 | for (int i = 0; i < _numFrameSamples; ++i) { |
| 214 | loudness += std::abs(*sampleAt); | 214 | loudness += (float) std::abs(*sampleAt); |
| 215 | sampleAt = sampleAt == _bufferLastAt ? _buffer : sampleAt + 1; | 215 | sampleAt = sampleAt == _bufferLastAt ? _buffer : sampleAt + 1; |
| 216 | } | 216 | } |
| 217 | loudness /= _numFrameSamples; | 217 | loudness /= _numFrameSamples; |
| @@ -52,9 +52,8 @@ AvatarData::AvatarData() : · 51 unmodified lines | |||
| 52 | _headData(NULL), | 52 | _headData(NULL), |
| 53 | _handData(NULL), | 53 | _handData(NULL), |
| 54 | _faceModelURL("http://invalid.com"), | 54 | _faceModelURL("http://invalid.com"), |
| 55 | _displayNameBoundingRect(), | 55 | _displayNameTargetAlpha(1.0f), |
| 56 | _displayNameTargetAlpha(0.0f), | 56 | _displayNameAlpha(1.0f), |
| 57 | _displayNameAlpha(0.0f), | ||
| 58 | _billboard(), | 57 | _billboard(), |
| 59 | _errorLogExpiry(0), | 58 | _errorLogExpiry(0), |
| 60 | _owningAvatarMixer(), | 59 | _owningAvatarMixer(), |
| @@ -163,7 +163,7 @@ public: · 162 unmodified lines | |||
| 163 | AvatarData(); | 163 | AvatarData(); |
| 164 | virtual ~AvatarData(); | 164 | virtual ~AvatarData(); |
| 165 | 165 | ||
| 166 | virtual bool isMyAvatar() { return false; } | 166 | virtual bool isMyAvatar() const { return false; } |
| 167 | 167 | ||
| 168 | const QUuid& getSessionUUID() const { return _sessionUUID; } | 168 | const QUuid& getSessionUUID() const { return _sessionUUID; } |
| 169 | 169 | ||
| @@ -378,7 +378,6 @@ protected: · 208 unmodified lines | |||
| 378 | QVector<AttachmentData> _attachmentData; | 378 | QVector<AttachmentData> _attachmentData; |
| 379 | QString _displayName; | 379 | QString _displayName; |
| 380 | 380 | ||
| 381 | QRect _displayNameBoundingRect; | ||
| 382 | float _displayNameTargetAlpha; | 381 | float _displayNameTargetAlpha; |
| 383 | float _displayNameAlpha; | 382 | float _displayNameAlpha; |
| 384 | 383 | ||
| @@ -17,10 +17,4 @@ find_package(PolyVox REQUIRED) · 16 unmodified lines | |||
| 17 | target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${POLYVOX_INCLUDE_DIRS}) | 17 | target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${POLYVOX_INCLUDE_DIRS}) |
| 18 | target_link_libraries(${TARGET_NAME} ${POLYVOX_LIBRARIES}) | 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 | link_hifi_libraries(shared gpu script-engine render render-utils) | 20 | link_hifi_libraries(shared gpu script-engine render render-utils) |
| @@ -27,10 +27,6 @@ · 26 unmodified lines | |||
| 27 | #include <SceneScriptingInterface.h> | 27 | #include <SceneScriptingInterface.h> |
| 28 | #include <ScriptEngine.h> | 28 | #include <ScriptEngine.h> |
| 29 | #include <TextureCache.h> | 29 | #include <TextureCache.h> |
| 30 | #include <SoundCache.h> | ||
| 31 | #include <soxr.h> | ||
| 32 | #include <AudioConstants.h> | ||
| 33 | |||
| 34 | 30 | ||
| 35 | #include "EntityTreeRenderer.h" | 31 | #include "EntityTreeRenderer.h" |
| 36 | 32 | ||
| @@ -54,7 +50,6 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf · 17 unmodified lines | |||
| 54 | _wantScripts(wantScripts), | 50 | _wantScripts(wantScripts), |
| 55 | _entitiesScriptEngine(NULL), | 51 | _entitiesScriptEngine(NULL), |
| 56 | _sandboxScriptEngine(NULL), | 52 | _sandboxScriptEngine(NULL), |
| 57 | _localAudioInterface(NULL), | ||
| 58 | _lastMouseEventValid(false), | 53 | _lastMouseEventValid(false), |
| 59 | _viewState(viewState), | 54 | _viewState(viewState), |
| 60 | _scriptingServices(scriptingServices), | 55 | _scriptingServices(scriptingServices), |
| @@ -911,15 +906,13 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI · 850 unmodified lines | |||
| 911 | bool precisionPicking = false; // for mouse moves we do not do precision picking | 906 | bool precisionPicking = false; // for mouse moves we do not do precision picking |
| 912 | RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking); | 907 | RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking); |
| 913 | if (rayPickResult.intersects) { | 908 | if (rayPickResult.intersects) { |
| 909 | //qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID; | ||
| 914 | QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); | 910 | QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); |
| 915 | |||
| 916 | // load the entity script if needed... | 911 | // load the entity script if needed... |
| 917 | QScriptValue entityScript = loadEntityScript(rayPickResult.entity); | 912 | QScriptValue entityScript = loadEntityScript(rayPickResult.entity); |
| 918 | if (entityScript.property("mouseMoveEvent").isValid()) { | 913 | if (entityScript.property("mouseMoveEvent").isValid()) { |
| 919 | entityScript.property("mouseMoveEvent").call(entityScript, entityScriptArgs); | 914 | entityScript.property("mouseMoveEvent").call(entityScript, entityScriptArgs); |
| 920 | } | 915 | } |
| 921 | |||
| 922 | //qCDebug(entitiesrenderer) << "mouseMoveEvent over entity:" << rayPickResult.entityID; | ||
| 923 | emit mouseMoveOnEntity(rayPickResult, event, deviceID); | 916 | emit mouseMoveOnEntity(rayPickResult, event, deviceID); |
| 924 | if (entityScript.property("mouseMoveOnEntity").isValid()) { | 917 | if (entityScript.property("mouseMoveOnEntity").isValid()) { |
| 925 | entityScript.property("mouseMoveOnEntity").call(entityScript, entityScriptArgs); | 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 | void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision) { | 1052 | void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision) { |
| 1061 | EntityItemPointer entity = entityTree->findEntityByEntityItemID(id); | 1053 | EntityItemPointer entity = entityTree->findEntityByEntityItemID(id); |
| 1062 | if (!entity) { | 1054 | if (!entity) { |
| @@ -1099,61 +1091,15 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT · 36 unmodified lines | |||
| 1099 | if (energyFactorOfFull < COLLISION_MINIMUM_VOLUME) { | 1091 | if (energyFactorOfFull < COLLISION_MINIMUM_VOLUME) { |
| 1100 | return; | 1092 | return; |
| 1101 | } | 1093 | } |
| 1102 | 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. | |
| 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. | ||
| 1113 | 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. | 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; | 1096 | const float volume = (energyFactorOfFull * COLLISION_SOUND_COMPRESSION_RANGE) + (1.0f - COLLISION_SOUND_COMPRESSION_RANGE); |
| 1115 | volume = (volume * COLLISION_SOUND_COMPRESSION_RANGE) + (1.0f - COLLISION_SOUND_COMPRESSION_RANGE); | 1097 | |
| 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; | ||
| 1122 | 1098 | ||
| 1123 | // Shift the pitch down by ln(1 + (size / COLLISION_SIZE_FOR_STANDARD_PITCH)) / ln(2) | 1099 | // Shift the pitch down by ln(1 + (size / COLLISION_SIZE_FOR_STANDARD_PITCH)) / ln(2) |
| 1124 | const float COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f; | 1100 | const float COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f; |
| 1125 | QByteArray samples = sound->getByteArray(); | 1101 | const float stretchFactor = log(1.0f + (entity->getMinimumAACube().getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2); |
| 1126 | soxr_io_spec_t spec = soxr_io_spec(SOXR_INT16_I, SOXR_INT16_I); | 1102 | AudioInjector::playSound(collisionSoundURL, volume, stretchFactor, position); |
| 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(); | ||
| 1157 | } | 1103 | } |
| 1158 | 1104 | ||
| 1159 | void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, | 1105 | void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, |
| @@ -158,7 +158,6 @@ private: · 157 unmodified lines | |||
| 158 | QHash<EntityItemID, EntityScriptDetails> _entityScripts; | 158 | QHash<EntityItemID, EntityScriptDetails> _entityScripts; |
| 159 | 159 | ||
| 160 | void playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision); | 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 | bool _lastMouseEventValid; | 162 | bool _lastMouseEventValid; |
| 164 | MouseEvent _lastMouseEvent; | 163 | MouseEvent _lastMouseEvent; |
| @@ -43,9 +43,9 @@ void RenderableLineEntityItem::render(RenderArgs* args) { · 42 unmodified lines | |||
| 43 | 43 | ||
| 44 | Q_ASSERT(args->_batch); | 44 | Q_ASSERT(args->_batch); |
| 45 | gpu::Batch& batch = *args->_batch; | 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. | 46 | Transform transform = Transform(); |
| 47 | //batch.setModelTransform(getTransformToCenter()); | 47 | transform.setTranslation(getPosition()); |
| 48 | batch.setModelTransform(Transform()); | 48 | batch.setModelTransform(transform); |
| 49 | 49 | ||
| 50 | batch._glLineWidth(getLineWidth()); | 50 | batch._glLineWidth(getLineWidth()); |
| 51 | if (getLinePoints().size() > 1) { | 51 | if (getLinePoints().size() > 1) { |
| @@ -11,10 +11,18 @@ · 10 unmodified lines | |||
| 11 | 11 | ||
| 12 | #include <QByteArray> | 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 | #include <glm/gtx/quaternion.hpp> | 19 | #include <glm/gtx/quaternion.hpp> |
| 16 | #include <glm/gtx/string_cast.hpp> | 20 | #include <glm/gtx/string_cast.hpp> |
| 17 | 21 | ||
| 22 | #ifdef __GNUC__ | ||
| 23 | #pragma GCC diagnostic pop | ||
| 24 | #endif | ||
| 25 | |||
| 18 | #include <gpu/GPUConfig.h> | 26 | #include <gpu/GPUConfig.h> |
| 19 | 27 | ||
| 20 | #include <DeferredLightingEffect.h> | 28 | #include <DeferredLightingEffect.h> |
| @@ -141,11 +149,7 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) · 120 unmodified lines | |||
| 141 | decompressVolumeData(); | 149 | decompressVolumeData(); |
| 142 | } | 150 | } |
| 143 | 151 | ||
| 144 | void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { | 152 | void RenderablePolyVoxEntityItem::updateVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { |
| 145 | if (voxelSurfaceStyle == _voxelSurfaceStyle) { | ||
| 146 | return; | ||
| 147 | } | ||
| 148 | |||
| 149 | // if we are switching to or from "edged" we need to force a resize of _volData. | 153 | // if we are switching to or from "edged" we need to force a resize of _volData. |
| 150 | if (voxelSurfaceStyle == SURFACE_EDGED_CUBIC || | 154 | if (voxelSurfaceStyle == SURFACE_EDGED_CUBIC || |
| 151 | _voxelSurfaceStyle == SURFACE_EDGED_CUBIC) { | 155 | _voxelSurfaceStyle == SURFACE_EDGED_CUBIC) { |
| @@ -153,10 +157,10 @@ void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxel · 1 unmodified line | |||
| 153 | delete _volData; | 157 | delete _volData; |
| 154 | } | 158 | } |
| 155 | _volData = nullptr; | 159 | _volData = nullptr; |
| 156 | PolyVoxEntityItem::setVoxelSurfaceStyle(voxelSurfaceStyle); | 160 | _voxelSurfaceStyle = voxelSurfaceStyle; |
| 157 | setVoxelVolumeSize(_voxelVolumeSize); | 161 | setVoxelVolumeSize(_voxelVolumeSize); |
| 158 | } else { | 162 | } else { |
| 159 | PolyVoxEntityItem::setVoxelSurfaceStyle(voxelSurfaceStyle); | 163 | _voxelSurfaceStyle = voxelSurfaceStyle; |
| 160 | } | 164 | } |
| 161 | _needsModelReload = true; | 165 | _needsModelReload = true; |
| 162 | } | 166 | } |
| @@ -36,17 +36,15 @@ public: · 35 unmodified lines | |||
| 36 | 36 | ||
| 37 | virtual uint8_t getVoxel(int x, int y, int z); | 37 | virtual uint8_t getVoxel(int x, int y, int z); |
| 38 | virtual void setVoxel(int x, int y, int z, uint8_t toValue); | 38 | virtual void setVoxel(int x, int y, int z, uint8_t toValue); |
| 39 | 39 | ||
| 40 | void updateOnCount(int x, int y, int z, uint8_t new_value); | 40 | void updateOnCount(int x, int y, int z, uint8_t new_value); |
| 41 | 41 | ||
| 42 | void render(RenderArgs* args); | 42 | void render(RenderArgs* args); |
| 43 | virtual bool supportsDetailedRayIntersection() const { return true; } | 43 | virtual bool supportsDetailedRayIntersection() const { return true; } |
| 44 | virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, | 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 | void** intersectedObject, bool precisionPicking) const; | 46 | void** intersectedObject, bool precisionPicking) const; |
| 47 | 47 | ||
| 48 | virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle); | ||
| 49 | |||
| 50 | void getModel(); | 48 | void getModel(); |
| 51 | 49 | ||
| 52 | virtual void setVoxelData(QByteArray voxelData); | 50 | virtual void setVoxelData(QByteArray voxelData); |
| @@ -74,6 +72,9 @@ public: · 21 unmodified lines | |||
| 74 | 72 | ||
| 75 | SIMPLE_RENDERABLE(); | 73 | SIMPLE_RENDERABLE(); |
| 76 | 74 | ||
| 75 | protected: | ||
| 76 | virtual void updateVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle); | ||
| 77 | |||
| 77 | private: | 78 | private: |
| 78 | // The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions | 79 | // The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions |
| 79 | // may not match _voxelVolumeSize. | 80 | // may not match _voxelVolumeSize. |
| @@ -82,6 +83,7 @@ private: · 2 unmodified lines | |||
| 82 | void compressVolumeData(); | 83 | void compressVolumeData(); |
| 83 | void decompressVolumeData(); | 84 | void decompressVolumeData(); |
| 84 | 85 | ||
| 86 | |||
| 85 | PolyVox::SimpleVolume<uint8_t>* _volData = nullptr; | 87 | PolyVox::SimpleVolume<uint8_t>* _volData = nullptr; |
| 86 | model::Geometry _modelGeometry; | 88 | model::Geometry _modelGeometry; |
| 87 | bool _needsModelReload = true; | 89 | bool _needsModelReload = true; |
| @@ -95,6 +95,7 @@ bool DeleteEntityOperator::preRecursion(OctreeElement* element) { · 94 unmodified lines | |||
| 95 | EntityItemPointer theEntity = details.entity; | 95 | EntityItemPointer theEntity = details.entity; |
| 96 | bool entityDeleted = entityTreeElement->removeEntityItem(theEntity); // remove it from the element | 96 | bool entityDeleted = entityTreeElement->removeEntityItem(theEntity); // remove it from the element |
| 97 | assert(entityDeleted); | 97 | assert(entityDeleted); |
| 98 | (void)entityDeleted; // quite warning | ||
| 98 | _tree->setContainingElement(details.entity->getEntityItemID(), NULL); // update or id to element lookup | 99 | _tree->setContainingElement(details.entity->getEntityItemID(), NULL); // update or id to element lookup |
| 99 | _foundCount++; | 100 | _foundCount++; |
| 100 | } | 101 | } |
| @@ -19,8 +19,8 @@ EntityActionType EntityActionInterface::actionTypeFromString(QString actionTypeS · 18 unmodified lines | |||
| 19 | if (normalizedActionTypeString == "none") { | 19 | if (normalizedActionTypeString == "none") { |
| 20 | return ACTION_TYPE_NONE; | 20 | return ACTION_TYPE_NONE; |
| 21 | } | 21 | } |
| 22 | if (normalizedActionTypeString == "pulltopoint") { | 22 | if (normalizedActionTypeString == "offset") { |
| 23 | return ACTION_TYPE_PULL_TO_POINT; | 23 | return ACTION_TYPE_OFFSET; |
| 24 | } | 24 | } |
| 25 | if (normalizedActionTypeString == "spring") { | 25 | if (normalizedActionTypeString == "spring") { |
| 26 | return ACTION_TYPE_SPRING; | 26 | return ACTION_TYPE_SPRING; |
| @@ -37,8 +37,8 @@ QString EntityActionInterface::actionTypeToString(EntityActionType actionType) { · 10 unmodified lines | |||
| 37 | switch(actionType) { | 37 | switch(actionType) { |
| 38 | case ACTION_TYPE_NONE: | 38 | case ACTION_TYPE_NONE: |
| 39 | return "none"; | 39 | return "none"; |
| 40 | case ACTION_TYPE_PULL_TO_POINT: | 40 | case ACTION_TYPE_OFFSET: |
| 41 | return "pullToPoint"; | 41 | return "offset"; |
| 42 | case ACTION_TYPE_SPRING: | 42 | case ACTION_TYPE_SPRING: |
| 43 | return "spring"; | 43 | return "spring"; |
| 44 | case ACTION_TYPE_HOLD: | 44 | case ACTION_TYPE_HOLD: |
| @@ -21,7 +21,7 @@ class EntitySimulation; · 20 unmodified lines | |||
| 21 | enum EntityActionType { | 21 | enum EntityActionType { |
| 22 | // keep these synchronized with actionTypeFromString and actionTypeToString | 22 | // keep these synchronized with actionTypeFromString and actionTypeToString |
| 23 | ACTION_TYPE_NONE, | 23 | ACTION_TYPE_NONE, |
| 24 | ACTION_TYPE_PULL_TO_POINT, | 24 | ACTION_TYPE_OFFSET, |
| 25 | ACTION_TYPE_SPRING, | 25 | ACTION_TYPE_SPRING, |
| 26 | ACTION_TYPE_HOLD | 26 | ACTION_TYPE_HOLD |
| 27 | }; | 27 | }; |
| @@ -639,8 +639,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef · 638 unmodified lines | |||
| 639 | void EntityItem::debugDump() const { | 639 | void EntityItem::debugDump() const { |
| 640 | auto position = getPosition(); | 640 | auto position = getPosition(); |
| 641 | qCDebug(entities) << "EntityItem id:" << getEntityItemID(); | 641 | qCDebug(entities) << "EntityItem id:" << getEntityItemID(); |
| 642 | qCDebug(entities, " edited ago:%f", getEditedAgo()); | 642 | qCDebug(entities, " edited ago:%f", (double)getEditedAgo()); |
| 643 | qCDebug(entities, " position:%f,%f,%f", position.x, position.y, position.z); | 643 | qCDebug(entities, " position:%f,%f,%f", (double)position.x, (double)position.y, (double)position.z); |
| 644 | qCDebug(entities) << " dimensions:" << getDimensions(); | 644 | qCDebug(entities) << " dimensions:" << getDimensions(); |
| 645 | } | 645 | } |
| 646 | 646 | ||
| @@ -14,7 +14,7 @@ · 13 unmodified lines | |||
| 14 | 14 | ||
| 15 | #include <stdint.h> | 15 | #include <stdint.h> |
| 16 | 16 | ||
| 17 | 17 | #include <QDebug> | |
| 18 | #include <QObject> | 18 | #include <QObject> |
| 19 | #include <QHash> | 19 | #include <QHash> |
| 20 | #include <QScriptEngine> | 20 | #include <QScriptEngine> |
| @@ -197,6 +197,8 @@ public: · 196 unmodified lines | |||
| 197 | QString getSimulatorIDAsString() const { return _simulatorID.toString().mid(1,36).toUpper(); } | 197 | QString getSimulatorIDAsString() const { return _simulatorID.toString().mid(1,36).toUpper(); } |
| 198 | 198 | ||
| 199 | void setVoxelDataDirty() { _voxelDataChanged = true; } | 199 | void setVoxelDataDirty() { _voxelDataChanged = true; } |
| 200 | |||
| 201 | void setLinePointsDirty() {_linePointsChanged = true; } | ||
| 200 | 202 | ||
| 201 | void setCreated(QDateTime& v); | 203 | void setCreated(QDateTime& v); |
| 202 | 204 | ||
| @@ -442,6 +442,43 @@ bool EntityScriptingInterface::setVoxels(QUuid entityID, · 441 unmodified lines | |||
| 442 | return true; | 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 | bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) { | 482 | bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) { |
| 446 | return setVoxels(entityID, [center, radius, value](PolyVoxEntityItem& polyVoxEntity) { | 483 | return setVoxels(entityID, [center, radius, value](PolyVoxEntityItem& polyVoxEntity) { |
| 447 | polyVoxEntity.setSphere(center, radius, value); | 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 | bool EntityScriptingInterface::actionWorker(const QUuid& entityID, | 516 | bool EntityScriptingInterface::actionWorker(const QUuid& entityID, |
| 465 | std::function<bool(EntitySimulation*, EntityItemPointer)> actor) { | 517 | std::function<bool(EntitySimulation*, EntityItemPointer)> actor) { |
| @@ -22,6 +22,7 @@ · 21 unmodified lines | |||
| 22 | #include <OctreeScriptingInterface.h> | 22 | #include <OctreeScriptingInterface.h> |
| 23 | #include <RegisteredMetaTypes.h> | 23 | #include <RegisteredMetaTypes.h> |
| 24 | #include "PolyVoxEntityItem.h" | 24 | #include "PolyVoxEntityItem.h" |
| 25 | #include "LineEntityItem.h" | ||
| 25 | 26 | ||
| 26 | #include "EntityEditPacketSender.h" | 27 | #include "EntityEditPacketSender.h" |
| 27 | 28 | ||
| @@ -121,6 +122,9 @@ public slots: · 93 unmodified lines | |||
| 121 | Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value); | 122 | Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value); |
| 122 | Q_INVOKABLE bool setVoxel(QUuid entityID, const glm::vec3& position, int value); | 123 | Q_INVOKABLE bool setVoxel(QUuid entityID, const glm::vec3& position, int value); |
| 123 | Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value); | 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 | Q_INVOKABLE void dumpTree() const; | 129 | Q_INVOKABLE void dumpTree() const; |
| 126 | 130 | ||
| @@ -157,6 +161,7 @@ signals: · 30 unmodified lines | |||
| 157 | private: | 161 | private: |
| 158 | bool actionWorker(const QUuid& entityID, std::function<bool(EntitySimulation*, EntityItemPointer)> actor); | 162 | bool actionWorker(const QUuid& entityID, std::function<bool(EntitySimulation*, EntityItemPointer)> actor); |
| 159 | bool setVoxels(QUuid entityID, std::function<void(PolyVoxEntityItem&)> actor); | 163 | bool setVoxels(QUuid entityID, std::function<void(PolyVoxEntityItem&)> actor); |
| 164 | bool setPoints(QUuid entityID, std::function<bool(LineEntityItem&)> actor); | ||
| 160 | void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties); | 165 | void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties); |
| 161 | 166 | ||
| 162 | /// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode | 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 | const float LineEntityItem::DEFAULT_LINE_WIDTH = 2.0f; | 25 | const float LineEntityItem::DEFAULT_LINE_WIDTH = 2.0f; |
| 26 | const int LineEntityItem::MAX_POINTS_PER_LINE = 70; | ||
| 26 | 27 | ||
| 27 | 28 | ||
| 28 | EntityItemPointer LineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { | 29 | EntityItemPointer LineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { |
| @@ -85,24 +86,38 @@ bool LineEntityItem::setProperties(const EntityItemProperties& properties) { · 56 unmodified lines | |||
| 85 | return somethingChanged; | 86 | return somethingChanged; |
| 86 | } | 87 | } |
| 87 | 88 | ||
| 88 | void LineEntityItem::setLinePoints(const QVector<glm::vec3>& points) { | 89 | bool LineEntityItem::appendPoint(const glm::vec3& point) { |
| 89 | QVector<glm::vec3> sanitizedPoints; | 90 | if (_points.size() > MAX_POINTS_PER_LINE - 1) { |
| 90 | int invalidPoints = 0; | 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 | for (int i = 0; i < points.size(); i++) { | 108 | for (int i = 0; i < points.size(); i++) { |
| 92 | glm::vec3 point = points.at(i); | 109 | glm::vec3 point = points.at(i); |
| 93 | // Make sure all of our points are valid numbers. | 110 | glm::vec3 pos = getPosition(); |
| 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 | 111 | glm::vec3 halfBox = getDimensions() * 0.5f; |
| 95 | if ( (point.x > 0 && point.x < TREE_SCALE) && (point.y > 0 && point.y < TREE_SCALE) && (point.z > 0 && point.z < TREE_SCALE) ) { | 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) ) { |
| 96 | sanitizedPoints << point; | 113 | qDebug() << "Point is outside entity's bounding box"; |
| 97 | } else { | 114 | return false; |
| 98 | ++invalidPoints; | ||
| 99 | } | 115 | } |
| 116 | |||
| 100 | } | 117 | } |
| 101 | if (invalidPoints > 0) { | 118 | _points = points; |
| 102 | qDebug() << "Line with" << invalidPoints << "INVALID POINTS"; | ||
| 103 | } | ||
| 104 | _points = sanitizedPoints; | ||
| 105 | _pointsChanged = true; | 119 | _pointsChanged = true; |
| 120 | return true; | ||
| 106 | } | 121 | } |
| 107 | 122 | ||
| 108 | int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, | 123 | int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, |
| @@ -54,7 +54,8 @@ class LineEntityItem : public EntityItem { · 53 unmodified lines | |||
| 54 | void setLineWidth(float lineWidth){ _lineWidth = lineWidth; } | 54 | void setLineWidth(float lineWidth){ _lineWidth = lineWidth; } |
| 55 | float getLineWidth() const{ return _lineWidth; } | 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 | const QVector<glm::vec3>& getLinePoints() const{ return _points; } | 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 | virtual void debugDump() const; | 70 | virtual void debugDump() const; |
| 70 | static const float DEFAULT_LINE_WIDTH; | 71 | static const float DEFAULT_LINE_WIDTH; |
| 72 | static const int MAX_POINTS_PER_LINE; | ||
| 71 | 73 | ||
| 72 | protected: | 74 | protected: |
| 73 | rgbColor _color; | 75 | rgbColor _color; |
| @@ -168,3 +168,10 @@ void PolyVoxEntityItem::debugDump() const { · 167 unmodified lines | |||
| 168 | qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions()); | 168 | qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions()); |
| 169 | qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); | 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 | SURFACE_EDGED_CUBIC | 61 | SURFACE_EDGED_CUBIC |
| 62 | }; | 62 | }; |
| 63 | 63 | ||
| 64 | virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { _voxelSurfaceStyle = voxelSurfaceStyle; } | 64 | void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle); |
| 65 | virtual void setVoxelSurfaceStyle(uint16_t voxelSurfaceStyle) { | 65 | // this other version of setVoxelSurfaceStyle is needed for SET_ENTITY_PROPERTY_FROM_PROPERTIES |
| 66 | setVoxelSurfaceStyle((PolyVoxSurfaceStyle) voxelSurfaceStyle); | 66 | void setVoxelSurfaceStyle(uint16_t voxelSurfaceStyle) { setVoxelSurfaceStyle((PolyVoxSurfaceStyle) voxelSurfaceStyle); } |
| 67 | } | ||
| 68 | virtual PolyVoxSurfaceStyle getVoxelSurfaceStyle() const { return _voxelSurfaceStyle; } | 67 | virtual PolyVoxSurfaceStyle getVoxelSurfaceStyle() const { return _voxelSurfaceStyle; } |
| 69 | 68 | ||
| 70 | static const glm::vec3 DEFAULT_VOXEL_VOLUME_SIZE; | 69 | static const glm::vec3 DEFAULT_VOXEL_VOLUME_SIZE; |
| @@ -89,6 +88,10 @@ class PolyVoxEntityItem : public EntityItem { · 18 unmodified lines | |||
| 89 | static QByteArray makeEmptyVoxelData(quint16 voxelXSize = 16, quint16 voxelYSize = 16, quint16 voxelZSize = 16); | 88 | static QByteArray makeEmptyVoxelData(quint16 voxelXSize = 16, quint16 voxelYSize = 16, quint16 voxelZSize = 16); |
| 90 | 89 | ||
| 91 | protected: | 90 | protected: |
| 91 | virtual void updateVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { | ||
| 92 | _voxelSurfaceStyle = voxelSurfaceStyle; | ||
| 93 | } | ||
| 94 | |||
| 92 | glm::vec3 _voxelVolumeSize; // this is always 3 bytes | 95 | glm::vec3 _voxelVolumeSize; // this is always 3 bytes |
| 93 | QByteArray _voxelData; | 96 | QByteArray _voxelData; |
| 94 | PolyVoxSurfaceStyle _voxelSurfaceStyle; | 97 | PolyVoxSurfaceStyle _voxelSurfaceStyle; |
| @@ -506,7 +506,7 @@ FBXNode parseFBX(QIODevice* device) { · 505 unmodified lines | |||
| 506 | 506 | ||
| 507 | QVector<glm::vec4> createVec4Vector(const QVector<double>& doubleVector) { | 507 | QVector<glm::vec4> createVec4Vector(const QVector<double>& doubleVector) { |
| 508 | QVector<glm::vec4> values; | 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 | float x = *it++; | 510 | float x = *it++; |
| 511 | float y = *it++; | 511 | float y = *it++; |
| 512 | float z = *it++; | 512 | float z = *it++; |
| @@ -516,9 +516,27 @@ QVector<glm::vec4> createVec4Vector(const QVector<double>& doubleVector) { · 3 unmodified lines | |||
| 516 | return values; | 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 | QVector<glm::vec3> createVec3Vector(const QVector<double>& doubleVector) { | 537 | QVector<glm::vec3> createVec3Vector(const QVector<double>& doubleVector) { |
| 520 | QVector<glm::vec3> values; | 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 | float x = *it++; | 540 | float x = *it++; |
| 523 | float y = *it++; | 541 | float y = *it++; |
| 524 | float z = *it++; | 542 | float z = *it++; |
| @@ -529,7 +547,7 @@ QVector<glm::vec3> createVec3Vector(const QVector<double>& doubleVector) { · 4 unmodified lines | |||
| 529 | 547 | ||
| 530 | QVector<glm::vec2> createVec2Vector(const QVector<double>& doubleVector) { | 548 | QVector<glm::vec2> createVec2Vector(const QVector<double>& doubleVector) { |
| 531 | QVector<glm::vec2> values; | 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 | float s = *it++; | 551 | float s = *it++; |
| 534 | float t = *it++; | 552 | float t = *it++; |
| 535 | values.append(glm::vec2(s, -t)); | 553 | values.append(glm::vec2(s, -t)); |
| @@ -799,6 +817,7 @@ public: · 263 unmodified lines | |||
| 799 | QVector<int> normalIndices; | 817 | QVector<int> normalIndices; |
| 800 | 818 | ||
| 801 | bool colorsByVertex; | 819 | bool colorsByVertex; |
| 820 | glm::vec4 averageColor{1.0f, 1.0f, 1.0f, 1.0f}; | ||
| 802 | QVector<glm::vec4> colors; | 821 | QVector<glm::vec4> colors; |
| 803 | QVector<int> colorIndices; | 822 | QVector<int> colorIndices; |
| 804 | 823 | ||
| @@ -940,8 +959,7 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) { · 135 unmodified lines | |||
| 940 | bool indexToDirect = false; | 959 | bool indexToDirect = false; |
| 941 | foreach (const FBXNode& subdata, child.children) { | 960 | foreach (const FBXNode& subdata, child.children) { |
| 942 | if (subdata.name == "Colors") { | 961 | if (subdata.name == "Colors") { |
| 943 | data.colors = createVec4Vector(getDoubleVector(subdata)); | 962 | data.colors = createVec4VectorRGBA(getDoubleVector(subdata), data.averageColor); |
| 944 | |||
| 945 | } else if (subdata.name == "ColorsIndex") { | 963 | } else if (subdata.name == "ColorsIndex") { |
| 946 | data.colorIndices = getIntVector(subdata); | 964 | data.colorIndices = getIntVector(subdata); |
| 947 | 965 | ||
| @@ -956,6 +974,19 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) { · 8 unmodified lines | |||
| 956 | // hack to work around wacky Makehuman exports | 974 | // hack to work around wacky Makehuman exports |
| 957 | data.colorsByVertex = true; | 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 | } else if (child.name == "LayerElementUV") { | 991 | } else if (child.name == "LayerElementUV") { |
| 961 | if (child.properties.at(0).toInt() == 0) { | 992 | if (child.properties.at(0).toInt() == 0) { |
| @@ -1251,7 +1282,7 @@ FBXLight extractLight(const FBXNode& object) { · 289 unmodified lines | |||
| 1251 | if (property.name == "P") { | 1282 | if (property.name == "P") { |
| 1252 | QString propname = property.properties.at(0).toString(); | 1283 | QString propname = property.properties.at(0).toString(); |
| 1253 | if (propname == "Intensity") { | 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 | } else if (propname == "Color") { | 1286 | } else if (propname == "Color") { |
| 1256 | light.color = getVec3(property.properties, valIndex); | 1287 | light.color = getVec3(property.properties, valIndex); |
| 1257 | } | 1288 | } |
| @@ -70,7 +70,7 @@ public: · 69 unmodified lines | |||
| 70 | typedef Stream::Slot Slot; | 70 | typedef Stream::Slot Slot; |
| 71 | 71 | ||
| 72 | Batch(); | 72 | Batch(); |
| 73 | Batch(const Batch& batch); | 73 | explicit Batch(const Batch& batch); |
| 74 | ~Batch(); | 74 | ~Batch(); |
| 75 | 75 | ||
| 76 | void clear(); | 76 | void clear(); |
| @@ -148,6 +148,7 @@ public: · 71 unmodified lines | |||
| 148 | void _glDrawBuffers(GLsizei n, const GLenum* bufs); | 148 | void _glDrawBuffers(GLsizei n, const GLenum* bufs); |
| 149 | 149 | ||
| 150 | void _glUseProgram(GLuint program); | 150 | void _glUseProgram(GLuint program); |
| 151 | void _glUniform1i(GLint location, GLint v0); | ||
| 151 | void _glUniform1f(GLint location, GLfloat v0); | 152 | void _glUniform1f(GLint location, GLfloat v0); |
| 152 | void _glUniform2f(GLint location, GLfloat v0, GLfloat v1); | 153 | void _glUniform2f(GLint location, GLfloat v0, GLfloat v1); |
| 153 | void _glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); | 154 | void _glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); |
| @@ -210,6 +211,7 @@ public: · 56 unmodified lines | |||
| 210 | COMMAND_glDrawBuffers, | 211 | COMMAND_glDrawBuffers, |
| 211 | 212 | ||
| 212 | COMMAND_glUseProgram, | 213 | COMMAND_glUseProgram, |
| 214 | COMMAND_glUniform1i, | ||
| 213 | COMMAND_glUniform1f, | 215 | COMMAND_glUniform1f, |
| 214 | COMMAND_glUniform2f, | 216 | COMMAND_glUniform2f, |
| 215 | COMMAND_glUniform3f, | 217 | COMMAND_glUniform3f, |
| @@ -12,6 +12,8 @@ · 11 unmodified lines | |||
| 12 | #include "GLBackendShared.h" | 12 | #include "GLBackendShared.h" |
| 13 | #include <glm/gtc/type_ptr.hpp> | 13 | #include <glm/gtc/type_ptr.hpp> |
| 14 | 14 | ||
| 15 | using namespace gpu; | ||
| 16 | |||
| 15 | GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = | 17 | GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = |
| 16 | { | 18 | { |
| 17 | (&::gpu::GLBackend::do_draw), | 19 | (&::gpu::GLBackend::do_draw), |
| @@ -59,6 +61,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = · 41 unmodified lines | |||
| 59 | (&::gpu::GLBackend::do_glDrawBuffers), | 61 | (&::gpu::GLBackend::do_glDrawBuffers), |
| 60 | 62 | ||
| 61 | (&::gpu::GLBackend::do_glUseProgram), | 63 | (&::gpu::GLBackend::do_glUseProgram), |
| 64 | (&::gpu::GLBackend::do_glUniform1i), | ||
| 62 | (&::gpu::GLBackend::do_glUniform1f), | 65 | (&::gpu::GLBackend::do_glUniform1f), |
| 63 | (&::gpu::GLBackend::do_glUniform2f), | 66 | (&::gpu::GLBackend::do_glUniform2f), |
| 64 | (&::gpu::GLBackend::do_glUniform3f), | 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 | void GLBackend::syncCache() { | 156 | void GLBackend::syncCache() { |
| 146 | syncTransformStateCache(); | 157 | syncTransformStateCache(); |
| @@ -433,6 +444,29 @@ void GLBackend::do_glUseProgram(Batch& batch, uint32 paramOffset) { · 286 unmodified lines | |||
| 433 | (void) CHECK_GL_ERROR(); | 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 | void Batch::_glUniform1f(GLint location, GLfloat v0) { | 470 | void Batch::_glUniform1f(GLint location, GLfloat v0) { |
| 437 | if (location < 0) { | 471 | if (location < 0) { |
| 438 | return; | 472 | return; |
| @@ -449,6 +483,8 @@ void GLBackend::do_glUniform1f(Batch& batch, uint32 paramOffset) { · 10 unmodified lines | |||
| 449 | // because these uniform setters are deprecated and we don;t want to create side effect | 483 | // because these uniform setters are deprecated and we don;t want to create side effect |
| 450 | return; | 484 | return; |
| 451 | } | 485 | } |
| 486 | updatePipeline(); | ||
| 487 | |||
| 452 | glUniform1f( | 488 | glUniform1f( |
| 453 | batch._params[paramOffset + 1]._int, | 489 | batch._params[paramOffset + 1]._int, |
| 454 | batch._params[paramOffset + 0]._float); | 490 | batch._params[paramOffset + 0]._float); |
| @@ -471,6 +507,7 @@ void GLBackend::do_glUniform2f(Batch& batch, uint32 paramOffset) { · 16 unmodified lines | |||
| 471 | // because these uniform setters are deprecated and we don;t want to create side effect | 507 | // because these uniform setters are deprecated and we don;t want to create side effect |
| 472 | return; | 508 | return; |
| 473 | } | 509 | } |
| 510 | updatePipeline(); | ||
| 474 | glUniform2f( | 511 | glUniform2f( |
| 475 | batch._params[paramOffset + 2]._int, | 512 | batch._params[paramOffset + 2]._int, |
| 476 | batch._params[paramOffset + 1]._float, | 513 | batch._params[paramOffset + 1]._float, |
| @@ -495,6 +532,7 @@ void GLBackend::do_glUniform3f(Batch& batch, uint32 paramOffset) { · 18 unmodified lines | |||
| 495 | // because these uniform setters are deprecated and we don;t want to create side effect | 532 | // because these uniform setters are deprecated and we don;t want to create side effect |
| 496 | return; | 533 | return; |
| 497 | } | 534 | } |
| 535 | updatePipeline(); | ||
| 498 | glUniform3f( | 536 | glUniform3f( |
| 499 | batch._params[paramOffset + 3]._int, | 537 | batch._params[paramOffset + 3]._int, |
| 500 | batch._params[paramOffset + 2]._float, | 538 | batch._params[paramOffset + 2]._float, |
| @@ -519,6 +557,7 @@ void GLBackend::do_glUniform3fv(Batch& batch, uint32 paramOffset) { · 18 unmodified lines | |||
| 519 | // because these uniform setters are deprecated and we don;t want to create side effect | 557 | // because these uniform setters are deprecated and we don;t want to create side effect |
| 520 | return; | 558 | return; |
| 521 | } | 559 | } |
| 560 | updatePipeline(); | ||
| 522 | glUniform3fv( | 561 | glUniform3fv( |
| 523 | batch._params[paramOffset + 2]._int, | 562 | batch._params[paramOffset + 2]._int, |
| 524 | batch._params[paramOffset + 1]._uint, | 563 | batch._params[paramOffset + 1]._uint, |
| @@ -544,6 +583,7 @@ void GLBackend::do_glUniform4fv(Batch& batch, uint32 paramOffset) { · 19 unmodified lines | |||
| 544 | // because these uniform setters are deprecated and we don;t want to create side effect | 583 | // because these uniform setters are deprecated and we don;t want to create side effect |
| 545 | return; | 584 | return; |
| 546 | } | 585 | } |
| 586 | updatePipeline(); | ||
| 547 | glUniform4fv( | 587 | glUniform4fv( |
| 548 | batch._params[paramOffset + 2]._int, | 588 | batch._params[paramOffset + 2]._int, |
| 549 | batch._params[paramOffset + 1]._uint, | 589 | batch._params[paramOffset + 1]._uint, |
| @@ -569,6 +609,7 @@ void GLBackend::do_glUniformMatrix4fv(Batch& batch, uint32 paramOffset) { · 19 unmodified lines | |||
| 569 | // because these uniform setters are deprecated and we don;t want to create side effect | 609 | // because these uniform setters are deprecated and we don;t want to create side effect |
| 570 | return; | 610 | return; |
| 571 | } | 611 | } |
| 612 | updatePipeline(); | ||
| 572 | glUniformMatrix4fv( | 613 | glUniformMatrix4fv( |
| 573 | batch._params[paramOffset + 3]._int, | 614 | batch._params[paramOffset + 3]._int, |
| 574 | batch._params[paramOffset + 2]._uint, | 615 | batch._params[paramOffset + 2]._uint, |
| @@ -656,4 +697,20 @@ void GLBackend::fetchMatrix(GLenum target, glm::mat4 & m) { · 81 unmodified lines | |||
| 656 | glGetFloatv(target, glm::value_ptr(m)); | 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 | #define hifi_gpu_GLBackend_h | 12 | #define hifi_gpu_GLBackend_h |
| 13 | 13 | ||
| 14 | #include <assert.h> | 14 | #include <assert.h> |
| 15 | #include <functional> | ||
| 16 | #include <bitset> | ||
| 17 | |||
| 15 | #include "GPUConfig.h" | 18 | #include "GPUConfig.h" |
| 16 | 19 | ||
| 17 | #include "Context.h" | 20 | #include "Context.h" |
| 18 | #include "Batch.h" | 21 | #include "Batch.h" |
| 19 | #include <bitset> | ||
| 20 | 22 | ||
| 21 | 23 | ||
| 22 | namespace gpu { | 24 | namespace gpu { |
| @@ -47,6 +49,11 @@ public: · 24 unmodified lines | |||
| 47 | 49 | ||
| 48 | static bool checkGLError(const char* name = nullptr); | 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 | static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet()); | 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 | void do_glDrawBuffers(Batch& batch, uint32 paramOffset); | 384 | void do_glDrawBuffers(Batch& batch, uint32 paramOffset); |
| 378 | 385 | ||
| 379 | void do_glUseProgram(Batch& batch, uint32 paramOffset); | 386 | void do_glUseProgram(Batch& batch, uint32 paramOffset); |
| 387 | void do_glUniform1i(Batch& batch, uint32 paramOffset); | ||
| 380 | void do_glUniform1f(Batch& batch, uint32 paramOffset); | 388 | void do_glUniform1f(Batch& batch, uint32 paramOffset); |
| 381 | void do_glUniform2f(Batch& batch, uint32 paramOffset); | 389 | void do_glUniform2f(Batch& batch, uint32 paramOffset); |
| 382 | void do_glUniform3f(Batch& batch, uint32 paramOffset); | 390 | void do_glUniform3f(Batch& batch, uint32 paramOffset); |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | |||
| 11 | #include "GPULogging.h" | 11 | #include "GPULogging.h" |
| 12 | #include "GLBackendShared.h" | 12 | #include "GLBackendShared.h" |
| 13 | 13 | ||
| 14 | using namespace gpu; | ||
| 14 | 15 | ||
| 15 | GLBackend::GLFramebuffer::GLFramebuffer() {} | 16 | GLBackend::GLFramebuffer::GLFramebuffer() {} |
| 16 | 17 | ||
| @@ -17,9 +17,7 @@ · 16 unmodified lines | |||
| 17 | 17 | ||
| 18 | #include "Batch.h" | 18 | #include "Batch.h" |
| 19 | 19 | ||
| 20 | using namespace gpu; | 20 | static const GLenum _primitiveToGLmode[gpu::NUM_PRIMITIVES] = { |
| 21 | |||
| 22 | static const GLenum _primitiveToGLmode[NUM_PRIMITIVES] = { | ||
| 23 | GL_POINTS, | 21 | GL_POINTS, |
| 24 | GL_LINES, | 22 | GL_LINES, |
| 25 | GL_LINE_STRIP, | 23 | GL_LINE_STRIP, |
| @@ -30,7 +28,7 @@ static const GLenum _primitiveToGLmode[NUM_PRIMITIVES] = { · 4 unmodified lines | |||
| 30 | GL_QUAD_STRIP, | 28 | GL_QUAD_STRIP, |
| 31 | }; | 29 | }; |
| 32 | 30 | ||
| 33 | static const GLenum _elementTypeToGLType[NUM_TYPES]= { | 31 | static const GLenum _elementTypeToGLType[gpu::NUM_TYPES] = { |
| 34 | GL_FLOAT, | 32 | GL_FLOAT, |
| 35 | GL_INT, | 33 | GL_INT, |
| 36 | GL_UNSIGNED_INT, | 34 | GL_UNSIGNED_INT, |
| @@ -49,10 +47,12 @@ static const GLenum _elementTypeToGLType[NUM_TYPES]= { · 12 unmodified lines | |||
| 49 | GL_UNSIGNED_BYTE | 47 | GL_UNSIGNED_BYTE |
| 50 | }; | 48 | }; |
| 51 | 49 | ||
| 52 | #if _DEBUG | 50 | // Stupid preprocessor trick to turn the line macro into a string |
| 53 | #define CHECK_GL_ERROR() ::gpu::GLBackend::checkGLError(__FUNCTION__) | 51 | #define CHECK_GL_ERROR_HELPER(x) #x |
| 54 | #else | 52 | // FIXME doesn't build on Linux or Mac. Hmmmm |
| 55 | #define CHECK_GL_ERROR() false | 53 | // #define CHECK_GL_ERROR() gpu::GLBackend::checkGLErrorDebug(__FUNCTION__ ":" CHECK_GL_ERROR_HELPER(__LINE__)) |
| 56 | #endif | 54 | #define CHECK_GL_ERROR() gpu::GLBackend::checkGLErrorDebug(__FUNCTION__) |
| 55 | |||
| 56 | #define CHECK_GL_STACK_STABLE(f) gpu::GLBackend::checkGLStackStable(f) | ||
| 57 | 57 | ||
| 58 | #endif | 58 | #endif |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | |||
| 11 | #include "GPULogging.h" | 11 | #include "GPULogging.h" |
| 12 | #include "GLBackendShared.h" | 12 | #include "GLBackendShared.h" |
| 13 | 13 | ||
| 14 | using namespace gpu; | ||
| 14 | 15 | ||
| 15 | GLBackend::GLTexture::GLTexture() : | 16 | GLBackend::GLTexture::GLTexture() : |
| 16 | _storageStamp(0), | 17 | _storageStamp(0), |
| @@ -343,10 +344,10 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { · 326 unmodified lines | |||
| 343 | if (bytes && texture.isAutogenerateMips()) { | 344 | if (bytes && texture.isAutogenerateMips()) { |
| 344 | glGenerateMipmap(GL_TEXTURE_2D); | 345 | glGenerateMipmap(GL_TEXTURE_2D); |
| 345 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); | 346 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); |
| 346 | } else { | 347 | }/* else { |
| 347 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | 348 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| 348 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | 349 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| 349 | } | 350 | }*/ |
| 350 | 351 | ||
| 351 | object->_target = GL_TEXTURE_2D; | 352 | object->_target = GL_TEXTURE_2D; |
| 352 | 353 | ||
| @@ -75,6 +75,8 @@ void GLBackend::syncTransformStateCache() { · 74 unmodified lines | |||
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | void GLBackend::updateTransform() { | 77 | void GLBackend::updateTransform() { |
| 78 | GLint originalMatrixMode; | ||
| 79 | glGetIntegerv(GL_MATRIX_MODE, &originalMatrixMode); | ||
| 78 | // Check all the dirty flags and update the state accordingly | 80 | // Check all the dirty flags and update the state accordingly |
| 79 | if (_transform._invalidProj) { | 81 | if (_transform._invalidProj) { |
| 80 | _transform._transformCamera._projection = _transform._projection; | 82 | _transform._transformCamera._projection = _transform._projection; |
| @@ -132,12 +134,13 @@ void GLBackend::updateTransform() { · 51 unmodified lines | |||
| 132 | (void) CHECK_GL_ERROR(); | 134 | (void) CHECK_GL_ERROR(); |
| 133 | } | 135 | } |
| 134 | 136 | ||
| 137 | |||
| 135 | if (_transform._invalidModel || _transform._invalidView) { | 138 | if (_transform._invalidModel || _transform._invalidView) { |
| 139 | if (_transform._lastMode != GL_MODELVIEW) { | ||
| 140 | glMatrixMode(GL_MODELVIEW); | ||
| 141 | _transform._lastMode = GL_MODELVIEW; | ||
| 142 | } | ||
| 136 | if (!_transform._model.isIdentity()) { | 143 | if (!_transform._model.isIdentity()) { |
| 137 | if (_transform._lastMode != GL_MODELVIEW) { | ||
| 138 | glMatrixMode(GL_MODELVIEW); | ||
| 139 | _transform._lastMode = GL_MODELVIEW; | ||
| 140 | } | ||
| 141 | Transform::Mat4 modelView; | 144 | Transform::Mat4 modelView; |
| 142 | if (!_transform._view.isIdentity()) { | 145 | if (!_transform._view.isIdentity()) { |
| 143 | Transform mvx; | 146 | Transform mvx; |
| @@ -147,19 +150,12 @@ void GLBackend::updateTransform() { · 3 unmodified lines | |||
| 147 | _transform._model.getMatrix(modelView); | 150 | _transform._model.getMatrix(modelView); |
| 148 | } | 151 | } |
| 149 | glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); | 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 | } else { | 157 | } else { |
| 151 | if (!_transform._view.isIdentity()) { | 158 | glLoadIdentity(); |
| 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 | } | ||
| 163 | } | 159 | } |
| 164 | (void) CHECK_GL_ERROR(); | 160 | (void) CHECK_GL_ERROR(); |
| 165 | } | 161 | } |
| @@ -167,6 +163,7 @@ void GLBackend::updateTransform() { · 1 unmodified line | |||
| 167 | 163 | ||
| 168 | // Flags are clean | 164 | // Flags are clean |
| 169 | _transform._invalidView = _transform._invalidProj = _transform._invalidModel = false; | 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 | void sphericalHarmonicsEvaluateDirection(float * result, int order, const glm::vec3 & dir) { | 581 | void sphericalHarmonicsEvaluateDirection(float * result, int order, const glm::vec3 & dir) { |
| 582 | // calculate coefficients for first 3 bands of spherical harmonics | 582 | // calculate coefficients for first 3 bands of spherical harmonics |
| 583 | double P_0_0 = 0.282094791773878140; | 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 | double P_1_1 = -0.488602511902919920; | 585 | double P_1_1 = -0.488602511902919920; |
| 586 | double P_2_0 = 0.946174695757560080 * dir.z * dir.z - 0.315391565252520050; | 586 | double P_2_0 = 0.946174695757560080 * (double)dir.z * (double)dir.z - 0.315391565252520050; |
| 587 | double P_2_1 = -1.092548430592079200 * dir.z; | 587 | double P_2_1 = -1.092548430592079200 * (double)dir.z; |
| 588 | double P_2_2 = 0.546274215296039590; | 588 | double P_2_2 = 0.546274215296039590; |
| 589 | result[0] = P_0_0; | 589 | result[0] = P_0_0; |
| 590 | result[1] = P_1_1 * dir.y; | 590 | result[1] = P_1_1 * (double)dir.y; |
| 591 | result[2] = P_1_0; | 591 | result[2] = P_1_0; |
| 592 | result[3] = P_1_1 * dir.x; | 592 | result[3] = P_1_1 * (double)dir.x; |
| 593 | result[4] = P_2_2 * (dir.x * dir.y + dir.y * 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 * dir.y; | 594 | result[5] = P_2_1 * (double)dir.y; |
| 595 | result[6] = P_2_0; | 595 | result[6] = P_2_0; |
| 596 | result[7] = P_2_1 * dir.x; | 596 | result[7] = P_2_1 * (double)dir.x; |
| 597 | result[8] = P_2_2 * (dir.x * dir.x - dir.y * dir.y); | 597 | result[8] = P_2_2 * ((double)dir.x * (double)dir.x - (double)dir.y * (double)dir.y); |
| 598 | } | 598 | } |
| 599 | 599 | ||
| 600 | bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<glm::vec3> & output, const uint order) { | 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 | L21 = coefs[7]; | 767 | L21 = coefs[7]; |
| 768 | L22 = coefs[8]; | 768 | L22 = coefs[8]; |
| 769 | } | 769 | } |
| 770 | } | 770 | } |
| @@ -73,7 +73,7 @@ void Light::setMaximumRadius(float radius) { · 72 unmodified lines | |||
| 73 | radius = 1.0f; | 73 | radius = 1.0f; |
| 74 | } | 74 | } |
| 75 | float CutOffIntensityRatio = 0.05f; | 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 | editSchema()._attenuation = Vec4(surfaceRadius, 1.0f/surfaceRadius, CutOffIntensityRatio, radius); | 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 | thePipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, skyState)); | 73 | thePipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, skyState)); |
| 74 | 74 | ||
| 75 | const float CLIP = 1.0; | 75 | const float CLIP = 1.0f; |
| 76 | const glm::vec2 vertices[4] = { {-CLIP, -CLIP}, {CLIP, -CLIP}, {-CLIP, CLIP}, {CLIP, CLIP}}; | 76 | const glm::vec2 vertices[4] = { {-CLIP, -CLIP}, {CLIP, -CLIP}, {-CLIP, CLIP}, {CLIP, CLIP}}; |
| 77 | theBuffer.reset(new gpu::Buffer(sizeof(vertices), (const gpu::Byte*) vertices)); | 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 | } else { | 110 | } else { |
| 111 | // skybox has no cubemap, just clear the color buffer | 111 | // skybox has no cubemap, just clear the color buffer |
| 112 | auto color = skybox.getColor(); | 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 | void EarthSunModel::updateWorldToSurface() const { | 43 | void EarthSunModel::updateWorldToSurface() const { |
| 44 | // Check if the final position is too close to the earth center ? | 44 | // Check if the final position is too close to the earth center ? |
| 45 | double absAltitude = _earthRadius + _altitude; | 45 | float absAltitude = _earthRadius + _altitude; |
| 46 | if ( absAltitude < 0.01) { | 46 | if ( absAltitude < 0.01f) { |
| 47 | absAltitude = 0.01; | 47 | absAltitude = 0.01f; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | // Final world to local Frame | 50 | // Final world to local Frame |
| @@ -263,8 +263,8 @@ double evalSunDeclinaison(double dayNumber) { · 212 unmodified lines | |||
| 263 | void SunSkyStage::updateGraphicsObject() const { | 263 | void SunSkyStage::updateGraphicsObject() const { |
| 264 | // Always update the sunLongitude based on the current dayTime and the current origin | 264 | // Always update the sunLongitude based on the current dayTime and the current origin |
| 265 | // The day time is supposed to be local at the origin | 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; | 266 | float signedNormalizedDayTime = (_dayTime - NUM_HOURS_PER_HALF_DAY) / NUM_HOURS_PER_HALF_DAY; |
| 267 | double sunLongitude = _earthSunModel.getLongitude() + (MAX_LONGITUDE * signedNormalizedDayTime); | 267 | float sunLongitude = _earthSunModel.getLongitude() + (MAX_LONGITUDE * signedNormalizedDayTime); |
| 268 | _earthSunModel.setSunLongitude(sunLongitude); | 268 | _earthSunModel.setSunLongitude(sunLongitude); |
| 269 | 269 | ||
| 270 | // And update the sunLAtitude as the declinaison depending of the time of the year | 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 | void SunSkyStage::setSkybox(const SkyboxPointer& skybox) { | 302 | void SunSkyStage::setSkybox(const SkyboxPointer& skybox) { |
| 303 | _skybox = skybox; | 303 | _skybox = skybox; |
| 304 | invalidate(); | 304 | invalidate(); |
| 305 | } | 305 | } |
| @@ -72,7 +72,7 @@ public: · 71 unmodified lines | |||
| 72 | 72 | ||
| 73 | protected: | 73 | protected: |
| 74 | float _scale = 1000.0f; //Km | 74 | float _scale = 1000.0f; //Km |
| 75 | double _earthRadius = 6360.0; | 75 | float _earthRadius = 6360.0; |
| 76 | 76 | ||
| 77 | Quat _surfaceOrientation; | 77 | Quat _surfaceOrientation; |
| 78 | 78 | ||
| @@ -308,6 +308,9 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const · 307 unmodified lines | |||
| 308 | handlePath(returnedPath, trigger); | 308 | handlePath(returnedPath, trigger); |
| 309 | } | 309 | } |
| 310 | } else { | 310 | } else { |
| 311 | // we're going to hit the index path, set that as the _newHostLookupPath | ||
| 312 | _newHostLookupPath = INDEX_PATH; | ||
| 313 | |||
| 311 | // we didn't override the path or get one back - ask the DS for the viewpoint of its index path | 314 | // we didn't override the path or get one back - ask the DS for the viewpoint of its index path |
| 312 | // which we will jump to if it exists | 315 | // which we will jump to if it exists |
| 313 | emit pathChangeRequired(INDEX_PATH); | 316 | emit pathChangeRequired(INDEX_PATH); |
| @@ -479,6 +482,7 @@ bool AddressManager::handleViewpoint(const QString& viewpointString, bool should · 165 unmodified lines | |||
| 479 | // We use _newHostLookupPath to determine if the client has already stored its last address | 482 | // We use _newHostLookupPath to determine if the client has already stored its last address |
| 480 | // before moving to a new host thanks to the information in the same lookup URL. | 483 | // before moving to a new host thanks to the information in the same lookup URL. |
| 481 | 484 | ||
| 485 | |||
| 482 | if (definitelyPathOnly || (!pathString.isEmpty() && pathString != _newHostLookupPath)) { | 486 | if (definitelyPathOnly || (!pathString.isEmpty() && pathString != _newHostLookupPath)) { |
| 483 | addCurrentAddressToHistory(LookupTrigger::UserInput); | 487 | addCurrentAddressToHistory(LookupTrigger::UserInput); |
| 484 | } | 488 | } |
| @@ -62,6 +62,9 @@ public: · 61 unmodified lines | |||
| 62 | 62 | ||
| 63 | void loadSettings(const QString& lookupString = QString()); | 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 | public slots: | 68 | public slots: |
| 66 | void handleLookupString(const QString& lookupString); | 69 | void handleLookupString(const QString& lookupString); |
| 67 | 70 | ||
| @@ -21,7 +21,7 @@ BandwidthRecorder::Channel::Channel() { · 20 unmodified lines | |||
| 21 | float BandwidthRecorder::Channel::getAverageInputPacketsPerSecond() { | 21 | float BandwidthRecorder::Channel::getAverageInputPacketsPerSecond() { |
| 22 | float delt = _input.getEventDeltaAverage(); | 22 | float delt = _input.getEventDeltaAverage(); |
| 23 | if (delt > 0.0f) { | 23 | if (delt > 0.0f) { |
| 24 | return (1.0 / delt); | 24 | return (1.0f / delt); |
| 25 | } | 25 | } |
| 26 | return 0.0f; | 26 | return 0.0f; |
| 27 | } | 27 | } |
| @@ -29,7 +29,7 @@ float BandwidthRecorder::Channel::getAverageInputPacketsPerSecond() { · 1 unmodified line | |||
| 29 | float BandwidthRecorder::Channel::getAverageOutputPacketsPerSecond() { | 29 | float BandwidthRecorder::Channel::getAverageOutputPacketsPerSecond() { |
| 30 | float delt = _input.getEventDeltaAverage(); | 30 | float delt = _input.getEventDeltaAverage(); |
| 31 | if (delt > 0.0f) { | 31 | if (delt > 0.0f) { |
| 32 | return (1.0 / _output.getEventDeltaAverage()); | 32 | return (1.0f / _output.getEventDeltaAverage()); |
| 33 | } | 33 | } |
| 34 | return 0.0f; | 34 | return 0.0f; |
| 35 | } | 35 | } |
| @@ -75,7 +75,7 @@ CoverageMap::~CoverageMap() { · 74 unmodified lines | |||
| 75 | 75 | ||
| 76 | void CoverageMap::printStats() { | 76 | void CoverageMap::printStats() { |
| 77 | qCDebug(octree, "CoverageMap::printStats()..."); | 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 | qCDebug(octree, "_mapCount=%d",_mapCount); | 79 | qCDebug(octree, "_mapCount=%d",_mapCount); |
| 80 | qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls); | 80 | qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls); |
| 81 | qCDebug(octree, "_notAllInView=%d",_notAllInView); | 81 | qCDebug(octree, "_notAllInView=%d",_notAllInView); |
| @@ -82,7 +82,7 @@ void CoverageMapV2::erase() { · 81 unmodified lines | |||
| 82 | 82 | ||
| 83 | if (_isRoot && wantDebugging) { | 83 | if (_isRoot && wantDebugging) { |
| 84 | qCDebug(octree, "CoverageMapV2 last to be deleted..."); | 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 | qCDebug(octree, "_mapCount=%d",_mapCount); | 86 | qCDebug(octree, "_mapCount=%d",_mapCount); |
| 87 | qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls); | 87 | qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls); |
| 88 | qCDebug(octree, "_notAllInView=%d",_notAllInView); | 88 | qCDebug(octree, "_notAllInView=%d",_notAllInView); |
| @@ -69,8 +69,8 @@ void OctreeElement::init(unsigned char * octalCode) { · 68 unmodified lines | |||
| 69 | // set up the _children union | 69 | // set up the _children union |
| 70 | _childBitmask = 0; | 70 | _childBitmask = 0; |
| 71 | _childrenExternal = false; | 71 | _childrenExternal = false; |
| 72 | 72 | ||
| 73 | 73 | ||
| 74 | #ifdef BLENDED_UNION_CHILDREN | 74 | #ifdef BLENDED_UNION_CHILDREN |
| 75 | _children.external = NULL; | 75 | _children.external = NULL; |
| 76 | _singleChildrenCount++; | 76 | _singleChildrenCount++; |
| @@ -662,7 +662,7 @@ void OctreeElement::deleteAllChildren() { · 585 unmodified lines | |||
| 662 | delete childAt; | 662 | delete childAt; |
| 663 | } | 663 | } |
| 664 | } | 664 | } |
| 665 | 665 | ||
| 666 | if (_childrenExternal) { | 666 | if (_childrenExternal) { |
| 667 | // if the children_t union represents _children.external we need to delete it here | 667 | // if the children_t union represents _children.external we need to delete it here |
| 668 | delete[] _children.external; | 668 | delete[] _children.external; |
| @@ -764,7 +764,7 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) { · 95 unmodified lines | |||
| 764 | memset(_children.external, 0, sizeof(OctreeElement*) * NUMBER_OF_CHILDREN); | 764 | memset(_children.external, 0, sizeof(OctreeElement*) * NUMBER_OF_CHILDREN); |
| 765 | _children.external[firstIndex] = previousChild; | 765 | _children.external[firstIndex] = previousChild; |
| 766 | _children.external[childIndex] = child; | 766 | _children.external[childIndex] = child; |
| 767 | 767 | ||
| 768 | _childrenExternal = true; | 768 | _childrenExternal = true; |
| 769 | 769 | ||
| 770 | _externalChildrenMemoryUsage += NUMBER_OF_CHILDREN * sizeof(OctreeElement*); | 770 | _externalChildrenMemoryUsage += NUMBER_OF_CHILDREN * sizeof(OctreeElement*); |
| @@ -776,7 +776,7 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) { · 5 unmodified lines | |||
| 776 | 776 | ||
| 777 | delete[] _children.external; | 777 | delete[] _children.external; |
| 778 | _childrenExternal = false; | 778 | _childrenExternal = false; |
| 779 | 779 | ||
| 780 | _externalChildrenMemoryUsage -= NUMBER_OF_CHILDREN * sizeof(OctreeElement*); | 780 | _externalChildrenMemoryUsage -= NUMBER_OF_CHILDREN * sizeof(OctreeElement*); |
| 781 | if (childIndex == firstIndex) { | 781 | if (childIndex == firstIndex) { |
| 782 | _children.single = previousSecondChild; | 782 | _children.single = previousSecondChild; |
| @@ -1203,12 +1203,13 @@ void OctreeElement::printDebugDetails(const char* label) const { · 420 unmodified lines | |||
| 1203 | setAtBit(childBits,i); | 1203 | setAtBit(childBits,i); |
| 1204 | } | 1204 | } |
| 1205 | } | 1205 | } |
| 1206 | 1206 | ||
| 1207 | QDebug elementDebug = qDebug().nospace(); | 1207 | QDebug elementDebug = qDebug().nospace(); |
| 1208 | 1208 | ||
| 1209 | QString resultString; | 1209 | QString resultString; |
| 1210 | resultString.sprintf("%s - Voxel at corner=(%f,%f,%f) size=%f\n isLeaf=%s isDirty=%s shouldRender=%s\n children=", label, | 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 | debug::valueOf(isLeaf()), debug::valueOf(isDirty()), debug::valueOf(getShouldRender())); | 1213 | debug::valueOf(isLeaf()), debug::valueOf(isDirty()), debug::valueOf(getShouldRender())); |
| 1213 | elementDebug << resultString; | 1214 | elementDebug << resultString; |
| 1214 | 1215 | ||
| @@ -1236,7 +1237,7 @@ ViewFrustum::location OctreeElement::inFrustum(const ViewFrustum& viewFrustum) c · 21 unmodified lines | |||
| 1236 | // By doing this, we don't need to test each child voxel's position vs the LOD boundary | 1237 | // By doing this, we don't need to test each child voxel's position vs the LOD boundary |
| 1237 | bool OctreeElement::calculateShouldRender(const ViewFrustum* viewFrustum, float voxelScaleSize, int boundaryLevelAdjust) const { | 1238 | bool OctreeElement::calculateShouldRender(const ViewFrustum* viewFrustum, float voxelScaleSize, int boundaryLevelAdjust) const { |
| 1238 | bool shouldRender = false; | 1239 | bool shouldRender = false; |
| 1239 | 1240 | ||
| 1240 | if (hasContent()) { | 1241 | if (hasContent()) { |
| 1241 | float furthestDistance = furthestDistanceToCamera(*viewFrustum); | 1242 | float furthestDistance = furthestDistanceToCamera(*viewFrustum); |
| 1242 | float childBoundary = boundaryDistanceForRenderLevel(getLevel() + 1 + boundaryLevelAdjust, voxelScaleSize); | 1243 | float childBoundary = boundaryDistanceForRenderLevel(getLevel() + 1 + boundaryLevelAdjust, voxelScaleSize); |
| @@ -1330,7 +1331,7 @@ void OctreeElement::notifyUpdateHooks() { · 87 unmodified lines | |||
| 1330 | } | 1331 | } |
| 1331 | 1332 | ||
| 1332 | bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, | 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 | void** intersectedObject, bool precisionPicking) { | 1335 | void** intersectedObject, bool precisionPicking) { |
| 1335 | 1336 | ||
| 1336 | keepSearching = true; // assume that we will continue searching after this. | 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 | // for any details inside the cube to be closer so we don't need to consider them. | 1355 | // for any details inside the cube to be closer so we don't need to consider them. |
| 1355 | if (_cube.contains(origin) || distanceToElementCube < distance) { | 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 | face, intersectedObject, precisionPicking, distanceToElementCube)) { | 1359 | face, intersectedObject, precisionPicking, distanceToElementCube)) { |
| 1359 | 1360 | ||
| 1360 | if (distanceToElementDetails < distance) { | 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 | bool OctreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, | 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 | void** intersectedObject, bool precisionPicking, float distanceToElementCube) { | 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 | if (hasContent()) { | 1376 | if (hasContent()) { |
| 1376 | element = this; | 1377 | element = this; |
| 1377 | distance = distanceToElementCube; | 1378 | distance = distanceToElementCube; |
| @@ -1399,7 +1400,8 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float · 21 unmodified lines | |||
| 1399 | float halfOurScale = ourScale / 2.0f; | 1400 | float halfOurScale = ourScale / 2.0f; |
| 1400 | 1401 | ||
| 1401 | if(s > ourScale) { | 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 | if (s > halfOurScale) { | 1407 | if (s > halfOurScale) { |
| @@ -1466,21 +1468,21 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float · 60 unmodified lines | |||
| 1466 | 1468 | ||
| 1467 | OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AACube& cube) { | 1469 | OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AACube& cube) { |
| 1468 | OctreeElement* child = NULL; | 1470 | OctreeElement* child = NULL; |
| 1469 | 1471 | ||
| 1470 | int childIndex = getMyChildContaining(cube); | 1472 | int childIndex = getMyChildContaining(cube); |
| 1471 | 1473 | ||
| 1472 | // If getMyChildContaining() returns CHILD_UNKNOWN then it means that our level | 1474 | // If getMyChildContaining() returns CHILD_UNKNOWN then it means that our level |
| 1473 | // is the correct level for this cube | 1475 | // is the correct level for this cube |
| 1474 | if (childIndex == CHILD_UNKNOWN) { | 1476 | if (childIndex == CHILD_UNKNOWN) { |
| 1475 | return this; | 1477 | return this; |
| 1476 | } | 1478 | } |
| 1477 | 1479 | ||
| 1478 | // Now, check if we have a child at that location | 1480 | // Now, check if we have a child at that location |
| 1479 | child = getChildAtIndex(childIndex); | 1481 | child = getChildAtIndex(childIndex); |
| 1480 | if (!child) { | 1482 | if (!child) { |
| 1481 | child = addChildAtIndex(childIndex); | 1483 | child = addChildAtIndex(childIndex); |
| 1482 | } | 1484 | } |
| 1483 | 1485 | ||
| 1484 | // if we've made a really small child, then go ahead and use that one. | 1486 | // if we've made a really small child, then go ahead and use that one. |
| 1485 | if (child->getScale() <= SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE) { | 1487 | if (child->getScale() <= SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE) { |
| 1486 | return child; | 1488 | return child; |
| @@ -1492,21 +1494,21 @@ OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AACube& cu · 5 unmodified lines | |||
| 1492 | 1494 | ||
| 1493 | OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AABox& box) { | 1495 | OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AABox& box) { |
| 1494 | OctreeElement* child = NULL; | 1496 | OctreeElement* child = NULL; |
| 1495 | 1497 | ||
| 1496 | int childIndex = getMyChildContaining(box); | 1498 | int childIndex = getMyChildContaining(box); |
| 1497 | 1499 | ||
| 1498 | // If getMyChildContaining() returns CHILD_UNKNOWN then it means that our level | 1500 | // If getMyChildContaining() returns CHILD_UNKNOWN then it means that our level |
| 1499 | // is the correct level for this cube | 1501 | // is the correct level for this cube |
| 1500 | if (childIndex == CHILD_UNKNOWN) { | 1502 | if (childIndex == CHILD_UNKNOWN) { |
| 1501 | return this; | 1503 | return this; |
| 1502 | } | 1504 | } |
| 1503 | 1505 | ||
| 1504 | // Now, check if we have a child at that location | 1506 | // Now, check if we have a child at that location |
| 1505 | child = getChildAtIndex(childIndex); | 1507 | child = getChildAtIndex(childIndex); |
| 1506 | if (!child) { | 1508 | if (!child) { |
| 1507 | child = addChildAtIndex(childIndex); | 1509 | child = addChildAtIndex(childIndex); |
| 1508 | } | 1510 | } |
| 1509 | 1511 | ||
| 1510 | // if we've made a really small child, then go ahead and use that one. | 1512 | // if we've made a really small child, then go ahead and use that one. |
| 1511 | if (child->getScale() <= SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE) { | 1513 | if (child->getScale() <= SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE) { |
| 1512 | return child; | 1514 | return child; |
| @@ -1542,7 +1544,7 @@ int OctreeElement::getMyChildContaining(const AACube& cube) const { · 29 unmodified lines | |||
| 1542 | if (childIndexCubeMinimum != childIndexCubeMaximum) { | 1544 | if (childIndexCubeMinimum != childIndexCubeMaximum) { |
| 1543 | return CHILD_UNKNOWN; | 1545 | return CHILD_UNKNOWN; |
| 1544 | } | 1546 | } |
| 1545 | 1547 | ||
| 1546 | return childIndexCubeMinimum; // either would do, they are the same | 1548 | return childIndexCubeMinimum; // either would do, they are the same |
| 1547 | } | 1549 | } |
| 1548 | return CHILD_UNKNOWN; // since cube is not contained in our element, it can't be in one of our children | 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 | // TODO: consider changing this to assert() | 1557 | // TODO: consider changing this to assert() |
| 1556 | if(boxLargestScale > ourScale) { | 1558 | if(boxLargestScale > ourScale) { |
| 1557 | qCDebug(octree, "UNEXPECTED -- OctreeElement::getMyChildContaining() " | 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 | // Determine which of our children the minimum and maximum corners of the cube live in... | 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 | int childIndexCubeMinimum = getMyChildContainingPoint(cubeCornerMinimum); | 1568 | int childIndexCubeMinimum = getMyChildContainingPoint(cubeCornerMinimum); |
| 1567 | int childIndexCubeMaximum = getMyChildContainingPoint(cubeCornerMaximum); | 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 | // then we are the containing element | 1572 | // then we are the containing element |
| 1571 | if (childIndexCubeMinimum != childIndexCubeMaximum) { | 1573 | if (childIndexCubeMinimum != childIndexCubeMaximum) { |
| 1572 | return CHILD_UNKNOWN; | 1574 | return CHILD_UNKNOWN; |
| @@ -1579,12 +1581,12 @@ int OctreeElement::getMyChildContaining(const AABox& box) const { · 6 unmodified lines | |||
| 1579 | int OctreeElement::getMyChildContainingPoint(const glm::vec3& point) const { | 1581 | int OctreeElement::getMyChildContainingPoint(const glm::vec3& point) const { |
| 1580 | glm::vec3 ourCenter = _cube.calcCenter(); | 1582 | glm::vec3 ourCenter = _cube.calcCenter(); |
| 1581 | int childIndex = CHILD_UNKNOWN; | 1583 | int childIndex = CHILD_UNKNOWN; |
| 1582 | 1584 | ||
| 1583 | // since point is not contained in our element, it can't be in one of our children | 1585 | // since point is not contained in our element, it can't be in one of our children |
| 1584 | if (!_cube.contains(point)) { | 1586 | if (!_cube.contains(point)) { |
| 1585 | return CHILD_UNKNOWN; | 1587 | return CHILD_UNKNOWN; |
| 1586 | } | 1588 | } |
| 1587 | 1589 | ||
| 1588 | // left half | 1590 | // left half |
| 1589 | if (point.x > ourCenter.x) { | 1591 | if (point.x > ourCenter.x) { |
| 1590 | if (point.y > ourCenter.y) { | 1592 | if (point.y > ourCenter.y) { |
| @@ -384,10 +384,12 @@ bool OctreePacketData::appendValue(const glm::vec3& value) { · 383 unmodified lines | |||
| 384 | bool OctreePacketData::appendValue(const QVector<glm::vec3>& value) { | 384 | bool OctreePacketData::appendValue(const QVector<glm::vec3>& value) { |
| 385 | uint16_t qVecSize = value.size(); | 385 | uint16_t qVecSize = value.size(); |
| 386 | bool success = appendValue(qVecSize); | 386 | bool success = appendValue(qVecSize); |
| 387 | success = append((const unsigned char*)value.constData(), qVecSize * sizeof(glm::vec3)); | ||
| 388 | if (success) { | 387 | if (success) { |
| 389 | _bytesOfValues += qVecSize * sizeof(glm::vec3); | 388 | success = append((const unsigned char*)value.constData(), qVecSize * sizeof(glm::vec3)); |
| 390 | _totalBytesOfValues += qVecSize * sizeof(glm::vec3); | 389 | if (success) { |
| 390 | _bytesOfValues += qVecSize * sizeof(glm::vec3); | ||
| 391 | _totalBytesOfValues += qVecSize * sizeof(glm::vec3); | ||
| 392 | } | ||
| 391 | } | 393 | } |
| 392 | return success; | 394 | return success; |
| 393 | } | 395 | } |
| @@ -350,6 +350,19 @@ void OctreePersistThread::rollOldBackupVersions(const BackupRule& rule) { · 349 unmodified lines | |||
| 350 | if (rule.extensionFormat.contains("%N")) { | 350 | if (rule.extensionFormat.contains("%N")) { |
| 351 | if (rule.maxBackupVersions > 0) { | 351 | if (rule.maxBackupVersions > 0) { |
| 352 | qCDebug(octree) << "Rolling old backup versions for rule" << rule.name << "..."; | 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 | for(int n = rule.maxBackupVersions - 1; n > 0; n--) { | 366 | for(int n = rule.maxBackupVersions - 1; n > 0; n--) { |
| 354 | QString backupExtensionN = rule.extensionFormat; | 367 | QString backupExtensionN = rule.extensionFormat; |
| 355 | QString backupExtensionNplusOne = rule.extensionFormat; | 368 | QString backupExtensionNplusOne = rule.extensionFormat; |
| @@ -96,8 +96,9 @@ void BoundingBox::explandToInclude(const BoundingBox& box) { · 95 unmodified lines | |||
| 96 | 96 | ||
| 97 | void BoundingBox::printDebugDetails(const char* label) const { | 97 | void BoundingBox::printDebugDetails(const char* label) const { |
| 98 | qCDebug(octree, "%s _set=%s\n corner=%f,%f size=%f,%f\n bounds=[(%f,%f) to (%f,%f)]", | 98 | qCDebug(octree, "%s _set=%s\n corner=%f,%f size=%f,%f\n bounds=[(%f,%f) to (%f,%f)]", |
| 99 | (label ? label : "BoundingBox"), | 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); | 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 | OctreeProjectedPolygon::OctreeProjectedPolygon(const BoundingBox& box) : | 110 | OctreeProjectedPolygon::OctreeProjectedPolygon(const BoundingBox& box) : |
| 110 | _vertexCount(4), | 111 | _vertexCount(4), |
| 111 | _maxX(-FLT_MAX), _maxY(-FLT_MAX), _minX(FLT_MAX), _minY(FLT_MAX), | 112 | _maxX(-FLT_MAX), _maxY(-FLT_MAX), _minX(FLT_MAX), _minY(FLT_MAX), |
| 112 | _distance(0) | 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 | _vertices[vertex] = point; | 122 | _vertices[vertex] = point; |
| 122 | 123 | ||
| 123 | // keep track of our bounding box | 124 | // keep track of our bounding box |
| 124 | if (point.x > _maxX) { | 125 | if (point.x > _maxX) { |
| 125 | _maxX = point.x; | 126 | _maxX = point.x; |
| @@ -133,14 +134,14 @@ void OctreeProjectedPolygon::setVertex(int vertex, const glm::vec2& point) { · 7 unmodified lines | |||
| 133 | if (point.y < _minY) { | 134 | if (point.y < _minY) { |
| 134 | _minY = point.y; | 135 | _minY = point.y; |
| 135 | } | 136 | } |
| 136 | 137 | ||
| 137 | } | 138 | } |
| 138 | 139 | ||
| 139 | // can be optimized with new pointInside() | 140 | // can be optimized with new pointInside() |
| 140 | bool OctreeProjectedPolygon::occludes(const OctreeProjectedPolygon& occludee, bool checkAllInView) const { | 141 | bool OctreeProjectedPolygon::occludes(const OctreeProjectedPolygon& occludee, bool checkAllInView) const { |
| 141 | 142 | ||
| 142 | OctreeProjectedPolygon::occludes_calls++; | 143 | OctreeProjectedPolygon::occludes_calls++; |
| 143 | 144 | ||
| 144 | // if we are completely out of view, then we definitely don't occlude! | 145 | // if we are completely out of view, then we definitely don't occlude! |
| 145 | // if the occludee is completely out of view, then we also don't occlude it | 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 | (occludee.getMinY() < getMinY())) { | 159 | (occludee.getMinY() < getMinY())) { |
| 159 | return false; | 160 | return false; |
| 160 | } | 161 | } |
| 161 | 162 | ||
| 162 | // we need to test for identity as well, because in the case of identity, none of the points | 163 | // we need to test for identity as well, because in the case of identity, none of the points |
| 163 | // will be "inside" but we don't want to bail early on the first non-inside point | 164 | // will be "inside" but we don't want to bail early on the first non-inside point |
| 164 | bool potentialIdenity = false; | 165 | bool potentialIdenity = false; |
| @@ -171,7 +172,7 @@ bool OctreeProjectedPolygon::occludes(const OctreeProjectedPolygon& occludee, bo · 6 unmodified lines | |||
| 171 | for(int i = 0; i < occludee.getVertexCount(); i++) { | 172 | for(int i = 0; i < occludee.getVertexCount(); i++) { |
| 172 | bool vertexMatched = false; | 173 | bool vertexMatched = false; |
| 173 | if (!pointInside(occludee.getVertex(i), &vertexMatched)) { | 174 | if (!pointInside(occludee.getVertex(i), &vertexMatched)) { |
| 174 | 175 | ||
| 175 | // so the point we just tested isn't inside, but it might have matched a vertex | 176 | // so the point we just tested isn't inside, but it might have matched a vertex |
| 176 | // if it didn't match a vertext, then we bail because we can't be an identity | 177 | // if it didn't match a vertext, then we bail because we can't be an identity |
| 177 | // or if we're not expecting identity, then we also bail early, no matter what | 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 | pointsInside++; | 183 | pointsInside++; |
| 183 | } | 184 | } |
| 184 | } | 185 | } |
| 185 | 186 | ||
| 186 | // we're only here if all points are inside matched and/or we had a potentialIdentity we need to check | 187 | // we're only here if all points are inside matched and/or we had a potentialIdentity we need to check |
| 187 | if (pointsInside == occludee.getVertexCount()) { | 188 | if (pointsInside == occludee.getVertexCount()) { |
| 188 | return true; | 189 | return true; |
| @@ -192,7 +193,7 @@ bool OctreeProjectedPolygon::occludes(const OctreeProjectedPolygon& occludee, bo · 3 unmodified lines | |||
| 192 | if (potentialIdenity) { | 193 | if (potentialIdenity) { |
| 193 | return matches(occludee); | 194 | return matches(occludee); |
| 194 | } | 195 | } |
| 195 | 196 | ||
| 196 | return false; // if we got this far, then we're not occluded | 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 | int originIndex = 0; | 212 | int originIndex = 0; |
| 212 | for(int i = 0; i < vertextCount; i++) { | 213 | for(int i = 0; i < vertextCount; i++) { |
| 213 | glm::vec2 testeeVertex = testee.getVertex(i); | 214 | glm::vec2 testeeVertex = testee.getVertex(i); |
| 214 | 215 | ||
| 215 | // if they match, we found our origin. | 216 | // if they match, we found our origin. |
| 216 | if (testeeVertex == polygonVertex) { | 217 | if (testeeVertex == polygonVertex) { |
| 217 | originIndex = i; | 218 | originIndex = i; |
| @@ -224,10 +225,10 @@ bool OctreeProjectedPolygon::matches(const OctreeProjectedPolygon& testee) const · 6 unmodified lines | |||
| 224 | glm::vec2 testeeVertex = testee.getVertex((i + originIndex) % vertextCount); | 225 | glm::vec2 testeeVertex = testee.getVertex((i + originIndex) % vertextCount); |
| 225 | glm::vec2 polygonVertex = getVertex(i); | 226 | glm::vec2 polygonVertex = getVertex(i); |
| 226 | if (testeeVertex != polygonVertex) { | 227 | if (testeeVertex != polygonVertex) { |
| 227 | return false; // we don't match, therefore we're not the same | 228 | return false; // we don't match, therefore we're not the same |
| 228 | } | 229 | } |
| 229 | } | 230 | } |
| 230 | return true; // all of our vertices match, therefore we're the same | 231 | return true; // all of our vertices match, therefore we're the same |
| 231 | } | 232 | } |
| 232 | 233 | ||
| 233 | bool OctreeProjectedPolygon::matches(const BoundingBox& box) const { | 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 | return false; | 260 | return false; |
| 260 | } | 261 | } |
| 261 | } | 262 | } |
| 262 | 263 | ||
| 263 | return true; | 264 | return true; |
| 264 | } | 265 | } |
| 265 | 266 | ||
| 266 | void OctreeProjectedPolygon::printDebugDetails() const { | 267 | void OctreeProjectedPolygon::printDebugDetails() const { |
| 267 | qCDebug(octree, "OctreeProjectedPolygon..." | 268 | qCDebug(octree, "OctreeProjectedPolygon..." |
| 268 | " minX=%f maxX=%f minY=%f maxY=%f", getMinX(), getMaxX(), getMinY(), getMaxY()); | 269 | " minX=%f maxX=%f minY=%f maxY=%f", (double)getMinX(), (double)getMaxX(), (double)getMinY(), (double)getMaxY()); |
| 269 | qCDebug(octree, " vertex count=%d distance=%f", getVertexCount(), getDistance()); | 270 | qCDebug(octree, " vertex count=%d distance=%f", getVertexCount(), (double)getDistance()); |
| 270 | for (int i = 0; i < getVertexCount(); i++) { | 271 | for (int i = 0; i < getVertexCount(); i++) { |
| 271 | glm::vec2 point = getVertex(i); | 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 | // intersect on all axes. | 292 | // intersect on all axes. |
| 292 | // | 293 | // |
| 293 | // Note: this only works on convex polygons | 294 | // Note: this only works on convex polygons |
| 294 | // | 295 | // |
| 295 | // | 296 | // |
| 296 | bool OctreeProjectedPolygon::intersectsOnAxes(const OctreeProjectedPolygon& testee) const { | 297 | bool OctreeProjectedPolygon::intersectsOnAxes(const OctreeProjectedPolygon& testee) const { |
| 297 | 298 | ||
| @@ -307,11 +308,11 @@ bool OctreeProjectedPolygon::intersectsOnAxes(const OctreeProjectedPolygon& test · 9 unmodified lines | |||
| 307 | // points that are ON the edge, are considered to be "outside" | 308 | // points that are ON the edge, are considered to be "outside" |
| 308 | for (int j = 0; j < testee.getVertexCount(); j++) { | 309 | for (int j = 0; j < testee.getVertexCount(); j++) { |
| 309 | glm::vec2 testeeVertex = testee.getVertex(j); | 310 | glm::vec2 testeeVertex = testee.getVertex(j); |
| 310 | 311 | ||
| 311 | // in comparison below: | 312 | // in comparison below: |
| 312 | // >= will cause points on edge to be considered inside | 313 | // >= will cause points on edge to be considered inside |
| 313 | // > will cause points on edge to be considered outside | 314 | // > will cause points on edge to be considered outside |
| 314 | 315 | ||
| 315 | float c2 = a * testeeVertex.x + b * testeeVertex.y; | 316 | float c2 = a * testeeVertex.x + b * testeeVertex.y; |
| 316 | if (c2 >= c) { | 317 | if (c2 >= c) { |
| 317 | goto CONTINUE_OUTER; | 318 | goto CONTINUE_OUTER; |
| @@ -328,11 +329,11 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 10 unmodified lines | |||
| 328 | // RIGHT/NEAR | 329 | // RIGHT/NEAR |
| 329 | // LEFT/NEAR | 330 | // LEFT/NEAR |
| 330 | if ( | 331 | if ( |
| 331 | (getProjectionType() == that.getProjectionType()) && | 332 | (getProjectionType() == that.getProjectionType()) && |
| 332 | ( | 333 | ( |
| 333 | getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR) || | 334 | getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR) || |
| 334 | getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR) | 335 | getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR) |
| 335 | ) | 336 | ) |
| 336 | ) { | 337 | ) { |
| 337 | if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(5)) { | 338 | if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(5)) { |
| 338 | return true; | 339 | return true; |
| @@ -350,10 +351,10 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 11 unmodified lines | |||
| 350 | 351 | ||
| 351 | // NEAR/BOTTOM | 352 | // NEAR/BOTTOM |
| 352 | if ( | 353 | if ( |
| 353 | (getProjectionType() == that.getProjectionType()) && | 354 | (getProjectionType() == that.getProjectionType()) && |
| 354 | ( | 355 | ( |
| 355 | getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM) | 356 | getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM) |
| 356 | ) | 357 | ) |
| 357 | ) { | 358 | ) { |
| 358 | if (getVertex(0) == that.getVertex(5) && getVertex(3) == that.getVertex(4)) { | 359 | if (getVertex(0) == that.getVertex(5) && getVertex(3) == that.getVertex(4)) { |
| 359 | return true; | 360 | return true; |
| @@ -371,10 +372,10 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 11 unmodified lines | |||
| 371 | 372 | ||
| 372 | // NEAR/TOP | 373 | // NEAR/TOP |
| 373 | if ( | 374 | if ( |
| 374 | (getProjectionType() == that.getProjectionType()) && | 375 | (getProjectionType() == that.getProjectionType()) && |
| 375 | ( | 376 | ( |
| 376 | getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP) | 377 | getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP) |
| 377 | ) | 378 | ) |
| 378 | ) { | 379 | ) { |
| 379 | if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) { | 380 | if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) { |
| 380 | return true; | 381 | return true; |
| @@ -393,11 +394,11 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 12 unmodified lines | |||
| 393 | // RIGHT/NEAR & NEAR/RIGHT/TOP | 394 | // RIGHT/NEAR & NEAR/RIGHT/TOP |
| 394 | // LEFT/NEAR & NEAR/LEFT/TOP | 395 | // LEFT/NEAR & NEAR/LEFT/TOP |
| 395 | if ( | 396 | if ( |
| 396 | ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) && | 397 | ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) && |
| 397 | (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | 398 | (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) |
| 398 | || | 399 | || |
| 399 | ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) && | 400 | ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) && |
| 400 | (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | 401 | (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) |
| 401 | ) | 402 | ) |
| 402 | { | 403 | { |
| 403 | if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) { | 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 | // RIGHT/NEAR & NEAR/RIGHT/TOP | 408 | // RIGHT/NEAR & NEAR/RIGHT/TOP |
| 408 | // LEFT/NEAR & NEAR/LEFT/TOP | 409 | // LEFT/NEAR & NEAR/LEFT/TOP |
| 409 | if ( | 410 | if ( |
| 410 | ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) && | 411 | ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) && |
| 411 | (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | 412 | (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) |
| 412 | || | 413 | || |
| 413 | ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) && | 414 | ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) && |
| 414 | (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | 415 | (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) |
| 415 | 416 | ||
| 416 | ) | 417 | ) |
| 417 | { | 418 | { |
| 418 | if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) { | 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 | // RIGHT/NEAR & NEAR/RIGHT/BOTTOM | 424 | // RIGHT/NEAR & NEAR/RIGHT/BOTTOM |
| 424 | // NEAR/LEFT & NEAR/LEFT/BOTTOM | 425 | // NEAR/LEFT & NEAR/LEFT/BOTTOM |
| 425 | if ( | 426 | if ( |
| 426 | ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | 427 | ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && |
| 427 | (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | 428 | (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) |
| 428 | || | 429 | || |
| 429 | ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | 430 | ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && |
| 430 | (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | 431 | (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) |
| 431 | 432 | ||
| 432 | ) | 433 | ) |
| 433 | { | 434 | { |
| 434 | if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) { | 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 | // RIGHT/NEAR & NEAR/RIGHT/BOTTOM | 439 | // RIGHT/NEAR & NEAR/RIGHT/BOTTOM |
| 439 | // NEAR/LEFT & NEAR/LEFT/BOTTOM | 440 | // NEAR/LEFT & NEAR/LEFT/BOTTOM |
| 440 | if ( | 441 | if ( |
| 441 | ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | 442 | ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && |
| 442 | (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | 443 | (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) |
| 443 | || | 444 | || |
| 444 | ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | 445 | ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && |
| 445 | (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | 446 | (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) |
| 446 | ) | 447 | ) |
| 447 | { | 448 | { |
| 448 | if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) { | 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 | // NEAR/TOP & NEAR | 454 | // NEAR/TOP & NEAR |
| 454 | if ( | 455 | if ( |
| 455 | (getProjectionType() == (PROJECTION_NEAR )) && | 456 | (getProjectionType() == (PROJECTION_NEAR )) && |
| 456 | (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) | 457 | (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) |
| 457 | ) | 458 | ) |
| 458 | { | 459 | { |
| 459 | if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) { | 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 | // NEAR/TOP & NEAR | 465 | // NEAR/TOP & NEAR |
| 465 | if ( | 466 | if ( |
| 466 | (that.getProjectionType() == (PROJECTION_NEAR )) && | 467 | (that.getProjectionType() == (PROJECTION_NEAR )) && |
| 467 | (getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) | 468 | (getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) |
| 468 | ) | 469 | ) |
| 469 | { | 470 | { |
| 470 | if (getVertex(5) == that.getVertex(0) && getVertex(2) == that.getVertex(1)) { | 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 | // NEAR/BOTTOM & NEAR | 476 | // NEAR/BOTTOM & NEAR |
| 476 | if ( | 477 | if ( |
| 477 | (getProjectionType() == (PROJECTION_NEAR )) && | 478 | (getProjectionType() == (PROJECTION_NEAR )) && |
| 478 | (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) | 479 | (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) |
| 479 | ) | 480 | ) |
| 480 | { | 481 | { |
| 481 | if (getVertex(2) == that.getVertex(3) && getVertex(3) == that.getVertex(0)) { | 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 | // NEAR/BOTTOM & NEAR | 487 | // NEAR/BOTTOM & NEAR |
| 487 | if ( | 488 | if ( |
| 488 | (that.getProjectionType() == (PROJECTION_NEAR )) && | 489 | (that.getProjectionType() == (PROJECTION_NEAR )) && |
| 489 | (getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) | 490 | (getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) |
| 490 | ) | 491 | ) |
| 491 | { | 492 | { |
| 492 | if (getVertex(3) == that.getVertex(2) && getVertex(0) == that.getVertex(3)) { | 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 | // NEAR/RIGHT & NEAR | 498 | // NEAR/RIGHT & NEAR |
| 498 | if ( | 499 | if ( |
| 499 | (getProjectionType() == (PROJECTION_NEAR )) && | 500 | (getProjectionType() == (PROJECTION_NEAR )) && |
| 500 | (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) | 501 | (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) |
| 501 | ) | 502 | ) |
| 502 | { | 503 | { |
| 503 | if (getVertex(0) == that.getVertex(1) && getVertex(3) == that.getVertex(4)) { | 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 | // NEAR/RIGHT & NEAR | 509 | // NEAR/RIGHT & NEAR |
| 509 | if ( | 510 | if ( |
| 510 | (that.getProjectionType() == (PROJECTION_NEAR )) && | 511 | (that.getProjectionType() == (PROJECTION_NEAR )) && |
| 511 | (getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) | 512 | (getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) |
| 512 | ) | 513 | ) |
| 513 | { | 514 | { |
| 514 | if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) { | 515 | if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) { |
| 515 | return true; | 516 | return true; |
| 516 | } | 517 | } |
| 517 | } | 518 | } |
| 518 | 519 | ||
| 519 | // NEAR/LEFT & NEAR | 520 | // NEAR/LEFT & NEAR |
| 520 | if ( | 521 | if ( |
| 521 | (getProjectionType() == (PROJECTION_NEAR )) && | 522 | (getProjectionType() == (PROJECTION_NEAR )) && |
| 522 | (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) | 523 | (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) |
| 523 | ) | 524 | ) |
| 524 | { | 525 | { |
| 525 | if (getVertex(1) == that.getVertex(1) && getVertex(2) == that.getVertex(4)) { | 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 | // NEAR/LEFT & NEAR | 531 | // NEAR/LEFT & NEAR |
| 531 | if ( | 532 | if ( |
| 532 | (that.getProjectionType() == (PROJECTION_NEAR )) && | 533 | (that.getProjectionType() == (PROJECTION_NEAR )) && |
| 533 | (getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) | 534 | (getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) |
| 534 | ) | 535 | ) |
| 535 | { | 536 | { |
| 536 | if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) { | 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 | return true; | 560 | return true; |
| 560 | } | 561 | } |
| 561 | } | 562 | } |
| 562 | 563 | ||
| 563 | 564 | ||
| 564 | // NEAR/RIGHT/BOTTOM & NEAR/BOTTOM | 565 | // NEAR/RIGHT/BOTTOM & NEAR/BOTTOM |
| 565 | if ( | 566 | if ( |
| @@ -582,7 +583,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 16 unmodified lines | |||
| 582 | return true; | 583 | return true; |
| 583 | } | 584 | } |
| 584 | } | 585 | } |
| 585 | 586 | ||
| 586 | // NEAR/LEFT/BOTTOM & NEAR/BOTTOM | 587 | // NEAR/LEFT/BOTTOM & NEAR/BOTTOM |
| 587 | if ( | 588 | if ( |
| 588 | ((getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) && | 589 | ((getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) && |
| @@ -592,12 +593,12 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 3 unmodified lines | |||
| 592 | if (getVertex(2) == that.getVertex(0) && getVertex(4) == that.getVertex(4)) { | 593 | if (getVertex(2) == that.getVertex(0) && getVertex(4) == that.getVertex(4)) { |
| 593 | return true; | 594 | return true; |
| 594 | } | 595 | } |
| 595 | } | 596 | } |
| 596 | 597 | ||
| 597 | // NEAR/LEFT/BOTTOM & NEAR/BOTTOM | 598 | // NEAR/LEFT/BOTTOM & NEAR/BOTTOM |
| 598 | if ( | 599 | if ( |
| 599 | ((that.getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) && | 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 | if (getVertex(0) == that.getVertex(2) && getVertex(4) == that.getVertex(4)) { | 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 | // LEFT/NEAR/BOTTOM | 610 | // LEFT/NEAR/BOTTOM |
| 610 | // LEFT/NEAR/TOP | 611 | // LEFT/NEAR/TOP |
| 611 | if ( | 612 | if ( |
| 612 | (getProjectionType() == that.getProjectionType()) && | 613 | (getProjectionType() == that.getProjectionType()) && |
| 613 | ( | 614 | ( |
| 614 | getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM ) || | 615 | getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM ) || |
| 615 | getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP ) || | 616 | getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP ) || |
| @@ -646,11 +647,11 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 30 unmodified lines | |||
| 646 | // RIGHT/NEAR | 647 | // RIGHT/NEAR |
| 647 | // LEFT/NEAR | 648 | // LEFT/NEAR |
| 648 | if ( | 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 | getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR) | 653 | getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR) |
| 653 | ) | 654 | ) |
| 654 | ) { | 655 | ) { |
| 655 | if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(5)) { | 656 | if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(5)) { |
| 656 | //setVertex(0, this.getVertex(0)); // no change | 657 | //setVertex(0, this.getVertex(0)); // no change |
| @@ -689,13 +690,13 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 32 unmodified lines | |||
| 689 | return; // done | 690 | return; // done |
| 690 | } | 691 | } |
| 691 | } | 692 | } |
| 692 | 693 | ||
| 693 | // NEAR/BOTTOM | 694 | // NEAR/BOTTOM |
| 694 | if ( | 695 | if ( |
| 695 | (getProjectionType() == that.getProjectionType()) && | 696 | (getProjectionType() == that.getProjectionType()) && |
| 696 | ( | 697 | ( |
| 697 | getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM) | 698 | getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM) |
| 698 | ) | 699 | ) |
| 699 | ) { | 700 | ) { |
| 700 | if (getVertex(0) == that.getVertex(5) && getVertex(3) == that.getVertex(4)) { | 701 | if (getVertex(0) == that.getVertex(5) && getVertex(3) == that.getVertex(4)) { |
| 701 | setVertex(0, that.getVertex(0)); | 702 | setVertex(0, that.getVertex(0)); |
| @@ -737,10 +738,10 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 35 unmodified lines | |||
| 737 | 738 | ||
| 738 | // NEAR/TOP | 739 | // NEAR/TOP |
| 739 | if ( | 740 | if ( |
| 740 | (getProjectionType() == that.getProjectionType()) && | 741 | (getProjectionType() == that.getProjectionType()) && |
| 741 | ( | 742 | ( |
| 742 | getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP) | 743 | getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP) |
| 743 | ) | 744 | ) |
| 744 | ) { | 745 | ) { |
| 745 | if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) { | 746 | if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) { |
| 746 | setVertex(0, that.getVertex(0)); | 747 | setVertex(0, that.getVertex(0)); |
| @@ -779,16 +780,16 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 32 unmodified lines | |||
| 779 | return; // done | 780 | return; // done |
| 780 | } | 781 | } |
| 781 | } | 782 | } |
| 782 | 783 | ||
| 783 | 784 | ||
| 784 | // RIGHT/NEAR & NEAR/RIGHT/TOP | 785 | // RIGHT/NEAR & NEAR/RIGHT/TOP |
| 785 | // LEFT/NEAR & NEAR/LEFT/TOP | 786 | // LEFT/NEAR & NEAR/LEFT/TOP |
| 786 | if ( | 787 | if ( |
| 787 | ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) && | 788 | ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) && |
| 788 | (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | 789 | (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) |
| 789 | || | 790 | || |
| 790 | ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) && | 791 | ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) && |
| 791 | (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | 792 | (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) |
| 792 | ) | 793 | ) |
| 793 | { | 794 | { |
| 794 | if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) { | 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 | // RIGHT/NEAR & NEAR/RIGHT/TOP | 807 | // RIGHT/NEAR & NEAR/RIGHT/TOP |
| 807 | // LEFT/NEAR & NEAR/LEFT/TOP | 808 | // LEFT/NEAR & NEAR/LEFT/TOP |
| 808 | if ( | 809 | if ( |
| 809 | ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) && | 810 | ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) && |
| 810 | (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | 811 | (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) |
| 811 | || | 812 | || |
| 812 | ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) && | 813 | ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) && |
| 813 | (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | 814 | (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) |
| 814 | 815 | ||
| 815 | ) | 816 | ) |
| 816 | { | 817 | { |
| 817 | if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) { | 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 | // RIGHT/NEAR & NEAR/RIGHT/BOTTOM | 830 | // RIGHT/NEAR & NEAR/RIGHT/BOTTOM |
| 830 | // NEAR/LEFT & NEAR/LEFT/BOTTOM | 831 | // NEAR/LEFT & NEAR/LEFT/BOTTOM |
| 831 | if ( | 832 | if ( |
| 832 | ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | 833 | ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && |
| 833 | (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | 834 | (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) |
| 834 | || | 835 | || |
| 835 | ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | 836 | ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && |
| 836 | (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | 837 | (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) |
| 837 | 838 | ||
| 838 | ) | 839 | ) |
| 839 | { | 840 | { |
| 840 | if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) { | 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 | // RIGHT/NEAR & NEAR/RIGHT/BOTTOM | 852 | // RIGHT/NEAR & NEAR/RIGHT/BOTTOM |
| 852 | // NEAR/LEFT & NEAR/LEFT/BOTTOM | 853 | // NEAR/LEFT & NEAR/LEFT/BOTTOM |
| 853 | if ( | 854 | if ( |
| 854 | ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | 855 | ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && |
| 855 | (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) | 856 | (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) |
| 856 | || | 857 | || |
| 857 | ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && | 858 | ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && |
| 858 | (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) | 859 | (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) |
| 859 | ) | 860 | ) |
| 860 | { | 861 | { |
| 861 | if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) { | 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 | //setVertex(3, this.getVertex(3)); // no change | 866 | //setVertex(3, this.getVertex(3)); // no change |
| 866 | //setVertex(4, this.getVertex(4)); // no change | 867 | //setVertex(4, this.getVertex(4)); // no change |
| 867 | //setVertex(5, this.getVertex(5)); // no change | 868 | //setVertex(5, this.getVertex(5)); // no change |
| 868 | setProjectionType((PROJECTION_RIGHT | PROJECTION_NEAR)); | 869 | setProjectionType((PROJECTION_RIGHT | PROJECTION_NEAR)); |
| 869 | return; // done | 870 | return; // done |
| 870 | } | 871 | } |
| 871 | } | 872 | } |
| 872 | 873 | ||
| 873 | 874 | ||
| 874 | // NEAR/TOP & NEAR | 875 | // NEAR/TOP & NEAR |
| 875 | if ( | 876 | if ( |
| 876 | (getProjectionType() == (PROJECTION_NEAR )) && | 877 | (getProjectionType() == (PROJECTION_NEAR )) && |
| 877 | (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) | 878 | (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) |
| 878 | ) | 879 | ) |
| 879 | { | 880 | { |
| 880 | if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) { | 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 | // NEAR/TOP & NEAR | 892 | // NEAR/TOP & NEAR |
| 892 | if ( | 893 | if ( |
| 893 | (that.getProjectionType() == (PROJECTION_NEAR )) && | 894 | (that.getProjectionType() == (PROJECTION_NEAR )) && |
| 894 | (getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) | 895 | (getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) |
| 895 | ) | 896 | ) |
| 896 | { | 897 | { |
| 897 | if (getVertex(5) == that.getVertex(0) && getVertex(2) == that.getVertex(1)) { | 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 | return; // done | 905 | return; // done |
| 905 | } | 906 | } |
| 906 | } | 907 | } |
| 907 | 908 | ||
| 908 | // NEAR/BOTTOM & NEAR | 909 | // NEAR/BOTTOM & NEAR |
| 909 | if ( | 910 | if ( |
| 910 | (getProjectionType() == (PROJECTION_NEAR )) && | 911 | (getProjectionType() == (PROJECTION_NEAR )) && |
| 911 | (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) | 912 | (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) |
| 912 | ) | 913 | ) |
| 913 | { | 914 | { |
| 914 | if (getVertex(2) == that.getVertex(3) && getVertex(3) == that.getVertex(0)) { | 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 | // NEAR/BOTTOM & NEAR | 925 | // NEAR/BOTTOM & NEAR |
| 925 | if ( | 926 | if ( |
| 926 | (that.getProjectionType() == (PROJECTION_NEAR )) && | 927 | (that.getProjectionType() == (PROJECTION_NEAR )) && |
| 927 | (getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) | 928 | (getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) |
| 928 | ) | 929 | ) |
| 929 | { | 930 | { |
| 930 | if (getVertex(3) == that.getVertex(2) && getVertex(0) == that.getVertex(3)) { | 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 | // NEAR/RIGHT & NEAR | 942 | // NEAR/RIGHT & NEAR |
| 942 | if ( | 943 | if ( |
| 943 | (getProjectionType() == (PROJECTION_NEAR )) && | 944 | (getProjectionType() == (PROJECTION_NEAR )) && |
| 944 | (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) | 945 | (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) |
| 945 | ) | 946 | ) |
| 946 | { | 947 | { |
| 947 | if (getVertex(0) == that.getVertex(1) && getVertex(3) == that.getVertex(4)) { | 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 | // NEAR/RIGHT & NEAR | 958 | // NEAR/RIGHT & NEAR |
| 958 | if ( | 959 | if ( |
| 959 | (that.getProjectionType() == (PROJECTION_NEAR )) && | 960 | (that.getProjectionType() == (PROJECTION_NEAR )) && |
| 960 | (getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) | 961 | (getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) |
| 961 | ) | 962 | ) |
| 962 | { | 963 | { |
| 963 | if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) { | 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 | // NEAR/LEFT & NEAR | 975 | // NEAR/LEFT & NEAR |
| 975 | if ( | 976 | if ( |
| 976 | (getProjectionType() == (PROJECTION_NEAR )) && | 977 | (getProjectionType() == (PROJECTION_NEAR )) && |
| 977 | (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) | 978 | (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) |
| 978 | ) | 979 | ) |
| 979 | { | 980 | { |
| 980 | if (getVertex(1) == that.getVertex(1) && getVertex(2) == that.getVertex(4)) { | 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 | // NEAR/LEFT & NEAR | 992 | // NEAR/LEFT & NEAR |
| 992 | if ( | 993 | if ( |
| 993 | (that.getProjectionType() == (PROJECTION_NEAR )) && | 994 | (that.getProjectionType() == (PROJECTION_NEAR )) && |
| 994 | (getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) | 995 | (getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) |
| 995 | ) | 996 | ) |
| 996 | { | 997 | { |
| 997 | if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) { | 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 | // NEAR/LEFT/BOTTOM & NEAR/BOTTOM | 1097 | // NEAR/LEFT/BOTTOM & NEAR/BOTTOM |
| 1097 | if ( | 1098 | if ( |
| 1098 | ((that.getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) && | 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 | if (getVertex(0) == that.getVertex(2) && getVertex(4) == that.getVertex(4)) { | 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 | // LEFT/NEAR/BOTTOM | 1119 | // LEFT/NEAR/BOTTOM |
| 1119 | // LEFT/NEAR/TOP | 1120 | // LEFT/NEAR/TOP |
| 1120 | if ( | 1121 | if ( |
| 1121 | (getProjectionType() == that.getProjectionType()) && | 1122 | (getProjectionType() == that.getProjectionType()) && |
| 1122 | ( | 1123 | ( |
| 1123 | getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM ) || | 1124 | getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM ) || |
| 1124 | getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP ) || | 1125 | getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP ) || |
| @@ -707,8 +707,8 @@ const char* OctreeSceneStats::getItemValue(Item item) { · 706 unmodified lines | |||
| 707 | float elapsedAverage = _elapsedAverage.getAverage(); | 707 | float elapsedAverage = _elapsedAverage.getAverage(); |
| 708 | calcAverageFPS = (float)USECS_PER_SECOND / (float)elapsedAverage; | 708 | calcAverageFPS = (float)USECS_PER_SECOND / (float)elapsedAverage; |
| 709 | 709 | ||
| 710 | sprintf(_itemValueBuffer, "%llu usecs (%d fps) Average: %.0f usecs (%d fps)", | 710 | sprintf(_itemValueBuffer, "%llu usecs (%d fps) Average: %.0f usecs (%d fps)", |
| 711 | (long long unsigned int)_elapsed, calcFPS, elapsedAverage, calcAverageFPS); | 711 | (long long unsigned int)_elapsed, calcFPS, (double)elapsedAverage, calcAverageFPS); |
| 712 | break; | 712 | break; |
| 713 | } | 713 | } |
| 714 | case ITEM_ENCODE: | 714 | case ITEM_ENCODE: |
| @@ -733,7 +733,7 @@ const char* OctreeSceneStats::getItemValue(Item item) { · 18 unmodified lines | |||
| 733 | float calculatedBPV = total == 0 ? 0 : (_bytes * 8) / total; | 733 | float calculatedBPV = total == 0 ? 0 : (_bytes * 8) / total; |
| 734 | float averageBPV = _bitsPerOctreeAverage.getAverage(); | 734 | float averageBPV = _bitsPerOctreeAverage.getAverage(); |
| 735 | sprintf(_itemValueBuffer, "%lu (%.2f bits/octree Average: %.2f bits/octree) %lu internal %lu leaves", | 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 | (long unsigned int)_existsInPacketBitsWritten, | 737 | (long unsigned int)_existsInPacketBitsWritten, |
| 738 | (long unsigned int)_colorSent); | 738 | (long unsigned int)_colorSent); |
| 739 | break; | 739 | break; |
| @@ -66,5 +66,6 @@ float Plane::distance(const glm::vec3 &point) const { · 65 unmodified lines | |||
| 66 | 66 | ||
| 67 | void Plane::print() const { | 67 | void Plane::print() const { |
| 68 | qCDebug(octree, "Plane - point (x=%f y=%f z=%f) normal (x=%f y=%f z=%f) d=%f", | 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 | _farClip = -_corners[BOTTOM_LEFT_FAR].z; | 65 | _farClip = -_corners[BOTTOM_LEFT_FAR].z; |
| 66 | _aspectRatio = (_corners[TOP_RIGHT_NEAR].x - _corners[BOTTOM_LEFT_NEAR].x) / | 66 | _aspectRatio = (_corners[TOP_RIGHT_NEAR].x - _corners[BOTTOM_LEFT_NEAR].x) / |
| 67 | (_corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_LEFT_NEAR].y); | 67 | (_corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_LEFT_NEAR].y); |
| 68 | glm::vec3 right = glm::normalize(glm::vec3(_corners[TOP_RIGHT_NEAR])); | 68 | |
| 69 | glm::vec3 left = glm::normalize(glm::vec3(_corners[TOP_LEFT_NEAR])); | 69 | glm::vec4 top = _inverseProjection * vec4(0, 1, -1, 1); |
| 70 | _fieldOfView = abs(glm::degrees(glm::angle(right, left))); | 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 | // ViewFrustum::calculateViewFrustum() | 74 | // ViewFrustum::calculateViewFrustum() |
| @@ -387,36 +388,36 @@ bool ViewFrustum::matches(const ViewFrustum& compareTo, bool debug) const { · 313 unmodified lines | |||
| 387 | if (!result && debug) { | 388 | if (!result && debug) { |
| 388 | qCDebug(octree, "ViewFrustum::matches()... result=%s", debug::valueOf(result)); | 389 | qCDebug(octree, "ViewFrustum::matches()... result=%s", debug::valueOf(result)); |
| 389 | qCDebug(octree, "%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f", | 390 | qCDebug(octree, "%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f", |
| 390 | (testMatches(compareTo._position,_position) ? "MATCHES " : "NO MATCH"), | 391 | (testMatches(compareTo._position,_position) ? "MATCHES " : "NO MATCH"), |
| 391 | compareTo._position.x, compareTo._position.y, compareTo._position.z, | 392 | (double)compareTo._position.x, (double)compareTo._position.y, (double)compareTo._position.z, |
| 392 | _position.x, _position.y, _position.z ); | 393 | (double)_position.x, (double)_position.y, (double)_position.z); |
| 393 | qCDebug(octree, "%s -- compareTo._direction=%f,%f,%f _direction=%f,%f,%f", | 394 | qCDebug(octree, "%s -- compareTo._direction=%f,%f,%f _direction=%f,%f,%f", |
| 394 | (testMatches(compareTo._direction, _direction) ? "MATCHES " : "NO MATCH"), | 395 | (testMatches(compareTo._direction, _direction) ? "MATCHES " : "NO MATCH"), |
| 395 | compareTo._direction.x, compareTo._direction.y, compareTo._direction.z, | 396 | (double)compareTo._direction.x, (double)compareTo._direction.y, (double)compareTo._direction.z, |
| 396 | _direction.x, _direction.y, _direction.z ); | 397 | (double)_direction.x, (double)_direction.y, (double)_direction.z ); |
| 397 | qCDebug(octree, "%s -- compareTo._up=%f,%f,%f _up=%f,%f,%f", | 398 | qCDebug(octree, "%s -- compareTo._up=%f,%f,%f _up=%f,%f,%f", |
| 398 | (testMatches(compareTo._up, _up) ? "MATCHES " : "NO MATCH"), | 399 | (testMatches(compareTo._up, _up) ? "MATCHES " : "NO MATCH"), |
| 399 | compareTo._up.x, compareTo._up.y, compareTo._up.z, | 400 | (double)compareTo._up.x, (double)compareTo._up.y, (double)compareTo._up.z, |
| 400 | _up.x, _up.y, _up.z ); | 401 | (double)_up.x, (double)_up.y, (double)_up.z ); |
| 401 | qCDebug(octree, "%s -- compareTo._right=%f,%f,%f _right=%f,%f,%f", | 402 | qCDebug(octree, "%s -- compareTo._right=%f,%f,%f _right=%f,%f,%f", |
| 402 | (testMatches(compareTo._right, _right) ? "MATCHES " : "NO MATCH"), | 403 | (testMatches(compareTo._right, _right) ? "MATCHES " : "NO MATCH"), |
| 403 | compareTo._right.x, compareTo._right.y, compareTo._right.z, | 404 | (double)compareTo._right.x, (double)compareTo._right.y, (double)compareTo._right.z, |
| 404 | _right.x, _right.y, _right.z ); | 405 | (double)_right.x, (double)_right.y, (double)_right.z ); |
| 405 | qCDebug(octree, "%s -- compareTo._fieldOfView=%f _fieldOfView=%f", | 406 | qCDebug(octree, "%s -- compareTo._fieldOfView=%f _fieldOfView=%f", |
| 406 | (testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"), | 407 | (testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"), |
| 407 | compareTo._fieldOfView, _fieldOfView); | 408 | (double)compareTo._fieldOfView, (double)_fieldOfView); |
| 408 | qCDebug(octree, "%s -- compareTo._aspectRatio=%f _aspectRatio=%f", | 409 | qCDebug(octree, "%s -- compareTo._aspectRatio=%f _aspectRatio=%f", |
| 409 | (testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"), | 410 | (testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"), |
| 410 | compareTo._aspectRatio, _aspectRatio); | 411 | (double)compareTo._aspectRatio, (double)_aspectRatio); |
| 411 | qCDebug(octree, "%s -- compareTo._nearClip=%f _nearClip=%f", | 412 | qCDebug(octree, "%s -- compareTo._nearClip=%f _nearClip=%f", |
| 412 | (testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"), | 413 | (testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"), |
| 413 | compareTo._nearClip, _nearClip); | 414 | (double)compareTo._nearClip, (double)_nearClip); |
| 414 | qCDebug(octree, "%s -- compareTo._farClip=%f _farClip=%f", | 415 | qCDebug(octree, "%s -- compareTo._farClip=%f _farClip=%f", |
| 415 | (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"), | 416 | (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"), |
| 416 | compareTo._farClip, _farClip); | 417 | (double)compareTo._farClip, (double)_farClip); |
| 417 | qCDebug(octree, "%s -- compareTo._focalLength=%f _focalLength=%f", | 418 | qCDebug(octree, "%s -- compareTo._focalLength=%f _focalLength=%f", |
| 418 | (testMatches(compareTo._focalLength, _focalLength) ? "MATCHES " : "NO MATCH"), | 419 | (testMatches(compareTo._focalLength, _focalLength) ? "MATCHES " : "NO MATCH"), |
| 419 | compareTo._focalLength, _focalLength); | 420 | (double)compareTo._focalLength, (double)_focalLength); |
| 420 | } | 421 | } |
| 421 | return result; | 422 | return result; |
| 422 | } | 423 | } |
| @@ -448,33 +449,34 @@ bool ViewFrustum::isVerySimilar(const ViewFrustum& compareTo, bool debug) const · 25 unmodified lines | |||
| 448 | if (!result && debug) { | 449 | if (!result && debug) { |
| 449 | qCDebug(octree, "ViewFrustum::isVerySimilar()... result=%s\n", debug::valueOf(result)); | 450 | qCDebug(octree, "ViewFrustum::isVerySimilar()... result=%s\n", debug::valueOf(result)); |
| 450 | qCDebug(octree, "%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f", | 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 | (testMatches(compareTo._position,_position, POSITION_SIMILAR_ENOUGH) ? |
| 452 | compareTo._position.x, compareTo._position.y, compareTo._position.z, | 453 | "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"), |
| 453 | _position.x, _position.y, _position.z ); | 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 | qCDebug(octree, "%s -- positionDistance=%f", | 457 | qCDebug(octree, "%s -- positionDistance=%f", |
| 456 | (testMatches(0,positionDistance, POSITION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"), | 458 | (testMatches(0,positionDistance, POSITION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"), |
| 457 | positionDistance); | 459 | (double)positionDistance); |
| 458 | 460 | ||
| 459 | qCDebug(octree, "%s -- angleOrientation=%f", | 461 | qCDebug(octree, "%s -- angleOrientation=%f", |
| 460 | (testMatches(0, angleOrientation, ORIENTATION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"), | 462 | (testMatches(0, angleOrientation, ORIENTATION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"), |
| 461 | angleOrientation); | 463 | (double)angleOrientation); |
| 462 | 464 | ||
| 463 | qCDebug(octree, "%s -- compareTo._fieldOfView=%f _fieldOfView=%f", | 465 | qCDebug(octree, "%s -- compareTo._fieldOfView=%f _fieldOfView=%f", |
| 464 | (testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"), | 466 | (testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"), |
| 465 | compareTo._fieldOfView, _fieldOfView); | 467 | (double)compareTo._fieldOfView, (double)_fieldOfView); |
| 466 | qCDebug(octree, "%s -- compareTo._aspectRatio=%f _aspectRatio=%f", | 468 | qCDebug(octree, "%s -- compareTo._aspectRatio=%f _aspectRatio=%f", |
| 467 | (testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"), | 469 | (testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"), |
| 468 | compareTo._aspectRatio, _aspectRatio); | 470 | (double)compareTo._aspectRatio, (double)_aspectRatio); |
| 469 | qCDebug(octree, "%s -- compareTo._nearClip=%f _nearClip=%f", | 471 | qCDebug(octree, "%s -- compareTo._nearClip=%f _nearClip=%f", |
| 470 | (testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"), | 472 | (testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"), |
| 471 | compareTo._nearClip, _nearClip); | 473 | (double)compareTo._nearClip, (double)_nearClip); |
| 472 | qCDebug(octree, "%s -- compareTo._farClip=%f _farClip=%f", | 474 | qCDebug(octree, "%s -- compareTo._farClip=%f _farClip=%f", |
| 473 | (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"), | 475 | (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"), |
| 474 | compareTo._farClip, _farClip); | 476 | (double)compareTo._farClip, (double)_farClip); |
| 475 | qCDebug(octree, "%s -- compareTo._focalLength=%f _focalLength=%f", | 477 | qCDebug(octree, "%s -- compareTo._focalLength=%f _focalLength=%f", |
| 476 | (testMatches(compareTo._focalLength, _focalLength) ? "MATCHES " : "NO MATCH"), | 478 | (testMatches(compareTo._focalLength, _focalLength) ? "MATCHES " : "NO MATCH"), |
| 477 | compareTo._focalLength, _focalLength); | 479 | (double)compareTo._focalLength, (double)_focalLength); |
| 478 | } | 480 | } |
| 479 | return result; | 481 | return result; |
| 480 | } | 482 | } |
| @@ -531,23 +533,23 @@ void ViewFrustum::computeOffAxisFrustum(float& left, float& right, float& bottom · 50 unmodified lines | |||
| 531 | 533 | ||
| 532 | void ViewFrustum::printDebugDetails() const { | 534 | void ViewFrustum::printDebugDetails() const { |
| 533 | qCDebug(octree, "ViewFrustum::printDebugDetails()..."); | 535 | qCDebug(octree, "ViewFrustum::printDebugDetails()..."); |
| 534 | qCDebug(octree, "_position=%f,%f,%f", _position.x, _position.y, _position.z ); | 536 | qCDebug(octree, "_position=%f,%f,%f", (double)_position.x, (double)_position.y, (double)_position.z ); |
| 535 | qCDebug(octree, "_direction=%f,%f,%f", _direction.x, _direction.y, _direction.z ); | 537 | qCDebug(octree, "_direction=%f,%f,%f", (double)_direction.x, (double)_direction.y, (double)_direction.z ); |
| 536 | qCDebug(octree, "_up=%f,%f,%f", _up.x, _up.y, _up.z ); | 538 | qCDebug(octree, "_up=%f,%f,%f", (double)_up.x, (double)_up.y, (double)_up.z ); |
| 537 | qCDebug(octree, "_right=%f,%f,%f", _right.x, _right.y, _right.z ); | 539 | qCDebug(octree, "_right=%f,%f,%f", (double)_right.x, (double)_right.y, (double)_right.z ); |
| 538 | qCDebug(octree, "_fieldOfView=%f", _fieldOfView); | 540 | qCDebug(octree, "_fieldOfView=%f", (double)_fieldOfView); |
| 539 | qCDebug(octree, "_aspectRatio=%f", _aspectRatio); | 541 | qCDebug(octree, "_aspectRatio=%f", (double)_aspectRatio); |
| 540 | qCDebug(octree, "_keyHoleRadius=%f", _keyholeRadius); | 542 | qCDebug(octree, "_keyHoleRadius=%f", (double)_keyholeRadius); |
| 541 | qCDebug(octree, "_nearClip=%f", _nearClip); | 543 | qCDebug(octree, "_nearClip=%f", (double)_nearClip); |
| 542 | qCDebug(octree, "_farClip=%f", _farClip); | 544 | qCDebug(octree, "_farClip=%f", (double)_farClip); |
| 543 | qCDebug(octree, "_focalLength=%f", _focalLength); | 545 | qCDebug(octree, "_focalLength=%f", (double)_focalLength); |
| 544 | } | 546 | } |
| 545 | 547 | ||
| 546 | glm::vec2 ViewFrustum::projectPoint(glm::vec3 point, bool& pointInView) const { | 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 | glm::vec4 projectedPointVec4 = _ourModelViewProjectionMatrix * pointVec4; | 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 | // what happens with w is 0??? | 554 | // what happens with w is 0??? |
| 553 | float x = projectedPointVec4.x / projectedPointVec4.w; | 555 | float x = projectedPointVec4.x / projectedPointVec4.w; |
| @@ -245,7 +245,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { · 244 unmodified lines | |||
| 245 | 245 | ||
| 246 | float dx2 = glm::distance2(position, _serverPosition); | 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 | if (dx2 > MAX_POSITION_ERROR_SQUARED) { | 249 | if (dx2 > MAX_POSITION_ERROR_SQUARED) { |
| 250 | 250 | ||
| 251 | #ifdef WANT_DEBUG | 251 | #ifdef WANT_DEBUG |
| @@ -270,7 +270,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { · 18 unmodified lines | |||
| 270 | _serverRotation = glm::normalize(computeBulletRotationStep(_serverAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP) * _serverRotation); | 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 | glm::quat actualRotation = bulletToGLM(worldTrans.getRotation()); | 274 | glm::quat actualRotation = bulletToGLM(worldTrans.getRotation()); |
| 275 | 275 | ||
| 276 | #ifdef WANT_DEBUG | 276 | #ifdef WANT_DEBUG |
| @@ -270,7 +270,9 @@ void MeshMassProperties::computeMassProperties(const VectorOfPoints& points, con · 269 unmodified lines | |||
| 270 | } | 270 | } |
| 271 | 271 | ||
| 272 | // create some variables to hold temporary results | 272 | // create some variables to hold temporary results |
| 273 | #ifndef NDEBUG | ||
| 273 | uint32_t numPoints = points.size(); | 274 | uint32_t numPoints = points.size(); |
| 275 | #endif | ||
| 274 | const btVector3 p0(0.0f, 0.0f, 0.0f); | 276 | const btVector3 p0(0.0f, 0.0f, 0.0f); |
| 275 | btMatrix3x3 tetraInertia; | 277 | btMatrix3x3 tetraInertia; |
| 276 | btMatrix3x3 doubleDebugInertia; | 278 | btMatrix3x3 doubleDebugInertia; |
| @@ -281,9 +283,11 @@ void MeshMassProperties::computeMassProperties(const VectorOfPoints& points, con · 4 unmodified lines | |||
| 281 | uint32_t numTriangles = triangleIndices.size() / 3; | 283 | uint32_t numTriangles = triangleIndices.size() / 3; |
| 282 | for (uint32_t i = 0; i < numTriangles; ++i) { | 284 | for (uint32_t i = 0; i < numTriangles; ++i) { |
| 283 | uint32_t t = 3 * i; | 285 | uint32_t t = 3 * i; |
| 286 | #ifndef NDEBUG | ||
| 284 | assert(triangleIndices[t] < numPoints); | 287 | assert(triangleIndices[t] < numPoints); |
| 285 | assert(triangleIndices[t + 1] < numPoints); | 288 | assert(triangleIndices[t + 1] < numPoints); |
| 286 | assert(triangleIndices[t + 2] < numPoints); | 289 | assert(triangleIndices[t + 2] < numPoints); |
| 290 | #endif | ||
| 287 | 291 | ||
| 288 | // extract raw vertices | 292 | // extract raw vertices |
| 289 | tetraPoints[0] = p0; | 293 | tetraPoints[0] = p0; |
| @@ -28,7 +28,7 @@ void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar delta · 27 unmodified lines | |||
| 28 | return; | 28 | return; |
| 29 | } | 29 | } |
| 30 | if (!_ownerEntity) { | 30 | if (!_ownerEntity) { |
| 31 | qDebug() << "ObjectActionPullToPoint::updateAction no owner entity"; | 31 | qDebug() << "ObjectAction::updateAction no owner entity"; |
| 32 | return; | 32 | return; |
| 33 | } | 33 | } |
| 34 | updateActionWorker(deltaTimeStep); | 34 | updateActionWorker(deltaTimeStep); |
| @@ -59,6 +59,7 @@ protected: · 58 unmodified lines | |||
| 59 | 59 | ||
| 60 | bool tryLockForRead() { return _lock.tryLockForRead(); } | 60 | bool tryLockForRead() { return _lock.tryLockForRead(); } |
| 61 | void lockForWrite() { _lock.lockForWrite(); } | 61 | void lockForWrite() { _lock.lockForWrite(); } |
| 62 | bool tryLockForWrite() { return _lock.tryLockForWrite(); } | ||
| 62 | void unlock() { _lock.unlock(); } | 63 | void unlock() { _lock.unlock(); } |
| 63 | 64 | ||
| 64 | bool _active; | 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) | 1 | set(TARGET_NAME render-utils) |
| 2 | 2 | ||
| 3 | AUTOSCRIBE_SHADER_LIB(gpu model render) | 3 | AUTOSCRIBE_SHADER_LIB(gpu model render) |
| 4 | 4 | ||
| 5 | # pull in the resources.qrc file | 5 | # pull in the resources.qrc file |
| 6 | qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc") | 6 | qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc") |
| 7 | 7 | ||
| 8 | # use setup_hifi_library macro to setup our project and link appropriate Qt modules | 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) | 9 | setup_hifi_library(Widgets OpenGL Network Qml Quick Script) |
| 10 | 10 | ||
| 11 | add_dependency_external_projects(glm) | 11 | setup_hifi_opengl() |
| 12 | find_package(GLM REQUIRED) | 12 | |
| 13 | target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) | 13 | add_dependency_external_projects(glm) |
| 14 | 14 | find_package(GLM REQUIRED) | |
| 15 | if (WIN32) | 15 | target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) |
| 16 | if (USE_NSIGHT) | 16 | |
| 17 | # try to find the Nsight package and add it to the build if we find it | 17 | if (WIN32) |
| 18 | find_package(NSIGHT) | 18 | if (USE_NSIGHT) |
| 19 | if (NSIGHT_FOUND) | 19 | # try to find the Nsight package and add it to the build if we find it |
| 20 | include_directories(${NSIGHT_INCLUDE_DIRS}) | 20 | find_package(NSIGHT) |
| 21 | add_definitions(-DNSIGHT_FOUND) | 21 | if (NSIGHT_FOUND) |
| 22 | target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}") | 22 | include_directories(${NSIGHT_INCLUDE_DIRS}) |
| 23 | endif () | 23 | add_definitions(-DNSIGHT_FOUND) |
| 24 | endif() | 24 | target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}") |
| 25 | endif (WIN32) | 25 | endif () |
| 26 | 26 | endif() | |
| 27 | link_hifi_libraries(animation fbx shared gpu model render) | 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 | gpu::Shader::BindingSet slotBindings; | 61 | gpu::Shader::BindingSet slotBindings; |
| 62 | gpu::Shader::makeProgram(*program, slotBindings); | 62 | gpu::Shader::makeProgram(*program, slotBindings); |
| 63 | gpu::Shader::makeProgram(*programTextured, slotBindings); | 63 | gpu::Shader::makeProgram(*programTextured, slotBindings); |
| 64 | 64 | ||
| 65 | gpu::StatePointer state = gpu::StatePointer(new gpu::State()); | 65 | gpu::StatePointer state = gpu::StatePointer(new gpu::State()); |
| 66 | state->setCullMode(gpu::State::CULL_BACK); | 66 | state->setCullMode(gpu::State::CULL_BACK); |
| 67 | state->setDepthTest(true, true, gpu::LESS_EQUAL); | 67 | state->setDepthTest(true, true, gpu::LESS_EQUAL); |
| 68 | state->setBlendFunction(false, | 68 | state->setBlendFunction(false, |
| 69 | gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, | 69 | gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, |
| 70 | gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); | 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 | _simpleProgram = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); | 80 | _simpleProgram = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); |
| 81 | _simpleProgramCullNone = gpu::PipelinePointer(gpu::Pipeline::create(program, stateCullNone)); | ||
| 72 | _simpleProgramTextured = gpu::PipelinePointer(gpu::Pipeline::create(programTextured, state)); | 82 | _simpleProgramTextured = gpu::PipelinePointer(gpu::Pipeline::create(programTextured, state)); |
| 83 | _simpleProgramTexturedCullNone = gpu::PipelinePointer(gpu::Pipeline::create(programTextured, stateCullNone)); | ||
| 73 | 84 | ||
| 74 | _viewState = viewState; | 85 | _viewState = viewState; |
| 75 | loadLightProgram(directional_light_frag, false, _directionalLight, _directionalLightLocations); | 86 | loadLightProgram(directional_light_frag, false, _directionalLight, _directionalLightLocations); |
| @@ -106,13 +117,21 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { · 30 unmodified lines | |||
| 106 | lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET)); | 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 | // DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(batch, true, true, true); | 121 | // DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(batch, true, true, true); |
| 111 | 122 | ||
| 112 | if (textured) { | 123 | if (textured) { |
| 113 | batch.setPipeline(_simpleProgramTextured); | 124 | if (culled) { |
| 125 | batch.setPipeline(_simpleProgramTextured); | ||
| 126 | } else { | ||
| 127 | batch.setPipeline(_simpleProgramTexturedCullNone); | ||
| 128 | } | ||
| 114 | } else { | 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 | // clear the normal and specular buffers | 214 | // clear the normal and specular buffers |
| 196 | auto textureCache = DependencyManager::get<TextureCache>(); | 215 | auto textureCache = DependencyManager::get<TextureCache>(); |
| 197 | textureCache->setPrimaryDrawBuffers(false, true, false); | 216 | textureCache->setPrimaryDrawBuffers(false, true, false); |
| @@ -205,7 +224,7 @@ void DeferredLightingEffect::prepare() { · 7 unmodified lines | |||
| 205 | textureCache->setPrimaryDrawBuffers(true, false, false); | 224 | textureCache->setPrimaryDrawBuffers(true, false, false); |
| 206 | } | 225 | } |
| 207 | 226 | ||
| 208 | void DeferredLightingEffect::render() { | 227 | void DeferredLightingEffect::render(RenderArgs* args) { |
| 209 | // perform deferred lighting, rendering to free fbo | 228 | // perform deferred lighting, rendering to free fbo |
| 210 | glDisable(GL_BLEND); | 229 | glDisable(GL_BLEND); |
| 211 | glDisable(GL_LIGHTING); | 230 | glDisable(GL_LIGHTING); |
| @@ -34,7 +34,7 @@ public: · 33 unmodified lines | |||
| 34 | void init(AbstractViewStateInterface* viewState); | 34 | void init(AbstractViewStateInterface* viewState); |
| 35 | 35 | ||
| 36 | /// Sets up the state necessary to render static untextured geometry with the simple program. | 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 | /// Tears down the state necessary to render static untextured geometry with the simple program. | 39 | /// Tears down the state necessary to render static untextured geometry with the simple program. |
| 40 | void releaseSimpleProgram(gpu::Batch& batch); | 40 | void releaseSimpleProgram(gpu::Batch& batch); |
| @@ -66,8 +66,8 @@ public: · 25 unmodified lines | |||
| 66 | void addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f), | 66 | void addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f), |
| 67 | float intensity = 0.5f, const glm::quat& orientation = glm::quat(), float exponent = 0.0f, float cutoff = PI); | 67 | float intensity = 0.5f, const glm::quat& orientation = glm::quat(), float exponent = 0.0f, float cutoff = PI); |
| 68 | 68 | ||
| 69 | void prepare(); | 69 | void prepare(RenderArgs* args); |
| 70 | void render(); | 70 | void render(RenderArgs* args); |
| 71 | void copyBack(RenderArgs* args); | 71 | void copyBack(RenderArgs* args); |
| 72 | 72 | ||
| 73 | void setupTransparent(RenderArgs* args, int lightBufferUnit); | 73 | void setupTransparent(RenderArgs* args, int lightBufferUnit); |
| @@ -100,7 +100,9 @@ private: · 26 unmodified lines | |||
| 100 | static void loadLightProgram(const char* fragSource, bool limited, ProgramObject& program, LightLocations& locations); | 100 | static void loadLightProgram(const char* fragSource, bool limited, ProgramObject& program, LightLocations& locations); |
| 101 | 101 | ||
| 102 | gpu::PipelinePointer _simpleProgram; | 102 | gpu::PipelinePointer _simpleProgram; |
| 103 | gpu::PipelinePointer _simpleProgramCullNone; | ||
| 103 | gpu::PipelinePointer _simpleProgramTextured; | 104 | gpu::PipelinePointer _simpleProgramTextured; |
| 105 | gpu::PipelinePointer _simpleProgramTexturedCullNone; | ||
| 104 | 106 | ||
| 105 | ProgramObject _directionalSkyboxLight; | 107 | ProgramObject _directionalSkyboxLight; |
| 106 | LightLocations _directionalSkyboxLightLocations; | 108 | LightLocations _directionalSkyboxLightLocations; |
| @@ -28,6 +28,9 @@ · 27 unmodified lines | |||
| 28 | #include "RenderUtilsLogging.h" | 28 | #include "RenderUtilsLogging.h" |
| 29 | #include "GeometryCache.h" | 29 | #include "GeometryCache.h" |
| 30 | 30 | ||
| 31 | #include "standardTransformPNTC_vert.h" | ||
| 32 | #include "standardDrawTexture_frag.h" | ||
| 33 | |||
| 31 | //#define WANT_DEBUG | 34 | //#define WANT_DEBUG |
| 32 | 35 | ||
| 33 | const int GeometryCache::UNKNOWN_ID = -1; | 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 | #endif // def WANT_DEBUG | 1028 | #endif // def WANT_DEBUG |
| 1026 | } | 1029 | } |
| 1027 | 1030 | ||
| 1028 | const int FLOATS_PER_VERTEX = 2; // vertices | ||
| 1029 | const int vertices = 8; | ||
| 1030 | |||
| 1031 | if (!details.isCreated) { | 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 | details.isCreated = true; | 1036 | details.isCreated = true; |
| 1034 | details.vertices = vertices; | 1037 | details.vertices = NUM_VERTICES; |
| 1035 | details.vertexSize = FLOATS_PER_VERTEX; | 1038 | details.vertexSize = FLOATS_PER_VERTEX; |
| 1036 | 1039 | ||
| 1037 | gpu::BufferPointer verticesBuffer(new gpu::Buffer()); | 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 | details.streamFormat = streamFormat; | 1047 | details.streamFormat = streamFormat; |
| 1045 | details.stream = stream; | 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 | details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA)); | 1051 | details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA)); |
| 1049 | 1052 | ||
| 1050 | details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride); | 1053 | details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride); |
| 1051 | details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride); | 1054 | details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride); |
| 1052 | 1055 | ||
| 1053 | 1056 | ||
| 1054 | int vertexPoints = vertices * FLOATS_PER_VERTEX; | 1057 | GLfloat vertexBuffer[NUM_FLOATS]; // only vertices, no normals because we're a 2D quad |
| 1055 | GLfloat* vertexBuffer = new GLfloat[vertexPoints]; // only vertices, no normals because we're a 2D quad | ||
| 1056 | GLfloat* vertex = vertexBuffer; | ||
| 1057 | int vertexPoint = 0; | 1058 | int vertexPoint = 0; |
| 1058 | 1059 | ||
| 1059 | // left side | 1060 | // Triangle strip points |
| 1060 | vertex[vertexPoint++] = x; | 1061 | // 3 ------ 5 |
| 1061 | vertex[vertexPoint++] = y + bevelDistance; | 1062 | // / \ |
| 1063 | // 1 7 | ||
| 1064 | // | | | ||
| 1065 | // 2 8 | ||
| 1066 | // \ / | ||
| 1067 | // 4 ------ 6 | ||
| 1062 | 1068 | ||
| 1063 | vertex[vertexPoint++] = x; | 1069 | // 1 |
| 1064 | vertex[vertexPoint++] = y + height - bevelDistance; | 1070 | vertexBuffer[vertexPoint++] = x; |
| 1065 | 1071 | vertexBuffer[vertexPoint++] = y + height - bevelDistance; | |
| 1066 | // top side | 1072 | // 2 |
| 1067 | vertex[vertexPoint++] = x + bevelDistance; | 1073 | vertexBuffer[vertexPoint++] = x; |
| 1068 | vertex[vertexPoint++] = y + height; | 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 | int compactColor = ((int(color.x * 255.0f) & 0xFF)) | | 1094 | int compactColor = ((int(color.x * 255.0f) & 0xFF)) | |
| 1087 | ((int(color.y * 255.0f) & 0xFF) << 8) | | 1095 | ((int(color.y * 255.0f) & 0xFF) << 8) | |
| 1088 | ((int(color.z * 255.0f) & 0xFF) << 16) | | 1096 | ((int(color.z * 255.0f) & 0xFF) << 16) | |
| 1089 | ((int(color.w * 255.0f) & 0xFF) << 24); | 1097 | ((int(color.w * 255.0f) & 0xFF) << 24); |
| 1090 | int colors[NUM_COLOR_SCALARS_PER_QUAD] = { compactColor, compactColor, compactColor, compactColor, | 1098 | int colors[NUM_VERTICES] = { compactColor, compactColor, compactColor, compactColor, |
| 1091 | compactColor, compactColor, compactColor, compactColor }; | 1099 | compactColor, compactColor, compactColor, compactColor }; |
| 1092 | 1100 | ||
| 1093 | 1101 | ||
| 1094 | details.verticesBuffer->append(sizeof(vertexBuffer), (gpu::Byte*) vertexBuffer); | 1102 | details.verticesBuffer->append(sizeof(vertexBuffer), (gpu::Byte*) vertexBuffer); |
| 1095 | details.colorBuffer->append(sizeof(colors), (gpu::Byte*) colors); | 1103 | details.colorBuffer->append(sizeof(colors), (gpu::Byte*) colors); |
| 1096 | |||
| 1097 | delete[] vertexBuffer; | ||
| 1098 | } | 1104 | } |
| 1099 | 1105 | ||
| 1100 | batch.setInputFormat(details.streamFormat); | 1106 | batch.setInputFormat(details.streamFormat); |
| 1101 | batch.setInputStream(0, *details.stream); | 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 | void GeometryCache::renderQuad(const glm::vec2& minCorner, const glm::vec2& maxCorner, const glm::vec4& color, int id) { | 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 | batch.draw(gpu::QUADS, 4, 0); | 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 | void GeometryCache::renderQuad(const glm::vec2& minCorner, const glm::vec2& maxCorner, | 1208 | void GeometryCache::renderQuad(const glm::vec2& minCorner, const glm::vec2& maxCorner, |
| 1183 | const glm::vec2& texCoordMinCorner, const glm::vec2& texCoordMaxCorner, | 1209 | const glm::vec2& texCoordMinCorner, const glm::vec2& texCoordMaxCorner, |
| 1184 | const glm::vec4& color, int id) { | 1210 | const glm::vec4& color, int id) { |
| @@ -1802,6 +1828,23 @@ QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url, const QS · 617 unmodified lines | |||
| 1802 | return geometry.staticCast<Resource>(); | 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 | const float NetworkGeometry::NO_HYSTERESIS = -1.0f; | 1848 | const float NetworkGeometry::NO_HYSTERESIS = -1.0f; |
| 1806 | 1849 | ||
| 1807 | NetworkGeometry::NetworkGeometry(const QUrl& url, const QSharedPointer<NetworkGeometry>& fallback, bool delayLoad, | 1850 | NetworkGeometry::NetworkGeometry(const QUrl& url, const QSharedPointer<NetworkGeometry>& fallback, bool delayLoad, |
| @@ -155,6 +155,10 @@ public: · 154 unmodified lines | |||
| 155 | void renderBevelCornersRect(int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID); | 155 | void renderBevelCornersRect(int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID); |
| 156 | void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID); | 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 | void renderQuad(int x, int y, int width, int height, const glm::vec4& color, int id = UNKNOWN_ID) | 162 | void renderQuad(int x, int y, int width, int height, const glm::vec4& color, int id = UNKNOWN_ID) |
| 159 | { renderQuad(glm::vec2(x,y), glm::vec2(x + width, y + height), color, id); } | 163 | { renderQuad(glm::vec2(x,y), glm::vec2(x + width, y + height), color, id); } |
| 160 | void renderQuad(gpu::Batch& batch, int x, int y, int width, int height, const glm::vec4& color, int id = UNKNOWN_ID) | 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 | /// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested | 253 | /// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested |
| 250 | QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false); | 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 | protected: | 259 | protected: |
| 253 | 260 | ||
| 254 | virtual QSharedPointer<Resource> createResource(const QUrl& url, | 261 | virtual QSharedPointer<Resource> createResource(const QUrl& url, |
| @@ -266,6 +273,7 @@ private: · 11 unmodified lines | |||
| 266 | int vertexSize; | 273 | int vertexSize; |
| 267 | }; | 274 | }; |
| 268 | 275 | ||
| 276 | gpu::PipelinePointer _standardDrawPipeline; | ||
| 269 | QHash<float, gpu::BufferPointer> _cubeVerticies; | 277 | QHash<float, gpu::BufferPointer> _cubeVerticies; |
| 270 | QHash<Vec2Pair, gpu::BufferPointer> _cubeColors; | 278 | QHash<Vec2Pair, gpu::BufferPointer> _cubeColors; |
| 271 | gpu::BufferPointer _wireCubeIndexBuffer; | 279 | gpu::BufferPointer _wireCubeIndexBuffer; |
| @@ -273,7 +281,7 @@ private: · 1 unmodified line | |||
| 273 | QHash<float, gpu::BufferPointer> _solidCubeVertices; | 281 | QHash<float, gpu::BufferPointer> _solidCubeVertices; |
| 274 | QHash<Vec2Pair, gpu::BufferPointer> _solidCubeColors; | 282 | QHash<Vec2Pair, gpu::BufferPointer> _solidCubeColors; |
| 275 | gpu::BufferPointer _solidCubeIndexBuffer; | 283 | gpu::BufferPointer _solidCubeIndexBuffer; |
| 276 | 284 | ||
| 277 | class BatchItemDetails { | 285 | class BatchItemDetails { |
| 278 | public: | 286 | public: |
| 279 | static int population; | 287 | static int population; |
| @@ -545,11 +545,6 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g · 544 unmodified lines | |||
| 545 | // we can use the AABox's ray intersection by mapping our origin and direction into the model frame | 545 | // we can use the AABox's ray intersection by mapping our origin and direction into the model frame |
| 546 | // and testing intersection there. | 546 | // and testing intersection there. |
| 547 | if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face)) { | 547 | if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face)) { |
| 548 | |||
| 549 | if (!_calculatedMeshBoxesValid) { | ||
| 550 | recalculateMeshBoxes(pickAgainstTriangles); | ||
| 551 | } | ||
| 552 | |||
| 553 | float bestDistance = std::numeric_limits<float>::max(); | 548 | float bestDistance = std::numeric_limits<float>::max(); |
| 554 | 549 | ||
| 555 | float distanceToSubMesh; | 550 | float distanceToSubMesh; |
| @@ -560,6 +555,11 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g · 4 unmodified lines | |||
| 560 | 555 | ||
| 561 | // If we hit the models box, then consider the submeshes... | 556 | // If we hit the models box, then consider the submeshes... |
| 562 | _mutex.lock(); | 557 | _mutex.lock(); |
| 558 | |||
| 559 | if (!_calculatedMeshBoxesValid) { | ||
| 560 | recalculateMeshBoxes(pickAgainstTriangles); | ||
| 561 | } | ||
| 562 | |||
| 563 | foreach(const AABox& subMeshBox, _calculatedMeshBoxes) { | 563 | foreach(const AABox& subMeshBox, _calculatedMeshBoxes) { |
| 564 | 564 | ||
| 565 | if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace)) { | 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 | void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent) { | 1806 | void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent) { |
| 1807 | PerformanceTimer perfTimer("Model::renderPart"); | ||
| 1807 | if (!_readyWhenAdded) { | 1808 | if (!_readyWhenAdded) { |
| 1808 | return; // bail asap | 1809 | return; // bail asap |
| 1809 | } | 1810 | } |
| 1810 | 1811 | ||
| 1811 | // We need to make sure we have valid offsets calculated before we can render | 1812 | // We need to make sure we have valid offsets calculated before we can render |
| 1812 | if (!_calculatedMeshPartOffsetValid) { | 1813 | if (!_calculatedMeshPartOffsetValid) { |
| 1814 | _mutex.lock(); | ||
| 1813 | recalculateMeshPartOffsets(); | 1815 | recalculateMeshPartOffsets(); |
| 1816 | _mutex.unlock(); | ||
| 1814 | } | 1817 | } |
| 1815 | auto textureCache = DependencyManager::get<TextureCache>(); | 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 | qint64 offset = _calculatedMeshPartOffset[QPair<int,int>(meshIndex, partIndex)]; | 2025 | qint64 offset = _calculatedMeshPartOffset[QPair<int,int>(meshIndex, partIndex)]; |
| 2026 | _mutex.unlock(); | ||
| 2022 | 2027 | ||
| 2023 | if (part.quadIndices.size() > 0) { | 2028 | if (part.quadIndices.size() > 0) { |
| 2024 | batch.drawIndexed(gpu::QUADS, part.quadIndices.size(), offset); | 2029 | batch.drawIndexed(gpu::QUADS, part.quadIndices.size(), offset); |
| @@ -11,6 +11,9 @@ · 10 unmodified lines | |||
| 11 | #include <QOpenGLDebugLogger> | 11 | #include <QOpenGLDebugLogger> |
| 12 | #include <QGLWidget> | 12 | #include <QGLWidget> |
| 13 | #include <QtQml> | 13 | #include <QtQml> |
| 14 | |||
| 15 | #include <PerfStat.h> | ||
| 16 | |||
| 14 | #include "AbstractViewStateInterface.h" | 17 | #include "AbstractViewStateInterface.h" |
| 15 | 18 | ||
| 16 | Q_DECLARE_LOGGING_CATEGORY(offscreenFocus) | 19 | Q_DECLARE_LOGGING_CATEGORY(offscreenFocus) |
| @@ -91,6 +94,7 @@ void OffscreenQmlSurface::resize(const QSize& newSize) { · 74 unmodified lines | |||
| 91 | // Qt bug in 5.4 forces this check of pixel ratio, | 94 | // Qt bug in 5.4 forces this check of pixel ratio, |
| 92 | // even though we're rendering offscreen. | 95 | // even though we're rendering offscreen. |
| 93 | qreal pixelRatio = 1.0; | 96 | qreal pixelRatio = 1.0; |
| 97 | _qmlEngine->rootContext()->setContextProperty("surfaceSize", newSize); | ||
| 94 | if (_renderControl && _renderControl->_renderWindow) { | 98 | if (_renderControl && _renderControl->_renderWindow) { |
| 95 | pixelRatio = _renderControl->_renderWindow->devicePixelRatio(); | 99 | pixelRatio = _renderControl->_renderWindow->devicePixelRatio(); |
| 96 | } else { | 100 | } else { |
| @@ -111,7 +115,6 @@ void OffscreenQmlSurface::resize(const QSize& newSize) { · 14 unmodified lines | |||
| 111 | _quickWindow->contentItem()->setSize(newSize); | 115 | _quickWindow->contentItem()->setSize(newSize); |
| 112 | } | 116 | } |
| 113 | 117 | ||
| 114 | |||
| 115 | // Update our members | 118 | // Update our members |
| 116 | if (_rootItem) { | 119 | if (_rootItem) { |
| 117 | _rootItem->setSize(newSize); | 120 | _rootItem->setSize(newSize); |
| @@ -212,6 +215,7 @@ QObject* OffscreenQmlSurface::finishQmlLoad(std::function<void(QQmlContext*, QOb · 94 unmodified lines | |||
| 212 | 215 | ||
| 213 | 216 | ||
| 214 | void OffscreenQmlSurface::updateQuick() { | 217 | void OffscreenQmlSurface::updateQuick() { |
| 218 | PerformanceTimer perfTimer("qmlUpdate"); | ||
| 215 | if (_paused) { | 219 | if (_paused) { |
| 216 | return; | 220 | return; |
| 217 | } | 221 | } |
| @@ -376,4 +380,4 @@ void OffscreenQmlSurface::setProxyWindow(QWindow* window) { · 158 unmodified lines | |||
| 376 | 380 | ||
| 377 | QQuickWindow* OffscreenQmlSurface::getWindow() { | 381 | QQuickWindow* OffscreenQmlSurface::getWindow() { |
| 378 | return _quickWindow; | 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 | #ifndef hifi_ProgramObject_h | 12 | #ifndef hifi_ProgramObject_h |
| 13 | #define hifi_ProgramObject_h | 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 | #include <QGLShaderProgram> | 20 | #include <QGLShaderProgram> |
| 16 | 21 | ||
| 22 | #ifdef __GNUC__ | ||
| 23 | #pragma GCC diagnostic pop | ||
| 24 | #endif | ||
| 25 | |||
| 17 | #include <glm/glm.hpp> | 26 | #include <glm/glm.hpp> |
| 18 | 27 | ||
| 19 | class ProgramObject : public QGLShaderProgram { | 28 | class ProgramObject : public QGLShaderProgram { |
| 20 | public: | 29 | public: |
| 21 | 30 | ||
| 22 | ProgramObject(QObject* parent = 0); | 31 | ProgramObject(QObject* parent = 0); |
| 23 | 32 | ||
| 24 | void setUniform(int location, const glm::vec2& value); | 33 | void setUniform(int location, const glm::vec2& value); |
| 25 | void setUniform(const char* name, const glm::vec2& value); | 34 | void setUniform(const char* name, const glm::vec2& value); |
| 26 | void setUniform(int location, const glm::vec3& value); | 35 | void setUniform(int location, const glm::vec3& value); |
| 27 | void setUniform(const char* name, const glm::vec3& value); | 36 | void setUniform(const char* name, const glm::vec3& value); |
| 28 | void setUniform(int location, const glm::vec4& value); | 37 | void setUniform(int location, const glm::vec4& value); |
| 29 | void setUniform(const char* name, const glm::vec4& value); | 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 | #endif // hifi_ProgramObject_h | 42 | #endif // hifi_ProgramObject_h |
| @@ -19,42 +19,54 @@ · 18 unmodified lines | |||
| 19 | 19 | ||
| 20 | #include <PerfStat.h> | 20 | #include <PerfStat.h> |
| 21 | 21 | ||
| 22 | #include "overlay3D_vert.h" | 22 | #include "overlay3D_vert.h" |
| 23 | #include "overlay3D_frag.h" | 23 | #include "overlay3D_frag.h" |
| 24 | 24 | ||
| 25 | using namespace render; | 25 | using namespace render; |
| 26 | 26 | ||
| 27 | template <> void render::jobRun(const PrepareDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | 27 | void PrepareDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { |
| 28 | PerformanceTimer perfTimer("PrepareDeferred"); | 28 | DependencyManager::get<DeferredLightingEffect>()->prepare(renderContext->args); |
| 29 | DependencyManager::get<DeferredLightingEffect>()->prepare(); | ||
| 30 | } | 29 | } |
| 31 | 30 | ||
| 32 | template <> void render::jobRun(const RenderDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | 31 | void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { |
| 33 | PerformanceTimer perfTimer("RenderDeferred"); | 32 | DependencyManager::get<DeferredLightingEffect>()->render(renderContext->args); |
| 34 | DependencyManager::get<DeferredLightingEffect>()->render(); | ||
| 35 | // renderContext->args->_context->syncCache(); | ||
| 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 | PerformanceTimer perfTimer("ResolveDeferred"); | 36 | PerformanceTimer perfTimer("ResolveDeferred"); |
| 40 | DependencyManager::get<DeferredLightingEffect>()->copyBack(renderContext->args); | 37 | DependencyManager::get<DeferredLightingEffect>()->copyBack(renderContext->args); |
| 41 | renderContext->args->_context->syncCache(); | ||
| 42 | |||
| 43 | } | 38 | } |
| 44 | 39 | ||
| 45 | |||
| 46 | |||
| 47 | RenderDeferredTask::RenderDeferredTask() : Task() { | 40 | RenderDeferredTask::RenderDeferredTask() : Task() { |
| 48 | _jobs.push_back(Job(PrepareDeferred())); | 41 | _jobs.push_back(Job(new PrepareDeferred::JobModel("PrepareDeferred"))); |
| 49 | _jobs.push_back(Job(DrawBackground())); | 42 | _jobs.push_back(Job(new DrawBackground::JobModel("DrawBackground"))); |
| 50 | _jobs.push_back(Job(DrawOpaqueDeferred())); | 43 | _jobs.push_back(Job(new FetchItems::JobModel("FetchOpaque", |
| 51 | _jobs.push_back(Job(DrawLight())); | 44 | FetchItems( |
| 52 | _jobs.push_back(Job(ResetGLState())); | 45 | [] (const RenderContextPointer& context, int count) { |
| 53 | _jobs.push_back(Job(RenderDeferred())); | 46 | context->_numFeedOpaqueItems = count; |
| 54 | _jobs.push_back(Job(ResolveDeferred())); | 47 | } |
| 55 | _jobs.push_back(Job(DrawTransparentDeferred())); | 48 | ) |
| 56 | _jobs.push_back(Job(DrawOverlay3D())); | 49 | ))); |
| 57 | _jobs.push_back(Job(ResetGLState())); | 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 | RenderDeferredTask::~RenderDeferredTask() { | 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 | 95 | void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) { | |
| 84 | |||
| 85 | template <> void render::jobRun(const DrawOpaqueDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | ||
| 86 | PerformanceTimer perfTimer("DrawOpaqueDeferred"); | ||
| 87 | assert(renderContext->args); | 96 | assert(renderContext->args); |
| 88 | assert(renderContext->args->_viewFrustum); | 97 | assert(renderContext->args->_viewFrustum); |
| 89 | 98 | ||
| 90 | // render opaques | 99 | RenderArgs* args = renderContext->args; |
| 91 | auto& scene = sceneContext->_scene; | 100 | gpu::Batch batch; |
| 92 | auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape().withoutLayered()); | 101 | args->_batch = &batch; |
| 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(); | ||
| 114 | 102 | ||
| 103 | renderContext->_numDrawnOpaqueItems = inItems.size(); | ||
| 115 | 104 | ||
| 116 | ItemIDsBounds sortedItems; | 105 | glm::mat4 projMat; |
| 117 | sortedItems.reserve(culledItems.size()); | 106 | Transform viewMat; |
| 118 | if (renderContext->_sortOpaque) { | 107 | args->_viewFrustum->evalProjectionMatrix(projMat); |
| 119 | depthSortItems(sceneContext, renderContext, true, renderedItems, sortedItems); // Sort Front to back opaque items! | 108 | args->_viewFrustum->evalViewTransform(viewMat); |
| 120 | renderedItems = sortedItems; | 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; | 115 | { |
| 124 | /* ItemMaterialBucketMap stateSortedItems; | 116 | GLenum buffers[3]; |
| 125 | stateSortedItems.allocateStandardMaterialBuckets(); | 117 | int bufferCount = 0; |
| 126 | if (true) { | 118 | buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; |
| 127 | for (auto& itemIDAndBound : renderedItems) { | 119 | buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; |
| 128 | stateSortedItems.insert(itemIDAndBound.id, scene->getItem(itemIDAndBound.id).getMaterialKey()); | 120 | buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; |
| 129 | } | 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)); | 128 | // Before rendering the batch make sure we re in sync with gl state |
| 160 | args->_batch = nullptr; | 129 | args->_context->syncCache(); |
| 161 | } | 130 | renderContext->args->_context->syncCache(); |
| 131 | args->_context->render((*args->_batch)); | ||
| 132 | args->_batch = nullptr; | ||
| 162 | } | 133 | } |
| 163 | 134 | ||
| 164 | 135 | void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) { | |
| 165 | template <> void render::jobRun(const DrawTransparentDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | ||
| 166 | PerformanceTimer perfTimer("DrawTransparentDeferred"); | ||
| 167 | assert(renderContext->args); | 136 | assert(renderContext->args); |
| 168 | assert(renderContext->args->_viewFrustum); | 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 | auto& renderDetails = renderContext->args->_details; | 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; | 146 | glm::mat4 projMat; |
| 185 | if (renderContext->_cullTransparent) { | 147 | Transform viewMat; |
| 186 | renderDetails.pointTo(RenderDetails::TRANSLUCENT_ITEM); | 148 | args->_viewFrustum->evalProjectionMatrix(projMat); |
| 187 | cullItems(sceneContext, renderContext, inItems, culledItems); | 149 | args->_viewFrustum->evalViewTransform(viewMat); |
| 188 | renderDetails.pointTo(RenderDetails::OTHER_ITEM); | 150 | if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { |
| 189 | renderedItems = culledItems; | 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(); | 157 | { |
| 193 | 158 | GLenum buffers[3]; | |
| 194 | ItemIDsBounds sortedItems; | 159 | int bufferCount = 0; |
| 195 | if (renderContext->_sortTransparent) { | 160 | buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; |
| 196 | depthSortItems(sceneContext, renderContext, false, renderedItems, sortedItems); // Sort Back to front transparent items! | 161 | batch._glDrawBuffers(bufferCount, buffers); |
| 197 | renderedItems = sortedItems; | 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) { | 177 | const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() const { |
| 201 | RenderArgs* args = renderContext->args; | 178 | if (!_opaquePipeline) { |
| 202 | gpu::Batch batch; | 179 | auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(overlay3D_vert))); |
| 203 | args->_batch = &batch; | 180 | auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(overlay3D_frag))); |
| 204 | |||
| 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; | 187 | _opaquePipeline.reset(gpu::Pipeline::create(program, state)); |
| 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); | ||
| 238 | } | 188 | } |
| 189 | return _opaquePipeline; | ||
| 239 | } | 190 | } |
| 240 | 191 | ||
| 241 | const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() const { | 192 | void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { |
| 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"); | ||
| 258 | assert(renderContext->args); | 193 | assert(renderContext->args); |
| 259 | assert(renderContext->args->_viewFrustum); | 194 | assert(renderContext->args->_viewFrustum); |
| 260 | 195 | ||
| @@ -271,13 +206,14 @@ template <> void render::jobRun(const DrawOverlay3D& job, const SceneContextPoin · 10 unmodified lines | |||
| 271 | inItems.emplace_back(id); | 206 | inItems.emplace_back(id); |
| 272 | } | 207 | } |
| 273 | } | 208 | } |
| 274 | 209 | renderContext->_numFeedOverlay3DItems = inItems.size(); | |
| 210 | renderContext->_numDrawnOverlay3DItems = inItems.size(); | ||
| 211 | |||
| 275 | RenderArgs* args = renderContext->args; | 212 | RenderArgs* args = renderContext->args; |
| 276 | gpu::Batch batch; | 213 | gpu::Batch batch; |
| 277 | args->_batch = &batch; | 214 | args->_batch = &batch; |
| 278 | args->_whiteTexture = DependencyManager::get<TextureCache>()->getWhiteTexture(); | 215 | args->_whiteTexture = DependencyManager::get<TextureCache>()->getWhiteTexture(); |
| 279 | 216 | ||
| 280 | |||
| 281 | glm::mat4 projMat; | 217 | glm::mat4 projMat; |
| 282 | Transform viewMat; | 218 | Transform viewMat; |
| 283 | args->_viewFrustum->evalProjectionMatrix(projMat); | 219 | args->_viewFrustum->evalProjectionMatrix(projMat); |
| @@ -287,12 +223,13 @@ template <> void render::jobRun(const DrawOverlay3D& job, const SceneContextPoin · 3 unmodified lines | |||
| 287 | } | 223 | } |
| 288 | batch.setProjectionTransform(projMat); | 224 | batch.setProjectionTransform(projMat); |
| 289 | batch.setViewTransform(viewMat); | 225 | batch.setViewTransform(viewMat); |
| 290 | batch.setPipeline(job.getOpaquePipeline()); | 226 | |
| 227 | batch.setPipeline(getOpaquePipeline()); | ||
| 291 | batch.setUniformTexture(0, args->_whiteTexture); | 228 | batch.setUniformTexture(0, args->_whiteTexture); |
| 292 | 229 | ||
| 293 | if (!inItems.empty()) { | 230 | if (!inItems.empty()) { |
| 294 | batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0); | 231 | batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0); |
| 295 | renderItems(sceneContext, renderContext, inItems); | 232 | renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnOverlay3DItems); |
| 296 | } | 233 | } |
| 297 | 234 | ||
| 298 | // Before rendering the batch make sure we re in sync with gl state | 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 | args->_batch = nullptr; | 238 | args->_batch = nullptr; |
| 302 | args->_whiteTexture.reset(); | 239 | args->_whiteTexture.reset(); |
| 303 | } | 240 | } |
| 241 | |||
| @@ -18,48 +18,49 @@ · 17 unmodified lines | |||
| 18 | 18 | ||
| 19 | class PrepareDeferred { | 19 | class PrepareDeferred { |
| 20 | public: | 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 { | 25 | |
| 23 | template <> void jobRun(const PrepareDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); | ||
| 24 | } | ||
| 25 | 26 | ||
| 26 | class RenderDeferred { | 27 | class RenderDeferred { |
| 27 | public: | 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 | class ResolveDeferred { | 34 | class ResolveDeferred { |
| 34 | public: | 35 | public: |
| 35 | }; | 36 | void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); |
| 36 | namespace render { | ||
| 37 | template <> void jobRun(const ResolveDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); | ||
| 38 | } | ||
| 39 | 37 | ||
| 38 | typedef render::Job::Model<ResolveDeferred> JobModel; | ||
| 39 | }; | ||
| 40 | 40 | ||
| 41 | class DrawOpaqueDeferred { | 41 | class DrawOpaqueDeferred { |
| 42 | public: | 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 | class DrawTransparentDeferred { | 48 | class DrawTransparentDeferred { |
| 49 | public: | 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 { | 54 | |
| 52 | template <> void jobRun(const DrawTransparentDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); | 55 | class DrawOverlay3D { |
| 53 | } | 56 | mutable gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable |
| 54 | 57 | public: | |
| 55 | class DrawOverlay3D { | 58 | const gpu::PipelinePointer& getOpaquePipeline() const; |
| 56 | mutable gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable | 59 | |
| 57 | public: | 60 | void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); |
| 58 | const gpu::PipelinePointer& getOpaquePipeline() const; | 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 | class RenderDeferredTask : public render::Task { | 65 | class RenderDeferredTask : public render::Task { |
| 65 | public: | 66 | public: |
| @@ -18,12 +18,21 @@ · 17 unmodified lines | |||
| 18 | #include <QBuffer> | 18 | #include <QBuffer> |
| 19 | #include <QFile> | 19 | #include <QFile> |
| 20 | 20 | ||
| 21 | #ifdef __GNUC__ | ||
| 22 | #pragma GCC diagnostic push | ||
| 23 | #pragma GCC diagnostic ignored "-Wdouble-promotion" | ||
| 24 | #endif | ||
| 25 | |||
| 21 | // FIXME, decouple from the GL headers | 26 | // FIXME, decouple from the GL headers |
| 22 | #include <QOpenGLShaderProgram> | 27 | #include <QOpenGLShaderProgram> |
| 23 | #include <QOpenGLTexture> | 28 | #include <QOpenGLTexture> |
| 24 | #include <QOpenGLVertexArrayObject> | 29 | #include <QOpenGLVertexArrayObject> |
| 25 | #include <QOpenGLBuffer> | 30 | #include <QOpenGLBuffer> |
| 26 | 31 | ||
| 32 | #ifdef __GNUC__ | ||
| 33 | #pragma GCC diagnostic pop | ||
| 34 | #endif | ||
| 35 | |||
| 27 | #include <glm/glm.hpp> | 36 | #include <glm/glm.hpp> |
| 28 | #include <glm/gtc/matrix_transform.hpp> | 37 | #include <glm/gtc/matrix_transform.hpp> |
| 29 | 38 | ||
| @@ -30,11 +30,6 @@ · 29 unmodified lines | |||
| 30 | #include "GeometryCache.h" | 30 | #include "GeometryCache.h" |
| 31 | #include "DeferredLightingEffect.h" | 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 | // Helper functions for reading binary data from an IO device | 33 | // Helper functions for reading binary data from an IO device |
| 39 | template<class T> | 34 | template<class T> |
| 40 | void readStream(QIODevice& in, T& t) { | 35 | void readStream(QIODevice& in, T& t) { |
| @@ -117,7 +112,7 @@ public: · 76 unmodified lines | |||
| 117 | 112 | ||
| 118 | // Render string to batch | 113 | // Render string to batch |
| 119 | void drawString(gpu::Batch& batch, float x, float y, const QString& str, | 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 | const glm::vec2& bound); | 116 | const glm::vec2& bound); |
| 122 | 117 | ||
| 123 | private: | 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 | TextRenderer3D::EffectType effectType, const glm::vec2& bounds) { | 366 | TextRenderer3D::EffectType effectType, const glm::vec2& bounds) { |
| 372 | if (str == "") { | 367 | if (str == "") { |
| 373 | return; | 368 | return; |
| @@ -429,40 +424,33 @@ void Font3D::drawString(gpu::Batch& batch, float x, float y, const QString& str, · 55 unmodified lines | |||
| 429 | setupGPU(); | 424 | setupGPU(); |
| 430 | batch.setPipeline(_pipeline); | 425 | batch.setPipeline(_pipeline); |
| 431 | batch.setUniformTexture(_fontLoc, _texture); | 426 | batch.setUniformTexture(_fontLoc, _texture); |
| 432 | batch._glUniform1f(_outlineLoc, (effectType == TextRenderer3D::OUTLINE_EFFECT) ? 1.0f : 0.0f); | 427 | batch._glUniform1i(_outlineLoc, (effectType == TextRenderer3D::OUTLINE_EFFECT)); |
| 433 | batch._glUniform4fv(_colorLoc, 1, (const GLfloat*)&color); | 428 | batch._glUniform4fv(_colorLoc, 1, (const GLfloat*)color); |
| 434 | 429 | ||
| 435 | batch.setInputFormat(_format); | 430 | batch.setInputFormat(_format); |
| 436 | batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride); | 431 | batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride); |
| 437 | batch.draw(gpu::QUADS, _numVertices, 0); | 432 | batch.draw(gpu::QUADS, _numVertices, 0); |
| 438 | } | 433 | } |
| 439 | 434 | ||
| 440 | TextRenderer3D* TextRenderer3D::getInstance(const char* family, float pointSize, | 435 | TextRenderer3D* TextRenderer3D::getInstance(const char* family, |
| 441 | int weight, bool italic, EffectType effect, int effectThickness, | 436 | int weight, bool italic, EffectType effect, int effectThickness) { |
| 442 | const QColor& color) { | 437 | return new TextRenderer3D(family, weight, italic, effect, effectThickness); |
| 443 | if (pointSize < 0) { | ||
| 444 | pointSize = DEFAULT_POINT_SIZE; | ||
| 445 | } | ||
| 446 | return new TextRenderer3D(family, pointSize, weight, italic, effect, | ||
| 447 | effectThickness, color); | ||
| 448 | } | 438 | } |
| 449 | 439 | ||
| 450 | TextRenderer3D::TextRenderer3D(const char* family, float pointSize, int weight, bool italic, | 440 | TextRenderer3D::TextRenderer3D(const char* family, int weight, bool italic, |
| 451 | EffectType effect, int effectThickness, const QColor& color) : | 441 | EffectType effect, int effectThickness) : |
| 452 | _effectType(effect), | 442 | _effectType(effect), |
| 453 | _effectThickness(effectThickness), | 443 | _effectThickness(effectThickness), |
| 454 | _pointSize(pointSize), | ||
| 455 | _color(toGlm(color)), | ||
| 456 | _font(loadFont3D(family)) { | 444 | _font(loadFont3D(family)) { |
| 457 | if (!_font) { | 445 | if (!_font) { |
| 458 | qWarning() << "Unable to load font with family " << family; | 446 | qWarning() << "Unable to load font with family " << family; |
| 459 | _font = loadFont3D("Courier"); | 447 | _font = loadFont3D("Courier"); |
| 460 | } | 448 | } |
| 461 | if (1 != _effectThickness) { | 449 | if (1 != _effectThickness) { |
| 462 | qWarning() << "Effect thickness not current supported"; | 450 | qWarning() << "Effect thickness not currently supported"; |
| 463 | } | 451 | } |
| 464 | if (NO_EFFECT != _effectType && OUTLINE_EFFECT != _effectType) { | 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 | const glm::vec2& bounds) { | 475 | const glm::vec2& bounds) { |
| 488 | // The font does all the OpenGL work | 476 | // The font does all the OpenGL work |
| 489 | if (_font) { | 477 | if (_font) { |
| 490 | glm::vec4 actualColor(color); | 478 | // Cache color so that the pointer stays valid. |
| 491 | if (actualColor.r < 0) { | 479 | _color = color; |
| 492 | actualColor = _color; | 480 | _font->drawString(batch, x, y, str, &_color, _effectType, bounds); |
| 493 | } | ||
| 494 | _font->drawString(batch, x, y, str, actualColor, _effectType, bounds); | ||
| 495 | } | 481 | } |
| 496 | } | 482 | } |
| 497 | 483 | ||
| @@ -39,25 +39,24 @@ class Batch; · 38 unmodified lines | |||
| 39 | class Font3D; | 39 | class Font3D; |
| 40 | 40 | ||
| 41 | // TextRenderer3D is actually a fairly thin wrapper around a Font class | 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 | class TextRenderer3D { | 43 | class TextRenderer3D { |
| 44 | public: | 44 | public: |
| 45 | enum EffectType { NO_EFFECT, SHADOW_EFFECT, OUTLINE_EFFECT }; | 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, | 47 | static TextRenderer3D* getInstance(const char* family, int weight = -1, bool italic = false, |
| 48 | EffectType effect = NO_EFFECT, int effectThickness = 1, const QColor& color = QColor(255, 255, 255)); | 48 | EffectType effect = NO_EFFECT, int effectThickness = 1); |
| 49 | |||
| 50 | ~TextRenderer3D(); | 49 | ~TextRenderer3D(); |
| 51 | 50 | ||
| 52 | glm::vec2 computeExtent(const QString& str) const; | 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), | 54 | 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)); | 55 | const glm::vec2& bounds = glm::vec2(-1.0f)); |
| 57 | 56 | ||
| 58 | private: | 57 | private: |
| 59 | TextRenderer3D(const char* family, float pointSize = -1, int weight = -1, bool italic = false, | 58 | TextRenderer3D(const char* family, int weight = -1, bool italic = false, |
| 60 | EffectType effect = NO_EFFECT, int effectThickness = 1, const QColor& color = QColor(255, 255, 255)); | 59 | EffectType effect = NO_EFFECT, int effectThickness = 1); |
| 61 | 60 | ||
| 62 | // the type of effect to apply | 61 | // the type of effect to apply |
| 63 | const EffectType _effectType; | 62 | const EffectType _effectType; |
| @@ -65,10 +64,8 @@ private: · 1 unmodified line | |||
| 65 | // the thickness of the effect | 64 | // the thickness of the effect |
| 66 | const int _effectThickness; | 65 | const int _effectThickness; |
| 67 | 66 | ||
| 68 | const float _pointSize; | ||
| 69 | |||
| 70 | // text color | 67 | // text color |
| 71 | const glm::vec4 _color; | 68 | glm::vec4 _color; |
| 72 | 69 | ||
| 73 | Font3D* _font; | 70 | Font3D* _font; |
| 74 | }; | 71 | }; |
| @@ -11,18 +11,21 @@ · 10 unmodified lines | |||
| 11 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | 11 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html |
| 12 | 12 | ||
| 13 | uniform sampler2D Font; | 13 | uniform sampler2D Font; |
| 14 | uniform float Outline; | 14 | uniform bool Outline; |
| 15 | uniform vec4 Color; | 15 | uniform vec4 Color; |
| 16 | 16 | ||
| 17 | const float gamma = 2.6; | 17 | // the interpolated normal |
| 18 | const float smoothing = 100.0; | 18 | varying vec4 interpolatedNormal; |
| 19 | |||
| 20 | const float gamma = 2.2; | ||
| 21 | const float smoothing = 64.0; | ||
| 19 | const float interiorCutoff = 0.8; | 22 | const float interiorCutoff = 0.8; |
| 20 | const float outlineExpansion = 0.2; | 23 | const float outlineExpansion = 0.2; |
| 21 | 24 | ||
| 22 | void main() { | 25 | void main() { |
| 23 | // retrieve signed distance | 26 | // retrieve signed distance |
| 24 | float sdf = texture2D(Font, gl_TexCoord[0].xy).g; | 27 | float sdf = texture2D(Font, gl_TexCoord[0].xy).g; |
| 25 | if (Outline == 1.0f) { | 28 | if (Outline) { |
| 26 | if (sdf > interiorCutoff) { | 29 | if (sdf > interiorCutoff) { |
| 27 | sdf = 1.0 - sdf; | 30 | sdf = 1.0 - sdf; |
| 28 | } else { | 31 | } else { |
| @@ -31,7 +34,7 @@ void main() { · 2 unmodified lines | |||
| 31 | } | 34 | } |
| 32 | // perform adaptive anti-aliasing of the edges | 35 | // perform adaptive anti-aliasing of the edges |
| 33 | // The larger we're rendering, the less anti-aliasing we need | 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 | float w = clamp( s, 0.0, 0.5); | 38 | float w = clamp( s, 0.0, 0.5); |
| 36 | float a = smoothstep(0.5 - w, 0.5 + w, sdf); | 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 | // final color | 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 | <$declareStandardTransform()$> | 14 | <$declareStandardTransform()$> |
| 15 | 15 | ||
| 16 | // the interpolated normal | ||
| 17 | varying vec4 interpolatedNormal; | ||
| 18 | |||
| 16 | void main() { | 19 | void main() { |
| 17 | gl_TexCoord[0] = gl_MultiTexCoord0; | 20 | gl_TexCoord[0] = gl_MultiTexCoord0; |
| 18 | 21 | ||
| @@ -20,4 +23,7 @@ void main() { · 1 unmodified line | |||
| 20 | TransformCamera cam = getTransformCamera(); | 23 | TransformCamera cam = getTransformCamera(); |
| 21 | TransformObject obj = getTransformObject(); | 24 | TransformObject obj = getTransformObject(); |
| 22 | <$transformModelToClipPos(cam, obj, gl_Vertex, gl_Position)$> | 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 | using namespace render; | 25 | using namespace render; |
| 26 | 26 | ||
| 27 | DrawSceneTask::DrawSceneTask() : Task() { | 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 | DrawSceneTask::~DrawSceneTask() { | 30 | DrawSceneTask::~DrawSceneTask() { |
| @@ -56,8 +51,11 @@ void DrawSceneTask::run(const SceneContextPointer& sceneContext, const RenderCon · 20 unmodified lines | |||
| 56 | Job::~Job() { | 51 | Job::~Job() { |
| 57 | } | 52 | } |
| 58 | 53 | ||
| 54 | |||
| 55 | |||
| 56 | |||
| 57 | |||
| 59 | void render::cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { | 58 | void render::cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { |
| 60 | PerformanceTimer perfTimer("cullItems"); | ||
| 61 | assert(renderContext->args); | 59 | assert(renderContext->args); |
| 62 | assert(renderContext->args->_viewFrustum); | 60 | assert(renderContext->args->_viewFrustum); |
| 63 | 61 | ||
| @@ -68,17 +66,9 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont · 4 unmodified lines | |||
| 68 | renderDetails->_considered += inItems.size(); | 66 | renderDetails->_considered += inItems.size(); |
| 69 | 67 | ||
| 70 | // Culling / LOD | 68 | // Culling / LOD |
| 71 | for (auto itemDetails : inItems) { | 69 | for (auto item : inItems) { |
| 72 | auto item = scene->getItem(itemDetails.id); | 70 | if (item.bounds.isNull()) { |
| 73 | AABox bound; | 71 | outItems.emplace_back(item); // One more Item to render |
| 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 | ||
| 82 | continue; | 72 | continue; |
| 83 | } | 73 | } |
| 84 | 74 | ||
| @@ -87,16 +77,16 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont · 2 unmodified lines | |||
| 87 | bool outOfView; | 77 | bool outOfView; |
| 88 | { | 78 | { |
| 89 | PerformanceTimer perfTimer("boxInFrustum"); | 79 | PerformanceTimer perfTimer("boxInFrustum"); |
| 90 | outOfView = args->_viewFrustum->boxInFrustum(bound) == ViewFrustum::OUTSIDE; | 80 | outOfView = args->_viewFrustum->boxInFrustum(item.bounds) == ViewFrustum::OUTSIDE; |
| 91 | } | 81 | } |
| 92 | if (!outOfView) { | 82 | if (!outOfView) { |
| 93 | bool bigEnoughToRender; | 83 | bool bigEnoughToRender; |
| 94 | { | 84 | { |
| 95 | PerformanceTimer perfTimer("shouldRender"); | 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 | if (bigEnoughToRender) { | 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 | } else { | 90 | } else { |
| 101 | renderDetails->_tooSmall++; | 91 | renderDetails->_tooSmall++; |
| 102 | } | 92 | } |
| @@ -107,6 +97,32 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont · 4 unmodified lines | |||
| 107 | renderDetails->_rendered += outItems.size(); | 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 | struct ItemBound { | 126 | struct ItemBound { |
| 111 | float _centerDepth = 0.0f; | 127 | float _centerDepth = 0.0f; |
| 112 | float _nearDepth = 0.0f; | 128 | float _nearDepth = 0.0f; |
| @@ -130,7 +146,6 @@ struct BackToFrontSort { · 17 unmodified lines | |||
| 130 | }; | 146 | }; |
| 131 | 147 | ||
| 132 | void render::depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { | 148 | void render::depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { |
| 133 | PerformanceTimer perfTimer("depthSortItems"); | ||
| 134 | assert(renderContext->args); | 149 | assert(renderContext->args); |
| 135 | assert(renderContext->args->_viewFrustum); | 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 | // Allocate and simply copy | 156 | // Allocate and simply copy |
| 157 | outItems.clear(); | ||
| 142 | outItems.reserve(inItems.size()); | 158 | outItems.reserve(inItems.size()); |
| 143 | 159 | ||
| 144 | 160 | ||
| 145 | // Make a local dataset of the center distance and closest point distance | 161 | // Make a local dataset of the center distance and closest point distance |
| 146 | std::vector<ItemBound> itemBounds; | 162 | std::vector<ItemBound> itemBounds; |
| 147 | itemBounds.reserve(outItems.size()); | 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 | void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems) { | 195 | void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems) { |
| 173 | PerformanceTimer perfTimer("renderItems"); | ||
| 174 | auto& scene = sceneContext->_scene; | 196 | auto& scene = sceneContext->_scene; |
| 175 | RenderArgs* args = renderContext->args; | 197 | RenderArgs* args = renderContext->args; |
| 176 | // render | 198 | // render |
| @@ -183,6 +205,10 @@ void render::renderItems(const SceneContextPointer& sceneContext, const RenderCo · 6 unmodified lines | |||
| 183 | int numItems = 0; | 205 | int numItems = 0; |
| 184 | for (auto itemDetails : inItems) { | 206 | for (auto itemDetails : inItems) { |
| 185 | auto item = scene->getItem(itemDetails.id); | 207 | auto item = scene->getItem(itemDetails.id); |
| 208 | if (numItems + 1 >= maxDrawnItems) { | ||
| 209 | item.render(args); | ||
| 210 | return; | ||
| 211 | } | ||
| 186 | item.render(args); | 212 | item.render(args); |
| 187 | numItems++; | 213 | numItems++; |
| 188 | if (numItems >= maxDrawnItems) { | 214 | if (numItems >= maxDrawnItems) { |
| @@ -224,8 +250,7 @@ void addClearStateCommands(gpu::Batch& batch) { · 35 unmodified lines | |||
| 224 | // Back to no program | 250 | // Back to no program |
| 225 | batch._glUseProgram(0); | 251 | batch._glUseProgram(0); |
| 226 | } | 252 | } |
| 227 | 253 | void ResetGLState::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | |
| 228 | template <> void render::jobRun(const ResetGLState& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | ||
| 229 | 254 | ||
| 230 | gpu::Batch theBatch; | 255 | gpu::Batch theBatch; |
| 231 | addClearStateCommands(theBatch); | 256 | addClearStateCommands(theBatch); |
| @@ -233,160 +258,7 @@ template <> void render::jobRun(const ResetGLState& job, const SceneContextPoint · 1 unmodified line | |||
| 233 | renderContext->args->_context->render(theBatch); | 258 | renderContext->args->_context->render(theBatch); |
| 234 | } | 259 | } |
| 235 | 260 | ||
| 236 | template <> void render::jobRun(const DrawOpaque& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | 261 | void DrawLight::run(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"); | ||
| 390 | assert(renderContext->args); | 262 | assert(renderContext->args); |
| 391 | assert(renderContext->args->_viewFrustum); | 263 | assert(renderContext->args->_viewFrustum); |
| 392 | 264 | ||
| @@ -398,7 +270,8 @@ template <> void render::jobRun(const DrawLight& job, const SceneContextPointer& · 5 unmodified lines | |||
| 398 | ItemIDsBounds inItems; | 270 | ItemIDsBounds inItems; |
| 399 | inItems.reserve(items.size()); | 271 | inItems.reserve(items.size()); |
| 400 | for (auto id : items) { | 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 | ItemIDsBounds culledItems; | 277 | ItemIDsBounds culledItems; |
| @@ -413,8 +286,7 @@ template <> void render::jobRun(const DrawLight& job, const SceneContextPointer& · 8 unmodified lines | |||
| 413 | args->_batch = nullptr; | 286 | args->_batch = nullptr; |
| 414 | } | 287 | } |
| 415 | 288 | ||
| 416 | template <> void render::jobRun(const DrawBackground& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | 289 | void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { |
| 417 | PerformanceTimer perfTimer("DrawBackground"); | ||
| 418 | assert(renderContext->args); | 290 | assert(renderContext->args); |
| 419 | assert(renderContext->args->_viewFrustum); | 291 | assert(renderContext->args->_viewFrustum); |
| 420 | 292 | ||
| @@ -450,53 +322,6 @@ template <> void render::jobRun(const DrawBackground& job, const SceneContextPoi · 29 unmodified lines | |||
| 450 | args->_context->syncCache(); | 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 | void ItemMaterialBucketMap::insert(const ItemID& id, const model::MaterialKey& key) { | 325 | void ItemMaterialBucketMap::insert(const ItemID& id, const model::MaterialKey& key) { |
| 501 | // Insert the itemID in every bucket where it filters true | 326 | // Insert the itemID in every bucket where it filters true |
| 502 | for (auto& bucket : (*this)) { | 327 | for (auto& bucket : (*this)) { |
| @@ -13,42 +13,173 @@ · 12 unmodified lines | |||
| 13 | #define hifi_render_Task_h | 13 | #define hifi_render_Task_h |
| 14 | 14 | ||
| 15 | #include "Engine.h" | 15 | #include "Engine.h" |
| 16 | #include "gpu/Batch.h" | ||
| 17 | #include <PerfStat.h> | ||
| 18 | |||
| 16 | 19 | ||
| 17 | namespace render { | 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 | class Job { | 35 | class Job { |
| 22 | public: | 36 | public: |
| 23 | 37 | ||
| 24 | template <class T> | 38 | // Varying represent a varying piece of data |
| 25 | Job(T data) : _concept(new Model<T>(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 | Job(const Job& other) : _concept(other._concept) {} | 77 | Job(const Job& other) : _concept(other._concept) {} |
| 27 | ~Job(); | 78 | ~Job(); |
| 28 | 79 | ||
| 29 | virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { | 80 | const std::string& getName() const { return _concept->getName(); } |
| 30 | if (_concept) { | 81 | const Varying getInput() const { return _concept->getInput(); } |
| 31 | _concept->run(sceneContext, renderContext); | 82 | const Varying getOutput() const { return _concept->getOutput(); } |
| 32 | } | 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 | protected: | 90 | protected: |
| 91 | public: | ||
| 92 | |||
| 36 | class Concept { | 93 | class Concept { |
| 94 | std::string _name; | ||
| 37 | public: | 95 | public: |
| 96 | Concept() : _name() {} | ||
| 97 | Concept(const std::string& name) : _name(name) {} | ||
| 38 | virtual ~Concept() = default; | 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 | virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) = 0; | 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 | template <class T> class Model : public Concept { | 111 | template <class T> class Model : public Concept { |
| 43 | public: | 112 | public: |
| 44 | typedef T Data; | 113 | typedef T Data; |
| 45 | 114 | ||
| 46 | Data _data; | 115 | Data _data; |
| 116 | |||
| 117 | Model() {} | ||
| 118 | Model(const std::string& name): Concept(name) {} | ||
| 47 | Model(Data data): _data(data) {} | 119 | Model(Data data): _data(data) {} |
| 120 | Model(Data data, const std::string& name): Concept(name), _data(data) {} | ||
| 48 | 121 | ||
| 49 | void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { jobRun(_data, sceneContext, renderContext); } | 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 | std::shared_ptr<Concept> _concept; | 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 | void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); | 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 { | 207 | typedef Job::ModelO<FetchItems, ItemIDsBounds> JobModel; |
| 70 | public: | ||
| 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 | public: | 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 | class DrawLight { | 228 | class DrawLight { |
| 81 | public: | 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 | class DrawBackground { | 235 | class DrawBackground { |
| 86 | public: | 236 | public: |
| 87 | }; | 237 | void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); |
| 88 | template <> void jobRun(const DrawBackground& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); | ||
| 89 | |||
| 90 | 238 | ||
| 91 | class DrawPostLayered { | 239 | typedef Job::Model<DrawBackground> JobModel; |
| 92 | public: | ||
| 93 | }; | 240 | }; |
| 94 | template <> void jobRun(const DrawPostLayered& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); | ||
| 95 | |||
| 96 | |||
| 97 | 241 | ||
| 98 | class ResetGLState { | 242 | class ResetGLState { |
| 99 | public: | 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 | class DrawSceneTask : public Task { | 251 | class DrawSceneTask : public Task { |
| @@ -126,6 +273,7 @@ public: · 21 unmodified lines | |||
| 126 | // standard builders allocating the main buckets | 273 | // standard builders allocating the main buckets |
| 127 | void allocateStandardMaterialBuckets(); | 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 | int _numDrawnTransparentItems = 0; | 45 | int _numDrawnTransparentItems = 0; |
| 46 | int _maxDrawnTransparentItems = -1; | 46 | int _maxDrawnTransparentItems = -1; |
| 47 | 47 | ||
| 48 | int _numFeedOverlay3DItems = 0; | ||
| 49 | int _numDrawnOverlay3DItems = 0; | ||
| 50 | int _maxDrawnOverlay3DItems = -1; | ||
| 51 | |||
| 48 | RenderContext() {} | 52 | RenderContext() {} |
| 49 | }; | 53 | }; |
| 50 | typedef std::shared_ptr<RenderContext> RenderContextPointer; | 54 | typedef std::shared_ptr<RenderContext> RenderContextPointer; |
| @@ -107,6 +107,7 @@ signals: · 106 unmodified lines | |||
| 107 | 107 | ||
| 108 | void mouseMoveEvent(const MouseEvent& event, unsigned int deviceID = 0); | 108 | void mouseMoveEvent(const MouseEvent& event, unsigned int deviceID = 0); |
| 109 | void mousePressEvent(const MouseEvent& event, unsigned int deviceID = 0); | 109 | void mousePressEvent(const MouseEvent& event, unsigned int deviceID = 0); |
| 110 | void mouseDoublePressEvent(const MouseEvent& event, unsigned int deviceID = 0); | ||
| 110 | void mouseReleaseEvent(const MouseEvent& event, unsigned int deviceID = 0); | 111 | void mouseReleaseEvent(const MouseEvent& event, unsigned int deviceID = 0); |
| 111 | 112 | ||
| 112 | void touchBeginEvent(const TouchEvent& event); | 113 | void touchBeginEvent(const TouchEvent& event); |
| @@ -46,24 +46,7 @@ ScriptAudioInjector* AudioScriptingInterface::playSound(Sound* sound, const Audi · 45 unmodified lines | |||
| 46 | AudioInjectorOptions optionsCopy = injectorOptions; | 46 | AudioInjectorOptions optionsCopy = injectorOptions; |
| 47 | optionsCopy.stereo = sound->isStereo(); | 47 | optionsCopy.stereo = sound->isStereo(); |
| 48 | 48 | ||
| 49 | QThread* injectorThread = new QThread(); | 49 | return new ScriptAudioInjector(AudioInjector::playSound(sound->getByteArray(), optionsCopy, _localAudioInterface)); |
| 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); | ||
| 67 | 50 | ||
| 68 | } else { | 51 | } else { |
| 69 | qCDebug(scriptengine) << "AudioScriptingInterface::playSound called with null Sound object."; | 52 | qCDebug(scriptengine) << "AudioScriptingInterface::playSound called with null Sound object."; |
| @@ -159,4 +159,6 @@ void SceneScriptingInterface::clearEngineCounters() { · 158 unmodified lines | |||
| 159 | _numDrawnOpaqueItems = 0; | 159 | _numDrawnOpaqueItems = 0; |
| 160 | _numFeedTransparentItems = 0; | 160 | _numFeedTransparentItems = 0; |
| 161 | _numDrawnTransparentItems = 0; | 161 | _numDrawnTransparentItems = 0; |
| 162 | _numFeedOverlay3DItems = 0; | ||
| 163 | _numDrawnOverlay3DItems = 0; | ||
| 162 | } | 164 | } |
| @@ -90,17 +90,22 @@ public: · 89 unmodified lines | |||
| 90 | Q_INVOKABLE int getEngineNumDrawnOpaqueItems() { return _numDrawnOpaqueItems; } | 90 | Q_INVOKABLE int getEngineNumDrawnOpaqueItems() { return _numDrawnOpaqueItems; } |
| 91 | void setEngineDrawnTransparentItems(int count) { _numDrawnTransparentItems = count; } | 91 | void setEngineDrawnTransparentItems(int count) { _numDrawnTransparentItems = count; } |
| 92 | Q_INVOKABLE int getEngineNumDrawnTransparentItems() { return _numDrawnTransparentItems; } | 92 | Q_INVOKABLE int getEngineNumDrawnTransparentItems() { return _numDrawnTransparentItems; } |
| 93 | void setEngineDrawnOverlay3DItems(int count) { _numDrawnOverlay3DItems = count; } | ||
| 94 | Q_INVOKABLE int getEngineNumDrawnOverlay3DItems() { return _numDrawnOverlay3DItems; } | ||
| 93 | 95 | ||
| 94 | void setEngineFeedOpaqueItems(int count) { _numFeedOpaqueItems = count; } | 96 | void setEngineFeedOpaqueItems(int count) { _numFeedOpaqueItems = count; } |
| 95 | Q_INVOKABLE int getEngineNumFeedOpaqueItems() { return _numFeedOpaqueItems; } | 97 | Q_INVOKABLE int getEngineNumFeedOpaqueItems() { return _numFeedOpaqueItems; } |
| 96 | void setEngineFeedTransparentItems(int count) { _numFeedTransparentItems = count; } | 98 | void setEngineFeedTransparentItems(int count) { _numFeedTransparentItems = count; } |
| 97 | Q_INVOKABLE int getEngineNumFeedTransparentItems() { return _numFeedTransparentItems; } | 99 | Q_INVOKABLE int getEngineNumFeedTransparentItems() { return _numFeedTransparentItems; } |
| 100 | void setEngineFeedOverlay3DItems(int count) { _numFeedOverlay3DItems = count; } | ||
| 101 | Q_INVOKABLE int getEngineNumFeedOverlay3DItems() { return _numFeedOverlay3DItems; } | ||
| 98 | 102 | ||
| 99 | Q_INVOKABLE void setEngineMaxDrawnOpaqueItems(int count) { _maxDrawnOpaqueItems = count; } | 103 | Q_INVOKABLE void setEngineMaxDrawnOpaqueItems(int count) { _maxDrawnOpaqueItems = count; } |
| 100 | Q_INVOKABLE int getEngineMaxDrawnOpaqueItems() { return _maxDrawnOpaqueItems; } | 104 | Q_INVOKABLE int getEngineMaxDrawnOpaqueItems() { return _maxDrawnOpaqueItems; } |
| 101 | Q_INVOKABLE void setEngineMaxDrawnTransparentItems(int count) { _maxDrawnTransparentItems = count; } | 105 | Q_INVOKABLE void setEngineMaxDrawnTransparentItems(int count) { _maxDrawnTransparentItems = count; } |
| 102 | Q_INVOKABLE int getEngineMaxDrawnTransparentItems() { return _maxDrawnTransparentItems; } | 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 | signals: | 109 | signals: |
| 105 | void shouldRenderAvatarsChanged(bool shouldRenderAvatars); | 110 | void shouldRenderAvatarsChanged(bool shouldRenderAvatars); |
| 106 | void shouldRenderEntitiesChanged(bool shouldRenderEntities); | 111 | void shouldRenderEntitiesChanged(bool shouldRenderEntities); |
| @@ -124,9 +129,12 @@ protected: · 17 unmodified lines | |||
| 124 | int _numDrawnOpaqueItems = 0; | 129 | int _numDrawnOpaqueItems = 0; |
| 125 | int _numFeedTransparentItems = 0; | 130 | int _numFeedTransparentItems = 0; |
| 126 | int _numDrawnTransparentItems = 0; | 131 | int _numDrawnTransparentItems = 0; |
| 132 | int _numFeedOverlay3DItems = 0; | ||
| 133 | int _numDrawnOverlay3DItems = 0; | ||
| 127 | 134 | ||
| 128 | int _maxDrawnOpaqueItems = -1; | 135 | int _maxDrawnOpaqueItems = -1; |
| 129 | int _maxDrawnTransparentItems = -1; | 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 | registerAnimationTypes(this); | 317 | registerAnimationTypes(this); |
| 318 | registerAvatarTypes(this); | 318 | registerAvatarTypes(this); |
| 319 | registerAudioMetaTypes(this); | 319 | registerAudioMetaTypes(this); |
| 320 | _controllerScriptingInterface->registerControllerTypes(this); | 320 | |
| 321 | if (_controllerScriptingInterface) { | ||
| 322 | _controllerScriptingInterface->registerControllerTypes(this); | ||
| 323 | } | ||
| 321 | 324 | ||
| 322 | qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly); | 325 | qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly); |
| 323 | qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue); | 326 | qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue); |
| @@ -35,7 +35,7 @@ · 34 unmodified lines | |||
| 35 | 35 | ||
| 36 | const QString NO_SCRIPT(""); | 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 | typedef QHash<QString, QScriptValueList> RegisteredEventHandlers; | 40 | typedef QHash<QString, QScriptValueList> RegisteredEventHandlers; |
| 41 | 41 | ||
| @@ -40,7 +40,7 @@ TouchEvent::TouchEvent() : · 39 unmodified lines | |||
| 40 | isRotating(false), | 40 | isRotating(false), |
| 41 | rotating("none") | 41 | rotating("none") |
| 42 | { | 42 | { |
| 43 | 43 | ||
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | TouchEvent::TouchEvent(const QTouchEvent& event) : | 46 | TouchEvent::TouchEvent(const QTouchEvent& event) : |
| @@ -77,9 +77,9 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) { · 30 unmodified lines | |||
| 77 | touchPoints = tPoints.count(); | 77 | touchPoints = tPoints.count(); |
| 78 | if (touchPoints > 1) { | 78 | if (touchPoints > 1) { |
| 79 | for (int i = 0; i < touchPoints; ++i) { | 79 | for (int i = 0; i < touchPoints; ++i) { |
| 80 | touchAvgX += tPoints[i].pos().x(); | 80 | touchAvgX += (float)tPoints[i].pos().x(); |
| 81 | touchAvgY += tPoints[i].pos().y(); | 81 | touchAvgY += (float)tPoints[i].pos().y(); |
| 82 | 82 | ||
| 83 | // add it to our points vector | 83 | // add it to our points vector |
| 84 | glm::vec2 thisPoint(tPoints[i].pos().x(), tPoints[i].pos().y()); | 84 | glm::vec2 thisPoint(tPoints[i].pos().x(), tPoints[i].pos().y()); |
| 85 | points << thisPoint; | 85 | points << thisPoint; |
| @@ -94,7 +94,7 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) { · 8 unmodified lines | |||
| 94 | } | 94 | } |
| 95 | x = touchAvgX; | 95 | x = touchAvgX; |
| 96 | y = touchAvgY; | 96 | y = touchAvgY; |
| 97 | 97 | ||
| 98 | // after calculating the center point (average touch point), determine the maximum radius | 98 | // after calculating the center point (average touch point), determine the maximum radius |
| 99 | // also calculate the rotation angle for each point | 99 | // also calculate the rotation angle for each point |
| 100 | float maxRadius = 0.0f; | 100 | float maxRadius = 0.0f; |
| @@ -105,25 +105,25 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) { · 4 unmodified lines | |||
| 105 | if (thisRadius > maxRadius) { | 105 | if (thisRadius > maxRadius) { |
| 106 | maxRadius = thisRadius; | 106 | maxRadius = thisRadius; |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | // calculate the angle for this point | 109 | // calculate the angle for this point |
| 110 | float thisAngle = angleBetweenPoints(center,touchPoint); | 110 | float thisAngle = angleBetweenPoints(center,touchPoint); |
| 111 | angles << thisAngle; | 111 | angles << thisAngle; |
| 112 | } | 112 | } |
| 113 | radius = maxRadius; | 113 | radius = maxRadius; |
| 114 | 114 | ||
| 115 | // after calculating the angles for each touch point, determine the average angle | 115 | // after calculating the angles for each touch point, determine the average angle |
| 116 | float totalAngle = 0.0f; | 116 | float totalAngle = 0.0f; |
| 117 | for (int i = 0; i < touchPoints; ++i) { | 117 | for (int i = 0; i < touchPoints; ++i) { |
| 118 | totalAngle += angles[i]; | 118 | totalAngle += angles[i]; |
| 119 | } | 119 | } |
| 120 | angle = totalAngle/(float)touchPoints; | 120 | angle = totalAngle/(float)touchPoints; |
| 121 | 121 | ||
| 122 | isPressed = event.touchPointStates().testFlag(Qt::TouchPointPressed); | 122 | isPressed = event.touchPointStates().testFlag(Qt::TouchPointPressed); |
| 123 | isMoved = event.touchPointStates().testFlag(Qt::TouchPointMoved); | 123 | isMoved = event.touchPointStates().testFlag(Qt::TouchPointMoved); |
| 124 | isStationary = event.touchPointStates().testFlag(Qt::TouchPointStationary); | 124 | isStationary = event.touchPointStates().testFlag(Qt::TouchPointStationary); |
| 125 | isReleased = event.touchPointStates().testFlag(Qt::TouchPointReleased); | 125 | isReleased = event.touchPointStates().testFlag(Qt::TouchPointReleased); |
| 126 | 126 | ||
| 127 | // keyboard modifiers | 127 | // keyboard modifiers |
| 128 | isShifted = event.modifiers().testFlag(Qt::ShiftModifier); | 128 | isShifted = event.modifiers().testFlag(Qt::ShiftModifier); |
| 129 | isMeta = event.modifiers().testFlag(Qt::MetaModifier); | 129 | isMeta = event.modifiers().testFlag(Qt::MetaModifier); |
| @@ -143,7 +143,7 @@ void TouchEvent::calculateMetaAttributes(const TouchEvent& other) { · 13 unmodified lines | |||
| 143 | isPinching = other.isPinching; | 143 | isPinching = other.isPinching; |
| 144 | isPinchOpening = other.isPinchOpening; | 144 | isPinchOpening = other.isPinchOpening; |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | // determine if the points are rotating... | 147 | // determine if the points are rotating... |
| 148 | // note: if the number of touch points change between events, then we don't consider ourselves to be rotating | 148 | // note: if the number of touch points change between events, then we don't consider ourselves to be rotating |
| 149 | if (touchPoints == other.touchPoints) { | 149 | if (touchPoints == other.touchPoints) { |
| @@ -178,7 +178,7 @@ QScriptValue TouchEvent::toScriptValue(QScriptEngine* engine, const TouchEvent& · 28 unmodified lines | |||
| 178 | obj.setProperty("isControl", event.isControl); | 178 | obj.setProperty("isControl", event.isControl); |
| 179 | obj.setProperty("isAlt", event.isAlt); | 179 | obj.setProperty("isAlt", event.isAlt); |
| 180 | obj.setProperty("touchPoints", event.touchPoints); | 180 | obj.setProperty("touchPoints", event.touchPoints); |
| 181 | 181 | ||
| 182 | QScriptValue pointsObj = engine->newArray(); | 182 | QScriptValue pointsObj = engine->newArray(); |
| 183 | int index = 0; | 183 | int index = 0; |
| 184 | foreach (glm::vec2 point, event.points) { | 184 | foreach (glm::vec2 point, event.points) { |
| @@ -190,7 +190,7 @@ QScriptValue TouchEvent::toScriptValue(QScriptEngine* engine, const TouchEvent& · 5 unmodified lines | |||
| 190 | obj.setProperty("radius", event.radius); | 190 | obj.setProperty("radius", event.radius); |
| 191 | obj.setProperty("isPinching", event.isPinching); | 191 | obj.setProperty("isPinching", event.isPinching); |
| 192 | obj.setProperty("isPinchOpening", event.isPinchOpening); | 192 | obj.setProperty("isPinchOpening", event.isPinchOpening); |
| 193 | 193 | ||
| 194 | obj.setProperty("angle", event.angle); | 194 | obj.setProperty("angle", event.angle); |
| 195 | obj.setProperty("deltaAngle", event.deltaAngle); | 195 | obj.setProperty("deltaAngle", event.deltaAngle); |
| 196 | QScriptValue anglesObj = engine->newArray(); | 196 | QScriptValue anglesObj = engine->newArray(); |
| @@ -200,7 +200,7 @@ QScriptValue TouchEvent::toScriptValue(QScriptEngine* engine, const TouchEvent& · 3 unmodified lines | |||
| 200 | index++; | 200 | index++; |
| 201 | } | 201 | } |
| 202 | obj.setProperty("angles", anglesObj); | 202 | obj.setProperty("angles", anglesObj); |
| 203 | 203 | ||
| 204 | obj.setProperty("isRotating", event.isRotating); | 204 | obj.setProperty("isRotating", event.isRotating); |
| 205 | obj.setProperty("rotating", event.rotating); | 205 | obj.setProperty("rotating", event.rotating); |
| 206 | return obj; | 206 | return obj; |
| @@ -6,4 +6,5 @@ setup_hifi_library(Gui Network Script Widgets) · 5 unmodified lines | |||
| 6 | 6 | ||
| 7 | add_dependency_external_projects(glm) | 7 | add_dependency_external_projects(glm) |
| 8 | find_package(GLM REQUIRED) | 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 | #include "GeometryUtil.h" | 16 | #include "GeometryUtil.h" |
| 17 | #include "NumericalConstants.h" | 17 | #include "NumericalConstants.h" |
| 18 | 18 | ||
| 19 | AABox::AABox(const AACube& other) : | 19 | AABox::AABox(const AACube& other) : |
| 20 | _corner(other.getCorner()), _scale(other.getScale(), other.getScale(), other.getScale()) { | 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 | _corner(other.minimum), | 24 | _corner(other.minimum), |
| 25 | _scale(other.maximum - other.minimum) { | 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 | _corner(corner), _scale(size, size, size) { | 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 | _corner(corner), _scale(dimensions) { | 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 | glm::vec3 AABox::calcCenter() const { | 39 | glm::vec3 AABox::calcCenter() const { |
| 40 | glm::vec3 center(_corner); | 40 | glm::vec3 center(_corner); |
| 41 | center += (_scale * 0.5f); | 41 | center += (_scale * 0.5f); |
| 42 | return center; | 42 | return center; |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | void AABox::scale(float scale) { | 45 | void AABox::scale(float scale) { |
| @@ -134,12 +134,12 @@ bool AABox::contains(const AABox& otherBox) const { · 88 unmodified lines | |||
| 134 | 134 | ||
| 135 | bool AABox::touches(const AABox& otherBox) const { | 135 | bool AABox::touches(const AABox& otherBox) const { |
| 136 | glm::vec3 relativeCenter = _corner - otherBox._corner + ((_scale - otherBox._scale) * 0.5f); | 136 | glm::vec3 relativeCenter = _corner - otherBox._corner + ((_scale - otherBox._scale) * 0.5f); |
| 137 | 137 | ||
| 138 | glm::vec3 totalHalfScale = (_scale + otherBox._scale) * 0.5f; | 138 | glm::vec3 totalHalfScale = (_scale + otherBox._scale) * 0.5f; |
| 139 | 139 | ||
| 140 | return fabs(relativeCenter.x) <= totalHalfScale.x && | 140 | return fabsf(relativeCenter.x) <= totalHalfScale.x && |
| 141 | fabs(relativeCenter.y) <= totalHalfScale.y && | 141 | fabsf(relativeCenter.y) <= totalHalfScale.y && |
| 142 | fabs(relativeCenter.z) <= totalHalfScale.z; | 142 | fabsf(relativeCenter.z) <= totalHalfScale.z; |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | bool AABox::contains(const AACube& otherCube) const { | 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 | bool AABox::touches(const AACube& otherCube) const { | 155 | bool AABox::touches(const AACube& otherCube) const { |
| 156 | glm::vec3 relativeCenter = _corner - otherCube.getCorner() + ((_scale - otherCube.getDimensions()) * 0.5f); | 156 | glm::vec3 relativeCenter = _corner - otherCube.getCorner() + ((_scale - otherCube.getDimensions()) * 0.5f); |
| 157 | 157 | ||
| 158 | glm::vec3 totalHalfScale = (_scale + otherCube.getDimensions()) * 0.5f; | 158 | glm::vec3 totalHalfScale = (_scale + otherCube.getDimensions()) * 0.5f; |
| 159 | 159 | ||
| 160 | return fabs(relativeCenter.x) <= totalHalfScale.x && | 160 | return fabsf(relativeCenter.x) <= totalHalfScale.x && |
| 161 | fabs(relativeCenter.y) <= totalHalfScale.y && | 161 | fabsf(relativeCenter.y) <= totalHalfScale.y && |
| 162 | fabs(relativeCenter.z) <= totalHalfScale.z; | 162 | fabsf(relativeCenter.z) <= totalHalfScale.z; |
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | // determines whether a value is within the expanded extents | 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 | isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale.y) && | 244 | isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale.y) && |
| 245 | isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x))) { | 245 | isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x))) { |
| 246 | distance = axisDistance; | 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 | return true; | 248 | return true; |
| 249 | } | 249 | } |
| 250 | // This case is unexpected, but mimics the previous behavior for inside out intersections | 250 | // This case is unexpected, but mimics the previous behavior for inside out intersections |
| 251 | distance = 0; | 251 | distance = 0; |
| 252 | return true; | 252 | return true; |
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | // check each axis | 255 | // check each axis |
| 256 | float axisDistance; | 256 | float axisDistance; |
| 257 | if ((findIntersection(origin.x, direction.x, _corner.x, _scale.x, axisDistance) && axisDistance >= 0 && | 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 | isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale.y) && | 272 | isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale.y) && |
| 273 | isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x))) { | 273 | isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x))) { |
| 274 | distance = axisDistance; | 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 | return true; | 276 | return true; |
| 277 | } | 277 | } |
| 278 | return false; | 278 | return false; |
| @@ -280,7 +280,7 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct · 1 unmodified line | |||
| 280 | 280 | ||
| 281 | bool AABox::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const { | 281 | bool AABox::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const { |
| 282 | glm::vec4 center4 = glm::vec4(center, 1.0f); | 282 | glm::vec4 center4 = glm::vec4(center, 1.0f); |
| 283 | 283 | ||
| 284 | float minPenetrationLength = FLT_MAX; | 284 | float minPenetrationLength = FLT_MAX; |
| 285 | for (int i = 0; i < FACE_COUNT; i++) { | 285 | for (int i = 0; i < FACE_COUNT; i++) { |
| 286 | glm::vec4 facePlane = getPlane((BoxFace)i); | 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 | minPenetrationLength = vectorLength; | 297 | minPenetrationLength = vectorLength; |
| 298 | } | 298 | } |
| 299 | } | 299 | } |
| 300 | 300 | ||
| 301 | return true; | 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 | glm::vec4 start4 = glm::vec4(start, 1.0f); | 305 | glm::vec4 start4 = glm::vec4(start, 1.0f); |
| 306 | glm::vec4 end4 = glm::vec4(end, 1.0f); | 306 | glm::vec4 end4 = glm::vec4(end, 1.0f); |
| 307 | glm::vec4 startToEnd = glm::vec4(end - start, 0.0f); | 307 | glm::vec4 startToEnd = glm::vec4(end - start, 0.0f); |
| 308 | 308 | ||
| 309 | float minPenetrationLength = FLT_MAX; | 309 | float minPenetrationLength = FLT_MAX; |
| 310 | for (int i = 0; i < FACE_COUNT; i++) { | 310 | for (int i = 0; i < FACE_COUNT; i++) { |
| 311 | // find the vector from the segment to the closest point on the face (starting from deeper end) | 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 | vector * ((vectorLength + radius) / -vectorLength); | 324 | vector * ((vectorLength + radius) / -vectorLength); |
| 325 | minPenetrationLength = vectorLength; | 325 | minPenetrationLength = vectorLength; |
| 326 | } | 326 | } |
| 327 | } | 327 | } |
| 328 | 328 | ||
| 329 | return true; | 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 | case MIN_X_FACE: | 334 | case MIN_X_FACE: |
| 335 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), | 335 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), |
| 336 | glm::vec3(_corner.x, _corner.y + _scale.y, _corner.z + _scale.z)); | 336 | glm::vec3(_corner.x, _corner.y + _scale.y, _corner.z + _scale.z)); |
| 337 | 337 | ||
| 338 | case MAX_X_FACE: | 338 | case MAX_X_FACE: |
| 339 | return glm::clamp(point, glm::vec3(_corner.x + _scale.x, _corner.y, _corner.z), | 339 | return glm::clamp(point, glm::vec3(_corner.x + _scale.x, _corner.y, _corner.z), |
| 340 | glm::vec3(_corner.x + _scale.x, _corner.y + _scale.y, _corner.z + _scale.z)); | 340 | glm::vec3(_corner.x + _scale.x, _corner.y + _scale.y, _corner.z + _scale.z)); |
| 341 | 341 | ||
| 342 | case MIN_Y_FACE: | 342 | case MIN_Y_FACE: |
| 343 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), | 343 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), |
| 344 | glm::vec3(_corner.x + _scale.x, _corner.y, _corner.z + _scale.z)); | 344 | glm::vec3(_corner.x + _scale.x, _corner.y, _corner.z + _scale.z)); |
| 345 | 345 | ||
| 346 | case MAX_Y_FACE: | 346 | case MAX_Y_FACE: |
| 347 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _scale.y, _corner.z), | 347 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _scale.y, _corner.z), |
| 348 | glm::vec3(_corner.x + _scale.x, _corner.y + _scale.y, _corner.z + _scale.z)); | 348 | glm::vec3(_corner.x + _scale.x, _corner.y + _scale.y, _corner.z + _scale.z)); |
| 349 | 349 | ||
| 350 | case MIN_Z_FACE: | 350 | case MIN_Z_FACE: |
| 351 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), | 351 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), |
| 352 | glm::vec3(_corner.x + _scale.z, _corner.y + _scale.y, _corner.z)); | 352 | glm::vec3(_corner.x + _scale.z, _corner.y + _scale.y, _corner.z)); |
| 353 | 353 | ||
| 354 | default: //quiet windows warnings | 354 | default: //quiet windows warnings |
| 355 | case MAX_Z_FACE: | 355 | case MAX_Z_FACE: |
| 356 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _scale.z), | 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 | anyOutside = true; | 374 | anyOutside = true; |
| 375 | float divisor = glm::dot(direction, iPlane); | 375 | float divisor = glm::dot(direction, iPlane); |
| 376 | if (fabs(divisor) < EPSILON) { | 376 | if (fabsf(divisor) < EPSILON) { |
| 377 | continue; // segment is parallel to plane | 377 | continue; // segment is parallel to plane |
| 378 | } | 378 | } |
| 379 | // find intersection and see if it lies within face bounds | 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 | return getClosestPointOnFace(glm::vec3(intersection), face); | 391 | return getClosestPointOnFace(glm::vec3(intersection), face); |
| 392 | 392 | ||
| 393 | outerContinue: ; | 393 | outerContinue: ; |
| 394 | } | 394 | } |
| 395 | 395 | ||
| 396 | // if we were outside any of the sides, we must check against the diagonals | 396 | // if we were outside any of the sides, we must check against the diagonals |
| 397 | if (anyOutside) { | 397 | if (anyOutside) { |
| 398 | int faceAxis = face / 2; | 398 | int faceAxis = face / 2; |
| 399 | int secondAxis = (faceAxis + 1) % 3; | 399 | int secondAxis = (faceAxis + 1) % 3; |
| 400 | int thirdAxis = (faceAxis + 2) % 3; | 400 | int thirdAxis = (faceAxis + 2) % 3; |
| 401 | 401 | ||
| 402 | glm::vec4 secondAxisMinPlane = getPlane((BoxFace)(secondAxis * 2)); | 402 | glm::vec4 secondAxisMinPlane = getPlane((BoxFace)(secondAxis * 2)); |
| 403 | glm::vec4 secondAxisMaxPlane = getPlane((BoxFace)(secondAxis * 2 + 1)); | 403 | glm::vec4 secondAxisMaxPlane = getPlane((BoxFace)(secondAxis * 2 + 1)); |
| 404 | glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1)); | 404 | glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1)); |
| 405 | 405 | ||
| 406 | glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f, | 406 | glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f, |
| 407 | glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), _scale) * 0.5f); | 407 | glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), _scale) * 0.5f); |
| 408 | glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset, | 408 | glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset, |
| 409 | secondAxisMaxPlane + thirdAxisMaxPlane + offset }; | 409 | secondAxisMaxPlane + thirdAxisMaxPlane + offset }; |
| 410 | 410 | ||
| 411 | float minDistance = FLT_MAX; | 411 | float minDistance = FLT_MAX; |
| 412 | for (size_t i = 0; i < sizeof(diagonals) / sizeof(diagonals[0]); i++) { | 412 | for (size_t i = 0; i < sizeof(diagonals) / sizeof(diagonals[0]); i++) { |
| 413 | float divisor = glm::dot(direction, diagonals[i]); | 413 | float divisor = glm::dot(direction, diagonals[i]); |
| 414 | if (fabs(divisor) < EPSILON) { | 414 | if (fabsf(divisor) < EPSILON) { |
| 415 | continue; // segment is parallel to diagonal plane | 415 | continue; // segment is parallel to diagonal plane |
| 416 | } | 416 | } |
| 417 | minDistance = glm::min(-glm::dot(origin, diagonals[i]) / divisor, minDistance); | 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 | return getClosestPointOnFace(glm::vec3(origin + direction * minDistance), face); | 420 | return getClosestPointOnFace(glm::vec3(origin + direction * minDistance), face); |
| 421 | } | 421 | } |
| 422 | } | 422 | } |
| 423 | 423 | ||
| 424 | // last resort or all inside: clamp origin to face | 424 | // last resort or all inside: clamp origin to face |
| 425 | return getClosestPointOnFace(glm::vec3(origin), face); | 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 | glm::vec3 clampedCorner = glm::clamp(_corner, min, max); | 453 | glm::vec3 clampedCorner = glm::clamp(_corner, min, max); |
| 454 | glm::vec3 clampedTopFarLeft = glm::clamp(calcTopFarLeft(), min, max); | 454 | glm::vec3 clampedTopFarLeft = glm::clamp(calcTopFarLeft(), min, max); |
| 455 | glm::vec3 clampedScale = clampedTopFarLeft - clampedCorner; | 455 | glm::vec3 clampedScale = clampedTopFarLeft - clampedCorner; |
| 456 | 456 | ||
| 457 | return AABox(clampedCorner, clampedScale); | 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 | glm::vec3 clampedCorner = glm::clamp(_corner, min, max); | 461 | glm::vec3 clampedCorner = glm::clamp(_corner, min, max); |
| 462 | glm::vec3 clampedTopFarLeft = glm::clamp(calcTopFarLeft(), min, max); | 462 | glm::vec3 clampedTopFarLeft = glm::clamp(calcTopFarLeft(), min, max); |
| 463 | glm::vec3 clampedScale = clampedTopFarLeft - clampedCorner; | 463 | glm::vec3 clampedScale = clampedTopFarLeft - clampedCorner; |
| 464 | 464 | ||
| 465 | return AABox(clampedCorner, clampedScale); | 465 | return AABox(clampedCorner, clampedScale); |
| 466 | } | 466 | } |
| 467 | 467 | ||
| @@ -21,14 +21,14 @@ AACube::AACube(const AABox& other) : · 20 unmodified lines | |||
| 21 | _corner(other.getCorner()), _scale(other.getLargestDimension()) { | 21 | _corner(other.getCorner()), _scale(other.getLargestDimension()) { |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | AACube::AACube(const Extents& other) : | 24 | AACube::AACube(const Extents& other) : |
| 25 | _corner(other.minimum) | 25 | _corner(other.minimum) |
| 26 | { | 26 | { |
| 27 | glm::vec3 dimensions = other.maximum - other.minimum; | 27 | glm::vec3 dimensions = other.maximum - other.minimum; |
| 28 | _scale = glm::max(dimensions.x, dimensions.y, dimensions.z); | 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 | _corner(corner), _scale(size) { | 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 | glm::vec3 AACube::calcCenter() const { | 38 | glm::vec3 AACube::calcCenter() const { |
| 39 | glm::vec3 center(_corner); | 39 | glm::vec3 center(_corner); |
| 40 | center += (glm::vec3(_scale, _scale, _scale) * 0.5f); | 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 | glm::vec3 topFarLeft(_corner); | 45 | glm::vec3 topFarLeft(_corner); |
| 46 | topFarLeft += glm::vec3(_scale, _scale, _scale); | 46 | topFarLeft += glm::vec3(_scale, _scale, _scale); |
| 47 | return topFarLeft; | 47 | return topFarLeft; |
| 48 | }; | 48 | }; |
| 49 | 49 | ||
| 50 | void AACube::scale(float scale) { | 50 | void AACube::scale(float scale) { |
| @@ -135,9 +135,9 @@ bool AACube::contains(const AACube& otherCube) const { · 84 unmodified lines | |||
| 135 | bool AACube::touches(const AACube& otherCube) const { | 135 | bool AACube::touches(const AACube& otherCube) const { |
| 136 | glm::vec3 relativeCenter = _corner - otherCube._corner + (glm::vec3(_scale - otherCube._scale) * 0.5f); | 136 | glm::vec3 relativeCenter = _corner - otherCube._corner + (glm::vec3(_scale - otherCube._scale) * 0.5f); |
| 137 | float totalHalfScale = 0.5f * (_scale + otherCube._scale); | 137 | float totalHalfScale = 0.5f * (_scale + otherCube._scale); |
| 138 | return fabs(relativeCenter.x) <= totalHalfScale && | 138 | return fabsf(relativeCenter.x) <= totalHalfScale && |
| 139 | fabs(relativeCenter.y) <= totalHalfScale && | 139 | fabsf(relativeCenter.y) <= totalHalfScale && |
| 140 | fabs(relativeCenter.z) <= totalHalfScale; | 140 | fabsf(relativeCenter.z) <= totalHalfScale; |
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | bool AACube::contains(const AABox& otherBox) const { | 143 | bool AACube::contains(const AABox& otherBox) const { |
| @@ -154,10 +154,10 @@ bool AACube::touches(const AABox& otherBox) const { · 10 unmodified lines | |||
| 154 | glm::vec3 myDimensions = glm::vec3(_scale); | 154 | glm::vec3 myDimensions = glm::vec3(_scale); |
| 155 | glm::vec3 relativeCenter = _corner - otherBox.getCorner() + ((myDimensions - otherBox.getScale()) * 0.5f); | 155 | glm::vec3 relativeCenter = _corner - otherBox.getCorner() + ((myDimensions - otherBox.getScale()) * 0.5f); |
| 156 | glm::vec3 totalHalfScale = (myDimensions + otherBox.getDimensions()) * 0.5f; | 156 | glm::vec3 totalHalfScale = (myDimensions + otherBox.getDimensions()) * 0.5f; |
| 157 | 157 | ||
| 158 | return fabs(relativeCenter.x) <= totalHalfScale.x && | 158 | return fabsf(relativeCenter.x) <= totalHalfScale.x && |
| 159 | fabs(relativeCenter.y) <= totalHalfScale.y && | 159 | fabsf(relativeCenter.y) <= totalHalfScale.y && |
| 160 | fabs(relativeCenter.z) <= totalHalfScale.z; | 160 | fabsf(relativeCenter.z) <= totalHalfScale.z; |
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | // determines whether a value is within the expanded extents | 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 | bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const { | 222 | bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const { |
| 223 | // handle the trivial case where the box contains the origin | 223 | // handle the trivial case where the box contains the origin |
| 224 | if (contains(origin)) { | 224 | if (contains(origin)) { |
| 225 | 225 | ||
| 226 | // We still want to calculate the distance from the origin to the inside out plane | 226 | // We still want to calculate the distance from the origin to the inside out plane |
| 227 | float axisDistance; | 227 | float axisDistance; |
| 228 | if ((findInsideOutIntersection(origin.x, direction.x, _corner.x, _scale, axisDistance) && axisDistance >= 0 && | 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 | isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) && | 243 | isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) && |
| 244 | isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) { | 244 | isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) { |
| 245 | distance = axisDistance; | 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 | return true; | 247 | return true; |
| 248 | } | 248 | } |
| 249 | // This case is unexpected, but mimics the previous behavior for inside out intersections | 249 | // This case is unexpected, but mimics the previous behavior for inside out intersections |
| 250 | distance = 0; | 250 | distance = 0; |
| 251 | return true; | 251 | return true; |
| 252 | } | 252 | } |
| 253 | 253 | ||
| 254 | // check each axis | 254 | // check each axis |
| 255 | float axisDistance; | 255 | float axisDistance; |
| 256 | if ((findIntersection(origin.x, direction.x, _corner.x, _scale, axisDistance) && axisDistance >= 0 && | 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 | isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) && | 271 | isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) && |
| 272 | isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) { | 272 | isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) { |
| 273 | distance = axisDistance; | 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 | return true; | 275 | return true; |
| 276 | } | 276 | } |
| 277 | return false; | 277 | return false; |
| @@ -279,7 +279,7 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc · 1 unmodified line | |||
| 279 | 279 | ||
| 280 | bool AACube::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const { | 280 | bool AACube::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const { |
| 281 | glm::vec4 center4 = glm::vec4(center, 1.0f); | 281 | glm::vec4 center4 = glm::vec4(center, 1.0f); |
| 282 | 282 | ||
| 283 | float minPenetrationLength = FLT_MAX; | 283 | float minPenetrationLength = FLT_MAX; |
| 284 | for (int i = 0; i < FACE_COUNT; i++) { | 284 | for (int i = 0; i < FACE_COUNT; i++) { |
| 285 | glm::vec4 facePlane = getPlane((BoxFace)i); | 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 | minPenetrationLength = vectorLength; | 296 | minPenetrationLength = vectorLength; |
| 297 | } | 297 | } |
| 298 | } | 298 | } |
| 299 | 299 | ||
| 300 | return true; | 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 | glm::vec4 start4 = glm::vec4(start, 1.0f); | 304 | glm::vec4 start4 = glm::vec4(start, 1.0f); |
| 305 | glm::vec4 end4 = glm::vec4(end, 1.0f); | 305 | glm::vec4 end4 = glm::vec4(end, 1.0f); |
| 306 | glm::vec4 startToEnd = glm::vec4(end - start, 0.0f); | 306 | glm::vec4 startToEnd = glm::vec4(end - start, 0.0f); |
| 307 | 307 | ||
| 308 | float minPenetrationLength = FLT_MAX; | 308 | float minPenetrationLength = FLT_MAX; |
| 309 | for (int i = 0; i < FACE_COUNT; i++) { | 309 | for (int i = 0; i < FACE_COUNT; i++) { |
| 310 | // find the vector from the segment to the closest point on the face (starting from deeper end) | 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 | vector * ((vectorLength + radius) / -vectorLength); | 323 | vector * ((vectorLength + radius) / -vectorLength); |
| 324 | minPenetrationLength = vectorLength; | 324 | minPenetrationLength = vectorLength; |
| 325 | } | 325 | } |
| 326 | } | 326 | } |
| 327 | 327 | ||
| 328 | return true; | 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 | case MIN_X_FACE: | 333 | case MIN_X_FACE: |
| 334 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), | 334 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), |
| 335 | glm::vec3(_corner.x, _corner.y + _scale, _corner.z + _scale)); | 335 | glm::vec3(_corner.x, _corner.y + _scale, _corner.z + _scale)); |
| 336 | 336 | ||
| 337 | case MAX_X_FACE: | 337 | case MAX_X_FACE: |
| 338 | return glm::clamp(point, glm::vec3(_corner.x + _scale, _corner.y, _corner.z), | 338 | return glm::clamp(point, glm::vec3(_corner.x + _scale, _corner.y, _corner.z), |
| 339 | glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale)); | 339 | glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale)); |
| 340 | 340 | ||
| 341 | case MIN_Y_FACE: | 341 | case MIN_Y_FACE: |
| 342 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), | 342 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), |
| 343 | glm::vec3(_corner.x + _scale, _corner.y, _corner.z + _scale)); | 343 | glm::vec3(_corner.x + _scale, _corner.y, _corner.z + _scale)); |
| 344 | 344 | ||
| 345 | case MAX_Y_FACE: | 345 | case MAX_Y_FACE: |
| 346 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _scale, _corner.z), | 346 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _scale, _corner.z), |
| 347 | glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale)); | 347 | glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale)); |
| 348 | 348 | ||
| 349 | case MIN_Z_FACE: | 349 | case MIN_Z_FACE: |
| 350 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), | 350 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), |
| 351 | glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z)); | 351 | glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z)); |
| 352 | 352 | ||
| 353 | default: //quiet windows warnings | 353 | default: //quiet windows warnings |
| 354 | case MAX_Z_FACE: | 354 | case MAX_Z_FACE: |
| 355 | return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _scale), | 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 | anyOutside = true; | 373 | anyOutside = true; |
| 374 | float divisor = glm::dot(direction, iPlane); | 374 | float divisor = glm::dot(direction, iPlane); |
| 375 | if (fabs(divisor) < EPSILON) { | 375 | if (fabsf(divisor) < EPSILON) { |
| 376 | continue; // segment is parallel to plane | 376 | continue; // segment is parallel to plane |
| 377 | } | 377 | } |
| 378 | // find intersection and see if it lies within face bounds | 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 | return getClosestPointOnFace(glm::vec3(intersection), face); | 390 | return getClosestPointOnFace(glm::vec3(intersection), face); |
| 391 | 391 | ||
| 392 | outerContinue: ; | 392 | outerContinue: ; |
| 393 | } | 393 | } |
| 394 | 394 | ||
| 395 | // if we were outside any of the sides, we must check against the diagonals | 395 | // if we were outside any of the sides, we must check against the diagonals |
| 396 | if (anyOutside) { | 396 | if (anyOutside) { |
| 397 | int faceAxis = face / 2; | 397 | int faceAxis = face / 2; |
| 398 | int secondAxis = (faceAxis + 1) % 3; | 398 | int secondAxis = (faceAxis + 1) % 3; |
| 399 | int thirdAxis = (faceAxis + 2) % 3; | 399 | int thirdAxis = (faceAxis + 2) % 3; |
| 400 | 400 | ||
| 401 | glm::vec4 secondAxisMinPlane = getPlane((BoxFace)(secondAxis * 2)); | 401 | glm::vec4 secondAxisMinPlane = getPlane((BoxFace)(secondAxis * 2)); |
| 402 | glm::vec4 secondAxisMaxPlane = getPlane((BoxFace)(secondAxis * 2 + 1)); | 402 | glm::vec4 secondAxisMaxPlane = getPlane((BoxFace)(secondAxis * 2 + 1)); |
| 403 | glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1)); | 403 | glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1)); |
| 404 | 404 | ||
| 405 | glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f, | 405 | glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f, |
| 406 | glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), glm::vec3(_scale, _scale, _scale)) * 0.5f); | 406 | glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), glm::vec3(_scale, _scale, _scale)) * 0.5f); |
| 407 | glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset, | 407 | glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset, |
| 408 | secondAxisMaxPlane + thirdAxisMaxPlane + offset }; | 408 | secondAxisMaxPlane + thirdAxisMaxPlane + offset }; |
| 409 | 409 | ||
| 410 | float minDistance = FLT_MAX; | 410 | float minDistance = FLT_MAX; |
| 411 | for (size_t i = 0; i < sizeof(diagonals) / sizeof(diagonals[0]); i++) { | 411 | for (size_t i = 0; i < sizeof(diagonals) / sizeof(diagonals[0]); i++) { |
| 412 | float divisor = glm::dot(direction, diagonals[i]); | 412 | float divisor = glm::dot(direction, diagonals[i]); |
| 413 | if (fabs(divisor) < EPSILON) { | 413 | if (fabsf(divisor) < EPSILON) { |
| 414 | continue; // segment is parallel to diagonal plane | 414 | continue; // segment is parallel to diagonal plane |
| 415 | } | 415 | } |
| 416 | minDistance = glm::min(-glm::dot(origin, diagonals[i]) / divisor, minDistance); | 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 | return getClosestPointOnFace(glm::vec3(origin + direction * minDistance), face); | 419 | return getClosestPointOnFace(glm::vec3(origin + direction * minDistance), face); |
| 420 | } | 420 | } |
| 421 | } | 421 | } |
| 422 | 422 | ||
| 423 | // last resort or all inside: clamp origin to face | 423 | // last resort or all inside: clamp origin to face |
| 424 | return getClosestPointOnFace(glm::vec3(origin), face); | 424 | return getClosestPointOnFace(glm::vec3(origin), face); |
| 425 | } | 425 | } |
| @@ -120,7 +120,7 @@ bool HingeConstraint::clamp(glm::quat& rotation) const { · 119 unmodified lines | |||
| 120 | forward /= length; | 120 | forward /= length; |
| 121 | float sign = (glm::dot(glm::cross(_forwardAxis, forward), _rotationAxis) > 0.0f ? 1.0f : -1.0f); | 121 | float sign = (glm::dot(glm::cross(_forwardAxis, forward), _rotationAxis) > 0.0f ? 1.0f : -1.0f); |
| 122 | //float angle = sign * acos(glm::dot(forward, _forwardAxis) / length); | 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 | glm::quat newRotation = glm::angleAxis(clampAngle(angle, _minAngle, _maxAngle), _rotationAxis); | 124 | glm::quat newRotation = glm::angleAxis(clampAngle(angle, _minAngle, _maxAngle), _rotationAxis); |
| 125 | if (fabsf(1.0f - glm::dot(newRotation, rotation)) > EPSILON * EPSILON) { | 125 | if (fabsf(1.0f - glm::dot(newRotation, rotation)) > EPSILON * EPSILON) { |
| 126 | rotation = newRotation; | 126 | rotation = newRotation; |
| @@ -238,7 +238,7 @@ glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) { · 237 unmodified lines | |||
| 238 | float sd10 = previous[0][1] * previous[2][2] - previous[2][1] * previous[0][2]; | 238 | float sd10 = previous[0][1] * previous[2][2] - previous[2][1] * previous[0][2]; |
| 239 | float sd20 = previous[0][1] * previous[1][2] - previous[1][1] * previous[0][2]; | 239 | float sd20 = previous[0][1] * previous[1][2] - previous[1][1] * previous[0][2]; |
| 240 | float det = previous[0][0] * sd00 + previous[2][0] * sd20 - previous[1][0] * sd10; | 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 | // determinant is zero; matrix is not invertible | 242 | // determinant is zero; matrix is not invertible |
| 243 | break; | 243 | break; |
| 244 | } | 244 | } |
| @@ -28,10 +28,19 @@ using glm::vec3; · 27 unmodified lines | |||
| 28 | using glm::vec4; | 28 | using glm::vec4; |
| 29 | using glm::quat; | 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 | #include <QtCore/QByteArray> | 36 | #include <QtCore/QByteArray> |
| 32 | #include <QtGui/QMatrix4x4> | 37 | #include <QtGui/QMatrix4x4> |
| 33 | #include <QtGui/QColor> | 38 | #include <QtGui/QColor> |
| 34 | 39 | ||
| 40 | #ifdef __GNUC__ | ||
| 41 | #pragma GCC diagnostic pop | ||
| 42 | #endif | ||
| 43 | |||
| 35 | #include "SharedUtil.h" | 44 | #include "SharedUtil.h" |
| 36 | 45 | ||
| 37 | // this is where the coordinate system is represented | 46 | // this is where the coordinate system is represented |
| @@ -122,6 +131,21 @@ float aspect(const T& t) { · 84 unmodified lines | |||
| 122 | return (float)t.x / (float)t.y; | 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 | #define YAW(euler) euler.y | 149 | #define YAW(euler) euler.y |
| 126 | #define PITCH(euler) euler.x | 150 | #define PITCH(euler) euler.x |
| 127 | #define ROLL(euler) euler.z | 151 | #define ROLL(euler) euler.z |
| @@ -118,11 +118,15 @@ public: · 117 unmodified lines | |||
| 118 | 118 | ||
| 119 | template <typename Function> | 119 | template <typename Function> |
| 120 | void withPush(Function f) { | 120 | void withPush(Function f) { |
| 121 | #ifndef NDEBUG | ||
| 121 | size_t startingDepth = size(); | 122 | size_t startingDepth = size(); |
| 123 | #endif | ||
| 122 | push(); | 124 | push(); |
| 123 | f(); | 125 | f(); |
| 124 | pop(); | 126 | pop(); |
| 125 | assert(startingDepth = size()); | 127 | #ifndef NDEBUG |
| 128 | assert(startingDepth == size()); | ||
| 129 | #endif | ||
| 126 | } | 130 | } |
| 127 | 131 | ||
| 128 | template <typename Function> | 132 | template <typename Function> |
| @@ -47,7 +47,7 @@ void printOctalCode(const unsigned char* octalCode) { · 46 unmodified lines | |||
| 47 | 47 | ||
| 48 | char sectionValue(const unsigned char* startByte, char startIndexInByte) { | 48 | char sectionValue(const unsigned char* startByte, char startIndexInByte) { |
| 49 | char rightShift = 8 - startIndexInByte - 3; | 49 | char rightShift = 8 - startIndexInByte - 3; |
| 50 | 50 | ||
| 51 | if (rightShift < 0) { | 51 | if (rightShift < 0) { |
| 52 | return ((startByte[0] << -rightShift) & 7) + (startByte[1] >> (8 + rightShift)); | 52 | return ((startByte[0] << -rightShift) & 7) + (startByte[1] >> (8 + rightShift)); |
| 53 | } else { | 53 | } else { |
| @@ -65,7 +65,7 @@ size_t bytesRequiredForCodeLength(unsigned char threeBitCodes) { · 11 unmodified lines | |||
| 65 | 65 | ||
| 66 | int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsigned char* descendantOctalCode) { | 66 | int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsigned char* descendantOctalCode) { |
| 67 | int parentSections = numberOfThreeBitSectionsInCode(ancestorOctalCode); | 67 | int parentSections = numberOfThreeBitSectionsInCode(ancestorOctalCode); |
| 68 | 68 | ||
| 69 | int branchStartBit = parentSections * 3; | 69 | int branchStartBit = parentSections * 3; |
| 70 | // Note: this does not appear to be "multi-byte length code" safe. When octal codes are larger than 255 bytes | 70 | // Note: this does not appear to be "multi-byte length code" safe. When octal codes are larger than 255 bytes |
| 71 | // long, the length code is stored in two bytes. The "1" below appears to assume that the length is always one | 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 | unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNumber) { | 76 | unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNumber) { |
| 77 | 77 | ||
| 78 | // find the length (in number of three bit code sequences) | 78 | // find the length (in number of three bit code sequences) |
| 79 | // in the parent | 79 | // in the parent |
| 80 | int parentCodeSections = parentOctalCode | 80 | int parentCodeSections = parentOctalCode |
| 81 | ? numberOfThreeBitSectionsInCode(parentOctalCode) | 81 | ? numberOfThreeBitSectionsInCode(parentOctalCode) |
| 82 | : 0; | 82 | : 0; |
| 83 | 83 | ||
| 84 | // get the number of bytes used by the parent octal code | 84 | // get the number of bytes used by the parent octal code |
| 85 | size_t parentCodeBytes = bytesRequiredForCodeLength(parentCodeSections); | 85 | size_t parentCodeBytes = bytesRequiredForCodeLength(parentCodeSections); |
| 86 | 86 | ||
| 87 | // child code will have one more section than the parent | 87 | // child code will have one more section than the parent |
| 88 | size_t childCodeBytes = bytesRequiredForCodeLength(parentCodeSections + 1); | 88 | size_t childCodeBytes = bytesRequiredForCodeLength(parentCodeSections + 1); |
| 89 | 89 | ||
| 90 | // create a new buffer to hold the new octal code | 90 | // create a new buffer to hold the new octal code |
| 91 | unsigned char* newCode = new unsigned char[childCodeBytes]; | 91 | unsigned char* newCode = new unsigned char[childCodeBytes]; |
| 92 | 92 | ||
| 93 | // copy the parent code to the child | 93 | // copy the parent code to the child |
| 94 | if (parentOctalCode) { | 94 | if (parentOctalCode) { |
| 95 | memcpy(newCode, parentOctalCode, parentCodeBytes); | 95 | memcpy(newCode, parentOctalCode, parentCodeBytes); |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | // the child octal code has one more set of three bits | 98 | // the child octal code has one more set of three bits |
| 99 | *newCode = parentCodeSections + 1; | 99 | *newCode = parentCodeSections + 1; |
| 100 | 100 | ||
| 101 | if (childCodeBytes > parentCodeBytes) { | 101 | if (childCodeBytes > parentCodeBytes) { |
| 102 | // we have a new byte due to the addition of the child code | 102 | // we have a new byte due to the addition of the child code |
| 103 | // so set it to zero for correct results when shifting later | 103 | // so set it to zero for correct results when shifting later |
| 104 | newCode[childCodeBytes - 1] = 0; | 104 | newCode[childCodeBytes - 1] = 0; |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | // add the child code bits to newCode | 107 | // add the child code bits to newCode |
| 108 | 108 | ||
| 109 | // find the start bit index | 109 | // find the start bit index |
| 110 | int startBit = parentCodeSections * 3; | 110 | int startBit = parentCodeSections * 3; |
| 111 | 111 | ||
| 112 | // calculate the amount of left shift required | 112 | // calculate the amount of left shift required |
| 113 | // this will be -1 or -2 if there's wrap | 113 | // this will be -1 or -2 if there's wrap |
| 114 | char leftShift = 8 - (startBit % 8) - 3; | 114 | char leftShift = 8 - (startBit % 8) - 3; |
| 115 | 115 | ||
| 116 | if (leftShift < 0) { | 116 | if (leftShift < 0) { |
| 117 | // we have a wrap-around to accomodate | 117 | // we have a wrap-around to accomodate |
| 118 | // right shift for the end of first byte | 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 | // no wraparound, left shift and add | 123 | // no wraparound, left shift and add |
| 124 | newCode[(startBit / 8) + 1] += (childNumber << leftShift); | 124 | newCode[(startBit / 8) + 1] += (childNumber << leftShift); |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | return newCode; | 127 | return newCode; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| @@ -135,9 +135,9 @@ void voxelDetailsForCode(const unsigned char* octalCode, VoxelPositionSize& voxe · 5 unmodified lines | |||
| 135 | if (octalCode) { | 135 | if (octalCode) { |
| 136 | for (int i = 0; i < numberOfThreeBitSectionsInCode(octalCode); i++) { | 136 | for (int i = 0; i < numberOfThreeBitSectionsInCode(octalCode); i++) { |
| 137 | currentScale *= 0.5f; | 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 | (BITS_IN_OCTAL * i) % BITS_IN_BYTE); | 139 | (BITS_IN_OCTAL * i) % BITS_IN_BYTE); |
| 140 | 140 | ||
| 141 | for (int j = 0; j < BITS_IN_OCTAL; j++) { | 141 | for (int j = 0; j < BITS_IN_OCTAL; j++) { |
| 142 | output[j] += currentScale * (float)oneAtBit(sectionIndex, (BITS_IN_BYTE - BITS_IN_OCTAL) + j); | 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 | void copyFirstVertexForCode(const unsigned char* octalCode, float* output) { | 152 | void copyFirstVertexForCode(const unsigned char* octalCode, float* output) { |
| 153 | memset(output, 0, 3 * sizeof(float)); | 153 | memset(output, 0, 3 * sizeof(float)); |
| 154 | 154 | ||
| 155 | float currentScale = 0.5f; | 155 | float currentScale = 0.5f; |
| 156 | 156 | ||
| 157 | for (int i = 0; i < numberOfThreeBitSectionsInCode(octalCode); i++) { | 157 | for (int i = 0; i < numberOfThreeBitSectionsInCode(octalCode); i++) { |
| 158 | int sectionIndex = sectionValue(octalCode + 1 + (3 * i / 8), (3 * i) % 8); | 158 | int sectionIndex = sectionValue(octalCode + 1 + (3 * i / 8), (3 * i) % 8); |
| 159 | 159 | ||
| 160 | for (int j = 0; j < 3; j++) { | 160 | for (int j = 0; j < 3; j++) { |
| 161 | output[j] += currentScale * (int)oneAtBit(sectionIndex, 5 + j); | 161 | output[j] += currentScale * (int)oneAtBit(sectionIndex, 5 + j); |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | currentScale *= 0.5; | 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 | OctalCodeComparison result = LESS_THAN; // assume it's shallower | 173 | OctalCodeComparison result = LESS_THAN; // assume it's shallower |
| 174 | 174 | ||
| 175 | size_t numberOfBytes = std::min(bytesRequiredForCodeLength(*codeA), bytesRequiredForCodeLength(*codeB)); | 175 | size_t numberOfBytes = std::min(bytesRequiredForCodeLength(*codeA), bytesRequiredForCodeLength(*codeB)); |
| 176 | int compare = memcmp(codeA, codeB, numberOfBytes); | 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 | int startAtByte = 1 + (BITS_IN_OCTAL * section / BITS_IN_BYTE); | 205 | int startAtByte = 1 + (BITS_IN_OCTAL * section / BITS_IN_BYTE); |
| 206 | char startIndexInByte = (BITS_IN_OCTAL * section) % BITS_IN_BYTE; | 206 | char startIndexInByte = (BITS_IN_OCTAL * section) % BITS_IN_BYTE; |
| 207 | const unsigned char* startByte = octalCode + startAtByte; | 207 | const unsigned char* startByte = octalCode + startAtByte; |
| 208 | 208 | ||
| 209 | return sectionValue(startByte, startIndexInByte); | 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 | unsigned char oldValue = *byteAt & ~shiftedMask; | 227 | unsigned char oldValue = *byteAt & ~shiftedMask; |
| 228 | unsigned char newValue = oldValue | shiftedValue; | 228 | unsigned char newValue = oldValue | shiftedValue; |
| 229 | *byteAt = newValue; | 229 | *byteAt = newValue; |
| 230 | 230 | ||
| 231 | // If the requested section is partially in the byte, then we | 231 | // If the requested section is partially in the byte, then we |
| 232 | // need to also set the portion of the section value in the next byte | 232 | // need to also set the portion of the section value in the next byte |
| 233 | // there's only two cases where this happens, if the bit in byte is | 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 | int newLength = codeLength - chopLevels; | 255 | int newLength = codeLength - chopLevels; |
| 256 | newCode = new unsigned char[newLength+1]; | 256 | newCode = new unsigned char[newLength+1]; |
| 257 | *newCode = newLength; // set the length byte | 257 | *newCode = newLength; // set the length byte |
| 258 | 258 | ||
| 259 | for (int section = chopLevels; section < codeLength; section++) { | 259 | for (int section = chopLevels; section < codeLength; section++) { |
| 260 | char sectionValue = getOctalCodeSectionValue(originalOctalCode, section); | 260 | char sectionValue = getOctalCodeSectionValue(originalOctalCode, section); |
| 261 | setOctalCodeSectionValue(newCode, section - chopLevels, sectionValue); | 261 | setOctalCodeSectionValue(newCode, section - chopLevels, sectionValue); |
| @@ -264,9 +264,9 @@ unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLev · 2 unmodified lines | |||
| 264 | return newCode; | 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 | bool includeColorSpace) { | 268 | bool includeColorSpace) { |
| 269 | 269 | ||
| 270 | int oldCodeLength = numberOfThreeBitSectionsInCode(originalOctalCode); | 270 | int oldCodeLength = numberOfThreeBitSectionsInCode(originalOctalCode); |
| 271 | int newParentCodeLength = numberOfThreeBitSectionsInCode(newParentOctalCode); | 271 | int newParentCodeLength = numberOfThreeBitSectionsInCode(newParentOctalCode); |
| 272 | int newCodeLength = newParentCodeLength + oldCodeLength; | 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 | int descendentCodeLength = numberOfThreeBitSectionsInCode(possibleDescendent); | 300 | int descendentCodeLength = numberOfThreeBitSectionsInCode(possibleDescendent); |
| 301 | 301 | ||
| 302 | // if the caller also include a child, then our descendent length is actually one extra! | 302 | // if the caller also include a child, then our descendent length is actually one extra! |
| 303 | if (descendentsChild != CHECK_NODE_ONLY) { | 303 | if (descendentsChild != CHECK_NODE_ONLY) { |
| 304 | descendentCodeLength++; | 304 | descendentCodeLength++; |
| 305 | } | 305 | } |
| 306 | 306 | ||
| 307 | if (ancestorCodeLength > descendentCodeLength) { | 307 | if (ancestorCodeLength > descendentCodeLength) { |
| 308 | return false; // if the descendent is shorter, it can't be a descendent | 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 | return false; // first non-match, means they don't match | 322 | return false; // first non-match, means they don't match |
| 323 | } | 323 | } |
| 324 | } | 324 | } |
| 325 | 325 | ||
| 326 | // they all match, so we are an ancestor | 326 | // they all match, so we are an ancestor |
| 327 | return true; | 327 | return true; |
| 328 | } | 328 | } |
| @@ -335,7 +335,7 @@ unsigned char* hexStringToOctalCode(const QString& input) { · 6 unmodified lines | |||
| 335 | 335 | ||
| 336 | // allocate byte array based on half of string length | 336 | // allocate byte array based on half of string length |
| 337 | unsigned char* bytes = new unsigned char[(input.length()) / HEX_BYTE_SIZE]; | 337 | unsigned char* bytes = new unsigned char[(input.length()) / HEX_BYTE_SIZE]; |
| 338 | 338 | ||
| 339 | // loop through the string - 2 bytes at a time converting | 339 | // loop through the string - 2 bytes at a time converting |
| 340 | // it to decimal equivalent and store in byte array | 340 | // it to decimal equivalent and store in byte array |
| 341 | bool ok = false; | 341 | bool ok = false; |
| @@ -348,7 +348,7 @@ unsigned char* hexStringToOctalCode(const QString& input) { · 6 unmodified lines | |||
| 348 | stringIndex += HEX_BYTE_SIZE; | 348 | stringIndex += HEX_BYTE_SIZE; |
| 349 | byteArrayIndex++; | 349 | byteArrayIndex++; |
| 350 | } | 350 | } |
| 351 | 351 | ||
| 352 | // something went wrong | 352 | // something went wrong |
| 353 | if (!ok) { | 353 | if (!ok) { |
| 354 | delete[] bytes; | 354 | delete[] bytes; |
| @@ -55,7 +55,7 @@ const int16_t COLLISION_GROUP_COLLISIONLESS = 1 << 15; · 54 unmodified lines | |||
| 55 | const int16_t COLLISION_MASK_DEFAULT = ~ COLLISION_GROUP_COLLISIONLESS; | 55 | const int16_t COLLISION_MASK_DEFAULT = ~ COLLISION_GROUP_COLLISIONLESS; |
| 56 | 56 | ||
| 57 | // STATIC also doesn't collide with other STATIC | 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 | const int16_t COLLISION_MASK_KINEMATIC = COLLISION_MASK_DEFAULT; | 60 | const int16_t COLLISION_MASK_KINEMATIC = COLLISION_MASK_DEFAULT; |
| 61 | 61 | ||
| @@ -20,6 +20,7 @@ · 19 unmodified lines | |||
| 20 | 20 | ||
| 21 | static int vec4MetaTypeId = qRegisterMetaType<glm::vec4>(); | 21 | static int vec4MetaTypeId = qRegisterMetaType<glm::vec4>(); |
| 22 | static int vec3MetaTypeId = qRegisterMetaType<glm::vec3>(); | 22 | static int vec3MetaTypeId = qRegisterMetaType<glm::vec3>(); |
| 23 | static int qVectorVec3MetaTypeId = qRegisterMetaType<QVector<glm::vec3>>(); | ||
| 23 | static int vec2MetaTypeId = qRegisterMetaType<glm::vec2>(); | 24 | static int vec2MetaTypeId = qRegisterMetaType<glm::vec2>(); |
| 24 | static int quatMetaTypeId = qRegisterMetaType<glm::quat>(); | 25 | static int quatMetaTypeId = qRegisterMetaType<glm::quat>(); |
| 25 | static int xColorMetaTypeId = qRegisterMetaType<xColor>(); | 26 | static int xColorMetaTypeId = qRegisterMetaType<xColor>(); |
| @@ -31,6 +32,7 @@ static int collisionMetaTypeId = qRegisterMetaType<Collision>(); · 5 unmodified lines | |||
| 31 | void registerMetaTypes(QScriptEngine* engine) { | 32 | void registerMetaTypes(QScriptEngine* engine) { |
| 32 | qScriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue); | 33 | qScriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue); |
| 33 | qScriptRegisterMetaType(engine, vec3toScriptValue, vec3FromScriptValue); | 34 | qScriptRegisterMetaType(engine, vec3toScriptValue, vec3FromScriptValue); |
| 35 | qScriptRegisterMetaType(engine, qVectorVec3ToScriptValue, qVectorVec3FromScriptValue); | ||
| 34 | qScriptRegisterMetaType(engine, vec2toScriptValue, vec2FromScriptValue); | 36 | qScriptRegisterMetaType(engine, vec2toScriptValue, vec2FromScriptValue); |
| 35 | qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue); | 37 | qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue); |
| 36 | qScriptRegisterMetaType(engine, qRectToScriptValue, qRectFromScriptValue); | 38 | qScriptRegisterMetaType(engine, qRectToScriptValue, qRectFromScriptValue); |
| @@ -93,6 +95,16 @@ QVector<glm::vec3> qVectorVec3FromScriptValue(const QScriptValue& array){ · 56 unmodified lines | |||
| 93 | return newVector; | 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 | QScriptValue vec2toScriptValue(QScriptEngine* engine, const glm::vec2 &vec2) { | 108 | QScriptValue vec2toScriptValue(QScriptEngine* engine, const glm::vec2 &vec2) { |
| 97 | QScriptValue obj = engine->newObject(); | 109 | QScriptValue obj = engine->newObject(); |
| 98 | obj.setProperty("x", vec2.x); | 110 | obj.setProperty("x", vec2.x); |
| @@ -57,6 +57,7 @@ QScriptValue qURLToScriptValue(QScriptEngine* engine, const QUrl& url); · 56 unmodified lines | |||
| 57 | void qURLFromScriptValue(const QScriptValue& object, QUrl& url); | 57 | void qURLFromScriptValue(const QScriptValue& object, QUrl& url); |
| 58 | 58 | ||
| 59 | QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector<glm::vec3>& vector); | 59 | QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector<glm::vec3>& vector); |
| 60 | void qVectorVec3FromScriptValue(const QScriptValue& array, QVector<glm::vec3>& vector); | ||
| 60 | QVector<glm::vec3> qVectorVec3FromScriptValue( const QScriptValue& array); | 61 | QVector<glm::vec3> qVectorVec3FromScriptValue( const QScriptValue& array); |
| 61 | 62 | ||
| 62 | class PickRay { | 63 | class PickRay { |
| @@ -881,7 +881,7 @@ bool capsuleVsAACube(const Shape* shapeA, const Shape* shapeB, CollisionList& co · 880 unmodified lines | |||
| 881 | faceNormal = glm::vec3(0.0f, 0.0f, signs.z); | 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 | if (glm::dot(nearestApproach, faceNormal) > cubeB->getScale() + capsuleA->getRadius()) { | 885 | if (glm::dot(nearestApproach, faceNormal) > cubeB->getScale() + capsuleA->getRadius()) { |
| 886 | return false; | 886 | return false; |
| 887 | } | 887 | } |
| @@ -29,7 +29,7 @@ inline bool isValidScale(glm::vec3 scale) { · 28 unmodified lines | |||
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | inline bool isValidScale(float scale) { | 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 | assert(result); | 33 | assert(result); |
| 34 | return result; | 34 | return result; |
| 35 | } | 35 | } |
| @@ -323,7 +323,7 @@ inline void Transform::setScale(const Vec3& scale) { · 287 unmodified lines | |||
| 323 | } | 323 | } |
| 324 | 324 | ||
| 325 | inline void Transform::postScale(float scale) { | 325 | inline void Transform::postScale(float scale) { |
| 326 | if (isValidScale(scale) || scale == 1.0f) { | 326 | if (!isValidScale(scale) || scale == 1.0f) { |
| 327 | return; | 327 | return; |
| 328 | } | 328 | } |
| 329 | if (isScaling()) { | 329 | if (isScaling()) { |
| @@ -13,35 +13,61 @@ · 12 unmodified lines | |||
| 13 | #include "SharedLogging.h" | 13 | #include "SharedLogging.h" |
| 14 | #include "VariantMapToScriptValue.h" | 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 | case QVariant::Bool: | 19 | case QVariant::Bool: |
| 25 | scriptValue.setProperty(key, qValue.toBool()); | 20 | return qValue.toBool(); |
| 26 | break; | 21 | break; |
| 27 | case QVariant::Int: | 22 | case QVariant::Int: |
| 28 | scriptValue.setProperty(key, qValue.toInt()); | 23 | return qValue.toInt(); |
| 29 | break; | 24 | break; |
| 30 | case QVariant::Double: | 25 | case QVariant::Double: |
| 31 | scriptValue.setProperty(key, qValue.toDouble()); | 26 | return qValue.toDouble(); |
| 32 | break; | 27 | break; |
| 33 | case QVariant::String: { | 28 | case QVariant::String: { |
| 34 | scriptValue.setProperty(key, scriptEngine.newVariant(qValue)); | 29 | return scriptEngine.newVariant(qValue); |
| 35 | break; | 30 | break; |
| 36 | } | 31 | } |
| 37 | case QVariant::Map: { | 32 | case QVariant::Map: { |
| 38 | QVariantMap childMap = qValue.toMap(); | 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 | break; | 40 | break; |
| 41 | } | 41 | } |
| 42 | default: | 42 | default: |
| 43 | qCDebug(shared) << "unhandled QScript type" << qValue.type(); | 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 | return scriptValue; | 73 | return scriptValue; |
| @@ -13,4 +13,6 @@ · 12 unmodified lines | |||
| 13 | #include <QScriptValue> | 13 | #include <QScriptValue> |
| 14 | #include <QScriptEngine> | 14 | #include <QScriptEngine> |
| 15 | 15 | ||
| 16 | QScriptValue variantToScriptValue(QVariant& qValue, QScriptEngine& scriptEngine); | ||
| 16 | QScriptValue variantMapToScriptValue(QVariantMap& variantMap, QScriptEngine& scriptEngine); | 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 | void VrMenu::addMenu(QMenu* menu) { | 136 | void VrMenu::addMenu(QMenu* menu) { |
| 137 | Q_ASSERT(!MenuUserData::forObject(menu)); | 137 | Q_ASSERT(!MenuUserData::forObject(menu)); |
| 138 | QObject * parent = menu->parent(); | 138 | QObject* parent = menu->parent(); |
| 139 | QObject * qmlParent; | 139 | QObject* qmlParent = nullptr; |
| 140 | if (dynamic_cast<QMenu*>(parent)) { | 140 | if (dynamic_cast<QMenu*>(parent)) { |
| 141 | MenuUserData* userData = MenuUserData::forObject(parent); | 141 | MenuUserData* userData = MenuUserData::forObject(parent); |
| 142 | qmlParent = findMenuObject(userData->uuid.toString()); | 142 | qmlParent = findMenuObject(userData->uuid.toString()); |
| @@ -116,20 +116,20 @@ void ShapeColliderTests::sphereTouchesSphere() { · 115 unmodified lines | |||
| 116 | << " ERROR: null collision" << std::endl; | 116 | << " ERROR: null collision" << std::endl; |
| 117 | return; | 117 | return; |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | // penetration points from sphereA into sphereB | 120 | // penetration points from sphereA into sphereB |
| 121 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); | 121 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 122 | if (fabs(inaccuracy) > EPSILON) { | 122 | if (fabsf(inaccuracy) > EPSILON) { |
| 123 | std::cout << __FILE__ << ":" << __LINE__ | 123 | std::cout << __FILE__ << ":" << __LINE__ |
| 124 | << " ERROR: bad penetration: expected = " << expectedPenetration | 124 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 125 | << " actual = " << collision->_penetration << std::endl; | 125 | << " actual = " << collision->_penetration << std::endl; |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | // contactPoint is on surface of sphereA | 128 | // contactPoint is on surface of sphereA |
| 129 | glm::vec3 AtoB = sphereB.getTranslation() - sphereA.getTranslation(); | 129 | glm::vec3 AtoB = sphereB.getTranslation() - sphereA.getTranslation(); |
| 130 | glm::vec3 expectedContactPoint = sphereA.getTranslation() + radiusA * glm::normalize(AtoB); | 130 | glm::vec3 expectedContactPoint = sphereA.getTranslation() + radiusA * glm::normalize(AtoB); |
| 131 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); | 131 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 132 | if (fabs(inaccuracy) > EPSILON) { | 132 | if (fabsf(inaccuracy) > EPSILON) { |
| 133 | std::cout << __FILE__ << ":" << __LINE__ | 133 | std::cout << __FILE__ << ":" << __LINE__ |
| 134 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint | 134 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 135 | << " actual = " << collision->_contactPoint << std::endl; | 135 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -145,21 +145,21 @@ void ShapeColliderTests::sphereTouchesSphere() { · 9 unmodified lines | |||
| 145 | } else { | 145 | } else { |
| 146 | ++numCollisions; | 146 | ++numCollisions; |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | // penetration points from sphereA into sphereB | 149 | // penetration points from sphereA into sphereB |
| 150 | CollisionInfo* collision = collisions.getCollision(numCollisions - 1); | 150 | CollisionInfo* collision = collisions.getCollision(numCollisions - 1); |
| 151 | float inaccuracy = glm::length(collision->_penetration + expectedPenetration); | 151 | float inaccuracy = glm::length(collision->_penetration + expectedPenetration); |
| 152 | if (fabs(inaccuracy) > EPSILON) { | 152 | if (fabsf(inaccuracy) > EPSILON) { |
| 153 | std::cout << __FILE__ << ":" << __LINE__ | 153 | std::cout << __FILE__ << ":" << __LINE__ |
| 154 | << " ERROR: bad penetration: expected = " << expectedPenetration | 154 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 155 | << " actual = " << collision->_penetration << std::endl; | 155 | << " actual = " << collision->_penetration << std::endl; |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | // contactPoint is on surface of sphereA | 158 | // contactPoint is on surface of sphereA |
| 159 | glm::vec3 BtoA = sphereA.getTranslation() - sphereB.getTranslation(); | 159 | glm::vec3 BtoA = sphereA.getTranslation() - sphereB.getTranslation(); |
| 160 | glm::vec3 expectedContactPoint = sphereB.getTranslation() + radiusB * glm::normalize(BtoA); | 160 | glm::vec3 expectedContactPoint = sphereB.getTranslation() + radiusB * glm::normalize(BtoA); |
| 161 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); | 161 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 162 | if (fabs(inaccuracy) > EPSILON) { | 162 | if (fabsf(inaccuracy) > EPSILON) { |
| 163 | std::cout << __FILE__ << ":" << __LINE__ | 163 | std::cout << __FILE__ << ":" << __LINE__ |
| 164 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint | 164 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 165 | << " actual = " << collision->_contactPoint << std::endl; | 165 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -175,7 +175,7 @@ void ShapeColliderTests::sphereMissesCapsule() { · 9 unmodified lines | |||
| 175 | float halfHeightB = 1.7f; | 175 | float halfHeightB = 1.7f; |
| 176 | float axialOffset = totalRadius + 1.1f * halfHeightB; | 176 | float axialOffset = totalRadius + 1.1f * halfHeightB; |
| 177 | float radialOffset = 1.2f * radiusA + 1.3f * radiusB; | 177 | float radialOffset = 1.2f * radiusA + 1.3f * radiusB; |
| 178 | 178 | ||
| 179 | SphereShape sphereA(radiusA); | 179 | SphereShape sphereA(radiusA); |
| 180 | CapsuleShape capsuleB(radiusB, halfHeightB); | 180 | CapsuleShape capsuleB(radiusB, halfHeightB); |
| 181 | 181 | ||
| @@ -228,7 +228,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 46 unmodified lines | |||
| 228 | float alpha = 0.5f; | 228 | float alpha = 0.5f; |
| 229 | float beta = 0.5f; | 229 | float beta = 0.5f; |
| 230 | float radialOffset = alpha * radiusA + beta * radiusB; | 230 | float radialOffset = alpha * radiusA + beta * radiusB; |
| 231 | 231 | ||
| 232 | SphereShape sphereA(radiusA); | 232 | SphereShape sphereA(radiusA); |
| 233 | CapsuleShape capsuleB(radiusB, halfHeightB); | 233 | CapsuleShape capsuleB(radiusB, halfHeightB); |
| 234 | 234 | ||
| @@ -245,21 +245,21 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 10 unmodified lines | |||
| 245 | } else { | 245 | } else { |
| 246 | ++numCollisions; | 246 | ++numCollisions; |
| 247 | } | 247 | } |
| 248 | 248 | ||
| 249 | // penetration points from sphereA into capsuleB | 249 | // penetration points from sphereA into capsuleB |
| 250 | CollisionInfo* collision = collisions.getCollision(numCollisions - 1); | 250 | CollisionInfo* collision = collisions.getCollision(numCollisions - 1); |
| 251 | glm::vec3 expectedPenetration = (radialOffset - totalRadius) * xAxis; | 251 | glm::vec3 expectedPenetration = (radialOffset - totalRadius) * xAxis; |
| 252 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); | 252 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 253 | if (fabs(inaccuracy) > EPSILON) { | 253 | if (fabsf(inaccuracy) > EPSILON) { |
| 254 | std::cout << __FILE__ << ":" << __LINE__ | 254 | std::cout << __FILE__ << ":" << __LINE__ |
| 255 | << " ERROR: bad penetration: expected = " << expectedPenetration | 255 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 256 | << " actual = " << collision->_penetration << std::endl; | 256 | << " actual = " << collision->_penetration << std::endl; |
| 257 | } | 257 | } |
| 258 | 258 | ||
| 259 | // contactPoint is on surface of sphereA | 259 | // contactPoint is on surface of sphereA |
| 260 | glm::vec3 expectedContactPoint = sphereA.getTranslation() - radiusA * xAxis; | 260 | glm::vec3 expectedContactPoint = sphereA.getTranslation() - radiusA * xAxis; |
| 261 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); | 261 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 262 | if (fabs(inaccuracy) > EPSILON) { | 262 | if (fabsf(inaccuracy) > EPSILON) { |
| 263 | std::cout << __FILE__ << ":" << __LINE__ | 263 | std::cout << __FILE__ << ":" << __LINE__ |
| 264 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint | 264 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 265 | << " actual = " << collision->_contactPoint << std::endl; | 265 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -273,7 +273,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 7 unmodified lines | |||
| 273 | } else { | 273 | } else { |
| 274 | ++numCollisions; | 274 | ++numCollisions; |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | // penetration points from sphereA into capsuleB | 277 | // penetration points from sphereA into capsuleB |
| 278 | collision = collisions.getCollision(numCollisions - 1); | 278 | collision = collisions.getCollision(numCollisions - 1); |
| 279 | expectedPenetration = - (radialOffset - totalRadius) * xAxis; | 279 | expectedPenetration = - (radialOffset - totalRadius) * xAxis; |
| @@ -282,12 +282,12 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 2 unmodified lines | |||
| 282 | expectedPenetration *= -1.0f; | 282 | expectedPenetration *= -1.0f; |
| 283 | } | 283 | } |
| 284 | inaccuracy = glm::length(collision->_penetration - expectedPenetration); | 284 | inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 285 | if (fabs(inaccuracy) > EPSILON) { | 285 | if (fabsf(inaccuracy) > EPSILON) { |
| 286 | std::cout << __FILE__ << ":" << __LINE__ | 286 | std::cout << __FILE__ << ":" << __LINE__ |
| 287 | << " ERROR: bad penetration: expected = " << expectedPenetration | 287 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 288 | << " actual = " << collision->_penetration << std::endl; | 288 | << " actual = " << collision->_penetration << std::endl; |
| 289 | } | 289 | } |
| 290 | 290 | ||
| 291 | // contactPoint is on surface of capsuleB | 291 | // contactPoint is on surface of capsuleB |
| 292 | glm::vec3 BtoA = sphereA.getTranslation() - capsuleB.getTranslation(); | 292 | glm::vec3 BtoA = sphereA.getTranslation() - capsuleB.getTranslation(); |
| 293 | glm::vec3 closestApproach = capsuleB.getTranslation() + glm::dot(BtoA, yAxis) * yAxis; | 293 | glm::vec3 closestApproach = capsuleB.getTranslation() + glm::dot(BtoA, yAxis) * yAxis; |
| @@ -298,7 +298,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 4 unmodified lines | |||
| 298 | expectedContactPoint = closestApproach - radiusB * glm::normalize(BtoA - closestApproach); | 298 | expectedContactPoint = closestApproach - radiusB * glm::normalize(BtoA - closestApproach); |
| 299 | } | 299 | } |
| 300 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); | 300 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 301 | if (fabs(inaccuracy) > EPSILON) { | 301 | if (fabsf(inaccuracy) > EPSILON) { |
| 302 | std::cout << __FILE__ << ":" << __LINE__ | 302 | std::cout << __FILE__ << ":" << __LINE__ |
| 303 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint | 303 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 304 | << " actual = " << collision->_contactPoint << std::endl; | 304 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -307,7 +307,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 2 unmodified lines | |||
| 307 | { // sphereA hits end cap at axis | 307 | { // sphereA hits end cap at axis |
| 308 | glm::vec3 axialOffset = (halfHeightB + alpha * radiusA + beta * radiusB) * yAxis; | 308 | glm::vec3 axialOffset = (halfHeightB + alpha * radiusA + beta * radiusB) * yAxis; |
| 309 | sphereA.setTranslation(axialOffset); | 309 | sphereA.setTranslation(axialOffset); |
| 310 | 310 | ||
| 311 | if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions)) | 311 | if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions)) |
| 312 | { | 312 | { |
| 313 | std::cout << __FILE__ << ":" << __LINE__ | 313 | std::cout << __FILE__ << ":" << __LINE__ |
| @@ -315,21 +315,21 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 1 unmodified line | |||
| 315 | } else { | 315 | } else { |
| 316 | ++numCollisions; | 316 | ++numCollisions; |
| 317 | } | 317 | } |
| 318 | 318 | ||
| 319 | // penetration points from sphereA into capsuleB | 319 | // penetration points from sphereA into capsuleB |
| 320 | CollisionInfo* collision = collisions.getCollision(numCollisions - 1); | 320 | CollisionInfo* collision = collisions.getCollision(numCollisions - 1); |
| 321 | glm::vec3 expectedPenetration = - ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; | 321 | glm::vec3 expectedPenetration = - ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; |
| 322 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); | 322 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 323 | if (fabs(inaccuracy) > EPSILON) { | 323 | if (fabsf(inaccuracy) > EPSILON) { |
| 324 | std::cout << __FILE__ << ":" << __LINE__ | 324 | std::cout << __FILE__ << ":" << __LINE__ |
| 325 | << " ERROR: bad penetration: expected = " << expectedPenetration | 325 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 326 | << " actual = " << collision->_penetration << std::endl; | 326 | << " actual = " << collision->_penetration << std::endl; |
| 327 | } | 327 | } |
| 328 | 328 | ||
| 329 | // contactPoint is on surface of sphereA | 329 | // contactPoint is on surface of sphereA |
| 330 | glm::vec3 expectedContactPoint = sphereA.getTranslation() - radiusA * yAxis; | 330 | glm::vec3 expectedContactPoint = sphereA.getTranslation() - radiusA * yAxis; |
| 331 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); | 331 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 332 | if (fabs(inaccuracy) > EPSILON) { | 332 | if (fabsf(inaccuracy) > EPSILON) { |
| 333 | std::cout << __FILE__ << ":" << __LINE__ | 333 | std::cout << __FILE__ << ":" << __LINE__ |
| 334 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint | 334 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 335 | << " actual = " << collision->_contactPoint << std::endl; | 335 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -343,7 +343,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 7 unmodified lines | |||
| 343 | } else { | 343 | } else { |
| 344 | ++numCollisions; | 344 | ++numCollisions; |
| 345 | } | 345 | } |
| 346 | 346 | ||
| 347 | // penetration points from sphereA into capsuleB | 347 | // penetration points from sphereA into capsuleB |
| 348 | collision = collisions.getCollision(numCollisions - 1); | 348 | collision = collisions.getCollision(numCollisions - 1); |
| 349 | expectedPenetration = ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; | 349 | expectedPenetration = ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; |
| @@ -352,12 +352,12 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 2 unmodified lines | |||
| 352 | expectedPenetration *= -1.0f; | 352 | expectedPenetration *= -1.0f; |
| 353 | } | 353 | } |
| 354 | inaccuracy = glm::length(collision->_penetration - expectedPenetration); | 354 | inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 355 | if (fabs(inaccuracy) > EPSILON) { | 355 | if (fabsf(inaccuracy) > EPSILON) { |
| 356 | std::cout << __FILE__ << ":" << __LINE__ | 356 | std::cout << __FILE__ << ":" << __LINE__ |
| 357 | << " ERROR: bad penetration: expected = " << expectedPenetration | 357 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 358 | << " actual = " << collision->_penetration << std::endl; | 358 | << " actual = " << collision->_penetration << std::endl; |
| 359 | } | 359 | } |
| 360 | 360 | ||
| 361 | // contactPoint is on surface of capsuleB | 361 | // contactPoint is on surface of capsuleB |
| 362 | glm::vec3 endPoint; | 362 | glm::vec3 endPoint; |
| 363 | capsuleB.getEndPoint(endPoint); | 363 | capsuleB.getEndPoint(endPoint); |
| @@ -367,7 +367,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 3 unmodified lines | |||
| 367 | expectedContactPoint = axialOffset - radiusA * yAxis; | 367 | expectedContactPoint = axialOffset - radiusA * yAxis; |
| 368 | } | 368 | } |
| 369 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); | 369 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 370 | if (fabs(inaccuracy) > EPSILON) { | 370 | if (fabsf(inaccuracy) > EPSILON) { |
| 371 | std::cout << __FILE__ << ":" << __LINE__ | 371 | std::cout << __FILE__ << ":" << __LINE__ |
| 372 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint | 372 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 373 | << " actual = " << collision->_contactPoint << std::endl; | 373 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -376,7 +376,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 2 unmodified lines | |||
| 376 | { // sphereA hits start cap at axis | 376 | { // sphereA hits start cap at axis |
| 377 | glm::vec3 axialOffset = - (halfHeightB + alpha * radiusA + beta * radiusB) * yAxis; | 377 | glm::vec3 axialOffset = - (halfHeightB + alpha * radiusA + beta * radiusB) * yAxis; |
| 378 | sphereA.setTranslation(axialOffset); | 378 | sphereA.setTranslation(axialOffset); |
| 379 | 379 | ||
| 380 | if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions)) | 380 | if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions)) |
| 381 | { | 381 | { |
| 382 | std::cout << __FILE__ << ":" << __LINE__ | 382 | std::cout << __FILE__ << ":" << __LINE__ |
| @@ -384,21 +384,21 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 1 unmodified line | |||
| 384 | } else { | 384 | } else { |
| 385 | ++numCollisions; | 385 | ++numCollisions; |
| 386 | } | 386 | } |
| 387 | 387 | ||
| 388 | // penetration points from sphereA into capsuleB | 388 | // penetration points from sphereA into capsuleB |
| 389 | CollisionInfo* collision = collisions.getCollision(numCollisions - 1); | 389 | CollisionInfo* collision = collisions.getCollision(numCollisions - 1); |
| 390 | glm::vec3 expectedPenetration = ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; | 390 | glm::vec3 expectedPenetration = ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; |
| 391 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); | 391 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 392 | if (fabs(inaccuracy) > EPSILON) { | 392 | if (fabsf(inaccuracy) > EPSILON) { |
| 393 | std::cout << __FILE__ << ":" << __LINE__ | 393 | std::cout << __FILE__ << ":" << __LINE__ |
| 394 | << " ERROR: bad penetration: expected = " << expectedPenetration | 394 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 395 | << " actual = " << collision->_penetration << std::endl; | 395 | << " actual = " << collision->_penetration << std::endl; |
| 396 | } | 396 | } |
| 397 | 397 | ||
| 398 | // contactPoint is on surface of sphereA | 398 | // contactPoint is on surface of sphereA |
| 399 | glm::vec3 expectedContactPoint = sphereA.getTranslation() + radiusA * yAxis; | 399 | glm::vec3 expectedContactPoint = sphereA.getTranslation() + radiusA * yAxis; |
| 400 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); | 400 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 401 | if (fabs(inaccuracy) > EPSILON) { | 401 | if (fabsf(inaccuracy) > EPSILON) { |
| 402 | std::cout << __FILE__ << ":" << __LINE__ | 402 | std::cout << __FILE__ << ":" << __LINE__ |
| 403 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint | 403 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 404 | << " actual = " << collision->_contactPoint << std::endl; | 404 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -412,7 +412,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 7 unmodified lines | |||
| 412 | } else { | 412 | } else { |
| 413 | ++numCollisions; | 413 | ++numCollisions; |
| 414 | } | 414 | } |
| 415 | 415 | ||
| 416 | // penetration points from sphereA into capsuleB | 416 | // penetration points from sphereA into capsuleB |
| 417 | collision = collisions.getCollision(numCollisions - 1); | 417 | collision = collisions.getCollision(numCollisions - 1); |
| 418 | expectedPenetration = - ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; | 418 | expectedPenetration = - ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; |
| @@ -421,12 +421,12 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 2 unmodified lines | |||
| 421 | expectedPenetration *= -1.0f; | 421 | expectedPenetration *= -1.0f; |
| 422 | } | 422 | } |
| 423 | inaccuracy = glm::length(collision->_penetration - expectedPenetration); | 423 | inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 424 | if (fabs(inaccuracy) > EPSILON) { | 424 | if (fabsf(inaccuracy) > EPSILON) { |
| 425 | std::cout << __FILE__ << ":" << __LINE__ | 425 | std::cout << __FILE__ << ":" << __LINE__ |
| 426 | << " ERROR: bad penetration: expected = " << expectedPenetration | 426 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 427 | << " actual = " << collision->_penetration << std::endl; | 427 | << " actual = " << collision->_penetration << std::endl; |
| 428 | } | 428 | } |
| 429 | 429 | ||
| 430 | // contactPoint is on surface of capsuleB | 430 | // contactPoint is on surface of capsuleB |
| 431 | glm::vec3 startPoint; | 431 | glm::vec3 startPoint; |
| 432 | capsuleB.getStartPoint(startPoint); | 432 | capsuleB.getStartPoint(startPoint); |
| @@ -436,7 +436,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 3 unmodified lines | |||
| 436 | expectedContactPoint = axialOffset + radiusA * yAxis; | 436 | expectedContactPoint = axialOffset + radiusA * yAxis; |
| 437 | } | 437 | } |
| 438 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); | 438 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 439 | if (fabs(inaccuracy) > EPSILON) { | 439 | if (fabsf(inaccuracy) > EPSILON) { |
| 440 | std::cout << __FILE__ << ":" << __LINE__ | 440 | std::cout << __FILE__ << ":" << __LINE__ |
| 441 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint | 441 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 442 | << " actual = " << collision->_contactPoint << std::endl; | 442 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -600,19 +600,19 @@ void ShapeColliderTests::capsuleTouchesCapsule() { · 157 unmodified lines | |||
| 600 | } else { | 600 | } else { |
| 601 | ++numCollisions; | 601 | ++numCollisions; |
| 602 | } | 602 | } |
| 603 | 603 | ||
| 604 | CollisionInfo* collision = collisions.getCollision(numCollisions - 1); | 604 | CollisionInfo* collision = collisions.getCollision(numCollisions - 1); |
| 605 | glm::vec3 expectedPenetration = overlap * xAxis; | 605 | glm::vec3 expectedPenetration = overlap * xAxis; |
| 606 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); | 606 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 607 | if (fabs(inaccuracy) > EPSILON) { | 607 | if (fabsf(inaccuracy) > EPSILON) { |
| 608 | std::cout << __FILE__ << ":" << __LINE__ | 608 | std::cout << __FILE__ << ":" << __LINE__ |
| 609 | << " ERROR: bad penetration: expected = " << expectedPenetration | 609 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 610 | << " actual = " << collision->_penetration << std::endl; | 610 | << " actual = " << collision->_penetration << std::endl; |
| 611 | } | 611 | } |
| 612 | 612 | ||
| 613 | glm::vec3 expectedContactPoint = capsuleA.getTranslation() + radiusA * xAxis; | 613 | glm::vec3 expectedContactPoint = capsuleA.getTranslation() + radiusA * xAxis; |
| 614 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); | 614 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 615 | if (fabs(inaccuracy) > EPSILON) { | 615 | if (fabsf(inaccuracy) > EPSILON) { |
| 616 | std::cout << __FILE__ << ":" << __LINE__ | 616 | std::cout << __FILE__ << ":" << __LINE__ |
| 617 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint | 617 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 618 | << " actual = " << collision->_contactPoint << std::endl; | 618 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -626,19 +626,19 @@ void ShapeColliderTests::capsuleTouchesCapsule() { · 7 unmodified lines | |||
| 626 | } else { | 626 | } else { |
| 627 | ++numCollisions; | 627 | ++numCollisions; |
| 628 | } | 628 | } |
| 629 | 629 | ||
| 630 | collision = collisions.getCollision(numCollisions - 1); | 630 | collision = collisions.getCollision(numCollisions - 1); |
| 631 | expectedPenetration = - overlap * xAxis; | 631 | expectedPenetration = - overlap * xAxis; |
| 632 | inaccuracy = glm::length(collision->_penetration - expectedPenetration); | 632 | inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 633 | if (fabs(inaccuracy) > EPSILON) { | 633 | if (fabsf(inaccuracy) > EPSILON) { |
| 634 | std::cout << __FILE__ << ":" << __LINE__ | 634 | std::cout << __FILE__ << ":" << __LINE__ |
| 635 | << " ERROR: bad penetration: expected = " << expectedPenetration | 635 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 636 | << " actual = " << collision->_penetration << std::endl; | 636 | << " actual = " << collision->_penetration << std::endl; |
| 637 | } | 637 | } |
| 638 | 638 | ||
| 639 | expectedContactPoint = capsuleB.getTranslation() - (radiusB + halfHeightB) * xAxis; | 639 | expectedContactPoint = capsuleB.getTranslation() - (radiusB + halfHeightB) * xAxis; |
| 640 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); | 640 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 641 | if (fabs(inaccuracy) > EPSILON) { | 641 | if (fabsf(inaccuracy) > EPSILON) { |
| 642 | std::cout << __FILE__ << ":" << __LINE__ | 642 | std::cout << __FILE__ << ":" << __LINE__ |
| 643 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint | 643 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 644 | << " actual = " << collision->_contactPoint << std::endl; | 644 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -661,19 +661,19 @@ void ShapeColliderTests::capsuleTouchesCapsule() { · 16 unmodified lines | |||
| 661 | } else { | 661 | } else { |
| 662 | ++numCollisions; | 662 | ++numCollisions; |
| 663 | } | 663 | } |
| 664 | 664 | ||
| 665 | CollisionInfo* collision = collisions.getCollision(numCollisions - 1); | 665 | CollisionInfo* collision = collisions.getCollision(numCollisions - 1); |
| 666 | glm::vec3 expectedPenetration = overlap * zAxis; | 666 | glm::vec3 expectedPenetration = overlap * zAxis; |
| 667 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); | 667 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 668 | if (fabs(inaccuracy) > EPSILON) { | 668 | if (fabsf(inaccuracy) > EPSILON) { |
| 669 | std::cout << __FILE__ << ":" << __LINE__ | 669 | std::cout << __FILE__ << ":" << __LINE__ |
| 670 | << " ERROR: bad penetration: expected = " << expectedPenetration | 670 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 671 | << " actual = " << collision->_penetration << std::endl; | 671 | << " actual = " << collision->_penetration << std::endl; |
| 672 | } | 672 | } |
| 673 | 673 | ||
| 674 | glm::vec3 expectedContactPoint = capsuleA.getTranslation() + radiusA * zAxis + shift * yAxis; | 674 | glm::vec3 expectedContactPoint = capsuleA.getTranslation() + radiusA * zAxis + shift * yAxis; |
| 675 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); | 675 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 676 | if (fabs(inaccuracy) > EPSILON) { | 676 | if (fabsf(inaccuracy) > EPSILON) { |
| 677 | std::cout << __FILE__ << ":" << __LINE__ | 677 | std::cout << __FILE__ << ":" << __LINE__ |
| 678 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint | 678 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 679 | << " actual = " << collision->_contactPoint << std::endl; | 679 | << " actual = " << collision->_contactPoint << std::endl; |
| @@ -683,7 +683,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() { · 3 unmodified lines | |||
| 683 | 683 | ||
| 684 | void ShapeColliderTests::sphereMissesAACube() { | 684 | void ShapeColliderTests::sphereMissesAACube() { |
| 685 | CollisionList collisions(16); | 685 | CollisionList collisions(16); |
| 686 | 686 | ||
| 687 | float sphereRadius = 1.0f; | 687 | float sphereRadius = 1.0f; |
| 688 | glm::vec3 sphereCenter(0.0f); | 688 | glm::vec3 sphereCenter(0.0f); |
| 689 | 689 | ||
| @@ -702,7 +702,7 @@ void ShapeColliderTests::sphereMissesAACube() { · 12 unmodified lines | |||
| 702 | 702 | ||
| 703 | sphereCenter = cubeCenter + (0.5f * cubeSide + sphereRadius + offset) * faceNormal; | 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 | cubeCenter, cubeSide, collisions); | 706 | cubeCenter, cubeSide, collisions); |
| 707 | 707 | ||
| 708 | if (collision) { | 708 | if (collision) { |
| @@ -742,9 +742,9 @@ void ShapeColliderTests::sphereMissesAACube() { · 33 unmodified lines | |||
| 742 | for (int m = 0; m < numSteps; ++m) { | 742 | for (int m = 0; m < numSteps; ++m) { |
| 743 | sphereCenter = startPosition + ((float)m * delta) * thirdNormal + (sphereRadius + offset) * edgeNormal; | 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 | cubeCenter, cubeSide, collisions); | 746 | cubeCenter, cubeSide, collisions); |
| 747 | 747 | ||
| 748 | if (collision) { | 748 | if (collision) { |
| 749 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube edge." | 749 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube edge." |
| 750 | << " edgeNormal = " << edgeNormal << std::endl; | 750 | << " edgeNormal = " << edgeNormal << std::endl; |
| @@ -779,10 +779,10 @@ void ShapeColliderTests::sphereMissesAACube() { · 28 unmodified lines | |||
| 779 | glm::quat rotation = glm::angleAxis(angle, cornerNormal); | 779 | glm::quat rotation = glm::angleAxis(angle, cornerNormal); |
| 780 | glm::vec3 offsetAxis = rotation * nearbyAxis; | 780 | glm::vec3 offsetAxis = rotation * nearbyAxis; |
| 781 | sphereCenter = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide) * cornerNormal + (sphereRadius + offset) * offsetAxis; | 781 | sphereCenter = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide) * cornerNormal + (sphereRadius + offset) * offsetAxis; |
| 782 | 782 | ||
| 783 | CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, | 783 | CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, |
| 784 | cubeCenter, cubeSide, collisions); | 784 | cubeCenter, cubeSide, collisions); |
| 785 | 785 | ||
| 786 | if (collision) { | 786 | if (collision) { |
| 787 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube corner." | 787 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube corner." |
| 788 | << " cornerNormal = " << cornerNormal << std::endl; | 788 | << " cornerNormal = " << cornerNormal << std::endl; |
| @@ -796,7 +796,7 @@ void ShapeColliderTests::sphereMissesAACube() { · 7 unmodified lines | |||
| 796 | 796 | ||
| 797 | void ShapeColliderTests::sphereTouchesAACubeFaces() { | 797 | void ShapeColliderTests::sphereTouchesAACubeFaces() { |
| 798 | CollisionList collisions(16); | 798 | CollisionList collisions(16); |
| 799 | 799 | ||
| 800 | float sphereRadius = 1.13f; | 800 | float sphereRadius = 1.13f; |
| 801 | glm::vec3 sphereCenter(0.0f); | 801 | glm::vec3 sphereCenter(0.0f); |
| 802 | 802 | ||
| @@ -817,38 +817,38 @@ void ShapeColliderTests::sphereTouchesAACubeFaces() { · 14 unmodified lines | |||
| 817 | float parallelOffset = 0.5f * cubeSide + sphereRadius - overlap; | 817 | float parallelOffset = 0.5f * cubeSide + sphereRadius - overlap; |
| 818 | float perpOffset = 0.25f * cubeSide; | 818 | float perpOffset = 0.25f * cubeSide; |
| 819 | glm::vec3 expectedPenetration = - overlap * faceNormal; | 819 | glm::vec3 expectedPenetration = - overlap * faceNormal; |
| 820 | 820 | ||
| 821 | // We rotate the position of the sphereCenter about a circle on the cube face so that | 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 | 822 | // it hits the same face in multiple spots. The penetration should be invarient for |
| 823 | // all collisions. | 823 | // all collisions. |
| 824 | float delta = TWO_PI / 4.0f; | 824 | float delta = TWO_PI / 4.0f; |
| 825 | for (float angle = 0; angle < TWO_PI + EPSILON; angle += delta) { | 825 | for (float angle = 0; angle < TWO_PI + EPSILON; angle += delta) { |
| 826 | glm::quat rotation = glm::angleAxis(angle, faceNormal); | 826 | glm::quat rotation = glm::angleAxis(angle, faceNormal); |
| 827 | glm::vec3 perpAxis = rotation * faceNormals[(i + 1) % numDirections]; | 827 | glm::vec3 perpAxis = rotation * faceNormals[(i + 1) % numDirections]; |
| 828 | 828 | ||
| 829 | sphereCenter = cubeCenter + parallelOffset * faceNormal + perpOffset * perpAxis; | 829 | sphereCenter = cubeCenter + parallelOffset * faceNormal + perpOffset * perpAxis; |
| 830 | 830 | ||
| 831 | CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, | 831 | CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, |
| 832 | cubeCenter, cubeSide, collisions); | 832 | cubeCenter, cubeSide, collisions); |
| 833 | 833 | ||
| 834 | if (!collision) { | 834 | if (!collision) { |
| 835 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide outside cube face." | 835 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide outside cube face." |
| 836 | << " faceNormal = " << faceNormal | 836 | << " faceNormal = " << faceNormal |
| 837 | << std::endl; | 837 | << std::endl; |
| 838 | break; | 838 | break; |
| 839 | } | 839 | } |
| 840 | 840 | ||
| 841 | if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) { | 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 | << " expected " << expectedPenetration << " faceNormal = " << faceNormal << std::endl; | 843 | << " expected " << expectedPenetration << " faceNormal = " << faceNormal << std::endl; |
| 844 | } | 844 | } |
| 845 | 845 | ||
| 846 | glm::vec3 expectedContact = sphereCenter - sphereRadius * faceNormal; | 846 | glm::vec3 expectedContact = sphereCenter - sphereRadius * faceNormal; |
| 847 | if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) { | 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 | << " expected " << expectedContact << " faceNormal = " << faceNormal << std::endl; | 849 | << " expected " << expectedContact << " faceNormal = " << faceNormal << std::endl; |
| 850 | } | 850 | } |
| 851 | 851 | ||
| 852 | if (collision->getShapeA()) { | 852 | if (collision->getShapeA()) { |
| 853 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: collision->_shapeA should be NULL" << std::endl; | 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 | // inside | 861 | // inside |
| 862 | { | 862 | { |
| 863 | collisions.clear(); | 863 | collisions.clear(); |
| 864 | float overlap = 1.25f * sphereRadius; | 864 | float overlap = 1.25f * sphereRadius; |
| 865 | float sphereOffset = 0.5f * cubeSide + sphereRadius - overlap; | 865 | float sphereOffset = 0.5f * cubeSide + sphereRadius - overlap; |
| 866 | sphereCenter = cubeCenter + sphereOffset * faceNormal; | 866 | sphereCenter = cubeCenter + sphereOffset * faceNormal; |
| 867 | 867 | ||
| 868 | CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, | 868 | CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, |
| 869 | cubeCenter, cubeSide, collisions); | 869 | cubeCenter, cubeSide, collisions); |
| 870 | 870 | ||
| 871 | if (!collision) { | 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 | << " faceNormal = " << faceNormal << std::endl; | 873 | << " faceNormal = " << faceNormal << std::endl; |
| 874 | break; | 874 | break; |
| 875 | } | 875 | } |
| 876 | 876 | ||
| 877 | glm::vec3 expectedPenetration = - overlap * faceNormal; | 877 | glm::vec3 expectedPenetration = - overlap * faceNormal; |
| 878 | if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) { | 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 | << " expected " << expectedPenetration << " faceNormal = " << faceNormal << std::endl; | 880 | << " expected " << expectedPenetration << " faceNormal = " << faceNormal << std::endl; |
| 881 | } | 881 | } |
| 882 | 882 | ||
| 883 | glm::vec3 expectedContact = sphereCenter - sphereRadius * faceNormal; | 883 | glm::vec3 expectedContact = sphereCenter - sphereRadius * faceNormal; |
| 884 | if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) { | 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 | << " expected " << expectedContact << " faceNormal = " << faceNormal << std::endl; | 886 | << " expected " << expectedContact << " faceNormal = " << faceNormal << std::endl; |
| 887 | } | 887 | } |
| 888 | } | 888 | } |
| @@ -892,14 +892,14 @@ void ShapeColliderTests::sphereTouchesAACubeFaces() { · 3 unmodified lines | |||
| 892 | 892 | ||
| 893 | void ShapeColliderTests::sphereTouchesAACubeEdges() { | 893 | void ShapeColliderTests::sphereTouchesAACubeEdges() { |
| 894 | CollisionList collisions(20); | 894 | CollisionList collisions(20); |
| 895 | 895 | ||
| 896 | float sphereRadius = 1.37f; | 896 | float sphereRadius = 1.37f; |
| 897 | glm::vec3 sphereCenter(0.0f); | 897 | glm::vec3 sphereCenter(0.0f); |
| 898 | 898 | ||
| 899 | glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f); | 899 | glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f); |
| 900 | float cubeSide = 2.98f; | 900 | float cubeSide = 2.98f; |
| 901 | 901 | ||
| 902 | float overlap = 0.25 * sphereRadius; | 902 | float overlap = 0.25f * sphereRadius; |
| 903 | int numSteps = 5; | 903 | int numSteps = 5; |
| 904 | 904 | ||
| 905 | glm::vec3 faceNormals[] = {xAxis, yAxis, zAxis}; | 905 | glm::vec3 faceNormals[] = {xAxis, yAxis, zAxis}; |
| @@ -935,23 +935,23 @@ void ShapeColliderTests::sphereTouchesAACubeEdges() { · 29 unmodified lines | |||
| 935 | for (int m = 0; m < numSteps; ++m) { | 935 | for (int m = 0; m < numSteps; ++m) { |
| 936 | sphereCenter = startPosition + ((float)m * delta) * thirdNormal + (sphereRadius - overlap) * edgeNormal; | 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 | cubeCenter, cubeSide, collisions); | 939 | cubeCenter, cubeSide, collisions); |
| 940 | 940 | ||
| 941 | if (!collision) { | 941 | if (!collision) { |
| 942 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube edge." | 942 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube edge." |
| 943 | << " edgeNormal = " << edgeNormal << std::endl; | 943 | << " edgeNormal = " << edgeNormal << std::endl; |
| 944 | break; | 944 | break; |
| 945 | } | 945 | } |
| 946 | 946 | ||
| 947 | if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) { | 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 | << " expected " << expectedPenetration << " edgeNormal = " << edgeNormal << std::endl; | 949 | << " expected " << expectedPenetration << " edgeNormal = " << edgeNormal << std::endl; |
| 950 | } | 950 | } |
| 951 | 951 | ||
| 952 | glm::vec3 expectedContact = sphereCenter - sphereRadius * edgeNormal; | 952 | glm::vec3 expectedContact = sphereCenter - sphereRadius * edgeNormal; |
| 953 | if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) { | 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 | << " expected " << expectedContact << " edgeNormal = " << edgeNormal << std::endl; | 955 | << " expected " << expectedContact << " edgeNormal = " << edgeNormal << std::endl; |
| 956 | } | 956 | } |
| 957 | } | 957 | } |
| @@ -963,14 +963,14 @@ void ShapeColliderTests::sphereTouchesAACubeEdges() { · 5 unmodified lines | |||
| 963 | 963 | ||
| 964 | void ShapeColliderTests::sphereTouchesAACubeCorners() { | 964 | void ShapeColliderTests::sphereTouchesAACubeCorners() { |
| 965 | CollisionList collisions(20); | 965 | CollisionList collisions(20); |
| 966 | 966 | ||
| 967 | float sphereRadius = 1.37f; | 967 | float sphereRadius = 1.37f; |
| 968 | glm::vec3 sphereCenter(0.0f); | 968 | glm::vec3 sphereCenter(0.0f); |
| 969 | 969 | ||
| 970 | glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f); | 970 | glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f); |
| 971 | float cubeSide = 2.98f; | 971 | float cubeSide = 2.98f; |
| 972 | 972 | ||
| 973 | float overlap = 0.25 * sphereRadius; | 973 | float overlap = 0.25f * sphereRadius; |
| 974 | int numSteps = 5; | 974 | int numSteps = 5; |
| 975 | 975 | ||
| 976 | glm::vec3 faceNormals[] = {xAxis, yAxis, zAxis}; | 976 | glm::vec3 faceNormals[] = {xAxis, yAxis, zAxis}; |
| @@ -997,25 +997,25 @@ void ShapeColliderTests::sphereTouchesAACubeCorners() { · 20 unmodified lines | |||
| 997 | glm::quat rotation = glm::angleAxis(angle, cornerNormal); | 997 | glm::quat rotation = glm::angleAxis(angle, cornerNormal); |
| 998 | glm::vec3 offsetAxis = rotation * nearbyAxis; | 998 | glm::vec3 offsetAxis = rotation * nearbyAxis; |
| 999 | sphereCenter = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide) * cornerNormal + (sphereRadius - overlap) * offsetAxis; | 999 | sphereCenter = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide) * cornerNormal + (sphereRadius - overlap) * offsetAxis; |
| 1000 | 1000 | ||
| 1001 | CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, | 1001 | CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, |
| 1002 | cubeCenter, cubeSide, collisions); | 1002 | cubeCenter, cubeSide, collisions); |
| 1003 | 1003 | ||
| 1004 | if (!collision) { | 1004 | if (!collision) { |
| 1005 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube corner." | 1005 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube corner." |
| 1006 | << " cornerNormal = " << cornerNormal << std::endl; | 1006 | << " cornerNormal = " << cornerNormal << std::endl; |
| 1007 | break; | 1007 | break; |
| 1008 | } | 1008 | } |
| 1009 | 1009 | ||
| 1010 | glm::vec3 expectedPenetration = - overlap * offsetAxis; | 1010 | glm::vec3 expectedPenetration = - overlap * offsetAxis; |
| 1011 | if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) { | 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 | << " expected " << expectedPenetration << " cornerNormal = " << cornerNormal << std::endl; | 1013 | << " expected " << expectedPenetration << " cornerNormal = " << cornerNormal << std::endl; |
| 1014 | } | 1014 | } |
| 1015 | 1015 | ||
| 1016 | glm::vec3 expectedContact = sphereCenter - sphereRadius * offsetAxis; | 1016 | glm::vec3 expectedContact = sphereCenter - sphereRadius * offsetAxis; |
| 1017 | if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) { | 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 | << " expected " << expectedContact << " cornerNormal = " << cornerNormal << std::endl; | 1019 | << " expected " << expectedContact << " cornerNormal = " << cornerNormal << std::endl; |
| 1020 | } | 1020 | } |
| 1021 | } | 1021 | } |
| @@ -1026,7 +1026,7 @@ void ShapeColliderTests::sphereTouchesAACubeCorners() { · 4 unmodified lines | |||
| 1026 | 1026 | ||
| 1027 | void ShapeColliderTests::capsuleMissesAACube() { | 1027 | void ShapeColliderTests::capsuleMissesAACube() { |
| 1028 | CollisionList collisions(16); | 1028 | CollisionList collisions(16); |
| 1029 | 1029 | ||
| 1030 | float capsuleRadius = 1.0f; | 1030 | float capsuleRadius = 1.0f; |
| 1031 | 1031 | ||
| 1032 | glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f); | 1032 | glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f); |
| @@ -1046,7 +1046,7 @@ void ShapeColliderTests::capsuleMissesAACube() { · 13 unmodified lines | |||
| 1046 | glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections]; | 1046 | glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections]; |
| 1047 | 1047 | ||
| 1048 | // pick a random point somewhere above the face | 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 | (cubeSide * (randFloat() - 0.5f)) * secondNormal + | 1050 | (cubeSide * (randFloat() - 0.5f)) * secondNormal + |
| 1051 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; | 1051 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1052 | 1052 | ||
| @@ -1097,23 +1097,23 @@ void ShapeColliderTests::capsuleMissesAACube() { · 44 unmodified lines | |||
| 1097 | glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal); | 1097 | glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal); |
| 1098 | 1098 | ||
| 1099 | // pick a random point somewhere above the edge | 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 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; | 1101 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1102 | 1102 | ||
| 1103 | // pick a second random point slightly more than one radius above the edge | 1103 | // pick a second random point slightly more than one radius above the edge |
| 1104 | glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide + capsuleRadius + offset) * edgeNormal + | 1104 | glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide + capsuleRadius + offset) * edgeNormal + |
| 1105 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; | 1105 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1106 | 1106 | ||
| 1107 | // randomly swap the points so capsule axis may point toward or away from edge | 1107 | // randomly swap the points so capsule axis may point toward or away from edge |
| 1108 | if (randFloat() > 0.5f) { | 1108 | if (randFloat() > 0.5f) { |
| 1109 | glm::vec3 temp = startPoint; | 1109 | glm::vec3 temp = startPoint; |
| 1110 | startPoint = endPoint; | 1110 | startPoint = endPoint; |
| 1111 | endPoint = temp; | 1111 | endPoint = temp; |
| 1112 | } | 1112 | } |
| 1113 | 1113 | ||
| 1114 | // create a capsule between the points | 1114 | // create a capsule between the points |
| 1115 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); | 1115 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); |
| 1116 | 1116 | ||
| 1117 | // collide capsule with cube | 1117 | // collide capsule with cube |
| 1118 | bool hit = ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions); | 1118 | bool hit = ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions); |
| 1119 | if (hit) { | 1119 | if (hit) { |
| @@ -1138,24 +1138,24 @@ void ShapeColliderTests::capsuleMissesAACube() { · 18 unmodified lines | |||
| 1138 | glm::vec3 cornerNormal = glm::normalize(firstNormal + secondNormal + thirdNormal); | 1138 | glm::vec3 cornerNormal = glm::normalize(firstNormal + secondNormal + thirdNormal); |
| 1139 | 1139 | ||
| 1140 | // pick a random point somewhere above the corner | 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 | (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal + | 1142 | (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal + |
| 1143 | (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal + | 1143 | (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal + |
| 1144 | (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal; | 1144 | (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1145 | 1145 | ||
| 1146 | // pick a second random point slightly more than one radius above the corner | 1146 | // pick a second random point slightly more than one radius above the corner |
| 1147 | glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide + capsuleRadius + offset) * cornerNormal; | 1147 | glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide + capsuleRadius + offset) * cornerNormal; |
| 1148 | 1148 | ||
| 1149 | // randomly swap the points so capsule axis may point toward or away from corner | 1149 | // randomly swap the points so capsule axis may point toward or away from corner |
| 1150 | if (randFloat() > 0.5f) { | 1150 | if (randFloat() > 0.5f) { |
| 1151 | glm::vec3 temp = startPoint; | 1151 | glm::vec3 temp = startPoint; |
| 1152 | startPoint = endPoint; | 1152 | startPoint = endPoint; |
| 1153 | endPoint = temp; | 1153 | endPoint = temp; |
| 1154 | } | 1154 | } |
| 1155 | 1155 | ||
| 1156 | // create a capsule between the points | 1156 | // create a capsule between the points |
| 1157 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); | 1157 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); |
| 1158 | 1158 | ||
| 1159 | // collide capsule with cube | 1159 | // collide capsule with cube |
| 1160 | if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { | 1160 | if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { |
| 1161 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube face." | 1161 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube face." |
| @@ -1190,7 +1190,7 @@ void ShapeColliderTests::capsuleMissesAACube() { · 28 unmodified lines | |||
| 1190 | glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal); | 1190 | glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal); |
| 1191 | 1191 | ||
| 1192 | // pick a random point somewhere along the edge | 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 | ((cubeSide - 2.0f * offset) * (randFloat() - 0.5f)) * thirdNormal; | 1194 | ((cubeSide - 2.0f * offset) * (randFloat() - 0.5f)) * thirdNormal; |
| 1195 | 1195 | ||
| 1196 | // pick a random normal that is deflected slightly from edgeNormal | 1196 | // pick a random normal that is deflected slightly from edgeNormal |
| @@ -1207,10 +1207,10 @@ void ShapeColliderTests::capsuleMissesAACube() { · 10 unmodified lines | |||
| 1207 | // now we can compute the capsule endpoints | 1207 | // now we can compute the capsule endpoints |
| 1208 | glm::vec3 endPoint = axisPoint + (0.5f * capsuleLength * randFloat()) * axisDirection; | 1208 | glm::vec3 endPoint = axisPoint + (0.5f * capsuleLength * randFloat()) * axisDirection; |
| 1209 | glm::vec3 startPoint = axisPoint - (0.5f * capsuleLength * randFloat()) * axisDirection; | 1209 | glm::vec3 startPoint = axisPoint - (0.5f * capsuleLength * randFloat()) * axisDirection; |
| 1210 | 1210 | ||
| 1211 | // create a capsule between the points | 1211 | // create a capsule between the points |
| 1212 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); | 1212 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); |
| 1213 | 1213 | ||
| 1214 | // collide capsule with cube | 1214 | // collide capsule with cube |
| 1215 | if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { | 1215 | if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { |
| 1216 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube" | 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 | // pick a random point somewhere above the corner | 1242 | // pick a random point somewhere above the corner |
| 1243 | glm::vec3 corner = cubeCenter + (0.5f * cubeSide) * (firstNormal + secondNormal + thirdNormal); | 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 | (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal + | 1245 | (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal + |
| 1246 | (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal + | 1246 | (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal + |
| 1247 | (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal; | 1247 | (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| @@ -1256,10 +1256,10 @@ void ShapeColliderTests::capsuleMissesAACube() { · 8 unmodified lines | |||
| 1256 | startPoint = endPoint; | 1256 | startPoint = endPoint; |
| 1257 | endPoint = temp; | 1257 | endPoint = temp; |
| 1258 | } | 1258 | } |
| 1259 | 1259 | ||
| 1260 | // create a capsule between the points | 1260 | // create a capsule between the points |
| 1261 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); | 1261 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); |
| 1262 | 1262 | ||
| 1263 | // collide capsule with cube | 1263 | // collide capsule with cube |
| 1264 | if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { | 1264 | if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { |
| 1265 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube" | 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 | // these are the steps along the capsuleAxis where we'll put the capsule endpoints | 1273 | // these are the steps along the capsuleAxis where we'll put the capsule endpoints |
| 1274 | float steps[] = { -1.0f, 2.0f, 0.25f, 0.75f, -1.0f }; | 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 | glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections]; | 1280 | glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections]; |
| 1281 | 1281 | ||
| 1282 | // pick two random point on opposite edges of the face | 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 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; | 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 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; | 1286 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1287 | 1287 | ||
| 1288 | // compute the un-normalized axis for the capsule | 1288 | // compute the un-normalized axis for the capsule |
| @@ -1309,7 +1309,7 @@ void ShapeColliderTests::capsuleMissesAACube() { · 20 unmodified lines | |||
| 1309 | 1309 | ||
| 1310 | void ShapeColliderTests::capsuleTouchesAACube() { | 1310 | void ShapeColliderTests::capsuleTouchesAACube() { |
| 1311 | CollisionList collisions(16); | 1311 | CollisionList collisions(16); |
| 1312 | 1312 | ||
| 1313 | float capsuleRadius = 1.0f; | 1313 | float capsuleRadius = 1.0f; |
| 1314 | 1314 | ||
| 1315 | glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f); | 1315 | glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f); |
| @@ -1330,12 +1330,12 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 14 unmodified lines | |||
| 1330 | glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections]; | 1330 | glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections]; |
| 1331 | 1331 | ||
| 1332 | // pick a random point somewhere above the face | 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 | (cubeSide * (randFloat() - 0.5f)) * secondNormal + | 1334 | (cubeSide * (randFloat() - 0.5f)) * secondNormal + |
| 1335 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; | 1335 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1336 | 1336 | ||
| 1337 | // pick a second random point slightly less than one radius above the face | 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 | // registering against other faces) | 1339 | // registering against other faces) |
| 1340 | glm::vec3 endPoint = cubeCenter + (0.5f * cubeSide + capsuleRadius - overlap) * faceNormal + | 1340 | glm::vec3 endPoint = cubeCenter + (0.5f * cubeSide + capsuleRadius - overlap) * faceNormal + |
| 1341 | ((cubeSide - 2.0f * overlap) * (randFloat() - 0.5f)) * secondNormal + | 1341 | ((cubeSide - 2.0f * overlap) * (randFloat() - 0.5f)) * secondNormal + |
| @@ -1365,25 +1365,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 23 unmodified lines | |||
| 1365 | << " ERROR: null collision with faceNormal = " << faceNormal << std::endl; | 1365 | << " ERROR: null collision with faceNormal = " << faceNormal << std::endl; |
| 1366 | return; | 1366 | return; |
| 1367 | } | 1367 | } |
| 1368 | 1368 | ||
| 1369 | // penetration points from capsule into cube | 1369 | // penetration points from capsule into cube |
| 1370 | glm::vec3 expectedPenetration = - overlap * faceNormal; | 1370 | glm::vec3 expectedPenetration = - overlap * faceNormal; |
| 1371 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); | 1371 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 1372 | if (fabs(inaccuracy) > allowableError) { | 1372 | if (fabsf(inaccuracy) > allowableError) { |
| 1373 | std::cout << __FILE__ << ":" << __LINE__ | 1373 | std::cout << __FILE__ << ":" << __LINE__ |
| 1374 | << " ERROR: bad penetration: expected = " << expectedPenetration | 1374 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 1375 | << " actual = " << collision->_penetration | 1375 | << " actual = " << collision->_penetration |
| 1376 | << " faceNormal = " << faceNormal | 1376 | << " faceNormal = " << faceNormal |
| 1377 | << std::endl; | 1377 | << std::endl; |
| 1378 | } | 1378 | } |
| 1379 | 1379 | ||
| 1380 | // contactPoint is on surface of capsule | 1380 | // contactPoint is on surface of capsule |
| 1381 | glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * faceNormal; | 1381 | glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * faceNormal; |
| 1382 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); | 1382 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 1383 | if (fabs(inaccuracy) > allowableError) { | 1383 | if (fabsf(inaccuracy) > allowableError) { |
| 1384 | std::cout << __FILE__ << ":" << __LINE__ | 1384 | std::cout << __FILE__ << ":" << __LINE__ |
| 1385 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint | 1385 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 1386 | << " actual = " << collision->_contactPoint | 1386 | << " actual = " << collision->_contactPoint |
| 1387 | << " faceNormal = " << faceNormal | 1387 | << " faceNormal = " << faceNormal |
| 1388 | << std::endl; | 1388 | << std::endl; |
| 1389 | } | 1389 | } |
| @@ -1414,24 +1414,24 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 24 unmodified lines | |||
| 1414 | glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal); | 1414 | glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal); |
| 1415 | 1415 | ||
| 1416 | // pick a random point somewhere above the edge | 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 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; | 1418 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1419 | 1419 | ||
| 1420 | // pick a second random point slightly less than one radius above the edge | 1420 | // pick a second random point slightly less than one radius above the edge |
| 1421 | glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide + capsuleRadius - overlap) * edgeNormal + | 1421 | glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide + capsuleRadius - overlap) * edgeNormal + |
| 1422 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; | 1422 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1423 | glm::vec3 collidingPoint = endPoint; | 1423 | glm::vec3 collidingPoint = endPoint; |
| 1424 | 1424 | ||
| 1425 | // randomly swap the points so capsule axis may point toward or away from edge | 1425 | // randomly swap the points so capsule axis may point toward or away from edge |
| 1426 | if (randFloat() > 0.5f) { | 1426 | if (randFloat() > 0.5f) { |
| 1427 | glm::vec3 temp = startPoint; | 1427 | glm::vec3 temp = startPoint; |
| 1428 | startPoint = endPoint; | 1428 | startPoint = endPoint; |
| 1429 | endPoint = temp; | 1429 | endPoint = temp; |
| 1430 | } | 1430 | } |
| 1431 | 1431 | ||
| 1432 | // create a capsule between the points | 1432 | // create a capsule between the points |
| 1433 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); | 1433 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); |
| 1434 | 1434 | ||
| 1435 | // collide capsule with cube | 1435 | // collide capsule with cube |
| 1436 | if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { | 1436 | if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { |
| 1437 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" | 1437 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" |
| @@ -1444,25 +1444,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 6 unmodified lines | |||
| 1444 | << " ERROR: null collision with edgeNormal = " << edgeNormal << std::endl; | 1444 | << " ERROR: null collision with edgeNormal = " << edgeNormal << std::endl; |
| 1445 | return; | 1445 | return; |
| 1446 | } | 1446 | } |
| 1447 | 1447 | ||
| 1448 | // penetration points from capsule into cube | 1448 | // penetration points from capsule into cube |
| 1449 | glm::vec3 expectedPenetration = - overlap * edgeNormal; | 1449 | glm::vec3 expectedPenetration = - overlap * edgeNormal; |
| 1450 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); | 1450 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 1451 | if (fabs(inaccuracy) > allowableError) { | 1451 | if (fabsf(inaccuracy) > allowableError) { |
| 1452 | std::cout << __FILE__ << ":" << __LINE__ | 1452 | std::cout << __FILE__ << ":" << __LINE__ |
| 1453 | << " ERROR: bad penetration: expected = " << expectedPenetration | 1453 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 1454 | << " actual = " << collision->_penetration | 1454 | << " actual = " << collision->_penetration |
| 1455 | << " edgeNormal = " << edgeNormal | 1455 | << " edgeNormal = " << edgeNormal |
| 1456 | << std::endl; | 1456 | << std::endl; |
| 1457 | } | 1457 | } |
| 1458 | 1458 | ||
| 1459 | // contactPoint is on surface of capsule | 1459 | // contactPoint is on surface of capsule |
| 1460 | glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * edgeNormal; | 1460 | glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * edgeNormal; |
| 1461 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); | 1461 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 1462 | if (fabs(inaccuracy) > allowableError) { | 1462 | if (fabsf(inaccuracy) > allowableError) { |
| 1463 | std::cout << __FILE__ << ":" << __LINE__ | 1463 | std::cout << __FILE__ << ":" << __LINE__ |
| 1464 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint | 1464 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 1465 | << " actual = " << collision->_contactPoint | 1465 | << " actual = " << collision->_contactPoint |
| 1466 | << " edgeNormal = " << edgeNormal | 1466 | << " edgeNormal = " << edgeNormal |
| 1467 | << std::endl; | 1467 | << std::endl; |
| 1468 | } | 1468 | } |
| @@ -1484,25 +1484,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 15 unmodified lines | |||
| 1484 | glm::vec3 cornerNormal = glm::normalize(firstNormal + secondNormal + thirdNormal); | 1484 | glm::vec3 cornerNormal = glm::normalize(firstNormal + secondNormal + thirdNormal); |
| 1485 | 1485 | ||
| 1486 | // pick a random point somewhere above the corner | 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 | (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal + | 1488 | (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal + |
| 1489 | (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal + | 1489 | (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal + |
| 1490 | (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal; | 1490 | (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1491 | 1491 | ||
| 1492 | // pick a second random point slightly less than one radius above the corner | 1492 | // pick a second random point slightly less than one radius above the corner |
| 1493 | glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide + capsuleRadius - overlap) * cornerNormal; | 1493 | glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide + capsuleRadius - overlap) * cornerNormal; |
| 1494 | glm::vec3 collidingPoint = endPoint; | 1494 | glm::vec3 collidingPoint = endPoint; |
| 1495 | 1495 | ||
| 1496 | // randomly swap the points so capsule axis may point toward or away from corner | 1496 | // randomly swap the points so capsule axis may point toward or away from corner |
| 1497 | if (randFloat() > 0.5f) { | 1497 | if (randFloat() > 0.5f) { |
| 1498 | glm::vec3 temp = startPoint; | 1498 | glm::vec3 temp = startPoint; |
| 1499 | startPoint = endPoint; | 1499 | startPoint = endPoint; |
| 1500 | endPoint = temp; | 1500 | endPoint = temp; |
| 1501 | } | 1501 | } |
| 1502 | 1502 | ||
| 1503 | // create a capsule between the points | 1503 | // create a capsule between the points |
| 1504 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); | 1504 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); |
| 1505 | 1505 | ||
| 1506 | // collide capsule with cube | 1506 | // collide capsule with cube |
| 1507 | if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { | 1507 | if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { |
| 1508 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" | 1508 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" |
| @@ -1515,25 +1515,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 6 unmodified lines | |||
| 1515 | << " ERROR: null collision with cornerNormal = " << cornerNormal << std::endl; | 1515 | << " ERROR: null collision with cornerNormal = " << cornerNormal << std::endl; |
| 1516 | return; | 1516 | return; |
| 1517 | } | 1517 | } |
| 1518 | 1518 | ||
| 1519 | // penetration points from capsule into cube | 1519 | // penetration points from capsule into cube |
| 1520 | glm::vec3 expectedPenetration = - overlap * cornerNormal; | 1520 | glm::vec3 expectedPenetration = - overlap * cornerNormal; |
| 1521 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); | 1521 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 1522 | if (fabs(inaccuracy) > allowableError) { | 1522 | if (fabsf(inaccuracy) > allowableError) { |
| 1523 | std::cout << __FILE__ << ":" << __LINE__ | 1523 | std::cout << __FILE__ << ":" << __LINE__ |
| 1524 | << " ERROR: bad penetration: expected = " << expectedPenetration | 1524 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 1525 | << " actual = " << collision->_penetration | 1525 | << " actual = " << collision->_penetration |
| 1526 | << " cornerNormal = " << cornerNormal | 1526 | << " cornerNormal = " << cornerNormal |
| 1527 | << std::endl; | 1527 | << std::endl; |
| 1528 | } | 1528 | } |
| 1529 | 1529 | ||
| 1530 | // contactPoint is on surface of capsule | 1530 | // contactPoint is on surface of capsule |
| 1531 | glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * cornerNormal; | 1531 | glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * cornerNormal; |
| 1532 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); | 1532 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 1533 | if (fabs(inaccuracy) > allowableError) { | 1533 | if (fabsf(inaccuracy) > allowableError) { |
| 1534 | std::cout << __FILE__ << ":" << __LINE__ | 1534 | std::cout << __FILE__ << ":" << __LINE__ |
| 1535 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint | 1535 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 1536 | << " actual = " << collision->_contactPoint | 1536 | << " actual = " << collision->_contactPoint |
| 1537 | << " cornerNormal = " << cornerNormal | 1537 | << " cornerNormal = " << cornerNormal |
| 1538 | << std::endl; | 1538 | << std::endl; |
| 1539 | } | 1539 | } |
| @@ -1566,7 +1566,7 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 26 unmodified lines | |||
| 1566 | glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal); | 1566 | glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal); |
| 1567 | 1567 | ||
| 1568 | // pick a random point somewhere along the edge | 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 | ((cubeSide - 2.0f * overlap) * (randFloat() - 0.5f)) * thirdNormal; | 1570 | ((cubeSide - 2.0f * overlap) * (randFloat() - 0.5f)) * thirdNormal; |
| 1571 | 1571 | ||
| 1572 | // pick a random normal that is deflected slightly from edgeNormal | 1572 | // pick a random normal that is deflected slightly from edgeNormal |
| @@ -1583,10 +1583,10 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 10 unmodified lines | |||
| 1583 | // now we can compute the capsule endpoints | 1583 | // now we can compute the capsule endpoints |
| 1584 | glm::vec3 endPoint = axisPoint + (0.5f * capsuleLength * randFloat()) * axisDirection; | 1584 | glm::vec3 endPoint = axisPoint + (0.5f * capsuleLength * randFloat()) * axisDirection; |
| 1585 | glm::vec3 startPoint = axisPoint - (0.5f * capsuleLength * randFloat()) * axisDirection; | 1585 | glm::vec3 startPoint = axisPoint - (0.5f * capsuleLength * randFloat()) * axisDirection; |
| 1586 | 1586 | ||
| 1587 | // create a capsule between the points | 1587 | // create a capsule between the points |
| 1588 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); | 1588 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); |
| 1589 | 1589 | ||
| 1590 | // collide capsule with cube | 1590 | // collide capsule with cube |
| 1591 | if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { | 1591 | if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { |
| 1592 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" | 1592 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" |
| @@ -1599,25 +1599,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 6 unmodified lines | |||
| 1599 | << " ERROR: null collision with edgeNormal = " << edgeNormal << std::endl; | 1599 | << " ERROR: null collision with edgeNormal = " << edgeNormal << std::endl; |
| 1600 | return; | 1600 | return; |
| 1601 | } | 1601 | } |
| 1602 | 1602 | ||
| 1603 | // penetration points from capsule into cube | 1603 | // penetration points from capsule into cube |
| 1604 | glm::vec3 expectedPenetration = - overlap * deflectedNormal; | 1604 | glm::vec3 expectedPenetration = - overlap * deflectedNormal; |
| 1605 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); | 1605 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 1606 | if (fabs(inaccuracy) > allowableError / capsuleLength) { | 1606 | if (fabsf(inaccuracy) > allowableError / capsuleLength) { |
| 1607 | std::cout << __FILE__ << ":" << __LINE__ | 1607 | std::cout << __FILE__ << ":" << __LINE__ |
| 1608 | << " ERROR: bad penetration: expected = " << expectedPenetration | 1608 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 1609 | << " actual = " << collision->_penetration | 1609 | << " actual = " << collision->_penetration |
| 1610 | << " edgeNormal = " << edgeNormal | 1610 | << " edgeNormal = " << edgeNormal |
| 1611 | << std::endl; | 1611 | << std::endl; |
| 1612 | } | 1612 | } |
| 1613 | 1613 | ||
| 1614 | // contactPoint is on surface of capsule | 1614 | // contactPoint is on surface of capsule |
| 1615 | glm::vec3 expectedContactPoint = axisPoint - capsuleRadius * deflectedNormal; | 1615 | glm::vec3 expectedContactPoint = axisPoint - capsuleRadius * deflectedNormal; |
| 1616 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); | 1616 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 1617 | if (fabs(inaccuracy) > allowableError / capsuleLength) { | 1617 | if (fabsf(inaccuracy) > allowableError / capsuleLength) { |
| 1618 | std::cout << __FILE__ << ":" << __LINE__ | 1618 | std::cout << __FILE__ << ":" << __LINE__ |
| 1619 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint | 1619 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 1620 | << " actual = " << collision->_contactPoint | 1620 | << " actual = " << collision->_contactPoint |
| 1621 | << " edgeNormal = " << edgeNormal | 1621 | << " edgeNormal = " << edgeNormal |
| 1622 | << std::endl; | 1622 | << std::endl; |
| 1623 | } | 1623 | } |
| @@ -1646,7 +1646,7 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 22 unmodified lines | |||
| 1646 | 1646 | ||
| 1647 | // pick a random point somewhere above the corner | 1647 | // pick a random point somewhere above the corner |
| 1648 | glm::vec3 corner = cubeCenter + (0.5f * cubeSide) * (firstNormal + secondNormal + thirdNormal); | 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 | (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal + | 1650 | (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal + |
| 1651 | (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal + | 1651 | (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal + |
| 1652 | (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal; | 1652 | (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| @@ -1662,10 +1662,10 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 9 unmodified lines | |||
| 1662 | startPoint = endPoint; | 1662 | startPoint = endPoint; |
| 1663 | endPoint = temp; | 1663 | endPoint = temp; |
| 1664 | } | 1664 | } |
| 1665 | 1665 | ||
| 1666 | // create a capsule between the points | 1666 | // create a capsule between the points |
| 1667 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); | 1667 | CapsuleShape capsule(capsuleRadius, startPoint, endPoint); |
| 1668 | 1668 | ||
| 1669 | // collide capsule with cube | 1669 | // collide capsule with cube |
| 1670 | if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { | 1670 | if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { |
| 1671 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" | 1671 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" |
| @@ -1678,25 +1678,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 6 unmodified lines | |||
| 1678 | << " ERROR: null collision with cornerNormal = " << cornerNormal << std::endl; | 1678 | << " ERROR: null collision with cornerNormal = " << cornerNormal << std::endl; |
| 1679 | return; | 1679 | return; |
| 1680 | } | 1680 | } |
| 1681 | 1681 | ||
| 1682 | // penetration points from capsule into cube | 1682 | // penetration points from capsule into cube |
| 1683 | glm::vec3 expectedPenetration = overlap * penetrationNormal; | 1683 | glm::vec3 expectedPenetration = overlap * penetrationNormal; |
| 1684 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); | 1684 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 1685 | if (fabs(inaccuracy) > allowableError) { | 1685 | if (fabsf(inaccuracy) > allowableError) { |
| 1686 | std::cout << __FILE__ << ":" << __LINE__ | 1686 | std::cout << __FILE__ << ":" << __LINE__ |
| 1687 | << " ERROR: bad penetration: expected = " << expectedPenetration | 1687 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 1688 | << " actual = " << collision->_penetration | 1688 | << " actual = " << collision->_penetration |
| 1689 | << " cornerNormal = " << cornerNormal | 1689 | << " cornerNormal = " << cornerNormal |
| 1690 | << std::endl; | 1690 | << std::endl; |
| 1691 | } | 1691 | } |
| 1692 | 1692 | ||
| 1693 | // contactPoint is on surface of capsule | 1693 | // contactPoint is on surface of capsule |
| 1694 | glm::vec3 expectedContactPoint = collidingPoint + capsuleRadius * penetrationNormal; | 1694 | glm::vec3 expectedContactPoint = collidingPoint + capsuleRadius * penetrationNormal; |
| 1695 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); | 1695 | inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); |
| 1696 | if (fabs(inaccuracy) > allowableError) { | 1696 | if (fabsf(inaccuracy) > allowableError) { |
| 1697 | std::cout << __FILE__ << ":" << __LINE__ | 1697 | std::cout << __FILE__ << ":" << __LINE__ |
| 1698 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint | 1698 | << " ERROR: bad contactPoint: expected = " << expectedContactPoint |
| 1699 | << " actual = " << collision->_contactPoint | 1699 | << " actual = " << collision->_contactPoint |
| 1700 | << " cornerNormal = " << cornerNormal | 1700 | << " cornerNormal = " << cornerNormal |
| 1701 | << std::endl; | 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 | // these are the steps along the capsuleAxis where we'll put the capsule endpoints | 1708 | // these are the steps along the capsuleAxis where we'll put the capsule endpoints |
| 1709 | float steps[] = { -1.0f, 2.0f, 0.25f, 0.75f, -1.0f }; | 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 | glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections]; | 1715 | glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections]; |
| 1716 | 1716 | ||
| 1717 | // pick two random point on opposite edges of the face | 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 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; | 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 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; | 1721 | (cubeSide * (randFloat() - 0.5f)) * thirdNormal; |
| 1722 | 1722 | ||
| 1723 | // compute the un-normalized axis for the capsule | 1723 | // compute the un-normalized axis for the capsule |
| @@ -1742,7 +1742,7 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 18 unmodified lines | |||
| 1742 | if (numCollisions != 2) { | 1742 | if (numCollisions != 2) { |
| 1743 | std::cout << __FILE__ << ":" << __LINE__ | 1743 | std::cout << __FILE__ << ":" << __LINE__ |
| 1744 | << " ERROR: capsule should hit cube face at two spots." | 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 | << ". faceNormal = " << faceNormal << std::endl; | 1746 | << ". faceNormal = " << faceNormal << std::endl; |
| 1747 | break; | 1747 | break; |
| 1748 | } | 1748 | } |
| @@ -1764,33 +1764,33 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 15 unmodified lines | |||
| 1764 | expectedContactPoints[0] = startPoint - capsuleRadius * faceNormal; | 1764 | expectedContactPoints[0] = startPoint - capsuleRadius * faceNormal; |
| 1765 | expectedContactPoints[1] = firstEdgeIntersection - overlap * faceNormal; | 1765 | expectedContactPoints[1] = firstEdgeIntersection - overlap * faceNormal; |
| 1766 | } | 1766 | } |
| 1767 | 1767 | ||
| 1768 | // verify each contact | 1768 | // verify each contact |
| 1769 | for (int k = 0; k < 2; ++k) { | 1769 | for (int k = 0; k < 2; ++k) { |
| 1770 | CollisionInfo* collision = collisions.getCollision(k); | 1770 | CollisionInfo* collision = collisions.getCollision(k); |
| 1771 | // penetration points from capsule into cube | 1771 | // penetration points from capsule into cube |
| 1772 | glm::vec3 expectedPenetration = - overlap * faceNormal; | 1772 | glm::vec3 expectedPenetration = - overlap * faceNormal; |
| 1773 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); | 1773 | float inaccuracy = glm::length(collision->_penetration - expectedPenetration); |
| 1774 | if (fabs(inaccuracy) > allowableError) { | 1774 | if (fabsf(inaccuracy) > allowableError) { |
| 1775 | std::cout << __FILE__ << ":" << __LINE__ | 1775 | std::cout << __FILE__ << ":" << __LINE__ |
| 1776 | << " ERROR: bad penetration: expected = " << expectedPenetration | 1776 | << " ERROR: bad penetration: expected = " << expectedPenetration |
| 1777 | << " actual = " << collision->_penetration | 1777 | << " actual = " << collision->_penetration |
| 1778 | << " faceNormal = " << faceNormal | 1778 | << " faceNormal = " << faceNormal |
| 1779 | << std::endl; | 1779 | << std::endl; |
| 1780 | } | 1780 | } |
| 1781 | 1781 | ||
| 1782 | // the order of the final contact points is undefined, so we | 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 | 1783 | // figure out which expected contact point is the closest to the real one |
| 1784 | // and then verify accuracy on that | 1784 | // and then verify accuracy on that |
| 1785 | float length0 = glm::length(collision->_contactPoint - expectedContactPoints[0]); | 1785 | float length0 = glm::length(collision->_contactPoint - expectedContactPoints[0]); |
| 1786 | float length1 = glm::length(collision->_contactPoint - expectedContactPoints[1]); | 1786 | float length1 = glm::length(collision->_contactPoint - expectedContactPoints[1]); |
| 1787 | glm::vec3 expectedContactPoint = (length0 < length1) ? expectedContactPoints[0] : expectedContactPoints[1]; | 1787 | glm::vec3 expectedContactPoint = (length0 < length1) ? expectedContactPoints[0] : expectedContactPoints[1]; |
| 1788 | // contactPoint is on surface of capsule | 1788 | // contactPoint is on surface of capsule |
| 1789 | inaccuracy = (length0 < length1) ? length0 : length1; | 1789 | inaccuracy = (length0 < length1) ? length0 : length1; |
| 1790 | if (fabs(inaccuracy) > allowableError) { | 1790 | if (fabsf(inaccuracy) > allowableError) { |
| 1791 | std::cout << __FILE__ << ":" << __LINE__ | 1791 | std::cout << __FILE__ << ":" << __LINE__ |
| 1792 | << " ERROR: bad contact: expectedContactPoint[" << k << "] = " << expectedContactPoint | 1792 | << " ERROR: bad contact: expectedContactPoint[" << k << "] = " << expectedContactPoint |
| 1793 | << " actual = " << collision->_contactPoint | 1793 | << " actual = " << collision->_contactPoint |
| 1794 | << " faceNormal = " << faceNormal | 1794 | << " faceNormal = " << faceNormal |
| 1795 | << std::endl; | 1795 | << std::endl; |
| 1796 | } | 1796 | } |
| @@ -1817,14 +1817,14 @@ void ShapeColliderTests::rayHitsSphere() { · 20 unmodified lines | |||
| 1817 | if (!sphere.findRayIntersection(intersection)) { | 1817 | if (!sphere.findRayIntersection(intersection)) { |
| 1818 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl; | 1818 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl; |
| 1819 | } | 1819 | } |
| 1820 | 1820 | ||
| 1821 | float expectedDistance = startDistance - radius; | 1821 | float expectedDistance = startDistance - radius; |
| 1822 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; | 1822 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; |
| 1823 | if (relativeError > EPSILON) { | 1823 | if (relativeError > EPSILON) { |
| 1824 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray sphere intersection distance error = " << relativeError << std::endl; | 1824 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray sphere intersection distance error = " << relativeError << std::endl; |
| 1825 | } | 1825 | } |
| 1826 | if (intersection._hitShape != &sphere) { | 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 | << std::endl; | 1828 | << std::endl; |
| 1829 | } | 1829 | } |
| 1830 | } | 1830 | } |
| @@ -1834,11 +1834,11 @@ void ShapeColliderTests::rayHitsSphere() { · 3 unmodified lines | |||
| 1834 | RayIntersectionInfo intersection; | 1834 | RayIntersectionInfo intersection; |
| 1835 | intersection._rayStart = glm::vec3(startDistance, startDistance, 0.0f); | 1835 | intersection._rayStart = glm::vec3(startDistance, startDistance, 0.0f); |
| 1836 | intersection._rayDirection = - glm::normalize(intersection._rayStart); | 1836 | intersection._rayDirection = - glm::normalize(intersection._rayStart); |
| 1837 | 1837 | ||
| 1838 | if (!sphere.findRayIntersection(intersection)) { | 1838 | if (!sphere.findRayIntersection(intersection)) { |
| 1839 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl; | 1839 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl; |
| 1840 | } | 1840 | } |
| 1841 | 1841 | ||
| 1842 | float expectedDistance = SQUARE_ROOT_OF_2 * startDistance - radius; | 1842 | float expectedDistance = SQUARE_ROOT_OF_2 * startDistance - radius; |
| 1843 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; | 1843 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; |
| 1844 | if (relativeError > EPSILON) { | 1844 | if (relativeError > EPSILON) { |
| @@ -1864,15 +1864,15 @@ void ShapeColliderTests::rayHitsSphere() { · 19 unmodified lines | |||
| 1864 | 1864 | ||
| 1865 | sphere.setRadius(radius); | 1865 | sphere.setRadius(radius); |
| 1866 | sphere.setTranslation(rotation * translation); | 1866 | sphere.setTranslation(rotation * translation); |
| 1867 | 1867 | ||
| 1868 | if (!sphere.findRayIntersection(intersection)) { | 1868 | if (!sphere.findRayIntersection(intersection)) { |
| 1869 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl; | 1869 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl; |
| 1870 | } | 1870 | } |
| 1871 | 1871 | ||
| 1872 | float expectedDistance = startDistance - radius; | 1872 | float expectedDistance = startDistance - radius; |
| 1873 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; | 1873 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; |
| 1874 | if (relativeError > EPSILON) { | 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 | << relativeError << std::endl; | 1876 | << relativeError << std::endl; |
| 1877 | } | 1877 | } |
| 1878 | } | 1878 | } |
| @@ -1890,29 +1890,29 @@ void ShapeColliderTests::rayBarelyHitsSphere() { · 11 unmodified lines | |||
| 1890 | RayIntersectionInfo intersection; | 1890 | RayIntersectionInfo intersection; |
| 1891 | intersection._rayStart = glm::vec3(-startDistance, radius - delta, 0.0f); | 1891 | intersection._rayStart = glm::vec3(-startDistance, radius - delta, 0.0f); |
| 1892 | intersection._rayDirection = xAxis; | 1892 | intersection._rayDirection = xAxis; |
| 1893 | 1893 | ||
| 1894 | // very simple ray along xAxis | 1894 | // very simple ray along xAxis |
| 1895 | if (!sphere.findRayIntersection(intersection)) { | 1895 | if (!sphere.findRayIntersection(intersection)) { |
| 1896 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely hit sphere" << std::endl; | 1896 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely hit sphere" << std::endl; |
| 1897 | } | 1897 | } |
| 1898 | if (intersection._hitShape != &sphere) { | 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 | << std::endl; | 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 | glm::vec3 axis = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f)); | 1906 | glm::vec3 axis = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f)); |
| 1907 | glm::quat rotation = glm::angleAxis(0.987654321f, axis); | 1907 | glm::quat rotation = glm::angleAxis(0.987654321f, axis); |
| 1908 | glm::vec3 translation(35.7f, 0.46f, -1.97f); | 1908 | glm::vec3 translation(35.7f, 0.46f, -1.97f); |
| 1909 | 1909 | ||
| 1910 | RayIntersectionInfo intersection; | 1910 | RayIntersectionInfo intersection; |
| 1911 | intersection._rayStart = rotation * (intersection._rayStart + translation); | 1911 | intersection._rayStart = rotation * (intersection._rayStart + translation); |
| 1912 | intersection._rayDirection = rotation * intersection._rayDirection; | 1912 | intersection._rayDirection = rotation * intersection._rayDirection; |
| 1913 | 1913 | ||
| 1914 | sphere.setTranslation(rotation * translation); | 1914 | sphere.setTranslation(rotation * translation); |
| 1915 | 1915 | ||
| 1916 | // ...and test again | 1916 | // ...and test again |
| 1917 | if (!sphere.findRayIntersection(intersection)) { | 1917 | if (!sphere.findRayIntersection(intersection)) { |
| 1918 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely hit sphere" << std::endl; | 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 | RayIntersectionInfo intersection; | 1934 | RayIntersectionInfo intersection; |
| 1935 | intersection._rayStart = glm::vec3(-startDistance, radius + delta, 0.0f); | 1935 | intersection._rayStart = glm::vec3(-startDistance, radius + delta, 0.0f); |
| 1936 | intersection._rayDirection = xAxis; | 1936 | intersection._rayDirection = xAxis; |
| 1937 | 1937 | ||
| 1938 | // very simple ray along xAxis | 1938 | // very simple ray along xAxis |
| 1939 | if (sphere.findRayIntersection(intersection)) { | 1939 | if (sphere.findRayIntersection(intersection)) { |
| 1940 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely miss sphere" << std::endl; | 1940 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely miss sphere" << std::endl; |
| 1941 | } | 1941 | } |
| 1942 | if (intersection._hitDistance != FLT_MAX) { | 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 | << std::endl; | 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 | float angle = 0.987654321f; | 1950 | float angle = 0.987654321f; |
| 1951 | glm::vec3 axis = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f)); | 1951 | glm::vec3 axis = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f)); |
| 1952 | glm::quat rotation = glm::angleAxis(angle, axis); | 1952 | glm::quat rotation = glm::angleAxis(angle, axis); |
| @@ -1956,13 +1956,13 @@ void ShapeColliderTests::rayBarelyMissesSphere() { · 3 unmodified lines | |||
| 1956 | intersection._rayStart = rotation * (glm::vec3(-startDistance, radius + delta, 0.0f) + translation); | 1956 | intersection._rayStart = rotation * (glm::vec3(-startDistance, radius + delta, 0.0f) + translation); |
| 1957 | intersection._rayDirection = rotation * xAxis; | 1957 | intersection._rayDirection = rotation * xAxis; |
| 1958 | sphere.setTranslation(rotation * translation); | 1958 | sphere.setTranslation(rotation * translation); |
| 1959 | 1959 | ||
| 1960 | // ...and test again | 1960 | // ...and test again |
| 1961 | if (sphere.findRayIntersection(intersection)) { | 1961 | if (sphere.findRayIntersection(intersection)) { |
| 1962 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely miss sphere" << std::endl; | 1962 | std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely miss sphere" << std::endl; |
| 1963 | } | 1963 | } |
| 1964 | if (intersection._hitDistance != FLT_MAX) { | 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 | << std::endl; | 1966 | << std::endl; |
| 1967 | } | 1967 | } |
| 1968 | if (intersection._hitShape != NULL) { | 1968 | if (intersection._hitShape != NULL) { |
| @@ -1978,7 +1978,7 @@ void ShapeColliderTests::rayHitsCapsule() { · 9 unmodified lines | |||
| 1978 | glm::vec3 center(0.0f); | 1978 | glm::vec3 center(0.0f); |
| 1979 | CapsuleShape capsule(radius, halfHeight); | 1979 | CapsuleShape capsule(radius, halfHeight); |
| 1980 | 1980 | ||
| 1981 | // simple tests along xAxis | 1981 | // simple tests along xAxis |
| 1982 | { // toward capsule center | 1982 | { // toward capsule center |
| 1983 | RayIntersectionInfo intersection; | 1983 | RayIntersectionInfo intersection; |
| 1984 | intersection._rayStart = glm::vec3(startDistance, 0.0f, 0.0f); | 1984 | intersection._rayStart = glm::vec3(startDistance, 0.0f, 0.0f); |
| @@ -1989,11 +1989,11 @@ void ShapeColliderTests::rayHitsCapsule() { · 4 unmodified lines | |||
| 1989 | float expectedDistance = startDistance - radius; | 1989 | float expectedDistance = startDistance - radius; |
| 1990 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; | 1990 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; |
| 1991 | if (relativeError > EPSILON) { | 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 | << relativeError << std::endl; | 1993 | << relativeError << std::endl; |
| 1994 | } | 1994 | } |
| 1995 | if (intersection._hitShape != &capsule) { | 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 | << std::endl; | 1997 | << std::endl; |
| 1998 | } | 1998 | } |
| 1999 | } | 1999 | } |
| @@ -2008,7 +2008,7 @@ void ShapeColliderTests::rayHitsCapsule() { · 8 unmodified lines | |||
| 2008 | float expectedDistance = startDistance - radius; | 2008 | float expectedDistance = startDistance - radius; |
| 2009 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; | 2009 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; |
| 2010 | if (relativeError > EPSILON) { | 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 | << relativeError << std::endl; | 2012 | << relativeError << std::endl; |
| 2013 | } | 2013 | } |
| 2014 | } | 2014 | } |
| @@ -2024,7 +2024,7 @@ void ShapeColliderTests::rayHitsCapsule() { · 9 unmodified lines | |||
| 2024 | float expectedDistance = startDistance - radius; | 2024 | float expectedDistance = startDistance - radius; |
| 2025 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; | 2025 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; |
| 2026 | if (relativeError > EPSILON) { | 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 | << relativeError << std::endl; | 2028 | << relativeError << std::endl; |
| 2029 | } | 2029 | } |
| 2030 | } | 2030 | } |
| @@ -2041,7 +2041,7 @@ void ShapeColliderTests::rayHitsCapsule() { · 10 unmodified lines | |||
| 2041 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; | 2041 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; |
| 2042 | // for edge cases we allow a LOT of error | 2042 | // for edge cases we allow a LOT of error |
| 2043 | if (relativeError > EDGE_CASE_SLOP_FACTOR * EPSILON) { | 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 | << relativeError << std::endl; | 2045 | << relativeError << std::endl; |
| 2046 | } | 2046 | } |
| 2047 | } | 2047 | } |
| @@ -2057,7 +2057,7 @@ void ShapeColliderTests::rayHitsCapsule() { · 9 unmodified lines | |||
| 2057 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; | 2057 | float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; |
| 2058 | // for edge cases we allow a LOT of error | 2058 | // for edge cases we allow a LOT of error |
| 2059 | if (relativeError > EDGE_CASE_SLOP_FACTOR * EPSILON) { | 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 | << relativeError << std::endl; | 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.