History

Merge branch 'master' of https://github.com/highfidelity/hifi into virtualEntities

ZappoMan committed 12 years ago

Commit 32d5eb32 parents 1b1c386 a6f0c9b159 files · +4368 −3616Browse files

Unified · Split

159 files
  1. CMakeLists.txt +12 −0
  2. assignment-client/CMakeLists.txt +8 −38
  3. assignment-client/src/Agent.cpp +1 −1
  4. assignment-client/src/audio/AudioMixer.cpp +71 −29
  5. assignment-client/src/audio/AudioMixer.h +4 −1
  6. assignment-client/src/audio/AudioMixerClientData.cpp +44 −1
  7. assignment-client/src/audio/AudioMixerClientData.h +5 −0
  8. assignment-client/src/audio/AudioMixerDatagramProcessor.cpp +47 −0
  9. assignment-client/src/audio/AudioMixerDatagramProcessor.h +32 −0
  10. assignment-client/src/avatars/ScriptableAvatar.cpp +2 −0
  11. cmake/macros/AutoMTC.cmake +2 −2
  12. cmake/macros/IncludeGLM.cmake +2 −2
  13. cmake/macros/IncludeHifiLibraryHeaders.cmake +14 −0
  14. cmake/macros/LinkHifiLibraries.cmake +34 −0
  15. cmake/macros/LinkHifiLibrary.cmake +0 −27
  16. cmake/macros/LinkSharedDependencies.cmake +25 −0
  17. cmake/macros/SetupHifiLibrary.cmake +17 −10
  18. cmake/macros/SetupHifiProject.cmake +15 −8
  19. cmake/modules/FindATL.cmake +29 −0
  20. cmake/modules/FindFaceplus.cmake +1 −1
  21. cmake/modules/FindFaceshift.cmake +1 −1
  22. cmake/modules/FindLeapMotion.cmake +1 −1
  23. cmake/modules/FindLibOVR.cmake +27 −18
  24. cmake/modules/FindPrioVR.cmake +1 −1
  25. cmake/modules/FindQxmpp.cmake +4 −2
  26. cmake/modules/FindRtMidi.cmake +1 −1
  27. cmake/modules/FindSixense.cmake +1 −1
  28. cmake/modules/FindVisage.cmake +18 −9
  29. domain-server/CMakeLists.txt +5 −35
  30. domain-server/resources/web/settings/describe.json +6 −0
  31. examples/clipboardExample.js +8 −1
  32. interface/CMakeLists.txt +26 −80
  33. interface/external/libovr/readme.txt +0 −0
  34. interface/interface_en.ts +6 −6
  35. interface/resources/shaders/metavoxel_heightfield.vert +14 −4
  36. interface/resources/shaders/metavoxel_heightfield_cascaded_shadow_map.frag +48 −0
  37. interface/resources/shaders/metavoxel_heightfield_cursor.frag +32 −0
  38. interface/resources/shaders/metavoxel_heightfield_cursor.vert +28 −0
  39. interface/resources/shaders/metavoxel_heightfield_shadow_map.frag +37 −0
  40. interface/src/Application.cpp +27 −15
  41. interface/src/Application.h +4 −1
  42. interface/src/Audio.cpp +42 −2
  43. interface/src/Audio.h +14 −3
  44. interface/src/Menu.cpp +44 −2
  45. interface/src/Menu.h +5 −0
  46. interface/src/MetavoxelSystem.cpp +779 −67
  47. interface/src/MetavoxelSystem.h +61 −9
  48. interface/src/avatar/Head.cpp +0 −3
  49. interface/src/avatar/Head.h +0 −2
  50. interface/src/avatar/MyAvatar.cpp +15 −8
  51. interface/src/avatar/SkeletonModel.cpp +65 −148
  52. interface/src/avatar/SkeletonModel.h +8 −11
  53. interface/src/avatar/SkeletonRagdoll.cpp +148 −0
  54. interface/src/avatar/SkeletonRagdoll.h +42 −0
  55. interface/src/devices/CaraFaceTracker.cpp +1 −1
  56. interface/src/devices/DdeFaceTracker.cpp +42 −5
  57. interface/src/devices/DdeFaceTracker.h +4 −0
  58. interface/src/devices/OculusManager.cpp +77 −13
  59. interface/src/devices/OculusManager.h +1 −0
  60. interface/src/devices/SixenseManager.cpp +3 −1
  61. interface/src/devices/SixenseManager.h +1 −1
  62. interface/src/renderer/JointState.h +1 −0
  63. interface/src/renderer/Model.cpp +5 −3
  64. interface/src/renderer/Model.h +3 −0
  65. interface/src/scripting/ClipboardScriptingInterface.cpp +31 −0
  66. interface/src/scripting/ClipboardScriptingInterface.h +3 −0
  67. interface/src/ui/ApplicationOverlay.cpp +29 −0
  68. interface/src/ui/ApplicationOverlay.h +2 −1
  69. interface/src/ui/MetavoxelEditor.cpp +94 −19
  70. interface/src/ui/MetavoxelEditor.h +58 −1
  71. interface/src/ui/VoxelImportDialog.cpp +94 −37
  72. interface/src/ui/VoxelImportDialog.h +21 −13
  73. interface/src/ui/overlays/Base3DOverlay.h +2 −0
  74. interface/src/voxels/OctreePacketProcessor.cpp +1 −1
  75. interface/src/voxels/VoxelImporter.cpp +33 −82
  76. interface/src/voxels/VoxelImporter.h +12 −11
  77. libraries/animation/CMakeLists.txt +5 −25
  78. libraries/audio/CMakeLists.txt +6 −21
  79. libraries/audio/src/AudioFilter.cpp +26 −0
  80. libraries/audio/src/AudioFilter.h +298 −0
  81. libraries/audio/src/AudioRingBuffer.cpp +2 −2
  82. libraries/audio/src/AudioRingBuffer.h +2 −4
  83. libraries/audio/src/InboundAudioStream.cpp +2 −0
  84. libraries/avatars/CMakeLists.txt +7 −25
  85. libraries/avatars/src/AvatarData.cpp +1 −1
  86. libraries/avatars/src/HeadData.cpp +2 −2
  87. libraries/avatars/src/Referential.cpp +1 −1
  88. libraries/embedded-webserver/CMakeLists.txt +4 −11
  89. libraries/entities/CMakeLists.txt +6 −34
  90. libraries/fbx/CMakeLists.txt +8 −23
  91. libraries/fbx/src/FBXReader.cpp +1 −1
  92. libraries/metavoxels/CMakeLists.txt +7 −22
  93. libraries/metavoxels/src/AttributeRegistry.cpp +297 −65
  94. libraries/metavoxels/src/AttributeRegistry.h +22 −4
  95. libraries/metavoxels/src/MetavoxelMessages.cpp +174 −0
  96. libraries/metavoxels/src/MetavoxelMessages.h +34 −0
  97. libraries/metavoxels/src/MetavoxelUtil.cpp +15 −0
  98. libraries/metavoxels/src/MetavoxelUtil.h +8 −0
  99. libraries/networking/CMakeLists.txt +9 −16
  100. libraries/networking/src/DomainHandler.cpp +4 −1
  101. libraries/networking/src/DomainHandler.h +1 −0
  102. libraries/networking/src/LimitedNodeList.cpp +25 −12
  103. libraries/networking/src/LimitedNodeList.h +1 −1
  104. libraries/networking/src/PacketHeaders.cpp +2 −0
  105. libraries/networking/src/PacketSender.h +0 −4
  106. libraries/networking/src/ReceivedPacketProcessor.h +0 −4
  107. libraries/networking/src/SequenceNumberStats.cpp +15 −10
  108. libraries/networking/src/SequenceNumberStats.h +13 −0
  109. libraries/networking/src/ThreadedAssignment.cpp +20 −3
  110. libraries/networking/src/ThreadedAssignment.h +7 −3
  111. libraries/octree/CMakeLists.txt +11 −22
  112. libraries/octree/src/EditPacketBuffer.cpp +1 −1
  113. libraries/octree/src/EditPacketBuffer.h +2 −2
  114. libraries/octree/src/JurisdictionListener.cpp +1 −1
  115. libraries/octree/src/JurisdictionListener.h +0 −4
  116. libraries/octree/src/JurisdictionSender.cpp +1 −1
  117. libraries/octree/src/OctreeEditPacketSender.cpp +3 −3
  118. libraries/octree/src/OctreeEditPacketSender.h +5 −5
  119. libraries/octree/src/OctreePacketData.cpp +2 −0
  120. libraries/octree/src/OctreeQuery.cpp +3 −2
  121. libraries/particles/CMakeLists.txt +7 −28
  122. libraries/particles/src/Particle.cpp +3 −3
  123. libraries/particles/src/Particle.h +1 −1
  124. libraries/particles/src/ParticleEditPacketSender.cpp +2 −2
  125. libraries/particles/src/ParticleEditPacketSender.h +1 −1
  126. libraries/script-engine/CMakeLists.txt +6 −30
  127. libraries/script-engine/src/Quat.cpp +1 −1
  128. libraries/shared/CMakeLists.txt +4 −30
  129. libraries/shared/external/pthread.h +0 −1403
  130. libraries/shared/external/sched.h +0 −189
  131. libraries/shared/src/AngularConstraint.cpp +2 −1
  132. libraries/shared/src/AngularConstraint.h +0 −1
  133. libraries/shared/src/ContactPoint.cpp +108 −72
  134. libraries/shared/src/ContactPoint.h +4 −2
  135. libraries/shared/src/GLMHelpers.cpp +299 −0
  136. libraries/shared/src/GLMHelpers.h +89 −0
  137. libraries/shared/src/MovingMinMaxAvg.h +1 −0
  138. libraries/shared/src/PhysicsSimulation.cpp +20 −20
  139. libraries/shared/src/PhysicsSimulation.h +2 −2
  140. libraries/shared/src/Ragdoll.cpp +23 −20
  141. libraries/shared/src/Ragdoll.h +14 −14
  142. libraries/shared/src/SharedUtil.cpp +1 −290
  143. libraries/shared/src/SharedUtil.h +0 −69
  144. libraries/voxels/CMakeLists.txt +11 −24
  145. libraries/voxels/src/VoxelEditPacketSender.h +1 −1
  146. tests/audio/CMakeLists.txt +4 −28
  147. tests/jitter/CMakeLists.txt +3 −28
  148. tests/jitter/src/main.cpp +258 −50
  149. tests/metavoxels/CMakeLists.txt +5 −25
  150. tests/networking/CMakeLists.txt +3 −28
  151. tests/networking/src/SequenceNumberStatsTests.cpp +4 −3
  152. tests/octree/CMakeLists.txt +14 −39
  153. tests/physics/CMakeLists.txt +4 −26
  154. tests/shared/CMakeLists.txt +4 −26
  155. tools/CMakeLists.txt +0 −1
  156. tools/bitstream2json/CMakeLists.txt +4 −21
  157. tools/json2bitstream/CMakeLists.txt +4 −21
  158. tools/mtc/CMakeLists.txt +2 −5
  159. voxel-edit/CMakeLists.txt +4 −35
CMakeLists.txt+12−0
@@ -44,6 +44,18 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) · 43 unmodified lines
44# Instruct CMake to run moc automatically when needed.44# Instruct CMake to run moc automatically when needed.
45set(CMAKE_AUTOMOC ON)45set(CMAKE_AUTOMOC ON)
46 46
47set(HIFI_LIBRARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries")
48
49# setup for find modules
50set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/")
51
52set(MACRO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macros")
53
54file(GLOB HIFI_CUSTOM_MACROS "cmake/macros/*.cmake")
55foreach(CUSTOM_MACRO ${HIFI_CUSTOM_MACROS})
56 include(${CUSTOM_MACRO})
57endforeach()
58
47# targets on all platforms59# targets on all platforms
48add_subdirectory(assignment-client)60add_subdirectory(assignment-client)
49add_subdirectory(domain-server)61add_subdirectory(domain-server)
assignment-client/CMakeLists.txt+8−38
@@ -1,47 +1,17 @@
1set(TARGET_NAME assignment-client)1set(TARGET_NAME assignment-client)
2 2
3set(ROOT_DIR ..)3setup_hifi_project(Core Gui Network Script Widgets)
4set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
5 4
6# setup for find modules5include_glm()
7set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/")
8
9find_package(Qt5 COMPONENTS Network Script Widgets)
10
11include("${MACRO_DIR}/SetupHifiProject.cmake")
12setup_hifi_project(${TARGET_NAME} TRUE)
13
14# include glm
15include("${MACRO_DIR}/IncludeGLM.cmake")
16include_glm(${TARGET_NAME} "${ROOT_DIR}")
17 6
18# link in the shared libraries7# link in the shared libraries
19include(${MACRO_DIR}/LinkHifiLibrary.cmake)8link_hifi_libraries(
20link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")9 audio avatars octree voxels fbx particles entities metavoxels
21link_hifi_library(audio ${TARGET_NAME} "${ROOT_DIR}")10 networking animation shared script-engine embedded-webserver
22link_hifi_library(avatars ${TARGET_NAME} "${ROOT_DIR}")11)
23link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}")
24link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}")
25link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}")
26link_hifi_library(particles ${TARGET_NAME} "${ROOT_DIR}")
27link_hifi_library(entities ${TARGET_NAME} "${ROOT_DIR}")
28link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}")
29link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
30link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}")
31link_hifi_library(script-engine ${TARGET_NAME} "${ROOT_DIR}")
32link_hifi_library(embedded-webserver ${TARGET_NAME} "${ROOT_DIR}")
33 12
34if (UNIX)13if (UNIX)
35 target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS})14 list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK ${CMAKE_DL_LIBS})
36endif (UNIX)15endif (UNIX)
37 16
38IF (WIN32)17link_shared_dependencies()
39 target_link_libraries(${TARGET_NAME} Winmm Ws2_32)
40ENDIF(WIN32)
41
42target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Script)
43
44# add a definition for ssize_t so that windows doesn't bail
45if (WIN32)
46 add_definitions(-Dssize_t=long)
47endif ()
assignment-client/src/Agent.cpp+1−1
@@ -115,7 +115,7 @@ void Agent::readPendingDatagrams() { · 114 unmodified lines
115 sourceNode->setLastHeardMicrostamp(usecTimestampNow());115 sourceNode->setLastHeardMicrostamp(usecTimestampNow());
116 116
117 QByteArray mutablePacket = receivedPacket;117 QByteArray mutablePacket = receivedPacket;
118 ssize_t messageLength = mutablePacket.size();118 int messageLength = mutablePacket.size();
119 119
120 if (datagramPacketType == PacketTypeOctreeStats) {120 if (datagramPacketType == PacketTypeOctreeStats) {
121 121
assignment-client/src/audio/AudioMixer.cpp+71−29
@@ -37,6 +37,7 @@ · 36 unmodified lines
37#include <QtCore/QJsonDocument>37#include <QtCore/QJsonDocument>
38#include <QtCore/QJsonObject>38#include <QtCore/QJsonObject>
39#include <QtCore/QJsonValue>39#include <QtCore/QJsonValue>
40#include <QtCore/QThread>
40#include <QtCore/QTimer>41#include <QtCore/QTimer>
41#include <QtNetwork/QNetworkRequest>42#include <QtNetwork/QNetworkRequest>
42#include <QtNetwork/QNetworkReply>43#include <QtNetwork/QNetworkReply>
@@ -52,6 +53,7 @@ · 9 unmodified lines
52 53
53#include "AudioRingBuffer.h"54#include "AudioRingBuffer.h"
54#include "AudioMixerClientData.h"55#include "AudioMixerClientData.h"
56#include "AudioMixerDatagramProcessor.h"
55#include "AvatarAudioStream.h"57#include "AvatarAudioStream.h"
56#include "InjectedAudioStream.h"58#include "InjectedAudioStream.h"
57 59
@@ -71,6 +73,8 @@ bool AudioMixer::_useDynamicJitterBuffers = false; · 13 unmodified lines
71int AudioMixer::_staticDesiredJitterBufferFrames = 0;73int AudioMixer::_staticDesiredJitterBufferFrames = 0;
72int AudioMixer::_maxFramesOverDesired = 0;74int AudioMixer::_maxFramesOverDesired = 0;
73 75
76bool AudioMixer::_printStreamStats = false;
77
74AudioMixer::AudioMixer(const QByteArray& packet) :78AudioMixer::AudioMixer(const QByteArray& packet) :
75 ThreadedAssignment(packet),79 ThreadedAssignment(packet),
76 _trailingSleepRatio(1.0f),80 _trailingSleepRatio(1.0f),
@@ -295,38 +299,34 @@ void AudioMixer::prepareMixForListeningNode(Node* node) { · 218 unmodified lines
295 }299 }
296}300}
297 301
298void AudioMixer::readPendingDatagrams() {302void AudioMixer::readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) {
299 QByteArray receivedPacket;
300 HifiSockAddr senderSockAddr;
301 NodeList* nodeList = NodeList::getInstance();303 NodeList* nodeList = NodeList::getInstance();
302 304
303 while (readAvailableDatagram(receivedPacket, senderSockAddr)) {305 if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
304 if (nodeList->packetVersionAndHashMatch(receivedPacket)) {306 // pull any new audio data from nodes off of the network stack
305 // pull any new audio data from nodes off of the network stack307 PacketType mixerPacketType = packetTypeForPacket(receivedPacket);
306 PacketType mixerPacketType = packetTypeForPacket(receivedPacket);308 if (mixerPacketType == PacketTypeMicrophoneAudioNoEcho
307 if (mixerPacketType == PacketTypeMicrophoneAudioNoEcho309 || mixerPacketType == PacketTypeMicrophoneAudioWithEcho
308 || mixerPacketType == PacketTypeMicrophoneAudioWithEcho310 || mixerPacketType == PacketTypeInjectAudio
309 || mixerPacketType == PacketTypeInjectAudio311 || mixerPacketType == PacketTypeSilentAudioFrame
310 || mixerPacketType == PacketTypeSilentAudioFrame312 || mixerPacketType == PacketTypeAudioStreamStats) {
311 || mixerPacketType == PacketTypeAudioStreamStats) {313
312 314 nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket);
313 nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket);315 } else if (mixerPacketType == PacketTypeMuteEnvironment) {
314 } else if (mixerPacketType == PacketTypeMuteEnvironment) {316 QByteArray packet = receivedPacket;
315 QByteArray packet = receivedPacket;317 populatePacketHeader(packet, PacketTypeMuteEnvironment);
316 populatePacketHeader(packet, PacketTypeMuteEnvironment);318
317 319 foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
318 foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {320 if (node->getType() == NodeType::Agent && node->getActiveSocket() && node->getLinkedData() && node != nodeList->sendingNodeForPacket(receivedPacket)) {
319 if (node->getType() == NodeType::Agent && node->getActiveSocket() && node->getLinkedData() && node != nodeList->sendingNodeForPacket(receivedPacket)) {321 nodeList->writeDatagram(packet, packet.size(), node);
320 nodeList->writeDatagram(packet, packet.size(), node);
321 }
322 }322 }
323
324 } else {
325 // let processNodeData handle it.
326 nodeList->processNodeData(senderSockAddr, receivedPacket);
327 }323 }
324
325 } else {
326 // let processNodeData handle it.
327 nodeList->processNodeData(senderSockAddr, receivedPacket);
328 }328 }
329 }329 }
330}330}
331 331
332void AudioMixer::sendStatsPacket() {332void AudioMixer::sendStatsPacket() {
@@ -390,7 +390,35 @@ void AudioMixer::run() { · 57 unmodified lines
390 ThreadedAssignment::commonInit(AUDIO_MIXER_LOGGING_TARGET_NAME, NodeType::AudioMixer);390 ThreadedAssignment::commonInit(AUDIO_MIXER_LOGGING_TARGET_NAME, NodeType::AudioMixer);
391 391
392 NodeList* nodeList = NodeList::getInstance();392 NodeList* nodeList = NodeList::getInstance();
393 393
394 // we do not want this event loop to be the handler for UDP datagrams, so disconnect
395 disconnect(&nodeList->getNodeSocket(), 0, this, 0);
396
397 // setup a QThread with us as parent that will house the AudioMixerDatagramProcessor
398 _datagramProcessingThread = new QThread(this);
399
400 // create an AudioMixerDatagramProcessor and move it to that thread
401 AudioMixerDatagramProcessor* datagramProcessor = new AudioMixerDatagramProcessor(nodeList->getNodeSocket(), thread());
402 datagramProcessor->moveToThread(_datagramProcessingThread);
403
404 // remove the NodeList as the parent of the node socket
405 nodeList->getNodeSocket().setParent(NULL);
406 nodeList->getNodeSocket().moveToThread(_datagramProcessingThread);
407
408 // let the datagram processor handle readyRead from node socket
409 connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead,
410 datagramProcessor, &AudioMixerDatagramProcessor::readPendingDatagrams);
411
412 // connect to the datagram processing thread signal that tells us we have to handle a packet
413 connect(datagramProcessor, &AudioMixerDatagramProcessor::packetRequiresProcessing, this, &AudioMixer::readPendingDatagram);
414
415 // delete the datagram processor and the associated thread when the QThread quits
416 connect(_datagramProcessingThread, &QThread::finished, datagramProcessor, &QObject::deleteLater);
417 connect(datagramProcessor, &QObject::destroyed, _datagramProcessingThread, &QThread::deleteLater);
418
419 // start the datagram processing thread
420 _datagramProcessingThread->start();
421
394 nodeList->addNodeTypeToInterestSet(NodeType::Agent);422 nodeList->addNodeTypeToInterestSet(NodeType::Agent);
395 423
396 nodeList->linkedDataCreateCallback = attachNewNodeDataToNode;424 nodeList->linkedDataCreateCallback = attachNewNodeDataToNode;
@@ -448,7 +476,11 @@ void AudioMixer::run() { · 51 unmodified lines
448 }476 }
449 qDebug() << "Max frames over desired:" << _maxFramesOverDesired;477 qDebug() << "Max frames over desired:" << _maxFramesOverDesired;
450 478
451 479 const QString PRINT_STREAM_STATS_JSON_KEY = "H-print-stream-stats";
480 _printStreamStats = audioGroupObject[PRINT_STREAM_STATS_JSON_KEY].toBool();
481 if (_printStreamStats) {
482 qDebug() << "Stream stats will be printed to stdout";
483 }
452 484
453 const QString UNATTENUATED_ZONE_KEY = "D-unattenuated-zone";485 const QString UNATTENUATED_ZONE_KEY = "D-unattenuated-zone";
454 486
@@ -547,6 +579,7 @@ void AudioMixer::run() { · 92 unmodified lines
547 sendAudioStreamStats = true;579 sendAudioStreamStats = true;
548 }580 }
549 581
582 bool streamStatsPrinted = false;
550 foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {583 foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
551 if (node->getLinkedData()) {584 if (node->getLinkedData()) {
552 AudioMixerClientData* nodeData = (AudioMixerClientData*)node->getLinkedData();585 AudioMixerClientData* nodeData = (AudioMixerClientData*)node->getLinkedData();
@@ -581,12 +614,21 @@ void AudioMixer::run() { · 28 unmodified lines
581 // send an audio stream stats packet if it's time614 // send an audio stream stats packet if it's time
582 if (sendAudioStreamStats) {615 if (sendAudioStreamStats) {
583 nodeData->sendAudioStreamStatsPackets(node);616 nodeData->sendAudioStreamStatsPackets(node);
617
618 if (_printStreamStats) {
619 printf("\nStats for agent %s:\n", node->getUUID().toString().toLatin1().data());
620 nodeData->printUpstreamDownstreamStats();
621 streamStatsPrinted = true;
622 }
584 }623 }
585 624
586 ++_sumListeners;625 ++_sumListeners;
587 }626 }
588 }627 }
589 }628 }
629 if (streamStatsPrinted) {
630 printf("\n----------------------------------------------------------------\n");
631 }
590 632
591 ++_numStatFrames;633 ++_numStatFrames;
592 634
assignment-client/src/audio/AudioMixer.h+4−1
@@ -33,7 +33,8 @@ public slots: · 32 unmodified lines
33 /// threaded run of assignment33 /// threaded run of assignment
34 void run();34 void run();
35 35
36 void readPendingDatagrams();36 void readPendingDatagrams() { }; // this will not be called since our datagram processing thread will handle
37 void readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr);
37 38
38 void sendStatsPacket();39 void sendStatsPacket();
39 40
@@ -66,6 +67,8 @@ private: · 26 unmodified lines
66 static int _staticDesiredJitterBufferFrames;67 static int _staticDesiredJitterBufferFrames;
67 static int _maxFramesOverDesired;68 static int _maxFramesOverDesired;
68 69
70 static bool _printStreamStats;
71
69 quint64 _lastSendAudioStreamStatsTime;72 quint64 _lastSendAudioStreamStatsTime;
70};73};
71 74
assignment-client/src/audio/AudioMixerClientData.cpp+44−1
@@ -22,7 +22,8 @@ · 21 unmodified lines
22 22
23AudioMixerClientData::AudioMixerClientData() :23AudioMixerClientData::AudioMixerClientData() :
24 _audioStreams(),24 _audioStreams(),
25 _outgoingMixedAudioSequenceNumber(0)25 _outgoingMixedAudioSequenceNumber(0),
26 _downstreamAudioStreamStats()
26{27{
27}28}
28 29
@@ -263,3 +264,45 @@ QString AudioMixerClientData::getAudioStreamStatsString() const { · 234 unmodified lines
263 }264 }
264 return result;265 return result;
265}266}
267
268void AudioMixerClientData::printUpstreamDownstreamStats() const {
269 // print the upstream (mic stream) stats if the mic stream exists
270 if (_audioStreams.contains(QUuid())) {
271 printf("Upstream:\n");
272 printAudioStreamStats(_audioStreams.value(QUuid())->getAudioStreamStats());
273 }
274 // print the downstream stats if they contain valid info
275 if (_downstreamAudioStreamStats._packetStreamStats._received > 0) {
276 printf("Downstream:\n");
277 printAudioStreamStats(_downstreamAudioStreamStats);
278 }
279}
280
281void AudioMixerClientData::printAudioStreamStats(const AudioStreamStats& streamStats) const {
282 printf(" Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)\n",
283 streamStats._packetStreamStats.getLostRate() * 100.0f,
284 streamStats._packetStreamStats._lost,
285 streamStats._packetStreamWindowStats.getLostRate() * 100.0f,
286 streamStats._packetStreamWindowStats._lost);
287
288 printf(" Ringbuffer frames | desired: %u, avg_available(10s): %u, available: %u\n",
289 streamStats._desiredJitterBufferFrames,
290 streamStats._framesAvailableAverage,
291 streamStats._framesAvailable);
292
293 printf(" Ringbuffer stats | starves: %u, prev_starve_lasted: %u, frames_dropped: %u, overflows: %u\n",
294 streamStats._starveCount,
295 streamStats._consecutiveNotMixedCount,
296 streamStats._framesDropped,
297 streamStats._overflowCount);
298
299 printf(" Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s\n",
300 formatUsecTime(streamStats._timeGapMin).toLatin1().data(),
301 formatUsecTime(streamStats._timeGapMax).toLatin1().data(),
302 formatUsecTime(streamStats._timeGapAverage).toLatin1().data());
303
304 printf(" Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s\n",
305 formatUsecTime(streamStats._timeGapWindowMin).toLatin1().data(),
306 formatUsecTime(streamStats._timeGapWindowMax).toLatin1().data(),
307 formatUsecTime(streamStats._timeGapWindowAverage).toLatin1().data());
308}
assignment-client/src/audio/AudioMixerClientData.h+5−0
@@ -38,6 +38,11 @@ public: · 37 unmodified lines
38 void incrementOutgoingMixedAudioSequenceNumber() { _outgoingMixedAudioSequenceNumber++; }38 void incrementOutgoingMixedAudioSequenceNumber() { _outgoingMixedAudioSequenceNumber++; }
39 quint16 getOutgoingSequenceNumber() const { return _outgoingMixedAudioSequenceNumber; }39 quint16 getOutgoingSequenceNumber() const { return _outgoingMixedAudioSequenceNumber; }
40 40
41 void printUpstreamDownstreamStats() const;
42
43private:
44 void printAudioStreamStats(const AudioStreamStats& streamStats) const;
45
41private:46private:
42 QHash<QUuid, PositionalAudioStream*> _audioStreams; // mic stream stored under key of null UUID47 QHash<QUuid, PositionalAudioStream*> _audioStreams; // mic stream stored under key of null UUID
43 48
assignment-client/src/audio/AudioMixerDatagramProcessor.cpp+47−0
@@ -0,0 +1,47 @@
1//
2// AudioMixerDatagramProcessor.cpp
3// assignment-client/src
4//
5// Created by Stephen Birarda on 2014-08-14.
6// Copyright 2014 High Fidelity, Inc.
7//
8// Distributed under the Apache License, Version 2.0.
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//
11
12#include <QDebug>
13
14#include <HifiSockAddr.h>
15#include <NodeList.h>
16
17#include "AudioMixerDatagramProcessor.h"
18
19AudioMixerDatagramProcessor::AudioMixerDatagramProcessor(QUdpSocket& nodeSocket, QThread* previousNodeSocketThread) :
20 _nodeSocket(nodeSocket),
21 _previousNodeSocketThread(previousNodeSocketThread)
22{
23
24}
25
26AudioMixerDatagramProcessor::~AudioMixerDatagramProcessor() {
27 // return the node socket to its previous thread
28 _nodeSocket.moveToThread(_previousNodeSocketThread);
29}
30
31void AudioMixerDatagramProcessor::readPendingDatagrams() {
32
33 HifiSockAddr senderSockAddr;
34 static QByteArray incomingPacket;
35
36 // read everything that is available
37 while (_nodeSocket.hasPendingDatagrams()) {
38 incomingPacket.resize(_nodeSocket.pendingDatagramSize());
39
40 // just get this packet off the stack
41 _nodeSocket.readDatagram(incomingPacket.data(), incomingPacket.size(),
42 senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
43
44 // emit the signal to tell AudioMixer it needs to process a packet
45 emit packetRequiresProcessing(incomingPacket, senderSockAddr);
46 }
47}
assignment-client/src/audio/AudioMixerDatagramProcessor.h+32−0
@@ -0,0 +1,32 @@
1//
2// AudioMixerDatagramProcessor.h
3// assignment-client/src
4//
5// Created by Stephen Birarda on 2014-08-14.
6// Copyright 2014 High Fidelity, Inc.
7//
8// Distributed under the Apache License, Version 2.0.
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//
11
12#ifndef hifi_AudioMixerDatagramProcessor_h
13#define hifi_AudioMixerDatagramProcessor_h
14
15#include <qobject.h>
16#include <qudpsocket.h>
17
18class AudioMixerDatagramProcessor : public QObject {
19 Q_OBJECT
20public:
21 AudioMixerDatagramProcessor(QUdpSocket& nodeSocket, QThread* previousNodeSocketThread);
22 ~AudioMixerDatagramProcessor();
23public slots:
24 void readPendingDatagrams();
25signals:
26 void packetRequiresProcessing(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr);
27private:
28 QUdpSocket& _nodeSocket;
29 QThread* _previousNodeSocketThread;
30};
31
32#endif // hifi_AudioMixerDatagramProcessor_h
assignment-client/src/avatars/ScriptableAvatar.cpp+2−0
@@ -11,6 +11,8 @@ · 10 unmodified lines
11 11
12#include <QThread>12#include <QThread>
13 13
14#include <GLMHelpers.h>
15
14#include "ScriptableAvatar.h"16#include "ScriptableAvatar.h"
15 17
16ScriptableAvatar::ScriptableAvatar(ScriptEngine* scriptEngine) : _scriptEngine(scriptEngine), _animation(NULL) {18ScriptableAvatar::ScriptableAvatar(ScriptEngine* scriptEngine) : _scriptEngine(scriptEngine), _animation(NULL) {
cmake/macros/AutoMTC.cmake+2−2
@@ -8,8 +8,8 @@ · 7 unmodified lines
8# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html8# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
9# 9#
10 10
11macro(AUTO_MTC TARGET ROOT_DIR)11macro(AUTO_MTC)
12 set(AUTOMTC_SRC ${TARGET}_automtc.cpp)12 set(AUTOMTC_SRC ${TARGET_NAME}_automtc.cpp)
13 13
14 file(GLOB INCLUDE_FILES src/*.h)14 file(GLOB INCLUDE_FILES src/*.h)
15 15
cmake/macros/IncludeGLM.cmake+2−2
@@ -7,7 +7,7 @@ · 6 unmodified lines
7# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html7# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
8# 8#
9 9
10macro(INCLUDE_GLM TARGET ROOT_DIR)10macro(INCLUDE_GLM)
11 11
12 find_package(GLM REQUIRED)12 find_package(GLM REQUIRED)
13 include_directories("${GLM_INCLUDE_DIRS}")13 include_directories("${GLM_INCLUDE_DIRS}")
@@ -16,4 +16,4 @@ macro(INCLUDE_GLM TARGET ROOT_DIR) · 2 unmodified lines
16 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${GLM_INCLUDE_DIRS}")16 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${GLM_INCLUDE_DIRS}")
17 endif ()17 endif ()
18 18
19endmacro(INCLUDE_GLM _target _root_dir)19endmacro(INCLUDE_GLM)
cmake/macros/IncludeHifiLibraryHeaders.cmake+14−0
@@ -0,0 +1,14 @@
1#
2# IncludeHifiLibraryHeaders.cmake
3# cmake/macros
4#
5# Copyright 2014 High Fidelity, Inc.
6# Created by Stephen Birarda on August 8, 2014
7#
8# Distributed under the Apache License, Version 2.0.
9# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10#
11
12macro(include_hifi_library_headers LIBRARY)
13 include_directories("${HIFI_LIBRARY_DIR}/${LIBRARY}/src")
14endmacro(include_hifi_library_headers _library _root_dir)
cmake/macros/LinkHifiLibraries.cmake+34−0
@@ -0,0 +1,34 @@
1#
2# LinkHifiLibrary.cmake
3#
4# Copyright 2013 High Fidelity, Inc.
5#
6# Distributed under the Apache License, Version 2.0.
7# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
8#
9
10macro(LINK_HIFI_LIBRARIES)
11
12 file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}")
13
14 set(LIBRARIES_TO_LINK ${ARGN})
15
16 foreach(HIFI_LIBRARY ${LIBRARIES_TO_LINK})
17 if (NOT TARGET ${HIFI_LIBRARY})
18 add_subdirectory("${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}" "${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}")
19 endif ()
20
21 include_directories("${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src")
22
23 add_dependencies(${TARGET_NAME} ${HIFI_LIBRARY})
24
25 # link the actual library - it is static so don't bubble it up
26 target_link_libraries(${TARGET_NAME} ${HIFI_LIBRARY})
27
28 # ask the library what its dynamic dependencies are and link them
29 get_target_property(LINKED_TARGET_DEPENDENCY_LIBRARIES ${HIFI_LIBRARY} DEPENDENCY_LIBRARIES)
30 list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK ${LINKED_TARGET_DEPENDENCY_LIBRARIES})
31
32 endforeach()
33
34endmacro(LINK_HIFI_LIBRARIES)
cmake/macros/LinkHifiLibrary.cmake+0−27
@@ -1,27 +0,0 @@
1#
2# LinkHifiLibrary.cmake
3#
4# Copyright 2013 High Fidelity, Inc.
5#
6# Distributed under the Apache License, Version 2.0.
7# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
8#
9
10macro(LINK_HIFI_LIBRARY LIBRARY TARGET ROOT_DIR)
11
12 if (NOT TARGET ${LIBRARY})
13 add_subdirectory("${ROOT_DIR}/libraries/${LIBRARY}" "${ROOT_DIR}/libraries/${LIBRARY}")
14 endif ()
15
16 include_directories("${ROOT_DIR}/libraries/${LIBRARY}/src")
17
18 add_dependencies(${TARGET} ${LIBRARY})
19 target_link_libraries(${TARGET} ${LIBRARY})
20
21 if (APPLE)
22 # currently the "shared" library requires CoreServices
23 # link in required OS X framework
24 set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework CoreServices")
25 endif ()
26
27endmacro(LINK_HIFI_LIBRARY _library _target _root_dir)
cmake/macros/LinkSharedDependencies.cmake+25−0
@@ -0,0 +1,25 @@
1#
2# LinkSharedDependencies.cmake
3# cmake/macros
4#
5# Copyright 2014 High Fidelity, Inc.
6# Created by Stephen Birarda on August 8, 2014
7#
8# Distributed under the Apache License, Version 2.0.
9# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10#
11
12macro(LINK_SHARED_DEPENDENCIES)
13 if (${TARGET_NAME}_LIBRARIES_TO_LINK)
14 list(REMOVE_DUPLICATES ${TARGET_NAME}_LIBRARIES_TO_LINK)
15
16 # link these libraries to our target
17 target_link_libraries(${TARGET_NAME} ${${TARGET_NAME}_LIBRARIES_TO_LINK})
18 endif ()
19
20 # we've already linked our Qt modules, but we need to bubble them up to parents
21 list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${${TARGET}_QT_MODULES_TO_LINK}")
22
23 # set the property on this target so it can be retreived by targets linking to us
24 set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${${TARGET}_LIBRARIES_TO_LINK}")
25endmacro(LINK_SHARED_DEPENDENCIES)
cmake/macros/SetupHifiLibrary.cmake+17−10
@@ -7,20 +7,27 @@ · 6 unmodified lines
7# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html7# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
8# 8#
9 9
10macro(SETUP_HIFI_LIBRARY TARGET)10macro(SETUP_HIFI_LIBRARY)
11 11
12 project(${TARGET})12 project(${TARGET_NAME})
13 13
14 # grab the implemenation and header files14 # grab the implemenation and header files
15 file(GLOB LIB_SRCS src/*.h src/*.cpp)15 file(GLOB LIB_SRCS src/*.h src/*.cpp)
16 set(LIB_SRCS ${LIB_SRCS} ${WRAPPED_SRCS})16 set(LIB_SRCS ${LIB_SRCS})
17 17
18 # create a library and set the property so it can be referenced later18 # create a library and set the property so it can be referenced later
19 add_library(${TARGET} ${LIB_SRCS} ${ARGN})19 add_library(${TARGET_NAME} ${LIB_SRCS} ${AUTOMTC_SRC})
20 20
21 find_package(Qt5Core REQUIRED)21 set(QT_MODULES_TO_LINK ${ARGN})
22 qt5_use_modules(${TARGET} Core)22 list(APPEND QT_MODULES_TO_LINK Core)
23 23
24 target_link_libraries(${TARGET} ${QT_LIBRARIES})24 find_package(Qt5 COMPONENTS ${QT_MODULES_TO_LINK} REQUIRED)
25 25
26endmacro(SETUP_HIFI_LIBRARY _target)26 foreach(QT_MODULE ${QT_MODULES_TO_LINK})
27 get_target_property(QT_LIBRARY_LOCATION Qt5::${QT_MODULE} LOCATION)
28
29 # add the actual path to the Qt module to our LIBRARIES_TO_LINK variable
30 target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE})
31 list(APPEND ${TARGET_NAME}_QT_MODULES_TO_LINK ${QT_LIBRARY_LOCATION})
32 endforeach()
33endmacro(SETUP_HIFI_LIBRARY)
cmake/macros/SetupHifiProject.cmake+15−8
@@ -7,8 +7,8 @@ · 6 unmodified lines
7# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html7# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
8# 8#
9 9
10macro(SETUP_HIFI_PROJECT TARGET INCLUDE_QT) 10macro(SETUP_HIFI_PROJECT)
11 project(${TARGET})11 project(${TARGET_NAME})
12 12
13 # grab the implemenation and header files13 # grab the implemenation and header files
14 file(GLOB TARGET_SRCS src/*)14 file(GLOB TARGET_SRCS src/*)
@@ -23,12 +23,19 @@ macro(SETUP_HIFI_PROJECT TARGET INCLUDE_QT) · 8 unmodified lines
23 endforeach()23 endforeach()
24 24
25 # add the executable, include additional optional sources25 # add the executable, include additional optional sources
26 add_executable(${TARGET} ${TARGET_SRCS} ${ARGN})26 add_executable(${TARGET_NAME} ${TARGET_SRCS} "${AUTOMTC_SRC}")
27 27
28 if (${INCLUDE_QT})28 set(QT_MODULES_TO_LINK ${ARGN})
29 find_package(Qt5Core REQUIRED)29 list(APPEND QT_MODULES_TO_LINK Core)
30 qt5_use_modules(${TARGET} Core)30
31 endif ()31 find_package(Qt5 COMPONENTS ${QT_MODULES_TO_LINK} REQUIRED)
32
33 foreach(QT_MODULE ${QT_MODULES_TO_LINK})
34 target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE})
35
36 # add the actual path to the Qt module to our LIBRARIES_TO_LINK variable
37 get_target_property(QT_LIBRARY_LOCATION Qt5::${QT_MODULE} LOCATION)
38 list(APPEND ${TARGET_NAME}_QT_MODULES_TO_LINK ${QT_LIBRARY_LOCATION})
39 endforeach()
32 40
33 target_link_libraries(${TARGET} ${QT_LIBRARIES})
34endmacro()41endmacro()
cmake/modules/FindATL.cmake+29−0
@@ -0,0 +1,29 @@
1#
2# FindATL.cmake
3#
4# Try to find the ATL library needed to use the LibOVR
5#
6# Once done this will define
7#
8# ATL_FOUND - system found ATL
9# ATL_LIBRARIES - Link this to use ATL
10#
11# Created on 8/13/2013 by Stephen Birarda
12# Copyright 2014 High Fidelity, Inc.
13#
14# Distributed under the Apache License, Version 2.0.
15# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
16#
17
18if (WIN32)
19 find_library(ATL_LIBRARY_RELEASE atls PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS "C:\\WinDDK")
20 find_library(ATL_LIBRARY_DEBUG atlsd PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS "C:\\WinDDK")
21
22 include(SelectLibraryConfigurations)
23 select_library_configurations(ATL)
24endif ()
25
26set(ATL_LIBRARIES "${ATL_LIBRARY}")
27
28include(FindPackageHandleStandardArgs)
29find_package_handle_standard_args(ATL DEFAULT_MSG ATL_LIBRARIES)
cmake/modules/FindFaceplus.cmake+1−1
@@ -19,6 +19,6 @@ if (WIN32) · 18 unmodified lines
19endif (WIN32)19endif (WIN32)
20 20
21include(FindPackageHandleStandardArgs)21include(FindPackageHandleStandardArgs)
22find_package_handle_standard_args(FACEPLUS DEFAULT_MSG FACEPLUS_INCLUDE_DIRS FACEPLUS_LIBRARIES)22find_package_handle_standard_args(Faceplus DEFAULT_MSG FACEPLUS_INCLUDE_DIRS FACEPLUS_LIBRARIES)
23 23
24mark_as_advanced(FACEPLUS_INCLUDE_DIRS FACEPLUS_LIBRARIES)24mark_as_advanced(FACEPLUS_INCLUDE_DIRS FACEPLUS_LIBRARIES)
cmake/modules/FindFaceshift.cmake+1−1
@@ -40,6 +40,6 @@ select_library_configurations(FACESHIFT) · 39 unmodified lines
40set(FACESHIFT_LIBRARIES ${FACESHIFT_LIBRARY})40set(FACESHIFT_LIBRARIES ${FACESHIFT_LIBRARY})
41 41
42include(FindPackageHandleStandardArgs)42include(FindPackageHandleStandardArgs)
43find_package_handle_standard_args(FACESHIFT DEFAULT_MSG FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES)43find_package_handle_standard_args(Faceshift DEFAULT_MSG FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES)
44 44
45mark_as_advanced(FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES FACESHIFT_SEARCH_DIRS)45mark_as_advanced(FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES FACESHIFT_SEARCH_DIRS)
cmake/modules/FindLeapMotion.cmake+1−1
@@ -30,6 +30,6 @@ select_library_configurations(LEAPMOTION) · 29 unmodified lines
30set(LEAPMOTION_LIBRARIES "${LEAPMOTION_LIBRARY}")30set(LEAPMOTION_LIBRARIES "${LEAPMOTION_LIBRARY}")
31 31
32include(FindPackageHandleStandardArgs)32include(FindPackageHandleStandardArgs)
33find_package_handle_standard_args(LEAPMOTION DEFAULT_MSG LEAPMOTION_INCLUDE_DIRS LEAPMOTION_LIBRARIES)33find_package_handle_standard_args(LeapMotion DEFAULT_MSG LEAPMOTION_INCLUDE_DIRS LEAPMOTION_LIBRARIES)
34 34
35mark_as_advanced(LEAPMOTION_INCLUDE_DIRS LEAPMOTION_LIBRARIES LEAPMOTION_SEARCH_DIRS)35mark_as_advanced(LEAPMOTION_INCLUDE_DIRS LEAPMOTION_LIBRARIES LEAPMOTION_SEARCH_DIRS)
cmake/modules/FindLibOVR.cmake+27−18
@@ -19,16 +19,18 @@ · 18 unmodified lines
19# 19#
20 20
21include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")21include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
22hifi_library_search_hints("oculus")22hifi_library_search_hints("libovr")
23 23
24find_path(LIBOVR_INCLUDE_DIRS OVR.h PATH_SUFFIXES Include HINTS ${OCULUS_SEARCH_DIRS})24find_path(LIBOVR_INCLUDE_DIRS OVR.h PATH_SUFFIXES Include HINTS ${LIBOVR_SEARCH_DIRS})
25find_path(LIBOVR_SRC_DIR Util_Render_Stereo.h PATH_SUFFIXES Src/Util HINTS ${OCULUS_SEARCH_DIRS})25find_path(LIBOVR_SRC_DIR Util_Render_Stereo.h PATH_SUFFIXES Src/Util HINTS ${LIBOVR_SEARCH_DIRS})
26 26
27include(SelectLibraryConfigurations)27include(SelectLibraryConfigurations)
28 28
29if (APPLE)29if (APPLE)
30 find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/MacOS/Debug HINTS ${OCULUS_SEARCH_DIRS})30 find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/Mac/Debug HINTS ${LIBOVR_SEARCH_DIRS})
31 find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/MacOS/Release HINTS ${OCULUS_SEARCH_DIRS})31 find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/Mac/Release HINTS ${LIBOVR_SEARCH_DIRS})
32 find_library(ApplicationServices ApplicationServices)
33 find_library(IOKit IOKit)
32elseif (UNIX)34elseif (UNIX)
33 find_library(UDEV_LIBRARY_RELEASE udev /usr/lib/x86_64-linux-gnu/)35 find_library(UDEV_LIBRARY_RELEASE udev /usr/lib/x86_64-linux-gnu/)
34 find_library(XINERAMA_LIBRARY_RELEASE Xinerama /usr/lib/x86_64-linux-gnu/)36 find_library(XINERAMA_LIBRARY_RELEASE Xinerama /usr/lib/x86_64-linux-gnu/)
@@ -39,29 +41,36 @@ elseif (UNIX) · 4 unmodified lines
39 set(LINUX_ARCH_DIR "x86_64")41 set(LINUX_ARCH_DIR "x86_64")
40 endif()42 endif()
41 43
42 find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/Linux/Debug/${LINUX_ARCH_DIR} HINTS ${OCULUS_SEARCH_DIRS})44 find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/Linux/Debug/${LINUX_ARCH_DIR} HINTS ${LIBOVR_SEARCH_DIRS})
43 find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/Linux/Release/${LINUX_ARCH_DIR} HINTS ${OCULUS_SEARCH_DIRS})45 find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/Linux/Release/${LINUX_ARCH_DIR} HINTS ${LIBOVR_SEARCH_DIRS})
44 46
45 select_library_configurations(UDEV)47 select_library_configurations(UDEV)
46 select_library_configurations(XINERAMA)48 select_library_configurations(XINERAMA)
47 49
48elseif (WIN32) 50elseif (WIN32)
49 find_library(LIBOVR_LIBRARY_DEBUG NAMES libovrd PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${OCULUS_SEARCH_DIRS})51 find_library(LIBOVR_LIBRARY_DEBUG NAMES libovrd PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${LIBOVR_SEARCH_DIRS})
50 find_library(LIBOVR_LIBRARY_RELEASE NAMES libovr PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${OCULUS_SEARCH_DIRS})52 find_library(LIBOVR_LIBRARY_RELEASE NAMES libovr PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${LIBOVR_SEARCH_DIRS})
53 find_package(ATL)
51endif ()54endif ()
52 55
53select_library_configurations(LIBOVR)56select_library_configurations(LIBOVR)
54set(LIBOVR_LIBRARIES "${LIBOVR_LIBRARY}")57set(LIBOVR_LIBRARIES ${LIBOVR_LIBRARY})
55 58
56if (UNIX AND NOT APPLE) 59list(APPEND LIBOVR_ARGS_LIST LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARY)
57 set(LIBOVR_LIBRARIES "${LIBOVR_LIBRARIES}" "${UDEV_LIBRARY}" "${XINERAMA_LIBRARY}")60
61if (APPLE)
62 list(APPEND LIBOVR_LIBRARIES ${IOKit} ${ApplicationServices})
63 list(APPEND LIBOVR_ARGS_LIST IOKit ApplicationServices)
64elseif (UNIX)
65 list(APPEND LIBOVR_LIBRARIES "${UDEV_LIBRARY}" "${XINERAMA_LIBRARY}")
66 list(APPEND LIBOVR_ARGS_LIST UDEV_LIBRARY XINERAMA_LIBRARY)
67elseif (WIN32)
68 list(APPEND LIBOVR_LIBRARIES ${ATL_LIBRARIES})
69 list(APPEND LIBOVR_ARGS_LIST ATL_LIBRARIES)
58endif ()70endif ()
59 71
60include(FindPackageHandleStandardArgs)72include(FindPackageHandleStandardArgs)
61if (UNIX AND NOT APPLE)
62 find_package_handle_standard_args(LIBOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARIES UDEV_LIBRARY XINERAMA_LIBRARY)
63else ()
64 find_package_handle_standard_args(LIBOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARIES)
65endif ()
66 73
67mark_as_advanced(LIBOVR_INCLUDE_DIRS LIBOVR_LIBRARIES OCULUS_SEARCH_DIRS)74find_package_handle_standard_args(LibOVR DEFAULT_MSG ${LIBOVR_ARGS_LIST})
75
76mark_as_advanced(LIBOVR_INCLUDE_DIRS LIBOVR_LIBRARIES LIBOVR_SEARCH_DIRS)
cmake/modules/FindPrioVR.cmake+1−1
@@ -19,6 +19,6 @@ if (WIN32) · 18 unmodified lines
19endif (WIN32)19endif (WIN32)
20 20
21include(FindPackageHandleStandardArgs)21include(FindPackageHandleStandardArgs)
22find_package_handle_standard_args(PRIOVR DEFAULT_MSG PRIOVR_INCLUDE_DIRS PRIOVR_LIBRARIES)22find_package_handle_standard_args(PrioVR DEFAULT_MSG PRIOVR_INCLUDE_DIRS PRIOVR_LIBRARIES)
23 23
24mark_as_advanced(PRIOVR_INCLUDE_DIRS PRIOVR_LIBRARIES)24mark_as_advanced(PRIOVR_INCLUDE_DIRS PRIOVR_LIBRARIES)
cmake/modules/FindQxmpp.cmake+4−2
@@ -26,12 +26,14 @@ find_path(QXMPP_INCLUDE_DIRS QXmppClient.h PATH_SUFFIXES include/qxmpp HINTS ${Q · 25 unmodified lines
26find_library(QXMPP_LIBRARY_RELEASE NAMES qxmpp PATH_SUFFIXES lib HINTS ${QXMPP_SEARCH_DIRS})26find_library(QXMPP_LIBRARY_RELEASE NAMES qxmpp PATH_SUFFIXES lib HINTS ${QXMPP_SEARCH_DIRS})
27find_library(QXMPP_LIBRARY_DEBUG NAMES qxmpp_d PATH_SUFFIXES lib HINTS ${QXMPP_SEARCH_DIRS})27find_library(QXMPP_LIBRARY_DEBUG NAMES qxmpp_d PATH_SUFFIXES lib HINTS ${QXMPP_SEARCH_DIRS})
28 28
29find_package(Qt5 COMPONENTS Xml REQUIRED)
30
29include(SelectLibraryConfigurations)31include(SelectLibraryConfigurations)
30select_library_configurations(QXMPP)32select_library_configurations(QXMPP)
31 33
32set(QXMPP_LIBRARIES "${QXMPP_LIBRARY}")34set(QXMPP_LIBRARIES "${QXMPP_LIBRARY}" Qt5::Xml)
33 35
34include(FindPackageHandleStandardArgs)36include(FindPackageHandleStandardArgs)
35find_package_handle_standard_args(QXMPP DEFAULT_MSG QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES)37find_package_handle_standard_args(QXmpp DEFAULT_MSG QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES QXMPP_LIBRARY)
36 38
37mark_as_advanced(QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES QXMPP_SEARCH_DIRS)39mark_as_advanced(QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES QXMPP_SEARCH_DIRS)
cmake/modules/FindRtMidi.cmake+1−1
@@ -25,6 +25,6 @@ find_path(RTMIDI_INCLUDE_DIRS RtMidi.h PATH_SUFFIXES include HINTS ${RTMIDI_SEAR · 24 unmodified lines
25find_library(RTMIDI_LIBRARIES NAMES rtmidi PATH_SUFFIXES lib HINTS ${RTMIDI_SEARCH_DIRS})25find_library(RTMIDI_LIBRARIES NAMES rtmidi PATH_SUFFIXES lib HINTS ${RTMIDI_SEARCH_DIRS})
26 26
27include(FindPackageHandleStandardArgs)27include(FindPackageHandleStandardArgs)
28find_package_handle_standard_args(RTMIDI DEFAULT_MSG RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES)28find_package_handle_standard_args(RtMidi DEFAULT_MSG RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES)
29 29
30mark_as_advanced(RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES RTMIDI_SEARCH_DIRS)30mark_as_advanced(RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES RTMIDI_SEARCH_DIRS)
cmake/modules/FindSixense.cmake+1−1
@@ -40,6 +40,6 @@ select_library_configurations(SIXENSE) · 39 unmodified lines
40set(SIXENSE_LIBRARIES "${SIXENSE_LIBRARY}")40set(SIXENSE_LIBRARIES "${SIXENSE_LIBRARY}")
41 41
42include(FindPackageHandleStandardArgs)42include(FindPackageHandleStandardArgs)
43find_package_handle_standard_args(SIXENSE DEFAULT_MSG SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES)43find_package_handle_standard_args(Sixense DEFAULT_MSG SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES)
44 44
45mark_as_advanced(SIXENSE_LIBRARIES SIXENSE_INCLUDE_DIRS SIXENSE_SEARCH_DIRS)45mark_as_advanced(SIXENSE_LIBRARIES SIXENSE_INCLUDE_DIRS SIXENSE_SEARCH_DIRS)
cmake/modules/FindVisage.cmake+18−9
@@ -32,6 +32,9 @@ if (APPLE) · 31 unmodified lines
32 find_library(VISAGE_VISION_LIBRARY NAME vsvision PATH_SUFFIXES lib HINTS ${VISAGE_SEARCH_DIRS})32 find_library(VISAGE_VISION_LIBRARY NAME vsvision PATH_SUFFIXES lib HINTS ${VISAGE_SEARCH_DIRS})
33 find_library(VISAGE_OPENCV_LIBRARY NAME OpenCV PATH_SUFFIXES dependencies/OpenCV_MacOSX/lib HINTS ${VISAGE_SEARCH_DIRS})33 find_library(VISAGE_OPENCV_LIBRARY NAME OpenCV PATH_SUFFIXES dependencies/OpenCV_MacOSX/lib HINTS ${VISAGE_SEARCH_DIRS})
34 34
35 find_library(AppKit AppKit)
36 find_library(QuartzCore QuartzCore)
37 find_library(QTKit QTKit)
35elseif (WIN32)38elseif (WIN32)
36 find_path(VISAGE_XML_INCLUDE_DIR libxml/xmlreader.h PATH_SUFFIXES dependencies/libxml2/include HINTS ${VISAGE_SEARCH_DIRS})39 find_path(VISAGE_XML_INCLUDE_DIR libxml/xmlreader.h PATH_SUFFIXES dependencies/libxml2/include HINTS ${VISAGE_SEARCH_DIRS})
37 find_path(VISAGE_OPENCV_INCLUDE_DIR opencv/cv.h PATH_SUFFIXES dependencies/OpenCV/include HINTS ${VISAGE_SEARCH_DIRS})40 find_path(VISAGE_OPENCV_INCLUDE_DIR opencv/cv.h PATH_SUFFIXES dependencies/OpenCV/include HINTS ${VISAGE_SEARCH_DIRS})
@@ -43,16 +46,22 @@ elseif (WIN32) · 5 unmodified lines
43endif ()46endif ()
44 47
45include(FindPackageHandleStandardArgs)48include(FindPackageHandleStandardArgs)
46find_package_handle_standard_args(VISAGE DEFAULT_MSG 49
47 VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR VISAGE_OPENCV_INCLUDE_DIR VISAGE_OPENCV2_INCLUDE_DIR50list(APPEND VISAGE_ARGS_LIST VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR
48 VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY51 VISAGE_OPENCV_INCLUDE_DIR VISAGE_OPENCV2_INCLUDE_DIR
49)52 VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY)
53
54if (APPLE)
55 list(APPEND VISAGE_ARGS_LIST QuartzCore AppKit QTKit)
56endif ()
57
58find_package_handle_standard_args(Visage DEFAULT_MSG ${VISAGE_ARGS_LIST})
50 59
51set(VISAGE_INCLUDE_DIRS "${VISAGE_XML_INCLUDE_DIR}" "${VISAGE_OPENCV_INCLUDE_DIR}" "${VISAGE_OPENCV2_INCLUDE_DIR}" "${VISAGE_BASE_INCLUDE_DIR}")60set(VISAGE_INCLUDE_DIRS "${VISAGE_XML_INCLUDE_DIR}" "${VISAGE_OPENCV_INCLUDE_DIR}" "${VISAGE_OPENCV2_INCLUDE_DIR}" "${VISAGE_BASE_INCLUDE_DIR}")
52set(VISAGE_LIBRARIES "${VISAGE_CORE_LIBRARY}" "${VISAGE_VISION_LIBRARY}" "${VISAGE_OPENCV_LIBRARY}")61set(VISAGE_LIBRARIES "${VISAGE_CORE_LIBRARY}" "${VISAGE_VISION_LIBRARY}" "${VISAGE_OPENCV_LIBRARY}")
53 62
54mark_as_advanced(63if (APPLE)
55 VISAGE_INCLUDE_DIRS VISAGE_LIBRARIES64 list(APPEND VISAGE_LIBRARIES ${QuartzCore} ${AppKit} ${QTKit})
56 VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR VISAGE_OPENCV_INCLUDE_DIR VISAGE_OPENCV2_INCLUDE_DIR65endif ()
57 VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY VISAGE_SEARCH_DIRS66
58)67mark_as_advanced(VISAGE_INCLUDE_DIRS VISAGE_LIBRARIES)
domain-server/CMakeLists.txt+5−35
@@ -1,24 +1,7 @@
1if (WIN32)
2 cmake_policy (SET CMP0020 NEW)
3endif (WIN32)
4
5set(TARGET_NAME domain-server)1set(TARGET_NAME domain-server)
6 2
7set(ROOT_DIR ..)3# setup the project and link required Qt modules
8set(MACRO_DIR "${ROOT_DIR}/cmake/macros")4setup_hifi_project(Network)
9
10# setup for find modules
11set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/")
12
13# set up the external glm library
14include(${MACRO_DIR}/IncludeGLM.cmake)
15include_glm(${TARGET_NAME} "${ROOT_DIR}")
16
17find_package(Qt5Network REQUIRED)
18
19include(${MACRO_DIR}/SetupHifiProject.cmake)
20
21setup_hifi_project(${TARGET_NAME} TRUE)
22 5
23# remove and then copy the files for the webserver6# remove and then copy the files for the webserver
24add_custom_command(TARGET ${TARGET_NAME} POST_BUILD7add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
@@ -29,20 +12,7 @@ add_custom_command(TARGET ${TARGET_NAME} POST_BUILD · 4 unmodified lines
29 "${PROJECT_SOURCE_DIR}/resources/web"12 "${PROJECT_SOURCE_DIR}/resources/web"
30 $<TARGET_FILE_DIR:${TARGET_NAME}>/resources/web)13 $<TARGET_FILE_DIR:${TARGET_NAME}>/resources/web)
31 14
32# link the shared hifi library15# link the shared hifi libraries
33include(${MACRO_DIR}/LinkHifiLibrary.cmake)16link_hifi_libraries(embedded-webserver networking shared)
34link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
35link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
36link_hifi_library(embedded-webserver ${TARGET_NAME} "${ROOT_DIR}")
37
38IF (WIN32)
39 target_link_libraries(${TARGET_NAME} Winmm Ws2_32)
40ENDIF(WIN32)
41
42# link QtNetwork
43target_link_libraries(${TARGET_NAME} Qt5::Network)
44 17
45# add a definition for ssize_t so that windows doesn't bail18link_shared_dependencies()
46if (WIN32)
47 add_definitions(-Dssize_t=long)
48endif ()
domain-server/resources/web/settings/describe.json+6−0
@@ -21,6 +21,12 @@ · 20 unmodified lines
21 "placeholder": "10",21 "placeholder": "10",
22 "default": "10"22 "default": "10"
23 },23 },
24 "H-print-stream-stats": {
25 "type": "checkbox",
26 "label": "Print Stream Stats:",
27 "help": "If enabled, audio upstream and downstream stats of each agent will be printed each second to stdout",
28 "default": false
29 },
24 "D-unattenuated-zone": {30 "D-unattenuated-zone": {
25 "label": "Unattenuated Zone",31 "label": "Unattenuated Zone",
26 "help": "Boxes for source and listener (corner x, corner y, corner z, size x, size y, size z, corner x, corner y, corner z, size x, size y, size z)",32 "help": "Boxes for source and listener (corner x, corner y, corner z, size x, size y, size z, corner x, corner y, corner z, size x, size y, size z)",
examples/clipboardExample.js+8−1
@@ -24,6 +24,7 @@ function setupMenus() { · 23 unmodified lines
24 Menu.removeMenuItem("Edit", "Paste");24 Menu.removeMenuItem("Edit", "Paste");
25 Menu.removeMenuItem("Edit", "Delete");25 Menu.removeMenuItem("Edit", "Delete");
26 Menu.removeMenuItem("Edit", "Nudge");26 Menu.removeMenuItem("Edit", "Nudge");
27 Menu.removeMenuItem("Edit", "Replace from File");
27 Menu.removeMenuItem("File", "Export Voxels");28 Menu.removeMenuItem("File", "Export Voxels");
28 Menu.removeMenuItem("File", "Import Voxels");29 Menu.removeMenuItem("File", "Import Voxels");
29 30
@@ -32,6 +33,7 @@ function setupMenus() { · 2 unmodified lines
32 Menu.addMenuItem({ menuName: "Edit", menuItemName: "Copy", shortcutKey: "CTRL+C", afterItem: "Cut" });33 Menu.addMenuItem({ menuName: "Edit", menuItemName: "Copy", shortcutKey: "CTRL+C", afterItem: "Cut" });
33 Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste", shortcutKey: "CTRL+V", afterItem: "Copy" });34 Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste", shortcutKey: "CTRL+V", afterItem: "Copy" });
34 Menu.addMenuItem({ menuName: "Edit", menuItemName: "Nudge", shortcutKey: "CTRL+N", afterItem: "Paste" });35 Menu.addMenuItem({ menuName: "Edit", menuItemName: "Nudge", shortcutKey: "CTRL+N", afterItem: "Paste" });
36 Menu.addMenuItem({ menuName: "Edit", menuItemName: "Replace from File", shortcutKey: "CTRL+R", afterItem: "Nudge" });
35 Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete", shortcutKeyEvent: { text: "backspace" }, afterItem: "Nudge" });37 Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete", shortcutKeyEvent: { text: "backspace" }, afterItem: "Nudge" });
36 Menu.addMenuItem({ menuName: "File", menuItemName: "Export Voxels", shortcutKey: "CTRL+E", afterItem: "Voxels" });38 Menu.addMenuItem({ menuName: "File", menuItemName: "Export Voxels", shortcutKey: "CTRL+E", afterItem: "Voxels" });
37 Menu.addMenuItem({ menuName: "File", menuItemName: "Import Voxels", shortcutKey: "CTRL+I", afterItem: "Export Voxels" });39 Menu.addMenuItem({ menuName: "File", menuItemName: "Import Voxels", shortcutKey: "CTRL+I", afterItem: "Export Voxels" });
@@ -60,7 +62,6 @@ function menuItemEvent(menuItem) { · 22 unmodified lines
60 print("deleting...");62 print("deleting...");
61 Clipboard.deleteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);63 Clipboard.deleteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);
62 }64 }
63
64 if (menuItem == "Export Voxels") {65 if (menuItem == "Export Voxels") {
65 print("export");66 print("export");
66 Clipboard.exportVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);67 Clipboard.exportVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s);
@@ -73,6 +74,12 @@ function menuItemEvent(menuItem) { · 6 unmodified lines
73 print("nudge");74 print("nudge");
74 Clipboard.nudgeVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s, { x: -1, y: 0, z: 0 });75 Clipboard.nudgeVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s, { x: -1, y: 0, z: 0 });
75 }76 }
77 if (menuItem == "Replace from File") {
78 var filename = Window.browse("Select file to load replacement", "", "Voxel Files (*.png *.svo *.schematic)");
79 if (filename) {
80 Clipboard.importVoxel(filename, selectedVoxel);
81 }
82 }
76}83}
77 84
78var selectCube = Overlays.addOverlay("cube", {85var selectCube = Overlays.addOverlay("cube", {
interface/CMakeLists.txt+26−80
@@ -1,18 +1,13 @@
1set(ROOT_DIR ..)
2set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
3
4set(TARGET_NAME interface)1set(TARGET_NAME interface)
5project(${TARGET_NAME})2project(${TARGET_NAME})
6 3
7# setup for find modules
8set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/")
9
10# set a default root dir for each of our optional externals if it was not passed4# set a default root dir for each of our optional externals if it was not passed
11set(OPTIONAL_EXTERNALS "faceplus" "faceshift" "oculus" "priovr" "sixense" "visage" "leapmotion" "rtmidi" "qxmpp")5set(OPTIONAL_EXTERNALS "Faceplus" "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp")
12foreach(EXTERNAL ${OPTIONAL_EXTERNALS})6foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
13 string(TOUPPER ${EXTERNAL} UPPER_EXTERNAL)7 string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE)
14 if (NOT ${UPPER_EXTERNAL}_ROOT_DIR)8 if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR)
15 set(${UPPER_EXTERNAL}_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/${EXTERNAL}")9 string(TOLOWER ${EXTERNAL} ${EXTERNAL}_LOWERCASE)
10 set(${${EXTERNAL}_UPPERCASE}_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/${${EXTERNAL}_LOWERCASE}")
16 endif ()11 endif ()
17endforeach()12endforeach()
18 13
@@ -38,8 +33,7 @@ elseif (WIN32) · 19 unmodified lines
38endif ()33endif ()
39 34
40# set up the external glm library35# set up the external glm library
41include("${MACRO_DIR}/IncludeGLM.cmake")36include_glm()
42include_glm(${TARGET_NAME} "${ROOT_DIR}")
43 37
44# create the InterfaceConfig.h file based on GL_HEADERS above38# create the InterfaceConfig.h file based on GL_HEADERS above
45configure_file(InterfaceConfig.h.in "${PROJECT_BINARY_DIR}/includes/InterfaceConfig.h")39configure_file(InterfaceConfig.h.in "${PROJECT_BINARY_DIR}/includes/InterfaceConfig.h")
@@ -52,7 +46,7 @@ foreach(SUBDIR avatar devices renderer ui starfield location scripting voxels pa · 6 unmodified lines
52 set(INTERFACE_SRCS ${INTERFACE_SRCS} "${SUBDIR_SRCS}")46 set(INTERFACE_SRCS ${INTERFACE_SRCS} "${SUBDIR_SRCS}")
53endforeach(SUBDIR)47endforeach(SUBDIR)
54 48
55find_package(Qt5 COMPONENTS Core Gui Multimedia Network OpenGL Script Svg WebKit WebKitWidgets Xml UiTools)49find_package(Qt5 COMPONENTS Gui Multimedia Network OpenGL Script Svg WebKitWidgets)
56 50
57# grab the ui files in resources/ui51# grab the ui files in resources/ui
58file (GLOB_RECURSE QT_UI_FILES ui/*.ui)52file (GLOB_RECURSE QT_UI_FILES ui/*.ui)
@@ -97,60 +91,36 @@ endif() · 38 unmodified lines
97# create the executable, make it a bundle on OS X91# create the executable, make it a bundle on OS X
98add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM})92add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM})
99 93
100# link in the hifi shared library
101include(${MACRO_DIR}/LinkHifiLibrary.cmake)
102
103# link required hifi libraries94# link required hifi libraries
104link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")95link_hifi_libraries(shared octree voxels fbx metavoxels networking particles entities avatars audio animation script-engine)
105link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}")
106link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}")
107link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}")
108link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}")
109link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
110link_hifi_library(particles ${TARGET_NAME} "${ROOT_DIR}")
111link_hifi_library(entities ${TARGET_NAME} "${ROOT_DIR}")
112link_hifi_library(avatars ${TARGET_NAME} "${ROOT_DIR}")
113link_hifi_library(audio ${TARGET_NAME} "${ROOT_DIR}")
114link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}")
115link_hifi_library(script-engine ${TARGET_NAME} "${ROOT_DIR}")
116 96
117# find any optional and required libraries97# find any optional and required libraries
118find_package(Faceplus)98find_package(ZLIB REQUIRED)
119find_package(Faceshift)
120find_package(LibOVR)
121find_package(PrioVR)
122find_package(SDL)
123find_package(Sixense)
124find_package(Visage)
125find_package(LeapMotion)
126find_package(ZLIB)
127find_package(Qxmpp)
128find_package(RtMidi)
129find_package(OpenSSL REQUIRED)99find_package(OpenSSL REQUIRED)
130 100
131# perform standard include and linking for found externals101# perform standard include and linking for found externals
132foreach(EXTERNAL ${OPTIONAL_EXTERNALS})102foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
133 string(TOUPPER ${EXTERNAL} UPPER_EXTERNAL)
134 103
135 if (${UPPER_EXTERNAL} MATCHES "OCULUS")104 if (${${EXTERNAL}_UPPERCASE}_REQUIRED)
136 # the oculus directory is named OCULUS and not LIBOVR so hack to fix that here105 find_package(${EXTERNAL} REQUIRED)
137 set(UPPER_EXTERNAL "LIBOVR")106 else ()
107 find_package(${EXTERNAL})
138 endif ()108 endif ()
139 109
140 if (${UPPER_EXTERNAL}_FOUND AND NOT DISABLE_${UPPER_EXTERNAL})110 if (${${EXTERNAL}_UPPERCASE}_FOUND AND NOT DISABLE_${${EXTERNAL}_UPPERCASE})
141 add_definitions(-DHAVE_${UPPER_EXTERNAL})111 add_definitions(-DHAVE_${${EXTERNAL}_UPPERCASE})
142 112
143 # include the library directories (ignoring warnings)113 # include the library directories (ignoring warnings)
144 include_directories(SYSTEM ${${UPPER_EXTERNAL}_INCLUDE_DIRS})114 include_directories(SYSTEM ${${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS})
145 115
146 # perform the system include hack for OS X to ignore warnings116 # perform the system include hack for OS X to ignore warnings
147 if (APPLE)117 if (APPLE)
148 foreach(EXTERNAL_INCLUDE_DIR ${${UPPER_EXTERNAL}_INCLUDE_DIRS})118 foreach(EXTERNAL_INCLUDE_DIR ${${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS})
149 SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${EXTERNAL_INCLUDE_DIR}")119 SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${EXTERNAL_INCLUDE_DIR}")
150 endforeach()120 endforeach()
151 endif ()121 endif ()
152 122
153 target_link_libraries(${TARGET_NAME} ${${UPPER_EXTERNAL}_LIBRARIES})123 target_link_libraries(${TARGET_NAME} ${${${EXTERNAL}_UPPERCASE}_LIBRARIES})
154 124
155 endif ()125 endif ()
156endforeach()126endforeach()
@@ -179,17 +149,11 @@ endif () · 22 unmodified lines
179 149
180# include headers for interface and InterfaceConfig.150# include headers for interface and InterfaceConfig.
181include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes")151include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes")
182 152include_directories("${OPENSSL_INCLUDE_DIR}")
183# include external library headers
184# use system flag so warnings are supressed
185include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
186 153
187target_link_libraries(154target_link_libraries(
188 ${TARGET_NAME}155 ${TARGET_NAME} ${ZLIB_LIBRARIES} ${OPENSSL_LIBRARIES}
189 "${ZLIB_LIBRARIES}"156 Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL Qt5::Script Qt5::Svg Qt5::WebKitWidgets
190 ${OPENSSL_LIBRARIES}
191 Qt5::Core Qt5::Gui Qt5::Multimedia Qt5::Network Qt5::OpenGL
192 Qt5::Script Qt5::Svg Qt5::WebKit Qt5::WebKitWidgets Qt5::Xml Qt5::UiTools
193)157)
194 158
195# assume we are using a Qt build without bearer management159# assume we are using a Qt build without bearer management
@@ -197,30 +161,12 @@ add_definitions(-DQT_NO_BEARERMANAGEMENT) · 1 unmodified line
197 161
198if (APPLE)162if (APPLE)
199 # link in required OS X frameworks and include the right GL headers163 # link in required OS X frameworks and include the right GL headers
200 find_library(AppKit AppKit)
201 find_library(CoreAudio CoreAudio)164 find_library(CoreAudio CoreAudio)
202 find_library(CoreServices CoreServices)165 find_library(CoreFoundation CoreFoundation)
203 find_library(Carbon Carbon)
204 find_library(Foundation Foundation)
205 find_library(GLUT GLUT)166 find_library(GLUT GLUT)
206 find_library(OpenGL OpenGL)167 find_library(OpenGL OpenGL)
207 find_library(IOKit IOKit)
208 find_library(QTKit QTKit)
209 find_library(QuartzCore QuartzCore)
210 168
211 target_link_libraries(169 target_link_libraries(${TARGET_NAME} ${CoreAudio} ${CoreFoundation} ${GLUT} ${OpenGL})
212 ${TARGET_NAME}
213 ${AppKit}
214 ${CoreAudio}
215 ${CoreServices}
216 ${Carbon}
217 ${Foundation}
218 ${GLUT}
219 ${OpenGL}
220 ${IOKit}
221 ${QTKit}
222 ${QuartzCore}
223 )
224 170
225 # install command for OS X bundle171 # install command for OS X bundle
226 INSTALL(TARGETS ${TARGET_NAME}172 INSTALL(TARGETS ${TARGET_NAME}
@@ -254,9 +200,9 @@ else (APPLE) · 27 unmodified lines
254 # we're using static GLEW, so define GLEW_STATIC200 # we're using static GLEW, so define GLEW_STATIC
255 add_definitions(-DGLEW_STATIC)201 add_definitions(-DGLEW_STATIC)
256 202
257 # add a definition for ssize_t so that windows doesn't bail
258 add_definitions(-Dssize_t=long)
259
260 target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" wsock32.lib opengl32.lib)203 target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" wsock32.lib opengl32.lib)
261 endif()204 endif()
262endif (APPLE)205endif (APPLE)
206
207# link any dependencies bubbled up from our linked dependencies
208link_shared_dependencies()
interface/external/libovr/readme.txtrenamed from interface/external/oculus/readme.txt+0−0

File renamed without changes.

interface/interface_en.ts+6−6
@@ -245,28 +245,28 @@ · 244 unmodified lines
245<context>245<context>
246 <name>QObject</name>246 <name>QObject</name>
247 <message>247 <message>
248 <location filename="src/ui/ImportDialog.cpp" line="22"/>248 <location filename="src/ui/VoxelImportDialog.cpp" line="22"/>
249 <location filename="src/ui/ImportDialog.cpp" line="23"/>249 <location filename="src/ui/VoxelImportDialog.cpp" line="23"/>
250 <source>Import Voxels</source>250 <source>Import Voxels</source>
251 <translation type="unfinished"></translation>251 <translation type="unfinished"></translation>
252 </message>252 </message>
253 <message>253 <message>
254 <location filename="src/ui/ImportDialog.cpp" line="24"/>254 <location filename="src/ui/VoxelImportDialog.cpp" line="24"/>
255 <source>Loading ...</source>255 <source>Loading ...</source>
256 <translation type="unfinished"></translation>256 <translation type="unfinished"></translation>
257 </message>257 </message>
258 <message>258 <message>
259 <location filename="src/ui/ImportDialog.cpp" line="25"/>259 <location filename="src/ui/VoxelImportDialog.cpp" line="25"/>
260 <source>Place voxels</source>260 <source>Place voxels</source>
261 <translation type="unfinished"></translation>261 <translation type="unfinished"></translation>
262 </message>262 </message>
263 <message>263 <message>
264 <location filename="src/ui/ImportDialog.cpp" line="26"/>264 <location filename="src/ui/VoxelImportDialog.cpp" line="26"/>
265 <source>&lt;b&gt;Import&lt;/b&gt; %1 as voxels</source>265 <source>&lt;b&gt;Import&lt;/b&gt; %1 as voxels</source>
266 <translation type="unfinished"></translation>266 <translation type="unfinished"></translation>
267 </message>267 </message>
268 <message>268 <message>
269 <location filename="src/ui/ImportDialog.cpp" line="27"/>269 <location filename="src/ui/VoxelImportDialog.cpp" line="27"/>
270 <source>Cancel</source>270 <source>Cancel</source>
271 <translation type="unfinished"></translation>271 <translation type="unfinished"></translation>
272 </message>272 </message>
interface/resources/shaders/metavoxel_heightfield.vert+14−4
@@ -17,6 +17,12 @@ uniform sampler2D heightMap; · 16 unmodified lines
17// the distance between height points in texture space17// the distance between height points in texture space
18uniform float heightScale;18uniform float heightScale;
19 19
20// the scale between height and color textures
21uniform float colorScale;
22
23// the interpolated position
24varying vec4 position;
25
20// the interpolated normal26// the interpolated normal
21varying vec4 normal;27varying vec4 normal;
22 28
@@ -29,13 +35,17 @@ void main(void) { · 6 unmodified lines
29 texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r;35 texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r;
30 normal = normalize(gl_ModelViewMatrix * vec4(deltaX, heightScale, deltaZ, 0.0));36 normal = normalize(gl_ModelViewMatrix * vec4(deltaX, heightScale, deltaZ, 0.0));
31 37
32 // pass along the texture coordinates
33 gl_TexCoord[0] = gl_MultiTexCoord0;
34
35 // add the height to the position38 // add the height to the position
36 float height = texture2D(heightMap, heightCoord).r;39 float height = texture2D(heightMap, heightCoord).r;
37 gl_Position = gl_ModelViewProjectionMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0));40 position = gl_ModelViewMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0));
41 gl_Position = gl_ProjectionMatrix * position;
38 42
39 // the zero height should be invisible43 // the zero height should be invisible
40 gl_FrontColor = vec4(1.0, 1.0, 1.0, step(height, 0.0));44 gl_FrontColor = vec4(1.0, 1.0, 1.0, step(height, 0.0));
45
46 // pass along the scaled/offset texture coordinates
47 gl_TexCoord[0] = (gl_MultiTexCoord0 - vec4(heightScale, heightScale, 0.0, 0.0)) * colorScale;
48
49 // and the shadow texture coordinates
50 gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[0], position), dot(gl_EyePlaneT[0], position), dot(gl_EyePlaneR[0], position), 1.0);
41}51}
interface/resources/shaders/metavoxel_heightfield_cascaded_shadow_map.frag+48−0
@@ -0,0 +1,48 @@
1#version 120
2
3//
4// metavoxel_heightfield.frag
5// fragment shader
6//
7// Created by Andrzej Kapolka on 7/28/14.
8// Copyright 2014 High Fidelity, Inc.
9//
10// Distributed under the Apache License, Version 2.0.
11// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
12//
13
14// the diffuse texture
15uniform sampler2D diffuseMap;
16
17// the shadow texture
18uniform sampler2DShadow shadowMap;
19
20// the distances to the cascade sections
21uniform vec3 shadowDistances;
22
23// the inverse of the size of the shadow map
24const float shadowScale = 1.0 / 2048.0;
25
26// the interpolated position
27varying vec4 position;
28
29// the interpolated normal
30varying vec4 normal;
31
32void main(void) {
33 // compute the index of the cascade to use and the corresponding texture coordinates
34 int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0)));
35 vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position),
36 dot(gl_EyePlaneR[shadowIndex], position));
37
38 // compute the base color based on OpenGL lighting model
39 float diffuse = dot(normalize(normal), gl_LightSource[0].position);
40 float facingLight = step(0.0, diffuse) * 0.25 *
41 (shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, -shadowScale, 0.0)).r +
42 shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, shadowScale, 0.0)).r +
43 shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, -shadowScale, 0.0)).r +
44 shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, shadowScale, 0.0)).r);
45 vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
46 gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
47 gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st);
48}
interface/resources/shaders/metavoxel_heightfield_cursor.frag+32−0
@@ -0,0 +1,32 @@
1#version 120
2
3//
4// metavoxel_heightfield_cursor.frag
5// fragment shader
6//
7// Created by Andrzej Kapolka on 8/7/14.
8// Copyright 2014 High Fidelity, Inc.
9//
10// Distributed under the Apache License, Version 2.0.
11// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
12//
13
14// the inner radius of the outline, squared
15const float SQUARED_OUTLINE_INNER_RADIUS = 0.81;
16
17// the outer radius of the outline, squared
18const float SQUARED_OUTLINE_OUTER_RADIUS = 1.0;
19
20// the inner radius of the inset, squared
21const float SQUARED_INSET_INNER_RADIUS = 0.855625;
22
23// the outer radius of the inset, squared
24const float SQUARED_INSET_OUTER_RADIUS = 0.950625;
25
26void main(void) {
27 // use the distance to compute the ring color, then multiply it by the varying color
28 float squaredDistance = dot(gl_TexCoord[0].st, gl_TexCoord[0].st);
29 float alpha = step(SQUARED_OUTLINE_INNER_RADIUS, squaredDistance) * step(squaredDistance, SQUARED_OUTLINE_OUTER_RADIUS);
30 float white = step(SQUARED_INSET_INNER_RADIUS, squaredDistance) * step(squaredDistance, SQUARED_INSET_OUTER_RADIUS);
31 gl_FragColor = gl_Color * vec4(white, white, white, alpha);
32}
interface/resources/shaders/metavoxel_heightfield_cursor.vert+28−0
@@ -0,0 +1,28 @@
1#version 120
2
3//
4// metavoxel_heighfield_cursor.vert
5// vertex shader
6//
7// Created by Andrzej Kapolka on 8/7/14.
8// Copyright 2014 High Fidelity, Inc.
9//
10// Distributed under the Apache License, Version 2.0.
11// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
12//
13
14// the height texture
15uniform sampler2D heightMap;
16
17void main(void) {
18 // compute the view space coordinates
19 float height = texture2D(heightMap, gl_MultiTexCoord0.st).r;
20 vec4 viewPosition = gl_ModelViewMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0));
21 gl_Position = gl_ProjectionMatrix * viewPosition;
22
23 // generate the texture coordinates from the view position
24 gl_TexCoord[0] = vec4(dot(viewPosition, gl_EyePlaneS[4]), dot(viewPosition, gl_EyePlaneT[4]), 0.0, 1.0);
25
26 // the zero height should be invisible
27 gl_FrontColor = vec4(1.0, 1.0, 1.0, 1.0 - step(height, 0.0));
28}
interface/resources/shaders/metavoxel_heightfield_shadow_map.frag+37−0
@@ -0,0 +1,37 @@
1#version 120
2
3//
4// metavoxel_heightfield.frag
5// fragment shader
6//
7// Created by Andrzej Kapolka on 7/28/14.
8// Copyright 2014 High Fidelity, Inc.
9//
10// Distributed under the Apache License, Version 2.0.
11// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
12//
13
14// the diffuse texture
15uniform sampler2D diffuseMap;
16
17// the shadow texture
18uniform sampler2DShadow shadowMap;
19
20// the inverse of the size of the shadow map
21const float shadowScale = 1.0 / 2048.0;
22
23// the interpolated normal
24varying vec4 normal;
25
26void main(void) {
27 // compute the base color based on OpenGL lighting model
28 float diffuse = dot(normalize(normal), gl_LightSource[0].position);
29 float facingLight = step(0.0, diffuse) * 0.25 *
30 (shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, -shadowScale, 0.0)).r +
31 shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, shadowScale, 0.0)).r +
32 shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, -shadowScale, 0.0)).r +
33 shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, shadowScale, 0.0)).r);
34 vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
35 gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
36 gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st);
37}
interface/src/Application.cpp+27−15
@@ -137,7 +137,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : · 136 unmodified lines
137 _frameCount(0),137 _frameCount(0),
138 _fps(60.0f),138 _fps(60.0f),
139 _justStarted(true),139 _justStarted(true),
140 _voxelImporter(NULL),140 _voxelImportDialog(NULL),
141 _voxelImporter(),
141 _importSucceded(false),142 _importSucceded(false),
142 _sharedVoxelSystem(TREE_SCALE, DEFAULT_MAX_VOXELS_PER_SYSTEM, &_clipboard),143 _sharedVoxelSystem(TREE_SCALE, DEFAULT_MAX_VOXELS_PER_SYSTEM, &_clipboard),
143 _entityClipboardRenderer(),144 _entityClipboardRenderer(),
@@ -242,6 +243,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : · 98 unmodified lines
242 243
243 connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&)));244 connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&)));
244 connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&)));245 connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&)));
246 connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(updateWindowTitle()));
247 connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle()));
245 connect(&domainHandler, &DomainHandler::settingsReceived, this, &Application::domainSettingsReceived);248 connect(&domainHandler, &DomainHandler::settingsReceived, this, &Application::domainSettingsReceived);
246 249
247 // hookup VoxelEditSender to PaymentManager so we can pay for octree edits250 // hookup VoxelEditSender to PaymentManager so we can pay for octree edits
@@ -430,7 +433,7 @@ Application::~Application() { · 182 unmodified lines
430 delete idleTimer;433 delete idleTimer;
431 434
432 _sharedVoxelSystem.changeTree(new VoxelTree);435 _sharedVoxelSystem.changeTree(new VoxelTree);
433 delete _voxelImporter;436 delete _voxelImportDialog;
434 437
435 // let the avatar mixer know we're out438 // let the avatar mixer know we're out
436 MyAvatar::sendKillAvatar();439 MyAvatar::sendKillAvatar();
@@ -465,8 +468,8 @@ void Application::saveSettings() { · 28 unmodified lines
465 Menu::getInstance()->saveSettings();468 Menu::getInstance()->saveSettings();
466 _rearMirrorTools->saveSettings(_settings);469 _rearMirrorTools->saveSettings(_settings);
467 470
468 if (_voxelImporter) {471 if (_voxelImportDialog) {
469 _voxelImporter->saveSettings(_settings);472 _voxelImportDialog->saveSettings(_settings);
470 }473 }
471 _settings->sync();474 _settings->sync();
472 _numChangedSettings = 0;475 _numChangedSettings = 0;
@@ -599,7 +602,7 @@ void Application::paintGL() { · 126 unmodified lines
599 602
600 if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {603 if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
601 _myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay604 _myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay
602 _myCamera.setTargetPosition(_myAvatar->getHead()->getFilteredEyePosition());605 _myCamera.setTargetPosition(_myAvatar->getHead()->getEyePosition());
603 _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation());606 _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation());
604 607
605 } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {608 } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
@@ -621,7 +624,7 @@ void Application::paintGL() { · 15 unmodified lines
621 _myCamera.setTargetPosition(_myAvatar->getHead()->getEyePosition() + glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0));624 _myCamera.setTargetPosition(_myAvatar->getHead()->getEyePosition() + glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0));
622 } else {625 } else {
623 _myCamera.setTightness(0.0f);626 _myCamera.setTightness(0.0f);
624 glm::vec3 eyePosition = _myAvatar->getHead()->getFilteredEyePosition();627 glm::vec3 eyePosition = _myAvatar->getHead()->getEyePosition();
625 float headHeight = eyePosition.y - _myAvatar->getPosition().y;628 float headHeight = eyePosition.y - _myAvatar->getPosition().y;
626 _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);629 _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
627 _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight + (_raiseMirror * _myAvatar->getScale()), 0));630 _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight + (_raiseMirror * _myAvatar->getScale()), 0));
@@ -814,9 +817,8 @@ bool Application::event(QEvent* event) { · 186 unmodified lines
814 QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event);817 QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event);
815 bool isHifiSchemeURL = !fileEvent->url().isEmpty() && fileEvent->url().toLocalFile().startsWith(CUSTOM_URL_SCHEME);818 bool isHifiSchemeURL = !fileEvent->url().isEmpty() && fileEvent->url().toLocalFile().startsWith(CUSTOM_URL_SCHEME);
816 if (isHifiSchemeURL) {819 if (isHifiSchemeURL) {
817 Menu::getInstance()->goTo(fileEvent->url().toString());820 Menu::getInstance()->goToURL(fileEvent->url().toLocalFile());
818 }821 }
819
820 return false;822 return false;
821 }823 }
822 return QApplication::event(event);824 return QApplication::event(event);
@@ -1440,6 +1442,15 @@ void Application::setEnable3DTVMode(bool enable3DTVMode) { · 617 unmodified lines
1440}1442}
1441 1443
1442void Application::setEnableVRMode(bool enableVRMode) {1444void Application::setEnableVRMode(bool enableVRMode) {
1445 if (enableVRMode) {
1446 if (!OculusManager::isConnected()) {
1447 // attempt to reconnect the Oculus manager - it's possible this was a workaround
1448 // for the sixense crash
1449 OculusManager::disconnect();
1450 OculusManager::connect();
1451 }
1452 }
1453
1443 resizeGL(_glWidget->width(), _glWidget->height());1454 resizeGL(_glWidget->width(), _glWidget->height());
1444}1455}
1445 1456
@@ -1599,17 +1610,17 @@ void Application::exportVoxels(const VoxelDetail& sourceVoxel) { · 153 unmodified lines
1599void Application::importVoxels() {1610void Application::importVoxels() {
1600 _importSucceded = false;1611 _importSucceded = false;
1601 1612
1602 if (!_voxelImporter) {1613 if (!_voxelImportDialog) {
1603 _voxelImporter = new VoxelImporter(_window);1614 _voxelImportDialog = new VoxelImportDialog(_window);
1604 _voxelImporter->loadSettings(_settings);1615 _voxelImportDialog->loadSettings(_settings);
1605 }1616 }
1606 1617
1607 if (!_voxelImporter->exec()) {1618 if (!_voxelImportDialog->exec()) {
1608 qDebug() << "Import succeeded." << endl;1619 qDebug() << "Import succeeded." << endl;
1609 _importSucceded = true;1620 _importSucceded = true;
1610 } else {1621 } else {
1611 qDebug() << "Import failed." << endl;1622 qDebug() << "Import failed." << endl;
1612 if (_sharedVoxelSystem.getTree() == _voxelImporter->getVoxelTree()) {1623 if (_sharedVoxelSystem.getTree() == _voxelImporter.getVoxelTree()) {
1613 _sharedVoxelSystem.killLocalVoxels();1624 _sharedVoxelSystem.killLocalVoxels();
1614 _sharedVoxelSystem.changeTree(&_clipboard);1625 _sharedVoxelSystem.changeTree(&_clipboard);
1615 }1626 }
@@ -1724,7 +1735,7 @@ void Application::init() { · 108 unmodified lines
1724 // Cleanup of the original shared tree1735 // Cleanup of the original shared tree
1725 _sharedVoxelSystem.init();1736 _sharedVoxelSystem.init();
1726 1737
1727 _voxelImporter = new VoxelImporter(_window);1738 _voxelImportDialog = new VoxelImportDialog(_window);
1728 1739
1729 _environment.init();1740 _environment.init();
1730 1741
@@ -3322,9 +3333,10 @@ void Application::updateWindowTitle(){ · 1591 unmodified lines
3322 QString buildVersion = " (build " + applicationVersion() + ")";3333 QString buildVersion = " (build " + applicationVersion() + ")";
3323 NodeList* nodeList = NodeList::getInstance();3334 NodeList* nodeList = NodeList::getInstance();
3324 3335
3336 QString connectionStatus = nodeList->getDomainHandler().isConnected() ? "" : " (NOT CONNECTED) ";
3325 QString username = AccountManager::getInstance().getAccountInfo().getUsername();3337 QString username = AccountManager::getInstance().getAccountInfo().getUsername();
3326 QString title = QString() + (!username.isEmpty() ? username + " @ " : QString())3338 QString title = QString() + (!username.isEmpty() ? username + " @ " : QString())
3327 + nodeList->getDomainHandler().getHostname() + buildVersion;3339 + nodeList->getDomainHandler().getHostname() + connectionStatus + buildVersion;
3328 3340
3329 AccountManager& accountManager = AccountManager::getInstance();3341 AccountManager& accountManager = AccountManager::getInstance();
3330 if (accountManager.getAccountInfo().hasBalance()) {3342 if (accountManager.getAccountInfo().hasBalance()) {
interface/src/Application.h+4−1
@@ -87,6 +87,7 @@ · 86 unmodified lines
87#include "ui/overlays/Overlays.h"87#include "ui/overlays/Overlays.h"
88#include "ui/ApplicationOverlay.h"88#include "ui/ApplicationOverlay.h"
89#include "ui/RunningScriptsWidget.h"89#include "ui/RunningScriptsWidget.h"
90#include "ui/VoxelImportDialog.h"
90#include "voxels/VoxelFade.h"91#include "voxels/VoxelFade.h"
91#include "voxels/VoxelHideShowThread.h"92#include "voxels/VoxelHideShowThread.h"
92#include "voxels/VoxelImporter.h"93#include "voxels/VoxelImporter.h"
@@ -193,6 +194,7 @@ public: · 100 unmodified lines
193 Camera* getCamera() { return &_myCamera; }194 Camera* getCamera() { return &_myCamera; }
194 ViewFrustum* getViewFrustum() { return &_viewFrustum; }195 ViewFrustum* getViewFrustum() { return &_viewFrustum; }
195 ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; }196 ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; }
197 VoxelImporter* getVoxelImporter() { return &_voxelImporter; }
196 VoxelSystem* getVoxels() { return &_voxels; }198 VoxelSystem* getVoxels() { return &_voxels; }
197 VoxelTree* getVoxelTree() { return _voxels.getTree(); }199 VoxelTree* getVoxelTree() { return _voxels.getTree(); }
198 const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; }200 const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; }
@@ -463,7 +465,8 @@ private: · 264 unmodified lines
463 465
464 VoxelSystem _voxels;466 VoxelSystem _voxels;
465 VoxelTree _clipboard; // if I copy/paste467 VoxelTree _clipboard; // if I copy/paste
466 VoxelImporter* _voxelImporter;468 VoxelImportDialog* _voxelImportDialog;
469 VoxelImporter _voxelImporter;
467 bool _importSucceded;470 bool _importSucceded;
468 VoxelSystem _sharedVoxelSystem;471 VoxelSystem _sharedVoxelSystem;
469 ViewFrustum _sharedVoxelSystemViewFrustum;472 ViewFrustum _sharedVoxelSystemViewFrustum;
interface/src/Audio.cpp+42−2
@@ -56,7 +56,6 @@ static const int MUTE_ICON_SIZE = 24; · 55 unmodified lines
56 56
57static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 100;57static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 100;
58 58
59
60Audio::Audio(QObject* parent) :59Audio::Audio(QObject* parent) :
61 AbstractAudioInterface(parent),60 AbstractAudioInterface(parent),
62 _audioInput(NULL),61 _audioInput(NULL),
@@ -83,6 +82,7 @@ Audio::Audio(QObject* parent) : · 20 unmodified lines
83 _noiseGateSampleCounter(0),82 _noiseGateSampleCounter(0),
84 _noiseGateOpen(false),83 _noiseGateOpen(false),
85 _noiseGateEnabled(true),84 _noiseGateEnabled(true),
85 _peqEnabled(false),
86 _toneInjectionEnabled(false),86 _toneInjectionEnabled(false),
87 _noiseGateFramesToClose(0),87 _noiseGateFramesToClose(0),
88 _totalInputAudioSamples(0),88 _totalInputAudioSamples(0),
@@ -132,6 +132,7 @@ void Audio::init(QGLWidget *parent) { · 43 unmodified lines
132void Audio::reset() {132void Audio::reset() {
133 _receivedAudioStream.reset();133 _receivedAudioStream.reset();
134 resetStats();134 resetStats();
135 _peq.reset();
135}136}
136 137
137void Audio::resetStats() {138void Audio::resetStats() {
@@ -418,9 +419,15 @@ void Audio::start() { · 280 unmodified lines
418 if (!outputFormatSupported) {419 if (!outputFormatSupported) {
419 qDebug() << "Unable to set up audio output because of a problem with output format.";420 qDebug() << "Unable to set up audio output because of a problem with output format.";
420 }421 }
422
423 _peq.initialize( _inputFormat.sampleRate(), _audioInput->bufferSize() );
424
421}425}
422 426
423void Audio::stop() {427void Audio::stop() {
428
429 _peq.finalize();
430
424 // "switch" to invalid devices in order to shut down the state431 // "switch" to invalid devices in order to shut down the state
425 switchInputToAudioDevice(QAudioDeviceInfo());432 switchInputToAudioDevice(QAudioDeviceInfo());
426 switchOutputToAudioDevice(QAudioDeviceInfo());433 switchOutputToAudioDevice(QAudioDeviceInfo());
@@ -462,7 +469,15 @@ void Audio::handleAudioInput() { · 35 unmodified lines
462 int inputSamplesRequired = (int)((float)NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * inputToNetworkInputRatio);469 int inputSamplesRequired = (int)((float)NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * inputToNetworkInputRatio);
463 470
464 QByteArray inputByteArray = _inputDevice->readAll();471 QByteArray inputByteArray = _inputDevice->readAll();
465 472
473 if (_peqEnabled && !_muted) {
474 // we wish to pre-filter our captured input, prior to loopback
475
476 int16_t* ioBuffer = (int16_t*)inputByteArray.data();
477
478 _peq.render( ioBuffer, ioBuffer, inputByteArray.size() / sizeof(int16_t) );
479 }
480
466 if (Menu::getInstance()->isOptionChecked(MenuOption::EchoLocalAudio) && !_muted && _audioOutput) {481 if (Menu::getInstance()->isOptionChecked(MenuOption::EchoLocalAudio) && !_muted && _audioOutput) {
467 // if this person wants local loopback add that to the locally injected audio482 // if this person wants local loopback add that to the locally injected audio
468 483
@@ -1172,6 +1187,31 @@ void Audio::renderToolBox(int x, int y, bool boxed) { · 703 unmodified lines
1172 glDisable(GL_TEXTURE_2D);1187 glDisable(GL_TEXTURE_2D);
1173}1188}
1174 1189
1190void Audio::toggleAudioFilter() {
1191 _peqEnabled = !_peqEnabled;
1192}
1193
1194void Audio::selectAudioFilterFlat() {
1195 if (Menu::getInstance()->isOptionChecked(MenuOption::AudioFilterFlat)) {
1196 _peq.loadProfile(0);
1197 }
1198}
1199void Audio::selectAudioFilterTrebleCut() {
1200 if (Menu::getInstance()->isOptionChecked(MenuOption::AudioFilterTrebleCut)) {
1201 _peq.loadProfile(1);
1202 }
1203}
1204void Audio::selectAudioFilterBassCut() {
1205 if (Menu::getInstance()->isOptionChecked(MenuOption::AudioFilterBassCut)) {
1206 _peq.loadProfile(2);
1207 }
1208}
1209void Audio::selectAudioFilterSmiley() {
1210 if (Menu::getInstance()->isOptionChecked(MenuOption::AudioFilterSmiley)) {
1211 _peq.loadProfile(3);
1212 }
1213}
1214
1175void Audio::toggleScope() {1215void Audio::toggleScope() {
1176 _scopeEnabled = !_scopeEnabled;1216 _scopeEnabled = !_scopeEnabled;
1177 if (_scopeEnabled) {1217 if (_scopeEnabled) {
interface/src/Audio.h+14−3
@@ -19,6 +19,7 @@ · 18 unmodified lines
19#include "AudioStreamStats.h"19#include "AudioStreamStats.h"
20#include "RingBufferHistory.h"20#include "RingBufferHistory.h"
21#include "MovingMinMaxAvg.h"21#include "MovingMinMaxAvg.h"
22#include "AudioFilter.h"
22 23
23#include <QAudio>24#include <QAudio>
24#include <QAudioInput>25#include <QAudioInput>
@@ -125,7 +126,12 @@ public slots: · 100 unmodified lines
125 void selectAudioScopeFiveFrames();126 void selectAudioScopeFiveFrames();
126 void selectAudioScopeTwentyFrames();127 void selectAudioScopeTwentyFrames();
127 void selectAudioScopeFiftyFrames();128 void selectAudioScopeFiftyFrames();
128 129 void toggleAudioFilter();
130 void selectAudioFilterFlat();
131 void selectAudioFilterTrebleCut();
132 void selectAudioFilterBassCut();
133 void selectAudioFilterSmiley();
134
129 virtual void handleAudioByteArray(const QByteArray& audioByteArray);135 virtual void handleAudioByteArray(const QByteArray& audioByteArray);
130 136
131 void sendDownstreamAudioStatsPacket();137 void sendDownstreamAudioStatsPacket();
@@ -252,12 +258,12 @@ private: · 120 unmodified lines
252 // Audio scope methods for rendering258 // Audio scope methods for rendering
253 void renderBackground(const float* color, int x, int y, int width, int height);259 void renderBackground(const float* color, int x, int y, int width, int height);
254 void renderGrid(const float* color, int x, int y, int width, int height, int rows, int cols);260 void renderGrid(const float* color, int x, int y, int width, int height, int rows, int cols);
255 void renderLineStrip(const float* color, int x, int y, int n, int offset, const QByteArray* byteArray);261 void renderLineStrip(const float* color, int x, int y, int n, int offset, const QByteArray* byteArray);
256 262
257 // audio stats methods for rendering263 // audio stats methods for rendering
258 void renderAudioStreamStats(const AudioStreamStats& streamStats, int horizontalOffset, int& verticalOffset,264 void renderAudioStreamStats(const AudioStreamStats& streamStats, int horizontalOffset, int& verticalOffset,
259 float scale, float rotation, int font, const float* color, bool isDownstreamStats = false);265 float scale, float rotation, int font, const float* color, bool isDownstreamStats = false);
260 266
261 // Audio scope data267 // Audio scope data
262 static const unsigned int NETWORK_SAMPLES_PER_FRAME = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL;268 static const unsigned int NETWORK_SAMPLES_PER_FRAME = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
263 static const unsigned int DEFAULT_FRAMES_PER_SCOPE = 5;269 static const unsigned int DEFAULT_FRAMES_PER_SCOPE = 5;
@@ -270,6 +276,11 @@ private: · 6 unmodified lines
270 int _scopeOutputOffset;276 int _scopeOutputOffset;
271 int _framesPerScope;277 int _framesPerScope;
272 int _samplesPerScope;278 int _samplesPerScope;
279
280 // Multi-band parametric EQ
281 bool _peqEnabled;
282 AudioFilterPEQ3 _peq;
283
273 QMutex _guard;284 QMutex _guard;
274 QByteArray* _scopeInput;285 QByteArray* _scopeInput;
275 QByteArray* _scopeOutputLeft;286 QByteArray* _scopeOutputLeft;
interface/src/Menu.cpp+44−2
@@ -486,6 +486,48 @@ Menu::Menu() : · 485 unmodified lines
486 true,486 true,
487 appInstance->getAudio(),487 appInstance->getAudio(),
488 SLOT(toggleAudioNoiseReduction()));488 SLOT(toggleAudioNoiseReduction()));
489
490 addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioFilter,
491 0,
492 false,
493 appInstance->getAudio(),
494 SLOT(toggleAudioFilter()));
495
496 QMenu* audioFilterMenu = audioDebugMenu->addMenu("Audio Filter Options");
497 addDisabledActionAndSeparator(audioFilterMenu, "Filter Response");
498 {
499 QAction *flat = addCheckableActionToQMenuAndActionHash(audioFilterMenu, MenuOption::AudioFilterFlat,
500 0,
501 true,
502 appInstance->getAudio(),
503 SLOT(selectAudioFilterFlat()));
504
505 QAction *trebleCut = addCheckableActionToQMenuAndActionHash(audioFilterMenu, MenuOption::AudioFilterTrebleCut,
506 0,
507 false,
508 appInstance->getAudio(),
509 SLOT(selectAudioFilterTrebleCut()));
510
511 QAction *bassCut = addCheckableActionToQMenuAndActionHash(audioFilterMenu, MenuOption::AudioFilterBassCut,
512 0,
513 false,
514 appInstance->getAudio(),
515 SLOT(selectAudioFilterBassCut()));
516
517 QAction *smiley = addCheckableActionToQMenuAndActionHash(audioFilterMenu, MenuOption::AudioFilterSmiley,
518 0,
519 false,
520 appInstance->getAudio(),
521 SLOT(selectAudioFilterSmiley()));
522
523
524 QActionGroup* audioFilterGroup = new QActionGroup(audioFilterMenu);
525 audioFilterGroup->addAction(flat);
526 audioFilterGroup->addAction(trebleCut);
527 audioFilterGroup->addAction(bassCut);
528 audioFilterGroup->addAction(smiley);
529 }
530
489 addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoServerAudio);531 addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoServerAudio);
490 addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoLocalAudio);532 addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoLocalAudio);
491 addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::StereoAudio, 0, false,533 addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::StereoAudio, 0, false,
@@ -1111,8 +1153,8 @@ void Menu::goTo() { · 619 unmodified lines
1111}1153}
1112 1154
1113bool Menu::goToURL(QString location) {1155bool Menu::goToURL(QString location) {
1114 if (location.startsWith(CUSTOM_URL_SCHEME + "//")) {1156 if (location.startsWith(CUSTOM_URL_SCHEME + "/")) {
1115 QStringList urlParts = location.remove(0, CUSTOM_URL_SCHEME.length() + 2).split('/', QString::SkipEmptyParts);1157 QStringList urlParts = location.remove(0, CUSTOM_URL_SCHEME.length()).split('/', QString::SkipEmptyParts);
1116 1158
1117 if (urlParts.count() > 1) {1159 if (urlParts.count() > 1) {
1118 // if url has 2 or more parts, the first one is domain name1160 // if url has 2 or more parts, the first one is domain name
interface/src/Menu.h+5−0
@@ -311,6 +311,11 @@ namespace MenuOption { · 310 unmodified lines
311 const QString Animations = "Animations...";311 const QString Animations = "Animations...";
312 const QString Atmosphere = "Atmosphere";312 const QString Atmosphere = "Atmosphere";
313 const QString Attachments = "Attachments...";313 const QString Attachments = "Attachments...";
314 const QString AudioFilter = "Audio Filter Bank";
315 const QString AudioFilterFlat = "Flat Response";
316 const QString AudioFilterTrebleCut= "Treble Cut";
317 const QString AudioFilterBassCut = "Bass Cut";
318 const QString AudioFilterSmiley = "Smiley Curve";
314 const QString AudioNoiseReduction = "Audio Noise Reduction";319 const QString AudioNoiseReduction = "Audio Noise Reduction";
315 const QString AudioScope = "Audio Scope";320 const QString AudioScope = "Audio Scope";
316 const QString AudioScopeFiftyFrames = "Fifty";321 const QString AudioScopeFiftyFrames = "Fifty";
interface/src/MetavoxelSystem.cpp+779−67
@@ -37,6 +37,9 @@ void MetavoxelSystem::init() { · 36 unmodified lines
37 _pointBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(new BufferDataAttribute("pointBuffer"));37 _pointBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(new BufferDataAttribute("pointBuffer"));
38 _heightfieldBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(38 _heightfieldBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(
39 new BufferDataAttribute("heightfieldBuffer"));39 new BufferDataAttribute("heightfieldBuffer"));
40
41 _heightfieldBufferAttribute->setLODThresholdMultiplier(
42 AttributeRegistry::getInstance()->getHeightfieldAttribute()->getLODThresholdMultiplier());
40}43}
41 44
42MetavoxelLOD MetavoxelSystem::getLOD() {45MetavoxelLOD MetavoxelSystem::getLOD() {
@@ -118,6 +121,334 @@ void MetavoxelSystem::render() { · 75 unmodified lines
118 guideToAugmented(renderVisitor);121 guideToAugmented(renderVisitor);
119}122}
120 123
124class RayHeightfieldIntersectionVisitor : public RayIntersectionVisitor {
125public:
126
127 float intersectionDistance;
128
129 RayHeightfieldIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, const MetavoxelLOD& lod);
130
131 virtual int visit(MetavoxelInfo& info, float distance);
132};
133
134RayHeightfieldIntersectionVisitor::RayHeightfieldIntersectionVisitor(const glm::vec3& origin,
135 const glm::vec3& direction, const MetavoxelLOD& lod) :
136 RayIntersectionVisitor(origin, direction, QVector<AttributePointer>() <<
137 Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector<AttributePointer>(), lod),
138 intersectionDistance(FLT_MAX) {
139}
140
141static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / 255.0f;
142
143int RayHeightfieldIntersectionVisitor::visit(MetavoxelInfo& info, float distance) {
144 if (!info.isLeaf) {
145 return _order;
146 }
147 const HeightfieldBuffer* buffer = static_cast<HeightfieldBuffer*>(
148 info.inputValues.at(0).getInlineValue<BufferDataPointer>().data());
149 if (!buffer) {
150 return STOP_RECURSION;
151 }
152 const QByteArray& contents = buffer->getHeight();
153 const uchar* src = (const uchar*)contents.constData();
154 int size = glm::sqrt((float)contents.size());
155 int unextendedSize = size - HeightfieldBuffer::HEIGHT_EXTENSION;
156 int highest = HeightfieldBuffer::HEIGHT_BORDER + unextendedSize;
157 float heightScale = unextendedSize * EIGHT_BIT_MAXIMUM_RECIPROCAL;
158
159 // find the initial location in heightfield coordinates
160 glm::vec3 entry = (_origin + distance * _direction - info.minimum) * (float)unextendedSize / info.size;
161 entry.x += HeightfieldBuffer::HEIGHT_BORDER;
162 entry.z += HeightfieldBuffer::HEIGHT_BORDER;
163 glm::vec3 floors = glm::floor(entry);
164 glm::vec3 ceils = glm::ceil(entry);
165 if (floors.x == ceils.x) {
166 if (_direction.x > 0.0f) {
167 ceils.x += 1.0f;
168 } else {
169 floors.x -= 1.0f;
170 }
171 }
172 if (floors.z == ceils.z) {
173 if (_direction.z > 0.0f) {
174 ceils.z += 1.0f;
175 } else {
176 floors.z -= 1.0f;
177 }
178 }
179
180 bool withinBounds = true;
181 float accumulatedDistance = 0.0f;
182 while (withinBounds) {
183 // find the heights at the corners of the current cell
184 int floorX = qMin(qMax((int)floors.x, HeightfieldBuffer::HEIGHT_BORDER), highest);
185 int floorZ = qMin(qMax((int)floors.z, HeightfieldBuffer::HEIGHT_BORDER), highest);
186 int ceilX = qMin(qMax((int)ceils.x, HeightfieldBuffer::HEIGHT_BORDER), highest);
187 int ceilZ = qMin(qMax((int)ceils.z, HeightfieldBuffer::HEIGHT_BORDER), highest);
188 float upperLeft = src[floorZ * size + floorX] * heightScale;
189 float upperRight = src[floorZ * size + ceilX] * heightScale;
190 float lowerLeft = src[ceilZ * size + floorX] * heightScale;
191 float lowerRight = src[ceilZ * size + ceilX] * heightScale;
192
193 // find the distance to the next x coordinate
194 float xDistance = FLT_MAX;
195 if (_direction.x > 0.0f) {
196 xDistance = (ceils.x - entry.x) / _direction.x;
197 } else if (_direction.x < 0.0f) {
198 xDistance = (floors.x - entry.x) / _direction.x;
199 }
200
201 // and the distance to the next z coordinate
202 float zDistance = FLT_MAX;
203 if (_direction.z > 0.0f) {
204 zDistance = (ceils.z - entry.z) / _direction.z;
205 } else if (_direction.z < 0.0f) {
206 zDistance = (floors.z - entry.z) / _direction.z;
207 }
208
209 // the exit distance is the lower of those two
210 float exitDistance = qMin(xDistance, zDistance);
211 glm::vec3 exit, nextFloors = floors, nextCeils = ceils;
212 if (exitDistance == FLT_MAX) {
213 if (_direction.y > 0.0f) {
214 return SHORT_CIRCUIT; // line points upwards; no collisions possible
215 }
216 withinBounds = false; // line points downwards; check this cell only
217
218 } else {
219 // find the exit point and the next cell, and determine whether it's still within the bounds
220 exit = entry + exitDistance * _direction;
221 withinBounds = (exit.y >= HeightfieldBuffer::HEIGHT_BORDER && exit.y <= highest);
222 if (exitDistance == xDistance) {
223 if (_direction.x > 0.0f) {
224 nextFloors.x += 1.0f;
225 withinBounds &= (nextCeils.x += 1.0f) <= highest;
226 } else {
227 withinBounds &= (nextFloors.x -= 1.0f) >= HeightfieldBuffer::HEIGHT_BORDER;
228 nextCeils.x -= 1.0f;
229 }
230 }
231 if (exitDistance == zDistance) {
232 if (_direction.z > 0.0f) {
233 nextFloors.z += 1.0f;
234 withinBounds &= (nextCeils.z += 1.0f) <= highest;
235 } else {
236 withinBounds &= (nextFloors.z -= 1.0f) >= HeightfieldBuffer::HEIGHT_BORDER;
237 nextCeils.z -= 1.0f;
238 }
239 }
240 // check the vertical range of the ray against the ranges of the cell heights
241 if (qMin(entry.y, exit.y) > qMax(qMax(upperLeft, upperRight), qMax(lowerLeft, lowerRight)) ||
242 qMax(entry.y, exit.y) < qMin(qMin(upperLeft, upperRight), qMin(lowerLeft, lowerRight))) {
243 entry = exit;
244 floors = nextFloors;
245 ceils = nextCeils;
246 accumulatedDistance += exitDistance;
247 continue;
248 }
249 }
250 // having passed the bounds check, we must check against the planes
251 glm::vec3 relativeEntry = entry - glm::vec3(floors.x, upperLeft, floors.z);
252
253 // first check the triangle including the Z+ segment
254 glm::vec3 lowerNormal(lowerLeft - lowerRight, 1.0f, upperLeft - lowerLeft);
255 float lowerProduct = glm::dot(lowerNormal, _direction);
256 if (lowerProduct < 0.0f) {
257 float planeDistance = -glm::dot(lowerNormal, relativeEntry) / lowerProduct;
258 glm::vec3 intersection = relativeEntry + planeDistance * _direction;
259 if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f &&
260 intersection.z >= intersection.x) {
261 intersectionDistance = qMin(intersectionDistance, distance +
262 (accumulatedDistance + planeDistance) * (info.size / unextendedSize));
263 return SHORT_CIRCUIT;
264 }
265 }
266
267 // then the one with the X+ segment
268 glm::vec3 upperNormal(upperLeft - upperRight, 1.0f, upperRight - lowerRight);
269 float upperProduct = glm::dot(upperNormal, _direction);
270 if (upperProduct < 0.0f) {
271 float planeDistance = -glm::dot(upperNormal, relativeEntry) / upperProduct;
272 glm::vec3 intersection = relativeEntry + planeDistance * _direction;
273 if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f &&
274 intersection.x >= intersection.z) {
275 intersectionDistance = qMin(intersectionDistance, distance +
276 (accumulatedDistance + planeDistance) * (info.size / unextendedSize));
277 return SHORT_CIRCUIT;
278 }
279 }
280
281 // no joy; continue on our way
282 entry = exit;
283 floors = nextFloors;
284 ceils = nextCeils;
285 accumulatedDistance += exitDistance;
286 }
287
288 return STOP_RECURSION;
289}
290
291bool MetavoxelSystem::findFirstRayHeightfieldIntersection(const glm::vec3& origin,
292 const glm::vec3& direction, float& distance) {
293 RayHeightfieldIntersectionVisitor visitor(origin, direction, getLOD());
294 guideToAugmented(visitor);
295 if (visitor.intersectionDistance == FLT_MAX) {
296 return false;
297 }
298 distance = visitor.intersectionDistance;
299 return true;
300}
301
302class HeightfieldHeightVisitor : public MetavoxelVisitor {
303public:
304
305 float height;
306
307 HeightfieldHeightVisitor(const MetavoxelLOD& lod, const glm::vec3& location);
308
309 virtual int visit(MetavoxelInfo& info);
310
311private:
312
313 glm::vec3 _location;
314};
315
316HeightfieldHeightVisitor::HeightfieldHeightVisitor(const MetavoxelLOD& lod, const glm::vec3& location) :
317 MetavoxelVisitor(QVector<AttributePointer>() <<
318 Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector<AttributePointer>(), lod),
319 height(-FLT_MAX),
320 _location(location) {
321}
322
323static const int REVERSE_ORDER = MetavoxelVisitor::encodeOrder(7, 6, 5, 4, 3, 2, 1, 0);
324
325int HeightfieldHeightVisitor::visit(MetavoxelInfo& info) {
326 glm::vec3 relative = _location - info.minimum;
327 if (relative.x < 0.0f || relative.z < 0.0f || relative.x > info.size || relative.z > info.size ||
328 height >= info.minimum.y + info.size) {
329 return STOP_RECURSION;
330 }
331 if (!info.isLeaf) {
332 return REVERSE_ORDER;
333 }
334 const HeightfieldBuffer* buffer = static_cast<HeightfieldBuffer*>(
335 info.inputValues.at(0).getInlineValue<BufferDataPointer>().data());
336 if (!buffer) {
337 return STOP_RECURSION;
338 }
339 const QByteArray& contents = buffer->getHeight();
340 const uchar* src = (const uchar*)contents.constData();
341 int size = glm::sqrt((float)contents.size());
342 int unextendedSize = size - HeightfieldBuffer::HEIGHT_EXTENSION;
343 int highest = HeightfieldBuffer::HEIGHT_BORDER + unextendedSize;
344 relative *= unextendedSize / info.size;
345 relative.x += HeightfieldBuffer::HEIGHT_BORDER;
346 relative.z += HeightfieldBuffer::HEIGHT_BORDER;
347
348 // find the bounds of the cell containing the point and the shared vertex heights
349 glm::vec3 floors = glm::floor(relative);
350 glm::vec3 ceils = glm::ceil(relative);
351 glm::vec3 fracts = glm::fract(relative);
352 int floorX = qMin(qMax((int)floors.x, HeightfieldBuffer::HEIGHT_BORDER), highest);
353 int floorZ = qMin(qMax((int)floors.z, HeightfieldBuffer::HEIGHT_BORDER), highest);
354 int ceilX = qMin(qMax((int)ceils.x, HeightfieldBuffer::HEIGHT_BORDER), highest);
355 int ceilZ = qMin(qMax((int)ceils.z, HeightfieldBuffer::HEIGHT_BORDER), highest);
356 float upperLeft = src[floorZ * size + floorX];
357 float lowerRight = src[ceilZ * size + ceilX];
358 float interpolatedHeight = glm::mix(upperLeft, lowerRight, fracts.z);
359
360 // the final vertex (and thus which triangle we check) depends on which half we're on
361 if (fracts.x >= fracts.z) {
362 float upperRight = src[floorZ * size + ceilX];
363 interpolatedHeight = glm::mix(interpolatedHeight, glm::mix(upperRight, lowerRight, fracts.z),
364 (fracts.x - fracts.z) / (1.0f - fracts.z));
365
366 } else {
367 float lowerLeft = src[ceilZ * size + floorX];
368 interpolatedHeight = glm::mix(glm::mix(upperLeft, lowerLeft, fracts.z), interpolatedHeight, fracts.x / fracts.z);
369 }
370 if (interpolatedHeight == 0.0f) {
371 return STOP_RECURSION; // ignore zero values
372 }
373
374 // convert the interpolated height into world space
375 height = qMax(height, info.minimum.y + interpolatedHeight * info.size * EIGHT_BIT_MAXIMUM_RECIPROCAL);
376 return SHORT_CIRCUIT;
377}
378
379float MetavoxelSystem::getHeightfieldHeight(const glm::vec3& location) {
380 HeightfieldHeightVisitor visitor(getLOD(), location);
381 guideToAugmented(visitor);
382 return visitor.height;
383}
384
385class HeightfieldCursorRenderVisitor : public MetavoxelVisitor {
386public:
387
388 HeightfieldCursorRenderVisitor(const Box& bounds);
389
390 virtual int visit(MetavoxelInfo& info);
391
392private:
393
394 Box _bounds;
395};
396
397HeightfieldCursorRenderVisitor::HeightfieldCursorRenderVisitor(const Box& bounds) :
398 MetavoxelVisitor(QVector<AttributePointer>() <<
399 Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute()),
400 _bounds(bounds) {
401}
402
403int HeightfieldCursorRenderVisitor::visit(MetavoxelInfo& info) {
404 if (!info.getBounds().intersects(_bounds)) {
405 return STOP_RECURSION;
406 }
407 if (!info.isLeaf) {
408 return DEFAULT_ORDER;
409 }
410 BufferDataPointer buffer = info.inputValues.at(0).getInlineValue<BufferDataPointer>();
411 if (buffer) {
412 buffer->render(true);
413 }
414 return STOP_RECURSION;
415}
416
417void MetavoxelSystem::renderHeightfieldCursor(const glm::vec3& position, float radius) {
418 glDepthFunc(GL_LEQUAL);
419 glEnable(GL_CULL_FACE);
420 glEnable(GL_POLYGON_OFFSET_FILL);
421 glPolygonOffset(-1.0f, -1.0f);
422
423 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
424
425 glEnableClientState(GL_VERTEX_ARRAY);
426 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
427
428 DefaultMetavoxelRendererImplementation::getHeightfieldCursorProgram().bind();
429
430 glActiveTexture(GL_TEXTURE4);
431 float scale = 1.0f / radius;
432 glm::vec4 sCoefficients(scale, 0.0f, 0.0f, -scale * position.x);
433 glm::vec4 tCoefficients(0.0f, 0.0f, scale, -scale * position.z);
434 glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&sCoefficients);
435 glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&tCoefficients);
436 glActiveTexture(GL_TEXTURE0);
437
438 glm::vec3 extents(radius, radius, radius);
439 HeightfieldCursorRenderVisitor visitor(Box(position - extents, position + extents));
440 guideToAugmented(visitor);
441
442 DefaultMetavoxelRendererImplementation::getHeightfieldCursorProgram().release();
443
444 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
445 glDisableClientState(GL_VERTEX_ARRAY);
446
447 glDisable(GL_POLYGON_OFFSET_FILL);
448 glDisable(GL_CULL_FACE);
449 glDepthFunc(GL_LESS);
450}
451
121void MetavoxelSystem::deleteTextures(int heightID, int colorID) {452void MetavoxelSystem::deleteTextures(int heightID, int colorID) {
122 glDeleteTextures(1, (GLuint*)&heightID);453 glDeleteTextures(1, (GLuint*)&heightID);
123 glDeleteTextures(1, (GLuint*)&colorID);454 glDeleteTextures(1, (GLuint*)&colorID);
@@ -239,7 +570,7 @@ PointBuffer::PointBuffer(const BufferPointVector& points) : · 115 unmodified lines
239 _points(points) {570 _points(points) {
240}571}
241 572
242void PointBuffer::render() {573void PointBuffer::render(bool cursor) {
243 // initialize buffer, etc. on first render574 // initialize buffer, etc. on first render
244 if (!_buffer.isCreated()) {575 if (!_buffer.isCreated()) {
245 _buffer.setUsagePattern(QOpenGLBuffer::StaticDraw);576 _buffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
@@ -265,16 +596,32 @@ void PointBuffer::render() { · 19 unmodified lines
265 _buffer.release();596 _buffer.release();
266}597}
267 598
599const int HeightfieldBuffer::HEIGHT_BORDER = 1;
600const int HeightfieldBuffer::SHARED_EDGE = 1;
601const int HeightfieldBuffer::HEIGHT_EXTENSION = 2 * HeightfieldBuffer::HEIGHT_BORDER + HeightfieldBuffer::SHARED_EDGE;
602
268HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale,603HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale,
269 const QByteArray& height, const QByteArray& color, bool clearAfterLoading) :604 const QByteArray& height, const QByteArray& color) :
270 _translation(translation),605 _translation(translation),
271 _scale(scale),606 _scale(scale),
607 _heightBounds(translation, translation + glm::vec3(scale, scale, scale)),
608 _colorBounds(_heightBounds),
272 _height(height),609 _height(height),
273 _color(color),610 _color(color),
274 _clearAfterLoading(clearAfterLoading),
275 _heightTextureID(0),611 _heightTextureID(0),
276 _colorTextureID(0),612 _colorTextureID(0),
277 _heightSize(glm::sqrt(height.size())) {613 _heightSize(glm::sqrt(height.size())),
614 _heightIncrement(scale / (_heightSize - HEIGHT_EXTENSION)),
615 _colorSize(glm::sqrt(color.size() / HeightfieldData::COLOR_BYTES)),
616 _colorIncrement(scale / (_colorSize - SHARED_EDGE)) {
617
618 _heightBounds.minimum.x -= _heightIncrement * HEIGHT_BORDER;
619 _heightBounds.minimum.z -= _heightIncrement * HEIGHT_BORDER;
620 _heightBounds.maximum.x += _heightIncrement * (SHARED_EDGE + HEIGHT_BORDER);
621 _heightBounds.maximum.z += _heightIncrement * (SHARED_EDGE + HEIGHT_BORDER);
622
623 _colorBounds.maximum.x += _colorIncrement * SHARED_EDGE;
624 _colorBounds.maximum.z += _colorIncrement * SHARED_EDGE;
278}625}
279 626
280HeightfieldBuffer::~HeightfieldBuffer() {627HeightfieldBuffer::~HeightfieldBuffer() {
@@ -288,25 +635,49 @@ HeightfieldBuffer::~HeightfieldBuffer() { · 7 unmodified lines
288 }635 }
289}636}
290 637
638QByteArray HeightfieldBuffer::getUnextendedHeight() const {
639 int srcSize = glm::sqrt(_height.size());
640 int destSize = srcSize - 3;
641 QByteArray unextended(destSize * destSize, 0);
642 const char* src = _height.constData() + srcSize + 1;
643 char* dest = unextended.data();
644 for (int z = 0; z < destSize; z++, src += srcSize, dest += destSize) {
645 memcpy(dest, src, destSize);
646 }
647 return unextended;
648}
649
650QByteArray HeightfieldBuffer::getUnextendedColor() const {
651 int srcSize = glm::sqrt(_color.size() / HeightfieldData::COLOR_BYTES);
652 int destSize = srcSize - 1;
653 QByteArray unextended(destSize * destSize * HeightfieldData::COLOR_BYTES, 0);
654 const char* src = _color.constData();
655 int srcStride = srcSize * HeightfieldData::COLOR_BYTES;
656 char* dest = unextended.data();
657 int destStride = destSize * HeightfieldData::COLOR_BYTES;
658 for (int z = 0; z < destSize; z++, src += srcStride, dest += destStride) {
659 memcpy(dest, src, destStride);
660 }
661 return unextended;
662}
663
291class HeightfieldPoint {664class HeightfieldPoint {
292public:665public:
293 glm::vec2 textureCoord;666 glm::vec2 textureCoord;
294 glm::vec3 vertex;667 glm::vec3 vertex;
295};668};
296 669
297void HeightfieldBuffer::render() {670void HeightfieldBuffer::render(bool cursor) {
298 // initialize textures, etc. on first render671 // initialize textures, etc. on first render
299 if (_heightTextureID == 0) {672 if (_heightTextureID == 0) {
300 glGenTextures(1, &_heightTextureID);673 glGenTextures(1, &_heightTextureID);
301 glBindTexture(GL_TEXTURE_2D, _heightTextureID);674 glBindTexture(GL_TEXTURE_2D, _heightTextureID);
675 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
302 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);676 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
303 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);677 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
304 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);678 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
305 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, _heightSize, _heightSize, 0,679 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, _heightSize, _heightSize, 0,
306 GL_LUMINANCE, GL_UNSIGNED_BYTE, _height.constData());680 GL_LUMINANCE, GL_UNSIGNED_BYTE, _height.constData());
307 if (_clearAfterLoading) {
308 _height.clear();
309 }
310 681
311 glGenTextures(1, &_colorTextureID);682 glGenTextures(1, &_colorTextureID);
312 glBindTexture(GL_TEXTURE_2D, _colorTextureID);683 glBindTexture(GL_TEXTURE_2D, _colorTextureID);
@@ -318,32 +689,32 @@ void HeightfieldBuffer::render() { · 5 unmodified lines
318 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, WHITE_COLOR);689 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, WHITE_COLOR);
319 690
320 } else {691 } else {
321 int colorSize = glm::sqrt(_color.size() / 3);692 int colorSize = glm::sqrt(_color.size() / HeightfieldData::COLOR_BYTES);
322 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, colorSize, colorSize, 0, GL_RGB, GL_UNSIGNED_BYTE, _color.constData());693 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, colorSize, colorSize, 0, GL_RGB, GL_UNSIGNED_BYTE, _color.constData());
323 if (_clearAfterLoading) {
324 _color.clear();
325 }
326 }694 }
327 }695 }
328 // create the buffer objects lazily696 // create the buffer objects lazily
329 int sizeWithSkirt = _heightSize + 2;697 int innerSize = _heightSize - 2 * HeightfieldBuffer::HEIGHT_BORDER;
330 int vertexCount = sizeWithSkirt * sizeWithSkirt;698 int vertexCount = _heightSize * _heightSize;
331 int rows = sizeWithSkirt - 1;699 int rows = _heightSize - 1;
332 int indexCount = rows * rows * 4;700 int indexCount = rows * rows * 3 * 2;
333 BufferPair& bufferPair = _bufferPairs[_heightSize];701 BufferPair& bufferPair = _bufferPairs[_heightSize];
334 if (!bufferPair.first.isCreated()) {702 if (!bufferPair.first.isCreated()) {
335 QVector<HeightfieldPoint> vertices(vertexCount);703 QVector<HeightfieldPoint> vertices(vertexCount);
336 HeightfieldPoint* point = vertices.data();704 HeightfieldPoint* point = vertices.data();
337 705
338 float step = 1.0f / (_heightSize - 1);706 float vertexStep = 1.0f / (innerSize - 1);
339 float z = -step;707 float z = -vertexStep;
340 for (int i = 0; i < sizeWithSkirt; i++, z += step) {708 float textureStep = 1.0f / _heightSize;
341 float x = -step;709 float t = textureStep / 2.0f;
710 for (int i = 0; i < _heightSize; i++, z += vertexStep, t += textureStep) {
711 float x = -vertexStep;
712 float s = textureStep / 2.0f;
342 const float SKIRT_LENGTH = 0.25f;713 const float SKIRT_LENGTH = 0.25f;
343 float baseY = (i == 0 || i == sizeWithSkirt - 1) ? -SKIRT_LENGTH : 0.0f;714 float baseY = (i == 0 || i == _heightSize - 1) ? -SKIRT_LENGTH : 0.0f;
344 for (int j = 0; j < sizeWithSkirt; j++, point++, x += step) {715 for (int j = 0; j < _heightSize; j++, point++, x += vertexStep, s += textureStep) {
345 point->vertex = glm::vec3(x, (j == 0 || j == sizeWithSkirt - 1) ? -SKIRT_LENGTH : baseY, z);716 point->vertex = glm::vec3(x, (j == 0 || j == _heightSize - 1) ? -SKIRT_LENGTH : baseY, z);
346 point->textureCoord = glm::vec2(x, z);717 point->textureCoord = glm::vec2(s, t);
347 }718 }
348 }719 }
349 720
@@ -355,13 +726,16 @@ void HeightfieldBuffer::render() { · 5 unmodified lines
355 QVector<int> indices(indexCount);726 QVector<int> indices(indexCount);
356 int* index = indices.data();727 int* index = indices.data();
357 for (int i = 0; i < rows; i++) {728 for (int i = 0; i < rows; i++) {
358 int lineIndex = i * sizeWithSkirt;729 int lineIndex = i * _heightSize;
359 int nextLineIndex = (i + 1) * sizeWithSkirt;730 int nextLineIndex = (i + 1) * _heightSize;
360 for (int j = 0; j < rows; j++) {731 for (int j = 0; j < rows; j++) {
361 *index++ = lineIndex + j;732 *index++ = lineIndex + j;
362 *index++ = nextLineIndex + j;733 *index++ = nextLineIndex + j;
734 *index++ = nextLineIndex + j + 1;
735
363 *index++ = nextLineIndex + j + 1;736 *index++ = nextLineIndex + j + 1;
364 *index++ = lineIndex + j + 1;737 *index++ = lineIndex + j + 1;
738 *index++ = lineIndex + j;
365 }739 }
366 }740 }
367 741
@@ -385,17 +759,33 @@ void HeightfieldBuffer::render() { · 17 unmodified lines
385 759
386 glBindTexture(GL_TEXTURE_2D, _heightTextureID);760 glBindTexture(GL_TEXTURE_2D, _heightTextureID);
387 761
388 glActiveTexture(GL_TEXTURE1);762 if (!cursor) {
389 glBindTexture(GL_TEXTURE_2D, _colorTextureID);763 int heightScaleLocation = DefaultMetavoxelRendererImplementation::getHeightScaleLocation();
764 int colorScaleLocation = DefaultMetavoxelRendererImplementation::getColorScaleLocation();
765 ProgramObject* program = &DefaultMetavoxelRendererImplementation::getHeightfieldProgram();
766 if (Menu::getInstance()->isOptionChecked(MenuOption::SimpleShadows)) {
767 heightScaleLocation = DefaultMetavoxelRendererImplementation::getShadowMapHeightScaleLocation();
768 colorScaleLocation = DefaultMetavoxelRendererImplementation::getShadowMapColorScaleLocation();
769 program = &DefaultMetavoxelRendererImplementation::getShadowMapHeightfieldProgram();
770
771 } else if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) {
772 heightScaleLocation = DefaultMetavoxelRendererImplementation::getCascadedShadowMapHeightScaleLocation();
773 colorScaleLocation = DefaultMetavoxelRendererImplementation::getCascadedShadowMapColorScaleLocation();
774 program = &DefaultMetavoxelRendererImplementation::getCascadedShadowMapHeightfieldProgram();
775 }
776 program->setUniformValue(heightScaleLocation, 1.0f / _heightSize);
777 program->setUniformValue(colorScaleLocation, (float)_heightSize / innerSize);
778 glActiveTexture(GL_TEXTURE1);
779 glBindTexture(GL_TEXTURE_2D, _colorTextureID);
780 }
390 781
391 DefaultMetavoxelRendererImplementation::getHeightfieldProgram().setUniformValue(782 glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0);
392 DefaultMetavoxelRendererImplementation::getHeightScaleLocation(), 1.0f / _heightSize);
393
394 glDrawRangeElements(GL_QUADS, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0);
395 783
396 glBindTexture(GL_TEXTURE_2D, 0);784 if (!cursor) {
785 glBindTexture(GL_TEXTURE_2D, 0);
786 glActiveTexture(GL_TEXTURE0);
787 }
397 788
398 glActiveTexture(GL_TEXTURE0);
399 glBindTexture(GL_TEXTURE_2D, 0);789 glBindTexture(GL_TEXTURE_2D, 0);
400 790
401 glPopMatrix();791 glPopMatrix();
@@ -444,17 +834,19 @@ BufferDataAttribute::BufferDataAttribute(const QString& name) : · 42 unmodified lines
444}834}
445 835
446bool BufferDataAttribute::merge(void*& parent, void* children[], bool postRead) const {836bool BufferDataAttribute::merge(void*& parent, void* children[], bool postRead) const {
447 BufferDataPointer firstChild = decodeInline<BufferDataPointer>(children[0]);837 *(BufferDataPointer*)&parent = _defaultValue;
448 for (int i = 1; i < MERGE_COUNT; i++) {838 for (int i = 0; i < MERGE_COUNT; i++) {
449 if (firstChild != decodeInline<BufferDataPointer>(children[i])) {839 if (decodeInline<BufferDataPointer>(children[i])) {
450 *(BufferDataPointer*)&parent = _defaultValue;
451 return false;840 return false;
452 }841 }
453 }842 }
454 *(BufferDataPointer*)&parent = firstChild;
455 return true;843 return true;
456}844}
457 845
846AttributeValue BufferDataAttribute::inherit(const AttributeValue& parentValue) const {
847 return AttributeValue(parentValue.getAttribute());
848}
849
458void DefaultMetavoxelRendererImplementation::init() {850void DefaultMetavoxelRendererImplementation::init() {
459 if (!_pointProgram.isLinked()) {851 if (!_pointProgram.isLinked()) {
460 _pointProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert");852 _pointProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert");
@@ -474,7 +866,47 @@ void DefaultMetavoxelRendererImplementation::init() { · 13 unmodified lines
474 _heightfieldProgram.setUniformValue("heightMap", 0);866 _heightfieldProgram.setUniformValue("heightMap", 0);
475 _heightfieldProgram.setUniformValue("diffuseMap", 1);867 _heightfieldProgram.setUniformValue("diffuseMap", 1);
476 _heightScaleLocation = _heightfieldProgram.uniformLocation("heightScale");868 _heightScaleLocation = _heightfieldProgram.uniformLocation("heightScale");
869 _colorScaleLocation = _heightfieldProgram.uniformLocation("colorScale");
477 _heightfieldProgram.release();870 _heightfieldProgram.release();
871
872 _shadowMapHeightfieldProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() +
873 "shaders/metavoxel_heightfield.vert");
874 _shadowMapHeightfieldProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() +
875 "shaders/metavoxel_heightfield_shadow_map.frag");
876 _shadowMapHeightfieldProgram.link();
877
878 _shadowMapHeightfieldProgram.bind();
879 _shadowMapHeightfieldProgram.setUniformValue("heightMap", 0);
880 _shadowMapHeightfieldProgram.setUniformValue("diffuseMap", 1);
881 _shadowMapHeightfieldProgram.setUniformValue("shadowMap", 2);
882 _shadowMapHeightScaleLocation = _shadowMapHeightfieldProgram.uniformLocation("heightScale");
883 _shadowMapColorScaleLocation = _shadowMapHeightfieldProgram.uniformLocation("colorScale");
884 _shadowMapHeightfieldProgram.release();
885
886 _cascadedShadowMapHeightfieldProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() +
887 "shaders/metavoxel_heightfield.vert");
888 _cascadedShadowMapHeightfieldProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() +
889 "shaders/metavoxel_heightfield_cascaded_shadow_map.frag");
890 _cascadedShadowMapHeightfieldProgram.link();
891
892 _cascadedShadowMapHeightfieldProgram.bind();
893 _cascadedShadowMapHeightfieldProgram.setUniformValue("heightMap", 0);
894 _cascadedShadowMapHeightfieldProgram.setUniformValue("diffuseMap", 1);
895 _cascadedShadowMapHeightfieldProgram.setUniformValue("shadowMap", 2);
896 _cascadedShadowMapHeightScaleLocation = _cascadedShadowMapHeightfieldProgram.uniformLocation("heightScale");
897 _cascadedShadowMapColorScaleLocation = _cascadedShadowMapHeightfieldProgram.uniformLocation("colorScale");
898 _shadowDistancesLocation = _cascadedShadowMapHeightfieldProgram.uniformLocation("shadowDistances");
899 _cascadedShadowMapHeightfieldProgram.release();
900
901 _heightfieldCursorProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() +
902 "shaders/metavoxel_heightfield_cursor.vert");
903 _heightfieldCursorProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() +
904 "shaders/metavoxel_heightfield_cursor.frag");
905 _heightfieldCursorProgram.link();
906
907 _heightfieldCursorProgram.bind();
908 _heightfieldCursorProgram.setUniformValue("heightMap", 0);
909 _heightfieldCursorProgram.release();
478 }910 }
479}911}
480 912
@@ -549,33 +981,279 @@ bool PointAugmentVisitor::postVisit(MetavoxelInfo& info) { · 68 unmodified lines
549 return true;981 return true;
550}982}
551 983
552class HeightfieldAugmentVisitor : public MetavoxelVisitor {984class HeightfieldFetchVisitor : public MetavoxelVisitor {
553public:985public:
986
987 HeightfieldFetchVisitor(const MetavoxelLOD& lod, const QVector<Box>& intersections);
988
989 void init(HeightfieldBuffer* buffer) { _buffer = buffer; }
990
991 virtual int visit(MetavoxelInfo& info);
554 992
555 HeightfieldAugmentVisitor(const MetavoxelLOD& lod);993private:
994
995 const QVector<Box>& _intersections;
996 HeightfieldBuffer* _buffer;
997};
998
999HeightfieldFetchVisitor::HeightfieldFetchVisitor(const MetavoxelLOD& lod, const QVector<Box>& intersections) :
1000 MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute() <<
1001 AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), QVector<AttributePointer>(), lod),
1002 _intersections(intersections) {
1003}
1004
1005int HeightfieldFetchVisitor::visit(MetavoxelInfo& info) {
1006 Box bounds = info.getBounds();
1007 const Box& heightBounds = _buffer->getHeightBounds();
1008 if (!bounds.intersects(heightBounds)) {
1009 return STOP_RECURSION;
1010 }
1011 if (!info.isLeaf && info.size > _buffer->getScale()) {
1012 return DEFAULT_ORDER;
1013 }
1014 HeightfieldDataPointer height = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>();
1015 if (!height) {
1016 return STOP_RECURSION;
1017 }
1018 foreach (const Box& intersection, _intersections) {
1019 Box overlap = intersection.getIntersection(bounds);
1020 if (overlap.isEmpty()) {
1021 continue;
1022 }
1023 float heightIncrement = _buffer->getHeightIncrement();
1024 int destX = (overlap.minimum.x - heightBounds.minimum.x) / heightIncrement;
1025 int destY = (overlap.minimum.z - heightBounds.minimum.z) / heightIncrement;
1026 int destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) / heightIncrement);
1027 int destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) / heightIncrement);
1028 int heightSize = _buffer->getHeightSize();
1029 char* dest = _buffer->getHeight().data() + destY * heightSize + destX;
1030
1031 const QByteArray& srcHeight = height->getContents();
1032 int srcSize = glm::sqrt(srcHeight.size());
1033 float srcIncrement = info.size / srcSize;
1034
1035 if (info.size == _buffer->getScale() && srcSize == (heightSize - HeightfieldBuffer::HEIGHT_EXTENSION)) {
1036 // easy case: same resolution
1037 int srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement;
1038 int srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement;
1039
1040 const char* src = srcHeight.constData() + srcY * srcSize + srcX;
1041 for (int y = 0; y < destHeight; y++, src += srcSize, dest += heightSize) {
1042 memcpy(dest, src, destWidth);
1043 }
1044 } else {
1045 // more difficult: different resolutions
1046 float srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement;
1047 float srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement;
1048 float srcAdvance = heightIncrement / srcIncrement;
1049 int shift = 0;
1050 float size = _buffer->getScale();
1051 while (size < info.size) {
1052 shift++;
1053 size *= 2.0f;
1054 }
1055 const int EIGHT_BIT_MAXIMUM = 255;
1056 int subtract = (_buffer->getTranslation().y - info.minimum.y) * EIGHT_BIT_MAXIMUM / _buffer->getScale();
1057 for (int y = 0; y < destHeight; y++, dest += heightSize, srcY += srcAdvance) {
1058 const uchar* src = (const uchar*)srcHeight.constData() + (int)srcY * srcSize;
1059 float lineSrcX = srcX;
1060 for (char* lineDest = dest, *end = dest + destWidth; lineDest != end; lineDest++, lineSrcX += srcAdvance) {
1061 *lineDest = qMin(qMax(0, (src[(int)lineSrcX] << shift) - subtract), EIGHT_BIT_MAXIMUM);
1062 }
1063 }
1064 }
1065
1066 int colorSize = _buffer->getColorSize();
1067 if (colorSize == 0) {
1068 return STOP_RECURSION;
1069 }
1070 HeightfieldDataPointer color = info.inputValues.at(1).getInlineValue<HeightfieldDataPointer>();
1071 if (!color) {
1072 return STOP_RECURSION;
1073 }
1074 const Box& colorBounds = _buffer->getColorBounds();
1075 overlap = colorBounds.getIntersection(overlap);
1076 float colorIncrement = _buffer->getColorIncrement();
1077 destX = (overlap.minimum.x - colorBounds.minimum.x) / colorIncrement;
1078 destY = (overlap.minimum.z - colorBounds.minimum.z) / colorIncrement;
1079 destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) / colorIncrement);
1080 destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) / colorIncrement);
1081 dest = _buffer->getColor().data() + (destY * colorSize + destX) * HeightfieldData::COLOR_BYTES;
1082 int destStride = colorSize * HeightfieldData::COLOR_BYTES;
1083 int destBytes = destWidth * HeightfieldData::COLOR_BYTES;
1084
1085 const QByteArray& srcColor = color->getContents();
1086 srcSize = glm::sqrt(srcColor.size() / HeightfieldData::COLOR_BYTES);
1087 int srcStride = srcSize * HeightfieldData::COLOR_BYTES;
1088 srcIncrement = info.size / srcSize;
1089
1090 if (srcIncrement == colorIncrement) {
1091 // easy case: same resolution
1092 int srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement;
1093 int srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement;
1094
1095 const char* src = srcColor.constData() + (srcY * srcSize + srcX) * HeightfieldData::COLOR_BYTES;
1096 for (int y = 0; y < destHeight; y++, src += srcStride, dest += destStride) {
1097 memcpy(dest, src, destBytes);
1098 }
1099 } else {
1100 // more difficult: different resolutions
1101 float srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement;
1102 float srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement;
1103 float srcAdvance = colorIncrement / srcIncrement;
1104 for (int y = 0; y < destHeight; y++, dest += destStride, srcY += srcAdvance) {
1105 const char* src = srcColor.constData() + (int)srcY * srcStride;
1106 float lineSrcX = srcX;
1107 for (char* lineDest = dest, *end = dest + destBytes; lineDest != end; lineDest += HeightfieldData::COLOR_BYTES,
1108 lineSrcX += srcAdvance) {
1109 const char* lineSrc = src + (int)lineSrcX * HeightfieldData::COLOR_BYTES;
1110 lineDest[0] = lineSrc[0];
1111 lineDest[1] = lineSrc[1];
1112 lineDest[2] = lineSrc[2];
1113 }
1114 }
1115 }
1116 }
1117 return STOP_RECURSION;
1118}
1119
1120class HeightfieldRegionVisitor : public MetavoxelVisitor {
1121public:
1122
1123 QVector<Box> regions;
1124 Box regionBounds;
1125
1126 HeightfieldRegionVisitor(const MetavoxelLOD& lod);
556 1127
557 virtual int visit(MetavoxelInfo& info);1128 virtual int visit(MetavoxelInfo& info);
1129
1130private:
1131
1132 void addRegion(const Box& unextended, const Box& extended);
1133
1134 QVector<Box> _intersections;
1135 HeightfieldFetchVisitor _fetchVisitor;
558};1136};
559 1137
560HeightfieldAugmentVisitor::HeightfieldAugmentVisitor(const MetavoxelLOD& lod) :1138HeightfieldRegionVisitor::HeightfieldRegionVisitor(const MetavoxelLOD& lod) :
561 MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute() <<1139 MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute() <<
562 AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), QVector<AttributePointer>() <<1140 AttributeRegistry::getInstance()->getHeightfieldColorAttribute() <<
563 Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), lod) {1141 Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector<AttributePointer>() <<
564}1142 Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), lod),
565 1143 regionBounds(glm::vec3(FLT_MAX, FLT_MAX, FLT_MAX), glm::vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX)),
566int HeightfieldAugmentVisitor::visit(MetavoxelInfo& info) {1144 _fetchVisitor(lod, _intersections) {
567 if (info.isLeaf) {1145}
568 HeightfieldBuffer* buffer = NULL;1146
569 HeightfieldDataPointer height = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>();1147int HeightfieldRegionVisitor::visit(MetavoxelInfo& info) {
570 if (height) {1148 if (!info.isLeaf) {
571 HeightfieldDataPointer color = info.inputValues.at(1).getInlineValue<HeightfieldDataPointer>();1149 return DEFAULT_ORDER;
572 buffer = new HeightfieldBuffer(info.minimum, info.size, height->getContents(),1150 }
573 color ? color->getContents() : QByteArray());1151 HeightfieldBuffer* buffer = NULL;
1152 HeightfieldDataPointer height = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>();
1153 if (height) {
1154 const QByteArray& heightContents = height->getContents();
1155 int size = glm::sqrt(heightContents.size());
1156 int extendedSize = size + HeightfieldBuffer::HEIGHT_EXTENSION;
1157 int heightContentsSize = extendedSize * extendedSize;
1158
1159 HeightfieldDataPointer color = info.inputValues.at(1).getInlineValue<HeightfieldDataPointer>();
1160 int colorContentsSize = 0;
1161 if (color) {
1162 const QByteArray& colorContents = color->getContents();
1163 int colorSize = glm::sqrt(colorContents.size() / HeightfieldData::COLOR_BYTES);
1164 int extendedColorSize = colorSize + HeightfieldBuffer::SHARED_EDGE;
1165 colorContentsSize = extendedColorSize * extendedColorSize * HeightfieldData::COLOR_BYTES;
574 }1166 }
575 info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(buffer)));1167
1168 const HeightfieldBuffer* existingBuffer = static_cast<const HeightfieldBuffer*>(
1169 info.inputValues.at(2).getInlineValue<BufferDataPointer>().data());
1170 Box bounds = info.getBounds();
1171 if (existingBuffer && existingBuffer->getHeight().size() == heightContentsSize &&
1172 existingBuffer->getColor().size() == colorContentsSize) {
1173 // we already have a buffer of the correct resolution
1174 addRegion(bounds, existingBuffer->getHeightBounds());
1175 return STOP_RECURSION;
1176 }
1177 // we must create a new buffer and update its borders
1178 buffer = new HeightfieldBuffer(info.minimum, info.size, QByteArray(heightContentsSize, 0),
1179 QByteArray(colorContentsSize, 0));
1180 const Box& heightBounds = buffer->getHeightBounds();
1181 addRegion(bounds, heightBounds);
1182
1183 _intersections.clear();
1184 _intersections.append(Box(heightBounds.minimum,
1185 glm::vec3(bounds.maximum.x, heightBounds.maximum.y, bounds.minimum.z)));
1186 _intersections.append(Box(glm::vec3(bounds.maximum.x, heightBounds.minimum.y, heightBounds.minimum.z),
1187 glm::vec3(heightBounds.maximum.x, heightBounds.maximum.y, bounds.maximum.z)));
1188 _intersections.append(Box(glm::vec3(bounds.minimum.x, heightBounds.minimum.y, bounds.maximum.z),
1189 heightBounds.maximum));
1190 _intersections.append(Box(glm::vec3(heightBounds.minimum.x, heightBounds.minimum.y, bounds.minimum.z),
1191 glm::vec3(bounds.minimum.x, heightBounds.maximum.y, heightBounds.maximum.z)));
1192
1193 _fetchVisitor.init(buffer);
1194 _data->guide(_fetchVisitor);
1195 }
1196 info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(buffer)));
1197 return STOP_RECURSION;
1198}
1199
1200void HeightfieldRegionVisitor::addRegion(const Box& unextended, const Box& extended) {
1201 regions.append(unextended);
1202 regionBounds.add(extended);
1203}
1204
1205class HeightfieldUpdateVisitor : public MetavoxelVisitor {
1206public:
1207
1208 HeightfieldUpdateVisitor(const MetavoxelLOD& lod, const QVector<Box>& regions, const Box& regionBounds);
1209
1210 virtual int visit(MetavoxelInfo& info);
1211
1212private:
1213
1214 const QVector<Box>& _regions;
1215 const Box& _regionBounds;
1216 QVector<Box> _intersections;
1217 HeightfieldFetchVisitor _fetchVisitor;
1218};
1219
1220HeightfieldUpdateVisitor::HeightfieldUpdateVisitor(const MetavoxelLOD& lod, const QVector<Box>& regions,
1221 const Box& regionBounds) :
1222 MetavoxelVisitor(QVector<AttributePointer>() <<
1223 Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector<AttributePointer>() <<
1224 Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), lod),
1225 _regions(regions),
1226 _regionBounds(regionBounds),
1227 _fetchVisitor(lod, _intersections) {
1228}
1229
1230int HeightfieldUpdateVisitor::visit(MetavoxelInfo& info) {
1231 if (!info.getBounds().intersects(_regionBounds)) {
1232 return STOP_RECURSION;
1233 }
1234 if (!info.isLeaf) {
1235 return DEFAULT_ORDER;
1236 }
1237 const HeightfieldBuffer* buffer = static_cast<const HeightfieldBuffer*>(
1238 info.inputValues.at(0).getInlineValue<BufferDataPointer>().data());
1239 if (!buffer) {
1240 return STOP_RECURSION;
1241 }
1242 _intersections.clear();
1243 foreach (const Box& region, _regions) {
1244 if (region.intersects(buffer->getHeightBounds())) {
1245 _intersections.append(region.getIntersection(buffer->getHeightBounds()));
1246 }
1247 }
1248 if (_intersections.isEmpty()) {
576 return STOP_RECURSION;1249 return STOP_RECURSION;
577 }1250 }
578 return DEFAULT_ORDER;1251 HeightfieldBuffer* newBuffer = new HeightfieldBuffer(info.minimum, info.size,
1252 buffer->getHeight(), buffer->getColor());
1253 _fetchVisitor.init(newBuffer);
1254 _data->guide(_fetchVisitor);
1255 info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(newBuffer)));
1256 return STOP_RECURSION;
579}1257}
580 1258
581void DefaultMetavoxelRendererImplementation::augment(MetavoxelData& data, const MetavoxelData& previous,1259void DefaultMetavoxelRendererImplementation::augment(MetavoxelData& data, const MetavoxelData& previous,
@@ -602,8 +1280,12 @@ void DefaultMetavoxelRendererImplementation::augment(MetavoxelData& data, const · 20 unmodified lines
602 PointAugmentVisitor pointAugmentVisitor(lod);1280 PointAugmentVisitor pointAugmentVisitor(lod);
603 data.guideToDifferent(expandedPrevious, pointAugmentVisitor);1281 data.guideToDifferent(expandedPrevious, pointAugmentVisitor);
604 1282
605 HeightfieldAugmentVisitor heightfieldAugmentVisitor(lod);1283 HeightfieldRegionVisitor heightfieldRegionVisitor(lod);
606 data.guideToDifferent(expandedPrevious, heightfieldAugmentVisitor);1284 data.guideToDifferent(expandedPrevious, heightfieldRegionVisitor);
1285
1286 HeightfieldUpdateVisitor heightfieldUpdateVisitor(lod, heightfieldRegionVisitor.regions,
1287 heightfieldRegionVisitor.regionBounds);
1288 data.guide(heightfieldUpdateVisitor);
607}1289}
608 1290
609class SpannerSimulateVisitor : public SpannerVisitor {1291class SpannerSimulateVisitor : public SpannerVisitor {
@@ -675,7 +1357,7 @@ bool SpannerRenderVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, · 65 unmodified lines
675class BufferRenderVisitor : public MetavoxelVisitor {1357class BufferRenderVisitor : public MetavoxelVisitor {
676public:1358public:
677 1359
678 BufferRenderVisitor(const AttributePointer& attribute, const MetavoxelLOD& lod);1360 BufferRenderVisitor(const AttributePointer& attribute);
679 1361
680 virtual int visit(MetavoxelInfo& info);1362 virtual int visit(MetavoxelInfo& info);
681 1363
@@ -685,8 +1367,8 @@ private: · 3 unmodified lines
685 int _containmentDepth;1367 int _containmentDepth;
686};1368};
687 1369
688BufferRenderVisitor::BufferRenderVisitor(const AttributePointer& attribute, const MetavoxelLOD& lod) :1370BufferRenderVisitor::BufferRenderVisitor(const AttributePointer& attribute) :
689 MetavoxelVisitor(QVector<AttributePointer>() << attribute, QVector<AttributePointer>(), lod),1371 MetavoxelVisitor(QVector<AttributePointer>() << attribute),
690 _order(encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())),1372 _order(encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())),
691 _containmentDepth(INT_MAX) {1373 _containmentDepth(INT_MAX) {
692}1374}
@@ -700,11 +1382,14 @@ int BufferRenderVisitor::visit(MetavoxelInfo& info) { · 7 unmodified lines
700 }1382 }
701 _containmentDepth = (intersection == Frustum::CONTAINS_INTERSECTION) ? _depth : INT_MAX;1383 _containmentDepth = (intersection == Frustum::CONTAINS_INTERSECTION) ? _depth : INT_MAX;
702 }1384 }
1385 if (!info.isLeaf) {
1386 return _order;
1387 }
703 BufferDataPointer buffer = info.inputValues.at(0).getInlineValue<BufferDataPointer>();1388 BufferDataPointer buffer = info.inputValues.at(0).getInlineValue<BufferDataPointer>();
704 if (buffer) {1389 if (buffer) {
705 buffer->render();1390 buffer->render();
706 }1391 }
707 return info.isLeaf ? STOP_RECURSION : _order;1392 return STOP_RECURSION;
708}1393}
709 1394
710void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod) {1395void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod) {
@@ -733,7 +1418,7 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox · 22 unmodified lines
733 1418
734 glDisable(GL_BLEND);1419 glDisable(GL_BLEND);
735 1420
736 BufferRenderVisitor pointRenderVisitor(Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), lod);1421 BufferRenderVisitor pointRenderVisitor(Application::getInstance()->getMetavoxels()->getPointBufferAttribute());
737 data.guide(pointRenderVisitor);1422 data.guide(pointRenderVisitor);
738 1423
739 glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);1424 glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
@@ -749,16 +1434,34 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox · 9 unmodified lines
749 1434
750 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);1435 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
751 1436
752 _heightfieldProgram.bind();1437 ProgramObject* program = &_heightfieldProgram;
1438 if (Menu::getInstance()->getShadowsEnabled()) {
1439 if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) {
1440 program = &_cascadedShadowMapHeightfieldProgram;
1441 program->bind();
1442 program->setUniform(_shadowDistancesLocation, Application::getInstance()->getShadowDistances());
1443
1444 } else {
1445 program = &_shadowMapHeightfieldProgram;
1446 }
1447 glActiveTexture(GL_TEXTURE2);
1448 glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID());
1449 glActiveTexture(GL_TEXTURE0);
1450 }
1451
1452 program->bind();
753 1453
754 glEnableClientState(GL_TEXTURE_COORD_ARRAY);1454 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
755 1455
756 BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(),1456 BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute());
757 lod);
758 data.guide(heightfieldRenderVisitor);1457 data.guide(heightfieldRenderVisitor);
759 1458
760 _heightfieldProgram.release();1459 program->release();
761 1460
1461 glActiveTexture(GL_TEXTURE2);
1462 glBindTexture(GL_TEXTURE_2D, 0);
1463 glActiveTexture(GL_TEXTURE0);
1464
762 glDisableClientState(GL_TEXTURE_COORD_ARRAY);1465 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
763 glDisableClientState(GL_VERTEX_ARRAY);1466 glDisableClientState(GL_VERTEX_ARRAY);
764 1467
@@ -771,6 +1474,15 @@ ProgramObject DefaultMetavoxelRendererImplementation::_pointProgram; · 6 unmodified lines
771int DefaultMetavoxelRendererImplementation::_pointScaleLocation;1474int DefaultMetavoxelRendererImplementation::_pointScaleLocation;
772ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldProgram;1475ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldProgram;
773int DefaultMetavoxelRendererImplementation::_heightScaleLocation;1476int DefaultMetavoxelRendererImplementation::_heightScaleLocation;
1477int DefaultMetavoxelRendererImplementation::_colorScaleLocation;
1478ProgramObject DefaultMetavoxelRendererImplementation::_shadowMapHeightfieldProgram;
1479int DefaultMetavoxelRendererImplementation::_shadowMapHeightScaleLocation;
1480int DefaultMetavoxelRendererImplementation::_shadowMapColorScaleLocation;
1481ProgramObject DefaultMetavoxelRendererImplementation::_cascadedShadowMapHeightfieldProgram;
1482int DefaultMetavoxelRendererImplementation::_cascadedShadowMapHeightScaleLocation;
1483int DefaultMetavoxelRendererImplementation::_cascadedShadowMapColorScaleLocation;
1484int DefaultMetavoxelRendererImplementation::_shadowDistancesLocation;
1485ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldCursorProgram;
774 1486
775static void enableClipPlane(GLenum plane, float x, float y, float z, float w) {1487static void enableClipPlane(GLenum plane, float x, float y, float z, float w) {
776 GLdouble coefficients[] = { x, y, z, w };1488 GLdouble coefficients[] = { x, y, z, w };
interface/src/MetavoxelSystem.h+61−9
@@ -43,6 +43,12 @@ public: · 42 unmodified lines
43 void simulate(float deltaTime);43 void simulate(float deltaTime);
44 void render();44 void render();
45 45
46 void renderHeightfieldCursor(const glm::vec3& position, float radius);
47
48 bool findFirstRayHeightfieldIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance);
49
50 Q_INVOKABLE float getHeightfieldHeight(const glm::vec3& location);
51
46 Q_INVOKABLE void deleteTextures(int heightID, int colorID);52 Q_INVOKABLE void deleteTextures(int heightID, int colorID);
47 53
48protected:54protected:
@@ -105,7 +111,7 @@ public: · 56 unmodified lines
105 111
106 virtual ~BufferData();112 virtual ~BufferData();
107 113
108 virtual void render() = 0;114 virtual void render(bool cursor = false) = 0;
109};115};
110 116
111typedef QExplicitlySharedDataPointer<BufferData> BufferDataPointer;117typedef QExplicitlySharedDataPointer<BufferData> BufferDataPointer;
@@ -116,7 +122,7 @@ public: · 4 unmodified lines
116 122
117 PointBuffer(const BufferPointVector& points);123 PointBuffer(const BufferPointVector& points);
118 124
119 virtual void render();125 virtual void render(bool cursor = false);
120 126
121private:127private:
122 128
@@ -129,29 +135,50 @@ private: · 6 unmodified lines
129class HeightfieldBuffer : public BufferData {135class HeightfieldBuffer : public BufferData {
130public:136public:
131 137
132 /// Creates a new heightfield buffer.138 static const int HEIGHT_BORDER;
133 /// \param clearAfterLoading if true, clear the data arrays after we load them into textures in order to reclaim the space139 static const int SHARED_EDGE;
134 HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color,140 static const int HEIGHT_EXTENSION;
135 bool clearAfterLoading = true);141
142 HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color);
136 ~HeightfieldBuffer();143 ~HeightfieldBuffer();
137 144
138 const glm::vec3& getTranslation() const { return _translation; }145 const glm::vec3& getTranslation() const { return _translation; }
146 float getScale() const { return _scale; }
147
148 const Box& getHeightBounds() const { return _heightBounds; }
149 const Box& getColorBounds() const { return _colorBounds; }
139 150
151 QByteArray& getHeight() { return _height; }
140 const QByteArray& getHeight() const { return _height; }152 const QByteArray& getHeight() const { return _height; }
153
154 QByteArray& getColor() { return _color; }
141 const QByteArray& getColor() const { return _color; }155 const QByteArray& getColor() const { return _color; }
142 156
143 virtual void render();157 QByteArray getUnextendedHeight() const;
158 QByteArray getUnextendedColor() const;
159
160 int getHeightSize() const { return _heightSize; }
161 float getHeightIncrement() const { return _heightIncrement; }
162
163 int getColorSize() const { return _colorSize; }
164 float getColorIncrement() const { return _colorIncrement; }
165
166 virtual void render(bool cursor = false);
144 167
145private:168private:
146 169
147 glm::vec3 _translation;170 glm::vec3 _translation;
148 float _scale;171 float _scale;
172 Box _heightBounds;
173 Box _colorBounds;
149 QByteArray _height;174 QByteArray _height;
150 QByteArray _color;175 QByteArray _color;
151 bool _clearAfterLoading;
152 GLuint _heightTextureID;176 GLuint _heightTextureID;
153 GLuint _colorTextureID;177 GLuint _colorTextureID;
154 int _heightSize;178 int _heightSize;
179 float _heightIncrement;
180 int _colorSize;
181 float _colorIncrement;
155 182
156 typedef QPair<QOpenGLBuffer, QOpenGLBuffer> BufferPair; 183 typedef QPair<QOpenGLBuffer, QOpenGLBuffer> BufferPair;
157 static QHash<int, BufferPair> _bufferPairs;184 static QHash<int, BufferPair> _bufferPairs;
@@ -180,6 +207,8 @@ public: · 22 unmodified lines
180 Q_INVOKABLE BufferDataAttribute(const QString& name = QString());207 Q_INVOKABLE BufferDataAttribute(const QString& name = QString());
181 208
182 virtual bool merge(void*& parent, void* children[], bool postRead = false) const;209 virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
210
211 virtual AttributeValue inherit(const AttributeValue& parentValue) const;
183};212};
184 213
185/// Renders metavoxels as points.214/// Renders metavoxels as points.
@@ -192,7 +221,18 @@ public: · 6 unmodified lines
192 221
193 static ProgramObject& getHeightfieldProgram() { return _heightfieldProgram; }222 static ProgramObject& getHeightfieldProgram() { return _heightfieldProgram; }
194 static int getHeightScaleLocation() { return _heightScaleLocation; }223 static int getHeightScaleLocation() { return _heightScaleLocation; }
195 224 static int getColorScaleLocation() { return _colorScaleLocation; }
225
226 static ProgramObject& getShadowMapHeightfieldProgram() { return _shadowMapHeightfieldProgram; }
227 static int getShadowMapHeightScaleLocation() { return _shadowMapHeightScaleLocation; }
228 static int getShadowMapColorScaleLocation() { return _shadowMapColorScaleLocation; }
229
230 static ProgramObject& getCascadedShadowMapHeightfieldProgram() { return _cascadedShadowMapHeightfieldProgram; }
231 static int getCascadedShadowMapHeightScaleLocation() { return _cascadedShadowMapHeightScaleLocation; }
232 static int getCascadedShadowMapColorScaleLocation() { return _cascadedShadowMapColorScaleLocation; }
233
234 static ProgramObject& getHeightfieldCursorProgram() { return _heightfieldCursorProgram; }
235
196 Q_INVOKABLE DefaultMetavoxelRendererImplementation();236 Q_INVOKABLE DefaultMetavoxelRendererImplementation();
197 237
198 virtual void augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod);238 virtual void augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod);
@@ -206,6 +246,18 @@ private: · 7 unmodified lines
206 246
207 static ProgramObject _heightfieldProgram;247 static ProgramObject _heightfieldProgram;
208 static int _heightScaleLocation;248 static int _heightScaleLocation;
249 static int _colorScaleLocation;
250
251 static ProgramObject _shadowMapHeightfieldProgram;
252 static int _shadowMapHeightScaleLocation;
253 static int _shadowMapColorScaleLocation;
254
255 static ProgramObject _cascadedShadowMapHeightfieldProgram;
256 static int _cascadedShadowMapHeightScaleLocation;
257 static int _cascadedShadowMapColorScaleLocation;
258 static int _shadowDistancesLocation;
259
260 static ProgramObject _heightfieldCursorProgram;
209};261};
210 262
211/// Base class for spanner renderers; provides clipping.263/// Base class for spanner renderers; provides clipping.
interface/src/avatar/Head.cpp+0−3
@@ -163,9 +163,6 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { · 162 unmodified lines
163 }163 }
164 _eyePosition = calculateAverageEyePosition();164 _eyePosition = calculateAverageEyePosition();
165 165
166 float velocityFilter = glm::clamp(1.0f - glm::length(_filteredEyePosition - _eyePosition), 0.0f, 1.0f);
167 _filteredEyePosition = velocityFilter * _filteredEyePosition + (1.0f - velocityFilter) * _eyePosition;
168
169}166}
170 167
171void Head::relaxLean(float deltaTime) {168void Head::relaxLean(float deltaTime) {
interface/src/avatar/Head.h+0−2
@@ -88,7 +88,6 @@ public: · 87 unmodified lines
88 88
89 const bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected)89 const bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected)
90 float getAverageLoudness() const { return _averageLoudness; }90 float getAverageLoudness() const { return _averageLoudness; }
91 glm::vec3 getFilteredEyePosition() const { return _filteredEyePosition; }
92 /// \return the point about which scaling occurs.91 /// \return the point about which scaling occurs.
93 glm::vec3 getScalePivot() const;92 glm::vec3 getScalePivot() const;
94 93
@@ -121,7 +120,6 @@ private: · 26 unmodified lines
121 glm::vec3 _leftEyePosition;120 glm::vec3 _leftEyePosition;
122 glm::vec3 _rightEyePosition;121 glm::vec3 _rightEyePosition;
123 glm::vec3 _eyePosition;122 glm::vec3 _eyePosition;
124 glm::vec3 _filteredEyePosition; // velocity filtered world space eye position
125 123
126 float _scale;124 float _scale;
127 float _lastLoudness;125 float _lastLoudness;
interface/src/avatar/MyAvatar.cpp+15−8
@@ -83,10 +83,11 @@ MyAvatar::MyAvatar() : · 82 unmodified lines
83 for (int i = 0; i < MAX_DRIVE_KEYS; i++) {83 for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
84 _driveKeys[i] = 0.0f;84 _driveKeys[i] = 0.0f;
85 }85 }
86 _skeletonModel.setEnableShapes(true);
87 // The skeleton is both a PhysicsEntity and Ragdoll, so we add it to the simulation once for each type.
88 _physicsSimulation.setEntity(&_skeletonModel);86 _physicsSimulation.setEntity(&_skeletonModel);
89 _physicsSimulation.setRagdoll(&_skeletonModel);87
88 _skeletonModel.setEnableShapes(true);
89 Ragdoll* ragdoll = _skeletonModel.buildRagdoll();
90 _physicsSimulation.setRagdoll(ragdoll);
90}91}
91 92
92MyAvatar::~MyAvatar() {93MyAvatar::~MyAvatar() {
@@ -206,9 +207,9 @@ void MyAvatar::simulate(float deltaTime) { · 113 unmodified lines
206 {207 {
207 PerformanceTimer perfTimer("ragdoll");208 PerformanceTimer perfTimer("ragdoll");
208 if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) {209 if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) {
209 const float minError = 0.01f;210 const float minError = 0.00001f;
210 const float maxIterations = 10;211 const float maxIterations = 3;
211 const quint64 maxUsec = 2000;212 const quint64 maxUsec = 4000;
212 _physicsSimulation.setTranslation(_position);213 _physicsSimulation.setTranslation(_position);
213 _physicsSimulation.stepForward(deltaTime, minError, maxIterations, maxUsec);214 _physicsSimulation.stepForward(deltaTime, minError, maxIterations, maxUsec);
214 } else {215 } else {
@@ -255,6 +256,12 @@ void MyAvatar::updateFromTrackers(float deltaTime) { · 40 unmodified lines
255 estimatedRotation.x *= -1.0f;256 estimatedRotation.x *= -1.0f;
256 estimatedRotation.z *= -1.0f;257 estimatedRotation.z *= -1.0f;
257 258
259 } else if (OculusManager::isConnected()) {
260 estimatedPosition = OculusManager::getRelativePosition();
261 estimatedPosition.x *= -1.0f;
262
263 const float OCULUS_LEAN_SCALE = 0.05f;
264 estimatedPosition /= OCULUS_LEAN_SCALE;
258 } else {265 } else {
259 FaceTracker* tracker = Application::getInstance()->getActiveFaceTracker();266 FaceTracker* tracker = Application::getInstance()->getActiveFaceTracker();
260 if (tracker) {267 if (tracker) {
@@ -1598,10 +1605,10 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) { · 1337 unmodified lines
1598 if (simulation != &(_physicsSimulation)) {1605 if (simulation != &(_physicsSimulation)) {
1599 skeleton->setEnableShapes(true);1606 skeleton->setEnableShapes(true);
1600 _physicsSimulation.addEntity(skeleton);1607 _physicsSimulation.addEntity(skeleton);
1601 _physicsSimulation.addRagdoll(skeleton);1608 _physicsSimulation.addRagdoll(skeleton->getRagdoll());
1602 }1609 }
1603 } else if (simulation == &(_physicsSimulation)) {1610 } else if (simulation == &(_physicsSimulation)) {
1604 _physicsSimulation.removeRagdoll(skeleton);1611 _physicsSimulation.removeRagdoll(skeleton->getRagdoll());
1605 _physicsSimulation.removeEntity(skeleton);1612 _physicsSimulation.removeEntity(skeleton);
1606 skeleton->setEnableShapes(false);1613 skeleton->setEnableShapes(false);
1607 }1614 }
interface/src/avatar/SkeletonModel.cpp+65−148
@@ -23,13 +23,19 @@ · 22 unmodified lines
23#include "Menu.h"23#include "Menu.h"
24#include "MuscleConstraint.h"24#include "MuscleConstraint.h"
25#include "SkeletonModel.h"25#include "SkeletonModel.h"
26#include "SkeletonRagdoll.h"
26 27
27SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : 28SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
28 Model(parent),29 Model(parent),
29 Ragdoll(),
30 _owningAvatar(owningAvatar),30 _owningAvatar(owningAvatar),
31 _boundingShape(),31 _boundingShape(),
32 _boundingShapeLocalOffset(0.0f) {32 _boundingShapeLocalOffset(0.0f),
33 _ragdoll(NULL) {
34}
35
36SkeletonModel::~SkeletonModel() {
37 delete _ragdoll;
38 _ragdoll = NULL;
33}39}
34 40
35void SkeletonModel::setJointStates(QVector<JointState> states) {41void SkeletonModel::setJointStates(QVector<JointState> states) {
@@ -155,9 +161,6 @@ void SkeletonModel::getBodyShapes(QVector<const Shape*>& shapes) const { · 119 unmodified lines
155void SkeletonModel::renderIKConstraints() {161void SkeletonModel::renderIKConstraints() {
156 renderJointConstraints(getRightHandJointIndex());162 renderJointConstraints(getRightHandJointIndex());
157 renderJointConstraints(getLeftHandJointIndex());163 renderJointConstraints(getLeftHandJointIndex());
158 //if (isActive() && _owningAvatar->isMyAvatar()) {
159 // renderRagdoll();
160 //}
161}164}
162 165
163class IndexValue {166class IndexValue {
@@ -432,6 +435,10 @@ bool SkeletonModel::getHeadPosition(glm::vec3& headPosition) const { · 268 unmodified lines
432}435}
433 436
434bool SkeletonModel::getNeckPosition(glm::vec3& neckPosition) const {437bool SkeletonModel::getNeckPosition(glm::vec3& neckPosition) const {
438 if (_owningAvatar->isMyAvatar() &&
439 Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) {
440 return isActive() && getVisibleJointPositionInWorldFrame(_geometry->getFBXGeometry().neckJointIndex, neckPosition);
441 }
435 return isActive() && getJointPositionInWorldFrame(_geometry->getFBXGeometry().neckJointIndex, neckPosition);442 return isActive() && getJointPositionInWorldFrame(_geometry->getFBXGeometry().neckJointIndex, neckPosition);
436}443}
437 444
@@ -445,11 +452,16 @@ bool SkeletonModel::getNeckParentRotationFromDefaultOrientation(glm::quat& neckP · 7 unmodified lines
445 }452 }
446 int parentIndex = geometry.joints.at(geometry.neckJointIndex).parentIndex;453 int parentIndex = geometry.joints.at(geometry.neckJointIndex).parentIndex;
447 glm::quat worldFrameRotation;454 glm::quat worldFrameRotation;
448 if (getJointRotationInWorldFrame(parentIndex, worldFrameRotation)) {455 bool success = false;
456 if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) {
457 success = getVisibleJointRotationInWorldFrame(parentIndex, worldFrameRotation);
458 } else {
459 success = getJointRotationInWorldFrame(parentIndex, worldFrameRotation);
460 }
461 if (success) {
449 neckParentRotation = worldFrameRotation * _jointStates[parentIndex].getFBXJoint().inverseDefaultRotation;462 neckParentRotation = worldFrameRotation * _jointStates[parentIndex].getFBXJoint().inverseDefaultRotation;
450 return true;
451 }463 }
452 return false;464 return success;
453}465}
454 466
455bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const {467bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const {
@@ -480,21 +492,25 @@ bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& seco · 24 unmodified lines
480}492}
481 493
482void SkeletonModel::renderRagdoll() {494void SkeletonModel::renderRagdoll() {
495 if (!_ragdoll) {
496 return;
497 }
498 const QVector<VerletPoint>& points = _ragdoll->getPoints();
483 const int BALL_SUBDIVISIONS = 6;499 const int BALL_SUBDIVISIONS = 6;
484 glDisable(GL_DEPTH_TEST);500 glDisable(GL_DEPTH_TEST);
485 glDisable(GL_LIGHTING);501 glDisable(GL_LIGHTING);
486 glPushMatrix();502 glPushMatrix();
487 503
488 Application::getInstance()->loadTranslatedViewMatrix(_translation);504 Application::getInstance()->loadTranslatedViewMatrix(_translation);
489 int numPoints = _ragdollPoints.size();505 int numPoints = points.size();
490 float alpha = 0.3f;506 float alpha = 0.3f;
491 float radius1 = 0.008f;507 float radius1 = 0.008f;
492 float radius2 = 0.01f;508 float radius2 = 0.01f;
493 glm::vec3 simulationTranslation = getTranslationInSimulationFrame();509 glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame();
494 for (int i = 0; i < numPoints; ++i) {510 for (int i = 0; i < numPoints; ++i) {
495 glPushMatrix();511 glPushMatrix();
496 // NOTE: ragdollPoints are in simulation-frame but we want them to be model-relative512 // NOTE: ragdollPoints are in simulation-frame but we want them to be model-relative
497 glm::vec3 position = _ragdollPoints[i]._position - simulationTranslation;513 glm::vec3 position = points[i]._position - simulationTranslation;
498 glTranslatef(position.x, position.y, position.z);514 glTranslatef(position.x, position.y, position.z);
499 // draw each point as a yellow hexagon with black border515 // draw each point as a yellow hexagon with black border
500 glColor4f(0.0f, 0.0f, 0.0f, alpha);516 glColor4f(0.0f, 0.0f, 0.0f, alpha);
@@ -508,109 +524,18 @@ void SkeletonModel::renderRagdoll() { · 7 unmodified lines
508 glEnable(GL_LIGHTING);524 glEnable(GL_LIGHTING);
509}525}
510 526
511// virtual
512void SkeletonModel::initRagdollPoints() {
513 clearRagdollConstraintsAndPoints();
514 _muscleConstraints.clear();
515
516 initRagdollTransform();
517 // one point for each joint
518 int numStates = _jointStates.size();
519 _ragdollPoints.fill(VerletPoint(), numStates);
520 for (int i = 0; i < numStates; ++i) {
521 const JointState& state = _jointStates.at(i);
522 // _ragdollPoints start in model-frame
523 _ragdollPoints[i].initPosition(state.getPosition());
524 }
525}
526
527void SkeletonModel::buildRagdollConstraints() {
528 // NOTE: the length of DistanceConstraints is computed and locked in at this time
529 // so make sure the ragdoll positions are in a normal configuration before here.
530 const int numPoints = _ragdollPoints.size();
531 assert(numPoints == _jointStates.size());
532
533 float minBone = FLT_MAX;
534 float maxBone = -FLT_MAX;
535 QMultiMap<int, int> families;
536 for (int i = 0; i < numPoints; ++i) {
537 const JointState& state = _jointStates.at(i);
538 int parentIndex = state.getParentIndex();
539 if (parentIndex == -1) {
540 FixedConstraint* anchor = new FixedConstraint(&_translationInSimulationFrame, &(_ragdollPoints[i]));
541 _fixedConstraints.push_back(anchor);
542 } else {
543 DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[i]), &(_ragdollPoints[parentIndex]));
544 bone->setDistance(state.getDistanceToParent());
545 _boneConstraints.push_back(bone);
546 families.insert(parentIndex, i);
547 }
548 float boneLength = glm::length(state.getPositionInParentFrame());
549 if (boneLength > maxBone) {
550 maxBone = boneLength;
551 } else if (boneLength < minBone) {
552 minBone = boneLength;
553 }
554 }
555 // Joints that have multiple children effectively have rigid constraints between the children
556 // in the parent frame, so we add DistanceConstraints between children in the same family.
557 QMultiMap<int, int>::iterator itr = families.begin();
558 while (itr != families.end()) {
559 QList<int> children = families.values(itr.key());
560 int numChildren = children.size();
561 if (numChildren > 1) {
562 for (int i = 1; i < numChildren; ++i) {
563 DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[i-1]]), &(_ragdollPoints[children[i]]));
564 _boneConstraints.push_back(bone);
565 }
566 if (numChildren > 2) {
567 DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[numChildren-1]]), &(_ragdollPoints[children[0]]));
568 _boneConstraints.push_back(bone);
569 }
570 }
571 ++itr;
572 }
573
574 float MAX_STRENGTH = 0.6f;
575 float MIN_STRENGTH = 0.05f;
576 // each joint gets a MuscleConstraint to its parent
577 for (int i = 1; i < numPoints; ++i) {
578 const JointState& state = _jointStates.at(i);
579 int p = state.getParentIndex();
580 if (p == -1) {
581 continue;
582 }
583 MuscleConstraint* constraint = new MuscleConstraint(&(_ragdollPoints[p]), &(_ragdollPoints[i]));
584 _muscleConstraints.push_back(constraint);
585
586 // Short joints are more susceptible to wiggle so we modulate the strength based on the joint's length:
587 // long = weak and short = strong.
588 constraint->setIndices(p, i);
589 float boneLength = glm::length(state.getPositionInParentFrame());
590
591 float strength = MIN_STRENGTH + (MAX_STRENGTH - MIN_STRENGTH) * (maxBone - boneLength) / (maxBone - minBone);
592 if (!families.contains(i)) {
593 // Although muscles only pull on the children not parents, nevertheless those joints that have
594 // parents AND children are more stable than joints at the end such as fingers. For such joints we
595 // bestow maximum strength which helps reduce wiggle.
596 strength = MAX_MUSCLE_STRENGTH;
597 }
598 constraint->setStrength(strength);
599 }
600
601}
602
603void SkeletonModel::updateVisibleJointStates() {527void SkeletonModel::updateVisibleJointStates() {
604 if (_showTrueJointTransforms) {528 if (_showTrueJointTransforms || !_ragdoll) {
605 // no need to update visible transforms529 // no need to update visible transforms
606 return;530 return;
607 }531 }
532 const QVector<VerletPoint>& ragdollPoints = _ragdoll->getPoints();
608 QVector<glm::vec3> points;533 QVector<glm::vec3> points;
609 points.reserve(_jointStates.size());534 points.reserve(_jointStates.size());
610 glm::quat invRotation = glm::inverse(_rotation);535 glm::quat invRotation = glm::inverse(_rotation);
611 for (int i = 0; i < _jointStates.size(); i++) {536 for (int i = 0; i < _jointStates.size(); i++) {
612 JointState& state = _jointStates[i];537 JointState& state = _jointStates[i];
613 points.push_back(_ragdollPoints[i]._position);538 points.push_back(ragdollPoints[i]._position);
614 539
615 // get the parent state (this is the state that we want to rotate)540 // get the parent state (this is the state that we want to rotate)
616 int parentIndex = state.getParentIndex();541 int parentIndex = state.getParentIndex();
@@ -644,15 +569,14 @@ void SkeletonModel::updateVisibleJointStates() { · 27 unmodified lines
644 }569 }
645}570}
646 571
647// virtual 572SkeletonRagdoll* SkeletonModel::buildRagdoll() {
648void SkeletonModel::stepRagdollForward(float deltaTime) {573 if (!_ragdoll) {
649 setRagdollTransform(_translation, _rotation);574 _ragdoll = new SkeletonRagdoll(this);
650 Ragdoll::stepRagdollForward(deltaTime);575 if (_enableShapes) {
651 updateMuscles();576 buildShapes();
652 int numConstraints = _muscleConstraints.size();577 }
653 for (int i = 0; i < numConstraints; ++i) {
654 _muscleConstraints[i]->enforce();
655 }578 }
579 return _ragdoll;
656}580}
657 581
658float DENSITY_OF_WATER = 1000.0f; // kg/m^3582float DENSITY_OF_WATER = 1000.0f; // kg/m^3
@@ -670,8 +594,13 @@ void SkeletonModel::buildShapes() { · 11 unmodified lines
670 return;594 return;
671 }595 }
672 596
673 initRagdollPoints();597 if (!_ragdoll) {
674 float massScale = getMassScale();598 _ragdoll = new SkeletonRagdoll(this);
599 }
600 _ragdoll->initPoints();
601 QVector<VerletPoint>& points = _ragdoll->getPoints();
602
603 float massScale = _ragdoll->getMassScale();
675 604
676 float uniformScale = extractUniformScale(_scale);605 float uniformScale = extractUniformScale(_scale);
677 const int numStates = _jointStates.size();606 const int numStates = _jointStates.size();
@@ -691,14 +620,14 @@ void SkeletonModel::buildShapes() { · 13 unmodified lines
691 Shape* shape = NULL;620 Shape* shape = NULL;
692 int parentIndex = joint.parentIndex;621 int parentIndex = joint.parentIndex;
693 if (type == Shape::SPHERE_SHAPE) {622 if (type == Shape::SPHERE_SHAPE) {
694 shape = new VerletSphereShape(radius, &(_ragdollPoints[i]));623 shape = new VerletSphereShape(radius, &(points[i]));
695 shape->setEntity(this);624 shape->setEntity(this);
696 _ragdollPoints[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume()));625 points[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume()));
697 } else if (type == Shape::CAPSULE_SHAPE) {626 } else if (type == Shape::CAPSULE_SHAPE) {
698 assert(parentIndex != -1);627 assert(parentIndex != -1);
699 shape = new VerletCapsuleShape(radius, &(_ragdollPoints[parentIndex]), &(_ragdollPoints[i]));628 shape = new VerletCapsuleShape(radius, &(points[parentIndex]), &(points[i]));
700 shape->setEntity(this);629 shape->setEntity(this);
701 _ragdollPoints[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume()));630 points[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume()));
702 } 631 }
703 if (parentIndex != -1) {632 if (parentIndex != -1) {
704 // always disable collisions between joint and its parent633 // always disable collisions between joint and its parent
@@ -708,7 +637,7 @@ void SkeletonModel::buildShapes() { · 3 unmodified lines
708 } else {637 } else {
709 // give the base joint a very large mass since it doesn't actually move638 // give the base joint a very large mass since it doesn't actually move
710 // in the local-frame simulation (it defines the origin)639 // in the local-frame simulation (it defines the origin)
711 _ragdollPoints[i].setMass(VERY_BIG_MASS);640 points[i].setMass(VERY_BIG_MASS);
712 }641 }
713 _shapes.push_back(shape);642 _shapes.push_back(shape);
714 }643 }
@@ -720,17 +649,11 @@ void SkeletonModel::buildShapes() { · 5 unmodified lines
720 // joints that are currently colliding.649 // joints that are currently colliding.
721 disableCurrentSelfCollisions();650 disableCurrentSelfCollisions();
722 651
723 buildRagdollConstraints();652 _ragdoll->buildConstraints();
724 653
725 // ... then move shapes back to current joint positions654 // ... then move shapes back to current joint positions
726 if (_ragdollPoints.size() == numStates) {655 _ragdoll->slamPointPositions();
727 int numStates = _jointStates.size();656 _ragdoll->enforceConstraints();
728 for (int i = 0; i < numStates; ++i) {
729 // ragdollPoints start in model-frame
730 _ragdollPoints[i].initPosition(_jointStates.at(i).getPosition());
731 }
732 }
733 enforceRagdollConstraints();
734}657}
735 658
736void SkeletonModel::moveShapesTowardJoints(float deltaTime) {659void SkeletonModel::moveShapesTowardJoints(float deltaTime) {
@@ -738,8 +661,9 @@ void SkeletonModel::moveShapesTowardJoints(float deltaTime) { · 1 unmodified line
738 // unravel a skelton that has become tangled in its constraints. So let's keep this661 // unravel a skelton that has become tangled in its constraints. So let's keep this
739 // around for a while just in case.662 // around for a while just in case.
740 const int numStates = _jointStates.size();663 const int numStates = _jointStates.size();
741 assert(_jointStates.size() == _ragdollPoints.size());664 QVector<VerletPoint>& ragdollPoints = _ragdoll->getPoints();
742 if (_ragdollPoints.size() != numStates) {665 assert(_jointStates.size() == ragdollPoints.size());
666 if (ragdollPoints.size() != numStates) {
743 return;667 return;
744 }668 }
745 669
@@ -748,32 +672,22 @@ void SkeletonModel::moveShapesTowardJoints(float deltaTime) { · 2 unmodified lines
748 float fraction = glm::clamp(deltaTime / RAGDOLL_FOLLOWS_JOINTS_TIMESCALE, 0.0f, 1.0f);672 float fraction = glm::clamp(deltaTime / RAGDOLL_FOLLOWS_JOINTS_TIMESCALE, 0.0f, 1.0f);
749 673
750 float oneMinusFraction = 1.0f - fraction; 674 float oneMinusFraction = 1.0f - fraction;
751 glm::vec3 simulationTranslation = getTranslationInSimulationFrame();675 glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame();
752 for (int i = 0; i < numStates; ++i) {676 for (int i = 0; i < numStates; ++i) {
753 // ragdollPoints are in simulation-frame but jointStates are in model-frame677 // ragdollPoints are in simulation-frame but jointStates are in model-frame
754 _ragdollPoints[i].initPosition(oneMinusFraction * _ragdollPoints[i]._position + 678 ragdollPoints[i].initPosition(oneMinusFraction * ragdollPoints[i]._position +
755 fraction * (simulationTranslation + _rotation * (_jointStates.at(i).getPosition())));679 fraction * (simulationTranslation + _rotation * (_jointStates.at(i).getPosition())));
756 }680 }
757}681}
758 682
759void SkeletonModel::updateMuscles() {
760 int numConstraints = _muscleConstraints.size();
761 for (int i = 0; i < numConstraints; ++i) {
762 MuscleConstraint* constraint = _muscleConstraints[i];
763 int j = constraint->getParentIndex();
764 int k = constraint->getChildIndex();
765 assert(j != -1 && k != -1);
766 // ragdollPoints are in simulation-frame but jointStates are in model-frame
767 constraint->setChildOffset(_rotation * (_jointStates.at(k).getPosition() - _jointStates.at(j).getPosition()));
768 }
769}
770
771void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) {683void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) {
772 // compute default joint transforms684 // compute default joint transforms
773 int numStates = _jointStates.size();685 int numStates = _jointStates.size();
774 QVector<glm::mat4> transforms;686 QVector<glm::mat4> transforms;
775 transforms.fill(glm::mat4(), numStates);687 transforms.fill(glm::mat4(), numStates);
776 688
689 QVector<VerletPoint>& ragdollPoints = _ragdoll->getPoints();
690
777 // compute the default transforms and slam the ragdoll positions accordingly691 // compute the default transforms and slam the ragdoll positions accordingly
778 // (which puts the shapes where we want them)692 // (which puts the shapes where we want them)
779 for (int i = 0; i < numStates; i++) {693 for (int i = 0; i < numStates; i++) {
@@ -782,7 +696,7 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { · 2 unmodified lines
782 int parentIndex = joint.parentIndex;696 int parentIndex = joint.parentIndex;
783 if (parentIndex == -1) {697 if (parentIndex == -1) {
784 transforms[i] = _jointStates[i].getTransform();698 transforms[i] = _jointStates[i].getTransform();
785 _ragdollPoints[i].initPosition(extractTranslation(transforms[i]));699 ragdollPoints[i].initPosition(extractTranslation(transforms[i]));
786 continue;700 continue;
787 }701 }
788 702
@@ -790,7 +704,7 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { · 1 unmodified line
790 transforms[i] = transforms[parentIndex] * glm::translate(joint.translation) 704 transforms[i] = transforms[parentIndex] * glm::translate(joint.translation)
791 * joint.preTransform * glm::mat4_cast(modifiedRotation) * joint.postTransform;705 * joint.preTransform * glm::mat4_cast(modifiedRotation) * joint.postTransform;
792 // setting the ragdollPoints here slams the VerletShapes into their default positions706 // setting the ragdollPoints here slams the VerletShapes into their default positions
793 _ragdollPoints[i].initPosition(extractTranslation(transforms[i]));707 ragdollPoints[i].initPosition(extractTranslation(transforms[i]));
794 }708 }
795 709
796 // compute bounding box that encloses all shapes710 // compute bounding box that encloses all shapes
@@ -909,9 +823,12 @@ const int BALL_SUBDIVISIONS = 10; · 112 unmodified lines
909 823
910// virtual824// virtual
911void SkeletonModel::renderJointCollisionShapes(float alpha) { 825void SkeletonModel::renderJointCollisionShapes(float alpha) {
826 if (!_ragdoll) {
827 return;
828 }
912 glPushMatrix();829 glPushMatrix();
913 Application::getInstance()->loadTranslatedViewMatrix(_translation);830 Application::getInstance()->loadTranslatedViewMatrix(_translation);
914 glm::vec3 simulationTranslation = getTranslationInSimulationFrame();831 glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame();
915 for (int i = 0; i < _shapes.size(); i++) { 832 for (int i = 0; i < _shapes.size(); i++) {
916 Shape* shape = _shapes[i];833 Shape* shape = _shapes[i];
917 if (!shape) { 834 if (!shape) {
interface/src/avatar/SkeletonModel.h+8−11
@@ -15,18 +15,20 @@ · 14 unmodified lines
15#include "renderer/Model.h"15#include "renderer/Model.h"
16 16
17#include <CapsuleShape.h>17#include <CapsuleShape.h>
18#include <Ragdoll.h>18#include "SkeletonRagdoll.h"
19 19
20class Avatar;20class Avatar;
21class MuscleConstraint;21class MuscleConstraint;
22class SkeletonRagdoll;
22 23
23/// A skeleton loaded from a model.24/// A skeleton loaded from a model.
24class SkeletonModel : public Model, public Ragdoll {25class SkeletonModel : public Model {
25 Q_OBJECT26 Q_OBJECT
26 27
27public:28public:
28 29
29 SkeletonModel(Avatar* owningAvatar, QObject* parent = NULL);30 SkeletonModel(Avatar* owningAvatar, QObject* parent = NULL);
31 ~SkeletonModel();
30 32
31 void setJointStates(QVector<JointState> states);33 void setJointStates(QVector<JointState> states);
32 34
@@ -96,12 +98,11 @@ public: · 63 unmodified lines
96 bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const;98 bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const;
97 99
98 virtual void updateVisibleJointStates();100 virtual void updateVisibleJointStates();
99
100 // virtual overrride from Ragdoll
101 virtual void stepRagdollForward(float deltaTime);
102 101
102 SkeletonRagdoll* buildRagdoll();
103 SkeletonRagdoll* getRagdoll() { return _ragdoll; }
104
103 void moveShapesTowardJoints(float fraction);105 void moveShapesTowardJoints(float fraction);
104 void updateMuscles();
105 106
106 void computeBoundingShape(const FBXGeometry& geometry);107 void computeBoundingShape(const FBXGeometry& geometry);
107 void renderBoundingCollisionShapes(float alpha);108 void renderBoundingCollisionShapes(float alpha);
@@ -115,10 +116,6 @@ public: · 7 unmodified lines
115 116
116protected:117protected:
117 118
118 // virtual overrrides from Ragdoll
119 void initRagdollPoints();
120 void buildRagdollConstraints();
121
122 void buildShapes();119 void buildShapes();
123 120
124 /// \param jointIndex index of joint in model121 /// \param jointIndex index of joint in model
@@ -147,7 +144,7 @@ private: · 22 unmodified lines
147 144
148 CapsuleShape _boundingShape;145 CapsuleShape _boundingShape;
149 glm::vec3 _boundingShapeLocalOffset;146 glm::vec3 _boundingShapeLocalOffset;
150 QVector<MuscleConstraint*> _muscleConstraints;147 SkeletonRagdoll* _ragdoll;
151};148};
152 149
153#endif // hifi_SkeletonModel_h150#endif // hifi_SkeletonModel_h
interface/src/avatar/SkeletonRagdoll.cpp+148−0
@@ -0,0 +1,148 @@
1//
2// SkeletonRagdoll.cpp
3// interface/src/avatar
4//
5// Created by Andrew Meadows 2014.08.14
6// Copyright 2014 High Fidelity, Inc.
7//
8// Distributed under the Apache License, Version 2.0.
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//
11
12#include <DistanceConstraint.h>
13#include <FixedConstraint.h>
14
15#include "SkeletonRagdoll.h"
16#include "MuscleConstraint.h"
17#include "../renderer/Model.h"
18
19SkeletonRagdoll::SkeletonRagdoll(Model* model) : Ragdoll(), _model(model) {
20 assert(_model);
21}
22
23SkeletonRagdoll::~SkeletonRagdoll() {
24}
25
26// virtual
27void SkeletonRagdoll::stepForward(float deltaTime) {
28 setTransform(_model->getTranslation(), _model->getRotation());
29 Ragdoll::stepForward(deltaTime);
30 updateMuscles();
31 int numConstraints = _muscleConstraints.size();
32 for (int i = 0; i < numConstraints; ++i) {
33 _muscleConstraints[i]->enforce();
34 }
35}
36
37void SkeletonRagdoll::slamPointPositions() {
38 QVector<JointState>& jointStates = _model->getJointStates();
39 int numStates = jointStates.size();
40 for (int i = 0; i < numStates; ++i) {
41 _points[i].initPosition(jointStates.at(i).getPosition());
42 }
43}
44
45// virtual
46void SkeletonRagdoll::initPoints() {
47 clearConstraintsAndPoints();
48 _muscleConstraints.clear();
49
50 initTransform();
51 // one point for each joint
52 QVector<JointState>& jointStates = _model->getJointStates();
53 int numStates = jointStates.size();
54 _points.fill(VerletPoint(), numStates);
55 slamPointPositions();
56}
57
58// virtual
59void SkeletonRagdoll::buildConstraints() {
60 QVector<JointState>& jointStates = _model->getJointStates();
61
62 // NOTE: the length of DistanceConstraints is computed and locked in at this time
63 // so make sure the ragdoll positions are in a normal configuration before here.
64 const int numPoints = _points.size();
65 assert(numPoints == jointStates.size());
66
67 float minBone = FLT_MAX;
68 float maxBone = -FLT_MAX;
69 QMultiMap<int, int> families;
70 for (int i = 0; i < numPoints; ++i) {
71 const JointState& state = jointStates.at(i);
72 int parentIndex = state.getParentIndex();
73 if (parentIndex == -1) {
74 FixedConstraint* anchor = new FixedConstraint(&_translationInSimulationFrame, &(_points[i]));
75 _fixedConstraints.push_back(anchor);
76 } else {
77 DistanceConstraint* bone = new DistanceConstraint(&(_points[i]), &(_points[parentIndex]));
78 bone->setDistance(state.getDistanceToParent());
79 _boneConstraints.push_back(bone);
80 families.insert(parentIndex, i);
81 }
82 float boneLength = glm::length(state.getPositionInParentFrame());
83 if (boneLength > maxBone) {
84 maxBone = boneLength;
85 } else if (boneLength < minBone) {
86 minBone = boneLength;
87 }
88 }
89 // Joints that have multiple children effectively have rigid constraints between the children
90 // in the parent frame, so we add DistanceConstraints between children in the same family.
91 QMultiMap<int, int>::iterator itr = families.begin();
92 while (itr != families.end()) {
93 QList<int> children = families.values(itr.key());
94 int numChildren = children.size();
95 if (numChildren > 1) {
96 for (int i = 1; i < numChildren; ++i) {
97 DistanceConstraint* bone = new DistanceConstraint(&(_points[children[i-1]]), &(_points[children[i]]));
98 _boneConstraints.push_back(bone);
99 }
100 if (numChildren > 2) {
101 DistanceConstraint* bone = new DistanceConstraint(&(_points[children[numChildren-1]]), &(_points[children[0]]));
102 _boneConstraints.push_back(bone);
103 }
104 }
105 ++itr;
106 }
107
108 float MAX_STRENGTH = 0.6f;
109 float MIN_STRENGTH = 0.05f;
110 // each joint gets a MuscleConstraint to its parent
111 for (int i = 1; i < numPoints; ++i) {
112 const JointState& state = jointStates.at(i);
113 int p = state.getParentIndex();
114 if (p == -1) {
115 continue;
116 }
117 MuscleConstraint* constraint = new MuscleConstraint(&(_points[p]), &(_points[i]));
118 _muscleConstraints.push_back(constraint);
119
120 // Short joints are more susceptible to wiggle so we modulate the strength based on the joint's length:
121 // long = weak and short = strong.
122 constraint->setIndices(p, i);
123 float boneLength = glm::length(state.getPositionInParentFrame());
124
125 float strength = MIN_STRENGTH + (MAX_STRENGTH - MIN_STRENGTH) * (maxBone - boneLength) / (maxBone - minBone);
126 if (!families.contains(i)) {
127 // Although muscles only pull on the children not parents, nevertheless those joints that have
128 // parents AND children are more stable than joints at the end such as fingers. For such joints we
129 // bestow maximum strength which helps reduce wiggle.
130 strength = MAX_MUSCLE_STRENGTH;
131 }
132 constraint->setStrength(strength);
133 }
134}
135
136void SkeletonRagdoll::updateMuscles() {
137 QVector<JointState>& jointStates = _model->getJointStates();
138 int numConstraints = _muscleConstraints.size();
139 glm::quat rotation = _model->getRotation();
140 for (int i = 0; i < numConstraints; ++i) {
141 MuscleConstraint* constraint = _muscleConstraints[i];
142 int j = constraint->getParentIndex();
143 int k = constraint->getChildIndex();
144 assert(j != -1 && k != -1);
145 // ragdollPoints are in simulation-frame but jointStates are in model-frame
146 constraint->setChildOffset(rotation * (jointStates.at(k).getPosition() - jointStates.at(j).getPosition()));
147 }
148}
interface/src/avatar/SkeletonRagdoll.h+42−0
@@ -0,0 +1,42 @@
1//
2// SkeletonkRagdoll.h
3// interface/src/avatar
4//
5// Created by Andrew Meadows 2014.08.14
6// Copyright 2014 High Fidelity, Inc.
7//
8// Distributed under the Apache License, Version 2.0.
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//
11
12#ifndef hifi_SkeletonRagdoll_h
13#define hifi_SkeletonRagdoll_h
14
15#include <QVector>
16
17#include <Ragdoll.h>
18
19#include "../renderer/JointState.h"
20
21class MuscleConstraint;
22class Model;
23
24class SkeletonRagdoll : public Ragdoll {
25public:
26
27 SkeletonRagdoll(Model* model);
28 virtual ~SkeletonRagdoll();
29
30 void slamPointPositions();
31 virtual void stepForward(float deltaTime);
32
33 virtual void initPoints();
34 virtual void buildConstraints();
35
36 void updateMuscles();
37private:
38 Model* _model;
39 QVector<MuscleConstraint*> _muscleConstraints;
40};
41
42#endif // hifi_SkeletonRagdoll_h
interface/src/devices/CaraFaceTracker.cpp+1−1
@@ -10,7 +10,7 @@ · 9 unmodified lines
10//10//
11 11
12#include "CaraFaceTracker.h"12#include "CaraFaceTracker.h"
13#include <SharedUtil.h>13#include <GLMHelpers.h>
14 14
15//qt15//qt
16#include <QJsonDocument>16#include <QJsonDocument>
interface/src/devices/DdeFaceTracker.cpp+42−5
@@ -178,6 +178,31 @@ float rescaleCoef(float ddeCoef) { · 177 unmodified lines
178 return (ddeCoef - DDE_MIN_RANGE) / (DDE_MAX_RANGE - DDE_MIN_RANGE);178 return (ddeCoef - DDE_MIN_RANGE) / (DDE_MAX_RANGE - DDE_MIN_RANGE);
179}179}
180 180
181const int MIN = 0;
182const int AVG = 1;
183const int MAX = 2;
184const float LONG_TERM_AVERAGE = 0.999f;
185
186
187void resetCoefficient(float * coefficient, float currentValue) {
188 coefficient[MIN] = coefficient[MAX] = coefficient[AVG] = currentValue;
189}
190
191float updateAndGetCoefficient(float * coefficient, float currentValue, bool scaleToRange = false) {
192 coefficient[MIN] = (currentValue < coefficient[MIN]) ? currentValue : coefficient[MIN];
193 coefficient[MAX] = (currentValue > coefficient[MAX]) ? currentValue : coefficient[MAX];
194 coefficient[AVG] = LONG_TERM_AVERAGE * coefficient[AVG] + (1.f - LONG_TERM_AVERAGE) * currentValue;
195 if (coefficient[MAX] > coefficient[MIN]) {
196 if (scaleToRange) {
197 return glm::clamp((currentValue - coefficient[AVG]) / (coefficient[MAX] - coefficient[MIN]), 0.f, 1.f);
198 } else {
199 return glm::clamp(currentValue - coefficient[AVG], 0.f, 1.f);
200 }
201 } else {
202 return 0.f;
203 }
204}
205
181void DdeFaceTracker::decodePacket(const QByteArray& buffer) {206void DdeFaceTracker::decodePacket(const QByteArray& buffer) {
182 if(buffer.size() > MIN_PACKET_SIZE) {207 if(buffer.size() > MIN_PACKET_SIZE) {
183 Packet packet;208 Packet packet;
@@ -189,14 +214,17 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { · 5 unmodified lines
189 memcpy(&translation, packet.translation, sizeof(packet.translation));214 memcpy(&translation, packet.translation, sizeof(packet.translation));
190 glm::quat rotation;215 glm::quat rotation;
191 memcpy(&rotation, &packet.rotation, sizeof(packet.rotation));216 memcpy(&rotation, &packet.rotation, sizeof(packet.rotation));
192 if (_reset) {217 if (_reset || (_lastReceiveTimestamp == 0)) {
193 memcpy(&_referenceTranslation, &translation, sizeof(glm::vec3));218 memcpy(&_referenceTranslation, &translation, sizeof(glm::vec3));
194 memcpy(&_referenceRotation, &rotation, sizeof(glm::quat));219 memcpy(&_referenceRotation, &rotation, sizeof(glm::quat));
220
221 resetCoefficient(_rightEye, packet.expressions[0]);
222 resetCoefficient(_leftEye, packet.expressions[1]);
195 _reset = false;223 _reset = false;
196 }224 }
197 225
198 // Compute relative translation226 // Compute relative translation
199 float LEAN_DAMPING_FACTOR = 40;227 float LEAN_DAMPING_FACTOR = 200.0f;
200 translation -= _referenceTranslation;228 translation -= _referenceTranslation;
201 translation /= LEAN_DAMPING_FACTOR;229 translation /= LEAN_DAMPING_FACTOR;
202 translation.x *= -1;230 translation.x *= -1;
@@ -208,10 +236,19 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { · 5 unmodified lines
208 _headTranslation = translation;236 _headTranslation = translation;
209 _headRotation = rotation;237 _headRotation = rotation;
210 238
239 if (_lastReceiveTimestamp == 0) {
240 // On first packet, reset coefficients
241 }
242
211 // Set blendshapes243 // Set blendshapes
212 float BLINK_MAGNIFIER = 2.0f;244 float EYE_MAGNIFIER = 4.0f;
213 _blendshapeCoefficients[_leftBlinkIndex] = rescaleCoef(packet.expressions[1]) * BLINK_MAGNIFIER;245
214 _blendshapeCoefficients[_rightBlinkIndex] = rescaleCoef(packet.expressions[0]) * BLINK_MAGNIFIER;246 float rightEye = (updateAndGetCoefficient(_rightEye, packet.expressions[0])) * EYE_MAGNIFIER;
247 _blendshapeCoefficients[_rightBlinkIndex] = rightEye;
248 float leftEye = (updateAndGetCoefficient(_leftEye, packet.expressions[1])) * EYE_MAGNIFIER;
249 _blendshapeCoefficients[_leftBlinkIndex] = leftEye;
250
251 // Right eye = packet.expressions[0];
215 252
216 float leftBrow = 1.0f - rescaleCoef(packet.expressions[14]);253 float leftBrow = 1.0f - rescaleCoef(packet.expressions[14]);
217 if (leftBrow < 0.5f) {254 if (leftBrow < 0.5f) {
interface/src/devices/DdeFaceTracker.h+4−0
@@ -84,6 +84,10 @@ private: · 83 unmodified lines
84 int _mouthSmileRightIndex;84 int _mouthSmileRightIndex;
85 85
86 int _jawOpenIndex;86 int _jawOpenIndex;
87
88 float _leftEye[3];
89 float _rightEye[3];
90
87};91};
88 92
89#endif // hifi_DdeFaceTracker_h93#endif // hifi_DdeFaceTracker_h
interface/src/devices/OculusManager.cpp+77−13
@@ -44,7 +44,7 @@ ovrFovPort OculusManager::_eyeFov[ovrEye_Count]; · 43 unmodified lines
44ovrEyeRenderDesc OculusManager::_eyeRenderDesc[ovrEye_Count];44ovrEyeRenderDesc OculusManager::_eyeRenderDesc[ovrEye_Count];
45ovrSizei OculusManager::_renderTargetSize;45ovrSizei OculusManager::_renderTargetSize;
46ovrVector2f OculusManager::_UVScaleOffset[ovrEye_Count][2];46ovrVector2f OculusManager::_UVScaleOffset[ovrEye_Count][2];
47GLuint OculusManager::_vertices[ovrEye_Count] = { 0, 0 };47GLuint OculusManager::_vertices[ovrEye_Count] = { 0, 0 };
48GLuint OculusManager::_indices[ovrEye_Count] = { 0, 0 };48GLuint OculusManager::_indices[ovrEye_Count] = { 0, 0 };
49GLsizei OculusManager::_meshSize[ovrEye_Count] = { 0, 0 };49GLsizei OculusManager::_meshSize[ovrEye_Count] = { 0, 0 };
50ovrFrameTiming OculusManager::_hmdFrameTiming;50ovrFrameTiming OculusManager::_hmdFrameTiming;
@@ -66,12 +66,14 @@ void OculusManager::connect() { · 15 unmodified lines
66 UserActivityLogger::getInstance().connectedDevice("hmd", "oculus");66 UserActivityLogger::getInstance().connectedDevice("hmd", "oculus");
67 }67 }
68 _isConnected = true;68 _isConnected = true;
69 69#if defined(__APPLE__) || defined(_WIN32)
70 _eyeFov[0] = _ovrHmd->DefaultEyeFov[0];
71 _eyeFov[1] = _ovrHmd->DefaultEyeFov[1];
72#else
70 ovrHmd_GetDesc(_ovrHmd, &_ovrHmdDesc);73 ovrHmd_GetDesc(_ovrHmd, &_ovrHmdDesc);
71
72 _eyeFov[0] = _ovrHmdDesc.DefaultEyeFov[0];74 _eyeFov[0] = _ovrHmdDesc.DefaultEyeFov[0];
73 _eyeFov[1] = _ovrHmdDesc.DefaultEyeFov[1];75 _eyeFov[1] = _ovrHmdDesc.DefaultEyeFov[1];
74 76#endif
75 //Get texture size77 //Get texture size
76 ovrSizei recommendedTex0Size = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left,78 ovrSizei recommendedTex0Size = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left,
77 _eyeFov[0], 1.0f);79 _eyeFov[0], 1.0f);
@@ -86,11 +88,21 @@ void OculusManager::connect() { · 8 unmodified lines
86 _eyeRenderDesc[0] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Left, _eyeFov[0]);88 _eyeRenderDesc[0] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Left, _eyeFov[0]);
87 _eyeRenderDesc[1] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Right, _eyeFov[1]);89 _eyeRenderDesc[1] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Right, _eyeFov[1]);
88 90
91#if defined(__APPLE__) || defined(_WIN32)
92 ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence);
93#else
89 ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence | ovrHmdCap_LatencyTest);94 ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence | ovrHmdCap_LatencyTest);
95#endif
90 96
97#if defined(__APPLE__) || defined(_WIN32)
98 ovrHmd_ConfigureTracking(_ovrHmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position |
99 ovrTrackingCap_MagYawCorrection,
100 ovrTrackingCap_Orientation);
101#else
91 ovrHmd_StartSensor(_ovrHmd, ovrSensorCap_Orientation | ovrSensorCap_YawCorrection |102 ovrHmd_StartSensor(_ovrHmd, ovrSensorCap_Orientation | ovrSensorCap_YawCorrection |
92 ovrSensorCap_Position,103 ovrSensorCap_Position,
93 ovrSensorCap_Orientation);104 ovrSensorCap_Orientation);
105#endif
94 106
95 if (!_camera) {107 if (!_camera) {
96 _camera = new Camera;108 _camera = new Camera;
@@ -123,6 +135,10 @@ void OculusManager::connect() { · 26 unmodified lines
123 135
124 } else {136 } else {
125 _isConnected = false;137 _isConnected = false;
138
139 // we're definitely not in "VR mode" so tell the menu that
140 Menu::getInstance()->getActionForOption(MenuOption::EnableVRMode)->setChecked(false);
141
126 ovrHmd_Destroy(_ovrHmd);142 ovrHmd_Destroy(_ovrHmd);
127 ovr_Shutdown();143 ovr_Shutdown();
128 }144 }
@@ -183,6 +199,16 @@ void OculusManager::generateDistortionMesh() { · 54 unmodified lines
183 DistortionVertex* v = pVBVerts;199 DistortionVertex* v = pVBVerts;
184 ovrDistortionVertex* ov = meshData.pVertexData;200 ovrDistortionVertex* ov = meshData.pVertexData;
185 for (unsigned int vertNum = 0; vertNum < meshData.VertexCount; vertNum++) {201 for (unsigned int vertNum = 0; vertNum < meshData.VertexCount; vertNum++) {
202#if defined(__APPLE__) || defined(_WIN32)
203 v->pos.x = ov->ScreenPosNDC.x;
204 v->pos.y = ov->ScreenPosNDC.y;
205 v->texR.x = ov->TanEyeAnglesR.x;
206 v->texR.y = ov->TanEyeAnglesR.y;
207 v->texG.x = ov->TanEyeAnglesG.x;
208 v->texG.y = ov->TanEyeAnglesG.y;
209 v->texB.x = ov->TanEyeAnglesB.x;
210 v->texB.y = ov->TanEyeAnglesB.y;
211#else
186 v->pos.x = ov->Pos.x;212 v->pos.x = ov->Pos.x;
187 v->pos.y = ov->Pos.y;213 v->pos.y = ov->Pos.y;
188 v->texR.x = ov->TexR.x;214 v->texR.x = ov->TexR.x;
@@ -191,6 +217,7 @@ void OculusManager::generateDistortionMesh() { · 2 unmodified lines
191 v->texG.y = ov->TexG.y;217 v->texG.y = ov->TexG.y;
192 v->texB.x = ov->TexB.x;218 v->texB.x = ov->TexB.x;
193 v->texB.y = ov->TexB.y;219 v->texB.y = ov->TexB.y;
220#endif
194 v->color.r = v->color.g = v->color.b = (GLubyte)(ov->VignetteFactor * 255.99f);221 v->color.r = v->color.g = v->color.b = (GLubyte)(ov->VignetteFactor * 255.99f);
195 v->color.a = (GLubyte)(ov->TimeWarpFactor * 255.99f);222 v->color.a = (GLubyte)(ov->TimeWarpFactor * 255.99f);
196 v++; 223 v++;
@@ -291,12 +318,23 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p · 94 unmodified lines
291 glPushMatrix();318 glPushMatrix();
292 319
293 glm::quat orientation;320 glm::quat orientation;
294 321 glm::vec3 trackerPosition;
322
323#if defined(__APPLE__) || defined(_WIN32)
324 ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds());
325 ovrVector3f ovrHeadPosition = ts.HeadPose.ThePose.Position;
326
327 trackerPosition = glm::vec3(ovrHeadPosition.x, ovrHeadPosition.y, ovrHeadPosition.z);
328 trackerPosition = bodyOrientation * trackerPosition;
329#endif
330
295 //Render each eye into an fbo331 //Render each eye into an fbo
296 for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++) {332 for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++) {
297 333#if defined(__APPLE__) || defined(_WIN32)
334 ovrEyeType eye = _ovrHmd->EyeRenderOrder[eyeIndex];
335#else
298 ovrEyeType eye = _ovrHmdDesc.EyeRenderOrder[eyeIndex];336 ovrEyeType eye = _ovrHmdDesc.EyeRenderOrder[eyeIndex];
299 337#endif
300 //Set the camera rotation for this eye338 //Set the camera rotation for this eye
301 eyeRenderPose[eye] = ovrHmd_GetEyePose(_ovrHmd, eye);339 eyeRenderPose[eye] = ovrHmd_GetEyePose(_ovrHmd, eye);
302 orientation.x = eyeRenderPose[eye].Orientation.x;340 orientation.x = eyeRenderPose[eye].Orientation.x;
@@ -305,7 +343,8 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p · 2 unmodified lines
305 orientation.w = eyeRenderPose[eye].Orientation.w;343 orientation.w = eyeRenderPose[eye].Orientation.w;
306 344
307 _camera->setTargetRotation(bodyOrientation * orientation);345 _camera->setTargetRotation(bodyOrientation * orientation);
308 _camera->setTargetPosition(position);346 _camera->setTargetPosition(position + trackerPosition);
347
309 _camera->update(1.0f / Application::getInstance()->getFps());348 _camera->update(1.0f / Application::getInstance()->getFps());
310 349
311 Matrix4f proj = ovrMatrix4f_Projection(_eyeRenderDesc[eye].Fov, whichCamera.getNearClip(), whichCamera.getFarClip(), true);350 Matrix4f proj = ovrMatrix4f_Projection(_eyeRenderDesc[eye].Fov, whichCamera.getNearClip(), whichCamera.getFarClip(), true);
@@ -425,19 +464,32 @@ void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) { · 113 unmodified lines
425//Tries to reconnect to the sensors464//Tries to reconnect to the sensors
426void OculusManager::reset() {465void OculusManager::reset() {
427#ifdef HAVE_LIBOVR466#ifdef HAVE_LIBOVR
428 disconnect();467 if (_isConnected) {
429 connect();468 ovrHmd_RecenterPose(_ovrHmd);
469 }
430#endif470#endif
431}471}
432 472
433//Gets the current predicted angles from the oculus sensors473//Gets the current predicted angles from the oculus sensors
434void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) {474void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) {
435#ifdef HAVE_LIBOVR475#ifdef HAVE_LIBOVR
476#if defined(__APPLE__) || defined(_WIN32)
477 ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds());
478#else
436 ovrSensorState ss = ovrHmd_GetSensorState(_ovrHmd, _hmdFrameTiming.ScanoutMidpointSeconds);479 ovrSensorState ss = ovrHmd_GetSensorState(_ovrHmd, _hmdFrameTiming.ScanoutMidpointSeconds);
437 480#endif
481#if defined(__APPLE__) || defined(_WIN32)
482 if (ts.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) {
483#else
438 if (ss.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) {484 if (ss.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) {
439 ovrPosef pose = ss.Predicted.Pose;485#endif
440 Quatf orientation = Quatf(pose.Orientation);486
487#if defined(__APPLE__) || defined(_WIN32)
488 ovrPosef headPose = ts.HeadPose.ThePose;
489#else
490 ovrPosef headPose = ss.Predicted.Pose;
491#endif
492 Quatf orientation = Quatf(headPose.Orientation);
441 orientation.GetEulerAngles<Axis_Y, Axis_X, Axis_Z, Rotate_CCW, Handed_R>(&yaw, &pitch, &roll);493 orientation.GetEulerAngles<Axis_Y, Axis_X, Axis_Z, Rotate_CCW, Handed_R>(&yaw, &pitch, &roll);
442 } else {494 } else {
443 yaw = 0.0f;495 yaw = 0.0f;
@@ -450,6 +502,18 @@ void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { · 6 unmodified lines
450 roll = 0.0f;502 roll = 0.0f;
451#endif503#endif
452}504}
505
506glm::vec3 OculusManager::getRelativePosition() {
507#if (defined(__APPLE__) || defined(_WIN32)) && HAVE_LIBOVR
508 ovrTrackingState trackingState = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds());
509 ovrVector3f headPosition = trackingState.HeadPose.ThePose.Position;
510
511 return glm::vec3(headPosition.x, headPosition.y, headPosition.z);
512#else
513 // no positional tracking in Linux yet
514 return glm::vec3(0.0f, 0.0f, 0.0f);
515#endif
516}
453 517
454//Used to set the size of the glow framebuffers518//Used to set the size of the glow framebuffers
455QSize OculusManager::getRenderTargetSize() {519QSize OculusManager::getRenderTargetSize() {
interface/src/devices/OculusManager.h+1−0
@@ -40,6 +40,7 @@ public: · 39 unmodified lines
40 /// param \pitch[out] pitch in radians40 /// param \pitch[out] pitch in radians
41 /// param \roll[out] roll in radians41 /// param \roll[out] roll in radians
42 static void getEulerAngles(float& yaw, float& pitch, float& roll);42 static void getEulerAngles(float& yaw, float& pitch, float& roll);
43 static glm::vec3 getRelativePosition();
43 static QSize getRenderTargetSize();44 static QSize getRenderTargetSize();
44 45
45private:46private:
interface/src/devices/SixenseManager.cpp+3−1
@@ -19,6 +19,7 @@ · 18 unmodified lines
19#include "UserActivityLogger.h"19#include "UserActivityLogger.h"
20 20
21#ifdef HAVE_SIXENSE21#ifdef HAVE_SIXENSE
22
22const int CALIBRATION_STATE_IDLE = 0;23const int CALIBRATION_STATE_IDLE = 0;
23const int CALIBRATION_STATE_X = 1;24const int CALIBRATION_STATE_X = 1;
24const int CALIBRATION_STATE_Y = 2;25const int CALIBRATION_STATE_Y = 2;
@@ -41,8 +42,9 @@ SixenseManager::SixenseManager() { · 16 unmodified lines
41 // By default we assume the _neckBase (in orb frame) is as high above the orb 42 // By default we assume the _neckBase (in orb frame) is as high above the orb
42 // as the "torso" is below it.43 // as the "torso" is below it.
43 _neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z);44 _neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z);
44 45
45 sixenseInit();46 sixenseInit();
47
46#endif48#endif
47 _hydrasConnected = false;49 _hydrasConnected = false;
48 _triggerPressed[0] = false;50 _triggerPressed[0] = false;
interface/src/devices/SixenseManager.h+1−1
@@ -71,7 +71,7 @@ private: · 70 unmodified lines
71 glm::vec3 _reachUp;71 glm::vec3 _reachUp;
72 glm::vec3 _reachForward;72 glm::vec3 _reachForward;
73 float _lastDistance;73 float _lastDistance;
74 74
75#endif75#endif
76 bool _hydrasConnected;76 bool _hydrasConnected;
77 quint64 _lastMovement;77 quint64 _lastMovement;
interface/src/renderer/JointState.h+1−0
@@ -16,6 +16,7 @@ · 15 unmodified lines
16#include <glm/gtx/quaternion.hpp>16#include <glm/gtx/quaternion.hpp>
17#include <glm/gtx/transform.hpp>17#include <glm/gtx/transform.hpp>
18 18
19#include <GLMHelpers.h>
19#include <FBXReader.h>20#include <FBXReader.h>
20 21
21class AngularConstraint;22class AngularConstraint;
interface/src/renderer/Model.cpp+5−3
@@ -1449,9 +1449,11 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re · 1448 unmodified lines
1449 if (cascadedShadows) {1449 if (cascadedShadows) {
1450 activeProgram->setUniform(activeLocations->shadowDistances, Application::getInstance()->getShadowDistances());1450 activeProgram->setUniform(activeLocations->shadowDistances, Application::getInstance()->getShadowDistances());
1451 }1451 }
1452 activeProgram->setUniformValueArray(activeLocations->localLightDirections,1452 if (mode != SHADOW_RENDER_MODE) {
1453 (const GLfloat*)_localLightDirections, MAX_LOCAL_LIGHTS, 4);1453 activeProgram->setUniformValueArray(activeLocations->localLightDirections,
1454 1454 (const GLfloat*)_localLightDirections, MAX_LOCAL_LIGHTS, 4);
1455 }
1456
1455 if (mesh.blendshapes.isEmpty()) {1457 if (mesh.blendshapes.isEmpty()) {
1456 if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) {1458 if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) {
1457 activeProgram->setAttributeBuffer(activeLocations->tangent, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3);1459 activeProgram->setAttributeBuffer(activeLocations->tangent, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3);
interface/src/renderer/Model.h+3−0
@@ -164,6 +164,9 @@ public: · 163 unmodified lines
164 const QVector<LocalLight>& getLocalLights() const { return _localLights; }164 const QVector<LocalLight>& getLocalLights() const { return _localLights; }
165 165
166 void setShowTrueJointTransforms(bool show) { _showTrueJointTransforms = show; }166 void setShowTrueJointTransforms(bool show) { _showTrueJointTransforms = show; }
167
168 QVector<JointState>& getJointStates() { return _jointStates; }
169 const QVector<JointState>& getJointStates() const { return _jointStates; }
167 170
168protected:171protected:
169 QSharedPointer<NetworkGeometry> _geometry;172 QSharedPointer<NetworkGeometry> _geometry;
interface/src/scripting/ClipboardScriptingInterface.cpp+31−0
@@ -87,6 +87,37 @@ bool ClipboardScriptingInterface::importVoxels() { · 86 unmodified lines
87 return Application::getInstance()->getImportSucceded();87 return Application::getInstance()->getImportSucceded();
88}88}
89 89
90bool ClipboardScriptingInterface::importVoxels(const QString& filename) {
91 qDebug() << "Importing ... ";
92
93 VoxelImporter* importer = Application::getInstance()->getVoxelImporter();
94
95 if (!importer->validImportFile(filename)) {
96 return false;
97 }
98
99 QEventLoop loop;
100 connect(importer, SIGNAL(importDone()), &loop, SLOT(quit()));
101 importer->import(filename);
102 loop.exec();
103
104 return true;
105}
106
107bool ClipboardScriptingInterface::importVoxels(const QString& filename, float x, float y, float z, float s) {
108 bool success = importVoxels(filename);
109
110 if (success) {
111 pasteVoxel(x, y, z, s);
112 }
113
114 return success;
115}
116
117bool ClipboardScriptingInterface::importVoxels(const QString& filename, const VoxelDetail& destinationVoxel) {
118 return importVoxels(filename, destinationVoxel.x, destinationVoxel.y, destinationVoxel.z, destinationVoxel.s);
119}
120
90void ClipboardScriptingInterface::nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec) {121void ClipboardScriptingInterface::nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec) {
91 nudgeVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s, nudgeVec);122 nudgeVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s, nudgeVec);
92}123}
interface/src/scripting/ClipboardScriptingInterface.h+3−0
@@ -39,6 +39,9 @@ public slots: · 38 unmodified lines
39 void exportVoxel(float x, float y, float z, float s);39 void exportVoxel(float x, float y, float z, float s);
40 40
41 bool importVoxels();41 bool importVoxels();
42 bool importVoxels(const QString& filename);
43 bool importVoxels(const QString& filename, float x, float y, float z, float s);
44 bool importVoxels(const QString& filename, const VoxelDetail& destinationVoxel);
42 45
43 void nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec);46 void nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec);
44 void nudgeVoxel(float x, float y, float z, float s, const glm::vec3& nudgeVec);47 void nudgeVoxel(float x, float y, float z, float s, const glm::vec3& nudgeVec);
interface/src/ui/ApplicationOverlay.cpp+29−0
@@ -57,6 +57,9 @@ ApplicationOverlay::~ApplicationOverlay() { · 56 unmodified lines
57const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f };57const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f };
58const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f };58const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f };
59 59
60const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f };
61const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f;
62
60// Renders the overlays either to a texture or to the screen63// Renders the overlays either to a texture or to the screen
61void ApplicationOverlay::renderOverlay(bool renderToTexture) {64void ApplicationOverlay::renderOverlay(bool renderToTexture) {
62 65
@@ -115,6 +118,8 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { · 52 unmodified lines
115 118
116 renderPointers();119 renderPointers();
117 120
121 renderDomainConnectionStatusBorder();
122
118 glPopMatrix();123 glPopMatrix();
119 124
120 125
@@ -1234,6 +1239,30 @@ void ApplicationOverlay::renderTexturedHemisphere() { · 1113 unmodified lines
1234 1239
1235}1240}
1236 1241
1242void ApplicationOverlay::renderDomainConnectionStatusBorder() {
1243 NodeList* nodeList = NodeList::getInstance();
1244
1245 if (nodeList && !nodeList->getDomainHandler().isConnected()) {
1246 QGLWidget* glWidget = Application::getInstance()->getGLWidget();
1247 int right = glWidget->width();
1248 int bottom = glWidget->height();
1249
1250 glColor3f(CONNECTION_STATUS_BORDER_COLOR[0],
1251 CONNECTION_STATUS_BORDER_COLOR[1],
1252 CONNECTION_STATUS_BORDER_COLOR[2]);
1253 glLineWidth(CONNECTION_STATUS_BORDER_LINE_WIDTH);
1254
1255 glBegin(GL_LINE_LOOP);
1256
1257 glVertex2i(0, 0);
1258 glVertex2i(0, bottom);
1259 glVertex2i(right, bottom);
1260 glVertex2i(right, 0);
1261
1262 glEnd();
1263 }
1264}
1265
1237QOpenGLFramebufferObject* ApplicationOverlay::getFramebufferObject() {1266QOpenGLFramebufferObject* ApplicationOverlay::getFramebufferObject() {
1238 QSize size = Application::getInstance()->getGLWidget()->size();1267 QSize size = Application::getInstance()->getGLWidget()->size();
1239 if (!_framebufferObject || _framebufferObject->size() != size) {1268 if (!_framebufferObject || _framebufferObject->size() != size) {
interface/src/ui/ApplicationOverlay.h+2−1
@@ -56,6 +56,7 @@ private: · 55 unmodified lines
56 void renderAudioMeter();56 void renderAudioMeter();
57 void renderStatsAndLogs();57 void renderStatsAndLogs();
58 void renderTexturedHemisphere();58 void renderTexturedHemisphere();
59 void renderDomainConnectionStatusBorder();
59 60
60 QOpenGLFramebufferObject* _framebufferObject;61 QOpenGLFramebufferObject* _framebufferObject;
61 float _trailingAudioLoudness;62 float _trailingAudioLoudness;
@@ -76,4 +77,4 @@ private: · 14 unmodified lines
76 GLuint _crosshairTexture;77 GLuint _crosshairTexture;
77};78};
78 79
79#endif // hifi_ApplicationOverlay_h80#endif // hifi_ApplicationOverlay_h
interface/src/ui/MetavoxelEditor.cpp+94−19
@@ -118,6 +118,8 @@ MetavoxelEditor::MetavoxelEditor() : · 117 unmodified lines
118 addTool(new SetSpannerTool(this));118 addTool(new SetSpannerTool(this));
119 addTool(new ImportHeightfieldTool(this));119 addTool(new ImportHeightfieldTool(this));
120 addTool(new EraseHeightfieldTool(this));120 addTool(new EraseHeightfieldTool(this));
121 addTool(new HeightfieldHeightBrushTool(this));
122 addTool(new HeightfieldColorBrushTool(this));
121 123
122 updateAttributes();124 updateAttributes();
123 125
@@ -954,11 +956,11 @@ void ImportHeightfieldTool::apply() { · 830 unmodified lines
954 HeightfieldBuffer* buffer = static_cast<HeightfieldBuffer*>(bufferData.data());956 HeightfieldBuffer* buffer = static_cast<HeightfieldBuffer*>(bufferData.data());
955 MetavoxelData data;957 MetavoxelData data;
956 data.setSize(scale);958 data.setSize(scale);
957 HeightfieldDataPointer heightPointer(new HeightfieldData(buffer->getHeight()));959 HeightfieldDataPointer heightPointer(new HeightfieldData(buffer->getUnextendedHeight()));
958 data.setRoot(AttributeRegistry::getInstance()->getHeightfieldAttribute(), new MetavoxelNode(AttributeValue(960 data.setRoot(AttributeRegistry::getInstance()->getHeightfieldAttribute(), new MetavoxelNode(AttributeValue(
959 AttributeRegistry::getInstance()->getHeightfieldAttribute(), encodeInline(heightPointer))));961 AttributeRegistry::getInstance()->getHeightfieldAttribute(), encodeInline(heightPointer))));
960 if (!buffer->getColor().isEmpty()) {962 if (!buffer->getColor().isEmpty()) {
961 HeightfieldDataPointer colorPointer(new HeightfieldData(buffer->getColor()));963 HeightfieldDataPointer colorPointer(new HeightfieldData(buffer->getUnextendedColor()));
962 data.setRoot(AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), new MetavoxelNode(AttributeValue(964 data.setRoot(AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), new MetavoxelNode(AttributeValue(
963 AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), encodeInline(colorPointer))));965 AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), encodeInline(colorPointer))));
964 }966 }
@@ -1001,34 +1003,38 @@ void ImportHeightfieldTool::updatePreview() { · 36 unmodified lines
1001 if (_heightImage.width() > 0 && _heightImage.height() > 0) {1003 if (_heightImage.width() > 0 && _heightImage.height() > 0) {
1002 float z = 0.0f;1004 float z = 0.0f;
1003 int blockSize = pow(2.0, _blockSize->value());1005 int blockSize = pow(2.0, _blockSize->value());
1004 int blockAdvancement = blockSize - 1;1006 int heightSize = blockSize + HeightfieldBuffer::HEIGHT_EXTENSION;
1005 for (int i = 0; i < _heightImage.height(); i += blockAdvancement, z++) {1007 int colorSize = blockSize + HeightfieldBuffer::SHARED_EDGE;
1008 for (int i = 0; i < _heightImage.height(); i += blockSize, z++) {
1006 float x = 0.0f;1009 float x = 0.0f;
1007 for (int j = 0; j < _heightImage.width(); j += blockAdvancement, x++) {1010 for (int j = 0; j < _heightImage.width(); j += blockSize, x++) {
1008 QByteArray height(blockSize * blockSize, 0);1011 QByteArray height(heightSize * heightSize, 0);
1009 int rows = qMin(blockSize, _heightImage.height() - i);1012 int extendedI = qMax(i - HeightfieldBuffer::HEIGHT_BORDER, 0);
1010 int columns = qMin(blockSize, _heightImage.width() - j);1013 int extendedJ = qMax(j - HeightfieldBuffer::HEIGHT_BORDER, 0);
1011 const int BYTES_PER_COLOR = 3;1014 int offsetY = extendedI - i + HeightfieldBuffer::HEIGHT_BORDER;
1015 int offsetX = extendedJ - j + HeightfieldBuffer::HEIGHT_BORDER;
1016 int rows = qMin(heightSize - offsetY, _heightImage.height() - extendedI);
1017 int columns = qMin(heightSize - offsetX, _heightImage.width() - extendedJ);
1012 for (int y = 0; y < rows; y++) {1018 for (int y = 0; y < rows; y++) {
1013 uchar* src = _heightImage.scanLine(i + y) + j * BYTES_PER_COLOR;1019 uchar* src = _heightImage.scanLine(extendedI + y) + extendedJ * HeightfieldData::COLOR_BYTES;
1014 char* dest = height.data() + y * blockSize;1020 char* dest = height.data() + (y + offsetY) * heightSize + offsetX;
1015 for (int x = 0; x < columns; x++) {1021 for (int x = 0; x < columns; x++) {
1016 *dest++ = *src;1022 *dest++ = *src;
1017 src += BYTES_PER_COLOR;1023 src += HeightfieldData::COLOR_BYTES;
1018 }1024 }
1019 }1025 }
1020
1021 QByteArray color;1026 QByteArray color;
1022 if (!_colorImage.isNull()) {1027 if (!_colorImage.isNull()) {
1023 color = QByteArray(blockSize * blockSize * BYTES_PER_COLOR, 0);1028 color = QByteArray(colorSize * colorSize * HeightfieldData::COLOR_BYTES, 0);
1024 rows = qMax(0, qMin(blockSize, _colorImage.height() - i));1029 rows = qMax(0, qMin(colorSize, _colorImage.height() - i));
1025 columns = qMax(0, qMin(blockSize, _colorImage.width() - j));1030 columns = qMax(0, qMin(colorSize, _colorImage.width() - j));
1026 for (int y = 0; y < rows; y++) {1031 for (int y = 0; y < rows; y++) {
1027 memcpy(color.data() + y * blockSize * BYTES_PER_COLOR,1032 memcpy(color.data() + y * colorSize * HeightfieldData::COLOR_BYTES,
1028 _colorImage.scanLine(i + y) + j * BYTES_PER_COLOR, columns * BYTES_PER_COLOR);1033 _colorImage.scanLine(i + y) + j * HeightfieldData::COLOR_BYTES,
1034 columns * HeightfieldData::COLOR_BYTES);
1029 }1035 }
1030 }1036 }
1031 buffers.append(BufferDataPointer(new HeightfieldBuffer(glm::vec3(x, 0.0f, z), 1.0f, height, color, false)));1037 buffers.append(BufferDataPointer(new HeightfieldBuffer(glm::vec3(x, 0.0f, z), 1.0f, height, color)));
1032 }1038 }
1033 }1039 }
1034 }1040 }
@@ -1080,3 +1086,72 @@ void EraseHeightfieldTool::apply() { · 45 unmodified lines
1080 message.edit = QVariant::fromValue(edit);1086 message.edit = QVariant::fromValue(edit);
1081 Application::getInstance()->getMetavoxels()->applyEdit(message, true);1087 Application::getInstance()->getMetavoxels()->applyEdit(message, true);
1082}1088}
1089
1090HeightfieldBrushTool::HeightfieldBrushTool(MetavoxelEditor* editor, const QString& name) :
1091 MetavoxelTool(editor, name, false) {
1092
1093 QWidget* widget = new QWidget();
1094 widget->setLayout(_form = new QFormLayout());
1095 layout()->addWidget(widget);
1096
1097 _form->addRow("Radius:", _radius = new QDoubleSpinBox());
1098 _radius->setSingleStep(0.01);
1099 _radius->setMaximum(FLT_MAX);
1100 _radius->setValue(1.0);
1101}
1102
1103void HeightfieldBrushTool::render() {
1104 if (Application::getInstance()->isMouseHidden()) {
1105 return;
1106 }
1107
1108 // find the intersection with the heightfield
1109 glm::vec3 origin = Application::getInstance()->getMouseRayOrigin();
1110 glm::vec3 direction = Application::getInstance()->getMouseRayDirection();
1111
1112 float distance;
1113 if (!Application::getInstance()->getMetavoxels()->findFirstRayHeightfieldIntersection(origin, direction, distance)) {
1114 return;
1115 }
1116 Application::getInstance()->getMetavoxels()->renderHeightfieldCursor(
1117 _position = origin + distance * direction, _radius->value());
1118}
1119
1120bool HeightfieldBrushTool::eventFilter(QObject* watched, QEvent* event) {
1121 if (event->type() == QEvent::Wheel) {
1122 float angle = static_cast<QWheelEvent*>(event)->angleDelta().y();
1123 const float ANGLE_SCALE = 1.0f / 1000.0f;
1124 _radius->setValue(_radius->value() * glm::pow(2.0f, angle * ANGLE_SCALE));
1125 return true;
1126
1127 } else if (event->type() == QEvent::MouseButtonPress) {
1128 MetavoxelEditMessage message = { createEdit(static_cast<QMouseEvent*>(event)->button() == Qt::RightButton) };
1129 Application::getInstance()->getMetavoxels()->applyEdit(message, true);
1130 return true;
1131 }
1132 return false;
1133}
1134
1135HeightfieldHeightBrushTool::HeightfieldHeightBrushTool(MetavoxelEditor* editor) :
1136 HeightfieldBrushTool(editor, "Height Brush") {
1137
1138 _form->addRow("Height:", _height = new QDoubleSpinBox());
1139 _height->setMinimum(-FLT_MAX);
1140 _height->setMaximum(FLT_MAX);
1141 _height->setValue(1.0);
1142}
1143
1144QVariant HeightfieldHeightBrushTool::createEdit(bool alternate) {
1145 return QVariant::fromValue(PaintHeightfieldHeightEdit(_position, _radius->value(),
1146 alternate ? -_height->value() : _height->value()));
1147}
1148
1149HeightfieldColorBrushTool::HeightfieldColorBrushTool(MetavoxelEditor* editor) :
1150 HeightfieldBrushTool(editor, "Color Brush") {
1151
1152 _form->addRow("Color:", _color = new QColorEditor(this));
1153}
1154
1155QVariant HeightfieldColorBrushTool::createEdit(bool alternate) {
1156 return QVariant::fromValue(PaintHeightfieldColorEdit(_position, _radius->value(), _color->getColor()));
1157}
interface/src/ui/MetavoxelEditor.h+58−1
@@ -18,6 +18,7 @@ · 17 unmodified lines
18#include "MetavoxelSystem.h"18#include "MetavoxelSystem.h"
19#include "renderer/ProgramObject.h"19#include "renderer/ProgramObject.h"
20 20
21class QColorEditor;
21class QComboBox;22class QComboBox;
22class QDoubleSpinBox;23class QDoubleSpinBox;
23class QGroupBox;24class QGroupBox;
@@ -282,7 +283,7 @@ private: · 258 unmodified lines
282 HeightfieldPreview _preview;283 HeightfieldPreview _preview;
283};284};
284 285
285// Allows clearing heighfield blocks.286/// Allows clearing heighfield blocks.
286class EraseHeightfieldTool : public HeightfieldTool {287class EraseHeightfieldTool : public HeightfieldTool {
287 Q_OBJECT288 Q_OBJECT
288 289
@@ -302,4 +303,60 @@ private: · 13 unmodified lines
302 QSpinBox* _length;303 QSpinBox* _length;
303};304};
304 305
306/// Base class for tools that allow painting on heightfields.
307class HeightfieldBrushTool : public MetavoxelTool {
308 Q_OBJECT
309
310public:
311
312 HeightfieldBrushTool(MetavoxelEditor* editor, const QString& name);
313
314 virtual void render();
315
316 virtual bool eventFilter(QObject* watched, QEvent* event);
317
318protected:
319
320 virtual QVariant createEdit(bool alternate) = 0;
321
322 QFormLayout* _form;
323 QDoubleSpinBox* _radius;
324
325 glm::vec3 _position;
326};
327
328/// Allows raising or lowering parts of the heightfield.
329class HeightfieldHeightBrushTool : public HeightfieldBrushTool {
330 Q_OBJECT
331
332public:
333
334 HeightfieldHeightBrushTool(MetavoxelEditor* editor);
335
336protected:
337
338 virtual QVariant createEdit(bool alternate);
339
340private:
341
342 QDoubleSpinBox* _height;
343};
344
345/// Allows coloring parts of the heightfield.
346class HeightfieldColorBrushTool : public HeightfieldBrushTool {
347 Q_OBJECT
348
349public:
350
351 HeightfieldColorBrushTool(MetavoxelEditor* editor);
352
353protected:
354
355 virtual QVariant createEdit(bool alternate);
356
357private:
358
359 QColorEditor* _color;
360};
361
305#endif // hifi_MetavoxelEditor_h362#endif // hifi_MetavoxelEditor_h
interface/src/ui/VoxelImportDialog.cpprenamed from interface/src/ui/ImportDialog.cpp+94−37
@@ -1,5 +1,5 @@
1//1//
2// ImportDialog.cpp2// VoxelImportDialog.cpp
3// interface/src/ui3// interface/src/ui
4//4//
5// Created by Clement Brisset on 8/12/13.5// Created by Clement Brisset on 8/12/13.
@@ -20,7 +20,11 @@ · 14 unmodified lines
20 20
21#include "Application.h"21#include "Application.h"
22 22
23#include "ImportDialog.h"23#include "VoxelImportDialog.h"
24#include "voxels/VoxelImporter.h"
25
26const QString SETTINGS_GROUP_NAME = "VoxelImport";
27const QString IMPORT_DIALOG_SETTINGS_KEY = "VoxelImportDialogSettings";
24 28
25const QString WINDOW_NAME = QObject::tr("Import Voxels");29const QString WINDOW_NAME = QObject::tr("Import Voxels");
26const QString IMPORT_BUTTON_NAME = QObject::tr("Import Voxels");30const QString IMPORT_BUTTON_NAME = QObject::tr("Import Voxels");
@@ -97,12 +101,14 @@ QString HiFiIconProvider::type(const QFileInfo &info) const { · 70 unmodified lines
97 return QFileIconProvider::type(info);101 return QFileIconProvider::type(info);
98}102}
99 103
100ImportDialog::ImportDialog(QWidget* parent) :104VoxelImportDialog::VoxelImportDialog(QWidget* parent) :
101 QFileDialog(parent, WINDOW_NAME, DOWNLOAD_LOCATION, NULL),105 QFileDialog(parent, WINDOW_NAME, DOWNLOAD_LOCATION, NULL),
102 _progressBar(this),
103 _importButton(IMPORT_BUTTON_NAME, this),
104 _cancelButton(CANCEL_BUTTON_NAME, this),106 _cancelButton(CANCEL_BUTTON_NAME, this),
105 _mode(importMode) {107 _importButton(IMPORT_BUTTON_NAME, this),
108 _importer(Application::getInstance()->getVoxelImporter()),
109 _mode(importMode),
110 _progressBar(this),
111 _didImport(false) {
106 112
107 setOption(QFileDialog::DontUseNativeDialog, true);113 setOption(QFileDialog::DontUseNativeDialog, true);
108 setFileMode(QFileDialog::ExistingFile);114 setFileMode(QFileDialog::ExistingFile);
@@ -113,41 +119,54 @@ ImportDialog::ImportDialog(QWidget* parent) : · 4 unmodified lines
113 119
114 _progressBar.setRange(0, 100);120 _progressBar.setRange(0, 100);
115 121
116 connect(&_importButton, SIGNAL(pressed()), SLOT(accept()));122 connect(&_importButton, SIGNAL(pressed()), this, SLOT(accept()));
117 connect(&_cancelButton, SIGNAL(pressed()), SIGNAL(canceled()));123 connect(&_cancelButton, SIGNAL(pressed()), this, SLOT(cancel()));
118 connect(this, SIGNAL(currentChanged(QString)), SLOT(saveCurrentFile(QString)));124 connect(this, SIGNAL(currentChanged(QString)), SLOT(saveCurrentFile(QString)));
119}125}
120 126
121void ImportDialog::reset() {127void VoxelImportDialog::cancel() {
128 switch (getMode()) {
129 case importMode:
130 _importer->cancel();
131 close();
132 break;
133 default:
134 _importer->reset();
135 setMode(importMode);
136 break;
137 }
138 emit canceled();
139}
140
141void VoxelImportDialog::saveSettings(QSettings* settings) {
142 settings->beginGroup(SETTINGS_GROUP_NAME);
143 settings->setValue(IMPORT_DIALOG_SETTINGS_KEY, saveState());
144 settings->endGroup();
145}
146
147void VoxelImportDialog::loadSettings(QSettings* settings) {
148 settings->beginGroup(SETTINGS_GROUP_NAME);
149 restoreState(settings->value(IMPORT_DIALOG_SETTINGS_KEY).toByteArray());
150 settings->endGroup();
151}
152
153bool VoxelImportDialog::prompt() {
154 reset();
155 exec();
156 return _didImport;
157}
158
159void VoxelImportDialog::reset() {
122 setMode(importMode);160 setMode(importMode);
123 _progressBar.setValue(0);161 _didImport = false;
124}162}
125 163
126void ImportDialog::setMode(dialogMode mode) {164void VoxelImportDialog::setMode(dialogMode mode) {
165 dialogMode previousMode = _mode;
127 _mode = mode;166 _mode = mode;
128 167
129 switch (_mode) {168 switch (_mode) {
130 case loadingMode:
131 _importButton.setEnabled(false);
132 _importButton.setText(LOADING_BUTTON_NAME);
133 findChild<QWidget*>("sidebar")->setEnabled(false);
134 findChild<QWidget*>("treeView")->setEnabled(false);
135 findChild<QWidget*>("backButton")->setEnabled(false);
136 findChild<QWidget*>("forwardButton")->setEnabled(false);
137 findChild<QWidget*>("toParentButton")->setEnabled(false);
138 break;
139 case placeMode:
140 _progressBar.setValue(100);
141 _importButton.setEnabled(true);
142 _importButton.setText(PLACE_BUTTON_NAME);
143 findChild<QWidget*>("sidebar")->setEnabled(false);
144 findChild<QWidget*>("treeView")->setEnabled(false);
145 findChild<QWidget*>("backButton")->setEnabled(false);
146 findChild<QWidget*>("forwardButton")->setEnabled(false);
147 findChild<QWidget*>("toParentButton")->setEnabled(false);
148 break;
149 case importMode:169 case importMode:
150 default:
151 _progressBar.setValue(0);170 _progressBar.setValue(0);
152 _importButton.setEnabled(true);171 _importButton.setEnabled(true);
153 _importButton.setText(IMPORT_BUTTON_NAME);172 _importButton.setText(IMPORT_BUTTON_NAME);
@@ -157,22 +176,60 @@ void ImportDialog::setMode(dialogMode mode) { · 3 unmodified lines
157 findChild<QWidget*>("forwardButton")->setEnabled(true);176 findChild<QWidget*>("forwardButton")->setEnabled(true);
158 findChild<QWidget*>("toParentButton")->setEnabled(true);177 findChild<QWidget*>("toParentButton")->setEnabled(true);
159 break;178 break;
179 case loadingMode:
180 // Connect to VoxelImporter signals
181 connect(_importer, SIGNAL(importProgress(int)), this, SLOT(updateProgressBar(int)));
182 connect(_importer, SIGNAL(importDone()), this, SLOT(afterImport()));
183
184 _importButton.setEnabled(false);
185 _importButton.setText(LOADING_BUTTON_NAME);
186 findChild<QWidget*>("sidebar")->setEnabled(false);
187 findChild<QWidget*>("treeView")->setEnabled(false);
188 findChild<QWidget*>("backButton")->setEnabled(false);
189 findChild<QWidget*>("forwardButton")->setEnabled(false);
190 findChild<QWidget*>("toParentButton")->setEnabled(false);
191 break;
192 case finishedMode:
193 if (previousMode == loadingMode) {
194 // Disconnect from VoxelImporter signals
195 disconnect(_importer, SIGNAL(importProgress(int)), this, SLOT(setProgressBarValue(int)));
196 disconnect(_importer, SIGNAL(importDone()), this, SLOT(afterImport()));
197 }
198 setMode(importMode);
199 break;
160 }200 }
161}201}
162 202
163void ImportDialog::setProgressBarValue(int value) {203void VoxelImportDialog::setProgressBarValue(int value) {
164 _progressBar.setValue(value);204 _progressBar.setValue(value);
165}205}
166 206
167void ImportDialog::accept() {207void VoxelImportDialog::accept() {
168 emit accepted();208 if (getMode() == importMode) {
209 QString filename = getCurrentFile();
210
211 // If file is invalid we ignore the call
212 if (!_importer->validImportFile(filename)) {
213 return;
214 }
215 // Let's prepare the dialog window for import
216 setMode(loadingMode);
217
218 _importer->import(filename);
219 }
220}
221
222void VoxelImportDialog::afterImport() {
223 setMode(finishedMode);
224 _didImport = true;
225 close();
169}226}
170 227
171void ImportDialog::saveCurrentFile(QString filename) {228void VoxelImportDialog::saveCurrentFile(QString filename) {
172 _currentFile = QFileInfo(filename).isFile() ? filename : "";229 _currentFile = QFileInfo(filename).isFile() ? filename : "";
173}230}
174 231
175void ImportDialog::setLayout() {232void VoxelImportDialog::setLayout() {
176 QGridLayout* gridLayout = (QGridLayout*) layout();233 QGridLayout* gridLayout = (QGridLayout*) layout();
177 gridLayout->addWidget(&_progressBar, 2, 0, 2, 1);234 gridLayout->addWidget(&_progressBar, 2, 0, 2, 1);
178 gridLayout->addWidget(&_cancelButton, 2, 1, 2, 1);235 gridLayout->addWidget(&_cancelButton, 2, 1, 2, 1);
@@ -258,7 +315,7 @@ void ImportDialog::setLayout() { · 79 unmodified lines
258 315
259}316}
260 317
261void ImportDialog::setImportTypes() {318void VoxelImportDialog::setImportTypes() {
262 QFile config(Application::resourcesPath() + "config/config.json");319 QFile config(Application::resourcesPath() + "config/config.json");
263 config.open(QFile::ReadOnly | QFile::Text);320 config.open(QFile::ReadOnly | QFile::Text);
264 QJsonDocument document = QJsonDocument::fromJson(config.readAll());321 QJsonDocument document = QJsonDocument::fromJson(config.readAll());
interface/src/ui/VoxelImportDialog.hrenamed from interface/src/ui/ImportDialog.h+21−13
@@ -1,5 +1,5 @@
1//1//
2// ImportDialog.h2// VoxelImportDialog.h
3// interface/src/ui3// interface/src/ui
4//4//
5// Created by Clement Brisset on 8/12/13.5// Created by Clement Brisset on 8/12/13.
@@ -9,8 +9,8 @@ · 3 unmodified lines
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//10//
11 11
12#ifndef hifi_ImportDialog_h12#ifndef hifi_VoxelImportDialog_h
13#define hifi_ImportDialog_h13#define hifi_VoxelImportDialog_h
14 14
15#include "InterfaceConfig.h"15#include "InterfaceConfig.h"
16 16
@@ -23,6 +23,8 @@ · 6 unmodified lines
23 23
24#include <SharedUtil.h>24#include <SharedUtil.h>
25 25
26#include "voxels/VoxelImporter.h"
27
26class HiFiIconProvider : public QFileIconProvider {28class HiFiIconProvider : public QFileIconProvider {
27public:29public:
28 HiFiIconProvider(const QHash<QString, QString> map) { iconsMap = map; };30 HiFiIconProvider(const QHash<QString, QString> map) { iconsMap = map; };
@@ -35,39 +37,45 @@ public: · 6 unmodified lines
35enum dialogMode {37enum dialogMode {
36 importMode,38 importMode,
37 loadingMode,39 loadingMode,
38 placeMode40 finishedMode
39};41};
40 42
41class ImportDialog : public QFileDialog {43class VoxelImportDialog : public QFileDialog {
42 Q_OBJECT44 Q_OBJECT
43 45
44public:46public:
45 ImportDialog(QWidget* parent = NULL);47 VoxelImportDialog(QWidget* parent = NULL);
46 void reset();
47 48
48 QString getCurrentFile() const { return _currentFile; }49 QString getCurrentFile() const { return _currentFile; }
49 dialogMode getMode() const { return _mode; }50 dialogMode getMode() const { return _mode; }
51
50 void setMode(dialogMode mode);52 void setMode(dialogMode mode);
53 void reset();
54 bool prompt();
55 void loadSettings(QSettings* settings);
56 void saveSettings(QSettings* settings);
51 57
52signals:58signals:
53 void canceled();59 void canceled();
54
55public slots:
56 void setProgressBarValue(int value);
57 60
58private slots:61private slots:
62 void setProgressBarValue(int value);
59 void accept();63 void accept();
64 void cancel();
60 void saveCurrentFile(QString filename);65 void saveCurrentFile(QString filename);
66 void afterImport();
61 67
62private:68private:
69 QPushButton _cancelButton;
63 QString _currentFile;70 QString _currentFile;
64 QProgressBar _progressBar;
65 QPushButton _importButton;71 QPushButton _importButton;
66 QPushButton _cancelButton;72 VoxelImporter* _importer;
67 dialogMode _mode;73 dialogMode _mode;
74 QProgressBar _progressBar;
75 bool _didImport;
68 76
69 void setLayout();77 void setLayout();
70 void setImportTypes();78 void setImportTypes();
71};79};
72 80
73#endif // hifi_ImportDialog_h81#endif // hifi_VoxelImportDialog_h
interface/src/ui/overlays/Base3DOverlay.h+2−0
@@ -11,6 +11,8 @@ · 10 unmodified lines
11#ifndef hifi_Base3DOverlay_h11#ifndef hifi_Base3DOverlay_h
12#define hifi_Base3DOverlay_h12#define hifi_Base3DOverlay_h
13 13
14#include <glm/glm.hpp>
15
14#include "Overlay.h"16#include "Overlay.h"
15 17
16class Base3DOverlay : public Overlay {18class Base3DOverlay : public Overlay {
interface/src/voxels/OctreePacketProcessor.cpp+1−1
@@ -26,7 +26,7 @@ void OctreePacketProcessor::processPacket(const SharedNodePointer& sendingNode, · 25 unmodified lines
26 if (packetsToProcessCount() > WAY_BEHIND && Application::getInstance()->getLogger()->extraDebugging()) {26 if (packetsToProcessCount() > WAY_BEHIND && Application::getInstance()->getLogger()->extraDebugging()) {
27 qDebug("OctreePacketProcessor::processPacket() packets to process=%d", packetsToProcessCount());27 qDebug("OctreePacketProcessor::processPacket() packets to process=%d", packetsToProcessCount());
28 }28 }
29 ssize_t messageLength = mutablePacket.size();29 int messageLength = mutablePacket.size();
30 30
31 Application* app = Application::getInstance();31 Application* app = Application::getInstance();
32 bool wasStatsPacket = false;32 bool wasStatsPacket = false;
interface/src/voxels/VoxelImporter.cpp+33−82
@@ -20,8 +20,7 @@ · 19 unmodified lines
20 20
21#include "voxels/VoxelImporter.h"21#include "voxels/VoxelImporter.h"
22 22
23const QString SETTINGS_GROUP_NAME = "VoxelImport";23const QStringList SUPPORTED_EXTENSIONS = QStringList() << "png" << "svo" << "schematic";
24const QString IMPORT_DIALOG_SETTINGS_KEY = "ImportDialogSettings";
25 24
26class ImportTask : public QObject, public QRunnable {25class ImportTask : public QObject, public QRunnable {
27public:26public:
@@ -32,104 +31,46 @@ private: · 4 unmodified lines
32 QString _filename;31 QString _filename;
33};32};
34 33
35VoxelImporter::VoxelImporter(QWidget* parent) :34VoxelImporter::VoxelImporter() :
36 QObject(parent),
37 _voxelTree(true),35 _voxelTree(true),
38 _importDialog(parent),36 _task(NULL)
39 _task(NULL),
40 _didImport(false)
41{37{
42 LocalVoxelsList::getInstance()->addPersistantTree(IMPORT_TREE_NAME, &_voxelTree);38 LocalVoxelsList::getInstance()->addPersistantTree(IMPORT_TREE_NAME, &_voxelTree);
43 39
44 connect(&_voxelTree, SIGNAL(importProgress(int)), &_importDialog, SLOT(setProgressBarValue(int)));40 connect(&_voxelTree, SIGNAL(importProgress(int)), this, SIGNAL(importProgress(int)));
45 connect(&_importDialog, SIGNAL(canceled()), this, SLOT(cancel()));
46 connect(&_importDialog, SIGNAL(accepted()), this, SLOT(import()));
47}
48
49void VoxelImporter::saveSettings(QSettings* settings) {
50 settings->beginGroup(SETTINGS_GROUP_NAME);
51 settings->setValue(IMPORT_DIALOG_SETTINGS_KEY, _importDialog.saveState());
52 settings->endGroup();
53}
54
55void VoxelImporter::loadSettings(QSettings* settings) {
56 settings->beginGroup(SETTINGS_GROUP_NAME);
57 _importDialog.restoreState(settings->value(IMPORT_DIALOG_SETTINGS_KEY).toByteArray());
58 settings->endGroup();
59}41}
60 42
61VoxelImporter::~VoxelImporter() {43VoxelImporter::~VoxelImporter() {
62 cleanupTask();44 cleanupTask();
63}45}
64 46
47void VoxelImporter::cancel() {
48 if (_task) {
49 disconnect(_task, 0, 0, 0);
50 }
51 reset();
52}
53
65void VoxelImporter::reset() {54void VoxelImporter::reset() {
66 _voxelTree.eraseAllOctreeElements();55 _voxelTree.eraseAllOctreeElements();
67 _importDialog.reset();
68
69 cleanupTask();56 cleanupTask();
70}57}
71 58
72int VoxelImporter::exec() {59void VoxelImporter::import(const QString& filename) {
73 reset();60 // If present, abort existing import
74 _importDialog.exec();61 if (_task) {
75
76 if (!_didImport) {
77 // if the import is rejected, we make sure to cleanup before leaving
78 cleanupTask();62 cleanupTask();
79 return 1;
80 } else {
81 _didImport = false;
82 return 0;
83 }63 }
84}
85 64
86void VoxelImporter::import() {65 // If not already done, we switch to the local tree
87 switch (_importDialog.getMode()) {66 if (Application::getInstance()->getSharedVoxelSystem()->getTree() != &_voxelTree) {
88 case loadingMode:67 Application::getInstance()->getSharedVoxelSystem()->changeTree(&_voxelTree);
89 _importDialog.setMode(placeMode);
90 return;
91 case placeMode:
92 // Means the user chose to import
93 _didImport = true;
94 _importDialog.close();
95 return;
96 case importMode:
97 default:
98 QString filename = _importDialog.getCurrentFile();
99 // if it's not a file, we ignore the call
100 if (!QFileInfo(filename).isFile()) {
101 return;
102 }
103
104 // Let's prepare the dialog window for import
105 _importDialog.setMode(loadingMode);
106
107 // If not already done, we switch to the local tree
108 if (Application::getInstance()->getSharedVoxelSystem()->getTree() != &_voxelTree) {
109 Application::getInstance()->getSharedVoxelSystem()->changeTree(&_voxelTree);
110 }
111
112 // Creation and launch of the import task on the thread pool
113 _task = new ImportTask(filename);
114 connect(_task, SIGNAL(destroyed()), SLOT(import()));
115 QThreadPool::globalInstance()->start(_task);
116 break;
117 }68 }
118}
119 69
120void VoxelImporter::cancel() {70 // Creation and launch of the import task on the thread pool
121 switch (_importDialog.getMode()) {71 _task = new ImportTask(filename);
122 case loadingMode:72 connect(_task, SIGNAL(destroyed()), SLOT(finishImport()));
123 disconnect(_task, 0, 0, 0);73 QThreadPool::globalInstance()->start(_task);
124 cleanupTask();
125 case placeMode:
126 _importDialog.setMode(importMode);
127 break;
128 case importMode:
129 default:
130 _importDialog.close();
131 break;
132 }
133}74}
134 75
135void VoxelImporter::cleanupTask() {76void VoxelImporter::cleanupTask() {
@@ -140,6 +81,16 @@ void VoxelImporter::cleanupTask() { · 4 unmodified lines
140 }81 }
141}82}
142 83
84void VoxelImporter::finishImport() {
85 cleanupTask();
86 emit importDone();
87}
88
89bool VoxelImporter::validImportFile(const QString& filename) {
90 QFileInfo fileInfo = QFileInfo(filename);
91 return fileInfo.isFile() && SUPPORTED_EXTENSIONS.indexOf(fileInfo.suffix().toLower()) != -1;
92}
93
143ImportTask::ImportTask(const QString &filename)94ImportTask::ImportTask(const QString &filename)
144 : _filename(filename)95 : _filename(filename)
145{96{
@@ -151,7 +102,7 @@ void ImportTask::run() { · 5 unmodified lines
151 // We start by cleaning up the shared voxel system just in case102 // We start by cleaning up the shared voxel system just in case
152 voxelSystem->killLocalVoxels();103 voxelSystem->killLocalVoxels();
153 104
154 // Then we call the righ method for the job105 // Then we call the right method for the job
155 if (_filename.endsWith(".png", Qt::CaseInsensitive)) {106 if (_filename.endsWith(".png", Qt::CaseInsensitive)) {
156 voxelSystem->getTree()->readFromSquareARGB32Pixels(_filename.toLocal8Bit().data());107 voxelSystem->getTree()->readFromSquareARGB32Pixels(_filename.toLocal8Bit().data());
157 } else if (_filename.endsWith(".svo", Qt::CaseInsensitive)) {108 } else if (_filename.endsWith(".svo", Qt::CaseInsensitive)) {
@@ -163,6 +114,6 @@ void ImportTask::run() { · 5 unmodified lines
163 qDebug() << "[ERROR] Invalid file extension." << endl;114 qDebug() << "[ERROR] Invalid file extension." << endl;
164 }115 }
165 116
166 // Here we reaverage the tree so that he is ready for preview117 // Here we reaverage the tree so that it is ready for preview
167 voxelSystem->getTree()->reaverageOctreeElements();118 voxelSystem->getTree()->reaverageOctreeElements();
168}119}
interface/src/voxels/VoxelImporter.h+12−11
@@ -14,8 +14,8 @@ · 13 unmodified lines
14 14
15#include <QThread>15#include <QThread>
16#include <QRunnable>16#include <QRunnable>
17#include <QStringList>
17 18
18#include "ui/ImportDialog.h"
19#include "voxels/VoxelSystem.h"19#include "voxels/VoxelSystem.h"
20 20
21class ImportTask;21class ImportTask;
@@ -23,28 +23,29 @@ class ImportTask; · 1 unmodified line
23class VoxelImporter : public QObject {23class VoxelImporter : public QObject {
24 Q_OBJECT24 Q_OBJECT
25public:25public:
26 VoxelImporter(QWidget* parent = NULL);26 VoxelImporter();
27 ~VoxelImporter();27 ~VoxelImporter();
28 28
29 void reset();29 void reset();
30 void loadSettings(QSettings* settings);30 void cancel();
31 void saveSettings(QSettings* settings);
32
33 VoxelTree* getVoxelTree() { return &_voxelTree; }31 VoxelTree* getVoxelTree() { return &_voxelTree; }
32 bool validImportFile(const QString& filename);
34 33
35public slots:34public slots:
36 int exec();35 void import(const QString& filename);
37 void import();36
38 void cancel();37signals:
38 void importDone();
39 void importProgress(int);
39 40
40private:41private:
41 VoxelTree _voxelTree;42 VoxelTree _voxelTree;
42 ImportDialog _importDialog;
43
44 ImportTask* _task;43 ImportTask* _task;
45 bool _didImport;
46 44
47 void cleanupTask();45 void cleanupTask();
46
47private slots:
48 void finishImport();
48};49};
49 50
50#endif // hifi_VoxelImporter_h51#endif // hifi_VoxelImporter_h
libraries/animation/CMakeLists.txt+5−25
@@ -1,29 +1,9 @@
1set(ROOT_DIR ../..)
2set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
3
4# setup for find modules
5set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
6
7set(TARGET_NAME animation)1set(TARGET_NAME animation)
8 2
9find_package(Qt5Widgets REQUIRED)3# use setup_hifi_library macro to setup our project and link appropriate Qt modules
10 4setup_hifi_library(Network Script)
11include(${MACRO_DIR}/SetupHifiLibrary.cmake)
12setup_hifi_library(${TARGET_NAME})
13
14include(${MACRO_DIR}/IncludeGLM.cmake)
15include_glm(${TARGET_NAME} "${ROOT_DIR}")
16
17include(${MACRO_DIR}/LinkHifiLibrary.cmake)
18link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
19link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}")
20
21# link ZLIB
22find_package(ZLIB)
23 5
24target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets)6link_hifi_libraries(shared fbx)
25 7
26# add a definition for ssize_t so that windows doesn't bail8# call macro to link our dependencies and bubble them up via a property on our target
27if (WIN32)9link_shared_dependencies()
28 add_definitions(-Dssize_t=long)
29endif ()
libraries/audio/CMakeLists.txt+6−21
@@ -1,26 +1,11 @@
1set(ROOT_DIR ../..)
2set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
3
4# setup for find modules
5set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
6
7set(TARGET_NAME audio)1set(TARGET_NAME audio)
8 2
9find_package(Qt5 COMPONENTS Script)3# use setup_hifi_library macro to setup our project and link appropriate Qt modules
10include_directories(SYSTEM "${Qt5Script_INCLUDE_DIRS}")4setup_hifi_library(Network)
11
12# set up the external glm library
13include(${MACRO_DIR}/SetupHifiLibrary.cmake)
14setup_hifi_library(${TARGET_NAME})
15 5
16include(${MACRO_DIR}/IncludeGLM.cmake)6include_glm()
17include_glm(${TARGET_NAME} "${ROOT_DIR}")
18 7
19include(${MACRO_DIR}/LinkHifiLibrary.cmake)8link_hifi_libraries(networking shared)
20link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
21link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
22 9
23# add a definition for ssize_t so that windows doesn't bail10# call macro to link our dependencies and bubble them up via a property on our target
24if (WIN32)11link_shared_dependencies()
25 add_definitions(-Dssize_t=long)
26endif ()
libraries/audio/src/AudioFilter.cpp+26−0
@@ -0,0 +1,26 @@
1//
2// AudioFilter.cpp
3// hifi
4//
5// Created by Craig Hansen-Sturm on 8/10/14.
6// Copyright 2014 High Fidelity, Inc.
7//
8// Distributed under the Apache License, Version 2.0.
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//
11
12#include <math.h>
13#include <vector>
14#include <SharedUtil.h>
15#include "AudioRingBuffer.h"
16#include "AudioFilter.h"
17
18template<>
19AudioFilterPEQ3::FilterParameter AudioFilterPEQ3::_profiles[ AudioFilterPEQ3::_profileCount ][ AudioFilterPEQ3::_filterCount ] = {
20
21 // Freq Gain Q Freq Gain Q Freq Gain Q
22 { { 300.0f, 1.0f, 1.0f }, { 1000.0f, 1.0f, 1.0f }, { 4000.0f, 1.0f, 1.0f } }, // flat response (default)
23 { { 300.0f, 1.0f, 1.0f }, { 1000.0f, 1.0f, 1.0f }, { 4000.0f, 0.1f, 1.0f } }, // treble cut
24 { { 300.0f, 0.1f, 1.0f }, { 1000.0f, 1.0f, 1.0f }, { 4000.0f, 1.0f, 1.0f } }, // bass cut
25 { { 300.0f, 1.5f, 0.71f }, { 1000.0f, 0.5f, 1.0f }, { 4000.0f, 1.50f, 0.71f } } // smiley curve
26};
libraries/audio/src/AudioFilter.h+298−0
@@ -0,0 +1,298 @@
1//
2// AudioFilter.h
3// hifi
4//
5// Created by Craig Hansen-Sturm on 8/9/14.
6// Copyright 2014 High Fidelity, Inc.
7//
8// Distributed under the Apache License, Version 2.0.
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//
11
12#ifndef hifi_AudioFilter_h
13#define hifi_AudioFilter_h
14
15////////////////////////////////////////////////////////////////////////////////////////////
16// Implements a standard biquad filter in "Direct Form 1"
17// Reference http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
18//
19class AudioBiquad {
20
21 //
22 // private data
23 //
24 float _a0; // gain
25 float _a1; // feedforward 1
26 float _a2; // feedforward 2
27 float _b1; // feedback 1
28 float _b2; // feedback 2
29
30 float _xm1;
31 float _xm2;
32 float _ym1;
33 float _ym2;
34
35public:
36
37 //
38 // ctor/dtor
39 //
40 AudioBiquad()
41 : _xm1(0.)
42 , _xm2(0.)
43 , _ym1(0.)
44 , _ym2(0.) {
45 setParameters(0.,0.,0.,0.,0.);
46 }
47
48 ~AudioBiquad() {
49 }
50
51 //
52 // public interface
53 //
54 void setParameters( const float a0, const float a1, const float a2, const float b1, const float b2 ) {
55 _a0 = a0; _a1 = a1; _a2 = a2; _b1 = b1; _b2 = b2;
56 }
57
58 void getParameters( float& a0, float& a1, float& a2, float& b1, float& b2 ) {
59 a0 = _a0; a1 = _a1; a2 = _a2; b1 = _b1; b2 = _b2;
60 }
61
62 void render( const float* in, float* out, const int frames) {
63
64 float x;
65 float y;
66
67 for (int i = 0; i < frames; ++i) {
68
69 x = *in++;
70
71 // biquad
72 y = (_a0 * x)
73 + (_a1 * _xm1)
74 + (_a2 * _xm2)
75 - (_b1 * _ym1)
76 - (_b2 * _ym2);
77
78 // update delay line
79 _xm2 = _xm1;
80 _xm1 = x;
81 _ym2 = _ym1;
82 _ym1 = y;
83
84 *out++ = y;
85 }
86 }
87
88 void reset() {
89 _xm1 = _xm2 = _ym1 = _ym2 = 0.;
90 }
91};
92
93////////////////////////////////////////////////////////////////////////////////////////////
94// Implements a single-band parametric EQ using a biquad "peaking EQ" configuration
95//
96// gain > 1.0 boosts the center frequency
97// gain < 1.0 cuts the center frequency
98//
99class AudioParametricEQ {
100
101 //
102 // private data
103 //
104 AudioBiquad _kernel;
105 float _sampleRate;
106 float _frequency;
107 float _gain;
108 float _slope;
109
110 // helpers
111 void updateKernel() {
112
113 /*
114 a0 = 1 + alpha*A
115 a1 = -2*cos(w0)
116 a2 = 1 - alpha*A
117 b1 = -2*cos(w0)
118 b2 = 1 - alpha/A
119 */
120
121 const float a = _gain;
122 const float omega = TWO_PI * _frequency / _sampleRate;
123 const float alpha = 0.5f * sinf(omega) / _slope;
124 const float gamma = 1.0f / ( 1.0f + (alpha/a) );
125
126 const float a0 = 1.0f + (alpha*a);
127 const float a1 = -2.0f * cosf(omega);
128 const float a2 = 1.0f - (alpha*a);
129 const float b1 = a1;
130 const float b2 = 1.0f - (alpha/a);
131
132 _kernel.setParameters( a0*gamma,a1*gamma,a2*gamma,b1*gamma,b2*gamma );
133 }
134
135public:
136 //
137 // ctor/dtor
138 //
139 AudioParametricEQ() {
140
141 setParameters(0.,0.,0.,0.);
142 updateKernel();
143 }
144
145 ~AudioParametricEQ() {
146 }
147
148 //
149 // public interface
150 //
151 void setParameters( const float sampleRate, const float frequency, const float gain, const float slope ) {
152
153 _sampleRate = std::max(sampleRate,1.0f);
154 _frequency = std::max(frequency,2.0f);
155 _gain = std::max(gain,0.0f);
156 _slope = std::max(slope,0.00001f);
157
158 updateKernel();
159 }
160
161 void getParameters( float& sampleRate, float& frequency, float& gain, float& slope ) {
162 sampleRate = _sampleRate; frequency = _frequency; gain = _gain; slope = _slope;
163 }
164
165 void render(const float* in, float* out, const int frames ) {
166 _kernel.render(in,out,frames);
167 }
168
169 void reset() {
170 _kernel.reset();
171 }
172};
173
174////////////////////////////////////////////////////////////////////////////////////////////
175// Helper/convenience class that implements a bank of EQ objects
176//
177template< typename T, const int N>
178class AudioFilterBank {
179
180 //
181 // types
182 //
183 struct FilterParameter {
184 float _p1;
185 float _p2;
186 float _p3;
187 };
188
189 //
190 // private static data
191 //
192 static const int _filterCount = N;
193 static const int _profileCount = 4;
194
195 static FilterParameter _profiles[_profileCount][_filterCount];
196
197 //
198 // private data
199 //
200 T _filters[ _filterCount ];
201 float* _buffer;
202 float _sampleRate;
203 uint16_t _frameCount;
204
205public:
206
207 //
208 // ctor/dtor
209 //
210 AudioFilterBank()
211 : _buffer(NULL)
212 , _sampleRate(0.)
213 , _frameCount(0) {
214 }
215
216 ~AudioFilterBank() {
217 finalize();
218 }
219
220 //
221 // public interface
222 //
223 void initialize( const float sampleRate, const int frameCount ) {
224 finalize();
225
226 _buffer = (float*)malloc( frameCount * sizeof(float) );
227 if(!_buffer) {
228 return;
229 }
230
231 _sampleRate = sampleRate;
232 _frameCount = frameCount;
233
234 reset();
235 loadProfile(0); // load default profile "flat response" into the bank (see AudioFilter.cpp)
236 }
237
238 void finalize() {
239 if (_buffer ) {
240 free (_buffer);
241 _buffer = NULL;
242 }
243 }
244
245 void loadProfile( int profileIndex ) {
246 if (profileIndex >= 0 && profileIndex < _profileCount) {
247
248 for (int i = 0; i < _filterCount; ++i) {
249 FilterParameter p = _profiles[profileIndex][i];
250
251 _filters[i].setParameters(_sampleRate,p._p1,p._p2,p._p3);
252 }
253 }
254 }
255
256 void render( const float* in, float* out, const int frameCount ) {
257 for (int i = 0; i < _filterCount; ++i) {
258 _filters[i].render( in, out, frameCount );
259 }
260 }
261
262 void render( const int16_t* in, int16_t* out, const int frameCount ) {
263 if (!_buffer || ( frameCount > _frameCount ))
264 return;
265
266 const int scale = (2 << ((8*sizeof(int16_t))-1));
267
268 // convert int16_t to float32 (normalized to -1. ... 1.)
269 for (int i = 0; i < frameCount; ++i) {
270 _buffer[i] = ((float)(*in++)) / scale;
271 }
272 // for this filter, we share input/output buffers at each stage, but our design does not mandate this
273 render( _buffer, _buffer, frameCount );
274
275 // convert float32 to int16_t
276 for (int i = 0; i < frameCount; ++i) {
277 *out++ = (int16_t)(_buffer[i] * scale);
278 }
279 }
280
281 void reset() {
282 for (int i = 0; i < _filterCount; ++i ) {
283 _filters[i].reset();
284 }
285 }
286
287};
288
289////////////////////////////////////////////////////////////////////////////////////////////
290// Specializations of AudioFilterBank
291//
292typedef AudioFilterBank< AudioParametricEQ, 1> AudioFilterPEQ1; // bank with one band of PEQ
293typedef AudioFilterBank< AudioParametricEQ, 2> AudioFilterPEQ2; // bank with two bands of PEQ
294typedef AudioFilterBank< AudioParametricEQ, 3> AudioFilterPEQ3; // bank with three bands of PEQ
295// etc....
296
297
298#endif // hifi_AudioFilter_h
libraries/audio/src/AudioRingBuffer.cpp+2−2
@@ -15,9 +15,9 @@ · 14 unmodified lines
15 15
16#include <QtCore/QDebug>16#include <QtCore/QDebug>
17 17
18#include "PacketHeaders.h"18#include <PacketHeaders.h>
19#include "AudioRingBuffer.h"
20 19
20#include "AudioRingBuffer.h"
21 21
22AudioRingBuffer::AudioRingBuffer(int numFrameSamples, bool randomAccessMode, int numFramesCapacity) :22AudioRingBuffer::AudioRingBuffer(int numFrameSamples, bool randomAccessMode, int numFramesCapacity) :
23 _frameCapacity(numFramesCapacity),23 _frameCapacity(numFramesCapacity),
libraries/audio/src/AudioRingBuffer.h+2−4
@@ -15,12 +15,10 @@ · 14 unmodified lines
15#include <limits>15#include <limits>
16#include <stdint.h>16#include <stdint.h>
17 17
18#include <glm/glm.hpp>
19
20#include <QtCore/QIODevice>18#include <QtCore/QIODevice>
21 19
22#include "NodeData.h"20#include <SharedUtil.h>
23#include "SharedUtil.h"21#include <NodeData.h>
24 22
25const int SAMPLE_RATE = 24000;23const int SAMPLE_RATE = 24000;
26 24
libraries/audio/src/InboundAudioStream.cpp+2−0
@@ -9,6 +9,8 @@ · 8 unmodified lines
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//10//
11 11
12#include <glm/glm.hpp>
13
12#include "InboundAudioStream.h"14#include "InboundAudioStream.h"
13#include "PacketHeaders.h"15#include "PacketHeaders.h"
14 16
libraries/avatars/CMakeLists.txt+7−25
@@ -1,30 +1,12 @@
1set(ROOT_DIR ../..)
2set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
3
4# setup for find modules
5set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
6
7set(TARGET_NAME avatars)1set(TARGET_NAME avatars)
8 2
9find_package(Qt5Script REQUIRED)3# use setup_hifi_library macro to setup our project and link appropriate Qt modules
10 4setup_hifi_library(Network Script)
11include(${MACRO_DIR}/SetupHifiLibrary.cmake)
12setup_hifi_library(${TARGET_NAME})
13
14include(${MACRO_DIR}/IncludeGLM.cmake)
15include_glm(${TARGET_NAME} "${ROOT_DIR}")
16
17include(${MACRO_DIR}/LinkHifiLibrary.cmake)
18link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
19 5
20# link in the hifi voxels library6include_glm()
21link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}")
22link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}")
23link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
24 7
25target_link_libraries(${TARGET_NAME} Qt5::Script)8link_hifi_libraries(shared octree voxels networking)
9include_hifi_library_headers(fbx)
26 10
27# add a definition for ssize_t so that windows doesn't bail11# call macro to link our dependencies and bubble them up via a property on our target
28if (WIN32)12link_shared_dependencies()
29 add_definitions(-Dssize_t=long)
30endif ()
libraries/avatars/src/AvatarData.cpp+1−1
@@ -22,7 +22,7 @@ · 21 unmodified lines
22#include <NetworkAccessManager.h>22#include <NetworkAccessManager.h>
23#include <NodeList.h>23#include <NodeList.h>
24#include <PacketHeaders.h>24#include <PacketHeaders.h>
25#include <SharedUtil.h>25#include <GLMHelpers.h>
26#include <StreamUtils.h>26#include <StreamUtils.h>
27#include <UUID.h>27#include <UUID.h>
28#include <VoxelConstants.h>28#include <VoxelConstants.h>
libraries/avatars/src/HeadData.cpp+2−2
@@ -11,13 +11,13 @@ · 10 unmodified lines
11 11
12#include <glm/gtx/quaternion.hpp>12#include <glm/gtx/quaternion.hpp>
13 13
14#include <FBXReader.h>
15#include <GLMHelpers.h>
14#include <OctreeConstants.h>16#include <OctreeConstants.h>
15 17
16#include "AvatarData.h"18#include "AvatarData.h"
17#include "HeadData.h"19#include "HeadData.h"
18 20
19#include "../fbx/src/FBXReader.h"
20
21HeadData::HeadData(AvatarData* owningAvatar) :21HeadData::HeadData(AvatarData* owningAvatar) :
22 _baseYaw(0.0f),22 _baseYaw(0.0f),
23 _basePitch(0.0f),23 _basePitch(0.0f),
libraries/avatars/src/Referential.cpp+1−1
@@ -9,7 +9,7 @@ · 8 unmodified lines
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//10//
11 11
12#include <SharedUtil.h>12#include <GLMHelpers.h>
13 13
14#include "AvatarData.h"14#include "AvatarData.h"
15#include "Referential.h"15#include "Referential.h"
libraries/embedded-webserver/CMakeLists.txt+4−11
@@ -1,14 +1,7 @@
1set(ROOT_DIR ../..)
2set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
3
4# setup for find modules
5set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
6
7set(TARGET_NAME embedded-webserver)1set(TARGET_NAME embedded-webserver)
8 2
9find_package(Qt5Network REQUIRED)3# use setup_hifi_library macro to setup our project and link appropriate Qt modules
10 4setup_hifi_library(Network)
11include(${MACRO_DIR}/SetupHifiLibrary.cmake)
12setup_hifi_library(${TARGET_NAME})
13 5
14target_link_libraries(${TARGET_NAME} Qt5::Network)6# call macro to link our dependencies and bubble them up via a property on our target
7link_shared_dependencies()
libraries/entities/CMakeLists.txt+6−34
@@ -1,39 +1,11 @@
1set(ROOT_DIR ../..)
2set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
3
4# setup for find modules
5set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
6
7set(TARGET_NAME entities)1set(TARGET_NAME entities)
8 2
9find_package(Qt5Widgets REQUIRED)3# use setup_hifi_library macro to setup our project and link appropriate Qt modules
10 4setup_hifi_library(Network Script)
11include(${MACRO_DIR}/AutoMTC.cmake)
12auto_mtc(${TARGET_NAME} "${ROOT_DIR}")
13
14include(${MACRO_DIR}/SetupHifiLibrary.cmake)
15setup_hifi_library(${TARGET_NAME} "${AUTOMTC_SRC}")
16
17include(${MACRO_DIR}/IncludeGLM.cmake)
18include_glm(${TARGET_NAME} "${ROOT_DIR}")
19
20include(${MACRO_DIR}/LinkHifiLibrary.cmake)
21link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
22link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}")
23link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}")
24link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
25link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}")
26
27# for streamable
28link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}")
29 5
30# link ZLIB6include_glm()
31find_package(ZLIB)
32 7
33include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}")8link_hifi_libraries(shared octree fbx networking animation)
34target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets)
35 9
36# add a definition for ssize_t so that windows doesn't bail10# call macro to link our dependencies and bubble them up via a property on our target
37if (WIN32)11link_shared_dependencies()
38 add_definitions(-Dssize_t=long)
39endif ()
libraries/fbx/CMakeLists.txt+8−23
@@ -1,30 +1,15 @@
1set(ROOT_DIR ../..)
2set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
3
4# setup for find modules
5set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
6
7set(TARGET_NAME fbx)1set(TARGET_NAME fbx)
8 2
9include(${MACRO_DIR}/SetupHifiLibrary.cmake)3# use setup_hifi_library macro to setup our project and link appropriate Qt modules
10setup_hifi_library(${TARGET_NAME})4setup_hifi_library()
11
12include(${MACRO_DIR}/IncludeGLM.cmake)
13include_glm(${TARGET_NAME} "${ROOT_DIR}")
14 5
15include(${MACRO_DIR}/LinkHifiLibrary.cmake)6include_glm()
16link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
17link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
18link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}")
19link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}")
20 7
21# link ZLIB8link_hifi_libraries(shared networking octree voxels)
22find_package(ZLIB)
23 9
10find_package(ZLIB REQUIRED)
24include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}")11include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}")
25target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets)12list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${ZLIB_LIBRARIES}")
26 13
27# add a definition for ssize_t so that windows doesn't bail14# call macro to link our dependencies and bubble them up via a property on our target
28if (WIN32)15link_shared_dependencies()
29 add_definitions(-Dssize_t=long)
30endif ()
libraries/fbx/src/FBXReader.cpp+1−1
@@ -23,9 +23,9 @@ · 22 unmodified lines
23#include <glm/gtx/transform.hpp>23#include <glm/gtx/transform.hpp>
24 24
25#include <GeometryUtil.h>25#include <GeometryUtil.h>
26#include <GLMHelpers.h>
26#include <OctalCode.h>27#include <OctalCode.h>
27#include <Shape.h>28#include <Shape.h>
28#include <SharedUtil.h>
29 29
30#include <VoxelTree.h>30#include <VoxelTree.h>
31 31
libraries/metavoxels/CMakeLists.txt+7−22
@@ -1,29 +1,14 @@
1set(ROOT_DIR ../..)
2set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
3
4# setup for find modules
5set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
6
7set(TARGET_NAME metavoxels)1set(TARGET_NAME metavoxels)
8 2
9find_package(Qt5 COMPONENTS Network Script Widgets)3auto_mtc()
10 4
11include(${MACRO_DIR}/AutoMTC.cmake)5# use setup_hifi_library macro to setup our project and link appropriate Qt modules
12auto_mtc(${TARGET_NAME} "${ROOT_DIR}")6setup_hifi_library(Network Script Widgets)
13
14include(${MACRO_DIR}/SetupHifiLibrary.cmake)
15setup_hifi_library(${TARGET_NAME} "${AUTOMTC_SRC}")
16 7
17# link in the networking library8# link in the networking library
18include(${MACRO_DIR}/LinkHifiLibrary.cmake)9link_hifi_libraries(shared networking)
19link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
20
21include(${MACRO_DIR}/IncludeGLM.cmake)
22include_glm(${TARGET_NAME} "${ROOT_DIR}")
23 10
24target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Script)11include_glm()
25 12
26# add a definition for ssize_t so that windows doesn't bail13# call macro to link our dependencies and bubble them up via a property on our target
27if (WIN32)14link_shared_dependencies()
28 add_definitions(-Dssize_t=long)
29endif ()
libraries/metavoxels/src/AttributeRegistry.cpp+297−65
@@ -489,22 +489,92 @@ HeightfieldData::HeightfieldData(const QByteArray& contents) : · 488 unmodified lines
489 _contents(contents) {489 _contents(contents) {
490}490}
491 491
492const int BYTES_PER_PIXEL = 3;492HeightfieldData::HeightfieldData(Bitstream& in, int bytes, bool color) {
493 read(in, bytes, color);
494}
493 495
494HeightfieldData::HeightfieldData(Bitstream& in, int bytes, bool color) :496enum HeightfieldImage { NULL_HEIGHTFIELD_IMAGE, NORMAL_HEIGHTFIELD_IMAGE, DEFLATED_HEIGHTFIELD_IMAGE };
495 _encoded(in.readAligned(bytes)) {497
496 498static QByteArray encodeHeightfieldImage(const QImage& image) {
497 QImage image = QImage::fromData(_encoded).convertToFormat(QImage::Format_RGB888);499 if (image.isNull()) {
498 if (color) {500 return QByteArray(1, NULL_HEIGHTFIELD_IMAGE);
499 _contents.resize(image.width() * image.height() * BYTES_PER_PIXEL);501 }
500 memcpy(_contents.data(), image.constBits(), _contents.size());502 QBuffer buffer;
503 buffer.open(QIODevice::WriteOnly);
504 const int JPEG_ENCODE_THRESHOLD = 16;
505 if (image.width() >= JPEG_ENCODE_THRESHOLD && image.height() >= JPEG_ENCODE_THRESHOLD) {
506 qint32 offsetX = image.offset().x(), offsetY = image.offset().y();
507 buffer.write((char*)&offsetX, sizeof(qint32));
508 buffer.write((char*)&offsetY, sizeof(qint32));
509 image.save(&buffer, "JPG");
510 return QByteArray(1, DEFLATED_HEIGHTFIELD_IMAGE) + qCompress(buffer.data());
501 511
502 } else {512 } else {
503 _contents.resize(image.width() * image.height());513 buffer.putChar(NORMAL_HEIGHTFIELD_IMAGE);
504 char* dest = _contents.data();514 image.save(&buffer, "PNG");
505 for (const uchar* src = image.constBits(), *end = src + _contents.size() * BYTES_PER_PIXEL;515 return buffer.data();
506 src != end; src += BYTES_PER_PIXEL) {516 }
507 *dest++ = *src;517}
518
519const QImage decodeHeightfieldImage(const QByteArray& data) {
520 switch (data.at(0)) {
521 case NULL_HEIGHTFIELD_IMAGE:
522 default:
523 return QImage();
524
525 case NORMAL_HEIGHTFIELD_IMAGE:
526 return QImage::fromData(QByteArray::fromRawData(data.constData() + 1, data.size() - 1));
527
528 case DEFLATED_HEIGHTFIELD_IMAGE: {
529 QByteArray inflated = qUncompress((const uchar*)data.constData() + 1, data.size() - 1);
530 const int OFFSET_SIZE = sizeof(qint32) * 2;
531 QImage image = QImage::fromData((const uchar*)inflated.constData() + OFFSET_SIZE, inflated.size() - OFFSET_SIZE);
532 const qint32* offsets = (const qint32*)inflated.constData();
533 image.setOffset(QPoint(offsets[0], offsets[1]));
534 return image;
535 }
536 }
537}
538
539HeightfieldData::HeightfieldData(Bitstream& in, int bytes, const HeightfieldDataPointer& reference, bool color) {
540 if (!reference) {
541 read(in, bytes, color);
542 return;
543 }
544 QMutexLocker locker(&reference->_encodedDeltaMutex);
545 reference->_encodedDelta = in.readAligned(bytes);
546 reference->_deltaData = this;
547 _contents = reference->_contents;
548 QImage image = decodeHeightfieldImage(reference->_encodedDelta);
549 if (image.isNull()) {
550 return;
551 }
552 QPoint offset = image.offset();
553 image = image.convertToFormat(QImage::Format_RGB888);
554 if (offset.x() == 0) {
555 set(image, color);
556 return;
557 }
558 int minX = offset.x() - 1;
559 int minY = offset.y() - 1;
560 if (color) {
561 int size = glm::sqrt(_contents.size() / (float)COLOR_BYTES);
562 char* dest = _contents.data() + (minY * size + minX) * COLOR_BYTES;
563 int destStride = size * COLOR_BYTES;
564 int srcStride = image.width() * COLOR_BYTES;
565 for (int y = 0; y < image.height(); y++) {
566 memcpy(dest, image.constScanLine(y), srcStride);
567 dest += destStride;
568 }
569 } else {
570 int size = glm::sqrt((float)_contents.size());
571 char* lineDest = _contents.data() + minY * size + minX;
572 for (int y = 0; y < image.height(); y++) {
573 const uchar* src = image.constScanLine(y);
574 for (char* dest = lineDest, *end = dest + image.width(); dest != end; dest++, src += COLOR_BYTES) {
575 *dest = *src;
576 }
577 lineDest += size;
508 }578 }
509 }579 }
510}580}
@@ -514,7 +584,7 @@ void HeightfieldData::write(Bitstream& out, bool color) { · 3 unmodified lines
514 if (_encoded.isEmpty()) {584 if (_encoded.isEmpty()) {
515 QImage image; 585 QImage image;
516 if (color) { 586 if (color) {
517 int size = glm::sqrt(_contents.size() / (float)BYTES_PER_PIXEL);587 int size = glm::sqrt(_contents.size() / (float)COLOR_BYTES);
518 image = QImage((uchar*)_contents.data(), size, size, QImage::Format_RGB888);588 image = QImage((uchar*)_contents.data(), size, size, QImage::Format_RGB888);
519 } else {589 } else {
520 int size = glm::sqrt((float)_contents.size());590 int size = glm::sqrt((float)_contents.size());
@@ -526,38 +596,170 @@ void HeightfieldData::write(Bitstream& out, bool color) { · 5 unmodified lines
526 *dest++ = *src;596 *dest++ = *src;
527 }597 }
528 }598 }
529 QBuffer buffer(&_encoded);599 _encoded = encodeHeightfieldImage(image);
530 buffer.open(QIODevice::WriteOnly);
531 image.save(&buffer, "JPG");
532 }600 }
533 out << _encoded.size();601 out << _encoded.size();
534 out.writeAligned(_encoded);602 out.writeAligned(_encoded);
535}603}
536 604
605void HeightfieldData::writeDelta(Bitstream& out, const HeightfieldDataPointer& reference, bool color) {
606 if (!reference || reference->getContents().size() != _contents.size()) {
607 write(out, color);
608 return;
609 }
610 QMutexLocker locker(&reference->_encodedDeltaMutex);
611 if (reference->_encodedDelta.isEmpty() || reference->_deltaData != this) {
612 QImage image;
613 int minX, minY;
614 if (color) {
615 int size = glm::sqrt(_contents.size() / (float)COLOR_BYTES);
616 minX = size;
617 minY = size;
618 int maxX = -1, maxY = -1;
619 const char* src = _contents.constData();
620 const char* ref = reference->_contents.constData();
621 for (int y = 0; y < size; y++) {
622 bool difference = false;
623 for (int x = 0; x < size; x++, src += COLOR_BYTES, ref += COLOR_BYTES) {
624 if (src[0] != ref[0] || src[1] != ref[1] || src[2] != ref[2]) {
625 minX = qMin(minX, x);
626 maxX = qMax(maxX, x);
627 difference = true;
628 }
629 }
630 if (difference) {
631 minY = qMin(minY, y);
632 maxY = qMax(maxY, y);
633 }
634 }
635 if (maxX >= minX) {
636 int width = maxX - minX + 1;
637 int height = maxY - minY + 1;
638 image = QImage(width, height, QImage::Format_RGB888);
639 src = _contents.constData() + (minY * size + minX) * COLOR_BYTES;
640 int srcStride = size * COLOR_BYTES;
641 int destStride = width * COLOR_BYTES;
642 for (int y = 0; y < height; y++) {
643 memcpy(image.scanLine(y), src, destStride);
644 src += srcStride;
645 }
646 }
647 } else {
648 int size = glm::sqrt((float)_contents.size());
649 minX = size;
650 minY = size;
651 int maxX = -1, maxY = -1;
652 const char* src = _contents.constData();
653 const char* ref = reference->_contents.constData();
654 for (int y = 0; y < size; y++) {
655 bool difference = false;
656 for (int x = 0; x < size; x++) {
657 if (*src++ != *ref++) {
658 minX = qMin(minX, x);
659 maxX = qMax(maxX, x);
660 difference = true;
661 }
662 }
663 if (difference) {
664 minY = qMin(minY, y);
665 maxY = qMax(maxY, y);
666 }
667 }
668 if (maxX >= minX) {
669 int width = qMax(maxX - minX + 1, 0);
670 int height = qMax(maxY - minY + 1, 0);
671 image = QImage(width, height, QImage::Format_RGB888);
672 const uchar* lineSrc = (const uchar*)_contents.constData() + minY * size + minX;
673 for (int y = 0; y < height; y++) {
674 uchar* dest = image.scanLine(y);
675 for (const uchar* src = lineSrc, *end = src + width; src != end; src++) {
676 *dest++ = *src;
677 *dest++ = *src;
678 *dest++ = *src;
679 }
680 lineSrc += size;
681 }
682 }
683 }
684 image.setOffset(QPoint(minX + 1, minY + 1));
685 reference->_encodedDelta = encodeHeightfieldImage(image);
686 reference->_deltaData = this;
687 }
688 out << reference->_encodedDelta.size();
689 out.writeAligned(reference->_encodedDelta);
690}
691
692void HeightfieldData::read(Bitstream& in, int bytes, bool color) {
693 set(decodeHeightfieldImage(_encoded = in.readAligned(bytes)).convertToFormat(QImage::Format_RGB888), color);
694}
695
696void HeightfieldData::set(const QImage& image, bool color) {
697 if (color) {
698 _contents.resize(image.width() * image.height() * COLOR_BYTES);
699 memcpy(_contents.data(), image.constBits(), _contents.size());
700
701 } else {
702 _contents.resize(image.width() * image.height());
703 char* dest = _contents.data();
704 for (const uchar* src = image.constBits(), *end = src + _contents.size() * COLOR_BYTES;
705 src != end; src += COLOR_BYTES) {
706 *dest++ = *src;
707 }
708 }
709}
710
537HeightfieldAttribute::HeightfieldAttribute(const QString& name) :711HeightfieldAttribute::HeightfieldAttribute(const QString& name) :
538 InlineAttribute<HeightfieldDataPointer>(name) {712 InlineAttribute<HeightfieldDataPointer>(name) {
539}713}
540 714
541void HeightfieldAttribute::read(Bitstream& in, void*& value, bool isLeaf) const {715void HeightfieldAttribute::read(Bitstream& in, void*& value, bool isLeaf) const {
542 if (isLeaf) { 716 if (!isLeaf) {
543 int size;717 return;
544 in >> size;718 }
545 if (size == 0) {719 int size;
546 *(HeightfieldDataPointer*)&value = HeightfieldDataPointer();720 in >> size;
547 } else {721 if (size == 0) {
548 *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, false));722 *(HeightfieldDataPointer*)&value = HeightfieldDataPointer();
549 }723 } else {
724 *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, false));
550 }725 }
551}726}
552 727
553void HeightfieldAttribute::write(Bitstream& out, void* value, bool isLeaf) const {728void HeightfieldAttribute::write(Bitstream& out, void* value, bool isLeaf) const {
554 if (isLeaf) {729 if (!isLeaf) {
555 HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);730 return;
556 if (data) {731 }
557 data->write(out, false);732 HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
558 } else {733 if (data) {
559 out << 0;734 data->write(out, false);
560 }735 } else {
736 out << 0;
737 }
738}
739
740void HeightfieldAttribute::readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const {
741 if (!isLeaf) {
742 return;
743 }
744 int size;
745 in >> size;
746 if (size == 0) {
747 *(HeightfieldDataPointer*)&value = HeightfieldDataPointer();
748 } else {
749 *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(
750 in, size, decodeInline<HeightfieldDataPointer>(reference), false));
751 }
752}
753
754void HeightfieldAttribute::writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const {
755 if (!isLeaf) {
756 return;
757 }
758 HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
759 if (data) {
760 data->writeDelta(out, decodeInline<HeightfieldDataPointer>(reference), false);
761 } else {
762 out << 0;
561 }763 }
562}764}
563 765
@@ -635,25 +837,53 @@ HeightfieldColorAttribute::HeightfieldColorAttribute(const QString& name) : · 71 unmodified lines
635}837}
636 838
637void HeightfieldColorAttribute::read(Bitstream& in, void*& value, bool isLeaf) const {839void HeightfieldColorAttribute::read(Bitstream& in, void*& value, bool isLeaf) const {
638 if (isLeaf) {840 if (!isLeaf) {
639 int size;841 return;
640 in >> size;842 }
641 if (size == 0) {843 int size;
642 *(HeightfieldDataPointer*)&value = HeightfieldDataPointer();844 in >> size;
643 } else {845 if (size == 0) {
644 *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, true));846 *(HeightfieldDataPointer*)&value = HeightfieldDataPointer();
645 }847 } else {
848 *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, true));
646 }849 }
647}850}
648 851
649void HeightfieldColorAttribute::write(Bitstream& out, void* value, bool isLeaf) const {852void HeightfieldColorAttribute::write(Bitstream& out, void* value, bool isLeaf) const {
650 if (isLeaf) {853 if (!isLeaf) {
651 HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);854 return;
652 if (data) {855 }
653 data->write(out, true);856 HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
654 } else {857 if (data) {
655 out << 0;858 data->write(out, true);
656 }859 } else {
860 out << 0;
861 }
862}
863
864void HeightfieldColorAttribute::readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const {
865 if (!isLeaf) {
866 return;
867 }
868 int size;
869 in >> size;
870 if (size == 0) {
871 *(HeightfieldDataPointer*)&value = HeightfieldDataPointer();
872 } else {
873 *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(
874 in, size, decodeInline<HeightfieldDataPointer>(reference), true));
875 }
876}
877
878void HeightfieldColorAttribute::writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const {
879 if (!isLeaf) {
880 return;
881 }
882 HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value);
883 if (data) {
884 data->writeDelta(out, decodeInline<HeightfieldDataPointer>(reference), true);
885 } else {
886 out << 0;
657 }887 }
658}888}
659 889
@@ -669,8 +899,8 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post · 9 unmodified lines
669 *(HeightfieldDataPointer*)&parent = HeightfieldDataPointer();899 *(HeightfieldDataPointer*)&parent = HeightfieldDataPointer();
670 return true;900 return true;
671 }901 }
672 int size = glm::sqrt(maxSize / (float)BYTES_PER_PIXEL);902 int size = glm::sqrt(maxSize / (float)HeightfieldData::COLOR_BYTES);
673 QByteArray contents(size * size * BYTES_PER_PIXEL, 0);903 QByteArray contents(size * size * HeightfieldData::COLOR_BYTES, 0);
674 int halfSize = size / 2;904 int halfSize = size / 2;
675 for (int i = 0; i < MERGE_COUNT; i++) {905 for (int i = 0; i < MERGE_COUNT; i++) {
676 HeightfieldDataPointer child = decodeInline<HeightfieldDataPointer>(children[i]);906 HeightfieldDataPointer child = decodeInline<HeightfieldDataPointer>(children[i]);
@@ -678,7 +908,7 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post · 1 unmodified line
678 continue;908 continue;
679 }909 }
680 const QByteArray& childContents = child->getContents();910 const QByteArray& childContents = child->getContents();
681 int childSize = glm::sqrt(childContents.size() / (float)BYTES_PER_PIXEL);911 int childSize = glm::sqrt(childContents.size() / (float)HeightfieldData::COLOR_BYTES);
682 const int INDEX_MASK = 1;912 const int INDEX_MASK = 1;
683 int xIndex = i & INDEX_MASK;913 int xIndex = i & INDEX_MASK;
684 const int Y_SHIFT = 1;914 const int Y_SHIFT = 1;
@@ -688,24 +918,25 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post · 3 unmodified lines
688 }918 }
689 int Z_SHIFT = 2;919 int Z_SHIFT = 2;
690 int zIndex = (i >> Z_SHIFT) & INDEX_MASK;920 int zIndex = (i >> Z_SHIFT) & INDEX_MASK;
691 char* dest = contents.data() + ((zIndex * halfSize * size) + (xIndex * halfSize)) * BYTES_PER_PIXEL;921 char* dest = contents.data() + ((zIndex * halfSize * size) + (xIndex * halfSize)) * HeightfieldData::COLOR_BYTES;
692 uchar* src = (uchar*)childContents.data();922 uchar* src = (uchar*)childContents.data();
693 int childStride = childSize * BYTES_PER_PIXEL;923 int childStride = childSize * HeightfieldData::COLOR_BYTES;
694 int stride = size * BYTES_PER_PIXEL;924 int stride = size * HeightfieldData::COLOR_BYTES;
695 int halfStride = stride / 2;925 int halfStride = stride / 2;
696 int childStep = 2 * BYTES_PER_PIXEL;926 int childStep = 2 * HeightfieldData::COLOR_BYTES;
697 int redOffset3 = childStride + BYTES_PER_PIXEL;927 int redOffset3 = childStride + HeightfieldData::COLOR_BYTES;
698 int greenOffset1 = BYTES_PER_PIXEL + 1;928 int greenOffset1 = HeightfieldData::COLOR_BYTES + 1;
699 int greenOffset2 = childStride + 1;929 int greenOffset2 = childStride + 1;
700 int greenOffset3 = childStride + BYTES_PER_PIXEL + 1;930 int greenOffset3 = childStride + HeightfieldData::COLOR_BYTES + 1;
701 int blueOffset1 = BYTES_PER_PIXEL + 2;931 int blueOffset1 = HeightfieldData::COLOR_BYTES + 2;
702 int blueOffset2 = childStride + 2;932 int blueOffset2 = childStride + 2;
703 int blueOffset3 = childStride + BYTES_PER_PIXEL + 2;933 int blueOffset3 = childStride + HeightfieldData::COLOR_BYTES + 2;
704 if (childSize == size) {934 if (childSize == size) {
705 // simple case: one destination value for four child values935 // simple case: one destination value for four child values
706 for (int z = 0; z < halfSize; z++) {936 for (int z = 0; z < halfSize; z++) {
707 for (char* end = dest + halfSize * BYTES_PER_PIXEL; dest != end; src += childStep) {937 for (char* end = dest + halfSize * HeightfieldData::COLOR_BYTES; dest != end; src += childStep) {
708 *dest++ = ((int)src[0] + (int)src[BYTES_PER_PIXEL] + (int)src[childStride] + (int)src[redOffset3]) >> 2;938 *dest++ = ((int)src[0] + (int)src[HeightfieldData::COLOR_BYTES] +
939 (int)src[childStride] + (int)src[redOffset3]) >> 2;
709 *dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2;940 *dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2;
710 *dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2;941 *dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2;
711 }942 }
@@ -717,13 +948,14 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post · 5 unmodified lines
717 int halfChildSize = childSize / 2;948 int halfChildSize = childSize / 2;
718 int destPerSrc = size / childSize;949 int destPerSrc = size / childSize;
719 for (int z = 0; z < halfChildSize; z++) {950 for (int z = 0; z < halfChildSize; z++) {
720 for (uchar* end = src + childSize * BYTES_PER_PIXEL; src != end; src += childStep) {951 for (uchar* end = src + childSize * HeightfieldData::COLOR_BYTES; src != end; src += childStep) {
721 *dest++ = ((int)src[0] + (int)src[BYTES_PER_PIXEL] + (int)src[childStride] + (int)src[redOffset3]) >> 2;952 *dest++ = ((int)src[0] + (int)src[HeightfieldData::COLOR_BYTES] +
953 (int)src[childStride] + (int)src[redOffset3]) >> 2;
722 *dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2;954 *dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2;
723 *dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2;955 *dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2;
724 for (int j = 1; j < destPerSrc; j++) {956 for (int j = 1; j < destPerSrc; j++) {
725 memcpy(dest, dest - BYTES_PER_PIXEL, BYTES_PER_PIXEL);957 memcpy(dest, dest - HeightfieldData::COLOR_BYTES, HeightfieldData::COLOR_BYTES);
726 dest += BYTES_PER_PIXEL;958 dest += HeightfieldData::COLOR_BYTES;
727 }959 }
728 }960 }
729 dest += halfStride;961 dest += halfStride;
libraries/metavoxels/src/AttributeRegistry.h+22−4
@@ -28,6 +28,7 @@ class QScriptEngine; · 27 unmodified lines
28class QScriptValue;28class QScriptValue;
29 29
30class Attribute;30class Attribute;
31class HeightfieldData;
31class MetavoxelData;32class MetavoxelData;
32class MetavoxelLOD;33class MetavoxelLOD;
33class MetavoxelNode;34class MetavoxelNode;
@@ -421,26 +422,37 @@ public: · 387 unmodified lines
421 virtual AttributeValue inherit(const AttributeValue& parentValue) const;422 virtual AttributeValue inherit(const AttributeValue& parentValue) const;
422};423};
423 424
425typedef QExplicitlySharedDataPointer<HeightfieldData> HeightfieldDataPointer;
426
424/// Contains a block of heightfield data.427/// Contains a block of heightfield data.
425class HeightfieldData : public QSharedData {428class HeightfieldData : public QSharedData {
426public:429public:
427 430
431 static const int COLOR_BYTES = 3;
432
428 HeightfieldData(const QByteArray& contents);433 HeightfieldData(const QByteArray& contents);
429 HeightfieldData(Bitstream& in, int bytes, bool color);434 HeightfieldData(Bitstream& in, int bytes, bool color);
430 435 HeightfieldData(Bitstream& in, int bytes, const HeightfieldDataPointer& reference, bool color);
436
431 const QByteArray& getContents() const { return _contents; }437 const QByteArray& getContents() const { return _contents; }
432 438
433 void write(Bitstream& out, bool color);439 void write(Bitstream& out, bool color);
440 void writeDelta(Bitstream& out, const HeightfieldDataPointer& reference, bool color);
434 441
435private:442private:
436 443
444 void read(Bitstream& in, int bytes, bool color);
445 void set(const QImage& image, bool color);
446
437 QByteArray _contents;447 QByteArray _contents;
438 QByteArray _encoded;448 QByteArray _encoded;
439 QMutex _encodedMutex;449 QMutex _encodedMutex;
450
451 HeightfieldDataPointer _deltaData;
452 QByteArray _encodedDelta;
453 QMutex _encodedDeltaMutex;
440};454};
441 455
442typedef QExplicitlySharedDataPointer<HeightfieldData> HeightfieldDataPointer;
443
444/// An attribute that stores heightfield data.456/// An attribute that stores heightfield data.
445class HeightfieldAttribute : public InlineAttribute<HeightfieldDataPointer> {457class HeightfieldAttribute : public InlineAttribute<HeightfieldDataPointer> {
446 Q_OBJECT458 Q_OBJECT
@@ -451,7 +463,10 @@ public: · 4 unmodified lines
451 463
452 virtual void read(Bitstream& in, void*& value, bool isLeaf) const;464 virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
453 virtual void write(Bitstream& out, void* value, bool isLeaf) const;465 virtual void write(Bitstream& out, void* value, bool isLeaf) const;
454 466
467 virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const;
468 virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const;
469
455 virtual bool merge(void*& parent, void* children[], bool postRead = false) const;470 virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
456};471};
457 472
@@ -466,6 +481,9 @@ public: · 8 unmodified lines
466 virtual void read(Bitstream& in, void*& value, bool isLeaf) const;481 virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
467 virtual void write(Bitstream& out, void* value, bool isLeaf) const;482 virtual void write(Bitstream& out, void* value, bool isLeaf) const;
468 483
484 virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const;
485 virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const;
486
469 virtual bool merge(void*& parent, void* children[], bool postRead = false) const;487 virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
470};488};
471 489
libraries/metavoxels/src/MetavoxelMessages.cpp+174−0
@@ -318,3 +318,177 @@ SetDataEdit::SetDataEdit(const glm::vec3& minimum, const MetavoxelData& data, bo · 317 unmodified lines
318void SetDataEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {318void SetDataEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
319 data.set(minimum, this->data, blend);319 data.set(minimum, this->data, blend);
320}320}
321
322PaintHeightfieldHeightEdit::PaintHeightfieldHeightEdit(const glm::vec3& position, float radius, float height) :
323 position(position),
324 radius(radius),
325 height(height) {
326}
327
328class PaintHeightfieldHeightEditVisitor : public MetavoxelVisitor {
329public:
330
331 PaintHeightfieldHeightEditVisitor(const PaintHeightfieldHeightEdit& edit);
332
333 virtual int visit(MetavoxelInfo& info);
334
335private:
336
337 PaintHeightfieldHeightEdit _edit;
338 Box _bounds;
339};
340
341PaintHeightfieldHeightEditVisitor::PaintHeightfieldHeightEditVisitor(const PaintHeightfieldHeightEdit& edit) :
342 MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute(),
343 QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute()),
344 _edit(edit) {
345
346 glm::vec3 extents(_edit.radius, _edit.radius, _edit.radius);
347 _bounds = Box(_edit.position - extents, _edit.position + extents);
348}
349
350int PaintHeightfieldHeightEditVisitor::visit(MetavoxelInfo& info) {
351 if (!info.getBounds().intersects(_bounds)) {
352 return STOP_RECURSION;
353 }
354 if (!info.isLeaf) {
355 return DEFAULT_ORDER;
356 }
357 HeightfieldDataPointer pointer = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>();
358 if (!pointer) {
359 return STOP_RECURSION;
360 }
361 QByteArray contents(pointer->getContents());
362 int size = glm::sqrt((float)contents.size());
363 int highest = size - 1;
364 float heightScale = size / info.size;
365
366 glm::vec3 center = (_edit.position - info.minimum) * heightScale;
367 float scaledRadius = _edit.radius * heightScale;
368 glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius);
369
370 glm::vec3 start = glm::floor(center - extents);
371 glm::vec3 end = glm::ceil(center + extents);
372
373 // raise/lower all points within the radius
374 float z = qMax(start.z, 0.0f);
375 float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest);
376 uchar* lineDest = (uchar*)contents.data() + (int)z * size + (int)startX;
377 float squaredRadius = scaledRadius * scaledRadius;
378 float squaredRadiusReciprocal = 1.0f / squaredRadius;
379 const int EIGHT_BIT_MAXIMUM = 255;
380 float scaledHeight = _edit.height * EIGHT_BIT_MAXIMUM / info.size;
381 bool changed = false;
382 for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
383 uchar* dest = lineDest;
384 for (float x = startX; x <= endX; x += 1.0f, dest++) {
385 float dx = x - center.x, dz = z - center.z;
386 float distanceSquared = dx * dx + dz * dz;
387 if (distanceSquared <= squaredRadius) {
388 // height falls off towards edges
389 int value = *dest + scaledHeight * (squaredRadius - distanceSquared) * squaredRadiusReciprocal;
390 if (value != *dest) {
391 *dest = qMin(qMax(value, 0), EIGHT_BIT_MAXIMUM);
392 changed = true;
393 }
394 }
395 }
396 lineDest += size;
397 }
398 if (changed) {
399 HeightfieldDataPointer newPointer(new HeightfieldData(contents));
400 info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldDataPointer>(newPointer));
401 }
402 return STOP_RECURSION;
403}
404
405void PaintHeightfieldHeightEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
406 PaintHeightfieldHeightEditVisitor visitor(*this);
407 data.guide(visitor);
408}
409
410PaintHeightfieldColorEdit::PaintHeightfieldColorEdit(const glm::vec3& position, float radius, const QColor& color) :
411 position(position),
412 radius(radius),
413 color(color) {
414}
415
416class PaintHeightfieldColorEditVisitor : public MetavoxelVisitor {
417public:
418
419 PaintHeightfieldColorEditVisitor(const PaintHeightfieldColorEdit& edit);
420
421 virtual int visit(MetavoxelInfo& info);
422
423private:
424
425 PaintHeightfieldColorEdit _edit;
426 Box _bounds;
427};
428
429PaintHeightfieldColorEditVisitor::PaintHeightfieldColorEditVisitor(const PaintHeightfieldColorEdit& edit) :
430 MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute(),
431 QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute()),
432 _edit(edit) {
433
434 glm::vec3 extents(_edit.radius, _edit.radius, _edit.radius);
435 _bounds = Box(_edit.position - extents, _edit.position + extents);
436}
437
438int PaintHeightfieldColorEditVisitor::visit(MetavoxelInfo& info) {
439 if (!info.getBounds().intersects(_bounds)) {
440 return STOP_RECURSION;
441 }
442 if (!info.isLeaf) {
443 return DEFAULT_ORDER;
444 }
445 HeightfieldDataPointer pointer = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>();
446 if (!pointer) {
447 return STOP_RECURSION;
448 }
449 QByteArray contents(pointer->getContents());
450 const int BYTES_PER_PIXEL = 3;
451 int size = glm::sqrt((float)contents.size() / BYTES_PER_PIXEL);
452 int highest = size - 1;
453 float heightScale = size / info.size;
454
455 glm::vec3 center = (_edit.position - info.minimum) * heightScale;
456 float scaledRadius = _edit.radius * heightScale;
457 glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius);
458
459 glm::vec3 start = glm::floor(center - extents);
460 glm::vec3 end = glm::ceil(center + extents);
461
462 // paint all points within the radius
463 float z = qMax(start.z, 0.0f);
464 float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest);
465 int stride = size * BYTES_PER_PIXEL;
466 char* lineDest = contents.data() + (int)z * stride + (int)startX * BYTES_PER_PIXEL;
467 float squaredRadius = scaledRadius * scaledRadius;
468 char red = _edit.color.red(), green = _edit.color.green(), blue = _edit.color.blue();
469 bool changed = false;
470 for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
471 char* dest = lineDest;
472 for (float x = startX; x <= endX; x += 1.0f, dest += BYTES_PER_PIXEL) {
473 float dx = x - center.x, dz = z - center.z;
474 if (dx * dx + dz * dz <= squaredRadius) {
475 dest[0] = red;
476 dest[1] = green;
477 dest[2] = blue;
478 changed = true;
479 }
480 }
481 lineDest += stride;
482 }
483 if (changed) {
484 HeightfieldDataPointer newPointer(new HeightfieldData(contents));
485 info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldDataPointer>(newPointer));
486 }
487 return STOP_RECURSION;
488}
489
490void PaintHeightfieldColorEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
491 PaintHeightfieldColorEditVisitor visitor(*this);
492 data.guide(visitor);
493}
494
libraries/metavoxels/src/MetavoxelMessages.h+34−0
@@ -207,4 +207,38 @@ public: · 206 unmodified lines
207 207
208DECLARE_STREAMABLE_METATYPE(SetDataEdit)208DECLARE_STREAMABLE_METATYPE(SetDataEdit)
209 209
210/// An edit that sets a region of a heightfield height.
211class PaintHeightfieldHeightEdit : public MetavoxelEdit {
212 STREAMABLE
213
214public:
215
216 STREAM glm::vec3 position;
217 STREAM float radius;
218 STREAM float height;
219
220 PaintHeightfieldHeightEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f, float height = 0.0f);
221
222 virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
223};
224
225DECLARE_STREAMABLE_METATYPE(PaintHeightfieldHeightEdit)
226
227/// An edit that sets a region of a heightfield color.
228class PaintHeightfieldColorEdit : public MetavoxelEdit {
229 STREAMABLE
230
231public:
232
233 STREAM glm::vec3 position;
234 STREAM float radius;
235 STREAM QColor color;
236
237 PaintHeightfieldColorEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f, const QColor& color = QColor());
238
239 virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
240};
241
242DECLARE_STREAMABLE_METATYPE(PaintHeightfieldColorEdit)
243
210#endif // hifi_MetavoxelMessages_h244#endif // hifi_MetavoxelMessages_h
libraries/metavoxels/src/MetavoxelUtil.cpp+15−0
@@ -24,6 +24,8 @@ · 23 unmodified lines
24#include <QVBoxLayout>24#include <QVBoxLayout>
25#include <QtDebug>25#include <QtDebug>
26 26
27#include <GLMHelpers.h>
28
27#include "MetavoxelUtil.h"29#include "MetavoxelUtil.h"
28#include "ScriptCache.h"30#include "ScriptCache.h"
29#include "StreamUtils.h"31#include "StreamUtils.h"
@@ -162,6 +164,11 @@ Box::Box(const glm::vec3& minimum, const glm::vec3& maximum) : · 132 unmodified lines
162 minimum(minimum), maximum(maximum) {164 minimum(minimum), maximum(maximum) {
163}165}
164 166
167void Box::add(const Box& other) {
168 minimum = glm::min(minimum, other.minimum);
169 maximum = glm::max(maximum, other.maximum);
170}
171
165bool Box::contains(const glm::vec3& point) const {172bool Box::contains(const glm::vec3& point) const {
166 return point.x >= minimum.x && point.x <= maximum.x &&173 return point.x >= minimum.x && point.x <= maximum.x &&
167 point.y >= minimum.y && point.y <= maximum.y &&174 point.y >= minimum.y && point.y <= maximum.y &&
@@ -180,6 +187,14 @@ bool Box::intersects(const Box& other) const { · 12 unmodified lines
180 other.maximum.z >= minimum.z && other.minimum.z <= maximum.z;187 other.maximum.z >= minimum.z && other.minimum.z <= maximum.z;
181}188}
182 189
190Box Box::getIntersection(const Box& other) const {
191 return Box(glm::max(minimum, other.minimum), glm::min(maximum, other.maximum));
192}
193
194bool Box::isEmpty() const {
195 return minimum.x >= maximum.x || minimum.y >= maximum.y || minimum.z >= maximum.z;
196}
197
183const int X_MAXIMUM_FLAG = 1;198const int X_MAXIMUM_FLAG = 1;
184const int Y_MAXIMUM_FLAG = 2;199const int Y_MAXIMUM_FLAG = 2;
185const int Z_MAXIMUM_FLAG = 4;200const int Z_MAXIMUM_FLAG = 4;
libraries/metavoxels/src/MetavoxelUtil.h+8−0
@@ -44,12 +44,18 @@ public: · 43 unmodified lines
44 44
45 explicit Box(const glm::vec3& minimum = glm::vec3(), const glm::vec3& maximum = glm::vec3());45 explicit Box(const glm::vec3& minimum = glm::vec3(), const glm::vec3& maximum = glm::vec3());
46 46
47 void add(const Box& other);
48
47 bool contains(const glm::vec3& point) const;49 bool contains(const glm::vec3& point) const;
48 50
49 bool contains(const Box& other) const;51 bool contains(const Box& other) const;
50 52
51 bool intersects(const Box& other) const;53 bool intersects(const Box& other) const;
52 54
55 Box getIntersection(const Box& other) const;
56
57 bool isEmpty() const;
58
53 float getLongestSide() const { return qMax(qMax(maximum.x - minimum.x, maximum.y - minimum.y), maximum.z - minimum.z); }59 float getLongestSide() const { return qMax(qMax(maximum.x - minimum.x, maximum.y - minimum.y), maximum.z - minimum.z); }
54 60
55 glm::vec3 getVertex(int index) const;61 glm::vec3 getVertex(int index) const;
@@ -138,6 +144,8 @@ public: · 82 unmodified lines
138 144
139 QColorEditor(QWidget* parent);145 QColorEditor(QWidget* parent);
140 146
147 const QColor& getColor() const { return _color; }
148
141signals:149signals:
142 150
143 void colorChanged(const QColor& color);151 void colorChanged(const QColor& color);
libraries/networking/CMakeLists.txt+9−16
@@ -1,21 +1,14 @@
1set(ROOT_DIR ../..)
2set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
3
4set(TARGET_NAME networking)1set(TARGET_NAME networking)
5project(${TARGET_NAME})
6
7find_package(Qt5 COMPONENTS Network)
8 2
9include(${MACRO_DIR}/SetupHifiLibrary.cmake)3# use setup_hifi_library macro to setup our project and link appropriate Qt modules
10setup_hifi_library(${TARGET_NAME})4setup_hifi_library(Network)
11 5
12# include GLM6link_hifi_libraries(shared)
13include(${MACRO_DIR}/IncludeGLM.cmake)
14include_glm(${TARGET_NAME} "${ROOT_DIR}")
15 7
16target_link_libraries(${TARGET_NAME} Qt5::Network)
17
18# add a definition for ssize_t so that windows doesn't bail
19if (WIN32)8if (WIN32)
20 add_definitions(-Dssize_t=long)9 # we need ws2_32.lib on windows, but it's static so we don't bubble it up
21endif ()10 target_link_libraries(${TARGET_NAME} ws2_32.lib)
11endif ()
12
13# call macro to link our dependencies and bubble them up via a property on our target
14link_shared_dependencies()
libraries/networking/src/DomainHandler.cpp+4−1
@@ -36,6 +36,7 @@ DomainHandler::DomainHandler(QObject* parent) : · 35 unmodified lines
36void DomainHandler::clearConnectionInfo() {36void DomainHandler::clearConnectionInfo() {
37 _uuid = QUuid();37 _uuid = QUuid();
38 _isConnected = false;38 _isConnected = false;
39 emit disconnectedFromDomain();
39 40
40 if (_handshakeTimer) {41 if (_handshakeTimer) {
41 _handshakeTimer->stop();42 _handshakeTimer->stop();
@@ -129,6 +130,8 @@ void DomainHandler::setIsConnected(bool isConnected) { · 87 unmodified lines
129 130
130 // we've connected to new domain - time to ask it for global settings131 // we've connected to new domain - time to ask it for global settings
131 requestDomainSettings();132 requestDomainSettings();
133 } else {
134 emit disconnectedFromDomain();
132 }135 }
133 }136 }
134}137}
@@ -196,4 +199,4 @@ void DomainHandler::parseDTLSRequirementPacket(const QByteArray& dtlsRequirement · 61 unmodified lines
196 _sockAddr.setPort(dtlsPort);199 _sockAddr.setPort(dtlsPort);
197 200
198// initializeDTLSSession();201// initializeDTLSSession();
199}202}
libraries/networking/src/DomainHandler.h+1−0
@@ -70,6 +70,7 @@ private slots: · 69 unmodified lines
70signals:70signals:
71 void hostnameChanged(const QString& hostname);71 void hostnameChanged(const QString& hostname);
72 void connectedToDomain(const QString& hostname);72 void connectedToDomain(const QString& hostname);
73 void disconnectedFromDomain();
73 74
74 void settingsReceived(const QJsonObject& domainSettingsObject);75 void settingsReceived(const QJsonObject& domainSettingsObject);
75 void settingsReceiveFail();76 void settingsReceiveFail();
libraries/networking/src/LimitedNodeList.cpp+25−12
@@ -82,8 +82,8 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short · 81 unmodified lines
82 qDebug() << "NodeList DTLS socket is listening on" << _dtlsSocket->localPort();82 qDebug() << "NodeList DTLS socket is listening on" << _dtlsSocket->localPort();
83 }83 }
84 84
85 const int LARGER_SNDBUF_SIZE = 1048576;85 const int LARGER_BUFFER_SIZE = 1048576;
86 changeSendSocketBufferSize(LARGER_SNDBUF_SIZE);86 changeSocketBufferSizes(LARGER_BUFFER_SIZE);
87 87
88 _packetStatTimer.start();88 _packetStatTimer.start();
89}89}
@@ -129,7 +129,7 @@ QUdpSocket& LimitedNodeList::getDTLSSocket() { · 39 unmodified lines
129 return *_dtlsSocket;129 return *_dtlsSocket;
130}130}
131 131
132void LimitedNodeList::changeSendSocketBufferSize(int numSendBytes) {132void LimitedNodeList::changeSocketBufferSizes(int numBytes) {
133 // change the socket send buffer size to be 1MB133 // change the socket send buffer size to be 1MB
134 int oldBufferSize = 0;134 int oldBufferSize = 0;
135 135
@@ -139,15 +139,28 @@ void LimitedNodeList::changeSendSocketBufferSize(int numSendBytes) { · 3 unmodified lines
139 unsigned int sizeOfInt = sizeof(oldBufferSize);139 unsigned int sizeOfInt = sizeof(oldBufferSize);
140#endif140#endif
141 141
142 getsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, SO_SNDBUF, reinterpret_cast<char*>(&oldBufferSize), &sizeOfInt);142 for (int i = 0; i < 2; i++) {
143 143 int bufferOpt = (i == 0) ? SO_SNDBUF : SO_RCVBUF;
144 setsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, SO_SNDBUF, reinterpret_cast<const char*>(&numSendBytes),144
145 sizeof(numSendBytes));145 getsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, bufferOpt, reinterpret_cast<char*>(&oldBufferSize), &sizeOfInt);
146 146
147 int newBufferSize = 0;147 setsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, bufferOpt, reinterpret_cast<const char*>(&numBytes),
148 getsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, SO_SNDBUF, reinterpret_cast<char*>(&newBufferSize), &sizeOfInt);148 sizeof(numBytes));
149 149
150 qDebug() << "Changed socket send buffer size from" << oldBufferSize << "to" << newBufferSize << "bytes";150 QString bufferTypeString = (i == 0) ? "send" : "receive";
151
152 if (oldBufferSize < numBytes) {
153 int newBufferSize = 0;
154 getsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, bufferOpt, reinterpret_cast<char*>(&newBufferSize), &sizeOfInt);
155
156 qDebug() << "Changed socket" << bufferTypeString << "buffer size from" << oldBufferSize << "to"
157 << newBufferSize << "bytes";
158 } else {
159 // don't make the buffer smaller
160 qDebug() << "Did not change socket" << bufferTypeString << "buffer size from" << oldBufferSize
161 << "since it is larger than desired size of" << numBytes;
162 }
163 }
151}164}
152 165
153bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) {166bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) {
libraries/networking/src/LimitedNodeList.h+1−1
@@ -123,7 +123,7 @@ protected: · 122 unmodified lines
123 NodeHash::iterator killNodeAtHashIterator(NodeHash::iterator& nodeItemToKill);123 NodeHash::iterator killNodeAtHashIterator(NodeHash::iterator& nodeItemToKill);
124 124
125 125
126 void changeSendSocketBufferSize(int numSendBytes);126 void changeSocketBufferSizes(int numBytes);
127 127
128 QUuid _sessionUUID;128 QUuid _sessionUUID;
129 NodeHash _nodeHash;129 NodeHash _nodeHash;
libraries/networking/src/PacketHeaders.cpp+2−0
@@ -80,6 +80,8 @@ PacketVersion versionForPacketType(PacketType type) { · 79 unmodified lines
80 return 2;80 return 2;
81 case PacketTypeAudioStreamStats:81 case PacketTypeAudioStreamStats:
82 return 1;82 return 1;
83 case PacketTypeMetavoxelData:
84 return 1;
83 default:85 default:
84 return 0;86 return 0;
85 }87 }
libraries/networking/src/PacketSender.h+0−4
@@ -39,10 +39,6 @@ public: · 38 unmodified lines
39 ~PacketSender();39 ~PacketSender();
40 40
41 /// Add packet to outbound queue.41 /// Add packet to outbound queue.
42 /// \param HifiSockAddr& address the destination address
43 /// \param packetData pointer to data
44 /// \param ssize_t packetLength size of data
45 /// \thread any thread, typically the application thread
46 void queuePacketForSending(const SharedNodePointer& destinationNode, const QByteArray& packet);42 void queuePacketForSending(const SharedNodePointer& destinationNode, const QByteArray& packet);
47 43
48 void setPacketsPerSecond(int packetsPerSecond);44 void setPacketsPerSecond(int packetsPerSecond);
libraries/networking/src/ReceivedPacketProcessor.h+0−4
@@ -24,10 +24,6 @@ public: · 23 unmodified lines
24 ReceivedPacketProcessor() { }24 ReceivedPacketProcessor() { }
25 25
26 /// Add packet from network receive thread to the processing queue.26 /// Add packet from network receive thread to the processing queue.
27 /// \param sockaddr& senderAddress the address of the sender
28 /// \param packetData pointer to received data
29 /// \param ssize_t packetLength size of received data
30 /// \thread network receive thread
31 void queueReceivedPacket(const SharedNodePointer& sendingNode, const QByteArray& packet);27 void queueReceivedPacket(const SharedNodePointer& sendingNode, const QByteArray& packet);
32 28
33 /// Are there received packets waiting to be processed29 /// Are there received packets waiting to be processed
libraries/networking/src/SequenceNumberStats.cpp+15−10
@@ -253,14 +253,19 @@ PacketStreamStats SequenceNumberStats::getStatsForHistoryWindow() const { · 252 unmodified lines
253 }253 }
254 254
255 // calculate difference between newest stats and oldest stats to get window stats255 // calculate difference between newest stats and oldest stats to get window stats
256 PacketStreamStats windowStats;256 return *newestStats - *oldestStats;
257 windowStats._received = newestStats->_received - oldestStats->_received;
258 windowStats._unreasonable = newestStats->_unreasonable - oldestStats->_unreasonable;
259 windowStats._early = newestStats->_early - oldestStats->_early;
260 windowStats._late = newestStats->_late - oldestStats->_late;
261 windowStats._lost = newestStats->_lost - oldestStats->_lost;
262 windowStats._recovered = newestStats->_recovered - oldestStats->_recovered;
263 windowStats._expectedReceived = newestStats->_expectedReceived - oldestStats->_expectedReceived;
264
265 return windowStats;
266}257}
258
259PacketStreamStats SequenceNumberStats::getStatsForLastHistoryInterval() const {
260
261 const PacketStreamStats* newestStats = _statsHistory.getNewestEntry();
262 const PacketStreamStats* secondNewestStats = _statsHistory.get(1);
263
264 // this catches cases where history is length 1 or 0 (both are NULL in case of 0)
265 if (newestStats == NULL || secondNewestStats == NULL) {
266 return PacketStreamStats();
267 }
268
269 return *newestStats - *secondNewestStats;
270}
271
libraries/networking/src/SequenceNumberStats.h+13−0
@@ -31,6 +31,18 @@ public: · 30 unmodified lines
31 _expectedReceived(0)31 _expectedReceived(0)
32 {}32 {}
33 33
34 PacketStreamStats operator-(const PacketStreamStats& rhs) const {
35 PacketStreamStats diff;
36 diff._received = _received - rhs._received;
37 diff._unreasonable = _unreasonable - rhs._unreasonable;
38 diff._early = _early - rhs._early;
39 diff._late = _late - rhs._late;
40 diff._lost = _lost - rhs._lost;
41 diff._recovered = _recovered - rhs._recovered;
42 diff._expectedReceived = _expectedReceived - rhs._expectedReceived;
43 return diff;
44 }
45
34 float getLostRate() const { return (float)_lost / _expectedReceived; }46 float getLostRate() const { return (float)_lost / _expectedReceived; }
35 47
36 quint32 _received;48 quint32 _received;
@@ -76,6 +88,7 @@ public: · 39 unmodified lines
76 88
77 const PacketStreamStats& getStats() const { return _stats; }89 const PacketStreamStats& getStats() const { return _stats; }
78 PacketStreamStats getStatsForHistoryWindow() const;90 PacketStreamStats getStatsForHistoryWindow() const;
91 PacketStreamStats getStatsForLastHistoryInterval() const;
79 const QSet<quint16>& getMissingSet() const { return _missingSet; }92 const QSet<quint16>& getMissingSet() const { return _missingSet; }
80 93
81private:94private:
libraries/networking/src/ThreadedAssignment.cpp+20−3
@@ -11,6 +11,7 @@ · 10 unmodified lines
11 11
12#include <QtCore/QCoreApplication>12#include <QtCore/QCoreApplication>
13#include <QtCore/QJsonObject>13#include <QtCore/QJsonObject>
14#include <QtCore/QThread>
14#include <QtCore/QTimer>15#include <QtCore/QTimer>
15 16
16#include "Logging.h"17#include "Logging.h"
@@ -18,7 +19,8 @@ · 1 unmodified line
18 19
19ThreadedAssignment::ThreadedAssignment(const QByteArray& packet) :20ThreadedAssignment::ThreadedAssignment(const QByteArray& packet) :
20 Assignment(packet),21 Assignment(packet),
21 _isFinished(false)22 _isFinished(false),
23 _datagramProcessingThread(NULL)
22{24{
23 25
24}26}
@@ -28,10 +30,25 @@ void ThreadedAssignment::setFinished(bool isFinished) { · 3 unmodified lines
28 30
29 if (_isFinished) {31 if (_isFinished) {
30 aboutToFinish();32 aboutToFinish();
31 emit finished();33
34 NodeList* nodeList = NodeList::getInstance();
35
36 // if we have a datagram processing thread, quit it and wait on it to make sure that
37 // the node socket is back on the same thread as the NodeList
38
39 if (_datagramProcessingThread) {
40 // tell the datagram processing thread to quit and wait until it is done, then return the node socket to the NodeList
41 _datagramProcessingThread->quit();
42 _datagramProcessingThread->wait();
43
44 // set node socket parent back to NodeList
45 nodeList->getNodeSocket().setParent(nodeList);
46 }
32 47
33 // move the NodeList back to the QCoreApplication instance's thread48 // move the NodeList back to the QCoreApplication instance's thread
34 NodeList::getInstance()->moveToThread(QCoreApplication::instance()->thread());49 nodeList->moveToThread(QCoreApplication::instance()->thread());
50
51 emit finished();
35 }52 }
36}53}
37 54
libraries/networking/src/ThreadedAssignment.h+7−3
@@ -20,6 +20,7 @@ class ThreadedAssignment : public Assignment { · 19 unmodified lines
20 Q_OBJECT20 Q_OBJECT
21public:21public:
22 ThreadedAssignment(const QByteArray& packet);22 ThreadedAssignment(const QByteArray& packet);
23
23 void setFinished(bool isFinished);24 void setFinished(bool isFinished);
24 virtual void aboutToFinish() { };25 virtual void aboutToFinish() { };
25 void addPacketStatsAndSendStatsPacket(QJsonObject& statsObject);26 void addPacketStatsAndSendStatsPacket(QJsonObject& statsObject);
@@ -29,15 +30,18 @@ public slots: · 3 unmodified lines
29 virtual void run() = 0;30 virtual void run() = 0;
30 virtual void readPendingDatagrams() = 0;31 virtual void readPendingDatagrams() = 0;
31 virtual void sendStatsPacket();32 virtual void sendStatsPacket();
32 33signals:
34 void finished();
35
33protected:36protected:
34 bool readAvailableDatagram(QByteArray& destinationByteArray, HifiSockAddr& senderSockAddr);37 bool readAvailableDatagram(QByteArray& destinationByteArray, HifiSockAddr& senderSockAddr);
35 void commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats = true);38 void commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats = true);
36 bool _isFinished;39 bool _isFinished;
40 QThread* _datagramProcessingThread;
41
37private slots:42private slots:
38 void checkInWithDomainServerOrExit();43 void checkInWithDomainServerOrExit();
39signals:44
40 void finished();
41};45};
42 46
43typedef QSharedPointer<ThreadedAssignment> SharedAssignmentPointer;47typedef QSharedPointer<ThreadedAssignment> SharedAssignmentPointer;
libraries/octree/CMakeLists.txt+11−22
@@ -1,30 +1,19 @@
1set(ROOT_DIR ../..)
2set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
3
4# setup for find modules
5set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
6
7set(TARGET_NAME octree)1set(TARGET_NAME octree)
8 2
9find_package(Qt5Widgets REQUIRED)3# use setup_hifi_library macro to setup our project and link appropriate Qt modules
4setup_hifi_library()
10 5
11include(${MACRO_DIR}/SetupHifiLibrary.cmake)6include_glm()
12setup_hifi_library(${TARGET_NAME})
13 7
14include(${MACRO_DIR}/IncludeGLM.cmake)8link_hifi_libraries(shared networking)
15include_glm(${TARGET_NAME} "${ROOT_DIR}")
16 9
17include(${MACRO_DIR}/LinkHifiLibrary.cmake)10# find ZLIB
18link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")11find_package(ZLIB REQUIRED)
19link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
20
21# link ZLIB
22find_package(ZLIB)
23 12
24include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}")13include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}")
25target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets)
26 14
27# add a definition for ssize_t so that windows doesn't bail15# append ZLIB and OpenSSL to our list of libraries to link
28if (WIN32)16list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${ZLIB_LIBRARIES}")
29 add_definitions(-Dssize_t=long)17
30endif ()18# call macro to link our dependencies and bubble them up via a property on our target
19link_shared_dependencies()
libraries/octree/src/EditPacketBuffer.cpp+1−1
@@ -20,7 +20,7 @@ EditPacketBuffer::EditPacketBuffer() : · 19 unmodified lines
20 20
21}21}
22 22
23EditPacketBuffer::EditPacketBuffer(PacketType type, unsigned char* buffer, ssize_t length, qint64 satoshiCost, QUuid nodeUUID) :23EditPacketBuffer::EditPacketBuffer(PacketType type, unsigned char* buffer, size_t length, qint64 satoshiCost, QUuid nodeUUID) :
24 _nodeUUID(nodeUUID),24 _nodeUUID(nodeUUID),
25 _currentType(type),25 _currentType(type),
26 _currentSize(length),26 _currentSize(length),
libraries/octree/src/EditPacketBuffer.h+2−2
@@ -21,13 +21,13 @@ · 20 unmodified lines
21class EditPacketBuffer {21class EditPacketBuffer {
22public:22public:
23 EditPacketBuffer();23 EditPacketBuffer();
24 EditPacketBuffer(PacketType type, unsigned char* codeColorBuffer, ssize_t length,24 EditPacketBuffer(PacketType type, unsigned char* codeColorBuffer, size_t length,
25 qint64 satoshiCost = 0, const QUuid nodeUUID = QUuid());25 qint64 satoshiCost = 0, const QUuid nodeUUID = QUuid());
26 26
27 QUuid _nodeUUID;27 QUuid _nodeUUID;
28 PacketType _currentType;28 PacketType _currentType;
29 unsigned char _currentBuffer[MAX_PACKET_SIZE];29 unsigned char _currentBuffer[MAX_PACKET_SIZE];
30 ssize_t _currentSize;30 size_t _currentSize;
31 qint64 _satoshiCost;31 qint64 _satoshiCost;
32};32};
33 33
libraries/octree/src/JurisdictionListener.cpp+1−1
@@ -35,7 +35,7 @@ void JurisdictionListener::nodeKilled(SharedNodePointer node) { · 34 unmodified lines
35bool JurisdictionListener::queueJurisdictionRequest() {35bool JurisdictionListener::queueJurisdictionRequest() {
36 static unsigned char buffer[MAX_PACKET_SIZE];36 static unsigned char buffer[MAX_PACKET_SIZE];
37 unsigned char* bufferOut = &buffer[0];37 unsigned char* bufferOut = &buffer[0];
38 ssize_t sizeOut = populatePacketHeader(reinterpret_cast<char*>(bufferOut), PacketTypeJurisdictionRequest);38 int sizeOut = populatePacketHeader(reinterpret_cast<char*>(bufferOut), PacketTypeJurisdictionRequest);
39 int nodeCount = 0;39 int nodeCount = 0;
40 40
41 NodeList* nodeList = NodeList::getInstance();41 NodeList* nodeList = NodeList::getInstance();
libraries/octree/src/JurisdictionListener.h+0−4
@@ -47,10 +47,6 @@ public slots: · 46 unmodified lines
47protected:47protected:
48 /// Callback for processing of received packets. Will process any queued PacketType_JURISDICTION and update the48 /// Callback for processing of received packets. Will process any queued PacketType_JURISDICTION and update the
49 /// jurisdiction map member variable49 /// jurisdiction map member variable
50 /// \param sockaddr& senderAddress the address of the sender
51 /// \param packetData pointer to received data
52 /// \param ssize_t packetLength size of received data
53 /// \thread "this" individual processing thread
54 virtual void processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet);50 virtual void processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet);
55 51
56private:52private:
libraries/octree/src/JurisdictionSender.cpp+1−1
@@ -47,7 +47,7 @@ bool JurisdictionSender::process() { · 46 unmodified lines
47 // add our packet to our own queue, then let the PacketSender class do the rest of the work.47 // add our packet to our own queue, then let the PacketSender class do the rest of the work.
48 static unsigned char buffer[MAX_PACKET_SIZE];48 static unsigned char buffer[MAX_PACKET_SIZE];
49 unsigned char* bufferOut = &buffer[0];49 unsigned char* bufferOut = &buffer[0];
50 ssize_t sizeOut = 0;50 int sizeOut = 0;
51 51
52 if (_jurisdictionMap) {52 if (_jurisdictionMap) {
53 sizeOut = _jurisdictionMap->packIntoMessage(bufferOut, MAX_PACKET_SIZE);53 sizeOut = _jurisdictionMap->packIntoMessage(bufferOut, MAX_PACKET_SIZE);
libraries/octree/src/OctreeEditPacketSender.cpp+3−3
@@ -83,7 +83,7 @@ bool OctreeEditPacketSender::serversExist() const { · 82 unmodified lines
83// This method is called when the edit packet layer has determined that it has a fully formed packet destined for83// This method is called when the edit packet layer has determined that it has a fully formed packet destined for
84// a known nodeID.84// a known nodeID.
85void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned char* buffer,85void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned char* buffer,
86 ssize_t length, qint64 satoshiCost) {86 size_t length, qint64 satoshiCost) {
87 87
88 bool wantDebug = false;88 bool wantDebug = false;
89 if (wantDebug) {89 if (wantDebug) {
@@ -171,7 +171,7 @@ void OctreeEditPacketSender::processPreServerExistsPackets() { · 81 unmodified lines
171}171}
172 172
173void OctreeEditPacketSender::queuePendingPacketToNodes(PacketType type, unsigned char* buffer,173void OctreeEditPacketSender::queuePendingPacketToNodes(PacketType type, unsigned char* buffer,
174 ssize_t length, qint64 satoshiCost) {174 size_t length, qint64 satoshiCost) {
175 // If we're asked to save messages while waiting for voxel servers to arrive, then do so...175 // If we're asked to save messages while waiting for voxel servers to arrive, then do so...
176 176
177 if (_maxPendingMessages > 0) {177 if (_maxPendingMessages > 0) {
@@ -189,7 +189,7 @@ void OctreeEditPacketSender::queuePendingPacketToNodes(PacketType type, unsigned · 11 unmodified lines
189 }189 }
190}190}
191 191
192void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t length, qint64 satoshiCost) {192void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, size_t length, qint64 satoshiCost) {
193 if (!_shouldSend) {193 if (!_shouldSend) {
194 return; // bail early194 return; // bail early
195 }195 }
libraries/octree/src/OctreeEditPacketSender.h+5−5
@@ -30,7 +30,7 @@ public: · 29 unmodified lines
30 /// Queues a single edit message. Will potentially send a pending multi-command packet. Determines which server30 /// Queues a single edit message. Will potentially send a pending multi-command packet. Determines which server
31 /// node or nodes the packet should be sent to. Can be called even before servers are known, in which case up to 31 /// node or nodes the packet should be sent to. Can be called even before servers are known, in which case up to
32 /// MaxPendingMessages will be buffered and processed when servers are known.32 /// MaxPendingMessages will be buffered and processed when servers are known.
33 void queueOctreeEditMessage(PacketType type, unsigned char* buffer, ssize_t length, qint64 satoshiCost = 0);33 void queueOctreeEditMessage(PacketType type, unsigned char* buffer, size_t length, qint64 satoshiCost = 0);
34 34
35 /// Releases all queued messages even if those messages haven't filled an MTU packet. This will move the packed message 35 /// Releases all queued messages even if those messages haven't filled an MTU packet. This will move the packed message
36 /// packets onto the send queue. If running in threaded mode, the caller does not need to do any further processing to36 /// packets onto the send queue. If running in threaded mode, the caller does not need to do any further processing to
@@ -82,7 +82,7 @@ public: · 45 unmodified lines
82 // you must override these...82 // you must override these...
83 virtual char getMyNodeType() const = 0;83 virtual char getMyNodeType() const = 0;
84 virtual void adjustEditPacketForClockSkew(PacketType type, 84 virtual void adjustEditPacketForClockSkew(PacketType type,
85 unsigned char* editPacketBuffer, ssize_t length, int clockSkew) { };85 unsigned char* editPacketBuffer, size_t length, int clockSkew) { };
86 86
87 bool hasDestinationWalletUUID() const { return !_destinationWalletUUID.isNull(); }87 bool hasDestinationWalletUUID() const { return !_destinationWalletUUID.isNull(); }
88 void setDestinationWalletUUID(const QUuid& destinationWalletUUID) { _destinationWalletUUID = destinationWalletUUID; }88 void setDestinationWalletUUID(const QUuid& destinationWalletUUID) { _destinationWalletUUID = destinationWalletUUID; }
@@ -98,9 +98,9 @@ signals: · 9 unmodified lines
98 98
99protected:99protected:
100 bool _shouldSend;100 bool _shouldSend;
101 void queuePacketToNode(const QUuid& nodeID, unsigned char* buffer, ssize_t length, qint64 satoshiCost = 0);101 void queuePacketToNode(const QUuid& nodeID, unsigned char* buffer, size_t length, qint64 satoshiCost = 0);
102 void queuePendingPacketToNodes(PacketType type, unsigned char* buffer, ssize_t length, qint64 satoshiCost = 0);102 void queuePendingPacketToNodes(PacketType type, unsigned char* buffer, size_t length, qint64 satoshiCost = 0);
103 void queuePacketToNodes(unsigned char* buffer, ssize_t length, qint64 satoshiCost = 0);103 void queuePacketToNodes(unsigned char* buffer, size_t length, qint64 satoshiCost = 0);
104 void initializePacket(EditPacketBuffer& packetBuffer, PacketType type);104 void initializePacket(EditPacketBuffer& packetBuffer, PacketType type);
105 void releaseQueuedPacket(EditPacketBuffer& packetBuffer); // releases specific queued packet105 void releaseQueuedPacket(EditPacketBuffer& packetBuffer); // releases specific queued packet
106 106
libraries/octree/src/OctreePacketData.cpp+2−0
@@ -9,7 +9,9 @@ · 8 unmodified lines
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//10//
11 11
12#include <GLMHelpers.h>
12#include <PerfStat.h>13#include <PerfStat.h>
14
13#include "OctreePacketData.h"15#include "OctreePacketData.h"
14 16
15bool OctreePacketData::_debug = false;17bool OctreePacketData::_debug = false;
libraries/octree/src/OctreeQuery.cpp+3−2
@@ -9,8 +9,9 @@ · 8 unmodified lines
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//10//
11 11
12#include <PacketHeaders.h>12//#include <PacketHeaders.h>
13#include <SharedUtil.h>13//#include <SharedUtil.h>
14#include <GLMHelpers.h>
14 15
15#include "OctreeConstants.h"16#include "OctreeConstants.h"
16#include "OctreeQuery.h"17#include "OctreeQuery.h"
libraries/particles/CMakeLists.txt+7−28
@@ -1,33 +1,12 @@
1set(ROOT_DIR ../..)
2set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
3
4# setup for find modules
5set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
6
7set(TARGET_NAME particles)1set(TARGET_NAME particles)
8 2
9find_package(Qt5Widgets REQUIRED)3# use setup_hifi_library macro to setup our project and link appropriate Qt modules
10 4setup_hifi_library(Gui Network Script)
11include(${MACRO_DIR}/SetupHifiLibrary.cmake)
12setup_hifi_library(${TARGET_NAME})
13
14include(${MACRO_DIR}/IncludeGLM.cmake)
15include_glm(${TARGET_NAME} "${ROOT_DIR}")
16
17include(${MACRO_DIR}/LinkHifiLibrary.cmake)
18link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
19link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}")
20link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}")
21link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
22link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}")
23 5
24# link ZLIB6include_glm()
25find_package(ZLIB)
26 7
27include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}")8link_hifi_libraries(shared octree fbx networking animation)
28target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets)9include_hifi_library_headers(script-engine)
29 10
30# add a definition for ssize_t so that windows doesn't bail11# call macro to link our dependencies and bubble them up via a property on our target
31if (WIN32)12link_shared_dependencies()
32 add_definitions(-Dssize_t=long)
33endif ()
libraries/particles/src/Particle.cpp+3−3
@@ -13,7 +13,7 @@ · 12 unmodified lines
13 13
14#include <Octree.h>14#include <Octree.h>
15#include <RegisteredMetaTypes.h>15#include <RegisteredMetaTypes.h>
16#include <SharedUtil.h> // usecTimestampNow()16#include <GLMHelpers.h>
17#include <VoxelsScriptingInterface.h>17#include <VoxelsScriptingInterface.h>
18#include <VoxelDetail.h>18#include <VoxelDetail.h>
19 19
@@ -22,7 +22,7 @@ · 2 unmodified lines
22// I'm open to other potential solutions. Could we change cmake to allow libraries to reference each others22// I'm open to other potential solutions. Could we change cmake to allow libraries to reference each others
23// headers, but not link to each other, this is essentially what this construct is doing, but would be23// headers, but not link to each other, this is essentially what this construct is doing, but would be
24// better to add includes to the include path, but not link24// better to add includes to the include path, but not link
25#include "../../script-engine/src/ScriptEngine.h"25#include <ScriptEngine.h>
26 26
27#include "ParticlesScriptingInterface.h"27#include "ParticlesScriptingInterface.h"
28#include "Particle.h"28#include "Particle.h"
@@ -856,7 +856,7 @@ bool Particle::encodeParticleEditMessageDetails(PacketType command, ParticleID i · 827 unmodified lines
856}856}
857 857
858// adjust any internal timestamps to fix clock skew for this server858// adjust any internal timestamps to fix clock skew for this server
859void Particle::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) {859void Particle::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, size_t length, int clockSkew) {
860 unsigned char* dataAt = codeColorBuffer;860 unsigned char* dataAt = codeColorBuffer;
861 int octets = numberOfThreeBitSectionsInCode(dataAt);861 int octets = numberOfThreeBitSectionsInCode(dataAt);
862 int lengthOfOctcode = bytesRequiredForCodeLength(octets);862 int lengthOfOctcode = bytesRequiredForCodeLength(octets);
libraries/particles/src/Particle.h+1−1
@@ -292,7 +292,7 @@ public: · 291 unmodified lines
292 static bool encodeParticleEditMessageDetails(PacketType command, ParticleID id, const ParticleProperties& details,292 static bool encodeParticleEditMessageDetails(PacketType command, ParticleID id, const ParticleProperties& details,
293 unsigned char* bufferOut, int sizeIn, int& sizeOut);293 unsigned char* bufferOut, int sizeIn, int& sizeOut);
294 294
295 static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew);295 static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, size_t length, int clockSkew);
296 296
297 void applyHardCollision(const CollisionInfo& collisionInfo);297 void applyHardCollision(const CollisionInfo& collisionInfo);
298 298
libraries/particles/src/ParticleEditPacketSender.cpp+2−2
@@ -38,8 +38,8 @@ void ParticleEditPacketSender::sendEditParticleMessage(PacketType type, Particle · 37 unmodified lines
38 }38 }
39}39}
40 40
41void ParticleEditPacketSender::adjustEditPacketForClockSkew(PacketType type, 41void ParticleEditPacketSender::adjustEditPacketForClockSkew(PacketType type,
42 unsigned char* codeColorBuffer, ssize_t length, int clockSkew) {42 unsigned char* codeColorBuffer, size_t length, int clockSkew) {
43 Particle::adjustEditPacketForClockSkew(codeColorBuffer, length, clockSkew);43 Particle::adjustEditPacketForClockSkew(codeColorBuffer, length, clockSkew);
44}44}
45 45
libraries/particles/src/ParticleEditPacketSender.h+1−1
@@ -31,6 +31,6 @@ public: · 30 unmodified lines
31 31
32 // My server type is the particle server32 // My server type is the particle server
33 virtual char getMyNodeType() const { return NodeType::ParticleServer; }33 virtual char getMyNodeType() const { return NodeType::ParticleServer; }
34 virtual void adjustEditPacketForClockSkew(PacketType type, unsigned char* codeColorBuffer, ssize_t length, int clockSkew);34 virtual void adjustEditPacketForClockSkew(PacketType type, unsigned char* codeColorBuffer, size_t length, int clockSkew);
35};35};
36#endif // hifi_ParticleEditPacketSender_h36#endif // hifi_ParticleEditPacketSender_h
libraries/script-engine/CMakeLists.txt+6−30
@@ -1,35 +1,11 @@
1set(ROOT_DIR ../..)
2set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
3
4# setup for find modules
5set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
6
7set(TARGET_NAME script-engine)1set(TARGET_NAME script-engine)
8 2
9find_package(Qt5Widgets REQUIRED)3# use setup_hifi_library macro to setup our project and link appropriate Qt modules
10 4setup_hifi_library(Gui Network Script Widgets)
11include(${MACRO_DIR}/SetupHifiLibrary.cmake)
12setup_hifi_library(${TARGET_NAME})
13
14include(${MACRO_DIR}/IncludeGLM.cmake)
15include_glm(${TARGET_NAME} "${ROOT_DIR}")
16
17include(${MACRO_DIR}/LinkHifiLibrary.cmake)
18link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
19link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}")
20link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}")
21link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}")
22link_hifi_library(particles ${TARGET_NAME} "${ROOT_DIR}")
23link_hifi_library(entities ${TARGET_NAME} "${ROOT_DIR}")
24link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}")
25 5
26# link ZLIB6include_glm()
27find_package(ZLIB)
28 7
29include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}")8link_hifi_libraries(shared octree voxels fbx particles entities animation)
30target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets)
31 9
32# add a definition for ssize_t so that windows doesn't bail10# call macro to link our dependencies and bubble them up via a property on our target
33if (WIN32)11link_shared_dependencies()
34 add_definitions(-Dssize_t=long)
35endif ()
libraries/script-engine/src/Quat.cpp+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14#include <QDebug>14#include <QDebug>
15 15
16#include <OctreeConstants.h>16#include <OctreeConstants.h>
17#include <SharedUtil.h>17#include <GLMHelpers.h>
18#include "Quat.h"18#include "Quat.h"
19 19
20 20
libraries/shared/CMakeLists.txt+4−30
@@ -1,33 +1,7 @@
1set(ROOT_DIR ../..)
2set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
3
4set(TARGET_NAME shared)1set(TARGET_NAME shared)
5project(${TARGET_NAME})
6
7find_package(Qt5 COMPONENTS Network Widgets Xml Script)
8
9include(${MACRO_DIR}/SetupHifiLibrary.cmake)
10setup_hifi_library(${TARGET_NAME})
11
12# include GLM
13include(${MACRO_DIR}/IncludeGLM.cmake)
14include_glm(${TARGET_NAME} "${ROOT_DIR}")
15
16set(EXTERNAL_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external")
17
18if (WIN32)
19 # include headers for external libraries and InterfaceConfig.
20 include_directories("${EXTERNAL_ROOT_DIR}")
21endif (WIN32)
22
23# link required libraries on UNIX
24if (UNIX AND NOT APPLE)
25 find_package(Threads REQUIRED)
26 target_link_libraries(${TARGET_NAME} "${CMAKE_THREAD_LIBS_INIT}")
27endif (UNIX AND NOT APPLE)
28 2
29# There is something special (bug) about Qt5Scripts, that we have to explicitly add its include3# use setup_hifi_library macro to setup our project and link appropriate Qt modules
30# directory when Qt5 (5.2.1) is compiled from source and is not in a standard place.4setup_hifi_library(Network Widgets)
31include_directories(SYSTEM "${Qt5Script_INCLUDE_DIRS}")
32 5
33target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets)6# call macro to link our dependencies and bubble them up via a property on our target
7link_shared_dependencies()
libraries/shared/external/pthread.h+0−1403
@@ -1,1403 +0,0 @@
1/* This is an implementation of the threads API of POSIX 1003.1-2001.
2 *
3 * --------------------------------------------------------------------------
4 *
5 * Pthreads-win32 - POSIX Threads Library for Win32
6 * Copyright(C) 1998 John E. Bossom
7 * Copyright(C) 1999,2005 Pthreads-win32 contributors
8 *
9 * Contact Email: rpj@callisto.canberra.edu.au
10 *
11 * The current list of contributors is contained
12 * in the file CONTRIBUTORS included with the source
13 * code distribution. The list can also be seen at the
14 * following World Wide Web location:
15 * http://sources.redhat.com/pthreads-win32/contributors.html
16 *
17 * This library is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU Lesser General Public
19 * License as published by the Free Software Foundation; either
20 * version 2 of the License, or (at your option) any later version.
21 *
22 * This library is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * Lesser General Public License for more details.
26 *
27 * You should have received a copy of the GNU Lesser General Public
28 * License along with this library in the file COPYING.LIB;
29 * if not, write to the Free Software Foundation, Inc.,
30 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
31 */
32
33#if !defined( PTHREAD_H )
34#define PTHREAD_H
35
36#define PTW32_STATIC_LIB
37
38/*
39 * See the README file for an explanation of the pthreads-win32 version
40 * numbering scheme and how the DLL is named etc.
41 */
42#define PTW32_VERSION 2,10,0,0
43#define PTW32_VERSION_STRING "2, 10, 0, 0\0"
44
45/* There are three implementations of cancel cleanup.
46 * Note that pthread.h is included in both application
47 * compilation units and also internally for the library.
48 * The code here and within the library aims to work
49 * for all reasonable combinations of environments.
50 *
51 * The three implementations are:
52 *
53 * WIN32 SEH
54 * C
55 * C++
56 *
57 * Please note that exiting a push/pop block via
58 * "return", "exit", "break", or "continue" will
59 * lead to different behaviour amongst applications
60 * depending upon whether the library was built
61 * using SEH, C++, or C. For example, a library built
62 * with SEH will call the cleanup routine, while both
63 * C++ and C built versions will not.
64 */
65
66/*
67 * Define defaults for cleanup code.
68 * Note: Unless the build explicitly defines one of the following, then
69 * we default to standard C style cleanup. This style uses setjmp/longjmp
70 * in the cancellation and thread exit implementations and therefore won't
71 * do stack unwinding if linked to applications that have it (e.g.
72 * C++ apps). This is currently consistent with most/all commercial Unix
73 * POSIX threads implementations.
74 */
75#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C )
76/*
77 [i_a] fix for apps using pthreads-Win32: when they do not define __CLEANUP_SEH themselves,
78 they're screwed as they'll receive the '__CLEANUP_C' macros which do NOT work when
79 the pthreads library code itself has actually been build with __CLEANUP_SEH,
80 which is the case when building this stuff in MSVC.
81
82 Hence this section is made to 'sensibly autodetect' the cleanup mode, when it hasn't
83 been hardwired in the makefiles / project files.
84
85 After all, who expects he MUST define one of these __CLEANUP_XXX defines in his own
86 code when using pthreads-Win32, for whatever reason.
87 */
88#if (defined(_MSC_VER) || defined(PTW32_RC_MSC))
89#define __CLEANUP_SEH
90#elif defined(__cplusplus)
91#define __CLEANUP_CXX
92#else
93#define __CLEANUP_C
94#endif
95#endif
96
97#if defined( __CLEANUP_SEH ) && ( !defined( _MSC_VER ) && !defined(PTW32_RC_MSC))
98#error ERROR [__FILE__, line __LINE__]: SEH is not supported for this compiler.
99#endif
100
101/*
102 * Stop here if we are being included by the resource compiler.
103 */
104#if !defined(RC_INVOKED)
105
106#undef PTW32_LEVEL
107
108#if defined(_POSIX_SOURCE)
109#define PTW32_LEVEL 0
110/* Early POSIX */
111#endif
112
113#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309
114#undef PTW32_LEVEL
115#define PTW32_LEVEL 1
116/* Include 1b, 1c and 1d */
117#endif
118
119#if defined(INCLUDE_NP)
120#undef PTW32_LEVEL
121#define PTW32_LEVEL 2
122/* Include Non-Portable extensions */
123#endif
124
125#define PTW32_LEVEL_MAX 3
126
127#if ( defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112 ) || !defined(PTW32_LEVEL)
128#define PTW32_LEVEL PTW32_LEVEL_MAX
129/* Include everything */
130#endif
131
132#if defined(_UWIN)
133# define HAVE_STRUCT_TIMESPEC 1
134# define HAVE_SIGNAL_H 1
135# undef HAVE_PTW32_CONFIG_H
136# pragma comment(lib, "pthread")
137#endif
138
139#if defined(__MINGW32__) || defined(__MINGW64__)
140# define PTW32_CONFIG_MINGW
141#endif
142#if defined(_MSC_VER)
143# if _MSC_VER < 1300
144# define PTW32_CONFIG_MSVC6
145# endif
146# if _MSC_VER < 1400
147# define PTW32_CONFIG_MSVC7
148# endif
149#endif
150
151/*
152 * -------------------------------------------------------------
153 *
154 *
155 * Module: pthread.h
156 *
157 * Purpose:
158 * Provides an implementation of PThreads based upon the
159 * standard:
160 *
161 * POSIX 1003.1-2001
162 * and
163 * The Single Unix Specification version 3
164 *
165 * (these two are equivalent)
166 *
167 * in order to enhance code portability between Windows,
168 * various commercial Unix implementations, and Linux.
169 *
170 * See the ANNOUNCE file for a full list of conforming
171 * routines and defined constants, and a list of missing
172 * routines and constants not defined in this implementation.
173 *
174 * Authors:
175 * There have been many contributors to this library.
176 * The initial implementation was contributed by
177 * John Bossom, and several others have provided major
178 * sections or revisions of parts of the implementation.
179 * Often significant effort has been contributed to
180 * find and fix important bugs and other problems to
181 * improve the reliability of the library, which sometimes
182 * is not reflected in the amount of code which changed as
183 * result.
184 * As much as possible, the contributors are acknowledged
185 * in the ChangeLog file in the source code distribution
186 * where their changes are noted in detail.
187 *
188 * Contributors are listed in the CONTRIBUTORS file.
189 *
190 * As usual, all bouquets go to the contributors, and all
191 * brickbats go to the project maintainer.
192 *
193 * Maintainer:
194 * The code base for this project is coordinated and
195 * eventually pre-tested, packaged, and made available by
196 *
197 * Ross Johnson <rpj@callisto.canberra.edu.au>
198 *
199 * QA Testers:
200 * Ultimately, the library is tested in the real world by
201 * a host of competent and demanding scientists and
202 * engineers who report bugs and/or provide solutions
203 * which are then fixed or incorporated into subsequent
204 * versions of the library. Each time a bug is fixed, a
205 * test case is written to prove the fix and ensure
206 * that later changes to the code don't reintroduce the
207 * same error. The number of test cases is slowly growing
208 * and therefore so is the code reliability.
209 *
210 * Compliance:
211 * See the file ANNOUNCE for the list of implemented
212 * and not-implemented routines and defined options.
213 * Of course, these are all defined is this file as well.
214 *
215 * Web site:
216 * The source code and other information about this library
217 * are available from
218 *
219 * http://sources.redhat.com/pthreads-win32/
220 *
221 * -------------------------------------------------------------
222 */
223
224/* Try to avoid including windows.h */
225#if defined(PTW32_CONFIG_MINGW) && defined(__cplusplus)
226#define PTW32_INCLUDE_WINDOWS_H
227#endif
228
229#if defined(PTW32_INCLUDE_WINDOWS_H)
230#include <windows.h>
231#endif
232
233#if defined(PTW32_CONFIG_MSVC6) || defined(__DMC__)
234/*
235 * VC++6.0 or early compiler's header has no DWORD_PTR type.
236 */
237typedef unsigned long DWORD_PTR;
238typedef unsigned long ULONG_PTR;
239#endif
240/*
241 * -----------------
242 * autoconf switches
243 * -----------------
244 */
245
246#if defined(HAVE_PTW32_CONFIG_H)
247#include "config.h"
248#endif /* HAVE_PTW32_CONFIG_H */
249
250#if !defined(NEED_FTIME)
251#include <time.h>
252#else /* NEED_FTIME */
253/* use native WIN32 time API */
254#endif /* NEED_FTIME */
255
256#if defined(HAVE_SIGNAL_H)
257#include <signal.h>
258#endif /* HAVE_SIGNAL_H */
259
260#include <limits.h>
261
262/*
263 * Boolean values to make us independent of system includes.
264 */
265enum {
266 PTW32_FALSE = 0,
267 PTW32_TRUE = (! PTW32_FALSE)
268};
269
270/*
271 * This is a duplicate of what is in the autoconf config.h,
272 * which is only used when building the pthread-win32 libraries.
273 */
274
275#if !defined(PTW32_CONFIG_H)
276# if defined(WINCE)
277# define NEED_ERRNO
278# define NEED_SEM
279# endif
280# if defined(__MINGW64__)
281# define HAVE_STRUCT_TIMESPEC
282# define HAVE_MODE_T
283# elif defined(_UWIN) || defined(__MINGW32__)
284# define HAVE_MODE_T
285# endif
286#endif
287
288/*
289 *
290 */
291
292#if PTW32_LEVEL >= PTW32_LEVEL_MAX
293#if defined(NEED_ERRNO)
294#include "need_errno.h"
295#else
296#include <errno.h>
297#endif
298#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */
299
300/*
301 * Several systems don't define some error numbers.
302 */
303#if !defined(ENOTSUP)
304# define ENOTSUP 48 /* This is the value in Solaris. */
305#endif
306
307#if !defined(ETIMEDOUT)
308# define ETIMEDOUT 10060 /* Same as WSAETIMEDOUT */
309#endif
310
311#if !defined(ENOSYS)
312# define ENOSYS 140 /* Semi-arbitrary value */
313#endif
314
315#if !defined(EDEADLK)
316# if defined(EDEADLOCK)
317# define EDEADLK EDEADLOCK
318# else
319# define EDEADLK 36 /* This is the value in MSVC. */
320# endif
321#endif
322
323/* POSIX 2008 - related to robust mutexes */
324#if !defined(EOWNERDEAD)
325# define EOWNERDEAD 43
326#endif
327#if !defined(ENOTRECOVERABLE)
328# define ENOTRECOVERABLE 44
329#endif
330
331#include <sched.h>
332
333/*
334 * To avoid including windows.h we define only those things that we
335 * actually need from it.
336 */
337#if !defined(PTW32_INCLUDE_WINDOWS_H)
338#if !defined(HANDLE)
339# define PTW32__HANDLE_DEF
340# define HANDLE void *
341#endif
342#if !defined(DWORD)
343# define PTW32__DWORD_DEF
344# define DWORD unsigned long
345#endif
346#endif
347
348#if !defined(HAVE_STRUCT_TIMESPEC)
349#define HAVE_STRUCT_TIMESPEC
350#if !defined(_TIMESPEC_DEFINED)
351#define _TIMESPEC_DEFINED
352struct timespec {
353 time_t tv_sec;
354 long tv_nsec;
355};
356#endif /* _TIMESPEC_DEFINED */
357#endif /* HAVE_STRUCT_TIMESPEC */
358
359#if !defined(SIG_BLOCK)
360#define SIG_BLOCK 0
361#endif /* SIG_BLOCK */
362
363#if !defined(SIG_UNBLOCK)
364#define SIG_UNBLOCK 1
365#endif /* SIG_UNBLOCK */
366
367#if !defined(SIG_SETMASK)
368#define SIG_SETMASK 2
369#endif /* SIG_SETMASK */
370
371#if defined(__cplusplus)
372extern "C"
373{
374#endif /* __cplusplus */
375
376/*
377 * -------------------------------------------------------------
378 *
379 * POSIX 1003.1-2001 Options
380 * =========================
381 *
382 * Options are normally set in <unistd.h>, which is not provided
383 * with pthreads-win32.
384 *
385 * For conformance with the Single Unix Specification (version 3), all of the
386 * options below are defined, and have a value of either -1 (not supported)
387 * or 200112L (supported).
388 *
389 * These options can neither be left undefined nor have a value of 0, because
390 * either indicates that sysconf(), which is not implemented, may be used at
391 * runtime to check the status of the option.
392 *
393 * _POSIX_THREADS (== 200112L)
394 * If == 200112L, you can use threads
395 *
396 * _POSIX_THREAD_ATTR_STACKSIZE (== 200112L)
397 * If == 200112L, you can control the size of a thread's
398 * stack
399 * pthread_attr_getstacksize
400 * pthread_attr_setstacksize
401 *
402 * _POSIX_THREAD_ATTR_STACKADDR (== -1)
403 * If == 200112L, you can allocate and control a thread's
404 * stack. If not supported, the following functions
405 * will return ENOSYS, indicating they are not
406 * supported:
407 * pthread_attr_getstackaddr
408 * pthread_attr_setstackaddr
409 *
410 * _POSIX_THREAD_PRIORITY_SCHEDULING (== -1)
411 * If == 200112L, you can use realtime scheduling.
412 * This option indicates that the behaviour of some
413 * implemented functions conforms to the additional TPS
414 * requirements in the standard. E.g. rwlocks favour
415 * writers over readers when threads have equal priority.
416 *
417 * _POSIX_THREAD_PRIO_INHERIT (== -1)
418 * If == 200112L, you can create priority inheritance
419 * mutexes.
420 * pthread_mutexattr_getprotocol +
421 * pthread_mutexattr_setprotocol +
422 *
423 * _POSIX_THREAD_PRIO_PROTECT (== -1)
424 * If == 200112L, you can create priority ceiling mutexes
425 * Indicates the availability of:
426 * pthread_mutex_getprioceiling
427 * pthread_mutex_setprioceiling
428 * pthread_mutexattr_getprioceiling
429 * pthread_mutexattr_getprotocol +
430 * pthread_mutexattr_setprioceiling
431 * pthread_mutexattr_setprotocol +
432 *
433 * _POSIX_THREAD_PROCESS_SHARED (== -1)
434 * If set, you can create mutexes and condition
435 * variables that can be shared with another
436 * process.If set, indicates the availability
437 * of:
438 * pthread_mutexattr_getpshared
439 * pthread_mutexattr_setpshared
440 * pthread_condattr_getpshared
441 * pthread_condattr_setpshared
442 *
443 * _POSIX_THREAD_SAFE_FUNCTIONS (== 200112L)
444 * If == 200112L you can use the special *_r library
445 * functions that provide thread-safe behaviour
446 *
447 * _POSIX_READER_WRITER_LOCKS (== 200112L)
448 * If == 200112L, you can use read/write locks
449 *
450 * _POSIX_SPIN_LOCKS (== 200112L)
451 * If == 200112L, you can use spin locks
452 *
453 * _POSIX_BARRIERS (== 200112L)
454 * If == 200112L, you can use barriers
455 *
456 * + These functions provide both 'inherit' and/or
457 * 'protect' protocol, based upon these macro
458 * settings.
459 *
460 * -------------------------------------------------------------
461 */
462
463/*
464 * POSIX Options
465 */
466#undef _POSIX_THREADS
467#define _POSIX_THREADS 200809L
468
469#undef _POSIX_READER_WRITER_LOCKS
470#define _POSIX_READER_WRITER_LOCKS 200809L
471
472#undef _POSIX_SPIN_LOCKS
473#define _POSIX_SPIN_LOCKS 200809L
474
475#undef _POSIX_BARRIERS
476#define _POSIX_BARRIERS 200809L
477
478#undef _POSIX_THREAD_SAFE_FUNCTIONS
479#define _POSIX_THREAD_SAFE_FUNCTIONS 200809L
480
481#undef _POSIX_THREAD_ATTR_STACKSIZE
482#define _POSIX_THREAD_ATTR_STACKSIZE 200809L
483
484/*
485 * The following options are not supported
486 */
487#undef _POSIX_THREAD_ATTR_STACKADDR
488#define _POSIX_THREAD_ATTR_STACKADDR -1
489
490#undef _POSIX_THREAD_PRIO_INHERIT
491#define _POSIX_THREAD_PRIO_INHERIT -1
492
493#undef _POSIX_THREAD_PRIO_PROTECT
494#define _POSIX_THREAD_PRIO_PROTECT -1
495
496/* TPS is not fully supported. */
497#undef _POSIX_THREAD_PRIORITY_SCHEDULING
498#define _POSIX_THREAD_PRIORITY_SCHEDULING -1
499
500#undef _POSIX_THREAD_PROCESS_SHARED
501#define _POSIX_THREAD_PROCESS_SHARED -1
502
503
504/*
505 * POSIX 1003.1-2001 Limits
506 * ===========================
507 *
508 * These limits are normally set in <limits.h>, which is not provided with
509 * pthreads-win32.
510 *
511 * PTHREAD_DESTRUCTOR_ITERATIONS
512 * Maximum number of attempts to destroy
513 * a thread's thread-specific data on
514 * termination (must be at least 4)
515 *
516 * PTHREAD_KEYS_MAX
517 * Maximum number of thread-specific data keys
518 * available per process (must be at least 128)
519 *
520 * PTHREAD_STACK_MIN
521 * Minimum supported stack size for a thread
522 *
523 * PTHREAD_THREADS_MAX
524 * Maximum number of threads supported per
525 * process (must be at least 64).
526 *
527 * SEM_NSEMS_MAX
528 * The maximum number of semaphores a process can have.
529 * (must be at least 256)
530 *
531 * SEM_VALUE_MAX
532 * The maximum value a semaphore can have.
533 * (must be at least 32767)
534 *
535 */
536#undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS
537#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4
538
539#undef PTHREAD_DESTRUCTOR_ITERATIONS
540#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS
541
542#undef _POSIX_THREAD_KEYS_MAX
543#define _POSIX_THREAD_KEYS_MAX 128
544
545#undef PTHREAD_KEYS_MAX
546#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX
547
548#undef PTHREAD_STACK_MIN
549#define PTHREAD_STACK_MIN 0
550
551#undef _POSIX_THREAD_THREADS_MAX
552#define _POSIX_THREAD_THREADS_MAX 64
553
554 /* Arbitrary value */
555#undef PTHREAD_THREADS_MAX
556#define PTHREAD_THREADS_MAX 2019
557
558#undef _POSIX_SEM_NSEMS_MAX
559#define _POSIX_SEM_NSEMS_MAX 256
560
561 /* Arbitrary value */
562#undef SEM_NSEMS_MAX
563#define SEM_NSEMS_MAX 1024
564
565#undef _POSIX_SEM_VALUE_MAX
566#define _POSIX_SEM_VALUE_MAX 32767
567
568#undef SEM_VALUE_MAX
569#define SEM_VALUE_MAX INT_MAX
570
571
572#if defined(__GNUC__) && !defined(__declspec)
573# error Please upgrade your GNU compiler to one that supports __declspec.
574#endif
575
576/*
577 * When building the library, you should define PTW32_BUILD so that
578 * the variables/functions are exported correctly. When using the library,
579 * do NOT define PTW32_BUILD, and then the variables/functions will
580 * be imported correctly.
581 */
582#if !defined(PTW32_STATIC_LIB)
583# if defined(PTW32_BUILD)
584# define PTW32_DLLPORT __declspec (dllexport)
585# else
586# define PTW32_DLLPORT __declspec (dllimport)
587# endif
588#else
589# define PTW32_DLLPORT
590#endif
591
592/*
593 * The Open Watcom C/C++ compiler uses a non-standard calling convention
594 * that passes function args in registers unless __cdecl is explicitly specified
595 * in exposed function prototypes.
596 *
597 * We force all calls to cdecl even though this could slow Watcom code down
598 * slightly. If you know that the Watcom compiler will be used to build both
599 * the DLL and application, then you can probably define this as a null string.
600 * Remember that pthread.h (this file) is used for both the DLL and application builds.
601 */
602#define PTW32_CDECL __cdecl
603
604#if defined(_UWIN) && PTW32_LEVEL >= PTW32_LEVEL_MAX
605# include <sys/types.h>
606#else
607/*
608 * Generic handle type - intended to extend uniqueness beyond
609 * that available with a simple pointer. It should scale for either
610 * IA-32 or IA-64.
611 */
612typedef struct {
613 void * p; /* Pointer to actual object */
614 unsigned int x; /* Extra information - reuse count etc */
615} ptw32_handle_t;
616
617typedef ptw32_handle_t pthread_t;
618typedef struct pthread_attr_t_ * pthread_attr_t;
619typedef struct pthread_once_t_ pthread_once_t;
620typedef struct pthread_key_t_ * pthread_key_t;
621typedef struct pthread_mutex_t_ * pthread_mutex_t;
622typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t;
623typedef struct pthread_cond_t_ * pthread_cond_t;
624typedef struct pthread_condattr_t_ * pthread_condattr_t;
625#endif
626typedef struct pthread_rwlock_t_ * pthread_rwlock_t;
627typedef struct pthread_rwlockattr_t_ * pthread_rwlockattr_t;
628typedef struct pthread_spinlock_t_ * pthread_spinlock_t;
629typedef struct pthread_barrier_t_ * pthread_barrier_t;
630typedef struct pthread_barrierattr_t_ * pthread_barrierattr_t;
631
632/*
633 * ====================
634 * ====================
635 * POSIX Threads
636 * ====================
637 * ====================
638 */
639
640enum {
641/*
642 * pthread_attr_{get,set}detachstate
643 */
644 PTHREAD_CREATE_JOINABLE = 0, /* Default */
645 PTHREAD_CREATE_DETACHED = 1,
646
647/*
648 * pthread_attr_{get,set}inheritsched
649 */
650 PTHREAD_INHERIT_SCHED = 0,
651 PTHREAD_EXPLICIT_SCHED = 1, /* Default */
652
653/*
654 * pthread_{get,set}scope
655 */
656 PTHREAD_SCOPE_PROCESS = 0,
657 PTHREAD_SCOPE_SYSTEM = 1, /* Default */
658
659/*
660 * pthread_setcancelstate paramters
661 */
662 PTHREAD_CANCEL_ENABLE = 0, /* Default */
663 PTHREAD_CANCEL_DISABLE = 1,
664
665/*
666 * pthread_setcanceltype parameters
667 */
668 PTHREAD_CANCEL_ASYNCHRONOUS = 0,
669 PTHREAD_CANCEL_DEFERRED = 1, /* Default */
670
671/*
672 * pthread_mutexattr_{get,set}pshared
673 * pthread_condattr_{get,set}pshared
674 */
675 PTHREAD_PROCESS_PRIVATE = 0,
676 PTHREAD_PROCESS_SHARED = 1,
677
678/*
679 * pthread_mutexattr_{get,set}robust
680 */
681 PTHREAD_MUTEX_STALLED = 0, /* Default */
682 PTHREAD_MUTEX_ROBUST = 1,
683
684/*
685 * pthread_barrier_wait
686 */
687 PTHREAD_BARRIER_SERIAL_THREAD = -1
688};
689
690/*
691 * ====================
692 * ====================
693 * cancellation
694 * ====================
695 * ====================
696 */
697#define PTHREAD_CANCELED ((void *)(size_t) -1)
698
699
700/*
701 * ====================
702 * ====================
703 * Once Key
704 * ====================
705 * ====================
706 */
707#define PTHREAD_ONCE_INIT { PTW32_FALSE, 0, 0, 0}
708
709struct pthread_once_t_
710{
711 int done; /* indicates if user function has been executed */
712 void * lock;
713 int reserved1;
714 int reserved2;
715};
716
717
718/*
719 * ====================
720 * ====================
721 * Object initialisers
722 * ====================
723 * ====================
724 */
725#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -1)
726#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -2)
727#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -3)
728
729/*
730 * Compatibility with LinuxThreads
731 */
732#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER
733#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER
734
735#define PTHREAD_COND_INITIALIZER ((pthread_cond_t)(size_t) -1)
736
737#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t)(size_t) -1)
738
739#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t)(size_t) -1)
740
741
742/*
743 * Mutex types.
744 */
745enum
746{
747 /* Compatibility with LinuxThreads */
748 PTHREAD_MUTEX_FAST_NP,
749 PTHREAD_MUTEX_RECURSIVE_NP,
750 PTHREAD_MUTEX_ERRORCHECK_NP,
751 PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP,
752 PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP,
753 /* For compatibility with POSIX */
754 PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP,
755 PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP,
756 PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP,
757 PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
758};
759
760
761typedef struct ptw32_cleanup_t ptw32_cleanup_t;
762
763#if defined(_MSC_VER)
764/* Disable MSVC 'anachronism used' warning */
765#pragma warning( disable : 4229 )
766#endif
767
768typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *);
769
770#if defined(_MSC_VER)
771#pragma warning( default : 4229 )
772#endif
773
774struct ptw32_cleanup_t
775{
776 ptw32_cleanup_callback_t routine;
777 void *arg;
778 struct ptw32_cleanup_t *prev;
779};
780
781#if defined(__CLEANUP_SEH)
782 /*
783 * WIN32 SEH version of cancel cleanup.
784 */
785
786#define pthread_cleanup_push( _rout, _arg ) \
787 { \
788 ptw32_cleanup_t _cleanup; \
789 \
790 _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \
791 _cleanup.arg = (_arg); \
792 __try \
793 { \
794
795#define pthread_cleanup_pop( _execute ) \
796 } \
797 __finally \
798 { \
799 if( _execute || AbnormalTermination()) \
800 { \
801 (*(_cleanup.routine))( _cleanup.arg ); \
802 } \
803 } \
804 }
805
806#else /* __CLEANUP_SEH */
807
808#if defined(__CLEANUP_C)
809
810 /*
811 * C implementation of PThreads cancel cleanup
812 */
813
814#define pthread_cleanup_push( _rout, _arg ) \
815 { \
816 ptw32_cleanup_t _cleanup; \
817 \
818 ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \
819
820#define pthread_cleanup_pop( _execute ) \
821 (void) ptw32_pop_cleanup( _execute ); \
822 }
823
824#else /* __CLEANUP_C */
825
826#if defined(__CLEANUP_CXX)
827
828 /*
829 * C++ version of cancel cleanup.
830 * - John E. Bossom.
831 */
832
833 class PThreadCleanup {
834 /*
835 * PThreadCleanup
836 *
837 * Purpose
838 * This class is a C++ helper class that is
839 * used to implement pthread_cleanup_push/
840 * pthread_cleanup_pop.
841 * The destructor of this class automatically
842 * pops the pushed cleanup routine regardless
843 * of how the code exits the scope
844 * (i.e. such as by an exception)
845 */
846 ptw32_cleanup_callback_t cleanUpRout;
847 void * obj;
848 int executeIt;
849
850 public:
851 PThreadCleanup() :
852 cleanUpRout( 0 ),
853 obj( 0 ),
854 executeIt( 0 )
855 /*
856 * No cleanup performed
857 */
858 {
859 }
860
861 PThreadCleanup(
862 ptw32_cleanup_callback_t routine,
863 void * arg ) :
864 cleanUpRout( routine ),
865 obj( arg ),
866 executeIt( 1 )
867 /*
868 * Registers a cleanup routine for 'arg'
869 */
870 {
871 }
872
873 ~PThreadCleanup()
874 {
875 if ( executeIt && ((void *) cleanUpRout != (void *) 0) )
876 {
877 (void) (*cleanUpRout)( obj );
878 }
879 }
880
881 void execute( int exec )
882 {
883 executeIt = exec;
884 }
885 };
886
887 /*
888 * C++ implementation of PThreads cancel cleanup;
889 * This implementation takes advantage of a helper
890 * class who's destructor automatically calls the
891 * cleanup routine if we exit our scope weirdly
892 */
893#define pthread_cleanup_push( _rout, _arg ) \
894 { \
895 PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \
896 (void *) (_arg) );
897
898#define pthread_cleanup_pop( _execute ) \
899 cleanup.execute( _execute ); \
900 }
901
902#else
903
904#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined.
905
906#endif /* __CLEANUP_CXX */
907
908#endif /* __CLEANUP_C */
909
910#endif /* __CLEANUP_SEH */
911
912/*
913 * ===============
914 * ===============
915 * Methods
916 * ===============
917 * ===============
918 */
919
920/*
921 * PThread Attribute Functions
922 */
923PTW32_DLLPORT int PTW32_CDECL pthread_attr_init (pthread_attr_t * attr);
924
925PTW32_DLLPORT int PTW32_CDECL pthread_attr_destroy (pthread_attr_t * attr);
926
927PTW32_DLLPORT int PTW32_CDECL pthread_attr_getdetachstate (const pthread_attr_t * attr,
928 int *detachstate);
929
930PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstackaddr (const pthread_attr_t * attr,
931 void **stackaddr);
932
933PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstacksize (const pthread_attr_t * attr,
934 size_t * stacksize);
935
936PTW32_DLLPORT int PTW32_CDECL pthread_attr_setdetachstate (pthread_attr_t * attr,
937 int detachstate);
938
939PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstackaddr (pthread_attr_t * attr,
940 void *stackaddr);
941
942PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstacksize (pthread_attr_t * attr,
943 size_t stacksize);
944
945PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedparam (const pthread_attr_t *attr,
946 struct sched_param *param);
947
948PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedparam (pthread_attr_t *attr,
949 const struct sched_param *param);
950
951PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedpolicy (pthread_attr_t *,
952 int);
953
954PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedpolicy (const pthread_attr_t *,
955 int *);
956
957PTW32_DLLPORT int PTW32_CDECL pthread_attr_setinheritsched(pthread_attr_t * attr,
958 int inheritsched);
959
960PTW32_DLLPORT int PTW32_CDECL pthread_attr_getinheritsched(const pthread_attr_t * attr,
961 int * inheritsched);
962
963PTW32_DLLPORT int PTW32_CDECL pthread_attr_setscope (pthread_attr_t *,
964 int);
965
966PTW32_DLLPORT int PTW32_CDECL pthread_attr_getscope (const pthread_attr_t *,
967 int *);
968
969/*
970 * PThread Functions
971 */
972PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid,
973 const pthread_attr_t * attr,
974 void *(PTW32_CDECL *start) (void *),
975 void *arg);
976
977PTW32_DLLPORT int PTW32_CDECL pthread_detach (pthread_t tid);
978
979PTW32_DLLPORT int PTW32_CDECL pthread_equal (pthread_t t1,
980 pthread_t t2);
981
982PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr);
983
984PTW32_DLLPORT int PTW32_CDECL pthread_join (pthread_t thread,
985 void **value_ptr);
986
987PTW32_DLLPORT pthread_t PTW32_CDECL pthread_self (void);
988
989PTW32_DLLPORT int PTW32_CDECL pthread_cancel (pthread_t thread);
990
991PTW32_DLLPORT int PTW32_CDECL pthread_setcancelstate (int state,
992 int *oldstate);
993
994PTW32_DLLPORT int PTW32_CDECL pthread_setcanceltype (int type,
995 int *oldtype);
996
997PTW32_DLLPORT void PTW32_CDECL pthread_testcancel (void);
998
999PTW32_DLLPORT int PTW32_CDECL pthread_once (pthread_once_t * once_control,
1000 void (PTW32_CDECL *init_routine) (void));
1001
1002#if PTW32_LEVEL >= PTW32_LEVEL_MAX
1003PTW32_DLLPORT ptw32_cleanup_t * PTW32_CDECL ptw32_pop_cleanup (int execute);
1004
1005PTW32_DLLPORT void PTW32_CDECL ptw32_push_cleanup (ptw32_cleanup_t * cleanup,
1006 ptw32_cleanup_callback_t routine,
1007 void *arg);
1008#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */
1009
1010/*
1011 * Thread Specific Data Functions
1012 */
1013PTW32_DLLPORT int PTW32_CDECL pthread_key_create (pthread_key_t * key,
1014 void (PTW32_CDECL *destructor) (void *));
1015
1016PTW32_DLLPORT int PTW32_CDECL pthread_key_delete (pthread_key_t key);
1017
1018PTW32_DLLPORT int PTW32_CDECL pthread_setspecific (pthread_key_t key,
1019 const void *value);
1020
1021PTW32_DLLPORT void * PTW32_CDECL pthread_getspecific (pthread_key_t key);
1022
1023
1024/*
1025 * Mutex Attribute Functions
1026 */
1027PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_init (pthread_mutexattr_t * attr);
1028
1029PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_destroy (pthread_mutexattr_t * attr);
1030
1031PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getpshared (const pthread_mutexattr_t
1032 * attr,
1033 int *pshared);
1034
1035PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setpshared (pthread_mutexattr_t * attr,
1036 int pshared);
1037
1038PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind);
1039PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_gettype (const pthread_mutexattr_t * attr, int *kind);
1040
1041PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setrobust(
1042 pthread_mutexattr_t *attr,
1043 int robust);
1044PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getrobust(
1045 const pthread_mutexattr_t * attr,
1046 int * robust);
1047
1048/*
1049 * Barrier Attribute Functions
1050 */
1051PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_init (pthread_barrierattr_t * attr);
1052
1053PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_destroy (pthread_barrierattr_t * attr);
1054
1055PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_getpshared (const pthread_barrierattr_t
1056 * attr,
1057 int *pshared);
1058
1059PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_setpshared (pthread_barrierattr_t * attr,
1060 int pshared);
1061
1062/*
1063 * Mutex Functions
1064 */
1065PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init (pthread_mutex_t * mutex,
1066 const pthread_mutexattr_t * attr);
1067
1068PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex);
1069
1070PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex);
1071
1072PTW32_DLLPORT int PTW32_CDECL pthread_mutex_timedlock(pthread_mutex_t * mutex,
1073 const struct timespec *abstime);
1074
1075PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex);
1076
1077PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex);
1078
1079PTW32_DLLPORT int PTW32_CDECL pthread_mutex_consistent (pthread_mutex_t * mutex);
1080
1081/*
1082 * Spinlock Functions
1083 */
1084PTW32_DLLPORT int PTW32_CDECL pthread_spin_init (pthread_spinlock_t * lock, int pshared);
1085
1086PTW32_DLLPORT int PTW32_CDECL pthread_spin_destroy (pthread_spinlock_t * lock);
1087
1088PTW32_DLLPORT int PTW32_CDECL pthread_spin_lock (pthread_spinlock_t * lock);
1089
1090PTW32_DLLPORT int PTW32_CDECL pthread_spin_trylock (pthread_spinlock_t * lock);
1091
1092PTW32_DLLPORT int PTW32_CDECL pthread_spin_unlock (pthread_spinlock_t * lock);
1093
1094/*
1095 * Barrier Functions
1096 */
1097PTW32_DLLPORT int PTW32_CDECL pthread_barrier_init (pthread_barrier_t * barrier,
1098 const pthread_barrierattr_t * attr,
1099 unsigned int count);
1100
1101PTW32_DLLPORT int PTW32_CDECL pthread_barrier_destroy (pthread_barrier_t * barrier);
1102
1103PTW32_DLLPORT int PTW32_CDECL pthread_barrier_wait (pthread_barrier_t * barrier);
1104
1105/*
1106 * Condition Variable Attribute Functions
1107 */
1108PTW32_DLLPORT int PTW32_CDECL pthread_condattr_init (pthread_condattr_t * attr);
1109
1110PTW32_DLLPORT int PTW32_CDECL pthread_condattr_destroy (pthread_condattr_t * attr);
1111
1112PTW32_DLLPORT int PTW32_CDECL pthread_condattr_getpshared (const pthread_condattr_t * attr,
1113 int *pshared);
1114
1115PTW32_DLLPORT int PTW32_CDECL pthread_condattr_setpshared (pthread_condattr_t * attr,
1116 int pshared);
1117
1118/*
1119 * Condition Variable Functions
1120 */
1121PTW32_DLLPORT int PTW32_CDECL pthread_cond_init (pthread_cond_t * cond,
1122 const pthread_condattr_t * attr);
1123
1124PTW32_DLLPORT int PTW32_CDECL pthread_cond_destroy (pthread_cond_t * cond);
1125
1126PTW32_DLLPORT int PTW32_CDECL pthread_cond_wait (pthread_cond_t * cond,
1127 pthread_mutex_t * mutex);
1128
1129PTW32_DLLPORT int PTW32_CDECL pthread_cond_timedwait (pthread_cond_t * cond,
1130 pthread_mutex_t * mutex,
1131 const struct timespec *abstime);
1132
1133PTW32_DLLPORT int PTW32_CDECL pthread_cond_signal (pthread_cond_t * cond);
1134
1135PTW32_DLLPORT int PTW32_CDECL pthread_cond_broadcast (pthread_cond_t * cond);
1136
1137/*
1138 * Scheduling
1139 */
1140PTW32_DLLPORT int PTW32_CDECL pthread_setschedparam (pthread_t thread,
1141 int policy,
1142 const struct sched_param *param);
1143
1144PTW32_DLLPORT int PTW32_CDECL pthread_getschedparam (pthread_t thread,
1145 int *policy,
1146 struct sched_param *param);
1147
1148PTW32_DLLPORT int PTW32_CDECL pthread_setconcurrency (int);
1149
1150PTW32_DLLPORT int PTW32_CDECL pthread_getconcurrency (void);
1151
1152/*
1153 * Read-Write Lock Functions
1154 */
1155PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_init(pthread_rwlock_t *lock,
1156 const pthread_rwlockattr_t *attr);
1157
1158PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_destroy(pthread_rwlock_t *lock);
1159
1160PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_tryrdlock(pthread_rwlock_t *);
1161
1162PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_trywrlock(pthread_rwlock_t *);
1163
1164PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_rdlock(pthread_rwlock_t *lock);
1165
1166PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedrdlock(pthread_rwlock_t *lock,
1167 const struct timespec *abstime);
1168
1169PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_wrlock(pthread_rwlock_t *lock);
1170
1171PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedwrlock(pthread_rwlock_t *lock,
1172 const struct timespec *abstime);
1173
1174PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_unlock(pthread_rwlock_t *lock);
1175
1176PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_init (pthread_rwlockattr_t * attr);
1177
1178PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr);
1179
1180PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr,
1181 int *pshared);
1182
1183PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr,
1184 int pshared);
1185
1186#if PTW32_LEVEL >= PTW32_LEVEL_MAX - 1
1187
1188/*
1189 * Signal Functions. Should be defined in <signal.h> but MSVC and MinGW32
1190 * already have signal.h that don't define these.
1191 */
1192PTW32_DLLPORT int PTW32_CDECL pthread_kill(pthread_t thread, int sig);
1193
1194/*
1195 * Non-portable functions
1196 */
1197
1198/*
1199 * Compatibility with Linux.
1200 */
1201PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr,
1202 int kind);
1203PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr,
1204 int *kind);
1205PTW32_DLLPORT int PTW32_CDECL pthread_timedjoin_np(pthread_t thread,
1206 void **value_ptr,
1207 const struct timespec *abstime);
1208
1209/*
1210 * Possibly supported by other POSIX threads implementations
1211 */
1212PTW32_DLLPORT int PTW32_CDECL pthread_delay_np (struct timespec * interval);
1213PTW32_DLLPORT int PTW32_CDECL pthread_num_processors_np(void);
1214PTW32_DLLPORT unsigned __int64 PTW32_CDECL pthread_getunique_np(pthread_t thread);
1215
1216/*
1217 * Useful if an application wants to statically link
1218 * the lib rather than load the DLL at run-time.
1219 */
1220PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_attach_np(void);
1221PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_detach_np(void);
1222PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_attach_np(void);
1223PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_detach_np(void);
1224
1225/*
1226 * Features that are auto-detected at load/run time.
1227 */
1228PTW32_DLLPORT int PTW32_CDECL pthread_win32_test_features_np(int);
1229enum ptw32_features {
1230 PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE = 0x0001, /* System provides it. */
1231 PTW32_ALERTABLE_ASYNC_CANCEL = 0x0002 /* Can cancel blocked threads. */
1232};
1233
1234/*
1235 * Register a system time change with the library.
1236 * Causes the library to perform various functions
1237 * in response to the change. Should be called whenever
1238 * the application's top level window receives a
1239 * WM_TIMECHANGE message. It can be passed directly to
1240 * pthread_create() as a new thread if desired.
1241 */
1242PTW32_DLLPORT void * PTW32_CDECL pthread_timechange_handler_np(void *);
1243
1244#endif /*PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 */
1245
1246#if PTW32_LEVEL >= PTW32_LEVEL_MAX
1247
1248/*
1249 * Returns the Win32 HANDLE for the POSIX thread.
1250 */
1251PTW32_DLLPORT HANDLE PTW32_CDECL pthread_getw32threadhandle_np(pthread_t thread);
1252/*
1253 * Returns the win32 thread ID for POSIX thread.
1254 */
1255PTW32_DLLPORT DWORD PTW32_CDECL pthread_getw32threadid_np (pthread_t thread);
1256
1257
1258/*
1259 * Protected Methods
1260 *
1261 * This function blocks until the given WIN32 handle
1262 * is signaled or pthread_cancel had been called.
1263 * This function allows the caller to hook into the
1264 * PThreads cancel mechanism. It is implemented using
1265 *
1266 * WaitForMultipleObjects
1267 *
1268 * on 'waitHandle' and a manually reset WIN32 Event
1269 * used to implement pthread_cancel. The 'timeout'
1270 * argument to TimedWait is simply passed to
1271 * WaitForMultipleObjects.
1272 */
1273PTW32_DLLPORT int PTW32_CDECL pthreadCancelableWait (HANDLE waitHandle);
1274PTW32_DLLPORT int PTW32_CDECL pthreadCancelableTimedWait (HANDLE waitHandle,
1275 DWORD timeout);
1276
1277#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */
1278
1279/*
1280 * Thread-Safe C Runtime Library Mappings.
1281 */
1282#if !defined(_UWIN)
1283# if defined(NEED_ERRNO)
1284 PTW32_DLLPORT int * PTW32_CDECL _errno( void );
1285# else
1286# if !defined(errno)
1287# if (defined(_MT) || defined(_DLL))
1288 __declspec(dllimport) extern int * __cdecl _errno(void);
1289# define errno (*_errno())
1290# endif
1291# endif
1292# endif
1293#endif
1294
1295/*
1296 * Some compiler environments don't define some things.
1297 */
1298#if defined(__BORLANDC__)
1299# define _ftime ftime
1300# define _timeb timeb
1301#endif
1302
1303#if defined(__cplusplus)
1304
1305/*
1306 * Internal exceptions
1307 */
1308class ptw32_exception {};
1309class ptw32_exception_cancel : public ptw32_exception {};
1310class ptw32_exception_exit : public ptw32_exception {};
1311
1312#endif
1313
1314#if PTW32_LEVEL >= PTW32_LEVEL_MAX
1315
1316/* FIXME: This is only required if the library was built using SEH */
1317/*
1318 * Get internal SEH tag
1319 */
1320PTW32_DLLPORT DWORD PTW32_CDECL ptw32_get_exception_services_code(void);
1321
1322#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */
1323
1324#if !defined(PTW32_BUILD)
1325
1326#if defined(__CLEANUP_SEH)
1327
1328/*
1329 * Redefine the SEH __except keyword to ensure that applications
1330 * propagate our internal exceptions up to the library's internal handlers.
1331 */
1332#define __except( E ) \
1333 __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \
1334 ? EXCEPTION_CONTINUE_SEARCH : ( E ) )
1335
1336#endif /* __CLEANUP_SEH */
1337
1338#if defined(__CLEANUP_CXX)
1339
1340/*
1341 * Redefine the C++ catch keyword to ensure that applications
1342 * propagate our internal exceptions up to the library's internal handlers.
1343 */
1344#if defined(_MSC_VER)
1345 /*
1346 * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll'
1347 * if you want Pthread-Win32 cancellation and pthread_exit to work.
1348 */
1349
1350#if !defined(PtW32NoCatchWarn)
1351
1352#pragma message("Specify \"/DPtW32NoCatchWarn\" compiler flag to skip this message.")
1353#pragma message("------------------------------------------------------------------")
1354#pragma message("When compiling applications with MSVC++ and C++ exception handling:")
1355#pragma message(" Replace any 'catch( ... )' in routines called from POSIX threads")
1356#pragma message(" with 'PtW32CatchAll' or 'CATCHALL' if you want POSIX thread")
1357#pragma message(" cancellation and pthread_exit to work. For example:")
1358#pragma message("")
1359#pragma message(" #if defined(PtW32CatchAll)")
1360#pragma message(" PtW32CatchAll")
1361#pragma message(" #else")
1362#pragma message(" catch(...)")
1363#pragma message(" #endif")
1364#pragma message(" {")
1365#pragma message(" /* Catchall block processing */")
1366#pragma message(" }")
1367#pragma message("------------------------------------------------------------------")
1368
1369#endif
1370
1371#define PtW32CatchAll \
1372 catch( ptw32_exception & ) { throw; } \
1373 catch( ... )
1374
1375#else /* _MSC_VER */
1376
1377#define catch( E ) \
1378 catch( ptw32_exception & ) { throw; } \
1379 catch( E )
1380
1381#endif /* _MSC_VER */
1382
1383#endif /* __CLEANUP_CXX */
1384
1385#endif /* ! PTW32_BUILD */
1386
1387#if defined(__cplusplus)
1388} /* End of extern "C" */
1389#endif /* __cplusplus */
1390
1391#if defined(PTW32__HANDLE_DEF)
1392# undef HANDLE
1393#endif
1394#if defined(PTW32__DWORD_DEF)
1395# undef DWORD
1396#endif
1397
1398#undef PTW32_LEVEL
1399#undef PTW32_LEVEL_MAX
1400
1401#endif /* ! RC_INVOKED */
1402
1403#endif /* PTHREAD_H */
libraries/shared/external/sched.h+0−189
@@ -1,189 +0,0 @@
1/*
2 * Module: sched.h
3 *
4 * Purpose:
5 * Provides an implementation of POSIX realtime extensions
6 * as defined in
7 *
8 * POSIX 1003.1b-1993 (POSIX.1b)
9 *
10 * --------------------------------------------------------------------------
11 *
12 * Pthreads-win32 - POSIX Threads Library for Win32
13 * Copyright(C) 1998 John E. Bossom
14 * Copyright(C) 1999,2005 Pthreads-win32 contributors
15 *
16 * Contact Email: rpj@callisto.canberra.edu.au
17 *
18 * The current list of contributors is contained
19 * in the file CONTRIBUTORS included with the source
20 * code distribution. The list can also be seen at the
21 * following World Wide Web location:
22 * http://sources.redhat.com/pthreads-win32/contributors.html
23 *
24 * This library is free software; you can redistribute it and/or
25 * modify it under the terms of the GNU Lesser General Public
26 * License as published by the Free Software Foundation; either
27 * version 2 of the License, or (at your option) any later version.
28 *
29 * This library is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
32 * Lesser General Public License for more details.
33 *
34 * You should have received a copy of the GNU Lesser General Public
35 * License along with this library in the file COPYING.LIB;
36 * if not, write to the Free Software Foundation, Inc.,
37 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
38 */
39#if !defined(_SCHED_H)
40#define _SCHED_H
41
42#undef PTW32_SCHED_LEVEL
43
44#if defined(_POSIX_SOURCE)
45#define PTW32_SCHED_LEVEL 0
46/* Early POSIX */
47#endif
48
49#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309
50#undef PTW32_SCHED_LEVEL
51#define PTW32_SCHED_LEVEL 1
52/* Include 1b, 1c and 1d */
53#endif
54
55#if defined(INCLUDE_NP)
56#undef PTW32_SCHED_LEVEL
57#define PTW32_SCHED_LEVEL 2
58/* Include Non-Portable extensions */
59#endif
60
61#define PTW32_SCHED_LEVEL_MAX 3
62
63#if ( defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112 ) || !defined(PTW32_SCHED_LEVEL)
64#define PTW32_SCHED_LEVEL PTW32_SCHED_LEVEL_MAX
65/* Include everything */
66#endif
67
68
69#if defined(__GNUC__) && !defined(__declspec)
70# error Please upgrade your GNU compiler to one that supports __declspec.
71#endif
72
73/*
74 * When building the library, you should define PTW32_BUILD so that
75 * the variables/functions are exported correctly. When using the library,
76 * do NOT define PTW32_BUILD, and then the variables/functions will
77 * be imported correctly.
78 */
79#if !defined(PTW32_STATIC_LIB)
80# if defined(PTW32_BUILD)
81# define PTW32_DLLPORT __declspec (dllexport)
82# else
83# define PTW32_DLLPORT __declspec (dllimport)
84# endif
85#else
86# define PTW32_DLLPORT
87#endif
88
89/*
90 * This is a duplicate of what is in the autoconf config.h,
91 * which is only used when building the pthread-win32 libraries.
92 */
93
94#if !defined(PTW32_CONFIG_H)
95# if defined(WINCE)
96# define NEED_ERRNO
97# define NEED_SEM
98# endif
99# if defined(__MINGW64__)
100# define HAVE_STRUCT_TIMESPEC
101# define HAVE_MODE_T
102# elif defined(_UWIN) || defined(__MINGW32__)
103# define HAVE_MODE_T
104# endif
105#endif
106
107/*
108 *
109 */
110
111#if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX
112#if defined(NEED_ERRNO)
113#include "need_errno.h"
114#else
115#include <errno.h>
116#endif
117#endif /* PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX */
118
119#if (defined(__MINGW64__) || defined(__MINGW32__)) || defined(_UWIN)
120# if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX
121/* For pid_t */
122# include <sys/types.h>
123/* Required by Unix 98 */
124# include <time.h>
125# else
126 typedef int pid_t;
127# endif
128#else
129 /* [i_a] fix for using pthread_win32 with mongoose code, which #define's its own pid_t akin to typedef HANDLE pid_t; */
130 #undef pid_t
131# if defined(_MSC_VER)
132 typedef void *pid_t;
133# else
134 typedef int pid_t;
135# endif
136#endif
137
138/* Thread scheduling policies */
139
140enum {
141 SCHED_OTHER = 0,
142 SCHED_FIFO,
143 SCHED_RR,
144 SCHED_MIN = SCHED_OTHER,
145 SCHED_MAX = SCHED_RR
146};
147
148struct sched_param {
149 int sched_priority;
150};
151
152#if defined(__cplusplus)
153extern "C"
154{
155#endif /* __cplusplus */
156
157PTW32_DLLPORT int __cdecl sched_yield (void);
158
159PTW32_DLLPORT int __cdecl sched_get_priority_min (int policy);
160
161PTW32_DLLPORT int __cdecl sched_get_priority_max (int policy);
162
163PTW32_DLLPORT int __cdecl sched_setscheduler (pid_t pid, int policy);
164
165PTW32_DLLPORT int __cdecl sched_getscheduler (pid_t pid);
166
167/*
168 * Note that this macro returns ENOTSUP rather than
169 * ENOSYS as might be expected. However, returning ENOSYS
170 * should mean that sched_get_priority_{min,max} are
171 * not implemented as well as sched_rr_get_interval.
172 * This is not the case, since we just don't support
173 * round-robin scheduling. Therefore I have chosen to
174 * return the same value as sched_setscheduler when
175 * SCHED_RR is passed to it.
176 */
177#define sched_rr_get_interval(_pid, _interval) \
178 ( errno = ENOTSUP, (int) -1 )
179
180
181#if defined(__cplusplus)
182} /* End of extern "C" */
183#endif /* __cplusplus */
184
185#undef PTW32_SCHED_LEVEL
186#undef PTW32_SCHED_LEVEL_MAX
187
188#endif /* !_SCHED_H */
189
libraries/shared/src/AngularConstraint.cpp+2−1
@@ -11,8 +11,9 @@ · 10 unmodified lines
11 11
12#include <glm/gtx/norm.hpp>12#include <glm/gtx/norm.hpp>
13 13
14#include "GLMHelpers.h"
15
14#include "AngularConstraint.h"16#include "AngularConstraint.h"
15#include "SharedUtil.h"
16 17
17// helper function18// helper function
18/// \param angle radian angle to be clamped within angleMin and angleMax19/// \param angle radian angle to be clamped within angleMin and angleMax
libraries/shared/src/AngularConstraint.h+0−1
@@ -14,7 +14,6 @@ · 13 unmodified lines
14 14
15#include <glm/glm.hpp>15#include <glm/glm.hpp>
16 16
17
18class AngularConstraint {17class AngularConstraint {
19public:18public:
20 /// \param minAngles minumum euler angles for the constraint19 /// \param minAngles minumum euler angles for the constraint
libraries/shared/src/ContactPoint.cpp+108−72
@@ -13,56 +13,128 @@ · 12 unmodified lines
13#include "Shape.h"13#include "Shape.h"
14#include "SharedUtil.h"14#include "SharedUtil.h"
15 15
16ContactPoint::ContactPoint() : _lastFrame(0), _shapeA(NULL), _shapeB(NULL), 16// This parameter helps keep the actual point of contact slightly inside each shape
17 _offsetA(0.0f), _offsetB(0.0f), _normal(0.0f) {17// which allows the collisions to happen almost every frame for more frequent updates.
18const float CONTACT_PENETRATION_ALLOWANCE = 0.005f;
19
20ContactPoint::ContactPoint() :
21 _lastFrame(0), _shapeA(NULL), _shapeB(NULL),
22 _offsetA(0.0f), _offsetB(0.0f),
23 _relativeMassA(0.5f), _relativeMassB(0.5f),
24 _numPointsA(0), _numPoints(0), _normal(0.0f) {
18}25}
19 26
20ContactPoint::ContactPoint(const CollisionInfo& collision, quint32 frame) : _lastFrame(frame),27ContactPoint::ContactPoint(const CollisionInfo& collision, quint32 frame) :
21 _shapeA(collision.getShapeA()), _shapeB(collision.getShapeB()), _offsetA(0.0f), _offsetB(0.0f), 28 _lastFrame(frame), _shapeA(collision.getShapeA()), _shapeB(collision.getShapeB()),
29 _offsetA(0.0f), _offsetB(0.0f),
30 _relativeMassA(0.5f), _relativeMassB(0.5f),
22 _numPointsA(0), _numPoints(0), _normal(0.0f) {31 _numPointsA(0), _numPoints(0), _normal(0.0f) {
23 32
24 _contactPoint = collision._contactPoint - 0.5f * collision._penetration;33 glm::vec3 pointA = collision._contactPoint;
25 _offsetA = collision._contactPoint - _shapeA->getTranslation();34 glm::vec3 pointB = collision._contactPoint - collision._penetration;
26 _offsetB = collision._contactPoint - collision._penetration - _shapeB->getTranslation();35
27 float pLength = glm::length(collision._penetration);36 float pLength = glm::length(collision._penetration);
28 if (pLength > EPSILON) {37 if (pLength > EPSILON) {
29 _normal = collision._penetration / pLength;38 _normal = collision._penetration / pLength;
30 }39 }
31
32 if (_shapeA->getID() > _shapeB->getID()) {40 if (_shapeA->getID() > _shapeB->getID()) {
33 // swap so that _shapeA always has lower ID41 // swap so that _shapeA always has lower ID
34 _shapeA = collision.getShapeB();42 _shapeA = collision.getShapeB();
35 _shapeB = collision.getShapeA();43 _shapeB = collision.getShapeA();
36
37 glm::vec3 temp = _offsetA;
38 _offsetA = _offsetB;
39 _offsetB = temp;
40 _normal = - _normal;44 _normal = - _normal;
45 pointA = pointB;
46 pointB = collision._contactPoint;
41 }47 }
42 48
49 // bring the contact points inside the shapes to help maintain collision updates
50 pointA -= CONTACT_PENETRATION_ALLOWANCE * _normal;
51 pointB += CONTACT_PENETRATION_ALLOWANCE * _normal;
52
53 _offsetA = pointA - _shapeA->getTranslation();
54 _offsetB = pointB - _shapeB->getTranslation();
55
43 _shapeA->getVerletPoints(_points);56 _shapeA->getVerletPoints(_points);
44 _numPointsA = _points.size();57 _numPointsA = _points.size();
45 _shapeB->getVerletPoints(_points);58 _shapeB->getVerletPoints(_points);
46 _numPoints = _points.size();59 _numPoints = _points.size();
47 60
61 // compute and cache relative masses
62 float massA = EPSILON;
63 for (int i = 0; i < _numPointsA; ++i) {
64 massA += _points[i]->getMass();
65 }
66 float massB = EPSILON;
67 for (int i = _numPointsA; i < _numPoints; ++i) {
68 massB += _points[i]->getMass();
69 }
70 float invTotalMass = 1.0f / (massA + massB);
71 _relativeMassA = massA * invTotalMass;
72 _relativeMassB = massB * invTotalMass;
73
74 // _contactPoint will be the weighted average of the two
75 _contactPoint = _relativeMassA * pointA + _relativeMassB * pointB;
76
48 // compute offsets for shapeA77 // compute offsets for shapeA
49 for (int i = 0; i < _numPointsA; ++i) {78 for (int i = 0; i < _numPointsA; ++i) {
50 glm::vec3 offset = _points[i]->_position - collision._contactPoint;79 glm::vec3 offset = _points[i]->_position - pointA;
51 _offsets.push_back(offset);80 _offsets.push_back(offset);
52 _distances.push_back(glm::length(offset));81 _distances.push_back(glm::length(offset));
53 }82 }
54 // compute offsets for shapeB83 // compute offsets for shapeB
55 for (int i = _numPointsA; i < _numPoints; ++i) {84 for (int i = _numPointsA; i < _numPoints; ++i) {
56 glm::vec3 offset = _points[i]->_position - collision._contactPoint + collision._penetration;85 glm::vec3 offset = _points[i]->_position - pointB;
57 _offsets.push_back(offset);86 _offsets.push_back(offset);
58 _distances.push_back(glm::length(offset));87 _distances.push_back(glm::length(offset));
59 }88 }
60}89}
61 90
62// virtual
63float ContactPoint::enforce() {91float ContactPoint::enforce() {
64 int numPoints = _points.size();92 glm::vec3 pointA = _shapeA->getTranslation() + _offsetA;
65 for (int i = 0; i < numPoints; ++i) {93 glm::vec3 pointB = _shapeB->getTranslation() + _offsetB;
94 glm::vec3 penetration = pointA - pointB;
95 float pDotN = glm::dot(penetration, _normal);
96 bool constraintViolation = (pDotN > CONTACT_PENETRATION_ALLOWANCE);
97
98 // the contact point will be the average of the two points on the shapes
99 _contactPoint = 0.5f * (pointA + pointB);
100
101 if (constraintViolation) {
102 for (int i = 0; i < _numPoints; ++i) {
103 VerletPoint* point = _points[i];
104 glm::vec3 offset = _offsets[i];
105
106 // split delta into parallel and perpendicular components
107 glm::vec3 delta = _contactPoint + offset - point->_position;
108 glm::vec3 paraDelta = glm::dot(delta, _normal) * _normal;
109 glm::vec3 perpDelta = delta - paraDelta;
110
111 // use the relative sizes of the components to decide how much perpenducular delta to use
112 // perpendicular < parallel ==> static friction ==> perpFactor = 1.0
113 // perpendicular > parallel ==> dynamic friction ==> cap to length of paraDelta ==> perpFactor < 1.0
114 float paraLength = glm::length(paraDelta);
115 float perpLength = glm::length(perpDelta);
116 float perpFactor = (perpLength > paraLength && perpLength > EPSILON) ? (paraLength / perpLength) : 1.0f;
117
118 // recombine the two components to get the final delta
119 delta = paraDelta + perpFactor * perpDelta;
120
121 glm::vec3 targetPosition = point->_position + delta;
122 _distances[i] = glm::distance(_contactPoint, targetPosition);
123 point->_position += delta;
124 }
125 } else {
126 for (int i = 0; i < _numPoints; ++i) {
127 _distances[i] = glm::length(glm::length(_offsets[i]));
128 }
129 }
130 return 0.0f;
131}
132
133// virtual
134void ContactPoint::applyFriction() {
135 // TODO: Andrew to re-implement this in a different way
136 /*
137 for (int i = 0; i < _numPoints; ++i) {
66 glm::vec3& position = _points[i]->_position;138 glm::vec3& position = _points[i]->_position;
67 // TODO: use a fast distance approximation139 // TODO: use a fast distance approximation
68 float newDistance = glm::distance(_contactPoint, position);140 float newDistance = glm::distance(_contactPoint, position);
@@ -75,60 +147,17 @@ float ContactPoint::enforce() { · 6 unmodified lines
75 position = center - (0.5f * constrainedDistance) * direction;147 position = center - (0.5f * constrainedDistance) * direction;
76 }148 }
77 }149 }
78 return 0.0f;150 */
79}
80
81void ContactPoint::buildConstraints() {
82 glm::vec3 pointA = _shapeA->getTranslation() + _offsetA;
83 glm::vec3 pointB = _shapeB->getTranslation() + _offsetB;
84 glm::vec3 penetration = pointA - pointB;
85 float pDotN = glm::dot(penetration, _normal);
86 bool actuallyMovePoints = (pDotN > EPSILON);
87
88 // the contact point will be the average of the two points on the shapes
89 _contactPoint = 0.5f * (pointA + pointB);
90
91 // TODO: Andrew to compute more correct lagrangian weights that provide a more realistic response.
92 //
93 // HACK: since the weights are naively equal for all points (which is what the above TODO is about) we
94 // don't want to use the full-strength delta because otherwise there can be annoying oscillations. We
95 // reduce this problem by in the short-term by attenuating the delta that is applied, the tradeoff is
96 // that this makes it easier for limbs to tunnel through during collisions.
97 const float HACK_STRENGTH = 0.5f;
98
99 int numPoints = _points.size();
100 for (int i = 0; i < numPoints; ++i) {
101 VerletPoint* point = _points[i];
102 glm::vec3 offset = _offsets[i];
103
104 // split delta into parallel and perpendicular components
105 glm::vec3 delta = _contactPoint + offset - point->_position;
106 glm::vec3 paraDelta = glm::dot(delta, _normal) * _normal;
107 glm::vec3 perpDelta = delta - paraDelta;
108
109 // use the relative sizes of the components to decide how much perpenducular delta to use
110 // perpendicular < parallel ==> static friciton ==> perpFactor = 1.0
111 // perpendicular > parallel ==> dynamic friciton ==> cap to length of paraDelta ==> perpFactor < 1.0
112 float paraLength = glm::length(paraDelta);
113 float perpLength = glm::length(perpDelta);
114 float perpFactor = (perpLength > paraLength && perpLength > EPSILON) ? (paraLength / perpLength) : 1.0f;
115
116 // recombine the two components to get the final delta
117 delta = paraDelta + perpFactor * perpDelta;
118
119 glm::vec3 targetPosition = point->_position + delta;
120 _distances[i] = glm::distance(_contactPoint, targetPosition);
121 if (actuallyMovePoints) {
122 point->_position += HACK_STRENGTH * delta;
123 }
124 }
125}151}
126 152
127void ContactPoint::updateContact(const CollisionInfo& collision, quint32 frame) {153void ContactPoint::updateContact(const CollisionInfo& collision, quint32 frame) {
128 _lastFrame = frame;154 _lastFrame = frame;
129 _contactPoint = collision._contactPoint - 0.5f * collision._penetration;155
130 _offsetA = collision._contactPoint - collision._shapeA->getTranslation();156 // compute contact points on surface of each shape
131 _offsetB = collision._contactPoint - collision._penetration - collision._shapeB->getTranslation();157 glm::vec3 pointA = collision._contactPoint;
158 glm::vec3 pointB = pointA - collision._penetration;
159
160 // compute the normal (which points from A into B)
132 float pLength = glm::length(collision._penetration);161 float pLength = glm::length(collision._penetration);
133 if (pLength > EPSILON) {162 if (pLength > EPSILON) {
134 _normal = collision._penetration / pLength;163 _normal = collision._penetration / pLength;
@@ -138,19 +167,26 @@ void ContactPoint::updateContact(const CollisionInfo& collision, quint32 frame) · 3 unmodified lines
138 167
139 if (collision._shapeA->getID() > collision._shapeB->getID()) {168 if (collision._shapeA->getID() > collision._shapeB->getID()) {
140 // our _shapeA always has lower ID169 // our _shapeA always has lower ID
141 glm::vec3 temp = _offsetA;
142 _offsetA = _offsetB;
143 _offsetB = temp;
144 _normal = - _normal;170 _normal = - _normal;
171 pointA = pointB;
172 pointB = collision._contactPoint;
145 }173 }
174
175 // bring the contact points inside the shapes to help maintain collision updates
176 pointA -= CONTACT_PENETRATION_ALLOWANCE * _normal;
177 pointB += CONTACT_PENETRATION_ALLOWANCE * _normal;
178
179 // compute relative offsets to per-shape contact points
180 _offsetA = pointA - collision._shapeA->getTranslation();
181 _offsetB = pointB - collision._shapeB->getTranslation();
146 182
147 // compute offsets for shapeA183 // compute offsets for shapeA
148 assert(_offsets.size() == _numPoints);184 assert(_offsets.size() == _numPoints);
149 for (int i = 0; i < _numPointsA; ++i) {185 for (int i = 0; i < _numPointsA; ++i) {
150 _offsets[i] = (_points[i]->_position - collision._contactPoint);186 _offsets[i] = _points[i]->_position - pointA;
151 }187 }
152 // compute offsets for shapeB188 // compute offsets for shapeB
153 for (int i = _numPointsA; i < _numPoints; ++i) {189 for (int i = _numPointsA; i < _numPoints; ++i) {
154 _offsets[i] = (_points[i]->_position - collision._contactPoint + collision._penetration);190 _offsets[i] = _points[i]->_position - pointB;
155 }191 }
156}192}
libraries/shared/src/ContactPoint.h+4−2
@@ -26,8 +26,8 @@ public: · 25 unmodified lines
26 ContactPoint(const CollisionInfo& collision, quint32 frame);26 ContactPoint(const CollisionInfo& collision, quint32 frame);
27 27
28 virtual float enforce();28 virtual float enforce();
29 29
30 void buildConstraints();30 void applyFriction();
31 void updateContact(const CollisionInfo& collision, quint32 frame);31 void updateContact(const CollisionInfo& collision, quint32 frame);
32 quint32 getLastFrame() const { return _lastFrame; }32 quint32 getLastFrame() const { return _lastFrame; }
33 33
@@ -41,6 +41,8 @@ protected: · 7 unmodified lines
41 glm::vec3 _offsetA; // contact point relative to A's center41 glm::vec3 _offsetA; // contact point relative to A's center
42 glm::vec3 _offsetB; // contact point relative to B's center42 glm::vec3 _offsetB; // contact point relative to B's center
43 glm::vec3 _contactPoint; // a "virtual" point that is added to the simulation43 glm::vec3 _contactPoint; // a "virtual" point that is added to the simulation
44 float _relativeMassA; // massA / totalMass
45 float _relativeMassB; // massB / totalMass
44 int _numPointsA; // number of VerletPoints that belong to _shapeA46 int _numPointsA; // number of VerletPoints that belong to _shapeA
45 int _numPoints; // total number of VerletPoints47 int _numPoints; // total number of VerletPoints
46 QVector<VerletPoint*> _points; // points that belong to colliding shapes48 QVector<VerletPoint*> _points; // points that belong to colliding shapes
libraries/shared/src/GLMHelpers.cpp+299−0
@@ -0,0 +1,299 @@
1//
2// GLMHelpers.cpp
3// libraries/shared/src
4//
5// Created by Stephen Birarda on 2014-08-07.
6// Copyright 2014 High Fidelity, Inc.
7//
8// Distributed under the Apache License, Version 2.0.
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//
11
12#include "GLMHelpers.h"
13
14// Safe version of glm::mix; based on the code in Nick Bobick's article,
15// http://www.gamasutra.com/features/19980703/quaternions_01.htm (via Clyde,
16// https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java)
17glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float proportion) {
18 float cosa = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
19 float ox = q2.x, oy = q2.y, oz = q2.z, ow = q2.w, s0, s1;
20
21 // adjust signs if necessary
22 if (cosa < 0.0f) {
23 cosa = -cosa;
24 ox = -ox;
25 oy = -oy;
26 oz = -oz;
27 ow = -ow;
28 }
29
30 // calculate coefficients; if the angle is too close to zero, we must fall back
31 // to linear interpolation
32 if ((1.0f - cosa) > EPSILON) {
33 float angle = acosf(cosa), sina = sinf(angle);
34 s0 = sinf((1.0f - proportion) * angle) / sina;
35 s1 = sinf(proportion * angle) / sina;
36
37 } else {
38 s0 = 1.0f - proportion;
39 s1 = proportion;
40 }
41
42 return glm::normalize(glm::quat(s0 * q1.w + s1 * ow, s0 * q1.x + s1 * ox, s0 * q1.y + s1 * oy, s0 * q1.z + s1 * oz));
43}
44
45// Allows sending of fixed-point numbers: radix 1 makes 15.1 number, radix 8 makes 8.8 number, etc
46int packFloatScalarToSignedTwoByteFixed(unsigned char* buffer, float scalar, int radix) {
47 int16_t outVal = (int16_t)(scalar * (float)(1 << radix));
48 memcpy(buffer, &outVal, sizeof(uint16_t));
49 return sizeof(uint16_t);
50}
51
52int unpackFloatScalarFromSignedTwoByteFixed(const int16_t* byteFixedPointer, float* destinationPointer, int radix) {
53 *destinationPointer = *byteFixedPointer / (float)(1 << radix);
54 return sizeof(int16_t);
55}
56
57int packFloatVec3ToSignedTwoByteFixed(unsigned char* destBuffer, const glm::vec3& srcVector, int radix) {
58 const unsigned char* startPosition = destBuffer;
59 destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.x, radix);
60 destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.y, radix);
61 destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.z, radix);
62 return destBuffer - startPosition;
63}
64
65int unpackFloatVec3FromSignedTwoByteFixed(const unsigned char* sourceBuffer, glm::vec3& destination, int radix) {
66 const unsigned char* startPosition = sourceBuffer;
67 sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.x), radix);
68 sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.y), radix);
69 sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.z), radix);
70 return sourceBuffer - startPosition;
71}
72
73
74int packFloatAngleToTwoByte(unsigned char* buffer, float degrees) {
75 const float ANGLE_CONVERSION_RATIO = (std::numeric_limits<uint16_t>::max() / 360.f);
76
77 uint16_t angleHolder = floorf((degrees + 180.f) * ANGLE_CONVERSION_RATIO);
78 memcpy(buffer, &angleHolder, sizeof(uint16_t));
79
80 return sizeof(uint16_t);
81}
82
83int unpackFloatAngleFromTwoByte(const uint16_t* byteAnglePointer, float* destinationPointer) {
84 *destinationPointer = (*byteAnglePointer / (float) std::numeric_limits<uint16_t>::max()) * 360.f - 180.f;
85 return sizeof(uint16_t);
86}
87
88int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput) {
89 const float QUAT_PART_CONVERSION_RATIO = (std::numeric_limits<uint16_t>::max() / 2.f);
90 uint16_t quatParts[4];
91 quatParts[0] = floorf((quatInput.x + 1.f) * QUAT_PART_CONVERSION_RATIO);
92 quatParts[1] = floorf((quatInput.y + 1.f) * QUAT_PART_CONVERSION_RATIO);
93 quatParts[2] = floorf((quatInput.z + 1.f) * QUAT_PART_CONVERSION_RATIO);
94 quatParts[3] = floorf((quatInput.w + 1.f) * QUAT_PART_CONVERSION_RATIO);
95
96 memcpy(buffer, &quatParts, sizeof(quatParts));
97 return sizeof(quatParts);
98}
99
100int unpackOrientationQuatFromBytes(const unsigned char* buffer, glm::quat& quatOutput) {
101 uint16_t quatParts[4];
102 memcpy(&quatParts, buffer, sizeof(quatParts));
103
104 quatOutput.x = ((quatParts[0] / (float) std::numeric_limits<uint16_t>::max()) * 2.f) - 1.f;
105 quatOutput.y = ((quatParts[1] / (float) std::numeric_limits<uint16_t>::max()) * 2.f) - 1.f;
106 quatOutput.z = ((quatParts[2] / (float) std::numeric_limits<uint16_t>::max()) * 2.f) - 1.f;
107 quatOutput.w = ((quatParts[3] / (float) std::numeric_limits<uint16_t>::max()) * 2.f) - 1.f;
108
109 return sizeof(quatParts);
110}
111
112// Safe version of glm::eulerAngles; uses the factorization method described in David Eberly's
113// http://www.geometrictools.com/Documentation/EulerAngles.pdf (via Clyde,
114// https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java)
115glm::vec3 safeEulerAngles(const glm::quat& q) {
116 float sy = 2.0f * (q.y * q.w - q.x * q.z);
117 glm::vec3 eulers;
118 if (sy < 1.0f - EPSILON) {
119 if (sy > -1.0f + EPSILON) {
120 eulers = glm::vec3(
121 atan2f(q.y * q.z + q.x * q.w, 0.5f - (q.x * q.x + q.y * q.y)),
122 asinf(sy),
123 atan2f(q.x * q.y + q.z * q.w, 0.5f - (q.y * q.y + q.z * q.z)));
124
125 } else {
126 // not a unique solution; x + z = atan2(-m21, m11)
127 eulers = glm::vec3(
128 0.0f,
129 - PI_OVER_TWO,
130 atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z)));
131 }
132 } else {
133 // not a unique solution; x - z = atan2(-m21, m11)
134 eulers = glm::vec3(
135 0.0f,
136 PI_OVER_TWO,
137 -atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z)));
138 }
139
140 // adjust so that z, rather than y, is in [-pi/2, pi/2]
141 if (eulers.z < -PI_OVER_TWO) {
142 if (eulers.x < 0.0f) {
143 eulers.x += PI;
144 } else {
145 eulers.x -= PI;
146 }
147 eulers.y = -eulers.y;
148 if (eulers.y < 0.0f) {
149 eulers.y += PI;
150 } else {
151 eulers.y -= PI;
152 }
153 eulers.z += PI;
154
155 } else if (eulers.z > PI_OVER_TWO) {
156 if (eulers.x < 0.0f) {
157 eulers.x += PI;
158 } else {
159 eulers.x -= PI;
160 }
161 eulers.y = -eulers.y;
162 if (eulers.y < 0.0f) {
163 eulers.y += PI;
164 } else {
165 eulers.y -= PI;
166 }
167 eulers.z -= PI;
168 }
169 return eulers;
170}
171
172// Helper function returns the positive angle (in radians) between two 3D vectors
173float angleBetween(const glm::vec3& v1, const glm::vec3& v2) {
174 return acosf((glm::dot(v1, v2)) / (glm::length(v1) * glm::length(v2)));
175}
176
177// Helper function return the rotation from the first vector onto the second
178glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) {
179 float angle = angleBetween(v1, v2);
180 if (glm::isnan(angle) || angle < EPSILON) {
181 return glm::quat();
182 }
183 glm::vec3 axis;
184 if (angle > 179.99f * RADIANS_PER_DEGREE) { // 180 degree rotation; must use another axis
185 axis = glm::cross(v1, glm::vec3(1.0f, 0.0f, 0.0f));
186 float axisLength = glm::length(axis);
187 if (axisLength < EPSILON) { // parallel to x; y will work
188 axis = glm::normalize(glm::cross(v1, glm::vec3(0.0f, 1.0f, 0.0f)));
189 } else {
190 axis /= axisLength;
191 }
192 } else {
193 axis = glm::normalize(glm::cross(v1, v2));
194 // It is possible for axis to be nan even when angle is not less than EPSILON.
195 // For example when angle is small but not tiny but v1 and v2 and have very short lengths.
196 if (glm::isnan(glm::dot(axis, axis))) {
197 // set angle and axis to values that will generate an identity rotation
198 angle = 0.0f;
199 axis = glm::vec3(1.0f, 0.0f, 0.0f);
200 }
201 }
202 return glm::angleAxis(angle, axis);
203}
204
205glm::vec3 extractTranslation(const glm::mat4& matrix) {
206 return glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]);
207}
208
209void setTranslation(glm::mat4& matrix, const glm::vec3& translation) {
210 matrix[3][0] = translation.x;
211 matrix[3][1] = translation.y;
212 matrix[3][2] = translation.z;
213}
214
215glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) {
216 // uses the iterative polar decomposition algorithm described by Ken Shoemake at
217 // http://www.cs.wisc.edu/graphics/Courses/838-s2002/Papers/polar-decomp.pdf
218 // code adapted from Clyde, https://github.com/threerings/clyde/blob/master/core/src/main/java/com/threerings/math/Matrix4f.java
219 // start with the contents of the upper 3x3 portion of the matrix
220 glm::mat3 upper = glm::mat3(matrix);
221 if (!assumeOrthogonal) {
222 for (int i = 0; i < 10; i++) {
223 // store the results of the previous iteration
224 glm::mat3 previous = upper;
225
226 // compute average of the matrix with its inverse transpose
227 float sd00 = previous[1][1] * previous[2][2] - previous[2][1] * previous[1][2];
228 float sd10 = previous[0][1] * previous[2][2] - previous[2][1] * previous[0][2];
229 float sd20 = previous[0][1] * previous[1][2] - previous[1][1] * previous[0][2];
230 float det = previous[0][0] * sd00 + previous[2][0] * sd20 - previous[1][0] * sd10;
231 if (fabs(det) == 0.0f) {
232 // determinant is zero; matrix is not invertible
233 break;
234 }
235 float hrdet = 0.5f / det;
236 upper[0][0] = +sd00 * hrdet + previous[0][0] * 0.5f;
237 upper[1][0] = -sd10 * hrdet + previous[1][0] * 0.5f;
238 upper[2][0] = +sd20 * hrdet + previous[2][0] * 0.5f;
239
240 upper[0][1] = -(previous[1][0] * previous[2][2] - previous[2][0] * previous[1][2]) * hrdet + previous[0][1] * 0.5f;
241 upper[1][1] = +(previous[0][0] * previous[2][2] - previous[2][0] * previous[0][2]) * hrdet + previous[1][1] * 0.5f;
242 upper[2][1] = -(previous[0][0] * previous[1][2] - previous[1][0] * previous[0][2]) * hrdet + previous[2][1] * 0.5f;
243
244 upper[0][2] = +(previous[1][0] * previous[2][1] - previous[2][0] * previous[1][1]) * hrdet + previous[0][2] * 0.5f;
245 upper[1][2] = -(previous[0][0] * previous[2][1] - previous[2][0] * previous[0][1]) * hrdet + previous[1][2] * 0.5f;
246 upper[2][2] = +(previous[0][0] * previous[1][1] - previous[1][0] * previous[0][1]) * hrdet + previous[2][2] * 0.5f;
247
248 // compute the difference; if it's small enough, we're done
249 glm::mat3 diff = upper - previous;
250 if (diff[0][0] * diff[0][0] + diff[1][0] * diff[1][0] + diff[2][0] * diff[2][0] + diff[0][1] * diff[0][1] +
251 diff[1][1] * diff[1][1] + diff[2][1] * diff[2][1] + diff[0][2] * diff[0][2] + diff[1][2] * diff[1][2] +
252 diff[2][2] * diff[2][2] < EPSILON) {
253 break;
254 }
255 }
256 }
257
258 // now that we have a nice orthogonal matrix, we can extract the rotation quaternion
259 // using the method described in http://en.wikipedia.org/wiki/Rotation_matrix#Conversions
260 float x2 = fabs(1.0f + upper[0][0] - upper[1][1] - upper[2][2]);
261 float y2 = fabs(1.0f - upper[0][0] + upper[1][1] - upper[2][2]);
262 float z2 = fabs(1.0f - upper[0][0] - upper[1][1] + upper[2][2]);
263 float w2 = fabs(1.0f + upper[0][0] + upper[1][1] + upper[2][2]);
264 return glm::normalize(glm::quat(0.5f * sqrtf(w2),
265 0.5f * sqrtf(x2) * (upper[1][2] >= upper[2][1] ? 1.0f : -1.0f),
266 0.5f * sqrtf(y2) * (upper[2][0] >= upper[0][2] ? 1.0f : -1.0f),
267 0.5f * sqrtf(z2) * (upper[0][1] >= upper[1][0] ? 1.0f : -1.0f)));
268}
269
270glm::vec3 extractScale(const glm::mat4& matrix) {
271 return glm::vec3(glm::length(matrix[0]), glm::length(matrix[1]), glm::length(matrix[2]));
272}
273
274float extractUniformScale(const glm::mat4& matrix) {
275 return extractUniformScale(extractScale(matrix));
276}
277
278float extractUniformScale(const glm::vec3& scale) {
279 return (scale.x + scale.y + scale.z) / 3.0f;
280}
281
282QByteArray createByteArray(const glm::vec3& vector) {
283 return QByteArray::number(vector.x) + ',' + QByteArray::number(vector.y) + ',' + QByteArray::number(vector.z);
284}
285
286bool isSimilarOrientation(const glm::quat& orientionA, const glm::quat& orientionB, float similarEnough) {
287 // Compute the angular distance between the two orientations
288 float angleOrientation = orientionA == orientionB ? 0.0f : glm::degrees(glm::angle(orientionA * glm::inverse(orientionB)));
289 if (isNaN(angleOrientation)) {
290 angleOrientation = 0.0f;
291 }
292 return (angleOrientation <= similarEnough);
293}
294
295bool isSimilarPosition(const glm::vec3& positionA, const glm::vec3& positionB, float similarEnough) {
296 // Compute the distance between the two points
297 float positionDistance = glm::distance(positionA, positionB);
298 return (positionDistance <= similarEnough);
299}
libraries/shared/src/GLMHelpers.h+89−0
@@ -0,0 +1,89 @@
1//
2// GLMHelpers.h
3// libraries/shared/src
4//
5// Created by Stephen Birarda on 2014-08-07.
6// Copyright 2014 High Fidelity, Inc.
7//
8// Distributed under the Apache License, Version 2.0.
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//
11
12#ifndef hifi_GLMHelpers_h
13#define hifi_GLMHelpers_h
14
15#include <stdint.h>
16
17#include <glm/glm.hpp>
18#include <glm/gtc/quaternion.hpp>
19
20#include <QtCore/QByteArray>
21
22#include "SharedUtil.h"
23
24glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha);
25
26// These pack/unpack functions are designed to start specific known types in as efficient a manner
27// as possible. Taking advantage of the known characteristics of the semantic types.
28
29// Angles are known to be between 0 and 360 degrees, this allows us to encode in 16bits with great accuracy
30int packFloatAngleToTwoByte(unsigned char* buffer, float degrees);
31int unpackFloatAngleFromTwoByte(const uint16_t* byteAnglePointer, float* destinationPointer);
32
33// Orientation Quats are known to have 4 normalized components be between -1.0 and 1.0
34// this allows us to encode each component in 16bits with great accuracy
35int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput);
36int unpackOrientationQuatFromBytes(const unsigned char* buffer, glm::quat& quatOutput);
37
38// Ratios need the be highly accurate when less than 10, but not very accurate above 10, and they
39// are never greater than 1000 to 1, this allows us to encode each component in 16bits
40int packFloatRatioToTwoByte(unsigned char* buffer, float ratio);
41int unpackFloatRatioFromTwoByte(const unsigned char* buffer, float& ratio);
42
43// Near/Far Clip values need the be highly accurate when less than 10, but only integer accuracy above 10 and
44// they are never greater than 16,000, this allows us to encode each component in 16bits
45int packClipValueToTwoByte(unsigned char* buffer, float clipValue);
46int unpackClipValueFromTwoByte(const unsigned char* buffer, float& clipValue);
47
48// Positive floats that don't need to be very precise
49int packFloatToByte(unsigned char* buffer, float value, float scaleBy);
50int unpackFloatFromByte(const unsigned char* buffer, float& value, float scaleBy);
51
52// Allows sending of fixed-point numbers: radix 1 makes 15.1 number, radix 8 makes 8.8 number, etc
53int packFloatScalarToSignedTwoByteFixed(unsigned char* buffer, float scalar, int radix);
54int unpackFloatScalarFromSignedTwoByteFixed(const int16_t* byteFixedPointer, float* destinationPointer, int radix);
55
56// A convenience for sending vec3's as fixed-point floats
57int packFloatVec3ToSignedTwoByteFixed(unsigned char* destBuffer, const glm::vec3& srcVector, int radix);
58int unpackFloatVec3FromSignedTwoByteFixed(const unsigned char* sourceBuffer, glm::vec3& destination, int radix);
59
60/// \return vec3 with euler angles in radians
61glm::vec3 safeEulerAngles(const glm::quat& q);
62
63float angleBetween(const glm::vec3& v1, const glm::vec3& v2);
64
65glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2);
66
67glm::vec3 extractTranslation(const glm::mat4& matrix);
68
69void setTranslation(glm::mat4& matrix, const glm::vec3& translation);
70
71glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal = false);
72
73glm::vec3 extractScale(const glm::mat4& matrix);
74
75float extractUniformScale(const glm::mat4& matrix);
76
77float extractUniformScale(const glm::vec3& scale);
78
79QByteArray createByteArray(const glm::vec3& vector);
80
81/// \return bool are two orientations similar to each other
82const float ORIENTATION_SIMILAR_ENOUGH = 5.0f; // 10 degrees in any direction
83bool isSimilarOrientation(const glm::quat& orientionA, const glm::quat& orientionB,
84 float similarEnough = ORIENTATION_SIMILAR_ENOUGH);
85const float POSITION_SIMILAR_ENOUGH = 0.1f; // 0.1 meter
86bool isSimilarPosition(const glm::vec3& positionA, const glm::vec3& positionB, float similarEnough = POSITION_SIMILAR_ENOUGH);
87
88
89#endif // hifi_GLMHelpers_h
libraries/shared/src/MovingMinMaxAvg.h+1−0
@@ -12,6 +12,7 @@ · 11 unmodified lines
12#ifndef hifi_MovingMinMaxAvg_h12#ifndef hifi_MovingMinMaxAvg_h
13#define hifi_MovingMinMaxAvg_h13#define hifi_MovingMinMaxAvg_h
14 14
15#include <cassert>
15#include <limits>16#include <limits>
16 17
17#include "RingBufferHistory.h"18#include "RingBufferHistory.h"
libraries/shared/src/PhysicsSimulation.cpp+20−20
@@ -47,12 +47,12 @@ PhysicsSimulation::~PhysicsSimulation() { · 46 unmodified lines
47void PhysicsSimulation::setRagdoll(Ragdoll* ragdoll) { 47void PhysicsSimulation::setRagdoll(Ragdoll* ragdoll) {
48 if (_ragdoll != ragdoll) {48 if (_ragdoll != ragdoll) {
49 if (_ragdoll) {49 if (_ragdoll) {
50 _ragdoll->_ragdollSimulation = NULL;50 _ragdoll->_simulation = NULL;
51 }51 }
52 _ragdoll = ragdoll;52 _ragdoll = ragdoll;
53 if (_ragdoll) {53 if (_ragdoll) {
54 assert(!(_ragdoll->_ragdollSimulation));54 assert(!(_ragdoll->_simulation));
55 _ragdoll->_ragdollSimulation = this;55 _ragdoll->_simulation = this;
56 }56 }
57 }57 }
58}58}
@@ -144,7 +144,7 @@ bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { · 85 unmodified lines
144 // list is full144 // list is full
145 return false;145 return false;
146 }146 }
147 if (doll->_ragdollSimulation == this) {147 if (doll->_simulation == this) {
148 for (int i = 0; i < numDolls; ++i) {148 for (int i = 0; i < numDolls; ++i) {
149 if (doll == _otherRagdolls[i]) {149 if (doll == _otherRagdolls[i]) {
150 // already in list150 // already in list
@@ -153,8 +153,8 @@ bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { · 2 unmodified lines
153 }153 }
154 }154 }
155 // add to list155 // add to list
156 assert(!(doll->_ragdollSimulation));156 assert(!(doll->_simulation));
157 doll->_ragdollSimulation = this;157 doll->_simulation = this;
158 _otherRagdolls.push_back(doll);158 _otherRagdolls.push_back(doll);
159 159
160 // set the massScale of otherRagdolls artificially high160 // set the massScale of otherRagdolls artificially high
@@ -164,7 +164,7 @@ bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { · 3 unmodified lines
164 164
165void PhysicsSimulation::removeRagdoll(Ragdoll* doll) {165void PhysicsSimulation::removeRagdoll(Ragdoll* doll) {
166 int numDolls = _otherRagdolls.size();166 int numDolls = _otherRagdolls.size();
167 if (doll->_ragdollSimulation != this) {167 if (doll->_simulation != this) {
168 return;168 return;
169 }169 }
170 for (int i = 0; i < numDolls; ++i) {170 for (int i = 0; i < numDolls; ++i) {
@@ -178,7 +178,7 @@ void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { · 7 unmodified lines
178 _otherRagdolls.pop_back();178 _otherRagdolls.pop_back();
179 _otherRagdolls[i] = lastDoll;179 _otherRagdolls[i] = lastDoll;
180 }180 }
181 doll->_ragdollSimulation = NULL;181 doll->_simulation = NULL;
182 doll->setMassScale(1.0f);182 doll->setMassScale(1.0f);
183 break;183 break;
184 }184 }
@@ -195,13 +195,13 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter · 10 unmodified lines
195 quint64 expiry = startTime + maxUsec;195 quint64 expiry = startTime + maxUsec;
196 196
197 moveRagdolls(deltaTime);197 moveRagdolls(deltaTime);
198 buildContactConstraints();198 enforceContacts();
199 int numDolls = _otherRagdolls.size();199 int numDolls = _otherRagdolls.size();
200 {200 {
201 PerformanceTimer perfTimer("enforce");201 PerformanceTimer perfTimer("enforce");
202 _ragdoll->enforceRagdollConstraints();202 _ragdoll->enforceConstraints();
203 for (int i = 0; i < numDolls; ++i) {203 for (int i = 0; i < numDolls; ++i) {
204 _otherRagdolls[i]->enforceRagdollConstraints();204 _otherRagdolls[i]->enforceConstraints();
205 }205 }
206 }206 }
207 207
@@ -214,12 +214,12 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter · 6 unmodified lines
214 214
215 { // enforce constraints215 { // enforce constraints
216 PerformanceTimer perfTimer("enforce");216 PerformanceTimer perfTimer("enforce");
217 error = _ragdoll->enforceRagdollConstraints();217 error = _ragdoll->enforceConstraints();
218 for (int i = 0; i < numDolls; ++i) {218 for (int i = 0; i < numDolls; ++i) {
219 error = glm::max(error, _otherRagdolls[i]->enforceRagdollConstraints());219 error = glm::max(error, _otherRagdolls[i]->enforceConstraints());
220 }220 }
221 }221 }
222 enforceContactConstraints();222 applyContactFriction();
223 ++iterations;223 ++iterations;
224 224
225 now = usecTimestampNow();225 now = usecTimestampNow();
@@ -230,10 +230,10 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter · 4 unmodified lines
230 230
231void PhysicsSimulation::moveRagdolls(float deltaTime) {231void PhysicsSimulation::moveRagdolls(float deltaTime) {
232 PerformanceTimer perfTimer("integrate");232 PerformanceTimer perfTimer("integrate");
233 _ragdoll->stepRagdollForward(deltaTime);233 _ragdoll->stepForward(deltaTime);
234 int numDolls = _otherRagdolls.size();234 int numDolls = _otherRagdolls.size();
235 for (int i = 0; i < numDolls; ++i) {235 for (int i = 0; i < numDolls; ++i) {
236 _otherRagdolls[i]->stepRagdollForward(deltaTime);236 _otherRagdolls[i]->stepForward(deltaTime);
237 }237 }
238}238}
239 239
@@ -288,20 +288,20 @@ void PhysicsSimulation::resolveCollisions() { · 48 unmodified lines
288 }288 }
289}289}
290 290
291void PhysicsSimulation::buildContactConstraints() {291void PhysicsSimulation::enforceContacts() {
292 PerformanceTimer perfTimer("contacts");292 PerformanceTimer perfTimer("contacts");
293 QMap<quint64, ContactPoint>::iterator itr = _contacts.begin();293 QMap<quint64, ContactPoint>::iterator itr = _contacts.begin();
294 while (itr != _contacts.end()) {294 while (itr != _contacts.end()) {
295 itr.value().buildConstraints();295 itr.value().enforce();
296 ++itr;296 ++itr;
297 }297 }
298}298}
299 299
300void PhysicsSimulation::enforceContactConstraints() {300void PhysicsSimulation::applyContactFriction() {
301 PerformanceTimer perfTimer("contacts");301 PerformanceTimer perfTimer("contacts");
302 QMap<quint64, ContactPoint>::iterator itr = _contacts.begin();302 QMap<quint64, ContactPoint>::iterator itr = _contacts.begin();
303 while (itr != _contacts.end()) {303 while (itr != _contacts.end()) {
304 itr.value().enforce();304 itr.value().applyFriction();
305 ++itr;305 ++itr;
306 }306 }
307}307}
libraries/shared/src/PhysicsSimulation.h+2−2
@@ -56,8 +56,8 @@ protected: · 55 unmodified lines
56 void computeCollisions();56 void computeCollisions();
57 void resolveCollisions();57 void resolveCollisions();
58 58
59 void buildContactConstraints();59 void enforceContacts();
60 void enforceContactConstraints();60 void applyContactFriction();
61 void updateContacts();61 void updateContacts();
62 void pruneContacts();62 void pruneContacts();
63 63
libraries/shared/src/Ragdoll.cpp+23−20
@@ -19,24 +19,27 @@ · 18 unmodified lines
19#include "PhysicsSimulation.h"19#include "PhysicsSimulation.h"
20#include "SharedUtil.h" // for EPSILON20#include "SharedUtil.h" // for EPSILON
21 21
22Ragdoll::Ragdoll() : _massScale(1.0f), _ragdollTranslation(0.0f), _translationInSimulationFrame(0.0f), _ragdollSimulation(NULL) {22Ragdoll::Ragdoll() : _massScale(1.0f), _translation(0.0f), _translationInSimulationFrame(0.0f), _simulation(NULL) {
23}23}
24 24
25Ragdoll::~Ragdoll() {25Ragdoll::~Ragdoll() {
26 clearRagdollConstraintsAndPoints();26 clearConstraintsAndPoints();
27 if (_simulation) {
28 _simulation->removeRagdoll(this);
29 }
27}30}
28 31
29void Ragdoll::stepRagdollForward(float deltaTime) {32void Ragdoll::stepForward(float deltaTime) {
30 if (_ragdollSimulation) {33 if (_simulation) {
31 updateSimulationTransforms(_ragdollTranslation - _ragdollSimulation->getTranslation(), _ragdollRotation);34 updateSimulationTransforms(_translation - _simulation->getTranslation(), _rotation);
32 }35 }
33 int numPoints = _ragdollPoints.size();36 int numPoints = _points.size();
34 for (int i = 0; i < numPoints; ++i) {37 for (int i = 0; i < numPoints; ++i) {
35 _ragdollPoints[i].integrateForward();38 _points[i].integrateForward();
36 }39 }
37}40}
38 41
39void Ragdoll::clearRagdollConstraintsAndPoints() {42void Ragdoll::clearConstraintsAndPoints() {
40 int numConstraints = _boneConstraints.size();43 int numConstraints = _boneConstraints.size();
41 for (int i = 0; i < numConstraints; ++i) {44 for (int i = 0; i < numConstraints; ++i) {
42 delete _boneConstraints[i];45 delete _boneConstraints[i];
@@ -47,10 +50,10 @@ void Ragdoll::clearRagdollConstraintsAndPoints() { · 4 unmodified lines
47 delete _fixedConstraints[i];50 delete _fixedConstraints[i];
48 }51 }
49 _fixedConstraints.clear();52 _fixedConstraints.clear();
50 _ragdollPoints.clear();53 _points.clear();
51}54}
52 55
53float Ragdoll::enforceRagdollConstraints() {56float Ragdoll::enforceConstraints() {
54 float maxDistance = 0.0f;57 float maxDistance = 0.0f;
55 // enforce the bone constraints first58 // enforce the bone constraints first
56 int numConstraints = _boneConstraints.size();59 int numConstraints = _boneConstraints.size();
@@ -65,16 +68,16 @@ float Ragdoll::enforceRagdollConstraints() { · 8 unmodified lines
65 return maxDistance;68 return maxDistance;
66}69}
67 70
68void Ragdoll::initRagdollTransform() {71void Ragdoll::initTransform() {
69 _ragdollTranslation = glm::vec3(0.0f);72 _translation = glm::vec3(0.0f);
70 _ragdollRotation = glm::quat();73 _rotation = glm::quat();
71 _translationInSimulationFrame = glm::vec3(0.0f);74 _translationInSimulationFrame = glm::vec3(0.0f);
72 _rotationInSimulationFrame = glm::quat();75 _rotationInSimulationFrame = glm::quat();
73}76}
74 77
75void Ragdoll::setRagdollTransform(const glm::vec3& translation, const glm::quat& rotation) {78void Ragdoll::setTransform(const glm::vec3& translation, const glm::quat& rotation) {
76 _ragdollTranslation = translation;79 _translation = translation;
77 _ragdollRotation = rotation;80 _rotation = rotation;
78}81}
79 82
80void Ragdoll::updateSimulationTransforms(const glm::vec3& translation, const glm::quat& rotation) {83void Ragdoll::updateSimulationTransforms(const glm::vec3& translation, const glm::quat& rotation) {
@@ -90,9 +93,9 @@ void Ragdoll::updateSimulationTransforms(const glm::vec3& translation, const glm · 9 unmodified lines
90 glm::quat deltaRotation = rotation * glm::inverse(_rotationInSimulationFrame);93 glm::quat deltaRotation = rotation * glm::inverse(_rotationInSimulationFrame);
91 94
92 // apply the deltas to all ragdollPoints95 // apply the deltas to all ragdollPoints
93 int numPoints = _ragdollPoints.size();96 int numPoints = _points.size();
94 for (int i = 0; i < numPoints; ++i) {97 for (int i = 0; i < numPoints; ++i) {
95 _ragdollPoints[i].move(deltaPosition, deltaRotation, _translationInSimulationFrame);98 _points[i].move(deltaPosition, deltaRotation, _translationInSimulationFrame);
96 }99 }
97 100
98 // remember the current transform101 // remember the current transform
@@ -106,9 +109,9 @@ void Ragdoll::setMassScale(float scale) { · 7 unmodified lines
106 scale = glm::clamp(glm::abs(scale), MIN_SCALE, MAX_SCALE);109 scale = glm::clamp(glm::abs(scale), MIN_SCALE, MAX_SCALE);
107 if (scale != _massScale) {110 if (scale != _massScale) {
108 float rescale = scale / _massScale;111 float rescale = scale / _massScale;
109 int numPoints = _ragdollPoints.size();112 int numPoints = _points.size();
110 for (int i = 0; i < numPoints; ++i) {113 for (int i = 0; i < numPoints; ++i) {
111 _ragdollPoints[i].setMass(rescale * _ragdollPoints[i].getMass());114 _points[i].setMass(rescale * _points[i].getMass());
112 }115 }
113 _massScale = scale;116 _massScale = scale;
114 }117 }
libraries/shared/src/Ragdoll.h+14−14
@@ -33,44 +33,44 @@ public: · 32 unmodified lines
33 Ragdoll();33 Ragdoll();
34 virtual ~Ragdoll();34 virtual ~Ragdoll();
35 35
36 virtual void stepRagdollForward(float deltaTime);36 virtual void stepForward(float deltaTime);
37 37
38 /// \return max distance of point movement38 /// \return max distance of point movement
39 float enforceRagdollConstraints();39 float enforceConstraints();
40 40
41 // both const and non-const getPoints()41 // both const and non-const getPoints()
42 const QVector<VerletPoint>& getRagdollPoints() const { return _ragdollPoints; }42 const QVector<VerletPoint>& getPoints() const { return _points; }
43 QVector<VerletPoint>& getRagdollPoints() { return _ragdollPoints; }43 QVector<VerletPoint>& getPoints() { return _points; }
44 44
45 void initRagdollTransform();45 void initTransform();
46 46
47 /// set the translation and rotation of the Ragdoll and adjust all VerletPoints.47 /// set the translation and rotation of the Ragdoll and adjust all VerletPoints.
48 void setRagdollTransform(const glm::vec3& translation, const glm::quat& rotation);48 void setTransform(const glm::vec3& translation, const glm::quat& rotation);
49 49
50 const glm::vec3& getTranslationInSimulationFrame() const { return _translationInSimulationFrame; }50 const glm::vec3& getTranslationInSimulationFrame() const { return _translationInSimulationFrame; }
51 51
52 void setMassScale(float scale);52 void setMassScale(float scale);
53 float getMassScale() const { return _massScale; }53 float getMassScale() const { return _massScale; }
54 54
55protected:55 void clearConstraintsAndPoints();
56 void clearRagdollConstraintsAndPoints();56 virtual void initPoints() = 0;
57 virtual void initRagdollPoints() = 0;57 virtual void buildConstraints() = 0;
58 virtual void buildRagdollConstraints() = 0;
59 58
59protected:
60 float _massScale;60 float _massScale;
61 glm::vec3 _ragdollTranslation; // world-frame61 glm::vec3 _translation; // world-frame
62 glm::quat _ragdollRotation; // world-frame62 glm::quat _rotation; // world-frame
63 glm::vec3 _translationInSimulationFrame;63 glm::vec3 _translationInSimulationFrame;
64 glm::quat _rotationInSimulationFrame;64 glm::quat _rotationInSimulationFrame;
65 65
66 QVector<VerletPoint> _ragdollPoints;66 QVector<VerletPoint> _points;
67 QVector<DistanceConstraint*> _boneConstraints;67 QVector<DistanceConstraint*> _boneConstraints;
68 QVector<FixedConstraint*> _fixedConstraints;68 QVector<FixedConstraint*> _fixedConstraints;
69private:69private:
70 void updateSimulationTransforms(const glm::vec3& translation, const glm::quat& rotation);70 void updateSimulationTransforms(const glm::vec3& translation, const glm::quat& rotation);
71 71
72 friend class PhysicsSimulation;72 friend class PhysicsSimulation;
73 PhysicsSimulation* _ragdollSimulation;73 PhysicsSimulation* _simulation;
74};74};
75 75
76#endif // hifi_Ragdoll_h76#endif // hifi_Ragdoll_h
libraries/shared/src/SharedUtil.cpp+1−290
@@ -9,6 +9,7 @@ · 8 unmodified lines
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//10//
11 11
12#include <cassert>
12#include <cstdlib>13#include <cstdlib>
13#include <cstdio>14#include <cstdio>
14#include <cstring>15#include <cstring>
@@ -79,40 +80,6 @@ bool shouldDo(float desiredInterval, float deltaTime) { · 64 unmodified lines
79 return randFloat() < deltaTime / desiredInterval;80 return randFloat() < deltaTime / desiredInterval;
80}81}
81 82
82// Safe version of glm::mix; based on the code in Nick Bobick's article,
83// http://www.gamasutra.com/features/19980703/quaternions_01.htm (via Clyde,
84// https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java)
85glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float proportion) {
86 float cosa = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
87 float ox = q2.x, oy = q2.y, oz = q2.z, ow = q2.w, s0, s1;
88
89 // adjust signs if necessary
90 if (cosa < 0.0f) {
91 cosa = -cosa;
92 ox = -ox;
93 oy = -oy;
94 oz = -oz;
95 ow = -ow;
96 }
97
98 // calculate coefficients; if the angle is too close to zero, we must fall back
99 // to linear interpolation
100 if ((1.0f - cosa) > EPSILON) {
101 float angle = acosf(cosa), sina = sinf(angle);
102 s0 = sinf((1.0f - proportion) * angle) / sina;
103 s1 = sinf(proportion * angle) / sina;
104
105 } else {
106 s0 = 1.0f - proportion;
107 s1 = proportion;
108 }
109
110 return glm::normalize(glm::quat(s0 * q1.w + s1 * ow, s0 * q1.x + s1 * ox, s0 * q1.y + s1 * oy, s0 * q1.z + s1 * oz));
111}
112
113
114
115
116void outputBufferBits(const unsigned char* buffer, int length, QDebug* continuedDebug) {83void outputBufferBits(const unsigned char* buffer, int length, QDebug* continuedDebug) {
117 for (int i = 0; i < length; i++) {84 for (int i = 0; i < length; i++) {
118 outputBits(buffer[i], continuedDebug);85 outputBits(buffer[i], continuedDebug);
@@ -489,73 +456,6 @@ int removeFromSortedArrays(void* value, void** valueArray, float* keyArray, int* · 370 unmodified lines
489 return -1; // error case456 return -1; // error case
490}457}
491 458
492// Allows sending of fixed-point numbers: radix 1 makes 15.1 number, radix 8 makes 8.8 number, etc
493int packFloatScalarToSignedTwoByteFixed(unsigned char* buffer, float scalar, int radix) {
494 int16_t outVal = (int16_t)(scalar * (float)(1 << radix));
495 memcpy(buffer, &outVal, sizeof(uint16_t));
496 return sizeof(uint16_t);
497}
498
499int unpackFloatScalarFromSignedTwoByteFixed(const int16_t* byteFixedPointer, float* destinationPointer, int radix) {
500 *destinationPointer = *byteFixedPointer / (float)(1 << radix);
501 return sizeof(int16_t);
502}
503
504int packFloatVec3ToSignedTwoByteFixed(unsigned char* destBuffer, const glm::vec3& srcVector, int radix) {
505 const unsigned char* startPosition = destBuffer;
506 destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.x, radix);
507 destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.y, radix);
508 destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.z, radix);
509 return destBuffer - startPosition;
510}
511
512int unpackFloatVec3FromSignedTwoByteFixed(const unsigned char* sourceBuffer, glm::vec3& destination, int radix) {
513 const unsigned char* startPosition = sourceBuffer;
514 sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.x), radix);
515 sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.y), radix);
516 sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.z), radix);
517 return sourceBuffer - startPosition;
518}
519
520
521int packFloatAngleToTwoByte(unsigned char* buffer, float degrees) {
522 const float ANGLE_CONVERSION_RATIO = (std::numeric_limits<uint16_t>::max() / 360.f);
523
524 uint16_t angleHolder = floorf((degrees + 180.f) * ANGLE_CONVERSION_RATIO);
525 memcpy(buffer, &angleHolder, sizeof(uint16_t));
526
527 return sizeof(uint16_t);
528}
529
530int unpackFloatAngleFromTwoByte(const uint16_t* byteAnglePointer, float* destinationPointer) {
531 *destinationPointer = (*byteAnglePointer / (float) std::numeric_limits<uint16_t>::max()) * 360.f - 180.f;
532 return sizeof(uint16_t);
533}
534
535int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput) {
536 const float QUAT_PART_CONVERSION_RATIO = (std::numeric_limits<uint16_t>::max() / 2.f);
537 uint16_t quatParts[4];
538 quatParts[0] = floorf((quatInput.x + 1.f) * QUAT_PART_CONVERSION_RATIO);
539 quatParts[1] = floorf((quatInput.y + 1.f) * QUAT_PART_CONVERSION_RATIO);
540 quatParts[2] = floorf((quatInput.z + 1.f) * QUAT_PART_CONVERSION_RATIO);
541 quatParts[3] = floorf((quatInput.w + 1.f) * QUAT_PART_CONVERSION_RATIO);
542
543 memcpy(buffer, &quatParts, sizeof(quatParts));
544 return sizeof(quatParts);
545}
546
547int unpackOrientationQuatFromBytes(const unsigned char* buffer, glm::quat& quatOutput) {
548 uint16_t quatParts[4];
549 memcpy(&quatParts, buffer, sizeof(quatParts));
550
551 quatOutput.x = ((quatParts[0] / (float) std::numeric_limits<uint16_t>::max()) * 2.f) - 1.f;
552 quatOutput.y = ((quatParts[1] / (float) std::numeric_limits<uint16_t>::max()) * 2.f) - 1.f;
553 quatOutput.z = ((quatParts[2] / (float) std::numeric_limits<uint16_t>::max()) * 2.f) - 1.f;
554 quatOutput.w = ((quatParts[3] / (float) std::numeric_limits<uint16_t>::max()) * 2.f) - 1.f;
555
556 return sizeof(quatParts);
557}
558
559float SMALL_LIMIT = 10.f;459float SMALL_LIMIT = 10.f;
560float LARGE_LIMIT = 1000.f;460float LARGE_LIMIT = 1000.f;
561 461
@@ -651,199 +551,10 @@ void debug::checkDeadBeef(void* memoryVoid, int size) { · 89 unmodified lines
651 assert(memcmp((unsigned char*)memoryVoid, DEADBEEF, std::min(size, DEADBEEF_SIZE)) != 0);551 assert(memcmp((unsigned char*)memoryVoid, DEADBEEF, std::min(size, DEADBEEF_SIZE)) != 0);
652}552}
653 553
654// Safe version of glm::eulerAngles; uses the factorization method described in David Eberly's
655// http://www.geometrictools.com/Documentation/EulerAngles.pdf (via Clyde,
656// https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java)
657glm::vec3 safeEulerAngles(const glm::quat& q) {
658 float sy = 2.0f * (q.y * q.w - q.x * q.z);
659 glm::vec3 eulers;
660 if (sy < 1.0f - EPSILON) {
661 if (sy > -1.0f + EPSILON) {
662 eulers = glm::vec3(
663 atan2f(q.y * q.z + q.x * q.w, 0.5f - (q.x * q.x + q.y * q.y)),
664 asinf(sy),
665 atan2f(q.x * q.y + q.z * q.w, 0.5f - (q.y * q.y + q.z * q.z)));
666
667 } else {
668 // not a unique solution; x + z = atan2(-m21, m11)
669 eulers = glm::vec3(
670 0.0f,
671 - PI_OVER_TWO,
672 atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z)));
673 }
674 } else {
675 // not a unique solution; x - z = atan2(-m21, m11)
676 eulers = glm::vec3(
677 0.0f,
678 PI_OVER_TWO,
679 -atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z)));
680 }
681
682 // adjust so that z, rather than y, is in [-pi/2, pi/2]
683 if (eulers.z < -PI_OVER_TWO) {
684 if (eulers.x < 0.0f) {
685 eulers.x += PI;
686 } else {
687 eulers.x -= PI;
688 }
689 eulers.y = -eulers.y;
690 if (eulers.y < 0.0f) {
691 eulers.y += PI;
692 } else {
693 eulers.y -= PI;
694 }
695 eulers.z += PI;
696
697 } else if (eulers.z > PI_OVER_TWO) {
698 if (eulers.x < 0.0f) {
699 eulers.x += PI;
700 } else {
701 eulers.x -= PI;
702 }
703 eulers.y = -eulers.y;
704 if (eulers.y < 0.0f) {
705 eulers.y += PI;
706 } else {
707 eulers.y -= PI;
708 }
709 eulers.z -= PI;
710 }
711 return eulers;
712}
713
714// Helper function returns the positive angle (in radians) between two 3D vectors
715float angleBetween(const glm::vec3& v1, const glm::vec3& v2) {
716 return acosf((glm::dot(v1, v2)) / (glm::length(v1) * glm::length(v2)));
717}
718
719// Helper function return the rotation from the first vector onto the second
720glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) {
721 float angle = angleBetween(v1, v2);
722 if (glm::isnan(angle) || angle < EPSILON) {
723 return glm::quat();
724 }
725 glm::vec3 axis;
726 if (angle > 179.99f * RADIANS_PER_DEGREE) { // 180 degree rotation; must use another axis
727 axis = glm::cross(v1, glm::vec3(1.0f, 0.0f, 0.0f));
728 float axisLength = glm::length(axis);
729 if (axisLength < EPSILON) { // parallel to x; y will work
730 axis = glm::normalize(glm::cross(v1, glm::vec3(0.0f, 1.0f, 0.0f)));
731 } else {
732 axis /= axisLength;
733 }
734 } else {
735 axis = glm::normalize(glm::cross(v1, v2));
736 // It is possible for axis to be nan even when angle is not less than EPSILON.
737 // For example when angle is small but not tiny but v1 and v2 and have very short lengths.
738 if (glm::isnan(glm::dot(axis, axis))) {
739 // set angle and axis to values that will generate an identity rotation
740 angle = 0.0f;
741 axis = glm::vec3(1.0f, 0.0f, 0.0f);
742 }
743 }
744 return glm::angleAxis(angle, axis);
745}
746
747glm::vec3 extractTranslation(const glm::mat4& matrix) {
748 return glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]);
749}
750
751void setTranslation(glm::mat4& matrix, const glm::vec3& translation) {
752 matrix[3][0] = translation.x;
753 matrix[3][1] = translation.y;
754 matrix[3][2] = translation.z;
755}
756
757glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) {
758 // uses the iterative polar decomposition algorithm described by Ken Shoemake at
759 // http://www.cs.wisc.edu/graphics/Courses/838-s2002/Papers/polar-decomp.pdf
760 // code adapted from Clyde, https://github.com/threerings/clyde/blob/master/core/src/main/java/com/threerings/math/Matrix4f.java
761 // start with the contents of the upper 3x3 portion of the matrix
762 glm::mat3 upper = glm::mat3(matrix);
763 if (!assumeOrthogonal) {
764 for (int i = 0; i < 10; i++) {
765 // store the results of the previous iteration
766 glm::mat3 previous = upper;
767
768 // compute average of the matrix with its inverse transpose
769 float sd00 = previous[1][1] * previous[2][2] - previous[2][1] * previous[1][2];
770 float sd10 = previous[0][1] * previous[2][2] - previous[2][1] * previous[0][2];
771 float sd20 = previous[0][1] * previous[1][2] - previous[1][1] * previous[0][2];
772 float det = previous[0][0] * sd00 + previous[2][0] * sd20 - previous[1][0] * sd10;
773 if (fabs(det) == 0.0f) {
774 // determinant is zero; matrix is not invertible
775 break;
776 }
777 float hrdet = 0.5f / det;
778 upper[0][0] = +sd00 * hrdet + previous[0][0] * 0.5f;
779 upper[1][0] = -sd10 * hrdet + previous[1][0] * 0.5f;
780 upper[2][0] = +sd20 * hrdet + previous[2][0] * 0.5f;
781
782 upper[0][1] = -(previous[1][0] * previous[2][2] - previous[2][0] * previous[1][2]) * hrdet + previous[0][1] * 0.5f;
783 upper[1][1] = +(previous[0][0] * previous[2][2] - previous[2][0] * previous[0][2]) * hrdet + previous[1][1] * 0.5f;
784 upper[2][1] = -(previous[0][0] * previous[1][2] - previous[1][0] * previous[0][2]) * hrdet + previous[2][1] * 0.5f;
785
786 upper[0][2] = +(previous[1][0] * previous[2][1] - previous[2][0] * previous[1][1]) * hrdet + previous[0][2] * 0.5f;
787 upper[1][2] = -(previous[0][0] * previous[2][1] - previous[2][0] * previous[0][1]) * hrdet + previous[1][2] * 0.5f;
788 upper[2][2] = +(previous[0][0] * previous[1][1] - previous[1][0] * previous[0][1]) * hrdet + previous[2][2] * 0.5f;
789
790 // compute the difference; if it's small enough, we're done
791 glm::mat3 diff = upper - previous;
792 if (diff[0][0] * diff[0][0] + diff[1][0] * diff[1][0] + diff[2][0] * diff[2][0] + diff[0][1] * diff[0][1] +
793 diff[1][1] * diff[1][1] + diff[2][1] * diff[2][1] + diff[0][2] * diff[0][2] + diff[1][2] * diff[1][2] +
794 diff[2][2] * diff[2][2] < EPSILON) {
795 break;
796 }
797 }
798 }
799
800 // now that we have a nice orthogonal matrix, we can extract the rotation quaternion
801 // using the method described in http://en.wikipedia.org/wiki/Rotation_matrix#Conversions
802 float x2 = fabs(1.0f + upper[0][0] - upper[1][1] - upper[2][2]);
803 float y2 = fabs(1.0f - upper[0][0] + upper[1][1] - upper[2][2]);
804 float z2 = fabs(1.0f - upper[0][0] - upper[1][1] + upper[2][2]);
805 float w2 = fabs(1.0f + upper[0][0] + upper[1][1] + upper[2][2]);
806 return glm::normalize(glm::quat(0.5f * sqrtf(w2),
807 0.5f * sqrtf(x2) * (upper[1][2] >= upper[2][1] ? 1.0f : -1.0f),
808 0.5f * sqrtf(y2) * (upper[2][0] >= upper[0][2] ? 1.0f : -1.0f),
809 0.5f * sqrtf(z2) * (upper[0][1] >= upper[1][0] ? 1.0f : -1.0f)));
810}
811
812glm::vec3 extractScale(const glm::mat4& matrix) {
813 return glm::vec3(glm::length(matrix[0]), glm::length(matrix[1]), glm::length(matrix[2]));
814}
815
816float extractUniformScale(const glm::mat4& matrix) {
817 return extractUniformScale(extractScale(matrix));
818}
819
820float extractUniformScale(const glm::vec3& scale) {
821 return (scale.x + scale.y + scale.z) / 3.0f;
822}
823
824bool isNaN(float value) { 554bool isNaN(float value) {
825 return value != value; 555 return value != value;
826}556}
827 557
828bool isSimilarOrientation(const glm::quat& orientionA, const glm::quat& orientionB, float similarEnough) {
829 // Compute the angular distance between the two orientations
830 float angleOrientation = orientionA == orientionB ? 0.0f : glm::degrees(glm::angle(orientionA * glm::inverse(orientionB)));
831 if (isNaN(angleOrientation)) {
832 angleOrientation = 0.0f;
833 }
834 return (angleOrientation <= similarEnough);
835}
836
837bool isSimilarPosition(const glm::vec3& positionA, const glm::vec3& positionB, float similarEnough) {
838 // Compute the distance between the two points
839 float positionDistance = glm::distance(positionA, positionB);
840 return (positionDistance <= similarEnough);
841}
842
843QByteArray createByteArray(const glm::vec3& vector) {
844 return QByteArray::number(vector.x) + ',' + QByteArray::number(vector.y) + ',' + QByteArray::number(vector.z);
845}
846
847QString formatUsecTime(float usecs, int prec) {558QString formatUsecTime(float usecs, int prec) {
848 static const quint64 SECONDS_PER_MINUTE = 60;559 static const quint64 SECONDS_PER_MINUTE = 60;
849 static const quint64 USECS_PER_MINUTE = USECS_PER_SECOND * SECONDS_PER_MINUTE;560 static const quint64 USECS_PER_MINUTE = USECS_PER_SECOND * SECONDS_PER_MINUTE;
libraries/shared/src/SharedUtil.h+0−69
@@ -19,9 +19,6 @@ · 18 unmodified lines
19#include <unistd.h> // not on windows, not needed for mac or windows19#include <unistd.h> // not on windows, not needed for mac or windows
20#endif20#endif
21 21
22#include <glm/glm.hpp>
23#include <glm/gtc/quaternion.hpp>
24
25#include <QtCore/QDebug>22#include <QtCore/QDebug>
26 23
27const int BYTES_PER_COLOR = 3;24const int BYTES_PER_COLOR = 3;
@@ -71,8 +68,6 @@ float randomSign(); /// \return -1.0 or 1.0 · 43 unmodified lines
71unsigned char randomColorValue(int minimum = 0);68unsigned char randomColorValue(int minimum = 0);
72bool randomBoolean();69bool randomBoolean();
73 70
74glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha);
75
76bool shouldDo(float desiredInterval, float deltaTime);71bool shouldDo(float desiredInterval, float deltaTime);
77 72
78void outputBufferBits(const unsigned char* buffer, int length, QDebug* continuedDebug = NULL);73void outputBufferBits(const unsigned char* buffer, int length, QDebug* continuedDebug = NULL);
@@ -108,8 +103,6 @@ int insertIntoSortedArrays(void* value, float key, int originalIndex, · 29 unmodified lines
108int removeFromSortedArrays(void* value, void** valueArray, float* keyArray, int* originalIndexArray,103int removeFromSortedArrays(void* value, void** valueArray, float* keyArray, int* originalIndexArray,
109 int currentCount, int maxCount);104 int currentCount, int maxCount);
110 105
111
112
113// Helper Class for debugging106// Helper Class for debugging
114class debug {107class debug {
115public:108public:
@@ -124,71 +117,9 @@ private: · 8 unmodified lines
124bool isBetween(int64_t value, int64_t max, int64_t min);117bool isBetween(int64_t value, int64_t max, int64_t min);
125 118
126 119
127// These pack/unpack functions are designed to start specific known types in as efficient a manner
128// as possible. Taking advantage of the known characteristics of the semantic types.
129
130// Angles are known to be between 0 and 360 degrees, this allows us to encode in 16bits with great accuracy
131int packFloatAngleToTwoByte(unsigned char* buffer, float degrees);
132int unpackFloatAngleFromTwoByte(const uint16_t* byteAnglePointer, float* destinationPointer);
133
134// Orientation Quats are known to have 4 normalized components be between -1.0 and 1.0
135// this allows us to encode each component in 16bits with great accuracy
136int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput);
137int unpackOrientationQuatFromBytes(const unsigned char* buffer, glm::quat& quatOutput);
138
139// Ratios need the be highly accurate when less than 10, but not very accurate above 10, and they
140// are never greater than 1000 to 1, this allows us to encode each component in 16bits
141int packFloatRatioToTwoByte(unsigned char* buffer, float ratio);
142int unpackFloatRatioFromTwoByte(const unsigned char* buffer, float& ratio);
143
144// Near/Far Clip values need the be highly accurate when less than 10, but only integer accuracy above 10 and
145// they are never greater than 16,000, this allows us to encode each component in 16bits
146int packClipValueToTwoByte(unsigned char* buffer, float clipValue);
147int unpackClipValueFromTwoByte(const unsigned char* buffer, float& clipValue);
148
149// Positive floats that don't need to be very precise
150int packFloatToByte(unsigned char* buffer, float value, float scaleBy);
151int unpackFloatFromByte(const unsigned char* buffer, float& value, float scaleBy);
152
153// Allows sending of fixed-point numbers: radix 1 makes 15.1 number, radix 8 makes 8.8 number, etc
154int packFloatScalarToSignedTwoByteFixed(unsigned char* buffer, float scalar, int radix);
155int unpackFloatScalarFromSignedTwoByteFixed(const int16_t* byteFixedPointer, float* destinationPointer, int radix);
156
157// A convenience for sending vec3's as fixed-point floats
158int packFloatVec3ToSignedTwoByteFixed(unsigned char* destBuffer, const glm::vec3& srcVector, int radix);
159int unpackFloatVec3FromSignedTwoByteFixed(const unsigned char* sourceBuffer, glm::vec3& destination, int radix);
160
161/// \return vec3 with euler angles in radians
162glm::vec3 safeEulerAngles(const glm::quat& q);
163
164float angleBetween(const glm::vec3& v1, const glm::vec3& v2);
165
166glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2);
167
168glm::vec3 extractTranslation(const glm::mat4& matrix);
169
170void setTranslation(glm::mat4& matrix, const glm::vec3& translation);
171
172glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal = false);
173
174glm::vec3 extractScale(const glm::mat4& matrix);
175
176float extractUniformScale(const glm::mat4& matrix);
177
178float extractUniformScale(const glm::vec3& scale);
179
180/// \return bool are two orientations similar to each other
181const float ORIENTATION_SIMILAR_ENOUGH = 5.0f; // 10 degrees in any direction
182bool isSimilarOrientation(const glm::quat& orientionA, const glm::quat& orientionB,
183 float similarEnough = ORIENTATION_SIMILAR_ENOUGH);
184const float POSITION_SIMILAR_ENOUGH = 0.1f; // 0.1 meter
185bool isSimilarPosition(const glm::vec3& positionA, const glm::vec3& positionB, float similarEnough = POSITION_SIMILAR_ENOUGH);
186
187/// \return bool is the float NaN 120/// \return bool is the float NaN
188bool isNaN(float value);121bool isNaN(float value);
189 122
190QByteArray createByteArray(const glm::vec3& vector);
191
192QString formatUsecTime(float usecs, int prec = 3);123QString formatUsecTime(float usecs, int prec = 3);
193 124
194 125
libraries/voxels/CMakeLists.txt+11−24
@@ -1,31 +1,18 @@
1set(ROOT_DIR ../..)
2set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
3
4# setup for find modules
5set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
6
7set(TARGET_NAME voxels)1set(TARGET_NAME voxels)
8 2
9find_package(Qt5 COMPONENTS Widgets Script)3# use setup_hifi_library macro to setup our project and link appropriate Qt modules
10 4setup_hifi_library(Widgets Script)
11include(${MACRO_DIR}/SetupHifiLibrary.cmake)
12setup_hifi_library(${TARGET_NAME})
13 5
14include(${MACRO_DIR}/IncludeGLM.cmake)6include_glm()
15include_glm(${TARGET_NAME} "${ROOT_DIR}")
16 7
17include(${MACRO_DIR}/LinkHifiLibrary.cmake)8link_hifi_libraries(shared octree networking)
18link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
19link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}")
20link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
21
22# link ZLIB
23find_package(ZLIB)
24 9
10# find ZLIB
11find_package(ZLIB REQUIRED)
25include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}")12include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}")
26target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets Qt5::Script)
27 13
28# add a definition for ssize_t so that windows doesn't bail14# add it to our list of libraries to link
29if (WIN32)15list(APPEND ${TARGET}_LIBRARIES_TO_LINK "${ZLIB_LIBRARIES}")
30 add_definitions(-Dssize_t=long)16
31endif ()17# call macro to link our dependencies and bubble them up via a property on our target
18link_shared_dependencies()
libraries/voxels/src/VoxelEditPacketSender.h+1−1
@@ -28,7 +28,7 @@ public: · 27 unmodified lines
28 /// Queues a single voxel edit message. Will potentially send a pending multi-command packet. Determines which voxel-server28 /// Queues a single voxel edit message. Will potentially send a pending multi-command packet. Determines which voxel-server
29 /// node or nodes the packet should be sent to. Can be called even before voxel servers are known, in which case up to 29 /// node or nodes the packet should be sent to. Can be called even before voxel servers are known, in which case up to
30 /// MaxPendingMessages will be buffered and processed when voxel servers are known.30 /// MaxPendingMessages will be buffered and processed when voxel servers are known.
31 void queueVoxelEditMessage(PacketType type, unsigned char* codeColorBuffer, ssize_t length) {31 void queueVoxelEditMessage(PacketType type, unsigned char* codeColorBuffer, size_t length) {
32 queueOctreeEditMessage(type, codeColorBuffer, length);32 queueOctreeEditMessage(type, codeColorBuffer, length);
33 }33 }
34 34
tests/audio/CMakeLists.txt+4−28
@@ -1,34 +1,10 @@
1set(TARGET_NAME audio-tests)1set(TARGET_NAME audio-tests)
2 2
3set(ROOT_DIR ../..)3setup_hifi_project()
4set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
5 4
6# setup for find modules5include_glm()
7set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
8
9#find_package(Qt5Network REQUIRED)
10#find_package(Qt5Script REQUIRED)
11#find_package(Qt5Widgets REQUIRED)
12
13include(${MACRO_DIR}/SetupHifiProject.cmake)
14setup_hifi_project(${TARGET_NAME} TRUE)
15
16include(${MACRO_DIR}/AutoMTC.cmake)
17auto_mtc(${TARGET_NAME} ${ROOT_DIR})
18
19#qt5_use_modules(${TARGET_NAME} Network Script Widgets)
20
21#include glm
22include(${MACRO_DIR}/IncludeGLM.cmake)
23include_glm(${TARGET_NAME} ${ROOT_DIR})
24 6
25# link in the shared libraries7# link in the shared libraries
26include(${MACRO_DIR}/LinkHifiLibrary.cmake)8link_hifi_libraries(shared audio networking)
27link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
28link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR})
29link_hifi_library(networking ${TARGET_NAME} ${ROOT_DIR})
30
31IF (WIN32)
32 target_link_libraries(${TARGET_NAME} Winmm Ws2_32)
33ENDIF(WIN32)
34 9
10link_shared_dependencies()
tests/jitter/CMakeLists.txt+3−28
@@ -1,33 +1,8 @@
1set(TARGET_NAME jitter-tests)1set(TARGET_NAME jitter-tests)
2 2
3set(ROOT_DIR ../..)3setup_hifi_project()
4set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
5
6# setup for find modules
7set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
8
9#find_package(Qt5Network REQUIRED)
10#find_package(Qt5Script REQUIRED)
11#find_package(Qt5Widgets REQUIRED)
12
13include(${MACRO_DIR}/SetupHifiProject.cmake)
14setup_hifi_project(${TARGET_NAME} TRUE)
15
16#include(${MACRO_DIR}/AutoMTC.cmake)
17#auto_mtc(${TARGET_NAME} ${ROOT_DIR})
18
19#qt5_use_modules(${TARGET_NAME} Network Script Widgets)
20
21#include glm - because it's a dependency of shared utils...
22include(${MACRO_DIR}/IncludeGLM.cmake)
23include_glm(${TARGET_NAME} ${ROOT_DIR})
24 4
25# link in the shared libraries5# link in the shared libraries
26include(${MACRO_DIR}/LinkHifiLibrary.cmake)6link_hifi_libraries(shared networking)
27link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
28link_hifi_library(networking ${TARGET_NAME} ${ROOT_DIR})
29
30IF (WIN32)
31 target_link_libraries(${TARGET_NAME} Winmm Ws2_32)
32ENDIF(WIN32)
33 7
8link_shared_dependencies()
tests/jitter/src/main.cpp+258−50
@@ -13,12 +13,17 @@ · 12 unmodified lines
13#include <sys/socket.h>13#include <sys/socket.h>
14#include <arpa/inet.h>14#include <arpa/inet.h>
15#endif15#endif
16#include <cerrno>
16#include <stdio.h>17#include <stdio.h>
17 18
18#include <MovingMinMaxAvg.h> // for MovingMinMaxAvg19#include <MovingMinMaxAvg.h>
20#include <SequenceNumberStats.h>
19#include <SharedUtil.h> // for usecTimestampNow21#include <SharedUtil.h> // for usecTimestampNow
22#include <SimpleMovingAverage.h>
23#include <StdDev.h>
20 24
21const quint64 MSEC_TO_USEC = 1000;25const quint64 MSEC_TO_USEC = 1000;
26const quint64 LARGE_STATS_TIME = 500; // we don't expect stats calculation to take more than this many usecs
22 27
23void runSend(const char* addressOption, int port, int gap, int size, int report);28void runSend(const char* addressOption, int port, int gap, int size, int report);
24void runReceive(const char* addressOption, int port, int gap, int size, int report);29void runReceive(const char* addressOption, int port, int gap, int size, int report);
@@ -56,112 +61,315 @@ int main(int argc, const char * argv[]) { · 31 unmodified lines
56void runSend(const char* addressOption, int port, int gap, int size, int report) {61void runSend(const char* addressOption, int port, int gap, int size, int report) {
57 std::cout << "runSend...\n";62 std::cout << "runSend...\n";
58 63
64#ifdef _WIN32
65 WSADATA wsaData;
66 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
67 printf("WSAStartup failed with error %d\n", WSAGetLastError());
68 return;
69 }
70#endif
71
59 int sockfd;72 int sockfd;
60 struct sockaddr_in servaddr;73 struct sockaddr_in servaddr;
61 74
62 char* outputBuffer = new char[size];75 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
63 memset(outputBuffer, 0, size);76
64
65 sockfd=socket(AF_INET,SOCK_DGRAM,0);
66
67 memset(&servaddr, 0, sizeof(servaddr));77 memset(&servaddr, 0, sizeof(servaddr));
68 servaddr.sin_family = AF_INET;78 servaddr.sin_family = AF_INET;
69 servaddr.sin_addr.s_addr=inet_addr(addressOption);79 servaddr.sin_addr.s_addr = inet_addr(addressOption);
70 servaddr.sin_port=htons(port);80 servaddr.sin_port = htons(port);
71
72 const int SAMPLES_FOR_30_SECONDS = 30 * 1000000 / gap;
73 81
82 const int SAMPLES_FOR_SECOND = 1000000 / gap;
83 std::cout << "SAMPLES_FOR_SECOND:" << SAMPLES_FOR_SECOND << "\n";
84 const int INTERVALS_PER_30_SECONDS = 30;
85 std::cout << "INTERVALS_PER_30_SECONDS:" << INTERVALS_PER_30_SECONDS << "\n";
86 const int SAMPLES_FOR_30_SECONDS = 30 * SAMPLES_FOR_SECOND;
74 std::cout << "SAMPLES_FOR_30_SECONDS:" << SAMPLES_FOR_30_SECONDS << "\n";87 std::cout << "SAMPLES_FOR_30_SECONDS:" << SAMPLES_FOR_30_SECONDS << "\n";
88 const int REPORTS_FOR_30_SECONDS = 30 * MSECS_PER_SECOND / report;
89 std::cout << "REPORTS_FOR_30_SECONDS:" << REPORTS_FOR_30_SECONDS << "\n";
90
91 int intervalsPerReport = report / MSEC_TO_USEC;
92 if (intervalsPerReport < 1) {
93 intervalsPerReport = 1;
94 }
95 std::cout << "intervalsPerReport:" << intervalsPerReport << "\n";
96 MovingMinMaxAvg<int> timeGaps(SAMPLES_FOR_SECOND, INTERVALS_PER_30_SECONDS);
97 MovingMinMaxAvg<int> timeGapsPerReport(SAMPLES_FOR_SECOND, intervalsPerReport);
98
99 char* outputBuffer = new char[size];
100 memset(outputBuffer, 0, size);
101
102 quint16 outgoingSequenceNumber = 0;
103
104
105 StDev stDevReportInterval;
106 StDev stDev30s;
107 StDev stDev;
108
109 SimpleMovingAverage averageNetworkTime(SAMPLES_FOR_30_SECONDS);
110 SimpleMovingAverage averageStatsCalcultionTime(SAMPLES_FOR_30_SECONDS);
111 float lastStatsCalculationTime = 0.0f; // we add out stats calculation time in the next calculation window
112 bool hasStatsCalculationTime = false;
75 113
76 MovingMinMaxAvg<int> timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats
77
78 quint64 last = usecTimestampNow();114 quint64 last = usecTimestampNow();
79 quint64 lastReport = 0;115 quint64 lastReport = 0;
80 116
81 while (true) {117 while (true) {
82 118
83 quint64 now = usecTimestampNow();119 quint64 now = usecTimestampNow();
84 int actualGap = now - last;120 int actualGap = now - last;
85 121
86 122
87 if (actualGap >= gap) {123 if (actualGap >= gap) {
88 sendto(sockfd, outputBuffer, size, 0, (struct sockaddr *)&servaddr, sizeof(servaddr));124
89 125 // pack seq num
126 memcpy(outputBuffer, &outgoingSequenceNumber, sizeof(quint16));
127
128 quint64 networkStart = usecTimestampNow();
129 int n = sendto(sockfd, outputBuffer, size, 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
130 quint64 networkEnd = usecTimestampNow();
131 float networkElapsed = (float)(networkEnd - networkStart);
132
133 if (n < 0) {
134 std::cout << "Send error: " << strerror(errno) << "\n";
135 }
136 outgoingSequenceNumber++;
137
138 quint64 statsCalcultionStart = usecTimestampNow();
139
90 int gapDifferece = actualGap - gap;140 int gapDifferece = actualGap - gap;
141
91 timeGaps.update(gapDifferece);142 timeGaps.update(gapDifferece);
143 timeGapsPerReport.update(gapDifferece);
144 stDev.addValue(gapDifferece);
145 stDev30s.addValue(gapDifferece);
146 stDevReportInterval.addValue(gapDifferece);
92 last = now;147 last = now;
148
149 // track out network time and stats calculation times
150 averageNetworkTime.updateAverage(networkElapsed);
151
152 // for our stats calculation time, we actually delay the updating by one sample.
153 // we do this so that the calculation of the average timing for the stats calculation
154 // happen inside of the calculation processing. This ensures that tracking stats on
155 // stats calculation doesn't side effect the remaining running time.
156 if (hasStatsCalculationTime) {
157 averageStatsCalcultionTime.updateAverage(lastStatsCalculationTime);
158 }
93 159
94 if (now - lastReport >= (report * MSEC_TO_USEC)) {160 if (now - lastReport >= (report * MSEC_TO_USEC)) {
95 std::cout << "SEND gap Difference From Expected "161
96 << "min: " << timeGaps.getMin() << " usecs, "162 std::cout << "\n"
97 << "max: " << timeGaps.getMax() << " usecs, "163 << "SEND gap Difference From Expected\n"
98 << "avg: " << timeGaps.getAverage() << " usecs, "164 << "Overall:\n"
99 << "min last 30: " << timeGaps.getWindowMin() << " usecs, "165 << "min: " << timeGaps.getMin() << " usecs, "
100 << "max last 30: " << timeGaps.getWindowMax() << " usecs, "166 << "max: " << timeGaps.getMax() << " usecs, "
101 << "avg last 30: " << timeGaps.getWindowAverage() << " usecs "167 << "avg: " << timeGaps.getAverage() << " usecs, "
102 << "\n";168 << "stdev: " << stDev.getStDev() << " usecs\n"
169 << "Last 30s:\n"
170 << "min: " << timeGaps.getWindowMin() << " usecs, "
171 << "max: " << timeGaps.getWindowMax() << " usecs, "
172 << "avg: " << timeGaps.getWindowAverage() << " usecs, "
173 << "stdev: " << stDev30s.getStDev() << " usecs\n"
174 << "Last report interval:\n"
175 << "min: " << timeGapsPerReport.getWindowMin() << " usecs, "
176 << "max: " << timeGapsPerReport.getWindowMax() << " usecs, "
177 << "avg: " << timeGapsPerReport.getWindowAverage() << " usecs, "
178 << "stdev: " << stDevReportInterval.getStDev() << " usecs\n"
179 << "Average Execution Times Last 30s:\n"
180 << " network: " << averageNetworkTime.getAverage() << " usecs average\n"
181 << " stats: " << averageStatsCalcultionTime.getAverage() << " usecs average"
182 << "\n";
183
184 stDevReportInterval.reset();
185 if (stDev30s.getSamples() > SAMPLES_FOR_30_SECONDS) {
186 stDev30s.reset();
187 }
188
103 lastReport = now;189 lastReport = now;
104 }190 }
191
192 quint64 statsCalcultionEnd = usecTimestampNow();
193 lastStatsCalculationTime = (float)(statsCalcultionEnd - statsCalcultionStart);
194 if (lastStatsCalculationTime > LARGE_STATS_TIME) {
195 qDebug() << "WARNING -- unexpectedly large lastStatsCalculationTime=" << lastStatsCalculationTime;
196 }
197 hasStatsCalculationTime = true;
198
105 }199 }
106 }200 }
201 delete[] outputBuffer;
202
203#ifdef _WIN32
204 WSACleanup();
205#endif
107}206}
108 207
109void runReceive(const char* addressOption, int port, int gap, int size, int report) {208void runReceive(const char* addressOption, int port, int gap, int size, int report) {
110 std::cout << "runReceive...\n";209 std::cout << "runReceive...\n";
111 210
211#ifdef _WIN32
212 WSADATA wsaData;
213 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
214 printf("WSAStartup failed with error %d\n", WSAGetLastError());
215 return;
216 }
217#endif
112 218
113 int sockfd,n;219 int sockfd, n;
114 struct sockaddr_in myaddr;220 struct sockaddr_in myaddr;
115 221
116 char* inputBuffer = new char[size];222 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
117 memset(inputBuffer, 0, size);223
118
119 sockfd=socket(AF_INET, SOCK_DGRAM, 0);
120
121 memset(&myaddr, 0, sizeof(myaddr));224 memset(&myaddr, 0, sizeof(myaddr));
122 myaddr.sin_family = AF_INET;225 myaddr.sin_family = AF_INET;
123 myaddr.sin_addr.s_addr=htonl(INADDR_ANY);226 myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
124 myaddr.sin_port=htons(port);227 myaddr.sin_port = htons(port);
125 228
126 const int SAMPLES_FOR_30_SECONDS = 30 * 1000000 / gap;
127 229
230 const int SAMPLES_FOR_SECOND = 1000000 / gap;
231 std::cout << "SAMPLES_FOR_SECOND:" << SAMPLES_FOR_SECOND << "\n";
232 const int INTERVALS_PER_30_SECONDS = 30;
233 std::cout << "INTERVALS_PER_30_SECONDS:" << INTERVALS_PER_30_SECONDS << "\n";
234 const int SAMPLES_FOR_30_SECONDS = 30 * SAMPLES_FOR_SECOND;
128 std::cout << "SAMPLES_FOR_30_SECONDS:" << SAMPLES_FOR_30_SECONDS << "\n";235 std::cout << "SAMPLES_FOR_30_SECONDS:" << SAMPLES_FOR_30_SECONDS << "\n";
236 const int REPORTS_FOR_30_SECONDS = 30 * MSECS_PER_SECOND / report;
237 std::cout << "REPORTS_FOR_30_SECONDS:" << REPORTS_FOR_30_SECONDS << "\n";
238
239 int intervalsPerReport = report / MSEC_TO_USEC;
240 if (intervalsPerReport < 1) {
241 intervalsPerReport = 1;
242 }
243 std::cout << "intervalsPerReport:" << intervalsPerReport << "\n";
244 MovingMinMaxAvg<int> timeGaps(SAMPLES_FOR_SECOND, INTERVALS_PER_30_SECONDS);
245 MovingMinMaxAvg<int> timeGapsPerReport(SAMPLES_FOR_SECOND, intervalsPerReport);
246
247 char* inputBuffer = new char[size];
248 memset(inputBuffer, 0, size);
249
250
251 SequenceNumberStats seqStats(REPORTS_FOR_30_SECONDS);
252
253 StDev stDevReportInterval;
254 StDev stDev30s;
255 StDev stDev;
256
257 SimpleMovingAverage averageNetworkTime(SAMPLES_FOR_30_SECONDS);
258 SimpleMovingAverage averageStatsCalcultionTime(SAMPLES_FOR_30_SECONDS);
259 float lastStatsCalculationTime = 0.0f; // we add out stats calculation time in the next calculation window
260 bool hasStatsCalculationTime = false;
129 261
130 MovingMinMaxAvg<int> timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats
131
132 if (bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {262 if (bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
133 std::cout << "bind failed\n";263 std::cout << "bind failed\n";
134 return;264 return;
135 } 265 }
136 266
137 quint64 last = 0; // first case267 quint64 last = 0; // first case
138 quint64 lastReport = 0;268 quint64 lastReport = 0;
139 269
140 while (true) {270 while (true) {
271
272 quint64 networkStart = usecTimestampNow();
141 n = recvfrom(sockfd, inputBuffer, size, 0, NULL, NULL); // we don't care about where it came from273 n = recvfrom(sockfd, inputBuffer, size, 0, NULL, NULL); // we don't care about where it came from
142 274 quint64 networkEnd = usecTimestampNow();
275 float networkElapsed = (float)(networkEnd - networkStart);
276
277 if (n < 0) {
278 std::cout << "Receive error: " << strerror(errno) << "\n";
279 }
280
281 // parse seq num
282 quint16 incomingSequenceNumber = *(reinterpret_cast<quint16*>(inputBuffer));
283 seqStats.sequenceNumberReceived(incomingSequenceNumber);
284
143 if (last == 0) {285 if (last == 0) {
144 last = usecTimestampNow();286 last = usecTimestampNow();
145 std::cout << "first packet received\n";287 std::cout << "first packet received\n";
146 } else {288 } else {
289
290 quint64 statsCalcultionStart = usecTimestampNow();
147 quint64 now = usecTimestampNow();291 quint64 now = usecTimestampNow();
148 int actualGap = now - last;292 int actualGap = now - last;
293
149 int gapDifferece = actualGap - gap;294 int gapDifferece = actualGap - gap;
150 timeGaps.update(gapDifferece);295 timeGaps.update(gapDifferece);
296 timeGapsPerReport.update(gapDifferece);
297 stDev.addValue(gapDifferece);
298 stDev30s.addValue(gapDifferece);
299 stDevReportInterval.addValue(gapDifferece);
151 last = now;300 last = now;
152 301
302 // track out network time and stats calculation times
303 averageNetworkTime.updateAverage(networkElapsed);
304
305 // for our stats calculation time, we actually delay the updating by one sample.
306 // we do this so that the calculation of the average timing for the stats calculation
307 // happen inside of the calculation processing. This ensures that tracking stats on
308 // stats calculation doesn't side effect the remaining running time.
309 if (hasStatsCalculationTime) {
310 averageStatsCalcultionTime.updateAverage(lastStatsCalculationTime);
311 }
312
153 if (now - lastReport >= (report * MSEC_TO_USEC)) {313 if (now - lastReport >= (report * MSEC_TO_USEC)) {
154 std::cout << "RECEIVE gap Difference From Expected "314
155 << "min: " << timeGaps.getMin() << " usecs, "315 seqStats.pushStatsToHistory();
156 << "max: " << timeGaps.getMax() << " usecs, "316
157 << "avg: " << timeGaps.getAverage() << " usecs, "317 std::cout << "RECEIVE gap Difference From Expected\n"
158 << "min last 30: " << timeGaps.getWindowMin() << " usecs, "318 << "Overall:\n"
159 << "max last 30: " << timeGaps.getWindowMax() << " usecs, "319 << "min: " << timeGaps.getMin() << " usecs, "
160 << "avg last 30: " << timeGaps.getWindowAverage() << " usecs "320 << "max: " << timeGaps.getMax() << " usecs, "
161 << "\n";321 << "avg: " << timeGaps.getAverage() << " usecs, "
322 << "stdev: " << stDev.getStDev() << " usecs\n"
323 << "Last 30s:\n"
324 << "min: " << timeGaps.getWindowMin() << " usecs, "
325 << "max: " << timeGaps.getWindowMax() << " usecs, "
326 << "avg: " << timeGaps.getWindowAverage() << " usecs, "
327 << "stdev: " << stDev30s.getStDev() << " usecs\n"
328 << "Last report interval:\n"
329 << "min: " << timeGapsPerReport.getWindowMin() << " usecs, "
330 << "max: " << timeGapsPerReport.getWindowMax() << " usecs, "
331 << "avg: " << timeGapsPerReport.getWindowAverage() << " usecs, "
332 << "stdev: " << stDevReportInterval.getStDev() << " usecs\n"
333 << "Average Execution Times Last 30s:\n"
334 << " network: " << averageNetworkTime.getAverage() << " usecs average\n"
335 << " stats: " << averageStatsCalcultionTime.getAverage() << " usecs average"
336 << "\n";
337 stDevReportInterval.reset();
338
339 if (stDev30s.getSamples() > SAMPLES_FOR_30_SECONDS) {
340 stDev30s.reset();
341 }
342
343 PacketStreamStats packetStatsLast30s = seqStats.getStatsForHistoryWindow();
344 PacketStreamStats packetStatsLastReportInterval = seqStats.getStatsForLastHistoryInterval();
345
346 std::cout << "RECEIVE Packet Stats\n"
347 << "Overall:\n"
348 << "lost: " << seqStats.getLost() << ", "
349 << "lost %: " << seqStats.getStats().getLostRate() * 100.0f << "%\n"
350 << "Last 30s:\n"
351 << "lost: " << packetStatsLast30s._lost << ", "
352 << "lost %: " << packetStatsLast30s.getLostRate() * 100.0f << "%\n"
353 << "Last report interval:\n"
354 << "lost: " << packetStatsLastReportInterval._lost << ", "
355 << "lost %: " << packetStatsLastReportInterval.getLostRate() * 100.0f << "%\n"
356 << "\n\n";
357
162 lastReport = now;358 lastReport = now;
163 }359 }
360
361 quint64 statsCalcultionEnd = usecTimestampNow();
362
363 lastStatsCalculationTime = (float)(statsCalcultionEnd - statsCalcultionStart);
364 if (lastStatsCalculationTime > LARGE_STATS_TIME) {
365 qDebug() << "WARNING -- unexpectedly large lastStatsCalculationTime=" << lastStatsCalculationTime;
366 }
367 hasStatsCalculationTime = true;
164 }368 }
165 }369 }
166}370 delete[] inputBuffer;
167 371
372#ifdef _WIN32
373 WSACleanup();
374#endif
375}
tests/metavoxels/CMakeLists.txt+5−25
@@ -1,32 +1,12 @@
1set(TARGET_NAME metavoxel-tests)1set(TARGET_NAME metavoxel-tests)
2 2
3set(ROOT_DIR ../..)3auto_mtc()
4set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
5 4
6# setup for find modules5include_glm()
7set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
8 6
9find_package(Qt5 COMPONENTS Network Script Widgets)7setup_hifi_project(Network Script Widgets)
10
11include(${MACRO_DIR}/AutoMTC.cmake)
12auto_mtc(${TARGET_NAME} "${ROOT_DIR}")
13
14include(${MACRO_DIR}/SetupHifiProject.cmake)
15setup_hifi_project(${TARGET_NAME} TRUE "${AUTOMTC_SRC}")
16
17#include glm
18include(${MACRO_DIR}/IncludeGLM.cmake)
19include_glm(${TARGET_NAME} "${ROOT_DIR}")
20 8
21# link in the shared libraries9# link in the shared libraries
22include(${MACRO_DIR}/LinkHifiLibrary.cmake)10link_hifi_libraries(metavoxels networking shared)
23link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}")
24link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
25link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
26
27IF (WIN32)
28 target_link_libraries(${TARGET_NAME} Winmm Ws2_32)
29ENDIF(WIN32)
30
31target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Script)
32 11
12link_shared_dependencies()
tests/networking/CMakeLists.txt+3−28
@@ -1,33 +1,8 @@
1set(TARGET_NAME networking-tests)1set(TARGET_NAME networking-tests)
2 2
3set(ROOT_DIR ../..)3setup_hifi_project()
4set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
5
6# setup for find modules
7set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
8
9#find_package(Qt5Network REQUIRED)
10#find_package(Qt5Script REQUIRED)
11#find_package(Qt5Widgets REQUIRED)
12
13include(${MACRO_DIR}/SetupHifiProject.cmake)
14setup_hifi_project(${TARGET_NAME} TRUE)
15
16include(${MACRO_DIR}/AutoMTC.cmake)
17auto_mtc(${TARGET_NAME} ${ROOT_DIR})
18
19#qt5_use_modules(${TARGET_NAME} Network Script Widgets)
20
21#include glm
22include(${MACRO_DIR}/IncludeGLM.cmake)
23include_glm(${TARGET_NAME} ${ROOT_DIR})
24 4
25# link in the shared libraries5# link in the shared libraries
26include(${MACRO_DIR}/LinkHifiLibrary.cmake)6link_hifi_libraries(shared networking)
27link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
28link_hifi_library(networking ${TARGET_NAME} ${ROOT_DIR})
29
30IF (WIN32)
31 target_link_libraries(${TARGET_NAME} Winmm Ws2_32)
32ENDIF(WIN32)
33 7
8link_shared_dependencies()
tests/networking/src/SequenceNumberStatsTests.cpp+4−3
@@ -9,11 +9,12 @@ · 8 unmodified lines
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//10//
11 11
12#include "SequenceNumberStatsTests.h"12#include <cassert>
13
14#include "SharedUtil.h"
15#include <limits>13#include <limits>
16 14
15#include <SharedUtil.h>
16
17#include "SequenceNumberStatsTests.h"
17 18
18void SequenceNumberStatsTests::runAllTests() {19void SequenceNumberStatsTests::runAllTests() {
19 rolloverTest();20 rolloverTest();
tests/octree/CMakeLists.txt+14−39
@@ -1,44 +1,19 @@
1set(TARGET_NAME octree-tests)1set(TARGET_NAME octree-tests)
2 2
3set(ROOT_DIR ../..)3setup_hifi_project(Script Network)
4set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
5 4
6# setup for find modules5include_glm()
7set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
8
9find_package(Qt5Network REQUIRED)
10find_package(Qt5Script REQUIRED)
11find_package(Qt5Widgets REQUIRED)
12
13include(${MACRO_DIR}/SetupHifiProject.cmake)
14setup_hifi_project(${TARGET_NAME} TRUE)
15
16include(${MACRO_DIR}/AutoMTC.cmake)
17auto_mtc(${TARGET_NAME} ${ROOT_DIR})
18
19qt5_use_modules(${TARGET_NAME} Network Script Widgets)
20
21#include glm
22include(${MACRO_DIR}/IncludeGLM.cmake)
23include_glm(${TARGET_NAME} ${ROOT_DIR})
24 6
25# link in the shared libraries7# link in the shared libraries
26include(${MACRO_DIR}/LinkHifiLibrary.cmake)8//link_hifi_library(entities ${TARGET_NAME} ${ROOT_DIR})
27link_hifi_library(entities ${TARGET_NAME} ${ROOT_DIR})9//link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR})
28link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR})10//link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR})
29link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR})11//link_hifi_library(networking ${TARGET_NAME} ${ROOT_DIR})
30link_hifi_library(networking ${TARGET_NAME} ${ROOT_DIR})12//link_hifi_library(animation ${TARGET_NAME} ${ROOT_DIR})
31link_hifi_library(animation ${TARGET_NAME} ${ROOT_DIR})13//link_hifi_library(fbx ${TARGET_NAME} ${ROOT_DIR})
32link_hifi_library(fbx ${TARGET_NAME} ${ROOT_DIR})14//link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
33link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})15//link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR})
34link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR})16
35 17link_hifi_libraries(animation fbx entities networking octree shared)
36IF (WIN32)18
37 # add a definition for ssize_t so that windows doesn't bail19link_shared_dependencies()
38 add_definitions(-Dssize_t=long)
39
40 #target_link_libraries(${TARGET_NAME} Winmm Ws2_32)
41 target_link_libraries(${TARGET_NAME} wsock32.lib)
42ENDIF(WIN32)
43
44
tests/physics/CMakeLists.txt+4−26
@@ -1,32 +1,10 @@
1set(TARGET_NAME physics-tests)1set(TARGET_NAME physics-tests)
2 2
3set(ROOT_DIR ../..)3setup_hifi_project()
4set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
5 4
6# setup for find modules5include_glm()
7set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
8
9#find_package(Qt5Network REQUIRED)
10#find_package(Qt5Script REQUIRED)
11#find_package(Qt5Widgets REQUIRED)
12
13include(${MACRO_DIR}/SetupHifiProject.cmake)
14setup_hifi_project(${TARGET_NAME} TRUE)
15
16include(${MACRO_DIR}/AutoMTC.cmake)
17auto_mtc(${TARGET_NAME} ${ROOT_DIR})
18
19#qt5_use_modules(${TARGET_NAME} Network Script Widgets)
20
21#include glm
22include(${MACRO_DIR}/IncludeGLM.cmake)
23include_glm(${TARGET_NAME} ${ROOT_DIR})
24 6
25# link in the shared libraries7# link in the shared libraries
26include(${MACRO_DIR}/LinkHifiLibrary.cmake)8link_hifi_libraries(shared)
27link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
28
29IF (WIN32)
30 #target_link_libraries(${TARGET_NAME} Winmm Ws2_32)
31ENDIF(WIN32)
32 9
10link_shared_dependencies()
tests/shared/CMakeLists.txt+4−26
@@ -1,32 +1,10 @@
1set(TARGET_NAME shared-tests)1set(TARGET_NAME shared-tests)
2 2
3set(ROOT_DIR ../..)3setup_hifi_project()
4set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
5 4
6# setup for find modules5include_glm()
7set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
8
9#find_package(Qt5Network REQUIRED)
10#find_package(Qt5Script REQUIRED)
11#find_package(Qt5Widgets REQUIRED)
12
13include(${MACRO_DIR}/SetupHifiProject.cmake)
14setup_hifi_project(${TARGET_NAME} TRUE)
15
16include(${MACRO_DIR}/AutoMTC.cmake)
17auto_mtc(${TARGET_NAME} ${ROOT_DIR})
18
19#qt5_use_modules(${TARGET_NAME} Network Script Widgets)
20
21#include glm
22include(${MACRO_DIR}/IncludeGLM.cmake)
23include_glm(${TARGET_NAME} ${ROOT_DIR})
24 6
25# link in the shared libraries7# link in the shared libraries
26include(${MACRO_DIR}/LinkHifiLibrary.cmake)8link_hifi_libraries(shared)
27link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
28
29IF (WIN32)
30 #target_link_libraries(${TARGET_NAME} Winmm Ws2_32)
31ENDIF(WIN32)
32 9
10link_shared_dependencies()
tools/CMakeLists.txt+0−1
@@ -1,4 +1,3 @@
1
2# add the tool directories1# add the tool directories
3add_subdirectory(bitstream2json)2add_subdirectory(bitstream2json)
4add_subdirectory(json2bitstream)3add_subdirectory(json2bitstream)
tools/bitstream2json/CMakeLists.txt+4−21
@@ -1,25 +1,8 @@
1set(TARGET_NAME bitstream2json)1set(TARGET_NAME bitstream2json)
2setup_hifi_project(Widgets Script)
2 3
3set(ROOT_DIR ../..)4include_glm()
4set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
5 5
6# setup for find modules6link_hifi_libraries(metavoxels)
7set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
8 7
9find_package(Qt5 COMPONENTS Network Script Widgets)8link_shared_dependencies()
10
11include(${MACRO_DIR}/SetupHifiProject.cmake)
12setup_hifi_project(${TARGET_NAME} TRUE)
13
14link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}")
15link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
16link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
17
18include(${MACRO_DIR}/IncludeGLM.cmake)
19include_glm(${TARGET_NAME} "${ROOT_DIR}")
20
21IF (WIN32)
22 target_link_libraries(${TARGET_NAME} Winmm Ws2_32)
23ENDIF(WIN32)
24
25target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Script)
tools/json2bitstream/CMakeLists.txt+4−21
@@ -1,25 +1,8 @@
1set(TARGET_NAME json2bitstream)1set(TARGET_NAME json2bitstream)
2setup_hifi_project(Widgets Script)
2 3
3set(ROOT_DIR ../..)4include_glm()
4set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
5 5
6# setup for find modules6link_hifi_libraries(metavoxels)
7set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
8 7
9find_package(Qt5 COMPONENTS Network Script Widgets)8link_shared_dependencies()
10
11include(${MACRO_DIR}/SetupHifiProject.cmake)
12setup_hifi_project(${TARGET_NAME} TRUE)
13
14link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}")
15link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
16link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
17
18include(${MACRO_DIR}/IncludeGLM.cmake)
19include_glm(${TARGET_NAME} "${ROOT_DIR}")
20
21IF (WIN32)
22 target_link_libraries(${TARGET_NAME} Winmm Ws2_32)
23ENDIF(WIN32)
24
25target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Script)
tools/mtc/CMakeLists.txt+2−5
@@ -1,7 +1,4 @@
1set(TARGET_NAME mtc)1set(TARGET_NAME mtc)
2setup_hifi_project()
2 3
3set(ROOT_DIR ../..)4link_shared_dependencies()
4set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
5
6include(${MACRO_DIR}/SetupHifiProject.cmake)
7setup_hifi_project(${TARGET_NAME} TRUE)
voxel-edit/CMakeLists.txt+4−35
@@ -1,40 +1,9 @@
1set(TARGET_NAME voxel-edit)1set(TARGET_NAME voxel-edit)
2 2
3set(ROOT_DIR ..)3setup_hifi_project()
4set(MACRO_DIR "${ROOT_DIR}/cmake/macros")
5 4
6# setup for find modules5include_glm()
7set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/")
8 6
9# set up the external glm library7link_hifi_libraries(networking octree shared voxels)
10include(${MACRO_DIR}/IncludeGLM.cmake)
11include_glm(${TARGET_NAME} "${ROOT_DIR}")
12 8
13find_package(Qt5Script REQUIRED)9link_shared_dependencies()
14
15include(${MACRO_DIR}/SetupHifiProject.cmake)
16setup_hifi_project(${TARGET_NAME} TRUE)
17
18# link in the shared library
19include(${MACRO_DIR}/LinkHifiLibrary.cmake)
20link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}")
21
22# link in the hifi octree library
23link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}")
24
25# link in the hifi voxels library
26link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}")
27
28# link in the hifi networking library
29link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}")
30
31IF (WIN32)
32 target_link_libraries(${TARGET_NAME} Winmm Ws2_32)
33ENDIF(WIN32)
34
35target_link_libraries(${TARGET_NAME} Qt5::Script)
36
37# add a definition for ssize_t so that windows doesn't bail
38if (WIN32)
39 add_definitions(-Dssize_t=long)
40endif ()

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

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

Repository code

Go to file
t