From fac497dadc139f3c1e649178c1ccf2fc2c0e4e14 Mon Sep 17 00:00:00 2001 From: Marcel Verhagen Date: Tue, 14 Jul 2015 15:31:56 +0200 Subject: [PATCH 01/74] Removed the file where the directory is stripped off the RelativeFilename, and replace \ with /. However this introduces a new problem with the current fbx files who do not have their textures in the original dir but moved it to the dir where the fbx file lives. Suppose there should be some logic when the texture is not found to look if the texture lives in the dir above the RelativeFilename. In any case it is not obvious when there is a texture missing on a model, it simply renders black. --- libraries/fbx/src/FBXReader.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 236e2979f5..24cbc983ed 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1781,9 +1781,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, TextureParam tex; foreach (const FBXNode& subobject, object.children) { if (subobject.name == "RelativeFilename") { - // trim off any path information QByteArray filename = subobject.properties.at(0).toByteArray(); - filename = filename.mid(qMax(filename.lastIndexOf('\\'), filename.lastIndexOf('/')) + 1); + filename = filename.replace('\\', '/'); textureFilenames.insert(getID(object.properties), filename); } else if (subobject.name == "TextureName") { // trim the name from the timestamp From eb48aa10185e8b5323ea2b3e2365fd1b6259e43d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Sun, 19 Jul 2015 12:10:37 -0700 Subject: [PATCH 02/74] Update edit.js to swing up on activate --- examples/libraries/entityCameraTool.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/libraries/entityCameraTool.js b/examples/libraries/entityCameraTool.js index d27d95c161..a3b817e300 100644 --- a/examples/libraries/entityCameraTool.js +++ b/examples/libraries/entityCameraTool.js @@ -141,7 +141,7 @@ CameraManager = function() { // Pick a point INITIAL_ZOOM_DISTANCE in front of the camera to use as a focal point that.zoomDistance = INITIAL_ZOOM_DISTANCE; - that.targetZoomDistance = that.zoomDistance; + that.targetZoomDistance = that.zoomDistance + 3.0; var focalPoint = Vec3.sum(Camera.getPosition(), Vec3.multiply(that.zoomDistance, Quat.getFront(Camera.getOrientation()))); @@ -150,6 +150,7 @@ CameraManager = function() { var xzDist = Math.sqrt(dPos.x * dPos.x + dPos.z * dPos.z); that.targetPitch = -Math.atan2(dPos.y, xzDist) * 180 / Math.PI; + that.targetPitch += (90 - that.targetPitch) / 3.0; // Swing camera "up" to look down at the focal point that.targetYaw = Math.atan2(dPos.x, dPos.z) * 180 / Math.PI; that.pitch = that.targetPitch; that.yaw = that.targetYaw; From 3439d45e0ee6b53027dcea062adfec2bf1566d93 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 20 Jul 2015 10:44:38 -0700 Subject: [PATCH 03/74] adding hit effect logic --- libraries/render-utils/src/HitEffect.cpp | 105 ++++++++++++++++++ libraries/render-utils/src/HitEffect.h | 34 ++++++ .../render-utils/src/RenderDeferredTask.cpp | 4 + libraries/render-utils/src/hit_effect.slf | 29 +++++ libraries/render-utils/src/hit_effect.slv | 21 ++++ 5 files changed, 193 insertions(+) create mode 100644 libraries/render-utils/src/HitEffect.cpp create mode 100644 libraries/render-utils/src/HitEffect.h create mode 100644 libraries/render-utils/src/hit_effect.slf create mode 100644 libraries/render-utils/src/hit_effect.slv diff --git a/libraries/render-utils/src/HitEffect.cpp b/libraries/render-utils/src/HitEffect.cpp new file mode 100644 index 0000000000..1b81c3b85f --- /dev/null +++ b/libraries/render-utils/src/HitEffect.cpp @@ -0,0 +1,105 @@ +// +// HitEffect.cpp +// interface/src/renderer +// +// Created by Andrzej Kapolka on 7/14/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL +#include + +#include + +#include + +#include +#include + +#include "AbstractViewStateInterface.h" +#include "HitEffect.h" +#include "ProgramObject.h" +#include "RenderUtil.h" +#include "TextureCache.h" +#include "DependencyManager.h" +#include "ViewFrustum.h" +#include "GeometryCache.h" + +#include "hit_effect_vert.h" +#include "hit_effect_frag.h" + + +HitEffect::HitEffect() { +} + +const gpu::PipelinePointer& HitEffect::getHitEffectPipeline() { + if (!_hitEffectPipeline) { + auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(hit_effect_vert))); + auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(hit_effect_frag))); + gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*program, slotBindings); + + _screenSizeLocation = program->getUniforms().findLocation("screenSize"); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + + state->setDepthTest(false, false, gpu::LESS_EQUAL); + + // Blend on transparent + state->setBlendFunction(true, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); + + + // Good to go add the brand new pipeline + _hitEffectPipeline.reset(gpu::Pipeline::create(program, state)); + } + return _hitEffectPipeline; +} + + + + +void HitEffect::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { + + // create a simple pipeline that does: + + assert(renderContext->args); + assert(renderContext->args->_viewFrustum); + RenderArgs* args = renderContext->args; + + // Allright, something to render let's do it + gpu::Batch batch; + + glm::mat4 projMat; + Transform viewMat; + args->_viewFrustum->evalProjectionMatrix(projMat); + args->_viewFrustum->evalViewTransform(viewMat); + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + batch.setModelTransform(Transform()); + + + + + // bind the first gpu::Pipeline we need - for calculating occlusion buffer + batch.setPipeline(getHitEffectPipeline()); + + + glm::vec4 color(0.0f, 0.0f, 0.0f, 1.0f); + glm::vec2 bottomLeft(-1.0f, -1.0f); + glm::vec2 topRight(1.0f, 1.0f); + DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, color); + + + // Ready to render + renderContext->args->_context->syncCache(); + args->_context->render((batch)); + +} + diff --git a/libraries/render-utils/src/HitEffect.h b/libraries/render-utils/src/HitEffect.h new file mode 100644 index 0000000000..3ee05a27aa --- /dev/null +++ b/libraries/render-utils/src/HitEffect.h @@ -0,0 +1,34 @@ +// +// hitEffect.h +// hifi +// +// Created by eric levin on 7/17/15. +// +// + +#ifndef hifi_hitEffect_h +#define hifi_hitEffect_h + +#include +#include "render/DrawTask.h" + +class AbstractViewStateInterface; +class ProgramObject; + +class HitEffect { +public: + + HitEffect(); + + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); + typedef render::Job::Model JobModel; + + const gpu::PipelinePointer& getHitEffectPipeline(); + +private: + + gpu::PipelinePointer _hitEffectPipeline; + GLuint _screenSizeLocation; +}; + +#endif diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index fab134913d..95e0344313 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -16,6 +16,7 @@ #include "ViewFrustum.h" #include "RenderArgs.h" #include "TextureCache.h" +#include "HitEffect.h" #include "render/DrawStatus.h" @@ -54,6 +55,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortOpaque", _jobs.back().getOutput()))); auto& renderedOpaques = _jobs.back().getOutput(); _jobs.push_back(Job(new DrawOpaqueDeferred::JobModel("DrawOpaqueDeferred", _jobs.back().getOutput()))); + _jobs.push_back(Job(new DrawLight::JobModel("DrawLight"))); _jobs.push_back(Job(new ResetGLState::JobModel())); _jobs.push_back(Job(new RenderDeferred::JobModel("RenderDeferred"))); @@ -75,7 +77,9 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _drawStatusJobIndex = _jobs.size() - 1; _jobs.push_back(Job(new DrawOverlay3D::JobModel("DrawOverlay3D"))); + _jobs.push_back(Job(new HitEffect::JobModel("HitEffect"))); _jobs.push_back(Job(new ResetGLState::JobModel())); + // Give ourselves 3 frmaes of timer queries _timerQueries.push_back(gpu::QueryPointer(new gpu::Query())); diff --git a/libraries/render-utils/src/hit_effect.slf b/libraries/render-utils/src/hit_effect.slf new file mode 100644 index 0000000000..cd94de3620 --- /dev/null +++ b/libraries/render-utils/src/hit_effect.slf @@ -0,0 +1,29 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// ambient_occlusion.frag +// fragment shader +// +// Created by Eric Levin on 7/20 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +<@include gpu/Transform.slh@> +<$declareStandardTransform()$> +<@include DeferredBufferWrite.slh@> + +void main(void) { + + TransformCamera cam = getTransformCamera(); + vec4 myViewport; + <$transformCameraViewport(cam, myViewport)$> + vec2 center = vec2(myViewport.z/2.0, myViewport.w/2.0); + float distFromCenter = distance(center, gl_FragCoord.xy); + //normalize + distFromCenter = distFromCenter/myViewport.z; + float alpha = mix(0.0, 1.0, distFromCenter); + gl_FragColor = vec4(0.7, 0.0, 0.0, alpha); +} \ No newline at end of file diff --git a/libraries/render-utils/src/hit_effect.slv b/libraries/render-utils/src/hit_effect.slv new file mode 100644 index 0000000000..c12e3e71f8 --- /dev/null +++ b/libraries/render-utils/src/hit_effect.slv @@ -0,0 +1,21 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// ambient_occlusion.vert +// vertex shader +// +// Created by Niraj Venkat on 7/20/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include gpu/Transform.slh@> + +<$declareStandardTransform()$> + +void main(void) { + gl_Position = gl_Vertex; +} \ No newline at end of file From e75a6feafe3fd73fe599e47bdaf814399a70d547 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 20 Jul 2015 11:58:26 -0700 Subject: [PATCH 04/74] can toggle hit effect on and off from a script --- interface/src/Application.cpp | 1 + libraries/render-utils/src/RenderDeferredTask.cpp | 7 +++++++ libraries/render-utils/src/RenderDeferredTask.h | 4 ++++ libraries/render-utils/src/hit_effect.slf | 9 +++++---- libraries/render/src/render/Engine.h | 1 + libraries/script-engine/src/SceneScriptingInterface.h | 5 +++++ 6 files changed, 23 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 342580e03c..0fb4bbcc74 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3570,6 +3570,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se renderContext._maxDrawnOverlay3DItems = sceneInterface->getEngineMaxDrawnOverlay3DItems(); renderContext._drawItemStatus = sceneInterface->doEngineDisplayItemStatus(); + renderContext._drawHitEffect = sceneInterface->doEngineDisplayHitEffect(); renderArgs->_shouldRender = LODManager::shouldRender; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 95e0344313..b9767105c3 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -78,6 +78,9 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _jobs.push_back(Job(new DrawOverlay3D::JobModel("DrawOverlay3D"))); _jobs.push_back(Job(new HitEffect::JobModel("HitEffect"))); + _jobs.back().setEnabled(false); + _drawHitEffectJobIndex = _jobs.size() -1; + _jobs.push_back(Job(new ResetGLState::JobModel())); @@ -106,6 +109,10 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend // Make sure we turn the displayItemStatus on/off setDrawItemStatus(renderContext->_drawItemStatus); + + //Make sure we display hit effect on screen, as desired from a script + setDrawHitEffect(renderContext->_drawHitEffect); + renderContext->args->_context->syncCache(); diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 4040606c62..b3957fe7dc 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -71,9 +71,13 @@ public: render::Jobs _jobs; int _drawStatusJobIndex = -1; + int _drawHitEffectJobIndex = -1; void setDrawItemStatus(bool draw) { if (_drawStatusJobIndex >= 0) { _jobs[_drawStatusJobIndex].setEnabled(draw); } } bool doDrawItemStatus() const { if (_drawStatusJobIndex >= 0) { return _jobs[_drawStatusJobIndex].isEnabled(); } else { return false; } } + + void setDrawHitEffect(bool draw) { if (_drawHitEffectJobIndex >= 0) { _jobs[_drawHitEffectJobIndex].setEnabled(draw); } } + bool doDrawHitEffect() const { if (_drawHitEffectJobIndex >=0) { return _jobs[_drawHitEffectJobIndex].isEnabled(); } else { return false; } } virtual void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); diff --git a/libraries/render-utils/src/hit_effect.slf b/libraries/render-utils/src/hit_effect.slf index cd94de3620..5a5d85b21f 100644 --- a/libraries/render-utils/src/hit_effect.slf +++ b/libraries/render-utils/src/hit_effect.slf @@ -22,8 +22,9 @@ void main(void) { <$transformCameraViewport(cam, myViewport)$> vec2 center = vec2(myViewport.z/2.0, myViewport.w/2.0); float distFromCenter = distance(center, gl_FragCoord.xy); - //normalize - distFromCenter = distFromCenter/myViewport.z; - float alpha = mix(0.0, 1.0, distFromCenter); - gl_FragColor = vec4(0.7, 0.0, 0.0, alpha); + //normalize distance from center based on average of screen width and height + float normalizationFactor = (myViewport.z + myViewport.w)/2.0; + distFromCenter = distFromCenter/normalizationFactor; + float alpha = mix(0.0, 1.0, pow(distFromCenter, 1.5)); + gl_FragColor = vec4(1.0, 0.0, 0.0, alpha); } \ No newline at end of file diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 1c600b13d6..e12d37118c 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -50,6 +50,7 @@ public: int _maxDrawnOverlay3DItems = -1; bool _drawItemStatus = false; + bool _drawHitEffect = false; RenderContext() {} }; diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index 674b452528..a3ce2a7300 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -109,6 +109,9 @@ public: Q_INVOKABLE void setEngineDisplayItemStatus(bool display) { _drawItemStatus = display; } Q_INVOKABLE bool doEngineDisplayItemStatus() { return _drawItemStatus; } + + Q_INVOKABLE void setEngineDisplayHitEffect(bool display) { _drawHitEffect = display; } + Q_INVOKABLE bool doEngineDisplayHitEffect() { return _drawHitEffect; } signals: void shouldRenderAvatarsChanged(bool shouldRenderAvatars); @@ -141,6 +144,8 @@ protected: int _maxDrawnOverlay3DItems = -1; bool _drawItemStatus = false; + + bool _drawHitEffect = false; }; From dcb20120703a48df6a9fa59072db819ea03b2435 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 20 Jul 2015 12:02:01 -0700 Subject: [PATCH 05/74] can toggle hit effect on and off from a script --- examples/example/games/hitEffect.js | 28 +++++++++++++++++++++++ libraries/render-utils/src/hit_effect.slf | 2 +- libraries/render-utils/src/hit_effect.slv | 4 ++-- 3 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 examples/example/games/hitEffect.js diff --git a/examples/example/games/hitEffect.js b/examples/example/games/hitEffect.js new file mode 100644 index 0000000000..0ba9ea14d1 --- /dev/null +++ b/examples/example/games/hitEffect.js @@ -0,0 +1,28 @@ +// +// hitEffect.js +// examples +// +// Created by Eric Levin on July 20, 2015 +// Copyright 2015 High Fidelity, Inc. +// +// An example of how to toggle a screen-space hit effect using the Scene global object. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +var hitEffectEnabled = false; + +toggleHitEffect(); + +function toggleHitEffect() { + Script.setTimeout(function() { + hitEffectEnabled = !hitEffectEnabled; + Scene.setEngineDisplayHitEffect(hitEffectEnabled); + toggleHitEffect(); + }, 1000); +} + + + + + diff --git a/libraries/render-utils/src/hit_effect.slf b/libraries/render-utils/src/hit_effect.slf index 5a5d85b21f..2c308f3711 100644 --- a/libraries/render-utils/src/hit_effect.slf +++ b/libraries/render-utils/src/hit_effect.slf @@ -2,7 +2,7 @@ <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // -// ambient_occlusion.frag +// hit_effect.frag // fragment shader // // Created by Eric Levin on 7/20 diff --git a/libraries/render-utils/src/hit_effect.slv b/libraries/render-utils/src/hit_effect.slv index c12e3e71f8..e7c3062667 100644 --- a/libraries/render-utils/src/hit_effect.slv +++ b/libraries/render-utils/src/hit_effect.slv @@ -2,10 +2,10 @@ <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // -// ambient_occlusion.vert +// hit_effect.vert // vertex shader // -// Created by Niraj Venkat on 7/20/15. +// Created by Eric Levin on 7/20/15. // Copyright 2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. From 8f0893ba2153b5a10f22aa0cff4cd573de3063cf Mon Sep 17 00:00:00 2001 From: Marcel Verhagen Date: Wed, 22 Jul 2015 22:34:45 +0200 Subject: [PATCH 06/74] Added fileOnUrl to check if a texture exist at the location. It return the correct filename of where the texture lives. Added the url of the fix file to extractFBXGeometry and readFBX and updated the calls to readFBX to include the url of the fix file. So it now does not break existing content. Found a second place in the FBXReader.cpp where the RelativeFileName stripped out the dir location. --- interface/src/ModelPackager.cpp | 2 +- libraries/animation/src/AnimationCache.cpp | 2 +- libraries/fbx/src/FBXReader.cpp | 31 +++++++++++++++----- libraries/fbx/src/FBXReader.h | 4 +-- libraries/render-utils/src/GeometryCache.cpp | 2 +- tools/vhacd-util/src/VHACDUtil.cpp | 2 +- 6 files changed, 29 insertions(+), 14 deletions(-) diff --git a/interface/src/ModelPackager.cpp b/interface/src/ModelPackager.cpp index 2864738f9c..09d572c31d 100644 --- a/interface/src/ModelPackager.cpp +++ b/interface/src/ModelPackager.cpp @@ -106,7 +106,7 @@ bool ModelPackager::loadModel() { } qCDebug(interfaceapp) << "Reading FBX file : " << _fbxInfo.filePath(); QByteArray fbxContents = fbx.readAll(); - _geometry = readFBX(fbxContents, QVariantHash()); + _geometry = readFBX(fbxContents, QVariantHash(), _fbxInfo.filePath()); // make sure we have some basic mappings populateBasicMapping(_mapping, _fbxInfo.filePath(), _geometry); diff --git a/libraries/animation/src/AnimationCache.cpp b/libraries/animation/src/AnimationCache.cpp index 6c02ccbd2b..0aa5c34544 100644 --- a/libraries/animation/src/AnimationCache.cpp +++ b/libraries/animation/src/AnimationCache.cpp @@ -65,7 +65,7 @@ void AnimationReader::run() { QSharedPointer animation = _animation.toStrongRef(); if (!animation.isNull()) { QMetaObject::invokeMethod(animation.data(), "setGeometry", - Q_ARG(const FBXGeometry&, readFBX(_reply->readAll(), QVariantHash()))); + Q_ARG(const FBXGeometry&, readFBX(_reply->readAll(), QVariantHash(), _reply->property("url").toString()))); } _reply->deleteLater(); } diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 24cbc983ed..554d56ee5a 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -1454,9 +1455,23 @@ void buildModelMesh(ExtractedMesh& extracted) { } #endif // USE_MODEL_MESH +QByteArray fileOnUrl(const QByteArray filenameString,const QString url) { + QString path = QFileInfo(url).path(); + QByteArray filename = filenameString; + QFileInfo checkFile(path + "/" + filename.replace('\\', '/')); + //check if the file exists at the RelativeFileName + if (checkFile.exists() && checkFile.isFile()) { + filename = filename.replace('\\', '/'); + } else { + // there is not texture at the filename. Assume it is in the root dir. + filename = filename.mid(qMax(filename.lastIndexOf('\\'), filename.lastIndexOf('/')) + 1); + } + filename = filename.mid(qMax(filename.lastIndexOf('\\'), filename.lastIndexOf('/')) + 1); + filename = filename.replace('\\', '/'); + return filename; +} - -FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, bool loadLightmaps, float lightmapLevel) { +FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, QString url, bool loadLightmaps, float lightmapLevel) { QHash meshes; QHash modelIDsToNames; QHash meshIDsToMeshIndices; @@ -1782,7 +1797,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, foreach (const FBXNode& subobject, object.children) { if (subobject.name == "RelativeFilename") { QByteArray filename = subobject.properties.at(0).toByteArray(); - filename = filename.replace('\\', '/'); + filename = fileOnUrl(filename, url); textureFilenames.insert(getID(object.properties), filename); } else if (subobject.name == "TextureName") { // trim the name from the timestamp @@ -1856,7 +1871,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, foreach (const FBXNode& subobject, object.children) { if (subobject.name == "RelativeFilename") { filename = subobject.properties.at(0).toByteArray(); - filename = filename.mid(qMax(filename.lastIndexOf('\\'), filename.lastIndexOf('/')) + 1); + filename = fileOnUrl(filename, url); } else if (subobject.name == "Content" && !subobject.properties.isEmpty()) { content = subobject.properties.at(0).toByteArray(); @@ -2709,12 +2724,12 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, return geometry; } -FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool loadLightmaps, float lightmapLevel) { +FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, const QString url, bool loadLightmaps, float lightmapLevel) { QBuffer buffer(const_cast(&model)); buffer.open(QIODevice::ReadOnly); - return readFBX(&buffer, mapping, loadLightmaps, lightmapLevel); + return readFBX(&buffer, mapping, url, loadLightmaps, lightmapLevel); } -FBXGeometry readFBX(QIODevice* device, const QVariantHash& mapping, bool loadLightmaps, float lightmapLevel) { - return extractFBXGeometry(parseFBX(device), mapping, loadLightmaps, lightmapLevel); +FBXGeometry readFBX(QIODevice* device, const QVariantHash& mapping, const QString url, bool loadLightmaps, float lightmapLevel) { + return extractFBXGeometry(parseFBX(device), mapping, url, loadLightmaps, lightmapLevel); } diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 200cd4a121..cf86c304ac 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -268,10 +268,10 @@ Q_DECLARE_METATYPE(FBXGeometry) /// Reads FBX geometry from the supplied model and mapping data. /// \exception QString if an error occurs in parsing -FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool loadLightmaps = true, float lightmapLevel = 1.0f); +FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, const QString url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f); /// Reads FBX geometry from the supplied model and mapping data. /// \exception QString if an error occurs in parsing -FBXGeometry readFBX(QIODevice* device, const QVariantHash& mapping, bool loadLightmaps = true, float lightmapLevel = 1.0f); +FBXGeometry readFBX(QIODevice* device, const QVariantHash& mapping, const QString url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f); #endif // hifi_FBXReader_h diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 02e59bfa3a..3d32ba74ad 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -2185,7 +2185,7 @@ void GeometryReader::run() { } else if (_url.path().toLower().endsWith("palaceoforinthilian4.fbx")) { lightmapLevel = 3.5f; } - fbxgeo = readFBX(_reply, _mapping, grabLightmaps, lightmapLevel); + fbxgeo = readFBX(_reply, _mapping, _url.path(), grabLightmaps, lightmapLevel); } else if (_url.path().toLower().endsWith(".obj")) { fbxgeo = OBJReader().readOBJ(_reply, _mapping, &_url); } diff --git a/tools/vhacd-util/src/VHACDUtil.cpp b/tools/vhacd-util/src/VHACDUtil.cpp index f1ff0e9e4f..d775244b9c 100644 --- a/tools/vhacd-util/src/VHACDUtil.cpp +++ b/tools/vhacd-util/src/VHACDUtil.cpp @@ -38,7 +38,7 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, FBXGeometry& result) { if (filename.toLower().endsWith(".obj")) { result = OBJReader().readOBJ(fbxContents, QVariantHash()); } else if (filename.toLower().endsWith(".fbx")) { - result = readFBX(fbxContents, QVariantHash()); + result = readFBX(fbxContents, QVariantHash(), filename); } else { qDebug() << "unknown file extension"; return false; From d25e09af74544db662a2e92637439386b00cb284 Mon Sep 17 00:00:00 2001 From: Marcel Verhagen Date: Sun, 26 Jul 2015 00:48:31 +0200 Subject: [PATCH 07/74] removed the last 2 filename lines, they should not be there. --- libraries/fbx/src/FBXReader.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 554d56ee5a..69482a8c81 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1463,11 +1463,9 @@ QByteArray fileOnUrl(const QByteArray filenameString,const QString url) { if (checkFile.exists() && checkFile.isFile()) { filename = filename.replace('\\', '/'); } else { - // there is not texture at the filename. Assume it is in the root dir. + // there is no texture at the fbx dir with the filename added. Assume it is in the fbx dir. filename = filename.mid(qMax(filename.lastIndexOf('\\'), filename.lastIndexOf('/')) + 1); } - filename = filename.mid(qMax(filename.lastIndexOf('\\'), filename.lastIndexOf('/')) + 1); - filename = filename.replace('\\', '/'); return filename; } From 8ac06c4059f696dcac5fec67a1241fbb52c2c079 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 27 Jul 2015 08:48:16 -0700 Subject: [PATCH 08/74] remove friend class from Avatar --- interface/src/avatar/Avatar.h | 13 +++++++------ interface/src/avatar/AvatarManager.cpp | 8 ++++---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index a587e69642..8ae4b9fb4d 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -186,9 +186,10 @@ public: virtual void computeShapeInfo(ShapeInfo& shapeInfo); - friend class AvatarManager; + void setMotionState(AvatarMotionState* motionState) { _motionState = motionState; } + AvatarMotionState* getMotionState() { return _motionState; } -signals: + signals: void collisionWithAvatar(const QUuid& myUUID, const QUuid& theirUUID, const CollisionInfo& collision); protected: @@ -218,7 +219,7 @@ protected: glm::vec3 _worldUpDirection; float _stringLength; bool _moving; ///< set when position is changing - + // protected methods... glm::vec3 getBodyRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } glm::vec3 getBodyUpDirection() const { return getOrientation() * IDENTITY_UP; } @@ -243,7 +244,7 @@ protected: virtual void updateJointMappings(); render::ItemID _renderItemID; - + private: bool _initialized; NetworkTexturePointer _billboardTexture; @@ -251,9 +252,9 @@ private: bool _isLookAtTarget; void renderBillboard(RenderArgs* renderArgs); - + float getBillboardSize() const; - + static int _jointConesID; int _voiceSphereID; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index ead330a41f..ee59a01e07 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -179,11 +179,11 @@ AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWe // protected void AvatarManager::removeAvatarMotionState(AvatarSharedPointer avatar) { auto rawPointer = std::static_pointer_cast(avatar); - AvatarMotionState* motionState= rawPointer->_motionState; + AvatarMotionState* motionState = rawPointer->getMotionState(); if (motionState) { // clean up physics stuff motionState->clearObjectBackPointer(); - rawPointer->_motionState = nullptr; + rawPointer->setMotionState(nullptr); _avatarMotionStates.remove(motionState); _motionStatesToAdd.remove(motionState); _motionStatesToDelete.push_back(motionState); @@ -307,7 +307,7 @@ void AvatarManager::updateAvatarPhysicsShape(const QUuid& id) { AvatarHash::iterator avatarItr = _avatarHash.find(id); if (avatarItr != _avatarHash.end()) { auto avatar = std::static_pointer_cast(avatarItr.value()); - AvatarMotionState* motionState = avatar->_motionState; + AvatarMotionState* motionState = avatar->getMotionState(); if (motionState) { motionState->addDirtyFlags(EntityItem::DIRTY_SHAPE); } else { @@ -316,7 +316,7 @@ void AvatarManager::updateAvatarPhysicsShape(const QUuid& id) { btCollisionShape* shape = ObjectMotionState::getShapeManager()->getShape(shapeInfo); if (shape) { AvatarMotionState* motionState = new AvatarMotionState(avatar.get(), shape); - avatar->_motionState = motionState; + avatar->setMotionState(motionState); _motionStatesToAdd.insert(motionState); _avatarMotionStates.insert(motionState); } From 7e582830415b351d40e3366ab4f77bf6b53b7194 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 27 Jul 2015 08:54:08 -0700 Subject: [PATCH 09/74] change the methods that aren't called from outside the class to be private --- interface/src/avatar/MyAvatar.h | 131 +++++++++++++++----------------- 1 file changed, 62 insertions(+), 69 deletions(-) diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 802c92ec2c..4fd66c0347 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -39,51 +39,40 @@ public: MyAvatar(RigPointer rig); ~MyAvatar(); - QByteArray toByteArray(); + void reset(); void update(float deltaTime); - void simulate(float deltaTime); void preRender(RenderArgs* renderArgs); - void updateFromTrackers(float deltaTime); - virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPositio) override; - virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel = 0.0f) override; - virtual bool shouldRenderHead(const RenderArgs* renderArgs) const override; - - // setters void setLeanScale(float scale) { _leanScale = scale; } - void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; } void setRealWorldFieldOfView(float realWorldFov) { _realWorldFieldOfView.set(realWorldFov); } - // getters float getLeanScale() const { return _leanScale; } Q_INVOKABLE glm::vec3 getDefaultEyePosition() const; - bool getShouldRenderLocally() const { return _shouldRender; } + float getRealWorldFieldOfView() { return _realWorldFieldOfView.get(); } - + const QList& getAnimationHandles() const { return _rig->getAnimationHandles(); } AnimationHandlePointer addAnimationHandle() { return _rig->createAnimationHandle(); } void removeAnimationHandle(const AnimationHandlePointer& handle) { _rig->removeAnimationHandle(handle); } - /// Allows scripts to run animations. Q_INVOKABLE void startAnimation(const QString& url, float fps = 30.0f, float priority = 1.0f, bool loop = false, - bool hold = false, float firstFrame = 0.0f, float lastFrame = FLT_MAX, const QStringList& maskedJoints = QStringList()); - + bool hold = false, float firstFrame = 0.0f, + float lastFrame = FLT_MAX, const QStringList& maskedJoints = QStringList()); /// Stops an animation as identified by a URL. Q_INVOKABLE void stopAnimation(const QString& url); - + /// Starts an animation by its role, using the provided URL and parameters if the avatar doesn't have a custom /// animation for the role. Q_INVOKABLE void startAnimationByRole(const QString& role, const QString& url = QString(), float fps = 30.0f, - float priority = 1.0f, bool loop = false, bool hold = false, float firstFrame = 0.0f, - float lastFrame = FLT_MAX, const QStringList& maskedJoints = QStringList()); - + float priority = 1.0f, bool loop = false, bool hold = false, float firstFrame = 0.0f, + float lastFrame = FLT_MAX, const QStringList& maskedJoints = QStringList()); /// Stops an animation identified by its role. Q_INVOKABLE void stopAnimationByRole(const QString& role); - Q_INVOKABLE AnimationDetails getAnimationDetailsByRole(const QString& role); Q_INVOKABLE AnimationDetails getAnimationDetails(const QString& url); - + void clearJointAnimationPriorities(); + // get/set avatar data void saveData(); void loadData(); @@ -94,41 +83,32 @@ public: // Set what driving keys are being pressed to control thrust levels void clearDriveKeys(); void setDriveKeys(int key, float val) { _driveKeys[key] = val; }; - bool getDriveKeys(int key) { return _driveKeys[key] != 0.0f; }; - void relayDriveKeysToCharacterController(); - bool isMyAvatar() const { return true; } - eyeContactTarget getEyeContactTarget(); - virtual int parseDataFromBuffer(const QByteArray& buffer); - static void sendKillAvatar(); - + Q_INVOKABLE glm::vec3 getTrackedHeadPosition() const { return _trackedHeadPosition; } Q_INVOKABLE glm::vec3 getHeadPosition() const { return getHead()->getPosition(); } Q_INVOKABLE float getHeadFinalYaw() const { return getHead()->getFinalYaw(); } Q_INVOKABLE float getHeadFinalRoll() const { return getHead()->getFinalRoll(); } Q_INVOKABLE float getHeadFinalPitch() const { return getHead()->getFinalPitch(); } Q_INVOKABLE float getHeadDeltaPitch() const { return getHead()->getDeltaPitch(); } - + Q_INVOKABLE glm::vec3 getEyePosition() const { return getHead()->getEyePosition(); } - + Q_INVOKABLE glm::vec3 getTargetAvatarPosition() const { return _targetAvatarPosition; } + AvatarWeakPointer getLookAtTargetAvatar() const { return _lookAtTargetAvatar; } void updateLookAtTargetAvatar(); void clearLookAtTargetAvatar(); - - virtual void setJointRotations(QVector jointRotations); - virtual void setJointData(int index, const glm::quat& rotation); - virtual void clearJointData(int index); - virtual void clearJointsData(); Q_INVOKABLE void useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName = QString()); Q_INVOKABLE void useHeadURL(const QUrl& headURL, const QString& modelName = QString()); Q_INVOKABLE void useBodyURL(const QUrl& bodyURL, const QString& modelName = QString()); - Q_INVOKABLE void useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, const QString& headName = QString(), const QString& bodyName = QString()); + Q_INVOKABLE void useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, + const QString& headName = QString(), const QString& bodyName = QString()); Q_INVOKABLE bool getUseFullAvatar() const { return _useFullAvatar; } Q_INVOKABLE const QUrl& getFullAvatarURLFromPreferences() const { return _fullAvatarURLFromPreferences; } @@ -143,48 +123,30 @@ public: virtual void setAttachmentData(const QVector& attachmentData); - virtual glm::vec3 getSkeletonPosition() const; - void updateLocalAABox(); DynamicCharacterController* getCharacterController() { return &_characterController; } - - void clearJointAnimationPriorities(); - glm::vec3 getScriptedMotorVelocity() const { return _scriptedMotorVelocity; } - float getScriptedMotorTimescale() const { return _scriptedMotorTimescale; } - QString getScriptedMotorFrame() const; - - void setScriptedMotorVelocity(const glm::vec3& velocity); - void setScriptedMotorTimescale(float timescale); - void setScriptedMotorFrame(QString frame); const QString& getCollisionSoundURL() {return _collisionSoundURL; } void setCollisionSoundURL(const QString& url); void clearScriptableSettings(); - virtual void attach(const QString& modelURL, const QString& jointName = QString(), - const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), float scale = 1.0f, - bool allowDuplicates = false, bool useSaved = true); - /// Renders a laser pointer for UI picking - void renderLaserPointers(gpu::Batch& batch); + glm::vec3 getLaserPointerTipPosition(const PalmData* palm); - - const RecorderPointer getRecorder() const { return _recorder; } - const PlayerPointer getPlayer() const { return _player; } - + float getBoomLength() const { return _boomLength; } void setBoomLength(float boomLength) { _boomLength = boomLength; } - + static const float ZOOM_MIN; static const float ZOOM_MAX; static const float ZOOM_DEFAULT; - + public slots: void increaseSize(); void decreaseSize(); void resetSize(); - + void goToLocation(const glm::vec3& newPosition, bool hasOrientation = false, const glm::quat& newOrientation = glm::quat(), bool shouldFaceLocation = false); @@ -204,7 +166,7 @@ public slots: void clearReferential(); bool setModelReferential(const QUuid& id); bool setJointReferential(const QUuid& id, int jointIndex); - + bool isRecording(); qint64 recorderElapsed(); void startRecording(); @@ -213,7 +175,7 @@ public slots: void loadLastRecording(); virtual void rebuildSkeletonBody(); - + signals: void transformChanged(); void newCollisionSoundURL(const QUrl& url); @@ -221,6 +183,37 @@ signals: private: + QByteArray toByteArray(); + void simulate(float deltaTime); + void updateFromTrackers(float deltaTime); + virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPositio) override; + virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel = 0.0f) override; + virtual bool shouldRenderHead(const RenderArgs* renderArgs) const override; + void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; } + bool getShouldRenderLocally() const { return _shouldRender; } + bool getDriveKeys(int key) { return _driveKeys[key] != 0.0f; }; + bool isMyAvatar() const { return true; } + virtual int parseDataFromBuffer(const QByteArray& buffer); + virtual void setJointRotations(QVector jointRotations); + virtual void setJointData(int index, const glm::quat& rotation); + virtual void clearJointData(int index); + virtual void clearJointsData(); + virtual glm::vec3 getSkeletonPosition() const; + void updateLocalAABox(); + glm::vec3 getScriptedMotorVelocity() const { return _scriptedMotorVelocity; } + float getScriptedMotorTimescale() const { return _scriptedMotorTimescale; } + QString getScriptedMotorFrame() const; + void setScriptedMotorVelocity(const glm::vec3& velocity); + void setScriptedMotorTimescale(float timescale); + void setScriptedMotorFrame(QString frame); + virtual void attach(const QString& modelURL, const QString& jointName = QString(), + const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), float scale = 1.0f, + bool allowDuplicates = false, bool useSaved = true); + + void renderLaserPointers(gpu::Batch& batch); + const RecorderPointer getRecorder() const { return _recorder; } + const PlayerPointer getPlayer() const { return _player; } + bool cameraInsideHead() const; // These are made private for MyAvatar so that you will use the "use" methods instead @@ -235,7 +228,7 @@ private: bool _wasPushing; bool _isPushing; bool _isBraking; - + float _boomLength; float _trapDuration; // seconds that avatar has been trapped by collisions @@ -256,30 +249,30 @@ private: bool _shouldRender; bool _billboardValid; float _oculusYawOffset; - + bool _feetTouchFloor; eyeContactTarget _eyeContactTarget; RecorderPointer _recorder; - + glm::vec3 _trackedHeadPosition; - + Setting::Handle _realWorldFieldOfView; - - // private methods + + // private methods void updateOrientation(float deltaTime); glm::vec3 applyKeyboardMotor(float deltaTime, const glm::vec3& velocity, bool isHovering); glm::vec3 applyScriptedMotor(float deltaTime, const glm::vec3& velocity); void updatePosition(float deltaTime); void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void maybeUpdateBillboard(); - + // Avatar Preferences bool _useFullAvatar = false; QUrl _fullAvatarURLFromPreferences; QUrl _headURLFromPreferences; QUrl _skeletonURLFromPreferences; - + QString _headModelName; QString _bodyModelName; QString _fullAvatarModelName; From 81375e47e07e02f9dd6798536e629d51242c53ce Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 27 Jul 2015 09:07:26 -0700 Subject: [PATCH 10/74] remove methods from MyAvatar: setJointRotations setJointData clearJointData clearJointsData --- interface/src/avatar/MyAvatar.cpp | 27 --------------------------- interface/src/avatar/MyAvatar.h | 4 ---- 2 files changed, 31 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 0dceb79402..fe4d4bc3cb 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -900,33 +900,6 @@ glm::vec3 MyAvatar::getDefaultEyePosition() const { const float SCRIPT_PRIORITY = DEFAULT_PRIORITY + 1.0f; const float RECORDER_PRIORITY = SCRIPT_PRIORITY + 1.0f; -void MyAvatar::setJointRotations(QVector jointRotations) { - int numStates = glm::min(_skeletonModel.getJointStateCount(), jointRotations.size()); - for (int i = 0; i < numStates; ++i) { - // HACK: ATM only Recorder calls setJointRotations() so we hardcode its priority here - _skeletonModel.setJointState(i, true, jointRotations[i], RECORDER_PRIORITY); - } -} - -void MyAvatar::setJointData(int index, const glm::quat& rotation) { - if (QThread::currentThread() == thread()) { - // HACK: ATM only JS scripts call setJointData() on MyAvatar so we hardcode the priority - _skeletonModel.setJointState(index, true, rotation, SCRIPT_PRIORITY); - } -} - -void MyAvatar::clearJointData(int index) { - if (QThread::currentThread() == thread()) { - // HACK: ATM only JS scripts call clearJointData() on MyAvatar so we hardcode the priority - _skeletonModel.setJointState(index, false, glm::quat(), 0.0f); - _skeletonModel.clearJointAnimationPriority(index); - } -} - -void MyAvatar::clearJointsData() { - clearJointAnimationPriorities(); -} - void MyAvatar::clearJointAnimationPriorities() { int numStates = _skeletonModel.getJointStateCount(); for (int i = 0; i < numStates; ++i) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 4fd66c0347..f208b68520 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -194,10 +194,6 @@ private: bool getDriveKeys(int key) { return _driveKeys[key] != 0.0f; }; bool isMyAvatar() const { return true; } virtual int parseDataFromBuffer(const QByteArray& buffer); - virtual void setJointRotations(QVector jointRotations); - virtual void setJointData(int index, const glm::quat& rotation); - virtual void clearJointData(int index); - virtual void clearJointsData(); virtual glm::vec3 getSkeletonPosition() const; void updateLocalAABox(); glm::vec3 getScriptedMotorVelocity() const { return _scriptedMotorVelocity; } From 32d051396262b35956d1cf8b545744ac49861266 Mon Sep 17 00:00:00 2001 From: Marcel Verhagen Date: Mon, 27 Jul 2015 19:04:49 +0200 Subject: [PATCH 11/74] The 3Dconnextion files from https://github.com/highfidelity/hifi/pull/5351 For now without a merge conflict. Updated the menu name. Still have to look at the fast zooming and yaw on windows, probably have to add a var to prevent the button changes to be pushed to fast. Not sure why the yaw thing does not always work, could be that the position is also send at the same time and the input mapper does not not process all those synchronical. Probably will have to do something with masking the postion when the rotation is set for yaw. --- cmake/modules/FindconnexionClient.cmake | 38 + interface/CMakeLists.txt | 2 +- .../connexionclient/Inc/I3dMouseParams.h | 79 ++ interface/external/connexionclient/readme.txt | 4 + interface/src/Application.cpp | 6 + interface/src/Menu.cpp | 6 + interface/src/Menu.h | 1 + interface/src/devices/3Dconnexion.cpp | 1013 +++++++++++++++++ interface/src/devices/3Dconnexion.h | 244 ++++ tests/ui/src/main.cpp | 1 + 10 files changed, 1393 insertions(+), 1 deletion(-) create mode 100644 cmake/modules/FindconnexionClient.cmake create mode 100644 interface/external/connexionclient/Inc/I3dMouseParams.h create mode 100644 interface/external/connexionclient/readme.txt create mode 100755 interface/src/devices/3Dconnexion.cpp create mode 100755 interface/src/devices/3Dconnexion.h diff --git a/cmake/modules/FindconnexionClient.cmake b/cmake/modules/FindconnexionClient.cmake new file mode 100644 index 0000000000..1d6d7d4514 --- /dev/null +++ b/cmake/modules/FindconnexionClient.cmake @@ -0,0 +1,38 @@ +# +# FindconnexionClient.cmake +# +# Once done this will define +# +# 3DCONNEXIONCLIENT_INCLUDE_DIRS +# +# Created on 10/06/2015 by Marcel Verhagen +# Copyright 2015 High Fidelity, Inc. +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# + +# setup hints for 3DCONNEXIONCLIENT search +include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") +hifi_library_search_hints("connexionclient") + +if (APPLE) + find_library(3DconnexionClient 3DconnexionClient) + if(EXISTS ${3DconnexionClient}) + set(CONNEXIONCLIENT_FOUND true) + set(CONNEXIONCLIENT_INCLUDE_DIR ${3DconnexionClient}) + set(CONNEXIONCLIENT_LIBRARY ${3DconnexionClient}) + set_target_properties(${TARGET_NAME} PROPERTIES LINK_FLAGS "-weak_framework 3DconnexionClient") + message(STATUS "Found 3Dconnexion") + mark_as_advanced(CONNEXIONCLIENT_INCLUDE_DIR CONNEXIONCLIENT_LIBRARY) + endif() +endif() + +if (WIN32) + find_path(CONNEXIONCLIENT_INCLUDE_DIRS I3dMouseParams.h PATH_SUFFIXES Inc HINTS ${CONNEXIONCLIENT_SEARCH_DIRS}) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(connexionClient DEFAULT_MSG CONNEXIONCLIENT_INCLUDE_DIRS) + + mark_as_advanced(CONNEXIONCLIENT_INCLUDE_DIRS CONNEXIONCLIENT_SEARCH_DIRS) +endif() diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 0c44ac801f..4ee3709f4a 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -2,7 +2,7 @@ set(TARGET_NAME interface) project(${TARGET_NAME}) # set a default root dir for each of our optional externals if it was not passed -set(OPTIONAL_EXTERNALS "Faceshift" "Sixense" "LeapMotion" "RtMidi" "SDL2" "RSSDK") +set(OPTIONAL_EXTERNALS "Faceshift" "Sixense" "LeapMotion" "RtMidi" "SDL2" "RSSDK" "connexionClient") foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE) if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR) diff --git a/interface/external/connexionclient/Inc/I3dMouseParams.h b/interface/external/connexionclient/Inc/I3dMouseParams.h new file mode 100644 index 0000000000..f250efe74f --- /dev/null +++ b/interface/external/connexionclient/Inc/I3dMouseParams.h @@ -0,0 +1,79 @@ +// +// 3DConnexion.cpp +// hifi +// +// Created by MarcelEdward Verhagen on 09-06-15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +#ifndef I3D_MOUSE_PARAMS_H +#define I3D_MOUSE_PARAMS_H + +// Parameters for the 3D mouse based on the SDK from 3Dconnexion + +class I3dMouseSensor { +public: + enum Speed { + SPEED_LOW = 0, + SPEED_MID, + SPEED_HIGH + }; + + virtual bool IsPanZoom() const = 0; + virtual bool IsRotate() const = 0; + virtual Speed GetSpeed() const = 0; + + virtual void SetPanZoom(bool isPanZoom) = 0; + virtual void SetRotate(bool isRotate) = 0; + virtual void SetSpeed(Speed speed) = 0; + +protected: + virtual ~I3dMouseSensor() {} +}; + +class I3dMouseNavigation { +public: + enum Pivot { + PIVOT_MANUAL = 0, + PIVOT_AUTO, + PIVOT_AUTO_OVERRIDE + }; + + enum Navigation { + NAVIGATION_OBJECT_MODE = 0, + NAVIGATION_CAMERA_MODE, + NAVIGATION_FLY_MODE, + NAVIGATION_WALK_MODE, + NAVIGATION_HELICOPTER_MODE + }; + + enum PivotVisibility { + PIVOT_HIDE = 0, + PIVOT_SHOW, + PIVOT_SHOW_MOVING + }; + + virtual Navigation GetNavigationMode() const = 0; + virtual Pivot GetPivotMode() const = 0; + virtual PivotVisibility GetPivotVisibility() const = 0; + virtual bool IsLockHorizon() const = 0; + + virtual void SetLockHorizon(bool bOn) = 0; + virtual void SetNavigationMode(Navigation navigation) = 0; + virtual void SetPivotMode(Pivot pivot) = 0; + virtual void SetPivotVisibility(PivotVisibility visibility) = 0; + +protected: + virtual ~I3dMouseNavigation(){} +}; + +class I3dMouseParam : public I3dMouseSensor, public I3dMouseNavigation { +public: + virtual ~I3dMouseParam() {} +}; + +#endif diff --git a/interface/external/connexionclient/readme.txt b/interface/external/connexionclient/readme.txt new file mode 100644 index 0000000000..dd67a29449 --- /dev/null +++ b/interface/external/connexionclient/readme.txt @@ -0,0 +1,4 @@ +The mac version does not require any files here. 3D connexion should be installed from +http://www.3dconnexion.eu/service/drivers.html + +For windows a header file is required Inc/I3dMouseParams.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fa2a82ecb4..33d88923eb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -115,6 +115,7 @@ #include "devices/MIDIManager.h" #include "devices/OculusManager.h" #include "devices/TV3DManager.h" +#include "devices/3Dconnexion.h" #include "scripting/AccountScriptingInterface.h" #include "scripting/AudioDeviceScriptingInterface.h" @@ -639,6 +640,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(applicationUpdater.data(), &AutoUpdater::newVersionIsAvailable, dialogsManager.data(), &DialogsManager::showUpdateDialog); applicationUpdater->checkForUpdate(); + // the 3Dconnexion device wants to be initiliazed after a window is displayed. + ConnexionClient::init(); + auto& packetReceiver = nodeList->getPacketReceiver(); packetReceiver.registerListener(PacketType::DomainConnectionDenied, this, "handleDomainConnectionDeniedPacket"); } @@ -750,6 +754,7 @@ Application::~Application() { Leapmotion::destroy(); RealSense::destroy(); + ConnexionClient::destroy(); qInstallMessageHandler(NULL); // NOTE: Do this as late as possible so we continue to get our log messages } @@ -1480,6 +1485,7 @@ void Application::focusOutEvent(QFocusEvent* event) { _keyboardMouseDevice.focusOutEvent(event); SixenseManager::getInstance().focusOutEvent(); SDL2Manager::getInstance()->focusOutEvent(); + ConnexionData::getInstance().focusOutEvent(); // synthesize events for keys currently pressed, since we may not get their release events foreach (int key, _keysPressed) { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 91ae6a4d02..c347fdac67 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -29,6 +29,7 @@ #include "devices/Faceshift.h" #include "devices/RealSense.h" #include "devices/SixenseManager.h" +#include "devices/3Dconnexion.h" #include "MainWindow.h" #include "scripting/MenuScriptingInterface.h" #if defined(Q_OS_MAC) || defined(Q_OS_WIN) @@ -447,6 +448,11 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtVectors, 0, false); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderFocusIndicator, 0, false); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ShowWhosLookingAtMe, 0, false); + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, + MenuOption::Connexion, + 0, false, + &ConnexionClient::getInstance(), + SLOT(toggleConnexion(bool))); MenuWrapper* handOptionsMenu = developerMenu->addMenu("Hands"); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, false); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index bf0f89abb5..0edd93c5a6 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -161,6 +161,7 @@ namespace MenuOption { const QString CenterPlayerInView = "Center Player In View"; const QString Chat = "Chat..."; const QString Collisions = "Collisions"; + const QString Connexion = "Activate 3D Connexion Devices""; const QString Console = "Console..."; const QString ControlWithSpeech = "Control With Speech"; const QString CopyAddress = "Copy Address to Clipboard"; diff --git a/interface/src/devices/3Dconnexion.cpp b/interface/src/devices/3Dconnexion.cpp new file mode 100755 index 0000000000..111e2d5991 --- /dev/null +++ b/interface/src/devices/3Dconnexion.cpp @@ -0,0 +1,1013 @@ +// +// 3DConnexion.cpp +// hifi +// +// Created by MarcelEdward Verhagen on 09-06-15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "3Dconnexion.h" +#include "UserActivityLogger.h" + +const float MAX_AXIS = 75.0f; // max forward = 2x speed + +void ConnexionData::focusOutEvent() { + _axisStateMap.clear(); + _buttonPressedMap.clear(); +}; + +ConnexionData& ConnexionData::getInstance() { + static ConnexionData sharedInstance; + return sharedInstance; +} + +ConnexionData::ConnexionData() { +} + +void ConnexionData::handleAxisEvent() { + //qCWarning(interfaceapp) << "pos state x = " << cc_position.x << " y = " << cc_position.y << " z = " << cc_position.z << " Rotation x = " << cc_rotation.x << " y = " << cc_rotation.y << " z = " << cc_rotation.z; + _axisStateMap[makeInput(ROTATION_AXIS_Y_POS).getChannel()] = (cc_rotation.y > 0.0f) ? cc_rotation.y / MAX_AXIS : 0.0f; + _axisStateMap[makeInput(ROTATION_AXIS_Y_NEG).getChannel()] = (cc_rotation.y < 0.0f) ? -cc_rotation.y / MAX_AXIS : 0.0f; + _axisStateMap[makeInput(POSITION_AXIS_X_POS).getChannel()] = (cc_position.x > 0.0f) ? cc_position.x / MAX_AXIS : 0.0f; + _axisStateMap[makeInput(POSITION_AXIS_X_NEG).getChannel()] = (cc_position.x < 0.0f) ? -cc_position.x / MAX_AXIS : 0.0f; + _axisStateMap[makeInput(POSITION_AXIS_Y_POS).getChannel()] = (cc_position.y > 0.0f) ? cc_position.y / MAX_AXIS : 0.0f; + _axisStateMap[makeInput(POSITION_AXIS_Y_NEG).getChannel()] = (cc_position.y < 0.0f) ? -cc_position.y / MAX_AXIS : 0.0f; + _axisStateMap[makeInput(POSITION_AXIS_Z_POS).getChannel()] = (cc_position.z > 0.0f) ? cc_position.z / MAX_AXIS : 0.0f; + _axisStateMap[makeInput(POSITION_AXIS_Z_NEG).getChannel()] = (cc_position.z < 0.0f) ? -cc_position.z / MAX_AXIS : 0.0f; + _axisStateMap[makeInput(ROTATION_AXIS_X_POS).getChannel()] = (cc_rotation.x > 0.0f) ? cc_rotation.x / MAX_AXIS : 0.0f; + _axisStateMap[makeInput(ROTATION_AXIS_X_NEG).getChannel()] = (cc_rotation.x < 0.0f) ? -cc_rotation.x / MAX_AXIS : 0.0f; + _axisStateMap[makeInput(ROTATION_AXIS_Z_POS).getChannel()] = (cc_rotation.z > 0.0f) ? cc_rotation.z / MAX_AXIS : 0.0f; + _axisStateMap[makeInput(ROTATION_AXIS_Z_NEG).getChannel()] = (cc_rotation.z < 0.0f) ? -cc_rotation.z / MAX_AXIS : 0.0f; +} + +void ConnexionData::setButton(int lastButtonState) { + _buttonPressedMap.clear(); + _buttonPressedMap.insert(lastButtonState); +} + +void ConnexionData::registerToUserInputMapper(UserInputMapper& mapper) { + // Grab the current free device ID + _deviceID = mapper.getFreeDeviceID(); + + auto proxy = UserInputMapper::DeviceProxy::Pointer(new UserInputMapper::DeviceProxy("ConnexionClient")); + proxy->getButton = [this](const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); }; + proxy->getAxis = [this](const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); }; + proxy->getAvailabeInputs = [this]() -> QVector { + QVector availableInputs; + + availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_1), "Left button")); + availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_2), "Right button")); + availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_3), "Both buttons")); + + availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_Y_NEG), "Move backward")); + availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_Y_POS), "Move forward")); + availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_X_POS), "Move right")); + availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_X_NEG), "Move Left")); + availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_Z_POS), "Move up")); + availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_Z_NEG), "Move down")); + availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_Y_NEG), "Rotate backward")); + availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_Y_POS), "Rotate forward")); + availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_X_POS), "Rotate right")); + availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_X_NEG), "Rotate left")); + availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_Z_POS), "Rotate up")); + availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_Z_NEG), "Rotate down")); + + return availableInputs; + }; + proxy->resetDeviceBindings = [this, &mapper]() -> bool { + mapper.removeAllInputChannelsForDevice(_deviceID); + this->assignDefaultInputMapping(mapper); + return true; + }; + mapper.registerDevice(_deviceID, proxy); +} + +void ConnexionData::assignDefaultInputMapping(UserInputMapper& mapper) { + const float JOYSTICK_MOVE_SPEED = 1.0f; + //const float DPAD_MOVE_SPEED = 0.5f; + const float JOYSTICK_YAW_SPEED = 0.5f; + const float JOYSTICK_PITCH_SPEED = 0.25f; + const float BOOM_SPEED = 0.1f; + + // Y axes are flipped (up is negative) + // postion: Movement, strafing + mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(POSITION_AXIS_Y_NEG), JOYSTICK_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(POSITION_AXIS_Y_POS), JOYSTICK_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(POSITION_AXIS_X_POS), JOYSTICK_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(POSITION_AXIS_X_NEG), JOYSTICK_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(POSITION_AXIS_Z_NEG), JOYSTICK_MOVE_SPEED); + mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(POSITION_AXIS_Z_POS), JOYSTICK_MOVE_SPEED); + + // Rotation: Camera orientation with button 1 + mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(ROTATION_AXIS_Z_POS), JOYSTICK_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(ROTATION_AXIS_Z_NEG), JOYSTICK_YAW_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(ROTATION_AXIS_Y_NEG), JOYSTICK_PITCH_SPEED); + mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(ROTATION_AXIS_Y_POS), JOYSTICK_PITCH_SPEED); + + // Button controls + // Zoom + mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(BUTTON_1), BOOM_SPEED); + mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(BUTTON_2), BOOM_SPEED); + + // Zoom + // mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(ROTATION_AXIS_Z_NEG), BOOM_SPEED); + // mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(ROTATION_AXIS_Z_POS), BOOM_SPEED); + +} + +float ConnexionData::getButton(int channel) const { + if (!_buttonPressedMap.empty()) { + if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) { + return 1.0f; + } else { + return 0.0f; + } + } + return 0.0f; +} + +float ConnexionData::getAxis(int channel) const { + auto axis = _axisStateMap.find(channel); + if (axis != _axisStateMap.end()) { + return (*axis).second; + } else { + return 0.0f; + } +} + +UserInputMapper::Input ConnexionData::makeInput(ConnexionData::ButtonChannel button) { + return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON); +} + +UserInputMapper::Input ConnexionData::makeInput(ConnexionData::PositionChannel axis) { + return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS); +} + +void ConnexionData::update() { + // the update is done in the ConnexionClient class. + // for windows in the nativeEventFilter the inputmapper is connected or registed or removed when an 3Dconnnexion device is attached or deteched + // for osx the api will call DeviceAddedHandler or DeviceRemoveHandler when a 3Dconnexion device is attached or detached +} + +ConnexionClient& ConnexionClient::getInstance() { + static ConnexionClient sharedInstance; + return sharedInstance; +} + +#ifdef HAVE_CONNEXIONCLIENT + +#ifdef _WIN32 + +static ConnexionClient* gMouseInput = 0; + +void ConnexionClient::toggleConnexion(bool shouldEnable) +{ + ConnexionData& connexiondata = ConnexionData::getInstance(); + if (shouldEnable && connexiondata.getDeviceID() == 0) { + ConnexionClient::init(); + } + if (!shouldEnable && connexiondata.getDeviceID() != 0) { + ConnexionClient::destroy(); + } + +} + +void ConnexionClient::init() { + if (Menu::getInstance()->isOptionChecked(MenuOption::Connexion)) { + ConnexionClient& cclient = ConnexionClient::getInstance(); + cclient.fLast3dmouseInputTime = 0; + + cclient.InitializeRawInput(GetActiveWindow()); + + gMouseInput = &cclient; + + QAbstractEventDispatcher::instance()->installNativeEventFilter(&cclient); + } +} + +void ConnexionClient::destroy() { + ConnexionClient& cclient = ConnexionClient::getInstance(); + QAbstractEventDispatcher::instance()->removeNativeEventFilter(&cclient); + ConnexionData& connexiondata = ConnexionData::getInstance(); + int deviceid = connexiondata.getDeviceID(); + connexiondata.setDeviceID(0); + Application::getUserInputMapper()->removeDevice(deviceid); +} + +#define LOGITECH_VENDOR_ID 0x46d + +#ifndef RIDEV_DEVNOTIFY +#define RIDEV_DEVNOTIFY 0x00002000 +#endif + +const int TRACE_RIDI_DEVICENAME = 0; +const int TRACE_RIDI_DEVICEINFO = 0; + +#ifdef _WIN64 +typedef unsigned __int64 QWORD; +#endif + +// object angular velocity per mouse tick 0.008 milliradians per second per count +static const double k3dmouseAngularVelocity = 8.0e-6; // radians per second per count + +static const int kTimeToLive = 5; + +enum ConnexionPid { + CONNEXIONPID_SPACEPILOT = 0xc625, + CONNEXIONPID_SPACENAVIGATOR = 0xc626, + CONNEXIONPID_SPACEEXPLORER = 0xc627, + CONNEXIONPID_SPACENAVIGATORFORNOTEBOOKS = 0xc628, + CONNEXIONPID_SPACEPILOTPRO = 0xc629 +}; + +// e3dmouse_virtual_key +enum V3dk { + V3DK_INVALID = 0 + , V3DK_MENU = 1, V3DK_FIT + , V3DK_TOP, V3DK_LEFT, V3DK_RIGHT, V3DK_FRONT, V3DK_BOTTOM, V3DK_BACK + , V3DK_CW, V3DK_CCW + , V3DK_ISO1, V3DK_ISO2 + , V3DK_1, V3DK_2, V3DK_3, V3DK_4, V3DK_5, V3DK_6, V3DK_7, V3DK_8, V3DK_9, V3DK_10 + , V3DK_ESC, V3DK_ALT, V3DK_SHIFT, V3DK_CTRL + , V3DK_ROTATE, V3DK_PANZOOM, V3DK_DOMINANT + , V3DK_PLUS, V3DK_MINUS +}; + +struct tag_VirtualKeys { + ConnexionPid pid; + size_t nKeys; + V3dk *vkeys; +}; + +// e3dmouse_virtual_key +static const V3dk SpaceExplorerKeys[] = { + V3DK_INVALID // there is no button 0 + , V3DK_1, V3DK_2 + , V3DK_TOP, V3DK_LEFT, V3DK_RIGHT, V3DK_FRONT + , V3DK_ESC, V3DK_ALT, V3DK_SHIFT, V3DK_CTRL + , V3DK_FIT, V3DK_MENU + , V3DK_PLUS, V3DK_MINUS + , V3DK_ROTATE +}; + +//e3dmouse_virtual_key +static const V3dk SpacePilotKeys[] = { + V3DK_INVALID + , V3DK_1, V3DK_2, V3DK_3, V3DK_4, V3DK_5, V3DK_6 + , V3DK_TOP, V3DK_LEFT, V3DK_RIGHT, V3DK_FRONT + , V3DK_ESC, V3DK_ALT, V3DK_SHIFT, V3DK_CTRL + , V3DK_FIT, V3DK_MENU + , V3DK_PLUS, V3DK_MINUS + , V3DK_DOMINANT, V3DK_ROTATE +}; + +static const struct tag_VirtualKeys _3dmouseVirtualKeys[] = { + CONNEXIONPID_SPACEPILOT + , sizeof(SpacePilotKeys) / sizeof(SpacePilotKeys[0]) + , const_cast(SpacePilotKeys), + CONNEXIONPID_SPACEEXPLORER + , sizeof(SpaceExplorerKeys) / sizeof(SpaceExplorerKeys[0]) + , const_cast(SpaceExplorerKeys) +}; + +// Converts a hid device keycode (button identifier) of a pre-2009 3Dconnexion USB device to the standard 3d mouse virtual key definition. +// pid USB Product ID (PID) of 3D mouse device +// hidKeyCode Hid keycode as retrieved from a Raw Input packet +// return The standard 3d mouse virtual key (button identifier) or zero if an error occurs. + +// Converts a hid device keycode (button identifier) of a pre-2009 3Dconnexion USB device +// to the standard 3d mouse virtual key definition. +unsigned short HidToVirtualKey(unsigned long pid, unsigned short hidKeyCode) { + unsigned short virtualkey = hidKeyCode; + for (size_t i = 0; iremoveDevice(deviceid); + } + + if (!ConnexionClient::Is3dmouseAttached()) { + return false; + } + + MSG* message = (MSG*)(msg); + + if (message->message == WM_INPUT) { + HRAWINPUT hRawInput = reinterpret_cast(message->lParam); + gMouseInput->OnRawInput(RIM_INPUT, hRawInput); + if (result != 0) { + result = 0; + } + return true; + } + return false; +} + +ConnexionClient::ConnexionClient() { + +} + +ConnexionClient::~ConnexionClient() { + ConnexionClient& cclient = ConnexionClient::getInstance(); + QAbstractEventDispatcher::instance()->removeNativeEventFilter(&cclient); +} + +// Access the mouse parameters structure +I3dMouseParam& ConnexionClient::MouseParams() { + return f3dMouseParams; +} + +// Access the mouse parameters structure +const I3dMouseParam& ConnexionClient::MouseParams() const { + return f3dMouseParams; +} + +//Called with the processed motion data when a 3D mouse event is received +void ConnexionClient::Move3d(HANDLE device, std::vector& motionData) { + Q_UNUSED(device); + ConnexionData& connexiondata = ConnexionData::getInstance(); + connexiondata.cc_position = { motionData[0] * 1000, motionData[1] * 1000, motionData[2] * 1000 }; + connexiondata.cc_rotation = { motionData[3] * 1500, motionData[4] * 1500, motionData[5] * 1500 }; + connexiondata.handleAxisEvent(); +} + +//Called when a 3D mouse key is pressed +void ConnexionClient::On3dmouseKeyDown(HANDLE device, int virtualKeyCode) { + Q_UNUSED(device); + ConnexionData& connexiondata = ConnexionData::getInstance(); + connexiondata.setButton(virtualKeyCode); +} + +//Called when a 3D mouse key is released +void ConnexionClient::On3dmouseKeyUp(HANDLE device, int virtualKeyCode) { + Q_UNUSED(device); + ConnexionData& connexiondata = ConnexionData::getInstance(); + connexiondata.setButton(0); +} + +//Get an initialized array of PRAWINPUTDEVICE for the 3D devices +//pNumDevices returns the number of devices to register. Currently this is always 1. +static PRAWINPUTDEVICE GetDevicesToRegister(unsigned int* pNumDevices) { + // Array of raw input devices to register + static RAWINPUTDEVICE sRawInputDevices[] = { + { 0x01, 0x08, 0x00, 0x00 } // Usage Page = 0x01 Generic Desktop Page, Usage Id= 0x08 Multi-axis Controller + }; + + if (pNumDevices) { + *pNumDevices = sizeof(sRawInputDevices) / sizeof(sRawInputDevices[0]); + } + + return sRawInputDevices; +} + +//Detect the 3D mouse +bool ConnexionClient::Is3dmouseAttached() { + unsigned int numDevicesOfInterest = 0; + PRAWINPUTDEVICE devicesToRegister = GetDevicesToRegister(&numDevicesOfInterest); + + unsigned int nDevices = 0; + + if (::GetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)) != 0) { + return false; + } + + if (nDevices == 0) { + return false; + } + + std::vector rawInputDeviceList(nDevices); + if (::GetRawInputDeviceList(&rawInputDeviceList[0], &nDevices, sizeof(RAWINPUTDEVICELIST)) == static_cast(-1)) { + return false; + } + + for (unsigned int i = 0; i < nDevices; ++i) { + RID_DEVICE_INFO rdi = { sizeof(rdi) }; + unsigned int cbSize = sizeof(rdi); + + if (GetRawInputDeviceInfo(rawInputDeviceList[i].hDevice, RIDI_DEVICEINFO, &rdi, &cbSize) > 0) { + //skip non HID and non logitec (3DConnexion) devices + if (rdi.dwType != RIM_TYPEHID || rdi.hid.dwVendorId != LOGITECH_VENDOR_ID) { + continue; + } + + //check if devices matches Multi-axis Controller + for (unsigned int j = 0; j < numDevicesOfInterest; ++j) { + if (devicesToRegister[j].usUsage == rdi.hid.usUsage + && devicesToRegister[j].usUsagePage == rdi.hid.usUsagePage) { + return true; + } + } + } + } + return false; +} + +// Initialize the window to recieve raw-input messages +// This needs to be called initially so that Windows will send the messages from the 3D mouse to the window. +bool ConnexionClient::InitializeRawInput(HWND hwndTarget) { + fWindow = hwndTarget; + + // Simply fail if there is no window + if (!hwndTarget) { + return false; + } + + unsigned int numDevices = 0; + PRAWINPUTDEVICE devicesToRegister = GetDevicesToRegister(&numDevices); + + if (numDevices == 0) { + return false; + } + + // Get OS version. + OSVERSIONINFO osvi = { sizeof(OSVERSIONINFO), 0 }; + ::GetVersionEx(&osvi); + + unsigned int cbSize = sizeof(devicesToRegister[0]); + for (size_t i = 0; i < numDevices; i++) { + // Set the target window to use + //devicesToRegister[i].hwndTarget = hwndTarget; + + // If Vista or newer, enable receiving the WM_INPUT_DEVICE_CHANGE message. + if (osvi.dwMajorVersion >= 6) { + devicesToRegister[i].dwFlags |= RIDEV_DEVNOTIFY; + } + } + return (::RegisterRawInputDevices(devicesToRegister, numDevices, cbSize) != FALSE); +} + +//Get the raw input data from Windows +UINT ConnexionClient::GetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader) { + //Includes workaround for incorrect alignment of the RAWINPUT structure on x64 os + //when running as Wow64 (copied directly from 3DConnexion code) +#ifdef _WIN64 + return ::GetRawInputBuffer(pData, pcbSize, cbSizeHeader); +#else + BOOL bIsWow64 = FALSE; + ::IsWow64Process(GetCurrentProcess(), &bIsWow64); + if (!bIsWow64 || pData == NULL) { + return ::GetRawInputBuffer(pData, pcbSize, cbSizeHeader); + } else { + HWND hwndTarget = fWindow; + + size_t cbDataSize = 0; + UINT nCount = 0; + PRAWINPUT pri = pData; + + MSG msg; + while (PeekMessage(&msg, hwndTarget, WM_INPUT, WM_INPUT, PM_NOREMOVE)) { + HRAWINPUT hRawInput = reinterpret_cast(msg.lParam); + size_t cbSize = *pcbSize - cbDataSize; + if (::GetRawInputData(hRawInput, RID_INPUT, pri, &cbSize, cbSizeHeader) == static_cast(-1)) { + if (nCount == 0) { + return static_cast(-1); + } else { + break; + } + } + ++nCount; + + // Remove the message for the data just read + PeekMessage(&msg, hwndTarget, WM_INPUT, WM_INPUT, PM_REMOVE); + + pri = NEXTRAWINPUTBLOCK(pri); + cbDataSize = reinterpret_cast(pri)-reinterpret_cast(pData); + if (cbDataSize >= *pcbSize) { + cbDataSize = *pcbSize; + break; + } + } + return nCount; + } +#endif +} + +// Process the raw input device data +// On3dmouseInput() does all the preprocessing of the rawinput device data before +// finally calling the Move3d method. +void ConnexionClient::On3dmouseInput() { + // Don't do any data processing in background + bool bIsForeground = (::GetActiveWindow() != NULL); + if (!bIsForeground) { + // set all cached data to zero so that a zero event is seen and the cached data deleted + for (std::map::iterator it = fDevice2Data.begin(); it != fDevice2Data.end(); it++) { + it->second.fAxes.assign(6, .0); + it->second.fIsDirty = true; + } + } + + DWORD dwNow = ::GetTickCount(); // Current time; + DWORD dwElapsedTime; // Elapsed time since we were last here + + if (0 == fLast3dmouseInputTime) { + dwElapsedTime = 10; // System timer resolution + } else { + dwElapsedTime = dwNow - fLast3dmouseInputTime; + if (fLast3dmouseInputTime > dwNow) { + dwElapsedTime = ~dwElapsedTime + 1; + } + if (dwElapsedTime<1) { + dwElapsedTime = 1; + } else if (dwElapsedTime > 500) { + // Check for wild numbers because the device was removed while sending data + dwElapsedTime = 10; + } + } + + //qDebug("On3DmouseInput() period is %dms\n", dwElapsedTime); + + float mouseData2Rotation = k3dmouseAngularVelocity; + // v = w * r, we don't know r yet so lets assume r=1.) + float mouseData2PanZoom = k3dmouseAngularVelocity; + + // Grab the I3dmouseParam interface + I3dMouseParam& i3dmouseParam = f3dMouseParams; + // Take a look at the users preferred speed setting and adjust the sensitivity accordingly + I3dMouseSensor::Speed speedSetting = i3dmouseParam.GetSpeed(); + // See "Programming for the 3D Mouse", Section 5.1.3 + float speed = (speedSetting == I3dMouseSensor::SPEED_LOW ? 0.25f : speedSetting == I3dMouseSensor::SPEED_HIGH ? 4.f : 1.f); + + // Multiplying by the following will convert the 3d mouse data to real world units + mouseData2PanZoom *= speed; + mouseData2Rotation *= speed; + + std::map::iterator iterator = fDevice2Data.begin(); + while (iterator != fDevice2Data.end()) { + + // If we have not received data for a while send a zero event + if ((--(iterator->second.fTimeToLive)) == 0) { + iterator->second.fAxes.assign(6, .0); + } else if ( !iterator->second.fIsDirty) { //!t_bPoll3dmouse && + // If we are not polling then only handle the data that was actually received + ++iterator; + continue; + } + iterator->second.fIsDirty = false; + + // get a copy of the device + HANDLE hdevice = iterator->first; + + // get a copy of the motion vectors and apply the user filters + std::vector motionData = iterator->second.fAxes; + + // apply the user filters + + // Pan Zoom filter + // See "Programming for the 3D Mouse", Section 5.1.2 + if (!i3dmouseParam.IsPanZoom()) { + // Pan zoom is switched off so set the translation vector values to zero + motionData[0] = motionData[1] = motionData[2] = 0.; + } + + // Rotate filter + // See "Programming for the 3D Mouse", Section 5.1.1 + if (!i3dmouseParam.IsRotate()) { + // Rotate is switched off so set the rotation vector values to zero + motionData[3] = motionData[4] = motionData[5] = 0.; + } + + // convert the translation vector into physical data + for (int axis = 0; axis < 3; axis++) { + motionData[axis] *= mouseData2PanZoom; + } + + // convert the directed Rotate vector into physical data + // See "Programming for the 3D Mouse", Section 7.2.2 + for (int axis = 3; axis < 6; axis++) { + motionData[axis] *= mouseData2Rotation; + } + + // Now that the data has had the filters and sensitivty settings applied + // calculate the displacements since the last view update + for (int axis = 0; axis < 6; axis++) { + motionData[axis] *= dwElapsedTime; + } + + // Now a bit of book keeping before passing on the data + if (iterator->second.IsZero()) { + iterator = fDevice2Data.erase(iterator); + } else { + ++iterator; + } + + // Work out which will be the next device + HANDLE hNextDevice = 0; + if (iterator != fDevice2Data.end()) { + hNextDevice = iterator->first; + } + + // Pass the 3dmouse input to the view controller + Move3d(hdevice, motionData); + + // Because we don't know what happened in the previous call, the cache might have + // changed so reload the iterator + iterator = fDevice2Data.find(hNextDevice); + } + + if (!fDevice2Data.empty()) { + fLast3dmouseInputTime = dwNow; + } else { + fLast3dmouseInputTime = 0; + } +} + +//Called when new raw input data is available +void ConnexionClient::OnRawInput(UINT nInputCode, HRAWINPUT hRawInput) { + const size_t cbSizeOfBuffer = 1024; + BYTE pBuffer[cbSizeOfBuffer]; + + PRAWINPUT pRawInput = reinterpret_cast(pBuffer); + UINT cbSize = cbSizeOfBuffer; + + if (::GetRawInputData(hRawInput, RID_INPUT, pRawInput, &cbSize, sizeof(RAWINPUTHEADER)) == static_cast(-1)) { + return; + } + + bool b3dmouseInput = TranslateRawInputData(nInputCode, pRawInput); + ::DefRawInputProc(&pRawInput, 1, sizeof(RAWINPUTHEADER)); + + // Check for any buffered messages + cbSize = cbSizeOfBuffer; + UINT nCount = this->GetRawInputBuffer(pRawInput, &cbSize, sizeof(RAWINPUTHEADER)); + if (nCount == (UINT)-1) { + qDebug("GetRawInputBuffer returned error %d\n", GetLastError()); + } + + while (nCount>0 && nCount != static_cast(-1)) { + PRAWINPUT pri = pRawInput; + UINT nInput; + for (nInput = 0; nInputGetRawInputBuffer(pRawInput, &cbSize, sizeof(RAWINPUTHEADER)); + } + + // If we have mouse input data for the app then tell tha app about it + if (b3dmouseInput) { + On3dmouseInput(); + } +} + +bool ConnexionClient::TranslateRawInputData(UINT nInputCode, PRAWINPUT pRawInput) { + bool bIsForeground = (nInputCode == RIM_INPUT); + + //qDebug("Rawinput.header.dwType=0x%x\n", pRawInput->header.dwType); + + // We are not interested in keyboard or mouse data received via raw input + if (pRawInput->header.dwType != RIM_TYPEHID) { + return false; + } + + if (TRACE_RIDI_DEVICENAME == 1) { + UINT dwSize = 0; + if (::GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICENAME, NULL, &dwSize) == 0) { + std::vector szDeviceName(dwSize + 1); + if (::GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICENAME, &szDeviceName[0], &dwSize) >0) { + qDebug("Device Name = %s\nDevice handle = 0x%x\n", &szDeviceName[0], pRawInput->header.hDevice); + } + } + } + + RID_DEVICE_INFO sRidDeviceInfo; + sRidDeviceInfo.cbSize = sizeof(RID_DEVICE_INFO); + UINT cbSize = sizeof(RID_DEVICE_INFO); + + if (::GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICEINFO, &sRidDeviceInfo, &cbSize) == cbSize) { + if (TRACE_RIDI_DEVICEINFO == 1) { + switch (sRidDeviceInfo.dwType) { + case RIM_TYPEMOUSE: + qDebug("\tsRidDeviceInfo.dwType=RIM_TYPEMOUSE\n"); + break; + case RIM_TYPEKEYBOARD: + qDebug("\tsRidDeviceInfo.dwType=RIM_TYPEKEYBOARD\n"); + break; + case RIM_TYPEHID: + qDebug("\tsRidDeviceInfo.dwType=RIM_TYPEHID\n"); + qDebug("\tVendor=0x%x\n\tProduct=0x%x\n\tUsagePage=0x%x\n\tUsage=0x%x\n", + sRidDeviceInfo.hid.dwVendorId, + sRidDeviceInfo.hid.dwProductId, + sRidDeviceInfo.hid.usUsagePage, + sRidDeviceInfo.hid.usUsage); + break; + } + } + + if (sRidDeviceInfo.hid.dwVendorId == LOGITECH_VENDOR_ID) { + if (pRawInput->data.hid.bRawData[0] == 0x01) { // Translation vector + TInputData& deviceData = fDevice2Data[pRawInput->header.hDevice]; + deviceData.fTimeToLive = kTimeToLive; + if (bIsForeground) { + short* pnRawData = reinterpret_cast(&pRawInput->data.hid.bRawData[1]); + // Cache the pan zoom data + deviceData.fAxes[0] = static_cast(pnRawData[0]); + deviceData.fAxes[1] = static_cast(pnRawData[1]); + deviceData.fAxes[2] = static_cast(pnRawData[2]); + + //qDebug("Pan/Zoom RI Data =\t0x%x,\t0x%x,\t0x%x\n", pnRawData[0], pnRawData[1], pnRawData[2]); + + if (pRawInput->data.hid.dwSizeHid >= 13) { // Highspeed package + // Cache the rotation data + deviceData.fAxes[3] = static_cast(pnRawData[3]); + deviceData.fAxes[4] = static_cast(pnRawData[4]); + deviceData.fAxes[5] = static_cast(pnRawData[5]); + deviceData.fIsDirty = true; + + //qDebug("Rotation RI Data =\t0x%x,\t0x%x,\t0x%x\n", pnRawData[3], pnRawData[4], pnRawData[5]); + return true; + } + } else { // Zero out the data if the app is not in forground + deviceData.fAxes.assign(6, 0.f); + } + } else if (pRawInput->data.hid.bRawData[0] == 0x02) { // Rotation vector + // If we are not in foreground do nothing + // The rotation vector was zeroed out with the translation vector in the previous message + if (bIsForeground) { + TInputData& deviceData = fDevice2Data[pRawInput->header.hDevice]; + deviceData.fTimeToLive = kTimeToLive; + + short* pnRawData = reinterpret_cast(&pRawInput->data.hid.bRawData[1]); + // Cache the rotation data + deviceData.fAxes[3] = static_cast(pnRawData[0]); + deviceData.fAxes[4] = static_cast(pnRawData[1]); + deviceData.fAxes[5] = static_cast(pnRawData[2]); + deviceData.fIsDirty = true; + + //qDebug("Rotation RI Data =\t0x%x,\t0x%x,\t0x%x\n", pnRawData[0], pnRawData[1], pnRawData[2]); + + return true; + } + } else if (pRawInput->data.hid.bRawData[0] == 0x03) { // Keystate change + // this is a package that contains 3d mouse keystate information + // bit0=key1, bit=key2 etc. + + unsigned long dwKeystate = *reinterpret_cast(&pRawInput->data.hid.bRawData[1]); + + //qDebug("ButtonData =0x%x\n", dwKeystate); + + // Log the keystate changes + unsigned long dwOldKeystate = fDevice2Keystate[pRawInput->header.hDevice]; + if (dwKeystate != 0) { + fDevice2Keystate[pRawInput->header.hDevice] = dwKeystate; + } else { + fDevice2Keystate.erase(pRawInput->header.hDevice); + } + + // Only call the keystate change handlers if the app is in foreground + if (bIsForeground) { + unsigned long dwChange = dwKeystate ^ dwOldKeystate; + + for (int nKeycode = 1; nKeycode<33; nKeycode++) { + if (dwChange & 0x01) { + int nVirtualKeyCode = HidToVirtualKey(sRidDeviceInfo.hid.dwProductId, nKeycode); + if (nVirtualKeyCode) { + if (dwKeystate & 0x01) { + On3dmouseKeyDown(pRawInput->header.hDevice, nVirtualKeyCode); + } else { + On3dmouseKeyUp(pRawInput->header.hDevice, nVirtualKeyCode); + } + } + } + dwChange >>= 1; + dwKeystate >>= 1; + } + } + } + } + } + return false; +} + +MouseParameters::MouseParameters() : fNavigation(NAVIGATION_OBJECT_MODE) + , fPivot(PIVOT_AUTO) + , fPivotVisibility(PIVOT_SHOW) + , fIsLockHorizon(true) + , fIsPanZoom(true) + , fIsRotate(true) + , fSpeed(SPEED_LOW) { +} + +MouseParameters::~MouseParameters() { +} + +bool MouseParameters::IsPanZoom() const { + return fIsPanZoom; +} + +bool MouseParameters::IsRotate() const { + return fIsRotate; +} + +MouseParameters::Speed MouseParameters::GetSpeed() const { + return fSpeed; +} + +void MouseParameters::SetPanZoom(bool isPanZoom) { + fIsPanZoom=isPanZoom; +} + +void MouseParameters::SetRotate(bool isRotate) { + fIsRotate=isRotate; +} + +void MouseParameters::SetSpeed(Speed speed) { + fSpeed=speed; +} + +MouseParameters::Navigation MouseParameters::GetNavigationMode() const { + return fNavigation; +} + +MouseParameters::Pivot MouseParameters::GetPivotMode() const { + return fPivot; +} + +MouseParameters::PivotVisibility MouseParameters::GetPivotVisibility() const { + return fPivotVisibility; +} + +bool MouseParameters::IsLockHorizon() const { + return fIsLockHorizon; +} + +void MouseParameters::SetLockHorizon(bool bOn) { + fIsLockHorizon=bOn; +} + +void MouseParameters::SetNavigationMode(Navigation navigation) { + fNavigation=navigation; +} + +void MouseParameters::SetPivotMode(Pivot pivot) { + if (fPivot!=PIVOT_MANUAL || pivot!=PIVOT_AUTO_OVERRIDE) { + fPivot = pivot; + } +} + +void MouseParameters::SetPivotVisibility(PivotVisibility visibility) { + fPivotVisibility = visibility; +} + +#else + +#define WITH_SEPARATE_THREAD false // set to true or false + +// Make the linker happy for the framework check (see link below for more info) +// http://developer.apple.com/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html + +extern int16_t SetConnexionHandlers(ConnexionMessageHandlerProc messageHandler, ConnexionAddedHandlerProc addedHandler, ConnexionRemovedHandlerProc removedHandler, bool useSeparateThread) __attribute__((weak_import)); + +int fConnexionClientID; + +static ConnexionDeviceState lastState; + +static void DeviceAddedHandler(unsigned int connection); +static void DeviceRemovedHandler(unsigned int connection); +static void MessageHandler(unsigned int connection, unsigned int messageType, void *messageArgument); + +void ConnexionClient::toggleConnexion(bool shouldEnable) +{ + if (shouldEnable && !ConnexionClient::Is3dmouseAttached()) { + ConnexionClient::init(); + } + if (!shouldEnable && ConnexionClient::Is3dmouseAttached()) { + ConnexionClient::destroy(); + } + +} + +void ConnexionClient::init() { + // Make sure the framework is installed + if (SetConnexionHandlers != NULL && Menu::getInstance()->isOptionChecked(MenuOption::Connexion)) { + // Install message handler and register our client + InstallConnexionHandlers(MessageHandler, DeviceAddedHandler, DeviceRemovedHandler); + // Either use this to take over in our application only... does not work + // fConnexionClientID = RegisterConnexionClient('MCTt', "\pConnexion Client Test", kConnexionClientModeTakeOver, kConnexionMaskAll); + + // ...or use this to take over system-wide + fConnexionClientID = RegisterConnexionClient(kConnexionClientWildcard, NULL, kConnexionClientModeTakeOver, kConnexionMaskAll); + ConnexionData& connexiondata = ConnexionData::getInstance(); + memcpy(&connexiondata.clientId, &fConnexionClientID, (long)sizeof(int)); + + // A separate API call is required to capture buttons beyond the first 8 + SetConnexionClientButtonMask(fConnexionClientID, kConnexionMaskAllButtons); + + // use default switches + ConnexionClientControl(fConnexionClientID, kConnexionCtlSetSwitches, kConnexionSwitchesDisabled, NULL); + + if (ConnexionClient::Is3dmouseAttached() && connexiondata.getDeviceID() == 0) { + connexiondata.registerToUserInputMapper(*Application::getUserInputMapper()); + connexiondata.assignDefaultInputMapping(*Application::getUserInputMapper()); + UserActivityLogger::getInstance().connectedDevice("controller", "3Dconnexion"); + } + //let one axis be dominant + //ConnexionClientControl(fConnexionClientID, kConnexionCtlSetSwitches, kConnexionSwitchDominant | kConnexionSwitchEnableAll, NULL); + } +} + +void ConnexionClient::destroy() { + // Make sure the framework is installed + if (&InstallConnexionHandlers != NULL) { + // Unregister our client and clean up all handlers + if (fConnexionClientID) { + UnregisterConnexionClient(fConnexionClientID); + } + CleanupConnexionHandlers(); + fConnexionClientID = 0; + ConnexionData& connexiondata = ConnexionData::getInstance(); + if (connexiondata.getDeviceID()!=0) { + Application::getUserInputMapper()->removeDevice(connexiondata.getDeviceID()); + connexiondata.setDeviceID(0); + } + } +} + +void DeviceAddedHandler(unsigned int connection) { + ConnexionData& connexiondata = ConnexionData::getInstance(); + if (connexiondata.getDeviceID() == 0) { + qCWarning(interfaceapp) << "3Dconnexion device added "; + connexiondata.registerToUserInputMapper(*Application::getUserInputMapper()); + connexiondata.assignDefaultInputMapping(*Application::getUserInputMapper()); + UserActivityLogger::getInstance().connectedDevice("controller", "3Dconnexion"); + } +} + +void DeviceRemovedHandler(unsigned int connection) { + ConnexionData& connexiondata = ConnexionData::getInstance(); + if (connexiondata.getDeviceID() != 0) { + qCWarning(interfaceapp) << "3Dconnexion device removed"; + Application::getUserInputMapper()->removeDevice(connexiondata.getDeviceID()); + connexiondata.setDeviceID(0); + } +} + +bool ConnexionClient::Is3dmouseAttached() { + int result; + if (fConnexionClientID) { + if (ConnexionControl(kConnexionCtlGetDeviceID, 0, &result)) { + return false; + } + return true; + } + return false; +} + +void MessageHandler(unsigned int connection, unsigned int messageType, void *messageArgument) { + ConnexionDeviceState *state; + + switch (messageType) { + case kConnexionMsgDeviceState: + state = (ConnexionDeviceState*)messageArgument; + if (state->client == fConnexionClientID) { + ConnexionData& connexiondata = ConnexionData::getInstance(); + connexiondata.cc_position = { state->axis[0], state->axis[1], state->axis[2] }; + connexiondata.cc_rotation = { state->axis[3], state->axis[4], state->axis[5] }; + + connexiondata.handleAxisEvent(); + if (state->buttons != lastState.buttons) { + connexiondata.setButton(state->buttons); + } + memmove(&lastState, state, (long)sizeof(ConnexionDeviceState)); + } + break; + case kConnexionMsgPrefsChanged: + // the prefs have changed, do something + break; + default: + // other messageTypes can happen and should be ignored + break; + } + +} + +#endif // __APPLE__ + +#endif // HAVE_CONNEXIONCLIENT diff --git a/interface/src/devices/3Dconnexion.h b/interface/src/devices/3Dconnexion.h new file mode 100755 index 0000000000..28b4924e44 --- /dev/null +++ b/interface/src/devices/3Dconnexion.h @@ -0,0 +1,244 @@ +// 3DConnexion.h +// hifi +// +// Created by Marcel Verhagen on 09-06-15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ConnexionClient_h +#define hifi_ConnexionClient_h + +#include +#include +#include "InterfaceLogging.h" +#include "Application.h" + +#include "ui/UserInputMapper.h" + +#ifndef HAVE_CONNEXIONCLIENT +class ConnexionClient : public QObject { + Q_OBJECT +public: + static ConnexionClient& getInstance(); + static void init() {}; + static void destroy() {}; + static bool Is3dmouseAttached() { return false; }; +public slots: + void toggleConnexion(bool shouldEnable) {}; +}; +#endif // NOT_HAVE_CONNEXIONCLIENT + +#ifdef HAVE_CONNEXIONCLIENT +// the windows connexion rawinput +#ifdef _WIN32 + +#include "I3dMouseParams.h" +#include +#include +#include +#include + +// windows rawinput parameters +class MouseParameters : public I3dMouseParam { +public: + MouseParameters(); + ~MouseParameters(); + + // I3dmouseSensor interface + bool IsPanZoom() const; + bool IsRotate() const; + Speed GetSpeed() const; + + void SetPanZoom(bool isPanZoom); + void SetRotate(bool isRotate); + void SetSpeed(Speed speed); + + // I3dmouseNavigation interface + Navigation GetNavigationMode() const; + Pivot GetPivotMode() const; + PivotVisibility GetPivotVisibility() const; + bool IsLockHorizon() const; + + void SetLockHorizon(bool bOn); + void SetNavigationMode(Navigation navigation); + void SetPivotMode(Pivot pivot); + void SetPivotVisibility(PivotVisibility visibility); + + static bool Is3dmouseAttached(); + +private: + MouseParameters(const MouseParameters&); + const MouseParameters& operator = (const MouseParameters&); + + Navigation fNavigation; + Pivot fPivot; + PivotVisibility fPivotVisibility; + bool fIsLockHorizon; + + bool fIsPanZoom; + bool fIsRotate; + Speed fSpeed; +}; + +class ConnexionClient : public QObject, public QAbstractNativeEventFilter { + Q_OBJECT +public: + ConnexionClient(); + ~ConnexionClient(); + + static ConnexionClient& getInstance(); + + ConnexionClient* client; + static void init(); + static void destroy(); + + static bool Is3dmouseAttached(); + + I3dMouseParam& MouseParams(); + const I3dMouseParam& MouseParams() const; + + virtual void Move3d(HANDLE device, std::vector& motionData); + virtual void On3dmouseKeyDown(HANDLE device, int virtualKeyCode); + virtual void On3dmouseKeyUp(HANDLE device, int virtualKeyCode); + + virtual bool nativeEventFilter(const QByteArray& eventType, void* message, long* result) Q_DECL_OVERRIDE + { + MSG* msg = static_cast< MSG * >(message); + return ConnexionClient::RawInputEventFilter(message, result); + } + +public slots: + void toggleConnexion(bool shouldEnable); + +signals: + void Move3d(std::vector& motionData); + void On3dmouseKeyDown(int virtualKeyCode); + void On3dmouseKeyUp(int virtualKeyCode); + +private: + bool InitializeRawInput(HWND hwndTarget); + + static bool RawInputEventFilter(void* msg, long* result); + + void OnRawInput(UINT nInputCode, HRAWINPUT hRawInput); + UINT GetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader); + bool TranslateRawInputData(UINT nInputCode, PRAWINPUT pRawInput); + void On3dmouseInput(); + + class TInputData { + public: + TInputData() : fAxes(6) {} + + bool IsZero() { + return (0.0f == fAxes[0] && 0.0f == fAxes[1] && 0.0f == fAxes[2] && + 0.0f == fAxes[3] && 0.0f == fAxes[4] && 0.0f == fAxes[5]); + } + + int fTimeToLive; // For telling if the device was unplugged while sending data + bool fIsDirty; + std::vector fAxes; + + }; + + HWND fWindow; + + // Data cache to handle multiple rawinput devices + std::map< HANDLE, TInputData> fDevice2Data; + std::map< HANDLE, unsigned long> fDevice2Keystate; + + // 3dmouse parameters + MouseParameters f3dMouseParams; // Rotate, Pan Zoom etc. + + // use to calculate distance traveled since last event + DWORD fLast3dmouseInputTime; +}; + +// the osx connexion api +#else + +#include +#include "3DconnexionClient/ConnexionClientAPI.h" + +class ConnexionClient : public QObject { + Q_OBJECT +public: + static ConnexionClient& getInstance(); + static bool Is3dmouseAttached(); + static void init(); + static void destroy(); +public slots: + void toggleConnexion(bool shouldEnable); +}; + +#endif // __APPLE__ + +#endif // HAVE_CONNEXIONCLIENT + + +// connnects to the userinputmapper +class ConnexionData : public QObject { + Q_OBJECT + +public: + static ConnexionData& getInstance(); + ConnexionData(); + + enum PositionChannel { + POSITION_AXIS_X_POS = 1, + POSITION_AXIS_X_NEG = 2, + POSITION_AXIS_Y_POS = 3, + POSITION_AXIS_Y_NEG = 4, + POSITION_AXIS_Z_POS = 5, + POSITION_AXIS_Z_NEG = 6, + ROTATION_AXIS_X_POS = 7, + ROTATION_AXIS_X_NEG = 8, + ROTATION_AXIS_Y_POS = 9, + ROTATION_AXIS_Y_NEG = 10, + ROTATION_AXIS_Z_POS = 11, + ROTATION_AXIS_Z_NEG = 12 + }; + + enum ButtonChannel { + BUTTON_1 = 1, + BUTTON_2 = 2, + BUTTON_3 = 3 + }; + + typedef std::unordered_set ButtonPressedMap; + typedef std::map AxisStateMap; + + float getButton(int channel) const; + float getAxis(int channel) const; + + UserInputMapper::Input makeInput(ConnexionData::PositionChannel axis); + UserInputMapper::Input makeInput(ConnexionData::ButtonChannel button); + + void registerToUserInputMapper(UserInputMapper& mapper); + void assignDefaultInputMapping(UserInputMapper& mapper); + + void update(); + void focusOutEvent(); + + int getDeviceID() { return _deviceID; } + void setDeviceID(int deviceID) { _deviceID = deviceID; } + + QString _name; + + glm::vec3 cc_position; + glm::vec3 cc_rotation; + int clientId; + + void setButton(int lastButtonState); + void handleAxisEvent(); + +protected: + int _deviceID = 0; + + ButtonPressedMap _buttonPressedMap; + AxisStateMap _axisStateMap; +}; + +#endif // defined(hifi_ConnexionClient_h) \ No newline at end of file diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index f5647bd176..fdc4dbae34 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -107,6 +107,7 @@ public: CachesSize, Chat, Collisions, + Connexion, Console, ControlWithSpeech, CopyAddress, From a5ad40bee97e14a860335f0fb3a1f74d5fc981fd Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 27 Jul 2015 14:07:28 -0700 Subject: [PATCH 12/74] INtroduce the resetStage command to clear up all cache and state in the gpu::Conference and make sure no more resource are linked --- interface/src/Application.cpp | 6 ++ libraries/gpu/src/gpu/Batch.cpp | 4 ++ libraries/gpu/src/gpu/Batch.h | 5 ++ libraries/gpu/src/gpu/Context.cpp | 1 + libraries/gpu/src/gpu/GLBackend.cpp | 20 +++++++ libraries/gpu/src/gpu/GLBackend.h | 45 ++++++++++---- libraries/gpu/src/gpu/GLBackendInput.cpp | 59 ++++++++++++++++--- libraries/gpu/src/gpu/GLBackendOutput.cpp | 5 ++ libraries/gpu/src/gpu/GLBackendPipeline.cpp | 22 +++++++ libraries/gpu/src/gpu/GLBackendQuery.cpp | 4 ++ libraries/gpu/src/gpu/GLBackendState.cpp | 2 +- libraries/gpu/src/gpu/GLBackendTransform.cpp | 4 +- .../render-utils/src/RenderDeferredTask.cpp | 1 - libraries/render/src/render/DrawTask.cpp | 40 ------------- libraries/render/src/render/DrawTask.h | 8 --- 15 files changed, 156 insertions(+), 70 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c2be31cfb3..7bfad60eaf 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -996,6 +996,12 @@ void Application::paintGL() { _compositor.displayOverlayTexture(&renderArgs); } + // Reset the gpu::Context Stages + gpu::Batch batch; + batch.resetStages(); + renderArgs._context->render(batch); + + if (!OculusManager::isConnected() || OculusManager::allowSwap()) { PROFILE_RANGE(__FUNCTION__ "/bufferSwap"); _glWidget->swapBuffers(); diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 4ac33d8f14..8815c1bae1 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -288,6 +288,10 @@ void Batch::getQuery(const QueryPointer& query) { _params.push_back(_queries.cache(query)); } +void Batch::resetStages() { + ADD_COMMAND(resetStages); +} + void push_back(Batch::Params& params, const vec3& v) { params.push_back(v.x); params.push_back(v.y); diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 58fe03c9cf..5f2c2dd089 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -113,6 +113,9 @@ public: void endQuery(const QueryPointer& query); void getQuery(const QueryPointer& query); + // Reset the stage caches and states + void resetStages(); + // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long // term strategy is to get rid of any GL calls in favor of the HIFI GPU API @@ -186,6 +189,8 @@ public: COMMAND_endQuery, COMMAND_getQuery, + COMMAND_resetStages, + // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long // term strategy is to get rid of any GL calls in favor of the HIFI GPU API diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index 604f39f46f..6730be33bb 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -45,3 +45,4 @@ void Context::syncCache() { void Context::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) { _backend->downloadFramebuffer(srcFramebuffer, region, destImage); } + diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index 6b1d552be9..51637462f1 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -46,6 +46,8 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::GLBackend::do_endQuery), (&::gpu::GLBackend::do_getQuery), + (&::gpu::GLBackend::do_resetStages), + (&::gpu::GLBackend::do_glEnable), (&::gpu::GLBackend::do_glDisable), @@ -128,6 +130,8 @@ GLBackend::GLBackend() : } GLBackend::~GLBackend() { + resetStages(); + killInput(); killTransform(); } @@ -246,6 +250,22 @@ void GLBackend::do_drawIndexedInstanced(Batch& batch, uint32 paramOffset) { (void) CHECK_GL_ERROR(); } +void GLBackend::do_resetStages(Batch& batch, uint32 paramOffset) { + resetStages(); +} + +void GLBackend::resetStages() { + resetInputStage(); + resetPipelineStage(); + resetTransformStage(); + resetUniformStage(); + resetResourceStage(); + resetOutputStage(); + resetQueryStage(); + + (void) CHECK_GL_ERROR(); +} + // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long // term strategy is to get rid of any GL calls in favor of the HIFI GPU API diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 9d8c9ef805..59a6c1ee7e 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -195,7 +195,7 @@ public: static const int MAX_NUM_ATTRIBUTES = Stream::NUM_INPUT_SLOTS; static const int MAX_NUM_INPUT_BUFFERS = 16; - uint32 getNumInputBuffers() const { return _input._buffersState.size(); } + uint32 getNumInputBuffers() const { return _input._invalidBuffers.size(); } // The State setters called by the GLState::Commands when a new state is assigned @@ -250,12 +250,16 @@ protected: void killInput(); void syncInputStateCache(); void updateInput(); + void resetInputStage(); struct InputStageState { bool _invalidFormat = true; Stream::FormatPointer _format; + typedef std::bitset ActivationCache; + ActivationCache _attributeActivation; + typedef std::bitset BuffersState; - BuffersState _buffersState; + BuffersState _invalidBuffers; Buffers _buffers; Offsets _bufferOffsets; @@ -266,23 +270,20 @@ protected: Offset _indexBufferOffset; Type _indexBufferType; - typedef std::bitset ActivationCache; - ActivationCache _attributeActivation; - GLuint _defaultVAO; InputStageState() : _invalidFormat(true), _format(0), - _buffersState(0), - _buffers(_buffersState.size(), BufferPointer(0)), - _bufferOffsets(_buffersState.size(), 0), - _bufferStrides(_buffersState.size(), 0), - _bufferVBOs(_buffersState.size(), 0), + _attributeActivation(0), + _invalidBuffers(0), + _buffers(_invalidBuffers.size(), BufferPointer(0)), + _bufferOffsets(_invalidBuffers.size(), 0), + _bufferStrides(_invalidBuffers.size(), 0), + _bufferVBOs(_invalidBuffers.size(), 0), _indexBuffer(0), _indexBufferOffset(0), _indexBufferType(UINT32), - _attributeActivation(0), _defaultVAO(0) {} } _input; @@ -298,6 +299,7 @@ protected: // Synchronize the state cache of this Backend with the actual real state of the GL Context void syncTransformStateCache(); void updateTransform(); + void resetTransformStage(); struct TransformStageState { TransformObject _transformObject; TransformCamera _transformCamera; @@ -330,12 +332,20 @@ protected: // Uniform Stage void do_setUniformBuffer(Batch& batch, uint32 paramOffset); - void do_setResourceTexture(Batch& batch, uint32 paramOffset); + void resetUniformStage(); struct UniformStageState { }; + // Resource Stage + void do_setResourceTexture(Batch& batch, uint32 paramOffset); + + void resetResourceStage(); + struct ResourceStageState { + + }; + // Pipeline Stage void do_setPipeline(Batch& batch, uint32 paramOffset); void do_setStateBlendFactor(Batch& batch, uint32 paramOffset); @@ -349,6 +359,7 @@ protected: void syncPipelineStateCache(); // Grab the actual gl state into it's gpu::State equivalent. THis is used by the above call syncPipleineStateCache() void getCurrentGLState(State::Data& state); + void resetPipelineStage(); struct PipelineStageState { @@ -388,6 +399,7 @@ protected: // Synchronize the state cache of this Backend with the actual real state of the GL Context void syncOutputStateCache(); + void resetOutputStage(); struct OutputStageState { @@ -402,6 +414,15 @@ protected: void do_endQuery(Batch& batch, uint32 paramOffset); void do_getQuery(Batch& batch, uint32 paramOffset); + void resetQueryStage(); + struct QueryStageState { + + }; + + // Reset stages + void do_resetStages(Batch& batch, uint32 paramOffset); + void resetStages(); + // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long // term strategy is to get rid of any GL calls in favor of the HIFI GPU API diff --git a/libraries/gpu/src/gpu/GLBackendInput.cpp b/libraries/gpu/src/gpu/GLBackendInput.cpp index 229b29cd43..9014024914 100755 --- a/libraries/gpu/src/gpu/GLBackendInput.cpp +++ b/libraries/gpu/src/gpu/GLBackendInput.cpp @@ -52,7 +52,7 @@ void GLBackend::do_setInputBuffer(Batch& batch, uint32 paramOffset) { } if (isModified) { - _input._buffersState.set(channel); + _input._invalidBuffers.set(channel); } } } @@ -154,7 +154,7 @@ void GLBackend::updateInput() { _stats._ISNumFormatChanges++; } - if (_input._buffersState.any()) { + if (_input._invalidBuffers.any()) { int numBuffers = _input._buffers.size(); auto buffer = _input._buffers.data(); auto vbo = _input._bufferVBOs.data(); @@ -162,7 +162,7 @@ void GLBackend::updateInput() { auto stride = _input._bufferStrides.data(); for (int bufferNum = 0; bufferNum < numBuffers; bufferNum++) { - if (_input._buffersState.test(bufferNum)) { + if (_input._invalidBuffers.test(bufferNum)) { glBindVertexBuffer(bufferNum, (*vbo), (*offset), (*stride)); } buffer++; @@ -170,11 +170,11 @@ void GLBackend::updateInput() { offset++; stride++; } - _input._buffersState.reset(); + _input._invalidBuffers.reset(); (void) CHECK_GL_ERROR(); } #else - if (_input._invalidFormat || _input._buffersState.any()) { + if (_input._invalidFormat || _input._invalidBuffers.any()) { if (_input._invalidFormat) { InputStageState::ActivationCache newActivation; @@ -232,7 +232,7 @@ void GLBackend::updateInput() { if ((channelIt).first < buffers.size()) { int bufferNum = (channelIt).first; - if (_input._buffersState.test(bufferNum) || _input._invalidFormat) { + if (_input._invalidBuffers.test(bufferNum) || _input._invalidFormat) { // GLuint vbo = gpu::GLBackend::getBufferID((*buffers[bufferNum])); GLuint vbo = _input._bufferVBOs[bufferNum]; if (boundVBO != vbo) { @@ -240,7 +240,7 @@ void GLBackend::updateInput() { (void) CHECK_GL_ERROR(); boundVBO = vbo; } - _input._buffersState[bufferNum] = false; + _input._invalidBuffers[bufferNum] = false; for (unsigned int i = 0; i < channel._slots.size(); i++) { const Stream::Attribute& attrib = attributes.at(channel._slots[i]); @@ -285,6 +285,51 @@ void GLBackend::updateInput() { #endif } +void GLBackend::resetInputStage() { + // Reset index buffer + _input._indexBufferType = UINT32; + _input._indexBufferOffset = 0; + _input._indexBuffer.reset(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + (void) CHECK_GL_ERROR(); + + +#if defined(SUPPORT_VAO) + // TODO +#else + glBindBuffer(GL_ARRAY_BUFFER, 0); + + size_t i = 0; +#if defined(SUPPORT_LEGACY_OPENGL) + for (; i < NUM_CLASSIC_ATTRIBS; i++) { + glDisableClientState(attributeSlotToClassicAttribName[i]); + } + glVertexPointer(4, GL_FLOAT, 0, 0); + glNormalPointer(GL_FLOAT, 0, 0); + glColorPointer(4, GL_FLOAT, 0, 0); + glTexCoordPointer(4, GL_FLOAT, 0, 0); +#endif + + for (; i < _input._attributeActivation.size(); i++) { + glDisableVertexAttribArray(i); + glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, 0, 0); + } +#endif + + // Reset vertex buffer and format + _input._format.reset(); + _input._invalidFormat = false; + _input._attributeActivation.reset(); + + for (int i = 0; i < _input._buffers.size(); i++) { + _input._buffers[i].reset(); + _input._bufferOffsets[i] = 0; + _input._bufferStrides[i] = 0; + _input._bufferVBOs[i] = 0; + } + _input._invalidBuffers.reset(); + +} void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) { _input._indexBufferType = (Type) batch._params[paramOffset + 2]._uint; diff --git a/libraries/gpu/src/gpu/GLBackendOutput.cpp b/libraries/gpu/src/gpu/GLBackendOutput.cpp index b37def48e7..6b0bfae635 100755 --- a/libraries/gpu/src/gpu/GLBackendOutput.cpp +++ b/libraries/gpu/src/gpu/GLBackendOutput.cpp @@ -177,6 +177,11 @@ void GLBackend::syncOutputStateCache() { _output._framebuffer.reset(); } +void GLBackend::resetOutputStage() { + _output._framebuffer.reset(); + _output._drawFBO = 0; + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); +} void GLBackend::do_setFramebuffer(Batch& batch, uint32 paramOffset) { auto framebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint); diff --git a/libraries/gpu/src/gpu/GLBackendPipeline.cpp b/libraries/gpu/src/gpu/GLBackendPipeline.cpp index 51a3a24e9b..4a54753af8 100755 --- a/libraries/gpu/src/gpu/GLBackendPipeline.cpp +++ b/libraries/gpu/src/gpu/GLBackendPipeline.cpp @@ -164,6 +164,24 @@ void GLBackend::updatePipeline() { #endif } +void GLBackend::resetPipelineStage() { + // First reset State to default + State::Signature resetSignature(0); + resetPipelineState(resetSignature); + _pipeline._state = nullptr; + _pipeline._invalidState = false; + + // Second the shader side + _pipeline._invalidProgram = false; + _pipeline._program = 0; + _pipeline._pipeline.reset(); + glUseProgram(0); +} + +void GLBackend::resetUniformStage() { + +} + void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) { GLuint slot = batch._params[paramOffset + 3]._uint; BufferPointer uniformBuffer = batch._buffers.get(batch._params[paramOffset + 2]._uint); @@ -188,6 +206,10 @@ void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) { (void) CHECK_GL_ERROR(); } +void GLBackend::resetResourceStage() { + +} + 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/gpu/src/gpu/GLBackendQuery.cpp b/libraries/gpu/src/gpu/GLBackendQuery.cpp index 39db19dafd..2bdf7c86ad 100644 --- a/libraries/gpu/src/gpu/GLBackendQuery.cpp +++ b/libraries/gpu/src/gpu/GLBackendQuery.cpp @@ -104,3 +104,7 @@ void GLBackend::do_getQuery(Batch& batch, uint32 paramOffset) { (void)CHECK_GL_ERROR(); } } + +void GLBackend::resetQueryStage() { +} + diff --git a/libraries/gpu/src/gpu/GLBackendState.cpp b/libraries/gpu/src/gpu/GLBackendState.cpp index 18fc9ddd3c..618a13e2c4 100644 --- a/libraries/gpu/src/gpu/GLBackendState.cpp +++ b/libraries/gpu/src/gpu/GLBackendState.cpp @@ -484,7 +484,7 @@ void GLBackend::syncPipelineStateCache() { glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); getCurrentGLState(state); State::Signature signature = State::evalSignature(state); - + _pipeline._stateCache = state; _pipeline._stateSignatureCache = signature; } diff --git a/libraries/gpu/src/gpu/GLBackendTransform.cpp b/libraries/gpu/src/gpu/GLBackendTransform.cpp index 65d9c6ed75..e05e0fc1c0 100755 --- a/libraries/gpu/src/gpu/GLBackendTransform.cpp +++ b/libraries/gpu/src/gpu/GLBackendTransform.cpp @@ -184,4 +184,6 @@ void GLBackend::updateTransform() { _transform._invalidView = _transform._invalidProj = _transform._invalidModel = _transform._invalidViewport = false; } - +void GLBackend::resetTransformStage() { + +} diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 0c8d19250b..30c8dffc0e 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -97,7 +97,6 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _drawStatusJobIndex = _jobs.size() - 1; _jobs.push_back(Job(new DrawOverlay3D::JobModel("DrawOverlay3D"))); - _jobs.push_back(Job(new ResetGLState::JobModel())); // Give ourselves 3 frmaes of timer queries _timerQueries.push_back(std::make_shared()); diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 0e3eba0b53..0aef913d50 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -216,46 +216,6 @@ void render::renderItems(const SceneContextPointer& sceneContext, const RenderCo } } -void addClearStateCommands(gpu::Batch& batch) { - batch._glDepthMask(true); - batch._glDepthFunc(GL_LESS); - batch._glDisable(GL_CULL_FACE); - - batch._glActiveTexture(GL_TEXTURE0 + 1); - batch._glBindTexture(GL_TEXTURE_2D, 0); - batch._glActiveTexture(GL_TEXTURE0 + 2); - batch._glBindTexture(GL_TEXTURE_2D, 0); - batch._glActiveTexture(GL_TEXTURE0 + 3); - batch._glBindTexture(GL_TEXTURE_2D, 0); - batch._glActiveTexture(GL_TEXTURE0); - batch._glBindTexture(GL_TEXTURE_2D, 0); - - - // deactivate vertex arrays after drawing - batch._glDisableClientState(GL_NORMAL_ARRAY); - batch._glDisableClientState(GL_VERTEX_ARRAY); - batch._glDisableClientState(GL_TEXTURE_COORD_ARRAY); - batch._glDisableClientState(GL_COLOR_ARRAY); - batch._glDisableVertexAttribArray(gpu::Stream::TANGENT); - batch._glDisableVertexAttribArray(gpu::Stream::SKIN_CLUSTER_INDEX); - batch._glDisableVertexAttribArray(gpu::Stream::SKIN_CLUSTER_WEIGHT); - - // bind with 0 to switch back to normal operation - batch._glBindBuffer(GL_ARRAY_BUFFER, 0); - batch._glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - batch._glBindTexture(GL_TEXTURE_2D, 0); - - // Back to no program - batch._glUseProgram(0); -} -void ResetGLState::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - - gpu::Batch theBatch; - addClearStateCommands(theBatch); - assert(renderContext->args); - renderContext->args->_context->render(theBatch); -} - void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { assert(renderContext->args); assert(renderContext->args->_viewFrustum); diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 62810d47f0..ec6656c0dc 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -260,14 +260,6 @@ public: typedef Job::Model JobModel; }; -class ResetGLState { -public: - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); - - typedef Job::Model JobModel; -}; - - class DrawSceneTask : public Task { public: From 5ae15d46b40877c6cac412382ef6bbda56e26637 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 27 Jul 2015 16:42:54 -0700 Subject: [PATCH 13/74] add some javascript callable stuff back to MyAvatar --- interface/src/avatar/MyAvatar.cpp | 29 ++++++++++++++++++- interface/src/avatar/MyAvatar.h | 5 ++++ interface/src/avatar/SkeletonModel.h | 42 ++++++++++++++-------------- libraries/render-utils/src/Model.cpp | 4 --- libraries/render-utils/src/Model.h | 5 ---- 5 files changed, 54 insertions(+), 31 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index fe4d4bc3cb..f29c21f114 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -900,10 +900,37 @@ glm::vec3 MyAvatar::getDefaultEyePosition() const { const float SCRIPT_PRIORITY = DEFAULT_PRIORITY + 1.0f; const float RECORDER_PRIORITY = SCRIPT_PRIORITY + 1.0f; +void MyAvatar::setJointRotations(QVector jointRotations) { + int numStates = glm::min(_skeletonModel.getJointStateCount(), jointRotations.size()); + for (int i = 0; i < numStates; ++i) { + // HACK: ATM only Recorder calls setJointRotations() so we hardcode its priority here + _skeletonModel.setJointState(i, true, jointRotations[i], RECORDER_PRIORITY); + } +} + +void MyAvatar::setJointData(int index, const glm::quat& rotation) { + if (QThread::currentThread() == thread()) { + // HACK: ATM only JS scripts call setJointData() on MyAvatar so we hardcode the priority + _rig->setJointState(index, true, rotation, SCRIPT_PRIORITY); + } +} + +void MyAvatar::clearJointData(int index) { + if (QThread::currentThread() == thread()) { + // HACK: ATM only JS scripts call clearJointData() on MyAvatar so we hardcode the priority + _rig->setJointState(index, false, glm::quat(), 0.0f); + _rig->clearJointAnimationPriority(index); + } +} + +void MyAvatar::clearJointsData() { + clearJointAnimationPriorities(); +} + void MyAvatar::clearJointAnimationPriorities() { int numStates = _skeletonModel.getJointStateCount(); for (int i = 0; i < numStates; ++i) { - _skeletonModel.clearJointAnimationPriority(i); + _rig->clearJointAnimationPriority(i); } } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index e83deddf16..4dfe0611af 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -104,6 +104,11 @@ public: void updateLookAtTargetAvatar(); void clearLookAtTargetAvatar(); + virtual void setJointRotations(QVector jointRotations); + virtual void setJointData(int index, const glm::quat& rotation); + virtual void clearJointData(int index); + virtual void clearJointsData(); + Q_INVOKABLE void useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName = QString()); Q_INVOKABLE void useHeadURL(const QUrl& headURL, const QString& modelName = QString()); Q_INVOKABLE void useBodyURL(const QUrl& bodyURL, const QString& modelName = QString()); diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 14dc2da3f0..5d76ac1149 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -22,68 +22,68 @@ class MuscleConstraint; /// A skeleton loaded from a model. class SkeletonModel : public Model { Q_OBJECT - + public: SkeletonModel(Avatar* owningAvatar, QObject* parent = nullptr, RigPointer rig = nullptr); ~SkeletonModel(); - + virtual void initJointStates(QVector states); void simulate(float deltaTime, bool fullUpdate = true); void renderIKConstraints(gpu::Batch& batch); - + /// Returns the index of the left hand joint, or -1 if not found. int getLeftHandJointIndex() const { return isActive() ? _geometry->getFBXGeometry().leftHandJointIndex : -1; } - + /// Returns the index of the right hand joint, or -1 if not found. int getRightHandJointIndex() const { return isActive() ? _geometry->getFBXGeometry().rightHandJointIndex : -1; } /// Retrieve the position of the left hand /// \return true whether or not the position was found bool getLeftHandPosition(glm::vec3& position) const; - + /// Retrieve the position of the right hand /// \return true whether or not the position was found bool getRightHandPosition(glm::vec3& position) const; - + /// Restores some fraction of the default position of the left hand. /// \param fraction the fraction of the default position to restore /// \return whether or not the left hand joint was found bool restoreLeftHandPosition(float fraction = 1.0f, float priority = 1.0f); - + /// Gets the position of the left shoulder. /// \return whether or not the left shoulder joint was found bool getLeftShoulderPosition(glm::vec3& position) const; - + /// Returns the extended length from the left hand to its last free ancestor. float getLeftArmLength() const; - + /// Restores some fraction of the default position of the right hand. /// \param fraction the fraction of the default position to restore /// \return whether or not the right hand joint was found bool restoreRightHandPosition(float fraction = 1.0f, float priority = 1.0f); - + /// Gets the position of the right shoulder. /// \return whether or not the right shoulder joint was found bool getRightShoulderPosition(glm::vec3& position) const; - + /// Returns the extended length from the right hand to its first free ancestor. float getRightArmLength() const; /// Returns the position of the head joint. /// \return whether or not the head was found bool getHeadPosition(glm::vec3& headPosition) const; - + /// Returns the position of the neck joint. /// \return whether or not the neck was found bool getNeckPosition(glm::vec3& neckPosition) const; - + /// Returns the rotation of the neck joint's parent from default orientation /// \return whether or not the neck was found bool getNeckParentRotationFromDefaultOrientation(glm::quat& neckParentRotation) const; - + /// Retrieve the positions of up to two eye meshes. /// \return whether or not both eye meshes were found bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; @@ -119,12 +119,12 @@ protected: /// \param jointIndex index of joint in model /// \param position position of joint in model-frame void applyHandPosition(int jointIndex, const glm::vec3& position); - + void applyPalmData(int jointIndex, PalmData& palm); - + /// Updates the state of the joint at the specified index. - virtual void updateJointState(int index); - + virtual void updateJointState(int index); + void maybeUpdateLeanRotation(const JointState& parentState, int index); void maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, int index); void maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, int index); @@ -137,9 +137,9 @@ protected: private: void renderJointConstraints(gpu::Batch& batch, int jointIndex); - void renderOrientationDirections(gpu::Batch& batch, int jointIndex, + void renderOrientationDirections(gpu::Batch& batch, int jointIndex, glm::vec3 position, const glm::quat& orientation, float size); - + struct OrientationLineIDs { int _up; int _front; @@ -154,7 +154,7 @@ private: void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation); bool getEyeModelPositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; - + Avatar* _owningAvatar; CapsuleShape _boundingShape; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index a316da0f99..1f7b67ef05 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1052,10 +1052,6 @@ void Model::clearJointState(int index) { _rig->clearJointState(index); } -void Model::clearJointAnimationPriority(int index) { - _rig->clearJointAnimationPriority(index); -} - void Model::setJointState(int index, bool valid, const glm::quat& rotation, float priority) { _rig->setJointState(index, valid, rotation, priority); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 45d7ce63ab..fc8347581b 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -150,10 +149,6 @@ public: /// Sets the distance parameter used for LOD computations. void setLODDistance(float distance) { _lodDistance = distance; } - const QList& getRunningAnimations() const { return _rig->getRunningAnimations(); } - /// Clear the joint animation priority - void clearJointAnimationPriority(int index); - void setScaleToFit(bool scaleToFit, float largestDimension = 0.0f, bool forceRescale = false); bool getScaleToFit() const { return _scaleToFit; } /// is scale to fit enabled From f525a8a245dd9f3f1fa647d3865f0e24ba88d683 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 27 Jul 2015 17:17:56 -0700 Subject: [PATCH 14/74] Removing all the unecessary calls of Batch from the gl legacy time --- interface/src/Application.cpp | 12 +- interface/src/Stars.cpp | 5 +- interface/src/ui/ApplicationOverlay.cpp | 2 +- .../src/RenderableWebEntityItem.cpp | 3 +- libraries/gpu/src/gpu/Batch.h | 52 +--- libraries/gpu/src/gpu/GLBackend.cpp | 250 +----------------- libraries/gpu/src/gpu/GLBackend.h | 25 +- libraries/gpu/src/gpu/GLBackendOutput.cpp | 8 +- libraries/gpu/src/gpu/GLBackendState.cpp | 5 + 9 files changed, 34 insertions(+), 328 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7bfad60eaf..42868166d0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -995,11 +995,6 @@ void Application::paintGL() { _compositor.displayOverlayTexture(&renderArgs); } - - // Reset the gpu::Context Stages - gpu::Batch batch; - batch.resetStages(); - renderArgs._context->render(batch); if (!OculusManager::isConnected() || OculusManager::allowSwap()) { @@ -1013,6 +1008,13 @@ void Application::paintGL() { _frameCount++; _numFramesSinceLastResize++; Stats::getInstance()->setRenderDetails(renderArgs._details); + + + // Reset the gpu::Context Stages + // Back to the default framebuffer; + gpu::Batch batch; + batch.resetStages(); + renderArgs._context->render(batch); } void Application::runTests() { diff --git a/interface/src/Stars.cpp b/interface/src/Stars.cpp index ebfddee38c..7d09b9b1c3 100644 --- a/interface/src/Stars.cpp +++ b/interface/src/Stars.cpp @@ -154,6 +154,7 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { auto state = gpu::StatePointer(new gpu::State()); // enable decal blend state->setDepthTest(gpu::State::DepthTest(false)); + state->setAntialiasedLineEnable(true); // line smoothing also smooth points state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); _starsPipeline.reset(gpu::Pipeline::create(program, state)); @@ -217,10 +218,10 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { // Render the stars batch.setPipeline(_starsPipeline); - batch._glEnable(GL_PROGRAM_POINT_SIZE_EXT); + /* batch._glEnable(GL_PROGRAM_POINT_SIZE_EXT); batch._glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); batch._glEnable(GL_POINT_SMOOTH); - + */ batch.setInputFormat(streamFormat); batch.setInputBuffer(VERTICES_SLOT, posView); batch.setInputBuffer(COLOR_SLOT, colView); diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index bc10b555e4..acc24ba2be 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -117,7 +117,7 @@ void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) { batch.setProjectionTransform(mat4()); batch.setModelTransform(Transform()); batch.setViewTransform(Transform()); - batch._glBindTexture(GL_TEXTURE_2D, _uiTexture); + batch._glActiveBindTexture(GL_TEXTURE0, GL_TEXTURE_2D, _uiTexture); geometryCache->renderUnitQuad(batch, glm::vec4(1)); } diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 7fa615073b..ee1fdfae45 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -178,8 +178,7 @@ void RenderableWebEntityItem::render(RenderArgs* args) { batch.setModelTransform(getTransformToCenter()); bool textured = false, culled = false, emissive = false; if (_texture) { - batch._glActiveTexture(GL_TEXTURE0); - batch._glBindTexture(GL_TEXTURE_2D, _texture); + batch._glActiveBindTexture(GL_TEXTURE0, GL_TEXTURE_2D, _texture); textured = emissive = true; } diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 5f2c2dd089..5135d1ac4f 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -94,7 +94,7 @@ public: 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 + // Ouput Stage void setFramebuffer(const FramebufferPointer& framebuffer); // Clear framebuffer layers @@ -122,28 +122,8 @@ public: // For now, instead of calling the raw gl Call, use the equivalent call on the batch so the call is beeing recorded // THe implementation of these functions is in GLBackend.cpp - void _glEnable(unsigned int cap); - void _glDisable(unsigned int cap); + void _glActiveBindTexture(unsigned int unit, unsigned int target, unsigned int texture); - void _glEnableClientState(unsigned int array); - void _glDisableClientState(unsigned int array); - - void _glCullFace(unsigned int mode); - void _glAlphaFunc(unsigned int func, float ref); - - void _glDepthFunc(unsigned int func); - void _glDepthMask(unsigned char flag); - void _glDepthRange(float zNear, float zFar); - - void _glBindBuffer(unsigned int target, unsigned int buffer); - - void _glBindTexture(unsigned int target, unsigned int texture); - void _glActiveTexture(unsigned int texture); - void _glTexParameteri(unsigned int target, unsigned int pname, int param); - - void _glDrawBuffers(int n, const unsigned int* bufs); - - void _glUseProgram(unsigned int program); void _glUniform1i(int location, int v0); void _glUniform1f(int location, float v0); void _glUniform2f(int location, float v0, float v1); @@ -153,9 +133,6 @@ public: void _glUniform4iv(int location, int count, const int* value); void _glUniformMatrix4fv(int location, int count, unsigned char transpose, const float* value); - void _glEnableVertexAttribArray(int location); - void _glDisableVertexAttribArray(int location); - void _glColor4f(float red, float green, float blue, float alpha); void _glLineWidth(float width); @@ -194,28 +171,8 @@ public: // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long // term strategy is to get rid of any GL calls in favor of the HIFI GPU API - COMMAND_glEnable, - COMMAND_glDisable, + COMMAND_glActiveBindTexture, - COMMAND_glEnableClientState, - COMMAND_glDisableClientState, - - COMMAND_glCullFace, - COMMAND_glAlphaFunc, - - COMMAND_glDepthFunc, - COMMAND_glDepthMask, - COMMAND_glDepthRange, - - COMMAND_glBindBuffer, - - COMMAND_glBindTexture, - COMMAND_glActiveTexture, - COMMAND_glTexParameteri, - - COMMAND_glDrawBuffers, - - COMMAND_glUseProgram, COMMAND_glUniform1i, COMMAND_glUniform1f, COMMAND_glUniform2f, @@ -225,9 +182,6 @@ public: COMMAND_glUniform4iv, COMMAND_glUniformMatrix4fv, - COMMAND_glEnableVertexAttribArray, - COMMAND_glDisableVertexAttribArray, - COMMAND_glColor4f, COMMAND_glLineWidth, diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index 51637462f1..8db192b827 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -48,28 +48,8 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::GLBackend::do_resetStages), - (&::gpu::GLBackend::do_glEnable), - (&::gpu::GLBackend::do_glDisable), + (&::gpu::GLBackend::do_glActiveBindTexture), - (&::gpu::GLBackend::do_glEnableClientState), - (&::gpu::GLBackend::do_glDisableClientState), - - (&::gpu::GLBackend::do_glCullFace), - (&::gpu::GLBackend::do_glAlphaFunc), - - (&::gpu::GLBackend::do_glDepthFunc), - (&::gpu::GLBackend::do_glDepthMask), - (&::gpu::GLBackend::do_glDepthRange), - - (&::gpu::GLBackend::do_glBindBuffer), - - (&::gpu::GLBackend::do_glBindTexture), - (&::gpu::GLBackend::do_glActiveTexture), - (&::gpu::GLBackend::do_glTexParameteri), - - (&::gpu::GLBackend::do_glDrawBuffers), - - (&::gpu::GLBackend::do_glUseProgram), (&::gpu::GLBackend::do_glUniform1i), (&::gpu::GLBackend::do_glUniform1f), (&::gpu::GLBackend::do_glUniform2f), @@ -79,9 +59,6 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::GLBackend::do_glUniform4iv), (&::gpu::GLBackend::do_glUniformMatrix4fv), - (&::gpu::GLBackend::do_glEnableVertexAttribArray), - (&::gpu::GLBackend::do_glDisableVertexAttribArray), - (&::gpu::GLBackend::do_glColor4f), (&::gpu::GLBackend::do_glLineWidth), }; @@ -275,211 +252,24 @@ void GLBackend::resetStages() { //#define DO_IT_NOW(call, offset) runLastCommand(); #define DO_IT_NOW(call, offset) - -void Batch::_glEnable(GLenum cap) { - ADD_COMMAND_GL(glEnable); - - _params.push_back(cap); - - DO_IT_NOW(_glEnable, 1); -} -void GLBackend::do_glEnable(Batch& batch, uint32 paramOffset) { - glEnable(batch._params[paramOffset]._uint); - (void) CHECK_GL_ERROR(); -} - -void Batch::_glDisable(GLenum cap) { - ADD_COMMAND_GL(glDisable); - - _params.push_back(cap); - - DO_IT_NOW(_glDisable, 1); -} -void GLBackend::do_glDisable(Batch& batch, uint32 paramOffset) { - glDisable(batch._params[paramOffset]._uint); - (void) CHECK_GL_ERROR(); -} - -void Batch::_glEnableClientState(GLenum array) { - ADD_COMMAND_GL(glEnableClientState); - - _params.push_back(array); - - DO_IT_NOW(_glEnableClientState, 1); -} -void GLBackend::do_glEnableClientState(Batch& batch, uint32 paramOffset) { - glEnableClientState(batch._params[paramOffset]._uint); - (void) CHECK_GL_ERROR(); -} - -void Batch::_glDisableClientState(GLenum array) { - ADD_COMMAND_GL(glDisableClientState); - - _params.push_back(array); - - DO_IT_NOW(_glDisableClientState, 1); -} -void GLBackend::do_glDisableClientState(Batch& batch, uint32 paramOffset) { - glDisableClientState(batch._params[paramOffset]._uint); - (void) CHECK_GL_ERROR(); -} - -void Batch::_glCullFace(GLenum mode) { - ADD_COMMAND_GL(glCullFace); - - _params.push_back(mode); - - DO_IT_NOW(_glCullFace, 1); -} -void GLBackend::do_glCullFace(Batch& batch, uint32 paramOffset) { - glCullFace(batch._params[paramOffset]._uint); - (void) CHECK_GL_ERROR(); -} - -void Batch::_glAlphaFunc(GLenum func, GLclampf ref) { - ADD_COMMAND_GL(glAlphaFunc); - - _params.push_back(ref); - _params.push_back(func); - - DO_IT_NOW(_glAlphaFunc, 2); -} -void GLBackend::do_glAlphaFunc(Batch& batch, uint32 paramOffset) { - glAlphaFunc( - batch._params[paramOffset + 1]._uint, - batch._params[paramOffset + 0]._float); - (void) CHECK_GL_ERROR(); -} - -void Batch::_glDepthFunc(GLenum func) { - ADD_COMMAND_GL(glDepthFunc); - - _params.push_back(func); - - DO_IT_NOW(_glDepthFunc, 1); -} -void GLBackend::do_glDepthFunc(Batch& batch, uint32 paramOffset) { - glDepthFunc(batch._params[paramOffset]._uint); - (void) CHECK_GL_ERROR(); -} - -void Batch::_glDepthMask(GLboolean flag) { - ADD_COMMAND_GL(glDepthMask); - - _params.push_back(flag); - - DO_IT_NOW(_glDepthMask, 1); -} -void GLBackend::do_glDepthMask(Batch& batch, uint32 paramOffset) { - glDepthMask(batch._params[paramOffset]._uint); - (void) CHECK_GL_ERROR(); -} - -void Batch::_glDepthRange(GLfloat zNear, GLfloat zFar) { - ADD_COMMAND_GL(glDepthRange); - - _params.push_back(zFar); - _params.push_back(zNear); - - DO_IT_NOW(_glDepthRange, 2); -} -void GLBackend::do_glDepthRange(Batch& batch, uint32 paramOffset) { - glDepthRange( - batch._params[paramOffset + 1]._float, - batch._params[paramOffset + 0]._float); - (void) CHECK_GL_ERROR(); -} - -void Batch::_glBindBuffer(GLenum target, GLuint buffer) { - ADD_COMMAND_GL(glBindBuffer); - - _params.push_back(buffer); - _params.push_back(target); - - DO_IT_NOW(_glBindBuffer, 2); -} -void GLBackend::do_glBindBuffer(Batch& batch, uint32 paramOffset) { - glBindBuffer( - batch._params[paramOffset + 1]._uint, - batch._params[paramOffset + 0]._uint); - (void) CHECK_GL_ERROR(); -} - -void Batch::_glBindTexture(GLenum target, GLuint texture) { - ADD_COMMAND_GL(glBindTexture); +void Batch::_glActiveBindTexture(GLenum unit, GLenum target, GLuint texture) { + ADD_COMMAND_GL(glActiveBindTexture); _params.push_back(texture); _params.push_back(target); + _params.push_back(unit); - DO_IT_NOW(_glBindTexture, 2); + + DO_IT_NOW(_glActiveBindTexture, 3); } -void GLBackend::do_glBindTexture(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glActiveBindTexture(Batch& batch, uint32 paramOffset) { + glActiveTexture(batch._params[paramOffset + 2]._uint); glBindTexture( batch._params[paramOffset + 1]._uint, batch._params[paramOffset + 0]._uint); (void) CHECK_GL_ERROR(); } -void Batch::_glActiveTexture(GLenum texture) { - ADD_COMMAND_GL(glActiveTexture); - - _params.push_back(texture); - - DO_IT_NOW(_glActiveTexture, 1); -} -void GLBackend::do_glActiveTexture(Batch& batch, uint32 paramOffset) { - glActiveTexture(batch._params[paramOffset]._uint); - (void) CHECK_GL_ERROR(); -} - -void Batch::_glTexParameteri(GLenum target, GLenum pname, GLint param) { - ADD_COMMAND_GL(glTexParameteri); - - _params.push_back(param); - _params.push_back(pname); - _params.push_back(target); - - DO_IT_NOW(glTexParameteri, 3); -} -void GLBackend::do_glTexParameteri(Batch& batch, uint32 paramOffset) { - glTexParameteri(batch._params[paramOffset + 2]._uint, - batch._params[paramOffset + 1]._uint, - batch._params[paramOffset + 0]._int); - (void) CHECK_GL_ERROR(); -} - -void Batch::_glDrawBuffers(GLsizei n, const GLenum* bufs) { - ADD_COMMAND_GL(glDrawBuffers); - - _params.push_back(cacheData(n * sizeof(GLenum), bufs)); - _params.push_back(n); - - DO_IT_NOW(_glDrawBuffers, 2); -} -void GLBackend::do_glDrawBuffers(Batch& batch, uint32 paramOffset) { - glDrawBuffers( - batch._params[paramOffset + 1]._uint, - (const GLenum*)batch.editData(batch._params[paramOffset + 0]._uint)); - (void) CHECK_GL_ERROR(); -} - -void Batch::_glUseProgram(GLuint program) { - ADD_COMMAND_GL(glUseProgram); - - _params.push_back(program); - - DO_IT_NOW(_glUseProgram, 1); -} -void GLBackend::do_glUseProgram(Batch& batch, uint32 paramOffset) { - - _pipeline._program = batch._params[paramOffset]._uint; - // for this call we still want to execute the glUseProgram in the order of the glCOmmand to avoid any issue - _pipeline._invalidProgram = false; - glUseProgram(_pipeline._program); - - (void) CHECK_GL_ERROR(); -} - void Batch::_glUniform1i(GLint location, GLint v0) { if (location < 0) { return; @@ -680,30 +470,6 @@ void GLBackend::do_glUniformMatrix4fv(Batch& batch, uint32 paramOffset) { (void) CHECK_GL_ERROR(); } -void Batch::_glEnableVertexAttribArray(GLint location) { - ADD_COMMAND_GL(glEnableVertexAttribArray); - - _params.push_back(location); - - DO_IT_NOW(_glEnableVertexAttribArray, 1); -} -void GLBackend::do_glEnableVertexAttribArray(Batch& batch, uint32 paramOffset) { - glEnableVertexAttribArray(batch._params[paramOffset]._uint); - (void) CHECK_GL_ERROR(); -} - -void Batch::_glDisableVertexAttribArray(GLint location) { - ADD_COMMAND_GL(glDisableVertexAttribArray); - - _params.push_back(location); - - DO_IT_NOW(_glDisableVertexAttribArray, 1); -} -void GLBackend::do_glDisableVertexAttribArray(Batch& batch, uint32 paramOffset) { - glDisableVertexAttribArray(batch._params[paramOffset]._uint); - (void) CHECK_GL_ERROR(); -} - void Batch::_glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { ADD_COMMAND_GL(glColor4f); diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 59a6c1ee7e..843e5d2006 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -426,28 +426,8 @@ protected: // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long // term strategy is to get rid of any GL calls in favor of the HIFI GPU API - void do_glEnable(Batch& batch, uint32 paramOffset); - void do_glDisable(Batch& batch, uint32 paramOffset); + void do_glActiveBindTexture(Batch& batch, uint32 paramOffset); - void do_glEnableClientState(Batch& batch, uint32 paramOffset); - void do_glDisableClientState(Batch& batch, uint32 paramOffset); - - void do_glCullFace(Batch& batch, uint32 paramOffset); - void do_glAlphaFunc(Batch& batch, uint32 paramOffset); - - void do_glDepthFunc(Batch& batch, uint32 paramOffset); - void do_glDepthMask(Batch& batch, uint32 paramOffset); - void do_glDepthRange(Batch& batch, uint32 paramOffset); - - void do_glBindBuffer(Batch& batch, uint32 paramOffset); - - void do_glBindTexture(Batch& batch, uint32 paramOffset); - void do_glActiveTexture(Batch& batch, uint32 paramOffset); - void do_glTexParameteri(Batch& batch, uint32 paramOffset); - - void do_glDrawBuffers(Batch& batch, uint32 paramOffset); - - void do_glUseProgram(Batch& batch, uint32 paramOffset); void do_glUniform1i(Batch& batch, uint32 paramOffset); void do_glUniform1f(Batch& batch, uint32 paramOffset); void do_glUniform2f(Batch& batch, uint32 paramOffset); @@ -457,9 +437,6 @@ protected: void do_glUniform4iv(Batch& batch, uint32 paramOffset); void do_glUniformMatrix4fv(Batch& batch, uint32 paramOffset); - void do_glEnableVertexAttribArray(Batch& batch, uint32 paramOffset); - void do_glDisableVertexAttribArray(Batch& batch, uint32 paramOffset); - void do_glColor4f(Batch& batch, uint32 paramOffset); void do_glLineWidth(Batch& batch, uint32 paramOffset); diff --git a/libraries/gpu/src/gpu/GLBackendOutput.cpp b/libraries/gpu/src/gpu/GLBackendOutput.cpp index 6b0bfae635..d57ef57d78 100755 --- a/libraries/gpu/src/gpu/GLBackendOutput.cpp +++ b/libraries/gpu/src/gpu/GLBackendOutput.cpp @@ -178,9 +178,11 @@ void GLBackend::syncOutputStateCache() { } void GLBackend::resetOutputStage() { - _output._framebuffer.reset(); - _output._drawFBO = 0; - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + if (_output._framebuffer) { + _output._framebuffer.reset(); + _output._drawFBO = 0; + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + } } void GLBackend::do_setFramebuffer(Batch& batch, uint32 paramOffset) { diff --git a/libraries/gpu/src/gpu/GLBackendState.cpp b/libraries/gpu/src/gpu/GLBackendState.cpp index 618a13e2c4..bd683e0136 100644 --- a/libraries/gpu/src/gpu/GLBackendState.cpp +++ b/libraries/gpu/src/gpu/GLBackendState.cpp @@ -482,6 +482,11 @@ void GLBackend::syncPipelineStateCache() { State::Data state; glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + + // Point size is always on + glEnable(GL_PROGRAM_POINT_SIZE_EXT); + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + getCurrentGLState(state); State::Signature signature = State::evalSignature(state); From 66c5aec744273781b735c10b5d625d761d3b95b5 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 27 Jul 2015 17:34:46 -0700 Subject: [PATCH 15/74] Remove commented dead code --- interface/src/Stars.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/interface/src/Stars.cpp b/interface/src/Stars.cpp index 7d09b9b1c3..c1e65086bf 100644 --- a/interface/src/Stars.cpp +++ b/interface/src/Stars.cpp @@ -218,10 +218,6 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { // Render the stars batch.setPipeline(_starsPipeline); - /* batch._glEnable(GL_PROGRAM_POINT_SIZE_EXT); - batch._glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); - batch._glEnable(GL_POINT_SMOOTH); - */ batch.setInputFormat(streamFormat); batch.setInputBuffer(VERTICES_SLOT, posView); batch.setInputBuffer(COLOR_SLOT, colView); From 81e80996f791ef40a4d701ea38842d91a2be4377 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 28 Jul 2015 11:24:33 -0700 Subject: [PATCH 16/74] Fix large marketplace imports not working --- examples/edit.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index ec3106e585..a07779c19d 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -1064,7 +1064,7 @@ function importSVO(importURL) { if (success) { var VERY_LARGE = 10000; - var position = { x: 0, y: 0, z: 0}; + var position = { x: 0.01, y: 0.01, z: 0.01}; if (Clipboard.getClipboardContentsLargestDimension() < VERY_LARGE) { position = getPositionToCreateEntity(); } @@ -1074,7 +1074,7 @@ function importSVO(importURL) { if (isActive) { selectionManager.setSelections(pastedEntityIDs); } - Window.raiseMainWindow(); + Window.raiseMainWindow(); } else { Window.alert("Can't import objects: objects would be out of bounds."); } From 2aa453b6102f0fb092283a5644498fcf7c355aeb Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 28 Jul 2015 12:05:45 -0700 Subject: [PATCH 17/74] fix build errors for shared-tests --- tests/shared/src/AngularConstraintTests.cpp | 1 + tests/shared/src/AngularConstraintTests.h | 7 ++----- tests/shared/src/MovingPercentileTests.cpp | 1 + tests/shared/src/MovingPercentileTests.h | 1 - tests/shared/src/TransformTests.cpp | 4 +++- tests/shared/src/TransformTests.h | 2 -- 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/tests/shared/src/AngularConstraintTests.cpp b/tests/shared/src/AngularConstraintTests.cpp index 95c5db18c2..4dcf3d7296 100644 --- a/tests/shared/src/AngularConstraintTests.cpp +++ b/tests/shared/src/AngularConstraintTests.cpp @@ -16,6 +16,7 @@ #include #include "AngularConstraintTests.h" +#include "../QTestExtensions.h" // Computes the error value between two quaternions (using glm::dot) float getErrorDifference(const glm::quat& a, const glm::quat& b) { diff --git a/tests/shared/src/AngularConstraintTests.h b/tests/shared/src/AngularConstraintTests.h index df2fe8e9c3..705639b571 100644 --- a/tests/shared/src/AngularConstraintTests.h +++ b/tests/shared/src/AngularConstraintTests.h @@ -12,6 +12,7 @@ #ifndef hifi_AngularConstraintTests_h #define hifi_AngularConstraintTests_h +#include #include class AngularConstraintTests : public QObject { @@ -21,10 +22,6 @@ private slots: void testConeRollerConstraint(); }; -// Use QCOMPARE_WITH_ABS_ERROR and define it for glm::quat -#include -float getErrorDifference (const glm::quat& a, const glm::quat& b); -QTextStream & operator << (QTextStream& stream, const glm::quat& q); -#include "../QTestExtensions.h" +float getErrorDifference(const glm::quat& a, const glm::quat& b); #endif // hifi_AngularConstraintTests_h diff --git a/tests/shared/src/MovingPercentileTests.cpp b/tests/shared/src/MovingPercentileTests.cpp index b9593fca83..fbbc3c7b9e 100644 --- a/tests/shared/src/MovingPercentileTests.cpp +++ b/tests/shared/src/MovingPercentileTests.cpp @@ -16,6 +16,7 @@ #include #include +#include <../QTestExtensions.h> QTEST_MAIN(MovingPercentileTests) diff --git a/tests/shared/src/MovingPercentileTests.h b/tests/shared/src/MovingPercentileTests.h index 4a1d4b33d2..ffc8ddb0f6 100644 --- a/tests/shared/src/MovingPercentileTests.h +++ b/tests/shared/src/MovingPercentileTests.h @@ -13,7 +13,6 @@ #define hifi_MovingPercentileTests_h #include -#include <../QTestExtensions.h> class MovingPercentileTests : public QObject { Q_OBJECT diff --git a/tests/shared/src/TransformTests.cpp b/tests/shared/src/TransformTests.cpp index 93b0583aa6..be22914b9d 100644 --- a/tests/shared/src/TransformTests.cpp +++ b/tests/shared/src/TransformTests.cpp @@ -8,10 +8,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "TransformTests.h" + #include -#include "TransformTests.h" #include "SharedLogging.h" +#include <../QTestExtensions.h> using namespace glm; diff --git a/tests/shared/src/TransformTests.h b/tests/shared/src/TransformTests.h index ab5c8cf144..a4d9b2a6c0 100644 --- a/tests/shared/src/TransformTests.h +++ b/tests/shared/src/TransformTests.h @@ -40,8 +40,6 @@ inline QTextStream& operator<< (QTextStream& stream, const glm::mat4& matrix) { return stream; } -#include <../QTestExtensions.h> - class TransformTests : public QObject { Q_OBJECT private slots: From d03a7d1b701d0459468ac7d4afe908d973957707 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 28 Jul 2015 12:24:17 -0700 Subject: [PATCH 18/74] fix physics-tests build errors --- tests/physics/src/BulletUtilTests.cpp | 7 +- tests/physics/src/BulletUtilTests.h | 3 - tests/physics/src/CollisionInfoTests.cpp | 70 ------------------- tests/physics/src/CollisionInfoTests.h | 29 -------- tests/physics/src/MeshMassPropertiesTests.cpp | 8 ++- tests/physics/src/MeshMassPropertiesTests.h | 6 -- tests/physics/src/ShapeColliderTests.cpp | 14 ++-- tests/physics/src/ShapeColliderTests.h | 7 -- 8 files changed, 18 insertions(+), 126 deletions(-) delete mode 100644 tests/physics/src/CollisionInfoTests.cpp delete mode 100644 tests/physics/src/CollisionInfoTests.h diff --git a/tests/physics/src/BulletUtilTests.cpp b/tests/physics/src/BulletUtilTests.cpp index bbd88f88b7..181d22327e 100644 --- a/tests/physics/src/BulletUtilTests.cpp +++ b/tests/physics/src/BulletUtilTests.cpp @@ -9,13 +9,16 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "BulletUtilTests.h" + #include -//#include "PhysicsTestUtil.h" #include #include -#include "BulletUtilTests.h" +// Add additional qtest functionality (the include order is important!) +#include "GlmTestUtils.h" +#include "../QTestExtensions.h" // Constants const glm::vec3 origin(0.0f); diff --git a/tests/physics/src/BulletUtilTests.h b/tests/physics/src/BulletUtilTests.h index fd4fe13d09..e8fee1e473 100644 --- a/tests/physics/src/BulletUtilTests.h +++ b/tests/physics/src/BulletUtilTests.h @@ -13,9 +13,6 @@ #define hifi_BulletUtilTests_h #include -// Add additional qtest functionality (the include order is important!) -#include "GlmTestUtils.h" -#include "../QTestExtensions.h" class BulletUtilTests : public QObject { Q_OBJECT diff --git a/tests/physics/src/CollisionInfoTests.cpp b/tests/physics/src/CollisionInfoTests.cpp deleted file mode 100644 index 70e2e14bb0..0000000000 --- a/tests/physics/src/CollisionInfoTests.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// -// CollisionInfoTests.cpp -// tests/physics/src -// -// Created by Andrew Meadows on 2/21/2014. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include - -#include -#include - -#include -#include -#include - -#include "CollisionInfoTests.h" - - - -QTEST_MAIN(CollisionInfoTests) -/* -static glm::vec3 xAxis(1.0f, 0.0f, 0.0f); -static glm::vec3 xZxis(0.0f, 1.0f, 0.0f); -static glm::vec3 xYxis(0.0f, 0.0f, 1.0f); - -void CollisionInfoTests::rotateThenTranslate() { - CollisionInfo collision; - collision._penetration = xAxis; - collision._contactPoint = xYxis; - collision._addedVelocity = xAxis + xYxis + xZxis; - - glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis); - float distance = 3.0f; - glm::vec3 translation = distance * xYxis; - - collision.rotateThenTranslate(rotation, translation); - QCOMPARE(collision._penetration, xYxis); - - glm::vec3 expectedContactPoint = -xAxis + translation; - QCOMPARE(collision._contactPoint, expectedContactPoint); - - glm::vec3 expectedAddedVelocity = xYxis - xAxis + xZxis; - QCOMPARE(collision._addedVelocity, expectedAddedVelocity); -} - -void CollisionInfoTests::translateThenRotate() { - CollisionInfo collision; - collision._penetration = xAxis; - collision._contactPoint = xYxis; - collision._addedVelocity = xAxis + xYxis + xZxis; - - glm::quat rotation = glm::angleAxis( -PI_OVER_TWO, zAxis); - float distance = 3.0f; - glm::vec3 translation = distance * xYxis; - - collision.translateThenRotate(translation, rotation); - QCOMPARE(collision._penetration, -xYxis); - - glm::vec3 expectedContactPoint = (1.0f + distance) * xAxis; - QCOMPARE(collision._contactPoint, expectedContactPoint); - - glm::vec3 expectedAddedVelocity = - xYxis + xAxis + xYxis; - QCOMPARE(collision._addedVelocity, expectedAddedVelocity); -}*/ - diff --git a/tests/physics/src/CollisionInfoTests.h b/tests/physics/src/CollisionInfoTests.h deleted file mode 100644 index d26d39be4b..0000000000 --- a/tests/physics/src/CollisionInfoTests.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// CollisionInfoTests.h -// tests/physics/src -// -// Created by Andrew Meadows on 2/21/2014. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_CollisionInfoTests_h -#define hifi_CollisionInfoTests_h - -#include - -// Add additional qtest functionality (the include order is important!) -#include "GlmTestUtils.h" -#include "../QTestExtensions.h" - -class CollisionInfoTests : public QObject { - Q_OBJECT - -private slots: -// void rotateThenTranslate(); -// void translateThenRotate(); -}; - -#endif // hifi_CollisionInfoTests_h diff --git a/tests/physics/src/MeshMassPropertiesTests.cpp b/tests/physics/src/MeshMassPropertiesTests.cpp index 794eee0fcf..e88bcae1b7 100644 --- a/tests/physics/src/MeshMassPropertiesTests.cpp +++ b/tests/physics/src/MeshMassPropertiesTests.cpp @@ -9,11 +9,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "MeshMassPropertiesTests.h" + #include -#include #include -#include "MeshMassPropertiesTests.h" +// Add additional qtest functionality (the include order is important!) +#include "BulletTestUtils.h" +#include "GlmTestUtils.h" +#include "../QTestExtensions.h" const btScalar acceptableRelativeError(1.0e-5f); const btScalar acceptableAbsoluteError(1.0e-4f); diff --git a/tests/physics/src/MeshMassPropertiesTests.h b/tests/physics/src/MeshMassPropertiesTests.h index 35471bdbad..b8af9d9db6 100644 --- a/tests/physics/src/MeshMassPropertiesTests.h +++ b/tests/physics/src/MeshMassPropertiesTests.h @@ -13,12 +13,6 @@ #define hifi_MeshMassPropertiesTests_h #include -#include - -// Add additional qtest functionality (the include order is important!) -#include "BulletTestUtils.h" -#include "GlmTestUtils.h" -#include "../QTestExtensions.h" // Relative error macro (see errorTest in BulletTestUtils.h) #define QCOMPARE_WITH_RELATIVE_ERROR(actual, expected, relativeError) \ diff --git a/tests/physics/src/ShapeColliderTests.cpp b/tests/physics/src/ShapeColliderTests.cpp index cb42f534cb..cb51e18fbd 100644 --- a/tests/physics/src/ShapeColliderTests.cpp +++ b/tests/physics/src/ShapeColliderTests.cpp @@ -9,12 +9,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ShapeColliderTests.h" + //#include #include #include #include #include +#include #include #include @@ -25,7 +28,10 @@ #include #include -#include "ShapeColliderTests.h" +// Add additional qtest functionality (the include order is important!) +#include "BulletTestUtils.h" +#include "GlmTestUtils.h" +#include "../QTestExtensions.h" const glm::vec3 origin(0.0f); @@ -1553,8 +1559,6 @@ void ShapeColliderTests::rayHitsCapsule() { intersection._rayDirection = - xAxis; QCOMPARE(capsule.findRayIntersection(intersection), true); float expectedDistance = startDistance - radius * sqrtf(2.0f * delta); // using small angle approximation of cosine -// float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; - // for edge cases we allow a LOT of error QCOMPARE_WITH_ABS_ERROR(intersection._hitDistance, expectedDistance, startDistance * EDGE_CASE_SLOP_FACTOR * EPSILON); } @@ -1564,8 +1568,6 @@ void ShapeColliderTests::rayHitsCapsule() { intersection._rayDirection = - xAxis; QCOMPARE(capsule.findRayIntersection(intersection), true); float expectedDistance = startDistance - radius * sqrtf(2.0f * delta); // using small angle approximation of cosine -// float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; - // for edge cases we allow a LOT of error QCOMPARE_WITH_ABS_ERROR(intersection._hitDistance, expectedDistance, startDistance * EPSILON * EDGE_CASE_SLOP_FACTOR); } @@ -1575,8 +1577,6 @@ void ShapeColliderTests::rayHitsCapsule() { intersection._rayDirection = - xAxis; QCOMPARE(capsule.findRayIntersection(intersection), true); float expectedDistance = startDistance - radius * sqrtf(2.0f * delta); // using small angle approximation of cosine - float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; - // for edge cases we allow a LOT of error QCOMPARE_WITH_ABS_ERROR(intersection._hitDistance, expectedDistance, startDistance * EPSILON * EDGE_CASE_SLOP_FACTOR); } // TODO: test at steep angles near cylinder/cap junction diff --git a/tests/physics/src/ShapeColliderTests.h b/tests/physics/src/ShapeColliderTests.h index 48d9cbd742..73e2b972a9 100644 --- a/tests/physics/src/ShapeColliderTests.h +++ b/tests/physics/src/ShapeColliderTests.h @@ -13,13 +13,6 @@ #define hifi_ShapeColliderTests_h #include -#include - -// Add additional qtest functionality (the include order is important!) -#include "BulletTestUtils.h" -#include "GlmTestUtils.h" -#include "../QTestExtensions.h" - class ShapeColliderTests : public QObject { Q_OBJECT From b46ad0c39780d475de0ed90d2b84029e2616ca96 Mon Sep 17 00:00:00 2001 From: bwent Date: Wed, 15 Jul 2015 11:50:10 -0700 Subject: [PATCH 19/74] Created subpanel panel item --- examples/utilities/tools/cookies.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 0fdae01c5e..8b4d739c02 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -416,6 +416,8 @@ DirectionBox = function(x,y,width,thumbSize) { this.onValueChanged = function(value) {}; } + + var textFontSize = 12; function PanelItem(name, setter, getter, displayer, x, y, textWidth, valueWidth, height) { @@ -429,7 +431,7 @@ function PanelItem(name, setter, getter, displayer, x, y, textWidth, valueWidth, } else if (value == false) { return "Off"; } - return value.toFixed(2); + return value; }; var topMargin = (height - textFontSize); @@ -616,7 +618,7 @@ Panel = function(x, y) { // print("created Item... colorBox=" + name); }; - this.newDirectionBox= function(name, setValue, getValue, displayValue) { + this.newDirectionBox = function(name, setValue, getValue, displayValue) { var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); @@ -630,6 +632,20 @@ Panel = function(x, y) { // print("created Item... directionBox=" + name); }; + this.newSubPanel = function(name) { + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); + + var panel = new Panel(this.widgetX, this.nextY); + + item.widget = panel; + + item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; + + this.nextY += rawYDelta; + + }; + + this.destroy = function() { for (var i in this.items) { this.items[i].destroy(); From 4ae03184ecfcab1377b9ac7911f792a9b34a0061 Mon Sep 17 00:00:00 2001 From: bwent Date: Tue, 21 Jul 2015 10:23:41 -0700 Subject: [PATCH 20/74] add subpanel functionality --- examples/utilities/tools/cookies.js | 242 +++++++++++++++++++++++++--- 1 file changed, 223 insertions(+), 19 deletions(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 8b4d739c02..2949626252 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -92,7 +92,6 @@ Slider = function(x,y,width,thumbSize) { this.isMoving = false; }; - // Public members: this.setNormalizedValue = function(value) { if (value < 0.0) { @@ -113,10 +112,19 @@ Slider = function(x,y,width,thumbSize) { this.setNormalizedValue(normValue); }; + this.reset = function(resetValue) { + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; + this.getValue = function() { return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; }; + this.getHeight = function() { + return 1.5 * this.thumbSize; + } + this.onValueChanged = function(value) {}; this.destroy = function() { @@ -130,6 +138,7 @@ Slider = function(x,y,width,thumbSize) { this.setBackgroundColor = function(color) { Overlays.editOverlay(this.background, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); }; + } // The Checkbox class @@ -158,10 +167,12 @@ Checkbox = function(x,y,width,thumbSize) { visible: true }); - + this.thumbSize = thumbSize; var checkX = x + (0.25 * thumbSize); var checkY = y + (0.25 * thumbSize); + var boxCheckStatus; + var clickedBox = false; var checkMark = Overlays.addOverlay("text", { @@ -181,22 +192,22 @@ Checkbox = function(x,y,width,thumbSize) { width: thumbSize / 2.5, height: thumbSize / 2.5, alpha: 1.0, - visible: boxCheckStatus + visible: !boxCheckStatus }); - - var boxCheckStatus; - var clickedBox = false; - this.updateThumb = function() { - if (clickedBox) { - boxCheckStatus = !boxCheckStatus; - if (boxCheckStatus) { - Overlays.editOverlay(unCheckMark, { visible: false }); - } else { - Overlays.editOverlay(unCheckMark, { visible: true }); - } + this.updateThumb = function() { + if(!clickedBox) { + return; + } + + boxCheckStatus = !boxCheckStatus; + if (boxCheckStatus) { + Overlays.editOverlay(unCheckMark, { visible: false }); + } else { + Overlays.editOverlay(unCheckMark, { visible: true }); } + }; this.isClickableOverlayItem = function(item) { @@ -215,10 +226,12 @@ Checkbox = function(x,y,width,thumbSize) { this.onValueChanged(this.getValue()); }; + this.onMouseReleaseEvent = function(event) { this.clickedBox = false; }; + // Public members: this.setNormalizedValue = function(value) { boxCheckStatus = value; @@ -232,10 +245,26 @@ Checkbox = function(x,y,width,thumbSize) { this.setNormalizedValue(value); }; + this.reset = function(resetValue) { + this.setValue(resetValue); + + this.onValueChanged(resetValue); + }; + this.getValue = function() { return boxCheckStatus; }; + this.getHeight = function() { + return 1.5 * this.thumbSize; + } + + this.setterFromWidget = function(value) { + var status = boxCheckStatus; + this.onValueChanged(boxCheckStatus); + this.updateThumb(); + }; + this.onValueChanged = function(value) {}; this.destroy = function() { @@ -267,6 +296,8 @@ ColorBox = function(x,y,width,thumbSize) { this.green.setBackgroundColor({x: 0, y: 1, z: 0}); this.blue.setBackgroundColor({x: 0, y: 0, z: 1}); + + this.isClickableOverlayItem = function(item) { return this.red.isClickableOverlayItem(item) || this.green.isClickableOverlayItem(item) @@ -293,6 +324,7 @@ ColorBox = function(x,y,width,thumbSize) { this.blue.onMousePressEvent(event, clickedOverlay); }; + this.onMouseReleaseEvent = function(event) { this.red.onMouseReleaseEvent(event); this.green.onMouseReleaseEvent(event); @@ -323,11 +355,20 @@ ColorBox = function(x,y,width,thumbSize) { this.updateRGBSliders(value); }; + this.reset = function(resetValue) { + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; + this.getValue = function() { var value = {x:this.red.getValue(), y:this.green.getValue(),z:this.blue.getValue()}; return value; }; + this.getHeight = function() { + return 1.5 * this.thumbSize; + } + this.destroy = function() { this.red.destroy(); this.green.destroy(); @@ -345,6 +386,8 @@ DirectionBox = function(x,y,width,thumbSize) { var sliderWidth = width; this.yaw = new Slider(x, y, width, slideHeight); this.pitch = new Slider(x, y + slideHeight, width, slideHeight); + + this.yaw.setThumbColor({x: 1, y: 0, z: 0}); this.yaw.minValue = -180; @@ -400,6 +443,11 @@ DirectionBox = function(x,y,width,thumbSize) { this.pitch.setValue(direction.y); }; + this.reset = function(resetValue) { + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; + this.getValue = function() { var dirZ = this.pitch.getValue(); var yaw = this.yaw.getValue() * Math.PI / 180; @@ -408,6 +456,10 @@ DirectionBox = function(x,y,width,thumbSize) { return value; }; + this.getHeight = function() { + return 1.5 * this.thumbSize; + } + this.destroy = function() { this.yaw.destroy(); this.pitch.destroy(); @@ -420,6 +472,48 @@ DirectionBox = function(x,y,width,thumbSize) { var textFontSize = 12; +// TODO: Make collapsable +function CollapsablePanelItem(name, x, y, textWidth, height) { + this.name = name; + this.height = height; + + var topMargin = (height - textFontSize); + + this.thumb = Overlays.addOverlay("text", { + backgroundColor: { red: 220, green: 220, blue: 220 }, + textFontSize: 10, + x: x, + y: y, + width: rawHeight, + height: rawHeight, + alpha: 1.0, + backgroundAlpha: 1.0, + visible: true + }); + + this.title = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: x + rawHeight, + y: y, + width: textWidth, + height: height, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true, + text: name, + font: {size: textFontSize}, + topMargin: topMargin, + }); + + this.destroy = function() { + Overlays.deleteOverlay(this.title); + Overlays.deleteOverlay(this.thumb); + if (this.widget != null) { + this.widget.destroy(); + } + } +} + function PanelItem(name, setter, getter, displayer, x, y, textWidth, valueWidth, height) { //print("creating panel item: " + name); @@ -548,15 +642,18 @@ Panel = function(x, y) { // Reset panel item upon double-clicking this.mouseDoublePressEvent = function(event) { + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); for (var i in this.items) { var item = this.items[i]; var widget = item.widget; - if (item.title == clickedOverlay || item.value == clickedOverlay) { - widget.updateThumb(); - widget.onValueChanged(item.resetValue); + if (clickedOverlay == item.title) { + item.activeWidget = widget; + + item.activeWidget.reset(item.resetValue); + break; } } @@ -569,8 +666,56 @@ Panel = function(x, y) { this.activeWidget = null; }; - this.newSlider = function(name, minValue, maxValue, setValue, getValue, displayValue) { + this.onMousePressEvent = function(event, clickedOverlay) { + for (var i in this.items) { + var item = this.items[i]; + if(item.widget.isClickableOverlayItem(clickedOverlay)) { + item.activeWidget = item.widget; + item.activeWidget.onMousePressEvent(event,clickedOverlay); + } + } + } + this.reset = function() { + for (var i in this.items) { + var item = this.items[i]; + if (item.activeWidget) { + item.activeWidget.reset(item.resetValue); + } + } + } + + this.onMouseMoveEvent = function(event) { + for (var i in this.items) { + var item = this.items[i]; + if (item.activeWidget) { + item.activeWidget.onMouseMoveEvent(event); + } + } + } + + this.onMouseReleaseEvent = function(event, clickedOverlay) { + for (var i in this.items) { + var item = this.items[i]; + if (item.activeWidget) { + item.activeWidget.onMouseReleaseEvent(event); + } + item.activeWidget = null; + } + } + + this.onMouseDoublePressEvent = function(event, clickedOverlay) { + + for (var i in this.items) { + var item = this.items[i]; + if (item.activeWidget) { + item.activeWidget.onMouseDoublePressEvent(event); + } + } + } + + this.newSlider = function(name, minValue, maxValue, setValue, getValue, displayValue) { + this.nextY = this.y + this.getHeight(); var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); var slider = new Slider(this.widgetX, this.nextY, widgetWidth, rawHeight); @@ -591,6 +736,8 @@ Panel = function(x, y) { } else if (displayValue == false) { display = function() {return "Off";}; } + + this.nextY = this.y + this.getHeight(); var item = new PanelItem(name, setValue, getValue, display, this.x, this.nextY, textWidth, valueWidth, rawHeight); @@ -600,11 +747,12 @@ Panel = function(x, y) { item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; item.setter(getValue()); this.items[name] = item; - this.nextY += rawYDelta; + //print("created Item... checkbox=" + name); }; this.newColorBox = function(name, setValue, getValue, displayValue) { + this.nextY = this.y + this.getHeight(); var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); @@ -618,7 +766,12 @@ Panel = function(x, y) { // print("created Item... colorBox=" + name); }; +<<<<<<< Updated upstream this.newDirectionBox = function(name, setValue, getValue, displayValue) { +======= + this.newDirectionBox= function(name, setValue, getValue, displayValue) { + this.nextY = this.y + this.getHeight(); +>>>>>>> Stashed changes var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); @@ -632,6 +785,7 @@ Panel = function(x, y) { // print("created Item... directionBox=" + name); }; +<<<<<<< Updated upstream this.newSubPanel = function(name) { var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); @@ -645,6 +799,32 @@ Panel = function(x, y) { }; +======= + var indentation = 30; + + this.newSubPanel = function(name) { + //TODO: make collapsable, fix double-press event + this.nextY = this.y + this.getHeight(); + + var item = new CollapsablePanelItem(name, this.x, this.nextY, textWidth, rawHeight, panel); + item.isSubPanel = true; + + this.nextY += 1.5 * item.height; + + var subPanel = new Panel(this.x + indentation, this.nextY); + + item.widget = subPanel; + this.items[name] = item; + return subPanel; + // print("created Item... subPanel=" + name); + }; + + this.onValueChanged = function(value) { + for (var i in this.items) { + this.items[i].widget.onValueChanged(value); + } + } +>>>>>>> Stashed changes this.destroy = function() { for (var i in this.items) { @@ -652,6 +832,7 @@ Panel = function(x, y) { } } + this.set = function(name, value) { var item = this.items[name]; if (item != null) { @@ -676,6 +857,29 @@ Panel = function(x, y) { return null; } + this.isClickableOverlayItem = function(item) { + for (var i in this.items) { + if (this.items[i].widget.isClickableOverlayItem(item)) { + return true; + } + } + return false; + } + + this.getHeight = function() { + var height = 0; + + for (var i in this.items) { + height += this.items[i].widget.getHeight(); + if(this.items[i].isSubPanel) { + height += 1.5 * rawHeight; + } + } + + + return height; + } + }; From 252780dc5dcebb32866c9b151adcda2f014df260 Mon Sep 17 00:00:00 2001 From: bwent Date: Mon, 27 Jul 2015 13:44:01 -0700 Subject: [PATCH 21/74] fix checkbox class, make subpanels collapsable --- examples/utilities/tools/cookies.js | 1669 ++++++++++++++++----------- 1 file changed, 983 insertions(+), 686 deletions(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 2949626252..9d064385bf 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -10,663 +10,925 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // // The Slider class -Slider = function(x,y,width,thumbSize) { - this.background = Overlays.addOverlay("text", { - backgroundColor: { red: 200, green: 200, blue: 255 }, - x: x, - y: y, - width: width, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true - }); - this.thumb = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: x, - y: y, - width: thumbSize, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 1.0, - visible: true - }); - - - this.thumbSize = thumbSize; - this.thumbHalfSize = 0.5 * thumbSize; - - this.minThumbX = x + this.thumbHalfSize; - this.maxThumbX = x + width - this.thumbHalfSize; - this.thumbX = this.minThumbX; - - this.minValue = 0.0; - this.maxValue = 1.0; - - this.clickOffsetX = 0; - this.isMoving = false; - - this.updateThumb = function() { - thumbTruePos = this.thumbX - 0.5 * this.thumbSize; - Overlays.editOverlay(this.thumb, { x: thumbTruePos } ); - }; - - this.isClickableOverlayItem = function(item) { - return (item == this.thumb) || (item == this.background); - }; - - this.onMouseMoveEvent = function(event) { - if (this.isMoving) { - newThumbX = event.x - this.clickOffsetX; - if (newThumbX < this.minThumbX) { - newThumbX = this.minThumbX; - } - if (newThumbX > this.maxThumbX) { - newThumbX = this.maxThumbX; - } - this.thumbX = newThumbX; - this.updateThumb(); - this.onValueChanged(this.getValue()); - } - }; - - this.onMousePressEvent = function(event, clickedOverlay) { - if (!this.isClickableOverlayItem(clickedOverlay)) { - this.isMoving = false; - return; - } - this.isMoving = true; - var clickOffset = event.x - this.thumbX; - if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { - this.clickOffsetX = clickOffset; - } else { - this.clickOffsetX = 0; - this.thumbX = event.x; - this.updateThumb(); - this.onValueChanged(this.getValue()); - } - - }; - - this.onMouseReleaseEvent = function(event) { - this.isMoving = false; - }; - - // Public members: - this.setNormalizedValue = function(value) { - if (value < 0.0) { - this.thumbX = this.minThumbX; - } else if (value > 1.0) { - this.thumbX = this.maxThumbX; - } else { - this.thumbX = value * (this.maxThumbX - this.minThumbX) + this.minThumbX; - } - this.updateThumb(); - }; - this.getNormalizedValue = function() { - return (this.thumbX - this.minThumbX) / (this.maxThumbX - this.minThumbX); - }; - - this.setValue = function(value) { - var normValue = (value - this.minValue) / (this.maxValue - this.minValue); - this.setNormalizedValue(normValue); - }; - - this.reset = function(resetValue) { - this.setValue(resetValue); - this.onValueChanged(resetValue); - }; - - this.getValue = function() { - return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; - }; - - this.getHeight = function() { - return 1.5 * this.thumbSize; - } - - this.onValueChanged = function(value) {}; - - this.destroy = function() { - Overlays.deleteOverlay(this.background); - Overlays.deleteOverlay(this.thumb); - }; - - this.setThumbColor = function(color) { - Overlays.editOverlay(this.thumb, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); - }; - this.setBackgroundColor = function(color) { - Overlays.editOverlay(this.background, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); - }; - -} - -// The Checkbox class -Checkbox = function(x,y,width,thumbSize) { - - this.background = Overlays.addOverlay("text", { - backgroundColor: { red: 125, green: 125, blue: 255 }, - x: x, - y: y, - width: width, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true - }); - - this.thumb = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - textFontSize: 10, - x: x, - y: y, - width: thumbSize, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 1.0, - visible: true - }); - - - this.thumbSize = thumbSize; - var checkX = x + (0.25 * thumbSize); - var checkY = y + (0.25 * thumbSize); - var boxCheckStatus; - var clickedBox = false; - - - var checkMark = Overlays.addOverlay("text", { - backgroundColor: { red: 0, green: 255, blue: 0 }, - x: checkX, - y: checkY, - width: thumbSize / 2.0, - height: thumbSize / 2.0, - alpha: 1.0, - visible: true - }); - - var unCheckMark = Overlays.addOverlay("image", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: checkX + 1.0, - y: checkY + 1.0, - width: thumbSize / 2.5, - height: thumbSize / 2.5, - alpha: 1.0, - visible: !boxCheckStatus - }); - - - this.updateThumb = function() { - if(!clickedBox) { - return; - } +(function () { + var Slider = function(x,y,width,thumbSize) { - boxCheckStatus = !boxCheckStatus; - if (boxCheckStatus) { - Overlays.editOverlay(unCheckMark, { visible: false }); - } else { - Overlays.editOverlay(unCheckMark, { visible: true }); - } + this.background = Overlays.addOverlay("text", { + backgroundColor: { red: 200, green: 200, blue: 255 }, + x: x, + y: y, + width: width, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true + }); + this.thumb = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: x, + y: y, + width: thumbSize, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 1.0, + visible: true + }); + + this.thumbSize = thumbSize; - }; + this.thumbHalfSize = 0.5 * thumbSize; + + this.minThumbX = x + this.thumbHalfSize; + this.maxThumbX = x + width - this.thumbHalfSize; + this.thumbX = this.minThumbX; + + this.minValue = 0.0; + this.maxValue = 1.0; - this.isClickableOverlayItem = function(item) { - return (item == this.thumb) || (item == checkMark) || (item == unCheckMark); + this.y = y; + + this.clickOffsetX = 0; + this.isMoving = false; + this.visible = true; }; - this.onMousePressEvent = function(event, clickedOverlay) { - if (!this.isClickableOverlayItem(clickedOverlay)) { - this.isMoving = false; - clickedBox = false; - return; - } - - clickedBox = true; - this.updateThumb(); - this.onValueChanged(this.getValue()); - }; - - - this.onMouseReleaseEvent = function(event) { - this.clickedBox = false; - }; - - - // Public members: - this.setNormalizedValue = function(value) { - boxCheckStatus = value; - }; - - this.getNormalizedValue = function() { - return boxCheckStatus; - }; - - this.setValue = function(value) { - this.setNormalizedValue(value); - }; - - this.reset = function(resetValue) { - this.setValue(resetValue); - - this.onValueChanged(resetValue); - }; - - this.getValue = function() { - return boxCheckStatus; - }; - - this.getHeight = function() { - return 1.5 * this.thumbSize; - } - - this.setterFromWidget = function(value) { - var status = boxCheckStatus; - this.onValueChanged(boxCheckStatus); - this.updateThumb(); - }; - - this.onValueChanged = function(value) {}; - - this.destroy = function() { - Overlays.deleteOverlay(this.background); - Overlays.deleteOverlay(this.thumb); - Overlays.deleteOverlay(checkMark); - Overlays.deleteOverlay(unCheckMark); - }; - - this.setThumbColor = function(color) { - Overlays.editOverlay(this.thumb, { red: 255, green: 255, blue: 255 } ); - }; - this.setBackgroundColor = function(color) { - Overlays.editOverlay(this.background, { red: 125, green: 125, blue: 255 }); - }; - -} - -// The ColorBox class -ColorBox = function(x,y,width,thumbSize) { - var self = this; + Slider.prototype.updateThumb = function() { + var thumbTruePos = this.thumbX - 0.5 * this.thumbSize; + Overlays.editOverlay(this.thumb, { x: thumbTruePos } ); + }; - var slideHeight = thumbSize / 3; - var sliderWidth = width; - this.red = new Slider(x, y, width, slideHeight); - this.green = new Slider(x, y + slideHeight, width, slideHeight); - this.blue = new Slider(x, y + 2 * slideHeight, width, slideHeight); - this.red.setBackgroundColor({x: 1, y: 0, z: 0}); - this.green.setBackgroundColor({x: 0, y: 1, z: 0}); - this.blue.setBackgroundColor({x: 0, y: 0, z: 1}); - - - - this.isClickableOverlayItem = function(item) { - return this.red.isClickableOverlayItem(item) - || this.green.isClickableOverlayItem(item) - || this.blue.isClickableOverlayItem(item); - }; - - this.onMouseMoveEvent = function(event) { - this.red.onMouseMoveEvent(event); - this.green.onMouseMoveEvent(event); - this.blue.onMouseMoveEvent(event); - }; - - this.onMousePressEvent = function(event, clickedOverlay) { - this.red.onMousePressEvent(event, clickedOverlay); - if (this.red.isMoving) { - return; - } - - this.green.onMousePressEvent(event, clickedOverlay); - if (this.green.isMoving) { - return; - } - - this.blue.onMousePressEvent(event, clickedOverlay); - }; - - - this.onMouseReleaseEvent = function(event) { - this.red.onMouseReleaseEvent(event); - this.green.onMouseReleaseEvent(event); - this.blue.onMouseReleaseEvent(event); - }; - - this.setterFromWidget = function(value) { - var color = self.getValue(); - self.onValueChanged(color); - self.updateRGBSliders(color); - }; - - this.red.onValueChanged = this.setterFromWidget; - this.green.onValueChanged = this.setterFromWidget; - this.blue.onValueChanged = this.setterFromWidget; - - this.updateRGBSliders = function(color) { - this.red.setThumbColor({x: color.x, y: 0, z: 0}); - this.green.setThumbColor({x: 0, y: color.y, z: 0}); - this.blue.setThumbColor({x: 0, y: 0, z: color.z}); - }; - - // Public members: - this.setValue = function(value) { - this.red.setValue(value.x); - this.green.setValue(value.y); - this.blue.setValue(value.z); - this.updateRGBSliders(value); - }; - - this.reset = function(resetValue) { - this.setValue(resetValue); - this.onValueChanged(resetValue); - }; - - this.getValue = function() { - var value = {x:this.red.getValue(), y:this.green.getValue(),z:this.blue.getValue()}; - return value; - }; - - this.getHeight = function() { - return 1.5 * this.thumbSize; - } - - this.destroy = function() { - this.red.destroy(); - this.green.destroy(); - this.blue.destroy(); - }; - - this.onValueChanged = function(value) {}; -} - -// The DirectionBox class -DirectionBox = function(x,y,width,thumbSize) { - var self = this; + Slider.prototype.isClickableOverlayItem = function(item) { + return (item == this.thumb) || (item == this.background); + }; - var slideHeight = thumbSize / 2; - var sliderWidth = width; - this.yaw = new Slider(x, y, width, slideHeight); - this.pitch = new Slider(x, y + slideHeight, width, slideHeight); - - - - this.yaw.setThumbColor({x: 1, y: 0, z: 0}); - this.yaw.minValue = -180; - this.yaw.maxValue = +180; - - this.pitch.setThumbColor({x: 0, y: 0, z: 1}); - this.pitch.minValue = -1; - this.pitch.maxValue = +1; - - this.isClickableOverlayItem = function(item) { - return this.yaw.isClickableOverlayItem(item) - || this.pitch.isClickableOverlayItem(item); - }; - - this.onMouseMoveEvent = function(event) { - this.yaw.onMouseMoveEvent(event); - this.pitch.onMouseMoveEvent(event); - }; - - this.onMousePressEvent = function(event, clickedOverlay) { - this.yaw.onMousePressEvent(event, clickedOverlay); - if (this.yaw.isMoving) { - return; - } - this.pitch.onMousePressEvent(event, clickedOverlay); - }; - - this.onMouseReleaseEvent = function(event) { - this.yaw.onMouseReleaseEvent(event); - this.pitch.onMouseReleaseEvent(event); - }; - - this.setterFromWidget = function(value) { - var yawPitch = self.getValue(); - self.onValueChanged(yawPitch); - }; - - this.yaw.onValueChanged = this.setterFromWidget; - this.pitch.onValueChanged = this.setterFromWidget; - - // Public members: - this.setValue = function(direction) { - var flatXZ = Math.sqrt(direction.x * direction.x + direction.z * direction.z); - if (flatXZ > 0.0) { - var flatX = direction.x / flatXZ; - var flatZ = direction.z / flatXZ; - var yaw = Math.acos(flatX) * 180 / Math.PI; - if (flatZ < 0) { - yaw = -yaw; + Slider.prototype.onMouseMoveEvent = function(event) { + if (this.isMoving) { + var newThumbX = event.x - this.clickOffsetX; + if (newThumbX < this.minThumbX) { + newThumbX = this.minThumbX; + } + if (newThumbX > this.maxThumbX) { + newThumbX = this.maxThumbX; + } + this.thumbX = newThumbX; + this.updateThumb(); + this.onValueChanged(this.getValue()); } - this.yaw.setValue(yaw); + }; + + Slider.prototype.onMousePressEvent = function(event, clickedOverlay) { + if (!this.isClickableOverlayItem(clickedOverlay)) { + this.isMoving = false; + return; + } + this.isMoving = true; + var clickOffset = event.x - this.thumbX; + if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { + this.clickOffsetX = clickOffset; + } else { + this.clickOffsetX = 0; + this.thumbX = event.x; + this.updateThumb(); + this.onValueChanged(this.getValue()); + } + + }; + + Slider.prototype.onMouseReleaseEvent = function(event) { + this.isMoving = false; + }; + + // Public members: + Slider.prototype.setNormalizedValue = function(value) { + if (value < 0.0) { + this.thumbX = this.minThumbX; + } else if (value > 1.0) { + this.thumbX = this.maxThumbX; + } else { + this.thumbX = value * (this.maxThumbX - this.minThumbX) + this.minThumbX; + } + this.updateThumb(); + }; + Slider.prototype.getNormalizedValue = function() { + return (this.thumbX - this.minThumbX) / (this.maxThumbX - this.minThumbX); + }; + + Slider.prototype.setValue = function(value) { + var normValue = (value - this.minValue) / (this.maxValue - this.minValue); + this.setNormalizedValue(normValue); + }; + + Slider.prototype.reset = function(resetValue) { + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; + + Slider.prototype.getValue = function() { + return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; + }; + + Slider.prototype.getHeight = function() { + if(!this.visible) { + return 0; + } + return 1.5 * this.thumbSize; + }; + + Slider.prototype.moveUp = function(newY) { + Overlays.editOverlay(this.background, {y: newY}); + Overlays.editOverlay(this.thumb, {y: newY}); + }; + + Slider.prototype.moveDown = function() { + Overlays.editOverlay(this.background, {y: this.y}); + Overlays.editOverlay(this.thumb, {y: this.y}); + }; + + Slider.prototype.onValueChanged = function(value) {}; + + Slider.prototype.hide = function() { + Overlays.editOverlay(this.background, {visible: false}); + Overlays.editOverlay(this.thumb, {visible: false}); + this.visible = false; + }; + + Slider.prototype.show = function() { + Overlays.editOverlay(this.background, {visible: true}); + Overlays.editOverlay(this.thumb, {visible: true}); + this.visible = true; + }; + + Slider.prototype.destroy = function() { + Overlays.deleteOverlay(this.background); + Overlays.deleteOverlay(this.thumb); + }; + + Slider.prototype.setThumbColor = function(color) { + Overlays.editOverlay(this.thumb, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); + }; + Slider.prototype.setBackgroundColor = function(color) { + Overlays.editOverlay(this.background, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); + }; + this.Slider = Slider; + + // The Checkbox class + var Checkbox = function(x,y,width,thumbSize) { + + this.background = Overlays.addOverlay("text", { + backgroundColor: { red: 125, green: 125, blue: 255 }, + x: x, + y: y, + width: width, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true + }); + + this.thumb = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + textFontSize: 10, + x: x, + y: y, + width: thumbSize, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 1.0, + visible: true + }); + + + this.thumbSize = thumbSize; + var checkX = x + (0.25 * thumbSize); + var checkY = y + (0.25 * thumbSize); + this.y = y; + this.boxCheckStatus = true; + this.clickedBox = false; + this.visible = true; + + + this.checkMark = Overlays.addOverlay("text", { + backgroundColor: { red: 0, green: 255, blue: 0 }, + x: checkX, + y: checkY, + width: thumbSize / 2.0, + height: thumbSize / 2.0, + alpha: 1.0, + visible: true + }); + + this.unCheckMark = Overlays.addOverlay("image", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: checkX + 1.0, + y: checkY + 1.0, + width: thumbSize / 2.5, + height: thumbSize / 2.5, + alpha: 1.0, + visible: false + }); + }; + + Checkbox.prototype.updateThumb = function() { + + Overlays.editOverlay(this.unCheckMark, { visible: !this.boxCheckStatus }); + + }; + + Checkbox.prototype.isClickableOverlayItem = function(item) { + return (item == this.thumb) || (item == this.checkMark) || (item == this.unCheckMark); + }; + + Checkbox.prototype.onMousePressEvent = function(event, clickedOverlay) { + + if (!this.isClickableOverlayItem(clickedOverlay)) { + return; + } + + this.boxCheckStatus = !this.boxCheckStatus; + this.onValueChanged(this.getValue()); + this.updateThumb(); + }; + + + Checkbox.prototype.onMouseReleaseEvent = function(event) { }; + + + // Public members: + + Checkbox.prototype.setValue = function(value) { + this.boxCheckStatus = value; + }; + + Checkbox.prototype.reset = function(resetValue) { + this.setValue(resetValue); + }; + + Checkbox.prototype.getValue = function() { + return this.boxCheckStatus; + }; + + Checkbox.prototype.getHeight = function() { + if(!this.visible) { + return 0; } - this.pitch.setValue(direction.y); + return 1.5 * this.thumbSize; + }; + + Checkbox.prototype.moveUp = function(newY) { + Overlays.editOverlay(this.background, {y: newY}); + Overlays.editOverlay(this.thumb, {y: newY}); + Overlays.editOverlay(this.checkMark, {y: newY}); + Overlays.editOverlay(this.unCheckMark, {y: newY}); }; - this.reset = function(resetValue) { - this.setValue(resetValue); - this.onValueChanged(resetValue); + Checkbox.prototype.moveDown = function() { + Overlays.editOverlay(this.background, {y: this.y}); + Overlays.editOverlay(this.thumb, {y: this.y}); + Overlays.editOverlay(this.checkMark, {y: this.y}); + Overlays.editOverlay(this.unCheckMark, {y: this.y}); }; + + Checkbox.prototype.setterFromWidget = function(value) { + this.updateThumb(); + }; + + Checkbox.prototype.onValueChanged = function(value) { }; - this.getValue = function() { - var dirZ = this.pitch.getValue(); - var yaw = this.yaw.getValue() * Math.PI / 180; - var cosY = Math.sqrt(1 - dirZ*dirZ); - var value = {x:cosY * Math.cos(yaw), y:dirZ, z: cosY * Math.sin(yaw)}; - return value; - }; - - this.getHeight = function() { - return 1.5 * this.thumbSize; + Checkbox.prototype.hide = function() { + Overlays.editOverlay(this.background, {visible: false}); + Overlays.editOverlay(this.thumb, {visible: false}); + Overlays.editOverlay(this.checkMark, {visible: false}); + Overlays.editOverlay(this.unCheckMark, {visible: false}); + this.visible = false; } - this.destroy = function() { - this.yaw.destroy(); - this.pitch.destroy(); + Checkbox.prototype.show = function() { + Overlays.editOverlay(this.background, {visible: true}); + Overlays.editOverlay(this.thumb, {visible: true}); + Overlays.editOverlay(this.checkMark, {visible: true}); + Overlays.editOverlay(this.unCheckMark, {visible: true}); + this.visible = true; + } + + Checkbox.prototype.destroy = function() { + Overlays.deleteOverlay(this.background); + Overlays.deleteOverlay(this.thumb); + Overlays.deleteOverlay(this.checkMark); + Overlays.deleteOverlay(this.unCheckMark); + }; + + Checkbox.prototype.setThumbColor = function(color) { + Overlays.editOverlay(this.thumb, { red: 255, green: 255, blue: 255 } ); + }; + Checkbox.prototype.setBackgroundColor = function(color) { + Overlays.editOverlay(this.background, { red: 125, green: 125, blue: 255 }); + }; + this.Checkbox = Checkbox; + + // The ColorBox class + var ColorBox = function(x,y,width,thumbSize) { + var self = this; + + var slideHeight = thumbSize / 3; + var sliderWidth = width; + this.red = new Slider(x, y, width, slideHeight); + this.green = new Slider(x, y + slideHeight, width, slideHeight); + this.blue = new Slider(x, y + 2 * slideHeight, width, slideHeight); + this.red.setBackgroundColor({x: 1, y: 0, z: 0}); + this.green.setBackgroundColor({x: 0, y: 1, z: 0}); + this.blue.setBackgroundColor({x: 0, y: 0, z: 1}); + + this.red.onValueChanged = this.setterFromWidget; + this.green.onValueChanged = this.setterFromWidget; + this.blue.onValueChanged = this.setterFromWidget; + + this.visible = true; + }; + + ColorBox.prototype.isClickableOverlayItem = function(item) { + return this.red.isClickableOverlayItem(item) + || this.green.isClickableOverlayItem(item) + || this.blue.isClickableOverlayItem(item); + }; + + ColorBox.prototype.onMouseMoveEvent = function(event) { + this.red.onMouseMoveEvent(event); + this.green.onMouseMoveEvent(event); + this.blue.onMouseMoveEvent(event); + }; + + ColorBox.prototype.onMousePressEvent = function(event, clickedOverlay) { + this.red.onMousePressEvent(event, clickedOverlay); + if (this.red.isMoving) { + return; + } + + this.green.onMousePressEvent(event, clickedOverlay); + if (this.green.isMoving) { + return; + } + + this.blue.onMousePressEvent(event, clickedOverlay); + }; + + + ColorBox.prototype.onMouseReleaseEvent = function(event) { + this.red.onMouseReleaseEvent(event); + this.green.onMouseReleaseEvent(event); + this.blue.onMouseReleaseEvent(event); + }; + + ColorBox.prototype.setterFromWidget = function(value) { + var color = this.getValue(); + this.onValueChanged(color); + this.updateRGBSliders(color); + }; + + ColorBox.prototype.updateRGBSliders = function(color) { + this.red.setThumbColor({x: color.x, y: 0, z: 0}); + this.green.setThumbColor({x: 0, y: color.y, z: 0}); + this.blue.setThumbColor({x: 0, y: 0, z: color.z}); + }; + + // Public members: + ColorBox.prototype.setValue = function(value) { + this.red.setValue(value.x); + this.green.setValue(value.y); + this.blue.setValue(value.z); + this.updateRGBSliders(value); + }; + + ColorBox.prototype.reset = function(resetValue) { + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; + + ColorBox.prototype.getValue = function() { + var value = {x:this.red.getValue(), y:this.green.getValue(),z:this.blue.getValue()}; + return value; + }; + + ColorBox.prototype.getHeight = function() { + if(!this.visible) { + return 0; + } + return 1.5 * this.thumbSize; + }; + + ColorBox.prototype.moveUp = function(newY) { + this.red.moveUp(newY); + this.green.moveUp(newY); + this.blue.moveUp(newY); }; - this.onValueChanged = function(value) {}; -} + ColorBox.prototype.moveDown = function() { + this.red.moveDown(); + this.green.moveDown(); + this.blue.moveDown(); + }; + ColorBox.prototype.hide = function() { + this.red.hide(); + this.green.hide(); + this.blue.hide(); + this.visible = false; + } - -var textFontSize = 12; - -// TODO: Make collapsable -function CollapsablePanelItem(name, x, y, textWidth, height) { - this.name = name; - this.height = height; - - var topMargin = (height - textFontSize); - - this.thumb = Overlays.addOverlay("text", { - backgroundColor: { red: 220, green: 220, blue: 220 }, - textFontSize: 10, - x: x, - y: y, - width: rawHeight, - height: rawHeight, - alpha: 1.0, - backgroundAlpha: 1.0, - visible: true - }); + ColorBox.prototype.show = function() { + this.red.show(); + this.green.show(); + this.blue.show(); + this.visible = true; + } - this.title = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: x + rawHeight, - y: y, - width: textWidth, - height: height, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true, - text: name, - font: {size: textFontSize}, - topMargin: topMargin, - }); + ColorBox.prototype.destroy = function() { + this.red.destroy(); + this.green.destroy(); + this.blue.destroy(); + }; + + ColorBox.prototype.onValueChanged = function(value) {}; + this.ColorBox = ColorBox; + + // The DirectionBox class + var DirectionBox = function(x,y,width,thumbSize) { + var self = this; + + var slideHeight = thumbSize / 2; + var sliderWidth = width; + this.yaw = new Slider(x, y, width, slideHeight); + this.pitch = new Slider(x, y + slideHeight, width, slideHeight); + + + this.yaw.setThumbColor({x: 1, y: 0, z: 0}); + this.yaw.minValue = -180; + this.yaw.maxValue = +180; + + this.pitch.setThumbColor({x: 0, y: 0, z: 1}); + this.pitch.minValue = -1; + this.pitch.maxValue = +1; + + this.yaw.onValueChanged = this.setterFromWidget; + this.pitch.onValueChanged = this.setterFromWidget; - this.destroy = function() { + this.visible = true; + }; + + DirectionBox.prototype.isClickableOverlayItem = function(item) { + return this.yaw.isClickableOverlayItem(item) + || this.pitch.isClickableOverlayItem(item); + }; + + DirectionBox.prototype.onMouseMoveEvent = function(event) { + this.yaw.onMouseMoveEvent(event); + this.pitch.onMouseMoveEvent(event); + }; + + DirectionBox.prototype.onMousePressEvent = function(event, clickedOverlay) { + this.yaw.onMousePressEvent(event, clickedOverlay); + if (this.yaw.isMoving) { + return; + } + this.pitch.onMousePressEvent(event, clickedOverlay); + }; + + DirectionBox.prototype.onMouseReleaseEvent = function(event) { + this.yaw.onMouseReleaseEvent(event); + this.pitch.onMouseReleaseEvent(event); + }; + + DirectionBox.prototype.setterFromWidget = function(value) { + var yawPitch = this.getValue(); + this.onValueChanged(yawPitch); + }; + + // Public members: + DirectionBox.prototype.setValue = function(direction) { + var flatXZ = Math.sqrt(direction.x * direction.x + direction.z * direction.z); + if (flatXZ > 0.0) { + var flatX = direction.x / flatXZ; + var flatZ = direction.z / flatXZ; + var yaw = Math.acos(flatX) * 180 / Math.PI; + if (flatZ < 0) { + yaw = -yaw; + } + this.yaw.setValue(yaw); + } + this.pitch.setValue(direction.y); + }; + + DirectionBox.prototype.reset = function(resetValue) { + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; + + DirectionBox.prototype.getValue = function() { + var dirZ = this.pitch.getValue(); + var yaw = this.yaw.getValue() * Math.PI / 180; + var cosY = Math.sqrt(1 - dirZ*dirZ); + var value = {x:cosY * Math.cos(yaw), y:dirZ, z: cosY * Math.sin(yaw)}; + return value; + }; + + DirectionBox.prototype.getHeight = function() { + if(!this.visible) { + return 0; + } + return 1.5 * this.thumbSize; + }; + + DirectionBox.prototype.moveUp = function(newY) { + this.pitch.moveUp(newY); + this.yaw.moveUp(newY); + }; + + DirectionBox.prototype.moveDown = function(newY) { + this.pitch.moveDown(); + this.yaw.moveDown(); + }; + + DirectionBox.prototype.hide = function() { + this.pitch.hide(); + this.yaw.hide(); + this.visible = false; + } + + DirectionBox.prototype.show = function() { + this.pitch.show(); + this.yaw.show(); + this.visible = true; + } + + DirectionBox.prototype.destroy = function() { + this.yaw.destroy(); + this.pitch.destroy(); + }; + + DirectionBox.prototype.onValueChanged = function(value) {}; + this.DirectionBox = DirectionBox; + + var textFontSize = 12; + + var CollapsablePanelItem = function (name, x, y, textWidth, height) { + this.name = name; + this.height = height; + this.y = y; + this.isCollapsable = true; + + var topMargin = (height - 1.5 * textFontSize); + + this.thumb = Overlays.addOverlay("text", { + backgroundColor: { red: 220, green: 220, blue: 220 }, + textFontSize: 10, + x: x, + y: y, + width: rawHeight, + height: rawHeight, + alpha: 1.0, + backgroundAlpha: 1.0, + visible: true + }); + + this.title = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: x + rawHeight * 1.5, + y: y, + width: textWidth, + height: height, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true, + text: " " + name, + font: {size: textFontSize}, + topMargin: topMargin + }); + }; + + CollapsablePanelItem.prototype.destroy = function() { Overlays.deleteOverlay(this.title); Overlays.deleteOverlay(this.thumb); - if (this.widget != null) { - this.widget.destroy(); - } - } -} - -function PanelItem(name, setter, getter, displayer, x, y, textWidth, valueWidth, height) { - //print("creating panel item: " + name); + }; - this.name = name; - - this.displayer = typeof displayer !== 'undefined' ? displayer : function(value) { - if(value == true) { - return "On"; - } else if (value == false) { - return "Off"; - } - return value; - }; - - var topMargin = (height - textFontSize); - this.title = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: x, - y: y, - width: textWidth, - height: height, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true, - text: name, - font: {size: textFontSize}, - topMargin: topMargin, - }); - - this.value = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: x + textWidth, - y: y, - width: valueWidth, - height: height, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true, - text: this.displayer(getter()), - font: {size: textFontSize}, - topMargin: topMargin - }); - - this.getter = getter; - this.resetValue = getter(); - - this.setter = function(value) { - - setter(value); - - Overlays.editOverlay(this.value, {text: this.displayer(getter())}); - - if (this.widget) { - this.widget.setValue(value); - } - - //print("successfully set value of widget to " + value); - }; - this.setterFromWidget = function(value) { - setter(value); - // ANd loop back the value after the final setter has been called - var value = getter(); - - if (this.widget) { - this.widget.setValue(value); - } - Overlays.editOverlay(this.value, {text: this.displayer(value)}); - }; - - this.widget = null; + CollapsablePanelItem.prototype.hide = function() { + Overlays.editOverlay(this.title, {visible: false}); + Overlays.editOverlay(this.thumb, {visible: false}); - this.destroy = function() { - Overlays.deleteOverlay(this.title); - Overlays.deleteOverlay(this.value); if (this.widget != null) { - this.widget.destroy(); + this.widget.hide(); + } + }; + + CollapsablePanelItem.prototype.show = function() { + Overlays.editOverlay(this.title, {visible: true}); + Overlays.editOverlay(this.thumb, {visible: true}); + + if (this.widget != null) { + this.widget.show(); + } + }; + + CollapsablePanelItem.prototype.moveUp = function(newY) { + Overlays.editOverlay(this.title, {y: newY}); + Overlays.editOverlay(this.thumb, {y: newY}); + + if (this.widget != null) { + this.widget.moveUp(newY); } } -} -var textWidth = 180; -var valueWidth = 100; -var widgetWidth = 300; -var rawHeight = 20; -var rawYDelta = rawHeight * 1.5; + CollapsablePanelItem.prototype.moveDown = function() { + Overlays.editOverlay(this.title, {y: this.y}); + Overlays.editOverlay(this.thumb, {y: this.y}); -Panel = function(x, y) { + if (this.widget != null) { + this.widget.moveDown(); + } - this.x = x; - this.y = y; - this.nextY = y; + } - this.widgetX = x + textWidth + valueWidth; + this.CollapsablePanelItem = CollapsablePanelItem; + + var PanelItem = function (name, setter, getter, displayer, x, y, textWidth, valueWidth, height) { + //print("creating panel item: " + name); + this.isCollapsable = false; + this.name = name; + this.y = y; + this.isCollapsed = false; + + this.displayer = typeof displayer !== 'undefined' ? displayer : function(value) { + if(value == true) { + return "On"; + } else if (value == false) { + return "Off"; + } + return value.toFixed(2); + }; + + var topMargin = (height - 1.5 * textFontSize); + this.title = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: x, + y: y, + width: textWidth, + height: height, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true, + text: " " + name, + font: {size: textFontSize}, + topMargin: topMargin + }); + + this.value = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: x + textWidth, + y: y, + width: valueWidth, + height: height, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true, + text: this.displayer(getter()), + font: {size: textFontSize}, + topMargin: topMargin + }); + + this.getter = getter; + this.resetValue = getter(); + + this.setter = function(value) { + + setter(value); - this.items = new Array(); - this.activeWidget = null; + Overlays.editOverlay(this.value, {text: this.displayer(getter())}); - this.mouseMoveEvent = function(event) { + if (this.widget) { + this.widget.setValue(value); + } + + //print("successfully set value of widget to " + value); + }; + this.setterFromWidget = function(value) { + setter(value); + // ANd loop back the value after the final setter has been called + var value = getter(); + + if (this.widget) { + this.widget.setValue(value); + } + Overlays.editOverlay(this.value, {text: this.displayer(value)}); + }; + + this.widget = null; + }; + + PanelItem.prototype.hide = function() { + Overlays.editOverlay(this.title, {visible: false}); + Overlays.editOverlay(this.value, {visible: false}); + + if (this.widget != null) { + this.widget.hide(); + } + }; + + + PanelItem.prototype.show = function() { + Overlays.editOverlay(this.title, {visible: true}); + Overlays.editOverlay(this.value, {visible: true}); + + if (this.widget != null) { + this.widget.show(); + } + + }; + + PanelItem.prototype.moveUp = function(newY) { + + Overlays.editOverlay(this.title, {y: newY}); + Overlays.editOverlay(this.value, {y: newY}); + + if (this.widget != null) { + this.widget.moveUp(newY); + } + + }; + + PanelItem.prototype.moveDown = function() { + + Overlays.editOverlay(this.title, {y: this.y}); + Overlays.editOverlay(this.value, {y: this.y}); + + if (this.widget != null) { + this.widget.moveDown(); + } + + }; + + PanelItem.prototype.destroy = function() { + Overlays.deleteOverlay(this.title); + Overlays.deleteOverlay(this.value); + + if (this.widget != null) { + this.widget.destroy(); + } + }; + this.PanelItem = PanelItem; + + var textWidth = 180; + var valueWidth = 100; + var widgetWidth = 300; + var rawHeight = 20; + var rawYDelta = rawHeight * 1.5; + + var Panel = function(x, y) { + + this.x = x; + this.y = y; + + this.nextY = y; print("creating panel at x: " + this.x + " y: " + this.y); + + this.widgetX = x + textWidth + valueWidth; + + this.items = new Array(); + this.activeWidget = null; + this.visible = true; + this.indentation = 30; + + }; + + Panel.prototype.mouseMoveEvent = function(event) { if (this.activeWidget) { this.activeWidget.onMouseMoveEvent(event); } }; - - this.mousePressEvent = function(event) { + + Panel.prototype.mousePressEvent = function(event) { // Make sure we quitted previous widget if (this.activeWidget) { this.activeWidget.onMouseReleaseEvent(event); } this.activeWidget = null; - + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); - + this.handleCollapse(clickedOverlay); + // If the user clicked any of the slider background then... for (var i in this.items) { + var item = this.items[i]; var widget = this.items[i].widget; - + if (widget.isClickableOverlayItem(clickedOverlay)) { this.activeWidget = widget; this.activeWidget.onMousePressEvent(event, clickedOverlay); - break; - } + + } } }; - - // Reset panel item upon double-clicking - this.mouseDoublePressEvent = function(event) { - + + // Reset panel item upon double-clicking + Panel.prototype.mouseDoublePressEvent = function(event) { var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + this.handleReset(clickedOverlay); + } + + Panel.prototype.handleReset = function (clickedOverlay) { for (var i in this.items) { - + var item = this.items[i]; var widget = item.widget; + + if (item.isSubPanel && widget) { + widget.handleReset(clickedOverlay); + } if (clickedOverlay == item.title) { item.activeWidget = widget; - + item.activeWidget.reset(item.resetValue); break; } - } - } + } + }; - this.mouseReleaseEvent = function(event) { + Panel.prototype.handleCollapse = function (clickedOverlay) { + + for (var i in this.items) { + + var item = this.items[i]; + var widget = item.widget; + + if (item.isSubPanel && widget) { + widget.handleCollapse(clickedOverlay); + } + + if (!item.isCollapsed && item.isCollapsable && clickedOverlay == item.thumb) { + this.collapse(clickedOverlay); + item.isCollapsed = true; + break; + } else if (item.isCollapsed && item.isCollapsable && clickedOverlay == item.thumb) { + this.expand(clickedOverlay); + item.isCollapsed = false; + } + } + }; + + Panel.prototype.collapse = function (clickedOverlay) { + var keys = Object.keys(this.items); + + for (var i = 0; i < keys.length; ++i) { + var item = this.items[keys[i]]; + + if(item.isCollapsable && clickedOverlay == item.thumb) { + var panel = item.widget; + panel.hide(); + break; + } + + } + + // Now recalculate new heights of subsequent widgets + for(var j = i + 1; j < keys.length; ++j) { + + this.items[keys[j]].moveUp(this.getCurrentY(keys[j])); + + } + + }; + + + Panel.prototype.expand = function (clickedOverlay) { + var keys = Object.keys(this.items); + + for (var i = 0; i < keys.length; ++i) { + var item = this.items[keys[i]]; + + if(item.isCollapsable && clickedOverlay == item.thumb) { + var panel = item.widget; + panel.show(); + break; + } + + } + + // Now recalculate new heights of subsequent widgets + for(var j = i + 1; j < keys.length; ++j) { + this.items[keys[j]].moveDown(); + } + + }; + + + Panel.prototype.mouseReleaseEvent = function(event) { if (this.activeWidget) { this.activeWidget.onMouseReleaseEvent(event); } this.activeWidget = null; }; - - this.onMousePressEvent = function(event, clickedOverlay) { + + Panel.prototype.onMousePressEvent = function(event, clickedOverlay) { for (var i in this.items) { var item = this.items[i]; if(item.widget.isClickableOverlayItem(clickedOverlay)) { @@ -674,27 +936,19 @@ Panel = function(x, y) { item.activeWidget.onMousePressEvent(event,clickedOverlay); } } - } - - this.reset = function() { - for (var i in this.items) { - var item = this.items[i]; - if (item.activeWidget) { - item.activeWidget.reset(item.resetValue); - } - } - } - - this.onMouseMoveEvent = function(event) { + }; + + + Panel.prototype.onMouseMoveEvent = function(event) { for (var i in this.items) { var item = this.items[i]; if (item.activeWidget) { item.activeWidget.onMouseMoveEvent(event); } } - } - - this.onMouseReleaseEvent = function(event, clickedOverlay) { + }; + + Panel.prototype.onMouseReleaseEvent = function(event, clickedOverlay) { for (var i in this.items) { var item = this.items[i]; if (item.activeWidget) { @@ -702,47 +956,46 @@ Panel = function(x, y) { } item.activeWidget = null; } - } - - this.onMouseDoublePressEvent = function(event, clickedOverlay) { - + }; + + Panel.prototype.onMouseDoublePressEvent = function(event, clickedOverlay) { for (var i in this.items) { var item = this.items[i]; if (item.activeWidget) { item.activeWidget.onMouseDoublePressEvent(event); } } - } - - this.newSlider = function(name, minValue, maxValue, setValue, getValue, displayValue) { + }; + + Panel.prototype.newSlider = function(name, minValue, maxValue, setValue, getValue, displayValue) { this.nextY = this.y + this.getHeight(); - var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); var slider = new Slider(this.widgetX, this.nextY, widgetWidth, rawHeight); slider.minValue = minValue; slider.maxValue = maxValue; - + item.widget = slider; item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; item.setter(getValue()); this.items[name] = item; - this.nextY += rawYDelta; - }; - this.newCheckbox = function(name, setValue, getValue, displayValue) { + }; + + Panel.prototype.newCheckbox = function(name, setValue, getValue, displayValue) { var display; if (displayValue == true) { display = function() {return "On";}; } else if (displayValue == false) { display = function() {return "Off";}; } - + this.nextY = this.y + this.getHeight(); - + var item = new PanelItem(name, setValue, getValue, display, this.x, this.nextY, textWidth, valueWidth, rawHeight); - + var checkbox = new Checkbox(this.widgetX, this.nextY, widgetWidth, rawHeight); - + item.widget = checkbox; item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; item.setter(getValue()); @@ -750,136 +1003,180 @@ Panel = function(x, y) { //print("created Item... checkbox=" + name); }; - - this.newColorBox = function(name, setValue, getValue, displayValue) { + + Panel.prototype.newColorBox = function(name, setValue, getValue, displayValue) { this.nextY = this.y + this.getHeight(); - + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); - + var colorBox = new ColorBox(this.widgetX, this.nextY, widgetWidth, rawHeight); - + item.widget = colorBox; item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; item.setter(getValue()); this.items[name] = item; - this.nextY += rawYDelta; + // print("created Item... colorBox=" + name); }; - -<<<<<<< Updated upstream - this.newDirectionBox = function(name, setValue, getValue, displayValue) { -======= - this.newDirectionBox= function(name, setValue, getValue, displayValue) { + + Panel.prototype.newDirectionBox = function(name, setValue, getValue, displayValue) { this.nextY = this.y + this.getHeight(); ->>>>>>> Stashed changes - + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); var directionBox = new DirectionBox(this.widgetX, this.nextY, widgetWidth, rawHeight); - + item.widget = directionBox; item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; item.setter(getValue()); this.items[name] = item; - this.nextY += rawYDelta; + // print("created Item... directionBox=" + name); }; - -<<<<<<< Updated upstream - this.newSubPanel = function(name) { - var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); - - var panel = new Panel(this.widgetX, this.nextY); - - item.widget = panel; - - item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; + - this.nextY += rawYDelta; - - }; - -======= - var indentation = 30; - - this.newSubPanel = function(name) { + + Panel.prototype.newSubPanel = function(name) { //TODO: make collapsable, fix double-press event this.nextY = this.y + this.getHeight(); - + var item = new CollapsablePanelItem(name, this.x, this.nextY, textWidth, rawHeight, panel); item.isSubPanel = true; + + this.nextY += 1.5 * item.height; + + var subPanel = new Panel(this.x + this.indentation, this.nextY); - this.nextY += 1.5 * item.height; - - var subPanel = new Panel(this.x + indentation, this.nextY); - item.widget = subPanel; this.items[name] = item; return subPanel; // print("created Item... subPanel=" + name); }; - - this.onValueChanged = function(value) { + + Panel.prototype.onValueChanged = function(value) { for (var i in this.items) { this.items[i].widget.onValueChanged(value); } - } ->>>>>>> Stashed changes - - this.destroy = function() { - for (var i in this.items) { - this.items[i].destroy(); - } - } - - - this.set = function(name, value) { + }; + + + Panel.prototype.set = function(name, value) { var item = this.items[name]; if (item != null) { return item.setter(value); } return null; - } - - this.get = function(name) { + }; + + Panel.prototype.get = function(name) { var item = this.items[name]; if (item != null) { return item.getter(); } return null; - } - - this.update = function(name) { + }; + + Panel.prototype.update = function(name) { var item = this.items[name]; if (item != null) { return item.setter(item.getter()); } return null; - } - - this.isClickableOverlayItem = function(item) { + }; + + Panel.prototype.isClickableOverlayItem = function(item) { for (var i in this.items) { if (this.items[i].widget.isClickableOverlayItem(item)) { return true; } } return false; - } - - this.getHeight = function() { + }; + + Panel.prototype.getHeight = function(show) { var height = 0; - + for (var i in this.items) { + height += this.items[i].widget.getHeight(); - if(this.items[i].isSubPanel) { + // if(show) { + // print("widget: " + i + " height: " + this.items[i].widget.getHeight()); + + // } + if(this.items[i].isSubPanel && this.items[i].widget.visible) { + height += 1.5 * rawHeight; - } + + } + } - return height; - } + }; -}; + Panel.prototype.moveUp = function() { + for (var i in this.items) { + this.items[i].widget.moveUp(); + } + + }; + + Panel.prototype.moveDown = function() { + for (var i in this.items) { + this.items[i].widget.moveDown(); + } + }; + + Panel.prototype.getCurrentY = function(key) { + var height = 0; + var keys = Object.keys(this.items); + + for (var i = 0; i < keys.indexOf(key); ++i) { + var item = this.items[keys[i]]; + + height += item.widget.getHeight(); + + if(item.isSubPanel) { + height += 1.5 * rawHeight; + + } + } + + return this.y + height; + }; + + + Panel.prototype.hide = function() { + for (var i in this.items) { + if(this.items[i].isSubPanel) { + this.items[i].widget.hide(); + } + this.items[i].hide(); + } + this.visible = false; + }; + + Panel.prototype.show = function() { + for (var i in this.items) { + if(this.items[i].isSubPanel) { + this.items[i].widget.show(); + } + this.items[i].show(); + } + this.visible = true; + }; + Panel.prototype.destroy = function() { + for (var i in this.items) { + + if(this.items[i].isSubPanel) { + this.items[i].widget.destroy(); + } + this.items[i].destroy(); + } + }; + + + this.Panel = Panel; +})(); \ No newline at end of file From b7d195e8173360ebb45fc1d9e7a771fc030a245c Mon Sep 17 00:00:00 2001 From: bwent Date: Mon, 27 Jul 2015 13:56:25 -0700 Subject: [PATCH 22/74] more subpanel fixes --- examples/utilities/tools/cookies.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 9d064385bf..44017c66da 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -888,10 +888,10 @@ } } + // Now recalculate new heights of subsequent widgets for(var j = i + 1; j < keys.length; ++j) { - this.items[keys[j]].moveUp(this.getCurrentY(keys[j])); } From 774b4851c323f5adec20173a45f9aa3474edb9fe Mon Sep 17 00:00:00 2001 From: bwent Date: Tue, 28 Jul 2015 12:18:26 -0700 Subject: [PATCH 23/74] Add tab to highlight widgets and update using left and right arrow keys --- examples/utilities/tools/cookies.js | 453 +++++++++++++++++----------- 1 file changed, 282 insertions(+), 171 deletions(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 44017c66da..b2dc8c1da7 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -9,6 +9,26 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + +HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; + +var SCALE = 1000; +var THUMB_COLOR = { + red: 150, + green: 150, + blue: 150 +}; +var THUMB_HIGHLIGHT = { + red: 255, + green: 255, + blue: 255 +}; +var CHECK_MARK_COLOR = { + red: 70, + green: 70, + blue: 90 +}; + // The Slider class (function () { var Slider = function(x,y,width,thumbSize) { @@ -24,7 +44,7 @@ visible: true }); this.thumb = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, + backgroundColor: THUMB_COLOR, x: x, y: y, width: thumbSize, @@ -61,6 +81,25 @@ return (item == this.thumb) || (item == this.background); }; + + Slider.prototype.onMousePressEvent = function(event, clickedOverlay) { + if (!this.isClickableOverlayItem(clickedOverlay)) { + this.isMoving = false; + return; + } + this.highlight(); + this.isMoving = true; + var clickOffset = event.x - this.thumbX; + if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { + this.clickOffsetX = clickOffset; + } else { + this.clickOffsetX = 0; + this.thumbX = event.x; + this.updateThumb(); + this.onValueChanged(this.getValue()); + } + }; + Slider.prototype.onMouseMoveEvent = function(event) { if (this.isMoving) { var newThumbX = event.x - this.clickOffsetX; @@ -76,34 +115,43 @@ } }; - Slider.prototype.onMousePressEvent = function(event, clickedOverlay) { - if (!this.isClickableOverlayItem(clickedOverlay)) { - this.isMoving = false; - return; - } - this.isMoving = true; - var clickOffset = event.x - this.thumbX; - if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { - this.clickOffsetX = clickOffset; - } else { - this.clickOffsetX = 0; - this.thumbX = event.x; - this.updateThumb(); - this.onValueChanged(this.getValue()); - } - - }; - Slider.prototype.onMouseReleaseEvent = function(event) { this.isMoving = false; + this.unhighlight(); }; - - // Public members: + + Slider.prototype.updateWithKeys = function(direction) { + this.range = this.maxThumbX - this.minThumbX; + this.thumbX += direction * (this.range / SCALE); + this.updateThumb(); + this.onValueChanged(this.getValue()); + }; + + Slider.prototype.highlight = function() { + if(this.highlighted) { + return; + } + Overlays.editOverlay(this.thumb, { + backgroundColor: {red: 255, green: 255, blue: 255} + }); + this.highlighted = true; + }; + + Slider.prototype.unhighlight = function() { + if(!this.highlighted) { + return; + } + Overlays.editOverlay(this.thumb, { + backgroundColor: THUMB_COLOR + }); + this.highlighted = false; + }; + Slider.prototype.setNormalizedValue = function(value) { if (value < 0.0) { this.thumbX = this.minThumbX; } else if (value > 1.0) { - this.thumbX = this.maxThumbX; + this.thumbX = this.maxThsumbX; } else { this.thumbX = value * (this.maxThumbX - this.minThumbX) + this.minThumbX; } @@ -117,16 +165,17 @@ var normValue = (value - this.minValue) / (this.maxValue - this.minValue); this.setNormalizedValue(normValue); }; + Slider.prototype.getValue = function() { + return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; + }; Slider.prototype.reset = function(resetValue) { this.setValue(resetValue); this.onValueChanged(resetValue); }; - Slider.prototype.getValue = function() { - return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; - }; - + Slider.prototype.onValueChanged = function(value) {}; + Slider.prototype.getHeight = function() { if(!this.visible) { return 0; @@ -143,8 +192,6 @@ Overlays.editOverlay(this.background, {y: this.y}); Overlays.editOverlay(this.thumb, {y: this.y}); }; - - Slider.prototype.onValueChanged = function(value) {}; Slider.prototype.hide = function() { Overlays.editOverlay(this.background, {visible: false}); @@ -157,36 +204,19 @@ Overlays.editOverlay(this.thumb, {visible: true}); this.visible = true; }; - + Slider.prototype.destroy = function() { Overlays.deleteOverlay(this.background); Overlays.deleteOverlay(this.thumb); }; - - Slider.prototype.setThumbColor = function(color) { - Overlays.editOverlay(this.thumb, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); - }; - Slider.prototype.setBackgroundColor = function(color) { - Overlays.editOverlay(this.background, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); - }; + this.Slider = Slider; // The Checkbox class var Checkbox = function(x,y,width,thumbSize) { - this.background = Overlays.addOverlay("text", { - backgroundColor: { red: 125, green: 125, blue: 255 }, - x: x, - y: y, - width: width, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true - }); - this.thumb = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, + backgroundColor: THUMB_COLOR, textFontSize: 10, x: x, y: y, @@ -208,64 +238,72 @@ this.checkMark = Overlays.addOverlay("text", { - backgroundColor: { red: 0, green: 255, blue: 0 }, + backgroundColor: CHECK_MARK_COLOR, x: checkX, y: checkY, width: thumbSize / 2.0, height: thumbSize / 2.0, alpha: 1.0, visible: true - }); - - this.unCheckMark = Overlays.addOverlay("image", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: checkX + 1.0, - y: checkY + 1.0, - width: thumbSize / 2.5, - height: thumbSize / 2.5, - alpha: 1.0, - visible: false - }); + }); }; Checkbox.prototype.updateThumb = function() { - - Overlays.editOverlay(this.unCheckMark, { visible: !this.boxCheckStatus }); - + Overlays.editOverlay(this.checkMark, { visible: this.boxCheckStatus }); }; Checkbox.prototype.isClickableOverlayItem = function(item) { - return (item == this.thumb) || (item == this.checkMark) || (item == this.unCheckMark); + return (item == this.thumb) || (item == this.checkMark); }; Checkbox.prototype.onMousePressEvent = function(event, clickedOverlay) { - if (!this.isClickableOverlayItem(clickedOverlay)) { return; - } - + } this.boxCheckStatus = !this.boxCheckStatus; this.onValueChanged(this.getValue()); this.updateThumb(); }; - - Checkbox.prototype.onMouseReleaseEvent = function(event) { }; - - - // Public members: + Checkbox.prototype.onMouseReleaseEvent = function(event) {}; + + Checkbox.prototype.updateWithKeys = function() { + this.boxCheckStatus = !this.boxCheckStatus; + this.onValueChanged(this.getValue()); + this.updateThumb(); + }; + + Checkbox.prototype.highlight = function() { + Overlays.editOverlay(this.thumb, { + backgroundColor: THUMB_HIGHLIGHT + }); + this.highlighted = true; + }; + + Checkbox.prototype.unhighlight = function() { + Overlays.editOverlay(this.thumb, { + backgroundColor: THUMB_COLOR + }); + this.highlighted = false; + }; Checkbox.prototype.setValue = function(value) { this.boxCheckStatus = value; }; + + Checkbox.prototype.setterFromWidget = function(value) { + this.updateThumb(); + }; + + Checkbox.prototype.getValue = function() { + return this.boxCheckStatus; + }; Checkbox.prototype.reset = function(resetValue) { this.setValue(resetValue); }; - - Checkbox.prototype.getValue = function() { - return this.boxCheckStatus; - }; + + Checkbox.prototype.onValueChanged = function(value) { }; Checkbox.prototype.getHeight = function() { if(!this.visible) { @@ -287,12 +325,6 @@ Overlays.editOverlay(this.checkMark, {y: this.y}); Overlays.editOverlay(this.unCheckMark, {y: this.y}); }; - - Checkbox.prototype.setterFromWidget = function(value) { - this.updateThumb(); - }; - - Checkbox.prototype.onValueChanged = function(value) { }; Checkbox.prototype.hide = function() { Overlays.editOverlay(this.background, {visible: false}); @@ -316,13 +348,7 @@ Overlays.deleteOverlay(this.checkMark); Overlays.deleteOverlay(this.unCheckMark); }; - - Checkbox.prototype.setThumbColor = function(color) { - Overlays.editOverlay(this.thumb, { red: 255, green: 255, blue: 255 } ); - }; - Checkbox.prototype.setBackgroundColor = function(color) { - Overlays.editOverlay(this.background, { red: 125, green: 125, blue: 255 }); - }; + this.Checkbox = Checkbox; // The ColorBox class @@ -351,12 +377,6 @@ || this.blue.isClickableOverlayItem(item); }; - ColorBox.prototype.onMouseMoveEvent = function(event) { - this.red.onMouseMoveEvent(event); - this.green.onMouseMoveEvent(event); - this.blue.onMouseMoveEvent(event); - }; - ColorBox.prototype.onMousePressEvent = function(event, clickedOverlay) { this.red.onMousePressEvent(event, clickedOverlay); if (this.red.isMoving) { @@ -370,19 +390,48 @@ this.blue.onMousePressEvent(event, clickedOverlay); }; - + + ColorBox.prototype.onMouseMoveEvent = function(event) { + this.red.onMouseMoveEvent(event); + this.green.onMouseMoveEvent(event); + this.blue.onMouseMoveEvent(event); + }; ColorBox.prototype.onMouseReleaseEvent = function(event) { this.red.onMouseReleaseEvent(event); this.green.onMouseReleaseEvent(event); this.blue.onMouseReleaseEvent(event); }; - + + ColorBox.prototype.updateWithKeys = function(direction) { + this.red.updateWithKeys(direction); + this.green.updateWithKeys(direction); + this.blue.updateWithKeys(direction); + } + + ColorBox.prototype.highlight = function() { + this.red.highlight(); + this.green.highlight(); + this.blue.highlight(); + + this.highlighted = true; + }; + + ColorBox.prototype.unhighlight = function() { + this.red.unhighlight(); + this.green.unhighlight(); + this.blue.unhighlight(); + + this.highlighted = false; + }; + ColorBox.prototype.setterFromWidget = function(value) { var color = this.getValue(); this.onValueChanged(color); this.updateRGBSliders(color); }; + + ColorBox.prototype.onValueChanged = function(value) {}; ColorBox.prototype.updateRGBSliders = function(color) { this.red.setThumbColor({x: color.x, y: 0, z: 0}); @@ -397,17 +446,18 @@ this.blue.setValue(value.z); this.updateRGBSliders(value); }; - - ColorBox.prototype.reset = function(resetValue) { - this.setValue(resetValue); - this.onValueChanged(resetValue); - }; - + ColorBox.prototype.getValue = function() { var value = {x:this.red.getValue(), y:this.green.getValue(),z:this.blue.getValue()}; return value; }; - + + ColorBox.prototype.reset = function(resetValue) { + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; + + ColorBox.prototype.getHeight = function() { if(!this.visible) { return 0; @@ -446,8 +496,7 @@ this.green.destroy(); this.blue.destroy(); }; - - ColorBox.prototype.onValueChanged = function(value) {}; + this.ColorBox = ColorBox; // The DirectionBox class @@ -479,11 +528,6 @@ || this.pitch.isClickableOverlayItem(item); }; - DirectionBox.prototype.onMouseMoveEvent = function(event) { - this.yaw.onMouseMoveEvent(event); - this.pitch.onMouseMoveEvent(event); - }; - DirectionBox.prototype.onMousePressEvent = function(event, clickedOverlay) { this.yaw.onMousePressEvent(event, clickedOverlay); if (this.yaw.isMoving) { @@ -491,18 +535,43 @@ } this.pitch.onMousePressEvent(event, clickedOverlay); }; + + DirectionBox.prototype.onMouseMoveEvent = function(event) { + this.yaw.onMouseMoveEvent(event); + this.pitch.onMouseMoveEvent(event); + }; DirectionBox.prototype.onMouseReleaseEvent = function(event) { this.yaw.onMouseReleaseEvent(event); this.pitch.onMouseReleaseEvent(event); }; + + DirectionBox.prototype.updateWithKeys = function(direction) { + this.yaw.updateWithKeys(direction); + this.pitch.updateWithKeys(direction); + }; + + DirectionBox.prototype.highlight = function() { + this.pitch.highlight(); + this.yaw.highlight(); + + this.highlighted = true; + }; + + DirectionBox.prototype.unhighlight = function() { + this.pitch.unhighlight(); + this.yaw.unhighlight(); + + this.highlighted = false; + }; DirectionBox.prototype.setterFromWidget = function(value) { var yawPitch = this.getValue(); this.onValueChanged(yawPitch); }; - - // Public members: + + DirectionBox.prototype.onValueChanged = function(value) {}; + DirectionBox.prototype.setValue = function(direction) { var flatXZ = Math.sqrt(direction.x * direction.x + direction.z * direction.z); if (flatXZ > 0.0) { @@ -516,13 +585,8 @@ } this.pitch.setValue(direction.y); }; - - DirectionBox.prototype.reset = function(resetValue) { - this.setValue(resetValue); - this.onValueChanged(resetValue); - }; - - DirectionBox.prototype.getValue = function() { + + DirectionBox.prototype.getValue = function() { var dirZ = this.pitch.getValue(); var yaw = this.yaw.getValue() * Math.PI / 180; var cosY = Math.sqrt(1 - dirZ*dirZ); @@ -530,6 +594,11 @@ return value; }; + DirectionBox.prototype.reset = function(resetValue) { + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; + DirectionBox.prototype.getHeight = function() { if(!this.visible) { return 0; @@ -564,7 +633,6 @@ this.pitch.destroy(); }; - DirectionBox.prototype.onValueChanged = function(value) {}; this.DirectionBox = DirectionBox; var textFontSize = 12; @@ -577,15 +645,14 @@ var topMargin = (height - 1.5 * textFontSize); - this.thumb = Overlays.addOverlay("text", { - backgroundColor: { red: 220, green: 220, blue: 220 }, - textFontSize: 10, + this.thumb = Overlays.addOverlay("image", { + color: {red: 255, green: 255, blue: 255}, + imageURL: HIFI_PUBLIC_BUCKET + 'images/tools/min-max-toggle.svg', x: x, y: y, width: rawHeight, height: rawHeight, alpha: 1.0, - backgroundAlpha: 1.0, visible: true }); @@ -644,13 +711,12 @@ if (this.widget != null) { this.widget.moveDown(); } - } - this.CollapsablePanelItem = CollapsablePanelItem; var PanelItem = function (name, setter, getter, displayer, x, y, textWidth, valueWidth, height) { //print("creating panel item: " + name); + this.isCollapsable = false; this.name = name; this.y = y; @@ -780,14 +846,23 @@ var widgetWidth = 300; var rawHeight = 20; var rawYDelta = rawHeight * 1.5; + var outerPanel = true; + var widgets; + var Panel = function(x, y) { - + + if (outerPanel) { + widgets = []; + } + outerPanel = false; + this.x = x; this.y = y; + this.nextY = y; - this.nextY = y; print("creating panel at x: " + this.x + " y: " + this.y); - + print("creating panel at x: " + this.x + " y: " + this.y); + this.widgetX = x + textWidth + valueWidth; this.items = new Array(); @@ -826,12 +901,20 @@ } } }; + + Panel.prototype.mouseReleaseEvent = function(event) { + if (this.activeWidget) { + this.activeWidget.onMouseReleaseEvent(event); + } + this.activeWidget = null; + }; // Reset panel item upon double-clicking Panel.prototype.mouseDoublePressEvent = function(event) { var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); this.handleReset(clickedOverlay); - } + }; + Panel.prototype.handleReset = function (clickedOverlay) { for (var i in this.items) { @@ -845,16 +928,13 @@ if (clickedOverlay == item.title) { item.activeWidget = widget; - item.activeWidget.reset(item.resetValue); - break; } } }; Panel.prototype.handleCollapse = function (clickedOverlay) { - for (var i in this.items) { var item = this.items[i]; @@ -886,19 +966,14 @@ panel.hide(); break; } - } - // Now recalculate new heights of subsequent widgets for(var j = i + 1; j < keys.length; ++j) { this.items[keys[j]].moveUp(this.getCurrentY(keys[j])); - } - }; - Panel.prototype.expand = function (clickedOverlay) { var keys = Object.keys(this.items); @@ -910,23 +985,13 @@ panel.show(); break; } - - } - - // Now recalculate new heights of subsequent widgets + } + // Now recalculate new heights of subsequent widgets for(var j = i + 1; j < keys.length; ++j) { this.items[keys[j]].moveDown(); } + }; - }; - - - Panel.prototype.mouseReleaseEvent = function(event) { - if (this.activeWidget) { - this.activeWidget.onMouseReleaseEvent(event); - } - this.activeWidget = null; - }; Panel.prototype.onMousePressEvent = function(event, clickedOverlay) { for (var i in this.items) { @@ -938,7 +1003,6 @@ } }; - Panel.prototype.onMouseMoveEvent = function(event) { for (var i in this.items) { var item = this.items[i]; @@ -966,7 +1030,63 @@ } } }; - + + var tabView = false; + var tabIndex = 0; + + Panel.prototype.keyPressEvent = function(event) { + if(event.text == "TAB" && !event.isShifted) { + tabView = true; + if(tabIndex < widgets.length) { + if(tabIndex > 0 && widgets[tabIndex - 1].highlighted) { + // Unhighlight previous widget + widgets[tabIndex - 1].unhighlight(); + } + widgets[tabIndex].highlight(); + tabIndex++; + } else { + widgets[tabIndex - 1].unhighlight(); + //Wrap around to front + tabIndex = 0; + widgets[tabIndex].highlight(); + tabIndex++; + } + } else if (tabView && event.isShifted) { + if(tabIndex > 0) { + tabIndex--; + if(tabIndex < widgets.length && widgets[tabIndex + 1].highlighted) { + // Unhighlight previous widget + widgets[tabIndex + 1].unhighlight(); + } + widgets[tabIndex].highlight(); + } else { + widgets[tabIndex].unhighlight(); + //Wrap around to end + tabIndex = widgets.length - 1; + widgets[tabIndex].highlight(); + } + } else if (event.text == "LEFT") { + for(var i = 0; i < widgets.length; i++) { + // Find the highlighted widget, allow control with arrow keys + if(widgets[i].highlighted) { + var k = -1; + widgets[i].updateWithKeys(k); + break; + } + } + } else if (event.text == "RIGHT") { + for(var i = 0; i < widgets.length; i++) { + // Find the highlighted widget, allow control with arrow keys + if(widgets[i].highlighted) { + var k = 1; + widgets[i].updateWithKeys(k); + break; + } + } + } + }; + + // Widget constructors Panel.prototype.newSlider = function(name, minValue, maxValue, setValue, getValue, displayValue) { this.nextY = this.y + this.getHeight(); @@ -974,6 +1094,7 @@ var slider = new Slider(this.widgetX, this.nextY, widgetWidth, rawHeight); slider.minValue = minValue; slider.maxValue = maxValue; + widgets.push(slider); item.widget = slider; item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; @@ -995,6 +1116,7 @@ var item = new PanelItem(name, setValue, getValue, display, this.x, this.nextY, textWidth, valueWidth, rawHeight); var checkbox = new Checkbox(this.widgetX, this.nextY, widgetWidth, rawHeight); + widgets.push(checkbox); item.widget = checkbox; item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; @@ -1010,6 +1132,7 @@ var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); var colorBox = new ColorBox(this.widgetX, this.nextY, widgetWidth, rawHeight); + widgets.push(colorBox); item.widget = colorBox; item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; @@ -1025,6 +1148,7 @@ var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); var directionBox = new DirectionBox(this.widgetX, this.nextY, widgetWidth, rawHeight); + widgets.push(directionBox); item.widget = directionBox; item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; @@ -1034,10 +1158,8 @@ // print("created Item... directionBox=" + name); }; - - Panel.prototype.newSubPanel = function(name) { - //TODO: make collapsable, fix double-press event + this.nextY = this.y + this.getHeight(); var item = new CollapsablePanelItem(name, this.x, this.nextY, textWidth, rawHeight, panel); @@ -1093,22 +1215,14 @@ return false; }; - Panel.prototype.getHeight = function(show) { + Panel.prototype.getHeight = function() { var height = 0; for (var i in this.items) { - height += this.items[i].widget.getHeight(); - // if(show) { - // print("widget: " + i + " height: " + this.items[i].widget.getHeight()); - - // } if(this.items[i].isSubPanel && this.items[i].widget.visible) { - - height += 1.5 * rawHeight; - - } - + height += 1.5 * rawHeight; + } } return height; @@ -1118,7 +1232,6 @@ for (var i in this.items) { this.items[i].widget.moveUp(); } - }; Panel.prototype.moveDown = function() { @@ -1141,7 +1254,6 @@ } } - return this.y + height; }; @@ -1177,6 +1289,5 @@ } }; - this.Panel = Panel; })(); \ No newline at end of file From d9693796bc06a77eb38c1c7fede2eb26d077f3c9 Mon Sep 17 00:00:00 2001 From: bwent Date: Tue, 28 Jul 2015 12:27:37 -0700 Subject: [PATCH 24/74] Capture key events --- examples/utilities/tools/cookies.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index b2dc8c1da7..175d8c2393 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -1288,6 +1288,15 @@ var CHECK_MARK_COLOR = { this.items[i].destroy(); } }; - this.Panel = Panel; -})(); \ No newline at end of file +})(); + + +Script.scriptEnding.connect(function scriptEnding() { + Controller.releaseKeyEvents({text: "left"}); + Controller.releaseKeyEvents({key: "right"}); +}); + + +Controller.captureKeyEvents({text: "left"}); +Controller.captureKeyEvents({text: "right"}); \ No newline at end of file From 2be95997d16ed572aac938af45393f8b8fbcfad1 Mon Sep 17 00:00:00 2001 From: bwent Date: Tue, 28 Jul 2015 12:32:14 -0700 Subject: [PATCH 25/74] clean up formatting --- examples/utilities/tools/cookies.js | 1317 +++++++++++++++------------ 1 file changed, 749 insertions(+), 568 deletions(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 175d8c2393..24cda69ba2 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -30,204 +30,230 @@ var CHECK_MARK_COLOR = { }; // The Slider class -(function () { - var Slider = function(x,y,width,thumbSize) { - +(function() { + var Slider = function(x, y, width, thumbSize) { + this.background = Overlays.addOverlay("text", { - backgroundColor: { red: 200, green: 200, blue: 255 }, - x: x, - y: y, - width: width, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true - }); + backgroundColor: { + red: 200, + green: 200, + blue: 255 + }, + x: x, + y: y, + width: width, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true + }); this.thumb = Overlays.addOverlay("text", { - backgroundColor: THUMB_COLOR, - x: x, - y: y, - width: thumbSize, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 1.0, - visible: true - }); - + backgroundColor: THUMB_COLOR, + x: x, + y: y, + width: thumbSize, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 1.0, + visible: true + }); + this.thumbSize = thumbSize; - + this.thumbHalfSize = 0.5 * thumbSize; - + this.minThumbX = x + this.thumbHalfSize; this.maxThumbX = x + width - this.thumbHalfSize; this.thumbX = this.minThumbX; - + this.minValue = 0.0; this.maxValue = 1.0; this.y = y; - + this.clickOffsetX = 0; this.isMoving = false; this.visible = true; }; - - Slider.prototype.updateThumb = function() { - var thumbTruePos = this.thumbX - 0.5 * this.thumbSize; - Overlays.editOverlay(this.thumb, { x: thumbTruePos } ); - }; - - Slider.prototype.isClickableOverlayItem = function(item) { - return (item == this.thumb) || (item == this.background); - }; - - - Slider.prototype.onMousePressEvent = function(event, clickedOverlay) { - if (!this.isClickableOverlayItem(clickedOverlay)) { - this.isMoving = false; - return; - } - this.highlight(); - this.isMoving = true; - var clickOffset = event.x - this.thumbX; - if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { - this.clickOffsetX = clickOffset; - } else { - this.clickOffsetX = 0; - this.thumbX = event.x; - this.updateThumb(); - this.onValueChanged(this.getValue()); - } - }; - Slider.prototype.onMouseMoveEvent = function(event) { - if (this.isMoving) { - var newThumbX = event.x - this.clickOffsetX; - if (newThumbX < this.minThumbX) { - newThumbX = this.minThumbX; - } - if (newThumbX > this.maxThumbX) { - newThumbX = this.maxThumbX; - } - this.thumbX = newThumbX; - this.updateThumb(); - this.onValueChanged(this.getValue()); - } - }; - - Slider.prototype.onMouseReleaseEvent = function(event) { + Slider.prototype.updateThumb = function() { + var thumbTruePos = this.thumbX - 0.5 * this.thumbSize; + Overlays.editOverlay(this.thumb, { + x: thumbTruePos + }); + }; + + Slider.prototype.isClickableOverlayItem = function(item) { + return (item == this.thumb) || (item == this.background); + }; + + + Slider.prototype.onMousePressEvent = function(event, clickedOverlay) { + if (!this.isClickableOverlayItem(clickedOverlay)) { this.isMoving = false; - this.unhighlight(); - }; + return; + } + this.highlight(); + this.isMoving = true; + var clickOffset = event.x - this.thumbX; + if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { + this.clickOffsetX = clickOffset; + } else { + this.clickOffsetX = 0; + this.thumbX = event.x; + this.updateThumb(); + this.onValueChanged(this.getValue()); + } + }; + + Slider.prototype.onMouseMoveEvent = function(event) { + if (this.isMoving) { + var newThumbX = event.x - this.clickOffsetX; + if (newThumbX < this.minThumbX) { + newThumbX = this.minThumbX; + } + if (newThumbX > this.maxThumbX) { + newThumbX = this.maxThumbX; + } + this.thumbX = newThumbX; + this.updateThumb(); + this.onValueChanged(this.getValue()); + } + }; + + Slider.prototype.onMouseReleaseEvent = function(event) { + this.isMoving = false; + this.unhighlight(); + }; Slider.prototype.updateWithKeys = function(direction) { this.range = this.maxThumbX - this.minThumbX; this.thumbX += direction * (this.range / SCALE); this.updateThumb(); this.onValueChanged(this.getValue()); - }; + }; Slider.prototype.highlight = function() { - if(this.highlighted) { + if (this.highlighted) { return; } Overlays.editOverlay(this.thumb, { - backgroundColor: {red: 255, green: 255, blue: 255} + backgroundColor: { + red: 255, + green: 255, + blue: 255 + } }); - this.highlighted = true; + this.highlighted = true; }; Slider.prototype.unhighlight = function() { - if(!this.highlighted) { + if (!this.highlighted) { return; } Overlays.editOverlay(this.thumb, { backgroundColor: THUMB_COLOR - }); + }); this.highlighted = false; }; Slider.prototype.setNormalizedValue = function(value) { - if (value < 0.0) { - this.thumbX = this.minThumbX; - } else if (value > 1.0) { - this.thumbX = this.maxThsumbX; - } else { - this.thumbX = value * (this.maxThumbX - this.minThumbX) + this.minThumbX; - } - this.updateThumb(); - }; + if (value < 0.0) { + this.thumbX = this.minThumbX; + } else if (value > 1.0) { + this.thumbX = this.maxThsumbX; + } else { + this.thumbX = value * (this.maxThumbX - this.minThumbX) + this.minThumbX; + } + this.updateThumb(); + }; Slider.prototype.getNormalizedValue = function() { - return (this.thumbX - this.minThumbX) / (this.maxThumbX - this.minThumbX); - }; - + return (this.thumbX - this.minThumbX) / (this.maxThumbX - this.minThumbX); + }; + Slider.prototype.setValue = function(value) { - var normValue = (value - this.minValue) / (this.maxValue - this.minValue); - this.setNormalizedValue(normValue); - }; + var normValue = (value - this.minValue) / (this.maxValue - this.minValue); + this.setNormalizedValue(normValue); + }; Slider.prototype.getValue = function() { - return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; - }; - + return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; + }; + Slider.prototype.reset = function(resetValue) { - this.setValue(resetValue); - this.onValueChanged(resetValue); - }; + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; Slider.prototype.onValueChanged = function(value) {}; Slider.prototype.getHeight = function() { - if(!this.visible) { - return 0; - } - return 1.5 * this.thumbSize; - }; + if (!this.visible) { + return 0; + } + return 1.5 * this.thumbSize; + }; Slider.prototype.moveUp = function(newY) { - Overlays.editOverlay(this.background, {y: newY}); - Overlays.editOverlay(this.thumb, {y: newY}); + Overlays.editOverlay(this.background, { + y: newY + }); + Overlays.editOverlay(this.thumb, { + y: newY + }); }; Slider.prototype.moveDown = function() { - Overlays.editOverlay(this.background, {y: this.y}); - Overlays.editOverlay(this.thumb, {y: this.y}); + Overlays.editOverlay(this.background, { + y: this.y + }); + Overlays.editOverlay(this.thumb, { + y: this.y + }); }; Slider.prototype.hide = function() { - Overlays.editOverlay(this.background, {visible: false}); - Overlays.editOverlay(this.thumb, {visible: false}); - this.visible = false; - }; + Overlays.editOverlay(this.background, { + visible: false + }); + Overlays.editOverlay(this.thumb, { + visible: false + }); + this.visible = false; + }; Slider.prototype.show = function() { - Overlays.editOverlay(this.background, {visible: true}); - Overlays.editOverlay(this.thumb, {visible: true}); - this.visible = true; - }; + Overlays.editOverlay(this.background, { + visible: true + }); + Overlays.editOverlay(this.thumb, { + visible: true + }); + this.visible = true; + }; Slider.prototype.destroy = function() { - Overlays.deleteOverlay(this.background); - Overlays.deleteOverlay(this.thumb); - }; + Overlays.deleteOverlay(this.background); + Overlays.deleteOverlay(this.thumb); + }; this.Slider = Slider; - + // The Checkbox class - var Checkbox = function(x,y,width,thumbSize) { - + var Checkbox = function(x, y, width, thumbSize) { + this.thumb = Overlays.addOverlay("text", { - backgroundColor: THUMB_COLOR, - textFontSize: 10, - x: x, - y: y, - width: thumbSize, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 1.0, - visible: true - }); - - + backgroundColor: THUMB_COLOR, + textFontSize: 10, + x: x, + y: y, + width: thumbSize, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 1.0, + visible: true + }); + + this.thumbSize = thumbSize; var checkX = x + (0.25 * thumbSize); var checkY = y + (0.25 * thumbSize); @@ -235,173 +261,217 @@ var CHECK_MARK_COLOR = { this.boxCheckStatus = true; this.clickedBox = false; this.visible = true; - - + + this.checkMark = Overlays.addOverlay("text", { - backgroundColor: CHECK_MARK_COLOR, - x: checkX, - y: checkY, - width: thumbSize / 2.0, - height: thumbSize / 2.0, - alpha: 1.0, - visible: true - }); + backgroundColor: CHECK_MARK_COLOR, + x: checkX, + y: checkY, + width: thumbSize / 2.0, + height: thumbSize / 2.0, + alpha: 1.0, + visible: true + }); }; - - Checkbox.prototype.updateThumb = function() { - Overlays.editOverlay(this.checkMark, { visible: this.boxCheckStatus }); - }; - + + Checkbox.prototype.updateThumb = function() { + Overlays.editOverlay(this.checkMark, { + visible: this.boxCheckStatus + }); + }; + Checkbox.prototype.isClickableOverlayItem = function(item) { - return (item == this.thumb) || (item == this.checkMark); - }; - + return (item == this.thumb) || (item == this.checkMark); + }; + Checkbox.prototype.onMousePressEvent = function(event, clickedOverlay) { - if (!this.isClickableOverlayItem(clickedOverlay)) { - return; - } - this.boxCheckStatus = !this.boxCheckStatus; - this.onValueChanged(this.getValue()); - this.updateThumb(); - }; - + if (!this.isClickableOverlayItem(clickedOverlay)) { + return; + } + this.boxCheckStatus = !this.boxCheckStatus; + this.onValueChanged(this.getValue()); + this.updateThumb(); + }; + Checkbox.prototype.onMouseReleaseEvent = function(event) {}; Checkbox.prototype.updateWithKeys = function() { this.boxCheckStatus = !this.boxCheckStatus; this.onValueChanged(this.getValue()); this.updateThumb(); - }; + }; Checkbox.prototype.highlight = function() { Overlays.editOverlay(this.thumb, { backgroundColor: THUMB_HIGHLIGHT }); - this.highlighted = true; - }; + this.highlighted = true; + }; Checkbox.prototype.unhighlight = function() { Overlays.editOverlay(this.thumb, { backgroundColor: THUMB_COLOR - }); + }); this.highlighted = false; - }; - + }; + Checkbox.prototype.setValue = function(value) { - this.boxCheckStatus = value; - }; + this.boxCheckStatus = value; + }; Checkbox.prototype.setterFromWidget = function(value) { - this.updateThumb(); - }; + this.updateThumb(); + }; Checkbox.prototype.getValue = function() { - return this.boxCheckStatus; - }; - - Checkbox.prototype.reset = function(resetValue) { - this.setValue(resetValue); - }; + return this.boxCheckStatus; + }; + + Checkbox.prototype.reset = function(resetValue) { + this.setValue(resetValue); + }; + + Checkbox.prototype.onValueChanged = function(value) {}; - Checkbox.prototype.onValueChanged = function(value) { }; - Checkbox.prototype.getHeight = function() { - if(!this.visible) { + if (!this.visible) { return 0; } - return 1.5 * this.thumbSize; - }; + return 1.5 * this.thumbSize; + }; Checkbox.prototype.moveUp = function(newY) { - Overlays.editOverlay(this.background, {y: newY}); - Overlays.editOverlay(this.thumb, {y: newY}); - Overlays.editOverlay(this.checkMark, {y: newY}); - Overlays.editOverlay(this.unCheckMark, {y: newY}); + Overlays.editOverlay(this.background, { + y: newY + }); + Overlays.editOverlay(this.thumb, { + y: newY + }); + Overlays.editOverlay(this.checkMark, { + y: newY + }); + Overlays.editOverlay(this.unCheckMark, { + y: newY + }); }; Checkbox.prototype.moveDown = function() { - Overlays.editOverlay(this.background, {y: this.y}); - Overlays.editOverlay(this.thumb, {y: this.y}); - Overlays.editOverlay(this.checkMark, {y: this.y}); - Overlays.editOverlay(this.unCheckMark, {y: this.y}); + Overlays.editOverlay(this.background, { + y: this.y + }); + Overlays.editOverlay(this.thumb, { + y: this.y + }); + Overlays.editOverlay(this.checkMark, { + y: this.y + }); + Overlays.editOverlay(this.unCheckMark, { + y: this.y + }); }; Checkbox.prototype.hide = function() { - Overlays.editOverlay(this.background, {visible: false}); - Overlays.editOverlay(this.thumb, {visible: false}); - Overlays.editOverlay(this.checkMark, {visible: false}); - Overlays.editOverlay(this.unCheckMark, {visible: false}); + Overlays.editOverlay(this.background, { + visible: false + }); + Overlays.editOverlay(this.thumb, { + visible: false + }); + Overlays.editOverlay(this.checkMark, { + visible: false + }); + Overlays.editOverlay(this.unCheckMark, { + visible: false + }); this.visible = false; } Checkbox.prototype.show = function() { - Overlays.editOverlay(this.background, {visible: true}); - Overlays.editOverlay(this.thumb, {visible: true}); - Overlays.editOverlay(this.checkMark, {visible: true}); - Overlays.editOverlay(this.unCheckMark, {visible: true}); + Overlays.editOverlay(this.background, { + visible: true + }); + Overlays.editOverlay(this.thumb, { + visible: true + }); + Overlays.editOverlay(this.checkMark, { + visible: true + }); + Overlays.editOverlay(this.unCheckMark, { + visible: true + }); this.visible = true; } - + Checkbox.prototype.destroy = function() { - Overlays.deleteOverlay(this.background); - Overlays.deleteOverlay(this.thumb); - Overlays.deleteOverlay(this.checkMark); - Overlays.deleteOverlay(this.unCheckMark); - }; + Overlays.deleteOverlay(this.background); + Overlays.deleteOverlay(this.thumb); + Overlays.deleteOverlay(this.checkMark); + Overlays.deleteOverlay(this.unCheckMark); + }; this.Checkbox = Checkbox; - + // The ColorBox class - var ColorBox = function(x,y,width,thumbSize) { + var ColorBox = function(x, y, width, thumbSize) { var self = this; - + var slideHeight = thumbSize / 3; var sliderWidth = width; this.red = new Slider(x, y, width, slideHeight); this.green = new Slider(x, y + slideHeight, width, slideHeight); this.blue = new Slider(x, y + 2 * slideHeight, width, slideHeight); - this.red.setBackgroundColor({x: 1, y: 0, z: 0}); - this.green.setBackgroundColor({x: 0, y: 1, z: 0}); - this.blue.setBackgroundColor({x: 0, y: 0, z: 1}); - + this.red.setBackgroundColor({ + x: 1, + y: 0, + z: 0 + }); + this.green.setBackgroundColor({ + x: 0, + y: 1, + z: 0 + }); + this.blue.setBackgroundColor({ + x: 0, + y: 0, + z: 1 + }); + this.red.onValueChanged = this.setterFromWidget; this.green.onValueChanged = this.setterFromWidget; this.blue.onValueChanged = this.setterFromWidget; this.visible = true; }; - - ColorBox.prototype.isClickableOverlayItem = function(item) { - return this.red.isClickableOverlayItem(item) - || this.green.isClickableOverlayItem(item) - || this.blue.isClickableOverlayItem(item); - }; - - ColorBox.prototype.onMousePressEvent = function(event, clickedOverlay) { - this.red.onMousePressEvent(event, clickedOverlay); - if (this.red.isMoving) { - return; - } - - this.green.onMousePressEvent(event, clickedOverlay); - if (this.green.isMoving) { - return; - } - - this.blue.onMousePressEvent(event, clickedOverlay); - }; - ColorBox.prototype.onMouseMoveEvent = function(event) { - this.red.onMouseMoveEvent(event); - this.green.onMouseMoveEvent(event); - this.blue.onMouseMoveEvent(event); - }; - + ColorBox.prototype.isClickableOverlayItem = function(item) { + return this.red.isClickableOverlayItem(item) || this.green.isClickableOverlayItem(item) || this.blue.isClickableOverlayItem(item); + }; + + ColorBox.prototype.onMousePressEvent = function(event, clickedOverlay) { + this.red.onMousePressEvent(event, clickedOverlay); + if (this.red.isMoving) { + return; + } + + this.green.onMousePressEvent(event, clickedOverlay); + if (this.green.isMoving) { + return; + } + + this.blue.onMousePressEvent(event, clickedOverlay); + }; + + ColorBox.prototype.onMouseMoveEvent = function(event) { + this.red.onMouseMoveEvent(event); + this.green.onMouseMoveEvent(event); + this.blue.onMouseMoveEvent(event); + }; + ColorBox.prototype.onMouseReleaseEvent = function(event) { - this.red.onMouseReleaseEvent(event); - this.green.onMouseReleaseEvent(event); - this.blue.onMouseReleaseEvent(event); - }; + this.red.onMouseReleaseEvent(event); + this.green.onMouseReleaseEvent(event); + this.blue.onMouseReleaseEvent(event); + }; ColorBox.prototype.updateWithKeys = function(direction) { this.red.updateWithKeys(direction); @@ -412,7 +482,7 @@ var CHECK_MARK_COLOR = { ColorBox.prototype.highlight = function() { this.red.highlight(); this.green.highlight(); - this.blue.highlight(); + this.blue.highlight(); this.highlighted = true; }; @@ -426,44 +496,60 @@ var CHECK_MARK_COLOR = { }; ColorBox.prototype.setterFromWidget = function(value) { - var color = this.getValue(); - this.onValueChanged(color); - this.updateRGBSliders(color); - }; + var color = this.getValue(); + this.onValueChanged(color); + this.updateRGBSliders(color); + }; ColorBox.prototype.onValueChanged = function(value) {}; - + ColorBox.prototype.updateRGBSliders = function(color) { - this.red.setThumbColor({x: color.x, y: 0, z: 0}); - this.green.setThumbColor({x: 0, y: color.y, z: 0}); - this.blue.setThumbColor({x: 0, y: 0, z: color.z}); - }; - - // Public members: + this.red.setThumbColor({ + x: color.x, + y: 0, + z: 0 + }); + this.green.setThumbColor({ + x: 0, + y: color.y, + z: 0 + }); + this.blue.setThumbColor({ + x: 0, + y: 0, + z: color.z + }); + }; + + // Public members: ColorBox.prototype.setValue = function(value) { - this.red.setValue(value.x); - this.green.setValue(value.y); - this.blue.setValue(value.z); - this.updateRGBSliders(value); - }; + this.red.setValue(value.x); + this.green.setValue(value.y); + this.blue.setValue(value.z); + this.updateRGBSliders(value); + }; ColorBox.prototype.getValue = function() { - var value = {x:this.red.getValue(), y:this.green.getValue(),z:this.blue.getValue()}; - return value; + var value = { + x: this.red.getValue(), + y: this.green.getValue(), + z: this.blue.getValue() }; + return value; + }; ColorBox.prototype.reset = function(resetValue) { - this.setValue(resetValue); - this.onValueChanged(resetValue); - }; + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; + - ColorBox.prototype.getHeight = function() { - if(!this.visible) { + if (!this.visible) { return 0; } - return 1.5 * this.thumbSize; - }; + return 1.5 * this.thumbSize; + }; ColorBox.prototype.moveUp = function(newY) { this.red.moveUp(newY); @@ -490,121 +576,132 @@ var CHECK_MARK_COLOR = { this.blue.show(); this.visible = true; } - + ColorBox.prototype.destroy = function() { - this.red.destroy(); - this.green.destroy(); - this.blue.destroy(); - }; + this.red.destroy(); + this.green.destroy(); + this.blue.destroy(); + }; this.ColorBox = ColorBox; - + // The DirectionBox class - var DirectionBox = function(x,y,width,thumbSize) { + var DirectionBox = function(x, y, width, thumbSize) { var self = this; - + var slideHeight = thumbSize / 2; var sliderWidth = width; this.yaw = new Slider(x, y, width, slideHeight); this.pitch = new Slider(x, y + slideHeight, width, slideHeight); - - - this.yaw.setThumbColor({x: 1, y: 0, z: 0}); + + + this.yaw.setThumbColor({ + x: 1, + y: 0, + z: 0 + }); this.yaw.minValue = -180; this.yaw.maxValue = +180; - - this.pitch.setThumbColor({x: 0, y: 0, z: 1}); + + this.pitch.setThumbColor({ + x: 0, + y: 0, + z: 1 + }); this.pitch.minValue = -1; this.pitch.maxValue = +1; - + this.yaw.onValueChanged = this.setterFromWidget; this.pitch.onValueChanged = this.setterFromWidget; this.visible = true; }; - - DirectionBox.prototype.isClickableOverlayItem = function(item) { - return this.yaw.isClickableOverlayItem(item) - || this.pitch.isClickableOverlayItem(item); - }; - - DirectionBox.prototype.onMousePressEvent = function(event, clickedOverlay) { - this.yaw.onMousePressEvent(event, clickedOverlay); - if (this.yaw.isMoving) { - return; - } - this.pitch.onMousePressEvent(event, clickedOverlay); - }; - DirectionBox.prototype.onMouseMoveEvent = function(event) { - this.yaw.onMouseMoveEvent(event); - this.pitch.onMouseMoveEvent(event); - }; - + DirectionBox.prototype.isClickableOverlayItem = function(item) { + return this.yaw.isClickableOverlayItem(item) || this.pitch.isClickableOverlayItem(item); + }; + + DirectionBox.prototype.onMousePressEvent = function(event, clickedOverlay) { + this.yaw.onMousePressEvent(event, clickedOverlay); + if (this.yaw.isMoving) { + return; + } + this.pitch.onMousePressEvent(event, clickedOverlay); + }; + + DirectionBox.prototype.onMouseMoveEvent = function(event) { + this.yaw.onMouseMoveEvent(event); + this.pitch.onMouseMoveEvent(event); + }; + DirectionBox.prototype.onMouseReleaseEvent = function(event) { - this.yaw.onMouseReleaseEvent(event); - this.pitch.onMouseReleaseEvent(event); - }; + this.yaw.onMouseReleaseEvent(event); + this.pitch.onMouseReleaseEvent(event); + }; DirectionBox.prototype.updateWithKeys = function(direction) { this.yaw.updateWithKeys(direction); this.pitch.updateWithKeys(direction); - }; + }; DirectionBox.prototype.highlight = function() { this.pitch.highlight(); this.yaw.highlight(); - + this.highlighted = true; - }; + }; DirectionBox.prototype.unhighlight = function() { this.pitch.unhighlight(); this.yaw.unhighlight(); - + this.highlighted = false; - }; - + }; + DirectionBox.prototype.setterFromWidget = function(value) { - var yawPitch = this.getValue(); - this.onValueChanged(yawPitch); - }; + var yawPitch = this.getValue(); + this.onValueChanged(yawPitch); + }; DirectionBox.prototype.onValueChanged = function(value) {}; DirectionBox.prototype.setValue = function(direction) { - var flatXZ = Math.sqrt(direction.x * direction.x + direction.z * direction.z); - if (flatXZ > 0.0) { - var flatX = direction.x / flatXZ; - var flatZ = direction.z / flatXZ; - var yaw = Math.acos(flatX) * 180 / Math.PI; - if (flatZ < 0) { - yaw = -yaw; - } - this.yaw.setValue(yaw); + var flatXZ = Math.sqrt(direction.x * direction.x + direction.z * direction.z); + if (flatXZ > 0.0) { + var flatX = direction.x / flatXZ; + var flatZ = direction.z / flatXZ; + var yaw = Math.acos(flatX) * 180 / Math.PI; + if (flatZ < 0) { + yaw = -yaw; } - this.pitch.setValue(direction.y); - }; + this.yaw.setValue(yaw); + } + this.pitch.setValue(direction.y); + }; - DirectionBox.prototype.getValue = function() { - var dirZ = this.pitch.getValue(); - var yaw = this.yaw.getValue() * Math.PI / 180; - var cosY = Math.sqrt(1 - dirZ*dirZ); - var value = {x:cosY * Math.cos(yaw), y:dirZ, z: cosY * Math.sin(yaw)}; - return value; + DirectionBox.prototype.getValue = function() { + var dirZ = this.pitch.getValue(); + var yaw = this.yaw.getValue() * Math.PI / 180; + var cosY = Math.sqrt(1 - dirZ * dirZ); + var value = { + x: cosY * Math.cos(yaw), + y: dirZ, + z: cosY * Math.sin(yaw) }; - + return value; + }; + DirectionBox.prototype.reset = function(resetValue) { - this.setValue(resetValue); - this.onValueChanged(resetValue); - }; - + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; + DirectionBox.prototype.getHeight = function() { - if(!this.visible) { + if (!this.visible) { return 0; } - return 1.5 * this.thumbSize; - }; + return 1.5 * this.thumbSize; + }; DirectionBox.prototype.moveUp = function(newY) { this.pitch.moveUp(newY); @@ -627,59 +724,73 @@ var CHECK_MARK_COLOR = { this.yaw.show(); this.visible = true; } - + DirectionBox.prototype.destroy = function() { - this.yaw.destroy(); - this.pitch.destroy(); - }; - + this.yaw.destroy(); + this.pitch.destroy(); + }; + this.DirectionBox = DirectionBox; - + var textFontSize = 12; - - var CollapsablePanelItem = function (name, x, y, textWidth, height) { + + var CollapsablePanelItem = function(name, x, y, textWidth, height) { this.name = name; this.height = height; this.y = y; this.isCollapsable = true; - + var topMargin = (height - 1.5 * textFontSize); - + this.thumb = Overlays.addOverlay("image", { - color: {red: 255, green: 255, blue: 255}, - imageURL: HIFI_PUBLIC_BUCKET + 'images/tools/min-max-toggle.svg', - x: x, - y: y, - width: rawHeight, - height: rawHeight, - alpha: 1.0, - visible: true - }); - + color: { + red: 255, + green: 255, + blue: 255 + }, + imageURL: HIFI_PUBLIC_BUCKET + 'images/tools/min-max-toggle.svg', + x: x, + y: y, + width: rawHeight, + height: rawHeight, + alpha: 1.0, + visible: true + }); + this.title = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: x + rawHeight * 1.5, - y: y, - width: textWidth, - height: height, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true, - text: " " + name, - font: {size: textFontSize}, - topMargin: topMargin - }); + backgroundColor: { + red: 255, + green: 255, + blue: 255 + }, + x: x + rawHeight * 1.5, + y: y, + width: textWidth, + height: height, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true, + text: " " + name, + font: { + size: textFontSize + }, + topMargin: topMargin + }); }; CollapsablePanelItem.prototype.destroy = function() { Overlays.deleteOverlay(this.title); Overlays.deleteOverlay(this.thumb); }; - - + + CollapsablePanelItem.prototype.hide = function() { - Overlays.editOverlay(this.title, {visible: false}); - Overlays.editOverlay(this.thumb, {visible: false}); + Overlays.editOverlay(this.title, { + visible: false + }); + Overlays.editOverlay(this.thumb, { + visible: false + }); if (this.widget != null) { this.widget.hide(); @@ -687,8 +798,12 @@ var CHECK_MARK_COLOR = { }; CollapsablePanelItem.prototype.show = function() { - Overlays.editOverlay(this.title, {visible: true}); - Overlays.editOverlay(this.thumb, {visible: true}); + Overlays.editOverlay(this.title, { + visible: true + }); + Overlays.editOverlay(this.thumb, { + visible: true + }); if (this.widget != null) { this.widget.show(); @@ -696,8 +811,12 @@ var CHECK_MARK_COLOR = { }; CollapsablePanelItem.prototype.moveUp = function(newY) { - Overlays.editOverlay(this.title, {y: newY}); - Overlays.editOverlay(this.thumb, {y: newY}); + Overlays.editOverlay(this.title, { + y: newY + }); + Overlays.editOverlay(this.thumb, { + y: newY + }); if (this.widget != null) { this.widget.moveUp(newY); @@ -705,74 +824,92 @@ var CHECK_MARK_COLOR = { } CollapsablePanelItem.prototype.moveDown = function() { - Overlays.editOverlay(this.title, {y: this.y}); - Overlays.editOverlay(this.thumb, {y: this.y}); + Overlays.editOverlay(this.title, { + y: this.y + }); + Overlays.editOverlay(this.thumb, { + y: this.y + }); if (this.widget != null) { this.widget.moveDown(); } } this.CollapsablePanelItem = CollapsablePanelItem; - - var PanelItem = function (name, setter, getter, displayer, x, y, textWidth, valueWidth, height) { + + var PanelItem = function(name, setter, getter, displayer, x, y, textWidth, valueWidth, height) { //print("creating panel item: " + name); this.isCollapsable = false; this.name = name; this.y = y; this.isCollapsed = false; - - this.displayer = typeof displayer !== 'undefined' ? displayer : function(value) { - if(value == true) { + + this.displayer = typeof displayer !== 'undefined' ? displayer : function(value) { + if (value == true) { return "On"; } else if (value == false) { return "Off"; } - return value.toFixed(2); + return value.toFixed(2); }; - + var topMargin = (height - 1.5 * textFontSize); this.title = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: x, - y: y, - width: textWidth, - height: height, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true, - text: " " + name, - font: {size: textFontSize}, - topMargin: topMargin - }); - + backgroundColor: { + red: 255, + green: 255, + blue: 255 + }, + x: x, + y: y, + width: textWidth, + height: height, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true, + text: " " + name, + font: { + size: textFontSize + }, + topMargin: topMargin + }); + this.value = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: x + textWidth, - y: y, - width: valueWidth, - height: height, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true, - text: this.displayer(getter()), - font: {size: textFontSize}, - topMargin: topMargin - }); - + backgroundColor: { + red: 255, + green: 255, + blue: 255 + }, + x: x + textWidth, + y: y, + width: valueWidth, + height: height, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true, + text: this.displayer(getter()), + font: { + size: textFontSize + }, + topMargin: topMargin + }); + this.getter = getter; this.resetValue = getter(); - + this.setter = function(value) { - + setter(value); - Overlays.editOverlay(this.value, {text: this.displayer(getter())}); + Overlays.editOverlay(this.value, { + text: this.displayer(getter()) + }); if (this.widget) { this.widget.setValue(value); - } - + } + //print("successfully set value of widget to " + value); }; this.setterFromWidget = function(value) { @@ -782,16 +919,22 @@ var CHECK_MARK_COLOR = { if (this.widget) { this.widget.setValue(value); - } - Overlays.editOverlay(this.value, {text: this.displayer(value)}); - }; - + } + Overlays.editOverlay(this.value, { + text: this.displayer(value) + }); + }; + this.widget = null; }; PanelItem.prototype.hide = function() { - Overlays.editOverlay(this.title, {visible: false}); - Overlays.editOverlay(this.value, {visible: false}); + Overlays.editOverlay(this.title, { + visible: false + }); + Overlays.editOverlay(this.value, { + visible: false + }); if (this.widget != null) { this.widget.hide(); @@ -800,8 +943,12 @@ var CHECK_MARK_COLOR = { PanelItem.prototype.show = function() { - Overlays.editOverlay(this.title, {visible: true}); - Overlays.editOverlay(this.value, {visible: true}); + Overlays.editOverlay(this.title, { + visible: true + }); + Overlays.editOverlay(this.value, { + visible: true + }); if (this.widget != null) { this.widget.show(); @@ -811,8 +958,12 @@ var CHECK_MARK_COLOR = { PanelItem.prototype.moveUp = function(newY) { - Overlays.editOverlay(this.title, {y: newY}); - Overlays.editOverlay(this.value, {y: newY}); + Overlays.editOverlay(this.title, { + y: newY + }); + Overlays.editOverlay(this.value, { + y: newY + }); if (this.widget != null) { this.widget.moveUp(newY); @@ -822,8 +973,12 @@ var CHECK_MARK_COLOR = { PanelItem.prototype.moveDown = function() { - Overlays.editOverlay(this.title, {y: this.y}); - Overlays.editOverlay(this.value, {y: this.y}); + Overlays.editOverlay(this.title, { + y: this.y + }); + Overlays.editOverlay(this.value, { + y: this.y + }); if (this.widget != null) { this.widget.moveDown(); @@ -832,15 +987,15 @@ var CHECK_MARK_COLOR = { }; PanelItem.prototype.destroy = function() { - Overlays.deleteOverlay(this.title); - Overlays.deleteOverlay(this.value); + Overlays.deleteOverlay(this.title); + Overlays.deleteOverlay(this.value); - if (this.widget != null) { - this.widget.destroy(); - } - }; + if (this.widget != null) { + this.widget.destroy(); + } + }; this.PanelItem = PanelItem; - + var textWidth = 180; var valueWidth = 100; var widgetWidth = 300; @@ -848,7 +1003,7 @@ var CHECK_MARK_COLOR = { var rawYDelta = rawHeight * 1.5; var outerPanel = true; var widgets; - + var Panel = function(x, y) { @@ -856,50 +1011,53 @@ var CHECK_MARK_COLOR = { widgets = []; } outerPanel = false; - + this.x = x; this.y = y; - this.nextY = y; + this.nextY = y; print("creating panel at x: " + this.x + " y: " + this.y); - - this.widgetX = x + textWidth + valueWidth; - + + this.widgetX = x + textWidth + valueWidth; + this.items = new Array(); this.activeWidget = null; this.visible = true; this.indentation = 30; }; - + Panel.prototype.mouseMoveEvent = function(event) { if (this.activeWidget) { this.activeWidget.onMouseMoveEvent(event); } }; - + Panel.prototype.mousePressEvent = function(event) { // Make sure we quitted previous widget if (this.activeWidget) { this.activeWidget.onMouseReleaseEvent(event); } - this.activeWidget = null; - - var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + this.activeWidget = null; + + var clickedOverlay = Overlays.getOverlayAtPoint({ + x: event.x, + y: event.y + }); this.handleCollapse(clickedOverlay); - + // If the user clicked any of the slider background then... for (var i in this.items) { var item = this.items[i]; var widget = this.items[i].widget; - + if (widget.isClickableOverlayItem(clickedOverlay)) { this.activeWidget = widget; - this.activeWidget.onMousePressEvent(event, clickedOverlay); + this.activeWidget.onMousePressEvent(event, clickedOverlay); break; - } - } + } + } }; Panel.prototype.mouseReleaseEvent = function(event) { @@ -907,39 +1065,42 @@ var CHECK_MARK_COLOR = { this.activeWidget.onMouseReleaseEvent(event); } this.activeWidget = null; - }; - - // Reset panel item upon double-clicking + }; + + // Reset panel item upon double-clicking Panel.prototype.mouseDoublePressEvent = function(event) { - var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + var clickedOverlay = Overlays.getOverlayAtPoint({ + x: event.x, + y: event.y + }); this.handleReset(clickedOverlay); }; - - Panel.prototype.handleReset = function (clickedOverlay) { + + Panel.prototype.handleReset = function(clickedOverlay) { for (var i in this.items) { - - var item = this.items[i]; + + var item = this.items[i]; var widget = item.widget; - + if (item.isSubPanel && widget) { widget.handleReset(clickedOverlay); } - + if (clickedOverlay == item.title) { item.activeWidget = widget; item.activeWidget.reset(item.resetValue); break; - } + } } }; - Panel.prototype.handleCollapse = function (clickedOverlay) { + Panel.prototype.handleCollapse = function(clickedOverlay) { for (var i in this.items) { - - var item = this.items[i]; + + var item = this.items[i]; var widget = item.widget; - + if (item.isSubPanel && widget) { widget.handleCollapse(clickedOverlay); } @@ -948,20 +1109,20 @@ var CHECK_MARK_COLOR = { this.collapse(clickedOverlay); item.isCollapsed = true; break; - } else if (item.isCollapsed && item.isCollapsable && clickedOverlay == item.thumb) { + } else if (item.isCollapsed && item.isCollapsable && clickedOverlay == item.thumb) { this.expand(clickedOverlay); item.isCollapsed = false; } } }; - Panel.prototype.collapse = function (clickedOverlay) { + Panel.prototype.collapse = function(clickedOverlay) { var keys = Object.keys(this.items); - + for (var i = 0; i < keys.length; ++i) { var item = this.items[keys[i]]; - if(item.isCollapsable && clickedOverlay == item.thumb) { + if (item.isCollapsable && clickedOverlay == item.thumb) { var panel = item.widget; panel.hide(); break; @@ -969,40 +1130,40 @@ var CHECK_MARK_COLOR = { } // Now recalculate new heights of subsequent widgets - for(var j = i + 1; j < keys.length; ++j) { + for (var j = i + 1; j < keys.length; ++j) { this.items[keys[j]].moveUp(this.getCurrentY(keys[j])); } }; - Panel.prototype.expand = function (clickedOverlay) { + Panel.prototype.expand = function(clickedOverlay) { var keys = Object.keys(this.items); - + for (var i = 0; i < keys.length; ++i) { var item = this.items[keys[i]]; - if(item.isCollapsable && clickedOverlay == item.thumb) { + if (item.isCollapsable && clickedOverlay == item.thumb) { var panel = item.widget; panel.show(); break; } - } - // Now recalculate new heights of subsequent widgets - for(var j = i + 1; j < keys.length; ++j) { + } + // Now recalculate new heights of subsequent widgets + for (var j = i + 1; j < keys.length; ++j) { this.items[keys[j]].moveDown(); } }; - + Panel.prototype.onMousePressEvent = function(event, clickedOverlay) { for (var i in this.items) { var item = this.items[i]; - if(item.widget.isClickableOverlayItem(clickedOverlay)) { + if (item.widget.isClickableOverlayItem(clickedOverlay)) { item.activeWidget = item.widget; - item.activeWidget.onMousePressEvent(event,clickedOverlay); + item.activeWidget.onMousePressEvent(event, clickedOverlay); } } }; - + Panel.prototype.onMouseMoveEvent = function(event) { for (var i in this.items) { var item = this.items[i]; @@ -1011,7 +1172,7 @@ var CHECK_MARK_COLOR = { } } }; - + Panel.prototype.onMouseReleaseEvent = function(event, clickedOverlay) { for (var i in this.items) { var item = this.items[i]; @@ -1021,7 +1182,7 @@ var CHECK_MARK_COLOR = { item.activeWidget = null; } }; - + Panel.prototype.onMouseDoublePressEvent = function(event, clickedOverlay) { for (var i in this.items) { var item = this.items[i]; @@ -1035,13 +1196,13 @@ var CHECK_MARK_COLOR = { var tabIndex = 0; Panel.prototype.keyPressEvent = function(event) { - if(event.text == "TAB" && !event.isShifted) { + if (event.text == "TAB" && !event.isShifted) { tabView = true; - if(tabIndex < widgets.length) { - if(tabIndex > 0 && widgets[tabIndex - 1].highlighted) { + if (tabIndex < widgets.length) { + if (tabIndex > 0 && widgets[tabIndex - 1].highlighted) { // Unhighlight previous widget widgets[tabIndex - 1].unhighlight(); - } + } widgets[tabIndex].highlight(); tabIndex++; } else { @@ -1052,32 +1213,32 @@ var CHECK_MARK_COLOR = { tabIndex++; } } else if (tabView && event.isShifted) { - if(tabIndex > 0) { + if (tabIndex > 0) { tabIndex--; - if(tabIndex < widgets.length && widgets[tabIndex + 1].highlighted) { + if (tabIndex < widgets.length && widgets[tabIndex + 1].highlighted) { // Unhighlight previous widget widgets[tabIndex + 1].unhighlight(); - } + } widgets[tabIndex].highlight(); } else { widgets[tabIndex].unhighlight(); //Wrap around to end tabIndex = widgets.length - 1; - widgets[tabIndex].highlight(); + widgets[tabIndex].highlight(); } } else if (event.text == "LEFT") { - for(var i = 0; i < widgets.length; i++) { + for (var i = 0; i < widgets.length; i++) { // Find the highlighted widget, allow control with arrow keys - if(widgets[i].highlighted) { + if (widgets[i].highlighted) { var k = -1; widgets[i].updateWithKeys(k); break; } } } else if (event.text == "RIGHT") { - for(var i = 0; i < widgets.length; i++) { + for (var i = 0; i < widgets.length; i++) { // Find the highlighted widget, allow control with arrow keys - if(widgets[i].highlighted) { + if (widgets[i].highlighted) { var k = 1; widgets[i].updateWithKeys(k); break; @@ -1095,93 +1256,105 @@ var CHECK_MARK_COLOR = { slider.minValue = minValue; slider.maxValue = maxValue; widgets.push(slider); - + item.widget = slider; - item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; - item.setter(getValue()); + item.widget.onValueChanged = function(value) { + item.setterFromWidget(value); + }; + item.setter(getValue()); this.items[name] = item; }; - + Panel.prototype.newCheckbox = function(name, setValue, getValue, displayValue) { var display; if (displayValue == true) { - display = function() {return "On";}; + display = function() { + return "On"; + }; } else if (displayValue == false) { - display = function() {return "Off";}; + display = function() { + return "Off"; + }; } - + this.nextY = this.y + this.getHeight(); - + var item = new PanelItem(name, setValue, getValue, display, this.x, this.nextY, textWidth, valueWidth, rawHeight); - + var checkbox = new Checkbox(this.widgetX, this.nextY, widgetWidth, rawHeight); widgets.push(checkbox); - + item.widget = checkbox; - item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; - item.setter(getValue()); - this.items[name] = item; - - //print("created Item... checkbox=" + name); - }; - - Panel.prototype.newColorBox = function(name, setValue, getValue, displayValue) { - this.nextY = this.y + this.getHeight(); - - var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); - - var colorBox = new ColorBox(this.widgetX, this.nextY, widgetWidth, rawHeight); - widgets.push(colorBox); - - item.widget = colorBox; - item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; - item.setter(getValue()); + item.widget.onValueChanged = function(value) { + item.setterFromWidget(value); + }; + item.setter(getValue()); this.items[name] = item; - // print("created Item... colorBox=" + name); + //print("created Item... checkbox=" + name); }; - + + Panel.prototype.newColorBox = function(name, setValue, getValue, displayValue) { + this.nextY = this.y + this.getHeight(); + + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); + + var colorBox = new ColorBox(this.widgetX, this.nextY, widgetWidth, rawHeight); + widgets.push(colorBox); + + item.widget = colorBox; + item.widget.onValueChanged = function(value) { + item.setterFromWidget(value); + }; + item.setter(getValue()); + this.items[name] = item; + + // print("created Item... colorBox=" + name); + }; + Panel.prototype.newDirectionBox = function(name, setValue, getValue, displayValue) { this.nextY = this.y + this.getHeight(); - + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); var directionBox = new DirectionBox(this.widgetX, this.nextY, widgetWidth, rawHeight); widgets.push(directionBox); - + item.widget = directionBox; - item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; - item.setter(getValue()); + item.widget.onValueChanged = function(value) { + item.setterFromWidget(value); + }; + item.setter(getValue()); this.items[name] = item; - - // print("created Item... directionBox=" + name); + + // print("created Item... directionBox=" + name); }; - + Panel.prototype.newSubPanel = function(name) { - + this.nextY = this.y + this.getHeight(); - + var item = new CollapsablePanelItem(name, this.x, this.nextY, textWidth, rawHeight, panel); item.isSubPanel = true; - + this.nextY += 1.5 * item.height; - + var subPanel = new Panel(this.x + this.indentation, this.nextY); - + item.widget = subPanel; this.items[name] = item; return subPanel; - // print("created Item... subPanel=" + name); + // print("created Item... subPanel=" + name); }; - + Panel.prototype.onValueChanged = function(value) { for (var i in this.items) { this.items[i].widget.onValueChanged(value); } }; - - + + Panel.prototype.set = function(name, value) { var item = this.items[name]; if (item != null) { @@ -1189,7 +1362,7 @@ var CHECK_MARK_COLOR = { } return null; }; - + Panel.prototype.get = function(name) { var item = this.items[name]; if (item != null) { @@ -1197,7 +1370,7 @@ var CHECK_MARK_COLOR = { } return null; }; - + Panel.prototype.update = function(name) { var item = this.items[name]; if (item != null) { @@ -1205,7 +1378,7 @@ var CHECK_MARK_COLOR = { } return null; }; - + Panel.prototype.isClickableOverlayItem = function(item) { for (var i in this.items) { if (this.items[i].widget.isClickableOverlayItem(item)) { @@ -1214,30 +1387,30 @@ var CHECK_MARK_COLOR = { } return false; }; - + Panel.prototype.getHeight = function() { var height = 0; - + for (var i in this.items) { - height += this.items[i].widget.getHeight(); - if(this.items[i].isSubPanel && this.items[i].widget.visible) { - height += 1.5 * rawHeight; - } + height += this.items[i].widget.getHeight(); + if (this.items[i].isSubPanel && this.items[i].widget.visible) { + height += 1.5 * rawHeight; + } } return height; }; Panel.prototype.moveUp = function() { - for (var i in this.items) { + for (var i in this.items) { this.items[i].widget.moveUp(); - } + } }; Panel.prototype.moveDown = function() { for (var i in this.items) { this.items[i].widget.moveDown(); - } + } }; Panel.prototype.getCurrentY = function(key) { @@ -1247,34 +1420,34 @@ var CHECK_MARK_COLOR = { for (var i = 0; i < keys.indexOf(key); ++i) { var item = this.items[keys[i]]; - height += item.widget.getHeight(); - - if(item.isSubPanel) { + height += item.widget.getHeight(); + + if (item.isSubPanel) { height += 1.5 * rawHeight; - - } + + } } return this.y + height; }; - + Panel.prototype.hide = function() { for (var i in this.items) { - if(this.items[i].isSubPanel) { + if (this.items[i].isSubPanel) { this.items[i].widget.hide(); } this.items[i].hide(); - } + } this.visible = false; }; Panel.prototype.show = function() { for (var i in this.items) { - if(this.items[i].isSubPanel) { + if (this.items[i].isSubPanel) { this.items[i].widget.show(); } this.items[i].show(); - } + } this.visible = true; }; @@ -1282,21 +1455,29 @@ var CHECK_MARK_COLOR = { Panel.prototype.destroy = function() { for (var i in this.items) { - if(this.items[i].isSubPanel) { + if (this.items[i].isSubPanel) { this.items[i].widget.destroy(); } this.items[i].destroy(); - } + } }; this.Panel = Panel; })(); Script.scriptEnding.connect(function scriptEnding() { - Controller.releaseKeyEvents({text: "left"}); - Controller.releaseKeyEvents({key: "right"}); + Controller.releaseKeyEvents({ + text: "left" + }); + Controller.releaseKeyEvents({ + key: "right" + }); }); -Controller.captureKeyEvents({text: "left"}); -Controller.captureKeyEvents({text: "right"}); \ No newline at end of file +Controller.captureKeyEvents({ + text: "left" +}); +Controller.captureKeyEvents({ + text: "right" +}); \ No newline at end of file From ccb3d433afb69e6ce391c7d302092143515a96f1 Mon Sep 17 00:00:00 2001 From: bwent Date: Fri, 24 Jul 2015 09:43:49 -0700 Subject: [PATCH 26/74] Example script solarsystem.js with orbiting satellite game --- examples/example/games/satellite.js | 279 +++++++++++++ examples/example/games/solarsystem.js | 554 ++++++++++++++++++++++++++ examples/utilities/tools/vector.js | 197 +++++++++ 3 files changed, 1030 insertions(+) create mode 100644 examples/example/games/satellite.js create mode 100644 examples/example/games/solarsystem.js create mode 100644 examples/utilities/tools/vector.js diff --git a/examples/example/games/satellite.js b/examples/example/games/satellite.js new file mode 100644 index 0000000000..d2e4dd2a99 --- /dev/null +++ b/examples/example/games/satellite.js @@ -0,0 +1,279 @@ +// +// satellite.js +// games +// +// Created by Bridget Went 7/1/2015. +// Copyright 2015 High Fidelity, Inc. +// +// A game to bring a satellite model into orbit around an animated earth model . +// - Double click to create a new satellite +// - Click on the satellite, drag a vector arrow to specify initial velocity +// - Release mouse to launch the active satellite +// - Orbital movement is calculated using equations of gravitational physics +// +// 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('../../utilities/tools/vector.js'); + +var URL = "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/"; + +SatelliteGame = function() { + var MAX_RANGE = 50.0; + var Y_AXIS = { + x: 0, + y: 1, + z: 0 + } + var LIFETIME = 6000; + + var v0; + var T = 4.0; + var M = 16000.0; + var m = M * 0.000000333; + var ERROR_THRESH = 20.0; + + // Create the spinning earth model + var EARTH_SIZE = 20.0; + var CLOUDS_OFFSET = 0.5; + var SPIN = 0.1; + var ZONE_DIM = 10.0; + var LIGHT_INTENSITY = 1.2; + + Earth = function(position, size) { + this.earth = Entities.addEntity({ + type: "Model", + shapeType: 'sphere', + modelURL: URL + "earth.fbx", + position: position, + dimensions: { + x: size, + y: size, + z: size + }, + rotation: Quat.angleAxis(180, {x: 1, y: 0, z: 0}), + angularVelocity: { x: 0.00, y: 0.5 * SPIN, z: 0.00 }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: 6000, + collisionsWillMove: false, + visible: true + }); + + this.clouds = Entities.addEntity({ + type: "Model", + shapeType: 'sphere', + modelURL: URL + "clouds.fbx?", + position: position, + dimensions: { + x: size + CLOUDS_OFFSET, + y: size + CLOUDS_OFFSET, + z: size + CLOUDS_OFFSET + }, + angularVelocity: { x: 0.00, y: SPIN, z: 0.00 }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false, + visible: true + }); + + this.zone = Entities.addEntity({ + type: "Zone", + position: position, + dimensions: { + x: ZONE_DIM, + y: ZONE_DIM, + z: ZONE_DIM + }, + keyLightDirection: Vec3.normalize(Vec3.subtract(position, Camera.getPosition())), + keyLightIntensity: LIGHT_INTENSITY + }); + + this.cleanup = function() { + Entities.deleteEntity(this.clouds); + Entities.deleteEntity(this.earth); + Entities.deleteEntity(this.zone); + } + } + + // Create earth model + var center = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE, Quat.getFront(Camera.getOrientation()))); + var distance = Vec3.length(Vec3.subtract(center, Camera.getPosition())); + var earth = new Earth(center, EARTH_SIZE); + + var satellites = []; + var SATELLITE_SIZE = 2.0; + var launched = false; + var activeSatellite; + + Satellite = function(position, planetCenter) { + // The Satellite class + + this.launched = false; + this.startPosition = position; + this.readyToLaunch = false; + this.radius = Vec3.length(Vec3.subtract(position, planetCenter)); + + this.satellite = Entities.addEntity({ + type: "Model", + modelURL: "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/satellite/satellite.fbx", + position: this.startPosition, + dimensions: { + x: SATELLITE_SIZE, + y: SATELLITE_SIZE, + z: SATELLITE_SIZE + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false, + }); + + this.getProperties = function() { + return Entities.getEntityProperties(this.satellite); + } + + this.launch = function() { + var prop = Entities.getEntityProperties(this.satellite); + var between = Vec3.subtract(planetCenter, prop.position); + var radius = Vec3.length(between); + this.G = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (M * T * T); + + var v0 = Vec3.normalize(Vec3.cross(between, Y_AXIS)); + v0 = Vec3.multiply(Math.sqrt((this.G * M) / radius), v0); + v0 = Vec3.multiply(this.arrow.magnitude, v0); + v0 = Vec3.multiply(Vec3.length(v0), this.arrow.direction); + + Entities.editEntity(this.satellite, { velocity: v0 }); + this.launched = true; + }; + + + this.update = function(deltaTime) { + var prop = Entities.getEntityProperties(this.satellite); + var between = Vec3.subtract(prop.position, planetCenter); + var radius = Vec3.length(between); + var a = -(this.G * M) * Math.pow(radius, (-2.0)); + var speed = a * deltaTime; + var vel = Vec3.multiply(speed, Vec3.normalize(between)); + + var newVelocity = Vec3.sum(prop.velocity, vel); + var newPos = Vec3.sum(prop.position, Vec3.multiply(newVelocity, deltaTime)); + + Entities.editEntity(this.satellite, { + velocity: newVelocity, + position: newPos + }); + }; + } + + function mouseDoublePressEvent(event) { + var pickRay = Camera.computePickRay(event.x, event.y); + var addVector = Vec3.multiply(pickRay.direction, distance); + var point = Vec3.sum(Camera.getPosition(), addVector); + + // Create a new satellite + activeSatellite = new Satellite(point, center); + satellites.push(activeSatellite); + } + + function mousePressEvent(event) { + if (!activeSatellite) { + return; + } + // Reset label + if (activeSatellite.arrow) { + activeSatellite.arrow.deleteLabel(); + } + var statsPosition = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE * 0.5, Quat.getFront(Camera.getOrientation()))); + var pickRay = Camera.computePickRay(event.x, event.y) + var rayPickResult = Entities.findRayIntersection(pickRay, true); + if (rayPickResult.entityID === activeSatellite.satellite) { + // Create a draggable vector arrow at satellite position + activeSatellite.arrow = new VectorArrow(distance, true, "INITIAL VELOCITY", statsPosition); + activeSatellite.arrow.onMousePressEvent(event); + activeSatellite.arrow.isDragging = true; + } + } + + function mouseMoveEvent(event) { + if(!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { + return; + } + activeSatellite.arrow.onMouseMoveEvent(event); + } + + function mouseReleaseEvent(event) { + if(!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { + return; + } + activeSatellite.arrow.onMouseReleaseEvent(event); + activeSatellite.launch(); + activeSatellite.arrow.cleanup(); + } + + var counter = 0.0; + var TIME = 500; + + function update(deltaTime) { + if(!activeSatellite) { + return; + } + // Update all satellites + for (var i = 0; i < satellites.length; i++) { + if (!satellites[i].launched) { + return; + } + satellites[i].update(deltaTime); + } + + counter++; + if (counter % TIME == 0) { + var prop = activeSatellite.getProperties(); + var error = calcEnergyError(prop.position, Vec3.length(prop.velocity)); + if (Math.abs(error) <= ERROR_THRESH) { + activeSatellite.arrow.editLabel("Nice job! The satellite has reached a stable orbit."); + } else { + activeSatellite.arrow.editLabel("Try again! The satellite is in an unstable orbit."); + } + } + } + + this.endGame = function() { + print("ending game"); + for(var i = 0; i < satellites.length; i++) { + Entities.deleteEntitiy(satellites[i].satellite); + satellites[i].arrow.cleanup(); + } + earth.cleanup(); + } + + + function calcEnergyError(pos, vel) { + //Calculate total energy error for active satellite's orbital motion + var radius = activeSatellite.radius; + var G = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (M * T * T); + var v0 = Math.sqrt((G * M) / radius); + + var totalEnergy = 0.5 * M * Math.pow(v0, 2.0) - ((G * M * m) / radius); + var measuredEnergy = 0.5 * M * Math.pow(vel, 2.0) - ((G * M * m) / Vec3.length(Vec3.subtract(pos, center))); + var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; + return error; + } + + Controller.mousePressEvent.connect(mousePressEvent); + Controller.mouseDoublePressEvent.connect(mouseDoublePressEvent); + Controller.mouseMoveEvent.connect(mouseMoveEvent); + Controller.mouseReleaseEvent.connect(mouseReleaseEvent); + Script.update.connect(update); + Script.scriptEnding.connect(this.endGame); + +} + + + diff --git a/examples/example/games/solarsystem.js b/examples/example/games/solarsystem.js new file mode 100644 index 0000000000..b651e551f0 --- /dev/null +++ b/examples/example/games/solarsystem.js @@ -0,0 +1,554 @@ +// +// solarsystem.js +// games +// +// Created by Bridget Went, 5/28/15. +// Copyright 2015 High Fidelity, Inc. +// +// The start to a project to build a virtual physics classroom to simulate the solar system, gravity, and orbital physics. +// A sun with oribiting planets is created in front of the user. UI elements allow for adjusting the period, gravity, trails, and energy recalculations. +// +// 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('../../utilities/tools/cookies.js'); +Script.include('satellite.js'); + +var BASE_URL = "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/planets/"; + +var NUM_PLANETS = 8; + +var trailsEnabled = true; +var energyConserved = true; +var planetView = false; +var earthView = false; +var satelliteGame; + +var PANEL_X = 850; +var PANEL_Y = 600; +var BUTTON_SIZE = 20; +var PADDING = 20; + +var DAMPING = 0.0; +var LIFETIME = 6000; +var ERROR_THRESH = 2.0; +var TIME_STEP = 70.0; + +var MAX_POINTS_PER_LINE = 5; +var LINE_DIM = 10; +var LINE_WIDTH = 3.0; +var line; +var planetLines = []; +var trails = []; + +var BOUNDS = 200; + + +// Alert user to move if they are too close to domain bounds +if (MyAvatar.position.x < BOUNDS || MyAvatar.position.x > TREE_SCALE - BOUNDS + || MyAvatar.position.y < BOUNDS || MyAvatar.position.y > TREE_SCALE - BOUNDS + || MyAvatar.position.z < BOUNDS || MyAvatar.position.z > TREE_SCALE - BOUNDS) { + Window.alert("Please move at least 200m away from domain bounds."); + return; +} + +// Save intiial avatar and camera position +var startingPosition = MyAvatar.position; +var startFrame = Window.location.href; + +// Place the sun +var MAX_RANGE = 80.0; +var SUN_SIZE = 8.0; +var center = Vec3.sum(startingPosition, Vec3.multiply(MAX_RANGE, Quat.getFront(Camera.getOrientation()))); + +var theSun = Entities.addEntity({ + type: "Model", + modelURL: BASE_URL + "sun.fbx", + position: center, + dimensions: { + x: SUN_SIZE, + y: SUN_SIZE, + z: SUN_SIZE + }, + angularDamping: DAMPING, + damping: DAMPING, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false +}); + +var planets = []; +var planet_properties = []; + +// Reference values +var radius = 7.0; +var T_ref = 1.0; +var size = 1.0; +var M = 250.0; +var m = M * 0.000000333; +var G = (Math.pow(radius, 3.0) / Math.pow((T_ref / (2.0 * Math.PI)), 2.0)) / M; +var G_ref = G; + +// Adjust size and distance as number of planets increases +var DELTA_RADIUS = 1.8; +var DELTA_SIZE = 0.2; + +function initPlanets() { + for (var i = 0; i < NUM_PLANETS; ++i) { + var v0 = Math.sqrt((G * M) / radius); + var T = (2.0 * Math.PI) * Math.sqrt(Math.pow(radius, 3.0) / (G * M)); + + if (i == 0) { + var color = {red: 255, green: 255, blue: 255}; + } else if (i == 1) { + var color = {red: 255, green: 160, blue: 110}; + } else if (i == 2) { + var color = {red: 10, green: 150, blue: 160}; + } else if (i == 3) { + var color = {red: 180, green: 70, blue: 10}; + } else if (i == 4) { + var color = {red: 250, green: 140, blue: 0}; + } else if (i == 5) { + var color = {red: 235, green: 215, blue: 0}; + } else if (i == 6) { + var color = {red:135, green: 205, blue: 240}; + } else if (i == 7) { + var color = {red:30, green: 140, blue: 255}; + } + + var prop = { + radius: radius, + position: Vec3.sum(center, {x: radius, y: 0.0, z: 0.0}), + lineColor: color, + period: T, + dimensions: size, + velocity: Vec3.multiply(v0, Vec3.normalize({x: 0, y: -0.2, z: 0.9})) + }; + planet_properties.push(prop); + + planets.push(Entities.addEntity({ + type: "Model", + modelURL: BASE_URL + (i + 1) + ".fbx", + position: prop.position, + dimensions: { + x: prop.dimensions, + y: prop.dimensions, + z: prop.dimensions + }, + velocity: prop.velocity, + angularDamping: DAMPING, + damping: DAMPING, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: true, + })); + + radius *= DELTA_RADIUS; + size += DELTA_SIZE; + } +} + +// Initialize planets +initPlanets(); + + +var labels = []; +var labelLines = []; +var labelsShowing = false; +var LABEL_X = 8.0; +var LABEL_Y = 3.0; +var LABEL_Z = 1.0; +var LABEL_DIST = 8.0; +var TEXT_HEIGHT = 1.0; +var sunLabel; + +function showLabels() { + labelsShowing = true; + for (var i = 0; i < NUM_PLANETS; i++) { + var properties = planet_properties[i]; + var text; + if (i == 0) { + text = "Mercury"; + } else if (i == 1) { + text = "Venus"; + } else if (i == 2) { + text = "Earth"; + } else if (i == 3) { + text = "Mars"; + } else if (i == 4) { + text = "Jupiter"; + } else if (i == 5) { + text = "Saturn"; + } else if (i == 6) { + text = "Uranus"; + } else if (i == 7) { + text = "Neptune"; + } + + text = text + " Speed: " + Vec3.length(properties.velocity).toFixed(2); + + var labelPos = Vec3.sum(planet_properties[i].position, {x: 0.0, y: LABEL_DIST, z: LABEL_DIST}); + var linePos = planet_properties[i].position; + labelLines.push(Entities.addEntity( { + type: "Line", + position: linePos, + dimensions: {x: 20, y: 20, z: 20}, + lineWidth: 3.0, + color: {red: 255, green: 255, blue: 255}, + linePoints: [{x: 0, y: 0, z: 0}, computeLocalPoint(linePos, labelPos)] + })); + + labels.push(Entities.addEntity( { + type: "Text", + text: text, + lineHeight: TEXT_HEIGHT, + dimensions: {x: LABEL_X, y: LABEL_Y, z: LABEL_Z}, + position: labelPos, + backgroundColor: {red: 10, green: 10, blue: 10}, + textColor: {red: 255, green: 255, blue: 255}, + faceCamera: true + })); + } +} + +function hideLabels() { + labelsShowing = false; + Entities.deleteEntity(sunLabel); + + for (var i = 0; i < NUM_PLANETS; ++i) { + Entities.deleteEntity(labelLines[i]); + Entities.deleteEntity(labels[i]); + } + labels = []; + labelLines = []; +} + +var time = 0.0; +var elapsed; +var counter = 0; +var dt = 1.0 / TIME_STEP; + +function update(deltaTime) { + if (paused) { + return; + } + deltaTime = dt; + time++; + + for (var i = 0; i < NUM_PLANETS; ++i) { + var properties = planet_properties[i]; + var between = Vec3.subtract(properties.position, center); + var speed = getAcceleration(properties.radius) * deltaTime; + var vel = Vec3.multiply(speed, Vec3.normalize(between)); + + // Update velocity and position + properties.velocity = Vec3.sum(properties.velocity, vel); + properties.position = Vec3.sum(properties.position, Vec3.multiply(properties.velocity, deltaTime)); + Entities.editEntity(planets[i], { + velocity: properties.velocity, + position: properties.position + }); + + + // Create new or update current trail + if (trailsEnabled) { + var lineStack = planetLines[i]; + var point = properties.position; + var prop = Entities.getEntityProperties(lineStack[lineStack.length - 1]); + var linePos = prop.position; + + trails[i].push(computeLocalPoint(linePos, point)); + + Entities.editEntity(lineStack[lineStack.length - 1], { + linePoints: trails[i] + }); + if (trails[i].length === MAX_POINTS_PER_LINE) { + trails[i] = newLine(lineStack, point, properties.period, properties.lineColor); + } + } + + // Measure total energy every 10 updates, recalibrate velocity if necessary + if (energyConserved) { + if (counter % 10 === 0) { + var error = calcEnergyError(planets[i], properties.radius, properties.v0, properties.velocity, properties.position); + if (Math.abs(error) >= ERROR_THRESH) { + var speed = adjustVelocity(planets[i], properties.position); + properties.velocity = Vec3.multiply(speed, Vec3.normalize(properties.velocity)); + } + } + } + } + + counter++; + if (time % TIME_STEP == 0) { + elapsed++; + } +} + +function computeLocalPoint(linePos, worldPoint) { + var localPoint = Vec3.subtract(worldPoint, linePos); + return localPoint; +} + +function getAcceleration(radius) { + var acc = -(G * M) * Math.pow(radius, (-2.0)); + return acc; +} + +// Create a new trail +function resetTrails(planetIndex) { + elapsed = 0.0; + var properties = planet_properties[planetIndex]; + + var trail = []; + var lineStack = []; + + //add the first line to both the line entity stack and the trail + trails.push(newLine(lineStack, properties.position, properties.period, properties.lineColor)); + planetLines.push(lineStack); +} + +// Create a new line +function newLine(lineStack, point, period, color) { + if (elapsed < period) { + var line = Entities.addEntity({ + position: point, + type: "Line", + color: color, + dimensions: { + x: LINE_DIM, + y: LINE_DIM, + z: LINE_DIM + }, + lifetime: LIFETIME, + lineWidth: LINE_WIDTH + }); + lineStack.push(line); + } else { + // Begin overwriting first lines after one full revolution (one period) + var firstLine = lineStack.shift(); + Entities.editEntity(firstLine, { + position: point, + linePoints: [{x: 0.0, y: 0.0, z: 0.0}] + }); + lineStack.push(firstLine); + + } + var points = []; + points.push(computeLocalPoint(point, point)); + return points; +} + +// Measure energy error, recalculate velocity to return to initial net energy +var totalEnergy; +var measuredEnergy; +var measuredPE; + +function calcEnergyError(planet, radius, v0, v, pos) { + totalEnergy = 0.5 * M * Math.pow(v0, 2.0) - ((G * M * m) / radius); + measuredEnergy = 0.5 * M * Math.pow(v, 2.0) - ((G * M * m) / Vec3.length(Vec3.subtract(center, pos))); + var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; + return error; +} +function adjustVelocity(planet, pos) { + var measuredPE = -(G * M * m) / Vec3.length(Vec3.subtract(center, pos)); + return Math.sqrt(2 * (totalEnergy - measuredPE) / M); +} + + +// Allow user to toggle pausing the model, switch to planet view +var pauseButton = Overlays.addOverlay("text", { + backgroundColor: { red: 200, green: 200, blue: 255 }, + text: "Pause", + x: PANEL_X, + y: PANEL_Y - 30, + width: 70, + height: 20, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true +}); + +var paused = false; + +function mousePressEvent(event) { + var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); + if(clickedOverlay == pauseButton) { + paused = !paused; + for (var i = 0; i < NUM_PLANETS; ++i) { + Entities.editEntity(planets[i], { velocity: {x: 0.0, y: 0.0, z: 0.0} }); + } + if (paused && !labelsShowing) { + Overlays.editOverlay(pauseButton, { text: "Paused", backgroundColor: {red: 255, green: 50, blue: 50} } ); + showLabels(); + } + if (paused == false && labelsShowing) { + Overlays.editOverlay(pauseButton, { text: "Pause", backgroundColor: {red: 200, green: 200, blue: 255}}); + hideLabels(); + } + planetView = false; + } +} + +function keyPressEvent(event) { + // Jump back to solar system view + if (event.text == "TAB" && planetView) { + if (earthView) { + satelliteGame.endGame(); + earthView = false; + } + MyAvatar.position = startingPosition; + } +} + +function mouseDoublePressEvent(event) { + if(earthView) { + return; + } + var pickRay = Camera.computePickRay(event.x, event.y) + var rayPickResult = Entities.findRayIntersection(pickRay, true); + + for (var i = 0; i < NUM_PLANETS; ++i) { + if (rayPickResult.entityID === labels[i]) { + planetView = true; + if (i == 2) { + MyAvatar.position = Vec3.sum(center, {x: 200, y: 200, z: 200}); + Camera.setPosition(Vec3.sum(center, {x: 200, y: 200, z: 200})); + earthView = true; + satelliteGame = new SatelliteGame(); + + } else { + MyAvatar.position = Vec3.sum({x: 0.0, y: 0.0, z: 3.0}, planet_properties[i].position); + Camera.lookAt(planet_properties[i].position); + } + break; + } + } +} + + + + +// Create UI panel +var panel = new Panel(PANEL_X, PANEL_Y); +var panelItems = []; + +var g_multiplier = 1.0; +panelItems.push(panel.newSlider("Adjust Gravitational Force: ", 0.1, 5.0, + function (value) { + g_multiplier = value; + G = G_ref * g_multiplier; + }, + + function () { + return g_multiplier; + }, + function (value) { + return value.toFixed(1) + "x"; + })); + +var period_multiplier = 1.0; +var last_alpha = period_multiplier; +panelItems.push(panel.newSlider("Adjust Orbital Period: ", 0.1, 3.0, + function (value) { + period_multiplier = value; + changePeriod(period_multiplier); + }, + function () { + return period_multiplier; + }, + function (value) { + return (value).toFixed(2) + "x"; + })); + +panelItems.push(panel.newCheckbox("Leave Trails: ", + function (value) { + trailsEnabled = value; + if (trailsEnabled) { + for (var i = 0; i < NUM_PLANETS; ++i) { + resetTrails(i); + } + //if trails are off and we've already created trails, remove existing trails + } else if (planetLines.length != 0) { + for (var i = 0; i < NUM_PLANETS; ++i) { + for (var j = 0; j < planetLines[i].length; ++j) { + Entities.deleteEntity(planetLines[i][j]); + } + planetLines[i] = []; + } + } + }, + function () { + return trailsEnabled; + }, + function (value) { + return value; + })); + +panelItems.push(panel.newCheckbox("Energy Error Calculations: ", + function (value) { + energyConserved = value; + }, + function () { + return energyConserved; + }, + function (value) { + return value; + })); + +// Update global G constant, period, poke velocity to new value +function changePeriod(alpha) { + var ratio = last_alpha / alpha; + G = Math.pow(ratio, 2.0) * G; + for (var i = 0; i < NUM_PLANETS; ++i) { + var properties = planet_properties[i]; + properties.period = ratio * properties.period; + properties.velocity = Vec3.multiply(ratio, properties.velocity); + + } + last_alpha = alpha; +} + + +// Clean up models, UI panels, lines, and button overlays +function scriptEnding() { + + satelliteGame.endGame(); + + Entities.deleteEntity(theSun); + for (var i = 0; i < NUM_PLANETS; ++i) { + Entities.deleteEntity(planets[i]); + } + Menu.removeMenu("Developer > Scene"); + panel.destroy(); + Overlays.deleteOverlay(pauseButton); + + var e = Entities.findEntities(MyAvatar.position, 16000); + for (i = 0; i < e.length; i++) { + var props = Entities.getEntityProperties(e[i]); + if (props.type === "Line" || props.type === "Text") { + Entities.deleteEntity(e[i]); + } + } +}; + + +Controller.mouseMoveEvent.connect(function panelMouseMoveEvent(event) { + return panel.mouseMoveEvent(event); +}); +Controller.mousePressEvent.connect(function panelMousePressEvent(event) { + return panel.mousePressEvent(event); +}); +Controller.mouseDoublePressEvent.connect(function panelMouseDoublePressEvent(event) { + return panel.mouseDoublePressEvent(event); +}); +Controller.mouseReleaseEvent.connect(function (event) { + return panel.mouseReleaseEvent(event); +}); +Controller.mousePressEvent.connect(mousePressEvent); +Controller.mouseDoublePressEvent.connect(mouseDoublePressEvent); +Controller.keyPressEvent.connect(keyPressEvent); + +Script.scriptEnding.connect(scriptEnding); +Script.update.connect(update); \ No newline at end of file diff --git a/examples/utilities/tools/vector.js b/examples/utilities/tools/vector.js new file mode 100644 index 0000000000..ab2e8cf200 --- /dev/null +++ b/examples/utilities/tools/vector.js @@ -0,0 +1,197 @@ +// +// vector.js +// examples +// +// Created by Bridget Went on 7/1/15. +// Copyright 2015 High Fidelity, Inc. +// +// A template for creating vector arrows using line entities. A VectorArrow object creates a +// draggable vector arrow where the user clicked at a specified distance from the viewer. +// The relative magnitude and direction of the vector may be displayed. +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +// + +var LINE_DIMENSIONS = 100; +var LIFETIME = 6000; +var RAD_TO_DEG = 180.0 / Math.PI; + +var LINE_WIDTH = 4; +var ARROW_WIDTH = 6; +var line, linePosition; +var arrow1, arrow2; + +var SCALE = 0.15; +var ANGLE = 150.0; + + +VectorArrow = function(distance, showStats, statsTitle, statsPosition) { + this.magnitude = 0; + this.direction = {x: 0, y: 0, z: 0}; + + this.showStats = showStats; + this.isDragging = false; + + this.newLine = function(position) { + linePosition = position; + var points = []; + + line = Entities.addEntity({ + position: linePosition, + type: "Line", + color: {red: 255, green: 255, blue: 255}, + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, + lineWidth: LINE_WIDTH, + lifetime: LIFETIME, + linePoints: [] + }); + + arrow1 = Entities.addEntity({ + position: {x: 0, y: 0, z: 0}, + type: "Line", + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, + color: {red: 255, green: 255, blue: 255}, + lineWidth: ARROW_WIDTH, + linePoints: [], + }); + + arrow2 = Entities.addEntity({ + position: {x: 0, y: 0, z: 0}, + type: "Line", + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, + color: {red: 255, green: 255, blue: 255}, + lineWidth: ARROW_WIDTH, + linePoints: [], + }); + + } + + + this.onMousePressEvent = function(event) { + + this.newLine(computeWorldPoint(event)); + + if (this.showStats) { + this.label = Entities.addEntity({ + type: "Text", + position: statsPosition, + dimensions: { + x: 4.0, + y: 1.5, + z: 0.1 + }, + lineHeight: 0.3, + faceCamera: true + }); + } + + this.isDragging = true; + + } + + + this.onMouseMoveEvent = function(event) { + + if (!this.isDragging) { + return; + } + + var worldPoint = computeWorldPoint(event); + var localPoint = computeLocalPoint(event, linePosition); + points = [{x: 0, y: 0, z: 0}, localPoint]; + Entities.editEntity(line, { linePoints: points }); + + var nextOffset = Vec3.multiply(SCALE, localPoint); + var normOffset = Vec3.normalize(localPoint); + var axis = Vec3.cross(normOffset, Quat.getFront(Camera.getOrientation()) ); + axis = Vec3.cross(axis, normOffset); + var rotate1 = Quat.angleAxis(ANGLE, axis); + var rotate2 = Quat.angleAxis(-ANGLE, axis); + + // Rotate arrow head to follow direction of the line + Entities.editEntity(arrow1, { + visible: true, + position: worldPoint, + linePoints: [{x: 0, y: 0, z: 0}, nextOffset], + rotation: rotate1 + }); + Entities.editEntity(arrow2, { + visible: true, + position: worldPoint, + linePoints: [{x: 0, y: 0, z: 0}, nextOffset], + rotation: rotate2 + }); + + this.magnitude = Vec3.length(localPoint) / 10.0; + this.direction = Vec3.normalize(Vec3.subtract(worldPoint, linePosition)); + + if (this.showStats) { + this.editLabel(statsTitle + " Magnitude " + this.magnitude.toFixed(2) + ", Direction: " + + this.direction.x.toFixed(2) + ", " + this.direction.y.toFixed(2) + ", " + this.direction.z.toFixed(2)); + } + } + + this.onMouseReleaseEvent = function() { + this.isDragging = false; + } + + this.cleanup = function() { + Entities.deleteEntity(line); + Entities.deleteEntity(arrow1); + Entities.deleteEntity(arrow2); + } + + this.deleteLabel = function() { + Entities.deleteEntity(this.label); + } + + this.editLabel = function(str) { + if(!this.showStats) { + return; + } + Entities.editEntity(this.label, { + text: str + }); + } + + function computeWorldPoint(event) { + var pickRay = Camera.computePickRay(event.x, event.y); + var addVector = Vec3.multiply(pickRay.direction, distance); + return Vec3.sum(Camera.getPosition(), addVector); + } + + function computeLocalPoint(event, linePosition) { + var localPoint = Vec3.subtract(computeWorldPoint(event), linePosition); + return localPoint; + } + + + +} + + + + + + + + + + + + From e0d6609a99b198f84a7a54445b2f9abb6465f047 Mon Sep 17 00:00:00 2001 From: bwent Date: Fri, 24 Jul 2015 10:18:33 -0700 Subject: [PATCH 27/74] resolve file path issue --- examples/example/games/satellite.js | 13 ++++++------- examples/example/{games => }/solarsystem.js | 12 +++++++++--- 2 files changed, 15 insertions(+), 10 deletions(-) rename examples/example/{games => }/solarsystem.js (96%) diff --git a/examples/example/games/satellite.js b/examples/example/games/satellite.js index d2e4dd2a99..e82285622b 100644 --- a/examples/example/games/satellite.js +++ b/examples/example/games/satellite.js @@ -15,7 +15,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include('../../utilities/tools/vector.js'); +Script.include('../utilities/tools/vector.js'); var URL = "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/"; @@ -38,8 +38,8 @@ SatelliteGame = function() { var EARTH_SIZE = 20.0; var CLOUDS_OFFSET = 0.5; var SPIN = 0.1; - var ZONE_DIM = 10.0; - var LIGHT_INTENSITY = 1.2; + var ZONE_DIM = 100.0; + var LIGHT_INTENSITY = 1.5; Earth = function(position, size) { this.earth = Entities.addEntity({ @@ -65,7 +65,7 @@ SatelliteGame = function() { this.clouds = Entities.addEntity({ type: "Model", shapeType: 'sphere', - modelURL: URL + "clouds.fbx?", + modelURL: URL + "clouds.fbx?i=2", position: position, dimensions: { x: size + CLOUDS_OFFSET, @@ -190,7 +190,7 @@ SatelliteGame = function() { if (activeSatellite.arrow) { activeSatellite.arrow.deleteLabel(); } - var statsPosition = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE * 0.5, Quat.getFront(Camera.getOrientation()))); + var statsPosition = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE * 0.4, Quat.getFront(Camera.getOrientation()))); var pickRay = Camera.computePickRay(event.x, event.y) var rayPickResult = Entities.findRayIntersection(pickRay, true); if (rayPickResult.entityID === activeSatellite.satellite) { @@ -245,9 +245,8 @@ SatelliteGame = function() { } this.endGame = function() { - print("ending game"); for(var i = 0; i < satellites.length; i++) { - Entities.deleteEntitiy(satellites[i].satellite); + Entities.deleteEntity(satellites[i].satellite); satellites[i].arrow.cleanup(); } earth.cleanup(); diff --git a/examples/example/games/solarsystem.js b/examples/example/solarsystem.js similarity index 96% rename from examples/example/games/solarsystem.js rename to examples/example/solarsystem.js index b651e551f0..09ba2eec8d 100644 --- a/examples/example/games/solarsystem.js +++ b/examples/example/solarsystem.js @@ -6,14 +6,20 @@ // Copyright 2015 High Fidelity, Inc. // // The start to a project to build a virtual physics classroom to simulate the solar system, gravity, and orbital physics. -// A sun with oribiting planets is created in front of the user. UI elements allow for adjusting the period, gravity, trails, and energy recalculations. +// - A sun with oribiting planets is created in front of the user +// - UI elements allow for adjusting the period, gravity, trails, and energy recalculations +// - Click "PAUSE" to pause the animation and show planet labels +// - In this mode, double-click a planet label to zoom in on that planet +// -Double-clicking on earth label initiates satellite orbiter game +// -Press "TAB" to toggle back to solar system view +// // // 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('../../utilities/tools/cookies.js'); -Script.include('satellite.js'); +Script.include('../utilities/tools/cookies.js'); +Script.include('games/satellite.js'); var BASE_URL = "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/planets/"; From 5272a1d6e74a23b310b765ef51242a9ea81e0cc7 Mon Sep 17 00:00:00 2001 From: bwent Date: Mon, 27 Jul 2015 14:28:43 -0700 Subject: [PATCH 28/74] refactoring variables and constants, fix update loop to continue over unlaunched satellites --- examples/example/games/satellite.js | 212 +++++++++++++------------ examples/example/solarsystem.js | 229 ++++++++++++++++++++-------- examples/utilities/tools/vector.js | 31 ++-- 3 files changed, 290 insertions(+), 182 deletions(-) diff --git a/examples/example/games/satellite.js b/examples/example/games/satellite.js index e82285622b..3ddce96aa5 100644 --- a/examples/example/games/satellite.js +++ b/examples/example/games/satellite.js @@ -27,11 +27,6 @@ SatelliteGame = function() { z: 0 } var LIFETIME = 6000; - - var v0; - var T = 4.0; - var M = 16000.0; - var m = M * 0.000000333; var ERROR_THRESH = 20.0; // Create the spinning earth model @@ -43,42 +38,54 @@ SatelliteGame = function() { Earth = function(position, size) { this.earth = Entities.addEntity({ - type: "Model", - shapeType: 'sphere', - modelURL: URL + "earth.fbx", - position: position, - dimensions: { - x: size, - y: size, - z: size - }, - rotation: Quat.angleAxis(180, {x: 1, y: 0, z: 0}), - angularVelocity: { x: 0.00, y: 0.5 * SPIN, z: 0.00 }, - angularDamping: 0.0, - damping: 0.0, - ignoreCollisions: false, - lifetime: 6000, - collisionsWillMove: false, - visible: true + type: "Model", + shapeType: 'sphere', + modelURL: URL + "earth.fbx", + position: position, + dimensions: { + x: size, + y: size, + z: size + }, + rotation: Quat.angleAxis(180, { + x: 1, + y: 0, + z: 0 + }), + angularVelocity: { + x: 0.00, + y: 0.5 * SPIN, + z: 0.00 + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: 6000, + collisionsWillMove: false, + visible: true }); this.clouds = Entities.addEntity({ - type: "Model", - shapeType: 'sphere', - modelURL: URL + "clouds.fbx?i=2", - position: position, - dimensions: { - x: size + CLOUDS_OFFSET, - y: size + CLOUDS_OFFSET, - z: size + CLOUDS_OFFSET - }, - angularVelocity: { x: 0.00, y: SPIN, z: 0.00 }, - angularDamping: 0.0, - damping: 0.0, - ignoreCollisions: false, - lifetime: LIFETIME, - collisionsWillMove: false, - visible: true + type: "Model", + shapeType: 'sphere', + modelURL: URL + "clouds.fbx?i=2", + position: position, + dimensions: { + x: size + CLOUDS_OFFSET, + y: size + CLOUDS_OFFSET, + z: size + CLOUDS_OFFSET + }, + angularVelocity: { + x: 0.00, + y: SPIN, + z: 0.00 + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false, + visible: true }); this.zone = Entities.addEntity({ @@ -93,11 +100,11 @@ SatelliteGame = function() { keyLightIntensity: LIGHT_INTENSITY }); - this.cleanup = function() { - Entities.deleteEntity(this.clouds); + this.cleanup = function() { + Entities.deleteEntity(this.clouds); Entities.deleteEntity(this.earth); Entities.deleteEntity(this.zone); - } + } } // Create earth model @@ -110,6 +117,10 @@ SatelliteGame = function() { var launched = false; var activeSatellite; + var PERIOD = 4.0; + var LARGE_BODY_MASS = 16000.0; + var SMALL_BODY_MASS = LARGE_BODY_MASS * 0.000000333; + Satellite = function(position, planetCenter) { // The Satellite class @@ -118,20 +129,20 @@ SatelliteGame = function() { this.readyToLaunch = false; this.radius = Vec3.length(Vec3.subtract(position, planetCenter)); - this.satellite = Entities.addEntity({ + this.satellite = Entities.addEntity({ type: "Model", - modelURL: "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/satellite/satellite.fbx", - position: this.startPosition, - dimensions: { - x: SATELLITE_SIZE, - y: SATELLITE_SIZE, - z: SATELLITE_SIZE - }, - angularDamping: 0.0, - damping: 0.0, - ignoreCollisions: false, - lifetime: LIFETIME, - collisionsWillMove: false, + modelURL: "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/satellite/satellite.fbx", + position: this.startPosition, + dimensions: { + x: SATELLITE_SIZE, + y: SATELLITE_SIZE, + z: SATELLITE_SIZE + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false, }); this.getProperties = function() { @@ -142,14 +153,16 @@ SatelliteGame = function() { var prop = Entities.getEntityProperties(this.satellite); var between = Vec3.subtract(planetCenter, prop.position); var radius = Vec3.length(between); - this.G = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (M * T * T); + this.gravity = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (LARGE_BODY_MASS * PERIOD * PERIOD); - var v0 = Vec3.normalize(Vec3.cross(between, Y_AXIS)); - v0 = Vec3.multiply(Math.sqrt((this.G * M) / radius), v0); - v0 = Vec3.multiply(this.arrow.magnitude, v0); - v0 = Vec3.multiply(Vec3.length(v0), this.arrow.direction); + var initialVelocity = Vec3.normalize(Vec3.cross(between, Y_AXIS)); + initialVelocity = Vec3.multiply(Math.sqrt((this.gravity * LARGE_BODY_MASS) / radius), initialVelocity); + initialVelocity = Vec3.multiply(this.arrow.magnitude, initialVelocity); + initialVelocity = Vec3.multiply(Vec3.length(initialVelocity), this.arrow.direction); - Entities.editEntity(this.satellite, { velocity: v0 }); + Entities.editEntity(this.satellite, { + velocity: initialVelocity + }); this.launched = true; }; @@ -158,12 +171,12 @@ SatelliteGame = function() { var prop = Entities.getEntityProperties(this.satellite); var between = Vec3.subtract(prop.position, planetCenter); var radius = Vec3.length(between); - var a = -(this.G * M) * Math.pow(radius, (-2.0)); - var speed = a * deltaTime; - var vel = Vec3.multiply(speed, Vec3.normalize(between)); + var acceleration = -(this.gravity * LARGE_BODY_MASS) * Math.pow(radius, (-2.0)); + var speed = acceleration * deltaTime; + var vel = Vec3.multiply(speed, Vec3.normalize(between)); - var newVelocity = Vec3.sum(prop.velocity, vel); - var newPos = Vec3.sum(prop.position, Vec3.multiply(newVelocity, deltaTime)); + var newVelocity = Vec3.sum(prop.velocity, vel); + var newPos = Vec3.sum(prop.position, Vec3.multiply(newVelocity, deltaTime)); Entities.editEntity(this.satellite, { velocity: newVelocity, @@ -173,11 +186,11 @@ SatelliteGame = function() { } function mouseDoublePressEvent(event) { - var pickRay = Camera.computePickRay(event.x, event.y); - var addVector = Vec3.multiply(pickRay.direction, distance); - var point = Vec3.sum(Camera.getPosition(), addVector); + var pickRay = Camera.computePickRay(event.x, event.y); + var addVector = Vec3.multiply(pickRay.direction, distance); + var point = Vec3.sum(Camera.getPosition(), addVector); - // Create a new satellite + // Create a new satellite activeSatellite = new Satellite(point, center); satellites.push(activeSatellite); } @@ -188,11 +201,11 @@ SatelliteGame = function() { } // Reset label if (activeSatellite.arrow) { - activeSatellite.arrow.deleteLabel(); - } + activeSatellite.arrow.deleteLabel(); + } var statsPosition = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE * 0.4, Quat.getFront(Camera.getOrientation()))); var pickRay = Camera.computePickRay(event.x, event.y) - var rayPickResult = Entities.findRayIntersection(pickRay, true); + var rayPickResult = Entities.findRayIntersection(pickRay, true); if (rayPickResult.entityID === activeSatellite.satellite) { // Create a draggable vector arrow at satellite position activeSatellite.arrow = new VectorArrow(distance, true, "INITIAL VELOCITY", statsPosition); @@ -202,50 +215,50 @@ SatelliteGame = function() { } function mouseMoveEvent(event) { - if(!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { + if (!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { return; } activeSatellite.arrow.onMouseMoveEvent(event); } function mouseReleaseEvent(event) { - if(!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { + if (!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { return; } activeSatellite.arrow.onMouseReleaseEvent(event); - activeSatellite.launch(); - activeSatellite.arrow.cleanup(); + activeSatellite.launch(); + activeSatellite.arrow.cleanup(); } var counter = 0.0; - var TIME = 500; + var CHECK_ENERGY_PERIOD = 500; function update(deltaTime) { - if(!activeSatellite) { + if (!activeSatellite) { return; } // Update all satellites for (var i = 0; i < satellites.length; i++) { if (!satellites[i].launched) { - return; + continue; } - satellites[i].update(deltaTime); + satellites[i].update(deltaTime); } - + counter++; - if (counter % TIME == 0) { + if (counter % CHECK_ENERGY_PERIOD == 0) { var prop = activeSatellite.getProperties(); - var error = calcEnergyError(prop.position, Vec3.length(prop.velocity)); - if (Math.abs(error) <= ERROR_THRESH) { - activeSatellite.arrow.editLabel("Nice job! The satellite has reached a stable orbit."); - } else { - activeSatellite.arrow.editLabel("Try again! The satellite is in an unstable orbit."); - } - } + var error = calcEnergyError(prop.position, Vec3.length(prop.velocity)); + if (Math.abs(error) <= ERROR_THRESH) { + activeSatellite.arrow.editLabel("Nice job! The satellite has reached a stable orbit."); + } else { + activeSatellite.arrow.editLabel("Try again! The satellite is in an unstable orbit."); + } + } } this.endGame = function() { - for(var i = 0; i < satellites.length; i++) { + for (var i = 0; i < satellites.length; i++) { Entities.deleteEntity(satellites[i].satellite); satellites[i].arrow.cleanup(); } @@ -256,13 +269,13 @@ SatelliteGame = function() { function calcEnergyError(pos, vel) { //Calculate total energy error for active satellite's orbital motion var radius = activeSatellite.radius; - var G = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (M * T * T); - var v0 = Math.sqrt((G * M) / radius); - - var totalEnergy = 0.5 * M * Math.pow(v0, 2.0) - ((G * M * m) / radius); - var measuredEnergy = 0.5 * M * Math.pow(vel, 2.0) - ((G * M * m) / Vec3.length(Vec3.subtract(pos, center))); - var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; - return error; + var gravity = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (LARGE_BODY_MASS * PERIOD * PERIOD); + var initialVelocityCalculated = Math.sqrt((gravity * LARGE_BODY_MASS) / radius); + + var totalEnergy = 0.5 * LARGE_BODY_MASS * Math.pow(initialVelocityCalculated, 2.0) - ((gravity * LARGE_BODY_MASS * SMALL_BODY_MASS) / radius); + var measuredEnergy = 0.5 * LARGE_BODY_MASS * Math.pow(vel, 2.0) - ((gravity * LARGE_BODY_MASS * SMALL_BODY_MASS) / Vec3.length(Vec3.subtract(pos, center))); + var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; + return error; } Controller.mousePressEvent.connect(mousePressEvent); @@ -272,7 +285,4 @@ SatelliteGame = function() { Script.update.connect(update); Script.scriptEnding.connect(this.endGame); -} - - - +} \ No newline at end of file diff --git a/examples/example/solarsystem.js b/examples/example/solarsystem.js index 09ba2eec8d..8d1f0c81e3 100644 --- a/examples/example/solarsystem.js +++ b/examples/example/solarsystem.js @@ -52,9 +52,7 @@ var BOUNDS = 200; // Alert user to move if they are too close to domain bounds -if (MyAvatar.position.x < BOUNDS || MyAvatar.position.x > TREE_SCALE - BOUNDS - || MyAvatar.position.y < BOUNDS || MyAvatar.position.y > TREE_SCALE - BOUNDS - || MyAvatar.position.z < BOUNDS || MyAvatar.position.z > TREE_SCALE - BOUNDS) { +if (MyAvatar.position.x < BOUNDS || MyAvatar.position.x > TREE_SCALE - BOUNDS || MyAvatar.position.y < BOUNDS || MyAvatar.position.y > TREE_SCALE - BOUNDS || MyAvatar.position.z < BOUNDS || MyAvatar.position.z > TREE_SCALE - BOUNDS) { Window.alert("Please move at least 200m away from domain bounds."); return; } @@ -106,30 +104,70 @@ function initPlanets() { var T = (2.0 * Math.PI) * Math.sqrt(Math.pow(radius, 3.0) / (G * M)); if (i == 0) { - var color = {red: 255, green: 255, blue: 255}; + var color = { + red: 255, + green: 255, + blue: 255 + }; } else if (i == 1) { - var color = {red: 255, green: 160, blue: 110}; + var color = { + red: 255, + green: 160, + blue: 110 + }; } else if (i == 2) { - var color = {red: 10, green: 150, blue: 160}; + var color = { + red: 10, + green: 150, + blue: 160 + }; } else if (i == 3) { - var color = {red: 180, green: 70, blue: 10}; + var color = { + red: 180, + green: 70, + blue: 10 + }; } else if (i == 4) { - var color = {red: 250, green: 140, blue: 0}; + var color = { + red: 250, + green: 140, + blue: 0 + }; } else if (i == 5) { - var color = {red: 235, green: 215, blue: 0}; + var color = { + red: 235, + green: 215, + blue: 0 + }; } else if (i == 6) { - var color = {red:135, green: 205, blue: 240}; + var color = { + red: 135, + green: 205, + blue: 240 + }; } else if (i == 7) { - var color = {red:30, green: 140, blue: 255}; + var color = { + red: 30, + green: 140, + blue: 255 + }; } var prop = { radius: radius, - position: Vec3.sum(center, {x: radius, y: 0.0, z: 0.0}), + position: Vec3.sum(center, { + x: radius, + y: 0.0, + z: 0.0 + }), lineColor: color, period: T, dimensions: size, - velocity: Vec3.multiply(v0, Vec3.normalize({x: 0, y: -0.2, z: 0.9})) + velocity: Vec3.multiply(v0, Vec3.normalize({ + x: 0, + y: -0.2, + z: 0.9 + })) }; planet_properties.push(prop); @@ -194,27 +232,55 @@ function showLabels() { text = text + " Speed: " + Vec3.length(properties.velocity).toFixed(2); - var labelPos = Vec3.sum(planet_properties[i].position, {x: 0.0, y: LABEL_DIST, z: LABEL_DIST}); + var labelPos = Vec3.sum(planet_properties[i].position, { + x: 0.0, + y: LABEL_DIST, + z: LABEL_DIST + }); var linePos = planet_properties[i].position; - labelLines.push(Entities.addEntity( { + labelLines.push(Entities.addEntity({ type: "Line", position: linePos, - dimensions: {x: 20, y: 20, z: 20}, + dimensions: { + x: 20, + y: 20, + z: 20 + }, lineWidth: 3.0, - color: {red: 255, green: 255, blue: 255}, - linePoints: [{x: 0, y: 0, z: 0}, computeLocalPoint(linePos, labelPos)] + color: { + red: 255, + green: 255, + blue: 255 + }, + linePoints: [{ + x: 0, + y: 0, + z: 0 + }, computeLocalPoint(linePos, labelPos)] })); - labels.push(Entities.addEntity( { + labels.push(Entities.addEntity({ type: "Text", text: text, lineHeight: TEXT_HEIGHT, - dimensions: {x: LABEL_X, y: LABEL_Y, z: LABEL_Z}, + dimensions: { + x: LABEL_X, + y: LABEL_Y, + z: LABEL_Z + }, position: labelPos, - backgroundColor: {red: 10, green: 10, blue: 10}, - textColor: {red: 255, green: 255, blue: 255}, + backgroundColor: { + red: 10, + green: 10, + blue: 10 + }, + textColor: { + red: 255, + green: 255, + blue: 255 + }, faceCamera: true - })); + })); } } @@ -255,7 +321,7 @@ function update(deltaTime) { velocity: properties.velocity, position: properties.position }); - + // Create new or update current trail if (trailsEnabled) { @@ -285,11 +351,11 @@ function update(deltaTime) { } } } - + counter++; if (time % TIME_STEP == 0) { elapsed++; - } + } } function computeLocalPoint(linePos, worldPoint) { @@ -306,7 +372,7 @@ function getAcceleration(radius) { function resetTrails(planetIndex) { elapsed = 0.0; var properties = planet_properties[planetIndex]; - + var trail = []; var lineStack = []; @@ -333,10 +399,14 @@ function newLine(lineStack, point, period, color) { lineStack.push(line); } else { // Begin overwriting first lines after one full revolution (one period) - var firstLine = lineStack.shift(); + var firstLine = lineStack.shift(); Entities.editEntity(firstLine, { position: point, - linePoints: [{x: 0.0, y: 0.0, z: 0.0}] + linePoints: [{ + x: 0.0, + y: 0.0, + z: 0.0 + }] }); lineStack.push(firstLine); @@ -357,6 +427,7 @@ function calcEnergyError(planet, radius, v0, v, pos) { var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; return error; } + function adjustVelocity(planet, pos) { var measuredPE = -(G * M * m) / Vec3.length(Vec3.subtract(center, pos)); return Math.sqrt(2 * (totalEnergy - measuredPE) / M); @@ -365,7 +436,11 @@ function adjustVelocity(planet, pos) { // Allow user to toggle pausing the model, switch to planet view var pauseButton = Overlays.addOverlay("text", { - backgroundColor: { red: 200, green: 200, blue: 255 }, + backgroundColor: { + red: 200, + green: 200, + blue: 255 + }, text: "Pause", x: PANEL_X, y: PANEL_Y - 30, @@ -379,22 +454,45 @@ var pauseButton = Overlays.addOverlay("text", { var paused = false; function mousePressEvent(event) { - var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); - if(clickedOverlay == pauseButton) { + var clickedOverlay = Overlays.getOverlayAtPoint({ + x: event.x, + y: event.y + }); + if (clickedOverlay == pauseButton) { paused = !paused; for (var i = 0; i < NUM_PLANETS; ++i) { - Entities.editEntity(planets[i], { velocity: {x: 0.0, y: 0.0, z: 0.0} }); + Entities.editEntity(planets[i], { + velocity: { + x: 0.0, + y: 0.0, + z: 0.0 + } + }); } if (paused && !labelsShowing) { - Overlays.editOverlay(pauseButton, { text: "Paused", backgroundColor: {red: 255, green: 50, blue: 50} } ); + Overlays.editOverlay(pauseButton, { + text: "Paused", + backgroundColor: { + red: 255, + green: 50, + blue: 50 + } + }); showLabels(); } if (paused == false && labelsShowing) { - Overlays.editOverlay(pauseButton, { text: "Pause", backgroundColor: {red: 200, green: 200, blue: 255}}); + Overlays.editOverlay(pauseButton, { + text: "Pause", + backgroundColor: { + red: 200, + green: 200, + blue: 255 + } + }); hideLabels(); } planetView = false; - } + } } function keyPressEvent(event) { @@ -409,7 +507,7 @@ function keyPressEvent(event) { } function mouseDoublePressEvent(event) { - if(earthView) { + if (earthView) { return; } var pickRay = Camera.computePickRay(event.x, event.y) @@ -419,57 +517,68 @@ function mouseDoublePressEvent(event) { if (rayPickResult.entityID === labels[i]) { planetView = true; if (i == 2) { - MyAvatar.position = Vec3.sum(center, {x: 200, y: 200, z: 200}); - Camera.setPosition(Vec3.sum(center, {x: 200, y: 200, z: 200})); + MyAvatar.position = Vec3.sum(center, { + x: 200, + y: 200, + z: 200 + }); + Camera.setPosition(Vec3.sum(center, { + x: 200, + y: 200, + z: 200 + })); earthView = true; satelliteGame = new SatelliteGame(); - + } else { - MyAvatar.position = Vec3.sum({x: 0.0, y: 0.0, z: 3.0}, planet_properties[i].position); + MyAvatar.position = Vec3.sum({ + x: 0.0, + y: 0.0, + z: 3.0 + }, planet_properties[i].position); Camera.lookAt(planet_properties[i].position); } - break; - } - } + break; + } + } } - // Create UI panel var panel = new Panel(PANEL_X, PANEL_Y); var panelItems = []; var g_multiplier = 1.0; panelItems.push(panel.newSlider("Adjust Gravitational Force: ", 0.1, 5.0, - function (value) { + function(value) { g_multiplier = value; G = G_ref * g_multiplier; }, - function () { + function() { return g_multiplier; }, - function (value) { + function(value) { return value.toFixed(1) + "x"; })); var period_multiplier = 1.0; var last_alpha = period_multiplier; panelItems.push(panel.newSlider("Adjust Orbital Period: ", 0.1, 3.0, - function (value) { + function(value) { period_multiplier = value; changePeriod(period_multiplier); }, - function () { + function() { return period_multiplier; }, - function (value) { + function(value) { return (value).toFixed(2) + "x"; })); panelItems.push(panel.newCheckbox("Leave Trails: ", - function (value) { + function(value) { trailsEnabled = value; if (trailsEnabled) { for (var i = 0; i < NUM_PLANETS; ++i) { @@ -485,21 +594,21 @@ panelItems.push(panel.newCheckbox("Leave Trails: ", } } }, - function () { + function() { return trailsEnabled; }, - function (value) { + function(value) { return value; })); panelItems.push(panel.newCheckbox("Energy Error Calculations: ", - function (value) { + function(value) { energyConserved = value; }, - function () { + function() { return energyConserved; }, - function (value) { + function(value) { return value; })); @@ -519,7 +628,7 @@ function changePeriod(alpha) { // Clean up models, UI panels, lines, and button overlays function scriptEnding() { - + satelliteGame.endGame(); Entities.deleteEntity(theSun); @@ -536,7 +645,7 @@ function scriptEnding() { if (props.type === "Line" || props.type === "Text") { Entities.deleteEntity(e[i]); } - } + } }; @@ -549,7 +658,7 @@ Controller.mousePressEvent.connect(function panelMousePressEvent(event) { Controller.mouseDoublePressEvent.connect(function panelMouseDoublePressEvent(event) { return panel.mouseDoublePressEvent(event); }); -Controller.mouseReleaseEvent.connect(function (event) { +Controller.mouseReleaseEvent.connect(function(event) { return panel.mouseReleaseEvent(event); }); Controller.mousePressEvent.connect(mousePressEvent); diff --git a/examples/utilities/tools/vector.js b/examples/utilities/tools/vector.js index ab2e8cf200..0635b6cbc7 100644 --- a/examples/utilities/tools/vector.js +++ b/examples/utilities/tools/vector.js @@ -82,6 +82,13 @@ VectorArrow = function(distance, showStats, statsTitle, statsPosition) { } + var STATS_DIMENSIONS = { + x: 4.0, + y: 1.5, + z: 0.1 + }; + var TEXT_HEIGHT = 0.3; + this.onMousePressEvent = function(event) { this.newLine(computeWorldPoint(event)); @@ -90,12 +97,8 @@ VectorArrow = function(distance, showStats, statsTitle, statsPosition) { this.label = Entities.addEntity({ type: "Text", position: statsPosition, - dimensions: { - x: 4.0, - y: 1.5, - z: 0.1 - }, - lineHeight: 0.3, + dimensions: STATS_DIMENSIONS, + lineHeight: TEXT_HEIGHT, faceCamera: true }); } @@ -137,7 +140,7 @@ VectorArrow = function(distance, showStats, statsTitle, statsPosition) { rotation: rotate2 }); - this.magnitude = Vec3.length(localPoint) / 10.0; + this.magnitude = Vec3.length(localPoint) * 0.1; this.direction = Vec3.normalize(Vec3.subtract(worldPoint, linePosition)); if (this.showStats) { @@ -180,18 +183,4 @@ VectorArrow = function(distance, showStats, statsTitle, statsPosition) { return localPoint; } - - } - - - - - - - - - - - - From 1107742188a8cd878a65c2983f68d458648d0598 Mon Sep 17 00:00:00 2001 From: bwent Date: Tue, 28 Jul 2015 12:39:04 -0700 Subject: [PATCH 29/74] Clean up formatting for satellite.js --- examples/example/games/satellite.js | 468 ++++++++++++++-------------- 1 file changed, 234 insertions(+), 234 deletions(-) diff --git a/examples/example/games/satellite.js b/examples/example/games/satellite.js index 3ddce96aa5..f362c0c1e4 100644 --- a/examples/example/games/satellite.js +++ b/examples/example/games/satellite.js @@ -3,13 +3,13 @@ // games // // Created by Bridget Went 7/1/2015. -// Copyright 2015 High Fidelity, Inc. +// Copyright 2015 High Fidelity, Inc. // // A game to bring a satellite model into orbit around an animated earth model . -// - Double click to create a new satellite -// - Click on the satellite, drag a vector arrow to specify initial velocity -// - Release mouse to launch the active satellite -// - Orbital movement is calculated using equations of gravitational physics +// - Double click to create a new satellite +// - Click on the satellite, drag a vector arrow to specify initial velocity +// - Release mouse to launch the active satellite +// - Orbital movement is calculated using equations of gravitational physics // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -20,269 +20,269 @@ Script.include('../utilities/tools/vector.js'); var URL = "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/"; SatelliteGame = function() { - var MAX_RANGE = 50.0; - var Y_AXIS = { - x: 0, - y: 1, - z: 0 - } - var LIFETIME = 6000; - var ERROR_THRESH = 20.0; + var MAX_RANGE = 50.0; + var Y_AXIS = { + x: 0, + y: 1, + z: 0 + } + var LIFETIME = 6000; + var ERROR_THRESH = 20.0; - // Create the spinning earth model - var EARTH_SIZE = 20.0; - var CLOUDS_OFFSET = 0.5; - var SPIN = 0.1; - var ZONE_DIM = 100.0; - var LIGHT_INTENSITY = 1.5; + // Create the spinning earth model + var EARTH_SIZE = 20.0; + var CLOUDS_OFFSET = 0.5; + var SPIN = 0.1; + var ZONE_DIM = 100.0; + var LIGHT_INTENSITY = 1.5; - Earth = function(position, size) { - this.earth = Entities.addEntity({ - type: "Model", - shapeType: 'sphere', - modelURL: URL + "earth.fbx", - position: position, - dimensions: { - x: size, - y: size, - z: size - }, - rotation: Quat.angleAxis(180, { - x: 1, - y: 0, - z: 0 - }), - angularVelocity: { - x: 0.00, - y: 0.5 * SPIN, - z: 0.00 - }, - angularDamping: 0.0, - damping: 0.0, - ignoreCollisions: false, - lifetime: 6000, - collisionsWillMove: false, - visible: true - }); + Earth = function(position, size) { + this.earth = Entities.addEntity({ + type: "Model", + shapeType: 'sphere', + modelURL: URL + "earth.fbx", + position: position, + dimensions: { + x: size, + y: size, + z: size + }, + rotation: Quat.angleAxis(180, { + x: 1, + y: 0, + z: 0 + }), + angularVelocity: { + x: 0.00, + y: 0.5 * SPIN, + z: 0.00 + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: 6000, + collisionsWillMove: false, + visible: true + }); - this.clouds = Entities.addEntity({ - type: "Model", - shapeType: 'sphere', - modelURL: URL + "clouds.fbx?i=2", - position: position, - dimensions: { - x: size + CLOUDS_OFFSET, - y: size + CLOUDS_OFFSET, - z: size + CLOUDS_OFFSET - }, - angularVelocity: { - x: 0.00, - y: SPIN, - z: 0.00 - }, - angularDamping: 0.0, - damping: 0.0, - ignoreCollisions: false, - lifetime: LIFETIME, - collisionsWillMove: false, - visible: true - }); + this.clouds = Entities.addEntity({ + type: "Model", + shapeType: 'sphere', + modelURL: URL + "clouds.fbx?i=2", + position: position, + dimensions: { + x: size + CLOUDS_OFFSET, + y: size + CLOUDS_OFFSET, + z: size + CLOUDS_OFFSET + }, + angularVelocity: { + x: 0.00, + y: SPIN, + z: 0.00 + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false, + visible: true + }); - this.zone = Entities.addEntity({ - type: "Zone", - position: position, - dimensions: { - x: ZONE_DIM, - y: ZONE_DIM, - z: ZONE_DIM - }, - keyLightDirection: Vec3.normalize(Vec3.subtract(position, Camera.getPosition())), - keyLightIntensity: LIGHT_INTENSITY - }); + this.zone = Entities.addEntity({ + type: "Zone", + position: position, + dimensions: { + x: ZONE_DIM, + y: ZONE_DIM, + z: ZONE_DIM + }, + keyLightDirection: Vec3.normalize(Vec3.subtract(position, Camera.getPosition())), + keyLightIntensity: LIGHT_INTENSITY + }); - this.cleanup = function() { - Entities.deleteEntity(this.clouds); - Entities.deleteEntity(this.earth); - Entities.deleteEntity(this.zone); - } - } + this.cleanup = function() { + Entities.deleteEntity(this.clouds); + Entities.deleteEntity(this.earth); + Entities.deleteEntity(this.zone); + } + } - // Create earth model - var center = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE, Quat.getFront(Camera.getOrientation()))); - var distance = Vec3.length(Vec3.subtract(center, Camera.getPosition())); - var earth = new Earth(center, EARTH_SIZE); + // Create earth model + var center = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE, Quat.getFront(Camera.getOrientation()))); + var distance = Vec3.length(Vec3.subtract(center, Camera.getPosition())); + var earth = new Earth(center, EARTH_SIZE); - var satellites = []; - var SATELLITE_SIZE = 2.0; - var launched = false; - var activeSatellite; + var satellites = []; + var SATELLITE_SIZE = 2.0; + var launched = false; + var activeSatellite; var PERIOD = 4.0; var LARGE_BODY_MASS = 16000.0; var SMALL_BODY_MASS = LARGE_BODY_MASS * 0.000000333; - Satellite = function(position, planetCenter) { - // The Satellite class + Satellite = function(position, planetCenter) { + // The Satellite class - this.launched = false; - this.startPosition = position; - this.readyToLaunch = false; - this.radius = Vec3.length(Vec3.subtract(position, planetCenter)); + this.launched = false; + this.startPosition = position; + this.readyToLaunch = false; + this.radius = Vec3.length(Vec3.subtract(position, planetCenter)); - this.satellite = Entities.addEntity({ - type: "Model", - modelURL: "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/satellite/satellite.fbx", - position: this.startPosition, - dimensions: { - x: SATELLITE_SIZE, - y: SATELLITE_SIZE, - z: SATELLITE_SIZE - }, - angularDamping: 0.0, - damping: 0.0, - ignoreCollisions: false, - lifetime: LIFETIME, - collisionsWillMove: false, - }); + this.satellite = Entities.addEntity({ + type: "Model", + modelURL: "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/satellite/satellite.fbx", + position: this.startPosition, + dimensions: { + x: SATELLITE_SIZE, + y: SATELLITE_SIZE, + z: SATELLITE_SIZE + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false, + }); - this.getProperties = function() { - return Entities.getEntityProperties(this.satellite); - } + this.getProperties = function() { + return Entities.getEntityProperties(this.satellite); + } - this.launch = function() { - var prop = Entities.getEntityProperties(this.satellite); - var between = Vec3.subtract(planetCenter, prop.position); - var radius = Vec3.length(between); - this.gravity = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (LARGE_BODY_MASS * PERIOD * PERIOD); + this.launch = function() { + var prop = Entities.getEntityProperties(this.satellite); + var between = Vec3.subtract(planetCenter, prop.position); + var radius = Vec3.length(between); + this.gravity = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (LARGE_BODY_MASS * PERIOD * PERIOD); - var initialVelocity = Vec3.normalize(Vec3.cross(between, Y_AXIS)); - initialVelocity = Vec3.multiply(Math.sqrt((this.gravity * LARGE_BODY_MASS) / radius), initialVelocity); - initialVelocity = Vec3.multiply(this.arrow.magnitude, initialVelocity); - initialVelocity = Vec3.multiply(Vec3.length(initialVelocity), this.arrow.direction); + var initialVelocity = Vec3.normalize(Vec3.cross(between, Y_AXIS)); + initialVelocity = Vec3.multiply(Math.sqrt((this.gravity * LARGE_BODY_MASS) / radius), initialVelocity); + initialVelocity = Vec3.multiply(this.arrow.magnitude, initialVelocity); + initialVelocity = Vec3.multiply(Vec3.length(initialVelocity), this.arrow.direction); - Entities.editEntity(this.satellite, { - velocity: initialVelocity - }); - this.launched = true; - }; + Entities.editEntity(this.satellite, { + velocity: initialVelocity + }); + this.launched = true; + }; - this.update = function(deltaTime) { - var prop = Entities.getEntityProperties(this.satellite); - var between = Vec3.subtract(prop.position, planetCenter); - var radius = Vec3.length(between); - var acceleration = -(this.gravity * LARGE_BODY_MASS) * Math.pow(radius, (-2.0)); - var speed = acceleration * deltaTime; - var vel = Vec3.multiply(speed, Vec3.normalize(between)); + this.update = function(deltaTime) { + var prop = Entities.getEntityProperties(this.satellite); + var between = Vec3.subtract(prop.position, planetCenter); + var radius = Vec3.length(between); + var acceleration = -(this.gravity * LARGE_BODY_MASS) * Math.pow(radius, (-2.0)); + var speed = acceleration * deltaTime; + var vel = Vec3.multiply(speed, Vec3.normalize(between)); - var newVelocity = Vec3.sum(prop.velocity, vel); - var newPos = Vec3.sum(prop.position, Vec3.multiply(newVelocity, deltaTime)); + var newVelocity = Vec3.sum(prop.velocity, vel); + var newPos = Vec3.sum(prop.position, Vec3.multiply(newVelocity, deltaTime)); - Entities.editEntity(this.satellite, { - velocity: newVelocity, - position: newPos - }); - }; - } + Entities.editEntity(this.satellite, { + velocity: newVelocity, + position: newPos + }); + }; + } - function mouseDoublePressEvent(event) { - var pickRay = Camera.computePickRay(event.x, event.y); - var addVector = Vec3.multiply(pickRay.direction, distance); - var point = Vec3.sum(Camera.getPosition(), addVector); + function mouseDoublePressEvent(event) { + var pickRay = Camera.computePickRay(event.x, event.y); + var addVector = Vec3.multiply(pickRay.direction, distance); + var point = Vec3.sum(Camera.getPosition(), addVector); - // Create a new satellite - activeSatellite = new Satellite(point, center); - satellites.push(activeSatellite); - } + // Create a new satellite + activeSatellite = new Satellite(point, center); + satellites.push(activeSatellite); + } - function mousePressEvent(event) { - if (!activeSatellite) { - return; - } - // Reset label - if (activeSatellite.arrow) { - activeSatellite.arrow.deleteLabel(); - } - var statsPosition = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE * 0.4, Quat.getFront(Camera.getOrientation()))); - var pickRay = Camera.computePickRay(event.x, event.y) - var rayPickResult = Entities.findRayIntersection(pickRay, true); - if (rayPickResult.entityID === activeSatellite.satellite) { - // Create a draggable vector arrow at satellite position - activeSatellite.arrow = new VectorArrow(distance, true, "INITIAL VELOCITY", statsPosition); - activeSatellite.arrow.onMousePressEvent(event); - activeSatellite.arrow.isDragging = true; - } - } + function mousePressEvent(event) { + if (!activeSatellite) { + return; + } + // Reset label + if (activeSatellite.arrow) { + activeSatellite.arrow.deleteLabel(); + } + var statsPosition = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE * 0.4, Quat.getFront(Camera.getOrientation()))); + var pickRay = Camera.computePickRay(event.x, event.y) + var rayPickResult = Entities.findRayIntersection(pickRay, true); + if (rayPickResult.entityID === activeSatellite.satellite) { + // Create a draggable vector arrow at satellite position + activeSatellite.arrow = new VectorArrow(distance, true, "INITIAL VELOCITY", statsPosition); + activeSatellite.arrow.onMousePressEvent(event); + activeSatellite.arrow.isDragging = true; + } + } - function mouseMoveEvent(event) { - if (!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { - return; - } - activeSatellite.arrow.onMouseMoveEvent(event); - } + function mouseMoveEvent(event) { + if (!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { + return; + } + activeSatellite.arrow.onMouseMoveEvent(event); + } - function mouseReleaseEvent(event) { - if (!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { - return; - } - activeSatellite.arrow.onMouseReleaseEvent(event); - activeSatellite.launch(); - activeSatellite.arrow.cleanup(); - } + function mouseReleaseEvent(event) { + if (!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { + return; + } + activeSatellite.arrow.onMouseReleaseEvent(event); + activeSatellite.launch(); + activeSatellite.arrow.cleanup(); + } - var counter = 0.0; - var CHECK_ENERGY_PERIOD = 500; + var counter = 0.0; + var CHECK_ENERGY_PERIOD = 500; - function update(deltaTime) { - if (!activeSatellite) { - return; - } - // Update all satellites - for (var i = 0; i < satellites.length; i++) { - if (!satellites[i].launched) { - continue; - } - satellites[i].update(deltaTime); - } + function update(deltaTime) { + if (!activeSatellite) { + return; + } + // Update all satellites + for (var i = 0; i < satellites.length; i++) { + if (!satellites[i].launched) { + continue; + } + satellites[i].update(deltaTime); + } - counter++; - if (counter % CHECK_ENERGY_PERIOD == 0) { - var prop = activeSatellite.getProperties(); - var error = calcEnergyError(prop.position, Vec3.length(prop.velocity)); - if (Math.abs(error) <= ERROR_THRESH) { - activeSatellite.arrow.editLabel("Nice job! The satellite has reached a stable orbit."); - } else { - activeSatellite.arrow.editLabel("Try again! The satellite is in an unstable orbit."); - } - } - } + counter++; + if (counter % CHECK_ENERGY_PERIOD == 0) { + var prop = activeSatellite.getProperties(); + var error = calcEnergyError(prop.position, Vec3.length(prop.velocity)); + if (Math.abs(error) <= ERROR_THRESH) { + activeSatellite.arrow.editLabel("Nice job! The satellite has reached a stable orbit."); + } else { + activeSatellite.arrow.editLabel("Try again! The satellite is in an unstable orbit."); + } + } + } - this.endGame = function() { - for (var i = 0; i < satellites.length; i++) { - Entities.deleteEntity(satellites[i].satellite); - satellites[i].arrow.cleanup(); - } - earth.cleanup(); - } + this.endGame = function() { + for (var i = 0; i < satellites.length; i++) { + Entities.deleteEntity(satellites[i].satellite); + satellites[i].arrow.cleanup(); + } + earth.cleanup(); + } - function calcEnergyError(pos, vel) { - //Calculate total energy error for active satellite's orbital motion - var radius = activeSatellite.radius; - var gravity = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (LARGE_BODY_MASS * PERIOD * PERIOD); - var initialVelocityCalculated = Math.sqrt((gravity * LARGE_BODY_MASS) / radius); + function calcEnergyError(pos, vel) { + //Calculate total energy error for active satellite's orbital motion + var radius = activeSatellite.radius; + var gravity = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (LARGE_BODY_MASS * PERIOD * PERIOD); + var initialVelocityCalculated = Math.sqrt((gravity * LARGE_BODY_MASS) / radius); - var totalEnergy = 0.5 * LARGE_BODY_MASS * Math.pow(initialVelocityCalculated, 2.0) - ((gravity * LARGE_BODY_MASS * SMALL_BODY_MASS) / radius); - var measuredEnergy = 0.5 * LARGE_BODY_MASS * Math.pow(vel, 2.0) - ((gravity * LARGE_BODY_MASS * SMALL_BODY_MASS) / Vec3.length(Vec3.subtract(pos, center))); - var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; - return error; - } + var totalEnergy = 0.5 * LARGE_BODY_MASS * Math.pow(initialVelocityCalculated, 2.0) - ((gravity * LARGE_BODY_MASS * SMALL_BODY_MASS) / radius); + var measuredEnergy = 0.5 * LARGE_BODY_MASS * Math.pow(vel, 2.0) - ((gravity * LARGE_BODY_MASS * SMALL_BODY_MASS) / Vec3.length(Vec3.subtract(pos, center))); + var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; + return error; + } - Controller.mousePressEvent.connect(mousePressEvent); - Controller.mouseDoublePressEvent.connect(mouseDoublePressEvent); - Controller.mouseMoveEvent.connect(mouseMoveEvent); - Controller.mouseReleaseEvent.connect(mouseReleaseEvent); - Script.update.connect(update); - Script.scriptEnding.connect(this.endGame); + Controller.mousePressEvent.connect(mousePressEvent); + Controller.mouseDoublePressEvent.connect(mouseDoublePressEvent); + Controller.mouseMoveEvent.connect(mouseMoveEvent); + Controller.mouseReleaseEvent.connect(mouseReleaseEvent); + Script.update.connect(update); + Script.scriptEnding.connect(this.endGame); } \ No newline at end of file From 34d63cdb43eceef33bd8ed4b66e06aae698ec2d1 Mon Sep 17 00:00:00 2001 From: Marcel Verhagen Date: Tue, 28 Jul 2015 22:02:36 +0200 Subject: [PATCH 30/74] Removed double "" --- interface/src/Menu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 0edd93c5a6..6487e6cac5 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -161,7 +161,7 @@ namespace MenuOption { const QString CenterPlayerInView = "Center Player In View"; const QString Chat = "Chat..."; const QString Collisions = "Collisions"; - const QString Connexion = "Activate 3D Connexion Devices""; + const QString Connexion = "Activate 3D Connexion Devices"; const QString Console = "Console..."; const QString ControlWithSpeech = "Control With Speech"; const QString CopyAddress = "Copy Address to Clipboard"; From 0b25fc335e84e43b75e9ed61ed6998b46ed0fec8 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 28 Jul 2015 13:21:29 -0700 Subject: [PATCH 31/74] Cleanup edit.js entity creation --- examples/edit.js | 228 ++++++++++++++++++++++------------------------- 1 file changed, 106 insertions(+), 122 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index a07779c19d..0f9c9fc4dd 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -291,22 +291,18 @@ var toolBar = (function () { var RESIZE_TIMEOUT = 120000; // 2 minutes var RESIZE_MAX_CHECKS = RESIZE_TIMEOUT / RESIZE_INTERVAL; function addModel(url) { - var position; + var entityID = createNewEntity({ + type: "Model", + dimensions: DEFAULT_DIMENSIONS, + modelURL: url + }, false); - position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); - - if (position.x > 0 && position.y > 0 && position.z > 0) { - var entityId = Entities.addEntity({ - type: "Model", - position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_DIMENSIONS), DEFAULT_DIMENSIONS), - dimensions: DEFAULT_DIMENSIONS, - modelURL: url - }); + if (entityID) { print("Model added: " + url); var checkCount = 0; function resize() { - var entityProperties = Entities.getEntityProperties(entityId); + var entityProperties = Entities.getEntityProperties(entityID); var naturalDimensions = entityProperties.naturalDimensions; checkCount++; @@ -318,21 +314,41 @@ var toolBar = (function () { print("Resize failed: timed out waiting for model (" + url + ") to load"); } } else { - Entities.editEntity(entityId, { dimensions: naturalDimensions }); + Entities.editEntity(entityID, { dimensions: naturalDimensions }); // Reset selection so that the selection overlays will be updated - selectionManager.setSelections([entityId]); + selectionManager.setSelections([entityID]); } } - selectionManager.setSelections([entityId]); + selectionManager.setSelections([entityID]); Script.setTimeout(resize, RESIZE_INTERVAL); - } else { - Window.alert("Can't add model: Model would be out of bounds."); } } + function createNewEntity(properties, dragOnCreate) { + // Default to true if not passed in + dragOnCreate = dragOnCreate == undefined ? true : dragOnCreate; + + var dimensions = properties.dimensions ? properties.dimensions : DEFAULT_DIMENSIONS; + var position = getPositionToCreateEntity(); + var entityID = null; + if (position != null) { + position = grid.snapToSurface(grid.snapToGrid(position, false, dimensions), dimensions), + properties.position = position; + + entityID = Entities.addEntity(properties); + if (dragOnCreate) { + placingEntityID = entityID; + } + } else { + Window.alert("Can't create " + properties.type + ": " + properties.type + " would be out of bounds."); + } + + return entityID; + } + var newModelButtonDown = false; var browseMarketplaceButtonDown = false; that.mousePressEvent = function (event) { @@ -363,127 +379,82 @@ var toolBar = (function () { } if (newCubeButton === toolBar.clicked(clickedOverlay)) { - var position = getPositionToCreateEntity(); + createNewEntity({ + type: "Box", + dimensions: DEFAULT_DIMENSIONS, + color: { red: 255, green: 0, blue: 0 } + }); - if (position.x > 0 && position.y > 0 && position.z > 0) { - placingEntityID = Entities.addEntity({ - type: "Box", - position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_DIMENSIONS), DEFAULT_DIMENSIONS), - dimensions: DEFAULT_DIMENSIONS, - color: { red: 255, green: 0, blue: 0 } - - }); - } else { - Window.alert("Can't create box: Box would be out of bounds."); - } return true; } if (newSphereButton === toolBar.clicked(clickedOverlay)) { - var position = getPositionToCreateEntity(); + createNewEntity({ + type: "Sphere", + dimensions: DEFAULT_DIMENSIONS, + color: { red: 255, green: 0, blue: 0 } + }); - if (position.x > 0 && position.y > 0 && position.z > 0) { - placingEntityID = Entities.addEntity({ - type: "Sphere", - position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_DIMENSIONS), DEFAULT_DIMENSIONS), - dimensions: DEFAULT_DIMENSIONS, - color: { red: 255, green: 0, blue: 0 } - }); - } else { - Window.alert("Can't create sphere: Sphere would be out of bounds."); - } return true; } if (newLightButton === toolBar.clicked(clickedOverlay)) { - var position = getPositionToCreateEntity(); + createNewEntity({ + type: "Light", + dimensions: DEFAULT_LIGHT_DIMENSIONS, + isSpotlight: false, + color: { red: 150, green: 150, blue: 150 }, - if (position.x > 0 && position.y > 0 && position.z > 0) { - placingEntityID = Entities.addEntity({ - type: "Light", - position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_LIGHT_DIMENSIONS), DEFAULT_LIGHT_DIMENSIONS), - dimensions: DEFAULT_LIGHT_DIMENSIONS, - isSpotlight: false, - color: { red: 150, green: 150, blue: 150 }, + constantAttenuation: 1, + linearAttenuation: 0, + quadraticAttenuation: 0, + exponent: 0, + cutoff: 180, // in degrees + }); - constantAttenuation: 1, - linearAttenuation: 0, - quadraticAttenuation: 0, - exponent: 0, - cutoff: 180, // in degrees - }); - } else { - Window.alert("Can't create Light: Light would be out of bounds."); - } return true; } - if (newTextButton === toolBar.clicked(clickedOverlay)) { - var position = getPositionToCreateEntity(); + createNewEntity({ + type: "Text", + dimensions: { x: 0.65, y: 0.3, z: 0.01 }, + backgroundColor: { red: 64, green: 64, blue: 64 }, + textColor: { red: 255, green: 255, blue: 255 }, + text: "some text", + lineHeight: 0.06 + }); - if (position.x > 0 && position.y > 0 && position.z > 0) { - placingEntityID = Entities.addEntity({ - type: "Text", - position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_DIMENSIONS), DEFAULT_DIMENSIONS), - dimensions: { x: 0.65, y: 0.3, z: 0.01 }, - backgroundColor: { red: 64, green: 64, blue: 64 }, - textColor: { red: 255, green: 255, blue: 255 }, - text: "some text", - lineHeight: 0.06 - }); - } else { - Window.alert("Can't create box: Text would be out of bounds."); - } return true; } if (newWebButton === toolBar.clicked(clickedOverlay)) { - var position = getPositionToCreateEntity(); + createNewEntity({ + type: "Web", + dimensions: { x: 1.6, y: 0.9, z: 0.01 }, + sourceUrl: "https://highfidelity.com/", + }); - if (position.x > 0 && position.y > 0 && position.z > 0) { - placingEntityID = Entities.addEntity({ - type: "Web", - position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_DIMENSIONS), DEFAULT_DIMENSIONS), - dimensions: { x: 1.6, y: 0.9, z: 0.01 }, - sourceUrl: "https://highfidelity.com/", - }); - } else { - Window.alert("Can't create Web Entity: would be out of bounds."); - } return true; } if (newZoneButton === toolBar.clicked(clickedOverlay)) { - var position = getPositionToCreateEntity(); + createNewEntity({ + type: "Zone", + dimensions: { x: 10, y: 10, z: 10 }, + }); - if (position.x > 0 && position.y > 0 && position.z > 0) { - placingEntityID = Entities.addEntity({ - type: "Zone", - position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_DIMENSIONS), DEFAULT_DIMENSIONS), - dimensions: { x: 10, y: 10, z: 10 }, - }); - } else { - Window.alert("Can't create box: Text would be out of bounds."); - } return true; } if (newPolyVoxButton === toolBar.clicked(clickedOverlay)) { - var position = getPositionToCreateEntity(); + createNewEntity({ + type: "PolyVox", + dimensions: { x: 10, y: 10, z: 10 }, + voxelVolumeSize: {x:16, y:16, z:16}, + voxelSurfaceStyle: 1 + }); - if (position.x > 0 && position.y > 0 && position.z > 0) { - placingEntityID = Entities.addEntity({ - type: "PolyVox", - position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_DIMENSIONS), - DEFAULT_DIMENSIONS), - dimensions: { x: 10, y: 10, z: 10 }, - voxelVolumeSize: {x:16, y:16, z:16}, - voxelSurfaceStyle: 1 - }); - } else { - Window.alert("Can't create PolyVox: would be out of bounds."); - } return true; } @@ -666,7 +637,7 @@ function handleIdleMouse() { idleMouseTimerId = null; if (isActive) { highlightEntityUnderCursor(lastMousePosition, true); - } + } } function highlightEntityUnderCursor(position, accurateRay) { @@ -837,15 +808,15 @@ function setupModelMenus() { } Menu.addMenuItem({ menuName: "Edit", menuItemName: "Entity List...", shortcutKey: "CTRL+META+L", afterItem: "Models" }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Large Models", shortcutKey: "CTRL+META+L", + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Large Models", shortcutKey: "CTRL+META+L", afterItem: "Entity List...", isCheckable: true, isChecked: true }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Small Models", shortcutKey: "CTRL+META+S", + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Small Models", shortcutKey: "CTRL+META+S", afterItem: "Allow Selecting of Large Models", isCheckable: true, isChecked: true }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Lights", shortcutKey: "CTRL+SHIFT+META+L", + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Lights", shortcutKey: "CTRL+SHIFT+META+L", afterItem: "Allow Selecting of Small Models", isCheckable: true }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Select All Entities In Box", shortcutKey: "CTRL+SHIFT+META+A", + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Select All Entities In Box", shortcutKey: "CTRL+SHIFT+META+A", afterItem: "Allow Selecting of Lights" }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Select All Entities Touching Box", shortcutKey: "CTRL+SHIFT+META+T", + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Select All Entities Touching Box", shortcutKey: "CTRL+SHIFT+META+T", afterItem: "Select All Entities In Box" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Models", isSeparator: true, beforeItem: "Settings" }); @@ -962,7 +933,7 @@ function selectAllEtitiesInCurrentSelectionBox(keepIfTouching) { entities.splice(i, 1); --i; } - } + } } selectionManager.setSelections(entities); } @@ -1038,17 +1009,29 @@ function handeMenuEvent(menuItem) { tooltip.show(false); } +// This function tries to find a reasonable position to place a new entity based on the camera +// position. If a reasonable position within the world bounds can't be found, `null` will +// be returned. The returned position will also take into account grid snapping settings. function getPositionToCreateEntity() { var distance = cameraManager.enabled ? cameraManager.zoomDistance : DEFAULT_ENTITY_DRAG_DROP_DISTANCE; var direction = Quat.getFront(Camera.orientation); var offset = Vec3.multiply(distance, direction); - var position = Vec3.sum(Camera.position, offset); + var placementPosition = Vec3.sum(Camera.position, offset); - position.x = Math.max(0, position.x); - position.y = Math.max(0, position.y); - position.z = Math.max(0, position.z); + var cameraPosition = Camera.position; - return position; + var cameraOutOfBounds = cameraPosition.x < 0 || cameraPosition.y < 0 || cameraPosition.z < 0; + var placementOutOfBounds = placementPosition.x < 0 || placementPosition.y < 0 || placementPosition.z < 0; + + if (cameraOutOfBounds && placementOutOfBounds) { + return null; + } + + placementPosition.x = Math.max(0, placementPosition.x); + placementPosition.y = Math.max(0, placementPosition.y); + placementPosition.z = Math.max(0, placementPosition.z); + + return placementPosition; } function importSVO(importURL) { @@ -1064,16 +1047,17 @@ function importSVO(importURL) { if (success) { var VERY_LARGE = 10000; - var position = { x: 0.01, y: 0.01, z: 0.01}; + var position = { x: 0, y: 0, z: 0 }; if (Clipboard.getClipboardContentsLargestDimension() < VERY_LARGE) { position = getPositionToCreateEntity(); } - if (position.x > 0 && position.y > 0 && position.z > 0) { + if (position != null) { var pastedEntityIDs = Clipboard.pasteEntities(position); if (isActive) { selectionManager.setSelections(pastedEntityIDs); } + Window.raiseMainWindow(); } else { Window.alert("Can't import objects: objects would be out of bounds."); @@ -1264,7 +1248,7 @@ PropertiesTool = function(opts) { if (data.properties.keyLightDirection !== undefined) { data.properties.keyLightDirection = Vec3.fromPolar( data.properties.keyLightDirection.x * DEGREES_TO_RADIANS, data.properties.keyLightDirection.y * DEGREES_TO_RADIANS); - } + } Entities.editEntity(selectionManager.selections[0], data.properties); if (data.properties.name != undefined) { entityListTool.sendUpdate(); @@ -1360,8 +1344,8 @@ PropertiesTool = function(opts) { var properties = selectionManager.savedProperties[selectionManager.selections[i]]; if (properties.type == "Zone") { var centerOfZone = properties.boundingBox.center; - var atmosphereCenter = { x: centerOfZone.x, - y: centerOfZone.y - properties.atmosphere.innerRadius, + var atmosphereCenter = { x: centerOfZone.x, + y: centerOfZone.y - properties.atmosphere.innerRadius, z: centerOfZone.z }; Entities.editEntity(selectionManager.selections[i], { From df9b66d2679c3740c8d885d5d02c2e37ea098e22 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Tue, 28 Jul 2015 15:08:52 -0700 Subject: [PATCH 32/74] Implement the uniform buffer and resource texture cache and their reset --- libraries/gpu/src/gpu/GLBackend.h | 30 +++++-- libraries/gpu/src/gpu/GLBackendPipeline.cpp | 86 +++++++++++++++++++-- 2 files changed, 103 insertions(+), 13 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 843e5d2006..215e01689b 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -197,6 +197,15 @@ public: uint32 getNumInputBuffers() const { return _input._invalidBuffers.size(); } + // this is the maximum per shader stage on the low end apple + // TODO make it platform dependant at init time + static const int MAX_NUM_UNIFORM_BUFFERS = 12; + uint32 getMaxNumUniformBuffers() const { return MAX_NUM_UNIFORM_BUFFERS; } + + // this is the maximum per shader stage on the low end apple + // TODO make it platform dependant at init time + static const int MAX_NUM_RESOURCE_TEXTURES = 16; + uint32 getMaxNumResourceTextures() const { return MAX_NUM_RESOURCE_TEXTURES; } // The State setters called by the GLState::Commands when a new state is assigned void do_setStateFillMode(int32 mode); @@ -332,19 +341,30 @@ protected: // Uniform Stage void do_setUniformBuffer(Batch& batch, uint32 paramOffset); - + + void releaseUniformBuffer(int slot); void resetUniformStage(); struct UniformStageState { - - }; + Buffers _buffers; + + UniformStageState(): + _buffers(MAX_NUM_UNIFORM_BUFFERS, nullptr) + {} + } _uniform; // Resource Stage void do_setResourceTexture(Batch& batch, uint32 paramOffset); + void releaseResourceTexture(int slot); void resetResourceStage(); struct ResourceStageState { - - }; + Textures _textures; + + ResourceStageState(): + _textures(MAX_NUM_RESOURCE_TEXTURES, nullptr) + {} + + } _resource; // Pipeline Stage void do_setPipeline(Batch& batch, uint32 paramOffset); diff --git a/libraries/gpu/src/gpu/GLBackendPipeline.cpp b/libraries/gpu/src/gpu/GLBackendPipeline.cpp index 4a54753af8..090dd4ad31 100755 --- a/libraries/gpu/src/gpu/GLBackendPipeline.cpp +++ b/libraries/gpu/src/gpu/GLBackendPipeline.cpp @@ -178,8 +178,27 @@ void GLBackend::resetPipelineStage() { glUseProgram(0); } + +void GLBackend::releaseUniformBuffer(int slot) { +#if (GPU_FEATURE_PROFILE == GPU_CORE) + auto& buf = _uniform._buffers[slot]; + if (buf) { + auto* object = Backend::getGPUObject(*buf); + if (object) { + GLuint bo = object->_buffer; + glBindBufferBase(GL_UNIFORM_BUFFER, slot, 0); // RELEASE + + (void) CHECK_GL_ERROR(); + } + buf.reset(); + } +#endif +} + void GLBackend::resetUniformStage() { - + for (int i = 0; i < _uniform._buffers.size(); i++) { + releaseUniformBuffer(i); + } } void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) { @@ -188,9 +207,31 @@ void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) { GLintptr rangeStart = batch._params[paramOffset + 1]._uint; GLsizeiptr rangeSize = batch._params[paramOffset + 0]._uint; + + + #if (GPU_FEATURE_PROFILE == GPU_CORE) - GLuint bo = getBufferID(*uniformBuffer); - glBindBufferRange(GL_UNIFORM_BUFFER, slot, bo, rangeStart, rangeSize); + if (!uniformBuffer) { + releaseUniformBuffer(slot); + return; + } + + // check cache before thinking + if (_uniform._buffers[slot] == uniformBuffer) { + return; + } + + // Sync BufferObject + auto* object = GLBackend::syncGPUObject(*uniformBuffer); + if (object) { + glBindBufferRange(GL_UNIFORM_BUFFER, slot, object->_buffer, rangeStart, rangeSize); + + _uniform._buffers[slot] = uniformBuffer; + (void) CHECK_GL_ERROR(); + } else { + releaseResourceTexture(slot); + return; + } #else // because we rely on the program uniform mechanism we need to have // the program bound, thank you MacOSX Legacy profile. @@ -202,23 +243,49 @@ void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) { // NOT working so we ll stick to the uniform float array until we move to core profile // GLuint bo = getBufferID(*uniformBuffer); //glUniformBufferEXT(_shader._program, slot, bo); -#endif + (void) CHECK_GL_ERROR(); + +#endif +} + +void GLBackend::releaseResourceTexture(int slot) { + auto& tex = _resource._textures[slot]; + if (tex) { + auto* object = Backend::getGPUObject(*tex); + if (object) { + GLuint to = object->_texture; + GLuint target = object->_target; + glActiveTexture(GL_TEXTURE0 + slot); + glBindTexture(target, 0); // RELEASE + + (void) CHECK_GL_ERROR(); + } + tex.reset(); + } } void GLBackend::resetResourceStage() { - + for (int i = 0; i < _resource._textures.size(); i++) { + releaseResourceTexture(i); + } } 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); + TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); - if (!uniformTexture) { + if (!resourceTexture) { + releaseResourceTexture(slot); + return; + } + // check cache before thinking + if (_resource._textures[slot] == resourceTexture) { return; } - GLTexture* object = GLBackend::syncGPUObject(*uniformTexture); + // Always make sure the GLObject is in sync + GLTexture* object = GLBackend::syncGPUObject(*resourceTexture); if (object) { GLuint to = object->_texture; GLuint target = object->_target; @@ -227,7 +294,10 @@ void GLBackend::do_setResourceTexture(Batch& batch, uint32 paramOffset) { (void) CHECK_GL_ERROR(); + _resource._textures[slot] = resourceTexture; + } else { + releaseResourceTexture(slot); return; } } From 469bace7ca4ec8d00ce2f6453f2d1d61df613e65 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 28 Jul 2015 15:15:34 -0700 Subject: [PATCH 33/74] removed unnessary computations from hit effect fragment shader --- libraries/render-utils/src/hit_effect.slf | 18 ++++++------------ libraries/render-utils/src/hit_effect.slv | 5 ++++- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/libraries/render-utils/src/hit_effect.slf b/libraries/render-utils/src/hit_effect.slf index 2c308f3711..6c0dcd7a70 100644 --- a/libraries/render-utils/src/hit_effect.slf +++ b/libraries/render-utils/src/hit_effect.slf @@ -11,20 +11,14 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -<@include gpu/Transform.slh@> -<$declareStandardTransform()$> + <@include DeferredBufferWrite.slh@> -void main(void) { +varying vec2 varQuadPosition; - TransformCamera cam = getTransformCamera(); - vec4 myViewport; - <$transformCameraViewport(cam, myViewport)$> - vec2 center = vec2(myViewport.z/2.0, myViewport.w/2.0); - float distFromCenter = distance(center, gl_FragCoord.xy); - //normalize distance from center based on average of screen width and height - float normalizationFactor = (myViewport.z + myViewport.w)/2.0; - distFromCenter = distFromCenter/normalizationFactor; - float alpha = mix(0.0, 1.0, pow(distFromCenter, 1.5)); +void main(void) { + vec2 center = vec2(0.0, 0.0); + float distFromCenter = distance( vec2(0.0, 0.0), varQuadPosition); + float alpha = mix(0.0, 0.5, pow(distFromCenter,5.)); gl_FragColor = vec4(1.0, 0.0, 0.0, alpha); } \ No newline at end of file diff --git a/libraries/render-utils/src/hit_effect.slv b/libraries/render-utils/src/hit_effect.slv index e7c3062667..d1efdebc18 100644 --- a/libraries/render-utils/src/hit_effect.slv +++ b/libraries/render-utils/src/hit_effect.slv @@ -16,6 +16,9 @@ <$declareStandardTransform()$> +varying vec2 varQuadPosition; + void main(void) { - gl_Position = gl_Vertex; + varQuadPosition = gl_Vertex.xy; + gl_Position = gl_Vertex; } \ No newline at end of file From 8b20f9d3a68a31450c95a6dbb90f51aa9fca8837 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Tue, 28 Jul 2015 15:48:01 -0700 Subject: [PATCH 34/74] do the minimum include to use glew on linux --- libraries/gpu/src/gpu/GLBackend.cpp | 7 +++++++ libraries/gpu/src/gpu/GPUConfig.h | 7 +++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index 6b1d552be9..3942af4f84 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -115,6 +115,13 @@ GLBackend::GLBackend() : #endif #if defined(Q_OS_LINUX) + GLenum err = glewInit(); + if (GLEW_OK != err) { + /* Problem: glewInit failed, something is seriously wrong. */ + qCDebug(gpulogging, "Error: %s\n", glewGetErrorString(err)); + } + qCDebug(gpulogging, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); + // TODO: Write the correct code for Linux... /* if (wglewGetExtension("WGL_EXT_swap_control")) { int swapInterval = wglGetSwapIntervalEXT(); diff --git a/libraries/gpu/src/gpu/GPUConfig.h b/libraries/gpu/src/gpu/GPUConfig.h index 1d092dbc6a..a9657076fa 100644 --- a/libraries/gpu/src/gpu/GPUConfig.h +++ b/libraries/gpu/src/gpu/GPUConfig.h @@ -34,8 +34,11 @@ #elif defined(ANDROID) #else -#include -#include + +#include +#include +//#include +//#include #define GPU_FEATURE_PROFILE GPU_LEGACY #define GPU_TRANSFORM_PROFILE GPU_LEGACY From 9cf3dfd3f7ef47469f87773daac5de87fba2b90f Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 28 Jul 2015 15:49:39 -0700 Subject: [PATCH 35/74] test this on windows ? --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b7522633ba..8f0a0e864f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1014,7 +1014,7 @@ void Application::paintGL() { // Back to the default framebuffer; gpu::Batch batch; batch.resetStages(); - renderArgs._context->render(batch); + // renderArgs._context->render(batch); } void Application::runTests() { From 27d3d3f450cc904636cfe55e13a4a1d053923c82 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 28 Jul 2015 15:51:15 -0700 Subject: [PATCH 36/74] fix w to x --- libraries/gpu/src/gpu/GPUConfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/gpu/src/gpu/GPUConfig.h b/libraries/gpu/src/gpu/GPUConfig.h index a9657076fa..2e3149919c 100644 --- a/libraries/gpu/src/gpu/GPUConfig.h +++ b/libraries/gpu/src/gpu/GPUConfig.h @@ -36,7 +36,7 @@ #else #include -#include +#include //#include //#include From b06485c266e783a1088d2f597a91ac1a22d17dd2 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 28 Jul 2015 17:41:45 -0700 Subject: [PATCH 37/74] Remove cauterize code from Rig and move it back into Model. * cauterize code is used as at render time and is not dependent on the jointStates. * MyAvatar now initialize the bone set used for cauterization and makes the decision to perform cauterization or not in preRender. --- interface/src/avatar/MyAvatar.cpp | 42 +++++++++++--- interface/src/avatar/MyAvatar.h | 4 +- interface/src/avatar/SkeletonModel.cpp | 10 +--- libraries/animation/src/Rig.cpp | 79 +++++--------------------- libraries/animation/src/Rig.h | 13 +---- libraries/render-utils/src/Model.cpp | 41 ++++++++++--- libraries/render-utils/src/Model.h | 16 +++++- 7 files changed, 98 insertions(+), 107 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5f0b5f03da..c995131427 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -969,12 +969,8 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { Avatar::setSkeletonModelURL(skeletonModelURL); render::ScenePointer scene = Application::getInstance()->getMain3DScene(); _billboardValid = false; - - if (_useFullAvatar) { - _skeletonModel.setVisibleInScene(_prevShouldDrawHead, scene); - } else { - _skeletonModel.setVisibleInScene(true, scene); - } + _skeletonModel.setVisibleInScene(true, scene); + _headBoneSet.clear(); } void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName) { @@ -1184,17 +1180,45 @@ void MyAvatar::setVisibleInSceneIfReady(Model* model, render::ScenePointer scene } } +void MyAvatar::initHeadBones() { + int neckJointIndex = -1; + if (_skeletonModel.getGeometry()) { + neckJointIndex = _skeletonModel.getGeometry()->getFBXGeometry().neckJointIndex; + } + if (neckJointIndex == -1) { + return; + } + _headBoneSet.clear(); + std::queue q; + q.push(neckJointIndex); + _headBoneSet.insert(neckJointIndex); + + // fbxJoints only hold links to parents not children, so we have to do a bit of extra work here. + while (q.size() > 0) { + int jointIndex = q.front(); + for (int i = 0; i < _skeletonModel.getJointStateCount(); i++) { + if (jointIndex == _skeletonModel.getParentJointIndex(i)) { + _headBoneSet.insert(i); + q.push(i); + } + } + q.pop(); + } +} + void MyAvatar::preRender(RenderArgs* renderArgs) { render::ScenePointer scene = Application::getInstance()->getMain3DScene(); const bool shouldDrawHead = shouldRenderHead(renderArgs); - _skeletonModel.initWhenReady(scene); + if (_skeletonModel.initWhenReady(scene)) { + initHeadBones(); + _skeletonModel.setCauterizeBoneSet(_headBoneSet); + } if (shouldDrawHead != _prevShouldDrawHead) { if (_useFullAvatar) { - _skeletonModel.setVisibleInScene(true, scene); - _rig->setFirstPerson(!shouldDrawHead); + _skeletonModel.setCauterizeBones(!shouldDrawHead); } else { getHead()->getFaceModel().setVisibleInScene(shouldDrawHead, scene); } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 802c92ec2c..67097a8f3b 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -273,7 +273,8 @@ private: void updatePosition(float deltaTime); void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void maybeUpdateBillboard(); - + void initHeadBones(); + // Avatar Preferences bool _useFullAvatar = false; QUrl _fullAvatarURLFromPreferences; @@ -286,6 +287,7 @@ private: RigPointer _rig; bool _prevShouldDrawHead; + std::unordered_set _headBoneSet; }; #endif // hifi_MyAvatar_h diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 636e58c5a8..122559bedb 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -51,7 +51,7 @@ SkeletonModel::~SkeletonModel() { void SkeletonModel::initJointStates(QVector states) { const FBXGeometry& geometry = _geometry->getFBXGeometry(); glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; - _boundingRadius = _rig->initJointStates(states, parentTransform, geometry.neckJointIndex); + _boundingRadius = _rig->initJointStates(states, parentTransform); // Determine the default eye position for avatar scale = 1.0 int headJointIndex = _geometry->getFBXGeometry().headJointIndex; @@ -175,14 +175,6 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); } } - - // if (_isFirstPerson) { - // cauterizeHead(); - // updateClusterMatrices(); - // } - if (_rig->getJointsAreDirty()) { - updateClusterMatrices(); - } } void SkeletonModel::renderIKConstraints(gpu::Batch& batch) { diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 0bd3f14096..302211b556 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -124,9 +124,8 @@ void Rig::deleteAnimations() { _animationHandles.clear(); } -float Rig::initJointStates(QVector states, glm::mat4 parentTransform, int neckJointIndex) { +float Rig::initJointStates(QVector states, glm::mat4 parentTransform) { _jointStates = states; - _neckJointIndex = neckJointIndex; initJointTransforms(parentTransform); int numStates = _jointStates.size(); @@ -142,8 +141,6 @@ float Rig::initJointStates(QVector states, glm::mat4 parentTransform _jointStates[i].slaveVisibleTransform(); } - initHeadBones(); - return radius; } @@ -195,8 +192,7 @@ JointState Rig::getJointState(int jointIndex) const { if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return JointState(); } - // return _jointStates[jointIndex]; - return maybeCauterizeHead(jointIndex); + return _jointStates[jointIndex]; } bool Rig::getJointStateRotation(int index, glm::quat& rotation) const { @@ -270,8 +266,7 @@ bool Rig::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position, return false; } // position is in world-frame - // position = translation + rotation * _jointStates[jointIndex].getPosition(); - position = translation + rotation * maybeCauterizeHead(jointIndex).getPosition(); + position = translation + rotation * _jointStates[jointIndex].getPosition(); return true; } @@ -280,7 +275,7 @@ bool Rig::getJointPosition(int jointIndex, glm::vec3& position) const { return false; } // position is in model-frame - position = extractTranslation(maybeCauterizeHead(jointIndex).getTransform()); + position = extractTranslation(_jointStates[jointIndex].getTransform()); return true; } @@ -288,7 +283,7 @@ bool Rig::getJointRotationInWorldFrame(int jointIndex, glm::quat& result, const if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return false; } - result = rotation * maybeCauterizeHead(jointIndex).getRotation(); + result = rotation * _jointStates[jointIndex].getRotation(); return true; } @@ -296,7 +291,7 @@ bool Rig::getJointRotation(int jointIndex, glm::quat& rotation) const { if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return false; } - rotation = maybeCauterizeHead(jointIndex).getRotation(); + rotation = _jointStates[jointIndex].getRotation(); return true; } @@ -304,7 +299,7 @@ bool Rig::getJointCombinedRotation(int jointIndex, glm::quat& result, const glm: if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return false; } - result = rotation * maybeCauterizeHead(jointIndex).getRotation(); + result = rotation * _jointStates[jointIndex].getRotation(); return true; } @@ -315,7 +310,7 @@ bool Rig::getVisibleJointPositionInWorldFrame(int jointIndex, glm::vec3& positio return false; } // position is in world-frame - position = translation + rotation * maybeCauterizeHead(jointIndex).getVisiblePosition(); + position = translation + rotation * _jointStates[jointIndex].getVisiblePosition(); return true; } @@ -323,7 +318,7 @@ bool Rig::getVisibleJointRotationInWorldFrame(int jointIndex, glm::quat& result, if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return false; } - result = rotation * maybeCauterizeHead(jointIndex).getVisibleRotation(); + result = rotation * _jointStates[jointIndex].getVisibleRotation(); return true; } @@ -331,14 +326,14 @@ glm::mat4 Rig::getJointTransform(int jointIndex) const { if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return glm::mat4(); } - return maybeCauterizeHead(jointIndex).getTransform(); + return _jointStates[jointIndex].getTransform(); } glm::mat4 Rig::getJointVisibleTransform(int jointIndex) const { if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return glm::mat4(); } - return maybeCauterizeHead(jointIndex).getVisibleTransform(); + return _jointStates[jointIndex].getVisibleTransform(); } void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation) { @@ -624,7 +619,7 @@ glm::vec3 Rig::getJointDefaultTranslationInConstrainedFrame(int jointIndex) { if (jointIndex == -1 || _jointStates.isEmpty()) { return glm::vec3(); } - return maybeCauterizeHead(jointIndex).getDefaultTranslationInConstrainedFrame(); + return _jointStates[jointIndex].getDefaultTranslationInConstrainedFrame(); } glm::quat Rig::setJointRotationInConstrainedFrame(int jointIndex, glm::quat targetRotation, float priority, bool constrain) { @@ -669,53 +664,5 @@ glm::quat Rig::getJointDefaultRotationInParentFrame(int jointIndex) { if (jointIndex == -1 || _jointStates.isEmpty()) { return glm::quat(); } - return maybeCauterizeHead(jointIndex).getDefaultRotationInParentFrame(); -} - -void Rig::initHeadBones() { - if (_neckJointIndex == -1) { - return; - } - _headBones.clear(); - std::queue q; - q.push(_neckJointIndex); - _headBones.push_back(_neckJointIndex); - - // fbxJoints only hold links to parents not children, so we have to do a bit of extra work here. - while (q.size() > 0) { - int jointIndex = q.front(); - for (int i = 0; i < _jointStates.size(); i++) { - const FBXJoint& fbxJoint = _jointStates[i].getFBXJoint(); - if (jointIndex == fbxJoint.parentIndex) { - _headBones.push_back(i); - q.push(i); - } - } - q.pop(); - } -} - -JointState Rig::maybeCauterizeHead(int jointIndex) const { - // if (_headBones.contains(jointIndex)) { - // XXX fix this... make _headBones a hash? add a flag to JointState? - if (_neckJointIndex != -1 && - _isFirstPerson && - std::find(_headBones.begin(), _headBones.end(), jointIndex) != _headBones.end()) { - glm::vec4 trans = _jointStates[jointIndex].getTransform()[3]; - glm::vec4 zero(0, 0, 0, 0); - glm::mat4 newXform(zero, zero, zero, trans); - JointState jointStateCopy = _jointStates[jointIndex]; - jointStateCopy.setTransform(newXform); - jointStateCopy.setVisibleTransform(newXform); - return jointStateCopy; - } else { - return _jointStates[jointIndex]; - } -} - -void Rig::setFirstPerson(bool isFirstPerson) { - if (_isFirstPerson != isFirstPerson) { - _isFirstPerson = isFirstPerson; - _jointsAreDirty = true; - } + return _jointStates[jointIndex].getDefaultRotationInParentFrame(); } diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 52d5866369..fe6bc82f35 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -75,7 +75,7 @@ public: float priority = 1.0f, bool loop = false, bool hold = false, float firstFrame = 0.0f, float lastFrame = FLT_MAX, const QStringList& maskedJoints = QStringList(), bool startAutomatically = false); - float initJointStates(QVector states, glm::mat4 parentTransform, int neckJointIndex); + float initJointStates(QVector states, glm::mat4 parentTransform); bool jointStatesEmpty() { return _jointStates.isEmpty(); }; int getJointStateCount() const { return _jointStates.size(); } int indexOfJoint(const QString& jointName) ; @@ -131,10 +131,6 @@ public: virtual void updateJointState(int index, glm::mat4 parentTransform) = 0; virtual void updateFaceJointState(int index, glm::mat4 parentTransform) = 0; - virtual void setFirstPerson(bool isFirstPerson); - virtual bool getIsFirstPerson() const { return _isFirstPerson; } - - bool getJointsAreDirty() { return _jointsAreDirty; } void setEnableRig(bool isEnabled) { _enableRig = isEnabled; } protected: @@ -143,13 +139,6 @@ public: QList _animationHandles; QList _runningAnimations; - JointState maybeCauterizeHead(int jointIndex) const; - void initHeadBones(); - bool _isFirstPerson = false; - std::vector _headBones; - bool _jointsAreDirty = false; - int _neckJointIndex = -1; - bool _enableRig; bool _isWalking; bool _isTurning; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 92e49fdc55..803658a667 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -67,6 +67,7 @@ Model::Model(RigPointer rig, QObject* parent) : _snapModelToRegistrationPoint(false), _snappedToRegistrationPoint(false), _showTrueJointTransforms(true), + _cauterizeBones(false), _lodDistance(0.0f), _pupilDilation(0.0f), _url("http://invalid.com"), @@ -452,6 +453,7 @@ bool Model::updateGeometry() { foreach (const FBXMesh& mesh, fbxGeometry.meshes) { MeshState state; state.clusterMatrices.resize(mesh.clusters.size()); + state.cauterizedClusterMatrices.resize(mesh.clusters.size()); _meshStates.append(state); auto buffer = std::make_shared(); @@ -472,7 +474,7 @@ bool Model::updateGeometry() { void Model::initJointStates(QVector states) { const FBXGeometry& geometry = _geometry->getFBXGeometry(); glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; - _boundingRadius = _rig->initJointStates(states, parentTransform, geometry.neckJointIndex); + _boundingRadius = _rig->initJointStates(states, parentTransform); } bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance, @@ -1337,6 +1339,12 @@ void Model::simulateInternal(float deltaTime) { glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; updateRig(deltaTime, parentTransform); + glm::mat4 zeroScale(glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), + glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), + glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), + glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); + auto cauterizeMatrix = _rig->getJointTransform(geometry.neckJointIndex) * zeroScale; + glm::mat4 modelToWorld = glm::mat4_cast(_rotation); for (int i = 0; i < _meshStates.size(); i++) { MeshState& state = _meshStates[i]; @@ -1344,14 +1352,30 @@ void Model::simulateInternal(float deltaTime) { if (_showTrueJointTransforms) { for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); - state.clusterMatrices[j] = - modelToWorld * _rig->getJointTransform(cluster.jointIndex) * cluster.inverseBindMatrix; + auto jointMatrix =_rig->getJointTransform(cluster.jointIndex); + state.clusterMatrices[j] = modelToWorld * jointMatrix * cluster.inverseBindMatrix; + + // as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty. + if (!_cauterizeBoneSet.empty()) { + if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) { + jointMatrix = cauterizeMatrix; + } + state.cauterizedClusterMatrices[j] = modelToWorld * jointMatrix * cluster.inverseBindMatrix; + } } } else { for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); - state.clusterMatrices[j] = - modelToWorld * _rig->getJointVisibleTransform(cluster.jointIndex) * cluster.inverseBindMatrix; + auto jointMatrix = _rig->getJointVisibleTransform(cluster.jointIndex); + state.clusterMatrices[j] = modelToWorld * jointMatrix * cluster.inverseBindMatrix; + + // as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty. + if (!_cauterizeBoneSet.empty()) { + if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) { + jointMatrix = cauterizeMatrix; + } + state.cauterizedClusterMatrices[j] = modelToWorld * jointMatrix * cluster.inverseBindMatrix; + } } } } @@ -1611,8 +1635,11 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran } if (isSkinned) { - batch._glUniformMatrix4fv(locations->clusterMatrices, state.clusterMatrices.size(), false, - (const float*)state.clusterMatrices.constData()); + const float* bones = (const float*)state.clusterMatrices.constData(); + if (_cauterizeBones) { + bones = (const float*)state.cauterizedClusterMatrices.constData(); + } + batch._glUniformMatrix4fv(locations->clusterMatrices, state.clusterMatrices.size(), false, bones); _transforms[0] = Transform(); _transforms[0].preTranslate(_translation); } else { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 83527969b2..1dab3f37a1 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -172,6 +173,9 @@ public: /// \return true if joint exists bool getJointRotation(int jointIndex, glm::quat& rotation) const; + /// Returns the index of the parent of the indexed joint, or -1 if not found. + int getParentJointIndex(int jointIndex) const; + void inverseKinematics(int jointIndex, glm::vec3 position, const glm::quat& rotation, float priority); /// Returns the extents of the model in its bind pose. @@ -187,6 +191,12 @@ public: bool getIsScaledToFit() const { return _scaledToFit; } /// is model scaled to fit const glm::vec3& getScaleToFitDimensions() const { return _scaleToFitDimensions; } /// the dimensions model is scaled to + void setCauterizeBones(bool flag) { _cauterizeBones = flag; } + bool getCauterizeBones() const { return _cauterizeBones; } + + const std::unordered_set& getCauterizeBoneSet() const { return _cauterizeBoneSet; } + void setCauterizeBoneSet(const std::unordered_set& boneSet) { _cauterizeBoneSet = boneSet; } + protected: void setPupilDilation(float dilation) { _pupilDilation = dilation; } @@ -218,9 +228,6 @@ protected: /// Clear the joint states void clearJointState(int index); - /// Returns the index of the parent of the indexed joint, or -1 if not found. - int getParentJointIndex(int jointIndex) const; - /// Returns the index of the last free ancestor of the indexed joint, or -1 if not found. int getLastFreeJointIndex(int jointIndex) const; @@ -255,9 +262,12 @@ protected: class MeshState { public: QVector clusterMatrices; + QVector cauterizedClusterMatrices; }; QVector _meshStates; + std::unordered_set _cauterizeBoneSet; + bool _cauterizeBones; // returns 'true' if needs fullUpdate after geometry change bool updateGeometry(); From 77a12eb50ea7af97a46060e178c2d6479af0bdc0 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 28 Jul 2015 17:53:01 -0700 Subject: [PATCH 38/74] compile on linux with GLEW --- cmake/modules/FindGLEW.cmake | 14 +++++++ interface/CMakeLists.txt | 6 +++ interface/src/Stars.cpp | 10 ++--- interface/src/devices/OculusManager.cpp | 6 +-- interface/src/devices/TV3DManager.cpp | 9 +++-- interface/src/devices/TV3DManager.h | 1 + .../src/RenderablePolyVoxEntityItem.cpp | 2 +- .../src/RenderableWebEntityItem.cpp | 3 +- libraries/gpu/CMakeLists.txt | 7 +++- libraries/gpu/src/gpu/Batch.cpp | 6 +-- libraries/gpu/src/gpu/GLBackend.cpp | 3 +- libraries/gpu/src/gpu/GLBackendQuery.cpp | 1 - libraries/gpu/src/gpu/GLBackendShader.cpp | 1 - libraries/gpu/src/gpu/GLBackendShared.h | 5 ++- libraries/gpu/src/gpu/GPUConfig.h | 2 +- libraries/model/src/model/Material.h | 2 +- .../src/AmbientOcclusionEffect.cpp | 6 +-- .../src/DeferredLightingEffect.cpp | 38 +++++++++--------- libraries/render-utils/src/GeometryCache.cpp | 10 ++--- libraries/render-utils/src/Model.cpp | 8 ++-- .../render-utils/src/RenderDeferredTask.cpp | 4 +- libraries/render-utils/src/TextureCache.cpp | 7 ++-- libraries/render/src/render/DrawStatus.cpp | 7 ++-- libraries/render/src/render/DrawTask.cpp | 6 +-- tests/render-utils/src/main.cpp | 39 ++++++++++--------- 25 files changed, 109 insertions(+), 94 deletions(-) diff --git a/cmake/modules/FindGLEW.cmake b/cmake/modules/FindGLEW.cmake index e86db3fdac..b1789fb614 100644 --- a/cmake/modules/FindGLEW.cmake +++ b/cmake/modules/FindGLEW.cmake @@ -38,5 +38,19 @@ if (WIN32) find_package_handle_standard_args(GLEW DEFAULT_MSG GLEW_INCLUDE_DIRS GLEW_LIBRARIES GLEW_DLL_PATH) add_paths_to_fixup_libs(${GLEW_DLL_PATH}) +elseif (APPLE) +else () + find_path(GLEW_INCLUDE_DIR GL/glew.h) + find_library(GLEW_LIBRARY NAMES GLEW glew32 glew glew32s PATH_SUFFIXES lib64) + + set(GLEW_INCLUDE_DIRS ${GLEW_INCLUDE_DIR}) + set(GLEW_LIBRARIES ${GLEW_LIBRARY}) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(GLEW + REQUIRED_VARS GLEW_INCLUDE_DIR GLEW_LIBRARY) + + mark_as_advanced(GLEW_INCLUDE_DIR GLEW_LIBRARY) + endif () diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 0c44ac801f..6af3cfa08b 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -245,6 +245,12 @@ else (APPLE) endif () endif() + else (WIN32) + find_package(GLEW REQUIRED) + target_include_directories(${TARGET_NAME} PRIVATE ${GLEW_INCLUDE_DIRS}) + + target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARIES}) + message(STATUS ${GLEW_LIBRARY}) endif() endif (APPLE) diff --git a/interface/src/Stars.cpp b/interface/src/Stars.cpp index ebfddee38c..7b612acb68 100644 --- a/interface/src/Stars.cpp +++ b/interface/src/Stars.cpp @@ -14,8 +14,6 @@ #include #include -#include -#include #include #include #include @@ -207,7 +205,7 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { batch._glUniform1f(_timeSlot, secs); geometryCache->renderUnitCube(batch); - glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); + //glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); static const size_t VERTEX_STRIDE = sizeof(StarVertex); size_t offset = offsetof(StarVertex, position); @@ -217,9 +215,9 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { // Render the stars batch.setPipeline(_starsPipeline); - batch._glEnable(GL_PROGRAM_POINT_SIZE_EXT); - batch._glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); - batch._glEnable(GL_POINT_SMOOTH); + //batch._glEnable(GL_PROGRAM_POINT_SIZE_EXT); + //batch._glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + //batch._glEnable(GL_POINT_SMOOTH); batch.setInputFormat(streamFormat); batch.setInputBuffer(VERTICES_SLOT, posView); diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index c9c70b4417..16685df96f 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -11,16 +11,16 @@ // #include "OculusManager.h" -#include +#include #include #include +#include #include +#include #include #include -#include -#include #include #include diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp index fefaf060bd..5dee5988c1 100644 --- a/interface/src/devices/TV3DManager.cpp +++ b/interface/src/devices/TV3DManager.cpp @@ -9,13 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "TV3DManager.h" + #include #include -#include "gpu/GLBackend.h" -#include "Application.h" +#include -#include "TV3DManager.h" +#include "Application.h" #include "Menu.h" int TV3DManager::_screenWidth = 1; @@ -63,6 +64,7 @@ void TV3DManager::setFrustum(Camera& whichCamera) { } void TV3DManager::configureCamera(Camera& whichCamera, int screenWidth, int screenHeight) { +#ifdef THIS_CURRENTLY_BROKEN_WAITING_FOR_DISPLAY_PLUGINS if (screenHeight == 0) { screenHeight = 1; // prevent divide by 0 } @@ -72,6 +74,7 @@ void TV3DManager::configureCamera(Camera& whichCamera, int screenWidth, int scre setFrustum(whichCamera); glViewport (0, 0, _screenWidth, _screenHeight); // sets drawing viewport +#endif } void TV3DManager::display(RenderArgs* renderArgs, Camera& whichCamera) { diff --git a/interface/src/devices/TV3DManager.h b/interface/src/devices/TV3DManager.h index 330a4ee0ee..96ee79f7d1 100644 --- a/interface/src/devices/TV3DManager.h +++ b/interface/src/devices/TV3DManager.h @@ -17,6 +17,7 @@ #include class Camera; +class RenderArgs; struct eyeFrustum { double left; diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index d3ee312311..681702bb07 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -35,7 +35,7 @@ #include #include "model/Geometry.h" -#include "gpu/GLBackend.h" +#include "gpu/Context.h" #include "EntityTreeRenderer.h" #include "RenderablePolyVoxEntityItem.h" diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 7fa615073b..9e48164647 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -8,7 +8,6 @@ #include "RenderableWebEntityItem.h" -#include #include #include #include @@ -24,7 +23,7 @@ #include #include #include -#include +#include #include "EntityTreeRenderer.h" diff --git a/libraries/gpu/CMakeLists.txt b/libraries/gpu/CMakeLists.txt index 30949b83e1..eda168091e 100644 --- a/libraries/gpu/CMakeLists.txt +++ b/libraries/gpu/CMakeLists.txt @@ -31,13 +31,16 @@ elseif (WIN32) elseif (ANDROID) target_link_libraries(${TARGET_NAME} "-lGLESv3" "-lEGL") else () + find_package(GLEW REQUIRED) + target_include_directories(${TARGET_NAME} PUBLIC ${GLEW_INCLUDE_DIRS}) + find_package(OpenGL REQUIRED) if (${OPENGL_INCLUDE_DIR}) include_directories(SYSTEM "${OPENGL_INCLUDE_DIR}") endif () - target_link_libraries(${TARGET_NAME} "${OPENGL_LIBRARY}") + target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" "${OPENGL_LIBRARY}") - target_include_directories(${TARGET_NAME} PUBLIC ${OPENGL_INCLUDE_DIR}) + # target_include_directories(${TARGET_NAME} PUBLIC ${OPENGL_INCLUDE_DIR}) endif (APPLE) diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 4ac33d8f14..b7f3ef444c 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -9,11 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "Batch.h" -#include "GPUConfig.h" - -#include #include +#include + +#include "GPUConfig.h" #if defined(NSIGHT_FOUND) diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index 3942af4f84..4bc8abadd0 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -8,9 +8,10 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "GLBackendShared.h" + #include #include "GPULogging.h" -#include "GLBackendShared.h" #include using namespace gpu; diff --git a/libraries/gpu/src/gpu/GLBackendQuery.cpp b/libraries/gpu/src/gpu/GLBackendQuery.cpp index 39db19dafd..297bdf9c40 100644 --- a/libraries/gpu/src/gpu/GLBackendQuery.cpp +++ b/libraries/gpu/src/gpu/GLBackendQuery.cpp @@ -8,7 +8,6 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "GPULogging.h" #include "GLBackendShared.h" diff --git a/libraries/gpu/src/gpu/GLBackendShader.cpp b/libraries/gpu/src/gpu/GLBackendShader.cpp index fd5bed2e5e..dccd035cb4 100755 --- a/libraries/gpu/src/gpu/GLBackendShader.cpp +++ b/libraries/gpu/src/gpu/GLBackendShader.cpp @@ -8,7 +8,6 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "GPULogging.h" #include "GLBackendShared.h" #include "Format.h" diff --git a/libraries/gpu/src/gpu/GLBackendShared.h b/libraries/gpu/src/gpu/GLBackendShared.h index 27f58fcbe3..75bef461f9 100644 --- a/libraries/gpu/src/gpu/GLBackendShared.h +++ b/libraries/gpu/src/gpu/GLBackendShared.h @@ -11,10 +11,11 @@ #ifndef hifi_gpu_GLBackend_Shared_h #define hifi_gpu_GLBackend_Shared_h -#include "GLBackend.h" - #include +#include "GPULogging.h" +#include "GLBackend.h" + #include "Batch.h" static const GLenum _primitiveToGLmode[gpu::NUM_PRIMITIVES] = { diff --git a/libraries/gpu/src/gpu/GPUConfig.h b/libraries/gpu/src/gpu/GPUConfig.h index 2e3149919c..5046221ad3 100644 --- a/libraries/gpu/src/gpu/GPUConfig.h +++ b/libraries/gpu/src/gpu/GPUConfig.h @@ -36,7 +36,7 @@ #else #include -#include +//#include //#include //#include diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index 392fd918a1..a1a17d29e9 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -13,13 +13,13 @@ #include #include +#include #include #include "gpu/Resource.h" #include "gpu/Texture.h" -#include namespace model { diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index f19fa6e18a..22e5a705e3 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -9,15 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL -#include - -#include #include #include #include +#include #include "gpu/StandardShaderLib.h" #include "AmbientOcclusionEffect.h" @@ -176,7 +173,6 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons assert(renderContext->args); assert(renderContext->args->_viewFrustum); RenderArgs* args = renderContext->args; - auto& scene = sceneContext->_scene; gpu::Batch batch; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index c14bbfcb1d..7563609026 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -12,12 +12,12 @@ #include "DeferredLightingEffect.h" #include -#include +#include +#include + #include #include #include -#include -#include #include "AbstractViewStateInterface.h" #include "GeometryCache.h" @@ -291,7 +291,7 @@ void DeferredLightingEffect::render(RenderArgs* args) { locations = &_directionalAmbientSphereLightCascadedShadowMapLocations; } batch.setPipeline(program); - batch._glUniform3fv(locations->shadowDistances, 1, (const GLfloat*) &_viewState->getShadowDistances()); + batch._glUniform3fv(locations->shadowDistances, 1, (const float*) &_viewState->getShadowDistances()); } else { if (useSkyboxCubemap) { @@ -325,7 +325,7 @@ void DeferredLightingEffect::render(RenderArgs* args) { sh = (*_skybox->getCubemap()->getIrradiance()); } for (int i =0; i ambientSphere + i, 1, (const GLfloat*) (&sh) + i * 4); + batch._glUniform4fv(locations->ambientSphere + i, 1, (const float*) (&sh) + i * 4); } } @@ -340,7 +340,7 @@ void DeferredLightingEffect::render(RenderArgs* args) { if (_atmosphere && (locations->atmosphereBufferUnit >= 0)) { batch.setUniformBuffer(locations->atmosphereBufferUnit, _atmosphere->getDataBuffer()); } - batch._glUniformMatrix4fv(locations->invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat)); + batch._glUniformMatrix4fv(locations->invViewMat, 1, false, reinterpret_cast< const float* >(&invViewMat)); } float left, right, bottom, top, nearVal, farVal; @@ -419,9 +419,9 @@ void DeferredLightingEffect::render(RenderArgs* args) { batch._glUniform2f(_pointLightLocations.depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT); batch._glUniform2f(_pointLightLocations.depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT); - batch._glUniformMatrix4fv(_pointLightLocations.invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat)); + batch._glUniformMatrix4fv(_pointLightLocations.invViewMat, 1, false, reinterpret_cast< const float* >(&invViewMat)); - batch._glUniformMatrix4fv(_pointLightLocations.texcoordMat, 1, false, reinterpret_cast< const GLfloat* >(&texcoordMat)); + batch._glUniformMatrix4fv(_pointLightLocations.texcoordMat, 1, false, reinterpret_cast< const float* >(&texcoordMat)); for (auto lightID : _pointLights) { auto& light = _allocatedLights[lightID]; @@ -467,9 +467,9 @@ void DeferredLightingEffect::render(RenderArgs* args) { batch._glUniform2f(_spotLightLocations.depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT); batch._glUniform2f(_spotLightLocations.depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT); - batch._glUniformMatrix4fv(_spotLightLocations.invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat)); + batch._glUniformMatrix4fv(_spotLightLocations.invViewMat, 1, false, reinterpret_cast< const float* >(&invViewMat)); - batch._glUniformMatrix4fv(_spotLightLocations.texcoordMat, 1, false, reinterpret_cast< const GLfloat* >(&texcoordMat)); + batch._glUniformMatrix4fv(_spotLightLocations.texcoordMat, 1, false, reinterpret_cast< const float* >(&texcoordMat)); for (auto lightID : _spotLights) { auto light = _allocatedLights[lightID]; @@ -489,7 +489,7 @@ void DeferredLightingEffect::render(RenderArgs* args) { if ((eyeHalfPlaneDistance > -nearRadius) && (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius)) { coneParam.w = 0.0f; - batch._glUniform4fv(_spotLightLocations.coneParam, 1, reinterpret_cast< const GLfloat* >(&coneParam)); + batch._glUniform4fv(_spotLightLocations.coneParam, 1, reinterpret_cast< const float* >(&coneParam)); Transform model; model.setTranslation(glm::vec3(0.0f, 0.0f, -1.0f)); @@ -509,7 +509,7 @@ void DeferredLightingEffect::render(RenderArgs* args) { batch.setViewTransform(viewMat); } else { coneParam.w = 1.0f; - batch._glUniform4fv(_spotLightLocations.coneParam, 1, reinterpret_cast< const GLfloat* >(&coneParam)); + batch._glUniform4fv(_spotLightLocations.coneParam, 1, reinterpret_cast< const float* >(&coneParam)); Transform model; model.setTranslation(light->getPosition()); @@ -595,9 +595,9 @@ void DeferredLightingEffect::loadLightProgram(const char* vertSource, const char slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), 3)); slotBindings.insert(gpu::Shader::Binding(std::string("shadowMap"), 4)); slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), 5)); - const GLint LIGHT_GPU_SLOT = 3; + const int LIGHT_GPU_SLOT = 3; slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_GPU_SLOT)); - const GLint ATMOSPHERE_GPU_SLOT = 4; + const int ATMOSPHERE_GPU_SLOT = 4; slotBindings.insert(gpu::Shader::Binding(std::string("atmosphereBufferUnit"), ATMOSPHERE_GPU_SLOT)); gpu::Shader::makeProgram(*program, slotBindings); @@ -677,10 +677,10 @@ model::MeshPointer DeferredLightingEffect::getSpotLightMesh() { int ringFloatOffset = slices * 3; - GLfloat* vertexData = new GLfloat[verticesSize]; - GLfloat* vertexRing0 = vertexData; - GLfloat* vertexRing1 = vertexRing0 + ringFloatOffset; - GLfloat* vertexRing2 = vertexRing1 + ringFloatOffset; + float* vertexData = new float[verticesSize]; + float* vertexRing0 = vertexData; + float* vertexRing1 = vertexRing0 + ringFloatOffset; + float* vertexRing2 = vertexRing1 + ringFloatOffset; for (int i = 0; i < slices; i++) { float theta = TWO_PI * i / slices; @@ -746,7 +746,7 @@ model::MeshPointer DeferredLightingEffect::getSpotLightMesh() { *(index++) = capVertex; } - _spotLightMesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(sizeof(GLushort) * indices, (gpu::Byte*) indexData), gpu::Element::INDEX_UINT16)); + _spotLightMesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(sizeof(unsigned short) * indices, (gpu::Byte*) indexData), gpu::Element::INDEX_UINT16)); delete[] indexData; model::Mesh::Part part(0, indices, 0, model::Mesh::TRIANGLES); diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 8550f8d8b6..b873b35b9c 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -9,22 +9,22 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// include this before QOpenGLBuffer, which includes an earlier version of OpenGL +#include "GeometryCache.h" + #include #include #include #include -#include -#include - #include #include +#include +#include + #include "TextureCache.h" #include "RenderUtilsLogging.h" -#include "GeometryCache.h" #include "standardTransformPNTC_vert.h" #include "standardDrawTexture_frag.h" diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 67eb85edfc..1e0e04c776 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -18,20 +18,18 @@ #include #include -#include -#include #include #include -#include "PhysicsEntity.h" #include #include #include +#include +#include #include "AbstractViewStateInterface.h" #include "AnimationHandle.h" #include "DeferredLightingEffect.h" #include "Model.h" -#include "RenderUtilsLogging.h" #include "model_vert.h" #include "model_shadow_vert.h" @@ -96,7 +94,7 @@ Model::~Model() { } Model::RenderPipelineLib Model::_renderPipelineLib; -const GLint MATERIAL_GPU_SLOT = 3; +const int MATERIAL_GPU_SLOT = 3; void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key, gpu::ShaderPointer& vertexShader, diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index cf9b455059..b4863a4764 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -10,12 +10,10 @@ // #include "RenderDeferredTask.h" -#include -#include -#include #include #include #include +#include #include "FramebufferCache.h" #include "DeferredLightingEffect.h" diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index 1a6ea97b64..d6a9bf5b36 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -16,16 +16,15 @@ #include #include -#include -#include -#include - #include #include #include #include #include +#include + + #include "RenderUtilsLogging.h" diff --git a/libraries/render/src/render/DrawStatus.cpp b/libraries/render/src/render/DrawStatus.cpp index f84d212112..f50f517d7d 100644 --- a/libraries/render/src/render/DrawStatus.cpp +++ b/libraries/render/src/render/DrawStatus.cpp @@ -15,15 +15,14 @@ #include #include +#include +#include #include #include #include #include -#include -#include - #include "drawItemBounds_vert.h" #include "drawItemBounds_frag.h" #include "drawItemStatus_vert.h" @@ -171,4 +170,4 @@ void DrawStatus::run(const SceneContextPointer& sceneContext, const RenderContex args->_context->syncCache(); renderContext->args->_context->syncCache(); args->_context->render((batch)); -} \ No newline at end of file +} diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 0e3eba0b53..d29420fdfd 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -14,12 +14,12 @@ #include #include -#include -#include -#include #include #include #include +#include +#include +#include using namespace render; diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index 3b7eb18368..ab01d333ac 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -8,30 +8,31 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include #include + #include -#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include class RateCounter { std::vector times; From 475d069185ffe68e2979a43856d082adb747b04c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 28 Jul 2015 18:12:10 -0700 Subject: [PATCH 39/74] fix rendering on linux --- libraries/gpu/src/gpu/Config.slh | 7 +++---- libraries/gpu/src/gpu/GPUConfig.h | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/libraries/gpu/src/gpu/Config.slh b/libraries/gpu/src/gpu/Config.slh index 76be161822..f24b54e5d5 100644 --- a/libraries/gpu/src/gpu/Config.slh +++ b/libraries/gpu/src/gpu/Config.slh @@ -21,10 +21,9 @@ <@def VERSION_HEADER #version 120 #extension GL_EXT_gpu_shader4 : enable@> <@else@> - <@def GPU_FEATURE_PROFILE GPU_LEGACY@> - <@def GPU_TRANSFORM_PROFILE GPU_LEGACY@> - <@def VERSION_HEADER #version 120 -#extension GL_EXT_gpu_shader4 : enable@> + <@def GPU_FEATURE_PROFILE GPU_CORE@> + <@def GPU_TRANSFORM_PROFILE GPU_CORE@> + <@def VERSION_HEADER #version 430 compatibility@> <@endif@> <@endif@> diff --git a/libraries/gpu/src/gpu/GPUConfig.h b/libraries/gpu/src/gpu/GPUConfig.h index 5046221ad3..d9b6d18894 100644 --- a/libraries/gpu/src/gpu/GPUConfig.h +++ b/libraries/gpu/src/gpu/GPUConfig.h @@ -40,8 +40,8 @@ //#include //#include -#define GPU_FEATURE_PROFILE GPU_LEGACY -#define GPU_TRANSFORM_PROFILE GPU_LEGACY +#define GPU_FEATURE_PROFILE GPU_CORE +#define GPU_TRANSFORM_PROFILE GPU_CORE #endif From 044ea2ace56303e1a5101dc282db4c1459f561ce Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 28 Jul 2015 19:31:43 -0700 Subject: [PATCH 40/74] Changed mirror position to not be achored to the head. But instead it's anchored to the "default" eye position, which is where the eyes are in the model, before IK or animations occur. --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3f185af5a1..967880ca8d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3381,7 +3381,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi // This was removed in commit 71e59cfa88c6563749594e25494102fe01db38e9 but could be further // investigated in order to adapt the technique while fixing the head rendering issue, // but the complexity of the hack suggests that a better approach - _mirrorCamera.setPosition(_myAvatar->getHead()->getEyePosition() + + _mirrorCamera.setPosition(_myAvatar->getDefaultEyePosition() + _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_REARVIEW_DISTANCE * _myAvatar->getScale()); } _mirrorCamera.setProjection(glm::perspective(glm::radians(fov), aspect, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP)); From 1d29fb9d7f9b2c482a352881cb6595904671e657 Mon Sep 17 00:00:00 2001 From: Marcel Verhagen Date: Wed, 29 Jul 2015 14:56:24 +0200 Subject: [PATCH 41/74] replace tabs with whitespaces. --- interface/src/devices/3Dconnexion.cpp | 38 +++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/interface/src/devices/3Dconnexion.cpp b/interface/src/devices/3Dconnexion.cpp index 111e2d5991..ef66e6660b 100755 --- a/interface/src/devices/3Dconnexion.cpp +++ b/interface/src/devices/3Dconnexion.cpp @@ -165,11 +165,11 @@ static ConnexionClient* gMouseInput = 0; void ConnexionClient::toggleConnexion(bool shouldEnable) { - ConnexionData& connexiondata = ConnexionData::getInstance(); - if (shouldEnable && connexiondata.getDeviceID() == 0) { + ConnexionData& connexiondata = ConnexionData::getInstance(); + if (shouldEnable && connexiondata.getDeviceID() == 0) { ConnexionClient::init(); } - if (!shouldEnable && connexiondata.getDeviceID() != 0) { + if (!shouldEnable && connexiondata.getDeviceID() != 0) { ConnexionClient::destroy(); } @@ -177,24 +177,24 @@ void ConnexionClient::toggleConnexion(bool shouldEnable) void ConnexionClient::init() { if (Menu::getInstance()->isOptionChecked(MenuOption::Connexion)) { - ConnexionClient& cclient = ConnexionClient::getInstance(); - cclient.fLast3dmouseInputTime = 0; + ConnexionClient& cclient = ConnexionClient::getInstance(); + cclient.fLast3dmouseInputTime = 0; - cclient.InitializeRawInput(GetActiveWindow()); + cclient.InitializeRawInput(GetActiveWindow()); - gMouseInput = &cclient; + gMouseInput = &cclient; - QAbstractEventDispatcher::instance()->installNativeEventFilter(&cclient); + QAbstractEventDispatcher::instance()->installNativeEventFilter(&cclient); } } void ConnexionClient::destroy() { - ConnexionClient& cclient = ConnexionClient::getInstance(); - QAbstractEventDispatcher::instance()->removeNativeEventFilter(&cclient); - ConnexionData& connexiondata = ConnexionData::getInstance(); - int deviceid = connexiondata.getDeviceID(); - connexiondata.setDeviceID(0); - Application::getUserInputMapper()->removeDevice(deviceid); + ConnexionClient& cclient = ConnexionClient::getInstance(); + QAbstractEventDispatcher::instance()->removeNativeEventFilter(&cclient); + ConnexionData& connexiondata = ConnexionData::getInstance(); + int deviceid = connexiondata.getDeviceID(); + connexiondata.setDeviceID(0); + Application::getUserInputMapper()->removeDevice(deviceid); } #define LOGITECH_VENDOR_ID 0x46d @@ -305,9 +305,9 @@ bool ConnexionClient::RawInputEventFilter(void* msg, long* result) { connexiondata.assignDefaultInputMapping(*Application::getUserInputMapper()); UserActivityLogger::getInstance().connectedDevice("controller", "3Dconnexion"); } else if (!ConnexionClient::Is3dmouseAttached() && connexiondata.getDeviceID() != 0) { - int deviceid = connexiondata.getDeviceID(); - connexiondata.setDeviceID(0); - Application::getUserInputMapper()->removeDevice(deviceid); + int deviceid = connexiondata.getDeviceID(); + connexiondata.setDeviceID(0); + Application::getUserInputMapper()->removeDevice(deviceid); } if (!ConnexionClient::Is3dmouseAttached()) { @@ -332,8 +332,8 @@ ConnexionClient::ConnexionClient() { } ConnexionClient::~ConnexionClient() { - ConnexionClient& cclient = ConnexionClient::getInstance(); - QAbstractEventDispatcher::instance()->removeNativeEventFilter(&cclient); + ConnexionClient& cclient = ConnexionClient::getInstance(); + QAbstractEventDispatcher::instance()->removeNativeEventFilter(&cclient); } // Access the mouse parameters structure From 327ecfe62ccba1d78f5bbdb933e2382dddddb786 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Wed, 29 Jul 2015 09:11:58 -0700 Subject: [PATCH 42/74] Be less noisy. --- interface/src/avatar/MyAvatar.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5f0b5f03da..054365b2b1 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -602,7 +602,6 @@ void MyAvatar::saveData() { for (int i = 0; i < animationHandles.size(); i++) { settings.setArrayIndex(i); const AnimationHandlePointer& pointer = animationHandles.at(i); - qCDebug(interfaceapp) << "Save animation" << pointer->getURL().toString(); settings.setValue("role", pointer->getRole()); settings.setValue("url", pointer->getURL()); settings.setValue("fps", pointer->getFPS()); From 7805cf4e481c07a78298c7774cb1792d55f06713 Mon Sep 17 00:00:00 2001 From: bwent Date: Wed, 29 Jul 2015 09:19:33 -0700 Subject: [PATCH 43/74] Format fixes, UI logos for collapse/expand toggle --- examples/utilities/tools/cookies.js | 35 ++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 24cda69ba2..751008fd99 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -12,7 +12,7 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; -var SCALE = 1000; +var SLIDER_RANGE_INCREMENT_SCALE = 1 / 1000; var THUMB_COLOR = { red: 150, green: 150, @@ -59,7 +59,6 @@ var CHECK_MARK_COLOR = { }); this.thumbSize = thumbSize; - this.thumbHalfSize = 0.5 * thumbSize; this.minThumbX = x + this.thumbHalfSize; @@ -128,7 +127,7 @@ var CHECK_MARK_COLOR = { Slider.prototype.updateWithKeys = function(direction) { this.range = this.maxThumbX - this.minThumbX; - this.thumbX += direction * (this.range / SCALE); + this.thumbX += direction * (this.range * SCALE); this.updateThumb(); this.onValueChanged(this.getValue()); }; @@ -211,6 +210,25 @@ var CHECK_MARK_COLOR = { }); }; + this.setThumbColor = function(color) { + Overlays.editOverlay(this.thumb, { + backgroundColor: { + red: color.x * 255, + green: color.y * 255, + blue: color.z * 255 + } + }); + }; + this.setBackgroundColor = function(color) { + Overlays.editOverlay(this.background, { + backgroundColor: { + red: color.x * 255, + green: color.y * 255, + blue: color.z * 255 + } + }); + }; + Slider.prototype.hide = function() { Overlays.editOverlay(this.background, { visible: false @@ -748,7 +766,7 @@ var CHECK_MARK_COLOR = { green: 255, blue: 255 }, - imageURL: HIFI_PUBLIC_BUCKET + 'images/tools/min-max-toggle.svg', + imageURL: HIFI_PUBLIC_BUCKET + 'images/tools/expand-ui.svg', x: x, y: y, width: rawHeight, @@ -778,6 +796,7 @@ var CHECK_MARK_COLOR = { }); }; + CollapsablePanelItem.prototype.destroy = function() { Overlays.deleteOverlay(this.title); Overlays.deleteOverlay(this.thumb); @@ -1044,6 +1063,7 @@ var CHECK_MARK_COLOR = { x: event.x, y: event.y }); + this.handleCollapse(clickedOverlay); // If the user clicked any of the slider background then... @@ -1106,10 +1126,15 @@ var CHECK_MARK_COLOR = { } if (!item.isCollapsed && item.isCollapsable && clickedOverlay == item.thumb) { + Overlays.editOverlay(item.thumb, { + imageURL: HIFI_PUBLIC_BUCKET + 'images/tools/expand-right.svg' + }); this.collapse(clickedOverlay); item.isCollapsed = true; - break; } else if (item.isCollapsed && item.isCollapsable && clickedOverlay == item.thumb) { + Overlays.editOverlay(item.thumb, { + imageURL: HIFI_PUBLIC_BUCKET + 'images/tools/expand-ui.svg' + }); this.expand(clickedOverlay); item.isCollapsed = false; } From 76acbde5955c1cd3f33d8e7228e19ae8899b6f34 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 29 Jul 2015 09:54:10 -0700 Subject: [PATCH 44/74] Removing the opengl and glew links from Interface since now coming from gpu lib --- interface/CMakeLists.txt | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 6af3cfa08b..4f99b6b34f 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -219,21 +219,22 @@ else (APPLE) $/resources ) - find_package(OpenGL REQUIRED) + # find_package(OpenGL REQUIRED) - if (${OPENGL_INCLUDE_DIR}) - include_directories(SYSTEM "${OPENGL_INCLUDE_DIR}") - endif () + # if (${OPENGL_INCLUDE_DIR}) + # include_directories(SYSTEM "${OPENGL_INCLUDE_DIR}") +# endif () - target_link_libraries(${TARGET_NAME} "${OPENGL_LIBRARY}") + # target_link_libraries(${TARGET_NAME} "${OPENGL_LIBRARY}") # link target to external libraries if (WIN32) - add_dependency_external_projects(glew) - find_package(GLEW REQUIRED) - target_include_directories(${TARGET_NAME} PRIVATE ${GLEW_INCLUDE_DIRS}) + # add_dependency_external_projects(glew) + # find_package(GLEW REQUIRED) + # target_include_directories(${TARGET_NAME} PRIVATE ${GLEW_INCLUDE_DIRS}) - target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARIES} wsock32.lib opengl32.lib Winmm.lib) + # target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARIES} wsock32.lib opengl32.lib Winmm.lib) + target_link_libraries(${TARGET_NAME} wsock32.lib Winmm.lib) if (USE_NSIGHT) # try to find the Nsight package and add it to the build if we find it From 7fdba9132e34ed987fd98faa40d8274f0235275e Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Wed, 29 Jul 2015 09:55:19 -0700 Subject: [PATCH 45/74] Revert Camera.h changes. --- interface/src/Camera.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Camera.h b/interface/src/Camera.h index bddb01ef21..6eed39cf16 100644 --- a/interface/src/Camera.h +++ b/interface/src/Camera.h @@ -28,7 +28,7 @@ enum CameraMode }; Q_DECLARE_METATYPE(CameraMode); -// static int cameraModeId = qRegisterMetaType(); +static int cameraModeId = qRegisterMetaType(); class Camera : public QObject { Q_OBJECT From 12d449f69d92a8eb85a5e9f4966fbd7b9acd23a1 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Wed, 29 Jul 2015 09:55:46 -0700 Subject: [PATCH 46/74] Update test case initialization post cauterization changes. --- tests/animation/src/RigTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/animation/src/RigTests.cpp b/tests/animation/src/RigTests.cpp index 0530ad5638..8dbba30031 100644 --- a/tests/animation/src/RigTests.cpp +++ b/tests/animation/src/RigTests.cpp @@ -73,7 +73,7 @@ void RigTests::initTestCase() { } _rig = std::make_shared(); - _rig->initJointStates(jointStates, glm::mat4(), geometry.neckJointIndex); + _rig->initJointStates(jointStates, glm::mat4()); std::cout << "Rig is ready " << geometry.joints.count() << " joints " << std::endl; } From d76cda396f84943b48da360b78438fd62916254a Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Wed, 29 Jul 2015 11:05:19 -0700 Subject: [PATCH 47/74] HBAO implementation ported from NVidia HLSL --- .../render-utils/src/ambient_occlusion.slf | 259 +++++++++++++++++- 1 file changed, 258 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/ambient_occlusion.slf b/libraries/render-utils/src/ambient_occlusion.slf index 3a49accf58..96aba989a8 100644 --- a/libraries/render-utils/src/ambient_occlusion.slf +++ b/libraries/render-utils/src/ambient_occlusion.slf @@ -17,7 +17,7 @@ <@include gpu/Transform.slh@> <$declareStandardTransform()$> - +/* varying vec2 varTexcoord; uniform sampler2D depthTexture; @@ -105,5 +105,262 @@ void main(void) { occlusion = 1.0 - occlusion / float(SAMPLE_COUNT); occlusion = clamp(pow(occlusion, g_intensity), 0.0, 1.0); gl_FragColor = vec4(vec3(occlusion), 1.0); +}*/ + +// This is a HBAO-Shader for OpenGL, based upon nvidias directX implementation +// supplied in their SampleSDK available from nvidia.com +// The slides describing the implementation is available at +// http://www.nvidia.co.uk/object/siggraph-2008-HBAO.html + +varying vec2 varTexcoord; + +uniform sampler2D depthTexture; +uniform sampler2D normalTexture; + +uniform float g_scale; +uniform float g_bias; +uniform float g_sample_rad; +uniform float g_intensity; +uniform float bufferWidth; +uniform float bufferHeight; + +const float PI = 3.14159265; + +const vec2 FocalLen = vec2(1.0, 1.0); +//const vec2 UVToViewA = vec2(1.0, 1.0); +//const vec2 UVToViewB = vec2(1.0, 1.0); + +const vec2 LinMAD = vec2(0.1-10.0, 0.1+10.0) / (2.0*0.1*10.0); + +const vec2 AORes = vec2(1024.0, 768.0); +const vec2 InvAORes = vec2(1.0/1024.0, 1.0/768.0); +const vec2 NoiseScale = vec2(1024.0, 768.0) / 4.0; + +const float AOStrength = 1.9; +const float R = 0.3; +const float R2 = 0.3*0.3; +const float NegInvR2 = - 1.0 / (0.3*0.3); +const float TanBias = tan(30.0 * PI / 180.0); +const float MaxRadiusPixels = 100.0; + +const int NumDirections = 6; +const int NumSamples = 4; + +float ViewSpaceZFromDepth(float d) +{ + // [0,1] -> [-1,1] clip space + d = d * 2.0 - 1.0; + + // Get view space Z + return -1.0 / (LinMAD.x * d + LinMAD.y); } +vec3 UVToViewSpace(vec2 uv, float z) +{ + //uv = UVToViewA * uv + UVToViewB; + return vec3(uv * z, z); +} + +vec3 GetViewPos(vec2 uv) +{ + float z = ViewSpaceZFromDepth(texture2D(depthTexture, uv).r); + return UVToViewSpace(uv, z); +} + +vec3 GetViewPosPoint(ivec2 uv) +{ + vec2 coord = vec2(gl_FragCoord.xy) + uv; + //float z = texelFetch(texture0, coord, 0).r; + float z = texture2D(depthTexture, uv).r; + return UVToViewSpace(uv, z); +} + +float TanToSin(float x) +{ + return x * inversesqrt(x*x + 1.0); +} + +float InvLength(vec2 V) +{ + return inversesqrt(dot(V,V)); +} + +float Tangent(vec3 V) +{ + return V.z * InvLength(V.xy); +} + +float BiasedTangent(vec3 V) +{ + return V.z * InvLength(V.xy) + TanBias; +} + +float Tangent(vec3 P, vec3 S) +{ + return -(P.z - S.z) * InvLength(S.xy - P.xy); +} + +float Length2(vec3 V) +{ + return dot(V,V); +} + +vec3 MinDiff(vec3 P, vec3 Pr, vec3 Pl) +{ + vec3 V1 = Pr - P; + vec3 V2 = P - Pl; + return (Length2(V1) < Length2(V2)) ? V1 : V2; +} + +vec2 SnapUVOffset(vec2 uv) +{ + return round(uv * AORes) * InvAORes; +} + +float Falloff(float d2) +{ + return d2 * NegInvR2 + 1.0f; +} + +float HorizonOcclusion( vec2 deltaUV, + vec3 P, + vec3 dPdu, + vec3 dPdv, + float randstep, + float numSamples) +{ + float ao = 0; + + // Offset the first coord with some noise + vec2 uv = varTexcoord + SnapUVOffset(randstep*deltaUV); + deltaUV = SnapUVOffset( deltaUV ); + + // Calculate the tangent vector + vec3 T = deltaUV.x * dPdu + deltaUV.y * dPdv; + + // Get the angle of the tangent vector from the viewspace axis + float tanH = BiasedTangent(T); + float sinH = TanToSin(tanH); + + float tanS; + float d2; + vec3 S; + + // Sample to find the maximum angle + for(float s = 1; s <= numSamples; ++s) + { + uv += deltaUV; + S = GetViewPos(uv); + tanS = Tangent(P, S); + d2 = Length2(S - P); + + // Is the sample within the radius and the angle greater? + if(d2 < R2 && tanS > tanH) + { + float sinS = TanToSin(tanS); + // Apply falloff based on the distance + ao += Falloff(d2) * (sinS - sinH); + + tanH = tanS; + sinH = sinS; + } + } + + return ao; +} + +vec2 RotateDirections(vec2 Dir, vec2 CosSin) +{ + return vec2(Dir.x*CosSin.x - Dir.y*CosSin.y, + Dir.x*CosSin.y + Dir.y*CosSin.x); +} + +void ComputeSteps(inout vec2 stepSizeUv, inout float numSteps, float rayRadiusPix, float rand) +{ + // Avoid oversampling if numSteps is greater than the kernel radius in pixels + numSteps = min(NumSamples, rayRadiusPix); + + // Divide by Ns+1 so that the farthest samples are not fully attenuated + float stepSizePix = rayRadiusPix / (numSteps + 1); + + // Clamp numSteps if it is greater than the max kernel footprint + float maxNumSteps = MaxRadiusPixels / stepSizePix; + if (maxNumSteps < numSteps) + { + // Use dithering to avoid AO discontinuities + numSteps = floor(maxNumSteps + rand); + numSteps = max(numSteps, 1); + stepSizePix = MaxRadiusPixels / numSteps; + } + + // Step size in uv space + stepSizeUv = stepSizePix * InvAORes; +} + +float getRandom(vec2 uv) { + return fract(sin(dot(uv.xy ,vec2(12.9898,78.233))) * 43758.5453); +} + +void main(void) +{ + float numDirections = NumDirections; + + vec3 P, Pr, Pl, Pt, Pb; + P = GetViewPos(varTexcoord); + + // Sample neighboring pixels + Pr = GetViewPos(varTexcoord + vec2( InvAORes.x, 0)); + Pl = GetViewPos(varTexcoord + vec2(-InvAORes.x, 0)); + Pt = GetViewPos(varTexcoord + vec2( 0, InvAORes.y)); + Pb = GetViewPos(varTexcoord + vec2( 0,-InvAORes.y)); + + // Calculate tangent basis vectors using the minimu difference + vec3 dPdu = MinDiff(P, Pr, Pl); + vec3 dPdv = MinDiff(P, Pt, Pb) * (AORes.y * InvAORes.x); + + // Get the random samples from the noise texture + vec3 random = vec3(getRandom(varTexcoord.xy), getRandom(varTexcoord.yx), getRandom(varTexcoord.xx)); + + // Calculate the projected size of the hemisphere + vec2 rayRadiusUV = 0.5 * R * FocalLen / -P.z; + float rayRadiusPix = rayRadiusUV.x * AORes.x; + + float ao = 1.0; + + // Make sure the radius of the evaluated hemisphere is more than a pixel + if(rayRadiusPix > 1.0) + { + ao = 0.0; + float numSteps; + vec2 stepSizeUV; + + // Compute the number of steps + ComputeSteps(stepSizeUV, numSteps, rayRadiusPix, random.z); + + float alpha = 2.0 * PI / numDirections; + + // Calculate the horizon occlusion of each direction + for(float d = 0; d < numDirections; ++d) + { + float theta = alpha * d; + + // Apply noise to the direction + vec2 dir = RotateDirections(vec2(cos(theta), sin(theta)), random.xy); + vec2 deltaUV = dir * stepSizeUV; + + // Sample the pixels along the direction + ao += HorizonOcclusion( deltaUV, + P, + dPdu, + dPdv, + random.z, + numSteps); + } + + // Average the results and produce the final AO + ao = 1.0 - ao / numDirections * AOStrength; + } + + //out_frag0 = vec2(ao, 30.0 * P.z); + gl_FragColor = vec4(vec3(ao), 1.0); +} \ No newline at end of file From 65e04337bf7abb58ad15e0f3159d236173a13812 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 29 Jul 2015 11:15:20 -0700 Subject: [PATCH 48/74] removed synccache line --- libraries/render-utils/src/HitEffect.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/render-utils/src/HitEffect.cpp b/libraries/render-utils/src/HitEffect.cpp index 170a6eaf0b..f65bc7666f 100644 --- a/libraries/render-utils/src/HitEffect.cpp +++ b/libraries/render-utils/src/HitEffect.cpp @@ -80,7 +80,6 @@ void HitEffect::run(const render::SceneContextPointer& sceneContext, const rende // Ready to render - // renderContext->args->_context->syncCache(); args->_context->render((batch)); } From 17650dde74598fb1cdff9df8979d7f8db096546c Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 29 Jul 2015 11:49:22 -0700 Subject: [PATCH 49/74] Solving the coimpiling issue with Render-utils test --- tests/render-utils/src/main.cpp | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index ab01d333ac..7c02c7e8a7 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -19,6 +19,10 @@ #include #include #include + +#include +#include + #include #include #include @@ -29,7 +33,7 @@ #include #include #include -#include + #include @@ -90,6 +94,7 @@ class QTestWindow : public QWindow { QSize _size; //TextRenderer* _textRenderer[4]; RateCounter fps; + gpu::ContextPointer _gpuContext; protected: void renderText(); @@ -119,6 +124,9 @@ public: show(); makeCurrent(); + _gpuContext.reset(new gpu::Context(new gpu::GLBackend())); + + { QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(this); @@ -131,23 +139,6 @@ public: } qDebug() << (const char*)glGetString(GL_VERSION); -#ifdef WIN32 - glewExperimental = true; - GLenum err = glewInit(); - if (GLEW_OK != err) { - /* Problem: glewInit failed, something is seriously wrong. */ - const GLubyte * errStr = glewGetErrorString(err); - qDebug("Error: %s\n", errStr); - } - qDebug("Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); - - if (wglewGetExtension("WGL_EXT_swap_control")) { - int swapInterval = wglGetSwapIntervalEXT(); - qDebug("V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF")); - } - glGetError(); -#endif - //_textRenderer[0] = TextRenderer::getInstance(SANS_FONT_FAMILY, 12, false); //_textRenderer[1] = TextRenderer::getInstance(SERIF_FONT_FAMILY, 12, false, // TextRenderer::SHADOW_EFFECT); From 661f29924fd79f6be76468ff5f6376b8153db557 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 29 Jul 2015 13:55:26 -0700 Subject: [PATCH 50/74] Clean up the cmakelist to normally onlly do th eminimal linking and include for gl --- interface/CMakeLists.txt | 29 ++++------------------------- libraries/gpu/CMakeLists.txt | 2 +- 2 files changed, 5 insertions(+), 26 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 4f99b6b34f..b6c8e3f3f4 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -218,40 +218,19 @@ else (APPLE) "${PROJECT_SOURCE_DIR}/resources" $/resources ) - - # find_package(OpenGL REQUIRED) - - # if (${OPENGL_INCLUDE_DIR}) - # include_directories(SYSTEM "${OPENGL_INCLUDE_DIR}") -# endif () - - # target_link_libraries(${TARGET_NAME} "${OPENGL_LIBRARY}") - + # link target to external libraries if (WIN32) - # add_dependency_external_projects(glew) - # find_package(GLEW REQUIRED) - # target_include_directories(${TARGET_NAME} PRIVATE ${GLEW_INCLUDE_DIRS}) - - # target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARIES} wsock32.lib opengl32.lib Winmm.lib) target_link_libraries(${TARGET_NAME} wsock32.lib Winmm.lib) - + if (USE_NSIGHT) - # try to find the Nsight package and add it to the build if we find it - find_package(NSIGHT) + # If required NSIGHT lib comes from gpu lib but still to add a precroc define if (NSIGHT_FOUND) - include_directories(${NSIGHT_INCLUDE_DIRS}) add_definitions(-DNSIGHT_FOUND) - target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}") endif () endif() - else (WIN32) - find_package(GLEW REQUIRED) - target_include_directories(${TARGET_NAME} PRIVATE ${GLEW_INCLUDE_DIRS}) - - target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARIES}) - message(STATUS ${GLEW_LIBRARY}) + # Nothing else required on linux apparently endif() endif (APPLE) diff --git a/libraries/gpu/CMakeLists.txt b/libraries/gpu/CMakeLists.txt index eda168091e..1e8faf1bca 100644 --- a/libraries/gpu/CMakeLists.txt +++ b/libraries/gpu/CMakeLists.txt @@ -23,7 +23,7 @@ elseif (WIN32) # try to find the Nsight package and add it to the build if we find it find_package(NSIGHT) if (NSIGHT_FOUND) - include_directories(${NSIGHT_INCLUDE_DIRS}) + target_include_directories(${TARGET_NAME} PUBLIC ${NSIGHT_INCLUDE_DIRS}) add_definitions(-DNSIGHT_FOUND) target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}") endif () From 9601e09ba9301005057a608893e82e23f7734427 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 29 Jul 2015 14:42:24 -0700 Subject: [PATCH 51/74] A simpler way to add the NSIGHT_FOUND define to all the projects depending on GPU --- interface/CMakeLists.txt | 8 +------- libraries/gpu/CMakeLists.txt | 8 ++++---- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index d47395a810..f1ef38ade9 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -221,14 +221,8 @@ else (APPLE) # link target to external libraries if (WIN32) + # target_link_libraries(${TARGET_NAME} wsock32.lib Winmm.lib) target_link_libraries(${TARGET_NAME} wsock32.lib Winmm.lib) - - if (USE_NSIGHT) - # If required NSIGHT lib comes from gpu lib but still to add a precroc define - if (NSIGHT_FOUND) - add_definitions(-DNSIGHT_FOUND) - endif () - endif() else (WIN32) # Nothing else required on linux apparently endif() diff --git a/libraries/gpu/CMakeLists.txt b/libraries/gpu/CMakeLists.txt index 1e8faf1bca..89939535b0 100644 --- a/libraries/gpu/CMakeLists.txt +++ b/libraries/gpu/CMakeLists.txt @@ -21,10 +21,11 @@ elseif (WIN32) if (USE_NSIGHT) # try to find the Nsight package and add it to the build if we find it + # note that this will also enable NSIGHT profilers in all the projects linking gpu find_package(NSIGHT) if (NSIGHT_FOUND) target_include_directories(${TARGET_NAME} PUBLIC ${NSIGHT_INCLUDE_DIRS}) - add_definitions(-DNSIGHT_FOUND) + target_compile_definitions(${TARGET_NAME} PUBLIC NSIGHT_FOUND) target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}") endif () endif() @@ -39,8 +40,7 @@ else () if (${OPENGL_INCLUDE_DIR}) include_directories(SYSTEM "${OPENGL_INCLUDE_DIR}") endif () - + target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" "${OPENGL_LIBRARY}") - - # target_include_directories(${TARGET_NAME} PUBLIC ${OPENGL_INCLUDE_DIR}) + endif (APPLE) From 3c934af297617fcceb90b5b70366c673be5dc768 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 29 Jul 2015 14:45:48 -0700 Subject: [PATCH 52/74] clean the gpuCOnfig.h for linux --- libraries/gpu/src/gpu/GPUConfig.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/gpu/src/gpu/GPUConfig.h b/libraries/gpu/src/gpu/GPUConfig.h index d9b6d18894..5590c4cc8d 100644 --- a/libraries/gpu/src/gpu/GPUConfig.h +++ b/libraries/gpu/src/gpu/GPUConfig.h @@ -36,9 +36,6 @@ #else #include -//#include -//#include -//#include #define GPU_FEATURE_PROFILE GPU_CORE #define GPU_TRANSFORM_PROFILE GPU_CORE From 838711e5261e1eccf73936f5c80242dff35e73e3 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Wed, 29 Jul 2015 15:27:50 -0700 Subject: [PATCH 53/74] Remove avatar->shift hips for idle animations. See https://app.asana.com/0/32622044445063/43127903156601 --- interface/src/Menu.cpp | 2 - interface/src/Menu.h | 1 - interface/src/avatar/MyAvatar.cpp | 11 +---- interface/src/avatar/MyAvatar.h | 1 - interface/src/avatar/SkeletonModel.cpp | 68 -------------------------- interface/src/avatar/SkeletonModel.h | 7 --- tests/ui/src/main.cpp | 1 - 7 files changed, 1 insertion(+), 90 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d6f64d360a..1cbe127857 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -249,8 +249,6 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::BlueSpeechSphere, 0, true); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::EnableCharacterController, 0, true, avatar, SLOT(updateMotionBehavior())); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ShiftHipsForIdleAnimations, 0, false, - avatar, SLOT(updateMotionBehavior())); MenuWrapper* viewMenu = addMenu("View"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 7a9fec4e78..62a1ae3b0f 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -273,7 +273,6 @@ namespace MenuOption { const QString SimpleShadows = "Simple"; const QString SixenseEnabled = "Enable Hydra Support"; const QString SixenseMouseInput = "Enable Sixense Mouse Input"; - const QString ShiftHipsForIdleAnimations = "Shift hips for idle animations"; const QString Stars = "Stars"; const QString Stats = "Stats"; const QString StopAllScripts = "Stop All Scripts"; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index f332173568..3ec6a2b1d6 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -98,7 +98,6 @@ MyAvatar::MyAvatar() : _lookAtTargetAvatar(), _shouldRender(true), _billboardValid(false), - _feetTouchFloor(true), _eyeContactTarget(LEFT_EYE), _realWorldFieldOfView("realWorldFieldOfView", DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES), @@ -166,9 +165,6 @@ void MyAvatar::update(float deltaTime) { head->setAudioAverageLoudness(audio->getAudioAverageInputLoudness()); simulate(deltaTime); - if (_feetTouchFloor) { - _skeletonModel.updateStandingFoot(); - } } void MyAvatar::simulate(float deltaTime) { @@ -1140,11 +1136,7 @@ glm::vec3 MyAvatar::getSkeletonPosition() const { // The avatar is rotated PI about the yAxis, so we have to correct for it // to get the skeleton offset contribution in the world-frame. const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - glm::vec3 skeletonOffset = _skeletonOffset; - if (_feetTouchFloor) { - skeletonOffset += _skeletonModel.getStandingOffset(); - } - return _position + getOrientation() * FLIP * skeletonOffset; + return _position + getOrientation() * FLIP * _skeletonOffset; } return Avatar::getPosition(); } @@ -1622,7 +1614,6 @@ void MyAvatar::updateMotionBehavior() { _motionBehaviors &= ~AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED; } _characterController.setEnabled(menu->isOptionChecked(MenuOption::EnableCharacterController)); - _feetTouchFloor = menu->isOptionChecked(MenuOption::ShiftHipsForIdleAnimations); } //Renders sixense laser pointers for UI selection with controllers diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index b18b8df121..90d9b47e1c 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -258,7 +258,6 @@ private: QList _animationHandles; - bool _feetTouchFloor; eyeContactTarget _eyeContactTarget; RecorderPointer _recorder; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index fa7c5f08bb..5deebca638 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -24,12 +24,6 @@ #include "Util.h" #include "InterfaceLogging.h" -enum StandingFootState { - LEFT_FOOT, - RIGHT_FOOT, - NO_FOOT -}; - SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : Model(parent), _triangleFanID(DependencyManager::get()->allocateID()), @@ -37,9 +31,6 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : _boundingShape(), _boundingShapeLocalOffset(0.0f), _defaultEyeModelPosition(glm::vec3(0.0f, 0.0f, 0.0f)), - _standingFoot(NO_FOOT), - _standingOffset(0.0f), - _clampedFootPosition(0.0f), _headClipDistance(DEFAULT_NEAR_CLIP), _isFirstPerson(false) { @@ -573,65 +564,6 @@ glm::vec3 SkeletonModel::getDefaultEyeModelPosition() const { return _owningAvatar->getScale() * _defaultEyeModelPosition; } -/// \return offset of hips after foot animation -void SkeletonModel::updateStandingFoot() { - if (_geometry == NULL) { - return; - } - glm::vec3 offset(0.0f); - int leftFootIndex = _geometry->getFBXGeometry().leftToeJointIndex; - int rightFootIndex = _geometry->getFBXGeometry().rightToeJointIndex; - - if (leftFootIndex != -1 && rightFootIndex != -1) { - glm::vec3 leftPosition, rightPosition; - getJointPosition(leftFootIndex, leftPosition); - getJointPosition(rightFootIndex, rightPosition); - - int lowestFoot = (leftPosition.y < rightPosition.y) ? LEFT_FOOT : RIGHT_FOOT; - const float MIN_STEP_HEIGHT_THRESHOLD = 0.05f; - bool oneFoot = fabsf(leftPosition.y - rightPosition.y) > MIN_STEP_HEIGHT_THRESHOLD; - int currentFoot = oneFoot ? lowestFoot : _standingFoot; - - if (_standingFoot == NO_FOOT) { - currentFoot = lowestFoot; - } - if (currentFoot != _standingFoot) { - if (_standingFoot == NO_FOOT) { - // pick the lowest foot - glm::vec3 lowestPosition = (currentFoot == LEFT_FOOT) ? leftPosition : rightPosition; - // we ignore zero length positions which can happen for a few frames until skeleton is fully loaded - if (glm::length(lowestPosition) > 0.0f) { - _standingFoot = currentFoot; - _clampedFootPosition = lowestPosition; - } - } else { - // swap feet - _standingFoot = currentFoot; - glm::vec3 nextPosition = leftPosition; - glm::vec3 prevPosition = rightPosition; - if (_standingFoot == RIGHT_FOOT) { - nextPosition = rightPosition; - prevPosition = leftPosition; - } - glm::vec3 oldOffset = _clampedFootPosition - prevPosition; - _clampedFootPosition = oldOffset + nextPosition; - offset = _clampedFootPosition - nextPosition; - } - } else { - glm::vec3 nextPosition = (_standingFoot == LEFT_FOOT) ? leftPosition : rightPosition; - offset = _clampedFootPosition - nextPosition; - } - - // clamp the offset to not exceed some max distance - const float MAX_STEP_OFFSET = 1.0f; - float stepDistance = glm::length(offset); - if (stepDistance > MAX_STEP_OFFSET) { - offset *= (MAX_STEP_OFFSET / stepDistance); - } - } - _standingOffset = offset; -} - float DENSITY_OF_WATER = 1000.0f; // kg/m^3 float MIN_JOINT_MASS = 1.0f; float VERY_BIG_MASS = 1.0e6f; diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 1044a16696..6f4dd096ad 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -96,10 +96,6 @@ public: /// \return whether or not the head was found. glm::vec3 getDefaultEyeModelPosition() const; - /// skeleton offset caused by moving feet - void updateStandingFoot(); - const glm::vec3& getStandingOffset() const { return _standingOffset; } - void computeBoundingShape(const FBXGeometry& geometry); void renderBoundingCollisionShapes(gpu::Batch& batch, float alpha); float getBoundingShapeRadius() const { return _boundingShape.getRadius(); } @@ -169,9 +165,6 @@ private: glm::vec3 _boundingShapeLocalOffset; glm::vec3 _defaultEyeModelPosition; - int _standingFoot; - glm::vec3 _standingOffset; - glm::vec3 _clampedFootPosition; float _headClipDistance; // Near clip distance to use if no separate head model diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index 614c733322..e8ab7e02df 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -215,7 +215,6 @@ public: SixenseEnabled, SixenseMouseInput, SixenseLasers, - ShiftHipsForIdleAnimations, Stars, Stats, StereoAudio, From 269db0ff6fc71aeca8179e173ad3e9e042f1da6c Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 29 Jul 2015 16:08:16 -0700 Subject: [PATCH 54/74] fixing the stars rendering that was vilently broken durign the hunt for GPUCOnfig.h includes --- interface/src/Stars.cpp | 6 +----- libraries/gpu/src/gpu/GLBackendState.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/interface/src/Stars.cpp b/interface/src/Stars.cpp index 7b612acb68..68e0001996 100644 --- a/interface/src/Stars.cpp +++ b/interface/src/Stars.cpp @@ -141,6 +141,7 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { auto state = gpu::StatePointer(new gpu::State()); // enable decal blend state->setDepthTest(gpu::State::DepthTest(false)); + state->setAntialiasedLineEnable(true); // line smoothing also smooth points state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); _gridPipeline.reset(gpu::Pipeline::create(program, state)); } @@ -205,8 +206,6 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { batch._glUniform1f(_timeSlot, secs); geometryCache->renderUnitCube(batch); - //glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); - static const size_t VERTEX_STRIDE = sizeof(StarVertex); size_t offset = offsetof(StarVertex, position); gpu::BufferView posView(vertexBuffer, offset, vertexBuffer->getSize(), VERTEX_STRIDE, positionElement); @@ -215,9 +214,6 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { // Render the stars batch.setPipeline(_starsPipeline); - //batch._glEnable(GL_PROGRAM_POINT_SIZE_EXT); - //batch._glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); - //batch._glEnable(GL_POINT_SMOOTH); batch.setInputFormat(streamFormat); batch.setInputBuffer(VERTICES_SLOT, posView); diff --git a/libraries/gpu/src/gpu/GLBackendState.cpp b/libraries/gpu/src/gpu/GLBackendState.cpp index 18fc9ddd3c..e9dcd3aad3 100644 --- a/libraries/gpu/src/gpu/GLBackendState.cpp +++ b/libraries/gpu/src/gpu/GLBackendState.cpp @@ -482,6 +482,12 @@ void GLBackend::syncPipelineStateCache() { State::Data state; glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + + // Point size is always on + glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); + glEnable(GL_PROGRAM_POINT_SIZE_EXT); + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + getCurrentGLState(state); State::Signature signature = State::evalSignature(state); From 5baf993c24a70b26de159259a5a6fbb5d6ffbc0f Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 29 Jul 2015 16:27:45 -0700 Subject: [PATCH 55/74] fixing the stars again --- interface/src/Stars.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Stars.cpp b/interface/src/Stars.cpp index 68e0001996..42b1a3f2e2 100644 --- a/interface/src/Stars.cpp +++ b/interface/src/Stars.cpp @@ -141,7 +141,6 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { auto state = gpu::StatePointer(new gpu::State()); // enable decal blend state->setDepthTest(gpu::State::DepthTest(false)); - state->setAntialiasedLineEnable(true); // line smoothing also smooth points state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); _gridPipeline.reset(gpu::Pipeline::create(program, state)); } @@ -153,6 +152,7 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { auto state = gpu::StatePointer(new gpu::State()); // enable decal blend state->setDepthTest(gpu::State::DepthTest(false)); + state->setAntialiasedLineEnable(true); // line smoothing also smooth points state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); _starsPipeline.reset(gpu::Pipeline::create(program, state)); @@ -219,6 +219,6 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { batch.setInputBuffer(VERTICES_SLOT, posView); batch.setInputBuffer(COLOR_SLOT, colView); batch.draw(gpu::Primitive::POINTS, STARFIELD_NUM_STARS); - + renderArgs->_context->render(batch); } From 4972cb024f34eb5fe2f4cfa34080be52ae06f3b2 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 29 Jul 2015 16:48:23 -0700 Subject: [PATCH 56/74] Try to make the inlucde sequence simpler in gpu for GLBackend --- libraries/gpu/src/gpu/Batch.cpp | 18 ------------------ libraries/gpu/src/gpu/GLBackend.cpp | 1 - libraries/gpu/src/gpu/GLBackend.h | 2 -- libraries/gpu/src/gpu/GLBackendShared.h | 2 -- 4 files changed, 23 deletions(-) diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index b7f3ef444c..a10f5b3de7 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -10,12 +10,6 @@ // #include "Batch.h" -#include -#include - -#include "GPUConfig.h" - - #if defined(NSIGHT_FOUND) #include "nvToolsExt.h" @@ -288,15 +282,3 @@ void Batch::getQuery(const QueryPointer& query) { _params.push_back(_queries.cache(query)); } -void push_back(Batch::Params& params, const vec3& v) { - params.push_back(v.x); - params.push_back(v.y); - params.push_back(v.z); -} - -void push_back(Batch::Params& params, const vec4& v) { - params.push_back(v.x); - params.push_back(v.y); - params.push_back(v.z); - params.push_back(v.a); -} diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index 4bc8abadd0..51a767882c 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -11,7 +11,6 @@ #include "GLBackendShared.h" #include -#include "GPULogging.h" #include using namespace gpu; diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 9d8c9ef805..3b1d4cde5e 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -18,8 +18,6 @@ #include "GPUConfig.h" #include "Context.h" -#include "Batch.h" - namespace gpu { diff --git a/libraries/gpu/src/gpu/GLBackendShared.h b/libraries/gpu/src/gpu/GLBackendShared.h index 75bef461f9..888fd1164d 100644 --- a/libraries/gpu/src/gpu/GLBackendShared.h +++ b/libraries/gpu/src/gpu/GLBackendShared.h @@ -16,8 +16,6 @@ #include "GPULogging.h" #include "GLBackend.h" -#include "Batch.h" - static const GLenum _primitiveToGLmode[gpu::NUM_PRIMITIVES] = { GL_POINTS, GL_LINES, From 8b7ad9cfcbaa68ab360c0a7561e5af5da8ee3c6e Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 29 Jul 2015 17:13:48 -0700 Subject: [PATCH 57/74] merge with upstream --- interface/src/Application.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5845267f72..1dc2878008 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1019,7 +1019,9 @@ void Application::paintGL() { // Back to the default framebuffer; gpu::Batch batch; batch.resetStages(); - // renderArgs._context->render(batch); + // TODO: Testing the water here, it is maybe not needed at all, + // i would like to keep it like that until we merge with DisplayPlugin + // renderArgs._context->render(batch); } void Application::runTests() { From c2934bdb5d3fc8e1b1fac2d60c0eec1430ae8d06 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 29 Jul 2015 17:35:29 -0700 Subject: [PATCH 58/74] Fix avatar head, eye and torso twist. * Updated SkeletionModel::updateRig to explicitly pass a set of HeadParameters to the rig to do procedural animation. * Moved torso lean procedural animation from SkeletonModel into Rig. * Moved eye tracking procedural animation from HeadModel into Rig. * Moved neck procedural animation from HeadModel into Rig. --- interface/src/avatar/FaceModel.cpp | 54 --------------------- interface/src/avatar/FaceModel.h | 10 ++-- interface/src/avatar/SkeletonModel.cpp | 57 +++++++--------------- libraries/animation/src/AvatarRig.cpp | 18 ------- libraries/animation/src/AvatarRig.h | 1 - libraries/animation/src/EntityRig.h | 1 - libraries/animation/src/Rig.cpp | 65 ++++++++++++++++++++++++++ libraries/animation/src/Rig.h | 25 ++++++++-- 8 files changed, 108 insertions(+), 123 deletions(-) diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index e35c70a8ab..d5d4da8665 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -50,60 +50,6 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) { } } -void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, int index) { - // get the rotation axes in joint space and use them to adjust the rotation - glm::mat3 axes = glm::mat3_cast(glm::quat()); - glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() * - glm::translate(_rig->getJointDefaultTranslationInConstrainedFrame(index)) * - joint.preTransform * glm::mat4_cast(joint.preRotation))); - glm::vec3 pitchYawRoll = safeEulerAngles(_owningHead->getFinalOrientationInLocalFrame()); - glm::vec3 lean = glm::radians(glm::vec3(_owningHead->getFinalLeanForward(), - _owningHead->getTorsoTwist(), - _owningHead->getFinalLeanSideways())); - pitchYawRoll -= lean; - _rig->setJointRotationInConstrainedFrame(index, - glm::angleAxis(-pitchYawRoll.z, glm::normalize(inverse * axes[2])) - * glm::angleAxis(pitchYawRoll.y, glm::normalize(inverse * axes[1])) - * glm::angleAxis(-pitchYawRoll.x, glm::normalize(inverse * axes[0])) - * joint.rotation, DEFAULT_PRIORITY); -} - -void FaceModel::maybeUpdateEyeRotation(Model* model, const JointState& parentState, const FBXJoint& joint, int index) { - // likewise with the eye joints - // NOTE: at the moment we do the math in the world-frame, hence the inverse transform is more complex than usual. - glm::mat4 inverse = glm::inverse(glm::mat4_cast(model->getRotation()) * parentState.getTransform() * - glm::translate(_rig->getJointDefaultTranslationInConstrainedFrame(index)) * - joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation)); - glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getFinalOrientationInWorldFrame() * IDENTITY_FRONT, 0.0f)); - glm::vec3 lookAtDelta = _owningHead->getCorrectedLookAtPosition() - model->getTranslation(); - glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(lookAtDelta + glm::length(lookAtDelta) * _owningHead->getSaccade(), 1.0f)); - glm::quat between = rotationBetween(front, lookAt); - const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE; - _rig->setJointRotationInConstrainedFrame(index, glm::angleAxis(glm::clamp(glm::angle(between), - -MAX_ANGLE, MAX_ANGLE), glm::axis(between)) * - joint.rotation, DEFAULT_PRIORITY); -} - -void FaceModel::updateJointState(int index) { - const JointState& state = _rig->getJointState(index); - const FBXJoint& joint = state.getFBXJoint(); - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - - // guard against out-of-bounds access to _jointStates - if (joint.parentIndex != -1 && joint.parentIndex >= 0 && joint.parentIndex < _rig->getJointStateCount()) { - const JointState& parentState = _rig->getJointState(joint.parentIndex); - if (index == geometry.neckJointIndex) { - maybeUpdateNeckRotation(parentState, joint, index); - - } else if (index == geometry.leftEyeJointIndex || index == geometry.rightEyeJointIndex) { - maybeUpdateEyeRotation(this, parentState, joint, index); - } - } - - glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; - _rig->updateFaceJointState(index, parentTransform); -} - bool FaceModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { if (!isActive()) { return false; diff --git a/interface/src/avatar/FaceModel.h b/interface/src/avatar/FaceModel.h index ce78c51e70..5a19a8ea29 100644 --- a/interface/src/avatar/FaceModel.h +++ b/interface/src/avatar/FaceModel.h @@ -19,23 +19,19 @@ class Head; /// A face formed from a linear mix of blendshapes according to a set of coefficients. class FaceModel : public Model { Q_OBJECT - + public: FaceModel(Head* owningHead, RigPointer rig); virtual void simulate(float deltaTime, bool fullUpdate = true); - - virtual void maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, int index); - virtual void maybeUpdateEyeRotation(Model* model, const JointState& parentState, const FBXJoint& joint, int index); - virtual void updateJointState(int index); /// Retrieve the positions of up to two eye meshes. /// \return whether or not both eye meshes were found bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; - + private: - + Head* _owningHead; }; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 122559bedb..a766a80bab 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -118,6 +118,24 @@ void SkeletonModel::updateClusterMatrices() { void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { _rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation()); Model::updateRig(deltaTime, parentTransform); + if (_owningAvatar->isMyAvatar()) { + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + + Rig::HeadParameters params; + params.leanSideways = _owningAvatar->getHead()->getFinalLeanSideways(); + params.leanForward = _owningAvatar->getHead()->getFinalLeanSideways(); + params.torsoTwist = _owningAvatar->getHead()->getTorsoTwist(); + params.localHeadOrientation = _owningAvatar->getHead()->getFinalOrientationInLocalFrame(); + params.worldHeadOrientation = _owningAvatar->getHead()->getFinalOrientationInWorldFrame(); + params.eyeLookAt = _owningAvatar->getHead()->getCorrectedLookAtPosition(); + params.eyeSaccade = _owningAvatar->getHead()->getSaccade(); + params.leanJointIndex = geometry.leanJointIndex; + params.neckJointIndex = geometry.neckJointIndex; + params.leftEyeJointIndex = geometry.leftEyeJointIndex; + params.rightEyeJointIndex = geometry.rightEyeJointIndex; + + _rig->updateFromHeadParameters(params); + } } void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { @@ -259,51 +277,12 @@ void SkeletonModel::updateJointState(int index) { const FBXGeometry& geometry = _geometry->getFBXGeometry(); glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; - const JointState joint = _rig->getJointState(index); - if (joint.getParentIndex() >= 0 && joint.getParentIndex() < _rig->getJointStateCount()) { - const JointState parentState = _rig->getJointState(joint.getParentIndex()); - if (index == geometry.leanJointIndex) { - maybeUpdateLeanRotation(parentState, index); - - } else if (index == geometry.neckJointIndex) { - maybeUpdateNeckRotation(parentState, joint.getFBXJoint(), index); - - } else if (index == geometry.leftEyeJointIndex || index == geometry.rightEyeJointIndex) { - maybeUpdateEyeRotation(parentState, joint.getFBXJoint(), index); - } - } - _rig->updateJointState(index, parentTransform); if (index == _geometry->getFBXGeometry().rootJointIndex) { _rig->clearJointTransformTranslation(index); } } - -void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, int index) { - if (!_owningAvatar->isMyAvatar()) { - return; - } - // get the rotation axes in joint space and use them to adjust the rotation - glm::vec3 xAxis(1.0f, 0.0f, 0.0f); - glm::vec3 yAxis(0.0f, 1.0f, 0.0f); - glm::vec3 zAxis(0.0f, 0.0f, 1.0f); - glm::quat inverse = glm::inverse(parentState.getRotation() * _rig->getJointDefaultRotationInParentFrame(index)); - _rig->setJointRotationInConstrainedFrame(index, - glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanSideways(), inverse * zAxis) - * glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanForward(), inverse * xAxis) - * glm::angleAxis(RADIANS_PER_DEGREE * _owningAvatar->getHead()->getTorsoTwist(), inverse * yAxis) - * _rig->getJointState(index).getFBXJoint().rotation, LEAN_PRIORITY); -} - -void SkeletonModel::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, int index) { - _owningAvatar->getHead()->getFaceModel().maybeUpdateNeckRotation(parentState, joint, index); -} - -void SkeletonModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, int index) { - _owningAvatar->getHead()->getFaceModel().maybeUpdateEyeRotation(this, parentState, joint, index); -} - void SkeletonModel::renderJointConstraints(gpu::Batch& batch, int jointIndex) { if (jointIndex == -1 || jointIndex >= _rig->getJointStateCount()) { return; diff --git a/libraries/animation/src/AvatarRig.cpp b/libraries/animation/src/AvatarRig.cpp index cf05e61cdb..3b48b0814f 100644 --- a/libraries/animation/src/AvatarRig.cpp +++ b/libraries/animation/src/AvatarRig.cpp @@ -31,21 +31,3 @@ void AvatarRig::updateJointState(int index, glm::mat4 parentTransform) { } } } - - -void AvatarRig::updateFaceJointState(int index, glm::mat4 parentTransform) { - JointState& state = _jointStates[index]; - const FBXJoint& joint = state.getFBXJoint(); - - // compute model transforms - int parentIndex = joint.parentIndex; - if (parentIndex == -1) { - state.computeTransform(parentTransform); - } else { - // guard against out-of-bounds access to _jointStates - if (joint.parentIndex >= 0 && joint.parentIndex < _jointStates.size()) { - const JointState& parentState = _jointStates.at(parentIndex); - state.computeTransform(parentState.getTransform(), parentState.getTransformChanged()); - } - } -} diff --git a/libraries/animation/src/AvatarRig.h b/libraries/animation/src/AvatarRig.h index dbffd8aa45..4a111a535b 100644 --- a/libraries/animation/src/AvatarRig.h +++ b/libraries/animation/src/AvatarRig.h @@ -22,7 +22,6 @@ class AvatarRig : public Rig { public: ~AvatarRig() {} virtual void updateJointState(int index, glm::mat4 parentTransform); - virtual void updateFaceJointState(int index, glm::mat4 parentTransform); }; #endif // hifi_AvatarRig_h diff --git a/libraries/animation/src/EntityRig.h b/libraries/animation/src/EntityRig.h index aa6a5fbd2b..e8e15a5a28 100644 --- a/libraries/animation/src/EntityRig.h +++ b/libraries/animation/src/EntityRig.h @@ -22,7 +22,6 @@ class EntityRig : public Rig { public: ~EntityRig() {} virtual void updateJointState(int index, glm::mat4 parentTransform); - virtual void updateFaceJointState(int index, glm::mat4 parentTransform) { } }; #endif // hifi_EntityRig_h diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index dc7b37129e..2ff6faa868 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -665,3 +665,68 @@ glm::quat Rig::getJointDefaultRotationInParentFrame(int jointIndex) { } return _jointStates[jointIndex].getDefaultRotationInParentFrame(); } + +void Rig::updateFromHeadParameters(const HeadParameters& params) { + updateLeanJoint(params.leanJointIndex, params.leanSideways, params.leanForward, params.torsoTwist); + updateNeckJoint(params.neckJointIndex, params.localHeadOrientation, params.leanSideways, params.leanForward, params.torsoTwist); + updateEyeJoint(params.leftEyeJointIndex, params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade); + updateEyeJoint(params.rightEyeJointIndex, params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade); +} + +void Rig::updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist) { + if (index > 0 && _jointStates[index].getParentIndex() > 0) { + auto& parentState = _jointStates[_jointStates[index].getParentIndex()]; + + // get the rotation axes in joint space and use them to adjust the rotation + glm::vec3 xAxis(1.0f, 0.0f, 0.0f); + glm::vec3 yAxis(0.0f, 1.0f, 0.0f); + glm::vec3 zAxis(0.0f, 0.0f, 1.0f); + glm::quat inverse = glm::inverse(parentState.getRotation() * getJointDefaultRotationInParentFrame(index)); + setJointRotationInConstrainedFrame(index, + glm::angleAxis(- RADIANS_PER_DEGREE * leanSideways, inverse * zAxis) * + glm::angleAxis(- RADIANS_PER_DEGREE * leanForward, inverse * xAxis) * + glm::angleAxis(RADIANS_PER_DEGREE * torsoTwist, inverse * yAxis) * + getJointState(index).getFBXJoint().rotation, DEFAULT_PRIORITY); + } +} + +void Rig::updateNeckJoint(int index, const glm::quat& localHeadOrientation, float leanSideways, float leanForward, float torsoTwist) { + if (index > 0 && _jointStates[index].getParentIndex() > 0) { + auto& parentState = _jointStates[_jointStates[index].getParentIndex()]; + auto joint = _jointStates[index].getFBXJoint(); + + // get the rotation axes in joint space and use them to adjust the rotation + glm::mat3 axes = glm::mat3_cast(glm::quat()); + glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() * + glm::translate(getJointDefaultTranslationInConstrainedFrame(index)) * + joint.preTransform * glm::mat4_cast(joint.preRotation))); + glm::vec3 pitchYawRoll = safeEulerAngles(localHeadOrientation); + glm::vec3 lean = glm::radians(glm::vec3(leanForward, torsoTwist, leanSideways)); + pitchYawRoll -= lean; + setJointRotationInConstrainedFrame(index, + glm::angleAxis(-pitchYawRoll.z, glm::normalize(inverse * axes[2])) * + glm::angleAxis(pitchYawRoll.y, glm::normalize(inverse * axes[1])) * + glm::angleAxis(-pitchYawRoll.x, glm::normalize(inverse * axes[0])) * + joint.rotation, DEFAULT_PRIORITY); + } +} + +void Rig::updateEyeJoint(int index, const glm::quat& worldHeadOrientation, const glm::vec3& lookAt, const glm::vec3& saccade) { + if ( index > 0 && _jointStates[index].getParentIndex() > 0) { + auto& parentState = _jointStates[_jointStates[index].getParentIndex()]; + auto joint = _jointStates[index].getFBXJoint(); + + // NOTE: at the moment we do the math in the world-frame, hence the inverse transform is more complex than usual. + glm::mat4 inverse = glm::inverse(parentState.getTransform() * + glm::translate(getJointDefaultTranslationInConstrainedFrame(index)) * + joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation)); + glm::vec3 front = glm::vec3(inverse * glm::vec4(worldHeadOrientation * IDENTITY_FRONT, 0.0f)); + glm::vec3 lookAtDelta = lookAt; + glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(lookAtDelta + glm::length(lookAtDelta) * saccade, 1.0f)); + glm::quat between = rotationBetween(front, lookAt); + const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE; + float angle = glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE); + glm::quat rot = glm::angleAxis(angle, glm::axis(between)); + setJointRotationInConstrainedFrame(index, rot * joint.rotation, DEFAULT_PRIORITY); + } +} diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index fe6bc82f35..2eb9d0e0b3 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -47,14 +47,27 @@ typedef std::shared_ptr AnimationHandlePointer; class Rig; typedef std::shared_ptr RigPointer; - class Rig : public QObject, public std::enable_shared_from_this { public: + struct HeadParameters { + float leanSideways = 0.0f; // degrees + float leanForward = 0.0f; // degrees + float torsoTwist = 0.0f; // degrees + glm::quat localHeadOrientation = glm::quat(); + glm::quat worldHeadOrientation = glm::quat(); + glm::vec3 eyeLookAt = glm::vec3(); // world space + glm::vec3 eyeSaccade = glm::vec3(); // world space + int leanJointIndex = -1; + int neckJointIndex = -1; + int leftEyeJointIndex = -1; + int rightEyeJointIndex = -1; + }; + virtual ~Rig() {} - RigPointer getRigPointer() { return shared_from_this(); } + RigPointer getRigPointer() { return shared_from_this(); } AnimationHandlePointer createAnimationHandle(); void removeAnimationHandle(const AnimationHandlePointer& handle); @@ -129,11 +142,17 @@ public: void updateVisibleJointStates(); virtual void updateJointState(int index, glm::mat4 parentTransform) = 0; - virtual void updateFaceJointState(int index, glm::mat4 parentTransform) = 0; void setEnableRig(bool isEnabled) { _enableRig = isEnabled; } + void updateFromHeadParameters(const HeadParameters& params); + protected: + + void updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist); + void updateNeckJoint(int index, const glm::quat& localHeadOrientation, float leanSideways, float leanForward, float torsoTwist); + void updateEyeJoint(int index, const glm::quat& worldHeadOrientation, const glm::vec3& lookAt, const glm::vec3& saccade); + QVector _jointStates; QList _animationHandles; From ac46b2bd1733ba18fe6e1db99a1ee204c7408bdc Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 29 Jul 2015 17:38:23 -0700 Subject: [PATCH 59/74] Keep the resetstage in --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1dc2878008..8f37174c18 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1021,7 +1021,7 @@ void Application::paintGL() { batch.resetStages(); // TODO: Testing the water here, it is maybe not needed at all, // i would like to keep it like that until we merge with DisplayPlugin - // renderArgs._context->render(batch); + renderArgs._context->render(batch); } void Application::runTests() { From b7ecffa0beba9a47969e97f69063ab761a613781 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 29 Jul 2015 17:55:56 -0700 Subject: [PATCH 60/74] treat a "g" in an obj file the same as a "o" --- libraries/fbx/src/OBJReader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index f16c6ba215..da63b2f47f 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -306,7 +306,8 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi } QByteArray token = tokenizer.getDatum(); //qCDebug(modelformat) << token; - if (token == "g") { + // we don't support separate objects in the same file, so treat "o" the same as "g". + if (token == "g" || token == "o") { if (sawG) { // we've encountered the beginning of the next group. tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN); From e32e45ed2b8faefc74c0f884d96eb9e1ee3a8865 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 29 Jul 2015 18:06:46 -0700 Subject: [PATCH 61/74] make sure the writting mask is on for depth buffer --- interface/src/Application.cpp | 2 -- libraries/gpu/src/gpu/GLBackendOutput.cpp | 12 ++++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8f37174c18..1c91f9282c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1019,8 +1019,6 @@ void Application::paintGL() { // Back to the default framebuffer; gpu::Batch batch; batch.resetStages(); - // TODO: Testing the water here, it is maybe not needed at all, - // i would like to keep it like that until we merge with DisplayPlugin renderArgs._context->render(batch); } diff --git a/libraries/gpu/src/gpu/GLBackendOutput.cpp b/libraries/gpu/src/gpu/GLBackendOutput.cpp index d57ef57d78..c898b4a843 100755 --- a/libraries/gpu/src/gpu/GLBackendOutput.cpp +++ b/libraries/gpu/src/gpu/GLBackendOutput.cpp @@ -209,10 +209,17 @@ void GLBackend::do_clearFramebuffer(Batch& batch, uint32 paramOffset) { int stencil = batch._params[paramOffset + 1]._int; int useScissor = batch._params[paramOffset + 0]._int; + bool restoreDepthMask = false; GLuint glmask = 0; if (masks & Framebuffer::BUFFER_STENCIL) { glClearStencil(stencil); glmask |= GL_STENCIL_BUFFER_BIT; + + bool cacheDepthMask = _pipeline._stateCache.depthTest.getWriteMask(); + if (!cacheDepthMask) { + restoreDepthMask = true; + glDepthMask(GL_TRUE); + } } if (masks & Framebuffer::BUFFER_DEPTH) { @@ -252,6 +259,11 @@ void GLBackend::do_clearFramebuffer(Batch& batch, uint32 paramOffset) { glDisable(GL_SCISSOR_TEST); } + // REstore write mask + if (restoreDepthMask) { + glDepthMask(GL_FALSE); + } + // Restore the color draw buffers only if a frmaebuffer is bound if (_output._framebuffer && !drawBuffers.empty()) { auto glFramebuffer = syncGPUObject(*_output._framebuffer); From 70d64a7777f90d6ae2afabc20348adfceb00e5e1 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 29 Jul 2015 18:27:10 -0700 Subject: [PATCH 62/74] Really fixing the depth write mask issue on clear... --- libraries/gpu/src/gpu/GLBackendOutput.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackendOutput.cpp b/libraries/gpu/src/gpu/GLBackendOutput.cpp index c898b4a843..d75d0cf521 100755 --- a/libraries/gpu/src/gpu/GLBackendOutput.cpp +++ b/libraries/gpu/src/gpu/GLBackendOutput.cpp @@ -209,11 +209,18 @@ void GLBackend::do_clearFramebuffer(Batch& batch, uint32 paramOffset) { int stencil = batch._params[paramOffset + 1]._int; int useScissor = batch._params[paramOffset + 0]._int; - bool restoreDepthMask = false; GLuint glmask = 0; if (masks & Framebuffer::BUFFER_STENCIL) { glClearStencil(stencil); glmask |= GL_STENCIL_BUFFER_BIT; + // TODO: we will probably need to also check the write mask of stencil like we do + // for depth buffer, but as would say a famous Fez owner "We'll cross that bridge when we come to it" + } + + bool restoreDepthMask = false; + if (masks & Framebuffer::BUFFER_DEPTH) { + glClearDepth(depth); + glmask |= GL_DEPTH_BUFFER_BIT; bool cacheDepthMask = _pipeline._stateCache.depthTest.getWriteMask(); if (!cacheDepthMask) { @@ -222,11 +229,6 @@ void GLBackend::do_clearFramebuffer(Batch& batch, uint32 paramOffset) { } } - if (masks & Framebuffer::BUFFER_DEPTH) { - glClearDepth(depth); - glmask |= GL_DEPTH_BUFFER_BIT; - } - std::vector drawBuffers; if (masks & Framebuffer::BUFFER_COLORS) { for (unsigned int i = 0; i < Framebuffer::MAX_NUM_RENDER_BUFFERS; i++) { @@ -259,7 +261,7 @@ void GLBackend::do_clearFramebuffer(Batch& batch, uint32 paramOffset) { glDisable(GL_SCISSOR_TEST); } - // REstore write mask + // Restore write mask meaning turn back off if (restoreDepthMask) { glDepthMask(GL_FALSE); } From 291e0e21ae858d09b53d05cbb1fc2dc19c7e306f Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Wed, 29 Jul 2015 18:47:27 -0700 Subject: [PATCH 63/74] HBAO final implementation --- .../src/AmbientOcclusionEffect.cpp | 2 +- .../render-utils/src/ambient_occlusion.slf | 183 +++--------------- .../render-utils/src/occlusion_blend.slf | 7 +- 3 files changed, 34 insertions(+), 158 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index f19fa6e18a..720f765ae4 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -164,7 +164,7 @@ const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() { // Blend on transparent state->setBlendFunction(true, - gpu::State::SRC_COLOR, gpu::State::BLEND_OP_ADD, gpu::State::DEST_COLOR); + gpu::State::INV_SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::SRC_ALPHA); // Good to go add the brand new pipeline _blendPipeline.reset(gpu::Pipeline::create(program, state)); diff --git a/libraries/render-utils/src/ambient_occlusion.slf b/libraries/render-utils/src/ambient_occlusion.slf index 96aba989a8..f45fd9b6a0 100644 --- a/libraries/render-utils/src/ambient_occlusion.slf +++ b/libraries/render-utils/src/ambient_occlusion.slf @@ -17,99 +17,8 @@ <@include gpu/Transform.slh@> <$declareStandardTransform()$> -/* -varying vec2 varTexcoord; -uniform sampler2D depthTexture; -uniform sampler2D normalTexture; - -uniform float g_scale; -uniform float g_bias; -uniform float g_sample_rad; -uniform float g_intensity; -uniform float bufferWidth; -uniform float bufferHeight; - -#define SAMPLE_COUNT 4 - -float getRandom(vec2 uv) { - return fract(sin(dot(uv.xy ,vec2(12.9898,78.233))) * 43758.5453); -} - -void main(void) { - vec3 sampleKernel[4] = { vec3(0.2, 0.0, 0.0), - vec3(0.0, 0.2, 0.0), - vec3(0.0, 0.0, 0.2), - vec3(0.2, 0.2, 0.2) }; - - TransformCamera cam = getTransformCamera(); - TransformObject obj = getTransformObject(); - - vec3 eyeDir = vec3(0.0, 0.0, -3.0); - vec3 cameraPositionWorldSpace; - <$transformEyeToWorldDir(cam, eyeDir, cameraPositionWorldSpace)$> - - vec4 depthColor = texture2D(depthTexture, varTexcoord); - - // z in non linear range [0,1] - float depthVal = depthColor.r; - // conversion into NDC [-1,1] - float zNDC = depthVal * 2.0 - 1.0; - float n = 1.0; // the near plane - float f = 30.0; // the far plane - float l = -1.0; // left - float r = 1.0; // right - float b = -1.0; // bottom - float t = 1.0; // top - - // conversion into eye space - float zEye = 2*f*n / (zNDC*(f-n)-(f+n)); - // Converting from pixel coordinates to NDC - float xNDC = gl_FragCoord.x/bufferWidth * 2.0 - 1.0; - float yNDC = gl_FragCoord.y/bufferHeight * 2.0 - 1.0; - // Unprojecting X and Y from NDC to eye space - float xEye = -zEye*(xNDC*(r-l)+(r+l))/(2.0*n); - float yEye = -zEye*(yNDC*(t-b)+(t+b))/(2.0*n); - vec3 currentFragEyeSpace = vec3(xEye, yEye, zEye); - vec3 currentFragWorldSpace; - <$transformEyeToWorldDir(cam, currentFragEyeSpace, currentFragWorldSpace)$> - - vec3 cameraToPositionRay = normalize(currentFragWorldSpace - cameraPositionWorldSpace); - vec3 origin = cameraToPositionRay * depthVal + cameraPositionWorldSpace; - - vec3 normal = normalize(texture2D(normalTexture, varTexcoord).xyz); - //normal = normalize(normal * normalMatrix); - - vec3 rvec = vec3(getRandom(varTexcoord.xy), getRandom(varTexcoord.yx), getRandom(varTexcoord.xx)) * 2.0 - 1.0; - vec3 tangent = normalize(rvec - normal * dot(rvec, normal)); - vec3 bitangent = cross(normal, tangent); - mat3 tbn = mat3(tangent, bitangent, normal); - - float occlusion = 0.0; - - for (int i = 0; i < SAMPLE_COUNT; ++i) { - vec3 samplePos = origin + (tbn * sampleKernel[i]) * g_sample_rad; - vec4 offset = cam._projectionViewUntranslated * vec4(samplePos, 1.0); - - offset.xy = (offset.xy / offset.w) * 0.5 + 0.5; - float depth = length(samplePos - cameraPositionWorldSpace); - - float sampleDepthVal = texture2D(depthTexture, offset.xy).r; - - float rangeDelta = abs(depthVal - sampleDepthVal); - float rangeCheck = smoothstep(0.0, 1.0, g_sample_rad / rangeDelta); - - occlusion += rangeCheck * step(sampleDepthVal, depth); - } - - occlusion = 1.0 - occlusion / float(SAMPLE_COUNT); - occlusion = clamp(pow(occlusion, g_intensity), 0.0, 1.0); - gl_FragColor = vec4(vec3(occlusion), 1.0); -}*/ - -// This is a HBAO-Shader for OpenGL, based upon nvidias directX implementation -// supplied in their SampleSDK available from nvidia.com -// The slides describing the implementation is available at +// Based on NVidia HBAO implementation in D3D11 // http://www.nvidia.co.uk/object/siggraph-2008-HBAO.html varying vec2 varTexcoord; @@ -127,8 +36,6 @@ uniform float bufferHeight; const float PI = 3.14159265; const vec2 FocalLen = vec2(1.0, 1.0); -//const vec2 UVToViewA = vec2(1.0, 1.0); -//const vec2 UVToViewB = vec2(1.0, 1.0); const vec2 LinMAD = vec2(0.1-10.0, 0.1+10.0) / (2.0*0.1*10.0); @@ -141,13 +48,12 @@ const float R = 0.3; const float R2 = 0.3*0.3; const float NegInvR2 = - 1.0 / (0.3*0.3); const float TanBias = tan(30.0 * PI / 180.0); -const float MaxRadiusPixels = 100.0; +const float MaxRadiusPixels = 50.0; const int NumDirections = 6; const int NumSamples = 4; -float ViewSpaceZFromDepth(float d) -{ +float ViewSpaceZFromDepth(float d){ // [0,1] -> [-1,1] clip space d = d * 2.0 - 1.0; @@ -155,80 +61,62 @@ float ViewSpaceZFromDepth(float d) return -1.0 / (LinMAD.x * d + LinMAD.y); } -vec3 UVToViewSpace(vec2 uv, float z) -{ +vec3 UVToViewSpace(vec2 uv, float z){ //uv = UVToViewA * uv + UVToViewB; return vec3(uv * z, z); } -vec3 GetViewPos(vec2 uv) -{ +vec3 GetViewPos(vec2 uv){ float z = ViewSpaceZFromDepth(texture2D(depthTexture, uv).r); return UVToViewSpace(uv, z); } -vec3 GetViewPosPoint(ivec2 uv) -{ +vec3 GetViewPosPoint(ivec2 uv){ vec2 coord = vec2(gl_FragCoord.xy) + uv; //float z = texelFetch(texture0, coord, 0).r; float z = texture2D(depthTexture, uv).r; return UVToViewSpace(uv, z); } -float TanToSin(float x) -{ +float TanToSin(float x){ return x * inversesqrt(x*x + 1.0); } -float InvLength(vec2 V) -{ +float InvLength(vec2 V){ return inversesqrt(dot(V,V)); } -float Tangent(vec3 V) -{ +float Tangent(vec3 V){ return V.z * InvLength(V.xy); } -float BiasedTangent(vec3 V) -{ +float BiasedTangent(vec3 V){ return V.z * InvLength(V.xy) + TanBias; } -float Tangent(vec3 P, vec3 S) -{ +float Tangent(vec3 P, vec3 S){ return -(P.z - S.z) * InvLength(S.xy - P.xy); } -float Length2(vec3 V) -{ +float Length2(vec3 V){ return dot(V,V); } -vec3 MinDiff(vec3 P, vec3 Pr, vec3 Pl) -{ +vec3 MinDiff(vec3 P, vec3 Pr, vec3 Pl){ vec3 V1 = Pr - P; vec3 V2 = P - Pl; return (Length2(V1) < Length2(V2)) ? V1 : V2; } -vec2 SnapUVOffset(vec2 uv) -{ +vec2 SnapUVOffset(vec2 uv){ return round(uv * AORes) * InvAORes; } -float Falloff(float d2) -{ +float Falloff(float d2){ return d2 * NegInvR2 + 1.0f; } -float HorizonOcclusion( vec2 deltaUV, - vec3 P, - vec3 dPdu, - vec3 dPdv, - float randstep, - float numSamples) -{ +float HorizonOcclusion( vec2 deltaUV, vec3 P, vec3 dPdu, vec3 dPdv, float randstep, float numSamples){ float ao = 0; // Offset the first coord with some noise @@ -247,8 +135,7 @@ float HorizonOcclusion( vec2 deltaUV, vec3 S; // Sample to find the maximum angle - for(float s = 1; s <= numSamples; ++s) - { + for(float s = 1; s <= numSamples; ++s){ uv += deltaUV; S = GetViewPos(uv); tanS = Tangent(P, S); @@ -265,18 +152,14 @@ float HorizonOcclusion( vec2 deltaUV, sinH = sinS; } } - return ao; } -vec2 RotateDirections(vec2 Dir, vec2 CosSin) -{ - return vec2(Dir.x*CosSin.x - Dir.y*CosSin.y, - Dir.x*CosSin.y + Dir.y*CosSin.x); +vec2 RotateDirections(vec2 Dir, vec2 CosSin){ + return vec2(Dir.x*CosSin.x - Dir.y*CosSin.y, Dir.x*CosSin.y + Dir.y*CosSin.x); } -void ComputeSteps(inout vec2 stepSizeUv, inout float numSteps, float rayRadiusPix, float rand) -{ +void ComputeSteps(inout vec2 stepSizeUv, inout float numSteps, float rayRadiusPix, float rand){ // Avoid oversampling if numSteps is greater than the kernel radius in pixels numSteps = min(NumSamples, rayRadiusPix); @@ -297,28 +180,27 @@ void ComputeSteps(inout vec2 stepSizeUv, inout float numSteps, float rayRadiusPi stepSizeUv = stepSizePix * InvAORes; } -float getRandom(vec2 uv) { +float getRandom(vec2 uv){ return fract(sin(dot(uv.xy ,vec2(12.9898,78.233))) * 43758.5453); } -void main(void) -{ +void main(void){ float numDirections = NumDirections; vec3 P, Pr, Pl, Pt, Pb; - P = GetViewPos(varTexcoord); + P = GetViewPos(varTexcoord); // Sample neighboring pixels - Pr = GetViewPos(varTexcoord + vec2( InvAORes.x, 0)); - Pl = GetViewPos(varTexcoord + vec2(-InvAORes.x, 0)); - Pt = GetViewPos(varTexcoord + vec2( 0, InvAORes.y)); - Pb = GetViewPos(varTexcoord + vec2( 0,-InvAORes.y)); + Pr = GetViewPos(varTexcoord + vec2( InvAORes.x, 0)); + Pl = GetViewPos(varTexcoord + vec2(-InvAORes.x, 0)); + Pt = GetViewPos(varTexcoord + vec2( 0, InvAORes.y)); + Pb = GetViewPos(varTexcoord + vec2( 0,-InvAORes.y)); - // Calculate tangent basis vectors using the minimu difference + // Calculate tangent basis vectors using the minimum difference vec3 dPdu = MinDiff(P, Pr, Pl); vec3 dPdv = MinDiff(P, Pt, Pb) * (AORes.y * InvAORes.x); - // Get the random samples from the noise texture + // Get the random samples from the noise function vec3 random = vec3(getRandom(varTexcoord.xy), getRandom(varTexcoord.yx), getRandom(varTexcoord.xx)); // Calculate the projected size of the hemisphere @@ -328,8 +210,7 @@ void main(void) float ao = 1.0; // Make sure the radius of the evaluated hemisphere is more than a pixel - if(rayRadiusPix > 1.0) - { + if(rayRadiusPix > 1.0){ ao = 0.0; float numSteps; vec2 stepSizeUV; @@ -340,8 +221,7 @@ void main(void) float alpha = 2.0 * PI / numDirections; // Calculate the horizon occlusion of each direction - for(float d = 0; d < numDirections; ++d) - { + for(float d = 0; d < numDirections; ++d){ float theta = alpha * d; // Apply noise to the direction @@ -361,6 +241,5 @@ void main(void) ao = 1.0 - ao / numDirections * AOStrength; } - //out_frag0 = vec2(ao, 30.0 * P.z); gl_FragColor = vec4(vec3(ao), 1.0); } \ No newline at end of file diff --git a/libraries/render-utils/src/occlusion_blend.slf b/libraries/render-utils/src/occlusion_blend.slf index 965d806759..cdab624b95 100644 --- a/libraries/render-utils/src/occlusion_blend.slf +++ b/libraries/render-utils/src/occlusion_blend.slf @@ -21,9 +21,6 @@ uniform sampler2D blurredOcclusionTexture; void main(void) { vec4 occlusionColor = texture2D(blurredOcclusionTexture, varTexcoord); - if(occlusionColor.r > 0.8 && occlusionColor.r <= 1.0) { - gl_FragColor = vec4(vec3(0.0), 0.0); - } else { - gl_FragColor = vec4(vec3(occlusionColor.r), 1.0); - } + gl_FragColor = vec4(vec3(0.0), occlusionColor.r); + } From dc34c025bd1b6413ed5306f4d4f5cff4ce0f686b Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Wed, 29 Jul 2015 18:54:05 -0700 Subject: [PATCH 64/74] whitespace --- libraries/animation/src/Rig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 2eb9d0e0b3..70f0a59a21 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -67,7 +67,7 @@ public: virtual ~Rig() {} - RigPointer getRigPointer() { return shared_from_this(); } + RigPointer getRigPointer() { return shared_from_this(); } AnimationHandlePointer createAnimationHandle(); void removeAnimationHandle(const AnimationHandlePointer& handle); From a9556660c4ee2995eb5f96039c7489a0bf276d8b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 29 Jul 2015 20:53:24 -0700 Subject: [PATCH 65/74] fix linux build --- libraries/entities/src/ParticleEffectEntityItem.cpp | 6 +++--- libraries/gpu/src/gpu/Batch.cpp | 2 ++ libraries/gpu/src/gpu/GLBackendShader.cpp | 3 +-- libraries/gpu/src/gpu/GLBackendState.cpp | 10 +++++----- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 4dfc9dd436..dc5bbb85ed 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -155,9 +155,9 @@ void ParticleEffectEntityItem::computeAndUpdateDimensions() { float yMin = std::min(yApex, yEnd); // times 2 because dimensions are diameters not radii. - glm::vec3 dims(2.0f * std::max(fabs(xMin), fabs(xMax)), - 2.0f * std::max(fabs(yMin), fabs(yMax)), - 2.0f * std::max(fabs(zMin), fabs(zMax))); + glm::vec3 dims(2.0f * std::max(fabsf(xMin), fabsf(xMax)), + 2.0f * std::max(fabsf(yMin), fabsf(yMax)), + 2.0f * std::max(fabsf(zMin), fabsf(zMax))); EntityItem::setDimensions(dims); } diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index a10f5b3de7..0347536808 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -8,6 +8,8 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "Batch.h" #if defined(NSIGHT_FOUND) diff --git a/libraries/gpu/src/gpu/GLBackendShader.cpp b/libraries/gpu/src/gpu/GLBackendShader.cpp index dccd035cb4..5fa0e277e5 100755 --- a/libraries/gpu/src/gpu/GLBackendShader.cpp +++ b/libraries/gpu/src/gpu/GLBackendShader.cpp @@ -639,14 +639,13 @@ int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindin GLchar name[NAME_LENGTH]; GLint length = 0; GLint size = 0; - GLenum type = 0; GLint binding = -1; glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &length); glGetActiveUniformBlockName(glprogram, i, NAME_LENGTH, &length, name); glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_BINDING, &binding); glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_DATA_SIZE, &size); - + GLuint blockIndex = glGetUniformBlockIndex(glprogram, name); // CHeck if there is a requested binding for this block diff --git a/libraries/gpu/src/gpu/GLBackendState.cpp b/libraries/gpu/src/gpu/GLBackendState.cpp index e9dcd3aad3..22c61b2365 100644 --- a/libraries/gpu/src/gpu/GLBackendState.cpp +++ b/libraries/gpu/src/gpu/GLBackendState.cpp @@ -482,15 +482,15 @@ void GLBackend::syncPipelineStateCache() { State::Data state; glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); - - // Point size is always on - glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); - glEnable(GL_PROGRAM_POINT_SIZE_EXT); + + // Point size is always on + glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); + glEnable(GL_PROGRAM_POINT_SIZE_EXT); glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); getCurrentGLState(state); State::Signature signature = State::evalSignature(state); - + _pipeline._stateCache = state; _pipeline._stateSignatureCache = signature; } From fa6d6a51230de1c91b8d2bf0ff29ddc5fe757603 Mon Sep 17 00:00:00 2001 From: Marcel Verhagen Date: Thu, 30 Jul 2015 15:08:02 +0200 Subject: [PATCH 66/74] Added the & references to the const variables --- libraries/fbx/src/FBXReader.cpp | 8 ++++---- libraries/fbx/src/FBXReader.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 69482a8c81..8b83acdca4 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1455,7 +1455,7 @@ void buildModelMesh(ExtractedMesh& extracted) { } #endif // USE_MODEL_MESH -QByteArray fileOnUrl(const QByteArray filenameString,const QString url) { +QByteArray fileOnUrl(const QByteArray& filenameString, const QString& url) { QString path = QFileInfo(url).path(); QByteArray filename = filenameString; QFileInfo checkFile(path + "/" + filename.replace('\\', '/')); @@ -1469,7 +1469,7 @@ QByteArray fileOnUrl(const QByteArray filenameString,const QString url) { return filename; } -FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, QString url, bool loadLightmaps, float lightmapLevel) { +FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) { QHash meshes; QHash modelIDsToNames; QHash meshIDsToMeshIndices; @@ -2722,12 +2722,12 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, return geometry; } -FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, const QString url, bool loadLightmaps, float lightmapLevel) { +FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) { QBuffer buffer(const_cast(&model)); buffer.open(QIODevice::ReadOnly); return readFBX(&buffer, mapping, url, loadLightmaps, lightmapLevel); } -FBXGeometry readFBX(QIODevice* device, const QVariantHash& mapping, const QString url, bool loadLightmaps, float lightmapLevel) { +FBXGeometry readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) { return extractFBXGeometry(parseFBX(device), mapping, url, loadLightmaps, lightmapLevel); } diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index cf86c304ac..776b78b3bb 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -268,10 +268,10 @@ Q_DECLARE_METATYPE(FBXGeometry) /// Reads FBX geometry from the supplied model and mapping data. /// \exception QString if an error occurs in parsing -FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, const QString url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f); +FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f); /// Reads FBX geometry from the supplied model and mapping data. /// \exception QString if an error occurs in parsing -FBXGeometry readFBX(QIODevice* device, const QVariantHash& mapping, const QString url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f); +FBXGeometry readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f); #endif // hifi_FBXReader_h From 4bb415fd0d6ffe8b5e936298bfa0d9359549ed67 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 30 Jul 2015 09:29:59 -0700 Subject: [PATCH 67/74] Fix for torso twist. Off by one error, 0 is a valid parent bone index. --- libraries/animation/src/Rig.cpp | 25 ++++++++++++++++++++++--- libraries/animation/src/Rig.h | 2 ++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 2ff6faa868..15f3dd65ec 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -16,6 +16,25 @@ #include "AnimationLogging.h" #include "Rig.h" +void Rig::HeadParameters::dump() const { + qCDebug(animation, "HeadParameters ="); + qCDebug(animation, " leanSideways = %0.5f", leanSideways); + qCDebug(animation, " leanForward = %0.5f", leanForward); + qCDebug(animation, " torsoTwist = %0.5f", torsoTwist); + glm::vec3 axis = glm::axis(localHeadOrientation); + float theta = glm::angle(localHeadOrientation); + qCDebug(animation, " localHeadOrientation axis = (%.5f, %.5f, %.5f), theta = %0.5f", axis.x, axis.y, axis.z, theta); + axis = glm::axis(worldHeadOrientation); + theta = glm::angle(worldHeadOrientation); + qCDebug(animation, " worldHeadOrientation axis = (%.5f, %.5f, %.5f), theta = %0.5f", axis.x, axis.y, axis.z, theta); + qCDebug(animation, " eyeLookAt = (%.5f, %.5f, %.5f)", eyeLookAt.x, eyeLookAt.y, eyeLookAt.z); + qCDebug(animation, " eyeSaccade = (%.5f, %.5f, %.5f)", eyeSaccade.x, eyeSaccade.y, eyeSaccade.z); + qCDebug(animation, " leanJointIndex = %.d", leanJointIndex); + qCDebug(animation, " neckJointIndex = %.d", neckJointIndex); + qCDebug(animation, " leftEyeJointIndex = %.d", leftEyeJointIndex); + qCDebug(animation, " rightEyeJointIndex = %.d", rightEyeJointIndex); +} + void insertSorted(QList& handles, const AnimationHandlePointer& handle) { for (QList::iterator it = handles.begin(); it != handles.end(); it++) { if (handle->getPriority() > (*it)->getPriority()) { @@ -674,7 +693,7 @@ void Rig::updateFromHeadParameters(const HeadParameters& params) { } void Rig::updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist) { - if (index > 0 && _jointStates[index].getParentIndex() > 0) { + if (index >= 0 && _jointStates[index].getParentIndex() >= 0) { auto& parentState = _jointStates[_jointStates[index].getParentIndex()]; // get the rotation axes in joint space and use them to adjust the rotation @@ -691,7 +710,7 @@ void Rig::updateLeanJoint(int index, float leanSideways, float leanForward, floa } void Rig::updateNeckJoint(int index, const glm::quat& localHeadOrientation, float leanSideways, float leanForward, float torsoTwist) { - if (index > 0 && _jointStates[index].getParentIndex() > 0) { + if (index >= 0 && _jointStates[index].getParentIndex() >= 0) { auto& parentState = _jointStates[_jointStates[index].getParentIndex()]; auto joint = _jointStates[index].getFBXJoint(); @@ -712,7 +731,7 @@ void Rig::updateNeckJoint(int index, const glm::quat& localHeadOrientation, floa } void Rig::updateEyeJoint(int index, const glm::quat& worldHeadOrientation, const glm::vec3& lookAt, const glm::vec3& saccade) { - if ( index > 0 && _jointStates[index].getParentIndex() > 0) { + if (index >= 0 && _jointStates[index].getParentIndex() >= 0) { auto& parentState = _jointStates[_jointStates[index].getParentIndex()]; auto joint = _jointStates[index].getFBXJoint(); diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 70f0a59a21..2af61bfded 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -63,6 +63,8 @@ public: int neckJointIndex = -1; int leftEyeJointIndex = -1; int rightEyeJointIndex = -1; + + void dump() const; }; virtual ~Rig() {} From fc80e427b9ceef1f61acf4f6005ef1a688091f94 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jul 2015 11:08:45 -0700 Subject: [PATCH 68/74] remove names from audio-mixer jitter calc comments --- assignment-client/src/audio/AudioMixer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index b68332210b..04cbb0b325 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -927,9 +927,9 @@ void AudioMixer::parseSettingsObject(const QJsonObject &settingsObject) { const QString USE_STDEV_FOR_DESIRED_CALC_JSON_KEY = "use_stdev_for_desired_calc"; _streamSettings._useStDevForJitterCalc = audioBufferGroupObject[USE_STDEV_FOR_DESIRED_CALC_JSON_KEY].toBool(); if (_streamSettings._useStDevForJitterCalc) { - qDebug() << "Using Philip's stdev method for jitter calc if dynamic jitter buffers enabled"; + qDebug() << "Using stdev method for jitter calc if dynamic jitter buffers enabled"; } else { - qDebug() << "Using Fred's max-gap method for jitter calc if dynamic jitter buffers enabled"; + qDebug() << "Using max-gap method for jitter calc if dynamic jitter buffers enabled"; } const QString WINDOW_STARVE_THRESHOLD_JSON_KEY = "window_starve_threshold"; From 314434e0689098d567f76e2cb2c92b586e9c5dc3 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 30 Jul 2015 12:27:28 -0700 Subject: [PATCH 69/74] Re-added neck and eye procedural animation to FaceModel. This is only used in the case of split head/body avatars. --- interface/src/avatar/FaceModel.cpp | 61 +++++++++++++++++++++++++++++- interface/src/avatar/FaceModel.h | 4 ++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index d5d4da8665..f909489dc9 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -25,6 +25,7 @@ FaceModel::FaceModel(Head* owningHead, RigPointer rig) : void FaceModel::simulate(float deltaTime, bool fullUpdate) { updateGeometry(); + Avatar* owningAvatar = static_cast(_owningHead->_owningAvatar); glm::vec3 neckPosition; if (!owningAvatar->getSkeletonModel().getNeckPosition(neckPosition)) { @@ -37,19 +38,75 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) { } setRotation(neckParentRotation); setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningHead->getScale()); - + setPupilDilation(_owningHead->getPupilDilation()); setBlendshapeCoefficients(_owningHead->getBlendshapeCoefficients()); - + // FIXME - this is very expensive, we shouldn't do it if we don't have to //invalidCalculatedMeshBoxes(); if (isActive()) { setOffset(-_geometry->getFBXGeometry().neckPivot); + + for (int i = 0; i < _rig->getJointStateCount(); i++) { + updateJointState(i); + } + Model::simulateInternal(deltaTime); } } +void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, int index) { + // get the rotation axes in joint space and use them to adjust the rotation + glm::mat3 axes = glm::mat3_cast(glm::quat()); + glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() * + glm::translate(_rig->getJointDefaultTranslationInConstrainedFrame(index)) * + joint.preTransform * glm::mat4_cast(joint.preRotation))); + glm::vec3 pitchYawRoll = safeEulerAngles(_owningHead->getFinalOrientationInLocalFrame()); + glm::vec3 lean = glm::radians(glm::vec3(_owningHead->getFinalLeanForward(), + _owningHead->getTorsoTwist(), + _owningHead->getFinalLeanSideways())); + pitchYawRoll -= lean; + _rig->setJointRotationInConstrainedFrame(index, + glm::angleAxis(-pitchYawRoll.z, glm::normalize(inverse * axes[2])) + * glm::angleAxis(pitchYawRoll.y, glm::normalize(inverse * axes[1])) + * glm::angleAxis(-pitchYawRoll.x, glm::normalize(inverse * axes[0])) + * joint.rotation, DEFAULT_PRIORITY); +} + +void FaceModel::maybeUpdateEyeRotation(Model* model, const JointState& parentState, const FBXJoint& joint, int index) { + // likewise with the eye joints + // NOTE: at the moment we do the math in the world-frame, hence the inverse transform is more complex than usual. + glm::mat4 inverse = glm::inverse(glm::mat4_cast(model->getRotation()) * parentState.getTransform() * + glm::translate(_rig->getJointDefaultTranslationInConstrainedFrame(index)) * + joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation)); + glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getFinalOrientationInWorldFrame() * IDENTITY_FRONT, 0.0f)); + glm::vec3 lookAtDelta = _owningHead->getCorrectedLookAtPosition() - model->getTranslation(); + glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(lookAtDelta + glm::length(lookAtDelta) * _owningHead->getSaccade(), 1.0f)); + glm::quat between = rotationBetween(front, lookAt); + const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE; + _rig->setJointRotationInConstrainedFrame(index, glm::angleAxis(glm::clamp(glm::angle(between), + -MAX_ANGLE, MAX_ANGLE), glm::axis(between)) * + joint.rotation, DEFAULT_PRIORITY); +} + +void FaceModel::updateJointState(int index) { + const JointState& state = _rig->getJointState(index); + const FBXJoint& joint = state.getFBXJoint(); + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + + // guard against out-of-bounds access to _jointStates + if (joint.parentIndex != -1 && joint.parentIndex >= 0 && joint.parentIndex < _rig->getJointStateCount()) { + const JointState& parentState = _rig->getJointState(joint.parentIndex); + if (index == geometry.neckJointIndex) { + maybeUpdateNeckRotation(parentState, joint, index); + + } else if (index == geometry.leftEyeJointIndex || index == geometry.rightEyeJointIndex) { + maybeUpdateEyeRotation(this, parentState, joint, index); + } + } +} + bool FaceModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { if (!isActive()) { return false; diff --git a/interface/src/avatar/FaceModel.h b/interface/src/avatar/FaceModel.h index 5a19a8ea29..40f502f2d3 100644 --- a/interface/src/avatar/FaceModel.h +++ b/interface/src/avatar/FaceModel.h @@ -26,6 +26,10 @@ public: virtual void simulate(float deltaTime, bool fullUpdate = true); + void maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, int index); + void maybeUpdateEyeRotation(Model* model, const JointState& parentState, const FBXJoint& joint, int index); + void updateJointState(int index); + /// Retrieve the positions of up to two eye meshes. /// \return whether or not both eye meshes were found bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; From 7a10b31dd94f999aa1ca571a6886c0e2c5beed22 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 30 Jul 2015 15:04:27 -0700 Subject: [PATCH 70/74] Clear translation on root joint. Also, delete/rename all instances of updateJointState except for the one in Rig and derived classes. --- interface/src/avatar/FaceModel.cpp | 4 ++-- interface/src/avatar/FaceModel.h | 2 +- interface/src/avatar/SkeletonModel.cpp | 33 -------------------------- interface/src/avatar/SkeletonModel.h | 13 ---------- libraries/animation/src/AvatarRig.cpp | 1 + libraries/render-utils/src/Model.cpp | 8 +------ libraries/render-utils/src/Model.h | 3 --- 7 files changed, 5 insertions(+), 59 deletions(-) diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index f909489dc9..066144a425 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -49,7 +49,7 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) { setOffset(-_geometry->getFBXGeometry().neckPivot); for (int i = 0; i < _rig->getJointStateCount(); i++) { - updateJointState(i); + maybeUpdateNeckAndEyeRotation(i); } Model::simulateInternal(deltaTime); @@ -90,7 +90,7 @@ void FaceModel::maybeUpdateEyeRotation(Model* model, const JointState& parentSta joint.rotation, DEFAULT_PRIORITY); } -void FaceModel::updateJointState(int index) { +void FaceModel::maybeUpdateNeckAndEyeRotation(int index) { const JointState& state = _rig->getJointState(index); const FBXJoint& joint = state.getFBXJoint(); const FBXGeometry& geometry = _geometry->getFBXGeometry(); diff --git a/interface/src/avatar/FaceModel.h b/interface/src/avatar/FaceModel.h index 40f502f2d3..54d685c73c 100644 --- a/interface/src/avatar/FaceModel.h +++ b/interface/src/avatar/FaceModel.h @@ -28,7 +28,7 @@ public: void maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, int index); void maybeUpdateEyeRotation(Model* model, const JointState& parentState, const FBXJoint& joint, int index); - void updateJointState(int index); + void maybeUpdateNeckAndEyeRotation(int index); /// Retrieve the positions of up to two eye meshes. /// \return whether or not both eye meshes were found diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 3830360c0e..1b3298c75d 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -83,29 +83,6 @@ void SkeletonModel::initJointStates(QVector states) { const float PALM_PRIORITY = DEFAULT_PRIORITY; const float LEAN_PRIORITY = DEFAULT_PRIORITY; - -void SkeletonModel::updateClusterMatrices() { - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - glm::mat4 modelToWorld = glm::mat4_cast(_rotation); - for (int i = 0; i < _meshStates.size(); i++) { - MeshState& state = _meshStates[i]; - const FBXMesh& mesh = geometry.meshes.at(i); - if (_showTrueJointTransforms) { - for (int j = 0; j < mesh.clusters.size(); j++) { - const FBXCluster& cluster = mesh.clusters.at(j); - state.clusterMatrices[j] = - modelToWorld * _rig->getJointTransform(cluster.jointIndex) * cluster.inverseBindMatrix; - } - } else { - for (int j = 0; j < mesh.clusters.size(); j++) { - const FBXCluster& cluster = mesh.clusters.at(j); - state.clusterMatrices[j] = - modelToWorld * _rig->getJointVisibleTransform(cluster.jointIndex) * cluster.inverseBindMatrix; - } - } - } -} - void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { _rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation()); Model::updateRig(deltaTime, parentTransform); @@ -264,16 +241,6 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { } } -void SkeletonModel::updateJointState(int index) { - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; - - _rig->updateJointState(index, parentTransform); - - if (index == _geometry->getFBXGeometry().rootJointIndex) { - _rig->clearJointTransformTranslation(index); - } -} void SkeletonModel::renderJointConstraints(gpu::Batch& batch, int jointIndex) { if (jointIndex == -1 || jointIndex >= _rig->getJointStateCount()) { return; diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index a089c7b6ef..ecc5c80118 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -117,19 +117,6 @@ protected: void applyHandPosition(int jointIndex, const glm::vec3& position); void applyPalmData(int jointIndex, PalmData& palm); - - /// Updates the state of the joint at the specified index. - virtual void updateJointState(int index); - - void maybeUpdateLeanRotation(const JointState& parentState, int index); - void maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, int index); - void maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, int index); - - void updateClusterMatrices(); - void cauterizeHead(); - void initHeadBones(); - void invalidateHeadBones(); - private: void renderJointConstraints(gpu::Batch& batch, int jointIndex); diff --git a/libraries/animation/src/AvatarRig.cpp b/libraries/animation/src/AvatarRig.cpp index 3b48b0814f..919ea43e7d 100644 --- a/libraries/animation/src/AvatarRig.cpp +++ b/libraries/animation/src/AvatarRig.cpp @@ -23,6 +23,7 @@ void AvatarRig::updateJointState(int index, glm::mat4 parentTransform) { int parentIndex = joint.parentIndex; if (parentIndex == -1) { state.computeTransform(parentTransform); + clearJointTransformTranslation(index); } else { // guard against out-of-bounds access to _jointStates if (joint.parentIndex >= 0 && joint.parentIndex < _jointStates.size()) { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index ec423f7091..72bc818b70 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1375,7 +1375,7 @@ void Model::simulateInternal(float deltaTime) { } } } - + // post the blender if we're not currently waiting for one to finish if (geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { _blendedBlendshapeCoefficients = _blendshapeCoefficients; @@ -1383,12 +1383,6 @@ void Model::simulateInternal(float deltaTime) { } } -void Model::updateJointState(int index) { - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; - _rig->updateJointState(index, parentTransform); -} - bool Model::setJointPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation, bool useRotation, int lastFreeIndex, bool allIntermediatesFree, const glm::vec3& alignment, float priority) { const FBXGeometry& geometry = _geometry->getFBXGeometry(); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 449cd42a25..09504c7501 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -276,9 +276,6 @@ protected: void simulateInternal(float deltaTime); virtual void updateRig(float deltaTime, glm::mat4 parentTransform); - /// Updates the state of the joint at the specified index. - virtual void updateJointState(int index); - /// \param jointIndex index of joint in model structure /// \param position position of joint in model-frame /// \param rotation rotation of joint in model-frame From 14f4c9c6c04b462f177828717803f52256902887 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 30 Jul 2015 15:07:36 -0700 Subject: [PATCH 71/74] REmove more of the unnecessary GLBacken .h and GPUCOnfig.h include, The gpu::Context is now completely agnostic of the True Backend --- interface/src/Application.cpp | 5 ++-- interface/src/GLCanvas.h | 1 - libraries/gpu/src/gpu/Context.cpp | 17 ++++++----- libraries/gpu/src/gpu/Context.h | 28 +++++++++++++++---- libraries/gpu/src/gpu/GLBackend.cpp | 18 ++++++++---- libraries/gpu/src/gpu/GLBackend.h | 10 +++++-- .../render-utils/src/FramebufferCache.cpp | 1 - libraries/render/src/render/DrawStatus.cpp | 13 ++++----- libraries/render/src/render/DrawTask.cpp | 2 -- tests/render-utils/src/main.cpp | 4 +-- 10 files changed, 63 insertions(+), 36 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1c91f9282c..047596e40a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -772,8 +772,9 @@ void Application::initializeGL() { } #endif - // Where the gpuContext is created and where the TRUE Backend is created and assigned - _gpuContext = std::make_shared(new gpu::GLBackend()); + // Where the gpuContext is initialized and where the TRUE Backend is created and assigned + gpu::Context::init(); + _gpuContext = std::make_shared(); initDisplay(); qCDebug(interfaceapp, "Initialized Display."); diff --git a/interface/src/GLCanvas.h b/interface/src/GLCanvas.h index 925061edd0..6c53a17e04 100644 --- a/interface/src/GLCanvas.h +++ b/interface/src/GLCanvas.h @@ -13,7 +13,6 @@ #define hifi_GLCanvas_h #include -#include #include #include diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index 6730be33bb..239c460c77 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -10,13 +10,16 @@ // #include "Context.h" -// this include should disappear! as soon as the gpu::Context is in place -#include "GLBackend.h" - using namespace gpu; -Context::Context(Backend* backend) : - _backend(backend) { +Context::CreateBackend Context::_createBackendCallback = nullptr; +Context::MakeProgram Context::_makeProgramCallback = nullptr; +std::once_flag Context::_initialized; + +Context::Context() { + if (_createBackendCallback) { + _backend.reset(_createBackendCallback()); + } } Context::Context(const Context& context) { @@ -26,8 +29,8 @@ Context::~Context() { } bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings) { - if (shader.isProgram()) { - return GLBackend::makeProgram(shader, bindings); + if (shader.isProgram() && _makeProgramCallback) { + return _makeProgramCallback(shader, bindings); } return false; } diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index ab7a1d1c11..7158bd1a6d 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -12,6 +12,7 @@ #define hifi_gpu_Context_h #include +#include #include "Batch.h" @@ -26,13 +27,12 @@ namespace gpu { class Backend { public: - virtual~ Backend() {}; + virtual void render(Batch& batch) = 0; virtual void syncCache() = 0; virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) = 0; - class TransformObject { public: Mat4 _model; @@ -118,7 +118,21 @@ protected: class Context { public: - Context(Backend* backend); + typedef Backend* (*CreateBackend)(); + typedef bool (*MakeProgram)(Shader& shader, const Shader::BindingSet& bindings); + + + // This one call must happen before any context is created or used (Shader::MakeProgram) in order to setup the Backend and any singleton data needed + template + static void init() { + std::call_once(_initialized, [] { + _createBackendCallback = T::createBackend; + _makeProgramCallback = T::makeProgram; + T::init(); + }); + } + + Context(); ~Context(); void render(Batch& batch); @@ -132,13 +146,17 @@ public: protected: Context(const Context& context); + std::unique_ptr _backend; + // This function can only be called by "static Shader::makeProgram()" // makeProgramShader(...) make a program shader ready to be used in a Batch. // It compiles the sub shaders, link them and defines the Slots and their bindings. // If the shader passed is not a program, nothing happens. - static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet()); + static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings); - std::unique_ptr _backend; + static CreateBackend _createBackendCallback; + static MakeProgram _makeProgramCallback; + static std::once_flag _initialized; friend class Shader; }; diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index 198fe4802a..c74a94e03e 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -63,12 +63,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::GLBackend::do_glLineWidth), }; -GLBackend::GLBackend() : - _input(), - _transform(), - _pipeline(), - _output() -{ +void GLBackend::init() { static std::once_flag once; std::call_once(once, [] { qCDebug(gpulogging) << "GL Version: " << QString((const char*) glGetString(GL_VERSION)); @@ -108,7 +103,18 @@ GLBackend::GLBackend() : }*/ #endif }); +} +Backend* GLBackend::createBackend() { + return new GLBackend(); +} + +GLBackend::GLBackend() : + _input(), + _transform(), + _pipeline(), + _output() +{ initInput(); initTransform(); } diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 3686c5138d..e86424ceb7 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -22,10 +22,17 @@ namespace gpu { class GLBackend : public Backend { -public: + + // Context Backend static interface required + friend class Context; + static void init(); + static Backend* createBackend(); + static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet()); explicit GLBackend(bool syncCache); GLBackend(); +public: + virtual ~GLBackend(); virtual void render(Batch& batch); @@ -47,7 +54,6 @@ public: static void checkGLStackStable(std::function f); - static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet()); class GLBuffer : public GPUObject { diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index 601d99108d..d6ebd001d2 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include "RenderUtilsLogging.h" static QQueue _cachedFramebuffers; diff --git a/libraries/render/src/render/DrawStatus.cpp b/libraries/render/src/render/DrawStatus.cpp index f50f517d7d..cf3616a83a 100644 --- a/libraries/render/src/render/DrawStatus.cpp +++ b/libraries/render/src/render/DrawStatus.cpp @@ -18,10 +18,7 @@ #include #include -#include #include -#include -#include #include "drawItemBounds_vert.h" #include "drawItemBounds_frag.h" @@ -151,17 +148,17 @@ void DrawStatus::run(const SceneContextPointer& sceneContext, const RenderContex const unsigned int VEC3_ADRESS_OFFSET = 3; for (int i = 0; i < nbItems; i++) { - batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const GLfloat*) (itemAABox + i)); - batch._glUniform3fv(_drawItemBoundDimLoc, 1, ((const GLfloat*) (itemAABox + i)) + VEC3_ADRESS_OFFSET); + batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const float*) (itemAABox + i)); + batch._glUniform3fv(_drawItemBoundDimLoc, 1, ((const float*) (itemAABox + i)) + VEC3_ADRESS_OFFSET); batch.draw(gpu::LINES, 24, 0); } batch.setPipeline(getDrawItemStatusPipeline()); for (int i = 0; i < nbItems; i++) { - batch._glUniform3fv(_drawItemStatusPosLoc, 1, (const GLfloat*) (itemAABox + i)); - batch._glUniform3fv(_drawItemStatusDimLoc, 1, ((const GLfloat*) (itemAABox + i)) + VEC3_ADRESS_OFFSET); - batch._glUniform4iv(_drawItemStatusValueLoc, 1, (const GLint*) (itemStatus + i)); + batch._glUniform3fv(_drawItemStatusPosLoc, 1, (const float*) (itemAABox + i)); + batch._glUniform3fv(_drawItemStatusDimLoc, 1, ((const float*) (itemAABox + i)) + VEC3_ADRESS_OFFSET); + batch._glUniform4iv(_drawItemStatusValueLoc, 1, (const int*) (itemStatus + i)); batch.draw(gpu::TRIANGLES, 24, 0); } diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 1a3b68af03..36ff302952 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -17,9 +17,7 @@ #include #include #include -#include #include -#include using namespace render; diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index 7c02c7e8a7..9abd533650 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -94,7 +94,6 @@ class QTestWindow : public QWindow { QSize _size; //TextRenderer* _textRenderer[4]; RateCounter fps; - gpu::ContextPointer _gpuContext; protected: void renderText(); @@ -124,7 +123,8 @@ public: show(); makeCurrent(); - _gpuContext.reset(new gpu::Context(new gpu::GLBackend())); + + gpu::Context::init(); From e52bf2e12de0c1bd6f916a5df7606f3fda2c662f Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 30 Jul 2015 15:51:34 -0700 Subject: [PATCH 72/74] Fix for head cauterization. When rendering rigidly bound mesh clusters were not properly using the cauterization matrix set. --- libraries/render-utils/src/Model.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 72bc818b70..417a4bb16f 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1625,15 +1625,21 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran } if (isSkinned) { - const float* bones = (const float*)state.clusterMatrices.constData(); + const float* bones; if (_cauterizeBones) { bones = (const float*)state.cauterizedClusterMatrices.constData(); + } else { + bones = (const float*)state.clusterMatrices.constData(); } batch._glUniformMatrix4fv(locations->clusterMatrices, state.clusterMatrices.size(), false, bones); _transforms[0] = Transform(); _transforms[0].preTranslate(_translation); } else { - _transforms[0] = Transform(state.clusterMatrices[0]); + if (_cauterizeBones) { + _transforms[0] = Transform(state.cauterizedClusterMatrices[0]); + } else { + _transforms[0] = Transform(state.clusterMatrices[0]); + } _transforms[0].preTranslate(_translation); } batch.setModelTransform(_transforms[0]); From 78a900c8661a8565557af37f0726ddfbed76011a Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 30 Jul 2015 17:01:48 -0700 Subject: [PATCH 73/74] Prototype blend. Just equal weighting for now. --- libraries/animation/src/AnimationHandle.cpp | 4 +++- libraries/animation/src/AnimationHandle.h | 2 ++ libraries/animation/src/JointState.cpp | 5 +++-- libraries/animation/src/JointState.h | 2 +- libraries/animation/src/Rig.cpp | 7 +++++-- libraries/animation/src/Rig.h | 2 +- 6 files changed, 15 insertions(+), 7 deletions(-) diff --git a/libraries/animation/src/AnimationHandle.cpp b/libraries/animation/src/AnimationHandle.cpp index e8ac6e0a10..605fb25f1c 100644 --- a/libraries/animation/src/AnimationHandle.cpp +++ b/libraries/animation/src/AnimationHandle.cpp @@ -176,7 +176,9 @@ void AnimationHandle::applyFrame(float frameIndex) { safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction), - _priority); + _priority, + false, + _mix); } } } diff --git a/libraries/animation/src/AnimationHandle.h b/libraries/animation/src/AnimationHandle.h index 5d39682a0a..42e564944e 100644 --- a/libraries/animation/src/AnimationHandle.h +++ b/libraries/animation/src/AnimationHandle.h @@ -63,6 +63,7 @@ public: void setPriority(float priority); float getPriority() const { return _priority; } + void setMix(float mix) { _mix = mix; } void setMaskedJoints(const QStringList& maskedJoints); const QStringList& getMaskedJoints() const { return _maskedJoints; } @@ -119,6 +120,7 @@ private: QString _role; QUrl _url; float _priority; + float _mix; QStringList _maskedJoints; QVector _jointMappings; diff --git a/libraries/animation/src/JointState.cpp b/libraries/animation/src/JointState.cpp index 8f14342e80..3682837719 100644 --- a/libraries/animation/src/JointState.cpp +++ b/libraries/animation/src/JointState.cpp @@ -232,12 +232,13 @@ glm::quat JointState::computeVisibleParentRotation() const { return _visibleRotation * glm::inverse(_fbxJoint->preRotation * _visibleRotationInConstrainedFrame * _fbxJoint->postRotation); } -void JointState::setRotationInConstrainedFrame(glm::quat targetRotation, float priority, bool constrain) { +void JointState::setRotationInConstrainedFrame(glm::quat targetRotation, float priority, bool constrain, float mix) { if (priority >= _animationPriority || _animationPriority == 0.0f) { if (constrain && _constraint) { _constraint->softClamp(targetRotation, _rotationInConstrainedFrame, 0.5f); } - setRotationInConstrainedFrameInternal(targetRotation); + auto rotation = (mix == 1.0f) ? targetRotation : safeMix(getRotationInConstrainedFrame(), targetRotation, mix); + setRotationInConstrainedFrameInternal(rotation); _animationPriority = priority; } } diff --git a/libraries/animation/src/JointState.h b/libraries/animation/src/JointState.h index f15590e5f2..93bf83d2c4 100644 --- a/libraries/animation/src/JointState.h +++ b/libraries/animation/src/JointState.h @@ -84,7 +84,7 @@ public: /// NOTE: the JointState's model-frame transform/rotation are NOT updated! void setRotationInBindFrame(const glm::quat& rotation, float priority, bool constrain = false); - void setRotationInConstrainedFrame(glm::quat targetRotation, float priority, bool constrain = false); + void setRotationInConstrainedFrame(glm::quat targetRotation, float priority, bool constrain = false, float mix = 1.0f); void setVisibleRotationInConstrainedFrame(const glm::quat& targetRotation); const glm::quat& getRotationInConstrainedFrame() const { return _rotationInConstrainedFrame; } const glm::quat& getVisibleRotationInConstrainedFrame() const { return _visibleRotationInConstrainedFrame; } diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 15f3dd65ec..8406b61d12 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -390,7 +390,10 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos } void Rig::updateAnimations(float deltaTime, glm::mat4 parentTransform) { + int nAnimationsSoFar = 0; foreach (const AnimationHandlePointer& handle, _runningAnimations) { + handle->setMix(1.0f / ++nAnimationsSoFar); + handle->setPriority(1.0); handle->simulate(deltaTime); } @@ -640,13 +643,13 @@ glm::vec3 Rig::getJointDefaultTranslationInConstrainedFrame(int jointIndex) { return _jointStates[jointIndex].getDefaultTranslationInConstrainedFrame(); } -glm::quat Rig::setJointRotationInConstrainedFrame(int jointIndex, glm::quat targetRotation, float priority, bool constrain) { +glm::quat Rig::setJointRotationInConstrainedFrame(int jointIndex, glm::quat targetRotation, float priority, bool constrain, float mix) { glm::quat endRotation; if (jointIndex == -1 || _jointStates.isEmpty()) { return endRotation; } JointState& state = _jointStates[jointIndex]; - state.setRotationInConstrainedFrame(targetRotation, priority, constrain); + state.setRotationInConstrainedFrame(targetRotation, priority, constrain, mix); endRotation = state.getRotationInConstrainedFrame(); return endRotation; } diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 2af61bfded..52db16826a 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -139,7 +139,7 @@ public: glm::quat setJointRotationInBindFrame(int jointIndex, const glm::quat& rotation, float priority, bool constrain = false); glm::vec3 getJointDefaultTranslationInConstrainedFrame(int jointIndex); glm::quat setJointRotationInConstrainedFrame(int jointIndex, glm::quat targetRotation, - float priority, bool constrain = false); + float priority, bool constrain = false, float mix = 1.0f); glm::quat getJointDefaultRotationInParentFrame(int jointIndex); void updateVisibleJointStates(); From fbf21cb089a4579b507dee31110266f183429243 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 30 Jul 2015 18:27:47 -0700 Subject: [PATCH 74/74] FIxed the problem on Mac, by removing all of the gpuConfig includesgit status q :q wq --- libraries/gpu/src/gpu/GLBackend.h | 8 +++---- libraries/gpu/src/gpu/GLBackendShader.cpp | 22 +++++++++++++++++-- .../src/DeferredLightingEffect.cpp | 5 ----- libraries/render-utils/src/Model.cpp | 6 +---- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index e86424ceb7..c0bae76d78 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -27,7 +27,7 @@ class GLBackend : public Backend { friend class Context; static void init(); static Backend* createBackend(); - static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet()); + static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings); explicit GLBackend(bool syncCache); GLBackend(); @@ -95,9 +95,9 @@ public: #if (GPU_TRANSFORM_PROFILE == GPU_CORE) #else - GLuint _transformObject_model = -1; - GLuint _transformCamera_viewInverse = -1; - GLuint _transformCamera_viewport = -1; + GLint _transformObject_model = -1; + GLint _transformCamera_viewInverse = -1; + GLint _transformCamera_viewport = -1; #endif GLShader(); diff --git a/libraries/gpu/src/gpu/GLBackendShader.cpp b/libraries/gpu/src/gpu/GLBackendShader.cpp index 5fa0e277e5..9c0cf7628d 100755 --- a/libraries/gpu/src/gpu/GLBackendShader.cpp +++ b/libraries/gpu/src/gpu/GLBackendShader.cpp @@ -541,7 +541,12 @@ ElementResource getFormatFromGLUniform(GLenum gltype) { }; -int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers) { +int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, + Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers +#if (GPU_FEATURE_PROFILE == GPU_LEGACY) + , Shader::SlotSet& fakeBuffers +#endif +) { GLint uniformsCount = 0; #if (GPU_FEATURE_PROFILE == GPU_LEGACY) @@ -582,6 +587,15 @@ int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, S } if (elementResource._resource == Resource::BUFFER) { +#if (GPU_FEATURE_PROFILE == GPU_LEGACY) + // if in legacy profile, we fake the uniform buffer with an array + // this is where we detect it assuming it's explicitely assinged a binding + auto requestedBinding = slotBindings.find(std::string(sname)); + if (requestedBinding != slotBindings.end()) { + // found one buffer! + fakeBuffers.insert(Shader::Slot(sname, location, elementResource._element, elementResource._resource)); + } +#endif uniforms.insert(Shader::Slot(sname, location, elementResource._element, elementResource._resource)); } else { // For texture/Sampler, the location is the actual binding value @@ -736,8 +750,12 @@ bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindin Shader::SlotSet uniforms; Shader::SlotSet textures; Shader::SlotSet samplers; +#if (GPU_FEATURE_PROFILE == GPU_CORE) makeUniformSlots(object->_program, slotBindings, uniforms, textures, samplers); - +#else + makeUniformSlots(object->_program, slotBindings, uniforms, textures, samplers, buffers); +#endif + Shader::SlotSet inputs; makeInputSlots(object->_program, slotBindings, inputs); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 7563609026..3fc0a4c46a 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -614,13 +614,8 @@ void DeferredLightingEffect::loadLightProgram(const char* vertSource, const char locations.texcoordMat = program->getUniforms().findLocation("texcoordMat"); locations.coneParam = program->getUniforms().findLocation("coneParam"); -#if (GPU_FEATURE_PROFILE == GPU_CORE) locations.lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); locations.atmosphereBufferUnit = program->getBuffers().findLocation("atmosphereBufferUnit"); -#else - locations.lightBufferUnit = program->getUniforms().findLocation("lightBuffer"); - locations.atmosphereBufferUnit = program->getUniforms().findLocation("atmosphereBufferUnit"); -#endif auto state = std::make_shared(); if (lightVolume) { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 1e0e04c776..1e4f3f7190 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -187,13 +187,9 @@ void Model::RenderPipelineLib::initLocations(gpu::ShaderPointer& program, Model: locations.specularTextureUnit = program->getTextures().findLocation("specularMap"); locations.emissiveTextureUnit = program->getTextures().findLocation("emissiveMap"); -#if (GPU_FEATURE_PROFILE == GPU_CORE) locations.materialBufferUnit = program->getBuffers().findLocation("materialBuffer"); locations.lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); -#else - locations.materialBufferUnit = program->getUniforms().findLocation("materialBuffer"); - locations.lightBufferUnit = program->getUniforms().findLocation("lightBuffer"); -#endif + locations.clusterMatrices = program->getUniforms().findLocation("clusterMatrices"); locations.clusterIndices = program->getInputs().findLocation("clusterIndices");;