From 1b36d56b7afe6ab8da12be6cb6ea36f9b8d51be9 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 18 Jan 2016 16:31:36 -0800 Subject: [PATCH 01/42] Add shadowmap as a debug feature --- interface/src/Application.cpp | 5 ++- interface/src/Menu.cpp | 1 + interface/src/Menu.h | 1 + .../src/DeferredLightingEffect.cpp | 36 +++++++++++++------ .../render-utils/src/DeferredLightingEffect.h | 24 +++++++++---- .../render-utils/src/RenderDeferredTask.cpp | 3 ++ .../render-utils/src/RenderDeferredTask.h | 3 -- .../render-utils/src/RenderShadowTask.cpp | 5 +++ libraries/render/src/render/Context.cpp | 3 +- libraries/render/src/render/Context.h | 4 ++- 10 files changed, 62 insertions(+), 23 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7dcb863049..a6eaf4d42d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -95,6 +95,7 @@ #include #include #include +#include #include #include #include @@ -672,6 +673,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : initializeGL(); // Start rendering + _renderEngine->addTask(make_shared()); _renderEngine->addTask(make_shared()); _renderEngine->registerScene(_main3DScene); @@ -3825,9 +3827,10 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se renderContext.setArgs(renderArgs); bool occlusionStatus = Menu::getInstance()->isOptionChecked(MenuOption::DebugAmbientOcclusion); + bool shadowStatus = Menu::getInstance()->isOptionChecked(MenuOption::DebugShadows); bool antialiasingStatus = Menu::getInstance()->isOptionChecked(MenuOption::Antialiasing); bool showOwnedStatus = Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowOwned); - renderContext.setOptions(occlusionStatus, antialiasingStatus, showOwnedStatus); + renderContext.setOptions(occlusionStatus, antialiasingStatus, showOwnedStatus, shadowStatus); _renderEngine->setRenderContext(renderContext); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 377d97bc30..246a3c5bd1 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -326,6 +326,7 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, 0, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::WorldAxes); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DebugAmbientOcclusion); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DebugShadows); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Antialiasing); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, 0, true); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 6bf66f1200..15cf118192 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -188,6 +188,7 @@ namespace MenuOption { const QString CoupleEyelids = "Couple Eyelids"; const QString CrashInterface = "Crash Interface"; const QString DebugAmbientOcclusion = "Debug Ambient Occlusion"; + const QString DebugShadows = "Debug Shadows"; const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DeleteBookmark = "Delete Bookmark..."; const QString DisableActivityLogger = "Disable Activity Logger"; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 5af89e7afc..8d022c93ee 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -56,14 +56,21 @@ void DeferredLightingEffect::init() { _directionalAmbientSphereLightLocations = std::make_shared(); _directionalSkyboxLightLocations = std::make_shared(); + _directionalLightShadowLocations = std::make_shared(); + _directionalAmbientSphereLightShadowLocations = std::make_shared(); + _directionalSkyboxLightShadowLocations = std::make_shared(); + _pointLightLocations = std::make_shared(); _spotLightLocations = std::make_shared(); - // TODO: To use shadowmaps, replace directional_*_light_frag with directional_*_light_shadow_frag shaders. loadLightProgram(deferred_light_vert, directional_light_frag, false, _directionalLight, _directionalLightLocations); loadLightProgram(deferred_light_vert, directional_ambient_light_frag, false, _directionalAmbientSphereLight, _directionalAmbientSphereLightLocations); loadLightProgram(deferred_light_vert, directional_skybox_light_frag, false, _directionalSkyboxLight, _directionalSkyboxLightLocations); + loadLightProgram(deferred_light_vert, directional_light_shadow_frag, false, _directionalLightShadow, _directionalLightShadowLocations); + loadLightProgram(deferred_light_vert, directional_ambient_light_shadow_frag, false, _directionalAmbientSphereLightShadow, _directionalAmbientSphereLightShadowLocations); + loadLightProgram(deferred_light_vert, directional_skybox_light_shadow_frag, false, _directionalSkyboxLightShadow, _directionalSkyboxLightShadowLocations); + loadLightProgram(deferred_light_limited_vert, point_light_frag, true, _pointLight, _pointLightLocations); loadLightProgram(deferred_light_spot_vert, spot_light_frag, true, _spotLight, _spotLightLocations); @@ -289,18 +296,27 @@ void DeferredLightingEffect::render(RenderArgs* args) { { bool useSkyboxCubemap = (_skybox) && (_skybox->getCubemap()); - auto& program = _directionalLight; - LightLocationsPtr locations = _directionalLightLocations; + auto& program = _shadowMapStatus ? _directionalLightShadow : _directionalLight; + LightLocationsPtr locations = _shadowMapStatus ? _directionalLightShadowLocations : _directionalLightLocations; - // TODO: At some point bring back the shadows... // Setup the global directional pass pipeline { - if (useSkyboxCubemap) { - program = _directionalSkyboxLight; - locations = _directionalSkyboxLightLocations; - } else if (_ambientLightMode > -1) { - program = _directionalAmbientSphereLight; - locations = _directionalAmbientSphereLightLocations; + if (_shadowMapStatus) { + if (useSkyboxCubemap) { + program = _directionalSkyboxLightShadow; + locations = _directionalSkyboxLightShadowLocations; + } else if (_ambientLightMode > -1) { + program = _directionalAmbientSphereLightShadow; + locations = _directionalAmbientSphereLightShadowLocations; + } + } else { + if (useSkyboxCubemap) { + program = _directionalSkyboxLight; + locations = _directionalSkyboxLightLocations; + } else if (_ambientLightMode > -1) { + program = _directionalAmbientSphereLight; + locations = _directionalAmbientSphereLightLocations; + } } if (locations->shadowTransformBuffer >= 0) { diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index d11dee7d49..b254052fb2 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -53,27 +53,37 @@ public: void setGlobalSkybox(const model::SkyboxPointer& skybox); const LightStage& getLightStage() { return _lightStage; } + void setShadowMapStatus(bool enable) { _shadowMapStatus = enable; }; private: LightStage _lightStage; + bool _shadowMapStatus{ false }; DeferredLightingEffect() = default; model::MeshPointer _spotLightMesh; model::MeshPointer getSpotLightMesh(); - + gpu::PipelinePointer _directionalSkyboxLight; - LightLocationsPtr _directionalSkyboxLightLocations; - gpu::PipelinePointer _directionalAmbientSphereLight; - LightLocationsPtr _directionalAmbientSphereLightLocations; - gpu::PipelinePointer _directionalLight; - LightLocationsPtr _directionalLightLocations; + + gpu::PipelinePointer _directionalSkyboxLightShadow; + gpu::PipelinePointer _directionalAmbientSphereLightShadow; + gpu::PipelinePointer _directionalLightShadow; gpu::PipelinePointer _pointLight; - LightLocationsPtr _pointLightLocations; gpu::PipelinePointer _spotLight; + + LightLocationsPtr _directionalSkyboxLightLocations; + LightLocationsPtr _directionalAmbientSphereLightLocations; + LightLocationsPtr _directionalLightLocations; + + LightLocationsPtr _directionalSkyboxLightShadowLocations; + LightLocationsPtr _directionalAmbientSphereLightShadowLocations; + LightLocationsPtr _directionalLightShadowLocations; + + LightLocationsPtr _pointLightLocations; LightLocationsPtr _spotLightLocations; using Lights = std::vector; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index dc3e5c652b..71313b5dc4 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -175,6 +175,9 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend setToneMappingExposure(renderContext->getTone().exposure); setToneMappingToneCurve(renderContext->getTone().toneCurve); + // TODO: For now, lighting is controlled through a singleton, so it is distinct + DependencyManager::get()->setShadowMapStatus(renderContext->getShadowMapStatus()); + for (auto job : _jobs) { job.run(sceneContext, renderContext); } diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 4fe0c75198..96cc8d1329 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -131,15 +131,12 @@ public: void setDrawHitEffect(bool draw) { enableJob(_drawHitEffectJobIndex, draw); } bool doDrawHitEffect() const { return getEnableJob(_drawHitEffectJobIndex); } - void setOcclusionStatus(bool draw) { enableJob(_occlusionJobIndex, draw); } bool doOcclusionStatus() const { return getEnableJob(_occlusionJobIndex); } - void setAntialiasingStatus(bool draw) { enableJob(_antialiasingJobIndex, draw); } bool doAntialiasingStatus() const { return getEnableJob(_antialiasingJobIndex); } - void setToneMappingExposure(float exposure); float getToneMappingExposure() const; diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index b6b9f15f60..6f8940002a 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -120,6 +120,11 @@ void RenderShadowTask::run(const SceneContextPointer& sceneContext, const Render assert(sceneContext); RenderArgs* args = renderContext->getArgs(); + // This feature is in a debugging stage - it must be turned on explicitly + if (!renderContext->getShadowMapStatus()) { + return; + } + // sanity checks if (!sceneContext->_scene || !args) { return; diff --git a/libraries/render/src/render/Context.cpp b/libraries/render/src/render/Context.cpp index 8facaad1b2..0e07726eb4 100644 --- a/libraries/render/src/render/Context.cpp +++ b/libraries/render/src/render/Context.cpp @@ -21,9 +21,10 @@ RenderContext::RenderContext(ItemsConfig items, Tone tone, int drawStatus, bool { } -void RenderContext::setOptions(bool occlusion, bool fxaa, bool showOwned) { +void RenderContext::setOptions(bool occlusion, bool fxaa, bool showOwned, bool shadowMap) { _occlusionStatus = occlusion; _fxaaStatus = fxaa; + _shadowMapStatus = shadowMap; if (showOwned) { _drawStatus |= render::showNetworkStatusFlag; diff --git a/libraries/render/src/render/Context.h b/libraries/render/src/render/Context.h index 4eeba0ee08..c1d26d0ccb 100644 --- a/libraries/render/src/render/Context.h +++ b/libraries/render/src/render/Context.h @@ -83,7 +83,8 @@ public: bool getDrawHitEffect() { return _drawHitEffect; } bool getOcclusionStatus() { return _occlusionStatus; } bool getFxaaStatus() { return _fxaaStatus; } - void setOptions(bool occlusion, bool fxaa, bool showOwned); + bool getShadowMapStatus() { return _shadowMapStatus; } + void setOptions(bool occlusion, bool fxaa, bool showOwned, bool shadowMap); // Debugging int _deferredDebugMode; @@ -97,6 +98,7 @@ protected: bool _drawHitEffect; bool _occlusionStatus { false }; bool _fxaaStatus = { false }; + bool _shadowMapStatus = { false }; ItemsConfig _items; Tone _tone; From ff425f40aec6b1258bcaba856473281ca4bb28d8 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 18 Jan 2016 18:43:01 -0800 Subject: [PATCH 02/42] Fix shadow leaking scene items --- libraries/render/src/render/DrawTask.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 68e1841345..5e63f5fa56 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -235,6 +235,9 @@ void PipelineSortShapes::run(const SceneContextPointer& sceneContext, const Rend } void DepthSortShapes::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapesIDsBounds& inShapes, ShapesIDsBounds& outShapes) { + outShapes.clear(); + outShapes.reserve(inShapes.size()); + for (auto& pipeline : inShapes) { auto& inItems = pipeline.second; auto outItems = outShapes.find(pipeline.first); From 3c80002dfe08d8a397e1a1d2cb87e50444fc2c25 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 18 Jan 2016 20:10:52 -0800 Subject: [PATCH 03/42] Fix keylight frustum culling by calc internal state before use --- libraries/render-utils/src/LightStage.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 0392f16594..96abcab9f2 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -70,6 +70,9 @@ void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float near glm::mat4 ortho = glm::ortho(min.x, max.x, min.y, max.y, -max.z, -min.z); _frustum->setProjection(ortho); + // Calculate the frustum's internal state + _frustum->calculate(); + // Update the buffer _schemaBuffer.edit().projection = ortho; _schemaBuffer.edit().viewInverse = viewInverse.getMatrix(); From 7a5562abce9e289efe6efe9f6f4aecc6c9918ab1 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 18 Jan 2016 20:50:03 -0800 Subject: [PATCH 04/42] Do not cauterize bones in SHADOW_RENDER_MODE --- libraries/render-utils/src/MeshPartPayload.cpp | 13 +++++++------ libraries/render-utils/src/MeshPartPayload.h | 12 +++++++----- libraries/render-utils/src/RenderShadowTask.cpp | 8 ++++++-- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 3fe639b47f..d5ee1434bb 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -215,7 +215,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat } } -void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations) const { +void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, bool canCauterize) const { batch.setModelTransform(_drawTransform); } @@ -442,25 +442,25 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) const { } } -void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations) const { +void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, bool canCauterize) const { // Still relying on the raw data from the model const Model::MeshState& state = _model->_meshStates.at(_meshIndex); Transform transform; if (state.clusterBuffer) { - if (_model->_cauterizeBones) { + if (canCauterize && _model->getCauterizeBones()) { batch.setUniformBuffer(ShapePipeline::Slot::SKINNING_GPU, state.cauterizedClusterBuffer); } else { batch.setUniformBuffer(ShapePipeline::Slot::SKINNING_GPU, state.clusterBuffer); } } else { - if (_model->_cauterizeBones) { + if (canCauterize && _model->getCauterizeBones()) { transform = Transform(state.cauterizedClusterMatrices[0]); } else { transform = Transform(state.clusterMatrices[0]); } } - // transform.preTranslate(_modelPosition); + transform.preTranslate(_transform.getTranslation()); batch.setModelTransform(transform); } @@ -507,8 +507,9 @@ void ModelMeshPartPayload::render(RenderArgs* args) const { assert(locations); // Bind the model transform and the skinCLusterMatrices if needed + bool canCauterize = args->_renderMode != RenderArgs::SHADOW_RENDER_MODE; _model->updateClusterMatrices(_transform.getTranslation(), _transform.getRotation()); - bindTransform(batch, locations); + bindTransform(batch, locations, canCauterize); //Bind the index buffer and vertex buffer and Blend shapes if needed bindMesh(batch); diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index d771a57203..feccf7ee64 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -46,7 +46,7 @@ public: void drawCall(gpu::Batch& batch) const; virtual void bindMesh(gpu::Batch& batch) const; virtual void bindMaterial(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations) const; - virtual void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations) const; + virtual void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, bool canCauterize = true) const; // Payload resource cached values model::MeshPointer _drawMesh; @@ -88,15 +88,17 @@ public: // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch) const override; - void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations) const override; - + void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, bool canCauterize) const override; void initCache(); + Model* _model; + int _meshIndex; int _shapeID; - bool _isSkinned = false; - bool _isBlendShaped = false; + + bool _isSkinned{ false }; + bool _isBlendShaped{ false }; }; #endif // hifi_MeshPartPayload_h diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 6f8940002a..3f9654512d 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -138,20 +138,24 @@ void RenderShadowTask::run(const SceneContextPointer& sceneContext, const Render return; } + // Cache old render args ViewFrustum* viewFrustum = args->_viewFrustum; + RenderArgs::RenderMode mode = args->_renderMode; auto nearClip = viewFrustum->getNearClip(); const int SHADOW_NEAR_DEPTH = -2; const int SHADOW_FAR_DEPTH = 20; globalLight->shadow.setKeylightFrustum(viewFrustum, nearClip + SHADOW_NEAR_DEPTH, nearClip + SHADOW_FAR_DEPTH); - // Set the keylight frustum + // Set the keylight render args args->_viewFrustum = globalLight->shadow.getFrustum().get(); + args->_renderMode = RenderArgs::SHADOW_RENDER_MODE; for (auto job : _jobs) { job.run(sceneContext, renderContext); } - // Reset the view frustum + // Reset the render args args->_viewFrustum = viewFrustum; + args->_renderMode = mode; }; From 398f83be3f4086aba87ee0dd90be737ecc4b9382 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 19 Jan 2016 12:01:18 -0800 Subject: [PATCH 05/42] Change shadow debug buffer to reuse shadowMap tex --- libraries/gpu/src/gpu/Framebuffer.cpp | 4 ---- .../render-utils/src/DebugDeferredBuffer.cpp | 15 ++++++++++----- libraries/render-utils/src/model_shadow.slf | 4 ++-- libraries/render-utils/src/skin_model_shadow.slf | 4 ++-- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/libraries/gpu/src/gpu/Framebuffer.cpp b/libraries/gpu/src/gpu/Framebuffer.cpp index 404ffa0a91..779d70cc88 100755 --- a/libraries/gpu/src/gpu/Framebuffer.cpp +++ b/libraries/gpu/src/gpu/Framebuffer.cpp @@ -63,10 +63,6 @@ Framebuffer* Framebuffer::createShadowmap(uint16 width) { depthTexture->setSampler(Sampler(samplerDesc)); framebuffer->setDepthStencilBuffer(depthTexture, depthFormat); - // Use a render buffer to allow use of the DebugDeferredBuffer Job - gpu::TexturePointer colorbuffer{gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, width)}; - framebuffer->setRenderBuffer(0, colorbuffer); - return framebuffer; } diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index e76a843121..e1ee308883 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -72,10 +72,15 @@ static const std::string DEFAULT_LIGHTING_SHADER { " }" }; static const std::string DEFAULT_SHADOW_SHADER { - "uniform sampler2D shadowMapColor;" - // The actual shadowMap is a sampler2DShadow, so we cannot normally sample it + "uniform sampler2DShadow shadowMap;" "vec4 getFragmentColor() {" - " return vec4(texture(shadowMapColor, uv).xyz, 1.0);" + " for (int i = 255; i >= 0; --i) {" + " float depth = i / 255.0;" + " if (texture(shadowMap, vec3(uv, depth)) > 0.5) {" + " return vec4(vec3(depth), 1.0);" + " }" + " }" + " return vec4(vec3(0.0), 1.0);" " }" }; static const std::string DEFAULT_CUSTOM_SHADER { @@ -169,7 +174,7 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Modes mode, std::st slotBindings.insert(gpu::Shader::Binding("specularMap", Specular)); slotBindings.insert(gpu::Shader::Binding("depthMap", Depth)); slotBindings.insert(gpu::Shader::Binding("lightingMap", Lighting)); - slotBindings.insert(gpu::Shader::Binding("shadowMapColor", Shadow)); + slotBindings.insert(gpu::Shader::Binding("shadowMap", Shadow)); gpu::Shader::makeProgram(*program, slotBindings); auto pipeline = gpu::Pipeline::create(program, std::make_shared()); @@ -225,7 +230,7 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren batch.setResourceTexture(Specular, framebufferCache->getDeferredSpecularTexture()); batch.setResourceTexture(Depth, framebufferCache->getPrimaryDepthTexture()); batch.setResourceTexture(Lighting, framebufferCache->getLightingTexture()); - batch.setResourceTexture(Shadow, lightStage.lights[0]->shadow.framebuffer->getRenderBuffer(0)); + batch.setResourceTexture(Shadow, lightStage.lights[0]->shadow.framebuffer->getDepthStencilBuffer()); const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); const glm::vec2 bottomLeft(renderContext->_deferredDebugSize.x, renderContext->_deferredDebugSize.y); diff --git a/libraries/render-utils/src/model_shadow.slf b/libraries/render-utils/src/model_shadow.slf index fd35ec11d7..178ea7b387 100755 --- a/libraries/render-utils/src/model_shadow.slf +++ b/libraries/render-utils/src/model_shadow.slf @@ -15,6 +15,6 @@ layout(location = 0) out vec4 _fragColor; void main(void) { - // stencil in solid color for debugging - _fragColor = vec4(0.0, 0.0, 1.0, 1.0); + // pass-through to set z-buffer + _fragColor = vec4(1.0, 1.0, 1.0, 0.0); } diff --git a/libraries/render-utils/src/skin_model_shadow.slf b/libraries/render-utils/src/skin_model_shadow.slf index 85d1b7424b..178ea7b387 100644 --- a/libraries/render-utils/src/skin_model_shadow.slf +++ b/libraries/render-utils/src/skin_model_shadow.slf @@ -15,6 +15,6 @@ layout(location = 0) out vec4 _fragColor; void main(void) { - // stencil in solid color for debugging - _fragColor = vec4(1.0, 0.0, 0.0, 1.0); + // pass-through to set z-buffer + _fragColor = vec4(1.0, 1.0, 1.0, 0.0); } From 387a14b6b121f6c46afc068e07d9bfede3a53ff1 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 19 Jan 2016 12:01:40 -0800 Subject: [PATCH 06/42] Fix shadowMap vertical keylight edge case --- libraries/render-utils/src/LightStage.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 96abcab9f2..c9f3d55677 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -28,6 +28,8 @@ void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float near glm::quat orientation; if (direction == IDENTITY_UP) { orientation = glm::quat(glm::mat3(IDENTITY_RIGHT, IDENTITY_UP, IDENTITY_FRONT)); + } else if (direction == -IDENTITY_UP) { + orientation = glm::quat(glm::mat3(-IDENTITY_RIGHT, -IDENTITY_UP, IDENTITY_FRONT)); } else { auto side = glm::normalize(glm::cross(direction, IDENTITY_UP)); auto up = glm::normalize(glm::cross(side, direction)); From 27967f60645ba2a097ccce4698b6c6d5a6185783 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 19 Jan 2016 15:22:45 -0800 Subject: [PATCH 07/42] Use 4-sample PCF for shadowMap sampling --- libraries/render-utils/src/Shadow.slh | 42 ++++++++++----------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/libraries/render-utils/src/Shadow.slh b/libraries/render-utils/src/Shadow.slh index c0ca4be0fe..34825d1613 100755 --- a/libraries/render-utils/src/Shadow.slh +++ b/libraries/render-utils/src/Shadow.slh @@ -60,36 +60,26 @@ float fetchShadow(vec3 shadowTexcoord) { return texture(shadowMap, shadowTexcoord); } -vec2 samples[8] = vec2[8]( - vec2(-2.0, -2.0), - vec2(2.0, -2.0), - vec2(2.0, 2.0), - vec2(-2.0, 2.0), - vec2(1.0, 0.0), - vec2(0.0, 1.0), - vec2(-1.0, 0.0), - vec2(0.0, -1.0) +vec2 PCFkernel[4] = vec2[4]( + vec2(-1.5, 0.5), + vec2(0.5, 0.5), + vec2(-1.5, -1.5), + vec2(0.5, -1.5) ); -float evalShadowAttenuationSampling(vec4 shadowTexcoord) { +float evalShadowAttenuationPCF(vec4 position, vec4 shadowTexcoord) { + float pcfRadius = 3.0; float shadowScale = getShadowScale(); - float shadowAttenuation = (0.25 * ( - fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[0], 0.0)) + - fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[1], 0.0)) + - fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[2], 0.0)) + - fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[3], 0.0)) - )); + // Offset for efficient PCF, see http://http.developer.nvidia.com/GPUGems/gpugems_ch11.html + vec2 offset = pcfRadius * step(fract(position.xy), vec2(0.5, 0.5)); - // Check for early bailing - if ((shadowAttenuation > 0) && (shadowAttenuation < 1.0)) { - shadowAttenuation = 0.5 * shadowAttenuation + (0.125 * ( - fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[4], 0.0)) + - fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[5], 0.0)) + - fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[6], 0.0)) + - fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[7], 0.0)) - )); - } + float shadowAttenuation = (0.25 * ( + fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(offset + PCFkernel[0], 0.0)) + + fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(offset + PCFkernel[1], 0.0)) + + fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(offset + PCFkernel[2], 0.0)) + + fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(offset + PCFkernel[3], 0.0)) + )); return shadowAttenuation; } @@ -97,7 +87,7 @@ float evalShadowAttenuationSampling(vec4 shadowTexcoord) { float evalShadowAttenuation(vec4 position) { vec4 shadowTexcoord = evalShadowTexcoord(position); - return evalShadowAttenuationSampling(shadowTexcoord); + return evalShadowAttenuationPCF(position, shadowTexcoord); } <@endif@> From c794ae8da28a1717991be7d5a4dbc775663d162d Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 19 Jan 2016 15:36:25 -0800 Subject: [PATCH 08/42] Avoid shadow attenuation outside of mapped area --- libraries/render-utils/src/Shadow.slh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/render-utils/src/Shadow.slh b/libraries/render-utils/src/Shadow.slh index 34825d1613..43a20057cd 100755 --- a/libraries/render-utils/src/Shadow.slh +++ b/libraries/render-utils/src/Shadow.slh @@ -86,6 +86,11 @@ float evalShadowAttenuationPCF(vec4 position, vec4 shadowTexcoord) { float evalShadowAttenuation(vec4 position) { vec4 shadowTexcoord = evalShadowTexcoord(position); + if (shadowTexcoord.x < 0.0 || shadowTexcoord.x > 1.0 || + shadowTexcoord.y < 0.0 || shadowTexcoord.y > 1.0) { + // If a point is not in the map, do not attenuate + return 1.0; + } return evalShadowAttenuationPCF(position, shadowTexcoord); } From 3445b7fd2c19cafde66e6fc26117916ed3ba85cc Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 19 Jan 2016 18:32:24 -0800 Subject: [PATCH 09/42] Fix orientation aligned with Y --- libraries/render-utils/src/LightStage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index c9f3d55677..0f1f396471 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -27,9 +27,9 @@ void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float near const auto& direction = glm::normalize(_light->getDirection()); glm::quat orientation; if (direction == IDENTITY_UP) { - orientation = glm::quat(glm::mat3(IDENTITY_RIGHT, IDENTITY_UP, IDENTITY_FRONT)); + orientation = glm::quat(glm::mat3(-IDENTITY_RIGHT, IDENTITY_FRONT, -IDENTITY_UP)); } else if (direction == -IDENTITY_UP) { - orientation = glm::quat(glm::mat3(-IDENTITY_RIGHT, -IDENTITY_UP, IDENTITY_FRONT)); + orientation = glm::quat(glm::mat3(IDENTITY_RIGHT, IDENTITY_FRONT, IDENTITY_UP)); } else { auto side = glm::normalize(glm::cross(direction, IDENTITY_UP)); auto up = glm::normalize(glm::cross(side, direction)); From a92c512c1704814d04d201b6a016b8a6d7671f0d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 19 Jan 2016 19:49:34 -0800 Subject: [PATCH 10/42] move collision group/mask calculus into EntityItem --- interface/src/Application.cpp | 6 ++- interface/src/avatar/AvatarMotionState.cpp | 2 +- libraries/entities/src/EntityItem.cpp | 27 ++++++++++++ libraries/entities/src/EntityItem.h | 7 +-- .../entities/src/EntityItemProperties.cpp | 4 +- libraries/physics/src/EntityMotionState.cpp | 41 +++--------------- libraries/physics/src/PhysicsEngine.cpp | 43 +++---------------- libraries/physics/src/PhysicsEngine.h | 27 +++++------- libraries/shared/src/PhysicsHelpers.cpp | 41 ++++++++++++++++-- libraries/shared/src/PhysicsHelpers.h | 11 +++++ 10 files changed, 108 insertions(+), 101 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fa730c5d40..cfe6b1f6aa 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -92,6 +92,7 @@ #include #include #include +#include #include #include #include @@ -3135,7 +3136,7 @@ void Application::update(float deltaTime) { PerformanceTimer perfTimer("havestChanges"); if (_physicsEngine->hasOutgoingChanges()) { getEntities()->getTree()->withWriteLock([&] { - _entitySimulation.handleOutgoingChanges(_physicsEngine->getOutgoingChanges(), _physicsEngine->getSessionID()); + _entitySimulation.handleOutgoingChanges(_physicsEngine->getOutgoingChanges(), Physics::getSessionUUID()); avatarManager->handleOutgoingChanges(_physicsEngine->getOutgoingChanges()); }); @@ -4296,6 +4297,9 @@ bool Application::acceptURL(const QString& urlString, bool defaultUpload) { } void Application::setSessionUUID(const QUuid& sessionUUID) { + // HACK: until we swap the library dependency order between physics and entities + // we cache the sessionID in two distinct places for physics. + Physics::setSessionUUID(sessionUUID); // TODO: remove this one _physicsEngine->setSessionUUID(sessionUUID); } diff --git a/interface/src/avatar/AvatarMotionState.cpp b/interface/src/avatar/AvatarMotionState.cpp index 84f276529a..b361ea5e26 100644 --- a/interface/src/avatar/AvatarMotionState.cpp +++ b/interface/src/avatar/AvatarMotionState.cpp @@ -146,6 +146,6 @@ QUuid AvatarMotionState::getSimulatorID() const { // virtual void AvatarMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const { group = BULLET_COLLISION_GROUP_OTHER_AVATAR; - mask = PhysicsEngine::getCollisionMask(group); + mask = Physics::getDefaultCollisionMask(group); } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 093ad33dcb..24314e807d 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1507,6 +1507,33 @@ void EntityItem::updateCreated(uint64_t value) { } } +void EntityItem::computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask) const { + // TODO: detect attachment status and adopt group of wearer + if (_collisionless) { + group = BULLET_COLLISION_GROUP_COLLISIONLESS; + mask = 0; + } else { + if (_dynamic) { + group = BULLET_COLLISION_GROUP_DYNAMIC; + } else if (isMoving() || hasActions()) { + group = BULLET_COLLISION_GROUP_KINEMATIC; + } else { + group = BULLET_COLLISION_GROUP_STATIC; + } + + uint8_t userMask = getCollisionMask(); + if ((bool)(userMask & USER_COLLISION_GROUP_MY_AVATAR) != + (bool)(userMask & USER_COLLISION_GROUP_OTHER_AVATAR)) { + // asymmetric avatar collision mask bits + if (!getSimulatorID().isNull() && (!getSimulatorID().isNull()) && getSimulatorID() != Physics::getSessionUUID()) { + // someone else owns the simulation, so we toggle the avatar bits (swap interpretation) + userMask ^= USER_COLLISION_MASK_AVATARS | ~userMask; + } + } + mask = Physics::getDefaultCollisionMask(group) & (int16_t)(userMask); + } +} + void EntityItem::setSimulationOwner(const QUuid& id, quint8 priority) { if (wantTerseEditLogging() && (id != _simulationOwner.getID() || priority != _simulationOwner.getPriority())) { qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << id << priority; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 9be018183a..67af53615d 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -275,9 +275,10 @@ public: void setCollisionless(bool value) { _collisionless = value; } uint8_t getCollisionMask() const { return _collisionMask; } - uint8_t getFinalCollisionMask() const { return _collisionless ? 0 : _collisionMask; } void setCollisionMask(uint8_t value) { _collisionMask = value; } + void computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask) const; + bool getDynamic() const { return _dynamic; } void setDynamic(bool value) { _dynamic = value; } @@ -370,8 +371,8 @@ public: bool clearActions(EntitySimulation* simulation); void setActionData(QByteArray actionData); const QByteArray getActionData() const; - bool hasActions() { return !_objectActions.empty(); } - QList getActionIDs() { return _objectActions.keys(); } + bool hasActions() const { return !_objectActions.empty(); } + QList getActionIDs() const { return _objectActions.keys(); } QVariantMap getActionArguments(const QUuid& actionID) const; void deserializeActions(); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 0535621c85..a8f476554b 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -162,8 +162,8 @@ QString EntityItemProperties::getCollisionMaskAsString() const { void EntityItemProperties::setCollisionMaskFromString(const QString& maskString) { QVector groups = maskString.splitRef(','); uint8_t mask = 0x00; - for (auto group : groups) { - mask |= getCollisionGroupAsBitMask(group); + for (auto groupName : groups) { + mask |= getCollisionGroupAsBitMask(groupName); } _collisionMask = mask; _collisionMaskChanged = true; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 4e5f942265..5cffd031d0 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -82,7 +82,7 @@ EntityMotionState::~EntityMotionState() { void EntityMotionState::updateServerPhysicsVariables() { assert(entityTreeIsLocked()); - if (_entity->getSimulatorID() == PhysicsEngine::getSessionID()) { + if (_entity->getSimulatorID() == Physics::getSessionUUID()) { // don't slam these values if we are the simulation owner return; } @@ -113,7 +113,7 @@ bool EntityMotionState::handleEasyChanges(uint32_t& flags) { _outgoingPriority = NO_PRORITY; } else { _nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS; - if (PhysicsEngine::getSessionID() == _entity->getSimulatorID() || _entity->getSimulationPriority() >= _outgoingPriority) { + if (Physics::getSessionUUID() == _entity->getSimulatorID() || _entity->getSimulationPriority() >= _outgoingPriority) { // we own the simulation or our priority looses to (or ties with) remote _outgoingPriority = NO_PRORITY; } @@ -527,7 +527,7 @@ uint32_t EntityMotionState::getIncomingDirtyFlags() { if (dirtyFlags | Simulation::DIRTY_SIMULATOR_ID) { // when SIMULATOR_ID changes we must check for reinterpretation of asymmetric collision mask // bits for the avatar groups (e.g. MY_AVATAR vs OTHER_AVATAR) - uint8_t entityCollisionMask = _entity->getCollisionMask(); + uint8_t entityCollisionMask = _entity->getCollisionless() ? 0 : _entity->getCollisionMask(); if ((bool)(entityCollisionMask & USER_COLLISION_GROUP_MY_AVATAR) != (bool)(entityCollisionMask & USER_COLLISION_GROUP_OTHER_AVATAR)) { // bits are asymmetric --> flag for reinsertion in physics simulation @@ -622,39 +622,8 @@ QString EntityMotionState::getName() const { // virtual void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const { - group = BULLET_COLLISION_GROUP_STATIC; - if (_entity) { - if (_entity->getCollisionless()) { - group = BULLET_COLLISION_GROUP_COLLISIONLESS; - } - switch (computePhysicsMotionType()){ - case MOTION_TYPE_STATIC: - group = BULLET_COLLISION_GROUP_STATIC; - break; - case MOTION_TYPE_DYNAMIC: - group = BULLET_COLLISION_GROUP_DYNAMIC; - break; - case MOTION_TYPE_KINEMATIC: - group = BULLET_COLLISION_GROUP_KINEMATIC; - break; - default: - break; - } - } - - mask = PhysicsEngine::getCollisionMask(group); - if (_entity) { - uint8_t entityCollisionMask = _entity->getFinalCollisionMask(); - if ((bool)(entityCollisionMask & USER_COLLISION_GROUP_MY_AVATAR) != - (bool)(entityCollisionMask & USER_COLLISION_GROUP_OTHER_AVATAR)) { - // asymmetric avatar collision mask bits - if (!_entity->getSimulatorID().isNull() && _entity->getSimulatorID() != PhysicsEngine::getSessionID()) { - // someone else owns the simulation, so we swap the interpretation of the bits - entityCollisionMask ^= USER_COLLISION_MASK_AVATARS | ~entityCollisionMask; - } - } - mask &= (int16_t)(entityCollisionMask); - } + assert(_entity); + _entity->computeCollisionGroupAndFinalMask(group, mask); } void EntityMotionState::setOutgoingPriority(quint8 priority) { diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 691f2b89c5..0a7ef606ba 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -18,47 +18,10 @@ #include "ThreadSafeDynamicsWorld.h" #include "PhysicsLogging.h" -uint32_t PhysicsEngine::getNumSubsteps() { - return _numSubsteps; -} - -btHashMap _collisionMasks; - -void initCollisionMaskTable() { - if (_collisionMasks.size() == 0) { - // build table of masks with their group as the key - _collisionMasks.insert(btHashInt((int)BULLET_COLLISION_GROUP_DYNAMIC), BULLET_COLLISION_MASK_DYNAMIC); - _collisionMasks.insert(btHashInt((int)BULLET_COLLISION_GROUP_STATIC), BULLET_COLLISION_MASK_STATIC); - _collisionMasks.insert(btHashInt((int)BULLET_COLLISION_GROUP_KINEMATIC), BULLET_COLLISION_MASK_KINEMATIC); - _collisionMasks.insert(btHashInt((int)BULLET_COLLISION_GROUP_MY_AVATAR), BULLET_COLLISION_MASK_MY_AVATAR); - _collisionMasks.insert(btHashInt((int)BULLET_COLLISION_GROUP_OTHER_AVATAR), BULLET_COLLISION_MASK_OTHER_AVATAR); - _collisionMasks.insert(btHashInt((int)BULLET_COLLISION_GROUP_COLLISIONLESS), BULLET_COLLISION_MASK_COLLISIONLESS); - } -} - -// static -int16_t PhysicsEngine::getCollisionMask(int16_t group) { - const int16_t* mask = _collisionMasks.find(btHashInt((int)group)); - return mask ? *mask : BULLET_COLLISION_MASK_DEFAULT; -} - -QUuid _sessionID; - -// static -void PhysicsEngine::setSessionUUID(const QUuid& sessionID) { - _sessionID = sessionID; -} - -// static -const QUuid& PhysicsEngine::getSessionID() { - return _sessionID; -} - - PhysicsEngine::PhysicsEngine(const glm::vec3& offset) : _originOffset(offset), + _sessionID(), _myAvatarController(nullptr) { - initCollisionMaskTable(); } PhysicsEngine::~PhysicsEngine() { @@ -90,6 +53,10 @@ void PhysicsEngine::init() { } } +uint32_t PhysicsEngine::getNumSubsteps() { + return _numSubsteps; +} + // private void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { assert(motionState); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index c42fe2f66e..16c8456e55 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -45,16 +45,11 @@ typedef QVector CollisionEvents; class PhysicsEngine { public: - static int16_t getCollisionMask(int16_t group); - - uint32_t getNumSubsteps(); - PhysicsEngine(const glm::vec3& offset); ~PhysicsEngine(); void init(); - static void setSessionUUID(const QUuid& sessionID); - static const QUuid& getSessionID(); + uint32_t getNumSubsteps(); void removeObjects(const VectorOfMotionStates& objects); void removeObjects(const SetOfMotionStates& objects); // only called during teardown @@ -95,6 +90,8 @@ public: void removeAction(const QUuid actionID); void forEachAction(std::function actor); + void setSessionUUID(const QUuid& sessionID) { _sessionID = sessionID; } + private: void addObjectToDynamicsWorld(ObjectMotionState* motionState); void removeObjectFromDynamicsWorld(ObjectMotionState* motionState); @@ -111,23 +108,21 @@ private: ThreadSafeDynamicsWorld* _dynamicsWorld = NULL; btGhostPairCallback* _ghostPairCallback = NULL; - glm::vec3 _originOffset; - ContactMap _contactMap; - uint32_t _numContactFrames = 0; + CollisionEvents _collisionEvents; + QHash _objectActions; + + glm::vec3 _originOffset; + QUuid _sessionID; - /// character collisions CharacterController* _myAvatarController; + uint32_t _numContactFrames = 0; + uint32_t _numSubsteps; + bool _dumpNextStats = false; bool _hasOutgoingChanges = false; - CollisionEvents _collisionEvents; - - QHash _objectActions; - - - uint32_t _numSubsteps; }; typedef std::shared_ptr PhysicsEnginePointer; diff --git a/libraries/shared/src/PhysicsHelpers.cpp b/libraries/shared/src/PhysicsHelpers.cpp index 578c85683b..18accfd799 100644 --- a/libraries/shared/src/PhysicsHelpers.cpp +++ b/libraries/shared/src/PhysicsHelpers.cpp @@ -11,6 +11,9 @@ #include "PhysicsHelpers.h" #include "NumericalConstants.h" +#include + +#include "PhysicsCollisionGroups.h" // This chunk of code was copied from Bullet-2.82, so we include the Bullet license here: /* @@ -19,12 +22,12 @@ * * This software is provided 'as-is', without any express or implied warranty. * In no event will the authors be held liable for any damages arising from the use of this software. - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it freely, + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it freely, * subject to the following restrictions: * - * 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. - * If you use this software in a product, an acknowledgment in the product documentation would be appreciated but + * 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. + * If you use this software in a product, an acknowledgment in the product documentation would be appreciated but * is not required. * 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. @@ -56,3 +59,33 @@ glm::quat computeBulletRotationStep(const glm::vec3& angularVelocity, float time } return glm::quat(cosf(0.5f * speed * timeStep), axis.x, axis.y, axis.z); } +/* end Bullet code derivation*/ + +int16_t Physics::getDefaultCollisionMask(int16_t group) { + switch(group) { + case BULLET_COLLISION_GROUP_STATIC: + return BULLET_COLLISION_MASK_STATIC; + case BULLET_COLLISION_GROUP_DYNAMIC: + return BULLET_COLLISION_MASK_DYNAMIC; + case BULLET_COLLISION_GROUP_KINEMATIC: + return BULLET_COLLISION_MASK_KINEMATIC; + case BULLET_COLLISION_GROUP_MY_AVATAR: + return BULLET_COLLISION_MASK_MY_AVATAR; + case BULLET_COLLISION_GROUP_OTHER_AVATAR: + return BULLET_COLLISION_MASK_OTHER_AVATAR; + default: + break; + }; + return BULLET_COLLISION_MASK_COLLISIONLESS; +} + +QUuid _sessionID; + +void Physics::setSessionUUID(const QUuid& sessionID) { + _sessionID = sessionID; +} + +const QUuid& Physics::getSessionUUID() { + return _sessionID; +} + diff --git a/libraries/shared/src/PhysicsHelpers.h b/libraries/shared/src/PhysicsHelpers.h index 3b6fccdc99..28ded661f0 100644 --- a/libraries/shared/src/PhysicsHelpers.h +++ b/libraries/shared/src/PhysicsHelpers.h @@ -14,6 +14,10 @@ #include #include +#include + +// TODO: move everything in here to the physics library after the physics/entities library +// dependency order is swapped. const int PHYSICS_ENGINE_MAX_NUM_SUBSTEPS = 6; // Bullet will start to "lose time" at 10 FPS. const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 90.0f; @@ -21,4 +25,11 @@ const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 90.0f; // return incremental rotation (Bullet-style) caused by angularVelocity over timeStep glm::quat computeBulletRotationStep(const glm::vec3& angularVelocity, float timeStep); +namespace Physics { + int16_t getDefaultCollisionMask(int16_t group); + + void setSessionUUID(const QUuid& sessionID); + const QUuid& getSessionUUID(); +}; + #endif // hifi_PhysicsHelpers_h From a91c181a899194a0a91ba385d138fc8e7d8aa1dc Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 14 Jan 2016 16:05:48 -0800 Subject: [PATCH 11/42] MyAvatar: Recenter when the head turns away from the hips Compute HMD facing moving average. When the moving average diverges from the hips by more then 45 degrees, recenter the body. Also, the follow code has been changed, instead of a follow velocity being passed to the CharacterController a desired target is passed. The CharacterController homes toward it's target based on the time remaining. Any follow deltas applied to move the avatar's position closer to it's target is stored and re-applied to the bodySensorMatrix. This centralizes the moving/homing code to one place, the CharacterContoller. A new FollowHelper class was also introduced, it groups together the data and logic necessary to perform the re-centering/follow procedure. This "hopefully" makes it easier to maintain. --- interface/src/avatar/MyAvatar.cpp | 189 +++++++++--------- interface/src/avatar/MyAvatar.h | 27 ++- libraries/physics/src/BulletUtil.h | 42 ++++ libraries/physics/src/CharacterController.cpp | 59 +++++- libraries/physics/src/CharacterController.h | 10 +- libraries/shared/src/GLMHelpers.cpp | 20 ++ libraries/shared/src/GLMHelpers.h | 3 + tests/physics/src/BulletUtilTests.cpp | 62 +++++- 8 files changed, 299 insertions(+), 113 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b1688b8f9e..acd1728388 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -222,15 +222,13 @@ QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) { } void MyAvatar::reset(bool andReload) { - if (andReload) { qApp->setRawAvatarUpdateThreading(false); } // Reset dynamic state. _wasPushing = _isPushing = _isBraking = _billboardValid = false; - _followVelocity = Vectors::ZERO; - _followSpeed = 0.0f; + _follow.deactivate(); _skeletonModel.reset(); getHead()->reset(); _targetVelocity = glm::vec3(0.0f); @@ -263,9 +261,22 @@ void MyAvatar::reset(bool andReload) { void MyAvatar::update(float deltaTime) { + // update moving average of HMD facing in xz plane. + const float HMD_FACING_TIMESCALE = 4.0f; // very slow average + float tau = deltaTime / HMD_FACING_TIMESCALE; + _hmdSensorFacingMovingAverage = lerp(_hmdSensorFacingMovingAverage, _hmdSensorFacing, tau); + +#ifdef DEBUG_DRAW_HMD_MOVING_AVERAGE + glm::vec3 p = transformPoint(getSensorToWorldMatrix(), _hmdSensorPosition + glm::vec3(_hmdSensorFacingMovingAverage.x, 0.0f, _hmdSensorFacingMovingAverage.y)); + DebugDraw::getInstance().addMarker("facing-avg", getOrientation(), p, glm::vec4(1.0f)); + p = transformPoint(getSensorToWorldMatrix(), _hmdSensorPosition + glm::vec3(_hmdSensorFacing.x, 0.0f, _hmdSensorFacing.y)); + DebugDraw::getInstance().addMarker("facing", getOrientation(), p, glm::vec4(1.0f)); +#endif + if (_goToPending) { setPosition(_goToPosition); setOrientation(_goToOrientation); + _hmdSensorFacingMovingAverage = _hmdSensorFacing; // reset moving average _goToPending = false; // updateFromHMDSensorMatrix (called from paintGL) expects that the sensorToWorldMatrix is updated for any position changes // that happen between render and Application::update (which calls updateSensorToWorldMatrix to do so). @@ -366,46 +377,7 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) { _hmdSensorMatrix = hmdSensorMatrix; _hmdSensorPosition = extractTranslation(hmdSensorMatrix); _hmdSensorOrientation = glm::quat_cast(hmdSensorMatrix); -} - -void MyAvatar::updateHMDFollowVelocity() { - // compute offset to body's target position (in sensor-frame) - auto sensorBodyMatrix = deriveBodyFromHMDSensor(); - glm::vec3 offset = extractTranslation(sensorBodyMatrix) - extractTranslation(_bodySensorMatrix); - _followOffsetDistance = glm::length(offset); - - const float FOLLOW_TIMESCALE = 0.5f; - const float FOLLOW_THRESHOLD_SPEED = 0.2f; - const float FOLLOW_MIN_DISTANCE = 0.01f; - const float FOLLOW_THRESHOLD_DISTANCE = 0.2f; - const float FOLLOW_MAX_IDLE_DISTANCE = 0.1f; - - bool hmdIsAtRest = _hmdAtRestDetector.update(_hmdSensorPosition, _hmdSensorOrientation); - - _followOffsetDistance = glm::length(offset); - if (_followOffsetDistance < FOLLOW_MIN_DISTANCE) { - // close enough - _followOffsetDistance = 0.0f; - } else { - bool avatarIsMoving = glm::length(_velocity - _followVelocity) > FOLLOW_THRESHOLD_SPEED; - bool shouldFollow = (hmdIsAtRest || avatarIsMoving) && _followOffsetDistance > FOLLOW_MAX_IDLE_DISTANCE; - - glm::vec3 truncatedOffset = offset; - if (truncatedOffset.y < 0.0f) { - truncatedOffset.y = 0.0f; - } - float truncatedDistance = glm::length(truncatedOffset); - bool needsNewSpeed = truncatedDistance > FOLLOW_THRESHOLD_DISTANCE; - if (needsNewSpeed || (shouldFollow && _followSpeed == 0.0f)) { - // compute new speed - _followSpeed = _followOffsetDistance / FOLLOW_TIMESCALE; - } - if (_followSpeed > 0.0f) { - // to compute new velocity we must rotate offset into the world-frame - glm::quat sensorToWorldRotation = glm::normalize(glm::quat_cast(_sensorToWorldMatrix)); - _followVelocity = _followSpeed * glm::normalize(sensorToWorldRotation * offset); - } - } + _hmdSensorFacing = getFacingDir2D(_hmdSensorOrientation); } // best called at end of main loop, just before rendering. @@ -1058,63 +1030,21 @@ void MyAvatar::prepareForPhysicsSimulation() { _characterController.setTargetVelocity(getTargetVelocity()); _characterController.setPositionAndOrientation(getPosition(), getOrientation()); if (qApp->isHMDMode()) { - updateHMDFollowVelocity(); - } else if (_followSpeed > 0.0f) { - _followVelocity = Vectors::ZERO; - _followSpeed = 0.0f; + _follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix); + } else { + _follow.deactivate(); } - _characterController.setFollowVelocity(_followVelocity); } -void MyAvatar::harvestResultsFromPhysicsSimulation(float deltaType) { +void MyAvatar::harvestResultsFromPhysicsSimulation(float deltaTime) { glm::vec3 position = getPosition(); glm::quat orientation = getOrientation(); _characterController.getPositionAndOrientation(position, orientation); nextAttitude(position, orientation); - if (_followSpeed > 0.0f) { - adjustSensorTransform(); - setVelocity(_characterController.getLinearVelocity() + _followVelocity); - } else { - setVelocity(_characterController.getLinearVelocity()); - } + _bodySensorMatrix = _follow.postPhysicsUpdate(*this, _bodySensorMatrix); // now that physics has adjusted our position, we can update attachements. - Avatar::simulateAttachments(deltaType); -} - -void MyAvatar::adjustSensorTransform() { - // compute blendFactor of latest hmdShift - // which we'll use to blend the rotation part - float linearDistance = _characterController.getFollowTime() * _followSpeed; - float blendFactor = linearDistance < _followOffsetDistance ? linearDistance / _followOffsetDistance : 1.0f; - - auto newBodySensorMatrix = deriveBodyFromHMDSensor(); - auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix; - glm::quat finalBodyRotation = glm::normalize(glm::quat_cast(worldBodyMatrix)); - if (blendFactor >= 0.99f) { - // the "adjustment" is more or less complete so stop following - _followVelocity = Vectors::ZERO; - _followSpeed = 0.0f; - // and slam the body's transform anyway to eliminate any slight errors - glm::vec3 finalBodyPosition = extractTranslation(worldBodyMatrix); - nextAttitude(finalBodyPosition, finalBodyRotation); - _bodySensorMatrix = newBodySensorMatrix; - } else { - // physics already did the positional blending for us - glm::vec3 newBodyPosition = getPosition(); - // but the rotational part must be done manually - glm::quat newBodyRotation = glm::normalize(safeMix(getOrientation(), finalBodyRotation, blendFactor)); - nextAttitude(newBodyPosition, newBodyRotation); - - // interp sensor matrix toward the desired - glm::vec3 prevPosition = extractTranslation(_bodySensorMatrix); - glm::quat prevRotation = glm::normalize(glm::quat_cast(_bodySensorMatrix)); - glm::vec3 nextPosition = extractTranslation(newBodySensorMatrix); - glm::quat nextRotation = glm::normalize(glm::quat_cast(newBodySensorMatrix)); - _bodySensorMatrix = createMatFromQuatAndPos( - glm::normalize(safeMix(prevRotation, nextRotation, blendFactor)), - lerp(prevPosition, nextPosition, blendFactor)); - } + Avatar::simulateAttachments(deltaTime); } QString MyAvatar::getScriptedMotorFrame() const { @@ -1832,3 +1762,80 @@ void audioListenModeFromScriptValue(const QScriptValue& object, AudioListenerMod void MyAvatar::lateUpdatePalms() { Avatar::updatePalms(); } + + +static const float FOLLOW_TIME = 0.5f; + +void MyAvatar::FollowHelper::deactivate() { + _timeTotal = FOLLOW_TIME; + _timeRemaining = 0.0f; +} + +void MyAvatar::FollowHelper::activate() { + // TODO: the follow time should be proportional to the displacement. + _timeRemaining = FOLLOW_TIME; + _timeTotal = FOLLOW_TIME; +} + +bool MyAvatar::FollowHelper::isActive() const { + return _timeRemaining > 0.0f; +} + +bool MyAvatar::FollowHelper::shouldActivate(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { + + const float FOLLOW_ROTATION_THRESHOLD = cosf(PI / 4.0f); + + glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix); + if (glm::dot(myAvatar.getHMDSensorFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD) { + return true; + } + + const float CYLINDER_TOP = 0.1f; + const float CYLINDER_BOTTOM = -0.5f; + const float CYLINDER_RADIUS = 0.15f; + + glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); + glm::vec3 truncatedOffset(offset.x, 0.0f, offset.y); + float truncatedDistance = glm::length(truncatedOffset); + + return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM) || (truncatedDistance > CYLINDER_RADIUS); +} + +void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) { + _desiredBodyMatrix = desiredBodyMatrix; + if (!isActive() && shouldActivate(myAvatar, desiredBodyMatrix, currentBodyMatrix)) { + activate(); + } + + if (isActive()) { + glm::mat4 desiredWorldMatrix = myAvatar.getSensorToWorldMatrix() * _desiredBodyMatrix; + myAvatar.getCharacterController()->setFollowParameters(desiredWorldMatrix, _timeRemaining); + } else { + glm::mat4 currentWorldMatrix = myAvatar.getSensorToWorldMatrix() * currentBodyMatrix; + myAvatar.getCharacterController()->setFollowParameters(currentWorldMatrix, 0.0f); + } +} + +glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix) { + if (isActive()) { + float dt = myAvatar.getCharacterController()->getFollowTime(); + _timeRemaining -= dt; + + // apply follow displacement to the body matrix. + glm::vec3 worldLinearDisplacement = myAvatar.getCharacterController()->getFollowLinearDisplacement(); + glm::quat worldAngularDisplacement = myAvatar.getCharacterController()->getFollowAngularDisplacement(); + glm::quat sensorToWorld = glmExtractRotation(myAvatar.getSensorToWorldMatrix()); + glm::quat worldToSensor = glm::inverse(sensorToWorld); + + glm::vec3 sensorLinearDisplacement = worldToSensor * worldLinearDisplacement; + glm::quat sensorAngularDisplacement = worldToSensor * worldAngularDisplacement * sensorToWorld; + + glm::mat4 newBodyMat = createMatFromQuatAndPos(sensorAngularDisplacement * glmExtractRotation(currentBodyMatrix), + sensorLinearDisplacement + extractTranslation(currentBodyMatrix)); + return newBodyMat; + + } else { + return currentBodyMatrix; + } +} + diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 33d307f5c2..a32dfc298d 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -96,8 +96,10 @@ public: const glm::mat4& getHMDSensorMatrix() const { return _hmdSensorMatrix; } const glm::vec3& getHMDSensorPosition() const { return _hmdSensorPosition; } const glm::quat& getHMDSensorOrientation() const { return _hmdSensorOrientation; } + const glm::vec2& getHMDSensorFacingMovingAverage() const { return _hmdSensorFacingMovingAverage; } glm::mat4 getSensorToWorldMatrix() const; + // Pass a recent sample of the HMD to the avatar. // This can also update the avatar's position to follow the HMD // as it moves through the world. @@ -204,10 +206,10 @@ public: virtual void setAttachmentData(const QVector& attachmentData) override; MyCharacterController* getCharacterController() { return &_characterController; } + const MyCharacterController* getCharacterController() const { return &_characterController; } void prepareForPhysicsSimulation(); void harvestResultsFromPhysicsSimulation(float deltaTime); - void adjustSensorTransform(); const QString& getCollisionSoundURL() { return _collisionSoundURL; } void setCollisionSoundURL(const QString& url); @@ -295,11 +297,6 @@ private: float scale = 1.0f, bool isSoft = false, bool allowDuplicates = false, bool useSaved = true) override; - //void beginFollowingHMD(); - //bool shouldFollowHMD() const; - //void followHMD(float deltaTime); - void updateHMDFollowVelocity(); - bool cameraInsideHead() const; // These are made private for MyAvatar so that you will use the "use" methods instead @@ -367,6 +364,8 @@ private: glm::mat4 _hmdSensorMatrix; glm::quat _hmdSensorOrientation; glm::vec3 _hmdSensorPosition; + glm::vec2 _hmdSensorFacing; // facing vector in xz plane + glm::vec2 _hmdSensorFacingMovingAverage { 0, 0 }; // facing vector in xz plane // cache of the current body position and orientation of the avatar's body, // in sensor space. @@ -375,9 +374,19 @@ private: // used to transform any sensor into world space, including the _hmdSensorMat, or hand controllers. glm::mat4 _sensorToWorldMatrix; - glm::vec3 _followVelocity { Vectors::ZERO }; - float _followSpeed { 0.0f }; - float _followOffsetDistance { 0.0f }; + struct FollowHelper { + glm::mat4 _desiredBodyMatrix; + float _timeRemaining { 0.0f }; + float _timeTotal { 0.0f }; + + void deactivate(); + void activate(); + bool isActive() const; + bool shouldActivate(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; + void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix); + glm::mat4 postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix); + }; + FollowHelper _follow; bool _goToPending; glm::vec3 _goToPosition; diff --git a/libraries/physics/src/BulletUtil.h b/libraries/physics/src/BulletUtil.h index 52bf2c8b06..79761a5462 100644 --- a/libraries/physics/src/BulletUtil.h +++ b/libraries/physics/src/BulletUtil.h @@ -32,4 +32,46 @@ inline btQuaternion glmToBullet(const glm::quat& g) { return btQuaternion(g.x, g.y, g.z, g.w); } +inline btMatrix3x3 glmToBullet(const glm::mat3& m) { + return btMatrix3x3(m[0][0], m[1][0], m[2][0], + m[0][1], m[1][1], m[2][1], + m[0][2], m[1][2], m[2][2]); +} + +// btTransform does not contain a full 4x4 matrix, so this transform is lossy. +// Affine transformations are OK but perspective transformations are not. +inline btTransform glmToBullet(const glm::mat4& m) { + glm::mat3 m3(m); + return btTransform(glmToBullet(m3), glmToBullet(glm::vec3(m[3][0], m[3][1], m[3][2]))); +} + +inline glm::mat4 bulletToGLM(const btTransform& t) { + glm::mat4 m(glm::mat4::_null); + + const btMatrix3x3& basis = t.getBasis(); + // copy over 3x3 part + for (int r = 0; r < 3; r++) { + for (int c = 0; c < 3; c++) { + m[c][r] = basis[r][c]; + } + } + + // copy traslation part + btVector3 origin = t.getOrigin(); + m[3][0] = origin.getX(); + m[3][1] = origin.getY(); + m[3][2] = origin.getZ(); + + // set last row + m[0][3] = 0.0f; + m[1][3] = 0.0f; + m[2][3] = 0.0f; + m[3][3] = 1.0f; + return m; +} + +inline btVector3 rotateVector(const btQuaternion& q, const btVector3& vec) { + return glmToBullet(bulletToGLM(q) * bulletToGLM(vec)); +} + #endif // hifi_BulletUtil_h diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 7c2ca31f8f..81132d9ece 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -13,7 +13,6 @@ #include -#include "BulletUtil.h" #include "PhysicsCollisionGroups.h" #include "ObjectMotionState.h" @@ -21,7 +20,6 @@ const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f); const float JUMP_SPEED = 3.5f; const float MAX_FALL_HEIGHT = 20.0f; - // helper class for simple ray-traces from character class ClosestNotMe : public btCollisionWorld::ClosestRayResultCallback { public: @@ -50,7 +48,8 @@ CharacterController::CharacterController() { _floorDistance = MAX_FALL_HEIGHT; _walkVelocity.setValue(0.0f, 0.0f, 0.0f); - _followVelocity.setValue(0.0f, 0.0f, 0.0f); + _followDesiredBodyTransform.setIdentity(); + _followTimeRemaining = 0.0f; _jumpSpeed = JUMP_SPEED; _isOnGround = false; _isJumping = false; @@ -59,6 +58,8 @@ CharacterController::CharacterController() { _isPushingUp = false; _jumpToHoverStart = 0; _followTime = 0.0f; + _followLinearDisplacement = btVector3(0, 0, 0); + _followAngularDisplacement = btQuaternion::getIdentity(); _pendingFlags = PENDING_FLAG_UPDATE_SHAPE; @@ -189,12 +190,38 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { } } - // Rather than add _followVelocity to the velocity of the RigidBody, we explicitly teleport - // the RigidBody forward according to the formula: distance = rate * time - if (_followVelocity.length2() > 0.0f) { + // Dynamicaly compute a follow velocity to move this body toward the _followDesiredBodyTransform. + // Rather then add this velocity to velocity the RigidBody, we explicitly teleport the RigidBody towards its goal. + // This mirrors the computation done in MyAvatar::FollowHelper::postPhysicsUpdate(). + // These two computations must be kept in sync. + _followTimeRemaining -= dt; + if (_followTimeRemaining >= 0.005f) { btTransform bodyTransform = _rigidBody->getWorldTransform(); - bodyTransform.setOrigin(bodyTransform.getOrigin() + dt * _followVelocity); - _rigidBody->setWorldTransform(bodyTransform); + + btVector3 startPos = bodyTransform.getOrigin(); + btVector3 deltaPos = _followDesiredBodyTransform.getOrigin() - startPos; + btVector3 vel = deltaPos / _followTimeRemaining; + btVector3 linearDisplacement = vel * dt; + btVector3 endPos = startPos + linearDisplacement; + + btQuaternion startRot = bodyTransform.getRotation(); + glm::vec2 currentFacing = getFacingDir2D(bulletToGLM(startRot)); + glm::vec2 currentRight(currentFacing.y, -currentFacing.x); + glm::vec2 desiredFacing = getFacingDir2D(bulletToGLM(_followDesiredBodyTransform.getRotation())); + float deltaAngle = acosf(glm::clamp(glm::dot(currentFacing, desiredFacing), -1.0f, 1.0f)); + float angularVel = deltaAngle / _followTimeRemaining; + float sign = copysignf(1.0f, glm::dot(desiredFacing, currentRight)); + btQuaternion angularDisplacement = btQuaternion(btVector3(0.0f, 1.0f, 0.0f), sign * angularVel * dt); + btQuaternion endRot = angularDisplacement * startRot; + + // in order to accumulate displacement of avatar position, we need to take _shapeLocalOffset into account. + btVector3 shapeLocalOffset = glmToBullet(_shapeLocalOffset); + btVector3 swingDisplacement = rotateVector(endRot, -shapeLocalOffset) - rotateVector(startRot, -shapeLocalOffset); + + _followLinearDisplacement = linearDisplacement + swingDisplacement + _followLinearDisplacement; + _followAngularDisplacement = angularDisplacement * _followAngularDisplacement; + + _rigidBody->setWorldTransform(btTransform(endRot, endPos)); } _followTime += dt; } @@ -323,8 +350,17 @@ void CharacterController::setTargetVelocity(const glm::vec3& velocity) { _walkVelocity = glmToBullet(velocity); } -void CharacterController::setFollowVelocity(const glm::vec3& velocity) { - _followVelocity = glmToBullet(velocity); +void CharacterController::setFollowParameters(const glm::mat4& desiredWorldBodyMatrix, float timeRemaining) { + _followTimeRemaining = timeRemaining; + _followDesiredBodyTransform = glmToBullet(desiredWorldBodyMatrix) * btTransform(btQuaternion::getIdentity(), glmToBullet(_shapeLocalOffset)); +} + +glm::vec3 CharacterController::getFollowLinearDisplacement() const { + return bulletToGLM(_followLinearDisplacement); +} + +glm::quat CharacterController::getFollowAngularDisplacement() const { + return bulletToGLM(_followAngularDisplacement); } glm::vec3 CharacterController::getLinearVelocity() const { @@ -378,6 +414,9 @@ void CharacterController::preSimulation() { } } _followTime = 0.0f; + + _followLinearDisplacement = btVector3(0, 0, 0); + _followAngularDisplacement = btQuaternion::getIdentity(); } void CharacterController::postSimulation() { diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 7bdc35fc0b..a32425e3e7 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -18,6 +18,7 @@ #include #include +#include "BulletUtil.h" const uint32_t PENDING_FLAG_ADD_TO_SIMULATION = 1U << 0; const uint32_t PENDING_FLAG_REMOVE_FROM_SIMULATION = 1U << 1; @@ -66,8 +67,10 @@ public: void getPositionAndOrientation(glm::vec3& position, glm::quat& rotation) const; void setTargetVelocity(const glm::vec3& velocity); - void setFollowVelocity(const glm::vec3& velocity); + void setFollowParameters(const glm::mat4& desiredWorldMatrix, float timeRemaining); float getFollowTime() const { return _followTime; } + glm::vec3 getFollowLinearDisplacement() const; + glm::quat getFollowAngularDisplacement() const; glm::vec3 getLinearVelocity() const; @@ -87,7 +90,8 @@ protected: protected: btVector3 _currentUp; btVector3 _walkVelocity; - btVector3 _followVelocity; + btTransform _followDesiredBodyTransform; + btScalar _followTimeRemaining; btTransform _characterBodyTransform; glm::vec3 _shapeLocalOffset; @@ -105,6 +109,8 @@ protected: btScalar _jumpSpeed; btScalar _followTime; + btVector3 _followLinearDisplacement; + btQuaternion _followAngularDisplacement; bool _enabled; bool _isOnGround; diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index 101412bbf7..5adb9ca947 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -425,3 +425,23 @@ void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& seconda vAxisOut = glm::cross(wAxisOut, uAxisOut); } +glm::vec2 getFacingDir2D(const glm::quat& rot) { + glm::vec3 facing3D = rot * Vectors::UNIT_NEG_Z; + glm::vec2 facing2D(facing3D.x, facing3D.z); + if (glm::length(facing2D) <= 0.0001f) { + return glm::vec2(1, 0); + } else { + return glm::normalize(facing2D); + } +} + +glm::vec2 getFacingDir2D(const glm::mat4& m) { + glm::vec3 facing3D = transformVector(m, Vectors::UNIT_NEG_Z); + glm::vec2 facing2D(facing3D.x, facing3D.z); + if (glm::length(facing2D) <= 0.0001f) { + return glm::vec2(1, 0); + } else { + return glm::normalize(facing2D); + } +} + diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 55458e98a2..e9894a34b7 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -224,4 +224,7 @@ glm::vec3 transformVector(const glm::mat4& m, const glm::vec3& v); void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& secondaryAxis, glm::vec3& uAxisOut, glm::vec3& vAxisOut, glm::vec3& wAxisOut); +glm::vec2 getFacingDir2D(const glm::quat& rot); +glm::vec2 getFacingDir2D(const glm::mat4& m); + #endif // hifi_GLMHelpers_h diff --git a/tests/physics/src/BulletUtilTests.cpp b/tests/physics/src/BulletUtilTests.cpp index 132d655274..5496c6ea2b 100644 --- a/tests/physics/src/BulletUtilTests.cpp +++ b/tests/physics/src/BulletUtilTests.cpp @@ -15,6 +15,7 @@ #include #include +#include // Add additional qtest functionality (the include order is important!) #include "../QTestExtensions.h" @@ -46,12 +47,49 @@ void BulletUtilTests::fromBulletToGLM() { QCOMPARE(gQ.y, bQ.getY()); QCOMPARE(gQ.z, bQ.getZ()); QCOMPARE(gQ.w, bQ.getW()); + + // mat4 + btMatrix3x3 basis(bQ); + btVector3 origin(100.0f, 200.0f, 300.0f); + btTransform bM(basis, origin); + + glm::mat4 gM = bulletToGLM(bM); + + glm::vec3 translation = extractTranslation(gM); + QCOMPARE(translation.x, bM.getOrigin().getX()); + QCOMPARE(translation.y, bM.getOrigin().getY()); + QCOMPARE(translation.z, bM.getOrigin().getZ()); + + glm::quat rotation = glmExtractRotation(gM); + QCOMPARE(rotation.x, bM.getRotation().getX()); + QCOMPARE(rotation.y, bM.getRotation().getY()); + QCOMPARE(rotation.z, bM.getRotation().getZ()); + QCOMPARE(rotation.w, bM.getRotation().getW()); + + // As a sanity check, transform vectors by their corresponding matrices and compare the result. + btVector3 bX = bM * btVector3(1.0f, 0.0f, 0.0f); + btVector3 bY = bM * btVector3(0.0f, 1.0f, 0.0f); + btVector3 bZ = bM * btVector3(0.0f, 0.0f, 1.0f); + + glm::vec3 gX = transformPoint(gM, glm::vec3(1.0f, 0.0f, 0.0f)); + glm::vec3 gY = transformPoint(gM, glm::vec3(0.0f, 1.0f, 0.0f)); + glm::vec3 gZ = transformPoint(gM, glm::vec3(0.0f, 0.0f, 1.0f)); + + QCOMPARE(gX.x, bX.getX()); + QCOMPARE(gX.y, bX.getY()); + QCOMPARE(gX.z, bX.getZ()); + QCOMPARE(gY.x, bY.getX()); + QCOMPARE(gY.y, bY.getY()); + QCOMPARE(gY.z, bY.getZ()); + QCOMPARE(gZ.x, bZ.getX()); + QCOMPARE(gZ.y, bZ.getY()); + QCOMPARE(gZ.z, bZ.getZ()); } void BulletUtilTests::fromGLMToBullet() { glm::vec3 gV(1.23f, 4.56f, 7.89f); btVector3 bV = glmToBullet(gV); - + QCOMPARE(gV.x, bV.getX()); QCOMPARE(gV.y, bV.getY()); QCOMPARE(gV.z, bV.getZ()); @@ -66,4 +104,26 @@ void BulletUtilTests::fromGLMToBullet() { QCOMPARE(gQ.y, bQ.getY()); QCOMPARE(gQ.z, bQ.getZ()); QCOMPARE(gQ.w, bQ.getW()); + + // mat3 + glm::mat3 gM3 = glm::mat3_cast(gQ); + btMatrix3x3 bM3 = glmToBullet(gM3); + bM3.getRotation(bQ); + QCOMPARE(gQ.x, bQ.getX()); + QCOMPARE(gQ.y, bQ.getY()); + QCOMPARE(gQ.z, bQ.getZ()); + QCOMPARE(gQ.w, bQ.getW()); + + // mat4 + glm::mat4 gM4 = createMatFromQuatAndPos(gQ, gV); + btTransform bM4 = glmToBullet(gM4); + bQ = bM4.getRotation(); + bV = bM4.getOrigin(); + QCOMPARE(gQ.x, bQ.getX()); + QCOMPARE(gQ.y, bQ.getY()); + QCOMPARE(gQ.z, bQ.getZ()); + QCOMPARE(gQ.w, bQ.getW()); + QCOMPARE(gV.x, bV.getX()); + QCOMPARE(gV.y, bV.getY()); + QCOMPARE(gV.z, bV.getZ()); } From e00481ddfbc3a5ce38dc59a72431c492f68231ef Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 21 Jan 2016 17:17:28 -0800 Subject: [PATCH 12/42] use macdeployqt for fixup of components --- cmake/macros/InstallBesideConsole.cmake | 28 +++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/cmake/macros/InstallBesideConsole.cmake b/cmake/macros/InstallBesideConsole.cmake index e30a25a0f8..6c8969dded 100644 --- a/cmake/macros/InstallBesideConsole.cmake +++ b/cmake/macros/InstallBesideConsole.cmake @@ -14,7 +14,8 @@ macro(install_beside_console) # install this component beside the installed server-console executable if (APPLE) set(CONSOLE_APP_CONTENTS "${CONSOLE_INSTALL_APP_PATH}/Contents") - set(COMPONENT_DESTINATION "${CONSOLE_APP_CONTENTS}/MacOS/Components.app/Contents/MacOS") + set(COMPONENT_APP_PATH "${CONSOLE_APP_CONTENTS}/MacOS/Components.app") + set(COMPONENT_DESTINATION "${COMPONENT_APP_PATH}/Contents/MacOS") else () set(COMPONENT_DESTINATION ${CONSOLE_INSTALL_DIR}) endif () @@ -55,13 +56,28 @@ macro(install_beside_console) endif () if (APPLE) - # during the install phase, call fixup to drop the shared libraries for these components in the right place + find_program(MACDEPLOYQT_COMMAND macdeployqt PATHS "${QT_DIR}/bin" NO_DEFAULT_PATH) + + if (NOT MACDEPLOYQT_COMMAND AND (PRODUCTION_BUILD OR PR_BUILD)) + message(FATAL_ERROR "Could not find macdeployqt at ${QT_DIR}/bin.\ + It is required to produce an relocatable interface application.\ + Check that the environment variable QT_DIR points to your Qt installation.\ + ") + endif () + + # during the install phase, call macdeployqt to drop the shared libraries for these components in the right place + set(COMPONENTS_BUNDLE_PATH "\${CMAKE_INSTALL_PREFIX}/${COMPONENT_APP_PATH}") + string(REPLACE " " "\\ " ESCAPED_BUNDLE_NAME ${COMPONENTS_BUNDLE_PATH}) + set(EXECUTABLE_NEEDING_FIXUP "\${CMAKE_INSTALL_PREFIX}/${COMPONENT_DESTINATION}/${TARGET_NAME}") + string(REPLACE " " "\\ " ESCAPED_EXECUTABLE_NAME ${EXECUTABLE_NEEDING_FIXUP}) + install(CODE " - include(BundleUtilities) - fixup_bundle(\"${EXECUTABLE_NEEDING_FIXUP}\" \"\" \"${FIXUP_LIBS}\") - " COMPONENT ${SERVER_COMPONENT}) - endif () + execute_process(COMMAND ${MACDEPLOYQT_COMMAND} ${ESCAPED_BUNDLE_NAME} -verbose=2 -executable=${ESCAPED_EXECUTABLE_NAME})" + COMPONENT ${SERVER_COMPONENT} + ) + endif() + endif () # set variables used by manual ssleay library copy From ca8a832818231f8bc3ae004953ef4cd357bf782d Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 21 Jan 2016 17:27:45 -0800 Subject: [PATCH 13/42] CharacterController: added hard limit to follow displacement To prevent tunneling when the rigid body cannot reach it's target due to being blocked by a wall or some other obstacle. Also, added unit tests for physics/BulletUtil rotateVector and clampLength functions. --- libraries/physics/src/BulletUtil.h | 8 +++++ libraries/physics/src/CharacterController.cpp | 3 +- tests/physics/src/BulletUtilTests.cpp | 34 +++++++++++++++++++ tests/physics/src/BulletUtilTests.h | 2 ++ 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/libraries/physics/src/BulletUtil.h b/libraries/physics/src/BulletUtil.h index 79761a5462..0122e86288 100644 --- a/libraries/physics/src/BulletUtil.h +++ b/libraries/physics/src/BulletUtil.h @@ -74,4 +74,12 @@ inline btVector3 rotateVector(const btQuaternion& q, const btVector3& vec) { return glmToBullet(bulletToGLM(q) * bulletToGLM(vec)); } +inline btVector3 clampLength(const btVector3& v, const float& maxLength) { + if (v.length() > maxLength) { + return v.normalized() * maxLength; + } else { + return v; + } +} + #endif // hifi_BulletUtil_h diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 81132d9ece..72d8220d4f 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -194,6 +194,7 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { // Rather then add this velocity to velocity the RigidBody, we explicitly teleport the RigidBody towards its goal. // This mirrors the computation done in MyAvatar::FollowHelper::postPhysicsUpdate(). // These two computations must be kept in sync. + const float MAX_DISPLACEMENT = 0.5f * _radius; _followTimeRemaining -= dt; if (_followTimeRemaining >= 0.005f) { btTransform bodyTransform = _rigidBody->getWorldTransform(); @@ -201,7 +202,7 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { btVector3 startPos = bodyTransform.getOrigin(); btVector3 deltaPos = _followDesiredBodyTransform.getOrigin() - startPos; btVector3 vel = deltaPos / _followTimeRemaining; - btVector3 linearDisplacement = vel * dt; + btVector3 linearDisplacement = clampLength(vel * dt, MAX_DISPLACEMENT); // clamp displacement to prevent tunneling. btVector3 endPos = startPos + linearDisplacement; btQuaternion startRot = bodyTransform.getRotation(); diff --git a/tests/physics/src/BulletUtilTests.cpp b/tests/physics/src/BulletUtilTests.cpp index 5496c6ea2b..b81742df65 100644 --- a/tests/physics/src/BulletUtilTests.cpp +++ b/tests/physics/src/BulletUtilTests.cpp @@ -127,3 +127,37 @@ void BulletUtilTests::fromGLMToBullet() { QCOMPARE(gV.y, bV.getY()); QCOMPARE(gV.z, bV.getZ()); } + +void BulletUtilTests::rotateVectorTest() { + + float angle = 0.317f * PI; + btVector3 axis(1.23f, 2.34f, 3.45f); + axis.normalize(); + btQuaternion q(axis, angle); + + btVector3 xAxis(1.0f, 0.0f, 0.0f); + + btVector3 result0 = rotateVector(q, xAxis); + + btTransform m(q); + btVector3 result1 = m * xAxis; + + QCOMPARE(result0.getX(), result0.getX()); + QCOMPARE(result0.getY(), result1.getY()); + QCOMPARE(result0.getZ(), result1.getZ()); +} + +void BulletUtilTests::clampLengthTest() { + btVector3 vec(1.0f, 3.0f, 2.0f); + btVector3 clampedVec1 = clampLength(vec, 1.0f); + btVector3 clampedVec2 = clampLength(vec, 2.0f); + btVector3 normalizedVec = vec.normalized(); + + QCOMPARE(clampedVec1.getX(), normalizedVec.getX()); + QCOMPARE(clampedVec1.getY(), normalizedVec.getY()); + QCOMPARE(clampedVec1.getZ(), normalizedVec.getZ()); + + QCOMPARE(clampedVec2.getX(), normalizedVec.getX() * 2.0f); + QCOMPARE(clampedVec2.getY(), normalizedVec.getY() * 2.0f); + QCOMPARE(clampedVec2.getZ(), normalizedVec.getZ() * 2.0f); +} diff --git a/tests/physics/src/BulletUtilTests.h b/tests/physics/src/BulletUtilTests.h index e8fee1e473..3f19484a60 100644 --- a/tests/physics/src/BulletUtilTests.h +++ b/tests/physics/src/BulletUtilTests.h @@ -20,6 +20,8 @@ class BulletUtilTests : public QObject { private slots: void fromBulletToGLM(); void fromGLMToBullet(); + void rotateVectorTest(); + void clampLengthTest(); }; #endif // hifi_BulletUtilTests_h From 451464cb474613b51ebe199e2533798e72aa1a79 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 22 Jan 2016 09:41:46 -0800 Subject: [PATCH 14/42] check values in location updates for NaN before using them --- libraries/shared/src/AACube.cpp | 10 +++++ libraries/shared/src/AACube.h | 2 + libraries/shared/src/SpatiallyNestable.cpp | 50 ++++++++++++++++++++++ libraries/shared/src/Transform.cpp | 20 +++++++++ libraries/shared/src/Transform.h | 2 + 5 files changed, 84 insertions(+) diff --git a/libraries/shared/src/AACube.cpp b/libraries/shared/src/AACube.cpp index 4218826141..f40f506924 100644 --- a/libraries/shared/src/AACube.cpp +++ b/libraries/shared/src/AACube.cpp @@ -478,3 +478,13 @@ AACube& AACube::operator += (const glm::vec3& point) { return (*this); } + +bool AACube::containsNaN() const { + if ( _corner.x != _corner.x || _corner.y != _corner.y || _corner.z != _corner.z) { + return true; + } + if (_scale != _scale) { + return true; + } + return false; +} diff --git a/libraries/shared/src/AACube.h b/libraries/shared/src/AACube.h index fbbbe9992a..dab5dafdaa 100644 --- a/libraries/shared/src/AACube.h +++ b/libraries/shared/src/AACube.h @@ -66,6 +66,8 @@ public: AACube& operator += (const glm::vec3& point); + bool containsNaN() const; + private: glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const; glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index c03da7ff13..1de091ec09 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -314,6 +314,11 @@ glm::vec3 SpatiallyNestable::getPosition(int jointIndex, bool& success) const { } void SpatiallyNestable::setPosition(const glm::vec3& position, bool& success) { + // guard against introducing NaN into the transform + if (position.x != position.x || position.y != position.y || position.z != position.z) { + success = false; + return; + } Transform parentTransform = getParentTransform(success); Transform myWorldTransform; _transformLock.withWriteLock([&] { @@ -358,6 +363,15 @@ glm::quat SpatiallyNestable::getOrientation(int jointIndex, bool& success) const } void SpatiallyNestable::setOrientation(const glm::quat& orientation, bool& success) { + // guard against introducing NaN into the transform + if (orientation.x != orientation.x || + orientation.y != orientation.y || + orientation.z != orientation.z || + orientation.w != orientation.w) { + success = false; + return; + } + Transform parentTransform = getParentTransform(success); Transform myWorldTransform; _transformLock.withWriteLock([&] { @@ -408,6 +422,10 @@ const Transform SpatiallyNestable::getTransform(int jointIndex, bool& success) c } void SpatiallyNestable::setTransform(const Transform& transform, bool& success) { + if (transform.containsNaN()) { + success = false; + return; + } Transform parentTransform = getParentTransform(success); _transformLock.withWriteLock([&] { Transform::inverseMult(_transform, parentTransform, transform); @@ -432,6 +450,11 @@ glm::vec3 SpatiallyNestable::getScale(int jointIndex) const { } void SpatiallyNestable::setScale(const glm::vec3& scale) { + // guard against introducing NaN into the transform + if (scale.x != scale.x || scale.y != scale.y || scale.z != scale.z) { + qDebug() << "SpatiallyNestable::setLocalScale -- scale contains NaN"; + return; + } // TODO: scale _transformLock.withWriteLock([&] { _transform.setScale(scale); @@ -448,6 +471,11 @@ const Transform SpatiallyNestable::getLocalTransform() const { } void SpatiallyNestable::setLocalTransform(const Transform& transform) { + // guard against introducing NaN into the transform + if (transform.containsNaN()) { + qDebug() << "SpatiallyNestable::setLocalTransform -- transform contains NaN"; + return; + } _transformLock.withWriteLock([&] { _transform = transform; }); @@ -463,6 +491,11 @@ glm::vec3 SpatiallyNestable::getLocalPosition() const { } void SpatiallyNestable::setLocalPosition(const glm::vec3& position) { + // guard against introducing NaN into the transform + if (position.x != position.x || position.y != position.y || position.z != position.z) { + qDebug() << "SpatiallyNestable::setLocalPosition -- position contains NaN"; + return; + } _transformLock.withWriteLock([&] { _transform.setTranslation(position); }); @@ -478,6 +511,14 @@ glm::quat SpatiallyNestable::getLocalOrientation() const { } void SpatiallyNestable::setLocalOrientation(const glm::quat& orientation) { + // guard against introducing NaN into the transform + if (orientation.x != orientation.x || + orientation.y != orientation.y || + orientation.z != orientation.z || + orientation.w != orientation.w) { + qDebug() << "SpatiallyNestable::setLocalOrientation -- orientation contains NaN"; + return; + } _transformLock.withWriteLock([&] { _transform.setRotation(orientation); }); @@ -494,6 +535,11 @@ glm::vec3 SpatiallyNestable::getLocalScale() const { } void SpatiallyNestable::setLocalScale(const glm::vec3& scale) { + // guard against introducing NaN into the transform + if (scale.x != scale.x || scale.y != scale.y || scale.z != scale.z) { + qDebug() << "SpatiallyNestable::setLocalScale -- scale contains NaN"; + return; + } // TODO: scale _transformLock.withWriteLock([&] { _transform.setScale(scale); @@ -561,6 +607,10 @@ AACube SpatiallyNestable::getMaximumAACube(bool& success) const { } void SpatiallyNestable::setQueryAACube(const AACube& queryAACube) { + if (queryAACube.containsNaN()) { + qDebug() << "SpatiallyNestable::setQueryAACube -- cube contains NaN"; + return; + } _queryAACube = queryAACube; if (queryAACube.getScale() > 0.0f) { _queryAACubeSet = true; diff --git a/libraries/shared/src/Transform.cpp b/libraries/shared/src/Transform.cpp index c51b3dae4b..9312191922 100644 --- a/libraries/shared/src/Transform.cpp +++ b/libraries/shared/src/Transform.cpp @@ -150,3 +150,23 @@ QJsonObject Transform::toJson(const Transform& transform) { } return result; } + +bool Transform::containsNaN() const { + if (_rotation.x != _rotation.x || + _rotation.y != _rotation.y || + _rotation.z != _rotation.z || + _rotation.w != _rotation.w) { + return true; + } + if (_scale.x != _scale.x || + _scale.y != _scale.y || + _scale.z != _scale.z) { + return true; + } + if (_translation.x != _translation.x || + _translation.y != _translation.y || + _translation.z != _translation.z) { + return true; + } + return false; +} diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index 310e2d0409..1024173cbd 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -145,6 +145,8 @@ public: Vec4 transform(const Vec4& pos) const; Vec3 transform(const Vec3& pos) const; + bool containsNaN() const; + protected: enum Flag { From d8fb61e820628b29c2c676e832c3bc1d789762f7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 21 Jan 2016 17:30:04 -0800 Subject: [PATCH 15/42] fix crash when deleting entities quickly --- interface/src/Application.cpp | 5 ++- libraries/entities/src/EntitySimulation.cpp | 7 +++ .../entities/src/SimpleEntitySimulation.cpp | 4 ++ .../physics/src/PhysicalEntitySimulation.cpp | 45 +++++++++++++------ .../physics/src/PhysicalEntitySimulation.h | 1 + 5 files changed, 47 insertions(+), 15 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4a4c9c6bc7..2266463962 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3089,13 +3089,14 @@ void Application::update(float deltaTime) { static VectorOfMotionStates motionStates; _entitySimulation.getObjectsToRemoveFromPhysics(motionStates); _physicsEngine->removeObjects(motionStates); + _entitySimulation.deleteObjectsRemovedFromPhysics(); - getEntities()->getTree()->withWriteLock([&] { + getEntities()->getTree()->withReadLock([&] { _entitySimulation.getObjectsToAddToPhysics(motionStates); _physicsEngine->addObjects(motionStates); }); - getEntities()->getTree()->withWriteLock([&] { + getEntities()->getTree()->withReadLock([&] { _entitySimulation.getObjectsToChange(motionStates); VectorOfMotionStates stillNeedChange = _physicsEngine->changeObjects(motionStates); _entitySimulation.setObjectsToChange(stillNeedChange); diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index ab29cfb2a4..23e5b99337 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -48,6 +48,7 @@ void EntitySimulation::takeEntitiesToDelete(VectorOfEntities& entitiesToDelete) } void EntitySimulation::removeEntityInternal(EntityItemPointer entity) { + QMutexLocker lock(&_mutex); // remove from all internal lists except _entitiesToDelete _mortalEntities.remove(entity); _entitiesToUpdate.remove(entity); @@ -61,6 +62,7 @@ void EntitySimulation::prepareEntityForDelete(EntityItemPointer entity) { assert(entity); assert(entity->isDead()); if (entity->isSimulated()) { + QMutexLocker lock(&_mutex); entity->clearActions(this); removeEntityInternal(entity); _entitiesToDelete.insert(entity); @@ -69,11 +71,13 @@ void EntitySimulation::prepareEntityForDelete(EntityItemPointer entity) { void EntitySimulation::addEntityInternal(EntityItemPointer entity) { if (entity->isMoving() && !entity->getPhysicsInfo()) { + QMutexLocker lock(&_mutex); _simpleKinematicEntities.insert(entity); } } void EntitySimulation::changeEntityInternal(EntityItemPointer entity) { + QMutexLocker lock(&_mutex); if (entity->isMoving() && !entity->getPhysicsInfo()) { _simpleKinematicEntities.insert(entity); } else { @@ -86,6 +90,7 @@ void EntitySimulation::expireMortalEntities(const quint64& now) { if (now > _nextExpiry) { // only search for expired entities if we expect to find one _nextExpiry = quint64(-1); + QMutexLocker lock(&_mutex); SetOfEntities::iterator itemItr = _mortalEntities.begin(); while (itemItr != _mortalEntities.end()) { EntityItemPointer entity = *itemItr; @@ -108,6 +113,7 @@ void EntitySimulation::expireMortalEntities(const quint64& now) { // protected void EntitySimulation::callUpdateOnEntitiesThatNeedIt(const quint64& now) { PerformanceTimer perfTimer("updatingEntities"); + QMutexLocker lock(&_mutex); SetOfEntities::iterator itemItr = _entitiesToUpdate.begin(); while (itemItr != _entitiesToUpdate.end()) { EntityItemPointer entity = *itemItr; @@ -124,6 +130,7 @@ void EntitySimulation::callUpdateOnEntitiesThatNeedIt(const quint64& now) { // protected void EntitySimulation::sortEntitiesThatMoved() { + QMutexLocker lock(&_mutex); // NOTE: this is only for entities that have been moved by THIS EntitySimulation. // External changes to entity position/shape are expected to be sorted outside of the EntitySimulation. PerformanceTimer perfTimer("sortingEntities"); diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index 3b2523bc92..120b536161 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -23,6 +23,7 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { // has finished simulating it. auto nodeList = DependencyManager::get(); + QMutexLocker lock(&_mutex); SetOfEntities::iterator itemItr = _entitiesWithSimulator.begin(); while (itemItr != _entitiesWithSimulator.end()) { EntityItemPointer entity = *itemItr; @@ -48,18 +49,21 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { void SimpleEntitySimulation::addEntityInternal(EntityItemPointer entity) { EntitySimulation::addEntityInternal(entity); if (!entity->getSimulatorID().isNull()) { + QMutexLocker lock(&_mutex); _entitiesWithSimulator.insert(entity); } } void SimpleEntitySimulation::removeEntityInternal(EntityItemPointer entity) { EntitySimulation::removeEntityInternal(entity); + QMutexLocker lock(&_mutex); _entitiesWithSimulator.remove(entity); } void SimpleEntitySimulation::changeEntityInternal(EntityItemPointer entity) { EntitySimulation::changeEntityInternal(entity); if (!entity->getSimulatorID().isNull()) { + QMutexLocker lock(&_mutex); _entitiesWithSimulator.insert(entity); } entity->clearDirtyFlags(); diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index a677cfae4d..d2c91f29dd 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -43,6 +43,7 @@ void PhysicalEntitySimulation::updateEntitiesInternal(const quint64& now) { } void PhysicalEntitySimulation::addEntityInternal(EntityItemPointer entity) { + QMutexLocker lock(&_mutex); assert(entity); assert(!entity->isDead()); if (entity->shouldBePhysical()) { @@ -57,6 +58,7 @@ void PhysicalEntitySimulation::addEntityInternal(EntityItemPointer entity) { void PhysicalEntitySimulation::removeEntityInternal(EntityItemPointer entity) { EntitySimulation::removeEntityInternal(entity); + QMutexLocker lock(&_mutex); _entitiesToAddToPhysics.remove(entity); EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); @@ -78,8 +80,7 @@ void PhysicalEntitySimulation::takeEntitiesToDelete(VectorOfEntities& entitiesTo // rather than do it here EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (motionState) { - delete motionState; - entity->setPhysicsInfo(nullptr); + _entitiesToRemoveFromPhysics.insert(entity); } } _entitiesToDelete.clear(); @@ -87,6 +88,7 @@ void PhysicalEntitySimulation::takeEntitiesToDelete(VectorOfEntities& entitiesTo void PhysicalEntitySimulation::changeEntityInternal(EntityItemPointer entity) { // queue incoming changes: from external sources (script, EntityServer, etc) to physics engine + QMutexLocker lock(&_mutex); assert(entity); EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (motionState) { @@ -119,7 +121,7 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { // while it is in the middle of a simulation step. As it is, we're probably in shutdown mode // anyway, so maybe the simulation was already properly shutdown? Cross our fingers... - // first disconnect each MotionStates from its Entity + // copy everything into _entitiesToDelete for (auto stateItr : _physicalObjects) { EntityMotionState* motionState = static_cast(&(*stateItr)); _entitiesToDelete.insert(motionState->getEntity()); @@ -134,8 +136,8 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { for (auto entity : _entitiesToDelete) { EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (motionState) { - delete motionState; entity->setPhysicsInfo(nullptr); + delete motionState; } } @@ -158,22 +160,39 @@ void PhysicalEntitySimulation::prepareEntityForDelete(EntityItemPointer entity) // end EntitySimulation overrides void PhysicalEntitySimulation::getObjectsToRemoveFromPhysics(VectorOfMotionStates& result) { - _entitiesToRelease.clear(); result.clear(); QMutexLocker lock(&_mutex); for (auto entity: _entitiesToRemoveFromPhysics) { - EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); - if (motionState) { - _pendingChanges.remove(motionState); - _physicalObjects.remove(motionState); - result.push_back(motionState); - } + // make sure it isn't on any side lists _entitiesToAddToPhysics.remove(entity); - if (entity->isDead()) { + + EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); + assert(motionState); + _pendingChanges.remove(motionState); + _physicalObjects.remove(motionState); + result.push_back(motionState); + _entitiesToRelease.insert(entity); + + if (entity->isSimulated() && entity->isDead()) { _entitiesToDelete.insert(entity); } } - _entitiesToRemoveFromPhysics.swap(_entitiesToRelease); + _entitiesToRemoveFromPhysics.clear(); +} + +void PhysicalEntitySimulation::deleteObjectsRemovedFromPhysics() { + QMutexLocker lock(&_mutex); + for (auto entity: _entitiesToRelease) { + EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); + assert(motionState); + entity->setPhysicsInfo(nullptr); + delete motionState; + + if (entity->isSimulated() && entity->isDead()) { + _entitiesToDelete.insert(entity); + } + } + _entitiesToRelease.clear(); } void PhysicalEntitySimulation::getObjectsToAddToPhysics(VectorOfMotionStates& result) { diff --git a/libraries/physics/src/PhysicalEntitySimulation.h b/libraries/physics/src/PhysicalEntitySimulation.h index 1c783d2f31..7138fb924c 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.h +++ b/libraries/physics/src/PhysicalEntitySimulation.h @@ -49,6 +49,7 @@ public: virtual void prepareEntityForDelete(EntityItemPointer entity) override; void getObjectsToRemoveFromPhysics(VectorOfMotionStates& result); + void deleteObjectsRemovedFromPhysics(); void getObjectsToAddToPhysics(VectorOfMotionStates& result); void setObjectsToChange(const VectorOfMotionStates& objectsToChange); void getObjectsToChange(VectorOfMotionStates& result); From 6b15beb88ad9735a645fc2b503d45f9f539ffef2 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 22 Jan 2016 10:36:21 -0800 Subject: [PATCH 16/42] use isNaN rather than a self-comparison --- libraries/shared/src/AACube.cpp | 2 +- libraries/shared/src/SpatiallyNestable.cpp | 18 ++++++------------ libraries/shared/src/Transform.cpp | 13 +++---------- 3 files changed, 10 insertions(+), 23 deletions(-) diff --git a/libraries/shared/src/AACube.cpp b/libraries/shared/src/AACube.cpp index f40f506924..df50ab0e4c 100644 --- a/libraries/shared/src/AACube.cpp +++ b/libraries/shared/src/AACube.cpp @@ -480,7 +480,7 @@ AACube& AACube::operator += (const glm::vec3& point) { } bool AACube::containsNaN() const { - if ( _corner.x != _corner.x || _corner.y != _corner.y || _corner.z != _corner.z) { + if (isNaN(_corner.x) || isNaN(_corner.y) || isNaN(_corner.z)) { return true; } if (_scale != _scale) { diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 1de091ec09..cb29db47aa 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -315,7 +315,7 @@ glm::vec3 SpatiallyNestable::getPosition(int jointIndex, bool& success) const { void SpatiallyNestable::setPosition(const glm::vec3& position, bool& success) { // guard against introducing NaN into the transform - if (position.x != position.x || position.y != position.y || position.z != position.z) { + if (isNaN(position.x) || isNaN(position.y) || isNaN(position.z)) { success = false; return; } @@ -364,10 +364,7 @@ glm::quat SpatiallyNestable::getOrientation(int jointIndex, bool& success) const void SpatiallyNestable::setOrientation(const glm::quat& orientation, bool& success) { // guard against introducing NaN into the transform - if (orientation.x != orientation.x || - orientation.y != orientation.y || - orientation.z != orientation.z || - orientation.w != orientation.w) { + if (isNaN(orientation.x) || isNaN(orientation.y) || isNaN(orientation.z) || isNaN(orientation.w)) { success = false; return; } @@ -451,7 +448,7 @@ glm::vec3 SpatiallyNestable::getScale(int jointIndex) const { void SpatiallyNestable::setScale(const glm::vec3& scale) { // guard against introducing NaN into the transform - if (scale.x != scale.x || scale.y != scale.y || scale.z != scale.z) { + if (isNaN(scale.x) || isNaN(scale.y) || isNaN(scale.z)) { qDebug() << "SpatiallyNestable::setLocalScale -- scale contains NaN"; return; } @@ -492,7 +489,7 @@ glm::vec3 SpatiallyNestable::getLocalPosition() const { void SpatiallyNestable::setLocalPosition(const glm::vec3& position) { // guard against introducing NaN into the transform - if (position.x != position.x || position.y != position.y || position.z != position.z) { + if (isNaN(position.x) || isNaN(position.y) || isNaN(position.z)) { qDebug() << "SpatiallyNestable::setLocalPosition -- position contains NaN"; return; } @@ -512,10 +509,7 @@ glm::quat SpatiallyNestable::getLocalOrientation() const { void SpatiallyNestable::setLocalOrientation(const glm::quat& orientation) { // guard against introducing NaN into the transform - if (orientation.x != orientation.x || - orientation.y != orientation.y || - orientation.z != orientation.z || - orientation.w != orientation.w) { + if (isNaN(orientation.x) || isNaN(orientation.y) || isNaN(orientation.z) || isNaN(orientation.w)) { qDebug() << "SpatiallyNestable::setLocalOrientation -- orientation contains NaN"; return; } @@ -536,7 +530,7 @@ glm::vec3 SpatiallyNestable::getLocalScale() const { void SpatiallyNestable::setLocalScale(const glm::vec3& scale) { // guard against introducing NaN into the transform - if (scale.x != scale.x || scale.y != scale.y || scale.z != scale.z) { + if (isNaN(scale.x) || isNaN(scale.y) || isNaN(scale.z)) { qDebug() << "SpatiallyNestable::setLocalScale -- scale contains NaN"; return; } diff --git a/libraries/shared/src/Transform.cpp b/libraries/shared/src/Transform.cpp index 9312191922..ff0e0a01c7 100644 --- a/libraries/shared/src/Transform.cpp +++ b/libraries/shared/src/Transform.cpp @@ -152,20 +152,13 @@ QJsonObject Transform::toJson(const Transform& transform) { } bool Transform::containsNaN() const { - if (_rotation.x != _rotation.x || - _rotation.y != _rotation.y || - _rotation.z != _rotation.z || - _rotation.w != _rotation.w) { + if (isNaN(_rotation.x) || isNaN(_rotation.y) || isNaN(_rotation.z) || isNaN(_rotation.w)) { return true; } - if (_scale.x != _scale.x || - _scale.y != _scale.y || - _scale.z != _scale.z) { + if (isNaN(_scale.x) || isNaN(_scale.y) || isNaN(_scale.z)) { return true; } - if (_translation.x != _translation.x || - _translation.y != _translation.y || - _translation.z != _translation.z) { + if (isNaN(_translation.x) || isNaN(_translation.y) || isNaN(_translation.z)) { return true; } return false; From 62949390955eee6b9f8ae54fa6efb4c518469f43 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 22 Jan 2016 10:37:11 -0800 Subject: [PATCH 17/42] missed one --- libraries/shared/src/AACube.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/AACube.cpp b/libraries/shared/src/AACube.cpp index df50ab0e4c..cdff048e71 100644 --- a/libraries/shared/src/AACube.cpp +++ b/libraries/shared/src/AACube.cpp @@ -483,7 +483,7 @@ bool AACube::containsNaN() const { if (isNaN(_corner.x) || isNaN(_corner.y) || isNaN(_corner.z)) { return true; } - if (_scale != _scale) { + if (isNaN(_scale)) { return true; } return false; From a9cf836cb047c4ed03b7457b5597812fb457e38c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 22 Jan 2016 11:13:55 -0800 Subject: [PATCH 18/42] added isVec3NaN and isQuatNaN functions --- libraries/shared/src/AACube.cpp | 2 +- libraries/shared/src/GLMHelpers.cpp | 7 +++++++ libraries/shared/src/GLMHelpers.h | 4 ++++ libraries/shared/src/SharedUtil.cpp | 4 ++-- libraries/shared/src/SharedUtil.h | 1 + libraries/shared/src/SpatiallyNestable.cpp | 12 ++++++------ libraries/shared/src/Transform.cpp | 6 +++--- 7 files changed, 24 insertions(+), 12 deletions(-) diff --git a/libraries/shared/src/AACube.cpp b/libraries/shared/src/AACube.cpp index cdff048e71..8118d276d7 100644 --- a/libraries/shared/src/AACube.cpp +++ b/libraries/shared/src/AACube.cpp @@ -480,7 +480,7 @@ AACube& AACube::operator += (const glm::vec3& point) { } bool AACube::containsNaN() const { - if (isNaN(_corner.x) || isNaN(_corner.y) || isNaN(_corner.z)) { + if (isVec3NaN(_corner)) { return true; } if (isNaN(_scale)) { diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index 101412bbf7..57bfff8b9d 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -425,3 +425,10 @@ void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& seconda vAxisOut = glm::cross(wAxisOut, uAxisOut); } +bool isVec3NaN(glm::vec3 value) { + return isNaN(value.x) || isNaN(value.y) || isNaN(value.z); +} + +bool isQuatNaN(glm::quat value) { + return isNaN(value.w) || isNaN(value.x) || isNaN(value.y) || isNaN(value.z); +} diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 55458e98a2..b6a9af78c7 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -224,4 +224,8 @@ glm::vec3 transformVector(const glm::mat4& m, const glm::vec3& v); void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& secondaryAxis, glm::vec3& uAxisOut, glm::vec3& vAxisOut, glm::vec3& wAxisOut); + +bool isVec3NaN(glm::vec3 value); +bool isQuatNaN(glm::quat value); + #endif // hifi_GLMHelpers_h diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 4c893e7074..8db66f3fca 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -624,8 +624,8 @@ void debug::checkDeadBeef(void* memoryVoid, int size) { assert(memcmp((unsigned char*)memoryVoid, DEADBEEF, std::min(size, DEADBEEF_SIZE)) != 0); } -bool isNaN(float value) { - return value != value; +bool isNaN(float value) { + return value != value; } QString formatUsecTime(float usecs, int prec) { diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 1fae3bcff6..521a2738df 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -162,6 +162,7 @@ bool isBetween(int64_t value, int64_t max, int64_t min); /// \return bool is the float NaN bool isNaN(float value); + QString formatUsecTime(float usecs, int prec = 3); QString formatSecondsElapsed(float seconds); bool similarStrings(const QString& stringA, const QString& stringB); diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index cb29db47aa..591bf1d0cf 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -315,7 +315,7 @@ glm::vec3 SpatiallyNestable::getPosition(int jointIndex, bool& success) const { void SpatiallyNestable::setPosition(const glm::vec3& position, bool& success) { // guard against introducing NaN into the transform - if (isNaN(position.x) || isNaN(position.y) || isNaN(position.z)) { + if (isVec3NaN(position)) { success = false; return; } @@ -364,7 +364,7 @@ glm::quat SpatiallyNestable::getOrientation(int jointIndex, bool& success) const void SpatiallyNestable::setOrientation(const glm::quat& orientation, bool& success) { // guard against introducing NaN into the transform - if (isNaN(orientation.x) || isNaN(orientation.y) || isNaN(orientation.z) || isNaN(orientation.w)) { + if (isQuatNaN(orientation)) { success = false; return; } @@ -448,7 +448,7 @@ glm::vec3 SpatiallyNestable::getScale(int jointIndex) const { void SpatiallyNestable::setScale(const glm::vec3& scale) { // guard against introducing NaN into the transform - if (isNaN(scale.x) || isNaN(scale.y) || isNaN(scale.z)) { + if (isVec3NaN(scale)) { qDebug() << "SpatiallyNestable::setLocalScale -- scale contains NaN"; return; } @@ -489,7 +489,7 @@ glm::vec3 SpatiallyNestable::getLocalPosition() const { void SpatiallyNestable::setLocalPosition(const glm::vec3& position) { // guard against introducing NaN into the transform - if (isNaN(position.x) || isNaN(position.y) || isNaN(position.z)) { + if (isVec3NaN(position)) { qDebug() << "SpatiallyNestable::setLocalPosition -- position contains NaN"; return; } @@ -509,7 +509,7 @@ glm::quat SpatiallyNestable::getLocalOrientation() const { void SpatiallyNestable::setLocalOrientation(const glm::quat& orientation) { // guard against introducing NaN into the transform - if (isNaN(orientation.x) || isNaN(orientation.y) || isNaN(orientation.z) || isNaN(orientation.w)) { + if (isQuatNaN(orientation)) { qDebug() << "SpatiallyNestable::setLocalOrientation -- orientation contains NaN"; return; } @@ -530,7 +530,7 @@ glm::vec3 SpatiallyNestable::getLocalScale() const { void SpatiallyNestable::setLocalScale(const glm::vec3& scale) { // guard against introducing NaN into the transform - if (isNaN(scale.x) || isNaN(scale.y) || isNaN(scale.z)) { + if (isVec3NaN(scale)) { qDebug() << "SpatiallyNestable::setLocalScale -- scale contains NaN"; return; } diff --git a/libraries/shared/src/Transform.cpp b/libraries/shared/src/Transform.cpp index ff0e0a01c7..3e75b58816 100644 --- a/libraries/shared/src/Transform.cpp +++ b/libraries/shared/src/Transform.cpp @@ -152,13 +152,13 @@ QJsonObject Transform::toJson(const Transform& transform) { } bool Transform::containsNaN() const { - if (isNaN(_rotation.x) || isNaN(_rotation.y) || isNaN(_rotation.z) || isNaN(_rotation.w)) { + if (isQuatNaN(_rotation)) { return true; } - if (isNaN(_scale.x) || isNaN(_scale.y) || isNaN(_scale.z)) { + if (isVec3NaN(_scale)) { return true; } - if (isNaN(_translation.x) || isNaN(_translation.y) || isNaN(_translation.z)) { + if (isVec3NaN(_translation)) { return true; } return false; From 673182c0918421e7e59ceb1a3e2e6a7769ea6daa Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 22 Jan 2016 11:22:02 -0800 Subject: [PATCH 19/42] formatting --- libraries/shared/src/SharedUtil.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 521a2738df..1fae3bcff6 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -162,7 +162,6 @@ bool isBetween(int64_t value, int64_t max, int64_t min); /// \return bool is the float NaN bool isNaN(float value); - QString formatUsecTime(float usecs, int prec = 3); QString formatSecondsElapsed(float seconds); bool similarStrings(const QString& stringA, const QString& stringB); From f98f8d5bbb3e3bb9e598205db0c1d29579c8cc00 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 22 Jan 2016 11:51:02 -0800 Subject: [PATCH 20/42] Revert "Adds a fix for a rendering issue where models with a texture driving both color and opacity would be rendered fully opaque" --- .../lightSaber/lightSaberEntityScript.js | 3 +- examples/widgets/weatherBox.js | 161 ------------------ libraries/fbx/src/FBXReader.cpp | 2 +- libraries/fbx/src/FBXReader.h | 1 - libraries/fbx/src/FBXReader_Material.cpp | 12 +- .../src/model-networking/ModelCache.cpp | 12 -- .../src/model-networking/ModelCache.h | 2 - 7 files changed, 5 insertions(+), 188 deletions(-) delete mode 100644 examples/widgets/weatherBox.js diff --git a/examples/flowArts/lightSaber/lightSaberEntityScript.js b/examples/flowArts/lightSaber/lightSaberEntityScript.js index a23abcc695..a86f471449 100644 --- a/examples/flowArts/lightSaber/lightSaberEntityScript.js +++ b/examples/flowArts/lightSaber/lightSaberEntityScript.js @@ -105,8 +105,7 @@ alphaStart: 0.5, alphaFinish: 0.5, textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", - emitterShouldTrail: false, - lifetime: 1000 + emitterShouldTrail: false } this.beam = Entities.addEntity(props); diff --git a/examples/widgets/weatherBox.js b/examples/widgets/weatherBox.js deleted file mode 100644 index 71457136e9..0000000000 --- a/examples/widgets/weatherBox.js +++ /dev/null @@ -1,161 +0,0 @@ -// -// weatherBox.js -// examples/widgets/weatherBox -// -// Created by Eric Levin on 1/20/16. -// Copyright 2016 High Fidelity, Inc. -// -// This script creates a weatherBox widget which (in final version) will display the current weather -// -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - - -Script.include("../libraries/utils.js"); -var weatherBox, boxDimensions; -var orientation = Camera.getOrientation(); -orientation = Quat.safeEulerAngles(orientation); -orientation.x = 0; -orientation = Quat.fromVec3Degrees(orientation); -var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(orientation))); - -var emitters = []; -var spheres = []; - -createWeatherBox(center); -center.y += boxDimensions.y / 2; -createCloud(center); -for (var i = 0; i < 7; i++) { - createLightningStrike(center) -} - -function createLightningStrike(basePosition) { - var normal = Vec3.subtract(position, MyAvatar.position); - normal.y = 0; - var textureURL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/lightning.png" - var linePoints = []; - var normals = []; - var strokeWidths = []; - var strokeWidth = 0.02 - var currentPointPosition = {x: 0, y: 0, z: 0}; - for (var i = 0; i < 8; i++) { - linePoints.push(currentPointPosition); - currentPointPosition = Vec3.sum(currentPointPosition, {x: randFloat(-0.05, 0.05), y: randFloat(-0.1, -0.05), z: randFloat(-0.05, 0.05)}); - linePoints.push(currentPointPosition); - normals.push(normal); - normals.push(normal); - strokeWidth -= 0.002; - strokeWidths.push(strokeWidth); - strokeWidths.push(strokeWidth); - } - var position = Vec3.sum(basePosition, {x: randFloat(-boxDimensions.x/20, boxDimensions.x/20), y: 0, z: randFloat(-boxDimensions.x/20, boxDimensions.x/20)}); - var bolt = Entities.addEntity({ - type: "PolyLine", - textures: textureURL, - position: position, - dimensions: { - x: 10, - y: 10, - z: 10 - }, - linePoints: linePoints, - normals: normals, - strokeWidths: strokeWidths, - lifetime: randFloat(0.01, 0.2) - }); - - Script.setTimeout(function() { - createLightningStrike(position) - }, randInt(500, 5000)); - -} - - -function createWeatherBox(position) { - var naturalDimensions = { - x: 1.11, - y: 1.3, - z: 1.11 - }; - boxDimensions = Vec3.multiply(naturalDimensions, 0.7); - var modelURL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/weatherBox.fbx" - weatherBox = Entities.addEntity({ - type: "Model", - name: "Weather Box", - modelURL: modelURL, - position: position, - dimensions: boxDimensions - }); -} - - -function createCloud(position) { - var props = { - "type": "ParticleEffect", - "position": position, - "isEmitting": true, - "maxParticles": 10000, - "lifespan": 3, - "emitRate": 2000, - "emitSpeed": 0.025, - "speedSpread": 0, - "emitDimensions": { - x: boxDimensions.x, - y: boxDimensions.x, - z: 0.1 - }, - "emitRadiusStart": 1, - "polarStart": 0, - "polarFinish": 1.570796012878418, - "azimuthStart": -3.1415927410125732, - "azimuthFinish": 3.1415927410125732, - "emitAcceleration": { - "x": 0, - "y": 0, - "z": 0 - }, - "particleRadius": 0.04, - "radiusSpread": 0.02, - "radiusStart": 0.04, - radiusFinish: 0.04, - "colorStart": { - "red": 40, - "green": 40, - "blue": 100 - }, - color: { - red: 40, - green: 40, - blue: 100 - }, - "colorFinish": { - "red": 40, - "green": 40, - "blue": 100 - }, - "alpha": 1, - "alphaSpread": 0, - "alphaStart": 0.3, - "alphaFinish": 0, - "emitterShouldTrail": true, - "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png" - } - - var oceanEmitter = Entities.addEntity(props); - emitters.push(oceanEmitter); -} - -function cleanup() { - emitters.forEach(function(emitter) { - Entities.deleteEntity(emitter); - }); - spheres.forEach(function(sphere) { - Entities.deleteEntity(sphere); - }); - Entities.deleteEntity(weatherBox); - -} - -Script.scriptEnding.connect(cleanup); diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 70de307f1b..1be3bbb5f6 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1035,7 +1035,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS } else if (type.contains("transparentcolor")) { // it should be TransparentColor... // THis is how Maya assign a texture that affect diffuse color AND transparency ? - opacityTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); + diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type.contains("bump")) { bumpTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type.contains("normal")) { diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 8b1b0d2588..51cb5baf9f 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -402,7 +402,6 @@ public: QHash specularTextures; QHash emissiveTextures; QHash ambientTextures; - QHash opacityTextures; QHash _fbxMaterials; diff --git a/libraries/fbx/src/FBXReader_Material.cpp b/libraries/fbx/src/FBXReader_Material.cpp index 1329fccc3a..e947a0356e 100644 --- a/libraries/fbx/src/FBXReader_Material.cpp +++ b/libraries/fbx/src/FBXReader_Material.cpp @@ -70,7 +70,8 @@ void FBXReader::consolidateFBXMaterials() { FBXTexture diffuseTexture; QString diffuseTextureID = diffuseTextures.value(material.materialID); if (!diffuseTextureID.isNull()) { - diffuseTexture = getTexture(diffuseTextureID); + diffuseTexture = getTexture(diffuseTextureID); + // FBX files generated by 3DSMax have an intermediate texture parent, apparently foreach (const QString& childTextureID, _connectionChildMap.values(diffuseTextureID)) { if (_textureFilenames.contains(childTextureID)) { @@ -79,16 +80,9 @@ void FBXReader::consolidateFBXMaterials() { } material.diffuseTexture = diffuseTexture; + detectDifferentUVs = (diffuseTexture.texcoordSet != 0) || (!diffuseTexture.transform.isIdentity()); } - - FBXTexture opacityTexture; - QString opacityTextureID = opacityTextures.value(material.materialID); - if (!opacityTextureID.isNull()) { - opacityTexture = getTexture(opacityTextureID); - material.opacityTexture = opacityTexture; - } - FBXTexture normalTexture; QString bumpTextureID = bumpTextures.value(material.materialID); diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index ef649fd7ae..2b425351f1 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -155,8 +155,6 @@ void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& u material->specularTexture = textureCache->getTexture(url); } else if (material->emissiveTextureName == name) { material->emissiveTexture = textureCache->getTexture(url); - } else if (material->opacityTextureName == name) { - material->opacityTexture = textureCache->getTexture(url); } } } else { @@ -288,16 +286,6 @@ static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const material._material->setTextureMap(model::MaterialKey::DIFFUSE_MAP, diffuseMap); } - if (!material.opacityTexture.filename.isEmpty()) { - networkMaterial->opacityTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.opacityTexture.filename)), DEFAULT_TEXTURE, material.opacityTexture.content); - networkMaterial->opacityTextureName = material.opacityTexture.name; - - auto opacityMap = model::TextureMapPointer(new model::TextureMap()); - opacityMap->setTextureSource(networkMaterial->opacityTexture->_textureSource); - opacityMap->setTextureTransform(material.opacityTexture.transform); - - material._material->setTextureMap(model::MaterialKey::TRANSPARENT_MAP, opacityMap); - } if (!material.normalTexture.filename.isEmpty()) { networkMaterial->normalTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.normalTexture.filename)), (material.normalTexture.isBumpmap ? BUMP_TEXTURE : NORMAL_TEXTURE), material.normalTexture.content); networkMaterial->normalTextureName = material.normalTexture.name; diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 53f17f4e6c..b2d81c5900 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -182,8 +182,6 @@ public: QSharedPointer specularTexture; QString emissiveTextureName; QSharedPointer emissiveTexture; - QString opacityTextureName; - QSharedPointer opacityTexture; }; From d401a45d205617feb150c5689e40c5e3186ab130 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 22 Jan 2016 11:51:56 -0800 Subject: [PATCH 21/42] Fix auto scroll and font in console log window --- server-console/src/log.css | 10 ++++++++-- server-console/src/log.js | 7 ++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/server-console/src/log.css b/server-console/src/log.css index d13a48b5a0..0a0aa4acb5 100644 --- a/server-console/src/log.css +++ b/server-console/src/log.css @@ -52,6 +52,7 @@ ul.tabs li.current { display: none; background-color: #ededed; width: 100%; + height: 100%; overflow: auto; margin: 0; padding: 0; @@ -63,7 +64,7 @@ ul.tabs li.current { } .tab-content { - overflow: auto; + overflow: hidden; padding: 10px; background-color: #ededed; } @@ -84,4 +85,9 @@ ul.tabs li.current { display: none; float: right; margin: 10px; -} \ No newline at end of file +} + +.log-line { + font-family: "Consolas", monospace; + font-size: 9.5pt; +} diff --git a/server-console/src/log.js b/server-console/src/log.js index d7aae8a432..fffe1006b4 100644 --- a/server-console/src/log.js +++ b/server-console/src/log.js @@ -154,9 +154,7 @@ ready = function() { } function appendLogMessage(pid, msg, name) { - console.log(pid, msg, name); - var id = "pid-" + pid; - id = name == "ds" ? "domain-server" : "assignment-client"; + var id = name == "ds" ? "domain-server" : "assignment-client"; var $pidLog = $('#' + id); var size = ++tabStates[id].size; @@ -167,8 +165,7 @@ ready = function() { var wasAtBottom = false; if (currentTab == id) { - var padding = 15; - wasAtBottom = $pidLog[0].scrollTop >= ($pidLog[0].scrollHeight - $pidLog.height() - (2 * padding)); + wasAtBottom = $pidLog[0].scrollTop >= ($pidLog[0].scrollHeight - $pidLog.height()); } var $logLine = $('
').text(msg); From 2633cb1f272d4274929dae9cceae0b3731a2f70a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 22 Jan 2016 11:54:24 -0800 Subject: [PATCH 22/42] rename NaN functions for vec3 and quat --- libraries/shared/src/AACube.cpp | 8 +------- libraries/shared/src/GLMHelpers.cpp | 4 ++-- libraries/shared/src/GLMHelpers.h | 4 ++-- libraries/shared/src/SpatiallyNestable.cpp | 12 ++++++------ libraries/shared/src/Transform.cpp | 11 +---------- 5 files changed, 12 insertions(+), 27 deletions(-) diff --git a/libraries/shared/src/AACube.cpp b/libraries/shared/src/AACube.cpp index 8118d276d7..bc97a6ff69 100644 --- a/libraries/shared/src/AACube.cpp +++ b/libraries/shared/src/AACube.cpp @@ -480,11 +480,5 @@ AACube& AACube::operator += (const glm::vec3& point) { } bool AACube::containsNaN() const { - if (isVec3NaN(_corner)) { - return true; - } - if (isNaN(_scale)) { - return true; - } - return false; + return isNaN(_corner) || isNaN(_scale); } diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index 57bfff8b9d..d95314eca8 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -425,10 +425,10 @@ void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& seconda vAxisOut = glm::cross(wAxisOut, uAxisOut); } -bool isVec3NaN(glm::vec3 value) { +bool isNaN(glm::vec3 value) { return isNaN(value.x) || isNaN(value.y) || isNaN(value.z); } -bool isQuatNaN(glm::quat value) { +bool isNaN(glm::quat value) { return isNaN(value.w) || isNaN(value.x) || isNaN(value.y) || isNaN(value.z); } diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index b6a9af78c7..7dc615b114 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -225,7 +225,7 @@ void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& seconda glm::vec3& uAxisOut, glm::vec3& vAxisOut, glm::vec3& wAxisOut); -bool isVec3NaN(glm::vec3 value); -bool isQuatNaN(glm::quat value); +bool isNaN(glm::vec3 value); +bool isNaN(glm::quat value); #endif // hifi_GLMHelpers_h diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 591bf1d0cf..e5719c17ff 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -315,7 +315,7 @@ glm::vec3 SpatiallyNestable::getPosition(int jointIndex, bool& success) const { void SpatiallyNestable::setPosition(const glm::vec3& position, bool& success) { // guard against introducing NaN into the transform - if (isVec3NaN(position)) { + if (isNaN(position)) { success = false; return; } @@ -364,7 +364,7 @@ glm::quat SpatiallyNestable::getOrientation(int jointIndex, bool& success) const void SpatiallyNestable::setOrientation(const glm::quat& orientation, bool& success) { // guard against introducing NaN into the transform - if (isQuatNaN(orientation)) { + if (isNaN(orientation)) { success = false; return; } @@ -448,7 +448,7 @@ glm::vec3 SpatiallyNestable::getScale(int jointIndex) const { void SpatiallyNestable::setScale(const glm::vec3& scale) { // guard against introducing NaN into the transform - if (isVec3NaN(scale)) { + if (isNaN(scale)) { qDebug() << "SpatiallyNestable::setLocalScale -- scale contains NaN"; return; } @@ -489,7 +489,7 @@ glm::vec3 SpatiallyNestable::getLocalPosition() const { void SpatiallyNestable::setLocalPosition(const glm::vec3& position) { // guard against introducing NaN into the transform - if (isVec3NaN(position)) { + if (isNaN(position)) { qDebug() << "SpatiallyNestable::setLocalPosition -- position contains NaN"; return; } @@ -509,7 +509,7 @@ glm::quat SpatiallyNestable::getLocalOrientation() const { void SpatiallyNestable::setLocalOrientation(const glm::quat& orientation) { // guard against introducing NaN into the transform - if (isQuatNaN(orientation)) { + if (isNaN(orientation)) { qDebug() << "SpatiallyNestable::setLocalOrientation -- orientation contains NaN"; return; } @@ -530,7 +530,7 @@ glm::vec3 SpatiallyNestable::getLocalScale() const { void SpatiallyNestable::setLocalScale(const glm::vec3& scale) { // guard against introducing NaN into the transform - if (isVec3NaN(scale)) { + if (isNaN(scale)) { qDebug() << "SpatiallyNestable::setLocalScale -- scale contains NaN"; return; } diff --git a/libraries/shared/src/Transform.cpp b/libraries/shared/src/Transform.cpp index 3e75b58816..a3a3c05731 100644 --- a/libraries/shared/src/Transform.cpp +++ b/libraries/shared/src/Transform.cpp @@ -152,14 +152,5 @@ QJsonObject Transform::toJson(const Transform& transform) { } bool Transform::containsNaN() const { - if (isQuatNaN(_rotation)) { - return true; - } - if (isVec3NaN(_scale)) { - return true; - } - if (isVec3NaN(_translation)) { - return true; - } - return false; + return isNaN(_rotation) || isNaN(_scale) || isNaN(_translation); } From 61b760038a13a20cb2dcd7d522c906dd5f2e8887 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 22 Jan 2016 11:54:28 -0800 Subject: [PATCH 23/42] Address feedback from code review --- interface/src/avatar/MyAvatar.cpp | 10 ++++------ interface/src/avatar/MyAvatar.h | 1 - libraries/physics/src/CharacterController.cpp | 7 ++++--- libraries/shared/src/GLMHelpers.cpp | 10 ++++++---- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index acd1728388..30dd2bdd34 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1767,14 +1767,12 @@ void MyAvatar::lateUpdatePalms() { static const float FOLLOW_TIME = 0.5f; void MyAvatar::FollowHelper::deactivate() { - _timeTotal = FOLLOW_TIME; _timeRemaining = 0.0f; } void MyAvatar::FollowHelper::activate() { - // TODO: the follow time should be proportional to the displacement. + // TODO: Perhaps, the follow time should be proportional to the displacement. _timeRemaining = FOLLOW_TIME; - _timeTotal = FOLLOW_TIME; } bool MyAvatar::FollowHelper::isActive() const { @@ -1795,10 +1793,10 @@ bool MyAvatar::FollowHelper::shouldActivate(const MyAvatar& myAvatar, const glm: const float CYLINDER_RADIUS = 0.15f; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); - glm::vec3 truncatedOffset(offset.x, 0.0f, offset.y); - float truncatedDistance = glm::length(truncatedOffset); + glm::vec3 radialOffset(offset.x, 0.0f, offset.y); + float radialDistance = glm::length(radialOffset); - return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM) || (truncatedDistance > CYLINDER_RADIUS); + return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM) || (radialDistance > CYLINDER_RADIUS); } void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index a32dfc298d..a911218991 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -377,7 +377,6 @@ private: struct FollowHelper { glm::mat4 _desiredBodyMatrix; float _timeRemaining { 0.0f }; - float _timeTotal { 0.0f }; void deactivate(); void activate(); diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 72d8220d4f..432b89ba31 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -194,9 +194,10 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { // Rather then add this velocity to velocity the RigidBody, we explicitly teleport the RigidBody towards its goal. // This mirrors the computation done in MyAvatar::FollowHelper::postPhysicsUpdate(). // These two computations must be kept in sync. + const float MINIMUM_TIME_REMAINING = 0.005f; const float MAX_DISPLACEMENT = 0.5f * _radius; _followTimeRemaining -= dt; - if (_followTimeRemaining >= 0.005f) { + if (_followTimeRemaining >= MINIMUM_TIME_REMAINING) { btTransform bodyTransform = _rigidBody->getWorldTransform(); btVector3 startPos = bodyTransform.getOrigin(); @@ -210,9 +211,9 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { glm::vec2 currentRight(currentFacing.y, -currentFacing.x); glm::vec2 desiredFacing = getFacingDir2D(bulletToGLM(_followDesiredBodyTransform.getRotation())); float deltaAngle = acosf(glm::clamp(glm::dot(currentFacing, desiredFacing), -1.0f, 1.0f)); - float angularVel = deltaAngle / _followTimeRemaining; + float angularSpeed = deltaAngle / _followTimeRemaining; float sign = copysignf(1.0f, glm::dot(desiredFacing, currentRight)); - btQuaternion angularDisplacement = btQuaternion(btVector3(0.0f, 1.0f, 0.0f), sign * angularVel * dt); + btQuaternion angularDisplacement = btQuaternion(btVector3(0.0f, 1.0f, 0.0f), sign * angularSpeed * dt); btQuaternion endRot = angularDisplacement * startRot; // in order to accumulate displacement of avatar position, we need to take _shapeLocalOffset into account. diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index 5adb9ca947..5073563afd 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -428,8 +428,9 @@ void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& seconda glm::vec2 getFacingDir2D(const glm::quat& rot) { glm::vec3 facing3D = rot * Vectors::UNIT_NEG_Z; glm::vec2 facing2D(facing3D.x, facing3D.z); - if (glm::length(facing2D) <= 0.0001f) { - return glm::vec2(1, 0); + const float ALMOST_ZERO = 0.0001f; + if (glm::length(facing2D) < ALMOST_ZERO) { + return glm::vec2(1.0f, 0.0f); } else { return glm::normalize(facing2D); } @@ -438,8 +439,9 @@ glm::vec2 getFacingDir2D(const glm::quat& rot) { glm::vec2 getFacingDir2D(const glm::mat4& m) { glm::vec3 facing3D = transformVector(m, Vectors::UNIT_NEG_Z); glm::vec2 facing2D(facing3D.x, facing3D.z); - if (glm::length(facing2D) <= 0.0001f) { - return glm::vec2(1, 0); + const float ALMOST_ZERO = 0.0001f; + if (glm::length(facing2D) < ALMOST_ZERO) { + return glm::vec2(1.0f, 0.0f); } else { return glm::normalize(facing2D); } From 822244ef725cbc246eaba4e2cdc213d737efda57 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 21 Jan 2016 16:43:08 -0800 Subject: [PATCH 24/42] Fix DS new assignment feature --- domain-server/src/DomainServer.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 19950c9e0b..8d9a28513d 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1148,13 +1148,22 @@ QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) { return nodeJson; } -const char ASSIGNMENT_SCRIPT_HOST_LOCATION[] = "resources/web/assignment"; +QDir pathForAssignmentScriptsDirectory() { + static const QString SCRIPTS_DIRECTORY_NAME = "/scripts/"; + + QDir directory(ServerPathUtils::getDataDirectory() + SCRIPTS_DIRECTORY_NAME); + if (!directory.exists()) { + directory.mkpath("."); + qInfo() << "Created path to " << directory.path(); + } + + return directory; +} + QString pathForAssignmentScript(const QUuid& assignmentUUID) { - QString newPath { ServerPathUtils::getDataDirectory() + "/" + QString(ASSIGNMENT_SCRIPT_HOST_LOCATION) }; - newPath += "/scripts/"; + QDir directory = pathForAssignmentScriptsDirectory(); // append the UUID for this script as the new filename, remove the curly braces - newPath += uuidStringWithoutCurlyBraces(assignmentUUID); - return newPath; + return directory.absoluteFilePath(uuidStringWithoutCurlyBraces(assignmentUUID)); } const QString URI_OAUTH = "/oauth"; From 89b8eb2efa754eb9c04d976a31ec82316be8b6e5 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 22 Jan 2016 11:43:33 -0800 Subject: [PATCH 25/42] Fix initial keyboard focus problems --- libraries/ui/src/OffscreenUi.cpp | 55 ++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 8f70931085..047c55be37 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -233,6 +234,58 @@ void OffscreenUi::setNavigationFocused(bool focused) { offscreenFlags->setNavigationFocused(focused); } +// FIXME HACK.... +// This hack is an attempt to work around the 'offscreen UI can't gain keyboard focus' bug +// https://app.asana.com/0/27650181942747/83176475832393 +// The problem seems related to https://bugreports.qt.io/browse/QTBUG-50309 +// +// The workaround seems to be to give some other window (same process or another process doesn't seem to matter) +// focus and then put focus back on the interface main window. +// +// If I could reliably reproduce this bug I could eventually track down what state change is occuring +// during the process of the main window losing and then gaining focus, but failing that, here's a +// brute force way of triggering that state change at application start in a way that should be nearly +// imperceptible to the user. +class KeyboardFocusHack : public QObject { + Q_OBJECT +public: + KeyboardFocusHack() { + Q_ASSERT(_mainWindow); + QTimer::singleShot(200, [=] { + _hackWindow = new QWindow(); + _hackWindow->setFlags(Qt::FramelessWindowHint); + _hackWindow->setGeometry(_mainWindow->x(), _mainWindow->y(), 10, 10); + _hackWindow->show(); + _hackWindow->requestActivate(); + QTimer::singleShot(200, [=] { + _hackWindow->hide(); + _hackWindow->deleteLater(); + _hackWindow = nullptr; + _mainWindow->requestActivate(); + this->deleteLater(); + }); + }); + } + +private: + + static QWindow* findMainWindow() { + auto windows = qApp->topLevelWindows(); + QWindow* result = nullptr; + for (auto window : windows) { + QVariant isMainWindow = window->property("MainWindow"); + if (!qobject_cast(window)) { + result = window; + break; + } + } + return result; + } + + QWindow* const _mainWindow { findMainWindow() }; + QWindow* _hackWindow { nullptr }; +}; + void OffscreenUi::createDesktop(const QUrl& url) { if (_desktop) { qDebug() << "Desktop already created"; @@ -254,6 +307,8 @@ void OffscreenUi::createDesktop(const QUrl& url) { _toolWindow = _desktop->findChild("ToolWindow"); new VrMenu(this); + + new KeyboardFocusHack(); } QQuickItem* OffscreenUi::getDesktop() { From 7af20e90c8c3a474fdde8b3333b66322f888adce Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 11 Jan 2016 18:46:14 -0800 Subject: [PATCH 26/42] Hooked up fly animation to json and Rig --- .../defaultAvatar_full/avatar-animation.json | 44 +++++++++-- interface/src/avatar/MyAvatar.cpp | 8 +- interface/src/avatar/MyAvatar.h | 2 + interface/src/avatar/SkeletonModel.cpp | 2 +- libraries/animation/src/Rig.cpp | 77 ++++++++++++------- libraries/animation/src/Rig.h | 5 +- 6 files changed, 98 insertions(+), 40 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index 629b9bc1f9..d510e7b966 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -246,7 +246,8 @@ { "var": "isMovingLeft", "state": "strafeLeft" }, { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, - { "var": "isAway", "state": "awayIntro" } + { "var": "isAway", "state": "awayIntro" }, + { "var": "isFlying", "state": "fly" } ] }, { @@ -261,7 +262,8 @@ { "var": "isMovingLeft", "state": "strafeLeft" }, { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, - { "var": "isAway", "state": "awayIntro" } + { "var": "isAway", "state": "awayIntro" }, + { "var": "isFlying", "state": "fly" } ] }, { @@ -275,7 +277,8 @@ { "var": "isMovingLeft", "state": "strafeLeft" }, { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, - { "var": "isAway", "state": "awayIntro" } + { "var": "isAway", "state": "awayIntro" }, + { "var": "isFlying", "state": "fly" } ] }, { @@ -289,7 +292,8 @@ { "var": "isMovingLeft", "state": "strafeLeft" }, { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, - { "var": "isAway", "state": "awayIntro" } + { "var": "isAway", "state": "awayIntro" }, + { "var": "isFlying", "state": "fly" } ] }, { @@ -303,7 +307,8 @@ { "var": "isMovingLeft", "state": "strafeLeft" }, { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, - { "var": "isAway", "state": "awayIntro" } + { "var": "isAway", "state": "awayIntro" }, + { "var": "isFlying", "state": "fly" } ] }, { @@ -317,7 +322,8 @@ { "var": "isMovingRight", "state": "strafeRight" }, { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, - { "var": "isAway", "state": "awayIntro" } + { "var": "isAway", "state": "awayIntro" }, + { "var": "isFlying", "state": "fly" } ] }, { @@ -331,7 +337,8 @@ { "var": "isMovingRight", "state": "strafeRight" }, { "var": "isMovingLeft", "state": "strafeLeft" }, { "var": "isTurningLeft", "state": "turnLeft" }, - { "var": "isAway", "state": "awayIntro" } + { "var": "isAway", "state": "awayIntro" }, + { "var": "isFlying", "state": "fly" } ] }, { @@ -345,7 +352,8 @@ { "var": "isMovingRight", "state": "strafeRight" }, { "var": "isMovingLeft", "state": "strafeLeft" }, { "var": "isTurningRight", "state": "turnRight" }, - { "var": "isAway", "state": "awayIntro" } + { "var": "isAway", "state": "awayIntro" }, + { "var": "isFlying", "state": "fly" } ] }, { @@ -371,6 +379,14 @@ "transitions": [ { "var": "awayOutroOnDone", "state": "idle" } ] + }, + { + "id": "fly", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { "var": "isNotFlying", "state": "idle" } + ] } ] }, @@ -657,6 +673,18 @@ "loopFlag": false }, "children": [] + }, + { + "id": "fly", + "type": "clip", + "data": { + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims/fly.fbx", + "startFrame": 1.0, + "endFrame": 80.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] } ] } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 82809cb7a5..3d079801ca 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1538,9 +1538,7 @@ void MyAvatar::updatePosition(float deltaTime) { // rotate velocity into camera frame glm::quat rotation = getHead()->getCameraOrientation(); glm::vec3 localVelocity = glm::inverse(rotation) * _targetVelocity; - - bool isHovering = _characterController.isHovering(); - glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isHovering); + glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isHovering()); newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity); // rotate back into world-frame @@ -1636,6 +1634,10 @@ void MyAvatar::doUpdateBillboard() { sendBillboardPacket(); } +bool MyAvatar::isHovering() const { + return _characterController.isHovering(); +} + void MyAvatar::increaseSize() { if ((1.0f + SCALING_RATIO) * _targetScale < MAX_AVATAR_SCALE) { _targetScale *= (1.0f + SCALING_RATIO); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 33d307f5c2..5f289840f0 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -231,6 +231,8 @@ public: glm::quat getCustomListenOrientation() { return _customListenOrientation; } void setCustomListenOrientation(glm::quat customListenOrientation) { _customListenOrientation = customListenOrientation; } + bool isHovering() const; + public slots: void increaseSize(); void decreaseSize(); diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index b7a154851f..ad434f6b61 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -133,7 +133,7 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { _rig->updateFromHandParameters(handParams, deltaTime); - _rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation()); + _rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation(), myAvatar->isHovering()); // evaluate AnimGraph animation and update jointStates. Model::updateRig(deltaTime, parentTransform); diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index bcda3e8f5c..df92d7d912 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -500,7 +500,7 @@ static const std::vector FORWARD_SPEEDS = { 0.4f, 1.4f, 4.5f }; // m/s static const std::vector BACKWARD_SPEEDS = { 0.6f, 1.45f }; // m/s static const std::vector LATERAL_SPEEDS = { 0.2f, 0.65f }; // m/s -void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation) { +void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation, bool isHovering) { glm::vec3 front = worldRotation * IDENTITY_FRONT; @@ -568,36 +568,43 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos const float TURN_ENTER_SPEED_THRESHOLD = 0.5f; // rad/sec const float TURN_EXIT_SPEED_THRESHOLD = 0.2f; // rad/sec - float moveThresh; - if (_state != RigRole::Move) { - moveThresh = MOVE_ENTER_SPEED_THRESHOLD; - } else { - moveThresh = MOVE_EXIT_SPEED_THRESHOLD; - } - - float turnThresh; - if (_state != RigRole::Turn) { - turnThresh = TURN_ENTER_SPEED_THRESHOLD; - } else { - turnThresh = TURN_EXIT_SPEED_THRESHOLD; - } - - if (glm::length(localVel) > moveThresh) { - if (_desiredState != RigRole::Move) { + if (isHovering) { + if (_desiredState != RigRole::Hover) { _desiredStateAge = 0.0f; } - _desiredState = RigRole::Move; + _desiredState = RigRole::Hover; } else { - if (fabsf(turningSpeed) > turnThresh) { - if (_desiredState != RigRole::Turn) { + float moveThresh; + if (_state != RigRole::Move) { + moveThresh = MOVE_ENTER_SPEED_THRESHOLD; + } else { + moveThresh = MOVE_EXIT_SPEED_THRESHOLD; + } + + float turnThresh; + if (_state != RigRole::Turn) { + turnThresh = TURN_ENTER_SPEED_THRESHOLD; + } else { + turnThresh = TURN_EXIT_SPEED_THRESHOLD; + } + + if (glm::length(localVel) > moveThresh) { + if (_desiredState != RigRole::Move) { _desiredStateAge = 0.0f; } - _desiredState = RigRole::Turn; - } else { // idle - if (_desiredState != RigRole::Idle) { - _desiredStateAge = 0.0f; + _desiredState = RigRole::Move; + } else { + if (fabsf(turningSpeed) > turnThresh) { + if (_desiredState != RigRole::Turn) { + _desiredStateAge = 0.0f; + } + _desiredState = RigRole::Turn; + } else { // idle + if (_desiredState != RigRole::Idle) { + _desiredStateAge = 0.0f; + } + _desiredState = RigRole::Idle; } - _desiredState = RigRole::Idle; } } @@ -649,6 +656,8 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isTurningLeft", false); _animVars.set("isTurningRight", false); _animVars.set("isNotTurning", true); + _animVars.set("isFlying", false); + _animVars.set("isNotFlying", true); } } else if (_state == RigRole::Turn) { if (turningSpeed > 0.0f) { @@ -667,7 +676,9 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isMovingRight", false); _animVars.set("isMovingLeft", false); _animVars.set("isNotMoving", true); - } else { + _animVars.set("isFlying", false); + _animVars.set("isNotFlying", true); + } else if (_state == RigRole::Idle ) { // default anim vars to notMoving and notTurning _animVars.set("isMovingForward", false); _animVars.set("isMovingBackward", false); @@ -677,6 +688,20 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isTurningLeft", false); _animVars.set("isTurningRight", false); _animVars.set("isNotTurning", true); + _animVars.set("isFlying", false); + _animVars.set("isNotFlying", true); + } else { + // flying. + _animVars.set("isMovingForward", false); + _animVars.set("isMovingBackward", false); + _animVars.set("isMovingLeft", false); + _animVars.set("isMovingRight", false); + _animVars.set("isNotMoving", true); + _animVars.set("isTurningLeft", false); + _animVars.set("isTurningRight", false); + _animVars.set("isNotTurning", true); + _animVars.set("isFlying", true); + _animVars.set("isNotFlying", false); } t += deltaTime; diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 0636230678..d26be83d36 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -141,7 +141,7 @@ public: glm::mat4 getJointTransform(int jointIndex) const; // Start or stop animations as needed. - void computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation); + void computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation, bool isHovering); // Regardless of who started the animations or how many, update the joints. void updateAnimations(float deltaTime, glm::mat4 rootTransform); @@ -268,7 +268,8 @@ public: enum class RigRole { Idle = 0, Turn, - Move + Move, + Hover }; RigRole _state { RigRole::Idle }; RigRole _desiredState { RigRole::Idle }; From b099376193cc40bee22960ad19375231376d1ad8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Jan 2016 14:47:25 -0800 Subject: [PATCH 27/42] fix a typo in message for macdeployqt --- cmake/macros/InstallBesideConsole.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/macros/InstallBesideConsole.cmake b/cmake/macros/InstallBesideConsole.cmake index 6c8969dded..c17e8d2564 100644 --- a/cmake/macros/InstallBesideConsole.cmake +++ b/cmake/macros/InstallBesideConsole.cmake @@ -60,7 +60,7 @@ macro(install_beside_console) if (NOT MACDEPLOYQT_COMMAND AND (PRODUCTION_BUILD OR PR_BUILD)) message(FATAL_ERROR "Could not find macdeployqt at ${QT_DIR}/bin.\ - It is required to produce an relocatable interface application.\ + It is required to produce a relocatable interface application.\ Check that the environment variable QT_DIR points to your Qt installation.\ ") endif () From 5743c8046c837211650c1dfe15ec4a0801a3d1a3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Jan 2016 11:15:49 -0800 Subject: [PATCH 28/42] install the server-console in a subdir on win32 --- cmake/macros/InstallBesideConsole.cmake | 22 ++++------------------ cmake/macros/SetPackagingParameters.cmake | 12 +++++++++++- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/cmake/macros/InstallBesideConsole.cmake b/cmake/macros/InstallBesideConsole.cmake index c17e8d2564..e257defcb7 100644 --- a/cmake/macros/InstallBesideConsole.cmake +++ b/cmake/macros/InstallBesideConsole.cmake @@ -12,25 +12,17 @@ macro(install_beside_console) if (WIN32 OR APPLE) # install this component beside the installed server-console executable - if (APPLE) - set(CONSOLE_APP_CONTENTS "${CONSOLE_INSTALL_APP_PATH}/Contents") - set(COMPONENT_APP_PATH "${CONSOLE_APP_CONTENTS}/MacOS/Components.app") - set(COMPONENT_DESTINATION "${COMPONENT_APP_PATH}/Contents/MacOS") - else () - set(COMPONENT_DESTINATION ${CONSOLE_INSTALL_DIR}) - endif () - if (APPLE) install( TARGETS ${TARGET_NAME} - RUNTIME DESTINATION ${COMPONENT_DESTINATION} + RUNTIME DESTINATION ${COMPONENT_INSTALL_DIR} COMPONENT ${SERVER_COMPONENT} ) else () # setup install of executable and things copied by fixup/windeployqt install( FILES "$/" - DESTINATION ${COMPONENT_DESTINATION} + DESTINATION ${COMPONENT_INSTALL_DIR} COMPONENT ${SERVER_COMPONENT} ) @@ -40,16 +32,10 @@ macro(install_beside_console) endif () if (TARGET_NAME STREQUAL domain-server) - if (APPLE) - set(RESOURCES_DESTINATION ${COMPONENT_DESTINATION}) - else () - set(RESOURCES_DESTINATION ${CONSOLE_INSTALL_DIR}) - endif () - # install the resources folder for the domain-server where its executable will be install( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/resources - DESTINATION ${RESOURCES_DESTINATION} + DESTINATION ${COMPONENT_INSTALL_DIR} USE_SOURCE_PERMISSIONS COMPONENT ${SERVER_COMPONENT} ) @@ -81,7 +67,7 @@ macro(install_beside_console) endif () # set variables used by manual ssleay library copy - set(TARGET_INSTALL_DIR ${COMPONENT_DESTINATION}) + set(TARGET_INSTALL_DIR ${COMPONENT_INSTALL_DIR}) set(TARGET_INSTALL_COMPONENT ${SERVER_COMPONENT}) manually_install_ssl_eay() diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 5bfbb0794d..9aba143c03 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -52,8 +52,18 @@ macro(SET_PACKAGING_PARAMETERS) set(CONSOLE_INSTALL_DIR ${DMG_SUBFOLDER_NAME}) set(INTERFACE_INSTALL_DIR ${DMG_SUBFOLDER_NAME}) + + set(CONSOLE_APP_CONTENTS "${CONSOLE_INSTALL_APP_PATH}/Contents") + set(COMPONENT_APP_PATH "${CONSOLE_APP_CONTENTS}/MacOS/Components.app") + set(COMPONENT_INSTALL_DIR "${COMPONENT_APP_PATH}/Contents/MacOS") else () - set(CONSOLE_INSTALL_DIR ".") + if (WIN32) + set(CONSOLE_INSTALL_DIR "server-console") + else () + set(CONSOLE_INSTALL_DIR ".") + endif () + + set(COMPONENT_INSTALL_DIR ".") set(INTERFACE_INSTALL_DIR ".") endif () From 9039334af565fa9c2432c57f91245ba48bb86cca Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Jan 2016 12:01:00 -0800 Subject: [PATCH 29/42] reinstate the search filter in log --- server-console/src/log.css | 1 - 1 file changed, 1 deletion(-) diff --git a/server-console/src/log.css b/server-console/src/log.css index 0a0aa4acb5..0b2a05554e 100644 --- a/server-console/src/log.css +++ b/server-console/src/log.css @@ -82,7 +82,6 @@ ul.tabs li.current { } .search { - display: none; float: right; margin: 10px; } From 055a0ff7d9c10fd28f9bb06b1852bc8148879166 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Jan 2016 13:39:47 -0800 Subject: [PATCH 30/42] check a level up from server-console.exe for win32 --- server-console/src/modules/path-finder.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/server-console/src/modules/path-finder.js b/server-console/src/modules/path-finder.js index d4cb9aa277..1898db91ac 100644 --- a/server-console/src/modules/path-finder.js +++ b/server-console/src/modules/path-finder.js @@ -23,9 +23,10 @@ exports.searchPaths = function(name, binaryType, releaseType) { if (!releaseType) { // check in the developer build tree for binaries + var typeSpecificPath = (binaryType == "local-release" ? "Release/" : "Debug/") paths = [ devBasePath + name + extension, - devBasePath + (binaryType == "local-release" ? "Release/" : "Debug/") + name + extension + devBasePath + typeSpecificPath + name + extension ] } else { // check directly beside the binary @@ -33,6 +34,11 @@ exports.searchPaths = function(name, binaryType, releaseType) { path.join(path.dirname(process.execPath), name + extension) ]; + if (process.platform == "win32") { + // check a level back in case we're packaged on windows + paths.push(path.resolve(path.dirname(process.execPath), '../' + name + extension)) + } + // assume we're inside an app bundle on OS X if (process.platform == "darwin") { var contentPath = ".app/Contents/"; From 47a630f0ade70219e97852cc63e0dc2361b96e70 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Jan 2016 14:18:45 -0800 Subject: [PATCH 31/42] manually install msvc DLLs with Interface/DS/AC --- cmake/macros/InstallBesideConsole.cmake | 1 + cmake/macros/ManuallyInstallMSVC.cmake | 37 +++++++++++++++++++++++++ interface/CMakeLists.txt | 1 + 3 files changed, 39 insertions(+) create mode 100644 cmake/macros/ManuallyInstallMSVC.cmake diff --git a/cmake/macros/InstallBesideConsole.cmake b/cmake/macros/InstallBesideConsole.cmake index e257defcb7..5f1dd00821 100644 --- a/cmake/macros/InstallBesideConsole.cmake +++ b/cmake/macros/InstallBesideConsole.cmake @@ -70,5 +70,6 @@ macro(install_beside_console) set(TARGET_INSTALL_DIR ${COMPONENT_INSTALL_DIR}) set(TARGET_INSTALL_COMPONENT ${SERVER_COMPONENT}) manually_install_ssl_eay() + manually_install_msvc() endmacro() diff --git a/cmake/macros/ManuallyInstallMSVC.cmake b/cmake/macros/ManuallyInstallMSVC.cmake new file mode 100644 index 0000000000..45e9362c91 --- /dev/null +++ b/cmake/macros/ManuallyInstallMSVC.cmake @@ -0,0 +1,37 @@ +# +# ManuallyInstallMSVC.cmake +# cmake/macros +# +# Copyright 2016 High Fidelity, Inc. +# Created by Stephen Birarda on January 22nd, 2016 +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# + +# On windows fixup_bundle does not find msvcr120.dll and msvcp120.dll that our targets need to be re-distributable. +# We use this macro to find them and manually install them beside the targets + +macro(manually_install_msvc) + if (WIN32) + # look for the msvcr DLLs required by this target + find_path(MSVC_DLL_PATH msvcr120.dll PATHS "C:/Windows/SysWOW64" NO_DEFAULT_PATH) + + if (MSVC_DLL_PATH-NOTFOUND) + # we didn't get the path to the DLLs - on production or PR build this is a fail + if (PRODUCTION_BUILD OR PR_BUILD) + message(FATAL_ERROR "Did not find MSVC_DLL_PATH for msvcr120.dll and msvcp120.dll.\ + Both are required to package re-distributable installer." + ) + endif () + else () + # manually install the two DLLs for this component + install( + FILES "${MSVC_DLL_PATH}/msvcr120.dll" "${MSVC_DLL_PATH}/msvcp120.dll" + DESTINATION ${TARGET_INSTALL_DIR} + COMPONENT ${TARGET_INSTALL_COMPONENT} + ) + endif () + + endif () +endmacro() diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index b4ce53b92a..3ae01f3673 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -267,6 +267,7 @@ if (WIN32) set(TARGET_INSTALL_DIR ${INTERFACE_INSTALL_DIR}) set(TARGET_INSTALL_COMPONENT ${CLIENT_COMPONENT}) manually_install_ssl_eay() + manually_install_msvc() package_libraries_for_deployment() endif() From 53eee270866a44df113d5a9dd17752838f3fdfe5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Jan 2016 14:26:20 -0800 Subject: [PATCH 32/42] use incredibly dumb win path to 64-bit dlls --- cmake/macros/ManuallyInstallMSVC.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/macros/ManuallyInstallMSVC.cmake b/cmake/macros/ManuallyInstallMSVC.cmake index 45e9362c91..ac899427a7 100644 --- a/cmake/macros/ManuallyInstallMSVC.cmake +++ b/cmake/macros/ManuallyInstallMSVC.cmake @@ -15,7 +15,7 @@ macro(manually_install_msvc) if (WIN32) # look for the msvcr DLLs required by this target - find_path(MSVC_DLL_PATH msvcr120.dll PATHS "C:/Windows/SysWOW64" NO_DEFAULT_PATH) + find_path(MSVC_DLL_PATH msvcr120.dll PATHS "C:/Windows/System32" NO_DEFAULT_PATH) if (MSVC_DLL_PATH-NOTFOUND) # we didn't get the path to the DLLs - on production or PR build this is a fail From 971603bd571e88bb42598dd3498168f928a99375 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Jan 2016 14:53:05 -0800 Subject: [PATCH 33/42] make shortcuts to server-console point to right place --- cmake/templates/CPackProperties.cmake.in | 1 + cmake/templates/NSIS.template.in | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index 7b3d0ae53e..285de84d39 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -11,6 +11,7 @@ set(INTERFACE_SHORTCUT_NAME "@INTERFACE_SM_SHORTCUT_NAME@") set(INTERFACE_WIN_EXEC_NAME "@INTERFACE_EXEC_PREFIX@.exe") +set(CONSOLE_INSTALL_SUBDIR "@CONSOLE_INSTALL_DIR@") set(CONSOLE_SHORTCUT_NAME "@CONSOLE_SM_SHORTCUT_NAME@") set(CONSOLE_WIN_EXEC_NAME "@CONSOLE_EXEC_NAME@") set(DS_EXEC_NAME "@DS_EXEC_NAME@") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 075b3df38b..1f3ebcd8c0 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -769,7 +769,7 @@ Section "-Core installation" ; Conditional handling for server console shortcut ${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" \ - "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" + "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" ${EndIf} CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\@UNINSTALLER_NAME@" @@ -958,7 +958,7 @@ Function HandlePostInstallOptions ${NSD_GetState} $DesktopServerCheckbox $DesktopServerState ${If} $DesktopServerState == ${BST_CHECKED} - CreateShortCut "$DESKTOP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" + CreateShortCut "$DESKTOP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" !insertmacro WritePostInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ YES ${Else} !insertmacro WritePostInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ NO @@ -968,7 +968,7 @@ Function HandlePostInstallOptions ${NSD_GetState} $ServerStartupCheckbox $ServerStartupState ${If} $ServerStartupState == ${BST_CHECKED} - CreateShortCut "$SMSTARTUP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" + CreateShortCut "$SMSTARTUP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" !insertmacro WritePostInstallOption @CONSOLE_STARTUP_REG_KEY@ YES ${Else} @@ -1012,7 +1012,7 @@ Function HandlePostInstallOptions ; both launches use the explorer trick in case the user has elevated permissions for the installer ; it won't be possible to use this approach if either application should be launched with a command line param ${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} - Exec '"$WINDIR\explorer.exe" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@"' + Exec '"$WINDIR\explorer.exe" "$INSTDIR\\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"' ${Else} Exec '"$WINDIR\explorer.exe" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@"' ${EndIf} From 921d4dccd7e388b54ddf32afccce42b486ae7a3e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Jan 2016 15:02:30 -0800 Subject: [PATCH 34/42] remove anything previously installed by old server-console --- cmake/templates/NSIS.template.in | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 1f3ebcd8c0..fd4358285f 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -685,6 +685,30 @@ FunctionEnd ;Installer Sections Section "-Core installation" + ;Delete any server-console files installed before it was placed in sub-folder + ;This is temporary and can be removed once users who had the initial installer have updated + Delete "$INSTDIR\server-console.exe" + Delete "$INSTDIR\locales" + Delete "$INSTDIR\resources\app" + Delete "$INSTDIR\resources\atom.asar" + Delete "$INSTDIR\build-info.json" + Delete "$INSTDIR\content_resources_200_percent.pak" + Delete "$INSTDIR\content_shell.pak" + Delete "$INSTDIR\d3dcompiler_47.dll" + Delete "$INSTDIR\icudtl.dat" + Delete "$INSTDIR\libEGL.dll" + Delete "$INSTDIR\libGLESv2.dll" + Delete "$INSTDIR\LICENSE" + Delete "$INSTDIR\LICENSES.chromium.html" + Delete "$INSTDIR\natives_blob.bin" + Delete "$INSTDIR\node.dll" + Delete "$INSTDIR\pdf.dll" + Delete "$INSTDIR\snapshot_blob.bin" + Delete "$INSTDIR\ui_resources_200_percent.pak" + Delete "$INSTDIR\vccorlib120.dll" + Delete "$INSTDIR\version" + Delete "$INSTDIR\xinput1_3.dll" + ;Use the entire tree produced by the INSTALL target. Keep the ;list of directories here in sync with the RMDir commands below. SetOutPath "$INSTDIR" From da1902ac72aca4a7f48aae847f2b4eb13bc487dc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Jan 2016 15:27:30 -0800 Subject: [PATCH 35/42] use CMake InstallRequiredSystemLibraries for MSVC --- cmake/macros/GenerateInstallers.cmake | 5 ++++ cmake/macros/InstallBesideConsole.cmake | 1 - cmake/macros/ManuallyInstallMSVC.cmake | 37 ------------------------- interface/CMakeLists.txt | 1 - 4 files changed, 5 insertions(+), 39 deletions(-) delete mode 100644 cmake/macros/ManuallyInstallMSVC.cmake diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 4d7119d737..e0523f32d3 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -25,6 +25,11 @@ macro(GENERATE_INSTALLERS) set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME}) if (WIN32) + # include CMake module that will install compiler system libraries + # so that we have msvcr120 and msvcp120 installed with targets + set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION ${INTERFACE_INSTALL_DIR}) + include(InstallRequiredSystemLibraries) + set(CPACK_NSIS_MUI_ICON "${HF_CMAKE_DIR}/installer/installer.ico") # install and reference the Add/Remove icon diff --git a/cmake/macros/InstallBesideConsole.cmake b/cmake/macros/InstallBesideConsole.cmake index 5f1dd00821..e257defcb7 100644 --- a/cmake/macros/InstallBesideConsole.cmake +++ b/cmake/macros/InstallBesideConsole.cmake @@ -70,6 +70,5 @@ macro(install_beside_console) set(TARGET_INSTALL_DIR ${COMPONENT_INSTALL_DIR}) set(TARGET_INSTALL_COMPONENT ${SERVER_COMPONENT}) manually_install_ssl_eay() - manually_install_msvc() endmacro() diff --git a/cmake/macros/ManuallyInstallMSVC.cmake b/cmake/macros/ManuallyInstallMSVC.cmake deleted file mode 100644 index ac899427a7..0000000000 --- a/cmake/macros/ManuallyInstallMSVC.cmake +++ /dev/null @@ -1,37 +0,0 @@ -# -# ManuallyInstallMSVC.cmake -# cmake/macros -# -# Copyright 2016 High Fidelity, Inc. -# Created by Stephen Birarda on January 22nd, 2016 -# -# Distributed under the Apache License, Version 2.0. -# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -# - -# On windows fixup_bundle does not find msvcr120.dll and msvcp120.dll that our targets need to be re-distributable. -# We use this macro to find them and manually install them beside the targets - -macro(manually_install_msvc) - if (WIN32) - # look for the msvcr DLLs required by this target - find_path(MSVC_DLL_PATH msvcr120.dll PATHS "C:/Windows/System32" NO_DEFAULT_PATH) - - if (MSVC_DLL_PATH-NOTFOUND) - # we didn't get the path to the DLLs - on production or PR build this is a fail - if (PRODUCTION_BUILD OR PR_BUILD) - message(FATAL_ERROR "Did not find MSVC_DLL_PATH for msvcr120.dll and msvcp120.dll.\ - Both are required to package re-distributable installer." - ) - endif () - else () - # manually install the two DLLs for this component - install( - FILES "${MSVC_DLL_PATH}/msvcr120.dll" "${MSVC_DLL_PATH}/msvcp120.dll" - DESTINATION ${TARGET_INSTALL_DIR} - COMPONENT ${TARGET_INSTALL_COMPONENT} - ) - endif () - - endif () -endmacro() diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 3ae01f3673..b4ce53b92a 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -267,7 +267,6 @@ if (WIN32) set(TARGET_INSTALL_DIR ${INTERFACE_INSTALL_DIR}) set(TARGET_INSTALL_COMPONENT ${CLIENT_COMPONENT}) manually_install_ssl_eay() - manually_install_msvc() package_libraries_for_deployment() endif() From 6951f1aed75abb74659d4b1a1ee971913f0e5611 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Jan 2016 15:31:01 -0800 Subject: [PATCH 36/42] tweak server console deletion requirements --- cmake/templates/NSIS.template.in | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index fd4358285f..0154d690b7 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -694,10 +694,6 @@ Section "-Core installation" Delete "$INSTDIR\build-info.json" Delete "$INSTDIR\content_resources_200_percent.pak" Delete "$INSTDIR\content_shell.pak" - Delete "$INSTDIR\d3dcompiler_47.dll" - Delete "$INSTDIR\icudtl.dat" - Delete "$INSTDIR\libEGL.dll" - Delete "$INSTDIR\libGLESv2.dll" Delete "$INSTDIR\LICENSE" Delete "$INSTDIR\LICENSES.chromium.html" Delete "$INSTDIR\natives_blob.bin" From 4e76f3ccc482e71fef9af2a8a58737c52bea193d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Jan 2016 15:39:53 -0800 Subject: [PATCH 37/42] use RMDir for removal of old SC dirs --- cmake/templates/NSIS.template.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 0154d690b7..bdf2b50b3c 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -688,8 +688,8 @@ Section "-Core installation" ;Delete any server-console files installed before it was placed in sub-folder ;This is temporary and can be removed once users who had the initial installer have updated Delete "$INSTDIR\server-console.exe" - Delete "$INSTDIR\locales" - Delete "$INSTDIR\resources\app" + RMDir /r "$INSTDIR\locales" + RMDir /r "$INSTDIR\resources\app" Delete "$INSTDIR\resources\atom.asar" Delete "$INSTDIR\build-info.json" Delete "$INSTDIR\content_resources_200_percent.pak" From 801cbf3faced021503ba3227eded81c937e31696 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Jan 2016 15:59:39 -0800 Subject: [PATCH 38/42] make sure CONSOLE_INSTALL_APP_PATH is defined before use --- cmake/macros/SetPackagingParameters.cmake | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 9aba143c03..b0f093977a 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -53,9 +53,15 @@ macro(SET_PACKAGING_PARAMETERS) set(CONSOLE_INSTALL_DIR ${DMG_SUBFOLDER_NAME}) set(INTERFACE_INSTALL_DIR ${DMG_SUBFOLDER_NAME}) + set(CONSOLE_EXEC_NAME "Server Console.app") + set(CONSOLE_INSTALL_APP_PATH "${CONSOLE_INSTALL_DIR}/${CONSOLE_EXEC_NAME}") + set(CONSOLE_APP_CONTENTS "${CONSOLE_INSTALL_APP_PATH}/Contents") set(COMPONENT_APP_PATH "${CONSOLE_APP_CONTENTS}/MacOS/Components.app") set(COMPONENT_INSTALL_DIR "${COMPONENT_APP_PATH}/Contents/MacOS") + + set(INTERFACE_INSTALL_APP_PATH "${CONSOLE_INSTALL_DIR}/${INTERFACE_BUNDLE_NAME}.app") + set(INTERFACE_ICON_FILENAME "${INTERFACE_ICON_PREFIX}.icns") else () if (WIN32) set(CONSOLE_INSTALL_DIR "server-console") @@ -98,15 +104,6 @@ macro(SET_PACKAGING_PARAMETERS) set(LAUNCH_NOW_REG_KEY "LaunchAfterInstall") endif () - if (APPLE) - - set(CONSOLE_EXEC_NAME "Server Console.app") - set(CONSOLE_INSTALL_APP_PATH "${CONSOLE_INSTALL_DIR}/${CONSOLE_EXEC_NAME}") - - set(INTERFACE_INSTALL_APP_PATH "${CONSOLE_INSTALL_DIR}/${INTERFACE_BUNDLE_NAME}.app") - set(INTERFACE_ICON_FILENAME "${INTERFACE_ICON_PREFIX}.icns") - endif() - # setup component categories for installer set(DDE_COMPONENT dde) set(CLIENT_COMPONENT client) From 9330c3d4f32162f7f8d247d1217dcaee75701f6b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 22 Jan 2016 15:55:43 -0800 Subject: [PATCH 39/42] Fix DS assignment scripts responses --- domain-server/src/DomainServer.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 8d9a28513d..db3c2df408 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1171,7 +1171,6 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url const QString JSON_MIME_TYPE = "application/json"; const QString URI_ASSIGNMENT = "/assignment"; - const QString URI_ASSIGNMENT_SCRIPTS = URI_ASSIGNMENT + "/scripts"; const QString URI_NODES = "/nodes"; const QString URI_SETTINGS = "/settings"; @@ -1212,13 +1211,14 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url if (matchingAssignment && matchingAssignment->getType() == Assignment::AgentType) { // we have a matching assignment and it is for the right type, have the HTTP manager handle it // via correct URL for the script so the client can download - - QUrl scriptURL = url; - scriptURL.setPath(URI_ASSIGNMENT + "/scripts/" - + uuidStringWithoutCurlyBraces(matchingAssignment->getUUID())); - - // have the HTTPManager serve the appropriate script file - return _httpManager.handleHTTPRequest(connection, scriptURL, true); + QFile scriptFile(pathForAssignmentScript(matchingAssignment->getUUID())); + + if (scriptFile.exists() && scriptFile.open(QIODevice::ReadOnly)) { + connection->respond(HTTPConnection::StatusCode200, scriptFile.readAll(), "application/javascript"); + } else { + connection->respond(HTTPConnection::StatusCode404, "Resource not found."); + } + return true; } // request not handled From 41a2173901cfbc0b7ae5bf3e3c7a6d0a3097ab5f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 22 Jan 2016 16:38:28 -0800 Subject: [PATCH 40/42] adjust grab script so that avatars can't bootstrap themselves during an object hand-off --- examples/controllers/handControllerGrab.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 431322d8c2..9dade9191f 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -165,6 +165,7 @@ var STATE_EQUIP_SPRING = 16; // "collidesWith" is specified by comma-separated list of group names // the possible group names are: static, dynamic, kinematic, myAvatar, otherAvatar var COLLIDES_WITH_WHILE_GRABBED = "dynamic,otherAvatar"; +var COLLIDES_WITH_WHILE_MULTI_GRABBED = "dynamic"; function stateToName(state) { switch (state) { @@ -1636,6 +1637,13 @@ function MyController(hand) { "collidesWith": COLLIDES_WITH_WHILE_GRABBED }; Entities.editEntity(entityID, whileHeldProperties); + } else if (data["refCount"] > 1) { + // if an object is being grabbed by more than one person (or the same person twice, but nevermind), switch + // the collision groups so that it wont collide with "other" avatars. This avoids a situation where two + // people are holding something and one of them will be able (if the other releases at the right time) to + // bootstrap themselves with the held object. This happens because the meaning of "otherAvatar" in + // the collision mask hinges on who the physics simulation owner is. + Entities.editEntity(entityID, {"collidesWith": COLLIDES_WITH_WHILE_MULTI_GRABBED}); } setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); @@ -1746,4 +1754,4 @@ function cleanup() { } Script.scriptEnding.connect(cleanup); -Script.update.connect(update); \ No newline at end of file +Script.update.connect(update); From 95f9f7e6d67db164fa4c22f0401b4e25713788b4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Jan 2016 16:10:17 -0800 Subject: [PATCH 41/42] remove old installer files while running new install --- cmake/templates/NSIS.template.in | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index bdf2b50b3c..b0c5b1fe05 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -685,8 +685,9 @@ FunctionEnd ;Installer Sections Section "-Core installation" + ;The following delete blocks are temporary and can be removed once users who had the initial installer have updated + ;Delete any server-console files installed before it was placed in sub-folder - ;This is temporary and can be removed once users who had the initial installer have updated Delete "$INSTDIR\server-console.exe" RMDir /r "$INSTDIR\locales" RMDir /r "$INSTDIR\resources\app" @@ -705,6 +706,10 @@ Section "-Core installation" Delete "$INSTDIR\version" Delete "$INSTDIR\xinput1_3.dll" + ; Remove the Old Interface directory and vcredist_x64.exe (from installs prior to Server Console) + RMDir /r "$INSTDIR\Interface" + Delete "$INSTDIR\vcredist_x64.exe" + ;Use the entire tree produced by the INSTALL target. Keep the ;list of directories here in sync with the RMDir commands below. SetOutPath "$INSTDIR" From 78609ed634a281e50a7d35fcc301b9005c71dd99 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Jan 2016 17:07:05 -0800 Subject: [PATCH 42/42] fix reference to components install path on OS X --- cmake/macros/InstallBesideConsole.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/macros/InstallBesideConsole.cmake b/cmake/macros/InstallBesideConsole.cmake index e257defcb7..4c6087b877 100644 --- a/cmake/macros/InstallBesideConsole.cmake +++ b/cmake/macros/InstallBesideConsole.cmake @@ -55,7 +55,7 @@ macro(install_beside_console) set(COMPONENTS_BUNDLE_PATH "\${CMAKE_INSTALL_PREFIX}/${COMPONENT_APP_PATH}") string(REPLACE " " "\\ " ESCAPED_BUNDLE_NAME ${COMPONENTS_BUNDLE_PATH}) - set(EXECUTABLE_NEEDING_FIXUP "\${CMAKE_INSTALL_PREFIX}/${COMPONENT_DESTINATION}/${TARGET_NAME}") + set(EXECUTABLE_NEEDING_FIXUP "\${CMAKE_INSTALL_PREFIX}/${COMPONENT_INSTALL_DIR}/${TARGET_NAME}") string(REPLACE " " "\\ " ESCAPED_EXECUTABLE_NAME ${EXECUTABLE_NEEDING_FIXUP}) install(CODE "