History

Merge with master

Sam Gondelman committed 11 years ago

Commit 19ec0802 parents 778e19a 0bef506214 files · +6701 −6001Browse files

Unified · Split

214 files
  1. CMakeLists.txt +1 −1
  2. assignment-client/src/audio/AudioMixerClientData.cpp +4 −4
  3. assignment-client/src/octree/OctreeServer.cpp +135 −130
  4. cmake/externals/LibOVR/CMakeLists.txt +7 −3
  5. cmake/externals/boostconfig/CMakeLists.txt +7 −7
  6. cmake/externals/glew/CMakeLists.txt +10 −5
  7. cmake/externals/oglplus/CMakeLists.txt +7 −7
  8. cmake/externals/tbb/CMakeLists.txt +7 −2
  9. cmake/macros/SetupHifiOpenGL.cmake +43 −0
  10. cmake/modules/FindFaceshift.cmake +5 −1
  11. cmake/modules/FindNSIGHT.cmake +16 −6
  12. cmake/modules/FindSixense.cmake +13 −5
  13. cmake/modules/FindTBB.cmake +1 −1
  14. examples/controllers/hydra/gun.js +7 −9
  15. examples/defaultScripts.js +0 −1
  16. examples/dice.js +6 −8
  17. examples/edit.js +7 −35
  18. examples/html/style.css +12 −14
  19. examples/libraries/toolBars.js +47 −6
  20. examples/mouseLook.js +38 −19
  21. examples/paint.js +44 −339
  22. examples/pointer.js +3 −9
  23. examples/stick.js +3 −1
  24. examples/utilities.js +39 −35
  25. examples/utilities/tools/cookies.js +25 −0
  26. examples/utilities/tools/renderEngineDebug.js +42 −39
  27. interface/resources/images/address-bar.svg +21 −5
  28. interface/resources/images/arrow.png +0 −0
  29. interface/resources/images/left-arrow.svg +50 −0
  30. interface/resources/images/redarrow.svg +11 −0
  31. interface/resources/images/redarrow_reversed.svg +11 −0
  32. interface/resources/images/right-arrow.svg +11 −0
  33. interface/resources/qml/AddressBarDialog.qml +68 −22
  34. interface/resources/qml/AvatarInputs.qml +177 −0
  35. interface/resources/qml/Stats.qml +258 −0
  36. interface/resources/qml/Tooltip.qml +31 −0
  37. interface/src/Application.cpp +115 −156
  38. interface/src/Application.h +37 −28
  39. interface/src/Camera.cpp +0 −16
  40. interface/src/Camera.h +4 −10
  41. interface/src/GLCanvas.cpp +2 −2
  42. interface/src/InterfaceActionFactory.cpp +3 −3
  43. interface/src/LODManager.cpp +3 −3
  44. interface/src/Menu.cpp +6 −0
  45. interface/src/Menu.h +1 −0
  46. interface/src/ModelPropertiesDialog.cpp +26 −26
  47. interface/src/Stars.cpp +8 −10
  48. interface/src/UIUtil.cpp +1 −1
  49. interface/src/Util.cpp +25 −22
  50. interface/src/audio/AudioIOStatsRenderer.cpp +69 −55
  51. interface/src/audio/AudioToolBox.cpp +0 −114
  52. interface/src/audio/AudioToolBox.h +0 −36
  53. interface/src/avatar/Avatar.cpp +110 −121
  54. interface/src/avatar/Avatar.h +5 −5
  55. interface/src/avatar/AvatarActionHold.cpp +10 −1
  56. interface/src/avatar/AvatarManager.cpp +17 −5
  57. interface/src/avatar/AvatarManager.h +1 −1
  58. interface/src/avatar/Head.cpp +13 −6
  59. interface/src/avatar/MyAvatar.cpp +81 −81
  60. interface/src/avatar/MyAvatar.h +1 −1
  61. interface/src/devices/CameraToolBox.cpp +0 −121
  62. interface/src/devices/CameraToolBox.h +0 −45
  63. interface/src/devices/DdeFaceTracker.cpp +6 −5
  64. interface/src/devices/OculusManager.cpp +469 −436
  65. interface/src/devices/OculusManager.h +7 −170
  66. interface/src/devices/SDL2Manager.cpp +2 −0
  67. interface/src/devices/SixenseManager.cpp +58 −50
  68. interface/src/devices/TV3DManager.cpp +9 −9
  69. interface/src/main.cpp +1 −1
  70. interface/src/scripting/ControllerScriptingInterface.cpp +1 −1
  71. interface/src/scripting/ControllerScriptingInterface.h +1 −0
  72. interface/src/scripting/HMDScriptingInterface.cpp +3 −3
  73. interface/src/scripting/HMDScriptingInterface.h +2 −2
  74. interface/src/starfield/renderer/Renderer.cpp +9 −0
  75. interface/src/ui/AddressBarDialog.cpp +24 −0
  76. interface/src/ui/AddressBarDialog.h +13 −0
  77. interface/src/ui/ApplicationCompositor.cpp +761 −0
  78. interface/src/ui/ApplicationCompositor.h +120 −0
  79. interface/src/ui/ApplicationOverlay.cpp +116 −1172
  80. interface/src/ui/ApplicationOverlay.h +14 −118
  81. interface/src/ui/AvatarInputs.cpp +134 −0
  82. interface/src/ui/AvatarInputs.h +59 −0
  83. interface/src/ui/FlowLayout.cpp +9 −0
  84. interface/src/ui/HMDToolsDialog.cpp +4 −59
  85. interface/src/ui/HMDToolsDialog.h +0 −4
  86. interface/src/ui/LogDialog.cpp +9 −0
  87. interface/src/ui/PreferencesDialog.cpp +2 −2
  88. interface/src/ui/RearMirrorTools.cpp +0 −134
  89. interface/src/ui/RearMirrorTools.h +0 −56
  90. interface/src/ui/Stats.cpp +221 −466
  91. interface/src/ui/Stats.h +121 −32
  92. interface/src/ui/UserInputMapper.cpp +1 −1
  93. interface/src/ui/overlays/Circle3DOverlay.cpp +161 −181
  94. interface/src/ui/overlays/Line3DOverlay.cpp +10 −0
  95. interface/src/ui/overlays/Line3DOverlay.h +1 −0
  96. interface/src/ui/overlays/Overlays.cpp +1 −1
  97. interface/src/ui/overlays/TextOverlay.cpp +1 −0
  98. libraries/audio-client/src/AudioClient.cpp +24 −1
  99. libraries/audio-client/src/AudioClient.h +6 −1
  100. libraries/audio-client/src/AudioNoiseGate.cpp +28 −15
  101. libraries/audio-client/src/AudioNoiseGate.h +1 −0
  102. libraries/audio/CMakeLists.txt +7 −1
  103. libraries/audio/src/AudioInjector.cpp +65 −4
  104. libraries/audio/src/AudioInjector.h +4 −0
  105. libraries/audio/src/AudioInjectorLocalBuffer.cpp +1 −4
  106. libraries/audio/src/AudioInjectorLocalBuffer.h +0 −3
  107. libraries/audio/src/AudioRingBuffer.cpp +1 −1
  108. libraries/avatars/src/AvatarData.cpp +2 −3
  109. libraries/avatars/src/AvatarData.h +1 −2
  110. libraries/entities-renderer/CMakeLists.txt +0 −6
  111. libraries/entities-renderer/src/EntityTreeRenderer.cpp +6 −60
  112. libraries/entities-renderer/src/EntityTreeRenderer.h +0 −1
  113. libraries/entities-renderer/src/RenderableLineEntityItem.cpp +3 −3
  114. libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +11 −7
  115. libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +6 −4
  116. libraries/entities/src/DeleteEntityOperator.cpp +1 −0
  117. libraries/entities/src/EntityActionInterface.cpp +4 −4
  118. libraries/entities/src/EntityActionInterface.h +1 −1
  119. libraries/entities/src/EntityItem.cpp +2 −2
  120. libraries/entities/src/EntityItemID.h +1 −1
  121. libraries/entities/src/EntityItemProperties.h +2 −0
  122. libraries/entities/src/EntityScriptingInterface.cpp +52 −0
  123. libraries/entities/src/EntityScriptingInterface.h +5 −0
  124. libraries/entities/src/LineEntityItem.cpp +28 −13
  125. libraries/entities/src/LineEntityItem.h +3 −1
  126. libraries/entities/src/PolyVoxEntityItem.cpp +7 −0
  127. libraries/entities/src/PolyVoxEntityItem.h +7 −4
  128. libraries/fbx/src/FBXReader.cpp +37 −6
  129. libraries/gpu/src/gpu/Batch.h +3 −1
  130. libraries/gpu/src/gpu/GLBackend.cpp +57 −0
  131. libraries/gpu/src/gpu/GLBackend.h +9 −1
  132. libraries/gpu/src/gpu/GLBackendOutput.cpp +1 −0
  133. libraries/gpu/src/gpu/GLBackendShared.h +9 −9
  134. libraries/gpu/src/gpu/GLBackendTexture.cpp +3 −2
  135. libraries/gpu/src/gpu/GLBackendTransform.cpp +13 −16
  136. libraries/gpu/src/gpu/Texture.cpp +10 −10
  137. libraries/model/src/model/Light.cpp +1 −1
  138. libraries/model/src/model/Skybox.cpp +2 −2
  139. libraries/model/src/model/Stage.cpp +6 −6
  140. libraries/model/src/model/Stage.h +1 −1
  141. libraries/networking/src/AddressManager.cpp +4 −0
  142. libraries/networking/src/AddressManager.h +3 −0
  143. libraries/networking/src/BandwidthRecorder.cpp +2 −2
  144. libraries/octree/src/CoverageMap.cpp +1 −1
  145. libraries/octree/src/CoverageMapV2.cpp +1 −1
  146. libraries/octree/src/OctreeElement.cpp +28 −26
  147. libraries/octree/src/OctreePacketData.cpp +5 −3
  148. libraries/octree/src/OctreePersistThread.cpp +13 −0
  149. libraries/octree/src/OctreeProjectedPolygon.cpp +104 −103
  150. libraries/octree/src/OctreeSceneStats.cpp +3 −3
  151. libraries/octree/src/Plane.cpp +2 −1
  152. libraries/octree/src/ViewFrustum.cpp +57 −55
  153. libraries/physics/src/EntityMotionState.cpp +2 −2
  154. libraries/physics/src/MeshMassProperties.cpp +4 −0
  155. libraries/physics/src/ObjectAction.cpp +1 −1
  156. libraries/physics/src/ObjectAction.h +1 −0
  157. libraries/physics/src/ObjectActionOffset.cpp +109 −0
  158. libraries/physics/src/ObjectActionOffset.h +35 −0
  159. libraries/physics/src/ObjectActionPullToPoint.cpp +0 −72
  160. libraries/physics/src/ObjectActionPullToPoint.h +0 −34
  161. libraries/render-utils/CMakeLists.txt +37 −27
  162. libraries/render-utils/src/DeferredLightingEffect.cpp +25 −6
  163. libraries/render-utils/src/DeferredLightingEffect.h +5 −3
  164. libraries/render-utils/src/GeometryCache.cpp +82 −39
  165. libraries/render-utils/src/GeometryCache.h +9 −1
  166. libraries/render-utils/src/Model.cpp +10 −5
  167. libraries/render-utils/src/OffscreenQmlSurface.cpp +6 −2
  168. libraries/render-utils/src/OglplusHelpers.cpp +325 −0
  169. libraries/render-utils/src/OglplusHelpers.h +173 −0
  170. libraries/render-utils/src/ProgramObject.h +12 −3
  171. libraries/render-utils/src/RenderDeferredTask.cpp +114 −176
  172. libraries/render-utils/src/RenderDeferredTask.h +25 −24
  173. libraries/render-utils/src/TextRenderer.cpp +9 −0
  174. libraries/render-utils/src/TextRenderer3D.cpp +14 −28
  175. libraries/render-utils/src/TextRenderer3D.h +9 −12
  176. libraries/render-utils/src/sdf_text3D.slf +11 −6
  177. libraries/render-utils/src/sdf_text3D.slv +6 −0
  178. libraries/render-utils/src/standardDrawTexture.slf +24 −0
  179. libraries/render-utils/src/standardTransformPNTC.slv +35 −0
  180. libraries/render-utils/src/stars.slf +76 −0
  181. libraries/render/src/render/DrawTask.cpp +54 −229
  182. libraries/render/src/render/DrawTask.h +172 −24
  183. libraries/render/src/render/Engine.h +4 −0
  184. libraries/script-engine/src/AbstractControllerScriptingInterface.h +1 −0
  185. libraries/script-engine/src/AudioScriptingInterface.cpp +1 −18
  186. libraries/script-engine/src/SceneScriptingInterface.cpp +2 −0
  187. libraries/script-engine/src/SceneScriptingInterface.h +9 −1
  188. libraries/script-engine/src/ScriptEngine.cpp +4 −1
  189. libraries/script-engine/src/ScriptEngine.h +1 −1
  190. libraries/script-engine/src/TouchEvent.cpp +13 −13
  191. libraries/shared/CMakeLists.txt +2 −1
  192. libraries/shared/src/AABox.cpp +38 −38
  193. libraries/shared/src/AACube.cpp +35 −35
  194. libraries/shared/src/AngularConstraint.cpp +1 −1
  195. libraries/shared/src/GLMHelpers.cpp +1 −1
  196. libraries/shared/src/GLMHelpers.h +24 −0
  197. libraries/shared/src/MatrixStack.h +5 −1
  198. libraries/shared/src/OctalCode.cpp +33 −33
  199. libraries/shared/src/PhysicsCollisionGroups.h +1 −1
  200. libraries/shared/src/RegisteredMetaTypes.cpp +12 −0
  201. libraries/shared/src/RegisteredMetaTypes.h +1 −0
  202. libraries/shared/src/ShapeCollider.cpp +1 −1
  203. libraries/shared/src/Transform.h +2 −2
  204. libraries/shared/src/VariantMapToScriptValue.cpp +39 −13
  205. libraries/shared/src/VariantMapToScriptValue.h +2 −0
  206. libraries/ui/src/Tooltip.cpp +51 −0
  207. libraries/ui/src/Tooltip.h +45 −0
  208. libraries/ui/src/VrMenu.cpp +2 −2
  209. tests/physics/src/ShapeColliderTests.cpp +257 −257
  210. tests/render-utils/src/main.cpp +9 −0
  211. tests/shared/src/AngularConstraintTests.cpp +1 −1
  212. tests/shared/src/MovingMinMaxAvgTests.cpp +9 −8
  213. tools/vhacd-util/src/VHACDUtil.cpp +1 −1
  214. tools/vhacd-util/src/VHACDUtilApp.cpp +1 −0
CMakeLists.txt+1−1
@@ -49,7 +49,7 @@ if (WIN32) · 48 unmodified lines
4949 else ()
5050 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -fno-strict-aliasing -Wno-unused-parameter")
5151 if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
52− set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb")
52+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -Woverloaded-virtual -Wdouble-promotion")
5353 endif ()
5454 endif(WIN32)
5555
assignment-client/src/audio/AudioMixerClientData.cpp+4−4
@@ -295,10 +295,10 @@ void AudioMixerClientData::printUpstreamDownstreamStats() const { · 294 unmodified lines
295295
296296 void AudioMixerClientData::printAudioStreamStats(const AudioStreamStats& streamStats) const {
297297 printf(" Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)\n",
298− streamStats._packetStreamStats.getLostRate() * 100.0f,
299− streamStats._packetStreamStats._lost,
300− streamStats._packetStreamWindowStats.getLostRate() * 100.0f,
301− streamStats._packetStreamWindowStats._lost);
298+ (double)(streamStats._packetStreamStats.getLostRate() * 100.0f),
299+ streamStats._packetStreamStats._lost,
300+ (double)(streamStats._packetStreamWindowStats.getLostRate() * 100.0f),
301+ streamStats._packetStreamWindowStats._lost);
302302
303303 printf(" Ringbuffer frames | desired: %u, avg_available(10s): %u, available: %u\n",
304304 streamStats._desiredJitterBufferFrames,
assignment-client/src/octree/OctreeServer.cpp+135−130
@@ -127,7 +127,7 @@ void OctreeServer::resetSendingStats() { · 126 unmodified lines
127127 _noProcessWait = 0;
128128 }
129129
130−void OctreeServer::trackEncodeTime(float time) {
130+void OctreeServer::trackEncodeTime(float time) {
131131 const float MAX_SHORT_TIME = 10.0f;
132132 const float MAX_LONG_TIME = 100.0f;
133133
@@ -144,10 +144,10 @@ void OctreeServer::trackEncodeTime(float time) { · 10 unmodified lines
144144 _extraLongEncode++;
145145 _averageExtraLongEncodeTime.updateAverage(time);
146146 }
147− _averageEncodeTime.updateAverage(time);
147+ _averageEncodeTime.updateAverage(time);
148148 }
149149
150−void OctreeServer::trackTreeWaitTime(float time) {
150+void OctreeServer::trackTreeWaitTime(float time) {
151151 const float MAX_SHORT_TIME = 10.0f;
152152 const float MAX_LONG_TIME = 100.0f;
153153 if (time == SKIP_TIME) {
@@ -166,7 +166,7 @@ void OctreeServer::trackTreeWaitTime(float time) { · 12 unmodified lines
166166 _averageTreeWaitTime.updateAverage(time);
167167 }
168168
169−void OctreeServer::trackCompressAndWriteTime(float time) {
169+void OctreeServer::trackCompressAndWriteTime(float time) {
170170 const float MAX_SHORT_TIME = 10.0f;
171171 const float MAX_LONG_TIME = 100.0f;
172172 if (time == SKIP_TIME) {
@@ -182,19 +182,19 @@ void OctreeServer::trackCompressAndWriteTime(float time) { · 9 unmodified lines
182182 _extraLongCompress++;
183183 _averageExtraLongCompressTime.updateAverage(time);
184184 }
185− _averageCompressAndWriteTime.updateAverage(time);
185+ _averageCompressAndWriteTime.updateAverage(time);
186186 }
187187
188−void OctreeServer::trackPacketSendingTime(float time) {
188+void OctreeServer::trackPacketSendingTime(float time) {
189189 if (time == SKIP_TIME) {
190190 _noSend++;
191191 time = 0.0f;
192192 }
193− _averagePacketSendingTime.updateAverage(time);
193+ _averagePacketSendingTime.updateAverage(time);
194194 }
195195
196196
197−void OctreeServer::trackProcessWaitTime(float time) {
197+void OctreeServer::trackProcessWaitTime(float time) {
198198 const float MAX_SHORT_TIME = 10.0f;
199199 const float MAX_LONG_TIME = 100.0f;
200200 if (time == SKIP_TIME) {
@@ -243,9 +243,9 @@ OctreeServer::OctreeServer(const QByteArray& packet) : · 42 unmodified lines
243243
244244 _averageLoopTime.updateAverage(0);
245245 qDebug() << "Octree server starting... [" << this << "]";
246−
246+
247247 // make sure the AccountManager has an Auth URL for payment redemptions
248−
248+
249249 AccountManager::getInstance().setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL);
250250 }
251251
@@ -278,13 +278,13 @@ OctreeServer::~OctreeServer() { · 26 unmodified lines
278278
279279 delete _jurisdiction;
280280 _jurisdiction = NULL;
281−
281+
282282 // cleanup our tree here...
283283 qDebug() << qPrintable(_safeServerName) << "server START cleaning up octree... [" << this << "]";
284284 delete _tree;
285285 _tree = NULL;
286286 qDebug() << qPrintable(_safeServerName) << "server DONE cleaning up octree... [" << this << "]";
287−
287+
288288 if (_instance == this) {
289289 _instance = NULL; // we are gone
290290 }
@@ -400,10 +400,10 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 109 unmodified lines
400400 statsString += QString().sprintf(" Internal Elements: %s nodes (%5.2f%%)\r\n",
401401 locale.toString((uint)internalNodeCount).rightJustified(16,
402402 ' ').toLocal8Bit().constData(),
403− ((float)internalNodeCount / (float)nodeCount) * AS_PERCENT);
403+ (double)((internalNodeCount / (float)nodeCount) * AS_PERCENT));
404404 statsString += QString().sprintf(" Leaf Elements: %s nodes (%5.2f%%)\r\n",
405405 locale.toString((uint)leafNodeCount).rightJustified(16, ' ').toLocal8Bit().constData(),
406− ((float)leafNodeCount / (float)nodeCount) * AS_PERCENT);
406+ (double)((leafNodeCount / (float)nodeCount) * AS_PERCENT));
407407 statsString += "\r\n";
408408 statsString += "\r\n";
409409
@@ -422,7 +422,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 12 unmodified lines
422422 .arg(locale.toString((uint)getCurrentClientCount()).rightJustified(COLUMN_WIDTH, ' '));
423423
424424 quint64 oneSecondAgo = usecTimestampNow() - USECS_PER_SECOND;
425−
425+
426426 statsString += QString(" process() last second: %1 clients\r\n")
427427 .arg(locale.toString((uint)howManyThreadsDidProcess(oneSecondAgo)).rightJustified(COLUMN_WIDTH, ' '));
428428 statsString += QString(" packetDistributor() last second: %1 clients\r\n")
@@ -434,13 +434,13 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 5 unmodified lines
434434
435435 float averageLoopTime = getAverageLoopTime();
436436 statsString += QString().sprintf(" Average packetLoop() time: %7.2f msecs"
437− " samples: %12d \r\n",
438− averageLoopTime, _averageLoopTime.getSampleCount());
437+ " samples: %12d \r\n",
438+ (double)averageLoopTime, _averageLoopTime.getSampleCount());
439439
440440 float averageInsideTime = getAverageInsideTime();
441441 statsString += QString().sprintf(" Average 'inside' time: %9.2f usecs"
442− " samples: %12d \r\n\r\n",
443− averageInsideTime, _averageInsideTime.getSampleCount());
442+ " samples: %12d \r\n\r\n",
443+ (double)averageInsideTime, _averageInsideTime.getSampleCount());
444444
445445
446446 // Process Wait
@@ -450,30 +450,30 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 3 unmodified lines
450450 float averageProcessWaitTime = getAverageProcessWaitTime();
451451 statsString += QString().sprintf(" Average process lock wait time:"
452452 " %9.2f usecs samples: %12d \r\n",
453− averageProcessWaitTime, allWaitTimes);
453+ (double)averageProcessWaitTime, allWaitTimes);
454454
455455 float zeroVsTotal = (allWaitTimes > 0) ? ((float)_noProcessWait / (float)allWaitTimes) : 0.0f;
456456 statsString += QString().sprintf(" No Lock Wait:"
457457 " (%6.2f%%) samples: %12d \r\n",
458− zeroVsTotal * AS_PERCENT, _noProcessWait);
458+ (double)(zeroVsTotal * AS_PERCENT), _noProcessWait);
459459
460460 float shortVsTotal = (allWaitTimes > 0) ? ((float)_shortProcessWait / (float)allWaitTimes) : 0.0f;
461461 statsString += QString().sprintf(" Avg process lock short wait time:"
462462 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",
463− _averageProcessShortWaitTime.getAverage(),
464− shortVsTotal * AS_PERCENT, _shortProcessWait);
463+ (double)_averageProcessShortWaitTime.getAverage(),
464+ (double)(shortVsTotal * AS_PERCENT), _shortProcessWait);
465465
466466 float longVsTotal = (allWaitTimes > 0) ? ((float)_longProcessWait / (float)allWaitTimes) : 0.0f;
467467 statsString += QString().sprintf(" Avg process lock long wait time:"
468468 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",
469− _averageProcessLongWaitTime.getAverage(),
470− longVsTotal * AS_PERCENT, _longProcessWait);
469+ (double)_averageProcessLongWaitTime.getAverage(),
470+ (double)(longVsTotal * AS_PERCENT), _longProcessWait);
471471
472472 float extraLongVsTotal = (allWaitTimes > 0) ? ((float)_extraLongProcessWait / (float)allWaitTimes) : 0.0f;
473473 statsString += QString().sprintf("Avg process lock extralong wait time:"
474474 " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n",
475− _averageProcessExtraLongWaitTime.getAverage(),
476− extraLongVsTotal * AS_PERCENT, _extraLongProcessWait);
475+ (double)_averageProcessExtraLongWaitTime.getAverage(),
476+ (double)(extraLongVsTotal * AS_PERCENT), _extraLongProcessWait);
477477 }
478478
479479 // Tree Wait
@@ -482,122 +482,125 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 2 unmodified lines
482482 float averageTreeWaitTime = getAverageTreeWaitTime();
483483 statsString += QString().sprintf(" Average tree lock wait time:"
484484 " %9.2f usecs samples: %12d \r\n",
485− averageTreeWaitTime, allWaitTimes);
485+ (double)averageTreeWaitTime, allWaitTimes);
486486
487487 float zeroVsTotal = (allWaitTimes > 0) ? ((float)_noTreeWait / (float)allWaitTimes) : 0.0f;
488488 statsString += QString().sprintf(" No Lock Wait:"
489489 " (%6.2f%%) samples: %12d \r\n",
490− zeroVsTotal * AS_PERCENT, _noTreeWait);
490+ (double)(zeroVsTotal * AS_PERCENT), _noTreeWait);
491491
492492 float shortVsTotal = (allWaitTimes > 0) ? ((float)_shortTreeWait / (float)allWaitTimes) : 0.0f;
493493 statsString += QString().sprintf(" Avg tree lock short wait time:"
494494 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",
495− _averageTreeShortWaitTime.getAverage(),
496− shortVsTotal * AS_PERCENT, _shortTreeWait);
495+ (double)_averageTreeShortWaitTime.getAverage(),
496+ (double)(shortVsTotal * AS_PERCENT), _shortTreeWait);
497497
498498 float longVsTotal = (allWaitTimes > 0) ? ((float)_longTreeWait / (float)allWaitTimes) : 0.0f;
499499 statsString += QString().sprintf(" Avg tree lock long wait time:"
500500 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",
501− _averageTreeLongWaitTime.getAverage(),
502− longVsTotal * AS_PERCENT, _longTreeWait);
501+ (double)_averageTreeLongWaitTime.getAverage(),
502+ (double)(longVsTotal * AS_PERCENT), _longTreeWait);
503503
504504 float extraLongVsTotal = (allWaitTimes > 0) ? ((float)_extraLongTreeWait / (float)allWaitTimes) : 0.0f;
505505 statsString += QString().sprintf(" Avg tree lock extra long wait time:"
506506 " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n",
507− _averageTreeExtraLongWaitTime.getAverage(),
508− extraLongVsTotal * AS_PERCENT, _extraLongTreeWait);
507+ (double)_averageTreeExtraLongWaitTime.getAverage(),
508+ (double)(extraLongVsTotal * AS_PERCENT), _extraLongTreeWait);
509509
510510 // encode
511511 float averageEncodeTime = getAverageEncodeTime();
512− statsString += QString().sprintf(" Average encode time: %9.2f usecs\r\n", averageEncodeTime);
513−
512+ statsString += QString().sprintf(" Average encode time: %9.2f usecs\r\n", (double)averageEncodeTime);
513+
514514 int allEncodeTimes = _noEncode + _shortEncode + _longEncode + _extraLongEncode;
515515
516516 float zeroVsTotalEncode = (allEncodeTimes > 0) ? ((float)_noEncode / (float)allEncodeTimes) : 0.0f;
517517 statsString += QString().sprintf(" No Encode:"
518518 " (%6.2f%%) samples: %12d \r\n",
519− zeroVsTotalEncode * AS_PERCENT, _noEncode);
519+ (double)(zeroVsTotalEncode * AS_PERCENT), _noEncode);
520520
521521 float shortVsTotalEncode = (allEncodeTimes > 0) ? ((float)_shortEncode / (float)allEncodeTimes) : 0.0f;
522522 statsString += QString().sprintf(" Avg short encode time:"
523523 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",
524− _averageShortEncodeTime.getAverage(),
525− shortVsTotalEncode * AS_PERCENT, _shortEncode);
524+ (double)_averageShortEncodeTime.getAverage(),
525+ (double)(shortVsTotalEncode * AS_PERCENT), _shortEncode);
526526
527527 float longVsTotalEncode = (allEncodeTimes > 0) ? ((float)_longEncode / (float)allEncodeTimes) : 0.0f;
528528 statsString += QString().sprintf(" Avg long encode time:"
529529 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",
530− _averageLongEncodeTime.getAverage(),
531− longVsTotalEncode * AS_PERCENT, _longEncode);
530+ (double)_averageLongEncodeTime.getAverage(),
531+ (double)(longVsTotalEncode * AS_PERCENT), _longEncode);
532532
533533 float extraLongVsTotalEncode = (allEncodeTimes > 0) ? ((float)_extraLongEncode / (float)allEncodeTimes) : 0.0f;
534534 statsString += QString().sprintf(" Avg extra long encode time:"
535535 " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n",
536− _averageExtraLongEncodeTime.getAverage(),
537− extraLongVsTotalEncode * AS_PERCENT, _extraLongEncode);
536+ (double)_averageExtraLongEncodeTime.getAverage(),
537+ (double)(extraLongVsTotalEncode * AS_PERCENT), _extraLongEncode);
538538
539539
540540 float averageCompressAndWriteTime = getAverageCompressAndWriteTime();
541− statsString += QString().sprintf(" Average compress and write time: %9.2f usecs\r\n",
542− averageCompressAndWriteTime);
541+ statsString += QString().sprintf(" Average compress and write time: %9.2f usecs\r\n",
542+ (double)averageCompressAndWriteTime);
543543
544544 int allCompressTimes = _noCompress + _shortCompress + _longCompress + _extraLongCompress;
545545
546546 float zeroVsTotalCompress = (allCompressTimes > 0) ? ((float)_noCompress / (float)allCompressTimes) : 0.0f;
547547 statsString += QString().sprintf(" No compression:"
548548 " (%6.2f%%) samples: %12d \r\n",
549− zeroVsTotalCompress * AS_PERCENT, _noCompress);
549+ (double)(zeroVsTotalCompress * AS_PERCENT), _noCompress);
550550
551551 float shortVsTotalCompress = (allCompressTimes > 0) ? ((float)_shortCompress / (float)allCompressTimes) : 0.0f;
552552 statsString += QString().sprintf(" Avg short compress time:"
553553 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",
554− _averageShortCompressTime.getAverage(),
555− shortVsTotalCompress * AS_PERCENT, _shortCompress);
554+ (double)_averageShortCompressTime.getAverage(),
555+ (double)(shortVsTotalCompress * AS_PERCENT), _shortCompress);
556556
557557 float longVsTotalCompress = (allCompressTimes > 0) ? ((float)_longCompress / (float)allCompressTimes) : 0.0f;
558558 statsString += QString().sprintf(" Avg long compress time:"
559559 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",
560− _averageLongCompressTime.getAverage(),
561− longVsTotalCompress * AS_PERCENT, _longCompress);
560+ (double)_averageLongCompressTime.getAverage(),
561+ (double)(longVsTotalCompress * AS_PERCENT), _longCompress);
562562
563563 float extraLongVsTotalCompress = (allCompressTimes > 0) ? ((float)_extraLongCompress / (float)allCompressTimes) : 0.0f;
564564 statsString += QString().sprintf(" Avg extra long compress time:"
565565 " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n",
566− _averageExtraLongCompressTime.getAverage(),
567− extraLongVsTotalCompress * AS_PERCENT, _extraLongCompress);
566+ (double)_averageExtraLongCompressTime.getAverage(),
567+ (double)(extraLongVsTotalCompress * AS_PERCENT), _extraLongCompress);
568568
569569 float averagePacketSendingTime = getAveragePacketSendingTime();
570− statsString += QString().sprintf(" Average packet sending time: %9.2f usecs (includes node lock)\r\n",
571− averagePacketSendingTime);
570+ statsString += QString().sprintf(" Average packet sending time: %9.2f usecs (includes node lock)\r\n",
571+ (double)averagePacketSendingTime);
572572
573− float noVsTotalSend = (_averagePacketSendingTime.getSampleCount() > 0) ?
573+ float noVsTotalSend = (_averagePacketSendingTime.getSampleCount() > 0) ?
574574 ((float)_noSend / (float)_averagePacketSendingTime.getSampleCount()) : 0.0f;
575575 statsString += QString().sprintf(" Not sending:"
576576 " (%6.2f%%) samples: %12d \r\n",
577− noVsTotalSend * AS_PERCENT, _noSend);
578−
577+ (double)(noVsTotalSend * AS_PERCENT), _noSend);
578+
579579 float averageNodeWaitTime = getAverageNodeWaitTime();
580− statsString += QString().sprintf(" Average node lock wait time: %9.2f usecs\r\n", averageNodeWaitTime);
580+ statsString += QString().sprintf(" Average node lock wait time: %9.2f usecs\r\n",
581+ (double)averageNodeWaitTime);
581582
582583 statsString += QString().sprintf("--------------------------------------------------------------\r\n");
583584
584585 float encodeToInsidePercent = averageInsideTime == 0.0f ? 0.0f : (averageEncodeTime / averageInsideTime) * AS_PERCENT;
585− statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n",
586− encodeToInsidePercent);
586+ statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n",
587+ (double)encodeToInsidePercent);
587588
588− float waitToInsidePercent = averageInsideTime == 0.0f ? 0.0f
589+ float waitToInsidePercent = averageInsideTime == 0.0f ? 0.0f
589590 : ((averageTreeWaitTime + averageNodeWaitTime) / averageInsideTime) * AS_PERCENT;
590− statsString += QString().sprintf(" waiting ratio: %5.2f%%\r\n", waitToInsidePercent);
591+ statsString += QString().sprintf(" waiting ratio: %5.2f%%\r\n",
592+ (double)waitToInsidePercent);
591593
592− float compressAndWriteToInsidePercent = averageInsideTime == 0.0f ? 0.0f
594+ float compressAndWriteToInsidePercent = averageInsideTime == 0.0f ? 0.0f
593595 : (averageCompressAndWriteTime / averageInsideTime) * AS_PERCENT;
594− statsString += QString().sprintf(" compress and write ratio: %5.2f%%\r\n",
595− compressAndWriteToInsidePercent);
596+ statsString += QString().sprintf(" compress and write ratio: %5.2f%%\r\n",
597+ (double)compressAndWriteToInsidePercent);
596598
597− float sendingToInsidePercent = averageInsideTime == 0.0f ? 0.0f
599+ float sendingToInsidePercent = averageInsideTime == 0.0f ? 0.0f
598600 : (averagePacketSendingTime / averageInsideTime) * AS_PERCENT;
599− statsString += QString().sprintf(" sending ratio: %5.2f%%\r\n", sendingToInsidePercent);
600−
601+ statsString += QString().sprintf(" sending ratio: %5.2f%%\r\n",
602+ (double)sendingToInsidePercent);
603+
601604
602605
603606 statsString += QString("\r\n");
@@ -610,13 +613,13 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 6 unmodified lines
610613 .arg(locale.toString((uint)totalWastedBytes).rightJustified(COLUMN_WIDTH, ' '));
611614 statsString += QString().sprintf(" Total OctalCode Bytes: %s bytes (%5.2f%%)\r\n",
612615 locale.toString((uint)totalBytesOfOctalCodes).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(),
613− ((float)totalBytesOfOctalCodes / (float)totalOutboundBytes) * AS_PERCENT);
616+ (double)((totalBytesOfOctalCodes / (float)totalOutboundBytes) * AS_PERCENT));
614617 statsString += QString().sprintf(" Total BitMasks Bytes: %s bytes (%5.2f%%)\r\n",
615618 locale.toString((uint)totalBytesOfBitMasks).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(),
616− ((float)totalBytesOfBitMasks / (float)totalOutboundBytes) * AS_PERCENT);
619+ (double)(((float)totalBytesOfBitMasks / (float)totalOutboundBytes) * AS_PERCENT));
617620 statsString += QString().sprintf(" Total Color Bytes: %s bytes (%5.2f%%)\r\n",
618621 locale.toString((uint)totalBytesOfColor).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(),
619− ((float)totalBytesOfColor / (float)totalOutboundBytes) * AS_PERCENT);
622+ (double)((totalBytesOfColor / (float)totalOutboundBytes) * AS_PERCENT));
620623
621624 statsString += "\r\n";
622625 statsString += "\r\n";
@@ -638,7 +641,8 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 15 unmodified lines
638641 .arg(locale.toString((uint)totalPacketsProcessed).rightJustified(COLUMN_WIDTH, ' '));
639642 statsString += QString(" Total Inbound Elements: %1 elements\r\n")
640643 .arg(locale.toString((uint)totalElementsProcessed).rightJustified(COLUMN_WIDTH, ' '));
641− statsString += QString().sprintf(" Average Inbound Elements/Packet: %f elements/packet\r\n", averageElementsPerPacket);
644+ statsString += QString().sprintf(" Average Inbound Elements/Packet: %f elements/packet\r\n",
645+ (double)averageElementsPerPacket);
642646 statsString += QString(" Average Transit Time/Packet: %1 usecs\r\n")
643647 .arg(locale.toString((uint)averageTransitTimePerPacket).rightJustified(COLUMN_WIDTH, ' '));
644648 statsString += QString(" Average Process Time/Packet: %1 usecs\r\n")
@@ -676,7 +680,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 31 unmodified lines
676680 statsString += QString(" Total Inbound Elements: %1 elements\r\n")
677681 .arg(locale.toString((uint)totalElementsProcessed).rightJustified(COLUMN_WIDTH, ' '));
678682 statsString += QString().sprintf(" Average Inbound Elements/Packet: %f elements/packet\r\n",
679− averageElementsPerPacket);
683+ (double)averageElementsPerPacket);
680684 statsString += QString(" Average Transit Time/Packet: %1 usecs\r\n")
681685 .arg(locale.toString((uint)averageTransitTimePerPacket).rightJustified(COLUMN_WIDTH, ' '));
682686 statsString += QString(" Average Process Time/Packet: %1 usecs\r\n")
@@ -710,14 +714,15 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 27 unmodified lines
710714 }
711715
712716 statsString += QString().sprintf("Element Node Memory Usage: %8.2f %s\r\n",
713− OctreeElement::getOctreeMemoryUsage() / memoryScale, memoryScaleLabel);
717+ OctreeElement::getOctreeMemoryUsage() / (double)memoryScale, memoryScaleLabel);
714718 statsString += QString().sprintf("Octcode Memory Usage: %8.2f %s\r\n",
715− OctreeElement::getOctcodeMemoryUsage() / memoryScale, memoryScaleLabel);
719+ OctreeElement::getOctcodeMemoryUsage() / (double)memoryScale, memoryScaleLabel);
716720 statsString += QString().sprintf("External Children Memory Usage: %8.2f %s\r\n",
717− OctreeElement::getExternalChildrenMemoryUsage() / memoryScale, memoryScaleLabel);
721+ OctreeElement::getExternalChildrenMemoryUsage() / (double)memoryScale,
722+ memoryScaleLabel);
718723 statsString += " -----------\r\n";
719724 statsString += QString().sprintf(" Total: %8.2f %s\r\n",
720− OctreeElement::getTotalMemoryUsage() / memoryScale, memoryScaleLabel);
725+ OctreeElement::getTotalMemoryUsage() / (double)memoryScale, memoryScaleLabel);
721726 statsString += "\r\n";
722727
723728 statsString += "OctreeElement Children Population Statistics...\r\n";
@@ -726,7 +731,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 2 unmodified lines
726731 checkSum += OctreeElement::getChildrenCount(i);
727732 statsString += QString().sprintf(" Nodes with %d children: %s nodes (%5.2f%%)\r\n", i,
728733 locale.toString((uint)OctreeElement::getChildrenCount(i)).rightJustified(16, ' ').toLocal8Bit().constData(),
729− ((float)OctreeElement::getChildrenCount(i) / (float)nodeCount) * AS_PERCENT);
734+ (double)(((float)OctreeElement::getChildrenCount(i) / (float)nodeCount) * AS_PERCENT));
730735 }
731736 statsString += " ----------------------\r\n";
732737 statsString += QString(" Total: %1 nodes\r\n")
@@ -831,7 +836,7 @@ void OctreeServer::readPendingDatagram(const QByteArray& receivedPacket, const H · 98 unmodified lines
831836
832837 // If we know we're shutting down we just drop these packets on the floor.
833838 // This stops us from initializing send threads we just shut down.
834−
839+
835840 if (!_isShuttingDown) {
836841 if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
837842 PacketType packetType = packetTypeForPacket(receivedPacket);
@@ -841,7 +846,7 @@ void OctreeServer::readPendingDatagram(const QByteArray& receivedPacket, const H · 3 unmodified lines
841846 // need to make sure we have it in our nodeList.
842847 if (matchingNode) {
843848 nodeList->updateNodeWithDataFromPacket(matchingNode, receivedPacket);
844−
849+
845850 OctreeQueryNode* nodeData = (OctreeQueryNode*) matchingNode->getLinkedData();
846851 if (nodeData && !nodeData->isOctreeSendThreadInitalized()) {
847852 nodeData->initializeOctreeSendThread(this, matchingNode);
@@ -870,33 +875,33 @@ void OctreeServer::readPendingDatagram(const QByteArray& receivedPacket, const H · 22 unmodified lines
870875
871876 void OctreeServer::setupDatagramProcessingThread() {
872877 auto nodeList = DependencyManager::get<NodeList>();
873−
878+
874879 // we do not want this event loop to be the handler for UDP datagrams, so disconnect
875880 disconnect(&nodeList->getNodeSocket(), 0, this, 0);
876−
881+
877882 // setup a QThread with us as parent that will house the OctreeServerDatagramProcessor
878883 _datagramProcessingThread = new QThread(this);
879884 _datagramProcessingThread->setObjectName("Octree Datagram Processor");
880−
885+
881886 // create an OctreeServerDatagramProcessor and move it to that thread
882887 OctreeServerDatagramProcessor* datagramProcessor = new OctreeServerDatagramProcessor(nodeList->getNodeSocket(), thread());
883888 datagramProcessor->moveToThread(_datagramProcessingThread);
884−
889+
885890 // remove the NodeList as the parent of the node socket
886891 nodeList->getNodeSocket().setParent(NULL);
887892 nodeList->getNodeSocket().moveToThread(_datagramProcessingThread);
888−
893+
889894 // let the datagram processor handle readyRead from node socket
890895 connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead,
891896 datagramProcessor, &OctreeServerDatagramProcessor::readPendingDatagrams);
892−
897+
893898 // connect to the datagram processing thread signal that tells us we have to handle a packet
894899 connect(datagramProcessor, &OctreeServerDatagramProcessor::packetRequiresProcessing, this, &OctreeServer::readPendingDatagram);
895−
900+
896901 // delete the datagram processor and the associated thread when the QThread quits
897902 connect(_datagramProcessingThread, &QThread::finished, datagramProcessor, &QObject::deleteLater);
898903 connect(datagramProcessor, &QObject::destroyed, _datagramProcessingThread, &QThread::deleteLater);
899−
904+
900905 // start the datagram processing thread
901906 _datagramProcessingThread->start();
902907 }
@@ -961,16 +966,16 @@ void OctreeServer::readConfiguration() { · 58 unmodified lines
961966 // wait until we have the domain-server settings, otherwise we bail
962967 auto nodeList = DependencyManager::get<NodeList>();
963968 DomainHandler& domainHandler = nodeList->getDomainHandler();
964−
969+
965970 qDebug() << "Waiting for domain settings from domain-server.";
966−
971+
967972 // block until we get the settingsRequestComplete signal
968973 QEventLoop loop;
969974 connect(&domainHandler, &DomainHandler::settingsReceived, &loop, &QEventLoop::quit);
970975 connect(&domainHandler, &DomainHandler::settingsReceiveFail, &loop, &QEventLoop::quit);
971976 domainHandler.requestDomainSettings();
972977 loop.exec();
973−
978+
974979 if (domainHandler.getSettingsObject().isEmpty()) {
975980 qDebug() << "No settings object from domain-server.";
976981 }
@@ -978,7 +983,7 @@ void OctreeServer::readConfiguration() { · 1 unmodified line
978983 QString settingsKey = getMyDomainSettingsKey();
979984 QJsonObject settingsSectionObject = settingsObject[settingsKey].toObject();
980985 _settings = settingsSectionObject; // keep this for later
981−
986+
982987 if (!readOptionString(QString("statusHost"), settingsSectionObject, _statusHost) || _statusHost.isEmpty()) {
983988 _statusHost = getLocalAddress().toString();
984989 }
@@ -1002,7 +1007,7 @@ void OctreeServer::readConfiguration() { · 17 unmodified lines
10021007 bool hasRoot = readOptionString(QString("jurisdictionRoot"), settingsSectionObject, jurisdictionRoot);
10031008 QString jurisdictionEndNodes;
10041009 bool hasEndNodes = readOptionString(QString("jurisdictionEndNodes"), settingsSectionObject, jurisdictionEndNodes);
1005−
1010+
10061011 if (hasRoot || hasEndNodes) {
10071012 _jurisdiction = new JurisdictionMap(qPrintable(jurisdictionRoot), qPrintable(jurisdictionEndNodes));
10081013 }
@@ -1050,7 +1055,7 @@ void OctreeServer::readConfiguration() { · 41 unmodified lines
10501055 qDebug() << "wantBackup=" << _wantBackup;
10511056
10521057 //qDebug() << "settingsSectionObject:" << settingsSectionObject;
1053−
1058+
10541059 } else {
10551060 qDebug("persistFilename= DISABLED");
10561061 }
@@ -1072,7 +1077,7 @@ void OctreeServer::readConfiguration() { · 15 unmodified lines
10721077 _packetsPerClientPerInterval = 1;
10731078 }
10741079 }
1075− qDebug("packetsPerSecondPerClientMax=%d _packetsPerClientPerInterval=%d",
1080+ qDebug("packetsPerSecondPerClientMax=%d _packetsPerClientPerInterval=%d",
10761081 packetsPerSecondPerClientMax, _packetsPerClientPerInterval);
10771082
10781083 // Check to see if the user passed in a command line option for setting packet send rate
@@ -1083,10 +1088,10 @@ void OctreeServer::readConfiguration() { · 4 unmodified lines
10831088 _packetsTotalPerInterval = 1;
10841089 }
10851090 }
1086− qDebug("packetsPerSecondTotalMax=%d _packetsTotalPerInterval=%d",
1091+ qDebug("packetsPerSecondTotalMax=%d _packetsTotalPerInterval=%d",
10871092 packetsPerSecondTotalMax, _packetsTotalPerInterval);
1088−
1089−
1093+
1094+
10901095 readAdditionalConfiguration(settingsSectionObject);
10911096 }
10921097
@@ -1101,8 +1106,8 @@ void OctreeServer::run() { · 8 unmodified lines
11011106 // make sure our NodeList knows what type we are
11021107 auto nodeList = DependencyManager::get<NodeList>();
11031108 nodeList->setOwnerType(getMyNodeType());
1104−
1105−
1109+
1110+
11061111 // use common init to setup common timers and logging
11071112 commonInit(getMyLoggingServerTargetName(), getMyNodeType());
11081113
@@ -1110,7 +1115,7 @@ void OctreeServer::run() { · 1 unmodified line
11101115
11111116 // read the configuration from either the payload or the domain server configuration
11121117 readConfiguration();
1113−
1118+
11141119 beforeRun(); // after payload has been processed
11151120
11161121 connect(nodeList.data(), SIGNAL(nodeAdded(SharedNodePointer)), SLOT(nodeAdded(SharedNodePointer)));
@@ -1119,7 +1124,7 @@ void OctreeServer::run() { · 2 unmodified lines
11191124
11201125 // we need to ask the DS about agents so we can ping/reply with them
11211126 nodeList->addNodeTypeToInterestSet(NodeType::Agent);
1122−
1127+
11231128 #ifndef WIN32
11241129 setvbuf(stdout, NULL, _IOLBF, 0);
11251130 #endif
@@ -1209,7 +1214,7 @@ void OctreeServer::forceNodeShutdown(SharedNodePointer node) { · 83 unmodified lines
12091214
12101215 quint64 end = usecTimestampNow();
12111216 quint64 usecsElapsed = (end - start);
1212− qDebug() << qPrintable(_safeServerName) << "server forceNodeShutdown() took: "
1217+ qDebug() << qPrintable(_safeServerName) << "server forceNodeShutdown() took: "
12131218 << usecsElapsed << " usecs for node:" << *node;
12141219 }
12151220
@@ -1225,7 +1230,7 @@ void OctreeServer::aboutToFinish() { · 9 unmodified lines
12251230 // This ensures that when we forceNodeShutdown below for each node we don't get any more newly connecting nodes
12261231 auto nodeList = DependencyManager::get<NodeList>();
12271232 nodeList->linkedDataCreateCallback = NULL;
1228−
1233+
12291234 if (_octreeInboundPacketProcessor) {
12301235 _octreeInboundPacketProcessor->terminating();
12311236 }
@@ -1240,7 +1245,7 @@ void OctreeServer::aboutToFinish() { · 8 unmodified lines
12401245 qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node;
12411246 forceNodeShutdown(node);
12421247 });
1243−
1248+
12441249 if (_persistThread) {
12451250 _persistThread->aboutToFinish();
12461251 _persistThread->terminating();
@@ -1282,7 +1287,7 @@ QString OctreeServer::getUptime() { · 35 unmodified lines
12821287 if (hours > 0 || minutes > 0) {
12831288 formattedUptime += QString(" ");
12841289 }
1285− formattedUptime += QString().sprintf("%.3f seconds", seconds);
1290+ formattedUptime += QString().sprintf("%.3f seconds", (double)seconds);
12861291 }
12871292 return formattedUptime;
12881293 }
@@ -1290,13 +1295,13 @@ QString OctreeServer::getUptime() { · 1 unmodified line
12901295 QString OctreeServer::getFileLoadTime() {
12911296 QString result;
12921297 if (isInitialLoadComplete()) {
1293−
1298+
12941299 const int USECS_PER_MSEC = 1000;
12951300 const int MSECS_PER_SEC = 1000;
12961301 const int SECS_PER_MIN = 60;
12971302 const int MIN_PER_HOUR = 60;
12981303 const int MSECS_PER_MIN = MSECS_PER_SEC * SECS_PER_MIN;
1299−
1304+
13001305 quint64 msecsElapsed = getLoadElapsedTime() / USECS_PER_MSEC;;
13011306 float seconds = (msecsElapsed % MSECS_PER_MIN)/(float)MSECS_PER_SEC;
13021307 int minutes = (msecsElapsed/(MSECS_PER_MIN)) % MIN_PER_HOUR;
@@ -1321,7 +1326,7 @@ QString OctreeServer::getFileLoadTime() { · 18 unmodified lines
13211326 if (hours > 0 || minutes > 0) {
13221327 result += QString(" ");
13231328 }
1324− result += QString().sprintf("%.3f seconds", seconds);
1329+ result += QString().sprintf("%.3f seconds", (double)seconds);
13251330 }
13261331 } else {
13271332 result = "Not yet loaded...";
@@ -1356,27 +1361,27 @@ void OctreeServer::sendStatsPacket() { · 28 unmodified lines
13561361 // 2) only send new data
13571362 // 3) automatically break up into multiple packets
13581363 static QJsonObject statsObject1;
1359−
1364+
13601365 QString baseName = getMyServerName() + QString("Server");
1361−
1366+
13621367 statsObject1[baseName + QString(".0.1.configuration")] = getConfiguration();
1363−
1368+
13641369 statsObject1[baseName + QString(".0.2.detailed_stats_url")] = getStatusLink();
1365−
1370+
13661371 statsObject1[baseName + QString(".0.3.uptime")] = getUptime();
13671372 statsObject1[baseName + QString(".0.4.persistFileLoadTime")] = getFileLoadTime();
13681373 statsObject1[baseName + QString(".0.5.clients")] = getCurrentClientCount();
1369−
1374+
13701375 quint64 oneSecondAgo = usecTimestampNow() - USECS_PER_SECOND;
1371−
1376+
13721377 statsObject1[baseName + QString(".0.6.threads.1.processing")] = (double)howManyThreadsDidProcess(oneSecondAgo);
1373− statsObject1[baseName + QString(".0.6.threads.2.packetDistributor")] =
1378+ statsObject1[baseName + QString(".0.6.threads.2.packetDistributor")] =
13741379 (double)howManyThreadsDidPacketDistributor(oneSecondAgo);
1375− statsObject1[baseName + QString(".0.6.threads.3.handlePacektSend")] =
1380+ statsObject1[baseName + QString(".0.6.threads.3.handlePacektSend")] =
13761381 (double)howManyThreadsDidHandlePacketSend(oneSecondAgo);
1377− statsObject1[baseName + QString(".0.6.threads.4.writeDatagram")] =
1378− (double)howManyThreadsDidCallWriteDatagram(oneSecondAgo);
1379−
1382+ statsObject1[baseName + QString(".0.6.threads.4.writeDatagram")] =
1383+ (double)howManyThreadsDidCallWriteDatagram(oneSecondAgo);
1384+
13801385 statsObject1[baseName + QString(".1.1.octree.elementCount")] = (double)OctreeElement::getNodeCount();
13811386 statsObject1[baseName + QString(".1.2.octree.internalElementCount")] = (double)OctreeElement::getInternalNodeCount();
13821387 statsObject1[baseName + QString(".1.3.octree.leafElementCount")] = (double)OctreeElement::getLeafNodeCount();
@@ -1388,9 +1393,9 @@ void OctreeServer::sendStatsPacket() { · 5 unmodified lines
13881393 statsObject2[baseName + QString(".2.outbound.data.totalPackets")] = (double)OctreeSendThread::_totalPackets;
13891394 statsObject2[baseName + QString(".2.outbound.data.totalBytes")] = (double)OctreeSendThread::_totalBytes;
13901395 statsObject2[baseName + QString(".2.outbound.data.totalBytesWasted")] = (double)OctreeSendThread::_totalWastedBytes;
1391− statsObject2[baseName + QString(".2.outbound.data.totalBytesOctalCodes")] =
1396+ statsObject2[baseName + QString(".2.outbound.data.totalBytesOctalCodes")] =
13921397 (double)OctreePacketData::getTotalBytesOfOctalCodes();
1393− statsObject2[baseName + QString(".2.outbound.data.totalBytesBitMasks")] =
1398+ statsObject2[baseName + QString(".2.outbound.data.totalBytesBitMasks")] =
13941399 (double)OctreePacketData::getTotalBytesOfBitMasks();
13951400 statsObject2[baseName + QString(".2.outbound.data.totalBytesBitMasks")] = (double)OctreePacketData::getTotalBytesOfColor();
13961401
@@ -1406,19 +1411,19 @@ void OctreeServer::sendStatsPacket() { · 9 unmodified lines
14061411
14071412 static QJsonObject statsObject3;
14081413
1409− statsObject3[baseName + QString(".3.inbound.data.1.totalPackets")] =
1414+ statsObject3[baseName + QString(".3.inbound.data.1.totalPackets")] =
14101415 (double)_octreeInboundPacketProcessor->getTotalPacketsProcessed();
1411− statsObject3[baseName + QString(".3.inbound.data.2.totalElements")] =
1416+ statsObject3[baseName + QString(".3.inbound.data.2.totalElements")] =
14121417 (double)_octreeInboundPacketProcessor->getTotalElementsProcessed();
1413− statsObject3[baseName + QString(".3.inbound.timing.1.avgTransitTimePerPacket")] =
1418+ statsObject3[baseName + QString(".3.inbound.timing.1.avgTransitTimePerPacket")] =
14141419 (double)_octreeInboundPacketProcessor->getAverageTransitTimePerPacket();
1415− statsObject3[baseName + QString(".3.inbound.timing.2.avgProcessTimePerPacket")] =
1420+ statsObject3[baseName + QString(".3.inbound.timing.2.avgProcessTimePerPacket")] =
14161421 (double)_octreeInboundPacketProcessor->getAverageProcessTimePerPacket();
1417− statsObject3[baseName + QString(".3.inbound.timing.3.avgLockWaitTimePerPacket")] =
1422+ statsObject3[baseName + QString(".3.inbound.timing.3.avgLockWaitTimePerPacket")] =
14181423 (double)_octreeInboundPacketProcessor->getAverageLockWaitTimePerPacket();
1419− statsObject3[baseName + QString(".3.inbound.timing.4.avgProcessTimePerElement")] =
1424+ statsObject3[baseName + QString(".3.inbound.timing.4.avgProcessTimePerElement")] =
14201425 (double)_octreeInboundPacketProcessor->getAverageProcessTimePerElement();
1421− statsObject3[baseName + QString(".3.inbound.timing.5.avgLockWaitTimePerElement")] =
1426+ statsObject3[baseName + QString(".3.inbound.timing.5.avgLockWaitTimePerElement")] =
14221427 (double)_octreeInboundPacketProcessor->getAverageLockWaitTimePerElement();
14231428
14241429 DependencyManager::get<NodeList>()->sendStatsToDomainServer(statsObject3);
cmake/externals/LibOVR/CMakeLists.txt+7−3
@@ -9,8 +9,8 @@ if (WIN32) · 8 unmodified lines
99
1010 ExternalProject_Add(
1111 ${EXTERNAL_NAME}
12− URL http://static.oculus.com/sdk-downloads/ovr_sdk_win_0.5.0.1.zip
13− URL_MD5 d3fc4c02db9be5ff08af4ef4c97b32f9
12+ URL http://static.oculus.com/sdk-downloads/0.6.0.0/1431634088/ovr_sdk_win_0.6.0.0.zip
13+ URL_MD5 a3dfdab037a854fdcf7e6033fa8d7028
1414 CONFIGURE_COMMAND ""
1515 BUILD_COMMAND ""
1616 INSTALL_COMMAND ""
@@ -21,7 +21,11 @@ if (WIN32) · 4 unmodified lines
2121
2222 # FIXME need to account for different architectures
2323 set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/LibOVR/Include CACHE TYPE INTERNAL)
24− set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/LibOVR/Lib/Windows/Win32/Release/VS2013/LibOVR.lib CACHE TYPE INTERNAL)
24+ if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
25+ set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/LibOVR/Lib/Windows/x64/Release/VS2013/LibOVR.lib CACHE TYPE INTERNAL)
26+ else()
27+ set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/LibOVR/Lib/Windows/Win32/Release/VS2013/LibOVR.lib CACHE TYPE INTERNAL)
28+ endif()
2529
2630 elseif(APPLE)
2731
cmake/externals/boostconfig/CMakeLists.txt+7−7
@@ -3,13 +3,13 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) · 2 unmodified lines
33
44 include(ExternalProject)
55 ExternalProject_Add(
6− ${EXTERNAL_NAME}
7− URL https://github.com/boostorg/config/archive/boost-1.58.0.zip
8− URL_MD5 42fa673bae2b7645a22736445e80eb8d
9− CONFIGURE_COMMAND ""
10− BUILD_COMMAND ""
11− INSTALL_COMMAND ""
12− LOG_DOWNLOAD 1
6+ ${EXTERNAL_NAME}
7+ URL https://github.com/boostorg/config/archive/boost-1.58.0.zip
8+ URL_MD5 42fa673bae2b7645a22736445e80eb8d
9+ CONFIGURE_COMMAND ""
10+ BUILD_COMMAND ""
11+ INSTALL_COMMAND ""
12+ LOG_DOWNLOAD 1
1313 )
1414
1515 ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
cmake/externals/glew/CMakeLists.txt+10−5
@@ -16,11 +16,16 @@ if (WIN32) · 15 unmodified lines
1616
1717 string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
1818 set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE PATH "List of glew include directories")
19−
20− set(_LIB_DIR ${SOURCE_DIR}/lib/Release/Win32)
21−
19+
20+ if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
21+ set(_LIB_DIR ${SOURCE_DIR}/lib/Release/x64)
22+ set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${SOURCE_DIR}/bin/Release/x64 CACHE FILEPATH "Location of GLEW DLL")
23+ else()
24+ set(_LIB_DIR ${SOURCE_DIR}/lib/Release/Win32)
25+ set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${SOURCE_DIR}/bin/Release/Win32 CACHE FILEPATH "Location of GLEW DLL")
26+ endif()
27+
2228 set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${_LIB_DIR}/glew32.lib CACHE FILEPATH "Location of GLEW release library")
2329 set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "Location of GLEW debug library")
24−
25− set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${SOURCE_DIR}/bin/Release/Win32 CACHE FILEPATH "Location of GLEW DLL")
30+
2631 endif ()
cmake/externals/oglplus/CMakeLists.txt+7−7
@@ -3,13 +3,13 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) · 2 unmodified lines
33
44 include(ExternalProject)
55 ExternalProject_Add(
6− ${EXTERNAL_NAME}
7− URL http://softlayer-dal.dl.sourceforge.net/project/oglplus/oglplus-0.61.x/oglplus-0.61.0.zip
8− URL_MD5 bb55038c36c660d2b6c7be380414fa60
9− CONFIGURE_COMMAND ""
10− BUILD_COMMAND ""
11− INSTALL_COMMAND ""
12− LOG_DOWNLOAD 1
6+ ${EXTERNAL_NAME}
7+ GIT_REPOSITORY https://github.com/matus-chochlik/oglplus.git
8+ GIT_TAG a2681383928b1166f176512cbe0f95e96fe68d08
9+ CONFIGURE_COMMAND ""
10+ BUILD_COMMAND ""
11+ INSTALL_COMMAND ""
12+ LOG_DOWNLOAD 1
1313 )
1414
1515 ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
cmake/externals/tbb/CMakeLists.txt+7−2
@@ -73,9 +73,14 @@ if (APPLE) · 72 unmodified lines
7373 )
7474
7575 elseif (WIN32)
76− set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/ia32/vc12")
76+ if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
77+ set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/intel64/vc12")
78+ set(${EXTERNAL_NAME_UPPER}_DLL_PATH "${SOURCE_DIR}/bin/intel64/vc12" CACHE PATH "Path to TBB DLLs")
79+ else()
80+ set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/ia32/vc12")
81+ set(${EXTERNAL_NAME_UPPER}_DLL_PATH "${SOURCE_DIR}/bin/ia32/vc12" CACHE PATH "Path to TBB DLLs")
82+ endif()
7783 set(_LIB_EXT "lib")
78− set(${EXTERNAL_NAME_UPPER}_DLL_PATH "${SOURCE_DIR}/bin/ia32/vc12" CACHE PATH "Path to TBB DLLs")
7984 elseif (ANDROID)
8085 set(_TBB_LIB_DIR "${SOURCE_DIR}/lib")
8186 set(_LIB_PREFIX "lib")
cmake/macros/SetupHifiOpenGL.cmake+43−0
@@ -0,0 +1,43 @@
1+
2+
3+macro(SETUP_HIFI_OPENGL)
4+
5+ if (APPLE)
6+
7+ # link in required OS X frameworks and include the right GL headers
8+ find_library(OpenGL OpenGL)
9+ target_link_libraries(${TARGET_NAME} ${OpenGL})
10+
11+ elseif (WIN32)
12+
13+ add_dependency_external_projects(glew)
14+ find_package(GLEW REQUIRED)
15+ target_include_directories(${TARGET_NAME} PUBLIC ${GLEW_INCLUDE_DIRS})
16+ target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARIES} opengl32.lib)
17+
18+ if (USE_NSIGHT)
19+ # try to find the Nsight package and add it to the build if we find it
20+ find_package(NSIGHT)
21+ if (NSIGHT_FOUND)
22+ include_directories(${NSIGHT_INCLUDE_DIRS})
23+ add_definitions(-DNSIGHT_FOUND)
24+ target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}")
25+ endif()
26+ endif()
27+
28+ elseif(ANDROID)
29+
30+ target_link_libraries(${TARGET_NAME} "-lGLESv3" "-lEGL")
31+
32+ else()
33+
34+ find_package(OpenGL REQUIRED)
35+ if (${OPENGL_INCLUDE_DIR})
36+ include_directories(SYSTEM "${OPENGL_INCLUDE_DIR}")
37+ endif()
38+ target_link_libraries(${TARGET_NAME} "${OPENGL_LIBRARY}")
39+ target_include_directories(${TARGET_NAME} PUBLIC ${OPENGL_INCLUDE_DIR})
40+
41+ endif()
42+
43+endmacro()
cmake/modules/FindFaceshift.cmake+5−1
@@ -28,7 +28,11 @@ if (APPLE) · 27 unmodified lines
2828 elseif (UNIX)
2929 set(ARCH_DIR "UNIX")
3030 elseif (WIN32)
31− set(ARCH_DIR "Win32")
31+ if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
32+ set(ARCH_DIR "x64")
33+ else()
34+ set(ARCH_DIR "Win32")
35+ endif()
3236 endif ()
3337
3438 find_library(FACESHIFT_LIBRARY_RELEASE NAME faceshift PATH_SUFFIXES lib/${ARCH_DIR} HINTS ${FACESHIFT_SEARCH_DIRS})
cmake/modules/FindNSIGHT.cmake+16−6
@@ -16,7 +16,16 @@ · 15 unmodified lines
1616 #
1717
1818 if (WIN32)
19−
19+
20+ if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
21+ set(ARCH_DIR "x64")
22+ set(ARCH_NAME "64")
23+ else()
24+ set(ARCH_DIR "Win32")
25+ set(ARCH_NAME "32")
26+ endif()
27+
28+
2029 find_path(NSIGHT_INCLUDE_DIRS
2130 NAMES
2231 nvToolsExt.h
@@ -25,17 +34,18 @@ if (WIN32) · 2 unmodified lines
2534 PATHS
2635 "C:/Program Files/NVIDIA Corporation/NvToolsExt")
2736
28− find_library(NSIGHT_LIBRARY_RELEASE nvToolsExt32_1
37+ find_library(NSIGHT_LIBRARY_RELEASE "nvToolsExt${ARCH_NAME}_1"
2938 PATH_SUFFIXES
30− "lib/Win32" "lib"
39+ "lib/${ARCH_DIR}" "lib"
3140 PATHS
3241 "C:/Program Files/NVIDIA Corporation/NvToolsExt")
33− find_library(NSIGHT_LIBRARY_DEBUG nvToolsExt32_1
42+ find_library(NSIGHT_LIBRARY_DEBUG "nvToolsExt${ARCH_NAME}_1"
3443 PATH_SUFFIXES
35− "lib/Win32" "lib"
44+ "lib/${ARCH_DIR}" "lib"
3645 PATHS
3746 "C:/Program Files/NVIDIA Corporation/NvToolsExt")
38−
47+
48+ add_paths_to_fixup_libs("C:/Program Files/NVIDIA Corporation/NvToolsExt/bin/${ARCH_DIR}")
3949 include(SelectLibraryConfigurations)
4050 select_library_configurations(NSIGHT)
4151 endif ()
cmake/modules/FindSixense.cmake+13−5
@@ -30,12 +30,20 @@ elseif (UNIX) · 29 unmodified lines
3030 find_library(SIXENSE_LIBRARY_RELEASE lib/linux_x64/release/libsixense_x64.so HINTS ${SIXENSE_SEARCH_DIRS})
3131 # find_library(SIXENSE_LIBRARY_DEBUG lib/linux_x64/debug/libsixensed_x64.so HINTS ${SIXENSE_SEARCH_DIRS})
3232 elseif (WIN32)
33− find_library(SIXENSE_LIBRARY_RELEASE lib/win32/release_dll/sixense.lib HINTS ${SIXENSE_SEARCH_DIRS})
34− find_library(SIXENSE_LIBRARY_DEBUG lib/win32/debug_dll/sixensed.lib HINTS ${SIXENSE_SEARCH_DIRS})
33+ if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
34+ set(ARCH_DIR "x64")
35+ set(ARCH_SUFFIX "_x64")
36+ else()
37+ set(ARCH_DIR "Win32")
38+ set(ARCH_SUFFIX "")
39+ endif()
40+
41+ find_library(SIXENSE_LIBRARY_RELEASE "lib/${ARCH_DIR}/release_dll/sixense${ARCH_SUFFIX}.lib" HINTS ${SIXENSE_SEARCH_DIRS})
42+ find_library(SIXENSE_LIBRARY_DEBUG "lib/${ARCH_DIR}/debug_dll/sixensed.lib" HINTS ${SIXENSE_SEARCH_DIRS})
3543
36− find_path(SIXENSE_DEBUG_DLL_PATH sixensed.dll PATH_SUFFIXES bin/win32/debug_dll HINTS ${SIXENSE_SEARCH_DIRS})
37− find_path(SIXENSE_RELEASE_DLL_PATH sixense.dll PATH_SUFFIXES bin/win32/release_dll HINTS ${SIXENSE_SEARCH_DIRS})
38− find_path(SIXENSE_DEVICE_DLL_PATH DeviceDLL.dll PATH_SUFFIXES samples/win32/sixense_simple3d HINTS ${SIXENSE_SEARCH_DIRS})
44+ find_path(SIXENSE_DEBUG_DLL_PATH "sixensed${ARCH_SUFFIX}.dll" PATH_SUFFIXES bin/${ARCH_DIR}/debug_dll HINTS ${SIXENSE_SEARCH_DIRS})
45+ find_path(SIXENSE_RELEASE_DLL_PATH "sixense${ARCH_SUFFIX}.dll" PATH_SUFFIXES bin/${ARCH_DIR}/release_dll HINTS ${SIXENSE_SEARCH_DIRS})
46+ find_path(SIXENSE_DEVICE_DLL_PATH DeviceDLL.dll PATH_SUFFIXES samples/${ARCH_DIR}/sixense_simple3d HINTS ${SIXENSE_SEARCH_DIRS})
3947 endif ()
4048
4149 include(SelectLibraryConfigurations)
cmake/modules/FindTBB.cmake+1−1
@@ -49,7 +49,7 @@ elseif (UNIX AND NOT ANDROID) · 48 unmodified lines
4949 endif ()
5050
5151 elseif (WIN32)
52− if (CMAKE_CL_64)
52+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
5353 set(_TBB_ARCH_DIR "intel64")
5454 else()
5555 set(_TBB_ARCH_DIR "ia32")
examples/controllers/hydra/gun.js+7−9
@@ -100,12 +100,12 @@ var NUM_BUTTONS = 3; · 99 unmodified lines
100100 var screenSize = Controller.getViewportDimensions();
101101 var startX = screenSize.x / 2 - (NUM_BUTTONS * (BUTTON_SIZE + PADDING)) / 2;
102102 Script.include(["../../libraries/toolBars.js"]);
103−const persistKey = "highfidelity.gun.toolbar.position";
104−var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL);
105−toolBar.save = function () {
106− Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y]));
107−};
108−var old = JSON.parse(Settings.getValue(persistKey) || '0');
103+var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.gun.toolbar", function (screenSize) {
104+ return {
105+ x: startX,
106+ y: (screenSize.y - (BUTTON_SIZE + PADDING)),
107+ };
108+});
109109 var reticle = Overlays.addOverlay("image", {
110110 x: screenSize.x / 2 - (BUTTON_SIZE / 2),
111111 y: screenSize.y / 2 - (BUTTON_SIZE / 2),
@@ -116,8 +116,6 @@ var reticle = Overlays.addOverlay("image", { · 4 unmodified lines
116116 });
117117
118118 var offButton = toolBar.addOverlay("image", {
119− x: old ? old[0] : startX,
120− y: old ? old[1] : (screenSize.y - (BUTTON_SIZE + PADDING)),
121119 width: BUTTON_SIZE,
122120 height: BUTTON_SIZE,
123121 imageURL: HIFI_PUBLIC_BUCKET + "images/gun/close.svg",
@@ -181,7 +179,7 @@ function entityCollisionWithEntity(entity1, entity2, collision) { · 57 unmodified lines
181179 }
182180
183181 function shootBullet(position, velocity, grenade) {
184− var BULLET_SIZE = 0.10;
182+ var BULLET_SIZE = .09;
185183 var BULLET_LIFETIME = 10.0;
186184 var BULLET_GRAVITY = -0.25;
187185 var GRENADE_VELOCITY = 15.0;
examples/defaultScripts.js+0−1
@@ -16,7 +16,6 @@ Script.load("lobby.js"); · 15 unmodified lines
1616 Script.load("notifications.js");
1717 Script.load("users.js");
1818 Script.load("grab.js");
19−Script.load("pointer.js");
2019 Script.load("directory.js");
2120 Script.load("mouseLook.js");
2221 Script.load("hmdControls.js");
examples/dice.js+6−8
@@ -33,15 +33,13 @@ var BUTTON_SIZE = 32; · 32 unmodified lines
3333 var PADDING = 3;
3434
3535 Script.include(["libraries/toolBars.js"]);
36−var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL);
37−const persistKey = "highfidelity.dice.toolbar.position";
38−toolBar.save = function () {
39− Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y]));
40−};
41−var old = JSON.parse(Settings.getValue(persistKey) || '0');
36+var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.dice.toolbar", function (screenSize) {
37+ return {
38+ x: (screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING),
39+ y: (screenSize.y - (BUTTON_SIZE + PADDING))
40+ };
41+});
4242 var offButton = toolBar.addOverlay("image", {
43− x: old ? old[0] : (screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING),
44− y: old ? old[1] : (screenSize.y - (BUTTON_SIZE + PADDING)),
4543 width: BUTTON_SIZE,
4644 height: BUTTON_SIZE,
4745 imageURL: HIFI_PUBLIC_BUCKET + "images/close.png",
examples/edit.js+7−35
@@ -49,7 +49,6 @@ selectionManager.addEventListener(function() { · 48 unmodified lines
4949 lightOverlayManager.updatePositions();
5050 });
5151
52−var windowDimensions = Controller.getViewportDimensions();
5352 var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/";
5453 var toolHeight = 50;
5554 var toolWidth = 50;
@@ -143,7 +142,12 @@ var toolBar = (function () { · 87 unmodified lines
143142 browseMarketplaceButton;
144143
145144 function initialize() {
146− toolBar = new ToolBar(0, 0, ToolBar.VERTICAL);
145+ toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.edit.toolbar", function (windowDimensions, toolbar) {
146+ return {
147+ x: windowDimensions.x - 8 - toolbar.width,
148+ y: (windowDimensions.y - toolbar.height) / 2
149+ };
150+ });
147151
148152 browseMarketplaceButton = toolBar.addTool({
149153 imageURL: toolIconUrl + "marketplace.svg",
@@ -321,38 +325,6 @@ var toolBar = (function () { · 171 unmodified lines
321325 }
322326 }
323327
324− const persistKey = "highfidelity.edit.toolbar.position";
325− that.move = function () {
326− var newViewPort,
327− toolsX,
328− toolsY;
329−
330− newViewPort = Controller.getViewportDimensions();
331−
332− if (toolBar === undefined) {
333− initialize();
334−
335− toolBar.save = function () {
336− Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y]));
337− };
338− var old = JSON.parse(Settings.getValue(persistKey) || '0');
339− if (old) {
340− windowDimensions = newViewPort;
341− toolBar.move(old[0], old[1]);
342− return;
343− }
344− } else if (windowDimensions.x === newViewPort.x &&
345− windowDimensions.y === newViewPort.y) {
346− return;
347− }
348−
349− windowDimensions = newViewPort;
350− toolsX = windowDimensions.x - 8 - toolBar.width;
351− toolsY = (windowDimensions.y - toolBar.height) / 2;
352−
353− toolBar.move(toolsX, toolsY);
354− };
355−
356328 var newModelButtonDown = false;
357329 var browseMarketplaceButtonDown = false;
358330 that.mousePressEvent = function (event) {
@@ -552,6 +524,7 @@ var toolBar = (function () { · 193 unmodified lines
552524 toolBar.cleanup();
553525 };
554526
527+ initialize();
555528 return that;
556529 }());
557530
@@ -931,7 +904,6 @@ var lastPosition = null; · 373 unmodified lines
931904
932905 // Do some stuff regularly, like check for placement of various overlays
933906 Script.update.connect(function (deltaTime) {
934− toolBar.move();
935907 progressDialog.move();
936908 selectionDisplay.checkMove();
937909 var dOrientation = Math.abs(Quat.dot(Camera.orientation, lastOrientation) - 1);
examples/html/style.css+12−14
@@ -8,7 +8,7 @@ body { · 7 unmodified lines
88 background-color: rgb(76, 76, 76);
99 color: rgb(204, 204, 204);
1010 font-family: Arial;
11− font-size: 8.25pt;
11+ font-size: 9.0pt;
1212
1313 -webkit-touch-callout: none;
1414 -webkit-user-select: none;
@@ -58,6 +58,7 @@ body { · 43 unmodified lines
5858
5959 .multi-property-section {
6060 }
61+
6162 .property-section {
6263 display: block;
6364 margin: 10 10;
@@ -132,7 +133,7 @@ input.no-spin::-webkit-inner-spin-button { · 68 unmodified lines
132133 table#entity-table {
133134 border-collapse: collapse;
134135 font-family: Sans-Serif;
135− font-size: 7.5pt;
136+ font-size: 9pt;
136137 width: 100%;
137138 }
138139
@@ -156,7 +157,7 @@ table#entity-table { · 17 unmodified lines
156157 }
157158
158159 #entity-table td {
159− font-size: 8.25pt;
160+ font-size: 9.0pt;
160161 border: 0pt black solid;
161162 word-wrap: nowrap;
162163 white-space: nowrap;
@@ -176,14 +177,14 @@ th#entity-type { · 13 unmodified lines
176177
177178 div.input-area {
178179 display: inline-block;
179− font-size: 7.5pt;
180+ font-size: 9pt;
180181 }
181182
182183 input {
183184 }
184185
185186 #type {
186− font-size: 10.5pt;
187+ font-size: 9.0pt;
187188 }
188189
189190 #type label {
@@ -191,14 +192,14 @@ input { · 1 unmodified line
191192 }
192193
193194 input, textarea {
194− background-color: rgb(102, 102, 102);
195− color: rgb(204, 204, 204);
195+ background-color: rgb(63, 63, 63);
196+ color: rgb(255, 255, 255);
196197 border: none;
197− font-size: 7.5pt;
198+ font-size: 9pt;
198199 }
199200
200201 input:disabled, textarea:disabled {
201− background-color: rgb(102, 102, 102);
202+ background-color: rgb(63, 63, 63);
202203 color: rgb(160, 160, 160);
203204 }
204205
@@ -224,7 +225,7 @@ input:disabled, textarea:disabled { · 19 unmodified lines
224225 #properties-list .property {
225226 padding: 4pt;
226227 border-bottom: 0.75pt solid rgb(63, 63, 63);
227− min-height: 1em;
228+ min-height: 12pt;
228229 }
229230
230231
@@ -245,7 +246,6 @@ table#properties-list { · 14 unmodified lines
245246 font-weight: bold;
246247 overflow: hidden;
247248 text-overflow: ellipsis;
248−
249249 vertical-align: middle;
250250 height: 1.2em;
251251 }
@@ -270,9 +270,7 @@ div.inner { · 18 unmodified lines
270270 }
271271
272272 td {
273−
274−
275− vertical-align: top;
273+ vertical-align: top;
276274 }
277275
278276 #no-entities {
examples/libraries/toolBars.js+47−6
@@ -126,7 +126,7 @@ Tool.prototype = new Overlay2D; · 125 unmodified lines
126126 Tool.IMAGE_HEIGHT = 50;
127127 Tool.IMAGE_WIDTH = 50;
128128
129−ToolBar = function(x, y, direction) {
129+ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPositionFunction) {
130130 this.tools = new Array();
131131 this.x = x;
132132 this.y = y;
@@ -336,7 +336,7 @@ ToolBar = function(x, y, direction) { · 203 unmodified lines
336336 return (that.x <= x) && (x <= (that.x + that.width)) &&
337337 (that.y <= y) && (y <= (that.y + that.height));
338338 }
339− that.hover = function (enable) {
339+ that.hover = function (enable) { // Can be overriden or extended by clients.
340340 that.isHovering = enable;
341341 if (that.back) {
342342 if (enable) {
@@ -348,6 +348,26 @@ ToolBar = function(x, y, direction) { · 5 unmodified lines
348348 });
349349 }
350350 };
351+ that.windowDimensions = Controller.getViewportDimensions();
352+ // Maybe fixme: Keeping the same percent of the window size isn't always the right thing.
353+ // For example, maybe we want "keep the same percentage to whatever two edges are closest to the edge of screen".
354+ // If we change that, the places to do so are onResizeViewport, save (maybe), and the initial move based on Settings, below.
355+ that.onResizeViewport = function (newSize) { // Can be overridden or extended by clients.
356+ var fractionX = that.x / that.windowDimensions.x;
357+ var fractionY = that.y / that.windowDimensions.y;
358+ that.windowDimensions = newSize || Controller.getViewportDimensions();
359+ that.move(fractionX * that.windowDimensions.x, fractionY * that.windowDimensions.y);
360+ };
361+ if (optionalPersistenceKey) {
362+ this.fractionKey = optionalPersistenceKey + '.fraction';
363+ this.save = function () {
364+ var screenSize = Controller.getViewportDimensions();
365+ var fraction = {x: that.x / screenSize.x, y: that.y / screenSize.y};
366+ Settings.setValue(this.fractionKey, JSON.stringify(fraction));
367+ }
368+ } else {
369+ this.save = function () { }; // Called on move. Can be overriden or extended by clients.
370+ }
351371 // These are currently only doing that which is necessary for toolbar hover and toolbar drag.
352372 // They have not yet been extended to tool hover/click/release, etc.
353373 this.mousePressEvent = function (event) {
@@ -375,15 +395,19 @@ ToolBar = function(x, y, direction) { · 21 unmodified lines
375395 }
376396 that.move(that.dragOffsetX + event.x, that.dragOffsetY + event.y);
377397 };
398+ that.checkResize = function () { // Can be overriden or extended, but usually not. See onResizeViewport.
399+ var currentWindowSize = Controller.getViewportDimensions();
400+ if ((currentWindowSize.x !== that.windowDimensions.x) || (currentWindowSize.y !== that.windowDimensions.y)) {
401+ that.onResizeViewport(currentWindowSize);
402+ }
403+ };
378404 Controller.mousePressEvent.connect(this.mousePressEvent);
379405 Controller.mouseMoveEvent.connect(this.mouseMove);
380− // Called on move. A different approach would be to have all this on the prototype,
381− // and let apps extend where needed. Ex. app defines its toolbar.move() to call this.__proto__.move and then save.
382− this.save = function () { };
406+ Script.update.connect(that.checkResize);
383407 // This compatability hack breaks the model, but makes converting existing scripts easier:
384408 this.addOverlay = function (ignored, oldSchoolProperties) {
385409 var properties = JSON.parse(JSON.stringify(oldSchoolProperties)); // a copy
386− if (that.numberOfTools() === 0) {
410+ if ((that.numberOfTools() === 0) && (properties.x != undefined) && (properties.y != undefined)) {
387411 that.move(properties.x, properties.y);
388412 }
389413 delete properties.x;
@@ -392,6 +416,23 @@ ToolBar = function(x, y, direction) { · 2 unmodified lines
392416 var id = that.tools[index].overlay();
393417 return id;
394418 }
419+ if (this.fractionKey || optionalInitialPositionFunction) {
420+ var savedFraction = JSON.parse(Settings.getValue(this.fractionKey) || '0'); // getValue can answer empty string
421+ var screenSize = Controller.getViewportDimensions();
422+ if (savedFraction) {
423+ // If we have saved data, keep the toolbar at the same proportion of the screen width/height.
424+ that.move(savedFraction.x * screenSize.x, savedFraction.y * screenSize.y);
425+ } else if (!optionalInitialPositionFunction) {
426+ print("No initPosition(screenSize, intializedToolbar) specified for ToolBar");
427+ } else {
428+ // Call the optionalInitialPositionFunctinon() AFTER the client has had a chance to set up.
429+ var that = this;
430+ Script.setTimeout(function () {
431+ var position = optionalInitialPositionFunction(screenSize, that);
432+ that.move(position.x, position.y);
433+ }, 0);
434+ }
435+ }
395436 }
396437 ToolBar.SPACING = 4;
397438 ToolBar.VERTICAL = 0;
examples/mouseLook.js+38−19
@@ -9,8 +9,6 @@ · 8 unmodified lines
99 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
1010 //
1111
12−HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
13−
1412 var lastX = Window.getCursorPositionX();
1513 var lastY = Window.getCursorPositionY();
1614 var yawFromMouse = 0;
@@ -46,6 +44,28 @@ var mouseLook = (function () { · 29 unmodified lines
4644 }
4745 }
4846
47+ function findInput(name) {
48+ var availableInputs = Controller.getAvailableInputs(keyboardID);
49+ for (i = 0; i < availableInputs.length; i++) {
50+ if (availableInputs[i].inputName == name) {
51+ return availableInputs[i].input;
52+ }
53+ }
54+ // If the input isn't found, it will default to the first available input
55+ return availableInputs[0].input;
56+ }
57+
58+ function findAction(name) {
59+ var actions = Controller.getAllActions();
60+ for (var i = 0; i < actions.length; i++) {
61+ if (actions[i].actionName == name) {
62+ return i;
63+ }
64+ }
65+ // If the action isn't found, it will default to the first available action
66+ return 0;
67+ }
68+
4969 function updateMapping() {
5070 if (keyboardID != 0) {
5171 if (active) {
@@ -55,41 +75,40 @@ var mouseLook = (function () { · 3 unmodified lines
5575 yawSpeed = 0;
5676 pitchSpeed = 0;
5777
58− var a = Controller.getAvailableInputs(keyboardID)[10].input.channel;
59− var d = Controller.getAvailableInputs(keyboardID)[13].input.channel;
60− var left = Controller.getAvailableInputs(keyboardID)[36].input.channel;
61− var right = Controller.getAvailableInputs(keyboardID)[38].input.channel;
62− var shift = Controller.getAvailableInputs(keyboardID)[41].input.channel;
78+ var a = findInput("A").channel;
79+ var d = findInput("D").channel;
80+ var left = findInput("Left").channel;
81+ var right = findInput("Right").channel;
82+ var shift = findInput("Shift").channel;
6383
64− for (i = 6; i <= 9; i++) {
84+ for (var i = findAction("YAW_LEFT"); i <= findAction("YAW_RIGHT"); i++) {
6585 var inputChannels = Controller.getAllActions()[i].inputChannels;
66− for (j = 0; j < inputChannels.length; j++) {
86+ for (var j = 0; j < inputChannels.length; j++) {
6787 var inputChannel = inputChannels[j];
68−
6988 // make a, d, left, and right strafe
7089 if ((inputChannel.input.channel == a || inputChannel.input.channel == left) && inputChannel.modifier.device == 0) {
7190 Controller.removeInputChannel(inputChannel);
72− inputChannel.action = 2;
91+ inputChannel.action = findAction("LATERAL_LEFT");
7392 Controller.addInputChannel(inputChannel);
7493 } else if ((inputChannel.input.channel == d || inputChannel.input.channel == right) && inputChannel.modifier.device == 0) {
7594 Controller.removeInputChannel(inputChannel);
76− inputChannel.action = 3;
95+ inputChannel.action = findAction("LATERAL_RIGHT");
7796 Controller.addInputChannel(inputChannel);
7897 }
7998 }
8099 }
81− // make shift + a/d/left/right change yaw/pitch
82− for (i = 2; i <= 3; i++) {
100+ for (var i = findAction("LATERAL_LEFT"); i <= findAction("LATERAL_RIGHT"); i++) {
83101 var inputChannels = Controller.getAllActions()[i].inputChannels;
84− for (j = 0; j < inputChannels.length; j++) {
102+ for (var j = 0; j < inputChannels.length; j++) {
85103 var inputChannel = inputChannels[j];
104+ // make shift + a/d/left/right change yaw/pitch
86105 if ((inputChannel.input.channel == a || inputChannel.input.channel == left) && inputChannel.modifier.channel == shift) {
87106 Controller.removeInputChannel(inputChannel);
88− inputChannel.action = 6;
107+ inputChannel.action = findAction("YAW_LEFT");
89108 Controller.addInputChannel(inputChannel);
90109 } else if ((inputChannel.input.channel == d || inputChannel.input.channel == right) && inputChannel.modifier.channel == shift) {
91110 Controller.removeInputChannel(inputChannel);
92− inputChannel.action = 7;
111+ inputChannel.action = findAction("YAW_RIGHT");
93112 Controller.addInputChannel(inputChannel);
94113 }
95114 }
@@ -134,8 +153,8 @@ var mouseLook = (function () { · 38 unmodified lines
134153 }
135154
136155 function resetCursorPosition() {
137− var newX = Window.x + Window.innerWidth / 2;
138− var newY = Window.y + Window.innerHeight / 2;
156+ var newX = Window.x + Window.innerWidth / 2.0;
157+ var newY = Window.y + Window.innerHeight / 2.0;
139158 Window.setCursorPosition(newX, newY);
140159 lastX = newX;
141160 lastY = newY;
examples/paint.js+44−339
@@ -10,17 +10,16 @@ · 9 unmodified lines
1010 //
1111 // Distributed under the Apache License, Version 2.0.
1212 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
13−//
14−Script.include('lineRider.js')
15−var MAX_POINTS_PER_LINE = 30;
16−var LINE_LIFETIME = 60 * 5 //5 minute lifetime
13+
14+var LINE_DIMENSIONS = 5;
15+var LIFETIME = 6000;
1716
1817 var colorPalette = [{
1918 red: 236,
2019 green: 208,
2120 blue: 120
2221 }, {
23− red: 217,
22+ red: 214,
2423 green: 91,
2524 blue: 67
2625 }, {
@@ -40,15 +39,6 @@ var colorPalette = [{ · 13 unmodified lines
4039 var currentColorIndex = 0;
4140 var currentColor = colorPalette[currentColorIndex];
4241
43−
44−
45−if (hydraCheck() === true) {
46− HydraPaint();
47−} else {
48− MousePaint();
49−}
50−
51−
5242 function cycleColor() {
5343 currentColor = colorPalette[++currentColorIndex];
5444 if (currentColorIndex === colorPalette.length - 1) {
@@ -57,42 +47,17 @@ function cycleColor() { · 2 unmodified lines
5747
5848 }
5949
60−function hydraCheck() {
61− var numberOfButtons = Controller.getNumberOfButtons();
62− var numberOfTriggers = Controller.getNumberOfTriggers();
63− var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
64− var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
65− hydrasConnected = (numberOfButtons == 12 && numberOfTriggers == 2 && controllersPerTrigger == 2);
66− return hydrasConnected; //hydrasConnected;
67−}
68−
69−//************ Mouse Paint **************************
50+MousePaint();
7051
7152 function MousePaint() {
72− var DRAWING_DISTANCE = 2;
53+ var DRAWING_DISTANCE = 5;
7354 var lines = [];
74− var deletedLines = [];
7555 var isDrawing = false;
76− var path = [];
77−
78− var lineRider = new LineRider();
79− lineRider.addStartHandler(function() {
80− var points = [];
81− //create points array from list of all points in path
82− path.forEach(function(point) {
83− points.push(point);
84− });
85− lineRider.setPath(points);
86− });
87−
88−
8956
9057 var LINE_WIDTH = 7;
91− var line;
92− var points = [];
93−
58+ var line, linePosition;
9459
95− var BRUSH_SIZE = 0.02;
60+ var BRUSH_SIZE = .05;
9661
9762 var brush = Entities.addEntity({
9863 type: 'Sphere',
@@ -110,51 +75,42 @@ function MousePaint() { · 11 unmodified lines
11075 });
11176
11277
113− function newLine(point) {
78+ function newLine(position) {
79+ linePosition = position;
11480 line = Entities.addEntity({
115− position: MyAvatar.position,
81+ position: position,
11682 type: "Line",
11783 color: currentColor,
11884 dimensions: {
119− x: 10,
120− y: 10,
121− z: 10
85+ x: LINE_DIMENSIONS,
86+ y: LINE_DIMENSIONS,
87+ z: LINE_DIMENSIONS
12288 },
89+ linePoints: [],
12390 lineWidth: LINE_WIDTH,
124− lifetime: LINE_LIFETIME
91+ lifetime: LIFETIME
12592 });
126− points = [];
127− if (point) {
128−
129− points.push(point);
130− path.push(point);
131− }
13293 lines.push(line);
13394 }
13495
13596
13697 function mouseMoveEvent(event) {
13798
99+ var worldPoint = computeWorldPoint(event);
100+ Entities.editEntity(brush, {
101+ position: worldPoint
102+ });
103+
138104 if (!isDrawing) {
139105 return;
140106 }
141107
142− var pickRay = Camera.computePickRay(event.x, event.y);
143− var addVector = Vec3.multiply(Vec3.normalize(pickRay.direction), DRAWING_DISTANCE);
144− var point = Vec3.sum(Camera.getPosition(), addVector);
145− points.push(point);
146− path.push(point);
147− Entities.editEntity(line, {
148− linePoints: points
149− });
150− Entities.editEntity(brush, {
151− position: point
152− });
153−
108+ var localPoint = computeLocalPoint(event)
109+ var success = Entities.appendPoint(line, localPoint);
154110
155− if (points.length === MAX_POINTS_PER_LINE) {
156− //We need to start a new line!
157− newLine(point);
111+ if (!success) {
112+ newLine(worldPoint);
113+ Entities.appendPoint(line, computeLocalPoint(event));
158114 }
159115 }
160116
@@ -171,17 +127,26 @@ function MousePaint() { · 10 unmodified lines
171127 lines.push(restoredLine);
172128 }
173129
130+ function computeWorldPoint(event) {
131+ var pickRay = Camera.computePickRay(event.x, event.y);
132+ var addVector = Vec3.multiply(Vec3.normalize(pickRay.direction), DRAWING_DISTANCE);
133+ return Vec3.sum(Camera.getPosition(), addVector);
134+ }
135+
136+ function computeLocalPoint(event) {
137+
138+ var localPoint = Vec3.subtract(computeWorldPoint(event), linePosition);
139+ return localPoint;
140+ }
141+
174142 function mousePressEvent(event) {
175− if(!event.isLeftButton) {
143+ if (!event.isLeftButton) {
176144 isDrawing = false;
177145 return;
178146 }
179− lineRider.mousePressEvent(event);
180− path = [];
181− newLine();
147+ newLine(computeWorldPoint(event));
182148 isDrawing = true;
183149
184−
185150 }
186151
187152 function mouseReleaseEvent() {
@@ -198,21 +163,21 @@ function MousePaint() { · 10 unmodified lines
198163 if (event.text === "z") {
199164 undoStroke();
200165 }
201− if(event.text === "x") {
166+ if (event.text === "x") {
202167 redoStroke();
203168 }
204169 }
205170
171+
172+
206173 function cleanup() {
207174 lines.forEach(function(line) {
208− Entities.deleteEntity(line);
175+ // Entities.deleteEntity(line);
209176 });
210177 Entities.deleteEntity(brush);
211− lineRider.cleanup();
212178
213179 }
214180
215−
216181 Controller.mousePressEvent.connect(mousePressEvent);
217182 Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
218183 Controller.mouseMoveEvent.connect(mouseMoveEvent);
@@ -222,266 +187,6 @@ function MousePaint() { · 3 unmodified lines
222187 }
223188
224189
225−
226−//*****************HYDRA PAINT *******************************************
227−
228−
229−
230−function HydraPaint() {
231−
232−
233−
234− var lineRider = new LineRider();
235− lineRider.addStartHandler(function() {
236− var points = [];
237− //create points array from list of all points in path
238− rightController.path.forEach(function(point) {
239− points.push(point);
240− });
241− lineRider.setPath(points);
242− });
243−
244− var LEFT = 0;
245− var RIGHT = 1;
246−
247− var currentTime = 0;
248−
249−
250− var minBrushSize = .02;
251− var maxBrushSize = .04
252−
253−
254− var minLineWidth = 5;
255− var maxLineWidth = 10;
256− var currentLineWidth = minLineWidth;
257− var MIN_PAINT_TRIGGER_THRESHOLD = .01;
258− var COLOR_CHANGE_TIME_FACTOR = 0.1;
259−
260− var RIGHT_BUTTON_1 = 7
261− var RIGHT_BUTTON_2 = 8
262− var RIGHT_BUTTON_3 = 9;
263− var RIGHT_BUTTON_4 = 10
264−
265− var LEFT_BUTTON_1 = 1;
266− var LEFT_BUTTON_2 = 2;
267− var LEFT_BUTTON_3 = 3;
268− var LEFT_BUTTON_4 = 4;
269−
270− var STROKE_SMOOTH_FACTOR = 1;
271−
272− var MIN_DRAW_DISTANCE = 0.2;
273− var MAX_DRAW_DISTANCE = 0.4;
274−
275− function controller(side, undoButton, redoButton, cycleColorButton, startRideButton) {
276− this.triggerHeld = false;
277− this.triggerThreshold = 0.9;
278− this.side = side;
279− this.palm = 2 * side;
280− this.tip = 2 * side + 1;
281− this.trigger = side;
282− this.lines = [];
283− this.deletedLines = [] //just an array of properties objects
284− this.isPainting = false;
285−
286− this.undoButton = undoButton;
287− this.undoButtonPressed = false;
288− this.prevUndoButtonPressed = false;
289−
290− this.redoButton = redoButton;
291− this.redoButtonPressed = false;
292− this.prevRedoButtonPressed = false;
293−
294− this.cycleColorButton = cycleColorButton;
295− this.cycleColorButtonPressed = false;
296− this.prevColorCycleButtonPressed = false;
297−
298− this.startRideButton = startRideButton;
299− this.startRideButtonPressed = false;
300− this.prevStartRideButtonPressed = false;
301−
302− this.strokeCount = 0;
303− this.currentBrushSize = minBrushSize;
304− this.points = [];
305− this.path = [];
306−
307− this.brush = Entities.addEntity({
308− type: 'Sphere',
309− position: {
310− x: 0,
311− y: 0,
312− z: 0
313− },
314− color: currentColor,
315− dimensions: {
316− x: minBrushSize,
317− y: minBrushSize,
318− z: minBrushSize
319− }
320− });
321−
322−
323− this.newLine = function(point) {
324− this.line = Entities.addEntity({
325− position: MyAvatar.position,
326− type: "Line",
327− color: currentColor,
328− dimensions: {
329− x: 10,
330− y: 10,
331− z: 10
332− },
333− lineWidth: 5,
334− lifetime: LINE_LIFETIME
335− });
336− this.points = [];
337− if (point) {
338− this.points.push(point);
339− this.path.push(point);
340− }
341− this.lines.push(this.line);
342− }
343−
344− this.update = function(deltaTime) {
345− this.updateControllerState();
346− this.avatarPalmOffset = Vec3.subtract(this.palmPosition, MyAvatar.position);
347− this.projectedForwardDistance = Vec3.dot(Quat.getFront(Camera.getOrientation()), this.avatarPalmOffset);
348− this.mappedPalmOffset = map(this.projectedForwardDistance, -.5, .5, MIN_DRAW_DISTANCE, MAX_DRAW_DISTANCE);
349− this.tipDirection = Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition));
350− this.offsetVector = Vec3.multiply(this.mappedPalmOffset, this.tipDirection);
351− this.drawPoint = Vec3.sum(this.palmPosition, this.offsetVector);
352− this.currentBrushSize = map(this.triggerValue, 0, 1, minBrushSize, maxBrushSize);
353− Entities.editEntity(this.brush, {
354− position: this.drawPoint,
355− dimensions: {
356− x: this.currentBrushSize,
357− y: this.currentBrushSize,
358− z: this.currentBrushSize
359− },
360− color: currentColor
361− });
362− if (this.triggerValue > MIN_PAINT_TRIGGER_THRESHOLD) {
363− if (!this.isPainting) {
364− this.isPainting = true;
365− this.newLine();
366− this.path = [];
367− }
368− if (this.strokeCount % STROKE_SMOOTH_FACTOR === 0) {
369− this.paint(this.drawPoint);
370− }
371− this.strokeCount++;
372− } else if (this.triggerValue < MIN_PAINT_TRIGGER_THRESHOLD && this.isPainting) {
373− this.releaseTrigger();
374− }
375−
376− this.oldPalmPosition = this.palmPosition;
377− this.oldTipPosition = this.tipPosition;
378− }
379−
380− this.releaseTrigger = function() {
381− this.isPainting = false;
382−
383− }
384−
385−
386− this.updateControllerState = function() {
387− this.undoButtonPressed = Controller.isButtonPressed(this.undoButton);
388− this.redoButtonPressed = Controller.isButtonPressed(this.redoButton);
389− this.cycleColorButtonPressed = Controller.isButtonPressed(this.cycleColorButton);
390− this.startRideButtonPressed = Controller.isButtonPressed(this.startRideButton);
391−
392− //This logic gives us button release
393− if (this.prevUndoButtonPressed === true && this.undoButtonPressed === false) {
394− //User released undo button, so undo
395− this.undoStroke();
396− }
397− if (this.prevRedoButtonPressed === true && this.redoButtonPressed === false) {
398− this.redoStroke();
399− }
400−
401− if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) {
402− cycleColor();
403− Entities.editEntity(this.brush, {
404− color: currentColor
405− });
406− }
407− if (this.prevStartRideButtonPressed === true && this.startRideButtonPressed === false) {
408− lineRider.toggleRide();
409− }
410− this.prevRedoButtonPressed = this.redoButtonPressed;
411− this.prevUndoButtonPressed = this.undoButtonPressed;
412− this.prevCycleColorButtonPressed = this.cycleColorButtonPressed;
413− this.prevStartRideButtonPressed = this.startRideButtonPressed;
414−
415− this.palmPosition = Controller.getSpatialControlPosition(this.palm);
416− this.tipPosition = Controller.getSpatialControlPosition(this.tip);
417− this.triggerValue = Controller.getTriggerValue(this.trigger);
418− }
419−
420− this.undoStroke = function() {
421− var deletedLine = this.lines.pop();
422− var deletedLineProps = Entities.getEntityProperties(deletedLine);
423− this.deletedLines.push(deletedLineProps);
424− Entities.deleteEntity(deletedLine);
425− }
426−
427− this.redoStroke = function() {
428− var restoredLine = Entities.addEntity(this.deletedLines.pop());
429− Entities.addEntity(restoredLine);
430− this.lines.push(restoredLine);
431− }
432−
433− this.paint = function(point) {
434−
435− currentLineWidth = map(this.triggerValue, 0, 1, minLineWidth, maxLineWidth);
436− this.points.push(point);
437− this.path.push(point);
438− Entities.editEntity(this.line, {
439− linePoints: this.points,
440− lineWidth: currentLineWidth,
441− });
442− if (this.points.length > MAX_POINTS_PER_LINE) {
443− this.newLine(point);
444− }
445− }
446−
447− this.cleanup = function() {
448− Entities.deleteEntity(this.brush);
449− this.lines.forEach(function(line) {
450− Entities.deleteEntity(line);
451− });
452− }
453− }
454−
455− function update(deltaTime) {
456− rightController.update(deltaTime);
457− leftController.update(deltaTime);
458− currentTime += deltaTime;
459− }
460−
461− function cleanup() {
462− rightController.cleanup();
463− leftController.cleanup();
464− lineRider.cleanup();
465− }
466−
467− function mousePressEvent(event) {
468− lineRider.mousePressEvent(event);
469− }
470−
471− function vectorIsZero(v) {
472− return v.x === 0 && v.y === 0 && v.z === 0;
473− }
474−
475−
476− var rightController = new controller(RIGHT, RIGHT_BUTTON_3, RIGHT_BUTTON_4, RIGHT_BUTTON_1, RIGHT_BUTTON_2);
477− var leftController = new controller(LEFT, LEFT_BUTTON_3, LEFT_BUTTON_4, LEFT_BUTTON_1, LEFT_BUTTON_2);
478−
479− Script.update.connect(update);
480− Script.scriptEnding.connect(cleanup);
481− Controller.mousePressEvent.connect(mousePressEvent);
482−
483−}
484−
485190 function randFloat(low, high) {
486191 return low + Math.random() * (high - low);
487192 }
examples/pointer.js+3−9
@@ -29,19 +29,13 @@ var buttonOnColor = { · 28 unmodified lines
2929 };
3030
3131 HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
32−var screenSize = Controller.getViewportDimensions();
3332
3433 var userCanPoint = false;
3534 Script.include(["libraries/toolBars.js"]);
36−const persistKey = "highfidelity.pointer.toolbar.position";
37−var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL);
38−toolBar.save = function () {
39− Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y]));
40−};
41−var old = JSON.parse(Settings.getValue(persistKey) || '0');
35+var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.pointer.toolbar", function (screenSize) {
36+ return {x: screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING, y: screenSize.y - (BUTTON_SIZE + PADDING)},
37+});
4238 var pointerButton = toolBar.addOverlay("image", {
43− x: old ? old[0] : screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING,
44− y: old ? old[1] : screenSize.y - (BUTTON_SIZE + PADDING),
4539 width: BUTTON_SIZE,
4640 height: BUTTON_SIZE,
4741 imageURL: HIFI_PUBLIC_BUCKET + "images/laser.png",
examples/stick.js+3−1
@@ -22,10 +22,12 @@ Script.setTimeout(function() { · 21 unmodified lines
2222 type: "Model",
2323 modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.fbx",
2424 compoundShapeURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.obj",
25− dimensions: {x: .11, y: .11, z: .59},
25+ dimensions: {x: .11, y: .11, z: 1.0},
2626 position: MyAvatar.getRightPalmPosition(), // initial position doesn't matter, as long as it's close
2727 rotation: MyAvatar.orientation,
2828 damping: .1,
29+ collisionSoundURL: "http://public.highfidelity.io/sounds/Collisions-hitsandslaps/67LCollision07.wav",
30+ restitution: 0.01,
2931 collisionsWillMove: true
3032 });
3133 actionID = Entities.addAction("hold", stickID, {relativePosition: {x: 0.0, y: 0.0, z: -0.9},
examples/utilities.js+39−35
@@ -9,48 +9,52 @@ · 8 unmodified lines
99 // Distributed under the Apache License, Version 2.0.
1010 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
1111
12−function hslToRgb(hslColor) {
13− var h = hslColor.hue;
14− var s = hslColor.sat;
15− var l = hslColor.light;
16− var r, g, b;
17−
18− if (s == 0) {
19− r = g = b = l; // achromatic
20− } else {
21− var hue2rgb = function hue2rgb(p, q, t) {
22− if (t < 0) t += 1;
23− if (t > 1) t -= 1;
24− if (t < 1 / 6) return p + (q - p) * 6 * t;
25− if (t < 1 / 2) return q;
26− if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
27− return p;
28− }
29−
30− var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
31− var p = 2 * l - q;
32− r = hue2rgb(p, q, h + 1 / 3);
33− g = hue2rgb(p, q, h);
34− b = hue2rgb(p, q, h - 1 / 3);
35− }
3612
37− return {
38− red: Math.round(r * 255),
39− green: Math.round(g * 255),
40− blue: Math.round(b * 255)
41− };
4213
14+map = function(value, min1, max1, min2, max2) {
15+ return min2 + (max2 - min2) * ((value - min1) / (max1 - min1));
4316 }
4417
45−function map(value, min1, max1, min2, max2) {
46− return min2 + (max2 - min2) * ((value - min1) / (max1 - min1));
18+hslToRgb = function(hslColor) {
19+ var h = hslColor.hue;
20+ var s = hslColor.sat;
21+ var l = hslColor.light;
22+ var r, g, b;
23+
24+ if (s == 0) {
25+ r = g = b = l; // achromatic
26+ } else {
27+ var hue2rgb = function hue2rgb(p, q, t) {
28+ if (t < 0) t += 1;
29+ if (t > 1) t -= 1;
30+ if (t < 1 / 6) return p + (q - p) * 6 * t;
31+ if (t < 1 / 2) return q;
32+ if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
33+ return p;
34+ }
35+
36+ var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
37+ var p = 2 * l - q;
38+ r = hue2rgb(p, q, h + 1 / 3);
39+ g = hue2rgb(p, q, h);
40+ b = hue2rgb(p, q, h - 1 / 3);
41+ }
42+
43+ return {
44+ red: Math.round(r * 255),
45+ green: Math.round(g * 255),
46+ blue: Math.round(b * 255)
47+ };
48+
4749 }
4850
49−function randFloat(low, high) {
50− return low + Math.random() * (high - low);
51+
52+
53+randFloat = function(low, high) {
54+ return low + Math.random() * (high - low);
5155 }
5256
5357
54−function randInt(low, high) {
55− return Math.floor(randFloat(low, high));
58+randInt = function(low, high) {
59+ return Math.floor(randFloat(low, high));
5660 }
examples/utilities/tools/cookies.js+25−0
@@ -120,6 +120,23 @@ Slider = function(x,y,width,thumbSize) { · 119 unmodified lines
120120
121121 this.onValueChanged = function(value) {};
122122
123+ this.setMaxValue = function(maxValue) {
124+ if (this.maxValue == maxValue) {
125+ return;
126+ }
127+ var currentVal = this.getValue();
128+ this.maxValue = maxValue;
129+ this.setValue(currentVal);
130+ }
131+ this.setMinValue = function(minValue) {
132+ if (this.minValue == minValue) {
133+ return;
134+ }
135+ var currentVal = this.getValue();
136+ this.minValue = minValue;
137+ this.setValue(currentVal);
138+ }
139+
123140 this.destroy = function() {
124141 Overlays.deleteOverlay(this.background);
125142 Overlays.deleteOverlay(this.thumb);
@@ -613,6 +630,14 @@ Panel = function(x, y) { · 487 unmodified lines
613630 return null;
614631 }
615632
633+ this.getWidget = function(name) {
634+ var item = this.items[name];
635+ if (item != null) {
636+ return item.widget;
637+ }
638+ return null;
639+ }
640+
616641 this.update = function(name) {
617642 var item = this.items[name];
618643 if (item != null) {
examples/utilities/tools/renderEngineDebug.js+42−39
@@ -10,25 +10,7 @@ · 9 unmodified lines
1010
1111 Script.include("cookies.js");
1212
13−var panel = new Panel(10, 400);
14−
15−panel.newCheckbox("Enable Cull Opaque",
16− function(value) { Scene.setEngineCullOpaque((value != 0)); },
17− function() { return Scene.doEngineCullOpaque(); },
18− function(value) { return (value); }
19−);
20−
21−panel.newCheckbox("Enable Sort Opaque",
22− function(value) { Scene.setEngineSortOpaque((value != 0)); },
23− function() { return Scene.doEngineSortOpaque(); },
24− function(value) { return (value); }
25−);
26−
27−panel.newCheckbox("Enable Render Opaque",
28− function(value) { Scene.setEngineRenderOpaque((value != 0)); },
29− function() { return Scene.doEngineRenderOpaque(); },
30− function(value) { return (value); }
31−);
13+var panel = new Panel(10, 800);
3214
3315 panel.newSlider("Num Feed Opaques", 0, 1000,
3416 function(value) { },
@@ -48,49 +30,70 @@ panel.newSlider("Max Drawn Opaques", -1, 1000, · 13 unmodified lines
4830 function(value) { return (value); }
4931 );
5032
51−panel.newCheckbox("Enable Cull Transparent",
52− function(value) { Scene.setEngineCullTransparent((value != 0)); },
53− function() { return Scene.doEngineCullTransparent(); },
33+panel.newSlider("Num Feed Transparents", 0, 100,
34+ function(value) { },
35+ function() { return Scene.getEngineNumFeedTransparentItems(); },
5436 function(value) { return (value); }
5537 );
5638
57−panel.newCheckbox("Enable Sort Transparent",
58− function(value) { Scene.setEngineSortTransparent((value != 0)); },
59− function() { return Scene.doEngineSortTransparent(); },
39+panel.newSlider("Num Drawn Transparents", 0, 100,
40+ function(value) { },
41+ function() { return Scene.getEngineNumDrawnTransparentItems(); },
6042 function(value) { return (value); }
6143 );
6244
63−panel.newCheckbox("Enable Render Transparent",
64− function(value) { Scene.setEngineRenderTransparent((value != 0)); },
65− function() { return Scene.doEngineRenderTransparent(); },
45+panel.newSlider("Max Drawn Transparents", -1, 100,
46+ function(value) { Scene.setEngineMaxDrawnTransparentItems(value); },
47+ function() { return Scene.getEngineMaxDrawnTransparentItems(); },
6648 function(value) { return (value); }
6749 );
6850
69−panel.newSlider("Num Feed Transparents", 0, 100,
51+panel.newSlider("Num Feed Overlay3Ds", 0, 100,
7052 function(value) { },
71− function() { return Scene.getEngineNumFeedTransparentItems(); },
53+ function() { return Scene.getEngineNumFeedOverlay3DItems(); },
7254 function(value) { return (value); }
7355 );
7456
75−panel.newSlider("Num Drawn Transparents", 0, 100,
57+panel.newSlider("Num Drawn Overlay3Ds", 0, 100,
7658 function(value) { },
77− function() { return Scene.getEngineNumDrawnTransparentItems(); },
59+ function() { return Scene.getEngineNumDrawnOverlay3DItems(); },
7860 function(value) { return (value); }
7961 );
8062
81−panel.newSlider("Max Drawn Transparents", -1, 100,
82− function(value) { Scene.setEngineMaxDrawnTransparentItems(value); },
83− function() { return Scene.getEngineMaxDrawnTransparentItems(); },
63+panel.newSlider("Max Drawn Overlay3Ds", -1, 100,
64+ function(value) { Scene.setEngineMaxDrawnOverlay3DItems(value); },
65+ function() { return Scene.getEngineMaxDrawnOverlay3DItems(); },
8466 function(value) { return (value); }
8567 );
8668
8769 var tickTackPeriod = 500;
8870
8971 function updateCounters() {
90− panel.set("Num Feed Opaques", panel.get("Num Feed Opaques"));
91− panel.set("Num Drawn Opaques", panel.get("Num Drawn Opaques"));
92− panel.set("Num Feed Transparents", panel.get("Num Feed Transparents"));
93− panel.set("Num Drawn Transparents", panel.get("Num Drawn Transparents"));
72+ var numFeedOpaques = panel.get("Num Feed Opaques");
73+ var numFeedTransparents = panel.get("Num Feed Transparents");
74+ var numFeedOverlay3Ds = panel.get("Num Feed Overlay3Ds");
75+
76+ panel.set("Num Feed Opaques", numFeedOpaques);
77+ panel.set("Num Drawn Opaques", panel.get("Num Drawn Opaques"));
78+ panel.set("Num Feed Transparents", numFeedTransparents);
79+ panel.set("Num Drawn Transparents", panel.get("Num Drawn Transparents"));
80+ panel.set("Num Feed Overlay3Ds", numFeedOverlay3Ds);
81+ panel.set("Num Drawn Overlay3Ds", panel.get("Num Drawn Overlay3Ds"));
82+
83+ var numMax = Math.max(numFeedOpaques * 1.2, 1);
84+ panel.getWidget("Num Feed Opaques").setMaxValue(numMax);
85+ panel.getWidget("Num Drawn Opaques").setMaxValue(numMax);
86+ panel.getWidget("Max Drawn Opaques").setMaxValue(numMax);
87+
88+ numMax = Math.max(numFeedTransparents * 1.2, 1);
89+ panel.getWidget("Num Feed Transparents").setMaxValue(numMax);
90+ panel.getWidget("Num Drawn Transparents").setMaxValue(numMax);
91+ panel.getWidget("Max Drawn Transparents").setMaxValue(numMax);
92+
93+ numMax = Math.max(numFeedOverlay3Ds * 1.2, 1);
94+ panel.getWidget("Num Feed Overlay3Ds").setMaxValue(numMax);
95+ panel.getWidget("Num Drawn Overlay3Ds").setMaxValue(numMax);
96+ panel.getWidget("Max Drawn Overlay3Ds").setMaxValue(numMax);
9497 }
9598 Script.setInterval(updateCounters, tickTackPeriod);
9699
interface/resources/images/address-bar.svg+21−5
@@ -15,7 +15,7 @@ · 14 unmodified lines
1515 viewBox="0 0 1440 200"
1616 id="svg4136"
1717 inkscape:version="0.91 r13725"
18− sodipodi:docname="address-bar.svg">
18+ sodipodi:docname="address-bar.002.svg">
1919 <metadata
2020 id="metadata4144">
2121 <rdf:RDF>
@@ -39,14 +39,14 @@ · 17 unmodified lines
3939 guidetolerance="10"
4040 inkscape:pageopacity="0"
4141 inkscape:pageshadow="2"
42− inkscape:window-width="1840"
42+ inkscape:window-width="1835"
4343 inkscape:window-height="1057"
4444 id="namedview4140"
4545 showgrid="false"
46− inkscape:zoom="0.8671875"
47− inkscape:cx="707.02439"
46+ inkscape:zoom="0.61319416"
47+ inkscape:cx="132.58366"
4848 inkscape:cy="52.468468"
49− inkscape:window-x="72"
49+ inkscape:window-x="77"
5050 inkscape:window-y="-8"
5151 inkscape:window-maximized="1"
5252 inkscape:current-layer="svg4136" />
@@ -59,6 +59,15 @@ · 6 unmodified lines
5959 y="30"
6060 rx="16.025024"
6161 ry="17.019567" />
62+ <rect
63+ style="fill:#dadada;fill-opacity:1;stroke:#cbcbcb;stroke-width:0.33821851;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
64+ id="rect4135"
65+ width="292.86267"
66+ height="139.66179"
67+ x="150.32542"
68+ y="30.169102"
69+ rx="16.817432"
70+ ry="20.612938" />
6271 <circle
6372 style="fill:#b8b8b8;fill-opacity:1;stroke:none;stroke-opacity:1"
6473 id="path4146"
@@ -69,4 +78,11 @@ · 4 unmodified lines
6978 d="m 100,36.000005 c -22.1,0 -40,17.9 -40,39.999995 0,30 40,88 40,88 0,0 40,-58 40,-88 0,-22.099995 -17.9,-39.999995 -40,-39.999995 z m 0,22 c 9.9,0 18,8.099995 18,17.999995 0,9.9 -8.1,18 -18,18 -9.9,0 -18,-8.1 -18,-18 0,-9.9 8.1,-17.999995 18,-17.999995 z"
7079 id="path4138"
7180 inkscape:connector-curvature="0" />
81+ <rect
82+ style="fill:#bdbdbd;fill-opacity:1;stroke:none;stroke-width:0.30000001;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
83+ id="rect4136"
84+ width="4"
85+ height="100"
86+ x="310.12924"
87+ y="50" />
7288 </svg>
interface/resources/images/arrow.png+0−0

Binary file not shown.

interface/resources/images/left-arrow.svg+50−0
@@ -0,0 +1,50 @@
1+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3+
4+<svg
5+ xmlns:dc="http://purl.org/dc/elements/1.1/"
6+ xmlns:cc="http://creativecommons.org/ns#"
7+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8+ xmlns:svg="http://www.w3.org/2000/svg"
9+ xmlns="http://www.w3.org/2000/svg"
10+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12+ version="1.1"
13+ id="Layer_1"
14+ x="0px"
15+ y="0px"
16+ viewBox="133.1 714.2 21.3 33.4"
17+ enable-background="new 133.1 714.2 21.3 33.4"
18+ xml:space="preserve"
19+ inkscape:version="0.91 r13725"
20+ sodipodi:docname="left-arrow.svg"><metadata
21+ id="metadata13"><rdf:RDF><cc:Work
22+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
23+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
24+ id="defs11" /><sodipodi:namedview
25+ pagecolor="#ffffff"
26+ bordercolor="#666666"
27+ borderopacity="1"
28+ objecttolerance="10"
29+ gridtolerance="10"
30+ guidetolerance="10"
31+ inkscape:pageopacity="0"
32+ inkscape:pageshadow="2"
33+ inkscape:window-width="1835"
34+ inkscape:window-height="1057"
35+ id="namedview9"
36+ showgrid="false"
37+ inkscape:zoom="7.0658679"
38+ inkscape:cx="10.65"
39+ inkscape:cy="16.700001"
40+ inkscape:window-x="77"
41+ inkscape:window-y="-8"
42+ inkscape:window-maximized="1"
43+ inkscape:current-layer="Layer_1" /><g
44+ id="g3"
45+ transform="matrix(-1,0,0,1,287.5,0)"><g
46+ id="g5"><path
47+ d="m 133.1,714.2 21.3,16.7 -21.3,16.7 0,-33.4 z"
48+ id="path7"
49+ inkscape:connector-curvature="0"
50+ style="fill:#535353" /></g></g></svg>
interface/resources/images/redarrow.svg+11−0
@@ -0,0 +1,11 @@
1+<?xml version="1.0" encoding="utf-8"?>
2+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3+<svg version="1.1" id="Layer_1" xmlns:xl="http://www.w3.org/1999/xlink"
4+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="133.1 714.2 21.3 33.4"
5+ enable-background="new 133.1 714.2 21.3 33.4" xml:space="preserve">
6+<g>
7+ <g>
8+ <path fill="#FF5353" d="M133.1,714.2l21.3,16.7l-21.3,16.7V714.2z"/>
9+ </g>
10+</g>
11+</svg>
interface/resources/images/redarrow_reversed.svg+11−0
@@ -0,0 +1,11 @@
1+<?xml version="1.0" encoding="utf-8"?>
2+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3+<svg version="1.1" id="Layer_1" xmlns:xl="http://www.w3.org/1999/xlink"
4+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="225.8 714.2 326.5 512"
5+ enable-background="new 225.8 714.2 326.5 512" xml:space="preserve">
6+<g>
7+ <g>
8+ <path fill="#FF5353" d="M552.4,1226.2l-326.5-256l326.5-256V1226.2z"/>
9+ </g>
10+</g>
11+</svg>
interface/resources/images/right-arrow.svg+11−0
@@ -0,0 +1,11 @@
1+<?xml version="1.0" encoding="utf-8"?>
2+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3+<svg version="1.1" id="Layer_1" xmlns:xl="http://www.w3.org/1999/xlink"
4+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="133.1 714.2 21.3 33.4"
5+ enable-background="new 133.1 714.2 21.3 33.4" xml:space="preserve">
6+<g>
7+ <g>
8+ <path fill="#535353" d="M133.1,714.2l21.3,16.7l-21.3,16.7V714.2z"/>
9+ </g>
10+</g>
11+</svg>
interface/resources/qml/AddressBarDialog.qml+68−22
@@ -30,6 +30,7 @@ DialogContainer { · 29 unmodified lines
3030 property int maximumX: parent ? parent.width - width : 0
3131 property int maximumY: parent ? parent.height - height : 0
3232
33+
3334 AddressBarDialog {
3435 id: addressBarDialog
3536
@@ -45,28 +46,6 @@ DialogContainer { · 9 unmodified lines
4546 property int inputAreaHeight: 56.0 * root.scale // Height of the background's input area
4647 property int inputAreaStep: (height - inputAreaHeight) / 2
4748
48− TextInput {
49− id: addressLine
50−
51− anchors {
52− fill: parent
53− leftMargin: parent.height + hifi.layout.spacing * 2
54− rightMargin: hifi.layout.spacing * 2
55− topMargin: parent.inputAreaStep + hifi.layout.spacing
56− bottomMargin: parent.inputAreaStep + hifi.layout.spacing
57−
58− }
59−
60− font.pixelSize: hifi.fonts.pixelSize * root.scale
61−
62− helperText: "Go to: place, @user, /path, network address"
63−
64− onAccepted: {
65− event.accepted = true // Generates erroneous error in program log, "ReferenceError: event is not defined".
66− addressBarDialog.loadAddress(addressLine.text)
67− }
68− }
69−
7049 MouseArea {
7150 // Drag the icon
7251 width: parent.height
@@ -96,6 +75,73 @@ DialogContainer { · 23 unmodified lines
9675 maximumY: root.parent ? root.maximumY + parent.inputAreaStep : 0
9776 }
9877 }
78+
79+ Image {
80+ id: backArrow
81+
82+ source: addressBarDialog.backEnabled ? "../images/left-arrow.svg" : "../images/redarrow_reversed.svg"
83+
84+ anchors {
85+ fill: parent
86+ leftMargin: parent.height + hifi.layout.spacing + 6
87+ rightMargin: parent.height + hifi.layout.spacing * 60
88+ topMargin: parent.inputAreaStep + parent.inputAreaStep + hifi.layout.spacing
89+ bottomMargin: parent.inputAreaStep + parent.inputAreaStep + hifi.layout.spacing
90+ }
91+
92+ MouseArea {
93+ anchors.fill: parent
94+ acceptedButtons: Qt.LeftButton
95+ onClicked: {
96+ addressBarDialog.loadBack()
97+ }
98+ }
99+ }
100+
101+ Image {
102+ id: forwardArrow
103+
104+ source: addressBarDialog.forwardEnabled ? "../images/right-arrow.svg" : "../images/redarrow.svg"
105+
106+ anchors {
107+ fill: parent
108+ leftMargin: parent.height + hifi.layout.spacing * 9
109+ rightMargin: parent.height + hifi.layout.spacing * 53
110+ topMargin: parent.inputAreaStep + parent.inputAreaStep + hifi.layout.spacing
111+ bottomMargin: parent.inputAreaStep + parent.inputAreaStep + hifi.layout.spacing
112+ }
113+
114+ MouseArea {
115+ anchors.fill: parent
116+ acceptedButtons: Qt.LeftButton
117+ onClicked: {
118+ addressBarDialog.loadForward()
119+ }
120+ }
121+ }
122+
123+ TextInput {
124+ id: addressLine
125+
126+ anchors {
127+ fill: parent
128+ leftMargin: parent.height + parent.height + hifi.layout.spacing * 5
129+ rightMargin: hifi.layout.spacing * 2
130+ topMargin: parent.inputAreaStep + hifi.layout.spacing
131+ bottomMargin: parent.inputAreaStep + hifi.layout.spacing
132+
133+ }
134+
135+ font.pixelSize: hifi.fonts.pixelSize * root.scale * 0.75
136+
137+ helperText: "Go to: place, @user, /path, network address"
138+
139+ onAccepted: {
140+ event.accepted = true // Generates erroneous error in program log, "ReferenceError: event is not defined".
141+ addressBarDialog.loadAddress(addressLine.text)
142+ }
143+ }
144+
99145 }
100146 }
101147
interface/resources/qml/AvatarInputs.qml+177−0
@@ -0,0 +1,177 @@
1+//
2+// Created by Bradley Austin Davis on 2015/06/19
3+// Copyright 2015 High Fidelity, Inc.
4+//
5+// Distributed under the Apache License, Version 2.0.
6+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
7+//
8+
9+import Hifi 1.0 as Hifi
10+import QtQuick 2.4
11+import QtQuick.Controls 1.3
12+import QtGraphicalEffects 1.0
13+
14+Hifi.AvatarInputs {
15+ id: root
16+ objectName: "AvatarInputs"
17+ anchors.fill: parent
18+
19+// width: 800
20+// height: 600
21+// color: "black"
22+ readonly property int iconPadding: 5
23+ readonly property int mirrorHeight: 215
24+ readonly property int mirrorWidth: 265
25+ readonly property int mirrorTopPad: iconPadding
26+ readonly property int mirrorLeftPad: 10
27+ readonly property int iconSize: 24
28+
29+ Item {
30+ id: mirror
31+ width: root.mirrorWidth
32+ height: root.mirrorVisible ? root.mirrorHeight : 0
33+ visible: root.mirrorVisible
34+ anchors.left: parent.left
35+ anchors.leftMargin: root.mirrorLeftPad
36+ anchors.top: parent.top
37+ anchors.topMargin: root.mirrorTopPad
38+ clip: true
39+
40+ MouseArea {
41+ id: hover
42+ anchors.fill: parent
43+ hoverEnabled: true
44+ propagateComposedEvents: true
45+ }
46+
47+ Image {
48+ id: closeMirror
49+ visible: hover.containsMouse
50+ width: root.iconSize
51+ height: root.iconSize
52+ anchors.top: parent.top
53+ anchors.topMargin: root.iconPadding
54+ anchors.left: parent.left
55+ anchors.leftMargin: root.iconPadding
56+ source: "../images/close.svg"
57+ MouseArea {
58+ anchors.fill: parent
59+ onClicked: {
60+ root.closeMirror();
61+ }
62+ }
63+ }
64+
65+ Image {
66+ id: zoomIn
67+ visible: hover.containsMouse
68+ width: root.iconSize
69+ height: root.iconSize
70+ anchors.bottom: parent.bottom
71+ anchors.bottomMargin: root.iconPadding
72+ anchors.left: parent.left
73+ anchors.leftMargin: root.iconPadding
74+ source: root.mirrorZoomed ? "../images/minus.svg" : "../images/plus.svg"
75+ MouseArea {
76+ anchors.fill: parent
77+ onClicked: {
78+ root.toggleZoom();
79+ }
80+ }
81+ }
82+ }
83+
84+ Item {
85+ width: root.mirrorWidth
86+ height: 44
87+
88+ x: root.mirrorLeftPad
89+ y: root.mirrorVisible ? root.mirrorTopPad + root.mirrorHeight : 5
90+
91+
92+
93+ Rectangle {
94+ anchors.fill: parent
95+ color: root.mirrorVisible ? (root.audioClipping ? "red" : "#696969") : "#00000000"
96+
97+ Image {
98+ id: faceMute
99+ width: root.iconSize
100+ height: root.iconSize
101+ visible: root.cameraEnabled
102+ anchors.left: parent.left
103+ anchors.leftMargin: root.iconPadding
104+ anchors.verticalCenter: parent.verticalCenter
105+ source: root.cameraMuted ? "../images/face-mute.svg" : "../images/face.svg"
106+ MouseArea {
107+ anchors.fill: parent
108+ onClicked: {
109+ root.toggleCameraMute()
110+ }
111+ onDoubleClicked: {
112+ root.resetSensors();
113+ }
114+ }
115+ }
116+
117+ Image {
118+ id: micMute
119+ width: root.iconSize
120+ height: root.iconSize
121+ anchors.left: root.cameraEnabled ? faceMute.right : parent.left
122+ anchors.leftMargin: root.iconPadding
123+ anchors.verticalCenter: parent.verticalCenter
124+ source: root.audioMuted ? "../images/mic-mute.svg" : "../images/mic.svg"
125+ MouseArea {
126+ anchors.fill: parent
127+ onClicked: {
128+ root.toggleAudioMute()
129+ }
130+ }
131+ }
132+
133+ Item {
134+ id: audioMeter
135+ anchors.verticalCenter: parent.verticalCenter
136+ anchors.left: micMute.right
137+ anchors.leftMargin: root.iconPadding
138+ anchors.right: parent.right
139+ anchors.rightMargin: root.iconPadding
140+ height: 8
141+ Rectangle {
142+ id: blueRect
143+ color: "blue"
144+ anchors.top: parent.top
145+ anchors.bottom: parent.bottom
146+ anchors.left: parent.left
147+ width: parent.width / 4
148+ }
149+ Rectangle {
150+ id: greenRect
151+ color: "green"
152+ anchors.top: parent.top
153+ anchors.bottom: parent.bottom
154+ anchors.left: blueRect.right
155+ anchors.right: redRect.left
156+ }
157+ Rectangle {
158+ id: redRect
159+ color: "red"
160+ anchors.top: parent.top
161+ anchors.bottom: parent.bottom
162+ anchors.right: parent.right
163+ width: parent.width / 5
164+ }
165+ Rectangle {
166+ z: 100
167+ anchors.top: parent.top
168+ anchors.bottom: parent.bottom
169+ anchors.right: parent.right
170+ width: (1.0 - root.audioLevel) * parent.width
171+ color: "black"
172+ }
173+ }
174+ }
175+ }
176+}
177+
interface/resources/qml/Stats.qml+258−0
@@ -0,0 +1,258 @@
1+import Hifi 1.0 as Hifi
2+import QtQuick 2.3
3+import QtQuick.Controls 1.2
4+
5+Item {
6+ anchors.fill: parent
7+ anchors.leftMargin: 300
8+ Hifi.Stats {
9+ id: root
10+ objectName: "Stats"
11+ implicitHeight: row.height
12+ implicitWidth: row.width
13+
14+ anchors.horizontalCenter: parent.horizontalCenter
15+
16+ readonly property int sTATS_GENERAL_MIN_WIDTH: 165
17+ readonly property int sTATS_PING_MIN_WIDTH: 190
18+ readonly property int sTATS_GEO_MIN_WIDTH: 240
19+ readonly property int sTATS_OCTREE_MIN_WIDTH: 410
20+ readonly property int fontSize: 12
21+ readonly property string fontColor: "white"
22+ readonly property string bgColor: "#99333333"
23+
24+ Row {
25+ id: row
26+ spacing: 8
27+ Rectangle {
28+ width: generalCol.width + 8;
29+ height: generalCol.height + 8;
30+ color: root.bgColor;
31+
32+ MouseArea {
33+ anchors.fill: parent
34+ onClicked: { root.expanded = !root.expanded; }
35+ }
36+
37+ Column {
38+ id: generalCol
39+ spacing: 4; x: 4; y: 4;
40+ width: sTATS_GENERAL_MIN_WIDTH
41+ Text {
42+ color: root.fontColor;
43+ font.pixelSize: root.fontSize
44+ text: "Servers: " + root.serverCount
45+ }
46+ Text {
47+ color: root.fontColor;
48+ font.pixelSize: root.fontSize
49+ text: "Avatars: " + root.avatarCount
50+ }
51+ Text {
52+ color: root.fontColor;
53+ font.pixelSize: root.fontSize
54+ text: "Framerate: " + root.framerate
55+ }
56+ Text {
57+ color: root.fontColor;
58+ font.pixelSize: root.fontSize
59+ text: "Packets In/Out: " + root.packetInCount + "/" + root.packetOutCount
60+ }
61+ Text {
62+ color: root.fontColor;
63+ font.pixelSize: root.fontSize
64+ text: "Mbps In/Out: " + root.mbpsIn.toFixed(2) + "/" + root.mbpsOut.toFixed(2)
65+ }
66+ }
67+ }
68+
69+ Rectangle {
70+ width: pingCol.width + 8
71+ height: pingCol.height + 8
72+ color: root.bgColor;
73+ visible: root.audioPing != -2
74+ MouseArea {
75+ anchors.fill: parent
76+ onClicked: { root.expanded = !root.expanded; }
77+ }
78+ Column {
79+ id: pingCol
80+ spacing: 4; x: 4; y: 4;
81+ width: sTATS_PING_MIN_WIDTH
82+ Text {
83+ color: root.fontColor
84+ font.pixelSize: root.fontSize
85+ text: "Audio ping: " + root.audioPing
86+ }
87+ Text {
88+ color: root.fontColor
89+ font.pixelSize: root.fontSize
90+ text: "Avatar ping: " + root.avatarPing
91+ }
92+ Text {
93+ color: root.fontColor
94+ font.pixelSize: root.fontSize
95+ text: "Entities avg ping: " + root.entitiesPing
96+ }
97+ Text {
98+ color: root.fontColor
99+ font.pixelSize: root.fontSize
100+ visible: root.expanded;
101+ text: "Voxel max ping: " + 0
102+ }
103+ }
104+ }
105+
106+ Rectangle {
107+ width: geoCol.width + 8
108+ height: geoCol.height + 8
109+ color: root.bgColor;
110+ MouseArea {
111+ anchors.fill: parent
112+ onClicked: { root.expanded = !root.expanded; }
113+ }
114+ Column {
115+ id: geoCol
116+ spacing: 4; x: 4; y: 4;
117+ width: sTATS_GEO_MIN_WIDTH
118+ Text {
119+ color: root.fontColor;
120+ font.pixelSize: root.fontSize
121+ text: "Position: " + root.position.x.toFixed(1) + ", " +
122+ root.position.y.toFixed(1) + ", " + root.position.z.toFixed(1)
123+ }
124+ Text {
125+ color: root.fontColor;
126+ font.pixelSize: root.fontSize
127+ text: "Velocity: " + root.velocity.toFixed(1)
128+ }
129+ Text {
130+ color: root.fontColor;
131+ font.pixelSize: root.fontSize
132+ text: "Yaw: " + root.yaw.toFixed(1)
133+ }
134+ Text {
135+ color: root.fontColor;
136+ font.pixelSize: root.fontSize
137+ visible: root.expanded;
138+ text: "Avatar Mixer: " + root.avatarMixerKbps + " kbps, " +
139+ root.avatarMixerPps + "pps";
140+ }
141+ Text {
142+ color: root.fontColor;
143+ font.pixelSize: root.fontSize
144+ visible: root.expanded;
145+ text: "Downloads: ";
146+ }
147+ }
148+ }
149+ Rectangle {
150+ width: octreeCol.width + 8
151+ height: octreeCol.height + 8
152+ color: root.bgColor;
153+ MouseArea {
154+ anchors.fill: parent
155+ onClicked: { root.expanded = !root.expanded; }
156+ }
157+ Column {
158+ id: octreeCol
159+ spacing: 4; x: 4; y: 4;
160+ width: sTATS_OCTREE_MIN_WIDTH
161+ Text {
162+ color: root.fontColor;
163+ font.pixelSize: root.fontSize
164+ text: "Triangles: " + root.triangles +
165+ " / Quads: " + root.quads + " / Material Switches: " + root.materialSwitches
166+ }
167+ Text {
168+ color: root.fontColor;
169+ font.pixelSize: root.fontSize
170+ visible: root.expanded;
171+ text: "\tMesh Parts Rendered Opaque: " + root.meshOpaque +
172+ " / Translucent: " + root.meshTranslucent;
173+ }
174+ Text {
175+ color: root.fontColor;
176+ font.pixelSize: root.fontSize
177+ visible: root.expanded;
178+ text: "\tOpaque considered: " + root.opaqueConsidered +
179+ " / Out of view: " + root.opaqueOutOfView + " / Too small: " + root.opaqueTooSmall;
180+ }
181+ Text {
182+ color: root.fontColor;
183+ font.pixelSize: root.fontSize
184+ visible: !root.expanded
185+ text: "Octree Elements Server: " + root.serverElements +
186+ " Local: " + root.localElements;
187+ }
188+ Text {
189+ color: root.fontColor;
190+ font.pixelSize: root.fontSize
191+ visible: root.expanded
192+ text: "Octree Sending Mode: " + root.sendingMode;
193+ }
194+ Text {
195+ color: root.fontColor;
196+ font.pixelSize: root.fontSize
197+ visible: root.expanded
198+ text: "Octree Packets to Process: " + root.packetStats;
199+ }
200+ Text {
201+ color: root.fontColor;
202+ font.pixelSize: root.fontSize
203+ visible: root.expanded
204+ text: "Octree Elements - ";
205+ }
206+ Text {
207+ color: root.fontColor;
208+ font.pixelSize: root.fontSize
209+ visible: root.expanded
210+ text: "\tServer: " + root.serverElements +
211+ " Internal: " + root.serverInternal +
212+ " Leaves: " + root.serverLeaves;
213+ }
214+ Text {
215+ color: root.fontColor;
216+ font.pixelSize: root.fontSize
217+ visible: root.expanded
218+ text: "\tLocal: " + root.localElements +
219+ " Internal: " + root.localInternal +
220+ " Leaves: " + root.localLeaves;
221+ }
222+ Text {
223+ color: root.fontColor;
224+ font.pixelSize: root.fontSize
225+ visible: root.expanded
226+ text: "LOD: " + root.lodStatus;
227+ }
228+ }
229+ }
230+ }
231+
232+ Rectangle {
233+ y: 250
234+ visible: root.timingExpanded
235+ width: perfText.width + 8
236+ height: perfText.height + 8
237+ color: root.bgColor;
238+ Text {
239+ x: 4; y: 4
240+ id: perfText
241+ color: root.fontColor
242+ font.family: root.monospaceFont
243+ font.pixelSize: 12
244+ text: "------------------------------------------ Function " +
245+ "--------------------------------------- --msecs- -calls--\n" +
246+ root.timingStats;
247+ }
248+ }
249+
250+ Connections {
251+ target: root.parent
252+ onWidthChanged: {
253+ root.x = root.parent.width - root.width;
254+ }
255+ }
256+ }
257+
258+}
interface/resources/qml/Tooltip.qml+31−0
@@ -0,0 +1,31 @@
1+import Hifi 1.0 as Hifi
2+import QtQuick 2.3 as Original
3+import "controls"
4+import "styles"
5+
6+Hifi.Tooltip {
7+ id: root
8+ HifiConstants { id: hifi }
9+ // FIXME adjust position based on the edges of the screen
10+ x: (lastMousePosition.x > surfaceSize.width/2) ? lastMousePosition.x - 140 : lastMousePosition.x + 20
11+ //y: lastMousePosition.y + 5
12+ y: (lastMousePosition.y > surfaceSize.height/2) ? lastMousePosition.y - 70 : lastMousePosition.y + 5
13+ implicitWidth: border.implicitWidth
14+ implicitHeight: border.implicitHeight
15+
16+ Border {
17+ id: border
18+ anchors.fill: parent
19+ implicitWidth: text.implicitWidth
20+ implicitHeight: Math.max(text.implicitHeight, 64)
21+
22+ Text {
23+ id: text
24+ anchors.fill: parent
25+ anchors.margins: 16
26+ font.pixelSize: hifi.fonts.pixelSize / 2
27+ text: root.text
28+ wrapMode: Original.Text.WordWrap
29+ }
30+ }
31+}
interface/src/Application.cpp+115−156
@@ -66,6 +66,9 @@ · 65 unmodified lines
6666 #include <EntityScriptingInterface.h>
6767 #include <ErrorDialog.h>
6868 #include <GlowEffect.h>
69+#include <gpu/Batch.h>
70+#include <gpu/Context.h>
71+#include <gpu/GLBackend.h>
6972 #include <HFActionEvent.h>
7073 #include <HFBackEvent.h>
7174 #include <InfoView.h>
@@ -83,12 +86,14 @@ · 11 unmodified lines
8386 #include <PerfStat.h>
8487 #include <PhysicsEngine.h>
8588 #include <ProgramObject.h>
89+#include <RenderDeferredTask.h>
8690 #include <ResourceCache.h>
8791 #include <SceneScriptingInterface.h>
8892 #include <ScriptCache.h>
8993 #include <SettingHandle.h>
9094 #include <SoundCache.h>
9195 #include <TextRenderer.h>
96+#include <Tooltip.h>
9297 #include <UserActivityLogger.h>
9398 #include <UUID.h>
9499 #include <VrMenu.h>
@@ -106,11 +111,9 @@ · 11 unmodified lines
106111
107112 #include "avatar/AvatarManager.h"
108113
109−#include "audio/AudioToolBox.h"
110114 #include "audio/AudioIOStatsRenderer.h"
111115 #include "audio/AudioScope.h"
112116
113−#include "devices/CameraToolBox.h"
114117 #include "devices/DdeFaceTracker.h"
115118 #include "devices/Faceshift.h"
116119 #include "devices/Leapmotion.h"
@@ -120,12 +123,6 @@ · 3 unmodified lines
120123 #include "devices/OculusManager.h"
121124 #include "devices/TV3DManager.h"
122125
123−#include "gpu/Batch.h"
124−#include "gpu/Context.h"
125−#include "gpu/GLBackend.h"
126−
127−#include "RenderDeferredTask.h"
128−
129126 #include "scripting/AccountScriptingInterface.h"
130127 #include "scripting/AudioDeviceScriptingInterface.h"
131128 #include "scripting/ClipboardScriptingInterface.h"
@@ -141,6 +138,7 @@ · 9 unmodified lines
141138 #include "SpeechRecognizer.h"
142139 #endif
143140
141+#include "ui/AvatarInputs.h"
144142 #include "ui/DataWebDialog.h"
145143 #include "ui/DialogsManager.h"
146144 #include "ui/LoginDialog.h"
@@ -281,8 +279,6 @@ bool setupEssentials(int& argc, char** argv) { · 134 unmodified lines
281279 auto animationCache = DependencyManager::set<AnimationCache>();
282280 auto ddeFaceTracker = DependencyManager::set<DdeFaceTracker>();
283281 auto modelBlender = DependencyManager::set<ModelBlender>();
284− auto audioToolBox = DependencyManager::set<AudioToolBox>();
285− auto cameraToolBox = DependencyManager::set<CameraToolBox>();
286282 auto avatarManager = DependencyManager::set<AvatarManager>();
287283 auto lodManager = DependencyManager::set<LODManager>();
288284 auto jsConsole = DependencyManager::set<StandAloneJSConsole>();
@@ -335,8 +331,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : · 46 unmodified lines
335331 _cursorVisible(true),
336332 _lastMouseMove(usecTimestampNow()),
337333 _lastMouseMoveWasSimulated(false),
338− _touchAvgX(0.0f),
339− _touchAvgY(0.0f),
340334 _isTouchPressed(false),
341335 _mousePressed(false),
342336 _enableProcessOctreeThread(true),
@@ -814,9 +808,9 @@ void Application::initializeGL() { · 471 unmodified lines
814808 _idleLoopStdev.reset();
815809
816810 if (_justStarted) {
817− float startupTime = (float)_applicationStartupTime.elapsed() / 1000.0;
811+ float startupTime = (float)_applicationStartupTime.elapsed() / 1000.0f;
818812 _justStarted = false;
819− qCDebug(interfaceapp, "Startup time: %4.2f seconds.", startupTime);
813+ qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTime);
820814 }
821815
822816 // update before the first render
@@ -831,6 +825,7 @@ void Application::initializeUi() { · 8 unmodified lines
831825 LoginDialog::registerType();
832826 MessageDialog::registerType();
833827 VrMenu::registerType();
828+ Tooltip::registerType();
834829 UpdateDialog::registerType();
835830
836831 auto offscreenUi = DependencyManager::get<OffscreenUi>();
@@ -844,7 +839,7 @@ void Application::initializeUi() { · 7 unmodified lines
844839 VrMenu::executeQueuedLambdas();
845840 offscreenUi->setMouseTranslator([this](const QPointF& p){
846841 if (OculusManager::isConnected()) {
847− glm::vec2 pos = _applicationOverlay.screenToOverlay(toGlm(p));
842+ glm::vec2 pos = _compositor.screenToOverlay(toGlm(p));
848843 return QPointF(pos.x, pos.y);
849844 }
850845 return QPointF(p);
@@ -877,6 +872,7 @@ void Application::paintGL() { · 26 unmodified lines
877872 OculusManager::beginFrameTiming();
878873 }
879874
875+
880876 PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings));
881877 bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
882878 PerformanceWarning warn(showWarnings, "Application::paintGL()");
@@ -884,6 +880,12 @@ void Application::paintGL() { · 1 unmodified line
884880
885881 {
886882 PerformanceTimer perfTimer("renderOverlay");
883+ /*
884+ gpu::Context context(new gpu::GLBackend());
885+ RenderArgs renderArgs(&context, nullptr, getViewFrustum(), lodManager->getOctreeSizeScale(),
886+ lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE,
887+ RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
888+ */
887889 _applicationOverlay.renderOverlay(&renderArgs);
888890 }
889891
@@ -912,13 +914,18 @@ void Application::paintGL() { · 22 unmodified lines
912914 }
913915
914916 } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
915− _myCamera.setPosition(_myAvatar->getDefaultEyePosition() +
916− _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, 1.0f) * _myAvatar->getBoomLength() * _myAvatar->getScale());
917917 if (OculusManager::isConnected()) {
918918 _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation());
919919 } else {
920920 _myCamera.setRotation(_myAvatar->getHead()->getOrientation());
921921 }
922+ if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) {
923+ _myCamera.setPosition(_myAvatar->getDefaultEyePosition() +
924+ _myCamera.getRotation() * glm::vec3(0.0f, 0.0f, 1.0f) * _myAvatar->getBoomLength() * _myAvatar->getScale());
925+ } else {
926+ _myCamera.setPosition(_myAvatar->getDefaultEyePosition() +
927+ _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, 1.0f) * _myAvatar->getBoomLength() * _myAvatar->getScale());
928+ }
922929
923930 } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
924931 _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
@@ -967,9 +974,7 @@ void Application::paintGL() { · 42 unmodified lines
967974 glPopMatrix();
968975
969976 renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE;
970− if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
971− _rearMirrorTools->render(&renderArgs, true, _glWidget->mapFromGlobal(QCursor::pos()));
972− } else if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
977+ if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
973978 renderRearViewMirror(&renderArgs, _mirrorViewRect);
974979 }
975980
@@ -977,6 +982,7 @@ void Application::paintGL() { · 1 unmodified line
977982
978983 auto finalFbo = DependencyManager::get<GlowEffect>()->render(&renderArgs);
979984
985+
980986 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
981987 glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo));
982988 glBlitFramebuffer(0, 0, _renderResolution.x, _renderResolution.y,
@@ -984,9 +990,10 @@ void Application::paintGL() { · 1 unmodified line
984990 GL_COLOR_BUFFER_BIT, GL_NEAREST);
985991 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
986992
987− _applicationOverlay.displayOverlayTexture();
993+ _compositor.displayOverlayTexture(&renderArgs);
988994 }
989995
996+
990997 if (!OculusManager::isConnected() || OculusManager::allowSwap()) {
991998 _glWidget->swapBuffers();
992999 }
@@ -1044,27 +1051,24 @@ void Application::resizeGL() { · 51 unmodified lines
10441051 } else {
10451052 renderSize = _glWidget->getDeviceSize() * getRenderResolutionScale();
10461053 }
1047− if (_renderResolution == toGlm(renderSize)) {
1048− return;
1049− }
10501054
1051− _renderResolution = toGlm(renderSize);
1052− DependencyManager::get<TextureCache>()->setFrameBufferSize(renderSize);
1053− resetCamerasOnResizeGL(_myCamera, _renderResolution);
1055+ if (_renderResolution != toGlm(renderSize)) {
1056+ _renderResolution = toGlm(renderSize);
1057+ DependencyManager::get<TextureCache>()->setFrameBufferSize(renderSize);
1058+ resetCamerasOnResizeGL(_myCamera, _renderResolution);
10541059
1055− glViewport(0, 0, _renderResolution.x, _renderResolution.y); // shouldn't this account for the menu???
1060+ glViewport(0, 0, _renderResolution.x, _renderResolution.y); // shouldn't this account for the menu???
10561061
1057− updateProjectionMatrix();
1058− glLoadIdentity();
1062+ updateProjectionMatrix();
1063+ glLoadIdentity();
1064+ }
10591065
10601066 auto offscreenUi = DependencyManager::get<OffscreenUi>();
1061− offscreenUi->resize(_glWidget->size());
1067+
1068+ auto canvasSize = _glWidget->size();
1069+ offscreenUi->resize(canvasSize);
10621070 _glWidget->makeCurrent();
10631071
1064− // update Stats width
1065− // let's set horizontal offset to give stats some margin to mirror
1066− int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2;
1067− Stats::getInstance()->resetWidth(_renderResolution.x, horizontalOffset);
10681072 }
10691073
10701074 void Application::updateProjectionMatrix() {
@@ -1568,27 +1572,9 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { · 497 unmodified lines
15681572 _keyboardMouseDevice.mousePressEvent(event);
15691573
15701574 if (event->button() == Qt::LeftButton) {
1571− _mouseDragStartedX = getTrueMouseX();
1572− _mouseDragStartedY = getTrueMouseY();
1575+ _mouseDragStarted = getTrueMouse();
15731576 _mousePressed = true;
15741577
1575− if (mouseOnScreen()) {
1576− if (DependencyManager::get<AudioToolBox>()->mousePressEvent(getMouseX(), getMouseY())) {
1577− // stop propagation
1578− return;
1579− }
1580−
1581− if (DependencyManager::get<CameraToolBox>()->mousePressEvent(getMouseX(), getMouseY())) {
1582− // stop propagation
1583− return;
1584− }
1585−
1586− if (_rearMirrorTools->mousePressEvent(getMouseX(), getMouseY())) {
1587− // stop propagation
1588− return;
1589− }
1590− }
1591−
15921578 // nobody handled this - make it an action event on the _window object
15931579 HFActionEvent actionEvent(HFActionEvent::startType(),
15941580 computePickRay(event->x(), event->y()));
@@ -1606,16 +1592,7 @@ void Application::mouseDoublePressEvent(QMouseEvent* event, unsigned int deviceI · 11 unmodified lines
16061592 return;
16071593 }
16081594
1609− if (activeWindow() == _window) {
1610− if (event->button() == Qt::LeftButton) {
1611− if (mouseOnScreen()) {
1612− if (DependencyManager::get<CameraToolBox>()->mouseDoublePressEvent(getMouseX(), getMouseY())) {
1613− // stop propagation
1614− return;
1615− }
1616− }
1617− }
1618− }
1595+ _controllerScriptingInterface.emitMouseDoublePressEvent(event);
16191596 }
16201597
16211598 void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) {
@@ -1637,13 +1614,6 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { · 15 unmodified lines
16371614 if (event->button() == Qt::LeftButton) {
16381615 _mousePressed = false;
16391616
1640− if (Menu::getInstance()->isOptionChecked(MenuOption::Stats) && mouseOnScreen()) {
1641− // let's set horizontal offset to give stats some margin to mirror
1642− int horizontalOffset = MIRROR_VIEW_WIDTH;
1643− Stats::getInstance()->checkClick(getMouseX(), getMouseY(),
1644− getMouseDragStartedX(), getMouseDragStartedY(), horizontalOffset);
1645− }
1646−
16471617 // fire an action end event
16481618 HFActionEvent actionEvent(HFActionEvent::endType(),
16491619 computePickRay(event->x(), event->y()));
@@ -1671,22 +1641,18 @@ void Application::touchUpdateEvent(QTouchEvent* event) { · 21 unmodified lines
16711641 bool validTouch = false;
16721642 if (activeWindow() == _window) {
16731643 const QList<QTouchEvent::TouchPoint>& tPoints = event->touchPoints();
1674− _touchAvgX = 0.0f;
1675− _touchAvgY = 0.0f;
1644+ _touchAvg = vec2();
16761645 int numTouches = tPoints.count();
16771646 if (numTouches > 1) {
16781647 for (int i = 0; i < numTouches; ++i) {
1679− _touchAvgX += tPoints[i].pos().x();
1680− _touchAvgY += tPoints[i].pos().y();
1648+ _touchAvg += toGlm(tPoints[i].pos());
16811649 }
1682− _touchAvgX /= (float)(numTouches);
1683− _touchAvgY /= (float)(numTouches);
1650+ _touchAvg /= (float)(numTouches);
16841651 validTouch = true;
16851652 }
16861653 }
16871654 if (!_isTouchPressed) {
1688− _touchDragStartedAvgX = _touchAvgX;
1689− _touchDragStartedAvgY = _touchAvgY;
1655+ _touchDragStartedAvg = _touchAvg;
16901656 }
16911657 _isTouchPressed = validTouch;
16921658 }
@@ -1722,8 +1688,7 @@ void Application::touchEndEvent(QTouchEvent* event) { · 29 unmodified lines
17221688 _keyboardMouseDevice.touchEndEvent(event);
17231689
17241690 // put any application specific touch behavior below here..
1725− _touchDragStartedAvgX = _touchAvgX;
1726− _touchDragStartedAvgY = _touchAvgY;
1691+ _touchDragStartedAvg = _touchAvg;
17271692 _isTouchPressed = false;
17281693
17291694 }
@@ -1872,9 +1837,9 @@ void Application::setFullscreen(bool fullscreen) { · 142 unmodified lines
18721837 Menu::getInstance()->getActionForOption(MenuOption::Fullscreen)->setChecked(fullscreen);
18731838 }
18741839
1875−// The following code block is useful on platforms that can have a visible
1876−// app menu in a fullscreen window. However the OSX mechanism hides the
1877−// application menu for fullscreen apps, so the check is not required.
1840+ // The following code block is useful on platforms that can have a visible
1841+ // app menu in a fullscreen window. However the OSX mechanism hides the
1842+ // application menu for fullscreen apps, so the check is not required.
18781843 #ifndef Q_OS_MAC
18791844 if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {
18801845 if (fullscreen) {
@@ -1939,16 +1904,15 @@ void Application::setEnableVRMode(bool enableVRMode) { · 58 unmodified lines
19391904 // attempt to reconnect the Oculus manager - it's possible this was a workaround
19401905 // for the sixense crash
19411906 OculusManager::disconnect();
1942− OculusManager::connect();
1907+ OculusManager::connect(_glWidget->context()->contextHandle());
1908+ _glWidget->setFocus();
1909+ _glWidget->makeCurrent();
1910+ glClear(GL_COLOR_BUFFER_BIT);
19431911 }
19441912 OculusManager::recalibrate();
19451913 } else {
19461914 OculusManager::abandonCalibration();
1947−
1948− _mirrorCamera.setHmdPosition(glm::vec3());
1949− _mirrorCamera.setHmdRotation(glm::quat());
1950− _myCamera.setHmdPosition(glm::vec3());
1951− _myCamera.setHmdRotation(glm::quat());
1915+ OculusManager::disconnect();
19521916 }
19531917
19541918 resizeGL();
@@ -1960,44 +1924,34 @@ void Application::setLowVelocityFilter(bool lowVelocityFilter) { · 5 unmodified lines
19601924
19611925 bool Application::mouseOnScreen() const {
19621926 if (OculusManager::isConnected()) {
1963− return getMouseX() >= 0 && getMouseX() <= _glWidget->getDeviceWidth() &&
1964− getMouseY() >= 0 && getMouseY() <= _glWidget->getDeviceHeight();
1927+ ivec2 mouse = getMouse();
1928+ if (!glm::all(glm::greaterThanEqual(mouse, ivec2()))) {
1929+ return false;
1930+ }
1931+ ivec2 size = toGlm(_glWidget->getDeviceSize());
1932+ if (!glm::all(glm::lessThanEqual(mouse, size))) {
1933+ return false;
1934+ }
19651935 }
19661936 return true;
19671937 }
19681938
1969−int Application::getMouseX() const {
1970− if (OculusManager::isConnected()) {
1971− glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseX(), getTrueMouseY()));
1972− return pos.x;
1973− }
1974− return getTrueMouseX();
1975−}
1976−
1977−int Application::getMouseY() const {
1939+ivec2 Application::getMouse() const {
19781940 if (OculusManager::isConnected()) {
1979− glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseX(), getTrueMouseY()));
1980− return pos.y;
1941+ return _compositor.screenToOverlay(getTrueMouse());
19811942 }
1982− return getTrueMouseY();
1943+ return getTrueMouse();
19831944 }
19841945
1985−int Application::getMouseDragStartedX() const {
1946+ivec2 Application::getMouseDragStarted() const {
19861947 if (OculusManager::isConnected()) {
1987− glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseDragStartedX(),
1988− getTrueMouseDragStartedY()));
1989− return pos.x;
1948+ return _compositor.screenToOverlay(getTrueMouseDragStarted());
19901949 }
1991− return getTrueMouseDragStartedX();
1950+ return getTrueMouseDragStarted();
19921951 }
19931952
1994−int Application::getMouseDragStartedY() const {
1995− if (OculusManager::isConnected()) {
1996− glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseDragStartedX(),
1997− getTrueMouseDragStartedY()));
1998− return pos.y;
1999− }
2000− return getTrueMouseDragStartedY();
1953+ivec2 Application::getTrueMouseDragStarted() const {
1954+ return _mouseDragStarted;
20011955 }
20021956
20031957 FaceTracker* Application::getActiveFaceTracker() {
@@ -2179,13 +2133,6 @@ void Application::init() { · 175 unmodified lines
21792133
21802134 _mirrorCamera.setMode(CAMERA_MODE_MIRROR);
21812135
2182− OculusManager::connect();
2183− if (OculusManager::isConnected()) {
2184− QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen),
2185− "trigger",
2186− Qt::QueuedConnection);
2187− }
2188−
21892136 TV3DManager::connect();
21902137 if (TV3DManager::isConnected()) {
21912138 QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen),
@@ -2249,13 +2196,6 @@ void Application::init() { · 57 unmodified lines
22492196 _entityClipboardRenderer.setViewFrustum(getViewFrustum());
22502197 _entityClipboardRenderer.setTree(&_entityClipboard);
22512198
2252− _rearMirrorTools = new RearMirrorTools(_mirrorViewRect);
2253−
2254− connect(_rearMirrorTools, SIGNAL(closeView()), SLOT(closeMirrorView()));
2255− connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView()));
2256− connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView()));
2257− connect(_rearMirrorTools, SIGNAL(resetView()), SLOT(resetSensors()));
2258−
22592199 // initialize the GlowEffect with our widget
22602200 bool glow = Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect);
22612201 DependencyManager::get<GlowEffect>()->init(glow);
@@ -2434,6 +2374,12 @@ void Application::cameraMenuChanged() { · 172 unmodified lines
24342374 }
24352375 }
24362376
2377+void Application::rotationModeChanged() {
2378+ if (!Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) {
2379+ _myAvatar->setHeadPitch(0);
2380+ }
2381+}
2382+
24372383 void Application::updateCamera(float deltaTime) {
24382384 PerformanceTimer perfTimer("updateCamera");
24392385 bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
@@ -3155,7 +3101,7 @@ PickRay Application::computePickRay(float x, float y) const { · 715 unmodified lines
31553101 y /= size.y;
31563102 PickRay result;
31573103 if (isHMDMode()) {
3158− getApplicationOverlay().computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction);
3104+ getApplicationCompositor().computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction);
31593105 } else {
31603106 if (QThread::currentThread() == activeRenderingThread) {
31613107 getDisplayViewFrustum()->computePickRay(x, y, result.origin, result.direction);
@@ -3184,13 +3130,11 @@ QImage Application::renderAvatarBillboard(RenderArgs* renderArgs) { · 22 unmodified lines
31843130 renderRearViewMirror(renderArgs, QRect(0, _glWidget->getDeviceHeight() - BILLBOARD_SIZE,
31853131 BILLBOARD_SIZE, BILLBOARD_SIZE),
31863132 true);
3187−
31883133 QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32);
31893134 glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
31903135 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
31913136
31923137 glBindFramebuffer(GL_FRAMEBUFFER, 0);
3193−
31943138 return image;
31953139 }
31963140
@@ -3386,9 +3330,8 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 189 unmodified lines
33863330
33873331 // flip x if in mirror mode (also requires reversing winding order for backface culling)
33883332 if (theCamera.getMode() == CAMERA_MODE_MIRROR) {
3389− glScalef(-1.0f, 1.0f, 1.0f);
3390− glFrontFace(GL_CW);
3391−
3333+ //glScalef(-1.0f, 1.0f, 1.0f);
3334+ //glFrontFace(GL_CW);
33923335 } else {
33933336 glFrontFace(GL_CCW);
33943337 }
@@ -3411,7 +3354,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 16 unmodified lines
34113354 viewTransform.setTranslation(theCamera.getPosition());
34123355 viewTransform.setRotation(rotation);
34133356 if (theCamera.getMode() == CAMERA_MODE_MIRROR) {
3414− viewTransform.setScale(Transform::Vec3(-1.0f, 1.0f, 1.0f));
3357+// viewTransform.setScale(Transform::Vec3(-1.0f, 1.0f, 1.0f));
34153358 }
34163359 if (renderArgs->_renderSide != RenderArgs::MONO) {
34173360 glm::mat4 invView = glm::inverse(_untranslatedViewMatrix);
@@ -3548,6 +3491,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 130 unmodified lines
35483491
35493492 renderContext._maxDrawnOpaqueItems = sceneInterface->getEngineMaxDrawnOpaqueItems();
35503493 renderContext._maxDrawnTransparentItems = sceneInterface->getEngineMaxDrawnTransparentItems();
3494+ renderContext._maxDrawnOverlay3DItems = sceneInterface->getEngineMaxDrawnOverlay3DItems();
35513495
35523496 renderArgs->_shouldRender = LODManager::shouldRender;
35533497
@@ -3564,7 +3508,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 10 unmodified lines
35643508
35653509 sceneInterface->setEngineFeedTransparentItems(engineRC->_numFeedTransparentItems);
35663510 sceneInterface->setEngineDrawnTransparentItems(engineRC->_numDrawnTransparentItems);
3567−
3511+
3512+ sceneInterface->setEngineFeedOverlay3DItems(engineRC->_numFeedOverlay3DItems);
3513+ sceneInterface->setEngineDrawnOverlay3DItems(engineRC->_numDrawnOverlay3DItems);
35683514 }
35693515 //Render the sixense lasers
35703516 if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) {
@@ -3672,8 +3618,8 @@ glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) { · 101 unmodified lines
36723618 // +-----------------------+
36733619 // -1,-1 1,-1
36743620
3675− glm::vec2 screenPoint((projectedPoint.x + 1.0) * horizontalScale,
3676− ((projectedPoint.y + 1.0) * -verticalScale) + _glWidget->getDeviceHeight());
3621+ glm::vec2 screenPoint((projectedPoint.x + 1.0f) * horizontalScale,
3622+ ((projectedPoint.y + 1.0f) * -verticalScale) + _glWidget->getDeviceHeight());
36773623
36783624 return screenPoint;
36793625 }
@@ -3691,7 +3637,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi · 11 unmodified lines
36913637 _mirrorCamera.setPosition(_myAvatar->getPosition() +
36923638 _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * BILLBOARD_DISTANCE * _myAvatar->getScale());
36933639
3694− } else if (RearMirrorTools::rearViewZoomLevel.get() == BODY) {
3640+ } else if (!AvatarInputs::getInstance()->mirrorZoomed()) {
36953641 _mirrorCamera.setPosition(_myAvatar->getChestPosition() +
36963642 _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_REARVIEW_BODY_DISTANCE * _myAvatar->getScale());
36973643
@@ -3726,7 +3672,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi · 28 unmodified lines
37263672 } else {
37273673 // if not rendering the billboard, the region is in device independent coordinates; must convert to device
37283674 QSize size = DependencyManager::get<TextureCache>()->getFrameBufferSize();
3729− float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale();
3675+ float ratio = (float)QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale();
37303676 int x = region.x() * ratio, y = region.y() * ratio, width = region.width() * ratio, height = region.height() * ratio;
37313677 glViewport(x, size.height() - y - height, width, height);
37323678 glScissor(x, size.height() - y - height, width, height);
@@ -3741,10 +3687,6 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi · 8 unmodified lines
37413687 displaySide(renderArgs, _mirrorCamera, true, billboard);
37423688 glPopMatrix();
37433689
3744− if (!billboard) {
3745− _rearMirrorTools->render(renderArgs, false, _glWidget->mapFromGlobal(QCursor::pos()));
3746− }
3747−
37483690 // reset Viewport and projection matrix
37493691 glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
37503692 glDisable(GL_SCISSOR_TEST);
@@ -3884,7 +3826,7 @@ void Application::nodeKilled(SharedNodePointer node) { · 133 unmodified lines
38843826 _entityServerJurisdictions.unlock();
38853827
38863828 qCDebug(interfaceapp, "model server going away...... v[%f, %f, %f, %f]",
3887− rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);
3829+ (double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s);
38883830
38893831 // Add the jurisditionDetails object to the list of "fade outs"
38903832 if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnOctreeServerChanges)) {
@@ -3970,7 +3912,8 @@ int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePoin · 79 unmodified lines
39703912 jurisdiction->unlock();
39713913
39723914 qCDebug(interfaceapp, "stats from new %s server... [%f, %f, %f, %f]",
3973− qPrintable(serverType), rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);
3915+ qPrintable(serverType),
3916+ (double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s);
39743917
39753918 // Add the jurisditionDetails object to the list of "fade outs"
39763919 if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnOctreeServerChanges)) {
@@ -4750,11 +4693,9 @@ void Application::postLambdaEvent(std::function<void()> f) { · 773 unmodified lines
47504693 }
47514694
47524695 void Application::initPlugins() {
4753− OculusManager::init();
47544696 }
47554697
47564698 void Application::shutdownPlugins() {
4757− OculusManager::deinit();
47584699 }
47594700
47604701 glm::vec3 Application::getHeadPosition() const {
@@ -4774,12 +4715,8 @@ QSize Application::getDeviceSize() const { · 13 unmodified lines
47744715 return _glWidget->getDeviceSize();
47754716 }
47764717
4777−int Application::getTrueMouseX() const {
4778− return _glWidget->mapFromGlobal(QCursor::pos()).x();
4779−}
4780−
4781−int Application::getTrueMouseY() const {
4782− return _glWidget->mapFromGlobal(QCursor::pos()).y();
4718+ivec2 Application::getTrueMouse() const {
4719+ return toGlm(_glWidget->mapFromGlobal(QCursor::pos()));
47834720 }
47844721
47854722 bool Application::isThrottleRendering() const {
@@ -4809,3 +4746,25 @@ qreal Application::getDevicePixelRatio() { · 23 unmodified lines
48094746 return _window ? _window->windowHandle()->devicePixelRatio() : 1.0;
48104747 }
48114748
4749+mat4 Application::getEyeProjection(int eye) const {
4750+ if (isHMDMode()) {
4751+ return OculusManager::getEyeProjection(eye);
4752+ }
4753+
4754+ return _viewFrustum.getProjection();
4755+}
4756+
4757+mat4 Application::getEyePose(int eye) const {
4758+ if (isHMDMode()) {
4759+ return OculusManager::getEyePose(eye);
4760+ }
4761+
4762+ return mat4();
4763+}
4764+
4765+mat4 Application::getHeadPose() const {
4766+ if (isHMDMode()) {
4767+ return OculusManager::getHeadPose();
4768+ }
4769+ return mat4();
4770+}
interface/src/Application.h+37−28
@@ -62,12 +62,12 @@ · 61 unmodified lines
6262 #include "ui/ModelsBrowser.h"
6363 #include "ui/NodeBounds.h"
6464 #include "ui/OctreeStatsDialog.h"
65−#include "ui/RearMirrorTools.h"
6665 #include "ui/SnapshotShareDialog.h"
6766 #include "ui/LodToolsDialog.h"
6867 #include "ui/LogDialog.h"
6968 #include "ui/overlays/Overlays.h"
7069 #include "ui/ApplicationOverlay.h"
70+#include "ui/ApplicationCompositor.h"
7171 #include "ui/RunningScriptsWidget.h"
7272 #include "ui/ToolWindow.h"
7373 #include "ui/UserInputMapper.h"
@@ -221,15 +221,21 @@ public: · 147 unmodified lines
221221 const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; }
222222 const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; }
223223 bool mouseOnScreen() const;
224− int getMouseX() const;
225− int getMouseY() const;
226− glm::ivec2 getTrueMousePosition() const;
227− int getTrueMouseX() const;
228− int getTrueMouseY() const;
229− int getMouseDragStartedX() const;
230− int getMouseDragStartedY() const;
231− int getTrueMouseDragStartedX() const { return _mouseDragStartedX; }
232− int getTrueMouseDragStartedY() const { return _mouseDragStartedY; }
224+
225+ ivec2 getMouse() const;
226+ ivec2 getTrueMouse() const;
227+ ivec2 getMouseDragStarted() const;
228+ ivec2 getTrueMouseDragStarted() const;
229+
230+ // TODO get rid of these and use glm types directly
231+ int getMouseX() const { return getMouse().x; }
232+ int getMouseY() const { return getMouse().y; }
233+ int getTrueMouseX() const { return getTrueMouse().x; }
234+ int getTrueMouseY() const { return getTrueMouse().y; }
235+ int getMouseDragStartedX() const { return getMouseDragStarted().x; }
236+ int getMouseDragStartedY() const { return getMouseDragStarted().y; }
237+ int getTrueMouseDragStartedX() const { return getTrueMouseDragStarted().x; }
238+ int getTrueMouseDragStartedY() const { return getTrueMouseDragStarted().y; }
233239 bool getLastMouseMoveWasSimulated() const { return _lastMouseMoveWasSimulated; }
234240
235241 FaceTracker* getActiveFaceTracker();
@@ -238,6 +244,8 @@ public: · 2 unmodified lines
238244 QSystemTrayIcon* getTrayIcon() { return _trayIcon; }
239245 ApplicationOverlay& getApplicationOverlay() { return _applicationOverlay; }
240246 const ApplicationOverlay& getApplicationOverlay() const { return _applicationOverlay; }
247+ ApplicationCompositor& getApplicationCompositor() { return _compositor; }
248+ const ApplicationCompositor& getApplicationCompositor() const { return _compositor; }
241249 Overlays& getOverlays() { return _overlays; }
242250
243251 float getFps() const { return _fps; }
@@ -330,6 +338,9 @@ public: · 86 unmodified lines
330338 bool isHMDMode() const;
331339 glm::quat getHeadOrientation() const;
332340 glm::vec3 getHeadPosition() const;
341+ glm::mat4 getHeadPose() const;
342+ glm::mat4 getEyePose(int eye) const;
343+ glm::mat4 getEyeProjection(int eye) const;
333344
334345 QRect getDesirableApplicationGeometry();
335346 RunningScriptsWidget* getRunningScriptsWidget() { return _runningScriptsWidget; }
@@ -451,6 +462,8 @@ private slots: · 115 unmodified lines
451462 void setFullscreen(bool fullscreen);
452463 void setEnable3DTVMode(bool enable3DTVMode);
453464 void setEnableVRMode(bool enableVRMode);
465+
466+ void rotationModeChanged();
454467
455468 glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint);
456469
@@ -548,21 +561,17 @@ private: · 91 unmodified lines
548561
549562 OctreeQuery _octreeQuery; // NodeData derived class for querying octee cells from octree servers
550563
551− KeyboardMouseDevice _keyboardMouseDevice; // Default input device, the good old keyboard mouse and maybe touchpad
552−
553− UserInputMapper _userInputMapper; // User input mapper allowing to mapp different real devices to the action channels that the application has to offer
554−
555− MyAvatar* _myAvatar; // TODO: move this and relevant code to AvatarManager (or MyAvatar as the case may be)
556−
557− Camera _myCamera; // My view onto the world
564+ KeyboardMouseDevice _keyboardMouseDevice; // Default input device, the good old keyboard mouse and maybe touchpad
565+ UserInputMapper _userInputMapper; // User input mapper allowing to mapp different real devices to the action channels that the application has to offer
566+ MyAvatar* _myAvatar; // TODO: move this and relevant code to AvatarManager (or MyAvatar as the case may be)
567+ Camera _myCamera; // My view onto the world
558568 Camera _mirrorCamera; // Cammera for mirror view
559569 QRect _mirrorViewRect;
560− RearMirrorTools* _rearMirrorTools;
561570
562− Setting::Handle<bool> _firstRun;
563− Setting::Handle<QString> _previousScriptLocation;
564− Setting::Handle<QString> _scriptsLocationHandle;
565− Setting::Handle<float> _fieldOfView;
571+ Setting::Handle<bool> _firstRun;
572+ Setting::Handle<QString> _previousScriptLocation;
573+ Setting::Handle<QString> _scriptsLocationHandle;
574+ Setting::Handle<float> _fieldOfView;
566575
567576 Transform _viewTransform;
568577 glm::mat4 _untranslatedViewMatrix;
@@ -580,18 +589,17 @@ private: · 11 unmodified lines
580589 Environment _environment;
581590
582591 bool _cursorVisible;
583− int _mouseDragStartedX;
584− int _mouseDragStartedY;
592+ ivec2 _mouseDragStarted;
593+
585594 quint64 _lastMouseMove;
586595 bool _lastMouseMoveWasSimulated;
587596
588597 glm::vec3 _mouseRayOrigin;
589598 glm::vec3 _mouseRayDirection;
590599
591− float _touchAvgX;
592− float _touchAvgY;
593− float _touchDragStartedAvgX;
594− float _touchDragStartedAvgY;
600+ vec2 _touchAvg;
601+ vec2 _touchDragStartedAvg;
602+
595603 bool _isTouchPressed; // true if multitouch has been pressed (clear when finished)
596604
597605 bool _mousePressed; // true if mouse has been pressed (clear when finished)
@@ -669,6 +677,7 @@ private: · 71 unmodified lines
669677
670678 Overlays _overlays;
671679 ApplicationOverlay _applicationOverlay;
680+ ApplicationCompositor _compositor;
672681 };
673682
674683 #endif // hifi_Application_h
interface/src/Camera.cpp+0−16
@@ -49,8 +49,6 @@ Camera::Camera() : · 48 unmodified lines
4949 _mode(CAMERA_MODE_THIRD_PERSON),
5050 _position(0.0f, 0.0f, 0.0f),
5151 _projection(glm::perspective(glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES), 16.0f/9.0f, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP)),
52− _hmdPosition(),
53− _hmdRotation(),
5452 _isKeepLookingAt(false),
5553 _lookingAt(0.0f, 0.0f, 0.0f)
5654 {
@@ -74,20 +72,6 @@ void Camera::setRotation(const glm::quat& rotation) { · 17 unmodified lines
7472 }
7573 }
7674
77−void Camera::setHmdPosition(const glm::vec3& hmdPosition) {
78− _hmdPosition = hmdPosition;
79− if (_isKeepLookingAt) {
80− lookAt(_lookingAt);
81− }
82−}
83−
84−void Camera::setHmdRotation(const glm::quat& hmdRotation) {
85− _hmdRotation = hmdRotation;
86− if (_isKeepLookingAt) {
87− lookAt(_lookingAt);
88− }
89−}
90−
9175 void Camera::setMode(CameraMode mode) {
9276 _mode = mode;
9377 emit modeUpdated(modeToString(mode));
interface/src/Camera.h+4−10
@@ -45,26 +45,22 @@ public: · 44 unmodified lines
4545
4646 void setRotation(const glm::quat& rotation);
4747 void setProjection(const glm::mat4 & projection);
48− void setHmdPosition(const glm::vec3& hmdPosition);
49− void setHmdRotation(const glm::quat& hmdRotation);
5048 void setMode(CameraMode m);
5149
52− glm::quat getRotation() const { return _rotation * _hmdRotation; }
50+ glm::quat getRotation() const { return _rotation; }
5351 const glm::mat4& getProjection() const { return _projection; }
54− const glm::vec3& getHmdPosition() const { return _hmdPosition; }
55− const glm::quat& getHmdRotation() const { return _hmdRotation; }
5652 CameraMode getMode() const { return _mode; }
5753
5854 public slots:
5955 QString getModeString() const;
6056 void setModeString(const QString& mode);
6157
62− glm::vec3 getPosition() const { return _position + _hmdPosition; }
58+ glm::vec3 getPosition() const { return _position; }
6359 void setPosition(const glm::vec3& position);
6460
65− void setOrientation(const glm::quat& orientation) { setRotation(orientation); }
6661 glm::quat getOrientation() const { return getRotation(); }
67−
62+ void setOrientation(const glm::quat& orientation) { setRotation(orientation); }
63+
6864 PickRay computePickRay(float x, float y);
6965
7066 // These only work on independent cameras
@@ -86,8 +82,6 @@ private: · 15 unmodified lines
8682 glm::vec3 _position;
8783 glm::quat _rotation;
8884 glm::mat4 _projection;
89− glm::vec3 _hmdPosition;
90− glm::quat _hmdRotation;
9185 bool _isKeepLookingAt;
9286 glm::vec3 _lookingAt;
9387 };
interface/src/GLCanvas.cpp+2−2
@@ -39,11 +39,11 @@ bool GLCanvas::isThrottleRendering() const { · 38 unmodified lines
3939 }
4040
4141 int GLCanvas::getDeviceWidth() const {
42− return width() * (windowHandle() ? windowHandle()->devicePixelRatio() : 1.0f);
42+ return width() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f);
4343 }
4444
4545 int GLCanvas::getDeviceHeight() const {
46− return height() * (windowHandle() ? windowHandle()->devicePixelRatio() : 1.0f);
46+ return height() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f);
4747 }
4848
4949 void GLCanvas::initializeGL() {
interface/src/InterfaceActionFactory.cpp+3−3
@@ -12,7 +12,7 @@ · 11 unmodified lines
1212
1313
1414 #include <avatar/AvatarActionHold.h>
15−#include <ObjectActionPullToPoint.h>
15+#include <ObjectActionOffset.h>
1616 #include <ObjectActionSpring.h>
1717
1818 #include "InterfaceActionFactory.h"
@@ -27,8 +27,8 @@ EntityActionPointer InterfaceActionFactory::factory(EntitySimulation* simulation · 8 unmodified lines
2727 switch (type) {
2828 case ACTION_TYPE_NONE:
2929 return nullptr;
30− case ACTION_TYPE_PULL_TO_POINT:
31− action = (EntityActionPointer) new ObjectActionPullToPoint(id, ownerEntity);
30+ case ACTION_TYPE_OFFSET:
31+ action = (EntityActionPointer) new ObjectActionOffset(id, ownerEntity);
3232 break;
3333 case ACTION_TYPE_SPRING:
3434 action = (EntityActionPointer) new ObjectActionSpring(id, ownerEntity);
interface/src/LODManager.cpp+3−3
@@ -205,11 +205,11 @@ QString LODManager::getLODFeedbackText() { · 204 unmodified lines
205205 int relativeToTwentyTwenty = 20 / relativeToDefault;
206206
207207 QString result;
208− if (relativeToDefault > 1.01) {
208+ if (relativeToDefault > 1.01f) {
209209 result = QString("20:%1 or %2 times further than average vision%3").arg(relativeToTwentyTwenty).arg(relativeToDefault,0,'f',2).arg(granularityFeedback);
210− } else if (relativeToDefault > 0.99) {
210+ } else if (relativeToDefault > 0.99f) {
211211 result = QString("20:20 or the default distance for average vision%1").arg(granularityFeedback);
212− } else if (relativeToDefault > 0.01) {
212+ } else if (relativeToDefault > 0.01f) {
213213 result = QString("20:%1 or %2 of default distance for average vision%3").arg(relativeToTwentyTwenty).arg(relativeToDefault,0,'f',3).arg(granularityFeedback);
214214 } else {
215215 result = QString("%2 of default distance for average vision%3").arg(relativeToDefault,0,'f',3).arg(granularityFeedback);
interface/src/Menu.cpp+6−0
@@ -287,6 +287,12 @@ Menu::Menu() { · 286 unmodified lines
287287 addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror,
288288 0, //QML Qt::SHIFT | Qt::Key_H,
289289 true);
290+ addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror,
291+ 0, // QML Qt::Key_H,
292+ false, qApp, SLOT(cameraMenuChanged()));
293+
294+ addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::CenterPlayerInView,
295+ 0, false, qApp, SLOT(rotationModeChanged()));
290296
291297 addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools,
292298 #ifdef Q_OS_MAC
interface/src/Menu.h+1−0
@@ -201,6 +201,7 @@ namespace MenuOption { · 200 unmodified lines
201201 const QString FrameTimer = "Show Timer";
202202 const QString Fullscreen = "Fullscreen";
203203 const QString FullscreenMirror = "Fullscreen Mirror";
204+ const QString CenterPlayerInView = "Center Player In View";
204205 const QString GlowWhenSpeaking = "Glow When Speaking";
205206 const QString NamesAboveHeads = "Names Above Heads";
206207 const QString HMDTools = "HMD Tools";
interface/src/ModelPropertiesDialog.cpp+26−26
@@ -33,19 +33,19 @@ _basePath(basePath), · 32 unmodified lines
3333 _geometry(geometry)
3434 {
3535 setWindowTitle("Set Model Properties");
36−
36+
3737 QFormLayout* form = new QFormLayout();
3838 setLayout(form);
39−
39+
4040 form->addRow("Name:", _name = new QLineEdit());
41−
41+
4242 form->addRow("Texture Directory:", _textureDirectory = new QPushButton());
4343 connect(_textureDirectory, SIGNAL(clicked(bool)), SLOT(chooseTextureDirectory()));
44−
44+
4545 form->addRow("Scale:", _scale = new QDoubleSpinBox());
4646 _scale->setMaximum(FLT_MAX);
4747 _scale->setSingleStep(0.01);
48−
48+
4949 if (_modelType != FSTReader::ENTITY_MODEL) {
5050 if (_modelType == FSTReader::ATTACHMENT_MODEL) {
5151 QHBoxLayout* translation = new QHBoxLayout();
@@ -57,7 +57,7 @@ _geometry(geometry) · 5 unmodified lines
5757 form->addRow("Pivot Joint:", _pivotJoint = createJointBox());
5858 connect(_pivotAboutCenter, SIGNAL(toggled(bool)), SLOT(updatePivotJoint()));
5959 _pivotAboutCenter->setChecked(true);
60−
60+
6161 } else {
6262 form->addRow("Left Eye Joint:", _leftEyeJoint = createJointBox());
6363 form->addRow("Right Eye Joint:", _rightEyeJoint = createJointBox());
@@ -69,22 +69,22 @@ _geometry(geometry) · 5 unmodified lines
6969 form->addRow("Head Joint:", _headJoint = createJointBox());
7070 form->addRow("Left Hand Joint:", _leftHandJoint = createJointBox());
7171 form->addRow("Right Hand Joint:", _rightHandJoint = createJointBox());
72−
72+
7373 form->addRow("Free Joints:", _freeJoints = new QVBoxLayout());
7474 QPushButton* newFreeJoint = new QPushButton("New Free Joint");
7575 _freeJoints->addWidget(newFreeJoint);
7676 connect(newFreeJoint, SIGNAL(clicked(bool)), SLOT(createNewFreeJoint()));
7777 }
7878 }
79−
79+
8080 QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok |
8181 QDialogButtonBox::Cancel | QDialogButtonBox::Reset);
8282 connect(buttons, SIGNAL(accepted()), SLOT(accept()));
8383 connect(buttons, SIGNAL(rejected()), SLOT(reject()));
8484 connect(buttons->button(QDialogButtonBox::Reset), SIGNAL(clicked(bool)), SLOT(reset()));
85−
85+
8686 form->addRow(buttons);
87−
87+
8888 // reset to initialize the fields
8989 reset();
9090 }
@@ -100,42 +100,42 @@ QVariantHash ModelPropertiesDialog::getMapping() const { · 9 unmodified lines
100100 mapping.insert(NAME_FIELD, _name->text());
101101 mapping.insert(TEXDIR_FIELD, _textureDirectory->text());
102102 mapping.insert(SCALE_FIELD, QString::number(_scale->value()));
103−
103+
104104 // update the joint indices
105105 QVariantHash jointIndices;
106106 for (int i = 0; i < _geometry.joints.size(); i++) {
107107 jointIndices.insert(_geometry.joints.at(i).name, QString::number(i));
108108 }
109109 mapping.insert(JOINT_INDEX_FIELD, jointIndices);
110−
110+
111111 if (_modelType != FSTReader::ENTITY_MODEL) {
112112 QVariantHash joints = mapping.value(JOINT_FIELD).toHash();
113113 if (_modelType == FSTReader::ATTACHMENT_MODEL) {
114114 glm::vec3 pivot;
115115 if (_pivotAboutCenter->isChecked()) {
116116 pivot = (_geometry.meshExtents.minimum + _geometry.meshExtents.maximum) * 0.5f;
117−
117+
118118 } else if (_pivotJoint->currentIndex() != 0) {
119119 pivot = extractTranslation(_geometry.joints.at(_pivotJoint->currentIndex() - 1).transform);
120120 }
121− mapping.insert(TRANSLATION_X_FIELD, -pivot.x * _scale->value() + _translationX->value());
122− mapping.insert(TRANSLATION_Y_FIELD, -pivot.y * _scale->value() + _translationY->value());
123− mapping.insert(TRANSLATION_Z_FIELD, -pivot.z * _scale->value() + _translationZ->value());
124−
121+ mapping.insert(TRANSLATION_X_FIELD, -pivot.x * (float)_scale->value() + (float)_translationX->value());
122+ mapping.insert(TRANSLATION_Y_FIELD, -pivot.y * (float)_scale->value() + (float)_translationY->value());
123+ mapping.insert(TRANSLATION_Z_FIELD, -pivot.z * (float)_scale->value() + (float)_translationZ->value());
124+
125125 } else {
126126 insertJointMapping(joints, "jointEyeLeft", _leftEyeJoint->currentText());
127127 insertJointMapping(joints, "jointEyeRight", _rightEyeJoint->currentText());
128128 insertJointMapping(joints, "jointNeck", _neckJoint->currentText());
129129 }
130−
131−
130+
131+
132132 if (_modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL) {
133133 insertJointMapping(joints, "jointRoot", _rootJoint->currentText());
134134 insertJointMapping(joints, "jointLean", _leanJoint->currentText());
135135 insertJointMapping(joints, "jointHead", _headJoint->currentText());
136136 insertJointMapping(joints, "jointLeftHand", _leftHandJoint->currentText());
137137 insertJointMapping(joints, "jointRightHand", _rightHandJoint->currentText());
138−
138+
139139 mapping.remove(FREE_JOINT_FIELD);
140140 for (int i = 0; i < _freeJoints->count() - 1; i++) {
141141 QComboBox* box = static_cast<QComboBox*>(_freeJoints->itemAt(i)->widget()->layout()->itemAt(0)->widget());
@@ -144,7 +144,7 @@ QVariantHash ModelPropertiesDialog::getMapping() const { · 2 unmodified lines
144144 }
145145 mapping.insert(JOINT_FIELD, joints);
146146 }
147−
147+
148148 return mapping;
149149 }
150150
@@ -156,9 +156,9 @@ void ModelPropertiesDialog::reset() { · 5 unmodified lines
156156 _name->setText(_originalMapping.value(NAME_FIELD).toString());
157157 _textureDirectory->setText(_originalMapping.value(TEXDIR_FIELD).toString());
158158 _scale->setValue(_originalMapping.value(SCALE_FIELD).toDouble());
159−
159+
160160 QVariantHash jointHash = _originalMapping.value(JOINT_FIELD).toHash();
161−
161+
162162 if (_modelType != FSTReader::ENTITY_MODEL) {
163163 if (_modelType == FSTReader::ATTACHMENT_MODEL) {
164164 _translationX->setValue(_originalMapping.value(TRANSLATION_X_FIELD).toDouble());
@@ -166,20 +166,20 @@ void ModelPropertiesDialog::reset() { · 1 unmodified line
166166 _translationZ->setValue(_originalMapping.value(TRANSLATION_Z_FIELD).toDouble());
167167 _pivotAboutCenter->setChecked(true);
168168 _pivotJoint->setCurrentIndex(0);
169−
169+
170170 } else {
171171 setJointText(_leftEyeJoint, jointHash.value("jointEyeLeft").toString());
172172 setJointText(_rightEyeJoint, jointHash.value("jointEyeRight").toString());
173173 setJointText(_neckJoint, jointHash.value("jointNeck").toString());
174174 }
175−
175+
176176 if (_modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL) {
177177 setJointText(_rootJoint, jointHash.value("jointRoot").toString());
178178 setJointText(_leanJoint, jointHash.value("jointLean").toString());
179179 setJointText(_headJoint, jointHash.value("jointHead").toString());
180180 setJointText(_leftHandJoint, jointHash.value("jointLeftHand").toString());
181181 setJointText(_rightHandJoint, jointHash.value("jointRightHand").toString());
182−
182+
183183 while (_freeJoints->count() > 1) {
184184 delete _freeJoints->itemAt(0)->widget();
185185 }
interface/src/Stars.cpp+8−10
@@ -16,13 +16,13 @@ · 15 unmodified lines
1616 #include "InterfaceConfig.h"
1717 #include "starfield/Controller.h"
1818
19−Stars::Stars() :
19+Stars::Stars() :
2020 _controller(0l), _starsLoaded(false) {
2121 _controller = new starfield::Controller;
2222 }
2323
24−Stars::~Stars() {
25− delete _controller;
24+Stars::~Stars() {
25+ delete _controller;
2626 }
2727
2828 bool Stars::generate(unsigned numStars, unsigned seed) {
@@ -30,22 +30,20 @@ bool Stars::generate(unsigned numStars, unsigned seed) { · 1 unmodified line
3030 return _starsLoaded;
3131 }
3232
33−bool Stars::setResolution(unsigned k) {
34− return _controller->setResolution(k);
33+bool Stars::setResolution(unsigned k) {
34+ return _controller->setResolution(k);
3535 }
3636
3737 void Stars::render(float fovY, float aspect, float nearZ, float alpha) {
3838 // determine length of screen diagonal from quadrant height and aspect ratio
39− float quadrantHeight = nearZ * tan(RADIANS_PER_DEGREE * fovY * 0.5f);
39+ float quadrantHeight = nearZ * tanf(RADIANS_PER_DEGREE * fovY * 0.5f);
4040 float halfDiagonal = sqrt(quadrantHeight * quadrantHeight * (1.0f + aspect * aspect));
4141
4242 // determine fov angle in respect to the diagonal
43− float fovDiagonal = atan(halfDiagonal / nearZ) * 2.0f;
43+ float fovDiagonal = atanf(halfDiagonal / nearZ) * 2.0f;
4444
4545 // pull the modelview matrix off the GL stack
46− glm::mat4 view; glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view));
46+ glm::mat4 view; glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view));
4747
4848 _controller->render(fovDiagonal, aspect, glm::affineInverse(view), alpha);
4949 }
50−
51−
interface/src/UIUtil.cpp+1−1
@@ -70,6 +70,6 @@ void UIUtil::internalScaleWidgetFontSizes(QWidget* widget, float scale) { · 69 unmodified lines
7070 }
7171
7272 QFont font = widget->font();
73− font.setPointSizeF(font.pointSizeF() * scale);
73+ font.setPointSizeF(font.pointSizeF() * (double)scale);
7474 widget->setFont(font);
7575 }
interface/src/Util.cpp+25−22
@@ -41,7 +41,7 @@ void renderWorldBox(gpu::Batch& batch) { · 40 unmodified lines
4141 static const glm::vec3 green(0.0f, 1.0f, 0.0f);
4242 static const glm::vec3 blue(0.0f, 0.0f, 1.0f);
4343 static const glm::vec3 grey(0.5f, 0.5f, 0.5f);
44−
44+
4545 auto transform = Transform{};
4646 batch.setModelTransform(transform);
4747 geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(TREE_SCALE, 0.0f, 0.0f), red);
@@ -49,13 +49,13 @@ void renderWorldBox(gpu::Batch& batch) { · 1 unmodified line
4949 geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, TREE_SCALE), blue);
5050 geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, TREE_SCALE), glm::vec3(TREE_SCALE, 0.0f, TREE_SCALE), grey);
5151 geometryCache->renderLine(batch, glm::vec3(TREE_SCALE, 0.0f, TREE_SCALE), glm::vec3(TREE_SCALE, 0.0f, 0.0f), grey);
52−
52+
5353 // Draw meter markers along the 3 axis to help with measuring things
5454 const float MARKER_DISTANCE = 1.0f;
5555 const float MARKER_RADIUS = 0.05f;
56−
56+
5757 geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, red);
58−
58+
5959 transform.setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, 0.0f));
6060 batch.setModelTransform(transform);
6161 geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, red);
@@ -79,10 +79,10 @@ const glm::vec3 randVector() { · 17 unmodified lines
7979 }
8080
8181 static TextRenderer* textRenderer(int mono) {
82− static TextRenderer* monoRenderer = TextRenderer::getInstance(MONO_FONT_FAMILY);
82+ static TextRenderer* monoRenderer = TextRenderer::getInstance(MONO_FONT_FAMILY);
8383 static TextRenderer* proportionalRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY,
8484 -1, -1, false, TextRenderer::SHADOW_EFFECT);
85− static TextRenderer* inconsolataRenderer = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, -1, INCONSOLATA_FONT_WEIGHT,
85+ static TextRenderer* inconsolataRenderer = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, -1, INCONSOLATA_FONT_WEIGHT,
8686 false);
8787 switch (mono) {
8888 case 1:
@@ -133,46 +133,46 @@ void runTimingTests() { · 44 unmodified lines
133133 QElapsedTimer startTime;
134134 startTime.start();
135135 float elapsedUsecs;
136−
136+
137137 float NSEC_TO_USEC = 1.0f / 1000.0f;
138138 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
139− qCDebug(interfaceapp, "QElapsedTimer::nsecElapsed() usecs: %f", elapsedUsecs);
140−
139+ qCDebug(interfaceapp, "QElapsedTimer::nsecElapsed() usecs: %f", (double)elapsedUsecs);
140+
141141 // Test sleep functions for accuracy
142142 startTime.start();
143143 QThread::msleep(1);
144144 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
145− qCDebug(interfaceapp, "QThread::msleep(1) ms: %f", elapsedUsecs / 1000.0f);
145+ qCDebug(interfaceapp, "QThread::msleep(1) ms: %f", (double)(elapsedUsecs / 1000.0f));
146146
147147 startTime.start();
148148 QThread::sleep(1);
149149 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
150− qCDebug(interfaceapp, "QThread::sleep(1) ms: %f", elapsedUsecs / 1000.0f);
150+ qCDebug(interfaceapp, "QThread::sleep(1) ms: %f", (double)(elapsedUsecs / 1000.0f));
151151
152152 startTime.start();
153153 usleep(1);
154154 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
155− qCDebug(interfaceapp, "usleep(1) ms: %f", elapsedUsecs / 1000.0f);
155+ qCDebug(interfaceapp, "usleep(1) ms: %f", (double)(elapsedUsecs / 1000.0f));
156156
157157 startTime.start();
158158 usleep(10);
159159 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
160− qCDebug(interfaceapp, "usleep(10) ms: %f", elapsedUsecs / 1000.0f);
160+ qCDebug(interfaceapp, "usleep(10) ms: %f", (double)(elapsedUsecs / 1000.0f));
161161
162162 startTime.start();
163163 usleep(100);
164164 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
165− qCDebug(interfaceapp, "usleep(100) ms: %f", elapsedUsecs / 1000.0f);
165+ qCDebug(interfaceapp, "usleep(100) ms: %f", (double)(elapsedUsecs / 1000.0f));
166166
167167 startTime.start();
168168 usleep(1000);
169169 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
170− qCDebug(interfaceapp, "usleep(1000) ms: %f", elapsedUsecs / 1000.0f);
170+ qCDebug(interfaceapp, "usleep(1000) ms: %f", (double)(elapsedUsecs / 1000.0f));
171171
172172 startTime.start();
173173 usleep(15000);
174174 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
175− qCDebug(interfaceapp, "usleep(15000) ms: %f", elapsedUsecs / 1000.0f);
175+ qCDebug(interfaceapp, "usleep(15000) ms: %f", (double)(elapsedUsecs / 1000.0f));
176176
177177 // Random number generation
178178 startTime.start();
@@ -180,7 +180,8 @@ void runTimingTests() { · 1 unmodified line
180180 iResults[i] = rand();
181181 }
182182 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
183− qCDebug(interfaceapp, "rand() stored in array usecs: %f, first result:%d", elapsedUsecs / (float) numTests, iResults[0]);
183+ qCDebug(interfaceapp, "rand() stored in array usecs: %f, first result:%d",
184+ (double)(elapsedUsecs / numTests), iResults[0]);
184185
185186 // Random number generation using randFloat()
186187 startTime.start();
@@ -188,7 +189,8 @@ void runTimingTests() { · 1 unmodified line
188189 fResults[i] = randFloat();
189190 }
190191 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
191− qCDebug(interfaceapp, "randFloat() stored in array usecs: %f, first result: %f", elapsedUsecs / (float) numTests, fResults[0]);
192+ qCDebug(interfaceapp, "randFloat() stored in array usecs: %f, first result: %f",
193+ (double)(elapsedUsecs / numTests), (double)(fResults[0]));
192194
193195 free(iResults);
194196 free(fResults);
@@ -200,7 +202,7 @@ void runTimingTests() { · 5 unmodified lines
200202 fTest = powf(fTest, 0.5f);
201203 }
202204 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
203− qCDebug(interfaceapp, "powf(f, 0.5) usecs: %f", elapsedUsecs / (float) numTests);
205+ qCDebug(interfaceapp, "powf(f, 0.5) usecs: %f", (double)(elapsedUsecs / (float) numTests));
204206
205207 // Vector Math
206208 float distance;
@@ -213,19 +215,20 @@ void runTimingTests() { · 6 unmodified lines
213215 }
214216 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
215217 qCDebug(interfaceapp, "vector math usecs: %f [%f usecs total for %d tests], last result:%f",
216− elapsedUsecs / (float) numTests, elapsedUsecs, numTests, distance);
218+ (double)(elapsedUsecs / (float) numTests), (double)elapsedUsecs, numTests, (double)distance);
217219
218220 // Vec3 test
219221 glm::vec3 vecA(randVector()), vecB(randVector());
220222 float result;
221−
223+
222224 startTime.start();
223225 for (int i = 0; i < numTests; i++) {
224226 glm::vec3 temp = vecA-vecB;
225227 result = glm::dot(temp,temp);
226228 }
227229 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
228− qCDebug(interfaceapp, "vec3 assign and dot() usecs: %f, last result:%f", elapsedUsecs / (float) numTests, result);
230+ qCDebug(interfaceapp, "vec3 assign and dot() usecs: %f, last result:%f",
231+ (double)(elapsedUsecs / numTests), (double)result);
229232 }
230233
231234 bool rayIntersectsSphere(const glm::vec3& rayStarting, const glm::vec3& rayNormalizedDirection,
interface/src/audio/AudioIOStatsRenderer.cpp+69−55
@@ -41,32 +41,32 @@ void AudioIOStatsRenderer::render(const float* color, int width, int height) { · 40 unmodified lines
4141 if (!_isEnabled) {
4242 return;
4343 }
44−
44+
4545 const int linesWhenCentered = _shouldShowInjectedStreams ? 34 : 27;
4646 const int CENTERED_BACKGROUND_HEIGHT = STATS_HEIGHT_PER_LINE * linesWhenCentered;
47−
47+
4848 int lines = _shouldShowInjectedStreams ? _stats->getMixerInjectedStreamStatsMap().size() * 7 + 27 : 27;
4949 int statsHeight = STATS_HEIGHT_PER_LINE * lines;
50−
51−
50+
51+
5252 static const glm::vec4 backgroundColor = { 0.2f, 0.2f, 0.2f, 0.6f };
5353 int x = std::max((width - (int)STATS_WIDTH) / 2, 0);
5454 int y = std::max((height - CENTERED_BACKGROUND_HEIGHT) / 2, 0);
5555 int w = STATS_WIDTH;
5656 int h = statsHeight;
5757 DependencyManager::get<GeometryCache>()->renderQuad(x, y, w, h, backgroundColor);
58−
58+
5959 int horizontalOffset = x + 5;
6060 int verticalOffset = y;
61−
61+
6262 float scale = 0.10f;
6363 float rotation = 0.0f;
6464 int font = 2;
65−
65+
6666 char latencyStatString[512];
67−
67+
6868 float audioInputBufferLatency = 0.0f, inputRingBufferLatency = 0.0f, networkRoundtripLatency = 0.0f, mixerRingBufferLatency = 0.0f, outputRingBufferLatency = 0.0f, audioOutputBufferLatency = 0.0f;
69−
69+
7070 AudioStreamStats downstreamAudioStreamStats = _stats->getMixerDownstreamStats();
7171 SharedNodePointer audioMixerNodePointer = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::AudioMixer);
7272 if (!audioMixerNodePointer.isNull()) {
@@ -78,48 +78,62 @@ void AudioIOStatsRenderer::render(const float* color, int width, int height) { · 5 unmodified lines
7878 audioOutputBufferLatency = _stats->getAudioOutputMsecsUnplayedStats().getWindowAverage();
7979 }
8080 float totalLatency = audioInputBufferLatency + inputRingBufferLatency + networkRoundtripLatency + mixerRingBufferLatency + outputRingBufferLatency + audioOutputBufferLatency;
81−
82− sprintf(latencyStatString, " Audio input buffer: %7.2fms - avg msecs of samples read to the input ring buffer in last 10s", audioInputBufferLatency);
81+
82+ sprintf(latencyStatString,
83+ " Audio input buffer: %7.2fms - avg msecs of samples read to the input ring buffer in last 10s",
84+ (double)audioInputBufferLatency);
8385 verticalOffset += STATS_HEIGHT_PER_LINE;
8486 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
85−
86− sprintf(latencyStatString, " Input ring buffer: %7.2fms - avg msecs of samples in input ring buffer in last 10s", inputRingBufferLatency);
87+
88+ sprintf(latencyStatString,
89+ " Input ring buffer: %7.2fms - avg msecs of samples in input ring buffer in last 10s",
90+ (double)inputRingBufferLatency);
8791 verticalOffset += STATS_HEIGHT_PER_LINE;
8892 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
89−
90− sprintf(latencyStatString, " Network to mixer: %7.2fms - half of last ping value calculated by the node list", networkRoundtripLatency / 2.0f);
93+
94+ sprintf(latencyStatString,
95+ " Network to mixer: %7.2fms - half of last ping value calculated by the node list",
96+ (double)(networkRoundtripLatency / 2.0f));
9197 verticalOffset += STATS_HEIGHT_PER_LINE;
9298 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
93−
94− sprintf(latencyStatString, " AudioMixer ring buffer: %7.2fms - avg msecs of samples in audio mixer's ring buffer in last 10s", mixerRingBufferLatency);
99+
100+ sprintf(latencyStatString,
101+ " AudioMixer ring buffer: %7.2fms - avg msecs of samples in audio mixer's ring buffer in last 10s",
102+ (double)mixerRingBufferLatency);
95103 verticalOffset += STATS_HEIGHT_PER_LINE;
96104 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
97−
98− sprintf(latencyStatString, " Network to client: %7.2fms - half of last ping value calculated by the node list", networkRoundtripLatency / 2.0f);
105+
106+ sprintf(latencyStatString,
107+ " Network to client: %7.2fms - half of last ping value calculated by the node list",
108+ (double)(networkRoundtripLatency / 2.0f));
99109 verticalOffset += STATS_HEIGHT_PER_LINE;
100110 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
101−
102− sprintf(latencyStatString, " Output ring buffer: %7.2fms - avg msecs of samples in output ring buffer in last 10s", outputRingBufferLatency);
111+
112+ sprintf(latencyStatString,
113+ " Output ring buffer: %7.2fms - avg msecs of samples in output ring buffer in last 10s",
114+ (double)outputRingBufferLatency);
103115 verticalOffset += STATS_HEIGHT_PER_LINE;
104116 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
105−
106− sprintf(latencyStatString, " Audio output buffer: %7.2fms - avg msecs of samples in audio output buffer in last 10s", audioOutputBufferLatency);
117+
118+ sprintf(latencyStatString,
119+ " Audio output buffer: %7.2fms - avg msecs of samples in audio output buffer in last 10s",
120+ (double)audioOutputBufferLatency);
107121 verticalOffset += STATS_HEIGHT_PER_LINE;
108122 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
109−
110− sprintf(latencyStatString, " TOTAL: %7.2fms\n", totalLatency);
123+
124+ sprintf(latencyStatString, " TOTAL: %7.2fms\n", (double)totalLatency);
111125 verticalOffset += STATS_HEIGHT_PER_LINE;
112126 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
113−
114−
127+
128+
115129 verticalOffset += STATS_HEIGHT_PER_LINE; // blank line
116−
130+
117131 char clientUpstreamMicLabelString[] = "Upstream Mic Audio Packets Sent Gaps (by client):";
118132 verticalOffset += STATS_HEIGHT_PER_LINE;
119133 drawText(horizontalOffset, verticalOffset, scale, rotation, font, clientUpstreamMicLabelString, color);
120−
134+
121135 const MovingMinMaxAvg<quint64>& packetSentTimeGaps = _stats->getPacketSentTimeGaps();
122−
136+
123137 char stringBuffer[512];
124138 sprintf(stringBuffer, " Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s",
125139 formatUsecTime(packetSentTimeGaps.getMin()).toLatin1().data(),
@@ -127,47 +141,47 @@ void AudioIOStatsRenderer::render(const float* color, int width, int height) { · 1 unmodified line
127141 formatUsecTime(packetSentTimeGaps.getAverage()).toLatin1().data());
128142 verticalOffset += STATS_HEIGHT_PER_LINE;
129143 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);
130−
144+
131145 sprintf(stringBuffer, " Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s",
132146 formatUsecTime(packetSentTimeGaps.getWindowMin()).toLatin1().data(),
133147 formatUsecTime(packetSentTimeGaps.getWindowMax()).toLatin1().data(),
134148 formatUsecTime(packetSentTimeGaps.getWindowAverage()).toLatin1().data());
135149 verticalOffset += STATS_HEIGHT_PER_LINE;
136150 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);
137−
151+
138152 verticalOffset += STATS_HEIGHT_PER_LINE; // blank line
139−
153+
140154 char upstreamMicLabelString[] = "Upstream mic audio stats (received and reported by audio-mixer):";
141155 verticalOffset += STATS_HEIGHT_PER_LINE;
142156 drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamMicLabelString, color);
143−
157+
144158 renderAudioStreamStats(&_stats->getMixerAvatarStreamStats(), horizontalOffset, verticalOffset,
145159 scale, rotation, font, color);
146−
147−
160+
161+
148162 verticalOffset += STATS_HEIGHT_PER_LINE; // blank line
149−
163+
150164 char downstreamLabelString[] = "Downstream mixed audio stats:";
151165 verticalOffset += STATS_HEIGHT_PER_LINE;
152166 drawText(horizontalOffset, verticalOffset, scale, rotation, font, downstreamLabelString, color);
153−
167+
154168 AudioStreamStats downstreamStats = _stats->getMixerDownstreamStats();
155169 renderAudioStreamStats(&downstreamStats, horizontalOffset, verticalOffset,
156170 scale, rotation, font, color, true);
157−
158−
171+
172+
159173 if (_shouldShowInjectedStreams) {
160−
174+
161175 foreach(const AudioStreamStats& injectedStreamAudioStats, _stats->getMixerInjectedStreamStatsMap()) {
162−
176+
163177 verticalOffset += STATS_HEIGHT_PER_LINE; // blank line
164−
178+
165179 char upstreamInjectedLabelString[512];
166180 sprintf(upstreamInjectedLabelString, "Upstream injected audio stats: stream ID: %s",
167181 injectedStreamAudioStats._streamIdentifier.toString().toLatin1().data());
168182 verticalOffset += STATS_HEIGHT_PER_LINE;
169183 drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamInjectedLabelString, color);
170−
184+
171185 renderAudioStreamStats(&injectedStreamAudioStats, horizontalOffset, verticalOffset, scale, rotation, font, color);
172186 }
173187 }
@@ -175,22 +189,22 @@ void AudioIOStatsRenderer::render(const float* color, int width, int height) { · 1 unmodified line
175189
176190 void AudioIOStatsRenderer::renderAudioStreamStats(const AudioStreamStats* streamStats, int horizontalOffset, int& verticalOffset,
177191 float scale, float rotation, int font, const float* color, bool isDownstreamStats) {
178−
192+
179193 char stringBuffer[512];
180−
194+
181195 sprintf(stringBuffer, " Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)",
182− streamStats->_packetStreamStats.getLostRate() * 100.0f,
196+ (double)(streamStats->_packetStreamStats.getLostRate() * 100.0f),
183197 streamStats->_packetStreamStats._lost,
184− streamStats->_packetStreamWindowStats.getLostRate() * 100.0f,
198+ (double)(streamStats->_packetStreamWindowStats.getLostRate() * 100.0f),
185199 streamStats->_packetStreamWindowStats._lost);
186200 verticalOffset += STATS_HEIGHT_PER_LINE;
187201 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);
188−
202+
189203 if (isDownstreamStats) {
190204 sprintf(stringBuffer, " Ringbuffer frames | desired: %u, avg_available(10s): %u+%d, available: %u+%d",
191205 streamStats->_desiredJitterBufferFrames,
192206 streamStats->_framesAvailableAverage,
193− (int)(_stats->getAudioInputMsecsReadStats().getWindowAverage() / AudioConstants::NETWORK_FRAME_MSECS),
207+ (int)((float)_stats->getAudioInputMsecsReadStats().getWindowAverage() / AudioConstants::NETWORK_FRAME_MSECS),
194208 streamStats->_framesAvailable,
195209 (int)(_stats->getAudioOutputMsecsUnplayedStats().getCurrentIntervalLastSample()
196210 / AudioConstants::NETWORK_FRAME_MSECS));
@@ -200,10 +214,10 @@ void AudioIOStatsRenderer::renderAudioStreamStats(const AudioStreamStats* stream · 3 unmodified lines
200214 streamStats->_framesAvailableAverage,
201215 streamStats->_framesAvailable);
202216 }
203−
217+
204218 verticalOffset += STATS_HEIGHT_PER_LINE;
205219 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);
206−
220+
207221 sprintf(stringBuffer, " Ringbuffer stats | starves: %u, prev_starve_lasted: %u, frames_dropped: %u, overflows: %u",
208222 streamStats->_starveCount,
209223 streamStats->_consecutiveNotMixedCount,
@@ -211,18 +225,18 @@ void AudioIOStatsRenderer::renderAudioStreamStats(const AudioStreamStats* stream · 1 unmodified line
211225 streamStats->_overflowCount);
212226 verticalOffset += STATS_HEIGHT_PER_LINE;
213227 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);
214−
228+
215229 sprintf(stringBuffer, " Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s",
216230 formatUsecTime(streamStats->_timeGapMin).toLatin1().data(),
217231 formatUsecTime(streamStats->_timeGapMax).toLatin1().data(),
218232 formatUsecTime(streamStats->_timeGapAverage).toLatin1().data());
219233 verticalOffset += STATS_HEIGHT_PER_LINE;
220234 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);
221−
235+
222236 sprintf(stringBuffer, " Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s",
223237 formatUsecTime(streamStats->_timeGapWindowMin).toLatin1().data(),
224238 formatUsecTime(streamStats->_timeGapWindowMax).toLatin1().data(),
225239 formatUsecTime(streamStats->_timeGapWindowAverage).toLatin1().data());
226240 verticalOffset += STATS_HEIGHT_PER_LINE;
227241 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);
228−}
242+}
interface/src/audio/AudioToolBox.cpp+0−114
@@ -1,114 +0,0 @@
1−//
2−// AudioToolBox.cpp
3−// interface/src/audio
4−//
5−// Created by Stephen Birarda on 2014-12-16.
6−// Copyright 2014 High Fidelity, Inc.
7−//
8−// Distributed under the Apache License, Version 2.0.
9−// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10−//
11−
12−#include "InterfaceConfig.h"
13−
14−#include <AudioClient.h>
15−#include <GLCanvas.h>
16−#include <PathUtils.h>
17−#include <GeometryCache.h>
18−#include <gpu/GLBackend.h>
19−
20−#include "Application.h"
21−#include "AudioToolBox.h"
22−
23−// Mute icon configration
24−const int MUTE_ICON_SIZE = 24;
25−
26−AudioToolBox::AudioToolBox() :
27− _iconPulseTimeReference(usecTimestampNow())
28−{
29−}
30−
31−bool AudioToolBox::mousePressEvent(int x, int y) {
32− if (_iconBounds.contains(x, y)) {
33− DependencyManager::get<AudioClient>()->toggleMute();
34− return true;
35− }
36− return false;
37−}
38−
39−void AudioToolBox::render(int x, int y, int padding, bool boxed) {
40− glEnable(GL_TEXTURE_2D);
41−
42− if (!_micTexture) {
43− _micTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/mic.svg");
44− }
45− if (!_muteTexture) {
46− _muteTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/mic-mute.svg");
47− }
48− if (_boxTexture) {
49− _boxTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/audio-box.svg");
50− }
51−
52− auto audioIO = DependencyManager::get<AudioClient>();
53−
54− if (boxed) {
55− bool isClipping = ((audioIO->getTimeSinceLastClip() > 0.0f) && (audioIO->getTimeSinceLastClip() < 1.0f));
56− const int BOX_LEFT_PADDING = 5;
57− const int BOX_TOP_PADDING = 10;
58− const int BOX_WIDTH = 266;
59− const int BOX_HEIGHT = 44;
60−
61− QRect boxBounds = QRect(x - BOX_LEFT_PADDING, y - BOX_TOP_PADDING, BOX_WIDTH, BOX_HEIGHT);
62− glm::vec4 quadColor;
63−
64− if (isClipping) {
65− quadColor = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f);
66− } else {
67− quadColor = glm::vec4(0.41f, 0.41f, 0.41f, 1.0f);
68− }
69− glm::vec2 topLeft(boxBounds.left(), boxBounds.top());
70− glm::vec2 bottomRight(boxBounds.right(), boxBounds.bottom());
71− static const glm::vec2 texCoordTopLeft(1,1);
72− static const glm::vec2 texCoordBottomRight(0, 0);
73− glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_boxTexture));
74− DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor);
75− }
76−
77− float iconColor = 1.0f;
78−
79− _iconBounds = QRect(x + padding, y, MUTE_ICON_SIZE, MUTE_ICON_SIZE);
80− if (!audioIO->isMuted()) {
81− glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_micTexture));
82− iconColor = 1.0f;
83− } else {
84− glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_muteTexture));
85−
86− // Make muted icon pulsate
87− static const float PULSE_MIN = 0.4f;
88− static const float PULSE_MAX = 1.0f;
89− static const float PULSE_FREQUENCY = 1.0f; // in Hz
90− qint64 now = usecTimestampNow();
91− if (now - _iconPulseTimeReference > (qint64)USECS_PER_SECOND) {
92− // Prevents t from getting too big, which would diminish glm::cos precision
93− _iconPulseTimeReference = now - ((now - _iconPulseTimeReference) % USECS_PER_SECOND);
94− }
95− float t = (float)(now - _iconPulseTimeReference) / (float)USECS_PER_SECOND;
96− float pulseFactor = (glm::cos(t * PULSE_FREQUENCY * 2.0f * PI) + 1.0f) / 2.0f;
97− iconColor = PULSE_MIN + (PULSE_MAX - PULSE_MIN) * pulseFactor;
98− }
99−
100− glm::vec4 quadColor(iconColor, iconColor, iconColor, 1.0f);
101−
102− glm::vec2 topLeft(_iconBounds.left(), _iconBounds.top());
103− glm::vec2 bottomRight(_iconBounds.right(), _iconBounds.bottom());
104− glm::vec2 texCoordTopLeft(1,1);
105− glm::vec2 texCoordBottomRight(0,0);
106−
107− if (_boxQuadID == GeometryCache::UNKNOWN_ID) {
108− _boxQuadID = DependencyManager::get<GeometryCache>()->allocateID();
109− }
110−
111− DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor, _boxQuadID);
112− glBindTexture(GL_TEXTURE_2D, 0);
113− glDisable(GL_TEXTURE_2D);
114−}
interface/src/audio/AudioToolBox.h+0−36
@@ -1,36 +0,0 @@
1−//
2−// AudioToolBox.h
3−// interface/src/audio
4−//
5−// Created by Stephen Birarda on 2014-12-16.
6−// Copyright 2014 High Fidelity, Inc.
7−//
8−// Distributed under the Apache License, Version 2.0.
9−// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10−//
11−
12−#ifndef hifi_AudioToolBox_h
13−#define hifi_AudioToolBox_h
14−
15−#include <DependencyManager.h>
16−#include <GeometryCache.h>
17−#include <QOpenGLTexture>
18−
19−class AudioToolBox : public Dependency {
20− SINGLETON_DEPENDENCY
21−public:
22− void render(int x, int y, int padding, bool boxed);
23−
24− bool mousePressEvent(int x, int y);
25−protected:
26− AudioToolBox();
27−private:
28− gpu::TexturePointer _micTexture;
29− gpu::TexturePointer _muteTexture;
30− gpu::TexturePointer _boxTexture;
31− int _boxQuadID = GeometryCache::UNKNOWN_ID;
32− QRect _iconBounds;
33− qint64 _iconPulseTimeReference = 0;
34−};
35−
36−#endif // hifi_AudioToolBox_h
interface/src/avatar/Avatar.cpp+110−121
@@ -57,7 +57,7 @@ const float CHAT_MESSAGE_SCALE = 0.0015f; · 56 unmodified lines
5757 const float CHAT_MESSAGE_HEIGHT = 0.1f;
5858 const float DISPLAYNAME_FADE_TIME = 0.5f;
5959 const float DISPLAYNAME_FADE_FACTOR = pow(0.01f, 1.0f / DISPLAYNAME_FADE_TIME);
60−const float DISPLAYNAME_ALPHA = 0.95f;
60+const float DISPLAYNAME_ALPHA = 1.0f;
6161 const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f;
6262
6363 namespace render {
@@ -107,6 +107,7 @@ Avatar::Avatar() : · 43 unmodified lines
107107 }
108108
109109 Avatar::~Avatar() {
110+ assert(_motionState == nullptr);
110111 for(auto attachment : _unusedAttachments) {
111112 delete attachment;
112113 }
@@ -280,9 +281,9 @@ enum TextRendererType { · 167 unmodified lines
280281 };
281282
282283 static TextRenderer3D* textRenderer(TextRendererType type) {
283− static TextRenderer3D* chatRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, 24, -1,
284+ static TextRenderer3D* chatRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, -1,
284285 false, TextRenderer3D::SHADOW_EFFECT);
285− static TextRenderer3D* displayNameRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, 12);
286+ static TextRenderer3D* displayNameRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY);
286287
287288 switch(type) {
288289 case CHAT:
@@ -323,7 +324,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 34 unmodified lines
323324 _referential->update();
324325 }
325326
326− auto batch = renderArgs->_batch;
327+ auto& batch = *renderArgs->_batch;
327328
328329 if (postLighting &&
329330 glm::distance(DependencyManager::get<AvatarManager>()->getMyAvatar()->getPosition(), _position) < 10.0f) {
@@ -354,9 +355,9 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 24 unmodified lines
354355 Transform pointerTransform;
355356 pointerTransform.setTranslation(position);
356357 pointerTransform.setRotation(rotation);
357− batch->setModelTransform(pointerTransform);
358− deferredLighting->bindSimpleProgram(*batch);
359− geometryCache->renderLine(*batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor);
358+ batch.setModelTransform(pointerTransform);
359+ deferredLighting->bindSimpleProgram(batch);
360+ geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor);
360361 }
361362 }
362363
@@ -377,9 +378,9 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 14 unmodified lines
377378 Transform pointerTransform;
378379 pointerTransform.setTranslation(position);
379380 pointerTransform.setRotation(rotation);
380− batch->setModelTransform(pointerTransform);
381− deferredLighting->bindSimpleProgram(*batch);
382− geometryCache->renderLine(*batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor);
381+ batch.setModelTransform(pointerTransform);
382+ deferredLighting->bindSimpleProgram(batch);
383+ geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor);
383384 }
384385 }
385386 }
@@ -464,8 +465,8 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 78 unmodified lines
464465 }
465466 Transform transform;
466467 transform.setTranslation(position);
467− batch->setModelTransform(transform);
468− DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(*batch, LOOK_AT_INDICATOR_RADIUS
468+ batch.setModelTransform(transform);
469+ DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(batch, LOOK_AT_INDICATOR_RADIUS
469470 , 15, 15, LOOK_AT_INDICATOR_COLOR);
470471 }
471472 }
@@ -492,14 +493,14 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 20 unmodified lines
492493 Transform transform;
493494 transform.setTranslation(_position);
494495 transform.setScale(height);
495− batch->setModelTransform(transform);
496+ batch.setModelTransform(transform);
496497
497498 if (_voiceSphereID == GeometryCache::UNKNOWN_ID) {
498499 _voiceSphereID = DependencyManager::get<GeometryCache>()->allocateID();
499500 }
500501
501− DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(*batch);
502− DependencyManager::get<GeometryCache>()->renderSphere(*batch, sphereRadius, 15, 15,
502+ DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch);
503+ DependencyManager::get<GeometryCache>()->renderSphere(batch, sphereRadius, 15, 15,
503504 glm::vec4(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE), true,
504505 _voiceSphereID);
505506 }
@@ -507,14 +508,12 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 1 unmodified line
507508 }
508509
509510 const float DISPLAYNAME_DISTANCE = 20.0f;
510− setShowDisplayName(renderArgs->_renderMode == RenderArgs::NORMAL_RENDER_MODE && distanceToTarget < DISPLAYNAME_DISTANCE);
511+ setShowDisplayName(distanceToTarget < DISPLAYNAME_DISTANCE);
511512
512− if (renderArgs->_renderMode != RenderArgs::NORMAL_RENDER_MODE || (isMyAvatar() &&
513− Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON)) {
514− return;
513+ auto cameraMode = Application::getInstance()->getCamera()->getMode();
514+ if (!isMyAvatar() || cameraMode != CAMERA_MODE_FIRST_PERSON) {
515+ renderDisplayName(batch, *renderArgs->_viewFrustum);
515516 }
516−
517− renderDisplayName(renderArgs);
518517 }
519518
520519 glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
@@ -654,8 +653,8 @@ float Avatar::getBillboardSize() const { · 133 unmodified lines
654653 return _scale * BILLBOARD_DISTANCE * tanf(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f));
655654 }
656655
657−glm::vec3 Avatar::getDisplayNamePosition() {
658− glm::vec3 namePosition;
656+glm::vec3 Avatar::getDisplayNamePosition() const {
657+ glm::vec3 namePosition(0.0f);
659658 if (getSkeletonModel().getNeckPosition(namePosition)) {
660659 namePosition += getBodyUpDirection() * getHeadHeight() * 1.1f;
661660 } else {
@@ -665,81 +664,73 @@ glm::vec3 Avatar::getDisplayNamePosition() { · 3 unmodified lines
665664 return namePosition;
666665 }
667666
668−float Avatar::calculateDisplayNameScaleFactor(const glm::vec3& textPosition, bool inHMD) {
669−
670− // We need to compute the scale factor such as the text remains with fixed size respect to window coordinates
671− // We project a unit vector and check the difference in screen coordinates, to check which is the
672− // correction scale needed
673− // save the matrices for later scale correction factor
674− // The up vector must be relative to the rotation current rotation matrix:
675− // we set the identity
667+Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& frustum, float fontSize) const {
668+ Transform result;
669+ // We assume textPosition is whithin the frustum
670+ glm::vec3 textPosition = getDisplayNamePosition();
671+
672+ // Compute viewProjection matrix
673+ glm::mat4 projMat, viewMat;
674+ Transform view;
675+ frustum.evalProjectionMatrix(projMat);
676+ frustum.evalViewTransform(view);
677+ glm::mat4 viewProj = projMat * view.getInverseMatrix(viewMat);
678+
679+ // Used to determine correct scale
676680 glm::vec3 testPoint0 = textPosition;
677− glm::vec3 testPoint1 = textPosition + (Application::getInstance()->getCamera()->getRotation() * IDENTITY_UP);
678−
679− double textWindowHeight;
680−
681+ glm::vec3 testPoint1 = testPoint0 + glm::normalize(frustum.getUp());
682+ // testPoints projections
683+ glm::vec4 p0 = viewProj * glm::vec4(testPoint0, 1.0);
684+ glm::vec4 p1 = viewProj * glm::vec4(testPoint1, 1.0);
685+
686+ // TODO REMOVE vvv
681687 GLint viewportMatrix[4];
682688 glGetIntegerv(GL_VIEWPORT, viewportMatrix);
683689 glm::dmat4 modelViewMatrix;
684− float windowSizeX = viewportMatrix[2] - viewportMatrix[0];
685690 float windowSizeY = viewportMatrix[3] - viewportMatrix[1];
691+ // TODO REMOVE ^^^
692+
693+ const float DESIRED_HIGHT_ON_SCREEN = 20; // In pixels (this is double on retinas)
694+
695+ // Projected point are between -1.0f and 1.0f, hence 0.5f * windowSizeY
696+ double pixelHeight = 0.5f * windowSizeY * glm::abs((p1.y / p1.w) - (p0.y / p0.w)); //
697+ // Handles pixel density (especially for macs retina displays)
698+ double devicePixelRatio = qApp->getDevicePixelRatio() * qApp->getRenderResolutionScale(); // pixels / unit
699+
700+ // Compute correct scale to apply
701+ float scale = DESIRED_HIGHT_ON_SCREEN / (fontSize * pixelHeight) * devicePixelRatio;
702+
703+ // Compute pixel alignment offset
704+ float clipToPix = 0.5f * windowSizeY / p1.w; // Got from clip to pixel coordinates
705+ glm::vec4 screenPos = clipToPix * p1; // in pixels coords
706+ glm::vec4 screenOffset = (glm::round(screenPos) - screenPos) / clipToPix; // in clip coords
707+ glm::vec3 worldOffset = glm::vec3(screenOffset.x, screenOffset.y, 0.0f) / (float)pixelHeight;
708+
709+ // Compute orientation
710+ glm::vec3 eulerAngles = ::safeEulerAngles(frustum.getOrientation());
711+ eulerAngles.z = 0.0f; // Cancel roll
712+ glm::quat orientation(eulerAngles); // back to quaternions
713+
714+ // Set transform (The order IS important)
715+ result.setTranslation(textPosition);
716+ result.setRotation(orientation); // Always face the screen
717+ result.postTranslate(worldOffset); // Pixel alignment
718+ result.setScale(scale);
719+ return result;
686720
687− glm::dmat4 projectionMatrix;
688− Application::getInstance()->getModelViewMatrix(&modelViewMatrix);
689− Application::getInstance()->getProjectionMatrix(&projectionMatrix);
690−
691−
692− glm::dvec4 p0 = modelViewMatrix * glm::dvec4(testPoint0, 1.0);
693− p0 = projectionMatrix * p0;
694− glm::dvec2 result0 = glm::vec2(windowSizeX * (p0.x / p0.w + 1.0f) * 0.5f, windowSizeY * (p0.y / p0.w + 1.0f) * 0.5f);
695−
696− glm::dvec4 p1 = modelViewMatrix * glm::dvec4(testPoint1, 1.0);
697− p1 = projectionMatrix * p1;
698− glm::vec2 result1 = glm::vec2(windowSizeX * (p1.x / p1.w + 1.0f) * 0.5f, windowSizeY * (p1.y / p1.w + 1.0f) * 0.5f);
699− textWindowHeight = abs(result1.y - result0.y);
700−
701− // need to scale to compensate for the font resolution due to the device
702− float scaleFactor = QApplication::desktop()->windowHandle()->devicePixelRatio() *
703− ((textWindowHeight > EPSILON) ? 1.0f / textWindowHeight : 1.0f);
704− if (inHMD) {
705− const float HMDMODE_NAME_SCALE = 0.65f;
706− scaleFactor *= HMDMODE_NAME_SCALE;
707− } else {
708− scaleFactor *= Application::getInstance()->getRenderResolutionScale();
709− }
710− return scaleFactor;
711721 }
712722
713−void Avatar::renderDisplayName(RenderArgs* renderArgs) {
714− auto batch = renderArgs->_batch;
715−
723+void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) const {
716724 bool shouldShowReceiveStats = DependencyManager::get<AvatarManager>()->shouldShowReceiveStats() && !isMyAvatar();
717725
726+ // If we have nothing to draw, or it's tottaly transparent, return
718727 if ((_displayName.isEmpty() && !shouldShowReceiveStats) || _displayNameAlpha == 0.0f) {
719728 return;
720729 }
721−
722− // which viewing mode?
723− bool inHMD = Application::getInstance()->isHMDMode();
724−
725− glm::vec3 textPosition = getDisplayNamePosition();
726−
727− // we need "always facing camera": we must remove the camera rotation from the stac
728− glm::quat rotation = Application::getInstance()->getCamera()->getRotation();
729−
730− // TODO: Fix scaling - at some point this or the text rendering changed in scale.
731− float scaleFactor = calculateDisplayNameScaleFactor(textPosition, inHMD);
732− scaleFactor /= 3.5f;
733−
734− Transform textTransform;
735− textTransform.setTranslation(textPosition);
736− textTransform.setRotation(rotation);
737− textTransform.setScale(scaleFactor);
730+ auto renderer = textRenderer(DISPLAYNAME);
738731
739732 // optionally render timing stats for this avatar with the display name
740733 QString renderedDisplayName = _displayName;
741− QRect nameDynamicRect = _displayNameBoundingRect;
742−
743734 if (shouldShowReceiveStats) {
744735 float kilobitsPerSecond = getAverageBytesReceivedPerSecond() / (float) BYTES_PER_KILOBIT;
745736
@@ -747,42 +738,43 @@ void Avatar::renderDisplayName(RenderArgs* renderArgs) { · 1 unmodified line
747738 if (!renderedDisplayName.isEmpty()) {
748739 statsFormat.prepend(" - ");
749740 }
750−
751− QString statsText = statsFormat.arg(QString::number(kilobitsPerSecond, 'f', 2)).arg(getReceiveRate());
752− renderedDisplayName += statsText;
753−
754− glm::vec2 extent = textRenderer(DISPLAYNAME)->computeExtent(renderedDisplayName);
755− nameDynamicRect = QRect(0, 0, (int)extent.x, (int)extent.y);
741+ renderedDisplayName += statsFormat.arg(QString::number(kilobitsPerSecond, 'f', 2)).arg(getReceiveRate());
756742 }
757−
758− int text_x = -nameDynamicRect.width() / 2;
759− int text_y = -nameDynamicRect.height() / 2;
760−
761− // draw a gray background
762− int left = text_x;
763− int right = left + nameDynamicRect.width();
764− int bottom = text_y;
765− int top = bottom + nameDynamicRect.height();
766− const int border = 8;
767− bottom -= border;
768− left -= border;
769− top += border;
770− right += border;
771743
744+ // Compute display name extent/position offset
745+ glm::vec2 extent = renderer->computeExtent(renderedDisplayName);
746+ QRect nameDynamicRect = QRect(0, 0, (int)extent.x, (int)extent.y);
747+ const int text_x = -nameDynamicRect.width() / 2;
748+ const int text_y = -nameDynamicRect.height() / 2;
749+
750+ // Compute background position/size
751+ static const float SLIGHTLY_BEHIND = -0.05f;
752+ const int border = 0.1f * nameDynamicRect.height();
753+ const int left = text_x - border;
754+ const int bottom = text_y - border;
755+ const int width = nameDynamicRect.width() + 2.0f * border;
756+ const int height = nameDynamicRect.height() + 2.0f * border;
757+ const int bevelDistance = 0.1f * height;
758+
759+ // Display name and background colors
772760 glm::vec4 textColor(0.93f, 0.93f, 0.93f, _displayNameAlpha);
773761 glm::vec4 backgroundColor(0.2f, 0.2f, 0.2f,
774− _displayNameAlpha * DISPLAYNAME_BACKGROUND_ALPHA / DISPLAYNAME_ALPHA);
762+ (_displayNameAlpha / DISPLAYNAME_ALPHA) * DISPLAYNAME_BACKGROUND_ALPHA);
763+
764+ // Compute display name transform
765+ auto textTransform = calculateDisplayNameTransform(frustum, renderer->getFontSize());
775766
767+ // Render background slightly behind to avoid z-fighting
776768 auto backgroundTransform = textTransform;
777− backgroundTransform.postTranslate(glm::vec3(0.0f, 0.0f, -0.001f));
778− batch->setModelTransform(backgroundTransform);
779− DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(*batch);
780− DependencyManager::get<GeometryCache>()->renderBevelCornersRect(*batch, left, bottom, right - left, top - bottom, 3,
781− backgroundColor);
769+ backgroundTransform.postTranslate(glm::vec3(0.0f, 0.0f, SLIGHTLY_BEHIND));
770+ batch.setModelTransform(backgroundTransform);
771+ DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch);
772+ DependencyManager::get<GeometryCache>()->renderBevelCornersRect(batch, left, bottom, width, height,
773+ bevelDistance, backgroundColor);
774+ // Render actual name
782775 QByteArray nameUTF8 = renderedDisplayName.toLocal8Bit();
783−
784− batch->setModelTransform(textTransform);
785− textRenderer(DISPLAYNAME)->draw(*batch, text_x, -text_y, nameUTF8.data(), textColor);
776+ batch.setModelTransform(textTransform);
777+ renderer->draw(batch, text_x, -text_y, nameUTF8.data(), textColor);
786778 }
787779
788780 bool Avatar::findRayIntersection(RayIntersectionInfo& intersection) const {
@@ -987,13 +979,6 @@ void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) { · 198 unmodified lines
987979 }
988980 }
989981
990−void Avatar::setDisplayName(const QString& displayName) {
991− AvatarData::setDisplayName(displayName);
992− // FIXME is this a sufficient replacement for tightBoundingRect?
993− glm::vec2 extent = textRenderer(DISPLAYNAME)->computeExtent(displayName);
994− _displayNameBoundingRect = QRect(0, 0, (int)extent.x, (int)extent.y);
995−}
996−
997982 void Avatar::setBillboard(const QByteArray& billboard) {
998983 AvatarData::setBillboard(billboard);
999984
@@ -1092,7 +1077,12 @@ float Avatar::getSkeletonHeight() const { · 92 unmodified lines
10921077 float Avatar::getHeadHeight() const {
10931078 Extents extents = getHead()->getFaceModel().getMeshExtents();
10941079 if (!extents.isEmpty() && extents.isValid()) {
1095− return extents.maximum.y - extents.minimum.y;
1080+
1081+ // HACK: We have a really odd case when fading out for some models where this value explodes
1082+ float result = extents.maximum.y - extents.minimum.y;
1083+ if (result >= 0.0f && result < 100.0f * _scale ) {
1084+ return result;
1085+ }
10961086 }
10971087
10981088 extents = _skeletonModel.getMeshExtents();
@@ -1116,7 +1106,7 @@ void Avatar::setShowDisplayName(bool showDisplayName) { · 17 unmodified lines
11161106 }
11171107
11181108 // For myAvatar, the alpha update is not done (called in simulate for other avatars)
1119− if (DependencyManager::get<AvatarManager>()->getMyAvatar() == this) {
1109+ if (isMyAvatar()) {
11201110 if (showDisplayName) {
11211111 _displayNameAlpha = DISPLAYNAME_ALPHA;
11221112 } else {
@@ -1129,7 +1119,6 @@ void Avatar::setShowDisplayName(bool showDisplayName) { · 6 unmodified lines
11291119 } else {
11301120 _displayNameTargetAlpha = 0.0f;
11311121 }
1132−
11331122 }
11341123
11351124 // virtual
interface/src/avatar/Avatar.h+5−5
@@ -98,6 +98,7 @@ public: · 97 unmodified lines
9898 //getters
9999 bool isInitialized() const { return _initialized; }
100100 SkeletonModel& getSkeletonModel() { return _skeletonModel; }
101+ const SkeletonModel& getSkeletonModel() const { return _skeletonModel; }
101102 const QVector<Model*>& getAttachmentModels() const { return _attachmentModels; }
102103 glm::vec3 getChestPosition() const;
103104 float getScale() const { return _scale; }
@@ -131,7 +132,7 @@ public: · 27 unmodified lines
131132 /// \return whether or not the plane penetrated
132133 bool findPlaneCollisions(const glm::vec4& plane, CollisionList& collisions);
133134
134− virtual bool isMyAvatar() { return false; }
135+ virtual bool isMyAvatar() const { return false; }
135136
136137 virtual QVector<glm::quat> getJointRotations() const;
137138 virtual glm::quat getJointRotation(int index) const;
@@ -141,7 +142,6 @@ public: · 3 unmodified lines
141142 virtual void setFaceModelURL(const QUrl& faceModelURL);
142143 virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
143144 virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData);
144− virtual void setDisplayName(const QString& displayName);
145145 virtual void setBillboard(const QByteArray& billboard);
146146
147147 void setShowDisplayName(bool showDisplayName);
@@ -232,10 +232,10 @@ protected: · 84 unmodified lines
232232 float getSkeletonHeight() const;
233233 float getHeadHeight() const;
234234 float getPelvisFloatingHeight() const;
235− glm::vec3 getDisplayNamePosition();
235+ glm::vec3 getDisplayNamePosition() const;
236236
237− float calculateDisplayNameScaleFactor(const glm::vec3& textPosition, bool inHMD);
238− void renderDisplayName(RenderArgs* renderArgs);
237+ Transform calculateDisplayNameTransform(const ViewFrustum& frustum, float fontSize) const;
238+ void renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) const;
239239 virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel = 0.0f);
240240 virtual bool shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const;
241241 virtual void fixupModelsInScene();
interface/src/avatar/AvatarActionHold.cpp+10−1
@@ -29,6 +29,12 @@ AvatarActionHold::~AvatarActionHold() { · 28 unmodified lines
2929
3030 void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
3131 auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
32+
33+ if (!tryLockForRead()) {
34+ // don't risk hanging the thread running the physics simulation
35+ return;
36+ }
37+
3238 glm::vec3 palmPosition;
3339 if (_hand == "right") {
3440 palmPosition = myAvatar->getRightPalmPosition();
@@ -40,8 +46,11 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { · 5 unmodified lines
4046 auto offset = rotation * _relativePosition;
4147 auto position = palmPosition + offset;
4248 rotation *= _relativeRotation;
49+ unlock();
4350
44− lockForWrite();
51+ if (!tryLockForWrite()) {
52+ return;
53+ }
4554 _positionalTarget = position;
4655 _rotationalTarget = rotation;
4756 unlock();
interface/src/avatar/AvatarManager.cpp+17−5
@@ -13,8 +13,18 @@ · 12 unmodified lines
1313
1414 #include <QScriptEngine>
1515
16+#ifdef __GNUC__
17+#pragma GCC diagnostic push
18+#pragma GCC diagnostic ignored "-Wdouble-promotion"
19+#endif
20+
1621 #include <glm/gtx/string_cast.hpp>
1722
23+#ifdef __GNUC__
24+#pragma GCC diagnostic pop
25+#endif
26+
27+
1828 #include <GlowEffect.h>
1929 #include <PerfStat.h>
2030 #include <RegisteredMetaTypes.h>
@@ -104,6 +114,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { · 83 unmodified lines
104114 // DO NOT update or fade out uninitialized Avatars
105115 ++avatarIterator;
106116 } else if (avatar->shouldDie()) {
117+ removeAvatarMotionState(avatar);
107118 _avatarFades.push_back(avatarIterator.value());
108119 avatarIterator = _avatarHash.erase(avatarIterator);
109120 } else {
@@ -153,12 +164,13 @@ AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWe · 43 unmodified lines
153164 }
154165
155166 // protected
156−void AvatarManager::removeAvatarMotionState(Avatar* avatar) {
157− AvatarMotionState* motionState= avatar->_motionState;
167+void AvatarManager::removeAvatarMotionState(AvatarSharedPointer avatar) {
168+ auto rawPointer = std::static_pointer_cast<Avatar>(avatar);
169+ AvatarMotionState* motionState= rawPointer->_motionState;
158170 if (motionState) {
159171 // clean up physics stuff
160172 motionState->clearObjectBackPointer();
161− avatar->_motionState = nullptr;
173+ rawPointer->_motionState = nullptr;
162174 _avatarMotionStates.remove(motionState);
163175 _motionStatesToAdd.remove(motionState);
164176 _motionStatesToDelete.push_back(motionState);
@@ -171,7 +183,7 @@ void AvatarManager::removeAvatar(const QUuid& sessionUUID) { · 6 unmodified lines
171183 if (avatarIterator != _avatarHash.end()) {
172184 std::shared_ptr<Avatar> avatar = std::dynamic_pointer_cast<Avatar>(avatarIterator.value());
173185 if (avatar != _myAvatar && avatar->isInitialized()) {
174− removeAvatarMotionState(avatar.get());
186+ removeAvatarMotionState(avatar);
175187 _avatarFades.push_back(avatarIterator.value());
176188 _avatarHash.erase(avatarIterator);
177189 }
@@ -187,7 +199,7 @@ void AvatarManager::clearOtherAvatars() { · 9 unmodified lines
187199 // don't remove myAvatar or uninitialized avatars from the list
188200 ++avatarIterator;
189201 } else {
190− removeAvatarMotionState(avatar.get());
202+ removeAvatarMotionState(avatar);
191203 _avatarFades.push_back(avatarIterator.value());
192204 avatarIterator = _avatarHash.erase(avatarIterator);
193205 }
interface/src/avatar/AvatarManager.h+1−1
@@ -73,7 +73,7 @@ private: · 72 unmodified lines
7373 // virtual overrides
7474 virtual AvatarSharedPointer newSharedAvatar();
7575 virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer);
76− void removeAvatarMotionState(Avatar* avatar);
76+ void removeAvatarMotionState(AvatarSharedPointer avatar);
7777 virtual void removeAvatar(const QUuid& sessionUUID);
7878
7979 QVector<AvatarSharedPointer> _avatarFades;
interface/src/avatar/Head.cpp+13−6
@@ -77,7 +77,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { · 76 unmodified lines
7777 const float AUDIO_LONG_TERM_AVERAGING_SECS = 30.0f;
7878 _averageLoudness = glm::mix(_averageLoudness, _audioLoudness, glm::min(deltaTime / AUDIO_AVERAGING_SECS, 1.0f));
7979
80− if (_longTermAverageLoudness == -1.0) {
80+ if (_longTermAverageLoudness == -1.0f) {
8181 _longTermAverageLoudness = _averageLoudness;
8282 } else {
8383 _longTermAverageLoudness = glm::mix(_longTermAverageLoudness, _averageLoudness, glm::min(deltaTime / AUDIO_LONG_TERM_AVERAGING_SECS, 1.0f));
@@ -124,18 +124,25 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { · 40 unmodified lines
124124
125125 if (!(_isFaceTrackerConnected || billboard)) {
126126 // Update eye saccades
127− const float AVERAGE_MICROSACCADE_INTERVAL = 0.50f;
128− const float AVERAGE_SACCADE_INTERVAL = 4.0f;
127+ const float AVERAGE_MICROSACCADE_INTERVAL = 1.0f;
128+ const float AVERAGE_SACCADE_INTERVAL = 6.0f;
129129 const float MICROSACCADE_MAGNITUDE = 0.002f;
130130 const float SACCADE_MAGNITUDE = 0.04f;
131−
131+ const float MAXIMUM_SACCADE_SPEED = 0.8f;
132+
132133 if (randFloat() < deltaTime / AVERAGE_MICROSACCADE_INTERVAL) {
133134 _saccadeTarget = MICROSACCADE_MAGNITUDE * randVector();
134135 } else if (randFloat() < deltaTime / AVERAGE_SACCADE_INTERVAL) {
135136 _saccadeTarget = SACCADE_MAGNITUDE * randVector();
136137 }
137− _saccade += (_saccadeTarget - _saccade) * 0.50f;
138−
138+
139+ glm::vec3 saccadeDelta = (_saccadeTarget - _saccade) * 0.5f;
140+ float speed = glm::length(saccadeDelta) / deltaTime;
141+ if (speed > MAXIMUM_SACCADE_SPEED) {
142+ saccadeDelta = saccadeDelta * MAXIMUM_SACCADE_SPEED / speed;
143+ }
144+ _saccade += saccadeDelta;
145+
139146 // Detect transition from talking to not; force blink after that and a delay
140147 bool forceBlink = false;
141148 const float TALKING_LOUDNESS = 100.0f;
interface/src/avatar/MyAvatar.cpp+81−81
@@ -59,10 +59,10 @@ const float MAX_WALKING_SPEED = 2.5f; // human walking speed · 58 unmodified lines
5959 const float MAX_BOOST_SPEED = 0.5f * MAX_WALKING_SPEED; // keyboard motor gets additive boost below this speed
6060 const float MIN_AVATAR_SPEED = 0.05f; // speed is set to zero below this
6161
62−// TODO: normalize avatar speed for standard avatar size, then scale all motion logic
62+// TODO: normalize avatar speed for standard avatar size, then scale all motion logic
6363 // to properly follow avatar size.
6464 float MAX_AVATAR_SPEED = 300.0f;
65−float MAX_KEYBOARD_MOTOR_SPEED = MAX_AVATAR_SPEED;
65+float MAX_KEYBOARD_MOTOR_SPEED = MAX_AVATAR_SPEED;
6666 float DEFAULT_KEYBOARD_MOTOR_TIMESCALE = 0.25f;
6767 float MIN_SCRIPTED_MOTOR_TIMESCALE = 0.005f;
6868 float DEFAULT_SCRIPTED_MOTOR_TIMESCALE = 1.0e6f;
@@ -146,7 +146,7 @@ void MyAvatar::update(float deltaTime) { · 77 unmodified lines
146146 if (_referential) {
147147 _referential->update();
148148 }
149−
149+
150150 Head* head = getHead();
151151 head->relaxLean(deltaTime);
152152 updateFromTrackers(deltaTime);
@@ -163,12 +163,12 @@ void MyAvatar::update(float deltaTime) { · 10 unmodified lines
163163
164164 void MyAvatar::simulate(float deltaTime) {
165165 PerformanceTimer perfTimer("simulate");
166−
166+
167167 // Play back recording
168168 if (_player && _player->isPlaying()) {
169169 _player->play();
170170 }
171−
171+
172172 if (_scale != _targetScale) {
173173 float scale = (1.0f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale;
174174 setScale(scale);
@@ -179,7 +179,7 @@ void MyAvatar::simulate(float deltaTime) { · 4 unmodified lines
179179 updateOrientation(deltaTime);
180180 updatePosition(deltaTime);
181181 }
182−
182+
183183 {
184184 PerformanceTimer perfTimer("hand");
185185 // update avatar skeleton and simulate hand and head
@@ -222,12 +222,12 @@ void MyAvatar::simulate(float deltaTime) { · 36 unmodified lines
222222 head->setScale(_scale);
223223 head->simulate(deltaTime, true);
224224 }
225−
225+
226226 // Record avatars movements.
227227 if (_recorder && _recorder->isRecording()) {
228228 _recorder->record();
229229 }
230−
230+
231231 // consider updating our billboard
232232 maybeUpdateBillboard();
233233 }
@@ -235,18 +235,18 @@ void MyAvatar::simulate(float deltaTime) { · 1 unmodified line
235235 // Update avatar head rotation with sensor data
236236 void MyAvatar::updateFromTrackers(float deltaTime) {
237237 glm::vec3 estimatedPosition, estimatedRotation;
238−
238+
239239 bool inHmd = qApp->isHMDMode();
240−
240+
241241 if (isPlaying() && inHmd) {
242242 return;
243243 }
244244
245245 if (inHmd) {
246− estimatedPosition = qApp->getHeadPosition();
246+ estimatedPosition = qApp->getHeadPosition();
247247 estimatedPosition.x *= -1.0f;
248248 _trackedHeadPosition = estimatedPosition;
249−
249+
250250 const float OCULUS_LEAN_SCALE = 0.05f;
251251 estimatedPosition /= OCULUS_LEAN_SCALE;
252252 } else {
@@ -257,7 +257,7 @@ void MyAvatar::updateFromTrackers(float deltaTime) { · 4 unmodified lines
257257 estimatedRotation = glm::degrees(safeEulerAngles(tracker->getHeadRotation()));
258258 }
259259 }
260−
260+
261261 // Rotate the body if the head is turned beyond the screen
262262 if (Menu::getInstance()->isOptionChecked(MenuOption::TurnWithHead)) {
263263 const float TRACKER_YAW_TURN_SENSITIVITY = 0.5f;
@@ -317,7 +317,7 @@ void MyAvatar::renderDebugBodyPoints() { · 53 unmodified lines
317317 glm::vec3 headPosition(getHead()->getEyePosition());
318318 float torsoToHead = glm::length(headPosition - torsoPosition);
319319 glm::vec3 position;
320− qCDebug(interfaceapp, "head-above-torso %.2f, scale = %0.2f", torsoToHead, getScale());
320+ qCDebug(interfaceapp, "head-above-torso %.2f, scale = %0.2f", (double)torsoToHead, (double)getScale());
321321
322322 // Torso Sphere
323323 position = torsoPosition;
@@ -433,7 +433,7 @@ void MyAvatar::startRecording() { · 109 unmodified lines
433433 auto audioClient = DependencyManager::get<AudioClient>();
434434 connect(audioClient.data(), &AudioClient::inputReceived, _recorder.data(),
435435 &Recorder::recordAudio, Qt::BlockingQueuedConnection);
436−
436+
437437 _recorder->startRecording();
438438 }
439439
@@ -449,7 +449,7 @@ void MyAvatar::stopRecording() { · 9 unmodified lines
449449 // stop grabbing audio from the AudioClient
450450 auto audioClient = DependencyManager::get<AudioClient>();
451451 disconnect(audioClient.data(), 0, _recorder.data(), 0);
452−
452+
453453 _recorder->stopRecording();
454454 }
455455 }
@@ -481,7 +481,7 @@ void MyAvatar::loadLastRecording() { · 25 unmodified lines
481481 if (!_player) {
482482 _player = PlayerPointer(new Player(this));
483483 }
484−
484+
485485 _player->loadRecording(_recorder->getRecording());
486486 }
487487
@@ -573,7 +573,7 @@ AnimationDetails MyAvatar::getAnimationDetailsByRole(const QString& role) { · 85 unmodified lines
573573 AnimationDetails result;
574574 if (QThread::currentThread() != thread()) {
575575 QMetaObject::invokeMethod(this, "getAnimationDetailsByRole", Qt::BlockingQueuedConnection,
576− Q_RETURN_ARG(AnimationDetails, result),
576+ Q_RETURN_ARG(AnimationDetails, result),
577577 Q_ARG(const QString&, role));
578578 return result;
579579 }
@@ -590,7 +590,7 @@ AnimationDetails MyAvatar::getAnimationDetails(const QString& url) { · 10 unmodified lines
590590 AnimationDetails result;
591591 if (QThread::currentThread() != thread()) {
592592 QMetaObject::invokeMethod(this, "getAnimationDetails", Qt::BlockingQueuedConnection,
593− Q_RETURN_ARG(AnimationDetails, result),
593+ Q_RETURN_ARG(AnimationDetails, result),
594594 Q_ARG(const QString&, url));
595595 return result;
596596 }
@@ -638,7 +638,7 @@ void MyAvatar::saveData() { · 41 unmodified lines
638638 settings.setValue("scale", attachment.scale);
639639 }
640640 settings.endArray();
641−
641+
642642 settings.beginWriteArray("animationHandles");
643643 for (int i = 0; i < _animationHandles.size(); i++) {
644644 settings.setArrayIndex(i);
@@ -655,7 +655,7 @@ void MyAvatar::saveData() { · 10 unmodified lines
655655 settings.setValue("maskedJoints", pointer->getMaskedJoints());
656656 }
657657 settings.endArray();
658−
658+
659659 settings.setValue("displayName", _displayName);
660660
661661 settings.endGroup();
@@ -681,7 +681,7 @@ void MyAvatar::loadData() { · 19 unmodified lines
681681 _targetScale = loadSetting(settings, "scale", 1.0f);
682682 setScale(_scale);
683683
684− // The old preferences only stored the face and skeleton URLs, we didn't track if the user wanted to use 1 or 2 urls
684+ // The old preferences only stored the face and skeleton URLs, we didn't track if the user wanted to use 1 or 2 urls
685685 // for their avatar, So we need to attempt to detect this old case and set our new preferences accordingly. If
686686 // the head URL is empty, then we will assume they are using a full url...
687687 bool isOldSettings = !(settings.contains("useFullAvatar") || settings.contains("fullAvatarURL"));
@@ -693,7 +693,7 @@ void MyAvatar::loadData() { · 5 unmodified lines
693693 _headModelName = settings.value("headModelName", DEFAULT_HEAD_MODEL_NAME).toString();
694694 _bodyModelName = settings.value("bodyModelName", DEFAULT_BODY_MODEL_NAME).toString();
695695 _fullAvatarModelName = settings.value("fullAvatarModelName", DEFAULT_FULL_AVATAR_MODEL_NAME).toString();
696−
696+
697697 if (isOldSettings) {
698698 bool assumeFullAvatar = _headURLFromPreferences.isEmpty();
699699 _useFullAvatar = assumeFullAvatar;
@@ -719,14 +719,14 @@ void MyAvatar::loadData() { · 19 unmodified lines
719719 QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString());
720720 _bodyModelName = bodyFST["name"].toString();
721721 }
722−
722+
723723 if (_headURLFromPreferences == DEFAULT_HEAD_MODEL_URL) {
724724 _headModelName = DEFAULT_HEAD_MODEL_NAME;
725725 } else {
726726 QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString());
727727 _headModelName = headFST["name"].toString();
728728 }
729−
729+
730730 _fullAvatarModelName = "Default";
731731 }
732732 }
@@ -736,7 +736,7 @@ void MyAvatar::loadData() { · 3 unmodified lines
736736 } else {
737737 useHeadAndBodyURLs(_headURLFromPreferences, _skeletonURLFromPreferences, _headModelName, _bodyModelName);
738738 }
739−
739+
740740 QVector<AttachmentData> attachmentData;
741741 int attachmentCount = settings.beginReadArray("attachmentData");
742742 for (int i = 0; i < attachmentCount; i++) {
@@ -757,7 +757,7 @@ void MyAvatar::loadData() { · 14 unmodified lines
757757 }
758758 settings.endArray();
759759 setAttachmentData(attachmentData);
760−
760+
761761 int animationCount = settings.beginReadArray("animationHandles");
762762 while (_animationHandles.size() > animationCount) {
763763 _animationHandles.takeLast()->stop();
@@ -780,7 +780,7 @@ void MyAvatar::loadData() { · 16 unmodified lines
780780 handle->setStartAutomatically(settings.value("startAutomatically", true).toBool());
781781 }
782782 settings.endArray();
783−
783+
784784 setDisplayName(settings.value("displayName").toString());
785785
786786 settings.endGroup();
@@ -792,7 +792,7 @@ void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const { · 5 unmodified lines
792792 settings.beginGroup(_skeletonModel.getURL().toString());
793793 settings.beginGroup(attachment.modelURL.toString());
794794 settings.setValue("jointName", attachment.jointName);
795−
795+
796796 settings.beginGroup(attachment.jointName);
797797 settings.setValue("translation_x", attachment.translation.x);
798798 settings.setValue("translation_y", attachment.translation.y);
@@ -802,7 +802,7 @@ void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const { · 3 unmodified lines
802802 settings.setValue("rotation_y", eulers.y);
803803 settings.setValue("rotation_z", eulers.z);
804804 settings.setValue("scale", attachment.scale);
805−
805+
806806 settings.endGroup();
807807 settings.endGroup();
808808 settings.endGroup();
@@ -814,7 +814,7 @@ AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString& · 5 unmodified lines
814814 settings.beginGroup("savedAttachmentData");
815815 settings.beginGroup(_skeletonModel.getURL().toString());
816816 settings.beginGroup(modelURL.toString());
817−
817+
818818 AttachmentData attachment;
819819 attachment.modelURL = modelURL;
820820 if (jointName.isEmpty()) {
@@ -836,18 +836,18 @@ AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString& · 15 unmodified lines
836836 } else {
837837 attachment = AttachmentData();
838838 }
839−
839+
840840 settings.endGroup();
841841 settings.endGroup();
842842 settings.endGroup();
843843 settings.endGroup();
844−
844+
845845 return attachment;
846846 }
847847
848848 int MyAvatar::parseDataAtOffset(const QByteArray& packet, int offset) {
849849 qCDebug(interfaceapp) << "Error: ignoring update packet for MyAvatar"
850− << " packetLength = " << packet.size()
850+ << " packetLength = " << packet.size()
851851 << " offset = " << offset;
852852 // this packet is just bad, so we pretend that we unpacked it ALL
853853 return packet.size() - offset;
@@ -865,14 +865,14 @@ void MyAvatar::updateLookAtTargetAvatar() { · 11 unmodified lines
865865 //
866866 _lookAtTargetAvatar.reset();
867867 _targetAvatarPosition = glm::vec3(0.0f);
868−
868+
869869 glm::vec3 lookForward = getHead()->getFinalOrientationInWorldFrame() * IDENTITY_FRONT;
870870 glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition();
871−
871+
872872 float smallestAngleTo = glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES) / 2.0f;
873873 const float KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR = 1.3f;
874874 const float GREATEST_LOOKING_AT_DISTANCE = 10.0f;
875−
875+
876876 int howManyLookingAtMe = 0;
877877 foreach (const AvatarSharedPointer& avatarPointer, DependencyManager::get<AvatarManager>()->getAvatarHash()) {
878878 Avatar* avatar = static_cast<Avatar*>(avatarPointer.get());
@@ -1004,13 +1004,13 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN · 125 unmodified lines
10041004 }
10051005
10061006 _useFullAvatar = true;
1007−
1007+
10081008 if (_fullAvatarURLFromPreferences != fullAvatarURL) {
10091009 _fullAvatarURLFromPreferences = fullAvatarURL;
10101010 if (modelName.isEmpty()) {
10111011 QVariantHash fullAvatarFST = FSTReader::downloadMapping(_fullAvatarURLFromPreferences.toString());
10121012 _fullAvatarModelName = fullAvatarFST["name"].toString();
1013− } else {
1013+ } else {
10141014 _fullAvatarModelName = modelName;
10151015 }
10161016 }
@@ -1051,7 +1051,7 @@ void MyAvatar::useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, cons · 34 unmodified lines
10511051 if (headName.isEmpty()) {
10521052 QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString());
10531053 _headModelName = headFST["name"].toString();
1054− } else {
1054+ } else {
10551055 _headModelName = headName;
10561056 }
10571057 }
@@ -1061,7 +1061,7 @@ void MyAvatar::useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, cons · 3 unmodified lines
10611061 if (bodyName.isEmpty()) {
10621062 QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString());
10631063 _bodyModelName = bodyFST["name"].toString();
1064− } else {
1064+ } else {
10651065 _bodyModelName = bodyName;
10661066 }
10671067 }
@@ -1092,7 +1092,7 @@ void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) · 24 unmodified lines
10921092 glm::vec3 MyAvatar::getSkeletonPosition() const {
10931093 CameraMode mode = Application::getInstance()->getCamera()->getMode();
10941094 if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) {
1095− // The avatar is rotated PI about the yAxis, so we have to correct for it
1095+ // The avatar is rotated PI about the yAxis, so we have to correct for it
10961096 // to get the skeleton offset contribution in the world-frame.
10971097 const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
10981098 glm::vec3 skeletonOffset = _skeletonOffset;
@@ -1135,9 +1135,9 @@ void MyAvatar::setScriptedMotorVelocity(const glm::vec3& velocity) { · 36 unmodified lines
11351135 }
11361136
11371137 void MyAvatar::setScriptedMotorTimescale(float timescale) {
1138− // we clamp the timescale on the large side (instead of just the low side) to prevent
1138+ // we clamp the timescale on the large side (instead of just the low side) to prevent
11391139 // obnoxiously large values from introducing NaN into avatar's velocity
1140− _scriptedMotorTimescale = glm::clamp(timescale, MIN_SCRIPTED_MOTOR_TIMESCALE,
1140+ _scriptedMotorTimescale = glm::clamp(timescale, MIN_SCRIPTED_MOTOR_TIMESCALE,
11411141 DEFAULT_SCRIPTED_MOTOR_TIMESCALE);
11421142 }
11431143
@@ -1155,14 +1155,14 @@ void MyAvatar::clearScriptableSettings() { · 11 unmodified lines
11551155 clearJointAnimationPriorities();
11561156 _scriptedMotorVelocity = glm::vec3(0.0f);
11571157 _scriptedMotorTimescale = DEFAULT_SCRIPTED_MOTOR_TIMESCALE;
1158−}
1158+}
11591159
11601160 void MyAvatar::attach(const QString& modelURL, const QString& jointName, const glm::vec3& translation,
11611161 const glm::quat& rotation, float scale, bool allowDuplicates, bool useSaved) {
1162− if (QThread::currentThread() != thread()) {
1162+ if (QThread::currentThread() != thread()) {
11631163 Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved);
11641164 return;
1165− }
1165+ }
11661166 if (useSaved) {
11671167 AttachmentData attachment = loadAttachmentData(modelURL, jointName);
11681168 if (attachment.isValid()) {
@@ -1199,7 +1199,7 @@ const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f; · 30 unmodified lines
11991199
12001200 bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const {
12011201 const Head* head = getHead();
1202− return (renderArgs->_renderMode != RenderArgs::NORMAL_RENDER_MODE) || (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON) ||
1202+ return (renderArgs->_renderMode != RenderArgs::NORMAL_RENDER_MODE) || (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON) ||
12031203 (glm::length(cameraPosition - head->getEyePosition()) > RENDER_HEAD_CUTOFF_DISTANCE * _scale);
12041204 }
12051205
@@ -1230,10 +1230,10 @@ void MyAvatar::updateOrientation(float deltaTime) { · 24 unmodified lines
12301230
12311231 //Invert yaw and roll when in mirror mode
12321232 if (Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_MIRROR) {
1233− YAW(euler) *= -1.0;
1234− ROLL(euler) *= -1.0;
1233+ YAW(euler) *= -1.0f;
1234+ ROLL(euler) *= -1.0f;
12351235 }
1236−
1236+
12371237 Head* head = getHead();
12381238 head->setBaseYaw(YAW(euler));
12391239 head->setBasePitch(PITCH(euler));
@@ -1246,9 +1246,9 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe · 6 unmodified lines
12461246 return localVelocity;
12471247 }
12481248 // compute motor efficiency
1249− // The timescale of the motor is the approximate time it takes for the motor to
1250− // accomplish its intended localVelocity. A short timescale makes the motor strong,
1251− // and a long timescale makes it weak. The value of timescale to use depends
1249+ // The timescale of the motor is the approximate time it takes for the motor to
1250+ // accomplish its intended localVelocity. A short timescale makes the motor strong,
1251+ // and a long timescale makes it weak. The value of timescale to use depends
12521252 // on what the motor is doing:
12531253 //
12541254 // (1) braking --> short timescale (aggressive motor assertion)
@@ -1259,8 +1259,8 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe · 4 unmodified lines
12591259 float MIN_KEYBOARD_BRAKE_SPEED = 0.3f;
12601260 float timescale = MAX_KEYBOARD_MOTOR_TIMESCALE;
12611261 bool isThrust = (glm::length2(_thrust) > EPSILON);
1262− if (_isPushing || isThrust ||
1263− (_scriptedMotorTimescale < MAX_KEYBOARD_MOTOR_TIMESCALE &&
1262+ if (_isPushing || isThrust ||
1263+ (_scriptedMotorTimescale < MAX_KEYBOARD_MOTOR_TIMESCALE &&
12641264 _motionBehaviors | AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED)) {
12651265 // we don't want to brake if something is pushing the avatar around
12661266 timescale = _keyboardMotorTimescale;
@@ -1277,18 +1277,18 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe · 10 unmodified lines
12771277 float motorEfficiency = glm::clamp(deltaTime / timescale, 0.0f, 1.0f);
12781278
12791279 glm::vec3 newLocalVelocity = localVelocity;
1280− float keyboardInput = fabsf(_driveKeys[FWD] - _driveKeys[BACK]) +
1281− (fabsf(_driveKeys[RIGHT] - _driveKeys[LEFT])) +
1280+ float keyboardInput = fabsf(_driveKeys[FWD] - _driveKeys[BACK]) +
1281+ (fabsf(_driveKeys[RIGHT] - _driveKeys[LEFT])) +
12821282 fabsf(_driveKeys[UP] - _driveKeys[DOWN]);
12831283 if (keyboardInput) {
12841284 // Compute keyboard input
12851285 glm::vec3 front = (_driveKeys[FWD] - _driveKeys[BACK]) * IDENTITY_FRONT;
12861286 glm::vec3 right = (_driveKeys[RIGHT] - _driveKeys[LEFT]) * IDENTITY_RIGHT;
12871287 glm::vec3 up = (_driveKeys[UP] - _driveKeys[DOWN]) * IDENTITY_UP;
1288−
1288+
12891289 glm::vec3 direction = front + right + up;
12901290 float directionLength = glm::length(direction);
1291−
1291+
12921292 // Compute motor magnitude
12931293 if (directionLength > EPSILON) {
12941294 direction /= directionLength;
@@ -1318,7 +1318,7 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe · 23 unmodified lines
13181318 motorEfficiency = glm::clamp(deltaTime / WALK_ACCELERATION_TIMESCALE, 0.0f, 1.0f);
13191319 }
13201320 _isPushing = true;
1321− }
1321+ }
13221322 newLocalVelocity = localVelocity + motorEfficiency * (_keyboardMotorVelocity - localVelocity);
13231323 } else {
13241324 _keyboardMotorVelocity = glm::vec3(0.0f);
@@ -1382,13 +1382,13 @@ void MyAvatar::updatePosition(float deltaTime) { · 57 unmodified lines
13821382 _targetVelocity *= MAX_AVATAR_SPEED / speed;
13831383 speed = MAX_AVATAR_SPEED;
13841384 }
1385−
1385+
13861386 if (speed > MIN_AVATAR_SPEED && !_characterController.isEnabled()) {
13871387 // update position ourselves
13881388 applyPositionDelta(deltaTime * _targetVelocity);
13891389 measureMotionDerivatives(deltaTime);
13901390 } // else physics will move avatar later
1391−
1391+
13921392 // update _moving flag based on speed
13931393 const float MOVING_SPEED_THRESHOLD = 0.01f;
13941394 _moving = speed > MOVING_SPEED_THRESHOLD;
@@ -1405,7 +1405,7 @@ bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float · 10 unmodified lines
14051405 float xzDistance = sqrt(positionBA.x * positionBA.x + positionBA.z * positionBA.z);
14061406 if (xzDistance < (radiusA + radiusB)) {
14071407 float yDistance = fabs(positionBA.y);
1408− float halfHeights = 0.5 * (heightA + heightB);
1408+ float halfHeights = 0.5f * (heightA + heightB);
14091409 if (yDistance < halfHeights) {
14101410 // cylinders collide
14111411 if (xzDistance > 0.0f) {
@@ -1448,60 +1448,60 @@ void MyAvatar::maybeUpdateBillboard() { · 36 unmodified lines
14481448 }
14491449 gpu::Context context(new gpu::GLBackend());
14501450 RenderArgs renderArgs(&context);
1451− QImage image = Application::getInstance()->renderAvatarBillboard(&renderArgs);
1451+ QImage image = qApp->renderAvatarBillboard(&renderArgs);
14521452 _billboard.clear();
14531453 QBuffer buffer(&_billboard);
14541454 buffer.open(QIODevice::WriteOnly);
14551455 image.save(&buffer, "PNG");
14561456 _billboardValid = true;
1457−
1457+
14581458 sendBillboardPacket();
14591459 }
14601460
14611461 void MyAvatar::increaseSize() {
14621462 if ((1.0f + SCALING_RATIO) * _targetScale < MAX_AVATAR_SCALE) {
14631463 _targetScale *= (1.0f + SCALING_RATIO);
1464− qCDebug(interfaceapp, "Changed scale to %f", _targetScale);
1464+ qCDebug(interfaceapp, "Changed scale to %f", (double)_targetScale);
14651465 }
14661466 }
14671467
14681468 void MyAvatar::decreaseSize() {
14691469 if (MIN_AVATAR_SCALE < (1.0f - SCALING_RATIO) * _targetScale) {
14701470 _targetScale *= (1.0f - SCALING_RATIO);
1471− qCDebug(interfaceapp, "Changed scale to %f", _targetScale);
1471+ qCDebug(interfaceapp, "Changed scale to %f", (double)_targetScale);
14721472 }
14731473 }
14741474
14751475 void MyAvatar::resetSize() {
14761476 _targetScale = 1.0f;
1477− qCDebug(interfaceapp, "Reseted scale to %f", _targetScale);
1477+ qCDebug(interfaceapp, "Reseted scale to %f", (double)_targetScale);
14781478 }
14791479
14801480 void MyAvatar::goToLocation(const glm::vec3& newPosition,
14811481 bool hasOrientation, const glm::quat& newOrientation,
14821482 bool shouldFaceLocation) {
1483−
1483+
14841484 qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - moving to " << newPosition.x << ", "
14851485 << newPosition.y << ", " << newPosition.z;
1486−
1486+
14871487 glm::vec3 shiftedPosition = newPosition;
1488−
1488+
14891489 if (hasOrientation) {
14901490 qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - new orientation is "
14911491 << newOrientation.x << ", " << newOrientation.y << ", " << newOrientation.z << ", " << newOrientation.w;
1492−
1492+
14931493 // orient the user to face the target
14941494 glm::quat quatOrientation = newOrientation;
1495−
1495+
14961496 if (shouldFaceLocation) {
1497−
1497+
14981498 quatOrientation = newOrientation * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
1499−
1499+
15001500 // move the user a couple units away
15011501 const float DISTANCE_TO_USER = 2.0f;
15021502 shiftedPosition = newPosition - quatOrientation * IDENTITY_FRONT * DISTANCE_TO_USER;
15031503 }
1504−
1504+
15051505 setOrientation(quatOrientation);
15061506 }
15071507
@@ -1547,7 +1547,6 @@ void MyAvatar::renderLaserPointers() { · 39 unmodified lines
15471547
15481548 //Gets the tip position for the laser pointer
15491549 glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) {
1550− const ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay();
15511550 glm::vec3 direction = glm::normalize(palm->getTipPosition() - palm->getPosition());
15521551
15531552 glm::vec3 position = palm->getPosition();
@@ -1556,7 +1555,8 @@ glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) { · 2 unmodified lines
15561555
15571556
15581557 glm::vec3 result;
1559− if (applicationOverlay.calculateRayUICollisionPoint(position, direction, result)) {
1558+ const auto& compositor = qApp->getApplicationCompositor();
1559+ if (compositor.calculateRayUICollisionPoint(position, direction, result)) {
15601560 return result;
15611561 }
15621562
@@ -1569,8 +1569,8 @@ void MyAvatar::clearDriveKeys() { · 6 unmodified lines
15691569 }
15701570 }
15711571
1572−void MyAvatar::relayDriveKeysToCharacterController() {
1572+void MyAvatar::relayDriveKeysToCharacterController() {
15731573 if (_driveKeys[UP] > 0.0f) {
1574− _characterController.jump();
1574+ _characterController.jump();
15751575 }
15761576 }
interface/src/avatar/MyAvatar.h+1−1
@@ -90,7 +90,7 @@ public: · 89 unmodified lines
9090
9191 void relayDriveKeysToCharacterController();
9292
93− bool isMyAvatar() { return true; }
93+ bool isMyAvatar() const { return true; }
9494
9595 bool isLookingAtLeftEye();
9696
interface/src/devices/CameraToolBox.cpp+0−121
@@ -1,121 +0,0 @@
1−//
2−// CameraToolBox.cpp
3−// interface/src/devices
4−//
5−// Created by David Rowe on 30 Apr 2015.
6−// Copyright 2015 High Fidelity, Inc.
7−//
8−// Distributed under the Apache License, Version 2.0.
9−// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10−//
11−
12−#include "InterfaceConfig.h"
13−
14−#include <GLCanvas.h>
15−#include <PathUtils.h>
16−
17−#include "gpu/GLBackend.h"
18−#include "Application.h"
19−#include "CameraToolBox.h"
20−#include "FaceTracker.h"
21−
22−
23−CameraToolBox::CameraToolBox() :
24− _iconPulseTimeReference(usecTimestampNow()),
25− _doubleClickTimer(NULL)
26−{
27−}
28−
29−CameraToolBox::~CameraToolBox() {
30− if (_doubleClickTimer) {
31− _doubleClickTimer->stop();
32− delete _doubleClickTimer;
33− }
34−}
35−
36−bool CameraToolBox::mousePressEvent(int x, int y) {
37− if (_iconBounds.contains(x, y)) {
38− if (!_doubleClickTimer) {
39− // Toggle mute after waiting to check that it's not a double-click.
40− const int DOUBLE_CLICK_WAIT = 200; // ms
41− _doubleClickTimer = new QTimer(this);
42− connect(_doubleClickTimer, SIGNAL(timeout()), this, SLOT(toggleMute()));
43− _doubleClickTimer->setSingleShot(true);
44− _doubleClickTimer->setInterval(DOUBLE_CLICK_WAIT);
45− _doubleClickTimer->start();
46− }
47− return true;
48− }
49− return false;
50−}
51−
52−bool CameraToolBox::mouseDoublePressEvent(int x, int y) {
53− if (_iconBounds.contains(x, y)) {
54− if (_doubleClickTimer) {
55− _doubleClickTimer->stop();
56− delete _doubleClickTimer;
57− _doubleClickTimer = NULL;
58− }
59− Application::getInstance()->resetSensors();
60− return true;
61− }
62− return false;
63−}
64−
65−void CameraToolBox::toggleMute() {
66− delete _doubleClickTimer;
67− _doubleClickTimer = NULL;
68−
69− FaceTracker* faceTracker = Application::getInstance()->getSelectedFaceTracker();
70− if (faceTracker) {
71− faceTracker->toggleMute();
72− }
73−}
74−
75−void CameraToolBox::render(int x, int y, bool boxed) {
76− glEnable(GL_TEXTURE_2D);
77−
78− if (!_enabledTexture) {
79− _enabledTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/face.svg");
80− }
81− if (!_mutedTexture) {
82− _mutedTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/face-mute.svg");
83− }
84−
85− const int MUTE_ICON_SIZE = 24;
86− _iconBounds = QRect(x, y, MUTE_ICON_SIZE, MUTE_ICON_SIZE);
87− float iconColor = 1.0f;
88− if (!Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking)) {
89− glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_enabledTexture));
90− } else {
91− glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_mutedTexture));
92−
93− // Make muted icon pulsate
94− static const float PULSE_MIN = 0.4f;
95− static const float PULSE_MAX = 1.0f;
96− static const float PULSE_FREQUENCY = 1.0f; // in Hz
97− qint64 now = usecTimestampNow();
98− if (now - _iconPulseTimeReference > (qint64)USECS_PER_SECOND) {
99− // Prevents t from getting too big, which would diminish glm::cos precision
100− _iconPulseTimeReference = now - ((now - _iconPulseTimeReference) % USECS_PER_SECOND);
101− }
102− float t = (float)(now - _iconPulseTimeReference) / (float)USECS_PER_SECOND;
103− float pulseFactor = (glm::cos(t * PULSE_FREQUENCY * 2.0f * PI) + 1.0f) / 2.0f;
104− iconColor = PULSE_MIN + (PULSE_MAX - PULSE_MIN) * pulseFactor;
105− }
106−
107− glm::vec4 quadColor(iconColor, iconColor, iconColor, 1.0f);
108−
109− glm::vec2 topLeft(_iconBounds.left(), _iconBounds.top());
110− glm::vec2 bottomRight(_iconBounds.right(), _iconBounds.bottom());
111− glm::vec2 texCoordTopLeft(1,1);
112− glm::vec2 texCoordBottomRight(0,0);
113−
114− if (_boxQuadID == GeometryCache::UNKNOWN_ID) {
115− _boxQuadID = DependencyManager::get<GeometryCache>()->allocateID();
116− }
117−
118− DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor, _boxQuadID);
119−
120− glDisable(GL_TEXTURE_2D);
121−}
interface/src/devices/CameraToolBox.h+0−45
@@ -1,45 +0,0 @@
1−//
2−// CameraToolBox.h
3−// interface/src/devices
4−//
5−// Created by David Rowe on 30 Apr 2015.
6−// Copyright 2015 High Fidelity, Inc.
7−//
8−// Distributed under the Apache License, Version 2.0.
9−// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10−//
11−
12−#ifndef hifi_CameraToolBox_h
13−#define hifi_CameraToolBox_h
14−
15−#include <QObject>
16−
17−#include <DependencyManager.h>
18−#include <GeometryCache.h>
19−
20−class CameraToolBox : public QObject, public Dependency {
21− Q_OBJECT
22− SINGLETON_DEPENDENCY
23−
24−public:
25− void render(int x, int y, bool boxed);
26− bool mousePressEvent(int x, int y);
27− bool mouseDoublePressEvent(int x, int y);
28−
29−protected:
30− CameraToolBox();
31− ~CameraToolBox();
32−
33−private slots:
34− void toggleMute();
35−
36−private:
37− gpu::TexturePointer _enabledTexture;
38− gpu::TexturePointer _mutedTexture;
39− int _boxQuadID = GeometryCache::UNKNOWN_ID;
40− QRect _iconBounds;
41− qint64 _iconPulseTimeReference = 0;
42− QTimer* _doubleClickTimer;
43−};
44−
45−#endif // hifi_CameraToolBox_h
interface/src/devices/DdeFaceTracker.cpp+6−5
@@ -415,7 +415,7 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { · 414 unmodified lines
415415 float browUp = _coefficients[_browUpCenterIndex];
416416 if (isFiltering) {
417417 const float BROW_VELOCITY_FILTER_STRENGTH = 0.5f;
418− float velocity = fabs(browUp - _lastBrowUp) / _averageMessageTime;
418+ float velocity = fabsf(browUp - _lastBrowUp) / _averageMessageTime;
419419 float velocityFilter = glm::clamp(velocity * BROW_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f);
420420 _filteredBrowUp = velocityFilter * browUp + (1.0f - velocityFilter) * _filteredBrowUp;
421421 _lastBrowUp = browUp;
@@ -438,11 +438,12 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { · 16 unmodified lines
438438
439439 // Velocity filter EyeBlink values
440440 const float DDE_EYEBLINK_SCALE = 3.0f;
441− float eyeBlinks[] = { DDE_EYEBLINK_SCALE * _coefficients[_leftBlinkIndex], DDE_EYEBLINK_SCALE * _coefficients[_rightBlinkIndex] };
441+ float eyeBlinks[] = { DDE_EYEBLINK_SCALE * _coefficients[_leftBlinkIndex],
442+ DDE_EYEBLINK_SCALE * _coefficients[_rightBlinkIndex] };
442443 if (isFiltering) {
443444 const float BLINK_VELOCITY_FILTER_STRENGTH = 0.3f;
444445 for (int i = 0; i < 2; i++) {
445− float velocity = fabs(eyeBlinks[i] - _lastEyeBlinks[i]) / _averageMessageTime;
446+ float velocity = fabsf(eyeBlinks[i] - _lastEyeBlinks[i]) / _averageMessageTime;
446447 float velocityFilter = glm::clamp(velocity * BLINK_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f);
447448 _filteredEyeBlinks[i] = velocityFilter * eyeBlinks[i] + (1.0f - velocityFilter) * _filteredEyeBlinks[i];
448449 _lastEyeBlinks[i] = eyeBlinks[i];
@@ -479,9 +480,9 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { · 30 unmodified lines
479480 if (_eyeStates[i] == EYE_CLOSING) {
480481 // Close eyelid until it's fully closed
481482 float closingValue = _lastEyeCoefficients[i] + EYELID_MOVEMENT_RATE * _averageMessageTime;
482− if (closingValue >= 1.0) {
483+ if (closingValue >= 1.0f) {
483484 _eyeStates[i] = EYE_CLOSED;
484− eyeCoefficients[i] = 1.0;
485+ eyeCoefficients[i] = 1.0f;
485486 } else {
486487 eyeCoefficients[i] = closingValue;
487488 }
interface/src/devices/OculusManager.cpp+469−436
@@ -11,13 +11,13 @@ · 10 unmodified lines
1111 //
1212
1313 #include "InterfaceConfig.h"
14−
1514 #include "OculusManager.h"
1615 #include "ui/overlays/Text3DOverlay.h"
1716
17+#include <CursorManager.h>
1818 #include <QDesktopWidget>
1919 #include <QGuiApplication>
20−#include <QScreen>
20+#include <QScreen>
2121 #include <QOpenGLTimerQuery>
2222
2323 #include <glm/glm.hpp>
@@ -25,6 +25,9 @@ · 1 unmodified line
2525 #include <avatar/AvatarManager.h>
2626 #include <avatar/MyAvatar.h>
2727 #include <GlowEffect.h>
28+#include <GlWindow.h>
29+#include <gpu/GLBackend.h>
30+#include <OglplusHelpers.h>
2831 #include <PathUtils.h>
2932 #include <SharedUtil.h>
3033 #include <UserActivityLogger.h>
@@ -34,8 +37,6 @@ · 3 unmodified lines
3437 #include "InterfaceLogging.h"
3538 #include "Application.h"
3639
37−#include <gpu/GLBackend.h>
38−
3940 template <typename Function>
4041 void for_each_eye(Function function) {
4142 for (ovrEyeType eye = ovrEyeType::ovrEye_Left;
@@ -52,202 +53,413 @@ void for_each_eye(const ovrHmd & hmd, Function function) { · 10 unmodified lines
5253 function(eye);
5354 }
5455 }
56+enum CalibrationState {
57+ UNCALIBRATED,
58+ WAITING_FOR_DELTA,
59+ WAITING_FOR_ZERO,
60+ WAITING_FOR_ZERO_HELD,
61+ CALIBRATED
62+};
63+
64+inline glm::mat4 toGlm(const ovrMatrix4f & om) {
65+ return glm::transpose(glm::make_mat4(&om.M[0][0]));
66+}
5567
56−#ifdef OVR_CLIENT_DISTORTION
57−ProgramObject OculusManager::_program;
58−int OculusManager::_textureLocation;
59−int OculusManager::_eyeToSourceUVScaleLocation;
60−int OculusManager::_eyeToSourceUVOffsetLocation;
61−int OculusManager::_eyeRotationStartLocation;
62−int OculusManager::_eyeRotationEndLocation;
63−int OculusManager::_positionAttributeLocation;
64−int OculusManager::_colorAttributeLocation;
65−int OculusManager::_texCoord0AttributeLocation;
66−int OculusManager::_texCoord1AttributeLocation;
67−int OculusManager::_texCoord2AttributeLocation;
68−ovrVector2f OculusManager::_UVScaleOffset[ovrEye_Count][2];
69−GLuint OculusManager::_vertices[ovrEye_Count] = { 0, 0 };
70−GLuint OculusManager::_indices[ovrEye_Count] = { 0, 0 };
71−GLsizei OculusManager::_meshSize[ovrEye_Count] = { 0, 0 };
72−ovrFrameTiming OculusManager::_hmdFrameTiming;
73−bool OculusManager::_programInitialized = false;
74−#endif
68+inline glm::mat4 toGlm(const ovrFovPort & fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) {
69+ return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true));
70+}
7571
76−ovrTexture OculusManager::_eyeTextures[ovrEye_Count];
77−bool OculusManager::_isConnected = false;
78−ovrHmd OculusManager::_ovrHmd;
79−ovrFovPort OculusManager::_eyeFov[ovrEye_Count];
80−ovrVector3f OculusManager::_eyeOffset[ovrEye_Count];
81−ovrEyeRenderDesc OculusManager::_eyeRenderDesc[ovrEye_Count];
82−ovrSizei OculusManager::_renderTargetSize;
83−glm::mat4 OculusManager::_eyeProjection[ovrEye_Count];
84−unsigned int OculusManager::_frameIndex = 0;
85−bool OculusManager::_frameTimingActive = false;
86−Camera* OculusManager::_camera = NULL;
87−ovrEyeType OculusManager::_activeEye = ovrEye_Count;
88−bool OculusManager::_hswDismissed = false;
89−
90−float OculusManager::CALIBRATION_DELTA_MINIMUM_LENGTH = 0.02f;
91−float OculusManager::CALIBRATION_DELTA_MINIMUM_ANGLE = 5.0f * RADIANS_PER_DEGREE;
92−float OculusManager::CALIBRATION_ZERO_MAXIMUM_LENGTH = 0.01f;
93−float OculusManager::CALIBRATION_ZERO_MAXIMUM_ANGLE = 2.0f * RADIANS_PER_DEGREE;
94−quint64 OculusManager::CALIBRATION_ZERO_HOLD_TIME = 3000000; // usec
95−float OculusManager::CALIBRATION_MESSAGE_DISTANCE = 2.5f;
96−OculusManager::CalibrationState OculusManager::_calibrationState;
97−glm::vec3 OculusManager::_calibrationPosition;
98−glm::quat OculusManager::_calibrationOrientation;
99−quint64 OculusManager::_calibrationStartTime;
100−int OculusManager::_calibrationMessage = 0;
101−glm::vec3 OculusManager::_eyePositions[ovrEye_Count];
102−// TODO expose this as a developer toggle
103−bool OculusManager::_eyePerFrameMode = false;
104−ovrEyeType OculusManager::_lastEyeRendered = ovrEye_Count;
105−ovrSizei OculusManager::_recommendedTexSize = { 0, 0 };
106−float OculusManager::_offscreenRenderScale = 1.0;
72+inline glm::vec3 toGlm(const ovrVector3f & ov) {
73+ return glm::make_vec3(&ov.x);
74+}
10775
76+inline glm::vec2 toGlm(const ovrVector2f & ov) {
77+ return glm::make_vec2(&ov.x);
78+}
10879
109−void OculusManager::initSdk() {
110− ovr_Initialize();
111− _ovrHmd = ovrHmd_Create(0);
112− if (!_ovrHmd) {
113− _ovrHmd = ovrHmd_CreateDebug(ovrHmd_DK2);
114− }
80+inline glm::ivec2 toGlm(const ovrVector2i & ov) {
81+ return glm::ivec2(ov.x, ov.y);
11582 }
11683
117−void OculusManager::shutdownSdk() {
118− if (_ovrHmd) {
119− ovrHmd_Destroy(_ovrHmd);
120− _ovrHmd = nullptr;
121− ovr_Shutdown();
122− }
84+inline glm::uvec2 toGlm(const ovrSizei & ov) {
85+ return glm::uvec2(ov.w, ov.h);
12386 }
12487
125−void OculusManager::init() {
126−#ifdef OVR_DIRECT_MODE
127− initSdk();
128−#endif
88+inline glm::quat toGlm(const ovrQuatf & oq) {
89+ return glm::make_quat(&oq.x);
12990 }
13091
131−void OculusManager::deinit() {
132−#ifdef OVR_DIRECT_MODE
133− shutdownSdk();
134−#endif
92+inline glm::mat4 toGlm(const ovrPosef & op) {
93+ glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation));
94+ glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position));
95+ return translation * orientation;
13596 }
13697
137−void OculusManager::connect() {
138−#ifndef OVR_DIRECT_MODE
139− initSdk();
140−#endif
141− _calibrationState = UNCALIBRATED;
142− qCDebug(interfaceapp) << "Oculus SDK" << OVR_VERSION_STRING;
143− if (_ovrHmd) {
144− if (!_isConnected) {
145− UserActivityLogger::getInstance().connectedDevice("hmd", "oculus");
98+inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) {
99+ ovrMatrix4f result;
100+ glm::mat4 transposed(glm::transpose(m));
101+ memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16);
102+ return result;
103+}
104+
105+inline ovrVector3f ovrFromGlm(const glm::vec3 & v) {
106+ return{ v.x, v.y, v.z };
107+}
108+
109+inline ovrVector2f ovrFromGlm(const glm::vec2 & v) {
110+ return{ v.x, v.y };
111+}
112+
113+inline ovrSizei ovrFromGlm(const glm::uvec2 & v) {
114+ return{ (int)v.x, (int)v.y };
115+}
116+
117+inline ovrQuatf ovrFromGlm(const glm::quat & q) {
118+ return{ q.x, q.y, q.z, q.w };
119+}
120+
121+
122+
123+#ifdef Q_OS_WIN
124+
125+// A base class for FBO wrappers that need to use the Oculus C
126+// API to manage textures via ovrHmd_CreateSwapTextureSetGL,
127+// ovrHmd_CreateMirrorTextureGL, etc
128+template <typename C>
129+struct RiftFramebufferWrapper : public FramebufferWrapper<C, char> {
130+ ovrHmd hmd;
131+ RiftFramebufferWrapper(const ovrHmd & hmd) : hmd(hmd) {
132+ color = 0;
133+ depth = 0;
134+ };
135+
136+ void Resize(const uvec2 & size) {
137+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oglplus::GetName(fbo));
138+ glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
139+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
140+ this->size = size;
141+ initColor();
142+ initDone();
143+ }
144+
145+protected:
146+ virtual void initDepth() override final {
147+ }
148+};
149+
150+// A wrapper for constructing and using a swap texture set,
151+// where each frame you draw to a texture via the FBO,
152+// then submit it and increment to the next texture.
153+// The Oculus SDK manages the creation and destruction of
154+// the textures
155+struct SwapFramebufferWrapper : public RiftFramebufferWrapper<ovrSwapTextureSet*> {
156+ SwapFramebufferWrapper(const ovrHmd & hmd)
157+ : RiftFramebufferWrapper(hmd) {
158+ }
159+
160+ ~SwapFramebufferWrapper() {
161+ if (color) {
162+ ovrHmd_DestroySwapTextureSet(hmd, color);
163+ color = nullptr;
146164 }
147− _isConnected = true;
148−
149− for_each_eye([&](ovrEyeType eye) {
150− _eyeFov[eye] = _ovrHmd->DefaultEyeFov[eye];
151− });
152−
153− ovrGLConfig cfg;
154− memset(&cfg, 0, sizeof(cfg));
155− cfg.OGL.Header.API = ovrRenderAPI_OpenGL;
156− cfg.OGL.Header.BackBufferSize = _ovrHmd->Resolution;
157− cfg.OGL.Header.Multisample = 1;
158−
159− int distortionCaps = 0
160− | ovrDistortionCap_Vignette
161− | ovrDistortionCap_Overdrive
162− | ovrDistortionCap_TimeWarp;
163−
164− int configResult = ovrHmd_ConfigureRendering(_ovrHmd, &cfg.Config,
165− distortionCaps, _eyeFov, _eyeRenderDesc);
166− assert(configResult);
167−
168−
169− _recommendedTexSize = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left, _eyeFov[ovrEye_Left], 1.0f);
170− _renderTargetSize = { _recommendedTexSize.w * 2, _recommendedTexSize.h };
171− for_each_eye([&](ovrEyeType eye) {
172− //Get texture size
173− _eyeTextures[eye].Header.API = ovrRenderAPI_OpenGL;
174− _eyeTextures[eye].Header.TextureSize = _renderTargetSize;
175− _eyeTextures[eye].Header.RenderViewport.Pos = { 0, 0 };
176− });
177− _eyeTextures[ovrEye_Right].Header.RenderViewport.Pos.x = _recommendedTexSize.w;
178−
179− ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction);
180−
181− ovrHmd_ConfigureTracking(_ovrHmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position |
182− ovrTrackingCap_MagYawCorrection,
183− ovrTrackingCap_Orientation);
184−
185− if (!_camera) {
186− _camera = new Camera;
187− configureCamera(*_camera); // no need to use screen dimensions; they're ignored
165+ }
166+
167+ void Increment() {
168+ ++color->CurrentIndex;
169+ color->CurrentIndex %= color->TextureCount;
170+ }
171+
172+protected:
173+ virtual void initColor() override {
174+ if (color) {
175+ ovrHmd_DestroySwapTextureSet(hmd, color);
176+ color = nullptr;
177+ }
178+
179+ ovrResult result = ovrHmd_CreateSwapTextureSetGL(hmd, GL_RGBA, size.x, size.y, &color);
180+ Q_ASSERT(OVR_SUCCESS(result));
181+
182+ for (int i = 0; i < color->TextureCount; ++i) {
183+ ovrGLTexture& ovrTex = (ovrGLTexture&)color->Textures[i];
184+ glBindTexture(GL_TEXTURE_2D, ovrTex.OGL.TexId);
185+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
186+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
187+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
188+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
189+ }
190+ glBindTexture(GL_TEXTURE_2D, 0);
191+ }
192+
193+ virtual void initDone() override {
194+ }
195+
196+ virtual void onBind(oglplus::Framebuffer::Target target) override {
197+ ovrGLTexture& tex = (ovrGLTexture&)(color->Textures[color->CurrentIndex]);
198+ glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.OGL.TexId, 0);
199+ }
200+
201+ virtual void onUnbind(oglplus::Framebuffer::Target target) override {
202+ glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
203+ }
204+};
205+
206+
207+// We use a FBO to wrap the mirror texture because it makes it easier to
208+// render to the screen via glBlitFramebuffer
209+struct MirrorFramebufferWrapper : public RiftFramebufferWrapper<ovrGLTexture*> {
210+ MirrorFramebufferWrapper(const ovrHmd & hmd)
211+ : RiftFramebufferWrapper(hmd) {
212+ }
213+
214+ virtual ~MirrorFramebufferWrapper() {
215+ if (color) {
216+ ovrHmd_DestroyMirrorTexture(hmd, (ovrTexture*)color);
217+ color = nullptr;
188218 }
189−#ifdef OVR_CLIENT_DISTORTION
190− if (!_programInitialized) {
191− // Shader program
192− _programInitialized = true;
193− _program.addShaderFromSourceFile(QGLShader::Vertex, PathUtils::resourcesPath() + "shaders/oculus.vert");
194− _program.addShaderFromSourceFile(QGLShader::Fragment, PathUtils::resourcesPath() + "shaders/oculus.frag");
195− _program.link();
196−
197− // Uniforms
198− _textureLocation = _program.uniformLocation("texture");
199− _eyeToSourceUVScaleLocation = _program.uniformLocation("EyeToSourceUVScale");
200− _eyeToSourceUVOffsetLocation = _program.uniformLocation("EyeToSourceUVOffset");
201− _eyeRotationStartLocation = _program.uniformLocation("EyeRotationStart");
202− _eyeRotationEndLocation = _program.uniformLocation("EyeRotationEnd");
203−
204− // Attributes
205− _positionAttributeLocation = _program.attributeLocation("position");
206− _colorAttributeLocation = _program.attributeLocation("color");
207− _texCoord0AttributeLocation = _program.attributeLocation("texCoord0");
208− _texCoord1AttributeLocation = _program.attributeLocation("texCoord1");
209− _texCoord2AttributeLocation = _program.attributeLocation("texCoord2");
219+ }
220+
221+private:
222+ void initColor() override {
223+ if (color) {
224+ ovrHmd_DestroyMirrorTexture(hmd, (ovrTexture*)color);
225+ color = nullptr;
210226 }
227+ ovrResult result = ovrHmd_CreateMirrorTextureGL(hmd, GL_RGBA, size.x, size.y, (ovrTexture**)&color);
228+ Q_ASSERT(OVR_SUCCESS(result));
229+ }
230+
231+ void initDone() override {
232+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oglplus::GetName(fbo));
233+ glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color->OGL.TexId, 0);
234+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
235+ }
236+};
237+
238+static SwapFramebufferWrapper* _swapFbo{ nullptr };
239+static MirrorFramebufferWrapper* _mirrorFbo{ nullptr };
240+static ovrLayerEyeFov _sceneLayer;
241+
242+#else
243+
244+static ovrTexture _eyeTextures[ovrEye_Count];
245+static GlWindow* _outputWindow{ nullptr };
211246
212− //Generate the distortion VBOs
213− generateDistortionMesh();
214247 #endif
215− } else {
248+
249+static bool _isConnected = false;
250+static ovrHmd _ovrHmd;
251+static ovrFovPort _eyeFov[ovrEye_Count];
252+static ovrVector3f _eyeOffset[ovrEye_Count];
253+static ovrEyeRenderDesc _eyeRenderDesc[ovrEye_Count];
254+static ovrSizei _renderTargetSize;
255+static glm::mat4 _eyeProjection[ovrEye_Count];
256+static unsigned int _frameIndex = 0;
257+static bool _frameTimingActive = false;
258+static Camera* _camera = NULL;
259+static ovrEyeType _activeEye = ovrEye_Count;
260+static bool _hswDismissed = false;
261+
262+static const float CALIBRATION_DELTA_MINIMUM_LENGTH = 0.02f;
263+static const float CALIBRATION_DELTA_MINIMUM_ANGLE = 5.0f * RADIANS_PER_DEGREE;
264+static const float CALIBRATION_ZERO_MAXIMUM_LENGTH = 0.01f;
265+static const float CALIBRATION_ZERO_MAXIMUM_ANGLE = 2.0f * RADIANS_PER_DEGREE;
266+static const quint64 CALIBRATION_ZERO_HOLD_TIME = 3000000; // usec
267+static const float CALIBRATION_MESSAGE_DISTANCE = 2.5f;
268+static CalibrationState _calibrationState;
269+static glm::vec3 _calibrationPosition;
270+static glm::quat _calibrationOrientation;
271+static quint64 _calibrationStartTime;
272+static int _calibrationMessage = 0;
273+static glm::vec3 _eyePositions[ovrEye_Count];
274+// TODO expose this as a developer toggle
275+static bool _eyePerFrameMode = false;
276+static ovrEyeType _lastEyeRendered = ovrEye_Count;
277+static ovrSizei _recommendedTexSize = { 0, 0 };
278+static float _offscreenRenderScale = 1.0;
279+static glm::mat4 _combinedProjection;
280+static ovrPosef _eyeRenderPoses[ovrEye_Count];
281+static ovrRecti _eyeViewports[ovrEye_Count];
282+static ovrVector3f _eyeOffsets[ovrEye_Count];
283+
284+glm::vec3 OculusManager::getLeftEyePosition() { return _eyePositions[ovrEye_Left]; }
285+glm::vec3 OculusManager::getRightEyePosition() { return _eyePositions[ovrEye_Right]; }
286+
287+void OculusManager::connect(QOpenGLContext* shareContext) {
288+ qCDebug(interfaceapp) << "Oculus SDK" << OVR_VERSION_STRING;
289+
290+ ovrInitParams initParams; memset(&initParams, 0, sizeof(initParams));
291+
292+#ifdef DEBUG
293+ initParams.Flags |= ovrInit_Debug;
294+#endif
295+
296+ ovr_Initialize(&initParams);
297+
298+#ifdef Q_OS_WIN
299+
300+ ovrResult res = ovrHmd_Create(0, &_ovrHmd);
301+#ifdef DEBUG
302+ if (!OVR_SUCCESS(res)) {
303+ res = ovrHmd_CreateDebug(ovrHmd_DK2, &_ovrHmd);
304+ Q_ASSERT(OVR_SUCCESS(res));
305+ }
306+#endif
307+
308+#else
309+
310+ _ovrHmd = ovrHmd_Create(0);
311+#ifdef DEBUG
312+ if (!_ovrHmd) {
313+ _ovrHmd = ovrHmd_CreateDebug(ovrHmd_DK2);
314+ }
315+#endif
316+
317+#endif
318+
319+ if (!_ovrHmd) {
216320 _isConnected = false;
217−
321+
218322 // we're definitely not in "VR mode" so tell the menu that
219323 Menu::getInstance()->getActionForOption(MenuOption::EnableVRMode)->setChecked(false);
324+ ovr_Shutdown();
325+ return;
326+ }
327+
328+ _calibrationState = UNCALIBRATED;
329+ if (!_isConnected) {
330+ UserActivityLogger::getInstance().connectedDevice("hmd", "oculus");
331+ }
332+ _isConnected = true;
333+
334+ for_each_eye([&](ovrEyeType eye) {
335+ _eyeFov[eye] = _ovrHmd->DefaultEyeFov[eye];
336+ _eyeProjection[eye] = toGlm(ovrMatrix4f_Projection(_eyeFov[eye],
337+ DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded));
338+ ovrEyeRenderDesc erd = ovrHmd_GetRenderDesc(_ovrHmd, eye, _eyeFov[eye]);
339+ _eyeOffsets[eye] = erd.HmdToEyeViewOffset;
340+ });
341+ ovrFovPort combinedFov = _ovrHmd->MaxEyeFov[0];
342+ combinedFov.RightTan = _ovrHmd->MaxEyeFov[1].RightTan;
343+ _combinedProjection = toGlm(ovrMatrix4f_Projection(combinedFov,
344+ DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded));
345+
346+ _recommendedTexSize = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left, _eyeFov[ovrEye_Left], 1.0f);
347+ _renderTargetSize = { _recommendedTexSize.w * 2, _recommendedTexSize.h };
348+
349+#ifdef Q_OS_WIN
350+
351+ _mirrorFbo = new MirrorFramebufferWrapper(_ovrHmd);
352+ _swapFbo = new SwapFramebufferWrapper(_ovrHmd);
353+ _swapFbo->Init(toGlm(_renderTargetSize));
354+ _sceneLayer.ColorTexture[0] = _swapFbo->color;
355+ _sceneLayer.ColorTexture[1] = nullptr;
356+ _sceneLayer.Viewport[0].Pos = { 0, 0 };
357+ _sceneLayer.Viewport[0].Size = _recommendedTexSize;
358+ _sceneLayer.Viewport[1].Pos = { _recommendedTexSize.w, 0 };
359+ _sceneLayer.Viewport[1].Size = _recommendedTexSize;
360+ _sceneLayer.Header.Type = ovrLayerType_EyeFov;
361+ _sceneLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft;
362+ for_each_eye([&](ovrEyeType eye) {
363+ _eyeViewports[eye] = _sceneLayer.Viewport[eye];
364+ _sceneLayer.Fov[eye] = _eyeFov[eye];
365+ });
366+
367+
368+
369+#else
370+ _outputWindow = new GlWindow(shareContext);
371+ _outputWindow->show();
372+// _outputWindow->setFlags(Qt::FramelessWindowHint );
373+// _outputWindow->resize(_ovrHmd->Resolution.w, _ovrHmd->Resolution.h);
374+// _outputWindow->setPosition(_ovrHmd->WindowsPos.x, _ovrHmd->WindowsPos.y);
375+ ivec2 desiredPosition = toGlm(_ovrHmd->WindowsPos);
376+ foreach(QScreen* screen, qGuiApp->screens()) {
377+ ivec2 screenPosition = toGlm(screen->geometry().topLeft());
378+ if (screenPosition == desiredPosition) {
379+ _outputWindow->setScreen(screen);
380+ break;
381+ }
382+ }
383+ _outputWindow->showFullScreen();
384+ _outputWindow->makeCurrent();
385+
386+ ovrGLConfig cfg;
387+ memset(&cfg, 0, sizeof(cfg));
388+ cfg.OGL.Header.API = ovrRenderAPI_OpenGL;
389+ cfg.OGL.Header.BackBufferSize = _ovrHmd->Resolution;
390+ cfg.OGL.Header.Multisample = 0;
391+
392+ int distortionCaps = 0
393+ | ovrDistortionCap_Vignette
394+ | ovrDistortionCap_Overdrive
395+ | ovrDistortionCap_TimeWarp;
396+
397+ int configResult = ovrHmd_ConfigureRendering(_ovrHmd, &cfg.Config,
398+ distortionCaps, _eyeFov, _eyeRenderDesc);
399+ assert(configResult);
400+ _outputWindow->doneCurrent();
401+
402+ for_each_eye([&](ovrEyeType eye) {
403+ //Get texture size
404+ _eyeTextures[eye].Header.API = ovrRenderAPI_OpenGL;
405+ _eyeTextures[eye].Header.TextureSize = _renderTargetSize;
406+ _eyeTextures[eye].Header.RenderViewport.Pos = { 0, 0 };
407+ _eyeTextures[eye].Header.RenderViewport.Size = _renderTargetSize;
408+ _eyeTextures[eye].Header.RenderViewport.Size.w /= 2;
409+ });
410+ _eyeTextures[ovrEye_Right].Header.RenderViewport.Pos.x = _recommendedTexSize.w;
411+ for_each_eye([&](ovrEyeType eye) {
412+ _eyeViewports[eye] = _eyeTextures[eye].Header.RenderViewport;
413+ });
414+#endif
415+
416+ ovrHmd_SetEnabledCaps(_ovrHmd,
417+ ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction);
418+
419+ ovrHmd_ConfigureTracking(_ovrHmd,
420+ ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection,
421+ ovrTrackingCap_Orientation);
422+
423+ if (!_camera) {
424+ _camera = new Camera;
425+ configureCamera(*_camera); // no need to use screen dimensions; they're ignored
220426 }
221427 }
222428
223429 //Disconnects and deallocates the OR
224430 void OculusManager::disconnect() {
225431 if (_isConnected) {
432+
433+#ifdef Q_OS_WIN
434+ if (_swapFbo) {
435+ delete _swapFbo;
436+ _swapFbo = nullptr;
437+ }
438+
439+ if (_mirrorFbo) {
440+ delete _mirrorFbo;
441+ _mirrorFbo = nullptr;
442+ }
443+#else
444+ _outputWindow->showNormal();
445+ _outputWindow->deleteLater();
446+ _outputWindow = nullptr;
447+#endif
448+
449+ if (_ovrHmd) {
450+ ovrHmd_Destroy(_ovrHmd);
451+ _ovrHmd = nullptr;
452+ }
453+ ovr_Shutdown();
454+
226455 _isConnected = false;
227456 // Prepare to potentially have to dismiss the HSW again
228457 // if the user re-enables VR
229458 _hswDismissed = false;
230−#ifndef OVR_DIRECT_MODE
231− shutdownSdk();
232−#endif
233−
234−#ifdef OVR_CLIENT_DISTORTION
235− //Free the distortion mesh data
236− for (int i = 0; i < ovrEye_Count; i++) {
237− if (_vertices[i] != 0) {
238− glDeleteBuffers(1, &(_vertices[i]));
239− _vertices[i] = 0;
240− }
241− if (_indices[i] != 0) {
242− glDeleteBuffers(1, &(_indices[i]));
243− _indices[i] = 0;
244− }
245− }
246−#endif
247459 }
248460 }
249461
250−void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) {
462+void positionCalibrationBillboard(Text3DOverlay* billboard) {
251463 MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
252464 glm::quat headOrientation = myAvatar->getHeadOrientation();
253465 headOrientation.x = 0;
@@ -258,7 +470,7 @@ void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) { · 4 unmodified lines
258470 billboard->setRotation(headOrientation);
259471 }
260472
261−void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) {
473+void calibrate(const glm::vec3& position, const glm::quat& orientation) {
262474 static QString instructionMessage = "Hold still to calibrate";
263475 static QString progressMessage;
264476 static Text3DOverlay* billboard;
@@ -346,7 +558,7 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { · 81 unmodified lines
346558 break;
347559 default:
348560 break;
349−
561+
350562 }
351563 }
352564
@@ -363,64 +575,9 @@ void OculusManager::abandonCalibration() { · 10 unmodified lines
363575 }
364576 }
365577
366−#ifdef OVR_CLIENT_DISTORTION
367−void OculusManager::generateDistortionMesh() {
368−
369− //Check if we already have the distortion mesh
370− if (_vertices[0] != 0) {
371− printf("WARNING: Tried to generate Oculus distortion mesh twice without freeing the VBOs.");
372− return;
373− }
374−
375− for (int eyeNum = 0; eyeNum < ovrEye_Count; eyeNum++) {
376− // Allocate and generate distortion mesh vertices
377− ovrDistortionMesh meshData;
378− ovrHmd_CreateDistortionMesh(_ovrHmd, _eyeRenderDesc[eyeNum].Eye, _eyeRenderDesc[eyeNum].Fov, _ovrHmd->DistortionCaps, &meshData);
379−
380− // Parse the vertex data and create a render ready vertex buffer
381− DistortionVertex* pVBVerts = new DistortionVertex[meshData.VertexCount];
382− _meshSize[eyeNum] = meshData.IndexCount;
383−
384− // Convert the oculus vertex data to the DistortionVertex format.
385− DistortionVertex* v = pVBVerts;
386− ovrDistortionVertex* ov = meshData.pVertexData;
387− for (unsigned int vertNum = 0; vertNum < meshData.VertexCount; vertNum++) {
388− v->pos.x = ov->ScreenPosNDC.x;
389− v->pos.y = ov->ScreenPosNDC.y;
390− v->texR.x = ov->TanEyeAnglesR.x;
391− v->texR.y = ov->TanEyeAnglesR.y;
392− v->texG.x = ov->TanEyeAnglesG.x;
393− v->texG.y = ov->TanEyeAnglesG.y;
394− v->texB.x = ov->TanEyeAnglesB.x;
395− v->texB.y = ov->TanEyeAnglesB.y;
396− v->color.r = v->color.g = v->color.b = (GLubyte)(ov->VignetteFactor * 255.99f);
397− v->color.a = (GLubyte)(ov->TimeWarpFactor * 255.99f);
398− v++;
399− ov++;
400− }
401−
402− //vertices
403− glGenBuffers(1, &(_vertices[eyeNum]));
404− glBindBuffer(GL_ARRAY_BUFFER, _vertices[eyeNum]);
405− glBufferData(GL_ARRAY_BUFFER, sizeof(DistortionVertex) * meshData.VertexCount, pVBVerts, GL_STATIC_DRAW);
406− glBindBuffer(GL_ARRAY_BUFFER, 0);
407−
408− //indices
409− glGenBuffers(1, &(_indices[eyeNum]));
410− glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indices[eyeNum]);
411− glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short) * meshData.IndexCount, meshData.pIndexData, GL_STATIC_DRAW);
412− glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
413−
414− //Now that we have the VBOs we can get rid of the mesh data
415− delete [] pVBVerts;
416− ovrHmd_DestroyDistortionMesh(&meshData);
417− }
418−
419−}
420−#endif
421578
422579 bool OculusManager::isConnected() {
423− return _isConnected && Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode);
580+ return _isConnected;
424581 }
425582
426583 //Begins the frame timing for oculus prediction purposes
@@ -428,10 +585,6 @@ void OculusManager::beginFrameTiming() { · 1 unmodified line
428585 if (_frameTimingActive) {
429586 printf("WARNING: Called OculusManager::beginFrameTiming() twice in a row, need to call OculusManager::endFrameTiming().");
430587 }
431−
432−#ifdef OVR_CLIENT_DISTORTION
433− _hmdFrameTiming = ovrHmd_BeginFrameTiming(_ovrHmd, _frameIndex);
434−#endif
435588 _frameTimingActive = true;
436589 }
437590
@@ -441,27 +594,18 @@ bool OculusManager::allowSwap() { · 3 unmodified lines
441594
442595 //Ends frame timing
443596 void OculusManager::endFrameTiming() {
444−#ifdef OVR_CLIENT_DISTORTION
445− ovrHmd_EndFrameTiming(_ovrHmd);
446−#endif
447597 _frameIndex++;
448598 _frameTimingActive = false;
449599 }
450600
451601 //Sets the camera FoV and aspect ratio
452602 void OculusManager::configureCamera(Camera& camera) {
453− ovrFovPort fov;
454603 if (_activeEye == ovrEye_Count) {
455604 // When not rendering, provide a FOV encompasing both eyes
456− fov = _eyeFov[0];
457− fov.RightTan = _eyeFov[1].RightTan;
458− } else {
459− // When rendering, provide the exact FOV
460− fov = _eyeFov[_activeEye];
461− }
462− // Convert the FOV to the correct projection matrix
463− glm::mat4 projection = toGlm(ovrMatrix4f_Projection(fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded));
464− camera.setProjection(projection);
605+ camera.setProjection(_combinedProjection);
606+ return;
607+ }
608+ camera.setProjection(_eyeProjection[_activeEye]);
465609 }
466610
467611 //Displays everything for the oculus, frame timing must be active
@@ -473,40 +617,9 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 5 unmodified lines
473617 assert(oldFrameIndex == -1 || (unsigned int)oldFrameIndex == _frameIndex - 1);
474618 oldFrameIndex = _frameIndex;
475619 #endif
476−
477− // Every so often do some additional timing calculations and debug output
478− bool debugFrame = 0 == _frameIndex % 400;
479620
480−#if 0
481− // Try to measure the amount of time taken to do the distortion
482− // (does not seem to work on OSX with SDK based distortion)
483− // FIXME can't use a static object here, because it will cause a crash when the
484− // query attempts deconstruct after the GL context is gone.
485− static bool timerActive = false;
486− static QOpenGLTimerQuery timerQuery;
487− if (!timerQuery.isCreated()) {
488− timerQuery.create();
489− }
490−
491− if (timerActive && timerQuery.isResultAvailable()) {
492− auto result = timerQuery.waitForResult();
493− if (result) { qCDebug(interfaceapp) << "Distortion took " << result << "ns"; };
494− timerActive = false;
495− }
496−#endif
497−
498−#ifdef OVR_DIRECT_MODE
499− static bool attached = false;
500− if (!attached) {
501− attached = true;
502− void * nativeWindowHandle = (void*)(size_t)glCanvas->effectiveWinId();
503− if (nullptr != nativeWindowHandle) {
504− ovrHmd_AttachToWindow(_ovrHmd, nativeWindowHandle, nullptr, nullptr);
505− }
506− }
507−#endif
508−
509−#ifndef OVR_CLIENT_DISTORTION
621+#ifndef Q_OS_WIN
622+
510623 // FIXME: we need a better way of responding to the HSW. In particular
511624 // we need to ensure that it's only displayed once per session, rather than
512625 // every time the user toggles VR mode, and we need to hook it up to actual
@@ -522,7 +635,7 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 9 unmodified lines
522635 }
523636 }
524637 #endif
525−
638+
526639
527640 //beginFrameTiming must be called before display
528641 if (!_frameTimingActive) {
@@ -545,14 +658,14 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 16 unmodified lines
545658
546659 glMatrixMode(GL_MODELVIEW);
547660 glPushMatrix();
548−
661+
549662 glm::quat orientation;
550663 glm::vec3 trackerPosition;
551664 auto deviceSize = qApp->getDeviceSize();
552665
553666 ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds());
554667 ovrVector3f ovrHeadPosition = ts.HeadPose.ThePose.Position;
555−
668+
556669 trackerPosition = glm::vec3(ovrHeadPosition.x, ovrHeadPosition.y, ovrHeadPosition.z);
557670
558671 if (_calibrationState != CALIBRATED) {
@@ -562,11 +675,11 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 3 unmodified lines
562675 }
563676
564677 trackerPosition = bodyOrientation * trackerPosition;
565− static ovrVector3f eyeOffsets[2] = { { 0, 0, 0 }, { 0, 0, 0 } };
566678 ovrPosef eyePoses[ovrEye_Count];
567− ovrHmd_GetEyePoses(_ovrHmd, _frameIndex, eyeOffsets, eyePoses, nullptr);
679+ ovrHmd_GetEyePoses(_ovrHmd, _frameIndex, _eyeOffsets, eyePoses, nullptr);
680+#ifndef Q_OS_WIN
568681 ovrHmd_BeginFrame(_ovrHmd, _frameIndex);
569− static ovrPosef eyeRenderPose[ovrEye_Count];
682+#endif
570683 //Render each eye into an fbo
571684 for_each_eye(_ovrHmd, [&](ovrEyeType eye){
572685 // If we're in eye-per-frame mode, only render one eye
@@ -576,29 +689,17 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 3 unmodified lines
576689 return;
577690 }
578691 _lastEyeRendered = _activeEye = eye;
579− eyeRenderPose[eye] = eyePoses[eye];
692+ _eyeRenderPoses[eye] = eyePoses[eye];
580693 // Set the camera rotation for this eye
581− orientation.x = eyeRenderPose[eye].Orientation.x;
582− orientation.y = eyeRenderPose[eye].Orientation.y;
583− orientation.z = eyeRenderPose[eye].Orientation.z;
584− orientation.w = eyeRenderPose[eye].Orientation.w;
585−
586− // Update the application camera with the latest HMD position
587− whichCamera.setHmdPosition(trackerPosition);
588− whichCamera.setHmdRotation(orientation);
589−
590694
695+ vec3 eyePosition = toGlm(_eyeRenderPoses[eye].Position);
696+ eyePosition = whichCamera.getRotation() * eyePosition;
697+ quat eyeRotation = toGlm(_eyeRenderPoses[eye].Orientation);
698+
591699 // Update our camera to what the application camera is doing
592− _camera->setRotation(whichCamera.getRotation());
593− _camera->setPosition(whichCamera.getPosition());
700+ _camera->setRotation(whichCamera.getRotation() * eyeRotation);
701+ _camera->setPosition(whichCamera.getPosition() + eyePosition);
594702 configureCamera(*_camera);
595−
596− // Store the latest left and right eye render locations for things that need to know
597− glm::vec3 thisEyePosition = position + trackerPosition +
598− (bodyOrientation * glm::quat(orientation.x, orientation.y, orientation.z, orientation.w) *
599− glm::vec3(_eyeRenderDesc[eye].HmdToEyeViewOffset.x, _eyeRenderDesc[eye].HmdToEyeViewOffset.y, _eyeRenderDesc[eye].HmdToEyeViewOffset.z));
600−
601− _eyePositions[eye] = thisEyePosition;
602703 _camera->update(1.0f / Application::getInstance()->getFps());
603704
604705 glMatrixMode(GL_PROJECTION);
@@ -607,15 +708,14 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 2 unmodified lines
607708 glMatrixMode(GL_MODELVIEW);
608709 glLoadIdentity();
609710
610− ovrRecti & vp = _eyeTextures[eye].Header.RenderViewport;
711+ ovrRecti & vp = _eyeViewports[eye];
611712 vp.Size.h = _recommendedTexSize.h * _offscreenRenderScale;
612713 vp.Size.w = _recommendedTexSize.w * _offscreenRenderScale;
613−
614714 glViewport(vp.Pos.x, vp.Pos.y, vp.Size.w, vp.Size.h);
615715
616716 renderArgs->_renderSide = RenderArgs::MONO;
617− qApp->displaySide(renderArgs, *_camera, false);
618− qApp->getApplicationOverlay().displayOverlayTextureHmd(*_camera);
717+ qApp->displaySide(renderArgs, *_camera);
718+ qApp->getApplicationCompositor().displayOverlayTextureHmd(renderArgs, eye);
619719 });
620720 _activeEye = ovrEye_Count;
621721
@@ -628,7 +728,7 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 6 unmodified lines
628728 glViewport(0, 0, _renderTargetSize.w, _renderTargetSize.h);
629729 finalFbo = DependencyManager::get<GlowEffect>()->render(renderArgs);
630730 } else {
631− finalFbo = DependencyManager::get<TextureCache>()->getPrimaryFramebuffer();
731+ finalFbo = DependencyManager::get<TextureCache>()->getPrimaryFramebuffer();
632732 glBindFramebuffer(GL_FRAMEBUFFER, 0);
633733 }
634734
@@ -638,141 +738,73 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 3 unmodified lines
638738 // restore our normal viewport
639739 glViewport(0, 0, deviceSize.width(), deviceSize.height());
640740
641−#if 0
642− if (debugFrame && !timerActive) {
643− timerQuery.begin();
644− }
645−#endif
741+#ifdef Q_OS_WIN
742+ auto srcFboSize = finalFbo->getSize();
646743
647−#ifdef OVR_CLIENT_DISTORTION
648−
649− //Wait till time-warp to reduce latency
650− ovr_WaitTillTime(_hmdFrameTiming.TimewarpPointSeconds);
651744
652−#ifdef DEBUG_RENDER_WITHOUT_DISTORTION
653− auto fboSize = finalFbo->getSize();
745+ // Blit to the oculus provided texture
654746 glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo));
747+ _swapFbo->Bound(oglplus::Framebuffer::Target::Draw, [&] {
748+ glBlitFramebuffer(
749+ 0, 0, srcFboSize.x, srcFboSize.y,
750+ 0, 0, _swapFbo->size.x, _swapFbo->size.y,
751+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
752+ });
753+
754+ // Blit to the onscreen window
755+ auto destWindowSize = qApp->getDeviceSize();
655756 glBlitFramebuffer(
656− 0, 0, fboSize.x, fboSize.y,
657− 0, 0, deviceSize.width(), deviceSize.height(),
757+ 0, 0, srcFboSize.x, srcFboSize.y,
758+ 0, 0, destWindowSize.width(), destWindowSize.height(),
658759 GL_COLOR_BUFFER_BIT, GL_NEAREST);
760+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
761+
762+ // Submit the frame to the Oculus SDK for timewarp and distortion
763+ for_each_eye([&](ovrEyeType eye) {
764+ _sceneLayer.RenderPose[eye] = _eyeRenderPoses[eye];
765+ });
766+ auto header = &_sceneLayer.Header;
767+ ovrResult res = ovrHmd_SubmitFrame(_ovrHmd, _frameIndex, nullptr, &header, 1);
768+ Q_ASSERT(OVR_SUCCESS(res));
769+ _swapFbo->Increment();
659770 #else
660− //Clear the color buffer to ensure that there isnt any residual color
661− //Left over from when OR was not connected.
662− glClear(GL_COLOR_BUFFER_BIT);
663− glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(finalFbo->getRenderBuffer(0)));
664− //Renders the distorted mesh onto the screen
665− renderDistortionMesh(eyeRenderPose);
666− glBindTexture(GL_TEXTURE_2D, 0);
667−#endif
668− glCanvas->swapBuffers();
771+ GLsync syncObject = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
772+ glFlush();
669773
670−#else
671774
775+ _outputWindow->makeCurrent();
776+ // force the compositing context to wait for the texture
777+ // rendering to complete before it starts the distortion rendering,
778+ // but without triggering a CPU/GPU synchronization
779+ glWaitSync(syncObject, 0, GL_TIMEOUT_IGNORED);
780+ glDeleteSync(syncObject);
781+
782+ GLuint textureId = gpu::GLBackend::getTextureID(finalFbo->getRenderBuffer(0));
672783 for_each_eye([&](ovrEyeType eye) {
673784 ovrGLTexture & glEyeTexture = reinterpret_cast<ovrGLTexture&>(_eyeTextures[eye]);
674− glEyeTexture.OGL.TexId = finalFbo->texture();
675−
676− });
785+ glEyeTexture.OGL.TexId = textureId;
677786
678− ovrHmd_EndFrame(_ovrHmd, eyeRenderPose, _eyeTextures);
787+ });
679788
789+ // restore our normal viewport
790+ ovrHmd_EndFrame(_ovrHmd, _eyeRenderPoses, _eyeTextures);
791+ glCanvas->makeCurrent();
680792 #endif
681793
682−#if 0
683− if (debugFrame && !timerActive) {
684− timerQuery.end();
685− timerActive = true;
686− }
687−#endif
688794
689− // No DK2, no message.
795+ // in order to account account for changes in the pick ray caused by head movement
796+ // we need to force a mouse move event on every frame (perhaps we could change this
797+ // to based on the head moving a minimum distance from the last position in which we
798+ // sent?)
690799 {
691− float latencies[5] = {};
692− if (debugFrame && ovrHmd_GetFloatArray(_ovrHmd, "DK2Latency", latencies, 5) == 5)
693− {
694− bool nonZero = false;
695− for (int i = 0; i < 5; ++i)
696− {
697− nonZero |= (latencies[i] != 0.f);
698− }
699−
700− if (nonZero)
701− {
702− qCDebug(interfaceapp) << QString().sprintf("M2P Latency: Ren: %4.2fms TWrp: %4.2fms PostPresent: %4.2fms Err: %4.2fms %4.2fms",
703− latencies[0], latencies[1], latencies[2], latencies[3], latencies[4]);
704− }
705− }
800+ QMouseEvent mouseEvent(QEvent::MouseMove, glCanvas->mapFromGlobal(QCursor::pos()),
801+ Qt::NoButton, Qt::NoButton, 0);
802+ qApp->mouseMoveEvent(&mouseEvent, 0);
706803 }
707−
708−}
709−
710−#ifdef OVR_CLIENT_DISTORTION
711−void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) {
712804
713− glLoadIdentity();
714− auto deviceSize = qApp->getDeviceSize();
715− glOrtho(0, deviceSize.width(), 0, deviceSize.height(), -1.0, 1.0);
716−
717− glDisable(GL_DEPTH_TEST);
718−
719− glDisable(GL_BLEND);
720− _program.bind();
721− _program.setUniformValue(_textureLocation, 0);
722−
723− _program.enableAttributeArray(_positionAttributeLocation);
724− _program.enableAttributeArray(_colorAttributeLocation);
725− _program.enableAttributeArray(_texCoord0AttributeLocation);
726− _program.enableAttributeArray(_texCoord1AttributeLocation);
727− _program.enableAttributeArray(_texCoord2AttributeLocation);
728−
729− //Render the distortion meshes for each eye
730− for (int eyeNum = 0; eyeNum < ovrEye_Count; eyeNum++) {
731−
732− ovrHmd_GetRenderScaleAndOffset(_eyeRenderDesc[eyeNum].Fov, _renderTargetSize, _eyeTextures[eyeNum].Header.RenderViewport,
733− _UVScaleOffset[eyeNum]);
734−
735− GLfloat uvScale[2] = { _UVScaleOffset[eyeNum][0].x, _UVScaleOffset[eyeNum][0].y };
736− _program.setUniformValueArray(_eyeToSourceUVScaleLocation, uvScale, 1, 2);
737− GLfloat uvOffset[2] = { _UVScaleOffset[eyeNum][1].x, 1.0f - _UVScaleOffset[eyeNum][1].y };
738− _program.setUniformValueArray(_eyeToSourceUVOffsetLocation, uvOffset, 1, 2);
739−
740− ovrMatrix4f timeWarpMatrices[2];
741− glm::mat4 transposeMatrices[2];
742− //Grabs the timewarp matrices to be used in the shader
743− ovrHmd_GetEyeTimewarpMatrices(_ovrHmd, (ovrEyeType)eyeNum, eyeRenderPose[eyeNum], timeWarpMatrices);
744− //Have to transpose the matrices before using them
745− transposeMatrices[0] = glm::transpose(toGlm(timeWarpMatrices[0]));
746− transposeMatrices[1] = glm::transpose(toGlm(timeWarpMatrices[1]));
747805
748− glUniformMatrix4fv(_eyeRotationStartLocation, 1, GL_FALSE, (GLfloat *)&transposeMatrices[0][0][0]);
749− glUniformMatrix4fv(_eyeRotationEndLocation, 1, GL_FALSE, (GLfloat *)&transposeMatrices[1][0][0]);
750806
751− glBindBuffer(GL_ARRAY_BUFFER, _vertices[eyeNum]);
752−
753− //Set vertex attribute pointers
754− glVertexAttribPointer(_positionAttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)0);
755− glVertexAttribPointer(_texCoord0AttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)8);
756− glVertexAttribPointer(_texCoord1AttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)16);
757− glVertexAttribPointer(_texCoord2AttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)24);
758− glVertexAttribPointer(_colorAttributeLocation, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(DistortionVertex), (void *)32);
759−
760− glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indices[eyeNum]);
761− glDrawElements(GL_TRIANGLES, _meshSize[eyeNum], GL_UNSIGNED_SHORT, 0);
762− }
763−
764− _program.disableAttributeArray(_positionAttributeLocation);
765− _program.disableAttributeArray(_colorAttributeLocation);
766− _program.disableAttributeArray(_texCoord0AttributeLocation);
767− _program.disableAttributeArray(_texCoord1AttributeLocation);
768− _program.disableAttributeArray(_texCoord2AttributeLocation);
769−
770− glEnable(GL_BLEND);
771− glEnable(GL_DEPTH_TEST);
772− _program.release();
773− glBindBuffer(GL_ARRAY_BUFFER, 0);
774807 }
775−#endif
776808
777809 //Tries to reconnect to the sensors
778810 void OculusManager::reset() {
@@ -781,21 +813,6 @@ void OculusManager::reset() { · 2 unmodified lines
781813 }
782814 }
783815
784−//Gets the current predicted angles from the oculus sensors
785−void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) {
786− ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds());
787− if (ts.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) {
788− glm::vec3 euler = glm::eulerAngles(toGlm(ts.HeadPose.ThePose.Orientation));
789− yaw = euler.y;
790− pitch = euler.x;
791− roll = euler.z;
792− } else {
793− yaw = 0.0f;
794− pitch = 0.0f;
795− roll = 0.0f;
796− }
797−}
798−
799816 glm::vec3 OculusManager::getRelativePosition() {
800817 ovrTrackingState trackingState = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds());
801818 return toGlm(trackingState.HeadPose.ThePose.Position);
@@ -826,6 +843,9 @@ void OculusManager::overrideOffAxisFrustum(float& left, float& right, float& bot · 24 unmodified lines
826843 }
827844
828845 int OculusManager::getHMDScreen() {
846+#ifdef Q_OS_WIN
847+ return -1;
848+#else
829849 int hmdScreenIndex = -1; // unknown
830850 // TODO: it might be smarter to handle multiple HMDs connected in this case. but for now,
831851 // we will simply assume the initialization code that set up _ovrHmd picked the best hmd
@@ -844,7 +864,7 @@ int OculusManager::getHMDScreen() { · 12 unmodified lines
844864 const int SIMILAR_NAMES = 10;
845865 const int EXACT_LOCATION_MATCH = 50;
846866 const int EXACT_RESOLUTION_MATCH = 25;
847−
867+
848868 int bestMatchScore = 0;
849869
850870 // look at the display list and see if we can find the best match
@@ -853,7 +873,7 @@ int OculusManager::getHMDScreen() { · 2 unmodified lines
853873 foreach (QScreen* screen, QGuiApplication::screens()) {
854874 QString screenName = screen->name();
855875 QRect screenRect = desktop->screenGeometry(screenNumber);
856−
876+
857877 int screenScore = 0;
858878 if (screenName == productNameFromOVR) {
859879 screenScore += EXACT_NAME_MATCH;
@@ -876,5 +896,18 @@ int OculusManager::getHMDScreen() { · 16 unmodified lines
876896 }
877897 }
878898 return hmdScreenIndex;
899+#endif
900+}
901+
902+mat4 OculusManager::getEyeProjection(int eye) {
903+ return _eyeProjection[eye];
879904 }
880905
906+mat4 OculusManager::getEyePose(int eye) {
907+ return toGlm(_eyeRenderPoses[eye]);
908+}
909+
910+mat4 OculusManager::getHeadPose() {
911+ ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds());
912+ return toGlm(ts.HeadPose.ThePose);
913+}
interface/src/devices/OculusManager.h+7−170
@@ -13,8 +13,6 @@ · 12 unmodified lines
1313 #ifndef hifi_OculusManager_h
1414 #define hifi_OculusManager_h
1515
16−#include <OVR_CAPI.h>
17−
1816 #include <ProgramObject.h>
1917 #include <glm/glm.hpp>
2018 #include <glm/gtc/matrix_transform.hpp>
@@ -22,39 +20,13 @@ · 1 unmodified line
2220
2321 #include "RenderArgs.h"
2422
23+class QOpenGLContext;
2524 class Camera;
26−class PalmData;
27−class Text3DOverlay;
28−
29−// Uncomment this to enable client side distortion. NOT recommended since
30−// the Oculus SDK will ideally provide the best practices for distortion in
31−// in terms of performance and quality, and by using it we will get updated
32−// best practices for free with new runtime releases.
33−#define OVR_CLIENT_DISTORTION 1
34−
35−
36−// Direct HMD mode is currently only supported on windows and some linux systems will
37−// misbehave if we try to enable the Oculus SDK at all, so isolate support for Direct
38−// mode only to windows for now
39−#ifdef Q_OS_WIN
40−// On Win32 platforms, enabling Direct HMD requires that the SDK be
41−// initialized before the GL context is set up, but this breaks v-sync
42−// for any application that has a Direct mode enable Rift connected
43−// but is not rendering to it. For the time being I'm setting this as
44−// a macro enabled mechanism which changes where the SDK is initialized.
45−// To enable Direct HMD mode, you can un-comment this, but with the
46−// caveat that it will break v-sync in NON-VR mode if you have an Oculus
47−// Rift connect and in Direct mode
48−#define OVR_DIRECT_MODE 1
49−#endif
50−
5125
5226 /// Handles interaction with the Oculus Rift.
5327 class OculusManager {
5428 public:
55− static void init();
56− static void deinit();
57− static void connect();
29+ static void connect(QOpenGLContext* shareContext);
5830 static void disconnect();
5931 static bool isConnected();
6032 static void recalibrate();
@@ -66,10 +38,6 @@ public: · 5 unmodified lines
6638 static void display(QGLWidget * glCanvas, RenderArgs* renderArgs, const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera);
6739 static void reset();
6840
69− /// param \yaw[out] yaw in radians
70− /// param \pitch[out] pitch in radians
71− /// param \roll[out] roll in radians
72− static void getEulerAngles(float& yaw, float& pitch, float& roll);
7341 static glm::vec3 getRelativePosition();
7442 static glm::quat getOrientation();
7543 static QSize getRenderTargetSize();
@@ -77,145 +45,14 @@ public: · 1 unmodified line
7745 static void overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal,
7846 float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane);
7947
80− static glm::vec3 getLeftEyePosition() { return _eyePositions[ovrEye_Left]; }
81− static glm::vec3 getRightEyePosition() { return _eyePositions[ovrEye_Right]; }
48+ static glm::vec3 getLeftEyePosition();
49+ static glm::vec3 getRightEyePosition();
8250
8351 static int getHMDScreen();
84−
85−private:
86− static void initSdk();
87− static void shutdownSdk();
88−#ifdef OVR_CLIENT_DISTORTION
89− static void generateDistortionMesh();
90− static void renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]);
91− struct DistortionVertex {
92− glm::vec2 pos;
93− glm::vec2 texR;
94− glm::vec2 texG;
95− glm::vec2 texB;
96− struct {
97− GLubyte r;
98− GLubyte g;
99− GLubyte b;
100− GLubyte a;
101− } color;
102− };
10352
104− static ProgramObject _program;
105− //Uniforms
106− static int _textureLocation;
107− static int _eyeToSourceUVScaleLocation;
108− static int _eyeToSourceUVOffsetLocation;
109− static int _eyeRotationStartLocation;
110− static int _eyeRotationEndLocation;
111− //Attributes
112− static int _positionAttributeLocation;
113− static int _colorAttributeLocation;
114− static int _texCoord0AttributeLocation;
115− static int _texCoord1AttributeLocation;
116− static int _texCoord2AttributeLocation;
117− static ovrVector2f _UVScaleOffset[ovrEye_Count][2];
118− static GLuint _vertices[ovrEye_Count];
119− static GLuint _indices[ovrEye_Count];
120− static GLsizei _meshSize[ovrEye_Count];
121− static ovrFrameTiming _hmdFrameTiming;
122− static bool _programInitialized;
123−#endif
124−
125− static ovrTexture _eyeTextures[ovrEye_Count];
126− static bool _isConnected;
127− static glm::vec3 _eyePositions[ovrEye_Count];
128− static ovrHmd _ovrHmd;
129− static ovrFovPort _eyeFov[ovrEye_Count];
130− static ovrVector3f _eyeOffset[ovrEye_Count];
131− static glm::mat4 _eyeProjection[ovrEye_Count];
132− static ovrEyeRenderDesc _eyeRenderDesc[ovrEye_Count];
133− static ovrSizei _renderTargetSize;
134− static unsigned int _frameIndex;
135− static bool _frameTimingActive;
136− static Camera* _camera;
137− static ovrEyeType _activeEye;
138− static bool _hswDismissed;
139−
140− static void calibrate(const glm::vec3 position, const glm::quat orientation);
141− enum CalibrationState {
142− UNCALIBRATED,
143− WAITING_FOR_DELTA,
144− WAITING_FOR_ZERO,
145− WAITING_FOR_ZERO_HELD,
146− CALIBRATED
147− };
148− static void positionCalibrationBillboard(Text3DOverlay* message);
149− static float CALIBRATION_DELTA_MINIMUM_LENGTH;
150− static float CALIBRATION_DELTA_MINIMUM_ANGLE;
151− static float CALIBRATION_ZERO_MAXIMUM_LENGTH;
152− static float CALIBRATION_ZERO_MAXIMUM_ANGLE;
153− static quint64 CALIBRATION_ZERO_HOLD_TIME;
154− static float CALIBRATION_MESSAGE_DISTANCE;
155− static CalibrationState _calibrationState;
156− static glm::vec3 _calibrationPosition;
157− static glm::quat _calibrationOrientation;
158− static quint64 _calibrationStartTime;
159− static int _calibrationMessage;
160− // TODO drop this variable and use the existing 'Developer | Render | Scale Resolution' value
161− static ovrSizei _recommendedTexSize;
162− static float _offscreenRenderScale;
163− static bool _eyePerFrameMode;
164− static ovrEyeType _lastEyeRendered;
53+ static glm::mat4 getEyeProjection(int eye);
54+ static glm::mat4 getEyePose(int eye);
55+ static glm::mat4 getHeadPose();
16556 };
16657
167−
168−inline glm::mat4 toGlm(const ovrMatrix4f & om) {
169− return glm::transpose(glm::make_mat4(&om.M[0][0]));
170−}
171−
172−inline glm::mat4 toGlm(const ovrFovPort & fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) {
173− return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true));
174−}
175−
176−inline glm::vec3 toGlm(const ovrVector3f & ov) {
177− return glm::make_vec3(&ov.x);
178−}
179−
180−inline glm::vec2 toGlm(const ovrVector2f & ov) {
181− return glm::make_vec2(&ov.x);
182−}
183−
184−inline glm::uvec2 toGlm(const ovrSizei & ov) {
185− return glm::uvec2(ov.w, ov.h);
186−}
187−
188−inline glm::quat toGlm(const ovrQuatf & oq) {
189− return glm::make_quat(&oq.x);
190−}
191−
192−inline glm::mat4 toGlm(const ovrPosef & op) {
193− glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation));
194− glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position));
195− return translation * orientation;
196−}
197−
198−inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) {
199− ovrMatrix4f result;
200− glm::mat4 transposed(glm::transpose(m));
201− memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16);
202− return result;
203−}
204−
205−inline ovrVector3f ovrFromGlm(const glm::vec3 & v) {
206− return{ v.x, v.y, v.z };
207−}
208−
209−inline ovrVector2f ovrFromGlm(const glm::vec2 & v) {
210− return{ v.x, v.y };
211−}
212−
213−inline ovrSizei ovrFromGlm(const glm::uvec2 & v) {
214− return{ (int)v.x, (int)v.y };
215−}
216−
217−inline ovrQuatf ovrFromGlm(const glm::quat & q) {
218− return{ q.x, q.y, q.z, q.w };
219−}
220−
22158 #endif // hifi_OculusManager_h
interface/src/devices/SDL2Manager.cpp+2−0
@@ -74,9 +74,11 @@ SDL2Manager* SDL2Manager::getInstance() { · 73 unmodified lines
7474 }
7575
7676 void SDL2Manager::focusOutEvent() {
77+#ifdef HAVE_SDL2
7778 for (auto joystick : _openJoysticks) {
7879 joystick->focusOutEvent();
7980 }
81+#endif
8082 }
8183
8284 void SDL2Manager::update() {
interface/src/devices/SixenseManager.cpp+58−50
@@ -36,6 +36,8 @@ const float NECK_X = 0.25f; // meters · 35 unmodified lines
3636 const float NECK_Y = 0.3f; // meters
3737 const float NECK_Z = 0.3f; // meters
3838
39+const float CONTROLLER_THRESHOLD = 0.35f;
40+
3941 #ifdef __APPLE__
4042 typedef int (*SixenseBaseFunction)();
4143 typedef int (*SixenseTakeIntFunction)(int);
@@ -71,25 +73,25 @@ SixenseManager::SixenseManager() : · 29 unmodified lines
7173
7274 SixenseManager::~SixenseManager() {
7375 #ifdef HAVE_SIXENSE_
74−
76+
7577 if (_isInitialized) {
7678 #ifdef __APPLE__
7779 SixenseBaseFunction sixenseExit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseExit");
7880 #endif
79−
81+
8082 sixenseExit();
8183 }
82−
84+
8385 #ifdef __APPLE__
8486 delete _sixenseLibrary;
8587 #endif
86−
88+
8789 #endif
8890 }
8991
9092 void SixenseManager::initialize() {
9193 #ifdef HAVE_SIXENSE
92−
94+
9395 if (!_isInitialized) {
9496 _lowVelocityFilter = false;
9597 _controllersAtBase = true;
@@ -97,22 +99,22 @@ void SixenseManager::initialize() { · 1 unmodified line
9799 // By default we assume the _neckBase (in orb frame) is as high above the orb
98100 // as the "torso" is below it.
99101 _neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z);
100−
102+
101103 #ifdef __APPLE__
102−
104+
103105 if (!_sixenseLibrary) {
104−
106+
105107 #ifdef SIXENSE_LIB_FILENAME
106108 _sixenseLibrary = new QLibrary(SIXENSE_LIB_FILENAME);
107109 #else
108110 const QString SIXENSE_LIBRARY_NAME = "libsixense_x64";
109111 QString frameworkSixenseLibrary = QCoreApplication::applicationDirPath() + "/../Frameworks/"
110112 + SIXENSE_LIBRARY_NAME;
111−
113+
112114 _sixenseLibrary = new QLibrary(frameworkSixenseLibrary);
113115 #endif
114116 }
115−
117+
116118 if (_sixenseLibrary->load()){
117119 qCDebug(interfaceapp) << "Loaded sixense library for hydra support -" << _sixenseLibrary->fileName();
118120 } else {
@@ -120,14 +122,14 @@ void SixenseManager::initialize() { · 1 unmodified line
120122 << "Continuing without hydra support.";
121123 return;
122124 }
123−
125+
124126 SixenseBaseFunction sixenseInit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseInit");
125127 #endif
126128 sixenseInit();
127−
129+
128130 _isInitialized = true;
129131 }
130−
132+
131133 #endif
132134 }
133135
@@ -138,7 +140,7 @@ void SixenseManager::setFilter(bool filter) { · 4 unmodified lines
138140 #ifdef __APPLE__
139141 SixenseTakeIntFunction sixenseSetFilterEnabled = (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseSetFilterEnabled");
140142 #endif
141−
143+
142144 if (filter) {
143145 sixenseSetFilterEnabled(1);
144146 } else {
@@ -158,7 +160,7 @@ void SixenseManager::update(float deltaTime) { · 13 unmodified lines
158160 SixenseBaseFunction sixenseGetNumActiveControllers =
159161 (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetNumActiveControllers");
160162 #endif
161−
163+
162164 if (sixenseGetNumActiveControllers() == 0) {
163165 _hydrasConnected = false;
164166 if (_deviceID != 0) {
@@ -173,7 +175,7 @@ void SixenseManager::update(float deltaTime) { · 8 unmodified lines
173175 }
174176 return;
175177 }
176−
178+
177179 PerformanceTimer perfTimer("sixense");
178180 if (!_hydrasConnected) {
179181 _hydrasConnected = true;
@@ -181,21 +183,21 @@ void SixenseManager::update(float deltaTime) { · 1 unmodified line
181183 getInstance().assignDefaultInputMapping(*Application::getUserInputMapper());
182184 UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra");
183185 }
184−
186+
185187 #ifdef __APPLE__
186188 SixenseBaseFunction sixenseGetMaxControllers =
187189 (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetMaxControllers");
188190 #endif
189−
191+
190192 int maxControllers = sixenseGetMaxControllers();
191−
193+
192194 // we only support two controllers
193195 sixenseControllerData controllers[2];
194−
196+
195197 #ifdef __APPLE__
196198 SixenseTakeIntFunction sixenseIsControllerEnabled =
197199 (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseIsControllerEnabled");
198−
200+
199201 SixenseTakeIntAndSixenseControllerData sixenseGetNewestData =
200202 (SixenseTakeIntAndSixenseControllerData) _sixenseLibrary->resolve("sixenseGetNewestData");
201203 #endif
@@ -208,9 +210,9 @@ void SixenseManager::update(float deltaTime) { · 6 unmodified lines
208210 sixenseControllerData* data = controllers + numActiveControllers;
209211 ++numActiveControllers;
210212 sixenseGetNewestData(i, data);
211−
213+
212214 // Set palm position and normal based on Hydra position/orientation
213−
215+
214216 // Either find a palm matching the sixense controller, or make a new one
215217 PalmData* palm;
216218 bool foundHand = false;
@@ -229,47 +231,47 @@ void SixenseManager::update(float deltaTime) { · 12 unmodified lines
229231 _prevPalms[numActiveControllers - 1] = palm;
230232 qCDebug(interfaceapp, "Found new Sixense controller, ID %i", data->controller_index);
231233 }
232−
234+
233235 // Disable the hands (and return to default pose) if both controllers are at base station
234236 if (foundHand) {
235237 palm->setActive(!_controllersAtBase);
236238 } else {
237239 palm->setActive(false); // if this isn't a Sixsense ID palm, always make it inactive
238240 }
239−
241+
240242 // Read controller buttons and joystick into the hand
241243 palm->setControllerButtons(data->buttons);
242244 palm->setTrigger(data->trigger);
243245 palm->setJoystick(data->joystick_x, data->joystick_y);
244−
246+
245247 handleButtonEvent(data->buttons, numActiveControllers - 1);
246248 handleAxisEvent(data->joystick_x, data->joystick_y, data->trigger, numActiveControllers - 1);
247−
249+
248250 // Emulate the mouse so we can use scripts
249251 if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput) && !_controllersAtBase) {
250252 emulateMouse(palm, numActiveControllers - 1);
251253 }
252−
254+
253255 // NOTE: Sixense API returns pos data in millimeters but we IMMEDIATELY convert to meters.
254256 glm::vec3 position(data->pos[0], data->pos[1], data->pos[2]);
255257 position *= METERS_PER_MILLIMETER;
256−
258+
257259 // Check to see if this hand/controller is on the base
258260 const float CONTROLLER_AT_BASE_DISTANCE = 0.075f;
259261 if (glm::length(position) < CONTROLLER_AT_BASE_DISTANCE) {
260262 numControllersAtBase++;
261263 }
262−
264+
263265 // Transform the measured position into body frame.
264266 glm::vec3 neck = _neckBase;
265267 // Zeroing y component of the "neck" effectively raises the measured position a little bit.
266268 neck.y = 0.0f;
267269 position = _orbRotation * (position - neck);
268−
270+
269271 // Rotation of Palm
270272 glm::quat rotation(data->rot_quat[3], -data->rot_quat[0], data->rot_quat[1], -data->rot_quat[2]);
271273 rotation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)) * _orbRotation * rotation;
272−
274+
273275 // Compute current velocity from position change
274276 glm::vec3 rawVelocity;
275277 if (deltaTime > 0.0f) {
@@ -278,11 +280,11 @@ void SixenseManager::update(float deltaTime) { · 2 unmodified lines
278280 rawVelocity = glm::vec3(0.0f);
279281 }
280282 palm->setRawVelocity(rawVelocity); // meters/sec
281−
283+
282284 // adjustment for hydra controllers fit into hands
283285 float sign = (i == 0) ? -1.0f : 1.0f;
284286 rotation *= glm::angleAxis(sign * PI/4.0f, glm::vec3(0.0f, 0.0f, 1.0f));
285−
287+
286288 // Angular Velocity of Palm
287289 glm::quat deltaRotation = rotation * glm::inverse(palm->getRawRotation());
288290 glm::vec3 angularVelocity(0.0f);
@@ -294,7 +296,7 @@ void SixenseManager::update(float deltaTime) { · 5 unmodified lines
294296 } else {
295297 palm->setRawAngularVelocity(glm::vec3(0.0f));
296298 }
297−
299+
298300 if (_lowVelocityFilter) {
299301 // Use a velocity sensitive filter to damp small motions and preserve large ones with
300302 // no latency.
@@ -307,7 +309,7 @@ void SixenseManager::update(float deltaTime) { · 6 unmodified lines
307309 palm->setRawPosition(position);
308310 palm->setRawRotation(rotation);
309311 }
310−
312+
311313 // Store the one fingertip in the palm structure so we can track velocity
312314 const float FINGER_LENGTH = 0.3f; // meters
313315 const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, FINGER_LENGTH);
@@ -320,19 +322,25 @@ void SixenseManager::update(float deltaTime) { · 6 unmodified lines
320322 }
321323 palm->setTipPosition(newTipPosition);
322324 }
323−
325+
324326 if (numActiveControllers == 2) {
325327 updateCalibration(controllers);
326328 }
327329 _controllersAtBase = (numControllersAtBase == 2);
328330 }
331+
332+ for (auto axisState : _axisStateMap) {
333+ if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) {
334+ _axisStateMap[axisState.first] = 0.0f;
335+ }
336+ }
329337 #endif // HAVE_SIXENSE
330338 }
331339
332340 //Constants for getCursorPixelRangeMultiplier()
333341 const float MIN_PIXEL_RANGE_MULT = 0.4f;
334342 const float MAX_PIXEL_RANGE_MULT = 2.0f;
335−const float RANGE_MULT = (MAX_PIXEL_RANGE_MULT - MIN_PIXEL_RANGE_MULT) * 0.01;
343+const float RANGE_MULT = (MAX_PIXEL_RANGE_MULT - MIN_PIXEL_RANGE_MULT) * 0.01f;
336344
337345 //Returns a multiplier to be applied to the cursor range for the controllers
338346 float SixenseManager::getCursorPixelRangeMult() const {
@@ -421,7 +429,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 82 unmodified lines
421429 _calibrationState = CALIBRATION_STATE_X;
422430 }
423431 return;
424− }
432+ }
425433
426434 quint64 now = usecTimestampNow() + LOCK_DURATION;
427435 // these are weighted running averages
@@ -431,7 +439,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 3 unmodified lines
431439 if (_calibrationState == CALIBRATION_STATE_X) {
432440 // compute new sliding average
433441 float distance = glm::distance(_averageLeft, _averageRight);
434− if (fabs(distance - _lastDistance) > MAXIMUM_NOISE_LEVEL) {
442+ if (fabsf(distance - _lastDistance) > MAXIMUM_NOISE_LEVEL) {
435443 // distance is increasing so acquire the data and push the expiry out
436444 _reachLeft = _averageLeft;
437445 _reachRight = _averageRight;
@@ -450,7 +458,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 12 unmodified lines
450458 glm::vec3 torso = 0.5f * (_reachLeft + _reachRight);
451459 glm::vec3 averagePosition = 0.5f * (_averageLeft + _averageRight);
452460 float distance = (averagePosition - torso).y;
453− if (fabs(distance) > fabs(_lastDistance) + MAXIMUM_NOISE_LEVEL) {
461+ if (fabsf(distance) > fabsf(_lastDistance) + MAXIMUM_NOISE_LEVEL) {
454462 // distance is increasing so acquire the data and push the expiry out
455463 _reachUp = averagePosition;
456464 _lastDistance = distance;
@@ -481,11 +489,11 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 24 unmodified lines
481489 _lastDistance = distance;
482490 _lockExpiry = now + LOCK_DURATION;
483491 } else if (now > _lockExpiry) {
484− if (fabs(_lastDistance) > 0.05f * MINIMUM_ARM_REACH) {
492+ if (fabsf(_lastDistance) > 0.05f * MINIMUM_ARM_REACH) {
485493 // lock has expired so clamp the data and move on
486494 _calibrationState = CALIBRATION_STATE_COMPLETE;
487495 qCDebug(interfaceapp, "success: sixense calibration: forward");
488− // TODO: it is theoretically possible to detect that the controllers have been
496+ // TODO: it is theoretically possible to detect that the controllers have been
489497 // accidentally switched (left hand is holding right controller) and to swap the order.
490498 }
491499 }
@@ -496,7 +504,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 4 unmodified lines
496504 void SixenseManager::emulateMouse(PalmData* palm, int index) {
497505 MyAvatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
498506 QPoint pos;
499−
507+
500508 Qt::MouseButton bumperButton;
501509 Qt::MouseButton triggerButton;
502510
@@ -510,16 +518,16 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { · 7 unmodified lines
510518 triggerButton = Qt::LeftButton;
511519 }
512520
513− if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)
521+ if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)
514522 || Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {
515− pos = qApp->getApplicationOverlay().getPalmClickLocation(palm);
523+ pos = qApp->getApplicationCompositor().getPalmClickLocation(palm);
516524 } else {
517525 // Get directon relative to avatar orientation
518526 glm::vec3 direction = glm::inverse(avatar->getOrientation()) * palm->getFingerDirection();
519527
520528 // Get the angles, scaled between (-0.5,0.5)
521529 float xAngle = (atan2(direction.z, direction.x) + M_PI_2);
522− float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2));
530+ float yAngle = 0.5f - ((atan2f(direction.z, direction.y) + (float)M_PI_2));
523531 auto canvasSize = qApp->getCanvasSize();
524532 // Get the pixel range over which the xAngle and yAngle are scaled
525533 float cursorRange = canvasSize.x * getCursorPixelRangeMult();
@@ -562,11 +570,11 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { · 36 unmodified lines
562570 if (!_bumperPressed[(int)(!index)]) {
563571 qApp->mouseMoveEvent(&mouseEvent, deviceID);
564572 }
565− }
573+ }
566574 }
567575 _oldX[index] = pos.x();
568576 _oldY[index] = pos.y();
569−
577+
570578
571579 //We need separate coordinates for clicks, since we need to check if
572580 //a magnification window was clicked on
@@ -580,7 +588,7 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { · 7 unmodified lines
580588 if (palm->getControllerButtons() & BUTTON_FWD) {
581589 if (!_bumperPressed[index]) {
582590 _bumperPressed[index] = true;
583−
591+
584592 QMouseEvent mouseEvent(QEvent::MouseButtonPress, pos, bumperButton, bumperButton, 0);
585593
586594 qApp->mousePressEvent(&mouseEvent, deviceID);
interface/src/devices/TV3DManager.cpp+9−9
@@ -12,6 +12,7 @@ · 11 unmodified lines
1212 #include "InterfaceConfig.h"
1313
1414 #include <glm/glm.hpp>
15+#include <glm/gtc/type_ptr.hpp>
1516
1617 #include <GlowEffect.h>
1718 #include "gpu/GLBackend.h"
@@ -106,21 +107,20 @@ void TV3DManager::display(RenderArgs* renderArgs, Camera& whichCamera) { · 88 unmodified lines
106107 _activeEye = &eye;
107108 glViewport(portalX, portalY, portalW, portalH);
108109 glScissor(portalX, portalY, portalW, portalH);
110+
111+ glm::mat4 projection = glm::frustum<float>(eye.left, eye.right, eye.bottom, eye.top, nearZ, farZ);
112+ float fov = atan(1.0f / projection[1][1]);
113+ projection = glm::translate(projection, vec3(eye.modelTranslation, 0, 0));
114+ eyeCamera.setProjection(projection);
115+
109116 glMatrixMode(GL_PROJECTION);
110117 glLoadIdentity(); // reset projection matrix
111− glFrustum(eye.left, eye.right, eye.bottom, eye.top, nearZ, farZ); // set left view frustum
112− GLfloat p[4][4];
113− // Really?
114− glGetFloatv(GL_PROJECTION_MATRIX, &(p[0][0]));
115− float cotangent = p[1][1];
116− GLfloat fov = atan(1.0f / cotangent);
117− glTranslatef(eye.modelTranslation, 0.0, 0.0); // translate to cancel parallax
118−
118+ glLoadMatrixf(glm::value_ptr(projection));
119119 glMatrixMode(GL_MODELVIEW);
120120 glLoadIdentity();
121121 renderArgs->_renderSide = RenderArgs::MONO;
122122 qApp->displaySide(renderArgs, eyeCamera, false);
123− qApp->getApplicationOverlay().displayOverlayTextureStereo(whichCamera, _aspect, fov);
123+ qApp->getApplicationCompositor().displayOverlayTexture(renderArgs);
124124 _activeEye = NULL;
125125 }, [&]{
126126 // render right side view
interface/src/main.cpp+1−1
@@ -23,7 +23,7 @@ · 22 unmodified lines
2323 #ifdef Q_OS_WIN
2424 static BOOL CALLBACK enumWindowsCallback(HWND hWnd, LPARAM lParam) {
2525 const UINT TIMEOUT = 200; // ms
26− DWORD response;
26+ DWORD_PTR response;
2727 LRESULT result = SendMessageTimeout(hWnd, UWM_IDENTIFY_INSTANCES, 0, 0, SMTO_BLOCK | SMTO_ABORTIFHUNG, TIMEOUT, &response);
2828 if (result == 0) { // Timeout; continue search.
2929 return TRUE;
interface/src/scripting/ControllerScriptingInterface.cpp+1−1
@@ -463,7 +463,7 @@ void ControllerScriptingInterface::resetDevice(unsigned int device) { · 462 unmodified lines
463463 }
464464
465465 int ControllerScriptingInterface::findDevice(QString name) {
466− Application::getUserInputMapper()->findDevice(name);
466+ return Application::getUserInputMapper()->findDevice(name);
467467 }
468468
469469 InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) :
interface/src/scripting/ControllerScriptingInterface.h+1−0
@@ -65,6 +65,7 @@ public: · 64 unmodified lines
6565
6666 void emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseMoveEvent(MouseEvent(*event, deviceID)); }
6767 void emitMousePressEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mousePressEvent(MouseEvent(*event, deviceID)); }
68+ void emitMouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseDoublePressEvent(MouseEvent(*event, deviceID)); }
6869 void emitMouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseReleaseEvent(MouseEvent(*event, deviceID)); }
6970
7071 void emitTouchBeginEvent(const TouchEvent& event) { emit touchBeginEvent(event); }
interface/src/scripting/HMDScriptingInterface.cpp+3−3
@@ -25,9 +25,9 @@ bool HMDScriptingInterface::getHUDLookAtPosition3D(glm::vec3& result) const { · 24 unmodified lines
2525
2626 glm::vec3 direction = orientation * glm::vec3(0.0f, 0.0f, -1.0f);
2727
28− ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay();
28+ const auto& compositor = Application::getInstance()->getApplicationCompositor();
2929
30− return applicationOverlay.calculateRayUICollisionPoint(position, direction, result);
30+ return compositor.calculateRayUICollisionPoint(position, direction, result);
3131 }
3232
3333 QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) {
@@ -40,7 +40,7 @@ QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* conte · 6 unmodified lines
4040 glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * (hudIntersection - sphereCenter);
4141 glm::quat rotation = ::rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), direction);
4242 glm::vec3 eulers = ::safeEulerAngles(rotation);
43− return qScriptValueFromValue<glm::vec2>(engine, Application::getInstance()->getApplicationOverlay()
43+ return qScriptValueFromValue<glm::vec2>(engine, Application::getInstance()->getApplicationCompositor()
4444 .sphericalToOverlay(glm::vec2(eulers.y, -eulers.x)));
4545 }
4646 return QScriptValue::NullValue;
interface/src/scripting/HMDScriptingInterface.h+2−2
@@ -27,11 +27,11 @@ public: · 26 unmodified lines
2727 static QScriptValue getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine);
2828
2929 public slots:
30− void toggleMagnifier() { Application::getInstance()->getApplicationOverlay().toggleMagnifier(); };
30+ void toggleMagnifier() { Application::getInstance()->getApplicationCompositor().toggleMagnifier(); };
3131
3232 private:
3333 HMDScriptingInterface() {};
34− bool getMagnifier() const { return Application::getInstance()->getApplicationOverlay().hasMagnifier(); };
34+ bool getMagnifier() const { return Application::getInstance()->getApplicationCompositor().hasMagnifier(); };
3535 bool isHMDMode() const { return Application::getInstance()->isHMDMode(); }
3636
3737 bool getHUDLookAtPosition3D(glm::vec3& result) const;
interface/src/starfield/renderer/Renderer.cpp+9−0
@@ -11,6 +11,7 @@ · 10 unmodified lines
1111 //
1212
1313 #include "starfield/renderer/Renderer.h"
14+#include "Application.h"
1415
1516 using namespace starfield;
1617
@@ -52,6 +53,10 @@ void Renderer::render(float perspective, float aspect, mat4 const& orientation, · 35 unmodified lines
5253 matrix[3][1] = 0.0f;
5354 matrix[3][2] = 0.0f;
5455
56+ glMatrixMode(GL_PROJECTION);
57+ glPushMatrix();
58+ glLoadMatrixf(glm::value_ptr(qApp->getDisplayViewFrustum()->getProjection()));
59+ glMatrixMode(GL_MODELVIEW);
5560 // extract local z vector
5661 vec3 ahead = vec3(matrix[2]);
5762
@@ -74,6 +79,10 @@ void Renderer::render(float perspective, float aspect, mat4 const& orientation, · 16 unmodified lines
7479 floodFill(cursor, TileSelection(*this, _tileArray, _tileArray + _tiling.getTileCount(), (TileSelection::Cursor*) _batchCountArray));
7580
7681 this->glBatch(glm::value_ptr(matrix), prepareBatch((unsigned*) _batchOffs, _outIndexPos), alpha);
82+ glMatrixMode(GL_PROJECTION);
83+ glPopMatrix();
84+ glMatrixMode(GL_MODELVIEW);
85+
7786 }
7887
7988 // renderer construction
interface/src/ui/AddressBarDialog.cpp+24−0
@@ -22,6 +22,20 @@ AddressBarDialog::AddressBarDialog(QQuickItem* parent) : OffscreenQmlDialog(pare · 21 unmodified lines
2222 connect(addressManager.data(), &AddressManager::lookupResultIsOffline, this, &AddressBarDialog::displayAddressOfflineMessage);
2323 connect(addressManager.data(), &AddressManager::lookupResultIsNotFound, this, &AddressBarDialog::displayAddressNotFoundMessage);
2424 connect(addressManager.data(), &AddressManager::lookupResultsFinished, this, &AddressBarDialog::hide);
25+ connect(addressManager.data(), &AddressManager::goBackPossible, this, [this] (bool isPossible) {
26+ if (isPossible != _backEnabled) {
27+ _backEnabled = isPossible;
28+ emit backEnabledChanged();
29+ }
30+ });
31+ connect(addressManager.data(), &AddressManager::goForwardPossible, this, [this] (bool isPossible) {
32+ if (isPossible != _forwardEnabled) {
33+ _forwardEnabled = isPossible;
34+ emit forwardEnabledChanged();
35+ }
36+ });
37+ _backEnabled = !(DependencyManager::get<AddressManager>()->getBackStack().isEmpty());
38+ _forwardEnabled = !(DependencyManager::get<AddressManager>()->getForwardStack().isEmpty());
2539 }
2640
2741 void AddressBarDialog::hide() {
@@ -35,6 +49,16 @@ void AddressBarDialog::loadAddress(const QString& address) { · 7 unmodified lines
3549 }
3650 }
3751
52+void AddressBarDialog::loadBack() {
53+ qDebug() << "Called LoadBack";
54+ DependencyManager::get<AddressManager>()->goBack();
55+}
56+
57+void AddressBarDialog::loadForward() {
58+ qDebug() << "Called LoadForward";
59+ DependencyManager::get<AddressManager>()->goForward();
60+}
61+
3862 void AddressBarDialog::displayAddressOfflineMessage() {
3963 OffscreenUi::error("That user or place is currently offline");
4064 }
interface/src/ui/AddressBarDialog.h+13−0
@@ -18,9 +18,17 @@ class AddressBarDialog : public OffscreenQmlDialog · 17 unmodified lines
1818 {
1919 Q_OBJECT
2020 HIFI_QML_DECL
21+ Q_PROPERTY(bool backEnabled READ backEnabled NOTIFY backEnabledChanged)
22+ Q_PROPERTY(bool forwardEnabled READ forwardEnabled NOTIFY forwardEnabledChanged)
2123
2224 public:
2325 AddressBarDialog(QQuickItem* parent = nullptr);
26+ bool backEnabled() { return _backEnabled; }
27+ bool forwardEnabled() { return _forwardEnabled; }
28+
29+signals:
30+ void backEnabledChanged();
31+ void forwardEnabledChanged();
2432
2533 protected:
2634 void displayAddressOfflineMessage();
@@ -28,6 +36,11 @@ protected: · 1 unmodified line
2836 void hide();
2937
3038 Q_INVOKABLE void loadAddress(const QString& address);
39+ Q_INVOKABLE void loadBack();
40+ Q_INVOKABLE void loadForward();
41+
42+ bool _backEnabled;
43+ bool _forwardEnabled;
3144 };
3245
3346 #endif
interface/src/ui/ApplicationCompositor.cpp+761−0
@@ -0,0 +1,761 @@
1+//
2+// ApplicationCompositor.cpp
3+// interface/src/ui/overlays
4+//
5+// Created by Benjamin Arnold on 5/27/14.
6+// Copyright 2014 High Fidelity, Inc.
7+//
8+// Distributed under the Apache License, Version 2.0.
9+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10+//
11+
12+#include "InterfaceConfig.h"
13+
14+#include "ApplicationCompositor.h"
15+
16+#include <glm/gtc/type_ptr.hpp>
17+
18+#include <avatar/AvatarManager.h>
19+#include <gpu/GLBackend.h>
20+#include <CursorManager.h>
21+#include <Tooltip.h>
22+
23+#include "Application.h"
24+
25+
26+// Used to animate the magnification windows
27+static const float MAG_SPEED = 0.08f;
28+
29+static const quint64 MSECS_TO_USECS = 1000ULL;
30+static const quint64 TOOLTIP_DELAY = 500 * MSECS_TO_USECS;
31+
32+static const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f };
33+static const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f };
34+static const float reticleSize = TWO_PI / 100.0f;
35+
36+static const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f };
37+static const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f;
38+
39+static const float CURSOR_PIXEL_SIZE = 32.0f;
40+static const float MOUSE_PITCH_RANGE = 1.0f * PI;
41+static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI;
42+static const glm::vec2 MOUSE_RANGE(MOUSE_YAW_RANGE, MOUSE_PITCH_RANGE);
43+
44+static gpu::BufferPointer _hemiVertices;
45+static gpu::BufferPointer _hemiIndices;
46+static int _hemiIndexCount{ 0 };
47+EntityItemID ApplicationCompositor::_noItemId;
48+static QString _tooltipId;
49+
50+// Return a point's cartesian coordinates on a sphere from pitch and yaw
51+glm::vec3 getPoint(float yaw, float pitch) {
52+ return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)),
53+ glm::sin(-pitch),
54+ glm::cos(-pitch) * (-glm::cos(yaw)));
55+}
56+
57+//Checks if the given ray intersects the sphere at the origin. result will store a multiplier that should
58+//be multiplied by dir and added to origin to get the location of the collision
59+bool raySphereIntersect(const glm::vec3 &dir, const glm::vec3 &origin, float r, float* result)
60+{
61+ //Source: http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection
62+
63+ //Compute A, B and C coefficients
64+ float a = glm::dot(dir, dir);
65+ float b = 2 * glm::dot(dir, origin);
66+ float c = glm::dot(origin, origin) - (r * r);
67+
68+ //Find discriminant
69+ float disc = b * b - 4 * a * c;
70+
71+ // if discriminant is negative there are no real roots, so return
72+ // false as ray misses sphere
73+ if (disc < 0) {
74+ return false;
75+ }
76+
77+ // compute q as described above
78+ float distSqrt = sqrtf(disc);
79+ float q;
80+ if (b < 0) {
81+ q = (-b - distSqrt) / 2.0f;
82+ } else {
83+ q = (-b + distSqrt) / 2.0f;
84+ }
85+
86+ // compute t0 and t1
87+ float t0 = q / a;
88+ float t1 = c / q;
89+
90+ // make sure t0 is smaller than t1
91+ if (t0 > t1) {
92+ // if t0 is bigger than t1 swap them around
93+ float temp = t0;
94+ t0 = t1;
95+ t1 = temp;
96+ }
97+
98+ // if t1 is less than zero, the object is in the ray's negative direction
99+ // and consequently the ray misses the sphere
100+ if (t1 < 0) {
101+ return false;
102+ }
103+
104+ // if t0 is less than zero, the intersection point is at t1
105+ if (t0 < 0) {
106+ *result = t1;
107+ return true;
108+ } else { // else the intersection point is at t0
109+ *result = t0;
110+ return true;
111+ }
112+}
113+
114+ApplicationCompositor::ApplicationCompositor() {
115+ memset(_reticleActive, 0, sizeof(_reticleActive));
116+ memset(_magActive, 0, sizeof(_reticleActive));
117+ memset(_magSizeMult, 0, sizeof(_magSizeMult));
118+
119+ auto geometryCache = DependencyManager::get<GeometryCache>();
120+
121+ _reticleQuad = geometryCache->allocateID();
122+ _magnifierQuad = geometryCache->allocateID();
123+ _magnifierBorder = geometryCache->allocateID();
124+
125+ auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
126+ connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity, [=](const EntityItemID& entityItemID, const MouseEvent& event) {
127+ if (_hoverItemId != entityItemID) {
128+ _hoverItemId = entityItemID;
129+ _hoverItemEnterUsecs = usecTimestampNow();
130+ auto properties = entityScriptingInterface->getEntityProperties(_hoverItemId);
131+ _hoverItemHref = properties.getHref();
132+ auto cursor = Cursor::Manager::instance().getCursor();
133+ if (!_hoverItemHref.isEmpty()) {
134+ cursor->setIcon(Cursor::Icon::LINK);
135+ } else {
136+ cursor->setIcon(Cursor::Icon::DEFAULT);
137+ }
138+ }
139+ });
140+
141+ connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, [=](const EntityItemID& entityItemID, const MouseEvent& event) {
142+ if (_hoverItemId == entityItemID) {
143+ _hoverItemId = _noItemId;
144+ _hoverItemHref.clear();
145+ auto cursor = Cursor::Manager::instance().getCursor();
146+ cursor->setIcon(Cursor::Icon::DEFAULT);
147+ if (!_tooltipId.isEmpty()) {
148+ qDebug() << "Closing tooltip " << _tooltipId;
149+ Tooltip::closeTip(_tooltipId);
150+ _tooltipId.clear();
151+ }
152+ }
153+ });
154+}
155+
156+ApplicationCompositor::~ApplicationCompositor() {
157+}
158+
159+
160+void ApplicationCompositor::bindCursorTexture(gpu::Batch& batch, uint8_t cursorIndex) {
161+ auto& cursorManager = Cursor::Manager::instance();
162+ auto cursor = cursorManager.getCursor(cursorIndex);
163+ auto iconId = cursor->getIcon();
164+ if (!_cursors.count(iconId)) {
165+ auto iconPath = cursorManager.getIconImage(cursor->getIcon());
166+ _cursors[iconId] = DependencyManager::get<TextureCache>()->
167+ getImageTexture(iconPath);
168+ }
169+ batch.setUniformTexture(0, _cursors[iconId]);
170+}
171+
172+// Draws the FBO texture for the screen
173+void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) {
174+ if (_alpha == 0.0f) {
175+ return;
176+ }
177+
178+ GLuint texture = qApp->getApplicationOverlay().getOverlayTexture();
179+ if (!texture) {
180+ return;
181+ }
182+
183+ updateTooltips();
184+
185+ vec2 canvasSize = qApp->getCanvasSize();
186+
187+ //Handle fading and deactivation/activation of UI
188+ gpu::Batch batch;
189+
190+ renderArgs->_context->syncCache();
191+ auto geometryCache = DependencyManager::get<GeometryCache>();
192+
193+ geometryCache->useSimpleDrawPipeline(batch);
194+ batch.setModelTransform(Transform());
195+ batch.setViewTransform(Transform());
196+ batch.setProjectionTransform(mat4());
197+ batch._glBindTexture(GL_TEXTURE_2D, texture);
198+ batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
199+ batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
200+ geometryCache->renderUnitQuad(batch, vec4(vec3(1), _alpha));
201+
202+ // Doesn't actually render
203+ renderPointers(batch);
204+
205+ //draw the mouse pointer
206+ // Get the mouse coordinates and convert to NDC [-1, 1]
207+ vec2 mousePosition = toNormalizedDeviceScale(vec2(qApp->getMouse()), canvasSize);
208+ // Invert the Y axis
209+ mousePosition.y *= -1.0f;
210+
211+ Transform model;
212+ model.setTranslation(vec3(mousePosition, 0));
213+ vec2 mouseSize = CURSOR_PIXEL_SIZE / canvasSize;
214+ model.setScale(vec3(mouseSize, 1.0f));
215+ batch.setModelTransform(model);
216+ bindCursorTexture(batch);
217+ vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f };
218+ geometryCache->renderUnitQuad(batch, vec4(1));
219+ renderArgs->_context->render(batch);
220+}
221+
222+
223+vec2 getPolarCoordinates(const PalmData& palm) {
224+ MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
225+ auto avatarOrientation = myAvatar->getOrientation();
226+ auto eyePos = myAvatar->getDefaultEyePosition();
227+ glm::vec3 tip = myAvatar->getLaserPointerTipPosition(&palm);
228+ // Direction of the tip relative to the eye
229+ glm::vec3 tipDirection = tip - eyePos;
230+ // orient into avatar space
231+ tipDirection = glm::inverse(avatarOrientation) * tipDirection;
232+ // Normalize for trig functions
233+ tipDirection = glm::normalize(tipDirection);
234+ // Convert to polar coordinates
235+ glm::vec2 polar(glm::atan(tipDirection.x, -tipDirection.z), glm::asin(tipDirection.y));
236+ return polar;
237+}
238+
239+// Draws the FBO texture for Oculus rift.
240+void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int eye) {
241+ if (_alpha == 0.0f) {
242+ return;
243+ }
244+
245+ GLuint texture = qApp->getApplicationOverlay().getOverlayTexture();
246+ if (!texture) {
247+ return;
248+ }
249+
250+ updateTooltips();
251+
252+ vec2 canvasSize = qApp->getCanvasSize();
253+ _textureAspectRatio = aspect(canvasSize);
254+
255+ renderArgs->_context->syncCache();
256+ auto geometryCache = DependencyManager::get<GeometryCache>();
257+
258+ gpu::Batch batch;
259+ geometryCache->useSimpleDrawPipeline(batch);
260+ batch._glDisable(GL_DEPTH_TEST);
261+ batch._glDisable(GL_CULL_FACE);
262+ batch._glBindTexture(GL_TEXTURE_2D, texture);
263+ batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
264+ batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
265+ batch.setViewTransform(Transform());
266+ batch.setProjectionTransform(qApp->getEyeProjection(eye));
267+
268+ mat4 eyePose = qApp->getEyePose(eye);
269+ glm::mat4 overlayXfm = glm::inverse(eyePose);
270+
271+#ifdef DEBUG_OVERLAY
272+ {
273+ batch.setModelTransform(glm::translate(mat4(), vec3(0, 0, -2)));
274+ geometryCache->renderUnitQuad(batch, glm::vec4(1));
275+ }
276+#else
277+ {
278+ batch.setModelTransform(overlayXfm);
279+ drawSphereSection(batch);
280+ }
281+#endif
282+
283+ // Doesn't actually render
284+ renderPointers(batch);
285+ vec3 reticleScale = vec3(Cursor::Manager::instance().getScale() * reticleSize);
286+
287+ bindCursorTexture(batch);
288+
289+ MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
290+ //Controller Pointers
291+ for (int i = 0; i < (int)myAvatar->getHand()->getNumPalms(); i++) {
292+ PalmData& palm = myAvatar->getHand()->getPalms()[i];
293+ if (palm.isActive()) {
294+ glm::vec2 polar = getPolarCoordinates(palm);
295+ // Convert to quaternion
296+ mat4 pointerXfm = glm::mat4_cast(quat(vec3(polar.y, -polar.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1));
297+ mat4 reticleXfm = overlayXfm * pointerXfm;
298+ reticleXfm = glm::scale(reticleXfm, reticleScale);
299+ batch.setModelTransform(reticleXfm);
300+ // Render reticle at location
301+ geometryCache->renderUnitQuad(batch, glm::vec4(1), _reticleQuad);
302+ }
303+ }
304+
305+ //Mouse Pointer
306+ if (_reticleActive[MOUSE]) {
307+ glm::vec2 projection = screenToSpherical(glm::vec2(_reticlePosition[MOUSE].x(),
308+ _reticlePosition[MOUSE].y()));
309+ mat4 pointerXfm = glm::mat4_cast(quat(vec3(-projection.y, projection.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1));
310+ mat4 reticleXfm = overlayXfm * pointerXfm;
311+ reticleXfm = glm::scale(reticleXfm, reticleScale);
312+ batch.setModelTransform(reticleXfm);
313+ geometryCache->renderUnitQuad(batch, glm::vec4(1), _reticleQuad);
314+ }
315+
316+ renderArgs->_context->render(batch);
317+}
318+
319+
320+void ApplicationCompositor::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const {
321+ cursorPos *= qApp->getCanvasSize();
322+ const glm::vec2 projection = screenToSpherical(cursorPos);
323+ // The overlay space orientation of the mouse coordinates
324+ const glm::quat orientation(glm::vec3(-projection.y, projection.x, 0.0f));
325+ // FIXME We now have the direction of the ray FROM THE DEFAULT HEAD POSE.
326+ // Now we need to account for the actual camera position relative to the overlay
327+ glm::vec3 overlaySpaceDirection = glm::normalize(orientation * IDENTITY_FRONT);
328+
329+
330+ // We need the RAW camera orientation and position, because this is what the overlay is
331+ // rendered relative to
332+ const glm::vec3 overlayPosition = qApp->getCamera()->getPosition();
333+ const glm::quat overlayOrientation = qApp->getCamera()->getRotation();
334+
335+ // Intersection UI overlay space
336+ glm::vec3 worldSpaceDirection = overlayOrientation * overlaySpaceDirection;
337+ glm::vec3 worldSpaceIntersection = (glm::normalize(worldSpaceDirection) * _oculusUIRadius) + overlayPosition;
338+ glm::vec3 worldSpaceHeadPosition = (overlayOrientation * glm::vec3(qApp->getHeadPose()[3])) + overlayPosition;
339+
340+ // Intersection in world space
341+ origin = worldSpaceHeadPosition;
342+ direction = glm::normalize(worldSpaceIntersection - worldSpaceHeadPosition);
343+}
344+
345+//Caculate the click location using one of the sixense controllers. Scale is not applied
346+QPoint ApplicationCompositor::getPalmClickLocation(const PalmData *palm) const {
347+ QPoint rv;
348+ auto canvasSize = qApp->getCanvasSize();
349+ if (qApp->isHMDMode()) {
350+ glm::vec2 polar = getPolarCoordinates(*palm);
351+ glm::vec2 point = sphericalToScreen(-polar);
352+ rv.rx() = point.x;
353+ rv.ry() = point.y;
354+ } else {
355+ MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
356+ glm::dmat4 projection;
357+ qApp->getProjectionMatrix(&projection);
358+ glm::quat invOrientation = glm::inverse(myAvatar->getOrientation());
359+ glm::vec3 eyePos = myAvatar->getDefaultEyePosition();
360+ glm::vec3 tip = myAvatar->getLaserPointerTipPosition(palm);
361+ glm::vec3 tipPos = invOrientation * (tip - eyePos);
362+
363+ glm::vec4 clipSpacePos = glm::vec4(projection * glm::dvec4(tipPos, 1.0));
364+ glm::vec3 ndcSpacePos;
365+ if (clipSpacePos.w != 0) {
366+ ndcSpacePos = glm::vec3(clipSpacePos) / clipSpacePos.w;
367+ }
368+
369+ rv.setX(((ndcSpacePos.x + 1.0) / 2.0) * canvasSize.x);
370+ rv.setY((1.0 - ((ndcSpacePos.y + 1.0) / 2.0)) * canvasSize.y);
371+ }
372+ return rv;
373+}
374+
375+//Finds the collision point of a world space ray
376+bool ApplicationCompositor::calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const {
377+ MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
378+
379+ glm::quat inverseOrientation = glm::inverse(myAvatar->getOrientation());
380+
381+ glm::vec3 relativePosition = inverseOrientation * (position - myAvatar->getDefaultEyePosition());
382+ glm::vec3 relativeDirection = glm::normalize(inverseOrientation * direction);
383+
384+ float t;
385+ if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getScale(), &t)){
386+ result = position + direction * t;
387+ return true;
388+ }
389+
390+ return false;
391+}
392+
393+//Renders optional pointers
394+void ApplicationCompositor::renderPointers(gpu::Batch& batch) {
395+ if (qApp->isHMDMode() && !qApp->getLastMouseMoveWasSimulated() && !qApp->isMouseHidden()) {
396+ //If we are in oculus, render reticle later
397+ QPoint position = QPoint(qApp->getTrueMouseX(), qApp->getTrueMouseY());
398+ _reticlePosition[MOUSE] = position;
399+ _reticleActive[MOUSE] = true;
400+ _magActive[MOUSE] = _magnifier;
401+ _reticleActive[LEFT_CONTROLLER] = false;
402+ _reticleActive[RIGHT_CONTROLLER] = false;
403+ } else if (qApp->getLastMouseMoveWasSimulated() && Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) {
404+ //only render controller pointer if we aren't already rendering a mouse pointer
405+ _reticleActive[MOUSE] = false;
406+ _magActive[MOUSE] = false;
407+ renderControllerPointers(batch);
408+ }
409+}
410+
411+
412+void ApplicationCompositor::renderControllerPointers(gpu::Batch& batch) {
413+ MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
414+
415+ //Static variables used for storing controller state
416+ static quint64 pressedTime[NUMBER_OF_RETICLES] = { 0ULL, 0ULL, 0ULL };
417+ static bool isPressed[NUMBER_OF_RETICLES] = { false, false, false };
418+ static bool stateWhenPressed[NUMBER_OF_RETICLES] = { false, false, false };
419+
420+ const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
421+
422+ for (unsigned int palmIndex = 2; palmIndex < 4; palmIndex++) {
423+ const int index = palmIndex - 1;
424+
425+ const PalmData* palmData = NULL;
426+
427+ if (palmIndex >= handData->getPalms().size()) {
428+ return;
429+ }
430+
431+ if (handData->getPalms()[palmIndex].isActive()) {
432+ palmData = &handData->getPalms()[palmIndex];
433+ } else {
434+ continue;
435+ }
436+
437+ int controllerButtons = palmData->getControllerButtons();
438+
439+ //Check for if we should toggle or drag the magnification window
440+ if (controllerButtons & BUTTON_3) {
441+ if (isPressed[index] == false) {
442+ //We are now dragging the window
443+ isPressed[index] = true;
444+ //set the pressed time in us
445+ pressedTime[index] = usecTimestampNow();
446+ stateWhenPressed[index] = _magActive[index];
447+ }
448+ } else if (isPressed[index]) {
449+ isPressed[index] = false;
450+ //If the button was only pressed for < 250 ms
451+ //then disable it.
452+
453+ const int MAX_BUTTON_PRESS_TIME = 250 * MSECS_TO_USECS;
454+ if (usecTimestampNow() < pressedTime[index] + MAX_BUTTON_PRESS_TIME) {
455+ _magActive[index] = !stateWhenPressed[index];
456+ }
457+ }
458+
459+ //if we have the oculus, we should make the cursor smaller since it will be
460+ //magnified
461+ if (qApp->isHMDMode()) {
462+
463+ QPoint point = getPalmClickLocation(palmData);
464+
465+ _reticlePosition[index] = point;
466+
467+ //When button 2 is pressed we drag the mag window
468+ if (isPressed[index]) {
469+ _magActive[index] = true;
470+ }
471+
472+ // If oculus is enabled, we draw the crosshairs later
473+ continue;
474+ }
475+
476+ auto canvasSize = qApp->getCanvasSize();
477+ int mouseX, mouseY;
478+ if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) {
479+ QPoint res = getPalmClickLocation(palmData);
480+ mouseX = res.x();
481+ mouseY = res.y();
482+ } else {
483+ // Get directon relative to avatar orientation
484+ glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * palmData->getFingerDirection();
485+
486+ // Get the angles, scaled between (-0.5,0.5)
487+ float xAngle = (atan2(direction.z, direction.x) + M_PI_2);
488+ float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2));
489+
490+ // Get the pixel range over which the xAngle and yAngle are scaled
491+ float cursorRange = canvasSize.x * SixenseManager::getInstance().getCursorPixelRangeMult();
492+
493+ mouseX = (canvasSize.x / 2.0f + cursorRange * xAngle);
494+ mouseY = (canvasSize.y / 2.0f + cursorRange * yAngle);
495+ }
496+
497+ //If the cursor is out of the screen then don't render it
498+ if (mouseX < 0 || mouseX >= (int)canvasSize.x || mouseY < 0 || mouseY >= (int)canvasSize.y) {
499+ _reticleActive[index] = false;
500+ continue;
501+ }
502+ _reticleActive[index] = true;
503+
504+
505+ const float reticleSize = 40.0f;
506+
507+ mouseX -= reticleSize / 2.0f;
508+ mouseY += reticleSize / 2.0f;
509+
510+
511+ glm::vec2 topLeft(mouseX, mouseY);
512+ glm::vec2 bottomRight(mouseX + reticleSize, mouseY - reticleSize);
513+ glm::vec2 texCoordTopLeft(0.0f, 0.0f);
514+ glm::vec2 texCoordBottomRight(1.0f, 1.0f);
515+
516+ DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
517+ glm::vec4(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f));
518+
519+ }
520+}
521+
522+//Renders a small magnification of the currently bound texture at the coordinates
523+void ApplicationCompositor::renderMagnifier(gpu::Batch& batch, const glm::vec2& magPos, float sizeMult, bool showBorder) {
524+ if (!_magnifier) {
525+ return;
526+ }
527+ auto canvasSize = qApp->getCanvasSize();
528+
529+ const int widgetWidth = canvasSize.x;
530+ const int widgetHeight = canvasSize.y;
531+
532+ const float halfWidth = (MAGNIFY_WIDTH / _textureAspectRatio) * sizeMult / 2.0f;
533+ const float halfHeight = MAGNIFY_HEIGHT * sizeMult / 2.0f;
534+ // Magnification Texture Coordinates
535+ const float magnifyULeft = (magPos.x - halfWidth) / (float)widgetWidth;
536+ const float magnifyURight = (magPos.x + halfWidth) / (float)widgetWidth;
537+ const float magnifyVTop = 1.0f - (magPos.y - halfHeight) / (float)widgetHeight;
538+ const float magnifyVBottom = 1.0f - (magPos.y + halfHeight) / (float)widgetHeight;
539+
540+ const float newHalfWidth = halfWidth * MAGNIFY_MULT;
541+ const float newHalfHeight = halfHeight * MAGNIFY_MULT;
542+ //Get yaw / pitch value for the corners
543+ const glm::vec2 topLeftYawPitch = overlayToSpherical(glm::vec2(magPos.x - newHalfWidth,
544+ magPos.y - newHalfHeight));
545+ const glm::vec2 bottomRightYawPitch = overlayToSpherical(glm::vec2(magPos.x + newHalfWidth,
546+ magPos.y + newHalfHeight));
547+
548+ const glm::vec3 bottomLeft = getPoint(topLeftYawPitch.x, bottomRightYawPitch.y);
549+ const glm::vec3 bottomRight = getPoint(bottomRightYawPitch.x, bottomRightYawPitch.y);
550+ const glm::vec3 topLeft = getPoint(topLeftYawPitch.x, topLeftYawPitch.y);
551+ const glm::vec3 topRight = getPoint(bottomRightYawPitch.x, topLeftYawPitch.y);
552+
553+ auto geometryCache = DependencyManager::get<GeometryCache>();
554+
555+ if (bottomLeft != _previousMagnifierBottomLeft || bottomRight != _previousMagnifierBottomRight
556+ || topLeft != _previousMagnifierTopLeft || topRight != _previousMagnifierTopRight) {
557+ QVector<glm::vec3> border;
558+ border << topLeft;
559+ border << bottomLeft;
560+ border << bottomRight;
561+ border << topRight;
562+ border << topLeft;
563+ geometryCache->updateVertices(_magnifierBorder, border, glm::vec4(1.0f, 0.0f, 0.0f, _alpha));
564+
565+ _previousMagnifierBottomLeft = bottomLeft;
566+ _previousMagnifierBottomRight = bottomRight;
567+ _previousMagnifierTopLeft = topLeft;
568+ _previousMagnifierTopRight = topRight;
569+ }
570+
571+ glPushMatrix(); {
572+ if (showBorder) {
573+ glDisable(GL_TEXTURE_2D);
574+ glLineWidth(1.0f);
575+ //Outer Line
576+ geometryCache->renderVertices(gpu::LINE_STRIP, _magnifierBorder);
577+ glEnable(GL_TEXTURE_2D);
578+ }
579+ glm::vec4 magnifierColor = { 1.0f, 1.0f, 1.0f, _alpha };
580+
581+ DependencyManager::get<GeometryCache>()->renderQuad(bottomLeft, bottomRight, topRight, topLeft,
582+ glm::vec2(magnifyULeft, magnifyVBottom),
583+ glm::vec2(magnifyURight, magnifyVBottom),
584+ glm::vec2(magnifyURight, magnifyVTop),
585+ glm::vec2(magnifyULeft, magnifyVTop),
586+ magnifierColor, _magnifierQuad);
587+
588+ } glPopMatrix();
589+}
590+
591+void ApplicationCompositor::buildHemiVertices(
592+ const float fov, const float aspectRatio, const int slices, const int stacks) {
593+ static float textureFOV = 0.0f, textureAspectRatio = 1.0f;
594+ if (textureFOV == fov && textureAspectRatio == aspectRatio) {
595+ return;
596+ }
597+
598+ textureFOV = fov;
599+ textureAspectRatio = aspectRatio;
600+
601+ auto geometryCache = DependencyManager::get<GeometryCache>();
602+
603+ _hemiVertices = gpu::BufferPointer(new gpu::Buffer());
604+ _hemiIndices = gpu::BufferPointer(new gpu::Buffer());
605+
606+
607+ if (fov >= PI) {
608+ qDebug() << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues";
609+ }
610+
611+ //UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm
612+
613+ vec3 pos;
614+ vec2 uv;
615+ // Compute vertices positions and texture UV coordinate
616+ // Create and write to buffer
617+ for (int i = 0; i < stacks; i++) {
618+ uv.y = (float)i / (float)(stacks - 1); // First stack is 0.0f, last stack is 1.0f
619+ // abs(theta) <= fov / 2.0f
620+ float pitch = -fov * (uv.y - 0.5f);
621+ for (int j = 0; j < slices; j++) {
622+ uv.x = (float)j / (float)(slices - 1); // First slice is 0.0f, last slice is 1.0f
623+ // abs(phi) <= fov * aspectRatio / 2.0f
624+ float yaw = -fov * aspectRatio * (uv.x - 0.5f);
625+ pos = getPoint(yaw, pitch);
626+ static const vec4 color(1);
627+ _hemiVertices->append(sizeof(pos), (gpu::Byte*)&pos);
628+ _hemiVertices->append(sizeof(vec2), (gpu::Byte*)&uv);
629+ _hemiVertices->append(sizeof(vec4), (gpu::Byte*)&color);
630+ }
631+ }
632+
633+ // Compute number of indices needed
634+ static const int VERTEX_PER_TRANGLE = 3;
635+ static const int TRIANGLE_PER_RECTANGLE = 2;
636+ int numberOfRectangles = (slices - 1) * (stacks - 1);
637+ _hemiIndexCount = numberOfRectangles * TRIANGLE_PER_RECTANGLE * VERTEX_PER_TRANGLE;
638+
639+ // Compute indices order
640+ std::vector<GLushort> indices;
641+ for (int i = 0; i < stacks - 1; i++) {
642+ for (int j = 0; j < slices - 1; j++) {
643+ GLushort bottomLeftIndex = i * slices + j;
644+ GLushort bottomRightIndex = bottomLeftIndex + 1;
645+ GLushort topLeftIndex = bottomLeftIndex + slices;
646+ GLushort topRightIndex = topLeftIndex + 1;
647+ // FIXME make a z-order curve for better vertex cache locality
648+ indices.push_back(topLeftIndex);
649+ indices.push_back(bottomLeftIndex);
650+ indices.push_back(topRightIndex);
651+
652+ indices.push_back(topRightIndex);
653+ indices.push_back(bottomLeftIndex);
654+ indices.push_back(bottomRightIndex);
655+ }
656+ }
657+ _hemiIndices->append(sizeof(GLushort) * indices.size(), (gpu::Byte*)&indices[0]);
658+}
659+
660+
661+void ApplicationCompositor::drawSphereSection(gpu::Batch& batch) {
662+ buildHemiVertices(_textureFov, _textureAspectRatio, 80, 80);
663+ static const int VERTEX_DATA_SLOT = 0;
664+ static const int TEXTURE_DATA_SLOT = 1;
665+ static const int COLOR_DATA_SLOT = 2;
666+ gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format()); // 1 for everyone
667+ streamFormat->setAttribute(gpu::Stream::POSITION, VERTEX_DATA_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
668+ streamFormat->setAttribute(gpu::Stream::TEXCOORD, TEXTURE_DATA_SLOT, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
669+ streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_DATA_SLOT, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::RGBA));
670+ batch.setInputFormat(streamFormat);
671+
672+ static const int VERTEX_STRIDE = sizeof(vec3) + sizeof(vec2) + sizeof(vec4);
673+ gpu::BufferView posView(_hemiVertices, 0, _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::POSITION)._element);
674+ gpu::BufferView uvView(_hemiVertices, sizeof(vec3), _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::TEXCOORD)._element);
675+ gpu::BufferView colView(_hemiVertices, sizeof(vec3) + sizeof(vec2), _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element);
676+ batch.setInputBuffer(VERTEX_DATA_SLOT, posView);
677+ batch.setInputBuffer(TEXTURE_DATA_SLOT, uvView);
678+ batch.setInputBuffer(COLOR_DATA_SLOT, colView);
679+ batch.setIndexBuffer(gpu::UINT16, _hemiIndices, 0);
680+ batch.drawIndexed(gpu::TRIANGLES, _hemiIndexCount);
681+}
682+
683+glm::vec2 ApplicationCompositor::directionToSpherical(const glm::vec3& direction) {
684+ glm::vec2 result;
685+ // Compute yaw
686+ glm::vec3 normalProjection = glm::normalize(glm::vec3(direction.x, 0.0f, direction.z));
687+ result.x = glm::acos(glm::dot(IDENTITY_FRONT, normalProjection));
688+ if (glm::dot(IDENTITY_RIGHT, normalProjection) > 0.0f) {
689+ result.x = -glm::abs(result.x);
690+ } else {
691+ result.x = glm::abs(result.x);
692+ }
693+ // Compute pitch
694+ result.y = angleBetween(IDENTITY_UP, direction) - PI_OVER_TWO;
695+
696+ return result;
697+}
698+
699+glm::vec3 ApplicationCompositor::sphericalToDirection(const glm::vec2& sphericalPos) {
700+ glm::quat rotation(glm::vec3(sphericalPos.y, sphericalPos.x, 0.0f));
701+ return rotation * IDENTITY_FRONT;
702+}
703+
704+glm::vec2 ApplicationCompositor::screenToSpherical(const glm::vec2& screenPos) {
705+ auto screenSize = qApp->getCanvasSize();
706+ glm::vec2 result;
707+ result.x = -(screenPos.x / screenSize.x - 0.5f);
708+ result.y = (screenPos.y / screenSize.y - 0.5f);
709+ result.x *= MOUSE_YAW_RANGE;
710+ result.y *= MOUSE_PITCH_RANGE;
711+
712+ return result;
713+}
714+
715+glm::vec2 ApplicationCompositor::sphericalToScreen(const glm::vec2& sphericalPos) {
716+ glm::vec2 result = sphericalPos;
717+ result.x *= -1.0;
718+ result /= MOUSE_RANGE;
719+ result += 0.5f;
720+ result *= qApp->getCanvasSize();
721+ return result;
722+}
723+
724+glm::vec2 ApplicationCompositor::sphericalToOverlay(const glm::vec2& sphericalPos) const {
725+ glm::vec2 result = sphericalPos;
726+ result.x *= -1.0;
727+ result /= _textureFov;
728+ result.x /= _textureAspectRatio;
729+ result += 0.5f;
730+ result *= qApp->getCanvasSize();
731+ return result;
732+}
733+
734+glm::vec2 ApplicationCompositor::overlayToSpherical(const glm::vec2& overlayPos) const {
735+ glm::vec2 result = overlayPos;
736+ result /= qApp->getCanvasSize();
737+ result -= 0.5f;
738+ result *= _textureFov;
739+ result.x *= _textureAspectRatio;
740+ result.x *= -1.0f;
741+ return result;
742+}
743+
744+glm::vec2 ApplicationCompositor::screenToOverlay(const glm::vec2& screenPos) const {
745+ return sphericalToOverlay(screenToSpherical(screenPos));
746+}
747+
748+glm::vec2 ApplicationCompositor::overlayToScreen(const glm::vec2& overlayPos) const {
749+ return sphericalToScreen(overlayToSpherical(overlayPos));
750+}
751+
752+void ApplicationCompositor::updateTooltips() {
753+ if (_hoverItemId != _noItemId) {
754+ quint64 hoverDuration = usecTimestampNow() - _hoverItemEnterUsecs;
755+ if (_hoverItemEnterUsecs != UINT64_MAX && !_hoverItemHref.isEmpty() && hoverDuration > TOOLTIP_DELAY) {
756+ // TODO Enable and position the tooltip
757+ _hoverItemEnterUsecs = UINT64_MAX;
758+ _tooltipId = Tooltip::showTip("URL: " + _hoverItemHref);
759+ }
760+ }
761+}
interface/src/ui/ApplicationCompositor.h+120−0
@@ -0,0 +1,120 @@
1+//
2+// Created by Bradley Austin Davis Arnold on 2015/06/13
3+// Copyright 2015 High Fidelity, Inc.
4+//
5+// Distributed under the Apache License, Version 2.0.
6+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
7+//
8+
9+#ifndef hifi_ApplicationCompositor_h
10+#define hifi_ApplicationCompositor_h
11+
12+#include <QObject>
13+#include <cstdint>
14+
15+#include <EntityItemID.h>
16+#include <GeometryCache.h>
17+#include <GLMHelpers.h>
18+#include <gpu/Batch.h>
19+#include <gpu/Texture.h>
20+
21+class Camera;
22+class PalmData;
23+class RenderArgs;
24+
25+const float MAGNIFY_WIDTH = 220.0f;
26+const float MAGNIFY_HEIGHT = 100.0f;
27+const float MAGNIFY_MULT = 2.0f;
28+
29+const float DEFAULT_HMD_UI_ANGULAR_SIZE = 72.0f;
30+
31+// Handles the drawing of the overlays to the screen
32+// TODO, move divide up the rendering, displaying and input handling
33+// facilities of this class
34+class ApplicationCompositor : public QObject {
35+ Q_OBJECT
36+public:
37+ ApplicationCompositor();
38+ ~ApplicationCompositor();
39+
40+ void displayOverlayTexture(RenderArgs* renderArgs);
41+ void displayOverlayTextureHmd(RenderArgs* renderArgs, int eye);
42+
43+ QPoint getPalmClickLocation(const PalmData *palm) const;
44+ bool calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const;
45+
46+ bool hasMagnifier() const { return _magnifier; }
47+ void toggleMagnifier() { _magnifier = !_magnifier; }
48+
49+ float getHmdUIAngularSize() const { return _hmdUIAngularSize; }
50+ void setHmdUIAngularSize(float hmdUIAngularSize) { _hmdUIAngularSize = hmdUIAngularSize; }
51+
52+ // Converter from one frame of reference to another.
53+ // Frame of reference:
54+ // Direction: Ray that represents the spherical values
55+ // Screen: Position on the screen (x,y)
56+ // Spherical: Pitch and yaw that gives the position on the sphere we project on (yaw,pitch)
57+ // Overlay: Position on the overlay (x,y)
58+ // (x,y) in Overlay are similar than (x,y) in Screen except they can be outside of the bound of te screen.
59+ // This allows for picking outside of the screen projection in 3D.
60+ glm::vec2 sphericalToOverlay(const glm::vec2 & sphericalPos) const;
61+ glm::vec2 overlayToSpherical(const glm::vec2 & overlayPos) const;
62+ glm::vec2 screenToOverlay(const glm::vec2 & screenPos) const;
63+ glm::vec2 overlayToScreen(const glm::vec2 & overlayPos) const;
64+ void computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const;
65+ GLuint getOverlayTexture() const;
66+
67+ static glm::vec2 directionToSpherical(const glm::vec3 & direction);
68+ static glm::vec3 sphericalToDirection(const glm::vec2 & sphericalPos);
69+ static glm::vec2 screenToSpherical(const glm::vec2 & screenPos);
70+ static glm::vec2 sphericalToScreen(const glm::vec2 & sphericalPos);
71+
72+private:
73+ void displayOverlayTextureStereo(RenderArgs* renderArgs, float aspectRatio, float fov);
74+ void bindCursorTexture(gpu::Batch& batch, uint8_t cursorId = 0);
75+ void buildHemiVertices(const float fov, const float aspectRatio, const int slices, const int stacks);
76+ void drawSphereSection(gpu::Batch& batch);
77+ void updateTooltips();
78+
79+ void renderPointers(gpu::Batch& batch);
80+ void renderMagnifier(gpu::Batch& batch, const glm::vec2& magPos, float sizeMult, bool showBorder);
81+ void renderControllerPointers(gpu::Batch& batch);
82+ void renderPointersOculus(gpu::Batch& batch);
83+
84+ // Support for hovering and tooltips
85+ static EntityItemID _noItemId;
86+ EntityItemID _hoverItemId{ _noItemId };
87+ QString _hoverItemHref;
88+ quint64 _hoverItemEnterUsecs{ 0 };
89+
90+ float _hmdUIAngularSize = DEFAULT_HMD_UI_ANGULAR_SIZE;
91+ float _textureFov{ glm::radians(DEFAULT_HMD_UI_ANGULAR_SIZE) };
92+ float _textureAspectRatio{ 1.0f };
93+ int _hemiVerticesID{ GeometryCache::UNKNOWN_ID };
94+
95+ enum Reticles { MOUSE, LEFT_CONTROLLER, RIGHT_CONTROLLER, NUMBER_OF_RETICLES };
96+ bool _reticleActive[NUMBER_OF_RETICLES];
97+ QPoint _reticlePosition[NUMBER_OF_RETICLES];
98+ bool _magActive[NUMBER_OF_RETICLES];
99+ float _magSizeMult[NUMBER_OF_RETICLES];
100+ bool _magnifier{ true };
101+
102+ float _alpha{ 1.0f };
103+ float _oculusUIRadius{ 1.0f };
104+
105+ QMap<uint16_t, gpu::TexturePointer> _cursors;
106+
107+ int _reticleQuad;
108+ int _magnifierQuad;
109+ int _magnifierBorder;
110+
111+ int _previousBorderWidth{ -1 };
112+ int _previousBorderHeight{ -1 };
113+
114+ glm::vec3 _previousMagnifierBottomLeft;
115+ glm::vec3 _previousMagnifierBottomRight;
116+ glm::vec3 _previousMagnifierTopLeft;
117+ glm::vec3 _previousMagnifierTopRight;
118+};
119+
120+#endif // hifi_ApplicationCompositor_h
interface/src/ui/ApplicationOverlay.cpp+116−1172
@@ -14,166 +14,58 @@ · 13 unmodified lines
1414 #include <QOpenGLFramebufferObject>
1515 #include <QOpenGLTexture>
1616
17+#include <glm/gtc/type_ptr.hpp>
18+
1719 #include <avatar/AvatarManager.h>
20+#include <DeferredLightingEffect.h>
1821 #include <GLMHelpers.h>
19−#include <PathUtils.h>
2022 #include <gpu/GLBackend.h>
23+#include <gpu/GLBackendShared.h>
2124 #include <GLMHelpers.h>
22−#include <PerfStat.h>
2325 #include <OffscreenUi.h>
26+#include <CursorManager.h>
27+#include <PerfStat.h>
2428
2529 #include "AudioClient.h"
2630 #include "audio/AudioIOStatsRenderer.h"
2731 #include "audio/AudioScope.h"
28−#include "audio/AudioToolBox.h"
2932 #include "Application.h"
3033 #include "ApplicationOverlay.h"
31−#include "devices/CameraToolBox.h"
3234
3335 #include "Util.h"
3436 #include "ui/Stats.h"
35−
36−// Used to animate the magnification windows
37−const float MAG_SPEED = 0.08f;
38−
39−const quint64 MSECS_TO_USECS = 1000ULL;
37+#include "ui/AvatarInputs.h"
4038
4139 const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f };
42−const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f };
43−const float reticleSize = TWO_PI / 100.0f;
44−
45−
46−const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f };
40+const int AUDIO_METER_GAP = 5;
41+const int MUTE_ICON_PADDING = 10;
42+const vec4 CONNECTION_STATUS_BORDER_COLOR{ 1.0f, 0.0f, 0.0f, 0.8f };
4743 const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f;
44+static const float ORTHO_NEAR_CLIP = -10000;
45+static const float ORTHO_FAR_CLIP = 10000;
4846
49−static const float MOUSE_PITCH_RANGE = 1.0f * PI;
50−static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI;
51−static const glm::vec2 MOUSE_RANGE(MOUSE_YAW_RANGE, MOUSE_PITCH_RANGE);
52−
53−// Return a point's cartesian coordinates on a sphere from pitch and yaw
54−glm::vec3 getPoint(float yaw, float pitch) {
55− return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)),
56− glm::sin(-pitch),
57− glm::cos(-pitch) * (-glm::cos(yaw)));
47+// TODO move somewhere useful
48+static void fboViewport(QOpenGLFramebufferObject* fbo) {
49+ auto size = fbo->size();
50+ glViewport(0, 0, size.width(), size.height());
5851 }
5952
60−//Checks if the given ray intersects the sphere at the origin. result will store a multiplier that should
61−//be multiplied by dir and added to origin to get the location of the collision
62−bool raySphereIntersect(const glm::vec3 &dir, const glm::vec3 &origin, float r, float* result)
53+ApplicationOverlay::ApplicationOverlay()
6354 {
64− //Source: http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection
65−
66− //Compute A, B and C coefficients
67− float a = glm::dot(dir, dir);
68− float b = 2 * glm::dot(dir, origin);
69− float c = glm::dot(origin, origin) - (r * r);
70−
71− //Find discriminant
72− float disc = b * b - 4 * a * c;
73−
74− // if discriminant is negative there are no real roots, so return
75− // false as ray misses sphere
76− if (disc < 0) {
77− return false;
78− }
79−
80− // compute q as described above
81− float distSqrt = sqrtf(disc);
82− float q;
83− if (b < 0) {
84− q = (-b - distSqrt) / 2.0;
85− } else {
86− q = (-b + distSqrt) / 2.0;
87− }
88−
89− // compute t0 and t1
90− float t0 = q / a;
91− float t1 = c / q;
92−
93− // make sure t0 is smaller than t1
94− if (t0 > t1) {
95− // if t0 is bigger than t1 swap them around
96− float temp = t0;
97− t0 = t1;
98− t1 = temp;
99− }
100−
101− // if t1 is less than zero, the object is in the ray's negative direction
102− // and consequently the ray misses the sphere
103− if (t1 < 0) {
104− return false;
105− }
106−
107− // if t0 is less than zero, the intersection point is at t1
108− if (t0 < 0) {
109− *result = t1;
110− return true;
111− } else { // else the intersection point is at t0
112− *result = t0;
113− return true;
114− }
115−}
116−
117−void ApplicationOverlay::renderReticle(glm::quat orientation, float alpha) {
118− glPushMatrix(); {
119− glm::vec3 axis = glm::axis(orientation);
120− glRotatef(glm::degrees(glm::angle(orientation)), axis.x, axis.y, axis.z);
121− glm::vec3 topLeft = getPoint(reticleSize / 2.0f, -reticleSize / 2.0f);
122− glm::vec3 topRight = getPoint(-reticleSize / 2.0f, -reticleSize / 2.0f);
123− glm::vec3 bottomLeft = getPoint(reticleSize / 2.0f, reticleSize / 2.0f);
124− glm::vec3 bottomRight = getPoint(-reticleSize / 2.0f, reticleSize / 2.0f);
125−
126− // TODO: this version of renderQuad() needs to take a color
127− glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], alpha };
128−
129−
130−
131− DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomLeft, bottomRight, topRight,
132− glm::vec2(0.0f, 0.0f), glm::vec2(1.0f, 0.0f),
133− glm::vec2(1.0f, 1.0f), glm::vec2(0.0f, 1.0f),
134− reticleColor, _reticleQuad);
135− } glPopMatrix();
136−}
137−
138−ApplicationOverlay::ApplicationOverlay() :
139− _textureFov(glm::radians(DEFAULT_HMD_UI_ANGULAR_SIZE)),
140− _textureAspectRatio(1.0f),
141− _lastMouseMove(0),
142− _magnifier(true),
143− _alpha(1.0f),
144− _oculusUIRadius(1.0f),
145− _trailingAudioLoudness(0.0f),
146− _previousBorderWidth(-1),
147− _previousBorderHeight(-1),
148− _previousMagnifierBottomLeft(),
149− _previousMagnifierBottomRight(),
150− _previousMagnifierTopLeft(),
151− _previousMagnifierTopRight()
152−{
153− memset(_reticleActive, 0, sizeof(_reticleActive));
154− memset(_magActive, 0, sizeof(_reticleActive));
155− memset(_magSizeMult, 0, sizeof(_magSizeMult));
156−
15755 auto geometryCache = DependencyManager::get<GeometryCache>();
158−
159− _reticleQuad = geometryCache->allocateID();
160− _magnifierQuad = geometryCache->allocateID();
161− _audioRedQuad = geometryCache->allocateID();
162− _audioGreenQuad = geometryCache->allocateID();
163− _audioBlueQuad = geometryCache->allocateID();
16456 _domainStatusBorder = geometryCache->allocateID();
16557 _magnifierBorder = geometryCache->allocateID();
166−
58+
16759 // Once we move UI rendering and screen rendering to different
16860 // threads, we need to use a sync object to deteremine when
169− // the current UI texture is no longer being read from, and only
61+ // the current UI texture is no longer being read from, and only
17062 // then release it back to the UI for re-use
17163 auto offscreenUi = DependencyManager::get<OffscreenUi>();
17264 connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [&](GLuint textureId) {
17365 auto offscreenUi = DependencyManager::get<OffscreenUi>();
17466 offscreenUi->lockTexture(textureId);
17567 assert(!glGetError());
176− std::swap(_newUiTexture, textureId);
68+ std::swap(_uiTexture, textureId);
17769 if (textureId) {
17870 offscreenUi->releaseTexture(textureId);
17971 }
@@ -185,846 +77,81 @@ ApplicationOverlay::~ApplicationOverlay() { · 5 unmodified lines
18577
18678 // Renders the overlays either to a texture or to the screen
18779 void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
80+ CHECK_GL_ERROR();
18881 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");
189− Overlays& overlays = qApp->getOverlays();
190−
191− _textureFov = glm::radians(_hmdUIAngularSize);
192− glm::vec2 size = qApp->getCanvasSize();
193− _textureAspectRatio = aspect(size);
19482
195− //Handle fading and deactivation/activation of UI
196−
197− // Render 2D overlay
198− glMatrixMode(GL_PROJECTION);
199− glDisable(GL_DEPTH_TEST);
200− glDisable(GL_LIGHTING);
201− glEnable(GL_BLEND);
202− glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
203− _overlays.buildFramebufferObject();
204− _overlays.bind();
205− glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
206− glViewport(0, 0, size.x, size.y);
83+ // TODO move to Application::idle()?
84+ Stats::getInstance()->updateStats();
85+ AvatarInputs::getInstance()->update();
20786
208− glPushMatrix(); {
209− const float NEAR_CLIP = -10000;
210− const float FAR_CLIP = 10000;
211− glLoadIdentity();
212− glOrtho(0, size.x, size.y, 0, NEAR_CLIP, FAR_CLIP);
87+ buildFramebufferObject();
21388
214− glMatrixMode(GL_MODELVIEW);
215−
216− renderAudioMeter();
217− renderCameraToggle();
218−
219− renderStatsAndLogs();
220−
221− // give external parties a change to hook in
222− emit qApp->renderingOverlay();
223−
224− overlays.renderHUD(renderArgs);
225−
226− renderPointers();
227−
228− renderDomainConnectionStatusBorder();
229−
230− glMatrixMode(GL_PROJECTION);
231− } glPopMatrix();
232−
233− glMatrixMode(GL_MODELVIEW);
234− glEnable(GL_DEPTH_TEST);
235− glEnable(GL_LIGHTING);
236− glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
237−
238− _overlays.release();
239−}
89+ // Execute the batch into our framebuffer
90+ _overlayFramebuffer->bind();
91+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
92+ fboViewport(_overlayFramebuffer);
24093
241−// A quick and dirty solution for compositing the old overlay
242−// texture with the new one
243−template <typename F>
244−void with_each_texture(GLuint firstPassTexture, GLuint secondPassTexture, F f) {
245− glEnable(GL_TEXTURE_2D);
246− glActiveTexture(GL_TEXTURE0);
247− if (firstPassTexture) {
248− glBindTexture(GL_TEXTURE_2D, firstPassTexture);
249− f();
250− }
251− if (secondPassTexture) {
252− glBindTexture(GL_TEXTURE_2D, secondPassTexture);
253− f();
254− }
255− glBindTexture(GL_TEXTURE_2D, 0);
256− glDisable(GL_TEXTURE_2D);
94+ // Now render the overlay components together into a single texture
95+ renderOverlays(renderArgs);
96+ renderStatsAndLogs(renderArgs);
97+ renderDomainConnectionStatusBorder(renderArgs);
98+ renderQmlUi(renderArgs);
99+ _overlayFramebuffer->release();
100+ CHECK_GL_ERROR();
257101 }
258102
259−// Draws the FBO texture for the screen
260−void ApplicationOverlay::displayOverlayTexture() {
261− if (_alpha == 0.0f) {
262− return;
103+void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) {
104+ if (_uiTexture) {
105+ gpu::Batch batch;
106+ auto geometryCache = DependencyManager::get<GeometryCache>();
107+ geometryCache->useSimpleDrawPipeline(batch);
108+ batch.setProjectionTransform(mat4());
109+ batch.setModelTransform(mat4());
110+ batch._glBindTexture(GL_TEXTURE_2D, _uiTexture);
111+ geometryCache->renderUnitQuad(batch, glm::vec4(1));
112+ renderArgs->_context->syncCache();
113+ renderArgs->_context->render(batch);
263114 }
264− glMatrixMode(GL_PROJECTION);
265− glPushMatrix(); {
266− glLoadIdentity();
267− glDisable(GL_DEPTH_TEST);
268− glDisable(GL_LIGHTING);
269− glEnable(GL_BLEND);
270− glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
271− glViewport(0, 0, qApp->getDeviceSize().width(), qApp->getDeviceSize().height());
272−
273− static const glm::vec2 topLeft(-1, 1);
274− static const glm::vec2 bottomRight(1, -1);
275− static const glm::vec2 texCoordTopLeft(0.0f, 1.0f);
276− static const glm::vec2 texCoordBottomRight(1.0f, 0.0f);
277− with_each_texture(_overlays.getTexture(), _newUiTexture, [&] {
278− DependencyManager::get<GeometryCache>()->renderQuad(
279− topLeft, bottomRight,
280− texCoordTopLeft, texCoordBottomRight,
281− glm::vec4(1.0f, 1.0f, 1.0f, _alpha));
282− });
283−
284− if (!_crosshairTexture) {
285− _crosshairTexture = DependencyManager::get<TextureCache>()->
286− getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png");
287− }
288−
289− //draw the mouse pointer
290− glm::vec2 canvasSize = qApp->getCanvasSize();
291− glm::vec2 mouseSize = 32.0f / canvasSize;
292− auto mouseTopLeft = topLeft * mouseSize;
293− auto mouseBottomRight = bottomRight * mouseSize;
294− vec2 mousePosition = vec2(qApp->getMouseX(), qApp->getMouseY());
295− mousePosition /= canvasSize;
296− mousePosition *= 2.0f;
297− mousePosition -= 1.0f;
298− mousePosition.y *= -1.0f;
299−
300− glEnable(GL_TEXTURE_2D);
301− glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
302− glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
303− glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f };
304− DependencyManager::get<GeometryCache>()->renderQuad(
305− mouseTopLeft + mousePosition, mouseBottomRight + mousePosition,
306− texCoordTopLeft, texCoordBottomRight,
307− reticleColor);
308− glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
309− glDisable(GL_TEXTURE_2D);
310− } glPopMatrix();
311115 }
312116
313−// Draws the FBO texture for Oculus rift.
314−void ApplicationOverlay::displayOverlayTextureHmd(Camera& whichCamera) {
315− if (_alpha == 0.0f) {
316− return;
317− }
318−
319− glEnable(GL_BLEND);
320− glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
321− glEnable(GL_DEPTH_TEST);
322− glDepthMask(GL_TRUE);
323− glDisable(GL_LIGHTING);
324− glEnable(GL_ALPHA_TEST);
325− glAlphaFunc(GL_GREATER, 0.01f);
326−
117+void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) {
118+ glm::vec2 size = qApp->getCanvasSize();
327119
328− //Update and draw the magnifiers
329− MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
330− const glm::quat& orientation = myAvatar->getOrientation();
331− // Always display the HMD overlay relative to the camera position but
332− // remove the HMD pose offset. This results in an overlay that sticks with you
333− // even in third person mode, but isn't drawn at a fixed distance.
334− glm::vec3 position = whichCamera.getPosition();
335− position -= qApp->getCamera()->getHmdPosition();
336− const float scale = myAvatar->getScale() * _oculusUIRadius;
337−
338−// glm::vec3 eyeOffset = setEyeOffsetPosition;
120+ mat4 legacyProjection = glm::ortho<float>(0, size.x, size.y, 0, ORTHO_NEAR_CLIP, ORTHO_FAR_CLIP);
121+ glMatrixMode(GL_PROJECTION);
122+ glPushMatrix();
123+ glLoadMatrixf(glm::value_ptr(legacyProjection));
339124 glMatrixMode(GL_MODELVIEW);
340− glPushMatrix(); {
341− glTranslatef(position.x, position.y, position.z);
342− glm::mat4 rotation = glm::toMat4(orientation);
343− glMultMatrixf(&rotation[0][0]);
344− glScalef(scale, scale, scale);
345− for (int i = 0; i < NUMBER_OF_RETICLES; i++) {
346−
347− if (_magActive[i]) {
348− _magSizeMult[i] += MAG_SPEED;
349− if (_magSizeMult[i] > 1.0f) {
350− _magSizeMult[i] = 1.0f;
351− }
352− } else {
353− _magSizeMult[i] -= MAG_SPEED;
354− if (_magSizeMult[i] < 0.0f) {
355− _magSizeMult[i] = 0.0f;
356− }
357− }
358−
359− if (_magSizeMult[i] > 0.0f) {
360− //Render magnifier, but dont show border for mouse magnifier
361− glm::vec2 projection = screenToOverlay(glm::vec2(_reticlePosition[MOUSE].x(),
362− _reticlePosition[MOUSE].y()));
363− with_each_texture(_overlays.getTexture(), 0, [&] {
364− renderMagnifier(projection, _magSizeMult[i], i != MOUSE);
365− });
366− }
367− }
368−
369− glDepthMask(GL_FALSE);
370− glDisable(GL_ALPHA_TEST);
371−
372− static float textureFOV = 0.0f, textureAspectRatio = 1.0f;
373− if (textureFOV != _textureFov ||
374− textureAspectRatio != _textureAspectRatio) {
375− textureFOV = _textureFov;
376− textureAspectRatio = _textureAspectRatio;
377−
378− _overlays.buildVBO(_textureFov, _textureAspectRatio, 80, 80);
379− }
380125
381− with_each_texture(_overlays.getTexture(), _newUiTexture, [&] {
382− _overlays.render();
383− });
384−
385− if (!Application::getInstance()->isMouseHidden()) {
386− renderPointersOculus();
387− }
388− glDepthMask(GL_TRUE);
389− glDisable(GL_TEXTURE_2D);
390−
391− glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
392− glEnable(GL_LIGHTING);
393− } glPopMatrix();
394−}
395−
396−// Draws the FBO texture for 3DTV.
397−void ApplicationOverlay::displayOverlayTextureStereo(Camera& whichCamera, float aspectRatio, float fov) {
398− if (_alpha == 0.0f) {
399− return;
400− }
401−
402− MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
403− const glm::vec3& viewMatrixTranslation = qApp->getViewMatrixTranslation();
404−
405− glEnable(GL_BLEND);
406− glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
407− glEnable(GL_DEPTH_TEST);
408− glDisable(GL_LIGHTING);
409−
410− glMatrixMode(GL_MODELVIEW);
411−
412− glPushMatrix();
413− glLoadIdentity();
414− // Transform to world space
415− glm::quat rotation = whichCamera.getRotation();
416− glm::vec3 axis2 = glm::axis(rotation);
417− glRotatef(-glm::degrees(glm::angle(rotation)), axis2.x, axis2.y, axis2.z);
418− glTranslatef(viewMatrixTranslation.x, viewMatrixTranslation.y, viewMatrixTranslation.z);
419−
420− // Translate to the front of the camera
421− glm::vec3 pos = whichCamera.getPosition();
422− glm::quat rot = myAvatar->getOrientation();
423− glm::vec3 axis = glm::axis(rot);
424−
425− glTranslatef(pos.x, pos.y, pos.z);
426− glRotatef(glm::degrees(glm::angle(rot)), axis.x, axis.y, axis.z);
427−
428− glm::vec4 overlayColor = {1.0f, 1.0f, 1.0f, _alpha};
429−
430− //Render
431− const GLfloat distance = 1.0f;
432−
433− const GLfloat halfQuadHeight = distance * tan(fov);
434− const GLfloat halfQuadWidth = halfQuadHeight * aspectRatio;
435− const GLfloat quadWidth = halfQuadWidth * 2.0f;
436− const GLfloat quadHeight = halfQuadHeight * 2.0f;
437−
438− GLfloat x = -halfQuadWidth;
439− GLfloat y = -halfQuadHeight;
440126 glDisable(GL_DEPTH_TEST);
441−
442− with_each_texture(_overlays.getTexture(), _newUiTexture, [&] {
443− DependencyManager::get<GeometryCache>()->renderQuad(glm::vec3(x, y + quadHeight, -distance),
444− glm::vec3(x + quadWidth, y + quadHeight, -distance),
445− glm::vec3(x + quadWidth, y, -distance),
446− glm::vec3(x, y, -distance),
447− glm::vec2(0.0f, 1.0f), glm::vec2(1.0f, 1.0f),
448− glm::vec2(1.0f, 0.0f), glm::vec2(0.0f, 0.0f),
449− overlayColor);
450− });
451−
452− if (!_crosshairTexture) {
453− _crosshairTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() +
454− "images/sixense-reticle.png");
455− }
456−
457− //draw the mouse pointer
127+ glDisable(GL_LIGHTING);
458128 glEnable(GL_BLEND);
459129 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
460− glEnable(GL_TEXTURE_2D);
461− glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
462− glm::vec2 canvasSize = qApp->getCanvasSize();
463− const float reticleSize = 40.0f / canvasSize.x * quadWidth;
464− x -= reticleSize / 2.0f;
465− y += reticleSize / 2.0f;
466− const float mouseX = (qApp->getMouseX() / (float)canvasSize.x) * quadWidth;
467− const float mouseY = (1.0 - (qApp->getMouseY() / (float)canvasSize.y)) * quadHeight;
468−
469− glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f };
470130
471− DependencyManager::get<GeometryCache>()->renderQuad(glm::vec3(x + mouseX, y + mouseY, -distance),
472− glm::vec3(x + mouseX + reticleSize, y + mouseY, -distance),
473− glm::vec3(x + mouseX + reticleSize, y + mouseY - reticleSize, -distance),
474− glm::vec3(x + mouseX, y + mouseY - reticleSize, -distance),
475− glm::vec2(0.0f, 0.0f), glm::vec2(1.0f, 0.0f),
476− glm::vec2(1.0f, 1.0f), glm::vec2(0.0f, 1.0f),
477− reticleColor, _reticleQuad);
131+ // give external parties a change to hook in
132+ emit qApp->renderingOverlay();
133+ qApp->getOverlays().renderHUD(renderArgs);
478134
479− glEnable(GL_DEPTH_TEST);
480−
135+ glMatrixMode(GL_PROJECTION);
481136 glPopMatrix();
482−
483− glDepthMask(GL_TRUE);
484− glBindTexture(GL_TEXTURE_2D, 0);
485− glDisable(GL_TEXTURE_2D);
486−
487− glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
488− glEnable(GL_LIGHTING);
489−}
490−
491−void ApplicationOverlay::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const {
492− cursorPos *= qApp->getCanvasSize();
493− const glm::vec2 projection = screenToSpherical(cursorPos);
494− // The overlay space orientation of the mouse coordinates
495− const glm::quat orientation(glm::vec3(-projection.y, projection.x, 0.0f));
496− // FIXME We now have the direction of the ray FROM THE DEFAULT HEAD POSE.
497− // Now we need to account for the actual camera position relative to the overlay
498− glm::vec3 overlaySpaceDirection = glm::normalize(orientation * IDENTITY_FRONT);
499−
500−
501− const glm::vec3& hmdPosition = qApp->getCamera()->getHmdPosition();
502− const glm::quat& hmdOrientation = qApp->getCamera()->getHmdRotation();
503−
504− // We need the RAW camera orientation and position, because this is what the overlay is
505− // rendered relative to
506− const glm::vec3 overlayPosition = qApp->getCamera()->getPosition() - hmdPosition;
507− const glm::quat overlayOrientation = qApp->getCamera()->getRotation() * glm::inverse(hmdOrientation);
508−
509− // Intersection UI overlay space
510− glm::vec3 worldSpaceDirection = overlayOrientation * overlaySpaceDirection;
511− glm::vec3 intersectionWithUi = glm::normalize(worldSpaceDirection) * _oculusUIRadius;
512− intersectionWithUi += overlayPosition;
513−
514− // Intersection in world space
515− origin = overlayPosition + hmdPosition;
516− direction = glm::normalize(intersectionWithUi - origin);
517−}
518−
519−glm::vec2 getPolarCoordinates(const PalmData& palm) {
520− MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
521− auto avatarOrientation = myAvatar->getOrientation();
522− auto eyePos = myAvatar->getDefaultEyePosition();
523− glm::vec3 tip = myAvatar->getLaserPointerTipPosition(&palm);
524− // Direction of the tip relative to the eye
525− glm::vec3 tipDirection = tip - eyePos;
526− // orient into avatar space
527− tipDirection = glm::inverse(avatarOrientation) * tipDirection;
528− // Normalize for trig functions
529− tipDirection = glm::normalize(tipDirection);
530− // Convert to polar coordinates
531− glm::vec2 polar(glm::atan(tipDirection.x, -tipDirection.z), glm::asin(tipDirection.y));
532− return polar;
533−}
534−
535−//Caculate the click location using one of the sixense controllers. Scale is not applied
536−QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const {
537− QPoint rv;
538− auto canvasSize = qApp->getCanvasSize();
539− if (qApp->isHMDMode()) {
540− glm::vec2 polar = getPolarCoordinates(*palm);
541− glm::vec2 point = sphericalToScreen(-polar);
542− rv.rx() = point.x;
543− rv.ry() = point.y;
544− } else {
545− MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
546− glm::dmat4 projection;
547− qApp->getProjectionMatrix(&projection);
548− glm::quat invOrientation = glm::inverse(myAvatar->getOrientation());
549− glm::vec3 eyePos = myAvatar->getDefaultEyePosition();
550− glm::vec3 tip = myAvatar->getLaserPointerTipPosition(palm);
551− glm::vec3 tipPos = invOrientation * (tip - eyePos);
552−
553− glm::vec4 clipSpacePos = glm::vec4(projection * glm::dvec4(tipPos, 1.0));
554− glm::vec3 ndcSpacePos;
555− if (clipSpacePos.w != 0) {
556− ndcSpacePos = glm::vec3(clipSpacePos) / clipSpacePos.w;
557− }
558−
559− rv.setX(((ndcSpacePos.x + 1.0) / 2.0) * canvasSize.x);
560− rv.setY((1.0 - ((ndcSpacePos.y + 1.0) / 2.0)) * canvasSize.y);
561− }
562− return rv;
563−}
564−
565−//Finds the collision point of a world space ray
566−bool ApplicationOverlay::calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const {
567− MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
568−
569− glm::quat inverseOrientation = glm::inverse(myAvatar->getOrientation());
570−
571− glm::vec3 relativePosition = inverseOrientation * (position - myAvatar->getDefaultEyePosition());
572− glm::vec3 relativeDirection = glm::normalize(inverseOrientation * direction);
573−
574− float t;
575− if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getScale(), &t)){
576− result = position + direction * t;
577− return true;
578− }
579−
580− return false;
581−}
582−
583−//Renders optional pointers
584−void ApplicationOverlay::renderPointers() {
585− //lazily load crosshair texture
586− if (_crosshairTexture == 0) {
587− _crosshairTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png");
588− }
589− glEnable(GL_TEXTURE_2D);
590− glEnable(GL_BLEND);
591− glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
592−
593− //glActiveTexture(GL_TEXTURE0);
594− //bindCursorTexture();
595−
596− if (qApp->isHMDMode() && !qApp->getLastMouseMoveWasSimulated() && !qApp->isMouseHidden()) {
597− //If we are in oculus, render reticle later
598− if (_lastMouseMove == 0) {
599− _lastMouseMove = usecTimestampNow();
600− }
601− QPoint position = QPoint(qApp->getTrueMouseX(), qApp->getTrueMouseY());
602−
603− static const int MAX_IDLE_TIME = 3;
604− if (_reticlePosition[MOUSE] != position) {
605− _lastMouseMove = usecTimestampNow();
606− } else if (usecTimestampNow() - _lastMouseMove > MAX_IDLE_TIME * USECS_PER_SECOND) {
607− //float pitch = 0.0f, yaw = 0.0f, roll = 0.0f; // radians
608− //OculusManager::getEulerAngles(yaw, pitch, roll);
609− glm::quat orientation = qApp->getHeadOrientation(); // (glm::vec3(pitch, yaw, roll));
610− glm::vec3 result;
611−
612− MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
613− if (calculateRayUICollisionPoint(myAvatar->getEyePosition(),
614− myAvatar->getOrientation() * orientation * IDENTITY_FRONT,
615− result)) {
616− glm::vec3 lookAtDirection = glm::inverse(myAvatar->getOrientation()) * (result - myAvatar->getDefaultEyePosition());
617− glm::vec2 spericalPos = directionToSpherical(glm::normalize(lookAtDirection));
618− glm::vec2 screenPos = sphericalToScreen(spericalPos);
619− position = QPoint(screenPos.x, screenPos.y);
620− // FIXME
621− //glCanvas->cursor().setPos(glCanvas->mapToGlobal(position));
622− } else {
623− qDebug() << "No collision point";
624− }
625− }
626−
627− _reticlePosition[MOUSE] = position;
628− _reticleActive[MOUSE] = true;
629− _magActive[MOUSE] = _magnifier;
630− _reticleActive[LEFT_CONTROLLER] = false;
631− _reticleActive[RIGHT_CONTROLLER] = false;
632− } else if (qApp->getLastMouseMoveWasSimulated() && Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) {
633− _lastMouseMove = 0;
634− //only render controller pointer if we aren't already rendering a mouse pointer
635− _reticleActive[MOUSE] = false;
636− _magActive[MOUSE] = false;
637− renderControllerPointers();
638− }
639− //glBindTexture(GL_TEXTURE_2D, 0);
640− //glDisable(GL_TEXTURE_2D);
641−}
642−
643−void ApplicationOverlay::renderControllerPointers() {
644− MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
645−
646− //Static variables used for storing controller state
647− static quint64 pressedTime[NUMBER_OF_RETICLES] = { 0ULL, 0ULL, 0ULL };
648− static bool isPressed[NUMBER_OF_RETICLES] = { false, false, false };
649− static bool stateWhenPressed[NUMBER_OF_RETICLES] = { false, false, false };
650−
651− const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
652−
653− for (unsigned int palmIndex = 2; palmIndex < 4; palmIndex++) {
654− const int index = palmIndex - 1;
655−
656− const PalmData* palmData = NULL;
657−
658− if (palmIndex >= handData->getPalms().size()) {
659− return;
660− }
661−
662− if (handData->getPalms()[palmIndex].isActive()) {
663− palmData = &handData->getPalms()[palmIndex];
664− } else {
665− continue;
666− }
667−
668− int controllerButtons = palmData->getControllerButtons();
669−
670− //Check for if we should toggle or drag the magnification window
671− if (controllerButtons & BUTTON_3) {
672− if (isPressed[index] == false) {
673− //We are now dragging the window
674− isPressed[index] = true;
675− //set the pressed time in us
676− pressedTime[index] = usecTimestampNow();
677− stateWhenPressed[index] = _magActive[index];
678− }
679− } else if (isPressed[index]) {
680− isPressed[index] = false;
681− //If the button was only pressed for < 250 ms
682− //then disable it.
683−
684− const int MAX_BUTTON_PRESS_TIME = 250 * MSECS_TO_USECS;
685− if (usecTimestampNow() < pressedTime[index] + MAX_BUTTON_PRESS_TIME) {
686− _magActive[index] = !stateWhenPressed[index];
687− }
688− }
689−
690− //if we have the oculus, we should make the cursor smaller since it will be
691− //magnified
692− if (qApp->isHMDMode()) {
693−
694− QPoint point = getPalmClickLocation(palmData);
695−
696− _reticlePosition[index] = point;
697−
698− //When button 2 is pressed we drag the mag window
699− if (isPressed[index]) {
700− _magActive[index] = true;
701− }
702−
703− // If oculus is enabled, we draw the crosshairs later
704− continue;
705− }
706−
707− auto canvasSize = qApp->getCanvasSize();
708− int mouseX, mouseY;
709− if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) {
710− QPoint res = getPalmClickLocation(palmData);
711− mouseX = res.x();
712− mouseY = res.y();
713− } else {
714− // Get directon relative to avatar orientation
715− glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * palmData->getFingerDirection();
716−
717− // Get the angles, scaled between (-0.5,0.5)
718− float xAngle = (atan2(direction.z, direction.x) + M_PI_2);
719− float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2));
720−
721− // Get the pixel range over which the xAngle and yAngle are scaled
722− float cursorRange = canvasSize.x * SixenseManager::getInstance().getCursorPixelRangeMult();
723−
724− mouseX = (canvasSize.x / 2.0f + cursorRange * xAngle);
725− mouseY = (canvasSize.y / 2.0f + cursorRange * yAngle);
726− }
727−
728− //If the cursor is out of the screen then don't render it
729− if (mouseX < 0 || mouseX >= (int)canvasSize.x || mouseY < 0 || mouseY >= (int)canvasSize.y) {
730− _reticleActive[index] = false;
731− continue;
732− }
733− _reticleActive[index] = true;
734−
735−
736− const float reticleSize = 40.0f;
737−
738− mouseX -= reticleSize / 2.0f;
739− mouseY += reticleSize / 2.0f;
740−
741−
742− glm::vec2 topLeft(mouseX, mouseY);
743− glm::vec2 bottomRight(mouseX + reticleSize, mouseY - reticleSize);
744− glm::vec2 texCoordTopLeft(0.0f, 0.0f);
745− glm::vec2 texCoordBottomRight(1.0f, 1.0f);
746−
747− DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
748− glm::vec4(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f));
749−
750− }
751−}
752−
753−void ApplicationOverlay::renderPointersOculus() {
754−
755− glEnable(GL_BLEND);
756− glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
757− glEnable(GL_TEXTURE_2D);
758−
759− glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
760− glDisable(GL_DEPTH_TEST);
761−
762137 glMatrixMode(GL_MODELVIEW);
763−
764− //Controller Pointers
765− MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
766− for (int i = 0; i < (int)myAvatar->getHand()->getNumPalms(); i++) {
767− PalmData& palm = myAvatar->getHand()->getPalms()[i];
768− if (palm.isActive()) {
769− glm::vec2 polar = getPolarCoordinates(palm);
770− // Convert to quaternion
771− glm::quat orientation = glm::quat(glm::vec3(polar.y, -polar.x, 0.0f));
772− // Render reticle at location
773− renderReticle(orientation, _alpha);
774− }
775− }
776−
777− //Mouse Pointer
778− if (_reticleActive[MOUSE]) {
779− glm::vec2 projection = screenToSpherical(glm::vec2(_reticlePosition[MOUSE].x(),
780− _reticlePosition[MOUSE].y()));
781− glm::quat orientation(glm::vec3(-projection.y, projection.x, 0.0f));
782− renderReticle(orientation, _alpha);
783− }
784138
785− glEnable(GL_DEPTH_TEST);
786− glDisable(GL_TEXTURE_2D);
787− glDisable(GL_BLEND);
139+ renderArgs->_context->syncCache();
140+ fboViewport(_overlayFramebuffer);
788141 }
789142
790−//Renders a small magnification of the currently bound texture at the coordinates
791−void ApplicationOverlay::renderMagnifier(glm::vec2 magPos, float sizeMult, bool showBorder) {
792− if (!_magnifier) {
793− return;
794− }
795− auto canvasSize = qApp->getCanvasSize();
796−
797− const int widgetWidth = canvasSize.x;
798− const int widgetHeight = canvasSize.y;
799−
800− const float halfWidth = (MAGNIFY_WIDTH / _textureAspectRatio) * sizeMult / 2.0f;
801− const float halfHeight = MAGNIFY_HEIGHT * sizeMult / 2.0f;
802− // Magnification Texture Coordinates
803− const float magnifyULeft = (magPos.x - halfWidth) / (float)widgetWidth;
804− const float magnifyURight = (magPos.x + halfWidth) / (float)widgetWidth;
805− const float magnifyVTop = 1.0f - (magPos.y - halfHeight) / (float)widgetHeight;
806− const float magnifyVBottom = 1.0f - (magPos.y + halfHeight) / (float)widgetHeight;
807−
808− const float newHalfWidth = halfWidth * MAGNIFY_MULT;
809− const float newHalfHeight = halfHeight * MAGNIFY_MULT;
810− //Get yaw / pitch value for the corners
811− const glm::vec2 topLeftYawPitch = overlayToSpherical(glm::vec2(magPos.x - newHalfWidth,
812− magPos.y - newHalfHeight));
813− const glm::vec2 bottomRightYawPitch = overlayToSpherical(glm::vec2(magPos.x + newHalfWidth,
814− magPos.y + newHalfHeight));
815−
816− const glm::vec3 bottomLeft = getPoint(topLeftYawPitch.x, bottomRightYawPitch.y);
817− const glm::vec3 bottomRight = getPoint(bottomRightYawPitch.x, bottomRightYawPitch.y);
818− const glm::vec3 topLeft = getPoint(topLeftYawPitch.x, topLeftYawPitch.y);
819− const glm::vec3 topRight = getPoint(bottomRightYawPitch.x, topLeftYawPitch.y);
820−
821− auto geometryCache = DependencyManager::get<GeometryCache>();
822−
823− if (bottomLeft != _previousMagnifierBottomLeft || bottomRight != _previousMagnifierBottomRight
824− || topLeft != _previousMagnifierTopLeft || topRight != _previousMagnifierTopRight) {
825− QVector<glm::vec3> border;
826− border << topLeft;
827− border << bottomLeft;
828− border << bottomRight;
829− border << topRight;
830− border << topLeft;
831− geometryCache->updateVertices(_magnifierBorder, border, glm::vec4(1.0f, 0.0f, 0.0f, _alpha));
832−
833− _previousMagnifierBottomLeft = bottomLeft;
834− _previousMagnifierBottomRight = bottomRight;
835− _previousMagnifierTopLeft = topLeft;
836− _previousMagnifierTopRight = topRight;
837− }
838−
839− glPushMatrix(); {
840− if (showBorder) {
841− glDisable(GL_TEXTURE_2D);
842− glLineWidth(1.0f);
843− //Outer Line
844− geometryCache->renderVertices(gpu::LINE_STRIP, _magnifierBorder);
845− glEnable(GL_TEXTURE_2D);
846− }
847− glm::vec4 magnifierColor = { 1.0f, 1.0f, 1.0f, _alpha };
848−
849− DependencyManager::get<GeometryCache>()->renderQuad(bottomLeft, bottomRight, topRight, topLeft,
850− glm::vec2(magnifyULeft, magnifyVBottom),
851− glm::vec2(magnifyURight, magnifyVBottom),
852− glm::vec2(magnifyURight, magnifyVTop),
853− glm::vec2(magnifyULeft, magnifyVTop),
854− magnifierColor, _magnifierQuad);
855−
856− } glPopMatrix();
143+void ApplicationOverlay::renderRearViewToFbo(RenderArgs* renderArgs) {
857144 }
858145
859−const int AUDIO_METER_GAP = 5;
860−const int MUTE_ICON_PADDING = 10;
861−
862−void ApplicationOverlay::renderCameraToggle() {
863− if (Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking)) {
864− return;
865− }
866−
867− int audioMeterY;
868− bool smallMirrorVisible = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !qApp->isHMDMode();
869− bool boxed = smallMirrorVisible &&
870− !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror);
871− if (boxed) {
872− audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_GAP + MUTE_ICON_PADDING;
873− } else {
874− audioMeterY = AUDIO_METER_GAP + MUTE_ICON_PADDING;
875− }
876−
877− DependencyManager::get<CameraToolBox>()->render(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP, audioMeterY, boxed);
146+void ApplicationOverlay::renderRearView(RenderArgs* renderArgs) {
878147 }
879148
880−void ApplicationOverlay::renderAudioMeter() {
881− auto audio = DependencyManager::get<AudioClient>();
882−
883− // Audio VU Meter and Mute Icon
884− const int MUTE_ICON_SIZE = 24;
885− const int AUDIO_METER_HEIGHT = 8;
886− const int INTER_ICON_GAP = 2;
887−
888− int cameraSpace = 0;
889− int audioMeterWidth = MIRROR_VIEW_WIDTH - MUTE_ICON_SIZE - MUTE_ICON_PADDING;
890− int audioMeterScaleWidth = audioMeterWidth - 2;
891− int audioMeterX = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_GAP;
892− if (!Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking)) {
893− cameraSpace = MUTE_ICON_SIZE + INTER_ICON_GAP;
894− audioMeterWidth -= cameraSpace;
895− audioMeterScaleWidth -= cameraSpace;
896− audioMeterX += cameraSpace;
897− }
898−
899− int audioMeterY;
900− bool smallMirrorVisible = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !qApp->isHMDMode();
901− bool boxed = smallMirrorVisible &&
902− !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror);
903− if (boxed) {
904− audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_GAP + MUTE_ICON_PADDING;
905− } else {
906− audioMeterY = AUDIO_METER_GAP + MUTE_ICON_PADDING;
907− }
908−
909− const glm::vec4 AUDIO_METER_BLUE = { 0.0, 0.0, 1.0, 1.0 };
910− const glm::vec4 AUDIO_METER_GREEN = { 0.0, 1.0, 0.0, 1.0 };
911− const glm::vec4 AUDIO_METER_RED = { 1.0, 0.0, 0.0, 1.0 };
912− const float CLIPPING_INDICATOR_TIME = 1.0f;
913− const float AUDIO_METER_AVERAGING = 0.5;
914− const float LOG2 = log(2.0f);
915− const float METER_LOUDNESS_SCALE = 2.8f / 5.0f;
916− const float LOG2_LOUDNESS_FLOOR = 11.0f;
917− float audioGreenStart = 0.25f * audioMeterScaleWidth;
918− float audioRedStart = 0.8f * audioMeterScaleWidth;
919− float audioLevel = 0.0f;
920− float loudness = audio->getLastInputLoudness() + 1.0f;
921−
922− _trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.0f - AUDIO_METER_AVERAGING) * loudness;
923− float log2loudness = log(_trailingAudioLoudness) / LOG2;
924−
925− if (log2loudness <= LOG2_LOUDNESS_FLOOR) {
926− audioLevel = (log2loudness / LOG2_LOUDNESS_FLOOR) * METER_LOUDNESS_SCALE * audioMeterScaleWidth;
927− } else {
928− audioLevel = (log2loudness - (LOG2_LOUDNESS_FLOOR - 1.0f)) * METER_LOUDNESS_SCALE * audioMeterScaleWidth;
929− }
930− if (audioLevel > audioMeterScaleWidth) {
931− audioLevel = audioMeterScaleWidth;
932− }
933− bool isClipping = ((audio->getTimeSinceLastClip() > 0.0f) && (audio->getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME));
934−
935− DependencyManager::get<AudioToolBox>()->render(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP, audioMeterY, cameraSpace, boxed);
936−
937− auto canvasSize = qApp->getCanvasSize();
938− DependencyManager::get<AudioScope>()->render(canvasSize.x, canvasSize.y);
939− DependencyManager::get<AudioIOStatsRenderer>()->render(WHITE_TEXT, canvasSize.x, canvasSize.y);
940−
941− audioMeterY += AUDIO_METER_HEIGHT;
942−
943− // Draw audio meter background Quad
944− DependencyManager::get<GeometryCache>()->renderQuad(audioMeterX, audioMeterY, audioMeterWidth, AUDIO_METER_HEIGHT,
945− glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
946−
947− if (audioLevel > audioRedStart) {
948− glm::vec4 quadColor;
949− if (!isClipping) {
950− quadColor = AUDIO_METER_RED;
951− } else {
952− quadColor = glm::vec4(1, 1, 1, 1);
953− }
954− // Draw Red Quad
955− DependencyManager::get<GeometryCache>()->renderQuad(audioMeterX + audioRedStart,
956− audioMeterY,
957− audioLevel - audioRedStart,
958− AUDIO_METER_HEIGHT, quadColor,
959− _audioRedQuad);
960−
961− audioLevel = audioRedStart;
962− }
963−
964− if (audioLevel > audioGreenStart) {
965− glm::vec4 quadColor;
966− if (!isClipping) {
967− quadColor = AUDIO_METER_GREEN;
968− } else {
969− quadColor = glm::vec4(1, 1, 1, 1);
970− }
971− // Draw Green Quad
972− DependencyManager::get<GeometryCache>()->renderQuad(audioMeterX + audioGreenStart,
973− audioMeterY,
974− audioLevel - audioGreenStart,
975− AUDIO_METER_HEIGHT, quadColor,
976− _audioGreenQuad);
977−
978− audioLevel = audioGreenStart;
979− }
980−
981− if (audioLevel >= 0) {
982− glm::vec4 quadColor;
983− if (!isClipping) {
984− quadColor = AUDIO_METER_BLUE;
985− } else {
986− quadColor = glm::vec4(1, 1, 1, 1);
987− }
988− // Draw Blue (low level) quad
989− DependencyManager::get<GeometryCache>()->renderQuad(audioMeterX,
990− audioMeterY,
991− audioLevel, AUDIO_METER_HEIGHT, quadColor,
992− _audioBlueQuad);
993− }
994−}
995−
996−void ApplicationOverlay::renderStatsAndLogs() {
997− Application* application = Application::getInstance();
998− QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
999−
1000− const OctreePacketProcessor& octreePacketProcessor = application->getOctreePacketProcessor();
1001− NodeBounds& nodeBoundsDisplay = application->getNodeBoundsDisplay();
1002−
149+void ApplicationOverlay::renderStatsAndLogs(RenderArgs* renderArgs) {
1003150 // Display stats and log text onscreen
1004− glLineWidth(1.0f);
1005− glPointSize(1.0f);
1006151
1007152 // Determine whether to compute timing details
1008− bool shouldDisplayTimingDetail = Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) &&
1009− Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
1010− Stats::getInstance()->isExpanded();
1011− if (shouldDisplayTimingDetail != PerformanceTimer::isActive()) {
1012− PerformanceTimer::setActive(shouldDisplayTimingDetail);
1013− }
1014−
1015− if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
1016− // let's set horizontal offset to give stats some margin to mirror
1017− int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2;
1018− int voxelPacketsToProcess = octreePacketProcessor.packetsToProcessCount();
1019− // Onscreen text about position, servers, etc
1020− Stats::getInstance()->display(WHITE_TEXT, horizontalOffset, application->getFps(),
1021− bandwidthRecorder->getCachedTotalAverageInputPacketsPerSecond(),
1022− bandwidthRecorder->getCachedTotalAverageOutputPacketsPerSecond(),
1023− bandwidthRecorder->getCachedTotalAverageInputKilobitsPerSecond(),
1024− bandwidthRecorder->getCachedTotalAverageOutputKilobitsPerSecond(),
1025− voxelPacketsToProcess);
1026− }
1027153
154+ /*
1028155 // Show on-screen msec timer
1029156 if (Menu::getInstance()->isOptionChecked(MenuOption::FrameTimer)) {
1030157 auto canvasSize = qApp->getCanvasSize();
@@ -1036,159 +163,77 @@ void ApplicationOverlay::renderStatsAndLogs() { · 5 unmodified lines
1036163 drawText(canvasSize.x - 100, canvasSize.y - timerBottom,
1037164 0.30f, 0.0f, 0, frameTimer.toUtf8().constData(), WHITE_TEXT);
1038165 }
166+
167+ glPointSize(1.0f);
168+ glDisable(GL_DEPTH_TEST);
169+ glDisable(GL_LIGHTING);
170+ glEnable(GL_BLEND);
171+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
172+ NodeBounds& nodeBoundsDisplay = qApp->getNodeBoundsDisplay();
1039173 nodeBoundsDisplay.drawOverlay();
174+ glEnable(GL_DEPTH_TEST);
175+ glEnable(GL_LIGHTING);
176+ glEnable(GL_BLEND);
177+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
178+ fboViewport(_overlayFramebuffer);
179+ */
1040180 }
1041181
1042−void ApplicationOverlay::renderDomainConnectionStatusBorder() {
182+void ApplicationOverlay::renderDomainConnectionStatusBorder(RenderArgs* renderArgs) {
183+ auto geometryCache = DependencyManager::get<GeometryCache>();
184+ static std::once_flag once;
185+ std::call_once(once, [&] {
186+ QVector<vec2> points;
187+ static const float B = 0.99f;
188+ points.push_back(vec2(-B));
189+ points.push_back(vec2(B, -B));
190+ points.push_back(vec2(B));
191+ points.push_back(vec2(-B, B));
192+ points.push_back(vec2(-B));
193+ geometryCache->updateVertices(_domainStatusBorder, points, CONNECTION_STATUS_BORDER_COLOR);
194+ });
1043195 auto nodeList = DependencyManager::get<NodeList>();
1044−
1045196 if (nodeList && !nodeList->getDomainHandler().isConnected()) {
197+ gpu::Batch batch;
1046198 auto geometryCache = DependencyManager::get<GeometryCache>();
1047− auto canvasSize = qApp->getCanvasSize();
1048− if ((int)canvasSize.x != _previousBorderWidth || (int)canvasSize.y != _previousBorderHeight) {
1049− glm::vec4 color(CONNECTION_STATUS_BORDER_COLOR[0],
1050− CONNECTION_STATUS_BORDER_COLOR[1],
1051− CONNECTION_STATUS_BORDER_COLOR[2], 1.0f);
1052−
1053− QVector<glm::vec2> border;
1054− border << glm::vec2(0, 0);
1055− border << glm::vec2(0, canvasSize.y);
1056− border << glm::vec2(canvasSize.x, canvasSize.y);
1057− border << glm::vec2(canvasSize.x, 0);
1058− border << glm::vec2(0, 0);
1059− geometryCache->updateVertices(_domainStatusBorder, border, color);
1060− _previousBorderWidth = canvasSize.x;
1061− _previousBorderHeight = canvasSize.y;
1062− }
1063−
1064− glLineWidth(CONNECTION_STATUS_BORDER_LINE_WIDTH);
1065−
1066− geometryCache->renderVertices(gpu::LINE_STRIP, _domainStatusBorder);
1067− }
1068−}
199+ geometryCache->useSimpleDrawPipeline(batch);
200+ batch.setProjectionTransform(mat4());
201+ batch.setModelTransform(mat4());
202+ batch.setUniformTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture());
203+ batch._glLineWidth(CONNECTION_STATUS_BORDER_LINE_WIDTH);
1069204
1070−ApplicationOverlay::TexturedHemisphere::TexturedHemisphere() :
1071− _vertices(0),
1072− _indices(0),
1073− _framebufferObject(NULL),
1074− _vbo(0, 0) {
1075−}
1076−
1077−ApplicationOverlay::TexturedHemisphere::~TexturedHemisphere() {
1078− cleanupVBO();
1079− if (_framebufferObject != NULL) {
1080− delete _framebufferObject;
1081− }
1082−}
1083−
1084−void ApplicationOverlay::TexturedHemisphere::bind() {
1085− _framebufferObject->bind();
1086−}
1087−
1088−void ApplicationOverlay::TexturedHemisphere::release() {
1089− _framebufferObject->release();
1090−}
205+ // TODO animate the disconnect border for some excitement while not connected?
206+ //double usecs = usecTimestampNow();
207+ //double secs = usecs / 1000000.0;
208+ //float scaleAmount = 1.0f + (0.01f * sin(secs * 5.0f));
209+ //batch.setModelTransform(glm::scale(mat4(), vec3(scaleAmount)));
1091210
1092−void ApplicationOverlay::TexturedHemisphere::buildVBO(const float fov,
1093− const float aspectRatio,
1094− const int slices,
1095− const int stacks) {
1096− if (fov >= PI) {
1097− qDebug() << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues";
1098− }
1099− // Cleanup old VBO if necessary
1100− cleanupVBO();
1101−
1102− //UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm
1103−
1104− // Compute number of vertices needed
1105− _vertices = slices * stacks;
1106−
1107− // Compute vertices positions and texture UV coordinate
1108− TextureVertex* vertexData = new TextureVertex[_vertices];
1109− TextureVertex* vertexPtr = &vertexData[0];
1110− for (int i = 0; i < stacks; i++) {
1111− float stacksRatio = (float)i / (float)(stacks - 1); // First stack is 0.0f, last stack is 1.0f
1112− // abs(theta) <= fov / 2.0f
1113− float pitch = -fov * (stacksRatio - 0.5f);
1114−
1115− for (int j = 0; j < slices; j++) {
1116− float slicesRatio = (float)j / (float)(slices - 1); // First slice is 0.0f, last slice is 1.0f
1117− // abs(phi) <= fov * aspectRatio / 2.0f
1118− float yaw = -fov * aspectRatio * (slicesRatio - 0.5f);
1119−
1120− vertexPtr->position = getPoint(yaw, pitch);
1121− vertexPtr->uv.x = slicesRatio;
1122− vertexPtr->uv.y = stacksRatio;
1123− vertexPtr++;
1124− }
1125− }
1126− // Create and write to buffer
1127− glGenBuffers(1, &_vbo.first);
1128− glBindBuffer(GL_ARRAY_BUFFER, _vbo.first);
1129− static const int BYTES_PER_VERTEX = sizeof(TextureVertex);
1130− glBufferData(GL_ARRAY_BUFFER, _vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW);
1131− delete[] vertexData;
1132−
1133−
1134− // Compute number of indices needed
1135− static const int VERTEX_PER_TRANGLE = 3;
1136− static const int TRIANGLE_PER_RECTANGLE = 2;
1137− int numberOfRectangles = (slices - 1) * (stacks - 1);
1138− _indices = numberOfRectangles * TRIANGLE_PER_RECTANGLE * VERTEX_PER_TRANGLE;
1139−
1140− // Compute indices order
1141− GLushort* indexData = new GLushort[_indices];
1142− GLushort* indexPtr = indexData;
1143− for (int i = 0; i < stacks - 1; i++) {
1144− for (int j = 0; j < slices - 1; j++) {
1145− GLushort bottomLeftIndex = i * slices + j;
1146− GLushort bottomRightIndex = bottomLeftIndex + 1;
1147− GLushort topLeftIndex = bottomLeftIndex + slices;
1148− GLushort topRightIndex = topLeftIndex + 1;
1149−
1150− *(indexPtr++) = topLeftIndex;
1151− *(indexPtr++) = bottomLeftIndex;
1152− *(indexPtr++) = topRightIndex;
1153−
1154− *(indexPtr++) = topRightIndex;
1155− *(indexPtr++) = bottomLeftIndex;
1156− *(indexPtr++) = bottomRightIndex;
1157− }
211+ geometryCache->renderVertices(batch, gpu::LINE_STRIP, _domainStatusBorder);
212+ renderArgs->_context->syncCache();
213+ renderArgs->_context->render(batch);
1158214 }
1159− // Create and write to buffer
1160− glGenBuffers(1, &_vbo.second);
1161− glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vbo.second);
1162− static const int BYTES_PER_INDEX = sizeof(GLushort);
1163− glBufferData(GL_ELEMENT_ARRAY_BUFFER, _indices * BYTES_PER_INDEX, indexData, GL_STATIC_DRAW);
1164− delete[] indexData;
1165215 }
1166216
1167−void ApplicationOverlay::TexturedHemisphere::cleanupVBO() {
1168− if (_vbo.first != 0) {
1169− glDeleteBuffers(1, &_vbo.first);
1170− _vbo.first = 0;
1171− }
1172− if (_vbo.second != 0) {
1173− glDeleteBuffers(1, &_vbo.second);
1174− _vbo.second = 0;
217+GLuint ApplicationOverlay::getOverlayTexture() {
218+ if (!_overlayFramebuffer) {
219+ return 0;
1175220 }
221+ return _overlayFramebuffer->texture();
1176222 }
1177223
1178−void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() {
1179− auto canvasSize = qApp->getCanvasSize();
1180− QSize fboSize = QSize(canvasSize.x, canvasSize.y);
1181− if (_framebufferObject != NULL && fboSize == _framebufferObject->size()) {
1182− // Already build
224+void ApplicationOverlay::buildFramebufferObject() {
225+ QSize fboSize = qApp->getDeviceSize();
226+ if (_overlayFramebuffer && fboSize == _overlayFramebuffer->size()) {
227+ // Already built
1183228 return;
1184229 }
1185230
1186− if (_framebufferObject != NULL) {
1187− delete _framebufferObject;
231+ if (_overlayFramebuffer) {
232+ delete _overlayFramebuffer;
1188233 }
1189234
1190− _framebufferObject = new QOpenGLFramebufferObject(fboSize, QOpenGLFramebufferObject::Depth);
1191− glBindTexture(GL_TEXTURE_2D, getTexture());
235+ _overlayFramebuffer = new QOpenGLFramebufferObject(fboSize, QOpenGLFramebufferObject::Depth);
236+ glBindTexture(GL_TEXTURE_2D, getOverlayTexture());
1192237 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1193238 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1194239 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
@@ -1197,104 +242,3 @@ void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() { · 2 unmodified lines
1197242 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
1198243 glBindTexture(GL_TEXTURE_2D, 0);
1199244 }
1200−
1201−//Renders a hemisphere with texture coordinates.
1202−void ApplicationOverlay::TexturedHemisphere::render() {
1203− if (_framebufferObject == NULL || _vbo.first == 0 || _vbo.second == 0) {
1204− qDebug() << "TexturedHemisphere::render(): Incorrect initialisation";
1205− return;
1206− }
1207−
1208− glBindBuffer(GL_ARRAY_BUFFER, _vbo.first);
1209− glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vbo.second);
1210−
1211− glEnableClientState(GL_VERTEX_ARRAY);
1212− glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1213−
1214− static const int STRIDE = sizeof(TextureVertex);
1215− static const void* VERTEX_POINTER = 0;
1216− static const void* TEX_COORD_POINTER = (void*)sizeof(glm::vec3);
1217− glVertexPointer(3, GL_FLOAT, STRIDE, VERTEX_POINTER);
1218− glTexCoordPointer(2, GL_FLOAT, STRIDE, TEX_COORD_POINTER);
1219−
1220− glDrawRangeElements(GL_TRIANGLES, 0, _vertices - 1, _indices, GL_UNSIGNED_SHORT, 0);
1221−
1222− glDisableClientState(GL_VERTEX_ARRAY);
1223− glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1224−
1225− glBindBuffer(GL_ARRAY_BUFFER, 0);
1226− glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1227−}
1228−
1229−GLuint ApplicationOverlay::TexturedHemisphere::getTexture() {
1230− return _framebufferObject->texture();
1231−}
1232−
1233−glm::vec2 ApplicationOverlay::directionToSpherical(const glm::vec3& direction) {
1234− glm::vec2 result;
1235− // Compute yaw
1236− glm::vec3 normalProjection = glm::normalize(glm::vec3(direction.x, 0.0f, direction.z));
1237− result.x = glm::acos(glm::dot(IDENTITY_FRONT, normalProjection));
1238− if (glm::dot(IDENTITY_RIGHT, normalProjection) > 0.0f) {
1239− result.x = -glm::abs(result.x);
1240− } else {
1241− result.x = glm::abs(result.x);
1242− }
1243− // Compute pitch
1244− result.y = angleBetween(IDENTITY_UP, direction) - PI_OVER_TWO;
1245−
1246− return result;
1247−}
1248−
1249−glm::vec3 ApplicationOverlay::sphericalToDirection(const glm::vec2& sphericalPos) {
1250− glm::quat rotation(glm::vec3(sphericalPos.y, sphericalPos.x, 0.0f));
1251− return rotation * IDENTITY_FRONT;
1252−}
1253−
1254−glm::vec2 ApplicationOverlay::screenToSpherical(const glm::vec2& screenPos) {
1255− auto screenSize = qApp->getCanvasSize();
1256− glm::vec2 result;
1257− result.x = -(screenPos.x / screenSize.x - 0.5f);
1258− result.y = (screenPos.y / screenSize.y - 0.5f);
1259− result.x *= MOUSE_YAW_RANGE;
1260− result.y *= MOUSE_PITCH_RANGE;
1261−
1262− return result;
1263−}
1264−
1265−glm::vec2 ApplicationOverlay::sphericalToScreen(const glm::vec2& sphericalPos) {
1266− glm::vec2 result = sphericalPos;
1267− result.x *= -1.0;
1268− result /= MOUSE_RANGE;
1269− result += 0.5f;
1270− result *= qApp->getCanvasSize();
1271− return result;
1272−}
1273−
1274−glm::vec2 ApplicationOverlay::sphericalToOverlay(const glm::vec2& sphericalPos) const {
1275− glm::vec2 result = sphericalPos;
1276− result.x *= -1.0;
1277− result /= _textureFov;
1278− result.x /= _textureAspectRatio;
1279− result += 0.5f;
1280− result *= qApp->getCanvasSize();
1281− return result;
1282−}
1283−
1284−glm::vec2 ApplicationOverlay::overlayToSpherical(const glm::vec2& overlayPos) const {
1285− glm::vec2 result = overlayPos;
1286− result /= qApp->getCanvasSize();
1287− result -= 0.5f;
1288− result *= _textureFov;
1289− result.x *= _textureAspectRatio;
1290− result.x *= -1.0f;
1291− return result;
1292−}
1293−
1294−glm::vec2 ApplicationOverlay::screenToOverlay(const glm::vec2& screenPos) const {
1295− return sphericalToOverlay(screenToSpherical(screenPos));
1296−}
1297−
1298−glm::vec2 ApplicationOverlay::overlayToScreen(const glm::vec2& overlayPos) const {
1299− return sphericalToScreen(overlayToSpherical(overlayPos));
1300−}
interface/src/ui/ApplicationOverlay.h+14−118
@@ -13,16 +13,8 @@ · 12 unmodified lines
1313 #define hifi_ApplicationOverlay_h
1414
1515 #include <gpu/Texture.h>
16−class Camera;
17−class Overlays;
1816 class QOpenGLFramebufferObject;
1917
20−const float MAGNIFY_WIDTH = 220.0f;
21−const float MAGNIFY_HEIGHT = 100.0f;
22−const float MAGNIFY_MULT = 2.0f;
23−
24−const float DEFAULT_HMD_UI_ANGULAR_SIZE = 72.0f;
25−
2618 // Handles the drawing of the overlays to the screen
2719 // TODO, move divide up the rendering, displaying and input handling
2820 // facilities of this class
@@ -33,122 +25,26 @@ public: · 4 unmodified lines
3325 ~ApplicationOverlay();
3426
3527 void renderOverlay(RenderArgs* renderArgs);
36− void displayOverlayTexture();
37− void displayOverlayTextureStereo(Camera& whichCamera, float aspectRatio, float fov);
38− void displayOverlayTextureHmd(Camera& whichCamera);
39−
40− QPoint getPalmClickLocation(const PalmData *palm) const;
41− bool calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const;
42−
43− bool hasMagnifier() const { return _magnifier; }
44− void toggleMagnifier() { _magnifier = !_magnifier; }
28+ GLuint getOverlayTexture();
4529
46− float getHmdUIAngularSize() const { return _hmdUIAngularSize; }
47− void setHmdUIAngularSize(float hmdUIAngularSize) { _hmdUIAngularSize = hmdUIAngularSize; }
48−
49− // Converter from one frame of reference to another.
50− // Frame of reference:
51− // Direction: Ray that represents the spherical values
52− // Screen: Position on the screen (x,y)
53− // Spherical: Pitch and yaw that gives the position on the sphere we project on (yaw,pitch)
54− // Overlay: Position on the overlay (x,y)
55− // (x,y) in Overlay are similar than (x,y) in Screen except they can be outside of the bound of te screen.
56− // This allows for picking outside of the screen projection in 3D.
57− glm::vec2 sphericalToOverlay(const glm::vec2 & sphericalPos) const;
58− glm::vec2 overlayToSpherical(const glm::vec2 & overlayPos) const;
59− glm::vec2 screenToOverlay(const glm::vec2 & screenPos) const;
60− glm::vec2 overlayToScreen(const glm::vec2 & overlayPos) const;
61− void computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const;
62−
63− static glm::vec2 directionToSpherical(const glm::vec3 & direction);
64− static glm::vec3 sphericalToDirection(const glm::vec2 & sphericalPos);
65− static glm::vec2 screenToSpherical(const glm::vec2 & screenPos);
66− static glm::vec2 sphericalToScreen(const glm::vec2 & sphericalPos);
67−
6830 private:
69− // Interleaved vertex data
70− struct TextureVertex {
71− glm::vec3 position;
72− glm::vec2 uv;
73− };
74−
75− typedef QPair<GLuint, GLuint> VerticesIndices;
76− class TexturedHemisphere {
77− public:
78− TexturedHemisphere();
79− ~TexturedHemisphere();
80−
81− void bind();
82− void release();
83− GLuint getTexture();
84−
85− void buildFramebufferObject();
86− void buildVBO(const float fov, const float aspectRatio, const int slices, const int stacks);
87− void render();
88−
89− private:
90− void cleanupVBO();
91−
92− GLuint _vertices;
93− GLuint _indices;
94− QOpenGLFramebufferObject* _framebufferObject;
95− VerticesIndices _vbo;
96− };
97−
98− float _hmdUIAngularSize = DEFAULT_HMD_UI_ANGULAR_SIZE;
99− void renderReticle(glm::quat orientation, float alpha);
100− void renderPointers();;
101− void renderMagnifier(glm::vec2 magPos, float sizeMult, bool showBorder);
102−
103− void renderControllerPointers();
104− void renderPointersOculus();
105−
106− void renderAudioMeter();
107− void renderCameraToggle();
108− void renderStatsAndLogs();
109− void renderDomainConnectionStatusBorder();
110− void bindCursorTexture(gpu::Batch& batch, uint8_t cursorId = 0);
31+ void renderStatsAndLogs(RenderArgs* renderArgs);
32+ void renderDomainConnectionStatusBorder(RenderArgs* renderArgs);
33+ void renderRearViewToFbo(RenderArgs* renderArgs);
34+ void renderRearView(RenderArgs* renderArgs);
35+ void renderQmlUi(RenderArgs* renderArgs);
36+ void renderOverlays(RenderArgs* renderArgs);
37+ void buildFramebufferObject();
38+
39+ float _alpha{ 1.0f };
40+ float _trailingAudioLoudness{ 0.0f };
41+ GLuint _uiTexture{ 0 };
11142
112− TexturedHemisphere _overlays;
113−
114− float _textureFov;
115− float _textureAspectRatio;
116−
117− enum Reticles { MOUSE, LEFT_CONTROLLER, RIGHT_CONTROLLER, NUMBER_OF_RETICLES };
118− bool _reticleActive[NUMBER_OF_RETICLES];
119− QPoint _reticlePosition[NUMBER_OF_RETICLES];
120− bool _magActive[NUMBER_OF_RETICLES];
121− float _magSizeMult[NUMBER_OF_RETICLES];
122− quint64 _lastMouseMove;
123− bool _magnifier;
124−
125− float _alpha = 1.0f;
126− float _oculusUIRadius;
127− float _trailingAudioLoudness;
128−
129− gpu::TexturePointer _crosshairTexture;
130−
131−
132− QMap<uint16_t, gpu::TexturePointer> _cursors;
133−
134− GLuint _newUiTexture{ 0 };
135−
136− int _reticleQuad;
137− int _magnifierQuad;
138− int _audioRedQuad;
139− int _audioGreenQuad;
140− int _audioBlueQuad;
14143 int _domainStatusBorder;
14244 int _magnifierBorder;
14345
144− int _previousBorderWidth;
145− int _previousBorderHeight;
146−
147− glm::vec3 _previousMagnifierBottomLeft;
148− glm::vec3 _previousMagnifierBottomRight;
149− glm::vec3 _previousMagnifierTopLeft;
150− glm::vec3 _previousMagnifierTopRight;
151−
46+ ivec2 _previousBorderSize{ -1 };
47+ QOpenGLFramebufferObject* _overlayFramebuffer{ nullptr };
15248 };
15349
15450 #endif // hifi_ApplicationOverlay_h
interface/src/ui/AvatarInputs.cpp+134−0
@@ -0,0 +1,134 @@
1+//
2+// Created by Bradley Austin Davis 2015/06/19
3+// Copyright 2013 High Fidelity, Inc.
4+//
5+// Distributed under the Apache License, Version 2.0.
6+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
7+//
8+
9+
10+#include "Application.h"
11+#include "AvatarInputs.h"
12+
13+#include <SettingHandle.h>
14+
15+#include "Menu.h"
16+#include "devices/FaceTracker.h"
17+
18+HIFI_QML_DEF(AvatarInputs)
19+
20+
21+static AvatarInputs* INSTANCE{ nullptr };
22+static const char SETTINGS_GROUP_NAME[] = "Rear View Tools";
23+static const char ZOOM_LEVEL_SETTINGS[] = "ZoomLevel";
24+
25+static Setting::Handle<int> rearViewZoomLevel(QStringList() << SETTINGS_GROUP_NAME << ZOOM_LEVEL_SETTINGS, 0);
26+
27+AvatarInputs* AvatarInputs::getInstance() {
28+ if (!INSTANCE) {
29+ AvatarInputs::registerType();
30+ AvatarInputs::show();
31+ Q_ASSERT(INSTANCE);
32+ }
33+ return INSTANCE;
34+}
35+
36+AvatarInputs::AvatarInputs(QQuickItem* parent) : QQuickItem(parent) {
37+ INSTANCE = this;
38+ int zoomSetting = rearViewZoomLevel.get();
39+ _mirrorZoomed = zoomSetting == 0;
40+}
41+
42+#define AI_UPDATE(name, src) \
43+ { \
44+ auto val = src; \
45+ if (_##name != val) { \
46+ _##name = val; \
47+ emit name##Changed(); \
48+ } \
49+ }
50+
51+#define AI_UPDATE_FLOAT(name, src, epsilon) \
52+ { \
53+ float val = src; \
54+ if (fabs(_##name - val) >= epsilon) { \
55+ _##name = val; \
56+ emit name##Changed(); \
57+ } \
58+ }
59+
60+void AvatarInputs::update() {
61+ if (!Menu::getInstance()) {
62+ return;
63+ }
64+ AI_UPDATE(mirrorVisible, Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !qApp->isHMDMode()
65+ && !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror));
66+ AI_UPDATE(cameraEnabled, !Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking));
67+ AI_UPDATE(cameraMuted, Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking));
68+
69+ auto audioIO = DependencyManager::get<AudioClient>();
70+ const float CLIPPING_INDICATOR_TIME = 1.0f;
71+ const float AUDIO_METER_AVERAGING = 0.5;
72+ const float LOG2 = log(2.0f);
73+ const float METER_LOUDNESS_SCALE = 2.8f / 5.0f;
74+ const float LOG2_LOUDNESS_FLOOR = 11.0f;
75+ float audioLevel = 0.0f;
76+ auto audio = DependencyManager::get<AudioClient>();
77+ float loudness = audio->getLastInputLoudness() + 1.0f;
78+
79+ _trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.0f - AUDIO_METER_AVERAGING) * loudness;
80+
81+ float log2loudness = logf(_trailingAudioLoudness) / LOG2;
82+
83+ if (log2loudness <= LOG2_LOUDNESS_FLOOR) {
84+ audioLevel = (log2loudness / LOG2_LOUDNESS_FLOOR) * METER_LOUDNESS_SCALE;
85+ } else {
86+ audioLevel = (log2loudness - (LOG2_LOUDNESS_FLOOR - 1.0f)) * METER_LOUDNESS_SCALE;
87+ }
88+ if (audioLevel > 1.0) {
89+ audioLevel = 1.0;
90+ }
91+ AI_UPDATE_FLOAT(audioLevel, audioLevel, 0.01);
92+ AI_UPDATE(audioClipping, ((audioIO->getTimeSinceLastClip() > 0.0f) && (audioIO->getTimeSinceLastClip() < 1.0f)));
93+ AI_UPDATE(audioMuted, audioIO->isMuted());
94+
95+ //// Make muted icon pulsate
96+ //static const float PULSE_MIN = 0.4f;
97+ //static const float PULSE_MAX = 1.0f;
98+ //static const float PULSE_FREQUENCY = 1.0f; // in Hz
99+ //qint64 now = usecTimestampNow();
100+ //if (now - _iconPulseTimeReference > (qint64)USECS_PER_SECOND) {
101+ // // Prevents t from getting too big, which would diminish glm::cos precision
102+ // _iconPulseTimeReference = now - ((now - _iconPulseTimeReference) % USECS_PER_SECOND);
103+ //}
104+ //float t = (float)(now - _iconPulseTimeReference) / (float)USECS_PER_SECOND;
105+ //float pulseFactor = (glm::cos(t * PULSE_FREQUENCY * 2.0f * PI) + 1.0f) / 2.0f;
106+ //iconColor = PULSE_MIN + (PULSE_MAX - PULSE_MIN) * pulseFactor;
107+}
108+
109+void AvatarInputs::toggleCameraMute() {
110+ FaceTracker* faceTracker = Application::getInstance()->getSelectedFaceTracker();
111+ if (faceTracker) {
112+ faceTracker->toggleMute();
113+ }
114+}
115+
116+void AvatarInputs::toggleAudioMute() {
117+ DependencyManager::get<AudioClient>()->toggleMute();
118+}
119+
120+void AvatarInputs::resetSensors() {
121+ qApp->resetSensors();
122+}
123+
124+void AvatarInputs::toggleZoom() {
125+ _mirrorZoomed = !_mirrorZoomed;
126+ rearViewZoomLevel.set(_mirrorZoomed ? 0 : 1);
127+ emit mirrorZoomedChanged();
128+}
129+
130+void AvatarInputs::closeMirror() {
131+ if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
132+ Menu::getInstance()->triggerOption(MenuOption::Mirror);
133+ }
134+}
interface/src/ui/AvatarInputs.h+59−0
@@ -0,0 +1,59 @@
1+//
2+// Created by Bradley Austin Davis 2015/06/19
3+// Copyright 2013 High Fidelity, Inc.
4+//
5+// Distributed under the Apache License, Version 2.0.
6+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
7+//
8+
9+#ifndef hifi_AvatarInputs_h
10+#define hifi_AvatarInputs_h
11+
12+#include <QQuickItem>
13+#include <OffscreenUi.h>
14+
15+#define AI_PROPERTY(type, name, initialValue) \
16+ Q_PROPERTY(type name READ name NOTIFY name##Changed) \
17+public: \
18+ type name() { return _##name; }; \
19+private: \
20+ type _##name{ initialValue };
21+
22+class AvatarInputs : public QQuickItem {
23+ Q_OBJECT
24+ HIFI_QML_DECL
25+
26+ AI_PROPERTY(bool, cameraEnabled, false)
27+ AI_PROPERTY(bool, cameraMuted, false)
28+ AI_PROPERTY(bool, audioMuted, false)
29+ AI_PROPERTY(bool, audioClipping, false)
30+ AI_PROPERTY(float, audioLevel, 0)
31+ AI_PROPERTY(bool, mirrorVisible, false)
32+ AI_PROPERTY(bool, mirrorZoomed, true)
33+
34+public:
35+ static AvatarInputs* getInstance();
36+ AvatarInputs(QQuickItem* parent = nullptr);
37+ void update();
38+
39+signals:
40+ void cameraEnabledChanged();
41+ void cameraMutedChanged();
42+ void audioMutedChanged();
43+ void audioClippingChanged();
44+ void audioLevelChanged();
45+ void mirrorVisibleChanged();
46+ void mirrorZoomedChanged();
47+
48+protected:
49+ Q_INVOKABLE void resetSensors();
50+ Q_INVOKABLE void toggleCameraMute();
51+ Q_INVOKABLE void toggleAudioMute();
52+ Q_INVOKABLE void toggleZoom();
53+ Q_INVOKABLE void closeMirror();
54+
55+private:
56+ float _trailingAudioLoudness{ 0 };
57+};
58+
59+#endif // hifi_AvatarInputs_h
interface/src/ui/FlowLayout.cpp+9−0
@@ -38,8 +38,17 @@ · 37 unmodified lines
3838 **
3939 ****************************************************************************/
4040
41+#ifdef __GNUC__
42+#pragma GCC diagnostic push
43+#pragma GCC diagnostic ignored "-Wdouble-promotion"
44+#endif
45+
4146 #include <QtWidgets>
4247
48+#ifdef __GNUC__
49+#pragma GCC diagnostic pop
50+#endif
51+
4352 #include "FlowLayout.h"
4453 //! [1]
4554 FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
interface/src/ui/HMDToolsDialog.cpp+4−59
@@ -56,8 +56,6 @@ HMDToolsDialog::HMDToolsDialog(QWidget* parent) : · 55 unmodified lines
5656
5757 this->QDialog::setLayout(form);
5858
59− _wasMoved = false;
60− _previousRect = Application::getInstance()->getWindow()->rect();
6159 Application::getInstance()->getWindow()->activateWindow();
6260
6361 // watch for our application window moving screens. If it does we want to update our screen details
@@ -136,24 +134,6 @@ void HMDToolsDialog::enterHDMMode() { · 72 unmodified lines
136134 if (!_inHDMMode) {
137135 _switchModeButton->setText("Leave HMD Mode");
138136 _debugDetails->setText(getDebugDetails());
139−
140− _hmdScreenNumber = OculusManager::getHMDScreen();
141−
142− if (_hmdScreenNumber >= 0) {
143− QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle();
144− _hmdScreen = QGuiApplication::screens()[_hmdScreenNumber];
145−
146− _previousRect = Application::getInstance()->getWindow()->rect();
147− _previousRect = QRect(mainWindow->mapToGlobal(_previousRect.topLeft()),
148− mainWindow->mapToGlobal(_previousRect.bottomRight()));
149− _previousScreen = mainWindow->screen();
150− QRect rect = QApplication::desktop()->screenGeometry(_hmdScreenNumber);
151− mainWindow->setScreen(_hmdScreen);
152− mainWindow->setGeometry(rect);
153−
154− _wasMoved = true;
155− }
156−
157137
158138 // if we're on a single screen setup, then hide our tools window when entering HMD mode
159139 if (QApplication::desktop()->screenCount() == 1) {
@@ -161,58 +141,21 @@ void HMDToolsDialog::enterHDMMode() { · 1 unmodified line
161141 }
162142
163143 Application::getInstance()->setEnableVRMode(true);
164−
165− const int SLIGHT_DELAY = 500;
166− // If we go to fullscreen immediately, it ends up on the primary monitor,
167− // even though we've already moved the window. By adding this delay, the
168− // fullscreen target screen ends up correct.
169− QTimer::singleShot(SLIGHT_DELAY, this, [&]{
170− Application::getInstance()->setFullscreen(true);
171− activateWindowAfterEnterMode();
172− });
173−
144+
174145 _inHDMMode = true;
175146 }
176147 }
177148
178−void HMDToolsDialog::activateWindowAfterEnterMode() {
179− Application::getInstance()->getWindow()->activateWindow();
180−
181− // center the cursor on the main application window
182− centerCursorOnWidget(Application::getInstance()->getWindow());
183−}
184−
185149 void HMDToolsDialog::leaveHDMMode() {
186150 if (_inHDMMode) {
187151 _switchModeButton->setText("Enter HMD Mode");
188152 _debugDetails->setText(getDebugDetails());
189−
190153 Application::getInstance()->setEnableVRMode(false);
191− Application::getInstance()->setFullscreen(false);
192154 Application::getInstance()->getWindow()->activateWindow();
193−
194− if (_wasMoved) {
195− QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle();
196− mainWindow->setScreen(_previousScreen);
197− mainWindow->setGeometry(_previousRect);
198−
199− const int SLIGHT_DELAY = 1500;
200− QTimer::singleShot(SLIGHT_DELAY, this, SLOT(moveWindowAfterLeaveMode()));
201− }
202− _wasMoved = false;
203155 _inHDMMode = false;
204156 }
205157 }
206158
207−void HMDToolsDialog::moveWindowAfterLeaveMode() {
208− QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle();
209− mainWindow->setScreen(_previousScreen);
210− mainWindow->setGeometry(_previousRect);
211− Application::getInstance()->getWindow()->activateWindow();
212− Application::getInstance()->resetSensors();
213−}
214−
215−
216159 void HMDToolsDialog::reject() {
217160 // Just regularly close upon ESC
218161 close();
@@ -244,13 +187,15 @@ void HMDToolsDialog::hideEvent(QHideEvent* event) { · 25 unmodified lines
244187
245188 void HMDToolsDialog::aboutToQuit() {
246189 if (_inHDMMode) {
190+ // FIXME this is ineffective because it doesn't trigger the menu to
191+ // save the fact that VR Mode is not checked.
247192 leaveHDMMode();
248193 }
249194 }
250195
251196 void HMDToolsDialog::screenCountChanged(int newCount) {
252197 if (!OculusManager::isConnected()) {
253− OculusManager::connect();
198+ //OculusManager::connect();
254199 }
255200 int hmdScreenNumber = OculusManager::getHMDScreen();
256201
interface/src/ui/HMDToolsDialog.h+0−4
@@ -35,8 +35,6 @@ signals: · 34 unmodified lines
3535 public slots:
3636 void reject();
3737 void switchModeClicked(bool checked);
38− void activateWindowAfterEnterMode();
39− void moveWindowAfterLeaveMode();
4038 void applicationWindowScreenChanged(QScreen* screen);
4139 void aboutToQuit();
4240 void screenCountChanged(int newCount);
@@ -51,8 +49,6 @@ private: · 8 unmodified lines
5149 void enterHDMMode();
5250 void leaveHDMMode();
5351
54− bool _wasMoved;
55− QRect _previousRect;
5652 QScreen* _previousScreen;
5753 QScreen* _hmdScreen;
5854 int _hmdScreenNumber;
interface/src/ui/LogDialog.cpp+9−0
@@ -11,10 +11,19 @@ · 10 unmodified lines
1111
1212 #include "InterfaceConfig.h"
1313
14+#ifdef __GNUC__
15+#pragma GCC diagnostic push
16+#pragma GCC diagnostic ignored "-Wdouble-promotion"
17+#endif
18+
1419 #include <QDesktopWidget>
1520 #include <QTextBlock>
1621 #include <QtGui>
1722
23+#ifdef __GNUC__
24+#pragma GCC diagnostic pop
25+#endif
26+
1827 #include <PathUtils.h>
1928 #include <SharedUtil.h>
2029
interface/src/ui/PreferencesDialog.cpp+2−2
@@ -175,7 +175,7 @@ void PreferencesDialog::loadPreferences() { · 174 unmodified lines
175175
176176 ui.maxOctreePPSSpin->setValue(qApp->getMaxOctreePacketsPerSecond());
177177
178− ui.oculusUIAngularSizeSpin->setValue(qApp->getApplicationOverlay().getHmdUIAngularSize());
178+ ui.oculusUIAngularSizeSpin->setValue(qApp->getApplicationCompositor().getHmdUIAngularSize());
179179
180180 SixenseManager& sixense = SixenseManager::getInstance();
181181 ui.sixenseReticleMoveSpeedSpin->setValue(sixense.getReticleMoveSpeed());
@@ -239,7 +239,7 @@ void PreferencesDialog::savePreferences() { · 57 unmodified lines
239239
240240 qApp->setMaxOctreePacketsPerSecond(ui.maxOctreePPSSpin->value());
241241
242− qApp->getApplicationOverlay().setHmdUIAngularSize(ui.oculusUIAngularSizeSpin->value());
242+ qApp->getApplicationCompositor().setHmdUIAngularSize(ui.oculusUIAngularSizeSpin->value());
243243
244244 SixenseManager& sixense = SixenseManager::getInstance();
245245 sixense.setReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value());
interface/src/ui/RearMirrorTools.cpp+0−134
@@ -1,134 +0,0 @@
1−//
2−// RearMirrorTools.cpp
3−// interface/src/ui
4−//
5−// Created by Stojce Slavkovski on 10/23/2013.
6−// Copyright 2013 High Fidelity, Inc.
7−//
8−// Distributed under the Apache License, Version 2.0.
9−// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10−//
11−
12−#include "InterfaceConfig.h"
13−
14−#include <QMouseEvent>
15−
16−#include <PathUtils.h>
17−#include <SharedUtil.h>
18−#include <gpu/GLBackend.h>
19−
20−#include "Application.h"
21−#include "RearMirrorTools.h"
22−#include "Util.h"
23−
24−const int ICON_SIZE = 24;
25−const int ICON_PADDING = 5;
26−
27−const char SETTINGS_GROUP_NAME[] = "Rear View Tools";
28−const char ZOOM_LEVEL_SETTINGS[] = "ZoomLevel";
29−Setting::Handle<int> RearMirrorTools::rearViewZoomLevel(QStringList() << SETTINGS_GROUP_NAME << ZOOM_LEVEL_SETTINGS,
30− ZoomLevel::HEAD);
31−
32−RearMirrorTools::RearMirrorTools(QRect& bounds) :
33− _bounds(bounds),
34− _windowed(false),
35− _fullScreen(false)
36−{
37− _closeTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/close.svg");
38−
39− _zoomHeadTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/plus.svg");
40− _zoomBodyTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/minus.svg");
41−
42− _shrinkIconRect = QRect(ICON_PADDING, ICON_PADDING, ICON_SIZE, ICON_SIZE);
43− _closeIconRect = QRect(_bounds.left() + ICON_PADDING, _bounds.top() + ICON_PADDING, ICON_SIZE, ICON_SIZE);
44− _resetIconRect = QRect(_bounds.width() - ICON_SIZE - ICON_PADDING, _bounds.top() + ICON_PADDING, ICON_SIZE, ICON_SIZE);
45− _bodyZoomIconRect = QRect(_bounds.width() - ICON_SIZE - ICON_PADDING, _bounds.bottom() - ICON_PADDING - ICON_SIZE, ICON_SIZE, ICON_SIZE);
46− _headZoomIconRect = QRect(_bounds.left() + ICON_PADDING, _bounds.bottom() - ICON_PADDING - ICON_SIZE, ICON_SIZE, ICON_SIZE);
47−}
48−
49−void RearMirrorTools::render(RenderArgs* renderArgs, bool fullScreen, const QPoint & mousePosition) {
50− if (fullScreen) {
51− _fullScreen = true;
52− displayIcon(QRect(QPoint(), qApp->getDeviceSize()), _shrinkIconRect, _closeTexture);
53− } else {
54− // render rear view tools if mouse is in the bounds
55− _windowed = _bounds.contains(mousePosition);
56− if (_windowed) {
57− displayIcon(_bounds, _closeIconRect, _closeTexture);
58−
59− ZoomLevel zoomLevel = (ZoomLevel)rearViewZoomLevel.get();
60− displayIcon(_bounds, _headZoomIconRect, _zoomHeadTexture, zoomLevel == HEAD);
61− displayIcon(_bounds, _bodyZoomIconRect, _zoomBodyTexture, zoomLevel == BODY);
62− }
63− }
64−}
65−
66−bool RearMirrorTools::mousePressEvent(int x, int y) {
67− if (_windowed) {
68− if (_closeIconRect.contains(x, y)) {
69− _windowed = false;
70− emit closeView();
71− return true;
72− }
73−
74− if (_headZoomIconRect.contains(x, y)) {
75− rearViewZoomLevel.set(HEAD);
76− return true;
77− }
78−
79− if (_bodyZoomIconRect.contains(x, y)) {
80− rearViewZoomLevel.set(BODY);
81− return true;
82− }
83−
84− if (_bounds.contains(x, y)) {
85− _windowed = false;
86− emit restoreView();
87− return true;
88− }
89− }
90−
91− if (_fullScreen) {
92− if (_shrinkIconRect.contains(x, y)) {
93− _fullScreen = false;
94− emit shrinkView();
95− return true;
96− }
97− }
98− return false;
99−}
100−
101−void RearMirrorTools::displayIcon(QRect bounds, QRect iconBounds, const gpu::TexturePointer& texture, bool selected) {
102−
103− glMatrixMode(GL_PROJECTION);
104− glPushMatrix();
105− glLoadIdentity();
106−
107− glOrtho(bounds.left(), bounds.right(), bounds.bottom(), bounds.top(), -1.0, 1.0);
108− glDisable(GL_DEPTH_TEST);
109− glDisable(GL_LIGHTING);
110− glEnable(GL_TEXTURE_2D);
111−
112− glm::vec4 quadColor;
113− if (selected) {
114− quadColor = glm::vec4(.5f, .5f, .5f, 1.0f);
115− } else {
116− quadColor = glm::vec4(1, 1, 1, 1);
117− }
118−
119− glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(texture));
120−
121− glm::vec2 topLeft(iconBounds.left(), iconBounds.top());
122− glm::vec2 bottomRight(iconBounds.right(), iconBounds.bottom());
123− static const glm::vec2 texCoordTopLeft(0.0f, 1.0f);
124− static const glm::vec2 texCoordBottomRight(1.0f, 0.0f);
125−
126− DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor);
127−
128− glPopMatrix();
129−
130− glMatrixMode(GL_MODELVIEW);
131−
132− glBindTexture(GL_TEXTURE_2D, 0);
133− glDisable(GL_TEXTURE_2D);
134−}
interface/src/ui/RearMirrorTools.h+0−56
@@ -1,56 +0,0 @@
1−//
2−// RearMirrorTools.h
3−// interface/src/ui
4−//
5−// Created by Stojce Slavkovski on 10/23/2013.
6−// Copyright 2013 High Fidelity, Inc.
7−//
8−// Distributed under the Apache License, Version 2.0.
9−// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10−//
11−
12−#ifndef hifi_RearMirrorTools_h
13−#define hifi_RearMirrorTools_h
14−
15−#include <gpu/Texture.h>
16−#include <SettingHandle.h>
17−
18−enum ZoomLevel {
19− HEAD = 0,
20− BODY = 1
21−};
22−
23−class RearMirrorTools : public QObject {
24− Q_OBJECT
25−public:
26− RearMirrorTools(QRect& bounds);
27− void render(RenderArgs* renderArgs, bool fullScreen, const QPoint & mousePos);
28− bool mousePressEvent(int x, int y);
29−
30− static Setting::Handle<int> rearViewZoomLevel;
31−
32−signals:
33− void closeView();
34− void shrinkView();
35− void resetView();
36− void restoreView();
37−
38−private:
39− QRect _bounds;
40− gpu::TexturePointer _closeTexture;
41− gpu::TexturePointer _zoomBodyTexture;
42− gpu::TexturePointer _zoomHeadTexture;
43−
44− QRect _closeIconRect;
45− QRect _resetIconRect;
46− QRect _shrinkIconRect;
47− QRect _headZoomIconRect;
48− QRect _bodyZoomIconRect;
49−
50− bool _windowed;
51− bool _fullScreen;
52−
53− void displayIcon(QRect bounds, QRect iconBounds, const gpu::TexturePointer& texture, bool selected = false);
54−};
55−
56−#endif // hifi_RearMirrorTools_h
interface/src/ui/Stats.cpp+221−466
@@ -1,17 +1,17 @@
11 //
2−// Stats.cpp
3−// interface/src/ui
4−//
5−// Created by Lucas Crisman on 22/03/14.
2+// Created by Bradley Austin Davis 2015/06/17
63 // Copyright 2013 High Fidelity, Inc.
74 //
85 // Distributed under the Apache License, Version 2.0.
96 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
107 //
118
12−#include <sstream>
9+#include <gpu/GPUConfig.h>
1310
14−#include <stdlib.h>
11+#include "Stats.h"
12+
13+#include <sstream>
14+#include <QFontDatabase>
1515
1616 #include <glm/glm.hpp>
1717 #include <glm/gtx/component_wise.hpp>
@@ -25,147 +25,31 @@ · 7 unmodified lines
2525 #include <LODManager.h>
2626 #include <PerfStat.h>
2727
28−#include "Stats.h"
2928 #include "BandwidthRecorder.h"
3029 #include "InterfaceConfig.h"
3130 #include "Menu.h"
3231 #include "Util.h"
3332 #include "SequenceNumberStats.h"
3433
35−using namespace std;
34+HIFI_QML_DEF(Stats)
3635
37−const int STATS_PELS_PER_LINE = 16;
38−const int STATS_PELS_INITIALOFFSET = 12;
36+using namespace std;
3937
40−const int STATS_GENERAL_MIN_WIDTH = 165;
41−const int STATS_PING_MIN_WIDTH = 190;
42−const int STATS_GEO_MIN_WIDTH = 240;
43−const int STATS_OCTREE_MIN_WIDTH = 410;
38+static Stats* INSTANCE{ nullptr };
4439
4540 Stats* Stats::getInstance() {
46− static Stats stats;
47− return &stats;
48−}
49−
50−Stats::Stats():
51− _expanded(false),
52− _recentMaxPackets(0),
53− _resetRecentMaxPacketsSoon(true),
54− _generalStatsWidth(STATS_GENERAL_MIN_WIDTH),
55− _pingStatsWidth(STATS_PING_MIN_WIDTH),
56− _geoStatsWidth(STATS_GEO_MIN_WIDTH),
57− _octreeStatsWidth(STATS_OCTREE_MIN_WIDTH),
58− _lastHorizontalOffset(0)
59−{
60− auto canvasSize = Application::getInstance()->getCanvasSize();
61− resetWidth(canvasSize.x, 0);
62−}
63−
64−void Stats::toggleExpanded() {
65− _expanded = !_expanded;
66−}
67−
68−// called on mouse click release
69−// check for clicks over stats in order to expand or contract them
70−void Stats::checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseDragStartedY, int horizontalOffset) {
71− auto canvasSize = Application::getInstance()->getCanvasSize();
72−
73− if (0 != glm::compMax(glm::abs(glm::ivec2(mouseX - mouseDragStartedX, mouseY - mouseDragStartedY)))) {
74− // not worried about dragging on stats
75− return;
76− }
77−
78− int statsHeight = 0,
79− statsWidth = 0,
80− statsX = 0,
81− statsY = 0,
82− lines = 0;
83−
84− statsX = horizontalOffset;
85−
86− // top-left stats click
87− lines = _expanded ? 5 : 3;
88− statsHeight = lines * STATS_PELS_PER_LINE + 10;
89− if (mouseX > statsX && mouseX < statsX + _generalStatsWidth && mouseY > statsY && mouseY < statsY + statsHeight) {
90− toggleExpanded();
91− return;
92− }
93− statsX += _generalStatsWidth;
94−
95− // ping stats click
96− if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
97− lines = _expanded ? 4 : 3;
98− statsHeight = lines * STATS_PELS_PER_LINE + 10;
99− if (mouseX > statsX && mouseX < statsX + _pingStatsWidth && mouseY > statsY && mouseY < statsY + statsHeight) {
100− toggleExpanded();
101− return;
102− }
103− statsX += _pingStatsWidth;
104− }
105−
106− // geo stats panel click
107− lines = _expanded ? 4 : 3;
108− statsHeight = lines * STATS_PELS_PER_LINE + 10;
109− if (mouseX > statsX && mouseX < statsX + _geoStatsWidth && mouseY > statsY && mouseY < statsY + statsHeight) {
110− toggleExpanded();
111− return;
112− }
113− statsX += _geoStatsWidth;
114−
115− // top-right stats click
116− lines = _expanded ? 11 : 3;
117− statsHeight = lines * STATS_PELS_PER_LINE + 10;
118− statsWidth = canvasSize.x - statsX;
119− if (mouseX > statsX && mouseX < statsX + statsWidth && mouseY > statsY && mouseY < statsY + statsHeight) {
120− toggleExpanded();
121− return;
122− }
123−}
124−
125−void Stats::resetWidth(int width, int horizontalOffset) {
126− auto canvasSize = Application::getInstance()->getCanvasSize();
127− int extraSpace = canvasSize.x - horizontalOffset - 2
128− - STATS_GENERAL_MIN_WIDTH
129− - (Menu::getInstance()->isOptionChecked(MenuOption::TestPing) ? STATS_PING_MIN_WIDTH -1 : 0)
130− - STATS_GEO_MIN_WIDTH
131− - STATS_OCTREE_MIN_WIDTH;
132−
133− int panels = 4;
134−
135− _generalStatsWidth = STATS_GENERAL_MIN_WIDTH;
136− if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
137− _pingStatsWidth = STATS_PING_MIN_WIDTH;
138− } else {
139− _pingStatsWidth = 0;
140− panels = 3;
141− }
142− _geoStatsWidth = STATS_GEO_MIN_WIDTH;
143− _octreeStatsWidth = STATS_OCTREE_MIN_WIDTH;
144−
145− if (extraSpace > panels) {
146− _generalStatsWidth += (int) extraSpace / panels;
147− if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
148− _pingStatsWidth += (int) extraSpace / panels;
149− }
150− _geoStatsWidth += (int) extraSpace / panels;
151− _octreeStatsWidth += canvasSize.x -
152− (_generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3);
41+ if (!INSTANCE) {
42+ Stats::registerType();
43+ Stats::show();
44+ Q_ASSERT(INSTANCE);
15345 }
46+ return INSTANCE;
15447 }
15548
156−
157−// translucent background box that makes stats more readable
158−void Stats::drawBackground(unsigned int rgba, int x, int y, int width, int height) {
159− glm::vec4 color(((rgba >> 24) & 0xff) / 255.0f,
160− ((rgba >> 16) & 0xff) / 255.0f,
161− ((rgba >> 8) & 0xff) / 255.0f,
162− (rgba & 0xff) / 255.0f);
163−
164− // FIX ME: is this correct? It seems to work to fix textures bleeding into us...
165− glBindTexture(GL_TEXTURE_2D, 0);
166− glDisable(GL_TEXTURE_2D);
167−
168− DependencyManager::get<GeometryCache>()->renderQuad(x, y, width, height, color);
49+Stats::Stats(QQuickItem* parent) : QQuickItem(parent) {
50+ INSTANCE = this;
51+ const QFont font = QFontDatabase::systemFont(QFontDatabase::FixedFont);
52+ _monospaceFont = font.family();
16953 }
17054
17155 bool Stats::includeTimingRecord(const QString& name) {
@@ -190,161 +74,70 @@ bool Stats::includeTimingRecord(const QString& name) { · 18 unmodified lines
19074 return false;
19175 }
19276
193−// display expanded or contracted stats
194−void Stats::display(
195− const float* color,
196− int horizontalOffset,
197− float fps,
198− int inPacketsPerSecond,
199− int outPacketsPerSecond,
200− int inKbitsPerSecond,
201− int outKbitsPerSecond,
202− int voxelPacketsToProcess)
203−{
204− auto canvasSize = Application::getInstance()->getCanvasSize();
205−
206− unsigned int backgroundColor = 0x33333399;
207− int verticalOffset = 0, lines = 0;
208− float scale = 0.10f;
209− float rotation = 0.0f;
210− int font = 2;
211−
212− QLocale locale(QLocale::English);
213− std::stringstream octreeStats;
214−
215− QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
216−
217− if (_lastHorizontalOffset != horizontalOffset) {
218− resetWidth(canvasSize.x, horizontalOffset);
219− _lastHorizontalOffset = horizontalOffset;
77+#define STAT_UPDATE(name, src) \
78+ { \
79+ auto val = src; \
80+ if (_##name != val) { \
81+ _##name = val; \
82+ emit name##Changed(); \
83+ } \
22084 }
22185
222− glPointSize(1.0f);
223−
224− // we need to take one avatar out so we don't include ourselves
225− int totalAvatars = DependencyManager::get<AvatarManager>()->size() - 1;
226− int totalServers = DependencyManager::get<NodeList>()->size();
227−
228− lines = 5;
229− int columnOneWidth = _generalStatsWidth;
230−
231− bool performanceTimerIsActive = PerformanceTimer::isActive();
232− bool displayPerf = _expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails);
233− if (displayPerf && performanceTimerIsActive) {
234− PerformanceTimer::tallyAllTimerRecords(); // do this even if we're not displaying them, so they don't stack up
235−
236− columnOneWidth = _generalStatsWidth + _pingStatsWidth + _geoStatsWidth; // 3 columns wide...
237− // we will also include room for 1 line per timing record and a header of 4 lines
238− lines += 4;
239−
240− const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
241− QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
242− bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen);
243− int statsLines = 0;
244− while (i.hasNext()) {
245− i.next();
246− if (includeTimingRecord(i.key())) {
247− lines++;
248− statsLines++;
249− if (onlyDisplayTopTen && statsLines == 10) {
250− break;
251− }
252− }
253− }
86+#define STAT_UPDATE_FLOAT(name, src, epsilon) \
87+ { \
88+ float val = src; \
89+ if (fabs(_##name - val) >= epsilon) { \
90+ _##name = val; \
91+ emit name##Changed(); \
92+ } \
25493 }
255−
256− drawBackground(backgroundColor, horizontalOffset, 0, columnOneWidth, (lines + 1) * STATS_PELS_PER_LINE);
257− horizontalOffset += 5;
258−
259− int columnOneHorizontalOffset = horizontalOffset;
260−
261− QString serverNodes = QString("Servers: %1").arg(totalServers);
262− QString avatarNodes = QString("Avatars: %1").arg(totalAvatars);
263− QString framesPerSecond = QString("Framerate: %1 FPS").arg(fps, 3, 'f', 0);
264−
265− verticalOffset = STATS_PELS_INITIALOFFSET; // first one is offset by less than a line
266− drawText(horizontalOffset, verticalOffset, scale, rotation, font, serverNodes.toUtf8().constData(), color);
267− verticalOffset += STATS_PELS_PER_LINE;
268− drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarNodes.toUtf8().constData(), color);
269− verticalOffset += STATS_PELS_PER_LINE;
270− drawText(horizontalOffset, verticalOffset, scale, rotation, font, framesPerSecond.toUtf8().constData(), color);
271−
272− QString packetsPerSecondString = QString("Packets In/Out: %1/%2").arg(inPacketsPerSecond).arg(outPacketsPerSecond);
273− QString averageMegabitsPerSecond = QString("Mbps In/Out: %1/%2").
274− arg((float)inKbitsPerSecond * 1.0f / 1000.0f).
275− arg((float)outKbitsPerSecond * 1.0f / 1000.0f);
276−
277− verticalOffset += STATS_PELS_PER_LINE;
278− drawText(horizontalOffset, verticalOffset, scale, rotation, font, packetsPerSecondString.toUtf8().constData(), color);
279− verticalOffset += STATS_PELS_PER_LINE;
280− drawText(horizontalOffset, verticalOffset, scale, rotation, font, averageMegabitsPerSecond.toUtf8().constData(), color);
28194
282−
283− // TODO: the display of these timing details should all be moved to JavaScript
284− if (displayPerf && performanceTimerIsActive) {
285− bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen);
286− // Timing details...
287− verticalOffset += STATS_PELS_PER_LINE * 4; // skip 3 lines to be under the other columns
288− drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font,
289− "-------------------------------------------------------- Function "
290− "------------------------------------------------------- --msecs- -calls--", color);
291−
292− // First iterate all the records, and for the ones that should be included, insert them into
293− // a new Map sorted by average time...
294− QMap<float, QString> sortedRecords;
295− const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
296− QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
29795
298− while (i.hasNext()) {
299− i.next();
300− if (includeTimingRecord(i.key())) {
301− float averageTime = (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC;
302− sortedRecords.insertMulti(averageTime, i.key());
303− }
96+void Stats::updateStats() {
97+ if (!Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
98+ if (isVisible()) {
99+ setVisible(false);
304100 }
305−
306− int linesDisplayed = 0;
307− QMapIterator<float, QString> j(sortedRecords);
308− j.toBack();
309− while (j.hasPrevious()) {
310− j.previous();
311− QChar noBreakingSpace = QChar::Nbsp;
312− QString functionName = j.value();
313− const PerformanceTimerRecord& record = allRecords.value(functionName);
314−
315− QString perfLine = QString("%1: %2 [%3]").
316− arg(QString(qPrintable(functionName)), 120, noBreakingSpace).
317− arg((float)record.getMovingAverage() / (float)USECS_PER_MSEC, 8, 'f', 3, noBreakingSpace).
318− arg((int)record.getCount(), 6, 10, noBreakingSpace);
319−
320− verticalOffset += STATS_PELS_PER_LINE;
321− drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font, perfLine.toUtf8().constData(), color);
322− linesDisplayed++;
323− if (onlyDisplayTopTen && linesDisplayed == 10) {
324− break;
325− }
101+ return;
102+ } else {
103+ if (!isVisible()) {
104+ setVisible(true);
326105 }
327106 }
328107
108+ bool shouldDisplayTimingDetail = Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) &&
109+ Menu::getInstance()->isOptionChecked(MenuOption::Stats) && isExpanded();
110+ if (shouldDisplayTimingDetail != PerformanceTimer::isActive()) {
111+ PerformanceTimer::setActive(shouldDisplayTimingDetail);
112+ }
329113
330− verticalOffset = STATS_PELS_INITIALOFFSET;
331− horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + 1;
332114
333− if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
334− int pingAudio = -1, pingAvatar = -1, pingVoxel = -1, pingOctreeMax = -1;
115+ auto nodeList = DependencyManager::get<NodeList>();
116+ auto avatarManager = DependencyManager::get<AvatarManager>();
117+ // we need to take one avatar out so we don't include ourselves
118+ STAT_UPDATE(avatarCount, avatarManager->size() - 1);
119+ STAT_UPDATE(serverCount, nodeList->size());
120+ STAT_UPDATE(framerate, (int)qApp->getFps());
121+
122+ auto bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
123+ STAT_UPDATE(packetInCount, bandwidthRecorder->getCachedTotalAverageInputPacketsPerSecond());
124+ STAT_UPDATE(packetOutCount, bandwidthRecorder->getCachedTotalAverageOutputPacketsPerSecond());
125+ STAT_UPDATE_FLOAT(mbpsIn, (float)bandwidthRecorder->getCachedTotalAverageOutputKilobitsPerSecond() / 1000.0f, 0.01f);
126+ STAT_UPDATE_FLOAT(mbpsOut, (float)bandwidthRecorder->getCachedTotalAverageInputKilobitsPerSecond() / 1000.0f, 0.01f);
335127
336− auto nodeList = DependencyManager::get<NodeList>();
128+ // Second column: ping
129+ if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
337130 SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer);
338131 SharedNodePointer avatarMixerNode = nodeList->soloNodeOfType(NodeType::AvatarMixer);
132+ STAT_UPDATE(audioPing, audioMixerNode ? audioMixerNode->getPingMs() : -1);
133+ STAT_UPDATE(avatarPing, avatarMixerNode ? avatarMixerNode->getPingMs() : -1);
339134
340− pingAudio = audioMixerNode ? audioMixerNode->getPingMs() : -1;
341− pingAvatar = avatarMixerNode ? avatarMixerNode->getPingMs() : -1;
342−
343− // Now handle voxel servers, since there could be more than one, we average their ping times
135+ //// Now handle voxel servers, since there could be more than one, we average their ping times
344136 unsigned long totalPingOctree = 0;
345137 int octreeServerCount = 0;
346−
347− nodeList->eachNode([&totalPingOctree, &pingOctreeMax, &octreeServerCount](const SharedNodePointer& node){
138+ int pingOctreeMax = 0;
139+ int pingVoxel;
140+ nodeList->eachNode([&](const SharedNodePointer& node) {
348141 // TODO: this should also support entities
349142 if (node->getType() == NodeType::EntityServer) {
350143 totalPingOctree += node->getPingMs();
@@ -359,168 +152,85 @@ void Stats::display( · 8 unmodified lines
359152 pingVoxel = totalPingOctree / octreeServerCount;
360153 }
361154
362− lines = _expanded ? 4 : 3;
363−
364− // only draw our background if column one didn't draw a wide background
365− if (columnOneWidth == _generalStatsWidth) {
366− drawBackground(backgroundColor, horizontalOffset, 0, _pingStatsWidth, (lines + 1) * STATS_PELS_PER_LINE);
367− }
368− horizontalOffset += 5;
369−
370−
371− QString audioPing;
372− if (pingAudio >= 0) {
373− audioPing = QString("Audio ping: %1").arg(pingAudio);
374− } else {
375− audioPing = QString("Audio ping: --");
376− }
377−
378− QString avatarPing;
379− if (pingAvatar >= 0) {
380− avatarPing = QString("Avatar ping: %1").arg(pingAvatar);
381− } else {
382− avatarPing = QString("Avatar ping: --");
383− }
384−
385− QString voxelAvgPing;
386− if (pingVoxel >= 0) {
387− voxelAvgPing = QString("Entities avg ping: %1").arg(pingVoxel);
388− } else {
389− voxelAvgPing = QString("Entities avg ping: --");
390− }
391−
392− drawText(horizontalOffset, verticalOffset, scale, rotation, font, audioPing.toUtf8().constData(), color);
393− verticalOffset += STATS_PELS_PER_LINE;
394− drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarPing.toUtf8().constData(), color);
395− verticalOffset += STATS_PELS_PER_LINE;
396− drawText(horizontalOffset, verticalOffset, scale, rotation, font, voxelAvgPing.toUtf8().constData(), color);
397−
398− if (_expanded) {
399− QString voxelMaxPing;
400− if (pingVoxel >= 0) { // Average is only meaningful if pingVoxel is valid.
401− voxelMaxPing = QString("Voxel max ping: %1").arg(pingOctreeMax);
402− } else {
403− voxelMaxPing = QString("Voxel max ping: --");
404− }
405−
406− verticalOffset += STATS_PELS_PER_LINE;
407− drawText(horizontalOffset, verticalOffset, scale, rotation, font, voxelMaxPing.toUtf8().constData(), color);
408− }
409−
410− verticalOffset = STATS_PELS_INITIALOFFSET;
411− horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + _pingStatsWidth + 2;
155+ //STAT_UPDATE(entitiesPing, pingVoxel);
156+ //if (_expanded) {
157+ // QString voxelMaxPing;
158+ // if (pingVoxel >= 0) { // Average is only meaningful if pingVoxel is valid.
159+ // voxelMaxPing = QString("Voxel max ping: %1").arg(pingOctreeMax);
160+ // } else {
161+ // voxelMaxPing = QString("Voxel max ping: --");
162+ // }
163+ } else {
164+ // -2 causes the QML to hide the ping column
165+ STAT_UPDATE(audioPing, -2);
412166 }
413167
414− MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
415− glm::vec3 avatarPos = myAvatar->getPosition();
416−
417− lines = _expanded ? 7 : 3;
418−
419− if (columnOneWidth == _generalStatsWidth) {
420− drawBackground(backgroundColor, horizontalOffset, 0, _geoStatsWidth, (lines + 1) * STATS_PELS_PER_LINE);
421− }
422− horizontalOffset += 5;
423−
424− QString avatarPosition = QString("Position: %1, %2, %3").
425− arg(avatarPos.x, -1, 'f', 1).
426− arg(avatarPos.y, -1, 'f', 1).
427− arg(avatarPos.z, -1, 'f', 1);
428− QString avatarVelocity = QString("Velocity: %1").arg(glm::length(myAvatar->getVelocity()), -1, 'f', 1);
429− QString avatarBodyYaw = QString("Yaw: %1").arg(myAvatar->getBodyYaw(), -1, 'f', 1);
430− QString avatarMixerStats;
431−
432− drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarPosition.toUtf8().constData(), color);
433− verticalOffset += STATS_PELS_PER_LINE;
434− drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarVelocity.toUtf8().constData(), color);
435− verticalOffset += STATS_PELS_PER_LINE;
436− drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarBodyYaw.toUtf8().constData(), color);
437168
169+ // Third column, avatar stats
170+ MyAvatar* myAvatar = avatarManager->getMyAvatar();
171+ glm::vec3 avatarPos = myAvatar->getPosition();
172+ STAT_UPDATE(position, QVector3D(avatarPos.x, avatarPos.y, avatarPos.z));
173+ STAT_UPDATE_FLOAT(velocity, glm::length(myAvatar->getVelocity()), 0.1f);
174+ STAT_UPDATE_FLOAT(yaw, myAvatar->getBodyYaw(), 0.1f);
438175 if (_expanded) {
439− SharedNodePointer avatarMixer = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::AvatarMixer);
176+ SharedNodePointer avatarMixer = nodeList->soloNodeOfType(NodeType::AvatarMixer);
440177 if (avatarMixer) {
441− avatarMixerStats = QString("Avatar Mixer: %1 kbps, %2 pps").
442− arg(roundf(bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer) +
443− bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AudioMixer))).
444− arg(roundf(bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer) +
445− bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer)));
178+ STAT_UPDATE(avatarMixerKbps, roundf(
179+ bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AvatarMixer) +
180+ bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AvatarMixer)));
181+ STAT_UPDATE(avatarMixerPps, roundf(
182+ bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AvatarMixer) +
183+ bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AvatarMixer)));
446184 } else {
447− avatarMixerStats = QString("No Avatar Mixer");
185+ STAT_UPDATE(avatarMixerKbps, -1);
186+ STAT_UPDATE(avatarMixerPps, -1);
448187 }
449−
450− verticalOffset += STATS_PELS_PER_LINE;
451− drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarMixerStats.toUtf8().constData(), color);
452−
453− stringstream downloads;
454− downloads << "Downloads: ";
455− foreach (Resource* resource, ResourceCache::getLoadingRequests()) {
456− downloads << (int)(resource->getProgress() * 100.0f) << "% ";
188+ SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer);
189+ if (audioMixerNode) {
190+ STAT_UPDATE(audioMixerKbps, roundf(
191+ bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer) +
192+ bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AudioMixer)));
193+ STAT_UPDATE(audioMixerPps, roundf(
194+ bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer) +
195+ bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer)));
196+ } else {
197+ STAT_UPDATE(audioMixerKbps, -1);
198+ STAT_UPDATE(audioMixerPps, -1);
457199 }
458− downloads << "(" << ResourceCache::getPendingRequestCount() << " pending)";
459−
460− verticalOffset += STATS_PELS_PER_LINE;
461− drawText(horizontalOffset, verticalOffset, scale, rotation, font, downloads.str().c_str(), color);
462− }
463200
464− verticalOffset = STATS_PELS_INITIALOFFSET;
465− horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3;
466−
467− lines = _expanded ? 10 : 3;
468−
469− drawBackground(backgroundColor, horizontalOffset, 0, canvasSize.x - horizontalOffset,
470− (lines + 1) * STATS_PELS_PER_LINE);
471− horizontalOffset += 5;
472−
473− // Model/Entity render details
474− octreeStats.str("");
475− octreeStats << "Triangles: " << _renderDetails._trianglesRendered
476− << " / Quads:" << _renderDetails._quadsRendered
477− << " / Material Switches:" << _renderDetails._materialSwitches;
478− drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
479−
480− if (_expanded) {
481− octreeStats.str("");
482− octreeStats << " Mesh Parts Rendered Opaque: " << _renderDetails._opaque._rendered
483− << " / Translucent:" << _renderDetails._translucent._rendered;
484− verticalOffset += STATS_PELS_PER_LINE;
485− drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
486−
487− octreeStats.str("");
488− octreeStats << " Opaque considered: " << _renderDetails._opaque._considered
489− << " / Out of view:" << _renderDetails._opaque._outOfView
490− << " / Too small:" << _renderDetails._opaque._tooSmall;
491− verticalOffset += STATS_PELS_PER_LINE;
492− drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
493−
494− octreeStats.str("");
495− octreeStats << " Translucent considered: " << _renderDetails._translucent._considered
496− << " / Out of view:" << _renderDetails._translucent._outOfView
497− << " / Too small:" << _renderDetails._translucent._tooSmall;
498− verticalOffset += STATS_PELS_PER_LINE;
499− drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
500− }
501−
502− // iterate all the current voxel stats, and list their sending modes, and total voxel counts
503− std::stringstream sendingMode("");
504− sendingMode << "Octree Sending Mode: [";
201+ STAT_UPDATE(downloads, ResourceCache::getLoadingRequests().size());
202+ STAT_UPDATE(downloadsPending, ResourceCache::getPendingRequestCount());
203+ // TODO fix to match original behavior
204+ //stringstream downloads;
205+ //downloads << "Downloads: ";
206+ //foreach(Resource* resource, ) {
207+ // downloads << (int)(resource->getProgress() * 100.0f) << "% ";
208+ //}
209+ //downloads << "(" << << " pending)";
210+ } // expanded avatar column
211+
212+ // Fourth column, octree stats
505213 int serverCount = 0;
506214 int movingServerCount = 0;
507215 unsigned long totalNodes = 0;
508216 unsigned long totalInternal = 0;
509217 unsigned long totalLeaves = 0;
218+ std::stringstream sendingModeStream("");
219+ sendingModeStream << "[";
510220 NodeToOctreeSceneStats* octreeServerSceneStats = Application::getInstance()->getOcteeSceneStats();
511− for(NodeToOctreeSceneStatsIterator i = octreeServerSceneStats->begin(); i != octreeServerSceneStats->end(); i++) {
221+ for (NodeToOctreeSceneStatsIterator i = octreeServerSceneStats->begin(); i != octreeServerSceneStats->end(); i++) {
512222 //const QUuid& uuid = i->first;
513223 OctreeSceneStats& stats = i->second;
514224 serverCount++;
515225 if (_expanded) {
516226 if (serverCount > 1) {
517− sendingMode << ",";
227+ sendingModeStream << ",";
518228 }
519229 if (stats.isMoving()) {
520− sendingMode << "M";
230+ sendingModeStream << "M";
521231 movingServerCount++;
522232 } else {
523− sendingMode << "S";
233+ sendingModeStream << "S";
524234 }
525235 }
526236
@@ -528,32 +238,35 @@ void Stats::display( · 1 unmodified line
528238 totalNodes += stats.getTotalElements();
529239 if (_expanded) {
530240 totalInternal += stats.getTotalInternal();
531− totalLeaves += stats.getTotalLeaves();
241+ totalLeaves += stats.getTotalLeaves();
532242 }
533243 }
534244 if (_expanded) {
535245 if (serverCount == 0) {
536− sendingMode << "---";
246+ sendingModeStream << "---";
537247 }
538− sendingMode << "] " << serverCount << " servers";
248+ sendingModeStream << "] " << serverCount << " servers";
539249 if (movingServerCount > 0) {
540− sendingMode << " <SCENE NOT STABLE>";
250+ sendingModeStream << " <SCENE NOT STABLE>";
541251 } else {
542− sendingMode << " <SCENE STABLE>";
252+ sendingModeStream << " <SCENE STABLE>";
543253 }
544− verticalOffset += STATS_PELS_PER_LINE;
545− drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)sendingMode.str().c_str(), color);
254+ QString sendingModeResult = sendingModeStream.str().c_str();
255+ STAT_UPDATE(sendingMode, sendingModeResult);
546256 }
547257
548258 // Incoming packets
259+ QLocale locale(QLocale::English);
260+ auto voxelPacketsToProcess = qApp->getOctreePacketProcessor().packetsToProcessCount();
549261 if (_expanded) {
550− octreeStats.str("");
262+ std::stringstream octreeStats;
551263 QString packetsString = locale.toString((int)voxelPacketsToProcess);
552264 QString maxString = locale.toString((int)_recentMaxPackets);
553265 octreeStats << "Octree Packets to Process: " << qPrintable(packetsString)
554− << " [Recent Max: " << qPrintable(maxString) << "]";
555− verticalOffset += STATS_PELS_PER_LINE;
556− drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
266+ << " [Recent Max: " << qPrintable(maxString) << "]";
267+ QString str = octreeStats.str().c_str();
268+ STAT_UPDATE(packetStats, str);
269+ // drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
557270 }
558271
559272 if (_resetRecentMaxPacketsSoon && voxelPacketsToProcess > 0) {
@@ -562,60 +275,102 @@ void Stats::display( · 2 unmodified lines
562275 }
563276 if (voxelPacketsToProcess == 0) {
564277 _resetRecentMaxPacketsSoon = true;
565− } else {
566− if (voxelPacketsToProcess > _recentMaxPackets) {
567− _recentMaxPackets = voxelPacketsToProcess;
568− }
278+ } else if (voxelPacketsToProcess > _recentMaxPackets) {
279+ _recentMaxPackets = voxelPacketsToProcess;
569280 }
570281
571− QString serversTotalString = locale.toString((uint)totalNodes); // consider adding: .rightJustified(10, ' ');
572− unsigned long localTotal = OctreeElement::getNodeCount();
573− QString localTotalString = locale.toString((uint)localTotal); // consider adding: .rightJustified(10, ' ');
574−
575282 // Server Octree Elements
576− if (!_expanded) {
577− octreeStats.str("");
578− octreeStats << "Octree Elements Server: " << qPrintable(serversTotalString)
579− << " Local:" << qPrintable(localTotalString);
580− verticalOffset += STATS_PELS_PER_LINE;
581− drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
582− }
283+ STAT_UPDATE(serverElements, totalNodes);
284+ STAT_UPDATE(localElements, OctreeElement::getNodeCount());
583285
584286 if (_expanded) {
585− octreeStats.str("");
586− octreeStats << "Octree Elements -";
587− verticalOffset += STATS_PELS_PER_LINE;
588− drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
287+ STAT_UPDATE(serverInternal, totalInternal);
288+ STAT_UPDATE(serverLeaves, totalLeaves);
289+ // Local Voxels
290+ STAT_UPDATE(localInternal, OctreeElement::getInternalNodeCount());
291+ STAT_UPDATE(localLeaves, OctreeElement::getLeafNodeCount());
292+ // LOD Details
293+ STAT_UPDATE(lodStatus, "You can see " + DependencyManager::get<LODManager>()->getLODFeedbackText());
294+ }
589295
590− QString serversInternalString = locale.toString((uint)totalInternal);
591− QString serversLeavesString = locale.toString((uint)totalLeaves);
296+ bool performanceTimerIsActive = PerformanceTimer::isActive();
297+ bool displayPerf = _expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails);
298+ if (displayPerf && performanceTimerIsActive) {
299+ if (!_timingExpanded) {
300+ _timingExpanded = true;
301+ emit timingExpandedChanged();
302+ }
303+ PerformanceTimer::tallyAllTimerRecords(); // do this even if we're not displaying them, so they don't stack up
592304
593− octreeStats.str("");
594− octreeStats << " Server: " << qPrintable(serversTotalString) <<
595− " Internal: " << qPrintable(serversInternalString) <<
596− " Leaves: " << qPrintable(serversLeavesString);
597− verticalOffset += STATS_PELS_PER_LINE;
598− drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
305+ // we will also include room for 1 line per timing record and a header of 4 lines
306+ // Timing details...
599307
600− // Local Voxels
601− unsigned long localInternal = OctreeElement::getInternalNodeCount();
602− unsigned long localLeaves = OctreeElement::getLeafNodeCount();
603− QString localInternalString = locale.toString((uint)localInternal);
604− QString localLeavesString = locale.toString((uint)localLeaves);
605−
606− octreeStats.str("");
607− octreeStats << " Local: " << qPrintable(serversTotalString) <<
608− " Internal: " << qPrintable(localInternalString) <<
609− " Leaves: " << qPrintable(localLeavesString) << "";
610− verticalOffset += STATS_PELS_PER_LINE;
611− drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
308+ // First iterate all the records, and for the ones that should be included, insert them into
309+ // a new Map sorted by average time...
310+ bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen);
311+ QMap<float, QString> sortedRecords;
312+ const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
313+ QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
314+
315+ while (i.hasNext()) {
316+ i.next();
317+ if (includeTimingRecord(i.key())) {
318+ float averageTime = (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC;
319+ sortedRecords.insertMulti(averageTime, i.key());
320+ }
321+ }
322+
323+ int linesDisplayed = 0;
324+ QMapIterator<float, QString> j(sortedRecords);
325+ j.toBack();
326+ QString perfLines;
327+ while (j.hasPrevious()) {
328+ j.previous();
329+ static const QChar noBreakingSpace = QChar::Nbsp;
330+ QString functionName = j.value();
331+ const PerformanceTimerRecord& record = allRecords.value(functionName);
332+ perfLines += QString("%1: %2 [%3]\n").
333+ arg(QString(qPrintable(functionName)), 90, noBreakingSpace).
334+ arg((float)record.getMovingAverage() / (float)USECS_PER_MSEC, 8, 'f', 3, noBreakingSpace).
335+ arg((int)record.getCount(), 6, 10, noBreakingSpace);
336+ linesDisplayed++;
337+ if (onlyDisplayTopTen && linesDisplayed == 10) {
338+ break;
339+ }
340+ }
341+ _timingStats = perfLines;
342+ emit timingStatsChanged();
343+ } else if (_timingExpanded) {
344+ _timingExpanded = false;
345+ emit timingExpandedChanged();
612346 }
347+}
348+
349+void Stats::setRenderDetails(const RenderDetails& details) {
350+ STAT_UPDATE(triangles, details._trianglesRendered);
351+ STAT_UPDATE(quads, details._quadsRendered);
352+ STAT_UPDATE(materialSwitches, details._materialSwitches);
353+ if (_expanded) {
354+ STAT_UPDATE(meshOpaque, details._opaque._rendered);
355+ STAT_UPDATE(meshTranslucent, details._opaque._rendered);
356+ STAT_UPDATE(opaqueConsidered, details._opaque._considered);
357+ STAT_UPDATE(opaqueOutOfView, details._opaque._outOfView);
358+ STAT_UPDATE(opaqueTooSmall, details._opaque._tooSmall);
359+ STAT_UPDATE(translucentConsidered, details._translucent._considered);
360+ STAT_UPDATE(translucentOutOfView, details._translucent._outOfView);
361+ STAT_UPDATE(translucentTooSmall, details._translucent._tooSmall);
362+ }
363+}
364+
365+
366+/*
367+// display expanded or contracted stats
368+void Stats::display(
369+ int voxelPacketsToProcess)
370+{
371+ // iterate all the current voxel stats, and list their sending modes, and total voxel counts
613372
614− // LOD Details
615− octreeStats.str("");
616− QString displayLODDetails = DependencyManager::get<LODManager>()->getLODFeedbackText();
617− octreeStats << "LOD: You can see " << qPrintable(displayLODDetails.trimmed());
618− verticalOffset += STATS_PELS_PER_LINE;
619− drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
620373 }
621374
375+
376+*/
interface/src/ui/Stats.h+121−32
@@ -1,8 +1,5 @@
11 //
2−// Stats.h
3−// interface/src/ui
4−//
5−// Created by Lucas Crisman on 22/03/14.
2+// Created by Bradley Austin Davis 2015/06/17
63 // Copyright 2013 High Fidelity, Inc.
74 //
85 // Distributed under the Apache License, Version 2.0.
@@ -13,47 +10,139 @@ · 4 unmodified lines
1310 #define hifi_Stats_h
1411
1512 #include <QObject>
13+#include <QQuickItem>
14+#include <QVector3D>
1615
16+#include <OffscreenUi.h>
1717 #include <RenderArgs.h>
1818
19−class Stats: public QObject {
19+#define STATS_PROPERTY(type, name, initialValue) \
20+ Q_PROPERTY(type name READ name NOTIFY name##Changed) \
21+public: \
22+ type name() { return _##name; }; \
23+private: \
24+ type _##name{ initialValue };
25+
26+
27+class Stats : public QQuickItem {
2028 Q_OBJECT
29+ HIFI_QML_DECL
30+ Q_PROPERTY(bool expanded READ isExpanded WRITE setExpanded NOTIFY expandedChanged)
31+ Q_PROPERTY(bool timingExpanded READ isTimingExpanded NOTIFY timingExpandedChanged)
32+ Q_PROPERTY(QString monospaceFont READ monospaceFont)
33+
34+ STATS_PROPERTY(int, serverCount, 0)
35+ STATS_PROPERTY(int, framerate, 0)
36+ STATS_PROPERTY(int, avatarCount, 0)
37+ STATS_PROPERTY(int, packetInCount, 0)
38+ STATS_PROPERTY(int, packetOutCount, 0)
39+ STATS_PROPERTY(float, mbpsIn, 0)
40+ STATS_PROPERTY(float, mbpsOut, 0)
41+ STATS_PROPERTY(int, audioPing, 0)
42+ STATS_PROPERTY(int, avatarPing, 0)
43+ STATS_PROPERTY(int, entitiesPing, 0)
44+ STATS_PROPERTY(QVector3D, position, QVector3D(0, 0, 0) )
45+ STATS_PROPERTY(float, velocity, 0)
46+ STATS_PROPERTY(float, yaw, 0)
47+ STATS_PROPERTY(int, avatarMixerKbps, 0)
48+ STATS_PROPERTY(int, avatarMixerPps, 0)
49+ STATS_PROPERTY(int, audioMixerKbps, 0)
50+ STATS_PROPERTY(int, audioMixerPps, 0)
51+ STATS_PROPERTY(int, downloads, 0)
52+ STATS_PROPERTY(int, downloadsPending, 0)
53+ STATS_PROPERTY(int, triangles, 0)
54+ STATS_PROPERTY(int, quads, 0)
55+ STATS_PROPERTY(int, materialSwitches, 0)
56+ STATS_PROPERTY(int, meshOpaque, 0)
57+ STATS_PROPERTY(int, meshTranslucent, 0)
58+ STATS_PROPERTY(int, opaqueConsidered, 0)
59+ STATS_PROPERTY(int, opaqueOutOfView, 0)
60+ STATS_PROPERTY(int, opaqueTooSmall, 0)
61+ STATS_PROPERTY(int, translucentConsidered, 0)
62+ STATS_PROPERTY(int, translucentOutOfView, 0)
63+ STATS_PROPERTY(int, translucentTooSmall, 0)
64+ STATS_PROPERTY(QString, sendingMode, QString())
65+ STATS_PROPERTY(QString, packetStats, QString())
66+ STATS_PROPERTY(QString, lodStatus, QString())
67+ STATS_PROPERTY(QString, timingStats, QString())
68+ STATS_PROPERTY(int, serverElements, 0)
69+ STATS_PROPERTY(int, serverInternal, 0)
70+ STATS_PROPERTY(int, serverLeaves, 0)
71+ STATS_PROPERTY(int, localElements, 0)
72+ STATS_PROPERTY(int, localInternal, 0)
73+ STATS_PROPERTY(int, localLeaves, 0)
2174
2275 public:
2376 static Stats* getInstance();
2477
25− Stats();
26−
27− static void drawBackground(unsigned int rgba, int x, int y, int width, int height);
28−
29− void toggleExpanded();
30− bool isExpanded() { return _expanded; }
31−
32− void checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseDragStartedY, int horizontalOffset);
33− void resetWidth(int width, int horizontalOffset);
34− void display(const float* color, int horizontalOffset, float fps, int inPacketsPerSecond, int outPacketsPerSecond,
35− int inKbitsPerSecond, int outKbitsPerSecond, int voxelPacketsToProcess);
78+ Stats(QQuickItem* parent = nullptr);
3679 bool includeTimingRecord(const QString& name);
37−
38− void setRenderDetails(const RenderDetails& details) { _renderDetails = details; }
39−
40−private:
41− static Stats* _sharedInstance;
80+ void setRenderDetails(const RenderDetails& details);
81+ const QString& monospaceFont() {
82+ return _monospaceFont;
83+ }
84+ void updateStats();
4285
43− bool _expanded;
86+ bool isExpanded() { return _expanded; }
87+ bool isTimingExpanded() { return _timingExpanded; }
4488
45− int _recentMaxPackets; // recent max incoming voxel packets to process
46− bool _resetRecentMaxPacketsSoon;
89+ void setExpanded(bool expanded) {
90+ if (_expanded != expanded) {
91+ _expanded = expanded;
92+ emit expandedChanged();
93+ }
94+ }
4795
48− int _generalStatsWidth;
49− int _bandwidthStatsWidth;
50− int _pingStatsWidth;
51− int _geoStatsWidth;
52− int _octreeStatsWidth;
96+signals:
97+ void expandedChanged();
98+ void timingExpandedChanged();
99+ void serverCountChanged();
100+ void framerateChanged();
101+ void avatarCountChanged();
102+ void packetInCountChanged();
103+ void packetOutCountChanged();
104+ void mbpsInChanged();
105+ void mbpsOutChanged();
106+ void audioPingChanged();
107+ void avatarPingChanged();
108+ void entitiesPingChanged();
109+ void positionChanged();
110+ void velocityChanged();
111+ void yawChanged();
112+ void avatarMixerKbpsChanged();
113+ void avatarMixerPpsChanged();
114+ void audioMixerKbpsChanged();
115+ void audioMixerPpsChanged();
116+ void downloadsChanged();
117+ void downloadsPendingChanged();
118+ void trianglesChanged();
119+ void quadsChanged();
120+ void materialSwitchesChanged();
121+ void meshOpaqueChanged();
122+ void meshTranslucentChanged();
123+ void opaqueConsideredChanged();
124+ void opaqueOutOfViewChanged();
125+ void opaqueTooSmallChanged();
126+ void translucentConsideredChanged();
127+ void translucentOutOfViewChanged();
128+ void translucentTooSmallChanged();
129+ void sendingModeChanged();
130+ void packetStatsChanged();
131+ void lodStatusChanged();
132+ void serverElementsChanged();
133+ void serverInternalChanged();
134+ void serverLeavesChanged();
135+ void localElementsChanged();
136+ void localInternalChanged();
137+ void localLeavesChanged();
138+ void timingStatsChanged();
53139
54− int _lastHorizontalOffset;
55−
56− RenderDetails _renderDetails;
140+private:
141+ int _recentMaxPackets{ 0 } ; // recent max incoming voxel packets to process
142+ bool _resetRecentMaxPacketsSoon{ true };
143+ bool _expanded{ false };
144+ bool _timingExpanded{ false };
145+ QString _monospaceFont;
57146 };
58147
59148 #endif // hifi_Stats_h
interface/src/ui/UserInputMapper.cpp+1−1
@@ -53,7 +53,7 @@ void UserInputMapper::resetDevice(uint16 deviceID) { · 52 unmodified lines
5353
5454 int UserInputMapper::findDevice(QString name) {
5555 for (auto device : _registeredDevices) {
56− if (device.second->_name == name) {
56+ if (device.second->_name.split(" (")[0] == name) {
5757 return device.first;
5858 }
5959 }
interface/src/ui/overlays/Circle3DOverlay.cpp+161−181
@@ -11,6 +11,7 @@ · 10 unmodified lines
1111 // include this before QGLWidget, which includes an earlier version of OpenGL
1212 #include "InterfaceConfig.h"
1313
14+#include <DeferredLightingEffect.h>
1415 #include <GeometryCache.h>
1516 #include <GlowEffect.h>
1617 #include <SharedUtil.h>
@@ -75,20 +76,20 @@ void Circle3DOverlay::render(RenderArgs* args) { · 58 unmodified lines
7576
7677 float alpha = getAlpha();
7778
78− if (alpha == 0.0) {
79+ if (alpha == 0.0f) {
7980 return; // do nothing if our alpha is 0, we're not visible
8081 }
81−
82+
8283 // Create the circle in the coordinates origin
8384 float outerRadius = getOuterRadius();
8485 float innerRadius = getInnerRadius(); // only used in solid case
8586 float startAt = getStartAt();
8687 float endAt = getEndAt();
87−
88+
8889 bool geometryChanged = (startAt != _lastStartAt || endAt != _lastEndAt ||
8990 innerRadius != _lastInnerRadius || outerRadius != _lastOuterRadius);
9091
91−
92+
9293 const float FULL_CIRCLE = 360.0f;
9394 const float SLICES = 180.0f; // The amount of segment to create the circle
9495 const float SLICE_ANGLE = FULL_CIRCLE / SLICES;
@@ -101,195 +102,178 @@ void Circle3DOverlay::render(RenderArgs* args) { · 6 unmodified lines
101102 bool colorChanged = colorX.red != _lastColor.red || colorX.green != _lastColor.green || colorX.blue != _lastColor.blue;
102103 _lastColor = colorX;
103104
104− glDisable(GL_LIGHTING);
105−
106− glm::vec3 position = getPosition();
107− glm::vec3 center = getCenter();
108− glm::vec2 dimensions = getDimensions();
109− glm::quat rotation = getRotation();
110−
111− float glowLevel = getGlowLevel();
112− Glower* glower = NULL;
113− if (glowLevel > 0.0f) {
114− glower = new Glower(glowLevel);
115− }
116−
117− glPushMatrix();
118− glTranslatef(position.x, position.y, position.z);
119− glm::vec3 axis = glm::axis(rotation);
120− glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
121− glPushMatrix();
122− glm::vec3 positionToCenter = center - position;
123− glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
124− glScalef(dimensions.x / 2.0f, dimensions.y / 2.0f, 1.0f);
105+ auto geometryCache = DependencyManager::get<GeometryCache>();
125106
126− glLineWidth(_lineWidth);
127−
128− auto geometryCache = DependencyManager::get<GeometryCache>();
107+ Transform transform;
108+ transform.setTranslation(getCenter());
109+ transform.setRotation(getRotation());
110+ transform.setScale(glm::vec3(getDimensions(), 0.01f));
111+
112+
113+ auto& batch = *args->_batch;
114+ batch._glLineWidth(_lineWidth);
115+ batch.setModelTransform(transform);
116+ DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, false, false);
117+
118+ // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise
119+ // we just draw a line...
120+ if (getIsSolid()) {
121+ if (_quadVerticesID == GeometryCache::UNKNOWN_ID) {
122+ _quadVerticesID = geometryCache->allocateID();
123+ }
124+
125+ if (geometryChanged || colorChanged) {
129126
130− // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise
131− // we just draw a line...
132− if (getIsSolid()) {
133− if (_quadVerticesID == GeometryCache::UNKNOWN_ID) {
134− _quadVerticesID = geometryCache->allocateID();
135− }
127+ QVector<glm::vec2> points;
128+
129+ float angle = startAt;
130+ float angleInRadians = glm::radians(angle);
131+ glm::vec2 firstInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius);
132+ glm::vec2 firstOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius);
133+
134+ points << firstInnerPoint << firstOuterPoint;
135+
136+ while (angle < endAt) {
137+ angleInRadians = glm::radians(angle);
138+ glm::vec2 thisInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius);
139+ glm::vec2 thisOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius);
136140
137− if (geometryChanged || colorChanged) {
138−
139− QVector<glm::vec2> points;
140−
141− float angle = startAt;
142− float angleInRadians = glm::radians(angle);
143− glm::vec2 firstInnerPoint(cos(angleInRadians) * innerRadius, sin(angleInRadians) * innerRadius);
144− glm::vec2 firstOuterPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius);
145−
146− points << firstInnerPoint << firstOuterPoint;
147−
148− while (angle < endAt) {
149− angleInRadians = glm::radians(angle);
150− glm::vec2 thisInnerPoint(cos(angleInRadians) * innerRadius, sin(angleInRadians) * innerRadius);
151− glm::vec2 thisOuterPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius);
152−
153− points << thisOuterPoint << thisInnerPoint;
141+ points << thisOuterPoint << thisInnerPoint;
154142
155− angle += SLICE_ANGLE;
156− }
143+ angle += SLICE_ANGLE;
144+ }
157145
158− // get the last slice portion....
159− angle = endAt;
160− angleInRadians = glm::radians(angle);
161− glm::vec2 lastInnerPoint(cos(angleInRadians) * innerRadius, sin(angleInRadians) * innerRadius);
162− glm::vec2 lastOuterPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius);
146+ // get the last slice portion....
147+ angle = endAt;
148+ angleInRadians = glm::radians(angle);
149+ glm::vec2 lastInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius);
150+ glm::vec2 lastOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius);
163151
164− points << lastOuterPoint << lastInnerPoint;
165−
166− geometryCache->updateVertices(_quadVerticesID, points, color);
167− }
168−
169− geometryCache->renderVertices(gpu::QUAD_STRIP, _quadVerticesID);
170−
171− } else {
172− if (_lineVerticesID == GeometryCache::UNKNOWN_ID) {
173− _lineVerticesID = geometryCache->allocateID();
174− }
175−
176− if (geometryChanged || colorChanged) {
177− QVector<glm::vec2> points;
178−
179− float angle = startAt;
180− float angleInRadians = glm::radians(angle);
181− glm::vec2 firstPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius);
182− points << firstPoint;
183−
184− while (angle < endAt) {
185− angle += SLICE_ANGLE;
186− angleInRadians = glm::radians(angle);
187− glm::vec2 thisPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius);
188− points << thisPoint;
189−
190− if (getIsDashedLine()) {
191− angle += SLICE_ANGLE / 2.0f; // short gap
192− angleInRadians = glm::radians(angle);
193− glm::vec2 dashStartPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius);
194− points << dashStartPoint;
195− }
196− }
152+ points << lastOuterPoint << lastInnerPoint;
197153
198− // get the last slice portion....
199− angle = endAt;
200− angleInRadians = glm::radians(angle);
201− glm::vec2 lastPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius);
202− points << lastPoint;
203−
204− geometryCache->updateVertices(_lineVerticesID, points, color);
205− }
206−
154+ geometryCache->updateVertices(_quadVerticesID, points, color);
155+ }
156+
157+ geometryCache->renderVertices(batch, gpu::QUAD_STRIP, _quadVerticesID);
158+
159+ } else {
160+ if (_lineVerticesID == GeometryCache::UNKNOWN_ID) {
161+ _lineVerticesID = geometryCache->allocateID();
162+ }
163+
164+ if (geometryChanged || colorChanged) {
165+ QVector<glm::vec2> points;
166+
167+ float angle = startAt;
168+ float angleInRadians = glm::radians(angle);
169+ glm::vec2 firstPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius);
170+ points << firstPoint;
171+
172+ while (angle < endAt) {
173+ angle += SLICE_ANGLE;
174+ angleInRadians = glm::radians(angle);
175+ glm::vec2 thisPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius);
176+ points << thisPoint;
177+
207178 if (getIsDashedLine()) {
208− geometryCache->renderVertices(gpu::LINES, _lineVerticesID);
209− } else {
210− geometryCache->renderVertices(gpu::LINE_STRIP, _lineVerticesID);
179+ angle += SLICE_ANGLE / 2.0f; // short gap
180+ angleInRadians = glm::radians(angle);
181+ glm::vec2 dashStartPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius);
182+ points << dashStartPoint;
211183 }
212184 }
213185
214− // draw our tick marks
215− // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise
216− // we just draw a line...
217− if (getHasTickMarks()) {
218−
219− if (_majorTicksVerticesID == GeometryCache::UNKNOWN_ID) {
220− _majorTicksVerticesID = geometryCache->allocateID();
221− }
222− if (_minorTicksVerticesID == GeometryCache::UNKNOWN_ID) {
223− _minorTicksVerticesID = geometryCache->allocateID();
224− }
225−
226− if (geometryChanged) {
227− QVector<glm::vec2> majorPoints;
228− QVector<glm::vec2> minorPoints;
229−
230− // draw our major tick marks
231− if (getMajorTickMarksAngle() > 0.0f && getMajorTickMarksLength() != 0.0f) {
186+ // get the last slice portion....
187+ angle = endAt;
188+ angleInRadians = glm::radians(angle);
189+ glm::vec2 lastPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius);
190+ points << lastPoint;
191+
192+ geometryCache->updateVertices(_lineVerticesID, points, color);
193+ }
194+
195+ if (getIsDashedLine()) {
196+ geometryCache->renderVertices(batch, gpu::LINES, _lineVerticesID);
197+ } else {
198+ geometryCache->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID);
199+ }
200+ }
201+
202+ // draw our tick marks
203+ // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise
204+ // we just draw a line...
205+ if (getHasTickMarks()) {
206+
207+ if (_majorTicksVerticesID == GeometryCache::UNKNOWN_ID) {
208+ _majorTicksVerticesID = geometryCache->allocateID();
209+ }
210+ if (_minorTicksVerticesID == GeometryCache::UNKNOWN_ID) {
211+ _minorTicksVerticesID = geometryCache->allocateID();
212+ }
213+
214+ if (geometryChanged) {
215+ QVector<glm::vec2> majorPoints;
216+ QVector<glm::vec2> minorPoints;
217+
218+ // draw our major tick marks
219+ if (getMajorTickMarksAngle() > 0.0f && getMajorTickMarksLength() != 0.0f) {
232220
233− float tickMarkAngle = getMajorTickMarksAngle();
234− float angle = startAt - fmod(startAt, tickMarkAngle) + tickMarkAngle;
235− float angleInRadians = glm::radians(angle);
236− float tickMarkLength = getMajorTickMarksLength();
237− float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius;
238− float endRadius = startRadius + tickMarkLength;
239−
240− while (angle <= endAt) {
241− angleInRadians = glm::radians(angle);
242−
243− glm::vec2 thisPointA(cos(angleInRadians) * startRadius, sin(angleInRadians) * startRadius);
244− glm::vec2 thisPointB(cos(angleInRadians) * endRadius, sin(angleInRadians) * endRadius);
245−
246− majorPoints << thisPointA << thisPointB;
221+ float tickMarkAngle = getMajorTickMarksAngle();
222+ float angle = startAt - fmodf(startAt, tickMarkAngle) + tickMarkAngle;
223+ float angleInRadians = glm::radians(angle);
224+ float tickMarkLength = getMajorTickMarksLength();
225+ float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius;
226+ float endRadius = startRadius + tickMarkLength;
247227
248− angle += tickMarkAngle;
249− }
250− }
251−
252− // draw our minor tick marks
253− if (getMinorTickMarksAngle() > 0.0f && getMinorTickMarksLength() != 0.0f) {
228+ while (angle <= endAt) {
229+ angleInRadians = glm::radians(angle);
230+
231+ glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius);
232+ glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius);
233+
234+ majorPoints << thisPointA << thisPointB;
235+
236+ angle += tickMarkAngle;
237+ }
238+ }
239+
240+ // draw our minor tick marks
241+ if (getMinorTickMarksAngle() > 0.0f && getMinorTickMarksLength() != 0.0f) {
254242
255− float tickMarkAngle = getMinorTickMarksAngle();
256− float angle = startAt - fmod(startAt, tickMarkAngle) + tickMarkAngle;
257− float angleInRadians = glm::radians(angle);
258− float tickMarkLength = getMinorTickMarksLength();
259− float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius;
260− float endRadius = startRadius + tickMarkLength;
261−
262− while (angle <= endAt) {
263− angleInRadians = glm::radians(angle);
264−
265− glm::vec2 thisPointA(cos(angleInRadians) * startRadius, sin(angleInRadians) * startRadius);
266− glm::vec2 thisPointB(cos(angleInRadians) * endRadius, sin(angleInRadians) * endRadius);
267−
268− minorPoints << thisPointA << thisPointB;
243+ float tickMarkAngle = getMinorTickMarksAngle();
244+ float angle = startAt - fmodf(startAt, tickMarkAngle) + tickMarkAngle;
245+ float angleInRadians = glm::radians(angle);
246+ float tickMarkLength = getMinorTickMarksLength();
247+ float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius;
248+ float endRadius = startRadius + tickMarkLength;
269249
270− angle += tickMarkAngle;
271− }
272− }
273−
274− xColor majorColorX = getMajorTickMarksColor();
275− glm::vec4 majorColor(majorColorX.red / MAX_COLOR, majorColorX.green / MAX_COLOR, majorColorX.blue / MAX_COLOR, alpha);
276−
277− geometryCache->updateVertices(_majorTicksVerticesID, majorPoints, majorColor);
278−
279− xColor minorColorX = getMinorTickMarksColor();
280− glm::vec4 minorColor(minorColorX.red / MAX_COLOR, minorColorX.green / MAX_COLOR, minorColorX.blue / MAX_COLOR, alpha);
281−
282− geometryCache->updateVertices(_minorTicksVerticesID, minorPoints, minorColor);
250+ while (angle <= endAt) {
251+ angleInRadians = glm::radians(angle);
252+
253+ glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius);
254+ glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius);
255+
256+ minorPoints << thisPointA << thisPointB;
257+
258+ angle += tickMarkAngle;
283259 }
284−
285− geometryCache->renderVertices(gpu::LINES, _majorTicksVerticesID);
286−
287− geometryCache->renderVertices(gpu::LINES, _minorTicksVerticesID);
288260 }
289261
290−
291− glPopMatrix();
292− glPopMatrix();
262+ xColor majorColorX = getMajorTickMarksColor();
263+ glm::vec4 majorColor(majorColorX.red / MAX_COLOR, majorColorX.green / MAX_COLOR, majorColorX.blue / MAX_COLOR, alpha);
264+
265+ geometryCache->updateVertices(_majorTicksVerticesID, majorPoints, majorColor);
266+
267+ xColor minorColorX = getMinorTickMarksColor();
268+ glm::vec4 minorColor(minorColorX.red / MAX_COLOR, minorColorX.green / MAX_COLOR, minorColorX.blue / MAX_COLOR, alpha);
269+
270+ geometryCache->updateVertices(_minorTicksVerticesID, minorPoints, minorColor);
271+ }
272+
273+ geometryCache->renderVertices(batch, gpu::LINES, _majorTicksVerticesID);
274+
275+ geometryCache->renderVertices(batch, gpu::LINES, _minorTicksVerticesID);
276+ }
293277
294278 if (geometryChanged) {
295279 _lastStartAt = startAt;
@@ -297,15 +281,11 @@ void Circle3DOverlay::render(RenderArgs* args) { · 1 unmodified line
297281 _lastInnerRadius = innerRadius;
298282 _lastOuterRadius = outerRadius;
299283 }
300−
301− if (glower) {
302− delete glower;
303− }
304284 }
305285
306286 void Circle3DOverlay::setProperties(const QScriptValue &properties) {
307287 Planar3DOverlay::setProperties(properties);
308−
288+
309289 QScriptValue startAt = properties.property("startAt");
310290 if (startAt.isValid()) {
311291 setStartAt(startAt.toVariant().toFloat());
@@ -415,7 +395,7 @@ QScriptValue Circle3DOverlay::getProperty(const QString& property) { · 103 unmodified lines
415395 }
416396
417397
418−bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin,
398+bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin,
419399 const glm::vec3& direction, float& distance, BoxFace& face) {
420400
421401 bool intersects = Planar3DOverlay::findRayIntersection(origin, direction, distance, face);
interface/src/ui/overlays/Line3DOverlay.cpp+10−0
@@ -32,6 +32,16 @@ Line3DOverlay::Line3DOverlay(const Line3DOverlay* line3DOverlay) : · 31 unmodified lines
3232 Line3DOverlay::~Line3DOverlay() {
3333 }
3434
35+AABox Line3DOverlay::getBounds() const {
36+ auto start = _position + _start;
37+ auto end = _position + _end;
38+
39+ auto min = glm::min(start, end);
40+ auto max = glm::max(start, end);
41+
42+ return AABox(min, max - min);
43+}
44+
3545 void Line3DOverlay::render(RenderArgs* args) {
3646 if (!_visible) {
3747 return; // do nothing if we're not visible
interface/src/ui/overlays/Line3DOverlay.h+1−0
@@ -21,6 +21,7 @@ public: · 20 unmodified lines
2121 Line3DOverlay(const Line3DOverlay* line3DOverlay);
2222 ~Line3DOverlay();
2323 virtual void render(RenderArgs* args);
24+ virtual AABox getBounds() const override;
2425
2526 // getters
2627 const glm::vec3& getStart() const { return _start; }
interface/src/ui/overlays/Overlays.cpp+1−1
@@ -258,7 +258,7 @@ void Overlays::deleteOverlay(unsigned int id) { · 257 unmodified lines
258258 unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
259259 glm::vec2 pointCopy = point;
260260 if (qApp->isHMDMode()) {
261− pointCopy = qApp->getApplicationOverlay().screenToOverlay(point);
261+ pointCopy = qApp->getApplicationCompositor().screenToOverlay(point);
262262 }
263263
264264 QReadLocker lock(&_lock);
interface/src/ui/overlays/TextOverlay.cpp+1−0
@@ -80,6 +80,7 @@ void TextOverlay::render(RenderArgs* args) { · 79 unmodified lines
8080
8181 glm::vec2 topLeft(left, top);
8282 glm::vec2 bottomRight(right, bottom);
83+ glBindTexture(GL_TEXTURE_2D, 0);
8384 DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, quadColor);
8485
8586 const int leftAdjust = -1; // required to make text render relative to left edge of bounds
libraries/audio-client/src/AudioClient.cpp+24−1
@@ -33,11 +33,20 @@ · 32 unmodified lines
3333 #include <QtMultimedia/QAudioInput>
3434 #include <QtMultimedia/QAudioOutput>
3535
36+#ifdef __GNUC__
37+#pragma GCC diagnostic push
38+#pragma GCC diagnostic ignored "-Wdouble-promotion"
39+#endif
40+
3641 extern "C" {
3742 #include <gverb/gverb.h>
3843 #include <gverb/gverbdsp.h>
3944 }
4045
46+#ifdef __GNUC__
47+#pragma GCC diagnostic pop
48+#endif
49+
4150 #include <soxr.h>
4251
4352 #include <NodeList.h>
@@ -786,6 +795,11 @@ void AudioClient::handleAudioInput() { · 742 unmodified lines
786795
787796 delete[] inputAudioSamples;
788797
798+ // Remove DC offset
799+ if (!_isStereoInput && !_audioSourceInjectEnabled) {
800+ _inputGate.removeDCOffset(networkAudioSamples, numNetworkSamples);
801+ }
802+
789803 // only impose the noise gate and perform tone injection if we are sending mono audio
790804 if (!_isStereoInput && !_audioSourceInjectEnabled && _isNoiseGateEnabled) {
791805 _inputGate.gateSamples(networkAudioSamples, numNetworkSamples);
@@ -1011,7 +1025,10 @@ bool AudioClient::outputLocalInjector(bool isStereo, AudioInjector* injector) { · 219 unmodified lines
10111025 localOutput->moveToThread(injector->getLocalBuffer()->thread());
10121026
10131027 // have it be stopped when that local buffer is about to close
1014− connect(injector->getLocalBuffer(), &AudioInjectorLocalBuffer::bufferEmpty, localOutput, &QAudioOutput::stop);
1028+ connect(localOutput, &QAudioOutput::stateChanged, this, &AudioClient::audioStateChanged);
1029+ connect(this, &AudioClient::audioFinished, localOutput, &QAudioOutput::stop);
1030+ connect(this, &AudioClient::audioFinished, injector, &AudioInjector::stop);
1031+
10151032 connect(injector->getLocalBuffer(), &QIODevice::aboutToClose, localOutput, &QAudioOutput::stop);
10161033
10171034 qCDebug(audioclient) << "Starting QAudioOutput for local injector" << localOutput;
@@ -1329,3 +1346,9 @@ void AudioClient::saveSettings() { · 311 unmodified lines
13291346 windowSecondsForDesiredReduction.set(_receivedAudioStream.getWindowSecondsForDesiredReduction());
13301347 repetitionWithFade.set(_receivedAudioStream.getRepetitionWithFade());
13311348 }
1349+
1350+void AudioClient::audioStateChanged(QAudio::State state) {
1351+ if (state == QAudio::IdleState) {
1352+ emit audioFinished();
1353+ }
1354+}
libraries/audio-client/src/AudioClient.h+6−1
@@ -167,7 +167,7 @@ public slots: · 166 unmodified lines
167167 QString getDefaultDeviceName(QAudio::Mode mode);
168168 QVector<QString> getDeviceNames(QAudio::Mode mode);
169169
170− float getInputVolume() const { return (_audioInput) ? _audioInput->volume() : 0.0f; }
170+ float getInputVolume() const { return (_audioInput) ? (float)_audioInput->volume() : 0.0f; }
171171 void setInputVolume(float volume) { if (_audioInput) _audioInput->setVolume(volume); }
172172 void setReverb(bool reverb);
173173 void setReverbOptions(const AudioEffectOptions* options);
@@ -188,6 +188,8 @@ signals: · 14 unmodified lines
188188 void receivedFirstPacket();
189189 void disconnected();
190190
191+ void audioFinished();
192+
191193 protected:
192194 AudioClient();
193195 ~AudioClient();
@@ -196,6 +198,9 @@ protected: · 2 unmodified lines
196198 deleteLater();
197199 }
198200
201+private slots:
202+ void audioStateChanged(QAudio::State state);
203+
199204 private:
200205 void outputFormatChanged();
201206
libraries/audio-client/src/AudioNoiseGate.cpp+28−15
@@ -33,6 +33,32 @@ AudioNoiseGate::AudioNoiseGate() : · 32 unmodified lines
3333
3434 }
3535
36+void AudioNoiseGate::removeDCOffset(int16_t* samples, int numSamples) {
37+ //
38+ // DC Offset correction
39+ //
40+ // Measure the DC offset over a trailing number of frames, and remove it from the input signal.
41+ // This causes the noise background measurements and server muting to be more accurate. Many off-board
42+ // ADC's have a noticeable DC offset.
43+ //
44+ const float DC_OFFSET_AVERAGING = 0.99f;
45+ float measuredDcOffset = 0.0f;
46+ // Remove trailing DC offset from samples
47+ for (int i = 0; i < numSamples; i++) {
48+ measuredDcOffset += samples[i];
49+ samples[i] -= (int16_t) _dcOffset;
50+ }
51+ // Update measured DC offset
52+ measuredDcOffset /= numSamples;
53+ if (_dcOffset == 0.0f) {
54+ // On first frame, copy over measured offset
55+ _dcOffset = measuredDcOffset;
56+ } else {
57+ _dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset;
58+ }
59+}
60+
61+
3662 void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
3763 //
3864 // Impose Noise Gate
@@ -61,17 +87,12 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { · 22 unmodified lines
6187 const int NOISE_GATE_WIDTH = 5;
6288 const int NOISE_GATE_CLOSE_FRAME_DELAY = 5;
6389 const int NOISE_GATE_FRAMES_TO_AVERAGE = 5;
64− const float DC_OFFSET_AVERAGING = 0.99f;
65−
66− // Check clipping, adjust DC offset, and check if should open noise gate
67− float measuredDcOffset = 0.0f;
90+
91+ // Check clipping, and check if should open noise gate
6892 _didClipInLastFrame = false;
6993
7094 for (int i = 0; i < numSamples; i++) {
71− measuredDcOffset += samples[i];
72− samples[i] -= (int16_t) _dcOffset;
7395 thisSample = std::abs(samples[i]);
74−
7596 if (thisSample >= ((float) AudioConstants::MAX_SAMPLE_VALUE * CLIPPING_THRESHOLD)) {
7697 _didClipInLastFrame = true;
7798 }
@@ -83,14 +104,6 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { · 5 unmodified lines
83104 }
84105 }
85106
86− measuredDcOffset /= numSamples;
87− if (_dcOffset == 0.0f) {
88− // On first frame, copy over measured offset
89− _dcOffset = measuredDcOffset;
90− } else {
91− _dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset;
92− }
93−
94107 _lastLoudness = fabs(loudness / numSamples);
95108
96109 if (_quietestFrame > _lastLoudness) {
libraries/audio-client/src/AudioNoiseGate.h+1−0
@@ -21,6 +21,7 @@ public: · 20 unmodified lines
2121 AudioNoiseGate();
2222
2323 void gateSamples(int16_t* samples, int numSamples);
24+ void removeDCOffset(int16_t* samples, int numSamples);
2425
2526 bool clippedInLastFrame() const { return _didClipInLastFrame; }
2627 float getMeasuredFloor() const { return _measuredFloor; }
libraries/audio/CMakeLists.txt+7−1
@@ -7,4 +7,10 @@ add_dependency_external_projects(glm) · 6 unmodified lines
77 find_package(GLM REQUIRED)
88 target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
99
10−link_hifi_libraries(networking shared)
10+# we use libsoxr for resampling
11+add_dependency_external_projects(soxr)
12+find_package(Soxr REQUIRED)
13+target_link_libraries(${TARGET_NAME} ${SOXR_LIBRARIES})
14+target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SOXR_INCLUDE_DIRS})
15+
16+link_hifi_libraries(networking shared)
libraries/audio/src/AudioInjector.cpp+65−4
@@ -16,10 +16,12 @@ · 15 unmodified lines
1616 #include <PacketHeaders.h>
1717 #include <SharedUtil.h>
1818 #include <UUID.h>
19+#include <soxr.h>
1920
2021 #include "AbstractAudioInterface.h"
2122 #include "AudioRingBuffer.h"
2223 #include "AudioLogging.h"
24+#include "SoundCache.h"
2325
2426 #include "AudioInjector.h"
2527
@@ -60,7 +62,6 @@ void AudioInjector::setIsFinished(bool isFinished) { · 34 unmodified lines
6062
6163 if (_shouldDeleteAfterFinish) {
6264 // we've been asked to delete after finishing, trigger a queued deleteLater here
63− qCDebug(audio) << "AudioInjector triggering delete from setIsFinished";
6465 QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
6566 }
6667 }
@@ -122,9 +123,6 @@ void AudioInjector::injectLocally() { · 55 unmodified lines
122123
123124 success = _localAudioInterface->outputLocalInjector(_options.stereo, this);
124125
125− // if we're not looping and the buffer tells us it is empty then emit finished
126− connect(_localBuffer, &AudioInjectorLocalBuffer::bufferEmpty, this, &AudioInjector::stop);
127−
128126 if (!success) {
129127 qCDebug(audio) << "AudioInjector::injectLocally could not output locally via _localAudioInterface";
130128 }
@@ -288,3 +286,66 @@ void AudioInjector::stopAndDeleteLater() { · 157 unmodified lines
288286 stop();
289287 QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
290288 }
289+
290+AudioInjector* AudioInjector::playSound(const QString& soundUrl, const float volume, const float stretchFactor, const glm::vec3 position) {
291+ if (soundUrl.isEmpty()) {
292+ return NULL;
293+ }
294+ auto soundCache = DependencyManager::get<SoundCache>();
295+ if (soundCache.isNull()) {
296+ return NULL;
297+ }
298+ SharedSoundPointer sound = soundCache.data()->getSound(QUrl(soundUrl));
299+ if (sound.isNull() || !sound->isReady()) {
300+ return NULL;
301+ }
302+
303+ AudioInjectorOptions options;
304+ options.stereo = sound->isStereo();
305+ options.position = position;
306+ options.volume = volume;
307+
308+ QByteArray samples = sound->getByteArray();
309+ if (stretchFactor == 1.0f) {
310+ return playSound(samples, options, NULL);
311+ }
312+
313+ soxr_io_spec_t spec = soxr_io_spec(SOXR_INT16_I, SOXR_INT16_I);
314+ soxr_quality_spec_t qualitySpec = soxr_quality_spec(SOXR_MQ, 0);
315+ const int channelCount = sound->isStereo() ? 2 : 1;
316+ const int standardRate = AudioConstants::SAMPLE_RATE;
317+ const int resampledRate = standardRate * stretchFactor;
318+ const int nInputSamples = samples.size() / sizeof(int16_t);
319+ const int nOutputSamples = nInputSamples * stretchFactor;
320+ QByteArray resampled(nOutputSamples * sizeof(int16_t), '\0');
321+ const int16_t* receivedSamples = reinterpret_cast<const int16_t*>(samples.data());
322+ soxr_error_t soxError = soxr_oneshot(standardRate, resampledRate, channelCount,
323+ receivedSamples, nInputSamples, NULL,
324+ reinterpret_cast<int16_t*>(resampled.data()), nOutputSamples, NULL,
325+ &spec, &qualitySpec, 0);
326+ if (soxError) {
327+ qCDebug(audio) << "Unable to resample" << soundUrl << "from" << nInputSamples << "@" << standardRate << "to" << nOutputSamples << "@" << resampledRate;
328+ resampled = samples;
329+ }
330+ return playSound(resampled, options, NULL);
331+}
332+
333+AudioInjector* AudioInjector::playSound(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface) {
334+ QThread* injectorThread = new QThread();
335+ injectorThread->setObjectName("Audio Injector Thread");
336+
337+ AudioInjector* injector = new AudioInjector(buffer, options);
338+ injector->setLocalAudioInterface(localInterface);
339+
340+ injector->moveToThread(injectorThread);
341+
342+ // start injecting when the injector thread starts
343+ connect(injectorThread, &QThread::started, injector, &AudioInjector::injectAudio);
344+
345+ // connect the right slots and signals for AudioInjector and thread cleanup
346+ connect(injector, &AudioInjector::destroyed, injectorThread, &QThread::quit);
347+ connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater);
348+
349+ injectorThread->start();
350+ return injector;
351+}
libraries/audio/src/AudioInjector.h+4−0
@@ -45,6 +45,10 @@ public: · 44 unmodified lines
4545 bool isLocalOnly() const { return _options.localOnly; }
4646
4747 void setLocalAudioInterface(AbstractAudioInterface* localAudioInterface) { _localAudioInterface = localAudioInterface; }
48+
49+ static AudioInjector* playSound(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface);
50+ static AudioInjector* playSound(const QString& soundUrl, const float volume, const float stretchFactor, const glm::vec3 position);
51+
4852 public slots:
4953 void injectAudio();
5054 void restart();
libraries/audio/src/AudioInjectorLocalBuffer.cpp+1−4
@@ -69,10 +69,7 @@ qint64 AudioInjectorLocalBuffer::readData(char* data, qint64 maxSize) { · 68 unmodified lines
6969 _currentOffset += bytesRead;
7070 }
7171
72− if (!_shouldLoop && bytesRead == bytesToEnd) {
73− // we hit the end of the buffer, emit a signal
74− emit bufferEmpty();
75− } else if (_shouldLoop && _currentOffset == _rawAudioArray.size()) {
72+ if (_shouldLoop && _currentOffset == _rawAudioArray.size()) {
7673 _currentOffset = 0;
7774 }
7875
libraries/audio/src/AudioInjectorLocalBuffer.h+0−3
@@ -32,9 +32,6 @@ public: · 31 unmodified lines
3232 void setCurrentOffset(int currentOffset) { _currentOffset = currentOffset; }
3333 void setVolume(float volume) { _volume = glm::clamp(volume, 0.0f, 1.0f); }
3434
35−signals:
36− void bufferEmpty();
37−
3835 private:
3936 qint64 recursiveReadFromFront(char* data, qint64 maxSize);
4037
libraries/audio/src/AudioRingBuffer.cpp+1−1
@@ -211,7 +211,7 @@ float AudioRingBuffer::getFrameLoudness(const int16_t* frameStart) const { · 210 unmodified lines
211211 const int16_t* _bufferLastAt = _buffer + _bufferLength - 1;
212212
213213 for (int i = 0; i < _numFrameSamples; ++i) {
214− loudness += std::abs(*sampleAt);
214+ loudness += (float) std::abs(*sampleAt);
215215 sampleAt = sampleAt == _bufferLastAt ? _buffer : sampleAt + 1;
216216 }
217217 loudness /= _numFrameSamples;
libraries/avatars/src/AvatarData.cpp+2−3
@@ -52,9 +52,8 @@ AvatarData::AvatarData() : · 51 unmodified lines
5252 _headData(NULL),
5353 _handData(NULL),
5454 _faceModelURL("http://invalid.com"),
55− _displayNameBoundingRect(),
56− _displayNameTargetAlpha(0.0f),
57− _displayNameAlpha(0.0f),
55+ _displayNameTargetAlpha(1.0f),
56+ _displayNameAlpha(1.0f),
5857 _billboard(),
5958 _errorLogExpiry(0),
6059 _owningAvatarMixer(),
libraries/avatars/src/AvatarData.h+1−2
@@ -163,7 +163,7 @@ public: · 162 unmodified lines
163163 AvatarData();
164164 virtual ~AvatarData();
165165
166− virtual bool isMyAvatar() { return false; }
166+ virtual bool isMyAvatar() const { return false; }
167167
168168 const QUuid& getSessionUUID() const { return _sessionUUID; }
169169
@@ -378,7 +378,6 @@ protected: · 208 unmodified lines
378378 QVector<AttachmentData> _attachmentData;
379379 QString _displayName;
380380
381− QRect _displayNameBoundingRect;
382381 float _displayNameTargetAlpha;
383382 float _displayNameAlpha;
384383
libraries/entities-renderer/CMakeLists.txt+0−6
@@ -17,10 +17,4 @@ find_package(PolyVox REQUIRED) · 16 unmodified lines
1717 target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${POLYVOX_INCLUDE_DIRS})
1818 target_link_libraries(${TARGET_NAME} ${POLYVOX_LIBRARIES})
1919
20−# for changing the pitch of collision sounds
21−add_dependency_external_projects(soxr)
22−find_package(Soxr REQUIRED)
23−target_link_libraries(${TARGET_NAME} ${SOXR_LIBRARIES})
24−target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SOXR_INCLUDE_DIRS})
25−
2620 link_hifi_libraries(shared gpu script-engine render render-utils)
libraries/entities-renderer/src/EntityTreeRenderer.cpp+6−60
@@ -27,10 +27,6 @@ · 26 unmodified lines
2727 #include <SceneScriptingInterface.h>
2828 #include <ScriptEngine.h>
2929 #include <TextureCache.h>
30−#include <SoundCache.h>
31−#include <soxr.h>
32−#include <AudioConstants.h>
33−
3430
3531 #include "EntityTreeRenderer.h"
3632
@@ -54,7 +50,6 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf · 17 unmodified lines
5450 _wantScripts(wantScripts),
5551 _entitiesScriptEngine(NULL),
5652 _sandboxScriptEngine(NULL),
57− _localAudioInterface(NULL),
5853 _lastMouseEventValid(false),
5954 _viewState(viewState),
6055 _scriptingServices(scriptingServices),
@@ -911,15 +906,13 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI · 850 unmodified lines
911906 bool precisionPicking = false; // for mouse moves we do not do precision picking
912907 RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking);
913908 if (rayPickResult.intersects) {
909+ //qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID;
914910 QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID);
915−
916911 // load the entity script if needed...
917912 QScriptValue entityScript = loadEntityScript(rayPickResult.entity);
918913 if (entityScript.property("mouseMoveEvent").isValid()) {
919914 entityScript.property("mouseMoveEvent").call(entityScript, entityScriptArgs);
920915 }
921−
922− //qCDebug(entitiesrenderer) << "mouseMoveEvent over entity:" << rayPickResult.entityID;
923916 emit mouseMoveOnEntity(rayPickResult, event, deviceID);
924917 if (entityScript.property("mouseMoveOnEntity").isValid()) {
925918 entityScript.property("mouseMoveOnEntity").call(entityScript, entityScriptArgs);
@@ -1056,7 +1049,6 @@ void EntityTreeRenderer::checkAndCallUnload(const EntityItemID& entityID) { · 130 unmodified lines
10561049 }
10571050 }
10581051
1059−
10601052 void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision) {
10611053 EntityItemPointer entity = entityTree->findEntityByEntityItemID(id);
10621054 if (!entity) {
@@ -1099,61 +1091,15 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT · 36 unmodified lines
10991091 if (energyFactorOfFull < COLLISION_MINIMUM_VOLUME) {
11001092 return;
11011093 }
1102−
1103− auto soundCache = DependencyManager::get<SoundCache>();
1104− if (soundCache.isNull()) {
1105− return;
1106− }
1107− SharedSoundPointer sound = soundCache.data()->getSound(QUrl(collisionSoundURL));
1108− if (sound.isNull() || !sound->isReady()) {
1109− return;
1110− }
1111−
1112− // This is a hack. Quiet sound aren't really heard at all, so we compress everything to the range [1-c, 1], if we play it all.
1094+ // Quiet sound aren't really heard at all, so we can compress everything to the range [1-c, 1], if we play it all.
11131095 const float COLLISION_SOUND_COMPRESSION_RANGE = 1.0f; // This section could be removed when the value is 1, but let's see how it goes.
1114− float volume = energyFactorOfFull;
1115− volume = (volume * COLLISION_SOUND_COMPRESSION_RANGE) + (1.0f - COLLISION_SOUND_COMPRESSION_RANGE);
1116−
1117− // This is quite similar to AudioScriptingInterface::playSound() and should probably be refactored.
1118− AudioInjectorOptions options;
1119− options.stereo = sound->isStereo();
1120− options.position = position;
1121− options.volume = volume;
1096+ const float volume = (energyFactorOfFull * COLLISION_SOUND_COMPRESSION_RANGE) + (1.0f - COLLISION_SOUND_COMPRESSION_RANGE);
1097+
11221098
11231099 // Shift the pitch down by ln(1 + (size / COLLISION_SIZE_FOR_STANDARD_PITCH)) / ln(2)
11241100 const float COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f;
1125− QByteArray samples = sound->getByteArray();
1126− soxr_io_spec_t spec = soxr_io_spec(SOXR_INT16_I, SOXR_INT16_I);
1127− soxr_quality_spec_t qualitySpec = soxr_quality_spec(SOXR_MQ, 0);
1128− const int channelCount = sound->isStereo() ? 2 : 1;
1129− const float factor = log(1.0f + (entity->getMinimumAACube().getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2);
1130− const int standardRate = AudioConstants::SAMPLE_RATE;
1131− const int resampledRate = standardRate * factor;
1132− const int nInputSamples = samples.size() / sizeof(int16_t);
1133− const int nOutputSamples = nInputSamples * factor;
1134− QByteArray resampled(nOutputSamples * sizeof(int16_t), '\0');
1135− const int16_t* receivedSamples = reinterpret_cast<const int16_t*>(samples.data());
1136− soxr_error_t soxError = soxr_oneshot(standardRate, resampledRate, channelCount,
1137− receivedSamples, nInputSamples, NULL,
1138− reinterpret_cast<int16_t*>(resampled.data()), nOutputSamples, NULL,
1139− &spec, &qualitySpec, 0);
1140− if (soxError) {
1141− qCDebug(entitiesrenderer) << "Unable to resample" << collisionSoundURL << "from" << nInputSamples << "@" << standardRate << "to" << nOutputSamples << "@" << resampledRate;
1142− resampled = samples;
1143− }
1144−
1145− AudioInjector* injector = new AudioInjector(resampled, options);
1146− injector->setLocalAudioInterface(_localAudioInterface);
1147− injector->triggerDeleteAfterFinish();
1148− QThread* injectorThread = new QThread();
1149− injectorThread->setObjectName("Audio Injector Thread");
1150− injector->moveToThread(injectorThread);
1151− // start injecting when the injector thread starts
1152− connect(injectorThread, &QThread::started, injector, &AudioInjector::injectAudio);
1153− // connect the right slots and signals for AudioInjector and thread cleanup
1154− connect(injector, &AudioInjector::destroyed, injectorThread, &QThread::quit);
1155− connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater);
1156− injectorThread->start();
1101+ const float stretchFactor = log(1.0f + (entity->getMinimumAACube().getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2);
1102+ AudioInjector::playSound(collisionSoundURL, volume, stretchFactor, position);
11571103 }
11581104
11591105 void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB,
libraries/entities-renderer/src/EntityTreeRenderer.h+0−1
@@ -158,7 +158,6 @@ private: · 157 unmodified lines
158158 QHash<EntityItemID, EntityScriptDetails> _entityScripts;
159159
160160 void playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision);
161− AbstractAudioInterface* _localAudioInterface; // So we can render collision sounds
162161
163162 bool _lastMouseEventValid;
164163 MouseEvent _lastMouseEvent;
libraries/entities-renderer/src/RenderableLineEntityItem.cpp+3−3
@@ -43,9 +43,9 @@ void RenderableLineEntityItem::render(RenderArgs* args) { · 42 unmodified lines
4343
4444 Q_ASSERT(args->_batch);
4545 gpu::Batch& batch = *args->_batch;
46− // TODO: Figure out clean , efficient way to do relative line positioning. For now we'll just use absolute positioning.
47− //batch.setModelTransform(getTransformToCenter());
48− batch.setModelTransform(Transform());
46+ Transform transform = Transform();
47+ transform.setTranslation(getPosition());
48+ batch.setModelTransform(transform);
4949
5050 batch._glLineWidth(getLineWidth());
5151 if (getLinePoints().size() > 1) {
libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp+11−7
@@ -11,10 +11,18 @@ · 10 unmodified lines
1111
1212 #include <QByteArray>
1313
14+#ifdef __GNUC__
15+#pragma GCC diagnostic push
16+#pragma GCC diagnostic ignored "-Wdouble-promotion"
17+#endif
1418
1519 #include <glm/gtx/quaternion.hpp>
1620 #include <glm/gtx/string_cast.hpp>
1721
22+#ifdef __GNUC__
23+#pragma GCC diagnostic pop
24+#endif
25+
1826 #include <gpu/GPUConfig.h>
1927
2028 #include <DeferredLightingEffect.h>
@@ -141,11 +149,7 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) · 120 unmodified lines
141149 decompressVolumeData();
142150 }
143151
144−void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) {
145− if (voxelSurfaceStyle == _voxelSurfaceStyle) {
146− return;
147− }
148−
152+void RenderablePolyVoxEntityItem::updateVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) {
149153 // if we are switching to or from "edged" we need to force a resize of _volData.
150154 if (voxelSurfaceStyle == SURFACE_EDGED_CUBIC ||
151155 _voxelSurfaceStyle == SURFACE_EDGED_CUBIC) {
@@ -153,10 +157,10 @@ void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxel · 1 unmodified line
153157 delete _volData;
154158 }
155159 _volData = nullptr;
156− PolyVoxEntityItem::setVoxelSurfaceStyle(voxelSurfaceStyle);
160+ _voxelSurfaceStyle = voxelSurfaceStyle;
157161 setVoxelVolumeSize(_voxelVolumeSize);
158162 } else {
159− PolyVoxEntityItem::setVoxelSurfaceStyle(voxelSurfaceStyle);
163+ _voxelSurfaceStyle = voxelSurfaceStyle;
160164 }
161165 _needsModelReload = true;
162166 }
libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h+6−4
@@ -36,17 +36,15 @@ public: · 35 unmodified lines
3636
3737 virtual uint8_t getVoxel(int x, int y, int z);
3838 virtual void setVoxel(int x, int y, int z, uint8_t toValue);
39−
39+
4040 void updateOnCount(int x, int y, int z, uint8_t new_value);
4141
4242 void render(RenderArgs* args);
4343 virtual bool supportsDetailedRayIntersection() const { return true; }
4444 virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
45− bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
45+ bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
4646 void** intersectedObject, bool precisionPicking) const;
4747
48− virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle);
49−
5048 void getModel();
5149
5250 virtual void setVoxelData(QByteArray voxelData);
@@ -74,6 +72,9 @@ public: · 21 unmodified lines
7472
7573 SIMPLE_RENDERABLE();
7674
75+protected:
76+ virtual void updateVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle);
77+
7778 private:
7879 // The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions
7980 // may not match _voxelVolumeSize.
@@ -82,6 +83,7 @@ private: · 2 unmodified lines
8283 void compressVolumeData();
8384 void decompressVolumeData();
8485
86+
8587 PolyVox::SimpleVolume<uint8_t>* _volData = nullptr;
8688 model::Geometry _modelGeometry;
8789 bool _needsModelReload = true;
libraries/entities/src/DeleteEntityOperator.cpp+1−0
@@ -95,6 +95,7 @@ bool DeleteEntityOperator::preRecursion(OctreeElement* element) { · 94 unmodified lines
9595 EntityItemPointer theEntity = details.entity;
9696 bool entityDeleted = entityTreeElement->removeEntityItem(theEntity); // remove it from the element
9797 assert(entityDeleted);
98+ (void)entityDeleted; // quite warning
9899 _tree->setContainingElement(details.entity->getEntityItemID(), NULL); // update or id to element lookup
99100 _foundCount++;
100101 }
libraries/entities/src/EntityActionInterface.cpp+4−4
@@ -19,8 +19,8 @@ EntityActionType EntityActionInterface::actionTypeFromString(QString actionTypeS · 18 unmodified lines
1919 if (normalizedActionTypeString == "none") {
2020 return ACTION_TYPE_NONE;
2121 }
22− if (normalizedActionTypeString == "pulltopoint") {
23− return ACTION_TYPE_PULL_TO_POINT;
22+ if (normalizedActionTypeString == "offset") {
23+ return ACTION_TYPE_OFFSET;
2424 }
2525 if (normalizedActionTypeString == "spring") {
2626 return ACTION_TYPE_SPRING;
@@ -37,8 +37,8 @@ QString EntityActionInterface::actionTypeToString(EntityActionType actionType) { · 10 unmodified lines
3737 switch(actionType) {
3838 case ACTION_TYPE_NONE:
3939 return "none";
40− case ACTION_TYPE_PULL_TO_POINT:
41− return "pullToPoint";
40+ case ACTION_TYPE_OFFSET:
41+ return "offset";
4242 case ACTION_TYPE_SPRING:
4343 return "spring";
4444 case ACTION_TYPE_HOLD:
libraries/entities/src/EntityActionInterface.h+1−1
@@ -21,7 +21,7 @@ class EntitySimulation; · 20 unmodified lines
2121 enum EntityActionType {
2222 // keep these synchronized with actionTypeFromString and actionTypeToString
2323 ACTION_TYPE_NONE,
24− ACTION_TYPE_PULL_TO_POINT,
24+ ACTION_TYPE_OFFSET,
2525 ACTION_TYPE_SPRING,
2626 ACTION_TYPE_HOLD
2727 };
libraries/entities/src/EntityItem.cpp+2−2
@@ -639,8 +639,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef · 638 unmodified lines
639639 void EntityItem::debugDump() const {
640640 auto position = getPosition();
641641 qCDebug(entities) << "EntityItem id:" << getEntityItemID();
642− qCDebug(entities, " edited ago:%f", getEditedAgo());
643− qCDebug(entities, " position:%f,%f,%f", position.x, position.y, position.z);
642+ qCDebug(entities, " edited ago:%f", (double)getEditedAgo());
643+ qCDebug(entities, " position:%f,%f,%f", (double)position.x, (double)position.y, (double)position.z);
644644 qCDebug(entities) << " dimensions:" << getDimensions();
645645 }
646646
libraries/entities/src/EntityItemID.h+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
1414
1515 #include <stdint.h>
1616
17−
17+#include <QDebug>
1818 #include <QObject>
1919 #include <QHash>
2020 #include <QScriptEngine>
libraries/entities/src/EntityItemProperties.h+2−0
@@ -197,6 +197,8 @@ public: · 196 unmodified lines
197197 QString getSimulatorIDAsString() const { return _simulatorID.toString().mid(1,36).toUpper(); }
198198
199199 void setVoxelDataDirty() { _voxelDataChanged = true; }
200+
201+ void setLinePointsDirty() {_linePointsChanged = true; }
200202
201203 void setCreated(QDateTime& v);
202204
libraries/entities/src/EntityScriptingInterface.cpp+52−0
@@ -442,6 +442,43 @@ bool EntityScriptingInterface::setVoxels(QUuid entityID, · 441 unmodified lines
442442 return true;
443443 }
444444
445+bool EntityScriptingInterface::setPoints(QUuid entityID, std::function<bool(LineEntityItem&)> actor) {
446+ if (!_entityTree) {
447+ return false;
448+ }
449+
450+ EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID));
451+ if (!entity) {
452+ qCDebug(entities) << "EntityScriptingInterface::setPoints no entity with ID" << entityID;
453+ }
454+
455+ EntityTypes::EntityType entityType = entity->getType();
456+
457+ if (entityType != EntityTypes::Line) {
458+ return false;
459+ }
460+
461+ auto now = usecTimestampNow();
462+
463+ LineEntityItem* lineEntity = static_cast<LineEntityItem*>(entity.get());
464+ _entityTree->lockForWrite();
465+ bool success = actor(*lineEntity);
466+ entity->setLastEdited(now);
467+ entity->setLastBroadcast(now);
468+ _entityTree->unlock();
469+
470+ _entityTree->lockForRead();
471+ EntityItemProperties properties = entity->getProperties();
472+ _entityTree->unlock();
473+
474+ properties.setLinePointsDirty();
475+ properties.setLastEdited(now);
476+
477+
478+ queueEntityMessage(PacketTypeEntityEdit, entityID, properties);
479+ return success;
480+}
481+
445482 bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) {
446483 return setVoxels(entityID, [center, radius, value](PolyVoxEntityItem& polyVoxEntity) {
447484 polyVoxEntity.setSphere(center, radius, value);
@@ -460,6 +497,21 @@ bool EntityScriptingInterface::setAllVoxels(QUuid entityID, int value) { · 12 unmodified lines
460497 });
461498 }
462499
500+bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector<glm::vec3>& points) {
501+ return setPoints(entityID, [points](LineEntityItem& lineEntity) -> bool
502+ {
503+ return lineEntity.setLinePoints(points);
504+ });
505+}
506+
507+bool EntityScriptingInterface::appendPoint(QUuid entityID, const glm::vec3& point) {
508+ return setPoints(entityID, [point](LineEntityItem& lineEntity) -> bool
509+ {
510+ return lineEntity.appendPoint(point);
511+ });
512+
513+}
514+
463515
464516 bool EntityScriptingInterface::actionWorker(const QUuid& entityID,
465517 std::function<bool(EntitySimulation*, EntityItemPointer)> actor) {
libraries/entities/src/EntityScriptingInterface.h+5−0
@@ -22,6 +22,7 @@ · 21 unmodified lines
2222 #include <OctreeScriptingInterface.h>
2323 #include <RegisteredMetaTypes.h>
2424 #include "PolyVoxEntityItem.h"
25+#include "LineEntityItem.h"
2526
2627 #include "EntityEditPacketSender.h"
2728
@@ -121,6 +122,9 @@ public slots: · 93 unmodified lines
121122 Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value);
122123 Q_INVOKABLE bool setVoxel(QUuid entityID, const glm::vec3& position, int value);
123124 Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value);
125+
126+ Q_INVOKABLE bool setAllPoints(QUuid entityID, const QVector<glm::vec3>& points);
127+ Q_INVOKABLE bool appendPoint(QUuid entityID, const glm::vec3& point);
124128
125129 Q_INVOKABLE void dumpTree() const;
126130
@@ -157,6 +161,7 @@ signals: · 30 unmodified lines
157161 private:
158162 bool actionWorker(const QUuid& entityID, std::function<bool(EntitySimulation*, EntityItemPointer)> actor);
159163 bool setVoxels(QUuid entityID, std::function<void(PolyVoxEntityItem&)> actor);
164+ bool setPoints(QUuid entityID, std::function<bool(LineEntityItem&)> actor);
160165 void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties);
161166
162167 /// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode
libraries/entities/src/LineEntityItem.cpp+28−13
@@ -23,6 +23,7 @@ · 22 unmodified lines
2323
2424
2525 const float LineEntityItem::DEFAULT_LINE_WIDTH = 2.0f;
26+const int LineEntityItem::MAX_POINTS_PER_LINE = 70;
2627
2728
2829 EntityItemPointer LineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
@@ -85,24 +86,38 @@ bool LineEntityItem::setProperties(const EntityItemProperties& properties) { · 56 unmodified lines
8586 return somethingChanged;
8687 }
8788
88−void LineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {
89− QVector<glm::vec3> sanitizedPoints;
90− int invalidPoints = 0;
89+bool LineEntityItem::appendPoint(const glm::vec3& point) {
90+ if (_points.size() > MAX_POINTS_PER_LINE - 1) {
91+ qDebug() << "MAX POINTS REACHED!";
92+ return false;
93+ }
94+ glm::vec3 halfBox = getDimensions() * 0.5f;
95+ if ( (point.x < - halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < - halfBox.z || point.z > halfBox.z) ) {
96+ qDebug() << "Point is outside entity's bounding box";
97+ return false;
98+ }
99+ _points << point;
100+ _pointsChanged = true;
101+ return true;
102+}
103+
104+bool LineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {
105+ if (points.size() > MAX_POINTS_PER_LINE) {
106+ return false;
107+ }
91108 for (int i = 0; i < points.size(); i++) {
92109 glm::vec3 point = points.at(i);
93− // Make sure all of our points are valid numbers.
94− // Must be greater than 0 because vector component is set to 0 if it is invalid data. Also should never be greater than TREE_SCALE
95− if ( (point.x > 0 && point.x < TREE_SCALE) && (point.y > 0 && point.y < TREE_SCALE) && (point.z > 0 && point.z < TREE_SCALE) ) {
96− sanitizedPoints << point;
97− } else {
98− ++invalidPoints;
110+ glm::vec3 pos = getPosition();
111+ glm::vec3 halfBox = getDimensions() * 0.5f;
112+ if ( (point.x < - halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < - halfBox.z || point.z > halfBox.z) ) {
113+ qDebug() << "Point is outside entity's bounding box";
114+ return false;
99115 }
116+
100117 }
101− if (invalidPoints > 0) {
102− qDebug() << "Line with" << invalidPoints << "INVALID POINTS";
103− }
104− _points = sanitizedPoints;
118+ _points = points;
105119 _pointsChanged = true;
120+ return true;
106121 }
107122
108123 int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
libraries/entities/src/LineEntityItem.h+3−1
@@ -54,7 +54,8 @@ class LineEntityItem : public EntityItem { · 53 unmodified lines
5454 void setLineWidth(float lineWidth){ _lineWidth = lineWidth; }
5555 float getLineWidth() const{ return _lineWidth; }
5656
57− void setLinePoints(const QVector<glm::vec3>& points);
57+ bool setLinePoints(const QVector<glm::vec3>& points);
58+ bool appendPoint(const glm::vec3& point);
5859
5960 const QVector<glm::vec3>& getLinePoints() const{ return _points; }
6061
@@ -68,6 +69,7 @@ class LineEntityItem : public EntityItem { · 7 unmodified lines
6869
6970 virtual void debugDump() const;
7071 static const float DEFAULT_LINE_WIDTH;
72+ static const int MAX_POINTS_PER_LINE;
7173
7274 protected:
7375 rgbColor _color;
libraries/entities/src/PolyVoxEntityItem.cpp+7−0
@@ -168,3 +168,10 @@ void PolyVoxEntityItem::debugDump() const { · 167 unmodified lines
168168 qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions());
169169 qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
170170 }
171+
172+void PolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) {
173+ if (voxelSurfaceStyle == _voxelSurfaceStyle) {
174+ return;
175+ }
176+ updateVoxelSurfaceStyle(voxelSurfaceStyle);
177+}
libraries/entities/src/PolyVoxEntityItem.h+7−4
@@ -61,10 +61,9 @@ class PolyVoxEntityItem : public EntityItem { · 60 unmodified lines
6161 SURFACE_EDGED_CUBIC
6262 };
6363
64− virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { _voxelSurfaceStyle = voxelSurfaceStyle; }
65− virtual void setVoxelSurfaceStyle(uint16_t voxelSurfaceStyle) {
66− setVoxelSurfaceStyle((PolyVoxSurfaceStyle) voxelSurfaceStyle);
67− }
64+ void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle);
65+ // this other version of setVoxelSurfaceStyle is needed for SET_ENTITY_PROPERTY_FROM_PROPERTIES
66+ void setVoxelSurfaceStyle(uint16_t voxelSurfaceStyle) { setVoxelSurfaceStyle((PolyVoxSurfaceStyle) voxelSurfaceStyle); }
6867 virtual PolyVoxSurfaceStyle getVoxelSurfaceStyle() const { return _voxelSurfaceStyle; }
6968
7069 static const glm::vec3 DEFAULT_VOXEL_VOLUME_SIZE;
@@ -89,6 +88,10 @@ class PolyVoxEntityItem : public EntityItem { · 18 unmodified lines
8988 static QByteArray makeEmptyVoxelData(quint16 voxelXSize = 16, quint16 voxelYSize = 16, quint16 voxelZSize = 16);
9089
9190 protected:
91+ virtual void updateVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) {
92+ _voxelSurfaceStyle = voxelSurfaceStyle;
93+ }
94+
9295 glm::vec3 _voxelVolumeSize; // this is always 3 bytes
9396 QByteArray _voxelData;
9497 PolyVoxSurfaceStyle _voxelSurfaceStyle;
libraries/fbx/src/FBXReader.cpp+37−6
@@ -506,7 +506,7 @@ FBXNode parseFBX(QIODevice* device) { · 505 unmodified lines
506506
507507 QVector<glm::vec4> createVec4Vector(const QVector<double>& doubleVector) {
508508 QVector<glm::vec4> values;
509− for (const double* it = doubleVector.constData(), *end = it + (doubleVector.size() / 4 * 4); it != end; ) {
509+ for (const double* it = doubleVector.constData(), *end = it + ((doubleVector.size() / 4) * 4); it != end; ) {
510510 float x = *it++;
511511 float y = *it++;
512512 float z = *it++;
@@ -516,9 +516,27 @@ QVector<glm::vec4> createVec4Vector(const QVector<double>& doubleVector) { · 3 unmodified lines
516516 return values;
517517 }
518518
519+
520+QVector<glm::vec4> createVec4VectorRGBA(const QVector<double>& doubleVector, glm::vec4& average) {
521+ QVector<glm::vec4> values;
522+ for (const double* it = doubleVector.constData(), *end = it + ((doubleVector.size() / 4) * 4); it != end; ) {
523+ float x = *it++;
524+ float y = *it++;
525+ float z = *it++;
526+ float w = *it++;
527+ auto val = glm::vec4(x, y, z, w);
528+ values.append(val);
529+ average += val;
530+ }
531+ if (!values.isEmpty()) {
532+ average *= (1.0f / float(values.size()));
533+ }
534+ return values;
535+}
536+
519537 QVector<glm::vec3> createVec3Vector(const QVector<double>& doubleVector) {
520538 QVector<glm::vec3> values;
521− for (const double* it = doubleVector.constData(), *end = it + (doubleVector.size() / 3 * 3); it != end; ) {
539+ for (const double* it = doubleVector.constData(), *end = it + ((doubleVector.size() / 3) * 3); it != end; ) {
522540 float x = *it++;
523541 float y = *it++;
524542 float z = *it++;
@@ -529,7 +547,7 @@ QVector<glm::vec3> createVec3Vector(const QVector<double>& doubleVector) { · 4 unmodified lines
529547
530548 QVector<glm::vec2> createVec2Vector(const QVector<double>& doubleVector) {
531549 QVector<glm::vec2> values;
532− for (const double* it = doubleVector.constData(), *end = it + (doubleVector.size() / 2 * 2); it != end; ) {
550+ for (const double* it = doubleVector.constData(), *end = it + ((doubleVector.size() / 2) * 2); it != end; ) {
533551 float s = *it++;
534552 float t = *it++;
535553 values.append(glm::vec2(s, -t));
@@ -799,6 +817,7 @@ public: · 263 unmodified lines
799817 QVector<int> normalIndices;
800818
801819 bool colorsByVertex;
820+ glm::vec4 averageColor{1.0f, 1.0f, 1.0f, 1.0f};
802821 QVector<glm::vec4> colors;
803822 QVector<int> colorIndices;
804823
@@ -940,8 +959,7 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) { · 135 unmodified lines
940959 bool indexToDirect = false;
941960 foreach (const FBXNode& subdata, child.children) {
942961 if (subdata.name == "Colors") {
943− data.colors = createVec4Vector(getDoubleVector(subdata));
944−
962+ data.colors = createVec4VectorRGBA(getDoubleVector(subdata), data.averageColor);
945963 } else if (subdata.name == "ColorsIndex") {
946964 data.colorIndices = getIntVector(subdata);
947965
@@ -956,6 +974,19 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) { · 8 unmodified lines
956974 // hack to work around wacky Makehuman exports
957975 data.colorsByVertex = true;
958976 }
977+
978+#if defined(FBXREADER_KILL_BLACK_COLOR_ATTRIBUTE)
979+ // Potential feature where we decide to kill the color attribute is to dark?
980+ // Tested with the model:
981+ // https://hifi-public.s3.amazonaws.com/ryan/gardenLight2.fbx
982+ // let's check if we did have true data ?
983+ if (glm::all(glm::lessThanEqual(data.averageColor, glm::vec4(0.09f)))) {
984+ data.colors.clear();
985+ data.colorIndices.clear();
986+ data.colorsByVertex = false;
987+ qCDebug(modelformat) << "LayerElementColor has an average value of 0.0f... let's forget it.";
988+ }
989+#endif
959990
960991 } else if (child.name == "LayerElementUV") {
961992 if (child.properties.at(0).toInt() == 0) {
@@ -1251,7 +1282,7 @@ FBXLight extractLight(const FBXNode& object) { · 289 unmodified lines
12511282 if (property.name == "P") {
12521283 QString propname = property.properties.at(0).toString();
12531284 if (propname == "Intensity") {
1254− light.intensity = 0.01f * property.properties.at(valIndex).value<double>();
1285+ light.intensity = 0.01f * property.properties.at(valIndex).value<float>();
12551286 } else if (propname == "Color") {
12561287 light.color = getVec3(property.properties, valIndex);
12571288 }
libraries/gpu/src/gpu/Batch.h+3−1
@@ -70,7 +70,7 @@ public: · 69 unmodified lines
7070 typedef Stream::Slot Slot;
7171
7272 Batch();
73− Batch(const Batch& batch);
73+ explicit Batch(const Batch& batch);
7474 ~Batch();
7575
7676 void clear();
@@ -148,6 +148,7 @@ public: · 71 unmodified lines
148148 void _glDrawBuffers(GLsizei n, const GLenum* bufs);
149149
150150 void _glUseProgram(GLuint program);
151+ void _glUniform1i(GLint location, GLint v0);
151152 void _glUniform1f(GLint location, GLfloat v0);
152153 void _glUniform2f(GLint location, GLfloat v0, GLfloat v1);
153154 void _glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
@@ -210,6 +211,7 @@ public: · 56 unmodified lines
210211 COMMAND_glDrawBuffers,
211212
212213 COMMAND_glUseProgram,
214+ COMMAND_glUniform1i,
213215 COMMAND_glUniform1f,
214216 COMMAND_glUniform2f,
215217 COMMAND_glUniform3f,
libraries/gpu/src/gpu/GLBackend.cpp+57−0
@@ -12,6 +12,8 @@ · 11 unmodified lines
1212 #include "GLBackendShared.h"
1313 #include <glm/gtc/type_ptr.hpp>
1414
15+using namespace gpu;
16+
1517 GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
1618 {
1719 (&::gpu::GLBackend::do_draw),
@@ -59,6 +61,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = · 41 unmodified lines
5961 (&::gpu::GLBackend::do_glDrawBuffers),
6062
6163 (&::gpu::GLBackend::do_glUseProgram),
64+ (&::gpu::GLBackend::do_glUniform1i),
6265 (&::gpu::GLBackend::do_glUniform1f),
6366 (&::gpu::GLBackend::do_glUniform2f),
6467 (&::gpu::GLBackend::do_glUniform3f),
@@ -141,6 +144,14 @@ bool GLBackend::checkGLError(const char* name) { · 76 unmodified lines
141144 }
142145 }
143146
147+bool GLBackend::checkGLErrorDebug(const char* name) {
148+#ifdef DEBUG
149+ return checkGLError(name);
150+#else
151+ Q_UNUSED(name);
152+ return false;
153+#endif
154+}
144155
145156 void GLBackend::syncCache() {
146157 syncTransformStateCache();
@@ -433,6 +444,29 @@ void GLBackend::do_glUseProgram(Batch& batch, uint32 paramOffset) { · 286 unmodified lines
433444 (void) CHECK_GL_ERROR();
434445 }
435446
447+void Batch::_glUniform1i(GLint location, GLint v0) {
448+ if (location < 0) {
449+ return;
450+ }
451+ ADD_COMMAND_GL(glUniform1i);
452+ _params.push_back(v0);
453+ _params.push_back(location);
454+
455+ DO_IT_NOW(_glUniform1i, 1);
456+}
457+void GLBackend::do_glUniform1i(Batch& batch, uint32 paramOffset) {
458+ if (_pipeline._program == 0) {
459+ // We should call updatePipeline() to bind the program but we are not doing that
460+ // because these uniform setters are deprecated and we don;t want to create side effect
461+ return;
462+ }
463+ updatePipeline();
464+ glUniform1f(
465+ batch._params[paramOffset + 1]._int,
466+ batch._params[paramOffset + 0]._int);
467+ (void) CHECK_GL_ERROR();
468+}
469+
436470 void Batch::_glUniform1f(GLint location, GLfloat v0) {
437471 if (location < 0) {
438472 return;
@@ -449,6 +483,8 @@ void GLBackend::do_glUniform1f(Batch& batch, uint32 paramOffset) { · 10 unmodified lines
449483 // because these uniform setters are deprecated and we don;t want to create side effect
450484 return;
451485 }
486+ updatePipeline();
487+
452488 glUniform1f(
453489 batch._params[paramOffset + 1]._int,
454490 batch._params[paramOffset + 0]._float);
@@ -471,6 +507,7 @@ void GLBackend::do_glUniform2f(Batch& batch, uint32 paramOffset) { · 16 unmodified lines
471507 // because these uniform setters are deprecated and we don;t want to create side effect
472508 return;
473509 }
510+ updatePipeline();
474511 glUniform2f(
475512 batch._params[paramOffset + 2]._int,
476513 batch._params[paramOffset + 1]._float,
@@ -495,6 +532,7 @@ void GLBackend::do_glUniform3f(Batch& batch, uint32 paramOffset) { · 18 unmodified lines
495532 // because these uniform setters are deprecated and we don;t want to create side effect
496533 return;
497534 }
535+ updatePipeline();
498536 glUniform3f(
499537 batch._params[paramOffset + 3]._int,
500538 batch._params[paramOffset + 2]._float,
@@ -519,6 +557,7 @@ void GLBackend::do_glUniform3fv(Batch& batch, uint32 paramOffset) { · 18 unmodified lines
519557 // because these uniform setters are deprecated and we don;t want to create side effect
520558 return;
521559 }
560+ updatePipeline();
522561 glUniform3fv(
523562 batch._params[paramOffset + 2]._int,
524563 batch._params[paramOffset + 1]._uint,
@@ -544,6 +583,7 @@ void GLBackend::do_glUniform4fv(Batch& batch, uint32 paramOffset) { · 19 unmodified lines
544583 // because these uniform setters are deprecated and we don;t want to create side effect
545584 return;
546585 }
586+ updatePipeline();
547587 glUniform4fv(
548588 batch._params[paramOffset + 2]._int,
549589 batch._params[paramOffset + 1]._uint,
@@ -569,6 +609,7 @@ void GLBackend::do_glUniformMatrix4fv(Batch& batch, uint32 paramOffset) { · 19 unmodified lines
569609 // because these uniform setters are deprecated and we don;t want to create side effect
570610 return;
571611 }
612+ updatePipeline();
572613 glUniformMatrix4fv(
573614 batch._params[paramOffset + 3]._int,
574615 batch._params[paramOffset + 2]._uint,
@@ -656,4 +697,20 @@ void GLBackend::fetchMatrix(GLenum target, glm::mat4 & m) { · 81 unmodified lines
656697 glGetFloatv(target, glm::value_ptr(m));
657698 }
658699
700+void GLBackend::checkGLStackStable(std::function<void()> f) {
701+#ifdef DEBUG
702+ GLint mvDepth, prDepth;
703+ glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &mvDepth);
704+ glGetIntegerv(GL_PROJECTION_STACK_DEPTH, &prDepth);
705+#endif
706+
707+ f();
659708
709+#ifdef DEBUG
710+ GLint mvDepthFinal, prDepthFinal;
711+ glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &mvDepthFinal);
712+ glGetIntegerv(GL_PROJECTION_STACK_DEPTH, &prDepthFinal);
713+ Q_ASSERT(mvDepth == mvDepthFinal);
714+ Q_ASSERT(prDepth == prDepthFinal);
715+#endif
716+}
libraries/gpu/src/gpu/GLBackend.h+9−1
@@ -12,11 +12,13 @@ · 11 unmodified lines
1212 #define hifi_gpu_GLBackend_h
1313
1414 #include <assert.h>
15+#include <functional>
16+#include <bitset>
17+
1518 #include "GPUConfig.h"
1619
1720 #include "Context.h"
1821 #include "Batch.h"
19−#include <bitset>
2022
2123
2224 namespace gpu {
@@ -47,6 +49,11 @@ public: · 24 unmodified lines
4749
4850 static bool checkGLError(const char* name = nullptr);
4951
52+ // Only checks in debug builds
53+ static bool checkGLErrorDebug(const char* name = nullptr);
54+
55+ static void checkGLStackStable(std::function<void()> f);
56+
5057 static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet());
5158
5259
@@ -377,6 +384,7 @@ protected: · 324 unmodified lines
377384 void do_glDrawBuffers(Batch& batch, uint32 paramOffset);
378385
379386 void do_glUseProgram(Batch& batch, uint32 paramOffset);
387+ void do_glUniform1i(Batch& batch, uint32 paramOffset);
380388 void do_glUniform1f(Batch& batch, uint32 paramOffset);
381389 void do_glUniform2f(Batch& batch, uint32 paramOffset);
382390 void do_glUniform3f(Batch& batch, uint32 paramOffset);
libraries/gpu/src/gpu/GLBackendOutput.cpp+1−0
@@ -11,6 +11,7 @@ · 10 unmodified lines
1111 #include "GPULogging.h"
1212 #include "GLBackendShared.h"
1313
14+using namespace gpu;
1415
1516 GLBackend::GLFramebuffer::GLFramebuffer() {}
1617
libraries/gpu/src/gpu/GLBackendShared.h+9−9
@@ -17,9 +17,7 @@ · 16 unmodified lines
1717
1818 #include "Batch.h"
1919
20−using namespace gpu;
21−
22−static const GLenum _primitiveToGLmode[NUM_PRIMITIVES] = {
20+static const GLenum _primitiveToGLmode[gpu::NUM_PRIMITIVES] = {
2321 GL_POINTS,
2422 GL_LINES,
2523 GL_LINE_STRIP,
@@ -30,7 +28,7 @@ static const GLenum _primitiveToGLmode[NUM_PRIMITIVES] = { · 4 unmodified lines
3028 GL_QUAD_STRIP,
3129 };
3230
33−static const GLenum _elementTypeToGLType[NUM_TYPES]= {
31+static const GLenum _elementTypeToGLType[gpu::NUM_TYPES] = {
3432 GL_FLOAT,
3533 GL_INT,
3634 GL_UNSIGNED_INT,
@@ -49,10 +47,12 @@ static const GLenum _elementTypeToGLType[NUM_TYPES]= { · 12 unmodified lines
4947 GL_UNSIGNED_BYTE
5048 };
5149
52−#if _DEBUG
53−#define CHECK_GL_ERROR() ::gpu::GLBackend::checkGLError(__FUNCTION__)
54−#else
55−#define CHECK_GL_ERROR() false
56−#endif
50+// Stupid preprocessor trick to turn the line macro into a string
51+#define CHECK_GL_ERROR_HELPER(x) #x
52+// FIXME doesn't build on Linux or Mac. Hmmmm
53+// #define CHECK_GL_ERROR() gpu::GLBackend::checkGLErrorDebug(__FUNCTION__ ":" CHECK_GL_ERROR_HELPER(__LINE__))
54+#define CHECK_GL_ERROR() gpu::GLBackend::checkGLErrorDebug(__FUNCTION__)
55+
56+#define CHECK_GL_STACK_STABLE(f) gpu::GLBackend::checkGLStackStable(f)
5757
5858 #endif
libraries/gpu/src/gpu/GLBackendTexture.cpp+3−2
@@ -11,6 +11,7 @@ · 10 unmodified lines
1111 #include "GPULogging.h"
1212 #include "GLBackendShared.h"
1313
14+using namespace gpu;
1415
1516 GLBackend::GLTexture::GLTexture() :
1617 _storageStamp(0),
@@ -343,10 +344,10 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { · 326 unmodified lines
343344 if (bytes && texture.isAutogenerateMips()) {
344345 glGenerateMipmap(GL_TEXTURE_2D);
345346 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
346− } else {
347+ }/* else {
347348 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
348349 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
349− }
350+ }*/
350351
351352 object->_target = GL_TEXTURE_2D;
352353
libraries/gpu/src/gpu/GLBackendTransform.cpp+13−16
@@ -75,6 +75,8 @@ void GLBackend::syncTransformStateCache() { · 74 unmodified lines
7575 }
7676
7777 void GLBackend::updateTransform() {
78+ GLint originalMatrixMode;
79+ glGetIntegerv(GL_MATRIX_MODE, &originalMatrixMode);
7880 // Check all the dirty flags and update the state accordingly
7981 if (_transform._invalidProj) {
8082 _transform._transformCamera._projection = _transform._projection;
@@ -132,12 +134,13 @@ void GLBackend::updateTransform() { · 51 unmodified lines
132134 (void) CHECK_GL_ERROR();
133135 }
134136
137+
135138 if (_transform._invalidModel || _transform._invalidView) {
139+ if (_transform._lastMode != GL_MODELVIEW) {
140+ glMatrixMode(GL_MODELVIEW);
141+ _transform._lastMode = GL_MODELVIEW;
142+ }
136143 if (!_transform._model.isIdentity()) {
137− if (_transform._lastMode != GL_MODELVIEW) {
138− glMatrixMode(GL_MODELVIEW);
139− _transform._lastMode = GL_MODELVIEW;
140− }
141144 Transform::Mat4 modelView;
142145 if (!_transform._view.isIdentity()) {
143146 Transform mvx;
@@ -147,19 +150,12 @@ void GLBackend::updateTransform() { · 3 unmodified lines
147150 _transform._model.getMatrix(modelView);
148151 }
149152 glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView));
153+ } else if (!_transform._view.isIdentity()) {
154+ Transform::Mat4 modelView;
155+ _transform._view.getInverseMatrix(modelView);
156+ glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView));
150157 } else {
151− if (!_transform._view.isIdentity()) {
152− if (_transform._lastMode != GL_MODELVIEW) {
153− glMatrixMode(GL_MODELVIEW);
154− _transform._lastMode = GL_MODELVIEW;
155− }
156− Transform::Mat4 modelView;
157− _transform._view.getInverseMatrix(modelView);
158− glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView));
159− } else {
160− // TODO: eventually do something about the matrix when neither view nor model is specified?
161− // glLoadIdentity();
162− }
158+ glLoadIdentity();
163159 }
164160 (void) CHECK_GL_ERROR();
165161 }
@@ -167,6 +163,7 @@ void GLBackend::updateTransform() { · 1 unmodified line
167163
168164 // Flags are clean
169165 _transform._invalidView = _transform._invalidProj = _transform._invalidModel = false;
166+ glMatrixMode(originalMatrixMode);
170167 }
171168
172169
libraries/gpu/src/gpu/Texture.cpp+10−10
@@ -581,20 +581,20 @@ void sphericalHarmonicsScale(float * result, int order, const float * input, flo · 580 unmodified lines
581581 void sphericalHarmonicsEvaluateDirection(float * result, int order, const glm::vec3 & dir) {
582582 // calculate coefficients for first 3 bands of spherical harmonics
583583 double P_0_0 = 0.282094791773878140;
584− double P_1_0 = 0.488602511902919920 * dir.z;
584+ double P_1_0 = 0.488602511902919920 * (double)dir.z;
585585 double P_1_1 = -0.488602511902919920;
586− double P_2_0 = 0.946174695757560080 * dir.z * dir.z - 0.315391565252520050;
587− double P_2_1 = -1.092548430592079200 * dir.z;
586+ double P_2_0 = 0.946174695757560080 * (double)dir.z * (double)dir.z - 0.315391565252520050;
587+ double P_2_1 = -1.092548430592079200 * (double)dir.z;
588588 double P_2_2 = 0.546274215296039590;
589589 result[0] = P_0_0;
590− result[1] = P_1_1 * dir.y;
590+ result[1] = P_1_1 * (double)dir.y;
591591 result[2] = P_1_0;
592− result[3] = P_1_1 * dir.x;
593− result[4] = P_2_2 * (dir.x * dir.y + dir.y * dir.x);
594− result[5] = P_2_1 * dir.y;
592+ result[3] = P_1_1 * (double)dir.x;
593+ result[4] = P_2_2 * ((double)dir.x * (double)dir.y + (double)dir.y * (double)dir.x);
594+ result[5] = P_2_1 * (double)dir.y;
595595 result[6] = P_2_0;
596− result[7] = P_2_1 * dir.x;
597− result[8] = P_2_2 * (dir.x * dir.x - dir.y * dir.y);
596+ result[7] = P_2_1 * (double)dir.x;
597+ result[8] = P_2_2 * ((double)dir.x * (double)dir.x - (double)dir.y * (double)dir.y);
598598 }
599599
600600 bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<glm::vec3> & output, const uint order) {
@@ -767,4 +767,4 @@ void SphericalHarmonics::evalFromTexture(const Texture& texture) { · 166 unmodified lines
767767 L21 = coefs[7];
768768 L22 = coefs[8];
769769 }
770−}
770+}
libraries/model/src/model/Light.cpp+1−1
@@ -73,7 +73,7 @@ void Light::setMaximumRadius(float radius) { · 72 unmodified lines
7373 radius = 1.0f;
7474 }
7575 float CutOffIntensityRatio = 0.05f;
76− float surfaceRadius = radius / (sqrt(1.0f / CutOffIntensityRatio) - 1.f);
76+ float surfaceRadius = radius / (sqrtf(1.0f / CutOffIntensityRatio) - 1.0f);
7777 editSchema()._attenuation = Vec4(surfaceRadius, 1.0f/surfaceRadius, CutOffIntensityRatio, radius);
7878 }
7979
libraries/model/src/model/Skybox.cpp+2−2
@@ -72,7 +72,7 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky · 71 unmodified lines
7272
7373 thePipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, skyState));
7474
75− const float CLIP = 1.0;
75+ const float CLIP = 1.0f;
7676 const glm::vec2 vertices[4] = { {-CLIP, -CLIP}, {CLIP, -CLIP}, {-CLIP, CLIP}, {CLIP, CLIP}};
7777 theBuffer.reset(new gpu::Buffer(sizeof(vertices), (const gpu::Byte*) vertices));
7878
@@ -110,7 +110,7 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky · 31 unmodified lines
110110 } else {
111111 // skybox has no cubemap, just clear the color buffer
112112 auto color = skybox.getColor();
113− batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(color, 0.0f), 0.f, 0);
113+ batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(color, 0.0f), 0.0f, 0);
114114 }
115115 }
116116
libraries/model/src/model/Stage.cpp+6−6
@@ -42,9 +42,9 @@ Mat4d EarthSunModel::evalWorldToGeoLocationMat(double longitude, double latitude · 41 unmodified lines
4242
4343 void EarthSunModel::updateWorldToSurface() const {
4444 // Check if the final position is too close to the earth center ?
45− double absAltitude = _earthRadius + _altitude;
46− if ( absAltitude < 0.01) {
47− absAltitude = 0.01;
45+ float absAltitude = _earthRadius + _altitude;
46+ if ( absAltitude < 0.01f) {
47+ absAltitude = 0.01f;
4848 }
4949
5050 // Final world to local Frame
@@ -263,8 +263,8 @@ double evalSunDeclinaison(double dayNumber) { · 212 unmodified lines
263263 void SunSkyStage::updateGraphicsObject() const {
264264 // Always update the sunLongitude based on the current dayTime and the current origin
265265 // The day time is supposed to be local at the origin
266− double signedNormalizedDayTime = (_dayTime - NUM_HOURS_PER_HALF_DAY) / NUM_HOURS_PER_HALF_DAY;
267− double sunLongitude = _earthSunModel.getLongitude() + (MAX_LONGITUDE * signedNormalizedDayTime);
266+ float signedNormalizedDayTime = (_dayTime - NUM_HOURS_PER_HALF_DAY) / NUM_HOURS_PER_HALF_DAY;
267+ float sunLongitude = _earthSunModel.getLongitude() + (MAX_LONGITUDE * signedNormalizedDayTime);
268268 _earthSunModel.setSunLongitude(sunLongitude);
269269
270270 // And update the sunLAtitude as the declinaison depending of the time of the year
@@ -302,4 +302,4 @@ void SunSkyStage::setBackgroundMode(BackgroundMode mode) { · 31 unmodified lines
302302 void SunSkyStage::setSkybox(const SkyboxPointer& skybox) {
303303 _skybox = skybox;
304304 invalidate();
305−}
305+}
libraries/model/src/model/Stage.h+1−1
@@ -72,7 +72,7 @@ public: · 71 unmodified lines
7272
7373 protected:
7474 float _scale = 1000.0f; //Km
75− double _earthRadius = 6360.0;
75+ float _earthRadius = 6360.0;
7676
7777 Quat _surfaceOrientation;
7878
libraries/networking/src/AddressManager.cpp+4−0
@@ -308,6 +308,9 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const · 307 unmodified lines
308308 handlePath(returnedPath, trigger);
309309 }
310310 } else {
311+ // we're going to hit the index path, set that as the _newHostLookupPath
312+ _newHostLookupPath = INDEX_PATH;
313+
311314 // we didn't override the path or get one back - ask the DS for the viewpoint of its index path
312315 // which we will jump to if it exists
313316 emit pathChangeRequired(INDEX_PATH);
@@ -479,6 +482,7 @@ bool AddressManager::handleViewpoint(const QString& viewpointString, bool should · 165 unmodified lines
479482 // We use _newHostLookupPath to determine if the client has already stored its last address
480483 // before moving to a new host thanks to the information in the same lookup URL.
481484
485+
482486 if (definitelyPathOnly || (!pathString.isEmpty() && pathString != _newHostLookupPath)) {
483487 addCurrentAddressToHistory(LookupTrigger::UserInput);
484488 }
libraries/networking/src/AddressManager.h+3−0
@@ -62,6 +62,9 @@ public: · 61 unmodified lines
6262
6363 void loadSettings(const QString& lookupString = QString());
6464
65+ const QStack<QUrl>& getBackStack() const { return _backStack; }
66+ const QStack<QUrl>& getForwardStack() const { return _forwardStack; }
67+
6568 public slots:
6669 void handleLookupString(const QString& lookupString);
6770
libraries/networking/src/BandwidthRecorder.cpp+2−2
@@ -21,7 +21,7 @@ BandwidthRecorder::Channel::Channel() { · 20 unmodified lines
2121 float BandwidthRecorder::Channel::getAverageInputPacketsPerSecond() {
2222 float delt = _input.getEventDeltaAverage();
2323 if (delt > 0.0f) {
24− return (1.0 / delt);
24+ return (1.0f / delt);
2525 }
2626 return 0.0f;
2727 }
@@ -29,7 +29,7 @@ float BandwidthRecorder::Channel::getAverageInputPacketsPerSecond() { · 1 unmodified line
2929 float BandwidthRecorder::Channel::getAverageOutputPacketsPerSecond() {
3030 float delt = _input.getEventDeltaAverage();
3131 if (delt > 0.0f) {
32− return (1.0 / _output.getEventDeltaAverage());
32+ return (1.0f / _output.getEventDeltaAverage());
3333 }
3434 return 0.0f;
3535 }
libraries/octree/src/CoverageMap.cpp+1−1
@@ -75,7 +75,7 @@ CoverageMap::~CoverageMap() { · 74 unmodified lines
7575
7676 void CoverageMap::printStats() {
7777 qCDebug(octree, "CoverageMap::printStats()...");
78− qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f",MINIMUM_POLYGON_AREA_TO_STORE);
78+ qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f", (double)MINIMUM_POLYGON_AREA_TO_STORE);
7979 qCDebug(octree, "_mapCount=%d",_mapCount);
8080 qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls);
8181 qCDebug(octree, "_notAllInView=%d",_notAllInView);
libraries/octree/src/CoverageMapV2.cpp+1−1
@@ -82,7 +82,7 @@ void CoverageMapV2::erase() { · 81 unmodified lines
8282
8383 if (_isRoot && wantDebugging) {
8484 qCDebug(octree, "CoverageMapV2 last to be deleted...");
85− qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f",MINIMUM_POLYGON_AREA_TO_STORE);
85+ qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f", (double)MINIMUM_POLYGON_AREA_TO_STORE);
8686 qCDebug(octree, "_mapCount=%d",_mapCount);
8787 qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls);
8888 qCDebug(octree, "_notAllInView=%d",_notAllInView);
libraries/octree/src/OctreeElement.cpp+28−26
@@ -69,8 +69,8 @@ void OctreeElement::init(unsigned char * octalCode) { · 68 unmodified lines
6969 // set up the _children union
7070 _childBitmask = 0;
7171 _childrenExternal = false;
72−
73−
72+
73+
7474 #ifdef BLENDED_UNION_CHILDREN
7575 _children.external = NULL;
7676 _singleChildrenCount++;
@@ -662,7 +662,7 @@ void OctreeElement::deleteAllChildren() { · 585 unmodified lines
662662 delete childAt;
663663 }
664664 }
665−
665+
666666 if (_childrenExternal) {
667667 // if the children_t union represents _children.external we need to delete it here
668668 delete[] _children.external;
@@ -764,7 +764,7 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) { · 95 unmodified lines
764764 memset(_children.external, 0, sizeof(OctreeElement*) * NUMBER_OF_CHILDREN);
765765 _children.external[firstIndex] = previousChild;
766766 _children.external[childIndex] = child;
767−
767+
768768 _childrenExternal = true;
769769
770770 _externalChildrenMemoryUsage += NUMBER_OF_CHILDREN * sizeof(OctreeElement*);
@@ -776,7 +776,7 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) { · 5 unmodified lines
776776
777777 delete[] _children.external;
778778 _childrenExternal = false;
779−
779+
780780 _externalChildrenMemoryUsage -= NUMBER_OF_CHILDREN * sizeof(OctreeElement*);
781781 if (childIndex == firstIndex) {
782782 _children.single = previousSecondChild;
@@ -1203,12 +1203,13 @@ void OctreeElement::printDebugDetails(const char* label) const { · 420 unmodified lines
12031203 setAtBit(childBits,i);
12041204 }
12051205 }
1206−
1206+
12071207 QDebug elementDebug = qDebug().nospace();
12081208
12091209 QString resultString;
12101210 resultString.sprintf("%s - Voxel at corner=(%f,%f,%f) size=%f\n isLeaf=%s isDirty=%s shouldRender=%s\n children=", label,
1211− _cube.getCorner().x, _cube.getCorner().y, _cube.getCorner().z, _cube.getScale(),
1211+ (double)_cube.getCorner().x, (double)_cube.getCorner().y, (double)_cube.getCorner().z,
1212+ (double)_cube.getScale(),
12121213 debug::valueOf(isLeaf()), debug::valueOf(isDirty()), debug::valueOf(getShouldRender()));
12131214 elementDebug << resultString;
12141215
@@ -1236,7 +1237,7 @@ ViewFrustum::location OctreeElement::inFrustum(const ViewFrustum& viewFrustum) c · 21 unmodified lines
12361237 // By doing this, we don't need to test each child voxel's position vs the LOD boundary
12371238 bool OctreeElement::calculateShouldRender(const ViewFrustum* viewFrustum, float voxelScaleSize, int boundaryLevelAdjust) const {
12381239 bool shouldRender = false;
1239−
1240+
12401241 if (hasContent()) {
12411242 float furthestDistance = furthestDistanceToCamera(*viewFrustum);
12421243 float childBoundary = boundaryDistanceForRenderLevel(getLevel() + 1 + boundaryLevelAdjust, voxelScaleSize);
@@ -1330,7 +1331,7 @@ void OctreeElement::notifyUpdateHooks() { · 87 unmodified lines
13301331 }
13311332
13321333 bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
1333− bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
1334+ bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
13341335 void** intersectedObject, bool precisionPicking) {
13351336
13361337 keepSearching = true; // assume that we will continue searching after this.
@@ -1354,7 +1355,7 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 · 17 unmodified lines
13541355 // for any details inside the cube to be closer so we don't need to consider them.
13551356 if (_cube.contains(origin) || distanceToElementCube < distance) {
13561357
1357− if (findDetailedRayIntersection(origin, direction, keepSearching, element, distanceToElementDetails,
1358+ if (findDetailedRayIntersection(origin, direction, keepSearching, element, distanceToElementDetails,
13581359 face, intersectedObject, precisionPicking, distanceToElementCube)) {
13591360
13601361 if (distanceToElementDetails < distance) {
@@ -1368,10 +1369,10 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 · 7 unmodified lines
13681369 }
13691370
13701371 bool OctreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
1371− bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
1372+ bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
13721373 void** intersectedObject, bool precisionPicking, float distanceToElementCube) {
13731374
1374− // we did hit this element, so calculate appropriate distances
1375+ // we did hit this element, so calculate appropriate distances
13751376 if (hasContent()) {
13761377 element = this;
13771378 distance = distanceToElementCube;
@@ -1399,7 +1400,8 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float · 21 unmodified lines
13991400 float halfOurScale = ourScale / 2.0f;
14001401
14011402 if(s > ourScale) {
1402− qCDebug(octree, "UNEXPECTED -- OctreeElement::getOrCreateChildElementAt() s=[%f] > ourScale=[%f] ", s, ourScale);
1403+ qCDebug(octree, "UNEXPECTED -- OctreeElement::getOrCreateChildElementAt() s=[%f] > ourScale=[%f] ",
1404+ (double)s, (double)ourScale);
14031405 }
14041406
14051407 if (s > halfOurScale) {
@@ -1466,21 +1468,21 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float · 60 unmodified lines
14661468
14671469 OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AACube& cube) {
14681470 OctreeElement* child = NULL;
1469−
1471+
14701472 int childIndex = getMyChildContaining(cube);
1471−
1473+
14721474 // If getMyChildContaining() returns CHILD_UNKNOWN then it means that our level
14731475 // is the correct level for this cube
14741476 if (childIndex == CHILD_UNKNOWN) {
14751477 return this;
14761478 }
1477−
1479+
14781480 // Now, check if we have a child at that location
14791481 child = getChildAtIndex(childIndex);
14801482 if (!child) {
14811483 child = addChildAtIndex(childIndex);
14821484 }
1483−
1485+
14841486 // if we've made a really small child, then go ahead and use that one.
14851487 if (child->getScale() <= SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE) {
14861488 return child;
@@ -1492,21 +1494,21 @@ OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AACube& cu · 5 unmodified lines
14921494
14931495 OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AABox& box) {
14941496 OctreeElement* child = NULL;
1495−
1497+
14961498 int childIndex = getMyChildContaining(box);
1497−
1499+
14981500 // If getMyChildContaining() returns CHILD_UNKNOWN then it means that our level
14991501 // is the correct level for this cube
15001502 if (childIndex == CHILD_UNKNOWN) {
15011503 return this;
15021504 }
1503−
1505+
15041506 // Now, check if we have a child at that location
15051507 child = getChildAtIndex(childIndex);
15061508 if (!child) {
15071509 child = addChildAtIndex(childIndex);
15081510 }
1509−
1511+
15101512 // if we've made a really small child, then go ahead and use that one.
15111513 if (child->getScale() <= SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE) {
15121514 return child;
@@ -1542,7 +1544,7 @@ int OctreeElement::getMyChildContaining(const AACube& cube) const { · 29 unmodified lines
15421544 if (childIndexCubeMinimum != childIndexCubeMaximum) {
15431545 return CHILD_UNKNOWN;
15441546 }
1545−
1547+
15461548 return childIndexCubeMinimum; // either would do, they are the same
15471549 }
15481550 return CHILD_UNKNOWN; // since cube is not contained in our element, it can't be in one of our children
@@ -1555,7 +1557,7 @@ int OctreeElement::getMyChildContaining(const AABox& box) const { · 6 unmodified lines
15551557 // TODO: consider changing this to assert()
15561558 if(boxLargestScale > ourScale) {
15571559 qCDebug(octree, "UNEXPECTED -- OctreeElement::getMyChildContaining() "
1558− "boxLargestScale=[%f] > ourScale=[%f] ", boxLargestScale, ourScale);
1560+ "boxLargestScale=[%f] > ourScale=[%f] ", (double)boxLargestScale, (double)ourScale);
15591561 }
15601562
15611563 // Determine which of our children the minimum and maximum corners of the cube live in...
@@ -1566,7 +1568,7 @@ int OctreeElement::getMyChildContaining(const AABox& box) const { · 4 unmodified lines
15661568 int childIndexCubeMinimum = getMyChildContainingPoint(cubeCornerMinimum);
15671569 int childIndexCubeMaximum = getMyChildContainingPoint(cubeCornerMaximum);
15681570
1569− // If the minimum and maximum corners of the cube are in two different children's cubes,
1571+ // If the minimum and maximum corners of the cube are in two different children's cubes,
15701572 // then we are the containing element
15711573 if (childIndexCubeMinimum != childIndexCubeMaximum) {
15721574 return CHILD_UNKNOWN;
@@ -1579,12 +1581,12 @@ int OctreeElement::getMyChildContaining(const AABox& box) const { · 6 unmodified lines
15791581 int OctreeElement::getMyChildContainingPoint(const glm::vec3& point) const {
15801582 glm::vec3 ourCenter = _cube.calcCenter();
15811583 int childIndex = CHILD_UNKNOWN;
1582−
1584+
15831585 // since point is not contained in our element, it can't be in one of our children
15841586 if (!_cube.contains(point)) {
15851587 return CHILD_UNKNOWN;
15861588 }
1587−
1589+
15881590 // left half
15891591 if (point.x > ourCenter.x) {
15901592 if (point.y > ourCenter.y) {
libraries/octree/src/OctreePacketData.cpp+5−3
@@ -384,10 +384,12 @@ bool OctreePacketData::appendValue(const glm::vec3& value) { · 383 unmodified lines
384384 bool OctreePacketData::appendValue(const QVector<glm::vec3>& value) {
385385 uint16_t qVecSize = value.size();
386386 bool success = appendValue(qVecSize);
387− success = append((const unsigned char*)value.constData(), qVecSize * sizeof(glm::vec3));
388387 if (success) {
389− _bytesOfValues += qVecSize * sizeof(glm::vec3);
390− _totalBytesOfValues += qVecSize * sizeof(glm::vec3);
388+ success = append((const unsigned char*)value.constData(), qVecSize * sizeof(glm::vec3));
389+ if (success) {
390+ _bytesOfValues += qVecSize * sizeof(glm::vec3);
391+ _totalBytesOfValues += qVecSize * sizeof(glm::vec3);
392+ }
391393 }
392394 return success;
393395 }
libraries/octree/src/OctreePersistThread.cpp+13−0
@@ -350,6 +350,19 @@ void OctreePersistThread::rollOldBackupVersions(const BackupRule& rule) { · 349 unmodified lines
350350 if (rule.extensionFormat.contains("%N")) {
351351 if (rule.maxBackupVersions > 0) {
352352 qCDebug(octree) << "Rolling old backup versions for rule" << rule.name << "...";
353+
354+ // Delete maximum rolling file because rename() fails on Windows if target exists
355+ QString backupMaxExtensionN = rule.extensionFormat;
356+ backupMaxExtensionN.replace(QString("%N"), QString::number(rule.maxBackupVersions));
357+ QString backupMaxFilenameN = _filename + backupMaxExtensionN;
358+ QFile backupMaxFileN(backupMaxFilenameN);
359+ if (backupMaxFileN.exists()) {
360+ int result = remove(qPrintable(backupMaxFilenameN));
361+ if (result != 0) {
362+ qCDebug(octree) << "ERROR deleting old backup file " << backupMaxFilenameN;
363+ }
364+ }
365+
353366 for(int n = rule.maxBackupVersions - 1; n > 0; n--) {
354367 QString backupExtensionN = rule.extensionFormat;
355368 QString backupExtensionNplusOne = rule.extensionFormat;
libraries/octree/src/OctreeProjectedPolygon.cpp+104−103
@@ -96,8 +96,9 @@ void BoundingBox::explandToInclude(const BoundingBox& box) { · 95 unmodified lines
9696
9797 void BoundingBox::printDebugDetails(const char* label) const {
9898 qCDebug(octree, "%s _set=%s\n corner=%f,%f size=%f,%f\n bounds=[(%f,%f) to (%f,%f)]",
99− (label ? label : "BoundingBox"),
100− debug::valueOf(_set), corner.x, corner.y, size.x, size.y, corner.x, corner.y, corner.x+size.x, corner.y+size.y);
99+ (label ? label : "BoundingBox"),
100+ debug::valueOf(_set), (double)corner.x, (double)corner.y, (double)size.x, (double)size.y,
101+ (double)corner.x, (double)corner.y, (double)(corner.x+size.x), (double)(corner.y+size.y));
101102 }
102103
103104
@@ -107,7 +108,7 @@ long OctreeProjectedPolygon::intersects_calls = 0; · 3 unmodified lines
107108
108109
109110 OctreeProjectedPolygon::OctreeProjectedPolygon(const BoundingBox& box) :
110− _vertexCount(4),
111+ _vertexCount(4),
111112 _maxX(-FLT_MAX), _maxY(-FLT_MAX), _minX(FLT_MAX), _minY(FLT_MAX),
112113 _distance(0)
113114 {
@@ -117,9 +118,9 @@ OctreeProjectedPolygon::OctreeProjectedPolygon(const BoundingBox& box) : · 3 unmodified lines
117118 }
118119
119120
120−void OctreeProjectedPolygon::setVertex(int vertex, const glm::vec2& point) {
121+void OctreeProjectedPolygon::setVertex(int vertex, const glm::vec2& point) {
121122 _vertices[vertex] = point;
122−
123+
123124 // keep track of our bounding box
124125 if (point.x > _maxX) {
125126 _maxX = point.x;
@@ -133,14 +134,14 @@ void OctreeProjectedPolygon::setVertex(int vertex, const glm::vec2& point) { · 7 unmodified lines
133134 if (point.y < _minY) {
134135 _minY = point.y;
135136 }
136−
137+
137138 }
138139
139140 // can be optimized with new pointInside()
140141 bool OctreeProjectedPolygon::occludes(const OctreeProjectedPolygon& occludee, bool checkAllInView) const {
141142
142143 OctreeProjectedPolygon::occludes_calls++;
143−
144+
144145 // if we are completely out of view, then we definitely don't occlude!
145146 // if the occludee is completely out of view, then we also don't occlude it
146147 //
@@ -158,7 +159,7 @@ bool OctreeProjectedPolygon::occludes(const OctreeProjectedPolygon& occludee, bo · 11 unmodified lines
158159 (occludee.getMinY() < getMinY())) {
159160 return false;
160161 }
161−
162+
162163 // we need to test for identity as well, because in the case of identity, none of the points
163164 // will be "inside" but we don't want to bail early on the first non-inside point
164165 bool potentialIdenity = false;
@@ -171,7 +172,7 @@ bool OctreeProjectedPolygon::occludes(const OctreeProjectedPolygon& occludee, bo · 6 unmodified lines
171172 for(int i = 0; i < occludee.getVertexCount(); i++) {
172173 bool vertexMatched = false;
173174 if (!pointInside(occludee.getVertex(i), &vertexMatched)) {
174−
175+
175176 // so the point we just tested isn't inside, but it might have matched a vertex
176177 // if it didn't match a vertext, then we bail because we can't be an identity
177178 // or if we're not expecting identity, then we also bail early, no matter what
@@ -182,7 +183,7 @@ bool OctreeProjectedPolygon::occludes(const OctreeProjectedPolygon& occludee, bo · 4 unmodified lines
182183 pointsInside++;
183184 }
184185 }
185−
186+
186187 // we're only here if all points are inside matched and/or we had a potentialIdentity we need to check
187188 if (pointsInside == occludee.getVertexCount()) {
188189 return true;
@@ -192,7 +193,7 @@ bool OctreeProjectedPolygon::occludes(const OctreeProjectedPolygon& occludee, bo · 3 unmodified lines
192193 if (potentialIdenity) {
193194 return matches(occludee);
194195 }
195−
196+
196197 return false; // if we got this far, then we're not occluded
197198 }
198199
@@ -211,7 +212,7 @@ bool OctreeProjectedPolygon::matches(const OctreeProjectedPolygon& testee) const · 12 unmodified lines
211212 int originIndex = 0;
212213 for(int i = 0; i < vertextCount; i++) {
213214 glm::vec2 testeeVertex = testee.getVertex(i);
214−
215+
215216 // if they match, we found our origin.
216217 if (testeeVertex == polygonVertex) {
217218 originIndex = i;
@@ -224,10 +225,10 @@ bool OctreeProjectedPolygon::matches(const OctreeProjectedPolygon& testee) const · 6 unmodified lines
224225 glm::vec2 testeeVertex = testee.getVertex((i + originIndex) % vertextCount);
225226 glm::vec2 polygonVertex = getVertex(i);
226227 if (testeeVertex != polygonVertex) {
227− return false; // we don't match, therefore we're not the same
228− }
229− }
230− return true; // all of our vertices match, therefore we're the same
228+ return false; // we don't match, therefore we're not the same
229+ }
230+ }
231+ return true; // all of our vertices match, therefore we're the same
231232 }
232233
233234 bool OctreeProjectedPolygon::matches(const BoundingBox& box) const {
@@ -259,17 +260,17 @@ bool OctreeProjectedPolygon::pointInside(const glm::vec2& point, bool* matchesVe · 25 unmodified lines
259260 return false;
260261 }
261262 }
262−
263+
263264 return true;
264265 }
265−
266+
266267 void OctreeProjectedPolygon::printDebugDetails() const {
267268 qCDebug(octree, "OctreeProjectedPolygon..."
268− " minX=%f maxX=%f minY=%f maxY=%f", getMinX(), getMaxX(), getMinY(), getMaxY());
269− qCDebug(octree, " vertex count=%d distance=%f", getVertexCount(), getDistance());
269+ " minX=%f maxX=%f minY=%f maxY=%f", (double)getMinX(), (double)getMaxX(), (double)getMinY(), (double)getMaxY());
270+ qCDebug(octree, " vertex count=%d distance=%f", getVertexCount(), (double)getDistance());
270271 for (int i = 0; i < getVertexCount(); i++) {
271272 glm::vec2 point = getVertex(i);
272− qCDebug(octree, " vertex[%d] = %f, %f ", i, point.x, point.y);
273+ qCDebug(octree, " vertex[%d] = %f, %f ", i, (double)point.x, (double)point.y);
273274 }
274275 }
275276
@@ -291,7 +292,7 @@ bool OctreeProjectedPolygon::intersects(const OctreeProjectedPolygon& testee) co · 15 unmodified lines
291292 // intersect on all axes.
292293 //
293294 // Note: this only works on convex polygons
294−//
295+//
295296 //
296297 bool OctreeProjectedPolygon::intersectsOnAxes(const OctreeProjectedPolygon& testee) const {
297298
@@ -307,11 +308,11 @@ bool OctreeProjectedPolygon::intersectsOnAxes(const OctreeProjectedPolygon& test · 9 unmodified lines
307308 // points that are ON the edge, are considered to be "outside"
308309 for (int j = 0; j < testee.getVertexCount(); j++) {
309310 glm::vec2 testeeVertex = testee.getVertex(j);
310−
311+
311312 // in comparison below:
312313 // >= will cause points on edge to be considered inside
313314 // > will cause points on edge to be considered outside
314−
315+
315316 float c2 = a * testeeVertex.x + b * testeeVertex.y;
316317 if (c2 >= c) {
317318 goto CONTINUE_OUTER;
@@ -328,11 +329,11 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 10 unmodified lines
328329 // RIGHT/NEAR
329330 // LEFT/NEAR
330331 if (
331− (getProjectionType() == that.getProjectionType()) &&
332+ (getProjectionType() == that.getProjectionType()) &&
332333 (
333334 getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR) ||
334335 getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)
335− )
336+ )
336337 ) {
337338 if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(5)) {
338339 return true;
@@ -350,10 +351,10 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 11 unmodified lines
350351
351352 // NEAR/BOTTOM
352353 if (
353− (getProjectionType() == that.getProjectionType()) &&
354+ (getProjectionType() == that.getProjectionType()) &&
354355 (
355356 getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM)
356− )
357+ )
357358 ) {
358359 if (getVertex(0) == that.getVertex(5) && getVertex(3) == that.getVertex(4)) {
359360 return true;
@@ -371,10 +372,10 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 11 unmodified lines
371372
372373 // NEAR/TOP
373374 if (
374− (getProjectionType() == that.getProjectionType()) &&
375+ (getProjectionType() == that.getProjectionType()) &&
375376 (
376377 getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP)
377− )
378+ )
378379 ) {
379380 if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) {
380381 return true;
@@ -393,11 +394,11 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 12 unmodified lines
393394 // RIGHT/NEAR & NEAR/RIGHT/TOP
394395 // LEFT/NEAR & NEAR/LEFT/TOP
395396 if (
396− ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) &&
397− (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
397+ ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) &&
398+ (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
398399 ||
399− ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) &&
400− (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
400+ ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) &&
401+ (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
401402 )
402403 {
403404 if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) {
@@ -407,12 +408,12 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 3 unmodified lines
407408 // RIGHT/NEAR & NEAR/RIGHT/TOP
408409 // LEFT/NEAR & NEAR/LEFT/TOP
409410 if (
410− ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) &&
411− (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
411+ ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) &&
412+ (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
412413 ||
413− ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) &&
414− (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
415−
414+ ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) &&
415+ (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
416+
416417 )
417418 {
418419 if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) {
@@ -423,12 +424,12 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines
423424 // RIGHT/NEAR & NEAR/RIGHT/BOTTOM
424425 // NEAR/LEFT & NEAR/LEFT/BOTTOM
425426 if (
426− ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
427− (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
427+ ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
428+ (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
428429 ||
429− ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
430− (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
431−
430+ ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
431+ (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
432+
432433 )
433434 {
434435 if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) {
@@ -438,11 +439,11 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 3 unmodified lines
438439 // RIGHT/NEAR & NEAR/RIGHT/BOTTOM
439440 // NEAR/LEFT & NEAR/LEFT/BOTTOM
440441 if (
441− ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
442− (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
442+ ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
443+ (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
443444 ||
444− ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
445− (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
445+ ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
446+ (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
446447 )
447448 {
448449 if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) {
@@ -453,7 +454,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines
453454 // NEAR/TOP & NEAR
454455 if (
455456 (getProjectionType() == (PROJECTION_NEAR )) &&
456− (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP ))
457+ (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP ))
457458 )
458459 {
459460 if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) {
@@ -464,7 +465,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines
464465 // NEAR/TOP & NEAR
465466 if (
466467 (that.getProjectionType() == (PROJECTION_NEAR )) &&
467− (getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP ))
468+ (getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP ))
468469 )
469470 {
470471 if (getVertex(5) == that.getVertex(0) && getVertex(2) == that.getVertex(1)) {
@@ -475,7 +476,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines
475476 // NEAR/BOTTOM & NEAR
476477 if (
477478 (getProjectionType() == (PROJECTION_NEAR )) &&
478− (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM ))
479+ (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM ))
479480 )
480481 {
481482 if (getVertex(2) == that.getVertex(3) && getVertex(3) == that.getVertex(0)) {
@@ -486,7 +487,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines
486487 // NEAR/BOTTOM & NEAR
487488 if (
488489 (that.getProjectionType() == (PROJECTION_NEAR )) &&
489− (getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM ))
490+ (getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM ))
490491 )
491492 {
492493 if (getVertex(3) == that.getVertex(2) && getVertex(0) == that.getVertex(3)) {
@@ -497,7 +498,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines
497498 // NEAR/RIGHT & NEAR
498499 if (
499500 (getProjectionType() == (PROJECTION_NEAR )) &&
500− (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT ))
501+ (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT ))
501502 )
502503 {
503504 if (getVertex(0) == that.getVertex(1) && getVertex(3) == that.getVertex(4)) {
@@ -508,18 +509,18 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines
508509 // NEAR/RIGHT & NEAR
509510 if (
510511 (that.getProjectionType() == (PROJECTION_NEAR )) &&
511− (getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT ))
512+ (getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT ))
512513 )
513514 {
514515 if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) {
515516 return true;
516517 }
517518 }
518−
519+
519520 // NEAR/LEFT & NEAR
520521 if (
521522 (getProjectionType() == (PROJECTION_NEAR )) &&
522− (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT ))
523+ (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT ))
523524 )
524525 {
525526 if (getVertex(1) == that.getVertex(1) && getVertex(2) == that.getVertex(4)) {
@@ -530,7 +531,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines
530531 // NEAR/LEFT & NEAR
531532 if (
532533 (that.getProjectionType() == (PROJECTION_NEAR )) &&
533− (getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT ))
534+ (getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT ))
534535 )
535536 {
536537 if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) {
@@ -559,7 +560,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 22 unmodified lines
559560 return true;
560561 }
561562 }
562−
563+
563564
564565 // NEAR/RIGHT/BOTTOM & NEAR/BOTTOM
565566 if (
@@ -582,7 +583,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 16 unmodified lines
582583 return true;
583584 }
584585 }
585−
586+
586587 // NEAR/LEFT/BOTTOM & NEAR/BOTTOM
587588 if (
588589 ((getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) &&
@@ -592,12 +593,12 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 3 unmodified lines
592593 if (getVertex(2) == that.getVertex(0) && getVertex(4) == that.getVertex(4)) {
593594 return true;
594595 }
595− }
596+ }
596597
597598 // NEAR/LEFT/BOTTOM & NEAR/BOTTOM
598599 if (
599600 ((that.getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) &&
600− (getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR | PROJECTION_LEFT )))
601+ (getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR | PROJECTION_LEFT )))
601602 )
602603 {
603604 if (getVertex(0) == that.getVertex(2) && getVertex(4) == that.getVertex(4)) {
@@ -609,7 +610,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 5 unmodified lines
609610 // LEFT/NEAR/BOTTOM
610611 // LEFT/NEAR/TOP
611612 if (
612− (getProjectionType() == that.getProjectionType()) &&
613+ (getProjectionType() == that.getProjectionType()) &&
613614 (
614615 getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM ) ||
615616 getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP ) ||
@@ -646,11 +647,11 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 30 unmodified lines
646647 // RIGHT/NEAR
647648 // LEFT/NEAR
648649 if (
649− (getProjectionType() == that.getProjectionType()) &&
650+ (getProjectionType() == that.getProjectionType()) &&
650651 (
651− getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR) ||
652+ getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR) ||
652653 getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)
653− )
654+ )
654655 ) {
655656 if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(5)) {
656657 //setVertex(0, this.getVertex(0)); // no change
@@ -689,13 +690,13 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 32 unmodified lines
689690 return; // done
690691 }
691692 }
692−
693+
693694 // NEAR/BOTTOM
694695 if (
695− (getProjectionType() == that.getProjectionType()) &&
696+ (getProjectionType() == that.getProjectionType()) &&
696697 (
697698 getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM)
698− )
699+ )
699700 ) {
700701 if (getVertex(0) == that.getVertex(5) && getVertex(3) == that.getVertex(4)) {
701702 setVertex(0, that.getVertex(0));
@@ -737,10 +738,10 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 35 unmodified lines
737738
738739 // NEAR/TOP
739740 if (
740− (getProjectionType() == that.getProjectionType()) &&
741+ (getProjectionType() == that.getProjectionType()) &&
741742 (
742743 getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP)
743− )
744+ )
744745 ) {
745746 if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) {
746747 setVertex(0, that.getVertex(0));
@@ -779,16 +780,16 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 32 unmodified lines
779780 return; // done
780781 }
781782 }
782−
783+
783784
784785 // RIGHT/NEAR & NEAR/RIGHT/TOP
785786 // LEFT/NEAR & NEAR/LEFT/TOP
786787 if (
787− ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) &&
788− (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
788+ ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) &&
789+ (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
789790 ||
790− ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) &&
791− (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
791+ ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) &&
792+ (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
792793 )
793794 {
794795 if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) {
@@ -806,12 +807,12 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 11 unmodified lines
806807 // RIGHT/NEAR & NEAR/RIGHT/TOP
807808 // LEFT/NEAR & NEAR/LEFT/TOP
808809 if (
809− ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) &&
810− (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
810+ ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) &&
811+ (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
811812 ||
812− ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) &&
813− (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
814−
813+ ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) &&
814+ (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
815+
815816 )
816817 {
817818 if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) {
@@ -829,12 +830,12 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 11 unmodified lines
829830 // RIGHT/NEAR & NEAR/RIGHT/BOTTOM
830831 // NEAR/LEFT & NEAR/LEFT/BOTTOM
831832 if (
832− ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
833− (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
833+ ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
834+ (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
834835 ||
835− ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
836− (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
837−
836+ ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
837+ (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
838+
838839 )
839840 {
840841 if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) {
@@ -851,11 +852,11 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 10 unmodified lines
851852 // RIGHT/NEAR & NEAR/RIGHT/BOTTOM
852853 // NEAR/LEFT & NEAR/LEFT/BOTTOM
853854 if (
854− ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
855− (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
855+ ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
856+ (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
856857 ||
857− ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
858− (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
858+ ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
859+ (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
859860 )
860861 {
861862 if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) {
@@ -865,16 +866,16 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 3 unmodified lines
865866 //setVertex(3, this.getVertex(3)); // no change
866867 //setVertex(4, this.getVertex(4)); // no change
867868 //setVertex(5, this.getVertex(5)); // no change
868− setProjectionType((PROJECTION_RIGHT | PROJECTION_NEAR));
869+ setProjectionType((PROJECTION_RIGHT | PROJECTION_NEAR));
869870 return; // done
870871 }
871872 }
872−
873−
873+
874+
874875 // NEAR/TOP & NEAR
875876 if (
876877 (getProjectionType() == (PROJECTION_NEAR )) &&
877− (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP ))
878+ (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP ))
878879 )
879880 {
880881 if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) {
@@ -891,7 +892,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 10 unmodified lines
891892 // NEAR/TOP & NEAR
892893 if (
893894 (that.getProjectionType() == (PROJECTION_NEAR )) &&
894− (getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP ))
895+ (getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP ))
895896 )
896897 {
897898 if (getVertex(5) == that.getVertex(0) && getVertex(2) == that.getVertex(1)) {
@@ -904,11 +905,11 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 6 unmodified lines
904905 return; // done
905906 }
906907 }
907−
908+
908909 // NEAR/BOTTOM & NEAR
909910 if (
910911 (getProjectionType() == (PROJECTION_NEAR )) &&
911− (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM ))
912+ (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM ))
912913 )
913914 {
914915 if (getVertex(2) == that.getVertex(3) && getVertex(3) == that.getVertex(0)) {
@@ -924,7 +925,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 9 unmodified lines
924925 // NEAR/BOTTOM & NEAR
925926 if (
926927 (that.getProjectionType() == (PROJECTION_NEAR )) &&
927− (getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM ))
928+ (getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM ))
928929 )
929930 {
930931 if (getVertex(3) == that.getVertex(2) && getVertex(0) == that.getVertex(3)) {
@@ -941,7 +942,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 10 unmodified lines
941942 // NEAR/RIGHT & NEAR
942943 if (
943944 (getProjectionType() == (PROJECTION_NEAR )) &&
944− (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT ))
945+ (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT ))
945946 )
946947 {
947948 if (getVertex(0) == that.getVertex(1) && getVertex(3) == that.getVertex(4)) {
@@ -957,7 +958,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 9 unmodified lines
957958 // NEAR/RIGHT & NEAR
958959 if (
959960 (that.getProjectionType() == (PROJECTION_NEAR )) &&
960− (getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT ))
961+ (getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT ))
961962 )
962963 {
963964 if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) {
@@ -974,7 +975,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 10 unmodified lines
974975 // NEAR/LEFT & NEAR
975976 if (
976977 (getProjectionType() == (PROJECTION_NEAR )) &&
977− (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT ))
978+ (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT ))
978979 )
979980 {
980981 if (getVertex(1) == that.getVertex(1) && getVertex(2) == that.getVertex(4)) {
@@ -991,7 +992,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 10 unmodified lines
991992 // NEAR/LEFT & NEAR
992993 if (
993994 (that.getProjectionType() == (PROJECTION_NEAR )) &&
994− (getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT ))
995+ (getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT ))
995996 )
996997 {
997998 if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) {
@@ -1096,7 +1097,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 98 unmodified lines
10961097 // NEAR/LEFT/BOTTOM & NEAR/BOTTOM
10971098 if (
10981099 ((that.getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) &&
1099− (getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR | PROJECTION_LEFT )))
1100+ (getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR | PROJECTION_LEFT )))
11001101 )
11011102 {
11021103 if (getVertex(0) == that.getVertex(2) && getVertex(4) == that.getVertex(4)) {
@@ -1118,7 +1119,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 15 unmodified lines
11181119 // LEFT/NEAR/BOTTOM
11191120 // LEFT/NEAR/TOP
11201121 if (
1121− (getProjectionType() == that.getProjectionType()) &&
1122+ (getProjectionType() == that.getProjectionType()) &&
11221123 (
11231124 getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM ) ||
11241125 getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP ) ||
libraries/octree/src/OctreeSceneStats.cpp+3−3
@@ -707,8 +707,8 @@ const char* OctreeSceneStats::getItemValue(Item item) { · 706 unmodified lines
707707 float elapsedAverage = _elapsedAverage.getAverage();
708708 calcAverageFPS = (float)USECS_PER_SECOND / (float)elapsedAverage;
709709
710− sprintf(_itemValueBuffer, "%llu usecs (%d fps) Average: %.0f usecs (%d fps)",
711− (long long unsigned int)_elapsed, calcFPS, elapsedAverage, calcAverageFPS);
710+ sprintf(_itemValueBuffer, "%llu usecs (%d fps) Average: %.0f usecs (%d fps)",
711+ (long long unsigned int)_elapsed, calcFPS, (double)elapsedAverage, calcAverageFPS);
712712 break;
713713 }
714714 case ITEM_ENCODE:
@@ -733,7 +733,7 @@ const char* OctreeSceneStats::getItemValue(Item item) { · 18 unmodified lines
733733 float calculatedBPV = total == 0 ? 0 : (_bytes * 8) / total;
734734 float averageBPV = _bitsPerOctreeAverage.getAverage();
735735 sprintf(_itemValueBuffer, "%lu (%.2f bits/octree Average: %.2f bits/octree) %lu internal %lu leaves",
736− total, calculatedBPV, averageBPV,
736+ total, (double)calculatedBPV, (double)averageBPV,
737737 (long unsigned int)_existsInPacketBitsWritten,
738738 (long unsigned int)_colorSent);
739739 break;
libraries/octree/src/Plane.cpp+2−1
@@ -66,5 +66,6 @@ float Plane::distance(const glm::vec3 &point) const { · 65 unmodified lines
6666
6767 void Plane::print() const {
6868 qCDebug(octree, "Plane - point (x=%f y=%f z=%f) normal (x=%f y=%f z=%f) d=%f",
69− _point.x, _point.y, _point.z, _normal.x, _normal.y, _normal.z, _dCoefficient);
69+ (double)_point.x, (double)_point.y, (double)_point.z,
70+ (double)_normal.x, (double)_normal.y, (double)_normal.z, (double)_dCoefficient);
7071 }
libraries/octree/src/ViewFrustum.cpp+57−55
@@ -65,9 +65,10 @@ void ViewFrustum::setProjection(const glm::mat4& projection) { · 64 unmodified lines
6565 _farClip = -_corners[BOTTOM_LEFT_FAR].z;
6666 _aspectRatio = (_corners[TOP_RIGHT_NEAR].x - _corners[BOTTOM_LEFT_NEAR].x) /
6767 (_corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_LEFT_NEAR].y);
68− glm::vec3 right = glm::normalize(glm::vec3(_corners[TOP_RIGHT_NEAR]));
69− glm::vec3 left = glm::normalize(glm::vec3(_corners[TOP_LEFT_NEAR]));
70− _fieldOfView = abs(glm::degrees(glm::angle(right, left)));
68+
69+ glm::vec4 top = _inverseProjection * vec4(0, 1, -1, 1);
70+ top /= top.w;
71+ _fieldOfView = abs(glm::degrees(2.0f * abs(glm::angle(vec3(0, 0, -1), glm::normalize(vec3(top))))));
7172 }
7273
7374 // ViewFrustum::calculateViewFrustum()
@@ -387,36 +388,36 @@ bool ViewFrustum::matches(const ViewFrustum& compareTo, bool debug) const { · 313 unmodified lines
387388 if (!result && debug) {
388389 qCDebug(octree, "ViewFrustum::matches()... result=%s", debug::valueOf(result));
389390 qCDebug(octree, "%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f",
390− (testMatches(compareTo._position,_position) ? "MATCHES " : "NO MATCH"),
391− compareTo._position.x, compareTo._position.y, compareTo._position.z,
392− _position.x, _position.y, _position.z );
391+ (testMatches(compareTo._position,_position) ? "MATCHES " : "NO MATCH"),
392+ (double)compareTo._position.x, (double)compareTo._position.y, (double)compareTo._position.z,
393+ (double)_position.x, (double)_position.y, (double)_position.z);
393394 qCDebug(octree, "%s -- compareTo._direction=%f,%f,%f _direction=%f,%f,%f",
394− (testMatches(compareTo._direction, _direction) ? "MATCHES " : "NO MATCH"),
395− compareTo._direction.x, compareTo._direction.y, compareTo._direction.z,
396− _direction.x, _direction.y, _direction.z );
395+ (testMatches(compareTo._direction, _direction) ? "MATCHES " : "NO MATCH"),
396+ (double)compareTo._direction.x, (double)compareTo._direction.y, (double)compareTo._direction.z,
397+ (double)_direction.x, (double)_direction.y, (double)_direction.z );
397398 qCDebug(octree, "%s -- compareTo._up=%f,%f,%f _up=%f,%f,%f",
398− (testMatches(compareTo._up, _up) ? "MATCHES " : "NO MATCH"),
399− compareTo._up.x, compareTo._up.y, compareTo._up.z,
400− _up.x, _up.y, _up.z );
399+ (testMatches(compareTo._up, _up) ? "MATCHES " : "NO MATCH"),
400+ (double)compareTo._up.x, (double)compareTo._up.y, (double)compareTo._up.z,
401+ (double)_up.x, (double)_up.y, (double)_up.z );
401402 qCDebug(octree, "%s -- compareTo._right=%f,%f,%f _right=%f,%f,%f",
402− (testMatches(compareTo._right, _right) ? "MATCHES " : "NO MATCH"),
403− compareTo._right.x, compareTo._right.y, compareTo._right.z,
404− _right.x, _right.y, _right.z );
403+ (testMatches(compareTo._right, _right) ? "MATCHES " : "NO MATCH"),
404+ (double)compareTo._right.x, (double)compareTo._right.y, (double)compareTo._right.z,
405+ (double)_right.x, (double)_right.y, (double)_right.z );
405406 qCDebug(octree, "%s -- compareTo._fieldOfView=%f _fieldOfView=%f",
406− (testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"),
407− compareTo._fieldOfView, _fieldOfView);
407+ (testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"),
408+ (double)compareTo._fieldOfView, (double)_fieldOfView);
408409 qCDebug(octree, "%s -- compareTo._aspectRatio=%f _aspectRatio=%f",
409− (testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"),
410− compareTo._aspectRatio, _aspectRatio);
410+ (testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"),
411+ (double)compareTo._aspectRatio, (double)_aspectRatio);
411412 qCDebug(octree, "%s -- compareTo._nearClip=%f _nearClip=%f",
412− (testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"),
413− compareTo._nearClip, _nearClip);
413+ (testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"),
414+ (double)compareTo._nearClip, (double)_nearClip);
414415 qCDebug(octree, "%s -- compareTo._farClip=%f _farClip=%f",
415− (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"),
416− compareTo._farClip, _farClip);
416+ (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"),
417+ (double)compareTo._farClip, (double)_farClip);
417418 qCDebug(octree, "%s -- compareTo._focalLength=%f _focalLength=%f",
418− (testMatches(compareTo._focalLength, _focalLength) ? "MATCHES " : "NO MATCH"),
419− compareTo._focalLength, _focalLength);
419+ (testMatches(compareTo._focalLength, _focalLength) ? "MATCHES " : "NO MATCH"),
420+ (double)compareTo._focalLength, (double)_focalLength);
420421 }
421422 return result;
422423 }
@@ -448,33 +449,34 @@ bool ViewFrustum::isVerySimilar(const ViewFrustum& compareTo, bool debug) const · 25 unmodified lines
448449 if (!result && debug) {
449450 qCDebug(octree, "ViewFrustum::isVerySimilar()... result=%s\n", debug::valueOf(result));
450451 qCDebug(octree, "%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f",
451− (testMatches(compareTo._position,_position, POSITION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"),
452− compareTo._position.x, compareTo._position.y, compareTo._position.z,
453− _position.x, _position.y, _position.z );
452+ (testMatches(compareTo._position,_position, POSITION_SIMILAR_ENOUGH) ?
453+ "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"),
454+ (double)compareTo._position.x, (double)compareTo._position.y, (double)compareTo._position.z,
455+ (double)_position.x, (double)_position.y, (double)_position.z );
454456
455457 qCDebug(octree, "%s -- positionDistance=%f",
456− (testMatches(0,positionDistance, POSITION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"),
457− positionDistance);
458+ (testMatches(0,positionDistance, POSITION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"),
459+ (double)positionDistance);
458460
459461 qCDebug(octree, "%s -- angleOrientation=%f",
460− (testMatches(0, angleOrientation, ORIENTATION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"),
461− angleOrientation);
462−
462+ (testMatches(0, angleOrientation, ORIENTATION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"),
463+ (double)angleOrientation);
464+
463465 qCDebug(octree, "%s -- compareTo._fieldOfView=%f _fieldOfView=%f",
464− (testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"),
465− compareTo._fieldOfView, _fieldOfView);
466+ (testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"),
467+ (double)compareTo._fieldOfView, (double)_fieldOfView);
466468 qCDebug(octree, "%s -- compareTo._aspectRatio=%f _aspectRatio=%f",
467− (testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"),
468− compareTo._aspectRatio, _aspectRatio);
469+ (testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"),
470+ (double)compareTo._aspectRatio, (double)_aspectRatio);
469471 qCDebug(octree, "%s -- compareTo._nearClip=%f _nearClip=%f",
470− (testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"),
471− compareTo._nearClip, _nearClip);
472+ (testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"),
473+ (double)compareTo._nearClip, (double)_nearClip);
472474 qCDebug(octree, "%s -- compareTo._farClip=%f _farClip=%f",
473− (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"),
474− compareTo._farClip, _farClip);
475+ (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"),
476+ (double)compareTo._farClip, (double)_farClip);
475477 qCDebug(octree, "%s -- compareTo._focalLength=%f _focalLength=%f",
476− (testMatches(compareTo._focalLength, _focalLength) ? "MATCHES " : "NO MATCH"),
477− compareTo._focalLength, _focalLength);
478+ (testMatches(compareTo._focalLength, _focalLength) ? "MATCHES " : "NO MATCH"),
479+ (double)compareTo._focalLength, (double)_focalLength);
478480 }
479481 return result;
480482 }
@@ -531,23 +533,23 @@ void ViewFrustum::computeOffAxisFrustum(float& left, float& right, float& bottom · 50 unmodified lines
531533
532534 void ViewFrustum::printDebugDetails() const {
533535 qCDebug(octree, "ViewFrustum::printDebugDetails()...");
534− qCDebug(octree, "_position=%f,%f,%f", _position.x, _position.y, _position.z );
535− qCDebug(octree, "_direction=%f,%f,%f", _direction.x, _direction.y, _direction.z );
536− qCDebug(octree, "_up=%f,%f,%f", _up.x, _up.y, _up.z );
537− qCDebug(octree, "_right=%f,%f,%f", _right.x, _right.y, _right.z );
538− qCDebug(octree, "_fieldOfView=%f", _fieldOfView);
539− qCDebug(octree, "_aspectRatio=%f", _aspectRatio);
540− qCDebug(octree, "_keyHoleRadius=%f", _keyholeRadius);
541− qCDebug(octree, "_nearClip=%f", _nearClip);
542− qCDebug(octree, "_farClip=%f", _farClip);
543− qCDebug(octree, "_focalLength=%f", _focalLength);
536+ qCDebug(octree, "_position=%f,%f,%f", (double)_position.x, (double)_position.y, (double)_position.z );
537+ qCDebug(octree, "_direction=%f,%f,%f", (double)_direction.x, (double)_direction.y, (double)_direction.z );
538+ qCDebug(octree, "_up=%f,%f,%f", (double)_up.x, (double)_up.y, (double)_up.z );
539+ qCDebug(octree, "_right=%f,%f,%f", (double)_right.x, (double)_right.y, (double)_right.z );
540+ qCDebug(octree, "_fieldOfView=%f", (double)_fieldOfView);
541+ qCDebug(octree, "_aspectRatio=%f", (double)_aspectRatio);
542+ qCDebug(octree, "_keyHoleRadius=%f", (double)_keyholeRadius);
543+ qCDebug(octree, "_nearClip=%f", (double)_nearClip);
544+ qCDebug(octree, "_farClip=%f", (double)_farClip);
545+ qCDebug(octree, "_focalLength=%f", (double)_focalLength);
544546 }
545547
546548 glm::vec2 ViewFrustum::projectPoint(glm::vec3 point, bool& pointInView) const {
547549
548− glm::vec4 pointVec4 = glm::vec4(point,1);
550+ glm::vec4 pointVec4 = glm::vec4(point, 1.0f);
549551 glm::vec4 projectedPointVec4 = _ourModelViewProjectionMatrix * pointVec4;
550− pointInView = (projectedPointVec4.w > 0); // math! If the w result is negative then the point is behind the viewer
552+ pointInView = (projectedPointVec4.w > 0.0f); // math! If the w result is negative then the point is behind the viewer
551553
552554 // what happens with w is 0???
553555 float x = projectedPointVec4.x / projectedPointVec4.w;
libraries/physics/src/EntityMotionState.cpp+2−2
@@ -245,7 +245,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { · 244 unmodified lines
245245
246246 float dx2 = glm::distance2(position, _serverPosition);
247247
248− const float MAX_POSITION_ERROR_SQUARED = 0.001f; // 0.001 m^2 ~~> 0.03 m
248+ const float MAX_POSITION_ERROR_SQUARED = 0.000004f; // Sqrt() - corresponds to 2 millimeters
249249 if (dx2 > MAX_POSITION_ERROR_SQUARED) {
250250
251251 #ifdef WANT_DEBUG
@@ -270,7 +270,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { · 18 unmodified lines
270270 _serverRotation = glm::normalize(computeBulletRotationStep(_serverAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP) * _serverRotation);
271271 }
272272 }
273− const float MIN_ROTATION_DOT = 0.99f; // 0.99 dot threshold coresponds to about 16 degrees of slop
273+ const float MIN_ROTATION_DOT = 0.99999f; // This corresponds to about 0.5 degrees of rotation
274274 glm::quat actualRotation = bulletToGLM(worldTrans.getRotation());
275275
276276 #ifdef WANT_DEBUG
libraries/physics/src/MeshMassProperties.cpp+4−0
@@ -270,7 +270,9 @@ void MeshMassProperties::computeMassProperties(const VectorOfPoints& points, con · 269 unmodified lines
270270 }
271271
272272 // create some variables to hold temporary results
273+ #ifndef NDEBUG
273274 uint32_t numPoints = points.size();
275+ #endif
274276 const btVector3 p0(0.0f, 0.0f, 0.0f);
275277 btMatrix3x3 tetraInertia;
276278 btMatrix3x3 doubleDebugInertia;
@@ -281,9 +283,11 @@ void MeshMassProperties::computeMassProperties(const VectorOfPoints& points, con · 4 unmodified lines
281283 uint32_t numTriangles = triangleIndices.size() / 3;
282284 for (uint32_t i = 0; i < numTriangles; ++i) {
283285 uint32_t t = 3 * i;
286+ #ifndef NDEBUG
284287 assert(triangleIndices[t] < numPoints);
285288 assert(triangleIndices[t + 1] < numPoints);
286289 assert(triangleIndices[t + 2] < numPoints);
290+ #endif
287291
288292 // extract raw vertices
289293 tetraPoints[0] = p0;
libraries/physics/src/ObjectAction.cpp+1−1
@@ -28,7 +28,7 @@ void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar delta · 27 unmodified lines
2828 return;
2929 }
3030 if (!_ownerEntity) {
31− qDebug() << "ObjectActionPullToPoint::updateAction no owner entity";
31+ qDebug() << "ObjectAction::updateAction no owner entity";
3232 return;
3333 }
3434 updateActionWorker(deltaTimeStep);
libraries/physics/src/ObjectAction.h+1−0
@@ -59,6 +59,7 @@ protected: · 58 unmodified lines
5959
6060 bool tryLockForRead() { return _lock.tryLockForRead(); }
6161 void lockForWrite() { _lock.lockForWrite(); }
62+ bool tryLockForWrite() { return _lock.tryLockForWrite(); }
6263 void unlock() { _lock.unlock(); }
6364
6465 bool _active;
libraries/physics/src/ObjectActionOffset.cpp+109−0
@@ -0,0 +1,109 @@
1+//
2+// ObjectActionOffset.cpp
3+// libraries/physics/src
4+//
5+// Created by Seth Alves 2015-6-17
6+// Copyright 2015 High Fidelity, Inc.
7+//
8+// Distributed under the Apache License, Version 2.0.
9+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10+//
11+
12+#include "ObjectActionOffset.h"
13+
14+ObjectActionOffset::ObjectActionOffset(QUuid id, EntityItemPointer ownerEntity) :
15+ ObjectAction(id, ownerEntity) {
16+ #if WANT_DEBUG
17+ qDebug() << "ObjectActionOffset::ObjectActionOffset";
18+ #endif
19+}
20+
21+ObjectActionOffset::~ObjectActionOffset() {
22+ #if WANT_DEBUG
23+ qDebug() << "ObjectActionOffset::~ObjectActionOffset";
24+ #endif
25+}
26+
27+void ObjectActionOffset::updateActionWorker(btScalar deltaTimeStep) {
28+ if (!tryLockForRead()) {
29+ // don't risk hanging the thread running the physics simulation
30+ return;
31+ }
32+
33+ void* physicsInfo = _ownerEntity->getPhysicsInfo();
34+ if (!physicsInfo) {
35+ unlock();
36+ return;
37+ }
38+ ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
39+ btRigidBody* rigidBody = motionState->getRigidBody();
40+ if (!rigidBody) {
41+ unlock();
42+ qDebug() << "ObjectActionOffset::updateActionWorker no rigidBody";
43+ return;
44+ }
45+
46+ if (_positionalTargetSet) {
47+ glm::vec3 offset = _pointToOffsetFrom - bulletToGLM(rigidBody->getCenterOfMassPosition());
48+ float offsetLength = glm::length(offset);
49+ float offsetError = _linearDistance - offsetLength;
50+
51+ // if (glm::abs(offsetError) > IGNORE_POSITION_DELTA) {
52+ if (glm::abs(offsetError) > 0.0f) {
53+ float offsetErrorAbs = glm::abs(offsetError);
54+ float offsetErrorDirection = - offsetError / offsetErrorAbs;
55+ glm::vec3 previousVelocity = bulletToGLM(rigidBody->getLinearVelocity());
56+
57+ glm::vec3 velocityAdjustment = glm::normalize(offset) * offsetErrorDirection * offsetErrorAbs / _linearTimeScale;
58+ rigidBody->setLinearVelocity(glmToBullet(previousVelocity + velocityAdjustment));
59+ // rigidBody->setLinearVelocity(glmToBullet(velocityAdjustment));
60+ rigidBody->activate();
61+ }
62+ }
63+
64+ unlock();
65+}
66+
67+
68+bool ObjectActionOffset::updateArguments(QVariantMap arguments) {
69+ bool pOk0 = true;
70+ glm::vec3 pointToOffsetFrom =
71+ EntityActionInterface::extractVec3Argument("offset action", arguments, "pointToOffsetFrom", pOk0, true);
72+
73+ bool pOk1 = true;
74+ float linearTimeScale =
75+ EntityActionInterface::extractFloatArgument("offset action", arguments, "linearTimeScale", pOk1, false);
76+
77+ bool pOk2 = true;
78+ float linearDistance =
79+ EntityActionInterface::extractFloatArgument("offset action", arguments, "linearDistance", pOk2, false);
80+
81+ if (!pOk0) {
82+ return false;
83+ }
84+ if (pOk1 && linearTimeScale <= 0.0f) {
85+ qDebug() << "offset action -- linearTimeScale must be greater than zero.";
86+ return false;
87+ }
88+
89+ lockForWrite();
90+
91+ _pointToOffsetFrom = pointToOffsetFrom;
92+ _positionalTargetSet = true;
93+
94+ if (pOk1) {
95+ _linearTimeScale = linearTimeScale;
96+ } else {
97+ _linearTimeScale = 0.1f;
98+ }
99+
100+ if (pOk2) {
101+ _linearDistance = linearDistance;
102+ } else {
103+ _linearDistance = 1.0f;
104+ }
105+
106+ _active = true;
107+ unlock();
108+ return true;
109+}
libraries/physics/src/ObjectActionOffset.h+35−0
@@ -0,0 +1,35 @@
1+//
2+// ObjectActionOffset.h
3+// libraries/physics/src
4+//
5+// Created by Seth Alves 2015-6-17
6+// Copyright 2015 High Fidelity, Inc.
7+//
8+// Distributed under the Apache License, Version 2.0.
9+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10+//
11+
12+#ifndef hifi_ObjectActionOffset_h
13+#define hifi_ObjectActionOffset_h
14+
15+#include <QUuid>
16+
17+#include <EntityItem.h>
18+#include "ObjectAction.h"
19+
20+class ObjectActionOffset : public ObjectAction {
21+public:
22+ ObjectActionOffset(QUuid id, EntityItemPointer ownerEntity);
23+ virtual ~ObjectActionOffset();
24+
25+ virtual bool updateArguments(QVariantMap arguments);
26+ virtual void updateActionWorker(float deltaTimeStep);
27+
28+private:
29+ glm::vec3 _pointToOffsetFrom;
30+ float _linearDistance;
31+ float _linearTimeScale;
32+ bool _positionalTargetSet;
33+};
34+
35+#endif // hifi_ObjectActionOffset_h
libraries/physics/src/ObjectActionPullToPoint.cpp+0−72
@@ -1,72 +0,0 @@
1−//
2−// ObjectActionPullToPoint.cpp
3−// libraries/physics/src
4−//
5−// Created by Seth Alves 2015-6-2
6−// Copyright 2015 High Fidelity, Inc.
7−//
8−// Distributed under the Apache License, Version 2.0.
9−// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10−//
11−
12−#include "ObjectActionPullToPoint.h"
13−
14−ObjectActionPullToPoint::ObjectActionPullToPoint(QUuid id, EntityItemPointer ownerEntity) :
15− ObjectAction(id, ownerEntity) {
16− #if WANT_DEBUG
17− qDebug() << "ObjectActionPullToPoint::ObjectActionPullToPoint";
18− #endif
19−}
20−
21−ObjectActionPullToPoint::~ObjectActionPullToPoint() {
22− #if WANT_DEBUG
23− qDebug() << "ObjectActionPullToPoint::~ObjectActionPullToPoint";
24− #endif
25−}
26−
27−void ObjectActionPullToPoint::updateActionWorker(btScalar deltaTimeStep) {
28− if (!tryLockForRead()) {
29− // don't risk hanging the thread running the physics simulation
30− return;
31− }
32−
33− void* physicsInfo = _ownerEntity->getPhysicsInfo();
34− if (!physicsInfo) {
35− unlock();
36− return;
37− }
38− ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
39− btRigidBody* rigidBody = motionState->getRigidBody();
40− if (!rigidBody) {
41− unlock();
42− return;
43− }
44−
45− glm::vec3 offset = _target - bulletToGLM(rigidBody->getCenterOfMassPosition());
46− float offsetLength = glm::length(offset);
47− if (offsetLength > IGNORE_POSITION_DELTA) {
48− glm::vec3 newVelocity = glm::normalize(offset) * _speed;
49− rigidBody->setLinearVelocity(glmToBullet(newVelocity));
50− rigidBody->activate();
51− } else {
52− rigidBody->setLinearVelocity(glmToBullet(glm::vec3()));
53− }
54−
55− unlock();
56−}
57−
58−
59−bool ObjectActionPullToPoint::updateArguments(QVariantMap arguments) {
60− bool ok = true;
61− glm::vec3 target = EntityActionInterface::extractVec3Argument("pull-to-point action", arguments, "target", ok);
62− float speed = EntityActionInterface::extractFloatArgument("pull-to-point action", arguments, "speed", ok);
63− if (ok) {
64− lockForWrite();
65− _target = target;
66− _speed = speed;
67− _active = true;
68− unlock();
69− return true;
70− }
71− return false;
72−}
libraries/physics/src/ObjectActionPullToPoint.h+0−34
@@ -1,34 +0,0 @@
1−//
2−// ObjectActionPullToPoint.h
3−// libraries/physics/src
4−//
5−// Created by Seth Alves 2015-6-3
6−// Copyright 2015 High Fidelity, Inc.
7−//
8−// Distributed under the Apache License, Version 2.0.
9−// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10−//
11−
12−#ifndef hifi_ObjectActionPullToPoint_h
13−#define hifi_ObjectActionPullToPoint_h
14−
15−#include <QUuid>
16−
17−#include <EntityItem.h>
18−#include "ObjectAction.h"
19−
20−class ObjectActionPullToPoint : public ObjectAction {
21−public:
22− ObjectActionPullToPoint(QUuid id, EntityItemPointer ownerEntity);
23− virtual ~ObjectActionPullToPoint();
24−
25− virtual bool updateArguments(QVariantMap arguments);
26− virtual void updateActionWorker(float deltaTimeStep);
27−
28−private:
29−
30− glm::vec3 _target;
31− float _speed;
32−};
33−
34−#endif // hifi_ObjectActionPullToPoint_h
libraries/render-utils/CMakeLists.txt+37−27
@@ -1,27 +1,37 @@
1−set(TARGET_NAME render-utils)
2−
3−AUTOSCRIBE_SHADER_LIB(gpu model render)
4−
5−# pull in the resources.qrc file
6−qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc")
7−
8−# use setup_hifi_library macro to setup our project and link appropriate Qt modules
9−setup_hifi_library(Widgets OpenGL Network Qml Quick Script)
10−
11−add_dependency_external_projects(glm)
12−find_package(GLM REQUIRED)
13−target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
14−
15−if (WIN32)
16− if (USE_NSIGHT)
17− # try to find the Nsight package and add it to the build if we find it
18− find_package(NSIGHT)
19− if (NSIGHT_FOUND)
20− include_directories(${NSIGHT_INCLUDE_DIRS})
21− add_definitions(-DNSIGHT_FOUND)
22− target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}")
23− endif ()
24− endif()
25−endif (WIN32)
26−
27−link_hifi_libraries(animation fbx shared gpu model render)
1+set(TARGET_NAME render-utils)
2+
3+AUTOSCRIBE_SHADER_LIB(gpu model render)
4+
5+# pull in the resources.qrc file
6+qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc")
7+
8+# use setup_hifi_library macro to setup our project and link appropriate Qt modules
9+setup_hifi_library(Widgets OpenGL Network Qml Quick Script)
10+
11+setup_hifi_opengl()
12+
13+add_dependency_external_projects(glm)
14+find_package(GLM REQUIRED)
15+target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
16+
17+if (WIN32)
18+ if (USE_NSIGHT)
19+ # try to find the Nsight package and add it to the build if we find it
20+ find_package(NSIGHT)
21+ if (NSIGHT_FOUND)
22+ include_directories(${NSIGHT_INCLUDE_DIRS})
23+ add_definitions(-DNSIGHT_FOUND)
24+ target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}")
25+ endif ()
26+ endif()
27+
28+ add_dependency_external_projects(boostconfig)
29+ find_package(BoostConfig REQUIRED)
30+ target_include_directories(${TARGET_NAME} PUBLIC ${BOOSTCONFIG_INCLUDE_DIRS})
31+
32+ add_dependency_external_projects(oglplus)
33+ find_package(OGLPLUS REQUIRED)
34+ target_include_directories(${TARGET_NAME} PUBLIC ${OGLPLUS_INCLUDE_DIRS})
35+endif (WIN32)
36+
37+link_hifi_libraries(animation fbx shared gpu model render)
libraries/render-utils/src/DeferredLightingEffect.cpp+25−6
@@ -61,15 +61,26 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { · 60 unmodified lines
6161 gpu::Shader::BindingSet slotBindings;
6262 gpu::Shader::makeProgram(*program, slotBindings);
6363 gpu::Shader::makeProgram(*programTextured, slotBindings);
64−
64+
6565 gpu::StatePointer state = gpu::StatePointer(new gpu::State());
6666 state->setCullMode(gpu::State::CULL_BACK);
6767 state->setDepthTest(true, true, gpu::LESS_EQUAL);
6868 state->setBlendFunction(false,
6969 gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
7070 gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
71+
72+
73+ gpu::StatePointer stateCullNone = gpu::StatePointer(new gpu::State());
74+ stateCullNone->setCullMode(gpu::State::CULL_NONE);
75+ stateCullNone->setDepthTest(true, true, gpu::LESS_EQUAL);
76+ stateCullNone->setBlendFunction(false,
77+ gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
78+ gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
79+
7180 _simpleProgram = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
81+ _simpleProgramCullNone = gpu::PipelinePointer(gpu::Pipeline::create(program, stateCullNone));
7282 _simpleProgramTextured = gpu::PipelinePointer(gpu::Pipeline::create(programTextured, state));
83+ _simpleProgramTexturedCullNone = gpu::PipelinePointer(gpu::Pipeline::create(programTextured, stateCullNone));
7384
7485 _viewState = viewState;
7586 loadLightProgram(directional_light_frag, false, _directionalLight, _directionalLightLocations);
@@ -106,13 +117,21 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { · 30 unmodified lines
106117 lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET));
107118 }
108119
109−void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured) {
120+void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled) {
110121 // DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(batch, true, true, true);
111122
112123 if (textured) {
113− batch.setPipeline(_simpleProgramTextured);
124+ if (culled) {
125+ batch.setPipeline(_simpleProgramTextured);
126+ } else {
127+ batch.setPipeline(_simpleProgramTexturedCullNone);
128+ }
114129 } else {
115− batch.setPipeline(_simpleProgram);
130+ if (culled) {
131+ batch.setPipeline(_simpleProgram);
132+ } else {
133+ batch.setPipeline(_simpleProgramCullNone);
134+ }
116135 }
117136 }
118137
@@ -191,7 +210,7 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu · 72 unmodified lines
191210 }
192211 }
193212
194−void DeferredLightingEffect::prepare() {
213+void DeferredLightingEffect::prepare(RenderArgs* args) {
195214 // clear the normal and specular buffers
196215 auto textureCache = DependencyManager::get<TextureCache>();
197216 textureCache->setPrimaryDrawBuffers(false, true, false);
@@ -205,7 +224,7 @@ void DeferredLightingEffect::prepare() { · 7 unmodified lines
205224 textureCache->setPrimaryDrawBuffers(true, false, false);
206225 }
207226
208−void DeferredLightingEffect::render() {
227+void DeferredLightingEffect::render(RenderArgs* args) {
209228 // perform deferred lighting, rendering to free fbo
210229 glDisable(GL_BLEND);
211230 glDisable(GL_LIGHTING);
libraries/render-utils/src/DeferredLightingEffect.h+5−3
@@ -34,7 +34,7 @@ public: · 33 unmodified lines
3434 void init(AbstractViewStateInterface* viewState);
3535
3636 /// Sets up the state necessary to render static untextured geometry with the simple program.
37− void bindSimpleProgram(gpu::Batch& batch, bool textured = false);
37+ void bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true);
3838
3939 /// Tears down the state necessary to render static untextured geometry with the simple program.
4040 void releaseSimpleProgram(gpu::Batch& batch);
@@ -66,8 +66,8 @@ public: · 25 unmodified lines
6666 void addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f),
6767 float intensity = 0.5f, const glm::quat& orientation = glm::quat(), float exponent = 0.0f, float cutoff = PI);
6868
69− void prepare();
70− void render();
69+ void prepare(RenderArgs* args);
70+ void render(RenderArgs* args);
7171 void copyBack(RenderArgs* args);
7272
7373 void setupTransparent(RenderArgs* args, int lightBufferUnit);
@@ -100,7 +100,9 @@ private: · 26 unmodified lines
100100 static void loadLightProgram(const char* fragSource, bool limited, ProgramObject& program, LightLocations& locations);
101101
102102 gpu::PipelinePointer _simpleProgram;
103+ gpu::PipelinePointer _simpleProgramCullNone;
103104 gpu::PipelinePointer _simpleProgramTextured;
105+ gpu::PipelinePointer _simpleProgramTexturedCullNone;
104106
105107 ProgramObject _directionalSkyboxLight;
106108 LightLocations _directionalSkyboxLightLocations;
libraries/render-utils/src/GeometryCache.cpp+82−39
@@ -28,6 +28,9 @@ · 27 unmodified lines
2828 #include "RenderUtilsLogging.h"
2929 #include "GeometryCache.h"
3030
31+#include "standardTransformPNTC_vert.h"
32+#include "standardDrawTexture_frag.h"
33+
3134 //#define WANT_DEBUG
3235
3336 const int GeometryCache::UNKNOWN_ID = -1;
@@ -1025,13 +1028,13 @@ void GeometryCache::renderBevelCornersRect(gpu::Batch& batch, int x, int y, int · 991 unmodified lines
10251028 #endif // def WANT_DEBUG
10261029 }
10271030
1028− const int FLOATS_PER_VERTEX = 2; // vertices
1029− const int vertices = 8;
1030−
10311031 if (!details.isCreated) {
1032−
1032+ static const int FLOATS_PER_VERTEX = 2; // vertices
1033+ static const int NUM_VERTICES = 8;
1034+ static const int NUM_FLOATS = NUM_VERTICES * FLOATS_PER_VERTEX;
1035+
10331036 details.isCreated = true;
1034− details.vertices = vertices;
1037+ details.vertices = NUM_VERTICES;
10351038 details.vertexSize = FLOATS_PER_VERTEX;
10361039
10371040 gpu::BufferPointer verticesBuffer(new gpu::Buffer());
@@ -1044,62 +1047,65 @@ void GeometryCache::renderBevelCornersRect(gpu::Batch& batch, int x, int y, int · 6 unmodified lines
10441047 details.streamFormat = streamFormat;
10451048 details.stream = stream;
10461049
1047− details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0);
1050+ details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ));
10481051 details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA));
10491052
10501053 details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride);
10511054 details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride);
10521055
10531056
1054− int vertexPoints = vertices * FLOATS_PER_VERTEX;
1055− GLfloat* vertexBuffer = new GLfloat[vertexPoints]; // only vertices, no normals because we're a 2D quad
1056− GLfloat* vertex = vertexBuffer;
1057+ GLfloat vertexBuffer[NUM_FLOATS]; // only vertices, no normals because we're a 2D quad
10571058 int vertexPoint = 0;
10581059
1059− // left side
1060− vertex[vertexPoint++] = x;
1061− vertex[vertexPoint++] = y + bevelDistance;
1060+ // Triangle strip points
1061+ // 3 ------ 5
1062+ // / \
1063+ // 1 7
1064+ // | |
1065+ // 2 8
1066+ // \ /
1067+ // 4 ------ 6
10621068
1063− vertex[vertexPoint++] = x;
1064− vertex[vertexPoint++] = y + height - bevelDistance;
1065−
1066− // top side
1067− vertex[vertexPoint++] = x + bevelDistance;
1068− vertex[vertexPoint++] = y + height;
1069+ // 1
1070+ vertexBuffer[vertexPoint++] = x;
1071+ vertexBuffer[vertexPoint++] = y + height - bevelDistance;
1072+ // 2
1073+ vertexBuffer[vertexPoint++] = x;
1074+ vertexBuffer[vertexPoint++] = y + bevelDistance;
1075+ // 3
1076+ vertexBuffer[vertexPoint++] = x + bevelDistance;
1077+ vertexBuffer[vertexPoint++] = y + height;
1078+ // 4
1079+ vertexBuffer[vertexPoint++] = x + bevelDistance;
1080+ vertexBuffer[vertexPoint++] = y;
1081+ // 5
1082+ vertexBuffer[vertexPoint++] = x + width - bevelDistance;
1083+ vertexBuffer[vertexPoint++] = y + height;
1084+ // 6
1085+ vertexBuffer[vertexPoint++] = x + width - bevelDistance;
1086+ vertexBuffer[vertexPoint++] = y;
1087+ // 7
1088+ vertexBuffer[vertexPoint++] = x + width;
1089+ vertexBuffer[vertexPoint++] = y + height - bevelDistance;
1090+ // 8
1091+ vertexBuffer[vertexPoint++] = x + width;
1092+ vertexBuffer[vertexPoint++] = y + bevelDistance;
10691093
1070− vertex[vertexPoint++] = x + width - bevelDistance;
1071− vertex[vertexPoint++] = y + height;
1072−
1073− // right
1074− vertex[vertexPoint++] = x + width;
1075− vertex[vertexPoint++] = y + height - bevelDistance;
1076− vertex[vertexPoint++] = x + width;
1077− vertex[vertexPoint++] = y + bevelDistance;
1078−
1079− // bottom
1080− vertex[vertexPoint++] = x + width - bevelDistance;
1081− vertex[vertexPoint++] = y;
1082− vertex[vertexPoint++] = x +bevelDistance;
1083− vertex[vertexPoint++] = y;
1084−
1085− const int NUM_COLOR_SCALARS_PER_QUAD = 8;
10861094 int compactColor = ((int(color.x * 255.0f) & 0xFF)) |
10871095 ((int(color.y * 255.0f) & 0xFF) << 8) |
10881096 ((int(color.z * 255.0f) & 0xFF) << 16) |
10891097 ((int(color.w * 255.0f) & 0xFF) << 24);
1090− int colors[NUM_COLOR_SCALARS_PER_QUAD] = { compactColor, compactColor, compactColor, compactColor,
1091− compactColor, compactColor, compactColor, compactColor };
1098+ int colors[NUM_VERTICES] = { compactColor, compactColor, compactColor, compactColor,
1099+ compactColor, compactColor, compactColor, compactColor };
10921100
10931101
10941102 details.verticesBuffer->append(sizeof(vertexBuffer), (gpu::Byte*) vertexBuffer);
10951103 details.colorBuffer->append(sizeof(colors), (gpu::Byte*) colors);
1096−
1097− delete[] vertexBuffer;
10981104 }
10991105
11001106 batch.setInputFormat(details.streamFormat);
11011107 batch.setInputStream(0, *details.stream);
1102− batch.draw(gpu::QUADS, 4, 0);
1108+ batch.draw(gpu::TRIANGLE_STRIP, details.vertices, 0);
11031109 }
11041110
11051111 void GeometryCache::renderQuad(const glm::vec2& minCorner, const glm::vec2& maxCorner, const glm::vec4& color, int id) {
@@ -1179,6 +1185,26 @@ void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, co · 73 unmodified lines
11791185 batch.draw(gpu::QUADS, 4, 0);
11801186 }
11811187
1188+void GeometryCache::renderUnitCube(gpu::Batch& batch) {
1189+ static const glm::vec4 color(1);
1190+ renderSolidCube(batch, 1, color);
1191+}
1192+
1193+void GeometryCache::renderUnitQuad(const glm::vec4& color, int id) {
1194+ gpu::Batch batch;
1195+ renderUnitQuad(batch, color, id);
1196+ gpu::GLBackend::renderBatch(batch);
1197+}
1198+
1199+void GeometryCache::renderUnitQuad(gpu::Batch& batch, const glm::vec4& color, int id) {
1200+ static const glm::vec2 topLeft(-1, 1);
1201+ static const glm::vec2 bottomRight(1, -1);
1202+ static const glm::vec2 texCoordTopLeft(0.0f, 1.0f);
1203+ static const glm::vec2 texCoordBottomRight(1.0f, 0.0f);
1204+ renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color, id);
1205+}
1206+
1207+
11821208 void GeometryCache::renderQuad(const glm::vec2& minCorner, const glm::vec2& maxCorner,
11831209 const glm::vec2& texCoordMinCorner, const glm::vec2& texCoordMaxCorner,
11841210 const glm::vec4& color, int id) {
@@ -1802,6 +1828,23 @@ QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url, const QS · 617 unmodified lines
18021828 return geometry.staticCast<Resource>();
18031829 }
18041830
1831+void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch) {
1832+ if (!_standardDrawPipeline) {
1833+ auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)));
1834+ auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(standardDrawTexture_frag)));
1835+ auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
1836+ gpu::Shader::makeProgram((*program));
1837+
1838+ auto state = gpu::StatePointer(new gpu::State());
1839+
1840+ // enable decal blend
1841+ state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
1842+
1843+ _standardDrawPipeline.reset(gpu::Pipeline::create(program, state));
1844+ }
1845+ batch.setPipeline(_standardDrawPipeline);
1846+}
1847+
18051848 const float NetworkGeometry::NO_HYSTERESIS = -1.0f;
18061849
18071850 NetworkGeometry::NetworkGeometry(const QUrl& url, const QSharedPointer<NetworkGeometry>& fallback, bool delayLoad,
libraries/render-utils/src/GeometryCache.h+9−1
@@ -155,6 +155,10 @@ public: · 154 unmodified lines
155155 void renderBevelCornersRect(int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID);
156156 void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID);
157157
158+ void renderUnitCube(gpu::Batch& batch);
159+ void renderUnitQuad(const glm::vec4& color = glm::vec4(1), int id = UNKNOWN_ID);
160+ void renderUnitQuad(gpu::Batch& batch, const glm::vec4& color = glm::vec4(1), int id = UNKNOWN_ID);
161+
158162 void renderQuad(int x, int y, int width, int height, const glm::vec4& color, int id = UNKNOWN_ID)
159163 { renderQuad(glm::vec2(x,y), glm::vec2(x + width, y + height), color, id); }
160164 void renderQuad(gpu::Batch& batch, int x, int y, int width, int height, const glm::vec4& color, int id = UNKNOWN_ID)
@@ -249,6 +253,9 @@ public: · 88 unmodified lines
249253 /// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested
250254 QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false);
251255
256+ /// Set a batch to the simple pipeline, returning the previous pipeline
257+ void useSimpleDrawPipeline(gpu::Batch& batch);
258+
252259 protected:
253260
254261 virtual QSharedPointer<Resource> createResource(const QUrl& url,
@@ -266,6 +273,7 @@ private: · 11 unmodified lines
266273 int vertexSize;
267274 };
268275
276+ gpu::PipelinePointer _standardDrawPipeline;
269277 QHash<float, gpu::BufferPointer> _cubeVerticies;
270278 QHash<Vec2Pair, gpu::BufferPointer> _cubeColors;
271279 gpu::BufferPointer _wireCubeIndexBuffer;
@@ -273,7 +281,7 @@ private: · 1 unmodified line
273281 QHash<float, gpu::BufferPointer> _solidCubeVertices;
274282 QHash<Vec2Pair, gpu::BufferPointer> _solidCubeColors;
275283 gpu::BufferPointer _solidCubeIndexBuffer;
276−
284+
277285 class BatchItemDetails {
278286 public:
279287 static int population;
libraries/render-utils/src/Model.cpp+10−5
@@ -545,11 +545,6 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g · 544 unmodified lines
545545 // we can use the AABox's ray intersection by mapping our origin and direction into the model frame
546546 // and testing intersection there.
547547 if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face)) {
548−
549− if (!_calculatedMeshBoxesValid) {
550− recalculateMeshBoxes(pickAgainstTriangles);
551− }
552−
553548 float bestDistance = std::numeric_limits<float>::max();
554549
555550 float distanceToSubMesh;
@@ -560,6 +555,11 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g · 4 unmodified lines
560555
561556 // If we hit the models box, then consider the submeshes...
562557 _mutex.lock();
558+
559+ if (!_calculatedMeshBoxesValid) {
560+ recalculateMeshBoxes(pickAgainstTriangles);
561+ }
562+
563563 foreach(const AABox& subMeshBox, _calculatedMeshBoxes) {
564564
565565 if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace)) {
@@ -1804,13 +1804,16 @@ AABox Model::getPartBounds(int meshIndex, int partIndex) { · 1238 unmodified lines
18041804 }
18051805
18061806 void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent) {
1807+ PerformanceTimer perfTimer("Model::renderPart");
18071808 if (!_readyWhenAdded) {
18081809 return; // bail asap
18091810 }
18101811
18111812 // We need to make sure we have valid offsets calculated before we can render
18121813 if (!_calculatedMeshPartOffsetValid) {
1814+ _mutex.lock();
18131815 recalculateMeshPartOffsets();
1816+ _mutex.unlock();
18141817 }
18151818 auto textureCache = DependencyManager::get<TextureCache>();
18161819
@@ -2018,7 +2021,9 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran · 201 unmodified lines
20182021 }
20192022 }
20202023
2024+ _mutex.lock();
20212025 qint64 offset = _calculatedMeshPartOffset[QPair<int,int>(meshIndex, partIndex)];
2026+ _mutex.unlock();
20222027
20232028 if (part.quadIndices.size() > 0) {
20242029 batch.drawIndexed(gpu::QUADS, part.quadIndices.size(), offset);
libraries/render-utils/src/OffscreenQmlSurface.cpp+6−2
@@ -11,6 +11,9 @@ · 10 unmodified lines
1111 #include <QOpenGLDebugLogger>
1212 #include <QGLWidget>
1313 #include <QtQml>
14+
15+#include <PerfStat.h>
16+
1417 #include "AbstractViewStateInterface.h"
1518
1619 Q_DECLARE_LOGGING_CATEGORY(offscreenFocus)
@@ -91,6 +94,7 @@ void OffscreenQmlSurface::resize(const QSize& newSize) { · 74 unmodified lines
9194 // Qt bug in 5.4 forces this check of pixel ratio,
9295 // even though we're rendering offscreen.
9396 qreal pixelRatio = 1.0;
97+ _qmlEngine->rootContext()->setContextProperty("surfaceSize", newSize);
9498 if (_renderControl && _renderControl->_renderWindow) {
9599 pixelRatio = _renderControl->_renderWindow->devicePixelRatio();
96100 } else {
@@ -111,7 +115,6 @@ void OffscreenQmlSurface::resize(const QSize& newSize) { · 14 unmodified lines
111115 _quickWindow->contentItem()->setSize(newSize);
112116 }
113117
114−
115118 // Update our members
116119 if (_rootItem) {
117120 _rootItem->setSize(newSize);
@@ -212,6 +215,7 @@ QObject* OffscreenQmlSurface::finishQmlLoad(std::function<void(QQmlContext*, QOb · 94 unmodified lines
212215
213216
214217 void OffscreenQmlSurface::updateQuick() {
218+ PerformanceTimer perfTimer("qmlUpdate");
215219 if (_paused) {
216220 return;
217221 }
@@ -376,4 +380,4 @@ void OffscreenQmlSurface::setProxyWindow(QWindow* window) { · 158 unmodified lines
376380
377381 QQuickWindow* OffscreenQmlSurface::getWindow() {
378382 return _quickWindow;
379−}
383+}
libraries/render-utils/src/OglplusHelpers.cpp+325−0
@@ -0,0 +1,325 @@
1+#ifdef Q_OS_WIN
2+
3+//
4+// Created by Bradley Austin Davis on 2015/05/29
5+// Copyright 2015 High Fidelity, Inc.
6+//
7+// Distributed under the Apache License, Version 2.0.
8+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
9+//
10+#include "OglplusHelpers.h"
11+
12+using namespace oglplus;
13+using namespace oglplus::shapes;
14+
15+static const char * SIMPLE_TEXTURED_VS = R"VS(#version 410 core
16+#pragma line __LINE__
17+
18+uniform mat4 Projection = mat4(1);
19+uniform mat4 ModelView = mat4(1);
20+
21+layout(location = 0) in vec3 Position;
22+layout(location = 1) in vec2 TexCoord;
23+
24+out vec2 vTexCoord;
25+
26+void main() {
27+ gl_Position = Projection * ModelView * vec4(Position, 1);
28+ vTexCoord = TexCoord;
29+}
30+
31+)VS";
32+
33+static const char * SIMPLE_TEXTURED_FS = R"FS(#version 410 core
34+#pragma line __LINE__
35+
36+uniform sampler2D sampler;
37+uniform float Alpha = 1.0;
38+
39+in vec2 vTexCoord;
40+out vec4 vFragColor;
41+
42+void main() {
43+ vec4 c = texture(sampler, vTexCoord);
44+ c.a = min(Alpha, c.a);
45+ vFragColor = c;
46+}
47+
48+)FS";
49+
50+
51+ProgramPtr loadDefaultShader() {
52+ ProgramPtr result;
53+ compileProgram(result, SIMPLE_TEXTURED_VS, SIMPLE_TEXTURED_FS);
54+ return result;
55+}
56+
57+void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs) {
58+ using namespace oglplus;
59+ try {
60+ result = ProgramPtr(new Program());
61+ // attach the shaders to the program
62+ result->AttachShader(
63+ VertexShader()
64+ .Source(GLSLSource(vs))
65+ .Compile()
66+ );
67+ result->AttachShader(
68+ FragmentShader()
69+ .Source(GLSLSource(fs))
70+ .Compile()
71+ );
72+ result->Link();
73+ } catch (ProgramBuildError & err) {
74+ Q_UNUSED(err);
75+ Q_ASSERT_X(false, "compileProgram", "Failed to build shader program");
76+ qFatal((const char*)err.Message);
77+ result.reset();
78+ }
79+}
80+
81+
82+ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect) {
83+ using namespace oglplus;
84+ Vec3f a(1, 0, 0);
85+ Vec3f b(0, 1, 0);
86+ if (aspect > 1) {
87+ b[1] /= aspect;
88+ } else {
89+ a[0] *= aspect;
90+ }
91+ return ShapeWrapperPtr(
92+ new shapes::ShapeWrapper({ "Position", "TexCoord" }, shapes::Plane(a, b), *program)
93+ );
94+}
95+
96+// Return a point's cartesian coordinates on a sphere from pitch and yaw
97+static glm::vec3 getPoint(float yaw, float pitch) {
98+ return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)),
99+ glm::sin(-pitch),
100+ glm::cos(-pitch) * (-glm::cos(yaw)));
101+}
102+
103+
104+class SphereSection : public DrawingInstructionWriter, public DrawMode {
105+public:
106+ using IndexArray = std::vector<GLuint>;
107+ using PosArray = std::vector<float>;
108+ using TexArray = std::vector<float>;
109+ /// The type of the index container returned by Indices()
110+ // vertex positions
111+ PosArray _pos_data;
112+ // vertex tex coords
113+ TexArray _tex_data;
114+ IndexArray _idx_data;
115+ unsigned int _prim_count{ 0 };
116+
117+public:
118+ SphereSection(
119+ const float fov,
120+ const float aspectRatio,
121+ const int slices_,
122+ const int stacks_) {
123+ //UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm
124+ if (fov >= PI) {
125+ qDebug() << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues";
126+ }
127+
128+ int gridSize = std::max(slices_, stacks_);
129+ int gridSizeLog2 = 1;
130+ while (1 << gridSizeLog2 < gridSize) {
131+ ++gridSizeLog2;
132+ }
133+ gridSize = (1 << gridSizeLog2) + 1;
134+ // Compute number of vertices needed
135+ int vertices = gridSize * gridSize;
136+ _pos_data.resize(vertices * 3);
137+ _tex_data.resize(vertices * 2);
138+
139+ // Compute vertices positions and texture UV coordinate
140+ for (int y = 0; y <= gridSize; ++y) {
141+ for (int x = 0; x <= gridSize; ++x) {
142+
143+ }
144+ }
145+ for (int i = 0; i < gridSize; i++) {
146+ float stacksRatio = (float)i / (float)(gridSize - 1); // First stack is 0.0f, last stack is 1.0f
147+ // abs(theta) <= fov / 2.0f
148+ float pitch = -fov * (stacksRatio - 0.5f);
149+ for (int j = 0; j < gridSize; j++) {
150+ float slicesRatio = (float)j / (float)(gridSize - 1); // First slice is 0.0f, last slice is 1.0f
151+ // abs(phi) <= fov * aspectRatio / 2.0f
152+ float yaw = -fov * aspectRatio * (slicesRatio - 0.5f);
153+ int vertex = i * gridSize + j;
154+ int posOffset = vertex * 3;
155+ int texOffset = vertex * 2;
156+ vec3 pos = getPoint(yaw, pitch);
157+ _pos_data[posOffset] = pos.x;
158+ _pos_data[posOffset + 1] = pos.y;
159+ _pos_data[posOffset + 2] = pos.z;
160+ _tex_data[texOffset] = slicesRatio;
161+ _tex_data[texOffset + 1] = stacksRatio;
162+ }
163+ } // done with vertices
164+
165+ int rowLen = gridSize;
166+
167+ // gridsize now refers to the triangles, not the vertices, so reduce by one
168+ // or die by fencepost error http://en.wikipedia.org/wiki/Off-by-one_error
169+ --gridSize;
170+ int quads = gridSize * gridSize;
171+ for (int t = 0; t < quads; ++t) {
172+ int x =
173+ ((t & 0x0001) >> 0) |
174+ ((t & 0x0004) >> 1) |
175+ ((t & 0x0010) >> 2) |
176+ ((t & 0x0040) >> 3) |
177+ ((t & 0x0100) >> 4) |
178+ ((t & 0x0400) >> 5) |
179+ ((t & 0x1000) >> 6) |
180+ ((t & 0x4000) >> 7);
181+ int y =
182+ ((t & 0x0002) >> 1) |
183+ ((t & 0x0008) >> 2) |
184+ ((t & 0x0020) >> 3) |
185+ ((t & 0x0080) >> 4) |
186+ ((t & 0x0200) >> 5) |
187+ ((t & 0x0800) >> 6) |
188+ ((t & 0x2000) >> 7) |
189+ ((t & 0x8000) >> 8);
190+ int i = x * (rowLen) + y;
191+
192+ _idx_data.push_back(i);
193+ _idx_data.push_back(i + 1);
194+ _idx_data.push_back(i + rowLen + 1);
195+
196+ _idx_data.push_back(i + rowLen + 1);
197+ _idx_data.push_back(i + rowLen);
198+ _idx_data.push_back(i);
199+ }
200+ _prim_count = quads * 2;
201+ }
202+
203+ /// Returns the winding direction of faces
204+ FaceOrientation FaceWinding(void) const {
205+ return FaceOrientation::CCW;
206+ }
207+
208+ typedef GLuint(SphereSection::*VertexAttribFunc)(std::vector<GLfloat>&) const;
209+
210+ /// Makes the vertex positions and returns the number of values per vertex
211+ template <typename T>
212+ GLuint Positions(std::vector<T>& dest) const {
213+ dest.clear();
214+ dest.insert(dest.begin(), _pos_data.begin(), _pos_data.end());
215+ return 3;
216+ }
217+
218+ /// Makes the vertex normals and returns the number of values per vertex
219+ template <typename T>
220+ GLuint Normals(std::vector<T>& dest) const {
221+ dest.clear();
222+ return 3;
223+ }
224+
225+ /// Makes the vertex tangents and returns the number of values per vertex
226+ template <typename T>
227+ GLuint Tangents(std::vector<T>& dest) const {
228+ dest.clear();
229+ return 3;
230+ }
231+
232+ /// Makes the vertex bi-tangents and returns the number of values per vertex
233+ template <typename T>
234+ GLuint Bitangents(std::vector<T>& dest) const {
235+ dest.clear();
236+ return 3;
237+ }
238+
239+ /// Makes the texture coordinates returns the number of values per vertex
240+ template <typename T>
241+ GLuint TexCoordinates(std::vector<T>& dest) const {
242+ dest.clear();
243+ dest.insert(dest.begin(), _tex_data.begin(), _tex_data.end());
244+ return 2;
245+ }
246+
247+ typedef VertexAttribsInfo<
248+ SphereSection,
249+ std::tuple<
250+ VertexPositionsTag,
251+ VertexNormalsTag,
252+ VertexTangentsTag,
253+ VertexBitangentsTag,
254+ VertexTexCoordinatesTag
255+ >
256+ > VertexAttribs;
257+
258+ Spheref MakeBoundingSphere(void) const {
259+ GLfloat min_x = _pos_data[3], max_x = _pos_data[3];
260+ GLfloat min_y = _pos_data[4], max_y = _pos_data[4];
261+ GLfloat min_z = _pos_data[5], max_z = _pos_data[5];
262+ for (std::size_t v = 0, vn = _pos_data.size() / 3; v != vn; ++v) {
263+ GLfloat x = _pos_data[v * 3 + 0];
264+ GLfloat y = _pos_data[v * 3 + 1];
265+ GLfloat z = _pos_data[v * 3 + 2];
266+
267+ if (min_x > x) min_x = x;
268+ if (min_y > y) min_y = y;
269+ if (min_z > z) min_z = z;
270+ if (max_x < x) max_x = x;
271+ if (max_y < y) max_y = y;
272+ if (max_z < z) max_z = z;
273+ }
274+
275+ Vec3f c(
276+ (min_x + max_x) * 0.5f,
277+ (min_y + max_y) * 0.5f,
278+ (min_z + max_z) * 0.5f
279+ );
280+
281+ return Spheref(
282+ c.x(), c.y(), c.z(),
283+ Distance(c, Vec3f(min_x, min_y, min_z))
284+ );
285+ }
286+
287+ /// Queries the bounding sphere coordinates and dimensions
288+ template <typename T>
289+ void BoundingSphere(oglplus::Sphere<T>& bounding_sphere) const {
290+ bounding_sphere = oglplus::Sphere<T>(MakeBoundingSphere());
291+ }
292+
293+
294+ /// Returns element indices that are used with the drawing instructions
295+ const IndexArray & Indices(Default = Default()) const {
296+ return _idx_data;
297+ }
298+
299+ /// Returns the instructions for rendering of faces
300+ DrawingInstructions Instructions(PrimitiveType primitive) const {
301+ DrawingInstructions instr = this->MakeInstructions();
302+ DrawOperation operation;
303+ operation.method = DrawOperation::Method::DrawElements;
304+ operation.mode = primitive;
305+ operation.first = 0;
306+ operation.count = _prim_count * 3;
307+ operation.restart_index = DrawOperation::NoRestartIndex();
308+ operation.phase = 0;
309+ this->AddInstruction(instr, operation);
310+ return std::move(instr);
311+ }
312+
313+ /// Returns the instructions for rendering of faces
314+ DrawingInstructions Instructions(Default = Default()) const {
315+ return Instructions(PrimitiveType::Triangles);
316+ }
317+};
318+
319+ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov, float aspect, int slices, int stacks) {
320+ using namespace oglplus;
321+ return ShapeWrapperPtr(
322+ new shapes::ShapeWrapper({ "Position", "TexCoord" }, SphereSection(fov, aspect, slices, stacks), *program)
323+ );
324+}
325+#endif
libraries/render-utils/src/OglplusHelpers.h+173−0
@@ -0,0 +1,173 @@
1+//
2+// Created by Bradley Austin Davis on 2015/05/26
3+// Copyright 2015 High Fidelity, Inc.
4+//
5+// Distributed under the Apache License, Version 2.0.
6+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
7+//
8+#pragma once
9+
10+// FIXME support oglplus on all platforms
11+// For now it's a convenient helper for Windows
12+
13+#include <QtGlobal>
14+
15+#ifdef Q_OS_WIN
16+#include "GLMHelpers.h"
17+
18+#define OGLPLUS_USE_GLCOREARB_H 0
19+
20+#if defined(__APPLE__)
21+
22+#define OGLPLUS_USE_GL3_H 1
23+
24+#elif defined(WIN32)
25+
26+#define OGLPLUS_USE_GLEW 1
27+#pragma warning(disable : 4068)
28+
29+#elif defined(ANDROID)
30+
31+#else
32+
33+#define OGLPLUS_USE_GLCOREARB_H 1
34+
35+#endif
36+
37+
38+
39+#define OGLPLUS_USE_BOOST_CONFIG 1
40+#define OGLPLUS_NO_SITE_CONFIG 1
41+#define OGLPLUS_LOW_PROFILE 1
42+#include <oglplus/gl.hpp>
43+
44+#include <oglplus/all.hpp>
45+#include <oglplus/interop/glm.hpp>
46+#include <oglplus/bound/texture.hpp>
47+#include <oglplus/bound/framebuffer.hpp>
48+#include <oglplus/bound/renderbuffer.hpp>
49+#include <oglplus/shapes/wrapper.hpp>
50+#include <oglplus/shapes/plane.hpp>
51+
52+#include "NumericalConstants.h"
53+
54+using FramebufferPtr = std::shared_ptr<oglplus::Framebuffer>;
55+using ShapeWrapperPtr = std::shared_ptr<oglplus::shapes::ShapeWrapper>;
56+using BufferPtr = std::shared_ptr<oglplus::Buffer>;
57+using VertexArrayPtr = std::shared_ptr<oglplus::VertexArray>;
58+using ProgramPtr = std::shared_ptr<oglplus::Program>;
59+using Mat4Uniform = oglplus::Uniform<mat4>;
60+
61+ProgramPtr loadDefaultShader();
62+void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs);
63+ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect = 1.0f);
64+ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov = PI / 3.0f * 2.0f, float aspect = 16.0f / 9.0f, int slices = 32, int stacks = 32);
65+
66+
67+// A basic wrapper for constructing a framebuffer with a renderbuffer
68+// for the depth attachment and an undefined type for the color attachement
69+// This allows us to reuse the basic framebuffer code for both the Mirror
70+// FBO as well as the Oculus swap textures we will use to render the scene
71+// Though we don't really need depth at all for the mirror FBO, or even an
72+// FBO, but using one means I can just use a glBlitFramebuffer to get it onto
73+// the screen.
74+template <
75+ typename C,
76+ typename D
77+>
78+struct FramebufferWrapper {
79+ uvec2 size;
80+ oglplus::Framebuffer fbo;
81+ C color;
82+ D depth;
83+
84+ FramebufferWrapper() {}
85+
86+ virtual ~FramebufferWrapper() {
87+ }
88+
89+ virtual void Init(const uvec2 & size) {
90+ this->size = size;
91+ initColor();
92+ initDepth();
93+ initDone();
94+ }
95+
96+ template <typename F>
97+ void Bound(F f) {
98+ Bound(oglplus::Framebuffer::Target::Draw, f);
99+ }
100+
101+ template <typename F>
102+ void Bound(oglplus::Framebuffer::Target target , F f) {
103+ fbo.Bind(target);
104+ onBind(target);
105+ f();
106+ onUnbind(target);
107+ oglplus::DefaultFramebuffer().Bind(target);
108+ }
109+
110+ void Viewport() {
111+ oglplus::Context::Viewport(size.x, size.y);
112+ }
113+
114+protected:
115+ virtual void onBind(oglplus::Framebuffer::Target target) {}
116+ virtual void onUnbind(oglplus::Framebuffer::Target target) {}
117+
118+ static GLenum toEnum(oglplus::Framebuffer::Target target) {
119+ switch (target) {
120+ case oglplus::Framebuffer::Target::Draw:
121+ return GL_DRAW_FRAMEBUFFER;
122+ case oglplus::Framebuffer::Target::Read:
123+ return GL_READ_FRAMEBUFFER;
124+ default:
125+ Q_ASSERT(false);
126+ return GL_FRAMEBUFFER;
127+ }
128+ }
129+
130+ virtual void initDepth() {}
131+
132+ virtual void initColor() {}
133+
134+ virtual void initDone() = 0;
135+};
136+
137+struct BasicFramebufferWrapper : public FramebufferWrapper <oglplus::Texture, oglplus::Renderbuffer> {
138+protected:
139+ virtual void initDepth() override {
140+ using namespace oglplus;
141+ Context::Bound(Renderbuffer::Target::Renderbuffer, depth)
142+ .Storage(
143+ PixelDataInternalFormat::DepthComponent,
144+ size.x, size.y);
145+ }
146+
147+ virtual void initColor() override {
148+ using namespace oglplus;
149+ Context::Bound(oglplus::Texture::Target::_2D, color)
150+ .MinFilter(TextureMinFilter::Linear)
151+ .MagFilter(TextureMagFilter::Linear)
152+ .WrapS(TextureWrap::ClampToEdge)
153+ .WrapT(TextureWrap::ClampToEdge)
154+ .Image2D(
155+ 0, PixelDataInternalFormat::RGBA8,
156+ size.x, size.y,
157+ 0, PixelDataFormat::RGB, PixelDataType::UnsignedByte, nullptr
158+ );
159+ }
160+
161+ virtual void initDone() override {
162+ using namespace oglplus;
163+ static const Framebuffer::Target target = Framebuffer::Target::Draw;
164+ Bound(target, [&] {
165+ fbo.AttachTexture(target, FramebufferAttachment::Color, color, 0);
166+ fbo.AttachRenderbuffer(target, FramebufferAttachment::Depth, depth);
167+ fbo.Complete(target);
168+ });
169+ }
170+};
171+
172+using BasicFramebufferWrapperPtr = std::shared_ptr<BasicFramebufferWrapper>;
173+#endif
libraries/render-utils/src/ProgramObject.h+12−3
@@ -12,22 +12,31 @@ · 11 unmodified lines
1212 #ifndef hifi_ProgramObject_h
1313 #define hifi_ProgramObject_h
1414
15+#ifdef __GNUC__
16+#pragma GCC diagnostic push
17+#pragma GCC diagnostic ignored "-Wdouble-promotion"
18+#endif
19+
1520 #include <QGLShaderProgram>
1621
22+#ifdef __GNUC__
23+#pragma GCC diagnostic pop
24+#endif
25+
1726 #include <glm/glm.hpp>
1827
1928 class ProgramObject : public QGLShaderProgram {
2029 public:
21−
30+
2231 ProgramObject(QObject* parent = 0);
23−
32+
2433 void setUniform(int location, const glm::vec2& value);
2534 void setUniform(const char* name, const glm::vec2& value);
2635 void setUniform(int location, const glm::vec3& value);
2736 void setUniform(const char* name, const glm::vec3& value);
2837 void setUniform(int location, const glm::vec4& value);
2938 void setUniform(const char* name, const glm::vec4& value);
30− void setUniformArray(const char* name, const glm::vec3* values, int count);
39+ void setUniformArray(const char* name, const glm::vec3* values, int count);
3140 };
3241
3342 #endif // hifi_ProgramObject_h
libraries/render-utils/src/RenderDeferredTask.cpp+114−176
@@ -19,42 +19,54 @@ · 18 unmodified lines
1919
2020 #include <PerfStat.h>
2121
22−#include "overlay3D_vert.h"
22+#include "overlay3D_vert.h"
2323 #include "overlay3D_frag.h"
2424
2525 using namespace render;
2626
27−template <> void render::jobRun(const PrepareDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
28− PerformanceTimer perfTimer("PrepareDeferred");
29− DependencyManager::get<DeferredLightingEffect>()->prepare();
27+void PrepareDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
28+ DependencyManager::get<DeferredLightingEffect>()->prepare(renderContext->args);
3029 }
3130
32−template <> void render::jobRun(const RenderDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
33− PerformanceTimer perfTimer("RenderDeferred");
34− DependencyManager::get<DeferredLightingEffect>()->render();
35−// renderContext->args->_context->syncCache();
31+void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
32+ DependencyManager::get<DeferredLightingEffect>()->render(renderContext->args);
3633 }
3734
38−template <> void render::jobRun(const ResolveDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
35+void ResolveDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
3936 PerformanceTimer perfTimer("ResolveDeferred");
4037 DependencyManager::get<DeferredLightingEffect>()->copyBack(renderContext->args);
41− renderContext->args->_context->syncCache();
42−
4338 }
4439
45−
46−
4740 RenderDeferredTask::RenderDeferredTask() : Task() {
48− _jobs.push_back(Job(PrepareDeferred()));
49− _jobs.push_back(Job(DrawBackground()));
50− _jobs.push_back(Job(DrawOpaqueDeferred()));
51− _jobs.push_back(Job(DrawLight()));
52− _jobs.push_back(Job(ResetGLState()));
53− _jobs.push_back(Job(RenderDeferred()));
54− _jobs.push_back(Job(ResolveDeferred()));
55− _jobs.push_back(Job(DrawTransparentDeferred()));
56− _jobs.push_back(Job(DrawOverlay3D()));
57− _jobs.push_back(Job(ResetGLState()));
41+ _jobs.push_back(Job(new PrepareDeferred::JobModel("PrepareDeferred")));
42+ _jobs.push_back(Job(new DrawBackground::JobModel("DrawBackground")));
43+ _jobs.push_back(Job(new FetchItems::JobModel("FetchOpaque",
44+ FetchItems(
45+ [] (const RenderContextPointer& context, int count) {
46+ context->_numFeedOpaqueItems = count;
47+ }
48+ )
49+ )));
50+ _jobs.push_back(Job(new CullItems::JobModel("CullOpaque", _jobs.back().getOutput())));
51+ _jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortOpaque", _jobs.back().getOutput())));
52+ _jobs.push_back(Job(new DrawOpaqueDeferred::JobModel("DrawOpaqueDeferred", _jobs.back().getOutput())));
53+ _jobs.push_back(Job(new DrawLight::JobModel("DrawLight")));
54+ _jobs.push_back(Job(new ResetGLState::JobModel()));
55+ _jobs.push_back(Job(new RenderDeferred::JobModel("RenderDeferred")));
56+ _jobs.push_back(Job(new ResolveDeferred::JobModel("ResolveDeferred")));
57+ _jobs.push_back(Job(new FetchItems::JobModel("FetchTransparent",
58+ FetchItems(
59+ ItemFilter::Builder::transparentShape().withoutLayered(),
60+ [] (const RenderContextPointer& context, int count) {
61+ context->_numFeedTransparentItems = count;
62+ }
63+ )
64+ )));
65+ _jobs.push_back(Job(new CullItems::JobModel("CullTransparent", _jobs.back().getOutput())));
66+ _jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false))));
67+ _jobs.push_back(Job(new DrawTransparentDeferred::JobModel("TransparentDeferred", _jobs.back().getOutput())));
68+ _jobs.push_back(Job(new DrawOverlay3D::JobModel("DrawOverlay3D")));
69+ _jobs.push_back(Job(new ResetGLState::JobModel()));
5870 }
5971
6072 RenderDeferredTask::~RenderDeferredTask() {
@@ -80,181 +92,104 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend · 19 unmodified lines
8092 }
8193 };
8294
83−
84−
85−template <> void render::jobRun(const DrawOpaqueDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
86− PerformanceTimer perfTimer("DrawOpaqueDeferred");
95+void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) {
8796 assert(renderContext->args);
8897 assert(renderContext->args->_viewFrustum);
8998
90− // render opaques
91− auto& scene = sceneContext->_scene;
92− auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape().withoutLayered());
93− auto& renderDetails = renderContext->args->_details;
94−
95− ItemIDsBounds inItems;
96− inItems.reserve(items.size());
97− for (auto id : items) {
98− inItems.emplace_back(ItemIDAndBounds(id));
99− }
100− ItemIDsBounds& renderedItems = inItems;
101−
102− renderContext->_numFeedOpaqueItems = renderedItems.size();
103−
104− ItemIDsBounds culledItems;
105− culledItems.reserve(inItems.size());
106− if (renderContext->_cullOpaque) {
107− renderDetails.pointTo(RenderDetails::OPAQUE_ITEM);
108− cullItems(sceneContext, renderContext, renderedItems, culledItems);
109− renderDetails.pointTo(RenderDetails::OTHER_ITEM);
110− renderedItems = culledItems;
111− }
112−
113− renderContext->_numDrawnOpaqueItems = renderedItems.size();
99+ RenderArgs* args = renderContext->args;
100+ gpu::Batch batch;
101+ args->_batch = &batch;
114102
103+ renderContext->_numDrawnOpaqueItems = inItems.size();
115104
116− ItemIDsBounds sortedItems;
117− sortedItems.reserve(culledItems.size());
118− if (renderContext->_sortOpaque) {
119− depthSortItems(sceneContext, renderContext, true, renderedItems, sortedItems); // Sort Front to back opaque items!
120− renderedItems = sortedItems;
105+ glm::mat4 projMat;
106+ Transform viewMat;
107+ args->_viewFrustum->evalProjectionMatrix(projMat);
108+ args->_viewFrustum->evalViewTransform(viewMat);
109+ if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
110+ viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
121111 }
112+ batch.setProjectionTransform(projMat);
113+ batch.setViewTransform(viewMat);
122114
123− // ItemIDsBounds sortedItems;
124− /* ItemMaterialBucketMap stateSortedItems;
125− stateSortedItems.allocateStandardMaterialBuckets();
126− if (true) {
127− for (auto& itemIDAndBound : renderedItems) {
128− stateSortedItems.insert(itemIDAndBound.id, scene->getItem(itemIDAndBound.id).getMaterialKey());
129− }
115+ {
116+ GLenum buffers[3];
117+ int bufferCount = 0;
118+ buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
119+ buffers[bufferCount++] = GL_COLOR_ATTACHMENT1;
120+ buffers[bufferCount++] = GL_COLOR_ATTACHMENT2;
121+ batch._glDrawBuffers(bufferCount, buffers);
122+ const float OPAQUE_ALPHA_THRESHOLD = 0.5f;
123+ args->_alphaThreshold = OPAQUE_ALPHA_THRESHOLD;
130124 }
131−*/
132−
133− if (renderContext->_renderOpaque) {
134− RenderArgs* args = renderContext->args;
135− gpu::Batch batch;
136− args->_batch = &batch;
137−
138− glm::mat4 projMat;
139− Transform viewMat;
140− args->_viewFrustum->evalProjectionMatrix(projMat);
141− args->_viewFrustum->evalViewTransform(viewMat);
142− if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
143− viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
144− }
145− batch.setProjectionTransform(projMat);
146− batch.setViewTransform(viewMat);
147−
148− {
149− GLenum buffers[3];
150− int bufferCount = 0;
151− buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
152− buffers[bufferCount++] = GL_COLOR_ATTACHMENT1;
153− buffers[bufferCount++] = GL_COLOR_ATTACHMENT2;
154− batch._glDrawBuffers(bufferCount, buffers);
155− }
156125
157− renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnOpaqueItems);
126+ renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnOpaqueItems);
158127
159− args->_context->render((*args->_batch));
160− args->_batch = nullptr;
161− }
128+ // Before rendering the batch make sure we re in sync with gl state
129+ args->_context->syncCache();
130+ renderContext->args->_context->syncCache();
131+ args->_context->render((*args->_batch));
132+ args->_batch = nullptr;
162133 }
163134
164−
165−template <> void render::jobRun(const DrawTransparentDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
166− PerformanceTimer perfTimer("DrawTransparentDeferred");
135+void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) {
167136 assert(renderContext->args);
168137 assert(renderContext->args->_viewFrustum);
169−
170− // render transparents
171− auto& scene = sceneContext->_scene;
172− auto& items = scene->getMasterBucket().at(ItemFilter::Builder::transparentShape().withoutLayered());
173138 auto& renderDetails = renderContext->args->_details;
174−
175− ItemIDsBounds inItems;
176− inItems.reserve(items.size());
177− for (auto id : items) {
178− inItems.push_back(id);
179− }
180− ItemIDsBounds& renderedItems = inItems;
181139
182− renderContext->_numFeedTransparentItems = renderedItems.size();
140+ RenderArgs* args = renderContext->args;
141+ gpu::Batch batch;
142+ args->_batch = &batch;
143+
144+ renderContext->_numDrawnTransparentItems = inItems.size();
183145
184− ItemIDsBounds culledItems;
185− if (renderContext->_cullTransparent) {
186− renderDetails.pointTo(RenderDetails::TRANSLUCENT_ITEM);
187− cullItems(sceneContext, renderContext, inItems, culledItems);
188− renderDetails.pointTo(RenderDetails::OTHER_ITEM);
189− renderedItems = culledItems;
146+ glm::mat4 projMat;
147+ Transform viewMat;
148+ args->_viewFrustum->evalProjectionMatrix(projMat);
149+ args->_viewFrustum->evalViewTransform(viewMat);
150+ if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
151+ viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
190152 }
153+ batch.setProjectionTransform(projMat);
154+ batch.setViewTransform(viewMat);
155+ const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f;
191156
192− renderContext->_numDrawnTransparentItems = renderedItems.size();
193−
194− ItemIDsBounds sortedItems;
195− if (renderContext->_sortTransparent) {
196− depthSortItems(sceneContext, renderContext, false, renderedItems, sortedItems); // Sort Back to front transparent items!
197− renderedItems = sortedItems;
157+ {
158+ GLenum buffers[3];
159+ int bufferCount = 0;
160+ buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
161+ batch._glDrawBuffers(bufferCount, buffers);
162+ args->_alphaThreshold = TRANSPARENT_ALPHA_THRESHOLD;
198163 }
164+
165+
166+ renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnTransparentItems);
167+
168+ // Before rendering the batch make sure we re in sync with gl state
169+ args->_context->syncCache();
170+ args->_context->render((*args->_batch));
171+ args->_batch = nullptr;
172+
173+ // reset blend function to standard...
174+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
175+}
199176
200− if (renderContext->_renderTransparent) {
201− RenderArgs* args = renderContext->args;
202− gpu::Batch batch;
203− args->_batch = &batch;
204−
177+const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() const {
178+ if (!_opaquePipeline) {
179+ auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(overlay3D_vert)));
180+ auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(overlay3D_frag)));
205181
182+ auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
206183
184+ auto state = gpu::StatePointer(new gpu::State());
185+ state->setDepthTest(true, true, gpu::LESS_EQUAL);
207186
208− glm::mat4 projMat;
209− Transform viewMat;
210− args->_viewFrustum->evalProjectionMatrix(projMat);
211− args->_viewFrustum->evalViewTransform(viewMat);
212− if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
213− viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
214− }
215− batch.setProjectionTransform(projMat);
216− batch.setViewTransform(viewMat);
217−
218− const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f;
219−
220− {
221− GLenum buffers[3];
222− int bufferCount = 0;
223− buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
224− batch._glDrawBuffers(bufferCount, buffers);
225− args->_alphaThreshold = TRANSPARENT_ALPHA_THRESHOLD;
226− }
227−
228−
229− renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnTransparentItems);
230−
231− // Before rendering the batch make sure we re in sync with gl state
232− args->_context->syncCache();
233− args->_context->render((*args->_batch));
234− args->_batch = nullptr;
235−
236− // reset blend function to standard...
237− // glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
187+ _opaquePipeline.reset(gpu::Pipeline::create(program, state));
238188 }
189+ return _opaquePipeline;
239190 }
240191
241−const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() const {
242− if (!_opaquePipeline) {
243− auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(overlay3D_vert)));
244− auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(overlay3D_frag)));
245−
246− auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
247−
248− auto state = gpu::StatePointer(new gpu::State());
249− state->setDepthTest(true, true, gpu::LESS_EQUAL);
250−
251− _opaquePipeline.reset(gpu::Pipeline::create(program, state));
252− }
253− return _opaquePipeline;
254−}
255−
256−template <> void render::jobRun(const DrawOverlay3D& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
257− PerformanceTimer perfTimer("DrawOverlay3D");
192+void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
258193 assert(renderContext->args);
259194 assert(renderContext->args->_viewFrustum);
260195
@@ -271,13 +206,14 @@ template <> void render::jobRun(const DrawOverlay3D& job, const SceneContextPoin · 10 unmodified lines
271206 inItems.emplace_back(id);
272207 }
273208 }
274−
209+ renderContext->_numFeedOverlay3DItems = inItems.size();
210+ renderContext->_numDrawnOverlay3DItems = inItems.size();
211+
275212 RenderArgs* args = renderContext->args;
276213 gpu::Batch batch;
277214 args->_batch = &batch;
278215 args->_whiteTexture = DependencyManager::get<TextureCache>()->getWhiteTexture();
279216
280−
281217 glm::mat4 projMat;
282218 Transform viewMat;
283219 args->_viewFrustum->evalProjectionMatrix(projMat);
@@ -287,12 +223,13 @@ template <> void render::jobRun(const DrawOverlay3D& job, const SceneContextPoin · 3 unmodified lines
287223 }
288224 batch.setProjectionTransform(projMat);
289225 batch.setViewTransform(viewMat);
290− batch.setPipeline(job.getOpaquePipeline());
226+
227+ batch.setPipeline(getOpaquePipeline());
291228 batch.setUniformTexture(0, args->_whiteTexture);
292229
293230 if (!inItems.empty()) {
294− batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0);
295− renderItems(sceneContext, renderContext, inItems);
231+ batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0);
232+ renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnOverlay3DItems);
296233 }
297234
298235 // Before rendering the batch make sure we re in sync with gl state
@@ -301,3 +238,4 @@ template <> void render::jobRun(const DrawOverlay3D& job, const SceneContextPoin · 2 unmodified lines
301238 args->_batch = nullptr;
302239 args->_whiteTexture.reset();
303240 }
241+
libraries/render-utils/src/RenderDeferredTask.h+25−24
@@ -18,48 +18,49 @@ · 17 unmodified lines
1818
1919 class PrepareDeferred {
2020 public:
21+ void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
22+
23+ typedef render::Job::Model<PrepareDeferred> JobModel;
2124 };
22−namespace render {
23−template <> void jobRun(const PrepareDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
24−}
25+
2526
2627 class RenderDeferred {
2728 public:
29+ void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
30+
31+ typedef render::Job::Model<RenderDeferred> JobModel;
2832 };
29−namespace render {
30−template <> void jobRun(const RenderDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
31−}
3233
3334 class ResolveDeferred {
3435 public:
35−};
36−namespace render {
37−template <> void jobRun(const ResolveDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
38−}
36+ void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
3937
38+ typedef render::Job::Model<ResolveDeferred> JobModel;
39+};
4040
4141 class DrawOpaqueDeferred {
4242 public:
43+ void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems);
44+
45+ typedef render::Job::ModelI<DrawOpaqueDeferred, render::ItemIDsBounds> JobModel;
4346 };
44−namespace render {
45−template <> void jobRun(const DrawOpaqueDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
46−}
4747
4848 class DrawTransparentDeferred {
4949 public:
50+ void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems);
51+
52+ typedef render::Job::ModelI<DrawTransparentDeferred, render::ItemIDsBounds> JobModel;
5053 };
51−namespace render {
52−template <> void jobRun(const DrawTransparentDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
53−}
54−
55−class DrawOverlay3D {
56− mutable gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable
57−public:
58− const gpu::PipelinePointer& getOpaquePipeline() const;
54+
55+class DrawOverlay3D {
56+ mutable gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable
57+public:
58+ const gpu::PipelinePointer& getOpaquePipeline() const;
59+
60+ void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
61+
62+ typedef render::Job::Model<DrawOverlay3D> JobModel;
5963 };
60−namespace render {
61−template <> void jobRun(const DrawOverlay3D& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
62−}
6364
6465 class RenderDeferredTask : public render::Task {
6566 public:
libraries/render-utils/src/TextRenderer.cpp+9−0
@@ -18,12 +18,21 @@ · 17 unmodified lines
1818 #include <QBuffer>
1919 #include <QFile>
2020
21+#ifdef __GNUC__
22+#pragma GCC diagnostic push
23+#pragma GCC diagnostic ignored "-Wdouble-promotion"
24+#endif
25+
2126 // FIXME, decouple from the GL headers
2227 #include <QOpenGLShaderProgram>
2328 #include <QOpenGLTexture>
2429 #include <QOpenGLVertexArrayObject>
2530 #include <QOpenGLBuffer>
2631
32+#ifdef __GNUC__
33+#pragma GCC diagnostic pop
34+#endif
35+
2736 #include <glm/glm.hpp>
2837 #include <glm/gtc/matrix_transform.hpp>
2938
libraries/render-utils/src/TextRenderer3D.cpp+14−28
@@ -30,11 +30,6 @@ · 29 unmodified lines
3030 #include "GeometryCache.h"
3131 #include "DeferredLightingEffect.h"
3232
33−// FIXME support the shadow effect, or remove it from the API
34−// FIXME figure out how to improve the anti-aliasing on the
35−// interior of the outline fonts
36−const float DEFAULT_POINT_SIZE = 12;
37−
3833 // Helper functions for reading binary data from an IO device
3934 template<class T>
4035 void readStream(QIODevice& in, T& t) {
@@ -117,7 +112,7 @@ public: · 76 unmodified lines
117112
118113 // Render string to batch
119114 void drawString(gpu::Batch& batch, float x, float y, const QString& str,
120− const glm::vec4& color, TextRenderer3D::EffectType effectType,
115+ const glm::vec4* color, TextRenderer3D::EffectType effectType,
121116 const glm::vec2& bound);
122117
123118 private:
@@ -367,7 +362,7 @@ void Font3D::setupGPU() { · 243 unmodified lines
367362 }
368363 }
369364
370−void Font3D::drawString(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4& color,
365+void Font3D::drawString(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4* color,
371366 TextRenderer3D::EffectType effectType, const glm::vec2& bounds) {
372367 if (str == "") {
373368 return;
@@ -429,40 +424,33 @@ void Font3D::drawString(gpu::Batch& batch, float x, float y, const QString& str, · 55 unmodified lines
429424 setupGPU();
430425 batch.setPipeline(_pipeline);
431426 batch.setUniformTexture(_fontLoc, _texture);
432− batch._glUniform1f(_outlineLoc, (effectType == TextRenderer3D::OUTLINE_EFFECT) ? 1.0f : 0.0f);
433− batch._glUniform4fv(_colorLoc, 1, (const GLfloat*)&color);
427+ batch._glUniform1i(_outlineLoc, (effectType == TextRenderer3D::OUTLINE_EFFECT));
428+ batch._glUniform4fv(_colorLoc, 1, (const GLfloat*)color);
434429
435430 batch.setInputFormat(_format);
436431 batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride);
437432 batch.draw(gpu::QUADS, _numVertices, 0);
438433 }
439434
440−TextRenderer3D* TextRenderer3D::getInstance(const char* family, float pointSize,
441− int weight, bool italic, EffectType effect, int effectThickness,
442− const QColor& color) {
443− if (pointSize < 0) {
444− pointSize = DEFAULT_POINT_SIZE;
445− }
446− return new TextRenderer3D(family, pointSize, weight, italic, effect,
447− effectThickness, color);
435+TextRenderer3D* TextRenderer3D::getInstance(const char* family,
436+ int weight, bool italic, EffectType effect, int effectThickness) {
437+ return new TextRenderer3D(family, weight, italic, effect, effectThickness);
448438 }
449439
450−TextRenderer3D::TextRenderer3D(const char* family, float pointSize, int weight, bool italic,
451− EffectType effect, int effectThickness, const QColor& color) :
440+TextRenderer3D::TextRenderer3D(const char* family, int weight, bool italic,
441+ EffectType effect, int effectThickness) :
452442 _effectType(effect),
453443 _effectThickness(effectThickness),
454− _pointSize(pointSize),
455− _color(toGlm(color)),
456444 _font(loadFont3D(family)) {
457445 if (!_font) {
458446 qWarning() << "Unable to load font with family " << family;
459447 _font = loadFont3D("Courier");
460448 }
461449 if (1 != _effectThickness) {
462− qWarning() << "Effect thickness not current supported";
450+ qWarning() << "Effect thickness not currently supported";
463451 }
464452 if (NO_EFFECT != _effectType && OUTLINE_EFFECT != _effectType) {
465− qWarning() << "Effect thickness not current supported";
453+ qWarning() << "Effect type not currently supported";
466454 }
467455 }
468456
@@ -487,11 +475,9 @@ void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const QString& st · 18 unmodified lines
487475 const glm::vec2& bounds) {
488476 // The font does all the OpenGL work
489477 if (_font) {
490− glm::vec4 actualColor(color);
491− if (actualColor.r < 0) {
492− actualColor = _color;
493− }
494− _font->drawString(batch, x, y, str, actualColor, _effectType, bounds);
478+ // Cache color so that the pointer stays valid.
479+ _color = color;
480+ _font->drawString(batch, x, y, str, &_color, _effectType, bounds);
495481 }
496482 }
497483
libraries/render-utils/src/TextRenderer3D.h+9−12
@@ -39,25 +39,24 @@ class Batch; · 38 unmodified lines
3939 class Font3D;
4040
4141 // TextRenderer3D is actually a fairly thin wrapper around a Font class
42−// defined in the cpp file.
42+// defined in the cpp file.
4343 class TextRenderer3D {
4444 public:
4545 enum EffectType { NO_EFFECT, SHADOW_EFFECT, OUTLINE_EFFECT };
4646
47− static TextRenderer3D* getInstance(const char* family, float pointSize = -1, int weight = -1, bool italic = false,
48− EffectType effect = NO_EFFECT, int effectThickness = 1, const QColor& color = QColor(255, 255, 255));
49−
47+ static TextRenderer3D* getInstance(const char* family, int weight = -1, bool italic = false,
48+ EffectType effect = NO_EFFECT, int effectThickness = 1);
5049 ~TextRenderer3D();
5150
5251 glm::vec2 computeExtent(const QString& str) const;
53− float getFontSize() const;
52+ float getFontSize() const; // Pixel size
5453
55− void draw(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4& color = glm::vec4(-1.0f),
56− const glm::vec2& bounds = glm::vec2(-1.0f));
54+ void draw(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4& color = glm::vec4(1.0f),
55+ const glm::vec2& bounds = glm::vec2(-1.0f));
5756
5857 private:
59− TextRenderer3D(const char* family, float pointSize = -1, int weight = -1, bool italic = false,
60− EffectType effect = NO_EFFECT, int effectThickness = 1, const QColor& color = QColor(255, 255, 255));
58+ TextRenderer3D(const char* family, int weight = -1, bool italic = false,
59+ EffectType effect = NO_EFFECT, int effectThickness = 1);
6160
6261 // the type of effect to apply
6362 const EffectType _effectType;
@@ -65,10 +64,8 @@ private: · 1 unmodified line
6564 // the thickness of the effect
6665 const int _effectThickness;
6766
68− const float _pointSize;
69−
7067 // text color
71− const glm::vec4 _color;
68+ glm::vec4 _color;
7269
7370 Font3D* _font;
7471 };
libraries/render-utils/src/sdf_text3D.slf+11−6
@@ -11,18 +11,21 @@ · 10 unmodified lines
1111 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
1212
1313 uniform sampler2D Font;
14−uniform float Outline;
14+uniform bool Outline;
1515 uniform vec4 Color;
1616
17−const float gamma = 2.6;
18−const float smoothing = 100.0;
17+// the interpolated normal
18+varying vec4 interpolatedNormal;
19+
20+const float gamma = 2.2;
21+const float smoothing = 64.0;
1922 const float interiorCutoff = 0.8;
2023 const float outlineExpansion = 0.2;
2124
2225 void main() {
2326 // retrieve signed distance
2427 float sdf = texture2D(Font, gl_TexCoord[0].xy).g;
25− if (Outline == 1.0f) {
28+ if (Outline) {
2629 if (sdf > interiorCutoff) {
2730 sdf = 1.0 - sdf;
2831 } else {
@@ -31,7 +34,7 @@ void main() { · 2 unmodified lines
3134 }
3235 // perform adaptive anti-aliasing of the edges
3336 // The larger we're rendering, the less anti-aliasing we need
34− float s = smoothing * length(fwidth(gl_TexCoord[0]));
37+ float s = smoothing * length(fwidth(gl_TexCoord[0].xy));
3538 float w = clamp( s, 0.0, 0.5);
3639 float a = smoothstep(0.5 - w, 0.5 + w, sdf);
3740
@@ -43,5 +46,7 @@ void main() { · 5 unmodified lines
4346 }
4447
4548 // final color
46− gl_FragColor = vec4(Color.rgb, a);
49+ gl_FragData[0] = vec4(Color.rgb, Color.a * a);
50+ gl_FragData[1] = vec4(interpolatedNormal.xyz, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
51+ gl_FragData[2] = vec4(0.0);
4752 }
libraries/render-utils/src/sdf_text3D.slv+6−0
@@ -13,6 +13,9 @@ · 12 unmodified lines
1313
1414 <$declareStandardTransform()$>
1515
16+// the interpolated normal
17+varying vec4 interpolatedNormal;
18+
1619 void main() {
1720 gl_TexCoord[0] = gl_MultiTexCoord0;
1821
@@ -20,4 +23,7 @@ void main() { · 1 unmodified line
2023 TransformCamera cam = getTransformCamera();
2124 TransformObject obj = getTransformObject();
2225 <$transformModelToClipPos(cam, obj, gl_Vertex, gl_Position)$>
26+ <$transformModelToEyeDir(cam, obj, gl_Normal, interpolatedNormal.xyz)$>
27+
28+ interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0);
2329 }
libraries/render-utils/src/standardDrawTexture.slf+24−0
@@ -0,0 +1,24 @@
1+<@include gpu/Config.slh@>
2+<$VERSION_HEADER$>
3+// Generated on <$_SCRIBE_DATE$>
4+// standardDrawTexture.frag
5+// fragment shader
6+//
7+// Created by Sam Gateau on 6/10/15.
8+// Copyright 2015 High Fidelity, Inc.
9+//
10+// Distributed under the Apache License, Version 2.0.
11+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
12+//
13+
14+// the texture
15+uniform sampler2D colorMap;
16+
17+varying vec2 varTexcoord;
18+varying vec4 varColor;
19+
20+
21+void main(void) {
22+ vec4 color = texture2D(colorMap, varTexcoord);
23+ gl_FragColor = color * varColor;
24+}
libraries/render-utils/src/standardTransformPNTC.slv+35−0
@@ -0,0 +1,35 @@
1+<@include gpu/Config.slh@>
2+<$VERSION_HEADER$>
3+// Generated on <$_SCRIBE_DATE$>
4+//
5+// standardTransformPNTC.slv
6+// vertex shader
7+//
8+// Created by Sam Gateau on 6/10/2015.
9+// Copyright 2015 High Fidelity, Inc.
10+//
11+// Distributed under the Apache License, Version 2.0.
12+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
13+//
14+
15+<@include gpu/Transform.slh@>
16+
17+<$declareStandardTransform()$>
18+
19+varying vec3 varPosition;
20+varying vec3 varNormal;
21+varying vec2 varTexcoord;
22+varying vec4 varColor;
23+
24+void main(void) {
25+ varTexcoord = gl_MultiTexCoord0.xy;
26+ varColor = gl_Color;
27+
28+ // standard transform
29+ TransformCamera cam = getTransformCamera();
30+ TransformObject obj = getTransformObject();
31+ <$transformModelToClipPos(cam, obj, gl_Vertex, gl_Position)$>
32+ <$transformModelToEyeDir(cam, obj, gl_Normal, varNormal)$>
33+ varNormal = normalize(varNormal);
34+ varPosition = gl_Vertex.xyz;
35+}
libraries/render-utils/src/stars.slf+76−0
@@ -0,0 +1,76 @@
1+<@include gpu/Config.slh@>
2+<$VERSION_HEADER$>
3+// Generated on <$_SCRIBE_DATE$>
4+// stars.frag
5+// fragment shader
6+//
7+// Created by Bradley Austin Davis on 2015/06/19
8+
9+varying vec2 varTexcoord;
10+varying vec3 varNomral;
11+varying vec3 varPosition;
12+
13+
14+const int star_iterations = 14;
15+const float time_scale = 0.2;
16+const vec3 col_star = vec3( 1.0, 0.7, 0.5 );
17+
18+float hash( float n ) { return fract(sin(n)*123.456789); }
19+
20+vec2 rotate( in vec2 uv, float a)
21+{
22+ float c = cos( a );
23+ float s = sin( a );
24+ return vec2( c * uv.x - s * uv.y, s * uv.x + c * uv.y );
25+}
26+
27+float noise( in vec3 p )
28+{
29+ vec3 fl = floor( p );
30+ vec3 fr = fract( p );
31+ fr = fr * fr * ( 3.0 - 2.0 * fr );
32+
33+ float n = fl.x + fl.y * 157.0 + 113.0 * fl.z;
34+ return mix( mix( mix( hash( n + 0.0), hash( n + 1.0 ), fr.x ),
35+ mix( hash( n + 157.0), hash( n + 158.0 ), fr.x ), fr.y ),
36+ mix( mix( hash( n + 113.0), hash( n + 114.0 ), fr.x ),
37+ mix( hash( n + 270.0), hash( n + 271.0 ), fr.x ), fr.y ), fr.z );
38+}
39+
40+float fbm( in vec2 p, float t )
41+{
42+ float f;
43+ f = 0.5000 * noise( vec3( p, t ) ); p *= 2.1;
44+ f += 0.2500 * noise( vec3( p, t ) ); p *= 2.2;
45+ f += 0.1250 * noise( vec3( p, t ) ); p *= 2.3;
46+ f += 0.0625 * noise( vec3( p, t ) );
47+ return f;
48+}
49+
50+vec3 doBackgroundStars( in vec3 dir )
51+{
52+ vec3 n = abs( dir );
53+ vec2 uv = ( n.x > n.y && n.x > n.z ) ? dir.yz / dir.x:
54+ ( n.y > n.x && n.y > n.z ) ? dir.zx / dir.y:
55+ dir.xy / dir.z;
56+
57+ float f = 0.0;
58+
59+ for( int i = 0 ; i < star_iterations; ++i )
60+ {
61+ uv = rotate( 1.07 * uv + vec2( 0.7 ), 0.5 );
62+
63+ float t = 10. * uv.x * uv.y;
64+ vec2 u = cos( 100. * uv ) * fbm( 10. * uv, 0.0 );
65+ f += smoothstep( 0.5, 0.55, u.x * u.y ) * ( 0.25 * sin( t ) + 0.75 );
66+ }
67+
68+ return f * col_star;
69+}
70+
71+void main(void) {
72+ vec3 c = doBackgroundStars( normalize(varPosition) );
73+ c = pow( c, vec3( 0.4545 ) );
74+ gl_FragColor = vec4( c, 1.0 );
75+}
76+
libraries/render/src/render/DrawTask.cpp+54−229
@@ -25,11 +25,6 @@ · 24 unmodified lines
2525 using namespace render;
2626
2727 DrawSceneTask::DrawSceneTask() : Task() {
28−
29− _jobs.push_back(Job(DrawOpaque()));
30− _jobs.push_back(Job(DrawLight()));
31− _jobs.push_back(Job(DrawTransparent()));
32− _jobs.push_back(Job(ResetGLState()));
3328 }
3429
3530 DrawSceneTask::~DrawSceneTask() {
@@ -56,8 +51,11 @@ void DrawSceneTask::run(const SceneContextPointer& sceneContext, const RenderCon · 20 unmodified lines
5651 Job::~Job() {
5752 }
5853
54+
55+
56+
57+
5958 void render::cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) {
60− PerformanceTimer perfTimer("cullItems");
6159 assert(renderContext->args);
6260 assert(renderContext->args->_viewFrustum);
6361
@@ -68,17 +66,9 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont · 4 unmodified lines
6866 renderDetails->_considered += inItems.size();
6967
7068 // Culling / LOD
71− for (auto itemDetails : inItems) {
72− auto item = scene->getItem(itemDetails.id);
73− AABox bound;
74− {
75− PerformanceTimer perfTimer("getBound");
76−
77− bound = item.getBound();
78− }
79−
80− if (bound.isNull()) {
81− outItems.emplace_back(ItemIDAndBounds(itemDetails.id)); // One more Item to render
69+ for (auto item : inItems) {
70+ if (item.bounds.isNull()) {
71+ outItems.emplace_back(item); // One more Item to render
8272 continue;
8373 }
8474
@@ -87,16 +77,16 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont · 2 unmodified lines
8777 bool outOfView;
8878 {
8979 PerformanceTimer perfTimer("boxInFrustum");
90− outOfView = args->_viewFrustum->boxInFrustum(bound) == ViewFrustum::OUTSIDE;
80+ outOfView = args->_viewFrustum->boxInFrustum(item.bounds) == ViewFrustum::OUTSIDE;
9181 }
9282 if (!outOfView) {
9383 bool bigEnoughToRender;
9484 {
9585 PerformanceTimer perfTimer("shouldRender");
96− bigEnoughToRender = (args->_shouldRender) ? args->_shouldRender(args, bound) : true;
86+ bigEnoughToRender = (args->_shouldRender) ? args->_shouldRender(args, item.bounds) : true;
9787 }
9888 if (bigEnoughToRender) {
99− outItems.emplace_back(ItemIDAndBounds(itemDetails.id, bound)); // One more Item to render
89+ outItems.emplace_back(item); // One more Item to render
10090 } else {
10191 renderDetails->_tooSmall++;
10292 }
@@ -107,6 +97,32 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont · 4 unmodified lines
10797 renderDetails->_rendered += outItems.size();
10898 }
10999
100+
101+void FetchItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems) {
102+ auto& scene = sceneContext->_scene;
103+ auto& items = scene->getMasterBucket().at(_filter);
104+ auto& renderDetails = renderContext->args->_details;
105+
106+ outItems.clear();
107+ outItems.reserve(items.size());
108+ for (auto id : items) {
109+ auto& item = scene->getItem(id);
110+ outItems.emplace_back(ItemIDAndBounds(id, item.getBound()));
111+ }
112+
113+ if (_probeNumItems) {
114+ _probeNumItems(renderContext, outItems.size());
115+ }
116+}
117+
118+void CullItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) {
119+
120+ outItems.clear();
121+ outItems.reserve(inItems.size());
122+ cullItems(sceneContext, renderContext, inItems, outItems);
123+}
124+
125+
110126 struct ItemBound {
111127 float _centerDepth = 0.0f;
112128 float _nearDepth = 0.0f;
@@ -130,7 +146,6 @@ struct BackToFrontSort { · 17 unmodified lines
130146 };
131147
132148 void render::depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) {
133− PerformanceTimer perfTimer("depthSortItems");
134149 assert(renderContext->args);
135150 assert(renderContext->args->_viewFrustum);
136151
@@ -139,9 +154,10 @@ void render::depthSortItems(const SceneContextPointer& sceneContext, const Rende · 2 unmodified lines
139154
140155
141156 // Allocate and simply copy
157+ outItems.clear();
142158 outItems.reserve(inItems.size());
143159
144−
160+
145161 // Make a local dataset of the center distance and closest point distance
146162 std::vector<ItemBound> itemBounds;
147163 itemBounds.reserve(outItems.size());
@@ -169,8 +185,14 @@ void render::depthSortItems(const SceneContextPointer& sceneContext, const Rende · 21 unmodified lines
169185 }
170186 }
171187
188+
189+void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) {
190+ outItems.clear();
191+ outItems.reserve(inItems.size());
192+ depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems);
193+}
194+
172195 void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems) {
173− PerformanceTimer perfTimer("renderItems");
174196 auto& scene = sceneContext->_scene;
175197 RenderArgs* args = renderContext->args;
176198 // render
@@ -183,6 +205,10 @@ void render::renderItems(const SceneContextPointer& sceneContext, const RenderCo · 6 unmodified lines
183205 int numItems = 0;
184206 for (auto itemDetails : inItems) {
185207 auto item = scene->getItem(itemDetails.id);
208+ if (numItems + 1 >= maxDrawnItems) {
209+ item.render(args);
210+ return;
211+ }
186212 item.render(args);
187213 numItems++;
188214 if (numItems >= maxDrawnItems) {
@@ -224,8 +250,7 @@ void addClearStateCommands(gpu::Batch& batch) { · 35 unmodified lines
224250 // Back to no program
225251 batch._glUseProgram(0);
226252 }
227−
228−template <> void render::jobRun(const ResetGLState& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
253+void ResetGLState::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
229254
230255 gpu::Batch theBatch;
231256 addClearStateCommands(theBatch);
@@ -233,160 +258,7 @@ template <> void render::jobRun(const ResetGLState& job, const SceneContextPoint · 1 unmodified line
233258 renderContext->args->_context->render(theBatch);
234259 }
235260
236−template <> void render::jobRun(const DrawOpaque& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
237− PerformanceTimer perfTimer("DrawOpaque");
238− assert(renderContext->args);
239− assert(renderContext->args->_viewFrustum);
240−
241− // render opaques
242− auto& scene = sceneContext->_scene;
243− auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape());
244− auto& renderDetails = renderContext->args->_details;
245−
246− ItemIDsBounds inItems;
247− inItems.reserve(items.size());
248− for (auto id : items) {
249− inItems.emplace_back(ItemIDAndBounds(id));
250− }
251− ItemIDsBounds& renderedItems = inItems;
252−
253− renderContext->_numFeedOpaqueItems = renderedItems.size();
254−
255− ItemIDsBounds culledItems;
256− culledItems.reserve(inItems.size());
257− if (renderContext->_cullOpaque) {
258− renderDetails.pointTo(RenderDetails::OPAQUE_ITEM);
259− cullItems(sceneContext, renderContext, renderedItems, culledItems);
260− renderDetails.pointTo(RenderDetails::OTHER_ITEM);
261− renderedItems = culledItems;
262− }
263−
264− renderContext->_numDrawnOpaqueItems = renderedItems.size();
265−
266− ItemIDsBounds sortedItems;
267− sortedItems.reserve(culledItems.size());
268− if (renderContext->_sortOpaque) {
269− depthSortItems(sceneContext, renderContext, true, renderedItems, sortedItems); // Sort Front to back opaque items!
270− renderedItems = sortedItems;
271− }
272−
273− if (renderContext->_renderOpaque) {
274− RenderArgs* args = renderContext->args;
275− gpu::Batch batch;
276− args->_batch = &batch;
277−
278− glm::mat4 projMat;
279− Transform viewMat;
280− args->_viewFrustum->evalProjectionMatrix(projMat);
281− args->_viewFrustum->evalViewTransform(viewMat);
282− if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
283− viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
284− }
285− batch.setProjectionTransform(projMat);
286− batch.setViewTransform(viewMat);
287−
288− {
289− GLenum buffers[3];
290− int bufferCount = 0;
291− buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
292− buffers[bufferCount++] = GL_COLOR_ATTACHMENT1;
293− buffers[bufferCount++] = GL_COLOR_ATTACHMENT2;
294− batch._glDrawBuffers(bufferCount, buffers);
295− }
296−
297− renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnOpaqueItems);
298−
299− args->_context->render((*args->_batch));
300− args->_batch = nullptr;
301− }
302−}
303−
304−
305−template <> void render::jobRun(const DrawTransparent& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
306− PerformanceTimer perfTimer("DrawTransparent");
307− assert(renderContext->args);
308− assert(renderContext->args->_viewFrustum);
309−
310− // render transparents
311− auto& scene = sceneContext->_scene;
312− auto& items = scene->getMasterBucket().at(ItemFilter::Builder::transparentShape());
313− auto& renderDetails = renderContext->args->_details;
314−
315− ItemIDsBounds inItems;
316− inItems.reserve(items.size());
317− for (auto id : items) {
318− inItems.emplace_back(id);
319− }
320− ItemIDsBounds& renderedItems = inItems;
321−
322− renderContext->_numFeedTransparentItems = renderedItems.size();
323−
324− ItemIDsBounds culledItems;
325− culledItems.reserve(inItems.size());
326− if (renderContext->_cullTransparent) {
327− renderDetails.pointTo(RenderDetails::TRANSLUCENT_ITEM);
328− cullItems(sceneContext, renderContext, inItems, culledItems);
329− renderDetails.pointTo(RenderDetails::OTHER_ITEM);
330− renderedItems = culledItems;
331− }
332−
333− renderContext->_numDrawnTransparentItems = renderedItems.size();
334−
335− ItemIDsBounds sortedItems;
336− sortedItems.reserve(culledItems.size());
337− if (renderContext->_sortTransparent) {
338− depthSortItems(sceneContext, renderContext, false, renderedItems, sortedItems); // Sort Back to front transparent items!
339− renderedItems = sortedItems;
340− }
341−
342− if (renderContext->_renderTransparent) {
343− RenderArgs* args = renderContext->args;
344− gpu::Batch batch;
345− args->_batch = &batch;
346−
347− glm::mat4 projMat;
348− Transform viewMat;
349− args->_viewFrustum->evalProjectionMatrix(projMat);
350− args->_viewFrustum->evalViewTransform(viewMat);
351− if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
352− viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
353− }
354− batch.setProjectionTransform(projMat);
355− batch.setViewTransform(viewMat);
356−
357− const float MOSTLY_OPAQUE_THRESHOLD = 0.75f;
358− const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f;
359−
360− // render translucent meshes afterwards
361− {
362− GLenum buffers[2];
363− int bufferCount = 0;
364− buffers[bufferCount++] = GL_COLOR_ATTACHMENT1;
365− buffers[bufferCount++] = GL_COLOR_ATTACHMENT2;
366− batch._glDrawBuffers(bufferCount, buffers);
367− args->_alphaThreshold = MOSTLY_OPAQUE_THRESHOLD;
368− }
369−
370− renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnTransparentItems);
371−
372− {
373− GLenum buffers[3];
374− int bufferCount = 0;
375− buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
376− batch._glDrawBuffers(bufferCount, buffers);
377− args->_alphaThreshold = TRANSPARENT_ALPHA_THRESHOLD;
378− }
379−
380−
381− renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnTransparentItems);
382−
383− args->_context->render((*args->_batch));
384− args->_batch = nullptr;
385− }
386−}
387−
388−template <> void render::jobRun(const DrawLight& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
389− PerformanceTimer perfTimer("DrawLight");
261+void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
390262 assert(renderContext->args);
391263 assert(renderContext->args->_viewFrustum);
392264
@@ -398,7 +270,8 @@ template <> void render::jobRun(const DrawLight& job, const SceneContextPointer& · 5 unmodified lines
398270 ItemIDsBounds inItems;
399271 inItems.reserve(items.size());
400272 for (auto id : items) {
401− inItems.emplace_back(id);
273+ auto item = scene->getItem(id);
274+ inItems.emplace_back(ItemIDAndBounds(id, item.getBound()));
402275 }
403276
404277 ItemIDsBounds culledItems;
@@ -413,8 +286,7 @@ template <> void render::jobRun(const DrawLight& job, const SceneContextPointer& · 8 unmodified lines
413286 args->_batch = nullptr;
414287 }
415288
416−template <> void render::jobRun(const DrawBackground& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
417− PerformanceTimer perfTimer("DrawBackground");
289+void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
418290 assert(renderContext->args);
419291 assert(renderContext->args->_viewFrustum);
420292
@@ -450,53 +322,6 @@ template <> void render::jobRun(const DrawBackground& job, const SceneContextPoi · 29 unmodified lines
450322 args->_context->syncCache();
451323 }
452324
453−template <> void render::jobRun(const DrawPostLayered& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
454− PerformanceTimer perfTimer("DrawPostLayered");
455− assert(renderContext->args);
456− assert(renderContext->args->_viewFrustum);
457−
458− // render backgrounds
459− auto& scene = sceneContext->_scene;
460− auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape().withLayered());
461−
462−
463− ItemIDsBounds inItems;
464− inItems.reserve(items.size());
465− for (auto id : items) {
466− auto& item = scene->getItem(id);
467− if (item.getKey().isVisible() && (item.getLayer() > 0)) {
468− inItems.emplace_back(id);
469− }
470− }
471− if (inItems.empty()) {
472− return;
473− }
474−
475− RenderArgs* args = renderContext->args;
476− gpu::Batch batch;
477− args->_batch = &batch;
478−
479− glm::mat4 projMat;
480− Transform viewMat;
481− args->_viewFrustum->evalProjectionMatrix(projMat);
482− args->_viewFrustum->evalViewTransform(viewMat);
483− if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
484− viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
485− }
486− batch.setProjectionTransform(projMat);
487− batch.setViewTransform(viewMat);
488−
489− batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0);
490−
491− renderItems(sceneContext, renderContext, inItems);
492− args->_context->render((*args->_batch));
493− args->_batch = nullptr;
494−
495− // Force the context sync
496− args->_context->syncCache();
497−}
498−
499−
500325 void ItemMaterialBucketMap::insert(const ItemID& id, const model::MaterialKey& key) {
501326 // Insert the itemID in every bucket where it filters true
502327 for (auto& bucket : (*this)) {
libraries/render/src/render/DrawTask.h+172−24
@@ -13,42 +13,173 @@ · 12 unmodified lines
1313 #define hifi_render_Task_h
1414
1515 #include "Engine.h"
16+#include "gpu/Batch.h"
17+#include <PerfStat.h>
18+
1619
1720 namespace render {
1821
19−template <class T> void jobRun(const T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { }
22+template <class T> void jobRun(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
23+ jobModel.run(sceneContext, renderContext);
24+}
25+template <class T, class I> void jobRunI(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const I& input) {
26+ jobModel.run(sceneContext, renderContext, input);
27+}
28+template <class T, class O> void jobRunO(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, O& output) {
29+ jobModel.run(sceneContext, renderContext, output);
30+}
31+template <class T, class I, class O> void jobRunIO(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const I& input, O& output) {
32+ jobModel.run(sceneContext, renderContext, input, output);
33+}
2034
2135 class Job {
2236 public:
2337
24− template <class T>
25− Job(T data) : _concept(new Model<T>(data)) {}
38+ // Varying represent a varying piece of data
39+ class Varying {
40+ public:
41+
42+ Varying(const Varying& var): _concept(var._concept) {}
43+
44+ Varying() {}
45+ template <class T>
46+ Varying(const T& data) : _concept(new Job::Varying::Model<T>(data)) {}
47+
48+ // Access the _data contained win the concept explicitely
49+ template <class T> T& edit() { return (static_cast<Model<T>*> (_concept.get())->_data); }
50+ template <class T> const T& get() const { return (static_cast<const Model<T>*> (_concept.get())->_data); }
51+
52+ protected:
53+ friend class Job;
54+
55+ std::vector<std::weak_ptr<Job>> _consumerJobs;
56+
57+ void addJobConsumer(const std::shared_ptr<Job>& job) {
58+ _consumerJobs.push_back(job);
59+ }
60+
61+ class Concept {
62+ public:
63+ virtual ~Concept() = default;
64+ };
65+ template <class T> class Model : public Concept {
66+ public:
67+ typedef T Data;
68+ Data _data;
69+ Model(const Model& source): _data(source.data) {}
70+ Model(const Data& data): _data(data) {}
71+ virtual ~Model() {}
72+ };
73+
74+ std::shared_ptr<Concept> _concept;
75+ };
76+
2677 Job(const Job& other) : _concept(other._concept) {}
2778 ~Job();
2879
29− virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
30− if (_concept) {
31− _concept->run(sceneContext, renderContext);
32− }
80+ const std::string& getName() const { return _concept->getName(); }
81+ const Varying getInput() const { return _concept->getInput(); }
82+ const Varying getOutput() const { return _concept->getOutput(); }
83+
84+ void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
85+ PerformanceTimer perfTimer(getName().c_str());
86+ PROFILE_RANGE(getName().c_str());
87+ _concept->run(sceneContext, renderContext);
3388 }
3489
3590 protected:
91+public:
92+
3693 class Concept {
94+ std::string _name;
3795 public:
96+ Concept() : _name() {}
97+ Concept(const std::string& name) : _name(name) {}
3898 virtual ~Concept() = default;
99+
100+ void setName(const std::string& name) { _name = name; }
101+ const std::string& getName() const { return _name; }
102+
103+ virtual const Varying getInput() const { return Varying(); }
104+ virtual const Varying getOutput() const { return Varying(); }
39105 virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) = 0;
40106 };
41107
108+ Job(Concept* concept) : _concept(concept) {}
109+
110+public:
42111 template <class T> class Model : public Concept {
43112 public:
44113 typedef T Data;
45−
114+
46115 Data _data;
116+
117+ Model() {}
118+ Model(const std::string& name): Concept(name) {}
47119 Model(Data data): _data(data) {}
120+ Model(Data data, const std::string& name): Concept(name), _data(data) {}
48121
49122 void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { jobRun(_data, sceneContext, renderContext); }
50123 };
51124
125+ template <class T, class I> class ModelI : public Concept {
126+ public:
127+ typedef T Data;
128+ typedef I Input;
129+
130+ Data _data;
131+ Varying _input;
132+
133+ const Varying getInput() const { return _input; }
134+
135+ ModelI(const std::string& name, const Varying& input): Concept(name), _input(input) {}
136+ ModelI(const std::string& name, Data data): Concept(name), _data(data) {}
137+
138+ void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { jobRunI(_data, sceneContext, renderContext, _input.get<I>()); }
139+ };
140+
141+ template <class T, class O> class ModelO : public Concept {
142+ public:
143+ typedef T Data;
144+ typedef O Output;
145+
146+ Data _data;
147+ Varying _output;
148+
149+ const Varying getOutput() const { return _output; }
150+
151+ ModelO(const std::string& name): Concept(name), _output(Output()) {
152+
153+ }
154+
155+ ModelO(const std::string& name, Data data): Concept(name), _data(data), _output(Output()) {}
156+
157+ void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
158+ jobRunO(_data, sceneContext, renderContext, _output.edit<O>());
159+ }
160+ };
161+
162+ template <class T, class I, class O> class ModelIO : public Concept {
163+ public:
164+ typedef T Data;
165+ typedef I Input;
166+ typedef O Output;
167+
168+ Data _data;
169+ Varying _input;
170+ Varying _output;
171+
172+ const Varying getInput() const { return _input; }
173+ const Varying getOutput() const { return _output; }
174+
175+ ModelIO(const std::string& name, const Varying& input, Data data = Data()): Concept(name), _data(data), _input(input), _output(Output()) {}
176+ ModelIO(const std::string& name, Data data, Output output): Concept(name), _data(data), _output(output) {}
177+
178+ void setInput(const Varying& input) { _input = input; }
179+
180+ void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { jobRunIO(_data, sceneContext, renderContext, _input.get<I>(), _output.edit<O>()); }
181+ };
182+
52183 std::shared_ptr<Concept> _concept;
53184 };
54185
@@ -62,43 +193,59 @@ void depthSortItems(const SceneContextPointer& sceneContext, const RenderContext · 7 unmodified lines
62193 void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1);
63194
64195
196+class FetchItems {
197+public:
198+ typedef std::function<void (const RenderContextPointer& context, int count)> ProbeNumItems;
199+ FetchItems(const ProbeNumItems& probe): _probeNumItems(probe) {}
200+ FetchItems(const ItemFilter& filter, const ProbeNumItems& probe): _filter(filter), _probeNumItems(probe) {}
65201
66−void materialSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems);
202+ ItemFilter _filter = ItemFilter::Builder::opaqueShape().withoutLayered();
203+ ProbeNumItems _probeNumItems;
67204
205+ void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems);
68206
69−class DrawOpaque {
70−public:
207+ typedef Job::ModelO<FetchItems, ItemIDsBounds> JobModel;
71208 };
72−template <> void jobRun(const DrawOpaque& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
73209
210+class CullItems {
211+public:
212+ void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems);
74213
75−class DrawTransparent {
214+ typedef Job::ModelIO<CullItems, ItemIDsBounds, ItemIDsBounds> JobModel;
215+};
216+
217+class DepthSortItems {
76218 public:
219+ bool _frontToBack = true;
220+
221+ DepthSortItems(bool frontToBack = true) : _frontToBack(frontToBack) {}
222+
223+ void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outITems);
224+
225+ typedef Job::ModelIO<DepthSortItems, ItemIDsBounds, ItemIDsBounds> JobModel;
77226 };
78−template <> void jobRun(const DrawTransparent& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
79227
80228 class DrawLight {
81229 public:
230+ void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
231+
232+ typedef Job::Model<DrawLight> JobModel;
82233 };
83−template <> void jobRun(const DrawLight& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
84234
85235 class DrawBackground {
86236 public:
87−};
88−template <> void jobRun(const DrawBackground& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
89−
237+ void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
90238
91−class DrawPostLayered {
92−public:
239+ typedef Job::Model<DrawBackground> JobModel;
93240 };
94−template <> void jobRun(const DrawPostLayered& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
95−
96−
97241
98242 class ResetGLState {
99243 public:
244+ void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
245+
246+ typedef Job::Model<ResetGLState> JobModel;
100247 };
101−template <> void jobRun(const ResetGLState& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
248+
102249
103250
104251 class DrawSceneTask : public Task {
@@ -126,6 +273,7 @@ public: · 21 unmodified lines
126273 // standard builders allocating the main buckets
127274 void allocateStandardMaterialBuckets();
128275 };
276+void materialSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems);
129277
130278 }
131279
libraries/render/src/render/Engine.h+4−0
@@ -45,6 +45,10 @@ public: · 44 unmodified lines
4545 int _numDrawnTransparentItems = 0;
4646 int _maxDrawnTransparentItems = -1;
4747
48+ int _numFeedOverlay3DItems = 0;
49+ int _numDrawnOverlay3DItems = 0;
50+ int _maxDrawnOverlay3DItems = -1;
51+
4852 RenderContext() {}
4953 };
5054 typedef std::shared_ptr<RenderContext> RenderContextPointer;
libraries/script-engine/src/AbstractControllerScriptingInterface.h+1−0
@@ -107,6 +107,7 @@ signals: · 106 unmodified lines
107107
108108 void mouseMoveEvent(const MouseEvent& event, unsigned int deviceID = 0);
109109 void mousePressEvent(const MouseEvent& event, unsigned int deviceID = 0);
110+ void mouseDoublePressEvent(const MouseEvent& event, unsigned int deviceID = 0);
110111 void mouseReleaseEvent(const MouseEvent& event, unsigned int deviceID = 0);
111112
112113 void touchBeginEvent(const TouchEvent& event);
libraries/script-engine/src/AudioScriptingInterface.cpp+1−18
@@ -46,24 +46,7 @@ ScriptAudioInjector* AudioScriptingInterface::playSound(Sound* sound, const Audi · 45 unmodified lines
4646 AudioInjectorOptions optionsCopy = injectorOptions;
4747 optionsCopy.stereo = sound->isStereo();
4848
49− QThread* injectorThread = new QThread();
50− injectorThread->setObjectName("Audio Injector Thread");
51−
52− AudioInjector* injector = new AudioInjector(sound, optionsCopy);
53− injector->setLocalAudioInterface(_localAudioInterface);
54−
55− injector->moveToThread(injectorThread);
56−
57− // start injecting when the injector thread starts
58− connect(injectorThread, &QThread::started, injector, &AudioInjector::injectAudio);
59−
60− // connect the right slots and signals for AudioInjector and thread cleanup
61− connect(injector, &AudioInjector::destroyed, injectorThread, &QThread::quit);
62− connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater);
63−
64− injectorThread->start();
65−
66− return new ScriptAudioInjector(injector);
49+ return new ScriptAudioInjector(AudioInjector::playSound(sound->getByteArray(), optionsCopy, _localAudioInterface));
6750
6851 } else {
6952 qCDebug(scriptengine) << "AudioScriptingInterface::playSound called with null Sound object.";
libraries/script-engine/src/SceneScriptingInterface.cpp+2−0
@@ -159,4 +159,6 @@ void SceneScriptingInterface::clearEngineCounters() { · 158 unmodified lines
159159 _numDrawnOpaqueItems = 0;
160160 _numFeedTransparentItems = 0;
161161 _numDrawnTransparentItems = 0;
162+ _numFeedOverlay3DItems = 0;
163+ _numDrawnOverlay3DItems = 0;
162164 }
libraries/script-engine/src/SceneScriptingInterface.h+9−1
@@ -90,17 +90,22 @@ public: · 89 unmodified lines
9090 Q_INVOKABLE int getEngineNumDrawnOpaqueItems() { return _numDrawnOpaqueItems; }
9191 void setEngineDrawnTransparentItems(int count) { _numDrawnTransparentItems = count; }
9292 Q_INVOKABLE int getEngineNumDrawnTransparentItems() { return _numDrawnTransparentItems; }
93+ void setEngineDrawnOverlay3DItems(int count) { _numDrawnOverlay3DItems = count; }
94+ Q_INVOKABLE int getEngineNumDrawnOverlay3DItems() { return _numDrawnOverlay3DItems; }
9395
9496 void setEngineFeedOpaqueItems(int count) { _numFeedOpaqueItems = count; }
9597 Q_INVOKABLE int getEngineNumFeedOpaqueItems() { return _numFeedOpaqueItems; }
9698 void setEngineFeedTransparentItems(int count) { _numFeedTransparentItems = count; }
9799 Q_INVOKABLE int getEngineNumFeedTransparentItems() { return _numFeedTransparentItems; }
100+ void setEngineFeedOverlay3DItems(int count) { _numFeedOverlay3DItems = count; }
101+ Q_INVOKABLE int getEngineNumFeedOverlay3DItems() { return _numFeedOverlay3DItems; }
98102
99103 Q_INVOKABLE void setEngineMaxDrawnOpaqueItems(int count) { _maxDrawnOpaqueItems = count; }
100104 Q_INVOKABLE int getEngineMaxDrawnOpaqueItems() { return _maxDrawnOpaqueItems; }
101105 Q_INVOKABLE void setEngineMaxDrawnTransparentItems(int count) { _maxDrawnTransparentItems = count; }
102106 Q_INVOKABLE int getEngineMaxDrawnTransparentItems() { return _maxDrawnTransparentItems; }
103−
107+ Q_INVOKABLE void setEngineMaxDrawnOverlay3DItems(int count) { _maxDrawnOverlay3DItems = count; }
108+ Q_INVOKABLE int getEngineMaxDrawnOverlay3DItems() { return _maxDrawnOverlay3DItems; }
104109 signals:
105110 void shouldRenderAvatarsChanged(bool shouldRenderAvatars);
106111 void shouldRenderEntitiesChanged(bool shouldRenderEntities);
@@ -124,9 +129,12 @@ protected: · 17 unmodified lines
124129 int _numDrawnOpaqueItems = 0;
125130 int _numFeedTransparentItems = 0;
126131 int _numDrawnTransparentItems = 0;
132+ int _numFeedOverlay3DItems = 0;
133+ int _numDrawnOverlay3DItems = 0;
127134
128135 int _maxDrawnOpaqueItems = -1;
129136 int _maxDrawnTransparentItems = -1;
137+ int _maxDrawnOverlay3DItems = -1;
130138
131139 };
132140
libraries/script-engine/src/ScriptEngine.cpp+4−1
@@ -317,7 +317,10 @@ void ScriptEngine::init() { · 316 unmodified lines
317317 registerAnimationTypes(this);
318318 registerAvatarTypes(this);
319319 registerAudioMetaTypes(this);
320− _controllerScriptingInterface->registerControllerTypes(this);
320+
321+ if (_controllerScriptingInterface) {
322+ _controllerScriptingInterface->registerControllerTypes(this);
323+ }
321324
322325 qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly);
323326 qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue);
libraries/script-engine/src/ScriptEngine.h+1−1
@@ -35,7 +35,7 @@ · 34 unmodified lines
3535
3636 const QString NO_SCRIPT("");
3737
38−const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0 / 60.0f) * 1000 * 1000) + 0.5);
38+const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0f / 60.0f) * 1000 * 1000) + 0.5f);
3939
4040 typedef QHash<QString, QScriptValueList> RegisteredEventHandlers;
4141
libraries/script-engine/src/TouchEvent.cpp+13−13
@@ -40,7 +40,7 @@ TouchEvent::TouchEvent() : · 39 unmodified lines
4040 isRotating(false),
4141 rotating("none")
4242 {
43−
43+
4444 }
4545
4646 TouchEvent::TouchEvent(const QTouchEvent& event) :
@@ -77,9 +77,9 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) { · 30 unmodified lines
7777 touchPoints = tPoints.count();
7878 if (touchPoints > 1) {
7979 for (int i = 0; i < touchPoints; ++i) {
80− touchAvgX += tPoints[i].pos().x();
81− touchAvgY += tPoints[i].pos().y();
82−
80+ touchAvgX += (float)tPoints[i].pos().x();
81+ touchAvgY += (float)tPoints[i].pos().y();
82+
8383 // add it to our points vector
8484 glm::vec2 thisPoint(tPoints[i].pos().x(), tPoints[i].pos().y());
8585 points << thisPoint;
@@ -94,7 +94,7 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) { · 8 unmodified lines
9494 }
9595 x = touchAvgX;
9696 y = touchAvgY;
97−
97+
9898 // after calculating the center point (average touch point), determine the maximum radius
9999 // also calculate the rotation angle for each point
100100 float maxRadius = 0.0f;
@@ -105,25 +105,25 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) { · 4 unmodified lines
105105 if (thisRadius > maxRadius) {
106106 maxRadius = thisRadius;
107107 }
108−
108+
109109 // calculate the angle for this point
110110 float thisAngle = angleBetweenPoints(center,touchPoint);
111111 angles << thisAngle;
112112 }
113113 radius = maxRadius;
114−
114+
115115 // after calculating the angles for each touch point, determine the average angle
116116 float totalAngle = 0.0f;
117117 for (int i = 0; i < touchPoints; ++i) {
118118 totalAngle += angles[i];
119119 }
120120 angle = totalAngle/(float)touchPoints;
121−
121+
122122 isPressed = event.touchPointStates().testFlag(Qt::TouchPointPressed);
123123 isMoved = event.touchPointStates().testFlag(Qt::TouchPointMoved);
124124 isStationary = event.touchPointStates().testFlag(Qt::TouchPointStationary);
125125 isReleased = event.touchPointStates().testFlag(Qt::TouchPointReleased);
126−
126+
127127 // keyboard modifiers
128128 isShifted = event.modifiers().testFlag(Qt::ShiftModifier);
129129 isMeta = event.modifiers().testFlag(Qt::MetaModifier);
@@ -143,7 +143,7 @@ void TouchEvent::calculateMetaAttributes(const TouchEvent& other) { · 13 unmodified lines
143143 isPinching = other.isPinching;
144144 isPinchOpening = other.isPinchOpening;
145145 }
146−
146+
147147 // determine if the points are rotating...
148148 // note: if the number of touch points change between events, then we don't consider ourselves to be rotating
149149 if (touchPoints == other.touchPoints) {
@@ -178,7 +178,7 @@ QScriptValue TouchEvent::toScriptValue(QScriptEngine* engine, const TouchEvent& · 28 unmodified lines
178178 obj.setProperty("isControl", event.isControl);
179179 obj.setProperty("isAlt", event.isAlt);
180180 obj.setProperty("touchPoints", event.touchPoints);
181−
181+
182182 QScriptValue pointsObj = engine->newArray();
183183 int index = 0;
184184 foreach (glm::vec2 point, event.points) {
@@ -190,7 +190,7 @@ QScriptValue TouchEvent::toScriptValue(QScriptEngine* engine, const TouchEvent& · 5 unmodified lines
190190 obj.setProperty("radius", event.radius);
191191 obj.setProperty("isPinching", event.isPinching);
192192 obj.setProperty("isPinchOpening", event.isPinchOpening);
193−
193+
194194 obj.setProperty("angle", event.angle);
195195 obj.setProperty("deltaAngle", event.deltaAngle);
196196 QScriptValue anglesObj = engine->newArray();
@@ -200,7 +200,7 @@ QScriptValue TouchEvent::toScriptValue(QScriptEngine* engine, const TouchEvent& · 3 unmodified lines
200200 index++;
201201 }
202202 obj.setProperty("angles", anglesObj);
203−
203+
204204 obj.setProperty("isRotating", event.isRotating);
205205 obj.setProperty("rotating", event.rotating);
206206 return obj;
libraries/shared/CMakeLists.txt+2−1
@@ -6,4 +6,5 @@ setup_hifi_library(Gui Network Script Widgets) · 5 unmodified lines
66
77 add_dependency_external_projects(glm)
88 find_package(GLM REQUIRED)
9−target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
9+target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
10+
libraries/shared/src/AABox.cpp+38−38
@@ -16,20 +16,20 @@ · 15 unmodified lines
1616 #include "GeometryUtil.h"
1717 #include "NumericalConstants.h"
1818
19−AABox::AABox(const AACube& other) :
19+AABox::AABox(const AACube& other) :
2020 _corner(other.getCorner()), _scale(other.getScale(), other.getScale(), other.getScale()) {
2121 }
2222
23−AABox::AABox(const Extents& other) :
23+AABox::AABox(const Extents& other) :
2424 _corner(other.minimum),
2525 _scale(other.maximum - other.minimum) {
2626 }
2727
28−AABox::AABox(const glm::vec3& corner, float size) :
28+AABox::AABox(const glm::vec3& corner, float size) :
2929 _corner(corner), _scale(size, size, size) {
3030 };
3131
32−AABox::AABox(const glm::vec3& corner, const glm::vec3& dimensions) :
32+AABox::AABox(const glm::vec3& corner, const glm::vec3& dimensions) :
3333 _corner(corner), _scale(dimensions) {
3434 };
3535
@@ -39,7 +39,7 @@ AABox::AABox() : _corner(std::numeric_limits<float>::infinity()), _scale(0.0f) { · 3 unmodified lines
3939 glm::vec3 AABox::calcCenter() const {
4040 glm::vec3 center(_corner);
4141 center += (_scale * 0.5f);
42− return center;
42+ return center;
4343 }
4444
4545 void AABox::scale(float scale) {
@@ -134,12 +134,12 @@ bool AABox::contains(const AABox& otherBox) const { · 88 unmodified lines
134134
135135 bool AABox::touches(const AABox& otherBox) const {
136136 glm::vec3 relativeCenter = _corner - otherBox._corner + ((_scale - otherBox._scale) * 0.5f);
137−
137+
138138 glm::vec3 totalHalfScale = (_scale + otherBox._scale) * 0.5f;
139−
140− return fabs(relativeCenter.x) <= totalHalfScale.x &&
141− fabs(relativeCenter.y) <= totalHalfScale.y &&
142− fabs(relativeCenter.z) <= totalHalfScale.z;
139+
140+ return fabsf(relativeCenter.x) <= totalHalfScale.x &&
141+ fabsf(relativeCenter.y) <= totalHalfScale.y &&
142+ fabsf(relativeCenter.z) <= totalHalfScale.z;
143143 }
144144
145145 bool AABox::contains(const AACube& otherCube) const {
@@ -154,12 +154,12 @@ bool AABox::contains(const AACube& otherCube) const { · 8 unmodified lines
154154
155155 bool AABox::touches(const AACube& otherCube) const {
156156 glm::vec3 relativeCenter = _corner - otherCube.getCorner() + ((_scale - otherCube.getDimensions()) * 0.5f);
157−
157+
158158 glm::vec3 totalHalfScale = (_scale + otherCube.getDimensions()) * 0.5f;
159−
160− return fabs(relativeCenter.x) <= totalHalfScale.x &&
161− fabs(relativeCenter.y) <= totalHalfScale.y &&
162− fabs(relativeCenter.z) <= totalHalfScale.z;
159+
160+ return fabsf(relativeCenter.x) <= totalHalfScale.x &&
161+ fabsf(relativeCenter.y) <= totalHalfScale.y &&
162+ fabsf(relativeCenter.z) <= totalHalfScale.z;
163163 }
164164
165165 // determines whether a value is within the expanded extents
@@ -244,14 +244,14 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct · 78 unmodified lines
244244 isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale.y) &&
245245 isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x))) {
246246 distance = axisDistance;
247− face = direction.z > 0 ? MAX_Z_FACE : MIN_Z_FACE;
247+ face = direction.z > 0 ? MAX_Z_FACE : MIN_Z_FACE;
248248 return true;
249249 }
250250 // This case is unexpected, but mimics the previous behavior for inside out intersections
251251 distance = 0;
252252 return true;
253253 }
254−
254+
255255 // check each axis
256256 float axisDistance;
257257 if ((findIntersection(origin.x, direction.x, _corner.x, _scale.x, axisDistance) && axisDistance >= 0 &&
@@ -272,7 +272,7 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct · 14 unmodified lines
272272 isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale.y) &&
273273 isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x))) {
274274 distance = axisDistance;
275− face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE;
275+ face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE;
276276 return true;
277277 }
278278 return false;
@@ -280,7 +280,7 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct · 1 unmodified line
280280
281281 bool AABox::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const {
282282 glm::vec4 center4 = glm::vec4(center, 1.0f);
283−
283+
284284 float minPenetrationLength = FLT_MAX;
285285 for (int i = 0; i < FACE_COUNT; i++) {
286286 glm::vec4 facePlane = getPlane((BoxFace)i);
@@ -297,7 +297,7 @@ bool AABox::findSpherePenetration(const glm::vec3& center, float radius, glm::ve · 10 unmodified lines
297297 minPenetrationLength = vectorLength;
298298 }
299299 }
300−
300+
301301 return true;
302302 }
303303
@@ -305,7 +305,7 @@ bool AABox::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, · 1 unmodified line
305305 glm::vec4 start4 = glm::vec4(start, 1.0f);
306306 glm::vec4 end4 = glm::vec4(end, 1.0f);
307307 glm::vec4 startToEnd = glm::vec4(end - start, 0.0f);
308−
308+
309309 float minPenetrationLength = FLT_MAX;
310310 for (int i = 0; i < FACE_COUNT; i++) {
311311 // find the vector from the segment to the closest point on the face (starting from deeper end)
@@ -324,8 +324,8 @@ bool AABox::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, · 12 unmodified lines
324324 vector * ((vectorLength + radius) / -vectorLength);
325325 minPenetrationLength = vectorLength;
326326 }
327− }
328−
327+ }
328+
329329 return true;
330330 }
331331
@@ -334,23 +334,23 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec3& point, BoxFace face) con · 2 unmodified lines
334334 case MIN_X_FACE:
335335 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
336336 glm::vec3(_corner.x, _corner.y + _scale.y, _corner.z + _scale.z));
337−
337+
338338 case MAX_X_FACE:
339339 return glm::clamp(point, glm::vec3(_corner.x + _scale.x, _corner.y, _corner.z),
340340 glm::vec3(_corner.x + _scale.x, _corner.y + _scale.y, _corner.z + _scale.z));
341−
341+
342342 case MIN_Y_FACE:
343343 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
344344 glm::vec3(_corner.x + _scale.x, _corner.y, _corner.z + _scale.z));
345−
345+
346346 case MAX_Y_FACE:
347347 return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _scale.y, _corner.z),
348348 glm::vec3(_corner.x + _scale.x, _corner.y + _scale.y, _corner.z + _scale.z));
349−
349+
350350 case MIN_Z_FACE:
351351 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
352352 glm::vec3(_corner.x + _scale.z, _corner.y + _scale.y, _corner.z));
353−
353+
354354 default: //quiet windows warnings
355355 case MAX_Z_FACE:
356356 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _scale.z),
@@ -373,7 +373,7 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& · 16 unmodified lines
373373 }
374374 anyOutside = true;
375375 float divisor = glm::dot(direction, iPlane);
376− if (fabs(divisor) < EPSILON) {
376+ if (fabsf(divisor) < EPSILON) {
377377 continue; // segment is parallel to plane
378378 }
379379 // find intersection and see if it lies within face bounds
@@ -389,29 +389,29 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& · 9 unmodified lines
389389 }
390390 }
391391 return getClosestPointOnFace(glm::vec3(intersection), face);
392−
392+
393393 outerContinue: ;
394394 }
395−
395+
396396 // if we were outside any of the sides, we must check against the diagonals
397397 if (anyOutside) {
398398 int faceAxis = face / 2;
399399 int secondAxis = (faceAxis + 1) % 3;
400400 int thirdAxis = (faceAxis + 2) % 3;
401−
401+
402402 glm::vec4 secondAxisMinPlane = getPlane((BoxFace)(secondAxis * 2));
403403 glm::vec4 secondAxisMaxPlane = getPlane((BoxFace)(secondAxis * 2 + 1));
404404 glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1));
405−
405+
406406 glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f,
407407 glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), _scale) * 0.5f);
408408 glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset,
409409 secondAxisMaxPlane + thirdAxisMaxPlane + offset };
410−
410+
411411 float minDistance = FLT_MAX;
412412 for (size_t i = 0; i < sizeof(diagonals) / sizeof(diagonals[0]); i++) {
413413 float divisor = glm::dot(direction, diagonals[i]);
414− if (fabs(divisor) < EPSILON) {
414+ if (fabsf(divisor) < EPSILON) {
415415 continue; // segment is parallel to diagonal plane
416416 }
417417 minDistance = glm::min(-glm::dot(origin, diagonals[i]) / divisor, minDistance);
@@ -420,7 +420,7 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& · 2 unmodified lines
420420 return getClosestPointOnFace(glm::vec3(origin + direction * minDistance), face);
421421 }
422422 }
423−
423+
424424 // last resort or all inside: clamp origin to face
425425 return getClosestPointOnFace(glm::vec3(origin), face);
426426 }
@@ -453,7 +453,7 @@ AABox AABox::clamp(const glm::vec3& min, const glm::vec3& max) const { · 26 unmodified lines
453453 glm::vec3 clampedCorner = glm::clamp(_corner, min, max);
454454 glm::vec3 clampedTopFarLeft = glm::clamp(calcTopFarLeft(), min, max);
455455 glm::vec3 clampedScale = clampedTopFarLeft - clampedCorner;
456−
456+
457457 return AABox(clampedCorner, clampedScale);
458458 }
459459
@@ -461,7 +461,7 @@ AABox AABox::clamp(float min, float max) const { · 1 unmodified line
461461 glm::vec3 clampedCorner = glm::clamp(_corner, min, max);
462462 glm::vec3 clampedTopFarLeft = glm::clamp(calcTopFarLeft(), min, max);
463463 glm::vec3 clampedScale = clampedTopFarLeft - clampedCorner;
464−
464+
465465 return AABox(clampedCorner, clampedScale);
466466 }
467467
libraries/shared/src/AACube.cpp+35−35
@@ -21,14 +21,14 @@ AACube::AACube(const AABox& other) : · 20 unmodified lines
2121 _corner(other.getCorner()), _scale(other.getLargestDimension()) {
2222 }
2323
24−AACube::AACube(const Extents& other) :
25− _corner(other.minimum)
24+AACube::AACube(const Extents& other) :
25+ _corner(other.minimum)
2626 {
2727 glm::vec3 dimensions = other.maximum - other.minimum;
2828 _scale = glm::max(dimensions.x, dimensions.y, dimensions.z);
2929 }
3030
31−AACube::AACube(const glm::vec3& corner, float size) :
31+AACube::AACube(const glm::vec3& corner, float size) :
3232 _corner(corner), _scale(size) {
3333 };
3434
@@ -38,13 +38,13 @@ AACube::AACube() : _corner(0,0,0), _scale(0) { · 3 unmodified lines
3838 glm::vec3 AACube::calcCenter() const {
3939 glm::vec3 center(_corner);
4040 center += (glm::vec3(_scale, _scale, _scale) * 0.5f);
41− return center;
41+ return center;
4242 }
4343
44−glm::vec3 AACube::calcTopFarLeft() const {
44+glm::vec3 AACube::calcTopFarLeft() const {
4545 glm::vec3 topFarLeft(_corner);
4646 topFarLeft += glm::vec3(_scale, _scale, _scale);
47− return topFarLeft;
47+ return topFarLeft;
4848 };
4949
5050 void AACube::scale(float scale) {
@@ -135,9 +135,9 @@ bool AACube::contains(const AACube& otherCube) const { · 84 unmodified lines
135135 bool AACube::touches(const AACube& otherCube) const {
136136 glm::vec3 relativeCenter = _corner - otherCube._corner + (glm::vec3(_scale - otherCube._scale) * 0.5f);
137137 float totalHalfScale = 0.5f * (_scale + otherCube._scale);
138− return fabs(relativeCenter.x) <= totalHalfScale &&
139− fabs(relativeCenter.y) <= totalHalfScale &&
140− fabs(relativeCenter.z) <= totalHalfScale;
138+ return fabsf(relativeCenter.x) <= totalHalfScale &&
139+ fabsf(relativeCenter.y) <= totalHalfScale &&
140+ fabsf(relativeCenter.z) <= totalHalfScale;
141141 }
142142
143143 bool AACube::contains(const AABox& otherBox) const {
@@ -154,10 +154,10 @@ bool AACube::touches(const AABox& otherBox) const { · 10 unmodified lines
154154 glm::vec3 myDimensions = glm::vec3(_scale);
155155 glm::vec3 relativeCenter = _corner - otherBox.getCorner() + ((myDimensions - otherBox.getScale()) * 0.5f);
156156 glm::vec3 totalHalfScale = (myDimensions + otherBox.getDimensions()) * 0.5f;
157−
158− return fabs(relativeCenter.x) <= totalHalfScale.x &&
159− fabs(relativeCenter.y) <= totalHalfScale.y &&
160− fabs(relativeCenter.z) <= totalHalfScale.z;
157+
158+ return fabsf(relativeCenter.x) <= totalHalfScale.x &&
159+ fabsf(relativeCenter.y) <= totalHalfScale.y &&
160+ fabsf(relativeCenter.z) <= totalHalfScale.z;
161161 }
162162
163163 // determines whether a value is within the expanded extents
@@ -222,7 +222,7 @@ bool AACube::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& · 58 unmodified lines
222222 bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const {
223223 // handle the trivial case where the box contains the origin
224224 if (contains(origin)) {
225−
225+
226226 // We still want to calculate the distance from the origin to the inside out plane
227227 float axisDistance;
228228 if ((findInsideOutIntersection(origin.x, direction.x, _corner.x, _scale, axisDistance) && axisDistance >= 0 &&
@@ -243,14 +243,14 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc · 14 unmodified lines
243243 isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) &&
244244 isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) {
245245 distance = axisDistance;
246− face = direction.z > 0 ? MAX_Z_FACE : MIN_Z_FACE;
246+ face = direction.z > 0 ? MAX_Z_FACE : MIN_Z_FACE;
247247 return true;
248248 }
249249 // This case is unexpected, but mimics the previous behavior for inside out intersections
250250 distance = 0;
251251 return true;
252252 }
253−
253+
254254 // check each axis
255255 float axisDistance;
256256 if ((findIntersection(origin.x, direction.x, _corner.x, _scale, axisDistance) && axisDistance >= 0 &&
@@ -271,7 +271,7 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc · 14 unmodified lines
271271 isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) &&
272272 isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) {
273273 distance = axisDistance;
274− face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE;
274+ face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE;
275275 return true;
276276 }
277277 return false;
@@ -279,7 +279,7 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc · 1 unmodified line
279279
280280 bool AACube::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const {
281281 glm::vec4 center4 = glm::vec4(center, 1.0f);
282−
282+
283283 float minPenetrationLength = FLT_MAX;
284284 for (int i = 0; i < FACE_COUNT; i++) {
285285 glm::vec4 facePlane = getPlane((BoxFace)i);
@@ -296,7 +296,7 @@ bool AACube::findSpherePenetration(const glm::vec3& center, float radius, glm::v · 10 unmodified lines
296296 minPenetrationLength = vectorLength;
297297 }
298298 }
299−
299+
300300 return true;
301301 }
302302
@@ -304,7 +304,7 @@ bool AACube::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end · 1 unmodified line
304304 glm::vec4 start4 = glm::vec4(start, 1.0f);
305305 glm::vec4 end4 = glm::vec4(end, 1.0f);
306306 glm::vec4 startToEnd = glm::vec4(end - start, 0.0f);
307−
307+
308308 float minPenetrationLength = FLT_MAX;
309309 for (int i = 0; i < FACE_COUNT; i++) {
310310 // find the vector from the segment to the closest point on the face (starting from deeper end)
@@ -323,8 +323,8 @@ bool AACube::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end · 12 unmodified lines
323323 vector * ((vectorLength + radius) / -vectorLength);
324324 minPenetrationLength = vectorLength;
325325 }
326− }
327−
326+ }
327+
328328 return true;
329329 }
330330
@@ -333,23 +333,23 @@ glm::vec3 AACube::getClosestPointOnFace(const glm::vec3& point, BoxFace face) co · 2 unmodified lines
333333 case MIN_X_FACE:
334334 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
335335 glm::vec3(_corner.x, _corner.y + _scale, _corner.z + _scale));
336−
336+
337337 case MAX_X_FACE:
338338 return glm::clamp(point, glm::vec3(_corner.x + _scale, _corner.y, _corner.z),
339339 glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale));
340−
340+
341341 case MIN_Y_FACE:
342342 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
343343 glm::vec3(_corner.x + _scale, _corner.y, _corner.z + _scale));
344−
344+
345345 case MAX_Y_FACE:
346346 return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _scale, _corner.z),
347347 glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale));
348−
348+
349349 case MIN_Z_FACE:
350350 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
351351 glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z));
352−
352+
353353 default: //quiet windows warnings
354354 case MAX_Z_FACE:
355355 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _scale),
@@ -372,7 +372,7 @@ glm::vec3 AACube::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4 · 16 unmodified lines
372372 }
373373 anyOutside = true;
374374 float divisor = glm::dot(direction, iPlane);
375− if (fabs(divisor) < EPSILON) {
375+ if (fabsf(divisor) < EPSILON) {
376376 continue; // segment is parallel to plane
377377 }
378378 // find intersection and see if it lies within face bounds
@@ -388,29 +388,29 @@ glm::vec3 AACube::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4 · 9 unmodified lines
388388 }
389389 }
390390 return getClosestPointOnFace(glm::vec3(intersection), face);
391−
391+
392392 outerContinue: ;
393393 }
394−
394+
395395 // if we were outside any of the sides, we must check against the diagonals
396396 if (anyOutside) {
397397 int faceAxis = face / 2;
398398 int secondAxis = (faceAxis + 1) % 3;
399399 int thirdAxis = (faceAxis + 2) % 3;
400−
400+
401401 glm::vec4 secondAxisMinPlane = getPlane((BoxFace)(secondAxis * 2));
402402 glm::vec4 secondAxisMaxPlane = getPlane((BoxFace)(secondAxis * 2 + 1));
403403 glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1));
404−
404+
405405 glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f,
406406 glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), glm::vec3(_scale, _scale, _scale)) * 0.5f);
407407 glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset,
408408 secondAxisMaxPlane + thirdAxisMaxPlane + offset };
409−
409+
410410 float minDistance = FLT_MAX;
411411 for (size_t i = 0; i < sizeof(diagonals) / sizeof(diagonals[0]); i++) {
412412 float divisor = glm::dot(direction, diagonals[i]);
413− if (fabs(divisor) < EPSILON) {
413+ if (fabsf(divisor) < EPSILON) {
414414 continue; // segment is parallel to diagonal plane
415415 }
416416 minDistance = glm::min(-glm::dot(origin, diagonals[i]) / divisor, minDistance);
@@ -419,7 +419,7 @@ glm::vec3 AACube::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4 · 2 unmodified lines
419419 return getClosestPointOnFace(glm::vec3(origin + direction * minDistance), face);
420420 }
421421 }
422−
422+
423423 // last resort or all inside: clamp origin to face
424424 return getClosestPointOnFace(glm::vec3(origin), face);
425425 }
libraries/shared/src/AngularConstraint.cpp+1−1
@@ -120,7 +120,7 @@ bool HingeConstraint::clamp(glm::quat& rotation) const { · 119 unmodified lines
120120 forward /= length;
121121 float sign = (glm::dot(glm::cross(_forwardAxis, forward), _rotationAxis) > 0.0f ? 1.0f : -1.0f);
122122 //float angle = sign * acos(glm::dot(forward, _forwardAxis) / length);
123− float angle = sign * acos(glm::dot(forward, _forwardAxis));
123+ float angle = sign * acosf(glm::dot(forward, _forwardAxis));
124124 glm::quat newRotation = glm::angleAxis(clampAngle(angle, _minAngle, _maxAngle), _rotationAxis);
125125 if (fabsf(1.0f - glm::dot(newRotation, rotation)) > EPSILON * EPSILON) {
126126 rotation = newRotation;
libraries/shared/src/GLMHelpers.cpp+1−1
@@ -238,7 +238,7 @@ glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) { · 237 unmodified lines
238238 float sd10 = previous[0][1] * previous[2][2] - previous[2][1] * previous[0][2];
239239 float sd20 = previous[0][1] * previous[1][2] - previous[1][1] * previous[0][2];
240240 float det = previous[0][0] * sd00 + previous[2][0] * sd20 - previous[1][0] * sd10;
241− if (fabs(det) == 0.0f) {
241+ if (fabsf(det) == 0.0f) {
242242 // determinant is zero; matrix is not invertible
243243 break;
244244 }
libraries/shared/src/GLMHelpers.h+24−0
@@ -28,10 +28,19 @@ using glm::vec3; · 27 unmodified lines
2828 using glm::vec4;
2929 using glm::quat;
3030
31+#ifdef __GNUC__
32+#pragma GCC diagnostic push
33+#pragma GCC diagnostic ignored "-Wdouble-promotion"
34+#endif
35+
3136 #include <QtCore/QByteArray>
3237 #include <QtGui/QMatrix4x4>
3338 #include <QtGui/QColor>
3439
40+#ifdef __GNUC__
41+#pragma GCC diagnostic pop
42+#endif
43+
3544 #include "SharedUtil.h"
3645
3746 // this is where the coordinate system is represented
@@ -122,6 +131,21 @@ float aspect(const T& t) { · 84 unmodified lines
122131 return (float)t.x / (float)t.y;
123132 }
124133
134+// Take values in an arbitrary range [0, size] and convert them to the range [0, 1]
135+template <typename T>
136+T toUnitScale(const T& value, const T& size) {
137+ return value / size;
138+}
139+
140+// Take values in an arbitrary range [0, size] and convert them to the range [0, 1]
141+template <typename T>
142+T toNormalizedDeviceScale(const T& value, const T& size) {
143+ vec2 result = toUnitScale(value, size);
144+ result *= 2.0f;
145+ result -= 1.0f;
146+ return result;
147+}
148+
125149 #define YAW(euler) euler.y
126150 #define PITCH(euler) euler.x
127151 #define ROLL(euler) euler.z
libraries/shared/src/MatrixStack.h+5−1
@@ -118,11 +118,15 @@ public: · 117 unmodified lines
118118
119119 template <typename Function>
120120 void withPush(Function f) {
121+ #ifndef NDEBUG
121122 size_t startingDepth = size();
123+ #endif
122124 push();
123125 f();
124126 pop();
125− assert(startingDepth = size());
127+ #ifndef NDEBUG
128+ assert(startingDepth == size());
129+ #endif
126130 }
127131
128132 template <typename Function>
libraries/shared/src/OctalCode.cpp+33−33
@@ -47,7 +47,7 @@ void printOctalCode(const unsigned char* octalCode) { · 46 unmodified lines
4747
4848 char sectionValue(const unsigned char* startByte, char startIndexInByte) {
4949 char rightShift = 8 - startIndexInByte - 3;
50−
50+
5151 if (rightShift < 0) {
5252 return ((startByte[0] << -rightShift) & 7) + (startByte[1] >> (8 + rightShift));
5353 } else {
@@ -65,7 +65,7 @@ size_t bytesRequiredForCodeLength(unsigned char threeBitCodes) { · 11 unmodified lines
6565
6666 int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsigned char* descendantOctalCode) {
6767 int parentSections = numberOfThreeBitSectionsInCode(ancestorOctalCode);
68−
68+
6969 int branchStartBit = parentSections * 3;
7070 // Note: this does not appear to be "multi-byte length code" safe. When octal codes are larger than 255 bytes
7171 // long, the length code is stored in two bytes. The "1" below appears to assume that the length is always one
@@ -74,45 +74,45 @@ int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsi · 2 unmodified lines
7474 }
7575
7676 unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNumber) {
77−
77+
7878 // find the length (in number of three bit code sequences)
7979 // in the parent
8080 int parentCodeSections = parentOctalCode
8181 ? numberOfThreeBitSectionsInCode(parentOctalCode)
8282 : 0;
83−
83+
8484 // get the number of bytes used by the parent octal code
8585 size_t parentCodeBytes = bytesRequiredForCodeLength(parentCodeSections);
86−
86+
8787 // child code will have one more section than the parent
8888 size_t childCodeBytes = bytesRequiredForCodeLength(parentCodeSections + 1);
89−
89+
9090 // create a new buffer to hold the new octal code
9191 unsigned char* newCode = new unsigned char[childCodeBytes];
92−
92+
9393 // copy the parent code to the child
9494 if (parentOctalCode) {
9595 memcpy(newCode, parentOctalCode, parentCodeBytes);
96− }
97−
96+ }
97+
9898 // the child octal code has one more set of three bits
9999 *newCode = parentCodeSections + 1;
100−
100+
101101 if (childCodeBytes > parentCodeBytes) {
102102 // we have a new byte due to the addition of the child code
103103 // so set it to zero for correct results when shifting later
104104 newCode[childCodeBytes - 1] = 0;
105105 }
106−
106+
107107 // add the child code bits to newCode
108−
108+
109109 // find the start bit index
110110 int startBit = parentCodeSections * 3;
111−
111+
112112 // calculate the amount of left shift required
113113 // this will be -1 or -2 if there's wrap
114114 char leftShift = 8 - (startBit % 8) - 3;
115−
115+
116116 if (leftShift < 0) {
117117 // we have a wrap-around to accomodate
118118 // right shift for the end of first byte
@@ -123,7 +123,7 @@ unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNu · 4 unmodified lines
123123 // no wraparound, left shift and add
124124 newCode[(startBit / 8) + 1] += (childNumber << leftShift);
125125 }
126−
126+
127127 return newCode;
128128 }
129129
@@ -135,9 +135,9 @@ void voxelDetailsForCode(const unsigned char* octalCode, VoxelPositionSize& voxe · 5 unmodified lines
135135 if (octalCode) {
136136 for (int i = 0; i < numberOfThreeBitSectionsInCode(octalCode); i++) {
137137 currentScale *= 0.5f;
138− int sectionIndex = sectionValue(octalCode + 1 + (BITS_IN_OCTAL * i / BITS_IN_BYTE),
138+ int sectionIndex = sectionValue(octalCode + 1 + (BITS_IN_OCTAL * i / BITS_IN_BYTE),
139139 (BITS_IN_OCTAL * i) % BITS_IN_BYTE);
140−
140+
141141 for (int j = 0; j < BITS_IN_OCTAL; j++) {
142142 output[j] += currentScale * (float)oneAtBit(sectionIndex, (BITS_IN_BYTE - BITS_IN_OCTAL) + j);
143143 }
@@ -151,17 +151,17 @@ void voxelDetailsForCode(const unsigned char* octalCode, VoxelPositionSize& voxe · 7 unmodified lines
151151
152152 void copyFirstVertexForCode(const unsigned char* octalCode, float* output) {
153153 memset(output, 0, 3 * sizeof(float));
154−
154+
155155 float currentScale = 0.5f;
156−
156+
157157 for (int i = 0; i < numberOfThreeBitSectionsInCode(octalCode); i++) {
158158 int sectionIndex = sectionValue(octalCode + 1 + (3 * i / 8), (3 * i) % 8);
159−
159+
160160 for (int j = 0; j < 3; j++) {
161161 output[j] += currentScale * (int)oneAtBit(sectionIndex, 5 + j);
162162 }
163−
164− currentScale *= 0.5;
163+
164+ currentScale *= 0.5f;
165165 }
166166 }
167167
@@ -171,7 +171,7 @@ OctalCodeComparison compareOctalCodes(const unsigned char* codeA, const unsigned · 3 unmodified lines
171171 }
172172
173173 OctalCodeComparison result = LESS_THAN; // assume it's shallower
174−
174+
175175 size_t numberOfBytes = std::min(bytesRequiredForCodeLength(*codeA), bytesRequiredForCodeLength(*codeB));
176176 int compare = memcmp(codeA, codeB, numberOfBytes);
177177
@@ -205,7 +205,7 @@ char getOctalCodeSectionValue(const unsigned char* octalCode, int section) { · 27 unmodified lines
205205 int startAtByte = 1 + (BITS_IN_OCTAL * section / BITS_IN_BYTE);
206206 char startIndexInByte = (BITS_IN_OCTAL * section) % BITS_IN_BYTE;
207207 const unsigned char* startByte = octalCode + startAtByte;
208−
208+
209209 return sectionValue(startByte, startIndexInByte);
210210 }
211211
@@ -227,7 +227,7 @@ void setOctalCodeSectionValue(unsigned char* octalCode, int section, char sectio · 15 unmodified lines
227227 unsigned char oldValue = *byteAt & ~shiftedMask;
228228 unsigned char newValue = oldValue | shiftedValue;
229229 *byteAt = newValue;
230−
230+
231231 // If the requested section is partially in the byte, then we
232232 // need to also set the portion of the section value in the next byte
233233 // there's only two cases where this happens, if the bit in byte is
@@ -255,7 +255,7 @@ unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLev · 21 unmodified lines
255255 int newLength = codeLength - chopLevels;
256256 newCode = new unsigned char[newLength+1];
257257 *newCode = newLength; // set the length byte
258−
258+
259259 for (int section = chopLevels; section < codeLength; section++) {
260260 char sectionValue = getOctalCodeSectionValue(originalOctalCode, section);
261261 setOctalCodeSectionValue(newCode, section - chopLevels, sectionValue);
@@ -264,9 +264,9 @@ unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLev · 2 unmodified lines
264264 return newCode;
265265 }
266266
267−unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode,
267+unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode,
268268 bool includeColorSpace) {
269−
269+
270270 int oldCodeLength = numberOfThreeBitSectionsInCode(originalOctalCode);
271271 int newParentCodeLength = numberOfThreeBitSectionsInCode(newParentOctalCode);
272272 int newCodeLength = newParentCodeLength + oldCodeLength;
@@ -298,12 +298,12 @@ bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* po · 25 unmodified lines
298298 }
299299
300300 int descendentCodeLength = numberOfThreeBitSectionsInCode(possibleDescendent);
301−
301+
302302 // if the caller also include a child, then our descendent length is actually one extra!
303303 if (descendentsChild != CHECK_NODE_ONLY) {
304304 descendentCodeLength++;
305305 }
306−
306+
307307 if (ancestorCodeLength > descendentCodeLength) {
308308 return false; // if the descendent is shorter, it can't be a descendent
309309 }
@@ -322,7 +322,7 @@ bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* po · 12 unmodified lines
322322 return false; // first non-match, means they don't match
323323 }
324324 }
325−
325+
326326 // they all match, so we are an ancestor
327327 return true;
328328 }
@@ -335,7 +335,7 @@ unsigned char* hexStringToOctalCode(const QString& input) { · 6 unmodified lines
335335
336336 // allocate byte array based on half of string length
337337 unsigned char* bytes = new unsigned char[(input.length()) / HEX_BYTE_SIZE];
338−
338+
339339 // loop through the string - 2 bytes at a time converting
340340 // it to decimal equivalent and store in byte array
341341 bool ok = false;
@@ -348,7 +348,7 @@ unsigned char* hexStringToOctalCode(const QString& input) { · 6 unmodified lines
348348 stringIndex += HEX_BYTE_SIZE;
349349 byteArrayIndex++;
350350 }
351−
351+
352352 // something went wrong
353353 if (!ok) {
354354 delete[] bytes;
libraries/shared/src/PhysicsCollisionGroups.h+1−1
@@ -55,7 +55,7 @@ const int16_t COLLISION_GROUP_COLLISIONLESS = 1 << 15; · 54 unmodified lines
5555 const int16_t COLLISION_MASK_DEFAULT = ~ COLLISION_GROUP_COLLISIONLESS;
5656
5757 // STATIC also doesn't collide with other STATIC
58−const int16_t COLLISION_MASK_STATIC = ~ (COLLISION_GROUP_COLLISIONLESS | COLLISION_MASK_STATIC);
58+const int16_t COLLISION_MASK_STATIC = ~ (COLLISION_GROUP_COLLISIONLESS | COLLISION_GROUP_STATIC);
5959
6060 const int16_t COLLISION_MASK_KINEMATIC = COLLISION_MASK_DEFAULT;
6161
libraries/shared/src/RegisteredMetaTypes.cpp+12−0
@@ -20,6 +20,7 @@ · 19 unmodified lines
2020
2121 static int vec4MetaTypeId = qRegisterMetaType<glm::vec4>();
2222 static int vec3MetaTypeId = qRegisterMetaType<glm::vec3>();
23+static int qVectorVec3MetaTypeId = qRegisterMetaType<QVector<glm::vec3>>();
2324 static int vec2MetaTypeId = qRegisterMetaType<glm::vec2>();
2425 static int quatMetaTypeId = qRegisterMetaType<glm::quat>();
2526 static int xColorMetaTypeId = qRegisterMetaType<xColor>();
@@ -31,6 +32,7 @@ static int collisionMetaTypeId = qRegisterMetaType<Collision>(); · 5 unmodified lines
3132 void registerMetaTypes(QScriptEngine* engine) {
3233 qScriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue);
3334 qScriptRegisterMetaType(engine, vec3toScriptValue, vec3FromScriptValue);
35+ qScriptRegisterMetaType(engine, qVectorVec3ToScriptValue, qVectorVec3FromScriptValue);
3436 qScriptRegisterMetaType(engine, vec2toScriptValue, vec2FromScriptValue);
3537 qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue);
3638 qScriptRegisterMetaType(engine, qRectToScriptValue, qRectFromScriptValue);
@@ -93,6 +95,16 @@ QVector<glm::vec3> qVectorVec3FromScriptValue(const QScriptValue& array){ · 56 unmodified lines
9395 return newVector;
9496 }
9597
98+void qVectorVec3FromScriptValue(const QScriptValue& array, QVector<glm::vec3>& vector ) {
99+ int length = array.property("length").toInteger();
100+
101+ for (int i = 0; i < length; i++) {
102+ glm::vec3 newVec3 = glm::vec3();
103+ vec3FromScriptValue(array.property(i), newVec3);
104+ vector << newVec3;
105+ }
106+}
107+
96108 QScriptValue vec2toScriptValue(QScriptEngine* engine, const glm::vec2 &vec2) {
97109 QScriptValue obj = engine->newObject();
98110 obj.setProperty("x", vec2.x);
libraries/shared/src/RegisteredMetaTypes.h+1−0
@@ -57,6 +57,7 @@ QScriptValue qURLToScriptValue(QScriptEngine* engine, const QUrl& url); · 56 unmodified lines
5757 void qURLFromScriptValue(const QScriptValue& object, QUrl& url);
5858
5959 QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector<glm::vec3>& vector);
60+void qVectorVec3FromScriptValue(const QScriptValue& array, QVector<glm::vec3>& vector);
6061 QVector<glm::vec3> qVectorVec3FromScriptValue( const QScriptValue& array);
6162
6263 class PickRay {
libraries/shared/src/ShapeCollider.cpp+1−1
@@ -881,7 +881,7 @@ bool capsuleVsAACube(const Shape* shapeA, const Shape* shapeB, CollisionList& co · 880 unmodified lines
881881 faceNormal = glm::vec3(0.0f, 0.0f, signs.z);
882882 }
883883
884− if (fabs(glm::dot(faceNormal, capsuleAxis)) < EPSILON) {
884+ if (fabsf(glm::dot(faceNormal, capsuleAxis)) < EPSILON) {
885885 if (glm::dot(nearestApproach, faceNormal) > cubeB->getScale() + capsuleA->getRadius()) {
886886 return false;
887887 }
libraries/shared/src/Transform.h+2−2
@@ -29,7 +29,7 @@ inline bool isValidScale(glm::vec3 scale) { · 28 unmodified lines
2929 }
3030
3131 inline bool isValidScale(float scale) {
32− bool result = scale != 0.0f;
32+ bool result = scale != 0.0f && !glm::isnan(scale) && !glm::isinf(scale);
3333 assert(result);
3434 return result;
3535 }
@@ -323,7 +323,7 @@ inline void Transform::setScale(const Vec3& scale) { · 287 unmodified lines
323323 }
324324
325325 inline void Transform::postScale(float scale) {
326− if (isValidScale(scale) || scale == 1.0f) {
326+ if (!isValidScale(scale) || scale == 1.0f) {
327327 return;
328328 }
329329 if (isScaling()) {
libraries/shared/src/VariantMapToScriptValue.cpp+39−13
@@ -13,35 +13,61 @@ · 12 unmodified lines
1313 #include "SharedLogging.h"
1414 #include "VariantMapToScriptValue.h"
1515
16−QScriptValue variantMapToScriptValue(QVariantMap& variantMap, QScriptEngine& scriptEngine) {
17− QScriptValue scriptValue = scriptEngine.newObject();
18−
19− for (QVariantMap::const_iterator iter = variantMap.begin(); iter != variantMap.end(); ++iter) {
20− QString key = iter.key();
21− QVariant qValue = iter.value();
2216
23− switch(qValue.type()) {
17+QScriptValue variantToScriptValue(QVariant& qValue, QScriptEngine& scriptEngine) {
18+ switch(qValue.type()) {
2419 case QVariant::Bool:
25− scriptValue.setProperty(key, qValue.toBool());
20+ return qValue.toBool();
2621 break;
2722 case QVariant::Int:
28− scriptValue.setProperty(key, qValue.toInt());
23+ return qValue.toInt();
2924 break;
3025 case QVariant::Double:
31− scriptValue.setProperty(key, qValue.toDouble());
26+ return qValue.toDouble();
3227 break;
3328 case QVariant::String: {
34− scriptValue.setProperty(key, scriptEngine.newVariant(qValue));
29+ return scriptEngine.newVariant(qValue);
3530 break;
3631 }
3732 case QVariant::Map: {
3833 QVariantMap childMap = qValue.toMap();
39− scriptValue.setProperty(key, variantMapToScriptValue(childMap, scriptEngine));
34+ return variantMapToScriptValue(childMap, scriptEngine);
35+ break;
36+ }
37+ case QVariant::List: {
38+ QVariantList childList = qValue.toList();
39+ return variantListToScriptValue(childList, scriptEngine);
4040 break;
4141 }
4242 default:
4343 qCDebug(shared) << "unhandled QScript type" << qValue.type();
44− }
44+ break;
45+ }
46+
47+ return QScriptValue();
48+}
49+
50+
51+QScriptValue variantMapToScriptValue(QVariantMap& variantMap, QScriptEngine& scriptEngine) {
52+ QScriptValue scriptValue = scriptEngine.newObject();
53+
54+ for (QVariantMap::const_iterator iter = variantMap.begin(); iter != variantMap.end(); ++iter) {
55+ QString key = iter.key();
56+ QVariant qValue = iter.value();
57+ scriptValue.setProperty(key, variantToScriptValue(qValue, scriptEngine));
58+ }
59+
60+ return scriptValue;
61+}
62+
63+
64+QScriptValue variantListToScriptValue(QVariantList& variantList, QScriptEngine& scriptEngine) {
65+ QScriptValue scriptValue = scriptEngine.newObject();
66+
67+ scriptValue.setProperty("length", variantList.size());
68+ int i = 0;
69+ foreach (QVariant v, variantList) {
70+ scriptValue.setProperty(i++, variantToScriptValue(v, scriptEngine));
4571 }
4672
4773 return scriptValue;
libraries/shared/src/VariantMapToScriptValue.h+2−0
@@ -13,4 +13,6 @@ · 12 unmodified lines
1313 #include <QScriptValue>
1414 #include <QScriptEngine>
1515
16+QScriptValue variantToScriptValue(QVariant& qValue, QScriptEngine& scriptEngine);
1617 QScriptValue variantMapToScriptValue(QVariantMap& variantMap, QScriptEngine& scriptEngine);
18+QScriptValue variantListToScriptValue(QVariantList& variantList, QScriptEngine& scriptEngine);
libraries/ui/src/Tooltip.cpp+51−0
@@ -0,0 +1,51 @@
1+//
2+// Tooltip.cpp
3+//
4+// Created by Bradley Austin Davis on 2015/04/14
5+// Copyright 2015 High Fidelity, Inc.
6+//
7+// Distributed under the Apache License, Version 2.0.
8+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
9+//
10+#include "Tooltip.h"
11+#include <QUuid>
12+
13+HIFI_QML_DEF(Tooltip)
14+
15+Tooltip::Tooltip(QQuickItem* parent) : QQuickItem(parent) {
16+}
17+
18+Tooltip::~Tooltip() {
19+}
20+
21+QString Tooltip::text() const {
22+ return _text;
23+}
24+
25+void Tooltip::setText(const QString& arg) {
26+ if (arg != _text) {
27+ _text = arg;
28+ emit textChanged();
29+ }
30+}
31+
32+void Tooltip::setVisible(bool visible) {
33+ QQuickItem::setVisible(visible);
34+}
35+
36+QString Tooltip::showTip(const QString& text) {
37+ const QString newTipId = QUuid().createUuid().toString();
38+ Tooltip::show([&](QQmlContext*, QObject* object) {
39+ object->setObjectName(newTipId);
40+ object->setProperty("text", text);
41+ });
42+ return newTipId;
43+}
44+
45+void Tooltip::closeTip(const QString& tipId) {
46+ auto rootItem = DependencyManager::get<OffscreenUi>()->getRootItem();
47+ QQuickItem* that = rootItem->findChild<QQuickItem*>(tipId);
48+ if (that) {
49+ that->deleteLater();
50+ }
51+}
libraries/ui/src/Tooltip.h+45−0
@@ -0,0 +1,45 @@
1+//
2+// Tooltip.h
3+//
4+// Created by Bradley Austin Davis on 2015/04/14
5+// Copyright 2015 High Fidelity, Inc.
6+//
7+// Distributed under the Apache License, Version 2.0.
8+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
9+//
10+
11+#pragma once
12+#ifndef hifi_Tooltip_h
13+#define hifi_Tooltip_h
14+
15+#include "OffscreenQmlDialog.h"
16+
17+class Tooltip : public QQuickItem
18+{
19+ Q_OBJECT
20+ HIFI_QML_DECL
21+
22+private:
23+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
24+
25+public:
26+ Tooltip(QQuickItem* parent = 0);
27+ virtual ~Tooltip();
28+
29+ QString text() const;
30+
31+ static QString showTip(const QString& text);
32+ static void closeTip(const QString& tipId);
33+
34+public slots:
35+ virtual void setVisible(bool v);
36+ void setText(const QString& arg);
37+
38+signals:
39+ void textChanged();
40+
41+private:
42+ QString _text;
43+};
44+
45+#endif // hifi_Tooltip_h
libraries/ui/src/VrMenu.cpp+2−2
@@ -135,8 +135,8 @@ void VrMenu::setRootMenu(QObject* rootMenu) { · 134 unmodified lines
135135
136136 void VrMenu::addMenu(QMenu* menu) {
137137 Q_ASSERT(!MenuUserData::forObject(menu));
138− QObject * parent = menu->parent();
139− QObject * qmlParent;
138+ QObject* parent = menu->parent();
139+ QObject* qmlParent = nullptr;
140140 if (dynamic_cast<QMenu*>(parent)) {
141141 MenuUserData* userData = MenuUserData::forObject(parent);
142142 qmlParent = findMenuObject(userData->uuid.toString());
tests/physics/src/ShapeColliderTests.cpp+257−257
@@ -116,20 +116,20 @@ void ShapeColliderTests::sphereTouchesSphere() { · 115 unmodified lines
116116 << " ERROR: null collision" << std::endl;
117117 return;
118118 }
119−
119+
120120 // penetration points from sphereA into sphereB
121121 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
122− if (fabs(inaccuracy) > EPSILON) {
122+ if (fabsf(inaccuracy) > EPSILON) {
123123 std::cout << __FILE__ << ":" << __LINE__
124124 << " ERROR: bad penetration: expected = " << expectedPenetration
125125 << " actual = " << collision->_penetration << std::endl;
126126 }
127−
127+
128128 // contactPoint is on surface of sphereA
129129 glm::vec3 AtoB = sphereB.getTranslation() - sphereA.getTranslation();
130130 glm::vec3 expectedContactPoint = sphereA.getTranslation() + radiusA * glm::normalize(AtoB);
131131 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
132− if (fabs(inaccuracy) > EPSILON) {
132+ if (fabsf(inaccuracy) > EPSILON) {
133133 std::cout << __FILE__ << ":" << __LINE__
134134 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
135135 << " actual = " << collision->_contactPoint << std::endl;
@@ -145,21 +145,21 @@ void ShapeColliderTests::sphereTouchesSphere() { · 9 unmodified lines
145145 } else {
146146 ++numCollisions;
147147 }
148−
148+
149149 // penetration points from sphereA into sphereB
150150 CollisionInfo* collision = collisions.getCollision(numCollisions - 1);
151151 float inaccuracy = glm::length(collision->_penetration + expectedPenetration);
152− if (fabs(inaccuracy) > EPSILON) {
152+ if (fabsf(inaccuracy) > EPSILON) {
153153 std::cout << __FILE__ << ":" << __LINE__
154154 << " ERROR: bad penetration: expected = " << expectedPenetration
155155 << " actual = " << collision->_penetration << std::endl;
156156 }
157−
157+
158158 // contactPoint is on surface of sphereA
159159 glm::vec3 BtoA = sphereA.getTranslation() - sphereB.getTranslation();
160160 glm::vec3 expectedContactPoint = sphereB.getTranslation() + radiusB * glm::normalize(BtoA);
161161 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
162− if (fabs(inaccuracy) > EPSILON) {
162+ if (fabsf(inaccuracy) > EPSILON) {
163163 std::cout << __FILE__ << ":" << __LINE__
164164 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
165165 << " actual = " << collision->_contactPoint << std::endl;
@@ -175,7 +175,7 @@ void ShapeColliderTests::sphereMissesCapsule() { · 9 unmodified lines
175175 float halfHeightB = 1.7f;
176176 float axialOffset = totalRadius + 1.1f * halfHeightB;
177177 float radialOffset = 1.2f * radiusA + 1.3f * radiusB;
178−
178+
179179 SphereShape sphereA(radiusA);
180180 CapsuleShape capsuleB(radiusB, halfHeightB);
181181
@@ -228,7 +228,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 46 unmodified lines
228228 float alpha = 0.5f;
229229 float beta = 0.5f;
230230 float radialOffset = alpha * radiusA + beta * radiusB;
231−
231+
232232 SphereShape sphereA(radiusA);
233233 CapsuleShape capsuleB(radiusB, halfHeightB);
234234
@@ -245,21 +245,21 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 10 unmodified lines
245245 } else {
246246 ++numCollisions;
247247 }
248−
248+
249249 // penetration points from sphereA into capsuleB
250250 CollisionInfo* collision = collisions.getCollision(numCollisions - 1);
251251 glm::vec3 expectedPenetration = (radialOffset - totalRadius) * xAxis;
252252 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
253− if (fabs(inaccuracy) > EPSILON) {
253+ if (fabsf(inaccuracy) > EPSILON) {
254254 std::cout << __FILE__ << ":" << __LINE__
255255 << " ERROR: bad penetration: expected = " << expectedPenetration
256256 << " actual = " << collision->_penetration << std::endl;
257257 }
258−
258+
259259 // contactPoint is on surface of sphereA
260260 glm::vec3 expectedContactPoint = sphereA.getTranslation() - radiusA * xAxis;
261261 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
262− if (fabs(inaccuracy) > EPSILON) {
262+ if (fabsf(inaccuracy) > EPSILON) {
263263 std::cout << __FILE__ << ":" << __LINE__
264264 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
265265 << " actual = " << collision->_contactPoint << std::endl;
@@ -273,7 +273,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 7 unmodified lines
273273 } else {
274274 ++numCollisions;
275275 }
276−
276+
277277 // penetration points from sphereA into capsuleB
278278 collision = collisions.getCollision(numCollisions - 1);
279279 expectedPenetration = - (radialOffset - totalRadius) * xAxis;
@@ -282,12 +282,12 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 2 unmodified lines
282282 expectedPenetration *= -1.0f;
283283 }
284284 inaccuracy = glm::length(collision->_penetration - expectedPenetration);
285− if (fabs(inaccuracy) > EPSILON) {
285+ if (fabsf(inaccuracy) > EPSILON) {
286286 std::cout << __FILE__ << ":" << __LINE__
287287 << " ERROR: bad penetration: expected = " << expectedPenetration
288288 << " actual = " << collision->_penetration << std::endl;
289289 }
290−
290+
291291 // contactPoint is on surface of capsuleB
292292 glm::vec3 BtoA = sphereA.getTranslation() - capsuleB.getTranslation();
293293 glm::vec3 closestApproach = capsuleB.getTranslation() + glm::dot(BtoA, yAxis) * yAxis;
@@ -298,7 +298,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 4 unmodified lines
298298 expectedContactPoint = closestApproach - radiusB * glm::normalize(BtoA - closestApproach);
299299 }
300300 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
301− if (fabs(inaccuracy) > EPSILON) {
301+ if (fabsf(inaccuracy) > EPSILON) {
302302 std::cout << __FILE__ << ":" << __LINE__
303303 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
304304 << " actual = " << collision->_contactPoint << std::endl;
@@ -307,7 +307,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 2 unmodified lines
307307 { // sphereA hits end cap at axis
308308 glm::vec3 axialOffset = (halfHeightB + alpha * radiusA + beta * radiusB) * yAxis;
309309 sphereA.setTranslation(axialOffset);
310−
310+
311311 if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions))
312312 {
313313 std::cout << __FILE__ << ":" << __LINE__
@@ -315,21 +315,21 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 1 unmodified line
315315 } else {
316316 ++numCollisions;
317317 }
318−
318+
319319 // penetration points from sphereA into capsuleB
320320 CollisionInfo* collision = collisions.getCollision(numCollisions - 1);
321321 glm::vec3 expectedPenetration = - ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis;
322322 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
323− if (fabs(inaccuracy) > EPSILON) {
323+ if (fabsf(inaccuracy) > EPSILON) {
324324 std::cout << __FILE__ << ":" << __LINE__
325325 << " ERROR: bad penetration: expected = " << expectedPenetration
326326 << " actual = " << collision->_penetration << std::endl;
327327 }
328−
328+
329329 // contactPoint is on surface of sphereA
330330 glm::vec3 expectedContactPoint = sphereA.getTranslation() - radiusA * yAxis;
331331 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
332− if (fabs(inaccuracy) > EPSILON) {
332+ if (fabsf(inaccuracy) > EPSILON) {
333333 std::cout << __FILE__ << ":" << __LINE__
334334 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
335335 << " actual = " << collision->_contactPoint << std::endl;
@@ -343,7 +343,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 7 unmodified lines
343343 } else {
344344 ++numCollisions;
345345 }
346−
346+
347347 // penetration points from sphereA into capsuleB
348348 collision = collisions.getCollision(numCollisions - 1);
349349 expectedPenetration = ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis;
@@ -352,12 +352,12 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 2 unmodified lines
352352 expectedPenetration *= -1.0f;
353353 }
354354 inaccuracy = glm::length(collision->_penetration - expectedPenetration);
355− if (fabs(inaccuracy) > EPSILON) {
355+ if (fabsf(inaccuracy) > EPSILON) {
356356 std::cout << __FILE__ << ":" << __LINE__
357357 << " ERROR: bad penetration: expected = " << expectedPenetration
358358 << " actual = " << collision->_penetration << std::endl;
359359 }
360−
360+
361361 // contactPoint is on surface of capsuleB
362362 glm::vec3 endPoint;
363363 capsuleB.getEndPoint(endPoint);
@@ -367,7 +367,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 3 unmodified lines
367367 expectedContactPoint = axialOffset - radiusA * yAxis;
368368 }
369369 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
370− if (fabs(inaccuracy) > EPSILON) {
370+ if (fabsf(inaccuracy) > EPSILON) {
371371 std::cout << __FILE__ << ":" << __LINE__
372372 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
373373 << " actual = " << collision->_contactPoint << std::endl;
@@ -376,7 +376,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 2 unmodified lines
376376 { // sphereA hits start cap at axis
377377 glm::vec3 axialOffset = - (halfHeightB + alpha * radiusA + beta * radiusB) * yAxis;
378378 sphereA.setTranslation(axialOffset);
379−
379+
380380 if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions))
381381 {
382382 std::cout << __FILE__ << ":" << __LINE__
@@ -384,21 +384,21 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 1 unmodified line
384384 } else {
385385 ++numCollisions;
386386 }
387−
387+
388388 // penetration points from sphereA into capsuleB
389389 CollisionInfo* collision = collisions.getCollision(numCollisions - 1);
390390 glm::vec3 expectedPenetration = ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis;
391391 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
392− if (fabs(inaccuracy) > EPSILON) {
392+ if (fabsf(inaccuracy) > EPSILON) {
393393 std::cout << __FILE__ << ":" << __LINE__
394394 << " ERROR: bad penetration: expected = " << expectedPenetration
395395 << " actual = " << collision->_penetration << std::endl;
396396 }
397−
397+
398398 // contactPoint is on surface of sphereA
399399 glm::vec3 expectedContactPoint = sphereA.getTranslation() + radiusA * yAxis;
400400 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
401− if (fabs(inaccuracy) > EPSILON) {
401+ if (fabsf(inaccuracy) > EPSILON) {
402402 std::cout << __FILE__ << ":" << __LINE__
403403 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
404404 << " actual = " << collision->_contactPoint << std::endl;
@@ -412,7 +412,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 7 unmodified lines
412412 } else {
413413 ++numCollisions;
414414 }
415−
415+
416416 // penetration points from sphereA into capsuleB
417417 collision = collisions.getCollision(numCollisions - 1);
418418 expectedPenetration = - ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis;
@@ -421,12 +421,12 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 2 unmodified lines
421421 expectedPenetration *= -1.0f;
422422 }
423423 inaccuracy = glm::length(collision->_penetration - expectedPenetration);
424− if (fabs(inaccuracy) > EPSILON) {
424+ if (fabsf(inaccuracy) > EPSILON) {
425425 std::cout << __FILE__ << ":" << __LINE__
426426 << " ERROR: bad penetration: expected = " << expectedPenetration
427427 << " actual = " << collision->_penetration << std::endl;
428428 }
429−
429+
430430 // contactPoint is on surface of capsuleB
431431 glm::vec3 startPoint;
432432 capsuleB.getStartPoint(startPoint);
@@ -436,7 +436,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 3 unmodified lines
436436 expectedContactPoint = axialOffset + radiusA * yAxis;
437437 }
438438 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
439− if (fabs(inaccuracy) > EPSILON) {
439+ if (fabsf(inaccuracy) > EPSILON) {
440440 std::cout << __FILE__ << ":" << __LINE__
441441 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
442442 << " actual = " << collision->_contactPoint << std::endl;
@@ -600,19 +600,19 @@ void ShapeColliderTests::capsuleTouchesCapsule() { · 157 unmodified lines
600600 } else {
601601 ++numCollisions;
602602 }
603−
603+
604604 CollisionInfo* collision = collisions.getCollision(numCollisions - 1);
605605 glm::vec3 expectedPenetration = overlap * xAxis;
606606 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
607− if (fabs(inaccuracy) > EPSILON) {
607+ if (fabsf(inaccuracy) > EPSILON) {
608608 std::cout << __FILE__ << ":" << __LINE__
609609 << " ERROR: bad penetration: expected = " << expectedPenetration
610610 << " actual = " << collision->_penetration << std::endl;
611611 }
612−
612+
613613 glm::vec3 expectedContactPoint = capsuleA.getTranslation() + radiusA * xAxis;
614614 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
615− if (fabs(inaccuracy) > EPSILON) {
615+ if (fabsf(inaccuracy) > EPSILON) {
616616 std::cout << __FILE__ << ":" << __LINE__
617617 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
618618 << " actual = " << collision->_contactPoint << std::endl;
@@ -626,19 +626,19 @@ void ShapeColliderTests::capsuleTouchesCapsule() { · 7 unmodified lines
626626 } else {
627627 ++numCollisions;
628628 }
629−
629+
630630 collision = collisions.getCollision(numCollisions - 1);
631631 expectedPenetration = - overlap * xAxis;
632632 inaccuracy = glm::length(collision->_penetration - expectedPenetration);
633− if (fabs(inaccuracy) > EPSILON) {
633+ if (fabsf(inaccuracy) > EPSILON) {
634634 std::cout << __FILE__ << ":" << __LINE__
635635 << " ERROR: bad penetration: expected = " << expectedPenetration
636636 << " actual = " << collision->_penetration << std::endl;
637637 }
638−
638+
639639 expectedContactPoint = capsuleB.getTranslation() - (radiusB + halfHeightB) * xAxis;
640640 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
641− if (fabs(inaccuracy) > EPSILON) {
641+ if (fabsf(inaccuracy) > EPSILON) {
642642 std::cout << __FILE__ << ":" << __LINE__
643643 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
644644 << " actual = " << collision->_contactPoint << std::endl;
@@ -661,19 +661,19 @@ void ShapeColliderTests::capsuleTouchesCapsule() { · 16 unmodified lines
661661 } else {
662662 ++numCollisions;
663663 }
664−
664+
665665 CollisionInfo* collision = collisions.getCollision(numCollisions - 1);
666666 glm::vec3 expectedPenetration = overlap * zAxis;
667667 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
668− if (fabs(inaccuracy) > EPSILON) {
668+ if (fabsf(inaccuracy) > EPSILON) {
669669 std::cout << __FILE__ << ":" << __LINE__
670670 << " ERROR: bad penetration: expected = " << expectedPenetration
671671 << " actual = " << collision->_penetration << std::endl;
672672 }
673−
673+
674674 glm::vec3 expectedContactPoint = capsuleA.getTranslation() + radiusA * zAxis + shift * yAxis;
675675 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
676− if (fabs(inaccuracy) > EPSILON) {
676+ if (fabsf(inaccuracy) > EPSILON) {
677677 std::cout << __FILE__ << ":" << __LINE__
678678 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
679679 << " actual = " << collision->_contactPoint << std::endl;
@@ -683,7 +683,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() { · 3 unmodified lines
683683
684684 void ShapeColliderTests::sphereMissesAACube() {
685685 CollisionList collisions(16);
686−
686+
687687 float sphereRadius = 1.0f;
688688 glm::vec3 sphereCenter(0.0f);
689689
@@ -702,7 +702,7 @@ void ShapeColliderTests::sphereMissesAACube() { · 12 unmodified lines
702702
703703 sphereCenter = cubeCenter + (0.5f * cubeSide + sphereRadius + offset) * faceNormal;
704704
705− CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
705+ CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
706706 cubeCenter, cubeSide, collisions);
707707
708708 if (collision) {
@@ -742,9 +742,9 @@ void ShapeColliderTests::sphereMissesAACube() { · 33 unmodified lines
742742 for (int m = 0; m < numSteps; ++m) {
743743 sphereCenter = startPosition + ((float)m * delta) * thirdNormal + (sphereRadius + offset) * edgeNormal;
744744
745− CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
745+ CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
746746 cubeCenter, cubeSide, collisions);
747−
747+
748748 if (collision) {
749749 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube edge."
750750 << " edgeNormal = " << edgeNormal << std::endl;
@@ -779,10 +779,10 @@ void ShapeColliderTests::sphereMissesAACube() { · 28 unmodified lines
779779 glm::quat rotation = glm::angleAxis(angle, cornerNormal);
780780 glm::vec3 offsetAxis = rotation * nearbyAxis;
781781 sphereCenter = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide) * cornerNormal + (sphereRadius + offset) * offsetAxis;
782−
783− CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
782+
783+ CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
784784 cubeCenter, cubeSide, collisions);
785−
785+
786786 if (collision) {
787787 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube corner."
788788 << " cornerNormal = " << cornerNormal << std::endl;
@@ -796,7 +796,7 @@ void ShapeColliderTests::sphereMissesAACube() { · 7 unmodified lines
796796
797797 void ShapeColliderTests::sphereTouchesAACubeFaces() {
798798 CollisionList collisions(16);
799−
799+
800800 float sphereRadius = 1.13f;
801801 glm::vec3 sphereCenter(0.0f);
802802
@@ -817,38 +817,38 @@ void ShapeColliderTests::sphereTouchesAACubeFaces() { · 14 unmodified lines
817817 float parallelOffset = 0.5f * cubeSide + sphereRadius - overlap;
818818 float perpOffset = 0.25f * cubeSide;
819819 glm::vec3 expectedPenetration = - overlap * faceNormal;
820−
821− // We rotate the position of the sphereCenter about a circle on the cube face so that
822− // it hits the same face in multiple spots. The penetration should be invarient for
820+
821+ // We rotate the position of the sphereCenter about a circle on the cube face so that
822+ // it hits the same face in multiple spots. The penetration should be invarient for
823823 // all collisions.
824824 float delta = TWO_PI / 4.0f;
825825 for (float angle = 0; angle < TWO_PI + EPSILON; angle += delta) {
826826 glm::quat rotation = glm::angleAxis(angle, faceNormal);
827827 glm::vec3 perpAxis = rotation * faceNormals[(i + 1) % numDirections];
828−
828+
829829 sphereCenter = cubeCenter + parallelOffset * faceNormal + perpOffset * perpAxis;
830−
831− CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
830+
831+ CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
832832 cubeCenter, cubeSide, collisions);
833−
833+
834834 if (!collision) {
835835 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide outside cube face."
836− << " faceNormal = " << faceNormal
836+ << " faceNormal = " << faceNormal
837837 << std::endl;
838838 break;
839839 }
840−
840+
841841 if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) {
842− std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration
842+ std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration
843843 << " expected " << expectedPenetration << " faceNormal = " << faceNormal << std::endl;
844844 }
845−
845+
846846 glm::vec3 expectedContact = sphereCenter - sphereRadius * faceNormal;
847847 if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) {
848− std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint
848+ std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint
849849 << " expected " << expectedContact << " faceNormal = " << faceNormal << std::endl;
850850 }
851−
851+
852852 if (collision->getShapeA()) {
853853 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: collision->_shapeA should be NULL" << std::endl;
854854 }
@@ -857,32 +857,32 @@ void ShapeColliderTests::sphereTouchesAACubeFaces() { · 2 unmodified lines
857857 }
858858 }
859859 }
860−
860+
861861 // inside
862862 {
863863 collisions.clear();
864864 float overlap = 1.25f * sphereRadius;
865865 float sphereOffset = 0.5f * cubeSide + sphereRadius - overlap;
866866 sphereCenter = cubeCenter + sphereOffset * faceNormal;
867−
868− CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
867+
868+ CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
869869 cubeCenter, cubeSide, collisions);
870−
870+
871871 if (!collision) {
872− std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide inside cube face."
872+ std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide inside cube face."
873873 << " faceNormal = " << faceNormal << std::endl;
874874 break;
875875 }
876−
876+
877877 glm::vec3 expectedPenetration = - overlap * faceNormal;
878878 if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) {
879− std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration
879+ std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration
880880 << " expected " << expectedPenetration << " faceNormal = " << faceNormal << std::endl;
881881 }
882−
882+
883883 glm::vec3 expectedContact = sphereCenter - sphereRadius * faceNormal;
884884 if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) {
885− std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint
885+ std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint
886886 << " expected " << expectedContact << " faceNormal = " << faceNormal << std::endl;
887887 }
888888 }
@@ -892,14 +892,14 @@ void ShapeColliderTests::sphereTouchesAACubeFaces() { · 3 unmodified lines
892892
893893 void ShapeColliderTests::sphereTouchesAACubeEdges() {
894894 CollisionList collisions(20);
895−
895+
896896 float sphereRadius = 1.37f;
897897 glm::vec3 sphereCenter(0.0f);
898898
899899 glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f);
900900 float cubeSide = 2.98f;
901901
902− float overlap = 0.25 * sphereRadius;
902+ float overlap = 0.25f * sphereRadius;
903903 int numSteps = 5;
904904
905905 glm::vec3 faceNormals[] = {xAxis, yAxis, zAxis};
@@ -935,23 +935,23 @@ void ShapeColliderTests::sphereTouchesAACubeEdges() { · 29 unmodified lines
935935 for (int m = 0; m < numSteps; ++m) {
936936 sphereCenter = startPosition + ((float)m * delta) * thirdNormal + (sphereRadius - overlap) * edgeNormal;
937937
938− CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
938+ CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
939939 cubeCenter, cubeSide, collisions);
940−
940+
941941 if (!collision) {
942942 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube edge."
943943 << " edgeNormal = " << edgeNormal << std::endl;
944944 break;
945945 }
946−
946+
947947 if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) {
948− std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration
948+ std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration
949949 << " expected " << expectedPenetration << " edgeNormal = " << edgeNormal << std::endl;
950950 }
951−
951+
952952 glm::vec3 expectedContact = sphereCenter - sphereRadius * edgeNormal;
953953 if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) {
954− std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint
954+ std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint
955955 << " expected " << expectedContact << " edgeNormal = " << edgeNormal << std::endl;
956956 }
957957 }
@@ -963,14 +963,14 @@ void ShapeColliderTests::sphereTouchesAACubeEdges() { · 5 unmodified lines
963963
964964 void ShapeColliderTests::sphereTouchesAACubeCorners() {
965965 CollisionList collisions(20);
966−
966+
967967 float sphereRadius = 1.37f;
968968 glm::vec3 sphereCenter(0.0f);
969969
970970 glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f);
971971 float cubeSide = 2.98f;
972972
973− float overlap = 0.25 * sphereRadius;
973+ float overlap = 0.25f * sphereRadius;
974974 int numSteps = 5;
975975
976976 glm::vec3 faceNormals[] = {xAxis, yAxis, zAxis};
@@ -997,25 +997,25 @@ void ShapeColliderTests::sphereTouchesAACubeCorners() { · 20 unmodified lines
997997 glm::quat rotation = glm::angleAxis(angle, cornerNormal);
998998 glm::vec3 offsetAxis = rotation * nearbyAxis;
999999 sphereCenter = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide) * cornerNormal + (sphereRadius - overlap) * offsetAxis;
1000−
1001− CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
1000+
1001+ CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
10021002 cubeCenter, cubeSide, collisions);
1003−
1003+
10041004 if (!collision) {
10051005 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube corner."
10061006 << " cornerNormal = " << cornerNormal << std::endl;
10071007 break;
10081008 }
1009−
1009+
10101010 glm::vec3 expectedPenetration = - overlap * offsetAxis;
10111011 if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) {
1012− std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration
1012+ std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration
10131013 << " expected " << expectedPenetration << " cornerNormal = " << cornerNormal << std::endl;
10141014 }
1015−
1015+
10161016 glm::vec3 expectedContact = sphereCenter - sphereRadius * offsetAxis;
10171017 if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) {
1018− std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint
1018+ std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint
10191019 << " expected " << expectedContact << " cornerNormal = " << cornerNormal << std::endl;
10201020 }
10211021 }
@@ -1026,7 +1026,7 @@ void ShapeColliderTests::sphereTouchesAACubeCorners() { · 4 unmodified lines
10261026
10271027 void ShapeColliderTests::capsuleMissesAACube() {
10281028 CollisionList collisions(16);
1029−
1029+
10301030 float capsuleRadius = 1.0f;
10311031
10321032 glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f);
@@ -1046,7 +1046,7 @@ void ShapeColliderTests::capsuleMissesAACube() { · 13 unmodified lines
10461046 glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections];
10471047
10481048 // pick a random point somewhere above the face
1049− glm::vec3 startPoint = cubeCenter + (cubeSide + capsuleRadius) * faceNormal +
1049+ glm::vec3 startPoint = cubeCenter + (cubeSide + capsuleRadius) * faceNormal +
10501050 (cubeSide * (randFloat() - 0.5f)) * secondNormal +
10511051 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;
10521052
@@ -1097,23 +1097,23 @@ void ShapeColliderTests::capsuleMissesAACube() { · 44 unmodified lines
10971097 glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal);
10981098
10991099 // pick a random point somewhere above the edge
1100− glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_2 * cubeSide + capsuleRadius) * edgeNormal +
1100+ glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_2 * cubeSide + capsuleRadius) * edgeNormal +
11011101 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;
1102−
1102+
11031103 // pick a second random point slightly more than one radius above the edge
11041104 glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide + capsuleRadius + offset) * edgeNormal +
11051105 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;
1106−
1106+
11071107 // randomly swap the points so capsule axis may point toward or away from edge
11081108 if (randFloat() > 0.5f) {
11091109 glm::vec3 temp = startPoint;
11101110 startPoint = endPoint;
11111111 endPoint = temp;
11121112 }
1113−
1113+
11141114 // create a capsule between the points
11151115 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);
1116−
1116+
11171117 // collide capsule with cube
11181118 bool hit = ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions);
11191119 if (hit) {
@@ -1138,24 +1138,24 @@ void ShapeColliderTests::capsuleMissesAACube() { · 18 unmodified lines
11381138 glm::vec3 cornerNormal = glm::normalize(firstNormal + secondNormal + thirdNormal);
11391139
11401140 // pick a random point somewhere above the corner
1141− glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_3 * cubeSide + capsuleRadius) * cornerNormal +
1141+ glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_3 * cubeSide + capsuleRadius) * cornerNormal +
11421142 (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal +
11431143 (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal +
11441144 (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal;
1145−
1145+
11461146 // pick a second random point slightly more than one radius above the corner
11471147 glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide + capsuleRadius + offset) * cornerNormal;
1148−
1148+
11491149 // randomly swap the points so capsule axis may point toward or away from corner
11501150 if (randFloat() > 0.5f) {
11511151 glm::vec3 temp = startPoint;
11521152 startPoint = endPoint;
11531153 endPoint = temp;
11541154 }
1155−
1155+
11561156 // create a capsule between the points
11571157 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);
1158−
1158+
11591159 // collide capsule with cube
11601160 if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {
11611161 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube face."
@@ -1190,7 +1190,7 @@ void ShapeColliderTests::capsuleMissesAACube() { · 28 unmodified lines
11901190 glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal);
11911191
11921192 // pick a random point somewhere along the edge
1193− glm::vec3 edgePoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide) * edgeNormal +
1193+ glm::vec3 edgePoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide) * edgeNormal +
11941194 ((cubeSide - 2.0f * offset) * (randFloat() - 0.5f)) * thirdNormal;
11951195
11961196 // pick a random normal that is deflected slightly from edgeNormal
@@ -1207,10 +1207,10 @@ void ShapeColliderTests::capsuleMissesAACube() { · 10 unmodified lines
12071207 // now we can compute the capsule endpoints
12081208 glm::vec3 endPoint = axisPoint + (0.5f * capsuleLength * randFloat()) * axisDirection;
12091209 glm::vec3 startPoint = axisPoint - (0.5f * capsuleLength * randFloat()) * axisDirection;
1210−
1210+
12111211 // create a capsule between the points
12121212 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);
1213−
1213+
12141214 // collide capsule with cube
12151215 if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {
12161216 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube"
@@ -1241,7 +1241,7 @@ void ShapeColliderTests::capsuleMissesAACube() { · 24 unmodified lines
12411241
12421242 // pick a random point somewhere above the corner
12431243 glm::vec3 corner = cubeCenter + (0.5f * cubeSide) * (firstNormal + secondNormal + thirdNormal);
1244− glm::vec3 startPoint = corner + (3.0f * cubeSide) * cornerNormal +
1244+ glm::vec3 startPoint = corner + (3.0f * cubeSide) * cornerNormal +
12451245 (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal +
12461246 (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal +
12471247 (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal;
@@ -1256,10 +1256,10 @@ void ShapeColliderTests::capsuleMissesAACube() { · 8 unmodified lines
12561256 startPoint = endPoint;
12571257 endPoint = temp;
12581258 }
1259−
1259+
12601260 // create a capsule between the points
12611261 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);
1262−
1262+
12631263 // collide capsule with cube
12641264 if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {
12651265 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube"
@@ -1269,7 +1269,7 @@ void ShapeColliderTests::capsuleMissesAACube() { · 3 unmodified lines
12691269 }
12701270 }
12711271
1272− // capsule sides almost hit cube faces
1272+ // capsule sides almost hit cube faces
12731273 // these are the steps along the capsuleAxis where we'll put the capsule endpoints
12741274 float steps[] = { -1.0f, 2.0f, 0.25f, 0.75f, -1.0f };
12751275
@@ -1280,9 +1280,9 @@ void ShapeColliderTests::capsuleMissesAACube() { · 4 unmodified lines
12801280 glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections];
12811281
12821282 // pick two random point on opposite edges of the face
1283− glm::vec3 firstEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal + secondNormal) +
1283+ glm::vec3 firstEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal + secondNormal) +
12841284 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;
1285− glm::vec3 secondEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal - secondNormal) +
1285+ glm::vec3 secondEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal - secondNormal) +
12861286 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;
12871287
12881288 // compute the un-normalized axis for the capsule
@@ -1309,7 +1309,7 @@ void ShapeColliderTests::capsuleMissesAACube() { · 20 unmodified lines
13091309
13101310 void ShapeColliderTests::capsuleTouchesAACube() {
13111311 CollisionList collisions(16);
1312−
1312+
13131313 float capsuleRadius = 1.0f;
13141314
13151315 glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f);
@@ -1330,12 +1330,12 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 14 unmodified lines
13301330 glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections];
13311331
13321332 // pick a random point somewhere above the face
1333− glm::vec3 startPoint = cubeCenter + (cubeSide + capsuleRadius) * faceNormal +
1333+ glm::vec3 startPoint = cubeCenter + (cubeSide + capsuleRadius) * faceNormal +
13341334 (cubeSide * (randFloat() - 0.5f)) * secondNormal +
13351335 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;
13361336
13371337 // pick a second random point slightly less than one radius above the face
1338− // (but reduce width of range by 2*overlap to prevent the penetration from
1338+ // (but reduce width of range by 2*overlap to prevent the penetration from
13391339 // registering against other faces)
13401340 glm::vec3 endPoint = cubeCenter + (0.5f * cubeSide + capsuleRadius - overlap) * faceNormal +
13411341 ((cubeSide - 2.0f * overlap) * (randFloat() - 0.5f)) * secondNormal +
@@ -1365,25 +1365,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 23 unmodified lines
13651365 << " ERROR: null collision with faceNormal = " << faceNormal << std::endl;
13661366 return;
13671367 }
1368−
1369− // penetration points from capsule into cube
1368+
1369+ // penetration points from capsule into cube
13701370 glm::vec3 expectedPenetration = - overlap * faceNormal;
13711371 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
1372− if (fabs(inaccuracy) > allowableError) {
1372+ if (fabsf(inaccuracy) > allowableError) {
13731373 std::cout << __FILE__ << ":" << __LINE__
13741374 << " ERROR: bad penetration: expected = " << expectedPenetration
1375− << " actual = " << collision->_penetration
1375+ << " actual = " << collision->_penetration
13761376 << " faceNormal = " << faceNormal
13771377 << std::endl;
13781378 }
1379−
1379+
13801380 // contactPoint is on surface of capsule
13811381 glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * faceNormal;
13821382 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
1383− if (fabs(inaccuracy) > allowableError) {
1383+ if (fabsf(inaccuracy) > allowableError) {
13841384 std::cout << __FILE__ << ":" << __LINE__
13851385 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
1386− << " actual = " << collision->_contactPoint
1386+ << " actual = " << collision->_contactPoint
13871387 << " faceNormal = " << faceNormal
13881388 << std::endl;
13891389 }
@@ -1414,24 +1414,24 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 24 unmodified lines
14141414 glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal);
14151415
14161416 // pick a random point somewhere above the edge
1417− glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_2 * cubeSide + capsuleRadius) * edgeNormal +
1417+ glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_2 * cubeSide + capsuleRadius) * edgeNormal +
14181418 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;
1419−
1419+
14201420 // pick a second random point slightly less than one radius above the edge
14211421 glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide + capsuleRadius - overlap) * edgeNormal +
14221422 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;
14231423 glm::vec3 collidingPoint = endPoint;
1424−
1424+
14251425 // randomly swap the points so capsule axis may point toward or away from edge
14261426 if (randFloat() > 0.5f) {
14271427 glm::vec3 temp = startPoint;
14281428 startPoint = endPoint;
14291429 endPoint = temp;
14301430 }
1431−
1431+
14321432 // create a capsule between the points
14331433 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);
1434−
1434+
14351435 // collide capsule with cube
14361436 if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {
14371437 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube"
@@ -1444,25 +1444,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 6 unmodified lines
14441444 << " ERROR: null collision with edgeNormal = " << edgeNormal << std::endl;
14451445 return;
14461446 }
1447−
1448− // penetration points from capsule into cube
1447+
1448+ // penetration points from capsule into cube
14491449 glm::vec3 expectedPenetration = - overlap * edgeNormal;
14501450 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
1451− if (fabs(inaccuracy) > allowableError) {
1451+ if (fabsf(inaccuracy) > allowableError) {
14521452 std::cout << __FILE__ << ":" << __LINE__
14531453 << " ERROR: bad penetration: expected = " << expectedPenetration
1454− << " actual = " << collision->_penetration
1454+ << " actual = " << collision->_penetration
14551455 << " edgeNormal = " << edgeNormal
14561456 << std::endl;
14571457 }
1458−
1458+
14591459 // contactPoint is on surface of capsule
14601460 glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * edgeNormal;
14611461 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
1462− if (fabs(inaccuracy) > allowableError) {
1462+ if (fabsf(inaccuracy) > allowableError) {
14631463 std::cout << __FILE__ << ":" << __LINE__
14641464 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
1465− << " actual = " << collision->_contactPoint
1465+ << " actual = " << collision->_contactPoint
14661466 << " edgeNormal = " << edgeNormal
14671467 << std::endl;
14681468 }
@@ -1484,25 +1484,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 15 unmodified lines
14841484 glm::vec3 cornerNormal = glm::normalize(firstNormal + secondNormal + thirdNormal);
14851485
14861486 // pick a random point somewhere above the corner
1487− glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_3 * cubeSide + capsuleRadius) * cornerNormal +
1487+ glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_3 * cubeSide + capsuleRadius) * cornerNormal +
14881488 (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal +
14891489 (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal +
14901490 (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal;
1491−
1491+
14921492 // pick a second random point slightly less than one radius above the corner
14931493 glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide + capsuleRadius - overlap) * cornerNormal;
14941494 glm::vec3 collidingPoint = endPoint;
1495−
1495+
14961496 // randomly swap the points so capsule axis may point toward or away from corner
14971497 if (randFloat() > 0.5f) {
14981498 glm::vec3 temp = startPoint;
14991499 startPoint = endPoint;
15001500 endPoint = temp;
15011501 }
1502−
1502+
15031503 // create a capsule between the points
15041504 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);
1505−
1505+
15061506 // collide capsule with cube
15071507 if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {
15081508 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube"
@@ -1515,25 +1515,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 6 unmodified lines
15151515 << " ERROR: null collision with cornerNormal = " << cornerNormal << std::endl;
15161516 return;
15171517 }
1518−
1519− // penetration points from capsule into cube
1518+
1519+ // penetration points from capsule into cube
15201520 glm::vec3 expectedPenetration = - overlap * cornerNormal;
15211521 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
1522− if (fabs(inaccuracy) > allowableError) {
1522+ if (fabsf(inaccuracy) > allowableError) {
15231523 std::cout << __FILE__ << ":" << __LINE__
15241524 << " ERROR: bad penetration: expected = " << expectedPenetration
1525− << " actual = " << collision->_penetration
1525+ << " actual = " << collision->_penetration
15261526 << " cornerNormal = " << cornerNormal
15271527 << std::endl;
15281528 }
1529−
1529+
15301530 // contactPoint is on surface of capsule
15311531 glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * cornerNormal;
15321532 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
1533− if (fabs(inaccuracy) > allowableError) {
1533+ if (fabsf(inaccuracy) > allowableError) {
15341534 std::cout << __FILE__ << ":" << __LINE__
15351535 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
1536− << " actual = " << collision->_contactPoint
1536+ << " actual = " << collision->_contactPoint
15371537 << " cornerNormal = " << cornerNormal
15381538 << std::endl;
15391539 }
@@ -1566,7 +1566,7 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 26 unmodified lines
15661566 glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal);
15671567
15681568 // pick a random point somewhere along the edge
1569− glm::vec3 edgePoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide) * edgeNormal +
1569+ glm::vec3 edgePoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide) * edgeNormal +
15701570 ((cubeSide - 2.0f * overlap) * (randFloat() - 0.5f)) * thirdNormal;
15711571
15721572 // pick a random normal that is deflected slightly from edgeNormal
@@ -1583,10 +1583,10 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 10 unmodified lines
15831583 // now we can compute the capsule endpoints
15841584 glm::vec3 endPoint = axisPoint + (0.5f * capsuleLength * randFloat()) * axisDirection;
15851585 glm::vec3 startPoint = axisPoint - (0.5f * capsuleLength * randFloat()) * axisDirection;
1586−
1586+
15871587 // create a capsule between the points
15881588 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);
1589−
1589+
15901590 // collide capsule with cube
15911591 if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {
15921592 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube"
@@ -1599,25 +1599,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 6 unmodified lines
15991599 << " ERROR: null collision with edgeNormal = " << edgeNormal << std::endl;
16001600 return;
16011601 }
1602−
1603− // penetration points from capsule into cube
1602+
1603+ // penetration points from capsule into cube
16041604 glm::vec3 expectedPenetration = - overlap * deflectedNormal;
16051605 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
1606− if (fabs(inaccuracy) > allowableError / capsuleLength) {
1606+ if (fabsf(inaccuracy) > allowableError / capsuleLength) {
16071607 std::cout << __FILE__ << ":" << __LINE__
16081608 << " ERROR: bad penetration: expected = " << expectedPenetration
1609− << " actual = " << collision->_penetration
1609+ << " actual = " << collision->_penetration
16101610 << " edgeNormal = " << edgeNormal
16111611 << std::endl;
16121612 }
1613−
1613+
16141614 // contactPoint is on surface of capsule
16151615 glm::vec3 expectedContactPoint = axisPoint - capsuleRadius * deflectedNormal;
16161616 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
1617− if (fabs(inaccuracy) > allowableError / capsuleLength) {
1617+ if (fabsf(inaccuracy) > allowableError / capsuleLength) {
16181618 std::cout << __FILE__ << ":" << __LINE__
16191619 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
1620− << " actual = " << collision->_contactPoint
1620+ << " actual = " << collision->_contactPoint
16211621 << " edgeNormal = " << edgeNormal
16221622 << std::endl;
16231623 }
@@ -1646,7 +1646,7 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 22 unmodified lines
16461646
16471647 // pick a random point somewhere above the corner
16481648 glm::vec3 corner = cubeCenter + (0.5f * cubeSide) * (firstNormal + secondNormal + thirdNormal);
1649− glm::vec3 startPoint = corner + (3.0f * cubeSide) * cornerNormal +
1649+ glm::vec3 startPoint = corner + (3.0f * cubeSide) * cornerNormal +
16501650 (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal +
16511651 (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal +
16521652 (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal;
@@ -1662,10 +1662,10 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 9 unmodified lines
16621662 startPoint = endPoint;
16631663 endPoint = temp;
16641664 }
1665−
1665+
16661666 // create a capsule between the points
16671667 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);
1668−
1668+
16691669 // collide capsule with cube
16701670 if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {
16711671 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube"
@@ -1678,25 +1678,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 6 unmodified lines
16781678 << " ERROR: null collision with cornerNormal = " << cornerNormal << std::endl;
16791679 return;
16801680 }
1681−
1682− // penetration points from capsule into cube
1681+
1682+ // penetration points from capsule into cube
16831683 glm::vec3 expectedPenetration = overlap * penetrationNormal;
16841684 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
1685− if (fabs(inaccuracy) > allowableError) {
1685+ if (fabsf(inaccuracy) > allowableError) {
16861686 std::cout << __FILE__ << ":" << __LINE__
16871687 << " ERROR: bad penetration: expected = " << expectedPenetration
1688− << " actual = " << collision->_penetration
1688+ << " actual = " << collision->_penetration
16891689 << " cornerNormal = " << cornerNormal
16901690 << std::endl;
16911691 }
1692−
1692+
16931693 // contactPoint is on surface of capsule
16941694 glm::vec3 expectedContactPoint = collidingPoint + capsuleRadius * penetrationNormal;
16951695 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
1696− if (fabs(inaccuracy) > allowableError) {
1696+ if (fabsf(inaccuracy) > allowableError) {
16971697 std::cout << __FILE__ << ":" << __LINE__
16981698 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
1699− << " actual = " << collision->_contactPoint
1699+ << " actual = " << collision->_contactPoint
17001700 << " cornerNormal = " << cornerNormal
17011701 << std::endl;
17021702 }
@@ -1704,7 +1704,7 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 1 unmodified line
17041704 }
17051705 }
17061706
1707− // capsule sides hit cube faces
1707+ // capsule sides hit cube faces
17081708 // these are the steps along the capsuleAxis where we'll put the capsule endpoints
17091709 float steps[] = { -1.0f, 2.0f, 0.25f, 0.75f, -1.0f };
17101710
@@ -1715,9 +1715,9 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 4 unmodified lines
17151715 glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections];
17161716
17171717 // pick two random point on opposite edges of the face
1718− glm::vec3 firstEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal + secondNormal) +
1718+ glm::vec3 firstEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal + secondNormal) +
17191719 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;
1720− glm::vec3 secondEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal - secondNormal) +
1720+ glm::vec3 secondEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal - secondNormal) +
17211721 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;
17221722
17231723 // compute the un-normalized axis for the capsule
@@ -1742,7 +1742,7 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 18 unmodified lines
17421742 if (numCollisions != 2) {
17431743 std::cout << __FILE__ << ":" << __LINE__
17441744 << " ERROR: capsule should hit cube face at two spots."
1745− << " Expected collisions size of 2 but is actually " << numCollisions
1745+ << " Expected collisions size of 2 but is actually " << numCollisions
17461746 << ". faceNormal = " << faceNormal << std::endl;
17471747 break;
17481748 }
@@ -1764,33 +1764,33 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 15 unmodified lines
17641764 expectedContactPoints[0] = startPoint - capsuleRadius * faceNormal;
17651765 expectedContactPoints[1] = firstEdgeIntersection - overlap * faceNormal;
17661766 }
1767−
1767+
17681768 // verify each contact
17691769 for (int k = 0; k < 2; ++k) {
17701770 CollisionInfo* collision = collisions.getCollision(k);
1771− // penetration points from capsule into cube
1771+ // penetration points from capsule into cube
17721772 glm::vec3 expectedPenetration = - overlap * faceNormal;
17731773 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
1774− if (fabs(inaccuracy) > allowableError) {
1774+ if (fabsf(inaccuracy) > allowableError) {
17751775 std::cout << __FILE__ << ":" << __LINE__
17761776 << " ERROR: bad penetration: expected = " << expectedPenetration
1777− << " actual = " << collision->_penetration
1777+ << " actual = " << collision->_penetration
17781778 << " faceNormal = " << faceNormal
17791779 << std::endl;
17801780 }
1781−
1782− // the order of the final contact points is undefined, so we
1783− // figure out which expected contact point is the closest to the real one
1781+
1782+ // the order of the final contact points is undefined, so we
1783+ // figure out which expected contact point is the closest to the real one
17841784 // and then verify accuracy on that
17851785 float length0 = glm::length(collision->_contactPoint - expectedContactPoints[0]);
17861786 float length1 = glm::length(collision->_contactPoint - expectedContactPoints[1]);
17871787 glm::vec3 expectedContactPoint = (length0 < length1) ? expectedContactPoints[0] : expectedContactPoints[1];
17881788 // contactPoint is on surface of capsule
17891789 inaccuracy = (length0 < length1) ? length0 : length1;
1790− if (fabs(inaccuracy) > allowableError) {
1790+ if (fabsf(inaccuracy) > allowableError) {
17911791 std::cout << __FILE__ << ":" << __LINE__
17921792 << " ERROR: bad contact: expectedContactPoint[" << k << "] = " << expectedContactPoint
1793− << " actual = " << collision->_contactPoint
1793+ << " actual = " << collision->_contactPoint
17941794 << " faceNormal = " << faceNormal
17951795 << std::endl;
17961796 }
@@ -1817,14 +1817,14 @@ void ShapeColliderTests::rayHitsSphere() { · 20 unmodified lines
18171817 if (!sphere.findRayIntersection(intersection)) {
18181818 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl;
18191819 }
1820−
1820+
18211821 float expectedDistance = startDistance - radius;
18221822 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;
18231823 if (relativeError > EPSILON) {
18241824 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray sphere intersection distance error = " << relativeError << std::endl;
18251825 }
18261826 if (intersection._hitShape != &sphere) {
1827− std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at sphere"
1827+ std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at sphere"
18281828 << std::endl;
18291829 }
18301830 }
@@ -1834,11 +1834,11 @@ void ShapeColliderTests::rayHitsSphere() { · 3 unmodified lines
18341834 RayIntersectionInfo intersection;
18351835 intersection._rayStart = glm::vec3(startDistance, startDistance, 0.0f);
18361836 intersection._rayDirection = - glm::normalize(intersection._rayStart);
1837−
1837+
18381838 if (!sphere.findRayIntersection(intersection)) {
18391839 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl;
18401840 }
1841−
1841+
18421842 float expectedDistance = SQUARE_ROOT_OF_2 * startDistance - radius;
18431843 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;
18441844 if (relativeError > EPSILON) {
@@ -1864,15 +1864,15 @@ void ShapeColliderTests::rayHitsSphere() { · 19 unmodified lines
18641864
18651865 sphere.setRadius(radius);
18661866 sphere.setTranslation(rotation * translation);
1867−
1867+
18681868 if (!sphere.findRayIntersection(intersection)) {
18691869 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl;
18701870 }
1871−
1871+
18721872 float expectedDistance = startDistance - radius;
18731873 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;
18741874 if (relativeError > EPSILON) {
1875− std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray sphere intersection distance error = "
1875+ std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray sphere intersection distance error = "
18761876 << relativeError << std::endl;
18771877 }
18781878 }
@@ -1890,29 +1890,29 @@ void ShapeColliderTests::rayBarelyHitsSphere() { · 11 unmodified lines
18901890 RayIntersectionInfo intersection;
18911891 intersection._rayStart = glm::vec3(-startDistance, radius - delta, 0.0f);
18921892 intersection._rayDirection = xAxis;
1893−
1893+
18941894 // very simple ray along xAxis
18951895 if (!sphere.findRayIntersection(intersection)) {
18961896 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely hit sphere" << std::endl;
18971897 }
18981898 if (intersection._hitShape != &sphere) {
1899− std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at sphere"
1899+ std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at sphere"
19001900 << std::endl;
19011901 }
19021902 }
19031903
19041904 {
1905− // translate and rotate the whole system...
1905+ // translate and rotate the whole system...
19061906 glm::vec3 axis = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f));
19071907 glm::quat rotation = glm::angleAxis(0.987654321f, axis);
19081908 glm::vec3 translation(35.7f, 0.46f, -1.97f);
1909−
1909+
19101910 RayIntersectionInfo intersection;
19111911 intersection._rayStart = rotation * (intersection._rayStart + translation);
19121912 intersection._rayDirection = rotation * intersection._rayDirection;
1913−
1913+
19141914 sphere.setTranslation(rotation * translation);
1915−
1915+
19161916 // ...and test again
19171917 if (!sphere.findRayIntersection(intersection)) {
19181918 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely hit sphere" << std::endl;
@@ -1934,19 +1934,19 @@ void ShapeColliderTests::rayBarelyMissesSphere() { · 15 unmodified lines
19341934 RayIntersectionInfo intersection;
19351935 intersection._rayStart = glm::vec3(-startDistance, radius + delta, 0.0f);
19361936 intersection._rayDirection = xAxis;
1937−
1937+
19381938 // very simple ray along xAxis
19391939 if (sphere.findRayIntersection(intersection)) {
19401940 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely miss sphere" << std::endl;
19411941 }
19421942 if (intersection._hitDistance != FLT_MAX) {
1943− std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss"
1943+ std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss"
19441944 << std::endl;
19451945 }
19461946 }
19471947
19481948 {
1949− // translate and rotate the whole system...
1949+ // translate and rotate the whole system...
19501950 float angle = 0.987654321f;
19511951 glm::vec3 axis = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f));
19521952 glm::quat rotation = glm::angleAxis(angle, axis);
@@ -1956,13 +1956,13 @@ void ShapeColliderTests::rayBarelyMissesSphere() { · 3 unmodified lines
19561956 intersection._rayStart = rotation * (glm::vec3(-startDistance, radius + delta, 0.0f) + translation);
19571957 intersection._rayDirection = rotation * xAxis;
19581958 sphere.setTranslation(rotation * translation);
1959−
1959+
19601960 // ...and test again
19611961 if (sphere.findRayIntersection(intersection)) {
19621962 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely miss sphere" << std::endl;
19631963 }
19641964 if (intersection._hitDistance != FLT_MAX) {
1965− std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss"
1965+ std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss"
19661966 << std::endl;
19671967 }
19681968 if (intersection._hitShape != NULL) {
@@ -1978,7 +1978,7 @@ void ShapeColliderTests::rayHitsCapsule() { · 9 unmodified lines
19781978 glm::vec3 center(0.0f);
19791979 CapsuleShape capsule(radius, halfHeight);
19801980
1981− // simple tests along xAxis
1981+ // simple tests along xAxis
19821982 { // toward capsule center
19831983 RayIntersectionInfo intersection;
19841984 intersection._rayStart = glm::vec3(startDistance, 0.0f, 0.0f);
@@ -1989,11 +1989,11 @@ void ShapeColliderTests::rayHitsCapsule() { · 4 unmodified lines
19891989 float expectedDistance = startDistance - radius;
19901990 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;
19911991 if (relativeError > EPSILON) {
1992− std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = "
1992+ std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = "
19931993 << relativeError << std::endl;
19941994 }
19951995 if (intersection._hitShape != &capsule) {
1996− std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at capsule"
1996+ std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at capsule"
19971997 << std::endl;
19981998 }
19991999 }
@@ -2008,7 +2008,7 @@ void ShapeColliderTests::rayHitsCapsule() { · 8 unmodified lines
20082008 float expectedDistance = startDistance - radius;
20092009 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;
20102010 if (relativeError > EPSILON) {
2011− std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = "
2011+ std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = "
20122012 << relativeError << std::endl;
20132013 }
20142014 }
@@ -2024,7 +2024,7 @@ void ShapeColliderTests::rayHitsCapsule() { · 9 unmodified lines
20242024 float expectedDistance = startDistance - radius;
20252025 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;
20262026 if (relativeError > EPSILON) {
2027− std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = "
2027+ std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = "
20282028 << relativeError << std::endl;
20292029 }
20302030 }
@@ -2041,7 +2041,7 @@ void ShapeColliderTests::rayHitsCapsule() { · 10 unmodified lines
20412041 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;
20422042 // for edge cases we allow a LOT of error
20432043 if (relativeError > EDGE_CASE_SLOP_FACTOR * EPSILON) {
2044− std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = "
2044+ std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = "
20452045 << relativeError << std::endl;
20462046 }
20472047 }
@@ -2057,7 +2057,7 @@ void ShapeColliderTests::rayHitsCapsule() { · 9 unmodified lines
20572057 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;
20582058 // for edge cases we allow a LOT of error
20592059 if (relativeError > EDGE_CASE_SLOP_FACTOR * EPSILON) {
2060− std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = "
2060+ std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = "
20612061 << relativeError << std::endl;

299 more lines aren’t shown here.

tests/render-utils/src/main.cpp+9−0

This diff is large: its 23 lines aren’t shown here.

tests/shared/src/AngularConstraintTests.cpp+1−1

This diff is large: its 9 lines aren’t shown here.

tests/shared/src/MovingMinMaxAvgTests.cpp+9−8

This diff is large: its 67 lines aren’t shown here.

tools/vhacd-util/src/VHACDUtil.cpp+1−1

This diff is large: its 9 lines aren’t shown here.

tools/vhacd-util/src/VHACDUtilApp.cpp+1−0

This diff is large: its 8 lines aren’t shown here.