Merge branch 'master' of github.com:highfidelity/hifi into fix-stanard-library-include-some-more

This commit is contained in:
Seth Alves 2016-05-09 18:39:37 -07:00
commit 68201746aa
49 changed files with 692 additions and 329 deletions

View file

@ -386,8 +386,7 @@ void Agent::sendAvatarBillboardPacket() {
void Agent::processAgentAvatarAndAudio(float deltaTime) { void Agent::processAgentAvatarAndAudio(float deltaTime) {
if (!_scriptEngine->isFinished() && _isAvatar) { if (!_scriptEngine->isFinished() && _isAvatar) {
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>(); auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
const int SCRIPT_AUDIO_BUFFER_SAMPLES = floor(((SCRIPT_DATA_CALLBACK_USECS * AudioConstants::SAMPLE_RATE) const int SCRIPT_AUDIO_BUFFER_SAMPLES = AudioConstants::SAMPLE_RATE / SCRIPT_FPS + 0.5;
/ (1000 * 1000)) + 0.5);
const int SCRIPT_AUDIO_BUFFER_BYTES = SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t); const int SCRIPT_AUDIO_BUFFER_BYTES = SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t);
QByteArray avatarByteArray = scriptedAvatar->toByteArray(true, randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO); QByteArray avatarByteArray = scriptedAvatar->toByteArray(true, randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO);

View file

@ -9,6 +9,9 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include <chrono>
#include <thread>
#include <NodeList.h> #include <NodeList.h>
#include <NumericalConstants.h> #include <NumericalConstants.h>
#include <udt/PacketHeaders.h> #include <udt/PacketHeaders.h>
@ -101,13 +104,16 @@ bool OctreeSendThread::process() {
int elapsed = (usecTimestampNow() - start); int elapsed = (usecTimestampNow() - start);
int usecToSleep = OCTREE_SEND_INTERVAL_USECS - elapsed; int usecToSleep = OCTREE_SEND_INTERVAL_USECS - elapsed;
if (usecToSleep > 0) { if (usecToSleep <= 0) {
PerformanceWarning warn(false,"OctreeSendThread... usleep()",false,&_usleepTime,&_usleepCalls);
usleep(usecToSleep);
} else {
const int MIN_USEC_TO_SLEEP = 1; 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 return isStillRunning(); // keep running till they terminate us

View file

@ -1,31 +1,52 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!-- Generator: Adobe Illustrator 19.2.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" <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"
x="0px" y="0px" width="1600px" height="100px" viewBox="0 0 1600 100" xml:space="preserve"> viewBox="0 0 1600 100" style="enable-background:new 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 <style type="text/css">
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 .st0{fill:#FFFFFF;}
c3.7,6.5,12,8.8,18.5,5.1C94.2,84.1,96.5,75.8,92.8,69.3z"/> </style>
<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 <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
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 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
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"/> 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="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 <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
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"/> 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
<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 "/> 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"/>
<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 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
<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 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"/>
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 <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 "/>
c0-4.3-0.8-8.3-2.2-12.1H174.3z"/> <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 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 <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
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 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
c0-2.9-0.4-5.8-1.1-8.5L278.8,53z"/> C182.1,42.8,174.3,42.8,174.3,42.8z"/>
<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 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
<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 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
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"/> c0-2.9-0.4-5.8-1.1-8.5L278.8,53z"/>
<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 <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 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-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-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 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"/> 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 "/> <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 "/>
</svg> <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

View file

@ -3013,8 +3013,19 @@ void Application::init() {
_entityClipboardRenderer.setTree(_entityClipboard); _entityClipboardRenderer.setTree(_entityClipboard);
// Make sure any new sounds are loaded as soon as know about them. // 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(tree.get(), &EntityTree::newCollisionSoundURL, this, [this](QUrl newURL, EntityItemID id) {
connect(getMyAvatar(), &MyAvatar::newCollisionSoundURL, DependencyManager::get<SoundCache>().data(), &SoundCache::getSound); 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 { void Application::updateLOD() const {

View file

@ -93,13 +93,13 @@ void AvatarActionHold::prepareForPhysicsSimulation() {
activateBody(true); activateBody(true);
} }
std::shared_ptr<Avatar> AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position, bool AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position,
glm::vec3& linearVelocity, glm::vec3& angularVelocity) { glm::vec3& linearVelocity, glm::vec3& angularVelocity) {
auto avatarManager = DependencyManager::get<AvatarManager>(); auto avatarManager = DependencyManager::get<AvatarManager>();
auto holdingAvatar = std::static_pointer_cast<Avatar>(avatarManager->getAvatarBySessionID(_holderID)); auto holdingAvatar = std::static_pointer_cast<Avatar>(avatarManager->getAvatarBySessionID(_holderID));
if (!holdingAvatar) { if (!holdingAvatar) {
return holdingAvatar; return false;;
} }
withReadLock([&]{ withReadLock([&]{
@ -171,62 +171,17 @@ std::shared_ptr<Avatar> AvatarActionHold::getTarget(float deltaTimeStep, glm::qu
linearVelocity = linearVelocity + glm::cross(angularVelocity, position - palmPosition); linearVelocity = linearVelocity + glm::cross(angularVelocity, position - palmPosition);
}); });
return holdingAvatar; return true;
} }
void AvatarActionHold::updateActionWorker(float deltaTimeStep) { void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
glm::quat rotation; if (_kinematic) {
glm::vec3 position; if (prepareForSpringUpdate(deltaTimeStep)) {
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) {
doKinematicUpdate(deltaTimeStep); doKinematicUpdate(deltaTimeStep);
} else {
forceBodyNonStatic();
ObjectActionSpring::updateActionWorker(deltaTimeStep);
} }
} else {
forceBodyNonStatic();
ObjectActionSpring::updateActionWorker(deltaTimeStep);
} }
} }

View file

@ -36,8 +36,8 @@ public:
virtual bool shouldSuppressLocationEdits() override { return _active && !_ownerEntity.expired(); } virtual bool shouldSuppressLocationEdits() override { return _active && !_ownerEntity.expired(); }
bool getAvatarRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation); bool getAvatarRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation);
std::shared_ptr<Avatar> getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position, virtual bool getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position,
glm::vec3& linearVelocity, glm::vec3& angularVelocity); glm::vec3& linearVelocity, glm::vec3& angularVelocity) override;
virtual void prepareForPhysicsSimulation() override; virtual void prepareForPhysicsSimulation() override;
@ -51,9 +51,6 @@ private:
QString _hand { "right" }; QString _hand { "right" };
QUuid _holderID; QUuid _holderID;
glm::vec3 _linearVelocityTarget;
glm::vec3 _angularVelocityTarget;
bool _kinematic { false }; bool _kinematic { false };
bool _kinematicSetVelocity { false }; bool _kinematicSetVelocity { false };
bool _previousSet { false }; bool _previousSet { false };

View file

@ -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.) // my avatar. (Other user machines will make a similar analysis and inject sound for their collisions.)
if (collision.idA.isNull() || collision.idB.isNull()) { if (collision.idA.isNull() || collision.idB.isNull()) {
MyAvatar* myAvatar = getMyAvatar(); MyAvatar* myAvatar = getMyAvatar();
const QString& collisionSoundURL = myAvatar->getCollisionSoundURL(); auto collisionSound = myAvatar->getCollisionSound();
if (!collisionSoundURL.isEmpty()) { if (collisionSound) {
const float velocityChange = glm::length(collision.velocityChange); 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 float MIN_AVATAR_COLLISION_ACCELERATION = 0.01f;
const bool isSound = (collision.type == CONTACT_EVENT_TYPE_START) && (velocityChange > MIN_AVATAR_COLLISION_ACCELERATION); 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. // but most avatars are roughly the same size, so let's not be so fancy yet.
const float AVATAR_STRETCH_FACTOR = 1.0f; 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); myAvatar->collisionWithEntity(collision);
return; return;
} }

View file

@ -23,7 +23,6 @@
#include <AccountManager.h> #include <AccountManager.h>
#include <AddressManager.h> #include <AddressManager.h>
#include <AudioClient.h> #include <AudioClient.h>
#include <DependencyManager.h>
#include <display-plugins/DisplayPlugin.h> #include <display-plugins/DisplayPlugin.h>
#include <FSTReader.h> #include <FSTReader.h>
#include <GeometryUtil.h> #include <GeometryUtil.h>
@ -32,6 +31,7 @@
#include <PathUtils.h> #include <PathUtils.h>
#include <PerfStat.h> #include <PerfStat.h>
#include <SharedUtil.h> #include <SharedUtil.h>
#include <SoundCache.h>
#include <TextRenderer3D.h> #include <TextRenderer3D.h>
#include <UserActivityLogger.h> #include <UserActivityLogger.h>
#include <AnimDebugDraw.h> #include <AnimDebugDraw.h>
@ -97,7 +97,6 @@ MyAvatar::MyAvatar(RigPointer rig) :
_scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE), _scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE),
_scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME), _scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME),
_motionBehaviors(AVATAR_MOTION_DEFAULTS), _motionBehaviors(AVATAR_MOTION_DEFAULTS),
_collisionSoundURL(""),
_characterController(this), _characterController(this),
_lookAtTargetAvatar(), _lookAtTargetAvatar(),
_shouldRender(true), _shouldRender(true),
@ -1232,12 +1231,20 @@ void MyAvatar::clearScriptableSettings() {
} }
void MyAvatar::setCollisionSoundURL(const QString& url) { void MyAvatar::setCollisionSoundURL(const QString& url) {
_collisionSoundURL = url; if (url != _collisionSoundURL) {
if (!url.isEmpty() && (url != _collisionSoundURL)) { _collisionSoundURL = url;
emit newCollisionSoundURL(QUrl(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, void MyAvatar::attach(const QString& modelURL, const QString& jointName,
const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& translation, const glm::quat& rotation,
float scale, bool isSoft, float scale, bool isSoft,

View file

@ -16,6 +16,7 @@
#include <SettingHandle.h> #include <SettingHandle.h>
#include <Rig.h> #include <Rig.h>
#include <Sound.h>
#include <controllers/Pose.h> #include <controllers/Pose.h>
@ -222,6 +223,9 @@ public:
const QString& getCollisionSoundURL() { return _collisionSoundURL; } const QString& getCollisionSoundURL() { return _collisionSoundURL; }
void setCollisionSoundURL(const QString& url); void setCollisionSoundURL(const QString& url);
SharedSoundPointer getCollisionSound();
void setCollisionSound(SharedSoundPointer sound) { _collisionSound = sound; }
void clearScriptableSettings(); void clearScriptableSettings();
float getBoomLength() const { return _boomLength; } float getBoomLength() const { return _boomLength; }
@ -362,6 +366,8 @@ private:
quint32 _motionBehaviors; quint32 _motionBehaviors;
QString _collisionSoundURL; QString _collisionSoundURL;
SharedSoundPointer _collisionSound;
MyCharacterController _characterController; MyCharacterController _characterController;
AvatarWeakPointer _lookAtTargetAvatar; AvatarWeakPointer _lookAtTargetAvatar;

View file

@ -203,7 +203,7 @@ int main(int argc, const char* argv[]) {
Application::shutdownPlugins(); Application::shutdownPlugins();
qCDebug(interfaceapp, "Normal exit."); qCDebug(interfaceapp, "Normal exit.");
#ifndef DEBUG #if !defined(DEBUG) && !defined(Q_OS_LINUX)
// HACK: exit immediately (don't handle shutdown callbacks) for Release build // HACK: exit immediately (don't handle shutdown callbacks) for Release build
_exit(exitCode); _exit(exitCode);
#endif #endif

View file

@ -365,17 +365,9 @@ void AudioInjector::stopAndDeleteLater() {
QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection); QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
} }
AudioInjector* AudioInjector::playSound(const QString& soundUrl, const float volume, const float stretchFactor, const glm::vec3 position) { AudioInjector* AudioInjector::playSound(SharedSoundPointer sound, const float volume, const float stretchFactor, const glm::vec3 position) {
if (soundUrl.isEmpty()) { if (!sound || !sound->isReady()) {
return NULL; return nullptr;
}
auto soundCache = DependencyManager::get<SoundCache>();
if (soundCache.isNull()) {
return NULL;
}
SharedSoundPointer sound = soundCache->getSound(QUrl(soundUrl));
if (sound.isNull() || !sound->isReady()) {
return NULL;
} }
AudioInjectorOptions options; AudioInjectorOptions options;
@ -385,7 +377,7 @@ AudioInjector* AudioInjector::playSound(const QString& soundUrl, const float vol
QByteArray samples = sound->getByteArray(); QByteArray samples = sound->getByteArray();
if (stretchFactor == 1.0f) { if (stretchFactor == 1.0f) {
return playSoundAndDelete(samples, options, NULL); return playSoundAndDelete(samples, options, nullptr);
} }
const int standardRate = AudioConstants::SAMPLE_RATE; const int standardRate = AudioConstants::SAMPLE_RATE;
@ -403,7 +395,7 @@ AudioInjector* AudioInjector::playSound(const QString& soundUrl, const float vol
nInputFrames); nInputFrames);
Q_UNUSED(nOutputFrames); Q_UNUSED(nOutputFrames);
return playSoundAndDelete(resampled, options, NULL); return playSoundAndDelete(resampled, options, nullptr);
} }
AudioInjector* AudioInjector::playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface) { AudioInjector* AudioInjector::playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface) {

View file

@ -60,7 +60,7 @@ public:
static AudioInjector* playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface); 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 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: public slots:
void restart(); void restart();

View file

@ -237,12 +237,6 @@ bool OpenGLDisplayPlugin::activate() {
_vsyncSupported = _container->getPrimaryWidget()->isVsyncSupported(); _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 #if THREADED_PRESENT
// Start the present thread if necessary // Start the present thread if necessary
@ -258,8 +252,18 @@ bool OpenGLDisplayPlugin::activate() {
// Start execution // Start execution
presentThread->start(); 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 // and the old context (if any) has been uncustomized
presentThread->setNewDisplayPlugin(this); presentThread->setNewDisplayPlugin(this);
#else #else

View file

@ -103,6 +103,7 @@ protected:
virtual void updateFrameData(); virtual void updateFrameData();
QThread* _presentThread{ nullptr };
ProgramPtr _program; ProgramPtr _program;
int32_t _mvpUniform { -1 }; int32_t _mvpUniform { -1 };
int32_t _alphaUniform { -1 }; int32_t _alphaUniform { -1 };

View file

@ -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 vec3 Position;
in vec2 TexCoord; in vec2 TexCoord;
@ -78,15 +78,15 @@ void main() {
)VS"; )VS";
static const GLint REPROJECTION_MATRIX_LOCATION = 0; static GLint REPROJECTION_MATRIX_LOCATION = -1;
static const GLint INVERSE_PROJECTION_MATRIX_LOCATION = 4; static GLint INVERSE_PROJECTION_MATRIX_LOCATION = -1;
static const GLint PROJECTION_MATRIX_LOCATION = 12; static GLint PROJECTION_MATRIX_LOCATION = -1;
static const char * REPROJECTION_FS = R"FS(#version 450 core static const char * REPROJECTION_FS = R"FS(#version 410 core
uniform sampler2D sampler; uniform sampler2D sampler;
layout (location = 0) uniform mat3 reprojection = mat3(1); uniform mat3 reprojection = mat3(1);
layout (location = 4) uniform mat4 inverseProjections[2]; uniform mat4 inverseProjections[2];
layout (location = 12) uniform mat4 projections[2]; uniform mat4 projections[2];
in vec2 vTexCoord; in vec2 vTexCoord;
in vec3 vPosition; in vec3 vPosition;
@ -205,6 +205,11 @@ void HmdDisplayPlugin::customizeContext() {
_enablePreview = !isVsyncEnabled(); _enablePreview = !isVsyncEnabled();
_sphereSection = loadSphereSection(_program, CompositorHelper::VIRTUAL_UI_TARGET_FOV.y, CompositorHelper::VIRTUAL_UI_ASPECT_RATIO); _sphereSection = loadSphereSection(_program, CompositorHelper::VIRTUAL_UI_TARGET_FOV.y, CompositorHelper::VIRTUAL_UI_ASPECT_RATIO);
compileProgram(_reprojectionProgram, REPROJECTION_VS, REPROJECTION_FS); 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() { void HmdDisplayPlugin::uncustomizeContext() {

View file

@ -820,14 +820,14 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT
return; return;
} }
QString collisionSoundURL; SharedSoundPointer collisionSound;
float mass = 1.0; // value doesn't get used, but set it so compiler is quiet float mass = 1.0; // value doesn't get used, but set it so compiler is quiet
AACube minAACube; AACube minAACube;
bool success = false; bool success = false;
_tree->withReadLock([&] { _tree->withReadLock([&] {
EntityItemPointer entity = entityTree->findEntityByEntityItemID(id); EntityItemPointer entity = entityTree->findEntityByEntityItemID(id);
if (entity) { if (entity) {
collisionSoundURL = entity->getCollisionSoundURL(); collisionSound = entity->getCollisionSound();
mass = entity->computeMass(); mass = entity->computeMass();
minAACube = entity->getMinimumAACube(success); minAACube = entity->getMinimumAACube(success);
} }
@ -835,9 +835,10 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT
if (!success) { if (!success) {
return; return;
} }
if (collisionSoundURL.isEmpty()) { if (!collisionSound) {
return; return;
} }
const float COLLISION_PENETRATION_TO_VELOCITY = 50; // as a subsitute for RELATIVE entity->getVelocity() 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, // 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. // 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 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); 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) // 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 COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f;
const float stretchFactor = log(1.0f + (minAACube.getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2); 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, void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB,

View file

@ -85,10 +85,14 @@ void makeEntityItemStatusGetters(EntityItemPointer entity, render::Item::Status:
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
const QUuid& myNodeID = nodeList->getSessionUUID(); const QUuid& myNodeID = nodeList->getSessionUUID();
bool weOwnSimulation = entity->getSimulationOwner().matchesValidID(myNodeID); bool weOwnSimulation = entity->getSimulationOwner().matchesValidID(myNodeID);
bool otherOwnSimulation = !weOwnSimulation && !entity->getSimulationOwner().isNull();
if (weOwnSimulation) { if (weOwnSimulation) {
return render::Item::Status::Value(1.0f, render::Item::Status::Value::BLUE, return render::Item::Status::Value(1.0f, render::Item::Status::Value::BLUE,
(unsigned char)RenderItemStatusIcon::SIMULATION_OWNER); (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, return render::Item::Status::Value(0.0f, render::Item::Status::Value::BLUE,
(unsigned char)RenderItemStatusIcon::SIMULATION_OWNER); (unsigned char)RenderItemStatusIcon::SIMULATION_OWNER);

View file

@ -25,6 +25,7 @@ enum class RenderItemStatusIcon {
PACKET_RECEIVED = 2, PACKET_RECEIVED = 2,
SIMULATION_OWNER = 3, SIMULATION_OWNER = 3,
HAS_ACTIONS = 4, HAS_ACTIONS = 4,
OTHER_SIMULATION_OWNER = 5,
NONE = 255 NONE = 255
}; };

View file

@ -174,9 +174,14 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
#endif #endif
if (!_webSurface) { if (!_webSurface) {
#if defined(Q_OS_LINUX)
// these don't seem to work on Linux
return;
#else
if (!buildWebSurface(static_cast<EntityTreeRenderer*>(args->_renderer))) { if (!buildWebSurface(static_cast<EntityTreeRenderer*>(args->_renderer))) {
return; return;
} }
#endif
} }
_lastRenderTime = usecTimestampNow(); _lastRenderTime = usecTimestampNow();

View file

@ -57,8 +57,6 @@ public:
virtual bool isMine() { return _isMine; } virtual bool isMine() { return _isMine; }
virtual void setIsMine(bool value) { _isMine = value; } virtual void setIsMine(bool value) { _isMine = value; }
bool locallyAddedButNotYetReceived = false;
virtual bool shouldSuppressLocationEdits() { return false; } virtual bool shouldSuppressLocationEdits() { return false; }
virtual void prepareForPhysicsSimulation() { } virtual void prepareForPhysicsSimulation() { }

View file

@ -726,8 +726,13 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_DESCRIPTION, QString, setDescription); READ_ENTITY_PROPERTY(PROP_DESCRIPTION, QString, setDescription);
READ_ENTITY_PROPERTY(PROP_ACTION_DATA, QByteArray, setActionData); READ_ENTITY_PROPERTY(PROP_ACTION_DATA, QByteArray, setActionData);
READ_ENTITY_PROPERTY(PROP_PARENT_ID, QUuid, setParentID); { // parentID and parentJointIndex are also protected by simulation ownership
READ_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex); 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); READ_ENTITY_PROPERTY(PROP_QUERY_AA_CUBE, AACube, setQueryAACube);
@ -852,6 +857,23 @@ void EntityItem::setHref(QString value) {
_href = 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) { void EntityItem::simulate(const quint64& now) {
if (_lastSimulated == 0) { if (_lastSimulated == 0) {
_lastSimulated = now; _lastSimulated = now;
@ -1700,16 +1722,31 @@ void EntityItem::setPendingOwnershipPriority(quint8 priority, const quint64& tim
_simulationOwner.setPendingPriority(priority, timestamp); _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(EntitySimulation* simulation, EntityActionPointer action) { bool EntityItem::addAction(EntitySimulation* simulation, EntityActionPointer action) {
bool result; bool result;
withWriteLock([&] { withWriteLock([&] {
checkWaitingToRemove(simulation); checkWaitingToRemove(simulation);
result = addActionInternal(simulation, action); result = addActionInternal(simulation, action);
if (!result) { if (result) {
removeActionInternal(action->getID()); action->setIsMine(true);
_actionDataDirty = true;
} else { } else {
action->locallyAddedButNotYetReceived = true; removeActionInternal(action->getID());
} }
}); });
@ -1783,6 +1820,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* s
EntityActionPointer action = _objectActions[actionID]; EntityActionPointer action = _objectActions[actionID];
action->setOwnerEntity(nullptr); action->setOwnerEntity(nullptr);
action->setIsMine(false);
_objectActions.remove(actionID); _objectActions.remove(actionID);
if (simulation) { if (simulation) {
@ -1863,7 +1901,6 @@ void EntityItem::deserializeActionsInternal() {
if (!action->isMine()) { if (!action->isMine()) {
action->deserialize(serializedAction); action->deserialize(serializedAction);
} }
action->locallyAddedButNotYetReceived = false;
updated << actionID; updated << actionID;
} else { } else {
auto actionFactory = DependencyManager::get<EntityActionFactoryInterface>(); auto actionFactory = DependencyManager::get<EntityActionFactoryInterface>();
@ -1871,7 +1908,6 @@ void EntityItem::deserializeActionsInternal() {
EntityActionPointer action = actionFactory->factoryBA(entity, serializedAction); EntityActionPointer action = actionFactory->factoryBA(entity, serializedAction);
if (action) { if (action) {
entity->addActionInternal(simulation, action); entity->addActionInternal(simulation, action);
action->locallyAddedButNotYetReceived = false;
updated << actionID; updated << actionID;
} else { } else {
static QString repeatedMessage = static QString repeatedMessage =
@ -1889,8 +1925,12 @@ void EntityItem::deserializeActionsInternal() {
QUuid id = i.key(); QUuid id = i.key();
if (!updated.contains(id)) { if (!updated.contains(id)) {
EntityActionPointer action = i.value(); 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; _actionsToRemove << id;
_previouslyDeletedActions.insert(id, now); _previouslyDeletedActions.insert(id, now);
} }

View file

@ -24,6 +24,7 @@
#include <PhysicsCollisionGroups.h> #include <PhysicsCollisionGroups.h>
#include <ShapeInfo.h> #include <ShapeInfo.h>
#include <Transform.h> #include <Transform.h>
#include <Sound.h>
#include <SpatiallyNestable.h> #include <SpatiallyNestable.h>
#include "EntityItemID.h" #include "EntityItemID.h"
@ -250,7 +251,10 @@ public:
void setScriptTimestamp(const quint64 value) { _scriptTimestamp = value; } void setScriptTimestamp(const quint64 value) { _scriptTimestamp = value; }
const QString& getCollisionSoundURL() const { return _collisionSoundURL; } 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 const glm::vec3& getRegistrationPoint() const { return _registrationPoint; } /// registration point as ratio of entity
@ -378,6 +382,7 @@ public:
void grabSimulationOwnership(); void grabSimulationOwnership();
void flagForMotionStateChange() { _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; } void flagForMotionStateChange() { _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; }
QString actionsToDebugString();
bool addAction(EntitySimulation* simulation, EntityActionPointer action); bool addAction(EntitySimulation* simulation, EntityActionPointer action);
bool updateAction(EntitySimulation* simulation, const QUuid& actionID, const QVariantMap& arguments); bool updateAction(EntitySimulation* simulation, const QUuid& actionID, const QVariantMap& arguments);
bool removeAction(EntitySimulation* simulation, const QUuid& actionID); bool removeAction(EntitySimulation* simulation, const QUuid& actionID);
@ -478,6 +483,7 @@ protected:
quint64 _loadedScriptTimestamp{ ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP + 1 }; quint64 _loadedScriptTimestamp{ ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP + 1 };
QString _collisionSoundURL; QString _collisionSoundURL;
SharedSoundPointer _collisionSound;
glm::vec3 _registrationPoint; glm::vec3 _registrationPoint;
float _angularDamping; float _angularDamping;
bool _visible; bool _visible;

View file

@ -1615,7 +1615,7 @@ void EntityItemProperties::setSimulationOwner(const QByteArray& data) {
QList<QString> EntityItemProperties::listChangedProperties() { QList<QString> EntityItemProperties::listChangedProperties() {
QList<QString> out; QList<QString> out;
if (containsPositionChange()) { if (containsPositionChange()) {
out += "posistion"; out += "position";
} }
if (dimensionsChanged()) { if (dimensionsChanged()) {
out += "dimensions"; out += "dimensions";

View file

@ -95,7 +95,6 @@ void EntityTree::postAddEntity(EntityItemPointer entity) {
} }
_isDirty = true; _isDirty = true;
maybeNotifyNewCollisionSoundURL("", entity->getCollisionSoundURL());
emit addingEntity(entity->getEntityItemID()); emit addingEntity(entity->getEntityItemID());
// find and hook up any entities with this entity as a (previously) missing parent // 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.setVelocityChanged(false);
properties.setAngularVelocityChanged(false); properties.setAngularVelocityChanged(false);
properties.setAccelerationChanged(false); properties.setAccelerationChanged(false);
properties.setParentIDChanged(false);
properties.setParentJointIndexChanged(false);
if (wantTerseEditLogging()) { if (wantTerseEditLogging()) {
qCDebug(entities) << (senderNode ? senderNode->getUUID() : "null") << "physical edits suppressed"; qCDebug(entities) << (senderNode ? senderNode->getUUID() : "null") << "physical edits suppressed";
@ -223,7 +224,6 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
QString entityScriptBefore = entity->getScript(); QString entityScriptBefore = entity->getScript();
quint64 entityScriptTimestampBefore = entity->getScriptTimestamp(); quint64 entityScriptTimestampBefore = entity->getScriptTimestamp();
QString collisionSoundURLBefore = entity->getCollisionSoundURL();
uint32_t preFlags = entity->getDirtyFlags(); uint32_t preFlags = entity->getDirtyFlags();
AACube newQueryAACube; AACube newQueryAACube;
@ -295,7 +295,6 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
if (entityScriptBefore != entityScriptAfter || reload) { if (entityScriptBefore != entityScriptAfter || reload) {
emitEntityScriptChanging(entity->getEntityItemID(), reload); // the entity script has changed 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). // 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); emit entityScriptChanging(entityItemID, reload);
} }
void EntityTree::maybeNotifyNewCollisionSoundURL(const QString& previousCollisionSoundURL, const QString& nextCollisionSoundURL) { void EntityTree::notifyNewCollisionSoundURL(const QString& newURL, const EntityItemID& entityID) {
if (!nextCollisionSoundURL.isEmpty() && (nextCollisionSoundURL != previousCollisionSoundURL)) { emit newCollisionSoundURL(QUrl(newURL), entityID);
emit newCollisionSoundURL(QUrl(nextCollisionSoundURL));
}
} }
void EntityTree::setSimulation(EntitySimulation* simulation) { void EntityTree::setSimulation(EntitySimulation* simulation) {
@ -848,6 +845,14 @@ void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList<Q
QString::number((int)center.y) + "," + QString::number((int)center.y) + "," +
QString::number((int)center.z); 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, int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength,

View file

@ -249,6 +249,8 @@ public:
void forgetAvatarID(QUuid avatarID) { _avatarIDs -= avatarID; } void forgetAvatarID(QUuid avatarID) { _avatarIDs -= avatarID; }
void deleteDescendantsOfAvatar(QUuid avatarID); void deleteDescendantsOfAvatar(QUuid avatarID);
void notifyNewCollisionSoundURL(const QString& newCollisionSoundURL, const EntityItemID& entityID);
public slots: public slots:
void callLoader(EntityItemID entityID); void callLoader(EntityItemID entityID);
@ -256,7 +258,7 @@ signals:
void deletingEntity(const EntityItemID& entityID); void deletingEntity(const EntityItemID& entityID);
void addingEntity(const EntityItemID& entityID); void addingEntity(const EntityItemID& entityID);
void entityScriptChanging(const EntityItemID& entityItemID, const bool reload); void entityScriptChanging(const EntityItemID& entityItemID, const bool reload);
void newCollisionSoundURL(const QUrl& url); void newCollisionSoundURL(const QUrl& url, const EntityItemID& entityID);
void clearingEntities(); void clearingEntities();
protected: protected:
@ -301,7 +303,6 @@ protected:
bool _wantEditLogging = false; bool _wantEditLogging = false;
bool _wantTerseEditLogging = false; bool _wantTerseEditLogging = false;
void maybeNotifyNewCollisionSoundURL(const QString& oldCollisionSoundURL, const QString& newCollisionSoundURL);
// some performance tracking properties - only used in server trees // some performance tracking properties - only used in server trees

View file

@ -34,8 +34,6 @@ OctreeElementPointer EntityTreeElement::createNewElement(unsigned char* octalCod
return newChild; return newChild;
} }
void EntityTreeElement::init(unsigned char* octalCode) { void EntityTreeElement::init(unsigned char* octalCode) {
OctreeElement::init(octalCode); OctreeElement::init(octalCode);
_octreeMemoryUsage += sizeof(EntityTreeElement); _octreeMemoryUsage += sizeof(EntityTreeElement);

View file

@ -17,8 +17,15 @@ QOpenGLContext* QOpenGLContextWrapper::currentContext() {
return QOpenGLContext::currentContext(); return QOpenGLContext::currentContext();
} }
QOpenGLContextWrapper::QOpenGLContextWrapper() : 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; return QOpenGLContext::currentContext() == context;
} }
void QOpenGLContextWrapper::moveToThread(QThread* thread) {
_context->moveToThread(thread);
}

View file

@ -15,16 +15,19 @@
class QOpenGLContext; class QOpenGLContext;
class QSurface; class QSurface;
class QSurfaceFormat; class QSurfaceFormat;
class QThread;
class QOpenGLContextWrapper { class QOpenGLContextWrapper {
public: public:
QOpenGLContextWrapper(); QOpenGLContextWrapper();
QOpenGLContextWrapper(QOpenGLContext* context);
void setFormat(const QSurfaceFormat& format); void setFormat(const QSurfaceFormat& format);
bool create(); bool create();
void swapBuffers(QSurface* surface); void swapBuffers(QSurface* surface);
bool makeCurrent(QSurface* surface); bool makeCurrent(QSurface* surface);
void doneCurrent(); void doneCurrent();
void setShareContext(QOpenGLContext* otherContext); void setShareContext(QOpenGLContext* otherContext);
void moveToThread(QThread* thread);
static QOpenGLContext* currentContext(); static QOpenGLContext* currentContext();

View file

@ -105,19 +105,19 @@ const QImage& image, bool isLinear, bool doCompress) {
gpu::Semantic gpuSemantic; gpu::Semantic gpuSemantic;
gpu::Semantic mipSemantic; gpu::Semantic mipSemantic;
if (isLinear) { if (isLinear) {
mipSemantic = gpu::SBGRA;
if (doCompress) {
gpuSemantic = gpu::COMPRESSED_SRGBA;
} else {
gpuSemantic = gpu::SRGBA;
}
} else {
mipSemantic = gpu::BGRA; mipSemantic = gpu::BGRA;
if (doCompress) { if (doCompress) {
gpuSemantic = gpu::COMPRESSED_RGBA; gpuSemantic = gpu::COMPRESSED_RGBA;
} else { } else {
gpuSemantic = gpu::RGBA; 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); formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, gpuSemantic);
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, mipSemantic); formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, mipSemantic);
@ -125,19 +125,19 @@ const QImage& image, bool isLinear, bool doCompress) {
gpu::Semantic gpuSemantic; gpu::Semantic gpuSemantic;
gpu::Semantic mipSemantic; gpu::Semantic mipSemantic;
if (isLinear) { if (isLinear) {
mipSemantic = gpu::SRGB;
if (doCompress) {
gpuSemantic = gpu::COMPRESSED_SRGB;
} else {
gpuSemantic = gpu::SRGB;
}
} else {
mipSemantic = gpu::RGB; mipSemantic = gpu::RGB;
if (doCompress) { if (doCompress) {
gpuSemantic = gpu::COMPRESSED_RGB; gpuSemantic = gpu::COMPRESSED_RGB;
} else { } else {
gpuSemantic = gpu::RGB; 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); formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpuSemantic);
formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, mipSemantic); formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, mipSemantic);
@ -171,14 +171,6 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag
if (generateMips) { if (generateMips) {
theTexture->autoGenerateMips(-1); 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) { 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) { 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) { 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) { gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
return process2DTextureColorFromImage(srcImage, true, true, true); return process2DTextureColorFromImage(srcImage, false, true, true);
} }

View file

@ -40,15 +40,14 @@ void ResourceCacheSharedItems::appendPendingRequest(QWeakPointer<Resource> resou
QList<QSharedPointer<Resource>> ResourceCacheSharedItems::getPendingRequests() { QList<QSharedPointer<Resource>> ResourceCacheSharedItems::getPendingRequests() {
QList<QSharedPointer<Resource>> result; QList<QSharedPointer<Resource>> result;
Lock lock(_mutex);
{ foreach(QSharedPointer<Resource> resource, _pendingRequests) {
Lock lock(_mutex); if (resource) {
foreach(QSharedPointer<Resource> resource, _pendingRequests) { result.append(resource);
if (resource) {
result.append(resource);
}
} }
} }
return result; return result;
} }
@ -59,20 +58,20 @@ uint32_t ResourceCacheSharedItems::getPendingRequestsCount() const {
QList<QSharedPointer<Resource>> ResourceCacheSharedItems::getLoadingRequests() { QList<QSharedPointer<Resource>> ResourceCacheSharedItems::getLoadingRequests() {
QList<QSharedPointer<Resource>> result; QList<QSharedPointer<Resource>> result;
Lock lock(_mutex);
{ foreach(QSharedPointer<Resource> resource, _loadingRequests) {
Lock lock(_mutex); if (resource) {
foreach(QSharedPointer<Resource> resource, _loadingRequests) { result.append(resource);
if (resource) {
result.append(resource);
}
} }
} }
return result; return result;
} }
void ResourceCacheSharedItems::removeRequest(QWeakPointer<Resource> resource) { void ResourceCacheSharedItems::removeRequest(QWeakPointer<Resource> resource) {
Lock lock(_mutex); Lock lock(_mutex);
// resource can only be removed if it still has a ref-count, as // resource can only be removed if it still has a ref-count, as
// QWeakPointer has no operator== implementation for two weak ptrs, so // QWeakPointer has no operator== implementation for two weak ptrs, so
// manually loop in case resource has been freed. // manually loop in case resource has been freed.
@ -88,11 +87,11 @@ void ResourceCacheSharedItems::removeRequest(QWeakPointer<Resource> resource) {
} }
QSharedPointer<Resource> ResourceCacheSharedItems::getHighestPendingRequest() { QSharedPointer<Resource> ResourceCacheSharedItems::getHighestPendingRequest() {
Lock lock(_mutex);
// look for the highest priority pending request // look for the highest priority pending request
int highestIndex = -1; int highestIndex = -1;
float highestPriority = -FLT_MAX; float highestPriority = -FLT_MAX;
QSharedPointer<Resource> highestResource; QSharedPointer<Resource> highestResource;
Lock lock(_mutex);
for (int i = 0; i < _pendingRequests.size();) { for (int i = 0; i < _pendingRequests.size();) {
// Clear any freed resources // Clear any freed resources
@ -139,17 +138,17 @@ void ScriptableResource::setInScript(bool isInScript) {
} }
void ScriptableResource::loadingChanged() { void ScriptableResource::loadingChanged() {
emit stateChanged(LOADING); setState(LOADING);
} }
void ScriptableResource::loadedChanged() { void ScriptableResource::loadedChanged() {
emit stateChanged(LOADED); setState(LOADED);
} }
void ScriptableResource::finished(bool success) { void ScriptableResource::finished(bool success) {
disconnectHelper(); disconnectHelper();
emit stateChanged(success ? FINISHED : FAILED); setState(success ? FINISHED : FAILED);
} }
void ScriptableResource::disconnectHelper() { void ScriptableResource::disconnectHelper() {
@ -262,12 +261,14 @@ void ResourceCache::refreshAll() {
clearUnusedResource(); clearUnusedResource();
resetResourceCounters(); resetResourceCounters();
_resourcesLock.lockForRead(); QHash<QUrl, QWeakPointer<Resource>> resources;
auto resourcesCopy = _resources; {
_resourcesLock.unlock(); QReadLocker locker(&_resourcesLock);
resources = _resources;
}
// Refresh all remaining resources in use // Refresh all remaining resources in use
foreach (QSharedPointer<Resource> resource, resourcesCopy) { foreach (QSharedPointer<Resource> resource, resources) {
if (resource) { if (resource) {
resource->refresh(); resource->refresh();
} }
@ -317,17 +318,17 @@ void ResourceCache::setRequestLimit(int limit) {
void ResourceCache::getResourceAsynchronously(const QUrl& url) { void ResourceCache::getResourceAsynchronously(const QUrl& url) {
qCDebug(networking) << "ResourceCache::getResourceAsynchronously" << url.toString(); qCDebug(networking) << "ResourceCache::getResourceAsynchronously" << url.toString();
_resourcesToBeGottenLock.lockForWrite(); QWriteLocker locker(&_resourcesToBeGottenLock);
_resourcesToBeGotten.enqueue(QUrl(url)); _resourcesToBeGotten.enqueue(QUrl(url));
_resourcesToBeGottenLock.unlock();
} }
void ResourceCache::checkAsynchronousGets() { void ResourceCache::checkAsynchronousGets() {
assert(QThread::currentThread() == thread()); assert(QThread::currentThread() == thread());
QWriteLocker locker(&_resourcesToBeGottenLock);
if (!_resourcesToBeGotten.isEmpty()) { if (!_resourcesToBeGotten.isEmpty()) {
_resourcesToBeGottenLock.lockForWrite();
QUrl url = _resourcesToBeGotten.dequeue(); QUrl url = _resourcesToBeGotten.dequeue();
_resourcesToBeGottenLock.unlock();
locker.unlock();
getResource(url); getResource(url);
} }
} }
@ -399,8 +400,10 @@ void ResourceCache::removeUnusedResource(const QSharedPointer<Resource>& resourc
if (_unusedResources.contains(resource->getLRUKey())) { if (_unusedResources.contains(resource->getLRUKey())) {
_unusedResources.remove(resource->getLRUKey()); _unusedResources.remove(resource->getLRUKey());
_unusedResourcesSize -= resource->getBytes(); _unusedResourcesSize -= resource->getBytes();
locker.unlock();
resetResourceCounters();
} }
resetResourceCounters();
} }
void ResourceCache::reserveUnusedResource(qint64 resourceSize) { void ResourceCache::reserveUnusedResource(qint64 resourceSize) {
@ -413,7 +416,9 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) {
it.value()->setCache(nullptr); it.value()->setCache(nullptr);
auto size = it.value()->getBytes(); auto size = it.value()->getBytes();
locker.unlock();
removeResource(it.value()->getURL(), size); removeResource(it.value()->getURL(), size);
locker.relock();
_unusedResourcesSize -= size; _unusedResourcesSize -= size;
_unusedResources.erase(it); _unusedResources.erase(it);
@ -433,8 +438,16 @@ void ResourceCache::clearUnusedResource() {
} }
void ResourceCache::resetResourceCounters() { void ResourceCache::resetResourceCounters() {
_numTotalResources = _resources.size(); {
_numUnusedResources = _unusedResources.size(); QReadLocker locker(&_resourcesLock);
_numTotalResources = _resources.size();
}
{
QReadLocker locker(&_unusedResourcesLock);
_numUnusedResources = _unusedResources.size();
}
emit dirty(); emit dirty();
} }

View file

@ -64,6 +64,7 @@ class ResourceCacheSharedItems : public Dependency {
using Mutex = std::mutex; using Mutex = std::mutex;
using Lock = std::unique_lock<Mutex>; using Lock = std::unique_lock<Mutex>;
public: public:
void appendPendingRequest(QWeakPointer<Resource> newRequest); void appendPendingRequest(QWeakPointer<Resource> newRequest);
void appendActiveRequest(QWeakPointer<Resource> newRequest); void appendActiveRequest(QWeakPointer<Resource> newRequest);
@ -113,6 +114,9 @@ signals:
void progressChanged(uint64_t bytesReceived, uint64_t bytesTotal); void progressChanged(uint64_t bytesReceived, uint64_t bytesTotal);
void stateChanged(int state); void stateChanged(int state);
protected:
void setState(State state) { _state = state; emit stateChanged(_state); }
private slots: private slots:
void loadingChanged(); void loadingChanged();
void loadedChanged(); void loadedChanged();
@ -224,26 +228,30 @@ private:
void resetResourceCounters(); void resetResourceCounters();
void removeResource(const QUrl& url, qint64 size = 0); void removeResource(const QUrl& url, qint64 size = 0);
QReadWriteLock _resourcesLock { QReadWriteLock::Recursive }; void getResourceAsynchronously(const QUrl& url);
QHash<QUrl, QWeakPointer<Resource>> _resources;
int _lastLRUKey = 0;
static int _requestLimit; static int _requestLimit;
static int _requestsActive; static int _requestsActive;
void getResourceAsynchronously(const QUrl& url); // Resources
QReadWriteLock _resourcesToBeGottenLock { QReadWriteLock::Recursive }; QHash<QUrl, QWeakPointer<Resource>> _resources;
QQueue<QUrl> _resourcesToBeGotten; QReadWriteLock _resourcesLock { QReadWriteLock::Recursive };
int _lastLRUKey = 0;
std::atomic<size_t> _numTotalResources { 0 };
std::atomic<size_t> _numUnusedResources { 0 };
std::atomic<size_t> _numTotalResources { 0 };
std::atomic<qint64> _totalResourcesSize { 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 }; std::atomic<qint64> _unusedResourcesSize { 0 };
qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE; // Pending resources
QReadWriteLock _unusedResourcesLock { QReadWriteLock::Recursive }; QQueue<QUrl> _resourcesToBeGotten;
QMap<int, QSharedPointer<Resource>> _unusedResources; QReadWriteLock _resourcesToBeGottenLock { QReadWriteLock::Recursive };
}; };
/// Base class for resources. /// Base class for resources.

View file

@ -9,6 +9,9 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include <chrono>
#include <thread>
#include <cstdio> #include <cstdio>
#include <fstream> #include <fstream>
#include <time.h> #include <time.h>
@ -201,7 +204,7 @@ bool OctreePersistThread::process() {
if (isStillRunning()) { if (isStillRunning()) {
quint64 MSECS_TO_USECS = 1000; quint64 MSECS_TO_USECS = 1000;
quint64 USECS_TO_SLEEP = 10 * MSECS_TO_USECS; // every 10ms 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... // do our updates then check to save...
_tree->update(); _tree->update();

View file

@ -430,6 +430,14 @@ glm::vec3 CharacterController::getLinearVelocity() const {
return velocity; return velocity;
} }
glm::vec3 CharacterController::getVelocityChange() const {
glm::vec3 velocity(0.0f);
if (_rigidBody) {
velocity = bulletToGLM(_rigidBody->getLinearVelocity());
}
return velocity;
}
void CharacterController::preSimulation() { void CharacterController::preSimulation() {
if (_enabled && _dynamicsWorld) { if (_enabled && _dynamicsWorld) {
quint64 now = usecTimestampNow(); quint64 now = usecTimestampNow();
@ -437,6 +445,7 @@ void CharacterController::preSimulation() {
// slam body to where it is supposed to be // slam body to where it is supposed to be
_rigidBody->setWorldTransform(_characterBodyTransform); _rigidBody->setWorldTransform(_characterBodyTransform);
btVector3 velocity = _rigidBody->getLinearVelocity(); btVector3 velocity = _rigidBody->getLinearVelocity();
_preSimulationVelocity = velocity;
btVector3 actualVertVelocity = velocity.dot(_currentUp) * _currentUp; btVector3 actualVertVelocity = velocity.dot(_currentUp) * _currentUp;
btVector3 actualHorizVelocity = velocity - actualVertVelocity; btVector3 actualHorizVelocity = velocity - actualVertVelocity;
@ -531,6 +540,9 @@ void CharacterController::preSimulation() {
void CharacterController::postSimulation() { void CharacterController::postSimulation() {
// postSimulation() exists for symmetry and just in case we need to do something here later // postSimulation() exists for symmetry and just in case we need to do something here later
btVector3 velocity = _rigidBody->getLinearVelocity();
_velocityChange = velocity - _preSimulationVelocity;
} }

View file

@ -77,6 +77,7 @@ public:
glm::vec3 getFollowVelocity() const; glm::vec3 getFollowVelocity() const;
glm::vec3 getLinearVelocity() const; glm::vec3 getLinearVelocity() const;
glm::vec3 getVelocityChange() const;
float getCapsuleRadius() const { return _radius; } float getCapsuleRadius() const { return _radius; }
float getCapsuleHalfHeight() const { return _halfHeight; } float getCapsuleHalfHeight() const { return _halfHeight; }
@ -112,6 +113,8 @@ protected:
btVector3 _currentUp; btVector3 _currentUp;
btVector3 _targetVelocity; btVector3 _targetVelocity;
btVector3 _parentVelocity; btVector3 _parentVelocity;
btVector3 _preSimulationVelocity;
btVector3 _velocityChange;
btTransform _followDesiredBodyTransform; btTransform _followDesiredBodyTransform;
btScalar _followTimeRemaining; btScalar _followTimeRemaining;
btTransform _characterBodyTransform; btTransform _characterBodyTransform;

View file

@ -21,9 +21,11 @@ const uint16_t ObjectActionSpring::springVersion = 1;
ObjectActionSpring::ObjectActionSpring(const QUuid& id, EntityItemPointer ownerEntity) : ObjectActionSpring::ObjectActionSpring(const QUuid& id, EntityItemPointer ownerEntity) :
ObjectAction(ACTION_TYPE_SPRING, id, ownerEntity), ObjectAction(ACTION_TYPE_SPRING, id, ownerEntity),
_positionalTarget(glm::vec3(0.0f)), _positionalTarget(glm::vec3(0.0f)),
_desiredPositionalTarget(glm::vec3(0.0f)),
_linearTimeScale(FLT_MAX), _linearTimeScale(FLT_MAX),
_positionalTargetSet(true), _positionalTargetSet(true),
_rotationalTarget(glm::quat()), _rotationalTarget(glm::quat()),
_desiredRotationalTarget(glm::quat()),
_angularTimeScale(FLT_MAX), _angularTimeScale(FLT_MAX),
_rotationalTargetSet(true) { _rotationalTargetSet(true) {
#if WANT_DEBUG #if WANT_DEBUG
@ -37,9 +39,81 @@ ObjectActionSpring::~ObjectActionSpring() {
#endif #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) { void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) {
// don't risk hanging the thread running the physics simulation if (!prepareForSpringUpdate(deltaTimeStep)) {
auto lockResult = withTryReadLock([&]{ return;
}
withReadLock([&]{
auto ownerEntity = _ownerEntity.lock(); auto ownerEntity = _ownerEntity.lock();
if (!ownerEntity) { if (!ownerEntity) {
return; return;
@ -65,6 +139,7 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) {
float speed = glm::min(offsetLength / _linearTimeScale, SPRING_MAX_SPEED); float speed = glm::min(offsetLength / _linearTimeScale, SPRING_MAX_SPEED);
targetVelocity = (-speed / offsetLength) * offset; targetVelocity = (-speed / offsetLength) * offset;
if (speed > rigidBody->getLinearSleepingThreshold()) { if (speed > rigidBody->getLinearSleepingThreshold()) {
forceBodyNonStatic();
rigidBody->activate(); rigidBody->activate();
} }
} }
@ -101,9 +176,6 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) {
rigidBody->setAngularVelocity(targetVelocity); rigidBody->setAngularVelocity(targetVelocity);
} }
}); });
if (!lockResult) {
qDebug() << "ObjectActionSpring::updateActionWorker lock failed";
}
} }
const float MIN_TIMESCALE = 0.1f; const float MIN_TIMESCALE = 0.1f;
@ -122,7 +194,7 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) {
bool ok = true; bool ok = true;
positionalTarget = EntityActionInterface::extractVec3Argument("spring action", arguments, "targetPosition", ok, false); positionalTarget = EntityActionInterface::extractVec3Argument("spring action", arguments, "targetPosition", ok, false);
if (!ok) { if (!ok) {
positionalTarget = _positionalTarget; positionalTarget = _desiredPositionalTarget;
} }
ok = true; ok = true;
linearTimeScale = EntityActionInterface::extractFloatArgument("spring action", arguments, "linearTimeScale", ok, false); linearTimeScale = EntityActionInterface::extractFloatArgument("spring action", arguments, "linearTimeScale", ok, false);
@ -133,7 +205,7 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) {
ok = true; ok = true;
rotationalTarget = EntityActionInterface::extractQuatArgument("spring action", arguments, "targetRotation", ok, false); rotationalTarget = EntityActionInterface::extractQuatArgument("spring action", arguments, "targetRotation", ok, false);
if (!ok) { if (!ok) {
rotationalTarget = _rotationalTarget; rotationalTarget = _desiredRotationalTarget;
} }
ok = true; ok = true;
@ -144,9 +216,9 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) {
} }
if (somethingChanged || if (somethingChanged ||
positionalTarget != _positionalTarget || positionalTarget != _desiredPositionalTarget ||
linearTimeScale != _linearTimeScale || linearTimeScale != _linearTimeScale ||
rotationalTarget != _rotationalTarget || rotationalTarget != _desiredRotationalTarget ||
angularTimeScale != _angularTimeScale) { angularTimeScale != _angularTimeScale) {
// something changed // something changed
needUpdate = true; needUpdate = true;
@ -155,9 +227,9 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) {
if (needUpdate) { if (needUpdate) {
withWriteLock([&] { withWriteLock([&] {
_positionalTarget = positionalTarget; _desiredPositionalTarget = positionalTarget;
_linearTimeScale = glm::max(MIN_TIMESCALE, glm::abs(linearTimeScale)); _linearTimeScale = glm::max(MIN_TIMESCALE, glm::abs(linearTimeScale));
_rotationalTarget = rotationalTarget; _desiredRotationalTarget = rotationalTarget;
_angularTimeScale = glm::max(MIN_TIMESCALE, glm::abs(angularTimeScale)); _angularTimeScale = glm::max(MIN_TIMESCALE, glm::abs(angularTimeScale));
_active = true; _active = true;
@ -177,9 +249,9 @@ QVariantMap ObjectActionSpring::getArguments() {
QVariantMap arguments = ObjectAction::getArguments(); QVariantMap arguments = ObjectAction::getArguments();
withReadLock([&] { withReadLock([&] {
arguments["linearTimeScale"] = _linearTimeScale; arguments["linearTimeScale"] = _linearTimeScale;
arguments["targetPosition"] = glmToQMap(_positionalTarget); arguments["targetPosition"] = glmToQMap(_desiredPositionalTarget);
arguments["targetRotation"] = glmToQMap(_rotationalTarget); arguments["targetRotation"] = glmToQMap(_desiredRotationalTarget);
arguments["angularTimeScale"] = _angularTimeScale; arguments["angularTimeScale"] = _angularTimeScale;
}); });
return arguments; return arguments;
@ -194,10 +266,10 @@ QByteArray ObjectActionSpring::serialize() const {
dataStream << ObjectActionSpring::springVersion; dataStream << ObjectActionSpring::springVersion;
withReadLock([&] { withReadLock([&] {
dataStream << _positionalTarget; dataStream << _desiredPositionalTarget;
dataStream << _linearTimeScale; dataStream << _linearTimeScale;
dataStream << _positionalTargetSet; dataStream << _positionalTargetSet;
dataStream << _rotationalTarget; dataStream << _desiredRotationalTarget;
dataStream << _angularTimeScale; dataStream << _angularTimeScale;
dataStream << _rotationalTargetSet; dataStream << _rotationalTargetSet;
dataStream << localTimeToServerTime(_expires); dataStream << localTimeToServerTime(_expires);
@ -226,11 +298,11 @@ void ObjectActionSpring::deserialize(QByteArray serializedArguments) {
} }
withWriteLock([&] { withWriteLock([&] {
dataStream >> _positionalTarget; dataStream >> _desiredPositionalTarget;
dataStream >> _linearTimeScale; dataStream >> _linearTimeScale;
dataStream >> _positionalTargetSet; dataStream >> _positionalTargetSet;
dataStream >> _rotationalTarget; dataStream >> _desiredRotationalTarget;
dataStream >> _angularTimeScale; dataStream >> _angularTimeScale;
dataStream >> _rotationalTargetSet; dataStream >> _rotationalTargetSet;

View file

@ -27,16 +27,26 @@ public:
virtual QByteArray serialize() const override; virtual QByteArray serialize() const override;
virtual void deserialize(QByteArray serializedArguments) 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: protected:
static const uint16_t springVersion; static const uint16_t springVersion;
glm::vec3 _positionalTarget; glm::vec3 _positionalTarget;
glm::vec3 _desiredPositionalTarget;
float _linearTimeScale; float _linearTimeScale;
bool _positionalTargetSet; bool _positionalTargetSet;
glm::quat _rotationalTarget; glm::quat _rotationalTarget;
glm::quat _desiredRotationalTarget;
float _angularTimeScale; float _angularTimeScale;
bool _rotationalTargetSet; bool _rotationalTargetSet;
glm::vec3 _linearVelocityTarget;
glm::vec3 _angularVelocityTarget;
virtual bool prepareForSpringUpdate(btScalar deltaTimeStep);
}; };
#endif // hifi_ObjectActionSpring_h #endif // hifi_ObjectActionSpring_h

View file

@ -32,7 +32,11 @@ const LoaderList& getLoadedPlugins() {
static std::once_flag once; static std::once_flag once;
static LoaderList loadedPlugins; static LoaderList loadedPlugins;
std::call_once(once, [&] { std::call_once(once, [&] {
#ifdef Q_OS_MAC
QString pluginPath = QCoreApplication::applicationDirPath() + "/../PlugIns/";
#else
QString pluginPath = QCoreApplication::applicationDirPath() + "/plugins/"; QString pluginPath = QCoreApplication::applicationDirPath() + "/plugins/";
#endif
QDir pluginDir(pluginPath); QDir pluginDir(pluginPath);
pluginDir.setFilter(QDir::Files); pluginDir.setFilter(QDir::Files);
if (pluginDir.exists()) { if (pluginDir.exists()) {

View file

@ -9,6 +9,9 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include <chrono>
#include <thread>
#include <QtCore/QCoreApplication> #include <QtCore/QCoreApplication>
#include <QtCore/QEventLoop> #include <QtCore/QEventLoop>
#include <QtCore/QFileInfo> #include <QtCore/QFileInfo>
@ -706,9 +709,15 @@ void ScriptEngine::run() {
QScriptValue result = evaluate(_scriptContents, _fileNameString); QScriptValue result = evaluate(_scriptContents, _fileNameString);
QElapsedTimer startTime; #ifdef _WIN32
startTime.start(); // 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; int thisFrame = 0;
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
@ -716,12 +725,29 @@ void ScriptEngine::run() {
qint64 lastUpdate = usecTimestampNow(); qint64 lastUpdate = usecTimestampNow();
// TODO: Integrate this with signals/slots instead of reimplementing throttling for ScriptEngine
while (!_isFinished) { while (!_isFinished) {
int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec // Throttle to SCRIPT_FPS
if (usecToSleep > 0) { const std::chrono::microseconds FRAME_DURATION(USECS_PER_SECOND / SCRIPT_FPS + 1);
usleep(usecToSleep); 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) { if (_isFinished) {
break; break;
} }

View file

@ -39,9 +39,9 @@
#include "ScriptUUID.h" #include "ScriptUUID.h"
#include "Vec3.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 { class CallbackData {
public: public:

View file

@ -12,13 +12,17 @@ if (APPLE)
set(TARGET_NAME oculusLegacy) set(TARGET_NAME oculusLegacy)
setup_hifi_plugin() 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) include_hifi_library_headers(octree)
add_dependency_external_projects(LibOVR) add_dependency_external_projects(LibOVR)
find_package(LibOVR REQUIRED) find_package(LibOVR REQUIRED)
target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS}) 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() endif()

View file

@ -9,6 +9,7 @@
#include <memory> #include <memory>
#include <QtCore/QThread.h>
#include <QtWidgets/QMainWindow> #include <QtWidgets/QMainWindow>
#include <QtOpenGL/QGLWidget> #include <QtOpenGL/QGLWidget>
#include <GLMHelpers.h> #include <GLMHelpers.h>
@ -16,7 +17,12 @@
#include <QtGui/QResizeEvent> #include <QtGui/QResizeEvent>
#include <QtGui/QGuiApplication> #include <QtGui/QGuiApplication>
#include <QtGui/QScreen> #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 <PerfStat.h>
#include <gl/OglplusHelpers.h> #include <gl/OglplusHelpers.h>
#include <ViewFrustum.h> #include <ViewFrustum.h>
@ -39,7 +45,7 @@ void OculusLegacyDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
_currentRenderFrameInfo = FrameInfo(); _currentRenderFrameInfo = FrameInfo();
_currentRenderFrameInfo.predictedDisplayTime = _currentRenderFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds(); _currentRenderFrameInfo.predictedDisplayTime = _currentRenderFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds();
_trackingState = ovrHmd_GetTrackingState(_hmd, _currentRenderFrameInfo.predictedDisplayTime); _trackingState = ovrHmd_GetTrackingState(_hmd, _currentRenderFrameInfo.predictedDisplayTime);
_currentRenderFrameInfo.renderPose = toGlm(_trackingState.HeadPose.ThePose); _currentRenderFrameInfo.rawRenderPose = _currentRenderFrameInfo.renderPose = toGlm(_trackingState.HeadPose.ThePose);
Lock lock(_mutex); Lock lock(_mutex);
_frameInfos[frameIndex] = _currentRenderFrameInfo; _frameInfos[frameIndex] = _currentRenderFrameInfo;
} }
@ -72,14 +78,34 @@ bool OculusLegacyDisplayPlugin::isSupported() const {
} }
bool OculusLegacyDisplayPlugin::internalActivate() { bool OculusLegacyDisplayPlugin::internalActivate() {
Parent::internalActivate(); if (!Parent::internalActivate()) {
return false;
}
if (!(ovr_Initialize(nullptr))) { if (!(ovr_Initialize(nullptr))) {
Q_ASSERT(false); Q_ASSERT(false);
qFatal("Failed to Initialize SDK"); qFatal("Failed to Initialize SDK");
return false; 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; _hswDismissed = false;
_hmd = ovrHmd_Create(0); _hmd = ovrHmd_Create(0);
if (!_hmd) { if (!_hmd) {
@ -96,7 +122,8 @@ bool OculusLegacyDisplayPlugin::internalActivate() {
ovrMatrix4f ovrPerspectiveProjection = ovrMatrix4f ovrPerspectiveProjection =
ovrMatrix4f_Projection(erd.Fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded); ovrMatrix4f_Projection(erd.Fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded);
_eyeProjections[eye] = toGlm(ovrPerspectiveProjection); _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)); eyeSizes[eye] = toGlm(ovrHmd_GetFovTextureSize(_hmd, eye, erd.Fov, 1.0f));
}); });
@ -121,6 +148,11 @@ void OculusLegacyDisplayPlugin::internalDeactivate() {
ovrHmd_Destroy(_hmd); ovrHmd_Destroy(_hmd);
_hmd = nullptr; _hmd = nullptr;
ovr_Shutdown(); ovr_Shutdown();
_hmdWindow->showNormal();
_hmdWindow->destroy();
_hmdWindow->deleteLater();
_hmdWindow = nullptr;
_container->makeRenderingContextCurrent();
} }
// DLL based display plugins MUST initialize GLEW inside the DLL code. // DLL based display plugins MUST initialize GLEW inside the DLL code.
@ -131,20 +163,21 @@ void OculusLegacyDisplayPlugin::customizeContext() {
glewInit(); glewInit();
glGetError(); glGetError();
}); });
_hmdWindow->requestActivate();
QThread::msleep(1000);
Parent::customizeContext(); Parent::customizeContext();
#if 0
ovrGLConfig config; memset(&config, 0, sizeof(ovrRenderAPIConfig)); ovrGLConfig config; memset(&config, 0, sizeof(ovrRenderAPIConfig));
auto& header = config.Config.Header; auto& header = config.Config.Header;
header.API = ovrRenderAPI_OpenGL; header.API = ovrRenderAPI_OpenGL;
header.BackBufferSize = _hmd->Resolution; header.BackBufferSize = _hmd->Resolution;
header.Multisample = 1; header.Multisample = 1;
int distortionCaps = ovrDistortionCap_TimeWarp; int distortionCaps = ovrDistortionCap_TimeWarp | ovrDistortionCap_Vignette;
memset(_eyeTextures, 0, sizeof(ovrTexture) * 2); memset(_eyeTextures, 0, sizeof(ovrTexture) * 2);
ovr_for_each_eye([&](ovrEyeType eye) { ovr_for_each_eye([&](ovrEyeType eye) {
auto& header = _eyeTextures[eye].Header; auto& header = _eyeTextures[eye].Header;
header.API = ovrRenderAPI_OpenGL; 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 = header.TextureSize;
header.RenderViewport.Size.w /= 2; header.RenderViewport.Size.w /= 2;
if (eye == ovrEye_Right) { if (eye == ovrEye_Right) {
@ -152,29 +185,57 @@ void OculusLegacyDisplayPlugin::customizeContext() {
} }
}); });
if (_hmdWindow->makeCurrent()) {
#ifndef NDEBUG #ifndef NDEBUG
ovrBool result = ovrBool result =
#endif
ovrHmd_ConfigureRendering(_hmd, &config.Config, distortionCaps, _eyeFovs, _eyeRenderDescs);
assert(result);
#endif #endif
ovrHmd_ConfigureRendering(_hmd, &config.Config, distortionCaps, _eyeFovs, _eyeRenderDescs);
assert(result);
_hmdWindow->doneCurrent();
}
} }
#if 0
void OculusLegacyDisplayPlugin::uncustomizeContext() { void OculusLegacyDisplayPlugin::uncustomizeContext() {
HmdDisplayPlugin::uncustomizeContext(); _hmdWindow->doneCurrent();
QOpenGLContextWrapper(_hmdWindow->context()).moveToThread(qApp->thread());
Parent::uncustomizeContext();
} }
void OculusLegacyDisplayPlugin::internalPresent() { void OculusLegacyDisplayPlugin::hmdPresent() {
ovrHmd_BeginFrame(_hmd, 0); if (!_hswDismissed) {
ovr_for_each_eye([&](ovrEyeType eye) { ovrHSWDisplayState hswState;
reinterpret_cast<ovrGLTexture&>(_eyeTextures[eye]).OGL.TexId = _currentSceneTexture; ovrHmd_GetHSWDisplayState(_hmd, &hswState);
}); if (hswState.Displayed) {
ovrHmd_EndFrame(_hmd, _eyePoses, _eyeTextures); 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 { int OculusLegacyDisplayPlugin::getHmdScreen() const {
return _hmdScreen; return _hmdScreen;
@ -184,4 +245,3 @@ float OculusLegacyDisplayPlugin::getTargetFrameRate() const {
return TARGET_RATE_OculusLegacy; return TARGET_RATE_OculusLegacy;
} }

View file

@ -14,42 +14,43 @@
#include <OVR_CAPI.h> #include <OVR_CAPI.h>
const float TARGET_RATE_OculusLegacy = 75.0f; const float TARGET_RATE_OculusLegacy = 75.0f;
class GLWindow;
class OculusLegacyDisplayPlugin : public HmdDisplayPlugin { class OculusLegacyDisplayPlugin : public HmdDisplayPlugin {
using Parent = HmdDisplayPlugin; using Parent = HmdDisplayPlugin;
public: public:
OculusLegacyDisplayPlugin(); OculusLegacyDisplayPlugin();
virtual bool isSupported() const override; bool isSupported() const override;
virtual const QString& getName() const override { return NAME; } const QString& getName() const override { return NAME; }
virtual int getHmdScreen() const override; int getHmdScreen() const override;
// Stereo specific methods // Stereo specific methods
virtual void resetSensors() override; void resetSensors() override;
virtual void beginFrameRender(uint32_t frameIndex) override; void beginFrameRender(uint32_t frameIndex) override;
virtual float getTargetFrameRate() const override; float getTargetFrameRate() const override;
protected: protected:
virtual bool internalActivate() override; bool internalActivate() override;
virtual void internalDeactivate() override; void internalDeactivate() override;
virtual void customizeContext() override; void customizeContext() override;
void hmdPresent() override {} void uncustomizeContext() override;
void hmdPresent() override;
bool isHmdMounted() const override { return true; } bool isHmdMounted() const override { return true; }
#if 0
virtual void uncustomizeContext() override;
virtual void internalPresent() override;
#endif
private: private:
static const QString NAME; static const QString NAME;
GLWindow* _hmdWindow{ nullptr };
ovrHmd _hmd; ovrHmd _hmd;
mutable ovrTrackingState _trackingState; mutable ovrTrackingState _trackingState;
ovrEyeRenderDesc _eyeRenderDescs[2]; ovrEyeRenderDesc _eyeRenderDescs[2];
ovrVector3f _ovrEyeOffsets[2];
ovrFovPort _eyeFovs[2]; ovrFovPort _eyeFovs[2];
//ovrTexture _eyeTextures[2]; // FIXME - not currently in use ovrTexture _eyeTextures[2]; // FIXME - not currently in use
mutable int _hmdScreen { -1 }; mutable int _hmdScreen { -1 };
bool _hswDismissed { false }; bool _hswDismissed { false };
}; };

View file

@ -26,8 +26,8 @@ function getFrame(callback) {
} }
function makeFrame(state) { function makeFrame(state) {
if (state == Resource.State.FAILED) { throw "Failed to load frame"; } if (state === Resource.State.FAILED) { throw "Failed to load frame"; }
if (state != Resource.State.FINISHED) { return; } if (state !== Resource.State.FINISHED) { return; }
var pictureFrameProperties = { var pictureFrameProperties = {
name: 'scriptableResourceTest Picture Frame', name: 'scriptableResourceTest Picture Frame',
@ -50,7 +50,6 @@ function getFrame(callback) {
position.x += - 5 * Math.sin(rads); position.x += - 5 * Math.sin(rads);
position.z += - 5 * Math.cos(rads); position.z += - 5 * Math.cos(rads);
print(JSON.stringify(position));
return position; return position;
} }
} }
@ -67,10 +66,10 @@ function prefetch(callback) {
var filepath = MOVIE_URL + padded + '.jpg'; var filepath = MOVIE_URL + padded + '.jpg';
var texture = TextureCache.prefetch(filepath); var texture = TextureCache.prefetch(filepath);
frames.push(texture); frames.push(texture);
if (!texture.state == Resource.State.FINISHED) { if (texture.state !== Resource.State.FINISHED) {
numLoading++; numLoading++;
texture.stateChanged.connect(function(state) { texture.stateChanged.connect(function(state) {
if (state == Resource.State.FAILED || state == Resource.State.FINISHED) { if (state === Resource.State.FAILED || state === Resource.State.FINISHED) {
--numLoading; --numLoading;
if (!numLoading) { callback(frames); } if (!numLoading) { callback(frames); }
} }

View 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();
});

View file

@ -1,5 +1,5 @@
// //
// testMovie.js // movieTest.js
// scripts/developer/tests/scriptableResource // scripts/developer/tests/scriptableResource
// //
// Created by Zach Pomerantz on 4/27/16. // Created by Zach Pomerantz on 4/27/16.

View file

@ -1,5 +1,5 @@
// //
// testPrefetch.js // prefetchTest.js
// scripts/developer/tests/scriptableResource // scripts/developer/tests/scriptableResource
// //
// Created by Zach Pomerantz on 4/27/16. // Created by Zach Pomerantz on 4/27/16.

View file

@ -29,6 +29,10 @@ var IDENTITY_QUAT = {
var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with handControllerGrab.js var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with handControllerGrab.js
var GRAB_USER_DATA_KEY = "grabKey"; // 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 = { var DEFAULT_GRABBABLE_DATA = {
grabbable: true, grabbable: true,
invertSolidWhileHeld: false invertSolidWhileHeld: false
@ -335,6 +339,9 @@ Grabber.prototype.pressEvent = function(event) {
mouse.startDrag(event); mouse.startDrag(event);
var now = Date.now();
this.lastHeartBeat = 0;
var clickedEntity = pickResults.entityID; var clickedEntity = pickResults.entityID;
var entityProperties = Entities.getEntityProperties(clickedEntity) var entityProperties = Entities.getEntityProperties(clickedEntity)
this.startPosition = entityProperties.position; this.startPosition = entityProperties.position;
@ -376,7 +383,16 @@ Grabber.prototype.pressEvent = function(event) {
if(!entityIsGrabbedByOther(this.entityID)){ if(!entityIsGrabbedByOther(this.entityID)){
this.moveEvent(event); 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 // TODO: play sounds again when we aren't leaking AudioInjector threads
//Audio.playSound(grabSound, { position: entityProperties.position, volume: VOLUME }); //Audio.playSound(grabSound, { position: entityProperties.position, volume: VOLUME });
} }
@ -394,17 +410,41 @@ Grabber.prototype.releaseEvent = function(event) {
beacon.disable(); 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 // TODO: play sounds again when we aren't leaking AudioInjector threads
//Audio.playSound(releaseSound, { position: entityProperties.position, volume: VOLUME }); //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) { Grabber.prototype.moveEvent = function(event) {
if (!this.isGrabbing) { if (!this.isGrabbing) {
return; return;
} }
mouse.updateDrag(event); mouse.updateDrag(event);
this.heartBeat(this.entityID);
// see if something added/restored gravity // see if something added/restored gravity
var entityProperties = Entities.getEntityProperties(this.entityID); var entityProperties = Entities.getEntityProperties(this.entityID);
if (Vec3.length(entityProperties.gravity) != 0) { if (Vec3.length(entityProperties.gravity) != 0) {

View file

@ -12,7 +12,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // 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 */ /*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_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_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 TRIGGER_OFF_VALUE = 0.15;
var BUMPER_ON_VALUE = 0.5; var BUMPER_ON_VALUE = 0.5;
@ -102,7 +102,6 @@ var ZERO_VEC = {
}; };
var NULL_UUID = "{00000000-0000-0000-0000-000000000000}"; 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 // these control how long an abandoned pointer line or action will hang around
var LIFETIME = 10; var LIFETIME = 10;
@ -740,10 +739,6 @@ function MyController(hand) {
}; };
this.propsArePhysical = function(props) { 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'); var isPhysical = (props.shapeType && props.shapeType != 'none');
return isPhysical; return isPhysical;
} }
@ -837,7 +832,7 @@ function MyController(hand) {
this.search = function() { this.search = function() {
this.grabbedEntity = null; this.grabbedEntity = null;
this.isInitialGrab = false; this.isInitialGrab = false;
this.doubleParentGrab = false; this.shouldResetParentOnRelease = false;
this.checkForStrayChildren(); this.checkForStrayChildren();
@ -914,7 +909,7 @@ function MyController(hand) {
candidateEntities = rayPickedCandidateEntities.concat(nearPickedCandidateEntities); candidateEntities = rayPickedCandidateEntities.concat(nearPickedCandidateEntities);
var forbiddenNames = ["Grab Debug Entity", "grab pointer"]; 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 minDistance = PICK_MAX_DISTANCE;
var i, props, distance, grabbableData; var i, props, distance, grabbableData;
@ -1019,6 +1014,10 @@ function MyController(hand) {
if (this.state == STATE_SEARCHING) { if (this.state == STATE_SEARCHING) {
this.setState(STATE_NEAR_GRABBING); this.setState(STATE_NEAR_GRABBING);
} else { // (this.state == STATE_HOLD_SEARCHING) } 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); this.setState(STATE_HOLD);
} }
return; 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 // 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 // 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. // 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.previousParentID = props.parentID;
this.previousParentJointIndex = props.parentJointIndex; this.previousParentJointIndex = props.parentJointIndex;
if (this.state == STATE_SEARCHING) { if (this.state == STATE_SEARCHING) {
@ -1149,7 +1148,7 @@ function MyController(hand) {
if (this.actionID === NULL_UUID) { if (this.actionID === NULL_UUID) {
this.actionID = null; this.actionID = null;
} }
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC);
if (this.actionID !== null) { if (this.actionID !== null) {
this.setState(STATE_CONTINUE_DISTANCE_HOLDING); this.setState(STATE_CONTINUE_DISTANCE_HOLDING);
@ -1184,7 +1183,7 @@ function MyController(hand) {
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
var now = Date.now(); 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; this.currentObjectTime = now;
// the action was set up when this.distanceHolding was called. update the targets. // the action was set up when this.distanceHolding was called. update the targets.
@ -1302,7 +1301,7 @@ function MyController(hand) {
ttl: ACTION_TTL ttl: ACTION_TTL
}); });
if (success) { if (success) {
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC);
} else { } else {
print("continueDistanceHolding -- updateAction failed"); print("continueDistanceHolding -- updateAction failed");
} }
@ -1327,7 +1326,7 @@ function MyController(hand) {
return false; return false;
} }
var now = Date.now(); var now = Date.now();
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC);
return true; return true;
}; };
@ -1436,6 +1435,10 @@ function MyController(hand) {
if (!this.setupHoldAction()) { if (!this.setupHoldAction()) {
return; return;
} }
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
action: 'grab',
grabbedEntity: this.grabbedEntity
}));
} else { } else {
// grab entity via parenting // grab entity via parenting
this.actionID = null; this.actionID = null;
@ -1563,7 +1566,7 @@ function MyController(hand) {
var now = Date.now(); var now = Date.now();
var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters 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) { if (deltaTime > 0.0) {
var worldDeltaPosition = Vec3.subtract(props.position, this.currentObjectPosition); var worldDeltaPosition = Vec3.subtract(props.position, this.currentObjectPosition);
@ -1590,7 +1593,7 @@ function MyController(hand) {
this.callEntityMethodOnGrabbed("continueNearGrab"); 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 // if less than a 5 seconds left, refresh the actions ttl
var success = Entities.updateAction(this.grabbedEntity, this.actionID, { var success = Entities.updateAction(this.grabbedEntity, this.actionID, {
hand: this.hand === RIGHT_HAND ? "right" : "left", hand: this.hand === RIGHT_HAND ? "right" : "left",
@ -1603,7 +1606,7 @@ function MyController(hand) {
ignoreIK: this.ignoreIK ignoreIK: this.ignoreIK
}); });
if (success) { if (success) {
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC);
} else { } else {
print("continueNearGrabbing -- updateAction failed"); print("continueNearGrabbing -- updateAction failed");
Entities.deleteAction(this.grabbedEntity, this.actionID); 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 // 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. // 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 parentID = props.parentID;
var forceVelocity = false; var forceVelocity = false;
var doSetVelocity = 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 // TODO: EntityScriptingInterface::convertLocationToScriptSemantics should be setting up
// props.velocity to be a world-frame velocity and localVelocity to be vs parent. Until that // 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 // 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; 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. // we parent-grabbed this from another parent grab. try to put it back where we found it.
var deactiveProps = { var deactiveProps = {
parentID: this.previousParentID, parentID: this.previousParentID,
@ -1892,7 +1895,8 @@ function MyController(hand) {
Entities.editEntity(entityID, deactiveProps); Entities.editEntity(entityID, deactiveProps);
} else if (noVelocity) { } else if (noVelocity) {
Entities.editEntity(entityID, {velocity: {x: 0.0, y: 0.0, z: 0.0}, 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 { } else {
data = null; data = null;

View file

@ -7,6 +7,6 @@ setup_hifi_project(Network Script)
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
# link in the shared libraries # 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() package_libraries_for_deployment()