From 7fc9fd97ff11076fd0b4e75e4cb1282f499be759 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Fri, 10 Jul 2015 11:03:12 -0700 Subject: [PATCH 1/9] Replacing setUniformTexture by setResourceTexture in order to differenciate the 2 types of binding points for the BUffers. --- interface/src/avatar/Avatar.cpp | 2 +- interface/src/ui/ApplicationCompositor.cpp | 2 +- interface/src/ui/ApplicationOverlay.cpp | 2 +- .../src/ui/overlays/BillboardOverlay.cpp | 4 +-- .../RenderableParticleEffectEntityItem.cpp | 2 +- libraries/gpu/src/gpu/Batch.cpp | 8 +++--- libraries/gpu/src/gpu/Batch.h | 6 ++-- libraries/gpu/src/gpu/GLBackend.cpp | 2 +- libraries/gpu/src/gpu/GLBackend.h | 2 +- libraries/gpu/src/gpu/GLBackendPipeline.cpp | 2 +- libraries/model/src/model/Skybox.cpp | 2 +- .../src/DeferredLightingEffect.cpp | 28 +++++++++---------- libraries/render-utils/src/Model.cpp | 10 +++---- .../render-utils/src/RenderDeferredTask.cpp | 2 +- libraries/render-utils/src/TextRenderer3D.cpp | 2 +- 15 files changed, 38 insertions(+), 38 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 3d4c158a0b..0dde96c7ce 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -644,7 +644,7 @@ void Avatar::renderBillboard(RenderArgs* renderArgs) { glm::vec2 texCoordBottomRight(1.0f, 1.0f); gpu::Batch& batch = *renderArgs->_batch; - batch.setUniformTexture(0, _billboardTexture->getGPUTexture()); + batch.setResourceTexture(0, _billboardTexture->getGPUTexture()); DependencyManager::get()->bindSimpleProgram(batch, true); DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index dafa332d53..a1420e3b6a 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -179,7 +179,7 @@ void ApplicationCompositor::bindCursorTexture(gpu::Batch& batch, uint8_t cursorI _cursors[iconId] = DependencyManager::get()-> getImageTexture(iconPath); } - batch.setUniformTexture(0, _cursors[iconId]); + batch.setResourceTexture(0, _cursors[iconId]); } // Draws the FBO texture for the screen diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index e7d220893f..4c3d082bdb 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -196,7 +196,7 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder(RenderArgs* renderAr geometryCache->useSimpleDrawPipeline(batch); batch.setProjectionTransform(mat4()); batch.setModelTransform(mat4()); - batch.setUniformTexture(0, DependencyManager::get()->getWhiteTexture()); + batch.setResourceTexture(0, DependencyManager::get()->getWhiteTexture()); batch._glLineWidth(CONNECTION_STATUS_BORDER_LINE_WIDTH); // TODO animate the disconnect border for some excitement while not connected? diff --git a/interface/src/ui/overlays/BillboardOverlay.cpp b/interface/src/ui/overlays/BillboardOverlay.cpp index 988223765a..1bf4f2a9c7 100644 --- a/interface/src/ui/overlays/BillboardOverlay.cpp +++ b/interface/src/ui/overlays/BillboardOverlay.cpp @@ -87,12 +87,12 @@ void BillboardOverlay::render(RenderArgs* args) { transform.postScale(glm::vec3(getDimensions(), 1.0f)); batch->setModelTransform(transform); - batch->setUniformTexture(0, _texture->getGPUTexture()); + batch->setResourceTexture(0, _texture->getGPUTexture()); DependencyManager::get()->renderQuad(*batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha)); - batch->setUniformTexture(0, args->_whiteTexture); // restore default white color after me + batch->setResourceTexture(0, args->_whiteTexture); // restore default white color after me } } diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index d00728a9eb..2eb95d1bef 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -50,7 +50,7 @@ void RenderableParticleEffectEntityItem::render(RenderArgs* args) { Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; if (textured) { - batch.setUniformTexture(0, _texture->getGPUTexture()); + batch.setResourceTexture(0, _texture->getGPUTexture()); } batch.setModelTransform(getTransformToCenter()); DependencyManager::get()->bindSimpleProgram(batch, textured); diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index b3e6b6117d..b643ba66b8 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -227,15 +227,15 @@ void Batch::setUniformBuffer(uint32 slot, const BufferView& view) { } -void Batch::setUniformTexture(uint32 slot, const TexturePointer& texture) { - ADD_COMMAND(setUniformTexture); +void Batch::setResourceTexture(uint32 slot, const TexturePointer& texture) { + ADD_COMMAND(setResourceTexture); _params.push_back(_textures.cache(texture)); _params.push_back(slot); } -void Batch::setUniformTexture(uint32 slot, const TextureView& view) { - setUniformTexture(slot, view._texture); +void Batch::setResourceTexture(uint32 slot, const TextureView& view) { + setResourceTexture(slot, view._texture); } void Batch::setFramebuffer(const FramebufferPointer& framebuffer) { diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 0cc1a6bee3..6841edb3ef 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -102,8 +102,8 @@ public: void setUniformBuffer(uint32 slot, const BufferPointer& buffer, Offset offset, Offset size); void setUniformBuffer(uint32 slot, const BufferView& view); // not a command, just a shortcut from a BufferView - void setUniformTexture(uint32 slot, const TexturePointer& view); - void setUniformTexture(uint32 slot, const TextureView& view); // not a command, just a shortcut from a TextureView + void setResourceTexture(uint32 slot, const TexturePointer& view); + void setResourceTexture(uint32 slot, const TextureView& view); // not a command, just a shortcut from a TextureView // Framebuffer Stage void setFramebuffer(const FramebufferPointer& framebuffer); @@ -172,7 +172,7 @@ public: COMMAND_setStateBlendFactor, COMMAND_setUniformBuffer, - COMMAND_setUniformTexture, + COMMAND_setResourceTexture, COMMAND_setFramebuffer, diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index 54a54ce2a5..a0320cea1b 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -35,7 +35,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::GLBackend::do_setStateBlendFactor), (&::gpu::GLBackend::do_setUniformBuffer), - (&::gpu::GLBackend::do_setUniformTexture), + (&::gpu::GLBackend::do_setResourceTexture), (&::gpu::GLBackend::do_setFramebuffer), diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 78b0f0838e..2f511ca8d4 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -309,7 +309,7 @@ protected: // Uniform Stage void do_setUniformBuffer(Batch& batch, uint32 paramOffset); - void do_setUniformTexture(Batch& batch, uint32 paramOffset); + void do_setResourceTexture(Batch& batch, uint32 paramOffset); struct UniformStageState { diff --git a/libraries/gpu/src/gpu/GLBackendPipeline.cpp b/libraries/gpu/src/gpu/GLBackendPipeline.cpp index 3b16c58b20..51a3a24e9b 100755 --- a/libraries/gpu/src/gpu/GLBackendPipeline.cpp +++ b/libraries/gpu/src/gpu/GLBackendPipeline.cpp @@ -188,7 +188,7 @@ void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) { (void) CHECK_GL_ERROR(); } -void GLBackend::do_setUniformTexture(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setResourceTexture(Batch& batch, uint32 paramOffset) { GLuint slot = batch._params[paramOffset + 1]._uint; TexturePointer uniformTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); diff --git a/libraries/model/src/model/Skybox.cpp b/libraries/model/src/model/Skybox.cpp index a02c646668..0fb2458f01 100755 --- a/libraries/model/src/model/Skybox.cpp +++ b/libraries/model/src/model/Skybox.cpp @@ -103,7 +103,7 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky batch.setInputBuffer(gpu::Stream::POSITION, theBuffer, 0, 8); batch.setUniformBuffer(SKYBOX_CONSTANTS_SLOT, theConstants, 0, theConstants->getSize()); batch.setInputFormat(theFormat); - batch.setUniformTexture(0, skybox.getCubemap()); + batch.setResourceTexture(0, skybox.getCubemap()); batch.draw(gpu::TRIANGLE_STRIP, 4); } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index a721e0cad3..c8ae000479 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -147,7 +147,7 @@ void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured, if (!config.isTextured()) { // If it is not textured, bind white texture and keep using textured pipeline - batch.setUniformTexture(0, DependencyManager::get()->getWhiteTexture()); + batch.setResourceTexture(0, DependencyManager::get()->getWhiteTexture()); } } @@ -244,13 +244,13 @@ void DeferredLightingEffect::render(RenderArgs* args) { batch.clearColorFramebuffer(freeFBO->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); - batch.setUniformTexture(0, textureCache->getPrimaryColorTexture()); + batch.setResourceTexture(0, textureCache->getPrimaryColorTexture()); - batch.setUniformTexture(1, textureCache->getPrimaryNormalTexture()); + batch.setResourceTexture(1, textureCache->getPrimaryNormalTexture()); - batch.setUniformTexture(2, textureCache->getPrimarySpecularTexture()); + batch.setResourceTexture(2, textureCache->getPrimarySpecularTexture()); - batch.setUniformTexture(3, textureCache->getPrimaryDepthTexture()); + batch.setResourceTexture(3, textureCache->getPrimaryDepthTexture()); // get the viewport side (left, right, both) int viewport[4]; @@ -275,7 +275,7 @@ void DeferredLightingEffect::render(RenderArgs* args) { const LightLocations* locations = &_directionalLightLocations; bool shadowsEnabled = _viewState->getShadowsEnabled(); if (shadowsEnabled) { - batch.setUniformTexture(4, textureCache->getShadowFramebuffer()->getDepthStencilBuffer()); + batch.setResourceTexture(4, textureCache->getShadowFramebuffer()->getDepthStencilBuffer()); program = _directionalLightShadowMap; locations = &_directionalLightShadowMapLocations; @@ -329,7 +329,7 @@ void DeferredLightingEffect::render(RenderArgs* args) { } if (useSkyboxCubemap) { - batch.setUniformTexture(5, _skybox->getCubemap()); + batch.setResourceTexture(5, _skybox->getCubemap()); } if (locations->lightBufferUnit >= 0) { @@ -377,11 +377,11 @@ void DeferredLightingEffect::render(RenderArgs* args) { } if (useSkyboxCubemap) { - batch.setUniformTexture(5, nullptr); + batch.setResourceTexture(5, nullptr); } if (shadowsEnabled) { - batch.setUniformTexture(4, nullptr); + batch.setResourceTexture(4, nullptr); } glm::vec4 sCoefficients(sWidth / 2.0f, 0.0f, 0.0f, sMin + sWidth / 2.0f); @@ -530,10 +530,10 @@ void DeferredLightingEffect::render(RenderArgs* args) { } // Probably not necessary in the long run because the gpu layer would unbound this texture if used as render target - batch.setUniformTexture(0, nullptr); - batch.setUniformTexture(1, nullptr); - batch.setUniformTexture(2, nullptr); - batch.setUniformTexture(3, nullptr); + batch.setResourceTexture(0, nullptr); + batch.setResourceTexture(1, nullptr); + batch.setResourceTexture(2, nullptr); + batch.setResourceTexture(3, nullptr); args->_context->syncCache(); args->_context->render(batch); @@ -551,7 +551,7 @@ void DeferredLightingEffect::copyBack(RenderArgs* args) { batch.setFramebuffer(textureCache->getPrimaryFramebuffer()); batch.setPipeline(_blitLightBuffer); - batch.setUniformTexture(0, freeFBO->getRenderBuffer(0)); + batch.setResourceTexture(0, freeFBO->getRenderBuffer(0)); batch.setProjectionTransform(glm::mat4()); batch.setViewTransform(Transform()); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 03140c4dfb..ce325d23cb 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -2031,10 +2031,10 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran } static bool showDiffuse = true; if (showDiffuse && diffuseMap) { - batch.setUniformTexture(0, diffuseMap->getGPUTexture()); + batch.setResourceTexture(0, diffuseMap->getGPUTexture()); } else { - batch.setUniformTexture(0, textureCache->getWhiteTexture()); + batch.setResourceTexture(0, textureCache->getWhiteTexture()); } if (locations->texcoordMatrices >= 0) { @@ -2050,14 +2050,14 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran if (!mesh.tangents.isEmpty()) { Texture* normalMap = networkPart.normalTexture.data(); - batch.setUniformTexture(1, !normalMap ? + batch.setResourceTexture(1, !normalMap ? textureCache->getBlueTexture() : normalMap->getGPUTexture()); } if (locations->specularTextureUnit >= 0) { Texture* specularMap = networkPart.specularTexture.data(); - batch.setUniformTexture(locations->specularTextureUnit, !specularMap ? + batch.setResourceTexture(locations->specularTextureUnit, !specularMap ? textureCache->getWhiteTexture() : specularMap->getGPUTexture()); } @@ -2074,7 +2074,7 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran GLBATCH(glUniform2f)(locations->emissiveParams, emissiveOffset, emissiveScale); Texture* emissiveMap = networkPart.emissiveTexture.data(); - batch.setUniformTexture(locations->emissiveTextureUnit, !emissiveMap ? + batch.setResourceTexture(locations->emissiveTextureUnit, !emissiveMap ? textureCache->getWhiteTexture() : emissiveMap->getGPUTexture()); } diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 8de5c8af01..cf60c42f98 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -236,7 +236,7 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon batch.setViewTransform(viewMat); batch.setPipeline(getOpaquePipeline()); - batch.setUniformTexture(0, args->_whiteTexture); + batch.setResourceTexture(0, args->_whiteTexture); if (!inItems.empty()) { batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0); diff --git a/libraries/render-utils/src/TextRenderer3D.cpp b/libraries/render-utils/src/TextRenderer3D.cpp index a429719b8b..973cddc4d7 100644 --- a/libraries/render-utils/src/TextRenderer3D.cpp +++ b/libraries/render-utils/src/TextRenderer3D.cpp @@ -423,7 +423,7 @@ void Font3D::drawString(gpu::Batch& batch, float x, float y, const QString& str, setupGPU(); batch.setPipeline(_pipeline); - batch.setUniformTexture(_fontLoc, _texture); + batch.setResourceTexture(_fontLoc, _texture); batch._glUniform1i(_outlineLoc, (effectType == TextRenderer3D::OUTLINE_EFFECT)); batch._glUniform4fv(_colorLoc, 1, (const GLfloat*)color); From 71440dfbc551f9a33278bb3e4b25c0286094684c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 10 Jul 2015 11:30:11 -0700 Subject: [PATCH 2/9] add checks for NaN --- .../entities/src/EntityActionInterface.cpp | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/libraries/entities/src/EntityActionInterface.cpp b/libraries/entities/src/EntityActionInterface.cpp index 2b723d4e15..ba7f3afea4 100644 --- a/libraries/entities/src/EntityActionInterface.cpp +++ b/libraries/entities/src/EntityActionInterface.cpp @@ -127,21 +127,21 @@ glm::vec3 EntityActionInterface::extractVec3Argument(QString objectName, QVarian qDebug() << objectName << "requires argument:" << argumentName; } ok = false; - return glm::vec3(); + return glm::vec3(0.0f); } QVariant resultV = arguments[argumentName]; if (resultV.type() != (QVariant::Type) QMetaType::QVariantMap) { qDebug() << objectName << "argument" << argumentName << "must be a map"; ok = false; - return glm::vec3(); + return glm::vec3(0.0f); } QVariantMap resultVM = resultV.toMap(); if (!resultVM.contains("x") || !resultVM.contains("y") || !resultVM.contains("z")) { - qDebug() << objectName << "argument" << argumentName << "must be a map with keys of x, y, z"; + qDebug() << objectName << "argument" << argumentName << "must be a map with keys: x, y, z"; ok = false; - return glm::vec3(); + return glm::vec3(0.0f); } QVariant xV = resultVM["x"]; @@ -155,9 +155,15 @@ glm::vec3 EntityActionInterface::extractVec3Argument(QString objectName, QVarian float y = yV.toFloat(&yOk); float z = zV.toFloat(&zOk); if (!xOk || !yOk || !zOk) { - qDebug() << objectName << "argument" << argumentName << "must be a map with keys of x, y, z and values of type float."; + qDebug() << objectName << "argument" << argumentName << "must be a map with keys: x, y, and z of type float."; ok = false; - return glm::vec3(); + return glm::vec3(0.0f); + } + + if (x != x || y != y || z != z) { + // at least one of the values is NaN + ok = false; + return glm::vec3(0.0f); } return glm::vec3(x, y, z); @@ -181,8 +187,8 @@ glm::quat EntityActionInterface::extractQuatArgument(QString objectName, QVarian } QVariantMap resultVM = resultV.toMap(); - if (!resultVM.contains("x") || !resultVM.contains("y") || !resultVM.contains("z")) { - qDebug() << objectName << "argument" << argumentName << "must be a map with keys of x, y, z"; + if (!resultVM.contains("x") || !resultVM.contains("y") || !resultVM.contains("z") || !resultVM.contains("w")) { + qDebug() << objectName << "argument" << argumentName << "must be a map with keys: x, y, z, and w"; ok = false; return glm::quat(); } @@ -202,12 +208,18 @@ glm::quat EntityActionInterface::extractQuatArgument(QString objectName, QVarian float w = wV.toFloat(&wOk); if (!xOk || !yOk || !zOk || !wOk) { qDebug() << objectName << "argument" << argumentName - << "must be a map with keys of x, y, z, w and values of type float."; + << "must be a map with keys: x, y, z, and w of type float."; ok = false; return glm::quat(); } - return glm::quat(w, x, y, z); + if (x != x || y != y || z != z || w != w) { + // at least one of the components is NaN! + ok = false; + return glm::quat(); + } + + return glm::normalize(glm::quat(w, x, y, z)); } float EntityActionInterface::extractFloatArgument(QString objectName, QVariantMap arguments, @@ -224,7 +236,7 @@ float EntityActionInterface::extractFloatArgument(QString objectName, QVariantMa bool vOk = true; float v = vV.toFloat(&vOk); - if (!vOk) { + if (!vOk || v != v) { ok = false; return 0.0f; } From 90ae1fea8b2aef2bfc1a0d3d288917202e3aa657 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 10 Jul 2015 11:30:24 -0700 Subject: [PATCH 3/9] handle case where action params are missing --- libraries/physics/src/ObjectActionOffset.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/libraries/physics/src/ObjectActionOffset.cpp b/libraries/physics/src/ObjectActionOffset.cpp index 2391ded13d..00b7fe6734 100644 --- a/libraries/physics/src/ObjectActionOffset.cpp +++ b/libraries/physics/src/ObjectActionOffset.cpp @@ -95,26 +95,21 @@ bool ObjectActionOffset::updateArguments(QVariantMap arguments) { glm::vec3 pointToOffsetFrom = EntityActionInterface::extractVec3Argument("offset action", arguments, "pointToOffsetFrom", ok, true); if (!ok) { - return false; + pointToOffsetFrom = _pointToOffsetFrom; } ok = true; float linearTimeScale = EntityActionInterface::extractFloatArgument("offset action", arguments, "linearTimeScale", ok, false); - if (ok) { - if (linearTimeScale <= 0.0f) { - qDebug() << "offset action -- linearTimeScale must be greater than zero."; - return false; - } - } else { - linearTimeScale = 0.1f; + if (!ok) { + linearTimeScale = _linearTimeScale; } ok = true; float linearDistance = EntityActionInterface::extractFloatArgument("offset action", arguments, "linearDistance", ok, false); if (!ok) { - linearDistance = 0.0f; + linearDistance = _linearDistance; } // only change stuff if something actually changed From 56f00a526d1403a1844156794e78704222f88fda Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 10 Jul 2015 11:31:37 -0700 Subject: [PATCH 4/9] cleanup of ObjectActionSpring --- libraries/physics/src/ObjectActionSpring.cpp | 189 ++++++++----------- libraries/physics/src/ObjectActionSpring.h | 1 + 2 files changed, 78 insertions(+), 112 deletions(-) diff --git a/libraries/physics/src/ObjectActionSpring.cpp b/libraries/physics/src/ObjectActionSpring.cpp index cb1dd20472..21e3c19bea 100644 --- a/libraries/physics/src/ObjectActionSpring.cpp +++ b/libraries/physics/src/ObjectActionSpring.cpp @@ -17,14 +17,16 @@ const float SPRING_MAX_SPEED = 10.0f; const uint16_t ObjectActionSpring::springVersion = 1; + ObjectActionSpring::ObjectActionSpring(const QUuid& id, EntityItemPointer ownerEntity) : ObjectAction(ACTION_TYPE_SPRING, id, ownerEntity), _positionalTarget(glm::vec3(0.0f)), - _linearTimeScale(0.2f), - _positionalTargetSet(false), + _linearTimeScale(FLT_MAX), + _positionalTargetSet(true), _rotationalTarget(glm::quat()), - _angularTimeScale(0.2f), - _rotationalTargetSet(false) { + _angularTimeScale(FLT_MAX), + _rotationalTargetSet(true), + _needsActivation(true) { #if WANT_DEBUG qDebug() << "ObjectActionSpring::ObjectActionSpring"; #endif @@ -61,130 +63,97 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) { return; } - // handle the linear part - if (_positionalTargetSet) { - // check for NaN - if (_positionalTarget.x != _positionalTarget.x || - _positionalTarget.y != _positionalTarget.y || - _positionalTarget.z != _positionalTarget.z) { - qDebug() << "ObjectActionSpring::updateActionWorker -- target position includes NaN"; - unlock(); - lockForWrite(); - _active = false; - unlock(); - return; - } - glm::vec3 offset = _positionalTarget - bulletToGLM(rigidBody->getCenterOfMassPosition()); - float offsetLength = glm::length(offset); - float speed = offsetLength / _linearTimeScale; - - // cap speed - if (speed > SPRING_MAX_SPEED) { - speed = SPRING_MAX_SPEED; - } - - if (offsetLength > IGNORE_POSITION_DELTA) { - glm::vec3 newVelocity = glm::normalize(offset) * speed; - rigidBody->setLinearVelocity(glmToBullet(newVelocity)); - rigidBody->activate(); - } else { - rigidBody->setLinearVelocity(glmToBullet(glm::vec3(0.0f))); - } + const float MAX_TIMESCALE = 600.0f; // 10 min is a long time + if (_linearTimeScale < MAX_TIMESCALE) { + btVector3 offset = rigidBody->getCenterOfMassPosition() - glmToBullet(_positionalTarget); + float offsetLength = offset.length(); + //float blend = glm::min(1.0f, deltaTimeStep / _linearTimeScale); + float blend = 1.0f; + float speed = (offsetLength > FLT_EPSILON) ? glm::min(offsetLength / _linearTimeScale, SPRING_MAX_SPEED) : 0.0f; + rigidBody->setLinearVelocity((1.0f - blend) * rigidBody->getLinearVelocity() - (blend * speed / (offsetLength * _linearTimeScale)) * offset); } - // handle rotation - if (_rotationalTargetSet) { - if (_rotationalTarget.x != _rotationalTarget.x || - _rotationalTarget.y != _rotationalTarget.y || - _rotationalTarget.z != _rotationalTarget.z || - _rotationalTarget.w != _rotationalTarget.w) { - qDebug() << "AvatarActionHold::updateActionWorker -- target rotation includes NaN"; - unlock(); - lockForWrite(); - _active = false; - unlock(); - return; - } + if (_angularTimeScale < MAX_TIMESCALE) { + btVector3 targetVelocity(0.0f, 0.0f, 0.0f); - glm::quat bodyRotation = bulletToGLM(rigidBody->getOrientation()); - // if qZero and qOne are too close to each other, we can get NaN for angle. - auto alignmentDot = glm::dot(bodyRotation, _rotationalTarget); - const float almostOne = 0.99999f; - if (glm::abs(alignmentDot) < almostOne) { - glm::quat target = _rotationalTarget; - if (alignmentDot < 0) { + btQuaternion bodyRotation = rigidBody->getOrientation(); + auto alignmentDot = bodyRotation.dot(glmToBullet(_rotationalTarget)); + const float ALMOST_ONE = 0.99999f; + if (glm::abs(alignmentDot) < ALMOST_ONE) { + btQuaternion target = glmToBullet(_rotationalTarget); + if (alignmentDot < 0.0f) { target = -target; } - glm::quat qZeroInverse = glm::inverse(bodyRotation); - glm::quat deltaQ = target * qZeroInverse; - glm::vec3 axis = glm::axis(deltaQ); - float angle = glm::angle(deltaQ); - assert(!isNaN(angle)); - glm::vec3 newAngularVelocity = (angle / _angularTimeScale) * glm::normalize(axis); - rigidBody->setAngularVelocity(glmToBullet(newAngularVelocity)); - rigidBody->activate(); - } else { - rigidBody->setAngularVelocity(glmToBullet(glm::vec3(0.0f))); + // if dQ is the incremental rotation that gets an object from Q0 to Q1 then: + // + // Q1 = dQ * Q0 + // + // solving for dQ gives: + // + // dQ = Q1 * Q0^ + btQuaternion deltaQ = target * bodyRotation.inverse(); + float angle = deltaQ.getAngle(); + const float MIN_ANGLE = 1.0e-4; + if (angle > MIN_ANGLE) { + targetVelocity = (angle / _angularTimeScale) * deltaQ.getAxis(); + } } + //float blend = glm::min(1.0f, deltaTimeStep / _angularTimeScale); + float blend = 1.0f; + rigidBody->setAngularVelocity((1.0f - blend) * rigidBody->getAngularVelocity() + blend * targetVelocity); + } + if (_needsActivation) { + rigidBody->activate(); + _needsActivation = false; } - unlock(); } +const float MIN_TIMESCALE = 0.1f; bool ObjectActionSpring::updateArguments(QVariantMap arguments) { // targets are required, spring-constants are optional - bool ptOk = true; + bool ok = true; glm::vec3 positionalTarget = - EntityActionInterface::extractVec3Argument("spring action", arguments, "targetPosition", ptOk, false); - bool pscOk = true; + EntityActionInterface::extractVec3Argument("spring action", arguments, "targetPosition", ok, false); + if (!ok) { + positionalTarget = _positionalTarget; + } + ok = true; float linearTimeScale = - EntityActionInterface::extractFloatArgument("spring action", arguments, "linearTimeScale", pscOk, false); - if (ptOk && pscOk && linearTimeScale <= 0.0f) { - qDebug() << "spring action -- linearTimeScale must be greater than zero."; - return false; + EntityActionInterface::extractFloatArgument("spring action", arguments, "linearTimeScale", ok, false); + if (!ok || linearTimeScale <= 0.0f) { + linearTimeScale = _linearTimeScale; } - bool rtOk = true; + ok = true; glm::quat rotationalTarget = - EntityActionInterface::extractQuatArgument("spring action", arguments, "targetRotation", rtOk, false); - bool rscOk = true; + EntityActionInterface::extractQuatArgument("spring action", arguments, "targetRotation", ok, false); + if (!ok) { + rotationalTarget = _rotationalTarget; + } + + ok = true; float angularTimeScale = - EntityActionInterface::extractFloatArgument("spring action", arguments, "angularTimeScale", rscOk, false); - - if (!ptOk && !rtOk) { - qDebug() << "spring action requires at least one of targetPosition or targetRotation argument"; - return false; + EntityActionInterface::extractFloatArgument("spring action", arguments, "angularTimeScale", ok, false); + if (!ok) { + angularTimeScale = _angularTimeScale; } - lockForWrite(); - - _positionalTargetSet = _rotationalTargetSet = false; - - if (ptOk) { + if (positionalTarget != _positionalTarget + || linearTimeScale != _linearTimeScale + || rotationalTarget != _rotationalTarget + || angularTimeScale != _angularTimeScale) { + // something changed + lockForWrite(); _positionalTarget = positionalTarget; - _positionalTargetSet = true; - - if (pscOk) { - _linearTimeScale = linearTimeScale; - } else { - _linearTimeScale = 0.1f; - } - } - - if (rtOk) { + _linearTimeScale = glm::max(MIN_TIMESCALE, glm::abs(linearTimeScale)); _rotationalTarget = rotationalTarget; - _rotationalTargetSet = true; - - if (rscOk) { - _angularTimeScale = angularTimeScale; - } else { - _angularTimeScale = 0.1f; - } + _angularTimeScale = glm::max(MIN_TIMESCALE, glm::abs(angularTimeScale)); + _active = true; + _needsActivation = true; + unlock(); } - - _active = true; - unlock(); return true; } @@ -192,15 +161,11 @@ QVariantMap ObjectActionSpring::getArguments() { QVariantMap arguments; lockForRead(); - if (_positionalTargetSet) { - arguments["linearTimeScale"] = _linearTimeScale; - arguments["targetPosition"] = glmToQMap(_positionalTarget); - } + arguments["linearTimeScale"] = _linearTimeScale; + arguments["targetPosition"] = glmToQMap(_positionalTarget); - if (_rotationalTargetSet) { - arguments["targetRotation"] = glmToQMap(_rotationalTarget); - arguments["angularTimeScale"] = _angularTimeScale; - } + arguments["targetRotation"] = glmToQMap(_rotationalTarget); + arguments["angularTimeScale"] = _angularTimeScale; unlock(); return arguments; diff --git a/libraries/physics/src/ObjectActionSpring.h b/libraries/physics/src/ObjectActionSpring.h index caa64c3d3a..a0a829bdab 100644 --- a/libraries/physics/src/ObjectActionSpring.h +++ b/libraries/physics/src/ObjectActionSpring.h @@ -37,6 +37,7 @@ protected: glm::quat _rotationalTarget; float _angularTimeScale; bool _rotationalTargetSet; + bool _needsActivation; }; #endif // hifi_ObjectActionSpring_h From 294c1ba367fe5de853bd9f3b91de62a60150ae17 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 10 Jul 2015 12:17:21 -0700 Subject: [PATCH 5/9] always serialize ACTION_TYPE_SPRING --- libraries/physics/src/ObjectActionSpring.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/ObjectActionSpring.cpp b/libraries/physics/src/ObjectActionSpring.cpp index 21e3c19bea..c1ef94296a 100644 --- a/libraries/physics/src/ObjectActionSpring.cpp +++ b/libraries/physics/src/ObjectActionSpring.cpp @@ -175,7 +175,7 @@ QByteArray ObjectActionSpring::serialize() const { QByteArray serializedActionArguments; QDataStream dataStream(&serializedActionArguments, QIODevice::WriteOnly); - dataStream << getType(); + dataStream << ACTION_TYPE_SPRING; dataStream << getID(); dataStream << ObjectActionSpring::springVersion; @@ -195,7 +195,7 @@ void ObjectActionSpring::deserialize(QByteArray serializedArguments) { EntityActionType type; dataStream >> type; - assert(type == getType()); + assert(type == ACTION_TYPE_SPRING); QUuid id; dataStream >> id; From 9cb7e86877f297944e845a919f4d5b3362dc28d0 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 10 Jul 2015 12:18:09 -0700 Subject: [PATCH 6/9] cleanup of AvatarActionHold deserialization --- interface/src/avatar/AvatarActionHold.cpp | 100 ++++++++-------------- 1 file changed, 38 insertions(+), 62 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index ba37112fe1..1e75250ee2 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -70,30 +70,14 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { return; } - // check for NaNs - if (position.x != position.x || - position.y != position.y || - position.z != position.z) { - qDebug() << "AvatarActionHold::updateActionWorker -- target position includes NaN"; - return; - } - if (rotation.x != rotation.x || - rotation.y != rotation.y || - rotation.z != rotation.z || - rotation.w != rotation.w) { - qDebug() << "AvatarActionHold::updateActionWorker -- target rotation includes NaN"; - return; - } - if (_positionalTarget != position || _rotationalTarget != rotation) { auto ownerEntity = _ownerEntity.lock(); if (ownerEntity) { ownerEntity->setActionDataDirty(true); } + _positionalTarget = position; + _rotationalTarget = rotation; } - - _positionalTarget = position; - _rotationalTarget = rotation; unlock(); ObjectActionSpring::updateActionWorker(deltaTimeStep); @@ -101,59 +85,51 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { bool AvatarActionHold::updateArguments(QVariantMap arguments) { - bool rPOk = true; + bool ok = true; glm::vec3 relativePosition = - EntityActionInterface::extractVec3Argument("hold", arguments, "relativePosition", rPOk, false); - bool rROk = true; + EntityActionInterface::extractVec3Argument("hold", arguments, "relativePosition", ok, false); + if (!ok) { + relativePosition = _relativePosition; + } + + ok = true; glm::quat relativeRotation = - EntityActionInterface::extractQuatArgument("hold", arguments, "relativeRotation", rROk, false); - bool tSOk = true; + EntityActionInterface::extractQuatArgument("hold", arguments, "relativeRotation", ok, false); + if (!ok) { + relativeRotation = _relativeRotation; + } + + ok = true; float timeScale = - EntityActionInterface::extractFloatArgument("hold", arguments, "timeScale", tSOk, false); - bool hOk = true; + EntityActionInterface::extractFloatArgument("hold", arguments, "timeScale", ok, false); + if (!ok) { + timeScale = _linearTimeScale; + } + + ok = true; QString hand = - EntityActionInterface::extractStringArgument("hold", arguments, "hand", hOk, false); + EntityActionInterface::extractStringArgument("hold", arguments, "hand", ok, false); + if (!ok || !(hand == "left" || hand == "right")) { + hand = _hand; + } - lockForWrite(); - if (rPOk) { + if (relativePosition != _relativePosition + || relativeRotation != _relativeRotation + || timeScale != _linearTimeScale + || hand != _hand) { + lockForWrite(); _relativePosition = relativePosition; - } else { - _relativePosition = glm::vec3(0.0f, 0.0f, 1.0f); - } - - if (rROk) { _relativeRotation = relativeRotation; - } else { - _relativeRotation = glm::quat(0.0f, 0.0f, 0.0f, 1.0f); - } + const float MIN_TIMESCALE = 0.1f; + _linearTimeScale = glm::min(MIN_TIMESCALE, timeScale); + _angularTimeScale = _linearTimeScale; + _hand = hand; - if (tSOk) { - _linearTimeScale = timeScale; - _angularTimeScale = timeScale; - } else { - _linearTimeScale = 0.2f; - _angularTimeScale = 0.2f; + _mine = true; + _active = true; + _needsActivation = true; + unlock(); } - - if (hOk) { - hand = hand.toLower(); - if (hand == "left") { - _hand = "left"; - } else if (hand == "right") { - _hand = "right"; - } else { - qDebug() << "hold action -- invalid hand argument:" << hand; - _hand = "right"; - } - } else { - _hand = "right"; - } - - _mine = true; - _positionalTargetSet = true; - _rotationalTargetSet = true; - _active = true; - unlock(); return true; } From 98f10e72ec4f5662604d2b93c5357e538e002c34 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Fri, 10 Jul 2015 15:20:49 -0700 Subject: [PATCH 7/9] fix the wrong function name that happened missing a merge --- interface/src/audio/AudioScope.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/audio/AudioScope.cpp b/interface/src/audio/AudioScope.cpp index 7a93be80f1..4b4e86e7f4 100644 --- a/interface/src/audio/AudioScope.cpp +++ b/interface/src/audio/AudioScope.cpp @@ -130,7 +130,7 @@ void AudioScope::render(RenderArgs* renderArgs, int width, int height) { auto geometryCache = DependencyManager::get(); geometryCache->useSimpleDrawPipeline(batch); auto textureCache = DependencyManager::get(); - batch.setUniformTexture(0, textureCache->getWhiteTexture()); + batch.setResourceTexture(0, textureCache->getWhiteTexture()); mat4 legacyProjection = glm::ortho(0, width, height, 0, -1000, 1000); batch.setProjectionTransform(legacyProjection); batch.setModelTransform(Transform()); From c340d336dcfb319dee2b84b528687a0c95658f1b Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Fri, 10 Jul 2015 15:43:56 -0700 Subject: [PATCH 8/9] Functional sword script: Mouse and hydra. Switchable hands. Scores above buttons (2d) and above head in-world. Adds avatar hit sound while sword is brandished. --- examples/example/games/sword.js | 259 +++++++++++++++++++------------- 1 file changed, 156 insertions(+), 103 deletions(-) diff --git a/examples/example/games/sword.js b/examples/example/games/sword.js index 66503b62aa..18d6911f0b 100644 --- a/examples/example/games/sword.js +++ b/examples/example/games/sword.js @@ -11,24 +11,26 @@ // "use strict"; /*jslint vars: true*/ -var Script, Entities, MyAvatar, Window, Overlays, Controller, Vec3, Quat, print, ToolBar; // Referenced globals provided by High Fidelity. -Script.include(["../../libraries/toolBars.js"]); +var Script, Entities, MyAvatar, Window, Overlays, Controller, Vec3, Quat, print, ToolBar, Settings; // Referenced globals provided by High Fidelity. +Script.include("http://s3.amazonaws.com/hifi-public/scripts/libraries/toolBars.js"); -var hand = "right"; +var hand = Settings.getValue("highfidelity.sword.hand", "right"); var nullActionID = "00000000-0000-0000-0000-000000000000"; var controllerID; var controllerActive; var stickID = null; var actionID = nullActionID; var targetIDs = []; -var dimensions = { x: 0.3, y: 0.1, z: 2.0 }; -var AWAY_ORIENTATION = Quat.fromPitchYawRollDegrees(-90, 0, 0); +var dimensions = { x: 0.3, y: 0.15, z: 2.0 }; var BUTTON_SIZE = 32; var stickModel = "https://hifi-public.s3.amazonaws.com/eric/models/stick.fbx"; var swordModel = "https://hifi-public.s3.amazonaws.com/ozan/props/sword/sword.fbx"; +var swordCollisionShape = "https://hifi-public.s3.amazonaws.com/ozan/props/sword/sword.obj"; +var swordCollisionSoundURL = "http://public.highfidelity.io/sounds/Collisions-hitsandslaps/swordStrike1.wav"; +var avatarCollisionSoundURL = "https://s3.amazonaws.com/hifi-public/sounds/Collisions-hitsandslaps/airhockey_hit1.wav"; var whichModel = "sword"; -var attachmentOffset, MOUSE_CONTROLLER_OFFSET = {x: 0.5, y: 0.4, z: 0.0}; // A fudge when using mouse rather than hand-controller, to hit yourself less often. +var originalAvatarCollisionSound; var toolBar = new ToolBar(0, 0, ToolBar.vertical, "highfidelity.sword.toolbar", function () { return {x: 100, y: 380}; @@ -37,6 +39,7 @@ var toolBar = new ToolBar(0, 0, ToolBar.vertical, "highfidelity.sword.toolbar", var SWORD_IMAGE = "http://s3.amazonaws.com/hifi-public/images/billiardsReticle.png"; // Toggle between brandishing/sheathing sword (creating if necessary) var TARGET_IMAGE = "http://s3.amazonaws.com/hifi-public/images/puck.png"; // Create a target dummy var CLEANUP_IMAGE = "http://s3.amazonaws.com/hifi-public/images/delete.png"; // Remove sword and all target dummies.f +var SWITCH_HANDS_IMAGE = "http://s3.amazonaws.com/hifi-public/images/up-arrow.svg"; // Toggle left vs right hand. Persists in settings. var swordButton = toolBar.addOverlay("image", { width: BUTTON_SIZE, height: BUTTON_SIZE, @@ -49,6 +52,12 @@ var targetButton = toolBar.addOverlay("image", { imageURL: TARGET_IMAGE, alpha: 1 }); +var switchHandsButton = toolBar.addOverlay("image", { + width: BUTTON_SIZE, + height: BUTTON_SIZE, + imageURL: SWITCH_HANDS_IMAGE, + alpha: 1 +}); var cleanupButton = toolBar.addOverlay("image", { width: BUTTON_SIZE, height: BUTTON_SIZE, @@ -77,53 +86,51 @@ function flash(color) { flasher.timer = Script.setTimeout(clearFlash, 500); } - var health = 100; -var display; -var isAway = false; +var display2d, display3d; +function trackAvatarWithText() { + Entities.editEntity(display3d, { + position: Vec3.sum(MyAvatar.position, {x: 0, y: 1.5, z: 0}), + rotation: Quat.multiply(MyAvatar.orientation, Quat.fromPitchYawRollDegrees(0, 180, 0)) + }); +} function updateDisplay() { var text = health.toString(); - if (!display) { + if (!display2d) { health = 100; - display = Overlays.addOverlay("text", { + display2d = Overlays.addOverlay("text", { text: text, font: { size: 20 }, color: {red: 0, green: 255, blue: 0}, backgroundColor: {red: 100, green: 100, blue: 100}, // Why doesn't this and the next work? backgroundAlpha: 0.9, - x: Window.innerWidth - 50, - y: 50 + x: toolBar.x - 5, // I'd like to add the score to the toolBar and have it drag with it, but toolBar doesn't support text (just buttons). + y: toolBar.y - 30 // So next best thing is to position it each time as if it were on top. }); + display3d = Entities.addEntity({ + name: MyAvatar.displayName + " score", + textColor: {red: 255, green: 255, blue: 255}, + type: "Text", + text: text, + lineHeight: 0.14, + backgroundColor: {red: 64, green: 64, blue: 64}, + dimensions: {x: 0.3, y: 0.2, z: 0.01}, + }); + Script.update.connect(trackAvatarWithText); } else { - Overlays.editOverlay(display, {text: text}); + Overlays.editOverlay(display2d, {text: text}); + Entities.editEntity(display3d, {text: text}); } } function removeDisplay() { - if (display) { - Overlays.deleteOverlay(display); - display = null; + if (display2d) { + Overlays.deleteOverlay(display2d); + display2d = null; + Script.update.disconnect(trackAvatarWithText); + Entities.deleteEntity(display3d); + display3d = null; } } - -function cleanUp(leaveButtons) { - attachmentOffset = {x: 0, y: 0, z: 0}; - if (stickID) { - Entities.deleteAction(stickID, actionID); - Entities.deleteEntity(stickID); - stickID = null; - actionID = null; - } - targetIDs.forEach(function (id) { - Entities.deleteAction(id.entity, id.action); - Entities.deleteEntity(id.entity); - }); - targetIDs = []; - removeDisplay(); - if (!leaveButtons) { - toolBar.cleanup(); - } -} - function computeEnergy(collision, entityID) { var id = entityID || collision.idA || collision.idB; var entity = id && Entities.getEntityProperties(id); @@ -133,31 +140,67 @@ function computeEnergy(collision, entityID) { return Math.min(Math.max(1.0, Math.round(energy)), 20); } function gotHit(collision) { - if (isAway) { return; } var energy = computeEnergy(collision); + print("Got hit - " + energy + " from " + collision.idA + " " + collision.idB); health -= energy; flash({red: 255, green: 0, blue: 0}); updateDisplay(); } function scoreHit(idA, idB, collision) { - if (isAway) { return; } var energy = computeEnergy(collision, idA); + print("Score + " + energy + " from " + JSON.stringify(idA) + " " + JSON.stringify(idB)); health += energy; flash({red: 0, green: 255, blue: 0}); updateDisplay(); } -function positionStick(stickOrientation) { - var baseOffset = Vec3.sum(attachmentOffset, {x: 0.0, y: 0.0, z: -dimensions.z / 2}); - var offset = Vec3.multiplyQbyV(stickOrientation, baseOffset); - Entities.updateAction(stickID, actionID, {relativePosition: offset, - relativeRotation: stickOrientation}); +function isFighting() { + return stickID && (actionID !== nullActionID); } - +function initControls() { + print("Sword hand is " + hand); + if (hand === "right") { + controllerID = 3; // right handed + } else { + controllerID = 4; // left handed + } +} +var inHand = false; +function positionStick(stickOrientation) { + var reorient = Quat.fromPitchYawRollDegrees(0, -90, 0); + var baseOffset = {x: -dimensions.z * 0.8, y: 0, z: 0}; + var offset = Vec3.multiplyQbyV(reorient, baseOffset); + stickOrientation = Quat.multiply(reorient, stickOrientation); + inHand = false; + Entities.updateAction(stickID, actionID, { + relativePosition: offset, + relativeRotation: stickOrientation + }); +} +function resetToHand() { // Maybe coordinate with positionStick? + if (inHand) { // Optimization: bail if we're already inHand. + return; + } + print('Reset to hand'); + Entities.updateAction(stickID, actionID, { + relativePosition: {x: 0.0, y: 0.0, z: -dimensions.z * 0.5}, + relativeRotation: Quat.fromVec3Degrees({x: 45.0, y: 0.0, z: 0.0}), + hand: hand, // It should not be necessary to repeat these two, but there seems to be a bug in that that + timeScale: 0.05 // they do not retain their earlier values if you don't repeat them. + }); + inHand = true; +} function mouseMoveEvent(event) { - attachmentOffset = MOUSE_CONTROLLER_OFFSET; - if (!stickID || actionID === nullActionID || isAway) { + if (event.deviceID) { // Not a MOUSE mouse event, but a (e.g., hydra) mouse event, with x/y that is not meaningful for us. + resetToHand(); // Can only happen when controller is uncradled, so let's drive with that, resetting our attachement. + return; + } + controllerActive = (Vec3.length(Controller.getSpatialControlPosition(controllerID)) > 0); + //print("Mouse move with hand controller " + (controllerActive ? "active" : "inactive") + JSON.stringify(event)); + if (controllerActive || !isFighting()) { + print('Attempting attachment reset'); + resetToHand(); return; } var windowCenterX = Window.innerWidth / 2; @@ -167,73 +210,80 @@ function mouseMoveEvent(event) { var mouseXRatio = mouseXCenterOffset / windowCenterX; var mouseYRatio = mouseYCenterOffset / windowCenterY; - var stickOrientation = Quat.fromPitchYawRollDegrees(mouseYRatio * -90, mouseXRatio * -90, 0); + var stickOrientation = Quat.fromPitchYawRollDegrees(mouseYRatio * 90, mouseXRatio * 90, 0); positionStick(stickOrientation); } - -function initControls() { - if (hand === "right") { - controllerID = 3; // right handed - } else { - controllerID = 4; // left handed +function removeSword() { + if (stickID) { + print('deleting action ' + actionID + ' and entity ' + stickID); + Entities.deleteAction(stickID, actionID); + Entities.deleteEntity(stickID); + stickID = null; + actionID = nullActionID; + Controller.mouseMoveEvent.disconnect(mouseMoveEvent); + MyAvatar.collisionWithEntity.disconnect(gotHit); + // removeEventhHandler happens automatically when the entity is deleted. + } + inHand = false; + if (originalAvatarCollisionSound !== undefined) { + MyAvatar.collisionSoundURL = originalAvatarCollisionSound; + } + removeDisplay(); +} +function cleanUp(leaveButtons) { + removeSword(); + targetIDs.forEach(function (id) { + Entities.deleteAction(id.entity, id.action); + Entities.deleteEntity(id.entity); + }); + targetIDs = []; + if (!leaveButtons) { + toolBar.cleanup(); } } - - -function update() { - var palmPosition = Controller.getSpatialControlPosition(controllerID); - controllerActive = (Vec3.length(palmPosition) > 0); - if (!controllerActive) { - return; +function makeSword() { + initControls(); + stickID = Entities.addEntity({ + type: "Model", + modelURL: swordModel, + compoundShapeURL: swordCollisionShape, + dimensions: dimensions, + position: (hand === 'right') ? MyAvatar.getRightPalmPosition() : MyAvatar.getLeftPalmPosition(), // initial position doesn't matter, as long as it's close + rotation: MyAvatar.orientation, + damping: 0.1, + collisionSoundURL: swordCollisionSoundURL, + restitution: 0.01, + collisionsWillMove: true + }); + actionID = Entities.addAction("hold", stickID, { + relativePosition: {x: 0.0, y: 0.0, z: -dimensions.z * 0.5}, + relativeRotation: Quat.fromVec3Degrees({x: 45.0, y: 0.0, z: 0.0}), + hand: hand, + timeScale: 0.05 + }); + if (actionID === nullActionID) { + print('*** FAILED TO MAKE SWORD ACTION ***'); + cleanUp(); } - - var stickOrientation = Controller.getSpatialControlRawRotation(controllerID); - var adjustment = Quat.fromPitchYawRollDegrees(180, 0, 0); - stickOrientation = Quat.multiply(stickOrientation, adjustment); - - positionStick(stickOrientation); -} - -function toggleAway() { - isAway = !isAway; - if (isAway) { - positionStick(AWAY_ORIENTATION); - removeDisplay(); - } else { - updateDisplay(); + if (originalAvatarCollisionSound === undefined) { + originalAvatarCollisionSound = MyAvatar.collisionSoundURL; // We won't get MyAvatar.collisionWithEntity unless there's a sound URL. (Bug.) + SoundCache.getSound(avatarCollisionSoundURL); // Interface does not currently "preload" this? (Bug?) } + MyAvatar.collisionSoundURL = avatarCollisionSoundURL; + Controller.mouseMoveEvent.connect(mouseMoveEvent); + MyAvatar.collisionWithEntity.connect(gotHit); + Script.addEventHandler(stickID, 'collisionWithEntity', scoreHit); + updateDisplay(); } function onClick(event) { switch (Overlays.getOverlayAtPoint(event)) { case swordButton: if (!stickID) { - initControls(); - stickID = Entities.addEntity({ - type: "Model", - modelURL: (whichModel === "sword") ? swordModel : stickModel, - //compoundShapeURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.obj", - shapeType: "box", - dimensions: dimensions, - position: MyAvatar.getRightPalmPosition(), // initial position doesn't matter, as long as it's close - rotation: MyAvatar.orientation, - damping: 0.1, - collisionSoundURL: "http://public.highfidelity.io/sounds/Collisions-hitsandslaps/swordStrike1.wav", - restitution: 0.01, - collisionsWillMove: true - }); - actionID = Entities.addAction("hold", stickID, {relativePosition: {x: 0.0, y: 0.0, z: -dimensions.z / 2}, - hand: hand, - timeScale: 0.15}); - if (actionID === nullActionID) { - print('*** FAILED TO MAKE SWORD ACTION ***'); - cleanUp(); - } - Script.addEventHandler(stickID, 'collisionWithEntity', scoreHit); - updateDisplay(); + makeSword(); } else { - toggleAway(); + removeSword(); } break; case targetButton: @@ -256,6 +306,12 @@ function onClick(event) { }); targetIDs.push({entity: boxId, action: action}); break; + case switchHandsButton: + cleanUp('leaveButtons'); + hand = hand === "right" ? "left" : "right"; + Settings.setValue("highfidelity.sword.hand", hand); + makeSword(); + break; case cleanupButton: cleanUp('leaveButtons'); break; @@ -263,7 +319,4 @@ function onClick(event) { } Script.scriptEnding.connect(cleanUp); -Controller.mouseMoveEvent.connect(mouseMoveEvent); Controller.mousePressEvent.connect(onClick); -Script.update.connect(update); -MyAvatar.collisionWithEntity.connect(gotHit); From 9ce9c541defef086bf9c24c0e3252a0ced649e71 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 10 Jul 2015 18:45:40 -0700 Subject: [PATCH 9/9] fix activation of object when action changes --- interface/src/avatar/AvatarActionHold.cpp | 2 +- libraries/entities/src/EntityItem.cpp | 6 +++++- .../entities/src/EntityScriptingInterface.cpp | 3 +++ libraries/physics/src/ObjectAction.cpp | 7 +++++++ libraries/physics/src/ObjectAction.h | 1 + libraries/physics/src/ObjectActionOffset.cpp | 6 +----- libraries/physics/src/ObjectActionOffset.h | 1 - libraries/physics/src/ObjectActionSpring.cpp | 20 +++++++------------ libraries/physics/src/ObjectActionSpring.h | 1 - 9 files changed, 25 insertions(+), 22 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 1e75250ee2..0c5145b596 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -127,7 +127,7 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { _mine = true; _active = true; - _needsActivation = true; + activateBody(); unlock(); } return true; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 794d0752a1..024e54dbaa 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1496,7 +1496,7 @@ bool EntityItem::addAction(EntitySimulation* simulation, EntityActionPointer act bool result = addActionInternal(simulation, action); if (!result) { - removeAction(simulation, action->getID()); + removeActionInternal(action->getID()); } unlock(); @@ -1520,6 +1520,7 @@ bool EntityItem::addActionInternal(EntitySimulation* simulation, EntityActionPoi QByteArray newDataCache = serializeActions(success); if (success) { _allActionsDataCache = newDataCache; + _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; } return success; } @@ -1537,6 +1538,7 @@ bool EntityItem::updateAction(EntitySimulation* simulation, const QUuid& actionI bool success = action->updateArguments(arguments); if (success) { _allActionsDataCache = serializeActions(success); + _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; } else { qDebug() << "EntityItem::updateAction failed"; } @@ -1572,6 +1574,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* s bool success = true; _allActionsDataCache = serializeActions(success); + _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; return success; } return false; @@ -1590,6 +1593,7 @@ bool EntityItem::clearActions(EntitySimulation* simulation) { // empty _serializedActions means no actions for the EntityItem _actionsToRemove.clear(); _allActionsDataCache.clear(); + _dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION; unlock(); return true; } diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index f1c6157694..18175da1f6 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -543,6 +543,9 @@ bool EntityScriptingInterface::actionWorker(const QUuid& entityID, } bool success = actor(simulation, entity); + if (success) { + _entityTree->entityChanged(entity); + } _entityTree->unlock(); // transmit the change diff --git a/libraries/physics/src/ObjectAction.cpp b/libraries/physics/src/ObjectAction.cpp index 101b69f03a..5205e08c62 100644 --- a/libraries/physics/src/ObjectAction.cpp +++ b/libraries/physics/src/ObjectAction.cpp @@ -129,3 +129,10 @@ void ObjectAction::setAngularVelocity(glm::vec3 angularVelocity) { rigidBody->activate(); } +void ObjectAction::activateBody() { + auto rigidBody = getRigidBody(); + if (rigidBody) { + rigidBody->activate(); + } +} + diff --git a/libraries/physics/src/ObjectAction.h b/libraries/physics/src/ObjectAction.h index f619657e92..f27ed9ab07 100644 --- a/libraries/physics/src/ObjectAction.h +++ b/libraries/physics/src/ObjectAction.h @@ -55,6 +55,7 @@ protected: virtual void setLinearVelocity(glm::vec3 linearVelocity); virtual glm::vec3 getAngularVelocity(); virtual void setAngularVelocity(glm::vec3 angularVelocity); + virtual void activateBody(); void lockForRead() { _lock.lockForRead(); } bool tryLockForRead() { return _lock.tryLockForRead(); } diff --git a/libraries/physics/src/ObjectActionOffset.cpp b/libraries/physics/src/ObjectActionOffset.cpp index 00b7fe6734..a00bbbd418 100644 --- a/libraries/physics/src/ObjectActionOffset.cpp +++ b/libraries/physics/src/ObjectActionOffset.cpp @@ -59,10 +59,6 @@ void ObjectActionOffset::updateActionWorker(btScalar deltaTimeStep) { const float MAX_LINEAR_TIMESCALE = 600.0f; // 10 minutes is a long time if (_positionalTargetSet && _linearTimeScale < MAX_LINEAR_TIMESCALE) { - if (_needsActivation) { - rigidBody->activate(); - _needsActivation = false; - } glm::vec3 objectPosition = bulletToGLM(rigidBody->getCenterOfMassPosition()); glm::vec3 springAxis = objectPosition - _pointToOffsetFrom; // from anchor to object float distance = glm::length(springAxis); @@ -122,7 +118,7 @@ bool ObjectActionOffset::updateArguments(QVariantMap arguments) { _linearDistance = linearDistance; _positionalTargetSet = true; _active = true; - _needsActivation = true; + activateBody(); unlock(); } return true; diff --git a/libraries/physics/src/ObjectActionOffset.h b/libraries/physics/src/ObjectActionOffset.h index a0190f3832..1918da6996 100644 --- a/libraries/physics/src/ObjectActionOffset.h +++ b/libraries/physics/src/ObjectActionOffset.h @@ -36,7 +36,6 @@ public: float _linearDistance; float _linearTimeScale; bool _positionalTargetSet; - bool _needsActivation = true; }; #endif // hifi_ObjectActionOffset_h diff --git a/libraries/physics/src/ObjectActionSpring.cpp b/libraries/physics/src/ObjectActionSpring.cpp index c1ef94296a..dde47f7c4e 100644 --- a/libraries/physics/src/ObjectActionSpring.cpp +++ b/libraries/physics/src/ObjectActionSpring.cpp @@ -25,8 +25,7 @@ ObjectActionSpring::ObjectActionSpring(const QUuid& id, EntityItemPointer ownerE _positionalTargetSet(true), _rotationalTarget(glm::quat()), _angularTimeScale(FLT_MAX), - _rotationalTargetSet(true), - _needsActivation(true) { + _rotationalTargetSet(true) { #if WANT_DEBUG qDebug() << "ObjectActionSpring::ObjectActionSpring"; #endif @@ -67,10 +66,10 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) { if (_linearTimeScale < MAX_TIMESCALE) { btVector3 offset = rigidBody->getCenterOfMassPosition() - glmToBullet(_positionalTarget); float offsetLength = offset.length(); - //float blend = glm::min(1.0f, deltaTimeStep / _linearTimeScale); - float blend = 1.0f; float speed = (offsetLength > FLT_EPSILON) ? glm::min(offsetLength / _linearTimeScale, SPRING_MAX_SPEED) : 0.0f; - rigidBody->setLinearVelocity((1.0f - blend) * rigidBody->getLinearVelocity() - (blend * speed / (offsetLength * _linearTimeScale)) * offset); + + // this action is aggresively critically damped and defeats the current velocity + rigidBody->setLinearVelocity((- speed / offsetLength) * offset); } if (_angularTimeScale < MAX_TIMESCALE) { @@ -98,13 +97,8 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) { targetVelocity = (angle / _angularTimeScale) * deltaQ.getAxis(); } } - //float blend = glm::min(1.0f, deltaTimeStep / _angularTimeScale); - float blend = 1.0f; - rigidBody->setAngularVelocity((1.0f - blend) * rigidBody->getAngularVelocity() + blend * targetVelocity); - } - if (_needsActivation) { - rigidBody->activate(); - _needsActivation = false; + // this action is aggresively critically damped and defeats the current velocity + rigidBody->setAngularVelocity(targetVelocity); } unlock(); } @@ -151,7 +145,7 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) { _rotationalTarget = rotationalTarget; _angularTimeScale = glm::max(MIN_TIMESCALE, glm::abs(angularTimeScale)); _active = true; - _needsActivation = true; + activateBody(); unlock(); } return true; diff --git a/libraries/physics/src/ObjectActionSpring.h b/libraries/physics/src/ObjectActionSpring.h index a0a829bdab..caa64c3d3a 100644 --- a/libraries/physics/src/ObjectActionSpring.h +++ b/libraries/physics/src/ObjectActionSpring.h @@ -37,7 +37,6 @@ protected: glm::quat _rotationalTarget; float _angularTimeScale; bool _rotationalTargetSet; - bool _needsActivation; }; #endif // hifi_ObjectActionSpring_h