mirror of
https://github.com/lubosz/overte.git
synced 2025-04-18 15:18:13 +02:00
merge from upstream
This commit is contained in:
commit
b761ecf44f
55 changed files with 1112 additions and 358 deletions
|
@ -386,8 +386,7 @@ void Agent::sendAvatarBillboardPacket() {
|
|||
void Agent::processAgentAvatarAndAudio(float deltaTime) {
|
||||
if (!_scriptEngine->isFinished() && _isAvatar) {
|
||||
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
|
||||
const int SCRIPT_AUDIO_BUFFER_SAMPLES = floor(((SCRIPT_DATA_CALLBACK_USECS * AudioConstants::SAMPLE_RATE)
|
||||
/ (1000 * 1000)) + 0.5);
|
||||
const int SCRIPT_AUDIO_BUFFER_SAMPLES = AudioConstants::SAMPLE_RATE / SCRIPT_FPS + 0.5;
|
||||
const int SCRIPT_AUDIO_BUFFER_BYTES = SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t);
|
||||
|
||||
QByteArray avatarByteArray = scriptedAvatar->toByteArray(true, randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO);
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include <NodeList.h>
|
||||
#include <NumericalConstants.h>
|
||||
#include <udt/PacketHeaders.h>
|
||||
|
@ -101,13 +104,16 @@ bool OctreeSendThread::process() {
|
|||
int elapsed = (usecTimestampNow() - start);
|
||||
int usecToSleep = OCTREE_SEND_INTERVAL_USECS - elapsed;
|
||||
|
||||
if (usecToSleep > 0) {
|
||||
PerformanceWarning warn(false,"OctreeSendThread... usleep()",false,&_usleepTime,&_usleepCalls);
|
||||
usleep(usecToSleep);
|
||||
} else {
|
||||
if (usecToSleep <= 0) {
|
||||
const int MIN_USEC_TO_SLEEP = 1;
|
||||
usleep(MIN_USEC_TO_SLEEP);
|
||||
usecToSleep = MIN_USEC_TO_SLEEP;
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceWarning warn(false,"OctreeSendThread... usleep()",false,&_usleepTime,&_usleepCalls);
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(usecToSleep));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return isStillRunning(); // keep running till they terminate us
|
||||
|
|
|
@ -1,31 +1,52 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" baseProfile="tiny" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px" y="0px" width="1600px" height="100px" viewBox="0 0 1600 100" xml:space="preserve">
|
||||
<path fill="#FFFFFF" d="M92.8,69.3c-0.8-1.5-1.9-2.7-3.1-3.8c4.4-11.4,3.7-24.6-2.6-35.8c-9.2-16.3-28.3-24.4-46.3-20l-3.1,0.7
|
||||
l4.9,8.7l1.7-0.3c13.7-2.7,27.6,3.6,34.5,15.7c4.9,8.7,5.5,18.9,1.9,27.9c-2.1,0.1-4.3,0.6-6.2,1.8c-6.5,3.7-8.8,12-5.1,18.5
|
||||
c3.7,6.5,12,8.8,18.5,5.1C94.2,84.1,96.5,75.8,92.8,69.3z"/>
|
||||
<path fill="#FFFFFF" d="M54.2,82.6l-1.5,0.1c-12.3,0.8-24.2-5.6-30.2-16.3c-3.8-6.6-4.9-14.2-3.7-21.3c2.8,0.4,5.9-0.1,8.6-1.6
|
||||
c6.5-3.7,8.8-12,5.1-18.5s-12-8.8-18.5-5.1C7.7,23.7,5.4,32,9,38.5c0.3,0.6,0.7,1.2,1.2,1.7c-2.6,10.3-1.4,21.5,4.1,31.1
|
||||
c7.5,13.2,21.5,21.2,36.5,21.2c1.8,0,3.5-0.1,5.2-0.3l3.6-0.4L54.2,82.6z"/>
|
||||
<path fill="#FFFFFF" d="M67.2,63.4H33.8c-1,0-2.1-0.5-2.6-1.5c-0.5-0.9-0.5-2.1,0-3L47.8,30c0.5-0.9,1.6-1.5,2.6-1.5
|
||||
s2.1,0.5,2.6,1.5l16.7,28.9c0.5,0.9,0.5,2.1,0,3C69.3,62.9,68.3,63.4,67.2,63.4z M39,57.4h23L50.4,37.5L39,57.4z"/>
|
||||
<polygon fill="#FFFFFF" points="175.4,30.6 149.9,8 123.9,30.7 139,30.7 139.2,59.6 161,59.3 160.8,30.7 "/>
|
||||
<polygon fill="#FFFFFF" points="225.6,39.8 251.1,62.5 277.1,39.8 261.9,39.8 261.7,8.9 240,9.2 240.2,39.8 "/>
|
||||
<path fill="#FFFFFF" d="M174.3,42.8c1.8,3.7,2.8,7.8,2.8,12.1c0,15.2-12.3,27.5-27.5,27.5c-15.2,0-27.5-12.3-27.5-27.5
|
||||
c0-4.4,1-8.5,2.9-12.1h-7.9c-1.4,3.8-2.2,7.8-2.2,12.1c0,19.2,15.6,34.7,34.7,34.7c19.2,0,34.7-15.6,34.7-34.7
|
||||
c0-4.3-0.8-8.3-2.2-12.1H174.3z"/>
|
||||
<path fill="#FFFFFF" d="M278.8,53c0.1,0.7,0.1,1.5,0.1,2.2c0,15.2-12.4,27.6-27.6,27.6c-15.2,0-27.6-12.4-27.6-27.6
|
||||
c0-1.1,0.1-2.1,0.2-3.1c-2.1-2.1-4.1-4.1-6.2-6.2c-0.8,3-1.3,6.1-1.3,9.3c0,19.2,15.6,34.9,34.9,34.9s34.9-15.6,34.9-34.9
|
||||
c0-2.9-0.4-5.8-1.1-8.5L278.8,53z"/>
|
||||
<circle fill="none" stroke="#000000" stroke-width="7" stroke-miterlimit="10" stroke-dasharray="7.7202,7.7202" cx="-174" cy="-5.8" r="14.7"/>
|
||||
<path d="M-174-10.6c2.6,0,4.7,2.1,4.7,4.7s-2.1,4.7-4.7,4.7s-4.7-2.1-4.7-4.7S-176.6-10.6-174-10.6 M-174-17.6
|
||||
c-6.5,0-11.7,5.3-11.7,11.7s5.3,11.7,11.7,11.7s11.7-5.3,11.7-11.7S-167.5-17.6-174-17.6L-174-17.6z"/>
|
||||
<path fill="#FFFFFF" d="M353.3,91.2c-0.3,0-0.7,0-1,0c-1.8-0.2-3.5-0.4-5.3-0.7c-21.3-3.6-35.2-22.8-32-44.2
|
||||
c2.7-18.2,17.7-31.4,36.8-32.5c17.2-0.9,33.8,11.4,38.2,28.5c0.8,3.1,1.1,6.3,1.6,9.5c0,0.3,0,0.7,0,1c-0.2,0.9-0.4,1.8-0.5,2.7
|
||||
c-1.3,16.3-12.9,30.1-28.8,34C359.3,90.4,356.3,90.7,353.3,91.2z M353.7,83.9c8.3,0,16.1-3.4,22.6-9.9c2.2-2.2,2-3.1-0.7-4.5
|
||||
c-3.9-1.9-7.8-3.7-11.7-5.6c-4-2-4.6-8.1-1.1-10.8c2-1.5,2.4-3.7,2.1-5.9c-0.2-1.8-1-3.5-1.2-5.3c-0.6-6-5.2-10.2-11.1-10.1
|
||||
c-5.9,0.1-10.4,4.8-10.6,10.9c-0.1,1.4-0.4,2.8-0.9,4.1c-0.6,1.9,0.1,4.9,1.7,6.3c3.8,3.1,3.1,9-1.4,11.2c-3.6,1.7-7.2,3.4-10.8,5.2
|
||||
c-3.4,1.6-3.6,2.5-0.8,5.1C336.2,80.6,343.8,83.9,353.7,83.9z"/>
|
||||
<polygon fill="#FFFFFF" points="445.3,14.1 484.6,14.1 461.5,38.2 485.6,41.4 422.2,86.9 441.2,53.4 425.6,49.3 "/>
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 1600 100" style="enable-background:new 0 0 1600 100;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<path class="st0" d="M92.8,69.3c-0.8-1.5-1.9-2.7-3.1-3.8c4.4-11.4,3.7-24.6-2.6-35.8c-9.2-16.3-28.3-24.4-46.3-20l-3.1,0.7l4.9,8.7
|
||||
l1.7-0.3c13.7-2.7,27.6,3.6,34.5,15.7c4.9,8.7,5.5,18.9,1.9,27.9c-2.1,0.1-4.3,0.6-6.2,1.8c-6.5,3.7-8.8,12-5.1,18.5
|
||||
c3.7,6.5,12,8.8,18.5,5.1C94.2,84.1,96.5,75.8,92.8,69.3z"/>
|
||||
<path class="st0" d="M54.2,82.6l-1.5,0.1c-12.3,0.8-24.2-5.6-30.2-16.3c-3.8-6.6-4.9-14.2-3.7-21.3c2.8,0.4,5.9-0.1,8.6-1.6
|
||||
c6.5-3.7,8.8-12,5.1-18.5s-12-8.8-18.5-5.1C7.7,23.7,5.4,32,9,38.5c0.3,0.6,0.7,1.2,1.2,1.7c-2.6,10.3-1.4,21.5,4.1,31.1
|
||||
c7.5,13.2,21.5,21.2,36.5,21.2c1.8,0,3.5-0.1,5.2-0.3l3.6-0.4L54.2,82.6z"/>
|
||||
<path class="st0" d="M67.2,63.4H33.8c-1,0-2.1-0.5-2.6-1.5c-0.5-0.9-0.5-2.1,0-3L47.8,30c0.5-0.9,1.6-1.5,2.6-1.5S52.5,29,53,30
|
||||
l16.7,28.9c0.5,0.9,0.5,2.1,0,3C69.3,62.9,68.3,63.4,67.2,63.4z M39,57.4h23L50.4,37.5L39,57.4z"/>
|
||||
<polygon class="st0" points="175.4,30.6 149.9,8 123.9,30.7 139,30.7 139.2,59.6 161,59.3 160.8,30.7 "/>
|
||||
<polygon class="st0" points="225.6,39.8 251.1,62.5 277.1,39.8 261.9,39.8 261.7,8.9 240,9.2 240.2,39.8 "/>
|
||||
<path class="st0" d="M174.3,42.8c1.8,3.7,2.8,7.8,2.8,12.1c0,15.2-12.3,27.5-27.5,27.5s-27.5-12.3-27.5-27.5c0-4.4,1-8.5,2.9-12.1
|
||||
h-7.9c-1.4,3.8-2.2,7.8-2.2,12.1c0,19.2,15.6,34.7,34.7,34.7c19.2,0,34.7-15.6,34.7-34.7c0-4.3-0.8-8.3-2.2-12.1
|
||||
C182.1,42.8,174.3,42.8,174.3,42.8z"/>
|
||||
<path class="st0" d="M278.8,53c0.1,0.7,0.1,1.5,0.1,2.2c0,15.2-12.4,27.6-27.6,27.6c-15.2,0-27.6-12.4-27.6-27.6
|
||||
c0-1.1,0.1-2.1,0.2-3.1c-2.1-2.1-4.1-4.1-6.2-6.2c-0.8,3-1.3,6.1-1.3,9.3c0,19.2,15.6,34.9,34.9,34.9s34.9-15.6,34.9-34.9
|
||||
c0-2.9-0.4-5.8-1.1-8.5L278.8,53z"/>
|
||||
<path class="st0" d="M353.3,91.2c-0.3,0-0.7,0-1,0c-1.8-0.2-3.5-0.4-5.3-0.7c-21.3-3.6-35.2-22.8-32-44.2
|
||||
c2.7-18.2,17.7-31.4,36.8-32.5c17.2-0.9,33.8,11.4,38.2,28.5c0.8,3.1,1.1,6.3,1.6,9.5c0,0.3,0,0.7,0,1c-0.2,0.9-0.4,1.8-0.5,2.7
|
||||
c-1.3,16.3-12.9,30.1-28.8,34C359.3,90.4,356.3,90.7,353.3,91.2z M353.7,83.9c8.3,0,16.1-3.4,22.6-9.9c2.2-2.2,2-3.1-0.7-4.5
|
||||
c-3.9-1.9-7.8-3.7-11.7-5.6c-4-2-4.6-8.1-1.1-10.8c2-1.5,2.4-3.7,2.1-5.9c-0.2-1.8-1-3.5-1.2-5.3c-0.6-6-5.2-10.2-11.1-10.1
|
||||
s-10.4,4.8-10.6,10.9c-0.1,1.4-0.4,2.8-0.9,4.1c-0.6,1.9,0.1,4.9,1.7,6.3c3.8,3.1,3.1,9-1.4,11.2c-3.6,1.7-7.2,3.4-10.8,5.2
|
||||
c-3.4,1.6-3.6,2.5-0.8,5.1C336.2,80.6,343.8,83.9,353.7,83.9z"/>
|
||||
<polygon class="st0" points="445.3,14.1 484.6,14.1 461.5,38.2 485.6,41.4 422.2,86.9 441.2,53.4 425.6,49.3 "/>
|
||||
<path class="st0" d="M564.7,53.2l0.1-8.7l-22.9-0.2c0.1-0.5,0.2-1.1,0.2-1.6c0.2-6.1,4.7-10.8,10.6-10.9c5.9-0.1,10.5,4.1,11.1,10.1
|
||||
c0.1,0.9,0.3,1.7,0.6,2.6l26.7,0.2c-3.3-17.9-19-31.4-37.9-31.4c-18.6,0-34.2,13.2-37.8,30.8l26.4,0.2l0,0l-0.9,0l-0.1,8.7
|
||||
l-26.2-0.2c0.5,20.8,17.5,37.6,38.5,37.6c20.7,0,37.6-16.4,38.5-36.9L564.7,53.2z M576.3,74c-6.5,6.5-14.3,9.9-22.6,9.9
|
||||
c-9.9,0-17.5-3.3-23.9-9.3c-2.8-2.6-2.6-3.5,0.8-5.1c3.6-1.8,7.2-3.5,10.8-5.2c4.5-2.2,5.2-8.1,1.4-11.2c0,0-0.1-0.1-0.1-0.1l20,0.2
|
||||
c-3.4,2.7-2.8,8.7,1.2,10.7c3.9,1.9,7.8,3.7,11.7,5.6C578.3,70.9,578.5,71.8,576.3,74z"/>
|
||||
<g>
|
||||
<path class="st0" d="M638.5,48.2c-1.2-1-2.3-2.2-3.2-3.5h-16.7v9.2h29.1c-1.4-0.6-2.6-1.3-4-2.2C641.6,50.4,640.3,49.7,638.5,48.2z
|
||||
"/>
|
||||
<path class="st0" d="M684.9,44.7h-31.3c1,0.5,2.1,1,3.2,1.5c2.2,1,3.5,1.8,5.6,3.1c2.1,1.3,4.2,2.3,6,3.8c0.4,0.3,0.7,0.6,1,0.9
|
||||
h15.5V44.7z"/>
|
||||
<path class="st0" d="M651.5,44.2c-1.4-0.7-2.6-1.4-3.6-2.2c-1.1-0.8-1.9-1.7-2.5-2.8c-0.6-1-0.9-2.2-0.9-3.7c0-2.1,0.7-3.8,2-5.1
|
||||
c1.3-1.3,3.2-2,5.7-2c1.1,0,2.2,0.1,3.2,0.4c1,0.3,1.9,0.8,2.7,1.4c0.8,0.7,1.5,1.6,2,2.7c0.5,1.1,0.9,2.5,1.1,4.2h7.4
|
||||
c0.2,0,0.5,0,0.9,0c0.4,0,0.9,0,1.3,0c0.5,0,0.9,0,1.3,0c0.4,0,0.7,0,0.9,0c-0.1-3.3-0.7-6.1-1.8-8.5s-2.5-4.4-4.4-5.9
|
||||
c-1.9-1.5-4-2.7-6.5-3.4c-2.5-0.7-5.1-1.1-8-1.1c-2.6,0-5,0.4-7.4,1.1c-2.4,0.7-4.4,1.8-6.3,3.2c-1.8,1.4-3.3,3.2-4.3,5.3
|
||||
c-1.1,2.1-1.6,4.6-1.6,7.6c0,3,0.6,5.5,1.7,7.5c0.3,0.6,0.7,1.2,1.1,1.8h17.3C652.2,44.5,651.9,44.3,651.5,44.2z"/>
|
||||
<path class="st0" d="M651.1,55c1.5,0.7,2.9,1.3,4.2,1.9s2.6,1.3,3.6,2.1c1,0.8,1.9,1.7,2.5,2.8s0.9,2.4,0.9,4c0,1.7-0.3,3.2-1,4.3
|
||||
c-0.7,1.1-1.5,2-2.5,2.7c-1,0.7-2.1,1.1-3.3,1.4c-1.2,0.3-2.4,0.4-3.5,0.4c-1.3,0-2.5-0.2-3.7-0.7c-1.1-0.4-2.1-1.2-2.9-2.1
|
||||
c-0.8-1-1.5-2.3-2-3.8c-0.5-1.6-0.8-3.5-0.8-5.7h-12.1c0.1,3.7,0.8,7,1.9,9.8c1.2,2.8,2.7,5.2,4.7,7c1.9,1.9,4.2,3.3,6.7,4.2
|
||||
s5.3,1.4,8.1,1.4c2.9,0,5.8-0.4,8.4-1.1c2.7-0.7,5-1.9,7.1-3.5c2-1.6,3.7-3.6,4.9-6.1s1.8-5.5,1.8-9.1c0-2.6-0.5-4.9-1.6-6.8
|
||||
c-0.9-1.5-2-2.9-3.3-4.1h-20.7C649.5,54.3,650.3,54.6,651.1,55z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 3 KiB After Width: | Height: | Size: 4.7 KiB |
|
@ -210,9 +210,7 @@ const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensi
|
|||
|
||||
class DeadlockWatchdogThread : public QThread {
|
||||
public:
|
||||
static const unsigned long HEARTBEAT_CHECK_INTERVAL_SECS = 1;
|
||||
static const unsigned long HEARTBEAT_UPDATE_INTERVAL_SECS = 1;
|
||||
static const unsigned long HEARTBEAT_REPORT_INTERVAL_USECS = 5 * USECS_PER_SECOND;
|
||||
static const unsigned long MAX_HEARTBEAT_AGE_USECS = 30 * USECS_PER_SECOND;
|
||||
static const int WARNING_ELAPSED_HEARTBEAT = 500 * USECS_PER_MSEC; // warn if elapsed heartbeat average is large
|
||||
static const int HEARTBEAT_SAMPLES = 100000; // ~5 seconds worth of samples
|
||||
|
@ -239,8 +237,6 @@ public:
|
|||
*crashTrigger = 0xDEAD10CC;
|
||||
}
|
||||
|
||||
static void setSuppressStatus(bool suppress) { _suppressStatus = suppress; }
|
||||
|
||||
void run() override {
|
||||
while (!_quit) {
|
||||
QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS);
|
||||
|
@ -248,7 +244,6 @@ public:
|
|||
uint64_t lastHeartbeat = _heartbeat; // sample atomic _heartbeat, because we could context switch away and have it updated on us
|
||||
uint64_t now = usecTimestampNow();
|
||||
auto lastHeartbeatAge = (now > lastHeartbeat) ? now - lastHeartbeat : 0;
|
||||
auto sinceLastReport = (now > _lastReport) ? now - _lastReport : 0;
|
||||
auto elapsedMovingAverage = _movingAverage.getAverage();
|
||||
|
||||
if (elapsedMovingAverage > _maxElapsedAverage) {
|
||||
|
@ -274,21 +269,10 @@ public:
|
|||
if (elapsedMovingAverage > WARNING_ELAPSED_HEARTBEAT) {
|
||||
qDebug() << "DEADLOCK WATCHDOG WARNING:"
|
||||
<< "lastHeartbeatAge:" << lastHeartbeatAge
|
||||
<< "elapsedMovingAverage:" << elapsedMovingAverage << "** OVER EXPECTED VALUE**"
|
||||
<< "elapsedMovingAverage:" << elapsedMovingAverage << "** OVER EXPECTED VALUE **"
|
||||
<< "maxElapsed:" << _maxElapsed
|
||||
<< "maxElapsedAverage:" << _maxElapsedAverage
|
||||
<< "samples:" << _movingAverage.getSamples();
|
||||
_lastReport = now;
|
||||
}
|
||||
|
||||
if (!_suppressStatus && sinceLastReport > HEARTBEAT_REPORT_INTERVAL_USECS) {
|
||||
qDebug() << "DEADLOCK WATCHDOG STATUS:"
|
||||
<< "lastHeartbeatAge:" << lastHeartbeatAge
|
||||
<< "elapsedMovingAverage:" << elapsedMovingAverage
|
||||
<< "maxElapsed:" << _maxElapsed
|
||||
<< "maxElapsedAverage:" << _maxElapsedAverage
|
||||
<< "samples:" << _movingAverage.getSamples();
|
||||
_lastReport = now;
|
||||
}
|
||||
|
||||
if (lastHeartbeatAge > MAX_HEARTBEAT_AGE_USECS) {
|
||||
|
@ -310,9 +294,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
static std::atomic<bool> _suppressStatus;
|
||||
static std::atomic<uint64_t> _heartbeat;
|
||||
static std::atomic<uint64_t> _lastReport;
|
||||
static std::atomic<uint64_t> _maxElapsed;
|
||||
static std::atomic<int> _maxElapsedAverage;
|
||||
static ThreadSafeMovingAverage<int, HEARTBEAT_SAMPLES> _movingAverage;
|
||||
|
@ -320,17 +302,11 @@ public:
|
|||
bool _quit { false };
|
||||
};
|
||||
|
||||
std::atomic<bool> DeadlockWatchdogThread::_suppressStatus;
|
||||
std::atomic<uint64_t> DeadlockWatchdogThread::_heartbeat;
|
||||
std::atomic<uint64_t> DeadlockWatchdogThread::_lastReport;
|
||||
std::atomic<uint64_t> DeadlockWatchdogThread::_maxElapsed;
|
||||
std::atomic<int> DeadlockWatchdogThread::_maxElapsedAverage;
|
||||
ThreadSafeMovingAverage<int, DeadlockWatchdogThread::HEARTBEAT_SAMPLES> DeadlockWatchdogThread::_movingAverage;
|
||||
|
||||
void Application::toggleSuppressDeadlockWatchdogStatus(bool checked) {
|
||||
DeadlockWatchdogThread::setSuppressStatus(checked);
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
class MyNativeEventFilter : public QAbstractNativeEventFilter {
|
||||
public:
|
||||
|
@ -3014,8 +2990,19 @@ void Application::init() {
|
|||
_entityClipboardRenderer.setTree(_entityClipboard);
|
||||
|
||||
// Make sure any new sounds are loaded as soon as know about them.
|
||||
connect(tree.get(), &EntityTree::newCollisionSoundURL, DependencyManager::get<SoundCache>().data(), &SoundCache::getSound);
|
||||
connect(getMyAvatar(), &MyAvatar::newCollisionSoundURL, DependencyManager::get<SoundCache>().data(), &SoundCache::getSound);
|
||||
connect(tree.get(), &EntityTree::newCollisionSoundURL, this, [this](QUrl newURL, EntityItemID id) {
|
||||
EntityTreePointer tree = getEntities()->getTree();
|
||||
if (auto entity = tree->findEntityByEntityItemID(id)) {
|
||||
auto sound = DependencyManager::get<SoundCache>()->getSound(newURL);
|
||||
entity->setCollisionSound(sound);
|
||||
}
|
||||
}, Qt::QueuedConnection);
|
||||
connect(getMyAvatar(), &MyAvatar::newCollisionSoundURL, this, [this](QUrl newURL) {
|
||||
if (auto avatar = getMyAvatar()) {
|
||||
auto sound = DependencyManager::get<SoundCache>()->getSound(newURL);
|
||||
avatar->setCollisionSound(sound);
|
||||
}
|
||||
}, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void Application::updateLOD() const {
|
||||
|
|
|
@ -255,7 +255,6 @@ public slots:
|
|||
|
||||
void resetSensors(bool andReload = false);
|
||||
void setActiveFaceTracker() const;
|
||||
void toggleSuppressDeadlockWatchdogStatus(bool checked);
|
||||
|
||||
#ifdef HAVE_IVIEWHMD
|
||||
void setActiveEyeTracker();
|
||||
|
|
|
@ -568,8 +568,6 @@ Menu::Menu() {
|
|||
addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::PipelineWarnings);
|
||||
addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::LogExtraTimings);
|
||||
addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::SuppressShortTimings);
|
||||
addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::SupressDeadlockWatchdogStatus, 0, false,
|
||||
qApp, SLOT(toggleSuppressDeadlockWatchdogStatus(bool)));
|
||||
|
||||
|
||||
// Developer > Audio >>>
|
||||
|
|
|
@ -182,7 +182,6 @@ namespace MenuOption {
|
|||
const QString Stats = "Stats";
|
||||
const QString StopAllScripts = "Stop All Scripts";
|
||||
const QString SuppressShortTimings = "Suppress Timings Less than 10ms";
|
||||
const QString SupressDeadlockWatchdogStatus = "Supress Deadlock Watchdog Status";
|
||||
const QString ThirdPerson = "Third Person";
|
||||
const QString ThreePointCalibration = "3 Point Calibration";
|
||||
const QString ThrottleFPSIfNotFocus = "Throttle FPS If Not Focus"; // FIXME - this value duplicated in Basic2DWindowOpenGLDisplayPlugin.cpp
|
||||
|
|
|
@ -93,13 +93,13 @@ void AvatarActionHold::prepareForPhysicsSimulation() {
|
|||
activateBody(true);
|
||||
}
|
||||
|
||||
std::shared_ptr<Avatar> AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position,
|
||||
glm::vec3& linearVelocity, glm::vec3& angularVelocity) {
|
||||
bool AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position,
|
||||
glm::vec3& linearVelocity, glm::vec3& angularVelocity) {
|
||||
auto avatarManager = DependencyManager::get<AvatarManager>();
|
||||
auto holdingAvatar = std::static_pointer_cast<Avatar>(avatarManager->getAvatarBySessionID(_holderID));
|
||||
|
||||
if (!holdingAvatar) {
|
||||
return holdingAvatar;
|
||||
return false;;
|
||||
}
|
||||
|
||||
withReadLock([&]{
|
||||
|
@ -171,62 +171,17 @@ std::shared_ptr<Avatar> AvatarActionHold::getTarget(float deltaTimeStep, glm::qu
|
|||
linearVelocity = linearVelocity + glm::cross(angularVelocity, position - palmPosition);
|
||||
});
|
||||
|
||||
return holdingAvatar;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
|
||||
glm::quat rotation;
|
||||
glm::vec3 position;
|
||||
glm::vec3 linearVelocity;
|
||||
glm::vec3 angularVelocity;
|
||||
bool valid = false;
|
||||
int holdCount = 0;
|
||||
|
||||
auto ownerEntity = _ownerEntity.lock();
|
||||
if (!ownerEntity) {
|
||||
return;
|
||||
}
|
||||
QList<EntityActionPointer> holdActions = ownerEntity->getActionsOfType(ACTION_TYPE_HOLD);
|
||||
foreach (EntityActionPointer action, holdActions) {
|
||||
std::shared_ptr<AvatarActionHold> holdAction = std::static_pointer_cast<AvatarActionHold>(action);
|
||||
glm::quat rotationForAction;
|
||||
glm::vec3 positionForAction;
|
||||
glm::vec3 linearVelocityForAction, angularVelocityForAction;
|
||||
std::shared_ptr<Avatar> holdingAvatar = holdAction->getTarget(deltaTimeStep, rotationForAction, positionForAction, linearVelocityForAction, angularVelocityForAction);
|
||||
if (holdingAvatar) {
|
||||
holdCount ++;
|
||||
if (holdAction.get() == this) {
|
||||
// only use the rotation for this action
|
||||
valid = true;
|
||||
rotation = rotationForAction;
|
||||
}
|
||||
|
||||
position += positionForAction;
|
||||
linearVelocity += linearVelocityForAction;
|
||||
angularVelocity += angularVelocityForAction;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid && holdCount > 0) {
|
||||
position /= holdCount;
|
||||
linearVelocity /= holdCount;
|
||||
angularVelocity /= holdCount;
|
||||
|
||||
withWriteLock([&]{
|
||||
_positionalTarget = position;
|
||||
_rotationalTarget = rotation;
|
||||
_linearVelocityTarget = linearVelocity;
|
||||
_angularVelocityTarget = angularVelocity;
|
||||
_positionalTargetSet = true;
|
||||
_rotationalTargetSet = true;
|
||||
_active = true;
|
||||
});
|
||||
if (_kinematic) {
|
||||
if (_kinematic) {
|
||||
if (prepareForSpringUpdate(deltaTimeStep)) {
|
||||
doKinematicUpdate(deltaTimeStep);
|
||||
} else {
|
||||
forceBodyNonStatic();
|
||||
ObjectActionSpring::updateActionWorker(deltaTimeStep);
|
||||
}
|
||||
} else {
|
||||
forceBodyNonStatic();
|
||||
ObjectActionSpring::updateActionWorker(deltaTimeStep);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,8 +36,8 @@ public:
|
|||
virtual bool shouldSuppressLocationEdits() override { return _active && !_ownerEntity.expired(); }
|
||||
|
||||
bool getAvatarRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation);
|
||||
std::shared_ptr<Avatar> getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position,
|
||||
glm::vec3& linearVelocity, glm::vec3& angularVelocity);
|
||||
virtual bool getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position,
|
||||
glm::vec3& linearVelocity, glm::vec3& angularVelocity) override;
|
||||
|
||||
virtual void prepareForPhysicsSimulation() override;
|
||||
|
||||
|
@ -51,9 +51,6 @@ private:
|
|||
QString _hand { "right" };
|
||||
QUuid _holderID;
|
||||
|
||||
glm::vec3 _linearVelocityTarget;
|
||||
glm::vec3 _angularVelocityTarget;
|
||||
|
||||
bool _kinematic { false };
|
||||
bool _kinematicSetVelocity { false };
|
||||
bool _previousSet { false };
|
||||
|
|
|
@ -309,9 +309,11 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents
|
|||
// my avatar. (Other user machines will make a similar analysis and inject sound for their collisions.)
|
||||
if (collision.idA.isNull() || collision.idB.isNull()) {
|
||||
MyAvatar* myAvatar = getMyAvatar();
|
||||
const QString& collisionSoundURL = myAvatar->getCollisionSoundURL();
|
||||
if (!collisionSoundURL.isEmpty()) {
|
||||
const float velocityChange = glm::length(collision.velocityChange);
|
||||
auto collisionSound = myAvatar->getCollisionSound();
|
||||
if (collisionSound) {
|
||||
const auto characterController = myAvatar->getCharacterController();
|
||||
const float avatarVelocityChange = (characterController ? glm::length(characterController->getVelocityChange()) : 0.0f);
|
||||
const float velocityChange = glm::length(collision.velocityChange) + avatarVelocityChange;
|
||||
const float MIN_AVATAR_COLLISION_ACCELERATION = 0.01f;
|
||||
const bool isSound = (collision.type == CONTACT_EVENT_TYPE_START) && (velocityChange > MIN_AVATAR_COLLISION_ACCELERATION);
|
||||
|
||||
|
@ -327,7 +329,7 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents
|
|||
// but most avatars are roughly the same size, so let's not be so fancy yet.
|
||||
const float AVATAR_STRETCH_FACTOR = 1.0f;
|
||||
|
||||
AudioInjector::playSound(collisionSoundURL, energyFactorOfFull, AVATAR_STRETCH_FACTOR, myAvatar->getPosition());
|
||||
AudioInjector::playSound(collisionSound, energyFactorOfFull, AVATAR_STRETCH_FACTOR, myAvatar->getPosition());
|
||||
myAvatar->collisionWithEntity(collision);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <AccountManager.h>
|
||||
#include <AddressManager.h>
|
||||
#include <AudioClient.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <display-plugins/DisplayPlugin.h>
|
||||
#include <FSTReader.h>
|
||||
#include <GeometryUtil.h>
|
||||
|
@ -32,6 +31,7 @@
|
|||
#include <PathUtils.h>
|
||||
#include <PerfStat.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <SoundCache.h>
|
||||
#include <TextRenderer3D.h>
|
||||
#include <UserActivityLogger.h>
|
||||
#include <AnimDebugDraw.h>
|
||||
|
@ -97,7 +97,6 @@ MyAvatar::MyAvatar(RigPointer rig) :
|
|||
_scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE),
|
||||
_scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME),
|
||||
_motionBehaviors(AVATAR_MOTION_DEFAULTS),
|
||||
_collisionSoundURL(""),
|
||||
_characterController(this),
|
||||
_lookAtTargetAvatar(),
|
||||
_shouldRender(true),
|
||||
|
@ -1232,12 +1231,20 @@ void MyAvatar::clearScriptableSettings() {
|
|||
}
|
||||
|
||||
void MyAvatar::setCollisionSoundURL(const QString& url) {
|
||||
_collisionSoundURL = url;
|
||||
if (!url.isEmpty() && (url != _collisionSoundURL)) {
|
||||
emit newCollisionSoundURL(QUrl(url));
|
||||
if (url != _collisionSoundURL) {
|
||||
_collisionSoundURL = url;
|
||||
|
||||
emit newCollisionSoundURL(QUrl(_collisionSoundURL));
|
||||
}
|
||||
}
|
||||
|
||||
SharedSoundPointer MyAvatar::getCollisionSound() {
|
||||
if (!_collisionSound) {
|
||||
_collisionSound = DependencyManager::get<SoundCache>()->getSound(_collisionSoundURL);
|
||||
}
|
||||
return _collisionSound;
|
||||
}
|
||||
|
||||
void MyAvatar::attach(const QString& modelURL, const QString& jointName,
|
||||
const glm::vec3& translation, const glm::quat& rotation,
|
||||
float scale, bool isSoft,
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <SettingHandle.h>
|
||||
#include <Rig.h>
|
||||
#include <Sound.h>
|
||||
|
||||
#include <controllers/Pose.h>
|
||||
|
||||
|
@ -222,6 +223,9 @@ public:
|
|||
const QString& getCollisionSoundURL() { return _collisionSoundURL; }
|
||||
void setCollisionSoundURL(const QString& url);
|
||||
|
||||
SharedSoundPointer getCollisionSound();
|
||||
void setCollisionSound(SharedSoundPointer sound) { _collisionSound = sound; }
|
||||
|
||||
void clearScriptableSettings();
|
||||
|
||||
float getBoomLength() const { return _boomLength; }
|
||||
|
@ -362,6 +366,8 @@ private:
|
|||
quint32 _motionBehaviors;
|
||||
QString _collisionSoundURL;
|
||||
|
||||
SharedSoundPointer _collisionSound;
|
||||
|
||||
MyCharacterController _characterController;
|
||||
|
||||
AvatarWeakPointer _lookAtTargetAvatar;
|
||||
|
|
|
@ -203,7 +203,7 @@ int main(int argc, const char* argv[]) {
|
|||
Application::shutdownPlugins();
|
||||
|
||||
qCDebug(interfaceapp, "Normal exit.");
|
||||
#ifndef DEBUG
|
||||
#if !defined(DEBUG) && !defined(Q_OS_LINUX)
|
||||
// HACK: exit immediately (don't handle shutdown callbacks) for Release build
|
||||
_exit(exitCode);
|
||||
#endif
|
||||
|
|
|
@ -365,17 +365,9 @@ void AudioInjector::stopAndDeleteLater() {
|
|||
QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
AudioInjector* AudioInjector::playSound(const QString& soundUrl, const float volume, const float stretchFactor, const glm::vec3 position) {
|
||||
if (soundUrl.isEmpty()) {
|
||||
return NULL;
|
||||
}
|
||||
auto soundCache = DependencyManager::get<SoundCache>();
|
||||
if (soundCache.isNull()) {
|
||||
return NULL;
|
||||
}
|
||||
SharedSoundPointer sound = soundCache->getSound(QUrl(soundUrl));
|
||||
if (sound.isNull() || !sound->isReady()) {
|
||||
return NULL;
|
||||
AudioInjector* AudioInjector::playSound(SharedSoundPointer sound, const float volume, const float stretchFactor, const glm::vec3 position) {
|
||||
if (!sound || !sound->isReady()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AudioInjectorOptions options;
|
||||
|
@ -385,7 +377,7 @@ AudioInjector* AudioInjector::playSound(const QString& soundUrl, const float vol
|
|||
|
||||
QByteArray samples = sound->getByteArray();
|
||||
if (stretchFactor == 1.0f) {
|
||||
return playSoundAndDelete(samples, options, NULL);
|
||||
return playSoundAndDelete(samples, options, nullptr);
|
||||
}
|
||||
|
||||
const int standardRate = AudioConstants::SAMPLE_RATE;
|
||||
|
@ -403,7 +395,7 @@ AudioInjector* AudioInjector::playSound(const QString& soundUrl, const float vol
|
|||
nInputFrames);
|
||||
|
||||
Q_UNUSED(nOutputFrames);
|
||||
return playSoundAndDelete(resampled, options, NULL);
|
||||
return playSoundAndDelete(resampled, options, nullptr);
|
||||
}
|
||||
|
||||
AudioInjector* AudioInjector::playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface) {
|
||||
|
|
|
@ -60,7 +60,7 @@ public:
|
|||
|
||||
static AudioInjector* playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface);
|
||||
static AudioInjector* playSound(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface);
|
||||
static AudioInjector* playSound(const QString& soundUrl, const float volume, const float stretchFactor, const glm::vec3 position);
|
||||
static AudioInjector* playSound(SharedSoundPointer sound, const float volume, const float stretchFactor, const glm::vec3 position);
|
||||
|
||||
public slots:
|
||||
void restart();
|
||||
|
|
|
@ -237,12 +237,6 @@ bool OpenGLDisplayPlugin::activate() {
|
|||
|
||||
_vsyncSupported = _container->getPrimaryWidget()->isVsyncSupported();
|
||||
|
||||
// Child classes may override this in order to do things like initialize
|
||||
// libraries, etc
|
||||
if (!internalActivate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#if THREADED_PRESENT
|
||||
// Start the present thread if necessary
|
||||
|
@ -258,8 +252,18 @@ bool OpenGLDisplayPlugin::activate() {
|
|||
// Start execution
|
||||
presentThread->start();
|
||||
}
|
||||
_presentThread = presentThread.data();
|
||||
#endif
|
||||
|
||||
// Child classes may override this in order to do things like initialize
|
||||
// libraries, etc
|
||||
if (!internalActivate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This should not return until the new context has been customized
|
||||
#if THREADED_PRESENT
|
||||
|
||||
// This should not return until the new context has been customized
|
||||
// and the old context (if any) has been uncustomized
|
||||
presentThread->setNewDisplayPlugin(this);
|
||||
#else
|
||||
|
|
|
@ -103,6 +103,7 @@ protected:
|
|||
|
||||
virtual void updateFrameData();
|
||||
|
||||
QThread* _presentThread{ nullptr };
|
||||
ProgramPtr _program;
|
||||
int32_t _mvpUniform { -1 };
|
||||
int32_t _alphaUniform { -1 };
|
||||
|
|
|
@ -63,7 +63,7 @@ bool HmdDisplayPlugin::internalActivate() {
|
|||
}
|
||||
|
||||
|
||||
static const char * REPROJECTION_VS = R"VS(#version 450 core
|
||||
static const char * REPROJECTION_VS = R"VS(#version 410 core
|
||||
in vec3 Position;
|
||||
in vec2 TexCoord;
|
||||
|
||||
|
@ -78,15 +78,15 @@ void main() {
|
|||
|
||||
)VS";
|
||||
|
||||
static const GLint REPROJECTION_MATRIX_LOCATION = 0;
|
||||
static const GLint INVERSE_PROJECTION_MATRIX_LOCATION = 4;
|
||||
static const GLint PROJECTION_MATRIX_LOCATION = 12;
|
||||
static const char * REPROJECTION_FS = R"FS(#version 450 core
|
||||
static GLint REPROJECTION_MATRIX_LOCATION = -1;
|
||||
static GLint INVERSE_PROJECTION_MATRIX_LOCATION = -1;
|
||||
static GLint PROJECTION_MATRIX_LOCATION = -1;
|
||||
static const char * REPROJECTION_FS = R"FS(#version 410 core
|
||||
|
||||
uniform sampler2D sampler;
|
||||
layout (location = 0) uniform mat3 reprojection = mat3(1);
|
||||
layout (location = 4) uniform mat4 inverseProjections[2];
|
||||
layout (location = 12) uniform mat4 projections[2];
|
||||
uniform mat3 reprojection = mat3(1);
|
||||
uniform mat4 inverseProjections[2];
|
||||
uniform mat4 projections[2];
|
||||
|
||||
in vec2 vTexCoord;
|
||||
in vec3 vPosition;
|
||||
|
@ -205,6 +205,11 @@ void HmdDisplayPlugin::customizeContext() {
|
|||
_enablePreview = !isVsyncEnabled();
|
||||
_sphereSection = loadSphereSection(_program, CompositorHelper::VIRTUAL_UI_TARGET_FOV.y, CompositorHelper::VIRTUAL_UI_ASPECT_RATIO);
|
||||
compileProgram(_reprojectionProgram, REPROJECTION_VS, REPROJECTION_FS);
|
||||
|
||||
using namespace oglplus;
|
||||
REPROJECTION_MATRIX_LOCATION = Uniform<glm::mat3>(*_reprojectionProgram, "reprojection").Location();
|
||||
INVERSE_PROJECTION_MATRIX_LOCATION = Uniform<glm::mat4>(*_reprojectionProgram, "inverseProjections").Location();
|
||||
PROJECTION_MATRIX_LOCATION = Uniform<glm::mat4>(*_reprojectionProgram, "projections").Location();
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::uncustomizeContext() {
|
||||
|
|
|
@ -820,14 +820,14 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT
|
|||
return;
|
||||
}
|
||||
|
||||
QString collisionSoundURL;
|
||||
SharedSoundPointer collisionSound;
|
||||
float mass = 1.0; // value doesn't get used, but set it so compiler is quiet
|
||||
AACube minAACube;
|
||||
bool success = false;
|
||||
_tree->withReadLock([&] {
|
||||
EntityItemPointer entity = entityTree->findEntityByEntityItemID(id);
|
||||
if (entity) {
|
||||
collisionSoundURL = entity->getCollisionSoundURL();
|
||||
collisionSound = entity->getCollisionSound();
|
||||
mass = entity->computeMass();
|
||||
minAACube = entity->getMinimumAACube(success);
|
||||
}
|
||||
|
@ -835,9 +835,10 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT
|
|||
if (!success) {
|
||||
return;
|
||||
}
|
||||
if (collisionSoundURL.isEmpty()) {
|
||||
if (!collisionSound) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float COLLISION_PENETRATION_TO_VELOCITY = 50; // as a subsitute for RELATIVE entity->getVelocity()
|
||||
// The collision.penetration is a pretty good indicator of changed velocity AFTER the initial contact,
|
||||
// but that first contact depends on exactly where we hit in the physics step.
|
||||
|
@ -859,11 +860,10 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT
|
|||
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.
|
||||
const float volume = (energyFactorOfFull * COLLISION_SOUND_COMPRESSION_RANGE) + (1.0f - COLLISION_SOUND_COMPRESSION_RANGE);
|
||||
|
||||
|
||||
// Shift the pitch down by ln(1 + (size / COLLISION_SIZE_FOR_STANDARD_PITCH)) / ln(2)
|
||||
const float COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f;
|
||||
const float stretchFactor = log(1.0f + (minAACube.getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2);
|
||||
AudioInjector::playSound(collisionSoundURL, volume, stretchFactor, position);
|
||||
AudioInjector::playSound(collisionSound, volume, stretchFactor, position);
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB,
|
||||
|
|
|
@ -85,10 +85,14 @@ void makeEntityItemStatusGetters(EntityItemPointer entity, render::Item::Status:
|
|||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
const QUuid& myNodeID = nodeList->getSessionUUID();
|
||||
bool weOwnSimulation = entity->getSimulationOwner().matchesValidID(myNodeID);
|
||||
bool otherOwnSimulation = !weOwnSimulation && !entity->getSimulationOwner().isNull();
|
||||
|
||||
if (weOwnSimulation) {
|
||||
return render::Item::Status::Value(1.0f, render::Item::Status::Value::BLUE,
|
||||
(unsigned char)RenderItemStatusIcon::SIMULATION_OWNER);
|
||||
} else if (otherOwnSimulation) {
|
||||
return render::Item::Status::Value(1.0f, render::Item::Status::Value::RED,
|
||||
(unsigned char)RenderItemStatusIcon::OTHER_SIMULATION_OWNER);
|
||||
}
|
||||
return render::Item::Status::Value(0.0f, render::Item::Status::Value::BLUE,
|
||||
(unsigned char)RenderItemStatusIcon::SIMULATION_OWNER);
|
||||
|
|
|
@ -25,6 +25,7 @@ enum class RenderItemStatusIcon {
|
|||
PACKET_RECEIVED = 2,
|
||||
SIMULATION_OWNER = 3,
|
||||
HAS_ACTIONS = 4,
|
||||
OTHER_SIMULATION_OWNER = 5,
|
||||
NONE = 255
|
||||
};
|
||||
|
||||
|
|
|
@ -174,9 +174,14 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
|
|||
#endif
|
||||
|
||||
if (!_webSurface) {
|
||||
#if defined(Q_OS_LINUX)
|
||||
// these don't seem to work on Linux
|
||||
return;
|
||||
#else
|
||||
if (!buildWebSurface(static_cast<EntityTreeRenderer*>(args->_renderer))) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
_lastRenderTime = usecTimestampNow();
|
||||
|
|
|
@ -59,8 +59,6 @@ public:
|
|||
virtual bool isMine() { return _isMine; }
|
||||
virtual void setIsMine(bool value) { _isMine = value; }
|
||||
|
||||
bool locallyAddedButNotYetReceived = false;
|
||||
|
||||
virtual bool shouldSuppressLocationEdits() { return false; }
|
||||
|
||||
virtual void prepareForPhysicsSimulation() { }
|
||||
|
|
|
@ -726,8 +726,13 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
READ_ENTITY_PROPERTY(PROP_DESCRIPTION, QString, setDescription);
|
||||
READ_ENTITY_PROPERTY(PROP_ACTION_DATA, QByteArray, setActionData);
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_PARENT_ID, QUuid, setParentID);
|
||||
READ_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex);
|
||||
{ // parentID and parentJointIndex are also protected by simulation ownership
|
||||
bool oldOverwrite = overwriteLocalData;
|
||||
overwriteLocalData = overwriteLocalData && !weOwnSimulation;
|
||||
READ_ENTITY_PROPERTY(PROP_PARENT_ID, QUuid, setParentID);
|
||||
READ_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex);
|
||||
overwriteLocalData = oldOverwrite;
|
||||
}
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_QUERY_AA_CUBE, AACube, setQueryAACube);
|
||||
|
||||
|
@ -852,6 +857,23 @@ void EntityItem::setHref(QString value) {
|
|||
_href = value;
|
||||
}
|
||||
|
||||
void EntityItem::setCollisionSoundURL(const QString& value) {
|
||||
if (_collisionSoundURL != value) {
|
||||
_collisionSoundURL = value;
|
||||
|
||||
if (auto myTree = getTree()) {
|
||||
myTree->notifyNewCollisionSoundURL(_collisionSoundURL, getEntityItemID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SharedSoundPointer EntityItem::getCollisionSound() {
|
||||
if (!_collisionSound) {
|
||||
_collisionSound = DependencyManager::get<SoundCache>()->getSound(_collisionSoundURL);
|
||||
}
|
||||
return _collisionSound;
|
||||
}
|
||||
|
||||
void EntityItem::simulate(const quint64& now) {
|
||||
if (_lastSimulated == 0) {
|
||||
_lastSimulated = now;
|
||||
|
@ -1700,16 +1722,31 @@ void EntityItem::setPendingOwnershipPriority(quint8 priority, const quint64& tim
|
|||
_simulationOwner.setPendingPriority(priority, timestamp);
|
||||
}
|
||||
|
||||
QString EntityItem::actionsToDebugString() {
|
||||
QString result;
|
||||
QVector<QByteArray> serializedActions;
|
||||
QHash<QUuid, EntityActionPointer>::const_iterator i = _objectActions.begin();
|
||||
while (i != _objectActions.end()) {
|
||||
const QUuid id = i.key();
|
||||
EntityActionPointer action = _objectActions[id];
|
||||
EntityActionType actionType = action->getType();
|
||||
result += QString("") + actionType + ":" + action->getID().toString() + " ";
|
||||
i++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool EntityItem::addAction(EntitySimulationPointer simulation, EntityActionPointer action) {
|
||||
bool result;
|
||||
withWriteLock([&] {
|
||||
checkWaitingToRemove(simulation);
|
||||
|
||||
result = addActionInternal(simulation, action);
|
||||
if (!result) {
|
||||
removeActionInternal(action->getID());
|
||||
if (result) {
|
||||
action->setIsMine(true);
|
||||
_actionDataDirty = true;
|
||||
} else {
|
||||
action->locallyAddedButNotYetReceived = true;
|
||||
removeActionInternal(action->getID());
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1783,6 +1820,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi
|
|||
EntityActionPointer action = _objectActions[actionID];
|
||||
|
||||
action->setOwnerEntity(nullptr);
|
||||
action->setIsMine(false);
|
||||
_objectActions.remove(actionID);
|
||||
|
||||
if (simulation) {
|
||||
|
@ -1863,7 +1901,6 @@ void EntityItem::deserializeActionsInternal() {
|
|||
if (!action->isMine()) {
|
||||
action->deserialize(serializedAction);
|
||||
}
|
||||
action->locallyAddedButNotYetReceived = false;
|
||||
updated << actionID;
|
||||
} else {
|
||||
auto actionFactory = DependencyManager::get<EntityActionFactoryInterface>();
|
||||
|
@ -1871,7 +1908,6 @@ void EntityItem::deserializeActionsInternal() {
|
|||
EntityActionPointer action = actionFactory->factoryBA(entity, serializedAction);
|
||||
if (action) {
|
||||
entity->addActionInternal(simulation, action);
|
||||
action->locallyAddedButNotYetReceived = false;
|
||||
updated << actionID;
|
||||
} else {
|
||||
static QString repeatedMessage =
|
||||
|
@ -1889,8 +1925,12 @@ void EntityItem::deserializeActionsInternal() {
|
|||
QUuid id = i.key();
|
||||
if (!updated.contains(id)) {
|
||||
EntityActionPointer action = i.value();
|
||||
// if we've just added this action, don't remove it due to lack of mention in an incoming packet.
|
||||
if (! action->locallyAddedButNotYetReceived) {
|
||||
|
||||
if (action->isMine()) {
|
||||
// we just received an update that didn't include one of our actions. tell the server about it (again).
|
||||
setActionDataNeedsTransmit(true);
|
||||
} else {
|
||||
// don't let someone else delete my action.
|
||||
_actionsToRemove << id;
|
||||
_previouslyDeletedActions.insert(id, now);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <PhysicsCollisionGroups.h>
|
||||
#include <ShapeInfo.h>
|
||||
#include <Transform.h>
|
||||
#include <Sound.h>
|
||||
#include <SpatiallyNestable.h>
|
||||
|
||||
#include "EntityItemID.h"
|
||||
|
@ -250,7 +251,10 @@ public:
|
|||
void setScriptTimestamp(const quint64 value) { _scriptTimestamp = value; }
|
||||
|
||||
const QString& getCollisionSoundURL() const { return _collisionSoundURL; }
|
||||
void setCollisionSoundURL(const QString& value) { _collisionSoundURL = value; }
|
||||
void setCollisionSoundURL(const QString& value);
|
||||
|
||||
SharedSoundPointer getCollisionSound();
|
||||
void setCollisionSound(SharedSoundPointer sound) { _collisionSound = sound; }
|
||||
|
||||
const glm::vec3& getRegistrationPoint() const { return _registrationPoint; } /// registration point as ratio of entity
|
||||
|
||||
|
@ -378,6 +382,7 @@ public:
|
|||
void grabSimulationOwnership();
|
||||
void flagForMotionStateChange() { _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; }
|
||||
|
||||
QString actionsToDebugString();
|
||||
bool addAction(EntitySimulationPointer simulation, EntityActionPointer action);
|
||||
bool updateAction(EntitySimulationPointer simulation, const QUuid& actionID, const QVariantMap& arguments);
|
||||
bool removeAction(EntitySimulationPointer simulation, const QUuid& actionID);
|
||||
|
@ -478,6 +483,7 @@ protected:
|
|||
quint64 _loadedScriptTimestamp{ ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP + 1 };
|
||||
|
||||
QString _collisionSoundURL;
|
||||
SharedSoundPointer _collisionSound;
|
||||
glm::vec3 _registrationPoint;
|
||||
float _angularDamping;
|
||||
bool _visible;
|
||||
|
|
|
@ -1615,7 +1615,7 @@ void EntityItemProperties::setSimulationOwner(const QByteArray& data) {
|
|||
QList<QString> EntityItemProperties::listChangedProperties() {
|
||||
QList<QString> out;
|
||||
if (containsPositionChange()) {
|
||||
out += "posistion";
|
||||
out += "position";
|
||||
}
|
||||
if (dimensionsChanged()) {
|
||||
out += "dimensions";
|
||||
|
|
|
@ -95,7 +95,6 @@ void EntityTree::postAddEntity(EntityItemPointer entity) {
|
|||
}
|
||||
|
||||
_isDirty = true;
|
||||
maybeNotifyNewCollisionSoundURL("", entity->getCollisionSoundURL());
|
||||
emit addingEntity(entity->getEntityItemID());
|
||||
|
||||
// find and hook up any entities with this entity as a (previously) missing parent
|
||||
|
@ -213,6 +212,8 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
|
|||
properties.setVelocityChanged(false);
|
||||
properties.setAngularVelocityChanged(false);
|
||||
properties.setAccelerationChanged(false);
|
||||
properties.setParentIDChanged(false);
|
||||
properties.setParentJointIndexChanged(false);
|
||||
|
||||
if (wantTerseEditLogging()) {
|
||||
qCDebug(entities) << (senderNode ? senderNode->getUUID() : "null") << "physical edits suppressed";
|
||||
|
@ -223,7 +224,6 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
|
|||
|
||||
QString entityScriptBefore = entity->getScript();
|
||||
quint64 entityScriptTimestampBefore = entity->getScriptTimestamp();
|
||||
QString collisionSoundURLBefore = entity->getCollisionSoundURL();
|
||||
uint32_t preFlags = entity->getDirtyFlags();
|
||||
|
||||
AACube newQueryAACube;
|
||||
|
@ -295,7 +295,6 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
|
|||
if (entityScriptBefore != entityScriptAfter || reload) {
|
||||
emitEntityScriptChanging(entity->getEntityItemID(), reload); // the entity script has changed
|
||||
}
|
||||
maybeNotifyNewCollisionSoundURL(collisionSoundURLBefore, entity->getCollisionSoundURL());
|
||||
}
|
||||
|
||||
// TODO: this final containingElement check should eventually be removed (or wrapped in an #ifdef DEBUG).
|
||||
|
@ -362,10 +361,8 @@ void EntityTree::emitEntityScriptChanging(const EntityItemID& entityItemID, cons
|
|||
emit entityScriptChanging(entityItemID, reload);
|
||||
}
|
||||
|
||||
void EntityTree::maybeNotifyNewCollisionSoundURL(const QString& previousCollisionSoundURL, const QString& nextCollisionSoundURL) {
|
||||
if (!nextCollisionSoundURL.isEmpty() && (nextCollisionSoundURL != previousCollisionSoundURL)) {
|
||||
emit newCollisionSoundURL(QUrl(nextCollisionSoundURL));
|
||||
}
|
||||
void EntityTree::notifyNewCollisionSoundURL(const QString& newURL, const EntityItemID& entityID) {
|
||||
emit newCollisionSoundURL(QUrl(newURL), entityID);
|
||||
}
|
||||
|
||||
void EntityTree::setSimulation(EntitySimulationPointer simulation) {
|
||||
|
@ -848,6 +845,14 @@ void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList<Q
|
|||
QString::number((int)center.y) + "," +
|
||||
QString::number((int)center.z);
|
||||
}
|
||||
if (properties.positionChanged()) {
|
||||
int index = changedProperties.indexOf("position");
|
||||
glm::vec3 pos = properties.getPosition();
|
||||
changedProperties[index] = QString("position:") +
|
||||
QString::number((int)pos.x) + "," +
|
||||
QString::number((int)pos.y) + "," +
|
||||
QString::number((int)pos.z);
|
||||
}
|
||||
}
|
||||
|
||||
int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength,
|
||||
|
|
|
@ -249,6 +249,8 @@ public:
|
|||
void forgetAvatarID(QUuid avatarID) { _avatarIDs -= avatarID; }
|
||||
void deleteDescendantsOfAvatar(QUuid avatarID);
|
||||
|
||||
void notifyNewCollisionSoundURL(const QString& newCollisionSoundURL, const EntityItemID& entityID);
|
||||
|
||||
public slots:
|
||||
void callLoader(EntityItemID entityID);
|
||||
|
||||
|
@ -256,7 +258,7 @@ signals:
|
|||
void deletingEntity(const EntityItemID& entityID);
|
||||
void addingEntity(const EntityItemID& entityID);
|
||||
void entityScriptChanging(const EntityItemID& entityItemID, const bool reload);
|
||||
void newCollisionSoundURL(const QUrl& url);
|
||||
void newCollisionSoundURL(const QUrl& url, const EntityItemID& entityID);
|
||||
void clearingEntities();
|
||||
|
||||
protected:
|
||||
|
@ -301,7 +303,6 @@ protected:
|
|||
|
||||
bool _wantEditLogging = false;
|
||||
bool _wantTerseEditLogging = false;
|
||||
void maybeNotifyNewCollisionSoundURL(const QString& oldCollisionSoundURL, const QString& newCollisionSoundURL);
|
||||
|
||||
|
||||
// some performance tracking properties - only used in server trees
|
||||
|
|
|
@ -34,8 +34,6 @@ OctreeElementPointer EntityTreeElement::createNewElement(unsigned char* octalCod
|
|||
return newChild;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void EntityTreeElement::init(unsigned char* octalCode) {
|
||||
OctreeElement::init(octalCode);
|
||||
_octreeMemoryUsage += sizeof(EntityTreeElement);
|
||||
|
|
|
@ -17,8 +17,15 @@ QOpenGLContext* QOpenGLContextWrapper::currentContext() {
|
|||
return QOpenGLContext::currentContext();
|
||||
}
|
||||
|
||||
|
||||
QOpenGLContextWrapper::QOpenGLContextWrapper() :
|
||||
_context(new QOpenGLContext)
|
||||
_context(new QOpenGLContext)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
QOpenGLContextWrapper::QOpenGLContextWrapper(QOpenGLContext* context) :
|
||||
_context(context)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -50,3 +57,7 @@ bool isCurrentContext(QOpenGLContext* context) {
|
|||
return QOpenGLContext::currentContext() == context;
|
||||
}
|
||||
|
||||
void QOpenGLContextWrapper::moveToThread(QThread* thread) {
|
||||
_context->moveToThread(thread);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,16 +15,19 @@
|
|||
class QOpenGLContext;
|
||||
class QSurface;
|
||||
class QSurfaceFormat;
|
||||
class QThread;
|
||||
|
||||
class QOpenGLContextWrapper {
|
||||
public:
|
||||
QOpenGLContextWrapper();
|
||||
QOpenGLContextWrapper(QOpenGLContext* context);
|
||||
void setFormat(const QSurfaceFormat& format);
|
||||
bool create();
|
||||
void swapBuffers(QSurface* surface);
|
||||
bool makeCurrent(QSurface* surface);
|
||||
void doneCurrent();
|
||||
void setShareContext(QOpenGLContext* otherContext);
|
||||
void moveToThread(QThread* thread);
|
||||
|
||||
static QOpenGLContext* currentContext();
|
||||
|
||||
|
|
|
@ -105,19 +105,19 @@ const QImage& image, bool isLinear, bool doCompress) {
|
|||
gpu::Semantic gpuSemantic;
|
||||
gpu::Semantic mipSemantic;
|
||||
if (isLinear) {
|
||||
mipSemantic = gpu::SBGRA;
|
||||
if (doCompress) {
|
||||
gpuSemantic = gpu::COMPRESSED_SRGBA;
|
||||
} else {
|
||||
gpuSemantic = gpu::SRGBA;
|
||||
}
|
||||
} else {
|
||||
mipSemantic = gpu::BGRA;
|
||||
if (doCompress) {
|
||||
gpuSemantic = gpu::COMPRESSED_RGBA;
|
||||
} else {
|
||||
gpuSemantic = gpu::RGBA;
|
||||
}
|
||||
} else {
|
||||
mipSemantic = gpu::SBGRA;
|
||||
if (doCompress) {
|
||||
gpuSemantic = gpu::COMPRESSED_SRGBA;
|
||||
} else {
|
||||
gpuSemantic = gpu::SRGBA;
|
||||
}
|
||||
}
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, gpuSemantic);
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, mipSemantic);
|
||||
|
@ -125,19 +125,19 @@ const QImage& image, bool isLinear, bool doCompress) {
|
|||
gpu::Semantic gpuSemantic;
|
||||
gpu::Semantic mipSemantic;
|
||||
if (isLinear) {
|
||||
mipSemantic = gpu::SRGB;
|
||||
if (doCompress) {
|
||||
gpuSemantic = gpu::COMPRESSED_SRGB;
|
||||
} else {
|
||||
gpuSemantic = gpu::SRGB;
|
||||
}
|
||||
} else {
|
||||
mipSemantic = gpu::RGB;
|
||||
if (doCompress) {
|
||||
gpuSemantic = gpu::COMPRESSED_RGB;
|
||||
} else {
|
||||
gpuSemantic = gpu::RGB;
|
||||
}
|
||||
} else {
|
||||
mipSemantic = gpu::SRGB;
|
||||
if (doCompress) {
|
||||
gpuSemantic = gpu::COMPRESSED_SRGB;
|
||||
} else {
|
||||
gpuSemantic = gpu::SRGB;
|
||||
}
|
||||
}
|
||||
formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpuSemantic);
|
||||
formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, mipSemantic);
|
||||
|
@ -171,14 +171,6 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag
|
|||
|
||||
if (generateMips) {
|
||||
theTexture->autoGenerateMips(-1);
|
||||
auto levels = theTexture->maxMip();
|
||||
uvec2 size(image.width(), image.height());
|
||||
for (uint8_t i = 1; i <= levels; ++i) {
|
||||
size >>= 1;
|
||||
size = glm::max(size, uvec2(1));
|
||||
image = image.scaled(size.x, size.y, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
theTexture->assignStoredMip(i, formatMip, image.byteCount(), image.constBits());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,20 +178,20 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag
|
|||
}
|
||||
|
||||
gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
return process2DTextureColorFromImage(srcImage, true, false, true);
|
||||
return process2DTextureColorFromImage(srcImage, false, false, true);
|
||||
}
|
||||
|
||||
|
||||
gpu::Texture* TextureUsage::createAlbedoTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
return process2DTextureColorFromImage(srcImage, true, true, true);
|
||||
return process2DTextureColorFromImage(srcImage, false, true, true);
|
||||
}
|
||||
|
||||
gpu::Texture* TextureUsage::createEmissiveTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
return process2DTextureColorFromImage(srcImage, true, true, true);
|
||||
return process2DTextureColorFromImage(srcImage, false, true, true);
|
||||
}
|
||||
|
||||
gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
return process2DTextureColorFromImage(srcImage, true, true, true);
|
||||
return process2DTextureColorFromImage(srcImage, false, true, true);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -40,15 +40,14 @@ void ResourceCacheSharedItems::appendPendingRequest(QWeakPointer<Resource> resou
|
|||
|
||||
QList<QSharedPointer<Resource>> ResourceCacheSharedItems::getPendingRequests() {
|
||||
QList<QSharedPointer<Resource>> result;
|
||||
Lock lock(_mutex);
|
||||
|
||||
{
|
||||
Lock lock(_mutex);
|
||||
foreach(QSharedPointer<Resource> resource, _pendingRequests) {
|
||||
if (resource) {
|
||||
result.append(resource);
|
||||
}
|
||||
foreach(QSharedPointer<Resource> resource, _pendingRequests) {
|
||||
if (resource) {
|
||||
result.append(resource);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -59,20 +58,20 @@ uint32_t ResourceCacheSharedItems::getPendingRequestsCount() const {
|
|||
|
||||
QList<QSharedPointer<Resource>> ResourceCacheSharedItems::getLoadingRequests() {
|
||||
QList<QSharedPointer<Resource>> result;
|
||||
Lock lock(_mutex);
|
||||
|
||||
{
|
||||
Lock lock(_mutex);
|
||||
foreach(QSharedPointer<Resource> resource, _loadingRequests) {
|
||||
if (resource) {
|
||||
result.append(resource);
|
||||
}
|
||||
foreach(QSharedPointer<Resource> resource, _loadingRequests) {
|
||||
if (resource) {
|
||||
result.append(resource);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ResourceCacheSharedItems::removeRequest(QWeakPointer<Resource> resource) {
|
||||
Lock lock(_mutex);
|
||||
|
||||
// resource can only be removed if it still has a ref-count, as
|
||||
// QWeakPointer has no operator== implementation for two weak ptrs, so
|
||||
// manually loop in case resource has been freed.
|
||||
|
@ -88,11 +87,11 @@ void ResourceCacheSharedItems::removeRequest(QWeakPointer<Resource> resource) {
|
|||
}
|
||||
|
||||
QSharedPointer<Resource> ResourceCacheSharedItems::getHighestPendingRequest() {
|
||||
Lock lock(_mutex);
|
||||
// look for the highest priority pending request
|
||||
int highestIndex = -1;
|
||||
float highestPriority = -FLT_MAX;
|
||||
QSharedPointer<Resource> highestResource;
|
||||
Lock lock(_mutex);
|
||||
|
||||
for (int i = 0; i < _pendingRequests.size();) {
|
||||
// Clear any freed resources
|
||||
|
@ -139,17 +138,17 @@ void ScriptableResource::setInScript(bool isInScript) {
|
|||
}
|
||||
|
||||
void ScriptableResource::loadingChanged() {
|
||||
emit stateChanged(LOADING);
|
||||
setState(LOADING);
|
||||
}
|
||||
|
||||
void ScriptableResource::loadedChanged() {
|
||||
emit stateChanged(LOADED);
|
||||
setState(LOADED);
|
||||
}
|
||||
|
||||
void ScriptableResource::finished(bool success) {
|
||||
disconnectHelper();
|
||||
|
||||
emit stateChanged(success ? FINISHED : FAILED);
|
||||
setState(success ? FINISHED : FAILED);
|
||||
}
|
||||
|
||||
void ScriptableResource::disconnectHelper() {
|
||||
|
@ -262,12 +261,14 @@ void ResourceCache::refreshAll() {
|
|||
clearUnusedResource();
|
||||
resetResourceCounters();
|
||||
|
||||
_resourcesLock.lockForRead();
|
||||
auto resourcesCopy = _resources;
|
||||
_resourcesLock.unlock();
|
||||
QHash<QUrl, QWeakPointer<Resource>> resources;
|
||||
{
|
||||
QReadLocker locker(&_resourcesLock);
|
||||
resources = _resources;
|
||||
}
|
||||
|
||||
// Refresh all remaining resources in use
|
||||
foreach (QSharedPointer<Resource> resource, resourcesCopy) {
|
||||
foreach (QSharedPointer<Resource> resource, resources) {
|
||||
if (resource) {
|
||||
resource->refresh();
|
||||
}
|
||||
|
@ -317,17 +318,17 @@ void ResourceCache::setRequestLimit(int limit) {
|
|||
|
||||
void ResourceCache::getResourceAsynchronously(const QUrl& url) {
|
||||
qCDebug(networking) << "ResourceCache::getResourceAsynchronously" << url.toString();
|
||||
_resourcesToBeGottenLock.lockForWrite();
|
||||
QWriteLocker locker(&_resourcesToBeGottenLock);
|
||||
_resourcesToBeGotten.enqueue(QUrl(url));
|
||||
_resourcesToBeGottenLock.unlock();
|
||||
}
|
||||
|
||||
void ResourceCache::checkAsynchronousGets() {
|
||||
assert(QThread::currentThread() == thread());
|
||||
QWriteLocker locker(&_resourcesToBeGottenLock);
|
||||
if (!_resourcesToBeGotten.isEmpty()) {
|
||||
_resourcesToBeGottenLock.lockForWrite();
|
||||
QUrl url = _resourcesToBeGotten.dequeue();
|
||||
_resourcesToBeGottenLock.unlock();
|
||||
|
||||
locker.unlock();
|
||||
getResource(url);
|
||||
}
|
||||
}
|
||||
|
@ -399,8 +400,10 @@ void ResourceCache::removeUnusedResource(const QSharedPointer<Resource>& resourc
|
|||
if (_unusedResources.contains(resource->getLRUKey())) {
|
||||
_unusedResources.remove(resource->getLRUKey());
|
||||
_unusedResourcesSize -= resource->getBytes();
|
||||
|
||||
locker.unlock();
|
||||
resetResourceCounters();
|
||||
}
|
||||
resetResourceCounters();
|
||||
}
|
||||
|
||||
void ResourceCache::reserveUnusedResource(qint64 resourceSize) {
|
||||
|
@ -413,7 +416,9 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) {
|
|||
it.value()->setCache(nullptr);
|
||||
auto size = it.value()->getBytes();
|
||||
|
||||
locker.unlock();
|
||||
removeResource(it.value()->getURL(), size);
|
||||
locker.relock();
|
||||
|
||||
_unusedResourcesSize -= size;
|
||||
_unusedResources.erase(it);
|
||||
|
@ -433,8 +438,16 @@ void ResourceCache::clearUnusedResource() {
|
|||
}
|
||||
|
||||
void ResourceCache::resetResourceCounters() {
|
||||
_numTotalResources = _resources.size();
|
||||
_numUnusedResources = _unusedResources.size();
|
||||
{
|
||||
QReadLocker locker(&_resourcesLock);
|
||||
_numTotalResources = _resources.size();
|
||||
}
|
||||
|
||||
{
|
||||
QReadLocker locker(&_unusedResourcesLock);
|
||||
_numUnusedResources = _unusedResources.size();
|
||||
}
|
||||
|
||||
emit dirty();
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ class ResourceCacheSharedItems : public Dependency {
|
|||
|
||||
using Mutex = std::mutex;
|
||||
using Lock = std::unique_lock<Mutex>;
|
||||
|
||||
public:
|
||||
void appendPendingRequest(QWeakPointer<Resource> newRequest);
|
||||
void appendActiveRequest(QWeakPointer<Resource> newRequest);
|
||||
|
@ -113,6 +114,9 @@ signals:
|
|||
void progressChanged(uint64_t bytesReceived, uint64_t bytesTotal);
|
||||
void stateChanged(int state);
|
||||
|
||||
protected:
|
||||
void setState(State state) { _state = state; emit stateChanged(_state); }
|
||||
|
||||
private slots:
|
||||
void loadingChanged();
|
||||
void loadedChanged();
|
||||
|
@ -224,26 +228,30 @@ private:
|
|||
void resetResourceCounters();
|
||||
void removeResource(const QUrl& url, qint64 size = 0);
|
||||
|
||||
QReadWriteLock _resourcesLock { QReadWriteLock::Recursive };
|
||||
QHash<QUrl, QWeakPointer<Resource>> _resources;
|
||||
int _lastLRUKey = 0;
|
||||
|
||||
void getResourceAsynchronously(const QUrl& url);
|
||||
|
||||
static int _requestLimit;
|
||||
static int _requestsActive;
|
||||
|
||||
void getResourceAsynchronously(const QUrl& url);
|
||||
QReadWriteLock _resourcesToBeGottenLock { QReadWriteLock::Recursive };
|
||||
QQueue<QUrl> _resourcesToBeGotten;
|
||||
|
||||
std::atomic<size_t> _numTotalResources { 0 };
|
||||
std::atomic<size_t> _numUnusedResources { 0 };
|
||||
// Resources
|
||||
QHash<QUrl, QWeakPointer<Resource>> _resources;
|
||||
QReadWriteLock _resourcesLock { QReadWriteLock::Recursive };
|
||||
int _lastLRUKey = 0;
|
||||
|
||||
std::atomic<size_t> _numTotalResources { 0 };
|
||||
std::atomic<qint64> _totalResourcesSize { 0 };
|
||||
|
||||
// Cached resources
|
||||
QMap<int, QSharedPointer<Resource>> _unusedResources;
|
||||
QReadWriteLock _unusedResourcesLock { QReadWriteLock::Recursive };
|
||||
qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE;
|
||||
|
||||
std::atomic<size_t> _numUnusedResources { 0 };
|
||||
std::atomic<qint64> _unusedResourcesSize { 0 };
|
||||
|
||||
qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE;
|
||||
QReadWriteLock _unusedResourcesLock { QReadWriteLock::Recursive };
|
||||
QMap<int, QSharedPointer<Resource>> _unusedResources;
|
||||
// Pending resources
|
||||
QQueue<QUrl> _resourcesToBeGotten;
|
||||
QReadWriteLock _resourcesToBeGottenLock { QReadWriteLock::Recursive };
|
||||
};
|
||||
|
||||
/// Base class for resources.
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <time.h>
|
||||
|
@ -201,7 +204,7 @@ bool OctreePersistThread::process() {
|
|||
if (isStillRunning()) {
|
||||
quint64 MSECS_TO_USECS = 1000;
|
||||
quint64 USECS_TO_SLEEP = 10 * MSECS_TO_USECS; // every 10ms
|
||||
usleep(USECS_TO_SLEEP);
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(USECS_TO_SLEEP));
|
||||
|
||||
// do our updates then check to save...
|
||||
_tree->update();
|
||||
|
|
|
@ -430,6 +430,14 @@ glm::vec3 CharacterController::getLinearVelocity() const {
|
|||
return velocity;
|
||||
}
|
||||
|
||||
glm::vec3 CharacterController::getVelocityChange() const {
|
||||
glm::vec3 velocity(0.0f);
|
||||
if (_rigidBody) {
|
||||
velocity = bulletToGLM(_rigidBody->getLinearVelocity());
|
||||
}
|
||||
return velocity;
|
||||
}
|
||||
|
||||
void CharacterController::preSimulation() {
|
||||
if (_enabled && _dynamicsWorld) {
|
||||
quint64 now = usecTimestampNow();
|
||||
|
@ -437,6 +445,7 @@ void CharacterController::preSimulation() {
|
|||
// slam body to where it is supposed to be
|
||||
_rigidBody->setWorldTransform(_characterBodyTransform);
|
||||
btVector3 velocity = _rigidBody->getLinearVelocity();
|
||||
_preSimulationVelocity = velocity;
|
||||
|
||||
btVector3 actualVertVelocity = velocity.dot(_currentUp) * _currentUp;
|
||||
btVector3 actualHorizVelocity = velocity - actualVertVelocity;
|
||||
|
@ -531,6 +540,9 @@ void CharacterController::preSimulation() {
|
|||
|
||||
void CharacterController::postSimulation() {
|
||||
// postSimulation() exists for symmetry and just in case we need to do something here later
|
||||
|
||||
btVector3 velocity = _rigidBody->getLinearVelocity();
|
||||
_velocityChange = velocity - _preSimulationVelocity;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -77,6 +77,7 @@ public:
|
|||
glm::vec3 getFollowVelocity() const;
|
||||
|
||||
glm::vec3 getLinearVelocity() const;
|
||||
glm::vec3 getVelocityChange() const;
|
||||
|
||||
float getCapsuleRadius() const { return _radius; }
|
||||
float getCapsuleHalfHeight() const { return _halfHeight; }
|
||||
|
@ -112,6 +113,8 @@ protected:
|
|||
btVector3 _currentUp;
|
||||
btVector3 _targetVelocity;
|
||||
btVector3 _parentVelocity;
|
||||
btVector3 _preSimulationVelocity;
|
||||
btVector3 _velocityChange;
|
||||
btTransform _followDesiredBodyTransform;
|
||||
btScalar _followTimeRemaining;
|
||||
btTransform _characterBodyTransform;
|
||||
|
|
|
@ -21,9 +21,11 @@ const uint16_t ObjectActionSpring::springVersion = 1;
|
|||
ObjectActionSpring::ObjectActionSpring(const QUuid& id, EntityItemPointer ownerEntity) :
|
||||
ObjectAction(ACTION_TYPE_SPRING, id, ownerEntity),
|
||||
_positionalTarget(glm::vec3(0.0f)),
|
||||
_desiredPositionalTarget(glm::vec3(0.0f)),
|
||||
_linearTimeScale(FLT_MAX),
|
||||
_positionalTargetSet(true),
|
||||
_rotationalTarget(glm::quat()),
|
||||
_desiredRotationalTarget(glm::quat()),
|
||||
_angularTimeScale(FLT_MAX),
|
||||
_rotationalTargetSet(true) {
|
||||
#if WANT_DEBUG
|
||||
|
@ -37,9 +39,81 @@ ObjectActionSpring::~ObjectActionSpring() {
|
|||
#endif
|
||||
}
|
||||
|
||||
bool ObjectActionSpring::getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position,
|
||||
glm::vec3& linearVelocity, glm::vec3& angularVelocity) {
|
||||
rotation = _desiredRotationalTarget;
|
||||
position = _desiredPositionalTarget;
|
||||
linearVelocity = glm::vec3();
|
||||
angularVelocity = glm::vec3();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ObjectActionSpring::prepareForSpringUpdate(btScalar deltaTimeStep) {
|
||||
auto ownerEntity = _ownerEntity.lock();
|
||||
if (!ownerEntity) {
|
||||
return false;
|
||||
}
|
||||
|
||||
glm::quat rotation;
|
||||
glm::vec3 position;
|
||||
glm::vec3 linearVelocity;
|
||||
glm::vec3 angularVelocity;
|
||||
|
||||
bool valid = false;
|
||||
int springCount = 0;
|
||||
|
||||
QList<EntityActionPointer> springDerivedActions;
|
||||
springDerivedActions.append(ownerEntity->getActionsOfType(ACTION_TYPE_SPRING));
|
||||
springDerivedActions.append(ownerEntity->getActionsOfType(ACTION_TYPE_HOLD));
|
||||
|
||||
foreach (EntityActionPointer action, springDerivedActions) {
|
||||
std::shared_ptr<ObjectActionSpring> springAction = std::static_pointer_cast<ObjectActionSpring>(action);
|
||||
glm::quat rotationForAction;
|
||||
glm::vec3 positionForAction;
|
||||
glm::vec3 linearVelocityForAction, angularVelocityForAction;
|
||||
bool success = springAction->getTarget(deltaTimeStep, rotationForAction,
|
||||
positionForAction, linearVelocityForAction,
|
||||
angularVelocityForAction);
|
||||
if (success) {
|
||||
springCount ++;
|
||||
if (springAction.get() == this) {
|
||||
// only use the rotation for this action
|
||||
valid = true;
|
||||
rotation = rotationForAction;
|
||||
}
|
||||
|
||||
position += positionForAction;
|
||||
linearVelocity += linearVelocityForAction;
|
||||
angularVelocity += angularVelocityForAction;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid && springCount > 0) {
|
||||
position /= springCount;
|
||||
linearVelocity /= springCount;
|
||||
angularVelocity /= springCount;
|
||||
|
||||
withWriteLock([&]{
|
||||
_positionalTarget = position;
|
||||
_rotationalTarget = rotation;
|
||||
_linearVelocityTarget = linearVelocity;
|
||||
_angularVelocityTarget = angularVelocity;
|
||||
_positionalTargetSet = true;
|
||||
_rotationalTargetSet = true;
|
||||
_active = true;
|
||||
});
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
||||
void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) {
|
||||
// don't risk hanging the thread running the physics simulation
|
||||
auto lockResult = withTryReadLock([&]{
|
||||
if (!prepareForSpringUpdate(deltaTimeStep)) {
|
||||
return;
|
||||
}
|
||||
|
||||
withReadLock([&]{
|
||||
auto ownerEntity = _ownerEntity.lock();
|
||||
if (!ownerEntity) {
|
||||
return;
|
||||
|
@ -65,6 +139,7 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) {
|
|||
float speed = glm::min(offsetLength / _linearTimeScale, SPRING_MAX_SPEED);
|
||||
targetVelocity = (-speed / offsetLength) * offset;
|
||||
if (speed > rigidBody->getLinearSleepingThreshold()) {
|
||||
forceBodyNonStatic();
|
||||
rigidBody->activate();
|
||||
}
|
||||
}
|
||||
|
@ -101,9 +176,6 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) {
|
|||
rigidBody->setAngularVelocity(targetVelocity);
|
||||
}
|
||||
});
|
||||
if (!lockResult) {
|
||||
qDebug() << "ObjectActionSpring::updateActionWorker lock failed";
|
||||
}
|
||||
}
|
||||
|
||||
const float MIN_TIMESCALE = 0.1f;
|
||||
|
@ -122,7 +194,7 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) {
|
|||
bool ok = true;
|
||||
positionalTarget = EntityActionInterface::extractVec3Argument("spring action", arguments, "targetPosition", ok, false);
|
||||
if (!ok) {
|
||||
positionalTarget = _positionalTarget;
|
||||
positionalTarget = _desiredPositionalTarget;
|
||||
}
|
||||
ok = true;
|
||||
linearTimeScale = EntityActionInterface::extractFloatArgument("spring action", arguments, "linearTimeScale", ok, false);
|
||||
|
@ -133,7 +205,7 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) {
|
|||
ok = true;
|
||||
rotationalTarget = EntityActionInterface::extractQuatArgument("spring action", arguments, "targetRotation", ok, false);
|
||||
if (!ok) {
|
||||
rotationalTarget = _rotationalTarget;
|
||||
rotationalTarget = _desiredRotationalTarget;
|
||||
}
|
||||
|
||||
ok = true;
|
||||
|
@ -144,9 +216,9 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) {
|
|||
}
|
||||
|
||||
if (somethingChanged ||
|
||||
positionalTarget != _positionalTarget ||
|
||||
positionalTarget != _desiredPositionalTarget ||
|
||||
linearTimeScale != _linearTimeScale ||
|
||||
rotationalTarget != _rotationalTarget ||
|
||||
rotationalTarget != _desiredRotationalTarget ||
|
||||
angularTimeScale != _angularTimeScale) {
|
||||
// something changed
|
||||
needUpdate = true;
|
||||
|
@ -155,9 +227,9 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) {
|
|||
|
||||
if (needUpdate) {
|
||||
withWriteLock([&] {
|
||||
_positionalTarget = positionalTarget;
|
||||
_desiredPositionalTarget = positionalTarget;
|
||||
_linearTimeScale = glm::max(MIN_TIMESCALE, glm::abs(linearTimeScale));
|
||||
_rotationalTarget = rotationalTarget;
|
||||
_desiredRotationalTarget = rotationalTarget;
|
||||
_angularTimeScale = glm::max(MIN_TIMESCALE, glm::abs(angularTimeScale));
|
||||
_active = true;
|
||||
|
||||
|
@ -177,9 +249,9 @@ QVariantMap ObjectActionSpring::getArguments() {
|
|||
QVariantMap arguments = ObjectAction::getArguments();
|
||||
withReadLock([&] {
|
||||
arguments["linearTimeScale"] = _linearTimeScale;
|
||||
arguments["targetPosition"] = glmToQMap(_positionalTarget);
|
||||
arguments["targetPosition"] = glmToQMap(_desiredPositionalTarget);
|
||||
|
||||
arguments["targetRotation"] = glmToQMap(_rotationalTarget);
|
||||
arguments["targetRotation"] = glmToQMap(_desiredRotationalTarget);
|
||||
arguments["angularTimeScale"] = _angularTimeScale;
|
||||
});
|
||||
return arguments;
|
||||
|
@ -194,10 +266,10 @@ QByteArray ObjectActionSpring::serialize() const {
|
|||
dataStream << ObjectActionSpring::springVersion;
|
||||
|
||||
withReadLock([&] {
|
||||
dataStream << _positionalTarget;
|
||||
dataStream << _desiredPositionalTarget;
|
||||
dataStream << _linearTimeScale;
|
||||
dataStream << _positionalTargetSet;
|
||||
dataStream << _rotationalTarget;
|
||||
dataStream << _desiredRotationalTarget;
|
||||
dataStream << _angularTimeScale;
|
||||
dataStream << _rotationalTargetSet;
|
||||
dataStream << localTimeToServerTime(_expires);
|
||||
|
@ -226,11 +298,11 @@ void ObjectActionSpring::deserialize(QByteArray serializedArguments) {
|
|||
}
|
||||
|
||||
withWriteLock([&] {
|
||||
dataStream >> _positionalTarget;
|
||||
dataStream >> _desiredPositionalTarget;
|
||||
dataStream >> _linearTimeScale;
|
||||
dataStream >> _positionalTargetSet;
|
||||
|
||||
dataStream >> _rotationalTarget;
|
||||
dataStream >> _desiredRotationalTarget;
|
||||
dataStream >> _angularTimeScale;
|
||||
dataStream >> _rotationalTargetSet;
|
||||
|
||||
|
|
|
@ -27,16 +27,26 @@ public:
|
|||
virtual QByteArray serialize() const override;
|
||||
virtual void deserialize(QByteArray serializedArguments) override;
|
||||
|
||||
virtual bool getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position,
|
||||
glm::vec3& linearVelocity, glm::vec3& angularVelocity);
|
||||
|
||||
protected:
|
||||
static const uint16_t springVersion;
|
||||
|
||||
glm::vec3 _positionalTarget;
|
||||
glm::vec3 _desiredPositionalTarget;
|
||||
float _linearTimeScale;
|
||||
bool _positionalTargetSet;
|
||||
|
||||
glm::quat _rotationalTarget;
|
||||
glm::quat _desiredRotationalTarget;
|
||||
float _angularTimeScale;
|
||||
bool _rotationalTargetSet;
|
||||
|
||||
glm::vec3 _linearVelocityTarget;
|
||||
glm::vec3 _angularVelocityTarget;
|
||||
|
||||
virtual bool prepareForSpringUpdate(btScalar deltaTimeStep);
|
||||
};
|
||||
|
||||
#endif // hifi_ObjectActionSpring_h
|
||||
|
|
|
@ -32,7 +32,11 @@ const LoaderList& getLoadedPlugins() {
|
|||
static std::once_flag once;
|
||||
static LoaderList loadedPlugins;
|
||||
std::call_once(once, [&] {
|
||||
#ifdef Q_OS_MAC
|
||||
QString pluginPath = QCoreApplication::applicationDirPath() + "/../PlugIns/";
|
||||
#else
|
||||
QString pluginPath = QCoreApplication::applicationDirPath() + "/plugins/";
|
||||
#endif
|
||||
QDir pluginDir(pluginPath);
|
||||
pluginDir.setFilter(QDir::Files);
|
||||
if (pluginDir.exists()) {
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QEventLoop>
|
||||
#include <QtCore/QFileInfo>
|
||||
|
@ -706,9 +709,15 @@ void ScriptEngine::run() {
|
|||
|
||||
QScriptValue result = evaluate(_scriptContents, _fileNameString);
|
||||
|
||||
QElapsedTimer startTime;
|
||||
startTime.start();
|
||||
#ifdef _WIN32
|
||||
// VS13 does not sleep_until unless it uses the system_clock, see:
|
||||
// https://www.reddit.com/r/cpp_questions/comments/3o71ic/sleep_until_not_working_with_a_time_pointsteady/
|
||||
using clock = std::chrono::system_clock;
|
||||
#else
|
||||
using clock = std::chrono::high_resolution_clock;
|
||||
#endif
|
||||
|
||||
clock::time_point startTime = clock::now();
|
||||
int thisFrame = 0;
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
@ -716,12 +725,29 @@ void ScriptEngine::run() {
|
|||
|
||||
qint64 lastUpdate = usecTimestampNow();
|
||||
|
||||
// TODO: Integrate this with signals/slots instead of reimplementing throttling for ScriptEngine
|
||||
while (!_isFinished) {
|
||||
int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec
|
||||
if (usecToSleep > 0) {
|
||||
usleep(usecToSleep);
|
||||
}
|
||||
// Throttle to SCRIPT_FPS
|
||||
const std::chrono::microseconds FRAME_DURATION(USECS_PER_SECOND / SCRIPT_FPS + 1);
|
||||
clock::time_point sleepTime(startTime + thisFrame++ * FRAME_DURATION);
|
||||
std::this_thread::sleep_until(sleepTime);
|
||||
|
||||
#ifdef SCRIPT_DELAY_DEBUG
|
||||
{
|
||||
auto now = clock::now();
|
||||
uint64_t seconds = std::chrono::duration_cast<std::chrono::seconds>(now - startTime).count();
|
||||
if (seconds > 0) { // avoid division by zero and time travel
|
||||
uint64_t fps = thisFrame / seconds;
|
||||
// Overreporting artificially reduces the reported rate
|
||||
if (thisFrame % SCRIPT_FPS == 0) {
|
||||
qCDebug(scriptengine) <<
|
||||
"Frame:" << thisFrame <<
|
||||
"Slept (us):" << std::chrono::duration_cast<std::chrono::microseconds>(now - sleepTime).count() <<
|
||||
"FPS:" << fps;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (_isFinished) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -39,9 +39,9 @@
|
|||
#include "ScriptUUID.h"
|
||||
#include "Vec3.h"
|
||||
|
||||
const QString NO_SCRIPT("");
|
||||
static const QString NO_SCRIPT("");
|
||||
|
||||
const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0f / 60.0f) * 1000 * 1000) + 0.5f);
|
||||
static const int SCRIPT_FPS = 60;
|
||||
|
||||
class CallbackData {
|
||||
public:
|
||||
|
|
|
@ -12,13 +12,17 @@ if (APPLE)
|
|||
|
||||
set(TARGET_NAME oculusLegacy)
|
||||
setup_hifi_plugin()
|
||||
link_hifi_libraries(shared gl gpu plugins display-plugins input-plugins)
|
||||
link_hifi_libraries(shared gl gpu plugins ui display-plugins input-plugins)
|
||||
|
||||
include_hifi_library_headers(octree)
|
||||
|
||||
add_dependency_external_projects(LibOVR)
|
||||
find_package(LibOVR REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES})
|
||||
find_library(COCOA_LIBRARY Cocoa)
|
||||
find_library(IOKIT_LIBRARY IOKit)
|
||||
target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES} ${COCOA_LIBRARY} ${IOKIT_LIBRARY})
|
||||
|
||||
|
||||
|
||||
endif()
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#include <QtCore/QThread.h>
|
||||
#include <QtWidgets/QMainWindow>
|
||||
#include <QtOpenGL/QGLWidget>
|
||||
#include <GLMHelpers.h>
|
||||
|
@ -16,7 +17,12 @@
|
|||
#include <QtGui/QResizeEvent>
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QScreen>
|
||||
#include <gl/GLWindow.h>
|
||||
#include <gl/GLWidget.h>
|
||||
#include <gpu/GLBackend.h>
|
||||
#include <MainWindow.h>
|
||||
|
||||
#include <gl/QOpenGLContextWrapper.h>
|
||||
#include <PerfStat.h>
|
||||
#include <gl/OglplusHelpers.h>
|
||||
#include <ViewFrustum.h>
|
||||
|
@ -39,7 +45,7 @@ void OculusLegacyDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
|
|||
_currentRenderFrameInfo = FrameInfo();
|
||||
_currentRenderFrameInfo.predictedDisplayTime = _currentRenderFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds();
|
||||
_trackingState = ovrHmd_GetTrackingState(_hmd, _currentRenderFrameInfo.predictedDisplayTime);
|
||||
_currentRenderFrameInfo.renderPose = toGlm(_trackingState.HeadPose.ThePose);
|
||||
_currentRenderFrameInfo.rawRenderPose = _currentRenderFrameInfo.renderPose = toGlm(_trackingState.HeadPose.ThePose);
|
||||
Lock lock(_mutex);
|
||||
_frameInfos[frameIndex] = _currentRenderFrameInfo;
|
||||
}
|
||||
|
@ -72,14 +78,34 @@ bool OculusLegacyDisplayPlugin::isSupported() const {
|
|||
}
|
||||
|
||||
bool OculusLegacyDisplayPlugin::internalActivate() {
|
||||
Parent::internalActivate();
|
||||
|
||||
if (!Parent::internalActivate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(ovr_Initialize(nullptr))) {
|
||||
Q_ASSERT(false);
|
||||
qFatal("Failed to Initialize SDK");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
_hmdWindow = new GLWindow();
|
||||
_hmdWindow->create();
|
||||
_hmdWindow->createContext(_container->getPrimaryContext());
|
||||
auto hmdScreen = qApp->screens()[_hmdScreen];
|
||||
auto hmdGeometry = hmdScreen->geometry();
|
||||
_hmdWindow->setGeometry(hmdGeometry);
|
||||
_hmdWindow->showFullScreen();
|
||||
|
||||
_hmdWindow->makeCurrent();
|
||||
glClearColor(1, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
_hmdWindow->swapBuffers();
|
||||
|
||||
_container->makeRenderingContextCurrent();
|
||||
|
||||
QOpenGLContextWrapper(_hmdWindow->context()).moveToThread(_presentThread);
|
||||
|
||||
_hswDismissed = false;
|
||||
_hmd = ovrHmd_Create(0);
|
||||
if (!_hmd) {
|
||||
|
@ -96,7 +122,8 @@ bool OculusLegacyDisplayPlugin::internalActivate() {
|
|||
ovrMatrix4f ovrPerspectiveProjection =
|
||||
ovrMatrix4f_Projection(erd.Fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded);
|
||||
_eyeProjections[eye] = toGlm(ovrPerspectiveProjection);
|
||||
_eyeOffsets[eye] = glm::translate(mat4(), toGlm(erd.HmdToEyeViewOffset));
|
||||
_ovrEyeOffsets[eye] = erd.HmdToEyeViewOffset;
|
||||
_eyeOffsets[eye] = glm::translate(mat4(), -1.0f * toGlm(_ovrEyeOffsets[eye]));
|
||||
eyeSizes[eye] = toGlm(ovrHmd_GetFovTextureSize(_hmd, eye, erd.Fov, 1.0f));
|
||||
});
|
||||
|
||||
|
@ -121,6 +148,11 @@ void OculusLegacyDisplayPlugin::internalDeactivate() {
|
|||
ovrHmd_Destroy(_hmd);
|
||||
_hmd = nullptr;
|
||||
ovr_Shutdown();
|
||||
_hmdWindow->showNormal();
|
||||
_hmdWindow->destroy();
|
||||
_hmdWindow->deleteLater();
|
||||
_hmdWindow = nullptr;
|
||||
_container->makeRenderingContextCurrent();
|
||||
}
|
||||
|
||||
// DLL based display plugins MUST initialize GLEW inside the DLL code.
|
||||
|
@ -131,20 +163,21 @@ void OculusLegacyDisplayPlugin::customizeContext() {
|
|||
glewInit();
|
||||
glGetError();
|
||||
});
|
||||
_hmdWindow->requestActivate();
|
||||
QThread::msleep(1000);
|
||||
Parent::customizeContext();
|
||||
#if 0
|
||||
ovrGLConfig config; memset(&config, 0, sizeof(ovrRenderAPIConfig));
|
||||
auto& header = config.Config.Header;
|
||||
header.API = ovrRenderAPI_OpenGL;
|
||||
header.BackBufferSize = _hmd->Resolution;
|
||||
header.Multisample = 1;
|
||||
int distortionCaps = ovrDistortionCap_TimeWarp;
|
||||
int distortionCaps = ovrDistortionCap_TimeWarp | ovrDistortionCap_Vignette;
|
||||
|
||||
memset(_eyeTextures, 0, sizeof(ovrTexture) * 2);
|
||||
ovr_for_each_eye([&](ovrEyeType eye) {
|
||||
auto& header = _eyeTextures[eye].Header;
|
||||
header.API = ovrRenderAPI_OpenGL;
|
||||
header.TextureSize = { (int)_desiredFramebufferSize.x, (int)_desiredFramebufferSize.y };
|
||||
header.TextureSize = { (int)_renderTargetSize.x, (int)_renderTargetSize.y };
|
||||
header.RenderViewport.Size = header.TextureSize;
|
||||
header.RenderViewport.Size.w /= 2;
|
||||
if (eye == ovrEye_Right) {
|
||||
|
@ -152,29 +185,57 @@ void OculusLegacyDisplayPlugin::customizeContext() {
|
|||
}
|
||||
});
|
||||
|
||||
if (_hmdWindow->makeCurrent()) {
|
||||
#ifndef NDEBUG
|
||||
ovrBool result =
|
||||
#endif
|
||||
ovrHmd_ConfigureRendering(_hmd, &config.Config, distortionCaps, _eyeFovs, _eyeRenderDescs);
|
||||
assert(result);
|
||||
ovrBool result =
|
||||
#endif
|
||||
ovrHmd_ConfigureRendering(_hmd, &config.Config, distortionCaps, _eyeFovs, _eyeRenderDescs);
|
||||
assert(result);
|
||||
_hmdWindow->doneCurrent();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#if 0
|
||||
void OculusLegacyDisplayPlugin::uncustomizeContext() {
|
||||
HmdDisplayPlugin::uncustomizeContext();
|
||||
_hmdWindow->doneCurrent();
|
||||
QOpenGLContextWrapper(_hmdWindow->context()).moveToThread(qApp->thread());
|
||||
Parent::uncustomizeContext();
|
||||
}
|
||||
|
||||
void OculusLegacyDisplayPlugin::internalPresent() {
|
||||
ovrHmd_BeginFrame(_hmd, 0);
|
||||
ovr_for_each_eye([&](ovrEyeType eye) {
|
||||
reinterpret_cast<ovrGLTexture&>(_eyeTextures[eye]).OGL.TexId = _currentSceneTexture;
|
||||
});
|
||||
ovrHmd_EndFrame(_hmd, _eyePoses, _eyeTextures);
|
||||
}
|
||||
void OculusLegacyDisplayPlugin::hmdPresent() {
|
||||
if (!_hswDismissed) {
|
||||
ovrHSWDisplayState hswState;
|
||||
ovrHmd_GetHSWDisplayState(_hmd, &hswState);
|
||||
if (hswState.Displayed) {
|
||||
ovrHmd_DismissHSWDisplay(_hmd);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
auto r = glm::quat_cast(_currentPresentFrameInfo.presentPose);
|
||||
ovrQuatf ovrRotation = { r.x, r.y, r.z, r.w };
|
||||
ovrPosef eyePoses[2];
|
||||
memset(eyePoses, 0, sizeof(ovrPosef) * 2);
|
||||
eyePoses[0].Orientation = eyePoses[1].Orientation = ovrRotation;
|
||||
|
||||
GLint texture = oglplus::GetName(_compositeFramebuffer->color);
|
||||
auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
glFlush();
|
||||
if (_hmdWindow->makeCurrent()) {
|
||||
glClearColor(0, 0.4, 0.8, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
ovrHmd_BeginFrame(_hmd, _currentPresentFrameIndex);
|
||||
glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
|
||||
glDeleteSync(sync);
|
||||
ovr_for_each_eye([&](ovrEyeType eye) {
|
||||
reinterpret_cast<ovrGLTexture&>(_eyeTextures[eye]).OGL.TexId = texture;
|
||||
});
|
||||
ovrHmd_EndFrame(_hmd, eyePoses, _eyeTextures);
|
||||
_hmdWindow->doneCurrent();
|
||||
}
|
||||
static auto widget = _container->getPrimaryWidget();
|
||||
widget->makeCurrent();
|
||||
}
|
||||
|
||||
int OculusLegacyDisplayPlugin::getHmdScreen() const {
|
||||
return _hmdScreen;
|
||||
|
@ -184,4 +245,3 @@ float OculusLegacyDisplayPlugin::getTargetFrameRate() const {
|
|||
return TARGET_RATE_OculusLegacy;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -14,42 +14,43 @@
|
|||
#include <OVR_CAPI.h>
|
||||
|
||||
const float TARGET_RATE_OculusLegacy = 75.0f;
|
||||
class GLWindow;
|
||||
|
||||
class OculusLegacyDisplayPlugin : public HmdDisplayPlugin {
|
||||
using Parent = HmdDisplayPlugin;
|
||||
public:
|
||||
OculusLegacyDisplayPlugin();
|
||||
virtual bool isSupported() const override;
|
||||
virtual const QString& getName() const override { return NAME; }
|
||||
bool isSupported() const override;
|
||||
const QString& getName() const override { return NAME; }
|
||||
|
||||
virtual int getHmdScreen() const override;
|
||||
int getHmdScreen() const override;
|
||||
|
||||
// Stereo specific methods
|
||||
virtual void resetSensors() override;
|
||||
virtual void beginFrameRender(uint32_t frameIndex) override;
|
||||
void resetSensors() override;
|
||||
void beginFrameRender(uint32_t frameIndex) override;
|
||||
|
||||
virtual float getTargetFrameRate() const override;
|
||||
float getTargetFrameRate() const override;
|
||||
|
||||
protected:
|
||||
virtual bool internalActivate() override;
|
||||
virtual void internalDeactivate() override;
|
||||
bool internalActivate() override;
|
||||
void internalDeactivate() override;
|
||||
|
||||
virtual void customizeContext() override;
|
||||
void hmdPresent() override {}
|
||||
void customizeContext() override;
|
||||
void uncustomizeContext() override;
|
||||
void hmdPresent() override;
|
||||
bool isHmdMounted() const override { return true; }
|
||||
#if 0
|
||||
virtual void uncustomizeContext() override;
|
||||
virtual void internalPresent() override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
static const QString NAME;
|
||||
|
||||
GLWindow* _hmdWindow{ nullptr };
|
||||
ovrHmd _hmd;
|
||||
mutable ovrTrackingState _trackingState;
|
||||
ovrEyeRenderDesc _eyeRenderDescs[2];
|
||||
ovrVector3f _ovrEyeOffsets[2];
|
||||
|
||||
ovrFovPort _eyeFovs[2];
|
||||
//ovrTexture _eyeTextures[2]; // FIXME - not currently in use
|
||||
ovrTexture _eyeTextures[2]; // FIXME - not currently in use
|
||||
mutable int _hmdScreen { -1 };
|
||||
bool _hswDismissed { false };
|
||||
};
|
||||
|
|
|
@ -26,8 +26,8 @@ function getFrame(callback) {
|
|||
}
|
||||
|
||||
function makeFrame(state) {
|
||||
if (state == Resource.State.FAILED) { throw "Failed to load frame"; }
|
||||
if (state != Resource.State.FINISHED) { return; }
|
||||
if (state === Resource.State.FAILED) { throw "Failed to load frame"; }
|
||||
if (state !== Resource.State.FINISHED) { return; }
|
||||
|
||||
var pictureFrameProperties = {
|
||||
name: 'scriptableResourceTest Picture Frame',
|
||||
|
@ -50,7 +50,6 @@ function getFrame(callback) {
|
|||
position.x += - 5 * Math.sin(rads);
|
||||
position.z += - 5 * Math.cos(rads);
|
||||
|
||||
print(JSON.stringify(position));
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
@ -67,10 +66,10 @@ function prefetch(callback) {
|
|||
var filepath = MOVIE_URL + padded + '.jpg';
|
||||
var texture = TextureCache.prefetch(filepath);
|
||||
frames.push(texture);
|
||||
if (!texture.state == Resource.State.FINISHED) {
|
||||
if (texture.state !== Resource.State.FINISHED) {
|
||||
numLoading++;
|
||||
texture.stateChanged.connect(function(state) {
|
||||
if (state == Resource.State.FAILED || state == Resource.State.FINISHED) {
|
||||
if (state === Resource.State.FAILED || state === Resource.State.FINISHED) {
|
||||
--numLoading;
|
||||
if (!numLoading) { callback(frames); }
|
||||
}
|
||||
|
|
34
scripts/developer/tests/scriptableResource/loadPerfTest.js
Normal file
34
scripts/developer/tests/scriptableResource/loadPerfTest.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// loadPerfTest.js
|
||||
// scripts/developer/tests/scriptableResource
|
||||
//
|
||||
// Created by Zach Pomerantz on 4/27/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Preloads 158 textures 50 times for performance profiling.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var TIMES = 50;
|
||||
|
||||
Script.include([
|
||||
'../../../developer/utilities/cache/cacheStats.js',
|
||||
'lib.js',
|
||||
], function() {
|
||||
var fetch = function() {
|
||||
prefetch(function(frames) {
|
||||
while (frames.length) { frames.pop(); }
|
||||
Script.requestGarbageCollection();
|
||||
|
||||
if (--TIMES > 0) {
|
||||
// Pause a bit to avoid a deadlock
|
||||
var DEADLOCK_AVOIDANCE_TIMEOUT = 100;
|
||||
Script.setTimeout(fetch, DEADLOCK_AVOIDANCE_TIMEOUT);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
fetch();
|
||||
});
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// testMovie.js
|
||||
// movieTest.js
|
||||
// scripts/developer/tests/scriptableResource
|
||||
//
|
||||
// Created by Zach Pomerantz on 4/27/16.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// testPrefetch.js
|
||||
// prefetchTest.js
|
||||
// scripts/developer/tests/scriptableResource
|
||||
//
|
||||
// Created by Zach Pomerantz on 4/27/16.
|
||||
|
|
|
@ -29,6 +29,10 @@ var IDENTITY_QUAT = {
|
|||
var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with handControllerGrab.js
|
||||
var GRAB_USER_DATA_KEY = "grabKey"; // shared with handControllerGrab.js
|
||||
|
||||
var MSECS_PER_SEC = 1000.0;
|
||||
var HEART_BEAT_INTERVAL = 5 * MSECS_PER_SEC;
|
||||
var HEART_BEAT_TIMEOUT = 15 * MSECS_PER_SEC;
|
||||
|
||||
var DEFAULT_GRABBABLE_DATA = {
|
||||
grabbable: true,
|
||||
invertSolidWhileHeld: false
|
||||
|
@ -335,6 +339,9 @@ Grabber.prototype.pressEvent = function(event) {
|
|||
|
||||
mouse.startDrag(event);
|
||||
|
||||
var now = Date.now();
|
||||
this.lastHeartBeat = 0;
|
||||
|
||||
var clickedEntity = pickResults.entityID;
|
||||
var entityProperties = Entities.getEntityProperties(clickedEntity)
|
||||
this.startPosition = entityProperties.position;
|
||||
|
@ -376,7 +383,16 @@ Grabber.prototype.pressEvent = function(event) {
|
|||
if(!entityIsGrabbedByOther(this.entityID)){
|
||||
this.moveEvent(event);
|
||||
}
|
||||
|
||||
|
||||
var args = "mouse";
|
||||
Entities.callEntityMethod(this.entityID, "startDistanceGrab", args);
|
||||
|
||||
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
|
||||
action: 'grab',
|
||||
grabbedEntity: this.entityID
|
||||
}));
|
||||
|
||||
|
||||
// TODO: play sounds again when we aren't leaking AudioInjector threads
|
||||
//Audio.playSound(grabSound, { position: entityProperties.position, volume: VOLUME });
|
||||
}
|
||||
|
@ -394,17 +410,41 @@ Grabber.prototype.releaseEvent = function(event) {
|
|||
|
||||
beacon.disable();
|
||||
|
||||
var args = "mouse";
|
||||
Entities.callEntityMethod(this.entityID, "releaseGrab", args);
|
||||
|
||||
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
|
||||
action: 'release',
|
||||
grabbedEntity: this.entityID,
|
||||
joint: "mouse"
|
||||
}));
|
||||
|
||||
|
||||
// TODO: play sounds again when we aren't leaking AudioInjector threads
|
||||
//Audio.playSound(releaseSound, { position: entityProperties.position, volume: VOLUME });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Grabber.prototype.heartBeat = function(entityID) {
|
||||
var now = Date.now();
|
||||
if (now - this.lastHeartBeat > HEART_BEAT_INTERVAL) {
|
||||
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
||||
data["heartBeat"] = now;
|
||||
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
|
||||
this.lastHeartBeat = now;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Grabber.prototype.moveEvent = function(event) {
|
||||
if (!this.isGrabbing) {
|
||||
return;
|
||||
}
|
||||
mouse.updateDrag(event);
|
||||
|
||||
this.heartBeat(this.entityID);
|
||||
|
||||
// see if something added/restored gravity
|
||||
var entityProperties = Entities.getEntityProperties(this.entityID);
|
||||
if (Vec3.length(entityProperties.gravity) != 0) {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
/*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt, pointInExtents, vec3equal, setEntityCustomData, getEntityCustomData */
|
||||
|
||||
Script.include("../libraries/utils.js");
|
||||
Script.include("/~/system/libraries/utils.js");
|
||||
|
||||
|
||||
//
|
||||
|
@ -28,7 +28,7 @@ var WANT_DEBUG_SEARCH_NAME = null;
|
|||
|
||||
var TRIGGER_SMOOTH_RATIO = 0.1; // Time averaging of trigger - 0.0 disables smoothing
|
||||
var TRIGGER_ON_VALUE = 0.4; // Squeezed just enough to activate search or near grab
|
||||
var TRIGGER_GRAB_VALUE = 0.85; // Squeezed far enough to complete distant grab
|
||||
var TRIGGER_GRAB_VALUE = 0.75; // Squeezed far enough to complete distant grab
|
||||
var TRIGGER_OFF_VALUE = 0.15;
|
||||
|
||||
var BUMPER_ON_VALUE = 0.5;
|
||||
|
@ -102,7 +102,6 @@ var ZERO_VEC = {
|
|||
};
|
||||
|
||||
var NULL_UUID = "{00000000-0000-0000-0000-000000000000}";
|
||||
var MSEC_PER_SEC = 1000.0;
|
||||
|
||||
// these control how long an abandoned pointer line or action will hang around
|
||||
var LIFETIME = 10;
|
||||
|
@ -740,10 +739,6 @@ function MyController(hand) {
|
|||
};
|
||||
|
||||
this.propsArePhysical = function(props) {
|
||||
if (!props.dynamic && props.parentID != MyAvatar.sessionUUID) {
|
||||
// if we have parented something, don't do this check on dynamic.
|
||||
return false;
|
||||
}
|
||||
var isPhysical = (props.shapeType && props.shapeType != 'none');
|
||||
return isPhysical;
|
||||
}
|
||||
|
@ -837,7 +832,7 @@ function MyController(hand) {
|
|||
this.search = function() {
|
||||
this.grabbedEntity = null;
|
||||
this.isInitialGrab = false;
|
||||
this.doubleParentGrab = false;
|
||||
this.shouldResetParentOnRelease = false;
|
||||
|
||||
this.checkForStrayChildren();
|
||||
|
||||
|
@ -914,7 +909,7 @@ function MyController(hand) {
|
|||
candidateEntities = rayPickedCandidateEntities.concat(nearPickedCandidateEntities);
|
||||
|
||||
var forbiddenNames = ["Grab Debug Entity", "grab pointer"];
|
||||
var forbiddenTypes = ['Unknown', 'Light', 'ParticleEffect', 'PolyLine', 'Zone'];
|
||||
var forbiddenTypes = ['Unknown', 'Light', 'PolyLine', 'Zone'];
|
||||
|
||||
var minDistance = PICK_MAX_DISTANCE;
|
||||
var i, props, distance, grabbableData;
|
||||
|
@ -1019,6 +1014,10 @@ function MyController(hand) {
|
|||
if (this.state == STATE_SEARCHING) {
|
||||
this.setState(STATE_NEAR_GRABBING);
|
||||
} else { // (this.state == STATE_HOLD_SEARCHING)
|
||||
// if there was already an action, we'll need to set the parent back to null once we release
|
||||
this.shouldResetParentOnRelease = true;
|
||||
this.previousParentID = props.parentID;
|
||||
this.previousParentJointIndex = props.parentJointIndex;
|
||||
this.setState(STATE_HOLD);
|
||||
}
|
||||
return;
|
||||
|
@ -1064,7 +1063,7 @@ function MyController(hand) {
|
|||
// it's not physical and it's already held via parenting. go ahead and grab it, but
|
||||
// save off the current parent and joint. this wont always be right if there are more than
|
||||
// two grabs and the order of release isn't opposite of the order of grabs.
|
||||
this.doubleParentGrab = true;
|
||||
this.shouldResetParentOnRelease = true;
|
||||
this.previousParentID = props.parentID;
|
||||
this.previousParentJointIndex = props.parentJointIndex;
|
||||
if (this.state == STATE_SEARCHING) {
|
||||
|
@ -1149,7 +1148,7 @@ function MyController(hand) {
|
|||
if (this.actionID === NULL_UUID) {
|
||||
this.actionID = null;
|
||||
}
|
||||
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
|
||||
this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC);
|
||||
|
||||
if (this.actionID !== null) {
|
||||
this.setState(STATE_CONTINUE_DISTANCE_HOLDING);
|
||||
|
@ -1184,7 +1183,7 @@ function MyController(hand) {
|
|||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
|
||||
|
||||
var now = Date.now();
|
||||
var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds
|
||||
var deltaTime = (now - this.currentObjectTime) / MSECS_PER_SEC; // convert to seconds
|
||||
this.currentObjectTime = now;
|
||||
|
||||
// the action was set up when this.distanceHolding was called. update the targets.
|
||||
|
@ -1302,7 +1301,7 @@ function MyController(hand) {
|
|||
ttl: ACTION_TTL
|
||||
});
|
||||
if (success) {
|
||||
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
|
||||
this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC);
|
||||
} else {
|
||||
print("continueDistanceHolding -- updateAction failed");
|
||||
}
|
||||
|
@ -1327,7 +1326,7 @@ function MyController(hand) {
|
|||
return false;
|
||||
}
|
||||
var now = Date.now();
|
||||
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
|
||||
this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC);
|
||||
return true;
|
||||
};
|
||||
|
||||
|
@ -1436,6 +1435,10 @@ function MyController(hand) {
|
|||
if (!this.setupHoldAction()) {
|
||||
return;
|
||||
}
|
||||
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
|
||||
action: 'grab',
|
||||
grabbedEntity: this.grabbedEntity
|
||||
}));
|
||||
} else {
|
||||
// grab entity via parenting
|
||||
this.actionID = null;
|
||||
|
@ -1563,7 +1566,7 @@ function MyController(hand) {
|
|||
var now = Date.now();
|
||||
|
||||
var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters
|
||||
var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds
|
||||
var deltaTime = (now - this.currentObjectTime) / MSECS_PER_SEC; // convert to seconds
|
||||
|
||||
if (deltaTime > 0.0) {
|
||||
var worldDeltaPosition = Vec3.subtract(props.position, this.currentObjectPosition);
|
||||
|
@ -1590,7 +1593,7 @@ function MyController(hand) {
|
|||
this.callEntityMethodOnGrabbed("continueNearGrab");
|
||||
}
|
||||
|
||||
if (this.actionID && this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) {
|
||||
if (this.actionID && this.actionTimeout - now < ACTION_TTL_REFRESH * MSECS_PER_SEC) {
|
||||
// if less than a 5 seconds left, refresh the actions ttl
|
||||
var success = Entities.updateAction(this.grabbedEntity, this.actionID, {
|
||||
hand: this.hand === RIGHT_HAND ? "right" : "left",
|
||||
|
@ -1603,7 +1606,7 @@ function MyController(hand) {
|
|||
ignoreIK: this.ignoreIK
|
||||
});
|
||||
if (success) {
|
||||
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
|
||||
this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC);
|
||||
} else {
|
||||
print("continueNearGrabbing -- updateAction failed");
|
||||
Entities.deleteAction(this.grabbedEntity, this.actionID);
|
||||
|
@ -1838,12 +1841,12 @@ function MyController(hand) {
|
|||
|
||||
// things that are held by parenting and dropped with no velocity will end up as "static" in bullet. If
|
||||
// it looks like the dropped thing should fall, give it a little velocity.
|
||||
var props = Entities.getEntityProperties(entityID, ["parentID", "velocity"])
|
||||
var props = Entities.getEntityProperties(entityID, ["parentID", "velocity", "dynamic", "shapeType"])
|
||||
var parentID = props.parentID;
|
||||
var forceVelocity = false;
|
||||
|
||||
var doSetVelocity = false;
|
||||
if (parentID != NULL_UUID && deactiveProps.parentID == NULL_UUID) {
|
||||
if (parentID != NULL_UUID && deactiveProps.parentID == NULL_UUID && this.propsArePhysical(props)) {
|
||||
// TODO: EntityScriptingInterface::convertLocationToScriptSemantics should be setting up
|
||||
// props.velocity to be a world-frame velocity and localVelocity to be vs parent. Until that
|
||||
// is done, we use a measured velocity here so that things held via a bumper-grab / parenting-grab
|
||||
|
@ -1881,7 +1884,7 @@ function MyController(hand) {
|
|||
}
|
||||
|
||||
data = null;
|
||||
} else if (this.doubleParentGrab) {
|
||||
} else if (this.shouldResetParentOnRelease) {
|
||||
// we parent-grabbed this from another parent grab. try to put it back where we found it.
|
||||
var deactiveProps = {
|
||||
parentID: this.previousParentID,
|
||||
|
@ -1892,7 +1895,8 @@ function MyController(hand) {
|
|||
Entities.editEntity(entityID, deactiveProps);
|
||||
} else if (noVelocity) {
|
||||
Entities.editEntity(entityID, {velocity: {x: 0.0, y: 0.0, z: 0.0},
|
||||
angularVelocity: {x: 0.0, y: 0.0, z: 0.0}});
|
||||
angularVelocity: {x: 0.0, y: 0.0, z: 0.0},
|
||||
dynamic: data["dynamic"]});
|
||||
}
|
||||
} else {
|
||||
data = null;
|
||||
|
|
181
scripts/tutorials/NBody/gravity.js
Normal file
181
scripts/tutorials/NBody/gravity.js
Normal file
|
@ -0,0 +1,181 @@
|
|||
// gravity.js
|
||||
//
|
||||
// Created by Philip Rosedale on March 29, 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
// This entity script causes the object to move with gravitational force and be attracted to other spheres nearby.
|
||||
// The force is scaled by GRAVITY_STRENGTH, and only entities of type "Sphere" within GRAVITY_RANGE will affect it.
|
||||
// The person who has most recently grabbed this object will simulate it.
|
||||
//
|
||||
|
||||
function Timer() {
|
||||
var time;
|
||||
var count = 0;
|
||||
var totalTime = 0;
|
||||
this.reset = function() {
|
||||
count = 0;
|
||||
totalTime = 0;
|
||||
}
|
||||
this.start = function() {
|
||||
time = new Date().getTime();
|
||||
}
|
||||
this.record = function() {
|
||||
var elapsed = new Date().getTime() - time;
|
||||
totalTime += elapsed;
|
||||
count++;
|
||||
return elapsed;
|
||||
}
|
||||
this.count = function() {
|
||||
return count;
|
||||
}
|
||||
this.average = function() {
|
||||
return (count == 0) ? 0 : totalTime / count;
|
||||
}
|
||||
this.elapsed = function() {
|
||||
return new Date().getTime() - time;
|
||||
}
|
||||
}
|
||||
|
||||
(function () {
|
||||
var entityID,
|
||||
wantDebug = true,
|
||||
CHECK_INTERVAL = 10.00,
|
||||
SEARCH_INTERVAL = 1000,
|
||||
GRAVITY_RANGE = 20.0,
|
||||
GRAVITY_STRENGTH = 1.0,
|
||||
MIN_VELOCITY = 0.01,
|
||||
timeoutID = null,
|
||||
timeSinceLastSearch = 0,
|
||||
timer = new Timer(),
|
||||
simulate = false,
|
||||
spheres = [];
|
||||
|
||||
var printDebug = function(message) {
|
||||
if (wantDebug) {
|
||||
print(message);
|
||||
}
|
||||
}
|
||||
|
||||
var greatestDimension = function(dimensions) {
|
||||
return Math.max(Math.max(dimensions.x, dimensions.y), dimensions.z);
|
||||
}
|
||||
|
||||
var mass2 = function(dimensions) {
|
||||
return dimensions.x * dimensions.y * dimensions.z;
|
||||
}
|
||||
|
||||
var findSpheres = function(position) {
|
||||
var entities = Entities.findEntities(position, GRAVITY_RANGE);
|
||||
spheres = [];
|
||||
for (var i = 0; i < entities.length; i++) {
|
||||
if (entityID == spheres[i]) {
|
||||
// this entity doesn't experience its own gravity.
|
||||
continue;
|
||||
}
|
||||
var props = Entities.getEntityProperties(entities[i]);
|
||||
if (props && (props.shapeType == "sphere" || props.type == "Sphere")) {
|
||||
spheres.push(entities[i]);
|
||||
}
|
||||
}
|
||||
// print("FOUND " + spheres.length + " SPHERES");
|
||||
}
|
||||
|
||||
var applyGravity = function() {
|
||||
if (!simulate) {
|
||||
return;
|
||||
}
|
||||
|
||||
var properties = Entities.getEntityProperties(entityID);
|
||||
if (!properties || !properties.position) {
|
||||
return;
|
||||
}
|
||||
|
||||
// update the list of nearby spheres
|
||||
var deltaTime = timer.elapsed() / 1000.0;
|
||||
if (deltaTime == 0.0) {
|
||||
return;
|
||||
}
|
||||
timeSinceLastSearch += CHECK_INTERVAL;
|
||||
if (timeSinceLastSearch >= SEARCH_INTERVAL) {
|
||||
findSpheres(properties.position);
|
||||
timeSinceLastSearch = 0;
|
||||
}
|
||||
|
||||
var deltaVelocity = { x: 0, y: 0, z: 0 };
|
||||
var otherCount = 0;
|
||||
var mass = mass2(properties.dimensions);
|
||||
|
||||
for (var i = 0; i < spheres.length; i++) {
|
||||
otherProperties = Entities.getEntityProperties(spheres[i]);
|
||||
if (!otherProperties || !otherProperties.position) {
|
||||
continue; // sphere was deleted
|
||||
}
|
||||
otherCount++;
|
||||
var radius = Vec3.distance(properties.position, otherProperties.position);
|
||||
var otherMass = mass2(otherProperties.dimensions);
|
||||
var r = (greatestDimension(properties.dimensions) + greatestDimension(otherProperties.dimensions)) / 2;
|
||||
if (radius > r) {
|
||||
var n0 = Vec3.normalize(Vec3.subtract(otherProperties.position, properties.position));
|
||||
var n1 = Vec3.multiply(deltaTime * GRAVITY_STRENGTH * otherMass / (radius * radius), n0);
|
||||
deltaVelocity = Vec3.sum(deltaVelocity, n1);
|
||||
}
|
||||
}
|
||||
Entities.editEntity(entityID, { velocity: Vec3.sum(properties.velocity, deltaVelocity) });
|
||||
if (Vec3.length(properties.velocity) < MIN_VELOCITY) {
|
||||
print("Gravity simulation stopped due to velocity");
|
||||
simulate = false;
|
||||
} else {
|
||||
timer.start();
|
||||
timeoutID = Script.setTimeout(applyGravity, CHECK_INTERVAL);
|
||||
}
|
||||
}
|
||||
this.applyGravity = applyGravity;
|
||||
|
||||
var releaseGrab = function() {
|
||||
printDebug("Gravity simulation started.");
|
||||
var properties = Entities.getEntityProperties(entityID);
|
||||
findSpheres(properties.position);
|
||||
timer.start();
|
||||
timeoutID = Script.setTimeout(applyGravity, CHECK_INTERVAL);
|
||||
simulate = true;
|
||||
}
|
||||
this.releaseGrab = releaseGrab;
|
||||
|
||||
var preload = function (givenEntityID) {
|
||||
printDebug("load gravity...");
|
||||
entityID = givenEntityID;
|
||||
};
|
||||
this.preload = preload;
|
||||
|
||||
var unload = function () {
|
||||
printDebug("Unload gravity...");
|
||||
if (timeoutID !== undefined) {
|
||||
Script.clearTimeout(timeoutID);
|
||||
}
|
||||
if (simulate) {
|
||||
Entities.editEntity(entityID, { velocity: { x: 0, y: 0, z: 0 } });
|
||||
}
|
||||
};
|
||||
this.unload = unload;
|
||||
|
||||
var handleMessages = function(channel, message, sender) {
|
||||
if (channel === 'Hifi-Object-Manipulation') {
|
||||
try {
|
||||
var parsedMessage = JSON.parse(message);
|
||||
if (parsedMessage.action === 'grab' && parsedMessage.grabbedEntity == entityID) {
|
||||
print("Gravity simulation stopped due to grab");
|
||||
simulate = false;
|
||||
}
|
||||
} catch (e) {
|
||||
print('error parsing Hifi-Object-Manipulation message: ' + message);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.handleMessages = handleMessages;
|
||||
|
||||
Messages.messageReceived.connect(this.handleMessages);
|
||||
Messages.subscribe('Hifi-Object-Manipulation');
|
||||
});
|
72
scripts/tutorials/NBody/gravity.svg
Normal file
72
scripts/tutorials/NBody/gravity.svg
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64"
|
||||
height="64"
|
||||
viewBox="0 0 64.000001 64.000001"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="gravity.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.4"
|
||||
inkscape:cx="192.07838"
|
||||
inkscape:cy="33.619203"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:window-width="2782"
|
||||
inkscape:window-height="1764"
|
||||
inkscape:window-x="98"
|
||||
inkscape:window-y="36"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-988.36216)">
|
||||
<ellipse
|
||||
style="fill:#a09898;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
id="path4690"
|
||||
cx="12.142858"
|
||||
cy="1039.1478"
|
||||
rx="8.5714283"
|
||||
ry="8.2142859" />
|
||||
<ellipse
|
||||
style="fill:#3131d9;fill-opacity:1;stroke:#000000;stroke-width:3;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
id="path4692"
|
||||
cx="39.285717"
|
||||
cy="1014.1478"
|
||||
rx="21.358366"
|
||||
ry="21.001223" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
166
scripts/tutorials/NBody/makePlanets.js
Normal file
166
scripts/tutorials/NBody/makePlanets.js
Normal file
|
@ -0,0 +1,166 @@
|
|||
// makePlanets.js
|
||||
//
|
||||
// Created by Philip Rosedale on March 29, 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
// Make an earth and moon, where you can grab and throw moon into orbit. Entity
|
||||
// script attached to moon gives it gravitation behavior and will also make it attracted to
|
||||
// other spheres placed nearby.
|
||||
//
|
||||
|
||||
var SCALE = 3.0;
|
||||
var EARTH_SIZE = 3.959 / SCALE;
|
||||
var MOON_SIZE = 1.079 / SCALE;
|
||||
|
||||
var BUTTON_SIZE = 32;
|
||||
var PADDING = 3;
|
||||
|
||||
var earth = null;
|
||||
var moon = null;
|
||||
|
||||
var SCRIPT_URL = Script.resolvePath("gravity.js");
|
||||
|
||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||
Script.include(["/~/system/libraries/toolBars.js"]);
|
||||
var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.makePlanets.js");
|
||||
|
||||
var makePlanetsIconURL = Script.resolvePath("gravity.svg");
|
||||
var button = toolBar.addOverlay("image", {
|
||||
width: BUTTON_SIZE,
|
||||
height: BUTTON_SIZE,
|
||||
imageURL: makePlanetsIconURL,
|
||||
color: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
},
|
||||
alpha: 1
|
||||
});
|
||||
|
||||
var deleteButton = toolBar.addOverlay("image", {
|
||||
width: BUTTON_SIZE,
|
||||
height: BUTTON_SIZE,
|
||||
imageURL: HIFI_PUBLIC_BUCKET + "images/delete.png",
|
||||
color: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
},
|
||||
alpha: 1
|
||||
});
|
||||
|
||||
function inFrontOfMe(distance) {
|
||||
return Vec3.sum(Camera.getPosition(), Vec3.multiply(distance, Quat.getFront(Camera.getOrientation())));
|
||||
}
|
||||
|
||||
function onButtonClick() {
|
||||
earth = Entities.addEntity({
|
||||
type: "Model",
|
||||
name: "Earth",
|
||||
modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/seth/production/NBody/earth.fbx",
|
||||
position: inFrontOfMe(2 * EARTH_SIZE),
|
||||
dimensions: { x: EARTH_SIZE, y: EARTH_SIZE, z: EARTH_SIZE },
|
||||
shapeType: "sphere",
|
||||
lifetime: 86400, // 1 day
|
||||
angularDamping: 0,
|
||||
angularVelocity: { x: 0, y: 0.1, z: 0 },
|
||||
});
|
||||
moon = Entities.addEntity({
|
||||
type: "Model",
|
||||
name: "Moon",
|
||||
modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/seth/production/NBody/moon.fbx",
|
||||
position: inFrontOfMe(EARTH_SIZE - MOON_SIZE),
|
||||
dimensions: { x: MOON_SIZE, y: MOON_SIZE, z: MOON_SIZE },
|
||||
dynamic: true,
|
||||
damping: 0, // 0.01,
|
||||
angularDamping: 0, // 0.01,
|
||||
script: SCRIPT_URL,
|
||||
shapeType: "sphere"
|
||||
});
|
||||
Entities.addEntity({
|
||||
"accelerationSpread": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"alpha": 1,
|
||||
"alphaFinish": 0,
|
||||
"alphaStart": 1,
|
||||
"azimuthFinish": 0,
|
||||
"azimuthStart": 0,
|
||||
"color": {
|
||||
"blue": 255,
|
||||
"green": 255,
|
||||
"red": 255
|
||||
},
|
||||
"colorFinish": {
|
||||
"blue": 255,
|
||||
"green": 255,
|
||||
"red": 255
|
||||
},
|
||||
"colorStart": {
|
||||
"blue": 255,
|
||||
"green": 255,
|
||||
"red": 255
|
||||
},
|
||||
"dimensions": {
|
||||
"x": 0.10890001058578491,
|
||||
"y": 0.10890001058578491,
|
||||
"z": 0.10890001058578491
|
||||
},
|
||||
"emitAcceleration": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"emitOrientation": {
|
||||
"w": 0.99999994039535522,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"emitRate": 300,
|
||||
"emitSpeed": 0,
|
||||
"emitterShouldTrail": 1,
|
||||
"maxParticles": 10000,
|
||||
"name": "moon trail",
|
||||
"parentID": moon,
|
||||
"particleRadius": 0.005,
|
||||
"radiusFinish": 0.005,
|
||||
"radiusSpread": 0.005,
|
||||
"radiusStart": 0.005,
|
||||
"speedSpread": 0,
|
||||
"lifespan": 20,
|
||||
"textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png",
|
||||
"type": "ParticleEffect",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||
});
|
||||
}
|
||||
|
||||
function onDeleteButton() {
|
||||
Entities.deleteEntity(earth);
|
||||
Entities.deleteEntity(moon);
|
||||
}
|
||||
|
||||
function mousePressEvent(event) {
|
||||
var clickedText = false;
|
||||
var clickedOverlay = Overlays.getOverlayAtPoint({
|
||||
x: event.x,
|
||||
y: event.y
|
||||
});
|
||||
if (clickedOverlay == button) {
|
||||
onButtonClick();
|
||||
} else if (clickedOverlay == deleteButton) {
|
||||
onDeleteButton();
|
||||
}
|
||||
}
|
||||
|
||||
function scriptEnding() {
|
||||
toolBar.cleanup();
|
||||
}
|
||||
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
|
@ -7,6 +7,6 @@ setup_hifi_project(Network Script)
|
|||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(entities avatars shared octree gpu model fbx networking animation)
|
||||
link_hifi_libraries(entities avatars shared octree gpu model fbx networking animation audio)
|
||||
|
||||
package_libraries_for_deployment()
|
||||
|
|
Loading…
Reference in a new issue