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
49else ()49else ()
50 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -fno-strict-aliasing -Wno-unused-parameter")50 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -fno-strict-aliasing -Wno-unused-parameter")
51 if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)51 if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
52 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb")52 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -Woverloaded-virtual -Wdouble-promotion")
53 endif ()53 endif ()
54endif(WIN32)54endif(WIN32)
55 55
assignment-client/src/audio/AudioMixerClientData.cpp+4−4
@@ -295,10 +295,10 @@ void AudioMixerClientData::printUpstreamDownstreamStats() const { · 294 unmodified lines
295 295
296void AudioMixerClientData::printAudioStreamStats(const AudioStreamStats& streamStats) const {296void AudioMixerClientData::printAudioStreamStats(const AudioStreamStats& streamStats) const {
297 printf(" Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)\n",297 printf(" Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)\n",
298 streamStats._packetStreamStats.getLostRate() * 100.0f,298 (double)(streamStats._packetStreamStats.getLostRate() * 100.0f),
299 streamStats._packetStreamStats._lost,299 streamStats._packetStreamStats._lost,
300 streamStats._packetStreamWindowStats.getLostRate() * 100.0f,300 (double)(streamStats._packetStreamWindowStats.getLostRate() * 100.0f),
301 streamStats._packetStreamWindowStats._lost);301 streamStats._packetStreamWindowStats._lost);
302 302
303 printf(" Ringbuffer frames | desired: %u, avg_available(10s): %u, available: %u\n",303 printf(" Ringbuffer frames | desired: %u, avg_available(10s): %u, available: %u\n",
304 streamStats._desiredJitterBufferFrames,304 streamStats._desiredJitterBufferFrames,
assignment-client/src/octree/OctreeServer.cpp+135−130
@@ -127,7 +127,7 @@ void OctreeServer::resetSendingStats() { · 126 unmodified lines
127 _noProcessWait = 0;127 _noProcessWait = 0;
128}128}
129 129
130void OctreeServer::trackEncodeTime(float time) { 130void OctreeServer::trackEncodeTime(float time) {
131 const float MAX_SHORT_TIME = 10.0f;131 const float MAX_SHORT_TIME = 10.0f;
132 const float MAX_LONG_TIME = 100.0f;132 const float MAX_LONG_TIME = 100.0f;
133 133
@@ -144,10 +144,10 @@ void OctreeServer::trackEncodeTime(float time) { · 10 unmodified lines
144 _extraLongEncode++;144 _extraLongEncode++;
145 _averageExtraLongEncodeTime.updateAverage(time);145 _averageExtraLongEncodeTime.updateAverage(time);
146 }146 }
147 _averageEncodeTime.updateAverage(time); 147 _averageEncodeTime.updateAverage(time);
148}148}
149 149
150void OctreeServer::trackTreeWaitTime(float time) { 150void OctreeServer::trackTreeWaitTime(float time) {
151 const float MAX_SHORT_TIME = 10.0f;151 const float MAX_SHORT_TIME = 10.0f;
152 const float MAX_LONG_TIME = 100.0f;152 const float MAX_LONG_TIME = 100.0f;
153 if (time == SKIP_TIME) {153 if (time == SKIP_TIME) {
@@ -166,7 +166,7 @@ void OctreeServer::trackTreeWaitTime(float time) { · 12 unmodified lines
166 _averageTreeWaitTime.updateAverage(time);166 _averageTreeWaitTime.updateAverage(time);
167}167}
168 168
169void OctreeServer::trackCompressAndWriteTime(float time) { 169void OctreeServer::trackCompressAndWriteTime(float time) {
170 const float MAX_SHORT_TIME = 10.0f;170 const float MAX_SHORT_TIME = 10.0f;
171 const float MAX_LONG_TIME = 100.0f;171 const float MAX_LONG_TIME = 100.0f;
172 if (time == SKIP_TIME) {172 if (time == SKIP_TIME) {
@@ -182,19 +182,19 @@ void OctreeServer::trackCompressAndWriteTime(float time) { · 9 unmodified lines
182 _extraLongCompress++;182 _extraLongCompress++;
183 _averageExtraLongCompressTime.updateAverage(time);183 _averageExtraLongCompressTime.updateAverage(time);
184 }184 }
185 _averageCompressAndWriteTime.updateAverage(time); 185 _averageCompressAndWriteTime.updateAverage(time);
186}186}
187 187
188void OctreeServer::trackPacketSendingTime(float time) { 188void OctreeServer::trackPacketSendingTime(float time) {
189 if (time == SKIP_TIME) {189 if (time == SKIP_TIME) {
190 _noSend++;190 _noSend++;
191 time = 0.0f;191 time = 0.0f;
192 }192 }
193 _averagePacketSendingTime.updateAverage(time); 193 _averagePacketSendingTime.updateAverage(time);
194}194}
195 195
196 196
197void OctreeServer::trackProcessWaitTime(float time) { 197void OctreeServer::trackProcessWaitTime(float time) {
198 const float MAX_SHORT_TIME = 10.0f;198 const float MAX_SHORT_TIME = 10.0f;
199 const float MAX_LONG_TIME = 100.0f;199 const float MAX_LONG_TIME = 100.0f;
200 if (time == SKIP_TIME) {200 if (time == SKIP_TIME) {
@@ -243,9 +243,9 @@ OctreeServer::OctreeServer(const QByteArray& packet) : · 42 unmodified lines
243 243
244 _averageLoopTime.updateAverage(0);244 _averageLoopTime.updateAverage(0);
245 qDebug() << "Octree server starting... [" << this << "]";245 qDebug() << "Octree server starting... [" << this << "]";
246 246
247 // make sure the AccountManager has an Auth URL for payment redemptions247 // make sure the AccountManager has an Auth URL for payment redemptions
248 248
249 AccountManager::getInstance().setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL);249 AccountManager::getInstance().setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL);
250}250}
251 251
@@ -278,13 +278,13 @@ OctreeServer::~OctreeServer() { · 26 unmodified lines
278 278
279 delete _jurisdiction;279 delete _jurisdiction;
280 _jurisdiction = NULL;280 _jurisdiction = NULL;
281 281
282 // cleanup our tree here...282 // cleanup our tree here...
283 qDebug() << qPrintable(_safeServerName) << "server START cleaning up octree... [" << this << "]";283 qDebug() << qPrintable(_safeServerName) << "server START cleaning up octree... [" << this << "]";
284 delete _tree;284 delete _tree;
285 _tree = NULL;285 _tree = NULL;
286 qDebug() << qPrintable(_safeServerName) << "server DONE cleaning up octree... [" << this << "]";286 qDebug() << qPrintable(_safeServerName) << "server DONE cleaning up octree... [" << this << "]";
287 287
288 if (_instance == this) {288 if (_instance == this) {
289 _instance = NULL; // we are gone289 _instance = NULL; // we are gone
290 }290 }
@@ -400,10 +400,10 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 109 unmodified lines
400 statsString += QString().sprintf(" Internal Elements: %s nodes (%5.2f%%)\r\n",400 statsString += QString().sprintf(" Internal Elements: %s nodes (%5.2f%%)\r\n",
401 locale.toString((uint)internalNodeCount).rightJustified(16,401 locale.toString((uint)internalNodeCount).rightJustified(16,
402 ' ').toLocal8Bit().constData(),402 ' ').toLocal8Bit().constData(),
403 ((float)internalNodeCount / (float)nodeCount) * AS_PERCENT);403 (double)((internalNodeCount / (float)nodeCount) * AS_PERCENT));
404 statsString += QString().sprintf(" Leaf Elements: %s nodes (%5.2f%%)\r\n",404 statsString += QString().sprintf(" Leaf Elements: %s nodes (%5.2f%%)\r\n",
405 locale.toString((uint)leafNodeCount).rightJustified(16, ' ').toLocal8Bit().constData(),405 locale.toString((uint)leafNodeCount).rightJustified(16, ' ').toLocal8Bit().constData(),
406 ((float)leafNodeCount / (float)nodeCount) * AS_PERCENT);406 (double)((leafNodeCount / (float)nodeCount) * AS_PERCENT));
407 statsString += "\r\n";407 statsString += "\r\n";
408 statsString += "\r\n";408 statsString += "\r\n";
409 409
@@ -422,7 +422,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 12 unmodified lines
422 .arg(locale.toString((uint)getCurrentClientCount()).rightJustified(COLUMN_WIDTH, ' '));422 .arg(locale.toString((uint)getCurrentClientCount()).rightJustified(COLUMN_WIDTH, ' '));
423 423
424 quint64 oneSecondAgo = usecTimestampNow() - USECS_PER_SECOND;424 quint64 oneSecondAgo = usecTimestampNow() - USECS_PER_SECOND;
425 425
426 statsString += QString(" process() last second: %1 clients\r\n")426 statsString += QString(" process() last second: %1 clients\r\n")
427 .arg(locale.toString((uint)howManyThreadsDidProcess(oneSecondAgo)).rightJustified(COLUMN_WIDTH, ' '));427 .arg(locale.toString((uint)howManyThreadsDidProcess(oneSecondAgo)).rightJustified(COLUMN_WIDTH, ' '));
428 statsString += QString(" packetDistributor() last second: %1 clients\r\n")428 statsString += QString(" packetDistributor() last second: %1 clients\r\n")
@@ -434,13 +434,13 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 5 unmodified lines
434 434
435 float averageLoopTime = getAverageLoopTime();435 float averageLoopTime = getAverageLoopTime();
436 statsString += QString().sprintf(" Average packetLoop() time: %7.2f msecs"436 statsString += QString().sprintf(" Average packetLoop() time: %7.2f msecs"
437 " samples: %12d \r\n", 437 " samples: %12d \r\n",
438 averageLoopTime, _averageLoopTime.getSampleCount());438 (double)averageLoopTime, _averageLoopTime.getSampleCount());
439 439
440 float averageInsideTime = getAverageInsideTime();440 float averageInsideTime = getAverageInsideTime();
441 statsString += QString().sprintf(" Average 'inside' time: %9.2f usecs"441 statsString += QString().sprintf(" Average 'inside' time: %9.2f usecs"
442 " samples: %12d \r\n\r\n", 442 " samples: %12d \r\n\r\n",
443 averageInsideTime, _averageInsideTime.getSampleCount());443 (double)averageInsideTime, _averageInsideTime.getSampleCount());
444 444
445 445
446 // Process Wait446 // Process Wait
@@ -450,30 +450,30 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 3 unmodified lines
450 float averageProcessWaitTime = getAverageProcessWaitTime();450 float averageProcessWaitTime = getAverageProcessWaitTime();
451 statsString += QString().sprintf(" Average process lock wait time:"451 statsString += QString().sprintf(" Average process lock wait time:"
452 " %9.2f usecs samples: %12d \r\n",452 " %9.2f usecs samples: %12d \r\n",
453 averageProcessWaitTime, allWaitTimes);453 (double)averageProcessWaitTime, allWaitTimes);
454 454
455 float zeroVsTotal = (allWaitTimes > 0) ? ((float)_noProcessWait / (float)allWaitTimes) : 0.0f;455 float zeroVsTotal = (allWaitTimes > 0) ? ((float)_noProcessWait / (float)allWaitTimes) : 0.0f;
456 statsString += QString().sprintf(" No Lock Wait:"456 statsString += QString().sprintf(" No Lock Wait:"
457 " (%6.2f%%) samples: %12d \r\n",457 " (%6.2f%%) samples: %12d \r\n",
458 zeroVsTotal * AS_PERCENT, _noProcessWait);458 (double)(zeroVsTotal * AS_PERCENT), _noProcessWait);
459 459
460 float shortVsTotal = (allWaitTimes > 0) ? ((float)_shortProcessWait / (float)allWaitTimes) : 0.0f;460 float shortVsTotal = (allWaitTimes > 0) ? ((float)_shortProcessWait / (float)allWaitTimes) : 0.0f;
461 statsString += QString().sprintf(" Avg process lock short wait time:"461 statsString += QString().sprintf(" Avg process lock short wait time:"
462 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",462 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",
463 _averageProcessShortWaitTime.getAverage(), 463 (double)_averageProcessShortWaitTime.getAverage(),
464 shortVsTotal * AS_PERCENT, _shortProcessWait);464 (double)(shortVsTotal * AS_PERCENT), _shortProcessWait);
465 465
466 float longVsTotal = (allWaitTimes > 0) ? ((float)_longProcessWait / (float)allWaitTimes) : 0.0f;466 float longVsTotal = (allWaitTimes > 0) ? ((float)_longProcessWait / (float)allWaitTimes) : 0.0f;
467 statsString += QString().sprintf(" Avg process lock long wait time:"467 statsString += QString().sprintf(" Avg process lock long wait time:"
468 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",468 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",
469 _averageProcessLongWaitTime.getAverage(), 469 (double)_averageProcessLongWaitTime.getAverage(),
470 longVsTotal * AS_PERCENT, _longProcessWait);470 (double)(longVsTotal * AS_PERCENT), _longProcessWait);
471 471
472 float extraLongVsTotal = (allWaitTimes > 0) ? ((float)_extraLongProcessWait / (float)allWaitTimes) : 0.0f;472 float extraLongVsTotal = (allWaitTimes > 0) ? ((float)_extraLongProcessWait / (float)allWaitTimes) : 0.0f;
473 statsString += QString().sprintf("Avg process lock extralong wait time:"473 statsString += QString().sprintf("Avg process lock extralong wait time:"
474 " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n",474 " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n",
475 _averageProcessExtraLongWaitTime.getAverage(), 475 (double)_averageProcessExtraLongWaitTime.getAverage(),
476 extraLongVsTotal * AS_PERCENT, _extraLongProcessWait);476 (double)(extraLongVsTotal * AS_PERCENT), _extraLongProcessWait);
477 }477 }
478 478
479 // Tree Wait479 // Tree Wait
@@ -482,122 +482,125 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 2 unmodified lines
482 float averageTreeWaitTime = getAverageTreeWaitTime();482 float averageTreeWaitTime = getAverageTreeWaitTime();
483 statsString += QString().sprintf(" Average tree lock wait time:"483 statsString += QString().sprintf(" Average tree lock wait time:"
484 " %9.2f usecs samples: %12d \r\n",484 " %9.2f usecs samples: %12d \r\n",
485 averageTreeWaitTime, allWaitTimes);485 (double)averageTreeWaitTime, allWaitTimes);
486 486
487 float zeroVsTotal = (allWaitTimes > 0) ? ((float)_noTreeWait / (float)allWaitTimes) : 0.0f;487 float zeroVsTotal = (allWaitTimes > 0) ? ((float)_noTreeWait / (float)allWaitTimes) : 0.0f;
488 statsString += QString().sprintf(" No Lock Wait:"488 statsString += QString().sprintf(" No Lock Wait:"
489 " (%6.2f%%) samples: %12d \r\n",489 " (%6.2f%%) samples: %12d \r\n",
490 zeroVsTotal * AS_PERCENT, _noTreeWait);490 (double)(zeroVsTotal * AS_PERCENT), _noTreeWait);
491 491
492 float shortVsTotal = (allWaitTimes > 0) ? ((float)_shortTreeWait / (float)allWaitTimes) : 0.0f;492 float shortVsTotal = (allWaitTimes > 0) ? ((float)_shortTreeWait / (float)allWaitTimes) : 0.0f;
493 statsString += QString().sprintf(" Avg tree lock short wait time:"493 statsString += QString().sprintf(" Avg tree lock short wait time:"
494 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",494 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",
495 _averageTreeShortWaitTime.getAverage(), 495 (double)_averageTreeShortWaitTime.getAverage(),
496 shortVsTotal * AS_PERCENT, _shortTreeWait);496 (double)(shortVsTotal * AS_PERCENT), _shortTreeWait);
497 497
498 float longVsTotal = (allWaitTimes > 0) ? ((float)_longTreeWait / (float)allWaitTimes) : 0.0f;498 float longVsTotal = (allWaitTimes > 0) ? ((float)_longTreeWait / (float)allWaitTimes) : 0.0f;
499 statsString += QString().sprintf(" Avg tree lock long wait time:"499 statsString += QString().sprintf(" Avg tree lock long wait time:"
500 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",500 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",
501 _averageTreeLongWaitTime.getAverage(), 501 (double)_averageTreeLongWaitTime.getAverage(),
502 longVsTotal * AS_PERCENT, _longTreeWait);502 (double)(longVsTotal * AS_PERCENT), _longTreeWait);
503 503
504 float extraLongVsTotal = (allWaitTimes > 0) ? ((float)_extraLongTreeWait / (float)allWaitTimes) : 0.0f;504 float extraLongVsTotal = (allWaitTimes > 0) ? ((float)_extraLongTreeWait / (float)allWaitTimes) : 0.0f;
505 statsString += QString().sprintf(" Avg tree lock extra long wait time:"505 statsString += QString().sprintf(" Avg tree lock extra long wait time:"
506 " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n",506 " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n",
507 _averageTreeExtraLongWaitTime.getAverage(), 507 (double)_averageTreeExtraLongWaitTime.getAverage(),
508 extraLongVsTotal * AS_PERCENT, _extraLongTreeWait);508 (double)(extraLongVsTotal * AS_PERCENT), _extraLongTreeWait);
509 509
510 // encode510 // encode
511 float averageEncodeTime = getAverageEncodeTime();511 float averageEncodeTime = getAverageEncodeTime();
512 statsString += QString().sprintf(" Average encode time: %9.2f usecs\r\n", averageEncodeTime);512 statsString += QString().sprintf(" Average encode time: %9.2f usecs\r\n", (double)averageEncodeTime);
513 513
514 int allEncodeTimes = _noEncode + _shortEncode + _longEncode + _extraLongEncode;514 int allEncodeTimes = _noEncode + _shortEncode + _longEncode + _extraLongEncode;
515 515
516 float zeroVsTotalEncode = (allEncodeTimes > 0) ? ((float)_noEncode / (float)allEncodeTimes) : 0.0f;516 float zeroVsTotalEncode = (allEncodeTimes > 0) ? ((float)_noEncode / (float)allEncodeTimes) : 0.0f;
517 statsString += QString().sprintf(" No Encode:"517 statsString += QString().sprintf(" No Encode:"
518 " (%6.2f%%) samples: %12d \r\n",518 " (%6.2f%%) samples: %12d \r\n",
519 zeroVsTotalEncode * AS_PERCENT, _noEncode);519 (double)(zeroVsTotalEncode * AS_PERCENT), _noEncode);
520 520
521 float shortVsTotalEncode = (allEncodeTimes > 0) ? ((float)_shortEncode / (float)allEncodeTimes) : 0.0f;521 float shortVsTotalEncode = (allEncodeTimes > 0) ? ((float)_shortEncode / (float)allEncodeTimes) : 0.0f;
522 statsString += QString().sprintf(" Avg short encode time:"522 statsString += QString().sprintf(" Avg short encode time:"
523 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",523 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",
524 _averageShortEncodeTime.getAverage(), 524 (double)_averageShortEncodeTime.getAverage(),
525 shortVsTotalEncode * AS_PERCENT, _shortEncode);525 (double)(shortVsTotalEncode * AS_PERCENT), _shortEncode);
526 526
527 float longVsTotalEncode = (allEncodeTimes > 0) ? ((float)_longEncode / (float)allEncodeTimes) : 0.0f;527 float longVsTotalEncode = (allEncodeTimes > 0) ? ((float)_longEncode / (float)allEncodeTimes) : 0.0f;
528 statsString += QString().sprintf(" Avg long encode time:"528 statsString += QString().sprintf(" Avg long encode time:"
529 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",529 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",
530 _averageLongEncodeTime.getAverage(), 530 (double)_averageLongEncodeTime.getAverage(),
531 longVsTotalEncode * AS_PERCENT, _longEncode);531 (double)(longVsTotalEncode * AS_PERCENT), _longEncode);
532 532
533 float extraLongVsTotalEncode = (allEncodeTimes > 0) ? ((float)_extraLongEncode / (float)allEncodeTimes) : 0.0f;533 float extraLongVsTotalEncode = (allEncodeTimes > 0) ? ((float)_extraLongEncode / (float)allEncodeTimes) : 0.0f;
534 statsString += QString().sprintf(" Avg extra long encode time:"534 statsString += QString().sprintf(" Avg extra long encode time:"
535 " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n",535 " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n",
536 _averageExtraLongEncodeTime.getAverage(), 536 (double)_averageExtraLongEncodeTime.getAverage(),
537 extraLongVsTotalEncode * AS_PERCENT, _extraLongEncode);537 (double)(extraLongVsTotalEncode * AS_PERCENT), _extraLongEncode);
538 538
539 539
540 float averageCompressAndWriteTime = getAverageCompressAndWriteTime();540 float averageCompressAndWriteTime = getAverageCompressAndWriteTime();
541 statsString += QString().sprintf(" Average compress and write time: %9.2f usecs\r\n", 541 statsString += QString().sprintf(" Average compress and write time: %9.2f usecs\r\n",
542 averageCompressAndWriteTime);542 (double)averageCompressAndWriteTime);
543 543
544 int allCompressTimes = _noCompress + _shortCompress + _longCompress + _extraLongCompress;544 int allCompressTimes = _noCompress + _shortCompress + _longCompress + _extraLongCompress;
545 545
546 float zeroVsTotalCompress = (allCompressTimes > 0) ? ((float)_noCompress / (float)allCompressTimes) : 0.0f;546 float zeroVsTotalCompress = (allCompressTimes > 0) ? ((float)_noCompress / (float)allCompressTimes) : 0.0f;
547 statsString += QString().sprintf(" No compression:"547 statsString += QString().sprintf(" No compression:"
548 " (%6.2f%%) samples: %12d \r\n",548 " (%6.2f%%) samples: %12d \r\n",
549 zeroVsTotalCompress * AS_PERCENT, _noCompress);549 (double)(zeroVsTotalCompress * AS_PERCENT), _noCompress);
550 550
551 float shortVsTotalCompress = (allCompressTimes > 0) ? ((float)_shortCompress / (float)allCompressTimes) : 0.0f;551 float shortVsTotalCompress = (allCompressTimes > 0) ? ((float)_shortCompress / (float)allCompressTimes) : 0.0f;
552 statsString += QString().sprintf(" Avg short compress time:"552 statsString += QString().sprintf(" Avg short compress time:"
553 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",553 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",
554 _averageShortCompressTime.getAverage(), 554 (double)_averageShortCompressTime.getAverage(),
555 shortVsTotalCompress * AS_PERCENT, _shortCompress);555 (double)(shortVsTotalCompress * AS_PERCENT), _shortCompress);
556 556
557 float longVsTotalCompress = (allCompressTimes > 0) ? ((float)_longCompress / (float)allCompressTimes) : 0.0f;557 float longVsTotalCompress = (allCompressTimes > 0) ? ((float)_longCompress / (float)allCompressTimes) : 0.0f;
558 statsString += QString().sprintf(" Avg long compress time:"558 statsString += QString().sprintf(" Avg long compress time:"
559 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",559 " %9.2f usecs (%6.2f%%) samples: %12d \r\n",
560 _averageLongCompressTime.getAverage(), 560 (double)_averageLongCompressTime.getAverage(),
561 longVsTotalCompress * AS_PERCENT, _longCompress);561 (double)(longVsTotalCompress * AS_PERCENT), _longCompress);
562 562
563 float extraLongVsTotalCompress = (allCompressTimes > 0) ? ((float)_extraLongCompress / (float)allCompressTimes) : 0.0f;563 float extraLongVsTotalCompress = (allCompressTimes > 0) ? ((float)_extraLongCompress / (float)allCompressTimes) : 0.0f;
564 statsString += QString().sprintf(" Avg extra long compress time:"564 statsString += QString().sprintf(" Avg extra long compress time:"
565 " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n",565 " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n",
566 _averageExtraLongCompressTime.getAverage(), 566 (double)_averageExtraLongCompressTime.getAverage(),
567 extraLongVsTotalCompress * AS_PERCENT, _extraLongCompress);567 (double)(extraLongVsTotalCompress * AS_PERCENT), _extraLongCompress);
568 568
569 float averagePacketSendingTime = getAveragePacketSendingTime();569 float averagePacketSendingTime = getAveragePacketSendingTime();
570 statsString += QString().sprintf(" Average packet sending time: %9.2f usecs (includes node lock)\r\n", 570 statsString += QString().sprintf(" Average packet sending time: %9.2f usecs (includes node lock)\r\n",
571 averagePacketSendingTime);571 (double)averagePacketSendingTime);
572 572
573 float noVsTotalSend = (_averagePacketSendingTime.getSampleCount() > 0) ? 573 float noVsTotalSend = (_averagePacketSendingTime.getSampleCount() > 0) ?
574 ((float)_noSend / (float)_averagePacketSendingTime.getSampleCount()) : 0.0f;574 ((float)_noSend / (float)_averagePacketSendingTime.getSampleCount()) : 0.0f;
575 statsString += QString().sprintf(" Not sending:"575 statsString += QString().sprintf(" Not sending:"
576 " (%6.2f%%) samples: %12d \r\n",576 " (%6.2f%%) samples: %12d \r\n",
577 noVsTotalSend * AS_PERCENT, _noSend);577 (double)(noVsTotalSend * AS_PERCENT), _noSend);
578 578
579 float averageNodeWaitTime = getAverageNodeWaitTime();579 float averageNodeWaitTime = getAverageNodeWaitTime();
580 statsString += QString().sprintf(" Average node lock wait time: %9.2f usecs\r\n", averageNodeWaitTime);580 statsString += QString().sprintf(" Average node lock wait time: %9.2f usecs\r\n",
581 (double)averageNodeWaitTime);
581 582
582 statsString += QString().sprintf("--------------------------------------------------------------\r\n");583 statsString += QString().sprintf("--------------------------------------------------------------\r\n");
583 584
584 float encodeToInsidePercent = averageInsideTime == 0.0f ? 0.0f : (averageEncodeTime / averageInsideTime) * AS_PERCENT;585 float encodeToInsidePercent = averageInsideTime == 0.0f ? 0.0f : (averageEncodeTime / averageInsideTime) * AS_PERCENT;
585 statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n", 586 statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n",
586 encodeToInsidePercent);587 (double)encodeToInsidePercent);
587 588
588 float waitToInsidePercent = averageInsideTime == 0.0f ? 0.0f 589 float waitToInsidePercent = averageInsideTime == 0.0f ? 0.0f
589 : ((averageTreeWaitTime + averageNodeWaitTime) / averageInsideTime) * AS_PERCENT;590 : ((averageTreeWaitTime + averageNodeWaitTime) / averageInsideTime) * AS_PERCENT;
590 statsString += QString().sprintf(" waiting ratio: %5.2f%%\r\n", waitToInsidePercent);591 statsString += QString().sprintf(" waiting ratio: %5.2f%%\r\n",
592 (double)waitToInsidePercent);
591 593
592 float compressAndWriteToInsidePercent = averageInsideTime == 0.0f ? 0.0f 594 float compressAndWriteToInsidePercent = averageInsideTime == 0.0f ? 0.0f
593 : (averageCompressAndWriteTime / averageInsideTime) * AS_PERCENT;595 : (averageCompressAndWriteTime / averageInsideTime) * AS_PERCENT;
594 statsString += QString().sprintf(" compress and write ratio: %5.2f%%\r\n", 596 statsString += QString().sprintf(" compress and write ratio: %5.2f%%\r\n",
595 compressAndWriteToInsidePercent);597 (double)compressAndWriteToInsidePercent);
596 598
597 float sendingToInsidePercent = averageInsideTime == 0.0f ? 0.0f 599 float sendingToInsidePercent = averageInsideTime == 0.0f ? 0.0f
598 : (averagePacketSendingTime / averageInsideTime) * AS_PERCENT;600 : (averagePacketSendingTime / averageInsideTime) * AS_PERCENT;
599 statsString += QString().sprintf(" sending ratio: %5.2f%%\r\n", sendingToInsidePercent);601 statsString += QString().sprintf(" sending ratio: %5.2f%%\r\n",
600 602 (double)sendingToInsidePercent);
603
601 604
602 605
603 statsString += QString("\r\n");606 statsString += QString("\r\n");
@@ -610,13 +613,13 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 6 unmodified lines
610 .arg(locale.toString((uint)totalWastedBytes).rightJustified(COLUMN_WIDTH, ' '));613 .arg(locale.toString((uint)totalWastedBytes).rightJustified(COLUMN_WIDTH, ' '));
611 statsString += QString().sprintf(" Total OctalCode Bytes: %s bytes (%5.2f%%)\r\n",614 statsString += QString().sprintf(" Total OctalCode Bytes: %s bytes (%5.2f%%)\r\n",
612 locale.toString((uint)totalBytesOfOctalCodes).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(),615 locale.toString((uint)totalBytesOfOctalCodes).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(),
613 ((float)totalBytesOfOctalCodes / (float)totalOutboundBytes) * AS_PERCENT);616 (double)((totalBytesOfOctalCodes / (float)totalOutboundBytes) * AS_PERCENT));
614 statsString += QString().sprintf(" Total BitMasks Bytes: %s bytes (%5.2f%%)\r\n",617 statsString += QString().sprintf(" Total BitMasks Bytes: %s bytes (%5.2f%%)\r\n",
615 locale.toString((uint)totalBytesOfBitMasks).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(),618 locale.toString((uint)totalBytesOfBitMasks).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(),
616 ((float)totalBytesOfBitMasks / (float)totalOutboundBytes) * AS_PERCENT);619 (double)(((float)totalBytesOfBitMasks / (float)totalOutboundBytes) * AS_PERCENT));
617 statsString += QString().sprintf(" Total Color Bytes: %s bytes (%5.2f%%)\r\n",620 statsString += QString().sprintf(" Total Color Bytes: %s bytes (%5.2f%%)\r\n",
618 locale.toString((uint)totalBytesOfColor).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(),621 locale.toString((uint)totalBytesOfColor).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(),
619 ((float)totalBytesOfColor / (float)totalOutboundBytes) * AS_PERCENT);622 (double)((totalBytesOfColor / (float)totalOutboundBytes) * AS_PERCENT));
620 623
621 statsString += "\r\n";624 statsString += "\r\n";
622 statsString += "\r\n";625 statsString += "\r\n";
@@ -638,7 +641,8 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 15 unmodified lines
638 .arg(locale.toString((uint)totalPacketsProcessed).rightJustified(COLUMN_WIDTH, ' '));641 .arg(locale.toString((uint)totalPacketsProcessed).rightJustified(COLUMN_WIDTH, ' '));
639 statsString += QString(" Total Inbound Elements: %1 elements\r\n")642 statsString += QString(" Total Inbound Elements: %1 elements\r\n")
640 .arg(locale.toString((uint)totalElementsProcessed).rightJustified(COLUMN_WIDTH, ' '));643 .arg(locale.toString((uint)totalElementsProcessed).rightJustified(COLUMN_WIDTH, ' '));
641 statsString += QString().sprintf(" Average Inbound Elements/Packet: %f elements/packet\r\n", averageElementsPerPacket);644 statsString += QString().sprintf(" Average Inbound Elements/Packet: %f elements/packet\r\n",
645 (double)averageElementsPerPacket);
642 statsString += QString(" Average Transit Time/Packet: %1 usecs\r\n")646 statsString += QString(" Average Transit Time/Packet: %1 usecs\r\n")
643 .arg(locale.toString((uint)averageTransitTimePerPacket).rightJustified(COLUMN_WIDTH, ' '));647 .arg(locale.toString((uint)averageTransitTimePerPacket).rightJustified(COLUMN_WIDTH, ' '));
644 statsString += QString(" Average Process Time/Packet: %1 usecs\r\n")648 statsString += QString(" Average Process Time/Packet: %1 usecs\r\n")
@@ -676,7 +680,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 31 unmodified lines
676 statsString += QString(" Total Inbound Elements: %1 elements\r\n")680 statsString += QString(" Total Inbound Elements: %1 elements\r\n")
677 .arg(locale.toString((uint)totalElementsProcessed).rightJustified(COLUMN_WIDTH, ' '));681 .arg(locale.toString((uint)totalElementsProcessed).rightJustified(COLUMN_WIDTH, ' '));
678 statsString += QString().sprintf(" Average Inbound Elements/Packet: %f elements/packet\r\n",682 statsString += QString().sprintf(" Average Inbound Elements/Packet: %f elements/packet\r\n",
679 averageElementsPerPacket);683 (double)averageElementsPerPacket);
680 statsString += QString(" Average Transit Time/Packet: %1 usecs\r\n")684 statsString += QString(" Average Transit Time/Packet: %1 usecs\r\n")
681 .arg(locale.toString((uint)averageTransitTimePerPacket).rightJustified(COLUMN_WIDTH, ' '));685 .arg(locale.toString((uint)averageTransitTimePerPacket).rightJustified(COLUMN_WIDTH, ' '));
682 statsString += QString(" Average Process Time/Packet: %1 usecs\r\n")686 statsString += QString(" Average Process Time/Packet: %1 usecs\r\n")
@@ -710,14 +714,15 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 27 unmodified lines
710 }714 }
711 715
712 statsString += QString().sprintf("Element Node Memory Usage: %8.2f %s\r\n",716 statsString += QString().sprintf("Element Node Memory Usage: %8.2f %s\r\n",
713 OctreeElement::getOctreeMemoryUsage() / memoryScale, memoryScaleLabel);717 OctreeElement::getOctreeMemoryUsage() / (double)memoryScale, memoryScaleLabel);
714 statsString += QString().sprintf("Octcode Memory Usage: %8.2f %s\r\n",718 statsString += QString().sprintf("Octcode Memory Usage: %8.2f %s\r\n",
715 OctreeElement::getOctcodeMemoryUsage() / memoryScale, memoryScaleLabel);719 OctreeElement::getOctcodeMemoryUsage() / (double)memoryScale, memoryScaleLabel);
716 statsString += QString().sprintf("External Children Memory Usage: %8.2f %s\r\n",720 statsString += QString().sprintf("External Children Memory Usage: %8.2f %s\r\n",
717 OctreeElement::getExternalChildrenMemoryUsage() / memoryScale, memoryScaleLabel);721 OctreeElement::getExternalChildrenMemoryUsage() / (double)memoryScale,
722 memoryScaleLabel);
718 statsString += " -----------\r\n";723 statsString += " -----------\r\n";
719 statsString += QString().sprintf(" Total: %8.2f %s\r\n",724 statsString += QString().sprintf(" Total: %8.2f %s\r\n",
720 OctreeElement::getTotalMemoryUsage() / memoryScale, memoryScaleLabel);725 OctreeElement::getTotalMemoryUsage() / (double)memoryScale, memoryScaleLabel);
721 statsString += "\r\n";726 statsString += "\r\n";
722 727
723 statsString += "OctreeElement Children Population Statistics...\r\n";728 statsString += "OctreeElement Children Population Statistics...\r\n";
@@ -726,7 +731,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url · 2 unmodified lines
726 checkSum += OctreeElement::getChildrenCount(i);731 checkSum += OctreeElement::getChildrenCount(i);
727 statsString += QString().sprintf(" Nodes with %d children: %s nodes (%5.2f%%)\r\n", i,732 statsString += QString().sprintf(" Nodes with %d children: %s nodes (%5.2f%%)\r\n", i,
728 locale.toString((uint)OctreeElement::getChildrenCount(i)).rightJustified(16, ' ').toLocal8Bit().constData(),733 locale.toString((uint)OctreeElement::getChildrenCount(i)).rightJustified(16, ' ').toLocal8Bit().constData(),
729 ((float)OctreeElement::getChildrenCount(i) / (float)nodeCount) * AS_PERCENT);734 (double)(((float)OctreeElement::getChildrenCount(i) / (float)nodeCount) * AS_PERCENT));
730 }735 }
731 statsString += " ----------------------\r\n";736 statsString += " ----------------------\r\n";
732 statsString += QString(" Total: %1 nodes\r\n")737 statsString += QString(" Total: %1 nodes\r\n")
@@ -831,7 +836,7 @@ void OctreeServer::readPendingDatagram(const QByteArray& receivedPacket, const H · 98 unmodified lines
831 836
832 // If we know we're shutting down we just drop these packets on the floor.837 // If we know we're shutting down we just drop these packets on the floor.
833 // This stops us from initializing send threads we just shut down.838 // This stops us from initializing send threads we just shut down.
834 839
835 if (!_isShuttingDown) {840 if (!_isShuttingDown) {
836 if (nodeList->packetVersionAndHashMatch(receivedPacket)) {841 if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
837 PacketType packetType = packetTypeForPacket(receivedPacket);842 PacketType packetType = packetTypeForPacket(receivedPacket);
@@ -841,7 +846,7 @@ void OctreeServer::readPendingDatagram(const QByteArray& receivedPacket, const H · 3 unmodified lines
841 // need to make sure we have it in our nodeList.846 // need to make sure we have it in our nodeList.
842 if (matchingNode) {847 if (matchingNode) {
843 nodeList->updateNodeWithDataFromPacket(matchingNode, receivedPacket);848 nodeList->updateNodeWithDataFromPacket(matchingNode, receivedPacket);
844 849
845 OctreeQueryNode* nodeData = (OctreeQueryNode*) matchingNode->getLinkedData();850 OctreeQueryNode* nodeData = (OctreeQueryNode*) matchingNode->getLinkedData();
846 if (nodeData && !nodeData->isOctreeSendThreadInitalized()) {851 if (nodeData && !nodeData->isOctreeSendThreadInitalized()) {
847 nodeData->initializeOctreeSendThread(this, matchingNode);852 nodeData->initializeOctreeSendThread(this, matchingNode);
@@ -870,33 +875,33 @@ void OctreeServer::readPendingDatagram(const QByteArray& receivedPacket, const H · 22 unmodified lines
870 875
871void OctreeServer::setupDatagramProcessingThread() {876void OctreeServer::setupDatagramProcessingThread() {
872 auto nodeList = DependencyManager::get<NodeList>();877 auto nodeList = DependencyManager::get<NodeList>();
873 878
874 // we do not want this event loop to be the handler for UDP datagrams, so disconnect879 // we do not want this event loop to be the handler for UDP datagrams, so disconnect
875 disconnect(&nodeList->getNodeSocket(), 0, this, 0);880 disconnect(&nodeList->getNodeSocket(), 0, this, 0);
876 881
877 // setup a QThread with us as parent that will house the OctreeServerDatagramProcessor882 // setup a QThread with us as parent that will house the OctreeServerDatagramProcessor
878 _datagramProcessingThread = new QThread(this);883 _datagramProcessingThread = new QThread(this);
879 _datagramProcessingThread->setObjectName("Octree Datagram Processor");884 _datagramProcessingThread->setObjectName("Octree Datagram Processor");
880 885
881 // create an OctreeServerDatagramProcessor and move it to that thread886 // create an OctreeServerDatagramProcessor and move it to that thread
882 OctreeServerDatagramProcessor* datagramProcessor = new OctreeServerDatagramProcessor(nodeList->getNodeSocket(), thread());887 OctreeServerDatagramProcessor* datagramProcessor = new OctreeServerDatagramProcessor(nodeList->getNodeSocket(), thread());
883 datagramProcessor->moveToThread(_datagramProcessingThread);888 datagramProcessor->moveToThread(_datagramProcessingThread);
884 889
885 // remove the NodeList as the parent of the node socket890 // remove the NodeList as the parent of the node socket
886 nodeList->getNodeSocket().setParent(NULL);891 nodeList->getNodeSocket().setParent(NULL);
887 nodeList->getNodeSocket().moveToThread(_datagramProcessingThread);892 nodeList->getNodeSocket().moveToThread(_datagramProcessingThread);
888 893
889 // let the datagram processor handle readyRead from node socket894 // let the datagram processor handle readyRead from node socket
890 connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead,895 connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead,
891 datagramProcessor, &OctreeServerDatagramProcessor::readPendingDatagrams);896 datagramProcessor, &OctreeServerDatagramProcessor::readPendingDatagrams);
892 897
893 // connect to the datagram processing thread signal that tells us we have to handle a packet898 // connect to the datagram processing thread signal that tells us we have to handle a packet
894 connect(datagramProcessor, &OctreeServerDatagramProcessor::packetRequiresProcessing, this, &OctreeServer::readPendingDatagram);899 connect(datagramProcessor, &OctreeServerDatagramProcessor::packetRequiresProcessing, this, &OctreeServer::readPendingDatagram);
895 900
896 // delete the datagram processor and the associated thread when the QThread quits901 // delete the datagram processor and the associated thread when the QThread quits
897 connect(_datagramProcessingThread, &QThread::finished, datagramProcessor, &QObject::deleteLater);902 connect(_datagramProcessingThread, &QThread::finished, datagramProcessor, &QObject::deleteLater);
898 connect(datagramProcessor, &QObject::destroyed, _datagramProcessingThread, &QThread::deleteLater);903 connect(datagramProcessor, &QObject::destroyed, _datagramProcessingThread, &QThread::deleteLater);
899 904
900 // start the datagram processing thread905 // start the datagram processing thread
901 _datagramProcessingThread->start();906 _datagramProcessingThread->start();
902}907}
@@ -961,16 +966,16 @@ void OctreeServer::readConfiguration() { · 58 unmodified lines
961 // wait until we have the domain-server settings, otherwise we bail966 // wait until we have the domain-server settings, otherwise we bail
962 auto nodeList = DependencyManager::get<NodeList>();967 auto nodeList = DependencyManager::get<NodeList>();
963 DomainHandler& domainHandler = nodeList->getDomainHandler();968 DomainHandler& domainHandler = nodeList->getDomainHandler();
964 969
965 qDebug() << "Waiting for domain settings from domain-server.";970 qDebug() << "Waiting for domain settings from domain-server.";
966 971
967 // block until we get the settingsRequestComplete signal972 // block until we get the settingsRequestComplete signal
968 QEventLoop loop;973 QEventLoop loop;
969 connect(&domainHandler, &DomainHandler::settingsReceived, &loop, &QEventLoop::quit);974 connect(&domainHandler, &DomainHandler::settingsReceived, &loop, &QEventLoop::quit);
970 connect(&domainHandler, &DomainHandler::settingsReceiveFail, &loop, &QEventLoop::quit);975 connect(&domainHandler, &DomainHandler::settingsReceiveFail, &loop, &QEventLoop::quit);
971 domainHandler.requestDomainSettings();976 domainHandler.requestDomainSettings();
972 loop.exec();977 loop.exec();
973 978
974 if (domainHandler.getSettingsObject().isEmpty()) {979 if (domainHandler.getSettingsObject().isEmpty()) {
975 qDebug() << "No settings object from domain-server.";980 qDebug() << "No settings object from domain-server.";
976 }981 }
@@ -978,7 +983,7 @@ void OctreeServer::readConfiguration() { · 1 unmodified line
978 QString settingsKey = getMyDomainSettingsKey();983 QString settingsKey = getMyDomainSettingsKey();
979 QJsonObject settingsSectionObject = settingsObject[settingsKey].toObject();984 QJsonObject settingsSectionObject = settingsObject[settingsKey].toObject();
980 _settings = settingsSectionObject; // keep this for later985 _settings = settingsSectionObject; // keep this for later
981 986
982 if (!readOptionString(QString("statusHost"), settingsSectionObject, _statusHost) || _statusHost.isEmpty()) {987 if (!readOptionString(QString("statusHost"), settingsSectionObject, _statusHost) || _statusHost.isEmpty()) {
983 _statusHost = getLocalAddress().toString();988 _statusHost = getLocalAddress().toString();
984 }989 }
@@ -1002,7 +1007,7 @@ void OctreeServer::readConfiguration() { · 17 unmodified lines
1002 bool hasRoot = readOptionString(QString("jurisdictionRoot"), settingsSectionObject, jurisdictionRoot);1007 bool hasRoot = readOptionString(QString("jurisdictionRoot"), settingsSectionObject, jurisdictionRoot);
1003 QString jurisdictionEndNodes;1008 QString jurisdictionEndNodes;
1004 bool hasEndNodes = readOptionString(QString("jurisdictionEndNodes"), settingsSectionObject, jurisdictionEndNodes);1009 bool hasEndNodes = readOptionString(QString("jurisdictionEndNodes"), settingsSectionObject, jurisdictionEndNodes);
1005 1010
1006 if (hasRoot || hasEndNodes) {1011 if (hasRoot || hasEndNodes) {
1007 _jurisdiction = new JurisdictionMap(qPrintable(jurisdictionRoot), qPrintable(jurisdictionEndNodes));1012 _jurisdiction = new JurisdictionMap(qPrintable(jurisdictionRoot), qPrintable(jurisdictionEndNodes));
1008 }1013 }
@@ -1050,7 +1055,7 @@ void OctreeServer::readConfiguration() { · 41 unmodified lines
1050 qDebug() << "wantBackup=" << _wantBackup;1055 qDebug() << "wantBackup=" << _wantBackup;
1051 1056
1052 //qDebug() << "settingsSectionObject:" << settingsSectionObject;1057 //qDebug() << "settingsSectionObject:" << settingsSectionObject;
1053 1058
1054 } else {1059 } else {
1055 qDebug("persistFilename= DISABLED");1060 qDebug("persistFilename= DISABLED");
1056 }1061 }
@@ -1072,7 +1077,7 @@ void OctreeServer::readConfiguration() { · 15 unmodified lines
1072 _packetsPerClientPerInterval = 1;1077 _packetsPerClientPerInterval = 1;
1073 }1078 }
1074 }1079 }
1075 qDebug("packetsPerSecondPerClientMax=%d _packetsPerClientPerInterval=%d", 1080 qDebug("packetsPerSecondPerClientMax=%d _packetsPerClientPerInterval=%d",
1076 packetsPerSecondPerClientMax, _packetsPerClientPerInterval);1081 packetsPerSecondPerClientMax, _packetsPerClientPerInterval);
1077 1082
1078 // Check to see if the user passed in a command line option for setting packet send rate1083 // Check to see if the user passed in a command line option for setting packet send rate
@@ -1083,10 +1088,10 @@ void OctreeServer::readConfiguration() { · 4 unmodified lines
1083 _packetsTotalPerInterval = 1;1088 _packetsTotalPerInterval = 1;
1084 }1089 }
1085 }1090 }
1086 qDebug("packetsPerSecondTotalMax=%d _packetsTotalPerInterval=%d", 1091 qDebug("packetsPerSecondTotalMax=%d _packetsTotalPerInterval=%d",
1087 packetsPerSecondTotalMax, _packetsTotalPerInterval);1092 packetsPerSecondTotalMax, _packetsTotalPerInterval);
1088 1093
1089 1094
1090 readAdditionalConfiguration(settingsSectionObject);1095 readAdditionalConfiguration(settingsSectionObject);
1091}1096}
1092 1097
@@ -1101,8 +1106,8 @@ void OctreeServer::run() { · 8 unmodified lines
1101 // make sure our NodeList knows what type we are1106 // make sure our NodeList knows what type we are
1102 auto nodeList = DependencyManager::get<NodeList>();1107 auto nodeList = DependencyManager::get<NodeList>();
1103 nodeList->setOwnerType(getMyNodeType());1108 nodeList->setOwnerType(getMyNodeType());
1104 1109
1105 1110
1106 // use common init to setup common timers and logging1111 // use common init to setup common timers and logging
1107 commonInit(getMyLoggingServerTargetName(), getMyNodeType());1112 commonInit(getMyLoggingServerTargetName(), getMyNodeType());
1108 1113
@@ -1110,7 +1115,7 @@ void OctreeServer::run() { · 1 unmodified line
1110 1115
1111 // read the configuration from either the payload or the domain server configuration1116 // read the configuration from either the payload or the domain server configuration
1112 readConfiguration();1117 readConfiguration();
1113 1118
1114 beforeRun(); // after payload has been processed1119 beforeRun(); // after payload has been processed
1115 1120
1116 connect(nodeList.data(), SIGNAL(nodeAdded(SharedNodePointer)), SLOT(nodeAdded(SharedNodePointer)));1121 connect(nodeList.data(), SIGNAL(nodeAdded(SharedNodePointer)), SLOT(nodeAdded(SharedNodePointer)));
@@ -1119,7 +1124,7 @@ void OctreeServer::run() { · 2 unmodified lines
1119 1124
1120 // we need to ask the DS about agents so we can ping/reply with them1125 // we need to ask the DS about agents so we can ping/reply with them
1121 nodeList->addNodeTypeToInterestSet(NodeType::Agent);1126 nodeList->addNodeTypeToInterestSet(NodeType::Agent);
1122 1127
1123#ifndef WIN321128#ifndef WIN32
1124 setvbuf(stdout, NULL, _IOLBF, 0);1129 setvbuf(stdout, NULL, _IOLBF, 0);
1125#endif1130#endif
@@ -1209,7 +1214,7 @@ void OctreeServer::forceNodeShutdown(SharedNodePointer node) { · 83 unmodified lines
1209 1214
1210 quint64 end = usecTimestampNow();1215 quint64 end = usecTimestampNow();
1211 quint64 usecsElapsed = (end - start);1216 quint64 usecsElapsed = (end - start);
1212 qDebug() << qPrintable(_safeServerName) << "server forceNodeShutdown() took: " 1217 qDebug() << qPrintable(_safeServerName) << "server forceNodeShutdown() took: "
1213 << usecsElapsed << " usecs for node:" << *node;1218 << usecsElapsed << " usecs for node:" << *node;
1214}1219}
1215 1220
@@ -1225,7 +1230,7 @@ void OctreeServer::aboutToFinish() { · 9 unmodified lines
1225 // This ensures that when we forceNodeShutdown below for each node we don't get any more newly connecting nodes1230 // This ensures that when we forceNodeShutdown below for each node we don't get any more newly connecting nodes
1226 auto nodeList = DependencyManager::get<NodeList>();1231 auto nodeList = DependencyManager::get<NodeList>();
1227 nodeList->linkedDataCreateCallback = NULL;1232 nodeList->linkedDataCreateCallback = NULL;
1228 1233
1229 if (_octreeInboundPacketProcessor) {1234 if (_octreeInboundPacketProcessor) {
1230 _octreeInboundPacketProcessor->terminating();1235 _octreeInboundPacketProcessor->terminating();
1231 }1236 }
@@ -1240,7 +1245,7 @@ void OctreeServer::aboutToFinish() { · 8 unmodified lines
1240 qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node;1245 qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node;
1241 forceNodeShutdown(node);1246 forceNodeShutdown(node);
1242 });1247 });
1243 1248
1244 if (_persistThread) {1249 if (_persistThread) {
1245 _persistThread->aboutToFinish();1250 _persistThread->aboutToFinish();
1246 _persistThread->terminating();1251 _persistThread->terminating();
@@ -1282,7 +1287,7 @@ QString OctreeServer::getUptime() { · 35 unmodified lines
1282 if (hours > 0 || minutes > 0) {1287 if (hours > 0 || minutes > 0) {
1283 formattedUptime += QString(" ");1288 formattedUptime += QString(" ");
1284 }1289 }
1285 formattedUptime += QString().sprintf("%.3f seconds", seconds);1290 formattedUptime += QString().sprintf("%.3f seconds", (double)seconds);
1286 }1291 }
1287 return formattedUptime;1292 return formattedUptime;
1288}1293}
@@ -1290,13 +1295,13 @@ QString OctreeServer::getUptime() { · 1 unmodified line
1290QString OctreeServer::getFileLoadTime() {1295QString OctreeServer::getFileLoadTime() {
1291 QString result;1296 QString result;
1292 if (isInitialLoadComplete()) {1297 if (isInitialLoadComplete()) {
1293 1298
1294 const int USECS_PER_MSEC = 1000;1299 const int USECS_PER_MSEC = 1000;
1295 const int MSECS_PER_SEC = 1000;1300 const int MSECS_PER_SEC = 1000;
1296 const int SECS_PER_MIN = 60;1301 const int SECS_PER_MIN = 60;
1297 const int MIN_PER_HOUR = 60;1302 const int MIN_PER_HOUR = 60;
1298 const int MSECS_PER_MIN = MSECS_PER_SEC * SECS_PER_MIN;1303 const int MSECS_PER_MIN = MSECS_PER_SEC * SECS_PER_MIN;
1299 1304
1300 quint64 msecsElapsed = getLoadElapsedTime() / USECS_PER_MSEC;;1305 quint64 msecsElapsed = getLoadElapsedTime() / USECS_PER_MSEC;;
1301 float seconds = (msecsElapsed % MSECS_PER_MIN)/(float)MSECS_PER_SEC;1306 float seconds = (msecsElapsed % MSECS_PER_MIN)/(float)MSECS_PER_SEC;
1302 int minutes = (msecsElapsed/(MSECS_PER_MIN)) % MIN_PER_HOUR;1307 int minutes = (msecsElapsed/(MSECS_PER_MIN)) % MIN_PER_HOUR;
@@ -1321,7 +1326,7 @@ QString OctreeServer::getFileLoadTime() { · 18 unmodified lines
1321 if (hours > 0 || minutes > 0) {1326 if (hours > 0 || minutes > 0) {
1322 result += QString(" ");1327 result += QString(" ");
1323 }1328 }
1324 result += QString().sprintf("%.3f seconds", seconds);1329 result += QString().sprintf("%.3f seconds", (double)seconds);
1325 }1330 }
1326 } else {1331 } else {
1327 result = "Not yet loaded...";1332 result = "Not yet loaded...";
@@ -1356,27 +1361,27 @@ void OctreeServer::sendStatsPacket() { · 28 unmodified lines
1356 // 2) only send new data1361 // 2) only send new data
1357 // 3) automatically break up into multiple packets1362 // 3) automatically break up into multiple packets
1358 static QJsonObject statsObject1;1363 static QJsonObject statsObject1;
1359 1364
1360 QString baseName = getMyServerName() + QString("Server");1365 QString baseName = getMyServerName() + QString("Server");
1361 1366
1362 statsObject1[baseName + QString(".0.1.configuration")] = getConfiguration();1367 statsObject1[baseName + QString(".0.1.configuration")] = getConfiguration();
1363 1368
1364 statsObject1[baseName + QString(".0.2.detailed_stats_url")] = getStatusLink();1369 statsObject1[baseName + QString(".0.2.detailed_stats_url")] = getStatusLink();
1365 1370
1366 statsObject1[baseName + QString(".0.3.uptime")] = getUptime();1371 statsObject1[baseName + QString(".0.3.uptime")] = getUptime();
1367 statsObject1[baseName + QString(".0.4.persistFileLoadTime")] = getFileLoadTime();1372 statsObject1[baseName + QString(".0.4.persistFileLoadTime")] = getFileLoadTime();
1368 statsObject1[baseName + QString(".0.5.clients")] = getCurrentClientCount();1373 statsObject1[baseName + QString(".0.5.clients")] = getCurrentClientCount();
1369 1374
1370 quint64 oneSecondAgo = usecTimestampNow() - USECS_PER_SECOND;1375 quint64 oneSecondAgo = usecTimestampNow() - USECS_PER_SECOND;
1371 1376
1372 statsObject1[baseName + QString(".0.6.threads.1.processing")] = (double)howManyThreadsDidProcess(oneSecondAgo);1377 statsObject1[baseName + QString(".0.6.threads.1.processing")] = (double)howManyThreadsDidProcess(oneSecondAgo);
1373 statsObject1[baseName + QString(".0.6.threads.2.packetDistributor")] = 1378 statsObject1[baseName + QString(".0.6.threads.2.packetDistributor")] =
1374 (double)howManyThreadsDidPacketDistributor(oneSecondAgo);1379 (double)howManyThreadsDidPacketDistributor(oneSecondAgo);
1375 statsObject1[baseName + QString(".0.6.threads.3.handlePacektSend")] = 1380 statsObject1[baseName + QString(".0.6.threads.3.handlePacektSend")] =
1376 (double)howManyThreadsDidHandlePacketSend(oneSecondAgo);1381 (double)howManyThreadsDidHandlePacketSend(oneSecondAgo);
1377 statsObject1[baseName + QString(".0.6.threads.4.writeDatagram")] = 1382 statsObject1[baseName + QString(".0.6.threads.4.writeDatagram")] =
1378 (double)howManyThreadsDidCallWriteDatagram(oneSecondAgo); 1383 (double)howManyThreadsDidCallWriteDatagram(oneSecondAgo);
1379 1384
1380 statsObject1[baseName + QString(".1.1.octree.elementCount")] = (double)OctreeElement::getNodeCount();1385 statsObject1[baseName + QString(".1.1.octree.elementCount")] = (double)OctreeElement::getNodeCount();
1381 statsObject1[baseName + QString(".1.2.octree.internalElementCount")] = (double)OctreeElement::getInternalNodeCount();1386 statsObject1[baseName + QString(".1.2.octree.internalElementCount")] = (double)OctreeElement::getInternalNodeCount();
1382 statsObject1[baseName + QString(".1.3.octree.leafElementCount")] = (double)OctreeElement::getLeafNodeCount();1387 statsObject1[baseName + QString(".1.3.octree.leafElementCount")] = (double)OctreeElement::getLeafNodeCount();
@@ -1388,9 +1393,9 @@ void OctreeServer::sendStatsPacket() { · 5 unmodified lines
1388 statsObject2[baseName + QString(".2.outbound.data.totalPackets")] = (double)OctreeSendThread::_totalPackets;1393 statsObject2[baseName + QString(".2.outbound.data.totalPackets")] = (double)OctreeSendThread::_totalPackets;
1389 statsObject2[baseName + QString(".2.outbound.data.totalBytes")] = (double)OctreeSendThread::_totalBytes;1394 statsObject2[baseName + QString(".2.outbound.data.totalBytes")] = (double)OctreeSendThread::_totalBytes;
1390 statsObject2[baseName + QString(".2.outbound.data.totalBytesWasted")] = (double)OctreeSendThread::_totalWastedBytes;1395 statsObject2[baseName + QString(".2.outbound.data.totalBytesWasted")] = (double)OctreeSendThread::_totalWastedBytes;
1391 statsObject2[baseName + QString(".2.outbound.data.totalBytesOctalCodes")] = 1396 statsObject2[baseName + QString(".2.outbound.data.totalBytesOctalCodes")] =
1392 (double)OctreePacketData::getTotalBytesOfOctalCodes();1397 (double)OctreePacketData::getTotalBytesOfOctalCodes();
1393 statsObject2[baseName + QString(".2.outbound.data.totalBytesBitMasks")] = 1398 statsObject2[baseName + QString(".2.outbound.data.totalBytesBitMasks")] =
1394 (double)OctreePacketData::getTotalBytesOfBitMasks();1399 (double)OctreePacketData::getTotalBytesOfBitMasks();
1395 statsObject2[baseName + QString(".2.outbound.data.totalBytesBitMasks")] = (double)OctreePacketData::getTotalBytesOfColor();1400 statsObject2[baseName + QString(".2.outbound.data.totalBytesBitMasks")] = (double)OctreePacketData::getTotalBytesOfColor();
1396 1401
@@ -1406,19 +1411,19 @@ void OctreeServer::sendStatsPacket() { · 9 unmodified lines
1406 1411
1407 static QJsonObject statsObject3;1412 static QJsonObject statsObject3;
1408 1413
1409 statsObject3[baseName + QString(".3.inbound.data.1.totalPackets")] = 1414 statsObject3[baseName + QString(".3.inbound.data.1.totalPackets")] =
1410 (double)_octreeInboundPacketProcessor->getTotalPacketsProcessed();1415 (double)_octreeInboundPacketProcessor->getTotalPacketsProcessed();
1411 statsObject3[baseName + QString(".3.inbound.data.2.totalElements")] = 1416 statsObject3[baseName + QString(".3.inbound.data.2.totalElements")] =
1412 (double)_octreeInboundPacketProcessor->getTotalElementsProcessed();1417 (double)_octreeInboundPacketProcessor->getTotalElementsProcessed();
1413 statsObject3[baseName + QString(".3.inbound.timing.1.avgTransitTimePerPacket")] = 1418 statsObject3[baseName + QString(".3.inbound.timing.1.avgTransitTimePerPacket")] =
1414 (double)_octreeInboundPacketProcessor->getAverageTransitTimePerPacket();1419 (double)_octreeInboundPacketProcessor->getAverageTransitTimePerPacket();
1415 statsObject3[baseName + QString(".3.inbound.timing.2.avgProcessTimePerPacket")] = 1420 statsObject3[baseName + QString(".3.inbound.timing.2.avgProcessTimePerPacket")] =
1416 (double)_octreeInboundPacketProcessor->getAverageProcessTimePerPacket();1421 (double)_octreeInboundPacketProcessor->getAverageProcessTimePerPacket();
1417 statsObject3[baseName + QString(".3.inbound.timing.3.avgLockWaitTimePerPacket")] = 1422 statsObject3[baseName + QString(".3.inbound.timing.3.avgLockWaitTimePerPacket")] =
1418 (double)_octreeInboundPacketProcessor->getAverageLockWaitTimePerPacket();1423 (double)_octreeInboundPacketProcessor->getAverageLockWaitTimePerPacket();
1419 statsObject3[baseName + QString(".3.inbound.timing.4.avgProcessTimePerElement")] = 1424 statsObject3[baseName + QString(".3.inbound.timing.4.avgProcessTimePerElement")] =
1420 (double)_octreeInboundPacketProcessor->getAverageProcessTimePerElement();1425 (double)_octreeInboundPacketProcessor->getAverageProcessTimePerElement();
1421 statsObject3[baseName + QString(".3.inbound.timing.5.avgLockWaitTimePerElement")] = 1426 statsObject3[baseName + QString(".3.inbound.timing.5.avgLockWaitTimePerElement")] =
1422 (double)_octreeInboundPacketProcessor->getAverageLockWaitTimePerElement();1427 (double)_octreeInboundPacketProcessor->getAverageLockWaitTimePerElement();
1423 1428
1424 DependencyManager::get<NodeList>()->sendStatsToDomainServer(statsObject3);1429 DependencyManager::get<NodeList>()->sendStatsToDomainServer(statsObject3);
cmake/externals/LibOVR/CMakeLists.txt+7−3
@@ -9,8 +9,8 @@ if (WIN32) · 8 unmodified lines
9 9
10 ExternalProject_Add(10 ExternalProject_Add(
11 ${EXTERNAL_NAME}11 ${EXTERNAL_NAME}
12 URL http://static.oculus.com/sdk-downloads/ovr_sdk_win_0.5.0.1.zip12 URL http://static.oculus.com/sdk-downloads/0.6.0.0/1431634088/ovr_sdk_win_0.6.0.0.zip
13 URL_MD5 d3fc4c02db9be5ff08af4ef4c97b32f913 URL_MD5 a3dfdab037a854fdcf7e6033fa8d7028
14 CONFIGURE_COMMAND ""14 CONFIGURE_COMMAND ""
15 BUILD_COMMAND ""15 BUILD_COMMAND ""
16 INSTALL_COMMAND ""16 INSTALL_COMMAND ""
@@ -21,7 +21,11 @@ if (WIN32) · 4 unmodified lines
21 21
22 # FIXME need to account for different architectures 22 # FIXME need to account for different architectures
23 set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/LibOVR/Include CACHE TYPE INTERNAL)23 set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/LibOVR/Include CACHE TYPE INTERNAL)
24 set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/LibOVR/Lib/Windows/Win32/Release/VS2013/LibOVR.lib CACHE TYPE INTERNAL)24 if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
25 set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/LibOVR/Lib/Windows/x64/Release/VS2013/LibOVR.lib CACHE TYPE INTERNAL)
26 else()
27 set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/LibOVR/Lib/Windows/Win32/Release/VS2013/LibOVR.lib CACHE TYPE INTERNAL)
28 endif()
25 29
26elseif(APPLE)30elseif(APPLE)
27 31
cmake/externals/boostconfig/CMakeLists.txt+7−7
@@ -3,13 +3,13 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) · 2 unmodified lines
3 3
4include(ExternalProject)4include(ExternalProject)
5ExternalProject_Add(5ExternalProject_Add(
6 ${EXTERNAL_NAME}6 ${EXTERNAL_NAME}
7 URL https://github.com/boostorg/config/archive/boost-1.58.0.zip7 URL https://github.com/boostorg/config/archive/boost-1.58.0.zip
8 URL_MD5 42fa673bae2b7645a22736445e80eb8d8 URL_MD5 42fa673bae2b7645a22736445e80eb8d
9 CONFIGURE_COMMAND ""9 CONFIGURE_COMMAND ""
10 BUILD_COMMAND ""10 BUILD_COMMAND ""
11 INSTALL_COMMAND ""11 INSTALL_COMMAND ""
12 LOG_DOWNLOAD 112 LOG_DOWNLOAD 1
13)13)
14 14
15ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)15ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
cmake/externals/glew/CMakeLists.txt+10−5
@@ -16,11 +16,16 @@ if (WIN32) · 15 unmodified lines
16 16
17 string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)17 string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
18 set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE PATH "List of glew include directories")18 set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE PATH "List of glew include directories")
19 19
20 set(_LIB_DIR ${SOURCE_DIR}/lib/Release/Win32)20 if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
21 21 set(_LIB_DIR ${SOURCE_DIR}/lib/Release/x64)
22 set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${SOURCE_DIR}/bin/Release/x64 CACHE FILEPATH "Location of GLEW DLL")
23 else()
24 set(_LIB_DIR ${SOURCE_DIR}/lib/Release/Win32)
25 set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${SOURCE_DIR}/bin/Release/Win32 CACHE FILEPATH "Location of GLEW DLL")
26 endif()
27
22 set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${_LIB_DIR}/glew32.lib CACHE FILEPATH "Location of GLEW release library")28 set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${_LIB_DIR}/glew32.lib CACHE FILEPATH "Location of GLEW release library")
23 set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "Location of GLEW debug library")29 set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "Location of GLEW debug library")
24 30
25 set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${SOURCE_DIR}/bin/Release/Win32 CACHE FILEPATH "Location of GLEW DLL")
26endif ()31endif ()
cmake/externals/oglplus/CMakeLists.txt+7−7
@@ -3,13 +3,13 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) · 2 unmodified lines
3 3
4include(ExternalProject)4include(ExternalProject)
5ExternalProject_Add(5ExternalProject_Add(
6 ${EXTERNAL_NAME}6 ${EXTERNAL_NAME}
7 URL http://softlayer-dal.dl.sourceforge.net/project/oglplus/oglplus-0.61.x/oglplus-0.61.0.zip7 GIT_REPOSITORY https://github.com/matus-chochlik/oglplus.git
8 URL_MD5 bb55038c36c660d2b6c7be380414fa608 GIT_TAG a2681383928b1166f176512cbe0f95e96fe68d08
9 CONFIGURE_COMMAND ""9 CONFIGURE_COMMAND ""
10 BUILD_COMMAND ""10 BUILD_COMMAND ""
11 INSTALL_COMMAND ""11 INSTALL_COMMAND ""
12 LOG_DOWNLOAD 112 LOG_DOWNLOAD 1
13)13)
14 14
15ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)15ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
cmake/externals/tbb/CMakeLists.txt+7−2
@@ -73,9 +73,14 @@ if (APPLE) · 72 unmodified lines
73 )73 )
74 74
75elseif (WIN32)75elseif (WIN32)
76 set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/ia32/vc12")76 if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
77 set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/intel64/vc12")
78 set(${EXTERNAL_NAME_UPPER}_DLL_PATH "${SOURCE_DIR}/bin/intel64/vc12" CACHE PATH "Path to TBB DLLs")
79 else()
80 set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/ia32/vc12")
81 set(${EXTERNAL_NAME_UPPER}_DLL_PATH "${SOURCE_DIR}/bin/ia32/vc12" CACHE PATH "Path to TBB DLLs")
82 endif()
77 set(_LIB_EXT "lib")83 set(_LIB_EXT "lib")
78 set(${EXTERNAL_NAME_UPPER}_DLL_PATH "${SOURCE_DIR}/bin/ia32/vc12" CACHE PATH "Path to TBB DLLs")
79elseif (ANDROID)84elseif (ANDROID)
80 set(_TBB_LIB_DIR "${SOURCE_DIR}/lib")85 set(_TBB_LIB_DIR "${SOURCE_DIR}/lib")
81 set(_LIB_PREFIX "lib")86 set(_LIB_PREFIX "lib")
cmake/macros/SetupHifiOpenGL.cmake+43−0
@@ -0,0 +1,43 @@
1
2
3macro(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
43endmacro()
cmake/modules/FindFaceshift.cmake+5−1
@@ -28,7 +28,11 @@ if (APPLE) · 27 unmodified lines
28elseif (UNIX)28elseif (UNIX)
29 set(ARCH_DIR "UNIX")29 set(ARCH_DIR "UNIX")
30elseif (WIN32)30elseif (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()
32endif ()36endif ()
33 37
34find_library(FACESHIFT_LIBRARY_RELEASE NAME faceshift PATH_SUFFIXES lib/${ARCH_DIR} HINTS ${FACESHIFT_SEARCH_DIRS})38find_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
16# 16#
17 17
18if (WIN32)18if (WIN32)
19 19
20 if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
21 set(ARCH_DIR "x64")
22 set(ARCH_NAME "64")
23 else()
24 set(ARCH_DIR "Win32")
25 set(ARCH_NAME "32")
26 endif()
27
28
20 find_path(NSIGHT_INCLUDE_DIRS29 find_path(NSIGHT_INCLUDE_DIRS
21 NAMES30 NAMES
22 nvToolsExt.h31 nvToolsExt.h
@@ -25,17 +34,18 @@ if (WIN32) · 2 unmodified lines
25 PATHS34 PATHS
26 "C:/Program Files/NVIDIA Corporation/NvToolsExt")35 "C:/Program Files/NVIDIA Corporation/NvToolsExt")
27 36
28 find_library(NSIGHT_LIBRARY_RELEASE nvToolsExt32_137 find_library(NSIGHT_LIBRARY_RELEASE "nvToolsExt${ARCH_NAME}_1"
29 PATH_SUFFIXES38 PATH_SUFFIXES
30 "lib/Win32" "lib"39 "lib/${ARCH_DIR}" "lib"
31 PATHS40 PATHS
32 "C:/Program Files/NVIDIA Corporation/NvToolsExt")41 "C:/Program Files/NVIDIA Corporation/NvToolsExt")
33 find_library(NSIGHT_LIBRARY_DEBUG nvToolsExt32_142 find_library(NSIGHT_LIBRARY_DEBUG "nvToolsExt${ARCH_NAME}_1"
34 PATH_SUFFIXES43 PATH_SUFFIXES
35 "lib/Win32" "lib"44 "lib/${ARCH_DIR}" "lib"
36 PATHS45 PATHS
37 "C:/Program Files/NVIDIA Corporation/NvToolsExt")46 "C:/Program Files/NVIDIA Corporation/NvToolsExt")
38 47
48 add_paths_to_fixup_libs("C:/Program Files/NVIDIA Corporation/NvToolsExt/bin/${ARCH_DIR}")
39 include(SelectLibraryConfigurations)49 include(SelectLibraryConfigurations)
40 select_library_configurations(NSIGHT)50 select_library_configurations(NSIGHT)
41endif ()51endif ()
cmake/modules/FindSixense.cmake+13−5
@@ -30,12 +30,20 @@ elseif (UNIX) · 29 unmodified lines
30 find_library(SIXENSE_LIBRARY_RELEASE lib/linux_x64/release/libsixense_x64.so HINTS ${SIXENSE_SEARCH_DIRS})30 find_library(SIXENSE_LIBRARY_RELEASE lib/linux_x64/release/libsixense_x64.so HINTS ${SIXENSE_SEARCH_DIRS})
31 # find_library(SIXENSE_LIBRARY_DEBUG lib/linux_x64/debug/libsixensed_x64.so HINTS ${SIXENSE_SEARCH_DIRS})31 # find_library(SIXENSE_LIBRARY_DEBUG lib/linux_x64/debug/libsixensed_x64.so HINTS ${SIXENSE_SEARCH_DIRS})
32elseif (WIN32)32elseif (WIN32)
33 find_library(SIXENSE_LIBRARY_RELEASE lib/win32/release_dll/sixense.lib HINTS ${SIXENSE_SEARCH_DIRS})33 if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
34 find_library(SIXENSE_LIBRARY_DEBUG lib/win32/debug_dll/sixensed.lib HINTS ${SIXENSE_SEARCH_DIRS})34 set(ARCH_DIR "x64")
35 set(ARCH_SUFFIX "_x64")
36 else()
37 set(ARCH_DIR "Win32")
38 set(ARCH_SUFFIX "")
39 endif()
40
41 find_library(SIXENSE_LIBRARY_RELEASE "lib/${ARCH_DIR}/release_dll/sixense${ARCH_SUFFIX}.lib" HINTS ${SIXENSE_SEARCH_DIRS})
42 find_library(SIXENSE_LIBRARY_DEBUG "lib/${ARCH_DIR}/debug_dll/sixensed.lib" HINTS ${SIXENSE_SEARCH_DIRS})
35 43
36 find_path(SIXENSE_DEBUG_DLL_PATH sixensed.dll PATH_SUFFIXES bin/win32/debug_dll HINTS ${SIXENSE_SEARCH_DIRS})44 find_path(SIXENSE_DEBUG_DLL_PATH "sixensed${ARCH_SUFFIX}.dll" PATH_SUFFIXES bin/${ARCH_DIR}/debug_dll HINTS ${SIXENSE_SEARCH_DIRS})
37 find_path(SIXENSE_RELEASE_DLL_PATH sixense.dll PATH_SUFFIXES bin/win32/release_dll HINTS ${SIXENSE_SEARCH_DIRS})45 find_path(SIXENSE_RELEASE_DLL_PATH "sixense${ARCH_SUFFIX}.dll" PATH_SUFFIXES bin/${ARCH_DIR}/release_dll HINTS ${SIXENSE_SEARCH_DIRS})
38 find_path(SIXENSE_DEVICE_DLL_PATH DeviceDLL.dll PATH_SUFFIXES samples/win32/sixense_simple3d HINTS ${SIXENSE_SEARCH_DIRS})46 find_path(SIXENSE_DEVICE_DLL_PATH DeviceDLL.dll PATH_SUFFIXES samples/${ARCH_DIR}/sixense_simple3d HINTS ${SIXENSE_SEARCH_DIRS})
39endif ()47endif ()
40 48
41include(SelectLibraryConfigurations)49include(SelectLibraryConfigurations)
cmake/modules/FindTBB.cmake+1−1
@@ -49,7 +49,7 @@ elseif (UNIX AND NOT ANDROID) · 48 unmodified lines
49 endif ()49 endif ()
50 50
51elseif (WIN32)51elseif (WIN32)
52 if (CMAKE_CL_64)52 if(CMAKE_SIZEOF_VOID_P EQUAL 8)
53 set(_TBB_ARCH_DIR "intel64")53 set(_TBB_ARCH_DIR "intel64")
54 else()54 else()
55 set(_TBB_ARCH_DIR "ia32")55 set(_TBB_ARCH_DIR "ia32")
examples/controllers/hydra/gun.js+7−9
@@ -100,12 +100,12 @@ var NUM_BUTTONS = 3; · 99 unmodified lines
100var screenSize = Controller.getViewportDimensions();100var screenSize = Controller.getViewportDimensions();
101var startX = screenSize.x / 2 - (NUM_BUTTONS * (BUTTON_SIZE + PADDING)) / 2;101var startX = screenSize.x / 2 - (NUM_BUTTONS * (BUTTON_SIZE + PADDING)) / 2;
102Script.include(["../../libraries/toolBars.js"]);102Script.include(["../../libraries/toolBars.js"]);
103const persistKey = "highfidelity.gun.toolbar.position";103var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.gun.toolbar", function (screenSize) {
104var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL);104 return {
105toolBar.save = function () {105 x: startX,
106 Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y]));106 y: (screenSize.y - (BUTTON_SIZE + PADDING)),
107};107 };
108var old = JSON.parse(Settings.getValue(persistKey) || '0');108});
109var reticle = Overlays.addOverlay("image", {109var reticle = Overlays.addOverlay("image", {
110 x: screenSize.x / 2 - (BUTTON_SIZE / 2),110 x: screenSize.x / 2 - (BUTTON_SIZE / 2),
111 y: screenSize.y / 2 - (BUTTON_SIZE / 2),111 y: screenSize.y / 2 - (BUTTON_SIZE / 2),
@@ -116,8 +116,6 @@ var reticle = Overlays.addOverlay("image", { · 4 unmodified lines
116 });116 });
117 117
118var offButton = toolBar.addOverlay("image", {118var offButton = toolBar.addOverlay("image", {
119 x: old ? old[0] : startX,
120 y: old ? old[1] : (screenSize.y - (BUTTON_SIZE + PADDING)),
121 width: BUTTON_SIZE,119 width: BUTTON_SIZE,
122 height: BUTTON_SIZE,120 height: BUTTON_SIZE,
123 imageURL: HIFI_PUBLIC_BUCKET + "images/gun/close.svg",121 imageURL: HIFI_PUBLIC_BUCKET + "images/gun/close.svg",
@@ -181,7 +179,7 @@ function entityCollisionWithEntity(entity1, entity2, collision) { · 57 unmodified lines
181}179}
182 180
183function shootBullet(position, velocity, grenade) {181function shootBullet(position, velocity, grenade) {
184 var BULLET_SIZE = 0.10;182 var BULLET_SIZE = .09;
185 var BULLET_LIFETIME = 10.0;183 var BULLET_LIFETIME = 10.0;
186 var BULLET_GRAVITY = -0.25;184 var BULLET_GRAVITY = -0.25;
187 var GRENADE_VELOCITY = 15.0;185 var GRENADE_VELOCITY = 15.0;
examples/defaultScripts.js+0−1
@@ -16,7 +16,6 @@ Script.load("lobby.js"); · 15 unmodified lines
16Script.load("notifications.js");16Script.load("notifications.js");
17Script.load("users.js");17Script.load("users.js");
18Script.load("grab.js");18Script.load("grab.js");
19Script.load("pointer.js");
20Script.load("directory.js");19Script.load("directory.js");
21Script.load("mouseLook.js");20Script.load("mouseLook.js");
22Script.load("hmdControls.js");21Script.load("hmdControls.js");
examples/dice.js+6−8
@@ -33,15 +33,13 @@ var BUTTON_SIZE = 32; · 32 unmodified lines
33var PADDING = 3;33var PADDING = 3;
34 34
35Script.include(["libraries/toolBars.js"]);35Script.include(["libraries/toolBars.js"]);
36var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL);36var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.dice.toolbar", function (screenSize) {
37const persistKey = "highfidelity.dice.toolbar.position";37 return {
38toolBar.save = function () {38 x: (screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING),
39 Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y]));39 y: (screenSize.y - (BUTTON_SIZE + PADDING))
40};40 };
41var old = JSON.parse(Settings.getValue(persistKey) || '0');41});
42var offButton = toolBar.addOverlay("image", {42var offButton = toolBar.addOverlay("image", {
43 x: old ? old[0] : (screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING),
44 y: old ? old[1] : (screenSize.y - (BUTTON_SIZE + PADDING)),
45 width: BUTTON_SIZE,43 width: BUTTON_SIZE,
46 height: BUTTON_SIZE,44 height: BUTTON_SIZE,
47 imageURL: HIFI_PUBLIC_BUCKET + "images/close.png",45 imageURL: HIFI_PUBLIC_BUCKET + "images/close.png",
examples/edit.js+7−35
@@ -49,7 +49,6 @@ selectionManager.addEventListener(function() { · 48 unmodified lines
49 lightOverlayManager.updatePositions();49 lightOverlayManager.updatePositions();
50});50});
51 51
52var windowDimensions = Controller.getViewportDimensions();
53var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/";52var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/";
54var toolHeight = 50;53var toolHeight = 50;
55var toolWidth = 50;54var toolWidth = 50;
@@ -143,7 +142,12 @@ var toolBar = (function () { · 87 unmodified lines
143 browseMarketplaceButton;142 browseMarketplaceButton;
144 143
145 function initialize() {144 function initialize() {
146 toolBar = new ToolBar(0, 0, ToolBar.VERTICAL);145 toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.edit.toolbar", function (windowDimensions, toolbar) {
146 return {
147 x: windowDimensions.x - 8 - toolbar.width,
148 y: (windowDimensions.y - toolbar.height) / 2
149 };
150 });
147 151
148 browseMarketplaceButton = toolBar.addTool({152 browseMarketplaceButton = toolBar.addTool({
149 imageURL: toolIconUrl + "marketplace.svg",153 imageURL: toolIconUrl + "marketplace.svg",
@@ -321,38 +325,6 @@ var toolBar = (function () { · 171 unmodified lines
321 }325 }
322 }326 }
323 327
324 const persistKey = "highfidelity.edit.toolbar.position";
325 that.move = function () {
326 var newViewPort,
327 toolsX,
328 toolsY;
329
330 newViewPort = Controller.getViewportDimensions();
331
332 if (toolBar === undefined) {
333 initialize();
334
335 toolBar.save = function () {
336 Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y]));
337 };
338 var old = JSON.parse(Settings.getValue(persistKey) || '0');
339 if (old) {
340 windowDimensions = newViewPort;
341 toolBar.move(old[0], old[1]);
342 return;
343 }
344 } else if (windowDimensions.x === newViewPort.x &&
345 windowDimensions.y === newViewPort.y) {
346 return;
347 }
348
349 windowDimensions = newViewPort;
350 toolsX = windowDimensions.x - 8 - toolBar.width;
351 toolsY = (windowDimensions.y - toolBar.height) / 2;
352
353 toolBar.move(toolsX, toolsY);
354 };
355
356 var newModelButtonDown = false;328 var newModelButtonDown = false;
357 var browseMarketplaceButtonDown = false;329 var browseMarketplaceButtonDown = false;
358 that.mousePressEvent = function (event) {330 that.mousePressEvent = function (event) {
@@ -552,6 +524,7 @@ var toolBar = (function () { · 193 unmodified lines
552 toolBar.cleanup();524 toolBar.cleanup();
553 };525 };
554 526
527 initialize();
555 return that;528 return that;
556}());529}());
557 530
@@ -931,7 +904,6 @@ var lastPosition = null; · 373 unmodified lines
931 904
932// Do some stuff regularly, like check for placement of various overlays905// Do some stuff regularly, like check for placement of various overlays
933Script.update.connect(function (deltaTime) {906Script.update.connect(function (deltaTime) {
934 toolBar.move();
935 progressDialog.move();907 progressDialog.move();
936 selectionDisplay.checkMove();908 selectionDisplay.checkMove();
937 var dOrientation = Math.abs(Quat.dot(Camera.orientation, lastOrientation) - 1);909 var dOrientation = Math.abs(Quat.dot(Camera.orientation, lastOrientation) - 1);
examples/html/style.css+12−14
@@ -8,7 +8,7 @@ body { · 7 unmodified lines
8 background-color: rgb(76, 76, 76);8 background-color: rgb(76, 76, 76);
9 color: rgb(204, 204, 204);9 color: rgb(204, 204, 204);
10 font-family: Arial;10 font-family: Arial;
11 font-size: 8.25pt;11 font-size: 9.0pt;
12 12
13 -webkit-touch-callout: none;13 -webkit-touch-callout: none;
14 -webkit-user-select: none;14 -webkit-user-select: none;
@@ -58,6 +58,7 @@ body { · 43 unmodified lines
58 58
59.multi-property-section {59.multi-property-section {
60}60}
61
61.property-section {62.property-section {
62 display: block;63 display: block;
63 margin: 10 10;64 margin: 10 10;
@@ -132,7 +133,7 @@ input.no-spin::-webkit-inner-spin-button { · 68 unmodified lines
132table#entity-table {133table#entity-table {
133 border-collapse: collapse;134 border-collapse: collapse;
134 font-family: Sans-Serif;135 font-family: Sans-Serif;
135 font-size: 7.5pt;136 font-size: 9pt;
136 width: 100%;137 width: 100%;
137}138}
138 139
@@ -156,7 +157,7 @@ table#entity-table { · 17 unmodified lines
156}157}
157 158
158#entity-table td {159#entity-table td {
159 font-size: 8.25pt;160 font-size: 9.0pt;
160 border: 0pt black solid;161 border: 0pt black solid;
161 word-wrap: nowrap;162 word-wrap: nowrap;
162 white-space: nowrap;163 white-space: nowrap;
@@ -176,14 +177,14 @@ th#entity-type { · 13 unmodified lines
176 177
177div.input-area {178div.input-area {
178 display: inline-block;179 display: inline-block;
179 font-size: 7.5pt;180 font-size: 9pt;
180}181}
181 182
182input {183input {
183}184}
184 185
185#type {186#type {
186 font-size: 10.5pt;187 font-size: 9.0pt;
187}188}
188 189
189#type label {190#type label {
@@ -191,14 +192,14 @@ input { · 1 unmodified line
191}192}
192 193
193input, textarea {194input, textarea {
194 background-color: rgb(102, 102, 102);195 background-color: rgb(63, 63, 63);
195 color: rgb(204, 204, 204);196 color: rgb(255, 255, 255);
196 border: none;197 border: none;
197 font-size: 7.5pt;198 font-size: 9pt;
198}199}
199 200
200input:disabled, textarea:disabled {201input:disabled, textarea:disabled {
201 background-color: rgb(102, 102, 102);202 background-color: rgb(63, 63, 63);
202 color: rgb(160, 160, 160);203 color: rgb(160, 160, 160);
203}204}
204 205
@@ -224,7 +225,7 @@ input:disabled, textarea:disabled { · 19 unmodified lines
224#properties-list .property {225#properties-list .property {
225 padding: 4pt;226 padding: 4pt;
226 border-bottom: 0.75pt solid rgb(63, 63, 63);227 border-bottom: 0.75pt solid rgb(63, 63, 63);
227 min-height: 1em;228 min-height: 12pt;
228}229}
229 230
230 231
@@ -245,7 +246,6 @@ table#properties-list { · 14 unmodified lines
245 font-weight: bold;246 font-weight: bold;
246 overflow: hidden;247 overflow: hidden;
247 text-overflow: ellipsis;248 text-overflow: ellipsis;
248
249 vertical-align: middle;249 vertical-align: middle;
250 height: 1.2em;250 height: 1.2em;
251}251}
@@ -270,9 +270,7 @@ div.inner { · 18 unmodified lines
270}270}
271 271
272td {272td {
273 273 vertical-align: top;
274
275 vertical-align: top;
276}274}
277 275
278#no-entities {276#no-entities {
examples/libraries/toolBars.js+47−6
@@ -126,7 +126,7 @@ Tool.prototype = new Overlay2D; · 125 unmodified lines
126Tool.IMAGE_HEIGHT = 50;126Tool.IMAGE_HEIGHT = 50;
127Tool.IMAGE_WIDTH = 50;127Tool.IMAGE_WIDTH = 50;
128 128
129ToolBar = function(x, y, direction) {129ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPositionFunction) {
130 this.tools = new Array();130 this.tools = new Array();
131 this.x = x;131 this.x = x;
132 this.y = y;132 this.y = y;
@@ -336,7 +336,7 @@ ToolBar = function(x, y, direction) { · 203 unmodified lines
336 return (that.x <= x) && (x <= (that.x + that.width)) &&336 return (that.x <= x) && (x <= (that.x + that.width)) &&
337 (that.y <= y) && (y <= (that.y + that.height));337 (that.y <= y) && (y <= (that.y + that.height));
338 }338 }
339 that.hover = function (enable) {339 that.hover = function (enable) { // Can be overriden or extended by clients.
340 that.isHovering = enable;340 that.isHovering = enable;
341 if (that.back) {341 if (that.back) {
342 if (enable) {342 if (enable) {
@@ -348,6 +348,26 @@ ToolBar = function(x, y, direction) { · 5 unmodified lines
348 });348 });
349 }349 }
350 };350 };
351 that.windowDimensions = Controller.getViewportDimensions();
352 // Maybe fixme: Keeping the same percent of the window size isn't always the right thing.
353 // For example, maybe we want "keep the same percentage to whatever two edges are closest to the edge of screen".
354 // If we change that, the places to do so are onResizeViewport, save (maybe), and the initial move based on Settings, below.
355 that.onResizeViewport = function (newSize) { // Can be overridden or extended by clients.
356 var fractionX = that.x / that.windowDimensions.x;
357 var fractionY = that.y / that.windowDimensions.y;
358 that.windowDimensions = newSize || Controller.getViewportDimensions();
359 that.move(fractionX * that.windowDimensions.x, fractionY * that.windowDimensions.y);
360 };
361 if (optionalPersistenceKey) {
362 this.fractionKey = optionalPersistenceKey + '.fraction';
363 this.save = function () {
364 var screenSize = Controller.getViewportDimensions();
365 var fraction = {x: that.x / screenSize.x, y: that.y / screenSize.y};
366 Settings.setValue(this.fractionKey, JSON.stringify(fraction));
367 }
368 } else {
369 this.save = function () { }; // Called on move. Can be overriden or extended by clients.
370 }
351 // These are currently only doing that which is necessary for toolbar hover and toolbar drag.371 // These are currently only doing that which is necessary for toolbar hover and toolbar drag.
352 // They have not yet been extended to tool hover/click/release, etc.372 // They have not yet been extended to tool hover/click/release, etc.
353 this.mousePressEvent = function (event) {373 this.mousePressEvent = function (event) {
@@ -375,15 +395,19 @@ ToolBar = function(x, y, direction) { · 21 unmodified lines
375 }395 }
376 that.move(that.dragOffsetX + event.x, that.dragOffsetY + event.y);396 that.move(that.dragOffsetX + event.x, that.dragOffsetY + event.y);
377 };397 };
398 that.checkResize = function () { // Can be overriden or extended, but usually not. See onResizeViewport.
399 var currentWindowSize = Controller.getViewportDimensions();
400 if ((currentWindowSize.x !== that.windowDimensions.x) || (currentWindowSize.y !== that.windowDimensions.y)) {
401 that.onResizeViewport(currentWindowSize);
402 }
403 };
378 Controller.mousePressEvent.connect(this.mousePressEvent);404 Controller.mousePressEvent.connect(this.mousePressEvent);
379 Controller.mouseMoveEvent.connect(this.mouseMove);405 Controller.mouseMoveEvent.connect(this.mouseMove);
380 // Called on move. A different approach would be to have all this on the prototype,406 Script.update.connect(that.checkResize);
381 // and let apps extend where needed. Ex. app defines its toolbar.move() to call this.__proto__.move and then save.
382 this.save = function () { };
383 // This compatability hack breaks the model, but makes converting existing scripts easier:407 // This compatability hack breaks the model, but makes converting existing scripts easier:
384 this.addOverlay = function (ignored, oldSchoolProperties) {408 this.addOverlay = function (ignored, oldSchoolProperties) {
385 var properties = JSON.parse(JSON.stringify(oldSchoolProperties)); // a copy409 var properties = JSON.parse(JSON.stringify(oldSchoolProperties)); // a copy
386 if (that.numberOfTools() === 0) {410 if ((that.numberOfTools() === 0) && (properties.x != undefined) && (properties.y != undefined)) {
387 that.move(properties.x, properties.y);411 that.move(properties.x, properties.y);
388 }412 }
389 delete properties.x;413 delete properties.x;
@@ -392,6 +416,23 @@ ToolBar = function(x, y, direction) { · 2 unmodified lines
392 var id = that.tools[index].overlay();416 var id = that.tools[index].overlay();
393 return id;417 return id;
394 }418 }
419 if (this.fractionKey || optionalInitialPositionFunction) {
420 var savedFraction = JSON.parse(Settings.getValue(this.fractionKey) || '0'); // getValue can answer empty string
421 var screenSize = Controller.getViewportDimensions();
422 if (savedFraction) {
423 // If we have saved data, keep the toolbar at the same proportion of the screen width/height.
424 that.move(savedFraction.x * screenSize.x, savedFraction.y * screenSize.y);
425 } else if (!optionalInitialPositionFunction) {
426 print("No initPosition(screenSize, intializedToolbar) specified for ToolBar");
427 } else {
428 // Call the optionalInitialPositionFunctinon() AFTER the client has had a chance to set up.
429 var that = this;
430 Script.setTimeout(function () {
431 var position = optionalInitialPositionFunction(screenSize, that);
432 that.move(position.x, position.y);
433 }, 0);
434 }
435 }
395}436}
396ToolBar.SPACING = 4;437ToolBar.SPACING = 4;
397ToolBar.VERTICAL = 0;438ToolBar.VERTICAL = 0;
examples/mouseLook.js+38−19
@@ -9,8 +9,6 @@ · 8 unmodified lines
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//10//
11 11
12HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
13
14var lastX = Window.getCursorPositionX();12var lastX = Window.getCursorPositionX();
15var lastY = Window.getCursorPositionY();13var lastY = Window.getCursorPositionY();
16var yawFromMouse = 0;14var yawFromMouse = 0;
@@ -46,6 +44,28 @@ var mouseLook = (function () { · 29 unmodified lines
46 }44 }
47 }45 }
48 46
47 function findInput(name) {
48 var availableInputs = Controller.getAvailableInputs(keyboardID);
49 for (i = 0; i < availableInputs.length; i++) {
50 if (availableInputs[i].inputName == name) {
51 return availableInputs[i].input;
52 }
53 }
54 // If the input isn't found, it will default to the first available input
55 return availableInputs[0].input;
56 }
57
58 function findAction(name) {
59 var actions = Controller.getAllActions();
60 for (var i = 0; i < actions.length; i++) {
61 if (actions[i].actionName == name) {
62 return i;
63 }
64 }
65 // If the action isn't found, it will default to the first available action
66 return 0;
67 }
68
49 function updateMapping() {69 function updateMapping() {
50 if (keyboardID != 0) {70 if (keyboardID != 0) {
51 if (active) {71 if (active) {
@@ -55,41 +75,40 @@ var mouseLook = (function () { · 3 unmodified lines
55 yawSpeed = 0;75 yawSpeed = 0;
56 pitchSpeed = 0;76 pitchSpeed = 0;
57 77
58 var a = Controller.getAvailableInputs(keyboardID)[10].input.channel;78 var a = findInput("A").channel;
59 var d = Controller.getAvailableInputs(keyboardID)[13].input.channel;79 var d = findInput("D").channel;
60 var left = Controller.getAvailableInputs(keyboardID)[36].input.channel;80 var left = findInput("Left").channel;
61 var right = Controller.getAvailableInputs(keyboardID)[38].input.channel;81 var right = findInput("Right").channel;
62 var shift = Controller.getAvailableInputs(keyboardID)[41].input.channel;82 var shift = findInput("Shift").channel;
63 83
64 for (i = 6; i <= 9; i++) {84 for (var i = findAction("YAW_LEFT"); i <= findAction("YAW_RIGHT"); i++) {
65 var inputChannels = Controller.getAllActions()[i].inputChannels;85 var inputChannels = Controller.getAllActions()[i].inputChannels;
66 for (j = 0; j < inputChannels.length; j++) {86 for (var j = 0; j < inputChannels.length; j++) {
67 var inputChannel = inputChannels[j];87 var inputChannel = inputChannels[j];
68
69 // make a, d, left, and right strafe88 // make a, d, left, and right strafe
70 if ((inputChannel.input.channel == a || inputChannel.input.channel == left) && inputChannel.modifier.device == 0) {89 if ((inputChannel.input.channel == a || inputChannel.input.channel == left) && inputChannel.modifier.device == 0) {
71 Controller.removeInputChannel(inputChannel);90 Controller.removeInputChannel(inputChannel);
72 inputChannel.action = 2;91 inputChannel.action = findAction("LATERAL_LEFT");
73 Controller.addInputChannel(inputChannel);92 Controller.addInputChannel(inputChannel);
74 } else if ((inputChannel.input.channel == d || inputChannel.input.channel == right) && inputChannel.modifier.device == 0) {93 } else if ((inputChannel.input.channel == d || inputChannel.input.channel == right) && inputChannel.modifier.device == 0) {
75 Controller.removeInputChannel(inputChannel);94 Controller.removeInputChannel(inputChannel);
76 inputChannel.action = 3;95 inputChannel.action = findAction("LATERAL_RIGHT");
77 Controller.addInputChannel(inputChannel);96 Controller.addInputChannel(inputChannel);
78 }97 }
79 }98 }
80 }99 }
81 // make shift + a/d/left/right change yaw/pitch100 for (var i = findAction("LATERAL_LEFT"); i <= findAction("LATERAL_RIGHT"); i++) {
82 for (i = 2; i <= 3; i++) {
83 var inputChannels = Controller.getAllActions()[i].inputChannels;101 var inputChannels = Controller.getAllActions()[i].inputChannels;
84 for (j = 0; j < inputChannels.length; j++) {102 for (var j = 0; j < inputChannels.length; j++) {
85 var inputChannel = inputChannels[j];103 var inputChannel = inputChannels[j];
104 // make shift + a/d/left/right change yaw/pitch
86 if ((inputChannel.input.channel == a || inputChannel.input.channel == left) && inputChannel.modifier.channel == shift) {105 if ((inputChannel.input.channel == a || inputChannel.input.channel == left) && inputChannel.modifier.channel == shift) {
87 Controller.removeInputChannel(inputChannel);106 Controller.removeInputChannel(inputChannel);
88 inputChannel.action = 6;107 inputChannel.action = findAction("YAW_LEFT");
89 Controller.addInputChannel(inputChannel);108 Controller.addInputChannel(inputChannel);
90 } else if ((inputChannel.input.channel == d || inputChannel.input.channel == right) && inputChannel.modifier.channel == shift) {109 } else if ((inputChannel.input.channel == d || inputChannel.input.channel == right) && inputChannel.modifier.channel == shift) {
91 Controller.removeInputChannel(inputChannel);110 Controller.removeInputChannel(inputChannel);
92 inputChannel.action = 7;111 inputChannel.action = findAction("YAW_RIGHT");
93 Controller.addInputChannel(inputChannel);112 Controller.addInputChannel(inputChannel);
94 }113 }
95 }114 }
@@ -134,8 +153,8 @@ var mouseLook = (function () { · 38 unmodified lines
134 }153 }
135 154
136 function resetCursorPosition() {155 function resetCursorPosition() {
137 var newX = Window.x + Window.innerWidth / 2;156 var newX = Window.x + Window.innerWidth / 2.0;
138 var newY = Window.y + Window.innerHeight / 2;157 var newY = Window.y + Window.innerHeight / 2.0;
139 Window.setCursorPosition(newX, newY);158 Window.setCursorPosition(newX, newY);
140 lastX = newX;159 lastX = newX;
141 lastY = newY;160 lastY = newY;
examples/paint.js+44−339
@@ -10,17 +10,16 @@ · 9 unmodified lines
10//10//
11// Distributed under the Apache License, Version 2.0.11// Distributed under the Apache License, Version 2.0.
12// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html12// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
13//13
14Script.include('lineRider.js')14var LINE_DIMENSIONS = 5;
15var MAX_POINTS_PER_LINE = 30;15var LIFETIME = 6000;
16var LINE_LIFETIME = 60 * 5 //5 minute lifetime
17 16
18var colorPalette = [{17var colorPalette = [{
19 red: 236,18 red: 236,
20 green: 208,19 green: 208,
21 blue: 12020 blue: 120
22}, {21}, {
23 red: 217,22 red: 214,
24 green: 91,23 green: 91,
25 blue: 6724 blue: 67
26}, {25}, {
@@ -40,15 +39,6 @@ var colorPalette = [{ · 13 unmodified lines
40var currentColorIndex = 0;39var currentColorIndex = 0;
41var currentColor = colorPalette[currentColorIndex];40var currentColor = colorPalette[currentColorIndex];
42 41
43
44
45if (hydraCheck() === true) {
46 HydraPaint();
47} else {
48 MousePaint();
49}
50
51
52function cycleColor() {42function cycleColor() {
53 currentColor = colorPalette[++currentColorIndex];43 currentColor = colorPalette[++currentColorIndex];
54 if (currentColorIndex === colorPalette.length - 1) {44 if (currentColorIndex === colorPalette.length - 1) {
@@ -57,42 +47,17 @@ function cycleColor() { · 2 unmodified lines
57 47
58}48}
59 49
60function hydraCheck() {50MousePaint();
61 var numberOfButtons = Controller.getNumberOfButtons();
62 var numberOfTriggers = Controller.getNumberOfTriggers();
63 var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
64 var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
65 hydrasConnected = (numberOfButtons == 12 && numberOfTriggers == 2 && controllersPerTrigger == 2);
66 return hydrasConnected; //hydrasConnected;
67}
68
69//************ Mouse Paint **************************
70 51
71function MousePaint() {52function MousePaint() {
72 var DRAWING_DISTANCE = 2;53 var DRAWING_DISTANCE = 5;
73 var lines = [];54 var lines = [];
74 var deletedLines = [];
75 var isDrawing = false;55 var isDrawing = false;
76 var path = [];
77
78 var lineRider = new LineRider();
79 lineRider.addStartHandler(function() {
80 var points = [];
81 //create points array from list of all points in path
82 path.forEach(function(point) {
83 points.push(point);
84 });
85 lineRider.setPath(points);
86 });
87
88
89 56
90 var LINE_WIDTH = 7;57 var LINE_WIDTH = 7;
91 var line;58 var line, linePosition;
92 var points = [];
93
94 59
95 var BRUSH_SIZE = 0.02;60 var BRUSH_SIZE = .05;
96 61
97 var brush = Entities.addEntity({62 var brush = Entities.addEntity({
98 type: 'Sphere',63 type: 'Sphere',
@@ -110,51 +75,42 @@ function MousePaint() { · 11 unmodified lines
110 });75 });
111 76
112 77
113 function newLine(point) {78 function newLine(position) {
79 linePosition = position;
114 line = Entities.addEntity({80 line = Entities.addEntity({
115 position: MyAvatar.position,81 position: position,
116 type: "Line",82 type: "Line",
117 color: currentColor,83 color: currentColor,
118 dimensions: {84 dimensions: {
119 x: 10,85 x: LINE_DIMENSIONS,
120 y: 10,86 y: LINE_DIMENSIONS,
121 z: 1087 z: LINE_DIMENSIONS
122 },88 },
89 linePoints: [],
123 lineWidth: LINE_WIDTH,90 lineWidth: LINE_WIDTH,
124 lifetime: LINE_LIFETIME91 lifetime: LIFETIME
125 });92 });
126 points = [];
127 if (point) {
128
129 points.push(point);
130 path.push(point);
131 }
132 lines.push(line);93 lines.push(line);
133 }94 }
134 95
135 96
136 function mouseMoveEvent(event) {97 function mouseMoveEvent(event) {
137 98
99 var worldPoint = computeWorldPoint(event);
100 Entities.editEntity(brush, {
101 position: worldPoint
102 });
103
138 if (!isDrawing) {104 if (!isDrawing) {
139 return;105 return;
140 }106 }
141 107
142 var pickRay = Camera.computePickRay(event.x, event.y);108 var localPoint = computeLocalPoint(event)
143 var addVector = Vec3.multiply(Vec3.normalize(pickRay.direction), DRAWING_DISTANCE);109 var success = Entities.appendPoint(line, localPoint);
144 var point = Vec3.sum(Camera.getPosition(), addVector);
145 points.push(point);
146 path.push(point);
147 Entities.editEntity(line, {
148 linePoints: points
149 });
150 Entities.editEntity(brush, {
151 position: point
152 });
153
154 110
155 if (points.length === MAX_POINTS_PER_LINE) {111 if (!success) {
156 //We need to start a new line!112 newLine(worldPoint);
157 newLine(point);113 Entities.appendPoint(line, computeLocalPoint(event));
158 }114 }
159 }115 }
160 116
@@ -171,17 +127,26 @@ function MousePaint() { · 10 unmodified lines
171 lines.push(restoredLine);127 lines.push(restoredLine);
172 }128 }
173 129
130 function computeWorldPoint(event) {
131 var pickRay = Camera.computePickRay(event.x, event.y);
132 var addVector = Vec3.multiply(Vec3.normalize(pickRay.direction), DRAWING_DISTANCE);
133 return Vec3.sum(Camera.getPosition(), addVector);
134 }
135
136 function computeLocalPoint(event) {
137
138 var localPoint = Vec3.subtract(computeWorldPoint(event), linePosition);
139 return localPoint;
140 }
141
174 function mousePressEvent(event) {142 function mousePressEvent(event) {
175 if(!event.isLeftButton) {143 if (!event.isLeftButton) {
176 isDrawing = false;144 isDrawing = false;
177 return;145 return;
178 }146 }
179 lineRider.mousePressEvent(event);147 newLine(computeWorldPoint(event));
180 path = [];
181 newLine();
182 isDrawing = true;148 isDrawing = true;
183 149
184
185 }150 }
186 151
187 function mouseReleaseEvent() {152 function mouseReleaseEvent() {
@@ -198,21 +163,21 @@ function MousePaint() { · 10 unmodified lines
198 if (event.text === "z") {163 if (event.text === "z") {
199 undoStroke();164 undoStroke();
200 }165 }
201 if(event.text === "x") {166 if (event.text === "x") {
202 redoStroke();167 redoStroke();
203 }168 }
204 }169 }
205 170
171
172
206 function cleanup() {173 function cleanup() {
207 lines.forEach(function(line) {174 lines.forEach(function(line) {
208 Entities.deleteEntity(line);175 // Entities.deleteEntity(line);
209 });176 });
210 Entities.deleteEntity(brush);177 Entities.deleteEntity(brush);
211 lineRider.cleanup();
212 178
213 }179 }
214 180
215
216 Controller.mousePressEvent.connect(mousePressEvent);181 Controller.mousePressEvent.connect(mousePressEvent);
217 Controller.mouseReleaseEvent.connect(mouseReleaseEvent);182 Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
218 Controller.mouseMoveEvent.connect(mouseMoveEvent);183 Controller.mouseMoveEvent.connect(mouseMoveEvent);
@@ -222,266 +187,6 @@ function MousePaint() { · 3 unmodified lines
222}187}
223 188
224 189
225
226//*****************HYDRA PAINT *******************************************
227
228
229
230function 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
485function randFloat(low, high) {190function randFloat(low, high) {
486 return low + Math.random() * (high - low);191 return low + Math.random() * (high - low);
487}192}
examples/pointer.js+3−9
@@ -29,19 +29,13 @@ var buttonOnColor = { · 28 unmodified lines
29};29};
30 30
31HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";31HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
32var screenSize = Controller.getViewportDimensions();
33 32
34var userCanPoint = false;33var userCanPoint = false;
35Script.include(["libraries/toolBars.js"]);34Script.include(["libraries/toolBars.js"]);
36const persistKey = "highfidelity.pointer.toolbar.position";35var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.pointer.toolbar", function (screenSize) {
37var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL);36 return {x: screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING, y: screenSize.y - (BUTTON_SIZE + PADDING)},
38toolBar.save = function () {37});
39 Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y]));
40};
41var old = JSON.parse(Settings.getValue(persistKey) || '0');
42var pointerButton = toolBar.addOverlay("image", {38var pointerButton = toolBar.addOverlay("image", {
43 x: old ? old[0] : screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING,
44 y: old ? old[1] : screenSize.y - (BUTTON_SIZE + PADDING),
45 width: BUTTON_SIZE,39 width: BUTTON_SIZE,
46 height: BUTTON_SIZE,40 height: BUTTON_SIZE,
47 imageURL: HIFI_PUBLIC_BUCKET + "images/laser.png",41 imageURL: HIFI_PUBLIC_BUCKET + "images/laser.png",
examples/stick.js+3−1
@@ -22,10 +22,12 @@ Script.setTimeout(function() { · 21 unmodified lines
22 type: "Model",22 type: "Model",
23 modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.fbx",23 modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.fbx",
24 compoundShapeURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.obj",24 compoundShapeURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.obj",
25 dimensions: {x: .11, y: .11, z: .59},25 dimensions: {x: .11, y: .11, z: 1.0},
26 position: MyAvatar.getRightPalmPosition(), // initial position doesn't matter, as long as it's close26 position: MyAvatar.getRightPalmPosition(), // initial position doesn't matter, as long as it's close
27 rotation: MyAvatar.orientation,27 rotation: MyAvatar.orientation,
28 damping: .1,28 damping: .1,
29 collisionSoundURL: "http://public.highfidelity.io/sounds/Collisions-hitsandslaps/67LCollision07.wav",
30 restitution: 0.01,
29 collisionsWillMove: true31 collisionsWillMove: true
30 });32 });
31 actionID = Entities.addAction("hold", stickID, {relativePosition: {x: 0.0, y: 0.0, z: -0.9},33 actionID = Entities.addAction("hold", stickID, {relativePosition: {x: 0.0, y: 0.0, z: -0.9},
examples/utilities.js+39−35
@@ -9,48 +9,52 @@ · 8 unmodified lines
9// Distributed under the Apache License, Version 2.0.9// Distributed under the Apache License, Version 2.0.
10// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html10// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
11 11
12function hslToRgb(hslColor) {
13 var h = hslColor.hue;
14 var s = hslColor.sat;
15 var l = hslColor.light;
16 var r, g, b;
17
18 if (s == 0) {
19 r = g = b = l; // achromatic
20 } else {
21 var hue2rgb = function hue2rgb(p, q, t) {
22 if (t < 0) t += 1;
23 if (t > 1) t -= 1;
24 if (t < 1 / 6) return p + (q - p) * 6 * t;
25 if (t < 1 / 2) return q;
26 if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
27 return p;
28 }
29
30 var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
31 var p = 2 * l - q;
32 r = hue2rgb(p, q, h + 1 / 3);
33 g = hue2rgb(p, q, h);
34 b = hue2rgb(p, q, h - 1 / 3);
35 }
36 12
37 return {
38 red: Math.round(r * 255),
39 green: Math.round(g * 255),
40 blue: Math.round(b * 255)
41 };
42 13
14map = function(value, min1, max1, min2, max2) {
15 return min2 + (max2 - min2) * ((value - min1) / (max1 - min1));
43}16}
44 17
45function map(value, min1, max1, min2, max2) {18hslToRgb = function(hslColor) {
46 return min2 + (max2 - min2) * ((value - min1) / (max1 - min1));19 var h = hslColor.hue;
20 var s = hslColor.sat;
21 var l = hslColor.light;
22 var r, g, b;
23
24 if (s == 0) {
25 r = g = b = l; // achromatic
26 } else {
27 var hue2rgb = function hue2rgb(p, q, t) {
28 if (t < 0) t += 1;
29 if (t > 1) t -= 1;
30 if (t < 1 / 6) return p + (q - p) * 6 * t;
31 if (t < 1 / 2) return q;
32 if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
33 return p;
34 }
35
36 var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
37 var p = 2 * l - q;
38 r = hue2rgb(p, q, h + 1 / 3);
39 g = hue2rgb(p, q, h);
40 b = hue2rgb(p, q, h - 1 / 3);
41 }
42
43 return {
44 red: Math.round(r * 255),
45 green: Math.round(g * 255),
46 blue: Math.round(b * 255)
47 };
48
47}49}
48 50
49function randFloat(low, high) {51
50 return low + Math.random() * (high - low);52
53randFloat = function(low, high) {
54 return low + Math.random() * (high - low);
51}55}
52 56
53 57
54function randInt(low, high) {58randInt = function(low, high) {
55 return Math.floor(randFloat(low, high));59 return Math.floor(randFloat(low, high));
56}60}
examples/utilities/tools/cookies.js+25−0
@@ -120,6 +120,23 @@ Slider = function(x,y,width,thumbSize) { · 119 unmodified lines
120 120
121 this.onValueChanged = function(value) {};121 this.onValueChanged = function(value) {};
122 122
123 this.setMaxValue = function(maxValue) {
124 if (this.maxValue == maxValue) {
125 return;
126 }
127 var currentVal = this.getValue();
128 this.maxValue = maxValue;
129 this.setValue(currentVal);
130 }
131 this.setMinValue = function(minValue) {
132 if (this.minValue == minValue) {
133 return;
134 }
135 var currentVal = this.getValue();
136 this.minValue = minValue;
137 this.setValue(currentVal);
138 }
139
123 this.destroy = function() {140 this.destroy = function() {
124 Overlays.deleteOverlay(this.background);141 Overlays.deleteOverlay(this.background);
125 Overlays.deleteOverlay(this.thumb);142 Overlays.deleteOverlay(this.thumb);
@@ -613,6 +630,14 @@ Panel = function(x, y) { · 487 unmodified lines
613 return null;630 return null;
614 }631 }
615 632
633 this.getWidget = function(name) {
634 var item = this.items[name];
635 if (item != null) {
636 return item.widget;
637 }
638 return null;
639 }
640
616 this.update = function(name) {641 this.update = function(name) {
617 var item = this.items[name];642 var item = this.items[name];
618 if (item != null) {643 if (item != null) {
examples/utilities/tools/renderEngineDebug.js+42−39
@@ -10,25 +10,7 @@ · 9 unmodified lines
10 10
11Script.include("cookies.js");11Script.include("cookies.js");
12 12
13var panel = new Panel(10, 400);13var panel = new Panel(10, 800);
14
15panel.newCheckbox("Enable Cull Opaque",
16 function(value) { Scene.setEngineCullOpaque((value != 0)); },
17 function() { return Scene.doEngineCullOpaque(); },
18 function(value) { return (value); }
19);
20
21panel.newCheckbox("Enable Sort Opaque",
22 function(value) { Scene.setEngineSortOpaque((value != 0)); },
23 function() { return Scene.doEngineSortOpaque(); },
24 function(value) { return (value); }
25);
26
27panel.newCheckbox("Enable Render Opaque",
28 function(value) { Scene.setEngineRenderOpaque((value != 0)); },
29 function() { return Scene.doEngineRenderOpaque(); },
30 function(value) { return (value); }
31);
32 14
33panel.newSlider("Num Feed Opaques", 0, 1000, 15panel.newSlider("Num Feed Opaques", 0, 1000,
34 function(value) { },16 function(value) { },
@@ -48,49 +30,70 @@ panel.newSlider("Max Drawn Opaques", -1, 1000, · 13 unmodified lines
48 function(value) { return (value); }30 function(value) { return (value); }
49);31);
50 32
51panel.newCheckbox("Enable Cull Transparent", 33panel.newSlider("Num Feed Transparents", 0, 100,
52 function(value) { Scene.setEngineCullTransparent((value != 0)); },34 function(value) { },
53 function() { return Scene.doEngineCullTransparent(); },35 function() { return Scene.getEngineNumFeedTransparentItems(); },
54 function(value) { return (value); }36 function(value) { return (value); }
55);37);
56 38
57panel.newCheckbox("Enable Sort Transparent", 39panel.newSlider("Num Drawn Transparents", 0, 100,
58 function(value) { Scene.setEngineSortTransparent((value != 0)); },40 function(value) { },
59 function() { return Scene.doEngineSortTransparent(); },41 function() { return Scene.getEngineNumDrawnTransparentItems(); },
60 function(value) { return (value); }42 function(value) { return (value); }
61);43);
62 44
63panel.newCheckbox("Enable Render Transparent", 45panel.newSlider("Max Drawn Transparents", -1, 100,
64 function(value) { Scene.setEngineRenderTransparent((value != 0)); },46 function(value) { Scene.setEngineMaxDrawnTransparentItems(value); },
65 function() { return Scene.doEngineRenderTransparent(); },47 function() { return Scene.getEngineMaxDrawnTransparentItems(); },
66 function(value) { return (value); }48 function(value) { return (value); }
67);49);
68 50
69panel.newSlider("Num Feed Transparents", 0, 100, 51panel.newSlider("Num Feed Overlay3Ds", 0, 100,
70 function(value) { },52 function(value) { },
71 function() { return Scene.getEngineNumFeedTransparentItems(); },53 function() { return Scene.getEngineNumFeedOverlay3DItems(); },
72 function(value) { return (value); }54 function(value) { return (value); }
73);55);
74 56
75panel.newSlider("Num Drawn Transparents", 0, 100, 57panel.newSlider("Num Drawn Overlay3Ds", 0, 100,
76 function(value) { },58 function(value) { },
77 function() { return Scene.getEngineNumDrawnTransparentItems(); },59 function() { return Scene.getEngineNumDrawnOverlay3DItems(); },
78 function(value) { return (value); }60 function(value) { return (value); }
79);61);
80 62
81panel.newSlider("Max Drawn Transparents", -1, 100, 63panel.newSlider("Max Drawn Overlay3Ds", -1, 100,
82 function(value) { Scene.setEngineMaxDrawnTransparentItems(value); },64 function(value) { Scene.setEngineMaxDrawnOverlay3DItems(value); },
83 function() { return Scene.getEngineMaxDrawnTransparentItems(); },65 function() { return Scene.getEngineMaxDrawnOverlay3DItems(); },
84 function(value) { return (value); }66 function(value) { return (value); }
85);67);
86 68
87var tickTackPeriod = 500;69var tickTackPeriod = 500;
88 70
89function updateCounters() {71function updateCounters() {
90 panel.set("Num Feed Opaques", panel.get("Num Feed Opaques"));72 var numFeedOpaques = panel.get("Num Feed Opaques");
91 panel.set("Num Drawn Opaques", panel.get("Num Drawn Opaques"));73 var numFeedTransparents = panel.get("Num Feed Transparents");
92 panel.set("Num Feed Transparents", panel.get("Num Feed Transparents"));74 var numFeedOverlay3Ds = panel.get("Num Feed Overlay3Ds");
93 panel.set("Num Drawn Transparents", panel.get("Num Drawn Transparents"));75
76 panel.set("Num Feed Opaques", numFeedOpaques);
77 panel.set("Num Drawn Opaques", panel.get("Num Drawn Opaques"));
78 panel.set("Num Feed Transparents", numFeedTransparents);
79 panel.set("Num Drawn Transparents", panel.get("Num Drawn Transparents"));
80 panel.set("Num Feed Overlay3Ds", numFeedOverlay3Ds);
81 panel.set("Num Drawn Overlay3Ds", panel.get("Num Drawn Overlay3Ds"));
82
83 var numMax = Math.max(numFeedOpaques * 1.2, 1);
84 panel.getWidget("Num Feed Opaques").setMaxValue(numMax);
85 panel.getWidget("Num Drawn Opaques").setMaxValue(numMax);
86 panel.getWidget("Max Drawn Opaques").setMaxValue(numMax);
87
88 numMax = Math.max(numFeedTransparents * 1.2, 1);
89 panel.getWidget("Num Feed Transparents").setMaxValue(numMax);
90 panel.getWidget("Num Drawn Transparents").setMaxValue(numMax);
91 panel.getWidget("Max Drawn Transparents").setMaxValue(numMax);
92
93 numMax = Math.max(numFeedOverlay3Ds * 1.2, 1);
94 panel.getWidget("Num Feed Overlay3Ds").setMaxValue(numMax);
95 panel.getWidget("Num Drawn Overlay3Ds").setMaxValue(numMax);
96 panel.getWidget("Max Drawn Overlay3Ds").setMaxValue(numMax);
94}97}
95Script.setInterval(updateCounters, tickTackPeriod);98Script.setInterval(updateCounters, tickTackPeriod);
96 99
interface/resources/images/address-bar.svg+21−5
@@ -15,7 +15,7 @@ · 14 unmodified lines
15 viewBox="0 0 1440 200"15 viewBox="0 0 1440 200"
16 id="svg4136"16 id="svg4136"
17 inkscape:version="0.91 r13725"17 inkscape:version="0.91 r13725"
18 sodipodi:docname="address-bar.svg">18 sodipodi:docname="address-bar.002.svg">
19 <metadata19 <metadata
20 id="metadata4144">20 id="metadata4144">
21 <rdf:RDF>21 <rdf:RDF>
@@ -39,14 +39,14 @@ · 17 unmodified lines
39 guidetolerance="10"39 guidetolerance="10"
40 inkscape:pageopacity="0"40 inkscape:pageopacity="0"
41 inkscape:pageshadow="2"41 inkscape:pageshadow="2"
42 inkscape:window-width="1840"42 inkscape:window-width="1835"
43 inkscape:window-height="1057"43 inkscape:window-height="1057"
44 id="namedview4140"44 id="namedview4140"
45 showgrid="false"45 showgrid="false"
46 inkscape:zoom="0.8671875"46 inkscape:zoom="0.61319416"
47 inkscape:cx="707.02439"47 inkscape:cx="132.58366"
48 inkscape:cy="52.468468"48 inkscape:cy="52.468468"
49 inkscape:window-x="72"49 inkscape:window-x="77"
50 inkscape:window-y="-8"50 inkscape:window-y="-8"
51 inkscape:window-maximized="1"51 inkscape:window-maximized="1"
52 inkscape:current-layer="svg4136" />52 inkscape:current-layer="svg4136" />
@@ -59,6 +59,15 @@ · 6 unmodified lines
59 y="30"59 y="30"
60 rx="16.025024"60 rx="16.025024"
61 ry="17.019567" />61 ry="17.019567" />
62 <rect
63 style="fill:#dadada;fill-opacity:1;stroke:#cbcbcb;stroke-width:0.33821851;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
64 id="rect4135"
65 width="292.86267"
66 height="139.66179"
67 x="150.32542"
68 y="30.169102"
69 rx="16.817432"
70 ry="20.612938" />
62 <circle71 <circle
63 style="fill:#b8b8b8;fill-opacity:1;stroke:none;stroke-opacity:1"72 style="fill:#b8b8b8;fill-opacity:1;stroke:none;stroke-opacity:1"
64 id="path4146"73 id="path4146"
@@ -69,4 +78,11 @@ · 4 unmodified lines
69 d="m 100,36.000005 c -22.1,0 -40,17.9 -40,39.999995 0,30 40,88 40,88 0,0 40,-58 40,-88 0,-22.099995 -17.9,-39.999995 -40,-39.999995 z m 0,22 c 9.9,0 18,8.099995 18,17.999995 0,9.9 -8.1,18 -18,18 -9.9,0 -18,-8.1 -18,-18 0,-9.9 8.1,-17.999995 18,-17.999995 z"78 d="m 100,36.000005 c -22.1,0 -40,17.9 -40,39.999995 0,30 40,88 40,88 0,0 40,-58 40,-88 0,-22.099995 -17.9,-39.999995 -40,-39.999995 z m 0,22 c 9.9,0 18,8.099995 18,17.999995 0,9.9 -8.1,18 -18,18 -9.9,0 -18,-8.1 -18,-18 0,-9.9 8.1,-17.999995 18,-17.999995 z"
70 id="path4138"79 id="path4138"
71 inkscape:connector-curvature="0" />80 inkscape:connector-curvature="0" />
81 <rect
82 style="fill:#bdbdbd;fill-opacity:1;stroke:none;stroke-width:0.30000001;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
83 id="rect4136"
84 width="4"
85 height="100"
86 x="310.12924"
87 y="50" />
72</svg>88</svg>
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
30 property int maximumX: parent ? parent.width - width : 030 property int maximumX: parent ? parent.width - width : 0
31 property int maximumY: parent ? parent.height - height : 031 property int maximumY: parent ? parent.height - height : 0
32 32
33
33 AddressBarDialog {34 AddressBarDialog {
34 id: addressBarDialog35 id: addressBarDialog
35 36
@@ -45,28 +46,6 @@ DialogContainer { · 9 unmodified lines
45 property int inputAreaHeight: 56.0 * root.scale // Height of the background's input area46 property int inputAreaHeight: 56.0 * root.scale // Height of the background's input area
46 property int inputAreaStep: (height - inputAreaHeight) / 247 property int inputAreaStep: (height - inputAreaHeight) / 2
47 48
48 TextInput {
49 id: addressLine
50
51 anchors {
52 fill: parent
53 leftMargin: parent.height + hifi.layout.spacing * 2
54 rightMargin: hifi.layout.spacing * 2
55 topMargin: parent.inputAreaStep + hifi.layout.spacing
56 bottomMargin: parent.inputAreaStep + hifi.layout.spacing
57
58 }
59
60 font.pixelSize: hifi.fonts.pixelSize * root.scale
61
62 helperText: "Go to: place, @user, /path, network address"
63
64 onAccepted: {
65 event.accepted = true // Generates erroneous error in program log, "ReferenceError: event is not defined".
66 addressBarDialog.loadAddress(addressLine.text)
67 }
68 }
69
70 MouseArea {49 MouseArea {
71 // Drag the icon50 // Drag the icon
72 width: parent.height51 width: parent.height
@@ -96,6 +75,73 @@ DialogContainer { · 23 unmodified lines
96 maximumY: root.parent ? root.maximumY + parent.inputAreaStep : 075 maximumY: root.parent ? root.maximumY + parent.inputAreaStep : 0
97 }76 }
98 }77 }
78
79 Image {
80 id: backArrow
81
82 source: addressBarDialog.backEnabled ? "../images/left-arrow.svg" : "../images/redarrow_reversed.svg"
83
84 anchors {
85 fill: parent
86 leftMargin: parent.height + hifi.layout.spacing + 6
87 rightMargin: parent.height + hifi.layout.spacing * 60
88 topMargin: parent.inputAreaStep + parent.inputAreaStep + hifi.layout.spacing
89 bottomMargin: parent.inputAreaStep + parent.inputAreaStep + hifi.layout.spacing
90 }
91
92 MouseArea {
93 anchors.fill: parent
94 acceptedButtons: Qt.LeftButton
95 onClicked: {
96 addressBarDialog.loadBack()
97 }
98 }
99 }
100
101 Image {
102 id: forwardArrow
103
104 source: addressBarDialog.forwardEnabled ? "../images/right-arrow.svg" : "../images/redarrow.svg"
105
106 anchors {
107 fill: parent
108 leftMargin: parent.height + hifi.layout.spacing * 9
109 rightMargin: parent.height + hifi.layout.spacing * 53
110 topMargin: parent.inputAreaStep + parent.inputAreaStep + hifi.layout.spacing
111 bottomMargin: parent.inputAreaStep + parent.inputAreaStep + hifi.layout.spacing
112 }
113
114 MouseArea {
115 anchors.fill: parent
116 acceptedButtons: Qt.LeftButton
117 onClicked: {
118 addressBarDialog.loadForward()
119 }
120 }
121 }
122
123 TextInput {
124 id: addressLine
125
126 anchors {
127 fill: parent
128 leftMargin: parent.height + parent.height + hifi.layout.spacing * 5
129 rightMargin: hifi.layout.spacing * 2
130 topMargin: parent.inputAreaStep + hifi.layout.spacing
131 bottomMargin: parent.inputAreaStep + hifi.layout.spacing
132
133 }
134
135 font.pixelSize: hifi.fonts.pixelSize * root.scale * 0.75
136
137 helperText: "Go to: place, @user, /path, network address"
138
139 onAccepted: {
140 event.accepted = true // Generates erroneous error in program log, "ReferenceError: event is not defined".
141 addressBarDialog.loadAddress(addressLine.text)
142 }
143 }
144
99 }145 }
100 }146 }
101 147
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
9import Hifi 1.0 as Hifi
10import QtQuick 2.4
11import QtQuick.Controls 1.3
12import QtGraphicalEffects 1.0
13
14Hifi.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 @@
1import Hifi 1.0 as Hifi
2import QtQuick 2.3
3import QtQuick.Controls 1.2
4
5Item {
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 @@
1import Hifi 1.0 as Hifi
2import QtQuick 2.3 as Original
3import "controls"
4import "styles"
5
6Hifi.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
66#include <EntityScriptingInterface.h>66#include <EntityScriptingInterface.h>
67#include <ErrorDialog.h>67#include <ErrorDialog.h>
68#include <GlowEffect.h>68#include <GlowEffect.h>
69#include <gpu/Batch.h>
70#include <gpu/Context.h>
71#include <gpu/GLBackend.h>
69#include <HFActionEvent.h>72#include <HFActionEvent.h>
70#include <HFBackEvent.h>73#include <HFBackEvent.h>
71#include <InfoView.h>74#include <InfoView.h>
@@ -83,12 +86,14 @@ · 11 unmodified lines
83#include <PerfStat.h>86#include <PerfStat.h>
84#include <PhysicsEngine.h>87#include <PhysicsEngine.h>
85#include <ProgramObject.h>88#include <ProgramObject.h>
89#include <RenderDeferredTask.h>
86#include <ResourceCache.h>90#include <ResourceCache.h>
87#include <SceneScriptingInterface.h>91#include <SceneScriptingInterface.h>
88#include <ScriptCache.h>92#include <ScriptCache.h>
89#include <SettingHandle.h>93#include <SettingHandle.h>
90#include <SoundCache.h>94#include <SoundCache.h>
91#include <TextRenderer.h>95#include <TextRenderer.h>
96#include <Tooltip.h>
92#include <UserActivityLogger.h>97#include <UserActivityLogger.h>
93#include <UUID.h>98#include <UUID.h>
94#include <VrMenu.h>99#include <VrMenu.h>
@@ -106,11 +111,9 @@ · 11 unmodified lines
106 111
107#include "avatar/AvatarManager.h"112#include "avatar/AvatarManager.h"
108 113
109#include "audio/AudioToolBox.h"
110#include "audio/AudioIOStatsRenderer.h"114#include "audio/AudioIOStatsRenderer.h"
111#include "audio/AudioScope.h"115#include "audio/AudioScope.h"
112 116
113#include "devices/CameraToolBox.h"
114#include "devices/DdeFaceTracker.h"117#include "devices/DdeFaceTracker.h"
115#include "devices/Faceshift.h"118#include "devices/Faceshift.h"
116#include "devices/Leapmotion.h"119#include "devices/Leapmotion.h"
@@ -120,12 +123,6 @@ · 3 unmodified lines
120#include "devices/OculusManager.h"123#include "devices/OculusManager.h"
121#include "devices/TV3DManager.h"124#include "devices/TV3DManager.h"
122 125
123#include "gpu/Batch.h"
124#include "gpu/Context.h"
125#include "gpu/GLBackend.h"
126
127#include "RenderDeferredTask.h"
128
129#include "scripting/AccountScriptingInterface.h"126#include "scripting/AccountScriptingInterface.h"
130#include "scripting/AudioDeviceScriptingInterface.h"127#include "scripting/AudioDeviceScriptingInterface.h"
131#include "scripting/ClipboardScriptingInterface.h"128#include "scripting/ClipboardScriptingInterface.h"
@@ -141,6 +138,7 @@ · 9 unmodified lines
141#include "SpeechRecognizer.h"138#include "SpeechRecognizer.h"
142#endif139#endif
143 140
141#include "ui/AvatarInputs.h"
144#include "ui/DataWebDialog.h"142#include "ui/DataWebDialog.h"
145#include "ui/DialogsManager.h"143#include "ui/DialogsManager.h"
146#include "ui/LoginDialog.h"144#include "ui/LoginDialog.h"
@@ -281,8 +279,6 @@ bool setupEssentials(int& argc, char** argv) { · 134 unmodified lines
281 auto animationCache = DependencyManager::set<AnimationCache>();279 auto animationCache = DependencyManager::set<AnimationCache>();
282 auto ddeFaceTracker = DependencyManager::set<DdeFaceTracker>();280 auto ddeFaceTracker = DependencyManager::set<DdeFaceTracker>();
283 auto modelBlender = DependencyManager::set<ModelBlender>();281 auto modelBlender = DependencyManager::set<ModelBlender>();
284 auto audioToolBox = DependencyManager::set<AudioToolBox>();
285 auto cameraToolBox = DependencyManager::set<CameraToolBox>();
286 auto avatarManager = DependencyManager::set<AvatarManager>();282 auto avatarManager = DependencyManager::set<AvatarManager>();
287 auto lodManager = DependencyManager::set<LODManager>();283 auto lodManager = DependencyManager::set<LODManager>();
288 auto jsConsole = DependencyManager::set<StandAloneJSConsole>();284 auto jsConsole = DependencyManager::set<StandAloneJSConsole>();
@@ -335,8 +331,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : · 46 unmodified lines
335 _cursorVisible(true),331 _cursorVisible(true),
336 _lastMouseMove(usecTimestampNow()),332 _lastMouseMove(usecTimestampNow()),
337 _lastMouseMoveWasSimulated(false),333 _lastMouseMoveWasSimulated(false),
338 _touchAvgX(0.0f),
339 _touchAvgY(0.0f),
340 _isTouchPressed(false),334 _isTouchPressed(false),
341 _mousePressed(false),335 _mousePressed(false),
342 _enableProcessOctreeThread(true),336 _enableProcessOctreeThread(true),
@@ -814,9 +808,9 @@ void Application::initializeGL() { · 471 unmodified lines
814 _idleLoopStdev.reset();808 _idleLoopStdev.reset();
815 809
816 if (_justStarted) {810 if (_justStarted) {
817 float startupTime = (float)_applicationStartupTime.elapsed() / 1000.0;811 float startupTime = (float)_applicationStartupTime.elapsed() / 1000.0f;
818 _justStarted = false;812 _justStarted = false;
819 qCDebug(interfaceapp, "Startup time: %4.2f seconds.", startupTime);813 qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTime);
820 }814 }
821 815
822 // update before the first render816 // update before the first render
@@ -831,6 +825,7 @@ void Application::initializeUi() { · 8 unmodified lines
831 LoginDialog::registerType();825 LoginDialog::registerType();
832 MessageDialog::registerType();826 MessageDialog::registerType();
833 VrMenu::registerType();827 VrMenu::registerType();
828 Tooltip::registerType();
834 UpdateDialog::registerType();829 UpdateDialog::registerType();
835 830
836 auto offscreenUi = DependencyManager::get<OffscreenUi>();831 auto offscreenUi = DependencyManager::get<OffscreenUi>();
@@ -844,7 +839,7 @@ void Application::initializeUi() { · 7 unmodified lines
844 VrMenu::executeQueuedLambdas();839 VrMenu::executeQueuedLambdas();
845 offscreenUi->setMouseTranslator([this](const QPointF& p){840 offscreenUi->setMouseTranslator([this](const QPointF& p){
846 if (OculusManager::isConnected()) {841 if (OculusManager::isConnected()) {
847 glm::vec2 pos = _applicationOverlay.screenToOverlay(toGlm(p));842 glm::vec2 pos = _compositor.screenToOverlay(toGlm(p));
848 return QPointF(pos.x, pos.y);843 return QPointF(pos.x, pos.y);
849 }844 }
850 return QPointF(p);845 return QPointF(p);
@@ -877,6 +872,7 @@ void Application::paintGL() { · 26 unmodified lines
877 OculusManager::beginFrameTiming();872 OculusManager::beginFrameTiming();
878 }873 }
879 874
875
880 PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings));876 PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings));
881 bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);877 bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
882 PerformanceWarning warn(showWarnings, "Application::paintGL()");878 PerformanceWarning warn(showWarnings, "Application::paintGL()");
@@ -884,6 +880,12 @@ void Application::paintGL() { · 1 unmodified line
884 880
885 {881 {
886 PerformanceTimer perfTimer("renderOverlay");882 PerformanceTimer perfTimer("renderOverlay");
883 /*
884 gpu::Context context(new gpu::GLBackend());
885 RenderArgs renderArgs(&context, nullptr, getViewFrustum(), lodManager->getOctreeSizeScale(),
886 lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE,
887 RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
888 */
887 _applicationOverlay.renderOverlay(&renderArgs);889 _applicationOverlay.renderOverlay(&renderArgs);
888 }890 }
889 891
@@ -912,13 +914,18 @@ void Application::paintGL() { · 22 unmodified lines
912 }914 }
913 915
914 } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {916 } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
915 _myCamera.setPosition(_myAvatar->getDefaultEyePosition() +
916 _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, 1.0f) * _myAvatar->getBoomLength() * _myAvatar->getScale());
917 if (OculusManager::isConnected()) {917 if (OculusManager::isConnected()) {
918 _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation());918 _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation());
919 } else {919 } else {
920 _myCamera.setRotation(_myAvatar->getHead()->getOrientation());920 _myCamera.setRotation(_myAvatar->getHead()->getOrientation());
921 }921 }
922 if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) {
923 _myCamera.setPosition(_myAvatar->getDefaultEyePosition() +
924 _myCamera.getRotation() * glm::vec3(0.0f, 0.0f, 1.0f) * _myAvatar->getBoomLength() * _myAvatar->getScale());
925 } else {
926 _myCamera.setPosition(_myAvatar->getDefaultEyePosition() +
927 _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, 1.0f) * _myAvatar->getBoomLength() * _myAvatar->getScale());
928 }
922 929
923 } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {930 } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
924 _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));931 _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
@@ -967,9 +974,7 @@ void Application::paintGL() { · 42 unmodified lines
967 glPopMatrix();974 glPopMatrix();
968 975
969 renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE;976 renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE;
970 if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {977 if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
971 _rearMirrorTools->render(&renderArgs, true, _glWidget->mapFromGlobal(QCursor::pos()));
972 } else if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
973 renderRearViewMirror(&renderArgs, _mirrorViewRect); 978 renderRearViewMirror(&renderArgs, _mirrorViewRect);
974 }979 }
975 980
@@ -977,6 +982,7 @@ void Application::paintGL() { · 1 unmodified line
977 982
978 auto finalFbo = DependencyManager::get<GlowEffect>()->render(&renderArgs);983 auto finalFbo = DependencyManager::get<GlowEffect>()->render(&renderArgs);
979 984
985
980 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);986 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
981 glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo));987 glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo));
982 glBlitFramebuffer(0, 0, _renderResolution.x, _renderResolution.y,988 glBlitFramebuffer(0, 0, _renderResolution.x, _renderResolution.y,
@@ -984,9 +990,10 @@ void Application::paintGL() { · 1 unmodified line
984 GL_COLOR_BUFFER_BIT, GL_NEAREST);990 GL_COLOR_BUFFER_BIT, GL_NEAREST);
985 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);991 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
986 992
987 _applicationOverlay.displayOverlayTexture();993 _compositor.displayOverlayTexture(&renderArgs);
988 }994 }
989 995
996
990 if (!OculusManager::isConnected() || OculusManager::allowSwap()) {997 if (!OculusManager::isConnected() || OculusManager::allowSwap()) {
991 _glWidget->swapBuffers();998 _glWidget->swapBuffers();
992 }999 }
@@ -1044,27 +1051,24 @@ void Application::resizeGL() { · 51 unmodified lines
1044 } else {1051 } else {
1045 renderSize = _glWidget->getDeviceSize() * getRenderResolutionScale();1052 renderSize = _glWidget->getDeviceSize() * getRenderResolutionScale();
1046 }1053 }
1047 if (_renderResolution == toGlm(renderSize)) {
1048 return;
1049 }
1050 1054
1051 _renderResolution = toGlm(renderSize);1055 if (_renderResolution != toGlm(renderSize)) {
1052 DependencyManager::get<TextureCache>()->setFrameBufferSize(renderSize);1056 _renderResolution = toGlm(renderSize);
1053 resetCamerasOnResizeGL(_myCamera, _renderResolution);1057 DependencyManager::get<TextureCache>()->setFrameBufferSize(renderSize);
1058 resetCamerasOnResizeGL(_myCamera, _renderResolution);
1054 1059
1055 glViewport(0, 0, _renderResolution.x, _renderResolution.y); // shouldn't this account for the menu???1060 glViewport(0, 0, _renderResolution.x, _renderResolution.y); // shouldn't this account for the menu???
1056 1061
1057 updateProjectionMatrix();1062 updateProjectionMatrix();
1058 glLoadIdentity();1063 glLoadIdentity();
1064 }
1059 1065
1060 auto offscreenUi = DependencyManager::get<OffscreenUi>();1066 auto offscreenUi = DependencyManager::get<OffscreenUi>();
1061 offscreenUi->resize(_glWidget->size());1067
1068 auto canvasSize = _glWidget->size();
1069 offscreenUi->resize(canvasSize);
1062 _glWidget->makeCurrent();1070 _glWidget->makeCurrent();
1063 1071
1064 // update Stats width
1065 // let's set horizontal offset to give stats some margin to mirror
1066 int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2;
1067 Stats::getInstance()->resetWidth(_renderResolution.x, horizontalOffset);
1068}1072}
1069 1073
1070void Application::updateProjectionMatrix() {1074void Application::updateProjectionMatrix() {
@@ -1568,27 +1572,9 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { · 497 unmodified lines
1568 _keyboardMouseDevice.mousePressEvent(event);1572 _keyboardMouseDevice.mousePressEvent(event);
1569 1573
1570 if (event->button() == Qt::LeftButton) {1574 if (event->button() == Qt::LeftButton) {
1571 _mouseDragStartedX = getTrueMouseX();1575 _mouseDragStarted = getTrueMouse();
1572 _mouseDragStartedY = getTrueMouseY();
1573 _mousePressed = true;1576 _mousePressed = true;
1574 1577
1575 if (mouseOnScreen()) {
1576 if (DependencyManager::get<AudioToolBox>()->mousePressEvent(getMouseX(), getMouseY())) {
1577 // stop propagation
1578 return;
1579 }
1580
1581 if (DependencyManager::get<CameraToolBox>()->mousePressEvent(getMouseX(), getMouseY())) {
1582 // stop propagation
1583 return;
1584 }
1585
1586 if (_rearMirrorTools->mousePressEvent(getMouseX(), getMouseY())) {
1587 // stop propagation
1588 return;
1589 }
1590 }
1591
1592 // nobody handled this - make it an action event on the _window object1578 // nobody handled this - make it an action event on the _window object
1593 HFActionEvent actionEvent(HFActionEvent::startType(),1579 HFActionEvent actionEvent(HFActionEvent::startType(),
1594 computePickRay(event->x(), event->y()));1580 computePickRay(event->x(), event->y()));
@@ -1606,16 +1592,7 @@ void Application::mouseDoublePressEvent(QMouseEvent* event, unsigned int deviceI · 11 unmodified lines
1606 return;1592 return;
1607 }1593 }
1608 1594
1609 if (activeWindow() == _window) {1595 _controllerScriptingInterface.emitMouseDoublePressEvent(event);
1610 if (event->button() == Qt::LeftButton) {
1611 if (mouseOnScreen()) {
1612 if (DependencyManager::get<CameraToolBox>()->mouseDoublePressEvent(getMouseX(), getMouseY())) {
1613 // stop propagation
1614 return;
1615 }
1616 }
1617 }
1618 }
1619}1596}
1620 1597
1621void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) {1598void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) {
@@ -1637,13 +1614,6 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { · 15 unmodified lines
1637 if (event->button() == Qt::LeftButton) {1614 if (event->button() == Qt::LeftButton) {
1638 _mousePressed = false;1615 _mousePressed = false;
1639 1616
1640 if (Menu::getInstance()->isOptionChecked(MenuOption::Stats) && mouseOnScreen()) {
1641 // let's set horizontal offset to give stats some margin to mirror
1642 int horizontalOffset = MIRROR_VIEW_WIDTH;
1643 Stats::getInstance()->checkClick(getMouseX(), getMouseY(),
1644 getMouseDragStartedX(), getMouseDragStartedY(), horizontalOffset);
1645 }
1646
1647 // fire an action end event1617 // fire an action end event
1648 HFActionEvent actionEvent(HFActionEvent::endType(),1618 HFActionEvent actionEvent(HFActionEvent::endType(),
1649 computePickRay(event->x(), event->y()));1619 computePickRay(event->x(), event->y()));
@@ -1671,22 +1641,18 @@ void Application::touchUpdateEvent(QTouchEvent* event) { · 21 unmodified lines
1671 bool validTouch = false;1641 bool validTouch = false;
1672 if (activeWindow() == _window) {1642 if (activeWindow() == _window) {
1673 const QList<QTouchEvent::TouchPoint>& tPoints = event->touchPoints();1643 const QList<QTouchEvent::TouchPoint>& tPoints = event->touchPoints();
1674 _touchAvgX = 0.0f;1644 _touchAvg = vec2();
1675 _touchAvgY = 0.0f;
1676 int numTouches = tPoints.count();1645 int numTouches = tPoints.count();
1677 if (numTouches > 1) {1646 if (numTouches > 1) {
1678 for (int i = 0; i < numTouches; ++i) {1647 for (int i = 0; i < numTouches; ++i) {
1679 _touchAvgX += tPoints[i].pos().x();1648 _touchAvg += toGlm(tPoints[i].pos());
1680 _touchAvgY += tPoints[i].pos().y();
1681 }1649 }
1682 _touchAvgX /= (float)(numTouches);1650 _touchAvg /= (float)(numTouches);
1683 _touchAvgY /= (float)(numTouches);
1684 validTouch = true;1651 validTouch = true;
1685 }1652 }
1686 }1653 }
1687 if (!_isTouchPressed) {1654 if (!_isTouchPressed) {
1688 _touchDragStartedAvgX = _touchAvgX;1655 _touchDragStartedAvg = _touchAvg;
1689 _touchDragStartedAvgY = _touchAvgY;
1690 }1656 }
1691 _isTouchPressed = validTouch;1657 _isTouchPressed = validTouch;
1692}1658}
@@ -1722,8 +1688,7 @@ void Application::touchEndEvent(QTouchEvent* event) { · 29 unmodified lines
1722 _keyboardMouseDevice.touchEndEvent(event);1688 _keyboardMouseDevice.touchEndEvent(event);
1723 1689
1724 // put any application specific touch behavior below here..1690 // put any application specific touch behavior below here..
1725 _touchDragStartedAvgX = _touchAvgX;1691 _touchDragStartedAvg = _touchAvg;
1726 _touchDragStartedAvgY = _touchAvgY;
1727 _isTouchPressed = false;1692 _isTouchPressed = false;
1728 1693
1729}1694}
@@ -1872,9 +1837,9 @@ void Application::setFullscreen(bool fullscreen) { · 142 unmodified lines
1872 Menu::getInstance()->getActionForOption(MenuOption::Fullscreen)->setChecked(fullscreen);1837 Menu::getInstance()->getActionForOption(MenuOption::Fullscreen)->setChecked(fullscreen);
1873 }1838 }
1874 1839
1875// The following code block is useful on platforms that can have a visible1840 // 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 the1841 // app menu in a fullscreen window. However the OSX mechanism hides the
1877// application menu for fullscreen apps, so the check is not required.1842 // application menu for fullscreen apps, so the check is not required.
1878#ifndef Q_OS_MAC1843#ifndef Q_OS_MAC
1879 if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {1844 if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {
1880 if (fullscreen) {1845 if (fullscreen) {
@@ -1939,16 +1904,15 @@ void Application::setEnableVRMode(bool enableVRMode) { · 58 unmodified lines
1939 // attempt to reconnect the Oculus manager - it's possible this was a workaround1904 // attempt to reconnect the Oculus manager - it's possible this was a workaround
1940 // for the sixense crash1905 // for the sixense crash
1941 OculusManager::disconnect();1906 OculusManager::disconnect();
1942 OculusManager::connect();1907 OculusManager::connect(_glWidget->context()->contextHandle());
1908 _glWidget->setFocus();
1909 _glWidget->makeCurrent();
1910 glClear(GL_COLOR_BUFFER_BIT);
1943 }1911 }
1944 OculusManager::recalibrate();1912 OculusManager::recalibrate();
1945 } else {1913 } else {
1946 OculusManager::abandonCalibration();1914 OculusManager::abandonCalibration();
1947 1915 OculusManager::disconnect();
1948 _mirrorCamera.setHmdPosition(glm::vec3());
1949 _mirrorCamera.setHmdRotation(glm::quat());
1950 _myCamera.setHmdPosition(glm::vec3());
1951 _myCamera.setHmdRotation(glm::quat());
1952 }1916 }
1953 1917
1954 resizeGL();1918 resizeGL();
@@ -1960,44 +1924,34 @@ void Application::setLowVelocityFilter(bool lowVelocityFilter) { · 5 unmodified lines
1960 1924
1961bool Application::mouseOnScreen() const {1925bool Application::mouseOnScreen() const {
1962 if (OculusManager::isConnected()) {1926 if (OculusManager::isConnected()) {
1963 return getMouseX() >= 0 && getMouseX() <= _glWidget->getDeviceWidth() &&1927 ivec2 mouse = getMouse();
1964 getMouseY() >= 0 && getMouseY() <= _glWidget->getDeviceHeight();1928 if (!glm::all(glm::greaterThanEqual(mouse, ivec2()))) {
1929 return false;
1930 }
1931 ivec2 size = toGlm(_glWidget->getDeviceSize());
1932 if (!glm::all(glm::lessThanEqual(mouse, size))) {
1933 return false;
1934 }
1965 }1935 }
1966 return true;1936 return true;
1967}1937}
1968 1938
1969int Application::getMouseX() const {1939ivec2 Application::getMouse() const {
1970 if (OculusManager::isConnected()) {
1971 glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseX(), getTrueMouseY()));
1972 return pos.x;
1973 }
1974 return getTrueMouseX();
1975}
1976
1977int Application::getMouseY() const {
1978 if (OculusManager::isConnected()) {1940 if (OculusManager::isConnected()) {
1979 glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseX(), getTrueMouseY()));1941 return _compositor.screenToOverlay(getTrueMouse());
1980 return pos.y;
1981 }1942 }
1982 return getTrueMouseY();1943 return getTrueMouse();
1983}1944}
1984 1945
1985int Application::getMouseDragStartedX() const {1946ivec2 Application::getMouseDragStarted() const {
1986 if (OculusManager::isConnected()) {1947 if (OculusManager::isConnected()) {
1987 glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseDragStartedX(),1948 return _compositor.screenToOverlay(getTrueMouseDragStarted());
1988 getTrueMouseDragStartedY()));
1989 return pos.x;
1990 }1949 }
1991 return getTrueMouseDragStartedX();1950 return getTrueMouseDragStarted();
1992}1951}
1993 1952
1994int Application::getMouseDragStartedY() const {1953ivec2 Application::getTrueMouseDragStarted() const {
1995 if (OculusManager::isConnected()) {1954 return _mouseDragStarted;
1996 glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseDragStartedX(),
1997 getTrueMouseDragStartedY()));
1998 return pos.y;
1999 }
2000 return getTrueMouseDragStartedY();
2001}1955}
2002 1956
2003FaceTracker* Application::getActiveFaceTracker() {1957FaceTracker* Application::getActiveFaceTracker() {
@@ -2179,13 +2133,6 @@ void Application::init() { · 175 unmodified lines
2179 2133
2180 _mirrorCamera.setMode(CAMERA_MODE_MIRROR);2134 _mirrorCamera.setMode(CAMERA_MODE_MIRROR);
2181 2135
2182 OculusManager::connect();
2183 if (OculusManager::isConnected()) {
2184 QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen),
2185 "trigger",
2186 Qt::QueuedConnection);
2187 }
2188
2189 TV3DManager::connect();2136 TV3DManager::connect();
2190 if (TV3DManager::isConnected()) {2137 if (TV3DManager::isConnected()) {
2191 QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen),2138 QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen),
@@ -2249,13 +2196,6 @@ void Application::init() { · 57 unmodified lines
2249 _entityClipboardRenderer.setViewFrustum(getViewFrustum());2196 _entityClipboardRenderer.setViewFrustum(getViewFrustum());
2250 _entityClipboardRenderer.setTree(&_entityClipboard);2197 _entityClipboardRenderer.setTree(&_entityClipboard);
2251 2198
2252 _rearMirrorTools = new RearMirrorTools(_mirrorViewRect);
2253
2254 connect(_rearMirrorTools, SIGNAL(closeView()), SLOT(closeMirrorView()));
2255 connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView()));
2256 connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView()));
2257 connect(_rearMirrorTools, SIGNAL(resetView()), SLOT(resetSensors()));
2258
2259 // initialize the GlowEffect with our widget2199 // initialize the GlowEffect with our widget
2260 bool glow = Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect);2200 bool glow = Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect);
2261 DependencyManager::get<GlowEffect>()->init(glow);2201 DependencyManager::get<GlowEffect>()->init(glow);
@@ -2434,6 +2374,12 @@ void Application::cameraMenuChanged() { · 172 unmodified lines
2434 }2374 }
2435}2375}
2436 2376
2377void Application::rotationModeChanged() {
2378 if (!Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) {
2379 _myAvatar->setHeadPitch(0);
2380 }
2381}
2382
2437void Application::updateCamera(float deltaTime) {2383void Application::updateCamera(float deltaTime) {
2438 PerformanceTimer perfTimer("updateCamera");2384 PerformanceTimer perfTimer("updateCamera");
2439 bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);2385 bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
@@ -3155,7 +3101,7 @@ PickRay Application::computePickRay(float x, float y) const { · 715 unmodified lines
3155 y /= size.y;3101 y /= size.y;
3156 PickRay result;3102 PickRay result;
3157 if (isHMDMode()) {3103 if (isHMDMode()) {
3158 getApplicationOverlay().computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction);3104 getApplicationCompositor().computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction);
3159 } else {3105 } else {
3160 if (QThread::currentThread() == activeRenderingThread) {3106 if (QThread::currentThread() == activeRenderingThread) {
3161 getDisplayViewFrustum()->computePickRay(x, y, result.origin, result.direction);3107 getDisplayViewFrustum()->computePickRay(x, y, result.origin, result.direction);
@@ -3184,13 +3130,11 @@ QImage Application::renderAvatarBillboard(RenderArgs* renderArgs) { · 22 unmodified lines
3184 renderRearViewMirror(renderArgs, QRect(0, _glWidget->getDeviceHeight() - BILLBOARD_SIZE,3130 renderRearViewMirror(renderArgs, QRect(0, _glWidget->getDeviceHeight() - BILLBOARD_SIZE,
3185 BILLBOARD_SIZE, BILLBOARD_SIZE),3131 BILLBOARD_SIZE, BILLBOARD_SIZE),
3186 true);3132 true);
3187
3188 QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32);3133 QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32);
3189 glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits());3134 glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
3190 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);3135 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
3191 3136
3192 glBindFramebuffer(GL_FRAMEBUFFER, 0);3137 glBindFramebuffer(GL_FRAMEBUFFER, 0);
3193
3194 return image;3138 return image;
3195}3139}
3196 3140
@@ -3386,9 +3330,8 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 189 unmodified lines
3386 3330
3387 // flip x if in mirror mode (also requires reversing winding order for backface culling)3331 // flip x if in mirror mode (also requires reversing winding order for backface culling)
3388 if (theCamera.getMode() == CAMERA_MODE_MIRROR) {3332 if (theCamera.getMode() == CAMERA_MODE_MIRROR) {
3389 glScalef(-1.0f, 1.0f, 1.0f);3333 //glScalef(-1.0f, 1.0f, 1.0f);
3390 glFrontFace(GL_CW);3334 //glFrontFace(GL_CW);
3391
3392 } else {3335 } else {
3393 glFrontFace(GL_CCW);3336 glFrontFace(GL_CCW);
3394 }3337 }
@@ -3411,7 +3354,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 16 unmodified lines
3411 viewTransform.setTranslation(theCamera.getPosition());3354 viewTransform.setTranslation(theCamera.getPosition());
3412 viewTransform.setRotation(rotation);3355 viewTransform.setRotation(rotation);
3413 if (theCamera.getMode() == CAMERA_MODE_MIRROR) {3356 if (theCamera.getMode() == CAMERA_MODE_MIRROR) {
3414 viewTransform.setScale(Transform::Vec3(-1.0f, 1.0f, 1.0f));3357// viewTransform.setScale(Transform::Vec3(-1.0f, 1.0f, 1.0f));
3415 }3358 }
3416 if (renderArgs->_renderSide != RenderArgs::MONO) {3359 if (renderArgs->_renderSide != RenderArgs::MONO) {
3417 glm::mat4 invView = glm::inverse(_untranslatedViewMatrix);3360 glm::mat4 invView = glm::inverse(_untranslatedViewMatrix);
@@ -3548,6 +3491,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 130 unmodified lines
3548 3491
3549 renderContext._maxDrawnOpaqueItems = sceneInterface->getEngineMaxDrawnOpaqueItems();3492 renderContext._maxDrawnOpaqueItems = sceneInterface->getEngineMaxDrawnOpaqueItems();
3550 renderContext._maxDrawnTransparentItems = sceneInterface->getEngineMaxDrawnTransparentItems();3493 renderContext._maxDrawnTransparentItems = sceneInterface->getEngineMaxDrawnTransparentItems();
3494 renderContext._maxDrawnOverlay3DItems = sceneInterface->getEngineMaxDrawnOverlay3DItems();
3551 3495
3552 renderArgs->_shouldRender = LODManager::shouldRender;3496 renderArgs->_shouldRender = LODManager::shouldRender;
3553 3497
@@ -3564,7 +3508,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 10 unmodified lines
3564 3508
3565 sceneInterface->setEngineFeedTransparentItems(engineRC->_numFeedTransparentItems);3509 sceneInterface->setEngineFeedTransparentItems(engineRC->_numFeedTransparentItems);
3566 sceneInterface->setEngineDrawnTransparentItems(engineRC->_numDrawnTransparentItems);3510 sceneInterface->setEngineDrawnTransparentItems(engineRC->_numDrawnTransparentItems);
3567 3511
3512 sceneInterface->setEngineFeedOverlay3DItems(engineRC->_numFeedOverlay3DItems);
3513 sceneInterface->setEngineDrawnOverlay3DItems(engineRC->_numDrawnOverlay3DItems);
3568 }3514 }
3569 //Render the sixense lasers3515 //Render the sixense lasers
3570 if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) {3516 if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) {
@@ -3672,8 +3618,8 @@ glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) { · 101 unmodified lines
3672 // +-----------------------+3618 // +-----------------------+
3673 // -1,-1 1,-13619 // -1,-1 1,-1
3674 3620
3675 glm::vec2 screenPoint((projectedPoint.x + 1.0) * horizontalScale,3621 glm::vec2 screenPoint((projectedPoint.x + 1.0f) * horizontalScale,
3676 ((projectedPoint.y + 1.0) * -verticalScale) + _glWidget->getDeviceHeight());3622 ((projectedPoint.y + 1.0f) * -verticalScale) + _glWidget->getDeviceHeight());
3677 3623
3678 return screenPoint;3624 return screenPoint;
3679}3625}
@@ -3691,7 +3637,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi · 11 unmodified lines
3691 _mirrorCamera.setPosition(_myAvatar->getPosition() +3637 _mirrorCamera.setPosition(_myAvatar->getPosition() +
3692 _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * BILLBOARD_DISTANCE * _myAvatar->getScale());3638 _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * BILLBOARD_DISTANCE * _myAvatar->getScale());
3693 3639
3694 } else if (RearMirrorTools::rearViewZoomLevel.get() == BODY) {3640 } else if (!AvatarInputs::getInstance()->mirrorZoomed()) {
3695 _mirrorCamera.setPosition(_myAvatar->getChestPosition() +3641 _mirrorCamera.setPosition(_myAvatar->getChestPosition() +
3696 _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_REARVIEW_BODY_DISTANCE * _myAvatar->getScale());3642 _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_REARVIEW_BODY_DISTANCE * _myAvatar->getScale());
3697 3643
@@ -3726,7 +3672,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi · 28 unmodified lines
3726 } else {3672 } else {
3727 // if not rendering the billboard, the region is in device independent coordinates; must convert to device3673 // if not rendering the billboard, the region is in device independent coordinates; must convert to device
3728 QSize size = DependencyManager::get<TextureCache>()->getFrameBufferSize();3674 QSize size = DependencyManager::get<TextureCache>()->getFrameBufferSize();
3729 float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale();3675 float ratio = (float)QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale();
3730 int x = region.x() * ratio, y = region.y() * ratio, width = region.width() * ratio, height = region.height() * ratio;3676 int x = region.x() * ratio, y = region.y() * ratio, width = region.width() * ratio, height = region.height() * ratio;
3731 glViewport(x, size.height() - y - height, width, height);3677 glViewport(x, size.height() - y - height, width, height);
3732 glScissor(x, size.height() - y - height, width, height);3678 glScissor(x, size.height() - y - height, width, height);
@@ -3741,10 +3687,6 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi · 8 unmodified lines
3741 displaySide(renderArgs, _mirrorCamera, true, billboard);3687 displaySide(renderArgs, _mirrorCamera, true, billboard);
3742 glPopMatrix();3688 glPopMatrix();
3743 3689
3744 if (!billboard) {
3745 _rearMirrorTools->render(renderArgs, false, _glWidget->mapFromGlobal(QCursor::pos()));
3746 }
3747
3748 // reset Viewport and projection matrix3690 // reset Viewport and projection matrix
3749 glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);3691 glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
3750 glDisable(GL_SCISSOR_TEST);3692 glDisable(GL_SCISSOR_TEST);
@@ -3884,7 +3826,7 @@ void Application::nodeKilled(SharedNodePointer node) { · 133 unmodified lines
3884 _entityServerJurisdictions.unlock();3826 _entityServerJurisdictions.unlock();
3885 3827
3886 qCDebug(interfaceapp, "model server going away...... v[%f, %f, %f, %f]",3828 qCDebug(interfaceapp, "model server going away...... v[%f, %f, %f, %f]",
3887 rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);3829 (double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s);
3888 3830
3889 // Add the jurisditionDetails object to the list of "fade outs"3831 // Add the jurisditionDetails object to the list of "fade outs"
3890 if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnOctreeServerChanges)) {3832 if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnOctreeServerChanges)) {
@@ -3970,7 +3912,8 @@ int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePoin · 79 unmodified lines
3970 jurisdiction->unlock();3912 jurisdiction->unlock();
3971 3913
3972 qCDebug(interfaceapp, "stats from new %s server... [%f, %f, %f, %f]",3914 qCDebug(interfaceapp, "stats from new %s server... [%f, %f, %f, %f]",
3973 qPrintable(serverType), rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);3915 qPrintable(serverType),
3916 (double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s);
3974 3917
3975 // Add the jurisditionDetails object to the list of "fade outs"3918 // Add the jurisditionDetails object to the list of "fade outs"
3976 if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnOctreeServerChanges)) {3919 if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnOctreeServerChanges)) {
@@ -4750,11 +4693,9 @@ void Application::postLambdaEvent(std::function<void()> f) { · 773 unmodified lines
4750}4693}
4751 4694
4752void Application::initPlugins() {4695void Application::initPlugins() {
4753 OculusManager::init();
4754}4696}
4755 4697
4756void Application::shutdownPlugins() {4698void Application::shutdownPlugins() {
4757 OculusManager::deinit();
4758}4699}
4759 4700
4760glm::vec3 Application::getHeadPosition() const {4701glm::vec3 Application::getHeadPosition() const {
@@ -4774,12 +4715,8 @@ QSize Application::getDeviceSize() const { · 13 unmodified lines
4774 return _glWidget->getDeviceSize();4715 return _glWidget->getDeviceSize();
4775}4716}
4776 4717
4777int Application::getTrueMouseX() const {4718ivec2 Application::getTrueMouse() const {
4778 return _glWidget->mapFromGlobal(QCursor::pos()).x();4719 return toGlm(_glWidget->mapFromGlobal(QCursor::pos()));
4779}
4780
4781int Application::getTrueMouseY() const {
4782 return _glWidget->mapFromGlobal(QCursor::pos()).y();
4783}4720}
4784 4721
4785bool Application::isThrottleRendering() const {4722bool Application::isThrottleRendering() const {
@@ -4809,3 +4746,25 @@ qreal Application::getDevicePixelRatio() { · 23 unmodified lines
4809 return _window ? _window->windowHandle()->devicePixelRatio() : 1.0;4746 return _window ? _window->windowHandle()->devicePixelRatio() : 1.0;
4810}4747}
4811 4748
4749mat4 Application::getEyeProjection(int eye) const {
4750 if (isHMDMode()) {
4751 return OculusManager::getEyeProjection(eye);
4752 }
4753
4754 return _viewFrustum.getProjection();
4755}
4756
4757mat4 Application::getEyePose(int eye) const {
4758 if (isHMDMode()) {
4759 return OculusManager::getEyePose(eye);
4760 }
4761
4762 return mat4();
4763}
4764
4765mat4 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
62#include "ui/ModelsBrowser.h"62#include "ui/ModelsBrowser.h"
63#include "ui/NodeBounds.h"63#include "ui/NodeBounds.h"
64#include "ui/OctreeStatsDialog.h"64#include "ui/OctreeStatsDialog.h"
65#include "ui/RearMirrorTools.h"
66#include "ui/SnapshotShareDialog.h"65#include "ui/SnapshotShareDialog.h"
67#include "ui/LodToolsDialog.h"66#include "ui/LodToolsDialog.h"
68#include "ui/LogDialog.h"67#include "ui/LogDialog.h"
69#include "ui/overlays/Overlays.h"68#include "ui/overlays/Overlays.h"
70#include "ui/ApplicationOverlay.h"69#include "ui/ApplicationOverlay.h"
70#include "ui/ApplicationCompositor.h"
71#include "ui/RunningScriptsWidget.h"71#include "ui/RunningScriptsWidget.h"
72#include "ui/ToolWindow.h"72#include "ui/ToolWindow.h"
73#include "ui/UserInputMapper.h"73#include "ui/UserInputMapper.h"
@@ -221,15 +221,21 @@ public: · 147 unmodified lines
221 const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; }221 const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; }
222 const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; }222 const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; }
223 bool mouseOnScreen() const;223 bool mouseOnScreen() const;
224 int getMouseX() const;224
225 int getMouseY() const;225 ivec2 getMouse() const;
226 glm::ivec2 getTrueMousePosition() const;226 ivec2 getTrueMouse() const;
227 int getTrueMouseX() const;227 ivec2 getMouseDragStarted() const;
228 int getTrueMouseY() const;228 ivec2 getTrueMouseDragStarted() const;
229 int getMouseDragStartedX() const;229
230 int getMouseDragStartedY() const;230 // TODO get rid of these and use glm types directly
231 int getTrueMouseDragStartedX() const { return _mouseDragStartedX; }231 int getMouseX() const { return getMouse().x; }
232 int getTrueMouseDragStartedY() const { return _mouseDragStartedY; }232 int getMouseY() const { return getMouse().y; }
233 int getTrueMouseX() const { return getTrueMouse().x; }
234 int getTrueMouseY() const { return getTrueMouse().y; }
235 int getMouseDragStartedX() const { return getMouseDragStarted().x; }
236 int getMouseDragStartedY() const { return getMouseDragStarted().y; }
237 int getTrueMouseDragStartedX() const { return getTrueMouseDragStarted().x; }
238 int getTrueMouseDragStartedY() const { return getTrueMouseDragStarted().y; }
233 bool getLastMouseMoveWasSimulated() const { return _lastMouseMoveWasSimulated; }239 bool getLastMouseMoveWasSimulated() const { return _lastMouseMoveWasSimulated; }
234 240
235 FaceTracker* getActiveFaceTracker();241 FaceTracker* getActiveFaceTracker();
@@ -238,6 +244,8 @@ public: · 2 unmodified lines
238 QSystemTrayIcon* getTrayIcon() { return _trayIcon; }244 QSystemTrayIcon* getTrayIcon() { return _trayIcon; }
239 ApplicationOverlay& getApplicationOverlay() { return _applicationOverlay; }245 ApplicationOverlay& getApplicationOverlay() { return _applicationOverlay; }
240 const ApplicationOverlay& getApplicationOverlay() const { return _applicationOverlay; }246 const ApplicationOverlay& getApplicationOverlay() const { return _applicationOverlay; }
247 ApplicationCompositor& getApplicationCompositor() { return _compositor; }
248 const ApplicationCompositor& getApplicationCompositor() const { return _compositor; }
241 Overlays& getOverlays() { return _overlays; }249 Overlays& getOverlays() { return _overlays; }
242 250
243 float getFps() const { return _fps; }251 float getFps() const { return _fps; }
@@ -330,6 +338,9 @@ public: · 86 unmodified lines
330 bool isHMDMode() const;338 bool isHMDMode() const;
331 glm::quat getHeadOrientation() const;339 glm::quat getHeadOrientation() const;
332 glm::vec3 getHeadPosition() const;340 glm::vec3 getHeadPosition() const;
341 glm::mat4 getHeadPose() const;
342 glm::mat4 getEyePose(int eye) const;
343 glm::mat4 getEyeProjection(int eye) const;
333 344
334 QRect getDesirableApplicationGeometry();345 QRect getDesirableApplicationGeometry();
335 RunningScriptsWidget* getRunningScriptsWidget() { return _runningScriptsWidget; }346 RunningScriptsWidget* getRunningScriptsWidget() { return _runningScriptsWidget; }
@@ -451,6 +462,8 @@ private slots: · 115 unmodified lines
451 void setFullscreen(bool fullscreen);462 void setFullscreen(bool fullscreen);
452 void setEnable3DTVMode(bool enable3DTVMode);463 void setEnable3DTVMode(bool enable3DTVMode);
453 void setEnableVRMode(bool enableVRMode);464 void setEnableVRMode(bool enableVRMode);
465
466 void rotationModeChanged();
454 467
455 glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint);468 glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint);
456 469
@@ -548,21 +561,17 @@ private: · 91 unmodified lines
548 561
549 OctreeQuery _octreeQuery; // NodeData derived class for querying octee cells from octree servers562 OctreeQuery _octreeQuery; // NodeData derived class for querying octee cells from octree servers
550 563
551 KeyboardMouseDevice _keyboardMouseDevice; // Default input device, the good old keyboard mouse and maybe touchpad564 KeyboardMouseDevice _keyboardMouseDevice; // Default input device, the good old keyboard mouse and maybe touchpad
552 565 UserInputMapper _userInputMapper; // User input mapper allowing to mapp different real devices to the action channels that the application has to offer
553 UserInputMapper _userInputMapper; // User input mapper allowing to mapp different real devices to the action channels that the application has to offer566 MyAvatar* _myAvatar; // TODO: move this and relevant code to AvatarManager (or MyAvatar as the case may be)
554 567 Camera _myCamera; // My view onto the world
555 MyAvatar* _myAvatar; // TODO: move this and relevant code to AvatarManager (or MyAvatar as the case may be)
556
557 Camera _myCamera; // My view onto the world
558 Camera _mirrorCamera; // Cammera for mirror view568 Camera _mirrorCamera; // Cammera for mirror view
559 QRect _mirrorViewRect;569 QRect _mirrorViewRect;
560 RearMirrorTools* _rearMirrorTools;
561 570
562 Setting::Handle<bool> _firstRun;571 Setting::Handle<bool> _firstRun;
563 Setting::Handle<QString> _previousScriptLocation;572 Setting::Handle<QString> _previousScriptLocation;
564 Setting::Handle<QString> _scriptsLocationHandle;573 Setting::Handle<QString> _scriptsLocationHandle;
565 Setting::Handle<float> _fieldOfView;574 Setting::Handle<float> _fieldOfView;
566 575
567 Transform _viewTransform;576 Transform _viewTransform;
568 glm::mat4 _untranslatedViewMatrix;577 glm::mat4 _untranslatedViewMatrix;
@@ -580,18 +589,17 @@ private: · 11 unmodified lines
580 Environment _environment;589 Environment _environment;
581 590
582 bool _cursorVisible;591 bool _cursorVisible;
583 int _mouseDragStartedX;592 ivec2 _mouseDragStarted;
584 int _mouseDragStartedY;593
585 quint64 _lastMouseMove;594 quint64 _lastMouseMove;
586 bool _lastMouseMoveWasSimulated;595 bool _lastMouseMoveWasSimulated;
587 596
588 glm::vec3 _mouseRayOrigin;597 glm::vec3 _mouseRayOrigin;
589 glm::vec3 _mouseRayDirection;598 glm::vec3 _mouseRayDirection;
590 599
591 float _touchAvgX;600 vec2 _touchAvg;
592 float _touchAvgY;601 vec2 _touchDragStartedAvg;
593 float _touchDragStartedAvgX;602
594 float _touchDragStartedAvgY;
595 bool _isTouchPressed; // true if multitouch has been pressed (clear when finished)603 bool _isTouchPressed; // true if multitouch has been pressed (clear when finished)
596 604
597 bool _mousePressed; // true if mouse has been pressed (clear when finished)605 bool _mousePressed; // true if mouse has been pressed (clear when finished)
@@ -669,6 +677,7 @@ private: · 71 unmodified lines
669 677
670 Overlays _overlays;678 Overlays _overlays;
671 ApplicationOverlay _applicationOverlay;679 ApplicationOverlay _applicationOverlay;
680 ApplicationCompositor _compositor;
672};681};
673 682
674#endif // hifi_Application_h683#endif // hifi_Application_h
interface/src/Camera.cpp+0−16
@@ -49,8 +49,6 @@ Camera::Camera() : · 48 unmodified lines
49 _mode(CAMERA_MODE_THIRD_PERSON),49 _mode(CAMERA_MODE_THIRD_PERSON),
50 _position(0.0f, 0.0f, 0.0f),50 _position(0.0f, 0.0f, 0.0f),
51 _projection(glm::perspective(glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES), 16.0f/9.0f, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP)),51 _projection(glm::perspective(glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES), 16.0f/9.0f, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP)),
52 _hmdPosition(),
53 _hmdRotation(),
54 _isKeepLookingAt(false),52 _isKeepLookingAt(false),
55 _lookingAt(0.0f, 0.0f, 0.0f)53 _lookingAt(0.0f, 0.0f, 0.0f)
56{54{
@@ -74,20 +72,6 @@ void Camera::setRotation(const glm::quat& rotation) { · 17 unmodified lines
74 }72 }
75}73}
76 74
77void Camera::setHmdPosition(const glm::vec3& hmdPosition) {
78 _hmdPosition = hmdPosition;
79 if (_isKeepLookingAt) {
80 lookAt(_lookingAt);
81 }
82}
83
84void Camera::setHmdRotation(const glm::quat& hmdRotation) {
85 _hmdRotation = hmdRotation;
86 if (_isKeepLookingAt) {
87 lookAt(_lookingAt);
88 }
89}
90
91void Camera::setMode(CameraMode mode) {75void Camera::setMode(CameraMode mode) {
92 _mode = mode;76 _mode = mode;
93 emit modeUpdated(modeToString(mode));77 emit modeUpdated(modeToString(mode));
interface/src/Camera.h+4−10
@@ -45,26 +45,22 @@ public: · 44 unmodified lines
45 45
46 void setRotation(const glm::quat& rotation);46 void setRotation(const glm::quat& rotation);
47 void setProjection(const glm::mat4 & projection);47 void setProjection(const glm::mat4 & projection);
48 void setHmdPosition(const glm::vec3& hmdPosition);
49 void setHmdRotation(const glm::quat& hmdRotation);
50 void setMode(CameraMode m);48 void setMode(CameraMode m);
51 49
52 glm::quat getRotation() const { return _rotation * _hmdRotation; }50 glm::quat getRotation() const { return _rotation; }
53 const glm::mat4& getProjection() const { return _projection; }51 const glm::mat4& getProjection() const { return _projection; }
54 const glm::vec3& getHmdPosition() const { return _hmdPosition; }
55 const glm::quat& getHmdRotation() const { return _hmdRotation; }
56 CameraMode getMode() const { return _mode; }52 CameraMode getMode() const { return _mode; }
57 53
58public slots:54public slots:
59 QString getModeString() const;55 QString getModeString() const;
60 void setModeString(const QString& mode);56 void setModeString(const QString& mode);
61 57
62 glm::vec3 getPosition() const { return _position + _hmdPosition; }58 glm::vec3 getPosition() const { return _position; }
63 void setPosition(const glm::vec3& position);59 void setPosition(const glm::vec3& position);
64 60
65 void setOrientation(const glm::quat& orientation) { setRotation(orientation); }
66 glm::quat getOrientation() const { return getRotation(); }61 glm::quat getOrientation() const { return getRotation(); }
67 62 void setOrientation(const glm::quat& orientation) { setRotation(orientation); }
63
68 PickRay computePickRay(float x, float y);64 PickRay computePickRay(float x, float y);
69 65
70 // These only work on independent cameras66 // These only work on independent cameras
@@ -86,8 +82,6 @@ private: · 15 unmodified lines
86 glm::vec3 _position;82 glm::vec3 _position;
87 glm::quat _rotation;83 glm::quat _rotation;
88 glm::mat4 _projection;84 glm::mat4 _projection;
89 glm::vec3 _hmdPosition;
90 glm::quat _hmdRotation;
91 bool _isKeepLookingAt;85 bool _isKeepLookingAt;
92 glm::vec3 _lookingAt;86 glm::vec3 _lookingAt;
93};87};
interface/src/GLCanvas.cpp+2−2
@@ -39,11 +39,11 @@ bool GLCanvas::isThrottleRendering() const { · 38 unmodified lines
39}39}
40 40
41int GLCanvas::getDeviceWidth() const {41int GLCanvas::getDeviceWidth() const {
42 return width() * (windowHandle() ? windowHandle()->devicePixelRatio() : 1.0f);42 return width() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f);
43}43}
44 44
45int GLCanvas::getDeviceHeight() const {45int GLCanvas::getDeviceHeight() const {
46 return height() * (windowHandle() ? windowHandle()->devicePixelRatio() : 1.0f);46 return height() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f);
47}47}
48 48
49void GLCanvas::initializeGL() {49void GLCanvas::initializeGL() {
interface/src/InterfaceActionFactory.cpp+3−3
@@ -12,7 +12,7 @@ · 11 unmodified lines
12 12
13 13
14#include <avatar/AvatarActionHold.h>14#include <avatar/AvatarActionHold.h>
15#include <ObjectActionPullToPoint.h>15#include <ObjectActionOffset.h>
16#include <ObjectActionSpring.h>16#include <ObjectActionSpring.h>
17 17
18#include "InterfaceActionFactory.h"18#include "InterfaceActionFactory.h"
@@ -27,8 +27,8 @@ EntityActionPointer InterfaceActionFactory::factory(EntitySimulation* simulation · 8 unmodified lines
27 switch (type) {27 switch (type) {
28 case ACTION_TYPE_NONE:28 case ACTION_TYPE_NONE:
29 return nullptr;29 return nullptr;
30 case ACTION_TYPE_PULL_TO_POINT:30 case ACTION_TYPE_OFFSET:
31 action = (EntityActionPointer) new ObjectActionPullToPoint(id, ownerEntity);31 action = (EntityActionPointer) new ObjectActionOffset(id, ownerEntity);
32 break;32 break;
33 case ACTION_TYPE_SPRING:33 case ACTION_TYPE_SPRING:
34 action = (EntityActionPointer) new ObjectActionSpring(id, ownerEntity);34 action = (EntityActionPointer) new ObjectActionSpring(id, ownerEntity);
interface/src/LODManager.cpp+3−3
@@ -205,11 +205,11 @@ QString LODManager::getLODFeedbackText() { · 204 unmodified lines
205 int relativeToTwentyTwenty = 20 / relativeToDefault;205 int relativeToTwentyTwenty = 20 / relativeToDefault;
206 206
207 QString result;207 QString result;
208 if (relativeToDefault > 1.01) {208 if (relativeToDefault > 1.01f) {
209 result = QString("20:%1 or %2 times further than average vision%3").arg(relativeToTwentyTwenty).arg(relativeToDefault,0,'f',2).arg(granularityFeedback);209 result = QString("20:%1 or %2 times further than average vision%3").arg(relativeToTwentyTwenty).arg(relativeToDefault,0,'f',2).arg(granularityFeedback);
210 } else if (relativeToDefault > 0.99) {210 } else if (relativeToDefault > 0.99f) {
211 result = QString("20:20 or the default distance for average vision%1").arg(granularityFeedback);211 result = QString("20:20 or the default distance for average vision%1").arg(granularityFeedback);
212 } else if (relativeToDefault > 0.01) {212 } else if (relativeToDefault > 0.01f) {
213 result = QString("20:%1 or %2 of default distance for average vision%3").arg(relativeToTwentyTwenty).arg(relativeToDefault,0,'f',3).arg(granularityFeedback);213 result = QString("20:%1 or %2 of default distance for average vision%3").arg(relativeToTwentyTwenty).arg(relativeToDefault,0,'f',3).arg(granularityFeedback);
214 } else {214 } else {
215 result = QString("%2 of default distance for average vision%3").arg(relativeToDefault,0,'f',3).arg(granularityFeedback);215 result = QString("%2 of default distance for average vision%3").arg(relativeToDefault,0,'f',3).arg(granularityFeedback);
interface/src/Menu.cpp+6−0
@@ -287,6 +287,12 @@ Menu::Menu() { · 286 unmodified lines
287 addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror,287 addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror,
288 0, //QML Qt::SHIFT | Qt::Key_H,288 0, //QML Qt::SHIFT | Qt::Key_H,
289 true);289 true);
290 addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror,
291 0, // QML Qt::Key_H,
292 false, qApp, SLOT(cameraMenuChanged()));
293
294 addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::CenterPlayerInView,
295 0, false, qApp, SLOT(rotationModeChanged()));
290 296
291 addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools,297 addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools,
292#ifdef Q_OS_MAC298#ifdef Q_OS_MAC
interface/src/Menu.h+1−0
@@ -201,6 +201,7 @@ namespace MenuOption { · 200 unmodified lines
201 const QString FrameTimer = "Show Timer";201 const QString FrameTimer = "Show Timer";
202 const QString Fullscreen = "Fullscreen";202 const QString Fullscreen = "Fullscreen";
203 const QString FullscreenMirror = "Fullscreen Mirror";203 const QString FullscreenMirror = "Fullscreen Mirror";
204 const QString CenterPlayerInView = "Center Player In View";
204 const QString GlowWhenSpeaking = "Glow When Speaking";205 const QString GlowWhenSpeaking = "Glow When Speaking";
205 const QString NamesAboveHeads = "Names Above Heads";206 const QString NamesAboveHeads = "Names Above Heads";
206 const QString HMDTools = "HMD Tools";207 const QString HMDTools = "HMD Tools";
interface/src/ModelPropertiesDialog.cpp+26−26
@@ -33,19 +33,19 @@ _basePath(basePath), · 32 unmodified lines
33_geometry(geometry)33_geometry(geometry)
34{34{
35 setWindowTitle("Set Model Properties");35 setWindowTitle("Set Model Properties");
36 36
37 QFormLayout* form = new QFormLayout();37 QFormLayout* form = new QFormLayout();
38 setLayout(form);38 setLayout(form);
39 39
40 form->addRow("Name:", _name = new QLineEdit());40 form->addRow("Name:", _name = new QLineEdit());
41 41
42 form->addRow("Texture Directory:", _textureDirectory = new QPushButton());42 form->addRow("Texture Directory:", _textureDirectory = new QPushButton());
43 connect(_textureDirectory, SIGNAL(clicked(bool)), SLOT(chooseTextureDirectory()));43 connect(_textureDirectory, SIGNAL(clicked(bool)), SLOT(chooseTextureDirectory()));
44 44
45 form->addRow("Scale:", _scale = new QDoubleSpinBox());45 form->addRow("Scale:", _scale = new QDoubleSpinBox());
46 _scale->setMaximum(FLT_MAX);46 _scale->setMaximum(FLT_MAX);
47 _scale->setSingleStep(0.01);47 _scale->setSingleStep(0.01);
48 48
49 if (_modelType != FSTReader::ENTITY_MODEL) {49 if (_modelType != FSTReader::ENTITY_MODEL) {
50 if (_modelType == FSTReader::ATTACHMENT_MODEL) {50 if (_modelType == FSTReader::ATTACHMENT_MODEL) {
51 QHBoxLayout* translation = new QHBoxLayout();51 QHBoxLayout* translation = new QHBoxLayout();
@@ -57,7 +57,7 @@ _geometry(geometry) · 5 unmodified lines
57 form->addRow("Pivot Joint:", _pivotJoint = createJointBox());57 form->addRow("Pivot Joint:", _pivotJoint = createJointBox());
58 connect(_pivotAboutCenter, SIGNAL(toggled(bool)), SLOT(updatePivotJoint()));58 connect(_pivotAboutCenter, SIGNAL(toggled(bool)), SLOT(updatePivotJoint()));
59 _pivotAboutCenter->setChecked(true);59 _pivotAboutCenter->setChecked(true);
60 60
61 } else {61 } else {
62 form->addRow("Left Eye Joint:", _leftEyeJoint = createJointBox());62 form->addRow("Left Eye Joint:", _leftEyeJoint = createJointBox());
63 form->addRow("Right Eye Joint:", _rightEyeJoint = createJointBox());63 form->addRow("Right Eye Joint:", _rightEyeJoint = createJointBox());
@@ -69,22 +69,22 @@ _geometry(geometry) · 5 unmodified lines
69 form->addRow("Head Joint:", _headJoint = createJointBox());69 form->addRow("Head Joint:", _headJoint = createJointBox());
70 form->addRow("Left Hand Joint:", _leftHandJoint = createJointBox());70 form->addRow("Left Hand Joint:", _leftHandJoint = createJointBox());
71 form->addRow("Right Hand Joint:", _rightHandJoint = createJointBox());71 form->addRow("Right Hand Joint:", _rightHandJoint = createJointBox());
72 72
73 form->addRow("Free Joints:", _freeJoints = new QVBoxLayout());73 form->addRow("Free Joints:", _freeJoints = new QVBoxLayout());
74 QPushButton* newFreeJoint = new QPushButton("New Free Joint");74 QPushButton* newFreeJoint = new QPushButton("New Free Joint");
75 _freeJoints->addWidget(newFreeJoint);75 _freeJoints->addWidget(newFreeJoint);
76 connect(newFreeJoint, SIGNAL(clicked(bool)), SLOT(createNewFreeJoint()));76 connect(newFreeJoint, SIGNAL(clicked(bool)), SLOT(createNewFreeJoint()));
77 }77 }
78 }78 }
79 79
80 QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok |80 QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok |
81 QDialogButtonBox::Cancel | QDialogButtonBox::Reset);81 QDialogButtonBox::Cancel | QDialogButtonBox::Reset);
82 connect(buttons, SIGNAL(accepted()), SLOT(accept()));82 connect(buttons, SIGNAL(accepted()), SLOT(accept()));
83 connect(buttons, SIGNAL(rejected()), SLOT(reject()));83 connect(buttons, SIGNAL(rejected()), SLOT(reject()));
84 connect(buttons->button(QDialogButtonBox::Reset), SIGNAL(clicked(bool)), SLOT(reset()));84 connect(buttons->button(QDialogButtonBox::Reset), SIGNAL(clicked(bool)), SLOT(reset()));
85 85
86 form->addRow(buttons);86 form->addRow(buttons);
87 87
88 // reset to initialize the fields88 // reset to initialize the fields
89 reset();89 reset();
90}90}
@@ -100,42 +100,42 @@ QVariantHash ModelPropertiesDialog::getMapping() const { · 9 unmodified lines
100 mapping.insert(NAME_FIELD, _name->text());100 mapping.insert(NAME_FIELD, _name->text());
101 mapping.insert(TEXDIR_FIELD, _textureDirectory->text());101 mapping.insert(TEXDIR_FIELD, _textureDirectory->text());
102 mapping.insert(SCALE_FIELD, QString::number(_scale->value()));102 mapping.insert(SCALE_FIELD, QString::number(_scale->value()));
103 103
104 // update the joint indices104 // update the joint indices
105 QVariantHash jointIndices;105 QVariantHash jointIndices;
106 for (int i = 0; i < _geometry.joints.size(); i++) {106 for (int i = 0; i < _geometry.joints.size(); i++) {
107 jointIndices.insert(_geometry.joints.at(i).name, QString::number(i));107 jointIndices.insert(_geometry.joints.at(i).name, QString::number(i));
108 }108 }
109 mapping.insert(JOINT_INDEX_FIELD, jointIndices);109 mapping.insert(JOINT_INDEX_FIELD, jointIndices);
110 110
111 if (_modelType != FSTReader::ENTITY_MODEL) {111 if (_modelType != FSTReader::ENTITY_MODEL) {
112 QVariantHash joints = mapping.value(JOINT_FIELD).toHash();112 QVariantHash joints = mapping.value(JOINT_FIELD).toHash();
113 if (_modelType == FSTReader::ATTACHMENT_MODEL) {113 if (_modelType == FSTReader::ATTACHMENT_MODEL) {
114 glm::vec3 pivot;114 glm::vec3 pivot;
115 if (_pivotAboutCenter->isChecked()) {115 if (_pivotAboutCenter->isChecked()) {
116 pivot = (_geometry.meshExtents.minimum + _geometry.meshExtents.maximum) * 0.5f;116 pivot = (_geometry.meshExtents.minimum + _geometry.meshExtents.maximum) * 0.5f;
117 117
118 } else if (_pivotJoint->currentIndex() != 0) {118 } else if (_pivotJoint->currentIndex() != 0) {
119 pivot = extractTranslation(_geometry.joints.at(_pivotJoint->currentIndex() - 1).transform);119 pivot = extractTranslation(_geometry.joints.at(_pivotJoint->currentIndex() - 1).transform);
120 }120 }
121 mapping.insert(TRANSLATION_X_FIELD, -pivot.x * _scale->value() + _translationX->value());121 mapping.insert(TRANSLATION_X_FIELD, -pivot.x * (float)_scale->value() + (float)_translationX->value());
122 mapping.insert(TRANSLATION_Y_FIELD, -pivot.y * _scale->value() + _translationY->value());122 mapping.insert(TRANSLATION_Y_FIELD, -pivot.y * (float)_scale->value() + (float)_translationY->value());
123 mapping.insert(TRANSLATION_Z_FIELD, -pivot.z * _scale->value() + _translationZ->value());123 mapping.insert(TRANSLATION_Z_FIELD, -pivot.z * (float)_scale->value() + (float)_translationZ->value());
124 124
125 } else {125 } else {
126 insertJointMapping(joints, "jointEyeLeft", _leftEyeJoint->currentText());126 insertJointMapping(joints, "jointEyeLeft", _leftEyeJoint->currentText());
127 insertJointMapping(joints, "jointEyeRight", _rightEyeJoint->currentText());127 insertJointMapping(joints, "jointEyeRight", _rightEyeJoint->currentText());
128 insertJointMapping(joints, "jointNeck", _neckJoint->currentText());128 insertJointMapping(joints, "jointNeck", _neckJoint->currentText());
129 }129 }
130 130
131 131
132 if (_modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL) {132 if (_modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL) {
133 insertJointMapping(joints, "jointRoot", _rootJoint->currentText());133 insertJointMapping(joints, "jointRoot", _rootJoint->currentText());
134 insertJointMapping(joints, "jointLean", _leanJoint->currentText());134 insertJointMapping(joints, "jointLean", _leanJoint->currentText());
135 insertJointMapping(joints, "jointHead", _headJoint->currentText());135 insertJointMapping(joints, "jointHead", _headJoint->currentText());
136 insertJointMapping(joints, "jointLeftHand", _leftHandJoint->currentText());136 insertJointMapping(joints, "jointLeftHand", _leftHandJoint->currentText());
137 insertJointMapping(joints, "jointRightHand", _rightHandJoint->currentText());137 insertJointMapping(joints, "jointRightHand", _rightHandJoint->currentText());
138 138
139 mapping.remove(FREE_JOINT_FIELD);139 mapping.remove(FREE_JOINT_FIELD);
140 for (int i = 0; i < _freeJoints->count() - 1; i++) {140 for (int i = 0; i < _freeJoints->count() - 1; i++) {
141 QComboBox* box = static_cast<QComboBox*>(_freeJoints->itemAt(i)->widget()->layout()->itemAt(0)->widget());141 QComboBox* box = static_cast<QComboBox*>(_freeJoints->itemAt(i)->widget()->layout()->itemAt(0)->widget());
@@ -144,7 +144,7 @@ QVariantHash ModelPropertiesDialog::getMapping() const { · 2 unmodified lines
144 }144 }
145 mapping.insert(JOINT_FIELD, joints);145 mapping.insert(JOINT_FIELD, joints);
146 }146 }
147 147
148 return mapping;148 return mapping;
149}149}
150 150
@@ -156,9 +156,9 @@ void ModelPropertiesDialog::reset() { · 5 unmodified lines
156 _name->setText(_originalMapping.value(NAME_FIELD).toString());156 _name->setText(_originalMapping.value(NAME_FIELD).toString());
157 _textureDirectory->setText(_originalMapping.value(TEXDIR_FIELD).toString());157 _textureDirectory->setText(_originalMapping.value(TEXDIR_FIELD).toString());
158 _scale->setValue(_originalMapping.value(SCALE_FIELD).toDouble());158 _scale->setValue(_originalMapping.value(SCALE_FIELD).toDouble());
159 159
160 QVariantHash jointHash = _originalMapping.value(JOINT_FIELD).toHash();160 QVariantHash jointHash = _originalMapping.value(JOINT_FIELD).toHash();
161 161
162 if (_modelType != FSTReader::ENTITY_MODEL) {162 if (_modelType != FSTReader::ENTITY_MODEL) {
163 if (_modelType == FSTReader::ATTACHMENT_MODEL) {163 if (_modelType == FSTReader::ATTACHMENT_MODEL) {
164 _translationX->setValue(_originalMapping.value(TRANSLATION_X_FIELD).toDouble());164 _translationX->setValue(_originalMapping.value(TRANSLATION_X_FIELD).toDouble());
@@ -166,20 +166,20 @@ void ModelPropertiesDialog::reset() { · 1 unmodified line
166 _translationZ->setValue(_originalMapping.value(TRANSLATION_Z_FIELD).toDouble());166 _translationZ->setValue(_originalMapping.value(TRANSLATION_Z_FIELD).toDouble());
167 _pivotAboutCenter->setChecked(true);167 _pivotAboutCenter->setChecked(true);
168 _pivotJoint->setCurrentIndex(0);168 _pivotJoint->setCurrentIndex(0);
169 169
170 } else {170 } else {
171 setJointText(_leftEyeJoint, jointHash.value("jointEyeLeft").toString());171 setJointText(_leftEyeJoint, jointHash.value("jointEyeLeft").toString());
172 setJointText(_rightEyeJoint, jointHash.value("jointEyeRight").toString());172 setJointText(_rightEyeJoint, jointHash.value("jointEyeRight").toString());
173 setJointText(_neckJoint, jointHash.value("jointNeck").toString());173 setJointText(_neckJoint, jointHash.value("jointNeck").toString());
174 }174 }
175 175
176 if (_modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL) {176 if (_modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL) {
177 setJointText(_rootJoint, jointHash.value("jointRoot").toString());177 setJointText(_rootJoint, jointHash.value("jointRoot").toString());
178 setJointText(_leanJoint, jointHash.value("jointLean").toString());178 setJointText(_leanJoint, jointHash.value("jointLean").toString());
179 setJointText(_headJoint, jointHash.value("jointHead").toString());179 setJointText(_headJoint, jointHash.value("jointHead").toString());
180 setJointText(_leftHandJoint, jointHash.value("jointLeftHand").toString());180 setJointText(_leftHandJoint, jointHash.value("jointLeftHand").toString());
181 setJointText(_rightHandJoint, jointHash.value("jointRightHand").toString());181 setJointText(_rightHandJoint, jointHash.value("jointRightHand").toString());
182 182
183 while (_freeJoints->count() > 1) {183 while (_freeJoints->count() > 1) {
184 delete _freeJoints->itemAt(0)->widget();184 delete _freeJoints->itemAt(0)->widget();
185 }185 }
interface/src/Stars.cpp+8−10
@@ -16,13 +16,13 @@ · 15 unmodified lines
16#include "InterfaceConfig.h"16#include "InterfaceConfig.h"
17#include "starfield/Controller.h"17#include "starfield/Controller.h"
18 18
19Stars::Stars() : 19Stars::Stars() :
20 _controller(0l), _starsLoaded(false) {20 _controller(0l), _starsLoaded(false) {
21 _controller = new starfield::Controller;21 _controller = new starfield::Controller;
22}22}
23 23
24Stars::~Stars() { 24Stars::~Stars() {
25 delete _controller; 25 delete _controller;
26}26}
27 27
28bool Stars::generate(unsigned numStars, unsigned seed) {28bool Stars::generate(unsigned numStars, unsigned seed) {
@@ -30,22 +30,20 @@ bool Stars::generate(unsigned numStars, unsigned seed) { · 1 unmodified line
30 return _starsLoaded;30 return _starsLoaded;
31}31}
32 32
33bool Stars::setResolution(unsigned k) { 33bool Stars::setResolution(unsigned k) {
34 return _controller->setResolution(k); 34 return _controller->setResolution(k);
35}35}
36 36
37void Stars::render(float fovY, float aspect, float nearZ, float alpha) {37void Stars::render(float fovY, float aspect, float nearZ, float alpha) {
38 // determine length of screen diagonal from quadrant height and aspect ratio38 // determine length of screen diagonal from quadrant height and aspect ratio
39 float quadrantHeight = nearZ * tan(RADIANS_PER_DEGREE * fovY * 0.5f);39 float quadrantHeight = nearZ * tanf(RADIANS_PER_DEGREE * fovY * 0.5f);
40 float halfDiagonal = sqrt(quadrantHeight * quadrantHeight * (1.0f + aspect * aspect));40 float halfDiagonal = sqrt(quadrantHeight * quadrantHeight * (1.0f + aspect * aspect));
41 41
42 // determine fov angle in respect to the diagonal42 // determine fov angle in respect to the diagonal
43 float fovDiagonal = atan(halfDiagonal / nearZ) * 2.0f;43 float fovDiagonal = atanf(halfDiagonal / nearZ) * 2.0f;
44 44
45 // pull the modelview matrix off the GL stack45 // pull the modelview matrix off the GL stack
46 glm::mat4 view; glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view)); 46 glm::mat4 view; glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view));
47 47
48 _controller->render(fovDiagonal, aspect, glm::affineInverse(view), alpha);48 _controller->render(fovDiagonal, aspect, glm::affineInverse(view), alpha);
49}49}
50
51
interface/src/UIUtil.cpp+1−1
@@ -70,6 +70,6 @@ void UIUtil::internalScaleWidgetFontSizes(QWidget* widget, float scale) { · 69 unmodified lines
70 }70 }
71 71
72 QFont font = widget->font();72 QFont font = widget->font();
73 font.setPointSizeF(font.pointSizeF() * scale);73 font.setPointSizeF(font.pointSizeF() * (double)scale);
74 widget->setFont(font);74 widget->setFont(font);
75}75}
interface/src/Util.cpp+25−22
@@ -41,7 +41,7 @@ void renderWorldBox(gpu::Batch& batch) { · 40 unmodified lines
41 static const glm::vec3 green(0.0f, 1.0f, 0.0f);41 static const glm::vec3 green(0.0f, 1.0f, 0.0f);
42 static const glm::vec3 blue(0.0f, 0.0f, 1.0f);42 static const glm::vec3 blue(0.0f, 0.0f, 1.0f);
43 static const glm::vec3 grey(0.5f, 0.5f, 0.5f);43 static const glm::vec3 grey(0.5f, 0.5f, 0.5f);
44 44
45 auto transform = Transform{};45 auto transform = Transform{};
46 batch.setModelTransform(transform);46 batch.setModelTransform(transform);
47 geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(TREE_SCALE, 0.0f, 0.0f), red);47 geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(TREE_SCALE, 0.0f, 0.0f), red);
@@ -49,13 +49,13 @@ void renderWorldBox(gpu::Batch& batch) { · 1 unmodified line
49 geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, TREE_SCALE), blue);49 geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, TREE_SCALE), blue);
50 geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, TREE_SCALE), glm::vec3(TREE_SCALE, 0.0f, TREE_SCALE), grey);50 geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, TREE_SCALE), glm::vec3(TREE_SCALE, 0.0f, TREE_SCALE), grey);
51 geometryCache->renderLine(batch, glm::vec3(TREE_SCALE, 0.0f, TREE_SCALE), glm::vec3(TREE_SCALE, 0.0f, 0.0f), grey);51 geometryCache->renderLine(batch, glm::vec3(TREE_SCALE, 0.0f, TREE_SCALE), glm::vec3(TREE_SCALE, 0.0f, 0.0f), grey);
52 52
53 // Draw meter markers along the 3 axis to help with measuring things53 // Draw meter markers along the 3 axis to help with measuring things
54 const float MARKER_DISTANCE = 1.0f;54 const float MARKER_DISTANCE = 1.0f;
55 const float MARKER_RADIUS = 0.05f;55 const float MARKER_RADIUS = 0.05f;
56 56
57 geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, red);57 geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, red);
58 58
59 transform.setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, 0.0f));59 transform.setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, 0.0f));
60 batch.setModelTransform(transform);60 batch.setModelTransform(transform);
61 geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, red);61 geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, red);
@@ -79,10 +79,10 @@ const glm::vec3 randVector() { · 17 unmodified lines
79}79}
80 80
81static TextRenderer* textRenderer(int mono) {81static TextRenderer* textRenderer(int mono) {
82 static TextRenderer* monoRenderer = TextRenderer::getInstance(MONO_FONT_FAMILY); 82 static TextRenderer* monoRenderer = TextRenderer::getInstance(MONO_FONT_FAMILY);
83 static TextRenderer* proportionalRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY,83 static TextRenderer* proportionalRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY,
84 -1, -1, false, TextRenderer::SHADOW_EFFECT);84 -1, -1, false, TextRenderer::SHADOW_EFFECT);
85 static TextRenderer* inconsolataRenderer = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, -1, INCONSOLATA_FONT_WEIGHT, 85 static TextRenderer* inconsolataRenderer = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, -1, INCONSOLATA_FONT_WEIGHT,
86 false);86 false);
87 switch (mono) {87 switch (mono) {
88 case 1:88 case 1:
@@ -133,46 +133,46 @@ void runTimingTests() { · 44 unmodified lines
133 QElapsedTimer startTime;133 QElapsedTimer startTime;
134 startTime.start();134 startTime.start();
135 float elapsedUsecs;135 float elapsedUsecs;
136 136
137 float NSEC_TO_USEC = 1.0f / 1000.0f;137 float NSEC_TO_USEC = 1.0f / 1000.0f;
138 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;138 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
139 qCDebug(interfaceapp, "QElapsedTimer::nsecElapsed() usecs: %f", elapsedUsecs);139 qCDebug(interfaceapp, "QElapsedTimer::nsecElapsed() usecs: %f", (double)elapsedUsecs);
140 140
141 // Test sleep functions for accuracy141 // Test sleep functions for accuracy
142 startTime.start();142 startTime.start();
143 QThread::msleep(1);143 QThread::msleep(1);
144 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;144 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
145 qCDebug(interfaceapp, "QThread::msleep(1) ms: %f", elapsedUsecs / 1000.0f);145 qCDebug(interfaceapp, "QThread::msleep(1) ms: %f", (double)(elapsedUsecs / 1000.0f));
146 146
147 startTime.start();147 startTime.start();
148 QThread::sleep(1);148 QThread::sleep(1);
149 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;149 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
150 qCDebug(interfaceapp, "QThread::sleep(1) ms: %f", elapsedUsecs / 1000.0f);150 qCDebug(interfaceapp, "QThread::sleep(1) ms: %f", (double)(elapsedUsecs / 1000.0f));
151 151
152 startTime.start();152 startTime.start();
153 usleep(1);153 usleep(1);
154 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;154 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
155 qCDebug(interfaceapp, "usleep(1) ms: %f", elapsedUsecs / 1000.0f);155 qCDebug(interfaceapp, "usleep(1) ms: %f", (double)(elapsedUsecs / 1000.0f));
156 156
157 startTime.start();157 startTime.start();
158 usleep(10);158 usleep(10);
159 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;159 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
160 qCDebug(interfaceapp, "usleep(10) ms: %f", elapsedUsecs / 1000.0f);160 qCDebug(interfaceapp, "usleep(10) ms: %f", (double)(elapsedUsecs / 1000.0f));
161 161
162 startTime.start();162 startTime.start();
163 usleep(100);163 usleep(100);
164 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;164 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
165 qCDebug(interfaceapp, "usleep(100) ms: %f", elapsedUsecs / 1000.0f);165 qCDebug(interfaceapp, "usleep(100) ms: %f", (double)(elapsedUsecs / 1000.0f));
166 166
167 startTime.start();167 startTime.start();
168 usleep(1000);168 usleep(1000);
169 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;169 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
170 qCDebug(interfaceapp, "usleep(1000) ms: %f", elapsedUsecs / 1000.0f);170 qCDebug(interfaceapp, "usleep(1000) ms: %f", (double)(elapsedUsecs / 1000.0f));
171 171
172 startTime.start();172 startTime.start();
173 usleep(15000);173 usleep(15000);
174 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;174 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
175 qCDebug(interfaceapp, "usleep(15000) ms: %f", elapsedUsecs / 1000.0f);175 qCDebug(interfaceapp, "usleep(15000) ms: %f", (double)(elapsedUsecs / 1000.0f));
176 176
177 // Random number generation177 // Random number generation
178 startTime.start();178 startTime.start();
@@ -180,7 +180,8 @@ void runTimingTests() { · 1 unmodified line
180 iResults[i] = rand();180 iResults[i] = rand();
181 }181 }
182 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;182 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
183 qCDebug(interfaceapp, "rand() stored in array usecs: %f, first result:%d", elapsedUsecs / (float) numTests, iResults[0]);183 qCDebug(interfaceapp, "rand() stored in array usecs: %f, first result:%d",
184 (double)(elapsedUsecs / numTests), iResults[0]);
184 185
185 // Random number generation using randFloat()186 // Random number generation using randFloat()
186 startTime.start();187 startTime.start();
@@ -188,7 +189,8 @@ void runTimingTests() { · 1 unmodified line
188 fResults[i] = randFloat();189 fResults[i] = randFloat();
189 }190 }
190 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;191 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
191 qCDebug(interfaceapp, "randFloat() stored in array usecs: %f, first result: %f", elapsedUsecs / (float) numTests, fResults[0]);192 qCDebug(interfaceapp, "randFloat() stored in array usecs: %f, first result: %f",
193 (double)(elapsedUsecs / numTests), (double)(fResults[0]));
192 194
193 free(iResults);195 free(iResults);
194 free(fResults);196 free(fResults);
@@ -200,7 +202,7 @@ void runTimingTests() { · 5 unmodified lines
200 fTest = powf(fTest, 0.5f);202 fTest = powf(fTest, 0.5f);
201 }203 }
202 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;204 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
203 qCDebug(interfaceapp, "powf(f, 0.5) usecs: %f", elapsedUsecs / (float) numTests);205 qCDebug(interfaceapp, "powf(f, 0.5) usecs: %f", (double)(elapsedUsecs / (float) numTests));
204 206
205 // Vector Math207 // Vector Math
206 float distance;208 float distance;
@@ -213,19 +215,20 @@ void runTimingTests() { · 6 unmodified lines
213 }215 }
214 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;216 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
215 qCDebug(interfaceapp, "vector math usecs: %f [%f usecs total for %d tests], last result:%f",217 qCDebug(interfaceapp, "vector math usecs: %f [%f usecs total for %d tests], last result:%f",
216 elapsedUsecs / (float) numTests, elapsedUsecs, numTests, distance);218 (double)(elapsedUsecs / (float) numTests), (double)elapsedUsecs, numTests, (double)distance);
217 219
218 // Vec3 test220 // Vec3 test
219 glm::vec3 vecA(randVector()), vecB(randVector());221 glm::vec3 vecA(randVector()), vecB(randVector());
220 float result;222 float result;
221 223
222 startTime.start();224 startTime.start();
223 for (int i = 0; i < numTests; i++) {225 for (int i = 0; i < numTests; i++) {
224 glm::vec3 temp = vecA-vecB;226 glm::vec3 temp = vecA-vecB;
225 result = glm::dot(temp,temp);227 result = glm::dot(temp,temp);
226 }228 }
227 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;229 elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC;
228 qCDebug(interfaceapp, "vec3 assign and dot() usecs: %f, last result:%f", elapsedUsecs / (float) numTests, result);230 qCDebug(interfaceapp, "vec3 assign and dot() usecs: %f, last result:%f",
231 (double)(elapsedUsecs / numTests), (double)result);
229}232}
230 233
231bool rayIntersectsSphere(const glm::vec3& rayStarting, const glm::vec3& rayNormalizedDirection,234bool 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
41 if (!_isEnabled) {41 if (!_isEnabled) {
42 return;42 return;
43 }43 }
44 44
45 const int linesWhenCentered = _shouldShowInjectedStreams ? 34 : 27;45 const int linesWhenCentered = _shouldShowInjectedStreams ? 34 : 27;
46 const int CENTERED_BACKGROUND_HEIGHT = STATS_HEIGHT_PER_LINE * linesWhenCentered;46 const int CENTERED_BACKGROUND_HEIGHT = STATS_HEIGHT_PER_LINE * linesWhenCentered;
47 47
48 int lines = _shouldShowInjectedStreams ? _stats->getMixerInjectedStreamStatsMap().size() * 7 + 27 : 27;48 int lines = _shouldShowInjectedStreams ? _stats->getMixerInjectedStreamStatsMap().size() * 7 + 27 : 27;
49 int statsHeight = STATS_HEIGHT_PER_LINE * lines;49 int statsHeight = STATS_HEIGHT_PER_LINE * lines;
50 50
51 51
52 static const glm::vec4 backgroundColor = { 0.2f, 0.2f, 0.2f, 0.6f };52 static const glm::vec4 backgroundColor = { 0.2f, 0.2f, 0.2f, 0.6f };
53 int x = std::max((width - (int)STATS_WIDTH) / 2, 0);53 int x = std::max((width - (int)STATS_WIDTH) / 2, 0);
54 int y = std::max((height - CENTERED_BACKGROUND_HEIGHT) / 2, 0);54 int y = std::max((height - CENTERED_BACKGROUND_HEIGHT) / 2, 0);
55 int w = STATS_WIDTH;55 int w = STATS_WIDTH;
56 int h = statsHeight;56 int h = statsHeight;
57 DependencyManager::get<GeometryCache>()->renderQuad(x, y, w, h, backgroundColor);57 DependencyManager::get<GeometryCache>()->renderQuad(x, y, w, h, backgroundColor);
58 58
59 int horizontalOffset = x + 5;59 int horizontalOffset = x + 5;
60 int verticalOffset = y;60 int verticalOffset = y;
61 61
62 float scale = 0.10f;62 float scale = 0.10f;
63 float rotation = 0.0f;63 float rotation = 0.0f;
64 int font = 2;64 int font = 2;
65 65
66 char latencyStatString[512];66 char latencyStatString[512];
67 67
68 float audioInputBufferLatency = 0.0f, inputRingBufferLatency = 0.0f, networkRoundtripLatency = 0.0f, mixerRingBufferLatency = 0.0f, outputRingBufferLatency = 0.0f, audioOutputBufferLatency = 0.0f;68 float audioInputBufferLatency = 0.0f, inputRingBufferLatency = 0.0f, networkRoundtripLatency = 0.0f, mixerRingBufferLatency = 0.0f, outputRingBufferLatency = 0.0f, audioOutputBufferLatency = 0.0f;
69 69
70 AudioStreamStats downstreamAudioStreamStats = _stats->getMixerDownstreamStats();70 AudioStreamStats downstreamAudioStreamStats = _stats->getMixerDownstreamStats();
71 SharedNodePointer audioMixerNodePointer = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::AudioMixer);71 SharedNodePointer audioMixerNodePointer = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::AudioMixer);
72 if (!audioMixerNodePointer.isNull()) {72 if (!audioMixerNodePointer.isNull()) {
@@ -78,48 +78,62 @@ void AudioIOStatsRenderer::render(const float* color, int width, int height) { · 5 unmodified lines
78 audioOutputBufferLatency = _stats->getAudioOutputMsecsUnplayedStats().getWindowAverage();78 audioOutputBufferLatency = _stats->getAudioOutputMsecsUnplayedStats().getWindowAverage();
79 }79 }
80 float totalLatency = audioInputBufferLatency + inputRingBufferLatency + networkRoundtripLatency + mixerRingBufferLatency + outputRingBufferLatency + audioOutputBufferLatency;80 float totalLatency = audioInputBufferLatency + inputRingBufferLatency + networkRoundtripLatency + mixerRingBufferLatency + outputRingBufferLatency + audioOutputBufferLatency;
81 81
82 sprintf(latencyStatString, " Audio input buffer: %7.2fms - avg msecs of samples read to the input ring buffer in last 10s", audioInputBufferLatency);82 sprintf(latencyStatString,
83 " Audio input buffer: %7.2fms - avg msecs of samples read to the input ring buffer in last 10s",
84 (double)audioInputBufferLatency);
83 verticalOffset += STATS_HEIGHT_PER_LINE;85 verticalOffset += STATS_HEIGHT_PER_LINE;
84 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);86 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
85 87
86 sprintf(latencyStatString, " Input ring buffer: %7.2fms - avg msecs of samples in input ring buffer in last 10s", inputRingBufferLatency);88 sprintf(latencyStatString,
89 " Input ring buffer: %7.2fms - avg msecs of samples in input ring buffer in last 10s",
90 (double)inputRingBufferLatency);
87 verticalOffset += STATS_HEIGHT_PER_LINE;91 verticalOffset += STATS_HEIGHT_PER_LINE;
88 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);92 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
89 93
90 sprintf(latencyStatString, " Network to mixer: %7.2fms - half of last ping value calculated by the node list", networkRoundtripLatency / 2.0f);94 sprintf(latencyStatString,
95 " Network to mixer: %7.2fms - half of last ping value calculated by the node list",
96 (double)(networkRoundtripLatency / 2.0f));
91 verticalOffset += STATS_HEIGHT_PER_LINE;97 verticalOffset += STATS_HEIGHT_PER_LINE;
92 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);98 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
93 99
94 sprintf(latencyStatString, " AudioMixer ring buffer: %7.2fms - avg msecs of samples in audio mixer's ring buffer in last 10s", mixerRingBufferLatency);100 sprintf(latencyStatString,
101 " AudioMixer ring buffer: %7.2fms - avg msecs of samples in audio mixer's ring buffer in last 10s",
102 (double)mixerRingBufferLatency);
95 verticalOffset += STATS_HEIGHT_PER_LINE;103 verticalOffset += STATS_HEIGHT_PER_LINE;
96 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);104 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
97 105
98 sprintf(latencyStatString, " Network to client: %7.2fms - half of last ping value calculated by the node list", networkRoundtripLatency / 2.0f);106 sprintf(latencyStatString,
107 " Network to client: %7.2fms - half of last ping value calculated by the node list",
108 (double)(networkRoundtripLatency / 2.0f));
99 verticalOffset += STATS_HEIGHT_PER_LINE;109 verticalOffset += STATS_HEIGHT_PER_LINE;
100 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);110 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
101 111
102 sprintf(latencyStatString, " Output ring buffer: %7.2fms - avg msecs of samples in output ring buffer in last 10s", outputRingBufferLatency);112 sprintf(latencyStatString,
113 " Output ring buffer: %7.2fms - avg msecs of samples in output ring buffer in last 10s",
114 (double)outputRingBufferLatency);
103 verticalOffset += STATS_HEIGHT_PER_LINE;115 verticalOffset += STATS_HEIGHT_PER_LINE;
104 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);116 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
105 117
106 sprintf(latencyStatString, " Audio output buffer: %7.2fms - avg msecs of samples in audio output buffer in last 10s", audioOutputBufferLatency);118 sprintf(latencyStatString,
119 " Audio output buffer: %7.2fms - avg msecs of samples in audio output buffer in last 10s",
120 (double)audioOutputBufferLatency);
107 verticalOffset += STATS_HEIGHT_PER_LINE;121 verticalOffset += STATS_HEIGHT_PER_LINE;
108 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);122 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
109 123
110 sprintf(latencyStatString, " TOTAL: %7.2fms\n", totalLatency);124 sprintf(latencyStatString, " TOTAL: %7.2fms\n", (double)totalLatency);
111 verticalOffset += STATS_HEIGHT_PER_LINE;125 verticalOffset += STATS_HEIGHT_PER_LINE;
112 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);126 drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
113 127
114 128
115 verticalOffset += STATS_HEIGHT_PER_LINE; // blank line129 verticalOffset += STATS_HEIGHT_PER_LINE; // blank line
116 130
117 char clientUpstreamMicLabelString[] = "Upstream Mic Audio Packets Sent Gaps (by client):";131 char clientUpstreamMicLabelString[] = "Upstream Mic Audio Packets Sent Gaps (by client):";
118 verticalOffset += STATS_HEIGHT_PER_LINE;132 verticalOffset += STATS_HEIGHT_PER_LINE;
119 drawText(horizontalOffset, verticalOffset, scale, rotation, font, clientUpstreamMicLabelString, color);133 drawText(horizontalOffset, verticalOffset, scale, rotation, font, clientUpstreamMicLabelString, color);
120 134
121 const MovingMinMaxAvg<quint64>& packetSentTimeGaps = _stats->getPacketSentTimeGaps();135 const MovingMinMaxAvg<quint64>& packetSentTimeGaps = _stats->getPacketSentTimeGaps();
122 136
123 char stringBuffer[512];137 char stringBuffer[512];
124 sprintf(stringBuffer, " Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s",138 sprintf(stringBuffer, " Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s",
125 formatUsecTime(packetSentTimeGaps.getMin()).toLatin1().data(),139 formatUsecTime(packetSentTimeGaps.getMin()).toLatin1().data(),
@@ -127,47 +141,47 @@ void AudioIOStatsRenderer::render(const float* color, int width, int height) { · 1 unmodified line
127 formatUsecTime(packetSentTimeGaps.getAverage()).toLatin1().data());141 formatUsecTime(packetSentTimeGaps.getAverage()).toLatin1().data());
128 verticalOffset += STATS_HEIGHT_PER_LINE;142 verticalOffset += STATS_HEIGHT_PER_LINE;
129 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);143 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);
130 144
131 sprintf(stringBuffer, " Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s",145 sprintf(stringBuffer, " Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s",
132 formatUsecTime(packetSentTimeGaps.getWindowMin()).toLatin1().data(),146 formatUsecTime(packetSentTimeGaps.getWindowMin()).toLatin1().data(),
133 formatUsecTime(packetSentTimeGaps.getWindowMax()).toLatin1().data(),147 formatUsecTime(packetSentTimeGaps.getWindowMax()).toLatin1().data(),
134 formatUsecTime(packetSentTimeGaps.getWindowAverage()).toLatin1().data());148 formatUsecTime(packetSentTimeGaps.getWindowAverage()).toLatin1().data());
135 verticalOffset += STATS_HEIGHT_PER_LINE;149 verticalOffset += STATS_HEIGHT_PER_LINE;
136 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);150 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);
137 151
138 verticalOffset += STATS_HEIGHT_PER_LINE; // blank line152 verticalOffset += STATS_HEIGHT_PER_LINE; // blank line
139 153
140 char upstreamMicLabelString[] = "Upstream mic audio stats (received and reported by audio-mixer):";154 char upstreamMicLabelString[] = "Upstream mic audio stats (received and reported by audio-mixer):";
141 verticalOffset += STATS_HEIGHT_PER_LINE;155 verticalOffset += STATS_HEIGHT_PER_LINE;
142 drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamMicLabelString, color);156 drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamMicLabelString, color);
143 157
144 renderAudioStreamStats(&_stats->getMixerAvatarStreamStats(), horizontalOffset, verticalOffset,158 renderAudioStreamStats(&_stats->getMixerAvatarStreamStats(), horizontalOffset, verticalOffset,
145 scale, rotation, font, color);159 scale, rotation, font, color);
146 160
147 161
148 verticalOffset += STATS_HEIGHT_PER_LINE; // blank line162 verticalOffset += STATS_HEIGHT_PER_LINE; // blank line
149 163
150 char downstreamLabelString[] = "Downstream mixed audio stats:";164 char downstreamLabelString[] = "Downstream mixed audio stats:";
151 verticalOffset += STATS_HEIGHT_PER_LINE;165 verticalOffset += STATS_HEIGHT_PER_LINE;
152 drawText(horizontalOffset, verticalOffset, scale, rotation, font, downstreamLabelString, color);166 drawText(horizontalOffset, verticalOffset, scale, rotation, font, downstreamLabelString, color);
153 167
154 AudioStreamStats downstreamStats = _stats->getMixerDownstreamStats();168 AudioStreamStats downstreamStats = _stats->getMixerDownstreamStats();
155 renderAudioStreamStats(&downstreamStats, horizontalOffset, verticalOffset,169 renderAudioStreamStats(&downstreamStats, horizontalOffset, verticalOffset,
156 scale, rotation, font, color, true);170 scale, rotation, font, color, true);
157 171
158 172
159 if (_shouldShowInjectedStreams) {173 if (_shouldShowInjectedStreams) {
160 174
161 foreach(const AudioStreamStats& injectedStreamAudioStats, _stats->getMixerInjectedStreamStatsMap()) {175 foreach(const AudioStreamStats& injectedStreamAudioStats, _stats->getMixerInjectedStreamStatsMap()) {
162 176
163 verticalOffset += STATS_HEIGHT_PER_LINE; // blank line177 verticalOffset += STATS_HEIGHT_PER_LINE; // blank line
164 178
165 char upstreamInjectedLabelString[512];179 char upstreamInjectedLabelString[512];
166 sprintf(upstreamInjectedLabelString, "Upstream injected audio stats: stream ID: %s",180 sprintf(upstreamInjectedLabelString, "Upstream injected audio stats: stream ID: %s",
167 injectedStreamAudioStats._streamIdentifier.toString().toLatin1().data());181 injectedStreamAudioStats._streamIdentifier.toString().toLatin1().data());
168 verticalOffset += STATS_HEIGHT_PER_LINE;182 verticalOffset += STATS_HEIGHT_PER_LINE;
169 drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamInjectedLabelString, color);183 drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamInjectedLabelString, color);
170 184
171 renderAudioStreamStats(&injectedStreamAudioStats, horizontalOffset, verticalOffset, scale, rotation, font, color);185 renderAudioStreamStats(&injectedStreamAudioStats, horizontalOffset, verticalOffset, scale, rotation, font, color);
172 }186 }
173 }187 }
@@ -175,22 +189,22 @@ void AudioIOStatsRenderer::render(const float* color, int width, int height) { · 1 unmodified line
175 189
176void AudioIOStatsRenderer::renderAudioStreamStats(const AudioStreamStats* streamStats, int horizontalOffset, int& verticalOffset,190void AudioIOStatsRenderer::renderAudioStreamStats(const AudioStreamStats* streamStats, int horizontalOffset, int& verticalOffset,
177 float scale, float rotation, int font, const float* color, bool isDownstreamStats) {191 float scale, float rotation, int font, const float* color, bool isDownstreamStats) {
178 192
179 char stringBuffer[512];193 char stringBuffer[512];
180 194
181 sprintf(stringBuffer, " Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)",195 sprintf(stringBuffer, " Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)",
182 streamStats->_packetStreamStats.getLostRate() * 100.0f,196 (double)(streamStats->_packetStreamStats.getLostRate() * 100.0f),
183 streamStats->_packetStreamStats._lost,197 streamStats->_packetStreamStats._lost,
184 streamStats->_packetStreamWindowStats.getLostRate() * 100.0f,198 (double)(streamStats->_packetStreamWindowStats.getLostRate() * 100.0f),
185 streamStats->_packetStreamWindowStats._lost);199 streamStats->_packetStreamWindowStats._lost);
186 verticalOffset += STATS_HEIGHT_PER_LINE;200 verticalOffset += STATS_HEIGHT_PER_LINE;
187 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);201 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);
188 202
189 if (isDownstreamStats) {203 if (isDownstreamStats) {
190 sprintf(stringBuffer, " Ringbuffer frames | desired: %u, avg_available(10s): %u+%d, available: %u+%d",204 sprintf(stringBuffer, " Ringbuffer frames | desired: %u, avg_available(10s): %u+%d, available: %u+%d",
191 streamStats->_desiredJitterBufferFrames,205 streamStats->_desiredJitterBufferFrames,
192 streamStats->_framesAvailableAverage,206 streamStats->_framesAvailableAverage,
193 (int)(_stats->getAudioInputMsecsReadStats().getWindowAverage() / AudioConstants::NETWORK_FRAME_MSECS),207 (int)((float)_stats->getAudioInputMsecsReadStats().getWindowAverage() / AudioConstants::NETWORK_FRAME_MSECS),
194 streamStats->_framesAvailable,208 streamStats->_framesAvailable,
195 (int)(_stats->getAudioOutputMsecsUnplayedStats().getCurrentIntervalLastSample()209 (int)(_stats->getAudioOutputMsecsUnplayedStats().getCurrentIntervalLastSample()
196 / AudioConstants::NETWORK_FRAME_MSECS));210 / AudioConstants::NETWORK_FRAME_MSECS));
@@ -200,10 +214,10 @@ void AudioIOStatsRenderer::renderAudioStreamStats(const AudioStreamStats* stream · 3 unmodified lines
200 streamStats->_framesAvailableAverage,214 streamStats->_framesAvailableAverage,
201 streamStats->_framesAvailable);215 streamStats->_framesAvailable);
202 }216 }
203 217
204 verticalOffset += STATS_HEIGHT_PER_LINE;218 verticalOffset += STATS_HEIGHT_PER_LINE;
205 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);219 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);
206 220
207 sprintf(stringBuffer, " Ringbuffer stats | starves: %u, prev_starve_lasted: %u, frames_dropped: %u, overflows: %u",221 sprintf(stringBuffer, " Ringbuffer stats | starves: %u, prev_starve_lasted: %u, frames_dropped: %u, overflows: %u",
208 streamStats->_starveCount,222 streamStats->_starveCount,
209 streamStats->_consecutiveNotMixedCount,223 streamStats->_consecutiveNotMixedCount,
@@ -211,18 +225,18 @@ void AudioIOStatsRenderer::renderAudioStreamStats(const AudioStreamStats* stream · 1 unmodified line
211 streamStats->_overflowCount);225 streamStats->_overflowCount);
212 verticalOffset += STATS_HEIGHT_PER_LINE;226 verticalOffset += STATS_HEIGHT_PER_LINE;
213 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);227 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);
214 228
215 sprintf(stringBuffer, " Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s",229 sprintf(stringBuffer, " Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s",
216 formatUsecTime(streamStats->_timeGapMin).toLatin1().data(),230 formatUsecTime(streamStats->_timeGapMin).toLatin1().data(),
217 formatUsecTime(streamStats->_timeGapMax).toLatin1().data(),231 formatUsecTime(streamStats->_timeGapMax).toLatin1().data(),
218 formatUsecTime(streamStats->_timeGapAverage).toLatin1().data());232 formatUsecTime(streamStats->_timeGapAverage).toLatin1().data());
219 verticalOffset += STATS_HEIGHT_PER_LINE;233 verticalOffset += STATS_HEIGHT_PER_LINE;
220 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);234 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);
221 235
222 sprintf(stringBuffer, " Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s",236 sprintf(stringBuffer, " Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s",
223 formatUsecTime(streamStats->_timeGapWindowMin).toLatin1().data(),237 formatUsecTime(streamStats->_timeGapWindowMin).toLatin1().data(),
224 formatUsecTime(streamStats->_timeGapWindowMax).toLatin1().data(),238 formatUsecTime(streamStats->_timeGapWindowMax).toLatin1().data(),
225 formatUsecTime(streamStats->_timeGapWindowAverage).toLatin1().data());239 formatUsecTime(streamStats->_timeGapWindowAverage).toLatin1().data());
226 verticalOffset += STATS_HEIGHT_PER_LINE;240 verticalOffset += STATS_HEIGHT_PER_LINE;
227 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);241 drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);
228}242}
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
24const int MUTE_ICON_SIZE = 24;
25
26AudioToolBox::AudioToolBox() :
27 _iconPulseTimeReference(usecTimestampNow())
28{
29}
30
31bool 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
39void 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
19class AudioToolBox : public Dependency {
20 SINGLETON_DEPENDENCY
21public:
22 void render(int x, int y, int padding, bool boxed);
23
24 bool mousePressEvent(int x, int y);
25protected:
26 AudioToolBox();
27private:
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
57const float CHAT_MESSAGE_HEIGHT = 0.1f;57const float CHAT_MESSAGE_HEIGHT = 0.1f;
58const float DISPLAYNAME_FADE_TIME = 0.5f;58const float DISPLAYNAME_FADE_TIME = 0.5f;
59const float DISPLAYNAME_FADE_FACTOR = pow(0.01f, 1.0f / DISPLAYNAME_FADE_TIME);59const float DISPLAYNAME_FADE_FACTOR = pow(0.01f, 1.0f / DISPLAYNAME_FADE_TIME);
60const float DISPLAYNAME_ALPHA = 0.95f;60const float DISPLAYNAME_ALPHA = 1.0f;
61const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f;61const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f;
62 62
63namespace render {63namespace render {
@@ -107,6 +107,7 @@ Avatar::Avatar() : · 43 unmodified lines
107}107}
108 108
109Avatar::~Avatar() {109Avatar::~Avatar() {
110 assert(_motionState == nullptr);
110 for(auto attachment : _unusedAttachments) {111 for(auto attachment : _unusedAttachments) {
111 delete attachment;112 delete attachment;
112 }113 }
@@ -280,9 +281,9 @@ enum TextRendererType { · 167 unmodified lines
280};281};
281 282
282static TextRenderer3D* textRenderer(TextRendererType type) {283static TextRenderer3D* textRenderer(TextRendererType type) {
283 static TextRenderer3D* chatRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, 24, -1,284 static TextRenderer3D* chatRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, -1,
284 false, TextRenderer3D::SHADOW_EFFECT);285 false, TextRenderer3D::SHADOW_EFFECT);
285 static TextRenderer3D* displayNameRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, 12);286 static TextRenderer3D* displayNameRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY);
286 287
287 switch(type) {288 switch(type) {
288 case CHAT:289 case CHAT:
@@ -323,7 +324,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 34 unmodified lines
323 _referential->update();324 _referential->update();
324 }325 }
325 326
326 auto batch = renderArgs->_batch;327 auto& batch = *renderArgs->_batch;
327 328
328 if (postLighting &&329 if (postLighting &&
329 glm::distance(DependencyManager::get<AvatarManager>()->getMyAvatar()->getPosition(), _position) < 10.0f) {330 glm::distance(DependencyManager::get<AvatarManager>()->getMyAvatar()->getPosition(), _position) < 10.0f) {
@@ -354,9 +355,9 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 24 unmodified lines
354 Transform pointerTransform;355 Transform pointerTransform;
355 pointerTransform.setTranslation(position);356 pointerTransform.setTranslation(position);
356 pointerTransform.setRotation(rotation);357 pointerTransform.setRotation(rotation);
357 batch->setModelTransform(pointerTransform);358 batch.setModelTransform(pointerTransform);
358 deferredLighting->bindSimpleProgram(*batch);359 deferredLighting->bindSimpleProgram(batch);
359 geometryCache->renderLine(*batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor);360 geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor);
360 }361 }
361 }362 }
362 363
@@ -377,9 +378,9 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 14 unmodified lines
377 Transform pointerTransform;378 Transform pointerTransform;
378 pointerTransform.setTranslation(position);379 pointerTransform.setTranslation(position);
379 pointerTransform.setRotation(rotation);380 pointerTransform.setRotation(rotation);
380 batch->setModelTransform(pointerTransform);381 batch.setModelTransform(pointerTransform);
381 deferredLighting->bindSimpleProgram(*batch);382 deferredLighting->bindSimpleProgram(batch);
382 geometryCache->renderLine(*batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor);383 geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor);
383 }384 }
384 }385 }
385 }386 }
@@ -464,8 +465,8 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 78 unmodified lines
464 }465 }
465 Transform transform;466 Transform transform;
466 transform.setTranslation(position);467 transform.setTranslation(position);
467 batch->setModelTransform(transform);468 batch.setModelTransform(transform);
468 DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(*batch, LOOK_AT_INDICATOR_RADIUS469 DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(batch, LOOK_AT_INDICATOR_RADIUS
469 , 15, 15, LOOK_AT_INDICATOR_COLOR);470 , 15, 15, LOOK_AT_INDICATOR_COLOR);
470 }471 }
471 }472 }
@@ -492,14 +493,14 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 20 unmodified lines
492 Transform transform;493 Transform transform;
493 transform.setTranslation(_position);494 transform.setTranslation(_position);
494 transform.setScale(height);495 transform.setScale(height);
495 batch->setModelTransform(transform);496 batch.setModelTransform(transform);
496 497
497 if (_voiceSphereID == GeometryCache::UNKNOWN_ID) {498 if (_voiceSphereID == GeometryCache::UNKNOWN_ID) {
498 _voiceSphereID = DependencyManager::get<GeometryCache>()->allocateID();499 _voiceSphereID = DependencyManager::get<GeometryCache>()->allocateID();
499 }500 }
500 501
501 DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(*batch);502 DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch);
502 DependencyManager::get<GeometryCache>()->renderSphere(*batch, sphereRadius, 15, 15,503 DependencyManager::get<GeometryCache>()->renderSphere(batch, sphereRadius, 15, 15,
503 glm::vec4(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE), true,504 glm::vec4(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE), true,
504 _voiceSphereID);505 _voiceSphereID);
505 }506 }
@@ -507,14 +508,12 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 1 unmodified line
507 }508 }
508 509
509 const float DISPLAYNAME_DISTANCE = 20.0f;510 const float DISPLAYNAME_DISTANCE = 20.0f;
510 setShowDisplayName(renderArgs->_renderMode == RenderArgs::NORMAL_RENDER_MODE && distanceToTarget < DISPLAYNAME_DISTANCE);511 setShowDisplayName(distanceToTarget < DISPLAYNAME_DISTANCE);
511 512
512 if (renderArgs->_renderMode != RenderArgs::NORMAL_RENDER_MODE || (isMyAvatar() &&513 auto cameraMode = Application::getInstance()->getCamera()->getMode();
513 Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON)) {514 if (!isMyAvatar() || cameraMode != CAMERA_MODE_FIRST_PERSON) {
514 return;515 renderDisplayName(batch, *renderArgs->_viewFrustum);
515 }516 }
516
517 renderDisplayName(renderArgs);
518}517}
519 518
520glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {519glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
@@ -654,8 +653,8 @@ float Avatar::getBillboardSize() const { · 133 unmodified lines
654 return _scale * BILLBOARD_DISTANCE * tanf(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f));653 return _scale * BILLBOARD_DISTANCE * tanf(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f));
655}654}
656 655
657glm::vec3 Avatar::getDisplayNamePosition() {656glm::vec3 Avatar::getDisplayNamePosition() const {
658 glm::vec3 namePosition;657 glm::vec3 namePosition(0.0f);
659 if (getSkeletonModel().getNeckPosition(namePosition)) {658 if (getSkeletonModel().getNeckPosition(namePosition)) {
660 namePosition += getBodyUpDirection() * getHeadHeight() * 1.1f;659 namePosition += getBodyUpDirection() * getHeadHeight() * 1.1f;
661 } else {660 } else {
@@ -665,81 +664,73 @@ glm::vec3 Avatar::getDisplayNamePosition() { · 3 unmodified lines
665 return namePosition;664 return namePosition;
666}665}
667 666
668float Avatar::calculateDisplayNameScaleFactor(const glm::vec3& textPosition, bool inHMD) {667Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& frustum, float fontSize) const {
669 668 Transform result;
670 // We need to compute the scale factor such as the text remains with fixed size respect to window coordinates669 // We assume textPosition is whithin the frustum
671 // We project a unit vector and check the difference in screen coordinates, to check which is the670 glm::vec3 textPosition = getDisplayNamePosition();
672 // correction scale needed671
673 // save the matrices for later scale correction factor672 // Compute viewProjection matrix
674 // The up vector must be relative to the rotation current rotation matrix:673 glm::mat4 projMat, viewMat;
675 // we set the identity674 Transform view;
675 frustum.evalProjectionMatrix(projMat);
676 frustum.evalViewTransform(view);
677 glm::mat4 viewProj = projMat * view.getInverseMatrix(viewMat);
678
679 // Used to determine correct scale
676 glm::vec3 testPoint0 = textPosition;680 glm::vec3 testPoint0 = textPosition;
677 glm::vec3 testPoint1 = textPosition + (Application::getInstance()->getCamera()->getRotation() * IDENTITY_UP);681 glm::vec3 testPoint1 = testPoint0 + glm::normalize(frustum.getUp());
678 682 // testPoints projections
679 double textWindowHeight;683 glm::vec4 p0 = viewProj * glm::vec4(testPoint0, 1.0);
680 684 glm::vec4 p1 = viewProj * glm::vec4(testPoint1, 1.0);
685
686 // TODO REMOVE vvv
681 GLint viewportMatrix[4];687 GLint viewportMatrix[4];
682 glGetIntegerv(GL_VIEWPORT, viewportMatrix);688 glGetIntegerv(GL_VIEWPORT, viewportMatrix);
683 glm::dmat4 modelViewMatrix;689 glm::dmat4 modelViewMatrix;
684 float windowSizeX = viewportMatrix[2] - viewportMatrix[0];
685 float windowSizeY = viewportMatrix[3] - viewportMatrix[1];690 float windowSizeY = viewportMatrix[3] - viewportMatrix[1];
691 // TODO REMOVE ^^^
692
693 const float DESIRED_HIGHT_ON_SCREEN = 20; // In pixels (this is double on retinas)
694
695 // Projected point are between -1.0f and 1.0f, hence 0.5f * windowSizeY
696 double pixelHeight = 0.5f * windowSizeY * glm::abs((p1.y / p1.w) - (p0.y / p0.w)); //
697 // Handles pixel density (especially for macs retina displays)
698 double devicePixelRatio = qApp->getDevicePixelRatio() * qApp->getRenderResolutionScale(); // pixels / unit
699
700 // Compute correct scale to apply
701 float scale = DESIRED_HIGHT_ON_SCREEN / (fontSize * pixelHeight) * devicePixelRatio;
702
703 // Compute pixel alignment offset
704 float clipToPix = 0.5f * windowSizeY / p1.w; // Got from clip to pixel coordinates
705 glm::vec4 screenPos = clipToPix * p1; // in pixels coords
706 glm::vec4 screenOffset = (glm::round(screenPos) - screenPos) / clipToPix; // in clip coords
707 glm::vec3 worldOffset = glm::vec3(screenOffset.x, screenOffset.y, 0.0f) / (float)pixelHeight;
708
709 // Compute orientation
710 glm::vec3 eulerAngles = ::safeEulerAngles(frustum.getOrientation());
711 eulerAngles.z = 0.0f; // Cancel roll
712 glm::quat orientation(eulerAngles); // back to quaternions
713
714 // Set transform (The order IS important)
715 result.setTranslation(textPosition);
716 result.setRotation(orientation); // Always face the screen
717 result.postTranslate(worldOffset); // Pixel alignment
718 result.setScale(scale);
719 return result;
686 720
687 glm::dmat4 projectionMatrix;
688 Application::getInstance()->getModelViewMatrix(&modelViewMatrix);
689 Application::getInstance()->getProjectionMatrix(&projectionMatrix);
690
691
692 glm::dvec4 p0 = modelViewMatrix * glm::dvec4(testPoint0, 1.0);
693 p0 = projectionMatrix * p0;
694 glm::dvec2 result0 = glm::vec2(windowSizeX * (p0.x / p0.w + 1.0f) * 0.5f, windowSizeY * (p0.y / p0.w + 1.0f) * 0.5f);
695
696 glm::dvec4 p1 = modelViewMatrix * glm::dvec4(testPoint1, 1.0);
697 p1 = projectionMatrix * p1;
698 glm::vec2 result1 = glm::vec2(windowSizeX * (p1.x / p1.w + 1.0f) * 0.5f, windowSizeY * (p1.y / p1.w + 1.0f) * 0.5f);
699 textWindowHeight = abs(result1.y - result0.y);
700
701 // need to scale to compensate for the font resolution due to the device
702 float scaleFactor = QApplication::desktop()->windowHandle()->devicePixelRatio() *
703 ((textWindowHeight > EPSILON) ? 1.0f / textWindowHeight : 1.0f);
704 if (inHMD) {
705 const float HMDMODE_NAME_SCALE = 0.65f;
706 scaleFactor *= HMDMODE_NAME_SCALE;
707 } else {
708 scaleFactor *= Application::getInstance()->getRenderResolutionScale();
709 }
710 return scaleFactor;
711}721}
712 722
713void Avatar::renderDisplayName(RenderArgs* renderArgs) {723void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) const {
714 auto batch = renderArgs->_batch;
715
716 bool shouldShowReceiveStats = DependencyManager::get<AvatarManager>()->shouldShowReceiveStats() && !isMyAvatar();724 bool shouldShowReceiveStats = DependencyManager::get<AvatarManager>()->shouldShowReceiveStats() && !isMyAvatar();
717 725
726 // If we have nothing to draw, or it's tottaly transparent, return
718 if ((_displayName.isEmpty() && !shouldShowReceiveStats) || _displayNameAlpha == 0.0f) {727 if ((_displayName.isEmpty() && !shouldShowReceiveStats) || _displayNameAlpha == 0.0f) {
719 return;728 return;
720 }729 }
721 730 auto renderer = textRenderer(DISPLAYNAME);
722 // which viewing mode?
723 bool inHMD = Application::getInstance()->isHMDMode();
724
725 glm::vec3 textPosition = getDisplayNamePosition();
726
727 // we need "always facing camera": we must remove the camera rotation from the stac
728 glm::quat rotation = Application::getInstance()->getCamera()->getRotation();
729
730 // TODO: Fix scaling - at some point this or the text rendering changed in scale.
731 float scaleFactor = calculateDisplayNameScaleFactor(textPosition, inHMD);
732 scaleFactor /= 3.5f;
733
734 Transform textTransform;
735 textTransform.setTranslation(textPosition);
736 textTransform.setRotation(rotation);
737 textTransform.setScale(scaleFactor);
738 731
739 // optionally render timing stats for this avatar with the display name732 // optionally render timing stats for this avatar with the display name
740 QString renderedDisplayName = _displayName;733 QString renderedDisplayName = _displayName;
741 QRect nameDynamicRect = _displayNameBoundingRect;
742
743 if (shouldShowReceiveStats) {734 if (shouldShowReceiveStats) {
744 float kilobitsPerSecond = getAverageBytesReceivedPerSecond() / (float) BYTES_PER_KILOBIT;735 float kilobitsPerSecond = getAverageBytesReceivedPerSecond() / (float) BYTES_PER_KILOBIT;
745 736
@@ -747,42 +738,43 @@ void Avatar::renderDisplayName(RenderArgs* renderArgs) { · 1 unmodified line
747 if (!renderedDisplayName.isEmpty()) {738 if (!renderedDisplayName.isEmpty()) {
748 statsFormat.prepend(" - ");739 statsFormat.prepend(" - ");
749 }740 }
750 741 renderedDisplayName += statsFormat.arg(QString::number(kilobitsPerSecond, 'f', 2)).arg(getReceiveRate());
751 QString statsText = statsFormat.arg(QString::number(kilobitsPerSecond, 'f', 2)).arg(getReceiveRate());
752 renderedDisplayName += statsText;
753
754 glm::vec2 extent = textRenderer(DISPLAYNAME)->computeExtent(renderedDisplayName);
755 nameDynamicRect = QRect(0, 0, (int)extent.x, (int)extent.y);
756 }742 }
757
758 int text_x = -nameDynamicRect.width() / 2;
759 int text_y = -nameDynamicRect.height() / 2;
760
761 // draw a gray background
762 int left = text_x;
763 int right = left + nameDynamicRect.width();
764 int bottom = text_y;
765 int top = bottom + nameDynamicRect.height();
766 const int border = 8;
767 bottom -= border;
768 left -= border;
769 top += border;
770 right += border;
771 743
744 // Compute display name extent/position offset
745 glm::vec2 extent = renderer->computeExtent(renderedDisplayName);
746 QRect nameDynamicRect = QRect(0, 0, (int)extent.x, (int)extent.y);
747 const int text_x = -nameDynamicRect.width() / 2;
748 const int text_y = -nameDynamicRect.height() / 2;
749
750 // Compute background position/size
751 static const float SLIGHTLY_BEHIND = -0.05f;
752 const int border = 0.1f * nameDynamicRect.height();
753 const int left = text_x - border;
754 const int bottom = text_y - border;
755 const int width = nameDynamicRect.width() + 2.0f * border;
756 const int height = nameDynamicRect.height() + 2.0f * border;
757 const int bevelDistance = 0.1f * height;
758
759 // Display name and background colors
772 glm::vec4 textColor(0.93f, 0.93f, 0.93f, _displayNameAlpha);760 glm::vec4 textColor(0.93f, 0.93f, 0.93f, _displayNameAlpha);
773 glm::vec4 backgroundColor(0.2f, 0.2f, 0.2f,761 glm::vec4 backgroundColor(0.2f, 0.2f, 0.2f,
774 _displayNameAlpha * DISPLAYNAME_BACKGROUND_ALPHA / DISPLAYNAME_ALPHA);762 (_displayNameAlpha / DISPLAYNAME_ALPHA) * DISPLAYNAME_BACKGROUND_ALPHA);
763
764 // Compute display name transform
765 auto textTransform = calculateDisplayNameTransform(frustum, renderer->getFontSize());
775 766
767 // Render background slightly behind to avoid z-fighting
776 auto backgroundTransform = textTransform;768 auto backgroundTransform = textTransform;
777 backgroundTransform.postTranslate(glm::vec3(0.0f, 0.0f, -0.001f));769 backgroundTransform.postTranslate(glm::vec3(0.0f, 0.0f, SLIGHTLY_BEHIND));
778 batch->setModelTransform(backgroundTransform);770 batch.setModelTransform(backgroundTransform);
779 DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(*batch);771 DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch);
780 DependencyManager::get<GeometryCache>()->renderBevelCornersRect(*batch, left, bottom, right - left, top - bottom, 3,772 DependencyManager::get<GeometryCache>()->renderBevelCornersRect(batch, left, bottom, width, height,
781 backgroundColor);773 bevelDistance, backgroundColor);
774 // Render actual name
782 QByteArray nameUTF8 = renderedDisplayName.toLocal8Bit();775 QByteArray nameUTF8 = renderedDisplayName.toLocal8Bit();
783 776 batch.setModelTransform(textTransform);
784 batch->setModelTransform(textTransform);777 renderer->draw(batch, text_x, -text_y, nameUTF8.data(), textColor);
785 textRenderer(DISPLAYNAME)->draw(*batch, text_x, -text_y, nameUTF8.data(), textColor);
786}778}
787 779
788bool Avatar::findRayIntersection(RayIntersectionInfo& intersection) const {780bool Avatar::findRayIntersection(RayIntersectionInfo& intersection) const {
@@ -987,13 +979,6 @@ void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) { · 198 unmodified lines
987 }979 }
988}980}
989 981
990void 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
997void Avatar::setBillboard(const QByteArray& billboard) {982void Avatar::setBillboard(const QByteArray& billboard) {
998 AvatarData::setBillboard(billboard);983 AvatarData::setBillboard(billboard);
999 984
@@ -1092,7 +1077,12 @@ float Avatar::getSkeletonHeight() const { · 92 unmodified lines
1092float Avatar::getHeadHeight() const {1077float Avatar::getHeadHeight() const {
1093 Extents extents = getHead()->getFaceModel().getMeshExtents();1078 Extents extents = getHead()->getFaceModel().getMeshExtents();
1094 if (!extents.isEmpty() && extents.isValid()) {1079 if (!extents.isEmpty() && extents.isValid()) {
1095 return extents.maximum.y - extents.minimum.y;1080
1081 // HACK: We have a really odd case when fading out for some models where this value explodes
1082 float result = extents.maximum.y - extents.minimum.y;
1083 if (result >= 0.0f && result < 100.0f * _scale ) {
1084 return result;
1085 }
1096 }1086 }
1097 1087
1098 extents = _skeletonModel.getMeshExtents();1088 extents = _skeletonModel.getMeshExtents();
@@ -1116,7 +1106,7 @@ void Avatar::setShowDisplayName(bool showDisplayName) { · 17 unmodified lines
1116 }1106 }
1117 1107
1118 // For myAvatar, the alpha update is not done (called in simulate for other avatars)1108 // For myAvatar, the alpha update is not done (called in simulate for other avatars)
1119 if (DependencyManager::get<AvatarManager>()->getMyAvatar() == this) {1109 if (isMyAvatar()) {
1120 if (showDisplayName) {1110 if (showDisplayName) {
1121 _displayNameAlpha = DISPLAYNAME_ALPHA;1111 _displayNameAlpha = DISPLAYNAME_ALPHA;
1122 } else {1112 } else {
@@ -1129,7 +1119,6 @@ void Avatar::setShowDisplayName(bool showDisplayName) { · 6 unmodified lines
1129 } else {1119 } else {
1130 _displayNameTargetAlpha = 0.0f;1120 _displayNameTargetAlpha = 0.0f;
1131 }1121 }
1132
1133}1122}
1134 1123
1135// virtual 1124// virtual
interface/src/avatar/Avatar.h+5−5
@@ -98,6 +98,7 @@ public: · 97 unmodified lines
98 //getters98 //getters
99 bool isInitialized() const { return _initialized; }99 bool isInitialized() const { return _initialized; }
100 SkeletonModel& getSkeletonModel() { return _skeletonModel; }100 SkeletonModel& getSkeletonModel() { return _skeletonModel; }
101 const SkeletonModel& getSkeletonModel() const { return _skeletonModel; }
101 const QVector<Model*>& getAttachmentModels() const { return _attachmentModels; }102 const QVector<Model*>& getAttachmentModels() const { return _attachmentModels; }
102 glm::vec3 getChestPosition() const;103 glm::vec3 getChestPosition() const;
103 float getScale() const { return _scale; }104 float getScale() const { return _scale; }
@@ -131,7 +132,7 @@ public: · 27 unmodified lines
131 /// \return whether or not the plane penetrated132 /// \return whether or not the plane penetrated
132 bool findPlaneCollisions(const glm::vec4& plane, CollisionList& collisions);133 bool findPlaneCollisions(const glm::vec4& plane, CollisionList& collisions);
133 134
134 virtual bool isMyAvatar() { return false; }135 virtual bool isMyAvatar() const { return false; }
135 136
136 virtual QVector<glm::quat> getJointRotations() const;137 virtual QVector<glm::quat> getJointRotations() const;
137 virtual glm::quat getJointRotation(int index) const;138 virtual glm::quat getJointRotation(int index) const;
@@ -141,7 +142,6 @@ public: · 3 unmodified lines
141 virtual void setFaceModelURL(const QUrl& faceModelURL);142 virtual void setFaceModelURL(const QUrl& faceModelURL);
142 virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);143 virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
143 virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData);144 virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData);
144 virtual void setDisplayName(const QString& displayName);
145 virtual void setBillboard(const QByteArray& billboard);145 virtual void setBillboard(const QByteArray& billboard);
146 146
147 void setShowDisplayName(bool showDisplayName);147 void setShowDisplayName(bool showDisplayName);
@@ -232,10 +232,10 @@ protected: · 84 unmodified lines
232 float getSkeletonHeight() const;232 float getSkeletonHeight() const;
233 float getHeadHeight() const;233 float getHeadHeight() const;
234 float getPelvisFloatingHeight() const;234 float getPelvisFloatingHeight() const;
235 glm::vec3 getDisplayNamePosition();235 glm::vec3 getDisplayNamePosition() const;
236 236
237 float calculateDisplayNameScaleFactor(const glm::vec3& textPosition, bool inHMD);237 Transform calculateDisplayNameTransform(const ViewFrustum& frustum, float fontSize) const;
238 void renderDisplayName(RenderArgs* renderArgs);238 void renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) const;
239 virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel = 0.0f);239 virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel = 0.0f);
240 virtual bool shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const;240 virtual bool shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const;
241 virtual void fixupModelsInScene();241 virtual void fixupModelsInScene();
interface/src/avatar/AvatarActionHold.cpp+10−1
@@ -29,6 +29,12 @@ AvatarActionHold::~AvatarActionHold() { · 28 unmodified lines
29 29
30void AvatarActionHold::updateActionWorker(float deltaTimeStep) {30void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
31 auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();31 auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
32
33 if (!tryLockForRead()) {
34 // don't risk hanging the thread running the physics simulation
35 return;
36 }
37
32 glm::vec3 palmPosition;38 glm::vec3 palmPosition;
33 if (_hand == "right") {39 if (_hand == "right") {
34 palmPosition = myAvatar->getRightPalmPosition();40 palmPosition = myAvatar->getRightPalmPosition();
@@ -40,8 +46,11 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { · 5 unmodified lines
40 auto offset = rotation * _relativePosition;46 auto offset = rotation * _relativePosition;
41 auto position = palmPosition + offset;47 auto position = palmPosition + offset;
42 rotation *= _relativeRotation;48 rotation *= _relativeRotation;
49 unlock();
43 50
44 lockForWrite();51 if (!tryLockForWrite()) {
52 return;
53 }
45 _positionalTarget = position;54 _positionalTarget = position;
46 _rotationalTarget = rotation;55 _rotationalTarget = rotation;
47 unlock();56 unlock();
interface/src/avatar/AvatarManager.cpp+17−5
@@ -13,8 +13,18 @@ · 12 unmodified lines
13 13
14#include <QScriptEngine>14#include <QScriptEngine>
15 15
16#ifdef __GNUC__
17#pragma GCC diagnostic push
18#pragma GCC diagnostic ignored "-Wdouble-promotion"
19#endif
20
16#include <glm/gtx/string_cast.hpp>21#include <glm/gtx/string_cast.hpp>
17 22
23#ifdef __GNUC__
24#pragma GCC diagnostic pop
25#endif
26
27
18#include <GlowEffect.h>28#include <GlowEffect.h>
19#include <PerfStat.h>29#include <PerfStat.h>
20#include <RegisteredMetaTypes.h>30#include <RegisteredMetaTypes.h>
@@ -104,6 +114,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { · 83 unmodified lines
104 // DO NOT update or fade out uninitialized Avatars114 // DO NOT update or fade out uninitialized Avatars
105 ++avatarIterator;115 ++avatarIterator;
106 } else if (avatar->shouldDie()) {116 } else if (avatar->shouldDie()) {
117 removeAvatarMotionState(avatar);
107 _avatarFades.push_back(avatarIterator.value());118 _avatarFades.push_back(avatarIterator.value());
108 avatarIterator = _avatarHash.erase(avatarIterator);119 avatarIterator = _avatarHash.erase(avatarIterator);
109 } else {120 } else {
@@ -153,12 +164,13 @@ AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWe · 43 unmodified lines
153}164}
154 165
155// protected166// protected
156void AvatarManager::removeAvatarMotionState(Avatar* avatar) {167void AvatarManager::removeAvatarMotionState(AvatarSharedPointer avatar) {
157 AvatarMotionState* motionState= avatar->_motionState;168 auto rawPointer = std::static_pointer_cast<Avatar>(avatar);
169 AvatarMotionState* motionState= rawPointer->_motionState;
158 if (motionState) {170 if (motionState) {
159 // clean up physics stuff171 // clean up physics stuff
160 motionState->clearObjectBackPointer();172 motionState->clearObjectBackPointer();
161 avatar->_motionState = nullptr;173 rawPointer->_motionState = nullptr;
162 _avatarMotionStates.remove(motionState);174 _avatarMotionStates.remove(motionState);
163 _motionStatesToAdd.remove(motionState);175 _motionStatesToAdd.remove(motionState);
164 _motionStatesToDelete.push_back(motionState);176 _motionStatesToDelete.push_back(motionState);
@@ -171,7 +183,7 @@ void AvatarManager::removeAvatar(const QUuid& sessionUUID) { · 6 unmodified lines
171 if (avatarIterator != _avatarHash.end()) {183 if (avatarIterator != _avatarHash.end()) {
172 std::shared_ptr<Avatar> avatar = std::dynamic_pointer_cast<Avatar>(avatarIterator.value());184 std::shared_ptr<Avatar> avatar = std::dynamic_pointer_cast<Avatar>(avatarIterator.value());
173 if (avatar != _myAvatar && avatar->isInitialized()) {185 if (avatar != _myAvatar && avatar->isInitialized()) {
174 removeAvatarMotionState(avatar.get());186 removeAvatarMotionState(avatar);
175 _avatarFades.push_back(avatarIterator.value());187 _avatarFades.push_back(avatarIterator.value());
176 _avatarHash.erase(avatarIterator);188 _avatarHash.erase(avatarIterator);
177 }189 }
@@ -187,7 +199,7 @@ void AvatarManager::clearOtherAvatars() { · 9 unmodified lines
187 // don't remove myAvatar or uninitialized avatars from the list199 // don't remove myAvatar or uninitialized avatars from the list
188 ++avatarIterator;200 ++avatarIterator;
189 } else {201 } else {
190 removeAvatarMotionState(avatar.get());202 removeAvatarMotionState(avatar);
191 _avatarFades.push_back(avatarIterator.value());203 _avatarFades.push_back(avatarIterator.value());
192 avatarIterator = _avatarHash.erase(avatarIterator);204 avatarIterator = _avatarHash.erase(avatarIterator);
193 }205 }
interface/src/avatar/AvatarManager.h+1−1
@@ -73,7 +73,7 @@ private: · 72 unmodified lines
73 // virtual overrides73 // virtual overrides
74 virtual AvatarSharedPointer newSharedAvatar();74 virtual AvatarSharedPointer newSharedAvatar();
75 virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer);75 virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer);
76 void removeAvatarMotionState(Avatar* avatar);76 void removeAvatarMotionState(AvatarSharedPointer avatar);
77 virtual void removeAvatar(const QUuid& sessionUUID);77 virtual void removeAvatar(const QUuid& sessionUUID);
78 78
79 QVector<AvatarSharedPointer> _avatarFades;79 QVector<AvatarSharedPointer> _avatarFades;
interface/src/avatar/Head.cpp+13−6
@@ -77,7 +77,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { · 76 unmodified lines
77 const float AUDIO_LONG_TERM_AVERAGING_SECS = 30.0f;77 const float AUDIO_LONG_TERM_AVERAGING_SECS = 30.0f;
78 _averageLoudness = glm::mix(_averageLoudness, _audioLoudness, glm::min(deltaTime / AUDIO_AVERAGING_SECS, 1.0f));78 _averageLoudness = glm::mix(_averageLoudness, _audioLoudness, glm::min(deltaTime / AUDIO_AVERAGING_SECS, 1.0f));
79 79
80 if (_longTermAverageLoudness == -1.0) {80 if (_longTermAverageLoudness == -1.0f) {
81 _longTermAverageLoudness = _averageLoudness;81 _longTermAverageLoudness = _averageLoudness;
82 } else {82 } else {
83 _longTermAverageLoudness = glm::mix(_longTermAverageLoudness, _averageLoudness, glm::min(deltaTime / AUDIO_LONG_TERM_AVERAGING_SECS, 1.0f));83 _longTermAverageLoudness = glm::mix(_longTermAverageLoudness, _averageLoudness, glm::min(deltaTime / AUDIO_LONG_TERM_AVERAGING_SECS, 1.0f));
@@ -124,18 +124,25 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { · 40 unmodified lines
124 124
125 if (!(_isFaceTrackerConnected || billboard)) {125 if (!(_isFaceTrackerConnected || billboard)) {
126 // Update eye saccades126 // Update eye saccades
127 const float AVERAGE_MICROSACCADE_INTERVAL = 0.50f;127 const float AVERAGE_MICROSACCADE_INTERVAL = 1.0f;
128 const float AVERAGE_SACCADE_INTERVAL = 4.0f;128 const float AVERAGE_SACCADE_INTERVAL = 6.0f;
129 const float MICROSACCADE_MAGNITUDE = 0.002f;129 const float MICROSACCADE_MAGNITUDE = 0.002f;
130 const float SACCADE_MAGNITUDE = 0.04f;130 const float SACCADE_MAGNITUDE = 0.04f;
131 131 const float MAXIMUM_SACCADE_SPEED = 0.8f;
132
132 if (randFloat() < deltaTime / AVERAGE_MICROSACCADE_INTERVAL) {133 if (randFloat() < deltaTime / AVERAGE_MICROSACCADE_INTERVAL) {
133 _saccadeTarget = MICROSACCADE_MAGNITUDE * randVector();134 _saccadeTarget = MICROSACCADE_MAGNITUDE * randVector();
134 } else if (randFloat() < deltaTime / AVERAGE_SACCADE_INTERVAL) {135 } else if (randFloat() < deltaTime / AVERAGE_SACCADE_INTERVAL) {
135 _saccadeTarget = SACCADE_MAGNITUDE * randVector();136 _saccadeTarget = SACCADE_MAGNITUDE * randVector();
136 }137 }
137 _saccade += (_saccadeTarget - _saccade) * 0.50f;138
138 139 glm::vec3 saccadeDelta = (_saccadeTarget - _saccade) * 0.5f;
140 float speed = glm::length(saccadeDelta) / deltaTime;
141 if (speed > MAXIMUM_SACCADE_SPEED) {
142 saccadeDelta = saccadeDelta * MAXIMUM_SACCADE_SPEED / speed;
143 }
144 _saccade += saccadeDelta;
145
139 // Detect transition from talking to not; force blink after that and a delay146 // Detect transition from talking to not; force blink after that and a delay
140 bool forceBlink = false;147 bool forceBlink = false;
141 const float TALKING_LOUDNESS = 100.0f;148 const float TALKING_LOUDNESS = 100.0f;
interface/src/avatar/MyAvatar.cpp+81−81
@@ -59,10 +59,10 @@ const float MAX_WALKING_SPEED = 2.5f; // human walking speed · 58 unmodified lines
59const float MAX_BOOST_SPEED = 0.5f * MAX_WALKING_SPEED; // keyboard motor gets additive boost below this speed59const float MAX_BOOST_SPEED = 0.5f * MAX_WALKING_SPEED; // keyboard motor gets additive boost below this speed
60const float MIN_AVATAR_SPEED = 0.05f; // speed is set to zero below this60const float MIN_AVATAR_SPEED = 0.05f; // speed is set to zero below this
61 61
62// TODO: normalize avatar speed for standard avatar size, then scale all motion logic 62// TODO: normalize avatar speed for standard avatar size, then scale all motion logic
63// to properly follow avatar size.63// to properly follow avatar size.
64float MAX_AVATAR_SPEED = 300.0f;64float MAX_AVATAR_SPEED = 300.0f;
65float MAX_KEYBOARD_MOTOR_SPEED = MAX_AVATAR_SPEED; 65float MAX_KEYBOARD_MOTOR_SPEED = MAX_AVATAR_SPEED;
66float DEFAULT_KEYBOARD_MOTOR_TIMESCALE = 0.25f;66float DEFAULT_KEYBOARD_MOTOR_TIMESCALE = 0.25f;
67float MIN_SCRIPTED_MOTOR_TIMESCALE = 0.005f;67float MIN_SCRIPTED_MOTOR_TIMESCALE = 0.005f;
68float DEFAULT_SCRIPTED_MOTOR_TIMESCALE = 1.0e6f;68float DEFAULT_SCRIPTED_MOTOR_TIMESCALE = 1.0e6f;
@@ -146,7 +146,7 @@ void MyAvatar::update(float deltaTime) { · 77 unmodified lines
146 if (_referential) {146 if (_referential) {
147 _referential->update();147 _referential->update();
148 }148 }
149 149
150 Head* head = getHead();150 Head* head = getHead();
151 head->relaxLean(deltaTime);151 head->relaxLean(deltaTime);
152 updateFromTrackers(deltaTime);152 updateFromTrackers(deltaTime);
@@ -163,12 +163,12 @@ void MyAvatar::update(float deltaTime) { · 10 unmodified lines
163 163
164void MyAvatar::simulate(float deltaTime) {164void MyAvatar::simulate(float deltaTime) {
165 PerformanceTimer perfTimer("simulate");165 PerformanceTimer perfTimer("simulate");
166 166
167 // Play back recording167 // Play back recording
168 if (_player && _player->isPlaying()) {168 if (_player && _player->isPlaying()) {
169 _player->play();169 _player->play();
170 }170 }
171 171
172 if (_scale != _targetScale) {172 if (_scale != _targetScale) {
173 float scale = (1.0f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale;173 float scale = (1.0f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale;
174 setScale(scale);174 setScale(scale);
@@ -179,7 +179,7 @@ void MyAvatar::simulate(float deltaTime) { · 4 unmodified lines
179 updateOrientation(deltaTime);179 updateOrientation(deltaTime);
180 updatePosition(deltaTime);180 updatePosition(deltaTime);
181 }181 }
182 182
183 {183 {
184 PerformanceTimer perfTimer("hand");184 PerformanceTimer perfTimer("hand");
185 // update avatar skeleton and simulate hand and head185 // update avatar skeleton and simulate hand and head
@@ -222,12 +222,12 @@ void MyAvatar::simulate(float deltaTime) { · 36 unmodified lines
222 head->setScale(_scale);222 head->setScale(_scale);
223 head->simulate(deltaTime, true);223 head->simulate(deltaTime, true);
224 }224 }
225 225
226 // Record avatars movements.226 // Record avatars movements.
227 if (_recorder && _recorder->isRecording()) {227 if (_recorder && _recorder->isRecording()) {
228 _recorder->record();228 _recorder->record();
229 }229 }
230 230
231 // consider updating our billboard231 // consider updating our billboard
232 maybeUpdateBillboard();232 maybeUpdateBillboard();
233}233}
@@ -235,18 +235,18 @@ void MyAvatar::simulate(float deltaTime) { · 1 unmodified line
235// Update avatar head rotation with sensor data235// Update avatar head rotation with sensor data
236void MyAvatar::updateFromTrackers(float deltaTime) {236void MyAvatar::updateFromTrackers(float deltaTime) {
237 glm::vec3 estimatedPosition, estimatedRotation;237 glm::vec3 estimatedPosition, estimatedRotation;
238 238
239 bool inHmd = qApp->isHMDMode();239 bool inHmd = qApp->isHMDMode();
240 240
241 if (isPlaying() && inHmd) {241 if (isPlaying() && inHmd) {
242 return;242 return;
243 }243 }
244 244
245 if (inHmd) {245 if (inHmd) {
246 estimatedPosition = qApp->getHeadPosition(); 246 estimatedPosition = qApp->getHeadPosition();
247 estimatedPosition.x *= -1.0f;247 estimatedPosition.x *= -1.0f;
248 _trackedHeadPosition = estimatedPosition;248 _trackedHeadPosition = estimatedPosition;
249 249
250 const float OCULUS_LEAN_SCALE = 0.05f;250 const float OCULUS_LEAN_SCALE = 0.05f;
251 estimatedPosition /= OCULUS_LEAN_SCALE;251 estimatedPosition /= OCULUS_LEAN_SCALE;
252 } else {252 } else {
@@ -257,7 +257,7 @@ void MyAvatar::updateFromTrackers(float deltaTime) { · 4 unmodified lines
257 estimatedRotation = glm::degrees(safeEulerAngles(tracker->getHeadRotation()));257 estimatedRotation = glm::degrees(safeEulerAngles(tracker->getHeadRotation()));
258 }258 }
259 }259 }
260 260
261 // Rotate the body if the head is turned beyond the screen261 // Rotate the body if the head is turned beyond the screen
262 if (Menu::getInstance()->isOptionChecked(MenuOption::TurnWithHead)) {262 if (Menu::getInstance()->isOptionChecked(MenuOption::TurnWithHead)) {
263 const float TRACKER_YAW_TURN_SENSITIVITY = 0.5f;263 const float TRACKER_YAW_TURN_SENSITIVITY = 0.5f;
@@ -317,7 +317,7 @@ void MyAvatar::renderDebugBodyPoints() { · 53 unmodified lines
317 glm::vec3 headPosition(getHead()->getEyePosition());317 glm::vec3 headPosition(getHead()->getEyePosition());
318 float torsoToHead = glm::length(headPosition - torsoPosition);318 float torsoToHead = glm::length(headPosition - torsoPosition);
319 glm::vec3 position;319 glm::vec3 position;
320 qCDebug(interfaceapp, "head-above-torso %.2f, scale = %0.2f", torsoToHead, getScale());320 qCDebug(interfaceapp, "head-above-torso %.2f, scale = %0.2f", (double)torsoToHead, (double)getScale());
321 321
322 // Torso Sphere322 // Torso Sphere
323 position = torsoPosition;323 position = torsoPosition;
@@ -433,7 +433,7 @@ void MyAvatar::startRecording() { · 109 unmodified lines
433 auto audioClient = DependencyManager::get<AudioClient>();433 auto audioClient = DependencyManager::get<AudioClient>();
434 connect(audioClient.data(), &AudioClient::inputReceived, _recorder.data(),434 connect(audioClient.data(), &AudioClient::inputReceived, _recorder.data(),
435 &Recorder::recordAudio, Qt::BlockingQueuedConnection);435 &Recorder::recordAudio, Qt::BlockingQueuedConnection);
436 436
437 _recorder->startRecording();437 _recorder->startRecording();
438}438}
439 439
@@ -449,7 +449,7 @@ void MyAvatar::stopRecording() { · 9 unmodified lines
449 // stop grabbing audio from the AudioClient449 // stop grabbing audio from the AudioClient
450 auto audioClient = DependencyManager::get<AudioClient>();450 auto audioClient = DependencyManager::get<AudioClient>();
451 disconnect(audioClient.data(), 0, _recorder.data(), 0);451 disconnect(audioClient.data(), 0, _recorder.data(), 0);
452 452
453 _recorder->stopRecording();453 _recorder->stopRecording();
454 }454 }
455}455}
@@ -481,7 +481,7 @@ void MyAvatar::loadLastRecording() { · 25 unmodified lines
481 if (!_player) {481 if (!_player) {
482 _player = PlayerPointer(new Player(this));482 _player = PlayerPointer(new Player(this));
483 }483 }
484 484
485 _player->loadRecording(_recorder->getRecording());485 _player->loadRecording(_recorder->getRecording());
486}486}
487 487
@@ -573,7 +573,7 @@ AnimationDetails MyAvatar::getAnimationDetailsByRole(const QString& role) { · 85 unmodified lines
573 AnimationDetails result;573 AnimationDetails result;
574 if (QThread::currentThread() != thread()) {574 if (QThread::currentThread() != thread()) {
575 QMetaObject::invokeMethod(this, "getAnimationDetailsByRole", Qt::BlockingQueuedConnection,575 QMetaObject::invokeMethod(this, "getAnimationDetailsByRole", Qt::BlockingQueuedConnection,
576 Q_RETURN_ARG(AnimationDetails, result), 576 Q_RETURN_ARG(AnimationDetails, result),
577 Q_ARG(const QString&, role));577 Q_ARG(const QString&, role));
578 return result;578 return result;
579 }579 }
@@ -590,7 +590,7 @@ AnimationDetails MyAvatar::getAnimationDetails(const QString& url) { · 10 unmodified lines
590 AnimationDetails result;590 AnimationDetails result;
591 if (QThread::currentThread() != thread()) {591 if (QThread::currentThread() != thread()) {
592 QMetaObject::invokeMethod(this, "getAnimationDetails", Qt::BlockingQueuedConnection,592 QMetaObject::invokeMethod(this, "getAnimationDetails", Qt::BlockingQueuedConnection,
593 Q_RETURN_ARG(AnimationDetails, result), 593 Q_RETURN_ARG(AnimationDetails, result),
594 Q_ARG(const QString&, url));594 Q_ARG(const QString&, url));
595 return result;595 return result;
596 }596 }
@@ -638,7 +638,7 @@ void MyAvatar::saveData() { · 41 unmodified lines
638 settings.setValue("scale", attachment.scale);638 settings.setValue("scale", attachment.scale);
639 }639 }
640 settings.endArray();640 settings.endArray();
641 641
642 settings.beginWriteArray("animationHandles");642 settings.beginWriteArray("animationHandles");
643 for (int i = 0; i < _animationHandles.size(); i++) {643 for (int i = 0; i < _animationHandles.size(); i++) {
644 settings.setArrayIndex(i);644 settings.setArrayIndex(i);
@@ -655,7 +655,7 @@ void MyAvatar::saveData() { · 10 unmodified lines
655 settings.setValue("maskedJoints", pointer->getMaskedJoints());655 settings.setValue("maskedJoints", pointer->getMaskedJoints());
656 }656 }
657 settings.endArray();657 settings.endArray();
658 658
659 settings.setValue("displayName", _displayName);659 settings.setValue("displayName", _displayName);
660 660
661 settings.endGroup();661 settings.endGroup();
@@ -681,7 +681,7 @@ void MyAvatar::loadData() { · 19 unmodified lines
681 _targetScale = loadSetting(settings, "scale", 1.0f);681 _targetScale = loadSetting(settings, "scale", 1.0f);
682 setScale(_scale);682 setScale(_scale);
683 683
684 // The old preferences only stored the face and skeleton URLs, we didn't track if the user wanted to use 1 or 2 urls 684 // The old preferences only stored the face and skeleton URLs, we didn't track if the user wanted to use 1 or 2 urls
685 // for their avatar, So we need to attempt to detect this old case and set our new preferences accordingly. If685 // for their avatar, So we need to attempt to detect this old case and set our new preferences accordingly. If
686 // the head URL is empty, then we will assume they are using a full url...686 // the head URL is empty, then we will assume they are using a full url...
687 bool isOldSettings = !(settings.contains("useFullAvatar") || settings.contains("fullAvatarURL"));687 bool isOldSettings = !(settings.contains("useFullAvatar") || settings.contains("fullAvatarURL"));
@@ -693,7 +693,7 @@ void MyAvatar::loadData() { · 5 unmodified lines
693 _headModelName = settings.value("headModelName", DEFAULT_HEAD_MODEL_NAME).toString();693 _headModelName = settings.value("headModelName", DEFAULT_HEAD_MODEL_NAME).toString();
694 _bodyModelName = settings.value("bodyModelName", DEFAULT_BODY_MODEL_NAME).toString();694 _bodyModelName = settings.value("bodyModelName", DEFAULT_BODY_MODEL_NAME).toString();
695 _fullAvatarModelName = settings.value("fullAvatarModelName", DEFAULT_FULL_AVATAR_MODEL_NAME).toString();695 _fullAvatarModelName = settings.value("fullAvatarModelName", DEFAULT_FULL_AVATAR_MODEL_NAME).toString();
696 696
697 if (isOldSettings) {697 if (isOldSettings) {
698 bool assumeFullAvatar = _headURLFromPreferences.isEmpty();698 bool assumeFullAvatar = _headURLFromPreferences.isEmpty();
699 _useFullAvatar = assumeFullAvatar;699 _useFullAvatar = assumeFullAvatar;
@@ -719,14 +719,14 @@ void MyAvatar::loadData() { · 19 unmodified lines
719 QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString());719 QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString());
720 _bodyModelName = bodyFST["name"].toString();720 _bodyModelName = bodyFST["name"].toString();
721 }721 }
722 722
723 if (_headURLFromPreferences == DEFAULT_HEAD_MODEL_URL) {723 if (_headURLFromPreferences == DEFAULT_HEAD_MODEL_URL) {
724 _headModelName = DEFAULT_HEAD_MODEL_NAME;724 _headModelName = DEFAULT_HEAD_MODEL_NAME;
725 } else {725 } else {
726 QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString());726 QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString());
727 _headModelName = headFST["name"].toString();727 _headModelName = headFST["name"].toString();
728 }728 }
729 729
730 _fullAvatarModelName = "Default";730 _fullAvatarModelName = "Default";
731 }731 }
732 }732 }
@@ -736,7 +736,7 @@ void MyAvatar::loadData() { · 3 unmodified lines
736 } else {736 } else {
737 useHeadAndBodyURLs(_headURLFromPreferences, _skeletonURLFromPreferences, _headModelName, _bodyModelName);737 useHeadAndBodyURLs(_headURLFromPreferences, _skeletonURLFromPreferences, _headModelName, _bodyModelName);
738 }738 }
739 739
740 QVector<AttachmentData> attachmentData;740 QVector<AttachmentData> attachmentData;
741 int attachmentCount = settings.beginReadArray("attachmentData");741 int attachmentCount = settings.beginReadArray("attachmentData");
742 for (int i = 0; i < attachmentCount; i++) {742 for (int i = 0; i < attachmentCount; i++) {
@@ -757,7 +757,7 @@ void MyAvatar::loadData() { · 14 unmodified lines
757 }757 }
758 settings.endArray();758 settings.endArray();
759 setAttachmentData(attachmentData);759 setAttachmentData(attachmentData);
760 760
761 int animationCount = settings.beginReadArray("animationHandles");761 int animationCount = settings.beginReadArray("animationHandles");
762 while (_animationHandles.size() > animationCount) {762 while (_animationHandles.size() > animationCount) {
763 _animationHandles.takeLast()->stop();763 _animationHandles.takeLast()->stop();
@@ -780,7 +780,7 @@ void MyAvatar::loadData() { · 16 unmodified lines
780 handle->setStartAutomatically(settings.value("startAutomatically", true).toBool());780 handle->setStartAutomatically(settings.value("startAutomatically", true).toBool());
781 }781 }
782 settings.endArray();782 settings.endArray();
783 783
784 setDisplayName(settings.value("displayName").toString());784 setDisplayName(settings.value("displayName").toString());
785 785
786 settings.endGroup();786 settings.endGroup();
@@ -792,7 +792,7 @@ void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const { · 5 unmodified lines
792 settings.beginGroup(_skeletonModel.getURL().toString());792 settings.beginGroup(_skeletonModel.getURL().toString());
793 settings.beginGroup(attachment.modelURL.toString());793 settings.beginGroup(attachment.modelURL.toString());
794 settings.setValue("jointName", attachment.jointName);794 settings.setValue("jointName", attachment.jointName);
795 795
796 settings.beginGroup(attachment.jointName);796 settings.beginGroup(attachment.jointName);
797 settings.setValue("translation_x", attachment.translation.x);797 settings.setValue("translation_x", attachment.translation.x);
798 settings.setValue("translation_y", attachment.translation.y);798 settings.setValue("translation_y", attachment.translation.y);
@@ -802,7 +802,7 @@ void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const { · 3 unmodified lines
802 settings.setValue("rotation_y", eulers.y);802 settings.setValue("rotation_y", eulers.y);
803 settings.setValue("rotation_z", eulers.z);803 settings.setValue("rotation_z", eulers.z);
804 settings.setValue("scale", attachment.scale);804 settings.setValue("scale", attachment.scale);
805 805
806 settings.endGroup();806 settings.endGroup();
807 settings.endGroup();807 settings.endGroup();
808 settings.endGroup();808 settings.endGroup();
@@ -814,7 +814,7 @@ AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString& · 5 unmodified lines
814 settings.beginGroup("savedAttachmentData");814 settings.beginGroup("savedAttachmentData");
815 settings.beginGroup(_skeletonModel.getURL().toString());815 settings.beginGroup(_skeletonModel.getURL().toString());
816 settings.beginGroup(modelURL.toString());816 settings.beginGroup(modelURL.toString());
817 817
818 AttachmentData attachment;818 AttachmentData attachment;
819 attachment.modelURL = modelURL;819 attachment.modelURL = modelURL;
820 if (jointName.isEmpty()) {820 if (jointName.isEmpty()) {
@@ -836,18 +836,18 @@ AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString& · 15 unmodified lines
836 } else {836 } else {
837 attachment = AttachmentData();837 attachment = AttachmentData();
838 }838 }
839 839
840 settings.endGroup();840 settings.endGroup();
841 settings.endGroup();841 settings.endGroup();
842 settings.endGroup();842 settings.endGroup();
843 settings.endGroup();843 settings.endGroup();
844 844
845 return attachment;845 return attachment;
846}846}
847 847
848int MyAvatar::parseDataAtOffset(const QByteArray& packet, int offset) {848int MyAvatar::parseDataAtOffset(const QByteArray& packet, int offset) {
849 qCDebug(interfaceapp) << "Error: ignoring update packet for MyAvatar"849 qCDebug(interfaceapp) << "Error: ignoring update packet for MyAvatar"
850 << " packetLength = " << packet.size() 850 << " packetLength = " << packet.size()
851 << " offset = " << offset;851 << " offset = " << offset;
852 // this packet is just bad, so we pretend that we unpacked it ALL852 // this packet is just bad, so we pretend that we unpacked it ALL
853 return packet.size() - offset;853 return packet.size() - offset;
@@ -865,14 +865,14 @@ void MyAvatar::updateLookAtTargetAvatar() { · 11 unmodified lines
865 //865 //
866 _lookAtTargetAvatar.reset();866 _lookAtTargetAvatar.reset();
867 _targetAvatarPosition = glm::vec3(0.0f);867 _targetAvatarPosition = glm::vec3(0.0f);
868 868
869 glm::vec3 lookForward = getHead()->getFinalOrientationInWorldFrame() * IDENTITY_FRONT;869 glm::vec3 lookForward = getHead()->getFinalOrientationInWorldFrame() * IDENTITY_FRONT;
870 glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition();870 glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition();
871 871
872 float smallestAngleTo = glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES) / 2.0f;872 float smallestAngleTo = glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES) / 2.0f;
873 const float KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR = 1.3f;873 const float KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR = 1.3f;
874 const float GREATEST_LOOKING_AT_DISTANCE = 10.0f;874 const float GREATEST_LOOKING_AT_DISTANCE = 10.0f;
875 875
876 int howManyLookingAtMe = 0;876 int howManyLookingAtMe = 0;
877 foreach (const AvatarSharedPointer& avatarPointer, DependencyManager::get<AvatarManager>()->getAvatarHash()) {877 foreach (const AvatarSharedPointer& avatarPointer, DependencyManager::get<AvatarManager>()->getAvatarHash()) {
878 Avatar* avatar = static_cast<Avatar*>(avatarPointer.get());878 Avatar* avatar = static_cast<Avatar*>(avatarPointer.get());
@@ -1004,13 +1004,13 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN · 125 unmodified lines
1004 }1004 }
1005 1005
1006 _useFullAvatar = true;1006 _useFullAvatar = true;
1007 1007
1008 if (_fullAvatarURLFromPreferences != fullAvatarURL) {1008 if (_fullAvatarURLFromPreferences != fullAvatarURL) {
1009 _fullAvatarURLFromPreferences = fullAvatarURL;1009 _fullAvatarURLFromPreferences = fullAvatarURL;
1010 if (modelName.isEmpty()) {1010 if (modelName.isEmpty()) {
1011 QVariantHash fullAvatarFST = FSTReader::downloadMapping(_fullAvatarURLFromPreferences.toString());1011 QVariantHash fullAvatarFST = FSTReader::downloadMapping(_fullAvatarURLFromPreferences.toString());
1012 _fullAvatarModelName = fullAvatarFST["name"].toString();1012 _fullAvatarModelName = fullAvatarFST["name"].toString();
1013 } else { 1013 } else {
1014 _fullAvatarModelName = modelName;1014 _fullAvatarModelName = modelName;
1015 }1015 }
1016 }1016 }
@@ -1051,7 +1051,7 @@ void MyAvatar::useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, cons · 34 unmodified lines
1051 if (headName.isEmpty()) {1051 if (headName.isEmpty()) {
1052 QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString());1052 QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString());
1053 _headModelName = headFST["name"].toString();1053 _headModelName = headFST["name"].toString();
1054 } else { 1054 } else {
1055 _headModelName = headName;1055 _headModelName = headName;
1056 }1056 }
1057 }1057 }
@@ -1061,7 +1061,7 @@ void MyAvatar::useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, cons · 3 unmodified lines
1061 if (bodyName.isEmpty()) {1061 if (bodyName.isEmpty()) {
1062 QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString());1062 QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString());
1063 _bodyModelName = bodyFST["name"].toString();1063 _bodyModelName = bodyFST["name"].toString();
1064 } else { 1064 } else {
1065 _bodyModelName = bodyName;1065 _bodyModelName = bodyName;
1066 }1066 }
1067 }1067 }
@@ -1092,7 +1092,7 @@ void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) · 24 unmodified lines
1092glm::vec3 MyAvatar::getSkeletonPosition() const {1092glm::vec3 MyAvatar::getSkeletonPosition() const {
1093 CameraMode mode = Application::getInstance()->getCamera()->getMode();1093 CameraMode mode = Application::getInstance()->getCamera()->getMode();
1094 if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) {1094 if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) {
1095 // The avatar is rotated PI about the yAxis, so we have to correct for it 1095 // The avatar is rotated PI about the yAxis, so we have to correct for it
1096 // to get the skeleton offset contribution in the world-frame.1096 // to get the skeleton offset contribution in the world-frame.
1097 const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));1097 const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
1098 glm::vec3 skeletonOffset = _skeletonOffset;1098 glm::vec3 skeletonOffset = _skeletonOffset;
@@ -1135,9 +1135,9 @@ void MyAvatar::setScriptedMotorVelocity(const glm::vec3& velocity) { · 36 unmodified lines
1135}1135}
1136 1136
1137void MyAvatar::setScriptedMotorTimescale(float timescale) {1137void MyAvatar::setScriptedMotorTimescale(float timescale) {
1138 // we clamp the timescale on the large side (instead of just the low side) to prevent 1138 // we clamp the timescale on the large side (instead of just the low side) to prevent
1139 // obnoxiously large values from introducing NaN into avatar's velocity1139 // obnoxiously large values from introducing NaN into avatar's velocity
1140 _scriptedMotorTimescale = glm::clamp(timescale, MIN_SCRIPTED_MOTOR_TIMESCALE, 1140 _scriptedMotorTimescale = glm::clamp(timescale, MIN_SCRIPTED_MOTOR_TIMESCALE,
1141 DEFAULT_SCRIPTED_MOTOR_TIMESCALE);1141 DEFAULT_SCRIPTED_MOTOR_TIMESCALE);
1142}1142}
1143 1143
@@ -1155,14 +1155,14 @@ void MyAvatar::clearScriptableSettings() { · 11 unmodified lines
1155 clearJointAnimationPriorities();1155 clearJointAnimationPriorities();
1156 _scriptedMotorVelocity = glm::vec3(0.0f);1156 _scriptedMotorVelocity = glm::vec3(0.0f);
1157 _scriptedMotorTimescale = DEFAULT_SCRIPTED_MOTOR_TIMESCALE;1157 _scriptedMotorTimescale = DEFAULT_SCRIPTED_MOTOR_TIMESCALE;
1158} 1158}
1159 1159
1160void MyAvatar::attach(const QString& modelURL, const QString& jointName, const glm::vec3& translation,1160void MyAvatar::attach(const QString& modelURL, const QString& jointName, const glm::vec3& translation,
1161 const glm::quat& rotation, float scale, bool allowDuplicates, bool useSaved) {1161 const glm::quat& rotation, float scale, bool allowDuplicates, bool useSaved) {
1162 if (QThread::currentThread() != thread()) { 1162 if (QThread::currentThread() != thread()) {
1163 Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved);1163 Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved);
1164 return;1164 return;
1165 } 1165 }
1166 if (useSaved) {1166 if (useSaved) {
1167 AttachmentData attachment = loadAttachmentData(modelURL, jointName);1167 AttachmentData attachment = loadAttachmentData(modelURL, jointName);
1168 if (attachment.isValid()) {1168 if (attachment.isValid()) {
@@ -1199,7 +1199,7 @@ const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f; · 30 unmodified lines
1199 1199
1200bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const {1200bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const {
1201 const Head* head = getHead();1201 const Head* head = getHead();
1202 return (renderArgs->_renderMode != RenderArgs::NORMAL_RENDER_MODE) || (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON) || 1202 return (renderArgs->_renderMode != RenderArgs::NORMAL_RENDER_MODE) || (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON) ||
1203 (glm::length(cameraPosition - head->getEyePosition()) > RENDER_HEAD_CUTOFF_DISTANCE * _scale);1203 (glm::length(cameraPosition - head->getEyePosition()) > RENDER_HEAD_CUTOFF_DISTANCE * _scale);
1204}1204}
1205 1205
@@ -1230,10 +1230,10 @@ void MyAvatar::updateOrientation(float deltaTime) { · 24 unmodified lines
1230 1230
1231 //Invert yaw and roll when in mirror mode1231 //Invert yaw and roll when in mirror mode
1232 if (Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_MIRROR) {1232 if (Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_MIRROR) {
1233 YAW(euler) *= -1.0;1233 YAW(euler) *= -1.0f;
1234 ROLL(euler) *= -1.0;1234 ROLL(euler) *= -1.0f;
1235 }1235 }
1236 1236
1237 Head* head = getHead();1237 Head* head = getHead();
1238 head->setBaseYaw(YAW(euler));1238 head->setBaseYaw(YAW(euler));
1239 head->setBasePitch(PITCH(euler));1239 head->setBasePitch(PITCH(euler));
@@ -1246,9 +1246,9 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe · 6 unmodified lines
1246 return localVelocity;1246 return localVelocity;
1247 }1247 }
1248 // compute motor efficiency1248 // compute motor efficiency
1249 // The timescale of the motor is the approximate time it takes for the motor to 1249 // The timescale of the motor is the approximate time it takes for the motor to
1250 // accomplish its intended localVelocity. A short timescale makes the motor strong, 1250 // accomplish its intended localVelocity. A short timescale makes the motor strong,
1251 // and a long timescale makes it weak. The value of timescale to use depends 1251 // and a long timescale makes it weak. The value of timescale to use depends
1252 // on what the motor is doing:1252 // on what the motor is doing:
1253 //1253 //
1254 // (1) braking --> short timescale (aggressive motor assertion)1254 // (1) braking --> short timescale (aggressive motor assertion)
@@ -1259,8 +1259,8 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe · 4 unmodified lines
1259 float MIN_KEYBOARD_BRAKE_SPEED = 0.3f;1259 float MIN_KEYBOARD_BRAKE_SPEED = 0.3f;
1260 float timescale = MAX_KEYBOARD_MOTOR_TIMESCALE;1260 float timescale = MAX_KEYBOARD_MOTOR_TIMESCALE;
1261 bool isThrust = (glm::length2(_thrust) > EPSILON);1261 bool isThrust = (glm::length2(_thrust) > EPSILON);
1262 if (_isPushing || isThrust || 1262 if (_isPushing || isThrust ||
1263 (_scriptedMotorTimescale < MAX_KEYBOARD_MOTOR_TIMESCALE && 1263 (_scriptedMotorTimescale < MAX_KEYBOARD_MOTOR_TIMESCALE &&
1264 _motionBehaviors | AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED)) {1264 _motionBehaviors | AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED)) {
1265 // we don't want to brake if something is pushing the avatar around1265 // we don't want to brake if something is pushing the avatar around
1266 timescale = _keyboardMotorTimescale;1266 timescale = _keyboardMotorTimescale;
@@ -1277,18 +1277,18 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe · 10 unmodified lines
1277 float motorEfficiency = glm::clamp(deltaTime / timescale, 0.0f, 1.0f);1277 float motorEfficiency = glm::clamp(deltaTime / timescale, 0.0f, 1.0f);
1278 1278
1279 glm::vec3 newLocalVelocity = localVelocity;1279 glm::vec3 newLocalVelocity = localVelocity;
1280 float keyboardInput = fabsf(_driveKeys[FWD] - _driveKeys[BACK]) + 1280 float keyboardInput = fabsf(_driveKeys[FWD] - _driveKeys[BACK]) +
1281 (fabsf(_driveKeys[RIGHT] - _driveKeys[LEFT])) + 1281 (fabsf(_driveKeys[RIGHT] - _driveKeys[LEFT])) +
1282 fabsf(_driveKeys[UP] - _driveKeys[DOWN]);1282 fabsf(_driveKeys[UP] - _driveKeys[DOWN]);
1283 if (keyboardInput) {1283 if (keyboardInput) {
1284 // Compute keyboard input1284 // Compute keyboard input
1285 glm::vec3 front = (_driveKeys[FWD] - _driveKeys[BACK]) * IDENTITY_FRONT;1285 glm::vec3 front = (_driveKeys[FWD] - _driveKeys[BACK]) * IDENTITY_FRONT;
1286 glm::vec3 right = (_driveKeys[RIGHT] - _driveKeys[LEFT]) * IDENTITY_RIGHT;1286 glm::vec3 right = (_driveKeys[RIGHT] - _driveKeys[LEFT]) * IDENTITY_RIGHT;
1287 glm::vec3 up = (_driveKeys[UP] - _driveKeys[DOWN]) * IDENTITY_UP;1287 glm::vec3 up = (_driveKeys[UP] - _driveKeys[DOWN]) * IDENTITY_UP;
1288 1288
1289 glm::vec3 direction = front + right + up;1289 glm::vec3 direction = front + right + up;
1290 float directionLength = glm::length(direction);1290 float directionLength = glm::length(direction);
1291 1291
1292 // Compute motor magnitude1292 // Compute motor magnitude
1293 if (directionLength > EPSILON) {1293 if (directionLength > EPSILON) {
1294 direction /= directionLength;1294 direction /= directionLength;
@@ -1318,7 +1318,7 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe · 23 unmodified lines
1318 motorEfficiency = glm::clamp(deltaTime / WALK_ACCELERATION_TIMESCALE, 0.0f, 1.0f);1318 motorEfficiency = glm::clamp(deltaTime / WALK_ACCELERATION_TIMESCALE, 0.0f, 1.0f);
1319 }1319 }
1320 _isPushing = true;1320 _isPushing = true;
1321 } 1321 }
1322 newLocalVelocity = localVelocity + motorEfficiency * (_keyboardMotorVelocity - localVelocity);1322 newLocalVelocity = localVelocity + motorEfficiency * (_keyboardMotorVelocity - localVelocity);
1323 } else {1323 } else {
1324 _keyboardMotorVelocity = glm::vec3(0.0f);1324 _keyboardMotorVelocity = glm::vec3(0.0f);
@@ -1382,13 +1382,13 @@ void MyAvatar::updatePosition(float deltaTime) { · 57 unmodified lines
1382 _targetVelocity *= MAX_AVATAR_SPEED / speed;1382 _targetVelocity *= MAX_AVATAR_SPEED / speed;
1383 speed = MAX_AVATAR_SPEED;1383 speed = MAX_AVATAR_SPEED;
1384 }1384 }
1385 1385
1386 if (speed > MIN_AVATAR_SPEED && !_characterController.isEnabled()) {1386 if (speed > MIN_AVATAR_SPEED && !_characterController.isEnabled()) {
1387 // update position ourselves1387 // update position ourselves
1388 applyPositionDelta(deltaTime * _targetVelocity);1388 applyPositionDelta(deltaTime * _targetVelocity);
1389 measureMotionDerivatives(deltaTime);1389 measureMotionDerivatives(deltaTime);
1390 } // else physics will move avatar later1390 } // else physics will move avatar later
1391 1391
1392 // update _moving flag based on speed1392 // update _moving flag based on speed
1393 const float MOVING_SPEED_THRESHOLD = 0.01f;1393 const float MOVING_SPEED_THRESHOLD = 0.01f;
1394 _moving = speed > MOVING_SPEED_THRESHOLD;1394 _moving = speed > MOVING_SPEED_THRESHOLD;
@@ -1405,7 +1405,7 @@ bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float · 10 unmodified lines
1405 float xzDistance = sqrt(positionBA.x * positionBA.x + positionBA.z * positionBA.z);1405 float xzDistance = sqrt(positionBA.x * positionBA.x + positionBA.z * positionBA.z);
1406 if (xzDistance < (radiusA + radiusB)) {1406 if (xzDistance < (radiusA + radiusB)) {
1407 float yDistance = fabs(positionBA.y);1407 float yDistance = fabs(positionBA.y);
1408 float halfHeights = 0.5 * (heightA + heightB);1408 float halfHeights = 0.5f * (heightA + heightB);
1409 if (yDistance < halfHeights) {1409 if (yDistance < halfHeights) {
1410 // cylinders collide1410 // cylinders collide
1411 if (xzDistance > 0.0f) {1411 if (xzDistance > 0.0f) {
@@ -1448,60 +1448,60 @@ void MyAvatar::maybeUpdateBillboard() { · 36 unmodified lines
1448 }1448 }
1449 gpu::Context context(new gpu::GLBackend());1449 gpu::Context context(new gpu::GLBackend());
1450 RenderArgs renderArgs(&context);1450 RenderArgs renderArgs(&context);
1451 QImage image = Application::getInstance()->renderAvatarBillboard(&renderArgs);1451 QImage image = qApp->renderAvatarBillboard(&renderArgs);
1452 _billboard.clear();1452 _billboard.clear();
1453 QBuffer buffer(&_billboard);1453 QBuffer buffer(&_billboard);
1454 buffer.open(QIODevice::WriteOnly);1454 buffer.open(QIODevice::WriteOnly);
1455 image.save(&buffer, "PNG");1455 image.save(&buffer, "PNG");
1456 _billboardValid = true;1456 _billboardValid = true;
1457 1457
1458 sendBillboardPacket();1458 sendBillboardPacket();
1459}1459}
1460 1460
1461void MyAvatar::increaseSize() {1461void MyAvatar::increaseSize() {
1462 if ((1.0f + SCALING_RATIO) * _targetScale < MAX_AVATAR_SCALE) {1462 if ((1.0f + SCALING_RATIO) * _targetScale < MAX_AVATAR_SCALE) {
1463 _targetScale *= (1.0f + SCALING_RATIO);1463 _targetScale *= (1.0f + SCALING_RATIO);
1464 qCDebug(interfaceapp, "Changed scale to %f", _targetScale);1464 qCDebug(interfaceapp, "Changed scale to %f", (double)_targetScale);
1465 }1465 }
1466}1466}
1467 1467
1468void MyAvatar::decreaseSize() {1468void MyAvatar::decreaseSize() {
1469 if (MIN_AVATAR_SCALE < (1.0f - SCALING_RATIO) * _targetScale) {1469 if (MIN_AVATAR_SCALE < (1.0f - SCALING_RATIO) * _targetScale) {
1470 _targetScale *= (1.0f - SCALING_RATIO);1470 _targetScale *= (1.0f - SCALING_RATIO);
1471 qCDebug(interfaceapp, "Changed scale to %f", _targetScale);1471 qCDebug(interfaceapp, "Changed scale to %f", (double)_targetScale);
1472 }1472 }
1473}1473}
1474 1474
1475void MyAvatar::resetSize() {1475void MyAvatar::resetSize() {
1476 _targetScale = 1.0f;1476 _targetScale = 1.0f;
1477 qCDebug(interfaceapp, "Reseted scale to %f", _targetScale);1477 qCDebug(interfaceapp, "Reseted scale to %f", (double)_targetScale);
1478}1478}
1479 1479
1480void MyAvatar::goToLocation(const glm::vec3& newPosition,1480void MyAvatar::goToLocation(const glm::vec3& newPosition,
1481 bool hasOrientation, const glm::quat& newOrientation,1481 bool hasOrientation, const glm::quat& newOrientation,
1482 bool shouldFaceLocation) {1482 bool shouldFaceLocation) {
1483 1483
1484 qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - moving to " << newPosition.x << ", "1484 qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - moving to " << newPosition.x << ", "
1485 << newPosition.y << ", " << newPosition.z;1485 << newPosition.y << ", " << newPosition.z;
1486 1486
1487 glm::vec3 shiftedPosition = newPosition;1487 glm::vec3 shiftedPosition = newPosition;
1488 1488
1489 if (hasOrientation) {1489 if (hasOrientation) {
1490 qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - new orientation is "1490 qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - new orientation is "
1491 << newOrientation.x << ", " << newOrientation.y << ", " << newOrientation.z << ", " << newOrientation.w;1491 << newOrientation.x << ", " << newOrientation.y << ", " << newOrientation.z << ", " << newOrientation.w;
1492 1492
1493 // orient the user to face the target1493 // orient the user to face the target
1494 glm::quat quatOrientation = newOrientation;1494 glm::quat quatOrientation = newOrientation;
1495 1495
1496 if (shouldFaceLocation) {1496 if (shouldFaceLocation) {
1497 1497
1498 quatOrientation = newOrientation * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));1498 quatOrientation = newOrientation * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
1499 1499
1500 // move the user a couple units away1500 // move the user a couple units away
1501 const float DISTANCE_TO_USER = 2.0f;1501 const float DISTANCE_TO_USER = 2.0f;
1502 shiftedPosition = newPosition - quatOrientation * IDENTITY_FRONT * DISTANCE_TO_USER;1502 shiftedPosition = newPosition - quatOrientation * IDENTITY_FRONT * DISTANCE_TO_USER;
1503 }1503 }
1504 1504
1505 setOrientation(quatOrientation);1505 setOrientation(quatOrientation);
1506 }1506 }
1507 1507
@@ -1547,7 +1547,6 @@ void MyAvatar::renderLaserPointers() { · 39 unmodified lines
1547 1547
1548//Gets the tip position for the laser pointer1548//Gets the tip position for the laser pointer
1549glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) {1549glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) {
1550 const ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay();
1551 glm::vec3 direction = glm::normalize(palm->getTipPosition() - palm->getPosition());1550 glm::vec3 direction = glm::normalize(palm->getTipPosition() - palm->getPosition());
1552 1551
1553 glm::vec3 position = palm->getPosition();1552 glm::vec3 position = palm->getPosition();
@@ -1556,7 +1555,8 @@ glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) { · 2 unmodified lines
1556 1555
1557 1556
1558 glm::vec3 result;1557 glm::vec3 result;
1559 if (applicationOverlay.calculateRayUICollisionPoint(position, direction, result)) {1558 const auto& compositor = qApp->getApplicationCompositor();
1559 if (compositor.calculateRayUICollisionPoint(position, direction, result)) {
1560 return result;1560 return result;
1561 }1561 }
1562 1562
@@ -1569,8 +1569,8 @@ void MyAvatar::clearDriveKeys() { · 6 unmodified lines
1569 }1569 }
1570}1570}
1571 1571
1572void MyAvatar::relayDriveKeysToCharacterController() { 1572void MyAvatar::relayDriveKeysToCharacterController() {
1573 if (_driveKeys[UP] > 0.0f) {1573 if (_driveKeys[UP] > 0.0f) {
1574 _characterController.jump(); 1574 _characterController.jump();
1575 }1575 }
1576}1576}
interface/src/avatar/MyAvatar.h+1−1
@@ -90,7 +90,7 @@ public: · 89 unmodified lines
90 90
91 void relayDriveKeysToCharacterController();91 void relayDriveKeysToCharacterController();
92 92
93 bool isMyAvatar() { return true; }93 bool isMyAvatar() const { return true; }
94 94
95 bool isLookingAtLeftEye();95 bool isLookingAtLeftEye();
96 96
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
23CameraToolBox::CameraToolBox() :
24 _iconPulseTimeReference(usecTimestampNow()),
25 _doubleClickTimer(NULL)
26{
27}
28
29CameraToolBox::~CameraToolBox() {
30 if (_doubleClickTimer) {
31 _doubleClickTimer->stop();
32 delete _doubleClickTimer;
33 }
34}
35
36bool 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
52bool 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
65void CameraToolBox::toggleMute() {
66 delete _doubleClickTimer;
67 _doubleClickTimer = NULL;
68
69 FaceTracker* faceTracker = Application::getInstance()->getSelectedFaceTracker();
70 if (faceTracker) {
71 faceTracker->toggleMute();
72 }
73}
74
75void 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
20class CameraToolBox : public QObject, public Dependency {
21 Q_OBJECT
22 SINGLETON_DEPENDENCY
23
24public:
25 void render(int x, int y, bool boxed);
26 bool mousePressEvent(int x, int y);
27 bool mouseDoublePressEvent(int x, int y);
28
29protected:
30 CameraToolBox();
31 ~CameraToolBox();
32
33private slots:
34 void toggleMute();
35
36private:
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
415 float browUp = _coefficients[_browUpCenterIndex];415 float browUp = _coefficients[_browUpCenterIndex];
416 if (isFiltering) {416 if (isFiltering) {
417 const float BROW_VELOCITY_FILTER_STRENGTH = 0.5f;417 const float BROW_VELOCITY_FILTER_STRENGTH = 0.5f;
418 float velocity = fabs(browUp - _lastBrowUp) / _averageMessageTime;418 float velocity = fabsf(browUp - _lastBrowUp) / _averageMessageTime;
419 float velocityFilter = glm::clamp(velocity * BROW_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f);419 float velocityFilter = glm::clamp(velocity * BROW_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f);
420 _filteredBrowUp = velocityFilter * browUp + (1.0f - velocityFilter) * _filteredBrowUp;420 _filteredBrowUp = velocityFilter * browUp + (1.0f - velocityFilter) * _filteredBrowUp;
421 _lastBrowUp = browUp;421 _lastBrowUp = browUp;
@@ -438,11 +438,12 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { · 16 unmodified lines
438 438
439 // Velocity filter EyeBlink values439 // Velocity filter EyeBlink values
440 const float DDE_EYEBLINK_SCALE = 3.0f;440 const float DDE_EYEBLINK_SCALE = 3.0f;
441 float eyeBlinks[] = { DDE_EYEBLINK_SCALE * _coefficients[_leftBlinkIndex], DDE_EYEBLINK_SCALE * _coefficients[_rightBlinkIndex] };441 float eyeBlinks[] = { DDE_EYEBLINK_SCALE * _coefficients[_leftBlinkIndex],
442 DDE_EYEBLINK_SCALE * _coefficients[_rightBlinkIndex] };
442 if (isFiltering) {443 if (isFiltering) {
443 const float BLINK_VELOCITY_FILTER_STRENGTH = 0.3f;444 const float BLINK_VELOCITY_FILTER_STRENGTH = 0.3f;
444 for (int i = 0; i < 2; i++) {445 for (int i = 0; i < 2; i++) {
445 float velocity = fabs(eyeBlinks[i] - _lastEyeBlinks[i]) / _averageMessageTime;446 float velocity = fabsf(eyeBlinks[i] - _lastEyeBlinks[i]) / _averageMessageTime;
446 float velocityFilter = glm::clamp(velocity * BLINK_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f);447 float velocityFilter = glm::clamp(velocity * BLINK_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f);
447 _filteredEyeBlinks[i] = velocityFilter * eyeBlinks[i] + (1.0f - velocityFilter) * _filteredEyeBlinks[i];448 _filteredEyeBlinks[i] = velocityFilter * eyeBlinks[i] + (1.0f - velocityFilter) * _filteredEyeBlinks[i];
448 _lastEyeBlinks[i] = eyeBlinks[i];449 _lastEyeBlinks[i] = eyeBlinks[i];
@@ -479,9 +480,9 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { · 30 unmodified lines
479 if (_eyeStates[i] == EYE_CLOSING) {480 if (_eyeStates[i] == EYE_CLOSING) {
480 // Close eyelid until it's fully closed481 // Close eyelid until it's fully closed
481 float closingValue = _lastEyeCoefficients[i] + EYELID_MOVEMENT_RATE * _averageMessageTime;482 float closingValue = _lastEyeCoefficients[i] + EYELID_MOVEMENT_RATE * _averageMessageTime;
482 if (closingValue >= 1.0) {483 if (closingValue >= 1.0f) {
483 _eyeStates[i] = EYE_CLOSED;484 _eyeStates[i] = EYE_CLOSED;
484 eyeCoefficients[i] = 1.0;485 eyeCoefficients[i] = 1.0f;
485 } else {486 } else {
486 eyeCoefficients[i] = closingValue;487 eyeCoefficients[i] = closingValue;
487 }488 }
interface/src/devices/OculusManager.cpp+469−436
@@ -11,13 +11,13 @@ · 10 unmodified lines
11//11//
12 12
13#include "InterfaceConfig.h"13#include "InterfaceConfig.h"
14
15#include "OculusManager.h"14#include "OculusManager.h"
16#include "ui/overlays/Text3DOverlay.h"15#include "ui/overlays/Text3DOverlay.h"
17 16
17#include <CursorManager.h>
18#include <QDesktopWidget>18#include <QDesktopWidget>
19#include <QGuiApplication>19#include <QGuiApplication>
20#include <QScreen> 20#include <QScreen>
21#include <QOpenGLTimerQuery>21#include <QOpenGLTimerQuery>
22 22
23#include <glm/glm.hpp>23#include <glm/glm.hpp>
@@ -25,6 +25,9 @@ · 1 unmodified line
25#include <avatar/AvatarManager.h>25#include <avatar/AvatarManager.h>
26#include <avatar/MyAvatar.h>26#include <avatar/MyAvatar.h>
27#include <GlowEffect.h>27#include <GlowEffect.h>
28#include <GlWindow.h>
29#include <gpu/GLBackend.h>
30#include <OglplusHelpers.h>
28#include <PathUtils.h>31#include <PathUtils.h>
29#include <SharedUtil.h>32#include <SharedUtil.h>
30#include <UserActivityLogger.h>33#include <UserActivityLogger.h>
@@ -34,8 +37,6 @@ · 3 unmodified lines
34#include "InterfaceLogging.h"37#include "InterfaceLogging.h"
35#include "Application.h"38#include "Application.h"
36 39
37#include <gpu/GLBackend.h>
38
39template <typename Function>40template <typename Function>
40void for_each_eye(Function function) {41void for_each_eye(Function function) {
41 for (ovrEyeType eye = ovrEyeType::ovrEye_Left;42 for (ovrEyeType eye = ovrEyeType::ovrEye_Left;
@@ -52,202 +53,413 @@ void for_each_eye(const ovrHmd & hmd, Function function) { · 10 unmodified lines
52 function(eye);53 function(eye);
53 }54 }
54}55}
56enum CalibrationState {
57 UNCALIBRATED,
58 WAITING_FOR_DELTA,
59 WAITING_FOR_ZERO,
60 WAITING_FOR_ZERO_HELD,
61 CALIBRATED
62};
63
64inline glm::mat4 toGlm(const ovrMatrix4f & om) {
65 return glm::transpose(glm::make_mat4(&om.M[0][0]));
66}
55 67
56#ifdef OVR_CLIENT_DISTORTION68inline glm::mat4 toGlm(const ovrFovPort & fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) {
57ProgramObject OculusManager::_program;69 return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true));
58int OculusManager::_textureLocation;70}
59int OculusManager::_eyeToSourceUVScaleLocation;
60int OculusManager::_eyeToSourceUVOffsetLocation;
61int OculusManager::_eyeRotationStartLocation;
62int OculusManager::_eyeRotationEndLocation;
63int OculusManager::_positionAttributeLocation;
64int OculusManager::_colorAttributeLocation;
65int OculusManager::_texCoord0AttributeLocation;
66int OculusManager::_texCoord1AttributeLocation;
67int OculusManager::_texCoord2AttributeLocation;
68ovrVector2f OculusManager::_UVScaleOffset[ovrEye_Count][2];
69GLuint OculusManager::_vertices[ovrEye_Count] = { 0, 0 };
70GLuint OculusManager::_indices[ovrEye_Count] = { 0, 0 };
71GLsizei OculusManager::_meshSize[ovrEye_Count] = { 0, 0 };
72ovrFrameTiming OculusManager::_hmdFrameTiming;
73bool OculusManager::_programInitialized = false;
74#endif
75 71
76ovrTexture OculusManager::_eyeTextures[ovrEye_Count];72inline glm::vec3 toGlm(const ovrVector3f & ov) {
77bool OculusManager::_isConnected = false;73 return glm::make_vec3(&ov.x);
78ovrHmd OculusManager::_ovrHmd;74}
79ovrFovPort OculusManager::_eyeFov[ovrEye_Count];
80ovrVector3f OculusManager::_eyeOffset[ovrEye_Count];
81ovrEyeRenderDesc OculusManager::_eyeRenderDesc[ovrEye_Count];
82ovrSizei OculusManager::_renderTargetSize;
83glm::mat4 OculusManager::_eyeProjection[ovrEye_Count];
84unsigned int OculusManager::_frameIndex = 0;
85bool OculusManager::_frameTimingActive = false;
86Camera* OculusManager::_camera = NULL;
87ovrEyeType OculusManager::_activeEye = ovrEye_Count;
88bool OculusManager::_hswDismissed = false;
89
90float OculusManager::CALIBRATION_DELTA_MINIMUM_LENGTH = 0.02f;
91float OculusManager::CALIBRATION_DELTA_MINIMUM_ANGLE = 5.0f * RADIANS_PER_DEGREE;
92float OculusManager::CALIBRATION_ZERO_MAXIMUM_LENGTH = 0.01f;
93float OculusManager::CALIBRATION_ZERO_MAXIMUM_ANGLE = 2.0f * RADIANS_PER_DEGREE;
94quint64 OculusManager::CALIBRATION_ZERO_HOLD_TIME = 3000000; // usec
95float OculusManager::CALIBRATION_MESSAGE_DISTANCE = 2.5f;
96OculusManager::CalibrationState OculusManager::_calibrationState;
97glm::vec3 OculusManager::_calibrationPosition;
98glm::quat OculusManager::_calibrationOrientation;
99quint64 OculusManager::_calibrationStartTime;
100int OculusManager::_calibrationMessage = 0;
101glm::vec3 OculusManager::_eyePositions[ovrEye_Count];
102// TODO expose this as a developer toggle
103bool OculusManager::_eyePerFrameMode = false;
104ovrEyeType OculusManager::_lastEyeRendered = ovrEye_Count;
105ovrSizei OculusManager::_recommendedTexSize = { 0, 0 };
106float OculusManager::_offscreenRenderScale = 1.0;
107 75
76inline glm::vec2 toGlm(const ovrVector2f & ov) {
77 return glm::make_vec2(&ov.x);
78}
108 79
109void OculusManager::initSdk() {80inline glm::ivec2 toGlm(const ovrVector2i & ov) {
110 ovr_Initialize();81 return glm::ivec2(ov.x, ov.y);
111 _ovrHmd = ovrHmd_Create(0);
112 if (!_ovrHmd) {
113 _ovrHmd = ovrHmd_CreateDebug(ovrHmd_DK2);
114 }
115}82}
116 83
117void OculusManager::shutdownSdk() {84inline glm::uvec2 toGlm(const ovrSizei & ov) {
118 if (_ovrHmd) {85 return glm::uvec2(ov.w, ov.h);
119 ovrHmd_Destroy(_ovrHmd);
120 _ovrHmd = nullptr;
121 ovr_Shutdown();
122 }
123}86}
124 87
125void OculusManager::init() {88inline glm::quat toGlm(const ovrQuatf & oq) {
126#ifdef OVR_DIRECT_MODE89 return glm::make_quat(&oq.x);
127 initSdk();
128#endif
129}90}
130 91
131void OculusManager::deinit() {92inline glm::mat4 toGlm(const ovrPosef & op) {
132#ifdef OVR_DIRECT_MODE93 glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation));
133 shutdownSdk();94 glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position));
134#endif95 return translation * orientation;
135}96}
136 97
137void OculusManager::connect() {98inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) {
138#ifndef OVR_DIRECT_MODE99 ovrMatrix4f result;
139 initSdk();100 glm::mat4 transposed(glm::transpose(m));
140#endif101 memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16);
141 _calibrationState = UNCALIBRATED;102 return result;
142 qCDebug(interfaceapp) << "Oculus SDK" << OVR_VERSION_STRING;103}
143 if (_ovrHmd) {104
144 if (!_isConnected) {105inline ovrVector3f ovrFromGlm(const glm::vec3 & v) {
145 UserActivityLogger::getInstance().connectedDevice("hmd", "oculus");106 return{ v.x, v.y, v.z };
107}
108
109inline ovrVector2f ovrFromGlm(const glm::vec2 & v) {
110 return{ v.x, v.y };
111}
112
113inline ovrSizei ovrFromGlm(const glm::uvec2 & v) {
114 return{ (int)v.x, (int)v.y };
115}
116
117inline 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
128template <typename C>
129struct 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
145protected:
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
155struct SwapFramebufferWrapper : public RiftFramebufferWrapper<ovrSwapTextureSet*> {
156 SwapFramebufferWrapper(const ovrHmd & hmd)
157 : RiftFramebufferWrapper(hmd) {
158 }
159
160 ~SwapFramebufferWrapper() {
161 if (color) {
162 ovrHmd_DestroySwapTextureSet(hmd, color);
163 color = nullptr;
146 }164 }
147 _isConnected = true;165 }
148 166
149 for_each_eye([&](ovrEyeType eye) {167 void Increment() {
150 _eyeFov[eye] = _ovrHmd->DefaultEyeFov[eye];168 ++color->CurrentIndex;
151 });169 color->CurrentIndex %= color->TextureCount;
152 170 }
153 ovrGLConfig cfg;171
154 memset(&cfg, 0, sizeof(cfg));172protected:
155 cfg.OGL.Header.API = ovrRenderAPI_OpenGL;173 virtual void initColor() override {
156 cfg.OGL.Header.BackBufferSize = _ovrHmd->Resolution;174 if (color) {
157 cfg.OGL.Header.Multisample = 1;175 ovrHmd_DestroySwapTextureSet(hmd, color);
158 176 color = nullptr;
159 int distortionCaps = 0177 }
160 | ovrDistortionCap_Vignette178
161 | ovrDistortionCap_Overdrive179 ovrResult result = ovrHmd_CreateSwapTextureSetGL(hmd, GL_RGBA, size.x, size.y, &color);
162 | ovrDistortionCap_TimeWarp;180 Q_ASSERT(OVR_SUCCESS(result));
163 181
164 int configResult = ovrHmd_ConfigureRendering(_ovrHmd, &cfg.Config,182 for (int i = 0; i < color->TextureCount; ++i) {
165 distortionCaps, _eyeFov, _eyeRenderDesc);183 ovrGLTexture& ovrTex = (ovrGLTexture&)color->Textures[i];
166 assert(configResult);184 glBindTexture(GL_TEXTURE_2D, ovrTex.OGL.TexId);
167 185 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
168 186 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
169 _recommendedTexSize = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left, _eyeFov[ovrEye_Left], 1.0f);187 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
170 _renderTargetSize = { _recommendedTexSize.w * 2, _recommendedTexSize.h };188 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
171 for_each_eye([&](ovrEyeType eye) {189 }
172 //Get texture size190 glBindTexture(GL_TEXTURE_2D, 0);
173 _eyeTextures[eye].Header.API = ovrRenderAPI_OpenGL;191 }
174 _eyeTextures[eye].Header.TextureSize = _renderTargetSize;192
175 _eyeTextures[eye].Header.RenderViewport.Pos = { 0, 0 };193 virtual void initDone() override {
176 });194 }
177 _eyeTextures[ovrEye_Right].Header.RenderViewport.Pos.x = _recommendedTexSize.w;195
178 196 virtual void onBind(oglplus::Framebuffer::Target target) override {
179 ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction);197 ovrGLTexture& tex = (ovrGLTexture&)(color->Textures[color->CurrentIndex]);
180 198 glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.OGL.TexId, 0);
181 ovrHmd_ConfigureTracking(_ovrHmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position |199 }
182 ovrTrackingCap_MagYawCorrection,200
183 ovrTrackingCap_Orientation);201 virtual void onUnbind(oglplus::Framebuffer::Target target) override {
184 202 glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
185 if (!_camera) {203 }
186 _camera = new Camera;204};
187 configureCamera(*_camera); // no need to use screen dimensions; they're ignored205
206
207// We use a FBO to wrap the mirror texture because it makes it easier to
208// render to the screen via glBlitFramebuffer
209struct MirrorFramebufferWrapper : public RiftFramebufferWrapper<ovrGLTexture*> {
210 MirrorFramebufferWrapper(const ovrHmd & hmd)
211 : RiftFramebufferWrapper(hmd) {
212 }
213
214 virtual ~MirrorFramebufferWrapper() {
215 if (color) {
216 ovrHmd_DestroyMirrorTexture(hmd, (ovrTexture*)color);
217 color = nullptr;
188 }218 }
189#ifdef OVR_CLIENT_DISTORTION219 }
190 if (!_programInitialized) {220
191 // Shader program221private:
192 _programInitialized = true;222 void initColor() override {
193 _program.addShaderFromSourceFile(QGLShader::Vertex, PathUtils::resourcesPath() + "shaders/oculus.vert");223 if (color) {
194 _program.addShaderFromSourceFile(QGLShader::Fragment, PathUtils::resourcesPath() + "shaders/oculus.frag");224 ovrHmd_DestroyMirrorTexture(hmd, (ovrTexture*)color);
195 _program.link();225 color = nullptr;
196
197 // Uniforms
198 _textureLocation = _program.uniformLocation("texture");
199 _eyeToSourceUVScaleLocation = _program.uniformLocation("EyeToSourceUVScale");
200 _eyeToSourceUVOffsetLocation = _program.uniformLocation("EyeToSourceUVOffset");
201 _eyeRotationStartLocation = _program.uniformLocation("EyeRotationStart");
202 _eyeRotationEndLocation = _program.uniformLocation("EyeRotationEnd");
203
204 // Attributes
205 _positionAttributeLocation = _program.attributeLocation("position");
206 _colorAttributeLocation = _program.attributeLocation("color");
207 _texCoord0AttributeLocation = _program.attributeLocation("texCoord0");
208 _texCoord1AttributeLocation = _program.attributeLocation("texCoord1");
209 _texCoord2AttributeLocation = _program.attributeLocation("texCoord2");
210 }226 }
227 ovrResult result = ovrHmd_CreateMirrorTextureGL(hmd, GL_RGBA, size.x, size.y, (ovrTexture**)&color);
228 Q_ASSERT(OVR_SUCCESS(result));
229 }
230
231 void initDone() override {
232 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oglplus::GetName(fbo));
233 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color->OGL.TexId, 0);
234 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
235 }
236};
237
238static SwapFramebufferWrapper* _swapFbo{ nullptr };
239static MirrorFramebufferWrapper* _mirrorFbo{ nullptr };
240static ovrLayerEyeFov _sceneLayer;
241
242#else
243
244static ovrTexture _eyeTextures[ovrEye_Count];
245static GlWindow* _outputWindow{ nullptr };
211 246
212 //Generate the distortion VBOs
213 generateDistortionMesh();
214#endif247#endif
215 } else {248
249static bool _isConnected = false;
250static ovrHmd _ovrHmd;
251static ovrFovPort _eyeFov[ovrEye_Count];
252static ovrVector3f _eyeOffset[ovrEye_Count];
253static ovrEyeRenderDesc _eyeRenderDesc[ovrEye_Count];
254static ovrSizei _renderTargetSize;
255static glm::mat4 _eyeProjection[ovrEye_Count];
256static unsigned int _frameIndex = 0;
257static bool _frameTimingActive = false;
258static Camera* _camera = NULL;
259static ovrEyeType _activeEye = ovrEye_Count;
260static bool _hswDismissed = false;
261
262static const float CALIBRATION_DELTA_MINIMUM_LENGTH = 0.02f;
263static const float CALIBRATION_DELTA_MINIMUM_ANGLE = 5.0f * RADIANS_PER_DEGREE;
264static const float CALIBRATION_ZERO_MAXIMUM_LENGTH = 0.01f;
265static const float CALIBRATION_ZERO_MAXIMUM_ANGLE = 2.0f * RADIANS_PER_DEGREE;
266static const quint64 CALIBRATION_ZERO_HOLD_TIME = 3000000; // usec
267static const float CALIBRATION_MESSAGE_DISTANCE = 2.5f;
268static CalibrationState _calibrationState;
269static glm::vec3 _calibrationPosition;
270static glm::quat _calibrationOrientation;
271static quint64 _calibrationStartTime;
272static int _calibrationMessage = 0;
273static glm::vec3 _eyePositions[ovrEye_Count];
274// TODO expose this as a developer toggle
275static bool _eyePerFrameMode = false;
276static ovrEyeType _lastEyeRendered = ovrEye_Count;
277static ovrSizei _recommendedTexSize = { 0, 0 };
278static float _offscreenRenderScale = 1.0;
279static glm::mat4 _combinedProjection;
280static ovrPosef _eyeRenderPoses[ovrEye_Count];
281static ovrRecti _eyeViewports[ovrEye_Count];
282static ovrVector3f _eyeOffsets[ovrEye_Count];
283
284glm::vec3 OculusManager::getLeftEyePosition() { return _eyePositions[ovrEye_Left]; }
285glm::vec3 OculusManager::getRightEyePosition() { return _eyePositions[ovrEye_Right]; }
286
287void OculusManager::connect(QOpenGLContext* shareContext) {
288 qCDebug(interfaceapp) << "Oculus SDK" << OVR_VERSION_STRING;
289
290 ovrInitParams initParams; memset(&initParams, 0, sizeof(initParams));
291
292#ifdef DEBUG
293 initParams.Flags |= ovrInit_Debug;
294#endif
295
296 ovr_Initialize(&initParams);
297
298#ifdef Q_OS_WIN
299
300 ovrResult res = ovrHmd_Create(0, &_ovrHmd);
301#ifdef DEBUG
302 if (!OVR_SUCCESS(res)) {
303 res = ovrHmd_CreateDebug(ovrHmd_DK2, &_ovrHmd);
304 Q_ASSERT(OVR_SUCCESS(res));
305 }
306#endif
307
308#else
309
310 _ovrHmd = ovrHmd_Create(0);
311#ifdef DEBUG
312 if (!_ovrHmd) {
313 _ovrHmd = ovrHmd_CreateDebug(ovrHmd_DK2);
314 }
315#endif
316
317#endif
318
319 if (!_ovrHmd) {
216 _isConnected = false;320 _isConnected = false;
217 321
218 // we're definitely not in "VR mode" so tell the menu that322 // we're definitely not in "VR mode" so tell the menu that
219 Menu::getInstance()->getActionForOption(MenuOption::EnableVRMode)->setChecked(false);323 Menu::getInstance()->getActionForOption(MenuOption::EnableVRMode)->setChecked(false);
324 ovr_Shutdown();
325 return;
326 }
327
328 _calibrationState = UNCALIBRATED;
329 if (!_isConnected) {
330 UserActivityLogger::getInstance().connectedDevice("hmd", "oculus");
331 }
332 _isConnected = true;
333
334 for_each_eye([&](ovrEyeType eye) {
335 _eyeFov[eye] = _ovrHmd->DefaultEyeFov[eye];
336 _eyeProjection[eye] = toGlm(ovrMatrix4f_Projection(_eyeFov[eye],
337 DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded));
338 ovrEyeRenderDesc erd = ovrHmd_GetRenderDesc(_ovrHmd, eye, _eyeFov[eye]);
339 _eyeOffsets[eye] = erd.HmdToEyeViewOffset;
340 });
341 ovrFovPort combinedFov = _ovrHmd->MaxEyeFov[0];
342 combinedFov.RightTan = _ovrHmd->MaxEyeFov[1].RightTan;
343 _combinedProjection = toGlm(ovrMatrix4f_Projection(combinedFov,
344 DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded));
345
346 _recommendedTexSize = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left, _eyeFov[ovrEye_Left], 1.0f);
347 _renderTargetSize = { _recommendedTexSize.w * 2, _recommendedTexSize.h };
348
349#ifdef Q_OS_WIN
350
351 _mirrorFbo = new MirrorFramebufferWrapper(_ovrHmd);
352 _swapFbo = new SwapFramebufferWrapper(_ovrHmd);
353 _swapFbo->Init(toGlm(_renderTargetSize));
354 _sceneLayer.ColorTexture[0] = _swapFbo->color;
355 _sceneLayer.ColorTexture[1] = nullptr;
356 _sceneLayer.Viewport[0].Pos = { 0, 0 };
357 _sceneLayer.Viewport[0].Size = _recommendedTexSize;
358 _sceneLayer.Viewport[1].Pos = { _recommendedTexSize.w, 0 };
359 _sceneLayer.Viewport[1].Size = _recommendedTexSize;
360 _sceneLayer.Header.Type = ovrLayerType_EyeFov;
361 _sceneLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft;
362 for_each_eye([&](ovrEyeType eye) {
363 _eyeViewports[eye] = _sceneLayer.Viewport[eye];
364 _sceneLayer.Fov[eye] = _eyeFov[eye];
365 });
366
367
368
369#else
370 _outputWindow = new GlWindow(shareContext);
371 _outputWindow->show();
372// _outputWindow->setFlags(Qt::FramelessWindowHint );
373// _outputWindow->resize(_ovrHmd->Resolution.w, _ovrHmd->Resolution.h);
374// _outputWindow->setPosition(_ovrHmd->WindowsPos.x, _ovrHmd->WindowsPos.y);
375 ivec2 desiredPosition = toGlm(_ovrHmd->WindowsPos);
376 foreach(QScreen* screen, qGuiApp->screens()) {
377 ivec2 screenPosition = toGlm(screen->geometry().topLeft());
378 if (screenPosition == desiredPosition) {
379 _outputWindow->setScreen(screen);
380 break;
381 }
382 }
383 _outputWindow->showFullScreen();
384 _outputWindow->makeCurrent();
385
386 ovrGLConfig cfg;
387 memset(&cfg, 0, sizeof(cfg));
388 cfg.OGL.Header.API = ovrRenderAPI_OpenGL;
389 cfg.OGL.Header.BackBufferSize = _ovrHmd->Resolution;
390 cfg.OGL.Header.Multisample = 0;
391
392 int distortionCaps = 0
393 | ovrDistortionCap_Vignette
394 | ovrDistortionCap_Overdrive
395 | ovrDistortionCap_TimeWarp;
396
397 int configResult = ovrHmd_ConfigureRendering(_ovrHmd, &cfg.Config,
398 distortionCaps, _eyeFov, _eyeRenderDesc);
399 assert(configResult);
400 _outputWindow->doneCurrent();
401
402 for_each_eye([&](ovrEyeType eye) {
403 //Get texture size
404 _eyeTextures[eye].Header.API = ovrRenderAPI_OpenGL;
405 _eyeTextures[eye].Header.TextureSize = _renderTargetSize;
406 _eyeTextures[eye].Header.RenderViewport.Pos = { 0, 0 };
407 _eyeTextures[eye].Header.RenderViewport.Size = _renderTargetSize;
408 _eyeTextures[eye].Header.RenderViewport.Size.w /= 2;
409 });
410 _eyeTextures[ovrEye_Right].Header.RenderViewport.Pos.x = _recommendedTexSize.w;
411 for_each_eye([&](ovrEyeType eye) {
412 _eyeViewports[eye] = _eyeTextures[eye].Header.RenderViewport;
413 });
414#endif
415
416 ovrHmd_SetEnabledCaps(_ovrHmd,
417 ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction);
418
419 ovrHmd_ConfigureTracking(_ovrHmd,
420 ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection,
421 ovrTrackingCap_Orientation);
422
423 if (!_camera) {
424 _camera = new Camera;
425 configureCamera(*_camera); // no need to use screen dimensions; they're ignored
220 }426 }
221}427}
222 428
223//Disconnects and deallocates the OR429//Disconnects and deallocates the OR
224void OculusManager::disconnect() {430void OculusManager::disconnect() {
225 if (_isConnected) {431 if (_isConnected) {
432
433#ifdef Q_OS_WIN
434 if (_swapFbo) {
435 delete _swapFbo;
436 _swapFbo = nullptr;
437 }
438
439 if (_mirrorFbo) {
440 delete _mirrorFbo;
441 _mirrorFbo = nullptr;
442 }
443#else
444 _outputWindow->showNormal();
445 _outputWindow->deleteLater();
446 _outputWindow = nullptr;
447#endif
448
449 if (_ovrHmd) {
450 ovrHmd_Destroy(_ovrHmd);
451 _ovrHmd = nullptr;
452 }
453 ovr_Shutdown();
454
226 _isConnected = false;455 _isConnected = false;
227 // Prepare to potentially have to dismiss the HSW again456 // Prepare to potentially have to dismiss the HSW again
228 // if the user re-enables VR457 // if the user re-enables VR
229 _hswDismissed = false;458 _hswDismissed = false;
230#ifndef OVR_DIRECT_MODE
231 shutdownSdk();
232#endif
233
234#ifdef OVR_CLIENT_DISTORTION
235 //Free the distortion mesh data
236 for (int i = 0; i < ovrEye_Count; i++) {
237 if (_vertices[i] != 0) {
238 glDeleteBuffers(1, &(_vertices[i]));
239 _vertices[i] = 0;
240 }
241 if (_indices[i] != 0) {
242 glDeleteBuffers(1, &(_indices[i]));
243 _indices[i] = 0;
244 }
245 }
246#endif
247 }459 }
248}460}
249 461
250void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) {462void positionCalibrationBillboard(Text3DOverlay* billboard) {
251 MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();463 MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
252 glm::quat headOrientation = myAvatar->getHeadOrientation();464 glm::quat headOrientation = myAvatar->getHeadOrientation();
253 headOrientation.x = 0;465 headOrientation.x = 0;
@@ -258,7 +470,7 @@ void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) { · 4 unmodified lines
258 billboard->setRotation(headOrientation);470 billboard->setRotation(headOrientation);
259}471}
260 472
261void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) {473void calibrate(const glm::vec3& position, const glm::quat& orientation) {
262 static QString instructionMessage = "Hold still to calibrate";474 static QString instructionMessage = "Hold still to calibrate";
263 static QString progressMessage;475 static QString progressMessage;
264 static Text3DOverlay* billboard;476 static Text3DOverlay* billboard;
@@ -346,7 +558,7 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { · 81 unmodified lines
346 break;558 break;
347 default:559 default:
348 break;560 break;
349 561
350 }562 }
351}563}
352 564
@@ -363,64 +575,9 @@ void OculusManager::abandonCalibration() { · 10 unmodified lines
363 }575 }
364}576}
365 577
366#ifdef OVR_CLIENT_DISTORTION
367void OculusManager::generateDistortionMesh() {
368
369 //Check if we already have the distortion mesh
370 if (_vertices[0] != 0) {
371 printf("WARNING: Tried to generate Oculus distortion mesh twice without freeing the VBOs.");
372 return;
373 }
374
375 for (int eyeNum = 0; eyeNum < ovrEye_Count; eyeNum++) {
376 // Allocate and generate distortion mesh vertices
377 ovrDistortionMesh meshData;
378 ovrHmd_CreateDistortionMesh(_ovrHmd, _eyeRenderDesc[eyeNum].Eye, _eyeRenderDesc[eyeNum].Fov, _ovrHmd->DistortionCaps, &meshData);
379
380 // Parse the vertex data and create a render ready vertex buffer
381 DistortionVertex* pVBVerts = new DistortionVertex[meshData.VertexCount];
382 _meshSize[eyeNum] = meshData.IndexCount;
383
384 // Convert the oculus vertex data to the DistortionVertex format.
385 DistortionVertex* v = pVBVerts;
386 ovrDistortionVertex* ov = meshData.pVertexData;
387 for (unsigned int vertNum = 0; vertNum < meshData.VertexCount; vertNum++) {
388 v->pos.x = ov->ScreenPosNDC.x;
389 v->pos.y = ov->ScreenPosNDC.y;
390 v->texR.x = ov->TanEyeAnglesR.x;
391 v->texR.y = ov->TanEyeAnglesR.y;
392 v->texG.x = ov->TanEyeAnglesG.x;
393 v->texG.y = ov->TanEyeAnglesG.y;
394 v->texB.x = ov->TanEyeAnglesB.x;
395 v->texB.y = ov->TanEyeAnglesB.y;
396 v->color.r = v->color.g = v->color.b = (GLubyte)(ov->VignetteFactor * 255.99f);
397 v->color.a = (GLubyte)(ov->TimeWarpFactor * 255.99f);
398 v++;
399 ov++;
400 }
401
402 //vertices
403 glGenBuffers(1, &(_vertices[eyeNum]));
404 glBindBuffer(GL_ARRAY_BUFFER, _vertices[eyeNum]);
405 glBufferData(GL_ARRAY_BUFFER, sizeof(DistortionVertex) * meshData.VertexCount, pVBVerts, GL_STATIC_DRAW);
406 glBindBuffer(GL_ARRAY_BUFFER, 0);
407
408 //indices
409 glGenBuffers(1, &(_indices[eyeNum]));
410 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indices[eyeNum]);
411 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short) * meshData.IndexCount, meshData.pIndexData, GL_STATIC_DRAW);
412 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
413
414 //Now that we have the VBOs we can get rid of the mesh data
415 delete [] pVBVerts;
416 ovrHmd_DestroyDistortionMesh(&meshData);
417 }
418
419}
420#endif
421 578
422bool OculusManager::isConnected() {579bool OculusManager::isConnected() {
423 return _isConnected && Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode);580 return _isConnected;
424}581}
425 582
426//Begins the frame timing for oculus prediction purposes583//Begins the frame timing for oculus prediction purposes
@@ -428,10 +585,6 @@ void OculusManager::beginFrameTiming() { · 1 unmodified line
428 if (_frameTimingActive) {585 if (_frameTimingActive) {
429 printf("WARNING: Called OculusManager::beginFrameTiming() twice in a row, need to call OculusManager::endFrameTiming().");586 printf("WARNING: Called OculusManager::beginFrameTiming() twice in a row, need to call OculusManager::endFrameTiming().");
430 }587 }
431
432#ifdef OVR_CLIENT_DISTORTION
433 _hmdFrameTiming = ovrHmd_BeginFrameTiming(_ovrHmd, _frameIndex);
434#endif
435 _frameTimingActive = true;588 _frameTimingActive = true;
436}589}
437 590
@@ -441,27 +594,18 @@ bool OculusManager::allowSwap() { · 3 unmodified lines
441 594
442//Ends frame timing595//Ends frame timing
443void OculusManager::endFrameTiming() {596void OculusManager::endFrameTiming() {
444#ifdef OVR_CLIENT_DISTORTION
445 ovrHmd_EndFrameTiming(_ovrHmd);
446#endif
447 _frameIndex++;597 _frameIndex++;
448 _frameTimingActive = false;598 _frameTimingActive = false;
449}599}
450 600
451//Sets the camera FoV and aspect ratio601//Sets the camera FoV and aspect ratio
452void OculusManager::configureCamera(Camera& camera) {602void OculusManager::configureCamera(Camera& camera) {
453 ovrFovPort fov;
454 if (_activeEye == ovrEye_Count) {603 if (_activeEye == ovrEye_Count) {
455 // When not rendering, provide a FOV encompasing both eyes604 // When not rendering, provide a FOV encompasing both eyes
456 fov = _eyeFov[0];605 camera.setProjection(_combinedProjection);
457 fov.RightTan = _eyeFov[1].RightTan;606 return;
458 } else {607 }
459 // When rendering, provide the exact FOV608 camera.setProjection(_eyeProjection[_activeEye]);
460 fov = _eyeFov[_activeEye];
461 }
462 // Convert the FOV to the correct projection matrix
463 glm::mat4 projection = toGlm(ovrMatrix4f_Projection(fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded));
464 camera.setProjection(projection);
465}609}
466 610
467//Displays everything for the oculus, frame timing must be active611//Displays everything for the oculus, frame timing must be active
@@ -473,40 +617,9 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 5 unmodified lines
473 assert(oldFrameIndex == -1 || (unsigned int)oldFrameIndex == _frameIndex - 1);617 assert(oldFrameIndex == -1 || (unsigned int)oldFrameIndex == _frameIndex - 1);
474 oldFrameIndex = _frameIndex;618 oldFrameIndex = _frameIndex;
475#endif619#endif
476
477 // Every so often do some additional timing calculations and debug output
478 bool debugFrame = 0 == _frameIndex % 400;
479 620
480#if 0621#ifndef Q_OS_WIN
481 // Try to measure the amount of time taken to do the distortion622
482 // (does not seem to work on OSX with SDK based distortion)
483 // FIXME can't use a static object here, because it will cause a crash when the
484 // query attempts deconstruct after the GL context is gone.
485 static bool timerActive = false;
486 static QOpenGLTimerQuery timerQuery;
487 if (!timerQuery.isCreated()) {
488 timerQuery.create();
489 }
490
491 if (timerActive && timerQuery.isResultAvailable()) {
492 auto result = timerQuery.waitForResult();
493 if (result) { qCDebug(interfaceapp) << "Distortion took " << result << "ns"; };
494 timerActive = false;
495 }
496#endif
497
498#ifdef OVR_DIRECT_MODE
499 static bool attached = false;
500 if (!attached) {
501 attached = true;
502 void * nativeWindowHandle = (void*)(size_t)glCanvas->effectiveWinId();
503 if (nullptr != nativeWindowHandle) {
504 ovrHmd_AttachToWindow(_ovrHmd, nativeWindowHandle, nullptr, nullptr);
505 }
506 }
507#endif
508
509#ifndef OVR_CLIENT_DISTORTION
510 // FIXME: we need a better way of responding to the HSW. In particular623 // FIXME: we need a better way of responding to the HSW. In particular
511 // we need to ensure that it's only displayed once per session, rather than624 // we need to ensure that it's only displayed once per session, rather than
512 // every time the user toggles VR mode, and we need to hook it up to actual625 // every time the user toggles VR mode, and we need to hook it up to actual
@@ -522,7 +635,7 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 9 unmodified lines
522 }635 }
523 }636 }
524#endif637#endif
525 638
526 639
527 //beginFrameTiming must be called before display640 //beginFrameTiming must be called before display
528 if (!_frameTimingActive) {641 if (!_frameTimingActive) {
@@ -545,14 +658,14 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 16 unmodified lines
545 658
546 glMatrixMode(GL_MODELVIEW);659 glMatrixMode(GL_MODELVIEW);
547 glPushMatrix();660 glPushMatrix();
548 661
549 glm::quat orientation;662 glm::quat orientation;
550 glm::vec3 trackerPosition;663 glm::vec3 trackerPosition;
551 auto deviceSize = qApp->getDeviceSize();664 auto deviceSize = qApp->getDeviceSize();
552 665
553 ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds());666 ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds());
554 ovrVector3f ovrHeadPosition = ts.HeadPose.ThePose.Position;667 ovrVector3f ovrHeadPosition = ts.HeadPose.ThePose.Position;
555 668
556 trackerPosition = glm::vec3(ovrHeadPosition.x, ovrHeadPosition.y, ovrHeadPosition.z);669 trackerPosition = glm::vec3(ovrHeadPosition.x, ovrHeadPosition.y, ovrHeadPosition.z);
557 670
558 if (_calibrationState != CALIBRATED) {671 if (_calibrationState != CALIBRATED) {
@@ -562,11 +675,11 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 3 unmodified lines
562 }675 }
563 676
564 trackerPosition = bodyOrientation * trackerPosition;677 trackerPosition = bodyOrientation * trackerPosition;
565 static ovrVector3f eyeOffsets[2] = { { 0, 0, 0 }, { 0, 0, 0 } };
566 ovrPosef eyePoses[ovrEye_Count];678 ovrPosef eyePoses[ovrEye_Count];
567 ovrHmd_GetEyePoses(_ovrHmd, _frameIndex, eyeOffsets, eyePoses, nullptr);679 ovrHmd_GetEyePoses(_ovrHmd, _frameIndex, _eyeOffsets, eyePoses, nullptr);
680#ifndef Q_OS_WIN
568 ovrHmd_BeginFrame(_ovrHmd, _frameIndex);681 ovrHmd_BeginFrame(_ovrHmd, _frameIndex);
569 static ovrPosef eyeRenderPose[ovrEye_Count];682#endif
570 //Render each eye into an fbo683 //Render each eye into an fbo
571 for_each_eye(_ovrHmd, [&](ovrEyeType eye){684 for_each_eye(_ovrHmd, [&](ovrEyeType eye){
572 // If we're in eye-per-frame mode, only render one eye685 // If we're in eye-per-frame mode, only render one eye
@@ -576,29 +689,17 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 3 unmodified lines
576 return;689 return;
577 }690 }
578 _lastEyeRendered = _activeEye = eye;691 _lastEyeRendered = _activeEye = eye;
579 eyeRenderPose[eye] = eyePoses[eye];692 _eyeRenderPoses[eye] = eyePoses[eye];
580 // Set the camera rotation for this eye693 // Set the camera rotation for this eye
581 orientation.x = eyeRenderPose[eye].Orientation.x;
582 orientation.y = eyeRenderPose[eye].Orientation.y;
583 orientation.z = eyeRenderPose[eye].Orientation.z;
584 orientation.w = eyeRenderPose[eye].Orientation.w;
585
586 // Update the application camera with the latest HMD position
587 whichCamera.setHmdPosition(trackerPosition);
588 whichCamera.setHmdRotation(orientation);
589
590 694
695 vec3 eyePosition = toGlm(_eyeRenderPoses[eye].Position);
696 eyePosition = whichCamera.getRotation() * eyePosition;
697 quat eyeRotation = toGlm(_eyeRenderPoses[eye].Orientation);
698
591 // Update our camera to what the application camera is doing699 // Update our camera to what the application camera is doing
592 _camera->setRotation(whichCamera.getRotation());700 _camera->setRotation(whichCamera.getRotation() * eyeRotation);
593 _camera->setPosition(whichCamera.getPosition());701 _camera->setPosition(whichCamera.getPosition() + eyePosition);
594 configureCamera(*_camera);702 configureCamera(*_camera);
595
596 // Store the latest left and right eye render locations for things that need to know
597 glm::vec3 thisEyePosition = position + trackerPosition +
598 (bodyOrientation * glm::quat(orientation.x, orientation.y, orientation.z, orientation.w) *
599 glm::vec3(_eyeRenderDesc[eye].HmdToEyeViewOffset.x, _eyeRenderDesc[eye].HmdToEyeViewOffset.y, _eyeRenderDesc[eye].HmdToEyeViewOffset.z));
600
601 _eyePositions[eye] = thisEyePosition;
602 _camera->update(1.0f / Application::getInstance()->getFps());703 _camera->update(1.0f / Application::getInstance()->getFps());
603 704
604 glMatrixMode(GL_PROJECTION);705 glMatrixMode(GL_PROJECTION);
@@ -607,15 +708,14 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 2 unmodified lines
607 glMatrixMode(GL_MODELVIEW);708 glMatrixMode(GL_MODELVIEW);
608 glLoadIdentity();709 glLoadIdentity();
609 710
610 ovrRecti & vp = _eyeTextures[eye].Header.RenderViewport;711 ovrRecti & vp = _eyeViewports[eye];
611 vp.Size.h = _recommendedTexSize.h * _offscreenRenderScale;712 vp.Size.h = _recommendedTexSize.h * _offscreenRenderScale;
612 vp.Size.w = _recommendedTexSize.w * _offscreenRenderScale;713 vp.Size.w = _recommendedTexSize.w * _offscreenRenderScale;
613
614 glViewport(vp.Pos.x, vp.Pos.y, vp.Size.w, vp.Size.h);714 glViewport(vp.Pos.x, vp.Pos.y, vp.Size.w, vp.Size.h);
615 715
616 renderArgs->_renderSide = RenderArgs::MONO;716 renderArgs->_renderSide = RenderArgs::MONO;
617 qApp->displaySide(renderArgs, *_camera, false);717 qApp->displaySide(renderArgs, *_camera);
618 qApp->getApplicationOverlay().displayOverlayTextureHmd(*_camera);718 qApp->getApplicationCompositor().displayOverlayTextureHmd(renderArgs, eye);
619 });719 });
620 _activeEye = ovrEye_Count;720 _activeEye = ovrEye_Count;
621 721
@@ -628,7 +728,7 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 6 unmodified lines
628 glViewport(0, 0, _renderTargetSize.w, _renderTargetSize.h);728 glViewport(0, 0, _renderTargetSize.w, _renderTargetSize.h);
629 finalFbo = DependencyManager::get<GlowEffect>()->render(renderArgs);729 finalFbo = DependencyManager::get<GlowEffect>()->render(renderArgs);
630 } else {730 } else {
631 finalFbo = DependencyManager::get<TextureCache>()->getPrimaryFramebuffer(); 731 finalFbo = DependencyManager::get<TextureCache>()->getPrimaryFramebuffer();
632 glBindFramebuffer(GL_FRAMEBUFFER, 0);732 glBindFramebuffer(GL_FRAMEBUFFER, 0);
633 }733 }
634 734
@@ -638,141 +738,73 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 3 unmodified lines
638 // restore our normal viewport738 // restore our normal viewport
639 glViewport(0, 0, deviceSize.width(), deviceSize.height());739 glViewport(0, 0, deviceSize.width(), deviceSize.height());
640 740
641#if 0741#ifdef Q_OS_WIN
642 if (debugFrame && !timerActive) {742 auto srcFboSize = finalFbo->getSize();
643 timerQuery.begin();
644 }
645#endif
646 743
647#ifdef OVR_CLIENT_DISTORTION
648
649 //Wait till time-warp to reduce latency
650 ovr_WaitTillTime(_hmdFrameTiming.TimewarpPointSeconds);
651 744
652#ifdef DEBUG_RENDER_WITHOUT_DISTORTION745 // Blit to the oculus provided texture
653 auto fboSize = finalFbo->getSize();
654 glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo));746 glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo));
747 _swapFbo->Bound(oglplus::Framebuffer::Target::Draw, [&] {
748 glBlitFramebuffer(
749 0, 0, srcFboSize.x, srcFboSize.y,
750 0, 0, _swapFbo->size.x, _swapFbo->size.y,
751 GL_COLOR_BUFFER_BIT, GL_NEAREST);
752 });
753
754 // Blit to the onscreen window
755 auto destWindowSize = qApp->getDeviceSize();
655 glBlitFramebuffer(756 glBlitFramebuffer(
656 0, 0, fboSize.x, fboSize.y,757 0, 0, srcFboSize.x, srcFboSize.y,
657 0, 0, deviceSize.width(), deviceSize.height(),758 0, 0, destWindowSize.width(), destWindowSize.height(),
658 GL_COLOR_BUFFER_BIT, GL_NEAREST);759 GL_COLOR_BUFFER_BIT, GL_NEAREST);
760 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
761
762 // Submit the frame to the Oculus SDK for timewarp and distortion
763 for_each_eye([&](ovrEyeType eye) {
764 _sceneLayer.RenderPose[eye] = _eyeRenderPoses[eye];
765 });
766 auto header = &_sceneLayer.Header;
767 ovrResult res = ovrHmd_SubmitFrame(_ovrHmd, _frameIndex, nullptr, &header, 1);
768 Q_ASSERT(OVR_SUCCESS(res));
769 _swapFbo->Increment();
659#else 770#else
660 //Clear the color buffer to ensure that there isnt any residual color771 GLsync syncObject = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
661 //Left over from when OR was not connected.772 glFlush();
662 glClear(GL_COLOR_BUFFER_BIT);
663 glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(finalFbo->getRenderBuffer(0)));
664 //Renders the distorted mesh onto the screen
665 renderDistortionMesh(eyeRenderPose);
666 glBindTexture(GL_TEXTURE_2D, 0);
667#endif
668 glCanvas->swapBuffers();
669 773
670#else
671 774
775 _outputWindow->makeCurrent();
776 // force the compositing context to wait for the texture
777 // rendering to complete before it starts the distortion rendering,
778 // but without triggering a CPU/GPU synchronization
779 glWaitSync(syncObject, 0, GL_TIMEOUT_IGNORED);
780 glDeleteSync(syncObject);
781
782 GLuint textureId = gpu::GLBackend::getTextureID(finalFbo->getRenderBuffer(0));
672 for_each_eye([&](ovrEyeType eye) {783 for_each_eye([&](ovrEyeType eye) {
673 ovrGLTexture & glEyeTexture = reinterpret_cast<ovrGLTexture&>(_eyeTextures[eye]);784 ovrGLTexture & glEyeTexture = reinterpret_cast<ovrGLTexture&>(_eyeTextures[eye]);
674 glEyeTexture.OGL.TexId = finalFbo->texture();785 glEyeTexture.OGL.TexId = textureId;
675
676 });
677 786
678 ovrHmd_EndFrame(_ovrHmd, eyeRenderPose, _eyeTextures);787 });
679 788
789 // restore our normal viewport
790 ovrHmd_EndFrame(_ovrHmd, _eyeRenderPoses, _eyeTextures);
791 glCanvas->makeCurrent();
680#endif792#endif
681 793
682#if 0
683 if (debugFrame && !timerActive) {
684 timerQuery.end();
685 timerActive = true;
686 }
687#endif
688 794
689 // No DK2, no message.795 // in order to account account for changes in the pick ray caused by head movement
796 // we need to force a mouse move event on every frame (perhaps we could change this
797 // to based on the head moving a minimum distance from the last position in which we
798 // sent?)
690 {799 {
691 float latencies[5] = {};800 QMouseEvent mouseEvent(QEvent::MouseMove, glCanvas->mapFromGlobal(QCursor::pos()),
692 if (debugFrame && ovrHmd_GetFloatArray(_ovrHmd, "DK2Latency", latencies, 5) == 5)801 Qt::NoButton, Qt::NoButton, 0);
693 {802 qApp->mouseMoveEvent(&mouseEvent, 0);
694 bool nonZero = false;
695 for (int i = 0; i < 5; ++i)
696 {
697 nonZero |= (latencies[i] != 0.f);
698 }
699
700 if (nonZero)
701 {
702 qCDebug(interfaceapp) << QString().sprintf("M2P Latency: Ren: %4.2fms TWrp: %4.2fms PostPresent: %4.2fms Err: %4.2fms %4.2fms",
703 latencies[0], latencies[1], latencies[2], latencies[3], latencies[4]);
704 }
705 }
706 }803 }
707
708}
709
710#ifdef OVR_CLIENT_DISTORTION
711void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) {
712 804
713 glLoadIdentity();
714 auto deviceSize = qApp->getDeviceSize();
715 glOrtho(0, deviceSize.width(), 0, deviceSize.height(), -1.0, 1.0);
716
717 glDisable(GL_DEPTH_TEST);
718
719 glDisable(GL_BLEND);
720 _program.bind();
721 _program.setUniformValue(_textureLocation, 0);
722
723 _program.enableAttributeArray(_positionAttributeLocation);
724 _program.enableAttributeArray(_colorAttributeLocation);
725 _program.enableAttributeArray(_texCoord0AttributeLocation);
726 _program.enableAttributeArray(_texCoord1AttributeLocation);
727 _program.enableAttributeArray(_texCoord2AttributeLocation);
728
729 //Render the distortion meshes for each eye
730 for (int eyeNum = 0; eyeNum < ovrEye_Count; eyeNum++) {
731
732 ovrHmd_GetRenderScaleAndOffset(_eyeRenderDesc[eyeNum].Fov, _renderTargetSize, _eyeTextures[eyeNum].Header.RenderViewport,
733 _UVScaleOffset[eyeNum]);
734
735 GLfloat uvScale[2] = { _UVScaleOffset[eyeNum][0].x, _UVScaleOffset[eyeNum][0].y };
736 _program.setUniformValueArray(_eyeToSourceUVScaleLocation, uvScale, 1, 2);
737 GLfloat uvOffset[2] = { _UVScaleOffset[eyeNum][1].x, 1.0f - _UVScaleOffset[eyeNum][1].y };
738 _program.setUniformValueArray(_eyeToSourceUVOffsetLocation, uvOffset, 1, 2);
739
740 ovrMatrix4f timeWarpMatrices[2];
741 glm::mat4 transposeMatrices[2];
742 //Grabs the timewarp matrices to be used in the shader
743 ovrHmd_GetEyeTimewarpMatrices(_ovrHmd, (ovrEyeType)eyeNum, eyeRenderPose[eyeNum], timeWarpMatrices);
744 //Have to transpose the matrices before using them
745 transposeMatrices[0] = glm::transpose(toGlm(timeWarpMatrices[0]));
746 transposeMatrices[1] = glm::transpose(toGlm(timeWarpMatrices[1]));
747 805
748 glUniformMatrix4fv(_eyeRotationStartLocation, 1, GL_FALSE, (GLfloat *)&transposeMatrices[0][0][0]);
749 glUniformMatrix4fv(_eyeRotationEndLocation, 1, GL_FALSE, (GLfloat *)&transposeMatrices[1][0][0]);
750 806
751 glBindBuffer(GL_ARRAY_BUFFER, _vertices[eyeNum]);
752
753 //Set vertex attribute pointers
754 glVertexAttribPointer(_positionAttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)0);
755 glVertexAttribPointer(_texCoord0AttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)8);
756 glVertexAttribPointer(_texCoord1AttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)16);
757 glVertexAttribPointer(_texCoord2AttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)24);
758 glVertexAttribPointer(_colorAttributeLocation, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(DistortionVertex), (void *)32);
759
760 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indices[eyeNum]);
761 glDrawElements(GL_TRIANGLES, _meshSize[eyeNum], GL_UNSIGNED_SHORT, 0);
762 }
763
764 _program.disableAttributeArray(_positionAttributeLocation);
765 _program.disableAttributeArray(_colorAttributeLocation);
766 _program.disableAttributeArray(_texCoord0AttributeLocation);
767 _program.disableAttributeArray(_texCoord1AttributeLocation);
768 _program.disableAttributeArray(_texCoord2AttributeLocation);
769
770 glEnable(GL_BLEND);
771 glEnable(GL_DEPTH_TEST);
772 _program.release();
773 glBindBuffer(GL_ARRAY_BUFFER, 0);
774}807}
775#endif
776 808
777//Tries to reconnect to the sensors809//Tries to reconnect to the sensors
778void OculusManager::reset() {810void OculusManager::reset() {
@@ -781,21 +813,6 @@ void OculusManager::reset() { · 2 unmodified lines
781 }813 }
782}814}
783 815
784//Gets the current predicted angles from the oculus sensors
785void 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
799glm::vec3 OculusManager::getRelativePosition() {816glm::vec3 OculusManager::getRelativePosition() {
800 ovrTrackingState trackingState = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds());817 ovrTrackingState trackingState = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds());
801 return toGlm(trackingState.HeadPose.ThePose.Position);818 return toGlm(trackingState.HeadPose.ThePose.Position);
@@ -826,6 +843,9 @@ void OculusManager::overrideOffAxisFrustum(float& left, float& right, float& bot · 24 unmodified lines
826}843}
827 844
828int OculusManager::getHMDScreen() {845int OculusManager::getHMDScreen() {
846#ifdef Q_OS_WIN
847 return -1;
848#else
829 int hmdScreenIndex = -1; // unknown849 int hmdScreenIndex = -1; // unknown
830 // TODO: it might be smarter to handle multiple HMDs connected in this case. but for now,850 // TODO: it might be smarter to handle multiple HMDs connected in this case. but for now,
831 // we will simply assume the initialization code that set up _ovrHmd picked the best hmd851 // we will simply assume the initialization code that set up _ovrHmd picked the best hmd
@@ -844,7 +864,7 @@ int OculusManager::getHMDScreen() { · 12 unmodified lines
844 const int SIMILAR_NAMES = 10;864 const int SIMILAR_NAMES = 10;
845 const int EXACT_LOCATION_MATCH = 50;865 const int EXACT_LOCATION_MATCH = 50;
846 const int EXACT_RESOLUTION_MATCH = 25;866 const int EXACT_RESOLUTION_MATCH = 25;
847 867
848 int bestMatchScore = 0;868 int bestMatchScore = 0;
849 869
850 // look at the display list and see if we can find the best match870 // look at the display list and see if we can find the best match
@@ -853,7 +873,7 @@ int OculusManager::getHMDScreen() { · 2 unmodified lines
853 foreach (QScreen* screen, QGuiApplication::screens()) {873 foreach (QScreen* screen, QGuiApplication::screens()) {
854 QString screenName = screen->name();874 QString screenName = screen->name();
855 QRect screenRect = desktop->screenGeometry(screenNumber);875 QRect screenRect = desktop->screenGeometry(screenNumber);
856 876
857 int screenScore = 0;877 int screenScore = 0;
858 if (screenName == productNameFromOVR) {878 if (screenName == productNameFromOVR) {
859 screenScore += EXACT_NAME_MATCH;879 screenScore += EXACT_NAME_MATCH;
@@ -876,5 +896,18 @@ int OculusManager::getHMDScreen() { · 16 unmodified lines
876 }896 }
877 }897 }
878 return hmdScreenIndex;898 return hmdScreenIndex;
899#endif
900}
901
902mat4 OculusManager::getEyeProjection(int eye) {
903 return _eyeProjection[eye];
879}904}
880 905
906mat4 OculusManager::getEyePose(int eye) {
907 return toGlm(_eyeRenderPoses[eye]);
908}
909
910mat4 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
13#ifndef hifi_OculusManager_h13#ifndef hifi_OculusManager_h
14#define hifi_OculusManager_h14#define hifi_OculusManager_h
15 15
16#include <OVR_CAPI.h>
17
18#include <ProgramObject.h>16#include <ProgramObject.h>
19#include <glm/glm.hpp>17#include <glm/glm.hpp>
20#include <glm/gtc/matrix_transform.hpp>18#include <glm/gtc/matrix_transform.hpp>
@@ -22,39 +20,13 @@ · 1 unmodified line
22 20
23#include "RenderArgs.h"21#include "RenderArgs.h"
24 22
23class QOpenGLContext;
25class Camera;24class Camera;
26class PalmData;
27class Text3DOverlay;
28
29// Uncomment this to enable client side distortion. NOT recommended since
30// the Oculus SDK will ideally provide the best practices for distortion in
31// in terms of performance and quality, and by using it we will get updated
32// best practices for free with new runtime releases.
33#define OVR_CLIENT_DISTORTION 1
34
35
36// Direct HMD mode is currently only supported on windows and some linux systems will
37// misbehave if we try to enable the Oculus SDK at all, so isolate support for Direct
38// mode only to windows for now
39#ifdef Q_OS_WIN
40// On Win32 platforms, enabling Direct HMD requires that the SDK be
41// initialized before the GL context is set up, but this breaks v-sync
42// for any application that has a Direct mode enable Rift connected
43// but is not rendering to it. For the time being I'm setting this as
44// a macro enabled mechanism which changes where the SDK is initialized.
45// To enable Direct HMD mode, you can un-comment this, but with the
46// caveat that it will break v-sync in NON-VR mode if you have an Oculus
47// Rift connect and in Direct mode
48#define OVR_DIRECT_MODE 1
49#endif
50
51 25
52/// Handles interaction with the Oculus Rift.26/// Handles interaction with the Oculus Rift.
53class OculusManager {27class OculusManager {
54public:28public:
55 static void init();29 static void connect(QOpenGLContext* shareContext);
56 static void deinit();
57 static void connect();
58 static void disconnect();30 static void disconnect();
59 static bool isConnected();31 static bool isConnected();
60 static void recalibrate();32 static void recalibrate();
@@ -66,10 +38,6 @@ public: · 5 unmodified lines
66 static void display(QGLWidget * glCanvas, RenderArgs* renderArgs, const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera);38 static void display(QGLWidget * glCanvas, RenderArgs* renderArgs, const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera);
67 static void reset();39 static void reset();
68 40
69 /// param \yaw[out] yaw in radians
70 /// param \pitch[out] pitch in radians
71 /// param \roll[out] roll in radians
72 static void getEulerAngles(float& yaw, float& pitch, float& roll);
73 static glm::vec3 getRelativePosition();41 static glm::vec3 getRelativePosition();
74 static glm::quat getOrientation();42 static glm::quat getOrientation();
75 static QSize getRenderTargetSize();43 static QSize getRenderTargetSize();
@@ -77,145 +45,14 @@ public: · 1 unmodified line
77 static void overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal,45 static void overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal,
78 float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane);46 float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane);
79 47
80 static glm::vec3 getLeftEyePosition() { return _eyePositions[ovrEye_Left]; }48 static glm::vec3 getLeftEyePosition();
81 static glm::vec3 getRightEyePosition() { return _eyePositions[ovrEye_Right]; }49 static glm::vec3 getRightEyePosition();
82 50
83 static int getHMDScreen();51 static int getHMDScreen();
84
85private:
86 static void initSdk();
87 static void shutdownSdk();
88#ifdef OVR_CLIENT_DISTORTION
89 static void generateDistortionMesh();
90 static void renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]);
91 struct DistortionVertex {
92 glm::vec2 pos;
93 glm::vec2 texR;
94 glm::vec2 texG;
95 glm::vec2 texB;
96 struct {
97 GLubyte r;
98 GLubyte g;
99 GLubyte b;
100 GLubyte a;
101 } color;
102 };
103 52
104 static ProgramObject _program;53 static glm::mat4 getEyeProjection(int eye);
105 //Uniforms54 static glm::mat4 getEyePose(int eye);
106 static int _textureLocation;55 static glm::mat4 getHeadPose();
107 static int _eyeToSourceUVScaleLocation;
108 static int _eyeToSourceUVOffsetLocation;
109 static int _eyeRotationStartLocation;
110 static int _eyeRotationEndLocation;
111 //Attributes
112 static int _positionAttributeLocation;
113 static int _colorAttributeLocation;
114 static int _texCoord0AttributeLocation;
115 static int _texCoord1AttributeLocation;
116 static int _texCoord2AttributeLocation;
117 static ovrVector2f _UVScaleOffset[ovrEye_Count][2];
118 static GLuint _vertices[ovrEye_Count];
119 static GLuint _indices[ovrEye_Count];
120 static GLsizei _meshSize[ovrEye_Count];
121 static ovrFrameTiming _hmdFrameTiming;
122 static bool _programInitialized;
123#endif
124
125 static ovrTexture _eyeTextures[ovrEye_Count];
126 static bool _isConnected;
127 static glm::vec3 _eyePositions[ovrEye_Count];
128 static ovrHmd _ovrHmd;
129 static ovrFovPort _eyeFov[ovrEye_Count];
130 static ovrVector3f _eyeOffset[ovrEye_Count];
131 static glm::mat4 _eyeProjection[ovrEye_Count];
132 static ovrEyeRenderDesc _eyeRenderDesc[ovrEye_Count];
133 static ovrSizei _renderTargetSize;
134 static unsigned int _frameIndex;
135 static bool _frameTimingActive;
136 static Camera* _camera;
137 static ovrEyeType _activeEye;
138 static bool _hswDismissed;
139
140 static void calibrate(const glm::vec3 position, const glm::quat orientation);
141 enum CalibrationState {
142 UNCALIBRATED,
143 WAITING_FOR_DELTA,
144 WAITING_FOR_ZERO,
145 WAITING_FOR_ZERO_HELD,
146 CALIBRATED
147 };
148 static void positionCalibrationBillboard(Text3DOverlay* message);
149 static float CALIBRATION_DELTA_MINIMUM_LENGTH;
150 static float CALIBRATION_DELTA_MINIMUM_ANGLE;
151 static float CALIBRATION_ZERO_MAXIMUM_LENGTH;
152 static float CALIBRATION_ZERO_MAXIMUM_ANGLE;
153 static quint64 CALIBRATION_ZERO_HOLD_TIME;
154 static float CALIBRATION_MESSAGE_DISTANCE;
155 static CalibrationState _calibrationState;
156 static glm::vec3 _calibrationPosition;
157 static glm::quat _calibrationOrientation;
158 static quint64 _calibrationStartTime;
159 static int _calibrationMessage;
160 // TODO drop this variable and use the existing 'Developer | Render | Scale Resolution' value
161 static ovrSizei _recommendedTexSize;
162 static float _offscreenRenderScale;
163 static bool _eyePerFrameMode;
164 static ovrEyeType _lastEyeRendered;
165};56};
166 57
167
168inline glm::mat4 toGlm(const ovrMatrix4f & om) {
169 return glm::transpose(glm::make_mat4(&om.M[0][0]));
170}
171
172inline 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
176inline glm::vec3 toGlm(const ovrVector3f & ov) {
177 return glm::make_vec3(&ov.x);
178}
179
180inline glm::vec2 toGlm(const ovrVector2f & ov) {
181 return glm::make_vec2(&ov.x);
182}
183
184inline glm::uvec2 toGlm(const ovrSizei & ov) {
185 return glm::uvec2(ov.w, ov.h);
186}
187
188inline glm::quat toGlm(const ovrQuatf & oq) {
189 return glm::make_quat(&oq.x);
190}
191
192inline 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
198inline 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
205inline ovrVector3f ovrFromGlm(const glm::vec3 & v) {
206 return{ v.x, v.y, v.z };
207}
208
209inline ovrVector2f ovrFromGlm(const glm::vec2 & v) {
210 return{ v.x, v.y };
211}
212
213inline ovrSizei ovrFromGlm(const glm::uvec2 & v) {
214 return{ (int)v.x, (int)v.y };
215}
216
217inline ovrQuatf ovrFromGlm(const glm::quat & q) {
218 return{ q.x, q.y, q.z, q.w };
219}
220
221#endif // hifi_OculusManager_h58#endif // hifi_OculusManager_h
interface/src/devices/SDL2Manager.cpp+2−0
@@ -74,9 +74,11 @@ SDL2Manager* SDL2Manager::getInstance() { · 73 unmodified lines
74}74}
75 75
76void SDL2Manager::focusOutEvent() {76void SDL2Manager::focusOutEvent() {
77#ifdef HAVE_SDL2
77 for (auto joystick : _openJoysticks) {78 for (auto joystick : _openJoysticks) {
78 joystick->focusOutEvent();79 joystick->focusOutEvent();
79 }80 }
81#endif
80}82}
81 83
82void SDL2Manager::update() {84void SDL2Manager::update() {
interface/src/devices/SixenseManager.cpp+58−50
@@ -36,6 +36,8 @@ const float NECK_X = 0.25f; // meters · 35 unmodified lines
36const float NECK_Y = 0.3f; // meters36const float NECK_Y = 0.3f; // meters
37const float NECK_Z = 0.3f; // meters37const float NECK_Z = 0.3f; // meters
38 38
39const float CONTROLLER_THRESHOLD = 0.35f;
40
39#ifdef __APPLE__41#ifdef __APPLE__
40typedef int (*SixenseBaseFunction)();42typedef int (*SixenseBaseFunction)();
41typedef int (*SixenseTakeIntFunction)(int);43typedef int (*SixenseTakeIntFunction)(int);
@@ -71,25 +73,25 @@ SixenseManager::SixenseManager() : · 29 unmodified lines
71 73
72SixenseManager::~SixenseManager() {74SixenseManager::~SixenseManager() {
73#ifdef HAVE_SIXENSE_75#ifdef HAVE_SIXENSE_
74 76
75 if (_isInitialized) {77 if (_isInitialized) {
76#ifdef __APPLE__78#ifdef __APPLE__
77 SixenseBaseFunction sixenseExit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseExit");79 SixenseBaseFunction sixenseExit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseExit");
78#endif80#endif
79 81
80 sixenseExit();82 sixenseExit();
81 }83 }
82 84
83#ifdef __APPLE__85#ifdef __APPLE__
84 delete _sixenseLibrary;86 delete _sixenseLibrary;
85#endif87#endif
86 88
87#endif89#endif
88}90}
89 91
90void SixenseManager::initialize() {92void SixenseManager::initialize() {
91#ifdef HAVE_SIXENSE93#ifdef HAVE_SIXENSE
92 94
93 if (!_isInitialized) {95 if (!_isInitialized) {
94 _lowVelocityFilter = false;96 _lowVelocityFilter = false;
95 _controllersAtBase = true;97 _controllersAtBase = true;
@@ -97,22 +99,22 @@ void SixenseManager::initialize() { · 1 unmodified line
97 // By default we assume the _neckBase (in orb frame) is as high above the orb99 // By default we assume the _neckBase (in orb frame) is as high above the orb
98 // as the "torso" is below it.100 // as the "torso" is below it.
99 _neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z);101 _neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z);
100 102
101#ifdef __APPLE__103#ifdef __APPLE__
102 104
103 if (!_sixenseLibrary) {105 if (!_sixenseLibrary) {
104 106
105#ifdef SIXENSE_LIB_FILENAME107#ifdef SIXENSE_LIB_FILENAME
106 _sixenseLibrary = new QLibrary(SIXENSE_LIB_FILENAME);108 _sixenseLibrary = new QLibrary(SIXENSE_LIB_FILENAME);
107#else109#else
108 const QString SIXENSE_LIBRARY_NAME = "libsixense_x64";110 const QString SIXENSE_LIBRARY_NAME = "libsixense_x64";
109 QString frameworkSixenseLibrary = QCoreApplication::applicationDirPath() + "/../Frameworks/"111 QString frameworkSixenseLibrary = QCoreApplication::applicationDirPath() + "/../Frameworks/"
110 + SIXENSE_LIBRARY_NAME;112 + SIXENSE_LIBRARY_NAME;
111 113
112 _sixenseLibrary = new QLibrary(frameworkSixenseLibrary);114 _sixenseLibrary = new QLibrary(frameworkSixenseLibrary);
113#endif115#endif
114 }116 }
115 117
116 if (_sixenseLibrary->load()){118 if (_sixenseLibrary->load()){
117 qCDebug(interfaceapp) << "Loaded sixense library for hydra support -" << _sixenseLibrary->fileName();119 qCDebug(interfaceapp) << "Loaded sixense library for hydra support -" << _sixenseLibrary->fileName();
118 } else {120 } else {
@@ -120,14 +122,14 @@ void SixenseManager::initialize() { · 1 unmodified line
120 << "Continuing without hydra support.";122 << "Continuing without hydra support.";
121 return;123 return;
122 }124 }
123 125
124 SixenseBaseFunction sixenseInit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseInit");126 SixenseBaseFunction sixenseInit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseInit");
125#endif127#endif
126 sixenseInit();128 sixenseInit();
127 129
128 _isInitialized = true;130 _isInitialized = true;
129 }131 }
130 132
131#endif133#endif
132}134}
133 135
@@ -138,7 +140,7 @@ void SixenseManager::setFilter(bool filter) { · 4 unmodified lines
138#ifdef __APPLE__140#ifdef __APPLE__
139 SixenseTakeIntFunction sixenseSetFilterEnabled = (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseSetFilterEnabled");141 SixenseTakeIntFunction sixenseSetFilterEnabled = (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseSetFilterEnabled");
140#endif142#endif
141 143
142 if (filter) {144 if (filter) {
143 sixenseSetFilterEnabled(1);145 sixenseSetFilterEnabled(1);
144 } else {146 } else {
@@ -158,7 +160,7 @@ void SixenseManager::update(float deltaTime) { · 13 unmodified lines
158 SixenseBaseFunction sixenseGetNumActiveControllers =160 SixenseBaseFunction sixenseGetNumActiveControllers =
159 (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetNumActiveControllers");161 (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetNumActiveControllers");
160#endif162#endif
161 163
162 if (sixenseGetNumActiveControllers() == 0) {164 if (sixenseGetNumActiveControllers() == 0) {
163 _hydrasConnected = false;165 _hydrasConnected = false;
164 if (_deviceID != 0) {166 if (_deviceID != 0) {
@@ -173,7 +175,7 @@ void SixenseManager::update(float deltaTime) { · 8 unmodified lines
173 }175 }
174 return;176 return;
175 }177 }
176 178
177 PerformanceTimer perfTimer("sixense");179 PerformanceTimer perfTimer("sixense");
178 if (!_hydrasConnected) {180 if (!_hydrasConnected) {
179 _hydrasConnected = true;181 _hydrasConnected = true;
@@ -181,21 +183,21 @@ void SixenseManager::update(float deltaTime) { · 1 unmodified line
181 getInstance().assignDefaultInputMapping(*Application::getUserInputMapper());183 getInstance().assignDefaultInputMapping(*Application::getUserInputMapper());
182 UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra");184 UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra");
183 }185 }
184 186
185#ifdef __APPLE__187#ifdef __APPLE__
186 SixenseBaseFunction sixenseGetMaxControllers =188 SixenseBaseFunction sixenseGetMaxControllers =
187 (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetMaxControllers");189 (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetMaxControllers");
188#endif190#endif
189 191
190 int maxControllers = sixenseGetMaxControllers();192 int maxControllers = sixenseGetMaxControllers();
191 193
192 // we only support two controllers194 // we only support two controllers
193 sixenseControllerData controllers[2];195 sixenseControllerData controllers[2];
194 196
195#ifdef __APPLE__197#ifdef __APPLE__
196 SixenseTakeIntFunction sixenseIsControllerEnabled =198 SixenseTakeIntFunction sixenseIsControllerEnabled =
197 (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseIsControllerEnabled");199 (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseIsControllerEnabled");
198 200
199 SixenseTakeIntAndSixenseControllerData sixenseGetNewestData =201 SixenseTakeIntAndSixenseControllerData sixenseGetNewestData =
200 (SixenseTakeIntAndSixenseControllerData) _sixenseLibrary->resolve("sixenseGetNewestData");202 (SixenseTakeIntAndSixenseControllerData) _sixenseLibrary->resolve("sixenseGetNewestData");
201#endif203#endif
@@ -208,9 +210,9 @@ void SixenseManager::update(float deltaTime) { · 6 unmodified lines
208 sixenseControllerData* data = controllers + numActiveControllers;210 sixenseControllerData* data = controllers + numActiveControllers;
209 ++numActiveControllers;211 ++numActiveControllers;
210 sixenseGetNewestData(i, data);212 sixenseGetNewestData(i, data);
211 213
212 // Set palm position and normal based on Hydra position/orientation214 // Set palm position and normal based on Hydra position/orientation
213 215
214 // Either find a palm matching the sixense controller, or make a new one216 // Either find a palm matching the sixense controller, or make a new one
215 PalmData* palm;217 PalmData* palm;
216 bool foundHand = false;218 bool foundHand = false;
@@ -229,47 +231,47 @@ void SixenseManager::update(float deltaTime) { · 12 unmodified lines
229 _prevPalms[numActiveControllers - 1] = palm;231 _prevPalms[numActiveControllers - 1] = palm;
230 qCDebug(interfaceapp, "Found new Sixense controller, ID %i", data->controller_index);232 qCDebug(interfaceapp, "Found new Sixense controller, ID %i", data->controller_index);
231 }233 }
232 234
233 // Disable the hands (and return to default pose) if both controllers are at base station235 // Disable the hands (and return to default pose) if both controllers are at base station
234 if (foundHand) {236 if (foundHand) {
235 palm->setActive(!_controllersAtBase);237 palm->setActive(!_controllersAtBase);
236 } else {238 } else {
237 palm->setActive(false); // if this isn't a Sixsense ID palm, always make it inactive239 palm->setActive(false); // if this isn't a Sixsense ID palm, always make it inactive
238 }240 }
239 241
240 // Read controller buttons and joystick into the hand242 // Read controller buttons and joystick into the hand
241 palm->setControllerButtons(data->buttons);243 palm->setControllerButtons(data->buttons);
242 palm->setTrigger(data->trigger);244 palm->setTrigger(data->trigger);
243 palm->setJoystick(data->joystick_x, data->joystick_y);245 palm->setJoystick(data->joystick_x, data->joystick_y);
244 246
245 handleButtonEvent(data->buttons, numActiveControllers - 1);247 handleButtonEvent(data->buttons, numActiveControllers - 1);
246 handleAxisEvent(data->joystick_x, data->joystick_y, data->trigger, numActiveControllers - 1);248 handleAxisEvent(data->joystick_x, data->joystick_y, data->trigger, numActiveControllers - 1);
247 249
248 // Emulate the mouse so we can use scripts250 // Emulate the mouse so we can use scripts
249 if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput) && !_controllersAtBase) {251 if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput) && !_controllersAtBase) {
250 emulateMouse(palm, numActiveControllers - 1);252 emulateMouse(palm, numActiveControllers - 1);
251 }253 }
252 254
253 // NOTE: Sixense API returns pos data in millimeters but we IMMEDIATELY convert to meters.255 // NOTE: Sixense API returns pos data in millimeters but we IMMEDIATELY convert to meters.
254 glm::vec3 position(data->pos[0], data->pos[1], data->pos[2]);256 glm::vec3 position(data->pos[0], data->pos[1], data->pos[2]);
255 position *= METERS_PER_MILLIMETER;257 position *= METERS_PER_MILLIMETER;
256 258
257 // Check to see if this hand/controller is on the base259 // Check to see if this hand/controller is on the base
258 const float CONTROLLER_AT_BASE_DISTANCE = 0.075f;260 const float CONTROLLER_AT_BASE_DISTANCE = 0.075f;
259 if (glm::length(position) < CONTROLLER_AT_BASE_DISTANCE) {261 if (glm::length(position) < CONTROLLER_AT_BASE_DISTANCE) {
260 numControllersAtBase++;262 numControllersAtBase++;
261 }263 }
262 264
263 // Transform the measured position into body frame.265 // Transform the measured position into body frame.
264 glm::vec3 neck = _neckBase;266 glm::vec3 neck = _neckBase;
265 // Zeroing y component of the "neck" effectively raises the measured position a little bit.267 // Zeroing y component of the "neck" effectively raises the measured position a little bit.
266 neck.y = 0.0f;268 neck.y = 0.0f;
267 position = _orbRotation * (position - neck);269 position = _orbRotation * (position - neck);
268 270
269 // Rotation of Palm271 // Rotation of Palm
270 glm::quat rotation(data->rot_quat[3], -data->rot_quat[0], data->rot_quat[1], -data->rot_quat[2]);272 glm::quat rotation(data->rot_quat[3], -data->rot_quat[0], data->rot_quat[1], -data->rot_quat[2]);
271 rotation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)) * _orbRotation * rotation;273 rotation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)) * _orbRotation * rotation;
272 274
273 // Compute current velocity from position change275 // Compute current velocity from position change
274 glm::vec3 rawVelocity;276 glm::vec3 rawVelocity;
275 if (deltaTime > 0.0f) {277 if (deltaTime > 0.0f) {
@@ -278,11 +280,11 @@ void SixenseManager::update(float deltaTime) { · 2 unmodified lines
278 rawVelocity = glm::vec3(0.0f);280 rawVelocity = glm::vec3(0.0f);
279 }281 }
280 palm->setRawVelocity(rawVelocity); // meters/sec282 palm->setRawVelocity(rawVelocity); // meters/sec
281 283
282 // adjustment for hydra controllers fit into hands284 // adjustment for hydra controllers fit into hands
283 float sign = (i == 0) ? -1.0f : 1.0f;285 float sign = (i == 0) ? -1.0f : 1.0f;
284 rotation *= glm::angleAxis(sign * PI/4.0f, glm::vec3(0.0f, 0.0f, 1.0f));286 rotation *= glm::angleAxis(sign * PI/4.0f, glm::vec3(0.0f, 0.0f, 1.0f));
285 287
286 // Angular Velocity of Palm288 // Angular Velocity of Palm
287 glm::quat deltaRotation = rotation * glm::inverse(palm->getRawRotation());289 glm::quat deltaRotation = rotation * glm::inverse(palm->getRawRotation());
288 glm::vec3 angularVelocity(0.0f);290 glm::vec3 angularVelocity(0.0f);
@@ -294,7 +296,7 @@ void SixenseManager::update(float deltaTime) { · 5 unmodified lines
294 } else {296 } else {
295 palm->setRawAngularVelocity(glm::vec3(0.0f));297 palm->setRawAngularVelocity(glm::vec3(0.0f));
296 }298 }
297 299
298 if (_lowVelocityFilter) {300 if (_lowVelocityFilter) {
299 // Use a velocity sensitive filter to damp small motions and preserve large ones with301 // Use a velocity sensitive filter to damp small motions and preserve large ones with
300 // no latency.302 // no latency.
@@ -307,7 +309,7 @@ void SixenseManager::update(float deltaTime) { · 6 unmodified lines
307 palm->setRawPosition(position);309 palm->setRawPosition(position);
308 palm->setRawRotation(rotation);310 palm->setRawRotation(rotation);
309 }311 }
310 312
311 // Store the one fingertip in the palm structure so we can track velocity313 // Store the one fingertip in the palm structure so we can track velocity
312 const float FINGER_LENGTH = 0.3f; // meters314 const float FINGER_LENGTH = 0.3f; // meters
313 const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, FINGER_LENGTH);315 const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, FINGER_LENGTH);
@@ -320,19 +322,25 @@ void SixenseManager::update(float deltaTime) { · 6 unmodified lines
320 }322 }
321 palm->setTipPosition(newTipPosition);323 palm->setTipPosition(newTipPosition);
322 }324 }
323 325
324 if (numActiveControllers == 2) {326 if (numActiveControllers == 2) {
325 updateCalibration(controllers);327 updateCalibration(controllers);
326 }328 }
327 _controllersAtBase = (numControllersAtBase == 2);329 _controllersAtBase = (numControllersAtBase == 2);
328 }330 }
331
332 for (auto axisState : _axisStateMap) {
333 if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) {
334 _axisStateMap[axisState.first] = 0.0f;
335 }
336 }
329#endif // HAVE_SIXENSE337#endif // HAVE_SIXENSE
330}338}
331 339
332//Constants for getCursorPixelRangeMultiplier()340//Constants for getCursorPixelRangeMultiplier()
333const float MIN_PIXEL_RANGE_MULT = 0.4f;341const float MIN_PIXEL_RANGE_MULT = 0.4f;
334const float MAX_PIXEL_RANGE_MULT = 2.0f;342const float MAX_PIXEL_RANGE_MULT = 2.0f;
335const float RANGE_MULT = (MAX_PIXEL_RANGE_MULT - MIN_PIXEL_RANGE_MULT) * 0.01;343const float RANGE_MULT = (MAX_PIXEL_RANGE_MULT - MIN_PIXEL_RANGE_MULT) * 0.01f;
336 344
337//Returns a multiplier to be applied to the cursor range for the controllers345//Returns a multiplier to be applied to the cursor range for the controllers
338float SixenseManager::getCursorPixelRangeMult() const {346float SixenseManager::getCursorPixelRangeMult() const {
@@ -421,7 +429,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 82 unmodified lines
421 _calibrationState = CALIBRATION_STATE_X;429 _calibrationState = CALIBRATION_STATE_X;
422 }430 }
423 return;431 return;
424 } 432 }
425 433
426 quint64 now = usecTimestampNow() + LOCK_DURATION;434 quint64 now = usecTimestampNow() + LOCK_DURATION;
427 // these are weighted running averages435 // these are weighted running averages
@@ -431,7 +439,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 3 unmodified lines
431 if (_calibrationState == CALIBRATION_STATE_X) {439 if (_calibrationState == CALIBRATION_STATE_X) {
432 // compute new sliding average440 // compute new sliding average
433 float distance = glm::distance(_averageLeft, _averageRight);441 float distance = glm::distance(_averageLeft, _averageRight);
434 if (fabs(distance - _lastDistance) > MAXIMUM_NOISE_LEVEL) {442 if (fabsf(distance - _lastDistance) > MAXIMUM_NOISE_LEVEL) {
435 // distance is increasing so acquire the data and push the expiry out443 // distance is increasing so acquire the data and push the expiry out
436 _reachLeft = _averageLeft;444 _reachLeft = _averageLeft;
437 _reachRight = _averageRight;445 _reachRight = _averageRight;
@@ -450,7 +458,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 12 unmodified lines
450 glm::vec3 torso = 0.5f * (_reachLeft + _reachRight);458 glm::vec3 torso = 0.5f * (_reachLeft + _reachRight);
451 glm::vec3 averagePosition = 0.5f * (_averageLeft + _averageRight);459 glm::vec3 averagePosition = 0.5f * (_averageLeft + _averageRight);
452 float distance = (averagePosition - torso).y;460 float distance = (averagePosition - torso).y;
453 if (fabs(distance) > fabs(_lastDistance) + MAXIMUM_NOISE_LEVEL) {461 if (fabsf(distance) > fabsf(_lastDistance) + MAXIMUM_NOISE_LEVEL) {
454 // distance is increasing so acquire the data and push the expiry out462 // distance is increasing so acquire the data and push the expiry out
455 _reachUp = averagePosition;463 _reachUp = averagePosition;
456 _lastDistance = distance;464 _lastDistance = distance;
@@ -481,11 +489,11 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 24 unmodified lines
481 _lastDistance = distance;489 _lastDistance = distance;
482 _lockExpiry = now + LOCK_DURATION;490 _lockExpiry = now + LOCK_DURATION;
483 } else if (now > _lockExpiry) {491 } else if (now > _lockExpiry) {
484 if (fabs(_lastDistance) > 0.05f * MINIMUM_ARM_REACH) {492 if (fabsf(_lastDistance) > 0.05f * MINIMUM_ARM_REACH) {
485 // lock has expired so clamp the data and move on493 // lock has expired so clamp the data and move on
486 _calibrationState = CALIBRATION_STATE_COMPLETE;494 _calibrationState = CALIBRATION_STATE_COMPLETE;
487 qCDebug(interfaceapp, "success: sixense calibration: forward");495 qCDebug(interfaceapp, "success: sixense calibration: forward");
488 // TODO: it is theoretically possible to detect that the controllers have been 496 // TODO: it is theoretically possible to detect that the controllers have been
489 // accidentally switched (left hand is holding right controller) and to swap the order.497 // accidentally switched (left hand is holding right controller) and to swap the order.
490 }498 }
491 }499 }
@@ -496,7 +504,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 4 unmodified lines
496void SixenseManager::emulateMouse(PalmData* palm, int index) {504void SixenseManager::emulateMouse(PalmData* palm, int index) {
497 MyAvatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();505 MyAvatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
498 QPoint pos;506 QPoint pos;
499 507
500 Qt::MouseButton bumperButton;508 Qt::MouseButton bumperButton;
501 Qt::MouseButton triggerButton;509 Qt::MouseButton triggerButton;
502 510
@@ -510,16 +518,16 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { · 7 unmodified lines
510 triggerButton = Qt::LeftButton;518 triggerButton = Qt::LeftButton;
511 }519 }
512 520
513 if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers) 521 if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)
514 || Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {522 || Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {
515 pos = qApp->getApplicationOverlay().getPalmClickLocation(palm);523 pos = qApp->getApplicationCompositor().getPalmClickLocation(palm);
516 } else {524 } else {
517 // Get directon relative to avatar orientation525 // Get directon relative to avatar orientation
518 glm::vec3 direction = glm::inverse(avatar->getOrientation()) * palm->getFingerDirection();526 glm::vec3 direction = glm::inverse(avatar->getOrientation()) * palm->getFingerDirection();
519 527
520 // Get the angles, scaled between (-0.5,0.5)528 // Get the angles, scaled between (-0.5,0.5)
521 float xAngle = (atan2(direction.z, direction.x) + M_PI_2);529 float xAngle = (atan2(direction.z, direction.x) + M_PI_2);
522 float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2));530 float yAngle = 0.5f - ((atan2f(direction.z, direction.y) + (float)M_PI_2));
523 auto canvasSize = qApp->getCanvasSize();531 auto canvasSize = qApp->getCanvasSize();
524 // Get the pixel range over which the xAngle and yAngle are scaled532 // Get the pixel range over which the xAngle and yAngle are scaled
525 float cursorRange = canvasSize.x * getCursorPixelRangeMult();533 float cursorRange = canvasSize.x * getCursorPixelRangeMult();
@@ -562,11 +570,11 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { · 36 unmodified lines
562 if (!_bumperPressed[(int)(!index)]) {570 if (!_bumperPressed[(int)(!index)]) {
563 qApp->mouseMoveEvent(&mouseEvent, deviceID);571 qApp->mouseMoveEvent(&mouseEvent, deviceID);
564 }572 }
565 } 573 }
566 }574 }
567 _oldX[index] = pos.x();575 _oldX[index] = pos.x();
568 _oldY[index] = pos.y();576 _oldY[index] = pos.y();
569 577
570 578
571 //We need separate coordinates for clicks, since we need to check if579 //We need separate coordinates for clicks, since we need to check if
572 //a magnification window was clicked on580 //a magnification window was clicked on
@@ -580,7 +588,7 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { · 7 unmodified lines
580 if (palm->getControllerButtons() & BUTTON_FWD) {588 if (palm->getControllerButtons() & BUTTON_FWD) {
581 if (!_bumperPressed[index]) {589 if (!_bumperPressed[index]) {
582 _bumperPressed[index] = true;590 _bumperPressed[index] = true;
583 591
584 QMouseEvent mouseEvent(QEvent::MouseButtonPress, pos, bumperButton, bumperButton, 0);592 QMouseEvent mouseEvent(QEvent::MouseButtonPress, pos, bumperButton, bumperButton, 0);
585 593
586 qApp->mousePressEvent(&mouseEvent, deviceID);594 qApp->mousePressEvent(&mouseEvent, deviceID);
interface/src/devices/TV3DManager.cpp+9−9
@@ -12,6 +12,7 @@ · 11 unmodified lines
12#include "InterfaceConfig.h"12#include "InterfaceConfig.h"
13 13
14#include <glm/glm.hpp>14#include <glm/glm.hpp>
15#include <glm/gtc/type_ptr.hpp>
15 16
16#include <GlowEffect.h>17#include <GlowEffect.h>
17#include "gpu/GLBackend.h"18#include "gpu/GLBackend.h"
@@ -106,21 +107,20 @@ void TV3DManager::display(RenderArgs* renderArgs, Camera& whichCamera) { · 88 unmodified lines
106 _activeEye = &eye;107 _activeEye = &eye;
107 glViewport(portalX, portalY, portalW, portalH);108 glViewport(portalX, portalY, portalW, portalH);
108 glScissor(portalX, portalY, portalW, portalH);109 glScissor(portalX, portalY, portalW, portalH);
110
111 glm::mat4 projection = glm::frustum<float>(eye.left, eye.right, eye.bottom, eye.top, nearZ, farZ);
112 float fov = atan(1.0f / projection[1][1]);
113 projection = glm::translate(projection, vec3(eye.modelTranslation, 0, 0));
114 eyeCamera.setProjection(projection);
115
109 glMatrixMode(GL_PROJECTION);116 glMatrixMode(GL_PROJECTION);
110 glLoadIdentity(); // reset projection matrix117 glLoadIdentity(); // reset projection matrix
111 glFrustum(eye.left, eye.right, eye.bottom, eye.top, nearZ, farZ); // set left view frustum118 glLoadMatrixf(glm::value_ptr(projection));
112 GLfloat p[4][4];
113 // Really?
114 glGetFloatv(GL_PROJECTION_MATRIX, &(p[0][0]));
115 float cotangent = p[1][1];
116 GLfloat fov = atan(1.0f / cotangent);
117 glTranslatef(eye.modelTranslation, 0.0, 0.0); // translate to cancel parallax
118
119 glMatrixMode(GL_MODELVIEW);119 glMatrixMode(GL_MODELVIEW);
120 glLoadIdentity();120 glLoadIdentity();
121 renderArgs->_renderSide = RenderArgs::MONO;121 renderArgs->_renderSide = RenderArgs::MONO;
122 qApp->displaySide(renderArgs, eyeCamera, false);122 qApp->displaySide(renderArgs, eyeCamera, false);
123 qApp->getApplicationOverlay().displayOverlayTextureStereo(whichCamera, _aspect, fov);123 qApp->getApplicationCompositor().displayOverlayTexture(renderArgs);
124 _activeEye = NULL;124 _activeEye = NULL;
125 }, [&]{125 }, [&]{
126 // render right side view126 // render right side view
interface/src/main.cpp+1−1
@@ -23,7 +23,7 @@ · 22 unmodified lines
23#ifdef Q_OS_WIN23#ifdef Q_OS_WIN
24static BOOL CALLBACK enumWindowsCallback(HWND hWnd, LPARAM lParam) {24static BOOL CALLBACK enumWindowsCallback(HWND hWnd, LPARAM lParam) {
25 const UINT TIMEOUT = 200; // ms25 const UINT TIMEOUT = 200; // ms
26 DWORD response;26 DWORD_PTR response;
27 LRESULT result = SendMessageTimeout(hWnd, UWM_IDENTIFY_INSTANCES, 0, 0, SMTO_BLOCK | SMTO_ABORTIFHUNG, TIMEOUT, &response);27 LRESULT result = SendMessageTimeout(hWnd, UWM_IDENTIFY_INSTANCES, 0, 0, SMTO_BLOCK | SMTO_ABORTIFHUNG, TIMEOUT, &response);
28 if (result == 0) { // Timeout; continue search.28 if (result == 0) { // Timeout; continue search.
29 return TRUE;29 return TRUE;
interface/src/scripting/ControllerScriptingInterface.cpp+1−1
@@ -463,7 +463,7 @@ void ControllerScriptingInterface::resetDevice(unsigned int device) { · 462 unmodified lines
463}463}
464 464
465int ControllerScriptingInterface::findDevice(QString name) {465int ControllerScriptingInterface::findDevice(QString name) {
466 Application::getUserInputMapper()->findDevice(name);466 return Application::getUserInputMapper()->findDevice(name);
467}467}
468 468
469InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) :469InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) :
interface/src/scripting/ControllerScriptingInterface.h+1−0
@@ -65,6 +65,7 @@ public: · 64 unmodified lines
65 65
66 void emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseMoveEvent(MouseEvent(*event, deviceID)); }66 void emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseMoveEvent(MouseEvent(*event, deviceID)); }
67 void emitMousePressEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mousePressEvent(MouseEvent(*event, deviceID)); }67 void emitMousePressEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mousePressEvent(MouseEvent(*event, deviceID)); }
68 void emitMouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseDoublePressEvent(MouseEvent(*event, deviceID)); }
68 void emitMouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseReleaseEvent(MouseEvent(*event, deviceID)); }69 void emitMouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseReleaseEvent(MouseEvent(*event, deviceID)); }
69 70
70 void emitTouchBeginEvent(const TouchEvent& event) { emit touchBeginEvent(event); }71 void emitTouchBeginEvent(const TouchEvent& event) { emit touchBeginEvent(event); }
interface/src/scripting/HMDScriptingInterface.cpp+3−3
@@ -25,9 +25,9 @@ bool HMDScriptingInterface::getHUDLookAtPosition3D(glm::vec3& result) const { · 24 unmodified lines
25 25
26 glm::vec3 direction = orientation * glm::vec3(0.0f, 0.0f, -1.0f);26 glm::vec3 direction = orientation * glm::vec3(0.0f, 0.0f, -1.0f);
27 27
28 ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay();28 const auto& compositor = Application::getInstance()->getApplicationCompositor();
29 29
30 return applicationOverlay.calculateRayUICollisionPoint(position, direction, result);30 return compositor.calculateRayUICollisionPoint(position, direction, result);
31}31}
32 32
33QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) {33QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) {
@@ -40,7 +40,7 @@ QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* conte · 6 unmodified lines
40 glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * (hudIntersection - sphereCenter);40 glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * (hudIntersection - sphereCenter);
41 glm::quat rotation = ::rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), direction);41 glm::quat rotation = ::rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), direction);
42 glm::vec3 eulers = ::safeEulerAngles(rotation);42 glm::vec3 eulers = ::safeEulerAngles(rotation);
43 return qScriptValueFromValue<glm::vec2>(engine, Application::getInstance()->getApplicationOverlay()43 return qScriptValueFromValue<glm::vec2>(engine, Application::getInstance()->getApplicationCompositor()
44 .sphericalToOverlay(glm::vec2(eulers.y, -eulers.x)));44 .sphericalToOverlay(glm::vec2(eulers.y, -eulers.x)));
45 }45 }
46 return QScriptValue::NullValue;46 return QScriptValue::NullValue;
interface/src/scripting/HMDScriptingInterface.h+2−2
@@ -27,11 +27,11 @@ public: · 26 unmodified lines
27 static QScriptValue getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine);27 static QScriptValue getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine);
28 28
29public slots:29public slots:
30 void toggleMagnifier() { Application::getInstance()->getApplicationOverlay().toggleMagnifier(); };30 void toggleMagnifier() { Application::getInstance()->getApplicationCompositor().toggleMagnifier(); };
31 31
32private:32private:
33 HMDScriptingInterface() {};33 HMDScriptingInterface() {};
34 bool getMagnifier() const { return Application::getInstance()->getApplicationOverlay().hasMagnifier(); };34 bool getMagnifier() const { return Application::getInstance()->getApplicationCompositor().hasMagnifier(); };
35 bool isHMDMode() const { return Application::getInstance()->isHMDMode(); }35 bool isHMDMode() const { return Application::getInstance()->isHMDMode(); }
36 36
37 bool getHUDLookAtPosition3D(glm::vec3& result) const;37 bool getHUDLookAtPosition3D(glm::vec3& result) const;
interface/src/starfield/renderer/Renderer.cpp+9−0
@@ -11,6 +11,7 @@ · 10 unmodified lines
11//11//
12 12
13#include "starfield/renderer/Renderer.h"13#include "starfield/renderer/Renderer.h"
14#include "Application.h"
14 15
15using namespace starfield;16using namespace starfield;
16 17
@@ -52,6 +53,10 @@ void Renderer::render(float perspective, float aspect, mat4 const& orientation, · 35 unmodified lines
52 matrix[3][1] = 0.0f;53 matrix[3][1] = 0.0f;
53 matrix[3][2] = 0.0f;54 matrix[3][2] = 0.0f;
54 55
56 glMatrixMode(GL_PROJECTION);
57 glPushMatrix();
58 glLoadMatrixf(glm::value_ptr(qApp->getDisplayViewFrustum()->getProjection()));
59 glMatrixMode(GL_MODELVIEW);
55 // extract local z vector60 // extract local z vector
56 vec3 ahead = vec3(matrix[2]);61 vec3 ahead = vec3(matrix[2]);
57 62
@@ -74,6 +79,10 @@ void Renderer::render(float perspective, float aspect, mat4 const& orientation, · 16 unmodified lines
74 floodFill(cursor, TileSelection(*this, _tileArray, _tileArray + _tiling.getTileCount(), (TileSelection::Cursor*) _batchCountArray));79 floodFill(cursor, TileSelection(*this, _tileArray, _tileArray + _tiling.getTileCount(), (TileSelection::Cursor*) _batchCountArray));
75 80
76 this->glBatch(glm::value_ptr(matrix), prepareBatch((unsigned*) _batchOffs, _outIndexPos), alpha);81 this->glBatch(glm::value_ptr(matrix), prepareBatch((unsigned*) _batchOffs, _outIndexPos), alpha);
82 glMatrixMode(GL_PROJECTION);
83 glPopMatrix();
84 glMatrixMode(GL_MODELVIEW);
85
77}86}
78 87
79// renderer construction88// renderer construction
interface/src/ui/AddressBarDialog.cpp+24−0
@@ -22,6 +22,20 @@ AddressBarDialog::AddressBarDialog(QQuickItem* parent) : OffscreenQmlDialog(pare · 21 unmodified lines
22 connect(addressManager.data(), &AddressManager::lookupResultIsOffline, this, &AddressBarDialog::displayAddressOfflineMessage);22 connect(addressManager.data(), &AddressManager::lookupResultIsOffline, this, &AddressBarDialog::displayAddressOfflineMessage);
23 connect(addressManager.data(), &AddressManager::lookupResultIsNotFound, this, &AddressBarDialog::displayAddressNotFoundMessage);23 connect(addressManager.data(), &AddressManager::lookupResultIsNotFound, this, &AddressBarDialog::displayAddressNotFoundMessage);
24 connect(addressManager.data(), &AddressManager::lookupResultsFinished, this, &AddressBarDialog::hide);24 connect(addressManager.data(), &AddressManager::lookupResultsFinished, this, &AddressBarDialog::hide);
25 connect(addressManager.data(), &AddressManager::goBackPossible, this, [this] (bool isPossible) {
26 if (isPossible != _backEnabled) {
27 _backEnabled = isPossible;
28 emit backEnabledChanged();
29 }
30 });
31 connect(addressManager.data(), &AddressManager::goForwardPossible, this, [this] (bool isPossible) {
32 if (isPossible != _forwardEnabled) {
33 _forwardEnabled = isPossible;
34 emit forwardEnabledChanged();
35 }
36 });
37 _backEnabled = !(DependencyManager::get<AddressManager>()->getBackStack().isEmpty());
38 _forwardEnabled = !(DependencyManager::get<AddressManager>()->getForwardStack().isEmpty());
25}39}
26 40
27void AddressBarDialog::hide() {41void AddressBarDialog::hide() {
@@ -35,6 +49,16 @@ void AddressBarDialog::loadAddress(const QString& address) { · 7 unmodified lines
35 }49 }
36}50}
37 51
52void AddressBarDialog::loadBack() {
53 qDebug() << "Called LoadBack";
54 DependencyManager::get<AddressManager>()->goBack();
55}
56
57void AddressBarDialog::loadForward() {
58 qDebug() << "Called LoadForward";
59 DependencyManager::get<AddressManager>()->goForward();
60}
61
38void AddressBarDialog::displayAddressOfflineMessage() {62void AddressBarDialog::displayAddressOfflineMessage() {
39 OffscreenUi::error("That user or place is currently offline");63 OffscreenUi::error("That user or place is currently offline");
40}64}
interface/src/ui/AddressBarDialog.h+13−0
@@ -18,9 +18,17 @@ class AddressBarDialog : public OffscreenQmlDialog · 17 unmodified lines
18{18{
19 Q_OBJECT19 Q_OBJECT
20 HIFI_QML_DECL20 HIFI_QML_DECL
21 Q_PROPERTY(bool backEnabled READ backEnabled NOTIFY backEnabledChanged)
22 Q_PROPERTY(bool forwardEnabled READ forwardEnabled NOTIFY forwardEnabledChanged)
21 23
22public:24public:
23 AddressBarDialog(QQuickItem* parent = nullptr);25 AddressBarDialog(QQuickItem* parent = nullptr);
26 bool backEnabled() { return _backEnabled; }
27 bool forwardEnabled() { return _forwardEnabled; }
28
29signals:
30 void backEnabledChanged();
31 void forwardEnabledChanged();
24 32
25protected:33protected:
26 void displayAddressOfflineMessage();34 void displayAddressOfflineMessage();
@@ -28,6 +36,11 @@ protected: · 1 unmodified line
28 void hide();36 void hide();
29 37
30 Q_INVOKABLE void loadAddress(const QString& address);38 Q_INVOKABLE void loadAddress(const QString& address);
39 Q_INVOKABLE void loadBack();
40 Q_INVOKABLE void loadForward();
41
42 bool _backEnabled;
43 bool _forwardEnabled;
31};44};
32 45
33#endif46#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
27static const float MAG_SPEED = 0.08f;
28
29static const quint64 MSECS_TO_USECS = 1000ULL;
30static const quint64 TOOLTIP_DELAY = 500 * MSECS_TO_USECS;
31
32static const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f };
33static const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f };
34static const float reticleSize = TWO_PI / 100.0f;
35
36static const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f };
37static const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f;
38
39static const float CURSOR_PIXEL_SIZE = 32.0f;
40static const float MOUSE_PITCH_RANGE = 1.0f * PI;
41static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI;
42static const glm::vec2 MOUSE_RANGE(MOUSE_YAW_RANGE, MOUSE_PITCH_RANGE);
43
44static gpu::BufferPointer _hemiVertices;
45static gpu::BufferPointer _hemiIndices;
46static int _hemiIndexCount{ 0 };
47EntityItemID ApplicationCompositor::_noItemId;
48static QString _tooltipId;
49
50// Return a point's cartesian coordinates on a sphere from pitch and yaw
51glm::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
59bool 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
114ApplicationCompositor::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
156ApplicationCompositor::~ApplicationCompositor() {
157}
158
159
160void 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
173void 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
223vec2 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.
240void 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
320void 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
346QPoint 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
376bool 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
394void 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
412void 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
523void 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
591void 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
661void 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
683glm::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
699glm::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
704glm::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
715glm::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
724glm::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
734glm::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
744glm::vec2 ApplicationCompositor::screenToOverlay(const glm::vec2& screenPos) const {
745 return sphericalToOverlay(screenToSpherical(screenPos));
746}
747
748glm::vec2 ApplicationCompositor::overlayToScreen(const glm::vec2& overlayPos) const {
749 return sphericalToScreen(overlayToSpherical(overlayPos));
750}
751
752void 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
21class Camera;
22class PalmData;
23class RenderArgs;
24
25const float MAGNIFY_WIDTH = 220.0f;
26const float MAGNIFY_HEIGHT = 100.0f;
27const float MAGNIFY_MULT = 2.0f;
28
29const 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
34class ApplicationCompositor : public QObject {
35 Q_OBJECT
36public:
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
72private:
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
14#include <QOpenGLFramebufferObject>14#include <QOpenGLFramebufferObject>
15#include <QOpenGLTexture>15#include <QOpenGLTexture>
16 16
17#include <glm/gtc/type_ptr.hpp>
18
17#include <avatar/AvatarManager.h>19#include <avatar/AvatarManager.h>
20#include <DeferredLightingEffect.h>
18#include <GLMHelpers.h>21#include <GLMHelpers.h>
19#include <PathUtils.h>
20#include <gpu/GLBackend.h>22#include <gpu/GLBackend.h>
23#include <gpu/GLBackendShared.h>
21#include <GLMHelpers.h>24#include <GLMHelpers.h>
22#include <PerfStat.h>
23#include <OffscreenUi.h>25#include <OffscreenUi.h>
26#include <CursorManager.h>
27#include <PerfStat.h>
24 28
25#include "AudioClient.h"29#include "AudioClient.h"
26#include "audio/AudioIOStatsRenderer.h"30#include "audio/AudioIOStatsRenderer.h"
27#include "audio/AudioScope.h"31#include "audio/AudioScope.h"
28#include "audio/AudioToolBox.h"
29#include "Application.h"32#include "Application.h"
30#include "ApplicationOverlay.h"33#include "ApplicationOverlay.h"
31#include "devices/CameraToolBox.h"
32 34
33#include "Util.h"35#include "Util.h"
34#include "ui/Stats.h"36#include "ui/Stats.h"
35 37#include "ui/AvatarInputs.h"
36// Used to animate the magnification windows
37const float MAG_SPEED = 0.08f;
38
39const quint64 MSECS_TO_USECS = 1000ULL;
40 38
41const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f };39const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f };
42const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f };40const int AUDIO_METER_GAP = 5;
43const float reticleSize = TWO_PI / 100.0f;41const int MUTE_ICON_PADDING = 10;
44 42const vec4 CONNECTION_STATUS_BORDER_COLOR{ 1.0f, 0.0f, 0.0f, 0.8f };
45
46const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f };
47const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f;43const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f;
44static const float ORTHO_NEAR_CLIP = -10000;
45static const float ORTHO_FAR_CLIP = 10000;
48 46
49static const float MOUSE_PITCH_RANGE = 1.0f * PI;47// TODO move somewhere useful
50static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI;48static void fboViewport(QOpenGLFramebufferObject* fbo) {
51static const glm::vec2 MOUSE_RANGE(MOUSE_YAW_RANGE, MOUSE_PITCH_RANGE);49 auto size = fbo->size();
52 50 glViewport(0, 0, size.width(), size.height());
53// Return a point's cartesian coordinates on a sphere from pitch and yaw
54glm::vec3 getPoint(float yaw, float pitch) {
55 return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)),
56 glm::sin(-pitch),
57 glm::cos(-pitch) * (-glm::cos(yaw)));
58}51}
59 52
60//Checks if the given ray intersects the sphere at the origin. result will store a multiplier that should53ApplicationOverlay::ApplicationOverlay()
61//be multiplied by dir and added to origin to get the location of the collision
62bool raySphereIntersect(const glm::vec3 &dir, const glm::vec3 &origin, float r, float* result)
63{54{
64 //Source: http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection
65
66 //Compute A, B and C coefficients
67 float a = glm::dot(dir, dir);
68 float b = 2 * glm::dot(dir, origin);
69 float c = glm::dot(origin, origin) - (r * r);
70
71 //Find discriminant
72 float disc = b * b - 4 * a * c;
73
74 // if discriminant is negative there are no real roots, so return
75 // false as ray misses sphere
76 if (disc < 0) {
77 return false;
78 }
79
80 // compute q as described above
81 float distSqrt = sqrtf(disc);
82 float q;
83 if (b < 0) {
84 q = (-b - distSqrt) / 2.0;
85 } else {
86 q = (-b + distSqrt) / 2.0;
87 }
88
89 // compute t0 and t1
90 float t0 = q / a;
91 float t1 = c / q;
92
93 // make sure t0 is smaller than t1
94 if (t0 > t1) {
95 // if t0 is bigger than t1 swap them around
96 float temp = t0;
97 t0 = t1;
98 t1 = temp;
99 }
100
101 // if t1 is less than zero, the object is in the ray's negative direction
102 // and consequently the ray misses the sphere
103 if (t1 < 0) {
104 return false;
105 }
106
107 // if t0 is less than zero, the intersection point is at t1
108 if (t0 < 0) {
109 *result = t1;
110 return true;
111 } else { // else the intersection point is at t0
112 *result = t0;
113 return true;
114 }
115}
116
117void 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
138ApplicationOverlay::ApplicationOverlay() :
139 _textureFov(glm::radians(DEFAULT_HMD_UI_ANGULAR_SIZE)),
140 _textureAspectRatio(1.0f),
141 _lastMouseMove(0),
142 _magnifier(true),
143 _alpha(1.0f),
144 _oculusUIRadius(1.0f),
145 _trailingAudioLoudness(0.0f),
146 _previousBorderWidth(-1),
147 _previousBorderHeight(-1),
148 _previousMagnifierBottomLeft(),
149 _previousMagnifierBottomRight(),
150 _previousMagnifierTopLeft(),
151 _previousMagnifierTopRight()
152{
153 memset(_reticleActive, 0, sizeof(_reticleActive));
154 memset(_magActive, 0, sizeof(_reticleActive));
155 memset(_magSizeMult, 0, sizeof(_magSizeMult));
156
157 auto geometryCache = DependencyManager::get<GeometryCache>();55 auto geometryCache = DependencyManager::get<GeometryCache>();
158
159 _reticleQuad = geometryCache->allocateID();
160 _magnifierQuad = geometryCache->allocateID();
161 _audioRedQuad = geometryCache->allocateID();
162 _audioGreenQuad = geometryCache->allocateID();
163 _audioBlueQuad = geometryCache->allocateID();
164 _domainStatusBorder = geometryCache->allocateID();56 _domainStatusBorder = geometryCache->allocateID();
165 _magnifierBorder = geometryCache->allocateID();57 _magnifierBorder = geometryCache->allocateID();
166 58
167 // Once we move UI rendering and screen rendering to different59 // Once we move UI rendering and screen rendering to different
168 // threads, we need to use a sync object to deteremine when60 // threads, we need to use a sync object to deteremine when
169 // the current UI texture is no longer being read from, and only 61 // the current UI texture is no longer being read from, and only
170 // then release it back to the UI for re-use62 // then release it back to the UI for re-use
171 auto offscreenUi = DependencyManager::get<OffscreenUi>();63 auto offscreenUi = DependencyManager::get<OffscreenUi>();
172 connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [&](GLuint textureId) {64 connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [&](GLuint textureId) {
173 auto offscreenUi = DependencyManager::get<OffscreenUi>();65 auto offscreenUi = DependencyManager::get<OffscreenUi>();
174 offscreenUi->lockTexture(textureId);66 offscreenUi->lockTexture(textureId);
175 assert(!glGetError());67 assert(!glGetError());
176 std::swap(_newUiTexture, textureId);68 std::swap(_uiTexture, textureId);
177 if (textureId) {69 if (textureId) {
178 offscreenUi->releaseTexture(textureId);70 offscreenUi->releaseTexture(textureId);
179 }71 }
@@ -185,846 +77,81 @@ ApplicationOverlay::~ApplicationOverlay() { · 5 unmodified lines
185 77
186// Renders the overlays either to a texture or to the screen78// Renders the overlays either to a texture or to the screen
187void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {79void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
80 CHECK_GL_ERROR();
188 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");81 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");
189 Overlays& overlays = qApp->getOverlays();
190
191 _textureFov = glm::radians(_hmdUIAngularSize);
192 glm::vec2 size = qApp->getCanvasSize();
193 _textureAspectRatio = aspect(size);
194 82
195 //Handle fading and deactivation/activation of UI83 // TODO move to Application::idle()?
196 84 Stats::getInstance()->updateStats();
197 // Render 2D overlay85 AvatarInputs::getInstance()->update();
198 glMatrixMode(GL_PROJECTION);
199 glDisable(GL_DEPTH_TEST);
200 glDisable(GL_LIGHTING);
201 glEnable(GL_BLEND);
202 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
203 _overlays.buildFramebufferObject();
204 _overlays.bind();
205 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
206 glViewport(0, 0, size.x, size.y);
207 86
208 glPushMatrix(); {87 buildFramebufferObject();
209 const float NEAR_CLIP = -10000;
210 const float FAR_CLIP = 10000;
211 glLoadIdentity();
212 glOrtho(0, size.x, size.y, 0, NEAR_CLIP, FAR_CLIP);
213 88
214 glMatrixMode(GL_MODELVIEW);89 // Execute the batch into our framebuffer
215 90 _overlayFramebuffer->bind();
216 renderAudioMeter();91 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
217 renderCameraToggle();92 fboViewport(_overlayFramebuffer);
218
219 renderStatsAndLogs();
220
221 // give external parties a change to hook in
222 emit qApp->renderingOverlay();
223
224 overlays.renderHUD(renderArgs);
225
226 renderPointers();
227
228 renderDomainConnectionStatusBorder();
229
230 glMatrixMode(GL_PROJECTION);
231 } glPopMatrix();
232
233 glMatrixMode(GL_MODELVIEW);
234 glEnable(GL_DEPTH_TEST);
235 glEnable(GL_LIGHTING);
236 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
237
238 _overlays.release();
239}
240 93
241// A quick and dirty solution for compositing the old overlay 94 // Now render the overlay components together into a single texture
242// texture with the new one95 renderOverlays(renderArgs);
243template <typename F>96 renderStatsAndLogs(renderArgs);
244void with_each_texture(GLuint firstPassTexture, GLuint secondPassTexture, F f) {97 renderDomainConnectionStatusBorder(renderArgs);
245 glEnable(GL_TEXTURE_2D);98 renderQmlUi(renderArgs);
246 glActiveTexture(GL_TEXTURE0);99 _overlayFramebuffer->release();
247 if (firstPassTexture) {100 CHECK_GL_ERROR();
248 glBindTexture(GL_TEXTURE_2D, firstPassTexture);
249 f();
250 }
251 if (secondPassTexture) {
252 glBindTexture(GL_TEXTURE_2D, secondPassTexture);
253 f();
254 }
255 glBindTexture(GL_TEXTURE_2D, 0);
256 glDisable(GL_TEXTURE_2D);
257}101}
258 102
259// Draws the FBO texture for the screen103void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) {
260void ApplicationOverlay::displayOverlayTexture() {104 if (_uiTexture) {
261 if (_alpha == 0.0f) {105 gpu::Batch batch;
262 return;106 auto geometryCache = DependencyManager::get<GeometryCache>();
107 geometryCache->useSimpleDrawPipeline(batch);
108 batch.setProjectionTransform(mat4());
109 batch.setModelTransform(mat4());
110 batch._glBindTexture(GL_TEXTURE_2D, _uiTexture);
111 geometryCache->renderUnitQuad(batch, glm::vec4(1));
112 renderArgs->_context->syncCache();
113 renderArgs->_context->render(batch);
263 }114 }
264 glMatrixMode(GL_PROJECTION);
265 glPushMatrix(); {
266 glLoadIdentity();
267 glDisable(GL_DEPTH_TEST);
268 glDisable(GL_LIGHTING);
269 glEnable(GL_BLEND);
270 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
271 glViewport(0, 0, qApp->getDeviceSize().width(), qApp->getDeviceSize().height());
272
273 static const glm::vec2 topLeft(-1, 1);
274 static const glm::vec2 bottomRight(1, -1);
275 static const glm::vec2 texCoordTopLeft(0.0f, 1.0f);
276 static const glm::vec2 texCoordBottomRight(1.0f, 0.0f);
277 with_each_texture(_overlays.getTexture(), _newUiTexture, [&] {
278 DependencyManager::get<GeometryCache>()->renderQuad(
279 topLeft, bottomRight,
280 texCoordTopLeft, texCoordBottomRight,
281 glm::vec4(1.0f, 1.0f, 1.0f, _alpha));
282 });
283
284 if (!_crosshairTexture) {
285 _crosshairTexture = DependencyManager::get<TextureCache>()->
286 getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png");
287 }
288
289 //draw the mouse pointer
290 glm::vec2 canvasSize = qApp->getCanvasSize();
291 glm::vec2 mouseSize = 32.0f / canvasSize;
292 auto mouseTopLeft = topLeft * mouseSize;
293 auto mouseBottomRight = bottomRight * mouseSize;
294 vec2 mousePosition = vec2(qApp->getMouseX(), qApp->getMouseY());
295 mousePosition /= canvasSize;
296 mousePosition *= 2.0f;
297 mousePosition -= 1.0f;
298 mousePosition.y *= -1.0f;
299
300 glEnable(GL_TEXTURE_2D);
301 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
302 glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
303 glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f };
304 DependencyManager::get<GeometryCache>()->renderQuad(
305 mouseTopLeft + mousePosition, mouseBottomRight + mousePosition,
306 texCoordTopLeft, texCoordBottomRight,
307 reticleColor);
308 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
309 glDisable(GL_TEXTURE_2D);
310 } glPopMatrix();
311}115}
312 116
313// Draws the FBO texture for Oculus rift.117void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) {
314void ApplicationOverlay::displayOverlayTextureHmd(Camera& whichCamera) {118 glm::vec2 size = qApp->getCanvasSize();
315 if (_alpha == 0.0f) {
316 return;
317 }
318
319 glEnable(GL_BLEND);
320 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
321 glEnable(GL_DEPTH_TEST);
322 glDepthMask(GL_TRUE);
323 glDisable(GL_LIGHTING);
324 glEnable(GL_ALPHA_TEST);
325 glAlphaFunc(GL_GREATER, 0.01f);
326
327 119
328 //Update and draw the magnifiers120 mat4 legacyProjection = glm::ortho<float>(0, size.x, size.y, 0, ORTHO_NEAR_CLIP, ORTHO_FAR_CLIP);
329 MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();121 glMatrixMode(GL_PROJECTION);
330 const glm::quat& orientation = myAvatar->getOrientation();122 glPushMatrix();
331 // Always display the HMD overlay relative to the camera position but 123 glLoadMatrixf(glm::value_ptr(legacyProjection));
332 // remove the HMD pose offset. This results in an overlay that sticks with you
333 // even in third person mode, but isn't drawn at a fixed distance.
334 glm::vec3 position = whichCamera.getPosition();
335 position -= qApp->getCamera()->getHmdPosition();
336 const float scale = myAvatar->getScale() * _oculusUIRadius;
337
338// glm::vec3 eyeOffset = setEyeOffsetPosition;
339 glMatrixMode(GL_MODELVIEW);124 glMatrixMode(GL_MODELVIEW);
340 glPushMatrix(); {
341 glTranslatef(position.x, position.y, position.z);
342 glm::mat4 rotation = glm::toMat4(orientation);
343 glMultMatrixf(&rotation[0][0]);
344 glScalef(scale, scale, scale);
345 for (int i = 0; i < NUMBER_OF_RETICLES; i++) {
346
347 if (_magActive[i]) {
348 _magSizeMult[i] += MAG_SPEED;
349 if (_magSizeMult[i] > 1.0f) {
350 _magSizeMult[i] = 1.0f;
351 }
352 } else {
353 _magSizeMult[i] -= MAG_SPEED;
354 if (_magSizeMult[i] < 0.0f) {
355 _magSizeMult[i] = 0.0f;
356 }
357 }
358
359 if (_magSizeMult[i] > 0.0f) {
360 //Render magnifier, but dont show border for mouse magnifier
361 glm::vec2 projection = screenToOverlay(glm::vec2(_reticlePosition[MOUSE].x(),
362 _reticlePosition[MOUSE].y()));
363 with_each_texture(_overlays.getTexture(), 0, [&] {
364 renderMagnifier(projection, _magSizeMult[i], i != MOUSE);
365 });
366 }
367 }
368
369 glDepthMask(GL_FALSE);
370 glDisable(GL_ALPHA_TEST);
371
372 static float textureFOV = 0.0f, textureAspectRatio = 1.0f;
373 if (textureFOV != _textureFov ||
374 textureAspectRatio != _textureAspectRatio) {
375 textureFOV = _textureFov;
376 textureAspectRatio = _textureAspectRatio;
377
378 _overlays.buildVBO(_textureFov, _textureAspectRatio, 80, 80);
379 }
380 125
381 with_each_texture(_overlays.getTexture(), _newUiTexture, [&] {
382 _overlays.render();
383 });
384
385 if (!Application::getInstance()->isMouseHidden()) {
386 renderPointersOculus();
387 }
388 glDepthMask(GL_TRUE);
389 glDisable(GL_TEXTURE_2D);
390
391 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
392 glEnable(GL_LIGHTING);
393 } glPopMatrix();
394}
395
396// Draws the FBO texture for 3DTV.
397void ApplicationOverlay::displayOverlayTextureStereo(Camera& whichCamera, float aspectRatio, float fov) {
398 if (_alpha == 0.0f) {
399 return;
400 }
401
402 MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
403 const glm::vec3& viewMatrixTranslation = qApp->getViewMatrixTranslation();
404
405 glEnable(GL_BLEND);
406 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
407 glEnable(GL_DEPTH_TEST);
408 glDisable(GL_LIGHTING);
409
410 glMatrixMode(GL_MODELVIEW);
411
412 glPushMatrix();
413 glLoadIdentity();
414 // Transform to world space
415 glm::quat rotation = whichCamera.getRotation();
416 glm::vec3 axis2 = glm::axis(rotation);
417 glRotatef(-glm::degrees(glm::angle(rotation)), axis2.x, axis2.y, axis2.z);
418 glTranslatef(viewMatrixTranslation.x, viewMatrixTranslation.y, viewMatrixTranslation.z);
419
420 // Translate to the front of the camera
421 glm::vec3 pos = whichCamera.getPosition();
422 glm::quat rot = myAvatar->getOrientation();
423 glm::vec3 axis = glm::axis(rot);
424
425 glTranslatef(pos.x, pos.y, pos.z);
426 glRotatef(glm::degrees(glm::angle(rot)), axis.x, axis.y, axis.z);
427
428 glm::vec4 overlayColor = {1.0f, 1.0f, 1.0f, _alpha};
429
430 //Render
431 const GLfloat distance = 1.0f;
432
433 const GLfloat halfQuadHeight = distance * tan(fov);
434 const GLfloat halfQuadWidth = halfQuadHeight * aspectRatio;
435 const GLfloat quadWidth = halfQuadWidth * 2.0f;
436 const GLfloat quadHeight = halfQuadHeight * 2.0f;
437
438 GLfloat x = -halfQuadWidth;
439 GLfloat y = -halfQuadHeight;
440 glDisable(GL_DEPTH_TEST);126 glDisable(GL_DEPTH_TEST);
441 127 glDisable(GL_LIGHTING);
442 with_each_texture(_overlays.getTexture(), _newUiTexture, [&] {
443 DependencyManager::get<GeometryCache>()->renderQuad(glm::vec3(x, y + quadHeight, -distance),
444 glm::vec3(x + quadWidth, y + quadHeight, -distance),
445 glm::vec3(x + quadWidth, y, -distance),
446 glm::vec3(x, y, -distance),
447 glm::vec2(0.0f, 1.0f), glm::vec2(1.0f, 1.0f),
448 glm::vec2(1.0f, 0.0f), glm::vec2(0.0f, 0.0f),
449 overlayColor);
450 });
451
452 if (!_crosshairTexture) {
453 _crosshairTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() +
454 "images/sixense-reticle.png");
455 }
456
457 //draw the mouse pointer
458 glEnable(GL_BLEND);128 glEnable(GL_BLEND);
459 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);129 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
460 glEnable(GL_TEXTURE_2D);
461 glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
462 glm::vec2 canvasSize = qApp->getCanvasSize();
463 const float reticleSize = 40.0f / canvasSize.x * quadWidth;
464 x -= reticleSize / 2.0f;
465 y += reticleSize / 2.0f;
466 const float mouseX = (qApp->getMouseX() / (float)canvasSize.x) * quadWidth;
467 const float mouseY = (1.0 - (qApp->getMouseY() / (float)canvasSize.y)) * quadHeight;
468
469 glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f };
470 130
471 DependencyManager::get<GeometryCache>()->renderQuad(glm::vec3(x + mouseX, y + mouseY, -distance), 131 // give external parties a change to hook in
472 glm::vec3(x + mouseX + reticleSize, y + mouseY, -distance),132 emit qApp->renderingOverlay();
473 glm::vec3(x + mouseX + reticleSize, y + mouseY - reticleSize, -distance),133 qApp->getOverlays().renderHUD(renderArgs);
474 glm::vec3(x + mouseX, y + mouseY - reticleSize, -distance),
475 glm::vec2(0.0f, 0.0f), glm::vec2(1.0f, 0.0f),
476 glm::vec2(1.0f, 1.0f), glm::vec2(0.0f, 1.0f),
477 reticleColor, _reticleQuad);
478 134
479 glEnable(GL_DEPTH_TEST);135 glMatrixMode(GL_PROJECTION);
480
481 glPopMatrix();136 glPopMatrix();
482
483 glDepthMask(GL_TRUE);
484 glBindTexture(GL_TEXTURE_2D, 0);
485 glDisable(GL_TEXTURE_2D);
486
487 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
488 glEnable(GL_LIGHTING);
489}
490
491void 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
519glm::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
536QPoint 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
566bool 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
584void 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
643void 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
753void ApplicationOverlay::renderPointersOculus() {
754
755 glEnable(GL_BLEND);
756 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
757 glEnable(GL_TEXTURE_2D);
758
759 glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
760 glDisable(GL_DEPTH_TEST);
761
762 glMatrixMode(GL_MODELVIEW);137 glMatrixMode(GL_MODELVIEW);
763
764 //Controller Pointers
765 MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
766 for (int i = 0; i < (int)myAvatar->getHand()->getNumPalms(); i++) {
767 PalmData& palm = myAvatar->getHand()->getPalms()[i];
768 if (palm.isActive()) {
769 glm::vec2 polar = getPolarCoordinates(palm);
770 // Convert to quaternion
771 glm::quat orientation = glm::quat(glm::vec3(polar.y, -polar.x, 0.0f));
772 // Render reticle at location
773 renderReticle(orientation, _alpha);
774 }
775 }
776
777 //Mouse Pointer
778 if (_reticleActive[MOUSE]) {
779 glm::vec2 projection = screenToSpherical(glm::vec2(_reticlePosition[MOUSE].x(),
780 _reticlePosition[MOUSE].y()));
781 glm::quat orientation(glm::vec3(-projection.y, projection.x, 0.0f));
782 renderReticle(orientation, _alpha);
783 }
784 138
785 glEnable(GL_DEPTH_TEST);139 renderArgs->_context->syncCache();
786 glDisable(GL_TEXTURE_2D);140 fboViewport(_overlayFramebuffer);
787 glDisable(GL_BLEND);
788}141}
789 142
790//Renders a small magnification of the currently bound texture at the coordinates143void ApplicationOverlay::renderRearViewToFbo(RenderArgs* renderArgs) {
791void ApplicationOverlay::renderMagnifier(glm::vec2 magPos, float sizeMult, bool showBorder) {
792 if (!_magnifier) {
793 return;
794 }
795 auto canvasSize = qApp->getCanvasSize();
796
797 const int widgetWidth = canvasSize.x;
798 const int widgetHeight = canvasSize.y;
799
800 const float halfWidth = (MAGNIFY_WIDTH / _textureAspectRatio) * sizeMult / 2.0f;
801 const float halfHeight = MAGNIFY_HEIGHT * sizeMult / 2.0f;
802 // Magnification Texture Coordinates
803 const float magnifyULeft = (magPos.x - halfWidth) / (float)widgetWidth;
804 const float magnifyURight = (magPos.x + halfWidth) / (float)widgetWidth;
805 const float magnifyVTop = 1.0f - (magPos.y - halfHeight) / (float)widgetHeight;
806 const float magnifyVBottom = 1.0f - (magPos.y + halfHeight) / (float)widgetHeight;
807
808 const float newHalfWidth = halfWidth * MAGNIFY_MULT;
809 const float newHalfHeight = halfHeight * MAGNIFY_MULT;
810 //Get yaw / pitch value for the corners
811 const glm::vec2 topLeftYawPitch = overlayToSpherical(glm::vec2(magPos.x - newHalfWidth,
812 magPos.y - newHalfHeight));
813 const glm::vec2 bottomRightYawPitch = overlayToSpherical(glm::vec2(magPos.x + newHalfWidth,
814 magPos.y + newHalfHeight));
815
816 const glm::vec3 bottomLeft = getPoint(topLeftYawPitch.x, bottomRightYawPitch.y);
817 const glm::vec3 bottomRight = getPoint(bottomRightYawPitch.x, bottomRightYawPitch.y);
818 const glm::vec3 topLeft = getPoint(topLeftYawPitch.x, topLeftYawPitch.y);
819 const glm::vec3 topRight = getPoint(bottomRightYawPitch.x, topLeftYawPitch.y);
820
821 auto geometryCache = DependencyManager::get<GeometryCache>();
822
823 if (bottomLeft != _previousMagnifierBottomLeft || bottomRight != _previousMagnifierBottomRight
824 || topLeft != _previousMagnifierTopLeft || topRight != _previousMagnifierTopRight) {
825 QVector<glm::vec3> border;
826 border << topLeft;
827 border << bottomLeft;
828 border << bottomRight;
829 border << topRight;
830 border << topLeft;
831 geometryCache->updateVertices(_magnifierBorder, border, glm::vec4(1.0f, 0.0f, 0.0f, _alpha));
832
833 _previousMagnifierBottomLeft = bottomLeft;
834 _previousMagnifierBottomRight = bottomRight;
835 _previousMagnifierTopLeft = topLeft;
836 _previousMagnifierTopRight = topRight;
837 }
838
839 glPushMatrix(); {
840 if (showBorder) {
841 glDisable(GL_TEXTURE_2D);
842 glLineWidth(1.0f);
843 //Outer Line
844 geometryCache->renderVertices(gpu::LINE_STRIP, _magnifierBorder);
845 glEnable(GL_TEXTURE_2D);
846 }
847 glm::vec4 magnifierColor = { 1.0f, 1.0f, 1.0f, _alpha };
848
849 DependencyManager::get<GeometryCache>()->renderQuad(bottomLeft, bottomRight, topRight, topLeft,
850 glm::vec2(magnifyULeft, magnifyVBottom),
851 glm::vec2(magnifyURight, magnifyVBottom),
852 glm::vec2(magnifyURight, magnifyVTop),
853 glm::vec2(magnifyULeft, magnifyVTop),
854 magnifierColor, _magnifierQuad);
855
856 } glPopMatrix();
857}144}
858 145
859const int AUDIO_METER_GAP = 5;146void ApplicationOverlay::renderRearView(RenderArgs* renderArgs) {
860const int MUTE_ICON_PADDING = 10;
861
862void ApplicationOverlay::renderCameraToggle() {
863 if (Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking)) {
864 return;
865 }
866
867 int audioMeterY;
868 bool smallMirrorVisible = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !qApp->isHMDMode();
869 bool boxed = smallMirrorVisible &&
870 !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror);
871 if (boxed) {
872 audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_GAP + MUTE_ICON_PADDING;
873 } else {
874 audioMeterY = AUDIO_METER_GAP + MUTE_ICON_PADDING;
875 }
876
877 DependencyManager::get<CameraToolBox>()->render(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP, audioMeterY, boxed);
878}147}
879 148
880void ApplicationOverlay::renderAudioMeter() {149void ApplicationOverlay::renderStatsAndLogs(RenderArgs* renderArgs) {
881 auto audio = DependencyManager::get<AudioClient>();
882
883 // Audio VU Meter and Mute Icon
884 const int MUTE_ICON_SIZE = 24;
885 const int AUDIO_METER_HEIGHT = 8;
886 const int INTER_ICON_GAP = 2;
887
888 int cameraSpace = 0;
889 int audioMeterWidth = MIRROR_VIEW_WIDTH - MUTE_ICON_SIZE - MUTE_ICON_PADDING;
890 int audioMeterScaleWidth = audioMeterWidth - 2;
891 int audioMeterX = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_GAP;
892 if (!Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking)) {
893 cameraSpace = MUTE_ICON_SIZE + INTER_ICON_GAP;
894 audioMeterWidth -= cameraSpace;
895 audioMeterScaleWidth -= cameraSpace;
896 audioMeterX += cameraSpace;
897 }
898
899 int audioMeterY;
900 bool smallMirrorVisible = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !qApp->isHMDMode();
901 bool boxed = smallMirrorVisible &&
902 !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror);
903 if (boxed) {
904 audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_GAP + MUTE_ICON_PADDING;
905 } else {
906 audioMeterY = AUDIO_METER_GAP + MUTE_ICON_PADDING;
907 }
908
909 const glm::vec4 AUDIO_METER_BLUE = { 0.0, 0.0, 1.0, 1.0 };
910 const glm::vec4 AUDIO_METER_GREEN = { 0.0, 1.0, 0.0, 1.0 };
911 const glm::vec4 AUDIO_METER_RED = { 1.0, 0.0, 0.0, 1.0 };
912 const float CLIPPING_INDICATOR_TIME = 1.0f;
913 const float AUDIO_METER_AVERAGING = 0.5;
914 const float LOG2 = log(2.0f);
915 const float METER_LOUDNESS_SCALE = 2.8f / 5.0f;
916 const float LOG2_LOUDNESS_FLOOR = 11.0f;
917 float audioGreenStart = 0.25f * audioMeterScaleWidth;
918 float audioRedStart = 0.8f * audioMeterScaleWidth;
919 float audioLevel = 0.0f;
920 float loudness = audio->getLastInputLoudness() + 1.0f;
921
922 _trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.0f - AUDIO_METER_AVERAGING) * loudness;
923 float log2loudness = log(_trailingAudioLoudness) / LOG2;
924
925 if (log2loudness <= LOG2_LOUDNESS_FLOOR) {
926 audioLevel = (log2loudness / LOG2_LOUDNESS_FLOOR) * METER_LOUDNESS_SCALE * audioMeterScaleWidth;
927 } else {
928 audioLevel = (log2loudness - (LOG2_LOUDNESS_FLOOR - 1.0f)) * METER_LOUDNESS_SCALE * audioMeterScaleWidth;
929 }
930 if (audioLevel > audioMeterScaleWidth) {
931 audioLevel = audioMeterScaleWidth;
932 }
933 bool isClipping = ((audio->getTimeSinceLastClip() > 0.0f) && (audio->getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME));
934
935 DependencyManager::get<AudioToolBox>()->render(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP, audioMeterY, cameraSpace, boxed);
936
937 auto canvasSize = qApp->getCanvasSize();
938 DependencyManager::get<AudioScope>()->render(canvasSize.x, canvasSize.y);
939 DependencyManager::get<AudioIOStatsRenderer>()->render(WHITE_TEXT, canvasSize.x, canvasSize.y);
940
941 audioMeterY += AUDIO_METER_HEIGHT;
942
943 // Draw audio meter background Quad
944 DependencyManager::get<GeometryCache>()->renderQuad(audioMeterX, audioMeterY, audioMeterWidth, AUDIO_METER_HEIGHT,
945 glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
946
947 if (audioLevel > audioRedStart) {
948 glm::vec4 quadColor;
949 if (!isClipping) {
950 quadColor = AUDIO_METER_RED;
951 } else {
952 quadColor = glm::vec4(1, 1, 1, 1);
953 }
954 // Draw Red Quad
955 DependencyManager::get<GeometryCache>()->renderQuad(audioMeterX + audioRedStart,
956 audioMeterY,
957 audioLevel - audioRedStart,
958 AUDIO_METER_HEIGHT, quadColor,
959 _audioRedQuad);
960
961 audioLevel = audioRedStart;
962 }
963
964 if (audioLevel > audioGreenStart) {
965 glm::vec4 quadColor;
966 if (!isClipping) {
967 quadColor = AUDIO_METER_GREEN;
968 } else {
969 quadColor = glm::vec4(1, 1, 1, 1);
970 }
971 // Draw Green Quad
972 DependencyManager::get<GeometryCache>()->renderQuad(audioMeterX + audioGreenStart,
973 audioMeterY,
974 audioLevel - audioGreenStart,
975 AUDIO_METER_HEIGHT, quadColor,
976 _audioGreenQuad);
977
978 audioLevel = audioGreenStart;
979 }
980
981 if (audioLevel >= 0) {
982 glm::vec4 quadColor;
983 if (!isClipping) {
984 quadColor = AUDIO_METER_BLUE;
985 } else {
986 quadColor = glm::vec4(1, 1, 1, 1);
987 }
988 // Draw Blue (low level) quad
989 DependencyManager::get<GeometryCache>()->renderQuad(audioMeterX,
990 audioMeterY,
991 audioLevel, AUDIO_METER_HEIGHT, quadColor,
992 _audioBlueQuad);
993 }
994}
995
996void ApplicationOverlay::renderStatsAndLogs() {
997 Application* application = Application::getInstance();
998 QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
999
1000 const OctreePacketProcessor& octreePacketProcessor = application->getOctreePacketProcessor();
1001 NodeBounds& nodeBoundsDisplay = application->getNodeBoundsDisplay();
1002
1003 // Display stats and log text onscreen150 // Display stats and log text onscreen
1004 glLineWidth(1.0f);
1005 glPointSize(1.0f);
1006 151
1007 // Determine whether to compute timing details152 // Determine whether to compute timing details
1008 bool shouldDisplayTimingDetail = Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) &&
1009 Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
1010 Stats::getInstance()->isExpanded();
1011 if (shouldDisplayTimingDetail != PerformanceTimer::isActive()) {
1012 PerformanceTimer::setActive(shouldDisplayTimingDetail);
1013 }
1014
1015 if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
1016 // let's set horizontal offset to give stats some margin to mirror
1017 int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2;
1018 int voxelPacketsToProcess = octreePacketProcessor.packetsToProcessCount();
1019 // Onscreen text about position, servers, etc
1020 Stats::getInstance()->display(WHITE_TEXT, horizontalOffset, application->getFps(),
1021 bandwidthRecorder->getCachedTotalAverageInputPacketsPerSecond(),
1022 bandwidthRecorder->getCachedTotalAverageOutputPacketsPerSecond(),
1023 bandwidthRecorder->getCachedTotalAverageInputKilobitsPerSecond(),
1024 bandwidthRecorder->getCachedTotalAverageOutputKilobitsPerSecond(),
1025 voxelPacketsToProcess);
1026 }
1027 153
154 /*
1028 // Show on-screen msec timer155 // Show on-screen msec timer
1029 if (Menu::getInstance()->isOptionChecked(MenuOption::FrameTimer)) {156 if (Menu::getInstance()->isOptionChecked(MenuOption::FrameTimer)) {
1030 auto canvasSize = qApp->getCanvasSize();157 auto canvasSize = qApp->getCanvasSize();
@@ -1036,159 +163,77 @@ void ApplicationOverlay::renderStatsAndLogs() { · 5 unmodified lines
1036 drawText(canvasSize.x - 100, canvasSize.y - timerBottom,163 drawText(canvasSize.x - 100, canvasSize.y - timerBottom,
1037 0.30f, 0.0f, 0, frameTimer.toUtf8().constData(), WHITE_TEXT);164 0.30f, 0.0f, 0, frameTimer.toUtf8().constData(), WHITE_TEXT);
1038 }165 }
166
167 glPointSize(1.0f);
168 glDisable(GL_DEPTH_TEST);
169 glDisable(GL_LIGHTING);
170 glEnable(GL_BLEND);
171 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
172 NodeBounds& nodeBoundsDisplay = qApp->getNodeBoundsDisplay();
1039 nodeBoundsDisplay.drawOverlay();173 nodeBoundsDisplay.drawOverlay();
174 glEnable(GL_DEPTH_TEST);
175 glEnable(GL_LIGHTING);
176 glEnable(GL_BLEND);
177 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
178 fboViewport(_overlayFramebuffer);
179 */
1040}180}
1041 181
1042void ApplicationOverlay::renderDomainConnectionStatusBorder() {182void ApplicationOverlay::renderDomainConnectionStatusBorder(RenderArgs* renderArgs) {
183 auto geometryCache = DependencyManager::get<GeometryCache>();
184 static std::once_flag once;
185 std::call_once(once, [&] {
186 QVector<vec2> points;
187 static const float B = 0.99f;
188 points.push_back(vec2(-B));
189 points.push_back(vec2(B, -B));
190 points.push_back(vec2(B));
191 points.push_back(vec2(-B, B));
192 points.push_back(vec2(-B));
193 geometryCache->updateVertices(_domainStatusBorder, points, CONNECTION_STATUS_BORDER_COLOR);
194 });
1043 auto nodeList = DependencyManager::get<NodeList>();195 auto nodeList = DependencyManager::get<NodeList>();
1044
1045 if (nodeList && !nodeList->getDomainHandler().isConnected()) {196 if (nodeList && !nodeList->getDomainHandler().isConnected()) {
197 gpu::Batch batch;
1046 auto geometryCache = DependencyManager::get<GeometryCache>();198 auto geometryCache = DependencyManager::get<GeometryCache>();
1047 auto canvasSize = qApp->getCanvasSize();199 geometryCache->useSimpleDrawPipeline(batch);
1048 if ((int)canvasSize.x != _previousBorderWidth || (int)canvasSize.y != _previousBorderHeight) {200 batch.setProjectionTransform(mat4());
1049 glm::vec4 color(CONNECTION_STATUS_BORDER_COLOR[0],201 batch.setModelTransform(mat4());
1050 CONNECTION_STATUS_BORDER_COLOR[1],202 batch.setUniformTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture());
1051 CONNECTION_STATUS_BORDER_COLOR[2], 1.0f);203 batch._glLineWidth(CONNECTION_STATUS_BORDER_LINE_WIDTH);
1052
1053 QVector<glm::vec2> border;
1054 border << glm::vec2(0, 0);
1055 border << glm::vec2(0, canvasSize.y);
1056 border << glm::vec2(canvasSize.x, canvasSize.y);
1057 border << glm::vec2(canvasSize.x, 0);
1058 border << glm::vec2(0, 0);
1059 geometryCache->updateVertices(_domainStatusBorder, border, color);
1060 _previousBorderWidth = canvasSize.x;
1061 _previousBorderHeight = canvasSize.y;
1062 }
1063
1064 glLineWidth(CONNECTION_STATUS_BORDER_LINE_WIDTH);
1065
1066 geometryCache->renderVertices(gpu::LINE_STRIP, _domainStatusBorder);
1067 }
1068}
1069 204
1070ApplicationOverlay::TexturedHemisphere::TexturedHemisphere() :205 // TODO animate the disconnect border for some excitement while not connected?
1071 _vertices(0),206 //double usecs = usecTimestampNow();
1072 _indices(0),207 //double secs = usecs / 1000000.0;
1073 _framebufferObject(NULL),208 //float scaleAmount = 1.0f + (0.01f * sin(secs * 5.0f));
1074 _vbo(0, 0) {209 //batch.setModelTransform(glm::scale(mat4(), vec3(scaleAmount)));
1075}
1076
1077ApplicationOverlay::TexturedHemisphere::~TexturedHemisphere() {
1078 cleanupVBO();
1079 if (_framebufferObject != NULL) {
1080 delete _framebufferObject;
1081 }
1082}
1083
1084void ApplicationOverlay::TexturedHemisphere::bind() {
1085 _framebufferObject->bind();
1086}
1087
1088void ApplicationOverlay::TexturedHemisphere::release() {
1089 _framebufferObject->release();
1090}
1091 210
1092void ApplicationOverlay::TexturedHemisphere::buildVBO(const float fov,211 geometryCache->renderVertices(batch, gpu::LINE_STRIP, _domainStatusBorder);
1093 const float aspectRatio,212 renderArgs->_context->syncCache();
1094 const int slices,213 renderArgs->_context->render(batch);
1095 const int stacks) {
1096 if (fov >= PI) {
1097 qDebug() << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues";
1098 }
1099 // Cleanup old VBO if necessary
1100 cleanupVBO();
1101
1102 //UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm
1103
1104 // Compute number of vertices needed
1105 _vertices = slices * stacks;
1106
1107 // Compute vertices positions and texture UV coordinate
1108 TextureVertex* vertexData = new TextureVertex[_vertices];
1109 TextureVertex* vertexPtr = &vertexData[0];
1110 for (int i = 0; i < stacks; i++) {
1111 float stacksRatio = (float)i / (float)(stacks - 1); // First stack is 0.0f, last stack is 1.0f
1112 // abs(theta) <= fov / 2.0f
1113 float pitch = -fov * (stacksRatio - 0.5f);
1114
1115 for (int j = 0; j < slices; j++) {
1116 float slicesRatio = (float)j / (float)(slices - 1); // First slice is 0.0f, last slice is 1.0f
1117 // abs(phi) <= fov * aspectRatio / 2.0f
1118 float yaw = -fov * aspectRatio * (slicesRatio - 0.5f);
1119
1120 vertexPtr->position = getPoint(yaw, pitch);
1121 vertexPtr->uv.x = slicesRatio;
1122 vertexPtr->uv.y = stacksRatio;
1123 vertexPtr++;
1124 }
1125 }
1126 // Create and write to buffer
1127 glGenBuffers(1, &_vbo.first);
1128 glBindBuffer(GL_ARRAY_BUFFER, _vbo.first);
1129 static const int BYTES_PER_VERTEX = sizeof(TextureVertex);
1130 glBufferData(GL_ARRAY_BUFFER, _vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW);
1131 delete[] vertexData;
1132
1133
1134 // Compute number of indices needed
1135 static const int VERTEX_PER_TRANGLE = 3;
1136 static const int TRIANGLE_PER_RECTANGLE = 2;
1137 int numberOfRectangles = (slices - 1) * (stacks - 1);
1138 _indices = numberOfRectangles * TRIANGLE_PER_RECTANGLE * VERTEX_PER_TRANGLE;
1139
1140 // Compute indices order
1141 GLushort* indexData = new GLushort[_indices];
1142 GLushort* indexPtr = indexData;
1143 for (int i = 0; i < stacks - 1; i++) {
1144 for (int j = 0; j < slices - 1; j++) {
1145 GLushort bottomLeftIndex = i * slices + j;
1146 GLushort bottomRightIndex = bottomLeftIndex + 1;
1147 GLushort topLeftIndex = bottomLeftIndex + slices;
1148 GLushort topRightIndex = topLeftIndex + 1;
1149
1150 *(indexPtr++) = topLeftIndex;
1151 *(indexPtr++) = bottomLeftIndex;
1152 *(indexPtr++) = topRightIndex;
1153
1154 *(indexPtr++) = topRightIndex;
1155 *(indexPtr++) = bottomLeftIndex;
1156 *(indexPtr++) = bottomRightIndex;
1157 }
1158 }214 }
1159 // Create and write to buffer
1160 glGenBuffers(1, &_vbo.second);
1161 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vbo.second);
1162 static const int BYTES_PER_INDEX = sizeof(GLushort);
1163 glBufferData(GL_ELEMENT_ARRAY_BUFFER, _indices * BYTES_PER_INDEX, indexData, GL_STATIC_DRAW);
1164 delete[] indexData;
1165}215}
1166 216
1167void ApplicationOverlay::TexturedHemisphere::cleanupVBO() {217GLuint ApplicationOverlay::getOverlayTexture() {
1168 if (_vbo.first != 0) {218 if (!_overlayFramebuffer) {
1169 glDeleteBuffers(1, &_vbo.first);219 return 0;
1170 _vbo.first = 0;
1171 }
1172 if (_vbo.second != 0) {
1173 glDeleteBuffers(1, &_vbo.second);
1174 _vbo.second = 0;
1175 }220 }
221 return _overlayFramebuffer->texture();
1176}222}
1177 223
1178void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() {224void ApplicationOverlay::buildFramebufferObject() {
1179 auto canvasSize = qApp->getCanvasSize();225 QSize fboSize = qApp->getDeviceSize();
1180 QSize fboSize = QSize(canvasSize.x, canvasSize.y);226 if (_overlayFramebuffer && fboSize == _overlayFramebuffer->size()) {
1181 if (_framebufferObject != NULL && fboSize == _framebufferObject->size()) {227 // Already built
1182 // Already build
1183 return;228 return;
1184 }229 }
1185 230
1186 if (_framebufferObject != NULL) {231 if (_overlayFramebuffer) {
1187 delete _framebufferObject;232 delete _overlayFramebuffer;
1188 }233 }
1189 234
1190 _framebufferObject = new QOpenGLFramebufferObject(fboSize, QOpenGLFramebufferObject::Depth);235 _overlayFramebuffer = new QOpenGLFramebufferObject(fboSize, QOpenGLFramebufferObject::Depth);
1191 glBindTexture(GL_TEXTURE_2D, getTexture());236 glBindTexture(GL_TEXTURE_2D, getOverlayTexture());
1192 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);237 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1193 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);238 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1194 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);239 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
@@ -1197,104 +242,3 @@ void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() { · 2 unmodified lines
1197 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);242 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
1198 glBindTexture(GL_TEXTURE_2D, 0);243 glBindTexture(GL_TEXTURE_2D, 0);
1199}244}
1200
1201//Renders a hemisphere with texture coordinates.
1202void 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
1229GLuint ApplicationOverlay::TexturedHemisphere::getTexture() {
1230 return _framebufferObject->texture();
1231}
1232
1233glm::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
1249glm::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
1254glm::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
1265glm::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
1274glm::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
1284glm::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
1294glm::vec2 ApplicationOverlay::screenToOverlay(const glm::vec2& screenPos) const {
1295 return sphericalToOverlay(screenToSpherical(screenPos));
1296}
1297
1298glm::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
13#define hifi_ApplicationOverlay_h13#define hifi_ApplicationOverlay_h
14 14
15#include <gpu/Texture.h>15#include <gpu/Texture.h>
16class Camera;
17class Overlays;
18class QOpenGLFramebufferObject;16class QOpenGLFramebufferObject;
19 17
20const float MAGNIFY_WIDTH = 220.0f;
21const float MAGNIFY_HEIGHT = 100.0f;
22const float MAGNIFY_MULT = 2.0f;
23
24const float DEFAULT_HMD_UI_ANGULAR_SIZE = 72.0f;
25
26// Handles the drawing of the overlays to the screen18// Handles the drawing of the overlays to the screen
27// TODO, move divide up the rendering, displaying and input handling19// TODO, move divide up the rendering, displaying and input handling
28// facilities of this class20// facilities of this class
@@ -33,122 +25,26 @@ public: · 4 unmodified lines
33 ~ApplicationOverlay();25 ~ApplicationOverlay();
34 26
35 void renderOverlay(RenderArgs* renderArgs);27 void renderOverlay(RenderArgs* renderArgs);
36 void displayOverlayTexture();28 GLuint getOverlayTexture();
37 void displayOverlayTextureStereo(Camera& whichCamera, float aspectRatio, float fov);
38 void displayOverlayTextureHmd(Camera& whichCamera);
39
40 QPoint getPalmClickLocation(const PalmData *palm) const;
41 bool calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const;
42
43 bool hasMagnifier() const { return _magnifier; }
44 void toggleMagnifier() { _magnifier = !_magnifier; }
45 29
46 float getHmdUIAngularSize() const { return _hmdUIAngularSize; }
47 void setHmdUIAngularSize(float hmdUIAngularSize) { _hmdUIAngularSize = hmdUIAngularSize; }
48
49 // Converter from one frame of reference to another.
50 // Frame of reference:
51 // Direction: Ray that represents the spherical values
52 // Screen: Position on the screen (x,y)
53 // Spherical: Pitch and yaw that gives the position on the sphere we project on (yaw,pitch)
54 // Overlay: Position on the overlay (x,y)
55 // (x,y) in Overlay are similar than (x,y) in Screen except they can be outside of the bound of te screen.
56 // This allows for picking outside of the screen projection in 3D.
57 glm::vec2 sphericalToOverlay(const glm::vec2 & sphericalPos) const;
58 glm::vec2 overlayToSpherical(const glm::vec2 & overlayPos) const;
59 glm::vec2 screenToOverlay(const glm::vec2 & screenPos) const;
60 glm::vec2 overlayToScreen(const glm::vec2 & overlayPos) const;
61 void computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const;
62
63 static glm::vec2 directionToSpherical(const glm::vec3 & direction);
64 static glm::vec3 sphericalToDirection(const glm::vec2 & sphericalPos);
65 static glm::vec2 screenToSpherical(const glm::vec2 & screenPos);
66 static glm::vec2 sphericalToScreen(const glm::vec2 & sphericalPos);
67
68private:30private:
69 // Interleaved vertex data31 void renderStatsAndLogs(RenderArgs* renderArgs);
70 struct TextureVertex {32 void renderDomainConnectionStatusBorder(RenderArgs* renderArgs);
71 glm::vec3 position;33 void renderRearViewToFbo(RenderArgs* renderArgs);
72 glm::vec2 uv;34 void renderRearView(RenderArgs* renderArgs);
73 };35 void renderQmlUi(RenderArgs* renderArgs);
74 36 void renderOverlays(RenderArgs* renderArgs);
75 typedef QPair<GLuint, GLuint> VerticesIndices;37 void buildFramebufferObject();
76 class TexturedHemisphere {38
77 public:39 float _alpha{ 1.0f };
78 TexturedHemisphere();40 float _trailingAudioLoudness{ 0.0f };
79 ~TexturedHemisphere();41 GLuint _uiTexture{ 0 };
80
81 void bind();
82 void release();
83 GLuint getTexture();
84
85 void buildFramebufferObject();
86 void buildVBO(const float fov, const float aspectRatio, const int slices, const int stacks);
87 void render();
88
89 private:
90 void cleanupVBO();
91
92 GLuint _vertices;
93 GLuint _indices;
94 QOpenGLFramebufferObject* _framebufferObject;
95 VerticesIndices _vbo;
96 };
97
98 float _hmdUIAngularSize = DEFAULT_HMD_UI_ANGULAR_SIZE;
99 void renderReticle(glm::quat orientation, float alpha);
100 void renderPointers();;
101 void renderMagnifier(glm::vec2 magPos, float sizeMult, bool showBorder);
102
103 void renderControllerPointers();
104 void renderPointersOculus();
105
106 void renderAudioMeter();
107 void renderCameraToggle();
108 void renderStatsAndLogs();
109 void renderDomainConnectionStatusBorder();
110 void bindCursorTexture(gpu::Batch& batch, uint8_t cursorId = 0);
111 42
112 TexturedHemisphere _overlays;
113
114 float _textureFov;
115 float _textureAspectRatio;
116
117 enum Reticles { MOUSE, LEFT_CONTROLLER, RIGHT_CONTROLLER, NUMBER_OF_RETICLES };
118 bool _reticleActive[NUMBER_OF_RETICLES];
119 QPoint _reticlePosition[NUMBER_OF_RETICLES];
120 bool _magActive[NUMBER_OF_RETICLES];
121 float _magSizeMult[NUMBER_OF_RETICLES];
122 quint64 _lastMouseMove;
123 bool _magnifier;
124
125 float _alpha = 1.0f;
126 float _oculusUIRadius;
127 float _trailingAudioLoudness;
128
129 gpu::TexturePointer _crosshairTexture;
130
131
132 QMap<uint16_t, gpu::TexturePointer> _cursors;
133
134 GLuint _newUiTexture{ 0 };
135
136 int _reticleQuad;
137 int _magnifierQuad;
138 int _audioRedQuad;
139 int _audioGreenQuad;
140 int _audioBlueQuad;
141 int _domainStatusBorder;43 int _domainStatusBorder;
142 int _magnifierBorder;44 int _magnifierBorder;
143 45
144 int _previousBorderWidth;46 ivec2 _previousBorderSize{ -1 };
145 int _previousBorderHeight;47 QOpenGLFramebufferObject* _overlayFramebuffer{ nullptr };
146
147 glm::vec3 _previousMagnifierBottomLeft;
148 glm::vec3 _previousMagnifierBottomRight;
149 glm::vec3 _previousMagnifierTopLeft;
150 glm::vec3 _previousMagnifierTopRight;
151
152};48};
153 49
154#endif // hifi_ApplicationOverlay_h50#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
18HIFI_QML_DEF(AvatarInputs)
19
20
21static AvatarInputs* INSTANCE{ nullptr };
22static const char SETTINGS_GROUP_NAME[] = "Rear View Tools";
23static const char ZOOM_LEVEL_SETTINGS[] = "ZoomLevel";
24
25static Setting::Handle<int> rearViewZoomLevel(QStringList() << SETTINGS_GROUP_NAME << ZOOM_LEVEL_SETTINGS, 0);
26
27AvatarInputs* AvatarInputs::getInstance() {
28 if (!INSTANCE) {
29 AvatarInputs::registerType();
30 AvatarInputs::show();
31 Q_ASSERT(INSTANCE);
32 }
33 return INSTANCE;
34}
35
36AvatarInputs::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
60void 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
109void AvatarInputs::toggleCameraMute() {
110 FaceTracker* faceTracker = Application::getInstance()->getSelectedFaceTracker();
111 if (faceTracker) {
112 faceTracker->toggleMute();
113 }
114}
115
116void AvatarInputs::toggleAudioMute() {
117 DependencyManager::get<AudioClient>()->toggleMute();
118}
119
120void AvatarInputs::resetSensors() {
121 qApp->resetSensors();
122}
123
124void AvatarInputs::toggleZoom() {
125 _mirrorZoomed = !_mirrorZoomed;
126 rearViewZoomLevel.set(_mirrorZoomed ? 0 : 1);
127 emit mirrorZoomedChanged();
128}
129
130void 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) \
17public: \
18 type name() { return _##name; }; \
19private: \
20 type _##name{ initialValue };
21
22class 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
34public:
35 static AvatarInputs* getInstance();
36 AvatarInputs(QQuickItem* parent = nullptr);
37 void update();
38
39signals:
40 void cameraEnabledChanged();
41 void cameraMutedChanged();
42 void audioMutedChanged();
43 void audioClippingChanged();
44 void audioLevelChanged();
45 void mirrorVisibleChanged();
46 void mirrorZoomedChanged();
47
48protected:
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
55private:
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
38**38**
39****************************************************************************/39****************************************************************************/
40 40
41#ifdef __GNUC__
42#pragma GCC diagnostic push
43#pragma GCC diagnostic ignored "-Wdouble-promotion"
44#endif
45
41#include <QtWidgets>46#include <QtWidgets>
42 47
48#ifdef __GNUC__
49#pragma GCC diagnostic pop
50#endif
51
43#include "FlowLayout.h"52#include "FlowLayout.h"
44//! [1]53//! [1]
45FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)54FlowLayout::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
56 56
57 this->QDialog::setLayout(form);57 this->QDialog::setLayout(form);
58 58
59 _wasMoved = false;
60 _previousRect = Application::getInstance()->getWindow()->rect();
61 Application::getInstance()->getWindow()->activateWindow();59 Application::getInstance()->getWindow()->activateWindow();
62 60
63 // watch for our application window moving screens. If it does we want to update our screen details61 // watch for our application window moving screens. If it does we want to update our screen details
@@ -136,24 +134,6 @@ void HMDToolsDialog::enterHDMMode() { · 72 unmodified lines
136 if (!_inHDMMode) {134 if (!_inHDMMode) {
137 _switchModeButton->setText("Leave HMD Mode");135 _switchModeButton->setText("Leave HMD Mode");
138 _debugDetails->setText(getDebugDetails());136 _debugDetails->setText(getDebugDetails());
139
140 _hmdScreenNumber = OculusManager::getHMDScreen();
141
142 if (_hmdScreenNumber >= 0) {
143 QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle();
144 _hmdScreen = QGuiApplication::screens()[_hmdScreenNumber];
145
146 _previousRect = Application::getInstance()->getWindow()->rect();
147 _previousRect = QRect(mainWindow->mapToGlobal(_previousRect.topLeft()),
148 mainWindow->mapToGlobal(_previousRect.bottomRight()));
149 _previousScreen = mainWindow->screen();
150 QRect rect = QApplication::desktop()->screenGeometry(_hmdScreenNumber);
151 mainWindow->setScreen(_hmdScreen);
152 mainWindow->setGeometry(rect);
153
154 _wasMoved = true;
155 }
156
157 137
158 // if we're on a single screen setup, then hide our tools window when entering HMD mode138 // if we're on a single screen setup, then hide our tools window when entering HMD mode
159 if (QApplication::desktop()->screenCount() == 1) {139 if (QApplication::desktop()->screenCount() == 1) {
@@ -161,58 +141,21 @@ void HMDToolsDialog::enterHDMMode() { · 1 unmodified line
161 }141 }
162 142
163 Application::getInstance()->setEnableVRMode(true);143 Application::getInstance()->setEnableVRMode(true);
164 144
165 const int SLIGHT_DELAY = 500;
166 // If we go to fullscreen immediately, it ends up on the primary monitor,
167 // even though we've already moved the window. By adding this delay, the
168 // fullscreen target screen ends up correct.
169 QTimer::singleShot(SLIGHT_DELAY, this, [&]{
170 Application::getInstance()->setFullscreen(true);
171 activateWindowAfterEnterMode();
172 });
173
174 _inHDMMode = true;145 _inHDMMode = true;
175 }146 }
176}147}
177 148
178void HMDToolsDialog::activateWindowAfterEnterMode() {
179 Application::getInstance()->getWindow()->activateWindow();
180
181 // center the cursor on the main application window
182 centerCursorOnWidget(Application::getInstance()->getWindow());
183}
184
185void HMDToolsDialog::leaveHDMMode() {149void HMDToolsDialog::leaveHDMMode() {
186 if (_inHDMMode) {150 if (_inHDMMode) {
187 _switchModeButton->setText("Enter HMD Mode");151 _switchModeButton->setText("Enter HMD Mode");
188 _debugDetails->setText(getDebugDetails());152 _debugDetails->setText(getDebugDetails());
189
190 Application::getInstance()->setEnableVRMode(false);153 Application::getInstance()->setEnableVRMode(false);
191 Application::getInstance()->setFullscreen(false);
192 Application::getInstance()->getWindow()->activateWindow();154 Application::getInstance()->getWindow()->activateWindow();
193
194 if (_wasMoved) {
195 QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle();
196 mainWindow->setScreen(_previousScreen);
197 mainWindow->setGeometry(_previousRect);
198
199 const int SLIGHT_DELAY = 1500;
200 QTimer::singleShot(SLIGHT_DELAY, this, SLOT(moveWindowAfterLeaveMode()));
201 }
202 _wasMoved = false;
203 _inHDMMode = false;155 _inHDMMode = false;
204 }156 }
205}157}
206 158
207void 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
216void HMDToolsDialog::reject() {159void HMDToolsDialog::reject() {
217 // Just regularly close upon ESC160 // Just regularly close upon ESC
218 close();161 close();
@@ -244,13 +187,15 @@ void HMDToolsDialog::hideEvent(QHideEvent* event) { · 25 unmodified lines
244 187
245void HMDToolsDialog::aboutToQuit() {188void HMDToolsDialog::aboutToQuit() {
246 if (_inHDMMode) {189 if (_inHDMMode) {
190 // FIXME this is ineffective because it doesn't trigger the menu to
191 // save the fact that VR Mode is not checked.
247 leaveHDMMode();192 leaveHDMMode();
248 }193 }
249}194}
250 195
251void HMDToolsDialog::screenCountChanged(int newCount) {196void HMDToolsDialog::screenCountChanged(int newCount) {
252 if (!OculusManager::isConnected()) {197 if (!OculusManager::isConnected()) {
253 OculusManager::connect();198 //OculusManager::connect();
254 }199 }
255 int hmdScreenNumber = OculusManager::getHMDScreen();200 int hmdScreenNumber = OculusManager::getHMDScreen();
256 201
interface/src/ui/HMDToolsDialog.h+0−4
@@ -35,8 +35,6 @@ signals: · 34 unmodified lines
35public slots:35public slots:
36 void reject();36 void reject();
37 void switchModeClicked(bool checked);37 void switchModeClicked(bool checked);
38 void activateWindowAfterEnterMode();
39 void moveWindowAfterLeaveMode();
40 void applicationWindowScreenChanged(QScreen* screen);38 void applicationWindowScreenChanged(QScreen* screen);
41 void aboutToQuit(); 39 void aboutToQuit();
42 void screenCountChanged(int newCount);40 void screenCountChanged(int newCount);
@@ -51,8 +49,6 @@ private: · 8 unmodified lines
51 void enterHDMMode();49 void enterHDMMode();
52 void leaveHDMMode();50 void leaveHDMMode();
53 51
54 bool _wasMoved;
55 QRect _previousRect;
56 QScreen* _previousScreen;52 QScreen* _previousScreen;
57 QScreen* _hmdScreen;53 QScreen* _hmdScreen;
58 int _hmdScreenNumber;54 int _hmdScreenNumber;
interface/src/ui/LogDialog.cpp+9−0
@@ -11,10 +11,19 @@ · 10 unmodified lines
11 11
12#include "InterfaceConfig.h"12#include "InterfaceConfig.h"
13 13
14#ifdef __GNUC__
15#pragma GCC diagnostic push
16#pragma GCC diagnostic ignored "-Wdouble-promotion"
17#endif
18
14#include <QDesktopWidget>19#include <QDesktopWidget>
15#include <QTextBlock>20#include <QTextBlock>
16#include <QtGui>21#include <QtGui>
17 22
23#ifdef __GNUC__
24#pragma GCC diagnostic pop
25#endif
26
18#include <PathUtils.h>27#include <PathUtils.h>
19#include <SharedUtil.h>28#include <SharedUtil.h>
20 29
interface/src/ui/PreferencesDialog.cpp+2−2
@@ -175,7 +175,7 @@ void PreferencesDialog::loadPreferences() { · 174 unmodified lines
175 175
176 ui.maxOctreePPSSpin->setValue(qApp->getMaxOctreePacketsPerSecond());176 ui.maxOctreePPSSpin->setValue(qApp->getMaxOctreePacketsPerSecond());
177 177
178 ui.oculusUIAngularSizeSpin->setValue(qApp->getApplicationOverlay().getHmdUIAngularSize());178 ui.oculusUIAngularSizeSpin->setValue(qApp->getApplicationCompositor().getHmdUIAngularSize());
179 179
180 SixenseManager& sixense = SixenseManager::getInstance();180 SixenseManager& sixense = SixenseManager::getInstance();
181 ui.sixenseReticleMoveSpeedSpin->setValue(sixense.getReticleMoveSpeed());181 ui.sixenseReticleMoveSpeedSpin->setValue(sixense.getReticleMoveSpeed());
@@ -239,7 +239,7 @@ void PreferencesDialog::savePreferences() { · 57 unmodified lines
239 239
240 qApp->setMaxOctreePacketsPerSecond(ui.maxOctreePPSSpin->value());240 qApp->setMaxOctreePacketsPerSecond(ui.maxOctreePPSSpin->value());
241 241
242 qApp->getApplicationOverlay().setHmdUIAngularSize(ui.oculusUIAngularSizeSpin->value());242 qApp->getApplicationCompositor().setHmdUIAngularSize(ui.oculusUIAngularSizeSpin->value());
243 243
244 SixenseManager& sixense = SixenseManager::getInstance();244 SixenseManager& sixense = SixenseManager::getInstance();
245 sixense.setReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value());245 sixense.setReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value());
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
24const int ICON_SIZE = 24;
25const int ICON_PADDING = 5;
26
27const char SETTINGS_GROUP_NAME[] = "Rear View Tools";
28const char ZOOM_LEVEL_SETTINGS[] = "ZoomLevel";
29Setting::Handle<int> RearMirrorTools::rearViewZoomLevel(QStringList() << SETTINGS_GROUP_NAME << ZOOM_LEVEL_SETTINGS,
30 ZoomLevel::HEAD);
31
32RearMirrorTools::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
49void 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
66bool 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
101void 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
18enum ZoomLevel {
19 HEAD = 0,
20 BODY = 1
21};
22
23class RearMirrorTools : public QObject {
24 Q_OBJECT
25public:
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
32signals:
33 void closeView();
34 void shrinkView();
35 void resetView();
36 void restoreView();
37
38private:
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 @@
1//1//
2// Stats.cpp2// Created by Bradley Austin Davis 2015/06/17
3// interface/src/ui
4//
5// Created by Lucas Crisman on 22/03/14.
6// Copyright 2013 High Fidelity, Inc.3// Copyright 2013 High Fidelity, Inc.
7//4//
8// Distributed under the Apache License, Version 2.0.5// Distributed under the Apache License, Version 2.0.
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html6// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//7//
11 8
12#include <sstream>9#include <gpu/GPUConfig.h>
13 10
14#include <stdlib.h>11#include "Stats.h"
12
13#include <sstream>
14#include <QFontDatabase>
15 15
16#include <glm/glm.hpp>16#include <glm/glm.hpp>
17#include <glm/gtx/component_wise.hpp>17#include <glm/gtx/component_wise.hpp>
@@ -25,147 +25,31 @@ · 7 unmodified lines
25#include <LODManager.h>25#include <LODManager.h>
26#include <PerfStat.h>26#include <PerfStat.h>
27 27
28#include "Stats.h"
29#include "BandwidthRecorder.h"28#include "BandwidthRecorder.h"
30#include "InterfaceConfig.h"29#include "InterfaceConfig.h"
31#include "Menu.h"30#include "Menu.h"
32#include "Util.h"31#include "Util.h"
33#include "SequenceNumberStats.h"32#include "SequenceNumberStats.h"
34 33
35using namespace std;34HIFI_QML_DEF(Stats)
36 35
37const int STATS_PELS_PER_LINE = 16;36using namespace std;
38const int STATS_PELS_INITIALOFFSET = 12;
39 37
40const int STATS_GENERAL_MIN_WIDTH = 165; 38static Stats* INSTANCE{ nullptr };
41const int STATS_PING_MIN_WIDTH = 190;
42const int STATS_GEO_MIN_WIDTH = 240;
43const int STATS_OCTREE_MIN_WIDTH = 410;
44 39
45Stats* Stats::getInstance() {40Stats* Stats::getInstance() {
46 static Stats stats;41 if (!INSTANCE) {
47 return &stats;42 Stats::registerType();
48}43 Stats::show();
49 44 Q_ASSERT(INSTANCE);
50Stats::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
64void 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
70void 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
125void Stats::resetWidth(int width, int horizontalOffset) {
126 auto canvasSize = Application::getInstance()->getCanvasSize();
127 int extraSpace = canvasSize.x - horizontalOffset - 2
128 - STATS_GENERAL_MIN_WIDTH
129 - (Menu::getInstance()->isOptionChecked(MenuOption::TestPing) ? STATS_PING_MIN_WIDTH -1 : 0)
130 - STATS_GEO_MIN_WIDTH
131 - STATS_OCTREE_MIN_WIDTH;
132
133 int panels = 4;
134
135 _generalStatsWidth = STATS_GENERAL_MIN_WIDTH;
136 if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
137 _pingStatsWidth = STATS_PING_MIN_WIDTH;
138 } else {
139 _pingStatsWidth = 0;
140 panels = 3;
141 }
142 _geoStatsWidth = STATS_GEO_MIN_WIDTH;
143 _octreeStatsWidth = STATS_OCTREE_MIN_WIDTH;
144
145 if (extraSpace > panels) {
146 _generalStatsWidth += (int) extraSpace / panels;
147 if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
148 _pingStatsWidth += (int) extraSpace / panels;
149 }
150 _geoStatsWidth += (int) extraSpace / panels;
151 _octreeStatsWidth += canvasSize.x -
152 (_generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3);
153 }45 }
46 return INSTANCE;
154}47}
155 48
156 49Stats::Stats(QQuickItem* parent) : QQuickItem(parent) {
157// translucent background box that makes stats more readable50 INSTANCE = this;
158void Stats::drawBackground(unsigned int rgba, int x, int y, int width, int height) {51 const QFont font = QFontDatabase::systemFont(QFontDatabase::FixedFont);
159 glm::vec4 color(((rgba >> 24) & 0xff) / 255.0f,52 _monospaceFont = font.family();
160 ((rgba >> 16) & 0xff) / 255.0f,
161 ((rgba >> 8) & 0xff) / 255.0f,
162 (rgba & 0xff) / 255.0f);
163
164 // FIX ME: is this correct? It seems to work to fix textures bleeding into us...
165 glBindTexture(GL_TEXTURE_2D, 0);
166 glDisable(GL_TEXTURE_2D);
167
168 DependencyManager::get<GeometryCache>()->renderQuad(x, y, width, height, color);
169}53}
170 54
171bool Stats::includeTimingRecord(const QString& name) {55bool Stats::includeTimingRecord(const QString& name) {
@@ -190,161 +74,70 @@ bool Stats::includeTimingRecord(const QString& name) { · 18 unmodified lines
190 return false;74 return false;
191}75}
192 76
193// display expanded or contracted stats77#define STAT_UPDATE(name, src) \
194void Stats::display(78 { \
195 const float* color, 79 auto val = src; \
196 int horizontalOffset, 80 if (_##name != val) { \
197 float fps, 81 _##name = val; \
198 int inPacketsPerSecond,82 emit name##Changed(); \
199 int outPacketsPerSecond,83 } \
200 int inKbitsPerSecond,
201 int outKbitsPerSecond,
202 int voxelPacketsToProcess)
203{
204 auto canvasSize = Application::getInstance()->getCanvasSize();
205
206 unsigned int backgroundColor = 0x33333399;
207 int verticalOffset = 0, lines = 0;
208 float scale = 0.10f;
209 float rotation = 0.0f;
210 int font = 2;
211
212 QLocale locale(QLocale::English);
213 std::stringstream octreeStats;
214
215 QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
216
217 if (_lastHorizontalOffset != horizontalOffset) {
218 resetWidth(canvasSize.x, horizontalOffset);
219 _lastHorizontalOffset = horizontalOffset;
220 }84 }
221 85
222 glPointSize(1.0f);86#define STAT_UPDATE_FLOAT(name, src, epsilon) \
223 87 { \
224 // we need to take one avatar out so we don't include ourselves88 float val = src; \
225 int totalAvatars = DependencyManager::get<AvatarManager>()->size() - 1;89 if (fabs(_##name - val) >= epsilon) { \
226 int totalServers = DependencyManager::get<NodeList>()->size();90 _##name = val; \
227 91 emit name##Changed(); \
228 lines = 5;92 } \
229 int columnOneWidth = _generalStatsWidth;
230
231 bool performanceTimerIsActive = PerformanceTimer::isActive();
232 bool displayPerf = _expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails);
233 if (displayPerf && performanceTimerIsActive) {
234 PerformanceTimer::tallyAllTimerRecords(); // do this even if we're not displaying them, so they don't stack up
235
236 columnOneWidth = _generalStatsWidth + _pingStatsWidth + _geoStatsWidth; // 3 columns wide...
237 // we will also include room for 1 line per timing record and a header of 4 lines
238 lines += 4;
239
240 const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
241 QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
242 bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen);
243 int statsLines = 0;
244 while (i.hasNext()) {
245 i.next();
246 if (includeTimingRecord(i.key())) {
247 lines++;
248 statsLines++;
249 if (onlyDisplayTopTen && statsLines == 10) {
250 break;
251 }
252 }
253 }
254 }93 }
255
256 drawBackground(backgroundColor, horizontalOffset, 0, columnOneWidth, (lines + 1) * STATS_PELS_PER_LINE);
257 horizontalOffset += 5;
258
259 int columnOneHorizontalOffset = horizontalOffset;
260
261 QString serverNodes = QString("Servers: %1").arg(totalServers);
262 QString avatarNodes = QString("Avatars: %1").arg(totalAvatars);
263 QString framesPerSecond = QString("Framerate: %1 FPS").arg(fps, 3, 'f', 0);
264
265 verticalOffset = STATS_PELS_INITIALOFFSET; // first one is offset by less than a line
266 drawText(horizontalOffset, verticalOffset, scale, rotation, font, serverNodes.toUtf8().constData(), color);
267 verticalOffset += STATS_PELS_PER_LINE;
268 drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarNodes.toUtf8().constData(), color);
269 verticalOffset += STATS_PELS_PER_LINE;
270 drawText(horizontalOffset, verticalOffset, scale, rotation, font, framesPerSecond.toUtf8().constData(), color);
271
272 QString packetsPerSecondString = QString("Packets In/Out: %1/%2").arg(inPacketsPerSecond).arg(outPacketsPerSecond);
273 QString averageMegabitsPerSecond = QString("Mbps In/Out: %1/%2").
274 arg((float)inKbitsPerSecond * 1.0f / 1000.0f).
275 arg((float)outKbitsPerSecond * 1.0f / 1000.0f);
276
277 verticalOffset += STATS_PELS_PER_LINE;
278 drawText(horizontalOffset, verticalOffset, scale, rotation, font, packetsPerSecondString.toUtf8().constData(), color);
279 verticalOffset += STATS_PELS_PER_LINE;
280 drawText(horizontalOffset, verticalOffset, scale, rotation, font, averageMegabitsPerSecond.toUtf8().constData(), color);
281 94
282
283 // TODO: the display of these timing details should all be moved to JavaScript
284 if (displayPerf && performanceTimerIsActive) {
285 bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen);
286 // Timing details...
287 verticalOffset += STATS_PELS_PER_LINE * 4; // skip 3 lines to be under the other columns
288 drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font,
289 "-------------------------------------------------------- Function "
290 "------------------------------------------------------- --msecs- -calls--", color);
291
292 // First iterate all the records, and for the ones that should be included, insert them into
293 // a new Map sorted by average time...
294 QMap<float, QString> sortedRecords;
295 const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
296 QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
297 95
298 while (i.hasNext()) {96void Stats::updateStats() {
299 i.next();97 if (!Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
300 if (includeTimingRecord(i.key())) {98 if (isVisible()) {
301 float averageTime = (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC;99 setVisible(false);
302 sortedRecords.insertMulti(averageTime, i.key());
303 }
304 }100 }
305 101 return;
306 int linesDisplayed = 0;102 } else {
307 QMapIterator<float, QString> j(sortedRecords);103 if (!isVisible()) {
308 j.toBack();104 setVisible(true);
309 while (j.hasPrevious()) {
310 j.previous();
311 QChar noBreakingSpace = QChar::Nbsp;
312 QString functionName = j.value();
313 const PerformanceTimerRecord& record = allRecords.value(functionName);
314
315 QString perfLine = QString("%1: %2 [%3]").
316 arg(QString(qPrintable(functionName)), 120, noBreakingSpace).
317 arg((float)record.getMovingAverage() / (float)USECS_PER_MSEC, 8, 'f', 3, noBreakingSpace).
318 arg((int)record.getCount(), 6, 10, noBreakingSpace);
319
320 verticalOffset += STATS_PELS_PER_LINE;
321 drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font, perfLine.toUtf8().constData(), color);
322 linesDisplayed++;
323 if (onlyDisplayTopTen && linesDisplayed == 10) {
324 break;
325 }
326 }105 }
327 }106 }
328 107
108 bool shouldDisplayTimingDetail = Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) &&
109 Menu::getInstance()->isOptionChecked(MenuOption::Stats) && isExpanded();
110 if (shouldDisplayTimingDetail != PerformanceTimer::isActive()) {
111 PerformanceTimer::setActive(shouldDisplayTimingDetail);
112 }
329 113
330 verticalOffset = STATS_PELS_INITIALOFFSET;
331 horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + 1;
332 114
333 if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {115 auto nodeList = DependencyManager::get<NodeList>();
334 int pingAudio = -1, pingAvatar = -1, pingVoxel = -1, pingOctreeMax = -1;116 auto avatarManager = DependencyManager::get<AvatarManager>();
117 // we need to take one avatar out so we don't include ourselves
118 STAT_UPDATE(avatarCount, avatarManager->size() - 1);
119 STAT_UPDATE(serverCount, nodeList->size());
120 STAT_UPDATE(framerate, (int)qApp->getFps());
121
122 auto bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
123 STAT_UPDATE(packetInCount, bandwidthRecorder->getCachedTotalAverageInputPacketsPerSecond());
124 STAT_UPDATE(packetOutCount, bandwidthRecorder->getCachedTotalAverageOutputPacketsPerSecond());
125 STAT_UPDATE_FLOAT(mbpsIn, (float)bandwidthRecorder->getCachedTotalAverageOutputKilobitsPerSecond() / 1000.0f, 0.01f);
126 STAT_UPDATE_FLOAT(mbpsOut, (float)bandwidthRecorder->getCachedTotalAverageInputKilobitsPerSecond() / 1000.0f, 0.01f);
335 127
336 auto nodeList = DependencyManager::get<NodeList>();128 // Second column: ping
129 if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
337 SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer);130 SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer);
338 SharedNodePointer avatarMixerNode = nodeList->soloNodeOfType(NodeType::AvatarMixer);131 SharedNodePointer avatarMixerNode = nodeList->soloNodeOfType(NodeType::AvatarMixer);
132 STAT_UPDATE(audioPing, audioMixerNode ? audioMixerNode->getPingMs() : -1);
133 STAT_UPDATE(avatarPing, avatarMixerNode ? avatarMixerNode->getPingMs() : -1);
339 134
340 pingAudio = audioMixerNode ? audioMixerNode->getPingMs() : -1;135 //// Now handle voxel servers, since there could be more than one, we average their ping times
341 pingAvatar = avatarMixerNode ? avatarMixerNode->getPingMs() : -1;
342
343 // Now handle voxel servers, since there could be more than one, we average their ping times
344 unsigned long totalPingOctree = 0;136 unsigned long totalPingOctree = 0;
345 int octreeServerCount = 0;137 int octreeServerCount = 0;
346 138 int pingOctreeMax = 0;
347 nodeList->eachNode([&totalPingOctree, &pingOctreeMax, &octreeServerCount](const SharedNodePointer& node){139 int pingVoxel;
140 nodeList->eachNode([&](const SharedNodePointer& node) {
348 // TODO: this should also support entities141 // TODO: this should also support entities
349 if (node->getType() == NodeType::EntityServer) {142 if (node->getType() == NodeType::EntityServer) {
350 totalPingOctree += node->getPingMs();143 totalPingOctree += node->getPingMs();
@@ -359,168 +152,85 @@ void Stats::display( · 8 unmodified lines
359 pingVoxel = totalPingOctree / octreeServerCount;152 pingVoxel = totalPingOctree / octreeServerCount;
360 }153 }
361 154
362 lines = _expanded ? 4 : 3;155 //STAT_UPDATE(entitiesPing, pingVoxel);
363 156 //if (_expanded) {
364 // only draw our background if column one didn't draw a wide background157 // QString voxelMaxPing;
365 if (columnOneWidth == _generalStatsWidth) {158 // if (pingVoxel >= 0) { // Average is only meaningful if pingVoxel is valid.
366 drawBackground(backgroundColor, horizontalOffset, 0, _pingStatsWidth, (lines + 1) * STATS_PELS_PER_LINE);159 // voxelMaxPing = QString("Voxel max ping: %1").arg(pingOctreeMax);
367 }160 // } else {
368 horizontalOffset += 5;161 // voxelMaxPing = QString("Voxel max ping: --");
369 162 // }
370 163 } else {
371 QString audioPing;164 // -2 causes the QML to hide the ping column
372 if (pingAudio >= 0) {165 STAT_UPDATE(audioPing, -2);
373 audioPing = QString("Audio ping: %1").arg(pingAudio);
374 } else {
375 audioPing = QString("Audio ping: --");
376 }
377
378 QString avatarPing;
379 if (pingAvatar >= 0) {
380 avatarPing = QString("Avatar ping: %1").arg(pingAvatar);
381 } else {
382 avatarPing = QString("Avatar ping: --");
383 }
384
385 QString voxelAvgPing;
386 if (pingVoxel >= 0) {
387 voxelAvgPing = QString("Entities avg ping: %1").arg(pingVoxel);
388 } else {
389 voxelAvgPing = QString("Entities avg ping: --");
390 }
391
392 drawText(horizontalOffset, verticalOffset, scale, rotation, font, audioPing.toUtf8().constData(), color);
393 verticalOffset += STATS_PELS_PER_LINE;
394 drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarPing.toUtf8().constData(), color);
395 verticalOffset += STATS_PELS_PER_LINE;
396 drawText(horizontalOffset, verticalOffset, scale, rotation, font, voxelAvgPing.toUtf8().constData(), color);
397
398 if (_expanded) {
399 QString voxelMaxPing;
400 if (pingVoxel >= 0) { // Average is only meaningful if pingVoxel is valid.
401 voxelMaxPing = QString("Voxel max ping: %1").arg(pingOctreeMax);
402 } else {
403 voxelMaxPing = QString("Voxel max ping: --");
404 }
405
406 verticalOffset += STATS_PELS_PER_LINE;
407 drawText(horizontalOffset, verticalOffset, scale, rotation, font, voxelMaxPing.toUtf8().constData(), color);
408 }
409
410 verticalOffset = STATS_PELS_INITIALOFFSET;
411 horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + _pingStatsWidth + 2;
412 }166 }
413 167
414 MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
415 glm::vec3 avatarPos = myAvatar->getPosition();
416
417 lines = _expanded ? 7 : 3;
418
419 if (columnOneWidth == _generalStatsWidth) {
420 drawBackground(backgroundColor, horizontalOffset, 0, _geoStatsWidth, (lines + 1) * STATS_PELS_PER_LINE);
421 }
422 horizontalOffset += 5;
423
424 QString avatarPosition = QString("Position: %1, %2, %3").
425 arg(avatarPos.x, -1, 'f', 1).
426 arg(avatarPos.y, -1, 'f', 1).
427 arg(avatarPos.z, -1, 'f', 1);
428 QString avatarVelocity = QString("Velocity: %1").arg(glm::length(myAvatar->getVelocity()), -1, 'f', 1);
429 QString avatarBodyYaw = QString("Yaw: %1").arg(myAvatar->getBodyYaw(), -1, 'f', 1);
430 QString avatarMixerStats;
431
432 drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarPosition.toUtf8().constData(), color);
433 verticalOffset += STATS_PELS_PER_LINE;
434 drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarVelocity.toUtf8().constData(), color);
435 verticalOffset += STATS_PELS_PER_LINE;
436 drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarBodyYaw.toUtf8().constData(), color);
437 168
169 // Third column, avatar stats
170 MyAvatar* myAvatar = avatarManager->getMyAvatar();
171 glm::vec3 avatarPos = myAvatar->getPosition();
172 STAT_UPDATE(position, QVector3D(avatarPos.x, avatarPos.y, avatarPos.z));
173 STAT_UPDATE_FLOAT(velocity, glm::length(myAvatar->getVelocity()), 0.1f);
174 STAT_UPDATE_FLOAT(yaw, myAvatar->getBodyYaw(), 0.1f);
438 if (_expanded) {175 if (_expanded) {
439 SharedNodePointer avatarMixer = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::AvatarMixer);176 SharedNodePointer avatarMixer = nodeList->soloNodeOfType(NodeType::AvatarMixer);
440 if (avatarMixer) {177 if (avatarMixer) {
441 avatarMixerStats = QString("Avatar Mixer: %1 kbps, %2 pps").178 STAT_UPDATE(avatarMixerKbps, roundf(
442 arg(roundf(bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer) +179 bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AvatarMixer) +
443 bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AudioMixer))).180 bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AvatarMixer)));
444 arg(roundf(bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer) +181 STAT_UPDATE(avatarMixerPps, roundf(
445 bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer)));182 bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AvatarMixer) +
183 bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AvatarMixer)));
446 } else {184 } else {
447 avatarMixerStats = QString("No Avatar Mixer");185 STAT_UPDATE(avatarMixerKbps, -1);
186 STAT_UPDATE(avatarMixerPps, -1);
448 }187 }
449 188 SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer);
450 verticalOffset += STATS_PELS_PER_LINE;189 if (audioMixerNode) {
451 drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarMixerStats.toUtf8().constData(), color);190 STAT_UPDATE(audioMixerKbps, roundf(
452 191 bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer) +
453 stringstream downloads;192 bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AudioMixer)));
454 downloads << "Downloads: ";193 STAT_UPDATE(audioMixerPps, roundf(
455 foreach (Resource* resource, ResourceCache::getLoadingRequests()) {194 bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer) +
456 downloads << (int)(resource->getProgress() * 100.0f) << "% ";195 bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer)));
196 } else {
197 STAT_UPDATE(audioMixerKbps, -1);
198 STAT_UPDATE(audioMixerPps, -1);
457 }199 }
458 downloads << "(" << ResourceCache::getPendingRequestCount() << " pending)";
459
460 verticalOffset += STATS_PELS_PER_LINE;
461 drawText(horizontalOffset, verticalOffset, scale, rotation, font, downloads.str().c_str(), color);
462 }
463 200
464 verticalOffset = STATS_PELS_INITIALOFFSET;201 STAT_UPDATE(downloads, ResourceCache::getLoadingRequests().size());
465 horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3;202 STAT_UPDATE(downloadsPending, ResourceCache::getPendingRequestCount());
466 203 // TODO fix to match original behavior
467 lines = _expanded ? 10 : 3;204 //stringstream downloads;
468 205 //downloads << "Downloads: ";
469 drawBackground(backgroundColor, horizontalOffset, 0, canvasSize.x - horizontalOffset,206 //foreach(Resource* resource, ) {
470 (lines + 1) * STATS_PELS_PER_LINE);207 // downloads << (int)(resource->getProgress() * 100.0f) << "% ";
471 horizontalOffset += 5;208 //}
472 209 //downloads << "(" << << " pending)";
473 // Model/Entity render details210 } // expanded avatar column
474 octreeStats.str("");211
475 octreeStats << "Triangles: " << _renderDetails._trianglesRendered212 // Fourth column, octree stats
476 << " / Quads:" << _renderDetails._quadsRendered
477 << " / Material Switches:" << _renderDetails._materialSwitches;
478 drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
479
480 if (_expanded) {
481 octreeStats.str("");
482 octreeStats << " Mesh Parts Rendered Opaque: " << _renderDetails._opaque._rendered
483 << " / Translucent:" << _renderDetails._translucent._rendered;
484 verticalOffset += STATS_PELS_PER_LINE;
485 drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
486
487 octreeStats.str("");
488 octreeStats << " Opaque considered: " << _renderDetails._opaque._considered
489 << " / Out of view:" << _renderDetails._opaque._outOfView
490 << " / Too small:" << _renderDetails._opaque._tooSmall;
491 verticalOffset += STATS_PELS_PER_LINE;
492 drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
493
494 octreeStats.str("");
495 octreeStats << " Translucent considered: " << _renderDetails._translucent._considered
496 << " / Out of view:" << _renderDetails._translucent._outOfView
497 << " / Too small:" << _renderDetails._translucent._tooSmall;
498 verticalOffset += STATS_PELS_PER_LINE;
499 drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
500 }
501
502 // iterate all the current voxel stats, and list their sending modes, and total voxel counts
503 std::stringstream sendingMode("");
504 sendingMode << "Octree Sending Mode: [";
505 int serverCount = 0;213 int serverCount = 0;
506 int movingServerCount = 0;214 int movingServerCount = 0;
507 unsigned long totalNodes = 0;215 unsigned long totalNodes = 0;
508 unsigned long totalInternal = 0;216 unsigned long totalInternal = 0;
509 unsigned long totalLeaves = 0;217 unsigned long totalLeaves = 0;
218 std::stringstream sendingModeStream("");
219 sendingModeStream << "[";
510 NodeToOctreeSceneStats* octreeServerSceneStats = Application::getInstance()->getOcteeSceneStats();220 NodeToOctreeSceneStats* octreeServerSceneStats = Application::getInstance()->getOcteeSceneStats();
511 for(NodeToOctreeSceneStatsIterator i = octreeServerSceneStats->begin(); i != octreeServerSceneStats->end(); i++) {221 for (NodeToOctreeSceneStatsIterator i = octreeServerSceneStats->begin(); i != octreeServerSceneStats->end(); i++) {
512 //const QUuid& uuid = i->first;222 //const QUuid& uuid = i->first;
513 OctreeSceneStats& stats = i->second;223 OctreeSceneStats& stats = i->second;
514 serverCount++;224 serverCount++;
515 if (_expanded) {225 if (_expanded) {
516 if (serverCount > 1) {226 if (serverCount > 1) {
517 sendingMode << ",";227 sendingModeStream << ",";
518 }228 }
519 if (stats.isMoving()) {229 if (stats.isMoving()) {
520 sendingMode << "M";230 sendingModeStream << "M";
521 movingServerCount++;231 movingServerCount++;
522 } else {232 } else {
523 sendingMode << "S";233 sendingModeStream << "S";
524 }234 }
525 }235 }
526 236
@@ -528,32 +238,35 @@ void Stats::display( · 1 unmodified line
528 totalNodes += stats.getTotalElements();238 totalNodes += stats.getTotalElements();
529 if (_expanded) {239 if (_expanded) {
530 totalInternal += stats.getTotalInternal();240 totalInternal += stats.getTotalInternal();
531 totalLeaves += stats.getTotalLeaves(); 241 totalLeaves += stats.getTotalLeaves();
532 }242 }
533 }243 }
534 if (_expanded) {244 if (_expanded) {
535 if (serverCount == 0) {245 if (serverCount == 0) {
536 sendingMode << "---";246 sendingModeStream << "---";
537 }247 }
538 sendingMode << "] " << serverCount << " servers";248 sendingModeStream << "] " << serverCount << " servers";
539 if (movingServerCount > 0) {249 if (movingServerCount > 0) {
540 sendingMode << " <SCENE NOT STABLE>";250 sendingModeStream << " <SCENE NOT STABLE>";
541 } else {251 } else {
542 sendingMode << " <SCENE STABLE>";252 sendingModeStream << " <SCENE STABLE>";
543 }253 }
544 verticalOffset += STATS_PELS_PER_LINE;254 QString sendingModeResult = sendingModeStream.str().c_str();
545 drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)sendingMode.str().c_str(), color);255 STAT_UPDATE(sendingMode, sendingModeResult);
546 }256 }
547 257
548 // Incoming packets258 // Incoming packets
259 QLocale locale(QLocale::English);
260 auto voxelPacketsToProcess = qApp->getOctreePacketProcessor().packetsToProcessCount();
549 if (_expanded) {261 if (_expanded) {
550 octreeStats.str("");262 std::stringstream octreeStats;
551 QString packetsString = locale.toString((int)voxelPacketsToProcess);263 QString packetsString = locale.toString((int)voxelPacketsToProcess);
552 QString maxString = locale.toString((int)_recentMaxPackets);264 QString maxString = locale.toString((int)_recentMaxPackets);
553 octreeStats << "Octree Packets to Process: " << qPrintable(packetsString)265 octreeStats << "Octree Packets to Process: " << qPrintable(packetsString)
554 << " [Recent Max: " << qPrintable(maxString) << "]"; 266 << " [Recent Max: " << qPrintable(maxString) << "]";
555 verticalOffset += STATS_PELS_PER_LINE;267 QString str = octreeStats.str().c_str();
556 drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);268 STAT_UPDATE(packetStats, str);
269 // drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
557 }270 }
558 271
559 if (_resetRecentMaxPacketsSoon && voxelPacketsToProcess > 0) {272 if (_resetRecentMaxPacketsSoon && voxelPacketsToProcess > 0) {
@@ -562,60 +275,102 @@ void Stats::display( · 2 unmodified lines
562 }275 }
563 if (voxelPacketsToProcess == 0) {276 if (voxelPacketsToProcess == 0) {
564 _resetRecentMaxPacketsSoon = true;277 _resetRecentMaxPacketsSoon = true;
565 } else {278 } else if (voxelPacketsToProcess > _recentMaxPackets) {
566 if (voxelPacketsToProcess > _recentMaxPackets) {279 _recentMaxPackets = voxelPacketsToProcess;
567 _recentMaxPackets = voxelPacketsToProcess;
568 }
569 }280 }
570 281
571 QString serversTotalString = locale.toString((uint)totalNodes); // consider adding: .rightJustified(10, ' ');
572 unsigned long localTotal = OctreeElement::getNodeCount();
573 QString localTotalString = locale.toString((uint)localTotal); // consider adding: .rightJustified(10, ' ');
574
575 // Server Octree Elements282 // Server Octree Elements
576 if (!_expanded) {283 STAT_UPDATE(serverElements, totalNodes);
577 octreeStats.str("");284 STAT_UPDATE(localElements, OctreeElement::getNodeCount());
578 octreeStats << "Octree Elements Server: " << qPrintable(serversTotalString)
579 << " Local:" << qPrintable(localTotalString);
580 verticalOffset += STATS_PELS_PER_LINE;
581 drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
582 }
583 285
584 if (_expanded) {286 if (_expanded) {
585 octreeStats.str("");287 STAT_UPDATE(serverInternal, totalInternal);
586 octreeStats << "Octree Elements -";288 STAT_UPDATE(serverLeaves, totalLeaves);
587 verticalOffset += STATS_PELS_PER_LINE;289 // Local Voxels
588 drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);290 STAT_UPDATE(localInternal, OctreeElement::getInternalNodeCount());
291 STAT_UPDATE(localLeaves, OctreeElement::getLeafNodeCount());
292 // LOD Details
293 STAT_UPDATE(lodStatus, "You can see " + DependencyManager::get<LODManager>()->getLODFeedbackText());
294 }
589 295
590 QString serversInternalString = locale.toString((uint)totalInternal);296 bool performanceTimerIsActive = PerformanceTimer::isActive();
591 QString serversLeavesString = locale.toString((uint)totalLeaves);297 bool displayPerf = _expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails);
298 if (displayPerf && performanceTimerIsActive) {
299 if (!_timingExpanded) {
300 _timingExpanded = true;
301 emit timingExpandedChanged();
302 }
303 PerformanceTimer::tallyAllTimerRecords(); // do this even if we're not displaying them, so they don't stack up
592 304
593 octreeStats.str("");305 // we will also include room for 1 line per timing record and a header of 4 lines
594 octreeStats << " Server: " << qPrintable(serversTotalString) <<306 // Timing details...
595 " Internal: " << qPrintable(serversInternalString) <<
596 " Leaves: " << qPrintable(serversLeavesString);
597 verticalOffset += STATS_PELS_PER_LINE;
598 drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
599 307
600 // Local Voxels308 // First iterate all the records, and for the ones that should be included, insert them into
601 unsigned long localInternal = OctreeElement::getInternalNodeCount();309 // a new Map sorted by average time...
602 unsigned long localLeaves = OctreeElement::getLeafNodeCount();310 bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen);
603 QString localInternalString = locale.toString((uint)localInternal);311 QMap<float, QString> sortedRecords;
604 QString localLeavesString = locale.toString((uint)localLeaves);312 const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
605 313 QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
606 octreeStats.str("");314
607 octreeStats << " Local: " << qPrintable(serversTotalString) <<315 while (i.hasNext()) {
608 " Internal: " << qPrintable(localInternalString) <<316 i.next();
609 " Leaves: " << qPrintable(localLeavesString) << "";317 if (includeTimingRecord(i.key())) {
610 verticalOffset += STATS_PELS_PER_LINE;318 float averageTime = (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC;
611 drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);319 sortedRecords.insertMulti(averageTime, i.key());
320 }
321 }
322
323 int linesDisplayed = 0;
324 QMapIterator<float, QString> j(sortedRecords);
325 j.toBack();
326 QString perfLines;
327 while (j.hasPrevious()) {
328 j.previous();
329 static const QChar noBreakingSpace = QChar::Nbsp;
330 QString functionName = j.value();
331 const PerformanceTimerRecord& record = allRecords.value(functionName);
332 perfLines += QString("%1: %2 [%3]\n").
333 arg(QString(qPrintable(functionName)), 90, noBreakingSpace).
334 arg((float)record.getMovingAverage() / (float)USECS_PER_MSEC, 8, 'f', 3, noBreakingSpace).
335 arg((int)record.getCount(), 6, 10, noBreakingSpace);
336 linesDisplayed++;
337 if (onlyDisplayTopTen && linesDisplayed == 10) {
338 break;
339 }
340 }
341 _timingStats = perfLines;
342 emit timingStatsChanged();
343 } else if (_timingExpanded) {
344 _timingExpanded = false;
345 emit timingExpandedChanged();
612 }346 }
347}
348
349void 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
368void Stats::display(
369 int voxelPacketsToProcess)
370{
371 // iterate all the current voxel stats, and list their sending modes, and total voxel counts
613 372
614 // LOD Details
615 octreeStats.str("");
616 QString displayLODDetails = DependencyManager::get<LODManager>()->getLODFeedbackText();
617 octreeStats << "LOD: You can see " << qPrintable(displayLODDetails.trimmed());
618 verticalOffset += STATS_PELS_PER_LINE;
619 drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
620}373}
621 374
375
376*/
interface/src/ui/Stats.h+121−32
@@ -1,8 +1,5 @@
1//1//
2// Stats.h2// Created by Bradley Austin Davis 2015/06/17
3// interface/src/ui
4//
5// Created by Lucas Crisman on 22/03/14.
6// Copyright 2013 High Fidelity, Inc.3// Copyright 2013 High Fidelity, Inc.
7//4//
8// Distributed under the Apache License, Version 2.0.5// Distributed under the Apache License, Version 2.0.
@@ -13,47 +10,139 @@ · 4 unmodified lines
13#define hifi_Stats_h10#define hifi_Stats_h
14 11
15#include <QObject>12#include <QObject>
13#include <QQuickItem>
14#include <QVector3D>
16 15
16#include <OffscreenUi.h>
17#include <RenderArgs.h>17#include <RenderArgs.h>
18 18
19class Stats: public QObject {19#define STATS_PROPERTY(type, name, initialValue) \
20 Q_PROPERTY(type name READ name NOTIFY name##Changed) \
21public: \
22 type name() { return _##name; }; \
23private: \
24 type _##name{ initialValue };
25
26
27class Stats : public QQuickItem {
20 Q_OBJECT28 Q_OBJECT
29 HIFI_QML_DECL
30 Q_PROPERTY(bool expanded READ isExpanded WRITE setExpanded NOTIFY expandedChanged)
31 Q_PROPERTY(bool timingExpanded READ isTimingExpanded NOTIFY timingExpandedChanged)
32 Q_PROPERTY(QString monospaceFont READ monospaceFont)
33
34 STATS_PROPERTY(int, serverCount, 0)
35 STATS_PROPERTY(int, framerate, 0)
36 STATS_PROPERTY(int, avatarCount, 0)
37 STATS_PROPERTY(int, packetInCount, 0)
38 STATS_PROPERTY(int, packetOutCount, 0)
39 STATS_PROPERTY(float, mbpsIn, 0)
40 STATS_PROPERTY(float, mbpsOut, 0)
41 STATS_PROPERTY(int, audioPing, 0)
42 STATS_PROPERTY(int, avatarPing, 0)
43 STATS_PROPERTY(int, entitiesPing, 0)
44 STATS_PROPERTY(QVector3D, position, QVector3D(0, 0, 0) )
45 STATS_PROPERTY(float, velocity, 0)
46 STATS_PROPERTY(float, yaw, 0)
47 STATS_PROPERTY(int, avatarMixerKbps, 0)
48 STATS_PROPERTY(int, avatarMixerPps, 0)
49 STATS_PROPERTY(int, audioMixerKbps, 0)
50 STATS_PROPERTY(int, audioMixerPps, 0)
51 STATS_PROPERTY(int, downloads, 0)
52 STATS_PROPERTY(int, downloadsPending, 0)
53 STATS_PROPERTY(int, triangles, 0)
54 STATS_PROPERTY(int, quads, 0)
55 STATS_PROPERTY(int, materialSwitches, 0)
56 STATS_PROPERTY(int, meshOpaque, 0)
57 STATS_PROPERTY(int, meshTranslucent, 0)
58 STATS_PROPERTY(int, opaqueConsidered, 0)
59 STATS_PROPERTY(int, opaqueOutOfView, 0)
60 STATS_PROPERTY(int, opaqueTooSmall, 0)
61 STATS_PROPERTY(int, translucentConsidered, 0)
62 STATS_PROPERTY(int, translucentOutOfView, 0)
63 STATS_PROPERTY(int, translucentTooSmall, 0)
64 STATS_PROPERTY(QString, sendingMode, QString())
65 STATS_PROPERTY(QString, packetStats, QString())
66 STATS_PROPERTY(QString, lodStatus, QString())
67 STATS_PROPERTY(QString, timingStats, QString())
68 STATS_PROPERTY(int, serverElements, 0)
69 STATS_PROPERTY(int, serverInternal, 0)
70 STATS_PROPERTY(int, serverLeaves, 0)
71 STATS_PROPERTY(int, localElements, 0)
72 STATS_PROPERTY(int, localInternal, 0)
73 STATS_PROPERTY(int, localLeaves, 0)
21 74
22public:75public:
23 static Stats* getInstance();76 static Stats* getInstance();
24 77
25 Stats();78 Stats(QQuickItem* parent = nullptr);
26
27 static void drawBackground(unsigned int rgba, int x, int y, int width, int height);
28
29 void toggleExpanded();
30 bool isExpanded() { return _expanded; }
31
32 void checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseDragStartedY, int horizontalOffset);
33 void resetWidth(int width, int horizontalOffset);
34 void display(const float* color, int horizontalOffset, float fps, int inPacketsPerSecond, int outPacketsPerSecond,
35 int inKbitsPerSecond, int outKbitsPerSecond, int voxelPacketsToProcess);
36 bool includeTimingRecord(const QString& name);79 bool includeTimingRecord(const QString& name);
37 80 void setRenderDetails(const RenderDetails& details);
38 void setRenderDetails(const RenderDetails& details) { _renderDetails = details; }81 const QString& monospaceFont() {
39 82 return _monospaceFont;
40private:83 }
41 static Stats* _sharedInstance;84 void updateStats();
42 85
43 bool _expanded;86 bool isExpanded() { return _expanded; }
87 bool isTimingExpanded() { return _timingExpanded; }
44 88
45 int _recentMaxPackets; // recent max incoming voxel packets to process89 void setExpanded(bool expanded) {
46 bool _resetRecentMaxPacketsSoon;90 if (_expanded != expanded) {
91 _expanded = expanded;
92 emit expandedChanged();
93 }
94 }
47 95
48 int _generalStatsWidth;96signals:
49 int _bandwidthStatsWidth;97 void expandedChanged();
50 int _pingStatsWidth;98 void timingExpandedChanged();
51 int _geoStatsWidth;99 void serverCountChanged();
52 int _octreeStatsWidth;100 void framerateChanged();
101 void avatarCountChanged();
102 void packetInCountChanged();
103 void packetOutCountChanged();
104 void mbpsInChanged();
105 void mbpsOutChanged();
106 void audioPingChanged();
107 void avatarPingChanged();
108 void entitiesPingChanged();
109 void positionChanged();
110 void velocityChanged();
111 void yawChanged();
112 void avatarMixerKbpsChanged();
113 void avatarMixerPpsChanged();
114 void audioMixerKbpsChanged();
115 void audioMixerPpsChanged();
116 void downloadsChanged();
117 void downloadsPendingChanged();
118 void trianglesChanged();
119 void quadsChanged();
120 void materialSwitchesChanged();
121 void meshOpaqueChanged();
122 void meshTranslucentChanged();
123 void opaqueConsideredChanged();
124 void opaqueOutOfViewChanged();
125 void opaqueTooSmallChanged();
126 void translucentConsideredChanged();
127 void translucentOutOfViewChanged();
128 void translucentTooSmallChanged();
129 void sendingModeChanged();
130 void packetStatsChanged();
131 void lodStatusChanged();
132 void serverElementsChanged();
133 void serverInternalChanged();
134 void serverLeavesChanged();
135 void localElementsChanged();
136 void localInternalChanged();
137 void localLeavesChanged();
138 void timingStatsChanged();
53 139
54 int _lastHorizontalOffset;140private:
55 141 int _recentMaxPackets{ 0 } ; // recent max incoming voxel packets to process
56 RenderDetails _renderDetails;142 bool _resetRecentMaxPacketsSoon{ true };
143 bool _expanded{ false };
144 bool _timingExpanded{ false };
145 QString _monospaceFont;
57};146};
58 147
59#endif // hifi_Stats_h148#endif // hifi_Stats_h
interface/src/ui/UserInputMapper.cpp+1−1
@@ -53,7 +53,7 @@ void UserInputMapper::resetDevice(uint16 deviceID) { · 52 unmodified lines
53 53
54int UserInputMapper::findDevice(QString name) {54int UserInputMapper::findDevice(QString name) {
55 for (auto device : _registeredDevices) {55 for (auto device : _registeredDevices) {
56 if (device.second->_name == name) {56 if (device.second->_name.split(" (")[0] == name) {
57 return device.first;57 return device.first;
58 }58 }
59 }59 }
interface/src/ui/overlays/Circle3DOverlay.cpp+161−181
@@ -11,6 +11,7 @@ · 10 unmodified lines
11// include this before QGLWidget, which includes an earlier version of OpenGL11// include this before QGLWidget, which includes an earlier version of OpenGL
12#include "InterfaceConfig.h"12#include "InterfaceConfig.h"
13 13
14#include <DeferredLightingEffect.h>
14#include <GeometryCache.h>15#include <GeometryCache.h>
15#include <GlowEffect.h>16#include <GlowEffect.h>
16#include <SharedUtil.h>17#include <SharedUtil.h>
@@ -75,20 +76,20 @@ void Circle3DOverlay::render(RenderArgs* args) { · 58 unmodified lines
75 76
76 float alpha = getAlpha();77 float alpha = getAlpha();
77 78
78 if (alpha == 0.0) {79 if (alpha == 0.0f) {
79 return; // do nothing if our alpha is 0, we're not visible80 return; // do nothing if our alpha is 0, we're not visible
80 }81 }
81 82
82 // Create the circle in the coordinates origin83 // Create the circle in the coordinates origin
83 float outerRadius = getOuterRadius();84 float outerRadius = getOuterRadius();
84 float innerRadius = getInnerRadius(); // only used in solid case85 float innerRadius = getInnerRadius(); // only used in solid case
85 float startAt = getStartAt();86 float startAt = getStartAt();
86 float endAt = getEndAt();87 float endAt = getEndAt();
87 88
88 bool geometryChanged = (startAt != _lastStartAt || endAt != _lastEndAt ||89 bool geometryChanged = (startAt != _lastStartAt || endAt != _lastEndAt ||
89 innerRadius != _lastInnerRadius || outerRadius != _lastOuterRadius);90 innerRadius != _lastInnerRadius || outerRadius != _lastOuterRadius);
90 91
91 92
92 const float FULL_CIRCLE = 360.0f;93 const float FULL_CIRCLE = 360.0f;
93 const float SLICES = 180.0f; // The amount of segment to create the circle94 const float SLICES = 180.0f; // The amount of segment to create the circle
94 const float SLICE_ANGLE = FULL_CIRCLE / SLICES;95 const float SLICE_ANGLE = FULL_CIRCLE / SLICES;
@@ -101,195 +102,178 @@ void Circle3DOverlay::render(RenderArgs* args) { · 6 unmodified lines
101 bool colorChanged = colorX.red != _lastColor.red || colorX.green != _lastColor.green || colorX.blue != _lastColor.blue;102 bool colorChanged = colorX.red != _lastColor.red || colorX.green != _lastColor.green || colorX.blue != _lastColor.blue;
102 _lastColor = colorX;103 _lastColor = colorX;
103 104
104 glDisable(GL_LIGHTING);105 auto geometryCache = DependencyManager::get<GeometryCache>();
105
106 glm::vec3 position = getPosition();
107 glm::vec3 center = getCenter();
108 glm::vec2 dimensions = getDimensions();
109 glm::quat rotation = getRotation();
110
111 float glowLevel = getGlowLevel();
112 Glower* glower = NULL;
113 if (glowLevel > 0.0f) {
114 glower = new Glower(glowLevel);
115 }
116
117 glPushMatrix();
118 glTranslatef(position.x, position.y, position.z);
119 glm::vec3 axis = glm::axis(rotation);
120 glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
121 glPushMatrix();
122 glm::vec3 positionToCenter = center - position;
123 glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
124 glScalef(dimensions.x / 2.0f, dimensions.y / 2.0f, 1.0f);
125 106
126 glLineWidth(_lineWidth);107 Transform transform;
127 108 transform.setTranslation(getCenter());
128 auto geometryCache = DependencyManager::get<GeometryCache>();109 transform.setRotation(getRotation());
110 transform.setScale(glm::vec3(getDimensions(), 0.01f));
111
112
113 auto& batch = *args->_batch;
114 batch._glLineWidth(_lineWidth);
115 batch.setModelTransform(transform);
116 DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, false, false);
117
118 // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise
119 // we just draw a line...
120 if (getIsSolid()) {
121 if (_quadVerticesID == GeometryCache::UNKNOWN_ID) {
122 _quadVerticesID = geometryCache->allocateID();
123 }
124
125 if (geometryChanged || colorChanged) {
129 126
130 // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise127 QVector<glm::vec2> points;
131 // we just draw a line...128
132 if (getIsSolid()) {129 float angle = startAt;
133 if (_quadVerticesID == GeometryCache::UNKNOWN_ID) {130 float angleInRadians = glm::radians(angle);
134 _quadVerticesID = geometryCache->allocateID();131 glm::vec2 firstInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius);
135 }132 glm::vec2 firstOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius);
133
134 points << firstInnerPoint << firstOuterPoint;
135
136 while (angle < endAt) {
137 angleInRadians = glm::radians(angle);
138 glm::vec2 thisInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius);
139 glm::vec2 thisOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius);
136 140
137 if (geometryChanged || colorChanged) {141 points << thisOuterPoint << thisInnerPoint;
138
139 QVector<glm::vec2> points;
140
141 float angle = startAt;
142 float angleInRadians = glm::radians(angle);
143 glm::vec2 firstInnerPoint(cos(angleInRadians) * innerRadius, sin(angleInRadians) * innerRadius);
144 glm::vec2 firstOuterPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius);
145
146 points << firstInnerPoint << firstOuterPoint;
147
148 while (angle < endAt) {
149 angleInRadians = glm::radians(angle);
150 glm::vec2 thisInnerPoint(cos(angleInRadians) * innerRadius, sin(angleInRadians) * innerRadius);
151 glm::vec2 thisOuterPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius);
152
153 points << thisOuterPoint << thisInnerPoint;
154 142
155 angle += SLICE_ANGLE;143 angle += SLICE_ANGLE;
156 }144 }
157 145
158 // get the last slice portion....146 // get the last slice portion....
159 angle = endAt;147 angle = endAt;
160 angleInRadians = glm::radians(angle);148 angleInRadians = glm::radians(angle);
161 glm::vec2 lastInnerPoint(cos(angleInRadians) * innerRadius, sin(angleInRadians) * innerRadius);149 glm::vec2 lastInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius);
162 glm::vec2 lastOuterPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius);150 glm::vec2 lastOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius);
163 151
164 points << lastOuterPoint << lastInnerPoint;152 points << lastOuterPoint << lastInnerPoint;
165
166 geometryCache->updateVertices(_quadVerticesID, points, color);
167 }
168
169 geometryCache->renderVertices(gpu::QUAD_STRIP, _quadVerticesID);
170
171 } else {
172 if (_lineVerticesID == GeometryCache::UNKNOWN_ID) {
173 _lineVerticesID = geometryCache->allocateID();
174 }
175
176 if (geometryChanged || colorChanged) {
177 QVector<glm::vec2> points;
178
179 float angle = startAt;
180 float angleInRadians = glm::radians(angle);
181 glm::vec2 firstPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius);
182 points << firstPoint;
183
184 while (angle < endAt) {
185 angle += SLICE_ANGLE;
186 angleInRadians = glm::radians(angle);
187 glm::vec2 thisPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius);
188 points << thisPoint;
189
190 if (getIsDashedLine()) {
191 angle += SLICE_ANGLE / 2.0f; // short gap
192 angleInRadians = glm::radians(angle);
193 glm::vec2 dashStartPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius);
194 points << dashStartPoint;
195 }
196 }
197 153
198 // get the last slice portion....154 geometryCache->updateVertices(_quadVerticesID, points, color);
199 angle = endAt;155 }
200 angleInRadians = glm::radians(angle);156
201 glm::vec2 lastPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius);157 geometryCache->renderVertices(batch, gpu::QUAD_STRIP, _quadVerticesID);
202 points << lastPoint;158
203 159 } else {
204 geometryCache->updateVertices(_lineVerticesID, points, color);160 if (_lineVerticesID == GeometryCache::UNKNOWN_ID) {
205 }161 _lineVerticesID = geometryCache->allocateID();
206 162 }
163
164 if (geometryChanged || colorChanged) {
165 QVector<glm::vec2> points;
166
167 float angle = startAt;
168 float angleInRadians = glm::radians(angle);
169 glm::vec2 firstPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius);
170 points << firstPoint;
171
172 while (angle < endAt) {
173 angle += SLICE_ANGLE;
174 angleInRadians = glm::radians(angle);
175 glm::vec2 thisPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius);
176 points << thisPoint;
177
207 if (getIsDashedLine()) {178 if (getIsDashedLine()) {
208 geometryCache->renderVertices(gpu::LINES, _lineVerticesID);179 angle += SLICE_ANGLE / 2.0f; // short gap
209 } else {180 angleInRadians = glm::radians(angle);
210 geometryCache->renderVertices(gpu::LINE_STRIP, _lineVerticesID);181 glm::vec2 dashStartPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius);
182 points << dashStartPoint;
211 }183 }
212 }184 }
213 185
214 // draw our tick marks186 // get the last slice portion....
215 // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise187 angle = endAt;
216 // we just draw a line...188 angleInRadians = glm::radians(angle);
217 if (getHasTickMarks()) {189 glm::vec2 lastPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius);
218 190 points << lastPoint;
219 if (_majorTicksVerticesID == GeometryCache::UNKNOWN_ID) {191
220 _majorTicksVerticesID = geometryCache->allocateID();192 geometryCache->updateVertices(_lineVerticesID, points, color);
221 }193 }
222 if (_minorTicksVerticesID == GeometryCache::UNKNOWN_ID) {194
223 _minorTicksVerticesID = geometryCache->allocateID();195 if (getIsDashedLine()) {
224 }196 geometryCache->renderVertices(batch, gpu::LINES, _lineVerticesID);
225 197 } else {
226 if (geometryChanged) {198 geometryCache->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID);
227 QVector<glm::vec2> majorPoints;199 }
228 QVector<glm::vec2> minorPoints;200 }
229 201
230 // draw our major tick marks202 // draw our tick marks
231 if (getMajorTickMarksAngle() > 0.0f && getMajorTickMarksLength() != 0.0f) {203 // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise
204 // we just draw a line...
205 if (getHasTickMarks()) {
206
207 if (_majorTicksVerticesID == GeometryCache::UNKNOWN_ID) {
208 _majorTicksVerticesID = geometryCache->allocateID();
209 }
210 if (_minorTicksVerticesID == GeometryCache::UNKNOWN_ID) {
211 _minorTicksVerticesID = geometryCache->allocateID();
212 }
213
214 if (geometryChanged) {
215 QVector<glm::vec2> majorPoints;
216 QVector<glm::vec2> minorPoints;
217
218 // draw our major tick marks
219 if (getMajorTickMarksAngle() > 0.0f && getMajorTickMarksLength() != 0.0f) {
232 220
233 float tickMarkAngle = getMajorTickMarksAngle();221 float tickMarkAngle = getMajorTickMarksAngle();
234 float angle = startAt - fmod(startAt, tickMarkAngle) + tickMarkAngle; 222 float angle = startAt - fmodf(startAt, tickMarkAngle) + tickMarkAngle;
235 float angleInRadians = glm::radians(angle);223 float angleInRadians = glm::radians(angle);
236 float tickMarkLength = getMajorTickMarksLength();224 float tickMarkLength = getMajorTickMarksLength();
237 float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius;225 float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius;
238 float endRadius = startRadius + tickMarkLength;226 float endRadius = startRadius + tickMarkLength;
239
240 while (angle <= endAt) {
241 angleInRadians = glm::radians(angle);
242
243 glm::vec2 thisPointA(cos(angleInRadians) * startRadius, sin(angleInRadians) * startRadius);
244 glm::vec2 thisPointB(cos(angleInRadians) * endRadius, sin(angleInRadians) * endRadius);
245
246 majorPoints << thisPointA << thisPointB;
247 227
248 angle += tickMarkAngle;228 while (angle <= endAt) {
249 }229 angleInRadians = glm::radians(angle);
250 }230
251 231 glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius);
252 // draw our minor tick marks232 glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius);
253 if (getMinorTickMarksAngle() > 0.0f && getMinorTickMarksLength() != 0.0f) {233
234 majorPoints << thisPointA << thisPointB;
235
236 angle += tickMarkAngle;
237 }
238 }
239
240 // draw our minor tick marks
241 if (getMinorTickMarksAngle() > 0.0f && getMinorTickMarksLength() != 0.0f) {
254 242
255 float tickMarkAngle = getMinorTickMarksAngle();243 float tickMarkAngle = getMinorTickMarksAngle();
256 float angle = startAt - fmod(startAt, tickMarkAngle) + tickMarkAngle; 244 float angle = startAt - fmodf(startAt, tickMarkAngle) + tickMarkAngle;
257 float angleInRadians = glm::radians(angle);245 float angleInRadians = glm::radians(angle);
258 float tickMarkLength = getMinorTickMarksLength();246 float tickMarkLength = getMinorTickMarksLength();
259 float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius;247 float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius;
260 float endRadius = startRadius + tickMarkLength;248 float endRadius = startRadius + tickMarkLength;
261
262 while (angle <= endAt) {
263 angleInRadians = glm::radians(angle);
264
265 glm::vec2 thisPointA(cos(angleInRadians) * startRadius, sin(angleInRadians) * startRadius);
266 glm::vec2 thisPointB(cos(angleInRadians) * endRadius, sin(angleInRadians) * endRadius);
267
268 minorPoints << thisPointA << thisPointB;
269 249
270 angle += tickMarkAngle;250 while (angle <= endAt) {
271 }251 angleInRadians = glm::radians(angle);
272 }252
273 253 glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius);
274 xColor majorColorX = getMajorTickMarksColor();254 glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius);
275 glm::vec4 majorColor(majorColorX.red / MAX_COLOR, majorColorX.green / MAX_COLOR, majorColorX.blue / MAX_COLOR, alpha);255
276 256 minorPoints << thisPointA << thisPointB;
277 geometryCache->updateVertices(_majorTicksVerticesID, majorPoints, majorColor);257
278 258 angle += tickMarkAngle;
279 xColor minorColorX = getMinorTickMarksColor();
280 glm::vec4 minorColor(minorColorX.red / MAX_COLOR, minorColorX.green / MAX_COLOR, minorColorX.blue / MAX_COLOR, alpha);
281
282 geometryCache->updateVertices(_minorTicksVerticesID, minorPoints, minorColor);
283 }259 }
284
285 geometryCache->renderVertices(gpu::LINES, _majorTicksVerticesID);
286
287 geometryCache->renderVertices(gpu::LINES, _minorTicksVerticesID);
288 }260 }
289 261
290 262 xColor majorColorX = getMajorTickMarksColor();
291 glPopMatrix();263 glm::vec4 majorColor(majorColorX.red / MAX_COLOR, majorColorX.green / MAX_COLOR, majorColorX.blue / MAX_COLOR, alpha);
292 glPopMatrix();264
265 geometryCache->updateVertices(_majorTicksVerticesID, majorPoints, majorColor);
266
267 xColor minorColorX = getMinorTickMarksColor();
268 glm::vec4 minorColor(minorColorX.red / MAX_COLOR, minorColorX.green / MAX_COLOR, minorColorX.blue / MAX_COLOR, alpha);
269
270 geometryCache->updateVertices(_minorTicksVerticesID, minorPoints, minorColor);
271 }
272
273 geometryCache->renderVertices(batch, gpu::LINES, _majorTicksVerticesID);
274
275 geometryCache->renderVertices(batch, gpu::LINES, _minorTicksVerticesID);
276 }
293 277
294 if (geometryChanged) {278 if (geometryChanged) {
295 _lastStartAt = startAt;279 _lastStartAt = startAt;
@@ -297,15 +281,11 @@ void Circle3DOverlay::render(RenderArgs* args) { · 1 unmodified line
297 _lastInnerRadius = innerRadius;281 _lastInnerRadius = innerRadius;
298 _lastOuterRadius = outerRadius;282 _lastOuterRadius = outerRadius;
299 }283 }
300
301 if (glower) {
302 delete glower;
303 }
304}284}
305 285
306void Circle3DOverlay::setProperties(const QScriptValue &properties) {286void Circle3DOverlay::setProperties(const QScriptValue &properties) {
307 Planar3DOverlay::setProperties(properties);287 Planar3DOverlay::setProperties(properties);
308 288
309 QScriptValue startAt = properties.property("startAt");289 QScriptValue startAt = properties.property("startAt");
310 if (startAt.isValid()) {290 if (startAt.isValid()) {
311 setStartAt(startAt.toVariant().toFloat());291 setStartAt(startAt.toVariant().toFloat());
@@ -415,7 +395,7 @@ QScriptValue Circle3DOverlay::getProperty(const QString& property) { · 103 unmodified lines
415}395}
416 396
417 397
418bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin, 398bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin,
419 const glm::vec3& direction, float& distance, BoxFace& face) {399 const glm::vec3& direction, float& distance, BoxFace& face) {
420 400
421 bool intersects = Planar3DOverlay::findRayIntersection(origin, direction, distance, face);401 bool intersects = Planar3DOverlay::findRayIntersection(origin, direction, distance, face);
interface/src/ui/overlays/Line3DOverlay.cpp+10−0
@@ -32,6 +32,16 @@ Line3DOverlay::Line3DOverlay(const Line3DOverlay* line3DOverlay) : · 31 unmodified lines
32Line3DOverlay::~Line3DOverlay() {32Line3DOverlay::~Line3DOverlay() {
33}33}
34 34
35AABox 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
35void Line3DOverlay::render(RenderArgs* args) {45void Line3DOverlay::render(RenderArgs* args) {
36 if (!_visible) {46 if (!_visible) {
37 return; // do nothing if we're not visible47 return; // do nothing if we're not visible
interface/src/ui/overlays/Line3DOverlay.h+1−0
@@ -21,6 +21,7 @@ public: · 20 unmodified lines
21 Line3DOverlay(const Line3DOverlay* line3DOverlay);21 Line3DOverlay(const Line3DOverlay* line3DOverlay);
22 ~Line3DOverlay();22 ~Line3DOverlay();
23 virtual void render(RenderArgs* args);23 virtual void render(RenderArgs* args);
24 virtual AABox getBounds() const override;
24 25
25 // getters26 // getters
26 const glm::vec3& getStart() const { return _start; }27 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
258unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {258unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
259 glm::vec2 pointCopy = point;259 glm::vec2 pointCopy = point;
260 if (qApp->isHMDMode()) {260 if (qApp->isHMDMode()) {
261 pointCopy = qApp->getApplicationOverlay().screenToOverlay(point);261 pointCopy = qApp->getApplicationCompositor().screenToOverlay(point);
262 }262 }
263 263
264 QReadLocker lock(&_lock);264 QReadLocker lock(&_lock);
interface/src/ui/overlays/TextOverlay.cpp+1−0
@@ -80,6 +80,7 @@ void TextOverlay::render(RenderArgs* args) { · 79 unmodified lines
80 80
81 glm::vec2 topLeft(left, top);81 glm::vec2 topLeft(left, top);
82 glm::vec2 bottomRight(right, bottom);82 glm::vec2 bottomRight(right, bottom);
83 glBindTexture(GL_TEXTURE_2D, 0);
83 DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, quadColor);84 DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, quadColor);
84 85
85 const int leftAdjust = -1; // required to make text render relative to left edge of bounds86 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
33#include <QtMultimedia/QAudioInput>33#include <QtMultimedia/QAudioInput>
34#include <QtMultimedia/QAudioOutput>34#include <QtMultimedia/QAudioOutput>
35 35
36#ifdef __GNUC__
37#pragma GCC diagnostic push
38#pragma GCC diagnostic ignored "-Wdouble-promotion"
39#endif
40
36extern "C" {41extern "C" {
37 #include <gverb/gverb.h>42 #include <gverb/gverb.h>
38 #include <gverb/gverbdsp.h>43 #include <gverb/gverbdsp.h>
39}44}
40 45
46#ifdef __GNUC__
47#pragma GCC diagnostic pop
48#endif
49
41#include <soxr.h>50#include <soxr.h>
42 51
43#include <NodeList.h>52#include <NodeList.h>
@@ -786,6 +795,11 @@ void AudioClient::handleAudioInput() { · 742 unmodified lines
786 795
787 delete[] inputAudioSamples;796 delete[] inputAudioSamples;
788 797
798 // Remove DC offset
799 if (!_isStereoInput && !_audioSourceInjectEnabled) {
800 _inputGate.removeDCOffset(networkAudioSamples, numNetworkSamples);
801 }
802
789 // only impose the noise gate and perform tone injection if we are sending mono audio803 // only impose the noise gate and perform tone injection if we are sending mono audio
790 if (!_isStereoInput && !_audioSourceInjectEnabled && _isNoiseGateEnabled) {804 if (!_isStereoInput && !_audioSourceInjectEnabled && _isNoiseGateEnabled) {
791 _inputGate.gateSamples(networkAudioSamples, numNetworkSamples);805 _inputGate.gateSamples(networkAudioSamples, numNetworkSamples);
@@ -1011,7 +1025,10 @@ bool AudioClient::outputLocalInjector(bool isStereo, AudioInjector* injector) { · 219 unmodified lines
1011 localOutput->moveToThread(injector->getLocalBuffer()->thread());1025 localOutput->moveToThread(injector->getLocalBuffer()->thread());
1012 1026
1013 // have it be stopped when that local buffer is about to close1027 // have it be stopped when that local buffer is about to close
1014 connect(injector->getLocalBuffer(), &AudioInjectorLocalBuffer::bufferEmpty, localOutput, &QAudioOutput::stop);1028 connect(localOutput, &QAudioOutput::stateChanged, this, &AudioClient::audioStateChanged);
1029 connect(this, &AudioClient::audioFinished, localOutput, &QAudioOutput::stop);
1030 connect(this, &AudioClient::audioFinished, injector, &AudioInjector::stop);
1031
1015 connect(injector->getLocalBuffer(), &QIODevice::aboutToClose, localOutput, &QAudioOutput::stop);1032 connect(injector->getLocalBuffer(), &QIODevice::aboutToClose, localOutput, &QAudioOutput::stop);
1016 1033
1017 qCDebug(audioclient) << "Starting QAudioOutput for local injector" << localOutput;1034 qCDebug(audioclient) << "Starting QAudioOutput for local injector" << localOutput;
@@ -1329,3 +1346,9 @@ void AudioClient::saveSettings() { · 311 unmodified lines
1329 windowSecondsForDesiredReduction.set(_receivedAudioStream.getWindowSecondsForDesiredReduction());1346 windowSecondsForDesiredReduction.set(_receivedAudioStream.getWindowSecondsForDesiredReduction());
1330 repetitionWithFade.set(_receivedAudioStream.getRepetitionWithFade());1347 repetitionWithFade.set(_receivedAudioStream.getRepetitionWithFade());
1331}1348}
1349
1350void 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
167 QString getDefaultDeviceName(QAudio::Mode mode);167 QString getDefaultDeviceName(QAudio::Mode mode);
168 QVector<QString> getDeviceNames(QAudio::Mode mode);168 QVector<QString> getDeviceNames(QAudio::Mode mode);
169 169
170 float getInputVolume() const { return (_audioInput) ? _audioInput->volume() : 0.0f; }170 float getInputVolume() const { return (_audioInput) ? (float)_audioInput->volume() : 0.0f; }
171 void setInputVolume(float volume) { if (_audioInput) _audioInput->setVolume(volume); }171 void setInputVolume(float volume) { if (_audioInput) _audioInput->setVolume(volume); }
172 void setReverb(bool reverb);172 void setReverb(bool reverb);
173 void setReverbOptions(const AudioEffectOptions* options);173 void setReverbOptions(const AudioEffectOptions* options);
@@ -188,6 +188,8 @@ signals: · 14 unmodified lines
188 void receivedFirstPacket();188 void receivedFirstPacket();
189 void disconnected();189 void disconnected();
190 190
191 void audioFinished();
192
191protected:193protected:
192 AudioClient();194 AudioClient();
193 ~AudioClient();195 ~AudioClient();
@@ -196,6 +198,9 @@ protected: · 2 unmodified lines
196 deleteLater();198 deleteLater();
197 }199 }
198 200
201private slots:
202 void audioStateChanged(QAudio::State state);
203
199private:204private:
200 void outputFormatChanged();205 void outputFormatChanged();
201 206
libraries/audio-client/src/AudioNoiseGate.cpp+28−15
@@ -33,6 +33,32 @@ AudioNoiseGate::AudioNoiseGate() : · 32 unmodified lines
33 33
34}34}
35 35
36void 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
36void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {62void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
37 //63 //
38 // Impose Noise Gate64 // Impose Noise Gate
@@ -61,17 +87,12 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { · 22 unmodified lines
61 const int NOISE_GATE_WIDTH = 5;87 const int NOISE_GATE_WIDTH = 5;
62 const int NOISE_GATE_CLOSE_FRAME_DELAY = 5;88 const int NOISE_GATE_CLOSE_FRAME_DELAY = 5;
63 const int NOISE_GATE_FRAMES_TO_AVERAGE = 5;89 const int NOISE_GATE_FRAMES_TO_AVERAGE = 5;
64 const float DC_OFFSET_AVERAGING = 0.99f;90
65 91 // Check clipping, and check if should open noise gate
66 // Check clipping, adjust DC offset, and check if should open noise gate
67 float measuredDcOffset = 0.0f;
68 _didClipInLastFrame = false;92 _didClipInLastFrame = false;
69 93
70 for (int i = 0; i < numSamples; i++) {94 for (int i = 0; i < numSamples; i++) {
71 measuredDcOffset += samples[i];
72 samples[i] -= (int16_t) _dcOffset;
73 thisSample = std::abs(samples[i]);95 thisSample = std::abs(samples[i]);
74
75 if (thisSample >= ((float) AudioConstants::MAX_SAMPLE_VALUE * CLIPPING_THRESHOLD)) {96 if (thisSample >= ((float) AudioConstants::MAX_SAMPLE_VALUE * CLIPPING_THRESHOLD)) {
76 _didClipInLastFrame = true;97 _didClipInLastFrame = true;
77 }98 }
@@ -83,14 +104,6 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) { · 5 unmodified lines
83 }104 }
84 }105 }
85 106
86 measuredDcOffset /= numSamples;
87 if (_dcOffset == 0.0f) {
88 // On first frame, copy over measured offset
89 _dcOffset = measuredDcOffset;
90 } else {
91 _dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset;
92 }
93
94 _lastLoudness = fabs(loudness / numSamples);107 _lastLoudness = fabs(loudness / numSamples);
95 108
96 if (_quietestFrame > _lastLoudness) {109 if (_quietestFrame > _lastLoudness) {
libraries/audio-client/src/AudioNoiseGate.h+1−0
@@ -21,6 +21,7 @@ public: · 20 unmodified lines
21 AudioNoiseGate();21 AudioNoiseGate();
22 22
23 void gateSamples(int16_t* samples, int numSamples);23 void gateSamples(int16_t* samples, int numSamples);
24 void removeDCOffset(int16_t* samples, int numSamples);
24 25
25 bool clippedInLastFrame() const { return _didClipInLastFrame; }26 bool clippedInLastFrame() const { return _didClipInLastFrame; }
26 float getMeasuredFloor() const { return _measuredFloor; }27 float getMeasuredFloor() const { return _measuredFloor; }
libraries/audio/CMakeLists.txt+7−1
@@ -7,4 +7,10 @@ add_dependency_external_projects(glm) · 6 unmodified lines
7find_package(GLM REQUIRED)7find_package(GLM REQUIRED)
8target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})8target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
9 9
10link_hifi_libraries(networking shared)10# we use libsoxr for resampling
11add_dependency_external_projects(soxr)
12find_package(Soxr REQUIRED)
13target_link_libraries(${TARGET_NAME} ${SOXR_LIBRARIES})
14target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SOXR_INCLUDE_DIRS})
15
16link_hifi_libraries(networking shared)
libraries/audio/src/AudioInjector.cpp+65−4
@@ -16,10 +16,12 @@ · 15 unmodified lines
16#include <PacketHeaders.h>16#include <PacketHeaders.h>
17#include <SharedUtil.h>17#include <SharedUtil.h>
18#include <UUID.h>18#include <UUID.h>
19#include <soxr.h>
19 20
20#include "AbstractAudioInterface.h"21#include "AbstractAudioInterface.h"
21#include "AudioRingBuffer.h"22#include "AudioRingBuffer.h"
22#include "AudioLogging.h"23#include "AudioLogging.h"
24#include "SoundCache.h"
23 25
24#include "AudioInjector.h"26#include "AudioInjector.h"
25 27
@@ -60,7 +62,6 @@ void AudioInjector::setIsFinished(bool isFinished) { · 34 unmodified lines
60 62
61 if (_shouldDeleteAfterFinish) {63 if (_shouldDeleteAfterFinish) {
62 // we've been asked to delete after finishing, trigger a queued deleteLater here64 // we've been asked to delete after finishing, trigger a queued deleteLater here
63 qCDebug(audio) << "AudioInjector triggering delete from setIsFinished";
64 QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);65 QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
65 }66 }
66 }67 }
@@ -122,9 +123,6 @@ void AudioInjector::injectLocally() { · 55 unmodified lines
122 123
123 success = _localAudioInterface->outputLocalInjector(_options.stereo, this);124 success = _localAudioInterface->outputLocalInjector(_options.stereo, this);
124 125
125 // if we're not looping and the buffer tells us it is empty then emit finished
126 connect(_localBuffer, &AudioInjectorLocalBuffer::bufferEmpty, this, &AudioInjector::stop);
127
128 if (!success) {126 if (!success) {
129 qCDebug(audio) << "AudioInjector::injectLocally could not output locally via _localAudioInterface";127 qCDebug(audio) << "AudioInjector::injectLocally could not output locally via _localAudioInterface";
130 }128 }
@@ -288,3 +286,66 @@ void AudioInjector::stopAndDeleteLater() { · 157 unmodified lines
288 stop();286 stop();
289 QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);287 QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
290}288}
289
290AudioInjector* 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
333AudioInjector* 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
45 bool isLocalOnly() const { return _options.localOnly; }45 bool isLocalOnly() const { return _options.localOnly; }
46 46
47 void setLocalAudioInterface(AbstractAudioInterface* localAudioInterface) { _localAudioInterface = localAudioInterface; }47 void setLocalAudioInterface(AbstractAudioInterface* localAudioInterface) { _localAudioInterface = localAudioInterface; }
48
49 static AudioInjector* playSound(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface);
50 static AudioInjector* playSound(const QString& soundUrl, const float volume, const float stretchFactor, const glm::vec3 position);
51
48public slots:52public slots:
49 void injectAudio();53 void injectAudio();
50 void restart();54 void restart();
libraries/audio/src/AudioInjectorLocalBuffer.cpp+1−4
@@ -69,10 +69,7 @@ qint64 AudioInjectorLocalBuffer::readData(char* data, qint64 maxSize) { · 68 unmodified lines
69 _currentOffset += bytesRead;69 _currentOffset += bytesRead;
70 }70 }
71 71
72 if (!_shouldLoop && bytesRead == bytesToEnd) {72 if (_shouldLoop && _currentOffset == _rawAudioArray.size()) {
73 // we hit the end of the buffer, emit a signal
74 emit bufferEmpty();
75 } else if (_shouldLoop && _currentOffset == _rawAudioArray.size()) {
76 _currentOffset = 0;73 _currentOffset = 0;
77 }74 }
78 75
libraries/audio/src/AudioInjectorLocalBuffer.h+0−3
@@ -32,9 +32,6 @@ public: · 31 unmodified lines
32 void setCurrentOffset(int currentOffset) { _currentOffset = currentOffset; }32 void setCurrentOffset(int currentOffset) { _currentOffset = currentOffset; }
33 void setVolume(float volume) { _volume = glm::clamp(volume, 0.0f, 1.0f); }33 void setVolume(float volume) { _volume = glm::clamp(volume, 0.0f, 1.0f); }
34 34
35signals:
36 void bufferEmpty();
37
38private:35private:
39 qint64 recursiveReadFromFront(char* data, qint64 maxSize);36 qint64 recursiveReadFromFront(char* data, qint64 maxSize);
40 37
libraries/audio/src/AudioRingBuffer.cpp+1−1
@@ -211,7 +211,7 @@ float AudioRingBuffer::getFrameLoudness(const int16_t* frameStart) const { · 210 unmodified lines
211 const int16_t* _bufferLastAt = _buffer + _bufferLength - 1;211 const int16_t* _bufferLastAt = _buffer + _bufferLength - 1;
212 212
213 for (int i = 0; i < _numFrameSamples; ++i) {213 for (int i = 0; i < _numFrameSamples; ++i) {
214 loudness += std::abs(*sampleAt);214 loudness += (float) std::abs(*sampleAt);
215 sampleAt = sampleAt == _bufferLastAt ? _buffer : sampleAt + 1;215 sampleAt = sampleAt == _bufferLastAt ? _buffer : sampleAt + 1;
216 }216 }
217 loudness /= _numFrameSamples;217 loudness /= _numFrameSamples;
libraries/avatars/src/AvatarData.cpp+2−3
@@ -52,9 +52,8 @@ AvatarData::AvatarData() : · 51 unmodified lines
52 _headData(NULL),52 _headData(NULL),
53 _handData(NULL),53 _handData(NULL),
54 _faceModelURL("http://invalid.com"),54 _faceModelURL("http://invalid.com"),
55 _displayNameBoundingRect(), 55 _displayNameTargetAlpha(1.0f),
56 _displayNameTargetAlpha(0.0f), 56 _displayNameAlpha(1.0f),
57 _displayNameAlpha(0.0f),
58 _billboard(),57 _billboard(),
59 _errorLogExpiry(0),58 _errorLogExpiry(0),
60 _owningAvatarMixer(),59 _owningAvatarMixer(),
libraries/avatars/src/AvatarData.h+1−2
@@ -163,7 +163,7 @@ public: · 162 unmodified lines
163 AvatarData();163 AvatarData();
164 virtual ~AvatarData();164 virtual ~AvatarData();
165 165
166 virtual bool isMyAvatar() { return false; }166 virtual bool isMyAvatar() const { return false; }
167 167
168 const QUuid& getSessionUUID() const { return _sessionUUID; }168 const QUuid& getSessionUUID() const { return _sessionUUID; }
169 169
@@ -378,7 +378,6 @@ protected: · 208 unmodified lines
378 QVector<AttachmentData> _attachmentData;378 QVector<AttachmentData> _attachmentData;
379 QString _displayName;379 QString _displayName;
380 380
381 QRect _displayNameBoundingRect;
382 float _displayNameTargetAlpha;381 float _displayNameTargetAlpha;
383 float _displayNameAlpha;382 float _displayNameAlpha;
384 383
libraries/entities-renderer/CMakeLists.txt+0−6
@@ -17,10 +17,4 @@ find_package(PolyVox REQUIRED) · 16 unmodified lines
17target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${POLYVOX_INCLUDE_DIRS})17target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${POLYVOX_INCLUDE_DIRS})
18target_link_libraries(${TARGET_NAME} ${POLYVOX_LIBRARIES})18target_link_libraries(${TARGET_NAME} ${POLYVOX_LIBRARIES})
19 19
20# for changing the pitch of collision sounds
21add_dependency_external_projects(soxr)
22find_package(Soxr REQUIRED)
23target_link_libraries(${TARGET_NAME} ${SOXR_LIBRARIES})
24target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SOXR_INCLUDE_DIRS})
25
26link_hifi_libraries(shared gpu script-engine render render-utils)20link_hifi_libraries(shared gpu script-engine render render-utils)
libraries/entities-renderer/src/EntityTreeRenderer.cpp+6−60
@@ -27,10 +27,6 @@ · 26 unmodified lines
27#include <SceneScriptingInterface.h>27#include <SceneScriptingInterface.h>
28#include <ScriptEngine.h>28#include <ScriptEngine.h>
29#include <TextureCache.h>29#include <TextureCache.h>
30#include <SoundCache.h>
31#include <soxr.h>
32#include <AudioConstants.h>
33
34 30
35#include "EntityTreeRenderer.h"31#include "EntityTreeRenderer.h"
36 32
@@ -54,7 +50,6 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf · 17 unmodified lines
54 _wantScripts(wantScripts),50 _wantScripts(wantScripts),
55 _entitiesScriptEngine(NULL),51 _entitiesScriptEngine(NULL),
56 _sandboxScriptEngine(NULL),52 _sandboxScriptEngine(NULL),
57 _localAudioInterface(NULL),
58 _lastMouseEventValid(false),53 _lastMouseEventValid(false),
59 _viewState(viewState),54 _viewState(viewState),
60 _scriptingServices(scriptingServices),55 _scriptingServices(scriptingServices),
@@ -911,15 +906,13 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI · 850 unmodified lines
911 bool precisionPicking = false; // for mouse moves we do not do precision picking906 bool precisionPicking = false; // for mouse moves we do not do precision picking
912 RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking);907 RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking);
913 if (rayPickResult.intersects) {908 if (rayPickResult.intersects) {
909 //qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID;
914 QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID);910 QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID);
915
916 // load the entity script if needed...911 // load the entity script if needed...
917 QScriptValue entityScript = loadEntityScript(rayPickResult.entity);912 QScriptValue entityScript = loadEntityScript(rayPickResult.entity);
918 if (entityScript.property("mouseMoveEvent").isValid()) {913 if (entityScript.property("mouseMoveEvent").isValid()) {
919 entityScript.property("mouseMoveEvent").call(entityScript, entityScriptArgs);914 entityScript.property("mouseMoveEvent").call(entityScript, entityScriptArgs);
920 }915 }
921
922 //qCDebug(entitiesrenderer) << "mouseMoveEvent over entity:" << rayPickResult.entityID;
923 emit mouseMoveOnEntity(rayPickResult, event, deviceID);916 emit mouseMoveOnEntity(rayPickResult, event, deviceID);
924 if (entityScript.property("mouseMoveOnEntity").isValid()) {917 if (entityScript.property("mouseMoveOnEntity").isValid()) {
925 entityScript.property("mouseMoveOnEntity").call(entityScript, entityScriptArgs);918 entityScript.property("mouseMoveOnEntity").call(entityScript, entityScriptArgs);
@@ -1056,7 +1049,6 @@ void EntityTreeRenderer::checkAndCallUnload(const EntityItemID& entityID) { · 130 unmodified lines
1056 }1049 }
1057}1050}
1058 1051
1059
1060void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision) {1052void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision) {
1061 EntityItemPointer entity = entityTree->findEntityByEntityItemID(id);1053 EntityItemPointer entity = entityTree->findEntityByEntityItemID(id);
1062 if (!entity) {1054 if (!entity) {
@@ -1099,61 +1091,15 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT · 36 unmodified lines
1099 if (energyFactorOfFull < COLLISION_MINIMUM_VOLUME) {1091 if (energyFactorOfFull < COLLISION_MINIMUM_VOLUME) {
1100 return;1092 return;
1101 }1093 }
1102 1094 // Quiet sound aren't really heard at all, so we can compress everything to the range [1-c, 1], if we play it all.
1103 auto soundCache = DependencyManager::get<SoundCache>();
1104 if (soundCache.isNull()) {
1105 return;
1106 }
1107 SharedSoundPointer sound = soundCache.data()->getSound(QUrl(collisionSoundURL));
1108 if (sound.isNull() || !sound->isReady()) {
1109 return;
1110 }
1111
1112 // This is a hack. Quiet sound aren't really heard at all, so we compress everything to the range [1-c, 1], if we play it all.
1113 const float COLLISION_SOUND_COMPRESSION_RANGE = 1.0f; // This section could be removed when the value is 1, but let's see how it goes.1095 const float COLLISION_SOUND_COMPRESSION_RANGE = 1.0f; // This section could be removed when the value is 1, but let's see how it goes.
1114 float volume = energyFactorOfFull;1096 const float volume = (energyFactorOfFull * COLLISION_SOUND_COMPRESSION_RANGE) + (1.0f - COLLISION_SOUND_COMPRESSION_RANGE);
1115 volume = (volume * COLLISION_SOUND_COMPRESSION_RANGE) + (1.0f - COLLISION_SOUND_COMPRESSION_RANGE);1097
1116
1117 // This is quite similar to AudioScriptingInterface::playSound() and should probably be refactored.
1118 AudioInjectorOptions options;
1119 options.stereo = sound->isStereo();
1120 options.position = position;
1121 options.volume = volume;
1122 1098
1123 // Shift the pitch down by ln(1 + (size / COLLISION_SIZE_FOR_STANDARD_PITCH)) / ln(2)1099 // Shift the pitch down by ln(1 + (size / COLLISION_SIZE_FOR_STANDARD_PITCH)) / ln(2)
1124 const float COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f;1100 const float COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f;
1125 QByteArray samples = sound->getByteArray();1101 const float stretchFactor = log(1.0f + (entity->getMinimumAACube().getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2);
1126 soxr_io_spec_t spec = soxr_io_spec(SOXR_INT16_I, SOXR_INT16_I);1102 AudioInjector::playSound(collisionSoundURL, volume, stretchFactor, position);
1127 soxr_quality_spec_t qualitySpec = soxr_quality_spec(SOXR_MQ, 0);
1128 const int channelCount = sound->isStereo() ? 2 : 1;
1129 const float factor = log(1.0f + (entity->getMinimumAACube().getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2);
1130 const int standardRate = AudioConstants::SAMPLE_RATE;
1131 const int resampledRate = standardRate * factor;
1132 const int nInputSamples = samples.size() / sizeof(int16_t);
1133 const int nOutputSamples = nInputSamples * factor;
1134 QByteArray resampled(nOutputSamples * sizeof(int16_t), '\0');
1135 const int16_t* receivedSamples = reinterpret_cast<const int16_t*>(samples.data());
1136 soxr_error_t soxError = soxr_oneshot(standardRate, resampledRate, channelCount,
1137 receivedSamples, nInputSamples, NULL,
1138 reinterpret_cast<int16_t*>(resampled.data()), nOutputSamples, NULL,
1139 &spec, &qualitySpec, 0);
1140 if (soxError) {
1141 qCDebug(entitiesrenderer) << "Unable to resample" << collisionSoundURL << "from" << nInputSamples << "@" << standardRate << "to" << nOutputSamples << "@" << resampledRate;
1142 resampled = samples;
1143 }
1144
1145 AudioInjector* injector = new AudioInjector(resampled, options);
1146 injector->setLocalAudioInterface(_localAudioInterface);
1147 injector->triggerDeleteAfterFinish();
1148 QThread* injectorThread = new QThread();
1149 injectorThread->setObjectName("Audio Injector Thread");
1150 injector->moveToThread(injectorThread);
1151 // start injecting when the injector thread starts
1152 connect(injectorThread, &QThread::started, injector, &AudioInjector::injectAudio);
1153 // connect the right slots and signals for AudioInjector and thread cleanup
1154 connect(injector, &AudioInjector::destroyed, injectorThread, &QThread::quit);
1155 connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater);
1156 injectorThread->start();
1157}1103}
1158 1104
1159void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB,1105void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB,
libraries/entities-renderer/src/EntityTreeRenderer.h+0−1
@@ -158,7 +158,6 @@ private: · 157 unmodified lines
158 QHash<EntityItemID, EntityScriptDetails> _entityScripts;158 QHash<EntityItemID, EntityScriptDetails> _entityScripts;
159 159
160 void playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision);160 void playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision);
161 AbstractAudioInterface* _localAudioInterface; // So we can render collision sounds
162 161
163 bool _lastMouseEventValid;162 bool _lastMouseEventValid;
164 MouseEvent _lastMouseEvent;163 MouseEvent _lastMouseEvent;
libraries/entities-renderer/src/RenderableLineEntityItem.cpp+3−3
@@ -43,9 +43,9 @@ void RenderableLineEntityItem::render(RenderArgs* args) { · 42 unmodified lines
43 43
44 Q_ASSERT(args->_batch);44 Q_ASSERT(args->_batch);
45 gpu::Batch& batch = *args->_batch;45 gpu::Batch& batch = *args->_batch;
46 // TODO: Figure out clean , efficient way to do relative line positioning. For now we'll just use absolute positioning.46 Transform transform = Transform();
47 //batch.setModelTransform(getTransformToCenter());47 transform.setTranslation(getPosition());
48 batch.setModelTransform(Transform());48 batch.setModelTransform(transform);
49 49
50 batch._glLineWidth(getLineWidth());50 batch._glLineWidth(getLineWidth());
51 if (getLinePoints().size() > 1) {51 if (getLinePoints().size() > 1) {
libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp+11−7
@@ -11,10 +11,18 @@ · 10 unmodified lines
11 11
12#include <QByteArray>12#include <QByteArray>
13 13
14#ifdef __GNUC__
15#pragma GCC diagnostic push
16#pragma GCC diagnostic ignored "-Wdouble-promotion"
17#endif
14 18
15#include <glm/gtx/quaternion.hpp>19#include <glm/gtx/quaternion.hpp>
16#include <glm/gtx/string_cast.hpp>20#include <glm/gtx/string_cast.hpp>
17 21
22#ifdef __GNUC__
23#pragma GCC diagnostic pop
24#endif
25
18#include <gpu/GPUConfig.h>26#include <gpu/GPUConfig.h>
19 27
20#include <DeferredLightingEffect.h>28#include <DeferredLightingEffect.h>
@@ -141,11 +149,7 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) · 120 unmodified lines
141 decompressVolumeData();149 decompressVolumeData();
142}150}
143 151
144void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) {152void RenderablePolyVoxEntityItem::updateVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) {
145 if (voxelSurfaceStyle == _voxelSurfaceStyle) {
146 return;
147 }
148
149 // if we are switching to or from "edged" we need to force a resize of _volData.153 // if we are switching to or from "edged" we need to force a resize of _volData.
150 if (voxelSurfaceStyle == SURFACE_EDGED_CUBIC ||154 if (voxelSurfaceStyle == SURFACE_EDGED_CUBIC ||
151 _voxelSurfaceStyle == SURFACE_EDGED_CUBIC) {155 _voxelSurfaceStyle == SURFACE_EDGED_CUBIC) {
@@ -153,10 +157,10 @@ void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxel · 1 unmodified line
153 delete _volData;157 delete _volData;
154 }158 }
155 _volData = nullptr;159 _volData = nullptr;
156 PolyVoxEntityItem::setVoxelSurfaceStyle(voxelSurfaceStyle);160 _voxelSurfaceStyle = voxelSurfaceStyle;
157 setVoxelVolumeSize(_voxelVolumeSize);161 setVoxelVolumeSize(_voxelVolumeSize);
158 } else {162 } else {
159 PolyVoxEntityItem::setVoxelSurfaceStyle(voxelSurfaceStyle);163 _voxelSurfaceStyle = voxelSurfaceStyle;
160 }164 }
161 _needsModelReload = true;165 _needsModelReload = true;
162}166}
libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h+6−4
@@ -36,17 +36,15 @@ public: · 35 unmodified lines
36 36
37 virtual uint8_t getVoxel(int x, int y, int z);37 virtual uint8_t getVoxel(int x, int y, int z);
38 virtual void setVoxel(int x, int y, int z, uint8_t toValue);38 virtual void setVoxel(int x, int y, int z, uint8_t toValue);
39 39
40 void updateOnCount(int x, int y, int z, uint8_t new_value);40 void updateOnCount(int x, int y, int z, uint8_t new_value);
41 41
42 void render(RenderArgs* args);42 void render(RenderArgs* args);
43 virtual bool supportsDetailedRayIntersection() const { return true; }43 virtual bool supportsDetailedRayIntersection() const { return true; }
44 virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,44 virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
45 bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, 45 bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
46 void** intersectedObject, bool precisionPicking) const;46 void** intersectedObject, bool precisionPicking) const;
47 47
48 virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle);
49
50 void getModel();48 void getModel();
51 49
52 virtual void setVoxelData(QByteArray voxelData);50 virtual void setVoxelData(QByteArray voxelData);
@@ -74,6 +72,9 @@ public: · 21 unmodified lines
74 72
75 SIMPLE_RENDERABLE();73 SIMPLE_RENDERABLE();
76 74
75protected:
76 virtual void updateVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle);
77
77private:78private:
78 // The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions79 // The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions
79 // may not match _voxelVolumeSize.80 // may not match _voxelVolumeSize.
@@ -82,6 +83,7 @@ private: · 2 unmodified lines
82 void compressVolumeData();83 void compressVolumeData();
83 void decompressVolumeData();84 void decompressVolumeData();
84 85
86
85 PolyVox::SimpleVolume<uint8_t>* _volData = nullptr;87 PolyVox::SimpleVolume<uint8_t>* _volData = nullptr;
86 model::Geometry _modelGeometry;88 model::Geometry _modelGeometry;
87 bool _needsModelReload = true;89 bool _needsModelReload = true;
libraries/entities/src/DeleteEntityOperator.cpp+1−0
@@ -95,6 +95,7 @@ bool DeleteEntityOperator::preRecursion(OctreeElement* element) { · 94 unmodified lines
95 EntityItemPointer theEntity = details.entity;95 EntityItemPointer theEntity = details.entity;
96 bool entityDeleted = entityTreeElement->removeEntityItem(theEntity); // remove it from the element96 bool entityDeleted = entityTreeElement->removeEntityItem(theEntity); // remove it from the element
97 assert(entityDeleted);97 assert(entityDeleted);
98 (void)entityDeleted; // quite warning
98 _tree->setContainingElement(details.entity->getEntityItemID(), NULL); // update or id to element lookup99 _tree->setContainingElement(details.entity->getEntityItemID(), NULL); // update or id to element lookup
99 _foundCount++;100 _foundCount++;
100 }101 }
libraries/entities/src/EntityActionInterface.cpp+4−4
@@ -19,8 +19,8 @@ EntityActionType EntityActionInterface::actionTypeFromString(QString actionTypeS · 18 unmodified lines
19 if (normalizedActionTypeString == "none") {19 if (normalizedActionTypeString == "none") {
20 return ACTION_TYPE_NONE;20 return ACTION_TYPE_NONE;
21 }21 }
22 if (normalizedActionTypeString == "pulltopoint") {22 if (normalizedActionTypeString == "offset") {
23 return ACTION_TYPE_PULL_TO_POINT;23 return ACTION_TYPE_OFFSET;
24 }24 }
25 if (normalizedActionTypeString == "spring") {25 if (normalizedActionTypeString == "spring") {
26 return ACTION_TYPE_SPRING;26 return ACTION_TYPE_SPRING;
@@ -37,8 +37,8 @@ QString EntityActionInterface::actionTypeToString(EntityActionType actionType) { · 10 unmodified lines
37 switch(actionType) {37 switch(actionType) {
38 case ACTION_TYPE_NONE:38 case ACTION_TYPE_NONE:
39 return "none";39 return "none";
40 case ACTION_TYPE_PULL_TO_POINT:40 case ACTION_TYPE_OFFSET:
41 return "pullToPoint";41 return "offset";
42 case ACTION_TYPE_SPRING:42 case ACTION_TYPE_SPRING:
43 return "spring";43 return "spring";
44 case ACTION_TYPE_HOLD:44 case ACTION_TYPE_HOLD:
libraries/entities/src/EntityActionInterface.h+1−1
@@ -21,7 +21,7 @@ class EntitySimulation; · 20 unmodified lines
21enum EntityActionType {21enum EntityActionType {
22 // keep these synchronized with actionTypeFromString and actionTypeToString22 // keep these synchronized with actionTypeFromString and actionTypeToString
23 ACTION_TYPE_NONE,23 ACTION_TYPE_NONE,
24 ACTION_TYPE_PULL_TO_POINT,24 ACTION_TYPE_OFFSET,
25 ACTION_TYPE_SPRING,25 ACTION_TYPE_SPRING,
26 ACTION_TYPE_HOLD26 ACTION_TYPE_HOLD
27};27};
libraries/entities/src/EntityItem.cpp+2−2
@@ -639,8 +639,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef · 638 unmodified lines
639void EntityItem::debugDump() const {639void EntityItem::debugDump() const {
640 auto position = getPosition();640 auto position = getPosition();
641 qCDebug(entities) << "EntityItem id:" << getEntityItemID();641 qCDebug(entities) << "EntityItem id:" << getEntityItemID();
642 qCDebug(entities, " edited ago:%f", getEditedAgo());642 qCDebug(entities, " edited ago:%f", (double)getEditedAgo());
643 qCDebug(entities, " position:%f,%f,%f", position.x, position.y, position.z);643 qCDebug(entities, " position:%f,%f,%f", (double)position.x, (double)position.y, (double)position.z);
644 qCDebug(entities) << " dimensions:" << getDimensions();644 qCDebug(entities) << " dimensions:" << getDimensions();
645}645}
646 646
libraries/entities/src/EntityItemID.h+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
14 14
15#include <stdint.h>15#include <stdint.h>
16 16
17 17#include <QDebug>
18#include <QObject>18#include <QObject>
19#include <QHash>19#include <QHash>
20#include <QScriptEngine>20#include <QScriptEngine>
libraries/entities/src/EntityItemProperties.h+2−0
@@ -197,6 +197,8 @@ public: · 196 unmodified lines
197 QString getSimulatorIDAsString() const { return _simulatorID.toString().mid(1,36).toUpper(); }197 QString getSimulatorIDAsString() const { return _simulatorID.toString().mid(1,36).toUpper(); }
198 198
199 void setVoxelDataDirty() { _voxelDataChanged = true; }199 void setVoxelDataDirty() { _voxelDataChanged = true; }
200
201 void setLinePointsDirty() {_linePointsChanged = true; }
200 202
201 void setCreated(QDateTime& v);203 void setCreated(QDateTime& v);
202 204
libraries/entities/src/EntityScriptingInterface.cpp+52−0
@@ -442,6 +442,43 @@ bool EntityScriptingInterface::setVoxels(QUuid entityID, · 441 unmodified lines
442 return true;442 return true;
443}443}
444 444
445bool 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
445bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) {482bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) {
446 return setVoxels(entityID, [center, radius, value](PolyVoxEntityItem& polyVoxEntity) {483 return setVoxels(entityID, [center, radius, value](PolyVoxEntityItem& polyVoxEntity) {
447 polyVoxEntity.setSphere(center, radius, value);484 polyVoxEntity.setSphere(center, radius, value);
@@ -460,6 +497,21 @@ bool EntityScriptingInterface::setAllVoxels(QUuid entityID, int value) { · 12 unmodified lines
460 });497 });
461}498}
462 499
500bool 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
507bool EntityScriptingInterface::appendPoint(QUuid entityID, const glm::vec3& point) {
508 return setPoints(entityID, [point](LineEntityItem& lineEntity) -> bool
509 {
510 return lineEntity.appendPoint(point);
511 });
512
513}
514
463 515
464bool EntityScriptingInterface::actionWorker(const QUuid& entityID,516bool EntityScriptingInterface::actionWorker(const QUuid& entityID,
465 std::function<bool(EntitySimulation*, EntityItemPointer)> actor) {517 std::function<bool(EntitySimulation*, EntityItemPointer)> actor) {
libraries/entities/src/EntityScriptingInterface.h+5−0
@@ -22,6 +22,7 @@ · 21 unmodified lines
22#include <OctreeScriptingInterface.h>22#include <OctreeScriptingInterface.h>
23#include <RegisteredMetaTypes.h>23#include <RegisteredMetaTypes.h>
24#include "PolyVoxEntityItem.h"24#include "PolyVoxEntityItem.h"
25#include "LineEntityItem.h"
25 26
26#include "EntityEditPacketSender.h"27#include "EntityEditPacketSender.h"
27 28
@@ -121,6 +122,9 @@ public slots: · 93 unmodified lines
121 Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value);122 Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value);
122 Q_INVOKABLE bool setVoxel(QUuid entityID, const glm::vec3& position, int value);123 Q_INVOKABLE bool setVoxel(QUuid entityID, const glm::vec3& position, int value);
123 Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value);124 Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value);
125
126 Q_INVOKABLE bool setAllPoints(QUuid entityID, const QVector<glm::vec3>& points);
127 Q_INVOKABLE bool appendPoint(QUuid entityID, const glm::vec3& point);
124 128
125 Q_INVOKABLE void dumpTree() const;129 Q_INVOKABLE void dumpTree() const;
126 130
@@ -157,6 +161,7 @@ signals: · 30 unmodified lines
157private:161private:
158 bool actionWorker(const QUuid& entityID, std::function<bool(EntitySimulation*, EntityItemPointer)> actor);162 bool actionWorker(const QUuid& entityID, std::function<bool(EntitySimulation*, EntityItemPointer)> actor);
159 bool setVoxels(QUuid entityID, std::function<void(PolyVoxEntityItem&)> actor);163 bool setVoxels(QUuid entityID, std::function<void(PolyVoxEntityItem&)> actor);
164 bool setPoints(QUuid entityID, std::function<bool(LineEntityItem&)> actor);
160 void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties);165 void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties);
161 166
162 /// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode167 /// 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
23 23
24 24
25const float LineEntityItem::DEFAULT_LINE_WIDTH = 2.0f;25const float LineEntityItem::DEFAULT_LINE_WIDTH = 2.0f;
26const int LineEntityItem::MAX_POINTS_PER_LINE = 70;
26 27
27 28
28EntityItemPointer LineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {29EntityItemPointer LineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
@@ -85,24 +86,38 @@ bool LineEntityItem::setProperties(const EntityItemProperties& properties) { · 56 unmodified lines
85 return somethingChanged;86 return somethingChanged;
86}87}
87 88
88void LineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {89bool LineEntityItem::appendPoint(const glm::vec3& point) {
89 QVector<glm::vec3> sanitizedPoints;90 if (_points.size() > MAX_POINTS_PER_LINE - 1) {
90 int invalidPoints = 0;91 qDebug() << "MAX POINTS REACHED!";
92 return false;
93 }
94 glm::vec3 halfBox = getDimensions() * 0.5f;
95 if ( (point.x < - halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < - halfBox.z || point.z > halfBox.z) ) {
96 qDebug() << "Point is outside entity's bounding box";
97 return false;
98 }
99 _points << point;
100 _pointsChanged = true;
101 return true;
102}
103
104bool LineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {
105 if (points.size() > MAX_POINTS_PER_LINE) {
106 return false;
107 }
91 for (int i = 0; i < points.size(); i++) {108 for (int i = 0; i < points.size(); i++) {
92 glm::vec3 point = points.at(i);109 glm::vec3 point = points.at(i);
93 // Make sure all of our points are valid numbers.110 glm::vec3 pos = getPosition();
94 // Must be greater than 0 because vector component is set to 0 if it is invalid data. Also should never be greater than TREE_SCALE111 glm::vec3 halfBox = getDimensions() * 0.5f;
95 if ( (point.x > 0 && point.x < TREE_SCALE) && (point.y > 0 && point.y < TREE_SCALE) && (point.z > 0 && point.z < TREE_SCALE) ) {112 if ( (point.x < - halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < - halfBox.z || point.z > halfBox.z) ) {
96 sanitizedPoints << point;113 qDebug() << "Point is outside entity's bounding box";
97 } else {114 return false;
98 ++invalidPoints;
99 }115 }
116
100 }117 }
101 if (invalidPoints > 0) {118 _points = points;
102 qDebug() << "Line with" << invalidPoints << "INVALID POINTS";
103 }
104 _points = sanitizedPoints;
105 _pointsChanged = true;119 _pointsChanged = true;
120 return true;
106}121}
107 122
108int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,123int 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
54 void setLineWidth(float lineWidth){ _lineWidth = lineWidth; }54 void setLineWidth(float lineWidth){ _lineWidth = lineWidth; }
55 float getLineWidth() const{ return _lineWidth; }55 float getLineWidth() const{ return _lineWidth; }
56 56
57 void setLinePoints(const QVector<glm::vec3>& points);57 bool setLinePoints(const QVector<glm::vec3>& points);
58 bool appendPoint(const glm::vec3& point);
58 59
59 const QVector<glm::vec3>& getLinePoints() const{ return _points; }60 const QVector<glm::vec3>& getLinePoints() const{ return _points; }
60 61
@@ -68,6 +69,7 @@ class LineEntityItem : public EntityItem { · 7 unmodified lines
68 69
69 virtual void debugDump() const;70 virtual void debugDump() const;
70 static const float DEFAULT_LINE_WIDTH;71 static const float DEFAULT_LINE_WIDTH;
72 static const int MAX_POINTS_PER_LINE;
71 73
72 protected:74 protected:
73 rgbColor _color;75 rgbColor _color;
libraries/entities/src/PolyVoxEntityItem.cpp+7−0
@@ -168,3 +168,10 @@ void PolyVoxEntityItem::debugDump() const { · 167 unmodified lines
168 qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions());168 qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions());
169 qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);169 qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
170}170}
171
172void 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
61 SURFACE_EDGED_CUBIC61 SURFACE_EDGED_CUBIC
62 };62 };
63 63
64 virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { _voxelSurfaceStyle = voxelSurfaceStyle; }64 void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle);
65 virtual void setVoxelSurfaceStyle(uint16_t voxelSurfaceStyle) {65 // this other version of setVoxelSurfaceStyle is needed for SET_ENTITY_PROPERTY_FROM_PROPERTIES
66 setVoxelSurfaceStyle((PolyVoxSurfaceStyle) voxelSurfaceStyle);66 void setVoxelSurfaceStyle(uint16_t voxelSurfaceStyle) { setVoxelSurfaceStyle((PolyVoxSurfaceStyle) voxelSurfaceStyle); }
67 }
68 virtual PolyVoxSurfaceStyle getVoxelSurfaceStyle() const { return _voxelSurfaceStyle; }67 virtual PolyVoxSurfaceStyle getVoxelSurfaceStyle() const { return _voxelSurfaceStyle; }
69 68
70 static const glm::vec3 DEFAULT_VOXEL_VOLUME_SIZE;69 static const glm::vec3 DEFAULT_VOXEL_VOLUME_SIZE;
@@ -89,6 +88,10 @@ class PolyVoxEntityItem : public EntityItem { · 18 unmodified lines
89 static QByteArray makeEmptyVoxelData(quint16 voxelXSize = 16, quint16 voxelYSize = 16, quint16 voxelZSize = 16);88 static QByteArray makeEmptyVoxelData(quint16 voxelXSize = 16, quint16 voxelYSize = 16, quint16 voxelZSize = 16);
90 89
91 protected:90 protected:
91 virtual void updateVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) {
92 _voxelSurfaceStyle = voxelSurfaceStyle;
93 }
94
92 glm::vec3 _voxelVolumeSize; // this is always 3 bytes95 glm::vec3 _voxelVolumeSize; // this is always 3 bytes
93 QByteArray _voxelData;96 QByteArray _voxelData;
94 PolyVoxSurfaceStyle _voxelSurfaceStyle;97 PolyVoxSurfaceStyle _voxelSurfaceStyle;
libraries/fbx/src/FBXReader.cpp+37−6
@@ -506,7 +506,7 @@ FBXNode parseFBX(QIODevice* device) { · 505 unmodified lines
506 506
507QVector<glm::vec4> createVec4Vector(const QVector<double>& doubleVector) {507QVector<glm::vec4> createVec4Vector(const QVector<double>& doubleVector) {
508 QVector<glm::vec4> values;508 QVector<glm::vec4> values;
509 for (const double* it = doubleVector.constData(), *end = it + (doubleVector.size() / 4 * 4); it != end; ) {509 for (const double* it = doubleVector.constData(), *end = it + ((doubleVector.size() / 4) * 4); it != end; ) {
510 float x = *it++;510 float x = *it++;
511 float y = *it++;511 float y = *it++;
512 float z = *it++;512 float z = *it++;
@@ -516,9 +516,27 @@ QVector<glm::vec4> createVec4Vector(const QVector<double>& doubleVector) { · 3 unmodified lines
516 return values;516 return values;
517}517}
518 518
519
520QVector<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
519QVector<glm::vec3> createVec3Vector(const QVector<double>& doubleVector) {537QVector<glm::vec3> createVec3Vector(const QVector<double>& doubleVector) {
520 QVector<glm::vec3> values;538 QVector<glm::vec3> values;
521 for (const double* it = doubleVector.constData(), *end = it + (doubleVector.size() / 3 * 3); it != end; ) {539 for (const double* it = doubleVector.constData(), *end = it + ((doubleVector.size() / 3) * 3); it != end; ) {
522 float x = *it++;540 float x = *it++;
523 float y = *it++;541 float y = *it++;
524 float z = *it++;542 float z = *it++;
@@ -529,7 +547,7 @@ QVector<glm::vec3> createVec3Vector(const QVector<double>& doubleVector) { · 4 unmodified lines
529 547
530QVector<glm::vec2> createVec2Vector(const QVector<double>& doubleVector) {548QVector<glm::vec2> createVec2Vector(const QVector<double>& doubleVector) {
531 QVector<glm::vec2> values;549 QVector<glm::vec2> values;
532 for (const double* it = doubleVector.constData(), *end = it + (doubleVector.size() / 2 * 2); it != end; ) {550 for (const double* it = doubleVector.constData(), *end = it + ((doubleVector.size() / 2) * 2); it != end; ) {
533 float s = *it++;551 float s = *it++;
534 float t = *it++;552 float t = *it++;
535 values.append(glm::vec2(s, -t));553 values.append(glm::vec2(s, -t));
@@ -799,6 +817,7 @@ public: · 263 unmodified lines
799 QVector<int> normalIndices;817 QVector<int> normalIndices;
800 818
801 bool colorsByVertex;819 bool colorsByVertex;
820 glm::vec4 averageColor{1.0f, 1.0f, 1.0f, 1.0f};
802 QVector<glm::vec4> colors;821 QVector<glm::vec4> colors;
803 QVector<int> colorIndices;822 QVector<int> colorIndices;
804 823
@@ -940,8 +959,7 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) { · 135 unmodified lines
940 bool indexToDirect = false;959 bool indexToDirect = false;
941 foreach (const FBXNode& subdata, child.children) {960 foreach (const FBXNode& subdata, child.children) {
942 if (subdata.name == "Colors") {961 if (subdata.name == "Colors") {
943 data.colors = createVec4Vector(getDoubleVector(subdata));962 data.colors = createVec4VectorRGBA(getDoubleVector(subdata), data.averageColor);
944
945 } else if (subdata.name == "ColorsIndex") {963 } else if (subdata.name == "ColorsIndex") {
946 data.colorIndices = getIntVector(subdata);964 data.colorIndices = getIntVector(subdata);
947 965
@@ -956,6 +974,19 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) { · 8 unmodified lines
956 // hack to work around wacky Makehuman exports974 // hack to work around wacky Makehuman exports
957 data.colorsByVertex = true;975 data.colorsByVertex = true;
958 }976 }
977
978#if defined(FBXREADER_KILL_BLACK_COLOR_ATTRIBUTE)
979 // Potential feature where we decide to kill the color attribute is to dark?
980 // Tested with the model:
981 // https://hifi-public.s3.amazonaws.com/ryan/gardenLight2.fbx
982 // let's check if we did have true data ?
983 if (glm::all(glm::lessThanEqual(data.averageColor, glm::vec4(0.09f)))) {
984 data.colors.clear();
985 data.colorIndices.clear();
986 data.colorsByVertex = false;
987 qCDebug(modelformat) << "LayerElementColor has an average value of 0.0f... let's forget it.";
988 }
989#endif
959 990
960 } else if (child.name == "LayerElementUV") {991 } else if (child.name == "LayerElementUV") {
961 if (child.properties.at(0).toInt() == 0) {992 if (child.properties.at(0).toInt() == 0) {
@@ -1251,7 +1282,7 @@ FBXLight extractLight(const FBXNode& object) { · 289 unmodified lines
1251 if (property.name == "P") {1282 if (property.name == "P") {
1252 QString propname = property.properties.at(0).toString();1283 QString propname = property.properties.at(0).toString();
1253 if (propname == "Intensity") {1284 if (propname == "Intensity") {
1254 light.intensity = 0.01f * property.properties.at(valIndex).value<double>();1285 light.intensity = 0.01f * property.properties.at(valIndex).value<float>();
1255 } else if (propname == "Color") {1286 } else if (propname == "Color") {
1256 light.color = getVec3(property.properties, valIndex);1287 light.color = getVec3(property.properties, valIndex);
1257 }1288 }
libraries/gpu/src/gpu/Batch.h+3−1
@@ -70,7 +70,7 @@ public: · 69 unmodified lines
70 typedef Stream::Slot Slot;70 typedef Stream::Slot Slot;
71 71
72 Batch();72 Batch();
73 Batch(const Batch& batch);73 explicit Batch(const Batch& batch);
74 ~Batch();74 ~Batch();
75 75
76 void clear();76 void clear();
@@ -148,6 +148,7 @@ public: · 71 unmodified lines
148 void _glDrawBuffers(GLsizei n, const GLenum* bufs);148 void _glDrawBuffers(GLsizei n, const GLenum* bufs);
149 149
150 void _glUseProgram(GLuint program);150 void _glUseProgram(GLuint program);
151 void _glUniform1i(GLint location, GLint v0);
151 void _glUniform1f(GLint location, GLfloat v0);152 void _glUniform1f(GLint location, GLfloat v0);
152 void _glUniform2f(GLint location, GLfloat v0, GLfloat v1);153 void _glUniform2f(GLint location, GLfloat v0, GLfloat v1);
153 void _glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);154 void _glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
@@ -210,6 +211,7 @@ public: · 56 unmodified lines
210 COMMAND_glDrawBuffers,211 COMMAND_glDrawBuffers,
211 212
212 COMMAND_glUseProgram,213 COMMAND_glUseProgram,
214 COMMAND_glUniform1i,
213 COMMAND_glUniform1f,215 COMMAND_glUniform1f,
214 COMMAND_glUniform2f,216 COMMAND_glUniform2f,
215 COMMAND_glUniform3f,217 COMMAND_glUniform3f,
libraries/gpu/src/gpu/GLBackend.cpp+57−0
@@ -12,6 +12,8 @@ · 11 unmodified lines
12#include "GLBackendShared.h"12#include "GLBackendShared.h"
13#include <glm/gtc/type_ptr.hpp>13#include <glm/gtc/type_ptr.hpp>
14 14
15using namespace gpu;
16
15GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = 17GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
16{18{
17 (&::gpu::GLBackend::do_draw),19 (&::gpu::GLBackend::do_draw),
@@ -59,6 +61,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = · 41 unmodified lines
59 (&::gpu::GLBackend::do_glDrawBuffers),61 (&::gpu::GLBackend::do_glDrawBuffers),
60 62
61 (&::gpu::GLBackend::do_glUseProgram),63 (&::gpu::GLBackend::do_glUseProgram),
64 (&::gpu::GLBackend::do_glUniform1i),
62 (&::gpu::GLBackend::do_glUniform1f),65 (&::gpu::GLBackend::do_glUniform1f),
63 (&::gpu::GLBackend::do_glUniform2f),66 (&::gpu::GLBackend::do_glUniform2f),
64 (&::gpu::GLBackend::do_glUniform3f),67 (&::gpu::GLBackend::do_glUniform3f),
@@ -141,6 +144,14 @@ bool GLBackend::checkGLError(const char* name) { · 76 unmodified lines
141 }144 }
142}145}
143 146
147bool GLBackend::checkGLErrorDebug(const char* name) {
148#ifdef DEBUG
149 return checkGLError(name);
150#else
151 Q_UNUSED(name);
152 return false;
153#endif
154}
144 155
145void GLBackend::syncCache() {156void GLBackend::syncCache() {
146 syncTransformStateCache();157 syncTransformStateCache();
@@ -433,6 +444,29 @@ void GLBackend::do_glUseProgram(Batch& batch, uint32 paramOffset) { · 286 unmodified lines
433 (void) CHECK_GL_ERROR();444 (void) CHECK_GL_ERROR();
434}445}
435 446
447void 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}
457void 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
436void Batch::_glUniform1f(GLint location, GLfloat v0) {470void Batch::_glUniform1f(GLint location, GLfloat v0) {
437 if (location < 0) {471 if (location < 0) {
438 return;472 return;
@@ -449,6 +483,8 @@ void GLBackend::do_glUniform1f(Batch& batch, uint32 paramOffset) { · 10 unmodified lines
449 // because these uniform setters are deprecated and we don;t want to create side effect483 // because these uniform setters are deprecated and we don;t want to create side effect
450 return;484 return;
451 }485 }
486 updatePipeline();
487
452 glUniform1f(488 glUniform1f(
453 batch._params[paramOffset + 1]._int,489 batch._params[paramOffset + 1]._int,
454 batch._params[paramOffset + 0]._float);490 batch._params[paramOffset + 0]._float);
@@ -471,6 +507,7 @@ void GLBackend::do_glUniform2f(Batch& batch, uint32 paramOffset) { · 16 unmodified lines
471 // because these uniform setters are deprecated and we don;t want to create side effect507 // because these uniform setters are deprecated and we don;t want to create side effect
472 return;508 return;
473 }509 }
510 updatePipeline();
474 glUniform2f(511 glUniform2f(
475 batch._params[paramOffset + 2]._int,512 batch._params[paramOffset + 2]._int,
476 batch._params[paramOffset + 1]._float,513 batch._params[paramOffset + 1]._float,
@@ -495,6 +532,7 @@ void GLBackend::do_glUniform3f(Batch& batch, uint32 paramOffset) { · 18 unmodified lines
495 // because these uniform setters are deprecated and we don;t want to create side effect532 // because these uniform setters are deprecated and we don;t want to create side effect
496 return;533 return;
497 }534 }
535 updatePipeline();
498 glUniform3f(536 glUniform3f(
499 batch._params[paramOffset + 3]._int,537 batch._params[paramOffset + 3]._int,
500 batch._params[paramOffset + 2]._float,538 batch._params[paramOffset + 2]._float,
@@ -519,6 +557,7 @@ void GLBackend::do_glUniform3fv(Batch& batch, uint32 paramOffset) { · 18 unmodified lines
519 // because these uniform setters are deprecated and we don;t want to create side effect557 // because these uniform setters are deprecated and we don;t want to create side effect
520 return;558 return;
521 }559 }
560 updatePipeline();
522 glUniform3fv(561 glUniform3fv(
523 batch._params[paramOffset + 2]._int,562 batch._params[paramOffset + 2]._int,
524 batch._params[paramOffset + 1]._uint,563 batch._params[paramOffset + 1]._uint,
@@ -544,6 +583,7 @@ void GLBackend::do_glUniform4fv(Batch& batch, uint32 paramOffset) { · 19 unmodified lines
544 // because these uniform setters are deprecated and we don;t want to create side effect583 // because these uniform setters are deprecated and we don;t want to create side effect
545 return;584 return;
546 }585 }
586 updatePipeline();
547 glUniform4fv(587 glUniform4fv(
548 batch._params[paramOffset + 2]._int,588 batch._params[paramOffset + 2]._int,
549 batch._params[paramOffset + 1]._uint,589 batch._params[paramOffset + 1]._uint,
@@ -569,6 +609,7 @@ void GLBackend::do_glUniformMatrix4fv(Batch& batch, uint32 paramOffset) { · 19 unmodified lines
569 // because these uniform setters are deprecated and we don;t want to create side effect609 // because these uniform setters are deprecated and we don;t want to create side effect
570 return;610 return;
571 }611 }
612 updatePipeline();
572 glUniformMatrix4fv(613 glUniformMatrix4fv(
573 batch._params[paramOffset + 3]._int,614 batch._params[paramOffset + 3]._int,
574 batch._params[paramOffset + 2]._uint,615 batch._params[paramOffset + 2]._uint,
@@ -656,4 +697,20 @@ void GLBackend::fetchMatrix(GLenum target, glm::mat4 & m) { · 81 unmodified lines
656 glGetFloatv(target, glm::value_ptr(m));697 glGetFloatv(target, glm::value_ptr(m));
657}698}
658 699
700void GLBackend::checkGLStackStable(std::function<void()> f) {
701#ifdef DEBUG
702 GLint mvDepth, prDepth;
703 glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &mvDepth);
704 glGetIntegerv(GL_PROJECTION_STACK_DEPTH, &prDepth);
705#endif
706
707 f();
659 708
709#ifdef DEBUG
710 GLint mvDepthFinal, prDepthFinal;
711 glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &mvDepthFinal);
712 glGetIntegerv(GL_PROJECTION_STACK_DEPTH, &prDepthFinal);
713 Q_ASSERT(mvDepth == mvDepthFinal);
714 Q_ASSERT(prDepth == prDepthFinal);
715#endif
716}
libraries/gpu/src/gpu/GLBackend.h+9−1
@@ -12,11 +12,13 @@ · 11 unmodified lines
12#define hifi_gpu_GLBackend_h12#define hifi_gpu_GLBackend_h
13 13
14#include <assert.h>14#include <assert.h>
15#include <functional>
16#include <bitset>
17
15#include "GPUConfig.h"18#include "GPUConfig.h"
16 19
17#include "Context.h"20#include "Context.h"
18#include "Batch.h"21#include "Batch.h"
19#include <bitset>
20 22
21 23
22namespace gpu {24namespace gpu {
@@ -47,6 +49,11 @@ public: · 24 unmodified lines
47 49
48 static bool checkGLError(const char* name = nullptr);50 static bool checkGLError(const char* name = nullptr);
49 51
52 // Only checks in debug builds
53 static bool checkGLErrorDebug(const char* name = nullptr);
54
55 static void checkGLStackStable(std::function<void()> f);
56
50 static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet());57 static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet());
51 58
52 59
@@ -377,6 +384,7 @@ protected: · 324 unmodified lines
377 void do_glDrawBuffers(Batch& batch, uint32 paramOffset);384 void do_glDrawBuffers(Batch& batch, uint32 paramOffset);
378 385
379 void do_glUseProgram(Batch& batch, uint32 paramOffset);386 void do_glUseProgram(Batch& batch, uint32 paramOffset);
387 void do_glUniform1i(Batch& batch, uint32 paramOffset);
380 void do_glUniform1f(Batch& batch, uint32 paramOffset);388 void do_glUniform1f(Batch& batch, uint32 paramOffset);
381 void do_glUniform2f(Batch& batch, uint32 paramOffset);389 void do_glUniform2f(Batch& batch, uint32 paramOffset);
382 void do_glUniform3f(Batch& batch, uint32 paramOffset);390 void do_glUniform3f(Batch& batch, uint32 paramOffset);
libraries/gpu/src/gpu/GLBackendOutput.cpp+1−0
@@ -11,6 +11,7 @@ · 10 unmodified lines
11#include "GPULogging.h"11#include "GPULogging.h"
12#include "GLBackendShared.h"12#include "GLBackendShared.h"
13 13
14using namespace gpu;
14 15
15GLBackend::GLFramebuffer::GLFramebuffer() {}16GLBackend::GLFramebuffer::GLFramebuffer() {}
16 17
libraries/gpu/src/gpu/GLBackendShared.h+9−9
@@ -17,9 +17,7 @@ · 16 unmodified lines
17 17
18#include "Batch.h"18#include "Batch.h"
19 19
20using namespace gpu;20static const GLenum _primitiveToGLmode[gpu::NUM_PRIMITIVES] = {
21
22static const GLenum _primitiveToGLmode[NUM_PRIMITIVES] = {
23 GL_POINTS,21 GL_POINTS,
24 GL_LINES,22 GL_LINES,
25 GL_LINE_STRIP,23 GL_LINE_STRIP,
@@ -30,7 +28,7 @@ static const GLenum _primitiveToGLmode[NUM_PRIMITIVES] = { · 4 unmodified lines
30 GL_QUAD_STRIP,28 GL_QUAD_STRIP,
31};29};
32 30
33static const GLenum _elementTypeToGLType[NUM_TYPES]= {31static const GLenum _elementTypeToGLType[gpu::NUM_TYPES] = {
34 GL_FLOAT,32 GL_FLOAT,
35 GL_INT,33 GL_INT,
36 GL_UNSIGNED_INT,34 GL_UNSIGNED_INT,
@@ -49,10 +47,12 @@ static const GLenum _elementTypeToGLType[NUM_TYPES]= { · 12 unmodified lines
49 GL_UNSIGNED_BYTE47 GL_UNSIGNED_BYTE
50};48};
51 49
52#if _DEBUG50// Stupid preprocessor trick to turn the line macro into a string
53#define CHECK_GL_ERROR() ::gpu::GLBackend::checkGLError(__FUNCTION__)51#define CHECK_GL_ERROR_HELPER(x) #x
54#else52// FIXME doesn't build on Linux or Mac. Hmmmm
55#define CHECK_GL_ERROR() false53// #define CHECK_GL_ERROR() gpu::GLBackend::checkGLErrorDebug(__FUNCTION__ ":" CHECK_GL_ERROR_HELPER(__LINE__))
56#endif54#define CHECK_GL_ERROR() gpu::GLBackend::checkGLErrorDebug(__FUNCTION__)
55
56#define CHECK_GL_STACK_STABLE(f) gpu::GLBackend::checkGLStackStable(f)
57 57
58#endif58#endif
libraries/gpu/src/gpu/GLBackendTexture.cpp+3−2
@@ -11,6 +11,7 @@ · 10 unmodified lines
11#include "GPULogging.h"11#include "GPULogging.h"
12#include "GLBackendShared.h"12#include "GLBackendShared.h"
13 13
14using namespace gpu;
14 15
15GLBackend::GLTexture::GLTexture() :16GLBackend::GLTexture::GLTexture() :
16 _storageStamp(0),17 _storageStamp(0),
@@ -343,10 +344,10 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { · 326 unmodified lines
343 if (bytes && texture.isAutogenerateMips()) {344 if (bytes && texture.isAutogenerateMips()) {
344 glGenerateMipmap(GL_TEXTURE_2D);345 glGenerateMipmap(GL_TEXTURE_2D);
345 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);346 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
346 } else {347 }/* else {
347 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);348 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
348 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);349 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
349 }350 }*/
350 351
351 object->_target = GL_TEXTURE_2D;352 object->_target = GL_TEXTURE_2D;
352 353
libraries/gpu/src/gpu/GLBackendTransform.cpp+13−16
@@ -75,6 +75,8 @@ void GLBackend::syncTransformStateCache() { · 74 unmodified lines
75}75}
76 76
77void GLBackend::updateTransform() {77void GLBackend::updateTransform() {
78 GLint originalMatrixMode;
79 glGetIntegerv(GL_MATRIX_MODE, &originalMatrixMode);
78 // Check all the dirty flags and update the state accordingly80 // Check all the dirty flags and update the state accordingly
79 if (_transform._invalidProj) {81 if (_transform._invalidProj) {
80 _transform._transformCamera._projection = _transform._projection;82 _transform._transformCamera._projection = _transform._projection;
@@ -132,12 +134,13 @@ void GLBackend::updateTransform() { · 51 unmodified lines
132 (void) CHECK_GL_ERROR();134 (void) CHECK_GL_ERROR();
133 }135 }
134 136
137
135 if (_transform._invalidModel || _transform._invalidView) {138 if (_transform._invalidModel || _transform._invalidView) {
139 if (_transform._lastMode != GL_MODELVIEW) {
140 glMatrixMode(GL_MODELVIEW);
141 _transform._lastMode = GL_MODELVIEW;
142 }
136 if (!_transform._model.isIdentity()) {143 if (!_transform._model.isIdentity()) {
137 if (_transform._lastMode != GL_MODELVIEW) {
138 glMatrixMode(GL_MODELVIEW);
139 _transform._lastMode = GL_MODELVIEW;
140 }
141 Transform::Mat4 modelView;144 Transform::Mat4 modelView;
142 if (!_transform._view.isIdentity()) {145 if (!_transform._view.isIdentity()) {
143 Transform mvx;146 Transform mvx;
@@ -147,19 +150,12 @@ void GLBackend::updateTransform() { · 3 unmodified lines
147 _transform._model.getMatrix(modelView);150 _transform._model.getMatrix(modelView);
148 }151 }
149 glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView));152 glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView));
153 } else if (!_transform._view.isIdentity()) {
154 Transform::Mat4 modelView;
155 _transform._view.getInverseMatrix(modelView);
156 glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView));
150 } else {157 } else {
151 if (!_transform._view.isIdentity()) {158 glLoadIdentity();
152 if (_transform._lastMode != GL_MODELVIEW) {
153 glMatrixMode(GL_MODELVIEW);
154 _transform._lastMode = GL_MODELVIEW;
155 }
156 Transform::Mat4 modelView;
157 _transform._view.getInverseMatrix(modelView);
158 glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView));
159 } else {
160 // TODO: eventually do something about the matrix when neither view nor model is specified?
161 // glLoadIdentity();
162 }
163 }159 }
164 (void) CHECK_GL_ERROR();160 (void) CHECK_GL_ERROR();
165 }161 }
@@ -167,6 +163,7 @@ void GLBackend::updateTransform() { · 1 unmodified line
167 163
168 // Flags are clean164 // Flags are clean
169 _transform._invalidView = _transform._invalidProj = _transform._invalidModel = false;165 _transform._invalidView = _transform._invalidProj = _transform._invalidModel = false;
166 glMatrixMode(originalMatrixMode);
170}167}
171 168
172 169
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
581void sphericalHarmonicsEvaluateDirection(float * result, int order, const glm::vec3 & dir) {581void sphericalHarmonicsEvaluateDirection(float * result, int order, const glm::vec3 & dir) {
582 // calculate coefficients for first 3 bands of spherical harmonics582 // calculate coefficients for first 3 bands of spherical harmonics
583 double P_0_0 = 0.282094791773878140;583 double P_0_0 = 0.282094791773878140;
584 double P_1_0 = 0.488602511902919920 * dir.z;584 double P_1_0 = 0.488602511902919920 * (double)dir.z;
585 double P_1_1 = -0.488602511902919920;585 double P_1_1 = -0.488602511902919920;
586 double P_2_0 = 0.946174695757560080 * dir.z * dir.z - 0.315391565252520050;586 double P_2_0 = 0.946174695757560080 * (double)dir.z * (double)dir.z - 0.315391565252520050;
587 double P_2_1 = -1.092548430592079200 * dir.z;587 double P_2_1 = -1.092548430592079200 * (double)dir.z;
588 double P_2_2 = 0.546274215296039590;588 double P_2_2 = 0.546274215296039590;
589 result[0] = P_0_0;589 result[0] = P_0_0;
590 result[1] = P_1_1 * dir.y;590 result[1] = P_1_1 * (double)dir.y;
591 result[2] = P_1_0;591 result[2] = P_1_0;
592 result[3] = P_1_1 * dir.x;592 result[3] = P_1_1 * (double)dir.x;
593 result[4] = P_2_2 * (dir.x * dir.y + dir.y * dir.x);593 result[4] = P_2_2 * ((double)dir.x * (double)dir.y + (double)dir.y * (double)dir.x);
594 result[5] = P_2_1 * dir.y;594 result[5] = P_2_1 * (double)dir.y;
595 result[6] = P_2_0;595 result[6] = P_2_0;
596 result[7] = P_2_1 * dir.x;596 result[7] = P_2_1 * (double)dir.x;
597 result[8] = P_2_2 * (dir.x * dir.x - dir.y * dir.y);597 result[8] = P_2_2 * ((double)dir.x * (double)dir.x - (double)dir.y * (double)dir.y);
598}598}
599 599
600bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<glm::vec3> & output, const uint order) {600bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<glm::vec3> & output, const uint order) {
@@ -767,4 +767,4 @@ void SphericalHarmonics::evalFromTexture(const Texture& texture) { · 166 unmodified lines
767 L21 = coefs[7];767 L21 = coefs[7];
768 L22 = coefs[8];768 L22 = coefs[8];
769 }769 }
770}770}
libraries/model/src/model/Light.cpp+1−1
@@ -73,7 +73,7 @@ void Light::setMaximumRadius(float radius) { · 72 unmodified lines
73 radius = 1.0f;73 radius = 1.0f;
74 }74 }
75 float CutOffIntensityRatio = 0.05f;75 float CutOffIntensityRatio = 0.05f;
76 float surfaceRadius = radius / (sqrt(1.0f / CutOffIntensityRatio) - 1.f);76 float surfaceRadius = radius / (sqrtf(1.0f / CutOffIntensityRatio) - 1.0f);
77 editSchema()._attenuation = Vec4(surfaceRadius, 1.0f/surfaceRadius, CutOffIntensityRatio, radius);77 editSchema()._attenuation = Vec4(surfaceRadius, 1.0f/surfaceRadius, CutOffIntensityRatio, radius);
78}78}
79 79
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
72 72
73 thePipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, skyState));73 thePipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, skyState));
74 74
75 const float CLIP = 1.0;75 const float CLIP = 1.0f;
76 const glm::vec2 vertices[4] = { {-CLIP, -CLIP}, {CLIP, -CLIP}, {-CLIP, CLIP}, {CLIP, CLIP}};76 const glm::vec2 vertices[4] = { {-CLIP, -CLIP}, {CLIP, -CLIP}, {-CLIP, CLIP}, {CLIP, CLIP}};
77 theBuffer.reset(new gpu::Buffer(sizeof(vertices), (const gpu::Byte*) vertices));77 theBuffer.reset(new gpu::Buffer(sizeof(vertices), (const gpu::Byte*) vertices));
78 78
@@ -110,7 +110,7 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky · 31 unmodified lines
110 } else {110 } else {
111 // skybox has no cubemap, just clear the color buffer111 // skybox has no cubemap, just clear the color buffer
112 auto color = skybox.getColor();112 auto color = skybox.getColor();
113 batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(color, 0.0f), 0.f, 0); 113 batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(color, 0.0f), 0.0f, 0);
114 }114 }
115}115}
116 116
libraries/model/src/model/Stage.cpp+6−6
@@ -42,9 +42,9 @@ Mat4d EarthSunModel::evalWorldToGeoLocationMat(double longitude, double latitude · 41 unmodified lines
42 42
43void EarthSunModel::updateWorldToSurface() const {43void EarthSunModel::updateWorldToSurface() const {
44 // Check if the final position is too close to the earth center ?44 // Check if the final position is too close to the earth center ?
45 double absAltitude = _earthRadius + _altitude;45 float absAltitude = _earthRadius + _altitude;
46 if ( absAltitude < 0.01) {46 if ( absAltitude < 0.01f) {
47 absAltitude = 0.01;47 absAltitude = 0.01f;
48 }48 }
49 49
50 // Final world to local Frame50 // Final world to local Frame
@@ -263,8 +263,8 @@ double evalSunDeclinaison(double dayNumber) { · 212 unmodified lines
263void SunSkyStage::updateGraphicsObject() const {263void SunSkyStage::updateGraphicsObject() const {
264 // Always update the sunLongitude based on the current dayTime and the current origin264 // Always update the sunLongitude based on the current dayTime and the current origin
265 // The day time is supposed to be local at the origin265 // The day time is supposed to be local at the origin
266 double signedNormalizedDayTime = (_dayTime - NUM_HOURS_PER_HALF_DAY) / NUM_HOURS_PER_HALF_DAY;266 float signedNormalizedDayTime = (_dayTime - NUM_HOURS_PER_HALF_DAY) / NUM_HOURS_PER_HALF_DAY;
267 double sunLongitude = _earthSunModel.getLongitude() + (MAX_LONGITUDE * signedNormalizedDayTime);267 float sunLongitude = _earthSunModel.getLongitude() + (MAX_LONGITUDE * signedNormalizedDayTime);
268 _earthSunModel.setSunLongitude(sunLongitude);268 _earthSunModel.setSunLongitude(sunLongitude);
269 269
270 // And update the sunLAtitude as the declinaison depending of the time of the year270 // 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
302void SunSkyStage::setSkybox(const SkyboxPointer& skybox) {302void SunSkyStage::setSkybox(const SkyboxPointer& skybox) {
303 _skybox = skybox;303 _skybox = skybox;
304 invalidate();304 invalidate();
305}305}
libraries/model/src/model/Stage.h+1−1
@@ -72,7 +72,7 @@ public: · 71 unmodified lines
72 72
73protected:73protected:
74 float _scale = 1000.0f; //Km74 float _scale = 1000.0f; //Km
75 double _earthRadius = 6360.0;75 float _earthRadius = 6360.0;
76 76
77 Quat _surfaceOrientation;77 Quat _surfaceOrientation;
78 78
libraries/networking/src/AddressManager.cpp+4−0
@@ -308,6 +308,9 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const · 307 unmodified lines
308 handlePath(returnedPath, trigger);308 handlePath(returnedPath, trigger);
309 }309 }
310 } else {310 } else {
311 // we're going to hit the index path, set that as the _newHostLookupPath
312 _newHostLookupPath = INDEX_PATH;
313
311 // we didn't override the path or get one back - ask the DS for the viewpoint of its index path314 // we didn't override the path or get one back - ask the DS for the viewpoint of its index path
312 // which we will jump to if it exists315 // which we will jump to if it exists
313 emit pathChangeRequired(INDEX_PATH);316 emit pathChangeRequired(INDEX_PATH);
@@ -479,6 +482,7 @@ bool AddressManager::handleViewpoint(const QString& viewpointString, bool should · 165 unmodified lines
479 // We use _newHostLookupPath to determine if the client has already stored its last address482 // We use _newHostLookupPath to determine if the client has already stored its last address
480 // before moving to a new host thanks to the information in the same lookup URL.483 // before moving to a new host thanks to the information in the same lookup URL.
481 484
485
482 if (definitelyPathOnly || (!pathString.isEmpty() && pathString != _newHostLookupPath)) {486 if (definitelyPathOnly || (!pathString.isEmpty() && pathString != _newHostLookupPath)) {
483 addCurrentAddressToHistory(LookupTrigger::UserInput);487 addCurrentAddressToHistory(LookupTrigger::UserInput);
484 }488 }
libraries/networking/src/AddressManager.h+3−0
@@ -62,6 +62,9 @@ public: · 61 unmodified lines
62 62
63 void loadSettings(const QString& lookupString = QString());63 void loadSettings(const QString& lookupString = QString());
64 64
65 const QStack<QUrl>& getBackStack() const { return _backStack; }
66 const QStack<QUrl>& getForwardStack() const { return _forwardStack; }
67
65public slots:68public slots:
66 void handleLookupString(const QString& lookupString);69 void handleLookupString(const QString& lookupString);
67 70
libraries/networking/src/BandwidthRecorder.cpp+2−2
@@ -21,7 +21,7 @@ BandwidthRecorder::Channel::Channel() { · 20 unmodified lines
21float BandwidthRecorder::Channel::getAverageInputPacketsPerSecond() {21float BandwidthRecorder::Channel::getAverageInputPacketsPerSecond() {
22 float delt = _input.getEventDeltaAverage();22 float delt = _input.getEventDeltaAverage();
23 if (delt > 0.0f) {23 if (delt > 0.0f) {
24 return (1.0 / delt);24 return (1.0f / delt);
25 }25 }
26 return 0.0f;26 return 0.0f;
27}27}
@@ -29,7 +29,7 @@ float BandwidthRecorder::Channel::getAverageInputPacketsPerSecond() { · 1 unmodified line
29float BandwidthRecorder::Channel::getAverageOutputPacketsPerSecond() {29float BandwidthRecorder::Channel::getAverageOutputPacketsPerSecond() {
30 float delt = _input.getEventDeltaAverage();30 float delt = _input.getEventDeltaAverage();
31 if (delt > 0.0f) {31 if (delt > 0.0f) {
32 return (1.0 / _output.getEventDeltaAverage());32 return (1.0f / _output.getEventDeltaAverage());
33 }33 }
34 return 0.0f;34 return 0.0f;
35}35}
libraries/octree/src/CoverageMap.cpp+1−1
@@ -75,7 +75,7 @@ CoverageMap::~CoverageMap() { · 74 unmodified lines
75 75
76void CoverageMap::printStats() {76void CoverageMap::printStats() {
77 qCDebug(octree, "CoverageMap::printStats()...");77 qCDebug(octree, "CoverageMap::printStats()...");
78 qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f",MINIMUM_POLYGON_AREA_TO_STORE);78 qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f", (double)MINIMUM_POLYGON_AREA_TO_STORE);
79 qCDebug(octree, "_mapCount=%d",_mapCount);79 qCDebug(octree, "_mapCount=%d",_mapCount);
80 qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls);80 qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls);
81 qCDebug(octree, "_notAllInView=%d",_notAllInView);81 qCDebug(octree, "_notAllInView=%d",_notAllInView);
libraries/octree/src/CoverageMapV2.cpp+1−1
@@ -82,7 +82,7 @@ void CoverageMapV2::erase() { · 81 unmodified lines
82 82
83 if (_isRoot && wantDebugging) {83 if (_isRoot && wantDebugging) {
84 qCDebug(octree, "CoverageMapV2 last to be deleted...");84 qCDebug(octree, "CoverageMapV2 last to be deleted...");
85 qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f",MINIMUM_POLYGON_AREA_TO_STORE);85 qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f", (double)MINIMUM_POLYGON_AREA_TO_STORE);
86 qCDebug(octree, "_mapCount=%d",_mapCount);86 qCDebug(octree, "_mapCount=%d",_mapCount);
87 qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls);87 qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls);
88 qCDebug(octree, "_notAllInView=%d",_notAllInView);88 qCDebug(octree, "_notAllInView=%d",_notAllInView);
libraries/octree/src/OctreeElement.cpp+28−26
@@ -69,8 +69,8 @@ void OctreeElement::init(unsigned char * octalCode) { · 68 unmodified lines
69 // set up the _children union69 // set up the _children union
70 _childBitmask = 0;70 _childBitmask = 0;
71 _childrenExternal = false;71 _childrenExternal = false;
72 72
73 73
74#ifdef BLENDED_UNION_CHILDREN74#ifdef BLENDED_UNION_CHILDREN
75 _children.external = NULL;75 _children.external = NULL;
76 _singleChildrenCount++;76 _singleChildrenCount++;
@@ -662,7 +662,7 @@ void OctreeElement::deleteAllChildren() { · 585 unmodified lines
662 delete childAt;662 delete childAt;
663 }663 }
664 }664 }
665 665
666 if (_childrenExternal) {666 if (_childrenExternal) {
667 // if the children_t union represents _children.external we need to delete it here667 // if the children_t union represents _children.external we need to delete it here
668 delete[] _children.external;668 delete[] _children.external;
@@ -764,7 +764,7 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) { · 95 unmodified lines
764 memset(_children.external, 0, sizeof(OctreeElement*) * NUMBER_OF_CHILDREN);764 memset(_children.external, 0, sizeof(OctreeElement*) * NUMBER_OF_CHILDREN);
765 _children.external[firstIndex] = previousChild;765 _children.external[firstIndex] = previousChild;
766 _children.external[childIndex] = child;766 _children.external[childIndex] = child;
767 767
768 _childrenExternal = true;768 _childrenExternal = true;
769 769
770 _externalChildrenMemoryUsage += NUMBER_OF_CHILDREN * sizeof(OctreeElement*);770 _externalChildrenMemoryUsage += NUMBER_OF_CHILDREN * sizeof(OctreeElement*);
@@ -776,7 +776,7 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) { · 5 unmodified lines
776 776
777 delete[] _children.external;777 delete[] _children.external;
778 _childrenExternal = false;778 _childrenExternal = false;
779 779
780 _externalChildrenMemoryUsage -= NUMBER_OF_CHILDREN * sizeof(OctreeElement*);780 _externalChildrenMemoryUsage -= NUMBER_OF_CHILDREN * sizeof(OctreeElement*);
781 if (childIndex == firstIndex) {781 if (childIndex == firstIndex) {
782 _children.single = previousSecondChild;782 _children.single = previousSecondChild;
@@ -1203,12 +1203,13 @@ void OctreeElement::printDebugDetails(const char* label) const { · 420 unmodified lines
1203 setAtBit(childBits,i);1203 setAtBit(childBits,i);
1204 }1204 }
1205 }1205 }
1206 1206
1207 QDebug elementDebug = qDebug().nospace();1207 QDebug elementDebug = qDebug().nospace();
1208 1208
1209 QString resultString;1209 QString resultString;
1210 resultString.sprintf("%s - Voxel at corner=(%f,%f,%f) size=%f\n isLeaf=%s isDirty=%s shouldRender=%s\n children=", label,1210 resultString.sprintf("%s - Voxel at corner=(%f,%f,%f) size=%f\n isLeaf=%s isDirty=%s shouldRender=%s\n children=", label,
1211 _cube.getCorner().x, _cube.getCorner().y, _cube.getCorner().z, _cube.getScale(),1211 (double)_cube.getCorner().x, (double)_cube.getCorner().y, (double)_cube.getCorner().z,
1212 (double)_cube.getScale(),
1212 debug::valueOf(isLeaf()), debug::valueOf(isDirty()), debug::valueOf(getShouldRender()));1213 debug::valueOf(isLeaf()), debug::valueOf(isDirty()), debug::valueOf(getShouldRender()));
1213 elementDebug << resultString;1214 elementDebug << resultString;
1214 1215
@@ -1236,7 +1237,7 @@ ViewFrustum::location OctreeElement::inFrustum(const ViewFrustum& viewFrustum) c · 21 unmodified lines
1236// By doing this, we don't need to test each child voxel's position vs the LOD boundary1237// By doing this, we don't need to test each child voxel's position vs the LOD boundary
1237bool OctreeElement::calculateShouldRender(const ViewFrustum* viewFrustum, float voxelScaleSize, int boundaryLevelAdjust) const {1238bool OctreeElement::calculateShouldRender(const ViewFrustum* viewFrustum, float voxelScaleSize, int boundaryLevelAdjust) const {
1238 bool shouldRender = false;1239 bool shouldRender = false;
1239 1240
1240 if (hasContent()) {1241 if (hasContent()) {
1241 float furthestDistance = furthestDistanceToCamera(*viewFrustum);1242 float furthestDistance = furthestDistanceToCamera(*viewFrustum);
1242 float childBoundary = boundaryDistanceForRenderLevel(getLevel() + 1 + boundaryLevelAdjust, voxelScaleSize);1243 float childBoundary = boundaryDistanceForRenderLevel(getLevel() + 1 + boundaryLevelAdjust, voxelScaleSize);
@@ -1330,7 +1331,7 @@ void OctreeElement::notifyUpdateHooks() { · 87 unmodified lines
1330}1331}
1331 1332
1332bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,1333bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
1333 bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, 1334 bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
1334 void** intersectedObject, bool precisionPicking) {1335 void** intersectedObject, bool precisionPicking) {
1335 1336
1336 keepSearching = true; // assume that we will continue searching after this.1337 keepSearching = true; // assume that we will continue searching after this.
@@ -1354,7 +1355,7 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 · 17 unmodified lines
1354 // for any details inside the cube to be closer so we don't need to consider them.1355 // for any details inside the cube to be closer so we don't need to consider them.
1355 if (_cube.contains(origin) || distanceToElementCube < distance) {1356 if (_cube.contains(origin) || distanceToElementCube < distance) {
1356 1357
1357 if (findDetailedRayIntersection(origin, direction, keepSearching, element, distanceToElementDetails, 1358 if (findDetailedRayIntersection(origin, direction, keepSearching, element, distanceToElementDetails,
1358 face, intersectedObject, precisionPicking, distanceToElementCube)) {1359 face, intersectedObject, precisionPicking, distanceToElementCube)) {
1359 1360
1360 if (distanceToElementDetails < distance) {1361 if (distanceToElementDetails < distance) {
@@ -1368,10 +1369,10 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 · 7 unmodified lines
1368}1369}
1369 1370
1370bool OctreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,1371bool OctreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
1371 bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, 1372 bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
1372 void** intersectedObject, bool precisionPicking, float distanceToElementCube) {1373 void** intersectedObject, bool precisionPicking, float distanceToElementCube) {
1373 1374
1374 // we did hit this element, so calculate appropriate distances 1375 // we did hit this element, so calculate appropriate distances
1375 if (hasContent()) {1376 if (hasContent()) {
1376 element = this;1377 element = this;
1377 distance = distanceToElementCube;1378 distance = distanceToElementCube;
@@ -1399,7 +1400,8 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float · 21 unmodified lines
1399 float halfOurScale = ourScale / 2.0f;1400 float halfOurScale = ourScale / 2.0f;
1400 1401
1401 if(s > ourScale) {1402 if(s > ourScale) {
1402 qCDebug(octree, "UNEXPECTED -- OctreeElement::getOrCreateChildElementAt() s=[%f] > ourScale=[%f] ", s, ourScale);1403 qCDebug(octree, "UNEXPECTED -- OctreeElement::getOrCreateChildElementAt() s=[%f] > ourScale=[%f] ",
1404 (double)s, (double)ourScale);
1403 }1405 }
1404 1406
1405 if (s > halfOurScale) {1407 if (s > halfOurScale) {
@@ -1466,21 +1468,21 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float · 60 unmodified lines
1466 1468
1467OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AACube& cube) {1469OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AACube& cube) {
1468 OctreeElement* child = NULL;1470 OctreeElement* child = NULL;
1469 1471
1470 int childIndex = getMyChildContaining(cube);1472 int childIndex = getMyChildContaining(cube);
1471 1473
1472 // If getMyChildContaining() returns CHILD_UNKNOWN then it means that our level1474 // If getMyChildContaining() returns CHILD_UNKNOWN then it means that our level
1473 // is the correct level for this cube1475 // is the correct level for this cube
1474 if (childIndex == CHILD_UNKNOWN) {1476 if (childIndex == CHILD_UNKNOWN) {
1475 return this;1477 return this;
1476 }1478 }
1477 1479
1478 // Now, check if we have a child at that location1480 // Now, check if we have a child at that location
1479 child = getChildAtIndex(childIndex);1481 child = getChildAtIndex(childIndex);
1480 if (!child) {1482 if (!child) {
1481 child = addChildAtIndex(childIndex);1483 child = addChildAtIndex(childIndex);
1482 }1484 }
1483 1485
1484 // if we've made a really small child, then go ahead and use that one.1486 // if we've made a really small child, then go ahead and use that one.
1485 if (child->getScale() <= SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE) {1487 if (child->getScale() <= SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE) {
1486 return child;1488 return child;
@@ -1492,21 +1494,21 @@ OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AACube& cu · 5 unmodified lines
1492 1494
1493OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AABox& box) {1495OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AABox& box) {
1494 OctreeElement* child = NULL;1496 OctreeElement* child = NULL;
1495 1497
1496 int childIndex = getMyChildContaining(box);1498 int childIndex = getMyChildContaining(box);
1497 1499
1498 // If getMyChildContaining() returns CHILD_UNKNOWN then it means that our level1500 // If getMyChildContaining() returns CHILD_UNKNOWN then it means that our level
1499 // is the correct level for this cube1501 // is the correct level for this cube
1500 if (childIndex == CHILD_UNKNOWN) {1502 if (childIndex == CHILD_UNKNOWN) {
1501 return this;1503 return this;
1502 }1504 }
1503 1505
1504 // Now, check if we have a child at that location1506 // Now, check if we have a child at that location
1505 child = getChildAtIndex(childIndex);1507 child = getChildAtIndex(childIndex);
1506 if (!child) {1508 if (!child) {
1507 child = addChildAtIndex(childIndex);1509 child = addChildAtIndex(childIndex);
1508 }1510 }
1509 1511
1510 // if we've made a really small child, then go ahead and use that one.1512 // if we've made a really small child, then go ahead and use that one.
1511 if (child->getScale() <= SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE) {1513 if (child->getScale() <= SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE) {
1512 return child;1514 return child;
@@ -1542,7 +1544,7 @@ int OctreeElement::getMyChildContaining(const AACube& cube) const { · 29 unmodified lines
1542 if (childIndexCubeMinimum != childIndexCubeMaximum) {1544 if (childIndexCubeMinimum != childIndexCubeMaximum) {
1543 return CHILD_UNKNOWN;1545 return CHILD_UNKNOWN;
1544 }1546 }
1545 1547
1546 return childIndexCubeMinimum; // either would do, they are the same1548 return childIndexCubeMinimum; // either would do, they are the same
1547 }1549 }
1548 return CHILD_UNKNOWN; // since cube is not contained in our element, it can't be in one of our children1550 return CHILD_UNKNOWN; // since cube is not contained in our element, it can't be in one of our children
@@ -1555,7 +1557,7 @@ int OctreeElement::getMyChildContaining(const AABox& box) const { · 6 unmodified lines
1555 // TODO: consider changing this to assert()1557 // TODO: consider changing this to assert()
1556 if(boxLargestScale > ourScale) {1558 if(boxLargestScale > ourScale) {
1557 qCDebug(octree, "UNEXPECTED -- OctreeElement::getMyChildContaining() "1559 qCDebug(octree, "UNEXPECTED -- OctreeElement::getMyChildContaining() "
1558 "boxLargestScale=[%f] > ourScale=[%f] ", boxLargestScale, ourScale);1560 "boxLargestScale=[%f] > ourScale=[%f] ", (double)boxLargestScale, (double)ourScale);
1559 }1561 }
1560 1562
1561 // Determine which of our children the minimum and maximum corners of the cube live in...1563 // Determine which of our children the minimum and maximum corners of the cube live in...
@@ -1566,7 +1568,7 @@ int OctreeElement::getMyChildContaining(const AABox& box) const { · 4 unmodified lines
1566 int childIndexCubeMinimum = getMyChildContainingPoint(cubeCornerMinimum);1568 int childIndexCubeMinimum = getMyChildContainingPoint(cubeCornerMinimum);
1567 int childIndexCubeMaximum = getMyChildContainingPoint(cubeCornerMaximum);1569 int childIndexCubeMaximum = getMyChildContainingPoint(cubeCornerMaximum);
1568 1570
1569 // If the minimum and maximum corners of the cube are in two different children's cubes, 1571 // If the minimum and maximum corners of the cube are in two different children's cubes,
1570 // then we are the containing element1572 // then we are the containing element
1571 if (childIndexCubeMinimum != childIndexCubeMaximum) {1573 if (childIndexCubeMinimum != childIndexCubeMaximum) {
1572 return CHILD_UNKNOWN;1574 return CHILD_UNKNOWN;
@@ -1579,12 +1581,12 @@ int OctreeElement::getMyChildContaining(const AABox& box) const { · 6 unmodified lines
1579int OctreeElement::getMyChildContainingPoint(const glm::vec3& point) const {1581int OctreeElement::getMyChildContainingPoint(const glm::vec3& point) const {
1580 glm::vec3 ourCenter = _cube.calcCenter();1582 glm::vec3 ourCenter = _cube.calcCenter();
1581 int childIndex = CHILD_UNKNOWN;1583 int childIndex = CHILD_UNKNOWN;
1582 1584
1583 // since point is not contained in our element, it can't be in one of our children1585 // since point is not contained in our element, it can't be in one of our children
1584 if (!_cube.contains(point)) {1586 if (!_cube.contains(point)) {
1585 return CHILD_UNKNOWN;1587 return CHILD_UNKNOWN;
1586 }1588 }
1587 1589
1588 // left half1590 // left half
1589 if (point.x > ourCenter.x) {1591 if (point.x > ourCenter.x) {
1590 if (point.y > ourCenter.y) {1592 if (point.y > ourCenter.y) {
libraries/octree/src/OctreePacketData.cpp+5−3
@@ -384,10 +384,12 @@ bool OctreePacketData::appendValue(const glm::vec3& value) { · 383 unmodified lines
384bool OctreePacketData::appendValue(const QVector<glm::vec3>& value) {384bool OctreePacketData::appendValue(const QVector<glm::vec3>& value) {
385 uint16_t qVecSize = value.size();385 uint16_t qVecSize = value.size();
386 bool success = appendValue(qVecSize);386 bool success = appendValue(qVecSize);
387 success = append((const unsigned char*)value.constData(), qVecSize * sizeof(glm::vec3));
388 if (success) {387 if (success) {
389 _bytesOfValues += qVecSize * sizeof(glm::vec3);388 success = append((const unsigned char*)value.constData(), qVecSize * sizeof(glm::vec3));
390 _totalBytesOfValues += qVecSize * sizeof(glm::vec3);389 if (success) {
390 _bytesOfValues += qVecSize * sizeof(glm::vec3);
391 _totalBytesOfValues += qVecSize * sizeof(glm::vec3);
392 }
391 }393 }
392 return success;394 return success;
393}395}
libraries/octree/src/OctreePersistThread.cpp+13−0
@@ -350,6 +350,19 @@ void OctreePersistThread::rollOldBackupVersions(const BackupRule& rule) { · 349 unmodified lines
350 if (rule.extensionFormat.contains("%N")) {350 if (rule.extensionFormat.contains("%N")) {
351 if (rule.maxBackupVersions > 0) {351 if (rule.maxBackupVersions > 0) {
352 qCDebug(octree) << "Rolling old backup versions for rule" << rule.name << "...";352 qCDebug(octree) << "Rolling old backup versions for rule" << rule.name << "...";
353
354 // Delete maximum rolling file because rename() fails on Windows if target exists
355 QString backupMaxExtensionN = rule.extensionFormat;
356 backupMaxExtensionN.replace(QString("%N"), QString::number(rule.maxBackupVersions));
357 QString backupMaxFilenameN = _filename + backupMaxExtensionN;
358 QFile backupMaxFileN(backupMaxFilenameN);
359 if (backupMaxFileN.exists()) {
360 int result = remove(qPrintable(backupMaxFilenameN));
361 if (result != 0) {
362 qCDebug(octree) << "ERROR deleting old backup file " << backupMaxFilenameN;
363 }
364 }
365
353 for(int n = rule.maxBackupVersions - 1; n > 0; n--) {366 for(int n = rule.maxBackupVersions - 1; n > 0; n--) {
354 QString backupExtensionN = rule.extensionFormat;367 QString backupExtensionN = rule.extensionFormat;
355 QString backupExtensionNplusOne = rule.extensionFormat;368 QString backupExtensionNplusOne = rule.extensionFormat;
libraries/octree/src/OctreeProjectedPolygon.cpp+104−103
@@ -96,8 +96,9 @@ void BoundingBox::explandToInclude(const BoundingBox& box) { · 95 unmodified lines
96 96
97void BoundingBox::printDebugDetails(const char* label) const {97void BoundingBox::printDebugDetails(const char* label) const {
98 qCDebug(octree, "%s _set=%s\n corner=%f,%f size=%f,%f\n bounds=[(%f,%f) to (%f,%f)]",98 qCDebug(octree, "%s _set=%s\n corner=%f,%f size=%f,%f\n bounds=[(%f,%f) to (%f,%f)]",
99 (label ? label : "BoundingBox"),99 (label ? label : "BoundingBox"),
100 debug::valueOf(_set), corner.x, corner.y, size.x, size.y, corner.x, corner.y, corner.x+size.x, corner.y+size.y);100 debug::valueOf(_set), (double)corner.x, (double)corner.y, (double)size.x, (double)size.y,
101 (double)corner.x, (double)corner.y, (double)(corner.x+size.x), (double)(corner.y+size.y));
101}102}
102 103
103 104
@@ -107,7 +108,7 @@ long OctreeProjectedPolygon::intersects_calls = 0; · 3 unmodified lines
107 108
108 109
109OctreeProjectedPolygon::OctreeProjectedPolygon(const BoundingBox& box) :110OctreeProjectedPolygon::OctreeProjectedPolygon(const BoundingBox& box) :
110 _vertexCount(4), 111 _vertexCount(4),
111 _maxX(-FLT_MAX), _maxY(-FLT_MAX), _minX(FLT_MAX), _minY(FLT_MAX),112 _maxX(-FLT_MAX), _maxY(-FLT_MAX), _minX(FLT_MAX), _minY(FLT_MAX),
112 _distance(0)113 _distance(0)
113{114{
@@ -117,9 +118,9 @@ OctreeProjectedPolygon::OctreeProjectedPolygon(const BoundingBox& box) : · 3 unmodified lines
117}118}
118 119
119 120
120void OctreeProjectedPolygon::setVertex(int vertex, const glm::vec2& point) { 121void OctreeProjectedPolygon::setVertex(int vertex, const glm::vec2& point) {
121 _vertices[vertex] = point;122 _vertices[vertex] = point;
122 123
123 // keep track of our bounding box124 // keep track of our bounding box
124 if (point.x > _maxX) {125 if (point.x > _maxX) {
125 _maxX = point.x;126 _maxX = point.x;
@@ -133,14 +134,14 @@ void OctreeProjectedPolygon::setVertex(int vertex, const glm::vec2& point) { · 7 unmodified lines
133 if (point.y < _minY) {134 if (point.y < _minY) {
134 _minY = point.y;135 _minY = point.y;
135 }136 }
136 137
137}138}
138 139
139// can be optimized with new pointInside()140// can be optimized with new pointInside()
140bool OctreeProjectedPolygon::occludes(const OctreeProjectedPolygon& occludee, bool checkAllInView) const {141bool OctreeProjectedPolygon::occludes(const OctreeProjectedPolygon& occludee, bool checkAllInView) const {
141 142
142 OctreeProjectedPolygon::occludes_calls++;143 OctreeProjectedPolygon::occludes_calls++;
143 144
144 // if we are completely out of view, then we definitely don't occlude!145 // if we are completely out of view, then we definitely don't occlude!
145 // if the occludee is completely out of view, then we also don't occlude it146 // if the occludee is completely out of view, then we also don't occlude it
146 //147 //
@@ -158,7 +159,7 @@ bool OctreeProjectedPolygon::occludes(const OctreeProjectedPolygon& occludee, bo · 11 unmodified lines
158 (occludee.getMinY() < getMinY())) {159 (occludee.getMinY() < getMinY())) {
159 return false;160 return false;
160 }161 }
161 162
162 // we need to test for identity as well, because in the case of identity, none of the points163 // we need to test for identity as well, because in the case of identity, none of the points
163 // will be "inside" but we don't want to bail early on the first non-inside point164 // will be "inside" but we don't want to bail early on the first non-inside point
164 bool potentialIdenity = false;165 bool potentialIdenity = false;
@@ -171,7 +172,7 @@ bool OctreeProjectedPolygon::occludes(const OctreeProjectedPolygon& occludee, bo · 6 unmodified lines
171 for(int i = 0; i < occludee.getVertexCount(); i++) {172 for(int i = 0; i < occludee.getVertexCount(); i++) {
172 bool vertexMatched = false;173 bool vertexMatched = false;
173 if (!pointInside(occludee.getVertex(i), &vertexMatched)) {174 if (!pointInside(occludee.getVertex(i), &vertexMatched)) {
174 175
175 // so the point we just tested isn't inside, but it might have matched a vertex176 // so the point we just tested isn't inside, but it might have matched a vertex
176 // if it didn't match a vertext, then we bail because we can't be an identity177 // if it didn't match a vertext, then we bail because we can't be an identity
177 // or if we're not expecting identity, then we also bail early, no matter what178 // or if we're not expecting identity, then we also bail early, no matter what
@@ -182,7 +183,7 @@ bool OctreeProjectedPolygon::occludes(const OctreeProjectedPolygon& occludee, bo · 4 unmodified lines
182 pointsInside++;183 pointsInside++;
183 }184 }
184 }185 }
185 186
186 // we're only here if all points are inside matched and/or we had a potentialIdentity we need to check187 // we're only here if all points are inside matched and/or we had a potentialIdentity we need to check
187 if (pointsInside == occludee.getVertexCount()) {188 if (pointsInside == occludee.getVertexCount()) {
188 return true;189 return true;
@@ -192,7 +193,7 @@ bool OctreeProjectedPolygon::occludes(const OctreeProjectedPolygon& occludee, bo · 3 unmodified lines
192 if (potentialIdenity) {193 if (potentialIdenity) {
193 return matches(occludee);194 return matches(occludee);
194 }195 }
195 196
196 return false; // if we got this far, then we're not occluded197 return false; // if we got this far, then we're not occluded
197}198}
198 199
@@ -211,7 +212,7 @@ bool OctreeProjectedPolygon::matches(const OctreeProjectedPolygon& testee) const · 12 unmodified lines
211 int originIndex = 0;212 int originIndex = 0;
212 for(int i = 0; i < vertextCount; i++) {213 for(int i = 0; i < vertextCount; i++) {
213 glm::vec2 testeeVertex = testee.getVertex(i);214 glm::vec2 testeeVertex = testee.getVertex(i);
214 215
215 // if they match, we found our origin.216 // if they match, we found our origin.
216 if (testeeVertex == polygonVertex) {217 if (testeeVertex == polygonVertex) {
217 originIndex = i;218 originIndex = i;
@@ -224,10 +225,10 @@ bool OctreeProjectedPolygon::matches(const OctreeProjectedPolygon& testee) const · 6 unmodified lines
224 glm::vec2 testeeVertex = testee.getVertex((i + originIndex) % vertextCount);225 glm::vec2 testeeVertex = testee.getVertex((i + originIndex) % vertextCount);
225 glm::vec2 polygonVertex = getVertex(i);226 glm::vec2 polygonVertex = getVertex(i);
226 if (testeeVertex != polygonVertex) {227 if (testeeVertex != polygonVertex) {
227 return false; // we don't match, therefore we're not the same 228 return false; // we don't match, therefore we're not the same
228 } 229 }
229 } 230 }
230 return true; // all of our vertices match, therefore we're the same 231 return true; // all of our vertices match, therefore we're the same
231}232}
232 233
233bool OctreeProjectedPolygon::matches(const BoundingBox& box) const {234bool OctreeProjectedPolygon::matches(const BoundingBox& box) const {
@@ -259,17 +260,17 @@ bool OctreeProjectedPolygon::pointInside(const glm::vec2& point, bool* matchesVe · 25 unmodified lines
259 return false;260 return false;
260 }261 }
261 }262 }
262 263
263 return true;264 return true;
264}265}
265 266
266void OctreeProjectedPolygon::printDebugDetails() const {267void OctreeProjectedPolygon::printDebugDetails() const {
267 qCDebug(octree, "OctreeProjectedPolygon..."268 qCDebug(octree, "OctreeProjectedPolygon..."
268 " minX=%f maxX=%f minY=%f maxY=%f", getMinX(), getMaxX(), getMinY(), getMaxY());269 " minX=%f maxX=%f minY=%f maxY=%f", (double)getMinX(), (double)getMaxX(), (double)getMinY(), (double)getMaxY());
269 qCDebug(octree, " vertex count=%d distance=%f", getVertexCount(), getDistance());270 qCDebug(octree, " vertex count=%d distance=%f", getVertexCount(), (double)getDistance());
270 for (int i = 0; i < getVertexCount(); i++) {271 for (int i = 0; i < getVertexCount(); i++) {
271 glm::vec2 point = getVertex(i);272 glm::vec2 point = getVertex(i);
272 qCDebug(octree, " vertex[%d] = %f, %f ", i, point.x, point.y);273 qCDebug(octree, " vertex[%d] = %f, %f ", i, (double)point.x, (double)point.y);
273 }274 }
274}275}
275 276
@@ -291,7 +292,7 @@ bool OctreeProjectedPolygon::intersects(const OctreeProjectedPolygon& testee) co · 15 unmodified lines
291// intersect on all axes.292// intersect on all axes.
292//293//
293// Note: this only works on convex polygons294// Note: this only works on convex polygons
294// 295//
295//296//
296bool OctreeProjectedPolygon::intersectsOnAxes(const OctreeProjectedPolygon& testee) const {297bool OctreeProjectedPolygon::intersectsOnAxes(const OctreeProjectedPolygon& testee) const {
297 298
@@ -307,11 +308,11 @@ bool OctreeProjectedPolygon::intersectsOnAxes(const OctreeProjectedPolygon& test · 9 unmodified lines
307 // points that are ON the edge, are considered to be "outside"308 // points that are ON the edge, are considered to be "outside"
308 for (int j = 0; j < testee.getVertexCount(); j++) {309 for (int j = 0; j < testee.getVertexCount(); j++) {
309 glm::vec2 testeeVertex = testee.getVertex(j);310 glm::vec2 testeeVertex = testee.getVertex(j);
310 311
311 // in comparison below:312 // in comparison below:
312 // >= will cause points on edge to be considered inside313 // >= will cause points on edge to be considered inside
313 // > will cause points on edge to be considered outside314 // > will cause points on edge to be considered outside
314 315
315 float c2 = a * testeeVertex.x + b * testeeVertex.y;316 float c2 = a * testeeVertex.x + b * testeeVertex.y;
316 if (c2 >= c) {317 if (c2 >= c) {
317 goto CONTINUE_OUTER;318 goto CONTINUE_OUTER;
@@ -328,11 +329,11 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 10 unmodified lines
328 // RIGHT/NEAR329 // RIGHT/NEAR
329 // LEFT/NEAR330 // LEFT/NEAR
330 if (331 if (
331 (getProjectionType() == that.getProjectionType()) && 332 (getProjectionType() == that.getProjectionType()) &&
332 (333 (
333 getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR) ||334 getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR) ||
334 getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)335 getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)
335 ) 336 )
336 ) {337 ) {
337 if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(5)) {338 if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(5)) {
338 return true;339 return true;
@@ -350,10 +351,10 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 11 unmodified lines
350 351
351 // NEAR/BOTTOM352 // NEAR/BOTTOM
352 if (353 if (
353 (getProjectionType() == that.getProjectionType()) && 354 (getProjectionType() == that.getProjectionType()) &&
354 (355 (
355 getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM)356 getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM)
356 ) 357 )
357 ) {358 ) {
358 if (getVertex(0) == that.getVertex(5) && getVertex(3) == that.getVertex(4)) {359 if (getVertex(0) == that.getVertex(5) && getVertex(3) == that.getVertex(4)) {
359 return true;360 return true;
@@ -371,10 +372,10 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 11 unmodified lines
371 372
372 // NEAR/TOP373 // NEAR/TOP
373 if (374 if (
374 (getProjectionType() == that.getProjectionType()) && 375 (getProjectionType() == that.getProjectionType()) &&
375 (376 (
376 getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP)377 getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP)
377 ) 378 )
378 ) {379 ) {
379 if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) {380 if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) {
380 return true;381 return true;
@@ -393,11 +394,11 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 12 unmodified lines
393 // RIGHT/NEAR & NEAR/RIGHT/TOP394 // RIGHT/NEAR & NEAR/RIGHT/TOP
394 // LEFT/NEAR & NEAR/LEFT/TOP395 // LEFT/NEAR & NEAR/LEFT/TOP
395 if (396 if (
396 ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) && 397 ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) &&
397 (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) 398 (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
398 ||399 ||
399 ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) && 400 ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) &&
400 (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) 401 (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
401 )402 )
402 {403 {
403 if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) {404 if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) {
@@ -407,12 +408,12 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 3 unmodified lines
407 // RIGHT/NEAR & NEAR/RIGHT/TOP408 // RIGHT/NEAR & NEAR/RIGHT/TOP
408 // LEFT/NEAR & NEAR/LEFT/TOP409 // LEFT/NEAR & NEAR/LEFT/TOP
409 if (410 if (
410 ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) && 411 ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) &&
411 (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) 412 (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
412 ||413 ||
413 ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) && 414 ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) &&
414 (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) 415 (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
415 416
416 )417 )
417 {418 {
418 if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) {419 if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) {
@@ -423,12 +424,12 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines
423 // RIGHT/NEAR & NEAR/RIGHT/BOTTOM424 // RIGHT/NEAR & NEAR/RIGHT/BOTTOM
424 // NEAR/LEFT & NEAR/LEFT/BOTTOM425 // NEAR/LEFT & NEAR/LEFT/BOTTOM
425 if (426 if (
426 ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && 427 ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
427 (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) 428 (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
428 ||429 ||
429 ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && 430 ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
430 (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) 431 (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
431 432
432 )433 )
433 {434 {
434 if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) {435 if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) {
@@ -438,11 +439,11 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 3 unmodified lines
438 // RIGHT/NEAR & NEAR/RIGHT/BOTTOM439 // RIGHT/NEAR & NEAR/RIGHT/BOTTOM
439 // NEAR/LEFT & NEAR/LEFT/BOTTOM440 // NEAR/LEFT & NEAR/LEFT/BOTTOM
440 if (441 if (
441 ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && 442 ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
442 (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) 443 (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
443 ||444 ||
444 ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && 445 ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
445 (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) 446 (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
446 )447 )
447 {448 {
448 if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) {449 if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) {
@@ -453,7 +454,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines
453 // NEAR/TOP & NEAR454 // NEAR/TOP & NEAR
454 if (455 if (
455 (getProjectionType() == (PROJECTION_NEAR )) &&456 (getProjectionType() == (PROJECTION_NEAR )) &&
456 (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) 457 (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP ))
457 )458 )
458 {459 {
459 if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) {460 if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) {
@@ -464,7 +465,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines
464 // NEAR/TOP & NEAR465 // NEAR/TOP & NEAR
465 if (466 if (
466 (that.getProjectionType() == (PROJECTION_NEAR )) &&467 (that.getProjectionType() == (PROJECTION_NEAR )) &&
467 (getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) 468 (getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP ))
468 )469 )
469 {470 {
470 if (getVertex(5) == that.getVertex(0) && getVertex(2) == that.getVertex(1)) {471 if (getVertex(5) == that.getVertex(0) && getVertex(2) == that.getVertex(1)) {
@@ -475,7 +476,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines
475 // NEAR/BOTTOM & NEAR476 // NEAR/BOTTOM & NEAR
476 if (477 if (
477 (getProjectionType() == (PROJECTION_NEAR )) &&478 (getProjectionType() == (PROJECTION_NEAR )) &&
478 (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) 479 (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM ))
479 )480 )
480 {481 {
481 if (getVertex(2) == that.getVertex(3) && getVertex(3) == that.getVertex(0)) {482 if (getVertex(2) == that.getVertex(3) && getVertex(3) == that.getVertex(0)) {
@@ -486,7 +487,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines
486 // NEAR/BOTTOM & NEAR487 // NEAR/BOTTOM & NEAR
487 if (488 if (
488 (that.getProjectionType() == (PROJECTION_NEAR )) &&489 (that.getProjectionType() == (PROJECTION_NEAR )) &&
489 (getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) 490 (getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM ))
490 )491 )
491 {492 {
492 if (getVertex(3) == that.getVertex(2) && getVertex(0) == that.getVertex(3)) {493 if (getVertex(3) == that.getVertex(2) && getVertex(0) == that.getVertex(3)) {
@@ -497,7 +498,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines
497 // NEAR/RIGHT & NEAR498 // NEAR/RIGHT & NEAR
498 if (499 if (
499 (getProjectionType() == (PROJECTION_NEAR )) &&500 (getProjectionType() == (PROJECTION_NEAR )) &&
500 (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) 501 (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT ))
501 )502 )
502 {503 {
503 if (getVertex(0) == that.getVertex(1) && getVertex(3) == that.getVertex(4)) {504 if (getVertex(0) == that.getVertex(1) && getVertex(3) == that.getVertex(4)) {
@@ -508,18 +509,18 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines
508 // NEAR/RIGHT & NEAR509 // NEAR/RIGHT & NEAR
509 if (510 if (
510 (that.getProjectionType() == (PROJECTION_NEAR )) &&511 (that.getProjectionType() == (PROJECTION_NEAR )) &&
511 (getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) 512 (getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT ))
512 )513 )
513 {514 {
514 if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) {515 if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) {
515 return true;516 return true;
516 }517 }
517 }518 }
518 519
519 // NEAR/LEFT & NEAR520 // NEAR/LEFT & NEAR
520 if (521 if (
521 (getProjectionType() == (PROJECTION_NEAR )) &&522 (getProjectionType() == (PROJECTION_NEAR )) &&
522 (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) 523 (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT ))
523 )524 )
524 {525 {
525 if (getVertex(1) == that.getVertex(1) && getVertex(2) == that.getVertex(4)) {526 if (getVertex(1) == that.getVertex(1) && getVertex(2) == that.getVertex(4)) {
@@ -530,7 +531,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 4 unmodified lines
530 // NEAR/LEFT & NEAR531 // NEAR/LEFT & NEAR
531 if (532 if (
532 (that.getProjectionType() == (PROJECTION_NEAR )) &&533 (that.getProjectionType() == (PROJECTION_NEAR )) &&
533 (getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) 534 (getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT ))
534 )535 )
535 {536 {
536 if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) {537 if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) {
@@ -559,7 +560,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 22 unmodified lines
559 return true;560 return true;
560 }561 }
561 }562 }
562 563
563 564
564 // NEAR/RIGHT/BOTTOM & NEAR/BOTTOM565 // NEAR/RIGHT/BOTTOM & NEAR/BOTTOM
565 if (566 if (
@@ -582,7 +583,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 16 unmodified lines
582 return true;583 return true;
583 }584 }
584 }585 }
585 586
586 // NEAR/LEFT/BOTTOM & NEAR/BOTTOM587 // NEAR/LEFT/BOTTOM & NEAR/BOTTOM
587 if (588 if (
588 ((getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) &&589 ((getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) &&
@@ -592,12 +593,12 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 3 unmodified lines
592 if (getVertex(2) == that.getVertex(0) && getVertex(4) == that.getVertex(4)) {593 if (getVertex(2) == that.getVertex(0) && getVertex(4) == that.getVertex(4)) {
593 return true;594 return true;
594 }595 }
595 } 596 }
596 597
597 // NEAR/LEFT/BOTTOM & NEAR/BOTTOM598 // NEAR/LEFT/BOTTOM & NEAR/BOTTOM
598 if (599 if (
599 ((that.getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) &&600 ((that.getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) &&
600 (getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR | PROJECTION_LEFT ))) 601 (getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR | PROJECTION_LEFT )))
601 )602 )
602 {603 {
603 if (getVertex(0) == that.getVertex(2) && getVertex(4) == that.getVertex(4)) {604 if (getVertex(0) == that.getVertex(2) && getVertex(4) == that.getVertex(4)) {
@@ -609,7 +610,7 @@ bool OctreeProjectedPolygon::canMerge(const OctreeProjectedPolygon& that) const · 5 unmodified lines
609 // LEFT/NEAR/BOTTOM610 // LEFT/NEAR/BOTTOM
610 // LEFT/NEAR/TOP611 // LEFT/NEAR/TOP
611 if (612 if (
612 (getProjectionType() == that.getProjectionType()) && 613 (getProjectionType() == that.getProjectionType()) &&
613 (614 (
614 getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM ) ||615 getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM ) ||
615 getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP ) ||616 getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP ) ||
@@ -646,11 +647,11 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 30 unmodified lines
646 // RIGHT/NEAR647 // RIGHT/NEAR
647 // LEFT/NEAR648 // LEFT/NEAR
648 if (649 if (
649 (getProjectionType() == that.getProjectionType()) && 650 (getProjectionType() == that.getProjectionType()) &&
650 (651 (
651 getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR) || 652 getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR) ||
652 getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)653 getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)
653 ) 654 )
654 ) {655 ) {
655 if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(5)) {656 if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(5)) {
656 //setVertex(0, this.getVertex(0)); // no change657 //setVertex(0, this.getVertex(0)); // no change
@@ -689,13 +690,13 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 32 unmodified lines
689 return; // done690 return; // done
690 }691 }
691 }692 }
692 693
693 // NEAR/BOTTOM694 // NEAR/BOTTOM
694 if (695 if (
695 (getProjectionType() == that.getProjectionType()) && 696 (getProjectionType() == that.getProjectionType()) &&
696 (697 (
697 getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM)698 getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM)
698 ) 699 )
699 ) {700 ) {
700 if (getVertex(0) == that.getVertex(5) && getVertex(3) == that.getVertex(4)) {701 if (getVertex(0) == that.getVertex(5) && getVertex(3) == that.getVertex(4)) {
701 setVertex(0, that.getVertex(0));702 setVertex(0, that.getVertex(0));
@@ -737,10 +738,10 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 35 unmodified lines
737 738
738 // NEAR/TOP739 // NEAR/TOP
739 if (740 if (
740 (getProjectionType() == that.getProjectionType()) && 741 (getProjectionType() == that.getProjectionType()) &&
741 (742 (
742 getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP)743 getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP)
743 ) 744 )
744 ) {745 ) {
745 if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) {746 if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) {
746 setVertex(0, that.getVertex(0));747 setVertex(0, that.getVertex(0));
@@ -779,16 +780,16 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 32 unmodified lines
779 return; // done780 return; // done
780 }781 }
781 }782 }
782 783
783 784
784 // RIGHT/NEAR & NEAR/RIGHT/TOP785 // RIGHT/NEAR & NEAR/RIGHT/TOP
785 // LEFT/NEAR & NEAR/LEFT/TOP786 // LEFT/NEAR & NEAR/LEFT/TOP
786 if (787 if (
787 ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) && 788 ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) &&
788 (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) 789 (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
789 ||790 ||
790 ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) && 791 ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) &&
791 (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) 792 (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
792 )793 )
793 {794 {
794 if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) {795 if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) {
@@ -806,12 +807,12 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 11 unmodified lines
806 // RIGHT/NEAR & NEAR/RIGHT/TOP807 // RIGHT/NEAR & NEAR/RIGHT/TOP
807 // LEFT/NEAR & NEAR/LEFT/TOP808 // LEFT/NEAR & NEAR/LEFT/TOP
808 if (809 if (
809 ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) && 810 ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) &&
810 (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) 811 (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
811 ||812 ||
812 ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) && 813 ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP)) &&
813 (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) 814 (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
814 815
815 )816 )
816 {817 {
817 if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) {818 if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) {
@@ -829,12 +830,12 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 11 unmodified lines
829 // RIGHT/NEAR & NEAR/RIGHT/BOTTOM830 // RIGHT/NEAR & NEAR/RIGHT/BOTTOM
830 // NEAR/LEFT & NEAR/LEFT/BOTTOM831 // NEAR/LEFT & NEAR/LEFT/BOTTOM
831 if (832 if (
832 ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && 833 ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
833 (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) 834 (getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
834 ||835 ||
835 ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && 836 ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
836 (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) 837 (getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
837 838
838 )839 )
839 {840 {
840 if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) {841 if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) {
@@ -851,11 +852,11 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 10 unmodified lines
851 // RIGHT/NEAR & NEAR/RIGHT/BOTTOM852 // RIGHT/NEAR & NEAR/RIGHT/BOTTOM
852 // NEAR/LEFT & NEAR/LEFT/BOTTOM853 // NEAR/LEFT & NEAR/LEFT/BOTTOM
853 if (854 if (
854 ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && 855 ((getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
855 (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR))) 856 (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))
856 ||857 ||
857 ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) && 858 ((getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&
858 (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR))) 859 (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))
859 )860 )
860 {861 {
861 if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) {862 if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) {
@@ -865,16 +866,16 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 3 unmodified lines
865 //setVertex(3, this.getVertex(3)); // no change866 //setVertex(3, this.getVertex(3)); // no change
866 //setVertex(4, this.getVertex(4)); // no change867 //setVertex(4, this.getVertex(4)); // no change
867 //setVertex(5, this.getVertex(5)); // no change868 //setVertex(5, this.getVertex(5)); // no change
868 setProjectionType((PROJECTION_RIGHT | PROJECTION_NEAR)); 869 setProjectionType((PROJECTION_RIGHT | PROJECTION_NEAR));
869 return; // done870 return; // done
870 }871 }
871 }872 }
872 873
873 874
874 // NEAR/TOP & NEAR875 // NEAR/TOP & NEAR
875 if (876 if (
876 (getProjectionType() == (PROJECTION_NEAR )) &&877 (getProjectionType() == (PROJECTION_NEAR )) &&
877 (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) 878 (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP ))
878 )879 )
879 {880 {
880 if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) {881 if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) {
@@ -891,7 +892,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 10 unmodified lines
891 // NEAR/TOP & NEAR892 // NEAR/TOP & NEAR
892 if (893 if (
893 (that.getProjectionType() == (PROJECTION_NEAR )) &&894 (that.getProjectionType() == (PROJECTION_NEAR )) &&
894 (getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) 895 (getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP ))
895 )896 )
896 {897 {
897 if (getVertex(5) == that.getVertex(0) && getVertex(2) == that.getVertex(1)) {898 if (getVertex(5) == that.getVertex(0) && getVertex(2) == that.getVertex(1)) {
@@ -904,11 +905,11 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 6 unmodified lines
904 return; // done905 return; // done
905 }906 }
906 }907 }
907 908
908 // NEAR/BOTTOM & NEAR909 // NEAR/BOTTOM & NEAR
909 if (910 if (
910 (getProjectionType() == (PROJECTION_NEAR )) &&911 (getProjectionType() == (PROJECTION_NEAR )) &&
911 (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) 912 (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM ))
912 )913 )
913 {914 {
914 if (getVertex(2) == that.getVertex(3) && getVertex(3) == that.getVertex(0)) {915 if (getVertex(2) == that.getVertex(3) && getVertex(3) == that.getVertex(0)) {
@@ -924,7 +925,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 9 unmodified lines
924 // NEAR/BOTTOM & NEAR925 // NEAR/BOTTOM & NEAR
925 if (926 if (
926 (that.getProjectionType() == (PROJECTION_NEAR )) &&927 (that.getProjectionType() == (PROJECTION_NEAR )) &&
927 (getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) 928 (getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM ))
928 )929 )
929 {930 {
930 if (getVertex(3) == that.getVertex(2) && getVertex(0) == that.getVertex(3)) {931 if (getVertex(3) == that.getVertex(2) && getVertex(0) == that.getVertex(3)) {
@@ -941,7 +942,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 10 unmodified lines
941 // NEAR/RIGHT & NEAR942 // NEAR/RIGHT & NEAR
942 if (943 if (
943 (getProjectionType() == (PROJECTION_NEAR )) &&944 (getProjectionType() == (PROJECTION_NEAR )) &&
944 (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) 945 (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT ))
945 )946 )
946 {947 {
947 if (getVertex(0) == that.getVertex(1) && getVertex(3) == that.getVertex(4)) {948 if (getVertex(0) == that.getVertex(1) && getVertex(3) == that.getVertex(4)) {
@@ -957,7 +958,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 9 unmodified lines
957 // NEAR/RIGHT & NEAR958 // NEAR/RIGHT & NEAR
958 if (959 if (
959 (that.getProjectionType() == (PROJECTION_NEAR )) &&960 (that.getProjectionType() == (PROJECTION_NEAR )) &&
960 (getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) 961 (getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT ))
961 )962 )
962 {963 {
963 if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) {964 if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) {
@@ -974,7 +975,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 10 unmodified lines
974 // NEAR/LEFT & NEAR975 // NEAR/LEFT & NEAR
975 if (976 if (
976 (getProjectionType() == (PROJECTION_NEAR )) &&977 (getProjectionType() == (PROJECTION_NEAR )) &&
977 (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) 978 (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT ))
978 )979 )
979 {980 {
980 if (getVertex(1) == that.getVertex(1) && getVertex(2) == that.getVertex(4)) {981 if (getVertex(1) == that.getVertex(1) && getVertex(2) == that.getVertex(4)) {
@@ -991,7 +992,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 10 unmodified lines
991 // NEAR/LEFT & NEAR992 // NEAR/LEFT & NEAR
992 if (993 if (
993 (that.getProjectionType() == (PROJECTION_NEAR )) &&994 (that.getProjectionType() == (PROJECTION_NEAR )) &&
994 (getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) 995 (getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT ))
995 )996 )
996 {997 {
997 if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) {998 if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) {
@@ -1096,7 +1097,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 98 unmodified lines
1096 // NEAR/LEFT/BOTTOM & NEAR/BOTTOM1097 // NEAR/LEFT/BOTTOM & NEAR/BOTTOM
1097 if (1098 if (
1098 ((that.getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) &&1099 ((that.getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) &&
1099 (getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR | PROJECTION_LEFT ))) 1100 (getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR | PROJECTION_LEFT )))
1100 )1101 )
1101 {1102 {
1102 if (getVertex(0) == that.getVertex(2) && getVertex(4) == that.getVertex(4)) {1103 if (getVertex(0) == that.getVertex(2) && getVertex(4) == that.getVertex(4)) {
@@ -1118,7 +1119,7 @@ void OctreeProjectedPolygon::merge(const OctreeProjectedPolygon& that) { · 15 unmodified lines
1118 // LEFT/NEAR/BOTTOM1119 // LEFT/NEAR/BOTTOM
1119 // LEFT/NEAR/TOP1120 // LEFT/NEAR/TOP
1120 if (1121 if (
1121 (getProjectionType() == that.getProjectionType()) && 1122 (getProjectionType() == that.getProjectionType()) &&
1122 (1123 (
1123 getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM ) ||1124 getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM ) ||
1124 getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP ) ||1125 getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP ) ||
libraries/octree/src/OctreeSceneStats.cpp+3−3
@@ -707,8 +707,8 @@ const char* OctreeSceneStats::getItemValue(Item item) { · 706 unmodified lines
707 float elapsedAverage = _elapsedAverage.getAverage();707 float elapsedAverage = _elapsedAverage.getAverage();
708 calcAverageFPS = (float)USECS_PER_SECOND / (float)elapsedAverage;708 calcAverageFPS = (float)USECS_PER_SECOND / (float)elapsedAverage;
709 709
710 sprintf(_itemValueBuffer, "%llu usecs (%d fps) Average: %.0f usecs (%d fps)", 710 sprintf(_itemValueBuffer, "%llu usecs (%d fps) Average: %.0f usecs (%d fps)",
711 (long long unsigned int)_elapsed, calcFPS, elapsedAverage, calcAverageFPS);711 (long long unsigned int)_elapsed, calcFPS, (double)elapsedAverage, calcAverageFPS);
712 break;712 break;
713 }713 }
714 case ITEM_ENCODE:714 case ITEM_ENCODE:
@@ -733,7 +733,7 @@ const char* OctreeSceneStats::getItemValue(Item item) { · 18 unmodified lines
733 float calculatedBPV = total == 0 ? 0 : (_bytes * 8) / total;733 float calculatedBPV = total == 0 ? 0 : (_bytes * 8) / total;
734 float averageBPV = _bitsPerOctreeAverage.getAverage();734 float averageBPV = _bitsPerOctreeAverage.getAverage();
735 sprintf(_itemValueBuffer, "%lu (%.2f bits/octree Average: %.2f bits/octree) %lu internal %lu leaves", 735 sprintf(_itemValueBuffer, "%lu (%.2f bits/octree Average: %.2f bits/octree) %lu internal %lu leaves",
736 total, calculatedBPV, averageBPV,736 total, (double)calculatedBPV, (double)averageBPV,
737 (long unsigned int)_existsInPacketBitsWritten,737 (long unsigned int)_existsInPacketBitsWritten,
738 (long unsigned int)_colorSent);738 (long unsigned int)_colorSent);
739 break;739 break;
libraries/octree/src/Plane.cpp+2−1
@@ -66,5 +66,6 @@ float Plane::distance(const glm::vec3 &point) const { · 65 unmodified lines
66 66
67void Plane::print() const {67void Plane::print() const {
68 qCDebug(octree, "Plane - point (x=%f y=%f z=%f) normal (x=%f y=%f z=%f) d=%f",68 qCDebug(octree, "Plane - point (x=%f y=%f z=%f) normal (x=%f y=%f z=%f) d=%f",
69 _point.x, _point.y, _point.z, _normal.x, _normal.y, _normal.z, _dCoefficient);69 (double)_point.x, (double)_point.y, (double)_point.z,
70 (double)_normal.x, (double)_normal.y, (double)_normal.z, (double)_dCoefficient);
70}71}
libraries/octree/src/ViewFrustum.cpp+57−55
@@ -65,9 +65,10 @@ void ViewFrustum::setProjection(const glm::mat4& projection) { · 64 unmodified lines
65 _farClip = -_corners[BOTTOM_LEFT_FAR].z;65 _farClip = -_corners[BOTTOM_LEFT_FAR].z;
66 _aspectRatio = (_corners[TOP_RIGHT_NEAR].x - _corners[BOTTOM_LEFT_NEAR].x) /66 _aspectRatio = (_corners[TOP_RIGHT_NEAR].x - _corners[BOTTOM_LEFT_NEAR].x) /
67 (_corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_LEFT_NEAR].y);67 (_corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_LEFT_NEAR].y);
68 glm::vec3 right = glm::normalize(glm::vec3(_corners[TOP_RIGHT_NEAR]));68
69 glm::vec3 left = glm::normalize(glm::vec3(_corners[TOP_LEFT_NEAR]));69 glm::vec4 top = _inverseProjection * vec4(0, 1, -1, 1);
70 _fieldOfView = abs(glm::degrees(glm::angle(right, left)));70 top /= top.w;
71 _fieldOfView = abs(glm::degrees(2.0f * abs(glm::angle(vec3(0, 0, -1), glm::normalize(vec3(top))))));
71}72}
72 73
73// ViewFrustum::calculateViewFrustum()74// ViewFrustum::calculateViewFrustum()
@@ -387,36 +388,36 @@ bool ViewFrustum::matches(const ViewFrustum& compareTo, bool debug) const { · 313 unmodified lines
387 if (!result && debug) {388 if (!result && debug) {
388 qCDebug(octree, "ViewFrustum::matches()... result=%s", debug::valueOf(result));389 qCDebug(octree, "ViewFrustum::matches()... result=%s", debug::valueOf(result));
389 qCDebug(octree, "%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f",390 qCDebug(octree, "%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f",
390 (testMatches(compareTo._position,_position) ? "MATCHES " : "NO MATCH"),391 (testMatches(compareTo._position,_position) ? "MATCHES " : "NO MATCH"),
391 compareTo._position.x, compareTo._position.y, compareTo._position.z,392 (double)compareTo._position.x, (double)compareTo._position.y, (double)compareTo._position.z,
392 _position.x, _position.y, _position.z );393 (double)_position.x, (double)_position.y, (double)_position.z);
393 qCDebug(octree, "%s -- compareTo._direction=%f,%f,%f _direction=%f,%f,%f",394 qCDebug(octree, "%s -- compareTo._direction=%f,%f,%f _direction=%f,%f,%f",
394 (testMatches(compareTo._direction, _direction) ? "MATCHES " : "NO MATCH"),395 (testMatches(compareTo._direction, _direction) ? "MATCHES " : "NO MATCH"),
395 compareTo._direction.x, compareTo._direction.y, compareTo._direction.z,396 (double)compareTo._direction.x, (double)compareTo._direction.y, (double)compareTo._direction.z,
396 _direction.x, _direction.y, _direction.z );397 (double)_direction.x, (double)_direction.y, (double)_direction.z );
397 qCDebug(octree, "%s -- compareTo._up=%f,%f,%f _up=%f,%f,%f",398 qCDebug(octree, "%s -- compareTo._up=%f,%f,%f _up=%f,%f,%f",
398 (testMatches(compareTo._up, _up) ? "MATCHES " : "NO MATCH"),399 (testMatches(compareTo._up, _up) ? "MATCHES " : "NO MATCH"),
399 compareTo._up.x, compareTo._up.y, compareTo._up.z,400 (double)compareTo._up.x, (double)compareTo._up.y, (double)compareTo._up.z,
400 _up.x, _up.y, _up.z );401 (double)_up.x, (double)_up.y, (double)_up.z );
401 qCDebug(octree, "%s -- compareTo._right=%f,%f,%f _right=%f,%f,%f",402 qCDebug(octree, "%s -- compareTo._right=%f,%f,%f _right=%f,%f,%f",
402 (testMatches(compareTo._right, _right) ? "MATCHES " : "NO MATCH"),403 (testMatches(compareTo._right, _right) ? "MATCHES " : "NO MATCH"),
403 compareTo._right.x, compareTo._right.y, compareTo._right.z,404 (double)compareTo._right.x, (double)compareTo._right.y, (double)compareTo._right.z,
404 _right.x, _right.y, _right.z );405 (double)_right.x, (double)_right.y, (double)_right.z );
405 qCDebug(octree, "%s -- compareTo._fieldOfView=%f _fieldOfView=%f",406 qCDebug(octree, "%s -- compareTo._fieldOfView=%f _fieldOfView=%f",
406 (testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"),407 (testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"),
407 compareTo._fieldOfView, _fieldOfView);408 (double)compareTo._fieldOfView, (double)_fieldOfView);
408 qCDebug(octree, "%s -- compareTo._aspectRatio=%f _aspectRatio=%f",409 qCDebug(octree, "%s -- compareTo._aspectRatio=%f _aspectRatio=%f",
409 (testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"),410 (testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"),
410 compareTo._aspectRatio, _aspectRatio);411 (double)compareTo._aspectRatio, (double)_aspectRatio);
411 qCDebug(octree, "%s -- compareTo._nearClip=%f _nearClip=%f",412 qCDebug(octree, "%s -- compareTo._nearClip=%f _nearClip=%f",
412 (testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"),413 (testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"),
413 compareTo._nearClip, _nearClip);414 (double)compareTo._nearClip, (double)_nearClip);
414 qCDebug(octree, "%s -- compareTo._farClip=%f _farClip=%f",415 qCDebug(octree, "%s -- compareTo._farClip=%f _farClip=%f",
415 (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"),416 (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"),
416 compareTo._farClip, _farClip);417 (double)compareTo._farClip, (double)_farClip);
417 qCDebug(octree, "%s -- compareTo._focalLength=%f _focalLength=%f",418 qCDebug(octree, "%s -- compareTo._focalLength=%f _focalLength=%f",
418 (testMatches(compareTo._focalLength, _focalLength) ? "MATCHES " : "NO MATCH"),419 (testMatches(compareTo._focalLength, _focalLength) ? "MATCHES " : "NO MATCH"),
419 compareTo._focalLength, _focalLength);420 (double)compareTo._focalLength, (double)_focalLength);
420 }421 }
421 return result;422 return result;
422}423}
@@ -448,33 +449,34 @@ bool ViewFrustum::isVerySimilar(const ViewFrustum& compareTo, bool debug) const · 25 unmodified lines
448 if (!result && debug) {449 if (!result && debug) {
449 qCDebug(octree, "ViewFrustum::isVerySimilar()... result=%s\n", debug::valueOf(result));450 qCDebug(octree, "ViewFrustum::isVerySimilar()... result=%s\n", debug::valueOf(result));
450 qCDebug(octree, "%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f",451 qCDebug(octree, "%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f",
451 (testMatches(compareTo._position,_position, POSITION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"),452 (testMatches(compareTo._position,_position, POSITION_SIMILAR_ENOUGH) ?
452 compareTo._position.x, compareTo._position.y, compareTo._position.z,453 "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"),
453 _position.x, _position.y, _position.z );454 (double)compareTo._position.x, (double)compareTo._position.y, (double)compareTo._position.z,
455 (double)_position.x, (double)_position.y, (double)_position.z );
454 456
455 qCDebug(octree, "%s -- positionDistance=%f",457 qCDebug(octree, "%s -- positionDistance=%f",
456 (testMatches(0,positionDistance, POSITION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"),458 (testMatches(0,positionDistance, POSITION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"),
457 positionDistance);459 (double)positionDistance);
458 460
459 qCDebug(octree, "%s -- angleOrientation=%f",461 qCDebug(octree, "%s -- angleOrientation=%f",
460 (testMatches(0, angleOrientation, ORIENTATION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"),462 (testMatches(0, angleOrientation, ORIENTATION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"),
461 angleOrientation);463 (double)angleOrientation);
462 464
463 qCDebug(octree, "%s -- compareTo._fieldOfView=%f _fieldOfView=%f",465 qCDebug(octree, "%s -- compareTo._fieldOfView=%f _fieldOfView=%f",
464 (testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"),466 (testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"),
465 compareTo._fieldOfView, _fieldOfView);467 (double)compareTo._fieldOfView, (double)_fieldOfView);
466 qCDebug(octree, "%s -- compareTo._aspectRatio=%f _aspectRatio=%f",468 qCDebug(octree, "%s -- compareTo._aspectRatio=%f _aspectRatio=%f",
467 (testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"),469 (testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"),
468 compareTo._aspectRatio, _aspectRatio);470 (double)compareTo._aspectRatio, (double)_aspectRatio);
469 qCDebug(octree, "%s -- compareTo._nearClip=%f _nearClip=%f",471 qCDebug(octree, "%s -- compareTo._nearClip=%f _nearClip=%f",
470 (testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"),472 (testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"),
471 compareTo._nearClip, _nearClip);473 (double)compareTo._nearClip, (double)_nearClip);
472 qCDebug(octree, "%s -- compareTo._farClip=%f _farClip=%f",474 qCDebug(octree, "%s -- compareTo._farClip=%f _farClip=%f",
473 (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"),475 (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"),
474 compareTo._farClip, _farClip);476 (double)compareTo._farClip, (double)_farClip);
475 qCDebug(octree, "%s -- compareTo._focalLength=%f _focalLength=%f",477 qCDebug(octree, "%s -- compareTo._focalLength=%f _focalLength=%f",
476 (testMatches(compareTo._focalLength, _focalLength) ? "MATCHES " : "NO MATCH"),478 (testMatches(compareTo._focalLength, _focalLength) ? "MATCHES " : "NO MATCH"),
477 compareTo._focalLength, _focalLength);479 (double)compareTo._focalLength, (double)_focalLength);
478 }480 }
479 return result;481 return result;
480}482}
@@ -531,23 +533,23 @@ void ViewFrustum::computeOffAxisFrustum(float& left, float& right, float& bottom · 50 unmodified lines
531 533
532void ViewFrustum::printDebugDetails() const {534void ViewFrustum::printDebugDetails() const {
533 qCDebug(octree, "ViewFrustum::printDebugDetails()...");535 qCDebug(octree, "ViewFrustum::printDebugDetails()...");
534 qCDebug(octree, "_position=%f,%f,%f", _position.x, _position.y, _position.z );536 qCDebug(octree, "_position=%f,%f,%f", (double)_position.x, (double)_position.y, (double)_position.z );
535 qCDebug(octree, "_direction=%f,%f,%f", _direction.x, _direction.y, _direction.z );537 qCDebug(octree, "_direction=%f,%f,%f", (double)_direction.x, (double)_direction.y, (double)_direction.z );
536 qCDebug(octree, "_up=%f,%f,%f", _up.x, _up.y, _up.z );538 qCDebug(octree, "_up=%f,%f,%f", (double)_up.x, (double)_up.y, (double)_up.z );
537 qCDebug(octree, "_right=%f,%f,%f", _right.x, _right.y, _right.z );539 qCDebug(octree, "_right=%f,%f,%f", (double)_right.x, (double)_right.y, (double)_right.z );
538 qCDebug(octree, "_fieldOfView=%f", _fieldOfView);540 qCDebug(octree, "_fieldOfView=%f", (double)_fieldOfView);
539 qCDebug(octree, "_aspectRatio=%f", _aspectRatio);541 qCDebug(octree, "_aspectRatio=%f", (double)_aspectRatio);
540 qCDebug(octree, "_keyHoleRadius=%f", _keyholeRadius);542 qCDebug(octree, "_keyHoleRadius=%f", (double)_keyholeRadius);
541 qCDebug(octree, "_nearClip=%f", _nearClip);543 qCDebug(octree, "_nearClip=%f", (double)_nearClip);
542 qCDebug(octree, "_farClip=%f", _farClip);544 qCDebug(octree, "_farClip=%f", (double)_farClip);
543 qCDebug(octree, "_focalLength=%f", _focalLength);545 qCDebug(octree, "_focalLength=%f", (double)_focalLength);
544}546}
545 547
546glm::vec2 ViewFrustum::projectPoint(glm::vec3 point, bool& pointInView) const {548glm::vec2 ViewFrustum::projectPoint(glm::vec3 point, bool& pointInView) const {
547 549
548 glm::vec4 pointVec4 = glm::vec4(point,1);550 glm::vec4 pointVec4 = glm::vec4(point, 1.0f);
549 glm::vec4 projectedPointVec4 = _ourModelViewProjectionMatrix * pointVec4;551 glm::vec4 projectedPointVec4 = _ourModelViewProjectionMatrix * pointVec4;
550 pointInView = (projectedPointVec4.w > 0); // math! If the w result is negative then the point is behind the viewer552 pointInView = (projectedPointVec4.w > 0.0f); // math! If the w result is negative then the point is behind the viewer
551 553
552 // what happens with w is 0???554 // what happens with w is 0???
553 float x = projectedPointVec4.x / projectedPointVec4.w;555 float x = projectedPointVec4.x / projectedPointVec4.w;
libraries/physics/src/EntityMotionState.cpp+2−2
@@ -245,7 +245,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { · 244 unmodified lines
245 245
246 float dx2 = glm::distance2(position, _serverPosition);246 float dx2 = glm::distance2(position, _serverPosition);
247 247
248 const float MAX_POSITION_ERROR_SQUARED = 0.001f; // 0.001 m^2 ~~> 0.03 m248 const float MAX_POSITION_ERROR_SQUARED = 0.000004f; // Sqrt() - corresponds to 2 millimeters
249 if (dx2 > MAX_POSITION_ERROR_SQUARED) {249 if (dx2 > MAX_POSITION_ERROR_SQUARED) {
250 250
251 #ifdef WANT_DEBUG251 #ifdef WANT_DEBUG
@@ -270,7 +270,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { · 18 unmodified lines
270 _serverRotation = glm::normalize(computeBulletRotationStep(_serverAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP) * _serverRotation);270 _serverRotation = glm::normalize(computeBulletRotationStep(_serverAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP) * _serverRotation);
271 }271 }
272 }272 }
273 const float MIN_ROTATION_DOT = 0.99f; // 0.99 dot threshold coresponds to about 16 degrees of slop273 const float MIN_ROTATION_DOT = 0.99999f; // This corresponds to about 0.5 degrees of rotation
274 glm::quat actualRotation = bulletToGLM(worldTrans.getRotation());274 glm::quat actualRotation = bulletToGLM(worldTrans.getRotation());
275 275
276 #ifdef WANT_DEBUG276 #ifdef WANT_DEBUG
libraries/physics/src/MeshMassProperties.cpp+4−0
@@ -270,7 +270,9 @@ void MeshMassProperties::computeMassProperties(const VectorOfPoints& points, con · 269 unmodified lines
270 }270 }
271 271
272 // create some variables to hold temporary results272 // create some variables to hold temporary results
273 #ifndef NDEBUG
273 uint32_t numPoints = points.size();274 uint32_t numPoints = points.size();
275 #endif
274 const btVector3 p0(0.0f, 0.0f, 0.0f);276 const btVector3 p0(0.0f, 0.0f, 0.0f);
275 btMatrix3x3 tetraInertia;277 btMatrix3x3 tetraInertia;
276 btMatrix3x3 doubleDebugInertia;278 btMatrix3x3 doubleDebugInertia;
@@ -281,9 +283,11 @@ void MeshMassProperties::computeMassProperties(const VectorOfPoints& points, con · 4 unmodified lines
281 uint32_t numTriangles = triangleIndices.size() / 3;283 uint32_t numTriangles = triangleIndices.size() / 3;
282 for (uint32_t i = 0; i < numTriangles; ++i) {284 for (uint32_t i = 0; i < numTriangles; ++i) {
283 uint32_t t = 3 * i;285 uint32_t t = 3 * i;
286 #ifndef NDEBUG
284 assert(triangleIndices[t] < numPoints);287 assert(triangleIndices[t] < numPoints);
285 assert(triangleIndices[t + 1] < numPoints);288 assert(triangleIndices[t + 1] < numPoints);
286 assert(triangleIndices[t + 2] < numPoints);289 assert(triangleIndices[t + 2] < numPoints);
290 #endif
287 291
288 // extract raw vertices292 // extract raw vertices
289 tetraPoints[0] = p0;293 tetraPoints[0] = p0;
libraries/physics/src/ObjectAction.cpp+1−1
@@ -28,7 +28,7 @@ void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar delta · 27 unmodified lines
28 return;28 return;
29 }29 }
30 if (!_ownerEntity) {30 if (!_ownerEntity) {
31 qDebug() << "ObjectActionPullToPoint::updateAction no owner entity";31 qDebug() << "ObjectAction::updateAction no owner entity";
32 return;32 return;
33 }33 }
34 updateActionWorker(deltaTimeStep);34 updateActionWorker(deltaTimeStep);
libraries/physics/src/ObjectAction.h+1−0
@@ -59,6 +59,7 @@ protected: · 58 unmodified lines
59 59
60 bool tryLockForRead() { return _lock.tryLockForRead(); }60 bool tryLockForRead() { return _lock.tryLockForRead(); }
61 void lockForWrite() { _lock.lockForWrite(); }61 void lockForWrite() { _lock.lockForWrite(); }
62 bool tryLockForWrite() { return _lock.tryLockForWrite(); }
62 void unlock() { _lock.unlock(); }63 void unlock() { _lock.unlock(); }
63 64
64 bool _active;65 bool _active;
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
14ObjectActionOffset::ObjectActionOffset(QUuid id, EntityItemPointer ownerEntity) :
15 ObjectAction(id, ownerEntity) {
16 #if WANT_DEBUG
17 qDebug() << "ObjectActionOffset::ObjectActionOffset";
18 #endif
19}
20
21ObjectActionOffset::~ObjectActionOffset() {
22 #if WANT_DEBUG
23 qDebug() << "ObjectActionOffset::~ObjectActionOffset";
24 #endif
25}
26
27void 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
68bool 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
20class ObjectActionOffset : public ObjectAction {
21public:
22 ObjectActionOffset(QUuid id, EntityItemPointer ownerEntity);
23 virtual ~ObjectActionOffset();
24
25 virtual bool updateArguments(QVariantMap arguments);
26 virtual void updateActionWorker(float deltaTimeStep);
27
28private:
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
14ObjectActionPullToPoint::ObjectActionPullToPoint(QUuid id, EntityItemPointer ownerEntity) :
15 ObjectAction(id, ownerEntity) {
16 #if WANT_DEBUG
17 qDebug() << "ObjectActionPullToPoint::ObjectActionPullToPoint";
18 #endif
19}
20
21ObjectActionPullToPoint::~ObjectActionPullToPoint() {
22 #if WANT_DEBUG
23 qDebug() << "ObjectActionPullToPoint::~ObjectActionPullToPoint";
24 #endif
25}
26
27void 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
59bool 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
20class ObjectActionPullToPoint : public ObjectAction {
21public:
22 ObjectActionPullToPoint(QUuid id, EntityItemPointer ownerEntity);
23 virtual ~ObjectActionPullToPoint();
24
25 virtual bool updateArguments(QVariantMap arguments);
26 virtual void updateActionWorker(float deltaTimeStep);
27
28private:
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 @@
1set(TARGET_NAME render-utils)1set(TARGET_NAME render-utils)
2 2
3AUTOSCRIBE_SHADER_LIB(gpu model render)3AUTOSCRIBE_SHADER_LIB(gpu model render)
4 4
5# pull in the resources.qrc file5# pull in the resources.qrc file
6qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc")6qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc")
7 7
8# use setup_hifi_library macro to setup our project and link appropriate Qt modules8# use setup_hifi_library macro to setup our project and link appropriate Qt modules
9setup_hifi_library(Widgets OpenGL Network Qml Quick Script)9setup_hifi_library(Widgets OpenGL Network Qml Quick Script)
10 10
11add_dependency_external_projects(glm)11setup_hifi_opengl()
12find_package(GLM REQUIRED)12
13target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})13add_dependency_external_projects(glm)
14 14find_package(GLM REQUIRED)
15if (WIN32)15target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
16 if (USE_NSIGHT)16
17 # try to find the Nsight package and add it to the build if we find it17if (WIN32)
18 find_package(NSIGHT)18 if (USE_NSIGHT)
19 if (NSIGHT_FOUND)19 # try to find the Nsight package and add it to the build if we find it
20 include_directories(${NSIGHT_INCLUDE_DIRS})20 find_package(NSIGHT)
21 add_definitions(-DNSIGHT_FOUND)21 if (NSIGHT_FOUND)
22 target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}")22 include_directories(${NSIGHT_INCLUDE_DIRS})
23 endif ()23 add_definitions(-DNSIGHT_FOUND)
24 endif()24 target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}")
25endif (WIN32)25 endif ()
26 26 endif()
27link_hifi_libraries(animation fbx shared gpu model render)27
28 add_dependency_external_projects(boostconfig)
29 find_package(BoostConfig REQUIRED)
30 target_include_directories(${TARGET_NAME} PUBLIC ${BOOSTCONFIG_INCLUDE_DIRS})
31
32 add_dependency_external_projects(oglplus)
33 find_package(OGLPLUS REQUIRED)
34 target_include_directories(${TARGET_NAME} PUBLIC ${OGLPLUS_INCLUDE_DIRS})
35endif (WIN32)
36
37link_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
61 gpu::Shader::BindingSet slotBindings;61 gpu::Shader::BindingSet slotBindings;
62 gpu::Shader::makeProgram(*program, slotBindings);62 gpu::Shader::makeProgram(*program, slotBindings);
63 gpu::Shader::makeProgram(*programTextured, slotBindings);63 gpu::Shader::makeProgram(*programTextured, slotBindings);
64 64
65 gpu::StatePointer state = gpu::StatePointer(new gpu::State());65 gpu::StatePointer state = gpu::StatePointer(new gpu::State());
66 state->setCullMode(gpu::State::CULL_BACK);66 state->setCullMode(gpu::State::CULL_BACK);
67 state->setDepthTest(true, true, gpu::LESS_EQUAL);67 state->setDepthTest(true, true, gpu::LESS_EQUAL);
68 state->setBlendFunction(false,68 state->setBlendFunction(false,
69 gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,69 gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
70 gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);70 gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
71
72
73 gpu::StatePointer stateCullNone = gpu::StatePointer(new gpu::State());
74 stateCullNone->setCullMode(gpu::State::CULL_NONE);
75 stateCullNone->setDepthTest(true, true, gpu::LESS_EQUAL);
76 stateCullNone->setBlendFunction(false,
77 gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
78 gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
79
71 _simpleProgram = gpu::PipelinePointer(gpu::Pipeline::create(program, state));80 _simpleProgram = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
81 _simpleProgramCullNone = gpu::PipelinePointer(gpu::Pipeline::create(program, stateCullNone));
72 _simpleProgramTextured = gpu::PipelinePointer(gpu::Pipeline::create(programTextured, state));82 _simpleProgramTextured = gpu::PipelinePointer(gpu::Pipeline::create(programTextured, state));
83 _simpleProgramTexturedCullNone = gpu::PipelinePointer(gpu::Pipeline::create(programTextured, stateCullNone));
73 84
74 _viewState = viewState;85 _viewState = viewState;
75 loadLightProgram(directional_light_frag, false, _directionalLight, _directionalLightLocations);86 loadLightProgram(directional_light_frag, false, _directionalLight, _directionalLightLocations);
@@ -106,13 +117,21 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { · 30 unmodified lines
106 lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET));117 lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET));
107}118}
108 119
109void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured) {120void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled) {
110 // DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(batch, true, true, true);121 // DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(batch, true, true, true);
111 122
112 if (textured) {123 if (textured) {
113 batch.setPipeline(_simpleProgramTextured);124 if (culled) {
125 batch.setPipeline(_simpleProgramTextured);
126 } else {
127 batch.setPipeline(_simpleProgramTexturedCullNone);
128 }
114 } else {129 } else {
115 batch.setPipeline(_simpleProgram);130 if (culled) {
131 batch.setPipeline(_simpleProgram);
132 } else {
133 batch.setPipeline(_simpleProgramCullNone);
134 }
116 }135 }
117}136}
118 137
@@ -191,7 +210,7 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu · 72 unmodified lines
191 }210 }
192}211}
193 212
194void DeferredLightingEffect::prepare() {213void DeferredLightingEffect::prepare(RenderArgs* args) {
195 // clear the normal and specular buffers214 // clear the normal and specular buffers
196 auto textureCache = DependencyManager::get<TextureCache>();215 auto textureCache = DependencyManager::get<TextureCache>();
197 textureCache->setPrimaryDrawBuffers(false, true, false);216 textureCache->setPrimaryDrawBuffers(false, true, false);
@@ -205,7 +224,7 @@ void DeferredLightingEffect::prepare() { · 7 unmodified lines
205 textureCache->setPrimaryDrawBuffers(true, false, false);224 textureCache->setPrimaryDrawBuffers(true, false, false);
206}225}
207 226
208void DeferredLightingEffect::render() {227void DeferredLightingEffect::render(RenderArgs* args) {
209 // perform deferred lighting, rendering to free fbo228 // perform deferred lighting, rendering to free fbo
210 glDisable(GL_BLEND);229 glDisable(GL_BLEND);
211 glDisable(GL_LIGHTING);230 glDisable(GL_LIGHTING);
libraries/render-utils/src/DeferredLightingEffect.h+5−3
@@ -34,7 +34,7 @@ public: · 33 unmodified lines
34 void init(AbstractViewStateInterface* viewState);34 void init(AbstractViewStateInterface* viewState);
35 35
36 /// Sets up the state necessary to render static untextured geometry with the simple program.36 /// Sets up the state necessary to render static untextured geometry with the simple program.
37 void bindSimpleProgram(gpu::Batch& batch, bool textured = false);37 void bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true);
38 38
39 /// Tears down the state necessary to render static untextured geometry with the simple program.39 /// Tears down the state necessary to render static untextured geometry with the simple program.
40 void releaseSimpleProgram(gpu::Batch& batch);40 void releaseSimpleProgram(gpu::Batch& batch);
@@ -66,8 +66,8 @@ public: · 25 unmodified lines
66 void addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f),66 void addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f),
67 float intensity = 0.5f, const glm::quat& orientation = glm::quat(), float exponent = 0.0f, float cutoff = PI);67 float intensity = 0.5f, const glm::quat& orientation = glm::quat(), float exponent = 0.0f, float cutoff = PI);
68 68
69 void prepare();69 void prepare(RenderArgs* args);
70 void render();70 void render(RenderArgs* args);
71 void copyBack(RenderArgs* args);71 void copyBack(RenderArgs* args);
72 72
73 void setupTransparent(RenderArgs* args, int lightBufferUnit);73 void setupTransparent(RenderArgs* args, int lightBufferUnit);
@@ -100,7 +100,9 @@ private: · 26 unmodified lines
100 static void loadLightProgram(const char* fragSource, bool limited, ProgramObject& program, LightLocations& locations);100 static void loadLightProgram(const char* fragSource, bool limited, ProgramObject& program, LightLocations& locations);
101 101
102 gpu::PipelinePointer _simpleProgram;102 gpu::PipelinePointer _simpleProgram;
103 gpu::PipelinePointer _simpleProgramCullNone;
103 gpu::PipelinePointer _simpleProgramTextured;104 gpu::PipelinePointer _simpleProgramTextured;
105 gpu::PipelinePointer _simpleProgramTexturedCullNone;
104 106
105 ProgramObject _directionalSkyboxLight;107 ProgramObject _directionalSkyboxLight;
106 LightLocations _directionalSkyboxLightLocations;108 LightLocations _directionalSkyboxLightLocations;
libraries/render-utils/src/GeometryCache.cpp+82−39
@@ -28,6 +28,9 @@ · 27 unmodified lines
28#include "RenderUtilsLogging.h"28#include "RenderUtilsLogging.h"
29#include "GeometryCache.h"29#include "GeometryCache.h"
30 30
31#include "standardTransformPNTC_vert.h"
32#include "standardDrawTexture_frag.h"
33
31//#define WANT_DEBUG34//#define WANT_DEBUG
32 35
33const int GeometryCache::UNKNOWN_ID = -1;36const int GeometryCache::UNKNOWN_ID = -1;
@@ -1025,13 +1028,13 @@ void GeometryCache::renderBevelCornersRect(gpu::Batch& batch, int x, int y, int · 991 unmodified lines
1025 #endif // def WANT_DEBUG1028 #endif // def WANT_DEBUG
1026 }1029 }
1027 1030
1028 const int FLOATS_PER_VERTEX = 2; // vertices
1029 const int vertices = 8;
1030
1031 if (!details.isCreated) {1031 if (!details.isCreated) {
1032 1032 static const int FLOATS_PER_VERTEX = 2; // vertices
1033 static const int NUM_VERTICES = 8;
1034 static const int NUM_FLOATS = NUM_VERTICES * FLOATS_PER_VERTEX;
1035
1033 details.isCreated = true;1036 details.isCreated = true;
1034 details.vertices = vertices;1037 details.vertices = NUM_VERTICES;
1035 details.vertexSize = FLOATS_PER_VERTEX;1038 details.vertexSize = FLOATS_PER_VERTEX;
1036 1039
1037 gpu::BufferPointer verticesBuffer(new gpu::Buffer());1040 gpu::BufferPointer verticesBuffer(new gpu::Buffer());
@@ -1044,62 +1047,65 @@ void GeometryCache::renderBevelCornersRect(gpu::Batch& batch, int x, int y, int · 6 unmodified lines
1044 details.streamFormat = streamFormat;1047 details.streamFormat = streamFormat;
1045 details.stream = stream;1048 details.stream = stream;
1046 1049
1047 details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0);1050 details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ));
1048 details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA));1051 details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA));
1049 1052
1050 details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride);1053 details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride);
1051 details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride);1054 details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride);
1052 1055
1053 1056
1054 int vertexPoints = vertices * FLOATS_PER_VERTEX;1057 GLfloat vertexBuffer[NUM_FLOATS]; // only vertices, no normals because we're a 2D quad
1055 GLfloat* vertexBuffer = new GLfloat[vertexPoints]; // only vertices, no normals because we're a 2D quad
1056 GLfloat* vertex = vertexBuffer;
1057 int vertexPoint = 0;1058 int vertexPoint = 0;
1058 1059
1059 // left side1060 // Triangle strip points
1060 vertex[vertexPoint++] = x;1061 // 3 ------ 5
1061 vertex[vertexPoint++] = y + bevelDistance;1062 // / \
1063 // 1 7
1064 // | |
1065 // 2 8
1066 // \ /
1067 // 4 ------ 6
1062 1068
1063 vertex[vertexPoint++] = x;1069 // 1
1064 vertex[vertexPoint++] = y + height - bevelDistance;1070 vertexBuffer[vertexPoint++] = x;
1065 1071 vertexBuffer[vertexPoint++] = y + height - bevelDistance;
1066 // top side1072 // 2
1067 vertex[vertexPoint++] = x + bevelDistance;1073 vertexBuffer[vertexPoint++] = x;
1068 vertex[vertexPoint++] = y + height;1074 vertexBuffer[vertexPoint++] = y + bevelDistance;
1075 // 3
1076 vertexBuffer[vertexPoint++] = x + bevelDistance;
1077 vertexBuffer[vertexPoint++] = y + height;
1078 // 4
1079 vertexBuffer[vertexPoint++] = x + bevelDistance;
1080 vertexBuffer[vertexPoint++] = y;
1081 // 5
1082 vertexBuffer[vertexPoint++] = x + width - bevelDistance;
1083 vertexBuffer[vertexPoint++] = y + height;
1084 // 6
1085 vertexBuffer[vertexPoint++] = x + width - bevelDistance;
1086 vertexBuffer[vertexPoint++] = y;
1087 // 7
1088 vertexBuffer[vertexPoint++] = x + width;
1089 vertexBuffer[vertexPoint++] = y + height - bevelDistance;
1090 // 8
1091 vertexBuffer[vertexPoint++] = x + width;
1092 vertexBuffer[vertexPoint++] = y + bevelDistance;
1069 1093
1070 vertex[vertexPoint++] = x + width - bevelDistance;
1071 vertex[vertexPoint++] = y + height;
1072
1073 // right
1074 vertex[vertexPoint++] = x + width;
1075 vertex[vertexPoint++] = y + height - bevelDistance;
1076 vertex[vertexPoint++] = x + width;
1077 vertex[vertexPoint++] = y + bevelDistance;
1078
1079 // bottom
1080 vertex[vertexPoint++] = x + width - bevelDistance;
1081 vertex[vertexPoint++] = y;
1082 vertex[vertexPoint++] = x +bevelDistance;
1083 vertex[vertexPoint++] = y;
1084
1085 const int NUM_COLOR_SCALARS_PER_QUAD = 8;
1086 int compactColor = ((int(color.x * 255.0f) & 0xFF)) |1094 int compactColor = ((int(color.x * 255.0f) & 0xFF)) |
1087 ((int(color.y * 255.0f) & 0xFF) << 8) |1095 ((int(color.y * 255.0f) & 0xFF) << 8) |
1088 ((int(color.z * 255.0f) & 0xFF) << 16) |1096 ((int(color.z * 255.0f) & 0xFF) << 16) |
1089 ((int(color.w * 255.0f) & 0xFF) << 24);1097 ((int(color.w * 255.0f) & 0xFF) << 24);
1090 int colors[NUM_COLOR_SCALARS_PER_QUAD] = { compactColor, compactColor, compactColor, compactColor,1098 int colors[NUM_VERTICES] = { compactColor, compactColor, compactColor, compactColor,
1091 compactColor, compactColor, compactColor, compactColor };1099 compactColor, compactColor, compactColor, compactColor };
1092 1100
1093 1101
1094 details.verticesBuffer->append(sizeof(vertexBuffer), (gpu::Byte*) vertexBuffer);1102 details.verticesBuffer->append(sizeof(vertexBuffer), (gpu::Byte*) vertexBuffer);
1095 details.colorBuffer->append(sizeof(colors), (gpu::Byte*) colors);1103 details.colorBuffer->append(sizeof(colors), (gpu::Byte*) colors);
1096
1097 delete[] vertexBuffer;
1098 }1104 }
1099 1105
1100 batch.setInputFormat(details.streamFormat);1106 batch.setInputFormat(details.streamFormat);
1101 batch.setInputStream(0, *details.stream);1107 batch.setInputStream(0, *details.stream);
1102 batch.draw(gpu::QUADS, 4, 0);1108 batch.draw(gpu::TRIANGLE_STRIP, details.vertices, 0);
1103}1109}
1104 1110
1105void GeometryCache::renderQuad(const glm::vec2& minCorner, const glm::vec2& maxCorner, const glm::vec4& color, int id) {1111void GeometryCache::renderQuad(const glm::vec2& minCorner, const glm::vec2& maxCorner, const glm::vec4& color, int id) {
@@ -1179,6 +1185,26 @@ void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, co · 73 unmodified lines
1179 batch.draw(gpu::QUADS, 4, 0);1185 batch.draw(gpu::QUADS, 4, 0);
1180}1186}
1181 1187
1188void GeometryCache::renderUnitCube(gpu::Batch& batch) {
1189 static const glm::vec4 color(1);
1190 renderSolidCube(batch, 1, color);
1191}
1192
1193void GeometryCache::renderUnitQuad(const glm::vec4& color, int id) {
1194 gpu::Batch batch;
1195 renderUnitQuad(batch, color, id);
1196 gpu::GLBackend::renderBatch(batch);
1197}
1198
1199void 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
1182void GeometryCache::renderQuad(const glm::vec2& minCorner, const glm::vec2& maxCorner,1208void GeometryCache::renderQuad(const glm::vec2& minCorner, const glm::vec2& maxCorner,
1183 const glm::vec2& texCoordMinCorner, const glm::vec2& texCoordMaxCorner, 1209 const glm::vec2& texCoordMinCorner, const glm::vec2& texCoordMaxCorner,
1184 const glm::vec4& color, int id) {1210 const glm::vec4& color, int id) {
@@ -1802,6 +1828,23 @@ QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url, const QS · 617 unmodified lines
1802 return geometry.staticCast<Resource>();1828 return geometry.staticCast<Resource>();
1803}1829}
1804 1830
1831void 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
1805const float NetworkGeometry::NO_HYSTERESIS = -1.0f;1848const float NetworkGeometry::NO_HYSTERESIS = -1.0f;
1806 1849
1807NetworkGeometry::NetworkGeometry(const QUrl& url, const QSharedPointer<NetworkGeometry>& fallback, bool delayLoad,1850NetworkGeometry::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
155 void renderBevelCornersRect(int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID);155 void renderBevelCornersRect(int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID);
156 void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID);156 void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID);
157 157
158 void renderUnitCube(gpu::Batch& batch);
159 void renderUnitQuad(const glm::vec4& color = glm::vec4(1), int id = UNKNOWN_ID);
160 void renderUnitQuad(gpu::Batch& batch, const glm::vec4& color = glm::vec4(1), int id = UNKNOWN_ID);
161
158 void renderQuad(int x, int y, int width, int height, const glm::vec4& color, int id = UNKNOWN_ID)162 void renderQuad(int x, int y, int width, int height, const glm::vec4& color, int id = UNKNOWN_ID)
159 { renderQuad(glm::vec2(x,y), glm::vec2(x + width, y + height), color, id); }163 { renderQuad(glm::vec2(x,y), glm::vec2(x + width, y + height), color, id); }
160 void renderQuad(gpu::Batch& batch, int x, int y, int width, int height, const glm::vec4& color, int id = UNKNOWN_ID)164 void renderQuad(gpu::Batch& batch, int x, int y, int width, int height, const glm::vec4& color, int id = UNKNOWN_ID)
@@ -249,6 +253,9 @@ public: · 88 unmodified lines
249 /// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested253 /// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested
250 QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false);254 QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false);
251 255
256 /// Set a batch to the simple pipeline, returning the previous pipeline
257 void useSimpleDrawPipeline(gpu::Batch& batch);
258
252protected:259protected:
253 260
254 virtual QSharedPointer<Resource> createResource(const QUrl& url,261 virtual QSharedPointer<Resource> createResource(const QUrl& url,
@@ -266,6 +273,7 @@ private: · 11 unmodified lines
266 int vertexSize;273 int vertexSize;
267 };274 };
268 275
276 gpu::PipelinePointer _standardDrawPipeline;
269 QHash<float, gpu::BufferPointer> _cubeVerticies;277 QHash<float, gpu::BufferPointer> _cubeVerticies;
270 QHash<Vec2Pair, gpu::BufferPointer> _cubeColors;278 QHash<Vec2Pair, gpu::BufferPointer> _cubeColors;
271 gpu::BufferPointer _wireCubeIndexBuffer;279 gpu::BufferPointer _wireCubeIndexBuffer;
@@ -273,7 +281,7 @@ private: · 1 unmodified line
273 QHash<float, gpu::BufferPointer> _solidCubeVertices;281 QHash<float, gpu::BufferPointer> _solidCubeVertices;
274 QHash<Vec2Pair, gpu::BufferPointer> _solidCubeColors;282 QHash<Vec2Pair, gpu::BufferPointer> _solidCubeColors;
275 gpu::BufferPointer _solidCubeIndexBuffer;283 gpu::BufferPointer _solidCubeIndexBuffer;
276 284
277 class BatchItemDetails {285 class BatchItemDetails {
278 public:286 public:
279 static int population;287 static int population;
libraries/render-utils/src/Model.cpp+10−5
@@ -545,11 +545,6 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g · 544 unmodified lines
545 // we can use the AABox's ray intersection by mapping our origin and direction into the model frame545 // we can use the AABox's ray intersection by mapping our origin and direction into the model frame
546 // and testing intersection there.546 // and testing intersection there.
547 if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face)) {547 if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face)) {
548
549 if (!_calculatedMeshBoxesValid) {
550 recalculateMeshBoxes(pickAgainstTriangles);
551 }
552
553 float bestDistance = std::numeric_limits<float>::max();548 float bestDistance = std::numeric_limits<float>::max();
554 549
555 float distanceToSubMesh;550 float distanceToSubMesh;
@@ -560,6 +555,11 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g · 4 unmodified lines
560 555
561 // If we hit the models box, then consider the submeshes...556 // If we hit the models box, then consider the submeshes...
562 _mutex.lock();557 _mutex.lock();
558
559 if (!_calculatedMeshBoxesValid) {
560 recalculateMeshBoxes(pickAgainstTriangles);
561 }
562
563 foreach(const AABox& subMeshBox, _calculatedMeshBoxes) {563 foreach(const AABox& subMeshBox, _calculatedMeshBoxes) {
564 564
565 if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace)) {565 if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace)) {
@@ -1804,13 +1804,16 @@ AABox Model::getPartBounds(int meshIndex, int partIndex) { · 1238 unmodified lines
1804}1804}
1805 1805
1806void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent) {1806void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent) {
1807 PerformanceTimer perfTimer("Model::renderPart");
1807 if (!_readyWhenAdded) {1808 if (!_readyWhenAdded) {
1808 return; // bail asap1809 return; // bail asap
1809 }1810 }
1810 1811
1811 // We need to make sure we have valid offsets calculated before we can render1812 // We need to make sure we have valid offsets calculated before we can render
1812 if (!_calculatedMeshPartOffsetValid) {1813 if (!_calculatedMeshPartOffsetValid) {
1814 _mutex.lock();
1813 recalculateMeshPartOffsets();1815 recalculateMeshPartOffsets();
1816 _mutex.unlock();
1814 }1817 }
1815 auto textureCache = DependencyManager::get<TextureCache>();1818 auto textureCache = DependencyManager::get<TextureCache>();
1816 1819
@@ -2018,7 +2021,9 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran · 201 unmodified lines
2018 }2021 }
2019 }2022 }
2020 2023
2024 _mutex.lock();
2021 qint64 offset = _calculatedMeshPartOffset[QPair<int,int>(meshIndex, partIndex)];2025 qint64 offset = _calculatedMeshPartOffset[QPair<int,int>(meshIndex, partIndex)];
2026 _mutex.unlock();
2022 2027
2023 if (part.quadIndices.size() > 0) {2028 if (part.quadIndices.size() > 0) {
2024 batch.drawIndexed(gpu::QUADS, part.quadIndices.size(), offset);2029 batch.drawIndexed(gpu::QUADS, part.quadIndices.size(), offset);
libraries/render-utils/src/OffscreenQmlSurface.cpp+6−2
@@ -11,6 +11,9 @@ · 10 unmodified lines
11#include <QOpenGLDebugLogger>11#include <QOpenGLDebugLogger>
12#include <QGLWidget>12#include <QGLWidget>
13#include <QtQml>13#include <QtQml>
14
15#include <PerfStat.h>
16
14#include "AbstractViewStateInterface.h"17#include "AbstractViewStateInterface.h"
15 18
16Q_DECLARE_LOGGING_CATEGORY(offscreenFocus)19Q_DECLARE_LOGGING_CATEGORY(offscreenFocus)
@@ -91,6 +94,7 @@ void OffscreenQmlSurface::resize(const QSize& newSize) { · 74 unmodified lines
91 // Qt bug in 5.4 forces this check of pixel ratio,94 // Qt bug in 5.4 forces this check of pixel ratio,
92 // even though we're rendering offscreen.95 // even though we're rendering offscreen.
93 qreal pixelRatio = 1.0;96 qreal pixelRatio = 1.0;
97 _qmlEngine->rootContext()->setContextProperty("surfaceSize", newSize);
94 if (_renderControl && _renderControl->_renderWindow) {98 if (_renderControl && _renderControl->_renderWindow) {
95 pixelRatio = _renderControl->_renderWindow->devicePixelRatio();99 pixelRatio = _renderControl->_renderWindow->devicePixelRatio();
96 } else {100 } else {
@@ -111,7 +115,6 @@ void OffscreenQmlSurface::resize(const QSize& newSize) { · 14 unmodified lines
111 _quickWindow->contentItem()->setSize(newSize);115 _quickWindow->contentItem()->setSize(newSize);
112 }116 }
113 117
114
115 // Update our members118 // Update our members
116 if (_rootItem) {119 if (_rootItem) {
117 _rootItem->setSize(newSize);120 _rootItem->setSize(newSize);
@@ -212,6 +215,7 @@ QObject* OffscreenQmlSurface::finishQmlLoad(std::function<void(QQmlContext*, QOb · 94 unmodified lines
212 215
213 216
214void OffscreenQmlSurface::updateQuick() {217void OffscreenQmlSurface::updateQuick() {
218 PerformanceTimer perfTimer("qmlUpdate");
215 if (_paused) {219 if (_paused) {
216 return;220 return;
217 }221 }
@@ -376,4 +380,4 @@ void OffscreenQmlSurface::setProxyWindow(QWindow* window) { · 158 unmodified lines
376 380
377QQuickWindow* OffscreenQmlSurface::getWindow() {381QQuickWindow* OffscreenQmlSurface::getWindow() {
378 return _quickWindow;382 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
12using namespace oglplus;
13using namespace oglplus::shapes;
14
15static const char * SIMPLE_TEXTURED_VS = R"VS(#version 410 core
16#pragma line __LINE__
17
18uniform mat4 Projection = mat4(1);
19uniform mat4 ModelView = mat4(1);
20
21layout(location = 0) in vec3 Position;
22layout(location = 1) in vec2 TexCoord;
23
24out vec2 vTexCoord;
25
26void main() {
27 gl_Position = Projection * ModelView * vec4(Position, 1);
28 vTexCoord = TexCoord;
29}
30
31)VS";
32
33static const char * SIMPLE_TEXTURED_FS = R"FS(#version 410 core
34#pragma line __LINE__
35
36uniform sampler2D sampler;
37uniform float Alpha = 1.0;
38
39in vec2 vTexCoord;
40out vec4 vFragColor;
41
42void main() {
43 vec4 c = texture(sampler, vTexCoord);
44 c.a = min(Alpha, c.a);
45 vFragColor = c;
46}
47
48)FS";
49
50
51ProgramPtr loadDefaultShader() {
52 ProgramPtr result;
53 compileProgram(result, SIMPLE_TEXTURED_VS, SIMPLE_TEXTURED_FS);
54 return result;
55}
56
57void 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
82ShapeWrapperPtr 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
97static 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
104class SphereSection : public DrawingInstructionWriter, public DrawMode {
105public:
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
117public:
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
319ShapeWrapperPtr 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
54using FramebufferPtr = std::shared_ptr<oglplus::Framebuffer>;
55using ShapeWrapperPtr = std::shared_ptr<oglplus::shapes::ShapeWrapper>;
56using BufferPtr = std::shared_ptr<oglplus::Buffer>;
57using VertexArrayPtr = std::shared_ptr<oglplus::VertexArray>;
58using ProgramPtr = std::shared_ptr<oglplus::Program>;
59using Mat4Uniform = oglplus::Uniform<mat4>;
60
61ProgramPtr loadDefaultShader();
62void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs);
63ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect = 1.0f);
64ShapeWrapperPtr 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.
74template <
75 typename C,
76 typename D
77>
78struct 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
114protected:
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
137struct BasicFramebufferWrapper : public FramebufferWrapper <oglplus::Texture, oglplus::Renderbuffer> {
138protected:
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
172using BasicFramebufferWrapperPtr = std::shared_ptr<BasicFramebufferWrapper>;
173#endif
libraries/render-utils/src/ProgramObject.h+12−3
@@ -12,22 +12,31 @@ · 11 unmodified lines
12#ifndef hifi_ProgramObject_h12#ifndef hifi_ProgramObject_h
13#define hifi_ProgramObject_h13#define hifi_ProgramObject_h
14 14
15#ifdef __GNUC__
16#pragma GCC diagnostic push
17#pragma GCC diagnostic ignored "-Wdouble-promotion"
18#endif
19
15#include <QGLShaderProgram>20#include <QGLShaderProgram>
16 21
22#ifdef __GNUC__
23#pragma GCC diagnostic pop
24#endif
25
17#include <glm/glm.hpp>26#include <glm/glm.hpp>
18 27
19class ProgramObject : public QGLShaderProgram {28class ProgramObject : public QGLShaderProgram {
20public:29public:
21 30
22 ProgramObject(QObject* parent = 0);31 ProgramObject(QObject* parent = 0);
23 32
24 void setUniform(int location, const glm::vec2& value);33 void setUniform(int location, const glm::vec2& value);
25 void setUniform(const char* name, const glm::vec2& value);34 void setUniform(const char* name, const glm::vec2& value);
26 void setUniform(int location, const glm::vec3& value);35 void setUniform(int location, const glm::vec3& value);
27 void setUniform(const char* name, const glm::vec3& value);36 void setUniform(const char* name, const glm::vec3& value);
28 void setUniform(int location, const glm::vec4& value);37 void setUniform(int location, const glm::vec4& value);
29 void setUniform(const char* name, const glm::vec4& value);38 void setUniform(const char* name, const glm::vec4& value);
30 void setUniformArray(const char* name, const glm::vec3* values, int count); 39 void setUniformArray(const char* name, const glm::vec3* values, int count);
31};40};
32 41
33#endif // hifi_ProgramObject_h42#endif // hifi_ProgramObject_h
libraries/render-utils/src/RenderDeferredTask.cpp+114−176
@@ -19,42 +19,54 @@ · 18 unmodified lines
19 19
20#include <PerfStat.h>20#include <PerfStat.h>
21 21
22#include "overlay3D_vert.h"22#include "overlay3D_vert.h"
23#include "overlay3D_frag.h"23#include "overlay3D_frag.h"
24 24
25using namespace render;25using namespace render;
26 26
27template <> void render::jobRun(const PrepareDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {27void PrepareDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
28 PerformanceTimer perfTimer("PrepareDeferred");28 DependencyManager::get<DeferredLightingEffect>()->prepare(renderContext->args);
29 DependencyManager::get<DeferredLightingEffect>()->prepare();
30}29}
31 30
32template <> void render::jobRun(const RenderDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {31void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
33 PerformanceTimer perfTimer("RenderDeferred");32 DependencyManager::get<DeferredLightingEffect>()->render(renderContext->args);
34 DependencyManager::get<DeferredLightingEffect>()->render();
35// renderContext->args->_context->syncCache();
36}33}
37 34
38template <> void render::jobRun(const ResolveDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {35void ResolveDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
39 PerformanceTimer perfTimer("ResolveDeferred");36 PerformanceTimer perfTimer("ResolveDeferred");
40 DependencyManager::get<DeferredLightingEffect>()->copyBack(renderContext->args);37 DependencyManager::get<DeferredLightingEffect>()->copyBack(renderContext->args);
41 renderContext->args->_context->syncCache();
42
43}38}
44 39
45
46
47RenderDeferredTask::RenderDeferredTask() : Task() {40RenderDeferredTask::RenderDeferredTask() : Task() {
48 _jobs.push_back(Job(PrepareDeferred()));41 _jobs.push_back(Job(new PrepareDeferred::JobModel("PrepareDeferred")));
49 _jobs.push_back(Job(DrawBackground()));42 _jobs.push_back(Job(new DrawBackground::JobModel("DrawBackground")));
50 _jobs.push_back(Job(DrawOpaqueDeferred()));43 _jobs.push_back(Job(new FetchItems::JobModel("FetchOpaque",
51 _jobs.push_back(Job(DrawLight()));44 FetchItems(
52 _jobs.push_back(Job(ResetGLState()));45 [] (const RenderContextPointer& context, int count) {
53 _jobs.push_back(Job(RenderDeferred()));46 context->_numFeedOpaqueItems = count;
54 _jobs.push_back(Job(ResolveDeferred()));47 }
55 _jobs.push_back(Job(DrawTransparentDeferred()));48 )
56 _jobs.push_back(Job(DrawOverlay3D()));49 )));
57 _jobs.push_back(Job(ResetGLState()));50 _jobs.push_back(Job(new CullItems::JobModel("CullOpaque", _jobs.back().getOutput())));
51 _jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortOpaque", _jobs.back().getOutput())));
52 _jobs.push_back(Job(new DrawOpaqueDeferred::JobModel("DrawOpaqueDeferred", _jobs.back().getOutput())));
53 _jobs.push_back(Job(new DrawLight::JobModel("DrawLight")));
54 _jobs.push_back(Job(new ResetGLState::JobModel()));
55 _jobs.push_back(Job(new RenderDeferred::JobModel("RenderDeferred")));
56 _jobs.push_back(Job(new ResolveDeferred::JobModel("ResolveDeferred")));
57 _jobs.push_back(Job(new FetchItems::JobModel("FetchTransparent",
58 FetchItems(
59 ItemFilter::Builder::transparentShape().withoutLayered(),
60 [] (const RenderContextPointer& context, int count) {
61 context->_numFeedTransparentItems = count;
62 }
63 )
64 )));
65 _jobs.push_back(Job(new CullItems::JobModel("CullTransparent", _jobs.back().getOutput())));
66 _jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false))));
67 _jobs.push_back(Job(new DrawTransparentDeferred::JobModel("TransparentDeferred", _jobs.back().getOutput())));
68 _jobs.push_back(Job(new DrawOverlay3D::JobModel("DrawOverlay3D")));
69 _jobs.push_back(Job(new ResetGLState::JobModel()));
58}70}
59 71
60RenderDeferredTask::~RenderDeferredTask() {72RenderDeferredTask::~RenderDeferredTask() {
@@ -80,181 +92,104 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend · 19 unmodified lines
80 }92 }
81};93};
82 94
83 95void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) {
84
85template <> void render::jobRun(const DrawOpaqueDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
86 PerformanceTimer perfTimer("DrawOpaqueDeferred");
87 assert(renderContext->args);96 assert(renderContext->args);
88 assert(renderContext->args->_viewFrustum);97 assert(renderContext->args->_viewFrustum);
89 98
90 // render opaques99 RenderArgs* args = renderContext->args;
91 auto& scene = sceneContext->_scene;100 gpu::Batch batch;
92 auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape().withoutLayered());101 args->_batch = &batch;
93 auto& renderDetails = renderContext->args->_details;
94
95 ItemIDsBounds inItems;
96 inItems.reserve(items.size());
97 for (auto id : items) {
98 inItems.emplace_back(ItemIDAndBounds(id));
99 }
100 ItemIDsBounds& renderedItems = inItems;
101
102 renderContext->_numFeedOpaqueItems = renderedItems.size();
103
104 ItemIDsBounds culledItems;
105 culledItems.reserve(inItems.size());
106 if (renderContext->_cullOpaque) {
107 renderDetails.pointTo(RenderDetails::OPAQUE_ITEM);
108 cullItems(sceneContext, renderContext, renderedItems, culledItems);
109 renderDetails.pointTo(RenderDetails::OTHER_ITEM);
110 renderedItems = culledItems;
111 }
112
113 renderContext->_numDrawnOpaqueItems = renderedItems.size();
114 102
103 renderContext->_numDrawnOpaqueItems = inItems.size();
115 104
116 ItemIDsBounds sortedItems;105 glm::mat4 projMat;
117 sortedItems.reserve(culledItems.size());106 Transform viewMat;
118 if (renderContext->_sortOpaque) {107 args->_viewFrustum->evalProjectionMatrix(projMat);
119 depthSortItems(sceneContext, renderContext, true, renderedItems, sortedItems); // Sort Front to back opaque items!108 args->_viewFrustum->evalViewTransform(viewMat);
120 renderedItems = sortedItems;109 if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
110 viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
121 }111 }
112 batch.setProjectionTransform(projMat);
113 batch.setViewTransform(viewMat);
122 114
123 // ItemIDsBounds sortedItems;115 {
124 /* ItemMaterialBucketMap stateSortedItems;116 GLenum buffers[3];
125 stateSortedItems.allocateStandardMaterialBuckets();117 int bufferCount = 0;
126 if (true) {118 buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
127 for (auto& itemIDAndBound : renderedItems) {119 buffers[bufferCount++] = GL_COLOR_ATTACHMENT1;
128 stateSortedItems.insert(itemIDAndBound.id, scene->getItem(itemIDAndBound.id).getMaterialKey());120 buffers[bufferCount++] = GL_COLOR_ATTACHMENT2;
129 }121 batch._glDrawBuffers(bufferCount, buffers);
122 const float OPAQUE_ALPHA_THRESHOLD = 0.5f;
123 args->_alphaThreshold = OPAQUE_ALPHA_THRESHOLD;
130 }124 }
131*/
132
133 if (renderContext->_renderOpaque) {
134 RenderArgs* args = renderContext->args;
135 gpu::Batch batch;
136 args->_batch = &batch;
137
138 glm::mat4 projMat;
139 Transform viewMat;
140 args->_viewFrustum->evalProjectionMatrix(projMat);
141 args->_viewFrustum->evalViewTransform(viewMat);
142 if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
143 viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
144 }
145 batch.setProjectionTransform(projMat);
146 batch.setViewTransform(viewMat);
147
148 {
149 GLenum buffers[3];
150 int bufferCount = 0;
151 buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
152 buffers[bufferCount++] = GL_COLOR_ATTACHMENT1;
153 buffers[bufferCount++] = GL_COLOR_ATTACHMENT2;
154 batch._glDrawBuffers(bufferCount, buffers);
155 }
156 125
157 renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnOpaqueItems);126 renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnOpaqueItems);
158 127
159 args->_context->render((*args->_batch));128 // Before rendering the batch make sure we re in sync with gl state
160 args->_batch = nullptr;129 args->_context->syncCache();
161 }130 renderContext->args->_context->syncCache();
131 args->_context->render((*args->_batch));
132 args->_batch = nullptr;
162}133}
163 134
164 135void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) {
165template <> void render::jobRun(const DrawTransparentDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
166 PerformanceTimer perfTimer("DrawTransparentDeferred");
167 assert(renderContext->args);136 assert(renderContext->args);
168 assert(renderContext->args->_viewFrustum);137 assert(renderContext->args->_viewFrustum);
169
170 // render transparents
171 auto& scene = sceneContext->_scene;
172 auto& items = scene->getMasterBucket().at(ItemFilter::Builder::transparentShape().withoutLayered());
173 auto& renderDetails = renderContext->args->_details;138 auto& renderDetails = renderContext->args->_details;
174
175 ItemIDsBounds inItems;
176 inItems.reserve(items.size());
177 for (auto id : items) {
178 inItems.push_back(id);
179 }
180 ItemIDsBounds& renderedItems = inItems;
181 139
182 renderContext->_numFeedTransparentItems = renderedItems.size();140 RenderArgs* args = renderContext->args;
141 gpu::Batch batch;
142 args->_batch = &batch;
143
144 renderContext->_numDrawnTransparentItems = inItems.size();
183 145
184 ItemIDsBounds culledItems;146 glm::mat4 projMat;
185 if (renderContext->_cullTransparent) {147 Transform viewMat;
186 renderDetails.pointTo(RenderDetails::TRANSLUCENT_ITEM);148 args->_viewFrustum->evalProjectionMatrix(projMat);
187 cullItems(sceneContext, renderContext, inItems, culledItems);149 args->_viewFrustum->evalViewTransform(viewMat);
188 renderDetails.pointTo(RenderDetails::OTHER_ITEM);150 if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
189 renderedItems = culledItems;151 viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
190 }152 }
153 batch.setProjectionTransform(projMat);
154 batch.setViewTransform(viewMat);
155 const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f;
191 156
192 renderContext->_numDrawnTransparentItems = renderedItems.size();157 {
193 158 GLenum buffers[3];
194 ItemIDsBounds sortedItems;159 int bufferCount = 0;
195 if (renderContext->_sortTransparent) {160 buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
196 depthSortItems(sceneContext, renderContext, false, renderedItems, sortedItems); // Sort Back to front transparent items!161 batch._glDrawBuffers(bufferCount, buffers);
197 renderedItems = sortedItems;162 args->_alphaThreshold = TRANSPARENT_ALPHA_THRESHOLD;
198 }163 }
164
165
166 renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnTransparentItems);
167
168 // Before rendering the batch make sure we re in sync with gl state
169 args->_context->syncCache();
170 args->_context->render((*args->_batch));
171 args->_batch = nullptr;
172
173 // reset blend function to standard...
174 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
175}
199 176
200 if (renderContext->_renderTransparent) {177const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() const {
201 RenderArgs* args = renderContext->args;178 if (!_opaquePipeline) {
202 gpu::Batch batch;179 auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(overlay3D_vert)));
203 args->_batch = &batch;180 auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(overlay3D_frag)));
204
205 181
182 auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
206 183
184 auto state = gpu::StatePointer(new gpu::State());
185 state->setDepthTest(true, true, gpu::LESS_EQUAL);
207 186
208 glm::mat4 projMat;187 _opaquePipeline.reset(gpu::Pipeline::create(program, state));
209 Transform viewMat;
210 args->_viewFrustum->evalProjectionMatrix(projMat);
211 args->_viewFrustum->evalViewTransform(viewMat);
212 if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
213 viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
214 }
215 batch.setProjectionTransform(projMat);
216 batch.setViewTransform(viewMat);
217
218 const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f;
219
220 {
221 GLenum buffers[3];
222 int bufferCount = 0;
223 buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
224 batch._glDrawBuffers(bufferCount, buffers);
225 args->_alphaThreshold = TRANSPARENT_ALPHA_THRESHOLD;
226 }
227
228
229 renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnTransparentItems);
230
231 // Before rendering the batch make sure we re in sync with gl state
232 args->_context->syncCache();
233 args->_context->render((*args->_batch));
234 args->_batch = nullptr;
235
236 // reset blend function to standard...
237 // glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
238 }188 }
189 return _opaquePipeline;
239}190}
240 191
241const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() const {192void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
242 if (!_opaquePipeline) {
243 auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(overlay3D_vert)));
244 auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(overlay3D_frag)));
245
246 auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
247
248 auto state = gpu::StatePointer(new gpu::State());
249 state->setDepthTest(true, true, gpu::LESS_EQUAL);
250
251 _opaquePipeline.reset(gpu::Pipeline::create(program, state));
252 }
253 return _opaquePipeline;
254}
255
256template <> void render::jobRun(const DrawOverlay3D& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
257 PerformanceTimer perfTimer("DrawOverlay3D");
258 assert(renderContext->args);193 assert(renderContext->args);
259 assert(renderContext->args->_viewFrustum);194 assert(renderContext->args->_viewFrustum);
260 195
@@ -271,13 +206,14 @@ template <> void render::jobRun(const DrawOverlay3D& job, const SceneContextPoin · 10 unmodified lines
271 inItems.emplace_back(id);206 inItems.emplace_back(id);
272 }207 }
273 }208 }
274 209 renderContext->_numFeedOverlay3DItems = inItems.size();
210 renderContext->_numDrawnOverlay3DItems = inItems.size();
211
275 RenderArgs* args = renderContext->args;212 RenderArgs* args = renderContext->args;
276 gpu::Batch batch;213 gpu::Batch batch;
277 args->_batch = &batch;214 args->_batch = &batch;
278 args->_whiteTexture = DependencyManager::get<TextureCache>()->getWhiteTexture();215 args->_whiteTexture = DependencyManager::get<TextureCache>()->getWhiteTexture();
279 216
280
281 glm::mat4 projMat;217 glm::mat4 projMat;
282 Transform viewMat;218 Transform viewMat;
283 args->_viewFrustum->evalProjectionMatrix(projMat);219 args->_viewFrustum->evalProjectionMatrix(projMat);
@@ -287,12 +223,13 @@ template <> void render::jobRun(const DrawOverlay3D& job, const SceneContextPoin · 3 unmodified lines
287 }223 }
288 batch.setProjectionTransform(projMat);224 batch.setProjectionTransform(projMat);
289 batch.setViewTransform(viewMat);225 batch.setViewTransform(viewMat);
290 batch.setPipeline(job.getOpaquePipeline());226
227 batch.setPipeline(getOpaquePipeline());
291 batch.setUniformTexture(0, args->_whiteTexture);228 batch.setUniformTexture(0, args->_whiteTexture);
292 229
293 if (!inItems.empty()) {230 if (!inItems.empty()) {
294 batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0);231 batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0);
295 renderItems(sceneContext, renderContext, inItems);232 renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnOverlay3DItems);
296 }233 }
297 234
298 // Before rendering the batch make sure we re in sync with gl state235 // Before rendering the batch make sure we re in sync with gl state
@@ -301,3 +238,4 @@ template <> void render::jobRun(const DrawOverlay3D& job, const SceneContextPoin · 2 unmodified lines
301 args->_batch = nullptr;238 args->_batch = nullptr;
302 args->_whiteTexture.reset();239 args->_whiteTexture.reset();
303}240}
241
libraries/render-utils/src/RenderDeferredTask.h+25−24
@@ -18,48 +18,49 @@ · 17 unmodified lines
18 18
19class PrepareDeferred {19class PrepareDeferred {
20public:20public:
21 void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
22
23 typedef render::Job::Model<PrepareDeferred> JobModel;
21};24};
22namespace render {25
23template <> void jobRun(const PrepareDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
24}
25 26
26class RenderDeferred {27class RenderDeferred {
27public:28public:
29 void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
30
31 typedef render::Job::Model<RenderDeferred> JobModel;
28};32};
29namespace render {
30template <> void jobRun(const RenderDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
31}
32 33
33class ResolveDeferred {34class ResolveDeferred {
34public:35public:
35};36 void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
36namespace render {
37template <> void jobRun(const ResolveDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
38}
39 37
38 typedef render::Job::Model<ResolveDeferred> JobModel;
39};
40 40
41class DrawOpaqueDeferred {41class DrawOpaqueDeferred {
42public:42public:
43 void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems);
44
45 typedef render::Job::ModelI<DrawOpaqueDeferred, render::ItemIDsBounds> JobModel;
43};46};
44namespace render {
45template <> void jobRun(const DrawOpaqueDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
46}
47 47
48class DrawTransparentDeferred {48class DrawTransparentDeferred {
49public:49public:
50 void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems);
51
52 typedef render::Job::ModelI<DrawTransparentDeferred, render::ItemIDsBounds> JobModel;
50};53};
51namespace render {54
52template <> void jobRun(const DrawTransparentDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);55class DrawOverlay3D {
53}56 mutable gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable
54 57public:
55class DrawOverlay3D {58 const gpu::PipelinePointer& getOpaquePipeline() const;
56 mutable gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable59
57public:60 void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
58 const gpu::PipelinePointer& getOpaquePipeline() const;61
62 typedef render::Job::Model<DrawOverlay3D> JobModel;
59};63};
60namespace render {
61template <> void jobRun(const DrawOverlay3D& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
62}
63 64
64class RenderDeferredTask : public render::Task {65class RenderDeferredTask : public render::Task {
65public:66public:
libraries/render-utils/src/TextRenderer.cpp+9−0
@@ -18,12 +18,21 @@ · 17 unmodified lines
18#include <QBuffer>18#include <QBuffer>
19#include <QFile>19#include <QFile>
20 20
21#ifdef __GNUC__
22#pragma GCC diagnostic push
23#pragma GCC diagnostic ignored "-Wdouble-promotion"
24#endif
25
21// FIXME, decouple from the GL headers26// FIXME, decouple from the GL headers
22#include <QOpenGLShaderProgram>27#include <QOpenGLShaderProgram>
23#include <QOpenGLTexture>28#include <QOpenGLTexture>
24#include <QOpenGLVertexArrayObject>29#include <QOpenGLVertexArrayObject>
25#include <QOpenGLBuffer>30#include <QOpenGLBuffer>
26 31
32#ifdef __GNUC__
33#pragma GCC diagnostic pop
34#endif
35
27#include <glm/glm.hpp>36#include <glm/glm.hpp>
28#include <glm/gtc/matrix_transform.hpp>37#include <glm/gtc/matrix_transform.hpp>
29 38
libraries/render-utils/src/TextRenderer3D.cpp+14−28
@@ -30,11 +30,6 @@ · 29 unmodified lines
30#include "GeometryCache.h"30#include "GeometryCache.h"
31#include "DeferredLightingEffect.h"31#include "DeferredLightingEffect.h"
32 32
33// FIXME support the shadow effect, or remove it from the API
34// FIXME figure out how to improve the anti-aliasing on the
35// interior of the outline fonts
36const float DEFAULT_POINT_SIZE = 12;
37
38// Helper functions for reading binary data from an IO device33// Helper functions for reading binary data from an IO device
39template<class T>34template<class T>
40void readStream(QIODevice& in, T& t) {35void readStream(QIODevice& in, T& t) {
@@ -117,7 +112,7 @@ public: · 76 unmodified lines
117 112
118 // Render string to batch113 // Render string to batch
119 void drawString(gpu::Batch& batch, float x, float y, const QString& str,114 void drawString(gpu::Batch& batch, float x, float y, const QString& str,
120 const glm::vec4& color, TextRenderer3D::EffectType effectType,115 const glm::vec4* color, TextRenderer3D::EffectType effectType,
121 const glm::vec2& bound);116 const glm::vec2& bound);
122 117
123private:118private:
@@ -367,7 +362,7 @@ void Font3D::setupGPU() { · 243 unmodified lines
367 }362 }
368}363}
369 364
370void Font3D::drawString(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4& color,365void Font3D::drawString(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4* color,
371 TextRenderer3D::EffectType effectType, const glm::vec2& bounds) {366 TextRenderer3D::EffectType effectType, const glm::vec2& bounds) {
372 if (str == "") {367 if (str == "") {
373 return;368 return;
@@ -429,40 +424,33 @@ void Font3D::drawString(gpu::Batch& batch, float x, float y, const QString& str, · 55 unmodified lines
429 setupGPU();424 setupGPU();
430 batch.setPipeline(_pipeline);425 batch.setPipeline(_pipeline);
431 batch.setUniformTexture(_fontLoc, _texture);426 batch.setUniformTexture(_fontLoc, _texture);
432 batch._glUniform1f(_outlineLoc, (effectType == TextRenderer3D::OUTLINE_EFFECT) ? 1.0f : 0.0f);427 batch._glUniform1i(_outlineLoc, (effectType == TextRenderer3D::OUTLINE_EFFECT));
433 batch._glUniform4fv(_colorLoc, 1, (const GLfloat*)&color);428 batch._glUniform4fv(_colorLoc, 1, (const GLfloat*)color);
434 429
435 batch.setInputFormat(_format);430 batch.setInputFormat(_format);
436 batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride);431 batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride);
437 batch.draw(gpu::QUADS, _numVertices, 0);432 batch.draw(gpu::QUADS, _numVertices, 0);
438}433}
439 434
440TextRenderer3D* TextRenderer3D::getInstance(const char* family, float pointSize,435TextRenderer3D* TextRenderer3D::getInstance(const char* family,
441 int weight, bool italic, EffectType effect, int effectThickness,436 int weight, bool italic, EffectType effect, int effectThickness) {
442 const QColor& color) {437 return new TextRenderer3D(family, weight, italic, effect, effectThickness);
443 if (pointSize < 0) {
444 pointSize = DEFAULT_POINT_SIZE;
445 }
446 return new TextRenderer3D(family, pointSize, weight, italic, effect,
447 effectThickness, color);
448}438}
449 439
450TextRenderer3D::TextRenderer3D(const char* family, float pointSize, int weight, bool italic,440TextRenderer3D::TextRenderer3D(const char* family, int weight, bool italic,
451 EffectType effect, int effectThickness, const QColor& color) :441 EffectType effect, int effectThickness) :
452 _effectType(effect),442 _effectType(effect),
453 _effectThickness(effectThickness),443 _effectThickness(effectThickness),
454 _pointSize(pointSize),
455 _color(toGlm(color)),
456 _font(loadFont3D(family)) {444 _font(loadFont3D(family)) {
457 if (!_font) {445 if (!_font) {
458 qWarning() << "Unable to load font with family " << family;446 qWarning() << "Unable to load font with family " << family;
459 _font = loadFont3D("Courier");447 _font = loadFont3D("Courier");
460 }448 }
461 if (1 != _effectThickness) {449 if (1 != _effectThickness) {
462 qWarning() << "Effect thickness not current supported";450 qWarning() << "Effect thickness not currently supported";
463 }451 }
464 if (NO_EFFECT != _effectType && OUTLINE_EFFECT != _effectType) {452 if (NO_EFFECT != _effectType && OUTLINE_EFFECT != _effectType) {
465 qWarning() << "Effect thickness not current supported";453 qWarning() << "Effect type not currently supported";
466 }454 }
467}455}
468 456
@@ -487,11 +475,9 @@ void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const QString& st · 18 unmodified lines
487 const glm::vec2& bounds) {475 const glm::vec2& bounds) {
488 // The font does all the OpenGL work476 // The font does all the OpenGL work
489 if (_font) {477 if (_font) {
490 glm::vec4 actualColor(color);478 // Cache color so that the pointer stays valid.
491 if (actualColor.r < 0) {479 _color = color;
492 actualColor = _color;480 _font->drawString(batch, x, y, str, &_color, _effectType, bounds);
493 }
494 _font->drawString(batch, x, y, str, actualColor, _effectType, bounds);
495 }481 }
496}482}
497 483
libraries/render-utils/src/TextRenderer3D.h+9−12
@@ -39,25 +39,24 @@ class Batch; · 38 unmodified lines
39class Font3D;39class Font3D;
40 40
41// TextRenderer3D is actually a fairly thin wrapper around a Font class41// TextRenderer3D is actually a fairly thin wrapper around a Font class
42// defined in the cpp file. 42// defined in the cpp file.
43class TextRenderer3D {43class TextRenderer3D {
44public:44public:
45 enum EffectType { NO_EFFECT, SHADOW_EFFECT, OUTLINE_EFFECT };45 enum EffectType { NO_EFFECT, SHADOW_EFFECT, OUTLINE_EFFECT };
46 46
47 static TextRenderer3D* getInstance(const char* family, float pointSize = -1, int weight = -1, bool italic = false,47 static TextRenderer3D* getInstance(const char* family, int weight = -1, bool italic = false,
48 EffectType effect = NO_EFFECT, int effectThickness = 1, const QColor& color = QColor(255, 255, 255));48 EffectType effect = NO_EFFECT, int effectThickness = 1);
49
50 ~TextRenderer3D();49 ~TextRenderer3D();
51 50
52 glm::vec2 computeExtent(const QString& str) const;51 glm::vec2 computeExtent(const QString& str) const;
53 float getFontSize() const;52 float getFontSize() const; // Pixel size
54 53
55 void draw(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4& color = glm::vec4(-1.0f),54 void draw(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4& color = glm::vec4(1.0f),
56 const glm::vec2& bounds = glm::vec2(-1.0f));55 const glm::vec2& bounds = glm::vec2(-1.0f));
57 56
58private:57private:
59 TextRenderer3D(const char* family, float pointSize = -1, int weight = -1, bool italic = false,58 TextRenderer3D(const char* family, int weight = -1, bool italic = false,
60 EffectType effect = NO_EFFECT, int effectThickness = 1, const QColor& color = QColor(255, 255, 255));59 EffectType effect = NO_EFFECT, int effectThickness = 1);
61 60
62 // the type of effect to apply61 // the type of effect to apply
63 const EffectType _effectType;62 const EffectType _effectType;
@@ -65,10 +64,8 @@ private: · 1 unmodified line
65 // the thickness of the effect64 // the thickness of the effect
66 const int _effectThickness;65 const int _effectThickness;
67 66
68 const float _pointSize;
69
70 // text color67 // text color
71 const glm::vec4 _color;68 glm::vec4 _color;
72 69
73 Font3D* _font;70 Font3D* _font;
74};71};
libraries/render-utils/src/sdf_text3D.slf+11−6
@@ -11,18 +11,21 @@ · 10 unmodified lines
11// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html11// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
12 12
13uniform sampler2D Font;13uniform sampler2D Font;
14uniform float Outline;14uniform bool Outline;
15uniform vec4 Color;15uniform vec4 Color;
16 16
17const float gamma = 2.6;17// the interpolated normal
18const float smoothing = 100.0;18varying vec4 interpolatedNormal;
19
20const float gamma = 2.2;
21const float smoothing = 64.0;
19const float interiorCutoff = 0.8;22const float interiorCutoff = 0.8;
20const float outlineExpansion = 0.2;23const float outlineExpansion = 0.2;
21 24
22void main() {25void main() {
23 // retrieve signed distance26 // retrieve signed distance
24 float sdf = texture2D(Font, gl_TexCoord[0].xy).g;27 float sdf = texture2D(Font, gl_TexCoord[0].xy).g;
25 if (Outline == 1.0f) {28 if (Outline) {
26 if (sdf > interiorCutoff) {29 if (sdf > interiorCutoff) {
27 sdf = 1.0 - sdf;30 sdf = 1.0 - sdf;
28 } else {31 } else {
@@ -31,7 +34,7 @@ void main() { · 2 unmodified lines
31 }34 }
32 // perform adaptive anti-aliasing of the edges35 // perform adaptive anti-aliasing of the edges
33 // The larger we're rendering, the less anti-aliasing we need36 // The larger we're rendering, the less anti-aliasing we need
34 float s = smoothing * length(fwidth(gl_TexCoord[0]));37 float s = smoothing * length(fwidth(gl_TexCoord[0].xy));
35 float w = clamp( s, 0.0, 0.5);38 float w = clamp( s, 0.0, 0.5);
36 float a = smoothstep(0.5 - w, 0.5 + w, sdf);39 float a = smoothstep(0.5 - w, 0.5 + w, sdf);
37 40
@@ -43,5 +46,7 @@ void main() { · 5 unmodified lines
43 }46 }
44 47
45 // final color48 // final color
46 gl_FragColor = vec4(Color.rgb, a);49 gl_FragData[0] = vec4(Color.rgb, Color.a * a);
50 gl_FragData[1] = vec4(interpolatedNormal.xyz, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
51 gl_FragData[2] = vec4(0.0);
47}52}
libraries/render-utils/src/sdf_text3D.slv+6−0
@@ -13,6 +13,9 @@ · 12 unmodified lines
13 13
14<$declareStandardTransform()$>14<$declareStandardTransform()$>
15 15
16// the interpolated normal
17varying vec4 interpolatedNormal;
18
16void main() {19void main() {
17 gl_TexCoord[0] = gl_MultiTexCoord0;20 gl_TexCoord[0] = gl_MultiTexCoord0;
18 21
@@ -20,4 +23,7 @@ void main() { · 1 unmodified line
20 TransformCamera cam = getTransformCamera();23 TransformCamera cam = getTransformCamera();
21 TransformObject obj = getTransformObject();24 TransformObject obj = getTransformObject();
22 <$transformModelToClipPos(cam, obj, gl_Vertex, gl_Position)$>25 <$transformModelToClipPos(cam, obj, gl_Vertex, gl_Position)$>
26 <$transformModelToEyeDir(cam, obj, gl_Normal, interpolatedNormal.xyz)$>
27
28 interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0);
23}29}
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
15uniform sampler2D colorMap;
16
17varying vec2 varTexcoord;
18varying vec4 varColor;
19
20
21void 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
19varying vec3 varPosition;
20varying vec3 varNormal;
21varying vec2 varTexcoord;
22varying vec4 varColor;
23
24void 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
9varying vec2 varTexcoord;
10varying vec3 varNomral;
11varying vec3 varPosition;
12
13
14const int star_iterations = 14;
15const float time_scale = 0.2;
16const vec3 col_star = vec3( 1.0, 0.7, 0.5 );
17
18float hash( float n ) { return fract(sin(n)*123.456789); }
19
20vec2 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
27float 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
40float 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
50vec3 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
71void 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
25using namespace render;25using namespace render;
26 26
27DrawSceneTask::DrawSceneTask() : Task() {27DrawSceneTask::DrawSceneTask() : Task() {
28
29 _jobs.push_back(Job(DrawOpaque()));
30 _jobs.push_back(Job(DrawLight()));
31 _jobs.push_back(Job(DrawTransparent()));
32 _jobs.push_back(Job(ResetGLState()));
33}28}
34 29
35DrawSceneTask::~DrawSceneTask() {30DrawSceneTask::~DrawSceneTask() {
@@ -56,8 +51,11 @@ void DrawSceneTask::run(const SceneContextPointer& sceneContext, const RenderCon · 20 unmodified lines
56Job::~Job() {51Job::~Job() {
57}52}
58 53
54
55
56
57
59void render::cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) {58void render::cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) {
60 PerformanceTimer perfTimer("cullItems");
61 assert(renderContext->args);59 assert(renderContext->args);
62 assert(renderContext->args->_viewFrustum);60 assert(renderContext->args->_viewFrustum);
63 61
@@ -68,17 +66,9 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont · 4 unmodified lines
68 renderDetails->_considered += inItems.size();66 renderDetails->_considered += inItems.size();
69 67
70 // Culling / LOD68 // Culling / LOD
71 for (auto itemDetails : inItems) {69 for (auto item : inItems) {
72 auto item = scene->getItem(itemDetails.id);70 if (item.bounds.isNull()) {
73 AABox bound;71 outItems.emplace_back(item); // One more Item to render
74 {
75 PerformanceTimer perfTimer("getBound");
76
77 bound = item.getBound();
78 }
79
80 if (bound.isNull()) {
81 outItems.emplace_back(ItemIDAndBounds(itemDetails.id)); // One more Item to render
82 continue;72 continue;
83 }73 }
84 74
@@ -87,16 +77,16 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont · 2 unmodified lines
87 bool outOfView;77 bool outOfView;
88 {78 {
89 PerformanceTimer perfTimer("boxInFrustum");79 PerformanceTimer perfTimer("boxInFrustum");
90 outOfView = args->_viewFrustum->boxInFrustum(bound) == ViewFrustum::OUTSIDE;80 outOfView = args->_viewFrustum->boxInFrustum(item.bounds) == ViewFrustum::OUTSIDE;
91 }81 }
92 if (!outOfView) {82 if (!outOfView) {
93 bool bigEnoughToRender;83 bool bigEnoughToRender;
94 {84 {
95 PerformanceTimer perfTimer("shouldRender");85 PerformanceTimer perfTimer("shouldRender");
96 bigEnoughToRender = (args->_shouldRender) ? args->_shouldRender(args, bound) : true;86 bigEnoughToRender = (args->_shouldRender) ? args->_shouldRender(args, item.bounds) : true;
97 }87 }
98 if (bigEnoughToRender) {88 if (bigEnoughToRender) {
99 outItems.emplace_back(ItemIDAndBounds(itemDetails.id, bound)); // One more Item to render89 outItems.emplace_back(item); // One more Item to render
100 } else {90 } else {
101 renderDetails->_tooSmall++;91 renderDetails->_tooSmall++;
102 }92 }
@@ -107,6 +97,32 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont · 4 unmodified lines
107 renderDetails->_rendered += outItems.size();97 renderDetails->_rendered += outItems.size();
108}98}
109 99
100
101void 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
118void 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
110struct ItemBound {126struct ItemBound {
111 float _centerDepth = 0.0f;127 float _centerDepth = 0.0f;
112 float _nearDepth = 0.0f;128 float _nearDepth = 0.0f;
@@ -130,7 +146,6 @@ struct BackToFrontSort { · 17 unmodified lines
130};146};
131 147
132void render::depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) {148void render::depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) {
133 PerformanceTimer perfTimer("depthSortItems");
134 assert(renderContext->args);149 assert(renderContext->args);
135 assert(renderContext->args->_viewFrustum);150 assert(renderContext->args->_viewFrustum);
136 151
@@ -139,9 +154,10 @@ void render::depthSortItems(const SceneContextPointer& sceneContext, const Rende · 2 unmodified lines
139 154
140 155
141 // Allocate and simply copy156 // Allocate and simply copy
157 outItems.clear();
142 outItems.reserve(inItems.size());158 outItems.reserve(inItems.size());
143 159
144 160
145 // Make a local dataset of the center distance and closest point distance161 // Make a local dataset of the center distance and closest point distance
146 std::vector<ItemBound> itemBounds;162 std::vector<ItemBound> itemBounds;
147 itemBounds.reserve(outItems.size());163 itemBounds.reserve(outItems.size());
@@ -169,8 +185,14 @@ void render::depthSortItems(const SceneContextPointer& sceneContext, const Rende · 21 unmodified lines
169 }185 }
170}186}
171 187
188
189void 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
172void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems) {195void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems) {
173 PerformanceTimer perfTimer("renderItems");
174 auto& scene = sceneContext->_scene;196 auto& scene = sceneContext->_scene;
175 RenderArgs* args = renderContext->args;197 RenderArgs* args = renderContext->args;
176 // render198 // render
@@ -183,6 +205,10 @@ void render::renderItems(const SceneContextPointer& sceneContext, const RenderCo · 6 unmodified lines
183 int numItems = 0;205 int numItems = 0;
184 for (auto itemDetails : inItems) {206 for (auto itemDetails : inItems) {
185 auto item = scene->getItem(itemDetails.id);207 auto item = scene->getItem(itemDetails.id);
208 if (numItems + 1 >= maxDrawnItems) {
209 item.render(args);
210 return;
211 }
186 item.render(args);212 item.render(args);
187 numItems++;213 numItems++;
188 if (numItems >= maxDrawnItems) {214 if (numItems >= maxDrawnItems) {
@@ -224,8 +250,7 @@ void addClearStateCommands(gpu::Batch& batch) { · 35 unmodified lines
224 // Back to no program250 // Back to no program
225 batch._glUseProgram(0);251 batch._glUseProgram(0);
226}252}
227 253void ResetGLState::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
228template <> void render::jobRun(const ResetGLState& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
229 254
230 gpu::Batch theBatch;255 gpu::Batch theBatch;
231 addClearStateCommands(theBatch);256 addClearStateCommands(theBatch);
@@ -233,160 +258,7 @@ template <> void render::jobRun(const ResetGLState& job, const SceneContextPoint · 1 unmodified line
233 renderContext->args->_context->render(theBatch);258 renderContext->args->_context->render(theBatch);
234}259}
235 260
236template <> void render::jobRun(const DrawOpaque& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {261void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
237 PerformanceTimer perfTimer("DrawOpaque");
238 assert(renderContext->args);
239 assert(renderContext->args->_viewFrustum);
240
241 // render opaques
242 auto& scene = sceneContext->_scene;
243 auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape());
244 auto& renderDetails = renderContext->args->_details;
245
246 ItemIDsBounds inItems;
247 inItems.reserve(items.size());
248 for (auto id : items) {
249 inItems.emplace_back(ItemIDAndBounds(id));
250 }
251 ItemIDsBounds& renderedItems = inItems;
252
253 renderContext->_numFeedOpaqueItems = renderedItems.size();
254
255 ItemIDsBounds culledItems;
256 culledItems.reserve(inItems.size());
257 if (renderContext->_cullOpaque) {
258 renderDetails.pointTo(RenderDetails::OPAQUE_ITEM);
259 cullItems(sceneContext, renderContext, renderedItems, culledItems);
260 renderDetails.pointTo(RenderDetails::OTHER_ITEM);
261 renderedItems = culledItems;
262 }
263
264 renderContext->_numDrawnOpaqueItems = renderedItems.size();
265
266 ItemIDsBounds sortedItems;
267 sortedItems.reserve(culledItems.size());
268 if (renderContext->_sortOpaque) {
269 depthSortItems(sceneContext, renderContext, true, renderedItems, sortedItems); // Sort Front to back opaque items!
270 renderedItems = sortedItems;
271 }
272
273 if (renderContext->_renderOpaque) {
274 RenderArgs* args = renderContext->args;
275 gpu::Batch batch;
276 args->_batch = &batch;
277
278 glm::mat4 projMat;
279 Transform viewMat;
280 args->_viewFrustum->evalProjectionMatrix(projMat);
281 args->_viewFrustum->evalViewTransform(viewMat);
282 if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
283 viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
284 }
285 batch.setProjectionTransform(projMat);
286 batch.setViewTransform(viewMat);
287
288 {
289 GLenum buffers[3];
290 int bufferCount = 0;
291 buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
292 buffers[bufferCount++] = GL_COLOR_ATTACHMENT1;
293 buffers[bufferCount++] = GL_COLOR_ATTACHMENT2;
294 batch._glDrawBuffers(bufferCount, buffers);
295 }
296
297 renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnOpaqueItems);
298
299 args->_context->render((*args->_batch));
300 args->_batch = nullptr;
301 }
302}
303
304
305template <> 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
388template <> void render::jobRun(const DrawLight& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
389 PerformanceTimer perfTimer("DrawLight");
390 assert(renderContext->args);262 assert(renderContext->args);
391 assert(renderContext->args->_viewFrustum);263 assert(renderContext->args->_viewFrustum);
392 264
@@ -398,7 +270,8 @@ template <> void render::jobRun(const DrawLight& job, const SceneContextPointer& · 5 unmodified lines
398 ItemIDsBounds inItems;270 ItemIDsBounds inItems;
399 inItems.reserve(items.size());271 inItems.reserve(items.size());
400 for (auto id : items) {272 for (auto id : items) {
401 inItems.emplace_back(id);273 auto item = scene->getItem(id);
274 inItems.emplace_back(ItemIDAndBounds(id, item.getBound()));
402 }275 }
403 276
404 ItemIDsBounds culledItems;277 ItemIDsBounds culledItems;
@@ -413,8 +286,7 @@ template <> void render::jobRun(const DrawLight& job, const SceneContextPointer& · 8 unmodified lines
413 args->_batch = nullptr;286 args->_batch = nullptr;
414}287}
415 288
416template <> void render::jobRun(const DrawBackground& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {289void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
417 PerformanceTimer perfTimer("DrawBackground");
418 assert(renderContext->args);290 assert(renderContext->args);
419 assert(renderContext->args->_viewFrustum);291 assert(renderContext->args->_viewFrustum);
420 292
@@ -450,53 +322,6 @@ template <> void render::jobRun(const DrawBackground& job, const SceneContextPoi · 29 unmodified lines
450 args->_context->syncCache();322 args->_context->syncCache();
451}323}
452 324
453template <> 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
500void ItemMaterialBucketMap::insert(const ItemID& id, const model::MaterialKey& key) {325void ItemMaterialBucketMap::insert(const ItemID& id, const model::MaterialKey& key) {
501 // Insert the itemID in every bucket where it filters true326 // Insert the itemID in every bucket where it filters true
502 for (auto& bucket : (*this)) {327 for (auto& bucket : (*this)) {
libraries/render/src/render/DrawTask.h+172−24
@@ -13,42 +13,173 @@ · 12 unmodified lines
13#define hifi_render_Task_h13#define hifi_render_Task_h
14 14
15#include "Engine.h"15#include "Engine.h"
16#include "gpu/Batch.h"
17#include <PerfStat.h>
18
16 19
17namespace render {20namespace render {
18 21
19template <class T> void jobRun(const T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { }22template <class T> void jobRun(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
23 jobModel.run(sceneContext, renderContext);
24}
25template <class T, class I> void jobRunI(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const I& input) {
26 jobModel.run(sceneContext, renderContext, input);
27}
28template <class T, class O> void jobRunO(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, O& output) {
29 jobModel.run(sceneContext, renderContext, output);
30}
31template <class T, class I, class O> void jobRunIO(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const I& input, O& output) {
32 jobModel.run(sceneContext, renderContext, input, output);
33}
20 34
21class Job {35class Job {
22public:36public:
23 37
24 template <class T> 38 // Varying represent a varying piece of data
25 Job(T data) : _concept(new Model<T>(data)) {}39 class Varying {
40 public:
41
42 Varying(const Varying& var): _concept(var._concept) {}
43
44 Varying() {}
45 template <class T>
46 Varying(const T& data) : _concept(new Job::Varying::Model<T>(data)) {}
47
48 // Access the _data contained win the concept explicitely
49 template <class T> T& edit() { return (static_cast<Model<T>*> (_concept.get())->_data); }
50 template <class T> const T& get() const { return (static_cast<const Model<T>*> (_concept.get())->_data); }
51
52 protected:
53 friend class Job;
54
55 std::vector<std::weak_ptr<Job>> _consumerJobs;
56
57 void addJobConsumer(const std::shared_ptr<Job>& job) {
58 _consumerJobs.push_back(job);
59 }
60
61 class Concept {
62 public:
63 virtual ~Concept() = default;
64 };
65 template <class T> class Model : public Concept {
66 public:
67 typedef T Data;
68 Data _data;
69 Model(const Model& source): _data(source.data) {}
70 Model(const Data& data): _data(data) {}
71 virtual ~Model() {}
72 };
73
74 std::shared_ptr<Concept> _concept;
75 };
76
26 Job(const Job& other) : _concept(other._concept) {}77 Job(const Job& other) : _concept(other._concept) {}
27 ~Job();78 ~Job();
28 79
29 virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {80 const std::string& getName() const { return _concept->getName(); }
30 if (_concept) {81 const Varying getInput() const { return _concept->getInput(); }
31 _concept->run(sceneContext, renderContext);82 const Varying getOutput() const { return _concept->getOutput(); }
32 }83
84 void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
85 PerformanceTimer perfTimer(getName().c_str());
86 PROFILE_RANGE(getName().c_str());
87 _concept->run(sceneContext, renderContext);
33 }88 }
34 89
35protected:90protected:
91public:
92
36 class Concept {93 class Concept {
94 std::string _name;
37 public:95 public:
96 Concept() : _name() {}
97 Concept(const std::string& name) : _name(name) {}
38 virtual ~Concept() = default;98 virtual ~Concept() = default;
99
100 void setName(const std::string& name) { _name = name; }
101 const std::string& getName() const { return _name; }
102
103 virtual const Varying getInput() const { return Varying(); }
104 virtual const Varying getOutput() const { return Varying(); }
39 virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) = 0;105 virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) = 0;
40 };106 };
41 107
108 Job(Concept* concept) : _concept(concept) {}
109
110public:
42 template <class T> class Model : public Concept {111 template <class T> class Model : public Concept {
43 public:112 public:
44 typedef T Data;113 typedef T Data;
45 114
46 Data _data;115 Data _data;
116
117 Model() {}
118 Model(const std::string& name): Concept(name) {}
47 Model(Data data): _data(data) {}119 Model(Data data): _data(data) {}
120 Model(Data data, const std::string& name): Concept(name), _data(data) {}
48 121
49 void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { jobRun(_data, sceneContext, renderContext); }122 void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { jobRun(_data, sceneContext, renderContext); }
50 };123 };
51 124
125 template <class T, class I> class ModelI : public Concept {
126 public:
127 typedef T Data;
128 typedef I Input;
129
130 Data _data;
131 Varying _input;
132
133 const Varying getInput() const { return _input; }
134
135 ModelI(const std::string& name, const Varying& input): Concept(name), _input(input) {}
136 ModelI(const std::string& name, Data data): Concept(name), _data(data) {}
137
138 void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { jobRunI(_data, sceneContext, renderContext, _input.get<I>()); }
139 };
140
141 template <class T, class O> class ModelO : public Concept {
142 public:
143 typedef T Data;
144 typedef O Output;
145
146 Data _data;
147 Varying _output;
148
149 const Varying getOutput() const { return _output; }
150
151 ModelO(const std::string& name): Concept(name), _output(Output()) {
152
153 }
154
155 ModelO(const std::string& name, Data data): Concept(name), _data(data), _output(Output()) {}
156
157 void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
158 jobRunO(_data, sceneContext, renderContext, _output.edit<O>());
159 }
160 };
161
162 template <class T, class I, class O> class ModelIO : public Concept {
163 public:
164 typedef T Data;
165 typedef I Input;
166 typedef O Output;
167
168 Data _data;
169 Varying _input;
170 Varying _output;
171
172 const Varying getInput() const { return _input; }
173 const Varying getOutput() const { return _output; }
174
175 ModelIO(const std::string& name, const Varying& input, Data data = Data()): Concept(name), _data(data), _input(input), _output(Output()) {}
176 ModelIO(const std::string& name, Data data, Output output): Concept(name), _data(data), _output(output) {}
177
178 void setInput(const Varying& input) { _input = input; }
179
180 void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { jobRunIO(_data, sceneContext, renderContext, _input.get<I>(), _output.edit<O>()); }
181 };
182
52 std::shared_ptr<Concept> _concept;183 std::shared_ptr<Concept> _concept;
53};184};
54 185
@@ -62,43 +193,59 @@ void depthSortItems(const SceneContextPointer& sceneContext, const RenderContext · 7 unmodified lines
62void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1);193void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1);
63 194
64 195
196class FetchItems {
197public:
198 typedef std::function<void (const RenderContextPointer& context, int count)> ProbeNumItems;
199 FetchItems(const ProbeNumItems& probe): _probeNumItems(probe) {}
200 FetchItems(const ItemFilter& filter, const ProbeNumItems& probe): _filter(filter), _probeNumItems(probe) {}
65 201
66void materialSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems);202 ItemFilter _filter = ItemFilter::Builder::opaqueShape().withoutLayered();
203 ProbeNumItems _probeNumItems;
67 204
205 void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems);
68 206
69class DrawOpaque {207 typedef Job::ModelO<FetchItems, ItemIDsBounds> JobModel;
70public:
71};208};
72template <> void jobRun(const DrawOpaque& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
73 209
210class CullItems {
211public:
212 void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems);
74 213
75class DrawTransparent {214 typedef Job::ModelIO<CullItems, ItemIDsBounds, ItemIDsBounds> JobModel;
215};
216
217class DepthSortItems {
76public:218public:
219 bool _frontToBack = true;
220
221 DepthSortItems(bool frontToBack = true) : _frontToBack(frontToBack) {}
222
223 void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outITems);
224
225 typedef Job::ModelIO<DepthSortItems, ItemIDsBounds, ItemIDsBounds> JobModel;
77};226};
78template <> void jobRun(const DrawTransparent& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
79 227
80class DrawLight {228class DrawLight {
81public:229public:
230 void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
231
232 typedef Job::Model<DrawLight> JobModel;
82};233};
83template <> void jobRun(const DrawLight& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
84 234
85class DrawBackground {235class DrawBackground {
86public:236public:
87};237 void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
88template <> void jobRun(const DrawBackground& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
89
90 238
91class DrawPostLayered {239 typedef Job::Model<DrawBackground> JobModel;
92public:
93};240};
94template <> void jobRun(const DrawPostLayered& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
95
96
97 241
98class ResetGLState {242class ResetGLState {
99public:243public:
244 void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
245
246 typedef Job::Model<ResetGLState> JobModel;
100};247};
101template <> void jobRun(const ResetGLState& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);248
102 249
103 250
104class DrawSceneTask : public Task {251class DrawSceneTask : public Task {
@@ -126,6 +273,7 @@ public: · 21 unmodified lines
126 // standard builders allocating the main buckets273 // standard builders allocating the main buckets
127 void allocateStandardMaterialBuckets();274 void allocateStandardMaterialBuckets();
128};275};
276void materialSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems);
129 277
130}278}
131 279
libraries/render/src/render/Engine.h+4−0
@@ -45,6 +45,10 @@ public: · 44 unmodified lines
45 int _numDrawnTransparentItems = 0;45 int _numDrawnTransparentItems = 0;
46 int _maxDrawnTransparentItems = -1;46 int _maxDrawnTransparentItems = -1;
47 47
48 int _numFeedOverlay3DItems = 0;
49 int _numDrawnOverlay3DItems = 0;
50 int _maxDrawnOverlay3DItems = -1;
51
48 RenderContext() {}52 RenderContext() {}
49};53};
50typedef std::shared_ptr<RenderContext> RenderContextPointer;54typedef std::shared_ptr<RenderContext> RenderContextPointer;
libraries/script-engine/src/AbstractControllerScriptingInterface.h+1−0
@@ -107,6 +107,7 @@ signals: · 106 unmodified lines
107 107
108 void mouseMoveEvent(const MouseEvent& event, unsigned int deviceID = 0);108 void mouseMoveEvent(const MouseEvent& event, unsigned int deviceID = 0);
109 void mousePressEvent(const MouseEvent& event, unsigned int deviceID = 0);109 void mousePressEvent(const MouseEvent& event, unsigned int deviceID = 0);
110 void mouseDoublePressEvent(const MouseEvent& event, unsigned int deviceID = 0);
110 void mouseReleaseEvent(const MouseEvent& event, unsigned int deviceID = 0);111 void mouseReleaseEvent(const MouseEvent& event, unsigned int deviceID = 0);
111 112
112 void touchBeginEvent(const TouchEvent& event);113 void touchBeginEvent(const TouchEvent& event);
libraries/script-engine/src/AudioScriptingInterface.cpp+1−18
@@ -46,24 +46,7 @@ ScriptAudioInjector* AudioScriptingInterface::playSound(Sound* sound, const Audi · 45 unmodified lines
46 AudioInjectorOptions optionsCopy = injectorOptions;46 AudioInjectorOptions optionsCopy = injectorOptions;
47 optionsCopy.stereo = sound->isStereo();47 optionsCopy.stereo = sound->isStereo();
48 48
49 QThread* injectorThread = new QThread();49 return new ScriptAudioInjector(AudioInjector::playSound(sound->getByteArray(), optionsCopy, _localAudioInterface));
50 injectorThread->setObjectName("Audio Injector Thread");
51
52 AudioInjector* injector = new AudioInjector(sound, optionsCopy);
53 injector->setLocalAudioInterface(_localAudioInterface);
54
55 injector->moveToThread(injectorThread);
56
57 // start injecting when the injector thread starts
58 connect(injectorThread, &QThread::started, injector, &AudioInjector::injectAudio);
59
60 // connect the right slots and signals for AudioInjector and thread cleanup
61 connect(injector, &AudioInjector::destroyed, injectorThread, &QThread::quit);
62 connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater);
63
64 injectorThread->start();
65
66 return new ScriptAudioInjector(injector);
67 50
68 } else {51 } else {
69 qCDebug(scriptengine) << "AudioScriptingInterface::playSound called with null Sound object.";52 qCDebug(scriptengine) << "AudioScriptingInterface::playSound called with null Sound object.";
libraries/script-engine/src/SceneScriptingInterface.cpp+2−0
@@ -159,4 +159,6 @@ void SceneScriptingInterface::clearEngineCounters() { · 158 unmodified lines
159 _numDrawnOpaqueItems = 0;159 _numDrawnOpaqueItems = 0;
160 _numFeedTransparentItems = 0;160 _numFeedTransparentItems = 0;
161 _numDrawnTransparentItems = 0;161 _numDrawnTransparentItems = 0;
162 _numFeedOverlay3DItems = 0;
163 _numDrawnOverlay3DItems = 0;
162}164}
libraries/script-engine/src/SceneScriptingInterface.h+9−1
@@ -90,17 +90,22 @@ public: · 89 unmodified lines
90 Q_INVOKABLE int getEngineNumDrawnOpaqueItems() { return _numDrawnOpaqueItems; }90 Q_INVOKABLE int getEngineNumDrawnOpaqueItems() { return _numDrawnOpaqueItems; }
91 void setEngineDrawnTransparentItems(int count) { _numDrawnTransparentItems = count; }91 void setEngineDrawnTransparentItems(int count) { _numDrawnTransparentItems = count; }
92 Q_INVOKABLE int getEngineNumDrawnTransparentItems() { return _numDrawnTransparentItems; }92 Q_INVOKABLE int getEngineNumDrawnTransparentItems() { return _numDrawnTransparentItems; }
93 void setEngineDrawnOverlay3DItems(int count) { _numDrawnOverlay3DItems = count; }
94 Q_INVOKABLE int getEngineNumDrawnOverlay3DItems() { return _numDrawnOverlay3DItems; }
93 95
94 void setEngineFeedOpaqueItems(int count) { _numFeedOpaqueItems = count; }96 void setEngineFeedOpaqueItems(int count) { _numFeedOpaqueItems = count; }
95 Q_INVOKABLE int getEngineNumFeedOpaqueItems() { return _numFeedOpaqueItems; }97 Q_INVOKABLE int getEngineNumFeedOpaqueItems() { return _numFeedOpaqueItems; }
96 void setEngineFeedTransparentItems(int count) { _numFeedTransparentItems = count; }98 void setEngineFeedTransparentItems(int count) { _numFeedTransparentItems = count; }
97 Q_INVOKABLE int getEngineNumFeedTransparentItems() { return _numFeedTransparentItems; }99 Q_INVOKABLE int getEngineNumFeedTransparentItems() { return _numFeedTransparentItems; }
100 void setEngineFeedOverlay3DItems(int count) { _numFeedOverlay3DItems = count; }
101 Q_INVOKABLE int getEngineNumFeedOverlay3DItems() { return _numFeedOverlay3DItems; }
98 102
99 Q_INVOKABLE void setEngineMaxDrawnOpaqueItems(int count) { _maxDrawnOpaqueItems = count; }103 Q_INVOKABLE void setEngineMaxDrawnOpaqueItems(int count) { _maxDrawnOpaqueItems = count; }
100 Q_INVOKABLE int getEngineMaxDrawnOpaqueItems() { return _maxDrawnOpaqueItems; }104 Q_INVOKABLE int getEngineMaxDrawnOpaqueItems() { return _maxDrawnOpaqueItems; }
101 Q_INVOKABLE void setEngineMaxDrawnTransparentItems(int count) { _maxDrawnTransparentItems = count; }105 Q_INVOKABLE void setEngineMaxDrawnTransparentItems(int count) { _maxDrawnTransparentItems = count; }
102 Q_INVOKABLE int getEngineMaxDrawnTransparentItems() { return _maxDrawnTransparentItems; }106 Q_INVOKABLE int getEngineMaxDrawnTransparentItems() { return _maxDrawnTransparentItems; }
103 107 Q_INVOKABLE void setEngineMaxDrawnOverlay3DItems(int count) { _maxDrawnOverlay3DItems = count; }
108 Q_INVOKABLE int getEngineMaxDrawnOverlay3DItems() { return _maxDrawnOverlay3DItems; }
104signals:109signals:
105 void shouldRenderAvatarsChanged(bool shouldRenderAvatars);110 void shouldRenderAvatarsChanged(bool shouldRenderAvatars);
106 void shouldRenderEntitiesChanged(bool shouldRenderEntities);111 void shouldRenderEntitiesChanged(bool shouldRenderEntities);
@@ -124,9 +129,12 @@ protected: · 17 unmodified lines
124 int _numDrawnOpaqueItems = 0;129 int _numDrawnOpaqueItems = 0;
125 int _numFeedTransparentItems = 0;130 int _numFeedTransparentItems = 0;
126 int _numDrawnTransparentItems = 0;131 int _numDrawnTransparentItems = 0;
132 int _numFeedOverlay3DItems = 0;
133 int _numDrawnOverlay3DItems = 0;
127 134
128 int _maxDrawnOpaqueItems = -1;135 int _maxDrawnOpaqueItems = -1;
129 int _maxDrawnTransparentItems = -1;136 int _maxDrawnTransparentItems = -1;
137 int _maxDrawnOverlay3DItems = -1;
130 138
131};139};
132 140
libraries/script-engine/src/ScriptEngine.cpp+4−1
@@ -317,7 +317,10 @@ void ScriptEngine::init() { · 316 unmodified lines
317 registerAnimationTypes(this);317 registerAnimationTypes(this);
318 registerAvatarTypes(this);318 registerAvatarTypes(this);
319 registerAudioMetaTypes(this);319 registerAudioMetaTypes(this);
320 _controllerScriptingInterface->registerControllerTypes(this);320
321 if (_controllerScriptingInterface) {
322 _controllerScriptingInterface->registerControllerTypes(this);
323 }
321 324
322 qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly);325 qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly);
323 qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue);326 qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue);
libraries/script-engine/src/ScriptEngine.h+1−1
@@ -35,7 +35,7 @@ · 34 unmodified lines
35 35
36const QString NO_SCRIPT("");36const QString NO_SCRIPT("");
37 37
38const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0 / 60.0f) * 1000 * 1000) + 0.5);38const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0f / 60.0f) * 1000 * 1000) + 0.5f);
39 39
40typedef QHash<QString, QScriptValueList> RegisteredEventHandlers;40typedef QHash<QString, QScriptValueList> RegisteredEventHandlers;
41 41
libraries/script-engine/src/TouchEvent.cpp+13−13
@@ -40,7 +40,7 @@ TouchEvent::TouchEvent() : · 39 unmodified lines
40 isRotating(false),40 isRotating(false),
41 rotating("none")41 rotating("none")
42{42{
43 43
44}44}
45 45
46TouchEvent::TouchEvent(const QTouchEvent& event) :46TouchEvent::TouchEvent(const QTouchEvent& event) :
@@ -77,9 +77,9 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) { · 30 unmodified lines
77 touchPoints = tPoints.count();77 touchPoints = tPoints.count();
78 if (touchPoints > 1) {78 if (touchPoints > 1) {
79 for (int i = 0; i < touchPoints; ++i) {79 for (int i = 0; i < touchPoints; ++i) {
80 touchAvgX += tPoints[i].pos().x();80 touchAvgX += (float)tPoints[i].pos().x();
81 touchAvgY += tPoints[i].pos().y();81 touchAvgY += (float)tPoints[i].pos().y();
82 82
83 // add it to our points vector83 // add it to our points vector
84 glm::vec2 thisPoint(tPoints[i].pos().x(), tPoints[i].pos().y());84 glm::vec2 thisPoint(tPoints[i].pos().x(), tPoints[i].pos().y());
85 points << thisPoint;85 points << thisPoint;
@@ -94,7 +94,7 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) { · 8 unmodified lines
94 }94 }
95 x = touchAvgX;95 x = touchAvgX;
96 y = touchAvgY;96 y = touchAvgY;
97 97
98 // after calculating the center point (average touch point), determine the maximum radius98 // after calculating the center point (average touch point), determine the maximum radius
99 // also calculate the rotation angle for each point99 // also calculate the rotation angle for each point
100 float maxRadius = 0.0f;100 float maxRadius = 0.0f;
@@ -105,25 +105,25 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) { · 4 unmodified lines
105 if (thisRadius > maxRadius) {105 if (thisRadius > maxRadius) {
106 maxRadius = thisRadius;106 maxRadius = thisRadius;
107 }107 }
108 108
109 // calculate the angle for this point109 // calculate the angle for this point
110 float thisAngle = angleBetweenPoints(center,touchPoint);110 float thisAngle = angleBetweenPoints(center,touchPoint);
111 angles << thisAngle;111 angles << thisAngle;
112 }112 }
113 radius = maxRadius;113 radius = maxRadius;
114 114
115 // after calculating the angles for each touch point, determine the average angle115 // after calculating the angles for each touch point, determine the average angle
116 float totalAngle = 0.0f;116 float totalAngle = 0.0f;
117 for (int i = 0; i < touchPoints; ++i) {117 for (int i = 0; i < touchPoints; ++i) {
118 totalAngle += angles[i];118 totalAngle += angles[i];
119 }119 }
120 angle = totalAngle/(float)touchPoints;120 angle = totalAngle/(float)touchPoints;
121 121
122 isPressed = event.touchPointStates().testFlag(Qt::TouchPointPressed);122 isPressed = event.touchPointStates().testFlag(Qt::TouchPointPressed);
123 isMoved = event.touchPointStates().testFlag(Qt::TouchPointMoved);123 isMoved = event.touchPointStates().testFlag(Qt::TouchPointMoved);
124 isStationary = event.touchPointStates().testFlag(Qt::TouchPointStationary);124 isStationary = event.touchPointStates().testFlag(Qt::TouchPointStationary);
125 isReleased = event.touchPointStates().testFlag(Qt::TouchPointReleased);125 isReleased = event.touchPointStates().testFlag(Qt::TouchPointReleased);
126 126
127 // keyboard modifiers127 // keyboard modifiers
128 isShifted = event.modifiers().testFlag(Qt::ShiftModifier);128 isShifted = event.modifiers().testFlag(Qt::ShiftModifier);
129 isMeta = event.modifiers().testFlag(Qt::MetaModifier);129 isMeta = event.modifiers().testFlag(Qt::MetaModifier);
@@ -143,7 +143,7 @@ void TouchEvent::calculateMetaAttributes(const TouchEvent& other) { · 13 unmodified lines
143 isPinching = other.isPinching;143 isPinching = other.isPinching;
144 isPinchOpening = other.isPinchOpening;144 isPinchOpening = other.isPinchOpening;
145 }145 }
146 146
147 // determine if the points are rotating...147 // determine if the points are rotating...
148 // note: if the number of touch points change between events, then we don't consider ourselves to be rotating148 // note: if the number of touch points change between events, then we don't consider ourselves to be rotating
149 if (touchPoints == other.touchPoints) {149 if (touchPoints == other.touchPoints) {
@@ -178,7 +178,7 @@ QScriptValue TouchEvent::toScriptValue(QScriptEngine* engine, const TouchEvent& · 28 unmodified lines
178 obj.setProperty("isControl", event.isControl);178 obj.setProperty("isControl", event.isControl);
179 obj.setProperty("isAlt", event.isAlt);179 obj.setProperty("isAlt", event.isAlt);
180 obj.setProperty("touchPoints", event.touchPoints);180 obj.setProperty("touchPoints", event.touchPoints);
181 181
182 QScriptValue pointsObj = engine->newArray();182 QScriptValue pointsObj = engine->newArray();
183 int index = 0;183 int index = 0;
184 foreach (glm::vec2 point, event.points) {184 foreach (glm::vec2 point, event.points) {
@@ -190,7 +190,7 @@ QScriptValue TouchEvent::toScriptValue(QScriptEngine* engine, const TouchEvent& · 5 unmodified lines
190 obj.setProperty("radius", event.radius);190 obj.setProperty("radius", event.radius);
191 obj.setProperty("isPinching", event.isPinching);191 obj.setProperty("isPinching", event.isPinching);
192 obj.setProperty("isPinchOpening", event.isPinchOpening);192 obj.setProperty("isPinchOpening", event.isPinchOpening);
193 193
194 obj.setProperty("angle", event.angle);194 obj.setProperty("angle", event.angle);
195 obj.setProperty("deltaAngle", event.deltaAngle);195 obj.setProperty("deltaAngle", event.deltaAngle);
196 QScriptValue anglesObj = engine->newArray();196 QScriptValue anglesObj = engine->newArray();
@@ -200,7 +200,7 @@ QScriptValue TouchEvent::toScriptValue(QScriptEngine* engine, const TouchEvent& · 3 unmodified lines
200 index++;200 index++;
201 }201 }
202 obj.setProperty("angles", anglesObj);202 obj.setProperty("angles", anglesObj);
203 203
204 obj.setProperty("isRotating", event.isRotating);204 obj.setProperty("isRotating", event.isRotating);
205 obj.setProperty("rotating", event.rotating);205 obj.setProperty("rotating", event.rotating);
206 return obj;206 return obj;
libraries/shared/CMakeLists.txt+2−1
@@ -6,4 +6,5 @@ setup_hifi_library(Gui Network Script Widgets) · 5 unmodified lines
6 6
7add_dependency_external_projects(glm)7add_dependency_external_projects(glm)
8find_package(GLM REQUIRED)8find_package(GLM REQUIRED)
9target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})9target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
10
libraries/shared/src/AABox.cpp+38−38
@@ -16,20 +16,20 @@ · 15 unmodified lines
16#include "GeometryUtil.h"16#include "GeometryUtil.h"
17#include "NumericalConstants.h"17#include "NumericalConstants.h"
18 18
19AABox::AABox(const AACube& other) : 19AABox::AABox(const AACube& other) :
20 _corner(other.getCorner()), _scale(other.getScale(), other.getScale(), other.getScale()) {20 _corner(other.getCorner()), _scale(other.getScale(), other.getScale(), other.getScale()) {
21}21}
22 22
23AABox::AABox(const Extents& other) : 23AABox::AABox(const Extents& other) :
24 _corner(other.minimum),24 _corner(other.minimum),
25 _scale(other.maximum - other.minimum) {25 _scale(other.maximum - other.minimum) {
26}26}
27 27
28AABox::AABox(const glm::vec3& corner, float size) : 28AABox::AABox(const glm::vec3& corner, float size) :
29 _corner(corner), _scale(size, size, size) {29 _corner(corner), _scale(size, size, size) {
30};30};
31 31
32AABox::AABox(const glm::vec3& corner, const glm::vec3& dimensions) : 32AABox::AABox(const glm::vec3& corner, const glm::vec3& dimensions) :
33 _corner(corner), _scale(dimensions) {33 _corner(corner), _scale(dimensions) {
34};34};
35 35
@@ -39,7 +39,7 @@ AABox::AABox() : _corner(std::numeric_limits<float>::infinity()), _scale(0.0f) { · 3 unmodified lines
39glm::vec3 AABox::calcCenter() const {39glm::vec3 AABox::calcCenter() const {
40 glm::vec3 center(_corner);40 glm::vec3 center(_corner);
41 center += (_scale * 0.5f);41 center += (_scale * 0.5f);
42 return center; 42 return center;
43}43}
44 44
45void AABox::scale(float scale) {45void AABox::scale(float scale) {
@@ -134,12 +134,12 @@ bool AABox::contains(const AABox& otherBox) const { · 88 unmodified lines
134 134
135bool AABox::touches(const AABox& otherBox) const {135bool AABox::touches(const AABox& otherBox) const {
136 glm::vec3 relativeCenter = _corner - otherBox._corner + ((_scale - otherBox._scale) * 0.5f);136 glm::vec3 relativeCenter = _corner - otherBox._corner + ((_scale - otherBox._scale) * 0.5f);
137 137
138 glm::vec3 totalHalfScale = (_scale + otherBox._scale) * 0.5f;138 glm::vec3 totalHalfScale = (_scale + otherBox._scale) * 0.5f;
139 139
140 return fabs(relativeCenter.x) <= totalHalfScale.x && 140 return fabsf(relativeCenter.x) <= totalHalfScale.x &&
141 fabs(relativeCenter.y) <= totalHalfScale.y && 141 fabsf(relativeCenter.y) <= totalHalfScale.y &&
142 fabs(relativeCenter.z) <= totalHalfScale.z;142 fabsf(relativeCenter.z) <= totalHalfScale.z;
143}143}
144 144
145bool AABox::contains(const AACube& otherCube) const {145bool AABox::contains(const AACube& otherCube) const {
@@ -154,12 +154,12 @@ bool AABox::contains(const AACube& otherCube) const { · 8 unmodified lines
154 154
155bool AABox::touches(const AACube& otherCube) const {155bool AABox::touches(const AACube& otherCube) const {
156 glm::vec3 relativeCenter = _corner - otherCube.getCorner() + ((_scale - otherCube.getDimensions()) * 0.5f);156 glm::vec3 relativeCenter = _corner - otherCube.getCorner() + ((_scale - otherCube.getDimensions()) * 0.5f);
157 157
158 glm::vec3 totalHalfScale = (_scale + otherCube.getDimensions()) * 0.5f;158 glm::vec3 totalHalfScale = (_scale + otherCube.getDimensions()) * 0.5f;
159 159
160 return fabs(relativeCenter.x) <= totalHalfScale.x && 160 return fabsf(relativeCenter.x) <= totalHalfScale.x &&
161 fabs(relativeCenter.y) <= totalHalfScale.y && 161 fabsf(relativeCenter.y) <= totalHalfScale.y &&
162 fabs(relativeCenter.z) <= totalHalfScale.z;162 fabsf(relativeCenter.z) <= totalHalfScale.z;
163}163}
164 164
165// determines whether a value is within the expanded extents165// determines whether a value is within the expanded extents
@@ -244,14 +244,14 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct · 78 unmodified lines
244 isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale.y) &&244 isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale.y) &&
245 isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x))) {245 isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x))) {
246 distance = axisDistance;246 distance = axisDistance;
247 face = direction.z > 0 ? MAX_Z_FACE : MIN_Z_FACE; 247 face = direction.z > 0 ? MAX_Z_FACE : MIN_Z_FACE;
248 return true;248 return true;
249 }249 }
250 // This case is unexpected, but mimics the previous behavior for inside out intersections250 // This case is unexpected, but mimics the previous behavior for inside out intersections
251 distance = 0;251 distance = 0;
252 return true;252 return true;
253 }253 }
254 254
255 // check each axis255 // check each axis
256 float axisDistance;256 float axisDistance;
257 if ((findIntersection(origin.x, direction.x, _corner.x, _scale.x, axisDistance) && axisDistance >= 0 &&257 if ((findIntersection(origin.x, direction.x, _corner.x, _scale.x, axisDistance) && axisDistance >= 0 &&
@@ -272,7 +272,7 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct · 14 unmodified lines
272 isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale.y) &&272 isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale.y) &&
273 isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x))) {273 isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x))) {
274 distance = axisDistance;274 distance = axisDistance;
275 face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE; 275 face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE;
276 return true;276 return true;
277 }277 }
278 return false;278 return false;
@@ -280,7 +280,7 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct · 1 unmodified line
280 280
281bool AABox::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const {281bool AABox::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const {
282 glm::vec4 center4 = glm::vec4(center, 1.0f);282 glm::vec4 center4 = glm::vec4(center, 1.0f);
283 283
284 float minPenetrationLength = FLT_MAX;284 float minPenetrationLength = FLT_MAX;
285 for (int i = 0; i < FACE_COUNT; i++) {285 for (int i = 0; i < FACE_COUNT; i++) {
286 glm::vec4 facePlane = getPlane((BoxFace)i);286 glm::vec4 facePlane = getPlane((BoxFace)i);
@@ -297,7 +297,7 @@ bool AABox::findSpherePenetration(const glm::vec3& center, float radius, glm::ve · 10 unmodified lines
297 minPenetrationLength = vectorLength;297 minPenetrationLength = vectorLength;
298 }298 }
299 }299 }
300 300
301 return true;301 return true;
302}302}
303 303
@@ -305,7 +305,7 @@ bool AABox::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, · 1 unmodified line
305 glm::vec4 start4 = glm::vec4(start, 1.0f);305 glm::vec4 start4 = glm::vec4(start, 1.0f);
306 glm::vec4 end4 = glm::vec4(end, 1.0f);306 glm::vec4 end4 = glm::vec4(end, 1.0f);
307 glm::vec4 startToEnd = glm::vec4(end - start, 0.0f);307 glm::vec4 startToEnd = glm::vec4(end - start, 0.0f);
308 308
309 float minPenetrationLength = FLT_MAX;309 float minPenetrationLength = FLT_MAX;
310 for (int i = 0; i < FACE_COUNT; i++) {310 for (int i = 0; i < FACE_COUNT; i++) {
311 // find the vector from the segment to the closest point on the face (starting from deeper end)311 // find the vector from the segment to the closest point on the face (starting from deeper end)
@@ -324,8 +324,8 @@ bool AABox::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, · 12 unmodified lines
324 vector * ((vectorLength + radius) / -vectorLength);324 vector * ((vectorLength + radius) / -vectorLength);
325 minPenetrationLength = vectorLength;325 minPenetrationLength = vectorLength;
326 }326 }
327 } 327 }
328 328
329 return true;329 return true;
330}330}
331 331
@@ -334,23 +334,23 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec3& point, BoxFace face) con · 2 unmodified lines
334 case MIN_X_FACE:334 case MIN_X_FACE:
335 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),335 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
336 glm::vec3(_corner.x, _corner.y + _scale.y, _corner.z + _scale.z));336 glm::vec3(_corner.x, _corner.y + _scale.y, _corner.z + _scale.z));
337 337
338 case MAX_X_FACE:338 case MAX_X_FACE:
339 return glm::clamp(point, glm::vec3(_corner.x + _scale.x, _corner.y, _corner.z),339 return glm::clamp(point, glm::vec3(_corner.x + _scale.x, _corner.y, _corner.z),
340 glm::vec3(_corner.x + _scale.x, _corner.y + _scale.y, _corner.z + _scale.z));340 glm::vec3(_corner.x + _scale.x, _corner.y + _scale.y, _corner.z + _scale.z));
341 341
342 case MIN_Y_FACE:342 case MIN_Y_FACE:
343 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),343 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
344 glm::vec3(_corner.x + _scale.x, _corner.y, _corner.z + _scale.z));344 glm::vec3(_corner.x + _scale.x, _corner.y, _corner.z + _scale.z));
345 345
346 case MAX_Y_FACE:346 case MAX_Y_FACE:
347 return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _scale.y, _corner.z),347 return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _scale.y, _corner.z),
348 glm::vec3(_corner.x + _scale.x, _corner.y + _scale.y, _corner.z + _scale.z));348 glm::vec3(_corner.x + _scale.x, _corner.y + _scale.y, _corner.z + _scale.z));
349 349
350 case MIN_Z_FACE:350 case MIN_Z_FACE:
351 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),351 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
352 glm::vec3(_corner.x + _scale.z, _corner.y + _scale.y, _corner.z));352 glm::vec3(_corner.x + _scale.z, _corner.y + _scale.y, _corner.z));
353 353
354 default: //quiet windows warnings354 default: //quiet windows warnings
355 case MAX_Z_FACE:355 case MAX_Z_FACE:
356 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _scale.z),356 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _scale.z),
@@ -373,7 +373,7 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& · 16 unmodified lines
373 }373 }
374 anyOutside = true;374 anyOutside = true;
375 float divisor = glm::dot(direction, iPlane);375 float divisor = glm::dot(direction, iPlane);
376 if (fabs(divisor) < EPSILON) {376 if (fabsf(divisor) < EPSILON) {
377 continue; // segment is parallel to plane377 continue; // segment is parallel to plane
378 }378 }
379 // find intersection and see if it lies within face bounds379 // find intersection and see if it lies within face bounds
@@ -389,29 +389,29 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& · 9 unmodified lines
389 }389 }
390 }390 }
391 return getClosestPointOnFace(glm::vec3(intersection), face);391 return getClosestPointOnFace(glm::vec3(intersection), face);
392 392
393 outerContinue: ;393 outerContinue: ;
394 }394 }
395 395
396 // if we were outside any of the sides, we must check against the diagonals396 // if we were outside any of the sides, we must check against the diagonals
397 if (anyOutside) {397 if (anyOutside) {
398 int faceAxis = face / 2;398 int faceAxis = face / 2;
399 int secondAxis = (faceAxis + 1) % 3;399 int secondAxis = (faceAxis + 1) % 3;
400 int thirdAxis = (faceAxis + 2) % 3;400 int thirdAxis = (faceAxis + 2) % 3;
401 401
402 glm::vec4 secondAxisMinPlane = getPlane((BoxFace)(secondAxis * 2));402 glm::vec4 secondAxisMinPlane = getPlane((BoxFace)(secondAxis * 2));
403 glm::vec4 secondAxisMaxPlane = getPlane((BoxFace)(secondAxis * 2 + 1));403 glm::vec4 secondAxisMaxPlane = getPlane((BoxFace)(secondAxis * 2 + 1));
404 glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1));404 glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1));
405 405
406 glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f,406 glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f,
407 glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), _scale) * 0.5f);407 glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), _scale) * 0.5f);
408 glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset,408 glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset,
409 secondAxisMaxPlane + thirdAxisMaxPlane + offset };409 secondAxisMaxPlane + thirdAxisMaxPlane + offset };
410 410
411 float minDistance = FLT_MAX;411 float minDistance = FLT_MAX;
412 for (size_t i = 0; i < sizeof(diagonals) / sizeof(diagonals[0]); i++) {412 for (size_t i = 0; i < sizeof(diagonals) / sizeof(diagonals[0]); i++) {
413 float divisor = glm::dot(direction, diagonals[i]);413 float divisor = glm::dot(direction, diagonals[i]);
414 if (fabs(divisor) < EPSILON) {414 if (fabsf(divisor) < EPSILON) {
415 continue; // segment is parallel to diagonal plane415 continue; // segment is parallel to diagonal plane
416 }416 }
417 minDistance = glm::min(-glm::dot(origin, diagonals[i]) / divisor, minDistance);417 minDistance = glm::min(-glm::dot(origin, diagonals[i]) / divisor, minDistance);
@@ -420,7 +420,7 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& · 2 unmodified lines
420 return getClosestPointOnFace(glm::vec3(origin + direction * minDistance), face);420 return getClosestPointOnFace(glm::vec3(origin + direction * minDistance), face);
421 }421 }
422 }422 }
423 423
424 // last resort or all inside: clamp origin to face424 // last resort or all inside: clamp origin to face
425 return getClosestPointOnFace(glm::vec3(origin), face);425 return getClosestPointOnFace(glm::vec3(origin), face);
426}426}
@@ -453,7 +453,7 @@ AABox AABox::clamp(const glm::vec3& min, const glm::vec3& max) const { · 26 unmodified lines
453 glm::vec3 clampedCorner = glm::clamp(_corner, min, max);453 glm::vec3 clampedCorner = glm::clamp(_corner, min, max);
454 glm::vec3 clampedTopFarLeft = glm::clamp(calcTopFarLeft(), min, max);454 glm::vec3 clampedTopFarLeft = glm::clamp(calcTopFarLeft(), min, max);
455 glm::vec3 clampedScale = clampedTopFarLeft - clampedCorner;455 glm::vec3 clampedScale = clampedTopFarLeft - clampedCorner;
456 456
457 return AABox(clampedCorner, clampedScale);457 return AABox(clampedCorner, clampedScale);
458}458}
459 459
@@ -461,7 +461,7 @@ AABox AABox::clamp(float min, float max) const { · 1 unmodified line
461 glm::vec3 clampedCorner = glm::clamp(_corner, min, max);461 glm::vec3 clampedCorner = glm::clamp(_corner, min, max);
462 glm::vec3 clampedTopFarLeft = glm::clamp(calcTopFarLeft(), min, max);462 glm::vec3 clampedTopFarLeft = glm::clamp(calcTopFarLeft(), min, max);
463 glm::vec3 clampedScale = clampedTopFarLeft - clampedCorner;463 glm::vec3 clampedScale = clampedTopFarLeft - clampedCorner;
464 464
465 return AABox(clampedCorner, clampedScale);465 return AABox(clampedCorner, clampedScale);
466}466}
467 467
libraries/shared/src/AACube.cpp+35−35
@@ -21,14 +21,14 @@ AACube::AACube(const AABox& other) : · 20 unmodified lines
21 _corner(other.getCorner()), _scale(other.getLargestDimension()) {21 _corner(other.getCorner()), _scale(other.getLargestDimension()) {
22}22}
23 23
24AACube::AACube(const Extents& other) : 24AACube::AACube(const Extents& other) :
25 _corner(other.minimum) 25 _corner(other.minimum)
26{26{
27 glm::vec3 dimensions = other.maximum - other.minimum;27 glm::vec3 dimensions = other.maximum - other.minimum;
28 _scale = glm::max(dimensions.x, dimensions.y, dimensions.z);28 _scale = glm::max(dimensions.x, dimensions.y, dimensions.z);
29}29}
30 30
31AACube::AACube(const glm::vec3& corner, float size) : 31AACube::AACube(const glm::vec3& corner, float size) :
32 _corner(corner), _scale(size) {32 _corner(corner), _scale(size) {
33};33};
34 34
@@ -38,13 +38,13 @@ AACube::AACube() : _corner(0,0,0), _scale(0) { · 3 unmodified lines
38glm::vec3 AACube::calcCenter() const {38glm::vec3 AACube::calcCenter() const {
39 glm::vec3 center(_corner);39 glm::vec3 center(_corner);
40 center += (glm::vec3(_scale, _scale, _scale) * 0.5f);40 center += (glm::vec3(_scale, _scale, _scale) * 0.5f);
41 return center; 41 return center;
42}42}
43 43
44glm::vec3 AACube::calcTopFarLeft() const { 44glm::vec3 AACube::calcTopFarLeft() const {
45 glm::vec3 topFarLeft(_corner);45 glm::vec3 topFarLeft(_corner);
46 topFarLeft += glm::vec3(_scale, _scale, _scale);46 topFarLeft += glm::vec3(_scale, _scale, _scale);
47 return topFarLeft; 47 return topFarLeft;
48};48};
49 49
50void AACube::scale(float scale) {50void AACube::scale(float scale) {
@@ -135,9 +135,9 @@ bool AACube::contains(const AACube& otherCube) const { · 84 unmodified lines
135bool AACube::touches(const AACube& otherCube) const {135bool AACube::touches(const AACube& otherCube) const {
136 glm::vec3 relativeCenter = _corner - otherCube._corner + (glm::vec3(_scale - otherCube._scale) * 0.5f);136 glm::vec3 relativeCenter = _corner - otherCube._corner + (glm::vec3(_scale - otherCube._scale) * 0.5f);
137 float totalHalfScale = 0.5f * (_scale + otherCube._scale);137 float totalHalfScale = 0.5f * (_scale + otherCube._scale);
138 return fabs(relativeCenter.x) <= totalHalfScale && 138 return fabsf(relativeCenter.x) <= totalHalfScale &&
139 fabs(relativeCenter.y) <= totalHalfScale && 139 fabsf(relativeCenter.y) <= totalHalfScale &&
140 fabs(relativeCenter.z) <= totalHalfScale;140 fabsf(relativeCenter.z) <= totalHalfScale;
141}141}
142 142
143bool AACube::contains(const AABox& otherBox) const {143bool AACube::contains(const AABox& otherBox) const {
@@ -154,10 +154,10 @@ bool AACube::touches(const AABox& otherBox) const { · 10 unmodified lines
154 glm::vec3 myDimensions = glm::vec3(_scale);154 glm::vec3 myDimensions = glm::vec3(_scale);
155 glm::vec3 relativeCenter = _corner - otherBox.getCorner() + ((myDimensions - otherBox.getScale()) * 0.5f);155 glm::vec3 relativeCenter = _corner - otherBox.getCorner() + ((myDimensions - otherBox.getScale()) * 0.5f);
156 glm::vec3 totalHalfScale = (myDimensions + otherBox.getDimensions()) * 0.5f;156 glm::vec3 totalHalfScale = (myDimensions + otherBox.getDimensions()) * 0.5f;
157 157
158 return fabs(relativeCenter.x) <= totalHalfScale.x && 158 return fabsf(relativeCenter.x) <= totalHalfScale.x &&
159 fabs(relativeCenter.y) <= totalHalfScale.y && 159 fabsf(relativeCenter.y) <= totalHalfScale.y &&
160 fabs(relativeCenter.z) <= totalHalfScale.z;160 fabsf(relativeCenter.z) <= totalHalfScale.z;
161}161}
162 162
163// determines whether a value is within the expanded extents163// 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
222bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const {222bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const {
223 // handle the trivial case where the box contains the origin223 // handle the trivial case where the box contains the origin
224 if (contains(origin)) {224 if (contains(origin)) {
225 225
226 // We still want to calculate the distance from the origin to the inside out plane226 // We still want to calculate the distance from the origin to the inside out plane
227 float axisDistance;227 float axisDistance;
228 if ((findInsideOutIntersection(origin.x, direction.x, _corner.x, _scale, axisDistance) && axisDistance >= 0 &&228 if ((findInsideOutIntersection(origin.x, direction.x, _corner.x, _scale, axisDistance) && axisDistance >= 0 &&
@@ -243,14 +243,14 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc · 14 unmodified lines
243 isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) &&243 isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) &&
244 isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) {244 isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) {
245 distance = axisDistance;245 distance = axisDistance;
246 face = direction.z > 0 ? MAX_Z_FACE : MIN_Z_FACE; 246 face = direction.z > 0 ? MAX_Z_FACE : MIN_Z_FACE;
247 return true;247 return true;
248 }248 }
249 // This case is unexpected, but mimics the previous behavior for inside out intersections249 // This case is unexpected, but mimics the previous behavior for inside out intersections
250 distance = 0;250 distance = 0;
251 return true;251 return true;
252 }252 }
253 253
254 // check each axis254 // check each axis
255 float axisDistance;255 float axisDistance;
256 if ((findIntersection(origin.x, direction.x, _corner.x, _scale, axisDistance) && axisDistance >= 0 &&256 if ((findIntersection(origin.x, direction.x, _corner.x, _scale, axisDistance) && axisDistance >= 0 &&
@@ -271,7 +271,7 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc · 14 unmodified lines
271 isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) &&271 isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) &&
272 isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) {272 isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) {
273 distance = axisDistance;273 distance = axisDistance;
274 face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE; 274 face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE;
275 return true;275 return true;
276 }276 }
277 return false;277 return false;
@@ -279,7 +279,7 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc · 1 unmodified line
279 279
280bool AACube::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const {280bool AACube::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const {
281 glm::vec4 center4 = glm::vec4(center, 1.0f);281 glm::vec4 center4 = glm::vec4(center, 1.0f);
282 282
283 float minPenetrationLength = FLT_MAX;283 float minPenetrationLength = FLT_MAX;
284 for (int i = 0; i < FACE_COUNT; i++) {284 for (int i = 0; i < FACE_COUNT; i++) {
285 glm::vec4 facePlane = getPlane((BoxFace)i);285 glm::vec4 facePlane = getPlane((BoxFace)i);
@@ -296,7 +296,7 @@ bool AACube::findSpherePenetration(const glm::vec3& center, float radius, glm::v · 10 unmodified lines
296 minPenetrationLength = vectorLength;296 minPenetrationLength = vectorLength;
297 }297 }
298 }298 }
299 299
300 return true;300 return true;
301}301}
302 302
@@ -304,7 +304,7 @@ bool AACube::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end · 1 unmodified line
304 glm::vec4 start4 = glm::vec4(start, 1.0f);304 glm::vec4 start4 = glm::vec4(start, 1.0f);
305 glm::vec4 end4 = glm::vec4(end, 1.0f);305 glm::vec4 end4 = glm::vec4(end, 1.0f);
306 glm::vec4 startToEnd = glm::vec4(end - start, 0.0f);306 glm::vec4 startToEnd = glm::vec4(end - start, 0.0f);
307 307
308 float minPenetrationLength = FLT_MAX;308 float minPenetrationLength = FLT_MAX;
309 for (int i = 0; i < FACE_COUNT; i++) {309 for (int i = 0; i < FACE_COUNT; i++) {
310 // find the vector from the segment to the closest point on the face (starting from deeper end)310 // find the vector from the segment to the closest point on the face (starting from deeper end)
@@ -323,8 +323,8 @@ bool AACube::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end · 12 unmodified lines
323 vector * ((vectorLength + radius) / -vectorLength);323 vector * ((vectorLength + radius) / -vectorLength);
324 minPenetrationLength = vectorLength;324 minPenetrationLength = vectorLength;
325 }325 }
326 } 326 }
327 327
328 return true;328 return true;
329}329}
330 330
@@ -333,23 +333,23 @@ glm::vec3 AACube::getClosestPointOnFace(const glm::vec3& point, BoxFace face) co · 2 unmodified lines
333 case MIN_X_FACE:333 case MIN_X_FACE:
334 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),334 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
335 glm::vec3(_corner.x, _corner.y + _scale, _corner.z + _scale));335 glm::vec3(_corner.x, _corner.y + _scale, _corner.z + _scale));
336 336
337 case MAX_X_FACE:337 case MAX_X_FACE:
338 return glm::clamp(point, glm::vec3(_corner.x + _scale, _corner.y, _corner.z),338 return glm::clamp(point, glm::vec3(_corner.x + _scale, _corner.y, _corner.z),
339 glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale));339 glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale));
340 340
341 case MIN_Y_FACE:341 case MIN_Y_FACE:
342 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),342 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
343 glm::vec3(_corner.x + _scale, _corner.y, _corner.z + _scale));343 glm::vec3(_corner.x + _scale, _corner.y, _corner.z + _scale));
344 344
345 case MAX_Y_FACE:345 case MAX_Y_FACE:
346 return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _scale, _corner.z),346 return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _scale, _corner.z),
347 glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale));347 glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale));
348 348
349 case MIN_Z_FACE:349 case MIN_Z_FACE:
350 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),350 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
351 glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z));351 glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z));
352 352
353 default: //quiet windows warnings353 default: //quiet windows warnings
354 case MAX_Z_FACE:354 case MAX_Z_FACE:
355 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _scale),355 return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _scale),
@@ -372,7 +372,7 @@ glm::vec3 AACube::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4 · 16 unmodified lines
372 }372 }
373 anyOutside = true;373 anyOutside = true;
374 float divisor = glm::dot(direction, iPlane);374 float divisor = glm::dot(direction, iPlane);
375 if (fabs(divisor) < EPSILON) {375 if (fabsf(divisor) < EPSILON) {
376 continue; // segment is parallel to plane376 continue; // segment is parallel to plane
377 }377 }
378 // find intersection and see if it lies within face bounds378 // find intersection and see if it lies within face bounds
@@ -388,29 +388,29 @@ glm::vec3 AACube::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4 · 9 unmodified lines
388 }388 }
389 }389 }
390 return getClosestPointOnFace(glm::vec3(intersection), face);390 return getClosestPointOnFace(glm::vec3(intersection), face);
391 391
392 outerContinue: ;392 outerContinue: ;
393 }393 }
394 394
395 // if we were outside any of the sides, we must check against the diagonals395 // if we were outside any of the sides, we must check against the diagonals
396 if (anyOutside) {396 if (anyOutside) {
397 int faceAxis = face / 2;397 int faceAxis = face / 2;
398 int secondAxis = (faceAxis + 1) % 3;398 int secondAxis = (faceAxis + 1) % 3;
399 int thirdAxis = (faceAxis + 2) % 3;399 int thirdAxis = (faceAxis + 2) % 3;
400 400
401 glm::vec4 secondAxisMinPlane = getPlane((BoxFace)(secondAxis * 2));401 glm::vec4 secondAxisMinPlane = getPlane((BoxFace)(secondAxis * 2));
402 glm::vec4 secondAxisMaxPlane = getPlane((BoxFace)(secondAxis * 2 + 1));402 glm::vec4 secondAxisMaxPlane = getPlane((BoxFace)(secondAxis * 2 + 1));
403 glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1));403 glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1));
404 404
405 glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f,405 glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f,
406 glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), glm::vec3(_scale, _scale, _scale)) * 0.5f);406 glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), glm::vec3(_scale, _scale, _scale)) * 0.5f);
407 glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset,407 glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset,
408 secondAxisMaxPlane + thirdAxisMaxPlane + offset };408 secondAxisMaxPlane + thirdAxisMaxPlane + offset };
409 409
410 float minDistance = FLT_MAX;410 float minDistance = FLT_MAX;
411 for (size_t i = 0; i < sizeof(diagonals) / sizeof(diagonals[0]); i++) {411 for (size_t i = 0; i < sizeof(diagonals) / sizeof(diagonals[0]); i++) {
412 float divisor = glm::dot(direction, diagonals[i]);412 float divisor = glm::dot(direction, diagonals[i]);
413 if (fabs(divisor) < EPSILON) {413 if (fabsf(divisor) < EPSILON) {
414 continue; // segment is parallel to diagonal plane414 continue; // segment is parallel to diagonal plane
415 }415 }
416 minDistance = glm::min(-glm::dot(origin, diagonals[i]) / divisor, minDistance);416 minDistance = glm::min(-glm::dot(origin, diagonals[i]) / divisor, minDistance);
@@ -419,7 +419,7 @@ glm::vec3 AACube::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4 · 2 unmodified lines
419 return getClosestPointOnFace(glm::vec3(origin + direction * minDistance), face);419 return getClosestPointOnFace(glm::vec3(origin + direction * minDistance), face);
420 }420 }
421 }421 }
422 422
423 // last resort or all inside: clamp origin to face423 // last resort or all inside: clamp origin to face
424 return getClosestPointOnFace(glm::vec3(origin), face);424 return getClosestPointOnFace(glm::vec3(origin), face);
425}425}
libraries/shared/src/AngularConstraint.cpp+1−1
@@ -120,7 +120,7 @@ bool HingeConstraint::clamp(glm::quat& rotation) const { · 119 unmodified lines
120 forward /= length;120 forward /= length;
121 float sign = (glm::dot(glm::cross(_forwardAxis, forward), _rotationAxis) > 0.0f ? 1.0f : -1.0f);121 float sign = (glm::dot(glm::cross(_forwardAxis, forward), _rotationAxis) > 0.0f ? 1.0f : -1.0f);
122 //float angle = sign * acos(glm::dot(forward, _forwardAxis) / length);122 //float angle = sign * acos(glm::dot(forward, _forwardAxis) / length);
123 float angle = sign * acos(glm::dot(forward, _forwardAxis));123 float angle = sign * acosf(glm::dot(forward, _forwardAxis));
124 glm::quat newRotation = glm::angleAxis(clampAngle(angle, _minAngle, _maxAngle), _rotationAxis);124 glm::quat newRotation = glm::angleAxis(clampAngle(angle, _minAngle, _maxAngle), _rotationAxis);
125 if (fabsf(1.0f - glm::dot(newRotation, rotation)) > EPSILON * EPSILON) {125 if (fabsf(1.0f - glm::dot(newRotation, rotation)) > EPSILON * EPSILON) {
126 rotation = newRotation;126 rotation = newRotation;
libraries/shared/src/GLMHelpers.cpp+1−1
@@ -238,7 +238,7 @@ glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) { · 237 unmodified lines
238 float sd10 = previous[0][1] * previous[2][2] - previous[2][1] * previous[0][2];238 float sd10 = previous[0][1] * previous[2][2] - previous[2][1] * previous[0][2];
239 float sd20 = previous[0][1] * previous[1][2] - previous[1][1] * previous[0][2];239 float sd20 = previous[0][1] * previous[1][2] - previous[1][1] * previous[0][2];
240 float det = previous[0][0] * sd00 + previous[2][0] * sd20 - previous[1][0] * sd10;240 float det = previous[0][0] * sd00 + previous[2][0] * sd20 - previous[1][0] * sd10;
241 if (fabs(det) == 0.0f) {241 if (fabsf(det) == 0.0f) {
242 // determinant is zero; matrix is not invertible242 // determinant is zero; matrix is not invertible
243 break;243 break;
244 }244 }
libraries/shared/src/GLMHelpers.h+24−0
@@ -28,10 +28,19 @@ using glm::vec3; · 27 unmodified lines
28using glm::vec4;28using glm::vec4;
29using glm::quat;29using glm::quat;
30 30
31#ifdef __GNUC__
32#pragma GCC diagnostic push
33#pragma GCC diagnostic ignored "-Wdouble-promotion"
34#endif
35
31#include <QtCore/QByteArray>36#include <QtCore/QByteArray>
32#include <QtGui/QMatrix4x4>37#include <QtGui/QMatrix4x4>
33#include <QtGui/QColor>38#include <QtGui/QColor>
34 39
40#ifdef __GNUC__
41#pragma GCC diagnostic pop
42#endif
43
35#include "SharedUtil.h"44#include "SharedUtil.h"
36 45
37// this is where the coordinate system is represented46// this is where the coordinate system is represented
@@ -122,6 +131,21 @@ float aspect(const T& t) { · 84 unmodified lines
122 return (float)t.x / (float)t.y;131 return (float)t.x / (float)t.y;
123}132}
124 133
134// Take values in an arbitrary range [0, size] and convert them to the range [0, 1]
135template <typename T>
136T 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]
141template <typename T>
142T toNormalizedDeviceScale(const T& value, const T& size) {
143 vec2 result = toUnitScale(value, size);
144 result *= 2.0f;
145 result -= 1.0f;
146 return result;
147}
148
125#define YAW(euler) euler.y149#define YAW(euler) euler.y
126#define PITCH(euler) euler.x150#define PITCH(euler) euler.x
127#define ROLL(euler) euler.z151#define ROLL(euler) euler.z
libraries/shared/src/MatrixStack.h+5−1
@@ -118,11 +118,15 @@ public: · 117 unmodified lines
118 118
119 template <typename Function>119 template <typename Function>
120 void withPush(Function f) {120 void withPush(Function f) {
121 #ifndef NDEBUG
121 size_t startingDepth = size();122 size_t startingDepth = size();
123 #endif
122 push();124 push();
123 f();125 f();
124 pop();126 pop();
125 assert(startingDepth = size());127 #ifndef NDEBUG
128 assert(startingDepth == size());
129 #endif
126 }130 }
127 131
128 template <typename Function>132 template <typename Function>
libraries/shared/src/OctalCode.cpp+33−33
@@ -47,7 +47,7 @@ void printOctalCode(const unsigned char* octalCode) { · 46 unmodified lines
47 47
48char sectionValue(const unsigned char* startByte, char startIndexInByte) {48char sectionValue(const unsigned char* startByte, char startIndexInByte) {
49 char rightShift = 8 - startIndexInByte - 3;49 char rightShift = 8 - startIndexInByte - 3;
50 50
51 if (rightShift < 0) {51 if (rightShift < 0) {
52 return ((startByte[0] << -rightShift) & 7) + (startByte[1] >> (8 + rightShift));52 return ((startByte[0] << -rightShift) & 7) + (startByte[1] >> (8 + rightShift));
53 } else {53 } else {
@@ -65,7 +65,7 @@ size_t bytesRequiredForCodeLength(unsigned char threeBitCodes) { · 11 unmodified lines
65 65
66int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsigned char* descendantOctalCode) {66int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsigned char* descendantOctalCode) {
67 int parentSections = numberOfThreeBitSectionsInCode(ancestorOctalCode);67 int parentSections = numberOfThreeBitSectionsInCode(ancestorOctalCode);
68 68
69 int branchStartBit = parentSections * 3;69 int branchStartBit = parentSections * 3;
70 // Note: this does not appear to be "multi-byte length code" safe. When octal codes are larger than 255 bytes70 // Note: this does not appear to be "multi-byte length code" safe. When octal codes are larger than 255 bytes
71 // long, the length code is stored in two bytes. The "1" below appears to assume that the length is always one71 // long, the length code is stored in two bytes. The "1" below appears to assume that the length is always one
@@ -74,45 +74,45 @@ int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsi · 2 unmodified lines
74}74}
75 75
76unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNumber) {76unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNumber) {
77 77
78 // find the length (in number of three bit code sequences)78 // find the length (in number of three bit code sequences)
79 // in the parent79 // in the parent
80 int parentCodeSections = parentOctalCode80 int parentCodeSections = parentOctalCode
81 ? numberOfThreeBitSectionsInCode(parentOctalCode)81 ? numberOfThreeBitSectionsInCode(parentOctalCode)
82 : 0;82 : 0;
83 83
84 // get the number of bytes used by the parent octal code84 // get the number of bytes used by the parent octal code
85 size_t parentCodeBytes = bytesRequiredForCodeLength(parentCodeSections);85 size_t parentCodeBytes = bytesRequiredForCodeLength(parentCodeSections);
86 86
87 // child code will have one more section than the parent87 // child code will have one more section than the parent
88 size_t childCodeBytes = bytesRequiredForCodeLength(parentCodeSections + 1);88 size_t childCodeBytes = bytesRequiredForCodeLength(parentCodeSections + 1);
89 89
90 // create a new buffer to hold the new octal code90 // create a new buffer to hold the new octal code
91 unsigned char* newCode = new unsigned char[childCodeBytes];91 unsigned char* newCode = new unsigned char[childCodeBytes];
92 92
93 // copy the parent code to the child93 // copy the parent code to the child
94 if (parentOctalCode) {94 if (parentOctalCode) {
95 memcpy(newCode, parentOctalCode, parentCodeBytes);95 memcpy(newCode, parentOctalCode, parentCodeBytes);
96 } 96 }
97 97
98 // the child octal code has one more set of three bits98 // the child octal code has one more set of three bits
99 *newCode = parentCodeSections + 1;99 *newCode = parentCodeSections + 1;
100 100
101 if (childCodeBytes > parentCodeBytes) {101 if (childCodeBytes > parentCodeBytes) {
102 // we have a new byte due to the addition of the child code102 // we have a new byte due to the addition of the child code
103 // so set it to zero for correct results when shifting later103 // so set it to zero for correct results when shifting later
104 newCode[childCodeBytes - 1] = 0;104 newCode[childCodeBytes - 1] = 0;
105 }105 }
106 106
107 // add the child code bits to newCode107 // add the child code bits to newCode
108 108
109 // find the start bit index109 // find the start bit index
110 int startBit = parentCodeSections * 3;110 int startBit = parentCodeSections * 3;
111 111
112 // calculate the amount of left shift required112 // calculate the amount of left shift required
113 // this will be -1 or -2 if there's wrap113 // this will be -1 or -2 if there's wrap
114 char leftShift = 8 - (startBit % 8) - 3;114 char leftShift = 8 - (startBit % 8) - 3;
115 115
116 if (leftShift < 0) {116 if (leftShift < 0) {
117 // we have a wrap-around to accomodate117 // we have a wrap-around to accomodate
118 // right shift for the end of first byte118 // right shift for the end of first byte
@@ -123,7 +123,7 @@ unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNu · 4 unmodified lines
123 // no wraparound, left shift and add123 // no wraparound, left shift and add
124 newCode[(startBit / 8) + 1] += (childNumber << leftShift);124 newCode[(startBit / 8) + 1] += (childNumber << leftShift);
125 }125 }
126 126
127 return newCode;127 return newCode;
128}128}
129 129
@@ -135,9 +135,9 @@ void voxelDetailsForCode(const unsigned char* octalCode, VoxelPositionSize& voxe · 5 unmodified lines
135 if (octalCode) {135 if (octalCode) {
136 for (int i = 0; i < numberOfThreeBitSectionsInCode(octalCode); i++) {136 for (int i = 0; i < numberOfThreeBitSectionsInCode(octalCode); i++) {
137 currentScale *= 0.5f;137 currentScale *= 0.5f;
138 int sectionIndex = sectionValue(octalCode + 1 + (BITS_IN_OCTAL * i / BITS_IN_BYTE), 138 int sectionIndex = sectionValue(octalCode + 1 + (BITS_IN_OCTAL * i / BITS_IN_BYTE),
139 (BITS_IN_OCTAL * i) % BITS_IN_BYTE);139 (BITS_IN_OCTAL * i) % BITS_IN_BYTE);
140 140
141 for (int j = 0; j < BITS_IN_OCTAL; j++) {141 for (int j = 0; j < BITS_IN_OCTAL; j++) {
142 output[j] += currentScale * (float)oneAtBit(sectionIndex, (BITS_IN_BYTE - BITS_IN_OCTAL) + j);142 output[j] += currentScale * (float)oneAtBit(sectionIndex, (BITS_IN_BYTE - BITS_IN_OCTAL) + j);
143 }143 }
@@ -151,17 +151,17 @@ void voxelDetailsForCode(const unsigned char* octalCode, VoxelPositionSize& voxe · 7 unmodified lines
151 151
152void copyFirstVertexForCode(const unsigned char* octalCode, float* output) {152void copyFirstVertexForCode(const unsigned char* octalCode, float* output) {
153 memset(output, 0, 3 * sizeof(float));153 memset(output, 0, 3 * sizeof(float));
154 154
155 float currentScale = 0.5f;155 float currentScale = 0.5f;
156 156
157 for (int i = 0; i < numberOfThreeBitSectionsInCode(octalCode); i++) {157 for (int i = 0; i < numberOfThreeBitSectionsInCode(octalCode); i++) {
158 int sectionIndex = sectionValue(octalCode + 1 + (3 * i / 8), (3 * i) % 8);158 int sectionIndex = sectionValue(octalCode + 1 + (3 * i / 8), (3 * i) % 8);
159 159
160 for (int j = 0; j < 3; j++) {160 for (int j = 0; j < 3; j++) {
161 output[j] += currentScale * (int)oneAtBit(sectionIndex, 5 + j);161 output[j] += currentScale * (int)oneAtBit(sectionIndex, 5 + j);
162 }162 }
163 163
164 currentScale *= 0.5;164 currentScale *= 0.5f;
165 }165 }
166}166}
167 167
@@ -171,7 +171,7 @@ OctalCodeComparison compareOctalCodes(const unsigned char* codeA, const unsigned · 3 unmodified lines
171 }171 }
172 172
173 OctalCodeComparison result = LESS_THAN; // assume it's shallower173 OctalCodeComparison result = LESS_THAN; // assume it's shallower
174 174
175 size_t numberOfBytes = std::min(bytesRequiredForCodeLength(*codeA), bytesRequiredForCodeLength(*codeB));175 size_t numberOfBytes = std::min(bytesRequiredForCodeLength(*codeA), bytesRequiredForCodeLength(*codeB));
176 int compare = memcmp(codeA, codeB, numberOfBytes);176 int compare = memcmp(codeA, codeB, numberOfBytes);
177 177
@@ -205,7 +205,7 @@ char getOctalCodeSectionValue(const unsigned char* octalCode, int section) { · 27 unmodified lines
205 int startAtByte = 1 + (BITS_IN_OCTAL * section / BITS_IN_BYTE);205 int startAtByte = 1 + (BITS_IN_OCTAL * section / BITS_IN_BYTE);
206 char startIndexInByte = (BITS_IN_OCTAL * section) % BITS_IN_BYTE;206 char startIndexInByte = (BITS_IN_OCTAL * section) % BITS_IN_BYTE;
207 const unsigned char* startByte = octalCode + startAtByte;207 const unsigned char* startByte = octalCode + startAtByte;
208 208
209 return sectionValue(startByte, startIndexInByte);209 return sectionValue(startByte, startIndexInByte);
210}210}
211 211
@@ -227,7 +227,7 @@ void setOctalCodeSectionValue(unsigned char* octalCode, int section, char sectio · 15 unmodified lines
227 unsigned char oldValue = *byteAt & ~shiftedMask;227 unsigned char oldValue = *byteAt & ~shiftedMask;
228 unsigned char newValue = oldValue | shiftedValue;228 unsigned char newValue = oldValue | shiftedValue;
229 *byteAt = newValue;229 *byteAt = newValue;
230 230
231 // If the requested section is partially in the byte, then we231 // If the requested section is partially in the byte, then we
232 // need to also set the portion of the section value in the next byte232 // need to also set the portion of the section value in the next byte
233 // there's only two cases where this happens, if the bit in byte is233 // there's only two cases where this happens, if the bit in byte is
@@ -255,7 +255,7 @@ unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLev · 21 unmodified lines
255 int newLength = codeLength - chopLevels;255 int newLength = codeLength - chopLevels;
256 newCode = new unsigned char[newLength+1];256 newCode = new unsigned char[newLength+1];
257 *newCode = newLength; // set the length byte257 *newCode = newLength; // set the length byte
258 258
259 for (int section = chopLevels; section < codeLength; section++) {259 for (int section = chopLevels; section < codeLength; section++) {
260 char sectionValue = getOctalCodeSectionValue(originalOctalCode, section);260 char sectionValue = getOctalCodeSectionValue(originalOctalCode, section);
261 setOctalCodeSectionValue(newCode, section - chopLevels, sectionValue);261 setOctalCodeSectionValue(newCode, section - chopLevels, sectionValue);
@@ -264,9 +264,9 @@ unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLev · 2 unmodified lines
264 return newCode;264 return newCode;
265}265}
266 266
267unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode, 267unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode,
268 bool includeColorSpace) {268 bool includeColorSpace) {
269 269
270 int oldCodeLength = numberOfThreeBitSectionsInCode(originalOctalCode);270 int oldCodeLength = numberOfThreeBitSectionsInCode(originalOctalCode);
271 int newParentCodeLength = numberOfThreeBitSectionsInCode(newParentOctalCode);271 int newParentCodeLength = numberOfThreeBitSectionsInCode(newParentOctalCode);
272 int newCodeLength = newParentCodeLength + oldCodeLength;272 int newCodeLength = newParentCodeLength + oldCodeLength;
@@ -298,12 +298,12 @@ bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* po · 25 unmodified lines
298 }298 }
299 299
300 int descendentCodeLength = numberOfThreeBitSectionsInCode(possibleDescendent);300 int descendentCodeLength = numberOfThreeBitSectionsInCode(possibleDescendent);
301 301
302 // if the caller also include a child, then our descendent length is actually one extra!302 // if the caller also include a child, then our descendent length is actually one extra!
303 if (descendentsChild != CHECK_NODE_ONLY) {303 if (descendentsChild != CHECK_NODE_ONLY) {
304 descendentCodeLength++;304 descendentCodeLength++;
305 }305 }
306 306
307 if (ancestorCodeLength > descendentCodeLength) {307 if (ancestorCodeLength > descendentCodeLength) {
308 return false; // if the descendent is shorter, it can't be a descendent308 return false; // if the descendent is shorter, it can't be a descendent
309 }309 }
@@ -322,7 +322,7 @@ bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* po · 12 unmodified lines
322 return false; // first non-match, means they don't match322 return false; // first non-match, means they don't match
323 }323 }
324 }324 }
325 325
326 // they all match, so we are an ancestor326 // they all match, so we are an ancestor
327 return true;327 return true;
328}328}
@@ -335,7 +335,7 @@ unsigned char* hexStringToOctalCode(const QString& input) { · 6 unmodified lines
335 335
336 // allocate byte array based on half of string length336 // allocate byte array based on half of string length
337 unsigned char* bytes = new unsigned char[(input.length()) / HEX_BYTE_SIZE];337 unsigned char* bytes = new unsigned char[(input.length()) / HEX_BYTE_SIZE];
338 338
339 // loop through the string - 2 bytes at a time converting339 // loop through the string - 2 bytes at a time converting
340 // it to decimal equivalent and store in byte array340 // it to decimal equivalent and store in byte array
341 bool ok = false;341 bool ok = false;
@@ -348,7 +348,7 @@ unsigned char* hexStringToOctalCode(const QString& input) { · 6 unmodified lines
348 stringIndex += HEX_BYTE_SIZE;348 stringIndex += HEX_BYTE_SIZE;
349 byteArrayIndex++;349 byteArrayIndex++;
350 }350 }
351 351
352 // something went wrong352 // something went wrong
353 if (!ok) {353 if (!ok) {
354 delete[] bytes;354 delete[] bytes;
libraries/shared/src/PhysicsCollisionGroups.h+1−1
@@ -55,7 +55,7 @@ const int16_t COLLISION_GROUP_COLLISIONLESS = 1 << 15; · 54 unmodified lines
55const int16_t COLLISION_MASK_DEFAULT = ~ COLLISION_GROUP_COLLISIONLESS;55const int16_t COLLISION_MASK_DEFAULT = ~ COLLISION_GROUP_COLLISIONLESS;
56 56
57// STATIC also doesn't collide with other STATIC57// STATIC also doesn't collide with other STATIC
58const int16_t COLLISION_MASK_STATIC = ~ (COLLISION_GROUP_COLLISIONLESS | COLLISION_MASK_STATIC);58const int16_t COLLISION_MASK_STATIC = ~ (COLLISION_GROUP_COLLISIONLESS | COLLISION_GROUP_STATIC);
59 59
60const int16_t COLLISION_MASK_KINEMATIC = COLLISION_MASK_DEFAULT;60const int16_t COLLISION_MASK_KINEMATIC = COLLISION_MASK_DEFAULT;
61 61
libraries/shared/src/RegisteredMetaTypes.cpp+12−0
@@ -20,6 +20,7 @@ · 19 unmodified lines
20 20
21static int vec4MetaTypeId = qRegisterMetaType<glm::vec4>();21static int vec4MetaTypeId = qRegisterMetaType<glm::vec4>();
22static int vec3MetaTypeId = qRegisterMetaType<glm::vec3>();22static int vec3MetaTypeId = qRegisterMetaType<glm::vec3>();
23static int qVectorVec3MetaTypeId = qRegisterMetaType<QVector<glm::vec3>>();
23static int vec2MetaTypeId = qRegisterMetaType<glm::vec2>();24static int vec2MetaTypeId = qRegisterMetaType<glm::vec2>();
24static int quatMetaTypeId = qRegisterMetaType<glm::quat>();25static int quatMetaTypeId = qRegisterMetaType<glm::quat>();
25static int xColorMetaTypeId = qRegisterMetaType<xColor>();26static int xColorMetaTypeId = qRegisterMetaType<xColor>();
@@ -31,6 +32,7 @@ static int collisionMetaTypeId = qRegisterMetaType<Collision>(); · 5 unmodified lines
31void registerMetaTypes(QScriptEngine* engine) {32void registerMetaTypes(QScriptEngine* engine) {
32 qScriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue);33 qScriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue);
33 qScriptRegisterMetaType(engine, vec3toScriptValue, vec3FromScriptValue);34 qScriptRegisterMetaType(engine, vec3toScriptValue, vec3FromScriptValue);
35 qScriptRegisterMetaType(engine, qVectorVec3ToScriptValue, qVectorVec3FromScriptValue);
34 qScriptRegisterMetaType(engine, vec2toScriptValue, vec2FromScriptValue);36 qScriptRegisterMetaType(engine, vec2toScriptValue, vec2FromScriptValue);
35 qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue);37 qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue);
36 qScriptRegisterMetaType(engine, qRectToScriptValue, qRectFromScriptValue);38 qScriptRegisterMetaType(engine, qRectToScriptValue, qRectFromScriptValue);
@@ -93,6 +95,16 @@ QVector<glm::vec3> qVectorVec3FromScriptValue(const QScriptValue& array){ · 56 unmodified lines
93 return newVector;95 return newVector;
94}96}
95 97
98void 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
96QScriptValue vec2toScriptValue(QScriptEngine* engine, const glm::vec2 &vec2) {108QScriptValue vec2toScriptValue(QScriptEngine* engine, const glm::vec2 &vec2) {
97 QScriptValue obj = engine->newObject();109 QScriptValue obj = engine->newObject();
98 obj.setProperty("x", vec2.x);110 obj.setProperty("x", vec2.x);
libraries/shared/src/RegisteredMetaTypes.h+1−0
@@ -57,6 +57,7 @@ QScriptValue qURLToScriptValue(QScriptEngine* engine, const QUrl& url); · 56 unmodified lines
57void qURLFromScriptValue(const QScriptValue& object, QUrl& url);57void qURLFromScriptValue(const QScriptValue& object, QUrl& url);
58 58
59QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector<glm::vec3>& vector);59QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector<glm::vec3>& vector);
60void qVectorVec3FromScriptValue(const QScriptValue& array, QVector<glm::vec3>& vector);
60QVector<glm::vec3> qVectorVec3FromScriptValue( const QScriptValue& array);61QVector<glm::vec3> qVectorVec3FromScriptValue( const QScriptValue& array);
61 62
62class PickRay {63class 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
881 faceNormal = glm::vec3(0.0f, 0.0f, signs.z);881 faceNormal = glm::vec3(0.0f, 0.0f, signs.z);
882 }882 }
883 883
884 if (fabs(glm::dot(faceNormal, capsuleAxis)) < EPSILON) {884 if (fabsf(glm::dot(faceNormal, capsuleAxis)) < EPSILON) {
885 if (glm::dot(nearestApproach, faceNormal) > cubeB->getScale() + capsuleA->getRadius()) {885 if (glm::dot(nearestApproach, faceNormal) > cubeB->getScale() + capsuleA->getRadius()) {
886 return false;886 return false;
887 }887 }
libraries/shared/src/Transform.h+2−2
@@ -29,7 +29,7 @@ inline bool isValidScale(glm::vec3 scale) { · 28 unmodified lines
29}29}
30 30
31inline bool isValidScale(float scale) {31inline bool isValidScale(float scale) {
32 bool result = scale != 0.0f;32 bool result = scale != 0.0f && !glm::isnan(scale) && !glm::isinf(scale);
33 assert(result);33 assert(result);
34 return result;34 return result;
35}35}
@@ -323,7 +323,7 @@ inline void Transform::setScale(const Vec3& scale) { · 287 unmodified lines
323}323}
324 324
325inline void Transform::postScale(float scale) {325inline void Transform::postScale(float scale) {
326 if (isValidScale(scale) || scale == 1.0f) {326 if (!isValidScale(scale) || scale == 1.0f) {
327 return;327 return;
328 }328 }
329 if (isScaling()) {329 if (isScaling()) {
libraries/shared/src/VariantMapToScriptValue.cpp+39−13
@@ -13,35 +13,61 @@ · 12 unmodified lines
13#include "SharedLogging.h"13#include "SharedLogging.h"
14#include "VariantMapToScriptValue.h"14#include "VariantMapToScriptValue.h"
15 15
16QScriptValue variantMapToScriptValue(QVariantMap& variantMap, QScriptEngine& scriptEngine) {
17 QScriptValue scriptValue = scriptEngine.newObject();
18
19 for (QVariantMap::const_iterator iter = variantMap.begin(); iter != variantMap.end(); ++iter) {
20 QString key = iter.key();
21 QVariant qValue = iter.value();
22 16
23 switch(qValue.type()) {17QScriptValue variantToScriptValue(QVariant& qValue, QScriptEngine& scriptEngine) {
18 switch(qValue.type()) {
24 case QVariant::Bool:19 case QVariant::Bool:
25 scriptValue.setProperty(key, qValue.toBool());20 return qValue.toBool();
26 break;21 break;
27 case QVariant::Int:22 case QVariant::Int:
28 scriptValue.setProperty(key, qValue.toInt());23 return qValue.toInt();
29 break;24 break;
30 case QVariant::Double:25 case QVariant::Double:
31 scriptValue.setProperty(key, qValue.toDouble());26 return qValue.toDouble();
32 break;27 break;
33 case QVariant::String: {28 case QVariant::String: {
34 scriptValue.setProperty(key, scriptEngine.newVariant(qValue));29 return scriptEngine.newVariant(qValue);
35 break;30 break;
36 }31 }
37 case QVariant::Map: {32 case QVariant::Map: {
38 QVariantMap childMap = qValue.toMap();33 QVariantMap childMap = qValue.toMap();
39 scriptValue.setProperty(key, variantMapToScriptValue(childMap, scriptEngine));34 return variantMapToScriptValue(childMap, scriptEngine);
35 break;
36 }
37 case QVariant::List: {
38 QVariantList childList = qValue.toList();
39 return variantListToScriptValue(childList, scriptEngine);
40 break;40 break;
41 }41 }
42 default:42 default:
43 qCDebug(shared) << "unhandled QScript type" << qValue.type();43 qCDebug(shared) << "unhandled QScript type" << qValue.type();
44 }44 break;
45 }
46
47 return QScriptValue();
48}
49
50
51QScriptValue 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
64QScriptValue variantListToScriptValue(QVariantList& variantList, QScriptEngine& scriptEngine) {
65 QScriptValue scriptValue = scriptEngine.newObject();
66
67 scriptValue.setProperty("length", variantList.size());
68 int i = 0;
69 foreach (QVariant v, variantList) {
70 scriptValue.setProperty(i++, variantToScriptValue(v, scriptEngine));
45 }71 }
46 72
47 return scriptValue;73 return scriptValue;
libraries/shared/src/VariantMapToScriptValue.h+2−0
@@ -13,4 +13,6 @@ · 12 unmodified lines
13#include <QScriptValue>13#include <QScriptValue>
14#include <QScriptEngine>14#include <QScriptEngine>
15 15
16QScriptValue variantToScriptValue(QVariant& qValue, QScriptEngine& scriptEngine);
16QScriptValue variantMapToScriptValue(QVariantMap& variantMap, QScriptEngine& scriptEngine);17QScriptValue variantMapToScriptValue(QVariantMap& variantMap, QScriptEngine& scriptEngine);
18QScriptValue 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
13HIFI_QML_DEF(Tooltip)
14
15Tooltip::Tooltip(QQuickItem* parent) : QQuickItem(parent) {
16}
17
18Tooltip::~Tooltip() {
19}
20
21QString Tooltip::text() const {
22 return _text;
23}
24
25void Tooltip::setText(const QString& arg) {
26 if (arg != _text) {
27 _text = arg;
28 emit textChanged();
29 }
30}
31
32void Tooltip::setVisible(bool visible) {
33 QQuickItem::setVisible(visible);
34}
35
36QString 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
45void 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
17class Tooltip : public QQuickItem
18{
19 Q_OBJECT
20 HIFI_QML_DECL
21
22private:
23 Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
24
25public:
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
34public slots:
35 virtual void setVisible(bool v);
36 void setText(const QString& arg);
37
38signals:
39 void textChanged();
40
41private:
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
135 135
136void VrMenu::addMenu(QMenu* menu) {136void VrMenu::addMenu(QMenu* menu) {
137 Q_ASSERT(!MenuUserData::forObject(menu));137 Q_ASSERT(!MenuUserData::forObject(menu));
138 QObject * parent = menu->parent();138 QObject* parent = menu->parent();
139 QObject * qmlParent;139 QObject* qmlParent = nullptr;
140 if (dynamic_cast<QMenu*>(parent)) {140 if (dynamic_cast<QMenu*>(parent)) {
141 MenuUserData* userData = MenuUserData::forObject(parent);141 MenuUserData* userData = MenuUserData::forObject(parent);
142 qmlParent = findMenuObject(userData->uuid.toString());142 qmlParent = findMenuObject(userData->uuid.toString());
tests/physics/src/ShapeColliderTests.cpp+257−257
@@ -116,20 +116,20 @@ void ShapeColliderTests::sphereTouchesSphere() { · 115 unmodified lines
116 << " ERROR: null collision" << std::endl;116 << " ERROR: null collision" << std::endl;
117 return;117 return;
118 }118 }
119 119
120 // penetration points from sphereA into sphereB120 // penetration points from sphereA into sphereB
121 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);121 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
122 if (fabs(inaccuracy) > EPSILON) {122 if (fabsf(inaccuracy) > EPSILON) {
123 std::cout << __FILE__ << ":" << __LINE__123 std::cout << __FILE__ << ":" << __LINE__
124 << " ERROR: bad penetration: expected = " << expectedPenetration124 << " ERROR: bad penetration: expected = " << expectedPenetration
125 << " actual = " << collision->_penetration << std::endl;125 << " actual = " << collision->_penetration << std::endl;
126 }126 }
127 127
128 // contactPoint is on surface of sphereA128 // contactPoint is on surface of sphereA
129 glm::vec3 AtoB = sphereB.getTranslation() - sphereA.getTranslation();129 glm::vec3 AtoB = sphereB.getTranslation() - sphereA.getTranslation();
130 glm::vec3 expectedContactPoint = sphereA.getTranslation() + radiusA * glm::normalize(AtoB);130 glm::vec3 expectedContactPoint = sphereA.getTranslation() + radiusA * glm::normalize(AtoB);
131 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);131 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
132 if (fabs(inaccuracy) > EPSILON) {132 if (fabsf(inaccuracy) > EPSILON) {
133 std::cout << __FILE__ << ":" << __LINE__133 std::cout << __FILE__ << ":" << __LINE__
134 << " ERROR: bad contactPoint: expected = " << expectedContactPoint134 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
135 << " actual = " << collision->_contactPoint << std::endl;135 << " actual = " << collision->_contactPoint << std::endl;
@@ -145,21 +145,21 @@ void ShapeColliderTests::sphereTouchesSphere() { · 9 unmodified lines
145 } else {145 } else {
146 ++numCollisions;146 ++numCollisions;
147 }147 }
148 148
149 // penetration points from sphereA into sphereB149 // penetration points from sphereA into sphereB
150 CollisionInfo* collision = collisions.getCollision(numCollisions - 1);150 CollisionInfo* collision = collisions.getCollision(numCollisions - 1);
151 float inaccuracy = glm::length(collision->_penetration + expectedPenetration);151 float inaccuracy = glm::length(collision->_penetration + expectedPenetration);
152 if (fabs(inaccuracy) > EPSILON) {152 if (fabsf(inaccuracy) > EPSILON) {
153 std::cout << __FILE__ << ":" << __LINE__153 std::cout << __FILE__ << ":" << __LINE__
154 << " ERROR: bad penetration: expected = " << expectedPenetration154 << " ERROR: bad penetration: expected = " << expectedPenetration
155 << " actual = " << collision->_penetration << std::endl;155 << " actual = " << collision->_penetration << std::endl;
156 }156 }
157 157
158 // contactPoint is on surface of sphereA158 // contactPoint is on surface of sphereA
159 glm::vec3 BtoA = sphereA.getTranslation() - sphereB.getTranslation();159 glm::vec3 BtoA = sphereA.getTranslation() - sphereB.getTranslation();
160 glm::vec3 expectedContactPoint = sphereB.getTranslation() + radiusB * glm::normalize(BtoA);160 glm::vec3 expectedContactPoint = sphereB.getTranslation() + radiusB * glm::normalize(BtoA);
161 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);161 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
162 if (fabs(inaccuracy) > EPSILON) {162 if (fabsf(inaccuracy) > EPSILON) {
163 std::cout << __FILE__ << ":" << __LINE__163 std::cout << __FILE__ << ":" << __LINE__
164 << " ERROR: bad contactPoint: expected = " << expectedContactPoint164 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
165 << " actual = " << collision->_contactPoint << std::endl;165 << " actual = " << collision->_contactPoint << std::endl;
@@ -175,7 +175,7 @@ void ShapeColliderTests::sphereMissesCapsule() { · 9 unmodified lines
175 float halfHeightB = 1.7f;175 float halfHeightB = 1.7f;
176 float axialOffset = totalRadius + 1.1f * halfHeightB;176 float axialOffset = totalRadius + 1.1f * halfHeightB;
177 float radialOffset = 1.2f * radiusA + 1.3f * radiusB;177 float radialOffset = 1.2f * radiusA + 1.3f * radiusB;
178 178
179 SphereShape sphereA(radiusA);179 SphereShape sphereA(radiusA);
180 CapsuleShape capsuleB(radiusB, halfHeightB);180 CapsuleShape capsuleB(radiusB, halfHeightB);
181 181
@@ -228,7 +228,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 46 unmodified lines
228 float alpha = 0.5f;228 float alpha = 0.5f;
229 float beta = 0.5f;229 float beta = 0.5f;
230 float radialOffset = alpha * radiusA + beta * radiusB;230 float radialOffset = alpha * radiusA + beta * radiusB;
231 231
232 SphereShape sphereA(radiusA);232 SphereShape sphereA(radiusA);
233 CapsuleShape capsuleB(radiusB, halfHeightB);233 CapsuleShape capsuleB(radiusB, halfHeightB);
234 234
@@ -245,21 +245,21 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 10 unmodified lines
245 } else {245 } else {
246 ++numCollisions;246 ++numCollisions;
247 }247 }
248 248
249 // penetration points from sphereA into capsuleB249 // penetration points from sphereA into capsuleB
250 CollisionInfo* collision = collisions.getCollision(numCollisions - 1);250 CollisionInfo* collision = collisions.getCollision(numCollisions - 1);
251 glm::vec3 expectedPenetration = (radialOffset - totalRadius) * xAxis;251 glm::vec3 expectedPenetration = (radialOffset - totalRadius) * xAxis;
252 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);252 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
253 if (fabs(inaccuracy) > EPSILON) {253 if (fabsf(inaccuracy) > EPSILON) {
254 std::cout << __FILE__ << ":" << __LINE__254 std::cout << __FILE__ << ":" << __LINE__
255 << " ERROR: bad penetration: expected = " << expectedPenetration255 << " ERROR: bad penetration: expected = " << expectedPenetration
256 << " actual = " << collision->_penetration << std::endl;256 << " actual = " << collision->_penetration << std::endl;
257 }257 }
258 258
259 // contactPoint is on surface of sphereA259 // contactPoint is on surface of sphereA
260 glm::vec3 expectedContactPoint = sphereA.getTranslation() - radiusA * xAxis;260 glm::vec3 expectedContactPoint = sphereA.getTranslation() - radiusA * xAxis;
261 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);261 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
262 if (fabs(inaccuracy) > EPSILON) {262 if (fabsf(inaccuracy) > EPSILON) {
263 std::cout << __FILE__ << ":" << __LINE__263 std::cout << __FILE__ << ":" << __LINE__
264 << " ERROR: bad contactPoint: expected = " << expectedContactPoint264 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
265 << " actual = " << collision->_contactPoint << std::endl;265 << " actual = " << collision->_contactPoint << std::endl;
@@ -273,7 +273,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 7 unmodified lines
273 } else {273 } else {
274 ++numCollisions;274 ++numCollisions;
275 }275 }
276 276
277 // penetration points from sphereA into capsuleB277 // penetration points from sphereA into capsuleB
278 collision = collisions.getCollision(numCollisions - 1);278 collision = collisions.getCollision(numCollisions - 1);
279 expectedPenetration = - (radialOffset - totalRadius) * xAxis;279 expectedPenetration = - (radialOffset - totalRadius) * xAxis;
@@ -282,12 +282,12 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 2 unmodified lines
282 expectedPenetration *= -1.0f;282 expectedPenetration *= -1.0f;
283 }283 }
284 inaccuracy = glm::length(collision->_penetration - expectedPenetration);284 inaccuracy = glm::length(collision->_penetration - expectedPenetration);
285 if (fabs(inaccuracy) > EPSILON) {285 if (fabsf(inaccuracy) > EPSILON) {
286 std::cout << __FILE__ << ":" << __LINE__286 std::cout << __FILE__ << ":" << __LINE__
287 << " ERROR: bad penetration: expected = " << expectedPenetration287 << " ERROR: bad penetration: expected = " << expectedPenetration
288 << " actual = " << collision->_penetration << std::endl;288 << " actual = " << collision->_penetration << std::endl;
289 }289 }
290 290
291 // contactPoint is on surface of capsuleB291 // contactPoint is on surface of capsuleB
292 glm::vec3 BtoA = sphereA.getTranslation() - capsuleB.getTranslation();292 glm::vec3 BtoA = sphereA.getTranslation() - capsuleB.getTranslation();
293 glm::vec3 closestApproach = capsuleB.getTranslation() + glm::dot(BtoA, yAxis) * yAxis;293 glm::vec3 closestApproach = capsuleB.getTranslation() + glm::dot(BtoA, yAxis) * yAxis;
@@ -298,7 +298,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 4 unmodified lines
298 expectedContactPoint = closestApproach - radiusB * glm::normalize(BtoA - closestApproach);298 expectedContactPoint = closestApproach - radiusB * glm::normalize(BtoA - closestApproach);
299 }299 }
300 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);300 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
301 if (fabs(inaccuracy) > EPSILON) {301 if (fabsf(inaccuracy) > EPSILON) {
302 std::cout << __FILE__ << ":" << __LINE__302 std::cout << __FILE__ << ":" << __LINE__
303 << " ERROR: bad contactPoint: expected = " << expectedContactPoint303 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
304 << " actual = " << collision->_contactPoint << std::endl;304 << " actual = " << collision->_contactPoint << std::endl;
@@ -307,7 +307,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 2 unmodified lines
307 { // sphereA hits end cap at axis307 { // sphereA hits end cap at axis
308 glm::vec3 axialOffset = (halfHeightB + alpha * radiusA + beta * radiusB) * yAxis;308 glm::vec3 axialOffset = (halfHeightB + alpha * radiusA + beta * radiusB) * yAxis;
309 sphereA.setTranslation(axialOffset);309 sphereA.setTranslation(axialOffset);
310 310
311 if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions))311 if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions))
312 {312 {
313 std::cout << __FILE__ << ":" << __LINE__313 std::cout << __FILE__ << ":" << __LINE__
@@ -315,21 +315,21 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 1 unmodified line
315 } else {315 } else {
316 ++numCollisions;316 ++numCollisions;
317 }317 }
318 318
319 // penetration points from sphereA into capsuleB319 // penetration points from sphereA into capsuleB
320 CollisionInfo* collision = collisions.getCollision(numCollisions - 1);320 CollisionInfo* collision = collisions.getCollision(numCollisions - 1);
321 glm::vec3 expectedPenetration = - ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis;321 glm::vec3 expectedPenetration = - ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis;
322 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);322 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
323 if (fabs(inaccuracy) > EPSILON) {323 if (fabsf(inaccuracy) > EPSILON) {
324 std::cout << __FILE__ << ":" << __LINE__324 std::cout << __FILE__ << ":" << __LINE__
325 << " ERROR: bad penetration: expected = " << expectedPenetration325 << " ERROR: bad penetration: expected = " << expectedPenetration
326 << " actual = " << collision->_penetration << std::endl;326 << " actual = " << collision->_penetration << std::endl;
327 }327 }
328 328
329 // contactPoint is on surface of sphereA329 // contactPoint is on surface of sphereA
330 glm::vec3 expectedContactPoint = sphereA.getTranslation() - radiusA * yAxis;330 glm::vec3 expectedContactPoint = sphereA.getTranslation() - radiusA * yAxis;
331 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);331 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
332 if (fabs(inaccuracy) > EPSILON) {332 if (fabsf(inaccuracy) > EPSILON) {
333 std::cout << __FILE__ << ":" << __LINE__333 std::cout << __FILE__ << ":" << __LINE__
334 << " ERROR: bad contactPoint: expected = " << expectedContactPoint334 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
335 << " actual = " << collision->_contactPoint << std::endl;335 << " actual = " << collision->_contactPoint << std::endl;
@@ -343,7 +343,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 7 unmodified lines
343 } else {343 } else {
344 ++numCollisions;344 ++numCollisions;
345 }345 }
346 346
347 // penetration points from sphereA into capsuleB347 // penetration points from sphereA into capsuleB
348 collision = collisions.getCollision(numCollisions - 1);348 collision = collisions.getCollision(numCollisions - 1);
349 expectedPenetration = ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis;349 expectedPenetration = ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis;
@@ -352,12 +352,12 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 2 unmodified lines
352 expectedPenetration *= -1.0f;352 expectedPenetration *= -1.0f;
353 }353 }
354 inaccuracy = glm::length(collision->_penetration - expectedPenetration);354 inaccuracy = glm::length(collision->_penetration - expectedPenetration);
355 if (fabs(inaccuracy) > EPSILON) {355 if (fabsf(inaccuracy) > EPSILON) {
356 std::cout << __FILE__ << ":" << __LINE__356 std::cout << __FILE__ << ":" << __LINE__
357 << " ERROR: bad penetration: expected = " << expectedPenetration357 << " ERROR: bad penetration: expected = " << expectedPenetration
358 << " actual = " << collision->_penetration << std::endl;358 << " actual = " << collision->_penetration << std::endl;
359 }359 }
360 360
361 // contactPoint is on surface of capsuleB361 // contactPoint is on surface of capsuleB
362 glm::vec3 endPoint;362 glm::vec3 endPoint;
363 capsuleB.getEndPoint(endPoint);363 capsuleB.getEndPoint(endPoint);
@@ -367,7 +367,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 3 unmodified lines
367 expectedContactPoint = axialOffset - radiusA * yAxis;367 expectedContactPoint = axialOffset - radiusA * yAxis;
368 }368 }
369 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);369 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
370 if (fabs(inaccuracy) > EPSILON) {370 if (fabsf(inaccuracy) > EPSILON) {
371 std::cout << __FILE__ << ":" << __LINE__371 std::cout << __FILE__ << ":" << __LINE__
372 << " ERROR: bad contactPoint: expected = " << expectedContactPoint372 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
373 << " actual = " << collision->_contactPoint << std::endl;373 << " actual = " << collision->_contactPoint << std::endl;
@@ -376,7 +376,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 2 unmodified lines
376 { // sphereA hits start cap at axis376 { // sphereA hits start cap at axis
377 glm::vec3 axialOffset = - (halfHeightB + alpha * radiusA + beta * radiusB) * yAxis;377 glm::vec3 axialOffset = - (halfHeightB + alpha * radiusA + beta * radiusB) * yAxis;
378 sphereA.setTranslation(axialOffset);378 sphereA.setTranslation(axialOffset);
379 379
380 if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions))380 if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions))
381 {381 {
382 std::cout << __FILE__ << ":" << __LINE__382 std::cout << __FILE__ << ":" << __LINE__
@@ -384,21 +384,21 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 1 unmodified line
384 } else {384 } else {
385 ++numCollisions;385 ++numCollisions;
386 }386 }
387 387
388 // penetration points from sphereA into capsuleB388 // penetration points from sphereA into capsuleB
389 CollisionInfo* collision = collisions.getCollision(numCollisions - 1);389 CollisionInfo* collision = collisions.getCollision(numCollisions - 1);
390 glm::vec3 expectedPenetration = ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis;390 glm::vec3 expectedPenetration = ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis;
391 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);391 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
392 if (fabs(inaccuracy) > EPSILON) {392 if (fabsf(inaccuracy) > EPSILON) {
393 std::cout << __FILE__ << ":" << __LINE__393 std::cout << __FILE__ << ":" << __LINE__
394 << " ERROR: bad penetration: expected = " << expectedPenetration394 << " ERROR: bad penetration: expected = " << expectedPenetration
395 << " actual = " << collision->_penetration << std::endl;395 << " actual = " << collision->_penetration << std::endl;
396 }396 }
397 397
398 // contactPoint is on surface of sphereA398 // contactPoint is on surface of sphereA
399 glm::vec3 expectedContactPoint = sphereA.getTranslation() + radiusA * yAxis;399 glm::vec3 expectedContactPoint = sphereA.getTranslation() + radiusA * yAxis;
400 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);400 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
401 if (fabs(inaccuracy) > EPSILON) {401 if (fabsf(inaccuracy) > EPSILON) {
402 std::cout << __FILE__ << ":" << __LINE__402 std::cout << __FILE__ << ":" << __LINE__
403 << " ERROR: bad contactPoint: expected = " << expectedContactPoint403 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
404 << " actual = " << collision->_contactPoint << std::endl;404 << " actual = " << collision->_contactPoint << std::endl;
@@ -412,7 +412,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 7 unmodified lines
412 } else {412 } else {
413 ++numCollisions;413 ++numCollisions;
414 }414 }
415 415
416 // penetration points from sphereA into capsuleB416 // penetration points from sphereA into capsuleB
417 collision = collisions.getCollision(numCollisions - 1);417 collision = collisions.getCollision(numCollisions - 1);
418 expectedPenetration = - ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis;418 expectedPenetration = - ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis;
@@ -421,12 +421,12 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 2 unmodified lines
421 expectedPenetration *= -1.0f;421 expectedPenetration *= -1.0f;
422 }422 }
423 inaccuracy = glm::length(collision->_penetration - expectedPenetration);423 inaccuracy = glm::length(collision->_penetration - expectedPenetration);
424 if (fabs(inaccuracy) > EPSILON) {424 if (fabsf(inaccuracy) > EPSILON) {
425 std::cout << __FILE__ << ":" << __LINE__425 std::cout << __FILE__ << ":" << __LINE__
426 << " ERROR: bad penetration: expected = " << expectedPenetration426 << " ERROR: bad penetration: expected = " << expectedPenetration
427 << " actual = " << collision->_penetration << std::endl;427 << " actual = " << collision->_penetration << std::endl;
428 }428 }
429 429
430 // contactPoint is on surface of capsuleB430 // contactPoint is on surface of capsuleB
431 glm::vec3 startPoint;431 glm::vec3 startPoint;
432 capsuleB.getStartPoint(startPoint);432 capsuleB.getStartPoint(startPoint);
@@ -436,7 +436,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { · 3 unmodified lines
436 expectedContactPoint = axialOffset + radiusA * yAxis;436 expectedContactPoint = axialOffset + radiusA * yAxis;
437 }437 }
438 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);438 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
439 if (fabs(inaccuracy) > EPSILON) {439 if (fabsf(inaccuracy) > EPSILON) {
440 std::cout << __FILE__ << ":" << __LINE__440 std::cout << __FILE__ << ":" << __LINE__
441 << " ERROR: bad contactPoint: expected = " << expectedContactPoint441 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
442 << " actual = " << collision->_contactPoint << std::endl;442 << " actual = " << collision->_contactPoint << std::endl;
@@ -600,19 +600,19 @@ void ShapeColliderTests::capsuleTouchesCapsule() { · 157 unmodified lines
600 } else {600 } else {
601 ++numCollisions;601 ++numCollisions;
602 }602 }
603 603
604 CollisionInfo* collision = collisions.getCollision(numCollisions - 1);604 CollisionInfo* collision = collisions.getCollision(numCollisions - 1);
605 glm::vec3 expectedPenetration = overlap * xAxis;605 glm::vec3 expectedPenetration = overlap * xAxis;
606 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);606 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
607 if (fabs(inaccuracy) > EPSILON) {607 if (fabsf(inaccuracy) > EPSILON) {
608 std::cout << __FILE__ << ":" << __LINE__608 std::cout << __FILE__ << ":" << __LINE__
609 << " ERROR: bad penetration: expected = " << expectedPenetration609 << " ERROR: bad penetration: expected = " << expectedPenetration
610 << " actual = " << collision->_penetration << std::endl;610 << " actual = " << collision->_penetration << std::endl;
611 }611 }
612 612
613 glm::vec3 expectedContactPoint = capsuleA.getTranslation() + radiusA * xAxis;613 glm::vec3 expectedContactPoint = capsuleA.getTranslation() + radiusA * xAxis;
614 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);614 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
615 if (fabs(inaccuracy) > EPSILON) {615 if (fabsf(inaccuracy) > EPSILON) {
616 std::cout << __FILE__ << ":" << __LINE__616 std::cout << __FILE__ << ":" << __LINE__
617 << " ERROR: bad contactPoint: expected = " << expectedContactPoint617 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
618 << " actual = " << collision->_contactPoint << std::endl;618 << " actual = " << collision->_contactPoint << std::endl;
@@ -626,19 +626,19 @@ void ShapeColliderTests::capsuleTouchesCapsule() { · 7 unmodified lines
626 } else {626 } else {
627 ++numCollisions;627 ++numCollisions;
628 }628 }
629 629
630 collision = collisions.getCollision(numCollisions - 1);630 collision = collisions.getCollision(numCollisions - 1);
631 expectedPenetration = - overlap * xAxis;631 expectedPenetration = - overlap * xAxis;
632 inaccuracy = glm::length(collision->_penetration - expectedPenetration);632 inaccuracy = glm::length(collision->_penetration - expectedPenetration);
633 if (fabs(inaccuracy) > EPSILON) {633 if (fabsf(inaccuracy) > EPSILON) {
634 std::cout << __FILE__ << ":" << __LINE__634 std::cout << __FILE__ << ":" << __LINE__
635 << " ERROR: bad penetration: expected = " << expectedPenetration635 << " ERROR: bad penetration: expected = " << expectedPenetration
636 << " actual = " << collision->_penetration << std::endl;636 << " actual = " << collision->_penetration << std::endl;
637 }637 }
638 638
639 expectedContactPoint = capsuleB.getTranslation() - (radiusB + halfHeightB) * xAxis;639 expectedContactPoint = capsuleB.getTranslation() - (radiusB + halfHeightB) * xAxis;
640 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);640 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
641 if (fabs(inaccuracy) > EPSILON) {641 if (fabsf(inaccuracy) > EPSILON) {
642 std::cout << __FILE__ << ":" << __LINE__642 std::cout << __FILE__ << ":" << __LINE__
643 << " ERROR: bad contactPoint: expected = " << expectedContactPoint643 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
644 << " actual = " << collision->_contactPoint << std::endl;644 << " actual = " << collision->_contactPoint << std::endl;
@@ -661,19 +661,19 @@ void ShapeColliderTests::capsuleTouchesCapsule() { · 16 unmodified lines
661 } else {661 } else {
662 ++numCollisions;662 ++numCollisions;
663 }663 }
664 664
665 CollisionInfo* collision = collisions.getCollision(numCollisions - 1);665 CollisionInfo* collision = collisions.getCollision(numCollisions - 1);
666 glm::vec3 expectedPenetration = overlap * zAxis;666 glm::vec3 expectedPenetration = overlap * zAxis;
667 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);667 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
668 if (fabs(inaccuracy) > EPSILON) {668 if (fabsf(inaccuracy) > EPSILON) {
669 std::cout << __FILE__ << ":" << __LINE__669 std::cout << __FILE__ << ":" << __LINE__
670 << " ERROR: bad penetration: expected = " << expectedPenetration670 << " ERROR: bad penetration: expected = " << expectedPenetration
671 << " actual = " << collision->_penetration << std::endl;671 << " actual = " << collision->_penetration << std::endl;
672 }672 }
673 673
674 glm::vec3 expectedContactPoint = capsuleA.getTranslation() + radiusA * zAxis + shift * yAxis;674 glm::vec3 expectedContactPoint = capsuleA.getTranslation() + radiusA * zAxis + shift * yAxis;
675 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);675 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
676 if (fabs(inaccuracy) > EPSILON) {676 if (fabsf(inaccuracy) > EPSILON) {
677 std::cout << __FILE__ << ":" << __LINE__677 std::cout << __FILE__ << ":" << __LINE__
678 << " ERROR: bad contactPoint: expected = " << expectedContactPoint678 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
679 << " actual = " << collision->_contactPoint << std::endl;679 << " actual = " << collision->_contactPoint << std::endl;
@@ -683,7 +683,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() { · 3 unmodified lines
683 683
684void ShapeColliderTests::sphereMissesAACube() {684void ShapeColliderTests::sphereMissesAACube() {
685 CollisionList collisions(16);685 CollisionList collisions(16);
686 686
687 float sphereRadius = 1.0f;687 float sphereRadius = 1.0f;
688 glm::vec3 sphereCenter(0.0f);688 glm::vec3 sphereCenter(0.0f);
689 689
@@ -702,7 +702,7 @@ void ShapeColliderTests::sphereMissesAACube() { · 12 unmodified lines
702 702
703 sphereCenter = cubeCenter + (0.5f * cubeSide + sphereRadius + offset) * faceNormal;703 sphereCenter = cubeCenter + (0.5f * cubeSide + sphereRadius + offset) * faceNormal;
704 704
705 CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, 705 CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
706 cubeCenter, cubeSide, collisions);706 cubeCenter, cubeSide, collisions);
707 707
708 if (collision) {708 if (collision) {
@@ -742,9 +742,9 @@ void ShapeColliderTests::sphereMissesAACube() { · 33 unmodified lines
742 for (int m = 0; m < numSteps; ++m) {742 for (int m = 0; m < numSteps; ++m) {
743 sphereCenter = startPosition + ((float)m * delta) * thirdNormal + (sphereRadius + offset) * edgeNormal;743 sphereCenter = startPosition + ((float)m * delta) * thirdNormal + (sphereRadius + offset) * edgeNormal;
744 744
745 CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, 745 CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
746 cubeCenter, cubeSide, collisions);746 cubeCenter, cubeSide, collisions);
747 747
748 if (collision) {748 if (collision) {
749 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube edge."749 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube edge."
750 << " edgeNormal = " << edgeNormal << std::endl;750 << " edgeNormal = " << edgeNormal << std::endl;
@@ -779,10 +779,10 @@ void ShapeColliderTests::sphereMissesAACube() { · 28 unmodified lines
779 glm::quat rotation = glm::angleAxis(angle, cornerNormal);779 glm::quat rotation = glm::angleAxis(angle, cornerNormal);
780 glm::vec3 offsetAxis = rotation * nearbyAxis;780 glm::vec3 offsetAxis = rotation * nearbyAxis;
781 sphereCenter = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide) * cornerNormal + (sphereRadius + offset) * offsetAxis;781 sphereCenter = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide) * cornerNormal + (sphereRadius + offset) * offsetAxis;
782 782
783 CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, 783 CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
784 cubeCenter, cubeSide, collisions);784 cubeCenter, cubeSide, collisions);
785 785
786 if (collision) {786 if (collision) {
787 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube corner."787 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube corner."
788 << " cornerNormal = " << cornerNormal << std::endl;788 << " cornerNormal = " << cornerNormal << std::endl;
@@ -796,7 +796,7 @@ void ShapeColliderTests::sphereMissesAACube() { · 7 unmodified lines
796 796
797void ShapeColliderTests::sphereTouchesAACubeFaces() {797void ShapeColliderTests::sphereTouchesAACubeFaces() {
798 CollisionList collisions(16);798 CollisionList collisions(16);
799 799
800 float sphereRadius = 1.13f;800 float sphereRadius = 1.13f;
801 glm::vec3 sphereCenter(0.0f);801 glm::vec3 sphereCenter(0.0f);
802 802
@@ -817,38 +817,38 @@ void ShapeColliderTests::sphereTouchesAACubeFaces() { · 14 unmodified lines
817 float parallelOffset = 0.5f * cubeSide + sphereRadius - overlap;817 float parallelOffset = 0.5f * cubeSide + sphereRadius - overlap;
818 float perpOffset = 0.25f * cubeSide;818 float perpOffset = 0.25f * cubeSide;
819 glm::vec3 expectedPenetration = - overlap * faceNormal;819 glm::vec3 expectedPenetration = - overlap * faceNormal;
820 820
821 // We rotate the position of the sphereCenter about a circle on the cube face so that 821 // We rotate the position of the sphereCenter about a circle on the cube face so that
822 // it hits the same face in multiple spots. The penetration should be invarient for 822 // it hits the same face in multiple spots. The penetration should be invarient for
823 // all collisions.823 // all collisions.
824 float delta = TWO_PI / 4.0f;824 float delta = TWO_PI / 4.0f;
825 for (float angle = 0; angle < TWO_PI + EPSILON; angle += delta) {825 for (float angle = 0; angle < TWO_PI + EPSILON; angle += delta) {
826 glm::quat rotation = glm::angleAxis(angle, faceNormal);826 glm::quat rotation = glm::angleAxis(angle, faceNormal);
827 glm::vec3 perpAxis = rotation * faceNormals[(i + 1) % numDirections];827 glm::vec3 perpAxis = rotation * faceNormals[(i + 1) % numDirections];
828 828
829 sphereCenter = cubeCenter + parallelOffset * faceNormal + perpOffset * perpAxis;829 sphereCenter = cubeCenter + parallelOffset * faceNormal + perpOffset * perpAxis;
830 830
831 CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, 831 CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
832 cubeCenter, cubeSide, collisions);832 cubeCenter, cubeSide, collisions);
833 833
834 if (!collision) {834 if (!collision) {
835 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide outside cube face."835 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide outside cube face."
836 << " faceNormal = " << faceNormal 836 << " faceNormal = " << faceNormal
837 << std::endl;837 << std::endl;
838 break;838 break;
839 }839 }
840 840
841 if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) {841 if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) {
842 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration 842 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration
843 << " expected " << expectedPenetration << " faceNormal = " << faceNormal << std::endl;843 << " expected " << expectedPenetration << " faceNormal = " << faceNormal << std::endl;
844 }844 }
845 845
846 glm::vec3 expectedContact = sphereCenter - sphereRadius * faceNormal;846 glm::vec3 expectedContact = sphereCenter - sphereRadius * faceNormal;
847 if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) {847 if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) {
848 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint 848 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint
849 << " expected " << expectedContact << " faceNormal = " << faceNormal << std::endl;849 << " expected " << expectedContact << " faceNormal = " << faceNormal << std::endl;
850 }850 }
851 851
852 if (collision->getShapeA()) {852 if (collision->getShapeA()) {
853 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: collision->_shapeA should be NULL" << std::endl;853 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: collision->_shapeA should be NULL" << std::endl;
854 }854 }
@@ -857,32 +857,32 @@ void ShapeColliderTests::sphereTouchesAACubeFaces() { · 2 unmodified lines
857 }857 }
858 }858 }
859 }859 }
860 860
861 // inside861 // inside
862 {862 {
863 collisions.clear();863 collisions.clear();
864 float overlap = 1.25f * sphereRadius;864 float overlap = 1.25f * sphereRadius;
865 float sphereOffset = 0.5f * cubeSide + sphereRadius - overlap;865 float sphereOffset = 0.5f * cubeSide + sphereRadius - overlap;
866 sphereCenter = cubeCenter + sphereOffset * faceNormal;866 sphereCenter = cubeCenter + sphereOffset * faceNormal;
867 867
868 CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, 868 CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
869 cubeCenter, cubeSide, collisions);869 cubeCenter, cubeSide, collisions);
870 870
871 if (!collision) {871 if (!collision) {
872 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide inside cube face." 872 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide inside cube face."
873 << " faceNormal = " << faceNormal << std::endl;873 << " faceNormal = " << faceNormal << std::endl;
874 break;874 break;
875 }875 }
876 876
877 glm::vec3 expectedPenetration = - overlap * faceNormal;877 glm::vec3 expectedPenetration = - overlap * faceNormal;
878 if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) {878 if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) {
879 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration 879 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration
880 << " expected " << expectedPenetration << " faceNormal = " << faceNormal << std::endl;880 << " expected " << expectedPenetration << " faceNormal = " << faceNormal << std::endl;
881 }881 }
882 882
883 glm::vec3 expectedContact = sphereCenter - sphereRadius * faceNormal;883 glm::vec3 expectedContact = sphereCenter - sphereRadius * faceNormal;
884 if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) {884 if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) {
885 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint 885 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint
886 << " expected " << expectedContact << " faceNormal = " << faceNormal << std::endl;886 << " expected " << expectedContact << " faceNormal = " << faceNormal << std::endl;
887 }887 }
888 }888 }
@@ -892,14 +892,14 @@ void ShapeColliderTests::sphereTouchesAACubeFaces() { · 3 unmodified lines
892 892
893void ShapeColliderTests::sphereTouchesAACubeEdges() {893void ShapeColliderTests::sphereTouchesAACubeEdges() {
894 CollisionList collisions(20);894 CollisionList collisions(20);
895 895
896 float sphereRadius = 1.37f;896 float sphereRadius = 1.37f;
897 glm::vec3 sphereCenter(0.0f);897 glm::vec3 sphereCenter(0.0f);
898 898
899 glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f);899 glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f);
900 float cubeSide = 2.98f;900 float cubeSide = 2.98f;
901 901
902 float overlap = 0.25 * sphereRadius;902 float overlap = 0.25f * sphereRadius;
903 int numSteps = 5;903 int numSteps = 5;
904 904
905 glm::vec3 faceNormals[] = {xAxis, yAxis, zAxis};905 glm::vec3 faceNormals[] = {xAxis, yAxis, zAxis};
@@ -935,23 +935,23 @@ void ShapeColliderTests::sphereTouchesAACubeEdges() { · 29 unmodified lines
935 for (int m = 0; m < numSteps; ++m) {935 for (int m = 0; m < numSteps; ++m) {
936 sphereCenter = startPosition + ((float)m * delta) * thirdNormal + (sphereRadius - overlap) * edgeNormal;936 sphereCenter = startPosition + ((float)m * delta) * thirdNormal + (sphereRadius - overlap) * edgeNormal;
937 937
938 CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, 938 CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
939 cubeCenter, cubeSide, collisions);939 cubeCenter, cubeSide, collisions);
940 940
941 if (!collision) {941 if (!collision) {
942 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube edge."942 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube edge."
943 << " edgeNormal = " << edgeNormal << std::endl;943 << " edgeNormal = " << edgeNormal << std::endl;
944 break;944 break;
945 }945 }
946 946
947 if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) {947 if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) {
948 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration 948 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration
949 << " expected " << expectedPenetration << " edgeNormal = " << edgeNormal << std::endl;949 << " expected " << expectedPenetration << " edgeNormal = " << edgeNormal << std::endl;
950 }950 }
951 951
952 glm::vec3 expectedContact = sphereCenter - sphereRadius * edgeNormal;952 glm::vec3 expectedContact = sphereCenter - sphereRadius * edgeNormal;
953 if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) {953 if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) {
954 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint 954 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint
955 << " expected " << expectedContact << " edgeNormal = " << edgeNormal << std::endl;955 << " expected " << expectedContact << " edgeNormal = " << edgeNormal << std::endl;
956 }956 }
957 }957 }
@@ -963,14 +963,14 @@ void ShapeColliderTests::sphereTouchesAACubeEdges() { · 5 unmodified lines
963 963
964void ShapeColliderTests::sphereTouchesAACubeCorners() {964void ShapeColliderTests::sphereTouchesAACubeCorners() {
965 CollisionList collisions(20);965 CollisionList collisions(20);
966 966
967 float sphereRadius = 1.37f;967 float sphereRadius = 1.37f;
968 glm::vec3 sphereCenter(0.0f);968 glm::vec3 sphereCenter(0.0f);
969 969
970 glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f);970 glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f);
971 float cubeSide = 2.98f;971 float cubeSide = 2.98f;
972 972
973 float overlap = 0.25 * sphereRadius;973 float overlap = 0.25f * sphereRadius;
974 int numSteps = 5;974 int numSteps = 5;
975 975
976 glm::vec3 faceNormals[] = {xAxis, yAxis, zAxis};976 glm::vec3 faceNormals[] = {xAxis, yAxis, zAxis};
@@ -997,25 +997,25 @@ void ShapeColliderTests::sphereTouchesAACubeCorners() { · 20 unmodified lines
997 glm::quat rotation = glm::angleAxis(angle, cornerNormal);997 glm::quat rotation = glm::angleAxis(angle, cornerNormal);
998 glm::vec3 offsetAxis = rotation * nearbyAxis;998 glm::vec3 offsetAxis = rotation * nearbyAxis;
999 sphereCenter = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide) * cornerNormal + (sphereRadius - overlap) * offsetAxis;999 sphereCenter = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide) * cornerNormal + (sphereRadius - overlap) * offsetAxis;
1000 1000
1001 CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius, 1001 CollisionInfo* collision = ShapeCollider::sphereVsAACubeHelper(sphereCenter, sphereRadius,
1002 cubeCenter, cubeSide, collisions);1002 cubeCenter, cubeSide, collisions);
1003 1003
1004 if (!collision) {1004 if (!collision) {
1005 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube corner."1005 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube corner."
1006 << " cornerNormal = " << cornerNormal << std::endl;1006 << " cornerNormal = " << cornerNormal << std::endl;
1007 break;1007 break;
1008 }1008 }
1009 1009
1010 glm::vec3 expectedPenetration = - overlap * offsetAxis;1010 glm::vec3 expectedPenetration = - overlap * offsetAxis;
1011 if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) {1011 if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) {
1012 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration 1012 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration
1013 << " expected " << expectedPenetration << " cornerNormal = " << cornerNormal << std::endl;1013 << " expected " << expectedPenetration << " cornerNormal = " << cornerNormal << std::endl;
1014 }1014 }
1015 1015
1016 glm::vec3 expectedContact = sphereCenter - sphereRadius * offsetAxis;1016 glm::vec3 expectedContact = sphereCenter - sphereRadius * offsetAxis;
1017 if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) {1017 if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) {
1018 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint 1018 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint
1019 << " expected " << expectedContact << " cornerNormal = " << cornerNormal << std::endl;1019 << " expected " << expectedContact << " cornerNormal = " << cornerNormal << std::endl;
1020 }1020 }
1021 }1021 }
@@ -1026,7 +1026,7 @@ void ShapeColliderTests::sphereTouchesAACubeCorners() { · 4 unmodified lines
1026 1026
1027void ShapeColliderTests::capsuleMissesAACube() {1027void ShapeColliderTests::capsuleMissesAACube() {
1028 CollisionList collisions(16);1028 CollisionList collisions(16);
1029 1029
1030 float capsuleRadius = 1.0f;1030 float capsuleRadius = 1.0f;
1031 1031
1032 glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f);1032 glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f);
@@ -1046,7 +1046,7 @@ void ShapeColliderTests::capsuleMissesAACube() { · 13 unmodified lines
1046 glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections];1046 glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections];
1047 1047
1048 // pick a random point somewhere above the face1048 // pick a random point somewhere above the face
1049 glm::vec3 startPoint = cubeCenter + (cubeSide + capsuleRadius) * faceNormal + 1049 glm::vec3 startPoint = cubeCenter + (cubeSide + capsuleRadius) * faceNormal +
1050 (cubeSide * (randFloat() - 0.5f)) * secondNormal +1050 (cubeSide * (randFloat() - 0.5f)) * secondNormal +
1051 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;1051 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;
1052 1052
@@ -1097,23 +1097,23 @@ void ShapeColliderTests::capsuleMissesAACube() { · 44 unmodified lines
1097 glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal);1097 glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal);
1098 1098
1099 // pick a random point somewhere above the edge1099 // pick a random point somewhere above the edge
1100 glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_2 * cubeSide + capsuleRadius) * edgeNormal + 1100 glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_2 * cubeSide + capsuleRadius) * edgeNormal +
1101 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;1101 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;
1102 1102
1103 // pick a second random point slightly more than one radius above the edge1103 // pick a second random point slightly more than one radius above the edge
1104 glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide + capsuleRadius + offset) * edgeNormal +1104 glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide + capsuleRadius + offset) * edgeNormal +
1105 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;1105 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;
1106 1106
1107 // randomly swap the points so capsule axis may point toward or away from edge1107 // randomly swap the points so capsule axis may point toward or away from edge
1108 if (randFloat() > 0.5f) {1108 if (randFloat() > 0.5f) {
1109 glm::vec3 temp = startPoint;1109 glm::vec3 temp = startPoint;
1110 startPoint = endPoint;1110 startPoint = endPoint;
1111 endPoint = temp;1111 endPoint = temp;
1112 }1112 }
1113 1113
1114 // create a capsule between the points1114 // create a capsule between the points
1115 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);1115 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);
1116 1116
1117 // collide capsule with cube1117 // collide capsule with cube
1118 bool hit = ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions);1118 bool hit = ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions);
1119 if (hit) {1119 if (hit) {
@@ -1138,24 +1138,24 @@ void ShapeColliderTests::capsuleMissesAACube() { · 18 unmodified lines
1138 glm::vec3 cornerNormal = glm::normalize(firstNormal + secondNormal + thirdNormal);1138 glm::vec3 cornerNormal = glm::normalize(firstNormal + secondNormal + thirdNormal);
1139 1139
1140 // pick a random point somewhere above the corner1140 // pick a random point somewhere above the corner
1141 glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_3 * cubeSide + capsuleRadius) * cornerNormal + 1141 glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_3 * cubeSide + capsuleRadius) * cornerNormal +
1142 (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal +1142 (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal +
1143 (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal +1143 (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal +
1144 (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal;1144 (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal;
1145 1145
1146 // pick a second random point slightly more than one radius above the corner1146 // pick a second random point slightly more than one radius above the corner
1147 glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide + capsuleRadius + offset) * cornerNormal;1147 glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide + capsuleRadius + offset) * cornerNormal;
1148 1148
1149 // randomly swap the points so capsule axis may point toward or away from corner1149 // randomly swap the points so capsule axis may point toward or away from corner
1150 if (randFloat() > 0.5f) {1150 if (randFloat() > 0.5f) {
1151 glm::vec3 temp = startPoint;1151 glm::vec3 temp = startPoint;
1152 startPoint = endPoint;1152 startPoint = endPoint;
1153 endPoint = temp;1153 endPoint = temp;
1154 }1154 }
1155 1155
1156 // create a capsule between the points1156 // create a capsule between the points
1157 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);1157 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);
1158 1158
1159 // collide capsule with cube1159 // collide capsule with cube
1160 if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {1160 if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {
1161 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube face."1161 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube face."
@@ -1190,7 +1190,7 @@ void ShapeColliderTests::capsuleMissesAACube() { · 28 unmodified lines
1190 glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal);1190 glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal);
1191 1191
1192 // pick a random point somewhere along the edge1192 // pick a random point somewhere along the edge
1193 glm::vec3 edgePoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide) * edgeNormal + 1193 glm::vec3 edgePoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide) * edgeNormal +
1194 ((cubeSide - 2.0f * offset) * (randFloat() - 0.5f)) * thirdNormal;1194 ((cubeSide - 2.0f * offset) * (randFloat() - 0.5f)) * thirdNormal;
1195 1195
1196 // pick a random normal that is deflected slightly from edgeNormal1196 // pick a random normal that is deflected slightly from edgeNormal
@@ -1207,10 +1207,10 @@ void ShapeColliderTests::capsuleMissesAACube() { · 10 unmodified lines
1207 // now we can compute the capsule endpoints1207 // now we can compute the capsule endpoints
1208 glm::vec3 endPoint = axisPoint + (0.5f * capsuleLength * randFloat()) * axisDirection;1208 glm::vec3 endPoint = axisPoint + (0.5f * capsuleLength * randFloat()) * axisDirection;
1209 glm::vec3 startPoint = axisPoint - (0.5f * capsuleLength * randFloat()) * axisDirection;1209 glm::vec3 startPoint = axisPoint - (0.5f * capsuleLength * randFloat()) * axisDirection;
1210 1210
1211 // create a capsule between the points1211 // create a capsule between the points
1212 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);1212 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);
1213 1213
1214 // collide capsule with cube1214 // collide capsule with cube
1215 if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {1215 if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {
1216 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube"1216 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube"
@@ -1241,7 +1241,7 @@ void ShapeColliderTests::capsuleMissesAACube() { · 24 unmodified lines
1241 1241
1242 // pick a random point somewhere above the corner1242 // pick a random point somewhere above the corner
1243 glm::vec3 corner = cubeCenter + (0.5f * cubeSide) * (firstNormal + secondNormal + thirdNormal);1243 glm::vec3 corner = cubeCenter + (0.5f * cubeSide) * (firstNormal + secondNormal + thirdNormal);
1244 glm::vec3 startPoint = corner + (3.0f * cubeSide) * cornerNormal + 1244 glm::vec3 startPoint = corner + (3.0f * cubeSide) * cornerNormal +
1245 (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal +1245 (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal +
1246 (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal +1246 (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal +
1247 (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal;1247 (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal;
@@ -1256,10 +1256,10 @@ void ShapeColliderTests::capsuleMissesAACube() { · 8 unmodified lines
1256 startPoint = endPoint;1256 startPoint = endPoint;
1257 endPoint = temp;1257 endPoint = temp;
1258 }1258 }
1259 1259
1260 // create a capsule between the points1260 // create a capsule between the points
1261 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);1261 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);
1262 1262
1263 // collide capsule with cube1263 // collide capsule with cube
1264 if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {1264 if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {
1265 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube"1265 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube"
@@ -1269,7 +1269,7 @@ void ShapeColliderTests::capsuleMissesAACube() { · 3 unmodified lines
1269 }1269 }
1270 }1270 }
1271 1271
1272 // capsule sides almost hit cube faces 1272 // capsule sides almost hit cube faces
1273 // these are the steps along the capsuleAxis where we'll put the capsule endpoints1273 // these are the steps along the capsuleAxis where we'll put the capsule endpoints
1274 float steps[] = { -1.0f, 2.0f, 0.25f, 0.75f, -1.0f };1274 float steps[] = { -1.0f, 2.0f, 0.25f, 0.75f, -1.0f };
1275 1275
@@ -1280,9 +1280,9 @@ void ShapeColliderTests::capsuleMissesAACube() { · 4 unmodified lines
1280 glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections];1280 glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections];
1281 1281
1282 // pick two random point on opposite edges of the face1282 // pick two random point on opposite edges of the face
1283 glm::vec3 firstEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal + secondNormal) + 1283 glm::vec3 firstEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal + secondNormal) +
1284 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;1284 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;
1285 glm::vec3 secondEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal - secondNormal) + 1285 glm::vec3 secondEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal - secondNormal) +
1286 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;1286 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;
1287 1287
1288 // compute the un-normalized axis for the capsule1288 // compute the un-normalized axis for the capsule
@@ -1309,7 +1309,7 @@ void ShapeColliderTests::capsuleMissesAACube() { · 20 unmodified lines
1309 1309
1310void ShapeColliderTests::capsuleTouchesAACube() {1310void ShapeColliderTests::capsuleTouchesAACube() {
1311 CollisionList collisions(16);1311 CollisionList collisions(16);
1312 1312
1313 float capsuleRadius = 1.0f;1313 float capsuleRadius = 1.0f;
1314 1314
1315 glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f);1315 glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f);
@@ -1330,12 +1330,12 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 14 unmodified lines
1330 glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections];1330 glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections];
1331 1331
1332 // pick a random point somewhere above the face1332 // pick a random point somewhere above the face
1333 glm::vec3 startPoint = cubeCenter + (cubeSide + capsuleRadius) * faceNormal + 1333 glm::vec3 startPoint = cubeCenter + (cubeSide + capsuleRadius) * faceNormal +
1334 (cubeSide * (randFloat() - 0.5f)) * secondNormal +1334 (cubeSide * (randFloat() - 0.5f)) * secondNormal +
1335 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;1335 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;
1336 1336
1337 // pick a second random point slightly less than one radius above the face1337 // pick a second random point slightly less than one radius above the face
1338 // (but reduce width of range by 2*overlap to prevent the penetration from 1338 // (but reduce width of range by 2*overlap to prevent the penetration from
1339 // registering against other faces)1339 // registering against other faces)
1340 glm::vec3 endPoint = cubeCenter + (0.5f * cubeSide + capsuleRadius - overlap) * faceNormal +1340 glm::vec3 endPoint = cubeCenter + (0.5f * cubeSide + capsuleRadius - overlap) * faceNormal +
1341 ((cubeSide - 2.0f * overlap) * (randFloat() - 0.5f)) * secondNormal +1341 ((cubeSide - 2.0f * overlap) * (randFloat() - 0.5f)) * secondNormal +
@@ -1365,25 +1365,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 23 unmodified lines
1365 << " ERROR: null collision with faceNormal = " << faceNormal << std::endl;1365 << " ERROR: null collision with faceNormal = " << faceNormal << std::endl;
1366 return;1366 return;
1367 }1367 }
1368 1368
1369 // penetration points from capsule into cube 1369 // penetration points from capsule into cube
1370 glm::vec3 expectedPenetration = - overlap * faceNormal;1370 glm::vec3 expectedPenetration = - overlap * faceNormal;
1371 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);1371 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
1372 if (fabs(inaccuracy) > allowableError) {1372 if (fabsf(inaccuracy) > allowableError) {
1373 std::cout << __FILE__ << ":" << __LINE__1373 std::cout << __FILE__ << ":" << __LINE__
1374 << " ERROR: bad penetration: expected = " << expectedPenetration1374 << " ERROR: bad penetration: expected = " << expectedPenetration
1375 << " actual = " << collision->_penetration 1375 << " actual = " << collision->_penetration
1376 << " faceNormal = " << faceNormal1376 << " faceNormal = " << faceNormal
1377 << std::endl;1377 << std::endl;
1378 }1378 }
1379 1379
1380 // contactPoint is on surface of capsule1380 // contactPoint is on surface of capsule
1381 glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * faceNormal;1381 glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * faceNormal;
1382 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);1382 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
1383 if (fabs(inaccuracy) > allowableError) {1383 if (fabsf(inaccuracy) > allowableError) {
1384 std::cout << __FILE__ << ":" << __LINE__1384 std::cout << __FILE__ << ":" << __LINE__
1385 << " ERROR: bad contactPoint: expected = " << expectedContactPoint1385 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
1386 << " actual = " << collision->_contactPoint 1386 << " actual = " << collision->_contactPoint
1387 << " faceNormal = " << faceNormal1387 << " faceNormal = " << faceNormal
1388 << std::endl;1388 << std::endl;
1389 }1389 }
@@ -1414,24 +1414,24 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 24 unmodified lines
1414 glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal);1414 glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal);
1415 1415
1416 // pick a random point somewhere above the edge1416 // pick a random point somewhere above the edge
1417 glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_2 * cubeSide + capsuleRadius) * edgeNormal + 1417 glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_2 * cubeSide + capsuleRadius) * edgeNormal +
1418 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;1418 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;
1419 1419
1420 // pick a second random point slightly less than one radius above the edge1420 // pick a second random point slightly less than one radius above the edge
1421 glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide + capsuleRadius - overlap) * edgeNormal +1421 glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide + capsuleRadius - overlap) * edgeNormal +
1422 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;1422 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;
1423 glm::vec3 collidingPoint = endPoint;1423 glm::vec3 collidingPoint = endPoint;
1424 1424
1425 // randomly swap the points so capsule axis may point toward or away from edge1425 // randomly swap the points so capsule axis may point toward or away from edge
1426 if (randFloat() > 0.5f) {1426 if (randFloat() > 0.5f) {
1427 glm::vec3 temp = startPoint;1427 glm::vec3 temp = startPoint;
1428 startPoint = endPoint;1428 startPoint = endPoint;
1429 endPoint = temp;1429 endPoint = temp;
1430 }1430 }
1431 1431
1432 // create a capsule between the points1432 // create a capsule between the points
1433 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);1433 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);
1434 1434
1435 // collide capsule with cube1435 // collide capsule with cube
1436 if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {1436 if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {
1437 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube"1437 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube"
@@ -1444,25 +1444,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 6 unmodified lines
1444 << " ERROR: null collision with edgeNormal = " << edgeNormal << std::endl;1444 << " ERROR: null collision with edgeNormal = " << edgeNormal << std::endl;
1445 return;1445 return;
1446 }1446 }
1447 1447
1448 // penetration points from capsule into cube 1448 // penetration points from capsule into cube
1449 glm::vec3 expectedPenetration = - overlap * edgeNormal;1449 glm::vec3 expectedPenetration = - overlap * edgeNormal;
1450 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);1450 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
1451 if (fabs(inaccuracy) > allowableError) {1451 if (fabsf(inaccuracy) > allowableError) {
1452 std::cout << __FILE__ << ":" << __LINE__1452 std::cout << __FILE__ << ":" << __LINE__
1453 << " ERROR: bad penetration: expected = " << expectedPenetration1453 << " ERROR: bad penetration: expected = " << expectedPenetration
1454 << " actual = " << collision->_penetration 1454 << " actual = " << collision->_penetration
1455 << " edgeNormal = " << edgeNormal1455 << " edgeNormal = " << edgeNormal
1456 << std::endl;1456 << std::endl;
1457 }1457 }
1458 1458
1459 // contactPoint is on surface of capsule1459 // contactPoint is on surface of capsule
1460 glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * edgeNormal;1460 glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * edgeNormal;
1461 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);1461 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
1462 if (fabs(inaccuracy) > allowableError) {1462 if (fabsf(inaccuracy) > allowableError) {
1463 std::cout << __FILE__ << ":" << __LINE__1463 std::cout << __FILE__ << ":" << __LINE__
1464 << " ERROR: bad contactPoint: expected = " << expectedContactPoint1464 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
1465 << " actual = " << collision->_contactPoint 1465 << " actual = " << collision->_contactPoint
1466 << " edgeNormal = " << edgeNormal1466 << " edgeNormal = " << edgeNormal
1467 << std::endl;1467 << std::endl;
1468 }1468 }
@@ -1484,25 +1484,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 15 unmodified lines
1484 glm::vec3 cornerNormal = glm::normalize(firstNormal + secondNormal + thirdNormal);1484 glm::vec3 cornerNormal = glm::normalize(firstNormal + secondNormal + thirdNormal);
1485 1485
1486 // pick a random point somewhere above the corner1486 // pick a random point somewhere above the corner
1487 glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_3 * cubeSide + capsuleRadius) * cornerNormal + 1487 glm::vec3 startPoint = cubeCenter + (SQUARE_ROOT_OF_3 * cubeSide + capsuleRadius) * cornerNormal +
1488 (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal +1488 (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal +
1489 (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal +1489 (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal +
1490 (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal;1490 (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal;
1491 1491
1492 // pick a second random point slightly less than one radius above the corner1492 // pick a second random point slightly less than one radius above the corner
1493 glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide + capsuleRadius - overlap) * cornerNormal;1493 glm::vec3 endPoint = cubeCenter + (SQUARE_ROOT_OF_3 * 0.5f * cubeSide + capsuleRadius - overlap) * cornerNormal;
1494 glm::vec3 collidingPoint = endPoint;1494 glm::vec3 collidingPoint = endPoint;
1495 1495
1496 // randomly swap the points so capsule axis may point toward or away from corner1496 // randomly swap the points so capsule axis may point toward or away from corner
1497 if (randFloat() > 0.5f) {1497 if (randFloat() > 0.5f) {
1498 glm::vec3 temp = startPoint;1498 glm::vec3 temp = startPoint;
1499 startPoint = endPoint;1499 startPoint = endPoint;
1500 endPoint = temp;1500 endPoint = temp;
1501 }1501 }
1502 1502
1503 // create a capsule between the points1503 // create a capsule between the points
1504 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);1504 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);
1505 1505
1506 // collide capsule with cube1506 // collide capsule with cube
1507 if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {1507 if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {
1508 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube"1508 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube"
@@ -1515,25 +1515,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 6 unmodified lines
1515 << " ERROR: null collision with cornerNormal = " << cornerNormal << std::endl;1515 << " ERROR: null collision with cornerNormal = " << cornerNormal << std::endl;
1516 return;1516 return;
1517 }1517 }
1518 1518
1519 // penetration points from capsule into cube 1519 // penetration points from capsule into cube
1520 glm::vec3 expectedPenetration = - overlap * cornerNormal;1520 glm::vec3 expectedPenetration = - overlap * cornerNormal;
1521 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);1521 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
1522 if (fabs(inaccuracy) > allowableError) {1522 if (fabsf(inaccuracy) > allowableError) {
1523 std::cout << __FILE__ << ":" << __LINE__1523 std::cout << __FILE__ << ":" << __LINE__
1524 << " ERROR: bad penetration: expected = " << expectedPenetration1524 << " ERROR: bad penetration: expected = " << expectedPenetration
1525 << " actual = " << collision->_penetration 1525 << " actual = " << collision->_penetration
1526 << " cornerNormal = " << cornerNormal1526 << " cornerNormal = " << cornerNormal
1527 << std::endl;1527 << std::endl;
1528 }1528 }
1529 1529
1530 // contactPoint is on surface of capsule1530 // contactPoint is on surface of capsule
1531 glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * cornerNormal;1531 glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * cornerNormal;
1532 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);1532 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
1533 if (fabs(inaccuracy) > allowableError) {1533 if (fabsf(inaccuracy) > allowableError) {
1534 std::cout << __FILE__ << ":" << __LINE__1534 std::cout << __FILE__ << ":" << __LINE__
1535 << " ERROR: bad contactPoint: expected = " << expectedContactPoint1535 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
1536 << " actual = " << collision->_contactPoint 1536 << " actual = " << collision->_contactPoint
1537 << " cornerNormal = " << cornerNormal1537 << " cornerNormal = " << cornerNormal
1538 << std::endl;1538 << std::endl;
1539 }1539 }
@@ -1566,7 +1566,7 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 26 unmodified lines
1566 glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal);1566 glm::vec3 edgeNormal = glm::normalize(faceNormal + neighborNormal);
1567 1567
1568 // pick a random point somewhere along the edge1568 // pick a random point somewhere along the edge
1569 glm::vec3 edgePoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide) * edgeNormal + 1569 glm::vec3 edgePoint = cubeCenter + (SQUARE_ROOT_OF_2 * 0.5f * cubeSide) * edgeNormal +
1570 ((cubeSide - 2.0f * overlap) * (randFloat() - 0.5f)) * thirdNormal;1570 ((cubeSide - 2.0f * overlap) * (randFloat() - 0.5f)) * thirdNormal;
1571 1571
1572 // pick a random normal that is deflected slightly from edgeNormal1572 // pick a random normal that is deflected slightly from edgeNormal
@@ -1583,10 +1583,10 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 10 unmodified lines
1583 // now we can compute the capsule endpoints1583 // now we can compute the capsule endpoints
1584 glm::vec3 endPoint = axisPoint + (0.5f * capsuleLength * randFloat()) * axisDirection;1584 glm::vec3 endPoint = axisPoint + (0.5f * capsuleLength * randFloat()) * axisDirection;
1585 glm::vec3 startPoint = axisPoint - (0.5f * capsuleLength * randFloat()) * axisDirection;1585 glm::vec3 startPoint = axisPoint - (0.5f * capsuleLength * randFloat()) * axisDirection;
1586 1586
1587 // create a capsule between the points1587 // create a capsule between the points
1588 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);1588 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);
1589 1589
1590 // collide capsule with cube1590 // collide capsule with cube
1591 if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {1591 if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {
1592 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube"1592 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube"
@@ -1599,25 +1599,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 6 unmodified lines
1599 << " ERROR: null collision with edgeNormal = " << edgeNormal << std::endl;1599 << " ERROR: null collision with edgeNormal = " << edgeNormal << std::endl;
1600 return;1600 return;
1601 }1601 }
1602 1602
1603 // penetration points from capsule into cube 1603 // penetration points from capsule into cube
1604 glm::vec3 expectedPenetration = - overlap * deflectedNormal;1604 glm::vec3 expectedPenetration = - overlap * deflectedNormal;
1605 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);1605 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
1606 if (fabs(inaccuracy) > allowableError / capsuleLength) {1606 if (fabsf(inaccuracy) > allowableError / capsuleLength) {
1607 std::cout << __FILE__ << ":" << __LINE__1607 std::cout << __FILE__ << ":" << __LINE__
1608 << " ERROR: bad penetration: expected = " << expectedPenetration1608 << " ERROR: bad penetration: expected = " << expectedPenetration
1609 << " actual = " << collision->_penetration 1609 << " actual = " << collision->_penetration
1610 << " edgeNormal = " << edgeNormal1610 << " edgeNormal = " << edgeNormal
1611 << std::endl;1611 << std::endl;
1612 }1612 }
1613 1613
1614 // contactPoint is on surface of capsule1614 // contactPoint is on surface of capsule
1615 glm::vec3 expectedContactPoint = axisPoint - capsuleRadius * deflectedNormal;1615 glm::vec3 expectedContactPoint = axisPoint - capsuleRadius * deflectedNormal;
1616 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);1616 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
1617 if (fabs(inaccuracy) > allowableError / capsuleLength) {1617 if (fabsf(inaccuracy) > allowableError / capsuleLength) {
1618 std::cout << __FILE__ << ":" << __LINE__1618 std::cout << __FILE__ << ":" << __LINE__
1619 << " ERROR: bad contactPoint: expected = " << expectedContactPoint1619 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
1620 << " actual = " << collision->_contactPoint 1620 << " actual = " << collision->_contactPoint
1621 << " edgeNormal = " << edgeNormal1621 << " edgeNormal = " << edgeNormal
1622 << std::endl;1622 << std::endl;
1623 }1623 }
@@ -1646,7 +1646,7 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 22 unmodified lines
1646 1646
1647 // pick a random point somewhere above the corner1647 // pick a random point somewhere above the corner
1648 glm::vec3 corner = cubeCenter + (0.5f * cubeSide) * (firstNormal + secondNormal + thirdNormal);1648 glm::vec3 corner = cubeCenter + (0.5f * cubeSide) * (firstNormal + secondNormal + thirdNormal);
1649 glm::vec3 startPoint = corner + (3.0f * cubeSide) * cornerNormal + 1649 glm::vec3 startPoint = corner + (3.0f * cubeSide) * cornerNormal +
1650 (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal +1650 (0.25f * cubeSide * (randFloat() - 0.5f)) * firstNormal +
1651 (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal +1651 (0.25f * cubeSide * (randFloat() - 0.5f)) * secondNormal +
1652 (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal;1652 (0.25f * cubeSide * (randFloat() - 0.5f)) * thirdNormal;
@@ -1662,10 +1662,10 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 9 unmodified lines
1662 startPoint = endPoint;1662 startPoint = endPoint;
1663 endPoint = temp;1663 endPoint = temp;
1664 }1664 }
1665 1665
1666 // create a capsule between the points1666 // create a capsule between the points
1667 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);1667 CapsuleShape capsule(capsuleRadius, startPoint, endPoint);
1668 1668
1669 // collide capsule with cube1669 // collide capsule with cube
1670 if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {1670 if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) {
1671 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube"1671 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube"
@@ -1678,25 +1678,25 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 6 unmodified lines
1678 << " ERROR: null collision with cornerNormal = " << cornerNormal << std::endl;1678 << " ERROR: null collision with cornerNormal = " << cornerNormal << std::endl;
1679 return;1679 return;
1680 }1680 }
1681 1681
1682 // penetration points from capsule into cube 1682 // penetration points from capsule into cube
1683 glm::vec3 expectedPenetration = overlap * penetrationNormal;1683 glm::vec3 expectedPenetration = overlap * penetrationNormal;
1684 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);1684 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
1685 if (fabs(inaccuracy) > allowableError) {1685 if (fabsf(inaccuracy) > allowableError) {
1686 std::cout << __FILE__ << ":" << __LINE__1686 std::cout << __FILE__ << ":" << __LINE__
1687 << " ERROR: bad penetration: expected = " << expectedPenetration1687 << " ERROR: bad penetration: expected = " << expectedPenetration
1688 << " actual = " << collision->_penetration 1688 << " actual = " << collision->_penetration
1689 << " cornerNormal = " << cornerNormal1689 << " cornerNormal = " << cornerNormal
1690 << std::endl;1690 << std::endl;
1691 }1691 }
1692 1692
1693 // contactPoint is on surface of capsule1693 // contactPoint is on surface of capsule
1694 glm::vec3 expectedContactPoint = collidingPoint + capsuleRadius * penetrationNormal;1694 glm::vec3 expectedContactPoint = collidingPoint + capsuleRadius * penetrationNormal;
1695 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);1695 inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint);
1696 if (fabs(inaccuracy) > allowableError) {1696 if (fabsf(inaccuracy) > allowableError) {
1697 std::cout << __FILE__ << ":" << __LINE__1697 std::cout << __FILE__ << ":" << __LINE__
1698 << " ERROR: bad contactPoint: expected = " << expectedContactPoint1698 << " ERROR: bad contactPoint: expected = " << expectedContactPoint
1699 << " actual = " << collision->_contactPoint 1699 << " actual = " << collision->_contactPoint
1700 << " cornerNormal = " << cornerNormal1700 << " cornerNormal = " << cornerNormal
1701 << std::endl;1701 << std::endl;
1702 }1702 }
@@ -1704,7 +1704,7 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 1 unmodified line
1704 }1704 }
1705 }1705 }
1706 1706
1707 // capsule sides hit cube faces 1707 // capsule sides hit cube faces
1708 // these are the steps along the capsuleAxis where we'll put the capsule endpoints1708 // these are the steps along the capsuleAxis where we'll put the capsule endpoints
1709 float steps[] = { -1.0f, 2.0f, 0.25f, 0.75f, -1.0f };1709 float steps[] = { -1.0f, 2.0f, 0.25f, 0.75f, -1.0f };
1710 1710
@@ -1715,9 +1715,9 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 4 unmodified lines
1715 glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections];1715 glm::vec3 thirdNormal = faceNormals[(i + 2) % numDirections];
1716 1716
1717 // pick two random point on opposite edges of the face1717 // pick two random point on opposite edges of the face
1718 glm::vec3 firstEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal + secondNormal) + 1718 glm::vec3 firstEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal + secondNormal) +
1719 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;1719 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;
1720 glm::vec3 secondEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal - secondNormal) + 1720 glm::vec3 secondEdgeIntersection = cubeCenter + (0.5f * cubeSide) * (faceNormal - secondNormal) +
1721 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;1721 (cubeSide * (randFloat() - 0.5f)) * thirdNormal;
1722 1722
1723 // compute the un-normalized axis for the capsule1723 // compute the un-normalized axis for the capsule
@@ -1742,7 +1742,7 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 18 unmodified lines
1742 if (numCollisions != 2) {1742 if (numCollisions != 2) {
1743 std::cout << __FILE__ << ":" << __LINE__1743 std::cout << __FILE__ << ":" << __LINE__
1744 << " ERROR: capsule should hit cube face at two spots."1744 << " ERROR: capsule should hit cube face at two spots."
1745 << " Expected collisions size of 2 but is actually " << numCollisions 1745 << " Expected collisions size of 2 but is actually " << numCollisions
1746 << ". faceNormal = " << faceNormal << std::endl;1746 << ". faceNormal = " << faceNormal << std::endl;
1747 break;1747 break;
1748 }1748 }
@@ -1764,33 +1764,33 @@ void ShapeColliderTests::capsuleTouchesAACube() { · 15 unmodified lines
1764 expectedContactPoints[0] = startPoint - capsuleRadius * faceNormal;1764 expectedContactPoints[0] = startPoint - capsuleRadius * faceNormal;
1765 expectedContactPoints[1] = firstEdgeIntersection - overlap * faceNormal;1765 expectedContactPoints[1] = firstEdgeIntersection - overlap * faceNormal;
1766 }1766 }
1767 1767
1768 // verify each contact1768 // verify each contact
1769 for (int k = 0; k < 2; ++k) {1769 for (int k = 0; k < 2; ++k) {
1770 CollisionInfo* collision = collisions.getCollision(k);1770 CollisionInfo* collision = collisions.getCollision(k);
1771 // penetration points from capsule into cube 1771 // penetration points from capsule into cube
1772 glm::vec3 expectedPenetration = - overlap * faceNormal;1772 glm::vec3 expectedPenetration = - overlap * faceNormal;
1773 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);1773 float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
1774 if (fabs(inaccuracy) > allowableError) {1774 if (fabsf(inaccuracy) > allowableError) {
1775 std::cout << __FILE__ << ":" << __LINE__1775 std::cout << __FILE__ << ":" << __LINE__
1776 << " ERROR: bad penetration: expected = " << expectedPenetration1776 << " ERROR: bad penetration: expected = " << expectedPenetration
1777 << " actual = " << collision->_penetration 1777 << " actual = " << collision->_penetration
1778 << " faceNormal = " << faceNormal1778 << " faceNormal = " << faceNormal
1779 << std::endl;1779 << std::endl;
1780 }1780 }
1781 1781
1782 // the order of the final contact points is undefined, so we 1782 // the order of the final contact points is undefined, so we
1783 // figure out which expected contact point is the closest to the real one 1783 // figure out which expected contact point is the closest to the real one
1784 // and then verify accuracy on that1784 // and then verify accuracy on that
1785 float length0 = glm::length(collision->_contactPoint - expectedContactPoints[0]);1785 float length0 = glm::length(collision->_contactPoint - expectedContactPoints[0]);
1786 float length1 = glm::length(collision->_contactPoint - expectedContactPoints[1]);1786 float length1 = glm::length(collision->_contactPoint - expectedContactPoints[1]);
1787 glm::vec3 expectedContactPoint = (length0 < length1) ? expectedContactPoints[0] : expectedContactPoints[1];1787 glm::vec3 expectedContactPoint = (length0 < length1) ? expectedContactPoints[0] : expectedContactPoints[1];
1788 // contactPoint is on surface of capsule1788 // contactPoint is on surface of capsule
1789 inaccuracy = (length0 < length1) ? length0 : length1;1789 inaccuracy = (length0 < length1) ? length0 : length1;
1790 if (fabs(inaccuracy) > allowableError) {1790 if (fabsf(inaccuracy) > allowableError) {
1791 std::cout << __FILE__ << ":" << __LINE__1791 std::cout << __FILE__ << ":" << __LINE__
1792 << " ERROR: bad contact: expectedContactPoint[" << k << "] = " << expectedContactPoint1792 << " ERROR: bad contact: expectedContactPoint[" << k << "] = " << expectedContactPoint
1793 << " actual = " << collision->_contactPoint 1793 << " actual = " << collision->_contactPoint
1794 << " faceNormal = " << faceNormal1794 << " faceNormal = " << faceNormal
1795 << std::endl;1795 << std::endl;
1796 }1796 }
@@ -1817,14 +1817,14 @@ void ShapeColliderTests::rayHitsSphere() { · 20 unmodified lines
1817 if (!sphere.findRayIntersection(intersection)) {1817 if (!sphere.findRayIntersection(intersection)) {
1818 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl;1818 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl;
1819 }1819 }
1820 1820
1821 float expectedDistance = startDistance - radius;1821 float expectedDistance = startDistance - radius;
1822 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;1822 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;
1823 if (relativeError > EPSILON) {1823 if (relativeError > EPSILON) {
1824 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray sphere intersection distance error = " << relativeError << std::endl;1824 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray sphere intersection distance error = " << relativeError << std::endl;
1825 }1825 }
1826 if (intersection._hitShape != &sphere) {1826 if (intersection._hitShape != &sphere) {
1827 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at sphere" 1827 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at sphere"
1828 << std::endl;1828 << std::endl;
1829 }1829 }
1830 }1830 }
@@ -1834,11 +1834,11 @@ void ShapeColliderTests::rayHitsSphere() { · 3 unmodified lines
1834 RayIntersectionInfo intersection;1834 RayIntersectionInfo intersection;
1835 intersection._rayStart = glm::vec3(startDistance, startDistance, 0.0f);1835 intersection._rayStart = glm::vec3(startDistance, startDistance, 0.0f);
1836 intersection._rayDirection = - glm::normalize(intersection._rayStart);1836 intersection._rayDirection = - glm::normalize(intersection._rayStart);
1837 1837
1838 if (!sphere.findRayIntersection(intersection)) {1838 if (!sphere.findRayIntersection(intersection)) {
1839 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl;1839 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl;
1840 }1840 }
1841 1841
1842 float expectedDistance = SQUARE_ROOT_OF_2 * startDistance - radius;1842 float expectedDistance = SQUARE_ROOT_OF_2 * startDistance - radius;
1843 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;1843 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;
1844 if (relativeError > EPSILON) {1844 if (relativeError > EPSILON) {
@@ -1864,15 +1864,15 @@ void ShapeColliderTests::rayHitsSphere() { · 19 unmodified lines
1864 1864
1865 sphere.setRadius(radius);1865 sphere.setRadius(radius);
1866 sphere.setTranslation(rotation * translation);1866 sphere.setTranslation(rotation * translation);
1867 1867
1868 if (!sphere.findRayIntersection(intersection)) {1868 if (!sphere.findRayIntersection(intersection)) {
1869 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl;1869 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl;
1870 }1870 }
1871 1871
1872 float expectedDistance = startDistance - radius;1872 float expectedDistance = startDistance - radius;
1873 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;1873 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;
1874 if (relativeError > EPSILON) {1874 if (relativeError > EPSILON) {
1875 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray sphere intersection distance error = " 1875 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray sphere intersection distance error = "
1876 << relativeError << std::endl;1876 << relativeError << std::endl;
1877 }1877 }
1878 }1878 }
@@ -1890,29 +1890,29 @@ void ShapeColliderTests::rayBarelyHitsSphere() { · 11 unmodified lines
1890 RayIntersectionInfo intersection;1890 RayIntersectionInfo intersection;
1891 intersection._rayStart = glm::vec3(-startDistance, radius - delta, 0.0f);1891 intersection._rayStart = glm::vec3(-startDistance, radius - delta, 0.0f);
1892 intersection._rayDirection = xAxis;1892 intersection._rayDirection = xAxis;
1893 1893
1894 // very simple ray along xAxis1894 // very simple ray along xAxis
1895 if (!sphere.findRayIntersection(intersection)) {1895 if (!sphere.findRayIntersection(intersection)) {
1896 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely hit sphere" << std::endl;1896 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely hit sphere" << std::endl;
1897 }1897 }
1898 if (intersection._hitShape != &sphere) {1898 if (intersection._hitShape != &sphere) {
1899 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at sphere" 1899 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at sphere"
1900 << std::endl;1900 << std::endl;
1901 }1901 }
1902 }1902 }
1903 1903
1904 {1904 {
1905 // translate and rotate the whole system... 1905 // translate and rotate the whole system...
1906 glm::vec3 axis = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f));1906 glm::vec3 axis = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f));
1907 glm::quat rotation = glm::angleAxis(0.987654321f, axis);1907 glm::quat rotation = glm::angleAxis(0.987654321f, axis);
1908 glm::vec3 translation(35.7f, 0.46f, -1.97f);1908 glm::vec3 translation(35.7f, 0.46f, -1.97f);
1909 1909
1910 RayIntersectionInfo intersection;1910 RayIntersectionInfo intersection;
1911 intersection._rayStart = rotation * (intersection._rayStart + translation);1911 intersection._rayStart = rotation * (intersection._rayStart + translation);
1912 intersection._rayDirection = rotation * intersection._rayDirection;1912 intersection._rayDirection = rotation * intersection._rayDirection;
1913 1913
1914 sphere.setTranslation(rotation * translation);1914 sphere.setTranslation(rotation * translation);
1915 1915
1916 // ...and test again1916 // ...and test again
1917 if (!sphere.findRayIntersection(intersection)) {1917 if (!sphere.findRayIntersection(intersection)) {
1918 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely hit sphere" << std::endl;1918 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely hit sphere" << std::endl;
@@ -1934,19 +1934,19 @@ void ShapeColliderTests::rayBarelyMissesSphere() { · 15 unmodified lines
1934 RayIntersectionInfo intersection;1934 RayIntersectionInfo intersection;
1935 intersection._rayStart = glm::vec3(-startDistance, radius + delta, 0.0f);1935 intersection._rayStart = glm::vec3(-startDistance, radius + delta, 0.0f);
1936 intersection._rayDirection = xAxis;1936 intersection._rayDirection = xAxis;
1937 1937
1938 // very simple ray along xAxis1938 // very simple ray along xAxis
1939 if (sphere.findRayIntersection(intersection)) {1939 if (sphere.findRayIntersection(intersection)) {
1940 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely miss sphere" << std::endl;1940 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely miss sphere" << std::endl;
1941 }1941 }
1942 if (intersection._hitDistance != FLT_MAX) {1942 if (intersection._hitDistance != FLT_MAX) {
1943 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" 1943 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss"
1944 << std::endl;1944 << std::endl;
1945 }1945 }
1946 }1946 }
1947 1947
1948 {1948 {
1949 // translate and rotate the whole system... 1949 // translate and rotate the whole system...
1950 float angle = 0.987654321f;1950 float angle = 0.987654321f;
1951 glm::vec3 axis = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f));1951 glm::vec3 axis = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f));
1952 glm::quat rotation = glm::angleAxis(angle, axis);1952 glm::quat rotation = glm::angleAxis(angle, axis);
@@ -1956,13 +1956,13 @@ void ShapeColliderTests::rayBarelyMissesSphere() { · 3 unmodified lines
1956 intersection._rayStart = rotation * (glm::vec3(-startDistance, radius + delta, 0.0f) + translation);1956 intersection._rayStart = rotation * (glm::vec3(-startDistance, radius + delta, 0.0f) + translation);
1957 intersection._rayDirection = rotation * xAxis;1957 intersection._rayDirection = rotation * xAxis;
1958 sphere.setTranslation(rotation * translation);1958 sphere.setTranslation(rotation * translation);
1959 1959
1960 // ...and test again1960 // ...and test again
1961 if (sphere.findRayIntersection(intersection)) {1961 if (sphere.findRayIntersection(intersection)) {
1962 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely miss sphere" << std::endl;1962 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely miss sphere" << std::endl;
1963 }1963 }
1964 if (intersection._hitDistance != FLT_MAX) {1964 if (intersection._hitDistance != FLT_MAX) {
1965 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" 1965 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss"
1966 << std::endl;1966 << std::endl;
1967 }1967 }
1968 if (intersection._hitShape != NULL) {1968 if (intersection._hitShape != NULL) {
@@ -1978,7 +1978,7 @@ void ShapeColliderTests::rayHitsCapsule() { · 9 unmodified lines
1978 glm::vec3 center(0.0f);1978 glm::vec3 center(0.0f);
1979 CapsuleShape capsule(radius, halfHeight);1979 CapsuleShape capsule(radius, halfHeight);
1980 1980
1981 // simple tests along xAxis 1981 // simple tests along xAxis
1982 { // toward capsule center1982 { // toward capsule center
1983 RayIntersectionInfo intersection;1983 RayIntersectionInfo intersection;
1984 intersection._rayStart = glm::vec3(startDistance, 0.0f, 0.0f);1984 intersection._rayStart = glm::vec3(startDistance, 0.0f, 0.0f);
@@ -1989,11 +1989,11 @@ void ShapeColliderTests::rayHitsCapsule() { · 4 unmodified lines
1989 float expectedDistance = startDistance - radius;1989 float expectedDistance = startDistance - radius;
1990 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;1990 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;
1991 if (relativeError > EPSILON) {1991 if (relativeError > EPSILON) {
1992 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " 1992 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = "
1993 << relativeError << std::endl;1993 << relativeError << std::endl;
1994 }1994 }
1995 if (intersection._hitShape != &capsule) {1995 if (intersection._hitShape != &capsule) {
1996 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at capsule" 1996 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at capsule"
1997 << std::endl;1997 << std::endl;
1998 }1998 }
1999 }1999 }
@@ -2008,7 +2008,7 @@ void ShapeColliderTests::rayHitsCapsule() { · 8 unmodified lines
2008 float expectedDistance = startDistance - radius;2008 float expectedDistance = startDistance - radius;
2009 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;2009 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;
2010 if (relativeError > EPSILON) {2010 if (relativeError > EPSILON) {
2011 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " 2011 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = "
2012 << relativeError << std::endl;2012 << relativeError << std::endl;
2013 }2013 }
2014 }2014 }
@@ -2024,7 +2024,7 @@ void ShapeColliderTests::rayHitsCapsule() { · 9 unmodified lines
2024 float expectedDistance = startDistance - radius;2024 float expectedDistance = startDistance - radius;
2025 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;2025 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;
2026 if (relativeError > EPSILON) {2026 if (relativeError > EPSILON) {
2027 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " 2027 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = "
2028 << relativeError << std::endl;2028 << relativeError << std::endl;
2029 }2029 }
2030 }2030 }
@@ -2041,7 +2041,7 @@ void ShapeColliderTests::rayHitsCapsule() { · 10 unmodified lines
2041 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;2041 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;
2042 // for edge cases we allow a LOT of error2042 // for edge cases we allow a LOT of error
2043 if (relativeError > EDGE_CASE_SLOP_FACTOR * EPSILON) {2043 if (relativeError > EDGE_CASE_SLOP_FACTOR * EPSILON) {
2044 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " 2044 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = "
2045 << relativeError << std::endl;2045 << relativeError << std::endl;
2046 }2046 }
2047 }2047 }
@@ -2057,7 +2057,7 @@ void ShapeColliderTests::rayHitsCapsule() { · 9 unmodified lines
2057 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;2057 float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance;
2058 // for edge cases we allow a LOT of error2058 // for edge cases we allow a LOT of error
2059 if (relativeError > EDGE_CASE_SLOP_FACTOR * EPSILON) {2059 if (relativeError > EDGE_CASE_SLOP_FACTOR * EPSILON) {
2060 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " 2060 std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = "
2061 << relativeError << std::endl;2061 << relativeError << std::endl;

299 more lines aren’t shown here.

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.