From 16bb861046681ed99fefdf2b2f421a65f52c980e Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 31 Dec 2015 15:52:28 -0800 Subject: [PATCH 001/215] Add render::Shape to abstract ModelRender --- libraries/render/src/render/Shape.cpp | 101 +++++++++++++++ libraries/render/src/render/Shape.h | 169 ++++++++++++++++++++++++++ 2 files changed, 270 insertions(+) create mode 100644 libraries/render/src/render/Shape.cpp create mode 100644 libraries/render/src/render/Shape.h diff --git a/libraries/render/src/render/Shape.cpp b/libraries/render/src/render/Shape.cpp new file mode 100644 index 0000000000..cbff84d068 --- /dev/null +++ b/libraries/render/src/render/Shape.cpp @@ -0,0 +1,101 @@ +// +// Shape.cpp +// render/src/render +// +// Created by Zach Pomerantz on 12/31/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 "Shape.h" + +#include + +using namespace render; + +Shape::PipelineLib _pipelineLip; + +const Shape::Pipeline& Shape::_pickPipeline(RenderArgs* args, const Key& key) { + assert(!_pipelineLib.empty()); + assert(args); + assert(args->_batch); + + PerformanceTimer perfTimer("Shape::getPipeline"); + + const auto& pipelineIterator = _pipelineLib.find(key); + if (pipelineIterator == _pipelineLib.end()) { + qDebug() << "Couldn't find a pipeline from ShapeKey ?" << key; + return Shape::Pipeline(); // uninitialized _pipeline == nullptr + } + + const auto& shapePipeline = pipelineIterator->second; + auto& batch = args->_batch; + + // Setup the one pipeline (to rule them all) + batch->setPipeline(shapePipeline.pipeline); + + return shapePipeline; +} + +void Shape::PipelineLib::addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader) { + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Shape::Slots::SKINNING_GPU)); + slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), Shape::Slots::MATERIAL_GPU)); + slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), Shape::Slots::DIFFUSE_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), Shape::Slots::NORMAL_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), Shape::Slots::SPECULAR_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), Shape::Slots::LIGHTMAP_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Shape::Slots::LIGHT_BUFFER)); + slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), Shape::Slots::NORMAL_FITTING_MAP)); + + gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader); + gpu::Shader::makeProgram(*program, slotBindings); + + auto locations = std::make_shared(); + locations->texcoordMatrices = program->getUniforms().findLocation("texcoordMatrices"); + locations->emissiveParams = program->getUniforms().findLocation("emissiveParams"); + locations->normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap"); + locations->diffuseTextureUnit = program->getTextures().findLocation("diffuseMap"); + locations->normalTextureUnit = program->getTextures().findLocation("normalMap"); + locations->specularTextureUnit = program->getTextures().findLocation("specularMap"); + locations->emissiveTextureUnit = program->getTextures().findLocation("emissiveMap"); + locations->skinClusterBufferUnit = program->getBuffers().findLocation("skinClusterBuffer"); + locations->materialBufferUnit = program->getBuffers().findLocation("materialBuffer"); + locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); + + auto state = std::make_shared(); + + // Backface on shadow + if (key.isShadow()) { + state->setCullMode(gpu::State::CULL_FRONT); + state->setDepthBias(1.0f); + state->setDepthBiasSlopeScale(4.0f); + } else { + state->setCullMode(gpu::State::CULL_BACK); + } + + // Z test depends on transparency + state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL); + + // Blend if transparent + state->setBlendFunction(key.isTranslucent(), + gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, // For transparent only, this keep the highlight intensity + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + // Add the brand new pipeline and cache its location in the lib + auto pipeline = gpu::Pipeline::create(program, state); + insert(value_type(key, Shape::Pipeline(pipeline, locations))); + + // Add a wireframe version + if (!key.isWireFrame()) { + ShapeKey wireframeKey(ShapeKey::Builder(key).withWireframe()); + + auto wireframeState = std::make_shared(state->getValues()); + wireframeState->setFillMode(gpu::State::FILL_LINE); + + auto wireframePipeline = gpu::Pipeline::create(program, wireframeState); + insert(value_type(wireframeKey, Shape::Pipeline(wireframePipeline, locations))); + } +} diff --git a/libraries/render/src/render/Shape.h b/libraries/render/src/render/Shape.h new file mode 100644 index 0000000000..cad4475da4 --- /dev/null +++ b/libraries/render/src/render/Shape.h @@ -0,0 +1,169 @@ +// +// Shape.h +// render/src/render +// +// Created by Zach Pomerantz on 12/31/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_render_Shape_h +#define hifi_render_Shape_h + +#include +#include + +namespace render { + +class ShapeKey { +public: + enum FlagBit { + TRANSLUCENT = 0, + LIGHTMAP, + TANGENTS, + SPECULAR, + EMISSIVE, + SKINNED, + STEREO, + DEPTH_ONLY, + SHADOW, + WIREFRAME, + + NUM_FLAGS, // Not a valid flag + }; + using Flags = std::bitset; + + Flags _flags; + + ShapeKey() : _flags{ 0 } {} + ShapeKey(const Flags& flags) : _flags(flags) {} + + class Builder { + friend class ShapeKey; + Flags _flags{ 0 }; + public: + Builder() {} + Builder(ShapeKey key) : _flags{ key._flags } {} + + ShapeKey build() const { return ShapeKey(_flags); } + + Builder& withTranslucent() { _flags.set(TRANSLUCENT); return (*this); } + Builder& withLightmap() { _flags.set(LIGHTMAP); return (*this); } + Builder& withTangents() { _flags.set(TANGENTS); return (*this); } + Builder& withSpecular() { _flags.set(SPECULAR); return (*this); } + Builder& withEmissive() { _flags.set(EMISSIVE); return (*this); } + Builder& withSkinned() { _flags.set(SKINNED); return (*this); } + Builder& withStereo() { _flags.set(STEREO); return (*this); } + Builder& withDepthOnly() { _flags.set(DEPTH_ONLY); return (*this); } + Builder& withShadow() { _flags.set(SHADOW); return (*this); } + Builder& withWireframe() { _flags.set(WIREFRAME); return (*this); } + }; + ShapeKey(const Builder& builder) : ShapeKey(builder._flags) {} + + bool hasLightmap() const { return _flags[LIGHTMAP]; } + bool hasTangents() const { return _flags[TANGENTS]; } + bool hasSpecular() const { return _flags[SPECULAR]; } + bool hasEmissive() const { return _flags[EMISSIVE]; } + bool isTranslucent() const { return _flags[TRANSLUCENT]; } + bool isSkinned() const { return _flags[SKINNED]; } + bool isStereo() const { return _flags[STEREO]; } + bool isDepthOnly() const { return _flags[DEPTH_ONLY]; } + bool isShadow() const { return _flags[SHADOW]; } + bool isWireFrame() const { return _flags[WIREFRAME]; } + + // Hasher for use in unordered_maps + class Hash { + public: + size_t operator() (const ShapeKey& key) { + return std::hash()(key._flags); + } + }; + + // Comparator for use in unordered_maps + class KeyEqual { + public: + bool operator()(const ShapeKey& lhs, const ShapeKey& rhs) const { return lhs._flags == rhs._flags; } + }; +}; + +inline QDebug operator<<(QDebug debug, const ShapeKey& renderKey) { + debug << "[ShapeKey:" + << "hasLightmap:" << renderKey.hasLightmap() + << "hasTangents:" << renderKey.hasTangents() + << "hasSpecular:" << renderKey.hasSpecular() + << "hasEmissive:" << renderKey.hasEmissive() + << "isTranslucent:" << renderKey.isTranslucent() + << "isSkinned:" << renderKey.isSkinned() + << "isStereo:" << renderKey.isStereo() + << "isDepthOnly:" << renderKey.isDepthOnly() + << "isShadow:" << renderKey.isShadow() + << "isWireFrame:" << renderKey.isWireFrame() + << "]"; + return debug; +} + +// Meta-information (pipeline and locations) to render a shape +class Shape { +public: + using Key = ShapeKey; + + class Slots { + public: + static const int SKINNING_GPU = 2; + static const int MATERIAL_GPU = 3; + static const int DIFFUSE_MAP = 0; + static const int NORMAL_MAP = 1; + static const int SPECULAR_MAP = 2; + static const int LIGHTMAP_MAP = 3; + static const int LIGHT_BUFFER = 4; + static const int NORMAL_FITTING_MAP = 10; + }; + + class Locations { + public: + int texcoordMatrices; + int diffuseTextureUnit; + int normalTextureUnit; + int specularTextureUnit; + int emissiveTextureUnit; + int emissiveParams; + int normalFittingMapUnit; + int skinClusterBufferUnit; + int materialBufferUnit; + int lightBufferUnit; + }; + + // Rendering abstraction over gpu::Pipeline and map locations + class Pipeline { + public: + gpu::PipelinePointer pipeline; + std::shared_ptr locations; + + Pipeline() : Pipeline(nullptr, nullptr) {} + Pipeline(gpu::PipelinePointer pipeline, std::shared_ptr locations) : + pipeline(pipeline), locations(locations) {} + }; + + using PipelineMap = std::unordered_map; + class PipelineLib : public PipelineMap { + public: + void addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader); + }; + + static void addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader) { + _pipelineLib.addPipeline(key, vertexShader, pixelShader); + } + virtual const Pipeline& pickPipeline(RenderArgs* args, const Key& key) { + return Shape::_pickPipeline(args, key); + } + +protected: + static const Pipeline& _pickPipeline(RenderArgs* args, const Key& key); + static PipelineLib _pipelineLib; +}; + +} + +#endif // hifi_render_Shape_h \ No newline at end of file From 59a354ea8ca2d28b1e9e276319ff82025920ec83 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Jan 2016 17:05:38 -0800 Subject: [PATCH 002/215] Change payload interface to return ShapeKey, not MaterialKey --- .../render-utils/src/MeshPartPayload.cpp | 237 ++++++++++-------- libraries/render-utils/src/MeshPartPayload.h | 6 +- libraries/render/src/render/Scene.h | 9 +- libraries/render/src/render/Shape.h | 37 +-- libraries/shared/src/RenderArgs.h | 6 + 5 files changed, 173 insertions(+), 122 deletions(-) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 414ad9cf97..a1e512bb24 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -14,30 +14,36 @@ #include #include "DeferredLightingEffect.h" - #include "Model.h" -namespace render { - template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) { - if (payload) { - return payload->getKey(); - } - // Return opaque for lack of a better idea - return ItemKey::Builder::opaqueShape(); - } +using namespace render; - template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) { - if (payload) { - return payload->getBound(); - } - return render::Item::Bound(); - } - template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args) { - return payload->render(args); +namespace render { +template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) { + if (payload) { + return payload->getKey(); } + return ItemKey::Builder::opaqueShape(); // for lack of a better idea } -using namespace render; +template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) { + if (payload) { + return payload->getBound(); + } + return Item::Bound(); +} + +template <> const ShapeKey shapeGetShapeKey(const MeshPartPayload::Pointer& payload) { + if (payload) { + return payload->getShapeKey(); + } + return ShapeKey::Builder::invalid(); +} + +template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args) { + return payload->render(args); +} +} MeshPartPayload::MeshPartPayload(model::MeshPointer mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform) { @@ -69,7 +75,7 @@ void MeshPartPayload::updateMaterial(model::MaterialPointer drawMaterial) { _drawMaterial = drawMaterial; } -render::ItemKey MeshPartPayload::getKey() const { +ItemKey MeshPartPayload::getKey() const { ItemKey::Builder builder; builder.withTypeShape(); @@ -83,10 +89,29 @@ render::ItemKey MeshPartPayload::getKey() const { return builder.build(); } -render::Item::Bound MeshPartPayload::getBound() const { +Item::Bound MeshPartPayload::getBound() const { return _worldBound; } +ShapeKey MeshPartPayload::getShapeKey() const { + model::MaterialKey drawMaterialKey; + if (_drawMaterial) { + drawMaterialKey = _drawMaterial->getKey(); + } + + bool isTranslucent = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap(); + bool hasTangents = drawMaterialKey.isNormalMap(); + bool hasSpecular = drawMaterialKey.isGlossMap(); + bool hasLightmap = drawMaterialKey.isLightmapMap(); + + ShapeKey::Builder builder; + if (isTranslucent) { builder.withTranslucent(); } + if (hasTangents) { builder.withTangents(); } + if (hasSpecular) { builder.withSpecular(); } + if (hasLightmap) { builder.withLightmap(); } + return builder.build(); +} + void MeshPartPayload::drawCall(gpu::Batch& batch) const { batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex); } @@ -195,27 +220,13 @@ void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locati void MeshPartPayload::render(RenderArgs* args) const { PerformanceTimer perfTimer("MeshPartPayload::render"); - gpu::Batch& batch = *(args->_batch); auto mode = args->_renderMode; - model::MaterialKey drawMaterialKey; - if (_drawMaterial) { - drawMaterialKey = _drawMaterial->getKey(); - } - bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap(); - - bool hasTangents = drawMaterialKey.isNormalMap(); - bool hasSpecular = drawMaterialKey.isGlossMap(); - bool hasLightmap = drawMaterialKey.isLightmapMap(); - bool isSkinned = false; - bool wireframe = false; - if (wireframe) { - translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false; - } + ShapeKey key = getShapeKey(); ModelRender::Locations* locations = nullptr; - ModelRender::pickPrograms(batch, mode, translucentMesh, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe, + ModelRender::pickPrograms(batch, mode, key.isTranslucent(), key.hasLightmap(), key.hasTangents(), key.hasSpecular(), key.isSkinned(), key.isWireFrame(), args, locations); @@ -230,7 +241,7 @@ void MeshPartPayload::render(RenderArgs* args) const { // TODO: We should be able to do that just in the renderTransparentJob - if (translucentMesh && locations->lightBufferUnit >= 0) { + if (key.isTranslucent() && locations->lightBufferUnit >= 0) { PerformanceTimer perfTimer("DLE->setupTransparent()"); DependencyManager::get()->setupTransparent(args, locations->lightBufferUnit); @@ -251,29 +262,32 @@ void MeshPartPayload::render(RenderArgs* args) const { } } - - namespace render { - template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload) { - if (payload) { - return payload->getKey(); - } - // Return opaque for lack of a better idea - return ItemKey::Builder::opaqueShape(); - } - - template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload) { - if (payload) { - return payload->getBound(); - } - return render::Item::Bound(); - } - template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args) { - return payload->render(args); +template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload) { + if (payload) { + return payload->getKey(); } + return ItemKey::Builder::opaqueShape(); // for lack of a better idea } -using namespace render; +template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload) { + if (payload) { + return payload->getBound(); + } + return Item::Bound(); +} + +template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload) { + if (payload) { + return payload->getShapeKey(); + } + return ShapeKey::Builder::invalid(); +} + +template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args) { + return payload->render(args); +} +} ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) : _model(model), @@ -310,7 +324,7 @@ void ModelMeshPartPayload::notifyLocationChanged() { _model->_needsUpdateClusterMatrices = true; } -render::ItemKey ModelMeshPartPayload::getKey() const { +ItemKey ModelMeshPartPayload::getKey() const { ItemKey::Builder builder; builder.withTypeShape(); @@ -332,12 +346,70 @@ render::ItemKey ModelMeshPartPayload::getKey() const { return builder.build(); } -render::Item::Bound ModelMeshPartPayload::getBound() const { +Item::Bound ModelMeshPartPayload::getBound() const { // NOTE: we can't cache this bounds because we need to handle the case of a moving // entity or mesh part. return _model->getPartBounds(_meshIndex, _partIndex, _transform.getTranslation(), _transform.getRotation()); } +ShapeKey ModelMeshPartPayload::getShapeKey() const { + const FBXGeometry& geometry = _model->_geometry->getFBXGeometry(); + const std::vector>& networkMeshes = _model->_geometry->getMeshes(); + + // guard against partially loaded meshes + if (_meshIndex >= (int)networkMeshes.size() || _meshIndex >= (int)geometry.meshes.size() || _meshIndex >= (int)_model->_meshStates.size()) { + return ShapeKey::Builder::invalid(); + } + + // Back to model to update the cluster matrices right now + _model->updateClusterMatrices(_transform.getTranslation(), _transform.getRotation()); + + const FBXMesh& mesh = geometry.meshes.at(_meshIndex); + + // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown + // to false to rebuild out mesh groups. + if (_meshIndex < 0 || _meshIndex >= (int)networkMeshes.size() || _meshIndex > geometry.meshes.size()) { + _model->_meshGroupsKnown = false; // regenerate these lists next time around. + _model->_readyWhenAdded = false; // in case any of our users are using scenes + _model->invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid + return ShapeKey::Builder::invalid(); + } + + + int vertexCount = mesh.vertices.size(); + if (vertexCount == 0) { + // sanity check + return ShapeKey::Builder::invalid(); + } + + + model::MaterialKey drawMaterialKey; + if (_drawMaterial) { + drawMaterialKey = _drawMaterial->getKey(); + } + + bool isTranslucent = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap(); + bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty(); + bool hasSpecular = drawMaterialKey.isGlossMap(); + bool hasLightmap = drawMaterialKey.isLightmapMap(); + + bool isSkinned = _isSkinned; + bool wireframe = _model->isWireframe(); + + if (wireframe) { + isTranslucent = hasTangents = hasSpecular = hasLightmap = isSkinned = false; + } + + ShapeKey::Builder builder; + if (isTranslucent) { builder.withTranslucent(); } + if (hasTangents) { builder.withTangents(); } + if (hasSpecular) { builder.withSpecular(); } + if (hasLightmap) { builder.withLightmap(); } + if (isSkinned) { builder.withSkinned(); } + if (wireframe) { builder.withWireframe(); } + return builder.build(); +} + void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) const { if (!_isBlendShaped) { batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0); @@ -387,6 +459,7 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::L void ModelMeshPartPayload::render(RenderArgs* args) const { PerformanceTimer perfTimer("ModelMeshPartPayload::render"); + if (!_model->_readyWhenAdded || !_model->_isVisible) { return; // bail asap } @@ -394,47 +467,11 @@ void ModelMeshPartPayload::render(RenderArgs* args) const { gpu::Batch& batch = *(args->_batch); auto mode = args->_renderMode; - const FBXGeometry& geometry = _model->_geometry->getFBXGeometry(); - const std::vector>& networkMeshes = _model->_geometry->getMeshes(); - - // guard against partially loaded meshes - if (_meshIndex >= (int)networkMeshes.size() || _meshIndex >= (int)geometry.meshes.size() || _meshIndex >= (int)_model->_meshStates.size() ) { + ShapeKey key = getShapeKey(); + if (!key.isValid()) { return; } - - // Back to model to update the cluster matrices right now - _model->updateClusterMatrices(_transform.getTranslation(), _transform.getRotation()); - - const FBXMesh& mesh = geometry.meshes.at(_meshIndex); - - // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown - // to false to rebuild out mesh groups. - if (_meshIndex < 0 || _meshIndex >= (int)networkMeshes.size() || _meshIndex > geometry.meshes.size()) { - _model->_meshGroupsKnown = false; // regenerate these lists next time around. - _model->_readyWhenAdded = false; // in case any of our users are using scenes - _model->invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid - return; // FIXME! - } - - - int vertexCount = mesh.vertices.size(); - if (vertexCount == 0) { - // sanity check - return; // FIXME! - } - model::MaterialKey drawMaterialKey; - if (_drawMaterial) { - drawMaterialKey = _drawMaterial->getKey(); - } - bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap(); - - bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty(); - bool hasSpecular = drawMaterialKey.isGlossMap(); - bool hasLightmap = drawMaterialKey.isLightmapMap(); - bool isSkinned = _isSkinned; - bool wireframe = _model->isWireframe(); - // render the part bounding box #ifdef DEBUG_BOUNDING_PARTS { @@ -458,12 +495,8 @@ void ModelMeshPartPayload::render(RenderArgs* args) const { } #endif //def DEBUG_BOUNDING_PARTS - if (wireframe) { - translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false; - } - ModelRender::Locations* locations = nullptr; - ModelRender::pickPrograms(batch, mode, translucentMesh, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe, + ModelRender::pickPrograms(batch, mode, key.isTranslucent(), key.hasLightmap(), key.hasTangents(), key.hasSpecular(), key.isSkinned(), key.isWireFrame(), args, locations); if (!locations) { // the pipeline could not be found @@ -481,7 +514,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) const { // TODO: We should be able to do that just in the renderTransparentJob - if (translucentMesh && locations->lightBufferUnit >= 0) { + if (key.isTranslucent() && locations->lightBufferUnit >= 0) { PerformanceTimer perfTimer("DLE->setupTransparent()"); DependencyManager::get()->setupTransparent(args, locations->lightBufferUnit); diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index e03d1c8a68..27312eb064 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -40,6 +40,7 @@ public: // Render Item interface virtual render::ItemKey getKey() const; virtual render::Item::Bound getBound() const; + virtual render::ShapeKey getShapeKey() const; // shape interface virtual void render(RenderArgs* args) const; // ModelMeshPartPayload functions to perform render @@ -67,10 +68,10 @@ public: namespace render { template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload); template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload); + template <> const ShapeKey shapeGetShapeKey(const MeshPartPayload::Pointer& payload); template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args); } - class ModelMeshPartPayload : public MeshPartPayload { public: ModelMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform); @@ -83,8 +84,9 @@ public: // Render Item interface render::ItemKey getKey() const override; render::Item::Bound getBound() const override; + render::ShapeKey getShapeKey() const override; // shape interface void render(RenderArgs* args) const override; - + // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch) const override; void bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const override; diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index 1976801c96..e71f088538 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -25,6 +25,7 @@ #include #include "model/Material.h" +#include "Shape.h" namespace render { @@ -264,7 +265,7 @@ public: virtual void render(RenderArgs* args) = 0; - virtual const model::MaterialKey getMaterialKey() const = 0; + virtual const ShapeKey getShapeKey() const = 0; ~PayloadInterface() {} @@ -304,7 +305,7 @@ public: void render(RenderArgs* args) { _payload->render(args); } // Shape Type Interface - const model::MaterialKey getMaterialKey() const { return _payload->getMaterialKey(); } + const ShapeKey getShapeKey() const { return _payload->getShapeKey(); } // Access the status const StatusPointer& getStatus() const { return _payload->getStatus(); } @@ -346,7 +347,7 @@ template int payloadGetLayer(const std::shared_ptr& payloadData) { template void payloadRender(const std::shared_ptr& payloadData, RenderArgs* args) { } // Shape type interface -template const model::MaterialKey shapeGetMaterialKey(const std::shared_ptr& payloadData) { return model::MaterialKey(); } +template const ShapeKey shapeGetShapeKey(const std::shared_ptr& payloadData) { return ShapeKey::Builder::invalid(); } template class Payload : public Item::PayloadInterface { public: @@ -364,7 +365,7 @@ public: virtual void render(RenderArgs* args) { payloadRender(_data, args); } // Shape Type interface - virtual const model::MaterialKey getMaterialKey() const { return shapeGetMaterialKey(_data); } + virtual const ShapeKey getShapeKey() const { return shapeGetShapeKey(_data); } protected: DataPointer _data; diff --git a/libraries/render/src/render/Shape.h b/libraries/render/src/render/Shape.h index cad4475da4..a4ae500bfc 100644 --- a/libraries/render/src/render/Shape.h +++ b/libraries/render/src/render/Shape.h @@ -31,6 +31,8 @@ public: SHADOW, WIREFRAME, + INVALID, + NUM_FLAGS, // Not a valid flag }; using Flags = std::bitset; @@ -59,6 +61,9 @@ public: Builder& withDepthOnly() { _flags.set(DEPTH_ONLY); return (*this); } Builder& withShadow() { _flags.set(SHADOW); return (*this); } Builder& withWireframe() { _flags.set(WIREFRAME); return (*this); } + Builder& invalidate() { _flags.set(INVALID); return (*this); } + + static const ShapeKey& invalid() { return Builder().invalidate(); } }; ShapeKey(const Builder& builder) : ShapeKey(builder._flags) {} @@ -72,6 +77,7 @@ public: bool isDepthOnly() const { return _flags[DEPTH_ONLY]; } bool isShadow() const { return _flags[SHADOW]; } bool isWireFrame() const { return _flags[WIREFRAME]; } + bool isValid() const { return !_flags[INVALID]; } // Hasher for use in unordered_maps class Hash { @@ -104,11 +110,9 @@ inline QDebug operator<<(QDebug debug, const ShapeKey& renderKey) { return debug; } -// Meta-information (pipeline and locations) to render a shape -class Shape { +// Rendering abstraction over gpu::Pipeline and map locations +class ShapePipeline { public: - using Key = ShapeKey; - class Slots { public: static const int SKINNING_GPU = 2; @@ -135,16 +139,21 @@ public: int lightBufferUnit; }; - // Rendering abstraction over gpu::Pipeline and map locations - class Pipeline { - public: - gpu::PipelinePointer pipeline; - std::shared_ptr locations; + gpu::PipelinePointer pipeline; + std::shared_ptr locations; - Pipeline() : Pipeline(nullptr, nullptr) {} - Pipeline(gpu::PipelinePointer pipeline, std::shared_ptr locations) : - pipeline(pipeline), locations(locations) {} - }; + ShapePipeline() : ShapePipeline(nullptr, nullptr) {} + ShapePipeline(gpu::PipelinePointer pipeline, std::shared_ptr locations) : + pipeline(pipeline), locations(locations) {} +}; + +// Meta-information (pipeline and locations) to render a shape +class Shape { +public: + using Key = ShapeKey; + using Pipeline = ShapePipeline; + using Slots = ShapePipeline::Slots; + using Locations = ShapePipeline::Locations; using PipelineMap = std::unordered_map; class PipelineLib : public PipelineMap { @@ -166,4 +175,4 @@ protected: } -#endif // hifi_render_Shape_h \ No newline at end of file +#endif // hifi_render_Shape_h diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index 640ccdcb1f..789033b826 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -20,6 +20,7 @@ class AABox; class OctreeRenderer; class ViewFrustum; + namespace gpu { class Batch; class Context; @@ -27,6 +28,10 @@ class Texture; class Framebuffer; } +namespace render { +class ShapePipeline; +} + class RenderDetails { public: enum Type { @@ -103,6 +108,7 @@ public: std::shared_ptr _context = nullptr; std::shared_ptr _blitFramebuffer = nullptr; + std::shared_ptr _pipeline = nullptr; OctreeRenderer* _renderer = nullptr; ViewFrustum* _viewFrustum = nullptr; glm::ivec4 _viewport{ 0, 0, 1, 1 }; From 1a3a9be605d497fae364ecd5ca1299a5f75f35d5 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Jan 2016 17:53:58 -0800 Subject: [PATCH 003/215] Use PipelinePointer for rendering Shape --- libraries/render/src/render/Scene.h | 3 +++ libraries/render/src/render/Shape.cpp | 8 ++++---- libraries/render/src/render/Shape.h | 5 +++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index e71f088538..1d8744c1a7 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -83,6 +83,9 @@ public: }; ItemKey(const Builder& builder) : ItemKey(builder._flags) {} + bool isShape() const { return _flags[TYPE_SHAPE]; } + bool isLight() const { return _flags[TYPE_LIGHT]; } + bool isOpaque() const { return !_flags[TRANSLUCENT]; } bool isTransparent() const { return _flags[TRANSLUCENT]; } diff --git a/libraries/render/src/render/Shape.cpp b/libraries/render/src/render/Shape.cpp index cbff84d068..79cb07ddf1 100644 --- a/libraries/render/src/render/Shape.cpp +++ b/libraries/render/src/render/Shape.cpp @@ -17,7 +17,7 @@ using namespace render; Shape::PipelineLib _pipelineLip; -const Shape::Pipeline& Shape::_pickPipeline(RenderArgs* args, const Key& key) { +const Shape::PipelinePointer& Shape::_pickPipeline(RenderArgs* args, const Key& key) { assert(!_pipelineLib.empty()); assert(args); assert(args->_batch); @@ -27,14 +27,14 @@ const Shape::Pipeline& Shape::_pickPipeline(RenderArgs* args, const Key& key) { const auto& pipelineIterator = _pipelineLib.find(key); if (pipelineIterator == _pipelineLib.end()) { qDebug() << "Couldn't find a pipeline from ShapeKey ?" << key; - return Shape::Pipeline(); // uninitialized _pipeline == nullptr + return std::make_shared(); } - const auto& shapePipeline = pipelineIterator->second; + Shape::PipelinePointer shapePipeline(&(pipelineIterator->second)); auto& batch = args->_batch; // Setup the one pipeline (to rule them all) - batch->setPipeline(shapePipeline.pipeline); + batch->setPipeline(shapePipeline->pipeline); return shapePipeline; } diff --git a/libraries/render/src/render/Shape.h b/libraries/render/src/render/Shape.h index a4ae500bfc..590075ccca 100644 --- a/libraries/render/src/render/Shape.h +++ b/libraries/render/src/render/Shape.h @@ -152,6 +152,7 @@ class Shape { public: using Key = ShapeKey; using Pipeline = ShapePipeline; + using PipelinePointer = std::shared_ptr; using Slots = ShapePipeline::Slots; using Locations = ShapePipeline::Locations; @@ -164,12 +165,12 @@ public: static void addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader) { _pipelineLib.addPipeline(key, vertexShader, pixelShader); } - virtual const Pipeline& pickPipeline(RenderArgs* args, const Key& key) { + virtual const PipelinePointer& pickPipeline(RenderArgs* args, const Key& key) { return Shape::_pickPipeline(args, key); } protected: - static const Pipeline& _pickPipeline(RenderArgs* args, const Key& key); + static const PipelinePointer& _pickPipeline(RenderArgs* args, const Key& key); static PipelineLib _pipelineLib; }; From 74c49300342f16316d3545c1dc6311e583c06392 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Jan 2016 17:57:37 -0800 Subject: [PATCH 004/215] Remove DrawBackround task --- libraries/render/src/render/DrawTask.cpp | 34 ------------------------ libraries/render/src/render/DrawTask.h | 9 ------- 2 files changed, 43 deletions(-) diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 44ba57143f..e6a3e024ad 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -264,40 +264,6 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext args->_batch = nullptr; } -void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - assert(renderContext->getArgs()); - assert(renderContext->getArgs()->_viewFrustum); - - // render backgrounds - auto& scene = sceneContext->_scene; - auto& items = scene->getMasterBucket().at(ItemFilter::Builder::background()); - - - ItemIDsBounds inItems; - inItems.reserve(items.size()); - for (auto id : items) { - inItems.emplace_back(id); - } - RenderArgs* args = renderContext->getArgs(); - doInBatch(args->_context, [=](gpu::Batch& batch) { - args->_batch = &batch; - batch.enableSkybox(true); - batch.setViewportTransform(args->_viewport); - batch.setStateScissorRect(args->_viewport); - - glm::mat4 projMat; - Transform viewMat; - args->_viewFrustum->evalProjectionMatrix(projMat); - args->_viewFrustum->evalViewTransform(viewMat); - - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat); - - renderItems(sceneContext, renderContext, inItems); - }); - args->_batch = nullptr; -} - void ItemMaterialBucketMap::insert(const ItemID& id, const model::MaterialKey& key) { // Insert the itemID in every bucket where it filters true for (auto& bucket : (*this)) { diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index ab102e32a7..b06223035d 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -275,15 +275,6 @@ public: typedef Job::Model JobModel; }; -class DrawBackground { -public: - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); - - - typedef Job::Model JobModel; -}; - - class DrawSceneTask : public Task { public: From e96b1fa881ba116bf7f17666bd13bcb8dfe80e1f Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 4 Jan 2016 10:48:33 -0800 Subject: [PATCH 005/215] Return copies of local vars in Shape --- libraries/render/src/render/Shape.cpp | 2 +- libraries/render/src/render/Shape.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/render/src/render/Shape.cpp b/libraries/render/src/render/Shape.cpp index 79cb07ddf1..a6b8e09126 100644 --- a/libraries/render/src/render/Shape.cpp +++ b/libraries/render/src/render/Shape.cpp @@ -17,7 +17,7 @@ using namespace render; Shape::PipelineLib _pipelineLip; -const Shape::PipelinePointer& Shape::_pickPipeline(RenderArgs* args, const Key& key) { +const Shape::PipelinePointer Shape::_pickPipeline(RenderArgs* args, const Key& key) { assert(!_pipelineLib.empty()); assert(args); assert(args->_batch); diff --git a/libraries/render/src/render/Shape.h b/libraries/render/src/render/Shape.h index 590075ccca..f8b2f77b5a 100644 --- a/libraries/render/src/render/Shape.h +++ b/libraries/render/src/render/Shape.h @@ -63,7 +63,7 @@ public: Builder& withWireframe() { _flags.set(WIREFRAME); return (*this); } Builder& invalidate() { _flags.set(INVALID); return (*this); } - static const ShapeKey& invalid() { return Builder().invalidate(); } + static const ShapeKey invalid() { return Builder().invalidate(); } }; ShapeKey(const Builder& builder) : ShapeKey(builder._flags) {} @@ -165,12 +165,12 @@ public: static void addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader) { _pipelineLib.addPipeline(key, vertexShader, pixelShader); } - virtual const PipelinePointer& pickPipeline(RenderArgs* args, const Key& key) { + virtual const PipelinePointer pickPipeline(RenderArgs* args, const Key& key) { return Shape::_pickPipeline(args, key); } protected: - static const PipelinePointer& _pickPipeline(RenderArgs* args, const Key& key); + static const PipelinePointer _pickPipeline(RenderArgs* args, const Key& key); static PipelineLib _pipelineLib; }; From c0800abdc5180e03fd4f035c48d98ad2d3978757 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 4 Jan 2016 12:23:06 -0800 Subject: [PATCH 006/215] Add virtual ~Shape --- libraries/render/src/render/Shape.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/render/src/render/Shape.h b/libraries/render/src/render/Shape.h index f8b2f77b5a..c3bf06f0ee 100644 --- a/libraries/render/src/render/Shape.h +++ b/libraries/render/src/render/Shape.h @@ -169,6 +169,8 @@ public: return Shape::_pickPipeline(args, key); } + virtual ~Shape() {}; + protected: static const PipelinePointer _pickPipeline(RenderArgs* args, const Key& key); static PipelineLib _pipelineLib; From c725fd1520d0a0c93e8980e309adc2d030740317 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 4 Jan 2016 12:33:06 -0800 Subject: [PATCH 007/215] Add specialized ShapeRender for deferred --- libraries/render-utils/src/ShapeRender.cpp | 195 +++++++++++++++++++++ libraries/render-utils/src/ShapeRender.h | 28 +++ 2 files changed, 223 insertions(+) create mode 100644 libraries/render-utils/src/ShapeRender.cpp create mode 100644 libraries/render-utils/src/ShapeRender.h diff --git a/libraries/render-utils/src/ShapeRender.cpp b/libraries/render-utils/src/ShapeRender.cpp new file mode 100644 index 0000000000..31db3b010e --- /dev/null +++ b/libraries/render-utils/src/ShapeRender.cpp @@ -0,0 +1,195 @@ +// +// ModelRender.cpp +// interface/src/renderer +// +// Created by Sam Gateau on 10/3/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 "ShapeRender.h" + +#include + +#include + +#include "DeferredLightingEffect.h" + +#include "model_vert.h" +#include "model_shadow_vert.h" +#include "model_normal_map_vert.h" +#include "model_lightmap_vert.h" +#include "model_lightmap_normal_map_vert.h" +#include "skin_model_vert.h" +#include "skin_model_shadow_vert.h" +#include "skin_model_normal_map_vert.h" + +#include "model_frag.h" +#include "model_shadow_frag.h" +#include "model_normal_map_frag.h" +#include "model_normal_specular_map_frag.h" +#include "model_specular_map_frag.h" +#include "model_lightmap_frag.h" +#include "model_lightmap_normal_map_frag.h" +#include "model_lightmap_normal_specular_map_frag.h" +#include "model_lightmap_specular_map_frag.h" +#include "model_translucent_frag.h" + +void ShapeRender::initPipeline() { + assert(_pipelineLib.empty()); + + // Vertex shaders + auto modelVertex = gpu::Shader::createVertex(std::string(model_vert)); + auto modelNormalMapVertex = gpu::Shader::createVertex(std::string(model_normal_map_vert)); + auto modelLightmapVertex = gpu::Shader::createVertex(std::string(model_lightmap_vert)); + auto modelLightmapNormalMapVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert)); + auto modelShadowVertex = gpu::Shader::createVertex(std::string(model_shadow_vert)); + auto skinModelVertex = gpu::Shader::createVertex(std::string(skin_model_vert)); + auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert)); + auto skinModelShadowVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert)); + + // Pixel shaders + auto modelPixel = gpu::Shader::createPixel(std::string(model_frag)); + auto modelNormalMapPixel = gpu::Shader::createPixel(std::string(model_normal_map_frag)); + auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(model_specular_map_frag)); + auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_frag)); + auto modelTranslucentPixel = gpu::Shader::createPixel(std::string(model_translucent_frag)); + auto modelShadowPixel = gpu::Shader::createPixel(std::string(model_shadow_frag)); + auto modelLightmapPixel = gpu::Shader::createPixel(std::string(model_lightmap_frag)); + auto modelLightmapNormalMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag)); + auto modelLightmapSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag)); + auto modelLightmapNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag)); + + // Fill the pipelineLib + + _pipelineLib.addPipeline( + RenderKey(0), + modelVertex, modelPixel); + + _pipelineLib.addPipeline( + RenderKey(RenderKey::HAS_TANGENTS), + modelNormalMapVertex, modelNormalMapPixel); + + _pipelineLib.addPipeline( + RenderKey(RenderKey::HAS_SPECULAR), + modelVertex, modelSpecularMapPixel); + + _pipelineLib.addPipeline( + RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), + modelNormalMapVertex, modelNormalSpecularMapPixel); + + + _pipelineLib.addPipeline( + RenderKey(RenderKey::IS_TRANSLUCENT), + modelVertex, modelTranslucentPixel); + // FIXME Ignore lightmap for translucents meshpart + _pipelineLib.addPipeline( + RenderKey(RenderKey::IS_TRANSLUCENT | RenderKey::HAS_LIGHTMAP), + modelVertex, modelTranslucentPixel); + + _pipelineLib.addPipeline( + RenderKey(RenderKey::HAS_TANGENTS | RenderKey::IS_TRANSLUCENT), + modelNormalMapVertex, modelTranslucentPixel); + + _pipelineLib.addPipeline( + RenderKey(RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), + modelVertex, modelTranslucentPixel); + + _pipelineLib.addPipeline( + RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), + modelNormalMapVertex, modelTranslucentPixel); + + + _pipelineLib.addPipeline( + RenderKey(RenderKey::HAS_LIGHTMAP), + modelLightmapVertex, modelLightmapPixel); + _pipelineLib.addPipeline( + RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_TANGENTS), + modelLightmapNormalMapVertex, modelLightmapNormalMapPixel); + + _pipelineLib.addPipeline( + RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_SPECULAR), + modelLightmapVertex, modelLightmapSpecularMapPixel); + + _pipelineLib.addPipeline( + RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), + modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel); + + + _pipelineLib.addPipeline( + RenderKey(RenderKey::IS_SKINNED), + skinModelVertex, modelPixel); + + _pipelineLib.addPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS), + skinModelNormalMapVertex, modelNormalMapPixel); + + _pipelineLib.addPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_SPECULAR), + skinModelVertex, modelSpecularMapPixel); + + _pipelineLib.addPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), + skinModelNormalMapVertex, modelNormalSpecularMapPixel); + + + _pipelineLib.addPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::IS_TRANSLUCENT), + skinModelVertex, modelTranslucentPixel); + + _pipelineLib.addPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::IS_TRANSLUCENT), + skinModelNormalMapVertex, modelTranslucentPixel); + + _pipelineLib.addPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), + skinModelVertex, modelTranslucentPixel); + + _pipelineLib.addPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), + skinModelNormalMapVertex, modelTranslucentPixel); + + + _pipelineLib.addPipeline( + RenderKey(RenderKey::IS_DEPTH_ONLY | RenderKey::IS_SHADOW), + modelShadowVertex, modelShadowPixel); + + + _pipelineLib.addPipeline( + RenderKey(RenderKey::IS_SKINNED | RenderKey::IS_DEPTH_ONLY | RenderKey::IS_SHADOW), + skinModelShadowVertex, modelShadowPixel); +} + +const render::PipelinePointer ShapeRender::pickPipeline(RenderArgs* args, Key& key) { + PerformanceTimer perfTimer("ShapeRender::pickPipeline"); + // TODO: There is probably a cleaner way to init the pipeline that in a derived class + if (_pipelineLib.empty()) { + initPipeline(); + } + + auto pipeline = _pickPipeline(args, key); + if (!pipeline) { + return pipeline; + } + + if ((pipeline->locations->normalFittingMapUnit > -1)) { + batch.setResourceTexture(pipeline->locations->normalFittingMapUnit, + DependencyManager::get()->getNormalFittingTexture()); + } +} + +model::MaterialPointer ShapeRender::_collisionHullMaterial; + +model::MaterialPointer ShapeRender::getCollisionHullMaterial() { + if (!_collisionHullMaterial) { + _collisionHullMaterial = std::make_shared(); + _collisionHullMaterial->setDiffuse(glm::vec3(1.0f, 0.5f, 0.0f)); + _collisionHullMaterial->setMetallic(0.02f); + _collisionHullMaterial->setGloss(1.0f); + } + + return _collisionHullMaterial; +} + diff --git a/libraries/render-utils/src/ShapeRender.h b/libraries/render-utils/src/ShapeRender.h new file mode 100644 index 0000000000..047f300dc0 --- /dev/null +++ b/libraries/render-utils/src/ShapeRender.h @@ -0,0 +1,28 @@ +// +// ModelRender.h +// render-utils/src +// +// Created by Zach Pomerantz on 1/4/2015. +// 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_render_utils_Shape_h +#define hifi_render_utils_Shape_h + +#include + +class ShapeRender : public render::Shape { + static model::MaterialPointer _collisionHullMaterial; + +public: + static void initPipeline(); + const render::PipelinePointer pickPipeline(RenderArgs* args, Key& key) override; + + static model::MaterialPointer getCollisionHullMaterial(); +}; + +#endif // hifi_render_utils_Shape_h + From 7913ca7f3b45812d0ea8ddbbc8e0d23b89921775 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 4 Jan 2016 12:33:38 -0800 Subject: [PATCH 008/215] Render using ShapeRender, pickPipeline in renderItems --- .../render-utils/src/MeshPartPayload.cpp | 51 ++-- libraries/render-utils/src/MeshPartPayload.h | 8 +- libraries/render-utils/src/ModelRender.cpp | 284 ------------------ libraries/render-utils/src/ModelRender.h | 157 ---------- .../render-utils/src/RenderDeferredTask.cpp | 9 +- .../render-utils/src/RenderDeferredTask.h | 7 +- libraries/render-utils/src/ShapeRender.cpp | 6 +- libraries/render-utils/src/ShapeRender.h | 2 +- libraries/render/src/render/DrawTask.cpp | 22 +- libraries/render/src/render/DrawTask.h | 4 +- 10 files changed, 57 insertions(+), 493 deletions(-) delete mode 100644 libraries/render-utils/src/ModelRender.cpp delete mode 100644 libraries/render-utils/src/ModelRender.h diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index a1e512bb24..f50deb0e43 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -129,14 +129,14 @@ void MeshPartPayload::bindMesh(gpu::Batch& batch) const { } } -void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const { +void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locations* locations) const { if (!_drawMaterial) { return; } auto textureCache = DependencyManager::get(); - batch.setUniformBuffer(ModelRender::MATERIAL_GPU_SLOT, _drawMaterial->getSchemaBuffer()); + batch.setUniformBuffer(ShapePipeline::Slots::MATERIAL_GPU, _drawMaterial->getSchemaBuffer()); auto materialKey = _drawMaterial->getKey(); auto textureMaps = _drawMaterial->getTextureMaps(); @@ -146,44 +146,44 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locatio if (materialKey.isDiffuseMap()) { auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP]; if (diffuseMap && diffuseMap->isDefined()) { - batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, diffuseMap->getTextureView()); + batch.setResourceTexture(ShapePipeline::Slots::DIFFUSE_MAP, diffuseMap->getTextureView()); if (!diffuseMap->getTextureTransform().isIdentity()) { diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]); } } else { - batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, textureCache->getGrayTexture()); + batch.setResourceTexture(ShapePipeline::Slots::DIFFUSE_MAP, textureCache->getGrayTexture()); } } else { - batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, textureCache->getWhiteTexture()); + batch.setResourceTexture(ShapePipeline::Slots::DIFFUSE_MAP, textureCache->getWhiteTexture()); } // Normal map if (materialKey.isNormalMap()) { auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP]; if (normalMap && normalMap->isDefined()) { - batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, normalMap->getTextureView()); + batch.setResourceTexture(ShapePipeline::Slots::::NORMAL_MAP, normalMap->getTextureView()); // texcoord are assumed to be the same has diffuse } else { - batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, textureCache->getBlueTexture()); + batch.setResourceTexture(ShapePipeline::Slots::NORMAL_MAP, textureCache->getBlueTexture()); } } else { - batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, nullptr); + batch.setResourceTexture(ShapePipeline::Slots::NORMAL_MAP, nullptr); } // TODO: For now gloss map is used as the "specular map in the shading, we ll need to fix that if (materialKey.isGlossMap()) { auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP]; if (specularMap && specularMap->isDefined()) { - batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, specularMap->getTextureView()); + batch.setResourceTexture(ShapePipeline::Slots::SPECULAR_MAP, specularMap->getTextureView()); // texcoord are assumed to be the same has diffuse } else { - batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, textureCache->getBlackTexture()); + batch.setResourceTexture(ShapePipeline::Slots::SPECULAR_MAP, textureCache->getBlackTexture()); } } else { - batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, nullptr); + batch.setResourceTexture(ShapePipeline::SPECULAR_MAP, nullptr); } // TODO: For now lightmaop is piped into the emissive map unit, we need to fix that and support for real emissive too @@ -191,7 +191,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locatio auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP]; if (lightmapMap && lightmapMap->isDefined()) { - batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, lightmapMap->getTextureView()); + batch.setResourceTexture(ShapePipeline::LIGHTMAP_MAP, lightmapMap->getTextureView()); auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale(); batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y); @@ -200,10 +200,10 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locatio lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]); } } else { - batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, textureCache->getGrayTexture()); + batch.setResourceTexture(ShapePipeline::LIGHTMAP_MAP, textureCache->getGrayTexture()); } } else { - batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, nullptr); + batch.setResourceTexture(ShapePipeline::LIGHTMAP_MAP, nullptr); } // Texcoord transforms ? @@ -212,7 +212,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locatio } } -void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const { +void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::Locations* locations) const { batch.setModelTransform(_drawTransform); } @@ -225,10 +225,8 @@ void MeshPartPayload::render(RenderArgs* args) const { ShapeKey key = getShapeKey(); - ModelRender::Locations* locations = nullptr; - ModelRender::pickPrograms(batch, mode, key.isTranslucent(), key.hasLightmap(), key.hasTangents(), key.hasSpecular(), key.isSkinned(), key.isWireFrame(), - args, locations); - + auto locations = args->_pipeline->locations; + assert(locations); // Bind the model transform and the skinCLusterMatrices if needed bindTransform(batch, locations); @@ -433,16 +431,16 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) const { } } -void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const { +void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::Locations* locations) const { // Still relying on the raw data from the model const Model::MeshState& state = _model->_meshStates.at(_meshIndex); Transform transform; if (state.clusterBuffer) { if (_model->_cauterizeBones) { - batch.setUniformBuffer(ModelRender::SKINNING_GPU_SLOT, state.cauterizedClusterBuffer); + batch.setUniformBuffer(ShapePipeline::SKINNING_GPU, state.cauterizedClusterBuffer); } else { - batch.setUniformBuffer(ModelRender::SKINNING_GPU_SLOT, state.clusterBuffer); + batch.setUniformBuffer(ShapePipeline::SKINNING_GPU, state.clusterBuffer); } } else { if (_model->_cauterizeBones) { @@ -495,13 +493,8 @@ void ModelMeshPartPayload::render(RenderArgs* args) const { } #endif //def DEBUG_BOUNDING_PARTS - ModelRender::Locations* locations = nullptr; - ModelRender::pickPrograms(batch, mode, key.isTranslucent(), key.hasLightmap(), key.hasTangents(), key.hasSpecular(), key.isSkinned(), key.isWireFrame(), - args, locations); - - if (!locations) { // the pipeline could not be found - return; - } + auto locations = args->_pipeline->locations; + assert(locations); // Bind the model transform and the skinCLusterMatrices if needed bindTransform(batch, locations); diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 27312eb064..cb7e1fd386 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -18,7 +18,7 @@ #include -#include "ModelRender.h" +#include "ShapeRender.h" class Model; @@ -46,8 +46,8 @@ public: // ModelMeshPartPayload functions to perform render void drawCall(gpu::Batch& batch) const; virtual void bindMesh(gpu::Batch& batch) const; - virtual void bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const; - virtual void bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const; + virtual void bindMaterial(gpu::Batch& batch, const render::ShapePipeline::Locations* locations) const; + virtual void bindTransform(gpu::Batch& batch, const render::ShapePipeline::Locations* locations) const; // Payload resource cached values model::MeshPointer _drawMesh; @@ -89,7 +89,7 @@ public: // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch) const override; - void bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const override; + void bindTransform(gpu::Batch& batch, const render::ShapePipeline::Locations* locations) const override; void initCache(); diff --git a/libraries/render-utils/src/ModelRender.cpp b/libraries/render-utils/src/ModelRender.cpp deleted file mode 100644 index 312d34e41b..0000000000 --- a/libraries/render-utils/src/ModelRender.cpp +++ /dev/null @@ -1,284 +0,0 @@ -// -// ModelRender.cpp -// interface/src/renderer -// -// Created by Sam Gateau on 10/3/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 "ModelRender.h" - -#include - -#include - -#include "DeferredLightingEffect.h" - -#include "model_vert.h" -#include "model_shadow_vert.h" -#include "model_normal_map_vert.h" -#include "model_lightmap_vert.h" -#include "model_lightmap_normal_map_vert.h" -#include "skin_model_vert.h" -#include "skin_model_shadow_vert.h" -#include "skin_model_normal_map_vert.h" - -#include "model_frag.h" -#include "model_shadow_frag.h" -#include "model_normal_map_frag.h" -#include "model_normal_specular_map_frag.h" -#include "model_specular_map_frag.h" -#include "model_lightmap_frag.h" -#include "model_lightmap_normal_map_frag.h" -#include "model_lightmap_normal_specular_map_frag.h" -#include "model_lightmap_specular_map_frag.h" -#include "model_translucent_frag.h" - -ModelRender::RenderPipelineLib ModelRender::_renderPipelineLib; - -const ModelRender::RenderPipelineLib& ModelRender::getRenderPipelineLib() { - if (_renderPipelineLib.empty()) { - // Vertex shaders - auto modelVertex = gpu::Shader::createVertex(std::string(model_vert)); - auto modelNormalMapVertex = gpu::Shader::createVertex(std::string(model_normal_map_vert)); - auto modelLightmapVertex = gpu::Shader::createVertex(std::string(model_lightmap_vert)); - auto modelLightmapNormalMapVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert)); - auto modelShadowVertex = gpu::Shader::createVertex(std::string(model_shadow_vert)); - auto skinModelVertex = gpu::Shader::createVertex(std::string(skin_model_vert)); - auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert)); - auto skinModelShadowVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert)); - - // Pixel shaders - auto modelPixel = gpu::Shader::createPixel(std::string(model_frag)); - auto modelNormalMapPixel = gpu::Shader::createPixel(std::string(model_normal_map_frag)); - auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(model_specular_map_frag)); - auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_frag)); - auto modelTranslucentPixel = gpu::Shader::createPixel(std::string(model_translucent_frag)); - auto modelShadowPixel = gpu::Shader::createPixel(std::string(model_shadow_frag)); - auto modelLightmapPixel = gpu::Shader::createPixel(std::string(model_lightmap_frag)); - auto modelLightmapNormalMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag)); - auto modelLightmapSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag)); - auto modelLightmapNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag)); - - // Fill the renderPipelineLib - - _renderPipelineLib.addRenderPipeline( - RenderKey(0), - modelVertex, modelPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::HAS_TANGENTS), - modelNormalMapVertex, modelNormalMapPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::HAS_SPECULAR), - modelVertex, modelSpecularMapPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), - modelNormalMapVertex, modelNormalSpecularMapPixel); - - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_TRANSLUCENT), - modelVertex, modelTranslucentPixel); - // FIXME Ignore lightmap for translucents meshpart - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_TRANSLUCENT | RenderKey::HAS_LIGHTMAP), - modelVertex, modelTranslucentPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::HAS_TANGENTS | RenderKey::IS_TRANSLUCENT), - modelNormalMapVertex, modelTranslucentPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), - modelVertex, modelTranslucentPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), - modelNormalMapVertex, modelTranslucentPixel); - - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::HAS_LIGHTMAP), - modelLightmapVertex, modelLightmapPixel); - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_TANGENTS), - modelLightmapNormalMapVertex, modelLightmapNormalMapPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_SPECULAR), - modelLightmapVertex, modelLightmapSpecularMapPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), - modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel); - - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_SKINNED), - skinModelVertex, modelPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS), - skinModelNormalMapVertex, modelNormalMapPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_SPECULAR), - skinModelVertex, modelSpecularMapPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), - skinModelNormalMapVertex, modelNormalSpecularMapPixel); - - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::IS_TRANSLUCENT), - skinModelVertex, modelTranslucentPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::IS_TRANSLUCENT), - skinModelNormalMapVertex, modelTranslucentPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), - skinModelVertex, modelTranslucentPixel); - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), - skinModelNormalMapVertex, modelTranslucentPixel); - - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_DEPTH_ONLY | RenderKey::IS_SHADOW), - modelShadowVertex, modelShadowPixel); - - - _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::IS_DEPTH_ONLY | RenderKey::IS_SHADOW), - skinModelShadowVertex, modelShadowPixel); - } - - return _renderPipelineLib; -} - - -void ModelRender::RenderPipelineLib::addRenderPipeline(ModelRender::RenderKey key, - gpu::ShaderPointer& vertexShader, - gpu::ShaderPointer& pixelShader) { - - gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), ModelRender::SKINNING_GPU_SLOT)); - slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), ModelRender::MATERIAL_GPU_SLOT)); - slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), ModelRender::DIFFUSE_MAP_SLOT)); - slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), ModelRender::NORMAL_MAP_SLOT)); - slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), ModelRender::SPECULAR_MAP_SLOT)); - slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), ModelRender::LIGHTMAP_MAP_SLOT)); - slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), ModelRender::LIGHT_BUFFER_SLOT)); - slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT)); - - gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader); - gpu::Shader::makeProgram(*program, slotBindings); - - - auto locations = std::make_shared(); - initLocations(program, *locations); - - - auto state = std::make_shared(); - - // Backface on shadow - if (key.isShadow()) { - state->setCullMode(gpu::State::CULL_FRONT); - state->setDepthBias(1.0f); - state->setDepthBiasSlopeScale(4.0f); - } else { - state->setCullMode(gpu::State::CULL_BACK); - } - - // Z test depends if transparent or not - state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL); - - // Blend on transparent - state->setBlendFunction(key.isTranslucent(), - gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, // For transparent only, this keep the highlight intensity - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - - // Good to go add the brand new pipeline - auto pipeline = gpu::Pipeline::create(program, state); - insert(value_type(key.getRaw(), RenderPipeline(pipeline, locations))); - - - if (!key.isWireFrame()) { - - RenderKey wireframeKey(key.getRaw() | RenderKey::IS_WIREFRAME); - auto wireframeState = std::make_shared(state->getValues()); - - wireframeState->setFillMode(gpu::State::FILL_LINE); - - // create a new RenderPipeline with the same shader side and the wireframe state - auto wireframePipeline = gpu::Pipeline::create(program, wireframeState); - insert(value_type(wireframeKey.getRaw(), RenderPipeline(wireframePipeline, locations))); - } -} - - -void ModelRender::RenderPipelineLib::initLocations(gpu::ShaderPointer& program, ModelRender::Locations& locations) { - locations.texcoordMatrices = program->getUniforms().findLocation("texcoordMatrices"); - locations.emissiveParams = program->getUniforms().findLocation("emissiveParams"); - locations.normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap"); - locations.diffuseTextureUnit = program->getTextures().findLocation("diffuseMap"); - locations.normalTextureUnit = program->getTextures().findLocation("normalMap"); - locations.specularTextureUnit = program->getTextures().findLocation("specularMap"); - locations.emissiveTextureUnit = program->getTextures().findLocation("emissiveMap"); - locations.skinClusterBufferUnit = program->getBuffers().findLocation("skinClusterBuffer"); - locations.materialBufferUnit = program->getBuffers().findLocation("materialBuffer"); - locations.lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); - -} - - -void ModelRender::pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, - bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args, - Locations*& locations) { - - PerformanceTimer perfTimer("Model::pickPrograms"); - getRenderPipelineLib(); - - RenderKey key(mode, translucent, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe); - auto pipeline = _renderPipelineLib.find(key.getRaw()); - if (pipeline == _renderPipelineLib.end()) { - qDebug() << "No good, couldn't find a pipeline from the key ?" << key.getRaw(); - locations = 0; - return; - } - - gpu::ShaderPointer program = (*pipeline).second._pipeline->getProgram(); - locations = (*pipeline).second._locations.get(); - - - // Setup the One pipeline - batch.setPipeline((*pipeline).second._pipeline); - - if ((locations->normalFittingMapUnit > -1)) { - batch.setResourceTexture(locations->normalFittingMapUnit, - DependencyManager::get()->getNormalFittingTexture()); - } -} - -model::MaterialPointer ModelRender::_collisionHullMaterial; - -model::MaterialPointer ModelRender::getCollisionHullMaterial() { - if (!_collisionHullMaterial) { - _collisionHullMaterial = std::make_shared(); - _collisionHullMaterial->setDiffuse(glm::vec3(1.0f, 0.5f, 0.0f)); - _collisionHullMaterial->setMetallic(0.02f); - _collisionHullMaterial->setGloss(1.0f); - } - return _collisionHullMaterial; -} - diff --git a/libraries/render-utils/src/ModelRender.h b/libraries/render-utils/src/ModelRender.h deleted file mode 100644 index 8331440fb0..0000000000 --- a/libraries/render-utils/src/ModelRender.h +++ /dev/null @@ -1,157 +0,0 @@ -// -// ModelRender.h -// interface/src/renderer -// -// Created by Sam Gateau on 10/3/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_ModelRender_h -#define hifi_ModelRender_h - -#include - -#include - -class ModelRender { -public: - - static const int SKINNING_GPU_SLOT = 2; - static const int MATERIAL_GPU_SLOT = 3; - static const int DIFFUSE_MAP_SLOT = 0; - static const int NORMAL_MAP_SLOT = 1; - static const int SPECULAR_MAP_SLOT = 2; - static const int LIGHTMAP_MAP_SLOT = 3; - static const int LIGHT_BUFFER_SLOT = 4; - - class Locations { - public: - int texcoordMatrices; - int diffuseTextureUnit; - int normalTextureUnit; - int specularTextureUnit; - int emissiveTextureUnit; - int emissiveParams; - int normalFittingMapUnit; - int skinClusterBufferUnit; - int materialBufferUnit; - int lightBufferUnit; - }; - - static void pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, - bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args, - Locations*& locations); - - class RenderKey { - public: - enum FlagBit { - IS_TRANSLUCENT_FLAG = 0, - HAS_LIGHTMAP_FLAG, - HAS_TANGENTS_FLAG, - HAS_SPECULAR_FLAG, - HAS_EMISSIVE_FLAG, - IS_SKINNED_FLAG, - IS_STEREO_FLAG, - IS_DEPTH_ONLY_FLAG, - IS_SHADOW_FLAG, - IS_WIREFRAME_FLAG, - - NUM_FLAGS, - }; - - enum Flag { - IS_TRANSLUCENT = (1 << IS_TRANSLUCENT_FLAG), - HAS_LIGHTMAP = (1 << HAS_LIGHTMAP_FLAG), - HAS_TANGENTS = (1 << HAS_TANGENTS_FLAG), - HAS_SPECULAR = (1 << HAS_SPECULAR_FLAG), - HAS_EMISSIVE = (1 << HAS_EMISSIVE_FLAG), - IS_SKINNED = (1 << IS_SKINNED_FLAG), - IS_STEREO = (1 << IS_STEREO_FLAG), - IS_DEPTH_ONLY = (1 << IS_DEPTH_ONLY_FLAG), - IS_SHADOW = (1 << IS_SHADOW_FLAG), - IS_WIREFRAME = (1 << IS_WIREFRAME_FLAG), - }; - typedef unsigned short Flags; - - - - bool isFlag(short flagNum) const { return bool((_flags & flagNum) != 0); } - - bool isTranslucent() const { return isFlag(IS_TRANSLUCENT); } - bool hasLightmap() const { return isFlag(HAS_LIGHTMAP); } - bool hasTangents() const { return isFlag(HAS_TANGENTS); } - bool hasSpecular() const { return isFlag(HAS_SPECULAR); } - bool hasEmissive() const { return isFlag(HAS_EMISSIVE); } - bool isSkinned() const { return isFlag(IS_SKINNED); } - bool isStereo() const { return isFlag(IS_STEREO); } - bool isDepthOnly() const { return isFlag(IS_DEPTH_ONLY); } - bool isShadow() const { return isFlag(IS_SHADOW); } // = depth only but with back facing - bool isWireFrame() const { return isFlag(IS_WIREFRAME); } - - Flags _flags = 0; - short _spare = 0; - - int getRaw() { return *reinterpret_cast(this); } - - - RenderKey( - bool translucent, bool hasLightmap, - bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe) : - RenderKey((translucent ? IS_TRANSLUCENT : 0) - | (hasLightmap ? HAS_LIGHTMAP : 0) - | (hasTangents ? HAS_TANGENTS : 0) - | (hasSpecular ? HAS_SPECULAR : 0) - | (isSkinned ? IS_SKINNED : 0) - | (isWireframe ? IS_WIREFRAME : 0) - ) {} - - RenderKey(RenderArgs::RenderMode mode, - bool translucent, bool hasLightmap, - bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe) : - RenderKey(((translucent && (mode != RenderArgs::SHADOW_RENDER_MODE)) ? IS_TRANSLUCENT : 0) - | (hasLightmap && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_LIGHTMAP : 0) // Lightmap, tangents and specular don't matter for depthOnly - | (hasTangents && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_TANGENTS : 0) - | (hasSpecular && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_SPECULAR : 0) - | (isSkinned ? IS_SKINNED : 0) - | (isWireframe ? IS_WIREFRAME : 0) - | ((mode == RenderArgs::SHADOW_RENDER_MODE) ? IS_DEPTH_ONLY : 0) - | ((mode == RenderArgs::SHADOW_RENDER_MODE) ? IS_SHADOW : 0) - ) {} - - RenderKey(int bitmask) : _flags(bitmask) {} - }; - - - class RenderPipeline { - public: - gpu::PipelinePointer _pipeline; - std::shared_ptr _locations; - RenderPipeline(gpu::PipelinePointer pipeline, std::shared_ptr locations) : - _pipeline(pipeline), _locations(locations) {} - }; - - typedef std::unordered_map BaseRenderPipelineMap; - class RenderPipelineLib : public BaseRenderPipelineMap { - public: - typedef RenderKey Key; - - - void addRenderPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader); - - void initLocations(gpu::ShaderPointer& program, Locations& locations); - }; - static RenderPipelineLib _renderPipelineLib; - - static const RenderPipelineLib& getRenderPipelineLib(); - - // Collision hull Material - static model::MaterialPointer _collisionHullMaterial; - - static model::MaterialPointer getCollisionHullMaterial(); - -}; - -#endif // hifi_ModelRender_h \ No newline at end of file diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 1b1d08f353..90bc1486f2 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -193,7 +193,7 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - renderItems(sceneContext, renderContext, inItems, opaque.maxDrawn); + renderItems(sceneContext, renderContext, this, inItems, opaque.maxDrawn); args->_batch = nullptr; }); } @@ -219,7 +219,7 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - renderItems(sceneContext, renderContext, inItems, transparent.maxDrawn); + renderItems(sceneContext, renderContext, this, inItems, transparent.maxDrawn); args->_batch = nullptr; }); } @@ -292,7 +292,7 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon batch.setPipeline(getOpaquePipeline()); batch.setResourceTexture(0, args->_whiteTexture); - renderItems(sceneContext, renderContext, inItems, renderContext->getItemsConfig().overlay3D.maxDrawn); + renderItems(sceneContext, renderContext, this, inItems, renderContext->getItemsConfig().overlay3D.maxDrawn); }); args->_batch = nullptr; args->_whiteTexture.reset(); @@ -381,8 +381,7 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - renderItems(sceneContext, renderContext, inItems); - + renderItems(sceneContext, renderContext, nullptr, inItems); }); args->_batch = nullptr; } diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 051faa3238..2c4102ef92 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -16,6 +16,7 @@ #include "gpu/Pipeline.h" +#include "ShapeRender.h" #include "ToneMappingEffect.h" class SetupDeferred { @@ -49,14 +50,14 @@ public: typedef render::Job::Model JobModel; }; -class DrawOpaqueDeferred { +class DrawOpaqueDeferred : public ShapeRender { public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems); typedef render::Job::ModelI JobModel; }; -class DrawTransparentDeferred { +class DrawTransparentDeferred : public ShapeRender { public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems); @@ -80,7 +81,7 @@ public: typedef render::Job::Model JobModel; }; -class DrawOverlay3D { +class DrawOverlay3D : public ShapeRender { static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable public: static const gpu::PipelinePointer& getOpaquePipeline(); diff --git a/libraries/render-utils/src/ShapeRender.cpp b/libraries/render-utils/src/ShapeRender.cpp index 31db3b010e..720cc5edad 100644 --- a/libraries/render-utils/src/ShapeRender.cpp +++ b/libraries/render-utils/src/ShapeRender.cpp @@ -1,8 +1,8 @@ // -// ModelRender.cpp -// interface/src/renderer +// ShapeRender.cpp +// render-utils/src // -// Created by Sam Gateau on 10/3/15. +// Created by Zach Pomerantz on 1/4/2015. // Copyright 2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. diff --git a/libraries/render-utils/src/ShapeRender.h b/libraries/render-utils/src/ShapeRender.h index 047f300dc0..7f7390992b 100644 --- a/libraries/render-utils/src/ShapeRender.h +++ b/libraries/render-utils/src/ShapeRender.h @@ -1,5 +1,5 @@ // -// ModelRender.h +// ShapeRender.h // render-utils/src // // Created by Zach Pomerantz on 1/4/2015. diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index e6a3e024ad..5bb8662149 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -209,24 +209,36 @@ void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderCo depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems); } -void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems) { +void render::renderItem(RenderArgs* args, const Shape* shapeContext, Item& item) { + if (item.isShape()) { + assert(shapeContext); + const auto& key = item._payload.getShapeKey(); + args->_pipeline = shapeContext->pickPipeline(args, key); + if (!args->pipeline) { + return; + } + } + item.render(args); +} + +void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Shape* shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems) { auto& scene = sceneContext->_scene; RenderArgs* args = renderContext->getArgs(); // render if ((maxDrawnItems < 0) || (maxDrawnItems > (int) inItems.size())) { for (auto itemDetails : inItems) { auto item = scene->getItem(itemDetails.id); - item.render(args); + renderItem(args, shapeContext, item); } } else { int numItems = 0; for (auto itemDetails : inItems) { auto item = scene->getItem(itemDetails.id); if (numItems + 1 >= maxDrawnItems) { - item.render(args); + renderItem(args, shapeContext, item); return; } - item.render(args); + renderItem(args, jobContext, item); numItems++; if (numItems >= maxDrawnItems) { return; @@ -259,7 +271,7 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { args->_batch = &batch; - renderItems(sceneContext, renderContext, culledItems); + renderItems(sceneContext, renderContext, this, culledItems); }); args->_batch = nullptr; } diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index b06223035d..8a1d84404e 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -222,7 +222,7 @@ typedef std::vector Jobs; void cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); void depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); -void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); +void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Shape* shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); class FetchItems { @@ -268,7 +268,7 @@ public: typedef Job::ModelIO JobModel; }; -class DrawLight { +class DrawLight : public Shape { public: void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); From dfcb74c3beff3013b00c6d63bda5d7d1f5f45c56 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 4 Jan 2016 13:12:06 -0800 Subject: [PATCH 009/215] Split renderItems to Lights/Shapes --- .../render-utils/src/RenderDeferredTask.cpp | 8 +-- libraries/render/src/render/DrawTask.cpp | 59 ++++++++++--------- libraries/render/src/render/DrawTask.h | 3 +- 3 files changed, 37 insertions(+), 33 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 90bc1486f2..27aeebc173 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -193,7 +193,7 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - renderItems(sceneContext, renderContext, this, inItems, opaque.maxDrawn); + renderShapes(sceneContext, renderContext, this, inItems, opaque.maxDrawn); args->_batch = nullptr; }); } @@ -219,7 +219,7 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - renderItems(sceneContext, renderContext, this, inItems, transparent.maxDrawn); + renderShapes(sceneContext, renderContext, this, inItems, transparent.maxDrawn); args->_batch = nullptr; }); } @@ -292,7 +292,7 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon batch.setPipeline(getOpaquePipeline()); batch.setResourceTexture(0, args->_whiteTexture); - renderItems(sceneContext, renderContext, this, inItems, renderContext->getItemsConfig().overlay3D.maxDrawn); + renderShapes(sceneContext, renderContext, this, inItems, renderContext->getItemsConfig().overlay3D.maxDrawn); }); args->_batch = nullptr; args->_whiteTexture.reset(); @@ -381,7 +381,7 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - renderItems(sceneContext, renderContext, nullptr, inItems); + renderLights(sceneContext, renderContext, inItems); }); args->_batch = nullptr; } diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 5bb8662149..729c72ad6f 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -209,39 +209,43 @@ void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderCo depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems); } -void render::renderItem(RenderArgs* args, const Shape* shapeContext, Item& item) { - if (item.isShape()) { - assert(shapeContext); - const auto& key = item._payload.getShapeKey(); - args->_pipeline = shapeContext->pickPipeline(args, key); - if (!args->pipeline) { - return; - } - } - item.render(args); -} - -void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Shape* shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems) { +void render::renderLights(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Shape* shapeContext, const ItemIDsBounds& inItems) { auto& scene = sceneContext->_scene; RenderArgs* args = renderContext->getArgs(); - // render - if ((maxDrawnItems < 0) || (maxDrawnItems > (int) inItems.size())) { - for (auto itemDetails : inItems) { - auto item = scene->getItem(itemDetails.id); - renderItem(args, shapeContext, item); + + for (const auto& itemDetails : inItems) { + const auto& item = scene->getItem(itemDetails.id); + item.render(args); + } +} + +void renderShape(RenderArgs* args, const Item& item, const ShapeKey& lastKey) { + assert(item.isShape()); + const auto& key = item._payload.getShapeKey(); + args->_pipeline = shapeContext->pickPipeline(args, key); + // only render with a pipeline + if (args->_pipeline) { + item.render(args); + } +} + +void render::renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Shape* shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems) { + auto& scene = sceneContext->_scene; + RenderArgs* args = renderContext->getArgs(); + + if ((maxDrawnItems < 0) || (maxDrawnItems > (int)inItems.size())) { + for (const auto& itemDetails : inItems) { + const auto& item = scene->getItem(itemDetails.id); + renderShape(args, item); } } else { int numItems = 0; - for (auto itemDetails : inItems) { - auto item = scene->getItem(itemDetails.id); - if (numItems + 1 >= maxDrawnItems) { - renderItem(args, shapeContext, item); - return; - } - renderItem(args, jobContext, item); + for (const auto& itemDetails : inItems) { numItems++; + const auto& item = scene->getItem(itemDetails.id); + renderShape(args, item); if (numItems >= maxDrawnItems) { - return; + break; } } } @@ -255,7 +259,6 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext auto& scene = sceneContext->_scene; auto& items = scene->getMasterBucket().at(ItemFilter::Builder::light()); - ItemIDsBounds inItems; inItems.reserve(items.size()); for (auto id : items) { @@ -271,7 +274,7 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { args->_batch = &batch; - renderItems(sceneContext, renderContext, this, culledItems); + renderLights(sceneContext, renderContext, culledItems); }); args->_batch = nullptr; } diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 8a1d84404e..870a7d6ea7 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -222,7 +222,8 @@ typedef std::vector Jobs; void cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); void depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); -void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Shape* shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); +void renderLights(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems); +void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Shape* shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); class FetchItems { From cf35974f0275061b961ab458ad9828b4dba4699b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 5 Jan 2016 01:18:57 -0800 Subject: [PATCH 010/215] Move shapeContext to jobContext --- .../render-utils/src/RenderDeferredTask.cpp | 6 +++--- libraries/render-utils/src/RenderDeferredTask.h | 14 +++++++++----- libraries/render-utils/src/ShapeRender.cpp | 11 +++++++---- libraries/render-utils/src/ShapeRender.h | 1 + libraries/render/src/render/DrawTask.cpp | 12 ++++++------ libraries/render/src/render/DrawTask.h | 16 ++++++++++------ 6 files changed, 36 insertions(+), 24 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 27aeebc173..456736e76c 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -193,7 +193,7 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - renderShapes(sceneContext, renderContext, this, inItems, opaque.maxDrawn); + renderShapes(sceneContext, renderContext, _context, inItems, opaque.maxDrawn); args->_batch = nullptr; }); } @@ -219,7 +219,7 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - renderShapes(sceneContext, renderContext, this, inItems, transparent.maxDrawn); + renderShapes(sceneContext, renderContext, _context, inItems, transparent.maxDrawn); args->_batch = nullptr; }); } @@ -292,7 +292,7 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon batch.setPipeline(getOpaquePipeline()); batch.setResourceTexture(0, args->_whiteTexture); - renderShapes(sceneContext, renderContext, this, inItems, renderContext->getItemsConfig().overlay3D.maxDrawn); + renderShapes(sceneContext, renderContext, _context, inItems, renderContext->getItemsConfig().overlay3D.maxDrawn); }); args->_batch = nullptr; args->_whiteTexture.reset(); diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 2c4102ef92..240d693de3 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -50,14 +50,16 @@ public: typedef render::Job::Model JobModel; }; -class DrawOpaqueDeferred : public ShapeRender { +class DrawOpaqueDeferred { + class JobContext : public render::Job::Context, public ShapeRender {} _context; public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems); typedef render::Job::ModelI JobModel; }; -class DrawTransparentDeferred : public ShapeRender { +class DrawTransparentDeferred { + class JobContext : public render::Job::Context, public ShapeRender {} _context; public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems); @@ -81,13 +83,15 @@ public: typedef render::Job::Model JobModel; }; -class DrawOverlay3D : public ShapeRender { +class DrawOverlay3D { static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable + + class JobContext : public render::Job::Context, public ShapeRender {} _context; public: static const gpu::PipelinePointer& getOpaquePipeline(); - + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); - + typedef render::Job::Model JobModel; }; diff --git a/libraries/render-utils/src/ShapeRender.cpp b/libraries/render-utils/src/ShapeRender.cpp index 720cc5edad..6ede4ea897 100644 --- a/libraries/render-utils/src/ShapeRender.cpp +++ b/libraries/render-utils/src/ShapeRender.cpp @@ -37,6 +37,13 @@ #include "model_lightmap_specular_map_frag.h" #include "model_translucent_frag.h" +void ShapeRender::ShapeRender() { + // TODO: There is probably a cleaner way to init the pipeline that in a derived class + if (_pipelineLib.empty()) { + initPipeline(); + } +} + void ShapeRender::initPipeline() { assert(_pipelineLib.empty()); @@ -164,10 +171,6 @@ void ShapeRender::initPipeline() { const render::PipelinePointer ShapeRender::pickPipeline(RenderArgs* args, Key& key) { PerformanceTimer perfTimer("ShapeRender::pickPipeline"); - // TODO: There is probably a cleaner way to init the pipeline that in a derived class - if (_pipelineLib.empty()) { - initPipeline(); - } auto pipeline = _pickPipeline(args, key); if (!pipeline) { diff --git a/libraries/render-utils/src/ShapeRender.h b/libraries/render-utils/src/ShapeRender.h index 7f7390992b..1eef35d736 100644 --- a/libraries/render-utils/src/ShapeRender.h +++ b/libraries/render-utils/src/ShapeRender.h @@ -18,6 +18,7 @@ class ShapeRender : public render::Shape { static model::MaterialPointer _collisionHullMaterial; public: + ShapeRender(); static void initPipeline(); const render::PipelinePointer pickPipeline(RenderArgs* args, Key& key) override; diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 729c72ad6f..adf3395cba 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -209,7 +209,7 @@ void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderCo depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems); } -void render::renderLights(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Shape* shapeContext, const ItemIDsBounds& inItems) { +void render::renderLights(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Job::ContextPointer& jobContext, const ItemIDsBounds& inItems) { auto& scene = sceneContext->_scene; RenderArgs* args = renderContext->getArgs(); @@ -219,31 +219,31 @@ void render::renderLights(const SceneContextPointer& sceneContext, const RenderC } } -void renderShape(RenderArgs* args, const Item& item, const ShapeKey& lastKey) { +void renderShape(RenderArgs* args, const Job::ContextPointer& jobContext, const Item& item) { assert(item.isShape()); const auto& key = item._payload.getShapeKey(); - args->_pipeline = shapeContext->pickPipeline(args, key); + args->_pipeline = jobContext->pickPipeline(args, key); // only render with a pipeline if (args->_pipeline) { item.render(args); } } -void render::renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Shape* shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems) { +void render::renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Job::ContextPointer& jobContext, const ItemIDsBounds& inItems, int maxDrawnItems) { auto& scene = sceneContext->_scene; RenderArgs* args = renderContext->getArgs(); if ((maxDrawnItems < 0) || (maxDrawnItems > (int)inItems.size())) { for (const auto& itemDetails : inItems) { const auto& item = scene->getItem(itemDetails.id); - renderShape(args, item); + renderShape(args, jobContext, item); } } else { int numItems = 0; for (const auto& itemDetails : inItems) { numItems++; const auto& item = scene->getItem(itemDetails.id); - renderShape(args, item); + renderShape(args, jobContext, item); if (numItems >= maxDrawnItems) { break; } diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 870a7d6ea7..3cf701117c 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -57,7 +57,7 @@ public: void addJobConsumer(const std::shared_ptr& job) { _consumerJobs.push_back(job); } - + class Concept { public: virtual ~Concept() = default; @@ -101,8 +101,12 @@ public: _concept->run(sceneContext, renderContext); } -protected: public: + class Context { + public: + virtual ShapePipeline pickPipeline(RenderArgs* args, const ShapeKey& key) = 0; + }; + using ContextPointer = std::shared_ptr; class Concept { std::string _name; @@ -111,7 +115,7 @@ public: Concept() : _name() {} Concept(const std::string& name) : _name(name) {} virtual ~Concept() = default; - + void setName(const std::string& name) { _name = name; } const std::string& getName() const { return _name; } @@ -175,7 +179,7 @@ public: const Varying getOutput() const { return _output; } ModelO(const std::string& name): Concept(name), _output(Output()) { - + } ModelO(const std::string& name, Data data): Concept(name), _data(data), _output(Output()) {} @@ -223,7 +227,7 @@ typedef std::vector Jobs; void cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); void depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); void renderLights(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems); -void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Shape* shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); +void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Job::ContextPointer& jobContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); class FetchItems { @@ -290,7 +294,7 @@ public: // A map of ItemIDs allowing to create bucket lists of SHAPE type items which are filtered by their -// Material +// Material class ItemMaterialBucketMap : public std::map { public: From 63444aac725b74fb1dfe1a3fd20976b3254c11a3 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 5 Jan 2016 11:35:28 -0800 Subject: [PATCH 011/215] Back to shapeContext, compiling --- .../render-utils/src/MeshPartPayload.cpp | 20 +++---- libraries/render-utils/src/MeshPartPayload.h | 6 +- libraries/render-utils/src/Model.cpp | 2 +- .../render-utils/src/RenderDeferredTask.cpp | 12 ++-- .../render-utils/src/RenderDeferredTask.h | 7 +-- libraries/render-utils/src/ShapeRender.cpp | 55 ++++++++++--------- libraries/render-utils/src/ShapeRender.h | 4 +- libraries/render/src/render/DrawTask.cpp | 24 ++++---- libraries/render/src/render/DrawTask.h | 5 +- libraries/render/src/render/Shape.cpp | 2 +- libraries/render/src/render/Shape.h | 3 +- 11 files changed, 73 insertions(+), 67 deletions(-) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index f50deb0e43..28a341a872 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -129,7 +129,7 @@ void MeshPartPayload::bindMesh(gpu::Batch& batch) const { } } -void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locations* locations) const { +void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations) const { if (!_drawMaterial) { return; } @@ -162,7 +162,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isNormalMap()) { auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP]; if (normalMap && normalMap->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slots::::NORMAL_MAP, normalMap->getTextureView()); + batch.setResourceTexture(ShapePipeline::Slots::NORMAL_MAP, normalMap->getTextureView()); // texcoord are assumed to be the same has diffuse } else { @@ -183,7 +183,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat batch.setResourceTexture(ShapePipeline::Slots::SPECULAR_MAP, textureCache->getBlackTexture()); } } else { - batch.setResourceTexture(ShapePipeline::SPECULAR_MAP, nullptr); + batch.setResourceTexture(ShapePipeline::Slots::SPECULAR_MAP, nullptr); } // TODO: For now lightmaop is piped into the emissive map unit, we need to fix that and support for real emissive too @@ -191,7 +191,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP]; if (lightmapMap && lightmapMap->isDefined()) { - batch.setResourceTexture(ShapePipeline::LIGHTMAP_MAP, lightmapMap->getTextureView()); + batch.setResourceTexture(ShapePipeline::Slots::LIGHTMAP_MAP, lightmapMap->getTextureView()); auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale(); batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y); @@ -200,10 +200,10 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]); } } else { - batch.setResourceTexture(ShapePipeline::LIGHTMAP_MAP, textureCache->getGrayTexture()); + batch.setResourceTexture(ShapePipeline::Slots::LIGHTMAP_MAP, textureCache->getGrayTexture()); } } else { - batch.setResourceTexture(ShapePipeline::LIGHTMAP_MAP, nullptr); + batch.setResourceTexture(ShapePipeline::Slots::LIGHTMAP_MAP, nullptr); } // Texcoord transforms ? @@ -212,7 +212,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat } } -void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::Locations* locations) const { +void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations) const { batch.setModelTransform(_drawTransform); } @@ -431,16 +431,16 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) const { } } -void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::Locations* locations) const { +void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations) const { // Still relying on the raw data from the model const Model::MeshState& state = _model->_meshStates.at(_meshIndex); Transform transform; if (state.clusterBuffer) { if (_model->_cauterizeBones) { - batch.setUniformBuffer(ShapePipeline::SKINNING_GPU, state.cauterizedClusterBuffer); + batch.setUniformBuffer(ShapePipeline::Slots::SKINNING_GPU, state.cauterizedClusterBuffer); } else { - batch.setUniformBuffer(ShapePipeline::SKINNING_GPU, state.clusterBuffer); + batch.setUniformBuffer(ShapePipeline::Slots::SKINNING_GPU, state.clusterBuffer); } } else { if (_model->_cauterizeBones) { diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index cb7e1fd386..7d693dcbe9 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -46,8 +46,8 @@ public: // ModelMeshPartPayload functions to perform render void drawCall(gpu::Batch& batch) const; virtual void bindMesh(gpu::Batch& batch) const; - virtual void bindMaterial(gpu::Batch& batch, const render::ShapePipeline::Locations* locations) const; - virtual void bindTransform(gpu::Batch& batch, const render::ShapePipeline::Locations* locations) const; + virtual void bindMaterial(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations) const; + virtual void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations) const; // Payload resource cached values model::MeshPointer _drawMesh; @@ -89,7 +89,7 @@ public: // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch) const override; - void bindTransform(gpu::Batch& batch, const render::ShapePipeline::Locations* locations) const override; + void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations) const override; void initCache(); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index ef9a837b27..b40d2565c3 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1193,7 +1193,7 @@ void Model::segregateMeshGroups() { int totalParts = mesh.parts.size(); for (int partIndex = 0; partIndex < totalParts; partIndex++) { if (showingCollisionHull) { - _renderItemsSet << std::make_shared(networkMesh._mesh, partIndex, ModelRender::getCollisionHullMaterial(), transform, offset); + _renderItemsSet << std::make_shared(networkMesh._mesh, partIndex, ShapeRender::getCollisionHullMaterial(), transform, offset); } else { _renderItemsSet << std::make_shared(this, i, partIndex, shapeID, transform, offset); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 456736e76c..a35447cd05 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -177,7 +177,7 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend assert(renderContext->getArgs()->_viewFrustum); RenderArgs* args = renderContext->getArgs(); - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); args->_batch = &batch; @@ -193,7 +193,7 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - renderShapes(sceneContext, renderContext, _context, inItems, opaque.maxDrawn); + renderShapes(sceneContext, renderContext, _renderer, inItems, opaque.maxDrawn); args->_batch = nullptr; }); } @@ -203,7 +203,7 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const assert(renderContext->getArgs()->_viewFrustum); RenderArgs* args = renderContext->getArgs(); - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); args->_batch = &batch; @@ -219,7 +219,7 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - renderShapes(sceneContext, renderContext, _context, inItems, transparent.maxDrawn); + renderShapes(sceneContext, renderContext, _renderer, inItems, transparent.maxDrawn); args->_batch = nullptr; }); } @@ -276,7 +276,7 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon } // Render the items - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; args->_whiteTexture = DependencyManager::get()->getWhiteTexture(); @@ -292,7 +292,7 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon batch.setPipeline(getOpaquePipeline()); batch.setResourceTexture(0, args->_whiteTexture); - renderShapes(sceneContext, renderContext, _context, inItems, renderContext->getItemsConfig().overlay3D.maxDrawn); + renderShapes(sceneContext, renderContext, _renderer, inItems, renderContext->getItemsConfig().overlay3D.maxDrawn); }); args->_batch = nullptr; args->_whiteTexture.reset(); diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 240d693de3..051f19c133 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -51,7 +51,7 @@ public: }; class DrawOpaqueDeferred { - class JobContext : public render::Job::Context, public ShapeRender {} _context; + ShapeRender _renderer; public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems); @@ -59,7 +59,7 @@ public: }; class DrawTransparentDeferred { - class JobContext : public render::Job::Context, public ShapeRender {} _context; + ShapeRender _renderer; public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems); @@ -85,8 +85,7 @@ public: class DrawOverlay3D { static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable - - class JobContext : public render::Job::Context, public ShapeRender {} _context; + ShapeRender _renderer; public: static const gpu::PipelinePointer& getOpaquePipeline(); diff --git a/libraries/render-utils/src/ShapeRender.cpp b/libraries/render-utils/src/ShapeRender.cpp index 6ede4ea897..c68664b69a 100644 --- a/libraries/render-utils/src/ShapeRender.cpp +++ b/libraries/render-utils/src/ShapeRender.cpp @@ -37,7 +37,7 @@ #include "model_lightmap_specular_map_frag.h" #include "model_translucent_frag.h" -void ShapeRender::ShapeRender() { +ShapeRender::ShapeRender() { // TODO: There is probably a cleaner way to init the pipeline that in a derived class if (_pipelineLib.empty()) { initPipeline(); @@ -72,104 +72,105 @@ void ShapeRender::initPipeline() { // Fill the pipelineLib _pipelineLib.addPipeline( - RenderKey(0), + Key::Builder(), modelVertex, modelPixel); _pipelineLib.addPipeline( - RenderKey(RenderKey::HAS_TANGENTS), + Key::Builder().withTangents(), modelNormalMapVertex, modelNormalMapPixel); _pipelineLib.addPipeline( - RenderKey(RenderKey::HAS_SPECULAR), + Key::Builder().withSpecular(), modelVertex, modelSpecularMapPixel); _pipelineLib.addPipeline( - RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), + Key::Builder().withTangents().withSpecular(), modelNormalMapVertex, modelNormalSpecularMapPixel); _pipelineLib.addPipeline( - RenderKey(RenderKey::IS_TRANSLUCENT), + Key::Builder().withTranslucent(), modelVertex, modelTranslucentPixel); // FIXME Ignore lightmap for translucents meshpart _pipelineLib.addPipeline( - RenderKey(RenderKey::IS_TRANSLUCENT | RenderKey::HAS_LIGHTMAP), + Key::Builder().withTranslucent().withLightmap(), modelVertex, modelTranslucentPixel); _pipelineLib.addPipeline( - RenderKey(RenderKey::HAS_TANGENTS | RenderKey::IS_TRANSLUCENT), + Key::Builder().withTangents().withTranslucent(), modelNormalMapVertex, modelTranslucentPixel); _pipelineLib.addPipeline( - RenderKey(RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), + Key::Builder().withSpecular().withTranslucent(), modelVertex, modelTranslucentPixel); _pipelineLib.addPipeline( - RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), + Key::Builder().withTangents().withSpecular().withTranslucent(), modelNormalMapVertex, modelTranslucentPixel); _pipelineLib.addPipeline( - RenderKey(RenderKey::HAS_LIGHTMAP), + Key::Builder().withLightmap(), modelLightmapVertex, modelLightmapPixel); + _pipelineLib.addPipeline( - RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_TANGENTS), + Key::Builder().withLightmap().withTangents(), modelLightmapNormalMapVertex, modelLightmapNormalMapPixel); _pipelineLib.addPipeline( - RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_SPECULAR), + Key::Builder().withLightmap().withSpecular(), modelLightmapVertex, modelLightmapSpecularMapPixel); _pipelineLib.addPipeline( - RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), + Key::Builder().withLightmap().withTangents().withSpecular(), modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel); _pipelineLib.addPipeline( - RenderKey(RenderKey::IS_SKINNED), + Key::Builder().withSkinned(), skinModelVertex, modelPixel); _pipelineLib.addPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS), + Key::Builder().withSkinned().withTangents(), skinModelNormalMapVertex, modelNormalMapPixel); _pipelineLib.addPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_SPECULAR), + Key::Builder().withSkinned().withSpecular(), skinModelVertex, modelSpecularMapPixel); _pipelineLib.addPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), + Key::Builder().withSkinned().withTangents().withSpecular(), skinModelNormalMapVertex, modelNormalSpecularMapPixel); _pipelineLib.addPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::IS_TRANSLUCENT), + Key::Builder().withSkinned().withTranslucent(), skinModelVertex, modelTranslucentPixel); _pipelineLib.addPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::IS_TRANSLUCENT), + Key::Builder().withSkinned().withTangents().withTranslucent(), skinModelNormalMapVertex, modelTranslucentPixel); _pipelineLib.addPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), + Key::Builder().withSkinned().withSpecular().withTranslucent(), skinModelVertex, modelTranslucentPixel); _pipelineLib.addPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT), + Key::Builder().withSkinned().withTangents().withSpecular().withTranslucent(), skinModelNormalMapVertex, modelTranslucentPixel); _pipelineLib.addPipeline( - RenderKey(RenderKey::IS_DEPTH_ONLY | RenderKey::IS_SHADOW), + Key::Builder().withDepthOnly().withShadow(), modelShadowVertex, modelShadowPixel); _pipelineLib.addPipeline( - RenderKey(RenderKey::IS_SKINNED | RenderKey::IS_DEPTH_ONLY | RenderKey::IS_SHADOW), + Key::Builder().withSkinned().withDepthOnly().withShadow(), skinModelShadowVertex, modelShadowPixel); } -const render::PipelinePointer ShapeRender::pickPipeline(RenderArgs* args, Key& key) { +const ShapeRender::PipelinePointer ShapeRender::pickPipeline(RenderArgs* args, const Key& key) const { PerformanceTimer perfTimer("ShapeRender::pickPipeline"); auto pipeline = _pickPipeline(args, key); @@ -178,9 +179,11 @@ const render::PipelinePointer ShapeRender::pickPipeline(RenderArgs* args, Key& k } if ((pipeline->locations->normalFittingMapUnit > -1)) { - batch.setResourceTexture(pipeline->locations->normalFittingMapUnit, + args->_batch->setResourceTexture(pipeline->locations->normalFittingMapUnit, DependencyManager::get()->getNormalFittingTexture()); } + + return pipeline; } model::MaterialPointer ShapeRender::_collisionHullMaterial; diff --git a/libraries/render-utils/src/ShapeRender.h b/libraries/render-utils/src/ShapeRender.h index 1eef35d736..a3f131f21d 100644 --- a/libraries/render-utils/src/ShapeRender.h +++ b/libraries/render-utils/src/ShapeRender.h @@ -13,6 +13,7 @@ #define hifi_render_utils_Shape_h #include +#include class ShapeRender : public render::Shape { static model::MaterialPointer _collisionHullMaterial; @@ -20,10 +21,9 @@ class ShapeRender : public render::Shape { public: ShapeRender(); static void initPipeline(); - const render::PipelinePointer pickPipeline(RenderArgs* args, Key& key) override; + const PipelinePointer pickPipeline(RenderArgs* args, const Key& key) const override; static model::MaterialPointer getCollisionHullMaterial(); }; #endif // hifi_render_utils_Shape_h - diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index adf3395cba..9636ba7d86 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -209,41 +209,43 @@ void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderCo depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems); } -void render::renderLights(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Job::ContextPointer& jobContext, const ItemIDsBounds& inItems) { +void render::renderLights(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) { auto& scene = sceneContext->_scene; RenderArgs* args = renderContext->getArgs(); for (const auto& itemDetails : inItems) { - const auto& item = scene->getItem(itemDetails.id); + // FIXME: Every item is copied because item.render cannot mutate a const + auto item = scene->getItem(itemDetails.id); item.render(args); } } -void renderShape(RenderArgs* args, const Job::ContextPointer& jobContext, const Item& item) { - assert(item.isShape()); - const auto& key = item._payload.getShapeKey(); - args->_pipeline = jobContext->pickPipeline(args, key); +void renderShape(RenderArgs* args, const Shape& shapeContext, Item& item) { + assert(item.getKey().isShape()); + const auto& key = item.getShapeKey(); + args->_pipeline = shapeContext.pickPipeline(args, key); // only render with a pipeline if (args->_pipeline) { item.render(args); } } -void render::renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Job::ContextPointer& jobContext, const ItemIDsBounds& inItems, int maxDrawnItems) { +void render::renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Shape& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems) { auto& scene = sceneContext->_scene; RenderArgs* args = renderContext->getArgs(); if ((maxDrawnItems < 0) || (maxDrawnItems > (int)inItems.size())) { for (const auto& itemDetails : inItems) { - const auto& item = scene->getItem(itemDetails.id); - renderShape(args, jobContext, item); + // FIXME: Every item is copied because item.render cannot mutate a const + auto item = scene->getItem(itemDetails.id); + renderShape(args, shapeContext, item); } } else { int numItems = 0; for (const auto& itemDetails : inItems) { numItems++; - const auto& item = scene->getItem(itemDetails.id); - renderShape(args, jobContext, item); + auto item = scene->getItem(itemDetails.id); + renderShape(args, shapeContext, item); if (numItems >= maxDrawnItems) { break; } diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 3cf701117c..d3741a07a7 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -13,6 +13,7 @@ #define hifi_render_Task_h #include "Engine.h" +#include "Shape.h" #include "gpu/Batch.h" #include @@ -104,7 +105,7 @@ public: public: class Context { public: - virtual ShapePipeline pickPipeline(RenderArgs* args, const ShapeKey& key) = 0; + virtual const ShapePipeline pickPipeline(RenderArgs* args, const ShapeKey& key) = 0; }; using ContextPointer = std::shared_ptr; @@ -227,7 +228,7 @@ typedef std::vector Jobs; void cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); void depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); void renderLights(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems); -void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Job::ContextPointer& jobContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); +void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Shape& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); class FetchItems { diff --git a/libraries/render/src/render/Shape.cpp b/libraries/render/src/render/Shape.cpp index a6b8e09126..e596082e4f 100644 --- a/libraries/render/src/render/Shape.cpp +++ b/libraries/render/src/render/Shape.cpp @@ -15,7 +15,7 @@ using namespace render; -Shape::PipelineLib _pipelineLip; +Shape::PipelineLib Shape::_pipelineLib; const Shape::PipelinePointer Shape::_pickPipeline(RenderArgs* args, const Key& key) { assert(!_pipelineLib.empty()); diff --git a/libraries/render/src/render/Shape.h b/libraries/render/src/render/Shape.h index c3bf06f0ee..56bfa1e036 100644 --- a/libraries/render/src/render/Shape.h +++ b/libraries/render/src/render/Shape.h @@ -138,6 +138,7 @@ public: int materialBufferUnit; int lightBufferUnit; }; + using LocationsPointer = std::shared_ptr; gpu::PipelinePointer pipeline; std::shared_ptr locations; @@ -165,7 +166,7 @@ public: static void addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader) { _pipelineLib.addPipeline(key, vertexShader, pixelShader); } - virtual const PipelinePointer pickPipeline(RenderArgs* args, const Key& key) { + virtual const PipelinePointer pickPipeline(RenderArgs* args, const Key& key) const { return Shape::_pickPipeline(args, key); } From ad329a933191aac0b18823d40e93d5deff780bcf Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 5 Jan 2016 12:14:02 -0800 Subject: [PATCH 012/215] Return nullptr if no pipeline is found --- libraries/render/src/render/Shape.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/libraries/render/src/render/Shape.cpp b/libraries/render/src/render/Shape.cpp index e596082e4f..faa562e28e 100644 --- a/libraries/render/src/render/Shape.cpp +++ b/libraries/render/src/render/Shape.cpp @@ -27,10 +27,10 @@ const Shape::PipelinePointer Shape::_pickPipeline(RenderArgs* args, const Key& k const auto& pipelineIterator = _pipelineLib.find(key); if (pipelineIterator == _pipelineLib.end()) { qDebug() << "Couldn't find a pipeline from ShapeKey ?" << key; - return std::make_shared(); + return PipelinePointer(nullptr); } - Shape::PipelinePointer shapePipeline(&(pipelineIterator->second)); + PipelinePointer shapePipeline(&(pipelineIterator->second)); auto& batch = args->_batch; // Setup the one pipeline (to rule them all) @@ -41,14 +41,14 @@ const Shape::PipelinePointer Shape::_pickPipeline(RenderArgs* args, const Key& k void Shape::PipelineLib::addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader) { gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Shape::Slots::SKINNING_GPU)); - slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), Shape::Slots::MATERIAL_GPU)); - slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), Shape::Slots::DIFFUSE_MAP)); - slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), Shape::Slots::NORMAL_MAP)); - slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), Shape::Slots::SPECULAR_MAP)); - slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), Shape::Slots::LIGHTMAP_MAP)); - slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Shape::Slots::LIGHT_BUFFER)); - slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), Shape::Slots::NORMAL_FITTING_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slots::SKINNING_GPU)); + slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), Slots::MATERIAL_GPU)); + slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), Slots::DIFFUSE_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), Slots::NORMAL_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), Slots::SPECULAR_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), Slots::LIGHTMAP_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Slots::LIGHT_BUFFER)); + slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), Slots::NORMAL_FITTING_MAP)); gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader); gpu::Shader::makeProgram(*program, slotBindings); @@ -86,7 +86,7 @@ void Shape::PipelineLib::addPipeline(Key key, gpu::ShaderPointer& vertexShader, // Add the brand new pipeline and cache its location in the lib auto pipeline = gpu::Pipeline::create(program, state); - insert(value_type(key, Shape::Pipeline(pipeline, locations))); + insert(value_type(key, Pipeline(pipeline, locations))); // Add a wireframe version if (!key.isWireFrame()) { @@ -96,6 +96,6 @@ void Shape::PipelineLib::addPipeline(Key key, gpu::ShaderPointer& vertexShader, wireframeState->setFillMode(gpu::State::FILL_LINE); auto wireframePipeline = gpu::Pipeline::create(program, wireframeState); - insert(value_type(wireframeKey, Shape::Pipeline(wireframePipeline, locations))); + insert(value_type(wireframeKey, Pipeline(wireframePipeline, locations))); } } From df54d1dcc92c9e37833d31c74df03e48845cf4ab Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 5 Jan 2016 14:22:00 -0800 Subject: [PATCH 013/215] Fix render::Shape::Pipeline ownership by storing shared_ptr in map --- libraries/render/src/render/Shape.cpp | 6 +++--- libraries/render/src/render/Shape.h | 30 +++++++++++++++------------ 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/libraries/render/src/render/Shape.cpp b/libraries/render/src/render/Shape.cpp index faa562e28e..2177a71138 100644 --- a/libraries/render/src/render/Shape.cpp +++ b/libraries/render/src/render/Shape.cpp @@ -30,7 +30,7 @@ const Shape::PipelinePointer Shape::_pickPipeline(RenderArgs* args, const Key& k return PipelinePointer(nullptr); } - PipelinePointer shapePipeline(&(pipelineIterator->second)); + PipelinePointer shapePipeline(pipelineIterator->second); auto& batch = args->_batch; // Setup the one pipeline (to rule them all) @@ -86,7 +86,7 @@ void Shape::PipelineLib::addPipeline(Key key, gpu::ShaderPointer& vertexShader, // Add the brand new pipeline and cache its location in the lib auto pipeline = gpu::Pipeline::create(program, state); - insert(value_type(key, Pipeline(pipeline, locations))); + insert(value_type(key, std::make_shared(pipeline, locations))); // Add a wireframe version if (!key.isWireFrame()) { @@ -96,6 +96,6 @@ void Shape::PipelineLib::addPipeline(Key key, gpu::ShaderPointer& vertexShader, wireframeState->setFillMode(gpu::State::FILL_LINE); auto wireframePipeline = gpu::Pipeline::create(program, wireframeState); - insert(value_type(wireframeKey, Pipeline(wireframePipeline, locations))); + insert(value_type(wireframeKey, std::make_shared(wireframePipeline, locations))); } } diff --git a/libraries/render/src/render/Shape.h b/libraries/render/src/render/Shape.h index 56bfa1e036..1613904fd7 100644 --- a/libraries/render/src/render/Shape.h +++ b/libraries/render/src/render/Shape.h @@ -95,18 +95,22 @@ public: }; inline QDebug operator<<(QDebug debug, const ShapeKey& renderKey) { - debug << "[ShapeKey:" - << "hasLightmap:" << renderKey.hasLightmap() - << "hasTangents:" << renderKey.hasTangents() - << "hasSpecular:" << renderKey.hasSpecular() - << "hasEmissive:" << renderKey.hasEmissive() - << "isTranslucent:" << renderKey.isTranslucent() - << "isSkinned:" << renderKey.isSkinned() - << "isStereo:" << renderKey.isStereo() - << "isDepthOnly:" << renderKey.isDepthOnly() - << "isShadow:" << renderKey.isShadow() - << "isWireFrame:" << renderKey.isWireFrame() - << "]"; + if (renderKey.isValid()) { + debug << "[ShapeKey:" + << "hasLightmap:" << renderKey.hasLightmap() + << "hasTangents:" << renderKey.hasTangents() + << "hasSpecular:" << renderKey.hasSpecular() + << "hasEmissive:" << renderKey.hasEmissive() + << "isTranslucent:" << renderKey.isTranslucent() + << "isSkinned:" << renderKey.isSkinned() + << "isStereo:" << renderKey.isStereo() + << "isDepthOnly:" << renderKey.isDepthOnly() + << "isShadow:" << renderKey.isShadow() + << "isWireFrame:" << renderKey.isWireFrame() + << "]"; + } else { + debug << "[ShapeKey: INVALID]"; + } return debug; } @@ -157,7 +161,7 @@ public: using Slots = ShapePipeline::Slots; using Locations = ShapePipeline::Locations; - using PipelineMap = std::unordered_map; + using PipelineMap = std::unordered_map; class PipelineLib : public PipelineMap { public: void addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader); From 258a414404c0f8d7bce1ce3658ff206a3df5799f Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 5 Jan 2016 15:54:47 -0800 Subject: [PATCH 014/215] Add ShapeKey::NO_PIPELINE for shapes without Shape::Pipeline --- libraries/render/src/render/DrawTask.cpp | 9 ++++++--- libraries/render/src/render/Scene.h | 2 +- libraries/render/src/render/Shape.h | 5 +++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 9636ba7d86..2fa96efdd4 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -223,9 +223,12 @@ void render::renderLights(const SceneContextPointer& sceneContext, const RenderC void renderShape(RenderArgs* args, const Shape& shapeContext, Item& item) { assert(item.getKey().isShape()); const auto& key = item.getShapeKey(); - args->_pipeline = shapeContext.pickPipeline(args, key); - // only render with a pipeline - if (args->_pipeline) { + if (key.isValid() && key.hasPipeline()) { + args->_pipeline = shapeContext.pickPipeline(args, key); + if (args->_pipeline) { + item.render(args); + } + } else if (!key.hasPipeline()) { item.render(args); } } diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index 1d8744c1a7..90625dfd14 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -350,7 +350,7 @@ template int payloadGetLayer(const std::shared_ptr& payloadData) { template void payloadRender(const std::shared_ptr& payloadData, RenderArgs* args) { } // Shape type interface -template const ShapeKey shapeGetShapeKey(const std::shared_ptr& payloadData) { return ShapeKey::Builder::invalid(); } +template const ShapeKey shapeGetShapeKey(const std::shared_ptr& payloadData) { return ShapeKey::Builder::noPipeline(); } template class Payload : public Item::PayloadInterface { public: diff --git a/libraries/render/src/render/Shape.h b/libraries/render/src/render/Shape.h index 1613904fd7..394b54858c 100644 --- a/libraries/render/src/render/Shape.h +++ b/libraries/render/src/render/Shape.h @@ -31,6 +31,7 @@ public: SHADOW, WIREFRAME, + NO_PIPELINE, INVALID, NUM_FLAGS, // Not a valid flag @@ -61,8 +62,10 @@ public: Builder& withDepthOnly() { _flags.set(DEPTH_ONLY); return (*this); } Builder& withShadow() { _flags.set(SHADOW); return (*this); } Builder& withWireframe() { _flags.set(WIREFRAME); return (*this); } + Builder& withoutPipeline() { _flags.set(NO_PIPELINE); return (*this); } Builder& invalidate() { _flags.set(INVALID); return (*this); } + static const ShapeKey noPipeline() { return Builder().withoutPipeline(); } static const ShapeKey invalid() { return Builder().invalidate(); } }; ShapeKey(const Builder& builder) : ShapeKey(builder._flags) {} @@ -77,6 +80,8 @@ public: bool isDepthOnly() const { return _flags[DEPTH_ONLY]; } bool isShadow() const { return _flags[SHADOW]; } bool isWireFrame() const { return _flags[WIREFRAME]; } + + bool hasPipeline() const { return !_flags[NO_PIPELINE]; } bool isValid() const { return !_flags[INVALID]; } // Hasher for use in unordered_maps From 4eff377258a24a86c8b68a986e1bdac394e75314 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 5 Jan 2016 16:27:02 -0800 Subject: [PATCH 015/215] Change Slots->Slot to be congruous with gpu --- .../render-utils/src/DeferredLightingEffect.h | 4 ++- .../render-utils/src/MeshPartPayload.cpp | 30 +++++++++---------- libraries/render/src/render/Shape.cpp | 16 +++++----- libraries/render/src/render/Shape.h | 4 +-- 4 files changed, 28 insertions(+), 26 deletions(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index dfb0ecbffb..40800258de 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -21,6 +21,8 @@ #include "model/Stage.h" #include "model/Geometry.h" +#include "render/Shape.h" + class RenderArgs; class SimpleProgramKey; struct LightLocations; @@ -30,7 +32,7 @@ class DeferredLightingEffect : public Dependency { SINGLETON_DEPENDENCY public: - static const int NORMAL_FITTING_MAP_SLOT = 10; + static const int NORMAL_FITTING_MAP_SLOT = render::Shape::Slot::NORMAL_FITTING_MAP; static const int DEFERRED_TRANSFORM_BUFFER_SLOT = 2; void init(); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 28a341a872..53feaa5a44 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -136,7 +136,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat auto textureCache = DependencyManager::get(); - batch.setUniformBuffer(ShapePipeline::Slots::MATERIAL_GPU, _drawMaterial->getSchemaBuffer()); + batch.setUniformBuffer(ShapePipeline::Slot::MATERIAL_GPU, _drawMaterial->getSchemaBuffer()); auto materialKey = _drawMaterial->getKey(); auto textureMaps = _drawMaterial->getTextureMaps(); @@ -146,44 +146,44 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isDiffuseMap()) { auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP]; if (diffuseMap && diffuseMap->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slots::DIFFUSE_MAP, diffuseMap->getTextureView()); + batch.setResourceTexture(ShapePipeline::Slot::DIFFUSE_MAP, diffuseMap->getTextureView()); if (!diffuseMap->getTextureTransform().isIdentity()) { diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]); } } else { - batch.setResourceTexture(ShapePipeline::Slots::DIFFUSE_MAP, textureCache->getGrayTexture()); + batch.setResourceTexture(ShapePipeline::Slot::DIFFUSE_MAP, textureCache->getGrayTexture()); } } else { - batch.setResourceTexture(ShapePipeline::Slots::DIFFUSE_MAP, textureCache->getWhiteTexture()); + batch.setResourceTexture(ShapePipeline::Slot::DIFFUSE_MAP, textureCache->getWhiteTexture()); } // Normal map if (materialKey.isNormalMap()) { auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP]; if (normalMap && normalMap->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slots::NORMAL_MAP, normalMap->getTextureView()); + batch.setResourceTexture(ShapePipeline::Slot::NORMAL_MAP, normalMap->getTextureView()); // texcoord are assumed to be the same has diffuse } else { - batch.setResourceTexture(ShapePipeline::Slots::NORMAL_MAP, textureCache->getBlueTexture()); + batch.setResourceTexture(ShapePipeline::Slot::NORMAL_MAP, textureCache->getBlueTexture()); } } else { - batch.setResourceTexture(ShapePipeline::Slots::NORMAL_MAP, nullptr); + batch.setResourceTexture(ShapePipeline::Slot::NORMAL_MAP, nullptr); } // TODO: For now gloss map is used as the "specular map in the shading, we ll need to fix that if (materialKey.isGlossMap()) { auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP]; if (specularMap && specularMap->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slots::SPECULAR_MAP, specularMap->getTextureView()); + batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, specularMap->getTextureView()); // texcoord are assumed to be the same has diffuse } else { - batch.setResourceTexture(ShapePipeline::Slots::SPECULAR_MAP, textureCache->getBlackTexture()); + batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, textureCache->getBlackTexture()); } } else { - batch.setResourceTexture(ShapePipeline::Slots::SPECULAR_MAP, nullptr); + batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, nullptr); } // TODO: For now lightmaop is piped into the emissive map unit, we need to fix that and support for real emissive too @@ -191,7 +191,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP]; if (lightmapMap && lightmapMap->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slots::LIGHTMAP_MAP, lightmapMap->getTextureView()); + batch.setResourceTexture(ShapePipeline::Slot::LIGHTMAP_MAP, lightmapMap->getTextureView()); auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale(); batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y); @@ -200,10 +200,10 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]); } } else { - batch.setResourceTexture(ShapePipeline::Slots::LIGHTMAP_MAP, textureCache->getGrayTexture()); + batch.setResourceTexture(ShapePipeline::Slot::LIGHTMAP_MAP, textureCache->getGrayTexture()); } } else { - batch.setResourceTexture(ShapePipeline::Slots::LIGHTMAP_MAP, nullptr); + batch.setResourceTexture(ShapePipeline::Slot::LIGHTMAP_MAP, nullptr); } // Texcoord transforms ? @@ -438,9 +438,9 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline: Transform transform; if (state.clusterBuffer) { if (_model->_cauterizeBones) { - batch.setUniformBuffer(ShapePipeline::Slots::SKINNING_GPU, state.cauterizedClusterBuffer); + batch.setUniformBuffer(ShapePipeline::Slot::SKINNING_GPU, state.cauterizedClusterBuffer); } else { - batch.setUniformBuffer(ShapePipeline::Slots::SKINNING_GPU, state.clusterBuffer); + batch.setUniformBuffer(ShapePipeline::Slot::SKINNING_GPU, state.clusterBuffer); } } else { if (_model->_cauterizeBones) { diff --git a/libraries/render/src/render/Shape.cpp b/libraries/render/src/render/Shape.cpp index 2177a71138..ed988adb5a 100644 --- a/libraries/render/src/render/Shape.cpp +++ b/libraries/render/src/render/Shape.cpp @@ -41,14 +41,14 @@ const Shape::PipelinePointer Shape::_pickPipeline(RenderArgs* args, const Key& k void Shape::PipelineLib::addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader) { gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slots::SKINNING_GPU)); - slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), Slots::MATERIAL_GPU)); - slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), Slots::DIFFUSE_MAP)); - slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), Slots::NORMAL_MAP)); - slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), Slots::SPECULAR_MAP)); - slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), Slots::LIGHTMAP_MAP)); - slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Slots::LIGHT_BUFFER)); - slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), Slots::NORMAL_FITTING_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slot::SKINNING_GPU)); + slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), Slot::MATERIAL_GPU)); + slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), Slot::DIFFUSE_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), Slot::NORMAL_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), Slot::SPECULAR_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), Slot::LIGHTMAP_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Slot::LIGHT_BUFFER)); + slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), Slot::NORMAL_FITTING_MAP)); gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader); gpu::Shader::makeProgram(*program, slotBindings); diff --git a/libraries/render/src/render/Shape.h b/libraries/render/src/render/Shape.h index 394b54858c..917b27f2dc 100644 --- a/libraries/render/src/render/Shape.h +++ b/libraries/render/src/render/Shape.h @@ -122,7 +122,7 @@ inline QDebug operator<<(QDebug debug, const ShapeKey& renderKey) { // Rendering abstraction over gpu::Pipeline and map locations class ShapePipeline { public: - class Slots { + class Slot { public: static const int SKINNING_GPU = 2; static const int MATERIAL_GPU = 3; @@ -163,7 +163,7 @@ public: using Key = ShapeKey; using Pipeline = ShapePipeline; using PipelinePointer = std::shared_ptr; - using Slots = ShapePipeline::Slots; + using Slot = ShapePipeline::Slot; using Locations = ShapePipeline::Locations; using PipelineMap = std::unordered_map; From 444a014252c1148850a85cf4903dc20fcbc1f6d5 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 5 Jan 2016 17:10:47 -0800 Subject: [PATCH 016/215] Delay renderEngine init for GLBackend init --- interface/src/Application.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e8673e7eac..69fef254c5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -452,8 +452,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _bookmarks = new Bookmarks(); // Before setting up the menu _runningScriptsWidget = new RunningScriptsWidget(_window); - _renderEngine->addTask(make_shared()); - _renderEngine->registerScene(_main3DScene); // start the nodeThread so its event loop is running QThread* nodeThread = new QThread(this); @@ -660,6 +658,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _offscreenContext->makeCurrent(); initializeGL(); + // Start rendering + _renderEngine->addTask(make_shared()); + _renderEngine->registerScene(_main3DScene); _toolWindow = new ToolWindow(); _toolWindow->setWindowFlags((_toolWindow->windowFlags() | Qt::WindowStaysOnTopHint) & ~Qt::WindowMinimizeButtonHint); From 948dc26d24d26c358874e2050eba39e292dc2619 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 5 Jan 2016 17:19:23 -0800 Subject: [PATCH 017/215] Add debug statement for invalid ShapeKey --- libraries/render/src/render/DrawTask.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 2fa96efdd4..f66b6461b9 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -230,6 +230,8 @@ void renderShape(RenderArgs* args, const Shape& shapeContext, Item& item) { } } else if (!key.hasPipeline()) { item.render(args); + } else { + qDebug() << "Item could not be rendered: invalid key ?" << key; } } From da50eacaad3fd0040118089304f2b8263de4102e Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 5 Jan 2016 18:08:16 -0800 Subject: [PATCH 018/215] Resolve Hash const function and include per Jenkins --- libraries/render-utils/src/DeferredLightingEffect.h | 4 ++-- libraries/render/src/render/Shape.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 40800258de..e0926fb5b8 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -21,7 +21,7 @@ #include "model/Stage.h" #include "model/Geometry.h" -#include "render/Shape.h" +#include "ShapeRender.h" class RenderArgs; class SimpleProgramKey; @@ -32,7 +32,7 @@ class DeferredLightingEffect : public Dependency { SINGLETON_DEPENDENCY public: - static const int NORMAL_FITTING_MAP_SLOT = render::Shape::Slot::NORMAL_FITTING_MAP; + static const int NORMAL_FITTING_MAP_SLOT = ShapeRender::Slot::NORMAL_FITTING_MAP; static const int DEFERRED_TRANSFORM_BUFFER_SLOT = 2; void init(); diff --git a/libraries/render/src/render/Shape.h b/libraries/render/src/render/Shape.h index 917b27f2dc..8fc93d76af 100644 --- a/libraries/render/src/render/Shape.h +++ b/libraries/render/src/render/Shape.h @@ -87,7 +87,7 @@ public: // Hasher for use in unordered_maps class Hash { public: - size_t operator() (const ShapeKey& key) { + size_t operator() (const ShapeKey& key) const { return std::hash()(key._flags); } }; From d8ff133cc681df28b6bb471c257c12c14e726d46 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 5 Jan 2016 18:11:24 -0800 Subject: [PATCH 019/215] Fix include in gpu-test --- libraries/render-utils/src/DeferredLightingEffect.h | 4 ++-- tests/gpu-test/CMakeLists.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index e0926fb5b8..40800258de 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -21,7 +21,7 @@ #include "model/Stage.h" #include "model/Geometry.h" -#include "ShapeRender.h" +#include "render/Shape.h" class RenderArgs; class SimpleProgramKey; @@ -32,7 +32,7 @@ class DeferredLightingEffect : public Dependency { SINGLETON_DEPENDENCY public: - static const int NORMAL_FITTING_MAP_SLOT = ShapeRender::Slot::NORMAL_FITTING_MAP; + static const int NORMAL_FITTING_MAP_SLOT = render::Shape::Slot::NORMAL_FITTING_MAP; static const int DEFERRED_TRANSFORM_BUFFER_SLOT = 2; void init(); diff --git a/tests/gpu-test/CMakeLists.txt b/tests/gpu-test/CMakeLists.txt index 3d83c310cf..6b985da4c9 100644 --- a/tests/gpu-test/CMakeLists.txt +++ b/tests/gpu-test/CMakeLists.txt @@ -3,5 +3,5 @@ AUTOSCRIBE_SHADER_LIB(gpu model render-utils) # This is not a testcase -- just set it up as a regular hifi project setup_hifi_project(Quick Gui OpenGL Script Widgets) set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") -link_hifi_libraries(networking gl gpu procedural shared fbx model model-networking animation script-engine render-utils ) +link_hifi_libraries(networking gl gpu procedural shared fbx model model-networking animation script-engine render render-utils ) package_libraries_for_deployment() \ No newline at end of file From 3e6ff0eb68a92666b6df91b63908ffbca3756294 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 5 Jan 2016 19:56:56 -0800 Subject: [PATCH 020/215] Moved hand animation control into grab script. --- examples/controllers/handControllerGrab.js | 85 ++++++++++++++++++- .../defaultAvatar_full/avatar-animation.json | 6 +- libraries/animation/src/Rig.cpp | 2 + 3 files changed, 88 insertions(+), 5 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 5ba0ccd0ef..8095ebc81b 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -18,6 +18,7 @@ Script.include("../libraries/utils.js"); // add lines where the hand ray picking is happening // var WANT_DEBUG = false; +var WANT_DEBUG_STATE = true; // // these tune time-averaging and "on" value for analog trigger @@ -302,9 +303,84 @@ function MyController(hand) { this.ignoreIK = false; this.offsetPosition = Vec3.ZERO; this.offsetRotation = Quat.IDENTITY; + this.handIdleAlpha = 0; + + var HAND_IDLE_RAMP_ON_RATE = 0.1; + var HAND_IDLE_RAMP_OFF_RATE = 0.02; var _this = this; + var farGrabStates = [STATE_DISTANCE_HOLDING, STATE_CONTINUE_DISTANCE_HOLDING]; + var pointStates = [STATE_SEARCHING, STATE_EQUIP_SEARCHING, + STATE_NEAR_TRIGGER, STATE_CONTINUE_NEAR_TRIGGER, + STATE_FAR_TRIGGER, STATE_CONTINUE_FAR_TRIGGER]; + var idleStates = [STATE_OFF]; + + var propList = ["isLeftHandFarGrab", "isLeftHandPoint", "isLeftHandIdle", "isLeftHandGrab", + "isRightHandFarGrab", "isRightHandPoint", "isRightHandIdle", "isRightHandGrab"]; + + // hook up anim var handler + this.animHandlerId = MyAvatar.addAnimationStateHandler(function (props) { + var foundState = false; + var result = {}; + + var isHandPrefix = (_this.hand === RIGHT_HAND) ? "isRight" : "isLeft"; + var handPrefix = (_this.hand === RIGHT_HAND) ? "right" : "left"; + + /* + // far grab check + if (farGrabStates.indexOf(_this.state) != -1) { + result[isHandPrefix + "HandFarGrab"] = true; + foundState = true; + } else { + result[isHandPrefix + "HandFarGrab"] = false; + } + */ + + result[handPrefix + "HandGrabBlend"] = _this.triggerValue; + + // point check + if (pointStates.indexOf(_this.state) != -1) { + result[isHandPrefix + "HandPoint"] = true; + foundState = true; + } else { + result[isHandPrefix + "HandPoint"] = false; + } + + // idle check + if (idleStates.indexOf(_this.state) != -1) { + + // ramp down handIdleAlpha + if (_this.handIdleAlpha > HAND_IDLE_RAMP_OFF_RATE) { + _this.handIdleAlpha -= HAND_IDLE_RAMP_OFF_RATE; + } else { + _this.handIdleAlpha = 0; + } + result[isHandPrefix + "HandIdle"] = true; + foundState = true; + } else { + + // ramp up handIdleAlpha + if (_this.handIdleAlpha < 1 - HAND_IDLE_RAMP_ON_RATE) { + _this.handIdleAlpha += HAND_IDLE_RAMP_ON_RATE; + } else { + _this.handIdleAlpha = 1; + } + result[isHandPrefix + "HandIdle"] = false; + } + + result[handPrefix + "HandOverlayAlpha"] = _this.handIdleAlpha; + + // grab check + if (!foundState) { + result[isHandPrefix + "HandGrab"] = true; + } else { + result[isHandPrefix + "HandGrab"] = false; + } + + return result; + }, propList); + this.update = function() { this.updateSmoothedTrigger(); @@ -360,7 +436,7 @@ function MyController(hand) { }; this.setState = function(newState) { - if (WANT_DEBUG) { + if (WANT_DEBUG || WANT_DEBUG_STATE) { print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand); } this.state = newState; @@ -1686,7 +1762,7 @@ function MyController(hand) { }, angularVelocity: { x: 0, - y: 0, + y: 0, z: 0 } }) @@ -1713,6 +1789,11 @@ function MyController(hand) { Entities.deleteEntity(this.particleBeam); Entities.deleteEntity(this.spotLight); Entities.deleteEntity(this.pointLight); + + if (this.animHandlerId) { + MyAvatar.removeAnimationStateHandler(this.animHandlerId); + this.animHandlerId = undefined; + } }; this.activateEntity = function(entityID, grabbedProperties) { diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index d63942c510..39e8dbb84a 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -168,7 +168,7 @@ "interpDuration": 3, "transitions": [ { "var": "isRightHandIdle", "state": "rightHandIdle" }, - { "var": "isRightHandPoint_DISABLED", "state": "rightHandPointHold" } + { "var": "isRightHandPoint", "state": "rightHandPointHold" } ] } ] @@ -264,7 +264,7 @@ "data": { "alpha": 1.0, "boneSet": "leftHand", - "alphaVar" : "leftHandOverlay" + "alphaVar" : "leftHandOverlayAlpha" }, "children": [ { @@ -317,7 +317,7 @@ "interpDuration": 3, "transitions": [ { "var": "isLeftHandIdle", "state": "leftHandIdle" }, - { "var": "isLeftHandPoint_DISABLED", "state": "leftHandPointHold" } + { "var": "isLeftHandPoint", "state": "leftHandPointHold" } ] } ] diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index c6060d791a..8567945a87 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -981,6 +981,7 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) { _animVars.set("rightHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition); } + /* // set leftHand grab vars _animVars.set("isLeftHandIdle", false); _animVars.set("isLeftHandPoint", false); @@ -1019,6 +1020,7 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) { _rightHandOverlayAlpha = glm::clamp(_rightHandOverlayAlpha + (rampOut ? -1.0f : 1.0f) * OVERLAY_RAMP_OUT_SPEED * dt, 0.0f, 1.0f); _animVars.set("rightHandOverlayAlpha", _rightHandOverlayAlpha); _animVars.set("rightHandGrabBlend", params.rightTrigger); + */ } } From 9bc661adc8e98f13d818ae0e22c43a78b39acdd8 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 6 Jan 2016 11:42:58 -0800 Subject: [PATCH 021/215] Cleanup for style/dead code --- .../render-utils/src/MeshPartPayload.cpp | 38 +++++++++---------- libraries/render-utils/src/MeshPartPayload.h | 6 +-- .../render-utils/src/RenderDeferredTask.h | 18 ++++++--- libraries/render-utils/src/ShapeRender.cpp | 3 +- libraries/render-utils/src/ShapeRender.h | 5 ++- libraries/render/src/render/DrawTask.cpp | 4 +- libraries/render/src/render/DrawTask.h | 8 +--- libraries/render/src/render/Scene.h | 5 ++- libraries/render/src/render/Shape.h | 36 ++++++++++-------- 9 files changed, 67 insertions(+), 56 deletions(-) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 53feaa5a44..7b1f6887f1 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -129,14 +129,14 @@ void MeshPartPayload::bindMesh(gpu::Batch& batch) const { } } -void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations) const { +void MeshPartPayload::bindMaterial(gpu::Batch& batch, const Shape::Pipeline::LocationsPointer locations) const { if (!_drawMaterial) { return; } auto textureCache = DependencyManager::get(); - batch.setUniformBuffer(ShapePipeline::Slot::MATERIAL_GPU, _drawMaterial->getSchemaBuffer()); + batch.setUniformBuffer(Shape::Pipeline::Slot::MATERIAL_GPU, _drawMaterial->getSchemaBuffer()); auto materialKey = _drawMaterial->getKey(); auto textureMaps = _drawMaterial->getTextureMaps(); @@ -146,44 +146,44 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isDiffuseMap()) { auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP]; if (diffuseMap && diffuseMap->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::DIFFUSE_MAP, diffuseMap->getTextureView()); + batch.setResourceTexture(Shape::Pipeline::Slot::DIFFUSE_MAP, diffuseMap->getTextureView()); if (!diffuseMap->getTextureTransform().isIdentity()) { diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]); } } else { - batch.setResourceTexture(ShapePipeline::Slot::DIFFUSE_MAP, textureCache->getGrayTexture()); + batch.setResourceTexture(Shape::Pipeline::Slot::DIFFUSE_MAP, textureCache->getGrayTexture()); } } else { - batch.setResourceTexture(ShapePipeline::Slot::DIFFUSE_MAP, textureCache->getWhiteTexture()); + batch.setResourceTexture(Shape::Pipeline::Slot::DIFFUSE_MAP, textureCache->getWhiteTexture()); } // Normal map if (materialKey.isNormalMap()) { auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP]; if (normalMap && normalMap->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::NORMAL_MAP, normalMap->getTextureView()); + batch.setResourceTexture(Shape::Pipeline::Slot::NORMAL_MAP, normalMap->getTextureView()); // texcoord are assumed to be the same has diffuse } else { - batch.setResourceTexture(ShapePipeline::Slot::NORMAL_MAP, textureCache->getBlueTexture()); + batch.setResourceTexture(Shape::Pipeline::Slot::NORMAL_MAP, textureCache->getBlueTexture()); } } else { - batch.setResourceTexture(ShapePipeline::Slot::NORMAL_MAP, nullptr); + batch.setResourceTexture(Shape::Pipeline::Slot::NORMAL_MAP, nullptr); } // TODO: For now gloss map is used as the "specular map in the shading, we ll need to fix that if (materialKey.isGlossMap()) { auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP]; if (specularMap && specularMap->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, specularMap->getTextureView()); + batch.setResourceTexture(Shape::Pipeline::Slot::SPECULAR_MAP, specularMap->getTextureView()); // texcoord are assumed to be the same has diffuse } else { - batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, textureCache->getBlackTexture()); + batch.setResourceTexture(Shape::Pipeline::Slot::SPECULAR_MAP, textureCache->getBlackTexture()); } } else { - batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, nullptr); + batch.setResourceTexture(Shape::Pipeline::Slot::SPECULAR_MAP, nullptr); } // TODO: For now lightmaop is piped into the emissive map unit, we need to fix that and support for real emissive too @@ -191,7 +191,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP]; if (lightmapMap && lightmapMap->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::LIGHTMAP_MAP, lightmapMap->getTextureView()); + batch.setResourceTexture(Shape::Pipeline::Slot::LIGHTMAP_MAP, lightmapMap->getTextureView()); auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale(); batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y); @@ -200,10 +200,10 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]); } } else { - batch.setResourceTexture(ShapePipeline::Slot::LIGHTMAP_MAP, textureCache->getGrayTexture()); + batch.setResourceTexture(Shape::Pipeline::Slot::LIGHTMAP_MAP, textureCache->getGrayTexture()); } } else { - batch.setResourceTexture(ShapePipeline::Slot::LIGHTMAP_MAP, nullptr); + batch.setResourceTexture(Shape::Pipeline::Slot::LIGHTMAP_MAP, nullptr); } // Texcoord transforms ? @@ -212,7 +212,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat } } -void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations) const { +void MeshPartPayload::bindTransform(gpu::Batch& batch, const Shape::Pipeline::LocationsPointer locations) const { batch.setModelTransform(_drawTransform); } @@ -377,7 +377,7 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { int vertexCount = mesh.vertices.size(); if (vertexCount == 0) { // sanity check - return ShapeKey::Builder::invalid(); + return ShapeKey::Builder::invalid(); // FIXME } @@ -431,16 +431,16 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) const { } } -void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations) const { +void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const Shape::Pipeline::LocationsPointer locations) const { // Still relying on the raw data from the model const Model::MeshState& state = _model->_meshStates.at(_meshIndex); Transform transform; if (state.clusterBuffer) { if (_model->_cauterizeBones) { - batch.setUniformBuffer(ShapePipeline::Slot::SKINNING_GPU, state.cauterizedClusterBuffer); + batch.setUniformBuffer(Shape::Pipeline::Slot::SKINNING_GPU, state.cauterizedClusterBuffer); } else { - batch.setUniformBuffer(ShapePipeline::Slot::SKINNING_GPU, state.clusterBuffer); + batch.setUniformBuffer(Shape::Pipeline::Slot::SKINNING_GPU, state.clusterBuffer); } } else { if (_model->_cauterizeBones) { diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 7d693dcbe9..1e6e6214ae 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -46,8 +46,8 @@ public: // ModelMeshPartPayload functions to perform render void drawCall(gpu::Batch& batch) const; virtual void bindMesh(gpu::Batch& batch) const; - virtual void bindMaterial(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations) const; - virtual void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations) const; + virtual void bindMaterial(gpu::Batch& batch, const render::Shape::Pipeline::LocationsPointer locations) const; + virtual void bindTransform(gpu::Batch& batch, const render::Shape::Pipeline::LocationsPointer locations) const; // Payload resource cached values model::MeshPointer _drawMesh; @@ -89,7 +89,7 @@ public: // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch) const override; - void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations) const override; + void bindTransform(gpu::Batch& batch, const render::Shape::Pipeline::LocationsPointer locations) const override; void initCache(); diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 051f19c133..01e9ab2a16 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -51,29 +51,35 @@ public: }; class DrawOpaqueDeferred { - ShapeRender _renderer; public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems); typedef render::Job::ModelI JobModel; + +protected: + ShapeRender _renderer; }; class DrawTransparentDeferred { - ShapeRender _renderer; public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems); typedef render::Job::ModelI JobModel; + +protected: + ShapeRender _renderer; }; class DrawStencilDeferred { - static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable public: static const gpu::PipelinePointer& getOpaquePipeline(); void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); typedef render::Job::Model JobModel; + +protected: + static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable }; class DrawBackgroundDeferred { @@ -84,14 +90,16 @@ public: }; class DrawOverlay3D { - static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable - ShapeRender _renderer; public: static const gpu::PipelinePointer& getOpaquePipeline(); void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); typedef render::Job::Model JobModel; + +protected: + static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable + ShapeRender _renderer; }; class Blit { diff --git a/libraries/render-utils/src/ShapeRender.cpp b/libraries/render-utils/src/ShapeRender.cpp index c68664b69a..c4ac9f3c2b 100644 --- a/libraries/render-utils/src/ShapeRender.cpp +++ b/libraries/render-utils/src/ShapeRender.cpp @@ -38,7 +38,8 @@ #include "model_translucent_frag.h" ShapeRender::ShapeRender() { - // TODO: There is probably a cleaner way to init the pipeline that in a derived class + // TODO: Move pipeline initialization to those Jobs using ShapeRender + // such that they own their own pipelines and it is done only once if (_pipelineLib.empty()) { initPipeline(); } diff --git a/libraries/render-utils/src/ShapeRender.h b/libraries/render-utils/src/ShapeRender.h index a3f131f21d..fc174896bb 100644 --- a/libraries/render-utils/src/ShapeRender.h +++ b/libraries/render-utils/src/ShapeRender.h @@ -16,14 +16,15 @@ #include class ShapeRender : public render::Shape { - static model::MaterialPointer _collisionHullMaterial; - public: ShapeRender(); static void initPipeline(); const PipelinePointer pickPipeline(RenderArgs* args, const Key& key) const override; static model::MaterialPointer getCollisionHullMaterial(); + +protected: + static model::MaterialPointer _collisionHullMaterial; }; #endif // hifi_render_utils_Shape_h diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index f66b6461b9..83caaa72b7 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -223,12 +223,12 @@ void render::renderLights(const SceneContextPointer& sceneContext, const RenderC void renderShape(RenderArgs* args, const Shape& shapeContext, Item& item) { assert(item.getKey().isShape()); const auto& key = item.getShapeKey(); - if (key.isValid() && key.hasPipeline()) { + if (key.isValid() && !key.hasOwnPipeline()) { args->_pipeline = shapeContext.pickPipeline(args, key); if (args->_pipeline) { item.render(args); } - } else if (!key.hasPipeline()) { + } else if (key.hasOwnPipeline()) { item.render(args); } else { qDebug() << "Item could not be rendered: invalid key ?" << key; diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index d3741a07a7..eef4247b17 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -103,12 +103,6 @@ public: } public: - class Context { - public: - virtual const ShapePipeline pickPipeline(RenderArgs* args, const ShapeKey& key) = 0; - }; - using ContextPointer = std::shared_ptr; - class Concept { std::string _name; bool _isEnabled = true; @@ -274,7 +268,7 @@ public: typedef Job::ModelIO JobModel; }; -class DrawLight : public Shape { +class DrawLight { public: void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index 90625dfd14..bff75ebcd8 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -350,7 +350,10 @@ template int payloadGetLayer(const std::shared_ptr& payloadData) { template void payloadRender(const std::shared_ptr& payloadData, RenderArgs* args) { } // Shape type interface -template const ShapeKey shapeGetShapeKey(const std::shared_ptr& payloadData) { return ShapeKey::Builder::noPipeline(); } +// This allows shapes to characterize their pipeline via a ShapeKey, to be picked with a subclass of Shape. +// When creating a new shape payload you need to create a specialized version, or the ShapeKey will be ownPipeline, +// implying that the shape will setup its own pipeline without the use of the ShapeKey. +template const ShapeKey shapeGetShapeKey(const std::shared_ptr& payloadData) { return ShapeKey::Builder::ownPipeline(); } template class Payload : public Item::PayloadInterface { public: diff --git a/libraries/render/src/render/Shape.h b/libraries/render/src/render/Shape.h index 8fc93d76af..4950af1da4 100644 --- a/libraries/render/src/render/Shape.h +++ b/libraries/render/src/render/Shape.h @@ -31,7 +31,7 @@ public: SHADOW, WIREFRAME, - NO_PIPELINE, + OWN_PIPELINE, INVALID, NUM_FLAGS, // Not a valid flag @@ -62,10 +62,10 @@ public: Builder& withDepthOnly() { _flags.set(DEPTH_ONLY); return (*this); } Builder& withShadow() { _flags.set(SHADOW); return (*this); } Builder& withWireframe() { _flags.set(WIREFRAME); return (*this); } - Builder& withoutPipeline() { _flags.set(NO_PIPELINE); return (*this); } + Builder& withOwnPipeline() { _flags.set(OWN_PIPELINE); return (*this); } Builder& invalidate() { _flags.set(INVALID); return (*this); } - static const ShapeKey noPipeline() { return Builder().withoutPipeline(); } + static const ShapeKey ownPipeline() { return Builder().withOwnPipeline(); } static const ShapeKey invalid() { return Builder().invalidate(); } }; ShapeKey(const Builder& builder) : ShapeKey(builder._flags) {} @@ -81,7 +81,7 @@ public: bool isShadow() const { return _flags[SHADOW]; } bool isWireFrame() const { return _flags[WIREFRAME]; } - bool hasPipeline() const { return !_flags[NO_PIPELINE]; } + bool hasOwnPipeline() const { return _flags[OWN_PIPELINE]; } bool isValid() const { return !_flags[INVALID]; } // Hasher for use in unordered_maps @@ -101,18 +101,22 @@ public: inline QDebug operator<<(QDebug debug, const ShapeKey& renderKey) { if (renderKey.isValid()) { - debug << "[ShapeKey:" - << "hasLightmap:" << renderKey.hasLightmap() - << "hasTangents:" << renderKey.hasTangents() - << "hasSpecular:" << renderKey.hasSpecular() - << "hasEmissive:" << renderKey.hasEmissive() - << "isTranslucent:" << renderKey.isTranslucent() - << "isSkinned:" << renderKey.isSkinned() - << "isStereo:" << renderKey.isStereo() - << "isDepthOnly:" << renderKey.isDepthOnly() - << "isShadow:" << renderKey.isShadow() - << "isWireFrame:" << renderKey.isWireFrame() - << "]"; + if (renderKey.hasOwnPipeline()) { + debug << "[ShapeKey: OWN_PIPELINE]"; + } else { + debug << "[ShapeKey:" + << "hasLightmap:" << renderKey.hasLightmap() + << "hasTangents:" << renderKey.hasTangents() + << "hasSpecular:" << renderKey.hasSpecular() + << "hasEmissive:" << renderKey.hasEmissive() + << "isTranslucent:" << renderKey.isTranslucent() + << "isSkinned:" << renderKey.isSkinned() + << "isStereo:" << renderKey.isStereo() + << "isDepthOnly:" << renderKey.isDepthOnly() + << "isShadow:" << renderKey.isShadow() + << "isWireFrame:" << renderKey.isWireFrame() + << "]"; + } } else { debug << "[ShapeKey: INVALID]"; } From b68572fdd09929ee0860c66cf5a9c746a43163c8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 6 Jan 2016 11:43:17 -0800 Subject: [PATCH 022/215] Cleanup renderShapes render loop --- libraries/render/src/render/DrawTask.cpp | 26 ++++++++---------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index f66b6461b9..f5fe5899c2 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -235,26 +235,16 @@ void renderShape(RenderArgs* args, const Shape& shapeContext, Item& item) { } } -void render::renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Shape& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems) { +void render::renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, + const Shape& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems) { auto& scene = sceneContext->_scene; RenderArgs* args = renderContext->getArgs(); - - if ((maxDrawnItems < 0) || (maxDrawnItems > (int)inItems.size())) { - for (const auto& itemDetails : inItems) { - // FIXME: Every item is copied because item.render cannot mutate a const - auto item = scene->getItem(itemDetails.id); - renderShape(args, shapeContext, item); - } - } else { - int numItems = 0; - for (const auto& itemDetails : inItems) { - numItems++; - auto item = scene->getItem(itemDetails.id); - renderShape(args, shapeContext, item); - if (numItems >= maxDrawnItems) { - break; - } - } + + auto numItemsToDraw = glm::max((int)inItems.size(), maxDrawnItems); + for (auto i = 0; i < numItemsToDraw; ++i) { + // FIXME: Every item is copied because item.render cannot mutate a const + auto item = scene->getItem(inItems[i].id); + renderShape(args, shapeContext, item); } } From b42fe22e038b9630bcf1f975db3a22c93a398fc7 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 6 Jan 2016 16:26:16 -0800 Subject: [PATCH 023/215] Fixing bad line ending. --- examples/controllers/handControllerGrab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 8095ebc81b..7b1dac8b64 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1762,7 +1762,7 @@ function MyController(hand) { }, angularVelocity: { x: 0, - y: 0, + y: 0, z: 0 } }) From dfc3f02db301bf97540fc0de483794522b040e53 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 6 Jan 2016 18:15:32 -0800 Subject: [PATCH 024/215] avatar-animation.json: Removed point outro state. Also replaced right hand point with force grab animation. --- .../defaultAvatar_full/avatar-animation.json | 62 +++---------------- 1 file changed, 9 insertions(+), 53 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index 39e8dbb84a..38cbbaa867 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -139,8 +139,8 @@ "interpDuration": 3, "transitions": [ { "var": "isRightHandIdle", "state": "rightHandIdle" }, - { "var": "isRightHandPointIntroOnDone", "state": "rightHandPointHold" }, - { "var": "isRightHandGrab", "state": "rightHandGrab" } + { "var": "isRightHandGrab", "state": "rightHandGrab" }, + { "var": "isRightHandPointIntroOnDone", "state": "rightHandPointHold" } ] }, { @@ -148,20 +148,10 @@ "interpTarget": 3, "interpDuration": 3, "transitions": [ - { "var": "isRightHandIdle", "state": "rightHandPointOutro" }, + { "var": "isRightHandIdle", "state": "rightHandIdle" }, { "var": "isRightHandGrab", "state": "rightHandGrab" } ] }, - { - "id": "rightHandPointOutro", - "interpTarget": 3, - "interpDuration": 3, - "transitions": [ - { "var": "isRightHandPointOutroOnDone", "state": "rightHandIdle" }, - { "var": "isRightHandGrab", "state": "rightHandGrab" }, - { "var": "isRightHandPoint", "state": "rightHandPointHold" } - ] - }, { "id": "rightHandGrab", "interpTarget": 3, @@ -190,9 +180,9 @@ "id": "rightHandPointHold", "type": "clip", "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_right_hand.fbx", + "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/force_grab_right.fbx", "startFrame": 12.0, - "endFrame": 12.0, + "endFrame": 35.0, "timeScale": 1.0, "loopFlag": true }, @@ -202,7 +192,7 @@ "id": "rightHandPointIntro", "type": "clip", "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_right_hand.fbx", + "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/force_grab_right.fbx", "startFrame": 0.0, "endFrame": 12.0, "timeScale": 1.0, @@ -210,18 +200,6 @@ }, "children": [] }, - { - "id": "rightHandPointOutro", - "type": "clip", - "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_right_hand.fbx", - "startFrame": 12.0, - "endFrame": 65.0, - "timeScale": 1.0, - "loopFlag": false - }, - "children": [] - }, { "id": "rightHandGrab", "type": "blendLinear", @@ -288,8 +266,8 @@ "interpDuration": 3, "transitions": [ { "var": "isLeftHandIdle", "state": "leftHandIdle" }, - { "var": "isLeftHandPointIntroOnDone", "state": "leftHandPointHold" }, - { "var": "isLeftHandGrab", "state": "leftHandGrab" } + { "var": "isLeftHandGrab", "state": "leftHandGrab" }, + { "var": "isLeftHandPointIntroOnDone", "state": "leftHandPointHold" } ] }, { @@ -297,20 +275,10 @@ "interpTarget": 3, "interpDuration": 3, "transitions": [ - { "var": "isLeftHandIdle", "state": "leftHandPointOutro" }, + { "var": "isLeftHandIdle", "state": "leftHandIdle" }, { "var": "isLeftHandGrab", "state": "leftHandGrab" } ] }, - { - "id": "leftHandPointOutro", - "interpTarget": 3, - "interpDuration": 3, - "transitions": [ - { "var": "isLeftHandPointOutroOnDone", "state": "leftHandIdle" }, - { "var": "isLeftHandGrab", "state": "leftHandGrab" }, - { "var": "isLeftHandPoint", "state": "leftHandPointHold" } - ] - }, { "id": "leftHandGrab", "interpTarget": 3, @@ -359,18 +327,6 @@ }, "children": [] }, - { - "id": "leftHandPointOutro", - "type": "clip", - "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_left_hand.fbx", - "startFrame": 12.0, - "endFrame": 65.0, - "timeScale": 1.0, - "loopFlag": false - }, - "children": [] - }, { "id": "leftHandGrab", "type": "blendLinear", From 9b4a395f6b592de7de9b4d7e61945067748705ed Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 6 Jan 2016 18:18:21 -0800 Subject: [PATCH 025/215] Promote render::Job to render::Task::Job --- .../render-utils/src/AmbientOcclusionEffect.h | 2 +- .../render-utils/src/AntialiasingEffect.h | 2 +- .../render-utils/src/DebugDeferredBuffer.h | 2 +- libraries/render-utils/src/HitEffect.h | 2 +- .../render-utils/src/RenderDeferredTask.cpp | 46 ++-- .../render-utils/src/RenderDeferredTask.h | 24 +- libraries/render/src/render/Context.cpp | 30 +++ libraries/render/src/render/Context.h | 112 +++++++++ libraries/render/src/render/DrawStatus.h | 2 +- libraries/render/src/render/DrawTask.cpp | 27 +-- libraries/render/src/render/DrawTask.h | 221 +---------------- libraries/render/src/render/Engine.cpp | 18 +- libraries/render/src/render/Engine.h | 110 +-------- libraries/render/src/render/Task.h | 229 ++++++++++++++++++ 14 files changed, 428 insertions(+), 399 deletions(-) create mode 100644 libraries/render/src/render/Context.cpp create mode 100644 libraries/render/src/render/Context.h create mode 100644 libraries/render/src/render/Task.h diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 6153795ea6..55970a2d6e 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -22,7 +22,7 @@ public: AmbientOcclusion(); void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); - typedef render::Job::Model JobModel; + using JobModel = render::Task::Job::Model; const gpu::PipelinePointer& getOcclusionPipeline(); const gpu::PipelinePointer& getHBlurPipeline(); diff --git a/libraries/render-utils/src/AntialiasingEffect.h b/libraries/render-utils/src/AntialiasingEffect.h index c7cce4cb15..51a8e3a1de 100644 --- a/libraries/render-utils/src/AntialiasingEffect.h +++ b/libraries/render-utils/src/AntialiasingEffect.h @@ -22,7 +22,7 @@ public: Antialiasing(); void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); - typedef render::Job::Model JobModel; + using JobModel = render::Task::Job::Model; const gpu::PipelinePointer& getAntialiasingPipeline(); const gpu::PipelinePointer& getBlendPipeline(); diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index 682888b2af..c9ea24644a 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -18,7 +18,7 @@ class DebugDeferredBuffer { public: - using JobModel = render::Job::Model; + using JobModel = render::Task::Job::Model; DebugDeferredBuffer(); diff --git a/libraries/render-utils/src/HitEffect.h b/libraries/render-utils/src/HitEffect.h index 0a96a5300d..a83fb36693 100644 --- a/libraries/render-utils/src/HitEffect.h +++ b/libraries/render-utils/src/HitEffect.h @@ -17,7 +17,7 @@ public: HitEffect(); void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); - typedef render::Job::Model JobModel; + using JobModel = render::Task::Job::Model; const gpu::PipelinePointer& getHitEffectPipeline(); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 1b1d08f353..9c286ba204 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -51,63 +51,63 @@ void ToneMappingDeferred::run(const SceneContextPointer& sceneContext, const Ren RenderDeferredTask::RenderDeferredTask() : Task() { // CPU only, create the list of renderedOpaques items - _jobs.push_back(Job(new FetchItems::JobModel("FetchOpaque", + addJob("FetchOpaque", std::make_shared( FetchItems([](const RenderContextPointer& context, int count) { context->getItemsConfig().opaque.numFeed = count; }) - ))); - _jobs.push_back(Job(new CullItemsOpaque::JobModel("CullOpaque", _jobs.back().getOutput()))); - _jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortOpaque", _jobs.back().getOutput()))); + )); + addJob("CullOpaque", std::make_shared(_jobs.back().getOutput())); + addJob("DepthSortOpaque", std::make_shared(_jobs.back().getOutput())); auto& renderedOpaques = _jobs.back().getOutput(); // CPU only, create the list of renderedTransparents items - _jobs.push_back(Job(new FetchItems::JobModel("FetchTransparent", + addJob("FetchTransparent", std::make_shared( FetchItems(ItemFilter::Builder::transparentShape().withoutLayered(), [](const RenderContextPointer& context, int count) { context->getItemsConfig().transparent.numFeed = count; }) - ))); - _jobs.push_back(Job(new CullItemsTransparent::JobModel("CullTransparent", _jobs.back().getOutput()))); - _jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false)))); + )); + addJob("CullTransparent", std::make_shared(_jobs.back().getOutput())); + addJob("DepthSortTransparent", std::make_shared(_jobs.back().getOutput(), DepthSortItems(false))); auto& renderedTransparents = _jobs.back().getOutput(); // GPU Jobs: Start preparing the deferred and lighting buffer - _jobs.push_back(Job(new PrepareDeferred::JobModel("PrepareDeferred"))); + addJob("PrepareDeferred", std::make_shared()); // Render opaque objects in DeferredBuffer - _jobs.push_back(Job(new DrawOpaqueDeferred::JobModel("DrawOpaqueDeferred", renderedOpaques))); + addJob("DrawOpaqueDeferred", std::make_shared(renderedOpaques)); // Once opaque is all rendered create stencil background - _jobs.push_back(Job(new DrawStencilDeferred::JobModel("DrawOpaqueStencil"))); + addJob("DrawOpaqueStencil", std::make_shared()); // Use Stencil and start drawing background in Lighting buffer - _jobs.push_back(Job(new DrawBackgroundDeferred::JobModel("DrawBackgroundDeferred"))); + addJob("DrawBackgroundDeferred", std::make_shared()); // Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now. - _jobs.push_back(Job(new DrawLight::JobModel("DrawLight"))); + addJob("DrawLight", std::make_shared()); // DeferredBuffer is complete, now let's shade it into the LightingBuffer - _jobs.push_back(Job(new RenderDeferred::JobModel("RenderDeferred"))); + addJob("RenderDeferred", std::make_shared()); // AO job, to be revisited - _jobs.push_back(Job(new AmbientOcclusion::JobModel("AmbientOcclusion"))); + addJob("AmbientOcclusion", std::make_shared()); _jobs.back().setEnabled(false); _occlusionJobIndex = (int)_jobs.size() - 1; // AA job to be revisited - _jobs.push_back(Job(new Antialiasing::JobModel("Antialiasing"))); + addJob("Antialiasing", std::make_shared()); _jobs.back().setEnabled(false); _antialiasingJobIndex = (int)_jobs.size() - 1; // Render transparent objects forward in LigthingBuffer - _jobs.push_back(Job(new DrawTransparentDeferred::JobModel("TransparentDeferred", renderedTransparents))); + addJob("TransparentDeferred", std::make_shared(renderedTransparents)); // Lighting Buffer ready for tone mapping - _jobs.push_back(Job(new ToneMappingDeferred::JobModel("ToneMapping"))); + addJob("ToneMapping", std::make_shared()); _toneMappingJobIndex = (int)_jobs.size() - 1; // Debugging Deferred buffer job - _jobs.push_back(Job(new DebugDeferredBuffer::JobModel("DebugDeferredBuffer"))); + addJob("DebugDeferredBuffer", std::make_shared()); _jobs.back().setEnabled(false); _drawDebugDeferredBufferIndex = (int)_jobs.size() - 1; @@ -116,18 +116,18 @@ RenderDeferredTask::RenderDeferredTask() : Task() { // Grab a texture map representing the different status icons and assign that to the drawStatsuJob auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg"; auto statusIconMap = DependencyManager::get()->getImageTexture(iconMapPath); - _jobs.push_back(Job(new render::DrawStatus::JobModel("DrawStatus", renderedOpaques, DrawStatus(statusIconMap)))); + addJob("DrawStatus", std::make_shared(renderedOpaques, DrawStatus(statusIconMap))); _jobs.back().setEnabled(false); _drawStatusJobIndex = (int)_jobs.size() - 1; } - _jobs.push_back(Job(new DrawOverlay3D::JobModel("DrawOverlay3D"))); + addJob("DrawOverlay3D", std::make_shared()); - _jobs.push_back(Job(new HitEffect::JobModel("HitEffect"))); + addJob("HitEffect", std::make_shared()); _jobs.back().setEnabled(false); _drawHitEffectJobIndex = (int)_jobs.size() -1; - _jobs.push_back(Job(new Blit::JobModel("Blit"))); + addJob("Blit", std::make_shared()); } RenderDeferredTask::~RenderDeferredTask() { diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 051faa3238..330a1cceae 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -22,14 +22,14 @@ class SetupDeferred { public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); - typedef render::Job::Model JobModel; + using JobModel = render::Task::Job::Model; }; class PrepareDeferred { public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); - typedef render::Job::Model JobModel; + using JobModel = render::Task::Job::Model; }; @@ -37,7 +37,7 @@ class RenderDeferred { public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); - typedef render::Job::Model JobModel; + using JobModel = render::Task::Job::Model; }; class ToneMappingDeferred { @@ -46,21 +46,21 @@ public: ToneMappingEffect _toneMappingEffect; - typedef render::Job::Model JobModel; + using JobModel = render::Task::Job::Model; }; class DrawOpaqueDeferred { public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems); - typedef render::Job::ModelI JobModel; + using JobModel = render::Task::Job::ModelI; }; class DrawTransparentDeferred { public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems); - typedef render::Job::ModelI JobModel; + using JobModel = render::Task::Job::ModelI; }; class DrawStencilDeferred { @@ -70,14 +70,14 @@ public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); - typedef render::Job::Model JobModel; + using JobModel = render::Task::Job::Model; }; class DrawBackgroundDeferred { public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); - typedef render::Job::Model JobModel; + using JobModel = render::Task::Job::Model; }; class DrawOverlay3D { @@ -86,15 +86,15 @@ public: static const gpu::PipelinePointer& getOpaquePipeline(); void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); - - typedef render::Job::Model JobModel; + + using JobModel = render::Task::Job::Model; }; class Blit { public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); - typedef render::Job::Model JobModel; + using JobModel = render::Task::Job::Model; }; class RenderDeferredTask : public render::Task { @@ -103,7 +103,7 @@ public: RenderDeferredTask(); ~RenderDeferredTask(); - render::Jobs _jobs; + render::Task::Jobs _jobs; int _drawDebugDeferredBufferIndex = -1; int _drawStatusJobIndex = -1; diff --git a/libraries/render/src/render/Context.cpp b/libraries/render/src/render/Context.cpp new file mode 100644 index 0000000000..4f7895e4fc --- /dev/null +++ b/libraries/render/src/render/Context.cpp @@ -0,0 +1,30 @@ +// +// Context.cpp +// render/src/render +// +// Created by Zach Pomerantz on 1/6/2015. +// 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 "Context.h" + +using namespace render; + +RenderContext::RenderContext(ItemsConfig items, Tone tone, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode) + : _deferredDebugMode{ deferredDebugMode }, _deferredDebugSize{ deferredDebugSize }, + _args{ nullptr }, + _drawStatus{ drawStatus }, _drawHitEffect{ drawHitEffect }, + _items{ items }, _tone{ tone } {} + +void RenderContext::setOptions(bool occlusion, bool fxaa, bool showOwned) { + _occlusionStatus = occlusion; + _fxaaStatus = fxaa; + + if (showOwned) { + _drawStatus |= render::showNetworkStatusFlag; + } +}; + diff --git a/libraries/render/src/render/Context.h b/libraries/render/src/render/Context.h new file mode 100644 index 0000000000..5f8ca60ddb --- /dev/null +++ b/libraries/render/src/render/Context.h @@ -0,0 +1,112 @@ +// +// Engine.h +// render/src/render +// +// Created by Zach Pomerantz on 1/6/2015. +// 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_render_Context_h +#define hifi_render_Context_h + +#include "Scene.h" + +namespace render { + +class SceneContext { +public: + ScenePointer _scene; + + SceneContext() {} +}; +using SceneContextPointer = std::shared_ptr; + +// see examples/utilities/tools/renderEngineDebug.js +const int showDisplayStatusFlag = 1; +const int showNetworkStatusFlag = 2; + +class RenderContext { +public: + class ItemsConfig { + public: + class Counter { + public: + Counter() {}; + Counter(const Counter& counter) { + numFeed = numDrawn = 0; + maxDrawn = counter.maxDrawn; + }; + + void setCounts(const Counter& counter) { + numFeed = counter.numFeed; + numDrawn = counter.numDrawn; + }; + + int numFeed = 0; + int numDrawn = 0; + int maxDrawn = -1; + }; + + class State : public Counter { + public: + bool render = true; + bool cull = true; + bool sort = true; + + Counter counter{}; + }; + + ItemsConfig(State opaqueState, State transparentState, Counter overlay3DCounter) + : opaque{ opaqueState }, transparent{ transparentState }, overlay3D{ overlay3DCounter } {} + ItemsConfig() : ItemsConfig{ {}, {}, {} } {} + + // TODO: If member count increases, store counters in a map instead of multiple members + State opaque{}; + State transparent{}; + Counter overlay3D{}; + }; + + class Tone { + public: + int toneCurve = 1; // Means just Gamma 2.2 correction + float exposure = 0.0; + }; + + RenderContext(ItemsConfig items, Tone tone, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode); + RenderContext() : RenderContext({}, {}, {}, {}, {}, {}) {}; + + void setArgs(RenderArgs* args) { _args = args; } + inline RenderArgs* getArgs() { return _args; } + inline ItemsConfig& getItemsConfig() { return _items; } + inline Tone& getTone() { return _tone; } + inline int getDrawStatus() { return _drawStatus; } + inline bool getDrawHitEffect() { return _drawHitEffect; } + inline bool getOcclusionStatus() { return _occlusionStatus; } + inline bool getFxaaStatus() { return _fxaaStatus; } + void setOptions(bool occlusion, bool fxaa, bool showOwned); + + // Debugging + int _deferredDebugMode; + glm::vec4 _deferredDebugSize; + +protected: + RenderArgs* _args; + + // Options + int _drawStatus; // bitflag + bool _drawHitEffect; + bool _occlusionStatus = false; + bool _fxaaStatus = false; + + ItemsConfig _items; + Tone _tone; +}; +typedef std::shared_ptr RenderContextPointer; + +} + +#endif // hifi_render_Context_h + diff --git a/libraries/render/src/render/DrawStatus.h b/libraries/render/src/render/DrawStatus.h index 1239819911..c9cf16c0cb 100644 --- a/libraries/render/src/render/DrawStatus.h +++ b/libraries/render/src/render/DrawStatus.h @@ -38,7 +38,7 @@ namespace render { void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems); - typedef Job::ModelI JobModel; + using JobModel = Task::Job::ModelI; const gpu::PipelinePointer getDrawItemBoundsPipeline(); const gpu::PipelinePointer getDrawItemStatusPipeline(); diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 44ba57143f..6b35e06a92 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -22,11 +22,9 @@ using namespace render; -DrawSceneTask::DrawSceneTask() : Task() { -} +DrawSceneTask::DrawSceneTask() : Task() {} -DrawSceneTask::~DrawSceneTask() { -} +DrawSceneTask::~DrawSceneTask() {} void DrawSceneTask::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { // sanity checks @@ -35,7 +33,6 @@ void DrawSceneTask::run(const SceneContextPointer& sceneContext, const RenderCon return; } - // Is it possible that we render without a viewFrustum ? if (!(renderContext->getArgs() && renderContext->getArgs()->_viewFrustum)) { return; @@ -46,13 +43,6 @@ void DrawSceneTask::run(const SceneContextPointer& sceneContext, const RenderCon } }; -Job::~Job() { -} - - - - - void render::cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { assert(renderContext->getArgs()); assert(renderContext->getArgs()->_viewFrustum); @@ -297,16 +287,3 @@ void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderCo }); args->_batch = nullptr; } - -void ItemMaterialBucketMap::insert(const ItemID& id, const model::MaterialKey& key) { - // Insert the itemID in every bucket where it filters true - for (auto& bucket : (*this)) { - if (bucket.first.test(key)) { - bucket.second.push_back(id); - } - } -} - -void ItemMaterialBucketMap::allocateStandardMaterialBuckets() { - (*this)[model::MaterialFilter::Builder::opaqueDiffuse()]; -} diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index ab102e32a7..3027cde73f 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -9,217 +9,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_render_Task_h -#define hifi_render_Task_h +#ifndef hifi_render_DrawTask_h +#define hifi_render_DrawTask_h #include "Engine.h" #include "gpu/Batch.h" -#include namespace render { -template void jobRun(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - jobModel.run(sceneContext, renderContext); -} -template void jobRunI(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const I& input) { - jobModel.run(sceneContext, renderContext, input); -} -template void jobRunO(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, O& output) { - jobModel.run(sceneContext, renderContext, output); -} -template void jobRunIO(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const I& input, O& output) { - jobModel.run(sceneContext, renderContext, input, output); -} - -class Job { -public: - - // Varying represent a varying piece of data - class Varying { - public: - - Varying(const Varying& var): _concept(var._concept) {} - - Varying() {} - template - Varying(const T& data) : _concept(std::make_shared>(data)) {} - - // Access the _data contained win the concept explicitely - template T& edit() { return std::static_pointer_cast>(_concept)->_data; } - template const T& get() const { return std::static_pointer_cast>(_concept)->_data; } - - protected: - friend class Job; - - std::vector> _consumerJobs; - - void addJobConsumer(const std::shared_ptr& job) { - _consumerJobs.push_back(job); - } - - class Concept { - public: - virtual ~Concept() = default; - }; - template class Model : public Concept { - public: - typedef T Data; - Data _data; - Model(const Model& source): _data(source.data) {} - Model(const Data& data): _data(data) {} - virtual ~Model() {} - }; - - std::shared_ptr _concept; - }; - - Job(const Job& other) : _concept(other._concept) {} - ~Job(); - - bool isEnabled() const { return _concept->isEnabled(); } - void setEnabled(bool isEnabled) { _concept->setEnabled(isEnabled); } - - const std::string& getName() const { return _concept->getName(); } - const Varying getInput() const { return _concept->getInput(); } - const Varying getOutput() const { return _concept->getOutput(); } - - template T& edit() { - auto theConcept = std::dynamic_pointer_cast(_concept); - assert(theConcept); - return theConcept->_data; - } - template const T& get() const { - auto theConcept = std::dynamic_pointer_cast(_concept); - assert(theConcept); - return theConcept->_data; - } - - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - PerformanceTimer perfTimer(getName().c_str()); - PROFILE_RANGE(getName().c_str()); - _concept->run(sceneContext, renderContext); - } - -protected: -public: - - class Concept { - std::string _name; - bool _isEnabled = true; - public: - Concept() : _name() {} - Concept(const std::string& name) : _name(name) {} - virtual ~Concept() = default; - - void setName(const std::string& name) { _name = name; } - const std::string& getName() const { return _name; } - - bool isEnabled() const { return _isEnabled; } - void setEnabled(bool isEnabled) { _isEnabled = isEnabled; } - - virtual const Varying getInput() const { return Varying(); } - virtual const Varying getOutput() const { return Varying(); } - virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) = 0; - }; - - Job(Concept* concept) : _concept(concept) {} - -public: - template class Model : public Concept { - public: - typedef T Data; - - Data _data; - - Model() {} - Model(const std::string& name): Concept(name) {} - Model(Data data): _data(data) {} - Model(Data data, const std::string& name): Concept(name), _data(data) {} - - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - if (isEnabled()) { - jobRun(_data, sceneContext, renderContext); - } - } - }; - - template class ModelI : public Concept { - public: - typedef T Data; - typedef I Input; - - Data _data; - Varying _input; - - const Varying getInput() const { return _input; } - - ModelI(const std::string& name, const Varying& input, Data data = Data()) : Concept(name), _data(data), _input(input) {} - ModelI(const std::string& name, Data data): Concept(name), _data(data) {} - - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - if (isEnabled()) { - jobRunI(_data, sceneContext, renderContext, _input.get()); - } - } - }; - - template class ModelO : public Concept { - public: - typedef T Data; - typedef O Output; - - Data _data; - Varying _output; - - const Varying getOutput() const { return _output; } - - ModelO(const std::string& name): Concept(name), _output(Output()) { - - } - - ModelO(const std::string& name, Data data): Concept(name), _data(data), _output(Output()) {} - - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - if (isEnabled()) { - jobRunO(_data, sceneContext, renderContext, _output.edit()); - } - } - }; - - template class ModelIO : public Concept { - public: - typedef T Data; - typedef I Input; - typedef O Output; - - Data _data; - Varying _input; - Varying _output; - - const Varying getInput() const { return _input; } - const Varying getOutput() const { return _output; } - - ModelIO(const std::string& name, const Varying& input, Data data = Data()): Concept(name), _data(data), _input(input), _output(Output()) {} - ModelIO(const std::string& name, Data data, Output output): Concept(name), _data(data), _output(output) {} - - void setInput(const Varying& input) { _input = input; } - - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - if (isEnabled()) { - jobRunIO(_data, sceneContext, renderContext, _input.get(), _output.edit()); - } - } - }; - - std::shared_ptr _concept; -}; - - - - -typedef std::vector Jobs; - void cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); void depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); @@ -236,25 +34,25 @@ public: void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems); - typedef Job::ModelO JobModel; + using JobModel = Task::Job::ModelO; }; class CullItems { public: void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); - typedef Job::ModelIO JobModel; + using JobModel = Task::Job::ModelIO; }; class CullItemsOpaque { public: void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); - typedef Job::ModelIO JobModel; + using JobModel = Task::Job::ModelIO; }; class CullItemsTransparent { public: void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); - typedef Job::ModelIO JobModel; + using JobModel = Task::Job::ModelIO; }; class DepthSortItems { @@ -265,14 +63,14 @@ public: void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); - typedef Job::ModelIO JobModel; + using JobModel = Task::Job::ModelIO; }; class DrawLight { public: void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); - typedef Job::Model JobModel; + using JobModel = Task::Job::Model; }; class DrawBackground { @@ -296,7 +94,6 @@ public: }; - // A map of ItemIDs allowing to create bucket lists of SHAPE type items which are filtered by their // Material class ItemMaterialBucketMap : public std::map { @@ -313,4 +110,4 @@ void materialSortItems(const SceneContextPointer& sceneContext, const RenderCont } -#endif // hifi_render_Task_h +#endif // hifi_render_DrawTask_h diff --git a/libraries/render/src/render/Engine.cpp b/libraries/render/src/render/Engine.cpp index 907c836347..4f07da8d38 100644 --- a/libraries/render/src/render/Engine.cpp +++ b/libraries/render/src/render/Engine.cpp @@ -8,26 +8,13 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + #include "Engine.h" #include "DrawTask.h" + using namespace render; -RenderContext::RenderContext(ItemsConfig items, Tone tone, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode) - : _deferredDebugMode{ deferredDebugMode }, _deferredDebugSize{ deferredDebugSize }, - _args{ nullptr }, - _drawStatus{ drawStatus }, _drawHitEffect{ drawHitEffect }, - _items{ items }, _tone{ tone } {} - -void RenderContext::setOptions(bool occlusion, bool fxaa, bool showOwned) { - _occlusionStatus = occlusion; - _fxaaStatus = fxaa; - - if (showOwned) { - _drawStatus |= render::showNetworkStatusFlag; - } -}; - Engine::Engine() : _sceneContext(std::make_shared()), _renderContext(std::make_shared()) @@ -49,6 +36,7 @@ void Engine::addTask(const TaskPointer& task) { } void Engine::run() { + // TODO: Tasks will need to be specified such that their data can feed into each other for (auto task : _tasks) { task->run(_sceneContext, _renderContext); } diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 4192dd3ed9..e07402f411 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -12,115 +12,11 @@ #ifndef hifi_render_Engine_h #define hifi_render_Engine_h -#include "Scene.h" +#include "Context.h" +#include "Task.h" namespace render { - -class SceneContext { -public: - ScenePointer _scene; - - SceneContext() {} -}; -using SceneContextPointer = std::shared_ptr; - -// see examples/utilities/tools/renderEngineDebug.js -const int showDisplayStatusFlag = 1; -const int showNetworkStatusFlag = 2; - - -class RenderContext { -public: - class ItemsConfig { - public: - class Counter { - public: - Counter() {}; - Counter(const Counter& counter) { - numFeed = numDrawn = 0; - maxDrawn = counter.maxDrawn; - }; - - void setCounts(const Counter& counter) { - numFeed = counter.numFeed; - numDrawn = counter.numDrawn; - }; - - int numFeed = 0; - int numDrawn = 0; - int maxDrawn = -1; - }; - - class State : public Counter { - public: - bool render = true; - bool cull = true; - bool sort = true; - - Counter counter{}; - }; - - ItemsConfig(State opaqueState, State transparentState, Counter overlay3DCounter) - : opaque{ opaqueState }, transparent{ transparentState }, overlay3D{ overlay3DCounter } {} - ItemsConfig() : ItemsConfig{ {}, {}, {} } {} - - // TODO: If member count increases, store counters in a map instead of multiple members - State opaque{}; - State transparent{}; - Counter overlay3D{}; - }; - - class Tone { - public: - int toneCurve = 1; // Means just Gamma 2.2 correction - float exposure = 0.0; - }; - - RenderContext(ItemsConfig items, Tone tone, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode); - RenderContext() : RenderContext({}, {}, {}, {}, {}, {}) {}; - - void setArgs(RenderArgs* args) { _args = args; } - inline RenderArgs* getArgs() { return _args; } - inline ItemsConfig& getItemsConfig() { return _items; } - inline Tone& getTone() { return _tone; } - inline int getDrawStatus() { return _drawStatus; } - inline bool getDrawHitEffect() { return _drawHitEffect; } - inline bool getOcclusionStatus() { return _occlusionStatus; } - inline bool getFxaaStatus() { return _fxaaStatus; } - void setOptions(bool occlusion, bool fxaa, bool showOwned); - - // Debugging - int _deferredDebugMode; - glm::vec4 _deferredDebugSize; - -protected: - RenderArgs* _args; - - // Options - int _drawStatus; // bitflag - bool _drawHitEffect; - bool _occlusionStatus = false; - bool _fxaaStatus = false; - - ItemsConfig _items; - Tone _tone; -}; -typedef std::shared_ptr RenderContextPointer; - -// The base class for a task that runs on the SceneContext -class Task { -public: - Task() {} - ~Task() {} - - virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {} - -protected: -}; -typedef std::shared_ptr TaskPointer; -typedef std::vector Tasks; - // The root of the tasks, the Engine, should not be known from the Tasks, // The SceneContext is what navigates from the engine down to the Tasks class Engine { @@ -146,7 +42,6 @@ public: void buildStandardTaskPipeline(); protected: - Tasks _tasks; SceneContextPointer _sceneContext; @@ -157,3 +52,4 @@ typedef std::shared_ptr EnginePointer; } #endif // hifi_render_Engine_h + diff --git a/libraries/render/src/render/Task.h b/libraries/render/src/render/Task.h new file mode 100644 index 0000000000..66221d89e8 --- /dev/null +++ b/libraries/render/src/render/Task.h @@ -0,0 +1,229 @@ +// +// Task.h +// render/src/render +// +// Created by Zach Pomerantz on 1/6/2015. +// 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_render_Task_h +#define hifi_render_Task_h + +#include "Context.h" + +#include "gpu/Batch.h" +#include + +namespace render { + +// A varying piece of data, to be used as Job/Task I/O +// TODO: Task IO +class Varying { +public: + Varying() {} + Varying(const Varying& var) : _concept(var._concept) {} + template Varying(const T& data) : _concept(std::make_shared>(data)) {} + + template T& edit() { return std::static_pointer_cast>(_concept)->_data; } + template const T& get() { return std::static_pointer_cast>(_concept)->_data; } + +protected: + class Concept { + public: + virtual ~Concept() = default; + }; + template class Model : public Concept { + public: + using Data = T; + + Model(const Data& data) : _data(data) {} + virtual ~Model() = default; + + Data _data; + }; + + std::shared_ptr _concept; +}; + +// FIXME: In c++17, use default classes of nullptr_t to combine these +template void jobRun(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + jobModel.run(sceneContext, renderContext); +} +template void jobRunI(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const I& input) { + jobModel.run(sceneContext, renderContext, input); +} +template void jobRunO(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, O& output) { + jobModel.run(sceneContext, renderContext, output); +} +template void jobRunIO(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const I& input, O& output) { + jobModel.run(sceneContext, renderContext, input, output); +} + +// The base class for a task that runs on the SceneContext +class Task { +public: + // The guts of a task; tasks are composed of multiple Jobs that execute serially + class Job { + public: + friend class Task; + + // The guts of a job; jobs are composed of a concept + class Concept { + public: + Concept() = default; + virtual ~Concept() = default; + + bool isEnabled() const { return _isEnabled; } + void setEnabled(bool isEnabled) { _isEnabled = isEnabled; } + + virtual const Varying getInput() const { return Varying(); } + virtual const Varying getOutput() const { return Varying(); } + virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) = 0; + + protected: + + bool _isEnabled = true; + }; + using ConceptPointer = std::shared_ptr; + + + template class Model : public Concept { + public: + typedef T Data; + + Data _data; + + Model() {} + Model(Data data): _data(data) {} + + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + if (isEnabled()) { + jobRun(_data, sceneContext, renderContext); + } + } + }; + + template class ModelI : public Concept { + public: + typedef T Data; + typedef I Input; + + Data _data; + Varying _input; + + const Varying getInput() const { return _input; } + + ModelI(const Varying& input, Data data = Data()) : _data(data), _input(input) {} + ModelI(Data data) : _data(data) {} + + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + if (isEnabled()) { + jobRunI(_data, sceneContext, renderContext, _input.get()); + } + } + }; + + template class ModelO : public Concept { + public: + typedef T Data; + typedef O Output; + + Data _data; + Varying _output; + + const Varying getOutput() const { return _output; } + + ModelO(Data data) : _data(data), _output(Output()) {} + ModelO() : _output(Output()) {} + + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + if (isEnabled()) { + jobRunO(_data, sceneContext, renderContext, _output.edit()); + } + } + }; + + template class ModelIO : public Concept { + public: + typedef T Data; + typedef I Input; + typedef O Output; + + Data _data; + Varying _input; + Varying _output; + + const Varying getInput() const { return _input; } + const Varying getOutput() const { return _output; } + + ModelIO(const Varying& input, Data data = Data()) : _data(data), _input(input), _output(Output()) {} + ModelIO(Data data) : _data(data), _output(Output()) {} + + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + if (isEnabled()) { + jobRunIO(_data, sceneContext, renderContext, _input.get(), _output.edit()); + } + } + }; + + Job(ConceptPointer concept) : _concept(concept) {} + Job(std::string name, ConceptPointer concept) : _name(name), _concept(concept) {} + + bool isEnabled() const { return _concept->isEnabled(); } + void setEnabled(bool isEnabled) { _concept->setEnabled(isEnabled); } + + const Varying getInput() const { return _concept->getInput(); } + const Varying getOutput() const { return _concept->getOutput(); } + + template T& edit() { + auto concept = std::static_pointer_cast(_concept); + assert(concept); + return concept->_data; + } + template const T& get() const { + auto concept = std::static_pointer_cast(_concept); + assert(concept); + return concept->_data; + } + + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + PerformanceTimer perfTimer(_name.c_str()); + PROFILE_RANGE(_name.c_str()); + + _concept->run(sceneContext, renderContext); + } + protected: + ConceptPointer _concept; + std::string _name = ""; + + }; + using Jobs = std::vector; + +public: + using VaryingPointer = std::shared_ptr; + + Task() {} + ~Task() {} + + // Queue a new job to the task; returns the job's index + template size_t addJob(std::string name, std::shared_ptr jobConcept) + { size_t size = _jobs.size(); _jobs.emplace_back(name, jobConcept); return size; } + template size_t addJob(std::shared_ptr jobConcept) + { size_t size = _jobs.size(); _jobs.emplace_back(jobConcept); return size; } + + const Job& getJob(size_t i) const { return _jobs.at(i); } + + virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {} + +protected: + Jobs _jobs; +}; +typedef std::shared_ptr TaskPointer; +typedef std::vector Tasks; + +} + +#endif // hifi_render_Task_h From f902c4078d8594749792790af9969e32352ab17f Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 6 Jan 2016 18:34:37 -0800 Subject: [PATCH 026/215] Clean old DrawSceneTask --- .../render-utils/src/RenderDeferredTask.cpp | 4 +- .../render-utils/src/RenderDeferredTask.h | 6 +- libraries/render/src/render/DrawTask.cpp | 56 ------------------- libraries/render/src/render/DrawTask.h | 35 ------------ libraries/render/src/render/Engine.cpp | 11 ---- libraries/render/src/render/Engine.h | 3 - 6 files changed, 3 insertions(+), 112 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 9c286ba204..d6b6678042 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -24,6 +24,7 @@ #include "HitEffect.h" #include "TextureCache.h" +#include "render/DrawTask.h" #include "render/DrawStatus.h" #include "AmbientOcclusionEffect.h" #include "AntialiasingEffect.h" @@ -130,9 +131,6 @@ RenderDeferredTask::RenderDeferredTask() : Task() { addJob("Blit", std::make_shared()); } -RenderDeferredTask::~RenderDeferredTask() { -} - void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { // sanity checks assert(sceneContext); diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 330a1cceae..220a1edb5d 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -12,7 +12,7 @@ #ifndef hifi_RenderDeferredTask_h #define hifi_RenderDeferredTask_h -#include "render/DrawTask.h" +#include "render/Engine.h" #include "gpu/Pipeline.h" @@ -101,10 +101,8 @@ class RenderDeferredTask : public render::Task { public: RenderDeferredTask(); - ~RenderDeferredTask(); + ~RenderDeferredTask() = default; - render::Task::Jobs _jobs; - int _drawDebugDeferredBufferIndex = -1; int _drawStatusJobIndex = -1; int _drawHitEffectJobIndex = -1; diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 6b35e06a92..d9fbc79d1e 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -15,34 +15,12 @@ #include #include -#include #include #include using namespace render; -DrawSceneTask::DrawSceneTask() : Task() {} - -DrawSceneTask::~DrawSceneTask() {} - -void DrawSceneTask::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - // sanity checks - assert(sceneContext); - if (!sceneContext->_scene) { - return; - } - - // Is it possible that we render without a viewFrustum ? - if (!(renderContext->getArgs() && renderContext->getArgs()->_viewFrustum)) { - return; - } - - for (auto job : _jobs) { - job.run(sceneContext, renderContext); - } -}; - void render::cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { assert(renderContext->getArgs()); assert(renderContext->getArgs()->_viewFrustum); @@ -253,37 +231,3 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext }); args->_batch = nullptr; } - -void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - assert(renderContext->getArgs()); - assert(renderContext->getArgs()->_viewFrustum); - - // render backgrounds - auto& scene = sceneContext->_scene; - auto& items = scene->getMasterBucket().at(ItemFilter::Builder::background()); - - - ItemIDsBounds inItems; - inItems.reserve(items.size()); - for (auto id : items) { - inItems.emplace_back(id); - } - RenderArgs* args = renderContext->getArgs(); - doInBatch(args->_context, [=](gpu::Batch& batch) { - args->_batch = &batch; - batch.enableSkybox(true); - batch.setViewportTransform(args->_viewport); - batch.setStateScissorRect(args->_viewport); - - glm::mat4 projMat; - Transform viewMat; - args->_viewFrustum->evalProjectionMatrix(projMat); - args->_viewFrustum->evalViewTransform(viewMat); - - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat); - - renderItems(sceneContext, renderContext, inItems); - }); - args->_batch = nullptr; -} diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 3027cde73f..3efb06871a 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -73,41 +73,6 @@ public: using JobModel = Task::Job::Model; }; -class DrawBackground { -public: - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); - - - typedef Job::Model JobModel; -}; - - -class DrawSceneTask : public Task { -public: - - DrawSceneTask(); - ~DrawSceneTask(); - - Jobs _jobs; - - virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); - -}; - -// A map of ItemIDs allowing to create bucket lists of SHAPE type items which are filtered by their -// Material -class ItemMaterialBucketMap : public std::map { -public: - - ItemMaterialBucketMap() {} - - void insert(const ItemID& id, const model::MaterialKey& key); - - // standard builders allocating the main buckets - void allocateStandardMaterialBuckets(); -}; -void materialSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); - } #endif // hifi_render_DrawTask_h diff --git a/libraries/render/src/render/Engine.cpp b/libraries/render/src/render/Engine.cpp index 4f07da8d38..aa5816475a 100644 --- a/libraries/render/src/render/Engine.cpp +++ b/libraries/render/src/render/Engine.cpp @@ -11,8 +11,6 @@ #include "Engine.h" -#include "DrawTask.h" - using namespace render; Engine::Engine() : @@ -41,12 +39,3 @@ void Engine::run() { task->run(_sceneContext, _renderContext); } } - -void Engine::buildStandardTaskPipeline() { - if (!_tasks.empty()) { - _tasks.clear(); - } - - addTask(std::make_shared()); -} - diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index e07402f411..fa01ef6018 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -38,9 +38,6 @@ public: void run(); - // standard pipeline of tasks - void buildStandardTaskPipeline(); - protected: Tasks _tasks; From f64481c5107ee9b1906e1fe40dfed23ca54a84a0 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 7 Jan 2016 16:47:48 +1300 Subject: [PATCH 027/215] Warn user if cannot evaluate model's textures property --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index f5090cc20c..6ec77a17bf 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -129,7 +129,11 @@ void RenderableModelEntityItem::remapTextures() { QJsonObject currentTexturesAsJsonObject = currentTexturesAsJson.object(); QVariantMap currentTextureMap = currentTexturesAsJsonObject.toVariantMap(); - QJsonDocument texturesAsJson = QJsonDocument::fromJson(_textures.toUtf8()); + QJsonParseError error; + QJsonDocument texturesAsJson = QJsonDocument::fromJson(_textures.toUtf8(), &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(entitiesrenderer) << "Could not evaluate textures property:" << _textures; + } QJsonObject texturesAsJsonObject = texturesAsJson.object(); QVariantMap textureMap = texturesAsJsonObject.toVariantMap(); From a6bfecf038be1acdea2d3068c2b3c2feaf08162e Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 7 Jan 2016 16:52:29 +1300 Subject: [PATCH 028/215] Format original textures property string more properly --- .../model-networking/src/model-networking/ModelCache.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 4fd47affc2..f24a20266d 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -171,22 +171,22 @@ QStringList NetworkGeometry::getTextureNames() const { for (auto&& material : _materials) { if (!material->diffuseTextureName.isEmpty() && material->diffuseTexture) { QString textureURL = material->diffuseTexture->getURL().toString(); - result << material->diffuseTextureName + ":" + textureURL; + result << material->diffuseTextureName + ":\"" + textureURL + "\""; } if (!material->normalTextureName.isEmpty() && material->normalTexture) { QString textureURL = material->normalTexture->getURL().toString(); - result << material->normalTextureName + ":" + textureURL; + result << material->normalTextureName + ":\"" + textureURL + "\""; } if (!material->specularTextureName.isEmpty() && material->specularTexture) { QString textureURL = material->specularTexture->getURL().toString(); - result << material->specularTextureName + ":" + textureURL; + result << material->specularTextureName + ":\"" + textureURL + "\""; } if (!material->emissiveTextureName.isEmpty() && material->emissiveTexture) { QString textureURL = material->emissiveTexture->getURL().toString(); - result << material->emissiveTextureName + ":" + textureURL; + result << material->emissiveTextureName + ":\"" + textureURL + "\""; } } From 25309e84b33df7709aab540679afd902a9704f93 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 7 Jan 2016 17:30:28 +1300 Subject: [PATCH 029/215] Fix interpreting textures properties --- .../src/RenderableModelEntityItem.cpp | 28 +++++++++++-------- .../src/RenderableModelEntityItem.h | 1 + 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 6ec77a17bf..06c7e1afef 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -101,6 +101,21 @@ int RenderableModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned c return bytesRead; } +QVariantMap RenderableModelEntityItem::parseTexturesToMap(QString textures) { + if (textures == "") { + return QVariantMap(); + } + + QString jsonTextures = "{\"" + textures.replace(":\"", "\":\"").replace(",\n", ",\"") + "}"; + QJsonParseError error; + QJsonDocument texturesAsJson = QJsonDocument::fromJson(jsonTextures.toUtf8(), &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(entitiesrenderer) << "Could not evaluate textures property value:" << _textures; + } + QJsonObject texturesAsJsonObject = texturesAsJson.object(); + return texturesAsJsonObject.toVariantMap(); +} + void RenderableModelEntityItem::remapTextures() { if (!_model) { return; // nothing to do if we don't have a model @@ -125,17 +140,8 @@ void RenderableModelEntityItem::remapTextures() { // since we're changing here, we need to run through our current texture map // and any textures in the recently mapped texture, that is not in our desired // textures, we need to "unset" - QJsonDocument currentTexturesAsJson = QJsonDocument::fromJson(_currentTextures.toUtf8()); - QJsonObject currentTexturesAsJsonObject = currentTexturesAsJson.object(); - QVariantMap currentTextureMap = currentTexturesAsJsonObject.toVariantMap(); - - QJsonParseError error; - QJsonDocument texturesAsJson = QJsonDocument::fromJson(_textures.toUtf8(), &error); - if (error.error != QJsonParseError::NoError) { - qCWarning(entitiesrenderer) << "Could not evaluate textures property:" << _textures; - } - QJsonObject texturesAsJsonObject = texturesAsJson.object(); - QVariantMap textureMap = texturesAsJsonObject.toVariantMap(); + QVariantMap currentTextureMap = parseTexturesToMap(_currentTextures); + QVariantMap textureMap = parseTexturesToMap(_textures); foreach(const QString& key, currentTextureMap.keys()) { // if the desired texture map (what we're setting the textures to) doesn't diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index eb7958ed47..99e5ecb097 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -80,6 +80,7 @@ public: virtual void resizeJointArrays(int newSize = -1) override; private: + QVariantMap parseTexturesToMap(QString textures); void remapTextures(); Model* _model = nullptr; From 7b74f7407a9247e339ddc9081cfa0fae5617f846 Mon Sep 17 00:00:00 2001 From: AlessandroSigna Date: Wed, 6 Jan 2016 16:17:28 -0800 Subject: [PATCH 030/215] Threadsafe access to EntityTree in OverlayPanel --- interface/src/ui/overlays/OverlayPanel.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/interface/src/ui/overlays/OverlayPanel.cpp b/interface/src/ui/overlays/OverlayPanel.cpp index 3d7b93822e..7c52a9030e 100644 --- a/interface/src/ui/overlays/OverlayPanel.cpp +++ b/interface/src/ui/overlays/OverlayPanel.cpp @@ -170,9 +170,10 @@ void OverlayPanel::applyTransformTo(Transform& transform, bool force) { transform.setTranslation(DependencyManager::get()->getMyAvatar() ->getPosition()); } else if (!_anchorPositionBindEntity.isNull()) { - transform.setTranslation(DependencyManager::get() - ->getEntityTree()->findEntityByID(_anchorPositionBindEntity) - ->getPosition()); + EntityTreePointer entityTree = DependencyManager::get()->getEntityTree(); + entityTree->withReadLock([&] { + transform.setTranslation(entityTree->findEntityByID(_anchorPositionBindEntity)->getPosition()); + }); } else { transform.setTranslation(getAnchorPosition()); } @@ -181,9 +182,10 @@ void OverlayPanel::applyTransformTo(Transform& transform, bool force) { transform.setRotation(DependencyManager::get()->getMyAvatar() ->getOrientation()); } else if (!_anchorRotationBindEntity.isNull()) { - transform.setRotation(DependencyManager::get() - ->getEntityTree()->findEntityByID(_anchorRotationBindEntity) - ->getRotation()); + EntityTreePointer entityTree = DependencyManager::get()->getEntityTree(); + entityTree->withReadLock([&] { + transform.setRotation(entityTree->findEntityByID(_anchorRotationBindEntity)->getRotation()); + }); } else { transform.setRotation(getAnchorRotation()); } From 18390c87dacd4675b3e0e9deb04b153e57a75591 Mon Sep 17 00:00:00 2001 From: AlessandroSigna Date: Thu, 7 Jan 2016 10:11:02 -0800 Subject: [PATCH 031/215] handling NULL pointer --- interface/src/ui/overlays/OverlayPanel.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/overlays/OverlayPanel.cpp b/interface/src/ui/overlays/OverlayPanel.cpp index 7c52a9030e..9e82a2507c 100644 --- a/interface/src/ui/overlays/OverlayPanel.cpp +++ b/interface/src/ui/overlays/OverlayPanel.cpp @@ -172,7 +172,10 @@ void OverlayPanel::applyTransformTo(Transform& transform, bool force) { } else if (!_anchorPositionBindEntity.isNull()) { EntityTreePointer entityTree = DependencyManager::get()->getEntityTree(); entityTree->withReadLock([&] { - transform.setTranslation(entityTree->findEntityByID(_anchorPositionBindEntity)->getPosition()); + EntityItemPointer foundEntity = entityTree->findEntityByID(_anchorPositionBindEntity); + if (foundEntity != NULL) { + transform.setTranslation(foundEntity->getPosition()); + } }); } else { transform.setTranslation(getAnchorPosition()); @@ -184,7 +187,10 @@ void OverlayPanel::applyTransformTo(Transform& transform, bool force) { } else if (!_anchorRotationBindEntity.isNull()) { EntityTreePointer entityTree = DependencyManager::get()->getEntityTree(); entityTree->withReadLock([&] { - transform.setRotation(entityTree->findEntityByID(_anchorRotationBindEntity)->getRotation()); + EntityItemPointer foundEntity = entityTree->findEntityByID(_anchorRotationBindEntity); + if (foundEntity != NULL) { + transform.setRotation(foundEntity->getRotation()); + } }); } else { transform.setRotation(getAnchorRotation()); From eaa67a41dd6e62cb739919ec6a938089f57be862 Mon Sep 17 00:00:00 2001 From: AlessandroSigna Date: Thu, 7 Jan 2016 11:08:11 -0800 Subject: [PATCH 032/215] Following coding standard --- interface/src/ui/overlays/OverlayPanel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/overlays/OverlayPanel.cpp b/interface/src/ui/overlays/OverlayPanel.cpp index 9e82a2507c..7db2c6f8a2 100644 --- a/interface/src/ui/overlays/OverlayPanel.cpp +++ b/interface/src/ui/overlays/OverlayPanel.cpp @@ -173,7 +173,7 @@ void OverlayPanel::applyTransformTo(Transform& transform, bool force) { EntityTreePointer entityTree = DependencyManager::get()->getEntityTree(); entityTree->withReadLock([&] { EntityItemPointer foundEntity = entityTree->findEntityByID(_anchorPositionBindEntity); - if (foundEntity != NULL) { + if (foundEntity) { transform.setTranslation(foundEntity->getPosition()); } }); @@ -188,7 +188,7 @@ void OverlayPanel::applyTransformTo(Transform& transform, bool force) { EntityTreePointer entityTree = DependencyManager::get()->getEntityTree(); entityTree->withReadLock([&] { EntityItemPointer foundEntity = entityTree->findEntityByID(_anchorRotationBindEntity); - if (foundEntity != NULL) { + if (foundEntity) { transform.setRotation(foundEntity->getRotation()); } }); From 0f6d9a4db648647a2db0be647953e4a404e09f2d Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 7 Jan 2016 11:34:28 -0800 Subject: [PATCH 033/215] Use variadic for addJob for cleaner construction --- .../render-utils/src/RenderDeferredTask.cpp | 56 +++++++++---------- libraries/render/src/render/Task.h | 14 ++--- 2 files changed, 33 insertions(+), 37 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index d6b6678042..36cd17bdc1 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -52,63 +52,61 @@ void ToneMappingDeferred::run(const SceneContextPointer& sceneContext, const Ren RenderDeferredTask::RenderDeferredTask() : Task() { // CPU only, create the list of renderedOpaques items - addJob("FetchOpaque", std::make_shared( - FetchItems([](const RenderContextPointer& context, int count) { - context->getItemsConfig().opaque.numFeed = count; - }) - )); - addJob("CullOpaque", std::make_shared(_jobs.back().getOutput())); - addJob("DepthSortOpaque", std::make_shared(_jobs.back().getOutput())); + addJob("FetchOpaque", FetchItems([](const RenderContextPointer& context, int count) { + context->getItemsConfig().opaque.numFeed = count; + })); + addJob("CullOpaque", _jobs.back().getOutput()); + addJob("DepthSortOpaque", _jobs.back().getOutput()); auto& renderedOpaques = _jobs.back().getOutput(); // CPU only, create the list of renderedTransparents items - addJob("FetchTransparent", std::make_shared( - FetchItems(ItemFilter::Builder::transparentShape().withoutLayered(), - [](const RenderContextPointer& context, int count) { - context->getItemsConfig().transparent.numFeed = count; - }) + addJob("FetchTransparent", FetchItems( + ItemFilter::Builder::transparentShape().withoutLayered(), + [](const RenderContextPointer& context, int count) { + context->getItemsConfig().transparent.numFeed = count; + } )); - addJob("CullTransparent", std::make_shared(_jobs.back().getOutput())); - addJob("DepthSortTransparent", std::make_shared(_jobs.back().getOutput(), DepthSortItems(false))); + addJob("CullTransparent", _jobs.back().getOutput()); + addJob("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false)); auto& renderedTransparents = _jobs.back().getOutput(); // GPU Jobs: Start preparing the deferred and lighting buffer - addJob("PrepareDeferred", std::make_shared()); + addJob("PrepareDeferred"); // Render opaque objects in DeferredBuffer - addJob("DrawOpaqueDeferred", std::make_shared(renderedOpaques)); + addJob("DrawOpaqueDeferred", renderedOpaques); // Once opaque is all rendered create stencil background - addJob("DrawOpaqueStencil", std::make_shared()); + addJob("DrawOpaqueStencil"); // Use Stencil and start drawing background in Lighting buffer - addJob("DrawBackgroundDeferred", std::make_shared()); + addJob("DrawBackgroundDeferred"); // Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now. - addJob("DrawLight", std::make_shared()); + addJob("DrawLight"); // DeferredBuffer is complete, now let's shade it into the LightingBuffer - addJob("RenderDeferred", std::make_shared()); + addJob("RenderDeferred"); // AO job, to be revisited - addJob("AmbientOcclusion", std::make_shared()); + addJob("AmbientOcclusion"); _jobs.back().setEnabled(false); _occlusionJobIndex = (int)_jobs.size() - 1; // AA job to be revisited - addJob("Antialiasing", std::make_shared()); + addJob("Antialiasing"); _jobs.back().setEnabled(false); _antialiasingJobIndex = (int)_jobs.size() - 1; // Render transparent objects forward in LigthingBuffer - addJob("TransparentDeferred", std::make_shared(renderedTransparents)); + addJob("TransparentDeferred", renderedTransparents); // Lighting Buffer ready for tone mapping - addJob("ToneMapping", std::make_shared()); + addJob("ToneMapping"); _toneMappingJobIndex = (int)_jobs.size() - 1; // Debugging Deferred buffer job - addJob("DebugDeferredBuffer", std::make_shared()); + addJob("DebugDeferredBuffer"); _jobs.back().setEnabled(false); _drawDebugDeferredBufferIndex = (int)_jobs.size() - 1; @@ -117,18 +115,18 @@ RenderDeferredTask::RenderDeferredTask() : Task() { // Grab a texture map representing the different status icons and assign that to the drawStatsuJob auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg"; auto statusIconMap = DependencyManager::get()->getImageTexture(iconMapPath); - addJob("DrawStatus", std::make_shared(renderedOpaques, DrawStatus(statusIconMap))); + addJob("DrawStatus", renderedOpaques, DrawStatus(statusIconMap)); _jobs.back().setEnabled(false); _drawStatusJobIndex = (int)_jobs.size() - 1; } - addJob("DrawOverlay3D", std::make_shared()); + addJob("DrawOverlay3D"); - addJob("HitEffect", std::make_shared()); + addJob("HitEffect"); _jobs.back().setEnabled(false); _drawHitEffectJobIndex = (int)_jobs.size() -1; - addJob("Blit", std::make_shared()); + addJob("Blit"); } void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { diff --git a/libraries/render/src/render/Task.h b/libraries/render/src/render/Task.h index 66221d89e8..137074fc14 100644 --- a/libraries/render/src/render/Task.h +++ b/libraries/render/src/render/Task.h @@ -203,16 +203,14 @@ public: using Jobs = std::vector; public: - using VaryingPointer = std::shared_ptr; - - Task() {} - ~Task() {} + Task() = default; + virtual ~Task() = default; // Queue a new job to the task; returns the job's index - template size_t addJob(std::string name, std::shared_ptr jobConcept) - { size_t size = _jobs.size(); _jobs.emplace_back(name, jobConcept); return size; } - template size_t addJob(std::shared_ptr jobConcept) - { size_t size = _jobs.size(); _jobs.emplace_back(jobConcept); return size; } + template size_t addJob(std::string name, A&&... args) { + _jobs.emplace_back(name, std::make_shared(args...)); + return _jobs.size() - 1; + } const Job& getJob(size_t i) const { return _jobs.at(i); } From 39269f12ec0737988e0802e20ebb952ecd966425 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 7 Jan 2016 11:34:43 -0800 Subject: [PATCH 034/215] Clean and fix Wreorder --- libraries/render-utils/src/RenderDeferredTask.h | 1 - libraries/render/src/render/Context.h | 2 +- libraries/render/src/render/Task.h | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 220a1edb5d..b4e926ddb9 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -101,7 +101,6 @@ class RenderDeferredTask : public render::Task { public: RenderDeferredTask(); - ~RenderDeferredTask() = default; int _drawDebugDeferredBufferIndex = -1; int _drawStatusJobIndex = -1; diff --git a/libraries/render/src/render/Context.h b/libraries/render/src/render/Context.h index 5f8ca60ddb..0820c50ca3 100644 --- a/libraries/render/src/render/Context.h +++ b/libraries/render/src/render/Context.h @@ -1,5 +1,5 @@ // -// Engine.h +// Context.h // render/src/render // // Created by Zach Pomerantz on 1/6/2015. diff --git a/libraries/render/src/render/Task.h b/libraries/render/src/render/Task.h index 137074fc14..f1a66baf15 100644 --- a/libraries/render/src/render/Task.h +++ b/libraries/render/src/render/Task.h @@ -170,7 +170,7 @@ public: }; Job(ConceptPointer concept) : _concept(concept) {} - Job(std::string name, ConceptPointer concept) : _name(name), _concept(concept) {} + Job(std::string name, ConceptPointer concept) : _concept(concept), _name(name) {} bool isEnabled() const { return _concept->isEnabled(); } void setEnabled(bool isEnabled) { _concept->setEnabled(isEnabled); } From 7f0781f6e893374df50f817dba097bccdd5af405 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 7 Jan 2016 11:49:02 -0800 Subject: [PATCH 035/215] Move model update next to bindTransform --- libraries/render-utils/src/MeshPartPayload.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 7b1f6887f1..fd2a025d1d 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -221,7 +221,6 @@ void MeshPartPayload::render(RenderArgs* args) const { PerformanceTimer perfTimer("MeshPartPayload::render"); gpu::Batch& batch = *(args->_batch); - auto mode = args->_renderMode; ShapeKey key = getShapeKey(); @@ -359,9 +358,6 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { return ShapeKey::Builder::invalid(); } - // Back to model to update the cluster matrices right now - _model->updateClusterMatrices(_transform.getTranslation(), _transform.getRotation()); - const FBXMesh& mesh = geometry.meshes.at(_meshIndex); // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown @@ -463,7 +459,6 @@ void ModelMeshPartPayload::render(RenderArgs* args) const { } gpu::Batch& batch = *(args->_batch); - auto mode = args->_renderMode; ShapeKey key = getShapeKey(); if (!key.isValid()) { @@ -497,6 +492,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) const { assert(locations); // Bind the model transform and the skinCLusterMatrices if needed + _model->updateClusterMatrices(_transform.getTranslation(), _transform.getRotation()); bindTransform(batch, locations); //Bind the index buffer and vertex buffer and Blend shapes if needed From fc2bf8f5856ec0460a36b038b96d9e4ca1406fbb Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 8 Jan 2016 10:17:36 +1300 Subject: [PATCH 036/215] Miscellaneous code tidying, noticed in passing --- libraries/model-networking/src/model-networking/ModelCache.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index f24a20266d..2bbbbb35cc 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -72,7 +72,7 @@ void GeometryReader::run() { } else if (_url.path().toLower().endsWith(".obj")) { fbxgeo = OBJReader().readOBJ(_data, _mapping, _url); } else { - QString errorStr("usupported format"); + QString errorStr("unsupported format"); emit onError(NetworkGeometry::ModelParseError, errorStr); } emit onSuccess(fbxgeo); @@ -149,7 +149,6 @@ void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& u if (_meshes.size() > 0) { auto textureCache = DependencyManager::get(); for (auto&& material : _materials) { - QSharedPointer matchingTexture = QSharedPointer(); if (material->diffuseTextureName == name) { material->diffuseTexture = textureCache->getTexture(url, DEFAULT_TEXTURE); } else if (material->normalTextureName == name) { From 1b3e14439595319fc641680270e1f77c48c3c8aa Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 7 Jan 2016 13:27:22 -0800 Subject: [PATCH 037/215] Rename Shape to ShapePipelineLib, Shape.h to ShapePipeline.h --- .../render-utils/src/DeferredLightingEffect.h | 4 +-- .../render-utils/src/MeshPartPayload.cpp | 36 +++++++++---------- libraries/render-utils/src/MeshPartPayload.h | 6 ++-- libraries/render-utils/src/ShapeRender.h | 4 +-- libraries/render/src/render/DrawTask.cpp | 4 +-- libraries/render/src/render/DrawTask.h | 4 +-- libraries/render/src/render/Scene.h | 2 +- .../render/{Shape.cpp => ShapePipeline.cpp} | 16 +++++---- .../src/render/{Shape.h => ShapePipeline.h} | 33 +++++++++-------- 9 files changed, 56 insertions(+), 53 deletions(-) rename libraries/render/src/render/{Shape.cpp => ShapePipeline.cpp} (87%) rename libraries/render/src/render/{Shape.h => ShapePipeline.h} (93%) diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 40800258de..f00f558122 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -21,7 +21,7 @@ #include "model/Stage.h" #include "model/Geometry.h" -#include "render/Shape.h" +#include "render/ShapePipeline.h" class RenderArgs; class SimpleProgramKey; @@ -32,7 +32,7 @@ class DeferredLightingEffect : public Dependency { SINGLETON_DEPENDENCY public: - static const int NORMAL_FITTING_MAP_SLOT = render::Shape::Slot::NORMAL_FITTING_MAP; + static const int NORMAL_FITTING_MAP_SLOT = render::ShapePipeline::Slot::NORMAL_FITTING_MAP; static const int DEFERRED_TRANSFORM_BUFFER_SLOT = 2; void init(); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index fd2a025d1d..b1c40ac5b5 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -129,14 +129,14 @@ void MeshPartPayload::bindMesh(gpu::Batch& batch) const { } } -void MeshPartPayload::bindMaterial(gpu::Batch& batch, const Shape::Pipeline::LocationsPointer locations) const { +void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations) const { if (!_drawMaterial) { return; } auto textureCache = DependencyManager::get(); - batch.setUniformBuffer(Shape::Pipeline::Slot::MATERIAL_GPU, _drawMaterial->getSchemaBuffer()); + batch.setUniformBuffer(ShapePipeline::Slot::MATERIAL_GPU, _drawMaterial->getSchemaBuffer()); auto materialKey = _drawMaterial->getKey(); auto textureMaps = _drawMaterial->getTextureMaps(); @@ -146,44 +146,44 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const Shape::Pipeline::Loc if (materialKey.isDiffuseMap()) { auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP]; if (diffuseMap && diffuseMap->isDefined()) { - batch.setResourceTexture(Shape::Pipeline::Slot::DIFFUSE_MAP, diffuseMap->getTextureView()); + batch.setResourceTexture(ShapePipeline::Slot::DIFFUSE_MAP, diffuseMap->getTextureView()); if (!diffuseMap->getTextureTransform().isIdentity()) { diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]); } } else { - batch.setResourceTexture(Shape::Pipeline::Slot::DIFFUSE_MAP, textureCache->getGrayTexture()); + batch.setResourceTexture(ShapePipeline::Slot::DIFFUSE_MAP, textureCache->getGrayTexture()); } } else { - batch.setResourceTexture(Shape::Pipeline::Slot::DIFFUSE_MAP, textureCache->getWhiteTexture()); + batch.setResourceTexture(ShapePipeline::Slot::DIFFUSE_MAP, textureCache->getWhiteTexture()); } // Normal map if (materialKey.isNormalMap()) { auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP]; if (normalMap && normalMap->isDefined()) { - batch.setResourceTexture(Shape::Pipeline::Slot::NORMAL_MAP, normalMap->getTextureView()); + batch.setResourceTexture(ShapePipeline::Slot::NORMAL_MAP, normalMap->getTextureView()); // texcoord are assumed to be the same has diffuse } else { - batch.setResourceTexture(Shape::Pipeline::Slot::NORMAL_MAP, textureCache->getBlueTexture()); + batch.setResourceTexture(ShapePipeline::Slot::NORMAL_MAP, textureCache->getBlueTexture()); } } else { - batch.setResourceTexture(Shape::Pipeline::Slot::NORMAL_MAP, nullptr); + batch.setResourceTexture(ShapePipeline::Slot::NORMAL_MAP, nullptr); } // TODO: For now gloss map is used as the "specular map in the shading, we ll need to fix that if (materialKey.isGlossMap()) { auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP]; if (specularMap && specularMap->isDefined()) { - batch.setResourceTexture(Shape::Pipeline::Slot::SPECULAR_MAP, specularMap->getTextureView()); + batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, specularMap->getTextureView()); // texcoord are assumed to be the same has diffuse } else { - batch.setResourceTexture(Shape::Pipeline::Slot::SPECULAR_MAP, textureCache->getBlackTexture()); + batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, textureCache->getBlackTexture()); } } else { - batch.setResourceTexture(Shape::Pipeline::Slot::SPECULAR_MAP, nullptr); + batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, nullptr); } // TODO: For now lightmaop is piped into the emissive map unit, we need to fix that and support for real emissive too @@ -191,7 +191,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const Shape::Pipeline::Loc auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP]; if (lightmapMap && lightmapMap->isDefined()) { - batch.setResourceTexture(Shape::Pipeline::Slot::LIGHTMAP_MAP, lightmapMap->getTextureView()); + batch.setResourceTexture(ShapePipeline::Slot::LIGHTMAP_MAP, lightmapMap->getTextureView()); auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale(); batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y); @@ -200,10 +200,10 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const Shape::Pipeline::Loc lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]); } } else { - batch.setResourceTexture(Shape::Pipeline::Slot::LIGHTMAP_MAP, textureCache->getGrayTexture()); + batch.setResourceTexture(ShapePipeline::Slot::LIGHTMAP_MAP, textureCache->getGrayTexture()); } } else { - batch.setResourceTexture(Shape::Pipeline::Slot::LIGHTMAP_MAP, nullptr); + batch.setResourceTexture(ShapePipeline::Slot::LIGHTMAP_MAP, nullptr); } // Texcoord transforms ? @@ -212,7 +212,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const Shape::Pipeline::Loc } } -void MeshPartPayload::bindTransform(gpu::Batch& batch, const Shape::Pipeline::LocationsPointer locations) const { +void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations) const { batch.setModelTransform(_drawTransform); } @@ -427,16 +427,16 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) const { } } -void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const Shape::Pipeline::LocationsPointer locations) const { +void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations) const { // Still relying on the raw data from the model const Model::MeshState& state = _model->_meshStates.at(_meshIndex); Transform transform; if (state.clusterBuffer) { if (_model->_cauterizeBones) { - batch.setUniformBuffer(Shape::Pipeline::Slot::SKINNING_GPU, state.cauterizedClusterBuffer); + batch.setUniformBuffer(ShapePipeline::Slot::SKINNING_GPU, state.cauterizedClusterBuffer); } else { - batch.setUniformBuffer(Shape::Pipeline::Slot::SKINNING_GPU, state.clusterBuffer); + batch.setUniformBuffer(ShapePipeline::Slot::SKINNING_GPU, state.clusterBuffer); } } else { if (_model->_cauterizeBones) { diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 1e6e6214ae..7d693dcbe9 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -46,8 +46,8 @@ public: // ModelMeshPartPayload functions to perform render void drawCall(gpu::Batch& batch) const; virtual void bindMesh(gpu::Batch& batch) const; - virtual void bindMaterial(gpu::Batch& batch, const render::Shape::Pipeline::LocationsPointer locations) const; - virtual void bindTransform(gpu::Batch& batch, const render::Shape::Pipeline::LocationsPointer locations) const; + virtual void bindMaterial(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations) const; + virtual void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations) const; // Payload resource cached values model::MeshPointer _drawMesh; @@ -89,7 +89,7 @@ public: // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch) const override; - void bindTransform(gpu::Batch& batch, const render::Shape::Pipeline::LocationsPointer locations) const override; + void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations) const override; void initCache(); diff --git a/libraries/render-utils/src/ShapeRender.h b/libraries/render-utils/src/ShapeRender.h index fc174896bb..590eca5511 100644 --- a/libraries/render-utils/src/ShapeRender.h +++ b/libraries/render-utils/src/ShapeRender.h @@ -12,10 +12,10 @@ #ifndef hifi_render_utils_Shape_h #define hifi_render_utils_Shape_h -#include +#include #include -class ShapeRender : public render::Shape { +class ShapeRender : public render::ShapePipelineLib { public: ShapeRender(); static void initPipeline(); diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 756e0847fc..df2c14662f 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -220,7 +220,7 @@ void render::renderLights(const SceneContextPointer& sceneContext, const RenderC } } -void renderShape(RenderArgs* args, const Shape& shapeContext, Item& item) { +void renderShape(RenderArgs* args, const ShapePipelineLib& shapeContext, Item& item) { assert(item.getKey().isShape()); const auto& key = item.getShapeKey(); if (key.isValid() && !key.hasOwnPipeline()) { @@ -236,7 +236,7 @@ void renderShape(RenderArgs* args, const Shape& shapeContext, Item& item) { } void render::renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, - const Shape& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems) { + const ShapePipelineLib& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems) { auto& scene = sceneContext->_scene; RenderArgs* args = renderContext->getArgs(); diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index eef4247b17..81dc7d358a 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -13,7 +13,7 @@ #define hifi_render_Task_h #include "Engine.h" -#include "Shape.h" +#include "ShapePipeline.h" #include "gpu/Batch.h" #include @@ -222,7 +222,7 @@ typedef std::vector Jobs; void cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); void depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); void renderLights(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems); -void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Shape& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); +void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePipelineLib& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); class FetchItems { diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index bff75ebcd8..3a6463b538 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -25,7 +25,7 @@ #include #include "model/Material.h" -#include "Shape.h" +#include "ShapePipeline.h" namespace render { diff --git a/libraries/render/src/render/Shape.cpp b/libraries/render/src/render/ShapePipeline.cpp similarity index 87% rename from libraries/render/src/render/Shape.cpp rename to libraries/render/src/render/ShapePipeline.cpp index ed988adb5a..b766fb8695 100644 --- a/libraries/render/src/render/Shape.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -1,5 +1,5 @@ // -// Shape.cpp +// ShapePipeline.cpp // render/src/render // // Created by Zach Pomerantz on 12/31/15. @@ -9,20 +9,24 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "Shape.h" +#include "ShapePipeline.h" #include using namespace render; -Shape::PipelineLib Shape::_pipelineLib; +ShapePipelineLib::PipelineLib ShapePipelineLib::_pipelineLib; -const Shape::PipelinePointer Shape::_pickPipeline(RenderArgs* args, const Key& key) { +void ShapePipelineLib::addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader) { + _pipelineLib.addPipeline(key, vertexShader, pixelShader); +} + +const ShapePipelineLib::PipelinePointer ShapePipelineLib::_pickPipeline(RenderArgs* args, const Key& key) { assert(!_pipelineLib.empty()); assert(args); assert(args->_batch); - PerformanceTimer perfTimer("Shape::getPipeline"); + PerformanceTimer perfTimer("ShapePipelineLib::getPipeline"); const auto& pipelineIterator = _pipelineLib.find(key); if (pipelineIterator == _pipelineLib.end()) { @@ -39,7 +43,7 @@ const Shape::PipelinePointer Shape::_pickPipeline(RenderArgs* args, const Key& k return shapePipeline; } -void Shape::PipelineLib::addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader) { +void ShapePipelineLib::PipelineLib::addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader) { gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slot::SKINNING_GPU)); slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), Slot::MATERIAL_GPU)); diff --git a/libraries/render/src/render/Shape.h b/libraries/render/src/render/ShapePipeline.h similarity index 93% rename from libraries/render/src/render/Shape.h rename to libraries/render/src/render/ShapePipeline.h index 4950af1da4..1f293cfb93 100644 --- a/libraries/render/src/render/Shape.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -1,5 +1,5 @@ // -// Shape.h +// ShapePipeline.h // render/src/render // // Created by Zach Pomerantz on 12/31/15. @@ -9,8 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_render_Shape_h -#define hifi_render_Shape_h +#ifndef hifi_render_ShapePipeline_h +#define hifi_render_ShapePipeline_h #include #include @@ -160,36 +160,35 @@ public: ShapePipeline(gpu::PipelinePointer pipeline, std::shared_ptr locations) : pipeline(pipeline), locations(locations) {} }; +using ShapePipelinePointer = std::shared_ptr; // Meta-information (pipeline and locations) to render a shape -class Shape { +class ShapePipelineLib { public: using Key = ShapeKey; using Pipeline = ShapePipeline; - using PipelinePointer = std::shared_ptr; + using PipelinePointer = ShapePipelinePointer; using Slot = ShapePipeline::Slot; using Locations = ShapePipeline::Locations; + virtual ~ShapePipelineLib() = default; + + static void addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader); + virtual const PipelinePointer pickPipeline(RenderArgs* args, const Key& key) const { + return ShapePipelineLib::_pickPipeline(args, key); + } + +protected: using PipelineMap = std::unordered_map; class PipelineLib : public PipelineMap { public: void addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader); }; - static void addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader) { - _pipelineLib.addPipeline(key, vertexShader, pixelShader); - } - virtual const PipelinePointer pickPipeline(RenderArgs* args, const Key& key) const { - return Shape::_pickPipeline(args, key); - } - - virtual ~Shape() {}; - -protected: - static const PipelinePointer _pickPipeline(RenderArgs* args, const Key& key); static PipelineLib _pipelineLib; + static const PipelinePointer _pickPipeline(RenderArgs* args, const Key& key); }; } -#endif // hifi_render_Shape_h +#endif // hifi_render_ShapePipeline_h From e809c4f89d2460cd86ecc429863beb849ee1a08d Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 7 Jan 2016 13:42:56 -0800 Subject: [PATCH 038/215] Avoid copying Item before rendering --- libraries/render/src/render/DrawTask.cpp | 8 +++----- libraries/render/src/render/Scene.h | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index df2c14662f..1b6bae54c8 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -214,13 +214,12 @@ void render::renderLights(const SceneContextPointer& sceneContext, const RenderC RenderArgs* args = renderContext->getArgs(); for (const auto& itemDetails : inItems) { - // FIXME: Every item is copied because item.render cannot mutate a const - auto item = scene->getItem(itemDetails.id); + auto& item = scene->getItem(itemDetails.id); item.render(args); } } -void renderShape(RenderArgs* args, const ShapePipelineLib& shapeContext, Item& item) { +void renderShape(RenderArgs* args, const ShapePipelineLib& shapeContext, const Item& item) { assert(item.getKey().isShape()); const auto& key = item.getShapeKey(); if (key.isValid() && !key.hasOwnPipeline()) { @@ -242,8 +241,7 @@ void render::renderShapes(const SceneContextPointer& sceneContext, const RenderC auto numItemsToDraw = glm::max((int)inItems.size(), maxDrawnItems); for (auto i = 0; i < numItemsToDraw; ++i) { - // FIXME: Every item is copied because item.render cannot mutate a const - auto item = scene->getItem(inItems[i].id); + auto& item = scene->getItem(inItems[i].id); renderShape(args, shapeContext, item); } } diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index 3a6463b538..567e054a8a 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -305,7 +305,7 @@ public: int getLayer() const { return _payload->getLayer(); } // Render call for the item - void render(RenderArgs* args) { _payload->render(args); } + void render(RenderArgs* args) const { _payload->render(args); } // Shape Type Interface const ShapeKey getShapeKey() const { return _payload->getShapeKey(); } From c19b4574016fec9139cf7ef257a136e78f565e02 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 7 Jan 2016 13:46:38 -0800 Subject: [PATCH 039/215] Forward arguments and mark T::JobModel as dependent name --- libraries/render/src/render/Task.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render/src/render/Task.h b/libraries/render/src/render/Task.h index f1a66baf15..4d2a3728c6 100644 --- a/libraries/render/src/render/Task.h +++ b/libraries/render/src/render/Task.h @@ -208,7 +208,7 @@ public: // Queue a new job to the task; returns the job's index template size_t addJob(std::string name, A&&... args) { - _jobs.emplace_back(name, std::make_shared(args...)); + _jobs.emplace_back(name, std::make_shared(std::forward(args)...)); return _jobs.size() - 1; } From 695c69fd34a4265e8cfa2a34e70e49b3a45d3d6b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 7 Jan 2016 14:22:17 -0800 Subject: [PATCH 040/215] Conform to coding standards --- libraries/render/src/render/Context.cpp | 4 ++- libraries/render/src/render/Context.h | 39 ++++++++++++------------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/libraries/render/src/render/Context.cpp b/libraries/render/src/render/Context.cpp index 4f7895e4fc..8facaad1b2 100644 --- a/libraries/render/src/render/Context.cpp +++ b/libraries/render/src/render/Context.cpp @@ -17,7 +17,9 @@ RenderContext::RenderContext(ItemsConfig items, Tone tone, int drawStatus, bool : _deferredDebugMode{ deferredDebugMode }, _deferredDebugSize{ deferredDebugSize }, _args{ nullptr }, _drawStatus{ drawStatus }, _drawHitEffect{ drawHitEffect }, - _items{ items }, _tone{ tone } {} + _items{ items }, _tone{ tone } +{ +} void RenderContext::setOptions(bool occlusion, bool fxaa, bool showOwned) { _occlusionStatus = occlusion; diff --git a/libraries/render/src/render/Context.h b/libraries/render/src/render/Context.h index 0820c50ca3..4eeba0ee08 100644 --- a/libraries/render/src/render/Context.h +++ b/libraries/render/src/render/Context.h @@ -34,27 +34,24 @@ public: public: class Counter { public: - Counter() {}; - Counter(const Counter& counter) { - numFeed = numDrawn = 0; - maxDrawn = counter.maxDrawn; - }; + Counter() {} + Counter(const Counter& counter) : maxDrawn { counter.maxDrawn } {} void setCounts(const Counter& counter) { numFeed = counter.numFeed; numDrawn = counter.numDrawn; }; - int numFeed = 0; - int numDrawn = 0; - int maxDrawn = -1; + int numFeed { 0 }; + int numDrawn { 0 }; + int maxDrawn { -1 }; }; class State : public Counter { public: - bool render = true; - bool cull = true; - bool sort = true; + bool render { true }; + bool cull { true }; + bool sort { true }; Counter counter{}; }; @@ -76,16 +73,16 @@ public: }; RenderContext(ItemsConfig items, Tone tone, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode); - RenderContext() : RenderContext({}, {}, {}, {}, {}, {}) {}; + RenderContext() {} void setArgs(RenderArgs* args) { _args = args; } - inline RenderArgs* getArgs() { return _args; } - inline ItemsConfig& getItemsConfig() { return _items; } - inline Tone& getTone() { return _tone; } - inline int getDrawStatus() { return _drawStatus; } - inline bool getDrawHitEffect() { return _drawHitEffect; } - inline bool getOcclusionStatus() { return _occlusionStatus; } - inline bool getFxaaStatus() { return _fxaaStatus; } + RenderArgs* getArgs() { return _args; } + ItemsConfig& getItemsConfig() { return _items; } + Tone& getTone() { return _tone; } + int getDrawStatus() { return _drawStatus; } + bool getDrawHitEffect() { return _drawHitEffect; } + bool getOcclusionStatus() { return _occlusionStatus; } + bool getFxaaStatus() { return _fxaaStatus; } void setOptions(bool occlusion, bool fxaa, bool showOwned); // Debugging @@ -98,8 +95,8 @@ protected: // Options int _drawStatus; // bitflag bool _drawHitEffect; - bool _occlusionStatus = false; - bool _fxaaStatus = false; + bool _occlusionStatus { false }; + bool _fxaaStatus = { false }; ItemsConfig _items; Tone _tone; From 35e17b76042ce9f850702b4c93def50f12f15cd9 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 7 Jan 2016 15:43:51 -0800 Subject: [PATCH 041/215] movable audio bar --- interface/resources/qml/AvatarInputs.qml | 44 +++++++++++------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/interface/resources/qml/AvatarInputs.qml b/interface/resources/qml/AvatarInputs.qml index 49aeee3074..ce729d468d 100644 --- a/interface/resources/qml/AvatarInputs.qml +++ b/interface/resources/qml/AvatarInputs.qml @@ -10,21 +10,32 @@ import Hifi 1.0 as Hifi import QtQuick 2.4 import QtQuick.Controls 1.3 import QtGraphicalEffects 1.0 +import Qt.labs.settings 1.0 Hifi.AvatarInputs { id: root objectName: "AvatarInputs" - anchors.fill: parent + width: mirrorWidth + height: controls.height + mirror.height + x: 10; y: 5 -// width: 800 -// height: 600 -// color: "black" - readonly property int iconPadding: 5 readonly property int mirrorHeight: 215 readonly property int mirrorWidth: 265 - readonly property int mirrorTopPad: iconPadding - readonly property int mirrorLeftPad: 10 readonly property int iconSize: 24 + readonly property int iconPadding: 5 + + Settings { + category: "Overlay.AvatarInputs" + property alias x: root.x + property alias y: root.y + } + + MouseArea { + id: hover + hoverEnabled: true + drag.target: parent + anchors.fill: parent + } Item { id: mirror @@ -32,18 +43,8 @@ Hifi.AvatarInputs { height: root.mirrorVisible ? root.mirrorHeight : 0 visible: root.mirrorVisible anchors.left: parent.left - anchors.leftMargin: root.mirrorLeftPad - anchors.top: parent.top - anchors.topMargin: root.mirrorTopPad clip: true - MouseArea { - id: hover - anchors.fill: parent - hoverEnabled: true - propagateComposedEvents: true - } - Image { id: closeMirror visible: hover.containsMouse @@ -64,7 +65,7 @@ Hifi.AvatarInputs { Image { id: zoomIn - visible: hover.containsMouse + visible: hover.containsMouse width: root.iconSize height: root.iconSize anchors.bottom: parent.bottom @@ -82,14 +83,11 @@ Hifi.AvatarInputs { } Item { + id: controls width: root.mirrorWidth height: 44 visible: !root.isHMD - - x: root.mirrorLeftPad - y: root.mirrorVisible ? root.mirrorTopPad + root.mirrorHeight : 5 - - + anchors.top: mirror.bottom Rectangle { anchors.fill: parent From 031f59b7b5c655b98c4e07f4a6399bf2017ff6e9 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 7 Jan 2016 16:12:36 -0800 Subject: [PATCH 042/215] Support for adding soft attachments from script. Also, bug fixes for setting MyAvatar.attachmentData property. --- interface/src/avatar/Avatar.cpp | 2 +- interface/src/avatar/MyAvatar.cpp | 20 ++++++++++------- interface/src/avatar/MyAvatar.h | 3 ++- libraries/avatars/src/AvatarData.cpp | 32 ++++++++++++++++++++-------- libraries/avatars/src/AvatarData.h | 19 +++++++++++------ 5 files changed, 50 insertions(+), 26 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 2f7ae62e2e..ebd7f017bb 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -940,7 +940,7 @@ static std::shared_ptr allocateAttachmentModel(bool isSoft, RigPointer ri void Avatar::setAttachmentData(const QVector& attachmentData) { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setAttachmentData", Qt::DirectConnection, + QMetaObject::invokeMethod(this, "setAttachmentData", Qt::BlockingQueuedConnection, Q_ARG(const QVector, attachmentData)); return; } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 98b09d6c59..a5303b401a 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1022,12 +1022,12 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN } void MyAvatar::setAttachmentData(const QVector& attachmentData) { - Avatar::setAttachmentData(attachmentData); if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setAttachmentData", Qt::DirectConnection, + QMetaObject::invokeMethod(this, "setAttachmentData", Qt::BlockingQueuedConnection, Q_ARG(const QVector, attachmentData)); return; } + Avatar::setAttachmentData(attachmentData); _billboardValid = false; } @@ -1165,21 +1165,25 @@ void MyAvatar::setCollisionSoundURL(const QString& url) { } } -void MyAvatar::attach(const QString& modelURL, const QString& jointName, const glm::vec3& translation, - const glm::quat& rotation, float scale, bool allowDuplicates, bool useSaved) { +void MyAvatar::attach(const QString& modelURL, const QString& jointName, + const glm::vec3& translation, const glm::quat& rotation, + float scale, bool isSoft, + bool allowDuplicates, bool useSaved) { if (QThread::currentThread() != thread()) { - Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved); + Avatar::attach(modelURL, jointName, translation, rotation, scale, isSoft, allowDuplicates, useSaved); return; } if (useSaved) { AttachmentData attachment = loadAttachmentData(modelURL, jointName); if (attachment.isValid()) { - Avatar::attach(modelURL, attachment.jointName, attachment.translation, - attachment.rotation, attachment.scale, allowDuplicates, useSaved); + Avatar::attach(modelURL, attachment.jointName, + attachment.translation, attachment.rotation, + attachment.scale, attachment.isSoft, + allowDuplicates, useSaved); return; } } - Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved); + Avatar::attach(modelURL, jointName, translation, rotation, scale, isSoft, allowDuplicates, useSaved); } void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 44823c9913..8c4bbcbba0 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -295,7 +295,8 @@ private: 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, + const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), + float scale = 1.0f, bool isSoft = false, bool allowDuplicates = false, bool useSaved = true) override; //void beginFollowingHMD(); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 0015a064fb..af8e1c1cda 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1085,12 +1085,15 @@ void AvatarData::setAttachmentData(const QVector& attachmentData _attachmentData = attachmentData; } -void AvatarData::attach(const QString& modelURL, const QString& jointName, const glm::vec3& translation, - const glm::quat& rotation, float scale, bool allowDuplicates, bool useSaved) { +void AvatarData::attach(const QString& modelURL, const QString& jointName, + const glm::vec3& translation, const glm::quat& rotation, + float scale, bool isSoft, + bool allowDuplicates, bool useSaved) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "attach", Q_ARG(const QString&, modelURL), Q_ARG(const QString&, jointName), - Q_ARG(const glm::vec3&, translation), Q_ARG(const glm::quat&, rotation), - Q_ARG(float, scale), Q_ARG(bool, allowDuplicates), Q_ARG(bool, useSaved)); + Q_ARG(const glm::vec3&, translation), Q_ARG(const glm::quat&, rotation), + Q_ARG(float, scale), Q_ARG(bool, isSoft), + Q_ARG(bool, allowDuplicates), Q_ARG(bool, useSaved)); return; } QVector attachmentData = getAttachmentData(); @@ -1107,6 +1110,7 @@ void AvatarData::attach(const QString& modelURL, const QString& jointName, const data.translation = translation; data.rotation = rotation; data.scale = scale; + data.isSoft = isSoft; attachmentData.append(data); setAttachmentData(attachmentData); } @@ -1334,7 +1338,7 @@ QDataStream& operator>>(QDataStream& in, AttachmentData& attachment) { attachment.translation >> attachment.rotation >> attachment.scale >> attachment.isSoft; } -void AttachmentDataObject::setModelURL(const QString& modelURL) const { +void AttachmentDataObject::setModelURL(const QString& modelURL) { AttachmentData data = qscriptvalue_cast(thisObject()); data.modelURL = modelURL; thisObject() = engine()->toScriptValue(data); @@ -1344,7 +1348,7 @@ QString AttachmentDataObject::getModelURL() const { return qscriptvalue_cast(thisObject()).modelURL.toString(); } -void AttachmentDataObject::setJointName(const QString& jointName) const { +void AttachmentDataObject::setJointName(const QString& jointName) { AttachmentData data = qscriptvalue_cast(thisObject()); data.jointName = jointName; thisObject() = engine()->toScriptValue(data); @@ -1354,7 +1358,7 @@ QString AttachmentDataObject::getJointName() const { return qscriptvalue_cast(thisObject()).jointName; } -void AttachmentDataObject::setTranslation(const glm::vec3& translation) const { +void AttachmentDataObject::setTranslation(const glm::vec3& translation) { AttachmentData data = qscriptvalue_cast(thisObject()); data.translation = translation; thisObject() = engine()->toScriptValue(data); @@ -1364,7 +1368,7 @@ glm::vec3 AttachmentDataObject::getTranslation() const { return qscriptvalue_cast(thisObject()).translation; } -void AttachmentDataObject::setRotation(const glm::quat& rotation) const { +void AttachmentDataObject::setRotation(const glm::quat& rotation) { AttachmentData data = qscriptvalue_cast(thisObject()); data.rotation = rotation; thisObject() = engine()->toScriptValue(data); @@ -1374,7 +1378,7 @@ glm::quat AttachmentDataObject::getRotation() const { return qscriptvalue_cast(thisObject()).rotation; } -void AttachmentDataObject::setScale(float scale) const { +void AttachmentDataObject::setScale(float scale) { AttachmentData data = qscriptvalue_cast(thisObject()); data.scale = scale; thisObject() = engine()->toScriptValue(data); @@ -1384,6 +1388,16 @@ float AttachmentDataObject::getScale() const { return qscriptvalue_cast(thisObject()).scale; } +void AttachmentDataObject::setIsSoft(bool isSoft) { + AttachmentData data = qscriptvalue_cast(thisObject()); + data.isSoft = isSoft; + thisObject() = engine()->toScriptValue(data); +} + +bool AttachmentDataObject::getIsSoft() const { + return qscriptvalue_cast(thisObject()).isSoft; +} + void registerAvatarTypes(QScriptEngine* engine) { qScriptRegisterSequenceMetaType >(engine); engine->setDefaultPrototype(qMetaTypeId(), engine->newQObject( diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 83195364bf..c23cbe9e5c 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -304,8 +304,9 @@ public: Q_INVOKABLE virtual void setAttachmentData(const QVector& attachmentData); Q_INVOKABLE 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); + const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), + float scale = 1.0f, bool isSoft = false, + bool allowDuplicates = false, bool useSaved = true); Q_INVOKABLE void detachOne(const QString& modelURL, const QString& jointName = QString()); Q_INVOKABLE void detachAll(const QString& modelURL, const QString& jointName = QString()); @@ -468,23 +469,27 @@ class AttachmentDataObject : public QObject, protected QScriptable { Q_PROPERTY(glm::vec3 translation READ getTranslation WRITE setTranslation) Q_PROPERTY(glm::quat rotation READ getRotation WRITE setRotation) Q_PROPERTY(float scale READ getScale WRITE setScale) + Q_PROPERTY(bool isSoft READ getIsSoft WRITE setIsSoft) public: - Q_INVOKABLE void setModelURL(const QString& modelURL) const; + Q_INVOKABLE void setModelURL(const QString& modelURL); Q_INVOKABLE QString getModelURL() const; - Q_INVOKABLE void setJointName(const QString& jointName) const; + Q_INVOKABLE void setJointName(const QString& jointName); Q_INVOKABLE QString getJointName() const; - Q_INVOKABLE void setTranslation(const glm::vec3& translation) const; + Q_INVOKABLE void setTranslation(const glm::vec3& translation); Q_INVOKABLE glm::vec3 getTranslation() const; - Q_INVOKABLE void setRotation(const glm::quat& rotation) const; + Q_INVOKABLE void setRotation(const glm::quat& rotation); Q_INVOKABLE glm::quat getRotation() const; - Q_INVOKABLE void setScale(float scale) const; + Q_INVOKABLE void setScale(float scale); Q_INVOKABLE float getScale() const; + + Q_INVOKABLE void setIsSoft(bool scale); + Q_INVOKABLE bool getIsSoft() const; }; void registerAvatarTypes(QScriptEngine* engine); From 5d19de76ab1eafd2ddb7fee989ad47f3f8e13504 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 7 Jan 2016 16:15:24 -0800 Subject: [PATCH 043/215] Added avatarAttachmentTest.js script --- examples/tests/avatarAttachmentTest.js | 148 +++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 examples/tests/avatarAttachmentTest.js diff --git a/examples/tests/avatarAttachmentTest.js b/examples/tests/avatarAttachmentTest.js new file mode 100644 index 0000000000..23b94ba8d5 --- /dev/null +++ b/examples/tests/avatarAttachmentTest.js @@ -0,0 +1,148 @@ +// +// avatarAttachmentTest.js +// examples/tests +// +// Created by Anthony Thibault on January 7, 2016 +// Copyright 2016 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 +// + +// Test for MyAvatar attachment API +// MyAvatar.setAttachmentData(); +// MyAvatar.getAttachmentData(); + +// Toggle button helper +function ToggleButtonBuddy(x, y, width, height, urls) { + this.up = Overlays.addOverlay("image", { + x: x, y: y, width: width, height: height, + subImage: { x: 0, y: height, width: width, height: height}, + imageURL: urls.up, + visible: true, + alpha: 1.0 + }); + this.down = Overlays.addOverlay("image", { + x: x, y: y, width: width, height: height, + subImage: { x: 0, y: height, width: width, height: height}, + imageURL: urls.down, + visible: false, + alpha: 1.0 + }); + this.callbacks = []; + + var self = this; + Controller.mousePressEvent.connect(function (event) { + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + if (clickedOverlay === self.up) { + // flip visiblity + Overlays.editOverlay(self.up, {visible: false}); + Overlays.editOverlay(self.down, {visible: true}); + self.onToggle(true); + } else if (clickedOverlay === self.down) { + // flip visiblity + Overlays.editOverlay(self.up, {visible: true}); + Overlays.editOverlay(self.down, {visible: false}); + self.onToggle(false); + } + }); +} +ToggleButtonBuddy.prototype.destroy = function () { + Overlays.deleteOverlay(this.up); + Overlays.deleteOverlay(this.down); +}; +ToggleButtonBuddy.prototype.addToggleHandler = function (callback) { + this.callbacks.push(callback); + return callback; +}; +ToggleButtonBuddy.prototype.removeToggleHandler = function (callback) { + var index = this.callbacks.indexOf(callback); + if (index != -1) { + this.callbacks.splice(index, 1); + } +}; +ToggleButtonBuddy.prototype.onToggle = function (isDown) { + var i, l = this.callbacks.length; + for (i = 0; i < l; i++) { + this.callbacks[i](isDown); + } +}; + +var windowDimensions = Controller.getViewportDimensions(); +var BUTTON_WIDTH = 64; +var BUTTON_HEIGHT = 64; +var BUTTON_PADDING = 10; +var buttonPositionX = windowDimensions.x - BUTTON_PADDING - BUTTON_WIDTH; +var buttonPositionY = (windowDimensions.y - BUTTON_HEIGHT) / 2 - (BUTTON_HEIGHT + BUTTON_PADDING); + +var hatButton = new ToggleButtonBuddy(buttonPositionX, buttonPositionY, BUTTON_WIDTH, BUTTON_HEIGHT, { + up: "https://s3.amazonaws.com/hifi-public/tony/icons/hat-up.svg", + down: "https://s3.amazonaws.com/hifi-public/tony/icons/hat-down.svg" +}); + +buttonPositionY += BUTTON_HEIGHT + BUTTON_PADDING; +var coatButton = new ToggleButtonBuddy(buttonPositionX, buttonPositionY, BUTTON_WIDTH, BUTTON_HEIGHT, { + up: "https://s3.amazonaws.com/hifi-public/tony/icons/coat-up.svg", + down: "https://s3.amazonaws.com/hifi-public/tony/icons/coat-down.svg" +}); + +var HAT_ATTACHMENT = { + modelURL: "https://s3.amazonaws.com/hifi-public/tony/cowboy-hat.fbx", + jointName: "Head", + translation: {"x": 0, "y": 0.2, "z": 0}, + rotation: {"x": 0, "y": 0, "z": 0, "w": 1}, + scale: 1, + isSoft: false +}; + +var COAT_ATTACHMENT = { + modelURL: "https://hifi-content.s3.amazonaws.com/ozan/dev/clothes/coat/coat_rig.fbx", + jointName: "Hips", + translation: {"x": 0, "y": 0, "z": 0}, + rotation: {"x": 0, "y": 0, "z": 0, "w": 1}, + scale: 1, + isSoft: true +}; + +hatButton.addToggleHandler(function (isDown) { + if (isDown) { + wearAttachment(HAT_ATTACHMENT); + } else { + removeAttachment(HAT_ATTACHMENT); + } +}); + +coatButton.addToggleHandler(function (isDown) { + if (isDown) { + wearAttachment(COAT_ATTACHMENT); + } else { + removeAttachment(COAT_ATTACHMENT); + } +}); + + +function wearAttachment(attachment) { + MyAvatar.attach(attachment.modelURL, + attachment.jointName, + attachment.translation, + attachment.rotation, + attachment.scale, + attachment.isSoft); +} + +function removeAttachment(attachment) { + var attachments = MyAvatar.attachmentData; + var i, l = attachments.length; + for (i = 0; i < l; i++) { + if (attachments[i].modelURL === attachment.modelURL) { + attachments.splice(i, 1); + MyAvatar.attachmentData = attachments; + break; + } + } +} + +Script.scriptEnding.connect(function() { + hatButton.destroy(); + coatbutton.destroy(); +}); From 31bed934fe82884bdf4b8adeec84fcdcfe72a2dc Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 7 Jan 2016 16:27:14 -0800 Subject: [PATCH 044/215] fix bug caused by accidental reuse of variable -- queryAABox was often of size 1 rather than the correct dimensions --- libraries/shared/src/SpatiallyNestable.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 07d5ddeeb0..02b1c0c0ae 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -598,7 +598,8 @@ AACube SpatiallyNestable::getQueryAACube(bool& success) const { return _queryAACube; } success = false; - return AACube(getPosition(success) - glm::vec3(defaultAACubeSize / 2.0f), defaultAACubeSize); + bool getPositionSuccess; + return AACube(getPosition(getPositionSuccess) - glm::vec3(defaultAACubeSize / 2.0f), defaultAACubeSize); } AACube SpatiallyNestable::getQueryAACube() const { From d8a3ae70a7c1ff418e5403376af7de927b72bdc6 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 7 Jan 2016 17:02:15 -0800 Subject: [PATCH 045/215] Conform to coding standard --- .../render-utils/src/MeshPartPayload.cpp | 45 ++++++++++++------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index b1c40ac5b5..492021c1a9 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -99,16 +99,19 @@ ShapeKey MeshPartPayload::getShapeKey() const { drawMaterialKey = _drawMaterial->getKey(); } - bool isTranslucent = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap(); - bool hasTangents = drawMaterialKey.isNormalMap(); - bool hasSpecular = drawMaterialKey.isGlossMap(); - bool hasLightmap = drawMaterialKey.isLightmapMap(); - ShapeKey::Builder builder; - if (isTranslucent) { builder.withTranslucent(); } - if (hasTangents) { builder.withTangents(); } - if (hasSpecular) { builder.withSpecular(); } - if (hasLightmap) { builder.withLightmap(); } + if (drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap()) { + builder.withTranslucent(); + } + if (drawMaterialKey.isNormalMap()) { + builder.withTangents(); + } + if (drawMaterialKey.isGlossMap()) { + builder.withSpecular(); + } + if (drawMaterialKey.isLightmapMap()) { + builder.withLightmap(); + } return builder.build(); } @@ -395,12 +398,24 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { } ShapeKey::Builder builder; - if (isTranslucent) { builder.withTranslucent(); } - if (hasTangents) { builder.withTangents(); } - if (hasSpecular) { builder.withSpecular(); } - if (hasLightmap) { builder.withLightmap(); } - if (isSkinned) { builder.withSkinned(); } - if (wireframe) { builder.withWireframe(); } + if (isTranslucent) { + builder.withTranslucent(); + } + if (hasTangents) { + builder.withTangents(); + } + if (hasSpecular) { + builder.withSpecular(); + } + if (hasLightmap) { + builder.withLightmap(); + } + if (isSkinned) { + builder.withSkinned(); + } + if (wireframe) { + builder.withWireframe(); + } return builder.build(); } From cac19b8579f6b10a00fa8e917be7963be956db0e Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 7 Jan 2016 19:34:44 -0800 Subject: [PATCH 046/215] grab animation work Hand animations now have 5 states: * idle * open * grasp * point * farGrasp The handControllerGrab.js script now chooses one of these five animations, based on the state of the HandController object. Also, removed hand trigger AnimVar setting from C++ Rig class. --- examples/controllers/handControllerGrab.js | 178 +++++++------ .../defaultAvatar_full/avatar-animation.json | 239 ++++++++++-------- interface/src/avatar/SkeletonModel.cpp | 2 - libraries/animation/src/Rig.cpp | 42 --- libraries/animation/src/Rig.h | 2 - 5 files changed, 226 insertions(+), 237 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 419f2b78d4..432b2d46fc 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -157,7 +157,12 @@ var STATE_CONTINUE_EQUIP = 14; var STATE_WAITING_FOR_BUMPER_RELEASE = 15; var STATE_EQUIP_SPRING = 16; - +// Used by the HandAnimaitonBuddy to play hand animations +var IDLE_HAND_STATES = [STATE_OFF, STATE_RELEASE]; +var OPEN_HAND_STATES = [STATE_SEARCHING, STATE_EQUIP_SEARCHING]; +var POINT_HAND_STATES = [STATE_NEAR_TRIGGER, STATE_CONTINUE_NEAR_TRIGGER, STATE_FAR_TRIGGER, STATE_CONTINUE_FAR_TRIGGER]; +var FAR_GRASP_HAND_STATES = [STATE_DISTANCE_HOLDING, STATE_CONTINUE_DISTANCE_HOLDING]; +// otherwise grasp function stateToName(state) { switch (state) { @@ -265,6 +270,94 @@ function getSpatialOffsetRotation(hand, spatialKey) { return rotation; } +var HAND_IDLE_RAMP_ON_RATE = 0.1; +var HAND_IDLE_RAMP_OFF_RATE = 0.02; + +// ctor +function HandAnimationBuddy(handController) { + + this.handController = handController; + this.hand = handController.hand; + this.handIdleAlpha = 0; + + var handPrefix = (this.hand === RIGHT_HAND) ? "right" : "left"; + this.animVarKeys = { + idle: handPrefix + "HandIdle", + overlayAlpha: handPrefix + "HandOverlayAlpha", + open: handPrefix + "HandOpen", + point: handPrefix + "HandPoint", + farGrasp: handPrefix + "HandFarGrasp", + grasp: handPrefix + "HandGrasp" + }; + + // hook up anim var handler + var self = this; + this.animHandlerId = MyAvatar.addAnimationStateHandler(function (props) { + return self.animStateHandler(props); + }, []); +} + +HandAnimationBuddy.prototype.animStateHandler = function (props) { + var foundState = false; + var result = {}; + + var state = this.handController.state; + var keys = this.animVarKeys; + + // idle check & process + if (IDLE_HAND_STATES.indexOf(state) != -1) { + // ramp down handIdleAlpha + this.handIdleAlpha = Math.max(0, this.handIdleAlpha - HAND_IDLE_RAMP_OFF_RATE); + result[keys.idle] = true; + foundState = true; + } else { + // ramp up handIdleAlpha + this.handIdleAlpha = Math.min(1, this.handIdleAlpha + HAND_IDLE_RAMP_ON_RATE); + result[keys.idle] = false; + } + result[keys.overlayAlpha] = this.handIdleAlpha; + + // open check + if (OPEN_HAND_STATES.indexOf(state) != -1) { + result[keys.open] = true; + foundState = true; + } else { + result[keys.open] = false; + } + + // point check + if (POINT_HAND_STATES.indexOf(state) != -1) { + result[keys.point] = true; + foundState = true; + } else { + result[keys.point] = false; + } + + // far grasp check + if (FAR_GRASP_HAND_STATES.indexOf(state) != -1) { + result[keys.farGrasp] = true; + foundState = true; + } else { + result[keys.farGrasp] = false; + } + + // grasp check + if (!foundState) { + result[keys.grasp] = true; + } else { + result[keys.grasp] = false; + } + + return result; +}; + +HandAnimationBuddy.prototype.cleanup = function () { + if (this.animHandlerId) { + MyAvatar.removeAnimationStateHandler(this.animHandlerId); + this.animHandlerId = undefined; + } +}; + function MyController(hand) { this.hand = hand; if (this.hand === RIGHT_HAND) { @@ -304,84 +397,11 @@ function MyController(hand) { this.ignoreIK = false; this.offsetPosition = Vec3.ZERO; this.offsetRotation = Quat.IDENTITY; - this.handIdleAlpha = 0; - var HAND_IDLE_RAMP_ON_RATE = 0.1; - var HAND_IDLE_RAMP_OFF_RATE = 0.02; + this.handAnimationBuddy = new HandAnimationBuddy(this); var _this = this; - var farGrabStates = [STATE_DISTANCE_HOLDING, STATE_CONTINUE_DISTANCE_HOLDING]; - var pointStates = [STATE_SEARCHING, STATE_EQUIP_SEARCHING, - STATE_NEAR_TRIGGER, STATE_CONTINUE_NEAR_TRIGGER, - STATE_FAR_TRIGGER, STATE_CONTINUE_FAR_TRIGGER]; - var idleStates = [STATE_OFF]; - - var propList = ["isLeftHandFarGrab", "isLeftHandPoint", "isLeftHandIdle", "isLeftHandGrab", - "isRightHandFarGrab", "isRightHandPoint", "isRightHandIdle", "isRightHandGrab"]; - - // hook up anim var handler - this.animHandlerId = MyAvatar.addAnimationStateHandler(function (props) { - var foundState = false; - var result = {}; - - var isHandPrefix = (_this.hand === RIGHT_HAND) ? "isRight" : "isLeft"; - var handPrefix = (_this.hand === RIGHT_HAND) ? "right" : "left"; - - /* - // far grab check - if (farGrabStates.indexOf(_this.state) != -1) { - result[isHandPrefix + "HandFarGrab"] = true; - foundState = true; - } else { - result[isHandPrefix + "HandFarGrab"] = false; - } - */ - - result[handPrefix + "HandGrabBlend"] = _this.triggerValue; - - // point check - if (pointStates.indexOf(_this.state) != -1) { - result[isHandPrefix + "HandPoint"] = true; - foundState = true; - } else { - result[isHandPrefix + "HandPoint"] = false; - } - - // idle check - if (idleStates.indexOf(_this.state) != -1) { - - // ramp down handIdleAlpha - if (_this.handIdleAlpha > HAND_IDLE_RAMP_OFF_RATE) { - _this.handIdleAlpha -= HAND_IDLE_RAMP_OFF_RATE; - } else { - _this.handIdleAlpha = 0; - } - result[isHandPrefix + "HandIdle"] = true; - foundState = true; - } else { - - // ramp up handIdleAlpha - if (_this.handIdleAlpha < 1 - HAND_IDLE_RAMP_ON_RATE) { - _this.handIdleAlpha += HAND_IDLE_RAMP_ON_RATE; - } else { - _this.handIdleAlpha = 1; - } - result[isHandPrefix + "HandIdle"] = false; - } - - result[handPrefix + "HandOverlayAlpha"] = _this.handIdleAlpha; - - // grab check - if (!foundState) { - result[isHandPrefix + "HandGrab"] = true; - } else { - result[isHandPrefix + "HandGrab"] = false; - } - - return result; - }, propList); - this.update = function() { this.updateSmoothedTrigger(); @@ -1802,11 +1822,7 @@ function MyController(hand) { Entities.deleteEntity(this.particleBeam); Entities.deleteEntity(this.spotLight); Entities.deleteEntity(this.pointLight); - - if (this.animHandlerId) { - MyAvatar.removeAnimationStateHandler(this.animHandlerId); - this.animHandlerId = undefined; - } + this.handAnimationBuddy.cleanup(); }; this.activateEntity = function(entityID, grabbedProperties) { @@ -2008,4 +2024,4 @@ function renewParticleBeamLifetimes(deltaTime) { } rightController.renewParticleBeamLifetime(); leftController.renewParticleBeamLifetime(); -} \ No newline at end of file +} diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index 38cbbaa867..3f9708cdb3 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -129,36 +129,54 @@ "interpTarget": 3, "interpDuration": 3, "transitions": [ - { "var": "isRightHandPoint", "state": "rightHandPointIntro" }, - { "var": "isRightHandGrab", "state": "rightHandGrab" } + { "var": "rightHandOpen", "state": "rightHandOpen" }, + { "var": "rightHandGrasp", "state": "rightHandGrasp" }, + { "var": "rightHandPoint", "state": "rightHandPoint" }, + { "var": "rightHandFarGrasp", "state": "rightHandFarGrasp" } ] }, { - "id": "rightHandPointIntro", + "id": "rightHandOpen", "interpTarget": 3, "interpDuration": 3, "transitions": [ - { "var": "isRightHandIdle", "state": "rightHandIdle" }, - { "var": "isRightHandGrab", "state": "rightHandGrab" }, - { "var": "isRightHandPointIntroOnDone", "state": "rightHandPointHold" } + { "var": "rightHandIdle", "state": "rightHandIdle" }, + { "var": "rightHandGrasp", "state": "rightHandGrasp" }, + { "var": "rightHandPoint", "state": "rightHandPoint" }, + { "var": "rightHandFarGrasp", "state": "rightHandFarGrasp" } ] }, { - "id": "rightHandPointHold", + "id": "rightHandGrasp", "interpTarget": 3, "interpDuration": 3, "transitions": [ - { "var": "isRightHandIdle", "state": "rightHandIdle" }, - { "var": "isRightHandGrab", "state": "rightHandGrab" } + { "var": "rightHandOpen", "state": "rightHandOpen" }, + { "var": "rightHandIdle", "state": "rightHandIdle" }, + { "var": "rightHandPoint", "state": "rightHandPoint" }, + { "var": "rightHandFarGrasp", "state": "rightHandFarGrasp" } ] }, { - "id": "rightHandGrab", + "id": "rightHandPoint", "interpTarget": 3, "interpDuration": 3, "transitions": [ - { "var": "isRightHandIdle", "state": "rightHandIdle" }, - { "var": "isRightHandPoint", "state": "rightHandPointHold" } + { "var": "rightHandOpen", "state": "rightHandOpen" }, + { "var": "rightHandIdle", "state": "rightHandIdle" }, + { "var": "rightHandGrasp", "state": "rightHandGrasp" }, + { "var": "rightHandFarGrasp", "state": "rightHandFarGrasp" } + ] + }, + { + "id": "rightHandFarGrasp", + "interpTarget": 3, + "interpDuration": 3, + "transitions": [ + { "var": "rightHandOpen", "state": "rightHandOpen" }, + { "var": "rightHandIdle", "state": "rightHandIdle" }, + { "var": "rightHandGrasp", "state": "rightHandGrasp" }, + { "var": "rightHandPoint", "state": "rightHandPoint" } ] } ] @@ -177,7 +195,43 @@ "children": [] }, { - "id": "rightHandPointHold", + "id": "rightHandOpen", + "type": "clip", + "data": { + "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/force_grab_right.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "rightHandGrasp", + "type": "clip", + "data": { + "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_right.fbx", + "startFrame": 10.0, + "endFrame": 10.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "rightHandPoint", + "type": "clip", + "data": { + "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_right_hand.fbx", + "startFrame": 20.0, + "endFrame": 20.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "rightHandFarGrasp", "type": "clip", "data": { "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/force_grab_right.fbx", @@ -187,52 +241,6 @@ "loopFlag": true }, "children": [] - }, - { - "id": "rightHandPointIntro", - "type": "clip", - "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/force_grab_right.fbx", - "startFrame": 0.0, - "endFrame": 12.0, - "timeScale": 1.0, - "loopFlag": false - }, - "children": [] - }, - { - "id": "rightHandGrab", - "type": "blendLinear", - "data": { - "alpha": 0.0, - "alphaVar": "rightHandGrabBlend" - }, - "children": [ - { - "id": "rightHandOpen", - "type": "clip", - "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_right.fbx", - "startFrame": 0.0, - "endFrame": 0.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "rightHandClose", - "type": "clip", - "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_right.fbx", - "startFrame": 10.0, - "endFrame": 10.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - } - ] } ] }, @@ -256,36 +264,54 @@ "interpTarget": 3, "interpDuration": 3, "transitions": [ - { "var": "isLeftHandPoint", "state": "leftHandPointIntro" }, - { "var": "isLeftHandGrab", "state": "leftHandGrab" } + { "var": "leftHandOpen", "state": "leftHandOpen" }, + { "var": "leftHandGrasp", "state": "leftHandGrasp" }, + { "var": "leftHandPoint", "state": "leftHandPoint" }, + { "var": "leftHandFarGrasp", "state": "leftHandFarGrasp" } ] }, { - "id": "leftHandPointIntro", + "id": "leftHandOpen", "interpTarget": 3, "interpDuration": 3, "transitions": [ - { "var": "isLeftHandIdle", "state": "leftHandIdle" }, - { "var": "isLeftHandGrab", "state": "leftHandGrab" }, - { "var": "isLeftHandPointIntroOnDone", "state": "leftHandPointHold" } + { "var": "leftHandIdle", "state": "leftHandIdle" }, + { "var": "leftHandGrasp", "state": "leftHandGrasp" }, + { "var": "leftHandPoint", "state": "leftHandPoint" }, + { "var": "leftHandFarGrasp", "state": "leftHandFarGrasp" } ] }, { - "id": "leftHandPointHold", + "id": "leftHandGrasp", "interpTarget": 3, "interpDuration": 3, "transitions": [ - { "var": "isLeftHandIdle", "state": "leftHandIdle" }, - { "var": "isLeftHandGrab", "state": "leftHandGrab" } + { "var": "leftHandOpen", "state": "leftHandOpen" }, + { "var": "leftHandIdle", "state": "leftHandIdle" }, + { "var": "leftHandPoint", "state": "leftHandPoint" }, + { "var": "leftHandFarGrasp", "state": "leftHandFarGrasp" } ] }, { - "id": "leftHandGrab", + "id": "leftHandPoint", "interpTarget": 3, "interpDuration": 3, "transitions": [ - { "var": "isLeftHandIdle", "state": "leftHandIdle" }, - { "var": "isLeftHandPoint", "state": "leftHandPointHold" } + { "var": "leftHandOpen", "state": "leftHandOpen" }, + { "var": "leftHandIdle", "state": "leftHandIdle" }, + { "var": "leftHandGrasp", "state": "leftHandGrasp" }, + { "var": "leftHandFarGrasp", "state": "leftHandFarGrasp" } + ] + }, + { + "id": "leftHandFarGrasp", + "interpTarget": 3, + "interpDuration": 3, + "transitions": [ + { "var": "leftHandOpen", "state": "leftHandOpen" }, + { "var": "leftHandIdle", "state": "leftHandIdle" }, + { "var": "leftHandGrasp", "state": "leftHandGrasp" }, + { "var": "leftHandPoint", "state": "leftHandPoint" } ] } ] @@ -304,7 +330,33 @@ "children": [] }, { - "id": "leftHandPointHold", + "id": "leftHandOpen", + "type": "clip", + "data": { + + "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_left.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "leftHandGrasp", + "type": "clip", + "data": { + + "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_left.fbx", + "startFrame": 10.0, + "endFrame": 10.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "leftHandPoint", "type": "clip", "data": { "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_left_hand.fbx", @@ -316,50 +368,17 @@ "children": [] }, { - "id": "leftHandPointIntro", + "id": "leftHandFarGrasp", "type": "clip", "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_left_hand.fbx", + + "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_left.fbx", "startFrame": 0.0, - "endFrame": 12.0, + "endFrame": 0.0, "timeScale": 1.0, - "loopFlag": false + "loopFlag": true }, "children": [] - }, - { - "id": "leftHandGrab", - "type": "blendLinear", - "data": { - "alpha": 0.0, - "alphaVar": "leftHandGrabBlend" - }, - "children": [ - { - "id": "leftHandOpen", - "type": "clip", - "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_left.fbx", - "startFrame": 0.0, - "endFrame": 0.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "leftHandClose", - "type": "clip", - "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_left.fbx", - "startFrame": 10.0, - "endFrame": 10.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - } - ] } ] }, diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index e8d952973b..3cd74afb81 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -119,7 +119,6 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { handParams.isLeftEnabled = true; handParams.leftPosition = Quaternions::Y_180 * leftPalm.getRawPosition(); handParams.leftOrientation = Quaternions::Y_180 * leftPalm.getRawRotation(); - handParams.leftTrigger = leftPalm.getTrigger(); } else { handParams.isLeftEnabled = false; } @@ -129,7 +128,6 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { handParams.isRightEnabled = true; handParams.rightPosition = Quaternions::Y_180 * rightPalm.getRawPosition(); handParams.rightOrientation = Quaternions::Y_180 * rightPalm.getRawRotation(); - handParams.rightTrigger = rightPalm.getTrigger(); } else { handParams.isRightEnabled = false; } diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 8567945a87..bcda3e8f5c 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -960,7 +960,6 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm } void Rig::updateFromHandParameters(const HandParameters& params, float dt) { - if (_animSkeleton && _animNode) { if (params.isLeftEnabled) { _animVars.set("leftHandPosition", params.leftPosition); @@ -980,47 +979,6 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) { _animVars.unset("rightHandRotation"); _animVars.set("rightHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition); } - - /* - // set leftHand grab vars - _animVars.set("isLeftHandIdle", false); - _animVars.set("isLeftHandPoint", false); - _animVars.set("isLeftHandGrab", false); - - // Split the trigger range into three zones. - bool rampOut = false; - if (params.leftTrigger > 0.6666f) { - _animVars.set("isLeftHandGrab", true); - } else if (params.leftTrigger > 0.3333f) { - _animVars.set("isLeftHandPoint", true); - } else { - _animVars.set("isLeftHandIdle", true); - rampOut = true; - } - const float OVERLAY_RAMP_OUT_SPEED = 6.0f; // ramp in and out over 1/6th of a sec - _leftHandOverlayAlpha = glm::clamp(_leftHandOverlayAlpha + (rampOut ? -1.0f : 1.0f) * OVERLAY_RAMP_OUT_SPEED * dt, 0.0f, 1.0f); - _animVars.set("leftHandOverlayAlpha", _leftHandOverlayAlpha); - _animVars.set("leftHandGrabBlend", params.leftTrigger); - - // set leftHand grab vars - _animVars.set("isRightHandIdle", false); - _animVars.set("isRightHandPoint", false); - _animVars.set("isRightHandGrab", false); - - // Split the trigger range into three zones - rampOut = false; - if (params.rightTrigger > 0.6666f) { - _animVars.set("isRightHandGrab", true); - } else if (params.rightTrigger > 0.3333f) { - _animVars.set("isRightHandPoint", true); - } else { - _animVars.set("isRightHandIdle", true); - rampOut = true; - } - _rightHandOverlayAlpha = glm::clamp(_rightHandOverlayAlpha + (rampOut ? -1.0f : 1.0f) * OVERLAY_RAMP_OUT_SPEED * dt, 0.0f, 1.0f); - _animVars.set("rightHandOverlayAlpha", _rightHandOverlayAlpha); - _animVars.set("rightHandGrabBlend", params.rightTrigger); - */ } } diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 669af2ea64..0636230678 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -71,8 +71,6 @@ public: glm::quat leftOrientation = glm::quat(); // rig space (z forward) glm::vec3 rightPosition = glm::vec3(); // rig space glm::quat rightOrientation = glm::quat(); // rig space (z forward) - float leftTrigger = 0.0f; - float rightTrigger = 0.0f; }; virtual ~Rig() {} From 0f52b82c214a670b5df621507cdfd672bf6e5308 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 8 Jan 2016 11:21:37 -0800 Subject: [PATCH 047/215] allow scripted addMenu() to specify grouping --- interface/src/scripting/MenuScriptingInterface.cpp | 4 ++-- interface/src/scripting/MenuScriptingInterface.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/scripting/MenuScriptingInterface.cpp b/interface/src/scripting/MenuScriptingInterface.cpp index 087d391daa..016c8df7e3 100644 --- a/interface/src/scripting/MenuScriptingInterface.cpp +++ b/interface/src/scripting/MenuScriptingInterface.cpp @@ -27,8 +27,8 @@ void MenuScriptingInterface::menuItemTriggered() { } } -void MenuScriptingInterface::addMenu(const QString& menu) { - QMetaObject::invokeMethod(Menu::getInstance(), "addMenu", Q_ARG(const QString&, menu)); +void MenuScriptingInterface::addMenu(const QString& menu, const QString& grouping) { + QMetaObject::invokeMethod(Menu::getInstance(), "addMenu", Q_ARG(const QString&, menu), Q_ARG(const QString&, grouping)); } void MenuScriptingInterface::removeMenu(const QString& menu) { diff --git a/interface/src/scripting/MenuScriptingInterface.h b/interface/src/scripting/MenuScriptingInterface.h index 51399c2fa5..03ff4b512a 100644 --- a/interface/src/scripting/MenuScriptingInterface.h +++ b/interface/src/scripting/MenuScriptingInterface.h @@ -28,7 +28,7 @@ private slots: void menuItemTriggered(); public slots: - void addMenu(const QString& menuName); + void addMenu(const QString& menuName, const QString& grouping = QString()); void removeMenu(const QString& menuName); bool menuExists(const QString& menuName); From fb484584e4bf6c4da568d33f088ee06371b5f050 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 8 Jan 2016 11:21:55 -0800 Subject: [PATCH 048/215] fix edit.js to honor new menu spec --- examples/edit.js | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 99219fcaa2..990e99b32d 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -1026,9 +1026,8 @@ function setupModelMenus() { // adj our menuitems Menu.addMenuItem({ menuName: "Edit", - menuItemName: "Models", + menuItemName: "Entities", isSeparator: true, - beforeItem: "Physics", grouping: "Advanced" }); if (!Menu.menuItemExists("Edit", "Delete")) { @@ -1039,7 +1038,7 @@ function setupModelMenus() { shortcutKeyEvent: { text: "backspace" }, - afterItem: "Models", + afterItem: "Entities", grouping: "Advanced" }); modelMenuAddedDelete = true; @@ -1051,7 +1050,7 @@ function setupModelMenus() { menuName: "Edit", menuItemName: "Entity List...", shortcutKey: "CTRL+META+L", - afterItem: "Models", + afterItem: "Entities", grouping: "Advanced" }); Menu.addMenuItem({ @@ -1096,28 +1095,21 @@ function setupModelMenus() { }); Menu.addMenuItem({ - menuName: "File", - menuItemName: "Models", - isSeparator: true, - beforeItem: "Settings", - grouping: "Advanced" - }); - Menu.addMenuItem({ - menuName: "File", + menuName: "Edit", menuItemName: "Export Entities", shortcutKey: "CTRL+META+E", - afterItem: "Models", + afterItem: "Entities", grouping: "Advanced" }); Menu.addMenuItem({ - menuName: "File", + menuName: "Edit", menuItemName: "Import Entities", shortcutKey: "CTRL+META+I", afterItem: "Export Entities", grouping: "Advanced" }); Menu.addMenuItem({ - menuName: "File", + menuName: "Edit", menuItemName: "Import Entities from URL", shortcutKey: "CTRL+META+U", afterItem: "Import Entities", @@ -1162,7 +1154,7 @@ function setupModelMenus() { setupModelMenus(); // do this when first running our script. function cleanupModelMenus() { - Menu.removeSeparator("Edit", "Models"); + Menu.removeSeparator("Edit", "Entities"); if (modelMenuAddedDelete) { // delete our menuitems Menu.removeMenuItem("Edit", "Delete"); @@ -1175,10 +1167,9 @@ function cleanupModelMenus() { Menu.removeMenuItem("Edit", "Select All Entities In Box"); Menu.removeMenuItem("Edit", "Select All Entities Touching Box"); - Menu.removeSeparator("File", "Models"); - Menu.removeMenuItem("File", "Export Entities"); - Menu.removeMenuItem("File", "Import Entities"); - Menu.removeMenuItem("File", "Import Entities from URL"); + Menu.removeMenuItem("Edit", "Export Entities"); + Menu.removeMenuItem("Edit", "Import Entities"); + Menu.removeMenuItem("Edit", "Import Entities from URL"); Menu.removeMenuItem("Edit", MENU_AUTO_FOCUS_ON_SELECT); Menu.removeMenuItem("Edit", MENU_EASE_ON_FOCUS); From b9068d07386946a6443dea57d62238e56ad8cbca Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 8 Jan 2016 11:22:21 -0800 Subject: [PATCH 049/215] fix selectAudioDevice.js to honor new menu spec --- examples/selectAudioDevice.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/selectAudioDevice.js b/examples/selectAudioDevice.js index 440580b883..b1da219eb5 100644 --- a/examples/selectAudioDevice.js +++ b/examples/selectAudioDevice.js @@ -48,8 +48,8 @@ var selectedInputMenu = ""; var selectedOutputMenu = ""; function setupAudioMenus() { - Menu.addMenu("Tools > Audio"); - Menu.addSeparator("Tools > Audio","Output Audio Device"); + Menu.addMenu("Audio > Devices", "Advanced"); + Menu.addSeparator("Audio > Devices","Output Audio Device"); var outputDeviceSetting = Settings.getValue(OUTPUT_DEVICE_SETTING); var outputDevices = AudioDevice.getOutputDevices(); @@ -63,7 +63,7 @@ function setupAudioMenus() { var thisDeviceSelected = (outputDevices[i] == selectedOutputDevice); var menuItem = "Use " + outputDevices[i] + " for Output"; Menu.addMenuItem({ - menuName: "Tools > Audio", + menuName: "Audio > Devices", menuItemName: menuItem, isCheckable: true, isChecked: thisDeviceSelected @@ -73,7 +73,7 @@ function setupAudioMenus() { } } - Menu.addSeparator("Tools > Audio","Input Audio Device"); + Menu.addSeparator("Audio > Devices","Input Audio Device"); var inputDeviceSetting = Settings.getValue(INPUT_DEVICE_SETTING); var inputDevices = AudioDevice.getInputDevices(); @@ -87,7 +87,7 @@ function setupAudioMenus() { var thisDeviceSelected = (inputDevices[i] == selectedInputDevice); var menuItem = "Use " + inputDevices[i] + " for Input"; Menu.addMenuItem({ - menuName: "Tools > Audio", + menuName: "Audio > Devices", menuItemName: menuItem, isCheckable: true, isChecked: thisDeviceSelected @@ -99,7 +99,7 @@ function setupAudioMenus() { } function onDevicechanged() { - Menu.removeMenu("Tools > Audio"); + Menu.removeMenu("Audio > Devices"); setupAudioMenus(); } @@ -110,7 +110,7 @@ Script.setTimeout(function () { }, 5000); function scriptEnding() { - Menu.removeMenu("Tools > Audio"); + Menu.removeMenu("Audio > Devices"); } Script.scriptEnding.connect(scriptEnding); From 4c1ad6900d6970823490d5103781124c68d3e168 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 8 Jan 2016 11:28:02 -0800 Subject: [PATCH 050/215] handControllerGrab.js: removed previous animationStateHandler Which was conflicting with the new HandAnimationBuddy animationStateHandler --- examples/controllers/handControllerGrab.js | 43 ---------------------- 1 file changed, 43 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 432b2d46fc..8c2b6e76dd 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1481,8 +1481,6 @@ function MyController(hand) { } else { // equipping Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); - this.startHandGrasp(); - this.setState(STATE_CONTINUE_EQUIP_BD); } @@ -1569,7 +1567,6 @@ function MyController(hand) { this.setState(STATE_RELEASE); Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); Entities.callEntityMethod(this.grabbedEntity, "unequip"); - this.endHandGrasp(); } }; @@ -1818,7 +1815,6 @@ function MyController(hand) { this.cleanup = function() { this.release(); - this.endHandGrasp(); Entities.deleteEntity(this.particleBeam); Entities.deleteEntity(this.spotLight); Entities.deleteEntity(this.pointLight); @@ -1871,45 +1867,6 @@ function MyController(hand) { } setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); }; - - - //this is our handler, where we do the actual work of changing animation settings - this.graspHand = function(animationProperties) { - var result = {}; - //full alpha on overlay for this hand - //set grab to true - //set idle to false - //full alpha on the blend btw open and grab - if (_this.hand === RIGHT_HAND) { - result['rightHandOverlayAlpha'] = 1.0; - result['isRightHandGrab'] = true; - result['isRightHandIdle'] = false; - result['rightHandGrabBlend'] = 1.0; - } else if (_this.hand === LEFT_HAND) { - result['leftHandOverlayAlpha'] = 1.0; - result['isLeftHandGrab'] = true; - result['isLeftHandIdle'] = false; - result['leftHandGrabBlend'] = 1.0; - } - //return an object with our updated settings - return result; - }; - - this.graspHandler = null - - this.startHandGrasp = function() { - if (this.hand === RIGHT_HAND) { - this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isRightHandGrab']); - } else if (this.hand === LEFT_HAND) { - this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isLeftHandGrab']); - } - }; - - this.endHandGrasp = function() { - // Tell the animation system we don't need any more callbacks. - MyAvatar.removeAnimationStateHandler(this.graspHandler); - }; - }; var rightController = new MyController(RIGHT_HAND); From e70be2d8fef238f2cd06748d8a47f8830158c521 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 8 Jan 2016 11:58:13 -0800 Subject: [PATCH 051/215] more menu rework --- interface/src/Menu.cpp | 132 +++++++++++++++++++---------------------- 1 file changed, 62 insertions(+), 70 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d57c395b48..6373b3fdb2 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -57,9 +57,6 @@ Menu::Menu() { // File/Application menu ---------------------------------- MenuWrapper* fileMenu = addMenu("File"); - // File > Quit - addActionToQMenuAndActionHash(fileMenu, MenuOption::Quit, Qt::CTRL | Qt::Key_Q, qApp,SLOT(quit()), QAction::QuitRole); - // File > Login menu items { addActionToQMenuAndActionHash(fileMenu, MenuOption::Login); @@ -85,6 +82,68 @@ Menu::Menu() { // File > About addActionToQMenuAndActionHash(fileMenu, MenuOption::AboutApp, 0, qApp, SLOT(aboutApp()), QAction::AboutRole); + // File > Quit + addActionToQMenuAndActionHash(fileMenu, MenuOption::Quit, Qt::CTRL | Qt::Key_Q, qApp, SLOT(quit()), QAction::QuitRole); + + + // Edit menu ---------------------------------- + MenuWrapper* editMenu = addMenu("Edit"); + + // Edit > Undo + QUndoStack* undoStack = qApp->getUndoStack(); + QAction* undoAction = undoStack->createUndoAction(editMenu); + undoAction->setShortcut(Qt::CTRL | Qt::Key_Z); + addActionToQMenuAndActionHash(editMenu, undoAction); + + // Edit > Redo + QAction* redoAction = undoStack->createRedoAction(editMenu); + redoAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Z); + addActionToQMenuAndActionHash(editMenu, redoAction); + + // Edit > Running Sccripts + addActionToQMenuAndActionHash(editMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J, + qApp, SLOT(toggleRunningScriptsWidget())); + + // Edit > Open and Run Script from File... [advanced] + addActionToQMenuAndActionHash(editMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, + qApp, SLOT(loadDialog()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + + // Edit > Open and Run Script from Url... [advanced] + addActionToQMenuAndActionHash(editMenu, MenuOption::LoadScriptURL, + Qt::CTRL | Qt::SHIFT | Qt::Key_O, qApp, SLOT(loadScriptURLDialog()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + + // Edit > Stop All Scripts... [advanced] + addActionToQMenuAndActionHash(editMenu, MenuOption::StopAllScripts, 0, qApp, SLOT(stopAllScripts()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + + // Edit > Reload All Scripts... [advanced] + addActionToQMenuAndActionHash(editMenu, MenuOption::ReloadAllScripts, Qt::CTRL | Qt::Key_R, + qApp, SLOT(reloadAllScripts()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + + // Edit > Scripts Editor... [advanced] + addActionToQMenuAndActionHash(editMenu, MenuOption::ScriptEditor, Qt::ALT | Qt::Key_S, + dialogsManager.data(), SLOT(showScriptEditor()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + + // Edit > Console... [advanced] + addActionToQMenuAndActionHash(editMenu, MenuOption::Console, Qt::CTRL | Qt::ALT | Qt::Key_J, + DependencyManager::get().data(), + SLOT(toggleConsole()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + + // Edit > Reload All Content [advanced] + addActionToQMenuAndActionHash(editMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + + + // Edit > Package Model... [advanced] + addActionToQMenuAndActionHash(editMenu, MenuOption::PackageModel, 0, + qApp, SLOT(packageModel()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + // Audio menu ---------------------------------- MenuWrapper* audioMenu = addMenu("Audio"); @@ -186,65 +245,6 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::MiniMirror, 0, false); - // Edit menu ---------------------------------- - MenuWrapper* editMenu = addMenu("Edit"); - - // Edit > Undo - QUndoStack* undoStack = qApp->getUndoStack(); - QAction* undoAction = undoStack->createUndoAction(editMenu); - undoAction->setShortcut(Qt::CTRL | Qt::Key_Z); - addActionToQMenuAndActionHash(editMenu, undoAction); - - // Edit > Redo - QAction* redoAction = undoStack->createRedoAction(editMenu); - redoAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Z); - addActionToQMenuAndActionHash(editMenu, redoAction); - - // Edit > Running Sccripts - addActionToQMenuAndActionHash(editMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J, - qApp, SLOT(toggleRunningScriptsWidget())); - - // Edit > Open and Run Script from File... [advanced] - addActionToQMenuAndActionHash(editMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, - qApp, SLOT(loadDialog()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - - // Edit > Open and Run Script from Url... [advanced] - addActionToQMenuAndActionHash(editMenu, MenuOption::LoadScriptURL, - Qt::CTRL | Qt::SHIFT | Qt::Key_O, qApp, SLOT(loadScriptURLDialog()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - - // Edit > Stop All Scripts... [advanced] - addActionToQMenuAndActionHash(editMenu, MenuOption::StopAllScripts, 0, qApp, SLOT(stopAllScripts()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - - // Edit > Reload All Scripts... [advanced] - addActionToQMenuAndActionHash(editMenu, MenuOption::ReloadAllScripts, Qt::CTRL | Qt::Key_R, - qApp, SLOT(reloadAllScripts()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - - // Edit > Scripts Editor... [advanced] - addActionToQMenuAndActionHash(editMenu, MenuOption::ScriptEditor, Qt::ALT | Qt::Key_S, - dialogsManager.data(), SLOT(showScriptEditor()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - - // Edit > Console... [advanced] - addActionToQMenuAndActionHash(editMenu, MenuOption::Console, Qt::CTRL | Qt::ALT | Qt::Key_J, - DependencyManager::get().data(), - SLOT(toggleConsole()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - - // Edit > Reload All Content [advanced] - addActionToQMenuAndActionHash(editMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - - - // Edit > Package Model... [advanced] - addActionToQMenuAndActionHash(editMenu, MenuOption::PackageModel, 0, - qApp, SLOT(packageModel()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - - // Navigate menu ---------------------------------- MenuWrapper* navigateMenu = addMenu("Navigate"); @@ -273,14 +273,6 @@ Menu::Menu() { QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - // Market menu ---------------------------------- - MenuWrapper* marketMenu = addMenu("Market"); - - // Market > Marketplace... -- FIXME: needs implementation - auto marketplaceAction = addActionToQMenuAndActionHash(marketMenu, "Marketplace..."); - marketplaceAction->setDisabled(true); - - // Settings menu ---------------------------------- MenuWrapper* settingsMenu = addMenu("Settings"); From 86691d5d0e2af3351e105e0f4a8e512081a52526 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 8 Jan 2016 13:12:43 -0800 Subject: [PATCH 052/215] remove vsync and framerate menus from 2d display plugin --- .../Basic2DWindowOpenGLDisplayPlugin.cpp | 63 +------------------ 1 file changed, 2 insertions(+), 61 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp index 71a885b31c..290e2e4f79 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp @@ -18,13 +18,6 @@ const QString Basic2DWindowOpenGLDisplayPlugin::NAME("2D Display"); static const QString FULLSCREEN = "Fullscreen"; -static const QString FRAMERATE = DisplayPlugin::MENU_PATH() + ">Framerate"; -static const QString FRAMERATE_UNLIMITED = "Unlimited"; -static const QString FRAMERATE_60 = "60"; -static const QString FRAMERATE_50 = "50"; -static const QString FRAMERATE_40 = "40"; -static const QString FRAMERATE_30 = "30"; -static const QString VSYNC_ON = "V-Sync On"; const QString& Basic2DWindowOpenGLDisplayPlugin::getName() const { return NAME; @@ -42,38 +35,12 @@ void Basic2DWindowOpenGLDisplayPlugin::activate() { _container->unsetFullscreen(); } }, true, false); - _container->addMenu(FRAMERATE); - _framerateActions.push_back( - _container->addMenuItem(PluginType::DISPLAY_PLUGIN, FRAMERATE, FRAMERATE_UNLIMITED, - [this](bool) { updateFramerate(); }, true, true, FRAMERATE)); - _framerateActions.push_back( - _container->addMenuItem(PluginType::DISPLAY_PLUGIN, FRAMERATE, FRAMERATE_60, - [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - _framerateActions.push_back( - _container->addMenuItem(PluginType::DISPLAY_PLUGIN, FRAMERATE, FRAMERATE_50, - [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - _framerateActions.push_back( - _container->addMenuItem(PluginType::DISPLAY_PLUGIN, FRAMERATE, FRAMERATE_40, - [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - _framerateActions.push_back( - _container->addMenuItem(PluginType::DISPLAY_PLUGIN, FRAMERATE, FRAMERATE_30, - [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - - // Vsync detection happens in the parent class activate, so we need to check after that - if (_vsyncSupported) { - _vsyncAction = _container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), VSYNC_ON, [this](bool) {}, true, true); - } else { - _vsyncAction = nullptr; - } updateFramerate(); } void Basic2DWindowOpenGLDisplayPlugin::submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) { - if (_vsyncAction) { - _wantVsync = _vsyncAction->isChecked(); - } - + _wantVsync = true; // always WindowOpenGLDisplayPlugin::submitSceneTexture(frameIndex, sceneTexture, sceneSize); } @@ -87,9 +54,7 @@ const uint32_t THROTTLED_FRAMERATE = 15; int Basic2DWindowOpenGLDisplayPlugin::getDesiredInterval() const { static const int ULIMIITED_PAINT_TIMER_DELAY_MS = 1; int result = ULIMIITED_PAINT_TIMER_DELAY_MS; - if (0 != _framerateTarget) { - result = MSECS_PER_SECOND / _framerateTarget; - } else if (_isThrottled) { + if (_isThrottled) { // This test wouldn't be necessary if we could depend on updateFramerate setting _framerateTarget. // Alas, that gets complicated: isThrottled() is const and other stuff depends on it. result = MSECS_PER_SECOND / THROTTLED_FRAMERATE; @@ -112,30 +77,6 @@ bool Basic2DWindowOpenGLDisplayPlugin::isThrottled() const { } void Basic2DWindowOpenGLDisplayPlugin::updateFramerate() { - QAction* checkedFramerate{ nullptr }; - foreach(auto action, _framerateActions) { - if (action->isChecked()) { - checkedFramerate = action; - break; - } - } - - _framerateTarget = 0; - if (checkedFramerate) { - QString actionText = checkedFramerate->text(); - if (FRAMERATE_60 == actionText) { - _framerateTarget = 60; - } else if (FRAMERATE_50 == actionText) { - _framerateTarget = 50; - } else if (FRAMERATE_40 == actionText) { - _framerateTarget = 40; - } else if (FRAMERATE_30 == actionText) { - _framerateTarget = 30; - } - } else if (_isThrottled) { - _framerateTarget = THROTTLED_FRAMERATE; - } - int newInterval = getDesiredInterval(); _timer.start(newInterval); } From 56aba412993e2db8250afc4b7921266b2eacf98b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 8 Jan 2016 12:57:47 -0800 Subject: [PATCH 053/215] Rename ShapeRender to DeferredPipelineLib --- ...ShapeRender.cpp => DeferredPipelineLib.cpp} | 18 +++++++++--------- .../{ShapeRender.h => DeferredPipelineLib.h} | 12 ++++++------ libraries/render-utils/src/MeshPartPayload.h | 3 +-- libraries/render-utils/src/Model.cpp | 5 +++-- .../render-utils/src/RenderDeferredTask.cpp | 6 +++--- .../render-utils/src/RenderDeferredTask.h | 8 ++++---- 6 files changed, 26 insertions(+), 26 deletions(-) rename libraries/render-utils/src/{ShapeRender.cpp => DeferredPipelineLib.cpp} (92%) rename libraries/render-utils/src/{ShapeRender.h => DeferredPipelineLib.h} (69%) diff --git a/libraries/render-utils/src/ShapeRender.cpp b/libraries/render-utils/src/DeferredPipelineLib.cpp similarity index 92% rename from libraries/render-utils/src/ShapeRender.cpp rename to libraries/render-utils/src/DeferredPipelineLib.cpp index c4ac9f3c2b..0526700633 100644 --- a/libraries/render-utils/src/ShapeRender.cpp +++ b/libraries/render-utils/src/DeferredPipelineLib.cpp @@ -1,5 +1,5 @@ // -// ShapeRender.cpp +// DeferredPipelineLib.cpp // render-utils/src // // Created by Zach Pomerantz on 1/4/2015. @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "ShapeRender.h" +#include "DeferredPipelineLib.h" #include @@ -37,15 +37,15 @@ #include "model_lightmap_specular_map_frag.h" #include "model_translucent_frag.h" -ShapeRender::ShapeRender() { - // TODO: Move pipeline initialization to those Jobs using ShapeRender +DeferredPipelineLib::DeferredPipelineLib() { + // TODO: Move pipeline initialization to those Jobs using DeferredPipelineLib // such that they own their own pipelines and it is done only once if (_pipelineLib.empty()) { initPipeline(); } } -void ShapeRender::initPipeline() { +void DeferredPipelineLib::initPipeline() { assert(_pipelineLib.empty()); // Vertex shaders @@ -171,8 +171,8 @@ void ShapeRender::initPipeline() { skinModelShadowVertex, modelShadowPixel); } -const ShapeRender::PipelinePointer ShapeRender::pickPipeline(RenderArgs* args, const Key& key) const { - PerformanceTimer perfTimer("ShapeRender::pickPipeline"); +const DeferredPipelineLib::PipelinePointer DeferredPipelineLib::pickPipeline(RenderArgs* args, const Key& key) const { + PerformanceTimer perfTimer("DeferredPipelineLib::pickPipeline"); auto pipeline = _pickPipeline(args, key); if (!pipeline) { @@ -187,9 +187,9 @@ const ShapeRender::PipelinePointer ShapeRender::pickPipeline(RenderArgs* args, c return pipeline; } -model::MaterialPointer ShapeRender::_collisionHullMaterial; +model::MaterialPointer DeferredPipelineLib::_collisionHullMaterial; -model::MaterialPointer ShapeRender::getCollisionHullMaterial() { +model::MaterialPointer DeferredPipelineLib::getCollisionHullMaterial() { if (!_collisionHullMaterial) { _collisionHullMaterial = std::make_shared(); _collisionHullMaterial->setDiffuse(glm::vec3(1.0f, 0.5f, 0.0f)); diff --git a/libraries/render-utils/src/ShapeRender.h b/libraries/render-utils/src/DeferredPipelineLib.h similarity index 69% rename from libraries/render-utils/src/ShapeRender.h rename to libraries/render-utils/src/DeferredPipelineLib.h index 590eca5511..98408d7754 100644 --- a/libraries/render-utils/src/ShapeRender.h +++ b/libraries/render-utils/src/DeferredPipelineLib.h @@ -1,5 +1,5 @@ // -// ShapeRender.h +// DeferredPipelineLib.h // render-utils/src // // Created by Zach Pomerantz on 1/4/2015. @@ -9,15 +9,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_render_utils_Shape_h -#define hifi_render_utils_Shape_h +#ifndef hifi_render_utils_DeferredPipelineLib_h +#define hifi_render_utils_DeferredPipelineLib_h #include #include -class ShapeRender : public render::ShapePipelineLib { +class DeferredPipelineLib : public render::ShapePipelineLib { public: - ShapeRender(); + DeferredPipelineLib(); static void initPipeline(); const PipelinePointer pickPipeline(RenderArgs* args, const Key& key) const override; @@ -27,4 +27,4 @@ protected: static model::MaterialPointer _collisionHullMaterial; }; -#endif // hifi_render_utils_Shape_h +#endif // hifi_render_utils_DeferredPipelineLib_h diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 7d693dcbe9..d771a57203 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -15,11 +15,10 @@ #include #include +#include #include -#include "ShapeRender.h" - class Model; class MeshPartPayload { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index b40d2565c3..40352a1bc3 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -22,8 +22,9 @@ #include #include "AbstractViewStateInterface.h" -#include "Model.h" +#include "DeferredPipelineLib.h" #include "MeshPartPayload.h" +#include "Model.h" #include "RenderUtilsLogging.h" @@ -1193,7 +1194,7 @@ void Model::segregateMeshGroups() { int totalParts = mesh.parts.size(); for (int partIndex = 0; partIndex < totalParts; partIndex++) { if (showingCollisionHull) { - _renderItemsSet << std::make_shared(networkMesh._mesh, partIndex, ShapeRender::getCollisionHullMaterial(), transform, offset); + _renderItemsSet << std::make_shared(networkMesh._mesh, partIndex, DeferredPipelineLib::getCollisionHullMaterial(), transform, offset); } else { _renderItemsSet << std::make_shared(this, i, partIndex, shapeID, transform, offset); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index a35447cd05..e3bf699fc8 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -193,7 +193,7 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - renderShapes(sceneContext, renderContext, _renderer, inItems, opaque.maxDrawn); + renderShapes(sceneContext, renderContext, _deferredPipelineLib, inItems, opaque.maxDrawn); args->_batch = nullptr; }); } @@ -219,7 +219,7 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - renderShapes(sceneContext, renderContext, _renderer, inItems, transparent.maxDrawn); + renderShapes(sceneContext, renderContext, _deferredPipelineLib, inItems, transparent.maxDrawn); args->_batch = nullptr; }); } @@ -292,7 +292,7 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon batch.setPipeline(getOpaquePipeline()); batch.setResourceTexture(0, args->_whiteTexture); - renderShapes(sceneContext, renderContext, _renderer, inItems, renderContext->getItemsConfig().overlay3D.maxDrawn); + renderShapes(sceneContext, renderContext, _deferredPipelineLib, inItems, renderContext->getItemsConfig().overlay3D.maxDrawn); }); args->_batch = nullptr; args->_whiteTexture.reset(); diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 01e9ab2a16..171fe843da 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -16,7 +16,7 @@ #include "gpu/Pipeline.h" -#include "ShapeRender.h" +#include "DeferredPipelineLib.h" #include "ToneMappingEffect.h" class SetupDeferred { @@ -57,7 +57,7 @@ public: typedef render::Job::ModelI JobModel; protected: - ShapeRender _renderer; + DeferredPipelineLib _deferredPipelineLib; }; class DrawTransparentDeferred { @@ -67,7 +67,7 @@ public: typedef render::Job::ModelI JobModel; protected: - ShapeRender _renderer; + DeferredPipelineLib _deferredPipelineLib; }; class DrawStencilDeferred { @@ -99,7 +99,7 @@ public: protected: static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable - ShapeRender _renderer; + DeferredPipelineLib _deferredPipelineLib; }; class Blit { From b3f19ef4d614eb3500830ba955051abaa11d7bf4 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 8 Jan 2016 16:08:43 -0800 Subject: [PATCH 054/215] separating out marketplace --- examples/marketplace.js | 121 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 examples/marketplace.js diff --git a/examples/marketplace.js b/examples/marketplace.js new file mode 100644 index 0000000000..27e2da56e3 --- /dev/null +++ b/examples/marketplace.js @@ -0,0 +1,121 @@ +Script.include([ + "libraries/toolBars.js", +]); + +HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; +var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/"; + +var MARKETPLACE_URL = "https://metaverse.highfidelity.com/marketplace"; +var marketplaceWindow = new OverlayWebWindow({ + title: 'Marketplace', + source: "about:blank", + width: 900, + height: 700, + visible: false +}); + +var toolHeight = 50; +var toolWidth = 50; + + +function showMarketplace(marketplaceID) { + var url = MARKETPLACE_URL; + if (marketplaceID) { + url = url + "/items/" + marketplaceID; + } + print("setting marketplace URL to " + url); + marketplaceWindow.setURL(url); + marketplaceWindow.setVisible(true); + marketplaceWindow.raise(); +} + +function hideMarketplace() { + marketplaceWindow.setVisible(false); + marketplaceWindow.setURL("about:blank"); +} + +function toggleMarketplace() { + if (marketplaceWindow.visible) { + hideMarketplace(); + } else { + showMarketplace(); + } +} + +var toolBar = (function() { + var that = {}, + toolBar, + browseMarketplaceButton; + + function initialize() { + toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.edit.toolbar", function(windowDimensions, toolbar) { + return { + x: windowDimensions.x - 100 - toolbar.width, + y: (windowDimensions.y - toolbar.height) / 2 + }; + }); + browseMarketplaceButton = toolBar.addTool({ + imageURL: toolIconUrl + "marketplace.svg", + width: toolWidth, + height: toolHeight, + alpha: 0.9, + visible: true, + }); + + toolBar.showTool(browseMarketplaceButton, true); + } + + var browseMarketplaceButtonDown = false; + that.mousePressEvent = function(event) { + print("CLICKED") + var clickedOverlay, + url, + file; + + if (!event.isLeftButton) { + // if another mouse button than left is pressed ignore it + return false; + } + + clickedOverlay = Overlays.getOverlayAtPoint({ + x: event.x, + y: event.y + }); + + + + if (browseMarketplaceButton === toolBar.clicked(clickedOverlay)) { + toggleMarketplace(); + return true; + } + + return false; + }; + + that.mouseReleaseEvent = function(event) { + var handled = false; + + + if (browseMarketplaceButtonDown) { + var clickedOverlay = Overlays.getOverlayAtPoint({ + x: event.x, + y: event.y + }); + } + + newModelButtonDown = false; + browseMarketplaceButtonDown = false; + + return handled; + } + + that.cleanup = function() { + toolBar.cleanup(); + }; + + initialize(); + return that; +}()); + +Controller.mousePressEvent.connect(toolBar.mousePressEvent) +Script.scriptEnding.connect(toolBar.cleanup); From 7e7424ec2b88fb6f099262a0f8981fc8e7c702ac Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 8 Jan 2016 16:22:10 -0800 Subject: [PATCH 055/215] Removed marketplace icon from edit menu --- examples/edit.js | 32 ++++---------------------------- examples/marketplace.js | 6 +++--- 2 files changed, 7 insertions(+), 31 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 99219fcaa2..5d724576d3 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -183,8 +183,7 @@ var toolBar = (function() { newTextButton, newWebButton, newZoneButton, - newPolyVoxButton, - browseMarketplaceButton; + newPolyVoxButton; function initialize() { toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.edit.toolbar", function(windowDimensions, toolbar) { @@ -194,13 +193,7 @@ var toolBar = (function() { }; }); - browseMarketplaceButton = toolBar.addTool({ - imageURL: toolIconUrl + "marketplace.svg", - width: toolWidth, - height: toolHeight, - alpha: 0.9, - visible: true, - }); + activeButton = toolBar.addTool({ imageURL: toolIconUrl + "edit-status.svg", @@ -415,7 +408,6 @@ var toolBar = (function() { } var newModelButtonDown = false; - var browseMarketplaceButtonDown = false; that.mousePressEvent = function(event) { var clickedOverlay, url, @@ -443,11 +435,7 @@ var toolBar = (function() { return true; } - if (browseMarketplaceButton === toolBar.clicked(clickedOverlay)) { - toggleMarketplace(); - return true; - } - + if (newCubeButton === toolBar.clicked(clickedOverlay)) { createNewEntity({ type: "Box", @@ -652,22 +640,10 @@ var toolBar = (function() { } handled = true; } - } else if (browseMarketplaceButtonDown) { - var clickedOverlay = Overlays.getOverlayAtPoint({ - x: event.x, - y: event.y - }); - if (browseMarketplaceButton === toolBar.clicked(clickedOverlay)) { - url = Window.s3Browse(".*(fbx|FBX|obj|OBJ)"); - if (url !== null && url !== "") { - addModel(url); - } - handled = true; - } } newModelButtonDown = false; - browseMarketplaceButtonDown = false; + return handled; } diff --git a/examples/marketplace.js b/examples/marketplace.js index 27e2da56e3..074966c196 100644 --- a/examples/marketplace.js +++ b/examples/marketplace.js @@ -48,10 +48,10 @@ var toolBar = (function() { browseMarketplaceButton; function initialize() { - toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.edit.toolbar", function(windowDimensions, toolbar) { + toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "", function(windowDimensions, toolbar) { return { - x: windowDimensions.x - 100 - toolbar.width, - y: (windowDimensions.y - toolbar.height) / 2 + x: windowDimensions.x - 8 - toolbar.width, + y: 150 }; }); browseMarketplaceButton = toolBar.addTool({ From a66bc791a3e2248c7dca777df513388628abceb4 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 8 Jan 2016 16:33:51 -0800 Subject: [PATCH 056/215] directory.js - icon is now movable and persistent --- examples/directory.js | 166 +++++++++++++++++++++++----------------- examples/marketplace.js | 15 +++- 2 files changed, 109 insertions(+), 72 deletions(-) diff --git a/examples/directory.js b/examples/directory.js index 8d9993ffda..69db3a4d89 100644 --- a/examples/directory.js +++ b/examples/directory.js @@ -9,89 +9,117 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include("libraries/globals.js"); +Script.include([ + "libraries/toolBars.js", +]); -var directory = (function () { +HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; +var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/"; - var DIRECTORY_URL = "https://metaverse.highfidelity.com/directory", - directoryWindow, - DIRECTORY_BUTTON_URL = HIFI_PUBLIC_BUCKET + "images/tools/directory.svg", - BUTTON_WIDTH = 50, - BUTTON_HEIGHT = 50, - BUTTON_ALPHA = 0.9, - BUTTON_MARGIN = 8, - directoryButton, - EDIT_TOOLBAR_BUTTONS = 10, // Number of buttons in edit.js toolbar - viewport; +var DIRECTORY_WINDOW_URL = "https://metaverse.highfidelity.com/directory"; +var directoryWindow = new OverlayWebWindow({ + title: 'directory', + source: "about:blank", + width: 900, + height: 700, + visible: false +}); - function updateButtonPosition() { - Overlays.editOverlay(directoryButton, { - x: viewport.x - BUTTON_WIDTH - BUTTON_MARGIN, - y: (viewport.y - (EDIT_TOOLBAR_BUTTONS + 1) * (BUTTON_HEIGHT + BUTTON_MARGIN) - BUTTON_MARGIN) / 2 - 1 +var toolHeight = 50; +var toolWidth = 50; + + +function showDirectory() { + directoryWindow.setURL(DIRECTORY_WINDOW_URL); + directoryWindow.setVisible(true); +} + +function hideDirectory() { + directoryWindow.setVisible(false); + directoryWindow.setURL("about:blank"); +} + +function toggleDirectory() { + if (directoryWindow.visible) { + hideDirectory(); + } else { + showDirectory(); + } +} + +var toolBar = (function() { + var that = {}, + toolBar, + browseDirectoryButton; + + function initialize() { + toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.directory.toolbar", function(windowDimensions, toolbar) { + return { + x: windowDimensions.x - 8 - toolbar.width, + y: 100 + }; }); + browseDirectoryButton = toolBar.addTool({ + imageURL: toolIconUrl + "directory.svg", + width: toolWidth, + height: toolHeight, + alpha: 0.9, + visible: true, + }); + + toolBar.showTool(browseDirectoryButton, true); } - function onMousePressEvent(event) { - var clickedOverlay; + var browseDirectoryButtonDown = false; + that.mousePressEvent = function(event) { + var clickedOverlay, + url, + file; - clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); - - if (clickedOverlay === directoryButton) { - if (directoryWindow.url !== DIRECTORY_URL) { - directoryWindow.setURL(DIRECTORY_URL); - } - directoryWindow.setVisible(true); - directoryWindow.raise(); + if (!event.isLeftButton) { + // if another mouse button than left is pressed ignore it + return false; } - } - function onDomainChanged() { - directoryWindow.setVisible(false); - } + clickedOverlay = Overlays.getOverlayAtPoint({ + x: event.x, + y: event.y + }); - function onScriptUpdate() { - var oldViewport = viewport; - viewport = Controller.getViewportDimensions(); - if (viewport.x !== oldViewport.x || viewport.y !== oldViewport.y) { - updateButtonPosition(); + if (browseDirectoryButton === toolBar.clicked(clickedOverlay)) { + toggleDirectory(); + return true; } + + return false; + }; + + that.mouseReleaseEvent = function(event) { + var handled = false; + + + if (browseDirectoryButtonDown) { + var clickedOverlay = Overlays.getOverlayAtPoint({ + x: event.x, + y: event.y + }); + } + + newModelButtonDown = false; + browseDirectoryButtonDown = false; + + return handled; } - function setUp() { - viewport = Controller.getViewportDimensions(); + that.cleanup = function() { + toolBar.cleanup(); + }; - directoryWindow = new OverlayWebWindow({ - title: 'Directory', - source: DIRECTORY_URL, - width: 900, - height: 700, - visible: false - }); + initialize(); + return that; +}()); - directoryButton = Overlays.addOverlay("image", { - imageURL: DIRECTORY_BUTTON_URL, - width: BUTTON_WIDTH, - height: BUTTON_HEIGHT, - x: viewport.x - BUTTON_WIDTH - BUTTON_MARGIN, - y: BUTTON_MARGIN, - alpha: BUTTON_ALPHA, - visible: true - }); - - updateButtonPosition(); - - Controller.mousePressEvent.connect(onMousePressEvent); - Window.domainChanged.connect(onDomainChanged); - - Script.update.connect(onScriptUpdate); - } - - function tearDown() { - Overlays.deleteOverlay(directoryButton); - } - - setUp(); - Script.scriptEnding.connect(tearDown); -}()); \ No newline at end of file +Controller.mousePressEvent.connect(toolBar.mousePressEvent) +Script.scriptEnding.connect(toolBar.cleanup); diff --git a/examples/marketplace.js b/examples/marketplace.js index 074966c196..4583492c58 100644 --- a/examples/marketplace.js +++ b/examples/marketplace.js @@ -1,3 +1,14 @@ +// +// marketplace.js +// examples +// +// Created by Eric Levin on 8 Jan 2016 +// Copyright 2016 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 +// + Script.include([ "libraries/toolBars.js", ]); @@ -26,7 +37,6 @@ function showMarketplace(marketplaceID) { print("setting marketplace URL to " + url); marketplaceWindow.setURL(url); marketplaceWindow.setVisible(true); - marketplaceWindow.raise(); } function hideMarketplace() { @@ -48,7 +58,7 @@ var toolBar = (function() { browseMarketplaceButton; function initialize() { - toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "", function(windowDimensions, toolbar) { + toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.marketplace.toolbar", function(windowDimensions, toolbar) { return { x: windowDimensions.x - 8 - toolbar.width, y: 150 @@ -67,7 +77,6 @@ var toolBar = (function() { var browseMarketplaceButtonDown = false; that.mousePressEvent = function(event) { - print("CLICKED") var clickedOverlay, url, file; From e2a3903def092d2169e1f507747312892da063d9 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 8 Jan 2016 16:58:25 -0800 Subject: [PATCH 057/215] add support for advanced/developer plugins and change diplay modes to match spec --- interface/src/Application.cpp | 29 ++++++++++++++++++- interface/src/Menu.h | 2 +- .../Basic2DWindowOpenGLDisplayPlugin.cpp | 7 ++--- .../Basic2DWindowOpenGLDisplayPlugin.h | 4 ++- .../src/display-plugins/NullDisplayPlugin.cpp | 1 + .../src/display-plugins/NullDisplayPlugin.h | 1 + .../stereo/InterleavedStereoDisplayPlugin.cpp | 7 ++--- .../stereo/InterleavedStereoDisplayPlugin.h | 5 +++- .../stereo/SideBySideStereoDisplayPlugin.cpp | 5 +--- .../stereo/SideBySideStereoDisplayPlugin.h | 4 ++- .../src/input-plugins/KeyboardMouseDevice.cpp | 1 + .../src/input-plugins/KeyboardMouseDevice.h | 4 ++- libraries/plugins/src/plugins/Plugin.h | 3 ++ plugins/hifiNeuron/src/NeuronPlugin.cpp | 1 + plugins/hifiNeuron/src/NeuronPlugin.h | 4 ++- plugins/hifiSdl2/src/SDL2Manager.cpp | 1 + plugins/hifiSdl2/src/SDL2Manager.h | 4 ++- plugins/hifiSixense/src/SixenseManager.cpp | 1 + plugins/hifiSixense/src/SixenseManager.h | 6 ++-- .../oculus/src/OculusDebugDisplayPlugin.cpp | 4 +-- plugins/oculus/src/OculusDebugDisplayPlugin.h | 4 ++- plugins/oculus/src/OculusDisplayPlugin.cpp | 5 +--- plugins/oculus/src/OculusDisplayPlugin.h | 6 ++-- plugins/openvr/src/OpenVrDisplayPlugin.cpp | 4 +-- plugins/openvr/src/OpenVrDisplayPlugin.h | 4 ++- 25 files changed, 79 insertions(+), 38 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b142b6cb71..7be74e717e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5062,6 +5062,7 @@ const DisplayPlugin* Application::getActiveDisplayPlugin() const { static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool active = false) { auto menu = Menu::getInstance(); QString name = displayPlugin->getName(); + QString grouping = displayPlugin->getGrouping(); Q_ASSERT(!menu->menuItemExists(MenuOption::OutputMenu, name)); static QActionGroup* displayPluginGroup = nullptr; @@ -5072,7 +5073,8 @@ static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool acti auto parent = menu->getMenu(MenuOption::OutputMenu); auto action = menu->addActionToQMenuAndActionHash(parent, name, 0, qApp, - SLOT(updateDisplayMode())); + SLOT(updateDisplayMode()), + QAction::NoRole, UNSPECIFIED_POSITION, grouping); action->setCheckable(true); action->setChecked(active); displayPluginGroup->addAction(action); @@ -5086,7 +5088,27 @@ void Application::updateDisplayMode() { static std::once_flag once; std::call_once(once, [&] { bool first = true; + + // first sort the plugins into groupings: standard, advanced, developer + DisplayPluginList standard; + DisplayPluginList advanced; + DisplayPluginList developer; foreach(auto displayPlugin, displayPlugins) { + QString grouping = displayPlugin->getGrouping(); + if (grouping == "Advanced") { + advanced.push_back(displayPlugin); + } else if (grouping == "Developer") { + developer.push_back(displayPlugin); + } else { + standard.push_back(displayPlugin); + } + } + + // concactonate the groupings into a single list in the order: standard, advanced, developer + standard.insert(std::end(standard), std::begin(advanced), std::end(advanced)); + standard.insert(std::end(standard), std::begin(developer), std::end(developer)); + + foreach(auto displayPlugin, standard) { addDisplayPluginToMenu(displayPlugin, first); // This must be a queued connection to avoid a deadlock QObject::connect(displayPlugin.get(), &DisplayPlugin::requestRender, @@ -5098,6 +5120,11 @@ void Application::updateDisplayMode() { first = false; } + + // after all plugins have been added to the menu, add a seperator to the menu + auto menu = Menu::getInstance(); + auto parent = menu->getMenu(MenuOption::OutputMenu); + parent->addSeparator(); }); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 085b349b8f..6a544f31c9 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -243,7 +243,7 @@ namespace MenuOption { const QString OctreeStats = "Entity Statistics"; const QString OnePointCalibration = "1 Point Calibration"; const QString OnlyDisplayTopTen = "Only Display Top Ten"; - const QString OutputMenu = "Display>Mode"; + const QString OutputMenu = "Display"; const QString PackageModel = "Package Model..."; const QString Pair = "Pair"; const QString PhysicsShowOwned = "Highlight Simulation Ownership"; diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp index 290e2e4f79..11bed0e0af 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp @@ -15,14 +15,11 @@ #include -const QString Basic2DWindowOpenGLDisplayPlugin::NAME("2D Display"); +const QString Basic2DWindowOpenGLDisplayPlugin::NAME("Desktop"); +const QString Basic2DWindowOpenGLDisplayPlugin::GROUPING("Standard"); static const QString FULLSCREEN = "Fullscreen"; -const QString& Basic2DWindowOpenGLDisplayPlugin::getName() const { - return NAME; -} - void Basic2DWindowOpenGLDisplayPlugin::activate() { WindowOpenGLDisplayPlugin::activate(); diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h index e3633b5fe8..29e26c1f28 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h @@ -18,7 +18,8 @@ class Basic2DWindowOpenGLDisplayPlugin : public WindowOpenGLDisplayPlugin { Q_OBJECT public: - virtual const QString & getName() const override; + virtual const QString& getName() const override { return NAME; } + virtual const QString& getGrouping() const override { return GROUPING; } virtual float getTargetFrameRate() override { return _framerateTarget ? (float) _framerateTarget : TARGET_FRAMERATE_Basic2DWindowOpenGL; } @@ -37,6 +38,7 @@ protected: private: void updateFramerate(); static const QString NAME; + static const QString GROUPING; QScreen* getFullscreenTarget(); std::vector _framerateActions; QAction* _vsyncAction { nullptr }; diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp index f780534bc9..54cf13fccd 100644 --- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp @@ -13,6 +13,7 @@ #include const QString NullDisplayPlugin::NAME("NullDisplayPlugin"); +const QString NullDisplayPlugin::GROUPING("Developer"); const QString & NullDisplayPlugin::getName() const { return NAME; diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h index 23e23e2c4e..d574324472 100644 --- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h @@ -24,4 +24,5 @@ public: virtual QImage getScreenshot() const override; private: static const QString NAME; + static const QString GROUPING; }; diff --git a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp index ffaf005533..7aacebbcea 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp @@ -44,11 +44,8 @@ void main() { )FS"; -const QString InterleavedStereoDisplayPlugin::NAME("Interleaved Stereo Display"); - -const QString & InterleavedStereoDisplayPlugin::getName() const { - return NAME; -} +const QString InterleavedStereoDisplayPlugin::NAME("3D TV - Interleaved"); +const QString InterleavedStereoDisplayPlugin::GROUPING("Advanced"); InterleavedStereoDisplayPlugin::InterleavedStereoDisplayPlugin() { } diff --git a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h index 7116363e44..33b6397788 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h @@ -13,7 +13,9 @@ class InterleavedStereoDisplayPlugin : public StereoDisplayPlugin { Q_OBJECT public: InterleavedStereoDisplayPlugin(); - virtual const QString & getName() const override; + + virtual const QString& getName() const override { return NAME; } + virtual const QString& getGrouping() const override { return GROUPING; } // initialize OpenGL context settings needed by the plugin virtual void customizeContext() override; @@ -23,4 +25,5 @@ public: private: static const QString NAME; + static const QString GROUPING; }; diff --git a/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp index 12865cf4cd..d542838d2f 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp @@ -10,10 +10,7 @@ #include const QString SideBySideStereoDisplayPlugin::NAME("3D TV - Side by Side Stereo"); - -const QString & SideBySideStereoDisplayPlugin::getName() const { - return NAME; -} +const QString SideBySideStereoDisplayPlugin::GROUPING("Advanced"); SideBySideStereoDisplayPlugin::SideBySideStereoDisplayPlugin() { } diff --git a/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.h index 9f8440227f..daca9cd474 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.h @@ -15,8 +15,10 @@ class SideBySideStereoDisplayPlugin : public StereoDisplayPlugin { Q_OBJECT public: SideBySideStereoDisplayPlugin(); - virtual const QString& getName() const override; + virtual const QString& getName() const override { return NAME; } + virtual const QString& getGrouping() const override { return GROUPING; } virtual glm::uvec2 getRecommendedRenderSize() const override; private: static const QString NAME; + static const QString GROUPING; }; diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp index 1d7fbbec67..45a1adb386 100755 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp @@ -19,6 +19,7 @@ #include const QString KeyboardMouseDevice::NAME = "Keyboard/Mouse"; +const QString KeyboardMouseDevice::GROUPING = "Standard"; void KeyboardMouseDevice::pluginUpdate(float deltaTime, bool jointsCaptured) { _inputDevice->update(deltaTime, jointsCaptured); diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h index b31c59d11a..654041ac35 100644 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h @@ -67,7 +67,8 @@ public: // Plugin functions virtual bool isSupported() const override { return true; } virtual bool isJointController() const override { return false; } - const QString& getName() const override { return NAME; } + virtual const QString& getName() const override { return NAME; } + virtual const QString& getGrouping() const override { return GROUPING; } virtual void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override; @@ -87,6 +88,7 @@ public: void wheelEvent(QWheelEvent* event); static const QString NAME; + static const QString GROUPING; protected: diff --git a/libraries/plugins/src/plugins/Plugin.h b/libraries/plugins/src/plugins/Plugin.h index c030b1073f..6928416f88 100644 --- a/libraries/plugins/src/plugins/Plugin.h +++ b/libraries/plugins/src/plugins/Plugin.h @@ -19,6 +19,9 @@ public: /// \return human-readable name virtual const QString& getName() const = 0; + /// \return human-readable grouping for the plugin, Standard, Advanced, or Developer + virtual const QString& getGrouping() const = 0; + /// \return string ID (not necessarily human-readable) virtual const QString& getID() const { assert(false); return UNKNOWN_PLUGIN_ID; } diff --git a/plugins/hifiNeuron/src/NeuronPlugin.cpp b/plugins/hifiNeuron/src/NeuronPlugin.cpp index a175ce8e06..b9372967d1 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.cpp +++ b/plugins/hifiNeuron/src/NeuronPlugin.cpp @@ -30,6 +30,7 @@ Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins") #endif const QString NeuronPlugin::NAME = "Neuron"; +const QString NeuronPlugin::GROUPING = "Standard"; const QString NeuronPlugin::NEURON_ID_STRING = "Perception Neuron"; // indices of joints of the Neuron standard skeleton. diff --git a/plugins/hifiNeuron/src/NeuronPlugin.h b/plugins/hifiNeuron/src/NeuronPlugin.h index c85a5dd383..85ed3a3ecd 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.h +++ b/plugins/hifiNeuron/src/NeuronPlugin.h @@ -28,7 +28,8 @@ public: // Plugin functions virtual bool isSupported() const override; virtual bool isJointController() const override { return true; } - const QString& getName() const override { return NAME; } + virtual const QString& getName() const override { return NAME; } + virtual const QString& getGrouping() const override { return GROUPING; } const QString& getID() const override { return NEURON_ID_STRING; } virtual void activate() override; @@ -65,6 +66,7 @@ protected: std::shared_ptr _inputDevice { std::make_shared() }; static const QString NAME; + static const QString GROUPING; static const QString NEURON_ID_STRING; std::string _serverAddress; diff --git a/plugins/hifiSdl2/src/SDL2Manager.cpp b/plugins/hifiSdl2/src/SDL2Manager.cpp index 7ca49bbd75..554a8659c0 100644 --- a/plugins/hifiSdl2/src/SDL2Manager.cpp +++ b/plugins/hifiSdl2/src/SDL2Manager.cpp @@ -44,6 +44,7 @@ static_assert( const QString SDL2Manager::NAME = "SDL2"; +const QString SDL2Manager::GROUPING = "Standard"; #ifdef HAVE_SDL2 SDL_JoystickID SDL2Manager::getInstanceId(SDL_GameController* controller) { diff --git a/plugins/hifiSdl2/src/SDL2Manager.h b/plugins/hifiSdl2/src/SDL2Manager.h index 61e2d37fd5..cb4d5cb744 100644 --- a/plugins/hifiSdl2/src/SDL2Manager.h +++ b/plugins/hifiSdl2/src/SDL2Manager.h @@ -29,7 +29,8 @@ public: // Plugin functions virtual bool isSupported() const override; virtual bool isJointController() const override { return false; } - const QString& getName() const override { return NAME; } + virtual const QString& getName() const override { return NAME; } + virtual const QString& getGrouping() const override { return GROUPING; } virtual void init() override; virtual void deinit() override; @@ -84,6 +85,7 @@ private: #endif bool _isInitialized; static const QString NAME; + static const QString GROUPING; }; #endif // hifi__SDL2Manager_h diff --git a/plugins/hifiSixense/src/SixenseManager.cpp b/plugins/hifiSixense/src/SixenseManager.cpp index 3377aac14c..5ef73d3646 100644 --- a/plugins/hifiSixense/src/SixenseManager.cpp +++ b/plugins/hifiSixense/src/SixenseManager.cpp @@ -56,6 +56,7 @@ bool SixenseManager::_sixenseLoaded = false; const QString SixenseManager::NAME = "Sixense"; +const QString SixenseManager::GROUPING = "Standard"; const QString SixenseManager::HYDRA_ID_STRING = "Razer Hydra"; const QString MENU_PARENT = "Developer"; diff --git a/plugins/hifiSixense/src/SixenseManager.h b/plugins/hifiSixense/src/SixenseManager.h index 753974e996..4eb07c974f 100644 --- a/plugins/hifiSixense/src/SixenseManager.h +++ b/plugins/hifiSixense/src/SixenseManager.h @@ -29,8 +29,9 @@ public: // Plugin functions virtual bool isSupported() const override; virtual bool isJointController() const override { return true; } - const QString& getName() const override { return NAME; } - const QString& getID() const override { return HYDRA_ID_STRING; } + virtual const QString& getName() const override { return NAME; } + virtual const QString& getGrouping() const override { return GROUPING; } + virtual const QString& getID() const override { return HYDRA_ID_STRING; } virtual void activate() override; virtual void deactivate() override; @@ -97,6 +98,7 @@ private: std::shared_ptr _inputDevice { std::make_shared() }; static const QString NAME; + static const QString GROUPING; static const QString HYDRA_ID_STRING; static bool _sixenseLoaded; diff --git a/plugins/oculus/src/OculusDebugDisplayPlugin.cpp b/plugins/oculus/src/OculusDebugDisplayPlugin.cpp index 26bb3cf9b2..9ef2cda514 100644 --- a/plugins/oculus/src/OculusDebugDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDebugDisplayPlugin.cpp @@ -9,10 +9,8 @@ #include const QString OculusDebugDisplayPlugin::NAME("Oculus Rift (Simulator)"); +const QString OculusDebugDisplayPlugin::GROUPING("Developer"); -const QString & OculusDebugDisplayPlugin::getName() const { - return NAME; -} static const QString DEBUG_FLAG("HIFI_DEBUG_OCULUS"); static bool enableDebugOculus = QProcessEnvironment::systemEnvironment().contains("HIFI_DEBUG_OCULUS"); diff --git a/plugins/oculus/src/OculusDebugDisplayPlugin.h b/plugins/oculus/src/OculusDebugDisplayPlugin.h index 04b68704cc..cc0d5c2065 100644 --- a/plugins/oculus/src/OculusDebugDisplayPlugin.h +++ b/plugins/oculus/src/OculusDebugDisplayPlugin.h @@ -11,7 +11,8 @@ class OculusDebugDisplayPlugin : public OculusBaseDisplayPlugin { public: - virtual const QString & getName() const override; + virtual const QString& getName() const override { return NAME; } + virtual const QString& getGrouping() const override { return GROUPING; } virtual bool isSupported() const override; protected: @@ -19,5 +20,6 @@ protected: private: static const QString NAME; + static const QString GROUPING; }; diff --git a/plugins/oculus/src/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp index c8fb0ba080..0b81f661df 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDisplayPlugin.cpp @@ -137,10 +137,7 @@ private: #endif const QString OculusDisplayPlugin::NAME("Oculus Rift"); - -const QString & OculusDisplayPlugin::getName() const { - return NAME; -} +const QString OculusDisplayPlugin::GROUPING("Standard"); static const QString MONO_PREVIEW = "Mono Preview"; static const QString FRAMERATE = DisplayPlugin::MENU_PATH() + ">Framerate"; diff --git a/plugins/oculus/src/OculusDisplayPlugin.h b/plugins/oculus/src/OculusDisplayPlugin.h index 03c9ba7511..4633e434e1 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.h +++ b/plugins/oculus/src/OculusDisplayPlugin.h @@ -17,7 +17,8 @@ const float TARGET_RATE_Oculus = 75.0f; class OculusDisplayPlugin : public OculusBaseDisplayPlugin { public: virtual void activate() override; - virtual const QString & getName() const override; + virtual const QString& getName() const override { return NAME; } + virtual const QString& getGrouping() const override { return GROUPING; } virtual void setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) override final; virtual float getTargetFrameRate() override { return TARGET_RATE_Oculus; } @@ -30,7 +31,8 @@ protected: private: using EyePoses = std::pair; static const QString NAME; - bool _enablePreview { false }; + static const QString GROUPING; + bool _enablePreview{ false }; bool _monoPreview { true }; QMap _frameEyePoses; diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index 58f7536856..6860245fb0 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -28,12 +28,10 @@ Q_DECLARE_LOGGING_CATEGORY(displayplugins) Q_LOGGING_CATEGORY(displayplugins, "hifi.displayplugins") const QString OpenVrDisplayPlugin::NAME("OpenVR (Vive)"); +const QString OpenVrDisplayPlugin::GROUPING("Standard"); const QString StandingHMDSensorMode = "Standing HMD Sensor Mode"; // this probably shouldn't be hardcoded here -const QString & OpenVrDisplayPlugin::getName() const { - return NAME; -} static vr::IVRCompositor* _compositor{ nullptr }; vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount]; diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.h b/plugins/openvr/src/OpenVrDisplayPlugin.h index 8186e59936..5983129572 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.h +++ b/plugins/openvr/src/OpenVrDisplayPlugin.h @@ -18,7 +18,8 @@ const float TARGET_RATE_OpenVr = 90.0f; // FIXME: get from sdk tracked device p class OpenVrDisplayPlugin : public WindowOpenGLDisplayPlugin { public: virtual bool isSupported() const override; - virtual const QString & getName() const override; + virtual const QString& getName() const override { return NAME; } + virtual const QString& getGrouping() const override { return GROUPING; } virtual bool isHmd() const override { return true; } virtual float getTargetFrameRate() override { return TARGET_RATE_OpenVr; } @@ -45,5 +46,6 @@ protected: private: vr::IVRSystem* _hmd { nullptr }; static const QString NAME; + static const QString GROUPING; }; From 8e915733f0b71b1b82803569f2adc999a89321cf Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 8 Jan 2016 17:15:18 -0800 Subject: [PATCH 058/215] added place holder right hand open/searching animation --- .../meshes/defaultAvatar_full/avatar-animation.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index 3f9708cdb3..19066e0ee8 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -198,9 +198,9 @@ "id": "rightHandOpen", "type": "clip", "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/force_grab_right.fbx", - "startFrame": 0.0, - "endFrame": 0.0, + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/open_variations.fbx", + "startFrame": 95.0, + "endFrame": 95.0, "timeScale": 1.0, "loopFlag": true }, From bf68f2f2fa5d554f05d09211daf36c388c59c38e Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 8 Jan 2016 11:56:19 -0800 Subject: [PATCH 059/215] Templatize item culling --- .../render-utils/src/RenderDeferredTask.cpp | 4 +-- libraries/render/src/render/DrawTask.cpp | 31 ++----------------- libraries/render/src/render/DrawTask.h | 20 +++++------- 3 files changed, 11 insertions(+), 44 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index e3bf699fc8..b68108d6f1 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -56,7 +56,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() { context->getItemsConfig().opaque.numFeed = count; }) ))); - _jobs.push_back(Job(new CullItemsOpaque::JobModel("CullOpaque", _jobs.back().getOutput()))); + _jobs.push_back(Job(new CullItems::JobModel("CullOpaque", _jobs.back().getOutput()))); _jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortOpaque", _jobs.back().getOutput()))); auto& renderedOpaques = _jobs.back().getOutput(); @@ -67,7 +67,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() { context->getItemsConfig().transparent.numFeed = count; }) ))); - _jobs.push_back(Job(new CullItemsTransparent::JobModel("CullTransparent", _jobs.back().getOutput()))); + _jobs.push_back(Job(new CullItems::JobModel("CullTransparent", _jobs.back().getOutput()))); _jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false)))); auto& renderedTransparents = _jobs.back().getOutput(); diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 1b6bae54c8..ec82da3d09 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -111,34 +111,6 @@ void FetchItems::run(const SceneContextPointer& sceneContext, const RenderContex } } -void CullItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { - - outItems.clear(); - outItems.reserve(inItems.size()); - RenderArgs* args = renderContext->getArgs(); - args->_details.pointTo(RenderDetails::OTHER_ITEM); - cullItems(sceneContext, renderContext, inItems, outItems); -} - -void CullItemsOpaque::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { - - outItems.clear(); - outItems.reserve(inItems.size()); - RenderArgs* args = renderContext->getArgs(); - args->_details.pointTo(RenderDetails::OPAQUE_ITEM); - cullItems(sceneContext, renderContext, inItems, outItems); -} - -void CullItemsTransparent::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { - - outItems.clear(); - outItems.reserve(inItems.size()); - RenderArgs* args = renderContext->getArgs(); - args->_details.pointTo(RenderDetails::TRANSLUCENT_ITEM); - cullItems(sceneContext, renderContext, inItems, outItems); -} - - struct ItemBound { float _centerDepth = 0.0f; float _nearDepth = 0.0f; @@ -261,9 +233,10 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext inItems.emplace_back(ItemIDAndBounds(id, item.getBound())); } + RenderArgs* args = renderContext->getArgs(); + ItemIDsBounds culledItems; culledItems.reserve(inItems.size()); - RenderArgs* args = renderContext->getArgs(); args->_details.pointTo(RenderDetails::OTHER_ITEM); cullItems(sceneContext, renderContext, inItems, culledItems); diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 81dc7d358a..ef9508365c 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -239,24 +239,18 @@ public: typedef Job::ModelO JobModel; }; +template class CullItems { public: - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { + outItems.clear(); + outItems.reserve(inItems.size()); + renderContext->getArgs()->_details.pointTo(T); + render::cullItems(sceneContext, renderContext, inItems, outItems); + } typedef Job::ModelIO JobModel; }; -class CullItemsOpaque { -public: - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); - typedef Job::ModelIO JobModel; -}; - -class CullItemsTransparent { -public: - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); - typedef Job::ModelIO JobModel; -}; - class DepthSortItems { public: bool _frontToBack = true; From ea8bdd57280d5c4ebac760daaf796b72153c3d77 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 8 Jan 2016 14:58:29 -0800 Subject: [PATCH 060/215] Change pipeline initialization to depend on class, not global pipelineLib state --- .../render-utils/src/DeferredPipelineLib.cpp | 38 ++++++++++--------- .../render-utils/src/DeferredPipelineLib.h | 4 +- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/libraries/render-utils/src/DeferredPipelineLib.cpp b/libraries/render-utils/src/DeferredPipelineLib.cpp index 0526700633..70f8d13a07 100644 --- a/libraries/render-utils/src/DeferredPipelineLib.cpp +++ b/libraries/render-utils/src/DeferredPipelineLib.cpp @@ -38,13 +38,29 @@ #include "model_translucent_frag.h" DeferredPipelineLib::DeferredPipelineLib() { - // TODO: Move pipeline initialization to those Jobs using DeferredPipelineLib - // such that they own their own pipelines and it is done only once - if (_pipelineLib.empty()) { + if (!_isInitPipeline) { initPipeline(); } } +const DeferredPipelineLib::PipelinePointer DeferredPipelineLib::pickPipeline(RenderArgs* args, const Key& key) const { + PerformanceTimer perfTimer("DeferredPipelineLib::pickPipeline"); + + auto pipeline = _pickPipeline(args, key); + if (!pipeline) { + return pipeline; + } + + if ((pipeline->locations->normalFittingMapUnit > -1)) { + args->_batch->setResourceTexture(pipeline->locations->normalFittingMapUnit, + DependencyManager::get()->getNormalFittingTexture()); + } + + return pipeline; +} + +bool DeferredPipelineLib::_isInitPipeline { false }; + void DeferredPipelineLib::initPipeline() { assert(_pipelineLib.empty()); @@ -169,22 +185,8 @@ void DeferredPipelineLib::initPipeline() { _pipelineLib.addPipeline( Key::Builder().withSkinned().withDepthOnly().withShadow(), skinModelShadowVertex, modelShadowPixel); -} -const DeferredPipelineLib::PipelinePointer DeferredPipelineLib::pickPipeline(RenderArgs* args, const Key& key) const { - PerformanceTimer perfTimer("DeferredPipelineLib::pickPipeline"); - - auto pipeline = _pickPipeline(args, key); - if (!pipeline) { - return pipeline; - } - - if ((pipeline->locations->normalFittingMapUnit > -1)) { - args->_batch->setResourceTexture(pipeline->locations->normalFittingMapUnit, - DependencyManager::get()->getNormalFittingTexture()); - } - - return pipeline; + _isInitPipeline = true; } model::MaterialPointer DeferredPipelineLib::_collisionHullMaterial; diff --git a/libraries/render-utils/src/DeferredPipelineLib.h b/libraries/render-utils/src/DeferredPipelineLib.h index 98408d7754..4ea891c58c 100644 --- a/libraries/render-utils/src/DeferredPipelineLib.h +++ b/libraries/render-utils/src/DeferredPipelineLib.h @@ -18,12 +18,14 @@ class DeferredPipelineLib : public render::ShapePipelineLib { public: DeferredPipelineLib(); - static void initPipeline(); const PipelinePointer pickPipeline(RenderArgs* args, const Key& key) const override; static model::MaterialPointer getCollisionHullMaterial(); protected: + static bool _isInitPipeline; + static void initPipeline(); + static model::MaterialPointer _collisionHullMaterial; }; From c1e8fe88e4506dcddeb4a45c086fd4a4802a674f Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 8 Jan 2016 16:12:32 -0800 Subject: [PATCH 061/215] Fix shader typo (ambien->ambient) --- libraries/render-utils/src/DeferredGlobalLight.slh | 4 ++-- libraries/render-utils/src/directional_ambient_light.slf | 2 +- libraries/render-utils/src/directional_light.slf | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index 11e157a50c..ca46ad0ebf 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -70,7 +70,7 @@ uniform SphericalHarmonics ambientSphere; <@include model/Light.slh@> <@func declareEvalAmbientGlobalColor()@> -vec3 evalAmbienGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) { +vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) { // Need the light now Light light = getLight(); @@ -93,7 +93,7 @@ vec3 evalAmbienGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 positi <$declareSphericalHarmonics()$> -vec3 evalAmbienSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) { +vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) { // Need the light now Light light = getLight(); diff --git a/libraries/render-utils/src/directional_ambient_light.slf b/libraries/render-utils/src/directional_ambient_light.slf index ae3b05862e..a905dbdfd5 100755 --- a/libraries/render-utils/src/directional_ambient_light.slf +++ b/libraries/render-utils/src/directional_ambient_light.slf @@ -36,7 +36,7 @@ void main(void) { frag.specularVal.xyz); _fragColor = vec4(color, 1.0); } else { - vec3 color = evalAmbienSphereGlobalColor( + vec3 color = evalAmbientSphereGlobalColor( deferredTransform.viewInverse, 1.0, frag.position.xyz, diff --git a/libraries/render-utils/src/directional_light.slf b/libraries/render-utils/src/directional_light.slf index 22b0157762..eff40df255 100644 --- a/libraries/render-utils/src/directional_light.slf +++ b/libraries/render-utils/src/directional_light.slf @@ -37,7 +37,7 @@ void main(void) { frag.specularVal.xyz); _fragColor = vec4(color, 1.0); } else { - vec3 color = evalAmbienGlobalColor( + vec3 color = evalAmbientGlobalColor( deferredTransform.viewInverse, 1.0, frag.position.xyz, From 293e432fe9a031edb18b84abce256c0a7a031f3d Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 8 Jan 2016 18:05:09 -0800 Subject: [PATCH 062/215] Fix setter named getFocalLength --- libraries/octree/src/ViewFrustum.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index 596d042506..795a259a3c 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -48,7 +48,7 @@ public: // setters for lens attributes void setProjection(const glm::mat4 & projection); - void getFocalLength(float focalLength) { _focalLength = focalLength; } + void setFocalLength(float focalLength) { _focalLength = focalLength; } // getters for lens attributes const glm::mat4& getProjection() const { return _projection; } From 407c1bc62682cf331450b7531c7d1c9bccc3866d Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 8 Jan 2016 18:47:03 -0800 Subject: [PATCH 063/215] Handle out-of-range in render::FetchItems --- libraries/render/src/render/DrawTask.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index ec82da3d09..27cd2011d8 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -97,13 +97,17 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont void FetchItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems) { auto& scene = sceneContext->_scene; - auto& items = scene->getMasterBucket().at(_filter); outItems.clear(); - outItems.reserve(items.size()); - for (auto id : items) { - auto& item = scene->getItem(id); - outItems.emplace_back(ItemIDAndBounds(id, item.getBound())); + + const auto& bucket = scene->getMasterBucket(); + const auto& items = bucket.find(_filter); + if (items != bucket.end()) { + outItems.reserve(items->second.size()); + for (auto& id : items->second) { + auto& item = scene->getItem(id); + outItems.emplace_back(ItemIDAndBounds(id, item.getBound())); + } } if (_probeNumItems) { From d8ced32879101b636f2248ef9f2543ff8f9f02f7 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 8 Jan 2016 21:37:00 -0800 Subject: [PATCH 064/215] fix mac/unix build buster --- plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp | 4 +--- plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h | 4 +++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp index f0f200fe1a..f6e6055d84 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp @@ -27,10 +27,8 @@ using namespace oglplus; const QString OculusLegacyDisplayPlugin::NAME("Oculus Rift (0.5) (Simulated)"); +const QString OculusLegacyDisplayPlugin::GROUPING("Standard"); -const QString & OculusLegacyDisplayPlugin::getName() const { - return NAME; -} OculusLegacyDisplayPlugin::OculusLegacyDisplayPlugin() { } diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h index cd1177b581..603bdac507 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h @@ -19,7 +19,8 @@ class OculusLegacyDisplayPlugin : public WindowOpenGLDisplayPlugin { public: OculusLegacyDisplayPlugin(); virtual bool isSupported() const override; - virtual const QString & getName() const override; + virtual const QString& getName() const override { return NAME; } + virtual const QString& getGrouping() const override { return GROUPING; } virtual void activate() override; virtual void deactivate() override; @@ -46,6 +47,7 @@ protected: private: static const QString NAME; + static const QString GROUPING; ovrHmd _hmd; mutable ovrTrackingState _trackingState; From 46ed5f6479c31937d5f0a62ae763fe18b255aedd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Sat, 9 Jan 2016 14:27:57 -0800 Subject: [PATCH 065/215] Fix AssignmentParentFinder not handling null parentID --- assignment-client/src/entities/AssignmentParentFinder.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/assignment-client/src/entities/AssignmentParentFinder.cpp b/assignment-client/src/entities/AssignmentParentFinder.cpp index cc5c7557dc..294556383e 100644 --- a/assignment-client/src/entities/AssignmentParentFinder.cpp +++ b/assignment-client/src/entities/AssignmentParentFinder.cpp @@ -13,6 +13,12 @@ SpatiallyNestableWeakPointer AssignmentParentFinder::find(QUuid parentID, bool& success) const { SpatiallyNestableWeakPointer parent; + + if (parentID.isNull()) { + success = true; + return parent; + } + // search entities parent = _tree->findEntityByEntityItemID(parentID); if (parent.expired()) { From d74686474a08ddf980d8c9bab6bc6a200760a00b Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sun, 10 Jan 2016 11:39:47 -0800 Subject: [PATCH 066/215] Ensure VR menus never render off the overlay --- interface/resources/qml/VrMenu.qml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/interface/resources/qml/VrMenu.qml b/interface/resources/qml/VrMenu.qml index 738ec34a02..689171f9e9 100644 --- a/interface/resources/qml/VrMenu.qml +++ b/interface/resources/qml/VrMenu.qml @@ -51,6 +51,16 @@ Hifi.VrMenu { VrMenuView { property int menuDepth: root.models.length - 1 model: root.models[menuDepth] + + function fit(position, size, maxposition) { + var padding = 8; + if (position < padding) { + position = padding; + } else if (position + size + padding > maxposition) { + position = maxposition - (size + padding); + } + return position; + } Component.onCompleted: { if (menuDepth === 0) { @@ -61,6 +71,8 @@ Hifi.VrMenu { x = lastColumn.x + 64; y = lastMousePosition.y - height / 2; } + x = fit(x, width, parent.width); + y = fit(y, height, parent.height); } onSelected: { From e4855b7595e954793eba406ce0fb6621047456f0 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Sun, 10 Jan 2016 15:34:46 -0800 Subject: [PATCH 067/215] Script that drops different kinds of entities near you --- examples/dropStuffNearMe.js | 88 +++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 examples/dropStuffNearMe.js diff --git a/examples/dropStuffNearMe.js b/examples/dropStuffNearMe.js new file mode 100644 index 0000000000..0b84490b4c --- /dev/null +++ b/examples/dropStuffNearMe.js @@ -0,0 +1,88 @@ +// +// Created by Philip Rosedale on January 9, 2016 +// 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 +// +// Puts a bunch of entities in front of you, with various adjustable properties for testing. +// +// Note that when creating things quickly, the entity server will ignore data if we send updates too quickly. +// like Internet MTU, these rates are set by th domain operator, so in this script there is a RATE_PER_SECOND +// variable letting you set this speed. If entities are missing from the grid after a relog, this number +// being too high may be the reason. + +var SIZE = 0.5; +var TYPE = "Box"; // Right now this can be "Box" or "Model" or "Sphere" +var MODEL_URL = "http://s3.amazonaws.com/hifi-public/models/content/basketball2.fbx"; +var MODEL_DIMENSION = { x: 0.3, y: 0.3, z: 0.3 }; + +var RATE_PER_SECOND = 1000; // The entity server will drop data if we create things too fast. +var SCRIPT_INTERVAL = 100; +var LIFETIME = 90; + +var NUMBER_TO_CREATE = 300; + +var GRAVITY = { x: 0, y: -9.8, z: 0 }; +var VELOCITY = { x: 0.0, y: 0, z: 0 }; +var ANGULAR_VELOCITY = { x: 1, y: 1, z: 1 }; + +var DAMPING = 0.5; +var ANGULAR_DAMPING = 0.5; + +var collidable = true; +var gravity = true; + + +var x = 0; +var z = 0; +var totalCreated = 0; + +var RANGE = 10; +var HOW_FAR_IN_FRONT_OF_ME = 3 * RANGE; + + +var center = Vec3.sum(MyAvatar.position, Vec3.multiply(HOW_FAR_IN_FRONT_OF_ME, Quat.getFront(Camera.orientation))); + + +function randomVector(range) { + return { + x: (Math.random() - 0.5) * range.x, + y: (Math.random() - 0.5) * range.y, + z: (Math.random() - 0.5) * range.z + } +} + +Vec3.print("Center: ", center); + +Script.setInterval(function () { + if (!Entities.serversExist() || !Entities.canRez() || (totalCreated > NUMBER_TO_CREATE)) { + return; + } + + var numToCreate = RATE_PER_SECOND * (SCRIPT_INTERVAL / 1000.0); + for (var i = 0; i < numToCreate; i++) { + var position = Vec3.sum(center, randomVector({ x: RANGE, y: RANGE, z: RANGE })); + if (totalCreated < NUMBER_TO_CREATE) { + Vec3.print("Position: ", position); + Entities.addEntity({ + type: TYPE, + modelURL: MODEL_URL, + name: "gridTest", + position: position, + dimensions: (TYPE == "Model") ? MODEL_DIMENSION : { x: SIZE, y: SIZE, z: SIZE }, + color: { red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255 }, + velocity: VELOCITY, + angularVelocity: Vec3.multiply(Math.random(), ANGULAR_VELOCITY), + damping: DAMPING, + angularDamping: ANGULAR_DAMPING, + gravity: (gravity ? GRAVITY : { x: 0, y: 0, z: 0}), + collisionsWillMove: collidable, + lifetime: LIFETIME + }); + } + + totalCreated++; + } +}, SCRIPT_INTERVAL); + From 9068d559988af9e6c47a0cd2ef3441d21b208517 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 11 Jan 2016 15:58:00 +1300 Subject: [PATCH 068/215] Fix display of File > About Interface window --- interface/resources/html/interface-welcome.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/resources/html/interface-welcome.html b/interface/resources/html/interface-welcome.html index 1fc719ed72..113de7f2a0 100644 --- a/interface/resources/html/interface-welcome.html +++ b/interface/resources/html/interface-welcome.html @@ -1,4 +1,4 @@ - + @@ -14,7 +14,7 @@ body { background: white; - width: 839px; + width: 100%; overflow-x: hidden; } @@ -181,7 +181,7 @@ function overrideBodyWidth() { document.body.style.width = "100%"; - container.style.width = "0"; + } //]]> From 8182372e02ec9550ec81506278516c48e6e1400f Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 11 Jan 2016 08:39:34 -0800 Subject: [PATCH 069/215] Made drag selection area bigger for marketplace and directory icons. Added marketplace.js to default scripts --- examples/defaultScripts.js | 1 + examples/directory.js | 3 ++- examples/marketplace.js | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index f06af70fb3..443e4b3bf8 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -11,6 +11,7 @@ Script.load("away.js"); Script.load("progress.js"); Script.load("edit.js"); +Script.load("marketplace.js"); Script.load("selectAudioDevice.js"); Script.load("inspect.js"); Script.load("notifications.js"); diff --git a/examples/directory.js b/examples/directory.js index 69db3a4d89..a18442747f 100644 --- a/examples/directory.js +++ b/examples/directory.js @@ -53,10 +53,11 @@ var toolBar = (function() { browseDirectoryButton; function initialize() { + ToolBar.SPACING = 16; toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.directory.toolbar", function(windowDimensions, toolbar) { return { x: windowDimensions.x - 8 - toolbar.width, - y: 100 + y: 50 }; }); browseDirectoryButton = toolBar.addTool({ diff --git a/examples/marketplace.js b/examples/marketplace.js index 4583492c58..83f1287ed8 100644 --- a/examples/marketplace.js +++ b/examples/marketplace.js @@ -58,10 +58,11 @@ var toolBar = (function() { browseMarketplaceButton; function initialize() { + ToolBar.SPACING = 16; toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.marketplace.toolbar", function(windowDimensions, toolbar) { return { x: windowDimensions.x - 8 - toolbar.width, - y: 150 + y: 135 }; }); browseMarketplaceButton = toolBar.addTool({ From b8565358ffc30cdf2f9e9f8ace48ce965682d942 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 11 Jan 2016 09:16:33 -0800 Subject: [PATCH 070/215] Added basic energy bar example --- examples/example/ui/energyBar.js | 105 +++++++++++++++++++++++++++++++ examples/libraries/utils.js | 5 ++ 2 files changed, 110 insertions(+) create mode 100644 examples/example/ui/energyBar.js diff --git a/examples/example/ui/energyBar.js b/examples/example/ui/energyBar.js new file mode 100644 index 0000000000..b0abf6778b --- /dev/null +++ b/examples/example/ui/energyBar.js @@ -0,0 +1,105 @@ +// energyBar.js +// examples/ui +// +// Created by Eric Levin on 1/4/15 +// Copyright 2015 High Fidelity, Inc. +// +// This script adds an energy bar overlay which displays the amount of energy a user has left for grabbing and moving objects +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +Script.include("../../libraries/utils.js"); +var energyColor = {red: 0, green: 200, blue: 0}; +var lowEnergyColor = {red: 255, green: 0, blue: 0}; +var totalWidth = 200; +var paddingRight = 50; +var xPosition = Window.innerWidth - totalWidth - paddingRight; +var lowEnergyThreshold = 0.3; +var currentEnergy = 1.0; +var energyLossRate = 0.003; +var energyChargeRate = 0.003; +var isGrabbing = false; +var refractoryPeriod = 2000; + +var lastAvatarVelocity = MyAvatar.getVelocity(); +var lastAvatarPosition = MyAvatar.position; + +var background = Overlays.addOverlay("text", { + x: xPosition, + y: 20, + width: totalWidth, + height: 10, + backgroundColor: {red: 184, green: 181, blue: 178} +}) + +var bar = Overlays.addOverlay("text", { + x: xPosition, + y: 20, + width: totalWidth, + height: 10, + backgroundColor: energyColor +}); + + +// Takes an energy value between 0 and 1 and sets energy bar width appropriately +function setEnergy(energy) { + energy = clamp(energy, 0, 1); + var barWidth = totalWidth * energy; + var color = energy <= lowEnergyThreshold ? lowEnergyColor: energyColor; + Overlays.editOverlay(bar, { width: barWidth, backgroundColor: color}); +} + +function avatarAccelerationEnergy() { + var AVATAR_MOVEMENT_ENERGY_CONSTANT = 0.001; + var velocity = MyAvatar.getVelocity(); + var dV = Vec3.subtract(velocity, lastAvatarVelocity); + var dE = Vec3.length(lastAvatarVelocity) * Vec3.length(dV) * AVATAR_MOVEMENT_ENERGY_CONSTANT; + lastAvatarVelocity = velocity; + if (dE > 0.01) { + print("de " + dE); + } + return dE; +} + +function teleported() { + var MAX_AVATAR_MOVEMENT_PER_FRAME = 30.0; + var position = MyAvatar.position; + var dP = Vec3.length(Vec3.subtract(position, lastAvatarPosition)); + lastAvatarPosition = position; + return (dP > MAX_AVATAR_MOVEMENT_PER_FRAME); +} + +function audioEnergy() { + var AUDIO_ENERGY_CONSTANT = 0.000001; + return MyAvatar.audioLoudness * AUDIO_ENERGY_CONSTANT; +} + +function update() { + // refill energy + currentEnergy += energyChargeRate; + + // Avatar acceleration + currentEnergy -= avatarAccelerationEnergy(); + + // Teleport cost + if (teleported()) { + currentEnergy = 0; + } + + // Making sounds + currentEnergy -= audioEnergy(); + + + currentEnergy = clamp(currentEnergy, 0, 1); + setEnergy(currentEnergy); +} + +function cleanup() { + Overlays.deleteOverlay(background); + Overlays.deleteOverlay(bar); +} + +Script.update.connect(update); +Script.scriptEnding.connect(cleanup); diff --git a/examples/libraries/utils.js b/examples/libraries/utils.js index 115c1bcb65..b2b2902cb0 100644 --- a/examples/libraries/utils.js +++ b/examples/libraries/utils.js @@ -297,3 +297,8 @@ calculateHandSizeRatio = function() { var handSizeRatio = centerHandPoint/standardCenterHandPoint; return handSizeRatio; } + +clamp = function(val, min, max){ + return Math.max(min, Math.min(max, val)) + } + From 3d8f8e56182bfe42c9875c0cf0c536e09a2d4b70 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 11 Jan 2016 10:39:27 -0800 Subject: [PATCH 071/215] Set WANT_DEBUG_STATE to false --- examples/controllers/handControllerGrab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 8c2b6e76dd..0e1a42863e 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -18,7 +18,7 @@ Script.include("../libraries/utils.js"); // add lines where the hand ray picking is happening // var WANT_DEBUG = false; -var WANT_DEBUG_STATE = true; +var WANT_DEBUG_STATE = false; // // these tune time-averaging and "on" value for analog trigger From dfba05ae5f825b2281a4a11a6108d5907149f05c Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 11 Jan 2016 11:07:07 -0800 Subject: [PATCH 072/215] CR feedback --- interface/src/Application.cpp | 37 ++++++++++++++----- .../Basic2DWindowOpenGLDisplayPlugin.cpp | 1 - .../Basic2DWindowOpenGLDisplayPlugin.h | 2 - .../src/display-plugins/NullDisplayPlugin.cpp | 1 - .../src/display-plugins/NullDisplayPlugin.h | 1 + .../stereo/InterleavedStereoDisplayPlugin.cpp | 1 - .../stereo/InterleavedStereoDisplayPlugin.h | 3 +- .../stereo/SideBySideStereoDisplayPlugin.cpp | 1 - .../stereo/SideBySideStereoDisplayPlugin.h | 3 +- .../src/input-plugins/KeyboardMouseDevice.cpp | 1 - .../src/input-plugins/KeyboardMouseDevice.h | 2 - libraries/plugins/src/plugins/Plugin.h | 6 ++- plugins/hifiNeuron/src/NeuronPlugin.cpp | 1 - plugins/hifiNeuron/src/NeuronPlugin.h | 2 - plugins/hifiSdl2/src/SDL2Manager.cpp | 1 - plugins/hifiSdl2/src/SDL2Manager.h | 2 - plugins/hifiSixense/src/SixenseManager.cpp | 1 - plugins/hifiSixense/src/SixenseManager.h | 2 - .../oculus/src/OculusDebugDisplayPlugin.cpp | 2 - plugins/oculus/src/OculusDebugDisplayPlugin.h | 3 +- plugins/oculus/src/OculusDisplayPlugin.cpp | 1 - plugins/oculus/src/OculusDisplayPlugin.h | 2 - .../src/OculusLegacyDisplayPlugin.cpp | 4 +- .../src/OculusLegacyDisplayPlugin.h | 2 - plugins/openvr/src/OpenVrDisplayPlugin.cpp | 2 - plugins/openvr/src/OpenVrDisplayPlugin.h | 2 - 26 files changed, 37 insertions(+), 49 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7be74e717e..2fdd778339 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5062,9 +5062,23 @@ const DisplayPlugin* Application::getActiveDisplayPlugin() const { static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool active = false) { auto menu = Menu::getInstance(); QString name = displayPlugin->getName(); - QString grouping = displayPlugin->getGrouping(); + auto grouping = displayPlugin->getGrouping(); + QString groupingMenu { "" }; Q_ASSERT(!menu->menuItemExists(MenuOption::OutputMenu, name)); + // assign the meny grouping based on plugin grouping + switch (grouping) { + case Plugin::ADVANCED: + groupingMenu = "Advanced"; + break; + case Plugin::DEVELOPER: + groupingMenu = "Developer"; + break; + default: + groupingMenu = "Standard"; + break; + } + static QActionGroup* displayPluginGroup = nullptr; if (!displayPluginGroup) { displayPluginGroup = new QActionGroup(menu); @@ -5074,7 +5088,8 @@ static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool acti auto action = menu->addActionToQMenuAndActionHash(parent, name, 0, qApp, SLOT(updateDisplayMode()), - QAction::NoRole, UNSPECIFIED_POSITION, grouping); + QAction::NoRole, UNSPECIFIED_POSITION, groupingMenu); + action->setCheckable(true); action->setChecked(active); displayPluginGroup->addAction(action); @@ -5094,13 +5109,17 @@ void Application::updateDisplayMode() { DisplayPluginList advanced; DisplayPluginList developer; foreach(auto displayPlugin, displayPlugins) { - QString grouping = displayPlugin->getGrouping(); - if (grouping == "Advanced") { - advanced.push_back(displayPlugin); - } else if (grouping == "Developer") { - developer.push_back(displayPlugin); - } else { - standard.push_back(displayPlugin); + auto grouping = displayPlugin->getGrouping(); + switch (grouping) { + case Plugin::ADVANCED: + advanced.push_back(displayPlugin); + break; + case Plugin::DEVELOPER: + developer.push_back(displayPlugin); + break; + default: + standard.push_back(displayPlugin); + break; } } diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp index 11bed0e0af..fb6e9c3b65 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp @@ -16,7 +16,6 @@ #include const QString Basic2DWindowOpenGLDisplayPlugin::NAME("Desktop"); -const QString Basic2DWindowOpenGLDisplayPlugin::GROUPING("Standard"); static const QString FULLSCREEN = "Fullscreen"; diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h index 29e26c1f28..6523b58914 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h @@ -19,7 +19,6 @@ class Basic2DWindowOpenGLDisplayPlugin : public WindowOpenGLDisplayPlugin { public: virtual const QString& getName() const override { return NAME; } - virtual const QString& getGrouping() const override { return GROUPING; } virtual float getTargetFrameRate() override { return _framerateTarget ? (float) _framerateTarget : TARGET_FRAMERATE_Basic2DWindowOpenGL; } @@ -38,7 +37,6 @@ protected: private: void updateFramerate(); static const QString NAME; - static const QString GROUPING; QScreen* getFullscreenTarget(); std::vector _framerateActions; QAction* _vsyncAction { nullptr }; diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp index 54cf13fccd..f780534bc9 100644 --- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp @@ -13,7 +13,6 @@ #include const QString NullDisplayPlugin::NAME("NullDisplayPlugin"); -const QString NullDisplayPlugin::GROUPING("Developer"); const QString & NullDisplayPlugin::getName() const { return NAME; diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h index d574324472..d576dbad51 100644 --- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h @@ -14,6 +14,7 @@ public: virtual ~NullDisplayPlugin() final {} virtual const QString & getName() const override; + virtual grouping getGrouping() const override { return DEVELOPER; } void stop() override; diff --git a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp index 7aacebbcea..40c6e6306b 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp @@ -45,7 +45,6 @@ void main() { )FS"; const QString InterleavedStereoDisplayPlugin::NAME("3D TV - Interleaved"); -const QString InterleavedStereoDisplayPlugin::GROUPING("Advanced"); InterleavedStereoDisplayPlugin::InterleavedStereoDisplayPlugin() { } diff --git a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h index 33b6397788..df2a9f4800 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h @@ -15,7 +15,7 @@ public: InterleavedStereoDisplayPlugin(); virtual const QString& getName() const override { return NAME; } - virtual const QString& getGrouping() const override { return GROUPING; } + virtual grouping getGrouping() const override { return ADVANCED; } // initialize OpenGL context settings needed by the plugin virtual void customizeContext() override; @@ -25,5 +25,4 @@ public: private: static const QString NAME; - static const QString GROUPING; }; diff --git a/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp index d542838d2f..e8a83d2b08 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp @@ -10,7 +10,6 @@ #include const QString SideBySideStereoDisplayPlugin::NAME("3D TV - Side by Side Stereo"); -const QString SideBySideStereoDisplayPlugin::GROUPING("Advanced"); SideBySideStereoDisplayPlugin::SideBySideStereoDisplayPlugin() { } diff --git a/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.h index daca9cd474..70f69ba4cb 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.h @@ -16,9 +16,8 @@ class SideBySideStereoDisplayPlugin : public StereoDisplayPlugin { public: SideBySideStereoDisplayPlugin(); virtual const QString& getName() const override { return NAME; } - virtual const QString& getGrouping() const override { return GROUPING; } + virtual grouping getGrouping() const override { return ADVANCED; } virtual glm::uvec2 getRecommendedRenderSize() const override; private: static const QString NAME; - static const QString GROUPING; }; diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp index 45a1adb386..1d7fbbec67 100755 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp @@ -19,7 +19,6 @@ #include const QString KeyboardMouseDevice::NAME = "Keyboard/Mouse"; -const QString KeyboardMouseDevice::GROUPING = "Standard"; void KeyboardMouseDevice::pluginUpdate(float deltaTime, bool jointsCaptured) { _inputDevice->update(deltaTime, jointsCaptured); diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h index 654041ac35..6acb2bf041 100644 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h @@ -68,7 +68,6 @@ public: virtual bool isSupported() const override { return true; } virtual bool isJointController() const override { return false; } virtual const QString& getName() const override { return NAME; } - virtual const QString& getGrouping() const override { return GROUPING; } virtual void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override; @@ -88,7 +87,6 @@ public: void wheelEvent(QWheelEvent* event); static const QString NAME; - static const QString GROUPING; protected: diff --git a/libraries/plugins/src/plugins/Plugin.h b/libraries/plugins/src/plugins/Plugin.h index 6928416f88..ee10ce331c 100644 --- a/libraries/plugins/src/plugins/Plugin.h +++ b/libraries/plugins/src/plugins/Plugin.h @@ -19,8 +19,10 @@ public: /// \return human-readable name virtual const QString& getName() const = 0; - /// \return human-readable grouping for the plugin, Standard, Advanced, or Developer - virtual const QString& getGrouping() const = 0; + typedef enum { STANDARD, ADVANCED, DEVELOPER } grouping; + + /// \return human-readable grouping for the plugin, STANDARD, ADVANCED, or DEVELOPER + virtual grouping getGrouping() const { return STANDARD; } /// \return string ID (not necessarily human-readable) virtual const QString& getID() const { assert(false); return UNKNOWN_PLUGIN_ID; } diff --git a/plugins/hifiNeuron/src/NeuronPlugin.cpp b/plugins/hifiNeuron/src/NeuronPlugin.cpp index b9372967d1..a175ce8e06 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.cpp +++ b/plugins/hifiNeuron/src/NeuronPlugin.cpp @@ -30,7 +30,6 @@ Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins") #endif const QString NeuronPlugin::NAME = "Neuron"; -const QString NeuronPlugin::GROUPING = "Standard"; const QString NeuronPlugin::NEURON_ID_STRING = "Perception Neuron"; // indices of joints of the Neuron standard skeleton. diff --git a/plugins/hifiNeuron/src/NeuronPlugin.h b/plugins/hifiNeuron/src/NeuronPlugin.h index 85ed3a3ecd..33c6879f5b 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.h +++ b/plugins/hifiNeuron/src/NeuronPlugin.h @@ -29,7 +29,6 @@ public: virtual bool isSupported() const override; virtual bool isJointController() const override { return true; } virtual const QString& getName() const override { return NAME; } - virtual const QString& getGrouping() const override { return GROUPING; } const QString& getID() const override { return NEURON_ID_STRING; } virtual void activate() override; @@ -66,7 +65,6 @@ protected: std::shared_ptr _inputDevice { std::make_shared() }; static const QString NAME; - static const QString GROUPING; static const QString NEURON_ID_STRING; std::string _serverAddress; diff --git a/plugins/hifiSdl2/src/SDL2Manager.cpp b/plugins/hifiSdl2/src/SDL2Manager.cpp index 554a8659c0..7ca49bbd75 100644 --- a/plugins/hifiSdl2/src/SDL2Manager.cpp +++ b/plugins/hifiSdl2/src/SDL2Manager.cpp @@ -44,7 +44,6 @@ static_assert( const QString SDL2Manager::NAME = "SDL2"; -const QString SDL2Manager::GROUPING = "Standard"; #ifdef HAVE_SDL2 SDL_JoystickID SDL2Manager::getInstanceId(SDL_GameController* controller) { diff --git a/plugins/hifiSdl2/src/SDL2Manager.h b/plugins/hifiSdl2/src/SDL2Manager.h index cb4d5cb744..6506cdccb6 100644 --- a/plugins/hifiSdl2/src/SDL2Manager.h +++ b/plugins/hifiSdl2/src/SDL2Manager.h @@ -30,7 +30,6 @@ public: virtual bool isSupported() const override; virtual bool isJointController() const override { return false; } virtual const QString& getName() const override { return NAME; } - virtual const QString& getGrouping() const override { return GROUPING; } virtual void init() override; virtual void deinit() override; @@ -85,7 +84,6 @@ private: #endif bool _isInitialized; static const QString NAME; - static const QString GROUPING; }; #endif // hifi__SDL2Manager_h diff --git a/plugins/hifiSixense/src/SixenseManager.cpp b/plugins/hifiSixense/src/SixenseManager.cpp index 5ef73d3646..3377aac14c 100644 --- a/plugins/hifiSixense/src/SixenseManager.cpp +++ b/plugins/hifiSixense/src/SixenseManager.cpp @@ -56,7 +56,6 @@ bool SixenseManager::_sixenseLoaded = false; const QString SixenseManager::NAME = "Sixense"; -const QString SixenseManager::GROUPING = "Standard"; const QString SixenseManager::HYDRA_ID_STRING = "Razer Hydra"; const QString MENU_PARENT = "Developer"; diff --git a/plugins/hifiSixense/src/SixenseManager.h b/plugins/hifiSixense/src/SixenseManager.h index 4eb07c974f..bbb9774368 100644 --- a/plugins/hifiSixense/src/SixenseManager.h +++ b/plugins/hifiSixense/src/SixenseManager.h @@ -30,7 +30,6 @@ public: virtual bool isSupported() const override; virtual bool isJointController() const override { return true; } virtual const QString& getName() const override { return NAME; } - virtual const QString& getGrouping() const override { return GROUPING; } virtual const QString& getID() const override { return HYDRA_ID_STRING; } virtual void activate() override; @@ -98,7 +97,6 @@ private: std::shared_ptr _inputDevice { std::make_shared() }; static const QString NAME; - static const QString GROUPING; static const QString HYDRA_ID_STRING; static bool _sixenseLoaded; diff --git a/plugins/oculus/src/OculusDebugDisplayPlugin.cpp b/plugins/oculus/src/OculusDebugDisplayPlugin.cpp index 9ef2cda514..94a3670e4b 100644 --- a/plugins/oculus/src/OculusDebugDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDebugDisplayPlugin.cpp @@ -9,8 +9,6 @@ #include const QString OculusDebugDisplayPlugin::NAME("Oculus Rift (Simulator)"); -const QString OculusDebugDisplayPlugin::GROUPING("Developer"); - static const QString DEBUG_FLAG("HIFI_DEBUG_OCULUS"); static bool enableDebugOculus = QProcessEnvironment::systemEnvironment().contains("HIFI_DEBUG_OCULUS"); diff --git a/plugins/oculus/src/OculusDebugDisplayPlugin.h b/plugins/oculus/src/OculusDebugDisplayPlugin.h index cc0d5c2065..c62fe12c73 100644 --- a/plugins/oculus/src/OculusDebugDisplayPlugin.h +++ b/plugins/oculus/src/OculusDebugDisplayPlugin.h @@ -12,7 +12,7 @@ class OculusDebugDisplayPlugin : public OculusBaseDisplayPlugin { public: virtual const QString& getName() const override { return NAME; } - virtual const QString& getGrouping() const override { return GROUPING; } + virtual grouping getGrouping() const override { return DEVELOPER; } virtual bool isSupported() const override; protected: @@ -20,6 +20,5 @@ protected: private: static const QString NAME; - static const QString GROUPING; }; diff --git a/plugins/oculus/src/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp index 0b81f661df..3002c746a2 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDisplayPlugin.cpp @@ -137,7 +137,6 @@ private: #endif const QString OculusDisplayPlugin::NAME("Oculus Rift"); -const QString OculusDisplayPlugin::GROUPING("Standard"); static const QString MONO_PREVIEW = "Mono Preview"; static const QString FRAMERATE = DisplayPlugin::MENU_PATH() + ">Framerate"; diff --git a/plugins/oculus/src/OculusDisplayPlugin.h b/plugins/oculus/src/OculusDisplayPlugin.h index 4633e434e1..d6ae4e6436 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.h +++ b/plugins/oculus/src/OculusDisplayPlugin.h @@ -18,7 +18,6 @@ class OculusDisplayPlugin : public OculusBaseDisplayPlugin { public: virtual void activate() override; virtual const QString& getName() const override { return NAME; } - virtual const QString& getGrouping() const override { return GROUPING; } virtual void setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) override final; virtual float getTargetFrameRate() override { return TARGET_RATE_Oculus; } @@ -31,7 +30,6 @@ protected: private: using EyePoses = std::pair; static const QString NAME; - static const QString GROUPING; bool _enablePreview{ false }; bool _monoPreview { true }; QMap _frameEyePoses; diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp index f6e6055d84..4bded4e58f 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp @@ -26,9 +26,7 @@ using namespace oglplus; -const QString OculusLegacyDisplayPlugin::NAME("Oculus Rift (0.5) (Simulated)"); -const QString OculusLegacyDisplayPlugin::GROUPING("Standard"); - +const QString OculusLegacyDisplayPlugin::NAME("Oculus Rift (0.5) (Legacy)"); OculusLegacyDisplayPlugin::OculusLegacyDisplayPlugin() { } diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h index 603bdac507..1ba288cc65 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h @@ -20,7 +20,6 @@ public: OculusLegacyDisplayPlugin(); virtual bool isSupported() const override; virtual const QString& getName() const override { return NAME; } - virtual const QString& getGrouping() const override { return GROUPING; } virtual void activate() override; virtual void deactivate() override; @@ -47,7 +46,6 @@ protected: private: static const QString NAME; - static const QString GROUPING; ovrHmd _hmd; mutable ovrTrackingState _trackingState; diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index 6860245fb0..7fb70180c4 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -28,11 +28,9 @@ Q_DECLARE_LOGGING_CATEGORY(displayplugins) Q_LOGGING_CATEGORY(displayplugins, "hifi.displayplugins") const QString OpenVrDisplayPlugin::NAME("OpenVR (Vive)"); -const QString OpenVrDisplayPlugin::GROUPING("Standard"); const QString StandingHMDSensorMode = "Standing HMD Sensor Mode"; // this probably shouldn't be hardcoded here - static vr::IVRCompositor* _compositor{ nullptr }; vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount]; mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount]; diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.h b/plugins/openvr/src/OpenVrDisplayPlugin.h index 5983129572..e290368de0 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.h +++ b/plugins/openvr/src/OpenVrDisplayPlugin.h @@ -19,7 +19,6 @@ class OpenVrDisplayPlugin : public WindowOpenGLDisplayPlugin { public: virtual bool isSupported() const override; virtual const QString& getName() const override { return NAME; } - virtual const QString& getGrouping() const override { return GROUPING; } virtual bool isHmd() const override { return true; } virtual float getTargetFrameRate() override { return TARGET_RATE_OpenVr; } @@ -46,6 +45,5 @@ protected: private: vr::IVRSystem* _hmd { nullptr }; static const QString NAME; - static const QString GROUPING; }; From c0cf717a04094c64a564c72b83223e3758629e3a Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 11 Jan 2016 11:13:33 -0800 Subject: [PATCH 073/215] CR feedback --- .../display-plugins/src/display-plugins/NullDisplayPlugin.cpp | 4 ---- .../display-plugins/src/display-plugins/NullDisplayPlugin.h | 3 +-- plugins/oculus/src/OculusDisplayPlugin.h | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp index f780534bc9..e8145db900 100644 --- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp @@ -14,10 +14,6 @@ const QString NullDisplayPlugin::NAME("NullDisplayPlugin"); -const QString & NullDisplayPlugin::getName() const { - return NAME; -} - glm::uvec2 NullDisplayPlugin::getRecommendedRenderSize() const { return glm::uvec2(100, 100); } diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h index d576dbad51..14b5529a29 100644 --- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h @@ -13,7 +13,7 @@ class NullDisplayPlugin : public DisplayPlugin { public: virtual ~NullDisplayPlugin() final {} - virtual const QString & getName() const override; + virtual const QString& getName() const override { return NAME; } virtual grouping getGrouping() const override { return DEVELOPER; } void stop() override; @@ -25,5 +25,4 @@ public: virtual QImage getScreenshot() const override; private: static const QString NAME; - static const QString GROUPING; }; diff --git a/plugins/oculus/src/OculusDisplayPlugin.h b/plugins/oculus/src/OculusDisplayPlugin.h index d6ae4e6436..98535a1790 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.h +++ b/plugins/oculus/src/OculusDisplayPlugin.h @@ -30,7 +30,7 @@ protected: private: using EyePoses = std::pair; static const QString NAME; - bool _enablePreview{ false }; + bool _enablePreview { false }; bool _monoPreview { true }; QMap _frameEyePoses; From e4e4cb01103d5fe89852fd4fa75791e412d76681 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 11 Jan 2016 12:03:44 -0800 Subject: [PATCH 074/215] Bug fix for Transform.postMult() with non-uniform scale. Previously it would not flag the matrix as non-uniform, this would cause some operations (such as inverse) to be incorrect. --- libraries/shared/src/Transform.h | 13 +++--------- tests/shared/src/TransformTests.cpp | 31 +++++++++++++++++++---------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index ec81513f3e..310e2d0409 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -104,8 +104,6 @@ public: const Vec3& getScale() const; Transform& setScale(float scale); Transform& setScale(const Vec3& scale); // [new this] = [this.translation] * [this.rotation] * [scale] - Transform& preScale(float scale); - Transform& preScale(const Vec3& scale); Transform& postScale(float scale); // [new this] = [this] * [scale] equivalent to:glScale Transform& postScale(const Vec3& scale); // [new this] = [this] * [scale] equivalent to:glScale @@ -350,14 +348,6 @@ inline Transform& Transform::setScale(const Vec3& scale) { return *this; } -inline Transform& Transform::preScale(float scale) { - return setScale(getScale() * scale); -} - -inline Transform& Transform::preScale(const Vec3& scale) { - return setScale(getScale() * scale); -} - inline Transform& Transform::postScale(float scale) { if (!isValidScale(scale) || scale == 1.0f) { return *this; @@ -376,6 +366,9 @@ inline Transform& Transform::postScale(const Vec3& scale) { return *this; } invalidCache(); + if ((scale.x != scale.y) || (scale.x != scale.z)) { + flagNonUniform(); + } if (isScaling()) { _scale *= scale; } else { diff --git a/tests/shared/src/TransformTests.cpp b/tests/shared/src/TransformTests.cpp index b936d45555..ca55bbf873 100644 --- a/tests/shared/src/TransformTests.cpp +++ b/tests/shared/src/TransformTests.cpp @@ -11,19 +11,21 @@ #include "TransformTests.h" #include -#include #include -#include #include "../QTestExtensions.h" +#include +#include +#include +#include -using namespace glm; +//using namespace glm; const vec3 xAxis(1.0f, 0.0f, 0.0f); const vec3 yAxis(0.0f, 1.0f, 0.0f); const vec3 zAxis(0.0f, 0.0f, 1.0f); -const quat rot90 = angleAxis((float)M_PI / 2.0f, yAxis); +const quat rot90 = glm::angleAxis((float)M_PI / 2.0f, yAxis); QTEST_MAIN(TransformTests) @@ -71,19 +73,26 @@ void TransformTests::getInverseMatrix() { vec4( 0.0f, 1.0f, 0.0f, 0.0f), vec4( 0.0f, 0.0f, 1.0f, 0.0f), vec4( 0.0f, 0.0f, 0.0f, 1.0f)); - const mat4 result_a = inverse(m * mirrorX); + const mat4 result_a = glm::inverse(m * mirrorX); Transform xform; xform.setTranslation(t); xform.setRotation(rot90); - - // - // change postScale to preScale and the test will pass... - // - xform.postScale(vec3(-1.0f, 1.0f, 1.0f)); + mat4 result_b; xform.getInverseMatrix(result_b); - QCOMPARE_WITH_ABS_ERROR(result_a, result_b, EPSILON); + // don't check elements directly, instead compare each axis transformed by the matrix. + auto xa = transformPoint(result_a, xAxis); + auto ya = transformPoint(result_a, yAxis); + auto za = transformPoint(result_a, zAxis); + + auto xb = transformPoint(result_b, xAxis); + auto yb = transformPoint(result_b, yAxis); + auto zb = transformPoint(result_b, zAxis); + + QCOMPARE_WITH_ABS_ERROR(xa, xb, EPSILON); + QCOMPARE_WITH_ABS_ERROR(ya, yb, EPSILON); + QCOMPARE_WITH_ABS_ERROR(za, zb, EPSILON); } From d28f80aa07df9593371006a95cb17e377da2f580 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 8 Jan 2016 16:48:58 -0800 Subject: [PATCH 075/215] Moving running scripts functionality to scripting library --- assignment-client/src/AssignmentClient.cpp | 4 + interface/resources/qml/AddressBarDialog.qml | 11 +- interface/src/Application.cpp | 345 ++------------ interface/src/Application.h | 40 +- interface/src/Menu.cpp | 7 +- interface/src/ui/HMDToolsDialog.cpp | 3 - interface/src/ui/JSConsole.cpp | 3 +- interface/src/ui/PreferencesDialog.cpp | 9 +- interface/src/ui/RunningScriptsWidget.cpp | 130 +----- interface/src/ui/RunningScriptsWidget.h | 15 - interface/src/ui/ScriptEditorWidget.cpp | 13 +- interface/src/ui/ScriptEditorWindow.cpp | 9 +- libraries/script-engine/src/ScriptEngine.cpp | 78 +--- libraries/script-engine/src/ScriptEngine.h | 4 +- libraries/script-engine/src/ScriptEngines.cpp | 434 ++++++++++++++++++ libraries/script-engine/src/ScriptEngines.h | 103 +++++ .../script-engine}/src/ScriptsModel.cpp | 24 +- .../script-engine}/src/ScriptsModel.h | 1 + .../script-engine}/src/ScriptsModelFilter.cpp | 0 .../script-engine}/src/ScriptsModelFilter.h | 0 20 files changed, 664 insertions(+), 569 deletions(-) create mode 100644 libraries/script-engine/src/ScriptEngines.cpp create mode 100644 libraries/script-engine/src/ScriptEngines.h rename {interface => libraries/script-engine}/src/ScriptsModel.cpp (96%) rename {interface => libraries/script-engine}/src/ScriptsModel.h (98%) rename {interface => libraries/script-engine}/src/ScriptsModelFilter.cpp (100%) rename {interface => libraries/script-engine}/src/ScriptsModelFilter.h (100%) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 0d62b8dcc7..3bd38c4ae7 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "AssignmentFactory.h" #include "AssignmentActionFactory.h" @@ -53,6 +54,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri auto scriptableAvatar = DependencyManager::set(); auto addressManager = DependencyManager::set(); + auto scriptEngines = DependencyManager::set(); // create a NodeList as an unassigned client, must be after addressManager auto nodeList = DependencyManager::set(NodeType::Unassigned, listenPort); @@ -174,6 +176,8 @@ AssignmentClient::~AssignmentClient() { void AssignmentClient::aboutToQuit() { stopAssignmentClient(); + DependencyManager::destroy(); + // clear the log handler so that Qt doesn't call the destructor on LogHandler qInstallMessageHandler(0); } diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index 6c94f9d254..e8ebb5d5fb 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -32,9 +32,14 @@ DialogContainer { property int maximumY: parent ? parent.height - height : 0 + Rectangle { + id: dragRegion + visible: dragMouseArea.containsMouse + } + AddressBarDialog { id: addressBarDialog - + z: dragRegion.z + 1 implicitWidth: backgroundImage.width implicitHeight: backgroundImage.height @@ -48,11 +53,13 @@ DialogContainer { property int inputAreaStep: (height - inputAreaHeight) / 2 MouseArea { + id: dragMouseArea // Drag the icon width: parent.height height: parent.height x: 0 y: 0 + hoverEnabled: true drag { target: root minimumX: -parent.inputAreaStep @@ -61,6 +68,8 @@ DialogContainer { maximumY: root.parent ? root.maximumY + parent.inputAreaStep : 0 } } + + MouseArea { // Drag the input rectangle diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2fdd778339..4f0b514827 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -103,6 +103,7 @@ #include #include #include +#include #include #include #include @@ -319,6 +320,7 @@ bool setupEssentials(int& argc, char** argv) { Setting::init(); // Set dependencies + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -402,16 +404,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _entityClipboard(new EntityTree()), _lastQueriedTime(usecTimestampNow()), _mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)), - _firstRun("firstRun", true), - _previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION), - _scriptsLocationHandle("scriptsLocation", DESKTOP_LOCATION), _fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES), _scaleMirror(1.0f), _rotateMirror(0.0f), _raiseMirror(0.0f), _enableProcessOctreeThread(true), - _runningScriptsWidget(NULL), - _runningScriptsWidgetWasVisible(false), _lastNackTime(usecTimestampNow()), _lastSendDownstreamAudioStats(usecTimestampNow()), _aboutToQuit(false), @@ -451,7 +448,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _bookmarks = new Bookmarks(); // Before setting up the menu - _runningScriptsWidget = new RunningScriptsWidget(_window); _renderEngine->addTask(make_shared()); _renderEngine->registerScene(_main3DScene); @@ -598,6 +594,30 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : connect(addressManager.data(), &AddressManager::hostChanged, this, &Application::updateWindowTitle); connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress); + auto scriptEngines = DependencyManager::get().data(); + scriptEngines->registerScriptInitializer([this](ScriptEngine* engine){ + registerScriptEngineWithApplicationServices(engine); + }); + + connect(scriptEngines, &ScriptEngines::scriptCountChanged, scriptEngines, [this] { + auto scriptEngines = DependencyManager::get(); + if (scriptEngines->getRunningScripts().isEmpty()) { + getMyAvatar()->clearScriptableSettings(); + } + }, Qt::QueuedConnection); + + connect(scriptEngines, &ScriptEngines::scriptsReloading, scriptEngines, [this] { + getEntities()->reloadEntityScripts(); + }, Qt::QueuedConnection); + + connect(scriptEngines, &ScriptEngines::scriptLoadError, + scriptEngines, [](const QString& filename, const QString& error){ + OffscreenUi::warning(nullptr, "Error Loading Script", filename + " failed to load."); + }, Qt::QueuedConnection); + + _runningScriptsWidget = new RunningScriptsWidget(_window); + + #ifdef _WIN32 WSADATA WsaData; int wsaresult = WSAStartup(MAKEWORD(2, 2), &WsaData); @@ -677,9 +697,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _overlays.init(); // do this before scripts load - _runningScriptsWidget->setRunningScripts(getRunningScripts()); - - connect(this, SIGNAL(aboutToQuit()), this, SLOT(saveScripts())); connect(this, SIGNAL(aboutToQuit()), this, SLOT(aboutToQuit())); // hook up bandwidth estimator @@ -846,18 +863,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : userInputMapper->registerDevice(_keyboardMouseDevice->getInputDevice()); userInputMapper->loadDefaultMapping(userInputMapper->getStandardDeviceID()); - // check first run... - if (_firstRun.get()) { - qCDebug(interfaceapp) << "This is a first run..."; - // clear the scripts, and set out script to our default scripts - clearScriptsBeforeRunning(); - loadScript(DEFAULT_SCRIPTS_JS_URL); - - _firstRun.set(false); - } else { - // do this as late as possible so that all required subsystems are initialized - loadScripts(); - } + // force the model the look at the correct directory (weird order of operations issue) + scriptEngines->setScriptsLocation(scriptEngines->getScriptsLocation()); + // do this as late as possible so that all required subsystems are initialized + scriptEngines->loadScripts(); loadSettings(); int SAVE_SETTINGS_INTERVAL = 10 * MSECS_PER_SECOND; // Let's save every seconds for now @@ -1016,7 +1025,9 @@ void Application::cleanupBeforeQuit() { nodeList->getPacketReceiver().setShouldDropPackets(true); getEntities()->shutdown(); // tell the entities system we're shutting down, so it will stop running scripts - ScriptEngine::stopAllScripts(this); // stop all currently running global scripts + DependencyManager::get()->saveScripts(); + DependencyManager::get()->shutdownScripting(); // stop all currently running global scripts + DependencyManager::destroy(); // first stop all timers directly or by invokeMethod // depending on what thread they run in @@ -1191,8 +1202,9 @@ void Application::initializeUi() { connect(engine, &QQmlEngine::quit, [] { qApp->quit(); }); - rootContext->setContextProperty("Audio", &AudioScriptingInterface::getInstance()); + rootContext->setContextProperty("AnimationCache", DependencyManager::get().data()); + rootContext->setContextProperty("Audio", &AudioScriptingInterface::getInstance()); rootContext->setContextProperty("Controller", DependencyManager::get().data()); rootContext->setContextProperty("Entities", DependencyManager::get().data()); rootContext->setContextProperty("MyAvatar", getMyAvatar()); @@ -1219,6 +1231,7 @@ void Application::initializeUi() { rootContext->setContextProperty("Menu", MenuScriptingInterface::getInstance()); rootContext->setContextProperty("Stats", Stats::getInstance()); rootContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance()); + rootContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get().data()); rootContext->setContextProperty("AudioDevice", AudioDeviceScriptingInterface::getInstance()); rootContext->setContextProperty("AnimationCache", DependencyManager::get().data()); rootContext->setContextProperty("SoundCache", DependencyManager::get().data()); @@ -1233,7 +1246,6 @@ void Application::initializeUi() { rootContext->setContextProperty("HMD", DependencyManager::get().data()); rootContext->setContextProperty("Scene", DependencyManager::get().data()); rootContext->setContextProperty("Render", DependencyManager::get().data()); - rootContext->setContextProperty("ScriptDiscoveryService", this->getRunningScriptsWidget()); _glWidget->installEventFilter(offscreenUi.data()); VrMenu::load(); @@ -3437,29 +3449,6 @@ bool Application::isHMDMode() const { } float Application::getTargetFrameRate() { return getActiveDisplayPlugin()->getTargetFrameRate(); } -QRect Application::getDesirableApplicationGeometry() { - QRect applicationGeometry = getWindow()->geometry(); - - // If our parent window is on the HMD, then don't use its geometry, instead use - // the "main screen" geometry. - HMDToolsDialog* hmdTools = DependencyManager::get()->getHMDToolsDialog(); - if (hmdTools && hmdTools->hasHMDScreen()) { - QScreen* hmdScreen = hmdTools->getHMDScreen(); - QWindow* appWindow = getWindow()->windowHandle(); - QScreen* appScreen = appWindow->screen(); - - // if our app's screen is the hmd screen, we don't want to place the - // running scripts widget on it. So we need to pick a better screen. - // we will use the screen for the HMDTools since it's a guarenteed - // better screen. - if (appScreen == hmdScreen) { - QScreen* betterScreen = hmdTools->windowHandle()->screen(); - applicationGeometry = betterScreen->geometry(); - } - } - return applicationGeometry; -} - ///////////////////////////////////////////////////////////////////////////////////// // loadViewFrustum() // @@ -4163,48 +4152,6 @@ int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer void Application::packetSent(quint64 length) { } -const QString SETTINGS_KEY = "Settings"; - -void Application::loadScripts() { - // loads all saved scripts - Settings settings; - int size = settings.beginReadArray(SETTINGS_KEY); - for (int i = 0; i < size; ++i){ - settings.setArrayIndex(i); - QString string = settings.value("script").toString(); - if (!string.isEmpty()) { - loadScript(string); - } - } - settings.endArray(); -} - -void Application::clearScriptsBeforeRunning() { - // clears all scripts from the settingsSettings settings; - Settings settings; - settings.beginWriteArray(SETTINGS_KEY); - settings.remove(""); -} - -void Application::saveScripts() { - // Saves all currently running user-loaded scripts - Settings settings; - settings.beginWriteArray(SETTINGS_KEY); - settings.remove(""); - - QStringList runningScripts = getRunningScripts(); - int i = 0; - for (auto it = runningScripts.begin(); it != runningScripts.end(); ++it) { - if (getScriptEngine(*it)->isUserLoaded()) { - settings.setArrayIndex(i); - settings.setValue("script", *it); - ++i; - } - } - settings.endArray(); -} - - void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) { // setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so // we can use the same ones from the application. @@ -4231,11 +4178,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("Clipboard", clipboardScriptable); connect(scriptEngine, &ScriptEngine::finished, clipboardScriptable, &ClipboardScriptingInterface::deleteLater); - connect(scriptEngine, &ScriptEngine::finished, this, &Application::scriptFinished, Qt::DirectConnection); - - connect(scriptEngine, SIGNAL(loadScript(const QString&, bool)), this, SLOT(loadScript(const QString&, bool))); - connect(scriptEngine, SIGNAL(reloadScript(const QString&, bool)), this, SLOT(reloadScript(const QString&, bool))); - scriptEngine->registerGlobalObject("Overlays", &_overlays); qScriptRegisterMetaType(scriptEngine, OverlayPropertyResultToScriptValue, OverlayPropertyResultFromScriptValue); qScriptRegisterMetaType(scriptEngine, RayToOverlayIntersectionResultToScriptValue, @@ -4283,7 +4225,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("Scene", DependencyManager::get().data()); scriptEngine->registerGlobalObject("Render", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("ScriptDiscoveryService", this->getRunningScriptsWidget()); + scriptEngine->registerGlobalObject("ScriptDiscoveryService", DependencyManager::get().data()); } bool Application::canAcceptURL(const QString& urlString) const { @@ -4389,7 +4331,7 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) { if (reply == QMessageBox::Yes) { qCDebug(interfaceapp) << "Chose to run the script: " << scriptFilenameOrURL; - loadScript(scriptFilenameOrURL); + DependencyManager::get()->loadScript(scriptFilenameOrURL); } else { qCDebug(interfaceapp) << "Declined to run the script: " << scriptFilenameOrURL; } @@ -4562,186 +4504,6 @@ bool Application::displayAvatarAttachmentConfirmationDialog(const QString& name) } } -ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUserLoaded, - bool loadScriptFromEditor, bool activateMainWindow, bool reload) { - - if (isAboutToQuit()) { - return NULL; - } - - QUrl scriptUrl(scriptFilename); - const QString& scriptURLString = scriptUrl.toString(); - { - QReadLocker lock(&_scriptEnginesHashLock); - if (_scriptEnginesHash.contains(scriptURLString) && loadScriptFromEditor - && !_scriptEnginesHash[scriptURLString]->isFinished()) { - - return _scriptEnginesHash[scriptURLString]; - } - } - - ScriptEngine* scriptEngine = new ScriptEngine(NO_SCRIPT, "", &_controllerScriptingInterface); - scriptEngine->setUserLoaded(isUserLoaded); - - if (scriptFilename.isNull()) { - // This appears to be the script engine used by the script widget's evaluation window before the file has been saved... - - // this had better be the script editor (we should de-couple so somebody who thinks they are loading a script - // doesn't just get an empty script engine) - - // we can complete setup now since there isn't a script we have to load - registerScriptEngineWithApplicationServices(scriptEngine); - scriptEngine->runInThread(); - } else { - // connect to the appropriate signals of this script engine - connect(scriptEngine, &ScriptEngine::scriptLoaded, this, &Application::handleScriptEngineLoaded); - connect(scriptEngine, &ScriptEngine::errorLoadingScript, this, &Application::handleScriptLoadError); - - // get the script engine object to load the script at the designated script URL - scriptEngine->loadURL(scriptUrl, reload); - } - - // restore the main window's active state - if (activateMainWindow && !loadScriptFromEditor) { - _window->activateWindow(); - } - - return scriptEngine; -} - -void Application::reloadScript(const QString& scriptName, bool isUserLoaded) { - loadScript(scriptName, isUserLoaded, false, false, true); -} - -// FIXME - change to new version of ScriptCache loading notification -void Application::handleScriptEngineLoaded(const QString& scriptFilename) { - ScriptEngine* scriptEngine = qobject_cast(sender()); - - { - QWriteLocker lock(&_scriptEnginesHashLock); - _scriptEnginesHash.insertMulti(scriptFilename, scriptEngine); - } - - _runningScriptsWidget->setRunningScripts(getRunningScripts()); - UserActivityLogger::getInstance().loadedScript(scriptFilename); - - // register our application services and set it off on its own thread - registerScriptEngineWithApplicationServices(scriptEngine); - scriptEngine->runInThread(); -} - -// FIXME - change to new version of ScriptCache loading notification -void Application::handleScriptLoadError(const QString& scriptFilename) { - qCDebug(interfaceapp) << "Application::loadScript(), script failed to load..."; - OffscreenUi::warning(getWindow(), "Error Loading Script", scriptFilename + " failed to load."); -} - -QStringList Application::getRunningScripts() { - QReadLocker lock(&_scriptEnginesHashLock); - return _scriptEnginesHash.keys(); -} - -ScriptEngine* Application::getScriptEngine(const QString& scriptHash) { - QReadLocker lock(&_scriptEnginesHashLock); - return _scriptEnginesHash.value(scriptHash, nullptr); -} - -void Application::scriptFinished(const QString& scriptName, ScriptEngine* engine) { - bool removed = false; - { - QWriteLocker lock(&_scriptEnginesHashLock); - const QString& scriptURLString = QUrl(scriptName).toString(); - for (auto it = _scriptEnginesHash.find(scriptURLString); it != _scriptEnginesHash.end(); ++it) { - if (it.value() == engine) { - _scriptEnginesHash.erase(it); - removed = true; - break; - } - } - } - if (removed) { - postLambdaEvent([this, scriptName]() { - _runningScriptsWidget->scriptStopped(scriptName); - _runningScriptsWidget->setRunningScripts(getRunningScripts()); - }); - } -} - -void Application::stopAllScripts(bool restart) { - { - QReadLocker lock(&_scriptEnginesHashLock); - - if (restart) { - // Delete all running scripts from cache so that they are re-downloaded when they are restarted - auto scriptCache = DependencyManager::get(); - for (QHash::const_iterator it = _scriptEnginesHash.constBegin(); - it != _scriptEnginesHash.constEnd(); it++) { - if (!it.value()->isFinished()) { - scriptCache->deleteScript(it.key()); - } - } - } - - // Stop and possibly restart all currently running scripts - for (QHash::const_iterator it = _scriptEnginesHash.constBegin(); - it != _scriptEnginesHash.constEnd(); it++) { - if (it.value()->isFinished()) { - continue; - } - if (restart && it.value()->isUserLoaded()) { - connect(it.value(), &ScriptEngine::finished, this, [this](QString scriptName, ScriptEngine* engine) { - reloadScript(scriptName); - }); - } - QMetaObject::invokeMethod(it.value(), "stop"); - //it.value()->stop(); - qCDebug(interfaceapp) << "stopping script..." << it.key(); - } - } - getMyAvatar()->clearScriptableSettings(); -} - -bool Application::stopScript(const QString& scriptHash, bool restart) { - bool stoppedScript = false; - { - QReadLocker lock(&_scriptEnginesHashLock); - if (_scriptEnginesHash.contains(scriptHash)) { - ScriptEngine* scriptEngine = _scriptEnginesHash[scriptHash]; - if (restart) { - auto scriptCache = DependencyManager::get(); - scriptCache->deleteScript(QUrl(scriptHash)); - connect(scriptEngine, &ScriptEngine::finished, this, [this](QString scriptName, ScriptEngine* engine) { - reloadScript(scriptName); - }); - } - scriptEngine->stop(); - stoppedScript = true; - qCDebug(interfaceapp) << "stopping script..." << scriptHash; - } - } - if (_scriptEnginesHash.empty()) { - getMyAvatar()->clearScriptableSettings(); - } - return stoppedScript; -} - -void Application::reloadAllScripts() { - DependencyManager::get()->clearCache(); - getEntities()->reloadEntityScripts(); - stopAllScripts(true); -} - -void Application::reloadOneScript(const QString& scriptName) { - stopScript(scriptName, true); -} - -void Application::loadDefaultScripts() { - QReadLocker lock(&_scriptEnginesHashLock); - if (!_scriptEnginesHash.contains(DEFAULT_SCRIPTS_JS_URL)) { - loadScript(DEFAULT_SCRIPTS_JS_URL); - } -} - void Application::toggleRunningScriptsWidget() { if (_runningScriptsWidget->isVisible()) { if (_runningScriptsWidget->hasFocus()) { @@ -4799,27 +4561,17 @@ void Application::domainSettingsReceived(const QJsonObject& domainSettingsObject qCDebug(interfaceapp) << "Destination wallet UUID for edit payments is" << voxelWalletUUID; } -QString Application::getPreviousScriptLocation() { - return _previousScriptLocation.get(); -} - -void Application::setPreviousScriptLocation(const QString& previousScriptLocation) { - _previousScriptLocation.set(previousScriptLocation); -} - void Application::loadDialog() { - - QString fileNameString = QFileDialog::getOpenFileName(_glWidget, - tr("Open Script"), - getPreviousScriptLocation(), - tr("JavaScript Files (*.js)")); + // To be migratd to QML + QString fileNameString = QFileDialog::getOpenFileName( + _glWidget, tr("Open Script"), "", tr("JavaScript Files (*.js)")); if (!fileNameString.isEmpty()) { - setPreviousScriptLocation(fileNameString); - loadScript(fileNameString); + DependencyManager::get()->loadScript(fileNameString); } } void Application::loadScriptURLDialog() { + // To be migratd to QML QInputDialog scriptURLDialog(getWindow()); scriptURLDialog.setWindowTitle("Open and Run Script URL"); scriptURLDialog.setLabelText("Script:"); @@ -4835,19 +4587,10 @@ void Application::loadScriptURLDialog() { // the user input a new hostname, use that newScript = scriptURLDialog.textValue(); } - loadScript(newScript); + DependencyManager::get()->loadScript(newScript); } } -QString Application::getScriptsLocation() { - return _scriptsLocationHandle.get(); -} - -void Application::setScriptsLocation(const QString& scriptsLocation) { - _scriptsLocationHandle.set(scriptsLocation); - emit scriptLocationChanged(scriptsLocation); -} - void Application::toggleLogDialog() { if (! _logDialog) { _logDialog = new LogDialog(_glWidget, getLogger()); diff --git a/interface/src/Application.h b/interface/src/Application.h index 39e5453d1d..9237373778 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -106,10 +106,6 @@ public: void postLambdaEvent(std::function f); - void loadScripts(); - QString getPreviousScriptLocation(); - void setPreviousScriptLocation(const QString& previousScriptLocation); - void clearScriptsBeforeRunning(); void initializeGL(); void initializeUi(); void paintGL(); @@ -197,9 +193,6 @@ public: NodeToJurisdictionMap& getEntityServerJurisdictions() { return _entityServerJurisdictions; } - QStringList getRunningScripts(); - ScriptEngine* getScriptEngine(const QString& scriptHash); - float getRenderResolutionScale() const; bool isAboutToQuit() const { return _aboutToQuit; } @@ -212,14 +205,8 @@ public: glm::mat4 getEyeOffset(int eye) const; glm::mat4 getEyeProjection(int eye) const; - QRect getDesirableApplicationGeometry(); - RunningScriptsWidget* getRunningScriptsWidget() { return _runningScriptsWidget; } - Bookmarks* getBookmarks() const { return _bookmarks; } - QString getScriptsLocation(); - void setScriptsLocation(const QString& scriptsLocation); - virtual bool canAcceptURL(const QString& url) const override; virtual bool acceptURL(const QString& url, bool defaultUpload = false) override; @@ -241,8 +228,6 @@ public: float getAverageSimsPerSecond(); signals: - void scriptLocationChanged(const QString& newPath); - void svoImportRequested(const QString& url); void checkBackgroundDownloads(); @@ -263,14 +248,6 @@ public slots: void loadDialog(); void loadScriptURLDialog(); void toggleLogDialog(); - - ScriptEngine* loadScript(const QString& scriptFilename = QString(), bool isUserLoaded = true, - bool loadScriptFromEditor = false, bool activateMainWindow = false, bool reload = false); - void stopAllScripts(bool restart = false); - bool stopScript(const QString& scriptHash, bool restart = false); - void reloadAllScripts(); - void reloadOneScript(const QString& scriptName); - void loadDefaultScripts(); void toggleRunningScriptsWidget(); void showFriendsWindow(); @@ -313,9 +290,6 @@ private slots: void idle(uint64_t now); void aboutToQuit(); - void handleScriptEngineLoaded(const QString& scriptFilename); - void handleScriptLoadError(const QString& scriptFilename); - void connectedToDomain(const QString& hostname); void audioMuteToggled(); @@ -331,10 +305,6 @@ private slots: void loadSettings(); void saveSettings(); - void scriptFinished(const QString& scriptName, ScriptEngine* engine); - void saveScripts(); - void reloadScript(const QString& scriptName, bool isUserLoaded = true); - bool acceptSnapshot(const QString& urlString); bool askToSetAvatarUrl(const QString& url); bool askToLoadScript(const QString& scriptFilenameOrURL); @@ -468,9 +438,6 @@ private: Camera _mirrorCamera; // Cammera for mirror view QRect _mirrorViewRect; - Setting::Handle _firstRun; - Setting::Handle _previousScriptLocation; - Setting::Handle _scriptsLocationHandle; Setting::Handle _fieldOfView; float _scaleMirror; @@ -499,12 +466,7 @@ private: TouchEvent _lastTouchEvent; - QReadWriteLock _scriptEnginesHashLock; - RunningScriptsWidget* _runningScriptsWidget; - QHash _scriptEnginesHash; - bool _runningScriptsWidgetWasVisible; - QString _scriptsLocation; - + RunningScriptsWidget* _runningScriptsWidget{ nullptr }; quint64 _lastNackTime; quint64 _lastSendDownstreamAudioStats; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 6373b3fdb2..eec04d4640 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "Application.h" #include "AccountManager.h" @@ -114,13 +115,15 @@ Menu::Menu() { Qt::CTRL | Qt::SHIFT | Qt::Key_O, qApp, SLOT(loadScriptURLDialog()), QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + auto scriptEngines = DependencyManager::get(); // Edit > Stop All Scripts... [advanced] - addActionToQMenuAndActionHash(editMenu, MenuOption::StopAllScripts, 0, qApp, SLOT(stopAllScripts()), + addActionToQMenuAndActionHash(editMenu, MenuOption::StopAllScripts, 0, + scriptEngines.data(), SLOT(stopAllScripts()), QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); // Edit > Reload All Scripts... [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::ReloadAllScripts, Qt::CTRL | Qt::Key_R, - qApp, SLOT(reloadAllScripts()), + scriptEngines.data(), SLOT(reloadAllScripts()), QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); // Edit > Scripts Editor... [advanced] diff --git a/interface/src/ui/HMDToolsDialog.cpp b/interface/src/ui/HMDToolsDialog.cpp index c1ea541864..f9fc444d4b 100644 --- a/interface/src/ui/HMDToolsDialog.cpp +++ b/interface/src/ui/HMDToolsDialog.cpp @@ -79,9 +79,6 @@ HMDToolsDialog::HMDToolsDialog(QWidget* parent) : // what screens we're allowed on watchWindow(windowHandle()); auto dialogsManager = DependencyManager::get(); - if (qApp->getRunningScriptsWidget()) { - watchWindow(qApp->getRunningScriptsWidget()->windowHandle()); - } if (qApp->getToolWindow()) { watchWindow(qApp->getToolWindow()->windowHandle()); } diff --git a/interface/src/ui/JSConsole.cpp b/interface/src/ui/JSConsole.cpp index 2d34ba5608..5d197f5ddc 100644 --- a/interface/src/ui/JSConsole.cpp +++ b/interface/src/ui/JSConsole.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include "Application.h" @@ -84,7 +85,7 @@ void JSConsole::setScriptEngine(ScriptEngine* scriptEngine) { // if scriptEngine is NULL then create one and keep track of it using _ownScriptEngine _ownScriptEngine = scriptEngine == NULL; - _scriptEngine = _ownScriptEngine ? qApp->loadScript(QString(), false) : scriptEngine; + _scriptEngine = _ownScriptEngine ? DependencyManager::get()->loadScript(QString(), false) : scriptEngine; connect(_scriptEngine, SIGNAL(printedMessage(const QString&)), this, SLOT(handlePrint(const QString&))); connect(_scriptEngine, SIGNAL(errorMessage(const QString&)), this, SLOT(handleError(const QString&))); diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 216c11a05c..b5e24fef1e 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "Application.h" #include "DialogsManager.h" @@ -44,7 +45,9 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) : connect(ui.buttonBrowseLocation, &QPushButton::clicked, this, &PreferencesDialog::openSnapshotLocationBrowser); connect(ui.buttonBrowseScriptsLocation, &QPushButton::clicked, this, &PreferencesDialog::openScriptsLocationBrowser); - connect(ui.buttonReloadDefaultScripts, &QPushButton::clicked, qApp, &Application::loadDefaultScripts); + connect(ui.buttonReloadDefaultScripts, &QPushButton::clicked, [] { + DependencyManager::get()->loadDefaultScripts(); + }); connect(ui.buttonChangeAppearance, &QPushButton::clicked, this, &PreferencesDialog::openFullAvatarModelBrowser); connect(ui.appearanceDescription, &QLineEdit::editingFinished, this, &PreferencesDialog::changeFullAvatarURL); @@ -171,7 +174,7 @@ void PreferencesDialog::loadPreferences() { ui.snapshotLocationEdit->setText(Snapshot::snapshotsLocation.get()); - ui.scriptsLocationEdit->setText(qApp->getScriptsLocation()); + ui.scriptsLocationEdit->setText(DependencyManager::get()->getScriptsLocation()); ui.pupilDilationSlider->setValue(myAvatar->getHead()->getPupilDilation() * ui.pupilDilationSlider->maximum()); @@ -265,7 +268,7 @@ void PreferencesDialog::savePreferences() { } if (!ui.scriptsLocationEdit->text().isEmpty() && QDir(ui.scriptsLocationEdit->text()).exists()) { - qApp->setScriptsLocation(ui.scriptsLocationEdit->text()); + DependencyManager::get()->setScriptsLocation(ui.scriptsLocationEdit->text()); } myAvatar->getHead()->setPupilDilation(ui.pupilDilationSlider->value() / (float)ui.pupilDilationSlider->maximum()); diff --git a/interface/src/ui/RunningScriptsWidget.cpp b/interface/src/ui/RunningScriptsWidget.cpp index 3752ea2176..483d467f01 100644 --- a/interface/src/ui/RunningScriptsWidget.cpp +++ b/interface/src/ui/RunningScriptsWidget.cpp @@ -22,8 +22,10 @@ #include #include +#include #include "Application.h" +#include "MainWindow.h" #include "Menu.h" #include "ScriptsModel.h" #include "UIUtil.h" @@ -33,57 +35,55 @@ RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) : Qt::WindowCloseButtonHint), ui(new Ui::RunningScriptsWidget), _reloadSignalMapper(this), - _stopSignalMapper(this), - _scriptsModelFilter(this), - _scriptsModel(this) { + _stopSignalMapper(this) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose, false); ui->filterLineEdit->installEventFilter(this); - connect(&_scriptsModelFilter, &QSortFilterProxyModel::modelReset, + auto scriptEngines = DependencyManager::get().data(); + connect(scriptEngines->scriptsModelFilter(), &QSortFilterProxyModel::modelReset, this, &RunningScriptsWidget::selectFirstInList); // FIXME: menu isn't prepared at this point. //QString shortcutText = Menu::getInstance()->getActionForOption(MenuOption::ReloadAllScripts)->shortcut().toString(QKeySequence::NativeText); //ui->tipLabel->setText("Tip: Use " + shortcutText + " to reload all scripts."); - - _scriptsModelFilter.setSourceModel(&_scriptsModel); - _scriptsModelFilter.sort(0, Qt::AscendingOrder); - _scriptsModelFilter.setDynamicSortFilter(true); - ui->scriptTreeView->setModel(&_scriptsModelFilter); + ui->scriptTreeView->setModel(scriptEngines->scriptsModelFilter()); connect(ui->filterLineEdit, &QLineEdit::textChanged, this, &RunningScriptsWidget::updateFileFilter); connect(ui->scriptTreeView, &QTreeView::doubleClicked, this, &RunningScriptsWidget::loadScriptFromList); - connect(ui->reloadAllButton, &QPushButton::clicked, qApp, &Application::reloadAllScripts); - connect(ui->stopAllButton, &QPushButton::clicked, this, &RunningScriptsWidget::allScriptsStopped); + connect(ui->reloadAllButton, &QPushButton::clicked, scriptEngines, &ScriptEngines::reloadAllScripts); + connect(ui->stopAllButton, &QPushButton::clicked, scriptEngines, &ScriptEngines::stopAllScripts); connect(ui->loadScriptFromDiskButton, &QPushButton::clicked, qApp, &Application::loadDialog); connect(ui->loadScriptFromURLButton, &QPushButton::clicked, qApp, &Application::loadScriptURLDialog); connect(&_reloadSignalMapper, static_cast(&QSignalMapper::mapped), - qApp, &Application::reloadOneScript); - + [scriptEngines](const QString& scriptName) { scriptEngines->stopScript(scriptName, true); }); connect(&_stopSignalMapper, static_cast(&QSignalMapper::mapped), - [](const QString& script) { qApp->stopScript(script); }); + [scriptEngines](const QString& scriptName) { scriptEngines->stopScript(scriptName); }); + setRunningScripts(scriptEngines->getRunningScripts()); + connect(scriptEngines, &ScriptEngines::scriptCountChanged, scriptEngines, [this, scriptEngines] { + setRunningScripts(scriptEngines->getRunningScripts()); + }, Qt::QueuedConnection); UIUtil::scaleWidgetFontSizes(this); } RunningScriptsWidget::~RunningScriptsWidget() { delete ui; - _scriptsModel.deleteLater(); } void RunningScriptsWidget::updateFileFilter(const QString& filter) { QRegExp regex("^.*" + QRegExp::escape(filter) + ".*$", Qt::CaseInsensitive); - _scriptsModelFilter.setFilterRegExp(regex); + DependencyManager::get()->scriptsModelFilter()->setFilterRegExp(regex); selectFirstInList(); } void RunningScriptsWidget::loadScriptFromList(const QModelIndex& index) { - QVariant scriptFile = _scriptsModelFilter.data(index, ScriptsModel::ScriptPath); - qApp->loadScript(scriptFile.toString()); + auto scriptEngines = DependencyManager::get(); + QVariant scriptFile = scriptEngines->scriptsModelFilter()->data(index, ScriptsModel::ScriptPath); + scriptEngines->loadScript(scriptFile.toString()); } void RunningScriptsWidget::loadSelectedScript() { @@ -172,7 +172,7 @@ void RunningScriptsWidget::showEvent(QShowEvent* event) { ui->filterLineEdit->setFocus(); } - QRect parentGeometry = qApp->getDesirableApplicationGeometry(); + QRect parentGeometry = qApp->getWindow()->geometry(); int titleBarHeight = UIUtil::getWindowTitleBarHeight(this); int topMargin = titleBarHeight; @@ -183,8 +183,9 @@ void RunningScriptsWidget::showEvent(QShowEvent* event) { } void RunningScriptsWidget::selectFirstInList() { - if (_scriptsModelFilter.rowCount() > 0) { - ui->scriptTreeView->setCurrentIndex(_scriptsModelFilter.index(0, 0)); + auto model = DependencyManager::get()->scriptsModelFilter(); + if (model->rowCount() > 0) { + ui->scriptTreeView->setCurrentIndex(model->index(0, 0)); } } @@ -217,90 +218,5 @@ void RunningScriptsWidget::keyPressEvent(QKeyEvent *keyEvent) { } void RunningScriptsWidget::allScriptsStopped() { - qApp->stopAllScripts(); -} - -QVariantList RunningScriptsWidget::getRunning() { - const int WINDOWS_DRIVE_LETTER_SIZE = 1; - QVariantList result; - foreach(const QString& runningScript, qApp->getRunningScripts()) { - QUrl runningScriptURL = QUrl(runningScript); - if (runningScriptURL.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) { - runningScriptURL = QUrl::fromLocalFile(runningScriptURL.toDisplayString(QUrl::FormattingOptions(QUrl::FullyEncoded))); - } - QVariantMap resultNode; - resultNode.insert("name", runningScriptURL.fileName()); - resultNode.insert("url", runningScriptURL.toDisplayString(QUrl::FormattingOptions(QUrl::FullyEncoded))); - // The path contains the exact path/URL of the script, which also is used in the stopScript function. - resultNode.insert("path", runningScript); - resultNode.insert("local", runningScriptURL.isLocalFile()); - result.append(resultNode); - } - return result; -} - -QVariantList RunningScriptsWidget::getPublic() { - return getPublicChildNodes(NULL); -} - -QVariantList RunningScriptsWidget::getPublicChildNodes(TreeNodeFolder* parent) { - QVariantList result; - QList treeNodes = qApp->getRunningScriptsWidget()->getScriptsModel() - ->getFolderNodes(parent); - for (int i = 0; i < treeNodes.size(); i++) { - TreeNodeBase* node = treeNodes.at(i); - if (node->getType() == TREE_NODE_TYPE_FOLDER) { - TreeNodeFolder* folder = static_cast(node); - QVariantMap resultNode; - resultNode.insert("name", node->getName()); - resultNode.insert("type", "folder"); - resultNode.insert("children", getPublicChildNodes(folder)); - result.append(resultNode); - continue; - } - TreeNodeScript* script = static_cast(node); - if (script->getOrigin() == ScriptOrigin::SCRIPT_ORIGIN_LOCAL) { - continue; - } - QVariantMap resultNode; - resultNode.insert("name", node->getName()); - resultNode.insert("type", "script"); - resultNode.insert("url", script->getFullPath()); - result.append(resultNode); - } - return result; -} - -QVariantList RunningScriptsWidget::getLocal() { - QVariantList result; - QList treeNodes = qApp->getRunningScriptsWidget()->getScriptsModel() - ->getFolderNodes(NULL); - for (int i = 0; i < treeNodes.size(); i++) { - TreeNodeBase* node = treeNodes.at(i); - if (node->getType() != TREE_NODE_TYPE_SCRIPT) { - continue; - } - TreeNodeScript* script = static_cast(node); - if (script->getOrigin() != ScriptOrigin::SCRIPT_ORIGIN_LOCAL) { - continue; - } - QVariantMap resultNode; - resultNode.insert("name", node->getName()); - resultNode.insert("path", script->getFullPath()); - result.append(resultNode); - } - return result; -} - -bool RunningScriptsWidget::stopScriptByName(const QString& name) { - foreach (const QString& runningScript, qApp->getRunningScripts()) { - if (QUrl(runningScript).fileName().toLower() == name.trimmed().toLower()) { - return qApp->stopScript(runningScript, false); - } - } - return false; -} - -bool RunningScriptsWidget::stopScript(const QString& name, bool restart) { - return qApp->stopScript(name, restart); + DependencyManager::get()->stopAllScripts(); } diff --git a/interface/src/ui/RunningScriptsWidget.h b/interface/src/ui/RunningScriptsWidget.h index 9029b13c56..b60586b5e7 100644 --- a/interface/src/ui/RunningScriptsWidget.h +++ b/interface/src/ui/RunningScriptsWidget.h @@ -33,24 +33,12 @@ public: void setRunningScripts(const QStringList& list); - const ScriptsModel* getScriptsModel() { return &_scriptsModel; } - -signals: - void scriptStopped(const QString& scriptName); - protected: virtual bool eventFilter(QObject* sender, QEvent* event); virtual void keyPressEvent(QKeyEvent* event); virtual void showEvent(QShowEvent* event); -public slots: - QVariantList getRunning(); - QVariantList getPublic(); - QVariantList getLocal(); - bool stopScript(const QString& name, bool restart = false); - bool stopScriptByName(const QString& name); - private slots: void allScriptsStopped(); void updateFileFilter(const QString& filter); @@ -62,9 +50,6 @@ private: Ui::RunningScriptsWidget* ui; QSignalMapper _reloadSignalMapper; QSignalMapper _stopSignalMapper; - ScriptsModelFilter _scriptsModelFilter; - ScriptsModel _scriptsModel; - QVariantList getPublicChildNodes(TreeNodeFolder* parent); }; diff --git a/interface/src/ui/ScriptEditorWidget.cpp b/interface/src/ui/ScriptEditorWidget.cpp index 380b645681..a261c208d7 100644 --- a/interface/src/ui/ScriptEditorWidget.cpp +++ b/interface/src/ui/ScriptEditorWidget.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -101,17 +102,18 @@ bool ScriptEditorWidget::setRunning(bool run) { disconnect(_scriptEngine, &ScriptEngine::finished, this, &ScriptEditorWidget::onScriptFinished); } + auto scriptEngines = DependencyManager::get(); if (run) { const QString& scriptURLString = QUrl(_currentScript).toString(); // Reload script so that an out of date copy is not retrieved from the cache - _scriptEngine = qApp->loadScript(scriptURLString, true, true, false, true); + _scriptEngine = scriptEngines->loadScript(scriptURLString, true, true, false, true); connect(_scriptEngine, &ScriptEngine::runningStateChanged, this, &ScriptEditorWidget::runningStateChanged); connect(_scriptEngine, &ScriptEngine::update, this, &ScriptEditorWidget::onScriptModified); connect(_scriptEngine, &ScriptEngine::finished, this, &ScriptEditorWidget::onScriptFinished); } else { connect(_scriptEngine, &ScriptEngine::finished, this, &ScriptEditorWidget::onScriptFinished); const QString& scriptURLString = QUrl(_currentScript).toString(); - qApp->stopScript(scriptURLString); + scriptEngines->stopScript(scriptURLString); _scriptEngine = NULL; } _console->setScriptEngine(_scriptEngine); @@ -173,7 +175,7 @@ void ScriptEditorWidget::loadFile(const QString& scriptPath) { } } const QString& scriptURLString = QUrl(_currentScript).toString(); - _scriptEngine = qApp->getScriptEngine(scriptURLString); + _scriptEngine = DependencyManager::get()->getScriptEngine(scriptURLString); if (_scriptEngine != NULL) { connect(_scriptEngine, &ScriptEngine::runningStateChanged, this, &ScriptEditorWidget::runningStateChanged); connect(_scriptEngine, &ScriptEngine::update, this, &ScriptEditorWidget::onScriptModified); @@ -187,11 +189,12 @@ bool ScriptEditorWidget::save() { } bool ScriptEditorWidget::saveAs() { + auto scriptEngines = DependencyManager::get(); QString fileName = QFileDialog::getSaveFileName(this, tr("Save script"), - qApp->getPreviousScriptLocation(), + scriptEngines->getPreviousScriptLocation(), tr("JavaScript Files (*.js)")); if (!fileName.isEmpty()) { - qApp->setPreviousScriptLocation(fileName); + scriptEngines->setPreviousScriptLocation(fileName); return saveFile(fileName); } else { return false; diff --git a/interface/src/ui/ScriptEditorWindow.cpp b/interface/src/ui/ScriptEditorWindow.cpp index 3c6d0f73d5..919c8b64d3 100644 --- a/interface/src/ui/ScriptEditorWindow.cpp +++ b/interface/src/ui/ScriptEditorWindow.cpp @@ -16,6 +16,7 @@ #include "ScriptEditorWidget.h" #include +#include #include #include #include @@ -27,6 +28,7 @@ #include #include +#include #include "Application.h" #include "PathUtils.h" @@ -85,11 +87,12 @@ void ScriptEditorWindow::loadScriptMenu(const QString& scriptName) { } void ScriptEditorWindow::loadScriptClicked() { + auto scriptEngines = DependencyManager::get(); QString scriptName = QFileDialog::getOpenFileName(this, tr("Interface"), - qApp->getPreviousScriptLocation(), + scriptEngines->getPreviousScriptLocation(), tr("JavaScript Files (*.js)")); if (!scriptName.isEmpty()) { - qApp->setPreviousScriptLocation(scriptName); + scriptEngines->setPreviousScriptLocation(scriptName); addScriptEditorWidget("loading...")->loadFile(scriptName); updateButtons(); } @@ -97,7 +100,7 @@ void ScriptEditorWindow::loadScriptClicked() { void ScriptEditorWindow::loadMenuAboutToShow() { _loadMenu->clear(); - QStringList runningScripts = qApp->getRunningScripts(); + QStringList runningScripts = DependencyManager::get()->getRunningScripts();; if (runningScripts.count() > 0) { QSignalMapper* signalMapper = new QSignalMapper(this); foreach (const QString& runningScript, runningScripts) { diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 8026102478..e997879391 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -46,11 +46,13 @@ #include "TypedArrays.h" #include "XMLHttpRequestClass.h" #include "WebSocketClass.h" - #include "RecordingScriptingInterface.h" +#include "ScriptEngines.h" #include "MIDIEvent.h" +std::atomic ScriptEngine::_stoppingAllScripts { false }; + static const QString SCRIPT_EXCEPTION_FORMAT = "[UncaughtException] %1 in %2:%3"; Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature) @@ -132,9 +134,7 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam _fileNameString(fileNameString), _arrayBufferClass(new ArrayBufferClass(this)) { - _allScriptsMutex.lock(); - _allKnownScriptEngines.insert(this); - _allScriptsMutex.unlock(); + DependencyManager::get()->addScriptEngine(this); connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) { hadUncaughtExceptions(*this, _fileNameString); @@ -144,14 +144,7 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam ScriptEngine::~ScriptEngine() { qCDebug(scriptengine) << "Script Engine shutting down (destructor) for script:" << getFilename(); - // If we're not already in the middle of stopping all scripts, then we should remove ourselves - // from the list of running scripts. We don't do this if we're in the process of stopping all scripts - // because that method removes scripts from its list as it iterates them - if (!_stoppingAllScripts) { - _allScriptsMutex.lock(); - _allKnownScriptEngines.remove(this); - _allScriptsMutex.unlock(); - } + DependencyManager::get()->removeScriptEngine(this); } void ScriptEngine::disconnectNonEssentialSignals() { @@ -187,67 +180,6 @@ void ScriptEngine::runInThread() { workerThread->start(); } -QSet ScriptEngine::_allKnownScriptEngines; -QMutex ScriptEngine::_allScriptsMutex; -std::atomic ScriptEngine::_stoppingAllScripts { false }; - -void ScriptEngine::stopAllScripts(QObject* application) { - _allScriptsMutex.lock(); - _stoppingAllScripts = true; - - qCDebug(scriptengine) << "Stopping all scripts.... currently known scripts:" << _allKnownScriptEngines.size(); - - QMutableSetIterator i(_allKnownScriptEngines); - while (i.hasNext()) { - ScriptEngine* scriptEngine = i.next(); - - QString scriptName = scriptEngine->getFilename(); - - // NOTE: typically all script engines are running. But there's at least one known exception to this, the - // "entities sandbox" which is only used to evaluate entities scripts to test their validity before using - // them. We don't need to stop scripts that aren't running. - if (scriptEngine->isRunning()) { - - // If the script is running, but still evaluating then we need to wait for its evaluation step to - // complete. After that we can handle the stop process appropriately - if (scriptEngine->evaluatePending()) { - while (scriptEngine->evaluatePending()) { - - // This event loop allows any started, but not yet finished evaluate() calls to complete - // we need to let these complete so that we can be guaranteed that the script engine isn't - // in a partially setup state, which can confuse our shutdown unwinding. - QEventLoop loop; - QObject::connect(scriptEngine, &ScriptEngine::evaluationFinished, &loop, &QEventLoop::quit); - loop.exec(); - } - } - - // We disconnect any script engine signals from the application because we don't want to do any - // extra stopScript/loadScript processing that the Application normally does when scripts start - // and stop. We can safely short circuit this because we know we're in the "quitting" process - scriptEngine->disconnect(application); - - // Calling stop on the script engine will set it's internal _isFinished state to true, and result - // in the ScriptEngine gracefully ending it's run() method. - scriptEngine->stop(); - - // We need to wait for the engine to be done running before we proceed, because we don't - // want any of the scripts final "scriptEnding()" or pending "update()" methods from accessing - // any application state after we leave this stopAllScripts() method - qCDebug(scriptengine) << "waiting on script:" << scriptName; - scriptEngine->waitTillDoneRunning(); - qCDebug(scriptengine) << "done waiting on script:" << scriptName; - - // If the script is stopped, we can remove it from our set - i.remove(); - } - } - _stoppingAllScripts = false; - _allScriptsMutex.unlock(); - qCDebug(scriptengine) << "DONE Stopping all scripts...."; -} - - void ScriptEngine::waitTillDoneRunning() { // If the script never started running or finished running before we got here, we don't need to wait for it if (_isRunning && _isThreaded) { diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 67a206d673..f89998d9f0 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -129,7 +129,6 @@ public: bool isRunning() const { return _isRunning; } // used by ScriptWidget void disconnectNonEssentialSignals(); - static void stopAllScripts(QObject* application); // used by Application on shutdown //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // NOTE - These are the callback implementations for ScriptUser the get called by ScriptCache when the contents @@ -204,8 +203,7 @@ protected: void forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHanderArgs); Q_INVOKABLE void entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success); - static QSet _allKnownScriptEngines; - static QMutex _allScriptsMutex; + friend class ScriptEngines; static std::atomic _stoppingAllScripts; }; diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp new file mode 100644 index 0000000000..a7894f1816 --- /dev/null +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -0,0 +1,434 @@ +// +// Created by Bradley Austin Davis on 2016/01/08 +// Copyright 2013-2016 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 "ScriptEngines.h" + +#include +#include + +#include +#include + +#include "ScriptEngine.h" +#include "ScriptEngineLogging.h" + +#define __STR2__(x) #x +#define __STR1__(x) __STR2__(x) +#define __LOC__ __FILE__ "("__STR1__(__LINE__)") : Warning Msg: " + +#ifndef __APPLE__ +static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); +#else +// Temporary fix to Qt bug: http://stackoverflow.com/questions/16194475 +static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).append("/script.js"); +#endif + +ScriptsModel& getScriptsModel() { + static ScriptsModel scriptsModel; + return scriptsModel; +} + +ScriptEngines::ScriptEngines() + : _scriptsLocationHandle("scriptsLocation", DESKTOP_LOCATION), + _previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION){ + _scriptsModelFilter.setSourceModel(&_scriptsModel); + _scriptsModelFilter.sort(0, Qt::AscendingOrder); + _scriptsModelFilter.setDynamicSortFilter(true); +} + + +QObject* scriptsModel(); + +void ScriptEngines::registerScriptInitializer(ScriptInitializer initializer) { + _scriptInitializers.push_back(initializer); +} + +void ScriptEngines::addScriptEngine(ScriptEngine* engine) { + _allScriptsMutex.lock(); + _allKnownScriptEngines.insert(engine); + _allScriptsMutex.unlock(); +} + +void ScriptEngines::removeScriptEngine(ScriptEngine* engine) { + // If we're not already in the middle of stopping all scripts, then we should remove ourselves + // from the list of running scripts. We don't do this if we're in the process of stopping all scripts + // because that method removes scripts from its list as it iterates them + if (!_stoppingAllScripts) { + _allScriptsMutex.lock(); + _allKnownScriptEngines.remove(engine); + _allScriptsMutex.unlock(); + } +} + +void ScriptEngines::shutdownScripting() { + _allScriptsMutex.lock(); + _stoppingAllScripts = true; + ScriptEngine::_stoppingAllScripts = true; + qCDebug(scriptengine) << "Stopping all scripts.... currently known scripts:" << _allKnownScriptEngines.size(); + + QMutableSetIterator i(_allKnownScriptEngines); + while (i.hasNext()) { + ScriptEngine* scriptEngine = i.next(); + QString scriptName = scriptEngine->getFilename(); + + // NOTE: typically all script engines are running. But there's at least one known exception to this, the + // "entities sandbox" which is only used to evaluate entities scripts to test their validity before using + // them. We don't need to stop scripts that aren't running. + if (scriptEngine->isRunning()) { + + // If the script is running, but still evaluating then we need to wait for its evaluation step to + // complete. After that we can handle the stop process appropriately + if (scriptEngine->evaluatePending()) { + while (scriptEngine->evaluatePending()) { + + // This event loop allows any started, but not yet finished evaluate() calls to complete + // we need to let these complete so that we can be guaranteed that the script engine isn't + // in a partially setup state, which can confuse our shutdown unwinding. + QEventLoop loop; + QObject::connect(scriptEngine, &ScriptEngine::evaluationFinished, &loop, &QEventLoop::quit); + loop.exec(); + } + } + + // We disconnect any script engine signals from the application because we don't want to do any + // extra stopScript/loadScript processing that the Application normally does when scripts start + // and stop. We can safely short circuit this because we know we're in the "quitting" process + scriptEngine->disconnect(this); + + // Calling stop on the script engine will set it's internal _isFinished state to true, and result + // in the ScriptEngine gracefully ending it's run() method. + scriptEngine->stop(); + + // We need to wait for the engine to be done running before we proceed, because we don't + // want any of the scripts final "scriptEnding()" or pending "update()" methods from accessing + // any application state after we leave this stopAllScripts() method + qCDebug(scriptengine) << "waiting on script:" << scriptName; + scriptEngine->waitTillDoneRunning(); + qCDebug(scriptengine) << "done waiting on script:" << scriptName; + + // If the script is stopped, we can remove it from our set + i.remove(); + } + } + _stoppingAllScripts = false; + _allScriptsMutex.unlock(); + qCDebug(scriptengine) << "DONE Stopping all scripts...."; +} + +QVariantList getPublicChildNodes(TreeNodeFolder* parent) { + QVariantList result; + QList treeNodes = getScriptsModel().getFolderNodes(parent); + for (int i = 0; i < treeNodes.size(); i++) { + TreeNodeBase* node = treeNodes.at(i); + if (node->getType() == TREE_NODE_TYPE_FOLDER) { + TreeNodeFolder* folder = static_cast(node); + QVariantMap resultNode; + resultNode.insert("name", node->getName()); + resultNode.insert("type", "folder"); + resultNode.insert("children", getPublicChildNodes(folder)); + result.append(resultNode); + continue; + } + TreeNodeScript* script = static_cast(node); + if (script->getOrigin() == ScriptOrigin::SCRIPT_ORIGIN_LOCAL) { + continue; + } + QVariantMap resultNode; + resultNode.insert("name", node->getName()); + resultNode.insert("type", "script"); + resultNode.insert("url", script->getFullPath()); + result.append(resultNode); + } + return result; +} + +QVariantList ScriptEngines::getPublic() { + return getPublicChildNodes(NULL); +} + +QVariantList ScriptEngines::getLocal() { + QVariantList result; + QList treeNodes = getScriptsModel().getFolderNodes(NULL); + for (int i = 0; i < treeNodes.size(); i++) { + TreeNodeBase* node = treeNodes.at(i); + if (node->getType() != TREE_NODE_TYPE_SCRIPT) { + continue; + } + TreeNodeScript* script = static_cast(node); + if (script->getOrigin() != ScriptOrigin::SCRIPT_ORIGIN_LOCAL) { + continue; + } + QVariantMap resultNode; + resultNode.insert("name", node->getName()); + resultNode.insert("path", script->getFullPath()); + result.append(resultNode); + } + return result; +} + +QVariantList ScriptEngines::getRunning() { + const int WINDOWS_DRIVE_LETTER_SIZE = 1; + QVariantList result; + auto runningScripts = getRunningScripts(); + foreach(const QString& runningScript, runningScripts) { + QUrl runningScriptURL = QUrl(runningScript); + if (runningScriptURL.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) { + runningScriptURL = QUrl::fromLocalFile(runningScriptURL.toDisplayString(QUrl::FormattingOptions(QUrl::FullyEncoded))); + } + QVariantMap resultNode; + resultNode.insert("name", runningScriptURL.fileName()); + resultNode.insert("url", runningScriptURL.toDisplayString(QUrl::FormattingOptions(QUrl::FullyEncoded))); + // The path contains the exact path/URL of the script, which also is used in the stopScript function. + resultNode.insert("path", runningScript); + resultNode.insert("local", runningScriptURL.isLocalFile()); + result.append(resultNode); + } + return result; +} + + +static const QString SETTINGS_KEY = "Settings"; +static const QString DEFAULT_SCRIPTS_JS_URL = "http://s3.amazonaws.com/hifi-public/scripts/defaultScripts.js"; + +void ScriptEngines::loadDefaultScripts() { + loadScript(DEFAULT_SCRIPTS_JS_URL); +} + +void ScriptEngines::loadOneScript(const QString& scriptFilename) { + loadScript(scriptFilename); +} + +void ScriptEngines::loadScripts() { + // check first run... + if (_firstRun.get()) { + qCDebug(scriptengine) << "This is a first run..."; + // clear the scripts, and set out script to our default scripts + clearScripts(); + loadDefaultScripts(); + _firstRun.set(false); + return; + } + + // loads all saved scripts + Settings settings; + int size = settings.beginReadArray(SETTINGS_KEY); + for (int i = 0; i < size; ++i) { + settings.setArrayIndex(i); + QString string = settings.value("script").toString(); + if (!string.isEmpty()) { + loadScript(string); + } + } + settings.endArray(); +} + +void ScriptEngines::clearScripts() { + // clears all scripts from the settingsSettings settings; + Settings settings; + settings.beginWriteArray(SETTINGS_KEY); + settings.remove(""); +} + +void ScriptEngines::saveScripts() { + // Saves all currently running user-loaded scripts + Settings settings; + settings.beginWriteArray(SETTINGS_KEY); + settings.remove(""); + + QStringList runningScripts = getRunningScripts(); + int i = 0; + for (auto it = runningScripts.begin(); it != runningScripts.end(); ++it) { + if (getScriptEngine(*it)->isUserLoaded()) { + settings.setArrayIndex(i); + settings.setValue("script", *it); + ++i; + } + } + settings.endArray(); +} + +QStringList ScriptEngines::getRunningScripts() { + QReadLocker lock(&_scriptEnginesHashLock); + return _scriptEnginesHash.keys(); +} + +void ScriptEngines::stopAllScripts(bool restart) { + QReadLocker lock(&_scriptEnginesHashLock); + if (restart) { + // Delete all running scripts from cache so that they are re-downloaded when they are restarted + auto scriptCache = DependencyManager::get(); + for (QHash::const_iterator it = _scriptEnginesHash.constBegin(); + it != _scriptEnginesHash.constEnd(); it++) { + if (!it.value()->isFinished()) { + scriptCache->deleteScript(it.key()); + } + } + } + + // Stop and possibly restart all currently running scripts + for (QHash::const_iterator it = _scriptEnginesHash.constBegin(); + it != _scriptEnginesHash.constEnd(); it++) { + if (it.value()->isFinished()) { + continue; + } + if (restart && it.value()->isUserLoaded()) { + connect(it.value(), &ScriptEngine::finished, this, [this](QString scriptName, ScriptEngine* engine) { + reloadScript(scriptName); + }); + } + QMetaObject::invokeMethod(it.value(), "stop"); + //it.value()->stop(); + qCDebug(scriptengine) << "stopping script..." << it.key(); + } +} + +bool ScriptEngines::stopScript(const QString& scriptHash, bool restart) { + bool stoppedScript = false; + { + QReadLocker lock(&_scriptEnginesHashLock); + if (_scriptEnginesHash.contains(scriptHash)) { + ScriptEngine* scriptEngine = _scriptEnginesHash[scriptHash]; + if (restart) { + auto scriptCache = DependencyManager::get(); + scriptCache->deleteScript(QUrl(scriptHash)); + connect(scriptEngine, &ScriptEngine::finished, this, [this](QString scriptName, ScriptEngine* engine) { + reloadScript(scriptName); + }); + } + scriptEngine->stop(); + stoppedScript = true; + qCDebug(scriptengine) << "stopping script..." << scriptHash; + } + } + return stoppedScript; +} + +QString ScriptEngines::getScriptsLocation() const { + return _scriptsLocationHandle.get(); +} + +void ScriptEngines::setScriptsLocation(const QString& scriptsLocation) { + _scriptsLocationHandle.set(scriptsLocation); + _scriptsModel.updateScriptsLocation(scriptsLocation); +} + +void ScriptEngines::reloadAllScripts() { + DependencyManager::get()->clearCache(); + emit scriptsReloading(); + stopAllScripts(true); +} + +ScriptEngine* ScriptEngines::loadScript(const QString& scriptFilename, bool isUserLoaded, bool loadScriptFromEditor, bool activateMainWindow, bool reload) { + if (thread() != QThread::currentThread()) { + ScriptEngine* result { nullptr }; + QMetaObject::invokeMethod(this, "loadScript", Qt::BlockingQueuedConnection, Q_RETURN_ARG(ScriptEngine*, result), + Q_ARG(QString, scriptFilename), + Q_ARG(bool, isUserLoaded), + Q_ARG(bool, loadScriptFromEditor), + Q_ARG(bool, activateMainWindow), + Q_ARG(bool, reload)); + return result; + } + QUrl scriptUrl(scriptFilename); + auto scriptEngine = getScriptEngine(scriptUrl.toString()); + if (scriptEngine) { + return scriptEngine; + } + + scriptEngine = new ScriptEngine(NO_SCRIPT, "", true); + scriptEngine->setUserLoaded(isUserLoaded); + + if (scriptFilename.isNull()) { + launchScriptEngine(scriptEngine); + } else { + // connect to the appropriate signals of this script engine + connect(scriptEngine, &ScriptEngine::scriptLoaded, this, &ScriptEngines::onScriptEngineLoaded); + connect(scriptEngine, &ScriptEngine::errorLoadingScript, this, &ScriptEngines::onScriptEngineError); + + // get the script engine object to load the script at the designated script URL + scriptEngine->loadURL(scriptUrl, reload); + } + + return scriptEngine; +} + +ScriptEngine* ScriptEngines::getScriptEngine(const QString& scriptHash) { + ScriptEngine* result = nullptr; + { + QReadLocker lock(&_scriptEnginesHashLock); + auto it = _scriptEnginesHash.find(scriptHash); + if (it != _scriptEnginesHash.end()) { + result = it.value(); + } + } + return result; +} + +// FIXME - change to new version of ScriptCache loading notification +void ScriptEngines::onScriptEngineLoaded(const QString& scriptFilename) { + UserActivityLogger::getInstance().loadedScript(scriptFilename); + ScriptEngine* scriptEngine = qobject_cast(sender()); + + launchScriptEngine(scriptEngine); + + { + QWriteLocker lock(&_scriptEnginesHashLock); + _scriptEnginesHash.insertMulti(scriptFilename, scriptEngine); + } + emit scriptCountChanged(); +} + +void ScriptEngines::launchScriptEngine(ScriptEngine* scriptEngine) { + connect(scriptEngine, &ScriptEngine::finished, this, &ScriptEngines::onScriptFinished, Qt::DirectConnection); + connect(scriptEngine, &ScriptEngine::loadScript, [&](const QString& scriptName, bool userLoaded) { + loadScript(scriptName, userLoaded); + }); + connect(scriptEngine, &ScriptEngine::reloadScript, [&](const QString& scriptName, bool userLoaded) { + loadScript(scriptName, userLoaded, false, false, true); + }); + + // register our application services and set it off on its own thread + for (auto initializer : _scriptInitializers) { + initializer(scriptEngine); + } + scriptEngine->runInThread(); +} + + +void ScriptEngines::onScriptFinished(const QString& scriptName, ScriptEngine* engine) { + bool removed = false; + { + QWriteLocker lock(&_scriptEnginesHashLock); + const QString& scriptURLString = QUrl(scriptName).toString(); + for (auto it = _scriptEnginesHash.find(scriptURLString); it != _scriptEnginesHash.end(); ++it) { + if (it.value() == engine) { + _scriptEnginesHash.erase(it); + removed = true; + break; + } + } + } + + if (removed) { + emit scriptCountChanged(); + } +} + +// FIXME - change to new version of ScriptCache loading notification +void ScriptEngines::onScriptEngineError(const QString& scriptFilename) { + qCDebug(scriptengine) << "Application::loadScript(), script failed to load..."; + emit scriptLoadError(scriptFilename, ""); +} + +QString ScriptEngines::getPreviousScriptLocation() const { + return _previousScriptLocation.get(); +} + +void ScriptEngines::setPreviousScriptLocation(const QString& previousScriptLocation) { + _previousScriptLocation.set(previousScriptLocation); +} diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h new file mode 100644 index 0000000000..6d78f3cfa0 --- /dev/null +++ b/libraries/script-engine/src/ScriptEngines.h @@ -0,0 +1,103 @@ +// +// Created by Bradley Austin Davis on 2016/01/08 +// Copyright 2013-2016 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_ScriptEngines_h +#define hifi_ScriptEngines_h + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "ScriptsModel.h" +#include "ScriptsModelFilter.h" + +class ScriptEngine; + +class ScriptEngines : public QObject, public Dependency { + Q_OBJECT + + Q_PROPERTY(ScriptsModel* scriptsModel READ scriptsModel CONSTANT) + Q_PROPERTY(ScriptsModelFilter* scriptsModelFilter READ scriptsModelFilter CONSTANT) + +public: + using ScriptInitializer = std::function; + + ScriptEngines(); + void registerScriptInitializer(ScriptInitializer initializer); + + void loadScripts(); + void saveScripts(); + void clearScripts(); + + QString getScriptsLocation() const; + void loadDefaultScripts(); + void setScriptsLocation(const QString& scriptsLocation); + QStringList getRunningScripts(); + ScriptEngine* getScriptEngine(const QString& scriptHash); + + QString getPreviousScriptLocation() const; + void setPreviousScriptLocation(const QString& previousScriptLocation); + + ScriptsModel* scriptsModel() { return &_scriptsModel; }; + ScriptsModelFilter* scriptsModelFilter() { return &_scriptsModelFilter; }; + + Q_INVOKABLE void loadOneScript(const QString& scriptFilename); + Q_INVOKABLE ScriptEngine* loadScript(const QString& scriptFilename = QString(), + bool isUserLoaded = true, bool loadScriptFromEditor = false, bool activateMainWindow = false, bool reload = false); + Q_INVOKABLE bool stopScript(const QString& scriptHash, bool restart = false); + + Q_INVOKABLE void reloadAllScripts(); + Q_INVOKABLE void stopAllScripts(bool restart = false); + + Q_INVOKABLE QVariantList getRunning(); + Q_INVOKABLE QVariantList getPublic(); + Q_INVOKABLE QVariantList getLocal(); + + // Called at shutdown time + void shutdownScripting(); + +signals: + void scriptCountChanged(); + void scriptsReloading(); + void scriptLoadError(const QString& filename, const QString& error); + +protected slots: + void onScriptFinished(const QString& fileNameString, ScriptEngine* engine); + +protected: + friend class ScriptEngine; + + void reloadScript(const QString& scriptName) { loadScript(scriptName, true, false, false, true); } + void addScriptEngine(ScriptEngine* engine); + void removeScriptEngine(ScriptEngine* engine); + void onScriptEngineLoaded(const QString& scriptFilename); + void onScriptEngineError(const QString& scriptFilename); + void launchScriptEngine(ScriptEngine* engine); + + + Setting::Handle _firstRun { "firstRun", true }; + QReadWriteLock _scriptEnginesHashLock; + QHash _scriptEnginesHash; + QSet _allKnownScriptEngines; + QMutex _allScriptsMutex; + std::atomic _stoppingAllScripts { false }; + std::list _scriptInitializers; + mutable Setting::Handle _scriptsLocationHandle; + mutable Setting::Handle _previousScriptLocation; + ScriptsModel _scriptsModel; + ScriptsModelFilter _scriptsModelFilter; +}; + +#endif // hifi_ScriptEngine_h diff --git a/interface/src/ScriptsModel.cpp b/libraries/script-engine/src/ScriptsModel.cpp similarity index 96% rename from interface/src/ScriptsModel.cpp rename to libraries/script-engine/src/ScriptsModel.cpp index a59d499863..07518dded1 100644 --- a/interface/src/ScriptsModel.cpp +++ b/libraries/script-engine/src/ScriptsModel.cpp @@ -1,7 +1,4 @@ // -// ScriptsModel.cpp -// interface/src -// // Created by Ryan Huffman on 05/12/14. // Copyright 2014 High Fidelity, Inc. // @@ -11,17 +8,21 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ScriptsModel.h" + #include #include #include #include -#include "Application.h" -#include "Menu.h" -#include "InterfaceLogging.h" +#include "ScriptEngine.h" +#include "ScriptEngines.h" +#include "ScriptEngineLogging.h" +#define __STR2__(x) #x +#define __STR1__(x) __STR2__(x) +#define __LOC__ __FILE__ "("__STR1__(__LINE__)") : Warning Msg: " -#include "ScriptsModel.h" static const QString S3_URL = "http://s3.amazonaws.com/hifi-public"; static const QString PUBLIC_URL = "http://public.highfidelity.io"; @@ -60,11 +61,8 @@ ScriptsModel::ScriptsModel(QObject* parent) : _localDirectory.setFilter(QDir::Files | QDir::Readable); _localDirectory.setNameFilters(QStringList("*.js")); - updateScriptsLocation(qApp->getScriptsLocation()); - + auto scriptEngines = DependencyManager::get(); connect(&_fsWatcher, &QFileSystemWatcher::directoryChanged, this, &ScriptsModel::reloadLocalFiles); - connect(qApp, &Application::scriptLocationChanged, this, &ScriptsModel::updateScriptsLocation); - reloadLocalFiles(); reloadRemoteFiles(); } @@ -182,7 +180,7 @@ void ScriptsModel::downloadFinished() { if (!data.isEmpty()) { finished = parseXML(data); } else { - qCDebug(interfaceapp) << "Error: Received no data when loading remote scripts"; + qCDebug(scriptengine) << "Error: Received no data when loading remote scripts"; } } @@ -231,7 +229,7 @@ bool ScriptsModel::parseXML(QByteArray xmlFile) { // Error handling if (xml.hasError()) { - qCDebug(interfaceapp) << "Error loading remote scripts: " << xml.errorString(); + qCDebug(scriptengine) << "Error loading remote scripts: " << xml.errorString(); return true; } diff --git a/interface/src/ScriptsModel.h b/libraries/script-engine/src/ScriptsModel.h similarity index 98% rename from interface/src/ScriptsModel.h rename to libraries/script-engine/src/ScriptsModel.h index ae75acfa3b..df9716d43b 100644 --- a/interface/src/ScriptsModel.h +++ b/libraries/script-engine/src/ScriptsModel.h @@ -92,6 +92,7 @@ protected: void rebuildTree(); private: + friend class ScriptEngines; bool _loadingScripts; QDir _localDirectory; QFileSystemWatcher _fsWatcher; diff --git a/interface/src/ScriptsModelFilter.cpp b/libraries/script-engine/src/ScriptsModelFilter.cpp similarity index 100% rename from interface/src/ScriptsModelFilter.cpp rename to libraries/script-engine/src/ScriptsModelFilter.cpp diff --git a/interface/src/ScriptsModelFilter.h b/libraries/script-engine/src/ScriptsModelFilter.h similarity index 100% rename from interface/src/ScriptsModelFilter.h rename to libraries/script-engine/src/ScriptsModelFilter.h From d1d178787c07a1022a25bd983441519905463303 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 11 Jan 2016 12:49:53 -0800 Subject: [PATCH 076/215] PR comments --- interface/src/Application.cpp | 23 +++++++++++++++++++ interface/src/Application.h | 3 ++- interface/src/ui/RunningScriptsWidget.cpp | 2 +- libraries/script-engine/src/ScriptEngines.cpp | 3 ++- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4f0b514827..b62f34630d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3449,6 +3449,29 @@ bool Application::isHMDMode() const { } float Application::getTargetFrameRate() { return getActiveDisplayPlugin()->getTargetFrameRate(); } +QRect Application::getDesirableApplicationGeometry() { + QRect applicationGeometry = getWindow()->geometry(); + + // If our parent window is on the HMD, then don't use its geometry, instead use + // the "main screen" geometry. + HMDToolsDialog* hmdTools = DependencyManager::get()->getHMDToolsDialog(); + if (hmdTools && hmdTools->hasHMDScreen()) { + QScreen* hmdScreen = hmdTools->getHMDScreen(); + QWindow* appWindow = getWindow()->windowHandle(); + QScreen* appScreen = appWindow->screen(); + + // if our app's screen is the hmd screen, we don't want to place the + // running scripts widget on it. So we need to pick a better screen. + // we will use the screen for the HMDTools since it's a guarenteed + // better screen. + if (appScreen == hmdScreen) { + QScreen* betterScreen = hmdTools->windowHandle()->screen(); + applicationGeometry = betterScreen->geometry(); + } + } + return applicationGeometry; +} + ///////////////////////////////////////////////////////////////////////////////////// // loadViewFrustum() // diff --git a/interface/src/Application.h b/interface/src/Application.h index 9237373778..9dd479bb5e 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -205,6 +205,7 @@ public: glm::mat4 getEyeOffset(int eye) const; glm::mat4 getEyeProjection(int eye) const; + QRect getDesirableApplicationGeometry(); Bookmarks* getBookmarks() const { return _bookmarks; } virtual bool canAcceptURL(const QString& url) const override; @@ -466,7 +467,7 @@ private: TouchEvent _lastTouchEvent; - RunningScriptsWidget* _runningScriptsWidget{ nullptr }; + RunningScriptsWidget* _runningScriptsWidget { nullptr }; quint64 _lastNackTime; quint64 _lastSendDownstreamAudioStats; diff --git a/interface/src/ui/RunningScriptsWidget.cpp b/interface/src/ui/RunningScriptsWidget.cpp index 483d467f01..1d2fe111f9 100644 --- a/interface/src/ui/RunningScriptsWidget.cpp +++ b/interface/src/ui/RunningScriptsWidget.cpp @@ -172,7 +172,7 @@ void RunningScriptsWidget::showEvent(QShowEvent* event) { ui->filterLineEdit->setFocus(); } - QRect parentGeometry = qApp->getWindow()->geometry(); + QRect parentGeometry = qApp->getDesirableApplicationGeometry(); int titleBarHeight = UIUtil::getWindowTitleBarHeight(this); int topMargin = titleBarHeight; diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index a7894f1816..293d798cd0 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -35,7 +35,8 @@ ScriptsModel& getScriptsModel() { ScriptEngines::ScriptEngines() : _scriptsLocationHandle("scriptsLocation", DESKTOP_LOCATION), - _previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION){ + _previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION) +{ _scriptsModelFilter.setSourceModel(&_scriptsModel); _scriptsModelFilter.sort(0, Qt::AscendingOrder); _scriptsModelFilter.setDynamicSortFilter(true); From e58f99c989a3b00219183c88dcb527790494a53e Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 11 Jan 2016 13:07:02 -0800 Subject: [PATCH 077/215] Ensure Oculus session is valid before base class activation --- plugins/oculus/src/OculusBaseDisplayPlugin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index d6811c3529..0be66bab67 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -78,7 +78,6 @@ void OculusBaseDisplayPlugin::deinit() { } void OculusBaseDisplayPlugin::activate() { - WindowOpenGLDisplayPlugin::activate(); if (!OVR_SUCCESS(ovr_Initialize(nullptr))) { qFatal("Could not init OVR"); } @@ -87,6 +86,8 @@ void OculusBaseDisplayPlugin::activate() { qFatal("Failed to acquire HMD"); } + WindowOpenGLDisplayPlugin::activate(); + _hmdDesc = ovr_GetHmdDesc(_session); _ipd = ovr_GetFloat(_session, OVR_KEY_IPD, _ipd); From 4ff2b85e1a87f14fb4cce2f80396c182aaec5722 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 11 Jan 2016 16:00:08 -0800 Subject: [PATCH 078/215] Replace ShapePipelineLib abstract with ShapePlumber instanced class --- .../render-utils/src/DeferredPipelineLib.cpp | 204 ------------------ .../render-utils/src/DeferredPipelineLib.h | 32 --- libraries/render-utils/src/Model.cpp | 12 +- libraries/render-utils/src/Model.h | 1 + .../render-utils/src/RenderDeferredTask.cpp | 169 ++++++++++++++- .../render-utils/src/RenderDeferredTask.h | 11 +- libraries/render/src/render/DrawTask.cpp | 6 +- libraries/render/src/render/DrawTask.h | 4 +- libraries/render/src/render/ShapePipeline.cpp | 128 ++++++----- libraries/render/src/render/ShapePipeline.h | 110 +++++++--- 10 files changed, 339 insertions(+), 338 deletions(-) delete mode 100644 libraries/render-utils/src/DeferredPipelineLib.cpp delete mode 100644 libraries/render-utils/src/DeferredPipelineLib.h diff --git a/libraries/render-utils/src/DeferredPipelineLib.cpp b/libraries/render-utils/src/DeferredPipelineLib.cpp deleted file mode 100644 index 70f8d13a07..0000000000 --- a/libraries/render-utils/src/DeferredPipelineLib.cpp +++ /dev/null @@ -1,204 +0,0 @@ -// -// DeferredPipelineLib.cpp -// render-utils/src -// -// Created by Zach Pomerantz on 1/4/2015. -// 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 "DeferredPipelineLib.h" - -#include - -#include - -#include "DeferredLightingEffect.h" - -#include "model_vert.h" -#include "model_shadow_vert.h" -#include "model_normal_map_vert.h" -#include "model_lightmap_vert.h" -#include "model_lightmap_normal_map_vert.h" -#include "skin_model_vert.h" -#include "skin_model_shadow_vert.h" -#include "skin_model_normal_map_vert.h" - -#include "model_frag.h" -#include "model_shadow_frag.h" -#include "model_normal_map_frag.h" -#include "model_normal_specular_map_frag.h" -#include "model_specular_map_frag.h" -#include "model_lightmap_frag.h" -#include "model_lightmap_normal_map_frag.h" -#include "model_lightmap_normal_specular_map_frag.h" -#include "model_lightmap_specular_map_frag.h" -#include "model_translucent_frag.h" - -DeferredPipelineLib::DeferredPipelineLib() { - if (!_isInitPipeline) { - initPipeline(); - } -} - -const DeferredPipelineLib::PipelinePointer DeferredPipelineLib::pickPipeline(RenderArgs* args, const Key& key) const { - PerformanceTimer perfTimer("DeferredPipelineLib::pickPipeline"); - - auto pipeline = _pickPipeline(args, key); - if (!pipeline) { - return pipeline; - } - - if ((pipeline->locations->normalFittingMapUnit > -1)) { - args->_batch->setResourceTexture(pipeline->locations->normalFittingMapUnit, - DependencyManager::get()->getNormalFittingTexture()); - } - - return pipeline; -} - -bool DeferredPipelineLib::_isInitPipeline { false }; - -void DeferredPipelineLib::initPipeline() { - assert(_pipelineLib.empty()); - - // Vertex shaders - auto modelVertex = gpu::Shader::createVertex(std::string(model_vert)); - auto modelNormalMapVertex = gpu::Shader::createVertex(std::string(model_normal_map_vert)); - auto modelLightmapVertex = gpu::Shader::createVertex(std::string(model_lightmap_vert)); - auto modelLightmapNormalMapVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert)); - auto modelShadowVertex = gpu::Shader::createVertex(std::string(model_shadow_vert)); - auto skinModelVertex = gpu::Shader::createVertex(std::string(skin_model_vert)); - auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert)); - auto skinModelShadowVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert)); - - // Pixel shaders - auto modelPixel = gpu::Shader::createPixel(std::string(model_frag)); - auto modelNormalMapPixel = gpu::Shader::createPixel(std::string(model_normal_map_frag)); - auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(model_specular_map_frag)); - auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_frag)); - auto modelTranslucentPixel = gpu::Shader::createPixel(std::string(model_translucent_frag)); - auto modelShadowPixel = gpu::Shader::createPixel(std::string(model_shadow_frag)); - auto modelLightmapPixel = gpu::Shader::createPixel(std::string(model_lightmap_frag)); - auto modelLightmapNormalMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag)); - auto modelLightmapSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag)); - auto modelLightmapNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag)); - - // Fill the pipelineLib - - _pipelineLib.addPipeline( - Key::Builder(), - modelVertex, modelPixel); - - _pipelineLib.addPipeline( - Key::Builder().withTangents(), - modelNormalMapVertex, modelNormalMapPixel); - - _pipelineLib.addPipeline( - Key::Builder().withSpecular(), - modelVertex, modelSpecularMapPixel); - - _pipelineLib.addPipeline( - Key::Builder().withTangents().withSpecular(), - modelNormalMapVertex, modelNormalSpecularMapPixel); - - - _pipelineLib.addPipeline( - Key::Builder().withTranslucent(), - modelVertex, modelTranslucentPixel); - // FIXME Ignore lightmap for translucents meshpart - _pipelineLib.addPipeline( - Key::Builder().withTranslucent().withLightmap(), - modelVertex, modelTranslucentPixel); - - _pipelineLib.addPipeline( - Key::Builder().withTangents().withTranslucent(), - modelNormalMapVertex, modelTranslucentPixel); - - _pipelineLib.addPipeline( - Key::Builder().withSpecular().withTranslucent(), - modelVertex, modelTranslucentPixel); - - _pipelineLib.addPipeline( - Key::Builder().withTangents().withSpecular().withTranslucent(), - modelNormalMapVertex, modelTranslucentPixel); - - - _pipelineLib.addPipeline( - Key::Builder().withLightmap(), - modelLightmapVertex, modelLightmapPixel); - - _pipelineLib.addPipeline( - Key::Builder().withLightmap().withTangents(), - modelLightmapNormalMapVertex, modelLightmapNormalMapPixel); - - _pipelineLib.addPipeline( - Key::Builder().withLightmap().withSpecular(), - modelLightmapVertex, modelLightmapSpecularMapPixel); - - _pipelineLib.addPipeline( - Key::Builder().withLightmap().withTangents().withSpecular(), - modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel); - - - _pipelineLib.addPipeline( - Key::Builder().withSkinned(), - skinModelVertex, modelPixel); - - _pipelineLib.addPipeline( - Key::Builder().withSkinned().withTangents(), - skinModelNormalMapVertex, modelNormalMapPixel); - - _pipelineLib.addPipeline( - Key::Builder().withSkinned().withSpecular(), - skinModelVertex, modelSpecularMapPixel); - - _pipelineLib.addPipeline( - Key::Builder().withSkinned().withTangents().withSpecular(), - skinModelNormalMapVertex, modelNormalSpecularMapPixel); - - - _pipelineLib.addPipeline( - Key::Builder().withSkinned().withTranslucent(), - skinModelVertex, modelTranslucentPixel); - - _pipelineLib.addPipeline( - Key::Builder().withSkinned().withTangents().withTranslucent(), - skinModelNormalMapVertex, modelTranslucentPixel); - - _pipelineLib.addPipeline( - Key::Builder().withSkinned().withSpecular().withTranslucent(), - skinModelVertex, modelTranslucentPixel); - - _pipelineLib.addPipeline( - Key::Builder().withSkinned().withTangents().withSpecular().withTranslucent(), - skinModelNormalMapVertex, modelTranslucentPixel); - - - _pipelineLib.addPipeline( - Key::Builder().withDepthOnly().withShadow(), - modelShadowVertex, modelShadowPixel); - - - _pipelineLib.addPipeline( - Key::Builder().withSkinned().withDepthOnly().withShadow(), - skinModelShadowVertex, modelShadowPixel); - - _isInitPipeline = true; -} - -model::MaterialPointer DeferredPipelineLib::_collisionHullMaterial; - -model::MaterialPointer DeferredPipelineLib::getCollisionHullMaterial() { - if (!_collisionHullMaterial) { - _collisionHullMaterial = std::make_shared(); - _collisionHullMaterial->setDiffuse(glm::vec3(1.0f, 0.5f, 0.0f)); - _collisionHullMaterial->setMetallic(0.02f); - _collisionHullMaterial->setGloss(1.0f); - } - - return _collisionHullMaterial; -} - diff --git a/libraries/render-utils/src/DeferredPipelineLib.h b/libraries/render-utils/src/DeferredPipelineLib.h deleted file mode 100644 index 4ea891c58c..0000000000 --- a/libraries/render-utils/src/DeferredPipelineLib.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// DeferredPipelineLib.h -// render-utils/src -// -// Created by Zach Pomerantz on 1/4/2015. -// 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_render_utils_DeferredPipelineLib_h -#define hifi_render_utils_DeferredPipelineLib_h - -#include -#include - -class DeferredPipelineLib : public render::ShapePipelineLib { -public: - DeferredPipelineLib(); - const PipelinePointer pickPipeline(RenderArgs* args, const Key& key) const override; - - static model::MaterialPointer getCollisionHullMaterial(); - -protected: - static bool _isInitPipeline; - static void initPipeline(); - - static model::MaterialPointer _collisionHullMaterial; -}; - -#endif // hifi_render_utils_DeferredPipelineLib_h diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 40352a1bc3..e2d0d02af7 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -22,7 +22,6 @@ #include #include "AbstractViewStateInterface.h" -#include "DeferredPipelineLib.h" #include "MeshPartPayload.h" #include "Model.h" @@ -36,6 +35,8 @@ static int vec3VectorTypeId = qRegisterMetaType >(); float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f; #define HTTP_INVALID_COM "http://invalid.com" +model::MaterialPointer Model::_collisionHullMaterial; + Model::Model(RigPointer rig, QObject* parent) : QObject(parent), _translation(0.0f), @@ -1194,8 +1195,13 @@ void Model::segregateMeshGroups() { int totalParts = mesh.parts.size(); for (int partIndex = 0; partIndex < totalParts; partIndex++) { if (showingCollisionHull) { - _renderItemsSet << std::make_shared(networkMesh._mesh, partIndex, DeferredPipelineLib::getCollisionHullMaterial(), transform, offset); - + if (!_collisionHullMaterial) { + _collisionHullMaterial = std::make_shared(); + _collisionHullMaterial->setDiffuse(glm::vec3(1.0f, 0.5f, 0.0f)); + _collisionHullMaterial->setMetallic(0.02f); + _collisionHullMaterial->setGloss(1.0f); + } + _renderItemsSet << std::make_shared(networkMesh._mesh, partIndex, _collisionHullMaterial, transform, offset); } else { _renderItemsSet << std::make_shared(this, i, partIndex, shapeID, transform, offset); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 3416a9b71e..157c6dbf70 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -347,6 +347,7 @@ protected: void recalculateMeshBoxes(bool pickAgainstTriangles = false); void segregateMeshGroups(); // used to calculate our list of translucent vs opaque meshes + static model::MaterialPointer _collisionHullMaterial; bool _meshGroupsKnown; bool _isWireframe; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index b68108d6f1..1ad0bb4abf 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -28,6 +28,26 @@ #include "AmbientOcclusionEffect.h" #include "AntialiasingEffect.h" +#include "model_vert.h" +#include "model_shadow_vert.h" +#include "model_normal_map_vert.h" +#include "model_lightmap_vert.h" +#include "model_lightmap_normal_map_vert.h" +#include "skin_model_vert.h" +#include "skin_model_shadow_vert.h" +#include "skin_model_normal_map_vert.h" + +#include "model_frag.h" +#include "model_shadow_frag.h" +#include "model_normal_map_frag.h" +#include "model_normal_specular_map_frag.h" +#include "model_specular_map_frag.h" +#include "model_lightmap_frag.h" +#include "model_lightmap_normal_map_frag.h" +#include "model_lightmap_normal_specular_map_frag.h" +#include "model_lightmap_specular_map_frag.h" +#include "model_translucent_frag.h" + #include "overlay3D_vert.h" #include "overlay3D_frag.h" @@ -35,6 +55,7 @@ using namespace render; +void initDeferredPipelines(render::ShapePlumber& plumber); void PrepareDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { DependencyManager::get()->prepare(renderContext->getArgs()); @@ -50,6 +71,15 @@ void ToneMappingDeferred::run(const SceneContextPointer& sceneContext, const Ren } RenderDeferredTask::RenderDeferredTask() : Task() { + // Prepare the ShapePipelines + ShapePlumberPointer shapePlumber = std::make_shared([](gpu::Batch& batch, ShapePipelinePointer pipeline) { + if ((pipeline->locations->normalFittingMapUnit > -1)) { + batch.setResourceTexture(pipeline->locations->normalFittingMapUnit, + DependencyManager::get()->getNormalFittingTexture()); + } + }); + initDeferredPipelines(*shapePlumber); + // CPU only, create the list of renderedOpaques items _jobs.push_back(Job(new FetchItems::JobModel("FetchOpaque", FetchItems([](const RenderContextPointer& context, int count) { @@ -75,7 +105,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _jobs.push_back(Job(new PrepareDeferred::JobModel("PrepareDeferred"))); // Render opaque objects in DeferredBuffer - _jobs.push_back(Job(new DrawOpaqueDeferred::JobModel("DrawOpaqueDeferred", renderedOpaques))); + _jobs.push_back(Job(new DrawOpaqueDeferred::JobModel("DrawOpaqueDeferred", renderedOpaques, DrawOpaqueDeferred(shapePlumber)))); // Once opaque is all rendered create stencil background _jobs.push_back(Job(new DrawStencilDeferred::JobModel("DrawOpaqueStencil"))); @@ -100,7 +130,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _antialiasingJobIndex = (int)_jobs.size() - 1; // Render transparent objects forward in LigthingBuffer - _jobs.push_back(Job(new DrawTransparentDeferred::JobModel("TransparentDeferred", renderedTransparents))); + _jobs.push_back(Job(new DrawTransparentDeferred::JobModel("TransparentDeferred", renderedTransparents, DrawTransparentDeferred(shapePlumber)))); // Lighting Buffer ready for tone mapping _jobs.push_back(Job(new ToneMappingDeferred::JobModel("ToneMapping"))); @@ -121,7 +151,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _drawStatusJobIndex = (int)_jobs.size() - 1; } - _jobs.push_back(Job(new DrawOverlay3D::JobModel("DrawOverlay3D"))); + _jobs.push_back(Job(new DrawOverlay3D::JobModel("DrawOverlay3D", DrawOverlay3D(shapePlumber)))); _jobs.push_back(Job(new HitEffect::JobModel("HitEffect"))); _jobs.back().setEnabled(false); @@ -193,7 +223,7 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - renderShapes(sceneContext, renderContext, _deferredPipelineLib, inItems, opaque.maxDrawn); + renderShapes(sceneContext, renderContext, _shapePlumber, inItems, opaque.maxDrawn); args->_batch = nullptr; }); } @@ -219,11 +249,12 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - renderShapes(sceneContext, renderContext, _deferredPipelineLib, inItems, transparent.maxDrawn); + renderShapes(sceneContext, renderContext, _shapePlumber, inItems, transparent.maxDrawn); args->_batch = nullptr; }); } +// TODO: Move this to the shapePlumber gpu::PipelinePointer DrawOverlay3D::_opaquePipeline; const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() { if (!_opaquePipeline) { @@ -292,7 +323,7 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon batch.setPipeline(getOpaquePipeline()); batch.setResourceTexture(0, args->_whiteTexture); - renderShapes(sceneContext, renderContext, _deferredPipelineLib, inItems, renderContext->getItemsConfig().overlay3D.maxDrawn); + renderShapes(sceneContext, renderContext, _shapePlumber, inItems, renderContext->getItemsConfig().overlay3D.maxDrawn); }); args->_batch = nullptr; args->_whiteTexture.reset(); @@ -485,3 +516,129 @@ int RenderDeferredTask::getToneMappingToneCurve() const { } } +void initDeferredPipelines(render::ShapePlumber& plumber) { + using Key = render::ShapeKey; + + // Vertex shaders + auto modelVertex = gpu::Shader::createVertex(std::string(model_vert)); + auto modelNormalMapVertex = gpu::Shader::createVertex(std::string(model_normal_map_vert)); + auto modelLightmapVertex = gpu::Shader::createVertex(std::string(model_lightmap_vert)); + auto modelLightmapNormalMapVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert)); + auto modelShadowVertex = gpu::Shader::createVertex(std::string(model_shadow_vert)); + auto skinModelVertex = gpu::Shader::createVertex(std::string(skin_model_vert)); + auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert)); + auto skinModelShadowVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert)); + + // Pixel shaders + auto modelPixel = gpu::Shader::createPixel(std::string(model_frag)); + auto modelNormalMapPixel = gpu::Shader::createPixel(std::string(model_normal_map_frag)); + auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(model_specular_map_frag)); + auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_frag)); + auto modelTranslucentPixel = gpu::Shader::createPixel(std::string(model_translucent_frag)); + auto modelShadowPixel = gpu::Shader::createPixel(std::string(model_shadow_frag)); + auto modelLightmapPixel = gpu::Shader::createPixel(std::string(model_lightmap_frag)); + auto modelLightmapNormalMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag)); + auto modelLightmapSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag)); + auto modelLightmapNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag)); + + // Fill the pipelineLib + + plumber.addPipeline( + Key::Builder(), + modelVertex, modelPixel); + + plumber.addPipeline( + Key::Builder().withTangents(), + modelNormalMapVertex, modelNormalMapPixel); + + plumber.addPipeline( + Key::Builder().withSpecular(), + modelVertex, modelSpecularMapPixel); + + plumber.addPipeline( + Key::Builder().withTangents().withSpecular(), + modelNormalMapVertex, modelNormalSpecularMapPixel); + + + plumber.addPipeline( + Key::Builder().withTranslucent(), + modelVertex, modelTranslucentPixel); + // FIXME Ignore lightmap for translucents meshpart + plumber.addPipeline( + Key::Builder().withTranslucent().withLightmap(), + modelVertex, modelTranslucentPixel); + + plumber.addPipeline( + Key::Builder().withTangents().withTranslucent(), + modelNormalMapVertex, modelTranslucentPixel); + + plumber.addPipeline( + Key::Builder().withSpecular().withTranslucent(), + modelVertex, modelTranslucentPixel); + + plumber.addPipeline( + Key::Builder().withTangents().withSpecular().withTranslucent(), + modelNormalMapVertex, modelTranslucentPixel); + + + plumber.addPipeline( + Key::Builder().withLightmap(), + modelLightmapVertex, modelLightmapPixel); + + plumber.addPipeline( + Key::Builder().withLightmap().withTangents(), + modelLightmapNormalMapVertex, modelLightmapNormalMapPixel); + + plumber.addPipeline( + Key::Builder().withLightmap().withSpecular(), + modelLightmapVertex, modelLightmapSpecularMapPixel); + + plumber.addPipeline( + Key::Builder().withLightmap().withTangents().withSpecular(), + modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel); + + + plumber.addPipeline( + Key::Builder().withSkinned(), + skinModelVertex, modelPixel); + + plumber.addPipeline( + Key::Builder().withSkinned().withTangents(), + skinModelNormalMapVertex, modelNormalMapPixel); + + plumber.addPipeline( + Key::Builder().withSkinned().withSpecular(), + skinModelVertex, modelSpecularMapPixel); + + plumber.addPipeline( + Key::Builder().withSkinned().withTangents().withSpecular(), + skinModelNormalMapVertex, modelNormalSpecularMapPixel); + + + plumber.addPipeline( + Key::Builder().withSkinned().withTranslucent(), + skinModelVertex, modelTranslucentPixel); + + plumber.addPipeline( + Key::Builder().withSkinned().withTangents().withTranslucent(), + skinModelNormalMapVertex, modelTranslucentPixel); + + plumber.addPipeline( + Key::Builder().withSkinned().withSpecular().withTranslucent(), + skinModelVertex, modelTranslucentPixel); + + plumber.addPipeline( + Key::Builder().withSkinned().withTangents().withSpecular().withTranslucent(), + skinModelNormalMapVertex, modelTranslucentPixel); + + + plumber.addPipeline( + Key::Builder().withDepthOnly(), + modelShadowVertex, modelShadowPixel); + + + plumber.addPipeline( + Key::Builder().withSkinned().withDepthOnly(), + skinModelShadowVertex, modelShadowPixel); +} + diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 171fe843da..b93cd0ec02 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -13,10 +13,10 @@ #define hifi_RenderDeferredTask_h #include "render/DrawTask.h" +#include "render/ShapePipeline.h" #include "gpu/Pipeline.h" -#include "DeferredPipelineLib.h" #include "ToneMappingEffect.h" class SetupDeferred { @@ -52,22 +52,24 @@ public: class DrawOpaqueDeferred { public: + DrawOpaqueDeferred(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems); typedef render::Job::ModelI JobModel; protected: - DeferredPipelineLib _deferredPipelineLib; + render::ShapePlumberPointer _shapePlumber; }; class DrawTransparentDeferred { public: + DrawTransparentDeferred(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems); typedef render::Job::ModelI JobModel; protected: - DeferredPipelineLib _deferredPipelineLib; + render::ShapePlumberPointer _shapePlumber; }; class DrawStencilDeferred { @@ -91,6 +93,7 @@ public: class DrawOverlay3D { public: + DrawOverlay3D(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} static const gpu::PipelinePointer& getOpaquePipeline(); void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); @@ -99,7 +102,7 @@ public: protected: static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable - DeferredPipelineLib _deferredPipelineLib; + render::ShapePlumberPointer _shapePlumber; }; class Blit { diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 27cd2011d8..4791324002 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -195,11 +195,11 @@ void render::renderLights(const SceneContextPointer& sceneContext, const RenderC } } -void renderShape(RenderArgs* args, const ShapePipelineLib& shapeContext, const Item& item) { +void renderShape(RenderArgs* args, const ShapePlumberPointer& shapeContext, const Item& item) { assert(item.getKey().isShape()); const auto& key = item.getShapeKey(); if (key.isValid() && !key.hasOwnPipeline()) { - args->_pipeline = shapeContext.pickPipeline(args, key); + args->_pipeline = shapeContext->pickPipeline(args, key); if (args->_pipeline) { item.render(args); } @@ -211,7 +211,7 @@ void renderShape(RenderArgs* args, const ShapePipelineLib& shapeContext, const I } void render::renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, - const ShapePipelineLib& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems) { + const ShapePlumberPointer& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems) { auto& scene = sceneContext->_scene; RenderArgs* args = renderContext->getArgs(); diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index ef9508365c..f2eb6920cf 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -134,7 +134,7 @@ public: Model() {} Model(const std::string& name): Concept(name) {} Model(Data data): _data(data) {} - Model(Data data, const std::string& name): Concept(name), _data(data) {} + Model(const std::string& name, Data data): Concept(name), _data(data) {} void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { if (isEnabled()) { @@ -222,7 +222,7 @@ typedef std::vector Jobs; void cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); void depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); void renderLights(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems); -void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePipelineLib& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); +void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); class FetchItems { diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index b766fb8695..4044750673 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -9,41 +9,67 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "DependencyManager.h" + #include "ShapePipeline.h" #include using namespace render; -ShapePipelineLib::PipelineLib ShapePipelineLib::_pipelineLib; - -void ShapePipelineLib::addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader) { - _pipelineLib.addPipeline(key, vertexShader, pixelShader); +ShapeKey::Filter::Builder::Builder() { + _mask.set(OWN_PIPELINE); + _mask.set(INVALID); } -const ShapePipelineLib::PipelinePointer ShapePipelineLib::_pickPipeline(RenderArgs* args, const Key& key) { - assert(!_pipelineLib.empty()); - assert(args); - assert(args->_batch); +void defaultStateSetter(ShapeKey key, gpu::State& state) { + // Cull backface + state.setCullMode(gpu::State::CULL_BACK); - PerformanceTimer perfTimer("ShapePipelineLib::getPipeline"); + // Z test depends on transparency + state.setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL); - const auto& pipelineIterator = _pipelineLib.find(key); - if (pipelineIterator == _pipelineLib.end()) { - qDebug() << "Couldn't find a pipeline from ShapeKey ?" << key; - return PipelinePointer(nullptr); + // Blend if transparent + state.setBlendFunction(key.isTranslucent(), + // For transparency, keep the highlight intensity + gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + // Add a wireframe version + if (!key.isWireFrame()) { + state.setFillMode(gpu::State::FILL_LINE); } - - PipelinePointer shapePipeline(pipelineIterator->second); - auto& batch = args->_batch; - - // Setup the one pipeline (to rule them all) - batch->setPipeline(shapePipeline->pipeline); - - return shapePipeline; } -void ShapePipelineLib::PipelineLib::addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader) { +void defaultBatchSetter(gpu::Batch& batch, ShapePipelinePointer pipeline) { +} + +ShapePlumber::ShapePlumber() : _stateSetter{ defaultStateSetter }, _batchSetter{ defaultBatchSetter } {} +ShapePlumber::ShapePlumber(BatchSetter batchSetter) : _stateSetter{ defaultStateSetter }, _batchSetter{ batchSetter } {} + +void ShapePlumber::addPipelineHelper(const Filter& filter, ShapeKey key, int bit, gpu::ShaderPointer program, LocationsPointer locations) { + // Iterate over all keys, toggling only bits set as significant in filter._mask + if (bit < (int)ShapeKey::FlagBit::NUM_FLAGS) { + addPipelineHelper(filter, key, ++bit, program, locations); + if (filter._mask[bit]) { + key._flags.flip(bit); + addPipelineHelper(filter, key, ++bit, program, locations); + } + } else { + auto state = std::make_shared(); + _stateSetter(key, *state); + + // Add the brand new pipeline and cache its location in the lib + auto pipeline = gpu::Pipeline::create(program, state); + _pipelineMap.insert(PipelineMap::value_type(key, std::make_shared(pipeline, locations))); + } +} + +void ShapePlumber::addPipeline(const Key& key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader) { + addPipeline(Filter{key}, vertexShader, pixelShader); +} + +void ShapePlumber::addPipeline(const Filter& filter, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader) { gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slot::SKINNING_GPU)); slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), Slot::MATERIAL_GPU)); @@ -69,37 +95,29 @@ void ShapePipelineLib::PipelineLib::addPipeline(Key key, gpu::ShaderPointer& ver locations->materialBufferUnit = program->getBuffers().findLocation("materialBuffer"); locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); - auto state = std::make_shared(); - - // Backface on shadow - if (key.isShadow()) { - state->setCullMode(gpu::State::CULL_FRONT); - state->setDepthBias(1.0f); - state->setDepthBiasSlopeScale(4.0f); - } else { - state->setCullMode(gpu::State::CULL_BACK); - } - - // Z test depends on transparency - state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL); - - // Blend if transparent - state->setBlendFunction(key.isTranslucent(), - gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, // For transparent only, this keep the highlight intensity - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - - // Add the brand new pipeline and cache its location in the lib - auto pipeline = gpu::Pipeline::create(program, state); - insert(value_type(key, std::make_shared(pipeline, locations))); - - // Add a wireframe version - if (!key.isWireFrame()) { - ShapeKey wireframeKey(ShapeKey::Builder(key).withWireframe()); - - auto wireframeState = std::make_shared(state->getValues()); - wireframeState->setFillMode(gpu::State::FILL_LINE); - - auto wireframePipeline = gpu::Pipeline::create(program, wireframeState); - insert(value_type(wireframeKey, std::make_shared(wireframePipeline, locations))); - } + ShapeKey key{filter._flags}; + addPipelineHelper(filter, key, 0, program, locations); +} + +const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Key& key) const { + assert(!_pipelineMap.empty()); + assert(args); + assert(args->_batch); + + PerformanceTimer perfTimer("ShapePlumber::pickPipeline"); + + const auto& pipelineIterator = _pipelineMap.find(key); + if (pipelineIterator == _pipelineMap.end()) { + qDebug() << "Couldn't find a pipeline from ShapeKey ?" << key; + return PipelinePointer(nullptr); + } + + PipelinePointer shapePipeline(pipelineIterator->second); + auto& batch = args->_batch; + _batchSetter(*batch, shapePipeline); + + // Setup the one pipeline (to rule them all) + batch->setPipeline(shapePipeline->pipeline); + + return shapePipeline; } diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index 1f293cfb93..04f9e0daa7 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -28,29 +28,26 @@ public: SKINNED, STEREO, DEPTH_ONLY, - SHADOW, WIREFRAME, OWN_PIPELINE, INVALID, - NUM_FLAGS, // Not a valid flag + NUM_FLAGS, // Not a valid flag }; using Flags = std::bitset; Flags _flags; - ShapeKey() : _flags{ 0 } {} - ShapeKey(const Flags& flags) : _flags(flags) {} + ShapeKey() : _flags{0} {} + ShapeKey(const Flags& flags) : _flags{flags} {} class Builder { - friend class ShapeKey; - Flags _flags{ 0 }; public: Builder() {} - Builder(ShapeKey key) : _flags{ key._flags } {} + Builder(ShapeKey key) : _flags{key._flags} {} - ShapeKey build() const { return ShapeKey(_flags); } + ShapeKey build() const { return ShapeKey{_flags}; } Builder& withTranslucent() { _flags.set(TRANSLUCENT); return (*this); } Builder& withLightmap() { _flags.set(LIGHTMAP); return (*this); } @@ -60,15 +57,70 @@ public: Builder& withSkinned() { _flags.set(SKINNED); return (*this); } Builder& withStereo() { _flags.set(STEREO); return (*this); } Builder& withDepthOnly() { _flags.set(DEPTH_ONLY); return (*this); } - Builder& withShadow() { _flags.set(SHADOW); return (*this); } Builder& withWireframe() { _flags.set(WIREFRAME); return (*this); } + Builder& withOwnPipeline() { _flags.set(OWN_PIPELINE); return (*this); } Builder& invalidate() { _flags.set(INVALID); return (*this); } static const ShapeKey ownPipeline() { return Builder().withOwnPipeline(); } static const ShapeKey invalid() { return Builder().invalidate(); } + + protected: + friend class ShapeKey; + Flags _flags{0}; + }; + ShapeKey(const Builder& builder) : ShapeKey{builder._flags} {} + + class Filter { + public: + Filter(Flags flags, Flags mask) : _flags{flags}, _mask{mask} {} + Filter(const ShapeKey& key) : _flags{ key._flags } { _mask.set(); } + + // Build a standard filter (will always exclude OWN_PIPELINE, INVALID) + class Builder { + public: + Builder(); + + Filter build() const { return Filter(_flags, _mask); } + + Builder& withOpaque() { _flags.reset(TRANSLUCENT); _mask.set(TRANSLUCENT); return (*this); } + Builder& withTranslucent() { _flags.set(TRANSLUCENT); _mask.set(TRANSLUCENT); return (*this); } + + Builder& withLightmap() { _flags.reset(LIGHTMAP); _mask.set(LIGHTMAP); return (*this); } + Builder& withoutLightmap() { _flags.set(LIGHTMAP); _mask.set(LIGHTMAP); return (*this); } + + Builder& withTangents() { _flags.reset(TANGENTS); _mask.set(TANGENTS); return (*this); } + Builder& withoutTangents() { _flags.set(TANGENTS); _mask.set(TANGENTS); return (*this); } + + Builder& withSpecular() { _flags.reset(SPECULAR); _mask.set(SPECULAR); return (*this); } + Builder& withoutSpecular() { _flags.set(SPECULAR); _mask.set(SPECULAR); return (*this); } + + Builder& withEmissive() { _flags.reset(EMISSIVE); _mask.set(EMISSIVE); return (*this); } + Builder& withoutEmissive() { _flags.set(EMISSIVE); _mask.set(EMISSIVE); return (*this); } + + Builder& withSkinned() { _flags.reset(SKINNED); _mask.set(SKINNED); return (*this); } + Builder& withoutSkinned() { _flags.set(SKINNED); _mask.set(SKINNED); return (*this); } + + Builder& withStereo() { _flags.reset(STEREO); _mask.set(STEREO); return (*this); } + Builder& withoutStereo() { _flags.set(STEREO); _mask.set(STEREO); return (*this); } + + Builder& withDepthOnly() { _flags.reset(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); } + Builder& withoutDepthOnly() { _flags.set(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); } + + Builder& withWireframe() { _flags.reset(WIREFRAME); _mask.set(WIREFRAME); return (*this); } + Builder& withoutWireframe() { _flags.set(WIREFRAME); _mask.set(WIREFRAME); return (*this); } + + protected: + friend class Filter; + Flags _flags{0}; + Flags _mask{0}; + }; + Filter(const Filter::Builder& builder) : Filter(builder._flags, builder._mask) {} + protected: + friend class ShapePlumber; + Flags _flags{0}; + Flags _mask{0}; }; - ShapeKey(const Builder& builder) : ShapeKey(builder._flags) {} bool hasLightmap() const { return _flags[LIGHTMAP]; } bool hasTangents() const { return _flags[TANGENTS]; } @@ -78,7 +130,6 @@ public: bool isSkinned() const { return _flags[SKINNED]; } bool isStereo() const { return _flags[STEREO]; } bool isDepthOnly() const { return _flags[DEPTH_ONLY]; } - bool isShadow() const { return _flags[SHADOW]; } bool isWireFrame() const { return _flags[WIREFRAME]; } bool hasOwnPipeline() const { return _flags[OWN_PIPELINE]; } @@ -113,7 +164,6 @@ inline QDebug operator<<(QDebug debug, const ShapeKey& renderKey) { << "isSkinned:" << renderKey.isSkinned() << "isStereo:" << renderKey.isStereo() << "isDepthOnly:" << renderKey.isDepthOnly() - << "isShadow:" << renderKey.isShadow() << "isWireFrame:" << renderKey.isWireFrame() << "]"; } @@ -124,6 +174,7 @@ inline QDebug operator<<(QDebug debug, const ShapeKey& renderKey) { } // Rendering abstraction over gpu::Pipeline and map locations +// Meta-information (pipeline and locations) to render a shape class ShapePipeline { public: class Slot { @@ -162,32 +213,33 @@ public: }; using ShapePipelinePointer = std::shared_ptr; -// Meta-information (pipeline and locations) to render a shape -class ShapePipelineLib { +class ShapePlumber { public: using Key = ShapeKey; + using Filter = Key::Filter; using Pipeline = ShapePipeline; using PipelinePointer = ShapePipelinePointer; - using Slot = ShapePipeline::Slot; - using Locations = ShapePipeline::Locations; + using PipelineMap = std::unordered_map; + using Slot = Pipeline::Slot; + using Locations = Pipeline::Locations; + using LocationsPointer = Pipeline::LocationsPointer; + using StateSetter = std::function; + using BatchSetter = std::function; - virtual ~ShapePipelineLib() = default; + ShapePlumber(); + explicit ShapePlumber(BatchSetter batchSetter); - static void addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader); - virtual const PipelinePointer pickPipeline(RenderArgs* args, const Key& key) const { - return ShapePipelineLib::_pickPipeline(args, key); - } + void addPipeline(const Key& key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader); + void addPipeline(const Filter& filter, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader); + const PipelinePointer pickPipeline(RenderArgs* args, const Key& key) const; protected: - using PipelineMap = std::unordered_map; - class PipelineLib : public PipelineMap { - public: - void addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader); - }; - - static PipelineLib _pipelineLib; - static const PipelinePointer _pickPipeline(RenderArgs* args, const Key& key); + void addPipelineHelper(const Filter& filter, Key key, int bit, gpu::ShaderPointer pipeline, LocationsPointer locations); + PipelineMap _pipelineMap; + StateSetter _stateSetter; + BatchSetter _batchSetter; }; +using ShapePlumberPointer = std::shared_ptr; } From b44ae3a19798b07f057c406cb9ffebf83fcbee2f Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 11 Jan 2016 16:55:45 -0800 Subject: [PATCH 079/215] avatar-animation.json: Updated right hand grasp animations --- .../defaultAvatar_full/avatar-animation.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index 19066e0ee8..4b12008bc3 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -198,9 +198,9 @@ "id": "rightHandOpen", "type": "clip", "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/open_variations.fbx", - "startFrame": 95.0, - "endFrame": 95.0, + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hand_variations.fbx", + "startFrame": 17.0, + "endFrame": 17.0, "timeScale": 1.0, "loopFlag": true }, @@ -210,9 +210,9 @@ "id": "rightHandGrasp", "type": "clip", "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_right.fbx", - "startFrame": 10.0, - "endFrame": 10.0, + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hand_variations.fbx", + "startFrame": 59.0, + "endFrame": 59.0, "timeScale": 1.0, "loopFlag": true }, @@ -234,9 +234,9 @@ "id": "rightHandFarGrasp", "type": "clip", "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/force_grab_right.fbx", - "startFrame": 12.0, - "endFrame": 35.0, + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hand_variations.fbx", + "startFrame": 49.0, + "endFrame": 49.0, "timeScale": 1.0, "loopFlag": true }, From db91b12203ab0fc0d342219b799e58f5d82b418f Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 11 Jan 2016 17:31:19 -0800 Subject: [PATCH 080/215] Refine addPipeline signature to be more explicit --- .../render-utils/src/RenderDeferredTask.cpp | 91 +++++++++++++------ libraries/render/src/render/ShapePipeline.cpp | 58 ++++-------- libraries/render/src/render/ShapePipeline.h | 27 +++--- 3 files changed, 94 insertions(+), 82 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index e533e2cb49..ddb8e928c5 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -74,12 +74,7 @@ void ToneMappingDeferred::run(const SceneContextPointer& sceneContext, const Ren RenderDeferredTask::RenderDeferredTask() : Task() { // Prepare the ShapePipelines - ShapePlumberPointer shapePlumber = std::make_shared([](gpu::Batch& batch, ShapePipelinePointer pipeline) { - if ((pipeline->locations->normalFittingMapUnit > -1)) { - batch.setResourceTexture(pipeline->locations->normalFittingMapUnit, - DependencyManager::get()->getNormalFittingTexture()); - } - }); + ShapePlumberPointer shapePlumber; initDeferredPipelines(*shapePlumber); // CPU only, create the list of renderedOpaques items @@ -513,8 +508,45 @@ int RenderDeferredTask::getToneMappingToneCurve() const { } } +void pipelineBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) { + if (pipeline.locations->normalFittingMapUnit > -1) { + batch.setResourceTexture(pipeline.locations->normalFittingMapUnit, + DependencyManager::get()->getNormalFittingTexture()); + } +} + void initDeferredPipelines(render::ShapePlumber& plumber) { using Key = render::ShapeKey; + using ShaderPointer = gpu::ShaderPointer; + + auto addPipeline = [&plumber](const Key& key, const ShaderPointer& vertexShader, const ShaderPointer& pixelShader) { + auto state = std::make_shared(); + + // Cull backface + state->setCullMode(gpu::State::CULL_BACK); + + // Z test depends on transparency + state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL); + + // Blend if transparent + state->setBlendFunction(key.isTranslucent(), + // For transparency, keep the highlight intensity + gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader); + plumber.addPipeline(key, program, state, &pipelineBatchSetter); + + // Add a wireframe version + if (!key.isWireFrame()) { + auto wireFrameKey = Key::Builder(key).withWireframe(); + auto wireFrameState = std::make_shared(state->getValues()); + + wireFrameState->setFillMode(gpu::State::FILL_LINE); + + plumber.addPipeline(wireFrameKey, program, wireFrameState, &pipelineBatchSetter); + } + }; // Vertex shaders auto modelVertex = gpu::Shader::createVertex(std::string(model_vert)); @@ -539,102 +571,101 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { auto modelLightmapNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag)); // Fill the pipelineLib - - plumber.addPipeline( + addPipeline( Key::Builder(), modelVertex, modelPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withTangents(), modelNormalMapVertex, modelNormalMapPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withSpecular(), modelVertex, modelSpecularMapPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withTangents().withSpecular(), modelNormalMapVertex, modelNormalSpecularMapPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withTranslucent(), modelVertex, modelTranslucentPixel); // FIXME Ignore lightmap for translucents meshpart - plumber.addPipeline( + addPipeline( Key::Builder().withTranslucent().withLightmap(), modelVertex, modelTranslucentPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withTangents().withTranslucent(), modelNormalMapVertex, modelTranslucentPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withSpecular().withTranslucent(), modelVertex, modelTranslucentPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withTangents().withSpecular().withTranslucent(), modelNormalMapVertex, modelTranslucentPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withLightmap(), modelLightmapVertex, modelLightmapPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withLightmap().withTangents(), modelLightmapNormalMapVertex, modelLightmapNormalMapPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withLightmap().withSpecular(), modelLightmapVertex, modelLightmapSpecularMapPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withLightmap().withTangents().withSpecular(), modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withSkinned(), skinModelVertex, modelPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withSkinned().withTangents(), skinModelNormalMapVertex, modelNormalMapPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withSkinned().withSpecular(), skinModelVertex, modelSpecularMapPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withSkinned().withTangents().withSpecular(), skinModelNormalMapVertex, modelNormalSpecularMapPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withSkinned().withTranslucent(), skinModelVertex, modelTranslucentPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withSkinned().withTangents().withTranslucent(), skinModelNormalMapVertex, modelTranslucentPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withSkinned().withSpecular().withTranslucent(), skinModelVertex, modelTranslucentPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withSkinned().withTangents().withSpecular().withTranslucent(), skinModelNormalMapVertex, modelTranslucentPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withDepthOnly(), modelShadowVertex, modelShadowPixel); - plumber.addPipeline( + addPipeline( Key::Builder().withSkinned().withDepthOnly(), skinModelShadowVertex, modelShadowPixel); } diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index 4044750673..5b89b6c6b7 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -22,54 +22,29 @@ ShapeKey::Filter::Builder::Builder() { _mask.set(INVALID); } -void defaultStateSetter(ShapeKey key, gpu::State& state) { - // Cull backface - state.setCullMode(gpu::State::CULL_BACK); - - // Z test depends on transparency - state.setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL); - - // Blend if transparent - state.setBlendFunction(key.isTranslucent(), - // For transparency, keep the highlight intensity - gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - - // Add a wireframe version - if (!key.isWireFrame()) { - state.setFillMode(gpu::State::FILL_LINE); - } -} - -void defaultBatchSetter(gpu::Batch& batch, ShapePipelinePointer pipeline) { -} - -ShapePlumber::ShapePlumber() : _stateSetter{ defaultStateSetter }, _batchSetter{ defaultBatchSetter } {} -ShapePlumber::ShapePlumber(BatchSetter batchSetter) : _stateSetter{ defaultStateSetter }, _batchSetter{ batchSetter } {} - -void ShapePlumber::addPipelineHelper(const Filter& filter, ShapeKey key, int bit, gpu::ShaderPointer program, LocationsPointer locations) { - // Iterate over all keys, toggling only bits set as significant in filter._mask +void ShapePlumber::addPipelineHelper(const Filter& filter, ShapeKey key, int bit, const PipelinePointer& pipeline) { + // Iterate over all keys if (bit < (int)ShapeKey::FlagBit::NUM_FLAGS) { - addPipelineHelper(filter, key, ++bit, program, locations); + ++bit; + addPipelineHelper(filter, key, bit, pipeline); if (filter._mask[bit]) { + // Toggle bits set as significant in filter._mask key._flags.flip(bit); - addPipelineHelper(filter, key, ++bit, program, locations); + addPipelineHelper(filter, key, bit, pipeline); } } else { - auto state = std::make_shared(); - _stateSetter(key, *state); - // Add the brand new pipeline and cache its location in the lib - auto pipeline = gpu::Pipeline::create(program, state); - _pipelineMap.insert(PipelineMap::value_type(key, std::make_shared(pipeline, locations))); + _pipelineMap.insert(PipelineMap::value_type(key, pipeline)); } } -void ShapePlumber::addPipeline(const Key& key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader) { - addPipeline(Filter{key}, vertexShader, pixelShader); +void ShapePlumber::addPipeline(const Key& key, const gpu::ShaderPointer& program, const gpu::StatePointer& state, + BatchSetter batchSetter) { + addPipeline(Filter{key}, program, state, batchSetter); } -void ShapePlumber::addPipeline(const Filter& filter, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader) { +void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& program, const gpu::StatePointer& state, + BatchSetter batchSetter) { gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slot::SKINNING_GPU)); slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), Slot::MATERIAL_GPU)); @@ -80,7 +55,6 @@ void ShapePlumber::addPipeline(const Filter& filter, gpu::ShaderPointer& vertexS slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Slot::LIGHT_BUFFER)); slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), Slot::NORMAL_FITTING_MAP)); - gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader); gpu::Shader::makeProgram(*program, slotBindings); auto locations = std::make_shared(); @@ -96,7 +70,9 @@ void ShapePlumber::addPipeline(const Filter& filter, gpu::ShaderPointer& vertexS locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); ShapeKey key{filter._flags}; - addPipelineHelper(filter, key, 0, program, locations); + auto gpuPipeline = gpu::Pipeline::create(program, state); + auto shapePipeline = std::make_shared(gpuPipeline, locations, batchSetter); + addPipelineHelper(filter, key, 0, shapePipeline); } const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Key& key) const { @@ -114,7 +90,9 @@ const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Ke PipelinePointer shapePipeline(pipelineIterator->second); auto& batch = args->_batch; - _batchSetter(*batch, shapePipeline); + + // Run the pipeline's BatchSetter on the passed in batch + shapePipeline->batchSetter(*shapePipeline, *batch); // Setup the one pipeline (to rule them all) batch->setPipeline(shapePipeline->pipeline); diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index 04f9e0daa7..3d189f15fa 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -204,12 +204,18 @@ public: }; using LocationsPointer = std::shared_ptr; + using BatchSetter = std::function; + + ShapePipeline(gpu::PipelinePointer pipeline, LocationsPointer locations, BatchSetter batchSetter) : + pipeline(pipeline), locations(locations), batchSetter(batchSetter) {} + gpu::PipelinePointer pipeline; std::shared_ptr locations; - ShapePipeline() : ShapePipeline(nullptr, nullptr) {} - ShapePipeline(gpu::PipelinePointer pipeline, std::shared_ptr locations) : - pipeline(pipeline), locations(locations) {} +protected: + friend class ShapePlumber; + + BatchSetter batchSetter; }; using ShapePipelinePointer = std::shared_ptr; @@ -223,21 +229,18 @@ public: using Slot = Pipeline::Slot; using Locations = Pipeline::Locations; using LocationsPointer = Pipeline::LocationsPointer; - using StateSetter = std::function; - using BatchSetter = std::function; + using BatchSetter = Pipeline::BatchSetter; - ShapePlumber(); - explicit ShapePlumber(BatchSetter batchSetter); + void addPipeline(const Key& key, const gpu::ShaderPointer& program, const gpu::StatePointer& state, + BatchSetter batchSetter = nullptr); + void addPipeline(const Filter& filter, const gpu::ShaderPointer& program, const gpu::StatePointer& state, + BatchSetter batchSetter = nullptr); - void addPipeline(const Key& key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader); - void addPipeline(const Filter& filter, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader); const PipelinePointer pickPipeline(RenderArgs* args, const Key& key) const; protected: - void addPipelineHelper(const Filter& filter, Key key, int bit, gpu::ShaderPointer pipeline, LocationsPointer locations); + void addPipelineHelper(const Filter& filter, Key key, int bit, const PipelinePointer& pipeline); PipelineMap _pipelineMap; - StateSetter _stateSetter; - BatchSetter _batchSetter; }; using ShapePlumberPointer = std::shared_ptr; From 40aecf3bf423c45ea17a229f310a302054b228ce Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 11 Jan 2016 17:36:12 -0800 Subject: [PATCH 081/215] I was told there would be no math --- examples/example/ui/energyBar.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/example/ui/energyBar.js b/examples/example/ui/energyBar.js index b0abf6778b..a45b09f6d4 100644 --- a/examples/example/ui/energyBar.js +++ b/examples/example/ui/energyBar.js @@ -54,12 +54,9 @@ function setEnergy(energy) { function avatarAccelerationEnergy() { var AVATAR_MOVEMENT_ENERGY_CONSTANT = 0.001; var velocity = MyAvatar.getVelocity(); - var dV = Vec3.subtract(velocity, lastAvatarVelocity); - var dE = Vec3.length(lastAvatarVelocity) * Vec3.length(dV) * AVATAR_MOVEMENT_ENERGY_CONSTANT; + var dV = Math.abs(Vec3.length(velocity) - Vec3.length(lastAvatarVelocity)); + var dE = Vec3.length(lastAvatarVelocity) * dV * AVATAR_MOVEMENT_ENERGY_CONSTANT; lastAvatarVelocity = velocity; - if (dE > 0.01) { - print("de " + dE); - } return dE; } From 3fdfa1b624580f9a9601558a1c6079cda0a424bf Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 11 Jan 2016 17:49:46 -0800 Subject: [PATCH 082/215] simpler loop --- examples/dropStuffNearMe.js | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/examples/dropStuffNearMe.js b/examples/dropStuffNearMe.js index 0b84490b4c..1c7c1f4f48 100644 --- a/examples/dropStuffNearMe.js +++ b/examples/dropStuffNearMe.js @@ -61,26 +61,25 @@ Script.setInterval(function () { } var numToCreate = RATE_PER_SECOND * (SCRIPT_INTERVAL / 1000.0); - for (var i = 0; i < numToCreate; i++) { + for (var i = 0; (i < numToCreate) && (totalCreated < NUMBER_TO_CREATE); i++) { var position = Vec3.sum(center, randomVector({ x: RANGE, y: RANGE, z: RANGE })); - if (totalCreated < NUMBER_TO_CREATE) { - Vec3.print("Position: ", position); - Entities.addEntity({ - type: TYPE, - modelURL: MODEL_URL, - name: "gridTest", - position: position, - dimensions: (TYPE == "Model") ? MODEL_DIMENSION : { x: SIZE, y: SIZE, z: SIZE }, - color: { red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255 }, - velocity: VELOCITY, - angularVelocity: Vec3.multiply(Math.random(), ANGULAR_VELOCITY), - damping: DAMPING, - angularDamping: ANGULAR_DAMPING, - gravity: (gravity ? GRAVITY : { x: 0, y: 0, z: 0}), - collisionsWillMove: collidable, - lifetime: LIFETIME - }); - } + + Vec3.print("Position: ", position); + Entities.addEntity({ + type: TYPE, + modelURL: MODEL_URL, + name: "gridTest", + position: position, + dimensions: (TYPE == "Model") ? MODEL_DIMENSION : { x: SIZE, y: SIZE, z: SIZE }, + color: { red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255 }, + velocity: VELOCITY, + angularVelocity: Vec3.multiply(Math.random(), ANGULAR_VELOCITY), + damping: DAMPING, + angularDamping: ANGULAR_DAMPING, + gravity: (gravity ? GRAVITY : { x: 0, y: 0, z: 0}), + collisionsWillMove: collidable, + lifetime: LIFETIME + }); totalCreated++; } From 74515f9089ad6b9c9860635c05f9c3a4a07a3a33 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 12 Jan 2016 16:09:40 +1300 Subject: [PATCH 083/215] Don't use cache when user loads script from disk --- 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 b62f34630d..90c5a353e3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4589,7 +4589,7 @@ void Application::loadDialog() { QString fileNameString = QFileDialog::getOpenFileName( _glWidget, tr("Open Script"), "", tr("JavaScript Files (*.js)")); if (!fileNameString.isEmpty()) { - DependencyManager::get()->loadScript(fileNameString); + DependencyManager::get()->loadScript(fileNameString, true, false, false, true); // Don't load from cache } } From c9e1d8f5f4a2100b081edb127cc45c274b249ac6 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 11 Jan 2016 19:10:29 -0800 Subject: [PATCH 084/215] Set up pipelinelib correctly (use filters insig bits) --- libraries/render/src/render/ShapePipeline.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index 5b89b6c6b7..99424cbf4b 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -25,12 +25,11 @@ ShapeKey::Filter::Builder::Builder() { void ShapePlumber::addPipelineHelper(const Filter& filter, ShapeKey key, int bit, const PipelinePointer& pipeline) { // Iterate over all keys if (bit < (int)ShapeKey::FlagBit::NUM_FLAGS) { - ++bit; - addPipelineHelper(filter, key, bit, pipeline); - if (filter._mask[bit]) { - // Toggle bits set as significant in filter._mask + addPipelineHelper(filter, key, bit + 1, pipeline); + if (!filter._mask[bit]) { + // Toggle bits set as insignificant in filter._mask key._flags.flip(bit); - addPipelineHelper(filter, key, bit, pipeline); + addPipelineHelper(filter, key, bit + 1, pipeline); } } else { // Add the brand new pipeline and cache its location in the lib From 016a14d3d507b2cb3a358dfd01ee0e90068babfc Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 11 Jan 2016 20:19:54 -0800 Subject: [PATCH 085/215] Init the shapePlumber --- libraries/render-utils/src/RenderDeferredTask.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index ddb8e928c5..ca25383a8d 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -74,7 +74,7 @@ void ToneMappingDeferred::run(const SceneContextPointer& sceneContext, const Ren RenderDeferredTask::RenderDeferredTask() : Task() { // Prepare the ShapePipelines - ShapePlumberPointer shapePlumber; + ShapePlumberPointer shapePlumber = std::make_shared(); initDeferredPipelines(*shapePlumber); // CPU only, create the list of renderedOpaques items From 92d63c48dd6503d6c5d3e0941e669831157ef7f5 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 12 Jan 2016 17:38:16 +1300 Subject: [PATCH 086/215] Resume Interface in 1st person if exited in 1st person --- 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 b62f34630d..575b5d2f17 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -878,7 +878,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _settingsTimer.setInterval(SAVE_SETTINGS_INTERVAL); _settingsThread.start(); - if (Menu::getInstance()->isOptionChecked(MenuOption::IndependentMode)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson)) { + getMyAvatar()->setBoomLength(MyAvatar::ZOOM_MIN); // So that camera doesn't auto-switch to third person. + } else if (Menu::getInstance()->isOptionChecked(MenuOption::IndependentMode)) { Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, true); cameraMenuChanged(); } From 71ed8d2a646e5aba76022f4c2463bae512a64888 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 12 Jan 2016 17:39:39 +1300 Subject: [PATCH 087/215] Change camera to first person if start up with it in camera entity mode Same as happens if start up with camera in independent mode. --- interface/src/Application.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 575b5d2f17..536db83d29 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -883,6 +883,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : } else if (Menu::getInstance()->isOptionChecked(MenuOption::IndependentMode)) { Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, true); cameraMenuChanged(); + } else if (Menu::getInstance()->isOptionChecked(MenuOption::CameraEntityMode)) { + Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, true); + cameraMenuChanged(); } // set the local loopback interface for local sounds from audio scripts From 5ec5ff9ad07f5b98ff798cdaab3f4d3606bb472f Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 12 Jan 2016 09:11:20 -0800 Subject: [PATCH 088/215] temporary fix to crash on startup --- interface/src/Application.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b62f34630d..f2059d103c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -615,8 +615,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : OffscreenUi::warning(nullptr, "Error Loading Script", filename + " failed to load."); }, Qt::QueuedConnection); - _runningScriptsWidget = new RunningScriptsWidget(_window); - #ifdef _WIN32 WSADATA WsaData; @@ -981,6 +979,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : connect(this, &Application::applicationStateChanged, this, &Application::activeChanged); + // FIXME -- NOTE: This will call ProcessEvents() which can cause authentication signals to fire, which + // if not logged in can cause the login dialog to appear. As currently implemented, the login requires + // the offscreen UI to render, so this needs to be well after OffscreenUi is available + _runningScriptsWidget = new RunningScriptsWidget(_window); + qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0); } From 5b9607ca29baa2dedd6cf636bc314dfb85778ca5 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 12 Jan 2016 10:36:59 -0800 Subject: [PATCH 089/215] fix merge --- interface/src/Application.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2af7f02972..087c6503d0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -448,8 +448,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _bookmarks = new Bookmarks(); // Before setting up the menu - _runningScriptsWidget = new RunningScriptsWidget(_window); - // start the nodeThread so its event loop is running QThread* nodeThread = new QThread(this); nodeThread->setObjectName("NodeList Thread"); From fee6bda7217a88b3d89cccc9b41b3df5c00a5d99 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 12 Jan 2016 12:18:26 -0800 Subject: [PATCH 090/215] Updated hand animation references. --- .../defaultAvatar_full/avatar-animation.json | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index 4b12008bc3..efd16576ee 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -198,9 +198,9 @@ "id": "rightHandOpen", "type": "clip", "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hand_variations.fbx", - "startFrame": 17.0, - "endFrame": 17.0, + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/search_right.fbx", + "startFrame": 0.0, + "endFrame": 0.0, "timeScale": 1.0, "loopFlag": true }, @@ -210,9 +210,9 @@ "id": "rightHandGrasp", "type": "clip", "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hand_variations.fbx", - "startFrame": 59.0, - "endFrame": 59.0, + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/grasp_right.fbx", + "startFrame": 0.0, + "endFrame": 0.0, "timeScale": 1.0, "loopFlag": true }, @@ -234,9 +234,9 @@ "id": "rightHandFarGrasp", "type": "clip", "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hand_variations.fbx", - "startFrame": 49.0, - "endFrame": 49.0, + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/far_grasp_right.fbx", + "startFrame": 0.0, + "endFrame": 0.0, "timeScale": 1.0, "loopFlag": true }, @@ -334,7 +334,7 @@ "type": "clip", "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_left.fbx", + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/search_left.fbx", "startFrame": 0.0, "endFrame": 0.0, "timeScale": 1.0, @@ -346,10 +346,9 @@ "id": "leftHandGrasp", "type": "clip", "data": { - - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_left.fbx", - "startFrame": 10.0, - "endFrame": 10.0, + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/grasp_left.fbx", + "startFrame": 0.0, + "endFrame": 0.0, "timeScale": 1.0, "loopFlag": true }, @@ -372,7 +371,7 @@ "type": "clip", "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_left.fbx", + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/far_grasp_left.fbx", "startFrame": 0.0, "endFrame": 0.0, "timeScale": 1.0, From 55af5eaf06c64e1bb041de74f96a1fc9adfa4c93 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 12 Jan 2016 12:40:02 -0800 Subject: [PATCH 091/215] Fix crash on shutdown due to lifetime of scripts --- libraries/script-engine/src/ScriptEngine.cpp | 3 --- libraries/script-engine/src/ScriptEngines.cpp | 11 ++++++++++- libraries/script-engine/src/ScriptEngines.h | 2 ++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index e997879391..a65fe7417d 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -171,9 +171,6 @@ void ScriptEngine::runInThread() { // when the thread is finished, add thread to the deleteLater queue connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater); - // when the thread is finished, add scriptEngine to the deleteLater queue - connect(workerThread, &QThread::finished, this, &ScriptEngine::deleteLater); - moveToThread(workerThread); // Starts an event loop, and emits workerThread->started() diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 293d798cd0..0a646bd696 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -112,6 +112,8 @@ void ScriptEngines::shutdownScripting() { scriptEngine->waitTillDoneRunning(); qCDebug(scriptengine) << "done waiting on script:" << scriptName; + scriptEngine->deleteLater(); + // If the script is stopped, we can remove it from our set i.remove(); } @@ -343,6 +345,10 @@ ScriptEngine* ScriptEngines::loadScript(const QString& scriptFilename, bool isUs scriptEngine = new ScriptEngine(NO_SCRIPT, "", true); scriptEngine->setUserLoaded(isUserLoaded); + connect(scriptEngine, &ScriptEngine::doneRunning, this, [scriptEngine] { + scriptEngine->deleteLater(); + }, Qt::QueuedConnection); + if (scriptFilename.isNull()) { launchScriptEngine(scriptEngine); @@ -431,5 +437,8 @@ QString ScriptEngines::getPreviousScriptLocation() const { } void ScriptEngines::setPreviousScriptLocation(const QString& previousScriptLocation) { - _previousScriptLocation.set(previousScriptLocation); + if (_previousScriptLocation.get() != previousScriptLocation) { + _previousScriptLocation.set(previousScriptLocation); + emit previousScriptLocationChanged(); + } } diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h index 6d78f3cfa0..97afe9ac57 100644 --- a/libraries/script-engine/src/ScriptEngines.h +++ b/libraries/script-engine/src/ScriptEngines.h @@ -30,6 +30,7 @@ class ScriptEngines : public QObject, public Dependency { Q_PROPERTY(ScriptsModel* scriptsModel READ scriptsModel CONSTANT) Q_PROPERTY(ScriptsModelFilter* scriptsModelFilter READ scriptsModelFilter CONSTANT) + Q_PROPERTY(QString previousScriptLocation READ getPreviousScriptLocation WRITE setPreviousScriptLocation NOTIFY previousScriptLocationChanged) public: using ScriptInitializer = std::function; @@ -72,6 +73,7 @@ signals: void scriptCountChanged(); void scriptsReloading(); void scriptLoadError(const QString& filename, const QString& error); + void previousScriptLocationChanged(); protected slots: void onScriptFinished(const QString& fileNameString, ScriptEngine* engine); From 21534cbde08c6a18b85fcd8e8d3cef6745ff9b38 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 11 Jan 2016 22:04:05 -0800 Subject: [PATCH 092/215] Layout for running scripts --- interface/resources/qml/Browser.qml | 18 +- interface/resources/qml/Global.js | 3 +- interface/resources/qml/Root.qml | 16 +- .../resources/qml/dialogs/RunningScripts.qml | 205 +++++++ .../resources/qml/windows/DefaultFrame.qml | 93 ++++ interface/resources/qml/windows/Frame.qml | 8 + interface/resources/qml/windows/Window.qml | 181 +++++++ interface/src/Application.cpp | 33 +- interface/src/Application.h | 2 - interface/src/ui/RunningScriptsWidget.cpp | 222 -------- interface/src/ui/RunningScriptsWidget.h | 56 -- interface/ui/runningScriptsWidget.ui | 511 ------------------ libraries/ui/src/OffscreenUi.cpp | 32 +- libraries/ui/src/OffscreenUi.h | 1 + libraries/ui/src/QmlWindowClass.cpp | 18 +- 15 files changed, 550 insertions(+), 849 deletions(-) create mode 100644 interface/resources/qml/dialogs/RunningScripts.qml create mode 100644 interface/resources/qml/windows/DefaultFrame.qml create mode 100644 interface/resources/qml/windows/Frame.qml create mode 100644 interface/resources/qml/windows/Window.qml delete mode 100644 interface/src/ui/RunningScriptsWidget.cpp delete mode 100644 interface/src/ui/RunningScriptsWidget.h delete mode 100644 interface/ui/runningScriptsWidget.ui diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index 8f3cd0e1e7..dc71eac1e7 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -1,18 +1,17 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 import QtWebEngine 1.1 + import "controls" import "styles" +import "windows" -VrDialog { +Window { id: root HifiConstants { id: hifi } title: "Browser" resizable: true - contentImplicitWidth: clientArea.implicitWidth - contentImplicitHeight: clientArea.implicitHeight - backgroundColor: "#7f000000" - + destroyOnInvisible: true Component.onCompleted: { enabled = true @@ -27,13 +26,8 @@ VrDialog { } Item { - id: clientArea - implicitHeight: 600 - implicitWidth: 800 - x: root.clientX - y: root.clientY - width: root.clientWidth - height: root.clientHeight + width: 800 + height: 600 Rectangle { anchors.left: parent.left diff --git a/interface/resources/qml/Global.js b/interface/resources/qml/Global.js index d41dde3c61..fadf6d6c71 100644 --- a/interface/resources/qml/Global.js +++ b/interface/resources/qml/Global.js @@ -40,7 +40,8 @@ function getTopLevelWindows(item) { for (var i = 0; i < desktop.children.length; ++i) { var child = desktop.children[i]; - if (Global.OFFSCREEN_WINDOW_OBJECT_NAME === child.objectName) { + if ((Global.OFFSCREEN_WINDOW_OBJECT_NAME === child.objectName) || + child[Global.OFFSCREEN_WINDOW_OBJECT_NAME]) { var windowId = child.toString(); currentWindows.push(child) } diff --git a/interface/resources/qml/Root.qml b/interface/resources/qml/Root.qml index 49262cb7db..247947b72c 100644 --- a/interface/resources/qml/Root.qml +++ b/interface/resources/qml/Root.qml @@ -1,13 +1,12 @@ -import Hifi 1.0 import QtQuick 2.5 import QtQuick.Controls 1.4 import "Global.js" as Global -// This is our primary 'window' object to which all dialogs and controls will -// be childed. -Root { - id: root +// This is our primary 'desktop' object to which all VR dialogs and +// windows will be childed. +Item { + id: desktop objectName: Global.OFFSCREEN_ROOT_OBJECT_NAME anchors.fill: parent; property var windows: []; @@ -16,11 +15,14 @@ Root { } onChildrenChanged: { - windows = Global.getTopLevelWindows(root); + windows = Global.getTopLevelWindows(desktop); } onParentChanged: { forceActiveFocus(); } -} + function raise(item) { + Global.raiseWindow(item); + } +} diff --git a/interface/resources/qml/dialogs/RunningScripts.qml b/interface/resources/qml/dialogs/RunningScripts.qml new file mode 100644 index 0000000000..1b25823fa7 --- /dev/null +++ b/interface/resources/qml/dialogs/RunningScripts.qml @@ -0,0 +1,205 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import Qt.labs.settings 1.0 + +import "../styles" as Hifi +import "../controls" as HifiControls +import "../windows" + +Window { + id: root + objectName: "RunningScripts" + title: "Running Scripts" + resizable: true + destroyOnInvisible: true + enabled: false + x: 40; y: 40 + + property var scripts: ScriptDiscoveryService; + property var scriptsModel: scripts.scriptsModelFilter + property var runningScriptsModel: ListModel { } + + Settings { + category: "Overlay.RunningScripts" + property alias x: root.x + property alias y: root.y + } + + Connections { + target: ScriptDiscoveryService + onScriptCountChanged: updateRunningScripts(); + } + + Component.onCompleted: updateRunningScripts() + + function updateRunningScripts() { + var runningScripts = ScriptDiscoveryService.getRunning(); + runningScriptsModel.clear() + for (var i = 0; i < runningScripts.length; ++i) { + runningScriptsModel.append(runningScripts[i]); + } + } + + function loadScript(script) { + console.log("Load script " + script); + scripts.loadOneScript(script); + } + + function reloadScript(script) { + console.log("Reload script " + script); + scripts.stopScript(script, true); + } + + function stopScript(script) { + console.log("Stop script " + script); + scripts.stopScript(script); + } + + function reloadAll() { + console.log("Reload all scripts"); + scripts.reloadAllScripts(); + } + + function stopAll() { + console.log("Stop all scripts"); + scripts.stopAllScripts(); + } + + Rectangle { + color: "white" + implicitWidth: 384; implicitHeight: 640 + + Item { + anchors { fill: parent; margins: 8 } + Text { + id: title + font.bold: true + font.pointSize: 16 + color: "#0e7077" + text: "Currently Running" + } + + Row { + id: allButtons + anchors.top: title.bottom + anchors.topMargin: 8 + spacing: 8 + Button { text: "Reload all"; onClicked: reloadAll() } + Button { text: "Stop all"; onClicked: stopAll() } + } + + ListView { + clip: true + anchors { + top: allButtons.bottom; + left: parent.left; + right: parent.right; + topMargin: 8 + bottom: row1.top + bottomMargin: 8 + } + + model: runningScriptsModel + + delegate: Rectangle { + radius: 3 + anchors { left: parent.left; right: parent.right } + + height: scriptName.height + 12 + color: index % 2 ? "#ddd" : "#eee" + + Text { + anchors { left: parent.left; leftMargin: 4; verticalCenter: parent.verticalCenter } + id: scriptName + text: name + } + + Row { + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: 4 + spacing: 4 + HifiControls.FontAwesome { + text: "\uf021"; size: scriptName.height; + MouseArea { + anchors { fill: parent; margins: -2; } + onClicked: reloadScript(model.url) + } + } + HifiControls.FontAwesome { + size: scriptName.height; text: "\uf00d" + MouseArea { + anchors { fill: parent; margins: -2; } + onClicked: stopScript(model.url) + } + } + } + } + } + + + Text { + id: loadLabel + text: "Load Scripts" + font.bold: true + font.pointSize: 16 + color: "#0e7077" + + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.bottom: filterEdit.top + anchors.bottomMargin: 8 + } + + Row { + id: row1 + spacing: 8 + anchors.bottom: filterEdit.top + anchors.bottomMargin: 8 + anchors.right: parent.right + Button { text: "from URL" } + Button { text: "from Disk" } + } + + TextField { + id: filterEdit + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: treeView.top + anchors.bottomMargin: 8 + placeholderText: "filter" + onTextChanged: scriptsModel.filterRegExp = new RegExp("^.*" + text + ".*$") + } + + TreeView { + id: treeView + height: 128 + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + headerVisible: false + focus: true + onClicked: { + console.log("treeview clicked " + scriptsModel.data(index, 0x100)) + } + + onDoubleClicked: { + console.log("treeview double clicked" + scriptsModel.data(index, 0x100)) + isExpanded(index) ? collapse(index) : expand(index) + } + + onActivated: { + console.log("treeview activated!" + index) + var path = scriptsModel.data(index, 0x100) + if (path) { + loadScript(path) + } + } + + model: scriptsModel + TableViewColumn { title: "Name"; role: "display"; } + } + } + } +} + diff --git a/interface/resources/qml/windows/DefaultFrame.qml b/interface/resources/qml/windows/DefaultFrame.qml new file mode 100644 index 0000000000..d810ea8c77 --- /dev/null +++ b/interface/resources/qml/windows/DefaultFrame.qml @@ -0,0 +1,93 @@ +import QtQuick 2.5 + +import "." +import "../controls" + +Frame { + id: root + anchors { margins: -16; topMargin: parent.closable ? -32 : -16; } + + + MouseArea { + id: controlsArea + anchors.fill: desktopControls + hoverEnabled: true + drag.target: root.parent + propagateComposedEvents: true + onClicked: { + root.raise() + mouse.accepted = false; + } + + MouseArea { + id: sizeDrag + enabled: root.parent.resizable + property int startX + property int startY + anchors.right: parent.right + anchors.bottom: parent.bottom + width: 16 + height: 16 + z: 1000 + hoverEnabled: true + onPressed: { + startX = mouseX + startY = mouseY + } + onPositionChanged: { + if (pressed) { + root.deltaSize((mouseX - startX), (mouseY - startY)) + startX = mouseX + startY = mouseY + } + } + } + } + + Rectangle { + id: desktopControls + // FIXME this doesn't work as expected + visible: root.parent.showFrame + anchors.fill: parent; + color: "#7f7f7f7f"; + radius: 3; + + + Row { + anchors.right: parent.right + anchors.top: parent.top + anchors.rightMargin: 4 + anchors.topMargin: 4 + spacing: 4 + FontAwesome { + visible: false + text: "\uf08d" + style: Text.Outline; styleColor: "white" + size: 16 + rotation: !root.parent ? 90 : root.parent.pinned ? 0 : 90 + color: root.pinned ? "red" : "black" + MouseArea { + anchors.fill: parent + propagateComposedEvents: true + onClicked: { root.pin(); mouse.accepted = false; } + } + } + + FontAwesome { + visible: root.parent.closable + text: closeClickArea.containsMouse ? "\uf057" : "\uf05c" + style: Text.Outline; + styleColor: "white" + color: closeClickArea.containsMouse ? "red" : "black" + size: 16 + MouseArea { + id: closeClickArea + anchors.fill: parent + hoverEnabled: true + onClicked: root.close(); + } + } + } + } +} + diff --git a/interface/resources/qml/windows/Frame.qml b/interface/resources/qml/windows/Frame.qml new file mode 100644 index 0000000000..cef2c5abc2 --- /dev/null +++ b/interface/resources/qml/windows/Frame.qml @@ -0,0 +1,8 @@ +import QtQuick 2.5 + +Item { + signal close() + signal pin() + signal raise() + signal deltaSize(real dx, real dy) +} diff --git a/interface/resources/qml/windows/Window.qml b/interface/resources/qml/windows/Window.qml new file mode 100644 index 0000000000..2e1f0e24d5 --- /dev/null +++ b/interface/resources/qml/windows/Window.qml @@ -0,0 +1,181 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtGraphicalEffects 1.0 +import "." +import "../styles" + +FocusScope { + id: window + objectName: "topLevelWindow" + HifiConstants { id: hifi } + implicitHeight: frame.height + implicitWidth: frame.width + + property bool topLevelWindow: true + property string title + property bool showFrame: true + property bool closable: true + property bool destroyOnInvisible: false + property bool destroyOnCloseButton: true + property bool pinned: false + property bool resizable: false + property real minX: 320 + property real minY: 240; + default property var content + property var frame: DefaultFrame { anchors.fill: content } + property var blur: FastBlur { anchors.fill: content; source: content; visible: false; radius: 0} + //property var hoverDetector: MouseArea { anchors.fill: frame; hoverEnabled: true; propagateComposedEvents: true; } + //property bool mouseInWindow: hoverDetector.containsMouse + children: [ frame, content, blur ] + signal windowDestroyed(); + + QtObject { + id: d + property vector2d minPosition: Qt.vector2d(0, 0); + property vector2d maxPosition: Qt.vector2d(100, 100); + + function clamp(value, min, max) { + return Math.min(Math.max(value, min), max); + } + + function updateParentRect() { +// if (!frame) { return; } +// console.log(window.parent.width); +// console.log(frame.width); +// minPosition = Qt.vector2d(-frame.anchors.leftMargin, -frame.anchors.topMargin); +// maxPosition = Qt.vector2d( +// Math.max(minPosition.x, Desktop.width - frame.width + minPosition.x), +// Math.max(minPosition.y, Desktop.height - frame.height + minPosition.y)) +// console.log(maxPosition); + } + + function keepOnScreen() { + //window.x = clamp(x, minPosition.x, maxPosition.x); + //window.y = clamp(y, minPosition.y, maxPosition.y); + } + + onMinPositionChanged: keepOnScreen(); + onMaxPositionChanged: keepOnScreen(); + } + + Component.onCompleted: { + d.updateParentRect(); + raise(); + } + + Component.onDestruction: { + console.log("Destroyed " + window); + windowDestroyed(); + } + + onParentChanged: { + d.updateParentRect(); + raise(); + } + + onFrameChanged: d.updateParentRect(); + onWidthChanged: d.updateParentRect(); + onHeightChanged: d.updateParentRect(); + onXChanged: d.keepOnScreen(); + onYChanged: d.keepOnScreen(); + + Connections { + target: frame + onRaise: window.raise(); + onClose: window.close(); + onPin: window.pin(); + onDeltaSize: { + console.log("deltaSize") + content.width = Math.max(content.width + dx, minX) + content.height = Math.max(content.height + dy, minY) + } + } + + + function raise() { + if (enabled && parent) { + Desktop.raise(window) + if (!focus) { + focus = true; + } + } + } + + function pin() { + pinned = ! pinned + } + + // our close function performs the same way as the OffscreenUI class: + // don't do anything but manipulate the enabled flag and let the other + // mechanisms decide if the window should be destroyed after the close + // animation completes + function close() { + if (destroyOnCloseButton) { + destroyOnInvisible = true + } + enabled = false; + } + + onEnabledChanged: { + if (!enabled) { + if (blur) { + blur.visible = true; + } + if (content) { + content.visible = false; + } + } + + opacity = enabled ? 1.0 : 0.0 + // If the dialog is initially invisible, setting opacity doesn't + // trigger making it visible. + if (enabled) { + visible = true; + raise(); + } + } + + // The offscreen UI will enable an object, rather than manipulating it's + // visibility, so that we can do animations in both directions. Because + // visibility and enabled are boolean flags, they cannot be animated. So when + // enabled is change, we modify a property that can be animated, like scale or + // opacity, and then when the target animation value is reached, we can + // modify the visibility + + // The actual animator + Behavior on opacity { + NumberAnimation { + duration: hifi.effects.fadeInDuration + easing.type: Easing.OutCubic + } + } + + // Once we're transparent, disable the dialog's visibility + onOpacityChanged: { + visible = (opacity != 0.0); + if (opacity == 1.0) { + content.visible = true; + blur.visible = false; + } + } + + // Some dialogs should be destroyed when they become + // invisible, so handle that + onVisibleChanged: { + if (!visible && destroyOnInvisible) { + console.log("Destroying " + window); + destroy(); + } + } + + Keys.onPressed: { + switch(event.key) { + case Qt.Key_W: + if (event.modifiers == Qt.ControlModifier) { + event.accepted = true + enabled = false + } + break; + } + } +} diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e0b595cfd9..adcf5d305b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1194,7 +1194,10 @@ void Application::initializeUi() { offscreenUi->create(_offscreenContext->getContext()); offscreenUi->setProxyWindow(_window->windowHandle()); offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/")); - offscreenUi->load("Root.qml"); + // OffscreenUi is a subclass of OffscreenQmlSurface specifically designed to + // support the window management and scripting proxies for VR use + offscreenUi->createDesktop(); + // FIXME either expose so that dialogs can set this themselves or // do better detection in the offscreen UI of what has focus offscreenUi->setNavigationFocused(false); @@ -1227,8 +1230,6 @@ void Application::initializeUi() { #endif rootContext->setContextProperty("Overlays", &_overlays); - rootContext->setContextProperty("Desktop", DependencyManager::get().data()); - rootContext->setContextProperty("Window", DependencyManager::get().data()); rootContext->setContextProperty("Menu", MenuScriptingInterface::getInstance()); rootContext->setContextProperty("Stats", Stats::getInstance()); @@ -4530,18 +4531,20 @@ bool Application::displayAvatarAttachmentConfirmationDialog(const QString& name) } void Application::toggleRunningScriptsWidget() { - if (_runningScriptsWidget->isVisible()) { - if (_runningScriptsWidget->hasFocus()) { - _runningScriptsWidget->hide(); - } else { - _runningScriptsWidget->raise(); - setActiveWindow(_runningScriptsWidget); - _runningScriptsWidget->setFocus(); - } - } else { - _runningScriptsWidget->show(); - _runningScriptsWidget->setFocus(); - } + static const QUrl url("dialogs/RunningScripts.qml"); + DependencyManager::get()->toggle(url, "RunningScripts"); + //if (_runningScriptsWidget->isVisible()) { + // if (_runningScriptsWidget->hasFocus()) { + // _runningScriptsWidget->hide(); + // } else { + // _runningScriptsWidget->raise(); + // setActiveWindow(_runningScriptsWidget); + // _runningScriptsWidget->setFocus(); + // } + //} else { + // _runningScriptsWidget->show(); + // _runningScriptsWidget->setFocus(); + //} } void Application::packageModel() { diff --git a/interface/src/Application.h b/interface/src/Application.h index 9dd479bb5e..38b4a8845c 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -61,7 +61,6 @@ #include "ui/OctreeStatsDialog.h" #include "ui/OverlayConductor.h" #include "ui/overlays/Overlays.h" -#include "ui/RunningScriptsWidget.h" #include "ui/SnapshotShareDialog.h" #include "ui/ToolWindow.h" #include "UndoStackScriptingInterface.h" @@ -467,7 +466,6 @@ private: TouchEvent _lastTouchEvent; - RunningScriptsWidget* _runningScriptsWidget { nullptr }; quint64 _lastNackTime; quint64 _lastSendDownstreamAudioStats; diff --git a/interface/src/ui/RunningScriptsWidget.cpp b/interface/src/ui/RunningScriptsWidget.cpp deleted file mode 100644 index 1d2fe111f9..0000000000 --- a/interface/src/ui/RunningScriptsWidget.cpp +++ /dev/null @@ -1,222 +0,0 @@ -// -// RunningScriptsWidget.cpp -// interface/src/ui -// -// Created by Mohammed Nafees on 03/28/2014. -// Updated by Ryan Huffman on 05/13/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 "ui_runningScriptsWidget.h" -#include "RunningScriptsWidget.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "Application.h" -#include "MainWindow.h" -#include "Menu.h" -#include "ScriptsModel.h" -#include "UIUtil.h" - -RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) : - QWidget(parent, Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | - Qt::WindowCloseButtonHint), - ui(new Ui::RunningScriptsWidget), - _reloadSignalMapper(this), - _stopSignalMapper(this) { - ui->setupUi(this); - - setAttribute(Qt::WA_DeleteOnClose, false); - - ui->filterLineEdit->installEventFilter(this); - - auto scriptEngines = DependencyManager::get().data(); - connect(scriptEngines->scriptsModelFilter(), &QSortFilterProxyModel::modelReset, - this, &RunningScriptsWidget::selectFirstInList); - - // FIXME: menu isn't prepared at this point. - //QString shortcutText = Menu::getInstance()->getActionForOption(MenuOption::ReloadAllScripts)->shortcut().toString(QKeySequence::NativeText); - //ui->tipLabel->setText("Tip: Use " + shortcutText + " to reload all scripts."); - ui->scriptTreeView->setModel(scriptEngines->scriptsModelFilter()); - - connect(ui->filterLineEdit, &QLineEdit::textChanged, this, &RunningScriptsWidget::updateFileFilter); - connect(ui->scriptTreeView, &QTreeView::doubleClicked, this, &RunningScriptsWidget::loadScriptFromList); - - connect(ui->reloadAllButton, &QPushButton::clicked, scriptEngines, &ScriptEngines::reloadAllScripts); - connect(ui->stopAllButton, &QPushButton::clicked, scriptEngines, &ScriptEngines::stopAllScripts); - connect(ui->loadScriptFromDiskButton, &QPushButton::clicked, qApp, &Application::loadDialog); - connect(ui->loadScriptFromURLButton, &QPushButton::clicked, qApp, &Application::loadScriptURLDialog); - connect(&_reloadSignalMapper, static_cast(&QSignalMapper::mapped), - [scriptEngines](const QString& scriptName) { scriptEngines->stopScript(scriptName, true); }); - connect(&_stopSignalMapper, static_cast(&QSignalMapper::mapped), - [scriptEngines](const QString& scriptName) { scriptEngines->stopScript(scriptName); }); - - setRunningScripts(scriptEngines->getRunningScripts()); - connect(scriptEngines, &ScriptEngines::scriptCountChanged, scriptEngines, [this, scriptEngines] { - setRunningScripts(scriptEngines->getRunningScripts()); - }, Qt::QueuedConnection); - UIUtil::scaleWidgetFontSizes(this); -} - -RunningScriptsWidget::~RunningScriptsWidget() { - delete ui; -} - -void RunningScriptsWidget::updateFileFilter(const QString& filter) { - QRegExp regex("^.*" + QRegExp::escape(filter) + ".*$", Qt::CaseInsensitive); - DependencyManager::get()->scriptsModelFilter()->setFilterRegExp(regex); - selectFirstInList(); -} - -void RunningScriptsWidget::loadScriptFromList(const QModelIndex& index) { - auto scriptEngines = DependencyManager::get(); - QVariant scriptFile = scriptEngines->scriptsModelFilter()->data(index, ScriptsModel::ScriptPath); - scriptEngines->loadScript(scriptFile.toString()); -} - -void RunningScriptsWidget::loadSelectedScript() { - QModelIndex selectedIndex = ui->scriptTreeView->currentIndex(); - if (selectedIndex.isValid()) { - loadScriptFromList(selectedIndex); - } -} - -void RunningScriptsWidget::setRunningScripts(const QStringList& list) { - setUpdatesEnabled(false); - QLayoutItem* widget; - while ((widget = ui->scriptListWidget->layout()->takeAt(0)) != NULL) { - delete widget->widget(); - delete widget; - } - QHash hash; - const int CLOSE_ICON_HEIGHT = 12; - for (int i = 0; i < list.size(); i++) { - if (!hash.contains(list.at(i))) { - hash.insert(list.at(i), 1); - } - QWidget* row = new QWidget(ui->scriptListWidget); - row->setFont(ui->scriptListWidget->font()); - row->setLayout(new QHBoxLayout(row)); - - QUrl url = QUrl(list.at(i)); - QLabel* name = new QLabel(url.fileName(), row); - if (hash.find(list.at(i)).value() != 1) { - name->setText(name->text() + "(" + QString::number(hash.find(list.at(i)).value()) + ")"); - } - ++hash[list.at(i)]; - - QPushButton* reloadButton = new QPushButton(row); - reloadButton->setFlat(true); - reloadButton->setIcon( - QIcon(QPixmap(PathUtils::resourcesPath() + "images/reload-script.svg").scaledToHeight(CLOSE_ICON_HEIGHT))); - reloadButton->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred)); - reloadButton->setStyleSheet("border: 0;"); - reloadButton->setCursor(Qt::PointingHandCursor); - connect(reloadButton, SIGNAL(clicked()), &_reloadSignalMapper, SLOT(map())); - _reloadSignalMapper.setMapping(reloadButton, url.toString()); - - QPushButton* closeButton = new QPushButton(row); - closeButton->setFlat(true); - closeButton->setIcon( - QIcon(QPixmap(PathUtils::resourcesPath() + "images/kill-script.svg").scaledToHeight(CLOSE_ICON_HEIGHT))); - closeButton->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred)); - closeButton->setStyleSheet("border: 0;"); - closeButton->setCursor(Qt::PointingHandCursor); - connect(closeButton, SIGNAL(clicked()), &_stopSignalMapper, SLOT(map())); - _stopSignalMapper.setMapping(closeButton, url.toString()); - - row->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); - - row->layout()->setContentsMargins(4, 4, 4, 4); - row->layout()->setSpacing(0); - - row->layout()->addWidget(name); - row->layout()->addWidget(reloadButton); - row->layout()->addWidget(closeButton); - - row->setToolTip(url.toString()); - - QFrame* line = new QFrame(row); - line->setFrameShape(QFrame::HLine); - line->setStyleSheet("color: #E1E1E1; margin-left: 6px; margin-right: 6px;"); - - ui->scriptListWidget->layout()->addWidget(row); - ui->scriptListWidget->layout()->addWidget(line); - } - - - ui->noRunningScriptsLabel->setVisible(list.isEmpty()); - ui->reloadAllButton->setVisible(!list.isEmpty()); - ui->stopAllButton->setVisible(!list.isEmpty()); - - ui->scriptListWidget->updateGeometry(); - setUpdatesEnabled(true); - Application::processEvents(); - repaint(); -} - -void RunningScriptsWidget::showEvent(QShowEvent* event) { - if (!event->spontaneous()) { - ui->filterLineEdit->setFocus(); - } - - QRect parentGeometry = qApp->getDesirableApplicationGeometry(); - int titleBarHeight = UIUtil::getWindowTitleBarHeight(this); - int topMargin = titleBarHeight; - - setGeometry(parentGeometry.topLeft().x(), parentGeometry.topLeft().y() + topMargin, - size().width(), parentWidget()->height() - topMargin); - - QWidget::showEvent(event); -} - -void RunningScriptsWidget::selectFirstInList() { - auto model = DependencyManager::get()->scriptsModelFilter(); - if (model->rowCount() > 0) { - ui->scriptTreeView->setCurrentIndex(model->index(0, 0)); - } -} - -bool RunningScriptsWidget::eventFilter(QObject* sender, QEvent* event) { - if (sender == ui->filterLineEdit) { - if (event->type() != QEvent::KeyPress) { - return false; - } - QKeyEvent* keyEvent = static_cast(event); - if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { - QModelIndex selectedIndex = ui->scriptTreeView->currentIndex(); - if (selectedIndex.isValid()) { - loadScriptFromList(selectedIndex); - } - event->accept(); - return true; - } - return false; - } - - return QWidget::eventFilter(sender, event); -} - -void RunningScriptsWidget::keyPressEvent(QKeyEvent *keyEvent) { - if (keyEvent->key() == Qt::Key_Escape) { - return; - } else { - QWidget::keyPressEvent(keyEvent); - } -} - -void RunningScriptsWidget::allScriptsStopped() { - DependencyManager::get()->stopAllScripts(); -} diff --git a/interface/src/ui/RunningScriptsWidget.h b/interface/src/ui/RunningScriptsWidget.h deleted file mode 100644 index b60586b5e7..0000000000 --- a/interface/src/ui/RunningScriptsWidget.h +++ /dev/null @@ -1,56 +0,0 @@ -// -// RunningScriptsWidget.h -// interface/src/ui -// -// Created by Mohammed Nafees on 03/28/2014. -// Updated by Ryan Huffman on 05/13/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_RunningScriptsWidget_h -#define hifi_RunningScriptsWidget_h - -#include -#include -#include - -#include "ScriptsModel.h" -#include "ScriptsModelFilter.h" -#include "ScriptsTableWidget.h" - -namespace Ui { - class RunningScriptsWidget; -} - -class RunningScriptsWidget : public QWidget { - Q_OBJECT -public: - explicit RunningScriptsWidget(QWidget* parent = NULL); - ~RunningScriptsWidget(); - - void setRunningScripts(const QStringList& list); - -protected: - virtual bool eventFilter(QObject* sender, QEvent* event); - - virtual void keyPressEvent(QKeyEvent* event); - virtual void showEvent(QShowEvent* event); - -private slots: - void allScriptsStopped(); - void updateFileFilter(const QString& filter); - void loadScriptFromList(const QModelIndex& index); - void loadSelectedScript(); - void selectFirstInList(); - -private: - Ui::RunningScriptsWidget* ui; - QSignalMapper _reloadSignalMapper; - QSignalMapper _stopSignalMapper; - QVariantList getPublicChildNodes(TreeNodeFolder* parent); -}; - -#endif // hifi_RunningScriptsWidget_h diff --git a/interface/ui/runningScriptsWidget.ui b/interface/ui/runningScriptsWidget.ui deleted file mode 100644 index d2484662c4..0000000000 --- a/interface/ui/runningScriptsWidget.ui +++ /dev/null @@ -1,511 +0,0 @@ - - - RunningScriptsWidget - - - - 0 - 0 - 364 - 728 - - - - - Helvetica,Arial,sans-serif - 13 - - - - Running Scripts - - - * { font-family: Helvetica, Arial, sans-serif; } - - - - - - - 0 - 0 - - - - - 0 - 141 - - - - - Helvetica,Arial,sans-serif - 13 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - - - 6 - - - 0 - - - 6 - - - 0 - - - - - - Helvetica,Arial,sans-serif - 16 - 75 - false - true - - - - color: #0e7077; -font: bold 16pt; - - - - Currently Running - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Minimum - - - - 0 - 4 - - - - - - - - - 0 - 0 - - - - - Helvetica,Arial,sans-serif - 13 - - - - reloadStopButtonArea { padding: 0 } - - - - 6 - - - 0 - - - 6 - - - 0 - - - - - - Helvetica,Arial,sans-serif - 13 - - - - Reload all - - - - - - - - Helvetica,Arial,sans-serif - 13 - - - - Stop all - - - - - - - Qt::Horizontal - - - - 0 - 0 - - - - - - - - - - - - 0 - 0 - - - - - Helvetica,Arial,sans-serif - 13 - - - - - 0 - - - 6 - - - 0 - - - 6 - - - 0 - - - - - - 0 - 0 - - - - - Helvetica,Arial,sans-serif - 14 - - - - color: #5f5f5f; margin: 2px; - - - There are no scripts running. - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - - 0 - 0 - - - - - Helvetica,Arial,sans-serif - 14 - - - - Qt::LeftToRight - - - QFrame::NoFrame - - - 0 - - - Qt::ScrollBarAsNeeded - - - Qt::ScrollBarAlwaysOff - - - QAbstractScrollArea::AdjustToContents - - - true - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - 0 - 0 - 328 - 18 - - - - - 0 - 0 - - - - - Helvetica,Arial,sans-serif - 14 - - - - Qt::LeftToRight - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - Helvetica,Arial,sans-serif - 14 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - - - - - - - - 0 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 0 - - - 6 - - - 6 - - - 6 - - - 6 - - - - - color: #0e7077; -font: bold 16pt; - - - Load Scripts - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - from URL - - - - - - - from Disk - - - - - - - - - - - 6 - - - 0 - - - 6 - - - 0 - - - - - - - - filter - - - true - - - - - - - - 0 - 0 - - - - Qt::ScrollBarAlwaysOn - - - Qt::ScrollBarAlwaysOff - - - true - - - false - - - - - - - - - - - - - - diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 67e6b089d6..489fd87112 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -16,19 +16,14 @@ #include #include + #include "ErrorDialog.h" #include "MessageDialog.h" -class OffscreenUiRoot : public QQuickItem { - Q_OBJECT -public: - - OffscreenUiRoot(QQuickItem* parent = 0); - Q_INVOKABLE void information(const QString& title, const QString& text); - Q_INVOKABLE void loadChild(const QUrl& url) { - DependencyManager::get()->load(url); - } -}; +// Needs to match the constants in resources/qml/Global.js +static const QString OFFSCREEN_ROOT_OBJECT_NAME = "desktopRoot"; +static const QString OFFSCREEN_WINDOW_OBJECT_NAME = "topLevelWindow"; +static QQuickItem* _desktop { nullptr }; class OffscreenFlags : public QObject { Q_OBJECT @@ -105,15 +100,7 @@ bool OffscreenUi::shouldSwallowShortcut(QEvent* event) { return false; } -OffscreenUiRoot::OffscreenUiRoot(QQuickItem* parent) : QQuickItem(parent) { -} - -void OffscreenUiRoot::information(const QString& title, const QString& text) { - OffscreenUi::information(title, text); -} - OffscreenUi::OffscreenUi() { - ::qmlRegisterType("Hifi", 1, 0, "Root"); } void OffscreenUi::create(QOpenGLContext* context) { @@ -258,4 +245,13 @@ void OffscreenUi::setNavigationFocused(bool focused) { offscreenFlags->setNavigationFocused(focused); } +void OffscreenUi::createDesktop() { + if (_desktop) { + qDebug() << "Desktop already created"; + } + _desktop = dynamic_cast(load("Root.qml")); + Q_ASSERT(_desktop); + getRootContext()->setContextProperty("Desktop", _desktop); +} + #include "OffscreenUi.moc" diff --git a/libraries/ui/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h index 7063d25279..15d2871460 100644 --- a/libraries/ui/src/OffscreenUi.h +++ b/libraries/ui/src/OffscreenUi.h @@ -26,6 +26,7 @@ class OffscreenUi : public OffscreenQmlSurface, public Dependency { public: OffscreenUi(); virtual void create(QOpenGLContext* context) override; + void createDesktop(); void show(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QObject*) {}); void toggle(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QObject*) {}); bool shouldSwallowShortcut(QEvent* event); diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index 269ef6d6c9..0d5fc7fbf6 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -91,7 +91,7 @@ QScriptValue QmlWindowClass::internalConstructor(const QString& qmlSource, const auto argumentCount = context->argumentCount(); QString url; QString title; - int width = 100, height = 100; + int width = -1, height = -1; bool visible = true; if (argumentCount > 1) { @@ -131,13 +131,19 @@ QScriptValue QmlWindowClass::internalConstructor(const QString& qmlSource, url = QUrl::fromLocalFile(url).toString(); } - width = std::max(100, std::min(1280, width)); - height = std::max(100, std::min(720, height)); + if (width != -1 || height != -1) { + width = std::max(100, std::min(1280, width)); + height = std::max(100, std::min(720, height)); + } QmlWindowClass* retVal{ nullptr }; + auto offscreenUi = DependencyManager::get(); + qDebug() << "Clearing component cache"; + offscreenUi->getRootContext()->engine()->clearComponentCache(); + // Build the event bridge and wrapper on the main thread - QMetaObject::invokeMethod(DependencyManager::get().data(), "load", Qt::BlockingQueuedConnection, + QMetaObject::invokeMethod(offscreenUi.data(), "load", Qt::BlockingQueuedConnection, Q_ARG(const QString&, qmlSource), Q_ARG(std::function, [&](QQmlContext* context, QObject* object) { setupServer(); @@ -147,7 +153,9 @@ QScriptValue QmlWindowClass::internalConstructor(const QString& qmlSource, if (!title.isEmpty()) { retVal->setTitle(title); } - retVal->setSize(width, height); + if (width != -1 && height != -1) { + retVal->setSize(width, height); + } object->setProperty(SOURCE_PROPERTY, url); if (visible) { object->setProperty("enabled", true); From 4f975de6a6710165e4dd54f45b28e5b3ebeddf68 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 12 Jan 2016 11:13:42 -0800 Subject: [PATCH 093/215] Working on crash fixes, file open dialog --- .../resources/qml/dialogs/RunningScripts.qml | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/dialogs/RunningScripts.qml b/interface/resources/qml/dialogs/RunningScripts.qml index 1b25823fa7..0a383abeec 100644 --- a/interface/resources/qml/dialogs/RunningScripts.qml +++ b/interface/resources/qml/dialogs/RunningScripts.qml @@ -1,5 +1,6 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 +import QtQuick.Dialogs 1.2 as OriginalDialogs import Qt.labs.settings 1.0 import "../styles" as Hifi @@ -19,6 +20,34 @@ Window { property var scriptsModel: scripts.scriptsModelFilter property var runningScriptsModel: ListModel { } + + Component { + id: fileDialogCreator + OriginalDialogs.FileDialog { + id: fileDialog + modality: Qt.ApplicationModal + title: "Please choose a file" + nameFilters: [ "JavaScript files (*.js)" ] + folder: "file:///" + scripts.previousScriptLocation + onAccepted: { + var chosen = fileDialog.fileUrl; + console.log("You chose: " + chosen); + var chosenFolder = fileDialog.folder.toString(); + // remove prefixed "file:///" + chosenFolder = chosenFolder.replace(/^(file:\/{3})/,""); + // unescape html codes like '%23' for '#' + var cleanPath = decodeURIComponent(chosenFolder); + scripts.previousScriptLocation = cleanPath; + } + onRejected: { + console.log("Canceled") + } + Component.onCompleted: visible = true + } + } + + + Settings { category: "Overlay.RunningScripts" property alias x: root.x @@ -158,7 +187,10 @@ Window { anchors.bottomMargin: 8 anchors.right: parent.right Button { text: "from URL" } - Button { text: "from Disk" } + Button { + text: "from Disk" + onClicked: fileDialogCreator.createObject(root); + } } TextField { From a9eb5b8229e12eb54b1dcbd1d1aa4132a1ae28d0 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 12 Jan 2016 11:48:18 -0800 Subject: [PATCH 094/215] Load script from file --- interface/resources/qml/dialogs/RunningScripts.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/resources/qml/dialogs/RunningScripts.qml b/interface/resources/qml/dialogs/RunningScripts.qml index 0a383abeec..7a76380487 100644 --- a/interface/resources/qml/dialogs/RunningScripts.qml +++ b/interface/resources/qml/dialogs/RunningScripts.qml @@ -38,6 +38,7 @@ Window { // unescape html codes like '%23' for '#' var cleanPath = decodeURIComponent(chosenFolder); scripts.previousScriptLocation = cleanPath; + scripts.loadOneScript(chosen); } onRejected: { console.log("Canceled") From dcc6739bce686613948474548d4ce6fc207a4456 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 12 Jan 2016 12:29:51 -0800 Subject: [PATCH 095/215] Final functionality for running scripts --- .../resources/qml/dialogs/RunningScripts.qml | 43 ++++++++++++++++--- interface/src/Application.cpp | 9 ++-- interface/src/Application.h | 4 +- 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/interface/resources/qml/dialogs/RunningScripts.qml b/interface/resources/qml/dialogs/RunningScripts.qml index 7a76380487..6d7ef648fe 100644 --- a/interface/resources/qml/dialogs/RunningScripts.qml +++ b/interface/resources/qml/dialogs/RunningScripts.qml @@ -47,8 +47,6 @@ Window { } } - - Settings { category: "Overlay.RunningScripts" property alias x: root.x @@ -187,10 +185,13 @@ Window { anchors.bottom: filterEdit.top anchors.bottomMargin: 8 anchors.right: parent.right - Button { text: "from URL" } + Button { + text: "from URL"; + onClicked: ApplicationInterface.loadScriptURLDialog(); + } Button { text: "from Disk" - onClicked: fileDialogCreator.createObject(root); + onClicked: ApplicationInterface.loadDialog(); } } @@ -207,7 +208,8 @@ Window { TreeView { id: treeView height: 128 - anchors.bottom: parent.bottom + anchors.bottom: loadButton.top + anchors.bottomMargin: 8 anchors.left: parent.left anchors.right: parent.right headerVisible: false @@ -232,6 +234,37 @@ Window { model: scriptsModel TableViewColumn { title: "Name"; role: "display"; } } + + TextField { + id: selectedScript + enabled: true + readOnly: true + anchors.left: parent.left + anchors.right: loadButton.left + anchors.rightMargin: 8 + anchors.bottom: loadButton.bottom + anchors.top: loadButton.top + Connections { + target: treeView + onCurrentIndexChanged: { + var path = scriptsModel.data(treeView.currentIndex, 0x100) + if (path) { + selectedScript.text = path + } else { + selectedScript.text = "" + } + + } + } + } + + Button { + id: loadButton + anchors.bottom: parent.bottom + anchors.right: parent.right + text: "Load" + enabled: selectedScript.text != "" + } } } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index adcf5d305b..84c6e5e55c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -977,12 +977,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : }); connect(this, &Application::applicationStateChanged, this, &Application::activeChanged); - - // FIXME -- NOTE: This will call ProcessEvents() which can cause authentication signals to fire, which - // if not logged in can cause the login dialog to appear. As currently implemented, the login requires - // the offscreen UI to render, so this needs to be well after OffscreenUi is available - _runningScriptsWidget = new RunningScriptsWidget(_window); - qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0); } @@ -1208,6 +1202,9 @@ void Application::initializeUi() { qApp->quit(); }); + // For some reason there is already an "Application" object in the QML context, + // though I can't find it. Hence, "ApplicationInterface" + rootContext->setContextProperty("ApplicationInterface", this); rootContext->setContextProperty("AnimationCache", DependencyManager::get().data()); rootContext->setContextProperty("Audio", &AudioScriptingInterface::getInstance()); rootContext->setContextProperty("Controller", DependencyManager::get().data()); diff --git a/interface/src/Application.h b/interface/src/Application.h index 38b4a8845c..d50fef327b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -245,8 +245,8 @@ public slots: bool importEntities(const QString& url); void setLowVelocityFilter(bool lowVelocityFilter); - void loadDialog(); - void loadScriptURLDialog(); + Q_INVOKABLE void loadDialog(); + Q_INVOKABLE void loadScriptURLDialog(); void toggleLogDialog(); void toggleRunningScriptsWidget(); From f3523329247f65757a035fd3047e10b0e19de507 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 12 Jan 2016 13:09:16 -0800 Subject: [PATCH 096/215] Fix logging warning --- libraries/script-engine/src/ScriptsModel.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptsModel.cpp b/libraries/script-engine/src/ScriptsModel.cpp index 07518dded1..620184ba10 100644 --- a/libraries/script-engine/src/ScriptsModel.cpp +++ b/libraries/script-engine/src/ScriptsModel.cpp @@ -61,7 +61,6 @@ ScriptsModel::ScriptsModel(QObject* parent) : _localDirectory.setFilter(QDir::Files | QDir::Readable); _localDirectory.setNameFilters(QStringList("*.js")); - auto scriptEngines = DependencyManager::get(); connect(&_fsWatcher, &QFileSystemWatcher::directoryChanged, this, &ScriptsModel::reloadLocalFiles); reloadLocalFiles(); reloadRemoteFiles(); From 2ed54d8ea77de21dc930f902b504d5eda00eb9b5 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 12 Jan 2016 13:11:03 -0800 Subject: [PATCH 097/215] Cleanup running scripts --- .../resources/qml/dialogs/RunningScripts.qml | 41 ++----------------- 1 file changed, 3 insertions(+), 38 deletions(-) diff --git a/interface/resources/qml/dialogs/RunningScripts.qml b/interface/resources/qml/dialogs/RunningScripts.qml index 6d7ef648fe..917d862547 100644 --- a/interface/resources/qml/dialogs/RunningScripts.qml +++ b/interface/resources/qml/dialogs/RunningScripts.qml @@ -20,33 +20,6 @@ Window { property var scriptsModel: scripts.scriptsModelFilter property var runningScriptsModel: ListModel { } - - Component { - id: fileDialogCreator - OriginalDialogs.FileDialog { - id: fileDialog - modality: Qt.ApplicationModal - title: "Please choose a file" - nameFilters: [ "JavaScript files (*.js)" ] - folder: "file:///" + scripts.previousScriptLocation - onAccepted: { - var chosen = fileDialog.fileUrl; - console.log("You chose: " + chosen); - var chosenFolder = fileDialog.folder.toString(); - // remove prefixed "file:///" - chosenFolder = chosenFolder.replace(/^(file:\/{3})/,""); - // unescape html codes like '%23' for '#' - var cleanPath = decodeURIComponent(chosenFolder); - scripts.previousScriptLocation = cleanPath; - scripts.loadOneScript(chosen); - } - onRejected: { - console.log("Canceled") - } - Component.onCompleted: visible = true - } - } - Settings { category: "Overlay.RunningScripts" property alias x: root.x @@ -214,23 +187,15 @@ Window { anchors.right: parent.right headerVisible: false focus: true - onClicked: { - console.log("treeview clicked " + scriptsModel.data(index, 0x100)) - } - - onDoubleClicked: { - console.log("treeview double clicked" + scriptsModel.data(index, 0x100)) - isExpanded(index) ? collapse(index) : expand(index) - } - + // FIXME doesn't work? + onDoubleClicked: isExpanded(index) ? collapse(index) : expand(index) + // FIXME not triggered by double click? onActivated: { - console.log("treeview activated!" + index) var path = scriptsModel.data(index, 0x100) if (path) { loadScript(path) } } - model: scriptsModel TableViewColumn { title: "Name"; role: "display"; } } From e7bfcba44f3e8e27d6937866951ccbc5f9767d55 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 12 Jan 2016 13:17:06 -0800 Subject: [PATCH 098/215] Fix 'load' button --- interface/resources/qml/dialogs/RunningScripts.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/resources/qml/dialogs/RunningScripts.qml b/interface/resources/qml/dialogs/RunningScripts.qml index 917d862547..e9b82609d9 100644 --- a/interface/resources/qml/dialogs/RunningScripts.qml +++ b/interface/resources/qml/dialogs/RunningScripts.qml @@ -229,6 +229,7 @@ Window { anchors.right: parent.right text: "Load" enabled: selectedScript.text != "" + onClicked: root.loadScript(selectedScript.text) } } } From e1ba4ff0a80150d4a7de1c8643fb64c8f0afdee1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 6 Jan 2016 16:56:47 -0800 Subject: [PATCH 099/215] add CollisionMask entity property --- interface/src/avatar/AvatarMotionState.cpp | 8 ++- interface/src/avatar/AvatarMotionState.h | 2 +- libraries/entities/src/EntityItem.cpp | 15 ++++ libraries/entities/src/EntityItem.h | 6 ++ .../entities/src/EntityItemProperties.cpp | 12 +++- libraries/entities/src/EntityItemProperties.h | 1 + .../entities/src/EntityItemPropertiesMacros.h | 1 + libraries/entities/src/EntityPropertyFlags.h | 2 + libraries/networking/src/udt/PacketHeaders.h | 1 + libraries/physics/src/CharacterController.cpp | 2 +- libraries/physics/src/EntityMotionState.cpp | 31 +++++--- libraries/physics/src/EntityMotionState.h | 2 +- libraries/physics/src/ObjectMotionState.h | 2 +- libraries/physics/src/PhysicsEngine.cpp | 42 ++++++----- libraries/physics/src/PhysicsEngine.h | 5 +- libraries/shared/src/PhysicsCollisionGroups.h | 70 ++++++++++--------- 16 files changed, 128 insertions(+), 74 deletions(-) diff --git a/interface/src/avatar/AvatarMotionState.cpp b/interface/src/avatar/AvatarMotionState.cpp index 9ce9594d45..7f11c83c4a 100644 --- a/interface/src/avatar/AvatarMotionState.cpp +++ b/interface/src/avatar/AvatarMotionState.cpp @@ -9,8 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include #include +#include +#include #include "Avatar.h" #include "AvatarMotionState.h" @@ -143,7 +144,8 @@ QUuid AvatarMotionState::getSimulatorID() const { } // virtual -int16_t AvatarMotionState::computeCollisionGroup() const { - return COLLISION_GROUP_OTHER_AVATAR; +void AvatarMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const { + group = BULLET_COLLISION_GROUP_OTHER_AVATAR; + mask = PhysicsEngine::getCollisionMask(group); } diff --git a/interface/src/avatar/AvatarMotionState.h b/interface/src/avatar/AvatarMotionState.h index 0465ddf50b..f02dba54bd 100644 --- a/interface/src/avatar/AvatarMotionState.h +++ b/interface/src/avatar/AvatarMotionState.h @@ -61,7 +61,7 @@ public: void addDirtyFlags(uint32_t flags) { _dirtyFlags |= flags; } - virtual int16_t computeCollisionGroup() const override; + virtual void computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const; friend class AvatarManager; friend class Avatar; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 97043a635d..c04d280132 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -64,6 +64,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _angularDamping(ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING), _visible(ENTITY_ITEM_DEFAULT_VISIBLE), _ignoreForCollisions(ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS), + _collisionMask(ENTITY_COLLISION_MASK_DEFAULT), _collisionsWillMove(ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE), _locked(ENTITY_ITEM_DEFAULT_LOCKED), _userData(ENTITY_ITEM_DEFAULT_USER_DATA), @@ -123,6 +124,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_ANGULAR_DAMPING; requestedProperties += PROP_VISIBLE; requestedProperties += PROP_IGNORE_FOR_COLLISIONS; + requestedProperties += PROP_COLLISION_MASK; requestedProperties += PROP_COLLISIONS_WILL_MOVE; requestedProperties += PROP_LOCKED; requestedProperties += PROP_USER_DATA; @@ -259,6 +261,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, getAngularDamping()); APPEND_ENTITY_PROPERTY(PROP_VISIBLE, getVisible()); APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, getIgnoreForCollisions()); + APPEND_ENTITY_PROPERTY(PROP_COLLISION_MASK, getCollisionMask()); APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, getCollisionsWillMove()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, getLocked()); APPEND_ENTITY_PROPERTY(PROP_USER_DATA, getUserData()); @@ -678,6 +681,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible); READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, updateIgnoreForCollisions); + if (args.bitstreamVersion >= VERSION_ENTITITES_HAVE_COLLISION_MASK) { + READ_ENTITY_PROPERTY(PROP_COLLISION_MASK, uint8_t, updateCollisionMask); + } READ_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, bool, updateCollisionsWillMove); READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData); @@ -1041,6 +1047,7 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper COPY_ENTITY_PROPERTY_TO_PROPERTIES(localRenderAlpha, getLocalRenderAlpha); COPY_ENTITY_PROPERTY_TO_PROPERTIES(visible, getVisible); COPY_ENTITY_PROPERTY_TO_PROPERTIES(ignoreForCollisions, getIgnoreForCollisions); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionMask, getCollisionMask); COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionsWillMove, getCollisionsWillMove); COPY_ENTITY_PROPERTY_TO_PROPERTIES(locked, getLocked); COPY_ENTITY_PROPERTY_TO_PROPERTIES(userData, getUserData); @@ -1096,6 +1103,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(restitution, updateRestitution); SET_ENTITY_PROPERTY_FROM_PROPERTIES(friction, updateFriction); SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, updateIgnoreForCollisions); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionMask, updateCollisionMask); SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, updateCollisionsWillMove); SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, updateCreated); SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime); @@ -1445,6 +1453,13 @@ void EntityItem::updateIgnoreForCollisions(bool value) { } } +void EntityItem::updateCollisionMask(uint8_t value) { + if ((_collisionMask & ENTITY_COLLISION_MASK_DEFAULT) != (value & ENTITY_COLLISION_MASK_DEFAULT)) { + _collisionMask = (value & ENTITY_COLLISION_MASK_DEFAULT); + _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; + } +} + void EntityItem::updateCollisionsWillMove(bool value) { if (_collisionsWillMove != value) { _collisionsWillMove = value; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 83f2ad164e..d3b52814a3 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -21,6 +21,7 @@ #include // for EncodeBitstreamParams class #include // for OctreeElement::AppendState #include +#include #include #include #include @@ -273,6 +274,9 @@ public: bool getIgnoreForCollisions() const { return _ignoreForCollisions; } void setIgnoreForCollisions(bool value) { _ignoreForCollisions = value; } + uint8_t getCollisionMask() const { return _collisionMask; } + void setCollisionMask(uint8_t value); + bool getCollisionsWillMove() const { return _collisionsWillMove; } void setCollisionsWillMove(bool value) { _collisionsWillMove = value; } @@ -327,6 +331,7 @@ public: void updateAngularVelocity(const glm::vec3& value); void updateAngularDamping(float value); void updateIgnoreForCollisions(bool value); + void updateCollisionMask(uint8_t value); void updateCollisionsWillMove(bool value); void updateLifetime(float value); void updateCreated(uint64_t value); @@ -440,6 +445,7 @@ protected: float _angularDamping; bool _visible; bool _ignoreForCollisions; + uint8_t _collisionMask { ENTITY_COLLISION_MASK_DEFAULT }; bool _collisionsWillMove; bool _locked; QString _userData; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 214f1e5d78..d647896d1f 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -203,6 +203,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_ANGULAR_VELOCITY, angularVelocity); CHECK_PROPERTY_CHANGE(PROP_ANGULAR_DAMPING, angularDamping); CHECK_PROPERTY_CHANGE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions); + CHECK_PROPERTY_CHANGE(PROP_COLLISION_MASK, collisionMask); CHECK_PROPERTY_CHANGE(PROP_COLLISIONS_WILL_MOVE, collisionsWillMove); CHECK_PROPERTY_CHANGE(PROP_IS_SPOTLIGHT, isSpotlight); CHECK_PROPERTY_CHANGE(PROP_INTENSITY, intensity); @@ -317,6 +318,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_DAMPING, angularDamping); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE, visible); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_MASK, collisionMask); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISIONS_WILL_MOVE, collisionsWillMove); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_HREF, href); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DESCRIPTION, description); @@ -538,6 +540,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(glowLevel, float, setGlowLevel); COPY_PROPERTY_FROM_QSCRIPTVALUE(localRenderAlpha, float, setLocalRenderAlpha); COPY_PROPERTY_FROM_QSCRIPTVALUE(ignoreForCollisions, bool, setIgnoreForCollisions); + COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionMask, uint8_t, setCollisionMask); COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionsWillMove, bool, setCollisionsWillMove); COPY_PROPERTY_FROM_QSCRIPTVALUE(isSpotlight, bool, setIsSpotlight); COPY_PROPERTY_FROM_QSCRIPTVALUE(intensity, float, setIntensity); @@ -700,6 +703,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_ANGULAR_VELOCITY, AngularVelocity, angularVelocity, glm::vec3); ADD_PROPERTY_TO_MAP(PROP_ANGULAR_DAMPING, AngularDamping, angularDamping, float); ADD_PROPERTY_TO_MAP(PROP_IGNORE_FOR_COLLISIONS, IgnoreForCollisions, ignoreForCollisions, bool); + ADD_PROPERTY_TO_MAP(PROP_COLLISION_MASK, CollisionMask, collisionMask, uint8_t); ADD_PROPERTY_TO_MAP(PROP_COLLISIONS_WILL_MOVE, CollisionsWillMove, collisionsWillMove, bool); ADD_PROPERTY_TO_MAP(PROP_IS_SPOTLIGHT, IsSpotlight, isSpotlight, bool); ADD_PROPERTY_TO_MAP(PROP_INTENSITY, Intensity, intensity, float); @@ -946,6 +950,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, properties.getAngularDamping()); APPEND_ENTITY_PROPERTY(PROP_VISIBLE, properties.getVisible()); APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, properties.getIgnoreForCollisions()); + APPEND_ENTITY_PROPERTY(PROP_COLLISION_MASK, properties.getCollisionMask()); APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, properties.getCollisionsWillMove()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, properties.getLocked()); APPEND_ENTITY_PROPERTY(PROP_USER_DATA, properties.getUserData()); @@ -1238,6 +1243,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_DAMPING, float, setAngularDamping); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE, bool, setVisible); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IGNORE_FOR_COLLISIONS, bool, setIgnoreForCollisions); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_MASK, uint8_t, setCollisionMask); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISIONS_WILL_MOVE, bool, setCollisionsWillMove); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_DATA, QString, setUserData); @@ -1419,6 +1425,7 @@ void EntityItemProperties::markAllChanged() { _localRenderAlphaChanged = true; _isSpotlightChanged = true; _ignoreForCollisionsChanged = true; + _collisionMaskChanged = true; _collisionsWillMoveChanged = true; _intensityChanged = true; @@ -1537,7 +1544,7 @@ bool EntityItemProperties::hasTerseUpdateChanges() const { bool EntityItemProperties::hasMiscPhysicsChanges() const { return _gravityChanged || _dimensionsChanged || _densityChanged || _frictionChanged || _restitutionChanged || _dampingChanged || _angularDampingChanged || _registrationPointChanged || - _compoundShapeURLChanged || _collisionsWillMoveChanged || _ignoreForCollisionsChanged; + _compoundShapeURLChanged || _collisionsWillMoveChanged || _ignoreForCollisionsChanged || _collisionMaskChanged; } void EntityItemProperties::clearSimulationOwner() { @@ -1653,6 +1660,9 @@ QList EntityItemProperties::listChangedProperties() { if (ignoreForCollisionsChanged()) { out += "ignoreForCollisions"; } + if (collisionMaskChanged()) { + out += "collisionMask"; + } if (collisionsWillMoveChanged()) { out += "collisionsWillMove"; } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 35e7bdfb78..46af6a1da9 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -128,6 +128,7 @@ public: DEFINE_PROPERTY_REF(PROP_ANGULAR_VELOCITY, AngularVelocity, angularVelocity, glm::vec3, ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY); DEFINE_PROPERTY(PROP_ANGULAR_DAMPING, AngularDamping, angularDamping, float, ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING); DEFINE_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, IgnoreForCollisions, ignoreForCollisions, bool, ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS); + DEFINE_PROPERTY(PROP_COLLISION_MASK, CollisionMask, collisionMask, uint8_t, ENTITY_COLLISION_MASK_DEFAULT); DEFINE_PROPERTY(PROP_COLLISIONS_WILL_MOVE, CollisionsWillMove, collisionsWillMove, bool, ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE); DEFINE_PROPERTY(PROP_IS_SPOTLIGHT, IsSpotlight, isSpotlight, bool, false); DEFINE_PROPERTY(PROP_INTENSITY, Intensity, intensity, float, 1.0f); diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index ad98ca7ba1..860da87705 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -191,6 +191,7 @@ inline quint16 quint16_convertFromScriptValue(const QScriptValue& v, bool& isVal inline uint16_t uint16_t_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); } inline int int_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); } inline bool bool_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toBool(); } +inline uint8_t uint8_t_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return (uint8_t)(0xff & v.toVariant().toInt(&isValid)); } inline QString QString_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toString().trimmed(); } inline QUuid QUuid_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); } inline EntityItemID EntityItemID_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); } diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index c59ed7141b..81301cb52d 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -165,6 +165,8 @@ enum EntityPropertyList { PROP_JOINT_TRANSLATIONS_SET, PROP_JOINT_TRANSLATIONS, + PROP_COLLISION_MASK, // one byte of collision group flags + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index c1404178ff..b8637e85cb 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -164,6 +164,7 @@ const PacketVersion VERSION_ENTITIES_HAVE_PARENTS = 51; const PacketVersion VERSION_ENTITIES_REMOVED_START_AUTOMATICALLY_FROM_ANIMATION_PROPERTY_GROUP = 52; const PacketVersion VERSION_MODEL_ENTITIES_JOINTS_ON_WIRE = 53; const PacketVersion VERSION_ENTITITES_HAVE_QUERY_BOX = 54; +const PacketVersion VERSION_ENTITITES_HAVE_COLLISION_MASK = 55; enum class AvatarMixerPacketVersion : PacketVersion { TranslationSupport = 17, diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 86d57b7ee9..0797058f05 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -84,7 +84,7 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) { // Before adding the RigidBody to the world we must save its oldGravity to the side // because adding an object to the world will overwrite it with the default gravity. btVector3 oldGravity = _rigidBody->getGravity(); - _dynamicsWorld->addRigidBody(_rigidBody, COLLISION_GROUP_MY_AVATAR, COLLISION_MASK_MY_AVATAR); + _dynamicsWorld->addRigidBody(_rigidBody, BULLET_COLLISION_GROUP_MY_AVATAR, BULLET_COLLISION_MASK_MY_AVATAR); _dynamicsWorld->addAction(this); // restore gravity settings _rigidBody->setGravity(oldGravity); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index c1338b772c..d603fde159 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -610,19 +610,28 @@ QString EntityMotionState::getName() const { } // virtual -int16_t EntityMotionState::computeCollisionGroup() const { - if (_entity->getIgnoreForCollisions()) { - return COLLISION_GROUP_COLLISIONLESS; +void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const { + group = BULLET_COLLISION_GROUP_STATIC; + if (_entity) { + if (_entity->getIgnoreForCollisions()) { + group = BULLET_COLLISION_GROUP_COLLISIONLESS; + } + switch (computeObjectMotionType()){ + case MOTION_TYPE_STATIC: + group = BULLET_COLLISION_GROUP_STATIC; + break; + case MOTION_TYPE_KINEMATIC: + group = BULLET_COLLISION_GROUP_KINEMATIC; + break; + default: + break; + } } - switch (computeObjectMotionType()){ - case MOTION_TYPE_STATIC: - return COLLISION_GROUP_STATIC; - case MOTION_TYPE_KINEMATIC: - return COLLISION_GROUP_KINEMATIC; - default: - break; + + mask = PhysicsEngine::getCollisionMask(group); + if (_entity) { + mask &= (int16_t)(_entity->getCollisionMask()); } - return COLLISION_GROUP_DEFAULT; } void EntityMotionState::setOutgoingPriority(quint8 priority) { diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 53e7982ae1..e543ee024e 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -80,7 +80,7 @@ public: virtual QString getName() const override; - virtual int16_t computeCollisionGroup() const override; + virtual void computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const; // eternal logic can suggest a simuator priority bid for the next outgoing update void setOutgoingPriority(quint8 priority); diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index e10d58e3ed..bbdf6c408a 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -136,7 +136,7 @@ public: virtual QString getName() const { return ""; } - virtual int16_t computeCollisionGroup() const = 0; + virtual void computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const = 0; bool isActive() const { return _body ? _body->isActive() : false; } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 9e295d5cf5..b2823746ee 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -22,20 +22,30 @@ uint32_t PhysicsEngine::getNumSubsteps() { return _numSubsteps; } +btHashMap _collisionMasks; + +void initCollisionMaskTable() { + if (_collisionMasks.size() == 0) { + // build table of masks with their group as the key + _collisionMasks.insert(btHashInt((int)BULLET_COLLISION_GROUP_DYNAMIC), BULLET_COLLISION_MASK_DYNAMIC); + _collisionMasks.insert(btHashInt((int)BULLET_COLLISION_GROUP_STATIC), BULLET_COLLISION_MASK_STATIC); + _collisionMasks.insert(btHashInt((int)BULLET_COLLISION_GROUP_KINEMATIC), BULLET_COLLISION_MASK_KINEMATIC); + _collisionMasks.insert(btHashInt((int)BULLET_COLLISION_GROUP_MY_AVATAR), BULLET_COLLISION_MASK_MY_AVATAR); + _collisionMasks.insert(btHashInt((int)BULLET_COLLISION_GROUP_OTHER_AVATAR), BULLET_COLLISION_MASK_OTHER_AVATAR); + _collisionMasks.insert(btHashInt((int)BULLET_COLLISION_GROUP_COLLISIONLESS), BULLET_COLLISION_MASK_COLLISIONLESS); + } +} + +// static +int16_t PhysicsEngine::getCollisionMask(int16_t group) { + const int16_t* mask = _collisionMasks.find(btHashInt((int)group)); + return mask ? *mask : BULLET_COLLISION_MASK_DEFAULT; +} + PhysicsEngine::PhysicsEngine(const glm::vec3& offset) : _originOffset(offset), _myAvatarController(nullptr) { - // build table of masks with their group as the key - _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_DEFAULT), COLLISION_MASK_DEFAULT); - _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_STATIC), COLLISION_MASK_STATIC); - _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_KINEMATIC), COLLISION_MASK_KINEMATIC); - _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_DEBRIS), COLLISION_MASK_DEBRIS); - _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_TRIGGER), COLLISION_MASK_TRIGGER); - _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_MY_AVATAR), COLLISION_MASK_MY_AVATAR); - _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_MY_ATTACHMENT), COLLISION_MASK_MY_ATTACHMENT); - _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_OTHER_AVATAR), COLLISION_MASK_OTHER_AVATAR); - _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_OTHER_ATTACHMENT), COLLISION_MASK_OTHER_ATTACHMENT); - _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_COLLISIONLESS), COLLISION_MASK_COLLISIONLESS); + initCollisionMaskTable(); } PhysicsEngine::~PhysicsEngine() { @@ -139,8 +149,9 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { body->setFlags(BT_DISABLE_WORLD_GRAVITY); motionState->updateBodyMaterialProperties(); - int16_t group = motionState->computeCollisionGroup(); - _dynamicsWorld->addRigidBody(body, group, getCollisionMask(group)); + int16_t group, mask; + motionState->computeCollisionGroupAndMask(group, mask); + _dynamicsWorld->addRigidBody(body, group, mask); motionState->clearIncomingDirtyFlags(); } @@ -457,11 +468,6 @@ void PhysicsEngine::setCharacterController(CharacterController* character) { } } -int16_t PhysicsEngine::getCollisionMask(int16_t group) const { - const int16_t* mask = _collisionMasks.find(btHashInt((int)group)); - return mask ? *mask : COLLISION_MASK_DEFAULT; -} - EntityActionPointer PhysicsEngine::getActionByID(const QUuid& actionID) const { if (_objectActions.contains(actionID)) { return _objectActions[actionID]; diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 0ca9b2aca8..b2a44b7a3c 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -45,6 +45,8 @@ typedef QVector CollisionEvents; class PhysicsEngine { public: + static int16_t getCollisionMask(int16_t group); + uint32_t getNumSubsteps(); PhysicsEngine(const glm::vec3& offset); @@ -88,8 +90,6 @@ public: void dumpNextStats() { _dumpNextStats = true; } - int16_t getCollisionMask(int16_t group) const; - EntityActionPointer getActionByID(const QUuid& actionID) const; void addAction(EntityActionPointer action); void removeAction(const QUuid actionID); @@ -127,7 +127,6 @@ private: QHash _objectActions; - btHashMap _collisionMasks; uint32_t _numSubsteps; }; diff --git a/libraries/shared/src/PhysicsCollisionGroups.h b/libraries/shared/src/PhysicsCollisionGroups.h index 42599a1b28..67862b7983 100644 --- a/libraries/shared/src/PhysicsCollisionGroups.h +++ b/libraries/shared/src/PhysicsCollisionGroups.h @@ -14,8 +14,8 @@ #include -/* Note: These are the Bullet collision groups defined in btBroadphaseProxy. Only - * DefaultFilter and StaticFilter are explicitly used by Bullet (when the collision +/* Note: These are the Bullet collision groups defined in btBroadphaseProxy. Only + * DefaultFilter and StaticFilter are explicitly used by Bullet (when the collision * filter of an object is not manually specified), the rest are merely suggestions. * enum CollisionFilterGroups { @@ -28,52 +28,54 @@ enum CollisionFilterGroups { AllFilter = -1 } * - * When using custom collision filters we pretty much need to do all or nothing. - * We'll be doing it all which means we define our own groups and build custom masks + * When using custom collision filters we pretty much need to do all or nothing. + * We'll be doing it all which means we define our own groups and build custom masks * for everything. * */ -const int16_t COLLISION_GROUP_DEFAULT = 1 << 0; -const int16_t COLLISION_GROUP_STATIC = 1 << 1; -const int16_t COLLISION_GROUP_KINEMATIC = 1 << 2; -const int16_t COLLISION_GROUP_DEBRIS = 1 << 3; -const int16_t COLLISION_GROUP_TRIGGER = 1 << 4; -const int16_t COLLISION_GROUP_MY_AVATAR = 1 << 5; -const int16_t COLLISION_GROUP_OTHER_AVATAR = 1 << 6; -const int16_t COLLISION_GROUP_MY_ATTACHMENT = 1 << 7; -const int16_t COLLISION_GROUP_OTHER_ATTACHMENT = 1 << 8; +const int16_t BULLET_COLLISION_GROUP_DYNAMIC = 1 << 0; +const int16_t BULLET_COLLISION_GROUP_STATIC = 1 << 1; +const int16_t BULLET_COLLISION_GROUP_KINEMATIC = 1 << 2; +const int16_t BULLET_COLLISION_GROUP_MY_AVATAR = 1 << 3; +const int16_t BULLET_COLLISION_GROUP_OTHER_AVATAR = 1 << 4; // ... -const int16_t COLLISION_GROUP_COLLISIONLESS = 1 << 14; +const int16_t BULLET_COLLISION_GROUP_COLLISIONLESS = 1 << 14; -/* Note: In order for objectA to collide with objectB at the filter stage +/* Note: In order for objectA to collide with objectB at the filter stage * both (groupA & maskB) and (groupB & maskA) must be non-zero. */ -// DEFAULT collides with everything except COLLISIONLESS -const int16_t COLLISION_MASK_DEFAULT = ~ COLLISION_GROUP_COLLISIONLESS; +// the default collision mask is: collides with everything except collisionless +const int16_t BULLET_COLLISION_MASK_DEFAULT = ~ BULLET_COLLISION_GROUP_COLLISIONLESS; -// STATIC also doesn't collide with other STATIC -const int16_t COLLISION_MASK_STATIC = ~ (COLLISION_GROUP_COLLISIONLESS | COLLISION_GROUP_STATIC); +const int16_t BULLET_COLLISION_MASK_DYNAMIC = BULLET_COLLISION_MASK_DEFAULT; -const int16_t COLLISION_MASK_KINEMATIC = COLLISION_MASK_DEFAULT; +// STATIC is special: it collides with everything exept COLLISIONLESS and other STATIC +const int16_t BULLET_COLLISION_MASK_STATIC = ~ (BULLET_COLLISION_GROUP_COLLISIONLESS | BULLET_COLLISION_GROUP_STATIC); -// DEBRIS also doesn't collide with other DEBRIS, or TRIGGER -const int16_t COLLISION_MASK_DEBRIS = ~ (COLLISION_GROUP_COLLISIONLESS - | COLLISION_GROUP_DEBRIS - | COLLISION_GROUP_TRIGGER); - -// TRIGGER also doesn't collide with DEBRIS, TRIGGER, or STATIC (TRIGGER only detects moveable things that matter) -const int16_t COLLISION_MASK_TRIGGER = COLLISION_MASK_DEBRIS & ~(COLLISION_GROUP_STATIC); - -// AVATAR also doesn't collide with corresponding ATTACHMENTs -const int16_t COLLISION_MASK_MY_AVATAR = ~(COLLISION_GROUP_COLLISIONLESS | COLLISION_GROUP_MY_ATTACHMENT); -const int16_t COLLISION_MASK_MY_ATTACHMENT = ~(COLLISION_GROUP_COLLISIONLESS | COLLISION_GROUP_MY_AVATAR); -const int16_t COLLISION_MASK_OTHER_AVATAR = ~(COLLISION_GROUP_COLLISIONLESS | COLLISION_GROUP_OTHER_ATTACHMENT); -const int16_t COLLISION_MASK_OTHER_ATTACHMENT = ~(COLLISION_GROUP_COLLISIONLESS | COLLISION_GROUP_OTHER_AVATAR); +const int16_t BULLET_COLLISION_MASK_KINEMATIC = BULLET_COLLISION_MASK_DEFAULT; +const int16_t BULLET_COLLISION_MASK_MY_AVATAR = BULLET_COLLISION_MASK_DEFAULT; +const int16_t BULLET_COLLISION_MASK_OTHER_AVATAR = BULLET_COLLISION_MASK_DEFAULT; // COLLISIONLESS gets an empty mask. -const int16_t COLLISION_MASK_COLLISIONLESS = 0; +const int16_t BULLET_COLLISION_MASK_COLLISIONLESS = 0; + + +// The USER collision groups are exposed to script and can be used to generate per-object collision masks. +const uint8_t USER_COLLISION_GROUP_DYNAMIC = 1 << 0; +const uint8_t USER_COLLISION_GROUP_STATIC = 1 << 1; +const uint8_t USER_COLLISION_GROUP_KINEMATIC = 1 << 2; +const uint8_t USER_COLLISION_GROUP_MY_AVATAR = 1 << 3; +const uint8_t USER_COLLISION_GROUP_OTHER_AVATAR = 1 << 4; + +const uint8_t ENTITY_COLLISION_MASK_DEFAULT = + USER_COLLISION_GROUP_DYNAMIC | + USER_COLLISION_GROUP_STATIC | + USER_COLLISION_GROUP_KINEMATIC | + USER_COLLISION_GROUP_MY_AVATAR | + USER_COLLISION_GROUP_OTHER_AVATAR; + #endif // hifi_PhysicsCollisionGroups_h From c9b125612cb5314bbe44d8c3bb8ed9fd86baec09 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 Jan 2016 13:40:24 -0800 Subject: [PATCH 100/215] fix bugs --- libraries/networking/src/udt/PacketHeaders.cpp | 2 +- libraries/physics/src/EntityMotionState.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 43f4b5dcc9..46bf41398c 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -41,7 +41,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: - return VERSION_ENTITITES_HAVE_QUERY_BOX; + return VERSION_ENTITITES_HAVE_COLLISION_MASK; case PacketType::AvatarData: case PacketType::BulkAvatarData: return static_cast(AvatarMixerPacketVersion::SoftAttachmentSupport); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index d603fde159..cecc5c96b1 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -623,6 +623,9 @@ void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& ma case MOTION_TYPE_KINEMATIC: group = BULLET_COLLISION_GROUP_KINEMATIC; break; + case MOTION_TYPE_DYNAMIC: + group = BULLET_COLLISION_GROUP_DYNAMIC; + break; default: break; } From 502921e87708cbb21c25104612921131146c7495 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 Jan 2016 13:53:50 -0800 Subject: [PATCH 101/215] more consistency for collision group values --- libraries/physics/src/EntityMotionState.cpp | 6 +++--- libraries/shared/src/PhysicsCollisionGroups.h | 21 +++++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index cecc5c96b1..956ed9fedd 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -620,12 +620,12 @@ void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& ma case MOTION_TYPE_STATIC: group = BULLET_COLLISION_GROUP_STATIC; break; - case MOTION_TYPE_KINEMATIC: - group = BULLET_COLLISION_GROUP_KINEMATIC; - break; case MOTION_TYPE_DYNAMIC: group = BULLET_COLLISION_GROUP_DYNAMIC; break; + case MOTION_TYPE_KINEMATIC: + group = BULLET_COLLISION_GROUP_KINEMATIC; + break; default: break; } diff --git a/libraries/shared/src/PhysicsCollisionGroups.h b/libraries/shared/src/PhysicsCollisionGroups.h index 67862b7983..a86722a084 100644 --- a/libraries/shared/src/PhysicsCollisionGroups.h +++ b/libraries/shared/src/PhysicsCollisionGroups.h @@ -34,8 +34,8 @@ enum CollisionFilterGroups { * */ -const int16_t BULLET_COLLISION_GROUP_DYNAMIC = 1 << 0; -const int16_t BULLET_COLLISION_GROUP_STATIC = 1 << 1; +const int16_t BULLET_COLLISION_GROUP_STATIC = 1 << 0; +const int16_t BULLET_COLLISION_GROUP_DYNAMIC = 1 << 1; const int16_t BULLET_COLLISION_GROUP_KINEMATIC = 1 << 2; const int16_t BULLET_COLLISION_GROUP_MY_AVATAR = 1 << 3; const int16_t BULLET_COLLISION_GROUP_OTHER_AVATAR = 1 << 4; @@ -50,13 +50,15 @@ const int16_t BULLET_COLLISION_GROUP_COLLISIONLESS = 1 << 14; // the default collision mask is: collides with everything except collisionless const int16_t BULLET_COLLISION_MASK_DEFAULT = ~ BULLET_COLLISION_GROUP_COLLISIONLESS; -const int16_t BULLET_COLLISION_MASK_DYNAMIC = BULLET_COLLISION_MASK_DEFAULT; - -// STATIC is special: it collides with everything exept COLLISIONLESS and other STATIC +// STATIC does not collide with itself (as optimization of physics simulation) const int16_t BULLET_COLLISION_MASK_STATIC = ~ (BULLET_COLLISION_GROUP_COLLISIONLESS | BULLET_COLLISION_GROUP_STATIC); +const int16_t BULLET_COLLISION_MASK_DYNAMIC = BULLET_COLLISION_MASK_DEFAULT; const int16_t BULLET_COLLISION_MASK_KINEMATIC = BULLET_COLLISION_MASK_DEFAULT; -const int16_t BULLET_COLLISION_MASK_MY_AVATAR = BULLET_COLLISION_MASK_DEFAULT; + +// MY_AVATAR does not collide with itself +const int16_t BULLET_COLLISION_MASK_MY_AVATAR = ~(BULLET_COLLISION_GROUP_COLLISIONLESS | BULLET_COLLISION_GROUP_MY_AVATAR); + const int16_t BULLET_COLLISION_MASK_OTHER_AVATAR = BULLET_COLLISION_MASK_DEFAULT; // COLLISIONLESS gets an empty mask. @@ -64,15 +66,16 @@ const int16_t BULLET_COLLISION_MASK_COLLISIONLESS = 0; // The USER collision groups are exposed to script and can be used to generate per-object collision masks. -const uint8_t USER_COLLISION_GROUP_DYNAMIC = 1 << 0; -const uint8_t USER_COLLISION_GROUP_STATIC = 1 << 1; +// They are not necessarily the same as the BULLET_COLLISION_GROUPS, but we start them off with matching numbers. +const uint8_t USER_COLLISION_GROUP_STATIC = 1 << 0; +const uint8_t USER_COLLISION_GROUP_DYNAMIC = 1 << 1; const uint8_t USER_COLLISION_GROUP_KINEMATIC = 1 << 2; const uint8_t USER_COLLISION_GROUP_MY_AVATAR = 1 << 3; const uint8_t USER_COLLISION_GROUP_OTHER_AVATAR = 1 << 4; const uint8_t ENTITY_COLLISION_MASK_DEFAULT = - USER_COLLISION_GROUP_DYNAMIC | USER_COLLISION_GROUP_STATIC | + USER_COLLISION_GROUP_DYNAMIC | USER_COLLISION_GROUP_KINEMATIC | USER_COLLISION_GROUP_MY_AVATAR | USER_COLLISION_GROUP_OTHER_AVATAR; From 6c49d81475e19fb9873ddf89837bbbbb984c245c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 Jan 2016 16:56:13 -0800 Subject: [PATCH 102/215] collision mask bit reinterpretation also cache sessionID in static methods inside PhysicsEngine --- libraries/entities/src/EntityItem.h | 2 +- libraries/physics/src/EntityMotionState.cpp | 36 ++++++++++++++----- libraries/physics/src/EntityMotionState.h | 4 +-- libraries/physics/src/ObjectMotionState.cpp | 6 ++-- libraries/physics/src/ObjectMotionState.h | 2 +- libraries/physics/src/PhysicsEngine.cpp | 15 +++++++- libraries/physics/src/PhysicsEngine.h | 5 ++- libraries/shared/src/PhysicsCollisionGroups.h | 1 + 8 files changed, 52 insertions(+), 19 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index d3b52814a3..d526ffec0d 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -275,7 +275,7 @@ public: void setIgnoreForCollisions(bool value) { _ignoreForCollisions = value; } uint8_t getCollisionMask() const { return _collisionMask; } - void setCollisionMask(uint8_t value); + void setCollisionMask(uint8_t value) { _collisionMask = value; } bool getCollisionsWillMove() const { return _collisionsWillMove; } void setCollisionsWillMove(bool value) { _collisionsWillMove = value; } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 956ed9fedd..f75469e820 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -80,9 +80,9 @@ EntityMotionState::~EntityMotionState() { _entity = nullptr; } -void EntityMotionState::updateServerPhysicsVariables(const QUuid& sessionID) { +void EntityMotionState::updateServerPhysicsVariables() { assert(entityTreeIsLocked()); - if (_entity->getSimulatorID() == sessionID) { + if (_entity->getSimulatorID() == PhysicsEngine::getSessionID()) { // don't slam these values if we are the simulation owner return; } @@ -96,10 +96,10 @@ void EntityMotionState::updateServerPhysicsVariables(const QUuid& sessionID) { } // virtual -bool EntityMotionState::handleEasyChanges(uint32_t& flags, PhysicsEngine* engine) { +bool EntityMotionState::handleEasyChanges(uint32_t& flags) { assert(entityTreeIsLocked()); - updateServerPhysicsVariables(engine->getSessionID()); - ObjectMotionState::handleEasyChanges(flags, engine); + updateServerPhysicsVariables(); + ObjectMotionState::handleEasyChanges(flags); if (flags & Simulation::DIRTY_SIMULATOR_ID) { _loopsWithoutOwner = 0; @@ -113,7 +113,7 @@ bool EntityMotionState::handleEasyChanges(uint32_t& flags, PhysicsEngine* engine _outgoingPriority = NO_PRORITY; } else { _nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS; - if (engine->getSessionID() == _entity->getSimulatorID() || _entity->getSimulationPriority() >= _outgoingPriority) { + if (PhysicsEngine::getSessionID() == _entity->getSimulatorID() || _entity->getSimulationPriority() >= _outgoingPriority) { // we own the simulation or our priority looses to (or ties with) remote _outgoingPriority = NO_PRORITY; } @@ -135,7 +135,7 @@ bool EntityMotionState::handleEasyChanges(uint32_t& flags, PhysicsEngine* engine // virtual bool EntityMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) { - updateServerPhysicsVariables(engine->getSessionID()); + updateServerPhysicsVariables(); return ObjectMotionState::handleHardAndEasyChanges(flags, engine); } @@ -523,6 +523,17 @@ uint32_t EntityMotionState::getIncomingDirtyFlags() { uint32_t dirtyFlags = 0; if (_body && _entity) { dirtyFlags = _entity->getDirtyFlags(); + + if (dirtyFlags | Simulation::DIRTY_SIMULATOR_ID) { + // when SIMULATOR_ID changes we must check for reinterpretation of asymmetric collision mask + // bits for the avatar groups (e.g. MY_AVATAR vs OTHER_AVATAR) + uint8_t entityCollisionMask = _entity->getCollisionMask(); + if ((bool)(entityCollisionMask & USER_COLLISION_GROUP_MY_AVATAR) != + (bool)(entityCollisionMask & USER_COLLISION_GROUP_OTHER_AVATAR)) { + // bits are asymmetric --> flag for reinsertion in physics simulation + dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; + } + } // we add DIRTY_MOTION_TYPE if the body's motion type disagrees with entity velocity settings int bodyFlags = _body->getCollisionFlags(); bool isMoving = _entity->isMoving(); @@ -633,7 +644,16 @@ void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& ma mask = PhysicsEngine::getCollisionMask(group); if (_entity) { - mask &= (int16_t)(_entity->getCollisionMask()); + uint8_t entityCollisionMask = _entity->getCollisionMask(); + if ((bool)(entityCollisionMask & USER_COLLISION_GROUP_MY_AVATAR) != + (bool)(entityCollisionMask & USER_COLLISION_GROUP_OTHER_AVATAR)) { + // asymmetric avatar collision mask bits + if (!_entity->getSimulatorID().isNull() && _entity->getSimulatorID() != PhysicsEngine::getSessionID()) { + // someone else owns the simulation, so we swap the interpretation of the bits + entityCollisionMask ^= USER_COLLISION_MASK_AVATARS | ~entityCollisionMask; + } + } + mask &= (int16_t)(entityCollisionMask); } } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index e543ee024e..7d7987b641 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -28,8 +28,8 @@ public: EntityMotionState(btCollisionShape* shape, EntityItemPointer item); virtual ~EntityMotionState(); - void updateServerPhysicsVariables(const QUuid& sessionID); - virtual bool handleEasyChanges(uint32_t& flags, PhysicsEngine* engine); + void updateServerPhysicsVariables(); + virtual bool handleEasyChanges(uint32_t& flags); virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine); /// \return MOTION_TYPE_DYNAMIC or MOTION_TYPE_STATIC based on params set in EntityItem diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index c434f67ad2..ecce821adf 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -164,7 +164,7 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) { } } -bool ObjectMotionState::handleEasyChanges(uint32_t& flags, PhysicsEngine* engine) { +bool ObjectMotionState::handleEasyChanges(uint32_t& flags) { if (flags & Simulation::DIRTY_POSITION) { btTransform worldTrans = _body->getWorldTransform(); btVector3 newPosition = glmToBullet(getObjectPosition()); @@ -251,7 +251,7 @@ bool ObjectMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* if ((flags & HARD_DIRTY_PHYSICS_FLAGS) == 0) { // no HARD flags remain, so do any EASY changes if (flags & EASY_DIRTY_PHYSICS_FLAGS) { - handleEasyChanges(flags, engine); + handleEasyChanges(flags); } return true; } @@ -268,7 +268,7 @@ bool ObjectMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* } } if (flags & EASY_DIRTY_PHYSICS_FLAGS) { - handleEasyChanges(flags, engine); + handleEasyChanges(flags); } // it is possible there are no HARD flags at this point (if DIRTY_SHAPE was removed) // so we check again before we reinsert: diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index bbdf6c408a..4a90b1d985 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -80,7 +80,7 @@ public: ObjectMotionState(btCollisionShape* shape); ~ObjectMotionState(); - virtual bool handleEasyChanges(uint32_t& flags, PhysicsEngine* engine); + virtual bool handleEasyChanges(uint32_t& flags); virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine); void updateBodyMaterialProperties(); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index b2823746ee..b665be5d53 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -42,6 +42,19 @@ int16_t PhysicsEngine::getCollisionMask(int16_t group) { return mask ? *mask : BULLET_COLLISION_MASK_DEFAULT; } +QUuid _sessionID; + +// static +void PhysicsEngine::setSessionUUID(const QUuid& sessionID) { + _sessionID = sessionID; +} + +// static +const QUuid& PhysicsEngine::getSessionID() { + return _sessionID; +} + + PhysicsEngine::PhysicsEngine(const glm::vec3& offset) : _originOffset(offset), _myAvatarController(nullptr) { @@ -209,7 +222,7 @@ VectorOfMotionStates PhysicsEngine::changeObjects(const VectorOfMotionStates& ob stillNeedChange.push_back(object); } } else if (flags & EASY_DIRTY_PHYSICS_FLAGS) { - if (object->handleEasyChanges(flags, this)) { + if (object->handleEasyChanges(flags)) { object->clearIncomingDirtyFlags(); } else { stillNeedChange.push_back(object); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index b2a44b7a3c..c42fe2f66e 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -53,8 +53,8 @@ public: ~PhysicsEngine(); void init(); - void setSessionUUID(const QUuid& sessionID) { _sessionID = sessionID; } - const QUuid& getSessionID() const { return _sessionID; } + static void setSessionUUID(const QUuid& sessionID); + static const QUuid& getSessionID(); void removeObjects(const VectorOfMotionStates& objects); void removeObjects(const SetOfMotionStates& objects); // only called during teardown @@ -122,7 +122,6 @@ private: bool _dumpNextStats = false; bool _hasOutgoingChanges = false; - QUuid _sessionID; CollisionEvents _collisionEvents; QHash _objectActions; diff --git a/libraries/shared/src/PhysicsCollisionGroups.h b/libraries/shared/src/PhysicsCollisionGroups.h index a86722a084..e7f9d57fef 100644 --- a/libraries/shared/src/PhysicsCollisionGroups.h +++ b/libraries/shared/src/PhysicsCollisionGroups.h @@ -80,5 +80,6 @@ const uint8_t ENTITY_COLLISION_MASK_DEFAULT = USER_COLLISION_GROUP_MY_AVATAR | USER_COLLISION_GROUP_OTHER_AVATAR; +const uint8_t USER_COLLISION_MASK_AVATARS = USER_COLLISION_GROUP_MY_AVATAR | USER_COLLISION_GROUP_OTHER_AVATAR; #endif // hifi_PhysicsCollisionGroups_h From 00e5d040a21e654d84528e41133c9ffc0cbead78 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 8 Jan 2016 10:47:14 -0800 Subject: [PATCH 103/215] use collision masks to prevent grab-bootstrap --- examples/controllers/handControllerGrab.js | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 0e1a42863e..06fde5e002 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -106,7 +106,7 @@ var GRABBABLE_PROPERTIES = [ "position", "rotation", "gravity", - "ignoreForCollisions", + "collisionMask", "collisionsWillMove", "locked", "name" @@ -117,7 +117,6 @@ var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js var DEFAULT_GRABBABLE_DATA = { grabbable: true, - invertSolidWhileHeld: false }; @@ -164,6 +163,14 @@ var POINT_HAND_STATES = [STATE_NEAR_TRIGGER, STATE_CONTINUE_NEAR_TRIGGER, STATE_ var FAR_GRASP_HAND_STATES = [STATE_DISTANCE_HOLDING, STATE_CONTINUE_DISTANCE_HOLDING]; // otherwise grasp +var COLLISION_GROUP_STATIC = 0x01; // bit 0 +var COLLISION_GROUP_DYNAMIC = 0x02; // bit 1 +var COLLISION_GROUP_KINEMATIC = 0x04; // bit 2 +var COLLISION_GROUP_MY_AVATAR = 0x08; // bit 3 +var COLLISION_GROUP_OTHER_AVATAR = 0x10; // bit 4 +var COLLISION_MASK_WHILE_GRABBED = COLLISION_GROUP_DYNAMIC | COLLISION_GROUP_OTHER_AVATAR; + + function stateToName(state) { switch (state) { case STATE_OFF: @@ -1823,7 +1830,6 @@ function MyController(hand) { this.activateEntity = function(entityID, grabbedProperties) { var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, entityID, DEFAULT_GRABBABLE_DATA); - var invertSolidWhileHeld = grabbableData["invertSolidWhileHeld"]; var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); data["activated"] = true; data["avatarId"] = MyAvatar.sessionUUID; @@ -1831,18 +1837,16 @@ function MyController(hand) { // zero gravity and set ignoreForCollisions in a way that lets us put them back, after all grabs are done if (data["refCount"] == 1) { data["gravity"] = grabbedProperties.gravity; - data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions; + data["collisionMask"] = grabbedProperties.collisionMask; data["collisionsWillMove"] = grabbedProperties.collisionsWillMove; var whileHeldProperties = { gravity: { x: 0, y: 0, z: 0 - } + }, + collisionMask: COLLISION_MASK_WHILE_GRABBED & grabbedProperties.collisionMask }; - if (invertSolidWhileHeld) { - whileHeldProperties["ignoreForCollisions"] = !grabbedProperties.ignoreForCollisions; - } Entities.editEntity(entityID, whileHeldProperties); } @@ -1857,7 +1861,7 @@ function MyController(hand) { if (data["refCount"] < 1) { Entities.editEntity(entityID, { gravity: data["gravity"], - ignoreForCollisions: data["ignoreForCollisions"], + collisionMask: data["collisionMask"], collisionsWillMove: data["collisionsWillMove"] }); data = null; From 222398e5cc942edc13c54983701485dc6fec1011 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 8 Jan 2016 11:46:40 -0800 Subject: [PATCH 104/215] no packet version check for collision mask --- libraries/entities/src/EntityItem.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index c04d280132..0a7a30f098 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -681,9 +681,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible); READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, updateIgnoreForCollisions); - if (args.bitstreamVersion >= VERSION_ENTITITES_HAVE_COLLISION_MASK) { - READ_ENTITY_PROPERTY(PROP_COLLISION_MASK, uint8_t, updateCollisionMask); - } + READ_ENTITY_PROPERTY(PROP_COLLISION_MASK, uint8_t, updateCollisionMask); READ_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, bool, updateCollisionsWillMove); READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData); From c52c543ab8482248f76741d6f58ca35411fe6d7b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 8 Jan 2016 20:24:37 -0800 Subject: [PATCH 105/215] use strings for JS collisionGroup API --- examples/controllers/handControllerGrab.js | 11 ++-- .../entities/src/EntityItemProperties.cpp | 57 ++++++++++++++++++- libraries/entities/src/EntityItemProperties.h | 4 ++ libraries/shared/src/PhysicsCollisionGroups.h | 2 + 4 files changed, 65 insertions(+), 9 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 06fde5e002..be5fdd7edb 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -163,12 +163,9 @@ var POINT_HAND_STATES = [STATE_NEAR_TRIGGER, STATE_CONTINUE_NEAR_TRIGGER, STATE_ var FAR_GRASP_HAND_STATES = [STATE_DISTANCE_HOLDING, STATE_CONTINUE_DISTANCE_HOLDING]; // otherwise grasp -var COLLISION_GROUP_STATIC = 0x01; // bit 0 -var COLLISION_GROUP_DYNAMIC = 0x02; // bit 1 -var COLLISION_GROUP_KINEMATIC = 0x04; // bit 2 -var COLLISION_GROUP_MY_AVATAR = 0x08; // bit 3 -var COLLISION_GROUP_OTHER_AVATAR = 0x10; // bit 4 -var COLLISION_MASK_WHILE_GRABBED = COLLISION_GROUP_DYNAMIC | COLLISION_GROUP_OTHER_AVATAR; +// collision masks are specified by comma-separated list of group names +// the possible list of names is: static, dynamic, kinematic, myAvatar, otherAvatar +var COLLISION_MASK_WHILE_GRABBED = "dynamic,otherAvatar"; function stateToName(state) { @@ -1845,7 +1842,7 @@ function MyController(hand) { y: 0, z: 0 }, - collisionMask: COLLISION_MASK_WHILE_GRABBED & grabbedProperties.collisionMask + "collisionMask": COLLISION_MASK_WHILE_GRABBED }; Entities.editEntity(entityID, whileHeldProperties); } diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index d647896d1f..f8dcb6ee56 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -116,6 +116,59 @@ void buildStringToShapeTypeLookup() { addShapeType(SHAPE_TYPE_CYLINDER_Z); } +QString getCollisionGroupAsString(uint8_t group) { + switch (group) { + case USER_COLLISION_GROUP_DYNAMIC: + return "dynamic"; + case USER_COLLISION_GROUP_STATIC: + return "static"; + case USER_COLLISION_GROUP_KINEMATIC: + return "kinematic"; + case USER_COLLISION_GROUP_MY_AVATAR: + return "myAvatar"; + case USER_COLLISION_GROUP_OTHER_AVATAR: + return "otherAvatar"; + }; + return ""; +} + +uint8_t getCollisionGroupAsBitMask(const QStringRef& name) { + if (0 == name.compare("dynamic")) { + return USER_COLLISION_GROUP_DYNAMIC; + } else if (0 == name.compare("static")) { + return USER_COLLISION_GROUP_STATIC; + } else if (0 == name.compare("kinematic")) { + return USER_COLLISION_GROUP_KINEMATIC; + } else if (0 == name.compare("myAvatar")) { + return USER_COLLISION_GROUP_MY_AVATAR; + } else if (0 == name.compare("otherAvatar")) { + return USER_COLLISION_GROUP_OTHER_AVATAR; + } + return 0; +} + +QString EntityItemProperties::getCollisionMaskAsString() const { + QString maskString(""); + for (int i = 0; i < NUM_USER_COLLISION_GROUPS; ++i) { + uint8_t group = 0x01 << i; + if (group & _collisionMask) { + maskString.append(getCollisionGroupAsString(group)); + maskString.append(','); + } + } + return maskString; +} + +void EntityItemProperties::setCollisionMaskFromString(const QString& maskString) { + QVector groups = maskString.splitRef(','); + uint8_t mask = 0x00; + for (auto group : groups) { + mask |= getCollisionGroupAsBitMask(group); + } + _collisionMask = mask; + _collisionMaskChanged = true; +} + QString EntityItemProperties::getShapeTypeAsString() const { if (_shapeType < sizeof(shapeTypeNames) / sizeof(char *)) return QString(shapeTypeNames[_shapeType]); @@ -318,7 +371,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_DAMPING, angularDamping); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE, visible); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_MASK, collisionMask); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_COLLISION_MASK, collisionMask, getCollisionMaskAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISIONS_WILL_MOVE, collisionsWillMove); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_HREF, href); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DESCRIPTION, description); @@ -540,7 +593,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(glowLevel, float, setGlowLevel); COPY_PROPERTY_FROM_QSCRIPTVALUE(localRenderAlpha, float, setLocalRenderAlpha); COPY_PROPERTY_FROM_QSCRIPTVALUE(ignoreForCollisions, bool, setIgnoreForCollisions); - COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionMask, uint8_t, setCollisionMask); + COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(collisionMask, CollisionMask); COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionsWillMove, bool, setCollisionsWillMove); COPY_PROPERTY_FROM_QSCRIPTVALUE(isSpotlight, bool, setIsSpotlight); COPY_PROPERTY_FROM_QSCRIPTVALUE(intensity, float, setIntensity); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 46af6a1da9..087925b139 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -274,6 +274,10 @@ public: void setJointRotationsDirty() { _jointRotationsSetChanged = true; _jointRotationsChanged = true; } void setJointTranslationsDirty() { _jointTranslationsSetChanged = true; _jointTranslationsChanged = true; } +protected: + QString getCollisionMaskAsString() const; + void setCollisionMaskFromString(const QString& maskString); + private: QUuid _id; bool _idSet; diff --git a/libraries/shared/src/PhysicsCollisionGroups.h b/libraries/shared/src/PhysicsCollisionGroups.h index e7f9d57fef..6d320e69cb 100644 --- a/libraries/shared/src/PhysicsCollisionGroups.h +++ b/libraries/shared/src/PhysicsCollisionGroups.h @@ -82,4 +82,6 @@ const uint8_t ENTITY_COLLISION_MASK_DEFAULT = const uint8_t USER_COLLISION_MASK_AVATARS = USER_COLLISION_GROUP_MY_AVATAR | USER_COLLISION_GROUP_OTHER_AVATAR; +const int NUM_USER_COLLISION_GROUPS = 5; + #endif // hifi_PhysicsCollisionGroups_h From 2288d96868339be5725161ecc5252de88a6c3925 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 12 Jan 2016 10:20:35 -0800 Subject: [PATCH 106/215] fix CharacterController ray cast for floor --- libraries/physics/src/CharacterController.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 0797058f05..7c2ca31f8f 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -27,6 +27,9 @@ class ClosestNotMe : public btCollisionWorld::ClosestRayResultCallback { public: ClosestNotMe(btRigidBody* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0f, 0.0f, 0.0f), btVector3(0.0f, 0.0f, 0.0f)) { _me = me; + // the RayResultCallback's group and mask must match MY_AVATAR + m_collisionFilterGroup = BULLET_COLLISION_GROUP_MY_AVATAR; + m_collisionFilterMask = BULLET_COLLISION_MASK_MY_AVATAR; } virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) { if (rayResult.m_collisionObject == _me) { From 6a5a74700fa508d03cb8dd9acb1396e1c2dbbb9e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 12 Jan 2016 12:53:35 -0800 Subject: [PATCH 107/215] activate sprung objects when action strong enough --- libraries/physics/src/ObjectActionSpring.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/libraries/physics/src/ObjectActionSpring.cpp b/libraries/physics/src/ObjectActionSpring.cpp index d9d6a323a7..a737a2b8b6 100644 --- a/libraries/physics/src/ObjectActionSpring.cpp +++ b/libraries/physics/src/ObjectActionSpring.cpp @@ -62,9 +62,10 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) { float offsetLength = offset.length(); btVector3 targetVelocity(0.0f, 0.0f, 0.0f); - if (offsetLength > 0) { - float speed = (offsetLength > FLT_EPSILON) ? glm::min(offsetLength / _linearTimeScale, SPRING_MAX_SPEED) : 0.0f; + float speed = (offsetLength > FLT_EPSILON) ? glm::min(offsetLength / _linearTimeScale, SPRING_MAX_SPEED) : 0.0f; + if (speed > rigidBody->getLinearSleepingThreshold()) { targetVelocity = (-speed / offsetLength) * offset; + rigidBody->activate(); } // this action is aggresively critically damped and defeats the current velocity @@ -90,10 +91,10 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) { // // dQ = Q1 * Q0^ btQuaternion deltaQ = target * bodyRotation.inverse(); - float angle = deltaQ.getAngle(); - const float MIN_ANGLE = 1.0e-4f; - if (angle > MIN_ANGLE) { - targetVelocity = (angle / _angularTimeScale) * deltaQ.getAxis(); + float speed = deltaQ.getAngle() / _angularTimeScale; + if (speed > rigidBody->getAngularSleepingThreshold()) { + targetVelocity = speed * deltaQ.getAxis(); + rigidBody->activate(); } } // this action is aggresively critically damped and defeats the current velocity From 1128982e65eb1b156c866e1a6bb06ecb75c06807 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 12 Jan 2016 17:16:56 -0800 Subject: [PATCH 108/215] pull grab script changes over from another branch --- examples/controllers/handControllerGrab.js | 311 ++++++++------------- 1 file changed, 121 insertions(+), 190 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index be5fdd7edb..3494e51434 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -93,7 +93,7 @@ var ZERO_VEC = { z: 0 }; -var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}"; +var NULL_UUID = "{00000000-0000-0000-0000-000000000000}"; var MSEC_PER_SEC = 1000.0; // these control how long an abandoned pointer line or action will hang around @@ -109,7 +109,10 @@ var GRABBABLE_PROPERTIES = [ "collisionMask", "collisionsWillMove", "locked", - "name" + "name", + "shapeType", + "parentID", + "parentJointIndex" ]; var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js @@ -117,9 +120,11 @@ var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js var DEFAULT_GRABBABLE_DATA = { grabbable: true, + disableReleaseVelocity: false }; + // sometimes we want to exclude objects from being picked var USE_BLACKLIST = true; var blacklist = []; @@ -167,7 +172,6 @@ var FAR_GRASP_HAND_STATES = [STATE_DISTANCE_HOLDING, STATE_CONTINUE_DISTANCE_HOL // the possible list of names is: static, dynamic, kinematic, myAvatar, otherAvatar var COLLISION_MASK_WHILE_GRABBED = "dynamic,otherAvatar"; - function stateToName(state) { switch (state) { case STATE_OFF: @@ -374,8 +378,6 @@ function MyController(hand) { var SPATIAL_CONTROLLERS_PER_PALM = 2; var TIP_CONTROLLER_OFFSET = 1; - this.palm = SPATIAL_CONTROLLERS_PER_PALM * hand; - this.tip = SPATIAL_CONTROLLERS_PER_PALM * hand + TIP_CONTROLLER_OFFSET; this.actionID = null; // action this script created... this.grabbedEntity = null; // on this entity. @@ -823,6 +825,10 @@ function MyController(hand) { } }; + this.propsArePhysical = function(props) { + var isPhysical = (props.shapeType && props.shapeType != 'none'); + return isPhysical; + } this.turnOffVisualizations = function() { if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) { @@ -897,7 +903,6 @@ function MyController(hand) { // the trigger is being pressed, so do a ray test to see what we are hitting var handPosition = this.getHandPosition(); - var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; var currentHandRotation = Controller.getPoseValue(controllerHandInput).rotation; var handDeltaRotation = Quat.multiply(currentHandRotation, Quat.inverse(this.startingHandRotation)); @@ -922,6 +927,9 @@ function MyController(hand) { this.lastPickTime = now; } + rayPickedCandidateEntities = []; // the list of candidates to consider grabbing + + this.intersectionDistance = 0.0; for (var index = 0; index < pickRays.length; ++index) { var pickRay = pickRays[index]; var directionNormalized = Vec3.normalize(pickRay.direction); @@ -931,14 +939,6 @@ function MyController(hand) { direction: pickRay.direction }; - if (WANT_DEBUG) { - this.debugLine(pickRayBacked.origin, Vec3.multiply(pickRayBacked.direction, NEAR_PICK_MAX_DISTANCE), { - red: 0, - green: 255, - blue: 0 - }) - } - Messages.sendMessage('Hifi-Light-Overlay-Ray-Check', JSON.stringify(pickRayBacked)); var intersection; @@ -949,189 +949,85 @@ function MyController(hand) { intersection = Entities.findRayIntersection(pickRayBacked, true); } - if (intersection.intersects) { - - // the ray is intersecting something we can move. + rayPickedCandidateEntities.push(intersection.entityID); this.intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); - - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA); - var defaultDisableNearGrabData = { - disableNearGrab: false - }; - //sometimes we want things to stay right where they are when we let go. - var disableNearGrabData = getEntityCustomData('handControllerKey', intersection.entityID, defaultDisableNearGrabData); - - if (intersection.properties.name == "Grab Debug Entity") { - continue; - } - - if (typeof grabbableData.grabbable !== 'undefined' && !grabbableData.grabbable) { - continue; - } - if (this.intersectionDistance > pickRay.length) { - // too far away for this ray. - continue; - } - if (this.intersectionDistance <= NEAR_PICK_MAX_DISTANCE) { - // the hand is very close to the intersected object. go into close-grabbing mode. - if (grabbableData.wantsTrigger) { - this.grabbedEntity = intersection.entityID; - this.setState(STATE_NEAR_TRIGGER); - return; - } else if (!intersection.properties.locked) { - this.grabbedEntity = intersection.entityID; - if (this.state == STATE_SEARCHING) { - if (disableNearGrabData.disableNearGrab !== true) { - this.setState(STATE_NEAR_GRABBING); - } else { - //disable near grab on this thing - } - } else { // equipping - if (typeof grabbableData.spatialKey !== 'undefined') { - // TODO - // if we go to STATE_EQUIP_SPRING the item will be pulled to the hand and will then switch - // to STATE_EQUIP. This needs some debugging, so just jump straight to STATE_EQUIP here. - // this.setState(STATE_EQUIP_SPRING); - this.setState(STATE_EQUIP); - } else { - this.setState(STATE_EQUIP); - } - } - return; - } - } else if (!entityIsGrabbedByOther(intersection.entityID)) { - // don't allow two people to distance grab the same object - if (intersection.properties.collisionsWillMove && !intersection.properties.locked) { - // the hand is far from the intersected object. go into distance-holding mode - this.grabbedEntity = intersection.entityID; - if (this.state == STATE_EQUIP_SEARCHING) { - // if a distance pick in equip mode hits something with a spatialKey, equip it - // TODO use STATE_EQUIP_SPRING here once it works right. - // this.setState(STATE_EQUIP_SPRING); - if (typeof grabbableData.spatialKey === 'undefined') { - // We want to give a temporary position offset to this object so it is pulled close to hand - var intersectionPointToCenterDistance = Vec3.length(Vec3.subtract(intersection.intersection, intersection.properties.position)); - this.temporaryPositionOffset = Vec3.normalize(Vec3.subtract(intersection.properties.position, handPosition)); - this.temporaryPositionOffset = Vec3.multiply(this.temporaryPositionOffset, intersectionPointToCenterDistance * FAR_TO_NEAR_GRAB_PADDING_FACTOR); - - } - this.setState(STATE_EQUIP); - this.turnOffVisualizations(); - return; - } else if ((this.state == STATE_SEARCHING) && this.triggerSmoothedGrab()) { - this.setState(STATE_DISTANCE_HOLDING); - return; - } - } else if (grabbableData.wantsTrigger && this.triggerSmoothedGrab()) { - this.grabbedEntity = intersection.entityID; - this.setState(STATE_FAR_TRIGGER); - return; - } - } } } + nearPickedCandidateEntities = Entities.findEntities(handPosition, GRAB_RADIUS); + candidateEntities = rayPickedCandidateEntities.concat(nearPickedCandidateEntities); - // forward ray test failed, try sphere test. - if (WANT_DEBUG) { - Entities.addEntity({ - type: "Sphere", - name: "Grab Debug Entity", - dimensions: { - x: GRAB_RADIUS, - y: GRAB_RADIUS, - z: GRAB_RADIUS - }, - visible: true, - position: handPosition, - color: { - red: 0, - green: 255, - blue: 0 - }, - lifetime: 0.1, - collisionsWillMove: false, - ignoreForCollisions: true, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }) - }); - } + var forbiddenNames = ["Grab Debug Entity", "grab pointer"]; + var forbiddenTyes = ['Unknown', 'Light', 'ParticleEffect', 'PolyLine', 'Zone']; - var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS); var minDistance = PICK_MAX_DISTANCE; var i, props, distance, grabbableData; this.grabbedEntity = null; - for (i = 0; i < nearbyEntities.length; i++) { + for (i = 0; i < candidateEntities.length; i++) { var grabbableDataForCandidate = - getEntityCustomData(GRABBABLE_DATA_KEY, nearbyEntities[i], DEFAULT_GRABBABLE_DATA); - if (typeof grabbableDataForCandidate.grabbable !== 'undefined' && !grabbableDataForCandidate.grabbable) { + getEntityCustomData(GRABBABLE_DATA_KEY, candidateEntities[i], DEFAULT_GRABBABLE_DATA); + var propsForCandidate = Entities.getEntityProperties(candidateEntities[i], GRABBABLE_PROPERTIES); + var grabbable = (typeof grabbableDataForCandidate.grabbable === 'undefined' || grabbableDataForCandidate.grabbable); + if (!grabbable && !grabbableDataForCandidate.wantsTrigger) { continue; } - var propsForCandidate = Entities.getEntityProperties(nearbyEntities[i], GRABBABLE_PROPERTIES); - - if (propsForCandidate.type == 'Unknown') { + if (forbiddenTyes.indexOf(propsForCandidate.type) >= 0) { continue; } - - if (propsForCandidate.type == 'Light') { - continue; - } - - if (propsForCandidate.type == 'ParticleEffect') { - continue; - } - - if (propsForCandidate.type == 'PolyLine') { - continue; - } - - if (propsForCandidate.type == 'Zone') { - continue; - } - if (propsForCandidate.locked && !grabbableDataForCandidate.wantsTrigger) { continue; } - - if (propsForCandidate.name == "Grab Debug Entity") { - continue; - } - - if (propsForCandidate.name == "grab pointer") { + if (forbiddenNames.indexOf(propsForCandidate.name) >= 0) { continue; } distance = Vec3.distance(propsForCandidate.position, handPosition); + if (distance > PICK_MAX_DISTANCE) { + // too far away, don't grab + continue; + } if (distance < minDistance) { - this.grabbedEntity = nearbyEntities[i]; + this.grabbedEntity = candidateEntities[i]; minDistance = distance; props = propsForCandidate; grabbableData = grabbableDataForCandidate; } } if (this.grabbedEntity !== null) { + // We've found an entity that we'll do something with. + var near = (nearPickedCandidateEntities.indexOf(this.grabbedEntity) >= 0); + var isPhysical = this.propsArePhysical(props); + + // near or far trigger if (grabbableData.wantsTrigger) { - this.setState(STATE_NEAR_TRIGGER); - return; - } else if (!props.locked && props.collisionsWillMove) { - var defaultDisableNearGrabData = { - disableNearGrab: false - }; - //sometimes we want things to stay right where they are when we let go. - var disableNearGrabData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultDisableNearGrabData); - if (disableNearGrabData.disableNearGrab === true) { - //do nothing because near grab is disabled for this object - } else { - this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP) - - } - + this.setState(near ? STATE_NEAR_TRIGGER : STATE_FAR_TRIGGER); return; } + // near grab or equip with action + if (isPhysical && near) { + this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP); + return; + } + // far grab or equip with action + if (isPhysical && !near) { + this.temporaryPositionOffset = null; + if (typeof grabbableData.spatialKey === 'undefined') { + // We want to give a temporary position offset to this object so it is pulled close to hand + var intersectionPointToCenterDistance = Vec3.length(Vec3.subtract(intersection.intersection, + intersection.properties.position)); + this.temporaryPositionOffset = Vec3.normalize(Vec3.subtract(intersection.properties.position, handPosition)); + this.temporaryPositionOffset = Vec3.multiply(this.temporaryPositionOffset, + intersectionPointToCenterDistance * + FAR_TO_NEAR_GRAB_PADDING_FACTOR); + } + this.setState(this.state == STATE_SEARCHING ? STATE_DISTANCE_HOLDING : STATE_EQUIP); + return; + } + + // else this thing isn't physical. grab it by reparenting it. + this.setState(STATE_NEAR_GRABBING); + return; } //search line visualizations @@ -1144,19 +1040,30 @@ function MyController(hand) { } if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { - this.overlayLineOn(searchVisualizationPickRay.origin, Vec3.sum(searchVisualizationPickRay.origin, Vec3.multiply(searchVisualizationPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); + this.overlayLineOn(searchVisualizationPickRay.origin, + Vec3.sum(searchVisualizationPickRay.origin, + Vec3.multiply(searchVisualizationPickRay.direction, + LINE_LENGTH)), + NO_INTERSECT_COLOR); } if (this.intersectionDistance > 0) { var SPHERE_INTERSECTION_SIZE = 0.011; var SEARCH_SPHERE_FOLLOW_RATE = 0.50; var SEARCH_SPHERE_CHASE_DROP = 0.2; - this.searchSphereDistance = this.searchSphereDistance * SEARCH_SPHERE_FOLLOW_RATE + this.intersectionDistance * (1.0 - SEARCH_SPHERE_FOLLOW_RATE); - var searchSphereLocation = Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, this.searchSphereDistance)); - searchSphereLocation.y -= ((this.intersectionDistance - this.searchSphereDistance) / this.intersectionDistance) * SEARCH_SPHERE_CHASE_DROP; - this.searchSphereOn(searchSphereLocation, SPHERE_INTERSECTION_SIZE * this.intersectionDistance, this.triggerSmoothedGrab() ? INTERSECT_COLOR : NO_INTERSECT_COLOR); + this.searchSphereDistance = this.searchSphereDistance * SEARCH_SPHERE_FOLLOW_RATE + + this.intersectionDistance * (1.0 - SEARCH_SPHERE_FOLLOW_RATE); + var searchSphereLocation = Vec3.sum(distantPickRay.origin, + Vec3.multiply(distantPickRay.direction, this.searchSphereDistance)); + searchSphereLocation.y -= ((this.intersectionDistance - this.searchSphereDistance) / + this.intersectionDistance) * SEARCH_SPHERE_CHASE_DROP; + this.searchSphereOn(searchSphereLocation, + SPHERE_INTERSECTION_SIZE * this.intersectionDistance, + this.triggerSmoothedGrab() ? INTERSECT_COLOR : NO_INTERSECT_COLOR); if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { - this.overlayLineOn(handPosition, searchSphereLocation, this.triggerSmoothedGrab() ? INTERSECT_COLOR : NO_INTERSECT_COLOR); + this.overlayLineOn(handPosition, + searchSphereLocation, + this.triggerSmoothedGrab() ? INTERSECT_COLOR : NO_INTERSECT_COLOR); } } }; @@ -1182,7 +1089,7 @@ function MyController(hand) { this.radiusScalar = 1.0; } - this.actionID = NULL_ACTION_ID; + this.actionID = NULL_UUID; this.actionID = Entities.addAction("spring", this.grabbedEntity, { targetPosition: this.currentObjectPosition, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, @@ -1191,7 +1098,7 @@ function MyController(hand) { tag: getTag(), ttl: ACTION_TTL }); - if (this.actionID === NULL_ACTION_ID) { + if (this.actionID === NULL_UUID) { this.actionID = null; } this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); @@ -1380,7 +1287,6 @@ function MyController(hand) { } }; - this.setupHoldAction = function() { this.actionID = Entities.addAction("hold", this.grabbedEntity, { hand: this.hand === RIGHT_HAND ? "right" : "left", @@ -1392,7 +1298,7 @@ function MyController(hand) { kinematicSetVelocity: true, ignoreIK: this.ignoreIK }); - if (this.actionID === NULL_ACTION_ID) { + if (this.actionID === NULL_UUID) { this.actionID = null; return false; } @@ -1427,7 +1333,6 @@ function MyController(hand) { var projection = Vec3.sum(axisStart, Vec3.multiply(scalar, Vec3.normalize(bPrime))); return projection - }; this.nearGrabbing = function() { @@ -1475,9 +1380,19 @@ function MyController(hand) { } } - - if (!this.setupHoldAction()) { - return; + var isPhysical = this.propsArePhysical(grabbedProperties); + if (isPhysical) { + // grab entity via action + if (!this.setupHoldAction()) { + return; + } + } else { + // grab entity via parenting + var handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); + Entities.editEntity(this.grabbedEntity, { + parentID: MyAvatar.sessionUUID, + parentJointIndex: handJointIndex + }); } if (this.state == STATE_NEAR_GRABBING) { @@ -1544,7 +1459,13 @@ function MyController(hand) { Entities.callEntityMethod(this.grabbedEntity, "continueEquip"); } - if (this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) { + //// jbp::: SEND UPDATE MESSAGE TO WEARABLES MANAGER + Messages.sendMessage('Hifi-Wearables-Manager', JSON.stringify({ + action: 'update', + grabbedEntity: this.grabbedEntity + })) + + if (this.actionID && this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) { // if less than a 5 seconds left, refresh the actions ttl var success = Entities.updateAction(this.grabbedEntity, this.actionID, { hand: this.hand === RIGHT_HAND ? "right" : "left", @@ -1593,7 +1514,7 @@ function MyController(hand) { if (typeof this.equipSpringID === 'undefined' || this.equipSpringID === null || - this.equipSpringID === NULL_ACTION_ID) { + this.equipSpringID === NULL_UUID) { this.equipSpringID = Entities.addAction("spring", this.grabbedEntity, { targetPosition: targetPosition, linearTimeScale: EQUIP_SPRING_TIMEFRAME, @@ -1602,7 +1523,7 @@ function MyController(hand) { ttl: ACTION_TTL, ignoreIK: ignoreIK }); - if (this.equipSpringID === NULL_ACTION_ID) { + if (this.equipSpringID === NULL_UUID) { this.equipSpringID = null; this.setState(STATE_OFF); return; @@ -1779,12 +1700,10 @@ function MyController(hand) { if (this.grabbedEntity !== null) { if (this.actionID !== null) { - //add velocity whatnot - var defaultReleaseVelocityData = { - disableReleaseVelocity: false - }; //sometimes we want things to stay right where they are when we let go. - var releaseVelocityData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultReleaseVelocityData); + var releaseVelocityData = getEntityCustomData(GRABBABLE_DATA_KEY, + this.grabbedEntity, + DEFAULT_GRABBABLE_DATA); if (releaseVelocityData.disableReleaseVelocity === true) { Entities.deleteAction(this.grabbedEntity, this.actionID); @@ -1805,16 +1724,23 @@ function MyController(hand) { } else { //don't make adjustments Entities.deleteAction(this.grabbedEntity, this.actionID); - } } } this.deactivateEntity(this.grabbedEntity); - this.grabbedEntity = null; this.actionID = null; this.setState(STATE_OFF); + + //// jbp::: SEND RELEASE MESSAGE TO WEARABLES MANAGER + + Messages.sendMessage('Hifi-Wearables-Manager', JSON.stringify({ + action: 'checkIfWearable', + grabbedEntity: this.grabbedEntity + })) + + this.grabbedEntity = null; }; this.cleanup = function() { @@ -1836,6 +1762,8 @@ function MyController(hand) { data["gravity"] = grabbedProperties.gravity; data["collisionMask"] = grabbedProperties.collisionMask; data["collisionsWillMove"] = grabbedProperties.collisionsWillMove; + data["parentID"] = grabbedProperties.parentID; + data["parentJointIndex"] = grabbedProperties.parentJointIndex; var whileHeldProperties = { gravity: { x: 0, @@ -1859,7 +1787,10 @@ function MyController(hand) { Entities.editEntity(entityID, { gravity: data["gravity"], collisionMask: data["collisionMask"], - collisionsWillMove: data["collisionsWillMove"] + collisionsWillMove: data["collisionsWillMove"], + ignoreForCollisions: data["ignoreForCollisions"], + parentID: data["parentID"], + parentJointIndex: data["parentJointIndex"] }); data = null; } From 699431a9ab91a2648d113f91f6666259eb5adf8b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 12 Jan 2016 17:27:36 -0800 Subject: [PATCH 109/215] testing something with chris --- examples/controllers/handControllerGrab.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 3494e51434..e179e3ac33 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1039,13 +1039,13 @@ function MyController(hand) { this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); } - if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { - this.overlayLineOn(searchVisualizationPickRay.origin, - Vec3.sum(searchVisualizationPickRay.origin, - Vec3.multiply(searchVisualizationPickRay.direction, - LINE_LENGTH)), - NO_INTERSECT_COLOR); - } + // if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { + // this.overlayLineOn(searchVisualizationPickRay.origin, + // Vec3.sum(searchVisualizationPickRay.origin, + // Vec3.multiply(searchVisualizationPickRay.direction, + // LINE_LENGTH)), + // NO_INTERSECT_COLOR); + // } if (this.intersectionDistance > 0) { var SPHERE_INTERSECTION_SIZE = 0.011; From 9dae425bfd486e7475119427e5dcbca9c26093ad Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 12 Jan 2016 19:28:41 -0800 Subject: [PATCH 110/215] Some fixes to whiteboard to get rid of gaps between lines and jagged lines --- .../whiteboard/whiteboardEntityScript.js | 7 ++-- .../painting/whiteboard/whiteboardSpawner.js | 35 ++++++++----------- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/examples/painting/whiteboard/whiteboardEntityScript.js b/examples/painting/whiteboard/whiteboardEntityScript.js index 374ec8b873..0cb20b9f42 100644 --- a/examples/painting/whiteboard/whiteboardEntityScript.js +++ b/examples/painting/whiteboard/whiteboardEntityScript.js @@ -28,8 +28,7 @@ var PAINT_TRIGGER_THRESHOLD = 0.6; var MIN_STROKE_WIDTH = 0.0005; var MAX_STROKE_WIDTH = 0.03; - - var textureURL = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/paintStroke.png"; + var textureURL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/paintStroke.png"; var TRIGGER_CONTROLS = [ Controller.Standard.LT, @@ -170,7 +169,7 @@ type: "PolyLine", name: "paintStroke", color: this.strokeColor, - textures: "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/paintStroke.png", + textures: textureURL, dimensions: { x: 50, y: 50, @@ -249,7 +248,7 @@ unload: function() { Overlays.deleteOverlay(this.laserPointer); - // this.eraseBoard(); + this.eraseBoard(); } }; diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js index f6c7aa77ca..9b40f3368b 100644 --- a/examples/painting/whiteboard/whiteboardSpawner.js +++ b/examples/painting/whiteboard/whiteboardSpawner.js @@ -41,6 +41,7 @@ var whiteboard = Entities.addEntity({ type: "Model", shapeType: "box", modelURL: modelURL, + dimensions: {x: 2, y: 2.67, z: 0.76}, name: "whiteboard base", position: center, rotation: rotation, @@ -53,8 +54,11 @@ var colorIndicatorPosition = { }; colorIndicatorPosition.y += 1.55; colorIndicatorPosition = Vec3.sum(colorIndicatorPosition, Vec3.multiply(-0.1, Quat.getFront(rotation))); +var colorIndicatorBorderDimensions = {x: 1.84, y: 0.46, z: 0.04}; var colorIndicatorBorder = Entities.addEntity({ type: "Model", + name: "Whiteboard Color Indicator Border", + dimensions: colorIndicatorBorderDimensions, position: colorIndicatorPosition, modelURL: colorIndicatorBorderModelURL, rotation: rotation, @@ -63,10 +67,12 @@ var colorIndicatorBorder = Entities.addEntity({ var surfaceCenter = Vec3.sum(center, Vec3.multiply(-0.1, Quat.getFront(rotation))); surfaceCenter.y += 0.6; +var whiteboardDimensions = {x: 1.8, y: 1.3, z: 0.01}; var drawingSurface = Entities.addEntity({ type: "Model", modelURL: surfaceModelURL, shapeType: "box", + dimensions: whiteboardDimensions, name: "whiteboard surface", position: surfaceCenter, script: scriptURL, @@ -111,6 +117,7 @@ var eraser = Entities.addEntity({ type: "Model", modelURL: eraserModelURL, position: eraserPosition, + dimensions: {x: 1.73, y: 0.47, z: 0.11}, name: "Eraser", script: scriptURL, rotation: rotation, @@ -122,11 +129,7 @@ var eraser = Entities.addEntity({ }) }); -Script.setTimeout(function() { - whiteboardDimensions = Entities.getEntityProperties(whiteboard, "naturalDimensions").naturalDimensions; - colorIndicatorBorderDimensions = Entities.getEntityProperties(colorIndicatorBorder, "naturalDimensions").naturalDimensions; - setUp(); -}, 2000) +setUp(); function setUp() { @@ -138,6 +141,7 @@ function setUp() { blockerPosition = Vec3.sum(blockerPosition, Vec3.multiply(-1, Quat.getFront(rotation))); blocker = Entities.addEntity({ type: "Box", + name: "Whiteboard Blocker", rotation: rotation, position: blockerPosition, dimensions: { @@ -148,26 +152,17 @@ function setUp() { shapeType: "box", visible: false }); - - var eraseModelDimensions = Entities.getEntityProperties(eraser, "naturalDimensions").naturalDimensions; - Entities.editEntity(eraser, { - dimensions: eraseModelDimensions - }); - Entities.editEntity(colorIndicatorBorder, { - dimensions: colorIndicatorBorderDimensions - }); - scriptURL = Script.resolvePath("colorIndicatorEntityScript.js"); var colorIndicatorPosition = Vec3.sum(center, { x: 0, - y: whiteboardDimensions.y / 2 + colorIndicatorBorderDimensions.y / 2, + y: whiteboardDimensions.y / 2 + colorIndicatorBorderDimensions.y * 2, z: 0 }); - colorIndicatorPosition = Vec3.sum(colorIndicatorPosition, Vec3.multiply(-.1, Quat.getFront(rotation))); + colorIndicatorPosition = Vec3.sum(colorIndicatorPosition, Vec3.multiply(-0.1, Quat.getFront(rotation))); var colorIndicatorBoxDimensions = Vec3.multiply(colorIndicatorBorderDimensions, 0.9); colorIndicatorBox = Entities.addEntity({ type: "Box", - name: "Color Indicator", + name: "Whiteboard Color Indicator", color: colors[0], rotation: rotation, position: colorIndicatorPosition, @@ -205,13 +200,13 @@ function setUp() { colorBoxPosition = Vec3.sum(colorBoxPosition, Vec3.multiply(palleteDepthOffset, Quat.getFront(rotation))); colorBoxPosition.y += palleteHeightOffset; var spaceBetweenColorBoxes = Vec3.multiply(direction, colorSquareDimensions.x * 1.76); - var palleteXOffset = Vec3.multiply(direction, 0.43); + var palleteXOffset = Vec3.multiply(direction, 0.33); colorBoxPosition = Vec3.sum(colorBoxPosition, palleteXOffset); var scriptURL = Script.resolvePath("colorSelectorEntityScript.js"); for (var i = 0; i < colors.length; i++) { var colorBox = Entities.addEntity({ type: "Box", - name: "Color Selector", + name: "Whiteboard Color Selector", position: colorBoxPosition, dimensions: colorSquareDimensions, rotation: rotation, @@ -247,4 +242,4 @@ function cleanup() { // Uncomment this line to delete whiteboard and all associated entity on script close -// Script.scriptEnding.connect(cleanup); +Script.scriptEnding.connect(cleanup); From 061cf5021cf11aeb88187609c2f0ce6215cdf045 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 12 Jan 2016 19:31:43 -0800 Subject: [PATCH 111/215] Don't clean up whiteboard on script shutdown --- examples/painting/whiteboard/whiteboardEntityScript.js | 2 +- examples/painting/whiteboard/whiteboardSpawner.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/painting/whiteboard/whiteboardEntityScript.js b/examples/painting/whiteboard/whiteboardEntityScript.js index 0cb20b9f42..181932c7cb 100644 --- a/examples/painting/whiteboard/whiteboardEntityScript.js +++ b/examples/painting/whiteboard/whiteboardEntityScript.js @@ -248,7 +248,7 @@ unload: function() { Overlays.deleteOverlay(this.laserPointer); - this.eraseBoard(); + // this.eraseBoard(); } }; diff --git a/examples/painting/whiteboard/whiteboardSpawner.js b/examples/painting/whiteboard/whiteboardSpawner.js index 9b40f3368b..791297a77b 100644 --- a/examples/painting/whiteboard/whiteboardSpawner.js +++ b/examples/painting/whiteboard/whiteboardSpawner.js @@ -242,4 +242,4 @@ function cleanup() { // Uncomment this line to delete whiteboard and all associated entity on script close -Script.scriptEnding.connect(cleanup); +// Script.scriptEnding.connect(cleanup); From 3f90312375426b6553b39d8b3b2050c21aeeb3d5 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 11 Jan 2016 16:28:36 -0800 Subject: [PATCH 112/215] Fix for XCode auto indent --- .../model-networking/src/model-networking/TextureCache.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index ae705faf86..40fb05c9ca 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -72,11 +72,12 @@ const gpu::TexturePointer& TextureCache::getPermutationNormalTexture() { data[3*i+0] = permutation[i]; data[3*i+1] = permutation[i]; data[3*i+2] = permutation[i]; + } #else for (int i = 0; i < 256 * 3; i++) { data[i] = rand() % 256; -#endif } +#endif for (int i = 256 * 3; i < 256 * 3 * 2; i += 3) { glm::vec3 randvec = glm::sphericalRand(1.0f); From 0008b1a055112fd19ce89fa37ba6b21379243419 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 11 Jan 2016 16:29:27 -0800 Subject: [PATCH 113/215] Code cleanup --- interface/src/Application.cpp | 30 +++++--- .../src/model-networking/ModelCache.cpp | 1 - .../src/model-networking/TextureCache.cpp | 74 ++++++------------- .../src/model-networking/TextureCache.h | 21 ++---- 4 files changed, 47 insertions(+), 79 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4c4786c6a2..f4d711e9d9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3635,10 +3635,15 @@ public: render::ItemID BackgroundRenderData::_item = 0; namespace render { - template <> const ItemKey payloadGetKey(const BackgroundRenderData::Pointer& stuff) { return ItemKey::Builder::background(); } - template <> const Item::Bound payloadGetBound(const BackgroundRenderData::Pointer& stuff) { return Item::Bound(); } - template <> void payloadRender(const BackgroundRenderData::Pointer& background, RenderArgs* args) { + template <> const ItemKey payloadGetKey(const BackgroundRenderData::Pointer& stuff) { + return ItemKey::Builder::background(); + } + template <> const Item::Bound payloadGetBound(const BackgroundRenderData::Pointer& stuff) { + return Item::Bound(); + } + + template <> void payloadRender(const BackgroundRenderData::Pointer& background, RenderArgs* args) { Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; @@ -3646,20 +3651,18 @@ namespace render { auto skyStage = DependencyManager::get()->getSkyStage(); auto backgroundMode = skyStage->getBackgroundMode(); - if (backgroundMode == model::SunSkyStage::NO_BACKGROUND) { - // this line intentionally left blank - } else { - if (backgroundMode == model::SunSkyStage::SKY_BOX) { + switch (backgroundMode) { + case model::SunSkyStage::SKY_BOX: { auto skybox = skyStage->getSkybox(); if (skybox && skybox->getCubemap() && skybox->getCubemap()->isDefined()) { PerformanceTimer perfTimer("skybox"); skybox->render(batch, *(args->_viewFrustum)); - } else { - // If no skybox texture is available, render the SKY_DOME while it loads - backgroundMode = model::SunSkyStage::SKY_DOME; + break; } + // If no skybox texture is available, render the SKY_DOME while it loads } - if (backgroundMode == model::SunSkyStage::SKY_DOME) { + // fall through to next case + case model::SunSkyStage::SKY_DOME: { if (Menu::getInstance()->isOptionChecked(MenuOption::Stars)) { PerformanceTimer perfTimer("stars"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), @@ -3725,6 +3728,11 @@ namespace render { } } + break; + case model::SunSkyStage::NO_BACKGROUND: + default: + // this line intentionally left blank + break; } } } diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 4fd47affc2..f3cc8b247e 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -149,7 +149,6 @@ void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& u if (_meshes.size() > 0) { auto textureCache = DependencyManager::get(); for (auto&& material : _materials) { - QSharedPointer matchingTexture = QSharedPointer(); if (material->diffuseTextureName == name) { material->diffuseTexture = textureCache->getTexture(url, DEFAULT_TEXTURE); } else if (material->normalTextureName == name) { diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 40fb05c9ca..60f6d50d59 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -174,19 +174,11 @@ QSharedPointer TextureCache::createResource(const QUrl& url, &Resource::allReferencesCleared); } -Texture::Texture() { -} - -Texture::~Texture() { -} - NetworkTexture::NetworkTexture(const QUrl& url, TextureType type, const QByteArray& content) : Resource(url, !content.isEmpty()), - _type(type), - _width(0), - _height(0) { - - _textureSource.reset(new gpu::TextureSource()); + _type(type) +{ + _textureSource = std::make_shared(); if (!url.isValid()) { _loaded = true; @@ -201,24 +193,9 @@ NetworkTexture::NetworkTexture(const QUrl& url, TextureType type, const QByteArr } NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content) : - Resource(url, !content.isEmpty()), - _type(CUSTOM_TEXTURE), - _textureLoader(textureLoader), - _width(0), - _height(0) { - - _textureSource.reset(new gpu::TextureSource()); - - if (!url.isValid()) { - _loaded = true; - } - - std::string theName = url.toString().toStdString(); - // if we have content, load it after we have our self pointer - if (!content.isEmpty()) { - _startedLoading = true; - QMetaObject::invokeMethod(this, "loadContent", Qt::QueuedConnection, Q_ARG(const QByteArray&, content)); - } + NetworkTexture(url, CUSTOM_TEXTURE, content) +{ + _textureLoader = textureLoader; } NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const { @@ -248,57 +225,52 @@ NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const { } } } - + class ImageReader : public QRunnable { public: - ImageReader(const QWeakPointer& texture, const NetworkTexture::TextureLoaderFunc& textureLoader, const QByteArray& data, const QUrl& url = QUrl()); - + ImageReader(const QWeakPointer& texture, const QByteArray& data, const QUrl& url = QUrl()); + virtual void run(); private: - + static void listSupportedImageFormats(); + QWeakPointer _texture; - NetworkTexture::TextureLoaderFunc _textureLoader; QUrl _url; QByteArray _content; }; void NetworkTexture::downloadFinished(const QByteArray& data) { // send the reader off to the thread pool - QThreadPool::globalInstance()->start(new ImageReader(_self, getTextureLoader(), data, _url)); + QThreadPool::globalInstance()->start(new ImageReader(_self, data, _url)); } void NetworkTexture::loadContent(const QByteArray& content) { - QThreadPool::globalInstance()->start(new ImageReader(_self, getTextureLoader(), content, _url)); + QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url)); } -ImageReader::ImageReader(const QWeakPointer& texture, const NetworkTexture::TextureLoaderFunc& textureLoader, const QByteArray& data, +ImageReader::ImageReader(const QWeakPointer& texture, const QByteArray& data, const QUrl& url) : _texture(texture), - _textureLoader(textureLoader), _url(url), _content(data) { - } -std::once_flag onceListSupportedFormatsflag; -void listSupportedImageFormats() { - std::call_once(onceListSupportedFormatsflag, [](){ +void ImageReader::listSupportedImageFormats() { + static std::once_flag once; + std::call_once(once, []{ auto supportedFormats = QImageReader::supportedImageFormats(); - QString formats; - foreach(const QByteArray& f, supportedFormats) { - formats += QString(f) + ","; - } - qCDebug(modelnetworking) << "List of supported Image formats:" << formats; + qCDebug(modelnetworking) << "List of supported Image formats:" << supportedFormats.join(", "); }); } void ImageReader::run() { - QSharedPointer texture = _texture.toStrongRef(); - if (texture.isNull()) { + auto texture = _texture.toStrongRef(); + if (!texture) { + qCWarning(modelnetworking) << "Could not get strong ref"; return; } @@ -325,7 +297,7 @@ void ImageReader::run() { } gpu::Texture* theTexture = nullptr; - auto ntex = dynamic_cast(&*texture); + auto ntex = texture.dynamicCast(); if (ntex) { theTexture = ntex->getTextureLoader()(image, _url.toString().toStdString()); } @@ -334,8 +306,6 @@ void ImageReader::run() { Q_ARG(const QImage&, image), Q_ARG(void*, theTexture), Q_ARG(int, originalWidth), Q_ARG(int, originalHeight)); - - } void NetworkTexture::setImage(const QImage& image, void* voidTexture, int originalWidth, diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 4171b6c1cb..033b4bede6 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -67,9 +67,6 @@ public: typedef gpu::Texture* TextureLoader(const QImage& image, const std::string& srcImageName); typedef std::function TextureLoaderFunc; - - NetworkTexturePointer getTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, - const QByteArray& content = QByteArray()); protected: virtual QSharedPointer createResource(const QUrl& url, @@ -94,15 +91,9 @@ private: class Texture { public: friend class TextureCache; - Texture(); - ~Texture(); - const gpu::TexturePointer getGPUTexture() const { return _textureSource->getGPUTexture(); } + gpu::TexturePointer getGPUTexture() const { return _textureSource->getGPUTexture(); } gpu::TextureSourcePointer _textureSource; - -protected: - -private: }; /// A texture loaded from the network. @@ -134,14 +125,14 @@ protected: virtual void imageLoaded(const QImage& image); - TextureType _type; private: + TextureType _type; TextureLoaderFunc _textureLoader; - int _originalWidth; - int _originalHeight; - int _width; - int _height; + int _originalWidth { 0 }; + int _originalHeight { 0 }; + int _width { 0 }; + int _height { 0 }; }; #endif // hifi_TextureCache_h From 5e41421f9de526f7288b268b123af08032721246 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 11 Jan 2016 18:58:46 -0800 Subject: [PATCH 114/215] Fix for skybox not always loading --- .../src/EntityTreeRenderer.cpp | 156 +++++++++--------- .../src/EntityTreeRenderer.h | 11 +- 2 files changed, 89 insertions(+), 78 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 07d9031f41..a904bee847 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include "EntityTreeRenderer.h" @@ -142,7 +141,7 @@ void EntityTreeRenderer::update() { // even if we haven't changed positions, if we previously attempted to set the skybox, but // have a pending download of the skybox texture, then we should attempt to reapply to // get the correct texture. - if (_pendingSkyboxTextureDownload) { + if (_pendingSkyboxTexture && _skyboxTexture && _skyboxTexture->isLoaded()) { applyZonePropertiesToScene(_bestZone); } @@ -255,26 +254,31 @@ void EntityTreeRenderer::forceRecheckEntities() { void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr zone) { - QSharedPointer scene = DependencyManager::get(); + auto scene = DependencyManager::get(); auto sceneStage = scene->getStage(); + auto skyStage = scene->getSkyStage(); auto sceneKeyLight = sceneStage->getKeyLight(); auto sceneLocation = sceneStage->getLocation(); auto sceneTime = sceneStage->getTime(); + auto backgroundMode = BACKGROUND_MODE_INHERIT; // Default + if (!_hasPreviousZone) { + _previousKeyLightColor = sceneKeyLight->getColor(); + _previousKeyLightIntensity = sceneKeyLight->getIntensity(); + _previousKeyLightAmbientIntensity = sceneKeyLight->getAmbientIntensity(); + _previousKeyLightDirection = sceneKeyLight->getDirection(); + _previousStageSunModelEnabled = sceneStage->isSunModelEnabled(); + _previousStageLongitude = sceneLocation->getLongitude(); + _previousStageLatitude = sceneLocation->getLatitude(); + _previousStageAltitude = sceneLocation->getAltitude(); + _previousStageHour = sceneTime->getHour(); + _previousStageDay = sceneTime->getDay(); + _hasPreviousZone = true; + } + if (zone) { - if (!_hasPreviousZone) { - _previousKeyLightColor = sceneKeyLight->getColor(); - _previousKeyLightIntensity = sceneKeyLight->getIntensity(); - _previousKeyLightAmbientIntensity = sceneKeyLight->getAmbientIntensity(); - _previousKeyLightDirection = sceneKeyLight->getDirection(); - _previousStageSunModelEnabled = sceneStage->isSunModelEnabled(); - _previousStageLongitude = sceneLocation->getLongitude(); - _previousStageLatitude = sceneLocation->getLatitude(); - _previousStageAltitude = sceneLocation->getAltitude(); - _previousStageHour = sceneTime->getHour(); - _previousStageDay = sceneTime->getDay(); - _hasPreviousZone = true; - } + backgroundMode = zone->getBackgroundMode(); + sceneKeyLight->setColor(ColorUtils::toVec3(zone->getKeyLightProperties().getColor())); sceneKeyLight->setIntensity(zone->getKeyLightProperties().getIntensity()); sceneKeyLight->setAmbientIntensity(zone->getKeyLightProperties().getAmbientIntensity()); @@ -284,85 +288,89 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrgetStageProperties().getAltitude()); sceneTime->setHour(zone->getStageProperties().calculateHour()); sceneTime->setDay(zone->getStageProperties().calculateDay()); - - if (zone->getBackgroundMode() == BACKGROUND_MODE_ATMOSPHERE) { + } + + switch (backgroundMode) { + case BACKGROUND_MODE_ATMOSPHERE: { EnvironmentData data = zone->getEnvironmentData(); glm::vec3 keyLightDirection = sceneKeyLight->getDirection(); glm::vec3 inverseKeyLightDirection = keyLightDirection * -1.0f; - + // NOTE: is this right? It seems like the "sun" should be based on the center of the // atmosphere, not where the camera is. glm::vec3 keyLightLocation = _viewState->getAvatarPosition() + (inverseKeyLightDirection * data.getAtmosphereOuterRadius()); - + data.setSunLocation(keyLightLocation); - + const float KEY_LIGHT_INTENSITY_TO_SUN_BRIGHTNESS_RATIO = 20.0f; float sunBrightness = sceneKeyLight->getIntensity() * KEY_LIGHT_INTENSITY_TO_SUN_BRIGHTNESS_RATIO; data.setSunBrightness(sunBrightness); - + _viewState->overrideEnvironmentData(data); - scene->getSkyStage()->setBackgroundMode(model::SunSkyStage::SKY_DOME); - _pendingSkyboxTextureDownload = false; - - } else { - _viewState->endOverrideEnvironmentData(); - auto stage = scene->getSkyStage(); - if (zone->getBackgroundMode() == BACKGROUND_MODE_SKYBOX) { - auto skybox = std::dynamic_pointer_cast(stage->getSkybox()); - skybox->setColor(zone->getSkyboxProperties().getColorVec3()); - static QString userData; - if (userData != zone->getUserData()) { - userData = zone->getUserData(); - ProceduralPointer procedural(new Procedural(userData)); - if (procedural->_enabled) { - skybox->setProcedural(procedural); - } else { - skybox->setProcedural(ProceduralPointer()); - } - } - if (zone->getSkyboxProperties().getURL().isEmpty()) { - skybox->setCubemap(gpu::TexturePointer()); - _pendingSkyboxTextureDownload = false; + skyStage->setBackgroundMode(model::SunSkyStage::SKY_DOME); + _pendingSkyboxTexture = false; + _skyboxTexture.clear(); + break; + } + case BACKGROUND_MODE_SKYBOX: { + auto skybox = std::dynamic_pointer_cast(skyStage->getSkybox()); + skybox->setColor(zone->getSkyboxProperties().getColorVec3()); + static QString userData; + if (userData != zone->getUserData()) { + userData = zone->getUserData(); + auto procedural = std::make_shared(userData); + if (procedural->_enabled) { + skybox->setProcedural(procedural); } else { - // Update the Texture of the Skybox with the one pointed by this zone - auto cubeMap = DependencyManager::get()->getTexture(zone->getSkyboxProperties().getURL(), CUBE_TEXTURE); - - if (cubeMap->getGPUTexture()) { - skybox->setCubemap(cubeMap->getGPUTexture()); - _pendingSkyboxTextureDownload = false; - } else { - _pendingSkyboxTextureDownload = true; - } + skybox->setProcedural(ProceduralPointer()); } - stage->setBackgroundMode(model::SunSkyStage::SKY_BOX); - } else { - stage->setBackgroundMode(model::SunSkyStage::SKY_DOME); // let the application atmosphere through - _pendingSkyboxTextureDownload = false; } + if (zone->getSkyboxProperties().getURL().isEmpty()) { + skybox->setCubemap(gpu::TexturePointer()); + _pendingSkyboxTexture = false; + _skyboxTexture.clear(); + } else { + // Update the Texture of the Skybox with the one pointed by this zone + auto textureCache = DependencyManager::get(); + _skyboxTexture = textureCache->getTexture(zone->getSkyboxProperties().getURL(), CUBE_TEXTURE); + + if (_skyboxTexture->getGPUTexture()) { + skybox->setCubemap(_skyboxTexture->getGPUTexture()); + _pendingSkyboxTexture = false; + } else { + _pendingSkyboxTexture = true; + } + } + + _viewState->endOverrideEnvironmentData(); + skyStage->setBackgroundMode(model::SunSkyStage::SKY_BOX); + break; } - } else { - _pendingSkyboxTextureDownload = false; - if (_hasPreviousZone) { - sceneKeyLight->setColor(_previousKeyLightColor); - sceneKeyLight->setIntensity(_previousKeyLightIntensity); - sceneKeyLight->setAmbientIntensity(_previousKeyLightAmbientIntensity); - sceneKeyLight->setDirection(_previousKeyLightDirection); - sceneStage->setSunModelEnable(_previousStageSunModelEnabled); - sceneStage->setLocation(_previousStageLongitude, _previousStageLatitude, - _previousStageAltitude); - sceneTime->setHour(_previousStageHour); - sceneTime->setDay(_previousStageDay); - _hasPreviousZone = false; - } - _viewState->endOverrideEnvironmentData(); - scene->getSkyStage()->setBackgroundMode(model::SunSkyStage::SKY_DOME); // let the application atmosphere through + case BACKGROUND_MODE_INHERIT: + if (_hasPreviousZone) { + sceneKeyLight->setColor(_previousKeyLightColor); + sceneKeyLight->setIntensity(_previousKeyLightIntensity); + sceneKeyLight->setAmbientIntensity(_previousKeyLightAmbientIntensity); + sceneKeyLight->setDirection(_previousKeyLightDirection); + sceneStage->setSunModelEnable(_previousStageSunModelEnabled); + sceneStage->setLocation(_previousStageLongitude, _previousStageLatitude, + _previousStageAltitude); + sceneTime->setHour(_previousStageHour); + sceneTime->setDay(_previousStageDay); + _hasPreviousZone = false; + } + _viewState->endOverrideEnvironmentData(); + skyStage->setBackgroundMode(model::SunSkyStage::SKY_DOME); // let the application atmosphere through + _pendingSkyboxTexture = false; + _skyboxTexture.clear(); + break; } } const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(EntityItemPointer entityItem) { const FBXGeometry* result = NULL; - + if (entityItem->getType() == EntityTypes::Model) { std::shared_ptr modelEntityItem = std::dynamic_pointer_cast(entityItem); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index e2cd4fc2dd..a841b5a687 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -15,12 +15,13 @@ #include #include -#include +#include #include // for RayToEntityIntersectionResult +#include #include #include #include -#include +#include class AbstractScriptingServicesInterface; class AbstractViewStateInterface; @@ -142,9 +143,11 @@ private: void forceRecheckEntities(); glm::vec3 _lastAvatarPosition; - bool _pendingSkyboxTextureDownload = false; QVector _currentEntitiesInside; - + + bool _pendingSkyboxTexture = false; + NetworkTexturePointer _skyboxTexture; + bool _wantScripts; ScriptEngine* _entitiesScriptEngine; From 911375b7a1a027822c685268a0be483659d5c88d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 12 Jan 2016 10:50:41 -0800 Subject: [PATCH 115/215] Don't change apply zone logic --- .../src/EntityTreeRenderer.cpp | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index a904bee847..b49002b4e1 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -261,24 +261,24 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrgetLocation(); auto sceneTime = sceneStage->getTime(); auto backgroundMode = BACKGROUND_MODE_INHERIT; // Default - - if (!_hasPreviousZone) { - _previousKeyLightColor = sceneKeyLight->getColor(); - _previousKeyLightIntensity = sceneKeyLight->getIntensity(); - _previousKeyLightAmbientIntensity = sceneKeyLight->getAmbientIntensity(); - _previousKeyLightDirection = sceneKeyLight->getDirection(); - _previousStageSunModelEnabled = sceneStage->isSunModelEnabled(); - _previousStageLongitude = sceneLocation->getLongitude(); - _previousStageLatitude = sceneLocation->getLatitude(); - _previousStageAltitude = sceneLocation->getAltitude(); - _previousStageHour = sceneTime->getHour(); - _previousStageDay = sceneTime->getDay(); - _hasPreviousZone = true; - } if (zone) { backgroundMode = zone->getBackgroundMode(); + if (!_hasPreviousZone) { + _previousKeyLightColor = sceneKeyLight->getColor(); + _previousKeyLightIntensity = sceneKeyLight->getIntensity(); + _previousKeyLightAmbientIntensity = sceneKeyLight->getAmbientIntensity(); + _previousKeyLightDirection = sceneKeyLight->getDirection(); + _previousStageSunModelEnabled = sceneStage->isSunModelEnabled(); + _previousStageLongitude = sceneLocation->getLongitude(); + _previousStageLatitude = sceneLocation->getLatitude(); + _previousStageAltitude = sceneLocation->getAltitude(); + _previousStageHour = sceneTime->getHour(); + _previousStageDay = sceneTime->getDay(); + _hasPreviousZone = true; + } + sceneKeyLight->setColor(ColorUtils::toVec3(zone->getKeyLightProperties().getColor())); sceneKeyLight->setIntensity(zone->getKeyLightProperties().getIntensity()); sceneKeyLight->setAmbientIntensity(zone->getKeyLightProperties().getAmbientIntensity()); From 47586e97a6c228bfc39299f1e4e1523fd2e64ea9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 12 Jan 2016 15:15:19 -0800 Subject: [PATCH 116/215] Stay closer to the old code (Use early exit) --- .../src/EntityTreeRenderer.cpp | 80 ++++++++++--------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index b49002b4e1..9f1f56f63c 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -260,37 +260,55 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrgetKeyLight(); auto sceneLocation = sceneStage->getLocation(); auto sceneTime = sceneStage->getTime(); - auto backgroundMode = BACKGROUND_MODE_INHERIT; // Default - if (zone) { - backgroundMode = zone->getBackgroundMode(); + if (!zone) { + _pendingSkyboxTexture = false; + _skyboxTexture.clear(); - if (!_hasPreviousZone) { - _previousKeyLightColor = sceneKeyLight->getColor(); - _previousKeyLightIntensity = sceneKeyLight->getIntensity(); - _previousKeyLightAmbientIntensity = sceneKeyLight->getAmbientIntensity(); - _previousKeyLightDirection = sceneKeyLight->getDirection(); - _previousStageSunModelEnabled = sceneStage->isSunModelEnabled(); - _previousStageLongitude = sceneLocation->getLongitude(); - _previousStageLatitude = sceneLocation->getLatitude(); - _previousStageAltitude = sceneLocation->getAltitude(); - _previousStageHour = sceneTime->getHour(); - _previousStageDay = sceneTime->getDay(); - _hasPreviousZone = true; + if (_hasPreviousZone) { + sceneKeyLight->setColor(_previousKeyLightColor); + sceneKeyLight->setIntensity(_previousKeyLightIntensity); + sceneKeyLight->setAmbientIntensity(_previousKeyLightAmbientIntensity); + sceneKeyLight->setDirection(_previousKeyLightDirection); + sceneStage->setSunModelEnable(_previousStageSunModelEnabled); + sceneStage->setLocation(_previousStageLongitude, _previousStageLatitude, + _previousStageAltitude); + sceneTime->setHour(_previousStageHour); + sceneTime->setDay(_previousStageDay); + _hasPreviousZone = false; } - sceneKeyLight->setColor(ColorUtils::toVec3(zone->getKeyLightProperties().getColor())); - sceneKeyLight->setIntensity(zone->getKeyLightProperties().getIntensity()); - sceneKeyLight->setAmbientIntensity(zone->getKeyLightProperties().getAmbientIntensity()); - sceneKeyLight->setDirection(zone->getKeyLightProperties().getDirection()); - sceneStage->setSunModelEnable(zone->getStageProperties().getSunModelEnabled()); - sceneStage->setLocation(zone->getStageProperties().getLongitude(), zone->getStageProperties().getLatitude(), - zone->getStageProperties().getAltitude()); - sceneTime->setHour(zone->getStageProperties().calculateHour()); - sceneTime->setDay(zone->getStageProperties().calculateDay()); + _viewState->endOverrideEnvironmentData(); + skyStage->setBackgroundMode(model::SunSkyStage::SKY_DOME); // let the application atmosphere through + + return; // Early exit } - switch (backgroundMode) { + if (!_hasPreviousZone) { + _previousKeyLightColor = sceneKeyLight->getColor(); + _previousKeyLightIntensity = sceneKeyLight->getIntensity(); + _previousKeyLightAmbientIntensity = sceneKeyLight->getAmbientIntensity(); + _previousKeyLightDirection = sceneKeyLight->getDirection(); + _previousStageSunModelEnabled = sceneStage->isSunModelEnabled(); + _previousStageLongitude = sceneLocation->getLongitude(); + _previousStageLatitude = sceneLocation->getLatitude(); + _previousStageAltitude = sceneLocation->getAltitude(); + _previousStageHour = sceneTime->getHour(); + _previousStageDay = sceneTime->getDay(); + _hasPreviousZone = true; + } + + sceneKeyLight->setColor(ColorUtils::toVec3(zone->getKeyLightProperties().getColor())); + sceneKeyLight->setIntensity(zone->getKeyLightProperties().getIntensity()); + sceneKeyLight->setAmbientIntensity(zone->getKeyLightProperties().getAmbientIntensity()); + sceneKeyLight->setDirection(zone->getKeyLightProperties().getDirection()); + sceneStage->setSunModelEnable(zone->getStageProperties().getSunModelEnabled()); + sceneStage->setLocation(zone->getStageProperties().getLongitude(), zone->getStageProperties().getLatitude(), + zone->getStageProperties().getAltitude()); + sceneTime->setHour(zone->getStageProperties().calculateHour()); + sceneTime->setDay(zone->getStageProperties().calculateDay()); + + switch (zone->getBackgroundMode()) { case BACKGROUND_MODE_ATMOSPHERE: { EnvironmentData data = zone->getEnvironmentData(); glm::vec3 keyLightDirection = sceneKeyLight->getDirection(); @@ -348,18 +366,6 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrsetColor(_previousKeyLightColor); - sceneKeyLight->setIntensity(_previousKeyLightIntensity); - sceneKeyLight->setAmbientIntensity(_previousKeyLightAmbientIntensity); - sceneKeyLight->setDirection(_previousKeyLightDirection); - sceneStage->setSunModelEnable(_previousStageSunModelEnabled); - sceneStage->setLocation(_previousStageLongitude, _previousStageLatitude, - _previousStageAltitude); - sceneTime->setHour(_previousStageHour); - sceneTime->setDay(_previousStageDay); - _hasPreviousZone = false; - } _viewState->endOverrideEnvironmentData(); skyStage->setBackgroundMode(model::SunSkyStage::SKY_DOME); // let the application atmosphere through _pendingSkyboxTexture = false; From e8d7411eeadca960afc5ff005ec96a50a198b377 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 12 Jan 2016 20:49:38 -0800 Subject: [PATCH 117/215] Indentation/Coding Standard --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 4 ++-- libraries/entities-renderer/src/EntityTreeRenderer.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 9f1f56f63c..a274c9d705 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -316,8 +316,8 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrgetAvatarPosition() - + (inverseKeyLightDirection * data.getAtmosphereOuterRadius()); + glm::vec3 keyLightLocation = _viewState->getAvatarPosition() + + (inverseKeyLightDirection * data.getAtmosphereOuterRadius()); data.setSunLocation(keyLightLocation); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index a841b5a687..09fe7a527c 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -145,7 +145,7 @@ private: glm::vec3 _lastAvatarPosition; QVector _currentEntitiesInside; - bool _pendingSkyboxTexture = false; + bool _pendingSkyboxTexture { false }; NetworkTexturePointer _skyboxTexture; bool _wantScripts; @@ -164,11 +164,11 @@ private: bool _displayModelBounds; bool _dontDoPrecisionPicking; - bool _shuttingDown = false; + bool _shuttingDown { false }; QMultiMap _waitingOnPreload; - bool _hasPreviousZone = false; + bool _hasPreviousZone { false }; std::shared_ptr _bestZone; float _bestZoneVolume; From e8adcd9f1f9cd19fcace837d1aa09bd5a4cc9ac7 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 12 Jan 2016 21:11:47 -0800 Subject: [PATCH 118/215] Fix inability to stop local scripts --- libraries/script-engine/src/ScriptEngines.cpp | 38 +++++++++++++------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 0a646bd696..0a0b2de47e 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -42,6 +42,17 @@ ScriptEngines::ScriptEngines() _scriptsModelFilter.setDynamicSortFilter(true); } +QString normalizeScriptUrl(const QString& rawScriptUrl) { + auto lower = rawScriptUrl.toLower(); + if (!rawScriptUrl.startsWith("http:") && !rawScriptUrl.startsWith("https:") && !rawScriptUrl.startsWith("atp:")) { + if (rawScriptUrl.startsWith("file:")) { + return rawScriptUrl.toLower(); + } + // Force lowercase on file scripts because of drive letter weirdness. + return QUrl::fromLocalFile(rawScriptUrl).toString().toLower(); + } + return QUrl(rawScriptUrl).toString(); +} QObject* scriptsModel(); @@ -290,22 +301,23 @@ void ScriptEngines::stopAllScripts(bool restart) { } } -bool ScriptEngines::stopScript(const QString& scriptHash, bool restart) { +bool ScriptEngines::stopScript(const QString& rawScriptUrl, bool restart) { bool stoppedScript = false; { QReadLocker lock(&_scriptEnginesHashLock); - if (_scriptEnginesHash.contains(scriptHash)) { - ScriptEngine* scriptEngine = _scriptEnginesHash[scriptHash]; + const QString scriptURLString = normalizeScriptUrl(rawScriptUrl); + if (_scriptEnginesHash.contains(scriptURLString)) { + ScriptEngine* scriptEngine = _scriptEnginesHash[scriptURLString]; if (restart) { auto scriptCache = DependencyManager::get(); - scriptCache->deleteScript(QUrl(scriptHash)); + scriptCache->deleteScript(QUrl(scriptURLString)); connect(scriptEngine, &ScriptEngine::finished, this, [this](QString scriptName, ScriptEngine* engine) { reloadScript(scriptName); }); } scriptEngine->stop(); stoppedScript = true; - qCDebug(scriptengine) << "stopping script..." << scriptHash; + qCDebug(scriptengine) << "stopping script..." << scriptURLString; } } return stoppedScript; @@ -364,11 +376,12 @@ ScriptEngine* ScriptEngines::loadScript(const QString& scriptFilename, bool isUs return scriptEngine; } -ScriptEngine* ScriptEngines::getScriptEngine(const QString& scriptHash) { +ScriptEngine* ScriptEngines::getScriptEngine(const QString& rawScriptUrl) { ScriptEngine* result = nullptr; { QReadLocker lock(&_scriptEnginesHashLock); - auto it = _scriptEnginesHash.find(scriptHash); + const QString scriptURLString = normalizeScriptUrl(rawScriptUrl); + auto it = _scriptEnginesHash.find(scriptURLString); if (it != _scriptEnginesHash.end()) { result = it.value(); } @@ -377,15 +390,16 @@ ScriptEngine* ScriptEngines::getScriptEngine(const QString& scriptHash) { } // FIXME - change to new version of ScriptCache loading notification -void ScriptEngines::onScriptEngineLoaded(const QString& scriptFilename) { - UserActivityLogger::getInstance().loadedScript(scriptFilename); +void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptUrl) { + UserActivityLogger::getInstance().loadedScript(rawScriptUrl); ScriptEngine* scriptEngine = qobject_cast(sender()); launchScriptEngine(scriptEngine); { QWriteLocker lock(&_scriptEnginesHashLock); - _scriptEnginesHash.insertMulti(scriptFilename, scriptEngine); + const QString scriptURLString = normalizeScriptUrl(rawScriptUrl); + _scriptEnginesHash.insertMulti(scriptURLString, scriptEngine); } emit scriptCountChanged(); } @@ -407,11 +421,11 @@ void ScriptEngines::launchScriptEngine(ScriptEngine* scriptEngine) { } -void ScriptEngines::onScriptFinished(const QString& scriptName, ScriptEngine* engine) { +void ScriptEngines::onScriptFinished(const QString& rawScriptUrl, ScriptEngine* engine) { bool removed = false; { QWriteLocker lock(&_scriptEnginesHashLock); - const QString& scriptURLString = QUrl(scriptName).toString(); + const QString scriptURLString = normalizeScriptUrl(rawScriptUrl); for (auto it = _scriptEnginesHash.find(scriptURLString); it != _scriptEnginesHash.end(); ++it) { if (it.value() == engine) { _scriptEnginesHash.erase(it); From 0a371e4b753184400c3e0f995b9dda01a61b5b8e Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 13 Jan 2016 11:06:29 -0800 Subject: [PATCH 119/215] Adjusted relative hand grab data for gun, ping ponger, and bow to to optimize for owen grabbing --- unpublishedScripts/hiddenEntityReset.js | 30 ++++++++++++++++--------- unpublishedScripts/masterReset.js | 25 ++++++++++++--------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 4352a5d562..19bf689357 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -300,12 +300,17 @@ userData: JSON.stringify({ grabbableKey: { spatialKey: { - relativePosition: { - x: 0, + rightRelativePosition: { + x: 0.03, y: 0, - z: 0 + z: -0.085 }, - relativeRotation: Quat.fromPitchYawRollDegrees(45, 90, 0) + leftRelativePosition: { + x: -0.03, + y: 0, + z: -0.085 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(100, 90, 0) }, invertSolidWhileHeld: true }, @@ -359,9 +364,14 @@ grabbableKey: { invertSolidWhileHeld: true, spatialKey: { - relativePosition: { - x: 0, - y: 0.06, + rightRelativePosition: { + x: -0.03, + y: 0, + z: 0.11 + }, + leftRelativePosition: { + x: 0.03, + y: 0, z: 0.11 }, relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, 90) @@ -1152,9 +1162,9 @@ grabbableKey: { spatialKey: { relativePosition: { - x: -0.05, + x: 0.01, y: 0, - z: 0.0 + z: 0.1 }, relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, -90) }, @@ -1509,4 +1519,4 @@ }; // entity scripts always need to return a newly constructed object of our type return new ResetSwitch(); -}); +}); \ No newline at end of file diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 8aedd1c650..f0c5ad6075 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -285,14 +285,14 @@ MasterReset = function() { grabbableKey: { spatialKey: { rightRelativePosition: { - x: 0.02, + x: 0.03, y: 0, - z: -0.03 + z: -0.085 }, leftRelativePosition: { - x: -0.02, + x: -0.03, y: 0, - z: -0.03 + z: -0.085 }, relativeRotation: Quat.fromPitchYawRollDegrees(100, 90, 0) }, @@ -348,9 +348,14 @@ MasterReset = function() { grabbableKey: { invertSolidWhileHeld: true, spatialKey: { - relativePosition: { - x: 0, - y: 0.06, + rightRelativePosition: { + x: -0.03, + y: 0, + z: 0.11 + }, + leftRelativePosition: { + x: 0.03, + y: 0, z: 0.11 }, relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, 90) @@ -1142,9 +1147,9 @@ MasterReset = function() { grabbableKey: { spatialKey: { relativePosition: { - x: 0, + x: 0.01, y: 0, - z: 0.06 + z: 0.1 }, relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, -90) }, @@ -1494,4 +1499,4 @@ MasterReset = function() { Script.scriptEnding.connect(cleanup); } -}; +}; \ No newline at end of file From 007013254ed130f24e5d1662941c4f5cfcbb97d3 Mon Sep 17 00:00:00 2001 From: "Kevini M. Thomas" Date: Wed, 13 Jan 2016 14:34:44 -0500 Subject: [PATCH 120/215] Fixed entity script loading functionality for the jsstreamplayer. --- .../zones/jsstreamplayerdomain-zone-entity.js | 2 +- examples/zones/jsstreamplayerdomain-zone.js | 30 ++++++++++++++----- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/examples/zones/jsstreamplayerdomain-zone-entity.js b/examples/zones/jsstreamplayerdomain-zone-entity.js index 3730c71b4f..bf811710eb 100644 --- a/examples/zones/jsstreamplayerdomain-zone-entity.js +++ b/examples/zones/jsstreamplayerdomain-zone-entity.js @@ -28,6 +28,6 @@ }; if (!isScriptRunning(SCRIPT_NAME)) { - Script.load(SCRIPT_NAME); + ScriptDiscoveryService.loadOneScript(SCRIPT_NAME); } }) \ No newline at end of file diff --git a/examples/zones/jsstreamplayerdomain-zone.js b/examples/zones/jsstreamplayerdomain-zone.js index 8e2195bd12..60564d373a 100644 --- a/examples/zones/jsstreamplayerdomain-zone.js +++ b/examples/zones/jsstreamplayerdomain-zone.js @@ -33,7 +33,7 @@ var toggleStreamPlayButton = Overlays.addOverlay("text", { visible: false, text: " Play" }); - + // Set up toggleStreamStopButton overlay. var toggleStreamStopButton = Overlays.addOverlay("text", { x: 166, @@ -47,7 +47,7 @@ var toggleStreamStopButton = Overlays.addOverlay("text", { visible: false, text: " Stop" }); - + // Set up increaseVolumeButton overlay. var toggleIncreaseVolumeButton = Overlays.addOverlay("text", { x: 211, @@ -61,7 +61,7 @@ var toggleIncreaseVolumeButton = Overlays.addOverlay("text", { visible: false, text: " +" }); - + // Set up decreaseVolumeButton overlay. var toggleDecreaseVolumeButton = Overlays.addOverlay("text", { x: 234, @@ -93,7 +93,7 @@ function changeVolume(volume) { } streamWindow.eventBridge.emitScriptEvent(JSON.stringify(volumeJSON)); } - + // Function that adds mousePressEvent functionality to connect UI to enter stream URL, play and stop stream. function mousePressEvent(event) { if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleStreamPlayButton) { @@ -116,7 +116,7 @@ function mousePressEvent(event) { // Function checking bool if in proper zone. function isOurZone(properties) { - return stream != "" && properties.type == "Zone"; + return stream != "" && stream != undefined && properties.type == "Zone"; } // Function to toggle visibile the overlay. @@ -129,7 +129,21 @@ function toggleVisible(newVisibility) { Overlays.editOverlay(toggleDecreaseVolumeButton, {visible: visible}); } } - + +// Procedure to check to see if you within a zone with a given stream. +var entities = Entities.findEntities(MyAvatar.position, 0.1); +for (var i in entities) { + var properties = Entities.getEntityProperties(entities[i]); + if (properties.type == "Zone") { + print("Entered zone: " + JSON.stringify(entities[i])); + stream = JSON.parse(properties.userData).stream; + if (isOurZone(properties)) { + print("Entered zone " + JSON.stringify(entities[i]) + " with stream: " + stream); + lastZone = properties.name; + toggleVisible(true); + } + } +} // Function to check if avatar is in proper domain. Window.domainChanged.connect(function() { Script.stop(); @@ -139,7 +153,7 @@ Window.domainChanged.connect(function() { Entities.enterEntity.connect(function(entityID) { print("Entered..." + JSON.stringify(entityID)); var properties = Entities.getEntityProperties(entityID); - stream = properties.userData; + stream = JSON.parse(properties.userData).stream; if(isOurZone(properties)) { lastZone = properties.name; @@ -173,4 +187,4 @@ Controller.mousePressEvent.connect(mousePressEvent); streamWindow.setVisible(false); // Call function upon ending script. -Script.scriptEnding.connect(onScriptEnding); \ No newline at end of file +Script.scriptEnding.connect(onScriptEnding); From 12f9091dc137863a1d891b065cebded974ea1629 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 6 Jan 2016 11:59:51 -0800 Subject: [PATCH 121/215] Fix doInBatch lambdas --- interface/src/Application.cpp | 2 +- interface/src/ui/ApplicationCompositor.cpp | 4 ++-- interface/src/ui/ApplicationOverlay.cpp | 2 +- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 2 +- libraries/render-utils/src/AntialiasingEffect.cpp | 2 +- libraries/render-utils/src/DeferredLightingEffect.cpp | 4 ++-- libraries/render-utils/src/HitEffect.cpp | 2 +- libraries/render-utils/src/RenderDeferredTask.cpp | 6 +++--- libraries/render-utils/src/ToneMappingEffect.cpp | 2 +- libraries/render/src/render/DrawStatus.cpp | 2 +- libraries/render/src/render/DrawTask.cpp | 2 +- 11 files changed, 15 insertions(+), 15 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4c4786c6a2..2d57d5bd29 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1600,7 +1600,7 @@ void Application::paintGL() { Stats::getInstance()->setRenderDetails(renderArgs._details); // Reset the gpu::Context Stages // Back to the default framebuffer; - gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) { + gpu::doInBatch(renderArgs._context, [&](gpu::Batch& batch) { batch.resetStages(); }); } diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index abc3520c83..cdbad3a620 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -202,7 +202,7 @@ void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) { updateTooltips(); //Handle fading and deactivation/activation of UI - gpu::doInBatch(renderArgs->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(renderArgs->_context, [&](gpu::Batch& batch) { auto geometryCache = DependencyManager::get(); @@ -270,7 +270,7 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int auto geometryCache = DependencyManager::get(); - gpu::doInBatch(renderArgs->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(renderArgs->_context, [&](gpu::Batch& batch) { geometryCache->useSimpleDrawPipeline(batch); batch.setResourceTexture(0, overlayFramebuffer->getRenderBuffer(0)); diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 9259478d46..d16431e9fb 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -70,7 +70,7 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { } // Execute the batch into our framebuffer - doInBatch(renderArgs->_context, [=](gpu::Batch& batch) { + doInBatch(renderArgs->_context, [&](gpu::Batch& batch) { renderArgs->_batch = &batch; int width = _overlayFramebuffer->getWidth(); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index c32bf2654d..39097e485b 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -179,7 +179,7 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons assert(renderContext->getArgs()->_viewFrustum); RenderArgs* args = renderContext->getArgs(); - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { auto framebufferCache = DependencyManager::get(); QSize framebufferSize = framebufferCache->getFrameBufferSize(); float fbWidth = framebufferSize.width(); diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index 3acc88f953..81ca5dcdaf 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -101,7 +101,7 @@ void Antialiasing::run(const render::SceneContextPointer& sceneContext, const re } RenderArgs* args = renderContext->getArgs(); - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); auto framebufferCache = DependencyManager::get(); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index e6892b95f4..5e6d9c2a10 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -295,7 +295,7 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu } void DeferredLightingEffect::prepare(RenderArgs* args) { - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); @@ -326,7 +326,7 @@ void DeferredLightingEffect::prepare(RenderArgs* args) { } void DeferredLightingEffect::render(RenderArgs* args) { - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { // Allocate the parameters buffer used by all the deferred shaders if (!_deferredTransformBuffer[0]._buffer) { diff --git a/libraries/render-utils/src/HitEffect.cpp b/libraries/render-utils/src/HitEffect.cpp index bf65eaf059..89f950d830 100644 --- a/libraries/render-utils/src/HitEffect.cpp +++ b/libraries/render-utils/src/HitEffect.cpp @@ -64,7 +64,7 @@ void HitEffect::run(const render::SceneContextPointer& sceneContext, const rende assert(renderContext->getArgs()); assert(renderContext->getArgs()->_viewFrustum); RenderArgs* args = renderContext->getArgs(); - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { glm::mat4 projMat; Transform viewMat; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index ca25383a8d..b9dfa3e3ec 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -349,7 +349,7 @@ void DrawStencilDeferred::run(const SceneContextPointer& sceneContext, const Ren // from the touched pixel generate the stencil buffer RenderArgs* args = renderContext->getArgs(); - doInBatch(args->_context, [=](gpu::Batch& batch) { + doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; auto deferredFboColorDepthStencil = DependencyManager::get()->getDeferredFramebufferDepthColor(); @@ -384,7 +384,7 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const inItems.emplace_back(id); } RenderArgs* args = renderContext->getArgs(); - doInBatch(args->_context, [=](gpu::Batch& batch) { + doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; auto lightingFBO = DependencyManager::get()->getLightingFramebuffer(); @@ -428,7 +428,7 @@ void Blit::run(const SceneContextPointer& sceneContext, const RenderContextPoint auto framebufferCache = DependencyManager::get(); auto primaryFbo = framebufferCache->getPrimaryFramebuffer(); - gpu::doInBatch(renderArgs->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(renderArgs->_context, [&](gpu::Batch& batch) { batch.setFramebuffer(blitFbo); if (renderArgs->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { diff --git a/libraries/render-utils/src/ToneMappingEffect.cpp b/libraries/render-utils/src/ToneMappingEffect.cpp index 2583719424..85c5810cd2 100644 --- a/libraries/render-utils/src/ToneMappingEffect.cpp +++ b/libraries/render-utils/src/ToneMappingEffect.cpp @@ -112,7 +112,7 @@ void ToneMappingEffect::render(RenderArgs* args) { init(); } auto framebufferCache = DependencyManager::get(); - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); QSize framebufferSize = framebufferCache->getFrameBufferSize(); diff --git a/libraries/render/src/render/DrawStatus.cpp b/libraries/render/src/render/DrawStatus.cpp index fa177bd0d4..3f919b3d8c 100644 --- a/libraries/render/src/render/DrawStatus.cpp +++ b/libraries/render/src/render/DrawStatus.cpp @@ -160,7 +160,7 @@ void DrawStatus::run(const SceneContextPointer& sceneContext, } // Allright, something to render let's do it - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { glm::mat4 projMat; Transform viewMat; args->_viewFrustum->evalProjectionMatrix(projMat); diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 2b977081a1..88aeb55ffc 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -212,7 +212,7 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext args->_details.pointTo(RenderDetails::OTHER_ITEM); cullItems(sceneContext, renderContext, inItems, culledItems); - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; renderLights(sceneContext, renderContext, culledItems); args->_batch = nullptr; From 11dc3cd2611824001ed8caf519467b931ab52164 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 8 Jan 2016 16:41:19 -0800 Subject: [PATCH 122/215] Move primitive rendering out of DeferredLightingEffect --- interface/src/Application.cpp | 2 +- interface/src/Util.cpp | 16 +- interface/src/avatar/Avatar.cpp | 15 +- interface/src/avatar/Hand.cpp | 5 +- interface/src/avatar/Head.cpp | 13 +- interface/src/avatar/SkeletonModel.cpp | 8 +- interface/src/ui/ApplicationOverlay.cpp | 1 - interface/src/ui/overlays/Circle3DOverlay.cpp | 3 +- interface/src/ui/overlays/Cube3DOverlay.cpp | 5 +- interface/src/ui/overlays/Image3DOverlay.cpp | 3 +- interface/src/ui/overlays/Line3DOverlay.cpp | 3 +- interface/src/ui/overlays/Sphere3DOverlay.cpp | 6 +- interface/src/ui/overlays/Text3DOverlay.cpp | 3 +- interface/src/ui/overlays/Web3DOverlay.cpp | 4 +- .../src/EntityTreeRenderer.cpp | 1 - .../src/RenderableBoxEntityItem.cpp | 3 +- .../src/RenderableLightEntityItem.cpp | 2 +- .../src/RenderableLineEntityItem.cpp | 3 +- .../src/RenderableModelEntityItem.cpp | 3 +- .../RenderableParticleEffectEntityItem.cpp | 1 - .../src/RenderablePolyLineEntityItem.cpp | 1 - .../src/RenderablePolyVoxEntityItem.cpp | 1 - .../src/RenderableSphereEntityItem.cpp | 3 +- .../src/RenderableTextEntityItem.cpp | 3 +- .../src/RenderableWebEntityItem.cpp | 5 +- .../src/RenderableZoneEntityItem.cpp | 7 +- .../src/DeferredLightingEffect.cpp | 191 +----------------- .../render-utils/src/DeferredLightingEffect.h | 96 +-------- libraries/render-utils/src/GeometryCache.cpp | 184 +++++++++++++++++ libraries/render-utils/src/GeometryCache.h | 99 ++++++++- .../render-utils/src/MeshPartPayload.cpp | 2 +- libraries/render-utils/src/TextRenderer3D.cpp | 1 - 32 files changed, 333 insertions(+), 360 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2d57d5bd29..7134860df0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3611,7 +3611,7 @@ namespace render { PerformanceTimer perfTimer("worldBox"); auto& batch = *args->_batch; - DependencyManager::get()->bindSimpleProgram(batch); + DependencyManager::get()->bindSimpleProgram(batch); renderWorldBox(batch); } } diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 3d97d48f90..4983983c02 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -96,28 +95,27 @@ void renderWorldBox(gpu::Batch& batch) { geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), glm::vec3(HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY); - auto deferredLighting = DependencyManager::get(); - - deferredLighting->renderWireCubeInstance(batch, Transform(), GREY4); + + geometryCache->renderWireCubeInstance(batch, Transform(), GREY4); // Draw meter markers along the 3 axis to help with measuring things const float MARKER_DISTANCE = 1.0f; const float MARKER_RADIUS = 0.05f; transform = Transform().setScale(MARKER_RADIUS); - deferredLighting->renderSolidSphereInstance(batch, transform, RED); + geometryCache->renderSolidSphereInstance(batch, transform, RED); transform = Transform().setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, 0.0f)).setScale(MARKER_RADIUS); - deferredLighting->renderSolidSphereInstance(batch, transform, RED); + geometryCache->renderSolidSphereInstance(batch, transform, RED); transform = Transform().setTranslation(glm::vec3(0.0f, MARKER_DISTANCE, 0.0f)).setScale(MARKER_RADIUS); - deferredLighting->renderSolidSphereInstance(batch, transform, GREEN); + geometryCache->renderSolidSphereInstance(batch, transform, GREEN); transform = Transform().setTranslation(glm::vec3(0.0f, 0.0f, MARKER_DISTANCE)).setScale(MARKER_RADIUS); - deferredLighting->renderSolidSphereInstance(batch, transform, BLUE); + geometryCache->renderSolidSphereInstance(batch, transform, BLUE); transform = Transform().setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, MARKER_DISTANCE)).setScale(MARKER_RADIUS); - deferredLighting->renderSolidSphereInstance(batch, transform, GREY); + geometryCache->renderSolidSphereInstance(batch, transform, GREY); } // Return a random vector of average length 1 diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 4f19b33abf..7cde674e52 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -331,7 +331,6 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { if (glm::distance(DependencyManager::get()->getMyAvatar()->getPosition(), getPosition()) < 10.0f) { auto geometryCache = DependencyManager::get(); - auto deferredLighting = DependencyManager::get(); // render pointing lasers glm::vec3 laserColor = glm::vec3(1.0f, 0.0f, 1.0f); @@ -359,7 +358,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { pointerTransform.setTranslation(position); pointerTransform.setRotation(rotation); batch.setModelTransform(pointerTransform); - deferredLighting->bindSimpleProgram(batch); + geometryCache->bindSimpleProgram(batch); geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor); } } @@ -383,7 +382,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { pointerTransform.setTranslation(position); pointerTransform.setRotation(rotation); batch.setModelTransform(pointerTransform); - deferredLighting->bindSimpleProgram(batch); + geometryCache->bindSimpleProgram(batch); geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor); } } @@ -457,7 +456,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { Transform transform; transform.setTranslation(position); transform.postScale(INDICATOR_RADIUS); - DependencyManager::get()->renderSolidSphereInstance(batch, transform, LOOK_AT_INDICATOR_COLOR); + DependencyManager::get()->renderSolidSphereInstance(batch, transform, LOOK_AT_INDICATOR_COLOR); } // If the avatar is looking at me, indicate that they are @@ -485,7 +484,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { eyeDiameter = DEFAULT_EYE_DIAMETER; } - DependencyManager::get()->renderSolidSphereInstance(batch, + DependencyManager::get()->renderSolidSphereInstance(batch, Transform(transform).postScale(eyeDiameter * getUniformScale() / 2.0f + RADIUS_INCREMENT), glm::vec4(LOOKING_AT_ME_COLOR, alpha)); @@ -495,7 +494,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { if (eyeDiameter == 0.0f) { eyeDiameter = DEFAULT_EYE_DIAMETER; } - DependencyManager::get()->renderSolidSphereInstance(batch, + DependencyManager::get()->renderSolidSphereInstance(batch, Transform(transform).postScale(eyeDiameter * getUniformScale() / 2.0f + RADIUS_INCREMENT), glm::vec4(LOOKING_AT_ME_COLOR, alpha)); @@ -655,7 +654,7 @@ void Avatar::renderBillboard(RenderArgs* renderArgs) { gpu::Batch& batch = *renderArgs->_batch; PROFILE_RANGE_BATCH(batch, __FUNCTION__); batch.setResourceTexture(0, _billboardTexture->getGPUTexture()); - DependencyManager::get()->bindSimpleProgram(batch, true); + DependencyManager::get()->bindSimpleProgram(batch, true); DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); } @@ -791,7 +790,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, co { PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderBevelCornersRect"); - DependencyManager::get()->bindSimpleProgram(batch, false, true, true, true); + DependencyManager::get()->bindSimpleProgram(batch, false, true, true, true); DependencyManager::get()->renderBevelCornersRect(batch, left, bottom, width, height, bevelDistance, backgroundColor); } diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index fe03d22f0b..fba5e1ab13 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -14,7 +14,6 @@ #include #include -#include #include "Avatar.h" #include "AvatarManager.h" @@ -61,7 +60,7 @@ void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) { transform.setTranslation(position); transform.setRotation(palm.getRotation()); transform.postScale(SPHERE_RADIUS); - DependencyManager::get()->renderSolidSphereInstance(batch, transform, grayColor); + DependencyManager::get()->renderSolidSphereInstance(batch, transform, grayColor); // draw a green sphere at the old "finger tip" transform = Transform(); @@ -69,7 +68,7 @@ void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) { transform.setTranslation(position); transform.setRotation(palm.getRotation()); transform.postScale(SPHERE_RADIUS); - DependencyManager::get()->renderSolidSphereInstance(batch, transform, greenColor); + DependencyManager::get()->renderSolidSphereInstance(batch, transform, greenColor); } } diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index aa2d268f3d..61bc5c861e 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -11,8 +11,6 @@ #include #include -#include -#include #include #include @@ -451,12 +449,11 @@ void Head::renderLookatVectors(RenderArgs* renderArgs, glm::vec3 leftEyePosition batch.setModelTransform(transform); // FIXME: THe line width of 2.0f is not supported anymore, we ll need a workaround - auto deferredLighting = DependencyManager::get(); - deferredLighting->bindSimpleProgram(batch); - - auto geometryCache = DependencyManager::get(); glm::vec4 startColor(0.2f, 0.2f, 0.2f, 1.0f); glm::vec4 endColor(1.0f, 1.0f, 1.0f, 0.0f); + + auto geometryCache = DependencyManager::get(); + geometryCache->bindSimpleProgram(batch); geometryCache->renderLine(batch, leftEyePosition, lookatPosition, startColor, endColor, _leftEyeLookAtID); geometryCache->renderLine(batch, rightEyePosition, lookatPosition, startColor, endColor, _rightEyeLookAtID); } @@ -466,9 +463,9 @@ void Head::renderLookatTarget(RenderArgs* renderArgs, glm::vec3 lookatPosition) auto transform = Transform{}; transform.setTranslation(lookatPosition); - auto deferredLighting = DependencyManager::get(); + auto geometryCache = DependencyManager::get(); const float LOOK_AT_TARGET_RADIUS = 0.075f; transform.postScale(LOOK_AT_TARGET_RADIUS); const glm::vec4 LOOK_AT_TARGET_COLOR = { 0.8f, 0.0f, 0.0f, 0.75f }; - deferredLighting->renderSolidSphereInstance(batch, transform, LOOK_AT_TARGET_COLOR); + geometryCache->renderSolidSphereInstance(batch, transform, LOOK_AT_TARGET_COLOR); } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 3cd74afb81..b7a154851f 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -12,7 +12,6 @@ #include #include -#include #include #include "Application.h" @@ -347,11 +346,10 @@ void SkeletonModel::computeBoundingShape() { void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float scale, float alpha) { auto geometryCache = DependencyManager::get(); - auto deferredLighting = DependencyManager::get(); // draw a blue sphere at the capsule top point glm::vec3 topPoint = _translation + getRotation() * (scale * (_boundingCapsuleLocalOffset + (0.5f * _boundingCapsuleHeight) * Vectors::UNIT_Y)); - deferredLighting->renderSolidSphereInstance(batch, + geometryCache->renderSolidSphereInstance(batch, Transform().setTranslation(topPoint).postScale(scale * _boundingCapsuleRadius), glm::vec4(0.6f, 0.6f, 0.8f, alpha)); @@ -359,14 +357,14 @@ void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float scale glm::vec3 bottomPoint = topPoint - glm::vec3(0.0f, scale * _boundingCapsuleHeight, 0.0f); glm::vec3 axis = topPoint - bottomPoint; - deferredLighting->renderSolidSphereInstance(batch, + geometryCache->renderSolidSphereInstance(batch, Transform().setTranslation(bottomPoint).postScale(scale * _boundingCapsuleRadius), glm::vec4(0.8f, 0.8f, 0.6f, alpha)); // draw a green cylinder between the two points glm::vec3 origin(0.0f); batch.setModelTransform(Transform().setTranslation(bottomPoint)); - deferredLighting->bindSimpleProgram(batch); + geometryCache->bindSimpleProgram(batch); Avatar::renderJointConnectingCone(batch, origin, axis, scale * _boundingCapsuleRadius, scale * _boundingCapsuleRadius, glm::vec4(0.6f, 0.8f, 0.6f, alpha)); } diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index d16431e9fb..43966553de 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -12,7 +12,6 @@ #include #include -#include #include #include #include diff --git a/interface/src/ui/overlays/Circle3DOverlay.cpp b/interface/src/ui/overlays/Circle3DOverlay.cpp index 0b7da72d58..bbb9addc3d 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.cpp +++ b/interface/src/ui/overlays/Circle3DOverlay.cpp @@ -10,7 +10,6 @@ #include "Circle3DOverlay.h" -#include #include #include @@ -106,7 +105,7 @@ void Circle3DOverlay::render(RenderArgs* args) { auto transform = _transform; transform.postScale(glm::vec3(getDimensions(), 1.0f)); batch.setModelTransform(transform); - DependencyManager::get()->bindSimpleProgram(batch, false, false); + DependencyManager::get()->bindSimpleProgram(batch, false, false); // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise // we just draw a line... diff --git a/interface/src/ui/overlays/Cube3DOverlay.cpp b/interface/src/ui/overlays/Cube3DOverlay.cpp index 3ad887ca65..7688bce985 100644 --- a/interface/src/ui/overlays/Cube3DOverlay.cpp +++ b/interface/src/ui/overlays/Cube3DOverlay.cpp @@ -13,7 +13,6 @@ #include -#include #include #include #include @@ -61,7 +60,7 @@ void Cube3DOverlay::render(RenderArgs* args) { // } transform.setScale(dimensions); - DependencyManager::get()->renderSolidCubeInstance(*batch, transform, cubeColor); + DependencyManager::get()->renderSolidCubeInstance(*batch, transform, cubeColor); } else { if (getIsDashedLine()) { @@ -99,7 +98,7 @@ void Cube3DOverlay::render(RenderArgs* args) { } else { batch->setModelTransform(Transform()); transform.setScale(dimensions); - DependencyManager::get()->renderWireCubeInstance(*batch, transform, cubeColor); + DependencyManager::get()->renderWireCubeInstance(*batch, transform, cubeColor); } } } diff --git a/interface/src/ui/overlays/Image3DOverlay.cpp b/interface/src/ui/overlays/Image3DOverlay.cpp index f1e0f08a3a..8ce8bf7a5f 100644 --- a/interface/src/ui/overlays/Image3DOverlay.cpp +++ b/interface/src/ui/overlays/Image3DOverlay.cpp @@ -14,7 +14,6 @@ #include -#include #include #include #include @@ -96,7 +95,7 @@ void Image3DOverlay::render(RenderArgs* args) { batch->setModelTransform(transform); batch->setResourceTexture(0, _texture->getGPUTexture()); - DependencyManager::get()->bindSimpleProgram(*batch, true, false, _emissive, true); + DependencyManager::get()->bindSimpleProgram(*batch, true, false, _emissive, true); DependencyManager::get()->renderQuad( *batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha) diff --git a/interface/src/ui/overlays/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp index 9dc609af31..ed97b95de0 100644 --- a/interface/src/ui/overlays/Line3DOverlay.cpp +++ b/interface/src/ui/overlays/Line3DOverlay.cpp @@ -12,7 +12,6 @@ #include #include -#include QString const Line3DOverlay::TYPE = "line3d"; @@ -54,7 +53,7 @@ void Line3DOverlay::render(RenderArgs* args) { auto batch = args->_batch; if (batch) { batch->setModelTransform(_transform); - DependencyManager::get()->bindSimpleProgram(*batch); + DependencyManager::get()->bindSimpleProgram(*batch); if (getIsDashedLine()) { // TODO: add support for color to renderDashedLine() diff --git a/interface/src/ui/overlays/Sphere3DOverlay.cpp b/interface/src/ui/overlays/Sphere3DOverlay.cpp index 7caff3ea04..63ed7fe31d 100644 --- a/interface/src/ui/overlays/Sphere3DOverlay.cpp +++ b/interface/src/ui/overlays/Sphere3DOverlay.cpp @@ -12,7 +12,6 @@ #include #include -#include #include #include @@ -45,12 +44,11 @@ void Sphere3DOverlay::render(RenderArgs* args) { Transform transform = _transform; transform.postScale(getDimensions() * SPHERE_OVERLAY_SCALE); if (_isSolid) { - DependencyManager::get()->renderSolidSphereInstance(*batch, transform, sphereColor); + DependencyManager::get()->renderSolidSphereInstance(*batch, transform, sphereColor); } else { - DependencyManager::get()->renderWireSphereInstance(*batch, transform, sphereColor); + DependencyManager::get()->renderWireSphereInstance(*batch, transform, sphereColor); } } - } Sphere3DOverlay* Sphere3DOverlay::createClone() const { diff --git a/interface/src/ui/overlays/Text3DOverlay.cpp b/interface/src/ui/overlays/Text3DOverlay.cpp index 8c448234ad..2e5110951d 100644 --- a/interface/src/ui/overlays/Text3DOverlay.cpp +++ b/interface/src/ui/overlays/Text3DOverlay.cpp @@ -10,7 +10,6 @@ #include "Text3DOverlay.h" -#include #include #include #include @@ -101,7 +100,7 @@ void Text3DOverlay::render(RenderArgs* args) { glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, SLIGHTLY_BEHIND); glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, SLIGHTLY_BEHIND); - DependencyManager::get()->bindSimpleProgram(batch, false, true, false, true); + DependencyManager::get()->bindSimpleProgram(batch, false, true, false, true); DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, quadColor); // Same font properties as textSize() diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 1088473a25..1ec502139b 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -16,8 +16,6 @@ #include #include - -#include #include #include #include @@ -103,7 +101,7 @@ void Web3DOverlay::render(RenderArgs* args) { } batch.setModelTransform(transform); - DependencyManager::get()->bindSimpleProgram(batch, true, false, false, true); + DependencyManager::get()->bindSimpleProgram(batch, true, false, false, true); DependencyManager::get()->renderQuad(batch, halfSize * -1.0f, halfSize, vec2(0), vec2(1), color); batch.setResourceTexture(0, args->_whiteTexture); // restore default white color after me } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 07d9031f41..6beba4eefa 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp index 4de363016b..1b1437a7d9 100644 --- a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp @@ -15,7 +15,6 @@ #include -#include #include #include #include @@ -69,7 +68,7 @@ void RenderableBoxEntityItem::render(RenderArgs* args) { batch._glColor4f(color.r, color.g, color.b, color.a); DependencyManager::get()->renderCube(batch); } else { - DependencyManager::get()->renderSolidCubeInstance(batch, transToCenter, cubeColor); + DependencyManager::get()->renderSolidCubeInstance(batch, transToCenter, cubeColor); } static const auto triCount = DependencyManager::get()->getCubeTriangleCount(); args->_details._trianglesRendered += (int)triCount; diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp index 5b8891d1f2..39182f322c 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp @@ -51,7 +51,7 @@ void RenderableLightEntityItem::render(RenderArgs* args) { Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; batch.setModelTransform(getTransformToCenter()); - DependencyManager::get()->renderWireSphere(batch, 0.5f, 15, 15, glm::vec4(color, 1.0f)); + DependencyManager::get()->renderWireSphere(batch, 0.5f, 15, 15, glm::vec4(color, 1.0f)); #endif }; diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp index 8eb3ea8754..b8815aab7c 100644 --- a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include "RenderableLineEntityItem.h" @@ -53,7 +52,7 @@ void RenderableLineEntityItem::render(RenderArgs* args) { batch.setModelTransform(transform); if (getLinePoints().size() > 1) { - DependencyManager::get()->bindSimpleProgram(batch); + DependencyManager::get()->bindSimpleProgram(batch); DependencyManager::get()->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID); } }; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index f5090cc20c..7424180437 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -16,7 +16,6 @@ #include #include -#include #include #include #include @@ -432,7 +431,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) { auto shapeTransform = getTransformToCenter(success); if (success) { batch.setModelTransform(Transform()); // we want to include the scale as well - DependencyManager::get()->renderWireCubeInstance(batch, shapeTransform, greenColor); + DependencyManager::get()->renderWireCubeInstance(batch, shapeTransform, greenColor); } } } diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 115eba0a05..e757f5c68a 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -11,7 +11,6 @@ #include #include -#include #include #include #include diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index fd28bc043d..600b876d39 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include "RenderablePolyLineEntityItem.h" diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 1048f594f4..1029f3b3af 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -27,7 +27,6 @@ #pragma GCC diagnostic pop #endif -#include #include #include #include diff --git a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp index 9bed5b3bb0..9f16de0db1 100644 --- a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp @@ -16,7 +16,6 @@ #include #include -#include #include #include @@ -73,7 +72,7 @@ void RenderableSphereEntityItem::render(RenderArgs* args) { DependencyManager::get()->renderSphere(batch); } else { batch.setModelTransform(Transform()); - DependencyManager::get()->renderSolidSphereInstance(batch, modelTransform, sphereColor); + DependencyManager::get()->renderSolidSphereInstance(batch, modelTransform, sphereColor); } static const auto triCount = DependencyManager::get()->getSphereTriangleCount(); args->_details._trianglesRendered += (int)triCount; diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index d88b4d5f0a..5cf31c15e0 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -11,7 +11,6 @@ #include -#include #include #include #include @@ -63,7 +62,7 @@ void RenderableTextEntityItem::render(RenderArgs* args) { batch.setModelTransform(transformToTopLeft); - DependencyManager::get()->bindSimpleProgram(batch, false, false, false, true); + DependencyManager::get()->bindSimpleProgram(batch, false, false, false, true); DependencyManager::get()->renderQuad(batch, minCorner, maxCorner, backgroundColor); float scale = _lineHeight / _textRenderer->getFontSize(); diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 979ec32878..ce89197069 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -15,7 +15,6 @@ #include -#include #include #include #include @@ -69,7 +68,7 @@ void RenderableWebEntityItem::render(RenderArgs* args) { gpu::Batch& batch = *args->_batch; batch.setModelTransform(getTransformToCenter()); // we want to include the scale as well glm::vec4 cubeColor{ 1.0f, 0.0f, 0.0f, 1.0f}; - DependencyManager::get()->renderWireCube(batch, 1.0f, cubeColor); + DependencyManager::get()->renderWireCube(batch, 1.0f, cubeColor); } #endif @@ -201,7 +200,7 @@ void RenderableWebEntityItem::render(RenderArgs* args) { textured = emissive = true; } - DependencyManager::get()->bindSimpleProgram(batch, textured, culled, emissive); + DependencyManager::get()->bindSimpleProgram(batch, textured, culled, emissive); DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, texMin, texMax, glm::vec4(1.0f)); } diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index eb01bd551e..9396933fc6 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include #include @@ -140,12 +139,12 @@ void RenderableZoneEntityItem::render(RenderArgs* args) { if (!success) { break; } - auto deferredLightingEffect = DependencyManager::get(); + auto geometryCache = DependencyManager::get(); if (getShapeType() == SHAPE_TYPE_SPHERE) { shapeTransform.postScale(SPHERE_ENTITY_SCALE); - deferredLightingEffect->renderWireSphereInstance(batch, shapeTransform, DEFAULT_COLOR); + geometryCache->renderWireSphereInstance(batch, shapeTransform, DEFAULT_COLOR); } else { - deferredLightingEffect->renderWireCubeInstance(batch, shapeTransform, DEFAULT_COLOR); + geometryCache->renderWireCubeInstance(batch, shapeTransform, DEFAULT_COLOR); } break; } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 5e6d9c2a10..d5dd53c252 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -24,11 +24,6 @@ #include "TextureCache.h" #include "FramebufferCache.h" - -#include "simple_vert.h" -#include "simple_textured_frag.h" -#include "simple_textured_emisive_frag.h" - #include "deferred_light_vert.h" #include "deferred_light_limited_vert.h" #include "deferred_light_spot_vert.h" @@ -53,47 +48,7 @@ struct LightLocations { static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations); -gpu::PipelinePointer DeferredLightingEffect::getPipeline(SimpleProgramKey config) { - auto it = _simplePrograms.find(config); - if (it != _simplePrograms.end()) { - return it.value(); - } - - auto state = std::make_shared(); - if (config.isCulled()) { - state->setCullMode(gpu::State::CULL_BACK); - } else { - state->setCullMode(gpu::State::CULL_NONE); - } - state->setDepthTest(true, true, gpu::LESS_EQUAL); - if (config.hasDepthBias()) { - state->setDepthBias(1.0f); - state->setDepthBiasSlopeScale(1.0f); - } - state->setBlendFunction(false, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - - gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader; - gpu::PipelinePointer pipeline = gpu::Pipeline::create(program, state); - _simplePrograms.insert(config, pipeline); - return pipeline; -} - void DeferredLightingEffect::init() { - auto VS = gpu::Shader::createVertex(std::string(simple_vert)); - auto PS = gpu::Shader::createPixel(std::string(simple_textured_frag)); - auto PSEmissive = gpu::Shader::createPixel(std::string(simple_textured_emisive_frag)); - - _simpleShader = gpu::Shader::createProgram(VS, PS); - _emissiveShader = gpu::Shader::createProgram(VS, PSEmissive); - - gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT)); - gpu::Shader::makeProgram(*_simpleShader, slotBindings); - gpu::Shader::makeProgram(*_emissiveShader, slotBindings); - - _directionalLightLocations = std::make_shared(); _directionalAmbientSphereLightLocations = std::make_shared(); _directionalSkyboxLightLocations = std::make_shared(); @@ -123,144 +78,6 @@ void DeferredLightingEffect::init() { lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET)); } - - -gpu::PipelinePointer DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, - bool emissive, bool depthBias) { - SimpleProgramKey config{textured, culled, emissive, depthBias}; - gpu::PipelinePointer pipeline = getPipeline(config); - batch.setPipeline(pipeline); - - gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader; - - if (!config.isTextured()) { - // If it is not textured, bind white texture and keep using textured pipeline - batch.setResourceTexture(0, DependencyManager::get()->getWhiteTexture()); - } - - batch.setResourceTexture(NORMAL_FITTING_MAP_SLOT, DependencyManager::get()->getNormalFittingTexture()); - return pipeline; -} - -uint32_t toCompactColor(const glm::vec4& color) { - uint32_t compactColor = ((int(color.x * 255.0f) & 0xFF)) | - ((int(color.y * 255.0f) & 0xFF) << 8) | - ((int(color.z * 255.0f) & 0xFF) << 16) | - ((int(color.w * 255.0f) & 0xFF) << 24); - return compactColor; -} - -static const size_t INSTANCE_TRANSFORM_BUFFER = 0; -static const size_t INSTANCE_COLOR_BUFFER = 1; - -template -void renderInstances(const std::string& name, gpu::Batch& batch, const Transform& transform, const glm::vec4& color, F f) { - { - gpu::BufferPointer instanceTransformBuffer = batch.getNamedBuffer(name, INSTANCE_TRANSFORM_BUFFER); - glm::mat4 glmTransform; - instanceTransformBuffer->append(transform.getMatrix(glmTransform)); - - gpu::BufferPointer instanceColorBuffer = batch.getNamedBuffer(name, INSTANCE_COLOR_BUFFER); - auto compactColor = toCompactColor(color); - instanceColorBuffer->append(compactColor); - } - - auto that = DependencyManager::get(); - batch.setupNamedCalls(name, [=](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - auto pipeline = that->bindSimpleProgram(batch); - auto location = pipeline->getProgram()->getUniforms().findLocation("Instanced"); - - batch._glUniform1i(location, 1); - f(batch, data); - batch._glUniform1i(location, 0); - }); -} - -void DeferredLightingEffect::renderSolidSphereInstance(gpu::Batch& batch, const Transform& transform, const glm::vec4& color) { - static const std::string INSTANCE_NAME = __FUNCTION__; - renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - DependencyManager::get()->renderShapeInstances(batch, GeometryCache::Sphere, data._count, - data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); - }); -} - -void DeferredLightingEffect::renderWireSphereInstance(gpu::Batch& batch, const Transform& transform, const glm::vec4& color) { - static const std::string INSTANCE_NAME = __FUNCTION__; - renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - DependencyManager::get()->renderWireShapeInstances(batch, GeometryCache::Sphere, data._count, - data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); - }); -} - -// Enable this in a debug build to cause 'box' entities to iterate through all the -// available shape types, both solid and wireframes -//#define DEBUG_SHAPES - -void DeferredLightingEffect::renderSolidCubeInstance(gpu::Batch& batch, const Transform& transform, const glm::vec4& color) { - static const std::string INSTANCE_NAME = __FUNCTION__; - -#ifdef DEBUG_SHAPES - static auto startTime = usecTimestampNow(); - renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - - auto usecs = usecTimestampNow(); - usecs -= startTime; - auto msecs = usecs / USECS_PER_MSEC; - float seconds = msecs; - seconds /= MSECS_PER_SECOND; - float fractionalSeconds = seconds - floor(seconds); - int shapeIndex = (int)seconds; - - // Every second we flip to the next shape. - static const int SHAPE_COUNT = 5; - GeometryCache::Shape shapes[SHAPE_COUNT] = { - GeometryCache::Cube, - GeometryCache::Tetrahedron, - GeometryCache::Sphere, - GeometryCache::Icosahedron, - GeometryCache::Line, - }; - - shapeIndex %= SHAPE_COUNT; - GeometryCache::Shape shape = shapes[shapeIndex]; - - // For the first half second for a given shape, show the wireframe, for the second half, show the solid. - if (fractionalSeconds > 0.5f) { - DependencyManager::get()->renderShapeInstances(batch, shape, data._count, - data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); - } else { - DependencyManager::get()->renderWireShapeInstances(batch, shape, data._count, - data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); - } - }); -#else - renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - DependencyManager::get()->renderCubeInstances(batch, data._count, - data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); - }); -#endif -} - -void DeferredLightingEffect::renderWireCubeInstance(gpu::Batch& batch, const Transform& transform, const glm::vec4& color) { - static const std::string INSTANCE_NAME = __FUNCTION__; - renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - DependencyManager::get()->renderWireCubeInstances(batch, data._count, - data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); - }); -} - -void DeferredLightingEffect::renderQuad(gpu::Batch& batch, const glm::vec3& minCorner, const glm::vec3& maxCorner, - const glm::vec4& color) { - bindSimpleProgram(batch); - DependencyManager::get()->renderQuad(batch, minCorner, maxCorner, color); -} - -void DeferredLightingEffect::renderLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, - const glm::vec4& color1, const glm::vec4& color2) { - bindSimpleProgram(batch); - DependencyManager::get()->renderLine(batch, p1, p2, color1, color2); -} - void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radius, const glm::vec3& color, float intensity) { addSpotLight(position, radius, color, intensity); @@ -663,12 +480,12 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2)); slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), 3)); slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), 5)); - const int LIGHT_GPU_SLOT = 3; + static const int LIGHT_GPU_SLOT = 3; slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_GPU_SLOT)); - const int ATMOSPHERE_GPU_SLOT = 4; + static const int ATMOSPHERE_GPU_SLOT = 4; slotBindings.insert(gpu::Shader::Binding(std::string("atmosphereBufferUnit"), ATMOSPHERE_GPU_SLOT)); - - slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), DeferredLightingEffect::DEFERRED_TRANSFORM_BUFFER_SLOT)); + static const int DEFERRED_TRANSFORM_BUFFER_SLOT = 2; + slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), DEFERRED_TRANSFORM_BUFFER_SLOT)); gpu::Shader::makeProgram(*program, slotBindings); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index f00f558122..cb746153a1 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -21,10 +21,7 @@ #include "model/Stage.h" #include "model/Geometry.h" -#include "render/ShapePipeline.h" - class RenderArgs; -class SimpleProgramKey; struct LightLocations; using LightLocationsPtr = std::shared_ptr; /// Handles deferred lighting for the bits that require it (voxels...) @@ -32,42 +29,7 @@ class DeferredLightingEffect : public Dependency { SINGLETON_DEPENDENCY public: - static const int NORMAL_FITTING_MAP_SLOT = render::ShapePipeline::Slot::NORMAL_FITTING_MAP; - static const int DEFERRED_TRANSFORM_BUFFER_SLOT = 2; - void init(); - - /// Sets up the state necessary to render static untextured geometry with the simple program. - gpu::PipelinePointer bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true, - bool emissive = false, bool depthBias = false); - - void renderSolidSphereInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color); - void renderSolidSphereInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec3& color) { - renderSolidSphereInstance(batch, xfm, glm::vec4(color, 1.0)); - } - - void renderWireSphereInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color); - void renderWireSphereInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec3& color) { - renderWireSphereInstance(batch, xfm, glm::vec4(color, 1.0)); - } - - void renderSolidCubeInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color); - void renderSolidCubeInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec3& color) { - renderSolidCubeInstance(batch, xfm, glm::vec4(color, 1.0)); - } - - void renderWireCubeInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color); - void renderWireCubeInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec3& color) { - renderWireCubeInstance(batch, xfm, glm::vec4(color, 1.0)); - } - - - //// Renders a quad with the simple program. - void renderQuad(gpu::Batch& batch, const glm::vec3& minCorner, const glm::vec3& maxCorner, const glm::vec4& color); - - //// Renders a line with the simple program. - void renderLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, - const glm::vec4& color1, const glm::vec4& color2); /// Adds a point light to render for the current frame. void addPointLight(const glm::vec3& position, float radius, const glm::vec3& color = glm::vec3(0.0f, 0.0f, 0.0f), @@ -90,17 +52,10 @@ public: void setGlobalSkybox(const model::SkyboxPointer& skybox); private: - DeferredLightingEffect() {} - virtual ~DeferredLightingEffect() { } + DeferredLightingEffect() = default; model::MeshPointer _spotLightMesh; model::MeshPointer getSpotLightMesh(); - - gpu::PipelinePointer getPipeline(SimpleProgramKey config); - - gpu::ShaderPointer _simpleShader; - gpu::ShaderPointer _emissiveShader; - QHash _simplePrograms; gpu::PipelinePointer _directionalSkyboxLight; LightLocationsPtr _directionalSkyboxLightLocations; @@ -160,53 +115,4 @@ private: UniformBufferView _deferredTransformBuffer[2]; }; -class SimpleProgramKey { -public: - enum FlagBit { - IS_TEXTURED_FLAG = 0, - IS_CULLED_FLAG, - IS_EMISSIVE_FLAG, - HAS_DEPTH_BIAS_FLAG, - - NUM_FLAGS, - }; - - enum Flag { - IS_TEXTURED = (1 << IS_TEXTURED_FLAG), - IS_CULLED = (1 << IS_CULLED_FLAG), - IS_EMISSIVE = (1 << IS_EMISSIVE_FLAG), - HAS_DEPTH_BIAS = (1 << HAS_DEPTH_BIAS_FLAG), - }; - typedef unsigned short Flags; - - bool isFlag(short flagNum) const { return bool((_flags & flagNum) != 0); } - - bool isTextured() const { return isFlag(IS_TEXTURED); } - bool isCulled() const { return isFlag(IS_CULLED); } - bool isEmissive() const { return isFlag(IS_EMISSIVE); } - bool hasDepthBias() const { return isFlag(HAS_DEPTH_BIAS); } - - Flags _flags = 0; - short _spare = 0; - - int getRaw() const { return *reinterpret_cast(this); } - - - SimpleProgramKey(bool textured = false, bool culled = true, - bool emissive = false, bool depthBias = false) { - _flags = (textured ? IS_TEXTURED : 0) | (culled ? IS_CULLED : 0) | - (emissive ? IS_EMISSIVE : 0) | (depthBias ? HAS_DEPTH_BIAS : 0); - } - - SimpleProgramKey(int bitmask) : _flags(bitmask) {} -}; - -inline uint qHash(const SimpleProgramKey& key, uint seed) { - return qHash(key.getRaw(), seed); -} - -inline bool operator==(const SimpleProgramKey& a, const SimpleProgramKey& b) { - return a.getRaw() == b.getRaw(); -} - #endif // hifi_DeferredLightingEffect_h diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 5ae90e2124..141d4f917d 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -29,6 +29,10 @@ #include "model/TextureMap.h" +#include "simple_vert.h" +#include "simple_textured_frag.h" +#include "simple_textured_emisive_frag.h" + //#define WANT_DEBUG const int GeometryCache::UNKNOWN_ID = -1; @@ -1741,3 +1745,183 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { } } + + + + + + + + + + + + +gpu::PipelinePointer GeometryCache::getPipeline(SimpleProgramKey config) { + static std::once_flag once; + std::call_once(once, [&]() { + auto VS = gpu::Shader::createVertex(std::string(simple_vert)); + auto PS = gpu::Shader::createPixel(std::string(simple_textured_frag)); + auto PSEmissive = gpu::Shader::createPixel(std::string(simple_textured_emisive_frag)); + + _simpleShader = gpu::Shader::createProgram(VS, PS); + _emissiveShader = gpu::Shader::createProgram(VS, PSEmissive); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), render::ShapePipeline::Slot::NORMAL_FITTING_MAP)); + gpu::Shader::makeProgram(*_simpleShader, slotBindings); + gpu::Shader::makeProgram(*_emissiveShader, slotBindings); + }); + + + auto it = _simplePrograms.find(config); + if (it != _simplePrograms.end()) { + return it.value(); + } + + auto state = std::make_shared(); + if (config.isCulled()) { + state->setCullMode(gpu::State::CULL_BACK); + } else { + state->setCullMode(gpu::State::CULL_NONE); + } + state->setDepthTest(true, true, gpu::LESS_EQUAL); + if (config.hasDepthBias()) { + state->setDepthBias(1.0f); + state->setDepthBiasSlopeScale(1.0f); + } + state->setBlendFunction(false, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader; + gpu::PipelinePointer pipeline = gpu::Pipeline::create(program, state); + _simplePrograms.insert(config, pipeline); + return pipeline; +} + +gpu::PipelinePointer GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, + bool emissive, bool depthBias) { + SimpleProgramKey config{textured, culled, emissive, depthBias}; + gpu::PipelinePointer pipeline = getPipeline(config); + batch.setPipeline(pipeline); + + gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader; + + if (!config.isTextured()) { + // If it is not textured, bind white texture and keep using textured pipeline + batch.setResourceTexture(0, DependencyManager::get()->getWhiteTexture()); + } + + batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP, + DependencyManager::get()->getNormalFittingTexture()); + return pipeline; +} + +uint32_t toCompactColor(const glm::vec4& color) { + uint32_t compactColor = ((int(color.x * 255.0f) & 0xFF)) | + ((int(color.y * 255.0f) & 0xFF) << 8) | + ((int(color.z * 255.0f) & 0xFF) << 16) | + ((int(color.w * 255.0f) & 0xFF) << 24); + return compactColor; +} + +static const size_t INSTANCE_TRANSFORM_BUFFER = 0; +static const size_t INSTANCE_COLOR_BUFFER = 1; + +template +void renderInstances(const std::string& name, gpu::Batch& batch, const Transform& transform, const glm::vec4& color, F f) { + { + gpu::BufferPointer instanceTransformBuffer = batch.getNamedBuffer(name, INSTANCE_TRANSFORM_BUFFER); + glm::mat4 glmTransform; + instanceTransformBuffer->append(transform.getMatrix(glmTransform)); + + gpu::BufferPointer instanceColorBuffer = batch.getNamedBuffer(name, INSTANCE_COLOR_BUFFER); + auto compactColor = toCompactColor(color); + instanceColorBuffer->append(compactColor); + } + + auto that = DependencyManager::get(); + batch.setupNamedCalls(name, [=](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + auto pipeline = that->bindSimpleProgram(batch); + auto location = pipeline->getProgram()->getUniforms().findLocation("Instanced"); + + batch._glUniform1i(location, 1); + f(batch, data); + batch._glUniform1i(location, 0); + }); +} + +void GeometryCache::renderSolidSphereInstance(gpu::Batch& batch, const Transform& transform, const glm::vec4& color) { + static const std::string INSTANCE_NAME = __FUNCTION__; + renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + DependencyManager::get()->renderShapeInstances(batch, GeometryCache::Sphere, data._count, + data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + }); +} + +void GeometryCache::renderWireSphereInstance(gpu::Batch& batch, const Transform& transform, const glm::vec4& color) { + static const std::string INSTANCE_NAME = __FUNCTION__; + renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + DependencyManager::get()->renderWireShapeInstances(batch, GeometryCache::Sphere, data._count, + data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + }); +} + +// Enable this in a debug build to cause 'box' entities to iterate through all the +// available shape types, both solid and wireframes +//#define DEBUG_SHAPES + +void GeometryCache::renderSolidCubeInstance(gpu::Batch& batch, const Transform& transform, const glm::vec4& color) { + static const std::string INSTANCE_NAME = __FUNCTION__; + +#ifdef DEBUG_SHAPES + static auto startTime = usecTimestampNow(); + renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + + auto usecs = usecTimestampNow(); + usecs -= startTime; + auto msecs = usecs / USECS_PER_MSEC; + float seconds = msecs; + seconds /= MSECS_PER_SECOND; + float fractionalSeconds = seconds - floor(seconds); + int shapeIndex = (int)seconds; + + // Every second we flip to the next shape. + static const int SHAPE_COUNT = 5; + GeometryCache::Shape shapes[SHAPE_COUNT] = { + GeometryCache::Cube, + GeometryCache::Tetrahedron, + GeometryCache::Sphere, + GeometryCache::Icosahedron, + GeometryCache::Line, + }; + + shapeIndex %= SHAPE_COUNT; + GeometryCache::Shape shape = shapes[shapeIndex]; + + // For the first half second for a given shape, show the wireframe, for the second half, show the solid. + if (fractionalSeconds > 0.5f) { + DependencyManager::get()->renderShapeInstances(batch, shape, data._count, + data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + } else { + DependencyManager::get()->renderWireShapeInstances(batch, shape, data._count, + data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + } + }); +#else + renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + DependencyManager::get()->renderCubeInstances(batch, data._count, + data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + }); +#endif +} + +void GeometryCache::renderWireCubeInstance(gpu::Batch& batch, const Transform& transform, const glm::vec4& color) { + static const std::string INSTANCE_NAME = __FUNCTION__; + renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + DependencyManager::get()->renderWireCubeInstances(batch, data._count, + data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + }); +} + diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index c408115011..4c16680622 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -16,7 +16,6 @@ #include - #include #include @@ -25,10 +24,13 @@ #include #include +#include #include #include +class SimpleProgramKey; + typedef glm::vec3 Vec3Key; typedef QPair Vec2Pair; @@ -146,6 +148,32 @@ public: int allocateID() { return _nextID++; } static const int UNKNOWN_ID; + + + /// Sets up the state necessary to render static untextured geometry with the simple program. + gpu::PipelinePointer bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true, + bool emissive = false, bool depthBias = false); + + void renderSolidSphereInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color); + void renderSolidSphereInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec3& color) { + renderSolidSphereInstance(batch, xfm, glm::vec4(color, 1.0)); + } + + void renderWireSphereInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color); + void renderWireSphereInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec3& color) { + renderWireSphereInstance(batch, xfm, glm::vec4(color, 1.0)); + } + + void renderSolidCubeInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color); + void renderSolidCubeInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec3& color) { + renderSolidCubeInstance(batch, xfm, glm::vec4(color, 1.0)); + } + + void renderWireCubeInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color); + void renderWireCubeInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec3& color) { + renderWireCubeInstance(batch, xfm, glm::vec4(color, 1.0)); + } + void renderShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& transformBuffer, gpu::BufferPointer& colorBuffer); void renderWireShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& transformBuffer, gpu::BufferPointer& colorBuffer); @@ -335,6 +363,75 @@ private: QHash _gridColors; QHash > _networkGeometry; + + + + + + + + + + + + + + + + gpu::PipelinePointer getPipeline(SimpleProgramKey config); + + gpu::ShaderPointer _simpleShader; + gpu::ShaderPointer _emissiveShader; + QHash _simplePrograms; }; +class SimpleProgramKey { +public: + enum FlagBit { + IS_TEXTURED_FLAG = 0, + IS_CULLED_FLAG, + IS_EMISSIVE_FLAG, + HAS_DEPTH_BIAS_FLAG, + + NUM_FLAGS, + }; + + enum Flag { + IS_TEXTURED = (1 << IS_TEXTURED_FLAG), + IS_CULLED = (1 << IS_CULLED_FLAG), + IS_EMISSIVE = (1 << IS_EMISSIVE_FLAG), + HAS_DEPTH_BIAS = (1 << HAS_DEPTH_BIAS_FLAG), + }; + typedef unsigned short Flags; + + bool isFlag(short flagNum) const { return bool((_flags & flagNum) != 0); } + + bool isTextured() const { return isFlag(IS_TEXTURED); } + bool isCulled() const { return isFlag(IS_CULLED); } + bool isEmissive() const { return isFlag(IS_EMISSIVE); } + bool hasDepthBias() const { return isFlag(HAS_DEPTH_BIAS); } + + Flags _flags = 0; + short _spare = 0; + + int getRaw() const { return *reinterpret_cast(this); } + + + SimpleProgramKey(bool textured = false, bool culled = true, + bool emissive = false, bool depthBias = false) { + _flags = (textured ? IS_TEXTURED : 0) | (culled ? IS_CULLED : 0) | + (emissive ? IS_EMISSIVE : 0) | (depthBias ? HAS_DEPTH_BIAS : 0); + } + + SimpleProgramKey(int bitmask) : _flags(bitmask) {} +}; + +inline uint qHash(const SimpleProgramKey& key, uint seed) { + return qHash(key.getRaw(), seed); +} + +inline bool operator==(const SimpleProgramKey& a, const SimpleProgramKey& b) { + return a.getRaw() == b.getRaw(); +} + #endif // hifi_GeometryCache_h diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 492021c1a9..3fe639b47f 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -499,7 +499,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) const { transform.setTranslation(partBounds.calcCenter()); transform.setScale(partBounds.getDimensions()); batch.setModelTransform(transform); - DependencyManager::get()->renderWireCube(batch, 1.0f, cubeColor); + DependencyManager::get()->renderWireCube(batch, 1.0f, cubeColor); } #endif //def DEBUG_BOUNDING_PARTS diff --git a/libraries/render-utils/src/TextRenderer3D.cpp b/libraries/render-utils/src/TextRenderer3D.cpp index c3056be00b..6d10ed7069 100644 --- a/libraries/render-utils/src/TextRenderer3D.cpp +++ b/libraries/render-utils/src/TextRenderer3D.cpp @@ -29,7 +29,6 @@ #include "sdf_text3D_frag.h" #include "GeometryCache.h" -#include "DeferredLightingEffect.h" const float TextRenderer3D::DEFAULT_POINT_SIZE = 12; From 205c14eb433b567f4446a2f553b639170d5a71d1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 8 Jan 2016 18:04:02 -0800 Subject: [PATCH 123/215] Remove unused headers --- interface/src/ui/overlays/ImageOverlay.cpp | 1 - interface/src/ui/overlays/Overlay.cpp | 4 +--- .../model-networking/src/model-networking/ModelCache.cpp | 2 -- libraries/model-networking/src/model-networking/ModelCache.h | 3 --- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 1 - libraries/render-utils/src/AntialiasingEffect.cpp | 1 - libraries/render-utils/src/DeferredLightingEffect.cpp | 1 - libraries/render-utils/src/GeometryCache.cpp | 5 ++--- tests/gpu-test/src/main.cpp | 1 - 9 files changed, 3 insertions(+), 16 deletions(-) diff --git a/interface/src/ui/overlays/ImageOverlay.cpp b/interface/src/ui/overlays/ImageOverlay.cpp index ed88f50981..8df62b9675 100644 --- a/interface/src/ui/overlays/ImageOverlay.cpp +++ b/interface/src/ui/overlays/ImageOverlay.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp index 0c909a1bfb..0497a20500 100644 --- a/interface/src/ui/overlays/Overlay.cpp +++ b/interface/src/ui/overlays/Overlay.cpp @@ -222,10 +222,8 @@ float Overlay::updatePulse() { } bool Overlay::addToScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges) { - auto overlayPayload = new Overlay::Payload(overlay); - auto overlayPayloadPointer = Overlay::PayloadPointer(overlayPayload); _renderItemID = scene->allocateID(); - pendingChanges.resetItem(_renderItemID, overlayPayloadPointer); + pendingChanges.resetItem(_renderItemID, std::make_shared(overlay)); return true; } diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 4fd47affc2..1d436851d7 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -22,8 +22,6 @@ #include "TextureCache.h" #include "ModelNetworkingLogging.h" -#include "gpu/StandardShaderLib.h" - #include "model/TextureMap.h" //#define WANT_DEBUG diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index cd75794e2b..b2d81c5900 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -48,9 +48,6 @@ public: /// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested QSharedPointer getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false); - /// Set a batch to the simple pipeline, returning the previous pipeline - void useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend = false); - private: ModelCache(); virtual ~ModelCache(); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 39097e485b..0dd2e080ec 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -16,7 +16,6 @@ #include #include -#include "gpu/StandardShaderLib.h" #include "AmbientOcclusionEffect.h" #include "TextureCache.h" #include "FramebufferCache.h" diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index 81ca5dcdaf..52e0836029 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -16,7 +16,6 @@ #include #include -#include "gpu/StandardShaderLib.h" #include "AntialiasingEffect.h" #include "TextureCache.h" #include "FramebufferCache.h" diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index d5dd53c252..7c8aa393d4 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -17,7 +17,6 @@ #include #include -#include #include "AbstractViewStateInterface.h" #include "GeometryCache.h" diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 141d4f917d..87635eb9b6 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1841,9 +1841,8 @@ void renderInstances(const std::string& name, gpu::Batch& batch, const Transform instanceColorBuffer->append(compactColor); } - auto that = DependencyManager::get(); - batch.setupNamedCalls(name, [=](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - auto pipeline = that->bindSimpleProgram(batch); + batch.setupNamedCalls(name, [f](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + auto pipeline = DependencyManager::get()->bindSimpleProgram(batch); auto location = pipeline->getProgram()->getUniforms().findLocation("Instanced"); batch._glUniform1i(location, 1); diff --git a/tests/gpu-test/src/main.cpp b/tests/gpu-test/src/main.cpp index e185266408..f5ff7de035 100644 --- a/tests/gpu-test/src/main.cpp +++ b/tests/gpu-test/src/main.cpp @@ -30,7 +30,6 @@ #include #include #include -#include #include #include From c30569cd5529e22a7850cfb0758175d7262d3695 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 11 Jan 2016 13:26:47 -0800 Subject: [PATCH 124/215] Naming coding standard --- libraries/gpu/src/gpu/Batch.cpp | 14 ++++----- libraries/gpu/src/gpu/Batch.h | 11 ++++--- libraries/render-utils/src/GeometryCache.cpp | 30 ++++++++++++-------- tests/gpu-test/src/main.cpp | 2 +- 4 files changed, 31 insertions(+), 26 deletions(-) diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index f9c4131a1b..999e528a94 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -362,8 +362,8 @@ bool Batch::isSkyboxEnabled() const { void Batch::setupNamedCalls(const std::string& instanceName, size_t count, NamedBatchData::Function function) { NamedBatchData& instance = _namedData[instanceName]; - instance._count += count; - instance._function = function; + instance.count += count; + instance.function = function; } void Batch::setupNamedCalls(const std::string& instanceName, NamedBatchData::Function function) { @@ -372,13 +372,13 @@ void Batch::setupNamedCalls(const std::string& instanceName, NamedBatchData::Fun BufferPointer Batch::getNamedBuffer(const std::string& instanceName, uint8_t index) { NamedBatchData& instance = _namedData[instanceName]; - if (instance._buffers.size() <= index) { - instance._buffers.resize(index + 1); + if (instance.buffers.size() <= index) { + instance.buffers.resize(index + 1); } - if (!instance._buffers[index]) { - instance._buffers[index].reset(new Buffer()); + if (!instance.buffers[index]) { + instance.buffers[index].reset(new Buffer()); } - return instance._buffers[index]; + return instance.buffers[index]; } void Batch::preExecute() { diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 88d28f9d10..aa2fc1622c 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -49,14 +49,13 @@ public: using BufferPointers = std::vector; using Function = std::function; - std::once_flag _once; - BufferPointers _buffers; - size_t _count{ 0 }; - Function _function; + BufferPointers buffers; + size_t count { 0 }; + Function function; void process(Batch& batch) { - if (_function) { - _function(batch, *this); + if (function) { + function(batch, *this); } } }; diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 87635eb9b6..8c112229b1 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1854,16 +1854,18 @@ void renderInstances(const std::string& name, gpu::Batch& batch, const Transform void GeometryCache::renderSolidSphereInstance(gpu::Batch& batch, const Transform& transform, const glm::vec4& color) { static const std::string INSTANCE_NAME = __FUNCTION__; renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - DependencyManager::get()->renderShapeInstances(batch, GeometryCache::Sphere, data._count, - data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + DependencyManager::get()->renderShapeInstances(batch, GeometryCache::Sphere, data.count, + data.buffers[INSTANCE_TRANSFORM_BUFFER], + data.buffers[INSTANCE_COLOR_BUFFER]); }); } void GeometryCache::renderWireSphereInstance(gpu::Batch& batch, const Transform& transform, const glm::vec4& color) { static const std::string INSTANCE_NAME = __FUNCTION__; renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - DependencyManager::get()->renderWireShapeInstances(batch, GeometryCache::Sphere, data._count, - data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + DependencyManager::get()->renderWireShapeInstances(batch, GeometryCache::Sphere, data.count, + data.buffers[INSTANCE_TRANSFORM_BUFFER], + data.buffers[INSTANCE_COLOR_BUFFER]); }); } @@ -1901,17 +1903,20 @@ void GeometryCache::renderSolidCubeInstance(gpu::Batch& batch, const Transform& // For the first half second for a given shape, show the wireframe, for the second half, show the solid. if (fractionalSeconds > 0.5f) { - DependencyManager::get()->renderShapeInstances(batch, shape, data._count, - data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + DependencyManager::get()->renderShapeInstances(batch, shape, data.count, + data.buffers[INSTANCE_TRANSFORM_BUFFER], + data.buffers[INSTANCE_COLOR_BUFFER]); } else { - DependencyManager::get()->renderWireShapeInstances(batch, shape, data._count, - data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + DependencyManager::get()->renderWireShapeInstances(batch, shape, data.count, + data.buffers[INSTANCE_TRANSFORM_BUFFER], + data.buffers[INSTANCE_COLOR_BUFFER]); } }); #else renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - DependencyManager::get()->renderCubeInstances(batch, data._count, - data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + DependencyManager::get()->renderCubeInstances(batch, data.count, + data.buffers[INSTANCE_TRANSFORM_BUFFER], + data.buffers[INSTANCE_COLOR_BUFFER]); }); #endif } @@ -1919,8 +1924,9 @@ void GeometryCache::renderSolidCubeInstance(gpu::Batch& batch, const Transform& void GeometryCache::renderWireCubeInstance(gpu::Batch& batch, const Transform& transform, const glm::vec4& color) { static const std::string INSTANCE_NAME = __FUNCTION__; renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - DependencyManager::get()->renderWireCubeInstances(batch, data._count, - data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + DependencyManager::get()->renderWireCubeInstances(batch, data.count, + data.buffers[INSTANCE_TRANSFORM_BUFFER], + data.buffers[INSTANCE_COLOR_BUFFER]); }); } diff --git a/tests/gpu-test/src/main.cpp b/tests/gpu-test/src/main.cpp index f5ff7de035..de5aa877eb 100644 --- a/tests/gpu-test/src/main.cpp +++ b/tests/gpu-test/src/main.cpp @@ -246,7 +246,7 @@ public: batch.setModelTransform(Transform()); batch.setPipeline(_pipeline); batch._glUniform1i(_instanceLocation, 1); - geometryCache->renderWireShapeInstances(batch, GeometryCache::Line, data._count, transformBuffer, colorBuffer); + geometryCache->renderWireShapeInstances(batch, GeometryCache::Line, data.count, transformBuffer, colorBuffer); batch._glUniform1i(_instanceLocation, 0); }); } From 1789878be10c7f9dab20a636afb34081ee19a28e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 12 Jan 2016 11:31:46 -0800 Subject: [PATCH 125/215] Remove dead code --- libraries/render-utils/src/GeometryCache.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 8c112229b1..6c669d3d1d 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -40,17 +40,6 @@ const int GeometryCache::UNKNOWN_ID = -1; static const int VERTICES_PER_TRIANGLE = 3; -//static const uint FLOATS_PER_VERTEX = 3; -//static const uint TRIANGLES_PER_QUAD = 2; -//static const uint CUBE_FACES = 6; -//static const uint CUBE_VERTICES_PER_FACE = 4; -//static const uint CUBE_VERTICES = CUBE_FACES * CUBE_VERTICES_PER_FACE; -//static const uint CUBE_VERTEX_POINTS = CUBE_VERTICES * FLOATS_PER_VERTEX; -//static const uint CUBE_INDICES = CUBE_FACES * TRIANGLES_PER_QUAD * VERTICES_PER_TRIANGLE; -//static const uint SPHERE_LATITUDES = 24; -//static const uint SPHERE_MERIDIANS = SPHERE_LATITUDES * 2; -//static const uint SPHERE_INDICES = SPHERE_MERIDIANS * (SPHERE_LATITUDES - 1) * TRIANGLES_PER_QUAD * VERTICES_PER_TRIANGLE; - static const gpu::Element POSITION_ELEMENT{ gpu::VEC3, gpu::FLOAT, gpu::XYZ }; static const gpu::Element NORMAL_ELEMENT{ gpu::VEC3, gpu::FLOAT, gpu::XYZ }; static const gpu::Element COLOR_ELEMENT{ gpu::VEC4, gpu::NUINT8, gpu::RGBA }; From 741c22c0acc1d7937e28ed7247e49b6197e396ec Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 12 Jan 2016 15:25:11 -0800 Subject: [PATCH 126/215] Move SimpleProgramKey to cpp --- libraries/render-utils/src/GeometryCache.cpp | 47 ++++++++++++-- libraries/render-utils/src/GeometryCache.h | 64 +------------------- 2 files changed, 44 insertions(+), 67 deletions(-) diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 6c669d3d1d..35773e8748 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1736,15 +1736,54 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { +class SimpleProgramKey { +public: + enum FlagBit { + IS_TEXTURED_FLAG = 0, + IS_CULLED_FLAG, + IS_EMISSIVE_FLAG, + HAS_DEPTH_BIAS_FLAG, + + NUM_FLAGS, + }; + + enum Flag { + IS_TEXTURED = (1 << IS_TEXTURED_FLAG), + IS_CULLED = (1 << IS_CULLED_FLAG), + IS_EMISSIVE = (1 << IS_EMISSIVE_FLAG), + HAS_DEPTH_BIAS = (1 << HAS_DEPTH_BIAS_FLAG), + }; + typedef unsigned short Flags; + + bool isFlag(short flagNum) const { return bool((_flags & flagNum) != 0); } + + bool isTextured() const { return isFlag(IS_TEXTURED); } + bool isCulled() const { return isFlag(IS_CULLED); } + bool isEmissive() const { return isFlag(IS_EMISSIVE); } + bool hasDepthBias() const { return isFlag(HAS_DEPTH_BIAS); } + + Flags _flags = 0; + short _spare = 0; + + int getRaw() const { return *reinterpret_cast(this); } + SimpleProgramKey(bool textured = false, bool culled = true, + bool emissive = false, bool depthBias = false) { + _flags = (textured ? IS_TEXTURED : 0) | (culled ? IS_CULLED : 0) | + (emissive ? IS_EMISSIVE : 0) | (depthBias ? HAS_DEPTH_BIAS : 0); + } + SimpleProgramKey(int bitmask) : _flags(bitmask) {} +}; +inline uint qHash(const SimpleProgramKey& key, uint seed) { + return qHash(key.getRaw(), seed); +} - - - - +inline bool operator==(const SimpleProgramKey& a, const SimpleProgramKey& b) { + return a.getRaw() == b.getRaw(); +} gpu::PipelinePointer GeometryCache::getPipeline(SimpleProgramKey config) { static std::once_flag once; diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 4c16680622..90ba3be978 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -364,20 +364,7 @@ private: QHash > _networkGeometry; - - - - - - - - - - - - - - + gpu::PipelinePointer getPipeline(SimpleProgramKey config); gpu::ShaderPointer _simpleShader; @@ -385,53 +372,4 @@ private: QHash _simplePrograms; }; -class SimpleProgramKey { -public: - enum FlagBit { - IS_TEXTURED_FLAG = 0, - IS_CULLED_FLAG, - IS_EMISSIVE_FLAG, - HAS_DEPTH_BIAS_FLAG, - - NUM_FLAGS, - }; - - enum Flag { - IS_TEXTURED = (1 << IS_TEXTURED_FLAG), - IS_CULLED = (1 << IS_CULLED_FLAG), - IS_EMISSIVE = (1 << IS_EMISSIVE_FLAG), - HAS_DEPTH_BIAS = (1 << HAS_DEPTH_BIAS_FLAG), - }; - typedef unsigned short Flags; - - bool isFlag(short flagNum) const { return bool((_flags & flagNum) != 0); } - - bool isTextured() const { return isFlag(IS_TEXTURED); } - bool isCulled() const { return isFlag(IS_CULLED); } - bool isEmissive() const { return isFlag(IS_EMISSIVE); } - bool hasDepthBias() const { return isFlag(HAS_DEPTH_BIAS); } - - Flags _flags = 0; - short _spare = 0; - - int getRaw() const { return *reinterpret_cast(this); } - - - SimpleProgramKey(bool textured = false, bool culled = true, - bool emissive = false, bool depthBias = false) { - _flags = (textured ? IS_TEXTURED : 0) | (culled ? IS_CULLED : 0) | - (emissive ? IS_EMISSIVE : 0) | (depthBias ? HAS_DEPTH_BIAS : 0); - } - - SimpleProgramKey(int bitmask) : _flags(bitmask) {} -}; - -inline uint qHash(const SimpleProgramKey& key, uint seed) { - return qHash(key.getRaw(), seed); -} - -inline bool operator==(const SimpleProgramKey& a, const SimpleProgramKey& b) { - return a.getRaw() == b.getRaw(); -} - #endif // hifi_GeometryCache_h From 8a77e2ee955501d5ad19da82f8335815bb95ca0e Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 13 Jan 2016 13:31:37 -0800 Subject: [PATCH 127/215] Split physics perf timing into three parts: updateStates, stepSimulation, and harvestChanges. --- interface/src/Application.cpp | 103 ++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 48 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4c4786c6a2..a278bc0047 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3102,63 +3102,70 @@ void Application::update(float deltaTime) { if (_physicsEnabled) { PerformanceTimer perfTimer("physics"); - - static VectorOfMotionStates motionStates; - _entitySimulation.getObjectsToRemoveFromPhysics(motionStates); - _physicsEngine->removeObjects(motionStates); - - getEntities()->getTree()->withWriteLock([&] { - _entitySimulation.getObjectsToAddToPhysics(motionStates); - _physicsEngine->addObjects(motionStates); - - }); - getEntities()->getTree()->withWriteLock([&] { - _entitySimulation.getObjectsToChange(motionStates); - VectorOfMotionStates stillNeedChange = _physicsEngine->changeObjects(motionStates); - _entitySimulation.setObjectsToChange(stillNeedChange); - }); - - _entitySimulation.applyActionChanges(); - AvatarManager* avatarManager = DependencyManager::get().data(); - avatarManager->getObjectsToRemoveFromPhysics(motionStates); - _physicsEngine->removeObjects(motionStates); - avatarManager->getObjectsToAddToPhysics(motionStates); - _physicsEngine->addObjects(motionStates); - avatarManager->getObjectsToChange(motionStates); - _physicsEngine->changeObjects(motionStates); - myAvatar->prepareForPhysicsSimulation(); - _physicsEngine->forEachAction([&](EntityActionPointer action) { - action->prepareForPhysicsSimulation(); - }); + { + PerformanceTimer perfTimer("updateStates)"); + static VectorOfMotionStates motionStates; + _entitySimulation.getObjectsToRemoveFromPhysics(motionStates); + _physicsEngine->removeObjects(motionStates); - getEntities()->getTree()->withWriteLock([&] { - _physicsEngine->stepSimulation(); - }); - - if (_physicsEngine->hasOutgoingChanges()) { getEntities()->getTree()->withWriteLock([&] { - _entitySimulation.handleOutgoingChanges(_physicsEngine->getOutgoingChanges(), _physicsEngine->getSessionID()); - avatarManager->handleOutgoingChanges(_physicsEngine->getOutgoingChanges()); + _entitySimulation.getObjectsToAddToPhysics(motionStates); + _physicsEngine->addObjects(motionStates); + + }); + getEntities()->getTree()->withWriteLock([&] { + _entitySimulation.getObjectsToChange(motionStates); + VectorOfMotionStates stillNeedChange = _physicsEngine->changeObjects(motionStates); + _entitySimulation.setObjectsToChange(stillNeedChange); }); - auto collisionEvents = _physicsEngine->getCollisionEvents(); - avatarManager->handleCollisionEvents(collisionEvents); + _entitySimulation.applyActionChanges(); - _physicsEngine->dumpStatsIfNecessary(); + avatarManager->getObjectsToRemoveFromPhysics(motionStates); + _physicsEngine->removeObjects(motionStates); + avatarManager->getObjectsToAddToPhysics(motionStates); + _physicsEngine->addObjects(motionStates); + avatarManager->getObjectsToChange(motionStates); + _physicsEngine->changeObjects(motionStates); - if (!_aboutToQuit) { - PerformanceTimer perfTimer("entities"); - // Collision events (and their scripts) must not be handled when we're locked, above. (That would risk - // deadlock.) - _entitySimulation.handleCollisionEvents(collisionEvents); - // NOTE: the getEntities()->update() call below will wait for lock - // and will simulate entity motion (the EntityTree has been given an EntitySimulation). - getEntities()->update(); // update the models... + myAvatar->prepareForPhysicsSimulation(); + _physicsEngine->forEachAction([&](EntityActionPointer action) { + action->prepareForPhysicsSimulation(); + }); + } + { + PerformanceTimer perfTimer("stepSimulation"); + getEntities()->getTree()->withWriteLock([&] { + _physicsEngine->stepSimulation(); + }); + } + { + PerformanceTimer perfTimer("havestChanges"); + if (_physicsEngine->hasOutgoingChanges()) { + getEntities()->getTree()->withWriteLock([&] { + _entitySimulation.handleOutgoingChanges(_physicsEngine->getOutgoingChanges(), _physicsEngine->getSessionID()); + avatarManager->handleOutgoingChanges(_physicsEngine->getOutgoingChanges()); + }); + + auto collisionEvents = _physicsEngine->getCollisionEvents(); + avatarManager->handleCollisionEvents(collisionEvents); + + _physicsEngine->dumpStatsIfNecessary(); + + if (!_aboutToQuit) { + PerformanceTimer perfTimer("entities"); + // Collision events (and their scripts) must not be handled when we're locked, above. (That would risk + // deadlock.) + _entitySimulation.handleCollisionEvents(collisionEvents); + // NOTE: the getEntities()->update() call below will wait for lock + // and will simulate entity motion (the EntityTree has been given an EntitySimulation). + getEntities()->update(); // update the models... + } + + myAvatar->harvestResultsFromPhysicsSimulation(deltaTime); } - - myAvatar->harvestResultsFromPhysicsSimulation(deltaTime); } } From 8da027c56f383abfb140d90437b0de09ad7195ef Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 13 Jan 2016 12:15:57 -0800 Subject: [PATCH 128/215] Encapsulate GPUObject in a safer way --- libraries/gpu/src/gpu/Context.h | 66 +++-------------------------- libraries/gpu/src/gpu/Format.h | 19 ++++++++- libraries/gpu/src/gpu/Framebuffer.h | 8 +--- libraries/gpu/src/gpu/Pipeline.h | 8 +--- libraries/gpu/src/gpu/Query.h | 10 +---- libraries/gpu/src/gpu/Resource.cpp | 13 ++---- libraries/gpu/src/gpu/Resource.h | 9 +--- libraries/gpu/src/gpu/Shader.h | 8 +--- libraries/gpu/src/gpu/State.h | 8 +--- libraries/gpu/src/gpu/Texture.h | 9 +--- 10 files changed, 34 insertions(+), 124 deletions(-) diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index ad21d71427..260aff72d7 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -97,68 +97,16 @@ public: TransformCamera getEyeCamera(int eye, const StereoState& stereo) const; }; - template< typename T > - static void setGPUObject(const Buffer& buffer, T* object) { - buffer.setGPUObject(object); + + template + static void setGPUObject(const GPUObjectWrapper& wrapper, T* object) { + wrapper.setGPUObject(object); } - template< typename T > - static T* getGPUObject(const Buffer& buffer) { - return reinterpret_cast(buffer.getGPUObject()); + template + static T* getGPUObject(const GPUObjectWrapper& wrapper) { + return reinterpret_cast(wrapper.getGPUObject()); } - template< typename T > - static void setGPUObject(const Texture& texture, T* object) { - texture.setGPUObject(object); - } - template< typename T > - static T* getGPUObject(const Texture& texture) { - return reinterpret_cast(texture.getGPUObject()); - } - - template< typename T > - static void setGPUObject(const Shader& shader, T* object) { - shader.setGPUObject(object); - } - template< typename T > - static T* getGPUObject(const Shader& shader) { - return reinterpret_cast(shader.getGPUObject()); - } - - template< typename T > - static void setGPUObject(const Pipeline& pipeline, T* object) { - pipeline.setGPUObject(object); - } - template< typename T > - static T* getGPUObject(const Pipeline& pipeline) { - return reinterpret_cast(pipeline.getGPUObject()); - } - - template< typename T > - static void setGPUObject(const State& state, T* object) { - state.setGPUObject(object); - } - template< typename T > - static T* getGPUObject(const State& state) { - return reinterpret_cast(state.getGPUObject()); - } - - template< typename T > - static void setGPUObject(const Framebuffer& framebuffer, T* object) { - framebuffer.setGPUObject(object); - } - template< typename T > - static T* getGPUObject(const Framebuffer& framebuffer) { - return reinterpret_cast(framebuffer.getGPUObject()); - } - - template< typename T > - static void setGPUObject(const Query& query, T* object) { - query.setGPUObject(object); - } - template< typename T > - static T* getGPUObject(const Query& query) { - return reinterpret_cast(query.getGPUObject()); - } protected: StereoState _stereo; diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index 41a95e2578..1ae579d9f5 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -16,10 +16,25 @@ namespace gpu { +class Backend; + class GPUObject { public: - GPUObject() {} - virtual ~GPUObject() {} + virtual ~GPUObject() = default; +}; + +class GPUObjectWrapper { +public: + virtual ~GPUObjectWrapper() { delete _gpuObject; } + +private: + // This shouldn't be used by anything else than the Backend class with the proper casting. + // TODO: Consider using std::unique_ptr to get rid of dtor and ensure correct destruction of GPU objects + mutable GPUObject* _gpuObject { nullptr }; + void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } + GPUObject* getGPUObject() const { return _gpuObject; } + + friend class Backend; }; typedef int Stamp; diff --git a/libraries/gpu/src/gpu/Framebuffer.h b/libraries/gpu/src/gpu/Framebuffer.h index 807047a56e..5fbc2e1487 100755 --- a/libraries/gpu/src/gpu/Framebuffer.h +++ b/libraries/gpu/src/gpu/Framebuffer.h @@ -64,7 +64,7 @@ protected: typedef std::shared_ptr SwapchainPointer; -class Framebuffer { +class Framebuffer : public GPUObjectWrapper { public: enum BufferMask { BUFFER_COLOR0 = 1, @@ -153,12 +153,6 @@ protected: // Non exposed Framebuffer(const Framebuffer& framebuffer) = delete; Framebuffer() {} - - // This shouldn't be used by anything else than the Backend class with the proper casting. - mutable GPUObject* _gpuObject = NULL; - void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } - GPUObject* getGPUObject() const { return _gpuObject; } - friend class Backend; }; typedef std::shared_ptr FramebufferPointer; diff --git a/libraries/gpu/src/gpu/Pipeline.h b/libraries/gpu/src/gpu/Pipeline.h index adc65a0c66..f062873869 100755 --- a/libraries/gpu/src/gpu/Pipeline.h +++ b/libraries/gpu/src/gpu/Pipeline.h @@ -20,7 +20,7 @@ namespace gpu { -class Pipeline { +class Pipeline : public GPUObjectWrapper { public: using Pointer = std::shared_ptr< Pipeline >; @@ -38,12 +38,6 @@ protected: Pipeline(); Pipeline(const Pipeline& pipeline); // deep copy of the sysmem shader Pipeline& operator=(const Pipeline& pipeline); // deep copy of the sysmem texture - - // This shouldn't be used by anything else than the Backend class with the proper casting. - mutable GPUObject* _gpuObject = nullptr; - void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } - GPUObject* getGPUObject() const { return _gpuObject; } - friend class Backend; }; typedef Pipeline::Pointer PipelinePointer; diff --git a/libraries/gpu/src/gpu/Query.h b/libraries/gpu/src/gpu/Query.h index d9c3185d9e..82f17c71ae 100644 --- a/libraries/gpu/src/gpu/Query.h +++ b/libraries/gpu/src/gpu/Query.h @@ -19,7 +19,7 @@ namespace gpu { - class Query { + class Query : public GPUObjectWrapper { public: Query(); ~Query(); @@ -27,14 +27,6 @@ namespace gpu { uint32 queryResult; double getElapsedTime(); - - protected: - - // This shouldn't be used by anything else than the Backend class with the proper casting. - mutable GPUObject* _gpuObject = NULL; - void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } - GPUObject* getGPUObject() const { return _gpuObject; } - friend class Backend; }; typedef std::shared_ptr QueryPointer; diff --git a/libraries/gpu/src/gpu/Resource.cpp b/libraries/gpu/src/gpu/Resource.cpp index c162b38b93..1788f6ece5 100644 --- a/libraries/gpu/src/gpu/Resource.cpp +++ b/libraries/gpu/src/gpu/Resource.cpp @@ -170,20 +170,17 @@ Resource::Size Resource::Sysmem::append(Size size, const Byte* bytes) { Buffer::Buffer() : Resource(), - _sysmem(new Sysmem()), - _gpuObject(NULL) { + _sysmem(new Sysmem()) { } Buffer::Buffer(Size size, const Byte* bytes) : Resource(), - _sysmem(new Sysmem(size, bytes)), - _gpuObject(NULL) { + _sysmem(new Sysmem(size, bytes)) { } Buffer::Buffer(const Buffer& buf) : Resource(), - _sysmem(new Sysmem(buf.getSysmem())), - _gpuObject(NULL) { + _sysmem(new Sysmem(buf.getSysmem())) { } Buffer& Buffer::operator=(const Buffer& buf) { @@ -196,10 +193,6 @@ Buffer::~Buffer() { delete _sysmem; _sysmem = NULL; } - if (_gpuObject) { - delete _gpuObject; - _gpuObject = NULL; - } } Buffer::Size Buffer::resize(Size size) { diff --git a/libraries/gpu/src/gpu/Resource.h b/libraries/gpu/src/gpu/Resource.h index 794ee680f4..817deaae86 100644 --- a/libraries/gpu/src/gpu/Resource.h +++ b/libraries/gpu/src/gpu/Resource.h @@ -108,7 +108,7 @@ protected: }; -class Buffer : public Resource { +class Buffer : public Resource, public GPUObjectWrapper { public: Buffer(); @@ -156,13 +156,6 @@ public: protected: Sysmem* _sysmem = NULL; - - - // This shouldn't be used by anything else than the Backend class with the proper casting. - mutable GPUObject* _gpuObject = NULL; - void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } - GPUObject* getGPUObject() const { return _gpuObject; } - friend class Backend; }; typedef std::shared_ptr BufferPointer; diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h index b737a42e12..908e57e06b 100755 --- a/libraries/gpu/src/gpu/Shader.h +++ b/libraries/gpu/src/gpu/Shader.h @@ -20,7 +20,7 @@ namespace gpu { -class Shader { +class Shader : public GPUObjectWrapper { public: typedef std::shared_ptr< Shader > Pointer; @@ -178,12 +178,6 @@ protected: // The type of the shader, the master key Type _type; - - // This shouldn't be used by anything else than the Backend class with the proper casting. - mutable GPUObject* _gpuObject = NULL; - void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } - GPUObject* getGPUObject() const { return _gpuObject; } - friend class Backend; }; typedef Shader::Pointer ShaderPointer; diff --git a/libraries/gpu/src/gpu/State.h b/libraries/gpu/src/gpu/State.h index 7740506bce..e468b01171 100755 --- a/libraries/gpu/src/gpu/State.h +++ b/libraries/gpu/src/gpu/State.h @@ -36,7 +36,7 @@ namespace gpu { class GPUObject; -class State { +class State : public GPUObjectWrapper { public: State(); virtual ~State(); @@ -392,12 +392,6 @@ protected: Data _values; Signature _signature{0}; Stamp _stamp{0}; - - // This shouldn't be used by anything else than the Backend class with the proper casting. - mutable GPUObject* _gpuObject = nullptr; - void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } - GPUObject* getGPUObject() const { return _gpuObject; } - friend class Backend; }; typedef std::shared_ptr< State > StatePointer; diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 6e8eb10380..e68b65a15e 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -136,7 +136,7 @@ protected: Desc _desc; }; -class Texture : public Resource { +class Texture : public Resource, public GPUObjectWrapper { public: class Pixels { @@ -386,13 +386,6 @@ protected: static Texture* create(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, const Sampler& sampler); Size resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices); - - // This shouldn't be used by anything else than the Backend class with the proper casting. - mutable GPUObject* _gpuObject = NULL; - void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } - GPUObject* getGPUObject() const { return _gpuObject; } - - friend class Backend; }; typedef std::shared_ptr TexturePointer; From 504939f1937fae3f2d1212e7dc6f2e7af45adab7 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 13 Jan 2016 14:07:48 -0800 Subject: [PATCH 129/215] Use a unique_ptr to track gpu objects --- libraries/gpu/src/gpu/Format.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index 1ae579d9f5..61fb1e847e 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -11,8 +11,10 @@ #ifndef hifi_gpu_Format_h #define hifi_gpu_Format_h -#include #include +#include + +#include namespace gpu { @@ -25,14 +27,15 @@ public: class GPUObjectWrapper { public: - virtual ~GPUObjectWrapper() { delete _gpuObject; } + virtual ~GPUObjectWrapper() = default; private: + using GPUObjectPointer = std::unique_ptr; + // This shouldn't be used by anything else than the Backend class with the proper casting. - // TODO: Consider using std::unique_ptr to get rid of dtor and ensure correct destruction of GPU objects - mutable GPUObject* _gpuObject { nullptr }; - void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } - GPUObject* getGPUObject() const { return _gpuObject; } + mutable GPUObjectPointer _gpuObject; + void setGPUObject(GPUObject* gpuObject) const { _gpuObject.reset(gpuObject); } + GPUObject* getGPUObject() const { return _gpuObject.get(); } friend class Backend; }; From f02cc8fd46935f6db8d9055de77933dc8ce17a51 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 13 Jan 2016 14:43:52 -0800 Subject: [PATCH 130/215] Tweaked bow position --- unpublishedScripts/hiddenEntityReset.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 19bf689357..f96443f059 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -113,7 +113,6 @@ z: 504.5 }); - createCombinedArmChair({ x: 549.29, y: 494.9, @@ -365,16 +364,16 @@ invertSolidWhileHeld: true, spatialKey: { rightRelativePosition: { - x: -0.03, - y: 0, + x: 0.03, + y: 0.08, z: 0.11 }, leftRelativePosition: { - x: 0.03, - y: 0, + x: -0.03, + y: 0.08, z: 0.11 }, - relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, 90) + relativeRotation: Quat.fromPitchYawRollDegrees(180, 90, 90) } } }) From cda6d6e4eaf43c846a5adb4b3c765d70283011d9 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 13 Jan 2016 14:44:42 -0800 Subject: [PATCH 131/215] bow tweaks --- unpublishedScripts/masterReset.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index f0c5ad6075..81c2db9e05 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -349,16 +349,16 @@ MasterReset = function() { invertSolidWhileHeld: true, spatialKey: { rightRelativePosition: { - x: -0.03, - y: 0, + x: 0.03, + y: 0.08, z: 0.11 }, leftRelativePosition: { - x: 0.03, - y: 0, + x: -0.03, + y: 0.08, z: 0.11 }, - relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, 90) + relativeRotation: Quat.fromPitchYawRollDegrees(180, 90, 90) } } }) From ef5af45acdc6a5902232f4e1d79d1f12aa021f5c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 13 Jan 2016 14:55:49 -0800 Subject: [PATCH 132/215] Replce GPUObjectWrapper by public const member --- libraries/gpu/src/gpu/Context.h | 12 ++++++------ libraries/gpu/src/gpu/Format.h | 9 +++------ libraries/gpu/src/gpu/Framebuffer.h | 4 +++- libraries/gpu/src/gpu/Pipeline.h | 4 +++- libraries/gpu/src/gpu/Query.h | 4 +++- libraries/gpu/src/gpu/Resource.h | 4 +++- libraries/gpu/src/gpu/Shader.h | 4 +++- libraries/gpu/src/gpu/State.h | 4 +++- libraries/gpu/src/gpu/Texture.h | 4 +++- 9 files changed, 30 insertions(+), 19 deletions(-) diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 260aff72d7..ed2afe91eb 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -98,13 +98,13 @@ public: }; - template - static void setGPUObject(const GPUObjectWrapper& wrapper, T* object) { - wrapper.setGPUObject(object); + template + static void setGPUObject(const U& object, T* gpuObject) { + object.gpuObject.setGPUObject(gpuObject); } - template - static T* getGPUObject(const GPUObjectWrapper& wrapper) { - return reinterpret_cast(wrapper.getGPUObject()); + template + static T* getGPUObject(const U& object) { + return reinterpret_cast(object.gpuObject.getGPUObject()); } diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index 61fb1e847e..54d40c3e12 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -25,15 +25,12 @@ public: virtual ~GPUObject() = default; }; -class GPUObjectWrapper { -public: - virtual ~GPUObjectWrapper() = default; - +class GPUObjectPointer { private: - using GPUObjectPointer = std::unique_ptr; + using GPUObjectUniquePointer = std::unique_ptr; // This shouldn't be used by anything else than the Backend class with the proper casting. - mutable GPUObjectPointer _gpuObject; + mutable GPUObjectUniquePointer _gpuObject; void setGPUObject(GPUObject* gpuObject) const { _gpuObject.reset(gpuObject); } GPUObject* getGPUObject() const { return _gpuObject.get(); } diff --git a/libraries/gpu/src/gpu/Framebuffer.h b/libraries/gpu/src/gpu/Framebuffer.h index 5fbc2e1487..e986e4a481 100755 --- a/libraries/gpu/src/gpu/Framebuffer.h +++ b/libraries/gpu/src/gpu/Framebuffer.h @@ -64,7 +64,7 @@ protected: typedef std::shared_ptr SwapchainPointer; -class Framebuffer : public GPUObjectWrapper { +class Framebuffer { public: enum BufferMask { BUFFER_COLOR0 = 1, @@ -134,6 +134,8 @@ public: static const uint32 MAX_NUM_RENDER_BUFFERS = 8; static uint32 getMaxNumRenderBuffers() { return MAX_NUM_RENDER_BUFFERS; } + const GPUObjectPointer gpuObject {}; + protected: SwapchainPointer _swapchain; diff --git a/libraries/gpu/src/gpu/Pipeline.h b/libraries/gpu/src/gpu/Pipeline.h index f062873869..28f7fe106e 100755 --- a/libraries/gpu/src/gpu/Pipeline.h +++ b/libraries/gpu/src/gpu/Pipeline.h @@ -20,7 +20,7 @@ namespace gpu { -class Pipeline : public GPUObjectWrapper { +class Pipeline { public: using Pointer = std::shared_ptr< Pipeline >; @@ -31,6 +31,8 @@ public: const StatePointer& getState() const { return _state; } + const GPUObjectPointer gpuObject {}; + protected: ShaderPointer _program; StatePointer _state; diff --git a/libraries/gpu/src/gpu/Query.h b/libraries/gpu/src/gpu/Query.h index 82f17c71ae..25897c5c91 100644 --- a/libraries/gpu/src/gpu/Query.h +++ b/libraries/gpu/src/gpu/Query.h @@ -19,7 +19,7 @@ namespace gpu { - class Query : public GPUObjectWrapper { + class Query { public: Query(); ~Query(); @@ -27,6 +27,8 @@ namespace gpu { uint32 queryResult; double getElapsedTime(); + + const GPUObjectPointer gpuObject {}; }; typedef std::shared_ptr QueryPointer; diff --git a/libraries/gpu/src/gpu/Resource.h b/libraries/gpu/src/gpu/Resource.h index 817deaae86..3517b67203 100644 --- a/libraries/gpu/src/gpu/Resource.h +++ b/libraries/gpu/src/gpu/Resource.h @@ -108,7 +108,7 @@ protected: }; -class Buffer : public Resource, public GPUObjectWrapper { +class Buffer : public Resource { public: Buffer(); @@ -153,6 +153,8 @@ public: const Sysmem& getSysmem() const { assert(_sysmem); return (*_sysmem); } Sysmem& editSysmem() { assert(_sysmem); return (*_sysmem); } + const GPUObjectPointer gpuObject {}; + protected: Sysmem* _sysmem = NULL; diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h index 908e57e06b..59c6401150 100755 --- a/libraries/gpu/src/gpu/Shader.h +++ b/libraries/gpu/src/gpu/Shader.h @@ -20,7 +20,7 @@ namespace gpu { -class Shader : public GPUObjectWrapper { +class Shader { public: typedef std::shared_ptr< Shader > Pointer; @@ -155,6 +155,8 @@ public: // independant of the graphics api in use underneath (looking at you opengl & vulkan). static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet()); + const GPUObjectPointer gpuObject {}; + protected: Shader(Type type, const Source& source); Shader(Type type, const Pointer& vertex, const Pointer& pixel); diff --git a/libraries/gpu/src/gpu/State.h b/libraries/gpu/src/gpu/State.h index e468b01171..7e32a7280a 100755 --- a/libraries/gpu/src/gpu/State.h +++ b/libraries/gpu/src/gpu/State.h @@ -36,7 +36,7 @@ namespace gpu { class GPUObject; -class State : public GPUObjectWrapper { +class State { public: State(); virtual ~State(); @@ -385,6 +385,8 @@ public: State(const Data& values); const Data& getValues() const { return _values; } + const GPUObjectPointer gpuObject {}; + protected: State(const State& state); State& operator=(const State& state); diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index e68b65a15e..378f49c2f4 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -136,7 +136,7 @@ protected: Desc _desc; }; -class Texture : public Resource, public GPUObjectWrapper { +class Texture : public Resource { public: class Pixels { @@ -356,6 +356,8 @@ public: // Only callable by the Backend void notifyMipFaceGPULoaded(uint16 level, uint8 face) const { return _storage->notifyMipFaceGPULoaded(level, face); } + const GPUObjectPointer gpuObject {}; + protected: std::unique_ptr< Storage > _storage; From 5a9d533e7007d71a59c6fc06ad16ac0bc9c71a16 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 13 Jan 2016 15:30:12 -0800 Subject: [PATCH 133/215] ping pong and gun tweaks --- unpublishedScripts/hiddenEntityReset.js | 17 +++++++++++------ unpublishedScripts/masterReset.js | 17 +++++++++++------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index f96443f059..cd4a05dfce 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -301,15 +301,15 @@ spatialKey: { rightRelativePosition: { x: 0.03, - y: 0, + y: 0.0, z: -0.085 }, leftRelativePosition: { x: -0.03, - y: 0, + y: 0.00, z: -0.085 }, - relativeRotation: Quat.fromPitchYawRollDegrees(100, 90, 0) + relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0) }, invertSolidWhileHeld: true }, @@ -1160,9 +1160,14 @@ }, grabbableKey: { spatialKey: { - relativePosition: { - x: 0.01, - y: 0, + rightRelativePosition: { + x: -0.05, + y: .06, + z: 0.1 + }, + leftRelativePosition: { + x: 0.05, + y: 0.06, z: 0.1 }, relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, -90) diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 81c2db9e05..79e14b4c88 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -286,15 +286,15 @@ MasterReset = function() { spatialKey: { rightRelativePosition: { x: 0.03, - y: 0, + y: 0.0, z: -0.085 }, leftRelativePosition: { x: -0.03, - y: 0, + y: 0.00, z: -0.085 }, - relativeRotation: Quat.fromPitchYawRollDegrees(100, 90, 0) + relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0) }, invertSolidWhileHeld: true }, @@ -1146,9 +1146,14 @@ MasterReset = function() { }, grabbableKey: { spatialKey: { - relativePosition: { - x: 0.01, - y: 0, + rightRelativePosition: { + x: -0.05, + y: .06, + z: 0.1 + }, + leftRelativePosition: { + x: 0.05, + y: 0.06, z: 0.1 }, relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, -90) From b6272b7824e6fb8409682751b3bf47e74dfd42c7 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 12 Jan 2016 20:41:57 -0800 Subject: [PATCH 134/215] Migrate tool window to overlay/QML --- examples/edit.js | 6 +- examples/example/games/planky.js | 2 +- examples/html/entityList.html | 426 ++--- examples/html/entityProperties.html | 1520 +++++++++-------- examples/html/eventBridgeLoader.js | 6 +- examples/html/gridControls.html | 202 +-- examples/libraries/entityList.js | 4 +- examples/libraries/gridTool.js | 4 +- interface/resources/qml/Global.js | 35 +- interface/resources/qml/QmlWebWindow.qml | 82 +- interface/resources/qml/QmlWindow.qml | 40 +- interface/resources/qml/Root.qml | 25 +- interface/resources/qml/ToolWindow.qml | 126 ++ interface/resources/qml/controls/VrDialog.qml | 4 +- interface/resources/qml/controls/WebView.qml | 50 + .../resources/qml/dialogs/FileDialog.qml | 232 +++ interface/resources/qml/test/Stubs.qml | 311 ++++ .../resources/qml/windows/DefaultFrame.qml | 141 +- interface/resources/qml/windows/Window.qml | 197 +-- interface/src/Application.cpp | 7 +- interface/src/Application.h | 5 - interface/src/scripting/WebWindowClass.cpp | 70 +- interface/src/scripting/WebWindowClass.h | 3 +- .../scripting/WindowScriptingInterface.cpp | 5 +- .../src/scripting/WindowScriptingInterface.h | 6 +- interface/src/ui/DialogsManager.cpp | 3 +- interface/src/ui/HMDToolsDialog.cpp | 3 - interface/src/ui/PreferencesDialog.cpp | 3 +- interface/src/ui/PreferencesDialog.h | 4 +- interface/src/ui/ToolWindow.cpp | 145 -- interface/src/ui/ToolWindow.h | 44 - libraries/gl/src/gl/OffscreenQmlSurface.cpp | 15 +- libraries/ui/src/OffscreenUi.cpp | 46 +- libraries/ui/src/OffscreenUi.h | 12 + libraries/ui/src/QmlWebWindowClass.cpp | 16 +- libraries/ui/src/QmlWindowClass.cpp | 199 ++- libraries/ui/src/QmlWindowClass.h | 8 +- 37 files changed, 2313 insertions(+), 1694 deletions(-) create mode 100644 interface/resources/qml/ToolWindow.qml create mode 100644 interface/resources/qml/controls/WebView.qml create mode 100644 interface/resources/qml/dialogs/FileDialog.qml create mode 100644 interface/resources/qml/test/Stubs.qml delete mode 100644 interface/src/ui/ToolWindow.cpp delete mode 100644 interface/src/ui/ToolWindow.h diff --git a/examples/edit.js b/examples/edit.js index 6d77aa2f11..41f25cb2e5 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -1502,7 +1502,11 @@ PropertiesTool = function(opts) { var that = {}; var url = Script.resolvePath('html/entityProperties.html'); - var webView = new WebWindow('Entity Properties', url, 200, 280, true); + var webView = new OverlayWebWindow({ + title: 'Entity Properties', + source: url, + toolWindow: true + }); var visible = false; diff --git a/examples/example/games/planky.js b/examples/example/games/planky.js index 8abc697353..78e7bf9cbe 100644 --- a/examples/example/games/planky.js +++ b/examples/example/games/planky.js @@ -51,7 +51,7 @@ SettingsWindow = function() { this.plankyStack = null; this.webWindow = null; this.init = function(plankyStack) { - _this.webWindow = new WebWindow('Planky', Script.resolvePath('../../html/plankySettings.html'), 255, 500, true); + _this.webWindow = new OverlayWebWindow('Planky', Script.resolvePath('../../html/plankySettings.html'), 255, 500, true); _this.webWindow.setVisible(false); _this.webWindow.eventBridge.webEventReceived.connect(_this.onWebEventReceived); _this.plankyStack = plankyStack; diff --git a/examples/html/entityList.html b/examples/html/entityList.html index 3a1eeedf95..ad10a50c01 100644 --- a/examples/html/entityList.html +++ b/examples/html/entityList.html @@ -2,6 +2,8 @@ + + diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index ff72e95313..daf85664fb 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -5,6 +5,8 @@ + + diff --git a/examples/html/eventBridgeLoader.js b/examples/html/eventBridgeLoader.js index b62e7d9384..ebfb6dc740 100644 --- a/examples/html/eventBridgeLoader.js +++ b/examples/html/eventBridgeLoader.js @@ -8,6 +8,8 @@ // void scriptEventReceived(const QString& data); // +var EventBridge; + EventBridgeConnectionProxy = function(parent) { this.parent = parent; this.realSignal = this.parent.realBridge.scriptEventReceived @@ -46,12 +48,10 @@ openEventBridge = function(callback) { socket.onopen = function() { channel = new QWebChannel(socket, function(channel) { console.log("Document url is " + document.URL); - for(var key in channel.objects){ - console.log("registered object: " + key); - } var webWindow = channel.objects[document.URL.toLowerCase()]; console.log("WebWindow is " + webWindow) eventBridgeProxy = new EventBridgeProxy(webWindow); + EventBridge = eventBridgeProxy; if (callback) { callback(eventBridgeProxy); } }); } diff --git a/examples/html/gridControls.html b/examples/html/gridControls.html index 941a4b5c2a..1a3e949446 100644 --- a/examples/html/gridControls.html +++ b/examples/html/gridControls.html @@ -1,110 +1,114 @@ + + diff --git a/examples/libraries/entityList.js b/examples/libraries/entityList.js index 1aa08fbe2d..b37ba58737 100644 --- a/examples/libraries/entityList.js +++ b/examples/libraries/entityList.js @@ -4,7 +4,9 @@ EntityListTool = function(opts) { var that = {}; var url = ENTITY_LIST_HTML_URL; - var webView = new WebWindow('Entities', url, 200, 280, true); + var webView = new OverlayWebWindow({ + title: 'Entities', source: url, toolWindow: true + }); var searchRadius = 100; diff --git a/examples/libraries/gridTool.js b/examples/libraries/gridTool.js index 35d9858ace..54f80e9c96 100644 --- a/examples/libraries/gridTool.js +++ b/examples/libraries/gridTool.js @@ -231,7 +231,9 @@ GridTool = function(opts) { var listeners = []; var url = GRID_CONTROLS_HTML_URL; - var webView = new WebWindow('Grid', url, 200, 280, true); + var webView = new OverlayWebWindow({ + title: 'Grid', source: url, toolWindow: true + }); horizontalGrid.addListener(function(data) { webView.eventBridge.emitScriptEvent(JSON.stringify(data)); diff --git a/interface/resources/qml/Global.js b/interface/resources/qml/Global.js index fadf6d6c71..3ad6352af6 100644 --- a/interface/resources/qml/Global.js +++ b/interface/resources/qml/Global.js @@ -10,18 +10,22 @@ function findChild(item, name) { return null; } -function findParent(item, name) { +function findParentMatching(item, predicate) { while (item) { - if (item.objectName === name) { - return item; + if (predicate(item)) { + break; } item = item.parent; } - return null; + return item; } -function getDesktop(item) { - return findParent(item, OFFSCREEN_ROOT_OBJECT_NAME); +function findParentByName(item, name) { + return findParentMatching(item, function(item) { + var testName = name; + var result = (item.name === testName); + return result; + }); } function findRootMenu(item) { @@ -29,6 +33,13 @@ function findRootMenu(item) { return item ? item.rootMenu : null; } +function isDesktop(item) { + return item.desktopRoot; +} + +function isTopLevelWindow(item) { + return item.topLevelWindow; +} function getTopLevelWindows(item) { var desktop = getDesktop(item); @@ -40,8 +51,7 @@ function getTopLevelWindows(item) { for (var i = 0; i < desktop.children.length; ++i) { var child = desktop.children[i]; - if ((Global.OFFSCREEN_WINDOW_OBJECT_NAME === child.objectName) || - child[Global.OFFSCREEN_WINDOW_OBJECT_NAME]) { + if (isTopLevelWindow(child)) { var windowId = child.toString(); currentWindows.push(child) } @@ -50,9 +60,12 @@ function getTopLevelWindows(item) { } +function getDesktop(item) { + return findParentMatching(item, isDesktop); +} + function getDesktopWindow(item) { - item = findParent(item, OFFSCREEN_WINDOW_OBJECT_NAME); - return item; + return findParentMatching(item, isTopLevelWindow) } function closeWindow(item) { @@ -142,7 +155,7 @@ function raiseWindow(item) { var desktop = getDesktop(targetWindow); if (!desktop) { - //console.warn("Could not find desktop for window " + targetWindow); + console.warn("Could not find desktop for window " + targetWindow); return; } diff --git a/interface/resources/qml/QmlWebWindow.qml b/interface/resources/qml/QmlWebWindow.qml index 008aaeccc3..a622931db7 100644 --- a/interface/resources/qml/QmlWebWindow.qml +++ b/interface/resources/qml/QmlWebWindow.qml @@ -2,86 +2,26 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 import QtWebEngine 1.1 -import "controls" +import "windows" as Windows +import "controls" as Controls import "styles" -VrDialog { +Windows.Window { id: root HifiConstants { id: hifi } title: "WebWindow" resizable: true - enabled: false visible: false // Don't destroy on close... otherwise the JS/C++ will have a dangling pointer destroyOnCloseButton: false - contentImplicitWidth: clientArea.implicitWidth - contentImplicitHeight: clientArea.implicitHeight - backgroundColor: "#7f000000" - property url source: "about:blank" + property alias source: webview.url - signal navigating(string url) - function stop() { - webview.stop(); + function raiseWindow() { Desktop.raise(root) } + + Controls.WebView { + id: webview + url: "about:blank" + anchors.fill: parent + focus: true } - - Component.onCompleted: { - // Ensure the JS from the web-engine makes it to our logging - webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) { - console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message); - }); - - } - - Item { - id: clientArea - implicitHeight: 600 - implicitWidth: 800 - x: root.clientX - y: root.clientY - width: root.clientWidth - height: root.clientHeight - - WebEngineView { - id: webview - url: root.source - anchors.fill: parent - focus: true - - property var originalUrl - property var lastFixupTime: 0 - - onUrlChanged: { - var currentUrl = url.toString(); - var newUrl = urlHandler.fixupUrl(currentUrl).toString(); - if (newUrl != currentUrl) { - var now = new Date().valueOf(); - if (url === originalUrl && (now - lastFixupTime < 100)) { - console.warn("URL fixup loop detected") - return; - } - originalUrl = url - lastFixupTime = now - url = newUrl; - } - } - - onLoadingChanged: { - // Required to support clicking on "hifi://" links - if (WebEngineView.LoadStartedStatus == loadRequest.status) { - var url = loadRequest.url.toString(); - if (urlHandler.canHandleUrl(url)) { - if (urlHandler.handleUrl(url)) { - webview.stop(); - } - } - } - } - - profile: WebEngineProfile { - id: webviewProfile - httpUserAgent: "Mozilla/5.0 (HighFidelityInterface)" - storageName: "qmlWebEngine" - } - } - } // item } // dialog diff --git a/interface/resources/qml/QmlWindow.qml b/interface/resources/qml/QmlWindow.qml index f8217371e7..2a8d8f60d9 100644 --- a/interface/resources/qml/QmlWindow.qml +++ b/interface/resources/qml/QmlWindow.qml @@ -5,52 +5,32 @@ import QtWebChannel 1.0 import QtWebSockets 1.0 import "qrc:///qtwebchannel/qwebchannel.js" as WebChannel -import "Global.js" as Global - +import "windows" as Windows import "controls" import "styles" -VrDialog { +Windows.Window { id: root HifiConstants { id: hifi } title: "QmlWindow" resizable: true - enabled: false visible: false focus: true property var channel; - // Don't destroy on close... otherwise the JS/C++ will have a dangling pointer destroyOnCloseButton: false - contentImplicitWidth: clientArea.implicitWidth - contentImplicitHeight: clientArea.implicitHeight property alias source: pageLoader.source - function raiseWindow() { - Global.raiseWindow(root) - } + function raiseWindow() { Desktop.raise(root) } - Item { - id: clientArea - implicitHeight: 600 - implicitWidth: 800 - x: root.clientX - y: root.clientY - width: root.clientWidth - height: root.clientHeight + Loader { + id: pageLoader + objectName: "Loader" focus: true - clip: true - - Loader { - id: pageLoader - objectName: "Loader" - anchors.fill: parent - focus: true - property var dialog: root + property var dialog: root - Keys.onPressed: { - console.log("QmlWindow pageLoader keypress") - } + Keys.onPressed: { + console.log("QmlWindow pageLoader keypress") } - } // item + } } // dialog diff --git a/interface/resources/qml/Root.qml b/interface/resources/qml/Root.qml index 247947b72c..08e75b7cce 100644 --- a/interface/resources/qml/Root.qml +++ b/interface/resources/qml/Root.qml @@ -7,22 +7,25 @@ import "Global.js" as Global // windows will be childed. Item { id: desktop - objectName: Global.OFFSCREEN_ROOT_OBJECT_NAME anchors.fill: parent; + onParentChanged: forceActiveFocus(); + + // Allows QML/JS to find the desktop through the parent chain + property bool desktopRoot: true + + // The VR version of the primary menu + property var rootMenu: Menu { objectName: "rootMenu" } + + // List of all top level windows property var windows: []; - property var rootMenu: Menu { - objectName: "rootMenu" - } + onChildrenChanged: windows = Global.getTopLevelWindows(desktop); - onChildrenChanged: { - windows = Global.getTopLevelWindows(desktop); - } - - onParentChanged: { - forceActiveFocus(); - } + // The tool window, one instance + property alias toolWindow: toolWindow + ToolWindow { id: toolWindow } function raise(item) { Global.raiseWindow(item); } + } diff --git a/interface/resources/qml/ToolWindow.qml b/interface/resources/qml/ToolWindow.qml new file mode 100644 index 0000000000..3ce5b5616d --- /dev/null +++ b/interface/resources/qml/ToolWindow.qml @@ -0,0 +1,126 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtWebEngine 1.1 + +import Qt.labs.settings 1.0 + +import "windows" as Windows +import "controls" as Controls + +Windows.Window { + id: toolWindow + resizable: true + objectName: "ToolWindow" + destroyOnCloseButton: false + destroyOnInvisible: false + visible: false + property string newTabSource + property alias tabView: tabView + onParentChanged: { + x = desktop.width / 2 - width / 2; + y = desktop.height / 2 - height / 2; + } + + Settings { + category: "ToolWindow.Position" + property alias x: toolWindow.x + property alias y: toolWindow.y + } + + property var webTabCreator: Component { + Controls.WebView { + id: webView + property string originalUrl; + + // Both toolWindow.newTabSource and url can change, so we need + // to store the original url here, without creating any bindings + Component.onCompleted: { + originalUrl = toolWindow.newTabSource; + url = originalUrl; + } + } + } + + TabView { + id: tabView; width: 384; height: 640; + onCountChanged: { + if (0 == count) { + toolWindow.visible = false + } + } + } + + function updateVisiblity() { + var newVisible = false + console.log("Checking " + tabView.count + " children") + for (var i = 0; i < tabView.count; ++i) { + if (tabView.getTab(i).enabled) { + console.log("Tab " + i + " enabled"); + newVisible = true; + break; + } + } + console.log("Setting toolWindow visible: " + newVisible); + visible = newVisible + } + + function findIndexForUrl(source) { + for (var i = 0; i < tabView.count; ++i) { + var tab = tabView.getTab(i); + if (tab && tab.item && tab.item.originalUrl && + tab.item.originalUrl === source) { + return i; + } + } + return -1; + } + + function removeTabForUrl(source) { + var index = findIndexForUrl(source); + if (index < 0) { + console.warn("Could not find tab for " + source); + return; + } + tabView.removeTab(index); + console.log("Updating visibility based on child tab removed"); + updateVisiblity(); + } + + function addWebTab(properties) { + if (!properties.source) { + console.warn("Attempted to open Web Tool Pane without URl") + return; + } + + var existingTabIndex = findIndexForUrl(properties.source); + if (existingTabIndex >= 0) { + console.log("Existing tab " + existingTabIndex + " found with URL " + properties.source) + return tabView.getTab(existingTabIndex); + } + + var title = properties.title || "Unknown"; + newTabSource = properties.source; + console.log(typeof(properties.source)) + var newTab = tabView.addTab(title, webTabCreator); + newTab.active = true; + newTab.enabled = false; + + if (properties.width) { + tabView.width = Math.min(Math.max(tabView.width, properties.width), + toolWindow.maxSize.x); + } + + if (properties.height) { + tabView.height = Math.min(Math.max(tabView.height, properties.height), + toolWindow.maxSize.y); + } + + console.log("Updating visibility based on child tab added"); + newTab.enabledChanged.connect(function() { + console.log("Updating visibility based on child tab enabled change"); + updateVisiblity(); + }) + updateVisiblity(); + return newTab + } +} diff --git a/interface/resources/qml/controls/VrDialog.qml b/interface/resources/qml/controls/VrDialog.qml index 18cab04533..d4568cded1 100644 --- a/interface/resources/qml/controls/VrDialog.qml +++ b/interface/resources/qml/controls/VrDialog.qml @@ -3,8 +3,6 @@ import QtQuick.Controls 1.2 import "." import "../styles" -import "../Global.js" as Global - /* * FIXME Need to create a client property here so that objects can be * placed in it without having to think about positioning within the outer @@ -48,7 +46,7 @@ DialogBase { if (enabled) { visible = true; if (root.parent) { - Global.raiseWindow(root); + Desktop.raise(root); } } } diff --git a/interface/resources/qml/controls/WebView.qml b/interface/resources/qml/controls/WebView.qml new file mode 100644 index 0000000000..285aa80d4e --- /dev/null +++ b/interface/resources/qml/controls/WebView.qml @@ -0,0 +1,50 @@ +import QtQuick 2.5 +import QtWebEngine 1.1 + +WebEngineView { + id: root + property var originalUrl + property int lastFixupTime: 0 + + Component.onCompleted: { + console.log("Connecting JS messaging to Hifi Logging") + // Ensure the JS from the web-engine makes it to our logging + root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) { + console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message); + }); + } + + + onUrlChanged: { + var currentUrl = url.toString(); + var newUrl = urlHandler.fixupUrl(currentUrl).toString(); + if (newUrl != currentUrl) { + var now = new Date().valueOf(); + if (url === originalUrl && (now - lastFixupTime < 100)) { + console.warn("URL fixup loop detected") + return; + } + originalUrl = url + lastFixupTime = now + url = newUrl; + } + } + + onLoadingChanged: { + // Required to support clicking on "hifi://" links + if (WebEngineView.LoadStartedStatus == loadRequest.status) { + var url = loadRequest.url.toString(); + if (urlHandler.canHandleUrl(url)) { + if (urlHandler.handleUrl(url)) { + root.stop(); + } + } + } + } + + profile: WebEngineProfile { + id: webviewProfile + httpUserAgent: "Mozilla/5.0 (HighFidelityInterface)" + storageName: "qmlWebEngine" + } +} diff --git a/interface/resources/qml/dialogs/FileDialog.qml b/interface/resources/qml/dialogs/FileDialog.qml new file mode 100644 index 0000000000..6711475d23 --- /dev/null +++ b/interface/resources/qml/dialogs/FileDialog.qml @@ -0,0 +1,232 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.4 +import Qt.labs.folderlistmodel 2.1 +import Qt.labs.settings 1.0 + +import ".." +import "." + +// Work in progress.... +DialogBase { + id: root + Constants { id: vr } + property string settingsName: "" + + signal selectedFile(var file); + signal canceled(); + + function selectCurrentFile() { + var row = tableView.currentRow + console.log("Selecting row " + row) + var fileName = folderModel.get(row, "fileName"); + if (fileName === "..") { + folderModel.folder = folderModel.parentFolder + } else if (folderModel.isFolder(row)) { + folderModel.folder = folderModel.get(row, "fileURL"); + } else { + selectedFile(folderModel.get(row, "fileURL")); + enabled = false + } + + } + + property var folderModel: FolderListModel { + id: folderModel + showDotAndDotDot: true + showDirsFirst: true + folder: "file:///C:/"; + onFolderChanged: tableView.currentRow = 0 + } + + property var filterModel: ListModel { + ListElement { + text: "All Files (*.*)" + filter: "*" + } + ListElement { + text: "Javascript Files (*.js)" + filter: "*.js" + } + ListElement { + text: "QML Files (*.qml)" + filter: "*.qml" + } + } + + Settings { + // fixme, combine with a property to allow different saved locations + category: "FileOpenLastFolder." + settingsName + property alias folder: folderModel.folder + } + + Rectangle { + id: currentDirectoryWrapper + anchors.left: parent.left + anchors.leftMargin: 8 + anchors.right: parent.right + anchors.rightMargin: 8 + anchors.top: parent.top + anchors.topMargin: 8 + height: currentDirectory.implicitHeight + 8 + radius: vr.styles.radius + color: vr.controls.colors.inputBackground + + TextEdit { + enabled: false + id: currentDirectory + text: folderModel.folder + anchors { + fill: parent + leftMargin: 8 + rightMargin: 8 + topMargin: 4 + bottomMargin: 4 + } + } + } + + + TableView { + id: tableView + focus: true + model: folderModel + anchors.top: currentDirectoryWrapper.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: selectionType.top + anchors.margins: 8 + itemDelegate: Item { + Text { + anchors.verticalCenter: parent.verticalCenter + font.family: vr.fonts.lightFontName + font.pointSize: 12 + color: tableView.activeFocus && styleData.row === tableView.currentRow ? "yellow" : styleData.textColor + elide: styleData.elideMode + text: getText(); + function getText() { + switch (styleData.column) { + //case 1: return Date.fromLocaleString(locale, styleData.value, "yyyy-MM-dd hh:mm:ss"); + case 2: return folderModel.get(styleData.row, "fileIsDir") ? "" : formatSize(styleData.value); + default: return styleData.value; + } + } + + function formatSize(size) { + var suffixes = [ "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" ]; + var suffixIndex = 0 + while ((size / 1024.0) > 1.1) { + size /= 1024.0; + ++suffixIndex; + } + + size = Math.round(size*1000)/1000; + size = size.toLocaleString() + + return size + " " + suffixes[suffixIndex]; + } + } + } + + TableViewColumn { + role: "fileName" + title: "Name" + width: 400 + } + TableViewColumn { + role: "fileModified" + title: "Date Modified" + width: 200 + } + TableViewColumn { + role: "fileSize" + title: "Size" + width: 200 + } + + function selectItem(row) { + selectCurrentFile() + } + + + Keys.onReturnPressed: selectCurrentFile(); + onDoubleClicked: { currentRow = row; selectCurrentFile(); } + onCurrentRowChanged: currentSelection.text = model.get(currentRow, "fileName"); + KeyNavigation.left: cancelButton + KeyNavigation.right: selectionType + } + + Rectangle { + anchors.right: selectionType.left + anchors.rightMargin: 8 + anchors.top: selectionType.top + anchors.bottom: selectionType.bottom + anchors.left: parent.left + anchors.leftMargin: 8 + radius: 8 + color: "#eee" + Text { + id: currentSelection + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 8 + anchors.verticalCenter: parent.verticalCenter + font.family: vr.fonts.mainFontName + font.pointSize: 18 + } + } + + ComboBox { + id: selectionType + anchors.bottom: buttonRow.top + anchors.bottomMargin: 8 + anchors.right: parent.right + anchors.rightMargin: 8 + anchors.left: buttonRow.left + model: filterModel + onCurrentIndexChanged: folderModel.nameFilters = [ + filterModel.get(currentIndex).filter + ] + + KeyNavigation.left: tableView + KeyNavigation.right: openButton + } + + Row { + id: buttonRow + anchors.right: parent.right + anchors.rightMargin: 8 + anchors.bottom: parent.bottom + anchors.bottomMargin: 8 + layoutDirection: Qt.RightToLeft + spacing: 8 + Button { + id: cancelButton + text: "Cancel" + KeyNavigation.up: selectionType + KeyNavigation.left: openButton + KeyNavigation.right: tableView.contentItem + Keys.onReturnPressed: { canceled(); root.enabled = false } + onClicked: { canceled(); root.enabled = false } + } + Button { + id: openButton + text: "Open" + enabled: tableView.currentRow != -1 && !folderModel.get(tableView.currentRow, "fileIsDir") + KeyNavigation.up: selectionType + KeyNavigation.left: selectionType + KeyNavigation.right: cancelButton + onClicked: selectCurrentFile(); + Keys.onReturnPressed: selectedFile(folderModel.get(tableView.currentRow, "fileURL")) + } + } + + Keys.onPressed: { + if (event.key === Qt.Key_Backspace && folderModel.parentFolder && folderModel.parentFolder != "") { + console.log("Navigating to " + folderModel.parentFolder) + folderModel.folder = folderModel.parentFolder + event.accepted = true + } + } +} + + diff --git a/interface/resources/qml/test/Stubs.qml b/interface/resources/qml/test/Stubs.qml new file mode 100644 index 0000000000..f23e5c89ee --- /dev/null +++ b/interface/resources/qml/test/Stubs.qml @@ -0,0 +1,311 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 + +// Stubs for the global service objects set by Interface.cpp when creating the UI +// This is useful for testing inside Qt creator where these services don't actually exist. +Item { + + Item { + objectName: "urlHandler" + function fixupUrl(url) { return url; } + function canHandleUrl(url) { return false; } + function handleUrl(url) { return true; } + } + + Item { + objectName: "Account" + function isLoggedIn() { return true; } + function getUsername() { return "Jherico"; } + } + + Item { + objectName: "ScriptDiscoveryService" + property var scriptsModelFilter: scriptsModel + signal scriptCountChanged() + property var _runningScripts:[ + { name: "wireFrameTest.js", url: "foo/wireframetest.js", path: "foo/wireframetest.js", local: true }, + { name: "edit.js", url: "foo/edit.js", path: "foo/edit.js", local: false }, + { name: "listAllScripts.js", url: "foo/listAllScripts.js", path: "foo/listAllScripts.js", local: false }, + { name: "users.js", url: "foo/users.js", path: "foo/users.js", local: false }, + ] + + function getRunning() { + return _runningScripts; + } + + } + + Item { + id: menuHelper + objectName: "MenuHelper" + + Component { + id: modelMaker + ListModel { } + } + + function toModel(menu, parent) { + if (!parent) { parent = menuHelper } + var result = modelMaker.createObject(parent); + if (menu.type !== MenuItemType.Menu) { + console.warn("Not a menu: " + menu); + return result; + } + + var items = menu.items; + for (var i = 0; i < items.length; ++i) { + var item = items[i]; + switch (item.type) { + case 2: + result.append({"name": item.title, "item": item}) + break; + case 1: + result.append({"name": item.text, "item": item}) + break; + case 0: + result.append({"name": "", "item": item}) + break; + } + } + return result; + } + + } + + Item { + objectName: "Desktop" + + property string _OFFSCREEN_ROOT_OBJECT_NAME: "desktopRoot"; + property string _OFFSCREEN_DIALOG_OBJECT_NAME: "topLevelWindow"; + + + function findChild(item, name) { + for (var i = 0; i < item.children.length; ++i) { + if (item.children[i].objectName === name) { + return item.children[i]; + } + } + return null; + } + + function findParent(item, name) { + while (item) { + if (item.objectName === name) { + return item; + } + item = item.parent; + } + return null; + } + + function findDialog(item) { + item = findParent(item, _OFFSCREEN_DIALOG_OBJECT_NAME); + return item; + } + + function closeDialog(item) { + item = findDialog(item); + if (item) { + item.enabled = false + } else { + console.warn("Could not find top level dialog") + } + } + + function getDesktop(item) { + while (item) { + if (item.desktopRoot) { + break; + } + item = item.parent; + } + return item + } + + function raise(item) { + var desktop = getDesktop(item); + if (desktop) { + desktop.raise(item); + } + } + } + + Menu { + id: root + objectName: "rootMenu" + + Menu { + title: "Audio" + } + + Menu { + title: "Avatar" + } + + Menu { + title: "Display" + ExclusiveGroup { id: displayMode } + Menu { + title: "More Stuff" + + Menu { title: "Empty" } + + MenuItem { + text: "Do Nothing" + onTriggered: console.log("Nothing") + } + } + MenuItem { + text: "Oculus" + exclusiveGroup: displayMode + checkable: true + } + MenuItem { + text: "OpenVR" + exclusiveGroup: displayMode + checkable: true + } + MenuItem { + text: "OSVR" + exclusiveGroup: displayMode + checkable: true + } + MenuItem { + text: "2D Screen" + exclusiveGroup: displayMode + checkable: true + checked: true + } + MenuItem { + text: "3D Screen (Active)" + exclusiveGroup: displayMode + checkable: true + } + MenuItem { + text: "3D Screen (Passive)" + exclusiveGroup: displayMode + checkable: true + } + } + + Menu { + title: "View" + Menu { + title: "Camera Mode" + ExclusiveGroup { id: cameraMode } + MenuItem { + exclusiveGroup: cameraMode + text: "First Person"; + onTriggered: console.log(text + " checked " + checked) + checkable: true + checked: true + } + MenuItem { + exclusiveGroup: cameraMode + text: "Third Person"; + onTriggered: console.log(text) + checkable: true + } + MenuItem { + exclusiveGroup: cameraMode + text: "Independent Mode"; + onTriggered: console.log(text) + checkable: true + } + MenuItem { + exclusiveGroup: cameraMode + text: "Entity Mode"; + onTriggered: console.log(text) + enabled: false + checkable: true + } + MenuItem { + exclusiveGroup: cameraMode + text: "Fullscreen Mirror"; + onTriggered: console.log(text) + checkable: true + } + } + } + + Menu { + title: "Edit" + + MenuItem { + text: "Undo" + shortcut: "Ctrl+Z" + enabled: false + onTriggered: console.log(text) + } + + MenuItem { + text: "Redo" + shortcut: "Ctrl+Shift+Z" + enabled: false + onTriggered: console.log(text) + } + + MenuSeparator { } + + MenuItem { + text: "Cut" + shortcut: "Ctrl+X" + onTriggered: console.log(text) + } + + MenuItem { + text: "Copy" + shortcut: "Ctrl+C" + onTriggered: console.log(text) + } + + MenuItem { + text: "Paste" + shortcut: "Ctrl+V" + visible: false + onTriggered: console.log("Paste") + } + } + + Menu { + title: "Navigate" + } + + Menu { + title: "Market" + } + + Menu { + title: "Settings" + } + + Menu { + title: "Developer" + } + + Menu { + title: "Quit" + } + + Menu { + title: "File" + + Action { + id: login + text: "Login" + } + + Action { + id: quit + text: "Quit" + shortcut: "Ctrl+Q" + onTriggered: Qt.quit(); + } + + MenuItem { action: quit } + MenuItem { action: login } + } + } + +} + diff --git a/interface/resources/qml/windows/DefaultFrame.qml b/interface/resources/qml/windows/DefaultFrame.qml index d810ea8c77..ed8999da04 100644 --- a/interface/resources/qml/windows/DefaultFrame.qml +++ b/interface/resources/qml/windows/DefaultFrame.qml @@ -4,90 +4,133 @@ import "." import "../controls" Frame { - id: root - anchors { margins: -16; topMargin: parent.closable ? -32 : -16; } + id: frame + // The frame fills the parent, which should be the size of the content. + // The frame decorations use negative anchor margins to extend beyond + anchors.fill: parent + // Size of the controls + readonly property real iconSize: 24; + // Convenience accessor for the window + property alias window: frame.parent + // FIXME needed? + property alias decoration: decoration - MouseArea { - id: controlsArea - anchors.fill: desktopControls - hoverEnabled: true - drag.target: root.parent - propagateComposedEvents: true - onClicked: { - root.raise() - mouse.accepted = false; - } - - MouseArea { - id: sizeDrag - enabled: root.parent.resizable - property int startX - property int startY - anchors.right: parent.right - anchors.bottom: parent.bottom - width: 16 - height: 16 - z: 1000 - hoverEnabled: true - onPressed: { - startX = mouseX - startY = mouseY - } - onPositionChanged: { - if (pressed) { - root.deltaSize((mouseX - startX), (mouseY - startY)) - startX = mouseX - startY = mouseY - } - } - } + Rectangle { + anchors { margins: -4 } + visible: !decoration.visible + anchors.fill: parent; + color: "#7f7f7f7f"; + radius: 3; } Rectangle { - id: desktopControls - // FIXME this doesn't work as expected - visible: root.parent.showFrame + id: decoration + anchors { margins: -iconSize; topMargin: -iconSize * (window.closable ? 2 : 1); } + visible: window.activator.containsMouse anchors.fill: parent; color: "#7f7f7f7f"; radius: 3; + // Allow dragging of the window + MouseArea { + id: dragMouseArea + anchors.fill: parent + drag { + target: window + // minimumX: (decoration.width - window.width) * -1 + // minimumY: 0 + // maximumX: (window.parent.width - window.width) - 2 * (decoration.width - window.width) + // maximumY: (window.parent.height - window.height) - 2 * (decoration.height - window.height) + } + } Row { + id: controlsRow anchors.right: parent.right anchors.top: parent.top - anchors.rightMargin: 4 - anchors.topMargin: 4 - spacing: 4 + anchors.rightMargin: iconSize + anchors.topMargin: iconSize / 2 + spacing: iconSize / 4 FontAwesome { visible: false text: "\uf08d" style: Text.Outline; styleColor: "white" - size: 16 - rotation: !root.parent ? 90 : root.parent.pinned ? 0 : 90 - color: root.pinned ? "red" : "black" + size: frame.iconSize + rotation: !frame.parent ? 90 : frame.parent.pinned ? 0 : 90 + color: frame.pinned ? "red" : "black" MouseArea { anchors.fill: parent propagateComposedEvents: true - onClicked: { root.pin(); mouse.accepted = false; } + onClicked: { frame.pin(); mouse.accepted = false; } } } FontAwesome { - visible: root.parent.closable + visible: window.closable text: closeClickArea.containsMouse ? "\uf057" : "\uf05c" style: Text.Outline; styleColor: "white" color: closeClickArea.containsMouse ? "red" : "black" - size: 16 + size: frame.iconSize MouseArea { id: closeClickArea anchors.fill: parent hoverEnabled: true - onClicked: root.close(); + onClicked: frame.close(); } } } + + // Allow sizing of the window + // FIXME works in native QML, doesn't work in Interface + MouseArea { + id: sizeDrag + width: iconSize + height: iconSize + + anchors { + right: decoration.right; + bottom: decoration.bottom + bottomMargin: iconSize * 2 + } + property vector2d pressOrigin + property vector2d sizeOrigin + property bool hid: false + onPressed: { + console.log("Pressed on size") + pressOrigin = Qt.vector2d(mouseX, mouseY) + sizeOrigin = Qt.vector2d(window.content.width, window.content.height) + hid = false; + } + onReleased: { + if (hid) { + window.content.visible = true + hid = false; + } + } + + onPositionChanged: { + if (pressed) { + if (window.content.visible) { + window.content.visible = false; + hid = true; + } + var delta = Qt.vector2d(mouseX, mouseY).minus(pressOrigin); + frame.deltaSize(delta.x, delta.y) + } + } + } + + FontAwesome { + visible: window.resizable + rotation: -45 + anchors { centerIn: sizeDrag } + horizontalAlignment: Text.AlignHCenter + text: "\uf07d" + size: iconSize / 3 * 2 + style: Text.Outline; styleColor: "white" + } } } diff --git a/interface/resources/qml/windows/Window.qml b/interface/resources/qml/windows/Window.qml index 2e1f0e24d5..6b008f2872 100644 --- a/interface/resources/qml/windows/Window.qml +++ b/interface/resources/qml/windows/Window.qml @@ -6,78 +6,75 @@ import "../styles" FocusScope { id: window - objectName: "topLevelWindow" HifiConstants { id: hifi } - implicitHeight: frame.height - implicitWidth: frame.width + // The Window size is the size of the content, while the frame + // decorations can extend outside it. Windows should generally not be + // given explicit height / width, but rather be allowed to conform to + // their content + implicitHeight: content.height + implicitWidth: content.width property bool topLevelWindow: true property string title - property bool showFrame: true + // Should the window include a close control? property bool closable: true - property bool destroyOnInvisible: false + // Should hitting the close button hide or destroy the window? property bool destroyOnCloseButton: true - property bool pinned: false + // Should hiding the window destroy it or just hide it? + property bool destroyOnInvisible: false + // FIXME support for pinned / unpinned pending full design + // property bool pinnable: false + // property bool pinned: false property bool resizable: false - property real minX: 320 - property real minY: 240; + property vector2d minSize: Qt.vector2d(100, 100) + property vector2d maxSize: Qt.vector2d(1280, 720) + + // The content to place inside the window, determined by the client default property var content - property var frame: DefaultFrame { anchors.fill: content } - property var blur: FastBlur { anchors.fill: content; source: content; visible: false; radius: 0} - //property var hoverDetector: MouseArea { anchors.fill: frame; hoverEnabled: true; propagateComposedEvents: true; } - //property bool mouseInWindow: hoverDetector.containsMouse - children: [ frame, content, blur ] - signal windowDestroyed(); - QtObject { - id: d - property vector2d minPosition: Qt.vector2d(0, 0); - property vector2d maxPosition: Qt.vector2d(100, 100); - function clamp(value, min, max) { - return Math.min(Math.max(value, min), max); + onContentChanged: { + if (content) { + content.anchors.fill = window } - - function updateParentRect() { -// if (!frame) { return; } -// console.log(window.parent.width); -// console.log(frame.width); -// minPosition = Qt.vector2d(-frame.anchors.leftMargin, -frame.anchors.topMargin); -// maxPosition = Qt.vector2d( -// Math.max(minPosition.x, Desktop.width - frame.width + minPosition.x), -// Math.max(minPosition.y, Desktop.height - frame.height + minPosition.y)) -// console.log(maxPosition); - } - - function keepOnScreen() { - //window.x = clamp(x, minPosition.x, maxPosition.x); - //window.y = clamp(y, minPosition.y, maxPosition.y); - } - - onMinPositionChanged: keepOnScreen(); - onMaxPositionChanged: keepOnScreen(); } + // Default to a standard frame. Can be overriden to provide custom + // frame styles, like a full desktop frame to simulate a modal window + property var frame: DefaultFrame { + z: -1 + anchors.fill: parent + } + + // This mouse area serves to raise the window. To function, it must live + // in the window and have a higher Z-order than the content, but follow + // the position and size of frame decoration + property var activator: MouseArea { + width: frame.decoration.width + height: frame.decoration.height + x: frame.decoration.anchors.margins + y: frame.decoration.anchors.topMargin + propagateComposedEvents: true + hoverEnabled: true + onPressed: { window.raise(); mouse.accepted = false; } + // Debugging visualization + // Rectangle { anchors.fill:parent; color: "#7f00ff00" } + } + + children: [ frame, content, activator ] + signal windowDestroyed(); + Component.onCompleted: { - d.updateParentRect(); + fadeTargetProperty = visible ? 1.0 : 0.0 raise(); } Component.onDestruction: { + content.destroy(); console.log("Destroyed " + window); windowDestroyed(); } - - onParentChanged: { - d.updateParentRect(); - raise(); - } - - onFrameChanged: d.updateParentRect(); - onWidthChanged: d.updateParentRect(); - onHeightChanged: d.updateParentRect(); - onXChanged: d.keepOnScreen(); - onYChanged: d.keepOnScreen(); + onParentChanged: raise(); Connections { target: frame @@ -85,15 +82,15 @@ FocusScope { onClose: window.close(); onPin: window.pin(); onDeltaSize: { - console.log("deltaSize") - content.width = Math.max(content.width + dx, minX) - content.height = Math.max(content.height + dy, minY) + var newSize = Qt.vector2d(content.width + dx, content.height + dy); + newSize = clampVector(newSize, minSize, maxSize); + window.width = newSize.x + window.height = newSize.y } } - function raise() { - if (enabled && parent) { + if (visible && parent) { Desktop.raise(window) if (!focus) { focus = true; @@ -102,48 +99,58 @@ FocusScope { } function pin() { - pinned = ! pinned +// pinned = ! pinned } // our close function performs the same way as the OffscreenUI class: - // don't do anything but manipulate the enabled flag and let the other + // don't do anything but manipulate the targetVisible flag and let the other // mechanisms decide if the window should be destroyed after the close // animation completes function close() { + console.log("Closing " + window) if (destroyOnCloseButton) { destroyOnInvisible = true } - enabled = false; + visible = false; } - onEnabledChanged: { - if (!enabled) { - if (blur) { - blur.visible = true; - } - if (content) { - content.visible = false; - } - } + // + // Enable window visibility transitions + // - opacity = enabled ? 1.0 : 0.0 - // If the dialog is initially invisible, setting opacity doesn't - // trigger making it visible. - if (enabled) { - visible = true; - raise(); + // The target property to animate, usually scale or opacity + property alias fadeTargetProperty: window.opacity + // always start the property at 0 to enable fade in on creation + opacity: 0 + + // Some dialogs should be destroyed when they become + // invisible, so handle that + onVisibleChanged: { + // If someone directly set the visibility to false + // toggle it back on and use the targetVisible flag to transition + // via fading. + if ((!visible && fadeTargetProperty != 0.0) || (visible && fadeTargetProperty == 0.0)) { + var target = visible; + visible = !visible; + fadeTargetProperty = target ? 1.0 : 0.0; + return; + } + if (!visible && destroyOnInvisible) { + console.log("Destroying " + window); + destroy(); + return; } } // The offscreen UI will enable an object, rather than manipulating it's // visibility, so that we can do animations in both directions. Because - // visibility and enabled are boolean flags, they cannot be animated. So when - // enabled is change, we modify a property that can be animated, like scale or - // opacity, and then when the target animation value is reached, we can - // modify the visibility + // visibility is a boolean flags, it cannot be animated. So when + // targetVisible is changed, we modify a property that can be animated, + // like scale or opacity, and then when the target animation value is reached, + // we can modify the visibility // The actual animator - Behavior on opacity { + Behavior on fadeTargetProperty { NumberAnimation { duration: hifi.effects.fadeInDuration easing.type: Easing.OutCubic @@ -151,31 +158,31 @@ FocusScope { } // Once we're transparent, disable the dialog's visibility - onOpacityChanged: { - visible = (opacity != 0.0); - if (opacity == 1.0) { - content.visible = true; - blur.visible = false; - } + onFadeTargetPropertyChanged: { + visible = (fadeTargetProperty != 0.0); } - // Some dialogs should be destroyed when they become - // invisible, so handle that - onVisibleChanged: { - if (!visible && destroyOnInvisible) { - console.log("Destroying " + window); - destroy(); - } - } Keys.onPressed: { switch(event.key) { case Qt.Key_W: - if (event.modifiers == Qt.ControlModifier) { + if (event.modifiers === Qt.ControlModifier) { event.accepted = true - enabled = false + visible = false } break; } } + + + function clamp(value, min, max) { + return Math.min(Math.max(value, min), max); + } + + function clampVector(value, min, max) { + return Qt.vector2d( + clamp(value.x, min.x, max.x), + clamp(value.y, min.y, max.y)) + } + } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4c4786c6a2..f9687cf095 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -395,7 +395,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : QApplication(argc, argv), _dependencyManagerIsSetup(setupEssentials(argc, argv)), _window(new MainWindow(desktop())), - _toolWindow(NULL), _undoStackScriptingInterface(&_undoStack), _frameCount(0), _fps(60.0f), @@ -678,10 +677,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _renderEngine->addTask(make_shared()); _renderEngine->registerScene(_main3DScene); - _toolWindow = new ToolWindow(); - _toolWindow->setWindowFlags((_toolWindow->windowFlags() | Qt::WindowStaysOnTopHint) & ~Qt::WindowMinimizeButtonHint); - _toolWindow->setWindowTitle("Tools"); - _offscreenContext->makeCurrent(); // Tell our entity edit sender about our known jurisdictions @@ -4751,7 +4746,7 @@ void Application::showFriendsWindow() { auto webWindowClass = _window->findChildren(FRIENDS_WINDOW_OBJECT_NAME); if (webWindowClass.empty()) { auto friendsWindow = new WebWindowClass(FRIENDS_WINDOW_TITLE, FRIENDS_WINDOW_URL, FRIENDS_WINDOW_WIDTH, - FRIENDS_WINDOW_HEIGHT, false); + FRIENDS_WINDOW_HEIGHT); friendsWindow->setParent(_window); friendsWindow->setObjectName(FRIENDS_WINDOW_OBJECT_NAME); connect(friendsWindow, &WebWindowClass::closed, &WebWindowClass::deleteLater); diff --git a/interface/src/Application.h b/interface/src/Application.h index d50fef327b..24e853eabb 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -62,7 +62,6 @@ #include "ui/OverlayConductor.h" #include "ui/overlays/Overlays.h" #include "ui/SnapshotShareDialog.h" -#include "ui/ToolWindow.h" #include "UndoStackScriptingInterface.h" class OffscreenGLCanvas; @@ -164,8 +163,6 @@ public: NodeToOctreeSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; } - ToolWindow* getToolWindow() { return _toolWindow ; } - virtual controller::ScriptingInterface* getControllerScriptingInterface() { return _controllerScriptingInterface; } virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine); @@ -400,8 +397,6 @@ private: MainWindow* _window; - ToolWindow* _toolWindow; - QUndoStack _undoStack; UndoStackScriptingInterface _undoStackScriptingInterface; diff --git a/interface/src/scripting/WebWindowClass.cpp b/interface/src/scripting/WebWindowClass.cpp index a5ce817f87..18beee4bbf 100644 --- a/interface/src/scripting/WebWindowClass.cpp +++ b/interface/src/scripting/WebWindowClass.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + #include #include #include @@ -35,48 +36,25 @@ void ScriptEventBridge::emitScriptEvent(const QString& data) { emit scriptEventReceived(data); } -WebWindowClass::WebWindowClass(const QString& title, const QString& url, int width, int height, bool isToolWindow) - : QObject(NULL), - _eventBridge(new ScriptEventBridge(this)), - _isToolWindow(isToolWindow) { +WebWindowClass::WebWindowClass(const QString& title, const QString& url, int width, int height) + : QObject(NULL), _eventBridge(new ScriptEventBridge(this)) { + auto dialogWidget = new QDialog(qApp->getWindow(), Qt::Window); + dialogWidget->setWindowTitle(title); + dialogWidget->resize(width, height); + dialogWidget->installEventFilter(this); + connect(dialogWidget, &QDialog::finished, this, &WebWindowClass::hasClosed); - if (_isToolWindow) { - ToolWindow* toolWindow = qApp->getToolWindow(); + auto layout = new QVBoxLayout(dialogWidget); + layout->setContentsMargins(0, 0, 0, 0); + dialogWidget->setLayout(layout); - auto dockWidget = new QDockWidget(title, toolWindow); - dockWidget->setFeatures(QDockWidget::DockWidgetMovable); - connect(dockWidget, &QDockWidget::visibilityChanged, this, &WebWindowClass::visibilityChanged); + _webView = new QWebView(dialogWidget); - _webView = new QWebView(dockWidget); - addEventBridgeToWindowObject(); + layout->addWidget(_webView); - dockWidget->setWidget(_webView); + addEventBridgeToWindowObject(); - auto titleWidget = new QWidget(dockWidget); - dockWidget->setTitleBarWidget(titleWidget); - - toolWindow->addDockWidget(Qt::TopDockWidgetArea, dockWidget, Qt::Horizontal); - - _windowWidget = dockWidget; - } else { - auto dialogWidget = new QDialog(qApp->getWindow(), Qt::Window); - dialogWidget->setWindowTitle(title); - dialogWidget->resize(width, height); - dialogWidget->installEventFilter(this); - connect(dialogWidget, &QDialog::finished, this, &WebWindowClass::hasClosed); - - auto layout = new QVBoxLayout(dialogWidget); - layout->setContentsMargins(0, 0, 0, 0); - dialogWidget->setLayout(layout); - - _webView = new QWebView(dialogWidget); - - layout->addWidget(_webView); - - addEventBridgeToWindowObject(); - - _windowWidget = dialogWidget; - } + _windowWidget = dialogWidget; auto style = QStyleFactory::create("fusion"); if (style) { @@ -121,13 +99,8 @@ void WebWindowClass::addEventBridgeToWindowObject() { void WebWindowClass::setVisible(bool visible) { if (visible) { - if (_isToolWindow) { - QMetaObject::invokeMethod( - qApp->getToolWindow(), "setVisible", Qt::AutoConnection, Q_ARG(bool, visible)); - } else { - QMetaObject::invokeMethod(_windowWidget, "showNormal", Qt::AutoConnection); - QMetaObject::invokeMethod(_windowWidget, "raise", Qt::AutoConnection); - } + QMetaObject::invokeMethod(_windowWidget, "showNormal", Qt::AutoConnection); + QMetaObject::invokeMethod(_windowWidget, "raise", Qt::AutoConnection); } QMetaObject::invokeMethod(_windowWidget, "setVisible", Qt::AutoConnection, Q_ARG(bool, visible)); } @@ -182,13 +155,18 @@ void WebWindowClass::raise() { QScriptValue WebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) { WebWindowClass* retVal; QString file = context->argument(0).toString(); + if (context->argument(4).toBool()) { + qWarning() << "ToolWindow views with WebWindow are no longer supported. Use OverlayWebWindow instead"; + return QScriptValue(); + } else { + qWarning() << "WebWindow views are deprecated. Use OverlayWebWindow instead"; + } QMetaObject::invokeMethod(DependencyManager::get().data(), "doCreateWebWindow", Qt::BlockingQueuedConnection, Q_RETURN_ARG(WebWindowClass*, retVal), Q_ARG(const QString&, file), Q_ARG(QString, context->argument(1).toString()), Q_ARG(int, context->argument(2).toInteger()), - Q_ARG(int, context->argument(3).toInteger()), - Q_ARG(bool, context->argument(4).toBool())); + Q_ARG(int, context->argument(3).toInteger())); connect(engine, &QScriptEngine::destroyed, retVal, &WebWindowClass::deleteLater); diff --git a/interface/src/scripting/WebWindowClass.h b/interface/src/scripting/WebWindowClass.h index cc6506b059..8859eb5b37 100644 --- a/interface/src/scripting/WebWindowClass.h +++ b/interface/src/scripting/WebWindowClass.h @@ -39,7 +39,7 @@ class WebWindowClass : public QObject { Q_PROPERTY(QSizeF size READ getSize WRITE setSize); public: - WebWindowClass(const QString& title, const QString& url, int width, int height, bool isToolWindow = false); + WebWindowClass(const QString& title, const QString& url, int width, int height); ~WebWindowClass(); static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); @@ -75,7 +75,6 @@ private: QWidget* _windowWidget; QWebView* _webView; ScriptEventBridge* _eventBridge; - bool _isToolWindow; }; #endif diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index fe84f36158..03a4993d92 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -23,6 +23,7 @@ #include "Menu.h" #include "OffscreenUi.h" #include "ui/ModelsBrowser.h" +#include "WebWindowClass.h" #include "WindowScriptingInterface.h" @@ -37,8 +38,8 @@ WindowScriptingInterface::WindowScriptingInterface() : connect(qApp, &Application::domainConnectionRefused, this, &WindowScriptingInterface::domainConnectionRefused); } -WebWindowClass* WindowScriptingInterface::doCreateWebWindow(const QString& title, const QString& url, int width, int height, bool isToolWindow) { - return new WebWindowClass(title, url, width, height, isToolWindow); +WebWindowClass* WindowScriptingInterface::doCreateWebWindow(const QString& title, const QString& url, int width, int height) { + return new WebWindowClass(title, url, width, height); } QScriptValue WindowScriptingInterface::hasFocus() { diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 1395639cd0..4b287a24e9 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -19,7 +19,7 @@ #include #include -#include "WebWindowClass.h" +class WebWindowClass; class WindowScriptingInterface : public QObject, public Dependency { Q_OBJECT @@ -82,8 +82,8 @@ private slots: void nonBlockingFormAccepted() { _nonBlockingFormActive = false; _formResult = QDialog::Accepted; emit nonBlockingFormClosed(); } void nonBlockingFormRejected() { _nonBlockingFormActive = false; _formResult = QDialog::Rejected; emit nonBlockingFormClosed(); } - WebWindowClass* doCreateWebWindow(const QString& title, const QString& url, int width, int height, bool isToolWindow); - + WebWindowClass* doCreateWebWindow(const QString& title, const QString& url, int width, int height); + private: QString jsRegExp2QtRegExp(QString string); QDialog* createForm(const QString& title, QScriptValue form); diff --git a/interface/src/ui/DialogsManager.cpp b/interface/src/ui/DialogsManager.cpp index 155d41c575..85b8ce0273 100644 --- a/interface/src/ui/DialogsManager.cpp +++ b/interface/src/ui/DialogsManager.cpp @@ -148,8 +148,7 @@ void DialogsManager::lodTools() { } void DialogsManager::toggleToolWindow() { - QMainWindow* toolWindow = qApp->getToolWindow(); - toolWindow->setVisible(!toolWindow->isVisible()); + DependencyManager::get()->toggleToolWindow(); } void DialogsManager::hmdTools(bool showTools) { diff --git a/interface/src/ui/HMDToolsDialog.cpp b/interface/src/ui/HMDToolsDialog.cpp index f9fc444d4b..a596403948 100644 --- a/interface/src/ui/HMDToolsDialog.cpp +++ b/interface/src/ui/HMDToolsDialog.cpp @@ -79,9 +79,6 @@ HMDToolsDialog::HMDToolsDialog(QWidget* parent) : // what screens we're allowed on watchWindow(windowHandle()); auto dialogsManager = DependencyManager::get(); - if (qApp->getToolWindow()) { - watchWindow(qApp->getToolWindow()->windowHandle()); - } if (dialogsManager->getBandwidthDialog()) { watchWindow(dialogsManager->getBandwidthDialog()->windowHandle()); } diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index b5e24fef1e..5e2322b5c4 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -28,6 +28,7 @@ #include "Snapshot.h" #include "UserActivityLogger.h" #include "UIUtil.h" +#include "scripting/WebWindowClass.h" const int PREFERENCES_HEIGHT_PADDING = 20; @@ -135,7 +136,7 @@ void PreferencesDialog::openFullAvatarModelBrowser() { const auto WIDTH = 900; const auto HEIGHT = 700; if (!_marketplaceWindow) { - _marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false); + _marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT); } _marketplaceWindow->setVisible(true); diff --git a/interface/src/ui/PreferencesDialog.h b/interface/src/ui/PreferencesDialog.h index a6c27dee08..77c203b57f 100644 --- a/interface/src/ui/PreferencesDialog.h +++ b/interface/src/ui/PreferencesDialog.h @@ -17,7 +17,7 @@ #include #include -#include "scripting/WebWindowClass.h" +class WebWindowClass; class PreferencesDialog : public QDialog { Q_OBJECT @@ -41,7 +41,7 @@ private: QString _displayNameString; - WebWindowClass* _marketplaceWindow = NULL; + WebWindowClass* _marketplaceWindow { nullptr }; private slots: void accept(); diff --git a/interface/src/ui/ToolWindow.cpp b/interface/src/ui/ToolWindow.cpp deleted file mode 100644 index aab64f9c7e..0000000000 --- a/interface/src/ui/ToolWindow.cpp +++ /dev/null @@ -1,145 +0,0 @@ -// -// ToolWindow.cpp -// interface/src/ui -// -// Created by Ryan Huffman on 11/13/14. -// 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 "Application.h" -#include "MainWindow.h" -#include "ToolWindow.h" -#include "UIUtil.h" - -const int DEFAULT_WIDTH = 300; - -ToolWindow::ToolWindow(QWidget* parent) : - QMainWindow(parent), - _selfHidden(false), - _hasShown(false), - _lastGeometry() { - - setTabPosition(Qt::TopDockWidgetArea, QTabWidget::TabPosition::North); - -# ifndef Q_OS_LINUX - setDockOptions(QMainWindow::ForceTabbedDocks); -# endif - qApp->installEventFilter(this); -} - -bool ToolWindow::event(QEvent* event) { - QEvent::Type type = event->type(); - if (type == QEvent::Show) { - - if (!_hasShown) { - _hasShown = true; - - QMainWindow* mainWindow = qApp->getWindow(); - QRect mainGeometry = mainWindow->geometry(); - - int titleBarHeight = UIUtil::getWindowTitleBarHeight(this); - int topMargin = titleBarHeight; - - _lastGeometry = QRect(mainGeometry.topLeft().x(), mainGeometry.topLeft().y() + topMargin, - DEFAULT_WIDTH, mainGeometry.height() - topMargin); - } - - setGeometry(_lastGeometry); - - return true; - } else if (type == QEvent::Hide) { - _lastGeometry = geometry(); - return true; - } - - return QMainWindow::event(event); -} - -bool ToolWindow::eventFilter(QObject* sender, QEvent* event) { -# ifndef Q_OS_LINUX - switch (event->type()) { - case QEvent::WindowStateChange: - if (qApp->getWindow()->isMinimized()) { - // If we are already visible, we are self-hiding - _selfHidden = isVisible(); - setVisible(false); - } else { - if (_selfHidden) { - setVisible(true); - } - } - break; - case QEvent::ApplicationDeactivate: - _selfHidden = isVisible(); - setVisible(false); - break; - case QEvent::ApplicationActivate: - if (_selfHidden) { - setVisible(true); - } - break; - default: - break; - } -# endif - return false; -} - -void ToolWindow::onChildVisibilityUpdated(bool visible) { - if (!_selfHidden && visible) { - setVisible(true); - } else { - bool hasVisible = false; - QList dockWidgets = findChildren(); - for (int i = 0; i < dockWidgets.count(); i++) { - if (dockWidgets[i]->isVisible()) { - hasVisible = true; - break; - } - } - // If a child was hidden and we don't have any children still visible, hide ourself. - if (!hasVisible) { - setVisible(false); - } - } -} - -void ToolWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget* dockWidget) { - QList dockWidgets = findChildren(); - - QMainWindow::addDockWidget(area, dockWidget); - - // We want to force tabbing, so retabify all of our widgets. - QDockWidget* lastDockWidget = dockWidget; - - foreach (QDockWidget* nextDockWidget, dockWidgets) { - tabifyDockWidget(lastDockWidget, nextDockWidget); - lastDockWidget = nextDockWidget; - } - - connect(dockWidget, &QDockWidget::visibilityChanged, this, &ToolWindow::onChildVisibilityUpdated); -} - -void ToolWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget* dockWidget, Qt::Orientation orientation) { - QList dockWidgets = findChildren(); - - QMainWindow::addDockWidget(area, dockWidget, orientation); - - QDockWidget* lastDockWidget = dockWidget; - - foreach(QDockWidget* nextDockWidget, dockWidgets) { - tabifyDockWidget(lastDockWidget, nextDockWidget); - lastDockWidget = nextDockWidget; - } - - connect(dockWidget, &QDockWidget::visibilityChanged, this, &ToolWindow::onChildVisibilityUpdated); -} - -void ToolWindow::removeDockWidget(QDockWidget* dockWidget) { - QMainWindow::removeDockWidget(dockWidget); - - disconnect(dockWidget, &QDockWidget::visibilityChanged, this, &ToolWindow::onChildVisibilityUpdated); -} diff --git a/interface/src/ui/ToolWindow.h b/interface/src/ui/ToolWindow.h deleted file mode 100644 index 03ae85a418..0000000000 --- a/interface/src/ui/ToolWindow.h +++ /dev/null @@ -1,44 +0,0 @@ -// -// ToolWindow.h -// interface/src/ui -// -// Created by Ryan Huffman on 11/13/14. -// 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_ToolWindow_h -#define hifi_ToolWindow_h - -#include -#include -#include -#include -#include - -class ToolWindow : public QMainWindow { - Q_OBJECT -public: - ToolWindow(QWidget* parent = NULL); - - virtual bool event(QEvent* event); - virtual void addDockWidget(Qt::DockWidgetArea area, QDockWidget* dockWidget); - virtual void addDockWidget(Qt::DockWidgetArea area, QDockWidget* dockWidget, Qt::Orientation orientation); - virtual void removeDockWidget(QDockWidget* dockWidget); - - virtual bool eventFilter(QObject* sender, QEvent* event); - -public slots: - void onChildVisibilityUpdated(bool visible); - - -private: - // Indicates whether this window was hidden by itself (because the main window lost focus). - bool _selfHidden; - bool _hasShown; - QRect _lastGeometry; -}; - -#endif // hifi_ToolWindow_h diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index d9e8579d58..32cb1131f2 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -340,12 +340,25 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) { _qmlComponent = new QQmlComponent(_qmlEngine); } -void OffscreenQmlSurface::resize(const QSize& newSize) { +void OffscreenQmlSurface::resize(const QSize& newSize_) { if (!_renderer || !_renderer->_quickWindow) { return; } + const float MAX_OFFSCREEN_DIMENSION = 4096; + QSize newSize = newSize_; + + if (newSize.width() > MAX_OFFSCREEN_DIMENSION || newSize.height() > MAX_OFFSCREEN_DIMENSION) { + float scale = std::min( + ((float)newSize.width() / MAX_OFFSCREEN_DIMENSION), + ((float)newSize.height() / MAX_OFFSCREEN_DIMENSION)); + newSize = QSize( + std::max(static_cast(scale * newSize.width()), 10), + std::max(static_cast(scale * newSize.height()), 10)); + } + + QSize currentSize = _renderer->_quickWindow->geometry().size(); if (newSize == currentSize) { diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 489fd87112..7188d49846 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -21,10 +21,6 @@ #include "MessageDialog.h" // Needs to match the constants in resources/qml/Global.js -static const QString OFFSCREEN_ROOT_OBJECT_NAME = "desktopRoot"; -static const QString OFFSCREEN_WINDOW_OBJECT_NAME = "topLevelWindow"; -static QQuickItem* _desktop { nullptr }; - class OffscreenFlags : public QObject { Q_OBJECT Q_PROPERTY(bool navigationFocused READ isNavigationFocused WRITE setNavigationFocused NOTIFY navigationFocusedChanged) @@ -252,6 +248,48 @@ void OffscreenUi::createDesktop() { _desktop = dynamic_cast(load("Root.qml")); Q_ASSERT(_desktop); getRootContext()->setContextProperty("Desktop", _desktop); + _toolWindow = _desktop->findChild("ToolWindow"); } +void OffscreenUi::toggleToolWindow() { + _toolWindow->setEnabled(!_toolWindow->isEnabled()); +} + +QQuickItem* OffscreenUi::getDesktop() { + return _desktop; +} + +QQuickItem* OffscreenUi::getToolWindow() { + return _toolWindow; +} + +Q_DECLARE_METATYPE(std::function); +static auto VoidLambdaType = qRegisterMetaType>(); +Q_DECLARE_METATYPE(std::function); +static auto VariantLambdaType = qRegisterMetaType>(); + + +void OffscreenUi::executeOnUiThread(std::function function) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "executeOnUiThread", Qt::QueuedConnection, + Q_ARG(std::function, function)); + return; + } + + function(); +} + +QVariant OffscreenUi::returnFromUiThread(std::function function) { + if (QThread::currentThread() != thread()) { + QVariant result; + QMetaObject::invokeMethod(this, "returnFromUiThread", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QVariant, result), + Q_ARG(std::function, function)); + return result; + } + + return function(); +} + + #include "OffscreenUi.moc" diff --git a/libraries/ui/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h index 15d2871460..4add90be75 100644 --- a/libraries/ui/src/OffscreenUi.h +++ b/libraries/ui/src/OffscreenUi.h @@ -12,6 +12,7 @@ #ifndef hifi_OffscreenUi_h #define hifi_OffscreenUi_h +#include #include #include @@ -33,6 +34,12 @@ public: bool navigationFocused(); void setNavigationFocused(bool focused); + QQuickItem* getDesktop(); + QQuickItem* getToolWindow(); + + Q_INVOKABLE void executeOnUiThread(std::function function); + Q_INVOKABLE QVariant returnFromUiThread(std::function function); + // Messagebox replacement functions using ButtonCallback = std::function; static ButtonCallback NO_OP_CALLBACK; @@ -70,6 +77,11 @@ public: QMessageBox::StandardButtons buttons = QMessageBox::Ok); static void error(const QString& text); // Interim dialog in new style + + void toggleToolWindow(); +private: + QQuickItem* _desktop { nullptr }; + QQuickItem* _toolWindow { nullptr }; }; #endif diff --git a/libraries/ui/src/QmlWebWindowClass.cpp b/libraries/ui/src/QmlWebWindowClass.cpp index 940ba121f3..8bf36b111f 100644 --- a/libraries/ui/src/QmlWebWindowClass.cpp +++ b/libraries/ui/src/QmlWebWindowClass.cpp @@ -31,25 +31,15 @@ static const char* const URL_PROPERTY = "source"; // Method called by Qt scripts to create a new web window in the overlay QScriptValue QmlWebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) { return QmlWindowClass::internalConstructor("QmlWebWindow.qml", context, engine, - [&](QQmlContext* context, QObject* object) { return new QmlWebWindowClass(object); }); + [&](QObject* object) { return new QmlWebWindowClass(object); }); } QmlWebWindowClass::QmlWebWindowClass(QObject* qmlWindow) : QmlWindowClass(qmlWindow) { - QObject::connect(_qmlWindow, SIGNAL(navigating(QString)), this, SLOT(handleNavigation(QString))); } -void QmlWebWindowClass::handleNavigation(const QString& url) { - bool handled = false; - static auto handler = dynamic_cast(qApp); - if (handler) { - if (handler->canAcceptURL(url)) { - handled = handler->acceptURL(url); - } - } - if (handled) { - QMetaObject::invokeMethod(_qmlWindow, "stop", Qt::AutoConnection); - } +// FIXME remove. +void QmlWebWindowClass::handleNavigation(const QString& url) { } QString QmlWebWindowClass::getURL() const { diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index 0d5fc7fbf6..26561a43b6 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -35,6 +35,7 @@ static const char* const TITLE_PROPERTY = "title"; static const char* const WIDTH_PROPERTY = "width"; static const char* const HEIGHT_PROPERTY = "height"; static const char* const VISIBILE_PROPERTY = "visible"; +static const char* const TOOLWINDOW_PROPERTY = "toolWindow"; void QmlScriptEventBridge::emitWebEvent(const QString& data) { QMetaObject::invokeMethod(this, "webEventReceived", Qt::QueuedConnection, Q_ARG(QString, data)); @@ -86,13 +87,14 @@ void QmlWindowClass::setupServer() { QScriptValue QmlWindowClass::internalConstructor(const QString& qmlSource, QScriptContext* context, QScriptEngine* engine, - std::function function) + std::function builder) { const auto argumentCount = context->argumentCount(); QString url; QString title; int width = -1, height = -1; bool visible = true; + bool toolWindow = false; if (argumentCount > 1) { if (!context->argument(0).isUndefined()) { @@ -107,6 +109,9 @@ QScriptValue QmlWindowClass::internalConstructor(const QString& qmlSource, if (context->argument(3).isNumber()) { height = context->argument(3).toInt32(); } + if (context->argument(4).isBool()) { + toolWindow = context->argument(4).toBool(); + } } else { auto argumentObject = context->argument(0); qDebug() << argumentObject.toString(); @@ -125,6 +130,9 @@ QScriptValue QmlWindowClass::internalConstructor(const QString& qmlSource, if (argumentObject.property(VISIBILE_PROPERTY).isBool()) { visible = argumentObject.property(VISIBILE_PROPERTY).toBool(); } + if (argumentObject.property(TOOLWINDOW_PROPERTY).isBool()) { + toolWindow = argumentObject.property(TOOLWINDOW_PROPERTY).toBool(); + } } if (!url.startsWith("http") && !url.startsWith("file://") && !url.startsWith("about:")) { @@ -137,17 +145,44 @@ QScriptValue QmlWindowClass::internalConstructor(const QString& qmlSource, } QmlWindowClass* retVal{ nullptr }; - auto offscreenUi = DependencyManager::get(); - qDebug() << "Clearing component cache"; - offscreenUi->getRootContext()->engine()->clearComponentCache(); - // Build the event bridge and wrapper on the main thread - QMetaObject::invokeMethod(offscreenUi.data(), "load", Qt::BlockingQueuedConnection, - Q_ARG(const QString&, qmlSource), - Q_ARG(std::function, [&](QQmlContext* context, QObject* object) { + if (toolWindow) { + auto toolWindow = offscreenUi->getToolWindow(); + QVariantMap properties; + properties.insert(TITLE_PROPERTY, title); + properties.insert(SOURCE_PROPERTY, url); + if (width != -1 && height != -1) { + properties.insert(WIDTH_PROPERTY, width); + properties.insert(HEIGHT_PROPERTY, height); + } + + // Build the event bridge and wrapper on the main thread + QVariant newTabVar; + bool invokeResult = QMetaObject::invokeMethod(toolWindow, "addWebTab", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QVariant, newTabVar), + Q_ARG(QVariant, QVariant::fromValue(properties))); + + QQuickItem* newTab = qvariant_cast(newTabVar); + if (!invokeResult || !newTab) { + return QScriptValue(); + } + + offscreenUi->returnFromUiThread([&] { setupServer(); - retVal = function(context, object); + retVal = builder(newTab); + retVal->_toolWindow = true; + offscreenUi->getRootContext()->engine()->setObjectOwnership(retVal->_qmlWindow, QQmlEngine::CppOwnership); + registerObject(url.toLower(), retVal); + return QVariant(); + }); + } else { + // Build the event bridge and wrapper on the main thread + QMetaObject::invokeMethod(offscreenUi.data(), "load", Qt::BlockingQueuedConnection, + Q_ARG(const QString&, qmlSource), + Q_ARG(std::function, [&](QQmlContext* context, QObject* object) { + setupServer(); + retVal = builder(object); context->engine()->setObjectOwnership(retVal->_qmlWindow, QQmlEngine::CppOwnership); registerObject(url.toLower(), retVal); if (!title.isEmpty()) { @@ -158,9 +193,12 @@ QScriptValue QmlWindowClass::internalConstructor(const QString& qmlSource, } object->setProperty(SOURCE_PROPERTY, url); if (visible) { - object->setProperty("enabled", true); + object->setProperty("visible", true); } })); + } + + retVal->_source = url; connect(engine, &QScriptEngine::destroyed, retVal, &QmlWindowClass::deleteLater); return engine->newQObject(retVal); } @@ -168,7 +206,7 @@ QScriptValue QmlWindowClass::internalConstructor(const QString& qmlSource, // Method called by Qt scripts to create a new web window in the overlay QScriptValue QmlWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) { - return internalConstructor("QmlWindow.qml", context, engine, [&](QQmlContext* context, QObject* object){ + return internalConstructor("QmlWindow.qml", context, engine, [&](QObject* object){ return new QmlWindowClass(object); }); } @@ -181,6 +219,21 @@ QmlWindowClass::QmlWindowClass(QObject* qmlWindow) Q_ASSERT(dynamic_cast(_qmlWindow)); } +QmlWindowClass::~QmlWindowClass() { + if (_qmlWindow) { + if (_toolWindow) { + auto offscreenUi = DependencyManager::get(); + auto toolWindow = offscreenUi->getToolWindow(); + auto invokeResult = QMetaObject::invokeMethod(toolWindow, "removeTabForUrl", Qt::QueuedConnection, + Q_ARG(QVariant, _source)); + Q_ASSERT(invokeResult); + } else { + _qmlWindow->deleteLater(); + } + _qmlWindow = nullptr; + } +} + void QmlWindowClass::registerObject(const QString& name, QObject* object) { webChannel.registerObject(name, object); } @@ -189,74 +242,85 @@ void QmlWindowClass::deregisterObject(QObject* object) { webChannel.deregisterObject(object); } -void QmlWindowClass::setVisible(bool visible) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setVisible", Qt::AutoConnection, Q_ARG(bool, visible)); - return; - } - - auto qmlWindow = asQuickItem(); - if (qmlWindow->isEnabled() != visible) { - qmlWindow->setEnabled(visible); - emit visibilityChanged(visible); - } -} - QQuickItem* QmlWindowClass::asQuickItem() const { + if (_toolWindow) { + return DependencyManager::get()->getToolWindow(); + } return dynamic_cast(_qmlWindow); } -bool QmlWindowClass::isVisible() const { - if (QThread::currentThread() != thread()) { - bool result; - QMetaObject::invokeMethod(const_cast(this), "isVisible", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, result)); - return result; +void QmlWindowClass::setVisible(bool visible) { + // For tool window tabs we special case visiblility as enable / disable of the tab, not the window + // The tool window itself has special logic based on whether any tabs are enabled + if (_toolWindow) { + auto targetTab = dynamic_cast(_qmlWindow); + DependencyManager::get()->executeOnUiThread([=] { + targetTab->setEnabled(visible); + //emit visibilityChanged(visible); + }); + } else { + QQuickItem* targetWindow = asQuickItem(); + DependencyManager::get()->executeOnUiThread([=] { + targetWindow->setVisible(visible); + //emit visibilityChanged(visible); + }); } +} - return asQuickItem()->isEnabled(); +bool QmlWindowClass::isVisible() const { + // The tool window itself has special logic based on whether any tabs are enabled + if (_toolWindow) { + auto targetTab = dynamic_cast(_qmlWindow); + return DependencyManager::get()->returnFromUiThread([&] { + return QVariant::fromValue(targetTab->isEnabled()); + }).toBool(); + } else { + QQuickItem* targetWindow = asQuickItem(); + return DependencyManager::get()->returnFromUiThread([&] { + return QVariant::fromValue(targetWindow->isVisible()); + }).toBool(); + } } glm::vec2 QmlWindowClass::getPosition() const { - if (QThread::currentThread() != thread()) { - glm::vec2 result; - QMetaObject::invokeMethod(const_cast(this), "getPosition", Qt::BlockingQueuedConnection, Q_RETURN_ARG(glm::vec2, result)); - return result; - } - - return glm::vec2(asQuickItem()->x(), asQuickItem()->y()); + QQuickItem* targetWindow = asQuickItem(); + QVariant result = DependencyManager::get()->returnFromUiThread([&]()->QVariant { + return targetWindow->position(); + }); + return toGlm(result.toPointF()); } void QmlWindowClass::setPosition(const glm::vec2& position) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setPosition", Qt::QueuedConnection, Q_ARG(glm::vec2, position)); - return; - } - - asQuickItem()->setPosition(QPointF(position.x, position.y)); + QQuickItem* targetWindow = asQuickItem(); + DependencyManager::get()->executeOnUiThread([=] { + targetWindow->setPosition(QPointF(position.x, position.y)); + }); } void QmlWindowClass::setPosition(int x, int y) { setPosition(glm::vec2(x, y)); } +// FIXME move to GLM helpers +glm::vec2 toGlm(const QSizeF& size) { + return glm::vec2(size.width(), size.height()); +} + glm::vec2 QmlWindowClass::getSize() const { - if (QThread::currentThread() != thread()) { - glm::vec2 result; - QMetaObject::invokeMethod(const_cast(this), "getSize", Qt::BlockingQueuedConnection, Q_RETURN_ARG(glm::vec2, result)); - return result; - } - - return glm::vec2(asQuickItem()->width(), asQuickItem()->height()); + QQuickItem* targetWindow = asQuickItem(); + QVariant result = DependencyManager::get()->returnFromUiThread([&]()->QVariant { + return QSizeF(targetWindow->width(), targetWindow->height()); + }); + return toGlm(result.toSizeF()); } void QmlWindowClass::setSize(const glm::vec2& size) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setSize", Qt::QueuedConnection, Q_ARG(glm::vec2, size)); - } - - asQuickItem()->setSize(QSizeF(size.x, size.y)); + QQuickItem* targetWindow = asQuickItem(); + DependencyManager::get()->executeOnUiThread([=] { + targetWindow->setSize(QSizeF(size.x, size.y)); + }); } void QmlWindowClass::setSize(int width, int height) { @@ -264,27 +328,28 @@ void QmlWindowClass::setSize(int width, int height) { } void QmlWindowClass::setTitle(const QString& title) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setTitle", Qt::QueuedConnection, Q_ARG(QString, title)); - } - - _qmlWindow->setProperty(TITLE_PROPERTY, title); + QQuickItem* targetWindow = asQuickItem(); + DependencyManager::get()->executeOnUiThread([=] { + targetWindow->setProperty(TITLE_PROPERTY, title); + }); } void QmlWindowClass::close() { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "close", Qt::QueuedConnection); - } - _qmlWindow->setProperty("destroyOnInvisible", true); - _qmlWindow->setProperty("visible", false); - _qmlWindow->deleteLater(); + DependencyManager::get()->executeOnUiThread([this] { + if (_qmlWindow) { + _qmlWindow->setProperty("destroyOnInvisible", true); + _qmlWindow->setProperty("visible", false); + _qmlWindow->deleteLater(); + _qmlWindow = nullptr; + } + }); } void QmlWindowClass::hasClosed() { } void QmlWindowClass::raise() { - QMetaObject::invokeMethod(_qmlWindow, "raiseWindow", Qt::QueuedConnection); + QMetaObject::invokeMethod(asQuickItem(), "raiseWindow", Qt::QueuedConnection); } #include "QmlWindowClass.moc" diff --git a/libraries/ui/src/QmlWindowClass.h b/libraries/ui/src/QmlWindowClass.h index 41572b448d..2e848b612d 100644 --- a/libraries/ui/src/QmlWindowClass.h +++ b/libraries/ui/src/QmlWindowClass.h @@ -51,6 +51,7 @@ class QmlWindowClass : public QObject { public: static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); QmlWindowClass(QObject* qmlWindow); + ~QmlWindowClass(); public slots: bool isVisible() const; @@ -84,7 +85,7 @@ protected slots: protected: static QScriptValue internalConstructor(const QString& qmlSource, QScriptContext* context, QScriptEngine* engine, - std::function function); + std::function function); static void setupServer(); static void registerObject(const QString& name, QObject* object); static void deregisterObject(QObject* object); @@ -95,9 +96,10 @@ protected: // FIXME needs to be initialized in the ctor once we have support // for tool window panes in QML - const bool _isToolWindow { false }; + bool _toolWindow { false }; const int _windowId; - QObject* const _qmlWindow; + QObject* _qmlWindow; + QString _source; }; #endif From 9a51a011c56354d0cda8b3d8a871642bcda74c67 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 13 Jan 2016 15:51:22 -0800 Subject: [PATCH 135/215] further tweaks --- unpublishedScripts/hiddenEntityReset.js | 8 ++++---- unpublishedScripts/masterReset.js | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index cd4a05dfce..8f095ba0c5 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -302,12 +302,12 @@ rightRelativePosition: { x: 0.03, y: 0.0, - z: -0.085 + z: -0.065 }, leftRelativePosition: { x: -0.03, y: 0.00, - z: -0.085 + z: -0.065 }, relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0) }, @@ -1163,12 +1163,12 @@ rightRelativePosition: { x: -0.05, y: .06, - z: 0.1 + z: 0.05 }, leftRelativePosition: { x: 0.05, y: 0.06, - z: 0.1 + z: 0.05 }, relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, -90) }, diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 79e14b4c88..e6605c17e0 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -287,12 +287,12 @@ MasterReset = function() { rightRelativePosition: { x: 0.03, y: 0.0, - z: -0.085 + z: -0.065 }, leftRelativePosition: { x: -0.03, y: 0.00, - z: -0.085 + z: -0.065 }, relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0) }, @@ -1149,12 +1149,12 @@ MasterReset = function() { rightRelativePosition: { x: -0.05, y: .06, - z: 0.1 + z: 0.05 }, leftRelativePosition: { x: 0.05, y: 0.06, - z: 0.1 + z: 0.05 }, relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, -90) }, From 3aa1837e072883b0b3c4ec2c1e9f8b9066f10690 Mon Sep 17 00:00:00 2001 From: "U-GAPOS\\andrew" Date: Wed, 13 Jan 2016 16:57:51 -0800 Subject: [PATCH 136/215] disable collisions between arrow and bow (the bow is currently kinematic while held) --- examples/toybox/bow/bow.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/toybox/bow/bow.js b/examples/toybox/bow/bow.js index 44fe33bb31..c04bb7a72c 100644 --- a/examples/toybox/bow/bow.js +++ b/examples/toybox/bow/bow.js @@ -540,6 +540,7 @@ var arrowProperties = { collisionsWillMove: true, ignoreForCollisions: false, + collisionMask: "static,dynamic,otherAvatar", // workaround: not with kinematic --> no collision with bow velocity: releaseVelocity, gravity: ARROW_GRAVITY, lifetime: 10, @@ -612,4 +613,4 @@ }; return new Bow(); -}); \ No newline at end of file +}); From 0126684a9623486e9c07dde56162efaf55a23786 Mon Sep 17 00:00:00 2001 From: "U-GAPOS\\andrew" Date: Wed, 13 Jan 2016 16:58:34 -0800 Subject: [PATCH 137/215] collisionMask shouldn't override ignoreForCollisions --- libraries/entities/src/EntityItem.h | 2 ++ libraries/physics/src/EntityMotionState.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index d526ffec0d..d0b79723d1 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -275,6 +275,7 @@ public: void setIgnoreForCollisions(bool value) { _ignoreForCollisions = value; } uint8_t getCollisionMask() const { return _collisionMask; } + uint8_t getFinalCollisionMask() const { return _ignoreForCollisions ? 0 : _collisionMask; } void setCollisionMask(uint8_t value) { _collisionMask = value; } bool getCollisionsWillMove() const { return _collisionsWillMove; } @@ -446,6 +447,7 @@ protected: bool _visible; bool _ignoreForCollisions; uint8_t _collisionMask { ENTITY_COLLISION_MASK_DEFAULT }; + uint8_t _collisionGroupOverride; bool _collisionsWillMove; bool _locked; QString _userData; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index f75469e820..2c09c3aa55 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -644,7 +644,7 @@ void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& ma mask = PhysicsEngine::getCollisionMask(group); if (_entity) { - uint8_t entityCollisionMask = _entity->getCollisionMask(); + uint8_t entityCollisionMask = _entity->getFinalCollisionMask(); if ((bool)(entityCollisionMask & USER_COLLISION_GROUP_MY_AVATAR) != (bool)(entityCollisionMask & USER_COLLISION_GROUP_OTHER_AVATAR)) { // asymmetric avatar collision mask bits From ee69d8f81704a58d3f35c5a722fb7e976c49b6b9 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 13 Jan 2016 17:44:01 -0800 Subject: [PATCH 138/215] Fix bitsetters for ShapeKey::Builder --- libraries/render/src/render/ShapePipeline.cpp | 4 ++- libraries/render/src/render/ShapePipeline.h | 34 +++++++++---------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index 99424cbf4b..c83f16c456 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -91,7 +91,9 @@ const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Ke auto& batch = args->_batch; // Run the pipeline's BatchSetter on the passed in batch - shapePipeline->batchSetter(*shapePipeline, *batch); + if (shapePipeline->batchSetter) { + shapePipeline->batchSetter(*shapePipeline, *batch); + } // Setup the one pipeline (to rule them all) batch->setPipeline(shapePipeline->pipeline); diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index 3d189f15fa..1a6837efa3 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -83,32 +83,32 @@ public: Filter build() const { return Filter(_flags, _mask); } - Builder& withOpaque() { _flags.reset(TRANSLUCENT); _mask.set(TRANSLUCENT); return (*this); } Builder& withTranslucent() { _flags.set(TRANSLUCENT); _mask.set(TRANSLUCENT); return (*this); } + Builder& withOpaque() { _flags.reset(TRANSLUCENT); _mask.set(TRANSLUCENT); return (*this); } - Builder& withLightmap() { _flags.reset(LIGHTMAP); _mask.set(LIGHTMAP); return (*this); } - Builder& withoutLightmap() { _flags.set(LIGHTMAP); _mask.set(LIGHTMAP); return (*this); } + Builder& withLightmap() { _flags.set(LIGHTMAP); _mask.set(LIGHTMAP); return (*this); } + Builder& withoutLightmap() { _flags.reset(LIGHTMAP); _mask.set(LIGHTMAP); return (*this); } - Builder& withTangents() { _flags.reset(TANGENTS); _mask.set(TANGENTS); return (*this); } - Builder& withoutTangents() { _flags.set(TANGENTS); _mask.set(TANGENTS); return (*this); } + Builder& withTangents() { _flags.set(TANGENTS); _mask.set(TANGENTS); return (*this); } + Builder& withoutTangents() { _flags.reset(TANGENTS); _mask.set(TANGENTS); return (*this); } - Builder& withSpecular() { _flags.reset(SPECULAR); _mask.set(SPECULAR); return (*this); } - Builder& withoutSpecular() { _flags.set(SPECULAR); _mask.set(SPECULAR); return (*this); } + Builder& withSpecular() { _flags.set(SPECULAR); _mask.set(SPECULAR); return (*this); } + Builder& withoutSpecular() { _flags.reset(SPECULAR); _mask.set(SPECULAR); return (*this); } - Builder& withEmissive() { _flags.reset(EMISSIVE); _mask.set(EMISSIVE); return (*this); } - Builder& withoutEmissive() { _flags.set(EMISSIVE); _mask.set(EMISSIVE); return (*this); } + Builder& withEmissive() { _flags.set(EMISSIVE); _mask.set(EMISSIVE); return (*this); } + Builder& withoutEmissive() { _flags.reset(EMISSIVE); _mask.set(EMISSIVE); return (*this); } - Builder& withSkinned() { _flags.reset(SKINNED); _mask.set(SKINNED); return (*this); } - Builder& withoutSkinned() { _flags.set(SKINNED); _mask.set(SKINNED); return (*this); } + Builder& withSkinned() { _flags.set(SKINNED); _mask.set(SKINNED); return (*this); } + Builder& withoutSkinned() { _flags.reset(SKINNED); _mask.set(SKINNED); return (*this); } - Builder& withStereo() { _flags.reset(STEREO); _mask.set(STEREO); return (*this); } - Builder& withoutStereo() { _flags.set(STEREO); _mask.set(STEREO); return (*this); } + Builder& withStereo() { _flags.set(STEREO); _mask.set(STEREO); return (*this); } + Builder& withoutStereo() { _flags.reset(STEREO); _mask.set(STEREO); return (*this); } - Builder& withDepthOnly() { _flags.reset(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); } - Builder& withoutDepthOnly() { _flags.set(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); } + Builder& withDepthOnly() { _flags.set(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); } + Builder& withoutDepthOnly() { _flags.reset(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); } - Builder& withWireframe() { _flags.reset(WIREFRAME); _mask.set(WIREFRAME); return (*this); } - Builder& withoutWireframe() { _flags.set(WIREFRAME); _mask.set(WIREFRAME); return (*this); } + Builder& withWireframe() { _flags.set(WIREFRAME); _mask.set(WIREFRAME); return (*this); } + Builder& withoutWireframe() { _flags.reset(WIREFRAME); _mask.set(WIREFRAME); return (*this); } protected: friend class Filter; From 293882916726ecaca47e811346a9ce84bd5e1766 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 13 Jan 2016 17:48:09 -0800 Subject: [PATCH 139/215] Add shadow items to stats --- interface/resources/qml/Stats.qml | 9 +++++++++ interface/src/ui/Stats.cpp | 4 ++++ interface/src/ui/Stats.h | 8 ++++++++ libraries/shared/src/RenderArgs.h | 5 +++++ 4 files changed, 26 insertions(+) diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index 9954cab063..2155a11d91 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -188,6 +188,7 @@ Item { visible: root.expanded; text: "\tItems Rendered Opaque: " + root.opaqueRendered + " / Translucent: " + root.translucentRendered + + " / Shadow: " + root.shadowRendered + " / Other: " + root.otherRendered; } Text { @@ -198,6 +199,14 @@ Item { " / Out of view: " + root.opaqueOutOfView + " / Too small: " + root.opaqueTooSmall; } + Text { + color: root.fontColor; + font.pixelSize: root.fontSize + visible: root.expanded; + text: "\tShadow considered: " + root.shadowConsidered + + " / Out of view: " + root.shadowOutOfView + + " / Too small: " + root.shadowTooSmall; + } Text { color: root.fontColor; font.pixelSize: root.fontSize diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index b82ab93068..ae9e37b591 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -348,6 +348,10 @@ void Stats::setRenderDetails(const RenderDetails& details) { STAT_UPDATE(opaqueOutOfView, details._opaque._outOfView); STAT_UPDATE(opaqueTooSmall, details._opaque._tooSmall); STAT_UPDATE(opaqueRendered, (int)details._opaque._rendered); + STAT_UPDATE(shadowConsidered, (int)details._shadow._considered); + STAT_UPDATE(shadowOutOfView, details._shadow._outOfView); + STAT_UPDATE(shadowTooSmall, details._shadow._tooSmall); + STAT_UPDATE(shadowRendered, (int)details._shadow._rendered); STAT_UPDATE(translucentConsidered, (int)details._translucent._considered); STAT_UPDATE(translucentOutOfView, details._translucent._outOfView); STAT_UPDATE(translucentTooSmall, details._translucent._tooSmall); diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index 5e948ce0f0..fc01fe7f23 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -64,6 +64,10 @@ class Stats : public QQuickItem { STATS_PROPERTY(int, opaqueOutOfView, 0) STATS_PROPERTY(int, opaqueTooSmall, 0) STATS_PROPERTY(int, opaqueRendered, 0) + STATS_PROPERTY(int, shadowConsidered, 0) + STATS_PROPERTY(int, shadowOutOfView, 0) + STATS_PROPERTY(int, shadowTooSmall, 0) + STATS_PROPERTY(int, shadowRendered, 0) STATS_PROPERTY(int, translucentConsidered, 0) STATS_PROPERTY(int, translucentOutOfView, 0) STATS_PROPERTY(int, translucentTooSmall, 0) @@ -151,6 +155,10 @@ signals: void opaqueOutOfViewChanged(); void opaqueTooSmallChanged(); void opaqueRenderedChanged(); + void shadowConsideredChanged(); + void shadowOutOfViewChanged(); + void shadowTooSmallChanged(); + void shadowRenderedChanged(); void translucentConsideredChanged(); void translucentOutOfViewChanged(); void translucentTooSmallChanged(); diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index 789033b826..e5dfd5f8ea 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -36,6 +36,7 @@ class RenderDetails { public: enum Type { OPAQUE_ITEM, + SHADOW_ITEM, TRANSLUCENT_ITEM, OTHER_ITEM }; @@ -51,6 +52,7 @@ public: int _trianglesRendered = 0; Item _opaque; + Item _shadow; Item _translucent; Item _other; @@ -61,6 +63,9 @@ public: case OPAQUE_ITEM: _item = &_opaque; break; + case SHADOW_ITEM: + _item = &_shadow; + break; case TRANSLUCENT_ITEM: _item = &_translucent; break; From e471dcc90e931b5a5283f5e8663215b123929ad6 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 13 Jan 2016 17:50:34 -0800 Subject: [PATCH 140/215] Fix GLBackend::do_setDepthRangeTransform by swapping hither/yon --- libraries/gpu/src/gpu/GLBackendTransform.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/gpu/src/gpu/GLBackendTransform.cpp b/libraries/gpu/src/gpu/GLBackendTransform.cpp index 686b52296f..9bfd258833 100755 --- a/libraries/gpu/src/gpu/GLBackendTransform.cpp +++ b/libraries/gpu/src/gpu/GLBackendTransform.cpp @@ -51,7 +51,7 @@ void GLBackend::do_setViewportTransform(Batch& batch, size_t paramOffset) { void GLBackend::do_setDepthRangeTransform(Batch& batch, size_t paramOffset) { - Vec2 depthRange(batch._params[paramOffset + 0]._float, batch._params[paramOffset + 1]._float); + Vec2 depthRange(batch._params[paramOffset + 1]._float, batch._params[paramOffset + 0]._float); if ((depthRange.x != _transform._depthRange.x) || (depthRange.y != _transform._depthRange.y)) { _transform._depthRange = depthRange; From 70cc7d87e474baf0f7c8edc42e20a93cf4f03294 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 13 Jan 2016 17:52:02 -0800 Subject: [PATCH 141/215] Expose global light through DeferredLighting singleton --- libraries/render-utils/src/DeferredLightingEffect.cpp | 4 ++++ libraries/render-utils/src/DeferredLightingEffect.h | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 7c8aa393d4..a5fce0b377 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -541,6 +541,10 @@ void DeferredLightingEffect::setGlobalLight(const glm::vec3& direction, const gl light->setAmbientIntensity(ambientIntensity); } +model::LightPointer DeferredLightingEffect::getGlobalLight() { + return _allocatedLights[_globalLights.front()]; +} + void DeferredLightingEffect::setGlobalSkybox(const model::SkyboxPointer& skybox) { _skybox = skybox; } diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index cb746153a1..e75961e11a 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -48,9 +48,10 @@ public: void setAmbientLightMode(int preset); void setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity, float ambientIntensity); void setGlobalAtmosphere(const model::AtmospherePointer& atmosphere) { _atmosphere = atmosphere; } - void setGlobalSkybox(const model::SkyboxPointer& skybox); + model::LightPointer getGlobalLight(); + private: DeferredLightingEffect() = default; From 5c9c34377eb8bfa39e65dcb46cd24f5ca660ca70 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 13 Jan 2016 17:53:15 -0800 Subject: [PATCH 142/215] Move GL context sync to render Engine (from Task) --- libraries/render-utils/src/RenderDeferredTask.cpp | 2 -- libraries/render/src/render/Engine.cpp | 6 +++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index b9dfa3e3ec..37126e6558 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -186,8 +186,6 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend setToneMappingExposure(renderContext->getTone().exposure); setToneMappingToneCurve(renderContext->getTone().toneCurve); - renderContext->getArgs()->_context->syncCache(); - for (auto job : _jobs) { job.run(sceneContext, renderContext); } diff --git a/libraries/render/src/render/Engine.cpp b/libraries/render/src/render/Engine.cpp index aa5816475a..06cfd2e78b 100644 --- a/libraries/render/src/render/Engine.cpp +++ b/libraries/render/src/render/Engine.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "Engine.h" using namespace render; @@ -34,7 +36,9 @@ void Engine::addTask(const TaskPointer& task) { } void Engine::run() { - // TODO: Tasks will need to be specified such that their data can feed into each other + // Sync GPU state before beginning to render + _renderContext->getArgs()->_context->syncCache(); + for (auto task : _tasks) { task->run(_sceneContext, _renderContext); } From 75b3523c3391e05c18caf8dbee347d30822cbdcf Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 13 Jan 2016 17:57:51 -0800 Subject: [PATCH 143/215] Simplify grab animation logic Moved all animation control out of the handControllerGrab.js script and back into squeezeHands.js Deleted old hydra/squeezeHands.js to avoid confusion. Added new sqeezeHands.js script to the default scripts. --- examples/controllers/handControllerGrab.js | 98 ------ examples/controllers/hydra/squeezeHands.js | 76 ----- examples/controllers/squeezeHands.js | 108 ++++--- examples/defaultScripts.js | 1 + .../defaultAvatar_full/avatar-animation.json | 280 ++++-------------- 5 files changed, 116 insertions(+), 447 deletions(-) delete mode 100644 examples/controllers/hydra/squeezeHands.js diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index be5fdd7edb..6feb2fb672 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -156,13 +156,6 @@ var STATE_CONTINUE_EQUIP = 14; var STATE_WAITING_FOR_BUMPER_RELEASE = 15; var STATE_EQUIP_SPRING = 16; -// Used by the HandAnimaitonBuddy to play hand animations -var IDLE_HAND_STATES = [STATE_OFF, STATE_RELEASE]; -var OPEN_HAND_STATES = [STATE_SEARCHING, STATE_EQUIP_SEARCHING]; -var POINT_HAND_STATES = [STATE_NEAR_TRIGGER, STATE_CONTINUE_NEAR_TRIGGER, STATE_FAR_TRIGGER, STATE_CONTINUE_FAR_TRIGGER]; -var FAR_GRASP_HAND_STATES = [STATE_DISTANCE_HOLDING, STATE_CONTINUE_DISTANCE_HOLDING]; -// otherwise grasp - // collision masks are specified by comma-separated list of group names // the possible list of names is: static, dynamic, kinematic, myAvatar, otherAvatar var COLLISION_MASK_WHILE_GRABBED = "dynamic,otherAvatar"; @@ -274,94 +267,6 @@ function getSpatialOffsetRotation(hand, spatialKey) { return rotation; } -var HAND_IDLE_RAMP_ON_RATE = 0.1; -var HAND_IDLE_RAMP_OFF_RATE = 0.02; - -// ctor -function HandAnimationBuddy(handController) { - - this.handController = handController; - this.hand = handController.hand; - this.handIdleAlpha = 0; - - var handPrefix = (this.hand === RIGHT_HAND) ? "right" : "left"; - this.animVarKeys = { - idle: handPrefix + "HandIdle", - overlayAlpha: handPrefix + "HandOverlayAlpha", - open: handPrefix + "HandOpen", - point: handPrefix + "HandPoint", - farGrasp: handPrefix + "HandFarGrasp", - grasp: handPrefix + "HandGrasp" - }; - - // hook up anim var handler - var self = this; - this.animHandlerId = MyAvatar.addAnimationStateHandler(function (props) { - return self.animStateHandler(props); - }, []); -} - -HandAnimationBuddy.prototype.animStateHandler = function (props) { - var foundState = false; - var result = {}; - - var state = this.handController.state; - var keys = this.animVarKeys; - - // idle check & process - if (IDLE_HAND_STATES.indexOf(state) != -1) { - // ramp down handIdleAlpha - this.handIdleAlpha = Math.max(0, this.handIdleAlpha - HAND_IDLE_RAMP_OFF_RATE); - result[keys.idle] = true; - foundState = true; - } else { - // ramp up handIdleAlpha - this.handIdleAlpha = Math.min(1, this.handIdleAlpha + HAND_IDLE_RAMP_ON_RATE); - result[keys.idle] = false; - } - result[keys.overlayAlpha] = this.handIdleAlpha; - - // open check - if (OPEN_HAND_STATES.indexOf(state) != -1) { - result[keys.open] = true; - foundState = true; - } else { - result[keys.open] = false; - } - - // point check - if (POINT_HAND_STATES.indexOf(state) != -1) { - result[keys.point] = true; - foundState = true; - } else { - result[keys.point] = false; - } - - // far grasp check - if (FAR_GRASP_HAND_STATES.indexOf(state) != -1) { - result[keys.farGrasp] = true; - foundState = true; - } else { - result[keys.farGrasp] = false; - } - - // grasp check - if (!foundState) { - result[keys.grasp] = true; - } else { - result[keys.grasp] = false; - } - - return result; -}; - -HandAnimationBuddy.prototype.cleanup = function () { - if (this.animHandlerId) { - MyAvatar.removeAnimationStateHandler(this.animHandlerId); - this.animHandlerId = undefined; - } -}; - function MyController(hand) { this.hand = hand; if (this.hand === RIGHT_HAND) { @@ -402,8 +307,6 @@ function MyController(hand) { this.offsetPosition = Vec3.ZERO; this.offsetRotation = Quat.IDENTITY; - this.handAnimationBuddy = new HandAnimationBuddy(this); - var _this = this; this.update = function() { @@ -1822,7 +1725,6 @@ function MyController(hand) { Entities.deleteEntity(this.particleBeam); Entities.deleteEntity(this.spotLight); Entities.deleteEntity(this.pointLight); - this.handAnimationBuddy.cleanup(); }; this.activateEntity = function(entityID, grabbedProperties) { diff --git a/examples/controllers/hydra/squeezeHands.js b/examples/controllers/hydra/squeezeHands.js deleted file mode 100644 index 00ba4800f4..0000000000 --- a/examples/controllers/hydra/squeezeHands.js +++ /dev/null @@ -1,76 +0,0 @@ -// -// squeezeHands.js -// examples -// -// Created by Philip Rosedale on June 4, 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 -// - -HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; - -var rightHandAnimation = HIFI_PUBLIC_BUCKET + "animations/RightHandAnimPhilip.fbx"; -var leftHandAnimation = HIFI_PUBLIC_BUCKET + "animations/LeftHandAnimPhilip.fbx"; - -var LEFT = 0; -var RIGHT = 1; - -var lastLeftFrame = 0; -var lastRightFrame = 0; - -var leftDirection = true; -var rightDirection = true; - -var LAST_FRAME = 15.0; // What is the number of the last frame we want to use in the animation? -var SMOOTH_FACTOR = 0.0; -var MAX_FRAMES = 30.0; - -Script.update.connect(function(deltaTime) { - var leftTriggerValue = Controller.getTriggerValue(LEFT); - var rightTriggerValue = Controller.getTriggerValue(RIGHT); - - var leftFrame, rightFrame; - - // Average last few trigger frames together for a bit of smoothing - leftFrame = (leftTriggerValue * LAST_FRAME) * (1.0 - SMOOTH_FACTOR) + lastLeftFrame * SMOOTH_FACTOR; - rightFrame = (rightTriggerValue * LAST_FRAME) * (1.0 - SMOOTH_FACTOR) + lastRightFrame * SMOOTH_FACTOR; - - if (!leftDirection) { - leftFrame = MAX_FRAMES - leftFrame; - } - if (!rightDirection) { - rightFrame = MAX_FRAMES - rightFrame; - } - - if ((leftTriggerValue == 1.0) && (leftDirection == true)) { - leftDirection = false; - lastLeftFrame = MAX_FRAMES - leftFrame; - } else if ((leftTriggerValue == 0.0) && (leftDirection == false)) { - leftDirection = true; - lastLeftFrame = leftFrame; - } - if ((rightTriggerValue == 1.0) && (rightDirection == true)) { - rightDirection = false; - lastRightFrame = MAX_FRAMES - rightFrame; - } else if ((rightTriggerValue == 0.0) && (rightDirection == false)) { - rightDirection = true; - lastRightFrame = rightFrame; - } - - if ((leftFrame != lastLeftFrame) && leftHandAnimation.length){ - MyAvatar.startAnimation(leftHandAnimation, 30.0, 1.0, false, true, leftFrame, leftFrame); - } - if ((rightFrame != lastRightFrame) && rightHandAnimation.length) { - MyAvatar.startAnimation(rightHandAnimation, 30.0, 1.0, false, true, rightFrame, rightFrame); - } - - lastLeftFrame = leftFrame; - lastRightFrame = rightFrame; -}); - -Script.scriptEnding.connect(function() { - MyAvatar.stopAnimation(leftHandAnimation); - MyAvatar.stopAnimation(rightHandAnimation); -}); \ No newline at end of file diff --git a/examples/controllers/squeezeHands.js b/examples/controllers/squeezeHands.js index 3bf13d8646..9fdb359b25 100644 --- a/examples/controllers/squeezeHands.js +++ b/examples/controllers/squeezeHands.js @@ -1,86 +1,80 @@ // -// squeezeHands.js -// examples +// controllers/squeezeHands.js // -// Created by Philip Rosedale on June 4, 2014 -// Copyright 2014 High Fidelity, Inc. +// Created by Anthony J. Thibault +// Copyright 2015 High Fidelity, Inc. +// +// Default script to drive the animation of the hands based on hand controllers. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; -var HIFI_OZAN_BUCKET = "http://hifi-public.s3.amazonaws.com/ozan/"; - -var rightHandAnimation = HIFI_OZAN_BUCKET + "anim/squeeze_hands/right_hand_anim.fbx"; -var leftHandAnimation = HIFI_OZAN_BUCKET + "anim/squeeze_hands/left_hand_anim.fbx"; - var lastLeftTrigger = 0; var lastRightTrigger = 0; - -var leftIsClosing = true; -var rightIsClosing = true; - -var LAST_FRAME = 15.0; // What is the number of the last frame we want to use in the animation? -var SMOOTH_FACTOR = 0.75; -var MAX_FRAMES = 30.0; - +var leftHandOverlayAlpha = 0; +var rightHandOverlayAlpha = 0; var CONTROLLER_DEAD_SPOT = 0.25; +var TRIGGER_SMOOTH_TIMESCALE = 0.1; +var OVERLAY_RAMP_RATE = 8.0; function clamp(val, min, max) { - if (val < min) { - return min; - } else if (val > max) { - return max; - } else { - return val; - } + return Math.min(Math.max(val, min), max); } function normalizeControllerValue(val) { - return clamp((val - CONTROLLER_DEAD_SPOT) / (1.0 - CONTROLLER_DEAD_SPOT), 0.0, 1.0); + return clamp((val - CONTROLLER_DEAD_SPOT) / (1 - CONTROLLER_DEAD_SPOT), 0, 1); } -Script.update.connect(function(deltaTime) { +function lerp(a, b, alpha) { + return a * (1 - alpha) + b * alpha; +} + +function init() { + Script.update.connect(update); + MyAvatar.addAnimationStateHandler(animStateHandler, ["leftHandOverlayAlpha", "rightHandOverlayAlpha", + "leftHandGraspAlpha", "rightHandGraspAlpha"]); +} + +function animStateHandler(props) { + return { leftHandOverlayAlpha: leftHandOverlayAlpha, + leftHandGraspAlpha: lastLeftTrigger, + rightHandOverlayAlpha: rightHandOverlayAlpha, + rightHandGraspAlpha: lastRightTrigger }; +} + +function update(dt) { var leftTrigger = normalizeControllerValue(Controller.getValue(Controller.Standard.LT)); var rightTrigger = normalizeControllerValue(Controller.getValue(Controller.Standard.RT)); // Average last few trigger values together for a bit of smoothing - var smoothLeftTrigger = leftTrigger * (1.0 - SMOOTH_FACTOR) + lastLeftTrigger * SMOOTH_FACTOR; - var smoothRightTrigger = rightTrigger * (1.0 - SMOOTH_FACTOR) + lastRightTrigger * SMOOTH_FACTOR; + var tau = clamp(dt / TRIGGER_SMOOTH_TIMESCALE, 0, 1); + lastLeftTrigger = lerp(leftTrigger, lastLeftTrigger, tau); + lastRightTrigger = lerp(rightTrigger, lastRightTrigger, tau); - if (leftTrigger == 0.0) { - leftIsClosing = true; - } else if (leftTrigger == 1.0) { - leftIsClosing = false; + // ramp on/off left hand overlay + var leftHandPose = Controller.getPoseValue(Controller.Standard.LeftHand); + if (leftHandPose.valid) { + leftHandOverlayAlpha = clamp(leftHandOverlayAlpha + OVERLAY_RAMP_RATE * dt, 0, 1); + } else { + leftHandOverlayAlpha = clamp(leftHandOverlayAlpha - OVERLAY_RAMP_RATE * dt, 0, 1); } - if (rightTrigger == 0.0) { - rightIsClosing = true; - } else if (rightTrigger == 1.0) { - rightIsClosing = false; + // ramp on/off right hand overlay + var rightHandPose = Controller.getPoseValue(Controller.Standard.RightHand); + if (rightHandPose.valid) { + rightHandOverlayAlpha = clamp(rightHandOverlayAlpha + OVERLAY_RAMP_RATE * dt, 0, 1); + } else { + rightHandOverlayAlpha = clamp(rightHandOverlayAlpha - OVERLAY_RAMP_RATE * dt, 0, 1); } +} - lastLeftTrigger = smoothLeftTrigger; - lastRightTrigger = smoothRightTrigger; +function shutdown() { + Script.update.disconnect(update); + MyAvatar.removeAnimationStateHandler(animStateHandler); +} - // 0..15 - var leftFrame = smoothLeftTrigger * LAST_FRAME; - var rightFrame = smoothRightTrigger * LAST_FRAME; +Script.scriptEnding.connect(shutdown); - var adjustedLeftFrame = (leftIsClosing) ? leftFrame : (MAX_FRAMES - leftFrame); - if (leftHandAnimation.length) { - MyAvatar.startAnimation(leftHandAnimation, 30.0, 1.0, false, true, adjustedLeftFrame, adjustedLeftFrame); - } - - var adjustedRightFrame = (rightIsClosing) ? rightFrame : (MAX_FRAMES - rightFrame); - if (rightHandAnimation.length) { - MyAvatar.startAnimation(rightHandAnimation, 30.0, 1.0, false, true, adjustedRightFrame, adjustedRightFrame); - } -}); - -Script.scriptEnding.connect(function() { - MyAvatar.stopAnimation(leftHandAnimation); - MyAvatar.stopAnimation(rightHandAnimation); -}); +init(); diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index 443e4b3bf8..5ca62470ee 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -17,6 +17,7 @@ Script.load("inspect.js"); Script.load("notifications.js"); Script.load("users.js"); Script.load("controllers/handControllerGrab.js"); +Script.load("controllers/squeezeHands.js"); Script.load("grab.js"); Script.load("directory.js"); Script.load("dialTone.js"); diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index efd16576ee..f220e66f0b 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -113,7 +113,7 @@ "id": "rightHandOverlay", "type": "overlay", "data": { - "alpha": 1.0, + "alpha": 0.0, "boneSet": "rightHand", "alphaVar": "rightHandOverlayAlpha" }, @@ -122,125 +122,50 @@ "id": "rightHandStateMachine", "type": "stateMachine", "data": { - "currentState": "rightHandIdle", + "currentState": "rightHandGrasp", "states": [ - { - "id": "rightHandIdle", - "interpTarget": 3, - "interpDuration": 3, - "transitions": [ - { "var": "rightHandOpen", "state": "rightHandOpen" }, - { "var": "rightHandGrasp", "state": "rightHandGrasp" }, - { "var": "rightHandPoint", "state": "rightHandPoint" }, - { "var": "rightHandFarGrasp", "state": "rightHandFarGrasp" } - ] - }, - { - "id": "rightHandOpen", - "interpTarget": 3, - "interpDuration": 3, - "transitions": [ - { "var": "rightHandIdle", "state": "rightHandIdle" }, - { "var": "rightHandGrasp", "state": "rightHandGrasp" }, - { "var": "rightHandPoint", "state": "rightHandPoint" }, - { "var": "rightHandFarGrasp", "state": "rightHandFarGrasp" } - ] - }, { "id": "rightHandGrasp", "interpTarget": 3, "interpDuration": 3, - "transitions": [ - { "var": "rightHandOpen", "state": "rightHandOpen" }, - { "var": "rightHandIdle", "state": "rightHandIdle" }, - { "var": "rightHandPoint", "state": "rightHandPoint" }, - { "var": "rightHandFarGrasp", "state": "rightHandFarGrasp" } - ] - }, - { - "id": "rightHandPoint", - "interpTarget": 3, - "interpDuration": 3, - "transitions": [ - { "var": "rightHandOpen", "state": "rightHandOpen" }, - { "var": "rightHandIdle", "state": "rightHandIdle" }, - { "var": "rightHandGrasp", "state": "rightHandGrasp" }, - { "var": "rightHandFarGrasp", "state": "rightHandFarGrasp" } - ] - }, - { - "id": "rightHandFarGrasp", - "interpTarget": 3, - "interpDuration": 3, - "transitions": [ - { "var": "rightHandOpen", "state": "rightHandOpen" }, - { "var": "rightHandIdle", "state": "rightHandIdle" }, - { "var": "rightHandGrasp", "state": "rightHandGrasp" }, - { "var": "rightHandPoint", "state": "rightHandPoint" } - ] + "transitions": [] } ] }, "children": [ - { - "id": "rightHandIdle", - "type": "clip", - "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_right_hand.fbx", - "startFrame": 0.0, - "endFrame": 0.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "rightHandOpen", - "type": "clip", - "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/search_right.fbx", - "startFrame": 0.0, - "endFrame": 0.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, { "id": "rightHandGrasp", - "type": "clip", + "type": "blendLinear", "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/grasp_right.fbx", - "startFrame": 0.0, - "endFrame": 0.0, - "timeScale": 1.0, - "loopFlag": true + "alpha": 0.0, + "alphaVar": "rightHandGraspAlpha" }, - "children": [] - }, - { - "id": "rightHandPoint", - "type": "clip", - "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_right_hand.fbx", - "startFrame": 20.0, - "endFrame": 20.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "rightHandFarGrasp", - "type": "clip", - "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/far_grasp_right.fbx", - "startFrame": 0.0, - "endFrame": 0.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] + "children": [ + { + "id": "rightHandGraspOpen", + "type": "clip", + "data": { + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/search_right.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "rightHandGraspClosed", + "type": "clip", + "data": { + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/grasp_right.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] } ] }, @@ -248,7 +173,7 @@ "id": "leftHandOverlay", "type": "overlay", "data": { - "alpha": 1.0, + "alpha": 0.0, "boneSet": "leftHand", "alphaVar" : "leftHandOverlayAlpha" }, @@ -257,127 +182,50 @@ "id": "leftHandStateMachine", "type": "stateMachine", "data": { - "currentState": "leftHandIdle", + "currentState": "leftHandGrasp", "states": [ - { - "id": "leftHandIdle", - "interpTarget": 3, - "interpDuration": 3, - "transitions": [ - { "var": "leftHandOpen", "state": "leftHandOpen" }, - { "var": "leftHandGrasp", "state": "leftHandGrasp" }, - { "var": "leftHandPoint", "state": "leftHandPoint" }, - { "var": "leftHandFarGrasp", "state": "leftHandFarGrasp" } - ] - }, - { - "id": "leftHandOpen", - "interpTarget": 3, - "interpDuration": 3, - "transitions": [ - { "var": "leftHandIdle", "state": "leftHandIdle" }, - { "var": "leftHandGrasp", "state": "leftHandGrasp" }, - { "var": "leftHandPoint", "state": "leftHandPoint" }, - { "var": "leftHandFarGrasp", "state": "leftHandFarGrasp" } - ] - }, { "id": "leftHandGrasp", "interpTarget": 3, "interpDuration": 3, - "transitions": [ - { "var": "leftHandOpen", "state": "leftHandOpen" }, - { "var": "leftHandIdle", "state": "leftHandIdle" }, - { "var": "leftHandPoint", "state": "leftHandPoint" }, - { "var": "leftHandFarGrasp", "state": "leftHandFarGrasp" } - ] - }, - { - "id": "leftHandPoint", - "interpTarget": 3, - "interpDuration": 3, - "transitions": [ - { "var": "leftHandOpen", "state": "leftHandOpen" }, - { "var": "leftHandIdle", "state": "leftHandIdle" }, - { "var": "leftHandGrasp", "state": "leftHandGrasp" }, - { "var": "leftHandFarGrasp", "state": "leftHandFarGrasp" } - ] - }, - { - "id": "leftHandFarGrasp", - "interpTarget": 3, - "interpDuration": 3, - "transitions": [ - { "var": "leftHandOpen", "state": "leftHandOpen" }, - { "var": "leftHandIdle", "state": "leftHandIdle" }, - { "var": "leftHandGrasp", "state": "leftHandGrasp" }, - { "var": "leftHandPoint", "state": "leftHandPoint" } - ] + "transitions": [] } ] }, "children": [ - { - "id": "leftHandIdle", - "type": "clip", - "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_left_hand.fbx", - "startFrame": 0.0, - "endFrame": 0.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "leftHandOpen", - "type": "clip", - "data": { - - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/search_left.fbx", - "startFrame": 0.0, - "endFrame": 0.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, { "id": "leftHandGrasp", - "type": "clip", + "type": "blendLinear", "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/grasp_left.fbx", - "startFrame": 0.0, - "endFrame": 0.0, - "timeScale": 1.0, - "loopFlag": true + "alpha": 0.0, + "alphaVar": "leftHandGraspAlpha" }, - "children": [] - }, - { - "id": "leftHandPoint", - "type": "clip", - "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_left_hand.fbx", - "startFrame": 12.0, - "endFrame": 12.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "leftHandFarGrasp", - "type": "clip", - "data": { - - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/far_grasp_left.fbx", - "startFrame": 0.0, - "endFrame": 0.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] + "children": [ + { + "id": "leftHandGraspOpen", + "type": "clip", + "data": { + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/search_left.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "leftHandGraspClosed", + "type": "clip", + "data": { + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/grasp_left.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] } ] }, From 1436b4f6b168b82dd6683abdcde79f8f0ffcac92 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 13 Jan 2016 18:17:40 -0800 Subject: [PATCH 144/215] Guard against unspecified deferredDebugMode --- libraries/render-utils/src/DebugDeferredBuffer.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index ca678770fb..ab2fa403f1 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -182,6 +182,14 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren assert(renderContext->getArgs()); assert(renderContext->getArgs()->_viewFrustum); RenderArgs* args = renderContext->getArgs(); + + // Guard against unspecified modes + auto mode = renderContext->_deferredDebugMode; + if (mode > (int)CustomMode) { + renderContext->_deferredDebugMode = -1; + return; + } + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { const auto geometryBuffer = DependencyManager::get(); const auto framebufferCache = DependencyManager::get(); From 30199106ecf5ea10ec5fdca726f3c6668e6ffae7 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 13 Jan 2016 20:47:05 -0800 Subject: [PATCH 145/215] Choice of hand ray pick or head pick --- examples/controllers/handControllerGrab.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index be5fdd7edb..c40aa065b8 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -33,6 +33,8 @@ var BUMPER_ON_VALUE = 0.5; var HAND_HEAD_MIX_RATIO = 0.0; // 0 = only use hands for search/move. 1 = only use head for search/move. +var PICK_WITH_HAND_RAY = true; + // // distant manipulation // @@ -903,8 +905,9 @@ function MyController(hand) { var handDeltaRotation = Quat.multiply(currentHandRotation, Quat.inverse(this.startingHandRotation)); var distantPickRay = { - origin: Camera.position, - direction: Vec3.mix(Quat.getUp(this.getHandRotation()), Quat.getFront(Camera.orientation), HAND_HEAD_MIX_RATIO), + origin: PICK_WITH_HAND_RAY ? handPosition : Camera.position, + direction: PICK_WITH_HAND_RAY ? Quat.getUp(this.getHandRotation()) : + Vec3.mix(Quat.getUp(this.getHandRotation()), Quat.getFront(Camera.orientation), HAND_HEAD_MIX_RATIO), length: PICK_MAX_DISTANCE }; @@ -1143,10 +1146,6 @@ function MyController(hand) { this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); } - if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { - this.overlayLineOn(searchVisualizationPickRay.origin, Vec3.sum(searchVisualizationPickRay.origin, Vec3.multiply(searchVisualizationPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); - } - if (this.intersectionDistance > 0) { var SPHERE_INTERSECTION_SIZE = 0.011; var SEARCH_SPHERE_FOLLOW_RATE = 0.50; @@ -1155,7 +1154,7 @@ function MyController(hand) { var searchSphereLocation = Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, this.searchSphereDistance)); searchSphereLocation.y -= ((this.intersectionDistance - this.searchSphereDistance) / this.intersectionDistance) * SEARCH_SPHERE_CHASE_DROP; this.searchSphereOn(searchSphereLocation, SPHERE_INTERSECTION_SIZE * this.intersectionDistance, this.triggerSmoothedGrab() ? INTERSECT_COLOR : NO_INTERSECT_COLOR); - if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { + if ((USE_OVERLAY_LINES_FOR_SEARCHING === true) && PICK_WITH_HAND_RAY) { this.overlayLineOn(handPosition, searchSphereLocation, this.triggerSmoothedGrab() ? INTERSECT_COLOR : NO_INTERSECT_COLOR); } } From ed5c53f23c0f2cdd142a7dfccd2db3f7c73dfd66 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 13 Jan 2016 22:49:00 -0800 Subject: [PATCH 146/215] Add getCorners to ViewFrustum --- libraries/octree/src/ViewFrustum.cpp | 17 +++++++++++++++++ libraries/octree/src/ViewFrustum.h | 13 ++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/libraries/octree/src/ViewFrustum.cpp b/libraries/octree/src/ViewFrustum.cpp index fd175a8e5b..0e7df1d9a4 100644 --- a/libraries/octree/src/ViewFrustum.cpp +++ b/libraries/octree/src/ViewFrustum.cpp @@ -736,6 +736,23 @@ void ViewFrustum::getFurthestPointFromCamera(const AACube& box, glm::vec3& furth } } +const ViewFrustum::Corners ViewFrustum::getCorners(const float& depth) { + glm::vec3 normal = glm::normalize(_direction); + + auto getCorner = [&](enum::BoxVertex nearCorner, enum::BoxVertex farCorner) { + const auto dir = glm::normalize(_cornersWorld[nearCorner] - _cornersWorld[farCorner]); + const auto factor = depth / glm::dot(dir, normal); + return _position + factor * dir; + }; + + return Corners{ + getCorner(TOP_LEFT_NEAR, TOP_LEFT_FAR), + getCorner(TOP_RIGHT_NEAR, TOP_RIGHT_FAR), + getCorner(BOTTOM_LEFT_NEAR, BOTTOM_LEFT_FAR), + getCorner(BOTTOM_RIGHT_NEAR, BOTTOM_RIGHT_FAR) + }; +} + float ViewFrustum::distanceToCamera(const glm::vec3& point) const { glm::vec3 temp = getPosition() - point; float distanceToPoint = sqrtf(glm::dot(temp, temp)); diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index 795a259a3c..4a39ac5f44 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -61,11 +61,22 @@ public: float getFarClip() const { return _farClip; } float getFocalLength() const { return _focalLength; } + const class Corners{ + public: + Corners(glm::vec3&& topLeft, glm::vec3&& topRight, glm::vec3&& bottomLeft, glm::vec3&& bottomRight) + : topLeft{ topLeft }, topRight{ topRight }, bottomLeft{ bottomLeft }, bottomRight{ bottomRight } {} + glm::vec3 topLeft; + glm::vec3 topRight; + glm::vec3 bottomLeft; + glm::vec3 bottomRight; + // Get the corners depth units from frustum position, along frustum orientation + } getCorners(const float& depth); + + // getters for corners const glm::vec3& getFarTopLeft() const { return _cornersWorld[TOP_LEFT_FAR]; } const glm::vec3& getFarTopRight() const { return _cornersWorld[TOP_RIGHT_FAR]; } const glm::vec3& getFarBottomLeft() const { return _cornersWorld[BOTTOM_LEFT_FAR]; } const glm::vec3& getFarBottomRight() const { return _cornersWorld[BOTTOM_RIGHT_FAR]; } - const glm::vec3& getNearTopLeft() const { return _cornersWorld[TOP_LEFT_NEAR]; } const glm::vec3& getNearTopRight() const { return _cornersWorld[TOP_RIGHT_NEAR]; } const glm::vec3& getNearBottomLeft() const { return _cornersWorld[BOTTOM_LEFT_NEAR]; } From 6b76cf484df7ca686feeb549d3119e5a185ffc96 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 14 Jan 2016 08:48:55 -0800 Subject: [PATCH 147/215] fix issues with HMD lookout 2D, and cleanup --- interface/src/Application.cpp | 2 +- interface/src/avatar/MyAvatar.cpp | 18 ----- interface/src/avatar/MyAvatar.h | 4 -- .../src/scripting/HMDScriptingInterface.cpp | 15 +--- .../src/scripting/HMDScriptingInterface.h | 4 -- interface/src/ui/ApplicationCompositor.cpp | 72 ------------------- interface/src/ui/ApplicationCompositor.h | 40 +++-------- 7 files changed, 15 insertions(+), 140 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4c4786c6a2..6de6388fb2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3514,7 +3514,7 @@ int Application::getBoundaryLevelAdjust() const { } PickRay Application::computePickRay(float x, float y) const { - vec2 pickPoint{ x, y }; + vec2 pickPoint { x, y }; PickRay result; if (isHMDMode()) { getApplicationCompositor().computeHmdPickRay(pickPoint, result.origin, result.direction); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index a5303b401a..b1688b8f9e 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1708,24 +1708,6 @@ void MyAvatar::updateMotionBehaviorFromMenu() { _characterController.setEnabled(menu->isOptionChecked(MenuOption::EnableCharacterController)); } -//Gets the tip position for the laser pointer -glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) { - glm::vec3 direction = glm::normalize(palm->getTipPosition() - palm->getPosition()); - - glm::vec3 position = palm->getPosition(); - //scale the position with the avatar - scaleVectorRelativeToPosition(position); - - - glm::vec3 result; - const auto& compositor = qApp->getApplicationCompositor(); - if (compositor.calculateRayUICollisionPoint(position, direction, result)) { - return result; - } - - return palm->getPosition(); -} - void MyAvatar::clearDriveKeys() { for (int i = 0; i < MAX_DRIVE_KEYS; ++i) { _driveKeys[i] = 0.0f; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 8c4bbcbba0..33d307f5c2 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -214,10 +214,6 @@ public: void clearScriptableSettings(); - /// Renders a laser pointer for UI picking - - glm::vec3 getLaserPointerTipPosition(const PalmData* palm); - float getBoomLength() const { return _boomLength; } void setBoomLength(float boomLength) { _boomLength = boomLength; } diff --git a/interface/src/scripting/HMDScriptingInterface.cpp b/interface/src/scripting/HMDScriptingInterface.cpp index 28d358fa39..ab53e6912a 100644 --- a/interface/src/scripting/HMDScriptingInterface.cpp +++ b/interface/src/scripting/HMDScriptingInterface.cpp @@ -27,10 +27,9 @@ QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* conte MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); glm::vec3 sphereCenter = myAvatar->getDefaultEyePosition(); glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * (hudIntersection - sphereCenter); - glm::quat rotation = ::rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), direction); - glm::vec3 eulers = ::safeEulerAngles(rotation); - return qScriptValueFromValue(engine, qApp->getApplicationCompositor() - .sphericalToOverlay(glm::vec2(eulers.y, -eulers.x))); + glm::vec2 polar = glm::vec2(glm::atan(direction.x, -direction.z), glm::asin(direction.y)) * -1.0f; + auto overlayPos = qApp->getApplicationCompositor().sphericalToOverlay(polar); + return qScriptValueFromValue(engine, overlayPos); } return QScriptValue::NullValue; } @@ -44,14 +43,6 @@ QScriptValue HMDScriptingInterface::getHUDLookAtPosition3D(QScriptContext* conte return QScriptValue::NullValue; } -void HMDScriptingInterface::toggleMagnifier() { - qApp->getApplicationCompositor().toggleMagnifier(); -} - -bool HMDScriptingInterface::getMagnifier() const { - return qApp->getApplicationCompositor().hasMagnifier(); -} - bool HMDScriptingInterface::getHUDLookAtPosition3D(glm::vec3& result) const { Camera* camera = qApp->getCamera(); glm::vec3 position = camera->getPosition(); diff --git a/interface/src/scripting/HMDScriptingInterface.h b/interface/src/scripting/HMDScriptingInterface.h index b803cc7801..f07350605f 100644 --- a/interface/src/scripting/HMDScriptingInterface.h +++ b/interface/src/scripting/HMDScriptingInterface.h @@ -23,7 +23,6 @@ class QScriptEngine; class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Dependency { Q_OBJECT - Q_PROPERTY(bool magnifier READ getMagnifier) Q_PROPERTY(glm::vec3 position READ getPosition) Q_PROPERTY(glm::quat orientation READ getOrientation) public: @@ -31,11 +30,8 @@ public: static QScriptValue getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine); static QScriptValue getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine); -public slots: - void toggleMagnifier(); private: - bool getMagnifier() const; // Get the position of the HMD glm::vec3 getPosition() const; diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index abc3520c83..9ac7e82963 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -117,8 +117,6 @@ ApplicationCompositor::ApplicationCompositor() : auto geometryCache = DependencyManager::get(); _reticleQuad = geometryCache->allocateID(); - _magnifierQuad = geometryCache->allocateID(); - _magnifierBorder = geometryCache->allocateID(); auto entityScriptingInterface = DependencyManager::get(); connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity, [=](const EntityItemID& entityItemID, const MouseEvent& event) { @@ -231,25 +229,6 @@ void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) { }); } - -vec2 ApplicationCompositor::getPolarCoordinates(const PalmData& palm) const { - MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); - glm::vec3 tip = myAvatar->getLaserPointerTipPosition(&palm); - glm::vec3 relativePos = myAvatar->getDefaultEyePosition(); - glm::quat rotation = myAvatar->getOrientation(); - if (Menu::getInstance()->isOptionChecked(MenuOption::StandingHMDSensorMode)) { - relativePos = _modelTransform.getTranslation(); - rotation = _modelTransform.getRotation(); - } - glm::vec3 tipDirection = tip - relativePos; - tipDirection = glm::inverse(rotation) * tipDirection; - // Normalize for trig functions - tipDirection = glm::normalize(tipDirection); - // Convert to polar coordinates - glm::vec2 polar(glm::atan(tipDirection.x, -tipDirection.z), glm::asin(tipDirection.y)); - return polar; -} - // Draws the FBO texture for Oculus rift. void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int eye) { PROFILE_RANGE(__FUNCTION__); @@ -345,36 +324,6 @@ void ApplicationCompositor::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& or direction = glm::normalize(worldSpaceIntersection - worldSpaceHeadPosition); } -//Caculate the click location using one of the sixense controllers. Scale is not applied -QPoint ApplicationCompositor::getPalmClickLocation(const PalmData *palm) const { - QPoint rv; - auto canvasSize = qApp->getCanvasSize(); - if (qApp->isHMDMode()) { - glm::vec2 polar = getPolarCoordinates(*palm); - glm::vec2 point = sphericalToScreen(-polar); - rv.rx() = point.x; - rv.ry() = point.y; - } else { - MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); - glm::mat4 projection; - qApp->getDisplayViewFrustum()->evalProjectionMatrix(projection); - glm::quat invOrientation = glm::inverse(myAvatar->getOrientation()); - glm::vec3 eyePos = myAvatar->getDefaultEyePosition(); - glm::vec3 tip = myAvatar->getLaserPointerTipPosition(palm); - glm::vec3 tipPos = invOrientation * (tip - eyePos); - - glm::vec4 clipSpacePos = glm::vec4(projection * glm::vec4(tipPos, 1.0f)); - glm::vec3 ndcSpacePos; - if (clipSpacePos.w != 0) { - ndcSpacePos = glm::vec3(clipSpacePos) / clipSpacePos.w; - } - - rv.setX(((ndcSpacePos.x + 1.0f) / 2.0f) * canvasSize.x); - rv.setY((1.0f - ((ndcSpacePos.y + 1.0f) / 2.0f)) * canvasSize.y); - } - return rv; -} - //Finds the collision point of a world space ray bool ApplicationCompositor::calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const { MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); @@ -498,27 +447,6 @@ void ApplicationCompositor::drawSphereSection(gpu::Batch& batch) { batch.drawIndexed(gpu::TRIANGLES, _hemiIndexCount); } -glm::vec2 ApplicationCompositor::directionToSpherical(const glm::vec3& direction) { - glm::vec2 result; - // Compute yaw - glm::vec3 normalProjection = glm::normalize(glm::vec3(direction.x, 0.0f, direction.z)); - result.x = glm::acos(glm::dot(IDENTITY_FRONT, normalProjection)); - if (glm::dot(IDENTITY_RIGHT, normalProjection) > 0.0f) { - result.x = -glm::abs(result.x); - } else { - result.x = glm::abs(result.x); - } - // Compute pitch - result.y = angleBetween(IDENTITY_UP, direction) - PI_OVER_TWO; - - return result; -} - -glm::vec3 ApplicationCompositor::sphericalToDirection(const glm::vec2& sphericalPos) { - glm::quat rotation(glm::vec3(sphericalPos.y, sphericalPos.x, 0.0f)); - return rotation * IDENTITY_FRONT; -} - glm::vec2 ApplicationCompositor::screenToSpherical(const glm::vec2& screenPos) { auto screenSize = qApp->getCanvasSize(); glm::vec2 result; diff --git a/interface/src/ui/ApplicationCompositor.h b/interface/src/ui/ApplicationCompositor.h index 5f023adaef..8476782550 100644 --- a/interface/src/ui/ApplicationCompositor.h +++ b/interface/src/ui/ApplicationCompositor.h @@ -43,20 +43,15 @@ public: void displayOverlayTexture(RenderArgs* renderArgs); void displayOverlayTextureHmd(RenderArgs* renderArgs, int eye); - QPoint getPalmClickLocation(const PalmData *palm) const; bool calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const; - bool hasMagnifier() const { return _magnifier; } - void toggleMagnifier() { _magnifier = !_magnifier; } - float getHmdUIAngularSize() const { return _hmdUIAngularSize; } void setHmdUIAngularSize(float hmdUIAngularSize) { _hmdUIAngularSize = hmdUIAngularSize; } // Converter from one frame of reference to another. // Frame of reference: - // Direction: Ray that represents the spherical values // Screen: Position on the screen (x,y) - // Spherical: Pitch and yaw that gives the position on the sphere we project on (yaw,pitch) + // Spherical: Polar coordinates that gives the position on the sphere we project on (yaw,pitch) // Overlay: Position on the overlay (x,y) // (x,y) in Overlay are similar than (x,y) in Screen except they can be outside of the bound of te screen. // This allows for picking outside of the screen projection in 3D. @@ -80,8 +75,6 @@ public: float getAlpha() const { return _alpha; } void setAlpha(float alpha) { _alpha = alpha; } - static glm::vec2 directionToSpherical(const glm::vec3 & direction); - static glm::vec3 sphericalToDirection(const glm::vec2 & sphericalPos); static glm::vec2 screenToSpherical(const glm::vec2 & screenPos); static glm::vec2 sphericalToScreen(const glm::vec2 & sphericalPos); @@ -92,8 +85,6 @@ private: void drawSphereSection(gpu::Batch& batch); void updateTooltips(); - vec2 getPolarCoordinates(const PalmData& palm) const; - // Support for hovering and tooltips static EntityItemID _noItemId; EntityItemID _hoverItemId { _noItemId }; @@ -101,31 +92,22 @@ private: QString _hoverItemDescription; quint64 _hoverItemEnterUsecs { 0 }; - float _hmdUIAngularSize = DEFAULT_HMD_UI_ANGULAR_SIZE; - float _textureFov{ glm::radians(DEFAULT_HMD_UI_ANGULAR_SIZE) }; - float _textureAspectRatio{ 1.0f }; - int _hemiVerticesID{ GeometryCache::UNKNOWN_ID }; + float _hmdUIAngularSize { DEFAULT_HMD_UI_ANGULAR_SIZE }; + float _textureFov { glm::radians(DEFAULT_HMD_UI_ANGULAR_SIZE) }; + float _textureAspectRatio { 1.0f }; + int _hemiVerticesID { GeometryCache::UNKNOWN_ID }; - bool _magnifier{ true }; - - float _alpha{ 1.0f }; - float _prevAlpha{ 1.0f }; - float _fadeInAlpha{ true }; - float _oculusUIRadius{ 1.0f }; + float _alpha { 1.0f }; + float _prevAlpha { 1.0f }; + float _fadeInAlpha { true }; + float _oculusUIRadius { 1.0f }; QMap _cursors; int _reticleQuad; - int _magnifierQuad; - int _magnifierBorder; - int _previousBorderWidth{ -1 }; - int _previousBorderHeight{ -1 }; - - glm::vec3 _previousMagnifierBottomLeft; - glm::vec3 _previousMagnifierBottomRight; - glm::vec3 _previousMagnifierTopLeft; - glm::vec3 _previousMagnifierTopRight; + int _previousBorderWidth { -1 }; + int _previousBorderHeight { -1 }; Transform _modelTransform; Transform _cameraBaseTransform; From c267d672d20fd197d147c433f30c6aaa4a411608 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 14 Jan 2016 08:57:27 -0800 Subject: [PATCH 148/215] Updated hand grab animations Left hand is old squeeze hands poses Right hand is new hydra grasp poses --- .../meshes/defaultAvatar_full/avatar-animation.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index f220e66f0b..04b596e000 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -145,7 +145,7 @@ "id": "rightHandGraspOpen", "type": "clip", "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/search_right.fbx", + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hydra_pose_right.fbx", "startFrame": 0.0, "endFrame": 0.0, "timeScale": 1.0, @@ -157,7 +157,7 @@ "id": "rightHandGraspClosed", "type": "clip", "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/grasp_right.fbx", + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hydra_pose_close_right.fbx", "startFrame": 0.0, "endFrame": 0.0, "timeScale": 1.0, @@ -205,7 +205,7 @@ "id": "leftHandGraspOpen", "type": "clip", "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/search_left.fbx", + "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_left.fbx", "startFrame": 0.0, "endFrame": 0.0, "timeScale": 1.0, @@ -217,9 +217,9 @@ "id": "leftHandGraspClosed", "type": "clip", "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/grasp_left.fbx", - "startFrame": 0.0, - "endFrame": 0.0, + "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_left.fbx", + "startFrame": 10.0, + "endFrame": 10.0, "timeScale": 1.0, "loopFlag": true }, From 72928fdbd6f6526149ceeb8c52cf4e8d81c66d9a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Jan 2016 10:42:27 -0800 Subject: [PATCH 149/215] fix problem where grab stops on slow movement --- libraries/physics/src/ObjectActionSpring.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/ObjectActionSpring.cpp b/libraries/physics/src/ObjectActionSpring.cpp index a737a2b8b6..3f2664fb12 100644 --- a/libraries/physics/src/ObjectActionSpring.cpp +++ b/libraries/physics/src/ObjectActionSpring.cpp @@ -63,8 +63,8 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) { btVector3 targetVelocity(0.0f, 0.0f, 0.0f); float speed = (offsetLength > FLT_EPSILON) ? glm::min(offsetLength / _linearTimeScale, SPRING_MAX_SPEED) : 0.0f; + targetVelocity = (-speed / offsetLength) * offset; if (speed > rigidBody->getLinearSleepingThreshold()) { - targetVelocity = (-speed / offsetLength) * offset; rigidBody->activate(); } @@ -92,8 +92,8 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) { // dQ = Q1 * Q0^ btQuaternion deltaQ = target * bodyRotation.inverse(); float speed = deltaQ.getAngle() / _angularTimeScale; + targetVelocity = speed * deltaQ.getAxis(); if (speed > rigidBody->getAngularSleepingThreshold()) { - targetVelocity = speed * deltaQ.getAxis(); rigidBody->activate(); } } From 82f7ea515d28afd07b603cf3489fea2496f3ce3c Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 14 Jan 2016 11:05:58 -0800 Subject: [PATCH 150/215] Clean up task construction --- .../render-utils/src/RenderDeferredTask.cpp | 43 +++++++---------- .../render-utils/src/RenderDeferredTask.h | 46 +++++++------------ libraries/render/src/render/Task.h | 7 +-- 3 files changed, 36 insertions(+), 60 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 37126e6558..d0d0338742 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -77,30 +77,28 @@ RenderDeferredTask::RenderDeferredTask() : Task() { ShapePlumberPointer shapePlumber = std::make_shared(); initDeferredPipelines(*shapePlumber); - // CPU only, create the list of renderedOpaques items - addJob("FetchOpaque", FetchItems([](const RenderContextPointer& context, int count) { + // CPU: Fetch the renderOpaques + const auto fetchedOpaques = addJob("FetchOpaque", FetchItems([](const RenderContextPointer& context, int count) { context->getItemsConfig().opaque.numFeed = count; })); - addJob>("CullOpaque", _jobs.back().getOutput()); - addJob("DepthSortOpaque", _jobs.back().getOutput()); - auto& renderedOpaques = _jobs.back().getOutput(); + const auto culledOpaques = addJob>("CullOpaque", fetchedOpaques); + const auto opaques = addJob("DepthSortOpaque", culledOpaques); // CPU only, create the list of renderedTransparents items - addJob("FetchTransparent", FetchItems( + const auto fetchedTransparents = addJob("FetchTransparent", FetchItems( ItemFilter::Builder::transparentShape().withoutLayered(), [](const RenderContextPointer& context, int count) { context->getItemsConfig().transparent.numFeed = count; } - )); - addJob>("CullTransparent", _jobs.back().getOutput()); - addJob("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false)); - auto& renderedTransparents = _jobs.back().getOutput(); + )); + const auto culledTransparents = addJob>("CullTransparent", fetchedTransparents); + const auto transparents = addJob("DepthSortTransparent", culledTransparents, DepthSortItems(false)); // GPU Jobs: Start preparing the deferred and lighting buffer addJob("PrepareDeferred"); // Render opaque objects in DeferredBuffer - addJob("DrawOpaqueDeferred", renderedOpaques, shapePlumber); + addJob("DrawOpaqueDeferred", opaques, shapePlumber); // Once opaque is all rendered create stencil background addJob("DrawOpaqueStencil"); @@ -116,16 +114,16 @@ RenderDeferredTask::RenderDeferredTask() : Task() { // AO job, to be revisited addJob("AmbientOcclusion"); - _jobs.back().setEnabled(false); _occlusionJobIndex = (int)_jobs.size() - 1; + enableJob(_occlusionJobIndex, false); // AA job to be revisited addJob("Antialiasing"); - _jobs.back().setEnabled(false); _antialiasingJobIndex = (int)_jobs.size() - 1; + enableJob(_antialiasingJobIndex, false); // Render transparent objects forward in LigthingBuffer - addJob("DrawTransparentDeferred", renderedTransparents, shapePlumber); + addJob("DrawTransparentDeferred", transparents, shapePlumber); // Lighting Buffer ready for tone mapping addJob("ToneMapping"); @@ -133,24 +131,24 @@ RenderDeferredTask::RenderDeferredTask() : Task() { // Debugging Deferred buffer job addJob("DebugDeferredBuffer"); - _jobs.back().setEnabled(false); _drawDebugDeferredBufferIndex = (int)_jobs.size() - 1; + enableJob(_drawDebugDeferredBufferIndex, false); // Status icon rendering job { // Grab a texture map representing the different status icons and assign that to the drawStatsuJob auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg"; auto statusIconMap = DependencyManager::get()->getImageTexture(iconMapPath); - addJob("DrawStatus", renderedOpaques, DrawStatus(statusIconMap)); - _jobs.back().setEnabled(false); + addJob("DrawStatus", opaques, DrawStatus(statusIconMap)); _drawStatusJobIndex = (int)_jobs.size() - 1; + enableJob(_drawStatusJobIndex, false); } addJob("DrawOverlay3D", shapePlumber); addJob("HitEffect"); - _jobs.back().setEnabled(false); _drawHitEffectJobIndex = (int)_jobs.size() -1; + enableJob(_drawHitEffectJobIndex, false); addJob("Blit"); } @@ -168,21 +166,12 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend return; } - // Make sure we turn the deferred buffer debug on/off setDrawDebugDeferredBuffer(renderContext->_deferredDebugMode); - - // Make sure we turn the displayItemStatus on/off setDrawItemStatus(renderContext->getDrawStatus()); - - // Make sure we display hit effect on screen, as desired from a script setDrawHitEffect(renderContext->getDrawHitEffect()); - - // TODO: turn on/off AO through menu item setOcclusionStatus(renderContext->getOcclusionStatus()); - setAntialiasingStatus(renderContext->getFxaaStatus()); - setToneMappingExposure(renderContext->getTone().exposure); setToneMappingToneCurve(renderContext->getTone().toneCurve); diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 85e3e7f211..4fe0c75198 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -113,41 +113,32 @@ public: class RenderDeferredTask : public render::Task { public: - RenderDeferredTask(); - int _drawDebugDeferredBufferIndex = -1; - int _drawStatusJobIndex = -1; - int _drawHitEffectJobIndex = -1; + int _drawDebugDeferredBufferIndex; + int _drawStatusJobIndex; + int _drawHitEffectJobIndex; + int _occlusionJobIndex; + int _antialiasingJobIndex; + int _toneMappingJobIndex; - void setDrawDebugDeferredBuffer(int draw) { - if (_drawDebugDeferredBufferIndex >= 0) { - _jobs[_drawDebugDeferredBufferIndex].setEnabled(draw >= 0); - } - } - bool doDrawDebugDeferredBuffer() const { if (_drawDebugDeferredBufferIndex >= 0) { return _jobs[_drawDebugDeferredBufferIndex].isEnabled(); } else { return false; } } + void setDrawDebugDeferredBuffer(int draw) { enableJob(_drawDebugDeferredBufferIndex, draw >= 0); } + bool doDrawDebugDeferredBuffer() const { return getEnableJob(_drawDebugDeferredBufferIndex); } - void setDrawItemStatus(int draw) { - if (_drawStatusJobIndex >= 0) { - _jobs[_drawStatusJobIndex].setEnabled(draw > 0); - } - } - bool doDrawItemStatus() const { if (_drawStatusJobIndex >= 0) { return _jobs[_drawStatusJobIndex].isEnabled(); } else { return false; } } + void setDrawItemStatus(int draw) { enableJob(_drawStatusJobIndex, draw > 0); } + bool doDrawItemStatus() const { return getEnableJob(_drawStatusJobIndex); } - void setDrawHitEffect(bool draw) { if (_drawHitEffectJobIndex >= 0) { _jobs[_drawHitEffectJobIndex].setEnabled(draw); } } - bool doDrawHitEffect() const { if (_drawHitEffectJobIndex >=0) { return _jobs[_drawHitEffectJobIndex].isEnabled(); } else { return false; } } + void setDrawHitEffect(bool draw) { enableJob(_drawHitEffectJobIndex, draw); } + bool doDrawHitEffect() const { return getEnableJob(_drawHitEffectJobIndex); } - int _occlusionJobIndex = -1; - void setOcclusionStatus(bool draw) { if (_occlusionJobIndex >= 0) { _jobs[_occlusionJobIndex].setEnabled(draw); } } - bool doOcclusionStatus() const { if (_occlusionJobIndex >= 0) { return _jobs[_occlusionJobIndex].isEnabled(); } else { return false; } } + void setOcclusionStatus(bool draw) { enableJob(_occlusionJobIndex, draw); } + bool doOcclusionStatus() const { return getEnableJob(_occlusionJobIndex); } - int _antialiasingJobIndex = -1; - void setAntialiasingStatus(bool draw) { if (_antialiasingJobIndex >= 0) { _jobs[_antialiasingJobIndex].setEnabled(draw); } } - bool doAntialiasingStatus() const { if (_antialiasingJobIndex >= 0) { return _jobs[_antialiasingJobIndex].isEnabled(); } else { return false; } } + void setAntialiasingStatus(bool draw) { enableJob(_antialiasingJobIndex, draw); } + bool doAntialiasingStatus() const { return getEnableJob(_antialiasingJobIndex); } - int _toneMappingJobIndex = -1; void setToneMappingExposure(float exposure); float getToneMappingExposure() const; @@ -156,11 +147,6 @@ public: int getToneMappingToneCurve() const; virtual void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); - - - gpu::Queries _timerQueries; - int _currentTimerQueryIndex = 0; }; - #endif // hifi_RenderDeferredTask_h diff --git a/libraries/render/src/render/Task.h b/libraries/render/src/render/Task.h index 4d2a3728c6..b63cb88dcf 100644 --- a/libraries/render/src/render/Task.h +++ b/libraries/render/src/render/Task.h @@ -207,12 +207,13 @@ public: virtual ~Task() = default; // Queue a new job to the task; returns the job's index - template size_t addJob(std::string name, A&&... args) { + template const Varying addJob(std::string name, A&&... args) { _jobs.emplace_back(name, std::make_shared(std::forward(args)...)); - return _jobs.size() - 1; + return _jobs.back().getOutput(); } - const Job& getJob(size_t i) const { return _jobs.at(i); } + void enableJob(size_t jobIndex, bool enable = true) { _jobs.at(jobIndex).setEnabled(enable); } + bool getEnableJob(size_t jobIndex) const { return _jobs.at(jobIndex).isEnabled(); } virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {} From 0776ae7e7285746eef65b683e36171c0a8e69b5a Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 14 Jan 2016 12:25:34 -0800 Subject: [PATCH 151/215] Add LightStage for rendering lights --- libraries/octree/src/ViewFrustum.h | 1 + .../src/DeferredLightingEffect.cpp | 6 +- .../render-utils/src/DeferredLightingEffect.h | 27 ++----- libraries/render-utils/src/LightStage.cpp | 79 +++++++++++++++++++ libraries/render-utils/src/LightStage.h | 62 +++++++++++++++ 5 files changed, 150 insertions(+), 25 deletions(-) create mode 100644 libraries/render-utils/src/LightStage.cpp create mode 100644 libraries/render-utils/src/LightStage.h diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index 4a39ac5f44..1c033cc38c 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -162,6 +162,7 @@ private: // Used to project points glm::mat4 _ourModelViewProjectionMatrix; }; +using ViewFrustumPointer = std::shared_ptr; #endif // hifi_ViewFrustum_h diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index a5fce0b377..b5f866166e 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -69,6 +69,8 @@ void DeferredLightingEffect::init() { _allocatedLights.push_back(std::make_shared()); model::LightPointer lp = _allocatedLights[0]; + // Add the global light to the light stage (for later shadow rendering) + _lightStage.addLight(lp); lp->setDirection(-glm::vec3(1.0f, 1.0f, 1.0f)); lp->setColor(glm::vec3(1.0f)); @@ -541,10 +543,6 @@ void DeferredLightingEffect::setGlobalLight(const glm::vec3& direction, const gl light->setAmbientIntensity(ambientIntensity); } -model::LightPointer DeferredLightingEffect::getGlobalLight() { - return _allocatedLights[_globalLights.front()]; -} - void DeferredLightingEffect::setGlobalSkybox(const model::SkyboxPointer& skybox) { _skybox = skybox; } diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index e75961e11a..d11dee7d49 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -21,6 +21,8 @@ #include "model/Stage.h" #include "model/Geometry.h" +#include "LightStage.h" + class RenderArgs; struct LightLocations; using LightLocationsPtr = std::shared_ptr; @@ -50,9 +52,11 @@ public: void setGlobalAtmosphere(const model::AtmospherePointer& atmosphere) { _atmosphere = atmosphere; } void setGlobalSkybox(const model::SkyboxPointer& skybox); - model::LightPointer getGlobalLight(); + const LightStage& getLightStage() { return _lightStage; } private: + LightStage _lightStage; + DeferredLightingEffect() = default; model::MeshPointer _spotLightMesh; @@ -72,26 +76,7 @@ private: gpu::PipelinePointer _spotLight; LightLocationsPtr _spotLightLocations; - class PointLight { - public: - glm::vec4 position; - float radius; - glm::vec4 ambient; - glm::vec4 diffuse; - glm::vec4 specular; - float constantAttenuation; - float linearAttenuation; - float quadraticAttenuation; - }; - - class SpotLight : public PointLight { - public: - glm::vec3 direction; - float exponent; - float cutoff; - }; - - typedef std::vector< model::LightPointer > Lights; + using Lights = std::vector; Lights _allocatedLights; std::vector _globalLights; diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp new file mode 100644 index 0000000000..0e79d7239c --- /dev/null +++ b/libraries/render-utils/src/LightStage.cpp @@ -0,0 +1,79 @@ +// +// LightStage.cpp +// render-utils/src +// +// Created by Zach Pomerantz on 1/14/2015. +// 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 "ViewFrustum.h" + +#include "LightStage.h" + +LightStage::Shadow::Shadow(model::LightPointer light) : _light{ light}, _frustum{ std::make_shared() } { + framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(MAP_SIZE)); + map = framebuffer->getDepthStencilBuffer(); +} + +void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float zBack, float zFront) { + // Orient the keylight frustum + const auto& direction = glm::normalize(_light->getDirection()); + glm::quat orientation; + if (direction == IDENTITY_UP) { + orientation = glm::quat(glm::mat3(IDENTITY_UP, -IDENTITY_FRONT, IDENTITY_RIGHT)); + } else { + auto side = glm::normalize(glm::cross(direction, IDENTITY_UP)); + auto up = glm::normalize(glm::cross(side, direction)); + auto orientation = glm::quat(glm::mat3(direction, up, side)); + } + _frustum->setOrientation(orientation); + + // Position the keylight frustum + _frustum->setPosition(viewFrustum->getPosition() - 21.0f * direction); + + _view = _frustum->getView(); + const Transform viewInverse{ _view.getInverseMatrix() }; + + viewFrustum->calculate(); + //const auto nearCorners = viewFrustum->getCorners(0); + const auto nearClip = viewFrustum->getNearClip(); + const auto nearCorners = viewFrustum->getCorners(nearClip - 1); + const auto farCorners = viewFrustum->getCorners(nearClip + 20); + + vec3 min{ viewInverse.transform(nearCorners.bottomLeft) }; + vec3 max{ min }; + // Expand keylight frustum to fit view frustum + auto fitFrustum = [&min, &max, &viewInverse](const vec3& viewCorner) { + const auto corner = viewInverse.transform(viewCorner); + + min.x = glm::min(min.x, corner.x); + min.y = glm::min(min.y, corner.y); + min.z = glm::min(min.z, corner.z); + + max.x = glm::max(max.x, corner.x); + max.y = glm::max(max.y, corner.y); + max.z = glm::max(max.z, corner.z); + }; + fitFrustum(nearCorners.bottomLeft); + fitFrustum(nearCorners.bottomRight); + fitFrustum(nearCorners.topLeft); + fitFrustum(nearCorners.topRight); + fitFrustum(farCorners.bottomLeft); + fitFrustum(farCorners.bottomRight); + fitFrustum(farCorners.topLeft); + fitFrustum(farCorners.topRight); + + glm::mat4 ortho = glm::ortho(min.x, max.x, min.y, max.y, -max.z, -min.z); + _frustum->setProjection(ortho); + _projection = ortho; +} + +const LightStage::LightPointer& LightStage::addLight(model::LightPointer light) { + Shadow stageShadow{light}; + LightPointer stageLight = std::make_shared(std::move(stageShadow)); + lights.push_back(stageLight); + return stageLight; +} diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h new file mode 100644 index 0000000000..de6e138ace --- /dev/null +++ b/libraries/render-utils/src/LightStage.h @@ -0,0 +1,62 @@ +// +// LightStage.h +// render-utils/src +// +// Created by Zach Pomerantz on 1/14/2015. +// 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_render_utils_LightStage_h +#define hifi_render_utils_LightStage_h + +#include "gpu/Framebuffer.h" + +#include "model/Light.h" + +class ViewFrustum; + +// Light stage to set up light-related rendering tasks +class LightStage { +public: + class Shadow { + public: + const int MAP_SIZE = 2048; + + Shadow(model::LightPointer light); + + void setKeylightFrustum(ViewFrustum* viewFrustum, float zBack, float zFront); + + const std::shared_ptr getFrustum() const { return _frustum; } + const glm::mat4& getProjection() const { return _projection; } + const Transform& getView() const { return _view; } + + gpu::FramebufferPointer framebuffer; + gpu::TexturePointer map; + protected: + model::LightPointer _light; + std::shared_ptr _frustum; + glm::mat4 _projection; + Transform _view; + }; + using ShadowPointer = std::shared_ptr; + + class Light { + public: + Light(Shadow&& shadow) : shadow{ shadow } {} + + model::LightPointer light; + Shadow shadow; + }; + using LightPointer = std::shared_ptr; + using Lights = std::vector; + + const LightPointer& addLight(model::LightPointer light); + // TODO: removeLight + + Lights lights; +}; + +#endif From b9b407fea03d084d2272f0da7b455f8dd4d81963 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 14 Jan 2016 12:47:21 -0800 Subject: [PATCH 152/215] Remove static shadowMap --- libraries/render-utils/src/FramebufferCache.cpp | 8 -------- libraries/render-utils/src/FramebufferCache.h | 6 +++--- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index 9f3d4ba0fe..4b2919e931 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -183,14 +183,6 @@ void FramebufferCache::releaseFramebuffer(const gpu::FramebufferPointer& framebu } } -gpu::FramebufferPointer FramebufferCache::getShadowFramebuffer() { - if (!_shadowFramebuffer) { - const int SHADOW_MAP_SIZE = 2048; - _shadowFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(SHADOW_MAP_SIZE)); - } - return _shadowFramebuffer; -} - gpu::FramebufferPointer FramebufferCache::getSelfieFramebuffer() { if (!_selfieFramebuffer) { createPrimaryFramebuffer(); diff --git a/libraries/render-utils/src/FramebufferCache.h b/libraries/render-utils/src/FramebufferCache.h index 7ac5e4af63..911c6f98dc 100644 --- a/libraries/render-utils/src/FramebufferCache.h +++ b/libraries/render-utils/src/FramebufferCache.h @@ -23,6 +23,9 @@ class FramebufferCache : public Dependency { SINGLETON_DEPENDENCY public: + // Shadow map size is static + static const int SHADOW_MAP_SIZE = 2048; + /// Sets the desired texture resolution for the framebuffer objects. void setFrameBufferSize(QSize frameBufferSize); const QSize& getFrameBufferSize() const { return _frameBufferSize; } @@ -45,9 +48,6 @@ public: gpu::TexturePointer getLightingTexture(); gpu::FramebufferPointer getLightingFramebuffer(); - /// Returns the framebuffer object used to render shadow maps; - gpu::FramebufferPointer getShadowFramebuffer(); - /// Returns the framebuffer object used to render selfie maps; gpu::FramebufferPointer getSelfieFramebuffer(); From 7744b89ba5be016d6f3cb22ebbd8ae84d175ae56 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 14 Jan 2016 12:48:27 -0800 Subject: [PATCH 153/215] Prepare shadowMap pipeline to debug in color --- libraries/gpu/src/gpu/Framebuffer.cpp | 9 +++- .../render-utils/src/DebugDeferredBuffer.cpp | 49 ++++++++++++------- .../render-utils/src/DebugDeferredBuffer.h | 1 + libraries/render-utils/src/model_shadow.slf | 6 +-- .../render-utils/src/skin_model_shadow.slf | 20 ++++++++ 5 files changed, 62 insertions(+), 23 deletions(-) create mode 100644 libraries/render-utils/src/skin_model_shadow.slf diff --git a/libraries/gpu/src/gpu/Framebuffer.cpp b/libraries/gpu/src/gpu/Framebuffer.cpp index ea650c6ad9..404ffa0a91 100755 --- a/libraries/gpu/src/gpu/Framebuffer.cpp +++ b/libraries/gpu/src/gpu/Framebuffer.cpp @@ -49,7 +49,9 @@ Framebuffer* Framebuffer::create( const Format& colorBufferFormat, const Format& Framebuffer* Framebuffer::createShadowmap(uint16 width) { auto framebuffer = Framebuffer::create(); - auto depthTexture = TexturePointer(Texture::create2D(Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH), width, width)); + + auto depthFormat = Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); // Depth32 texel format + auto depthTexture = TexturePointer(Texture::create2D(depthFormat, width, width)); Sampler::Desc samplerDesc; samplerDesc._borderColor = glm::vec4(1.0f); @@ -59,8 +61,11 @@ Framebuffer* Framebuffer::createShadowmap(uint16 width) { samplerDesc._comparisonFunc = LESS_EQUAL; depthTexture->setSampler(Sampler(samplerDesc)); + framebuffer->setDepthStencilBuffer(depthTexture, depthFormat); - framebuffer->setDepthStencilBuffer(depthTexture, Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH)); + // Use a render buffer to allow use of the DebugDeferredBuffer Job + gpu::TexturePointer colorbuffer{gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, width)}; + framebuffer->setRenderBuffer(0, colorbuffer); return framebuffer; } diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index ab2fa403f1..e76a843121 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -20,6 +20,7 @@ #include "GeometryCache.h" #include "FramebufferCache.h" +#include "DeferredLightingEffect.h" #include "debug_deferred_buffer_vert.h" #include "debug_deferred_buffer_frag.h" @@ -31,45 +32,53 @@ enum Slots { Normal, Specular, Depth, - Lighting + Lighting, + Shadow }; -static const std::string DEEFAULT_DIFFUSE_SHADER { +static const std::string DEFAULT_DIFFUSE_SHADER { "vec4 getFragmentColor() {" " return vec4(pow(texture(diffuseMap, uv).xyz, vec3(1.0 / 2.2)), 1.0);" " }" }; -static const std::string DEEFAULT_ALPHA_SHADER { +static const std::string DEFAULT_ALPHA_SHADER { "vec4 getFragmentColor() {" " return vec4(vec3(texture(diffuseMap, uv).a), 1.0);" " }" }; -static const std::string DEEFAULT_SPECULAR_SHADER { +static const std::string DEFAULT_SPECULAR_SHADER { "vec4 getFragmentColor() {" " return vec4(texture(specularMap, uv).xyz, 1.0);" " }" }; -static const std::string DEEFAULT_ROUGHNESS_SHADER { +static const std::string DEFAULT_ROUGHNESS_SHADER { "vec4 getFragmentColor() {" " return vec4(vec3(texture(specularMap, uv).a), 1.0);" " }" }; -static const std::string DEEFAULT_NORMAL_SHADER { +static const std::string DEFAULT_NORMAL_SHADER { "vec4 getFragmentColor() {" " return vec4(normalize(texture(normalMap, uv).xyz), 1.0);" " }" }; -static const std::string DEEFAULT_DEPTH_SHADER { +static const std::string DEFAULT_DEPTH_SHADER { "vec4 getFragmentColor() {" " return vec4(vec3(texture(depthMap, uv).x), 1.0);" " }" }; -static const std::string DEEFAULT_LIGHTING_SHADER { +static const std::string DEFAULT_LIGHTING_SHADER { "vec4 getFragmentColor() {" " return vec4(pow(texture(lightingMap, uv).xyz, vec3(1.0 / 2.2)), 1.0);" " }" }; -static const std::string DEEFAULT_CUSTOM_SHADER { +static const std::string DEFAULT_SHADOW_SHADER { + "uniform sampler2D shadowMapColor;" + // The actual shadowMap is a sampler2DShadow, so we cannot normally sample it + "vec4 getFragmentColor() {" + " return vec4(texture(shadowMapColor, uv).xyz, 1.0);" + " }" +}; +static const std::string DEFAULT_CUSTOM_SHADER { "vec4 getFragmentColor() {" " return vec4(1.0, 0.0, 0.0, 1.0);" " }" @@ -98,21 +107,23 @@ DebugDeferredBuffer::DebugDeferredBuffer() { std::string DebugDeferredBuffer::getShaderSourceCode(Modes mode, std::string customFile) { switch (mode) { case DiffuseMode: - return DEEFAULT_DIFFUSE_SHADER; + return DEFAULT_DIFFUSE_SHADER; case AlphaMode: - return DEEFAULT_ALPHA_SHADER; + return DEFAULT_ALPHA_SHADER; case SpecularMode: - return DEEFAULT_SPECULAR_SHADER; + return DEFAULT_SPECULAR_SHADER; case RoughnessMode: - return DEEFAULT_ROUGHNESS_SHADER; + return DEFAULT_ROUGHNESS_SHADER; case NormalMode: - return DEEFAULT_NORMAL_SHADER; + return DEFAULT_NORMAL_SHADER; case DepthMode: - return DEEFAULT_DEPTH_SHADER; + return DEFAULT_DEPTH_SHADER; case LightingMode: - return DEEFAULT_LIGHTING_SHADER; + return DEFAULT_LIGHTING_SHADER; + case ShadowMode: + return DEFAULT_SHADOW_SHADER; case CustomMode: - return getFileContent(customFile, DEEFAULT_CUSTOM_SHADER); + return getFileContent(customFile, DEFAULT_CUSTOM_SHADER); } Q_UNREACHABLE(); return std::string(); @@ -158,6 +169,7 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Modes mode, std::st slotBindings.insert(gpu::Shader::Binding("specularMap", Specular)); slotBindings.insert(gpu::Shader::Binding("depthMap", Depth)); slotBindings.insert(gpu::Shader::Binding("lightingMap", Lighting)); + slotBindings.insert(gpu::Shader::Binding("shadowMapColor", Shadow)); gpu::Shader::makeProgram(*program, slotBindings); auto pipeline = gpu::Pipeline::create(program, std::make_shared()); @@ -193,7 +205,7 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { const auto geometryBuffer = DependencyManager::get(); const auto framebufferCache = DependencyManager::get(); - + const auto& lightStage = DependencyManager::get()->getLightStage(); glm::mat4 projMat; Transform viewMat; @@ -213,6 +225,7 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren batch.setResourceTexture(Specular, framebufferCache->getDeferredSpecularTexture()); batch.setResourceTexture(Depth, framebufferCache->getPrimaryDepthTexture()); batch.setResourceTexture(Lighting, framebufferCache->getLightingTexture()); + batch.setResourceTexture(Shadow, lightStage.lights[0]->shadow.framebuffer->getRenderBuffer(0)); const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); const glm::vec2 bottomLeft(renderContext->_deferredDebugSize.x, renderContext->_deferredDebugSize.y); diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index c9ea24644a..eba48cd0c3 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -33,6 +33,7 @@ private: NormalMode, DepthMode, LightingMode, + ShadowMode, CustomMode // Needs to stay last }; diff --git a/libraries/render-utils/src/model_shadow.slf b/libraries/render-utils/src/model_shadow.slf index d691104bdd..fd35ec11d7 100755 --- a/libraries/render-utils/src/model_shadow.slf +++ b/libraries/render-utils/src/model_shadow.slf @@ -12,9 +12,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -out vec4 _fragColor; +layout(location = 0) out vec4 _fragColor; void main(void) { - // fixed color for now (we may eventually want to use texture alpha) - _fragColor = vec4(1.0, 1.0, 1.0, 0.0); + // stencil in solid color for debugging + _fragColor = vec4(0.0, 0.0, 1.0, 1.0); } diff --git a/libraries/render-utils/src/skin_model_shadow.slf b/libraries/render-utils/src/skin_model_shadow.slf new file mode 100644 index 0000000000..85d1b7424b --- /dev/null +++ b/libraries/render-utils/src/skin_model_shadow.slf @@ -0,0 +1,20 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_shadow.frag +// fragment shader +// +// Created by Andrzej Kapolka on 3/24/14. +// 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 +// + +layout(location = 0) out vec4 _fragColor; + +void main(void) { + // stencil in solid color for debugging + _fragColor = vec4(1.0, 0.0, 0.0, 1.0); +} From 51d678670d73641ab28eabc2f2401479e542c101 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 14 Jan 2016 12:57:30 -0800 Subject: [PATCH 154/215] Updated grab animations for right hand --- .../resources/meshes/defaultAvatar_full/avatar-animation.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index 04b596e000..cbd7b08a16 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -145,7 +145,7 @@ "id": "rightHandGraspOpen", "type": "clip", "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hydra_pose_right.fbx", + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hydra_pose_open_right_v2.fbx", "startFrame": 0.0, "endFrame": 0.0, "timeScale": 1.0, @@ -157,7 +157,7 @@ "id": "rightHandGraspClosed", "type": "clip", "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hydra_pose_close_right.fbx", + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hydra_pose_close_right_v2.fbx", "startFrame": 0.0, "endFrame": 0.0, "timeScale": 1.0, From 2177765b090d09e6067b45725815f47c5c6396a7 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 14 Jan 2016 13:11:11 -0800 Subject: [PATCH 155/215] wire up audio show level meter menu --- interface/resources/qml/AvatarInputs.qml | 2 +- interface/src/Menu.cpp | 5 ++--- interface/src/Menu.h | 3 ++- interface/src/ui/AvatarInputs.cpp | 1 + interface/src/ui/AvatarInputs.h | 4 +++- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/interface/resources/qml/AvatarInputs.qml b/interface/resources/qml/AvatarInputs.qml index ce729d468d..fb989dd174 100644 --- a/interface/resources/qml/AvatarInputs.qml +++ b/interface/resources/qml/AvatarInputs.qml @@ -86,7 +86,7 @@ Hifi.AvatarInputs { id: controls width: root.mirrorWidth height: 44 - visible: !root.isHMD + visible: root.showAudioTools anchors.top: mirror.bottom Rectangle { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index eec04d4640..09edfeac0e 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -156,9 +156,8 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(audioMenu, MenuOption::MuteAudio, Qt::CTRL | Qt::Key_M, false, audioIO.data(), SLOT(toggleMute())); - // Audio > Level Meter [advanced] -- FIXME: needs implementation - auto levelMeterAction = addCheckableActionToQMenuAndActionHash(audioMenu, "Level Meter", 0, false, NULL, NULL, UNSPECIFIED_POSITION, "Advanced"); - levelMeterAction->setDisabled(true); + // Audio > Show Level Meter + addCheckableActionToQMenuAndActionHash(audioMenu, MenuOption::AudioTools, 0, true); // Avatar menu ---------------------------------- diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 6a544f31c9..6bf66f1200 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -156,6 +156,7 @@ namespace MenuOption { const QString AssetMigration = "ATP Asset Migration"; const QString Atmosphere = "Atmosphere"; const QString Attachments = "Attachments..."; + const QString AudioNetworkStats = "Audio Network Stats"; const QString AudioNoiseReduction = "Audio Noise Reduction"; const QString AudioScope = "Show Scope"; const QString AudioScopeFiftyFrames = "Fifty"; @@ -163,8 +164,8 @@ namespace MenuOption { const QString AudioScopeFrames = "Display Frames"; const QString AudioScopePause = "Pause Scope"; const QString AudioScopeTwentyFrames = "Twenty"; - const QString AudioNetworkStats = "Audio Network Stats"; const QString AudioStatsShowInjectedStreams = "Audio Stats Show Injected Streams"; + const QString AudioTools = "Show Level Meter"; const QString AutoMuteAudio = "Auto Mute Microphone"; const QString AvatarReceiveStats = "Show Receive Stats"; const QString Back = "Back"; diff --git a/interface/src/ui/AvatarInputs.cpp b/interface/src/ui/AvatarInputs.cpp index fa6eaf072d..b09289c78a 100644 --- a/interface/src/ui/AvatarInputs.cpp +++ b/interface/src/ui/AvatarInputs.cpp @@ -67,6 +67,7 @@ void AvatarInputs::update() { AI_UPDATE(cameraEnabled, !Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking)); AI_UPDATE(cameraMuted, Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking)); AI_UPDATE(isHMD, qApp->isHMDMode()); + AI_UPDATE(showAudioTools, Menu::getInstance()->isOptionChecked(MenuOption::AudioTools)); auto audioIO = DependencyManager::get(); const float AUDIO_METER_AVERAGING = 0.5; diff --git a/interface/src/ui/AvatarInputs.h b/interface/src/ui/AvatarInputs.h index 36d3027a42..85570ecd3c 100644 --- a/interface/src/ui/AvatarInputs.h +++ b/interface/src/ui/AvatarInputs.h @@ -17,7 +17,7 @@ public: \ type name() { return _##name; }; \ private: \ - type _##name{ initialValue }; + type _##name{ initialValue }; class AvatarInputs : public QQuickItem { Q_OBJECT @@ -31,6 +31,7 @@ class AvatarInputs : public QQuickItem { AI_PROPERTY(bool, mirrorVisible, false) AI_PROPERTY(bool, mirrorZoomed, true) AI_PROPERTY(bool, isHMD, false) + AI_PROPERTY(bool, showAudioTools, true) public: static AvatarInputs* getInstance(); @@ -46,6 +47,7 @@ signals: void mirrorVisibleChanged(); void mirrorZoomedChanged(); void isHMDChanged(); + void showAudioToolsChanged(); protected: Q_INVOKABLE void resetSensors(); From 0ad39feeb60eb154f2b516c2351a9d9a22b74699 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 14 Jan 2016 13:31:01 -0800 Subject: [PATCH 156/215] juggle developer menus a bit --- interface/src/Menu.cpp | 46 +++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 09edfeac0e..377d97bc30 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -324,8 +324,10 @@ Menu::Menu() { // Developer > Render >>> MenuWrapper* renderOptionsMenu = developerMenu->addMenu("Render"); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, 0, true); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::WorldAxes); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DebugAmbientOcclusion); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Antialiasing); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, 0, true); // Developer > Render > Ambient Light MenuWrapper* ambientLightMenu = renderOptionsMenu->addMenu(MenuOption::RenderAmbientLight); @@ -356,15 +358,8 @@ Menu::Menu() { resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionThird, 0, false)); resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionQuarter, 0, false)); - // Developer > Render > Stars - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, - 0, // QML Qt::Key_Asterisk, - true); - // Developer > Render > LOD Tools - addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, - 0, // QML Qt::SHIFT | Qt::Key_L, - dialogsManager.data(), SLOT(lodTools())); + addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, 0, dialogsManager.data(), SLOT(lodTools())); // Developer > Assets >>> MenuWrapper* assetDeveloperMenu = developerMenu->addMenu("Assets"); @@ -497,6 +492,12 @@ Menu::Menu() { MenuWrapper* leapOptionsMenu = handOptionsMenu->addMenu("Leap Motion"); addCheckableActionToQMenuAndActionHash(leapOptionsMenu, MenuOption::LeapMotionOnHMD, 0, false); + // Developer > Entities >>> + MenuWrapper* entitiesOptionsMenu = developerMenu->addMenu("Entities"); + addActionToQMenuAndActionHash(entitiesOptionsMenu, MenuOption::OctreeStats, 0, + dialogsManager.data(), SLOT(octreeStatsDetails())); + addCheckableActionToQMenuAndActionHash(entitiesOptionsMenu, MenuOption::ShowRealtimeEntityStats); + // Developer > Network >>> MenuWrapper* networkMenu = developerMenu->addMenu("Network"); addActionToQMenuAndActionHash(networkMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches())); @@ -513,12 +514,14 @@ Menu::Menu() { dialogsManager.data(), SLOT(cachesSizeDialog())); addActionToQMenuAndActionHash(networkMenu, MenuOption::DiskCacheEditor, 0, dialogsManager.data(), SLOT(toggleDiskCacheEditor())); - addActionToQMenuAndActionHash(networkMenu, MenuOption::ShowDSConnectTable, 0, dialogsManager.data(), SLOT(showDomainConnectionDialog())); + addActionToQMenuAndActionHash(networkMenu, MenuOption::BandwidthDetails, 0, + dialogsManager.data(), SLOT(bandwidthDetails())); - // Developer > Timing and Stats >>> - MenuWrapper* timingMenu = developerMenu->addMenu("Timing and Stats"); + + // Developer > Timing >>> + MenuWrapper* timingMenu = developerMenu->addMenu("Timing"); MenuWrapper* perfTimerMenu = timingMenu->addMenu("Performance Timer"); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayDebugTimingDetails, 0, false); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::OnlyDisplayTopTen, 0, true); @@ -533,7 +536,6 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::PipelineWarnings); addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::LogExtraTimings); addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::SuppressShortTimings); - addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::ShowRealtimeEntityStats); // Developer > Audio >>> MenuWrapper* audioDebugMenu = developerMenu->addMenu("Audio"); @@ -570,6 +572,10 @@ Menu::Menu() { audioScopeFramesGroup->addAction(fiftyFrames); } + // Developer > Audio > Audio Network Stats... + addActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioNetworkStats, 0, + dialogsManager.data(), SLOT(audioStatsDetails())); + // Developer > Physics >>> MenuWrapper* physicsOptionsMenu = developerMenu->addMenu("Physics"); addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowOwned); @@ -587,22 +593,6 @@ Menu::Menu() { // Developer > Stats addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::Stats); - // Developer > Audio Stats... - addActionToQMenuAndActionHash(developerMenu, MenuOption::AudioNetworkStats, 0, - dialogsManager.data(), SLOT(audioStatsDetails())); - - // Developer > Bandwidth Stats... - addActionToQMenuAndActionHash(developerMenu, MenuOption::BandwidthDetails, 0, - dialogsManager.data(), SLOT(bandwidthDetails())); - - // Developer > Entity Stats... - addActionToQMenuAndActionHash(developerMenu, MenuOption::OctreeStats, 0, - dialogsManager.data(), SLOT(octreeStatsDetails())); - - // Developer > World Axes - addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::WorldAxes); - - #if 0 /// -------------- REMOVED FOR NOW -------------- addDisabledActionAndSeparator(navigateMenu, "History"); From c704a8d8c56f8455960e7cc96a0ac99cf25c24d1 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 14 Jan 2016 13:53:11 -0800 Subject: [PATCH 157/215] Add RenderShadowTask --- .../render-utils/src/RenderShadowTask.cpp | 128 ++++++++++++++++++ libraries/render-utils/src/RenderShadowTask.h | 41 ++++++ libraries/render/src/render/DrawTask.h | 1 + 3 files changed, 170 insertions(+) create mode 100644 libraries/render-utils/src/RenderShadowTask.cpp create mode 100644 libraries/render-utils/src/RenderShadowTask.h diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp new file mode 100644 index 0000000000..1447da624d --- /dev/null +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -0,0 +1,128 @@ +// +// RenderShadowTask.cpp +// render-utils/src/ +// +// Created by Zach Pomerantz on 1/7/2016. +// Copyright 2016 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 "DeferredLightingEffect.h" +#include "FramebufferCache.h" + +#include "RenderShadowTask.h" + +#include "model_shadow_vert.h" +#include "skin_model_shadow_vert.h" + +#include "model_shadow_frag.h" +#include "skin_model_shadow_frag.h" + +using namespace render; + +void RenderShadowMap::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, + const render::ItemIDsBounds& inItems) { + assert(renderContext->getArgs()); + assert(renderContext->getArgs()->_viewFrustum); + + const auto& lightStage = DependencyManager::get()->getLightStage(); + const auto globalLight = lightStage.lights[0]; + const auto& shadow = globalLight->shadow; + const auto& fbo = shadow.framebuffer; + + RenderArgs* args = renderContext->getArgs(); + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + args->_batch = &batch; + + glm::ivec4 viewport{0, 0, fbo->getWidth(), fbo->getHeight()}; + batch.setViewportTransform(viewport); + batch.setStateScissorRect(viewport); + + batch.setFramebuffer(fbo); + batch.clearFramebuffer( + gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH, + vec4(vec3(1.0, 1.0, 1.0), 1.0), 1.0, 0, true); + + batch.setProjectionTransform(shadow.getProjection()); + batch.setViewTransform(shadow.getView()); + + renderShapes(sceneContext, renderContext, _shapePlumber, inItems); + args->_batch = nullptr; + }); +} + +RenderShadowTask::RenderShadowTask() : Task() { + // Prepare the ShapePipeline + ShapePlumberPointer shapePlumber = std::make_shared(); + { + auto state = std::make_shared(); + state->setCullMode(gpu::State::CULL_BACK); + state->setDepthTest(true, true, gpu::LESS_EQUAL); + + auto modelVertex = gpu::Shader::createVertex(std::string(model_shadow_vert)); + auto modelPixel = gpu::Shader::createPixel(std::string(model_shadow_frag)); + gpu::ShaderPointer modelProgram = gpu::Shader::createProgram(modelVertex, modelPixel); + shapePlumber->addPipeline( + ShapeKey::Filter::Builder().withoutSkinned(), + modelProgram, state); + + auto skinVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert)); + auto skinPixel = gpu::Shader::createPixel(std::string(skin_model_shadow_frag)); + gpu::ShaderPointer skinProgram = gpu::Shader::createProgram(skinVertex, skinPixel); + shapePlumber->addPipeline( + ShapeKey::Filter::Builder().withSkinned(), + skinProgram, state); + } + + // CPU: Fetch shadow-casting opaques + addJob("FetchShadowMap"); + + // CPU: Cull against KeyLight frustum (nearby viewing camera) + addJob>("CullShadowMap", _jobs.back().getOutput()); + + // CPU: Sort front to back + addJob("DepthSortShadowMap", _jobs.back().getOutput()); + + // GPU: Render to shadow map + addJob("RenderShadowMap", _jobs.back().getOutput(), shapePlumber); +} + +void RenderShadowTask::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + assert(sceneContext); + RenderArgs* args = renderContext->getArgs(); + + // sanity checks + if (!sceneContext->_scene || !args) { + return; + } + + // TODO: If we're not using the global keylight, bail + const auto& lightStage = DependencyManager::get()->getLightStage(); + const auto globalLight = lightStage.lights[0]; + + // If the global light is not set, bail + if (!globalLight) { + return; + } + + ViewFrustum* viewFrustum = args->_viewFrustum; + + const auto nearClip = viewFrustum->getNearClip(); + globalLight->shadow.setKeylightFrustum(viewFrustum, nearClip - 1, nearClip + 20); + + // Set the keylight frustum + args->_viewFrustum = globalLight->shadow.getFrustum().get(); + + for (auto job : _jobs) { + job.run(sceneContext, renderContext); + } + + // Reset the view frustum + args->_viewFrustum = viewFrustum; +}; diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h new file mode 100644 index 0000000000..333ed18c84 --- /dev/null +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -0,0 +1,41 @@ +// +// RenderShadowTask.h +// render-utils/src/ +// +// Created by Zach Pomerantz on 1/7/2016. +// Copyright 2016 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_RenderShadowTask_h +#define hifi_RenderShadowTask_h + +#include +#include + +#include +#include + +class ViewFrustum; + +class RenderShadowMap { +public: + RenderShadowMap(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, + const render::ItemIDsBounds& inItems); + + using JobModel = render::Task::Job::ModelI; +protected: + render::ShapePlumberPointer _shapePlumber; +}; + +class RenderShadowTask : public render::Task { +public: + RenderShadowTask(); + + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); +}; + +#endif // hifi_RenderShadowTask_h diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index b31ec9763e..3c2c0973b2 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -28,6 +28,7 @@ void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPo class FetchItems { public: typedef std::function ProbeNumItems; + FetchItems() {} FetchItems(const ProbeNumItems& probe): _probeNumItems(probe) {} FetchItems(const ItemFilter& filter, const ProbeNumItems& probe): _filter(filter), _probeNumItems(probe) {} From ec496f1907c0e103db10f28513518612421d18b4 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 14 Jan 2016 14:06:07 -0800 Subject: [PATCH 158/215] Return copy of Light from LightStage --- libraries/render-utils/src/LightStage.cpp | 2 +- libraries/render-utils/src/LightStage.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 0e79d7239c..de0041ae00 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -71,7 +71,7 @@ void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float zBac _projection = ortho; } -const LightStage::LightPointer& LightStage::addLight(model::LightPointer light) { +const LightStage::LightPointer LightStage::addLight(model::LightPointer light) { Shadow stageShadow{light}; LightPointer stageLight = std::make_shared(std::move(stageShadow)); lights.push_back(stageLight); diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index de6e138ace..28ffd2ca0f 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -53,7 +53,7 @@ public: using LightPointer = std::shared_ptr; using Lights = std::vector; - const LightPointer& addLight(model::LightPointer light); + const LightPointer addLight(model::LightPointer light); // TODO: removeLight Lights lights; From e76e13c05c53178cc746a4c4dcbedefca92096bc Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 14 Jan 2016 14:20:31 -0800 Subject: [PATCH 159/215] Removing close button on tool window, fixing dragging --- interface/resources/qml/ToolWindow.qml | 1 + interface/resources/qml/windows/DefaultFrame.qml | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/ToolWindow.qml b/interface/resources/qml/ToolWindow.qml index 3ce5b5616d..b2529ff522 100644 --- a/interface/resources/qml/ToolWindow.qml +++ b/interface/resources/qml/ToolWindow.qml @@ -13,6 +13,7 @@ Windows.Window { objectName: "ToolWindow" destroyOnCloseButton: false destroyOnInvisible: false + closable: false visible: false property string newTabSource property alias tabView: tabView diff --git a/interface/resources/qml/windows/DefaultFrame.qml b/interface/resources/qml/windows/DefaultFrame.qml index ed8999da04..c9d41a6935 100644 --- a/interface/resources/qml/windows/DefaultFrame.qml +++ b/interface/resources/qml/windows/DefaultFrame.qml @@ -27,7 +27,8 @@ Frame { Rectangle { id: decoration anchors { margins: -iconSize; topMargin: -iconSize * (window.closable ? 2 : 1); } - visible: window.activator.containsMouse + // FIXME doesn't work + // visible: window.activator.containsMouse anchors.fill: parent; color: "#7f7f7f7f"; radius: 3; From 90516d95f2d803c4ad527852810cb4ee1f0a5350 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 14 Jan 2016 16:22:58 -0800 Subject: [PATCH 160/215] Updated animations for left hand grasp --- .../meshes/defaultAvatar_full/avatar-animation.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index cbd7b08a16..629b9bc1f9 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -145,7 +145,7 @@ "id": "rightHandGraspOpen", "type": "clip", "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hydra_pose_open_right_v2.fbx", + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hydra_pose_open_right.fbx", "startFrame": 0.0, "endFrame": 0.0, "timeScale": 1.0, @@ -157,7 +157,7 @@ "id": "rightHandGraspClosed", "type": "clip", "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hydra_pose_close_right_v2.fbx", + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hydra_pose_closed_right.fbx", "startFrame": 0.0, "endFrame": 0.0, "timeScale": 1.0, @@ -205,7 +205,7 @@ "id": "leftHandGraspOpen", "type": "clip", "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_left.fbx", + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hydra_pose_open_left.fbx", "startFrame": 0.0, "endFrame": 0.0, "timeScale": 1.0, @@ -217,7 +217,7 @@ "id": "leftHandGraspClosed", "type": "clip", "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_left.fbx", + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hydra_pose_closed_left.fbx", "startFrame": 10.0, "endFrame": 10.0, "timeScale": 1.0, From d4491a9ec2a1a5befcaac962aeca44cace6afec8 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 14 Jan 2016 17:13:07 -0800 Subject: [PATCH 161/215] added dice icon back to dice.js script --- examples/dice.js | 59 ++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/examples/dice.js b/examples/dice.js index ee88984b75..29b522f16b 100644 --- a/examples/dice.js +++ b/examples/dice.js @@ -33,11 +33,11 @@ var BUTTON_SIZE = 32; var PADDING = 3; Script.include(["libraries/toolBars.js"]); -var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.dice.toolbar", function (screenSize) { - return { - x: (screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING), - y: (screenSize.y - (BUTTON_SIZE + PADDING)) - }; +var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.dice.toolbar", function(screenSize) { + return { + x: (screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING), + y: (screenSize.y - (BUTTON_SIZE + PADDING)) + }; }); var offButton = toolBar.addOverlay("image", { width: BUTTON_SIZE, @@ -65,12 +65,13 @@ var deleteButton = toolBar.addOverlay("image", { alpha: 1 }); +var diceIconURL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/images/dice.png" var diceButton = toolBar.addOverlay("image", { x: screenSize.x / 2 + PADDING, y: screenSize.y - (BUTTON_SIZE + PADDING), width: BUTTON_SIZE, height: BUTTON_SIZE, - imageURL: HIFI_PUBLIC_BUCKET + "images/die.png", + imageURL: diceIconURL, color: { red: 255, green: 255, @@ -79,6 +80,7 @@ var diceButton = toolBar.addOverlay("image", { alpha: 1 }); + var GRAVITY = -3.5; // NOTE: angularVelocity is in radians/sec @@ -90,28 +92,27 @@ function shootDice(position, velocity) { Window.alert(INSUFFICIENT_PERMISSIONS_ERROR_MSG); } else { for (var i = 0; i < NUMBER_OF_DICE; i++) { - dice.push(Entities.addEntity( - { - type: "Model", - modelURL: HIFI_PUBLIC_BUCKET + "models/props/Dice/goldDie.fbx", - position: position, - velocity: velocity, - rotation: Quat.fromPitchYawRollDegrees(Math.random() * 360, Math.random() * 360, Math.random() * 360), - angularVelocity: { - x: Math.random() * MAX_ANGULAR_SPEED, - y: Math.random() * MAX_ANGULAR_SPEED, - z: Math.random() * MAX_ANGULAR_SPEED - }, - gravity: { - x: 0, - y: GRAVITY, - z: 0 - }, - lifetime: LIFETIME, - shapeType: "box", - collisionsWillMove: true, - collisionSoundURL: "http://s3.amazonaws.com/hifi-public/sounds/dice/diceCollide.wav" - })); + dice.push(Entities.addEntity({ + type: "Model", + modelURL: HIFI_PUBLIC_BUCKET + "models/props/Dice/goldDie.fbx", + position: position, + velocity: velocity, + rotation: Quat.fromPitchYawRollDegrees(Math.random() * 360, Math.random() * 360, Math.random() * 360), + angularVelocity: { + x: Math.random() * MAX_ANGULAR_SPEED, + y: Math.random() * MAX_ANGULAR_SPEED, + z: Math.random() * MAX_ANGULAR_SPEED + }, + gravity: { + x: 0, + y: GRAVITY, + z: 0 + }, + lifetime: LIFETIME, + shapeType: "box", + collisionsWillMove: true, + collisionSoundURL: "http://s3.amazonaws.com/hifi-public/sounds/dice/diceCollide.wav" + })); position = Vec3.sum(position, Vec3.multiply(DIE_SIZE, Vec3.normalize(Quat.getRight(Camera.getOrientation())))); } } @@ -150,4 +151,4 @@ function scriptEnding() { } Controller.mousePressEvent.connect(mousePressEvent); -Script.scriptEnding.connect(scriptEnding); +Script.scriptEnding.connect(scriptEnding); \ No newline at end of file From e2158e48a1995bb5913d42fa56e016ba5b90609b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 14 Jan 2016 18:03:58 -0800 Subject: [PATCH 162/215] Declare Corners explicitly --- libraries/octree/src/ViewFrustum.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index 1c033cc38c..da7822e1a6 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -61,7 +61,7 @@ public: float getFarClip() const { return _farClip; } float getFocalLength() const { return _focalLength; } - const class Corners{ + class Corners { public: Corners(glm::vec3&& topLeft, glm::vec3&& topRight, glm::vec3&& bottomLeft, glm::vec3&& bottomRight) : topLeft{ topLeft }, topRight{ topRight }, bottomLeft{ bottomLeft }, bottomRight{ bottomRight } {} @@ -70,7 +70,8 @@ public: glm::vec3 bottomLeft; glm::vec3 bottomRight; // Get the corners depth units from frustum position, along frustum orientation - } getCorners(const float& depth); + }; + const Corners getCorners(const float& depth); // getters for corners const glm::vec3& getFarTopLeft() const { return _cornersWorld[TOP_LEFT_FAR]; } From 40279c8fc5ac1483c466f4bae7b11a46bdc39a2b Mon Sep 17 00:00:00 2001 From: EdgarPironti Date: Thu, 14 Jan 2016 18:20:40 -0800 Subject: [PATCH 163/215] Item, Review, Shop and Vendor scripts. --- examples/vrShop/item/shopItemEntityScript.js | 389 ++++++++ examples/vrShop/item/shopItemGrab.js | 862 ++++++++++++++++++ .../vrShop/review/shopReviewEntityScript.js | 477 ++++++++++ examples/vrShop/review/shopReviewerAC.js | 96 ++ .../shop/shopGrabSwapperEntityScript.js | 55 ++ examples/vrShop/vendor/shopVendorAddItem.js | 101 ++ 6 files changed, 1980 insertions(+) create mode 100644 examples/vrShop/item/shopItemEntityScript.js create mode 100644 examples/vrShop/item/shopItemGrab.js create mode 100644 examples/vrShop/review/shopReviewEntityScript.js create mode 100644 examples/vrShop/review/shopReviewerAC.js create mode 100644 examples/vrShop/shop/shopGrabSwapperEntityScript.js create mode 100644 examples/vrShop/vendor/shopVendorAddItem.js diff --git a/examples/vrShop/item/shopItemEntityScript.js b/examples/vrShop/item/shopItemEntityScript.js new file mode 100644 index 0000000000..0b54df0f90 --- /dev/null +++ b/examples/vrShop/item/shopItemEntityScript.js @@ -0,0 +1,389 @@ +// shopItemEntityScript.js +// +// This script makes the shop items react properly to the grab (see shopItemGrab.js) and gives it the capability to interact with the shop environment (inspection entity and cart) +// The first time the item is grabbed a copy of itself is created on the shelf. +// If the item isn't held by the user it can be inInspect or inCart, otherwise it's destroyed +// The start and release grab methods handle the creation of the item copy, UI, inspection entity +// If the item is released into a valid zone, the doSomething() method of that zone is called and the item sends its ID + +// Created by Alessandro Signa and Edgar Pironti on 01/13/2016 +// Copyright 2016 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 +// + +(function() { + var utilitiesScript = Script.resolvePath("../../libraries/utils.js"); + var overlayManagerScript = Script.resolvePath("../../libraries/overlayManager.js"); + var inspectEntityScript = Script.resolvePath("../inspect/shopInspectEntityScript.js"); + + Script.include(utilitiesScript); + Script.include(overlayManagerScript); + + + var RED_IMAGE_URL = "https://dl.dropboxusercontent.com/u/14127429/FBX/VRshop/inspRED.png"; + var GREEN_IMAGE_URL = "https://dl.dropboxusercontent.com/u/14127429/FBX/VRshop/inspGREEN.png"; + var MIN_DIMENSION_THRESHOLD = null; + var MAX_DIMENSION_THRESHOLD = null; + var PENETRATION_THRESHOLD = 0.2; + var MAPPING_NAME = "controllerMapping_Inspection"; + var SHOPPING_CART_NAME = "Shopping cart"; + + var _this; + var onShelf = true; + var inspecting = false; + var inCart = false; + var overlayInspectRed = true; + var zoneID = null; + var newPosition; + var originalDimensions = null; + var deltaLX = 0; + var deltaLY = 0; + var deltaRX = 0; + var deltaRY = 0; + var inspectingEntity = null; + var inspectPanel = null; + var background = null; + var textCart = null; + var cartID = null; + + // this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember + // our this object, so we can access it in cases where we're called without a this (like in the case of various global signals) + ItemEntity = function() { + _this = this; + }; + + function update(deltaTime) { + if(inspecting){ + _this.orientationPositionUpdate(); + } + }; + + + ItemEntity.prototype = { + + // preload() will be called when the entity has become visible (or known) to the interface + // it gives us a chance to set our local JavaScript object up. In this case it means: + // * remembering our entityID, so we can access it in cases where we're called without an entityID + // * connecting to the update signal so we can check our grabbed state + preload: function(entityID) { + this.entityID = entityID; + print("PRELOAD: " + Entities.getEntityProperties(this.entityID).name + " " + entityID + " at:"); + Vec3.print(Entities.getEntityProperties(this.entityID).name, Entities.getEntityProperties(this.entityID).position); + + Script.update.connect(update); + + MIN_DIMENSION_THRESHOLD = Vec3.length(Entities.getEntityProperties(this.entityID).dimensions)/2; + MAX_DIMENSION_THRESHOLD = Vec3.length(Entities.getEntityProperties(this.entityID).dimensions)*2; + + }, + + //create a rectangle red or green do guide the user in putting the item in the inspection area + createInspectOverlay: function (entityBindID) { + inspectPanel = new OverlayPanel({ + anchorPositionBinding: { entity: entityBindID }, + anchorRotationBinding: { entity: entityBindID }, + isFacingAvatar: false + }); + + background = new Image3DOverlay({ + url: RED_IMAGE_URL, + dimensions: { + x: 0.6, + y: 0.6, + }, + isFacingAvatar: false, + alpha: 1, + ignoreRayIntersection: false, + offsetPosition: { + x: 0, + y: 0, + z: 0 + }, + emissive: true, + }); + + inspectPanel.addChild(background); + }, + + //add an overlay on the item grabbed by the customer to give him the feedback if the item is inside the bounding box of the cart + createCartOverlay: function (entityBindID) { + cartPanel = new OverlayPanel({ + anchorPositionBinding: { entity: entityBindID }, + offsetPosition: { x: 0, y: 0.2, z: 0.1 }, + isFacingAvatar: true, + + }); + var entityProperties = Entities.getEntityProperties(entityBindID); + var userDataObj = JSON.parse(entityProperties.userData); + var availabilityNumber = userDataObj.infoKey.availability; + + textCart = new Text3DOverlay({ + text: availabilityNumber > 0 ? "Store the item!" : "Not available!", + isFacingAvatar: false, + alpha: 1.0, + ignoreRayIntersection: true, + dimensions: { x: 0, y: 0 }, + backgroundColor: { red: 255, green: 255, blue: 255 }, + color: { red: 0, green: 0, blue: 0 }, + topMargin: 0.00625, + leftMargin: 0.00625, + bottomMargin: 0.1, + rightMargin: 0.00625, + lineHeight: 0.02, + alpha: 1, + backgroundAlpha: 0.3, + visible: false + }); + + cartPanel.addChild(textCart); + + }, + + + + setCartOverlayVisible: function () { + textCart.visible = true; + }, + + setCartOverlayNotVisible: function () { + textCart.visible = false; + }, + + changeOverlayColor: function () { + if (overlayInspectRed) { + //print ("Change color of overlay to green"); + overlayInspectRed = false; + background.url = GREEN_IMAGE_URL; + } else { + //print ("Change color of overlay to red"); + overlayInspectRed = true; + background.url = RED_IMAGE_URL; + } + }, + + //What is done by this methos changes acoordingly to the previous state of the item - onShelf , inCart, inInspect + startNearGrab: function () { + + //we have to distinguish if the user who is grabbing has a cart or not + //if he does it is a buyer, otherwise he probably want to do a review + var thisItemPosition = Entities.getEntityProperties(_this.entityID).position; + + // if onShelf is true, this is the first grab + if (onShelf === true) { + + var foundEntities = Entities.findEntities(thisItemPosition, 5); + foundEntities.forEach( function (foundEntityID) { + var entityName = Entities.getEntityProperties(foundEntityID).name; + if (entityName == SHOPPING_CART_NAME) { + var cartOwnerID = getEntityCustomData('ownerKey', foundEntityID, null).ownerID; + if (cartOwnerID == MyAvatar.sessionUUID) { + cartID = foundEntityID; + } + } + }); + + // Create a copy of this entity if it is the first grab + print("creating a copy of the grabbed dentity"); + var entityProperties = Entities.getEntityProperties(_this.entityID); + + var entityOnShelf = Entities.addEntity({ + type: entityProperties.type, + name: entityProperties.name, + position: thisItemPosition, + dimensions: entityProperties.dimensions, + rotation: entityProperties.rotation, + collisionsWillMove: false, + ignoreForCollisions: true, + modelURL: entityProperties.modelURL, + shapeType: entityProperties.shapeType, + originalTextures: entityProperties.originalTextures, + script: entityProperties.script, + userData: entityProperties.userData + }); + + var tempUserDataObj = JSON.parse(entityProperties.userData); + var availabilityNumber = tempUserDataObj.infoKey.availability; + + if (availabilityNumber > 0 && cartID) { + tempUserDataObj.infoKey.availability = tempUserDataObj.infoKey.availability - 1; + setEntityCustomData('infoKey', entityOnShelf, tempUserDataObj.infoKey); + } + + setEntityCustomData('statusKey', _this.entityID, { + status: "inHand" + }); + + onShelf = false; + setEntityCustomData('ownerKey', _this.entityID, { + ownerID: MyAvatar.sessionUUID + }); + originalDimensions = entityProperties.dimensions; + + } + + //if cartID is defined the user is a buyer + if (cartID) { + // Everytime we grab, we create the inspectEntity and the inspectAreaOverlay in front of the avatar + if(!inspecting) { + inspectingEntity = Entities.addEntity({ + type: "Box", + name: "inspectionEntity", + dimensions: {x: 0.5, y: 0.5, z: 0.5}, + collisionsWillMove: false, + ignoreForCollisions: false, + visible: false, + script: inspectEntityScript, + userData: JSON.stringify({ + ownerKey: { + ownerID: MyAvatar.sessionUUID + }, + itemKey: { + itemID: _this.entityID + }, + grabbableKey: { + grabbable: false + } + }) + }); + } + + Entities.editEntity(_this.entityID, { ignoreForCollisions: false }); + _this.createInspectOverlay(inspectingEntity); + _this.createCartOverlay(_this.entityID); + + if (inspecting === true) { + inspecting = false; + Entities.editEntity(_this.entityID, { dimensions: originalDimensions }); + Controller.disableMapping(MAPPING_NAME); + setEntityCustomData('statusKey', _this.entityID, { + status: "inHand" + }); + } else if (inCart === true) { + inCart = false; + Entities.editEntity(_this.entityID, { dimensions: originalDimensions }); + setEntityCustomData('statusKey', _this.entityID, { + status: "inHand" + }); + var dataJSON = { + id: _this.entityID + }; + var dataArray = [JSON.stringify(dataJSON)]; + Entities.callEntityMethod(zoneID, 'refreshCartContent', dataArray); + } + } + }, + + continueNearGrab: function () { + }, + + //Every time the item is released I have to check what's the role of the user and where the release happens + releaseGrab: function () { + + //if cart ID is not defined destroy the item whatever the zone is because the user is a reviewer + if (!cartID) { + Entities.deleteEntity(this.entityID); + return; + } + + Entities.editEntity(_this.entityID, { ignoreForCollisions: true }); + // Destroy overlay + inspectPanel.destroy(); + cartPanel.destroy(); + inspectPanel = cartPanel = null; + + if (zoneID !== null) { + var dataJSON = { + id: _this.entityID + }; + var dataArray = [JSON.stringify(dataJSON)]; + Entities.callEntityMethod(zoneID, 'doSomething', dataArray); + + var statusObj = getEntityCustomData('statusKey', _this.entityID, null); + + //There are two known zones where the relase can happen: inspecting area and cart + if (statusObj.status == "inInspect") { + inspecting = true; + + var mapping = Controller.newMapping(MAPPING_NAME); + mapping.from(Controller.Standard.LX).to(function (value) { + deltaLX = value; + }); + mapping.from(Controller.Standard.LY).to(function (value) { + deltaLY = value; + }); + mapping.from(Controller.Standard.RX).to(function (value) { + deltaRX = value; + }); + mapping.from(Controller.Standard.RY).to(function (value) { + deltaRY = value; + }); + Controller.enableMapping(MAPPING_NAME); + } else if (statusObj.status == "inCart") { + Entities.deleteEntity(inspectingEntity); + inspectingEntity = null; + + var entityProperties = Entities.getEntityProperties(this.entityID); + var userDataObj = JSON.parse(entityProperties.userData); + var availabilityNumber = userDataObj.infoKey.availability; + //if the item is no more available, destroy it + if (availabilityNumber == 0) { + Entities.deleteEntity(this.entityID); + } + print("inCart is TRUE"); + inCart = true; + } else { // any other zone + //print("------------zoneID is something"); + Entities.deleteEntity(inspectingEntity); + inspectingEntity = null; + } + + } else { // ZoneID is null, released somewhere that is not a zone. + //print("------------zoneID is null"); + Entities.deleteEntity(inspectingEntity); + inspectingEntity = null; + Entities.deleteEntity(this.entityID); + } + + }, + + //Analysing the collisions we can define the value of zoneID + collisionWithEntity: function(myID, otherID, collisionInfo) { + var penetrationValue = Vec3.length(collisionInfo.penetration); + if (penetrationValue > PENETRATION_THRESHOLD && zoneID === null) { + zoneID = otherID; + print("Item IN: " + Entities.getEntityProperties(zoneID).name); + } else if (penetrationValue < PENETRATION_THRESHOLD && zoneID !== null && otherID == zoneID) { + print("Item OUT: " + Entities.getEntityProperties(zoneID).name); + zoneID = null; + } + }, + + //this method handles the rotation and scale of the item while in inspect and also guarantees to keep the item in the proper position. It's done every update + orientationPositionUpdate: function() { + //position + var inspectingEntityPosition = Entities.getEntityProperties(inspectingEntity).position; //at this time inspectingEntity is a valid entity + var inspectingEntityRotation = Entities.getEntityProperties(inspectingEntity).rotation; + newPosition = Vec3.sum(inspectingEntityPosition, Vec3.multiply(Quat.getFront(inspectingEntityRotation), -0.2)); //put the item near to the face of the user + Entities.editEntity(_this.entityID, { position: newPosition }); + //orientation + var newRotation = Quat.multiply(Entities.getEntityProperties(_this.entityID).rotation, Quat.fromPitchYawRollDegrees(deltaRY*10, deltaRX*10, 0)) + Entities.editEntity(_this.entityID, { rotation: newRotation }); + //zoom + var oldDimension = Entities.getEntityProperties(_this.entityID).dimensions; + var scaleFactor = (deltaLY * 0.1) + 1; + if (!((Vec3.length(oldDimension) < MIN_DIMENSION_THRESHOLD && scaleFactor < 1) || (Vec3.length(oldDimension) > MAX_DIMENSION_THRESHOLD && scaleFactor > 1))) { + var newDimension = Vec3.multiply(oldDimension, scaleFactor); + Entities.editEntity(_this.entityID, { dimensions: newDimension }); + } + }, + + unload: function (entityID) { + Script.update.disconnect(update); + } + }; + + // entity scripts always need to return a newly constructed object of our type + return new ItemEntity(); +}) \ No newline at end of file diff --git a/examples/vrShop/item/shopItemGrab.js b/examples/vrShop/item/shopItemGrab.js new file mode 100644 index 0000000000..a7226675eb --- /dev/null +++ b/examples/vrShop/item/shopItemGrab.js @@ -0,0 +1,862 @@ +// shopItemGrab.js +// +// Semplified and coarse version of handControllerGrab.js with the addition of the ownerID concept. +// This grab is the only one which should run in the vrShop. It allows only near grab and add the feature of checking the ownerID. (See shopGrapSwapperEntityScript.js) +// + +Script.include("../../libraries/utils.js"); + +var SHOP_GRAB_CHANNEL = "Hifi-vrShop-Grab"; +Messages.sendMessage('Hifi-Hand-Disabler', "both"); //disable both the hands from handControlledGrab + +// +// add lines where the hand ray picking is happening +// +var WANT_DEBUG = false; + +// +// these tune time-averaging and "on" value for analog trigger +// + +var TRIGGER_SMOOTH_RATIO = 0.1; // 0.0 disables smoothing of trigger value +var TRIGGER_ON_VALUE = 0.4; +var TRIGGER_OFF_VALUE = 0.15; +// +// distant manipulation +// + +var DISTANCE_HOLDING_RADIUS_FACTOR = 5; // multiplied by distance between hand and object +var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position +var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did + +var NO_INTERSECT_COLOR = { + red: 10, + green: 10, + blue: 255 +}; // line color when pick misses +var INTERSECT_COLOR = { + red: 250, + green: 10, + blue: 10 +}; // line color when pick hits +var LINE_ENTITY_DIMENSIONS = { + x: 1000, + y: 1000, + z: 1000 +}; +var LINE_LENGTH = 500; +var PICK_MAX_DISTANCE = 500; // max length of pick-ray + +// +// near grabbing +// + +var GRAB_RADIUS = 0.03; // if the ray misses but an object is this close, it will still be selected +var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position +var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable. +var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected +var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things +var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object +var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed + +// +// equip +// + +var EQUIP_SPRING_SHUTOFF_DISTANCE = 0.05; +var EQUIP_SPRING_TIMEFRAME = 0.4; // how quickly objects move to their new position + +// +// other constants +// + +var RIGHT_HAND = 1; +var LEFT_HAND = 0; + +var ZERO_VEC = { + x: 0, + y: 0, + z: 0 +}; + +var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}"; +var MSEC_PER_SEC = 1000.0; + +// these control how long an abandoned pointer line or action will hang around +var LIFETIME = 10; +var ACTION_TTL = 15; // seconds +var ACTION_TTL_REFRESH = 5; +var PICKS_PER_SECOND_PER_HAND = 5; +var MSECS_PER_SEC = 1000.0; +var GRABBABLE_PROPERTIES = [ + "position", + "rotation", + "gravity", + "ignoreForCollisions", + "collisionsWillMove", + "locked", + "name" +]; + +var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js +var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js + +var DEFAULT_GRABBABLE_DATA = { + grabbable: true, + invertSolidWhileHeld: false +}; + + +// states for the state machine +var STATE_OFF = 0; +var STATE_SEARCHING = 1; +var STATE_NEAR_GRABBING = 4; +var STATE_CONTINUE_NEAR_GRABBING = 5; +var STATE_NEAR_TRIGGER = 6; +var STATE_CONTINUE_NEAR_TRIGGER = 7; +var STATE_FAR_TRIGGER = 8; +var STATE_CONTINUE_FAR_TRIGGER = 9; +var STATE_RELEASE = 10; +var STATE_EQUIP_SEARCHING = 11; +var STATE_EQUIP = 12 +var STATE_CONTINUE_EQUIP_BD = 13; // equip while bumper is still held down +var STATE_CONTINUE_EQUIP = 14; +var STATE_EQUIP_SPRING = 16; + + +function stateToName(state) { + switch (state) { + case STATE_OFF: + return "off"; + case STATE_SEARCHING: + return "searching"; + case STATE_NEAR_GRABBING: + return "near_grabbing"; + case STATE_CONTINUE_NEAR_GRABBING: + return "continue_near_grabbing"; + case STATE_NEAR_TRIGGER: + return "near_trigger"; + case STATE_CONTINUE_NEAR_TRIGGER: + return "continue_near_trigger"; + case STATE_FAR_TRIGGER: + return "far_trigger"; + case STATE_CONTINUE_FAR_TRIGGER: + return "continue_far_trigger"; + case STATE_RELEASE: + return "release"; + case STATE_EQUIP_SEARCHING: + return "equip_searching"; + case STATE_EQUIP: + return "equip"; + case STATE_CONTINUE_EQUIP_BD: + return "continue_equip_bd"; + case STATE_CONTINUE_EQUIP: + return "continue_equip"; + case STATE_EQUIP_SPRING: + return "state_equip_spring"; + } + + return "unknown"; +} + + + +function MyController(hand) { + this.hand = hand; + if (this.hand === RIGHT_HAND) { + this.getHandPosition = MyAvatar.getRightPalmPosition; + this.getHandRotation = MyAvatar.getRightPalmRotation; + } else { + this.getHandPosition = MyAvatar.getLeftPalmPosition; + this.getHandRotation = MyAvatar.getLeftPalmRotation; + } + + var SPATIAL_CONTROLLERS_PER_PALM = 2; + var TIP_CONTROLLER_OFFSET = 1; + this.palm = SPATIAL_CONTROLLERS_PER_PALM * hand; + this.tip = SPATIAL_CONTROLLERS_PER_PALM * hand + TIP_CONTROLLER_OFFSET; + + this.actionID = null; // action this script created... + this.grabbedEntity = null; // on this entity. + this.state = STATE_OFF; + this.pointer = null; // entity-id of line object + this.triggerValue = 0; // rolling average of trigger value + this.rawTriggerValue = 0; + + this.offsetPosition = { + x: 0.0, + y: 0.0, + z: 0.0 + }; + this.offsetRotation = { + x: 0.0, + y: 0.0, + z: 0.0, + w: 1.0 + }; + + var _this = this; + + this.update = function() { + + this.updateSmoothedTrigger(); + + switch (this.state) { + case STATE_OFF: + this.off(); + this.touchTest(); + break; + case STATE_SEARCHING: + this.search(); + break; + case STATE_EQUIP_SEARCHING: + this.search(); + break; + case STATE_NEAR_GRABBING: + case STATE_EQUIP: + this.nearGrabbing(); + break; + case STATE_EQUIP_SPRING: + this.pullTowardEquipPosition() + break; + case STATE_CONTINUE_NEAR_GRABBING: + case STATE_CONTINUE_EQUIP_BD: + case STATE_CONTINUE_EQUIP: + this.continueNearGrabbing(); + break; + case STATE_NEAR_TRIGGER: + this.nearTrigger(); + break; + case STATE_CONTINUE_NEAR_TRIGGER: + this.continueNearTrigger(); + break; + case STATE_FAR_TRIGGER: + this.farTrigger(); + break; + case STATE_CONTINUE_FAR_TRIGGER: + this.continueFarTrigger(); + break; + case STATE_RELEASE: + this.release(); + break; + } + }; + + this.setState = function(newState) { + if (WANT_DEBUG) { + print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand); + } + this.state = newState; + } + + this.debugLine = function(closePoint, farPoint, color) { + Entities.addEntity({ + type: "Line", + name: "Grab Debug Entity", + dimensions: LINE_ENTITY_DIMENSIONS, + visible: true, + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: 0.1, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + } + + this.lineOn = function(closePoint, farPoint, color) { + // draw a line + if (this.pointer === null) { + this.pointer = Entities.addEntity({ + type: "Line", + name: "grab pointer", + dimensions: LINE_ENTITY_DIMENSIONS, + visible: false, + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: LIFETIME, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + } else { + var age = Entities.getEntityProperties(this.pointer, "age").age; + this.pointer = Entities.editEntity(this.pointer, { + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: age + LIFETIME + }); + } + }; + + this.lineOff = function() { + if (this.pointer !== null) { + Entities.deleteEntity(this.pointer); + } + this.pointer = null; + }; + + this.triggerPress = function(value) { + _this.rawTriggerValue = value; + }; + + + this.updateSmoothedTrigger = function() { + var triggerValue = this.rawTriggerValue; + // smooth out trigger value + this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) + + (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO)); + }; + + this.triggerSmoothedSqueezed = function() { + return this.triggerValue > TRIGGER_ON_VALUE; + }; + + this.triggerSmoothedReleased = function() { + return this.triggerValue < TRIGGER_OFF_VALUE; + }; + + this.triggerSqueezed = function() { + var triggerValue = this.rawTriggerValue; + return triggerValue > TRIGGER_ON_VALUE; + }; + + this.off = function() { + if (this.triggerSmoothedSqueezed()) { + this.lastPickTime = 0; + this.setState(STATE_SEARCHING); + return; + } + } + + this.search = function() { + this.grabbedEntity = null; + + if (this.state == STATE_SEARCHING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + return; + } + + // the trigger is being pressed, do a ray test + var handPosition = this.getHandPosition(); + var distantPickRay = { + origin: handPosition, + direction: Quat.getUp(this.getHandRotation()), + length: PICK_MAX_DISTANCE + }; + + // don't pick 60x per second. + var pickRays = []; + var now = Date.now(); + if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { + pickRays = [distantPickRay]; + this.lastPickTime = now; + } + + for (var index = 0; index < pickRays.length; ++index) { + var pickRay = pickRays[index]; + var directionNormalized = Vec3.normalize(pickRay.direction); + var directionBacked = Vec3.multiply(directionNormalized, PICK_BACKOFF_DISTANCE); + var pickRayBacked = { + origin: Vec3.subtract(pickRay.origin, directionBacked), + direction: pickRay.direction + }; + + + var intersection = Entities.findRayIntersection(pickRayBacked, true); + + if (intersection.intersects) { + // the ray is intersecting something we can move. + var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); + + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA); + + if (intersection.properties.name == "Grab Debug Entity") { + continue; + } + + if (typeof grabbableData.grabbable !== 'undefined' && !grabbableData.grabbable) { + continue; + } + if (intersectionDistance > pickRay.length) { + // too far away for this ray. + continue; + } + if (intersectionDistance <= NEAR_PICK_MAX_DISTANCE) { + // the hand is very close to the intersected object. go into close-grabbing mode. + if (grabbableData.wantsTrigger) { + this.grabbedEntity = intersection.entityID; + this.setState(STATE_NEAR_TRIGGER); + return; + } else if (!intersection.properties.locked) { + var ownerObj = getEntityCustomData('ownerKey', intersection.entityID, null); + + if (ownerObj == null || ownerObj.ownerID === MyAvatar.sessionUUID) { //I can only grab new or already mine items + this.grabbedEntity = intersection.entityID; + if (this.state == STATE_SEARCHING) { + this.setState(STATE_NEAR_GRABBING); + } else { // equipping + if (typeof grabbableData.spatialKey !== 'undefined') { + this.setState(STATE_EQUIP_SPRING); + } else { + this.setState(STATE_EQUIP); + } + } + return; + } + } + } + } + } + + this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + }; + + this.nearGrabbing = function() { + var now = Date.now(); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + //Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + + this.lineOff(); + + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) { + Entities.editEntity(this.grabbedEntity, { + collisionsWillMove: false + }); + } + + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); + + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { + // if an object is "equipped" and has a spatialKey, use it. + if (grabbableData.spatialKey.relativePosition) { + this.offsetPosition = grabbableData.spatialKey.relativePosition; + } + if (grabbableData.spatialKey.relativeRotation) { + this.offsetRotation = grabbableData.spatialKey.relativeRotation; + } + } else { + var objectRotation = grabbedProperties.rotation; + this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); + + var currentObjectPosition = grabbedProperties.position; + var offset = Vec3.subtract(currentObjectPosition, handPosition); + this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); + } + + this.actionID = NULL_ACTION_ID; + this.actionID = Entities.addAction("hold", this.grabbedEntity, { + hand: this.hand === RIGHT_HAND ? "right" : "left", + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, + relativePosition: this.offsetPosition, + relativeRotation: this.offsetRotation, + ttl: ACTION_TTL, + kinematic: NEAR_GRABBING_KINEMATIC, + kinematicSetVelocity: true + }); + if (this.actionID === NULL_ACTION_ID) { + this.actionID = null; + } else { + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + if (this.state == STATE_NEAR_GRABBING) { + this.setState(STATE_CONTINUE_NEAR_GRABBING); + } else { + // equipping + Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); + this.startHandGrasp(); + this.setState(STATE_CONTINUE_EQUIP_BD); + } + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + + Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); + + } + + this.currentHandControllerTipPosition = + (this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition; + + this.currentObjectTime = Date.now(); + }; + + this.continueNearGrabbing = function() { + if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + //Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + + // Keep track of the fingertip velocity to impart when we release the object. + // Note that the idea of using a constant 'tip' velocity regardless of the + // object's actual held offset is an idea intended to make it easier to throw things: + // Because we might catch something or transfer it between hands without a good idea + // of it's actual offset, let's try imparting a velocity which is at a fixed radius + // from the palm. + + var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; + var now = Date.now(); + + var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters + var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds + + this.currentHandControllerTipPosition = handControllerPosition; + this.currentObjectTime = now; + Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab"); + + if (this.state === STATE_CONTINUE_EQUIP_BD) { + Entities.callEntityMethod(this.grabbedEntity, "continueEquip"); + } + + if (this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) { + // if less than a 5 seconds left, refresh the actions ttl + Entities.updateAction(this.grabbedEntity, this.actionID, { + hand: this.hand === RIGHT_HAND ? "right" : "left", + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, + relativePosition: this.offsetPosition, + relativeRotation: this.offsetRotation, + ttl: ACTION_TTL, + kinematic: NEAR_GRABBING_KINEMATIC, + kinematicSetVelocity: true + }); + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + } + }; + + + this.pullTowardEquipPosition = function() { + this.lineOff(); + + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + // use a spring to pull the object to where it will be when equipped + var relativeRotation = { + x: 0.0, + y: 0.0, + z: 0.0, + w: 1.0 + }; + var relativePosition = { + x: 0.0, + y: 0.0, + z: 0.0 + }; + if (grabbableData.spatialKey.relativePosition) { + relativePosition = grabbableData.spatialKey.relativePosition; + } + if (grabbableData.spatialKey.relativeRotation) { + relativeRotation = grabbableData.spatialKey.relativeRotation; + } + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); + var targetRotation = Quat.multiply(handRotation, relativeRotation); + var offset = Vec3.multiplyQbyV(targetRotation, relativePosition); + var targetPosition = Vec3.sum(handPosition, offset); + + if (typeof this.equipSpringID === 'undefined' || + this.equipSpringID === null || + this.equipSpringID === NULL_ACTION_ID) { + this.equipSpringID = Entities.addAction("spring", this.grabbedEntity, { + targetPosition: targetPosition, + linearTimeScale: EQUIP_SPRING_TIMEFRAME, + targetRotation: targetRotation, + angularTimeScale: EQUIP_SPRING_TIMEFRAME, + ttl: ACTION_TTL + }); + if (this.equipSpringID === NULL_ACTION_ID) { + this.equipSpringID = null; + this.setState(STATE_OFF); + return; + } + } else { + Entities.updateAction(this.grabbedEntity, this.equipSpringID, { + targetPosition: targetPosition, + linearTimeScale: EQUIP_SPRING_TIMEFRAME, + targetRotation: targetRotation, + angularTimeScale: EQUIP_SPRING_TIMEFRAME, + ttl: ACTION_TTL + }); + } + + if (Vec3.distance(grabbedProperties.position, targetPosition) < EQUIP_SPRING_SHUTOFF_DISTANCE) { + Entities.deleteAction(this.grabbedEntity, this.equipSpringID); + this.equipSpringID = null; + this.setState(STATE_EQUIP); + } + }; + + this.nearTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + + Entities.callEntityMethod(this.grabbedEntity, "startNearTrigger"); + this.setState(STATE_CONTINUE_NEAR_TRIGGER); + }; + + this.farTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + return; + } + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + Entities.callEntityMethod(this.grabbedEntity, "startFarTrigger"); + this.setState(STATE_CONTINUE_FAR_TRIGGER); + }; + + this.continueNearTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + + Entities.callEntityMethod(this.grabbedEntity, "continueNearTrigger"); + }; + + this.continueFarTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + + var handPosition = this.getHandPosition(); + var pickRay = { + origin: handPosition, + direction: Quat.getUp(this.getHandRotation()) + }; + + var now = Date.now(); + if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { + var intersection = Entities.findRayIntersection(pickRay, true); + this.lastPickTime = now; + if (intersection.entityID != this.grabbedEntity) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + return; + } + } + + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); + }; + + _this.allTouchedIDs = {}; + this.touchTest = function() { + var maxDistance = 0.05; + var leftHandPosition = MyAvatar.getLeftPalmPosition(); + var rightHandPosition = MyAvatar.getRightPalmPosition(); + var leftEntities = Entities.findEntities(leftHandPosition, maxDistance); + var rightEntities = Entities.findEntities(rightHandPosition, maxDistance); + var ids = []; + + if (leftEntities.length !== 0) { + leftEntities.forEach(function(entity) { + ids.push(entity); + }); + + } + + if (rightEntities.length !== 0) { + rightEntities.forEach(function(entity) { + ids.push(entity); + }); + } + + ids.forEach(function(id) { + + var props = Entities.getEntityProperties(id, ["boundingBox", "name"]); + if (props.name === 'pointer') { + return; + } else { + var entityMinPoint = props.boundingBox.brn; + var entityMaxPoint = props.boundingBox.tfl; + var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint); + var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint); + + if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) { + // we haven't been touched before, but either right or left is touching us now + _this.allTouchedIDs[id] = true; + _this.startTouch(id); + } else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id]) { + // we have been touched before and are still being touched + // continue touch + _this.continueTouch(id); + } else if (_this.allTouchedIDs[id]) { + delete _this.allTouchedIDs[id]; + _this.stopTouch(id); + + } else { + //we are in another state + return; + } + } + + }); + + }; + + this.startTouch = function(entityID) { + Entities.callEntityMethod(entityID, "startTouch"); + }; + + this.continueTouch = function(entityID) { + Entities.callEntityMethod(entityID, "continueTouch"); + }; + + this.stopTouch = function(entityID) { + Entities.callEntityMethod(entityID, "stopTouch"); + }; + + this.release = function() { + + this.lineOff(); + + if (this.grabbedEntity !== null) { + if (this.actionID !== null) { + Entities.deleteAction(this.grabbedEntity, this.actionID); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + print("CALLING releaseGrab"); + } + } + + + this.grabbedEntity = null; + this.actionID = null; + this.setState(STATE_OFF); + + }; + + this.cleanup = function() { + this.release(); + this.endHandGrasp(); + }; + + + + + //this is our handler, where we do the actual work of changing animation settings + this.graspHand = function(animationProperties) { + var result = {}; + //full alpha on overlay for this hand + //set grab to true + //set idle to false + //full alpha on the blend btw open and grab + if (_this.hand === RIGHT_HAND) { + result['rightHandOverlayAlpha'] = 1.0; + result['isRightHandGrab'] = true; + result['isRightHandIdle'] = false; + result['rightHandGrabBlend'] = 1.0; + } else if (_this.hand === LEFT_HAND) { + result['leftHandOverlayAlpha'] = 1.0; + result['isLeftHandGrab'] = true; + result['isLeftHandIdle'] = false; + result['leftHandGrabBlend'] = 1.0; + } + //return an object with our updated settings + return result; + } + + this.graspHandler = null + this.startHandGrasp = function() { + if (this.hand === RIGHT_HAND) { + this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isRightHandGrab']); + } else if (this.hand === LEFT_HAND) { + this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isLeftHandGrab']); + } + } + + this.endHandGrasp = function() { + // Tell the animation system we don't need any more callbacks. + MyAvatar.removeAnimationStateHandler(this.graspHandler); + } + +} + +var rightController = new MyController(RIGHT_HAND); +var leftController = new MyController(LEFT_HAND); + +var MAPPING_NAME = "com.highfidelity.handControllerGrab"; + +var mapping = Controller.newMapping(MAPPING_NAME); +mapping.from([Controller.Standard.RT]).peek().to(rightController.triggerPress); +mapping.from([Controller.Standard.LT]).peek().to(leftController.triggerPress); + +Controller.enableMapping(MAPPING_NAME); + +var handToDisable = 'none'; + +function update() { + if (handToDisable !== LEFT_HAND) { + leftController.update(); + } + if (handToDisable !== RIGHT_HAND) { + rightController.update(); + } +} + +Messages.subscribe(SHOP_GRAB_CHANNEL); + +stopScriptMessage = function(channel, message, sender) { + if (channel == SHOP_GRAB_CHANNEL && sender === MyAvatar.sessionUUID) { + //stop this script and enable the handControllerGrab + Messages.sendMessage('Hifi-Hand-Disabler', "none"); + Messages.unsubscribe(SHOP_GRAB_CHANNEL); + Messages.messageReceived.disconnect(stopScriptMessage); + Script.stop(); + } +} + +Messages.messageReceived.connect(stopScriptMessage); + +function cleanup() { + rightController.cleanup(); + leftController.cleanup(); + Controller.disableMapping(MAPPING_NAME); +} + +Script.scriptEnding.connect(cleanup); +Script.update.connect(update); \ No newline at end of file diff --git a/examples/vrShop/review/shopReviewEntityScript.js b/examples/vrShop/review/shopReviewEntityScript.js new file mode 100644 index 0000000000..49f0a49dea --- /dev/null +++ b/examples/vrShop/review/shopReviewEntityScript.js @@ -0,0 +1,477 @@ +// shopReviewEntityScript.js +// +// This script handles the review phase in the vrShop. It starts entering into the entity holding in hand the item to review. +// Then the user can rate the item and record a review for that item. +// Finally the recording is stored into the asset and a link to that file is stored into the DB entity of that item. +// During the whole reviewing experience an (interactive) UI drives the user. + +// Created by Alessandro Signa and Edgar Pironti on 01/13/2016 +// Copyright 2016 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 +// + +(function () { + var utilitiesScript = Script.resolvePath("../../libraries/utils.js"); + var overlayManagerScript = Script.resolvePath("../../libraries/overlayManager.js"); + Script.include(utilitiesScript); + Script.include(overlayManagerScript); + + var POINTER_ICON_URL = "https://dl.dropboxusercontent.com/u/14127429/FBX/VRshop/Pointer.png"; + var STAR_ON_URL = "https://dl.dropboxusercontent.com/u/14127429/FBX/VRshop/SingleStar_Yellow.png"; + var STAR_OFF_URL = "https://dl.dropboxusercontent.com/u/14127429/FBX/VRshop/SingleStar_Black.png"; + var RECORDING_ON_ICON_URL = "https://dl.dropboxusercontent.com/u/14127429/FBX/VRshop/REC.png"; + var ANCHOR_ENTITY_FOR_UI_NAME = "anchorEntityForReviewUI"; + var START_RECORDING_TEXT = "Press the bumper to start recording"; + var STOP_RECORDING_TEXT = "Press the bumper to stop recording"; + var SHOPPING_CART_NAME = "Shopping cart"; + var CAMERA_NAME = "CameraReview"; + + + var RIGHT_HAND = 1; + var LEFT_HAND = 0; + + var LINE_LENGTH = 100; + var COLOR = { + red: 165, + green: 199, + blue: 218 + }; + + + + var _this; + var dataBaseID = null; + var cameraEntity = null; + var scoreAssigned = null; + var hoveredButton = null; + var hoveredButtonIndex = -1; + var recording = false; + var workDone = false; + + var PENETRATION_THRESHOLD = 0.2; + + + var isUIWorking = false; + var wantToStopTrying = false; + var rightController = null; + var leftController = null; + var workingHand = null; + + var mainPanel = null; + var cameraPanel = null; + var buttons = []; + var onAirOverlay = null; + var instructionsOverlay = null; + + + var pointer = new Image3DOverlay({ + url: POINTER_ICON_URL, + dimensions: { + x: 0.015, + y: 0.015 + }, + alpha: 1, + emissive: true, + isFacingAvatar: false, + ignoreRayIntersection: true, + }) + + function ReviewZone() { + _this = this; + return; + }; + + function MyController(hand) { + this.hand = hand; + if (this.hand === RIGHT_HAND) { + this.getHandPosition = MyAvatar.getRightPalmPosition; + this.getHandRotation = MyAvatar.getRightPalmRotation; + this.bumper = Controller.Standard.RB; + } else { + this.getHandPosition = MyAvatar.getLeftPalmPosition; + this.getHandRotation = MyAvatar.getLeftPalmRotation; + this.bumper = Controller.Standard.LB; + } + + this.pickRay = null; // ray object + this.overlayLine = null; // id of line overlay + this.waitingForBumpReleased = false; + + this.overlayLineOn = function(closePoint, farPoint, color) { + if (this.overlayLine == null) { + var lineProperties = { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + ignoreRayIntersection: true, + visible: true, + alpha: 1 + }; + this.overlayLine = new Line3DOverlay(lineProperties); + } else { + this.overlayLine.start = closePoint; + this.overlayLine.end = farPoint; + } + }, + + this.updateRay = function() { + //update the ray object + this.pickRay = { + origin: this.getHandPosition(), + direction: Quat.getUp(this.getHandRotation()) + }; + //update the ray overlay and the pointer + + var rayPickResult = OverlayManager.findRayIntersection(this.pickRay); + if (rayPickResult.intersects) { + var normal = Vec3.multiply(Quat.getFront(Camera.getOrientation()), -1); + var offset = Vec3.multiply(normal, 0.001); + pointer.position = Vec3.sum(rayPickResult.intersection, offset); //pointer is a global Image3DOverlay + pointer.rotation = Camera.getOrientation(); + pointer.visible = true; + } else { + pointer.visible = false; + } + + var farPoint = rayPickResult.intersects ? rayPickResult.intersection : Vec3.sum(this.pickRay.origin, Vec3.multiply(this.pickRay.direction, LINE_LENGTH)); + this.overlayLineOn(this.pickRay.origin, farPoint, COLOR); + + }, + //the update of each hand has to update the ray belonging to that hand and handle the bumper event + this.updateHand = function() { + //detect the bumper event + var bumperPressed = Controller.getValue(this.bumper); + if (bumperPressed && this != workingHand) { + //mantain active one ray at a time + workingHand.clean(); + workingHand = this; + } else if (this != workingHand) { + return; + } + + if (!scoreAssigned) { + this.updateRay(); + + //manage event on UI + var lastHoveredButton = hoveredButton; + hoveredButton = OverlayManager.findOnRay(this.pickRay); + //print("hovered button: " + hoveredButton); + if (lastHoveredButton != hoveredButton) { + hoveredButtonIndex = -1; + if (hoveredButton) { + for (var i = 0; i < buttons.length; i++) { + if (buttons[i] == hoveredButton) { + //print("Adapting overlay rendering"); + hoveredButtonIndex = i; + } + } + } + adaptOverlayOnHover(hoveredButtonIndex); + } + } else if (!instructionsOverlay.visible) { + workingHand.clean(); + for (var i = 0; i < buttons.length; i++) { + buttons[i].destroy(); + } + buttons = []; + instructionsOverlay.visible = true; + } + + + if (bumperPressed && !this.waitingForBumpReleased) { + this.waitingForBumpReleased = true; + + if (hoveredButton) { + scoreAssigned = hoveredButtonIndex + 1; + hoveredButton = null; + } else if (scoreAssigned && !recording) { + instructionsOverlay.text = STOP_RECORDING_TEXT; + Recording.startRecording(); + onAirOverlay.visible = true; + recording = true; + } else if (scoreAssigned && recording) { + Recording.stopRecording(); + Recording.saveRecordingToAsset(saveDataIntoDB); + onAirOverlay.visible = false; + recording = false; + workDone = true; + _this.cleanUI(); + } + } else if (!bumperPressed && this.waitingForBumpReleased) { + this.waitingForBumpReleased = false; + } + }, + + this.clean = function() { + this.pickRay = null; + if (this.overlayLine) { + this.overlayLine.destroy(); + } + this.overlayLine = null; + pointer.visible = false; + } + }; + + function update(deltaTime) { + + if (!workDone) { + leftController.updateHand(); + rightController.updateHand(); + } else { + _this.cleanUI(); + Script.update.disconnect(update); + } + + + if (!insideZone && isUIWorking) { + // Destroy rays + _this.cleanUI(); + } + + }; + + //This method is the callback called once the recording is loaded into the asset + function saveDataIntoDB(url) { + // Feed the database + var dbObj = getEntityCustomData('infoKey', dataBaseID, null); + if(dbObj) { + var myName = MyAvatar.displayName ? MyAvatar.displayName : "Anonymous"; + dbObj.dbKey[dbObj.dbKey.length] = {name: myName, score: scoreAssigned, clip_url: url}; + setEntityCustomData('infoKey', dataBaseID, dbObj); + print("Feeded DB: " + url"); + } + }; + + // Find items in the zone. It returns a not null value if an item belonging to the user is found AND if a cart belonging to him is not found + function findItemToReview(searchingPointEntityID) { + var foundItemToReviewID = null; + var entitiesInZone = Entities.findEntities(Entities.getEntityProperties(searchingPointEntityID).position, 5); + for (var i = 0; i < entitiesInZone.length; i++) { + + var ownerObj = getEntityCustomData('ownerKey', entitiesInZone[i], null); + + if (ownerObj) { + print("Not sure if review. Check " + MyAvatar.sessionUUID); + if (ownerObj.ownerID === MyAvatar.sessionUUID) { + if (Entities.getEntityProperties(entitiesInZone[i]).name == SHOPPING_CART_NAME) { + //the user has a cart, he's not a reviewer + print("the user has a cart, it's not a reviewer"); + return null; + } else { + foundItemToReviewID = entitiesInZone[i]; + } + } + } + } + var res = null; + if (foundItemToReviewID) { + res = Entities.getEntityProperties(foundItemToReviewID).name; + print("Found an item to review: " + res); + //delete the item + Entities.deleteEntity(foundItemToReviewID); + } + return res; + }; + + function findAnchorEntityForUI(searchingPointEntityID) { + + var entitiesInZone = Entities.findEntities(Entities.getEntityProperties(searchingPointEntityID).position, 2); + for (var i = 0; i < entitiesInZone.length; i++) { + + if (Entities.getEntityProperties(entitiesInZone[i]).name == ANCHOR_ENTITY_FOR_UI_NAME) { + print("Anchor entity found " + entitiesInZone[i]); + return entitiesInZone[i]; + } + } + return null; + }; + + function findItemByName(searchingPointEntityID, itemName) { + // find the database entity + print("Looking for item: " + itemName); + var entitiesInZone = Entities.findEntities(Entities.getEntityProperties(searchingPointEntityID).position, (Entities.getEntityProperties(searchingPointEntityID).dimensions.x)*10); + + for (var i = 0; i < entitiesInZone.length; i++) { + if (Entities.getEntityProperties(entitiesInZone[i]).name == itemName) { + print(itemName + " found! " + entitiesInZone[i]); + return entitiesInZone[i]; + } + } + print("Item " + itemName + " not found"); + return null; + }; + + function adaptOverlayOnHover(hoveredButtonIndex) { + for (var i = buttons.length - 1; i >= 0; i--) { + if (i <= hoveredButtonIndex) { + buttons[i].url = STAR_ON_URL; + } else { + buttons[i].url = STAR_OFF_URL; + } + } + }; + + + ReviewZone.prototype = { + + preload: function (entityID) { + }, + + //When the avatar comes into the review zone the script looks for the actual item to review, the proper DB for that item and the entity camera. If all goes well the UI is created + enterEntity: function (entityID) { + print("entering in the review area"); + insideZone = true; + + var itemToReview = findItemToReview(entityID); //return the name or null + cameraEntity = findItemByName(entityID, CAMERA_NAME); + if (itemToReview && cameraEntity) { + dataBaseID = findItemByName(entityID, itemToReview + "DB"); //return the ID of the DB or null + if (dataBaseID) { + var anchorEntityForUI = findAnchorEntityForUI(entityID); + if (anchorEntityForUI) { + _this.createReviewUI(anchorEntityForUI); + rightController = new MyController(RIGHT_HAND); //rightController and leftController are two objects + leftController = new MyController(LEFT_HAND); + workingHand = rightController; + Script.update.connect(update); + } + } + } + }, + + leaveEntity: function (entityID) { + print("leaving the review area"); + if (!workDone) { + Script.update.disconnect(update); + } + if (recording) { + Recording.stopRecording(); + recording = false; + } + + if (cameraPanel) { + cameraPanel.destroy(); + cameraPanel = null; + } + workDone = false; + cameraEntity = null; + dataBaseID = null; + scoreAssigned = null; + hoveredButton = null; + hoveredButtonIndex = -1; + insideZone = false; + _this.cleanUI(); + }, + + createReviewUI : function(anchorEntityID) { + Entities.editEntity(anchorEntityID, { locked: false }); + var anchorEntityPosition = Entities.getEntityProperties(anchorEntityID).position; + anchorEntityPosition.y = MyAvatar.getHeadPosition().y; + Entities.editEntity(anchorEntityID, { position: anchorEntityPosition }); + Entities.editEntity(anchorEntityID, { locked: true }); + + //set the main panel to follow the inspect entity + mainPanel = new OverlayPanel({ + anchorPositionBinding: { entity: anchorEntityID }, + anchorRotationBinding: { entity: anchorEntityID }, + + isFacingAvatar: false + }); + + var offsetPositionY = 0.0; + var offsetPositionX = -0.3; + + for (var i = 0; i < 3; i++) { + buttons[i] = new Image3DOverlay({ + url: STAR_OFF_URL, + dimensions: { + x: 0.15, + y: 0.15 + }, + isFacingAvatar: false, + alpha: 0.8, + ignoreRayIntersection: false, + offsetPosition: { + x: offsetPositionX - (i * offsetPositionX), + y: offsetPositionY, + z: 0 + }, + emissive: true, + }); + mainPanel.addChild(buttons[i]); + } + + instructionsOverlay= new Text3DOverlay({ + text: START_RECORDING_TEXT, + isFacingAvatar: false, + alpha: 1.0, + ignoreRayIntersection: true, + offsetPosition: { + x: -0.5, + y: 0, + z: 0 + }, + dimensions: { x: 0, y: 0 }, + backgroundColor: { red: 0, green: 255, blue: 0 }, + color: { red: 0, green: 0, blue: 0 }, + topMargin: 0.00625, + leftMargin: 0.00625, + bottomMargin: 0.1, + rightMargin: 0.00625, + lineHeight: 0.06, + alpha: 1, + backgroundAlpha: 0.3, + visible: false + }); + + mainPanel.addChild(instructionsOverlay); + + cameraPanel = new OverlayPanel({ + anchorPositionBinding: { entity: cameraEntity }, + isFacingAvatar: false + }); + + onAirOverlay = new Image3DOverlay({ + url: RECORDING_ON_ICON_URL, + dimensions: { + x: 0.2, + y: 0.2 + }, + isFacingAvatar: false, + alpha: 0.8, + ignoreRayIntersection: true, + offsetPosition: { + x: 0, + y: 0.7, + z: 0 + }, + emissive: true, + visible: false, + }); + cameraPanel.addChild(onAirOverlay); + + isUIWorking = true; + }, + + cleanUI: function () { + workingHand.clean(); + if (mainPanel) { + mainPanel.destroy(); + } + mainPanel = null; + isUIWorking = false; + }, + + unload: function (entityID) { + this.cleanUI(); + if (cameraPanel) { + cameraPanel.destroy(); + } + } + } + + return new ReviewZone(); +}); \ No newline at end of file diff --git a/examples/vrShop/review/shopReviewerAC.js b/examples/vrShop/review/shopReviewerAC.js new file mode 100644 index 0000000000..7b7776fe98 --- /dev/null +++ b/examples/vrShop/review/shopReviewerAC.js @@ -0,0 +1,96 @@ +// shopReviewerAC.js +// + +// Created by Alessandro Signa and Edgar Pironti on 01/13/2016 +// Copyright 2016 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 + + +var command = null; +var clip_url = null; + +var REVIEW_CHANNEL = "reviewChannel"; +var playFromCurrentLocation = true; +var useDisplayName = true; +var useAttachments = true; +var useAvatarModel = true; + +var totalTime = 0; +var subscribed = false; +var WAIT_FOR_AUDIO_MIXER = 1; + +var PLAY = "Play"; +var SHOW = "Show"; +var HIDE = "Hide"; + +function getAction(channel, message, senderID) { + if(subscribed) { + print("I'm the agent and I received this: " + message); + + if (Recording.isPlaying()) { + Recording.stopPlaying(); + } + + m = JSON.parse(message); + + command = m.command; + clip_url = m.clip_url; + + switch(command) { + case PLAY: + print("Play"); + if (!Recording.isPlaying()) { + Recording.setPlayerTime(0.0); + Recording.startPlaying(); + } + break; + + case SHOW: + print("Show"); + Recording.loadRecording(clip_url); + Agent.isAvatar = true; + Recording.setPlayerTime(0.0); + Recording.startPlaying(); + Recording.stopPlaying(); + break; + + case HIDE: + print("Hide"); + Agent.isAvatar = false; + break; + + default: + print("Unknown action: " + action); + break; + } + } +} + + +function update(deltaTime) { + + totalTime += deltaTime; + + if (totalTime > WAIT_FOR_AUDIO_MIXER) { + if (!subscribed) { + Messages.subscribe(REVIEW_CHANNEL); + subscribed = true; + Recording.setPlayFromCurrentLocation(playFromCurrentLocation); + Recording.setPlayerUseDisplayName(useDisplayName); + Recording.setPlayerUseAttachments(useAttachments); + Recording.setPlayerUseHeadModel(false); + Recording.setPlayerUseSkeletonModel(useAvatarModel); + } + } + +} + +Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == REVIEW_CHANNEL) { + getAction(channel, message, senderID); + } +}); + +Script.update.connect(update); \ No newline at end of file diff --git a/examples/vrShop/shop/shopGrabSwapperEntityScript.js b/examples/vrShop/shop/shopGrabSwapperEntityScript.js new file mode 100644 index 0000000000..b6f52b2731 --- /dev/null +++ b/examples/vrShop/shop/shopGrabSwapperEntityScript.js @@ -0,0 +1,55 @@ +// shopGrapSwapperEntityScript.js +// +// This script handle the transition from handControllerGrab to shopItemGrab +// When an avatar enters the zone a message is sent to the handControllerGrab script to disable itself and the shopItemGrab is loaded. +// When exit from the zone the handControllerGrab is re-enabled. +// This mechanism may not work well with the last changes to the animations in handControllerGrab, if it's the case please load this script manually and disable that one. + +// Created by Alessandro Signa and Edgar Pironti on 01/13/2016 +// Copyright 2016 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 +// + +(function () { + var SHOP_GRAB_SCRIPT_URL = Script.resolvePath("../item/shopItemGrab.js"); + var SHOP_GRAB_CHANNEL = "Hifi-vrShop-Grab"; + var _this; + + function SwapGrabZone() { + _this = this; + return; + }; + + function isScriptRunning(script) { + script = script.toLowerCase().trim(); + var runningScripts = ScriptDiscoveryService.getRunning(); + for (i in runningScripts) { + if (runningScripts[i].url.toLowerCase().trim() == script) { + return true; + } + } + return false; + }; + + SwapGrabZone.prototype = { + + enterEntity: function (entityID) { + print("entering in the shop area"); + + if (!isScriptRunning(SHOP_GRAB_SCRIPT_URL)) { + Script.load(SHOP_GRAB_SCRIPT_URL); + } + + }, + + leaveEntity: function (entityID) { + print("leaving the shop area"); + Messages.sendMessage(SHOP_GRAB_CHANNEL, null); //signal to shopItemGrab that it has to kill itself + } + + } + + return new SwapGrabZone(); +}); \ No newline at end of file diff --git a/examples/vrShop/vendor/shopVendorAddItem.js b/examples/vrShop/vendor/shopVendorAddItem.js new file mode 100644 index 0000000000..a73fa97ba8 --- /dev/null +++ b/examples/vrShop/vendor/shopVendorAddItem.js @@ -0,0 +1,101 @@ +// shopVendorAddItem.js +// +// This shows a propt to allow the user to create a custom shop item, it also creates a DB entity for that object + +// Created by Alessandro Signa and Edgar Pironti on 01/13/2016 +// Copyright 2016 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 +// + +var TITLE = "Add Item Form"; +var DEFAULT_ITEM_NAME = "New Item"; +var DEFAULT_ROOT_DIRECTORY_URL = "https://dl.dropboxusercontent.com/u/14127429/FBX/VRshop/"; +var DEFAULT_MODEL_1_RELATIVE_PATH = "cubeRed.fbx"; // those paths are relative to the root directory url +var DEFAULT_PREVIEW_1_RELATIVE_PATH = "previewRed.png"; +var DEFAULT_MODEL_2_RELATIVE_PATH = "cubeGreen.fbx"; +var DEFAULT_PREVIEW_2_RELATIVE_PATH = "previewGreen.png"; +var DEFAULT_MODEL_3_RELATIVE_PATH = "cubeBlue.fbx"; +var DEFAULT_PREVIEW_3_RELATIVE_PATH = "previewBlue.png"; +var DEFAULT_QUANTITY = 1; +var DEFAULT_PRICE = 1.00; +var DEFAULT_DESCRIPTION = "Description empty"; + + +var scriptURL = Script.resolvePath("../item/shopItemEntityScript.js"); +var rotation = Quat.safeEulerAngles(Camera.getOrientation()); +rotation = Quat.fromPitchYawRollDegrees(0, rotation.y, 0); +var position = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(rotation))); + +var form = [ + {"label": "Item Name", "value": DEFAULT_ITEM_NAME}, + + {"label": "Root directory URL", "value": DEFAULT_ROOT_DIRECTORY_URL}, + {"label": "Model 1 relative path", "value": DEFAULT_MODEL_1_RELATIVE_PATH}, + {"label": "Preview 1 relative path", "value": DEFAULT_PREVIEW_1_RELATIVE_PATH}, + {"label": "Model 2 relative path", "value": DEFAULT_MODEL_2_RELATIVE_PATH}, + {"label": "Preview 2 relative path", "value": DEFAULT_PREVIEW_2_RELATIVE_PATH}, + {"label": "Model 3 relative path", "value": DEFAULT_MODEL_3_RELATIVE_PATH}, + {"label": "Preview 3 relative path", "value": DEFAULT_PREVIEW_3_RELATIVE_PATH}, + + {"label": "Quantity", "value": DEFAULT_QUANTITY}, + {"label": "Price", "value": DEFAULT_PRICE}, + {"label": "Description", "value": DEFAULT_DESCRIPTION}, + {"label": "Wearable", "type": "checkbox", "value": false}, + +]; + +var accepted = Window.form(TITLE, form); + +if (accepted) { + var modelURL = "" + form[1].value + form[2].value; + var myEntity = Entities.addEntity({ + type: "Model", + name: form[0].value, + position: position, + script: scriptURL, + rotation: rotation, + collisionsWillMove: false, + ignoreForCollisions: true, + collisionMask: "static,dynamic,otherAvatar", + shapeType: "box", + modelURL: modelURL, + userData: JSON.stringify({ + infoKey: { + rootURL: form[1].value, + modelURLs: [ + form[2].value, + form[4].value, + form[6].value + ], + previewURLs: [ + form[3].value, + form[5].value, + form[7].value + ], + availability: form[8].value, + price: form[9].value, + description: form[10].value, + wearable: form[11].value + } + }) + }); + + var myEntityDB = Entities.addEntity({ + type: "Box", + name: form[0].value + "DB", + position: {x: 0, y: 0, z: 0}, + rotation: rotation, + collisionsWillMove: false, + ignoreForCollisions: true, + visible: false, + shapeType: "box", + userData: JSON.stringify({ + infoKey: { + dbKey: [ + ] + } + }) + }); +} \ No newline at end of file From e4501e3a8f6c29a6c7584d1e4b5aa6878bfe89eb Mon Sep 17 00:00:00 2001 From: AlessandroSigna Date: Thu, 14 Jan 2016 18:23:39 -0800 Subject: [PATCH 164/215] Added cart, cash, inspect and readme --- examples/vrShop/README.txt | 51 ++ examples/vrShop/cart/shopCartEntityScript.js | 324 +++++++ .../vrShop/cart/shopCartSpawnEntityScript.js | 91 ++ .../vrShop/cart/shopCartZeroEntityScript.js | 39 + examples/vrShop/cash/shopCashEntityScript.js | 94 ++ .../cash/shopCashRegisterEntityScript.js | 166 ++++ examples/vrShop/cash/shopCashierAC.js | 73 ++ .../vrShop/cash/shopCreditCardEntityScript.js | 45 + .../vrShop/inspect/shopInspectEntityScript.js | 858 ++++++++++++++++++ 9 files changed, 1741 insertions(+) create mode 100644 examples/vrShop/README.txt create mode 100644 examples/vrShop/cart/shopCartEntityScript.js create mode 100644 examples/vrShop/cart/shopCartSpawnEntityScript.js create mode 100644 examples/vrShop/cart/shopCartZeroEntityScript.js create mode 100644 examples/vrShop/cash/shopCashEntityScript.js create mode 100644 examples/vrShop/cash/shopCashRegisterEntityScript.js create mode 100644 examples/vrShop/cash/shopCashierAC.js create mode 100644 examples/vrShop/cash/shopCreditCardEntityScript.js create mode 100644 examples/vrShop/inspect/shopInspectEntityScript.js diff --git a/examples/vrShop/README.txt b/examples/vrShop/README.txt new file mode 100644 index 0000000000..af20c2e23e --- /dev/null +++ b/examples/vrShop/README.txt @@ -0,0 +1,51 @@ +Instructions for experiencing vrShop +Alessandro Signa and Edgar Pironti, 13 Jan 2016 + +To avoid weird issues we suggest to run this build https://github.com/highfidelity/hifi/pull/6786 +To test the experience in the current release of interface that PR needs to be merged +and the scripts need to be updated to the new collisionMask system. + +Go to the vrShop domain. + +When you get closer to the shop (entering the Zone - GrabSwapper) you should notice that +shopItemGrab is in your running scripts. At this point the handControllerGrab should be disabled +(it will be re-enabled automatically when leaving the zone), but if you still see rays +coming out from your hands when you squeeze the triggers something went wrong so you probably +want to remove manually handControllerGrab + +Once you're here you can do two different experiences: buyer and reviewr. +Both of them are designed to be done entirely using HMD and hand controllers, +so please put your Oculus on and equip your hydra. + +BUYER +First of all you have to pass through the pick cart line, the Zone - CartSpawner is there. +Now you see a cart following you (look at your right). +Reach the shelf and grab an item (you can only near grab here). +An inspection area should now stay in front of you, drop the item inside it to inspect. Be sure +to see the overlay turning green before releasing the item. + +In inspect mode you can't move or rotate your avatar but you can scale and rotate the item. +Interact with the UI buttons using your bumpers: you can change the color of the item, +see the reviews (looking at the review cabin) and you can also try some of the items on (but +this feature at the moment works well only with the Will avatar increasing its default size once). + +If you are good with your item you can put it in the cart, otherwise just drop it around. +You can also pick again an item from your cart to inspect it or to discard it. +To empty the cart you can push the right primary button. + +Then you can go to the cashier for the "payment": once you enter the Zone - CashDesk +a credit card will appear above the register and a bot will give you some informations. +Just drag that card to the register to confirm the purchase. + +When you're ready to exit pass again through the leave cart line. + +REVIEWER +Go and grab the item you want to review, this time don't pick the cart. +Enter into the review cabin holding the item in your hand , if all goes right the item should disappear +and a UI appears allowing you to rate the item. +Now you can follow the instrucions to record a review: both the voice and the animation of your avatar +will be recorded and stored into the DB of that item. + + + + diff --git a/examples/vrShop/cart/shopCartEntityScript.js b/examples/vrShop/cart/shopCartEntityScript.js new file mode 100644 index 0000000000..b572c30bdd --- /dev/null +++ b/examples/vrShop/cart/shopCartEntityScript.js @@ -0,0 +1,324 @@ +// shopCartEntityScript.js +// +// This script makes the cart follow the avatar who picks it and manage interations with items (store and delete them) and with cash register (send the item prices) + +// Created by Alessandro Signa and Edgar Pironti on 01/13/2016 +// Copyright 2016 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 +// + + +(function() { + var utilitiesScript = Script.resolvePath("../../libraries/utils.js"); + var overlayManagerScript = Script.resolvePath("../../libraries/overlayManager.js"); + Script.include(utilitiesScript); + Script.include(overlayManagerScript); + + var COMFORT_ARM_LENGTH = 0.5; + var CART_REGISTER_CHANNEL = "Hifi-vrShop-Register"; + var PENETRATION_THRESHOLD = 0.2; + + var _this; + var cartIsMine = false; + var originalY = 0; + var itemsID = []; + var scaleFactor = 0.7; //TODO: The scale factor will dipend on the number of items in the cart. We would resize even the items already present. + var cartTargetPosition; + var singlePrices = []; + var singlePriceTagsAreShowing = false; + var collidedItemID = null; + + // this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember + // our this object, so we can access it in cases where we're called without a this (like in the case of various global signals) + ShopCart = function() { + _this = this; + }; + + function update(deltaTime) { + _this.followAvatar(); + + if (Controller.getValue(Controller.Standard.RightPrimaryThumb)) { + _this.resetCart(); + _this.computeAndSendTotalPrice(); + + } + }; + + function receivingMessage(channel, message, senderID) { + if (senderID === MyAvatar.sessionUUID && channel == CART_REGISTER_CHANNEL) { + var messageObj = JSON.parse(message); + if (messageObj.senderEntity != _this.entityID) { + print("--------------- cart received message"); + //Receiving this message means that the register wants the total price + _this.computeAndSendTotalPrice(); + } + } + + }; + + ShopCart.prototype = { + + // preload() will be called when the entity has become visible (or known) to the interface + // it gives us a chance to set our local JavaScript object up. In this case it means: + // * remembering our entityID, so we can access it in cases where we're called without an entityID + // * connecting to the update signal so we can check our grabbed state + preload: function(entityID) { + this.entityID = entityID; + //get the owner ID from user data and compare to the mine + //so the update will be connected just for the owner + var ownerObj = getEntityCustomData('ownerKey', this.entityID, null); + if (ownerObj.ownerID === MyAvatar.sessionUUID) { + cartIsMine = true; + cartTargetPosition = Entities.getEntityProperties(_this.entityID).position; //useful if the entity script is assigned manually + Script.update.connect(update); + Messages.subscribe(CART_REGISTER_CHANNEL); + Messages.messageReceived.connect(receivingMessage); + } + }, + + //update cart's target position. It will be at the right of the avatar as long as he moves + followAvatar: function() { + if (Vec3.length(MyAvatar.getVelocity()) > 0.1) { + var radius = (Entities.getEntityProperties(_this.entityID).dimensions.x) / 2 + COMFORT_ARM_LENGTH; + var properY = MyAvatar.position.y + ((MyAvatar.getHeadPosition().y - MyAvatar.position.y) / 2); + var targetPositionPrecomputing = {x: MyAvatar.position.x, y: properY, z: MyAvatar.position.z}; + cartTargetPosition = Vec3.sum(targetPositionPrecomputing, Vec3.multiply(Quat.getRight(MyAvatar.orientation), radius)); + } + + var cartPosition = Entities.getEntityProperties(_this.entityID).position; + var positionDifference = Vec3.subtract(cartTargetPosition, cartPosition); + if (Vec3.length(positionDifference) > 0.1) { + //give to the cart the proper velocity and make it ignore for collision + Entities.editEntity(_this.entityID, { velocity: positionDifference }); + Entities.editEntity(_this.entityID, { ignoreForCollisions: true }); + if (collidedItemID != null) { + Entities.callEntityMethod(collidedItemID, 'setCartOverlayNotVisible', null); + collidedItemID = null; + } + } else if (Vec3.length(positionDifference) > 0.01) { + //give to the cart the proper velocity and make it NOT ignore for collision + Entities.editEntity(_this.entityID, { velocity: positionDifference }); + Entities.editEntity(_this.entityID, { ignoreForCollisions: false }); + } else if (Vec3.length(positionDifference) > 0) { + //set the position to be at the right of MyAvatar and make it NOT ignore for collision + Entities.editEntity(_this.entityID, { position: cartTargetPosition }); + positionDifference = Vec3.subtract(cartTargetPosition, cartPosition); + Entities.editEntity(_this.entityID, { velocity: positionDifference }); + Entities.editEntity(_this.entityID, { ignoreForCollisions: false }); + } + + }, + + // delete all items stored into the cart + resetCart: function () { + + //print("RESET CART - USER DATA: " + Entities.getEntityProperties(_this.entityID).userData); + if (itemsID.length != 0) { + if (singlePriceTagsAreShowing) { + _this.singlePriceOff(); + } + for (var i=0; i < itemsID.length; i++) { + Entities.deleteEntity(itemsID[i]); + } + + // Clear the userData field for the cart + Entities.editEntity(this.entityID, { userData: ""}); + + setEntityCustomData('ownerKey', this.entityID, { + ownerID: MyAvatar.sessionUUID + }); + + setEntityCustomData('grabbableKey', this.entityID, { + grabbable: false + }); + + itemsID = []; + } + }, + + //delete the item pointed by dataArray (data.id) from the cart because it's been grabbed from there + refreshCartContent: function (entityID, dataArray) { + var data = JSON.parse(dataArray[0]); + + for (var i=0; i < itemsID.length; i++) { + if(itemsID[i] == data.id) { + itemsID.splice(i, 1); + //if the price tags are showing we have to remove also the proper tag + if (singlePriceTagsAreShowing) { + singlePrices[i].destroy(); + singlePrices.splice(i, 1); + } + } + } + + _this.computeAndSendTotalPrice(); + }, + + //show the prices on each item into the cart + singlePriceOn: function () { + //create an array of text3D which follows the structure of the itemsID array. Each text3D is like the 'Store the item!' one + var i = 0; + itemsID.forEach( function(itemID) { + singlePrices[i] = new OverlayPanel({ + anchorPositionBinding: { entity: itemID }, + offsetPosition: { x: 0, y: 0.15, z: 0 }, + isFacingAvatar: true, + + }); + + var textPrice = new Text3DOverlay({ + text: "" + getEntityCustomData('infoKey', itemID, null).price + " $", + isFacingAvatar: false, + alpha: 1.0, + ignoreRayIntersection: true, + dimensions: { x: 0, y: 0 }, + backgroundColor: { red: 255, green: 255, blue: 255 }, + color: { red: 0, green: 0, blue: 0 }, + topMargin: 0.00625, + leftMargin: 0.00625, + bottomMargin: 0.1, + rightMargin: 0.00625, + lineHeight: 0.02, + alpha: 1, + backgroundAlpha: 0.3, + visible: true + }); + + singlePrices[i].addChild(textPrice); + i++; + }); + + singlePriceTagsAreShowing = true; + }, + + singlePriceOff: function () { + //destroy or make invisible the text3D, or both + singlePrices.forEach(function(panel) { + panel.destroy(); + }); + singlePrices = []; + singlePriceTagsAreShowing = false; + }, + + //Send to the register the total price for all the items in the cart + computeAndSendTotalPrice: function () { + var totalPrice = 0; + itemsID.forEach( function(itemID) { + var infoObj = getEntityCustomData('infoKey', itemID, null); + if(infoObj != null) { + totalPrice += infoObj.price; + } + }); + + var messageObj = {senderEntity: _this.entityID, totalPrice: totalPrice}; + Messages.sendMessage(CART_REGISTER_CHANNEL, JSON.stringify(messageObj)); + }, + + //dataArray stores the ID of the item which has to be stored into the cart + //this entity method is invoked by shopItemEntityScript.js + doSomething: function (entityID, dataArray) { + collidedItemID = null; + var data = JSON.parse(dataArray[0]); + var itemOwnerObj = getEntityCustomData('ownerKey', data.id, null); + + var cartOwnerObj = getEntityCustomData('ownerKey', this.entityID, null); + + if (cartOwnerObj == null) { + //print("The cart doesn't have a owner."); + Entities.deleteEntity(data.id); + } + + if (itemOwnerObj.ownerID === cartOwnerObj.ownerID) { + // TODO if itemsQuantity == fullCart resize all the items present in the cart and change the scaleFactor for this and next insert + + print("Going to put item in the cart!"); + var itemsQuantity = itemsID.length; + + itemsID[itemsQuantity] = data.id; + + var oldDimension = Entities.getEntityProperties(data.id).dimensions; + Entities.editEntity(data.id, { dimensions: Vec3.multiply(oldDimension, scaleFactor) }); + Entities.editEntity(data.id, { velocity: {x: 0.0, y: 0.0, z: 0.0} }); + // parent item to the cart + Entities.editEntity(data.id, { parentID: this.entityID }); + + itemsQuantity = itemsID.length; + + setEntityCustomData('statusKey', data.id, { + status: "inCart" + }); + + _this.computeAndSendTotalPrice(); + + //if the single price tags are showing we have to put a tag also in the new item + if (singlePriceTagsAreShowing) { + singlePrices[itemsQuantity-1] = new OverlayPanel({ + anchorPositionBinding: { entity: data.id }, + offsetPosition: { x: 0, y: 0.15, z: 0 }, + isFacingAvatar: true, + + }); + + var textPrice = new Text3DOverlay({ + text: "" + getEntityCustomData('infoKey', data.id, null).price + " $", + isFacingAvatar: false, + alpha: 1.0, + ignoreRayIntersection: true, + dimensions: { x: 0, y: 0 }, + backgroundColor: { red: 255, green: 255, blue: 255 }, + color: { red: 0, green: 0, blue: 0 }, + topMargin: 0.00625, + leftMargin: 0.00625, + bottomMargin: 0.1, + rightMargin: 0.00625, + lineHeight: 0.02, + alpha: 1, + backgroundAlpha: 0.3, + visible: true + }); + + singlePrices[itemsQuantity-1].addChild(textPrice); + } + } else { + print("Not your cart!"); + Entities.deleteEntity(data.id); + } + }, + + //detect when the item enters or leave the cart while it's grabbed + collisionWithEntity: function(myID, otherID, collisionInfo) { + var penetrationValue = Vec3.length(collisionInfo.penetration); + + var cartOwnerObj = getEntityCustomData('ownerKey', myID, null); + var itemOwnerObj = getEntityCustomData('ownerKey', otherID, null); + + if (penetrationValue > PENETRATION_THRESHOLD && collidedItemID === null) { + if (itemOwnerObj != null && itemOwnerObj.ownerID === cartOwnerObj.ownerID) { + Entities.callEntityMethod(otherID, 'setCartOverlayVisible', null); + collidedItemID = otherID; + } + } else if (penetrationValue < PENETRATION_THRESHOLD && collidedItemID !== null) { + if (itemOwnerObj != null && itemOwnerObj.ownerID === cartOwnerObj.ownerID) { + Entities.callEntityMethod(otherID, 'setCartOverlayNotVisible', null); + collidedItemID = null; + } + } + }, + + unload: function (entityID) { + print("UNLOAD CART"); + if(cartIsMine){ + Script.update.disconnect(update); + _this.resetCart(); //useful if the script is reloaded manually + //Entities.deleteEntity(_this.entityID); //comment for manual reload + Messages.unsubscribe(CART_REGISTER_CHANNEL); + Messages.messageReceived.disconnect(receivingMessage); + } + } + }; + + // entity scripts always need to return a newly constructed object of our type + return new ShopCart(); +}) \ No newline at end of file diff --git a/examples/vrShop/cart/shopCartSpawnEntityScript.js b/examples/vrShop/cart/shopCartSpawnEntityScript.js new file mode 100644 index 0000000000..b5b678d9fb --- /dev/null +++ b/examples/vrShop/cart/shopCartSpawnEntityScript.js @@ -0,0 +1,91 @@ +// shopCartSpawnEntityScript.js +// +// If an avatar doesn't own a cart and enters the zone, a cart is added. +// Otherwise if it already has a cart, this will be destroyed + +// Created by Alessandro Signa and Edgar Pironti on 01/13/2016 +// Copyright 2016 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 +// + + +(function () { + var CART_MASTER_NAME = "ShopCartZero"; + var CART_SCRIPT_URL = Script.resolvePath("shopCartEntityScript.js"); + var SHOP_GRAB_SCRIPT_URL = Script.resolvePath("../item/shopItemGrab.js"); + var _this; + var isOwningACart = false; + var cartMasterID = null; + var myCartID = null; + + + function SpawnCartZone() { + _this = this; + return; + }; + + + + SpawnCartZone.prototype = { + + preload: function (entityID) { + this.entityID = entityID; + // Look for the ShopCartZero. Every cart created by this script is a copy of it + var ids = Entities.findEntities(Entities.getEntityProperties(this.entityID).position, 50); + ids.forEach(function(id) { + var properties = Entities.getEntityProperties(id); + if (properties.name == CART_MASTER_NAME) { + cartMasterID = id; + print("Master Cart found"); + Entities.editEntity(_this.entityID, { collisionMask: "static,dynamic,otherAvatar" }); + + return; + } + }); + }, + + enterEntity: function (entityID) { + print("entering in the spawn cart area"); + + if (myCartID) { + Entities.callEntityMethod(myCartID, "resetCart"); + Entities.deleteEntity (myCartID); + myCartID = null; + } else { + var entityProperties = Entities.getEntityProperties(cartMasterID); + myCartID = Entities.addEntity({ + type: entityProperties.type, + name: "Shopping cart", + ignoreForCollisions: false, + collisionsWillMove: false, + position: entityProperties.position, + dimensions: entityProperties.dimensions, + modelURL: entityProperties.modelURL, + shapeType: entityProperties.shapeType, + originalTextures: entityProperties.originalTextures, + script: CART_SCRIPT_URL, + userData: JSON.stringify({ + ownerKey: { + ownerID: MyAvatar.sessionUUID + }, + grabbableKey: { + grabbable: false + } + }) + }); + } + }, + + leaveEntity: function (entityID) { + + }, + + unload: function (entityID) { + + } + } + + return new SpawnCartZone(); +}); \ No newline at end of file diff --git a/examples/vrShop/cart/shopCartZeroEntityScript.js b/examples/vrShop/cart/shopCartZeroEntityScript.js new file mode 100644 index 0000000000..6b3ef96a59 --- /dev/null +++ b/examples/vrShop/cart/shopCartZeroEntityScript.js @@ -0,0 +1,39 @@ +// shopCartZeroEntityScript.js +// + +// Created by Alessandro Signa and Edgar Pironti on 01/13/2016 +// Copyright 2016 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 +// + + +(function() { + BALL_ANGULAR_VELOCITY = {x:0, y:5, z:0} + var _this; + + + // this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember + // our this object, so we can access it in cases where we're called without a this (like in the case of various global signals) + ShopCartZero = function() { + _this = this; + }; + + + ShopCartZero.prototype = { + + // preload() will be called when the entity has become visible (or known) to the interface + // it gives us a chance to set our local JavaScript object up. In this case it means: + // * remembering our entityID, so we can access it in cases where we're called without an entityID + // * connecting to the update signal so we can check our grabbed state + preload: function(entityID) { + this.entityID = entityID; + Entities.editEntity(_this.entityID, { angularVelocity: BALL_ANGULAR_VELOCITY }); + Entities.editEntity(_this.entityID, { angularDamping: 0 }); + }, + }; + + // entity scripts always need to return a newly constructed object of our type + return new ShopCartZero(); +}) \ No newline at end of file diff --git a/examples/vrShop/cash/shopCashEntityScript.js b/examples/vrShop/cash/shopCashEntityScript.js new file mode 100644 index 0000000000..9efdaf8ee2 --- /dev/null +++ b/examples/vrShop/cash/shopCashEntityScript.js @@ -0,0 +1,94 @@ +// shopCashEntityScript.js +// +// When an avatar enters the zone the cashier bot (agent) is activated and the cash register as well. +// A credit card model will be added to the scene for make the payment + +// Created by Alessandro Signa and Edgar Pironti on 01/13/2016 +// Copyright 2016 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 +// + + +(function () { + var AGENT_PLAYBACK_CHANNEL = "playbackChannel"; + var PLAY_MESSAGE = "Play"; + var REGISTER_NAME = "CashRegister"; + var CARD_ANGULAR_VELOCITY = {x: 0, y: 2, z: 0}; + var CARD_POSITION_OFFSET = {x: 0, y: 0.5, z: 0}; + var CARD_INITIAL_ORIENTATION = {x: 0, y: 0, z: 40}; + var CARD_DIMENSIONS = {x: 0.02, y: 0.09, z: 0.15}; + var SCRIPT_URL = Script.resolvePath("shopCreditCardEntityScript.js"); + + var _this; + var cashRegisterID = null; + var cardID = null; + + + function CashZone() { + _this = this; + return; + }; + + CashZone.prototype = { + + preload: function (entityID) { + }, + + enterEntity: function (entityID) { + print("entering in the cash area"); + Messages.sendMessage(AGENT_PLAYBACK_CHANNEL, PLAY_MESSAGE); + print("Play sent."); + + // Look for the register + var entitiesInZone = Entities.findEntities(Entities.getEntityProperties(entityID).position, (Entities.getEntityProperties(entityID).dimensions.x)/2); + entitiesInZone.forEach( function(e) { + if (Entities.getEntityProperties(e).name == REGISTER_NAME) { + cashRegisterID = Entities.getEntityProperties(e).id; + print(cashRegisterID); + } + }); + + // create a credit card above register position + var cardPosition = Vec3.sum(Entities.getEntityProperties(cashRegisterID).position, CARD_POSITION_OFFSET); + var cardOrientationQuat = Quat.fromVec3Degrees(CARD_INITIAL_ORIENTATION); + + cardID = Entities.addEntity({ + type: "Model", + name: "CreditCard", + position: cardPosition, + rotation: cardOrientationQuat, + dimensions: CARD_DIMENSIONS, + collisionsWillMove: false, + ignoreForCollisions: false, + angularVelocity: CARD_ANGULAR_VELOCITY, + angularDamping: 0, + script: Script.resolvePath(SCRIPT_URL), + // We have to put the ownerID in the card, and check this property when grabbing the card. Otherwise it cannot be grabbed - I can only grab my card + userData: JSON.stringify({ + ownerKey: { + ownerID: MyAvatar.sessionUUID + } + }), + modelURL: "https://dl.dropboxusercontent.com/u/14127429/FBX/VRshop/CreditCard.fbx", + shapeType: "box" + }); + + Entities.callEntityMethod(cashRegisterID, 'cashRegisterOn', null); + }, + + leaveEntity: function (entityID) { + // destroy card + Entities.deleteEntity(cardID); + cardID = null; + + Entities.callEntityMethod(cashRegisterID, 'cashRegisterOff', null); + }, + + unload: function (entityID) { + } + } + + return new CashZone(); +}); \ No newline at end of file diff --git a/examples/vrShop/cash/shopCashRegisterEntityScript.js b/examples/vrShop/cash/shopCashRegisterEntityScript.js new file mode 100644 index 0000000000..bc6dd25f75 --- /dev/null +++ b/examples/vrShop/cash/shopCashRegisterEntityScript.js @@ -0,0 +1,166 @@ +// shopCashRegisterEntityScript.js +// +// The register manages the total price overlay and the payment through collision with credit card + +// Created by Alessandro Signa and Edgar Pironti on 01/13/2016 +// Copyright 2016 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 +// + +(function () { + var overlayManagerScript = Script.resolvePath("../../libraries/overlayManager.js"); + Script.include(overlayManagerScript); + + var SHOPPING_CART_NAME = "Shopping cart"; + var CART_REGISTER_CHANNEL = "Hifi-vrShop-Register"; + var CREDIT_CARD_NAME = "CreditCard"; + + var _this; + var cartID = null; + var registerPanel = null; + var priceText = null; + var payingAvatarID = null; + var totalPrice = 0; + + function CashRegister() { + _this = this; + return; + }; + + function receivingMessage(channel, message, senderID) { + if (senderID === MyAvatar.sessionUUID && channel == CART_REGISTER_CHANNEL) { + var messageObj = JSON.parse(message); + if (messageObj.senderEntity != _this.entityID) { + //This message means that the cart sent the total price: create or update the Overlay on the register + var price = messageObj.totalPrice.toFixed(2); + _this.cashRegisterOverlayOn("" + price + " $"); + totalPrice = messageObj.totalPrice; + } + } + }; + + CashRegister.prototype = { + + preload: function (entityID) { + this.entityID = entityID; + }, + + //This method is called by the cashZone when an avatar comes in it + //It has to find the cart belonging to that avatar and ask it the total price of the items + cashRegisterOn: function() { + print("cashRegister ON"); + Messages.subscribe(CART_REGISTER_CHANNEL); + Messages.messageReceived.connect(receivingMessage); + var cashRegisterPosition = Entities.getEntityProperties(_this.entityID).position; + var foundEntities = Entities.findEntities(cashRegisterPosition, 50); + foundEntities.forEach( function (foundEntityID) { + var entityName = Entities.getEntityProperties(foundEntityID).name; + if (entityName == SHOPPING_CART_NAME) { + var cartOwnerID = getEntityCustomData('ownerKey', foundEntityID, null).ownerID; + if (cartOwnerID == MyAvatar.sessionUUID) { + cartID = foundEntityID; + + } + } + }); + if (cartID != null) { + payingAvatarID = MyAvatar.sessionUUID; + Messages.sendMessage(CART_REGISTER_CHANNEL, JSON.stringify({senderEntity: _this.entityID})); //with this message the cart know that it has to compute and send back the total price of the items + Entities.callEntityMethod(cartID, 'singlePriceOn', null); + //sometimes the cart is unable to receive the message. I think it's a message mixer problem + } else { + payingAvatarID = null; + // Show anyway the overlay with the price 0$ + _this.cashRegisterOverlayOn("0 $"); + } + }, + + cashRegisterOff: function() { + print("cashRegister OFF"); + Messages.unsubscribe(CART_REGISTER_CHANNEL); + Messages.messageReceived.disconnect(receivingMessage); + priceText.visible = false; + if (cartID != null) { + Entities.callEntityMethod(cartID, 'singlePriceOff', null); + } + }, + + cashRegisterOverlayOn: function (string) { + print("cashRegister OVERLAY ON"); + var stringOffset = string.length * 0.018; + if (priceText == null) { + + registerPanel = new OverlayPanel({ + anchorPositionBinding: { entity: _this.entityID }, + offsetPosition: { x: 0, y: 0.21, z: -0.14 }, + isFacingAvatar: false, + + }); + + priceText = new Text3DOverlay({ + text: string, + isFacingAvatar: false, + ignoreRayIntersection: true, + dimensions: { x: 0, y: 0 }, + offsetPosition: { + x: -stringOffset, + y: 0, + z: 0 + }, + backgroundColor: { red: 255, green: 255, blue: 255 }, + color: { red: 0, green: 255, blue: 0 }, + topMargin: 0.00625, + leftMargin: 0.00625, + bottomMargin: 0.1, + rightMargin: 0.00625, + lineHeight: 0.06, + alpha: 1, + backgroundAlpha: 0.3, + visible: true + }); + + registerPanel.addChild(priceText); + } else { + priceText.text = string; + priceText.visible = true; + priceText.offsetPosition = { + x: -stringOffset, + y: 0, + z: 0 + }; + } + }, + + //Manage the collision with credit card + collisionWithEntity: function (myID, otherID, collisionInfo) { + var entityName = Entities.getEntityProperties(otherID).name; + var entityOwnerID = getEntityCustomData('ownerKey', otherID, null).ownerID; + if (entityName == CREDIT_CARD_NAME && entityOwnerID == payingAvatarID) { + //The register collided with the right credit card - CHECKOUT + Entities.deleteEntity(otherID); + Entities.callEntityMethod(cartID, 'resetCart', null); + _this.cashRegisterOverlayOn("THANK YOU!"); + _this.clean(); + } + }, + + //clean all the variable related to the cart + clean: function () { + cartID = null; + payingAvatarID = null; + totalPrice = 0; + }, + + unload: function (entityID) { + _this.clean(); + if (registerPanel != null) { + registerPanel.destroy(); + } + registerPanel = priceText = null; + } + } + + return new CashRegister(); +}); \ No newline at end of file diff --git a/examples/vrShop/cash/shopCashierAC.js b/examples/vrShop/cash/shopCashierAC.js new file mode 100644 index 0000000000..1219806e8a --- /dev/null +++ b/examples/vrShop/cash/shopCashierAC.js @@ -0,0 +1,73 @@ +// shopCashierAC.js +// + +// Created by Alessandro Signa and Edgar Pironti on 01/13/2016 +// Copyright 2016 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 + +// Set the following variable to the values needed +var clip_url = "atp:6865d9c89472d58b18929aff0ac779026bc129190f7536f71d3835f7e2629c93.hfr"; // This url is working in VRshop + + +var PLAYBACK_CHANNEL = "playbackChannel"; +var playFromCurrentLocation = false; +var useDisplayName = true; +var useAttachments = true; +var useAvatarModel = true; + +var totalTime = 0; +var subscribed = false; +var WAIT_FOR_AUDIO_MIXER = 1; + +var PLAY = "Play"; + +function getAction(channel, message, senderID) { + if(subscribed) { + print("I'm the agent and I received this: " + message); + + switch(message) { + case PLAY: + print("Play"); + if (!Recording.isPlaying()) { + Recording.setPlayerTime(0.0); + Recording.startPlaying(); + } + break; + + default: + print("Unknown action: " + action); + break; + } + } +} + + +function update(deltaTime) { + + totalTime += deltaTime; + + if (totalTime > WAIT_FOR_AUDIO_MIXER) { + if (!subscribed) { + Messages.subscribe(PLAYBACK_CHANNEL); + subscribed = true; + Recording.loadRecording(clip_url); + Recording.setPlayFromCurrentLocation(playFromCurrentLocation); + Recording.setPlayerUseDisplayName(useDisplayName); + Recording.setPlayerUseAttachments(useAttachments); + Recording.setPlayerUseHeadModel(false); + Recording.setPlayerUseSkeletonModel(useAvatarModel); + Agent.isAvatar = true; + } + } + +} + +Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == PLAYBACK_CHANNEL) { + getAction(channel, message, senderID); + } +}); + +Script.update.connect(update); \ No newline at end of file diff --git a/examples/vrShop/cash/shopCreditCardEntityScript.js b/examples/vrShop/cash/shopCreditCardEntityScript.js new file mode 100644 index 0000000000..cfefebfcda --- /dev/null +++ b/examples/vrShop/cash/shopCreditCardEntityScript.js @@ -0,0 +1,45 @@ +// shopCreditCardEntityScript.js +// + +// Created by Alessandro Signa and Edgar Pironti on 01/13/2016 +// Copyright 2016 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 +// + +(function() { + + var _this; + var entityProperties = null; + + // this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember + // our this object, so we can access it in cases where we're called without a this (like in the case of various global signals) + CreditCard = function() { + _this = this; + }; + + CreditCard.prototype = { + + preload: function(entityID) { + this.entityID = entityID; + var ownerObj = getEntityCustomData('ownerKey', this.entityID, null); + if (ownerObj.ownerID === MyAvatar.sessionUUID) { + myCard = true; + entityProperties = Entities.getEntityProperties(this.entityID); + } + }, + + releaseGrab: function () { + //reset the card to its original properties (position, angular velocity, ecc) + Entities.editEntity(_this.entityID, entityProperties); + }, + + unload: function (entityID) { + Entities.deleteEntity(this.entityID); + } + }; + + // entity scripts always need to return a newly constructed object of our type + return new CreditCard(); +}) \ No newline at end of file diff --git a/examples/vrShop/inspect/shopInspectEntityScript.js b/examples/vrShop/inspect/shopInspectEntityScript.js new file mode 100644 index 0000000000..dc8537043f --- /dev/null +++ b/examples/vrShop/inspect/shopInspectEntityScript.js @@ -0,0 +1,858 @@ +// shopInspectEntityScript.js +// +// The inspection entity which runs this entity script will be in fron of the avatar while he's grabbing an item. +// This script gives some information to the avatar using interactive 3DOverlays: +// - Drive the customer to put he item in the correct zone to inspect it +// - Create the UI while inspecting with text and buttons and manages the clicks on them modifying the item and communicating with agents +// And also it creates the MyController which are in charge to render the rays from the hands during inspecting and analysing their intersection with other overlays + +// Created by Alessandro Signa and Edgar Pironti on 01/13/2016 +// Copyright 2016 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 +// + + +(function() { + + + var utilitiesScript = Script.resolvePath("../../libraries/utils.js"); + var overlayManagerScript = Script.resolvePath("../../libraries/overlayManager.js"); + Script.include(utilitiesScript); + Script.include(overlayManagerScript); + + var AGENT_REVIEW_CHANNEL = "reviewChannel"; + var NO_REVIEWS_AVAILABLE = "No reviews available"; + var SEPARATOR = "Separator"; + var CAMERA_REVIEW = "CameraReview"; + + var ZERO_STAR_URL = "https://dl.dropboxusercontent.com/u/14127429/FBX/VRshop/0Star.png"; + var ONE_STAR_URL = "https://dl.dropboxusercontent.com/u/14127429/FBX/VRshop/1Star.png"; + var TWO_STAR_URL = "https://dl.dropboxusercontent.com/u/14127429/FBX/VRshop/2Star.png"; + var THREE_STAR_URL = "https://dl.dropboxusercontent.com/u/14127429/FBX/VRshop/3Star.png"; + + var POINTER_ICON_URL = "https://dl.dropboxusercontent.com/u/14127429/FBX/VRshop/Pointer.png"; + var TRY_ON_ICON = "https://dl.dropboxusercontent.com/u/14127429/FBX/VRshop/TryOn.png" + + var MIN_DIMENSION_THRESHOLD = null; + var IN_HAND_STATUS = "inHand"; + var IN_INSPECT_STATUS = "inInspect"; + + var RIGHT_HAND = 1; + var LEFT_HAND = 0; + + var LINE_LENGTH = 100; + var COLOR = { + red: 165, + green: 199, + blue: 218 + }; + + var COMFORT_ARM_LENGTH = 0.4; + + var PENETRATION_THRESHOLD = 0.2; + + var _this; + var inspecting = false; + var inspectingMyItem = false; + var inspectedEntityID = null; + var isUIWorking = false; + var wantToStopTrying = false; + var rightController = null; + var leftController = null; + var workingHand = null; + var collidedItemID = null; + var tempTryEntity = null; + var tryingOnAvatar = false; + var itemOriginalDimensions = null; + + var mainPanel = null; + var mirrorPanel = null; + var buttons = []; + var tryOnAvatarButton = null; + var playButton = null; + var nextButton = null; + var textReviewerName = null; + var modelURLsArray = []; + var previewURLsArray = []; + var starURL = null; + + var reviewIndex = 0; + var reviewsNumber = 0; + var dbMatrix = null; + + var separator = null; + var cameraReview = null; + + + var pointer = new Image3DOverlay({ //maybe we want to use one pointer for each hand ? + url: POINTER_ICON_URL, + dimensions: { + x: 0.015, + y: 0.015 + }, + alpha: 1, + emissive: true, + isFacingAvatar: false, + ignoreRayIntersection: true, + }) + + + + // this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember + // our this object, so we can access it in cases where we're called without a this (like in the case of various global signals) + InspectEntity = function() { + _this = this; + }; + + + function MyController(hand) { + this.hand = hand; + if (this.hand === RIGHT_HAND) { + this.getHandPosition = MyAvatar.getRightPalmPosition; + this.getHandRotation = MyAvatar.getRightPalmRotation; + this.bumper = Controller.Standard.RB; + } else { + this.getHandPosition = MyAvatar.getLeftPalmPosition; + this.getHandRotation = MyAvatar.getLeftPalmRotation; + this.bumper = Controller.Standard.LB; + } + + this.pickRay = null; // ray object + this.overlayLine = null; // id of line overlay + this.waitingForBumpReleased = false; + + this.overlayLineOn = function(closePoint, farPoint, color) { + if (this.overlayLine == null) { + var lineProperties = { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + ignoreRayIntersection: true, + visible: true, + alpha: 1 + }; + this.overlayLine = new Line3DOverlay(lineProperties); + } else { + this.overlayLine.start = closePoint; + this.overlayLine.end = farPoint; + } + }, + + this.updateRay = function() { + //update the ray object + this.pickRay = { + origin: this.getHandPosition(), + direction: Quat.getUp(this.getHandRotation()) + }; + + //update the ray overlay and the pointer + var rayPickResult = OverlayManager.findRayIntersection(this.pickRay); + if (rayPickResult.intersects) { + var normal = Vec3.multiply(Quat.getFront(Camera.getOrientation()), -1); + var offset = Vec3.multiply(normal, 0.001); + pointer.position = Vec3.sum(rayPickResult.intersection, offset); //pointer is a global Image3DOverlay + pointer.rotation = Camera.getOrientation(); + pointer.visible = true; + } else { + pointer.visible = false; + } + + var farPoint = rayPickResult.intersects ? rayPickResult.intersection : Vec3.sum(this.pickRay.origin, Vec3.multiply(this.pickRay.direction, LINE_LENGTH)); + this.overlayLineOn(this.pickRay.origin, farPoint, COLOR); + + }, + //the update of each hand has to update the ray belonging to that hand and handle the bumper event + this.updateHand = function() { + //detect the bumper event + var bumperPressed = Controller.getValue(this.bumper); + if (bumperPressed && this != workingHand) { + workingHand.clean(); + workingHand = this; + } else if (this != workingHand) { + return; + } + + this.updateRay(); + + //manage event on UI + if (bumperPressed && !this.waitingForBumpReleased) { + this.waitingForBumpReleased = true; //to avoid looping on the button while keep pressing the bumper + var triggeredButton = OverlayManager.findOnRay(this.pickRay); + if (triggeredButton != null) { + //search the index of the UI element triggered + for (var i = 0; i < buttons.length; i++) { + if (buttons[i] == triggeredButton) { + + _this.changeModel(i); + } + } + + //the nextButton moves to the next customer review, changing the agent accordingly + if (nextButton == triggeredButton) { + + reviewIndex ++; + if (reviewIndex == reviewsNumber) { + reviewIndex = 0; + } + + var message = { + command: "Show", + clip_url: dbMatrix[reviewIndex].clip_url + }; + + Messages.sendMessage(AGENT_REVIEW_CHANNEL, JSON.stringify(message)); + print("Show sent to agent"); + + // update UI + textReviewerName.text = dbMatrix[reviewIndex].name; + reviewerScore.url = starConverter(dbMatrix[reviewIndex].score); + print("UI updated"); + } + + //the playButton sends the play command to the agent + if (playButton == triggeredButton) { + var message = { + command: "Play", + clip_url: dbMatrix[reviewIndex].clip_url + }; + + Messages.sendMessage(AGENT_REVIEW_CHANNEL, JSON.stringify(message)); + print("Play sent to agent"); + + } + + //the tryOnAvatarButton change the camera mode and puts t a copy of the inspected item in a proper position on the the avatar + if (tryOnAvatarButton == triggeredButton) { + print("tryOnAvatar pressed!"); + + var itemPositionWhileTrying = null; + //All the offset here are good just for Will avatar increasing its size by one + switch (Entities.getEntityProperties(inspectedEntityID).name) { + case "Item_Sunglasses": + itemPositionWhileTrying = {x: 0, y: 0.04, z: 0.05}; + break; + case "Item_Hat": + itemPositionWhileTrying = {x: 0, y: 0.16, z: 0.025}; + break; + default: + //there isn't any position specified for that item, use a default one + itemPositionWhileTrying = {x: 0, y: 0.16, z: 0.025}; + break; + } + + //Code for the overlay text for the mirror. + mirrorPanel = new OverlayPanel({ + anchorPositionBinding: { avatar: "MyAvatar" }, + anchorRotationBinding: { avatar: "MyAvatar" }, + offsetPosition: { + x: 0.5, + y: 0.9, + z: 0 + }, + offsetRotation: Quat.fromVec3Degrees({x: 0, y: 180, z: 0}), + + isFacingAvatar: false + }); + var mirrorText = new Text3DOverlay({ + text: "Press the bumper to go back in inspection", + isFacingAvatar: false, + ignoreRayIntersection: true, + + + dimensions: { x: 0, y: 0 }, + backgroundColor: { red: 255, green: 255, blue: 255 }, + color: { red: 200, green: 0, blue: 0 }, + topMargin: 0.00625, + leftMargin: 0.00625, + bottomMargin: 0.1, + rightMargin: 0.00625, + lineHeight: 0.05, + alpha: 1, + backgroundAlpha: 0.3, + visible: true + }); + mirrorPanel.addChild(mirrorText); + + tryingOnAvatar = true; + + //Clean inspect Overlays and related stuff + workingHand.clean(); + mainPanel.destroy(); + mainPanel = null; + isUIWorking = false; + Entities.editEntity(inspectedEntityID, { visible: false }); //the inspected item becomes invisible + + + Camera.mode = "entity"; + Camera.cameraEntity = _this.entityID; + var entityProperties = Entities.getEntityProperties(inspectedEntityID); + tempTryEntity = Entities.addEntity({ + type: entityProperties.type, + name: entityProperties.name, + localPosition: itemPositionWhileTrying, + dimensions: itemOriginalDimensions, + collisionsWillMove: false, + ignoreForCollisions: true, + modelURL: entityProperties.modelURL, + shapeType: entityProperties.shapeType, + originalTextures: entityProperties.originalTextures, + parentID: MyAvatar.sessionUUID, + parentJointIndex: MyAvatar.getJointIndex("Head") + }); + } + } + } else if (!bumperPressed && this.waitingForBumpReleased) { + this.waitingForBumpReleased = false; + } + }, + + this.clean = function() { + this.pickRay = null; + this.overlayLine.destroy(); + this.overlayLine = null; + pointer.visible = false; + } + }; + + function update(deltaTime) { + + if (tryingOnAvatar) { + // if trying the item on avatar, wait for a bumper being pressed to exit this mode + //the bumper is already pressed when we get here because we triggered the button pressing the bumper so we have to wait it's released + if(Controller.getValue(workingHand.bumper) && wantToStopTrying) { + Camera.cameraEntity = null; + Camera.mode = "first person"; + mirrorPanel.destroy(); + mirrorPanel = null; + Entities.deleteEntity(tempTryEntity); + tempTryEntity = null; + Entities.editEntity(inspectedEntityID, { visible: true }); + _this.createInspectUI(); + tryingOnAvatar = false; + wantToStopTrying = false; + } else if (!Controller.getValue(workingHand.bumper) && !wantToStopTrying) { + //no bumper is pressed + wantToStopTrying = true; + } + return; + } else if (inspecting) { + //update the rays from both hands + leftController.updateHand(); + rightController.updateHand(); + + //check the item status for consistency + var entityStatus = getEntityCustomData('statusKey', inspectedEntityID, null).status; + if (entityStatus == IN_HAND_STATUS) { + //the inspection is over + inspecting = false; + inspectedEntityID = null; + } + } else if (isUIWorking) { + //getting here when the inspect phase end, so we want to clean the UI + // Destroy rays + workingHand.clean(); + + // Destroy overlay + mainPanel.destroy(); + isUIWorking = false; + + var message = { + command: "Hide", + clip_url: "" + }; + + Messages.sendMessage(AGENT_REVIEW_CHANNEL, JSON.stringify(message)); + print("Hide sent to agent"); + + if (separator != null || cameraReview != null) { + Entities.editEntity(separator, { visible: true }); + Entities.editEntity(separator, { locked: true }); + Entities.editEntity(cameraReview, { visible: true }); + Entities.editEntity(cameraReview, { locked: true }); + } + } + + _this.positionRotationUpdate(); + }; + + function starConverter(value) { + var starURL = ZERO_STAR_URL; + + switch(value) { + case 0: + starURL = ZERO_STAR_URL; + break; + + case 1: + starURL = ONE_STAR_URL; + break; + + case 2: + starURL = TWO_STAR_URL; + break; + + case 3: + starURL = THREE_STAR_URL; + break; + + default: + starURL = ZERO_STAR_URL; + break; + } + + return starURL; + }; + + + // look for the database entity relative to the inspected item + function findItemDataBase(entityID, item) { + var dataBaseID = null; + var databaseEntityName = item + "DB"; + var entitiesInZone = Entities.findEntities(Entities.getEntityProperties(entityID).position, (Entities.getEntityProperties(entityID).dimensions.x)*100); + + for (var i = 0; i < entitiesInZone.length && dataBaseID == null; i++) { + if (Entities.getEntityProperties(entitiesInZone[i]).name == databaseEntityName) { + dataBaseID = entitiesInZone[i]; + print("Database found! " + entitiesInZone[i]); + return dataBaseID; + } + } + print("No database for this item."); + return null; + }; + + function findItemByName(searchingPointEntityID, itemName) { + print("Looking for item: " + itemName); + var entitiesInZone = Entities.findEntities(Entities.getEntityProperties(searchingPointEntityID).position, (Entities.getEntityProperties(searchingPointEntityID).dimensions.x)*100); + + for (var i = 0; i < entitiesInZone.length; i++) { + if (Entities.getEntityProperties(entitiesInZone[i]).name == itemName) { + print(itemName + " found! " + entitiesInZone[i]); + return entitiesInZone[i]; + } + } + print("Item " + itemName + " not found"); + return null; + }; + + InspectEntity.prototype = { + + preload: function(entityID) { + this.entityID = entityID; + print("PRELOAD INSPECT ENTITY"); + //get the owner ID from user data and compare to the mine + //the update will be connected just for the owner + var ownerObj = getEntityCustomData('ownerKey', this.entityID, null); + if (ownerObj.ownerID === MyAvatar.sessionUUID) { + rightController = new MyController(RIGHT_HAND); //rightController and leftController are two objects + leftController = new MyController(LEFT_HAND); + workingHand = rightController; + inspectingMyItem = true; + inspectRadius = (Entities.getEntityProperties(_this.entityID).dimensions.x) / 2 + COMFORT_ARM_LENGTH; + Script.update.connect(update); + } + }, + + //Put the item which calls this method in inspect mode if it belongs to the owner of the inspect zone + doSomething: function (entityID, dataArray) { + var data = JSON.parse(dataArray[0]); + var itemOwnerObj = getEntityCustomData('ownerKey', data.id, null); + + var inspectOwnerObj = getEntityCustomData('ownerKey', this.entityID, null); + + if (inspectOwnerObj == null) { + Entities.deleteEntity(data.id); + } + + if (itemOwnerObj.ownerID === inspectOwnerObj.ownerID) { + //setup the things for inspecting the item + inspecting = true; + inspectedEntityID = data.id; //store the ID of the inspected entity + setEntityCustomData('statusKey', data.id, { + status: IN_INSPECT_STATUS + }); + _this.createInspectUI(); + itemOriginalDimensions = Entities.getEntityProperties(inspectedEntityID).dimensions; + + // find separator and camera and hide + separator = findItemByName(inspectedEntityID, SEPARATOR); + Entities.editEntity(separator, { locked: false }); + Entities.editEntity(separator, { visible: false }); + print("Got here! Entity to hide: " + separator); + cameraReview = findItemByName(inspectedEntityID, CAMERA_REVIEW); + Entities.editEntity(cameraReview, { locked: false }); + Entities.editEntity(cameraReview, { visible: false }); + print("Got here! Entity to hide: " + cameraReview); + } else { + Entities.deleteEntity(data.id); + } + }, + + //make the inspection entity stay at the proper position with respect to the avatar and camera positions + positionRotationUpdate: function() { + var newRotation; + if (tryingOnAvatar) { + newRotation = Vec3.sum(Quat.safeEulerAngles(MyAvatar.orientation), {x:0, y: 180, z: 0}); //neccessary to set properly the camera in entity mode when trying on avatar + Entities.editEntity(_this.entityID, { rotation: Quat.fromVec3Degrees(newRotation) }); + } else { + var newPosition = Vec3.sum(Camera.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), inspectRadius)); + Entities.editEntity(_this.entityID, { position: newPosition }); + newRotation = MyAvatar.orientation; + Entities.editEntity(_this.entityID, { rotation: newRotation }); + } + + newPosition = Vec3.sum(newPosition, Vec3.multiply(Quat.getRight(newRotation), 0.34)); + + }, + + createInspectUI : function() { + + var infoObj = getEntityCustomData('infoKey', inspectedEntityID, null); + var itemDescriptionString = null; + var priceNumber = -1; + var availabilityNumber = -1; + var wearable = false; + + if(infoObj != null) { + //var modelURLsLoop = infoObj.modelURLs; ?? + var rootURLString = infoObj.rootURL; + for (var i = 0; i < infoObj.modelURLs.length; i++) { + modelURLsArray[i] = rootURLString + infoObj.modelURLs[i]; + previewURLsArray[i] = rootURLString + infoObj.previewURLs[i]; + } + + itemDescriptionString = infoObj.description; + priceNumber = infoObj.price; + availabilityNumber = infoObj.availability; + wearable = infoObj.wearable; + infoObj = null; + } + + //Looking for the item DB, this entity has in its userData the info of the customer reviews for the item + var DBID = findItemDataBase(_this.entityID, Entities.getEntityProperties(inspectedEntityID).name); + + if (DBID != null) { + infoObj = getEntityCustomData('infoKey', DBID, null); + var scoreAverage = null; + var reviewerName = null; + + if(infoObj != null) { + dbMatrix = infoObj.dbKey; + reviewsNumber = infoObj.dbKey.length; + //print("DB matrix is " + dbMatrix + " with element number: " + reviewsNumber); + var scoreSum = null; + + for (var i = 0; i < dbMatrix.length; i++) { + scoreSum += dbMatrix[i].score; + } + + if (dbMatrix.length) { + scoreAverage = Math.round(scoreSum / dbMatrix.length); + reviewerName = dbMatrix[reviewIndex].name; + + var message = { + command: "Show", + clip_url: dbMatrix[reviewIndex].clip_url + }; + + Messages.sendMessage(AGENT_REVIEW_CHANNEL, JSON.stringify(message)); + print("Show sent to agent"); + } else { + //some default value if the DB is empty + scoreAverage = 0; + reviewerName = NO_REVIEWS_AVAILABLE; + } + + } + + print ("Creating inspect UI"); + //set the main panel to follow the inspect entity + mainPanel = new OverlayPanel({ + anchorPositionBinding: { entity: _this.entityID }, + anchorRotationBinding: { entity: _this.entityID }, + isFacingAvatar: false + }); + + var offsetPositionY = 0.2; + var offsetPositionX = -0.4; + + //these buttons are the 3 previews of the item + for (var i = 0; i < previewURLsArray.length; i++) { + buttons[i] = new Image3DOverlay({ + url: previewURLsArray[i], + dimensions: { + x: 0.15, + y: 0.15 + }, + isFacingAvatar: false, + alpha: 0.8, + ignoreRayIntersection: false, + offsetPosition: { + x: offsetPositionX, + y: offsetPositionY - (i * offsetPositionY), + z: 0 + }, + emissive: true, + }); + + mainPanel.addChild(buttons[i]); + } + + //aggregateScore is the average between those given by the reviewers + var aggregateScore = new Image3DOverlay({ + url: starConverter(scoreAverage), + dimensions: { + x: 0.25, + y: 0.25 + }, + isFacingAvatar: false, + alpha: 1, + ignoreRayIntersection: true, + offsetPosition: { + x: 0, + y: 0.27, + z: 0 + }, + emissive: true, + }); + + mainPanel.addChild(aggregateScore); + + //if any review is available create buttons to manage them + if (dbMatrix.length) { + + playButton = new Image3DOverlay({ + url: "https://dl.dropboxusercontent.com/u/14127429/FBX/VRshop/Play.png", + dimensions: { + x: 0.08, + y: 0.08 + }, + isFacingAvatar: false, + alpha: 1, + ignoreRayIntersection: false, + offsetPosition: { + x: 0.42, + y: 0.27, + z: 0 + }, + emissive: true, + }); + + mainPanel.addChild(playButton); + + + reviewerScore = new Image3DOverlay({ + url: starConverter(dbMatrix[reviewIndex].score), + dimensions: { + x: 0.15, + y: 0.15 + }, + isFacingAvatar: false, + alpha: 1, + ignoreRayIntersection: true, + offsetPosition: { + x: 0.31, + y: 0.26, + z: 0 + }, + emissive: true, + }); + + mainPanel.addChild(reviewerScore); + + nextButton = new Image3DOverlay({ + url: "https://dl.dropboxusercontent.com/u/14127429/FBX/VRshop/Next.png", + dimensions: { + x: 0.2, + y: 0.2 + }, + isFacingAvatar: false, + alpha: 1, + ignoreRayIntersection: false, + offsetPosition: { + x: 0.36, + y: 0.18, + z: 0 + }, + emissive: true, + }); + + + mainPanel.addChild(nextButton); + + } + + textReviewerName = new Text3DOverlay({ + text: reviewerName, + isFacingAvatar: false, + alpha: 1.0, + ignoreRayIntersection: true, + offsetPosition: { + x: 0.23, + y: 0.31, + z: 0 + }, + dimensions: { x: 0, y: 0 }, + backgroundColor: { red: 255, green: 255, blue: 255 }, + color: { red: 0, green: 0, blue: 0 }, + topMargin: 0.00625, + leftMargin: 0.00625, + bottomMargin: 0.1, + rightMargin: 0.00625, + lineHeight: 0.02, + alpha: 1, + backgroundAlpha: 0.3 + }); + + mainPanel.addChild(textReviewerName); + + //if the item is wearable create a tryOnAvatarButton + if (wearable) { + tryOnAvatarButton = new Image3DOverlay({ + url: TRY_ON_ICON, + dimensions: { + x: 0.2, + y: 0.2 + }, + isFacingAvatar: false, + alpha: 1, + ignoreRayIntersection: false, + offsetPosition: { + x: 0.35, + y: -0.22, + z: 0 + }, + emissive: true, + }); + + mainPanel.addChild(tryOnAvatarButton); + } + + + var textQuantityString = new Text3DOverlay({ + text: "Quantity: ", + isFacingAvatar: false, + alpha: 1.0, + ignoreRayIntersection: true, + offsetPosition: { + x: 0.25, + y: -0.3, + z: 0 + }, + dimensions: { x: 0, y: 0 }, + backgroundColor: { red: 255, green: 255, blue: 255 }, + color: { red: 0, green: 0, blue: 0 }, + topMargin: 0.00625, + leftMargin: 0.00625, + bottomMargin: 0.1, + rightMargin: 0.00625, + lineHeight: 0.02, + alpha: 1, + backgroundAlpha: 0.3 + }); + + mainPanel.addChild(textQuantityString); + + var textQuantityNumber = new Text3DOverlay({ + text: availabilityNumber, + isFacingAvatar: false, + alpha: 1.0, + ignoreRayIntersection: true, + offsetPosition: { + x: 0.28, + y: -0.32, + z: 0 + }, + dimensions: { x: 0, y: 0 }, + backgroundColor: { red: 255, green: 255, blue: 255 }, + color: { red: 0, green: 0, blue: 0 }, + topMargin: 0.00625, + leftMargin: 0.00625, + bottomMargin: 0.1, + rightMargin: 0.00625, + lineHeight: 0.06, + alpha: 1, + backgroundAlpha: 0.3 + }); + + mainPanel.addChild(textQuantityNumber); + + if (itemDescriptionString != null) { + var textDescription = new Text3DOverlay({ + text: "Price: " + priceNumber + "\nAdditional information: \n" + itemDescriptionString, + isFacingAvatar: false, + alpha: 1.0, + ignoreRayIntersection: true, + offsetPosition: { + x: -0.2, + y: -0.3, + z: 0 + }, + dimensions: { x: 0, y: 0 }, + backgroundColor: { red: 255, green: 255, blue: 255 }, + color: { red: 0, green: 0, blue: 0 }, + topMargin: 0.00625, + leftMargin: 0.00625, + bottomMargin: 0.1, + rightMargin: 0.00625, + lineHeight: 0.02, + alpha: 1, + backgroundAlpha: 0.3 + }); + + mainPanel.addChild(textDescription); + } + + + + print ("GOT HERE: Descrition " + itemDescriptionString + " Availability " + availabilityNumber); + + isUIWorking = true; + } + }, + + //Manage the collisions and tell to the item if it is into the this inspection area + collisionWithEntity: function(myID, otherID, collisionInfo) { + + var itemObj = getEntityCustomData('itemKey', _this.entityID, null); + if (itemObj != null) { + if (itemObj.itemID == otherID) { //verify that the inspect area is colliding with the actual item which created it + + var penetrationValue = Vec3.length(collisionInfo.penetration); + if (penetrationValue > PENETRATION_THRESHOLD && collidedItemID === null) { + collidedItemID = otherID; + print("Start collision with: " + Entities.getEntityProperties(collidedItemID).name); + Entities.callEntityMethod(otherID, 'changeOverlayColor', null); + + } else if (penetrationValue < PENETRATION_THRESHOLD && collidedItemID !== null) { + + print("End collision with: " + Entities.getEntityProperties(collidedItemID).name); + collidedItemID = null; + Entities.callEntityMethod(otherID, 'changeOverlayColor', null); + } + } + } + }, + + changeModel: function(index) { + var entityProperties = Entities.getEntityProperties(inspectedEntityID); + if (entityProperties.modelURL != modelURLsArray[index]) { + Entities.editEntity(inspectedEntityID, { modelURL: modelURLsArray[index] }); + } + }, + + unload: function (entityID) { + if(inspectingMyItem){ + print("UNLOAD INSPECT ENTITY"); + Script.update.disconnect(update); + + // clean UI + Entities.deleteEntity(_this.entityID); + } + } + }; + return new InspectEntity(); +}) \ No newline at end of file From 41e6dd48e07b4a0cee04d23966be06c3b0fbc11a Mon Sep 17 00:00:00 2001 From: AlessandroSigna Date: Thu, 14 Jan 2016 18:27:17 -0800 Subject: [PATCH 165/215] Overlay manager exposing findRayIntersection --- examples/libraries/overlayManager.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/libraries/overlayManager.js b/examples/libraries/overlayManager.js index 0623721375..ce79214537 100644 --- a/examples/libraries/overlayManager.js +++ b/examples/libraries/overlayManager.js @@ -383,6 +383,9 @@ searchList[object._id] = object; }); return searchList; + }, + findRayIntersection: function(pickRay) { + return Overlays.findRayIntersection(pickRay); } }; From b9352d3eaaaa2cf472fa571f7ef3498ae317fae7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 15 Jan 2016 08:44:52 -0800 Subject: [PATCH 166/215] prevent nan inside spring action --- libraries/physics/src/ObjectAction.cpp | 1 - libraries/physics/src/ObjectActionSpring.cpp | 14 +++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/libraries/physics/src/ObjectAction.cpp b/libraries/physics/src/ObjectAction.cpp index f90286845a..d32495e30c 100644 --- a/libraries/physics/src/ObjectAction.cpp +++ b/libraries/physics/src/ObjectAction.cpp @@ -241,7 +241,6 @@ void ObjectAction::activateBody(bool forceActivation) { auto rigidBody = getRigidBody(); if (rigidBody) { rigidBody->activate(forceActivation); - assert(rigidBody->isActive()); } else { qDebug() << "ObjectAction::activateBody -- no rigid body" << (void*)rigidBody; } diff --git a/libraries/physics/src/ObjectActionSpring.cpp b/libraries/physics/src/ObjectActionSpring.cpp index 3f2664fb12..dcd77c1010 100644 --- a/libraries/physics/src/ObjectActionSpring.cpp +++ b/libraries/physics/src/ObjectActionSpring.cpp @@ -58,16 +58,16 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) { const float MAX_TIMESCALE = 600.0f; // 10 min is a long time if (_linearTimeScale < MAX_TIMESCALE) { + btVector3 targetVelocity(0.0f, 0.0f, 0.0f); btVector3 offset = rigidBody->getCenterOfMassPosition() - glmToBullet(_positionalTarget); float offsetLength = offset.length(); - btVector3 targetVelocity(0.0f, 0.0f, 0.0f); - - float speed = (offsetLength > FLT_EPSILON) ? glm::min(offsetLength / _linearTimeScale, SPRING_MAX_SPEED) : 0.0f; - targetVelocity = (-speed / offsetLength) * offset; - if (speed > rigidBody->getLinearSleepingThreshold()) { - rigidBody->activate(); + if (offsetLength > FLT_EPSILON) { + float speed = glm::min(offsetLength / _linearTimeScale, SPRING_MAX_SPEED); + targetVelocity = (-speed / offsetLength) * offset; + if (speed > rigidBody->getLinearSleepingThreshold()) { + rigidBody->activate(); + } } - // this action is aggresively critically damped and defeats the current velocity rigidBody->setLinearVelocity(targetVelocity); } From 710fb5df53b79a69337522241c985e9c75bf3ced Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 15 Jan 2016 10:18:29 -0800 Subject: [PATCH 167/215] Fix shadowed orientation in LightStage --- libraries/render-utils/src/LightStage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index de0041ae00..d2b76a279a 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -27,7 +27,7 @@ void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float zBac } else { auto side = glm::normalize(glm::cross(direction, IDENTITY_UP)); auto up = glm::normalize(glm::cross(side, direction)); - auto orientation = glm::quat(glm::mat3(direction, up, side)); + orientation = glm::quat(glm::mat3(direction, up, side)); } _frustum->setOrientation(orientation); From e914f024450c817adf9b2eb29b6b76dd40a4ccec Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 15 Jan 2016 10:28:52 -0800 Subject: [PATCH 168/215] Use near/far in LightStage setFrustum --- libraries/render-utils/src/LightStage.cpp | 8 ++++---- libraries/render-utils/src/LightStage.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index d2b76a279a..0ff83ca93e 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -18,7 +18,7 @@ LightStage::Shadow::Shadow(model::LightPointer light) : _light{ light}, _frustum map = framebuffer->getDepthStencilBuffer(); } -void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float zBack, float zFront) { +void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float near, float far) { // Orient the keylight frustum const auto& direction = glm::normalize(_light->getDirection()); glm::quat orientation; @@ -32,7 +32,7 @@ void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float zBac _frustum->setOrientation(orientation); // Position the keylight frustum - _frustum->setPosition(viewFrustum->getPosition() - 21.0f * direction); + _frustum->setPosition(viewFrustum->getPosition() - (glm::abs(near) + glm::abs(far))*direction); _view = _frustum->getView(); const Transform viewInverse{ _view.getInverseMatrix() }; @@ -40,8 +40,8 @@ void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float zBac viewFrustum->calculate(); //const auto nearCorners = viewFrustum->getCorners(0); const auto nearClip = viewFrustum->getNearClip(); - const auto nearCorners = viewFrustum->getCorners(nearClip - 1); - const auto farCorners = viewFrustum->getCorners(nearClip + 20); + const auto nearCorners = viewFrustum->getCorners(near); + const auto farCorners = viewFrustum->getCorners(far); vec3 min{ viewInverse.transform(nearCorners.bottomLeft) }; vec3 max{ min }; diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index 28ffd2ca0f..d95f82230d 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -27,7 +27,7 @@ public: Shadow(model::LightPointer light); - void setKeylightFrustum(ViewFrustum* viewFrustum, float zBack, float zFront); + void setKeylightFrustum(ViewFrustum* viewFrustum, float near, float far); const std::shared_ptr getFrustum() const { return _frustum; } const glm::mat4& getProjection() const { return _projection; } From b423bc38ba83d19437d3f8b82731bd690f5b6c36 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 15 Jan 2016 10:46:01 -0800 Subject: [PATCH 169/215] Remove magic numbers --- libraries/render-utils/src/LightStage.cpp | 10 ++++++---- libraries/render-utils/src/RenderShadowTask.cpp | 8 +++++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 0ff83ca93e..3b8eddd3b4 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -18,7 +18,9 @@ LightStage::Shadow::Shadow(model::LightPointer light) : _light{ light}, _frustum map = framebuffer->getDepthStencilBuffer(); } -void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float near, float far) { +void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float nearDepth, float farDepth) { + assert(nearDepth >= 0 && farDepth > 0); + // Orient the keylight frustum const auto& direction = glm::normalize(_light->getDirection()); glm::quat orientation; @@ -32,7 +34,7 @@ void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float near _frustum->setOrientation(orientation); // Position the keylight frustum - _frustum->setPosition(viewFrustum->getPosition() - (glm::abs(near) + glm::abs(far))*direction); + _frustum->setPosition(viewFrustum->getPosition() - (nearDepth + farDepth)*direction); _view = _frustum->getView(); const Transform viewInverse{ _view.getInverseMatrix() }; @@ -40,8 +42,8 @@ void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float near viewFrustum->calculate(); //const auto nearCorners = viewFrustum->getCorners(0); const auto nearClip = viewFrustum->getNearClip(); - const auto nearCorners = viewFrustum->getCorners(near); - const auto farCorners = viewFrustum->getCorners(far); + const auto nearCorners = viewFrustum->getCorners(nearDepth); + const auto farCorners = viewFrustum->getCorners(farDepth); vec3 min{ viewInverse.transform(nearCorners.bottomLeft) }; vec3 max{ min }; diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 1447da624d..5735fe8318 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -102,7 +102,6 @@ void RenderShadowTask::run(const SceneContextPointer& sceneContext, const Render return; } - // TODO: If we're not using the global keylight, bail const auto& lightStage = DependencyManager::get()->getLightStage(); const auto globalLight = lightStage.lights[0]; @@ -113,8 +112,11 @@ void RenderShadowTask::run(const SceneContextPointer& sceneContext, const Render ViewFrustum* viewFrustum = args->_viewFrustum; - const auto nearClip = viewFrustum->getNearClip(); - globalLight->shadow.setKeylightFrustum(viewFrustum, nearClip - 1, nearClip + 20); + auto nearClip = viewFrustum->getNearClip(); + const int SHADOW_NEAR_DEPTH = -1; + const int SHADOW_FAR_DEPTH = 20; + globalLight->shadow.setKeylightFrustum(viewFrustum, + glm::max(0.0f, nearClip - SHADOW_NEAR_DEPTH), nearClip + SHADOW_FAR_DEPTH); // Set the keylight frustum args->_viewFrustum = globalLight->shadow.getFrustum().get(); From 986af50b7139e300b113846f380d08e219bc1f9d Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 15 Jan 2016 10:50:42 -0800 Subject: [PATCH 170/215] Remove unneccessary const --- libraries/octree/src/ViewFrustum.cpp | 4 ++-- libraries/render-utils/src/LightStage.cpp | 7 ++----- libraries/render-utils/src/RenderDeferredTask.cpp | 12 ++++++------ 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/libraries/octree/src/ViewFrustum.cpp b/libraries/octree/src/ViewFrustum.cpp index 0e7df1d9a4..85df5a0c93 100644 --- a/libraries/octree/src/ViewFrustum.cpp +++ b/libraries/octree/src/ViewFrustum.cpp @@ -740,8 +740,8 @@ const ViewFrustum::Corners ViewFrustum::getCorners(const float& depth) { glm::vec3 normal = glm::normalize(_direction); auto getCorner = [&](enum::BoxVertex nearCorner, enum::BoxVertex farCorner) { - const auto dir = glm::normalize(_cornersWorld[nearCorner] - _cornersWorld[farCorner]); - const auto factor = depth / glm::dot(dir, normal); + auto dir = glm::normalize(_cornersWorld[nearCorner] - _cornersWorld[farCorner]); + auto factor = depth / glm::dot(dir, normal); return _position + factor * dir; }; diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 3b8eddd3b4..708c136eab 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -40,10 +40,8 @@ void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float near const Transform viewInverse{ _view.getInverseMatrix() }; viewFrustum->calculate(); - //const auto nearCorners = viewFrustum->getCorners(0); - const auto nearClip = viewFrustum->getNearClip(); - const auto nearCorners = viewFrustum->getCorners(nearDepth); - const auto farCorners = viewFrustum->getCorners(farDepth); + auto nearCorners = viewFrustum->getCorners(nearDepth); + auto farCorners = viewFrustum->getCorners(farDepth); vec3 min{ viewInverse.transform(nearCorners.bottomLeft) }; vec3 max{ min }; @@ -59,7 +57,6 @@ void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float near max.y = glm::max(max.y, corner.y); max.z = glm::max(max.z, corner.z); }; - fitFrustum(nearCorners.bottomLeft); fitFrustum(nearCorners.bottomRight); fitFrustum(nearCorners.topLeft); fitFrustum(nearCorners.topRight); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index d0d0338742..c458a23812 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -78,21 +78,21 @@ RenderDeferredTask::RenderDeferredTask() : Task() { initDeferredPipelines(*shapePlumber); // CPU: Fetch the renderOpaques - const auto fetchedOpaques = addJob("FetchOpaque", FetchItems([](const RenderContextPointer& context, int count) { + auto fetchedOpaques = addJob("FetchOpaque", FetchItems([](const RenderContextPointer& context, int count) { context->getItemsConfig().opaque.numFeed = count; })); - const auto culledOpaques = addJob>("CullOpaque", fetchedOpaques); - const auto opaques = addJob("DepthSortOpaque", culledOpaques); + auto culledOpaques = addJob>("CullOpaque", fetchedOpaques); + auto opaques = addJob("DepthSortOpaque", culledOpaques); // CPU only, create the list of renderedTransparents items - const auto fetchedTransparents = addJob("FetchTransparent", FetchItems( + auto fetchedTransparents = addJob("FetchTransparent", FetchItems( ItemFilter::Builder::transparentShape().withoutLayered(), [](const RenderContextPointer& context, int count) { context->getItemsConfig().transparent.numFeed = count; } )); - const auto culledTransparents = addJob>("CullTransparent", fetchedTransparents); - const auto transparents = addJob("DepthSortTransparent", culledTransparents, DepthSortItems(false)); + auto culledTransparents = addJob>("CullTransparent", fetchedTransparents); + auto transparents = addJob("DepthSortTransparent", culledTransparents, DepthSortItems(false)); // GPU Jobs: Start preparing the deferred and lighting buffer addJob("PrepareDeferred"); From d6e5e2de815079a2f0d25617c77aa3b430cdf11a Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 15 Jan 2016 12:43:45 -0800 Subject: [PATCH 171/215] Fix orientation of shadow frustum --- libraries/render-utils/src/LightStage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 708c136eab..f6c2e14f2b 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -25,11 +25,11 @@ void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float near const auto& direction = glm::normalize(_light->getDirection()); glm::quat orientation; if (direction == IDENTITY_UP) { - orientation = glm::quat(glm::mat3(IDENTITY_UP, -IDENTITY_FRONT, IDENTITY_RIGHT)); + orientation = glm::quat(glm::mat3(IDENTITY_RIGHT, IDENTITY_UP, IDENTITY_FRONT)); } else { auto side = glm::normalize(glm::cross(direction, IDENTITY_UP)); auto up = glm::normalize(glm::cross(side, direction)); - orientation = glm::quat(glm::mat3(direction, up, side)); + orientation = glm::quat_cast(glm::mat3(side, up, -direction)); } _frustum->setOrientation(orientation); From 5c1c1e3a3b5600b97178e06d69105ad66f367f6d Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 15 Jan 2016 12:57:31 -0800 Subject: [PATCH 172/215] Change LightStage setFrustum signature to near/farDepth --- libraries/render-utils/src/LightStage.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index d95f82230d..3d59de6164 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -27,7 +27,7 @@ public: Shadow(model::LightPointer light); - void setKeylightFrustum(ViewFrustum* viewFrustum, float near, float far); + void setKeylightFrustum(ViewFrustum* viewFrustum, float nearDepth, float farDepth); const std::shared_ptr getFrustum() const { return _frustum; } const glm::mat4& getProjection() const { return _projection; } From bb02a1eda2650d6fa6d75d9edcf23e606d80f15a Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 15 Jan 2016 14:45:40 -0800 Subject: [PATCH 173/215] Fix JS web window crash caused by race condition --- libraries/ui/src/QmlWebWindowClass.cpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/libraries/ui/src/QmlWebWindowClass.cpp b/libraries/ui/src/QmlWebWindowClass.cpp index 8bf36b111f..96e99654c8 100644 --- a/libraries/ui/src/QmlWebWindowClass.cpp +++ b/libraries/ui/src/QmlWebWindowClass.cpp @@ -42,19 +42,15 @@ QmlWebWindowClass::QmlWebWindowClass(QObject* qmlWindow) : QmlWindowClass(qmlWin void QmlWebWindowClass::handleNavigation(const QString& url) { } -QString QmlWebWindowClass::getURL() const { - if (QThread::currentThread() != thread()) { - QString result; - QMetaObject::invokeMethod(const_cast(this), "getURL", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, result)); - return result; - } - - return _qmlWindow->property(URL_PROPERTY).toString(); +QString QmlWebWindowClass::getURL() const { + QVariant result = DependencyManager::get()->returnFromUiThread([&]()->QVariant { + return _qmlWindow->property(URL_PROPERTY); + }); + return result.toString(); } void QmlWebWindowClass::setURL(const QString& urlString) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setURL", Qt::QueuedConnection, Q_ARG(QString, urlString)); - } - _qmlWindow->setProperty(URL_PROPERTY, urlString); -} \ No newline at end of file + DependencyManager::get()->executeOnUiThread([=] { + _qmlWindow->setProperty(URL_PROPERTY, urlString); + }); +} From 8b420adbc8c4ede991133da9af7a7a94fbffeba7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 13 Jan 2016 13:42:49 -0800 Subject: [PATCH 174/215] namechange MotionType to PhysicsMotionType --- interface/src/avatar/AvatarMotionState.cpp | 2 +- interface/src/avatar/AvatarMotionState.h | 4 ++-- libraries/physics/src/EntityMotionState.cpp | 8 ++++---- libraries/physics/src/EntityMotionState.h | 6 +++--- libraries/physics/src/ObjectMotionState.cpp | 2 +- libraries/physics/src/ObjectMotionState.h | 12 ++++++------ libraries/physics/src/PhysicsEngine.cpp | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/interface/src/avatar/AvatarMotionState.cpp b/interface/src/avatar/AvatarMotionState.cpp index 7f11c83c4a..84f276529a 100644 --- a/interface/src/avatar/AvatarMotionState.cpp +++ b/interface/src/avatar/AvatarMotionState.cpp @@ -41,7 +41,7 @@ void AvatarMotionState::clearIncomingDirtyFlags() { } } -MotionType AvatarMotionState::computeObjectMotionType() const { +PhysicsMotionType AvatarMotionState::computePhysicsMotionType() const { // TODO?: support non-DYNAMIC motion for avatars? (e.g. when sitting) return MOTION_TYPE_DYNAMIC; } diff --git a/interface/src/avatar/AvatarMotionState.h b/interface/src/avatar/AvatarMotionState.h index f02dba54bd..51b4e5627e 100644 --- a/interface/src/avatar/AvatarMotionState.h +++ b/interface/src/avatar/AvatarMotionState.h @@ -22,12 +22,12 @@ class AvatarMotionState : public ObjectMotionState { public: AvatarMotionState(Avatar* avatar, btCollisionShape* shape); - virtual MotionType getMotionType() const override { return _motionType; } + virtual PhysicsMotionType getMotionType() const override { return _motionType; } virtual uint32_t getIncomingDirtyFlags() override; virtual void clearIncomingDirtyFlags() override; - virtual MotionType computeObjectMotionType() const override; + virtual PhysicsMotionType computePhysicsMotionType() const override; virtual bool isMoving() const override; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 2c09c3aa55..74fc7b0716 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -139,7 +139,7 @@ bool EntityMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* return ObjectMotionState::handleHardAndEasyChanges(flags, engine); } -MotionType EntityMotionState::computeObjectMotionType() const { +PhysicsMotionType EntityMotionState::computePhysicsMotionType() const { if (!_entity) { return MOTION_TYPE_STATIC; } @@ -157,7 +157,7 @@ bool EntityMotionState::isMoving() const { // This callback is invoked by the physics simulation in two cases: // (1) when the RigidBody is first added to the world -// (irregardless of MotionType: STATIC, DYNAMIC, or KINEMATIC) +// (irregardless of PhysicsMotionType: STATIC, DYNAMIC, or KINEMATIC) // (2) at the beginning of each simulation step for KINEMATIC RigidBody's -- // it is an opportunity for outside code to update the object's simulation position void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { @@ -608,7 +608,7 @@ glm::vec3 EntityMotionState::getObjectLinearVelocityChange() const { } // virtual -void EntityMotionState::setMotionType(MotionType motionType) { +void EntityMotionState::setMotionType(PhysicsMotionType motionType) { ObjectMotionState::setMotionType(motionType); resetMeasuredBodyAcceleration(); } @@ -627,7 +627,7 @@ void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& ma if (_entity->getIgnoreForCollisions()) { group = BULLET_COLLISION_GROUP_COLLISIONLESS; } - switch (computeObjectMotionType()){ + switch (computePhysicsMotionType()){ case MOTION_TYPE_STATIC: group = BULLET_COLLISION_GROUP_STATIC; break; diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 7d7987b641..b579d4442d 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -32,8 +32,8 @@ public: virtual bool handleEasyChanges(uint32_t& flags); virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine); - /// \return MOTION_TYPE_DYNAMIC or MOTION_TYPE_STATIC based on params set in EntityItem - virtual MotionType computeObjectMotionType() const; + /// \return PhysicsMotionType based on params set in EntityItem + virtual PhysicsMotionType computePhysicsMotionType() const; virtual bool isMoving() const; @@ -94,7 +94,7 @@ protected: virtual bool isReadyToComputeShape() const override; virtual btCollisionShape* computeNewShape(); - virtual void setMotionType(MotionType motionType); + virtual void setMotionType(PhysicsMotionType motionType); // In the glorious future (when entities lib depends on physics lib) the EntityMotionState will be // properly "owned" by the EntityItem and will be deleted by it in the dtor. In pursuit of that diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index ecce821adf..482c3146f8 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -120,7 +120,7 @@ void ObjectMotionState::releaseShape() { } } -void ObjectMotionState::setMotionType(MotionType motionType) { +void ObjectMotionState::setMotionType(PhysicsMotionType motionType) { _motionType = motionType; } diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 4a90b1d985..539327ce0c 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -23,13 +23,13 @@ #include "ContactInfo.h" #include "ShapeManager.h" -enum MotionType { +enum PhysicsMotionType { MOTION_TYPE_STATIC, // no motion MOTION_TYPE_DYNAMIC, // motion according to physical laws MOTION_TYPE_KINEMATIC // keyframed motion }; -inline QString motionTypeToString(MotionType motionType) { +inline QString motionTypeToString(PhysicsMotionType motionType) { switch(motionType) { case MOTION_TYPE_STATIC: return QString("static"); case MOTION_TYPE_DYNAMIC: return QString("dynamic"); @@ -88,7 +88,7 @@ public: virtual void updateBodyMassProperties(); MotionStateType getType() const { return _type; } - virtual MotionType getMotionType() const { return _motionType; } + virtual PhysicsMotionType getMotionType() const { return _motionType; } void setMass(float mass) { _mass = fabsf(mass); } float getMass() { return _mass; } @@ -105,7 +105,7 @@ public: virtual uint32_t getIncomingDirtyFlags() = 0; virtual void clearIncomingDirtyFlags() = 0; - virtual MotionType computeObjectMotionType() const = 0; + virtual PhysicsMotionType computePhysicsMotionType() const = 0; btCollisionShape* getShape() const { return _shape; } btRigidBody* getRigidBody() const { return _body; } @@ -150,13 +150,13 @@ public: protected: virtual bool isReadyToComputeShape() const = 0; virtual btCollisionShape* computeNewShape() = 0; - void setMotionType(MotionType motionType); + void setMotionType(PhysicsMotionType motionType); void updateCCDConfiguration(); void setRigidBody(btRigidBody* body); MotionStateType _type = MOTIONSTATE_TYPE_INVALID; // type of MotionState - MotionType _motionType; // type of motion: KINEMATIC, DYNAMIC, or STATIC + PhysicsMotionType _motionType; // type of motion: KINEMATIC, DYNAMIC, or STATIC btCollisionShape* _shape; btRigidBody* _body; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index b665be5d53..691f2b89c5 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -98,7 +98,7 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { float mass = 0.0f; // NOTE: the body may or may not already exist, depending on whether this corresponds to a reinsertion, or a new insertion. btRigidBody* body = motionState->getRigidBody(); - MotionType motionType = motionState->computeObjectMotionType(); + PhysicsMotionType motionType = motionState->computePhysicsMotionType(); motionState->setMotionType(motionType); switch(motionType) { case MOTION_TYPE_KINEMATIC: { From 952f5b23f694560ef3d0b6b127a4cec539c7bf4e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 13 Jan 2016 17:48:51 -0800 Subject: [PATCH 175/215] namechange collisionsWillMove --> dynamic --- libraries/entities/src/EntityItem.cpp | 18 +++++++-------- libraries/entities/src/EntityItem.h | 9 ++++---- .../entities/src/EntityItemProperties.cpp | 23 +++++++++++-------- libraries/entities/src/EntityItemProperties.h | 4 ++-- .../src/EntityItemPropertiesDefaults.h | 2 +- .../entities/src/EntityItemPropertiesMacros.h | 10 +++++++- libraries/entities/src/EntityPropertyFlags.h | 6 ++--- libraries/entities/src/EntityTree.cpp | 8 +++---- libraries/physics/src/EntityMotionState.cpp | 2 +- 9 files changed, 46 insertions(+), 36 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 0a7a30f098..93826d0fbf 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -65,7 +65,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _visible(ENTITY_ITEM_DEFAULT_VISIBLE), _ignoreForCollisions(ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS), _collisionMask(ENTITY_COLLISION_MASK_DEFAULT), - _collisionsWillMove(ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE), + _dynamic(ENTITY_ITEM_DEFAULT_DYNAMIC), _locked(ENTITY_ITEM_DEFAULT_LOCKED), _userData(ENTITY_ITEM_DEFAULT_USER_DATA), _simulationOwner(), @@ -125,7 +125,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_VISIBLE; requestedProperties += PROP_IGNORE_FOR_COLLISIONS; requestedProperties += PROP_COLLISION_MASK; - requestedProperties += PROP_COLLISIONS_WILL_MOVE; + requestedProperties += PROP_DYNAMIC; requestedProperties += PROP_LOCKED; requestedProperties += PROP_USER_DATA; requestedProperties += PROP_MARKETPLACE_ID; @@ -262,7 +262,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_VISIBLE, getVisible()); APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, getIgnoreForCollisions()); APPEND_ENTITY_PROPERTY(PROP_COLLISION_MASK, getCollisionMask()); - APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, getCollisionsWillMove()); + APPEND_ENTITY_PROPERTY(PROP_DYNAMIC, getDynamic()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, getLocked()); APPEND_ENTITY_PROPERTY(PROP_USER_DATA, getUserData()); APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, getMarketplaceID()); @@ -682,7 +682,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible); READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, updateIgnoreForCollisions); READ_ENTITY_PROPERTY(PROP_COLLISION_MASK, uint8_t, updateCollisionMask); - READ_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, bool, updateCollisionsWillMove); + READ_ENTITY_PROPERTY(PROP_DYNAMIC, bool, updateDynamic); READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData); @@ -1046,7 +1046,7 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper COPY_ENTITY_PROPERTY_TO_PROPERTIES(visible, getVisible); COPY_ENTITY_PROPERTY_TO_PROPERTIES(ignoreForCollisions, getIgnoreForCollisions); COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionMask, getCollisionMask); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionsWillMove, getCollisionsWillMove); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(dynamic, getDynamic); COPY_ENTITY_PROPERTY_TO_PROPERTIES(locked, getLocked); COPY_ENTITY_PROPERTY_TO_PROPERTIES(userData, getUserData); COPY_ENTITY_PROPERTY_TO_PROPERTIES(marketplaceID, getMarketplaceID); @@ -1102,7 +1102,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(friction, updateFriction); SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, updateIgnoreForCollisions); SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionMask, updateCollisionMask); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, updateCollisionsWillMove); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(dynamic, updateDynamic); SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, updateCreated); SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime); @@ -1458,9 +1458,9 @@ void EntityItem::updateCollisionMask(uint8_t value) { } } -void EntityItem::updateCollisionsWillMove(bool value) { - if (_collisionsWillMove != value) { - _collisionsWillMove = value; +void EntityItem::updateDynamic(bool value) { + if (_dynamic != value) { + _dynamic = value; _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; } } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index d0b79723d1..f00ad7691a 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -278,8 +278,8 @@ public: uint8_t getFinalCollisionMask() const { return _ignoreForCollisions ? 0 : _collisionMask; } void setCollisionMask(uint8_t value) { _collisionMask = value; } - bool getCollisionsWillMove() const { return _collisionsWillMove; } - void setCollisionsWillMove(bool value) { _collisionsWillMove = value; } + bool getDynamic() const { return _dynamic; } + void setDynamic(bool value) { _dynamic = value; } virtual bool shouldBePhysical() const { return false; } @@ -333,7 +333,7 @@ public: void updateAngularDamping(float value); void updateIgnoreForCollisions(bool value); void updateCollisionMask(uint8_t value); - void updateCollisionsWillMove(bool value); + void updateDynamic(bool value); void updateLifetime(float value); void updateCreated(uint64_t value); virtual void updateShapeType(ShapeType type) { /* do nothing */ } @@ -447,8 +447,7 @@ protected: bool _visible; bool _ignoreForCollisions; uint8_t _collisionMask { ENTITY_COLLISION_MASK_DEFAULT }; - uint8_t _collisionGroupOverride; - bool _collisionsWillMove; + bool _dynamic; bool _locked; QString _userData; SimulationOwner _simulationOwner; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index f8dcb6ee56..cc53b35c3b 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -257,7 +257,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_ANGULAR_DAMPING, angularDamping); CHECK_PROPERTY_CHANGE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions); CHECK_PROPERTY_CHANGE(PROP_COLLISION_MASK, collisionMask); - CHECK_PROPERTY_CHANGE(PROP_COLLISIONS_WILL_MOVE, collisionsWillMove); + CHECK_PROPERTY_CHANGE(PROP_DYNAMIC, dynamic); CHECK_PROPERTY_CHANGE(PROP_IS_SPOTLIGHT, isSpotlight); CHECK_PROPERTY_CHANGE(PROP_INTENSITY, intensity); CHECK_PROPERTY_CHANGE(PROP_EXPONENT, exponent); @@ -372,7 +372,8 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE, visible); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_COLLISION_MASK, collisionMask, getCollisionMaskAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISIONS_WILL_MOVE, collisionsWillMove); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DYNAMIC, dynamic); + COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_DYNAMIC, dynamic, collisionsWillMove, getDynamic()); // legacy support COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_HREF, href); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DESCRIPTION, description); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FACE_CAMERA, faceCamera); @@ -594,7 +595,8 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(localRenderAlpha, float, setLocalRenderAlpha); COPY_PROPERTY_FROM_QSCRIPTVALUE(ignoreForCollisions, bool, setIgnoreForCollisions); COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(collisionMask, CollisionMask); - COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionsWillMove, bool, setCollisionsWillMove); + COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(collisionsWillMove, bool, setDynamic, getDynamic); // legacy support + COPY_PROPERTY_FROM_QSCRIPTVALUE(dynamic, bool, setDynamic); COPY_PROPERTY_FROM_QSCRIPTVALUE(isSpotlight, bool, setIsSpotlight); COPY_PROPERTY_FROM_QSCRIPTVALUE(intensity, float, setIntensity); COPY_PROPERTY_FROM_QSCRIPTVALUE(exponent, float, setExponent); @@ -757,7 +759,8 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_ANGULAR_DAMPING, AngularDamping, angularDamping, float); ADD_PROPERTY_TO_MAP(PROP_IGNORE_FOR_COLLISIONS, IgnoreForCollisions, ignoreForCollisions, bool); ADD_PROPERTY_TO_MAP(PROP_COLLISION_MASK, CollisionMask, collisionMask, uint8_t); - ADD_PROPERTY_TO_MAP(PROP_COLLISIONS_WILL_MOVE, CollisionsWillMove, collisionsWillMove, bool); + ADD_PROPERTY_TO_MAP(PROP_DYNAMIC, unused, collisionsWillMove, unused); // legacy support + ADD_PROPERTY_TO_MAP(PROP_DYNAMIC, unused, dynamic, unused); ADD_PROPERTY_TO_MAP(PROP_IS_SPOTLIGHT, IsSpotlight, isSpotlight, bool); ADD_PROPERTY_TO_MAP(PROP_INTENSITY, Intensity, intensity, float); ADD_PROPERTY_TO_MAP(PROP_EXPONENT, Exponent, exponent, float); @@ -1004,7 +1007,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_VISIBLE, properties.getVisible()); APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, properties.getIgnoreForCollisions()); APPEND_ENTITY_PROPERTY(PROP_COLLISION_MASK, properties.getCollisionMask()); - APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, properties.getCollisionsWillMove()); + APPEND_ENTITY_PROPERTY(PROP_DYNAMIC, properties.getDynamic()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, properties.getLocked()); APPEND_ENTITY_PROPERTY(PROP_USER_DATA, properties.getUserData()); APPEND_ENTITY_PROPERTY(PROP_HREF, properties.getHref()); @@ -1297,7 +1300,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE, bool, setVisible); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IGNORE_FOR_COLLISIONS, bool, setIgnoreForCollisions); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_MASK, uint8_t, setCollisionMask); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISIONS_WILL_MOVE, bool, setCollisionsWillMove); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DYNAMIC, bool, setDynamic); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_DATA, QString, setUserData); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HREF, QString, setHref); @@ -1479,7 +1482,7 @@ void EntityItemProperties::markAllChanged() { _isSpotlightChanged = true; _ignoreForCollisionsChanged = true; _collisionMaskChanged = true; - _collisionsWillMoveChanged = true; + _dynamicChanged = true; _intensityChanged = true; _exponentChanged = true; @@ -1597,7 +1600,7 @@ bool EntityItemProperties::hasTerseUpdateChanges() const { bool EntityItemProperties::hasMiscPhysicsChanges() const { return _gravityChanged || _dimensionsChanged || _densityChanged || _frictionChanged || _restitutionChanged || _dampingChanged || _angularDampingChanged || _registrationPointChanged || - _compoundShapeURLChanged || _collisionsWillMoveChanged || _ignoreForCollisionsChanged || _collisionMaskChanged; + _compoundShapeURLChanged || _dynamicChanged || _ignoreForCollisionsChanged || _collisionMaskChanged; } void EntityItemProperties::clearSimulationOwner() { @@ -1716,8 +1719,8 @@ QList EntityItemProperties::listChangedProperties() { if (collisionMaskChanged()) { out += "collisionMask"; } - if (collisionsWillMoveChanged()) { - out += "collisionsWillMove"; + if (dynamicChanged()) { + out += "dynamic"; } if (isSpotlightChanged()) { out += "isSpotlight"; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 087925b139..f9072e2e89 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -129,7 +129,7 @@ public: DEFINE_PROPERTY(PROP_ANGULAR_DAMPING, AngularDamping, angularDamping, float, ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING); DEFINE_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, IgnoreForCollisions, ignoreForCollisions, bool, ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS); DEFINE_PROPERTY(PROP_COLLISION_MASK, CollisionMask, collisionMask, uint8_t, ENTITY_COLLISION_MASK_DEFAULT); - DEFINE_PROPERTY(PROP_COLLISIONS_WILL_MOVE, CollisionsWillMove, collisionsWillMove, bool, ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE); + DEFINE_PROPERTY(PROP_DYNAMIC, Dynamic, dynamic, bool, ENTITY_ITEM_DEFAULT_DYNAMIC); DEFINE_PROPERTY(PROP_IS_SPOTLIGHT, IsSpotlight, isSpotlight, bool, false); DEFINE_PROPERTY(PROP_INTENSITY, Intensity, intensity, float, 1.0f); DEFINE_PROPERTY(PROP_EXPONENT, Exponent, exponent, float, 0.0f); @@ -356,7 +356,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, AngularVelocity, angularVelocity, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AngularDamping, angularDamping, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, IgnoreForCollisions, ignoreForCollisions, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionsWillMove, collisionsWillMove, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, Dynamic, dynamic, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, IsSpotlight, isSpotlight, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Intensity, intensity, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Exponent, exponent, ""); diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index 06c6565d1b..39b144c014 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -69,7 +69,7 @@ const float ENTITY_ITEM_MAX_FRICTION = 0.99f; const float ENTITY_ITEM_DEFAULT_FRICTION = 0.5f; const bool ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS = false; -const bool ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE = false; +const bool ENTITY_ITEM_DEFAULT_DYNAMIC = false; const bool ENTITY_ITEM_DEFAULT_BILLBOARDED = false; const float ENTITY_ITEM_DEFAULT_CUTOFF = PI / 2; diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 860da87705..c1ac9f454b 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -168,7 +168,15 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const AACube& v) { retu QScriptValue V = convertScriptValue(engine, G); \ properties.setProperty(#P, V); \ } - + +// same as COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER but uses #X instead of #P in the setProperty() step +#define COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(p, P, X, G) \ + if ((_desiredProperties.isEmpty() || _desiredProperties.getHasProperty(p)) && \ + (!skipDefaults || defaultEntityProperties._##P != _##P)) { \ + QScriptValue V = convertScriptValue(engine, G); \ + properties.setProperty(#X, V); \ + } + #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(P, G) \ if (!skipDefaults || defaultEntityProperties._##P != _##P) { \ QScriptValue V = convertScriptValue(engine, G); \ diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 81301cb52d..dec2a607da 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -17,7 +17,7 @@ enum EntityPropertyList { PROP_PAGED_PROPERTY, PROP_CUSTOM_PROPERTIES_INCLUDED, - + // these properties are supported by the EntityItem base class PROP_VISIBLE, PROP_POSITION, @@ -33,7 +33,7 @@ enum EntityPropertyList { // these properties are supported by some derived classes PROP_COLOR, - + // these are used by models only PROP_MODEL_URL, PROP_ANIMATION_URL, @@ -46,7 +46,7 @@ enum EntityPropertyList { PROP_ANGULAR_VELOCITY, PROP_ANGULAR_DAMPING, PROP_IGNORE_FOR_COLLISIONS, - PROP_COLLISIONS_WILL_MOVE, + PROP_DYNAMIC, // property used by Light entity PROP_IS_SPOTLIGHT, diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 9861252d63..1017f54f67 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -734,15 +734,15 @@ void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList= 0) { - bool value = properties.getCollisionsWillMove(); + bool value = properties.getDynamic(); QString changeHint = "0"; if (value) { changeHint = "1"; } - changedProperties[index] = QString("collisionsWillMove:") + changeHint; + changedProperties[index] = QString("dynamic:") + changeHint; } } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 74fc7b0716..d0de720fa3 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -144,7 +144,7 @@ PhysicsMotionType EntityMotionState::computePhysicsMotionType() const { return MOTION_TYPE_STATIC; } assert(entityTreeIsLocked()); - if (_entity->getCollisionsWillMove()) { + if (_entity->getDynamic()) { return MOTION_TYPE_DYNAMIC; } return (_entity->isMoving() || _entity->hasActions()) ? MOTION_TYPE_KINEMATIC : MOTION_TYPE_STATIC; From 29a52bf0ba0c54db7b9e88fba45595f24c4d0a8a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 13 Jan 2016 17:49:48 -0800 Subject: [PATCH 176/215] namechange collisionsWillMove --> dynamic --- examples/FlockOfbirds.js | 4 +-- examples/animationPerfTest.js | 2 +- examples/baseball/createBatButton.js | 2 +- examples/baseball/pitching.js | 4 +-- examples/blockWorld.js | 6 ++-- examples/blocks.js | 4 +-- examples/controllers/hydra/gun.js | 8 ++--- examples/controllers/hydra/paddleBall.js | 6 ++-- examples/controllers/hydra/toyball.js | 4 +-- examples/controllers/toybox.js | 4 +-- examples/cubePerfTest.js | 2 +- .../data_visualization/earthquakes_live.js | 2 +- examples/debugging/grabInspector.js | 2 +- examples/dice.js | 4 +-- examples/dropStuffNearMe.js | 2 +- examples/drylake/createAvatarDetector.js | 4 +-- examples/drylake/explodeHelicopter.js | 4 +-- examples/drylake/ratCreator.js | 6 ++-- examples/example/brownianFun.js | 4 +-- .../example/entities/collidingEntities.js | 4 +-- examples/example/entityCollisionExample.js | 2 +- examples/example/games/airHockey.js | 6 ++-- examples/example/games/billiards.js | 6 ++-- .../games/color_busters/colorBusterWand.js | 4 +-- .../color_busters/createColorBusterCubes.js | 4 +-- .../color_busters/createColorBusterWand.js | 4 +-- .../example/games/exterminatorGame/pistol.js | 2 +- examples/example/games/grabHockey.js | 2 +- examples/example/games/hydraGrabHockey.js | 4 +-- examples/example/games/make-dummy.js | 2 +- examples/example/games/planky.js | 2 +- examples/example/games/satellite.js | 6 ++-- .../example/games/spaceInvadersExample.js | 4 +-- examples/example/games/sword.js | 2 +- examples/example/hmd/colorCube.js | 2 +- examples/example/solarsystem.js | 4 +-- examples/example/soundToys.js | 2 +- examples/flowArts/arcBall/arcBall.js | 4 +-- examples/flowArts/lightBall/lightBall.js | 2 +- examples/flowArts/lightSaber/lightSaber.js | 2 +- examples/flowArts/raveStick/raveStick.js | 2 +- examples/grab.js | 6 ++-- examples/grenade.js | 4 +-- examples/gridTest.js | 4 +-- examples/harmonicOscillator.js | 2 +- examples/html/entityProperties.html | 4 +-- examples/libraries/easyStarExample.js | 4 +-- examples/libraries/entityPropertyDialogBox.js | 4 +-- examples/light_modifier/lightModifier.js | 16 ++++----- examples/lotsoBlocks.js | 4 +-- examples/magBalls/constants.js | 6 ++-- examples/particle_explorer/main.js | 12 ++----- examples/planets.js | 4 +-- examples/playa/playaSpawner.js | 2 +- examples/popcorn.js | 2 +- examples/stick-hydra.js | 2 +- examples/stick.js | 2 +- examples/toybox/basketball/createRack.js | 6 ++-- .../basketball/createSingleBasketball.js | 4 +-- examples/toybox/blockers/createTestBlocks.js | 8 ++--- examples/toybox/bow/bow.js | 12 +++---- examples/toybox/bow/createBow.js | 4 +-- examples/toybox/bubblewand/createWand.js | 2 +- examples/toybox/bubblewand/wand.js | 6 ++-- examples/toybox/doll/createDoll.js | 4 +-- .../toybox/flashlight/createFlashlight.js | 4 +-- .../toybox/ping_pong_gun/createPingPongGun.js | 4 +-- .../toybox/ping_pong_gun/createTargets.js | 8 ++--- examples/toybox/ping_pong_gun/pingPongGun.js | 2 +- examples/toybox/pistol/createPistol.js | 4 +-- examples/toybox/pistol/pistol.js | 4 +-- examples/weapons/shootingRangeSpawner.js | 4 +-- .../targetPractice/shooterPlatform.js | 2 +- .../targetPractice/targetPracticeGame.js | 2 +- unpublishedScripts/basketballsResetter.js | 2 +- unpublishedScripts/hiddenEntityReset.js | 34 +++++++++---------- unpublishedScripts/masterReset.js | 34 +++++++++---------- unpublishedScripts/targetsResetter.js | 2 +- 78 files changed, 184 insertions(+), 192 deletions(-) diff --git a/examples/FlockOfbirds.js b/examples/FlockOfbirds.js index 5d67c25c17..514e8a5fab 100644 --- a/examples/FlockOfbirds.js +++ b/examples/FlockOfbirds.js @@ -272,7 +272,7 @@ function loadBirds(howMany) { gravity: { x: 0, y: BIRD_GRAVITY, z: 0 }, velocity: { x: 0, y: -0.1, z: 0 }, damping: LINEAR_DAMPING, - collisionsWillMove: true, + dynamic: true, lifetime: STARTING_LIFETIME, color: colors[whichBird] }), @@ -289,4 +289,4 @@ function loadBirds(howMany) { color: {red: 100, green: 100, blue: 100} }); } -} \ No newline at end of file +} diff --git a/examples/animationPerfTest.js b/examples/animationPerfTest.js index b832d2e61f..93d362299c 100644 --- a/examples/animationPerfTest.js +++ b/examples/animationPerfTest.js @@ -53,7 +53,7 @@ for (var i = 0; i < NUM_MOONS; i++) { dimensions: { x: radius, y: radius, z: radius }, color: color, ignoreCollisions: true, - collisionsWillMove: false + dynamic: false })); } diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 37cc7f0a5e..20f020a716 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -65,7 +65,7 @@ modelURL: BAT_MODEL, position: dropPosition, compoundShapeURL: BAT_COLLISION_HULL, - collisionsWillMove: true, + dynamic: true, velocity: { x: 0, y: 0.05, z: 0}, // workaround for gravity not taking effect on add gravity: { x: 0, y: -9.81, z: 0}, rotation: Quat.fromPitchYawRollDegrees(0.0, 0.0, -90.0), diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 09f33c9dd4..01aae28a55 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -107,7 +107,7 @@ var PITCHING_MACHINE_PROPERTIES = { y: 0.61, z: 0.39 }, - collisionsWillMove: false, + dynamic: false, shapeType: "Box" }; PITCHING_MACHINE_PROPERTIES.dimensions = Vec3.multiply(2.5, PITCHING_MACHINE_PROPERTIES.dimensions); @@ -217,7 +217,7 @@ var BASEBALL_PROPERTIES = { y: BASEBALL_RADIUS, z: BASEBALL_RADIUS }, - collisionsWillMove: true, + dynamic: true, angularVelocity: { x: 17.0, y: 0, diff --git a/examples/blockWorld.js b/examples/blockWorld.js index 53809612ed..12e531e8de 100644 --- a/examples/blockWorld.js +++ b/examples/blockWorld.js @@ -104,7 +104,7 @@ function generateFloor() { green: randFloat(70, 71), blue: randFloat(70, 80) }, - // collisionsWillMove: true + // dynamic: true })); } @@ -132,7 +132,7 @@ function dropBlock() { shapeType: 'box', position: dropPos, dimensions: BLOCK_SIZE, - collisionsWillMove: true, + dynamic: true, gravity: { x: 0, y: -9, @@ -198,4 +198,4 @@ function map(value, min1, max1, min2, max2) { } Script.scriptEnding.connect(cleanup); -Controller.mousePressEvent.connect(mousePressEvent); \ No newline at end of file +Controller.mousePressEvent.connect(mousePressEvent); diff --git a/examples/blocks.js b/examples/blocks.js index 29ccd9fff0..a52c7c278e 100644 --- a/examples/blocks.js +++ b/examples/blocks.js @@ -101,7 +101,7 @@ for (var i = 0; i < NUM_BLOCKS; i++) { ignoreCollisions: false, damping: DAMPING, lifetime: LIFETIME, - collisionsWillMove: true })); + dynamic: true })); } function scriptEnding() { @@ -121,4 +121,4 @@ function scriptEnding() { } } -Script.scriptEnding.connect(scriptEnding); \ No newline at end of file +Script.scriptEnding.connect(scriptEnding); diff --git a/examples/controllers/hydra/gun.js b/examples/controllers/hydra/gun.js index 576c4335f6..42dd1144eb 100644 --- a/examples/controllers/hydra/gun.js +++ b/examples/controllers/hydra/gun.js @@ -234,7 +234,7 @@ function shootBullet(position, velocity, grenade) { damping: 0.01, density: 8000, ignoreCollisions: false, - collisionsWillMove: true + dynamic: true }); Script.addEventHandler(bulletID, "collisionWithEntity", entityCollisionWithEntity); @@ -294,7 +294,7 @@ function shootTarget() { rotation: Camera.getOrientation(), damping: 0.1, density: 100.0, - collisionsWillMove: true + dynamic: true }); // Record start time @@ -349,7 +349,7 @@ function makeGrid(type, scale, size) { rotation: Camera.getOrientation(), damping: 0.1, density: 100.0, - collisionsWillMove: true + dynamic: true }); } } @@ -401,7 +401,7 @@ function makePlatform(gravity, scale, size) { lifetime: TARGET_LIFE, damping: 0.1, density: 100.0, - collisionsWillMove: true + dynamic: true }); } } diff --git a/examples/controllers/hydra/paddleBall.js b/examples/controllers/hydra/paddleBall.js index d90a78c260..9bf558ef21 100644 --- a/examples/controllers/hydra/paddleBall.js +++ b/examples/controllers/hydra/paddleBall.js @@ -59,7 +59,7 @@ function createEntities() { gravity: { x: 0, y: GRAVITY, z: 0 }, ignoreCollisions: false, damping: 0.50, - collisionsWillMove: true }); + dynamic: true }); paddle = Entities.addEntity( { type: "Box", @@ -71,7 +71,7 @@ function createEntities() { damping: 0.10, visible: false, rotation : leftHanded ? MyAvatar.leftHandPose.rotation : MyAvatar.rightHandPose.rotation, - collisionsWillMove: false }); + dynamic: false }); modelURL = "http://public.highfidelity.io/models/attachments/pong_paddle.fbx"; paddleModel = Entities.addEntity( @@ -84,7 +84,7 @@ function createEntities() { modelURL: modelURL, damping: 0.10, rotation : leftHanded ? MyAvatar.leftHandPose.rotation : MyAvatar.rightHandPose.rotation, - collisionsWillMove: false }); + dynamic: false }); line = Overlays.addOverlay("line3d", { start: { x: 0, y: 0, z: 0 }, diff --git a/examples/controllers/hydra/toyball.js b/examples/controllers/hydra/toyball.js index 10f8a82ec9..0d5faea317 100644 --- a/examples/controllers/hydra/toyball.js +++ b/examples/controllers/hydra/toyball.js @@ -154,7 +154,7 @@ function checkControllerSide(whichSide) { dimensions: { x: BALL_RADIUS * 2, y: BALL_RADIUS * 2, z: BALL_RADIUS * 2 }, damping: 0.00001, shapeType: "sphere", - collisionsWillMove: false, + dynamic: false, color: HELD_COLOR, lifetime: LIFETIME_SECONDS }; @@ -200,7 +200,7 @@ function checkControllerSide(whichSide) { velocity: linearVelocity, rotation: palmRotation, angularVelocity: angularVelocity, - collisionsWillMove: true, + dynamic: true, color: THROWN_COLOR, gravity: { x: 0, y: -GRAVITY_STRENGTH, z: 0}, }; diff --git a/examples/controllers/toybox.js b/examples/controllers/toybox.js index bf03974fda..9ca0a069fc 100644 --- a/examples/controllers/toybox.js +++ b/examples/controllers/toybox.js @@ -175,7 +175,7 @@ function createTable() { damping: 0.1, restitution: 0.01, density: 0.5, - collisionsWillMove: true, + dynamic: true, color: { red: randInt(0, 255), green: randInt(0, 255), blue: randInt(0, 255) }, }); if (type == "Model") { @@ -196,4 +196,4 @@ function removeTable() { } Script.scriptEnding.connect(cleanUp); -Controller.mousePressEvent.connect(onClick); \ No newline at end of file +Controller.mousePressEvent.connect(onClick); diff --git a/examples/cubePerfTest.js b/examples/cubePerfTest.js index f2f4d48b22..7e26556891 100644 --- a/examples/cubePerfTest.js +++ b/examples/cubePerfTest.js @@ -42,7 +42,7 @@ for (var x = 0; x < SIDE_SIZE; x++) { dimensions: { x: radius, y: radius, z: radius }, color: color, ignoreCollisions: true, - collisionsWillMove: false, + dynamic: false, lifetime: LIFETIME })); } diff --git a/examples/data_visualization/earthquakes_live.js b/examples/data_visualization/earthquakes_live.js index 8594f827a0..ad0c9ec6a6 100644 --- a/examples/data_visualization/earthquakes_live.js +++ b/examples/data_visualization/earthquakes_live.js @@ -51,7 +51,7 @@ function createEarth() { z: EARTH_SPHERE_RADIUS }, rotation: Quat.fromPitchYawRollDegrees(0, 90, 0), - // collisionsWillMove: true, + // dynamic: true, //if you have a shapetype it blocks the smaller markers // shapeType:'sphere' // userData: JSON.stringify({ diff --git a/examples/debugging/grabInspector.js b/examples/debugging/grabInspector.js index aeea2c20b4..11367d8832 100644 --- a/examples/debugging/grabInspector.js +++ b/examples/debugging/grabInspector.js @@ -108,7 +108,7 @@ Script.setInterval(function() { var grabData = userData["grabKey"] // {"grabbableKey":{"invertSolidWhileHeld":true}, - // "grabKey":{"activated":true,"avatarId":"{6ea8b092-10e0-4058-888b-6facc40d0fe9}","refCount":1,"gravity":{"x":0,"y":0,"z":0},"ignoreForCollisions":0,"collisionsWillMove":1} + // "grabKey":{"activated":true,"avatarId":"{6ea8b092-10e0-4058-888b-6facc40d0fe9}","refCount":1,"gravity":{"x":0,"y":0,"z":0},"ignoreForCollisions":0,"dynamic":1} // } if (typeof grabData != 'undefined') { diff --git a/examples/dice.js b/examples/dice.js index 29b522f16b..f687a3823b 100644 --- a/examples/dice.js +++ b/examples/dice.js @@ -110,7 +110,7 @@ function shootDice(position, velocity) { }, lifetime: LIFETIME, shapeType: "box", - collisionsWillMove: true, + dynamic: true, collisionSoundURL: "http://s3.amazonaws.com/hifi-public/sounds/dice/diceCollide.wav" })); position = Vec3.sum(position, Vec3.multiply(DIE_SIZE, Vec3.normalize(Quat.getRight(Camera.getOrientation())))); @@ -151,4 +151,4 @@ function scriptEnding() { } Controller.mousePressEvent.connect(mousePressEvent); -Script.scriptEnding.connect(scriptEnding); \ No newline at end of file +Script.scriptEnding.connect(scriptEnding); diff --git a/examples/dropStuffNearMe.js b/examples/dropStuffNearMe.js index 1c7c1f4f48..89a1e14a10 100644 --- a/examples/dropStuffNearMe.js +++ b/examples/dropStuffNearMe.js @@ -77,7 +77,7 @@ Script.setInterval(function () { damping: DAMPING, angularDamping: ANGULAR_DAMPING, gravity: (gravity ? GRAVITY : { x: 0, y: 0, z: 0}), - collisionsWillMove: collidable, + dynamic: collidable, lifetime: LIFETIME }); diff --git a/examples/drylake/createAvatarDetector.js b/examples/drylake/createAvatarDetector.js index 51ca55248e..c858512ba0 100644 --- a/examples/drylake/createAvatarDetector.js +++ b/examples/drylake/createAvatarDetector.js @@ -24,7 +24,7 @@ function createAvatarDetector() { y: 2, z: 1 }, - collisionsWillMove: false, + dynamic: false, ignoreForCollisions: true, visible: false, color: { @@ -52,4 +52,4 @@ var cleanup = function() { createAvatarDetector(); Script.scriptEnding.connect(cleanup); -Script.update.connect(updateAvatarDetector); \ No newline at end of file +Script.update.connect(updateAvatarDetector); diff --git a/examples/drylake/explodeHelicopter.js b/examples/drylake/explodeHelicopter.js index efca1a91cc..6275a9f43b 100644 --- a/examples/drylake/explodeHelicopter.js +++ b/examples/drylake/explodeHelicopter.js @@ -56,7 +56,7 @@ function explodeHelicopter(explodePosition) { dimensions: partsURLS[i].dimensions, position: position, shapeType: "box", - collisionsWillMove: true, + dynamic: true, damping: 0, gravity: { x: 0, @@ -141,4 +141,4 @@ function cleanup() { }) } -Script.scriptEnding.connect(cleanup); \ No newline at end of file +Script.scriptEnding.connect(cleanup); diff --git a/examples/drylake/ratCreator.js b/examples/drylake/ratCreator.js index 237b8ec32f..60a026084e 100644 --- a/examples/drylake/ratCreator.js +++ b/examples/drylake/ratCreator.js @@ -90,7 +90,7 @@ var modelRatProperties = { damping: 0.8, angularDamping: 0.99, friction: 0.75, - collisionsWillMove: true, + dynamic: true, ignoreForCollisions: false, gravity: { x: 0, @@ -194,7 +194,7 @@ function addAvoiderBlock(position) { z: 1 }, position: position, - collisionsWillMove: false, + dynamic: false, ignoreForCollisions: true, visible: false }; @@ -468,4 +468,4 @@ if (USE_CONSTANT_SPAWNER === true) { } }, RAT_SPAWN_RATE); - } \ No newline at end of file + } diff --git a/examples/example/brownianFun.js b/examples/example/brownianFun.js index b7f7fe3b32..533fb170dd 100644 --- a/examples/example/brownianFun.js +++ b/examples/example/brownianFun.js @@ -165,7 +165,7 @@ function spawnBalls() { blue: randFloat(10, 180) }, ignoreCollisions: false, - collisionsWillMove: true, + dynamic: true, gravity: { x: 0, y: -9.9, @@ -244,4 +244,4 @@ Script.scriptEnding.connect(cleanup); Script.scriptEnding.connect(cleanup); -Controller.mousePressEvent.connect(mousePressEvent); \ No newline at end of file +Controller.mousePressEvent.connect(mousePressEvent); diff --git a/examples/example/entities/collidingEntities.js b/examples/example/entities/collidingEntities.js index 37c35e971d..65bbaf7d02 100644 --- a/examples/example/entities/collidingEntities.js +++ b/examples/example/entities/collidingEntities.js @@ -43,7 +43,7 @@ function draw(deltaTime) { var properties = { type: "Sphere", - collisionsWillMove: true, + dynamic: true, position: startPosition, dimensions: {x: largeRadius, y: largeRadius, z: largeRadius}, registrationPoint: { x: 0.5, y: 0.5, z: 0.5 }, @@ -84,7 +84,7 @@ function draw(deltaTime) { if (numberEntitiesAdded <= MAX_ENTITIES) { var properties = { type: "Sphere", - collisionsWillMove: true, + dynamic: true, position: center, dimensions: {x: entitySize, y: entitySize, z: entitySize}, registrationPoint: { x: 0.5, y: 0.5, z: 0.5 }, diff --git a/examples/example/entityCollisionExample.js b/examples/example/entityCollisionExample.js index de50d52753..ae8594e3b0 100644 --- a/examples/example/entityCollisionExample.js +++ b/examples/example/entityCollisionExample.js @@ -19,7 +19,7 @@ var position = Vec3.sum(MyAvatar.position, Quat.getFront(MyAvatar.orientation)); var properties = { type: "Box", position: position, - collisionsWillMove: true, + dynamic: true, color: { red: 200, green: 0, blue: 0 } }; var collider = Entities.addEntity(properties); diff --git a/examples/example/games/airHockey.js b/examples/example/games/airHockey.js index ca7f007df6..ffd237c89c 100755 --- a/examples/example/games/airHockey.js +++ b/examples/example/games/airHockey.js @@ -177,7 +177,7 @@ function makeNewProp(which, position) { damping: PUCK_DAMPING, angularDamping: ANGULAR_DAMPING, lifetime: LIFETIME, - collisionsWillMove: true + dynamic: true }); } else if (which == "paddle1") { paddle1Pos = Vec3.sum(center, { @@ -211,7 +211,7 @@ function makeNewProp(which, position) { damping: PADDLE_DAMPING, angularDamping: PADDLE_ANGULAR_DAMPING, lifetime: LIFETIME, - collisionsWillMove: true + dynamic: true }); } else if (which == "paddle2") { paddle2Pos = Vec3.sum(center, { @@ -245,7 +245,7 @@ function makeNewProp(which, position) { damping: PADDLE_DAMPING, angularDamping: PADDLE_ANGULAR_DAMPING, lifetime: LIFETIME, - collisionsWillMove: true + dynamic: true }); } } diff --git a/examples/example/games/billiards.js b/examples/example/games/billiards.js index c110b33042..f1329987b2 100644 --- a/examples/example/games/billiards.js +++ b/examples/example/games/billiards.js @@ -128,7 +128,7 @@ function makeBalls(pos) { damping: 0.50, shapeType: "sphere", collisionSoundURL: hitSound, - collisionsWillMove: true })); + dynamic: true })); ballPosition.z += (BALL_SIZE + BALL_GAP) * SCALE; ballNumber++; } @@ -149,7 +149,7 @@ function makeBalls(pos) { ignoreCollisions: false, damping: 0.50, shapeType: "sphere", - collisionsWillMove: true }); + dynamic: true }); } @@ -184,7 +184,7 @@ function shootCue(velocity) { damping: 0.10, density: 8000, ignoreCollisions: false, - collisionsWillMove: true + dynamic: true }); print("Shot, velocity = " + velocity); } diff --git a/examples/example/games/color_busters/colorBusterWand.js b/examples/example/games/color_busters/colorBusterWand.js index f9d69e8414..825883d3fd 100644 --- a/examples/example/games/color_busters/colorBusterWand.js +++ b/examples/example/games/color_busters/colorBusterWand.js @@ -219,7 +219,7 @@ type: 'Box', dimensions: COLOR_INDICATOR_DIMENSIONS, position: this.currentProperties.position, - collisionsWillMove: false, + dynamic: false, ignoreForCollisions: true } @@ -262,4 +262,4 @@ }; return new ColorBusterWand(); -}); \ No newline at end of file +}); diff --git a/examples/example/games/color_busters/createColorBusterCubes.js b/examples/example/games/color_busters/createColorBusterCubes.js index 3fdd772704..bcec021676 100644 --- a/examples/example/games/color_busters/createColorBusterCubes.js +++ b/examples/example/games/color_busters/createColorBusterCubes.js @@ -81,7 +81,7 @@ function createColorBusterCube(row, column, vertical) { name: 'Hifi-ColorBusterCube', type: 'Box', dimensions: CUBE_DIMENSIONS, - collisionsWillMove: false, + dynamic: false, ignoreForCollisions: false, color: startingColor[1], position: position, @@ -127,4 +127,4 @@ if (DELETE_AT_ENDING === true) { } -createBoard(); \ No newline at end of file +createBoard(); diff --git a/examples/example/games/color_busters/createColorBusterWand.js b/examples/example/games/color_busters/createColorBusterWand.js index a08f529aa8..d57b5ab3b6 100644 --- a/examples/example/games/color_busters/createColorBusterWand.js +++ b/examples/example/games/color_busters/createColorBusterWand.js @@ -71,7 +71,7 @@ function createColorBusterWand() { dimensions: COLOR_WAND_DIMENSIONS, position: center, script: COLOR_WAND_SCRIPT_URL, - collisionsWillMove: true, + dynamic: true, userData: JSON.stringify({ hifiColorBusterWandKey: { owner: MyAvatar.sessionUUID, @@ -96,4 +96,4 @@ if (DELETE_AT_ENDING === true) { Script.scriptEnding.connect(deleteWand); } -createColorBusterWand(); \ No newline at end of file +createColorBusterWand(); diff --git a/examples/example/games/exterminatorGame/pistol.js b/examples/example/games/exterminatorGame/pistol.js index e1923835c3..b5b8d37812 100644 --- a/examples/example/games/exterminatorGame/pistol.js +++ b/examples/example/games/exterminatorGame/pistol.js @@ -169,7 +169,7 @@ function fire(side, value) { if (intersection.intersects) { Script.setTimeout(function() { createEntityHitEffect(intersection.intersection); - if (shootAnything && intersection.properties.collisionsWillMove === 1) { + if (shootAnything && intersection.properties.dynamic === 1) { // Any entity with collisions will move can be shot Entities.editEntity(intersection.entityID, { velocity: Vec3.multiply(shotDirection, GUN_FORCE) diff --git a/examples/example/games/grabHockey.js b/examples/example/games/grabHockey.js index fc21caee1d..961a8af6ad 100644 --- a/examples/example/games/grabHockey.js +++ b/examples/example/games/grabHockey.js @@ -142,7 +142,7 @@ function mousePressEvent(event) { if (!pickResults.intersects) { return; } - if (pickResults.properties.collisionsWillMove) { + if (pickResults.properties.dynamic) { grabbedEntity = pickResults.entityID; var props = Entities.getEntityProperties(grabbedEntity) originalGravity = props.gravity; diff --git a/examples/example/games/hydraGrabHockey.js b/examples/example/games/hydraGrabHockey.js index 26f9a443ab..e7d6746309 100644 --- a/examples/example/games/hydraGrabHockey.js +++ b/examples/example/games/hydraGrabHockey.js @@ -190,7 +190,7 @@ function controller(side) { direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)) }; var intersection = getRayIntersection(pickRay, true); - if (intersection.intersects && intersection.properties.collisionsWillMove) { + if (intersection.intersects && intersection.properties.dynamic) { this.laserWasHovered = true; if (this.triggerHeld && !this.grabbing) { this.grab(intersection.entityID); @@ -298,4 +298,4 @@ var leftController = new controller(LEFT); Script.update.connect(update); -Script.scriptEnding.connect(scriptEnding); \ No newline at end of file +Script.scriptEnding.connect(scriptEnding); diff --git a/examples/example/games/make-dummy.js b/examples/example/games/make-dummy.js index 068a8b7f9a..c74433aedf 100644 --- a/examples/example/games/make-dummy.js +++ b/examples/example/games/make-dummy.js @@ -49,7 +49,7 @@ function mousePressEvent(event) { dimensions: {x: 0.3, y: 0.7, z: 0.3}, gravity: {x: 0.0, y: -3.0, z: 0.0}, damping: 0.2, - collisionsWillMove: true + dynamic: true }); var pointToOffsetFrom = Vec3.sum(position, {x: 0.0, y: 2.0, z: 0.0}); diff --git a/examples/example/games/planky.js b/examples/example/games/planky.js index 78e7bf9cbe..5f16097bb1 100644 --- a/examples/example/games/planky.js +++ b/examples/example/games/planky.js @@ -289,7 +289,7 @@ PlankyStack = function() { } if (!editMode) { _this.planks.forEach(function(plank, index, object) { - Entities.editEntity(plank.entity, {ignoreForCollisions: false, collisionsWillMove: true}); + Entities.editEntity(plank.entity, {ignoreForCollisions: false, dynamic: true}); }); } }; diff --git a/examples/example/games/satellite.js b/examples/example/games/satellite.js index 9ae0105917..2d71be8ed8 100644 --- a/examples/example/games/satellite.js +++ b/examples/example/games/satellite.js @@ -67,7 +67,7 @@ SatelliteCreator = function() { damping: 0.0, ignoreCollisions: false, lifetime: 6000, - collisionsWillMove: false, + dynamic: false, visible: true }); @@ -90,7 +90,7 @@ SatelliteCreator = function() { damping: 0.0, ignoreCollisions: false, lifetime: LIFETIME, - collisionsWillMove: false, + dynamic: false, visible: true }); @@ -174,7 +174,7 @@ SatelliteCreator = function() { damping: 0.0, ignoreCollisions: false, lifetime: LIFETIME, - collisionsWillMove: false, + dynamic: false, }); this.getProperties = function() { diff --git a/examples/example/games/spaceInvadersExample.js b/examples/example/games/spaceInvadersExample.js index 330351e009..df7649d942 100644 --- a/examples/example/games/spaceInvadersExample.js +++ b/examples/example/games/spaceInvadersExample.js @@ -191,7 +191,7 @@ function initializeInvaders() { dimensions: { x: invaderSize * 2, y: invaderSize * 2, z: invaderSize * 2 }, color: { red: 255, green: 0, blue: 0 }, modelURL: invaderModels[row].modelURL, - collisionsWillMove: true, + dynamic: true, lifetime: itemLifetimes }); } @@ -341,7 +341,7 @@ function fireMissile() { velocity: { x: 0, y: 5, z: 0}, gravity: { x: 0, y: 0, z: 0 }, damping: 0, - collisionsWillMove: true, + dynamic: true, dimensions: { x: missileSize, y: missileSize, z: missileSize }, color: { red: 0, green: 0, blue: 255 }, lifetime: 5 diff --git a/examples/example/games/sword.js b/examples/example/games/sword.js index 31a9a82d87..6000ea52fe 100644 --- a/examples/example/games/sword.js +++ b/examples/example/games/sword.js @@ -286,7 +286,7 @@ function makeSword() { damping: 0.1, collisionSoundURL: swordCollisionSoundURL, restitution: 0.01, - collisionsWillMove: true, + dynamic: true, }); if (originalAvatarCollisionSound === undefined) { diff --git a/examples/example/hmd/colorCube.js b/examples/example/hmd/colorCube.js index a138f38190..4acde2951f 100644 --- a/examples/example/hmd/colorCube.js +++ b/examples/example/hmd/colorCube.js @@ -30,7 +30,7 @@ ColorCube.prototype.create = function() { name: that.NAME, color: that.COLOR, ignoreCollisions: true, - collisionsWillMove: false, + dynamic: false, dimensions: { x: size, y: size, z: size }, lifetime: 3600, userData: JSON.stringify(that.USER_DATA) diff --git a/examples/example/solarsystem.js b/examples/example/solarsystem.js index 7b9967b001..6d28a6c8a9 100644 --- a/examples/example/solarsystem.js +++ b/examples/example/solarsystem.js @@ -55,7 +55,7 @@ CreateSimulation = function() { damping: DAMPING, ignoreCollisions: false, lifetime: LIFETIME, - collisionsWillMove: false + dynamic: false }); @@ -187,7 +187,7 @@ CreateSimulation = function() { damping: DAMPING, ignoreCollisions: false, lifetime: LIFETIME, - collisionsWillMove: false, + dynamic: false, }); this.computeAcceleration = function() { diff --git a/examples/example/soundToys.js b/examples/example/soundToys.js index 9d8c824b90..d46d5d8b60 100644 --- a/examples/example/soundToys.js +++ b/examples/example/soundToys.js @@ -37,7 +37,7 @@ function makeAll() { type: "Model", modelURL: HIFI_PUBLIC_BUCKET + model, collisionSoundURL: sound, - collisionsWillMove: true, + dynamic: true, shapeType: "box", restitution: 0.8, dimensions: currentDimensions, diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index 12ef2df48a..1c8d7cf3c8 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -46,7 +46,7 @@ ArcBall = function(spawnPosition) { }, ignoreForCollisions: true, damping: 0.8, - collisionsWillMove: true, + dynamic: true, userData: JSON.stringify({ grabbableKey: { spatialKey: { @@ -142,4 +142,4 @@ ArcBall = function(spawnPosition) { } this.cleanup = cleanup; -} \ No newline at end of file +} diff --git a/examples/flowArts/lightBall/lightBall.js b/examples/flowArts/lightBall/lightBall.js index b2ed00f326..bbeac3a357 100644 --- a/examples/flowArts/lightBall/lightBall.js +++ b/examples/flowArts/lightBall/lightBall.js @@ -41,7 +41,7 @@ LightBall = function(spawnPosition) { green: 10, blue: 150 }, - collisionsWillMove: true, + dynamic: true, // gravity: { // x: 0, // y: -0.5, diff --git a/examples/flowArts/lightSaber/lightSaber.js b/examples/flowArts/lightSaber/lightSaber.js index c4ab49e8e6..a6f14ebe7b 100644 --- a/examples/flowArts/lightSaber/lightSaber.js +++ b/examples/flowArts/lightSaber/lightSaber.js @@ -23,7 +23,7 @@ LightSaber = function(spawnPosition) { modelURL: modelURL, position: spawnPosition, shapeType: 'box', - collisionsWillMove: true, + dynamic: true, script: scriptURL, dimensions: { x: 0.06, diff --git a/examples/flowArts/raveStick/raveStick.js b/examples/flowArts/raveStick/raveStick.js index d1180e2b34..3b51430f91 100644 --- a/examples/flowArts/raveStick/raveStick.js +++ b/examples/flowArts/raveStick/raveStick.js @@ -33,7 +33,7 @@ RaveStick = function(spawnPosition) { modelURL: modelURL, position: spawnPosition, shapeType: 'box', - collisionsWillMove: true, + dynamic: true, script: scriptURL, dimensions: { x: 0.06, diff --git a/examples/grab.js b/examples/grab.js index cb0723b8eb..64a8ea16e2 100644 --- a/examples/grab.js +++ b/examples/grab.js @@ -320,7 +320,7 @@ Grabber.prototype.pressEvent = function(event) { return; } - if (!pickResults.properties.collisionsWillMove) { + if (!pickResults.properties.dynamic) { // only grab dynamic objects return; } @@ -510,7 +510,7 @@ Grabber.prototype.activateEntity = function(entityID, grabbedProperties) { if (data["refCount"] == 1) { data["gravity"] = grabbedProperties.gravity; data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions; - data["collisionsWillMove"] = grabbedProperties.collisionsWillMove; + data["dynamic"] = grabbedProperties.dynamic; var whileHeldProperties = {gravity: {x:0, y:0, z:0}}; if (invertSolidWhileHeld) { whileHeldProperties["ignoreForCollisions"] = ! grabbedProperties.ignoreForCollisions; @@ -528,7 +528,7 @@ Grabber.prototype.deactivateEntity = function(entityID) { Entities.editEntity(entityID, { gravity: data["gravity"], ignoreForCollisions: data["ignoreForCollisions"], - collisionsWillMove: data["collisionsWillMove"] + dynamic: data["dynamic"] }); data = null; } diff --git a/examples/grenade.js b/examples/grenade.js index 7b987b1091..ab0e6b5a47 100644 --- a/examples/grenade.js +++ b/examples/grenade.js @@ -52,7 +52,7 @@ function makeGrenade() { dimensions: { x: 0.09, y: 0.20, z: 0.09 }, - collisionsWillMove: true, + dynamic: true, modelURL: grenadeURL, shapeType: "box" }); @@ -160,7 +160,7 @@ function blowShitUp(position, radius) { var SPIN_RATE = 20.0; for (var i = 0; i < stuff.length; i++) { var properties = Entities.getEntityProperties(stuff[i]); - if (properties.collisionsWillMove) { + if (properties.dynamic) { var diff = Vec3.subtract(properties.position, position); var distance = Vec3.length(diff); var velocity = Vec3.sum(properties.velocity, Vec3.multiply(STRENGTH * 1.0 / distance, Vec3.normalize(diff))); diff --git a/examples/gridTest.js b/examples/gridTest.js index 2baa4650e3..0d6040470f 100644 --- a/examples/gridTest.js +++ b/examples/gridTest.js @@ -46,7 +46,7 @@ Script.setInterval(function () { position: position, dimensions: MODEL_DIMENSION, ignoreCollisions: true, - collisionsWillMove: false, + dynamic: false, lifetime: LIFETIME }); } else { @@ -57,7 +57,7 @@ Script.setInterval(function () { dimensions: { x: SIZE, y: SIZE, z: SIZE }, color: { red: x / ROWS_X * 255, green: 50, blue: z / ROWS_Z * 255 }, ignoreCollisions: true, - collisionsWillMove: false, + dynamic: false, lifetime: LIFETIME }); } diff --git a/examples/harmonicOscillator.js b/examples/harmonicOscillator.js index 4cd2989f3d..953820922b 100644 --- a/examples/harmonicOscillator.js +++ b/examples/harmonicOscillator.js @@ -25,7 +25,7 @@ ball = Entities.addEntity( position: basePosition, dimensions: { x: 0.1, y: 0.1, z: 0.1 }, color: { red: 255, green: 0, blue: 255 }, - collisionsWillMove: false, + dynamic: false, ignoreForCollisions: true }); diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index daf85664fb..f2a8e026fb 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -1242,9 +1242,9 @@
- Collisions Will Move + Dynamic - +
diff --git a/examples/libraries/easyStarExample.js b/examples/libraries/easyStarExample.js index 76c791a81f..67811e2b72 100644 --- a/examples/libraries/easyStarExample.js +++ b/examples/libraries/easyStarExample.js @@ -75,7 +75,7 @@ var playerSphere = Entities.addEntity({ y: -9.8, z: 0 }, - collisionsWillMove: true, + dynamic: true, damping: 0.2 }); @@ -267,4 +267,4 @@ function cleanup() { } -Script.scriptEnding.connect(cleanup); \ No newline at end of file +Script.scriptEnding.connect(cleanup); diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js index 39ffbed629..3f09a40e9c 100644 --- a/examples/libraries/entityPropertyDialogBox.js +++ b/examples/libraries/entityPropertyDialogBox.js @@ -201,7 +201,7 @@ EntityPropertyDialogBox = (function () { index++; array.push({ label: "Ignore for Collisions:", type: "checkbox", value: properties.ignoreForCollisions }); index++; - array.push({ label: "Collisions Will Move:", type: "checkbox", value: properties.collisionsWillMove }); + array.push({ label: "Collisions Will Move:", type: "checkbox", value: properties.dynamic }); index++; array.push({ label: "Collision Sound URL:", value: properties.collisionSoundURL }); index++; @@ -413,7 +413,7 @@ EntityPropertyDialogBox = (function () { index++; // skip header properties.density = array[index++].value; properties.ignoreForCollisions = array[index++].value; - properties.collisionsWillMove = array[index++].value; + properties.dynamic = array[index++].value; properties.lifetime = array[index++].value; properties.visible = array[index++].value; diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index b50bbe9478..84ef3430fc 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -227,7 +227,7 @@ entitySlider.prototype = { type: 'Line', name: 'Hifi-Slider-Axis::' + this.sliderType, color: this.color, - collisionsWillMove: false, + dynamic: false, ignoreForCollisions: true, dimensions: { x: 3, @@ -250,7 +250,7 @@ entitySlider.prototype = { var properties = { name: 'Hifi-End-Of-Axis', type: 'Box', - collisionsWillMove: false, + dynamic: false, ignoreForCollisions: true, dimensions: { x: 0.01, @@ -360,7 +360,7 @@ entitySlider.prototype = { type: 'Sphere', name: 'Hifi-Slider-' + this.sliderType, dimensions: SLIDER_DIMENSIONS, - collisionsWillMove: true, + dynamic: true, color: this.color, position: sliderPosition, script: SLIDER_SCRIPT_URL, @@ -558,7 +558,7 @@ function createPanelEntity(position) { z: 0.1 }, visible: false, - collisionsWillMove: false, + dynamic: false, ignoreForCollisions: true } @@ -582,7 +582,7 @@ function createVisiblePanel() { z: SLIDER_DIMENSIONS.z / 4 }, visible: true, - collisionsWillMove: false, + dynamic: false, ignoreForCollisions: true, position: moveDown, rotation: avatarRot, @@ -602,7 +602,7 @@ function createLightModel(position, rotation) { shapeType: 'box', modelURL: LIGHT_MODEL_URL, dimensions: LIGHT_MODEL_DIMENSIONS, - collisionsWillMove: true, + dynamic: true, position: position, rotation: rotation, script: PARENT_SCRIPT_URL, @@ -639,7 +639,7 @@ function createCloseButton(axisStart) { position: Vec3.sum(position, VERTICAL_OFFFSET), rotation: Quat.multiply(avatarRot, Quat.fromPitchYawRollDegrees(90, 0, 45)), //rotation: Quat.fromPitchYawRollDegrees(0, 0, 90), - collisionsWillMove: false, + dynamic: false, ignoreForCollisions: true, script: CLOSE_BUTTON_SCRIPT_URL, userData: JSON.stringify({ @@ -873,4 +873,4 @@ subscribeToCleanupMessages(); // linearAttenuation: 0, // quadraticAttenuation: 0, // exponent: 0, -// cutoff: 180, // in degrees \ No newline at end of file +// cutoff: 180, // in degrees diff --git a/examples/lotsoBlocks.js b/examples/lotsoBlocks.js index 63ed774d2d..3539988f0b 100644 --- a/examples/lotsoBlocks.js +++ b/examples/lotsoBlocks.js @@ -42,7 +42,7 @@ for (var i = 0; i < NUM_BLOCKS; i++) { z: basePosition.z + randFloat(-SPAWN_RANGE, SPAWN_RANGE) }, color: {red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255}, - collisionsWillMove: true, + dynamic: true, gravity: {x: 0, y: 0, z: 0} })); } @@ -60,4 +60,4 @@ Script.scriptEnding.connect(cleanup); function randFloat(low, high) { return low + Math.random() * ( high - low ); -} \ No newline at end of file +} diff --git a/examples/magBalls/constants.js b/examples/magBalls/constants.js index d9dee94329..3b06fcf167 100644 --- a/examples/magBalls/constants.js +++ b/examples/magBalls/constants.js @@ -39,7 +39,7 @@ BALL_PROTOTYPE = { dimensions: BALL_DIMENSIONS, color: BALL_COLOR, ignoreCollisions: true, - collisionsWillMove: false + dynamic: false }; // 2 millimeters @@ -62,7 +62,7 @@ LINE_PROTOTYPE = { lineWidth: 5, visible: true, ignoreCollisions: true, - collisionsWillMove: false, + dynamic: false, } EDGE_PROTOTYPE = LINE_PROTOTYPE; @@ -76,7 +76,7 @@ EDGE_PROTOTYPE = LINE_PROTOTYPE; // rotation: rotation, // visible: true, // ignoreCollisions: true, -// collisionsWillMove: false +// dynamic: false // } diff --git a/examples/particle_explorer/main.js b/examples/particle_explorer/main.js index a2a112d8e5..3f15efb836 100644 --- a/examples/particle_explorer/main.js +++ b/examples/particle_explorer/main.js @@ -9,7 +9,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/*global window, alert, EventBridge, dat, convertBinaryToBoolean, listenForSettingsUpdates,createVec3Folder,createQuatFolder,writeVec3ToInterface,writeDataToInterface*/ +/*global window, alert, EventBridge, dat, listenForSettingsUpdates,createVec3Folder,createQuatFolder,writeVec3ToInterface,writeDataToInterface*/ var Settings = function() { this.exportSettings = function() { @@ -66,7 +66,7 @@ var keysToIgnore = [ 'angularVelocity', 'angularDamping', 'ignoreForCollisions', - 'collisionsWillMove', + 'dynamic', 'href', 'actionData', 'marketplaceID', @@ -502,11 +502,3 @@ function registerDOMElementsForListenerBlocking() { }); } -///utility method for converting weird collisionWillMove type propertyies from binary to new Boolean() -// -// function convertBinaryToBoolean(value) { -// if (value === 0) { -// return false; -// } -// return true; -// } \ No newline at end of file diff --git a/examples/planets.js b/examples/planets.js index 467c642fbf..1ab26b361b 100644 --- a/examples/planets.js +++ b/examples/planets.js @@ -58,7 +58,7 @@ for (var i = 0; i < planetTypes.length; i++) { angularDamping: 0.0, ignoreCollisions: false, lifetime: LIFETIME, - collisionsWillMove: false })); + dynamic: false })); } Script.setTimeout(createParticles, 1000); @@ -82,7 +82,7 @@ function createParticles() { ignoreCollisions: false, damping: DAMPING, lifetime: LIFETIME, - collisionsWillMove: true })); + dynamic: true })); } Script.update.connect(update); } diff --git a/examples/playa/playaSpawner.js b/examples/playa/playaSpawner.js index 61101a0e62..84a6093441 100644 --- a/examples/playa/playaSpawner.js +++ b/examples/playa/playaSpawner.js @@ -113,7 +113,7 @@ function spawnBoxes() { collisionSoundURL: collisionSoundURL, shapeType: "box", position: position, - collisionsWillMove: true, + dynamic: true, dimensions: {x: 1, y: 2, z: 3}, velocity: {x: 0, y: -.01, z: 0}, gravity: {x: 0, y: -2.5 - Math.random() * 6, z: 0} diff --git a/examples/popcorn.js b/examples/popcorn.js index ec24b962f2..00e3014ada 100644 --- a/examples/popcorn.js +++ b/examples/popcorn.js @@ -148,7 +148,7 @@ for (var i = 0; i < NUM_BALLS; i++) { ignoreCollisions: false, damping: DAMPING, lifetime: LIFETIME, - collisionsWillMove: true })); + dynamic: true })); } var VEL_MAG = 2.0; diff --git a/examples/stick-hydra.js b/examples/stick-hydra.js index a74f7954bb..495ab7be5c 100644 --- a/examples/stick-hydra.js +++ b/examples/stick-hydra.js @@ -37,7 +37,7 @@ function makeNewStick() { damping: .1, collisionSoundURL: "http://public.highfidelity.io/sounds/Collisions-hitsandslaps/67LCollision07.wav", restitution: 0.01, - collisionsWillMove: true + dynamic: true }); actionID = Entities.addAction("hold", stickID, {relativePosition: {x: 0.0, y: 0.0, z: -0.5}, diff --git a/examples/stick.js b/examples/stick.js index 6683d8dcb6..7174addfc2 100644 --- a/examples/stick.js +++ b/examples/stick.js @@ -37,7 +37,7 @@ function makeNewStick() { damping: .1, collisionSoundURL: "http://public.highfidelity.io/sounds/Collisions-hitsandslaps/67LCollision07.wav", restitution: 0.01, - collisionsWillMove: true + dynamic: true }); actionID = Entities.addAction("hold", stickID, {relativePosition: {x: 0.0, y: 0.0, z: -0.9}, hand: hand, diff --git a/examples/toybox/basketball/createRack.js b/examples/toybox/basketball/createRack.js index aee492f684..995f5487f9 100644 --- a/examples/toybox/basketball/createRack.js +++ b/examples/toybox/basketball/createRack.js @@ -47,7 +47,7 @@ var rack = Entities.addEntity({ y: 1.37, z: 1.73 }, - collisionsWillMove: true, + dynamic: true, ignoreForCollisions: false, collisionSoundURL: collisionSoundURL, compoundShapeURL: rackCollisionHullURL, @@ -89,7 +89,7 @@ function createBalls() { y: -9.8, z: 0 }, - collisionsWillMove: true, + dynamic: true, ignoreForCollisions: false, modelURL: basketballURL, userData: JSON.stringify({ @@ -150,4 +150,4 @@ function atEnd() { Script.clearInterval(distanceCheckInterval); } -Script.scriptEnding.connect(atEnd); \ No newline at end of file +Script.scriptEnding.connect(atEnd); diff --git a/examples/toybox/basketball/createSingleBasketball.js b/examples/toybox/basketball/createSingleBasketball.js index 6765e5e075..7663b40c42 100644 --- a/examples/toybox/basketball/createSingleBasketball.js +++ b/examples/toybox/basketball/createSingleBasketball.js @@ -42,7 +42,7 @@ function makeBasketball() { y: DIAMETER, z: DIAMETER }, - collisionsWillMove: true, + dynamic: true, collisionSoundURL: collisionSoundURL, modelURL: basketballURL, restitution: 1.0, @@ -94,4 +94,4 @@ function deleteStuff() { } Script.update.connect(update); -Script.scriptEnding.connect(scriptEnding); \ No newline at end of file +Script.scriptEnding.connect(scriptEnding); diff --git a/examples/toybox/blockers/createTestBlocks.js b/examples/toybox/blockers/createTestBlocks.js index 10bdb14d76..487770b1bc 100644 --- a/examples/toybox/blockers/createTestBlocks.js +++ b/examples/toybox/blockers/createTestBlocks.js @@ -90,7 +90,7 @@ var topBlock = Entities.addEntity({ rotation: topBlock_rotation, damping: LINEAR_DAMPING, gravity: BLOCK_GRAVITY, - collisionsWillMove: true, + dynamic: true, velocity: { x: 0, y: -0.01, @@ -108,7 +108,7 @@ var sideBlock1 = Entities.addEntity({ rotation: sideBlock1_rotation, damping: LINEAR_DAMPING, gravity: BLOCK_GRAVITY, - collisionsWillMove: true + dynamic: true }); var sideBlock2 = Entities.addEntity({ @@ -119,10 +119,10 @@ var sideBlock2 = Entities.addEntity({ dimensions: blockDimensions, position: sideBlock2_position, rotation: sideBlock2_rotation, - collsionsWillMove: true, + dynamic: true, damping: LINEAR_DAMPING, gravity: BLOCK_GRAVITY, - collisionsWillMove: true + dynamic: true }); var ground = Entities.addEntity({ diff --git a/examples/toybox/bow/bow.js b/examples/toybox/bow/bow.js index c04bb7a72c..5c27b61e9e 100644 --- a/examples/toybox/bow/bow.js +++ b/examples/toybox/bow/bow.js @@ -234,7 +234,7 @@ compoundShapeURL: ARROW_COLLISION_HULL_URL, dimensions: ARROW_DIMENSIONS, position: this.bowProperties.position, - collisionsWillMove: false, + dynamic: false, ignoreForCollisions: true, collisionSoundURL: ARROW_HIT_SOUND_URL, damping: 0.01, @@ -264,7 +264,7 @@ z: 0 }, position: collision.contactPoint, - collisionsWillMove: false + dynamic: false }) // print('ARROW COLLIDED WITH::' + entityB); Script.removeEventHandler(arrow, "collisionWithEntity", makeArrowStick) @@ -286,7 +286,7 @@ type: 'Line', position: Vec3.sum(this.bowProperties.position, TOP_NOTCH_OFFSET), dimensions: LINE_DIMENSIONS, - collisionsWillMove: false, + dynamic: false, ignoreForCollisions: true, userData: JSON.stringify({ grabbableKey: { @@ -304,7 +304,7 @@ type: 'Line', position: Vec3.sum(this.bowProperties.position, BOTTOM_NOTCH_OFFSET), dimensions: LINE_DIMENSIONS, - collisionsWillMove: false, + dynamic: false, ignoreForCollisions: true, userData: JSON.stringify({ grabbableKey: { @@ -389,7 +389,7 @@ position: Vec3.sum(this.bowProperties.position, TOP_NOTCH_OFFSET), dimensions: LINE_DIMENSIONS, visible: true, - collisionsWillMove: false, + dynamic: false, ignoreForCollisions: true, userData: JSON.stringify({ grabbableKey: { @@ -538,7 +538,7 @@ //make the arrow physical, give it gravity, a lifetime, and set our velocity var arrowProperties = { - collisionsWillMove: true, + dynamic: true, ignoreForCollisions: false, collisionMask: "static,dynamic,otherAvatar", // workaround: not with kinematic --> no collision with bow velocity: releaseVelocity, diff --git a/examples/toybox/bow/createBow.js b/examples/toybox/bow/createBow.js index 4f0cddfc0d..abe0238de1 100644 --- a/examples/toybox/bow/createBow.js +++ b/examples/toybox/bow/createBow.js @@ -39,7 +39,7 @@ var bow = Entities.addEntity({ modelURL: MODEL_URL, position: center, dimensions: BOW_DIMENSIONS, - collisionsWillMove: true, + dynamic: true, gravity: BOW_GRAVITY, shapeType: 'compound', compoundShapeURL: COLLISION_HULL_URL, @@ -68,4 +68,4 @@ function cleanup() { Entities.deleteEntity(bow); } -Script.scriptEnding.connect(cleanup); \ No newline at end of file +Script.scriptEnding.connect(cleanup); diff --git a/examples/toybox/bubblewand/createWand.js b/examples/toybox/bubblewand/createWand.js index efd86b046f..d859d7cb9f 100644 --- a/examples/toybox/bubblewand/createWand.js +++ b/examples/toybox/bubblewand/createWand.js @@ -41,7 +41,7 @@ var wand = Entities.addEntity({ z: 0.05 }, //must be enabled to be grabbable in the physics engine - collisionsWillMove: true, + dynamic: true, compoundShapeURL: WAND_COLLISION_SHAPE, script: WAND_SCRIPT_URL, userData: JSON.stringify({ diff --git a/examples/toybox/bubblewand/wand.js b/examples/toybox/bubblewand/wand.js index a6e4eae34d..02dcdb2cb9 100644 --- a/examples/toybox/bubblewand/wand.js +++ b/examples/toybox/bubblewand/wand.js @@ -71,7 +71,7 @@ addCollisionsToBubbleAfterCreation: function(bubble) { //if the bubble collide immediately, we get weird effects. so we add collisions after release Entities.editEntity(bubble, { - collisionsWillMove: true + dynamic: true }); }, randomizeBubbleGravity: function() { @@ -161,7 +161,7 @@ modelURL: BUBBLE_MODEL, position: this.getWandTipPosition(properties), dimensions: BUBBLE_INITIAL_DIMENSIONS, - collisionsWillMove: false, + dynamic: false, ignoreForCollisions: true, damping: BUBBLE_LINEAR_DAMPING, shapeType: "sphere" @@ -198,4 +198,4 @@ return new BubbleWand(); -}); \ No newline at end of file +}); diff --git a/examples/toybox/doll/createDoll.js b/examples/toybox/doll/createDoll.js index 52ba5a5291..4a3f1cfbd8 100644 --- a/examples/toybox/doll/createDoll.js +++ b/examples/toybox/doll/createDoll.js @@ -47,7 +47,7 @@ function createDoll() { y: 0, z: 0 }, - collisionsWillMove: true, + dynamic: true, userData: JSON.stringify({ grabbableKey: { invertSolidWhileHeld: true @@ -57,4 +57,4 @@ function createDoll() { return doll; } -createDoll(); \ No newline at end of file +createDoll(); diff --git a/examples/toybox/flashlight/createFlashlight.js b/examples/toybox/flashlight/createFlashlight.js index 108d519d3e..897ba516e1 100644 --- a/examples/toybox/flashlight/createFlashlight.js +++ b/examples/toybox/flashlight/createFlashlight.js @@ -33,7 +33,7 @@ var flashlight = Entities.addEntity({ y: 0.30, z: 0.08 }, - collisionsWillMove: true, + dynamic: true, shapeType: 'box', script: scriptURL, userData: JSON.stringify({ @@ -41,4 +41,4 @@ var flashlight = Entities.addEntity({ invertSolidWhileHeld: true } }) -}); \ No newline at end of file +}); diff --git a/examples/toybox/ping_pong_gun/createPingPongGun.js b/examples/toybox/ping_pong_gun/createPingPongGun.js index 7835dbf7f9..c8f7093b7e 100644 --- a/examples/toybox/ping_pong_gun/createPingPongGun.js +++ b/examples/toybox/ping_pong_gun/createPingPongGun.js @@ -34,7 +34,7 @@ var pingPongGun = Entities.addEntity({ y: 0.21, z: 0.47 }, - collisionsWillMove: true, + dynamic: true, collisionSoundURL: COLLISION_SOUND_URL, userData: JSON.stringify({ grabbableKey: { @@ -54,4 +54,4 @@ var pingPongGun = Entities.addEntity({ function cleanUp() { Entities.deleteEntity(pingPongGun); } -Script.scriptEnding.connect(cleanUp); \ No newline at end of file +Script.scriptEnding.connect(cleanUp); diff --git a/examples/toybox/ping_pong_gun/createTargets.js b/examples/toybox/ping_pong_gun/createTargets.js index c421352a9d..baeca9c065 100644 --- a/examples/toybox/ping_pong_gun/createTargets.js +++ b/examples/toybox/ping_pong_gun/createTargets.js @@ -55,7 +55,7 @@ var targetIntervalClearer = Entities.addEntity({ }, rotation: rotation, visible: false, - collisionsWillMove: false, + dynamic: false, ignoreForCollisions: true, }); @@ -89,7 +89,7 @@ function addTargets() { type: 'Model', modelURL: MODEL_URL, shapeType: 'compound', - collisionsWillMove: true, + dynamic: true, dimensions: TARGET_DIMENSIONS, compoundShapeURL: COLLISION_HULL_URL, position: position, @@ -122,7 +122,7 @@ function testTargetDistanceFromStart() { type: 'Model', modelURL: MODEL_URL, shapeType: 'compound', - collisionsWillMove: true, + dynamic: true, dimensions: TARGET_DIMENSIONS, compoundShapeURL: COLLISION_HULL_URL, position: originalPositions[index], @@ -167,4 +167,4 @@ function atEnd() { deleteTargets(); } -Script.scriptEnding.connect(atEnd); \ No newline at end of file +Script.scriptEnding.connect(atEnd); diff --git a/examples/toybox/ping_pong_gun/pingPongGun.js b/examples/toybox/ping_pong_gun/pingPongGun.js index bd8b5f710d..5b928719fa 100644 --- a/examples/toybox/ping_pong_gun/pingPongGun.js +++ b/examples/toybox/ping_pong_gun/pingPongGun.js @@ -126,7 +126,7 @@ damping: BALL_LINEAR_DAMPING, gravity: BALL_GRAVITY, restitution: BALL_RESTITUTION, - collisionsWillMove: true, + dynamic: true, rotation: gunProperties.rotation, position: this.getGunTipPosition(gunProperties), velocity: forwardVec, diff --git a/examples/toybox/pistol/createPistol.js b/examples/toybox/pistol/createPistol.js index 693c53b9b4..8449a2234a 100644 --- a/examples/toybox/pistol/createPistol.js +++ b/examples/toybox/pistol/createPistol.js @@ -19,7 +19,7 @@ var pistol = Entities.addEntity({ blue: 20 }, shapeType: 'box', - collisionsWillMove: true, + dynamic: true, gravity: {x: 0, y: -5.0, z: 0}, restitution: 0, collisionSoundURL: "https://s3.amazonaws.com/hifi-public/sounds/Guns/Gun_Drop_and_Metalli_1.wav", @@ -43,4 +43,4 @@ function cleanup() { Entities.deleteEntity(pistol); } -Script.scriptEnding.connect(cleanup); \ No newline at end of file +Script.scriptEnding.connect(cleanup); diff --git a/examples/toybox/pistol/pistol.js b/examples/toybox/pistol/pistol.js index e0f063d463..989ab4b179 100644 --- a/examples/toybox/pistol/pistol.js +++ b/examples/toybox/pistol/pistol.js @@ -153,7 +153,7 @@ }); }, randFloat(10, 200)); } - if (intersection.properties.collisionsWillMove === 1) { + if (intersection.properties.dynamic === 1) { // Any entity with collisions will move can be shot Entities.editEntity(intersection.entityID, { velocity: Vec3.multiply(this.firingDirection, this.bulletForce) @@ -359,4 +359,4 @@ // entity scripts always need to return a newly constructed object of our type return new Pistol(); -}); \ No newline at end of file +}); diff --git a/examples/weapons/shootingRangeSpawner.js b/examples/weapons/shootingRangeSpawner.js index e5e76a71fc..6d21d20d7f 100644 --- a/examples/weapons/shootingRangeSpawner.js +++ b/examples/weapons/shootingRangeSpawner.js @@ -62,7 +62,7 @@ function initMonsters() { y: 1.6, z: 0.07 }, - collisionsWillMove: true, + dynamic: true, shapeType: 'box', velocity: { x: randFloat(1, 3), @@ -114,4 +114,4 @@ function cleanup() { }); } -Script.scriptEnding.connect(cleanup); \ No newline at end of file +Script.scriptEnding.connect(cleanup); diff --git a/examples/winterSmashUp/targetPractice/shooterPlatform.js b/examples/winterSmashUp/targetPractice/shooterPlatform.js index 4fae47a415..9666b90d5e 100644 --- a/examples/winterSmashUp/targetPractice/shooterPlatform.js +++ b/examples/winterSmashUp/targetPractice/shooterPlatform.js @@ -37,7 +37,7 @@ modelURL: MODEL_URL, position: MyAvatar.position, dimensions: {x: 0.04, y: 1.3, z: 0.21}, - collisionsWillMove: true, + dynamic: true, gravity: {x: 0, y: 0, z: 0}, shapeType: 'compound', compoundShapeURL: COLLISION_HULL_URL, diff --git a/examples/winterSmashUp/targetPractice/targetPracticeGame.js b/examples/winterSmashUp/targetPractice/targetPracticeGame.js index d58258af5a..72c10ddb01 100644 --- a/examples/winterSmashUp/targetPractice/targetPracticeGame.js +++ b/examples/winterSmashUp/targetPractice/targetPracticeGame.js @@ -157,7 +157,7 @@ var onTargetHit = function(targetEntity, projectileEntity, collision) { parentID: targetEntity }); Entities.editEntity(targetEntity, { - collisionsWillMove: true, + dynamic: true, gravity: {x: 0, y: GRAVITY, z: 0}, velocity: {x: 0, y: -0.01, z: 0} }); diff --git a/unpublishedScripts/basketballsResetter.js b/unpublishedScripts/basketballsResetter.js index 6b8bc75f0d..e4938a2b79 100644 --- a/unpublishedScripts/basketballsResetter.js +++ b/unpublishedScripts/basketballsResetter.js @@ -81,7 +81,7 @@ var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; y: -9.8, z: 0 }, - collisionsWillMove: true, + dynamic: true, collisionSoundURL: basketballCollisionSoundURL, ignoreForCollisions: false, modelURL: basketballURL, diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 8f095ba0c5..ec50264811 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -177,7 +177,7 @@ rotation: rotation, position: position, shapeType: 'box', - collisionsWillMove: true, + dynamic: true, script: raveStickEntityScriptURL, dimensions: { x: 0.06, @@ -295,7 +295,7 @@ y: -3.0, z: 0 }, - collisionsWillMove: true, + dynamic: true, userData: JSON.stringify({ grabbableKey: { spatialKey: { @@ -351,7 +351,7 @@ position: startPosition, rotation: BOW_ROTATION, dimensions: BOW_DIMENSIONS, - collisionsWillMove: true, + dynamic: true, gravity: BOW_GRAVITY, shapeType: 'compound', compoundShapeURL: COLLISION_HULL_URL, @@ -493,7 +493,7 @@ y: 1.37, z: 1.73 }, - collisionsWillMove: true, + dynamic: true, ignoreForCollisions: false, compoundShapeURL: rackCollisionHullURL, userData: JSON.stringify({ @@ -541,7 +541,7 @@ y: -9.8, z: 0 }, - collisionsWillMove: true, + dynamic: true, collisionSoundURL: 'http://hifi-public.s3.amazonaws.com/sounds/basketball/basketball.wav', ignoreForCollisions: false, modelURL: basketballURL, @@ -686,7 +686,7 @@ type: 'Model', modelURL: MODEL_URL, shapeType: 'compound', - collisionsWillMove: true, + dynamic: true, dimensions: TARGET_DIMENSIONS, compoundShapeURL: COLLISION_HULL_URL, position: position, @@ -767,7 +767,7 @@ y: 0.30, z: 0.08 }, - collisionsWillMove: true, + dynamic: true, collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/flashlight_drop.L.wav", gravity: { x: 0, @@ -1057,7 +1057,7 @@ z: 0 }, shapeType: "box", - collisionsWillMove: true, + dynamic: true, userData: JSON.stringify({ resetMe: { resetMe: true @@ -1101,7 +1101,7 @@ z: 0.2 }, rotation: rotation, - collisionsWillMove: true, + dynamic: true, gravity: { x: 0, y: -100, @@ -1152,7 +1152,7 @@ y: 0.21, z: 0.47 }, - collisionsWillMove: true, + dynamic: true, collisionSoundURL: COLLISION_SOUND_URL, userData: JSON.stringify({ resetMe: { @@ -1200,7 +1200,7 @@ z: 0.05 }, //must be enabled to be grabbable in the physics engine - collisionsWillMove: true, + dynamic: true, compoundShapeURL: WAND_COLLISION_SHAPE, script: wandScriptURL, userData: JSON.stringify({ @@ -1231,7 +1231,7 @@ type: "Model", modelURL: modelURL, position: position, - collisionsWillMove: true, + dynamic: true, shapeType: "sphere", name: "basketball", dimensions: { @@ -1291,7 +1291,7 @@ y: -0.1, z: 0 }, - collisionsWillMove: true, + dynamic: true, userData: JSON.stringify({ resetMe: { resetMe: true @@ -1319,7 +1319,7 @@ y: 0.17, z: 0.07 }, - collisionsWillMove: true, + dynamic: true, collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/SpryPntCnDrp1.L.wav", shapeType: 'box', restitution: 0, @@ -1358,7 +1358,7 @@ y: 2.18, z: 1.07 }, - collisionsWillMove: true, + dynamic: true, shapeType: 'box', gravity: { x: 0, @@ -1402,7 +1402,7 @@ y: 1.56, z: 1.35 }, - collisionsWillMove: true, + dynamic: true, gravity: { x: 0, y: -0.8, @@ -1484,7 +1484,7 @@ shapeType: 'box', name: "block", dimensions: blockTypes[i].dimensions, - collisionsWillMove: true, + dynamic: true, collisionSoundURL: collisionSoundURL, gravity: { x: 0, diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index e6605c17e0..72074da5f1 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -157,7 +157,7 @@ MasterReset = function() { rotation: rotation, position: position, shapeType: 'box', - collisionsWillMove: true, + dynamic: true, script: raveStickEntityScriptURL, dimensions: { x: 0.06, @@ -279,7 +279,7 @@ MasterReset = function() { z: 0 }, restitution: 0, - collisionsWillMove: true, + dynamic: true, collisionSoundURL: "https://s3.amazonaws.com/hifi-public/sounds/Guns/Gun_Drop_and_Metalli_1.wav", userData: JSON.stringify({ grabbableKey: { @@ -336,7 +336,7 @@ MasterReset = function() { position: startPosition, rotation: BOW_ROTATION, dimensions: BOW_DIMENSIONS, - collisionsWillMove: true, + dynamic: true, gravity: BOW_GRAVITY, shapeType: 'compound', compoundShapeURL: COLLISION_HULL_URL, @@ -477,7 +477,7 @@ MasterReset = function() { y: 1.37, z: 1.73 }, - collisionsWillMove: true, + dynamic: true, ignoreForCollisions: false, compoundShapeURL: rackCollisionHullURL, userData: JSON.stringify({ @@ -526,7 +526,7 @@ MasterReset = function() { y: -9.8, z: 0 }, - collisionsWillMove: true, + dynamic: true, collisionSoundURL: 'http://hifi-public.s3.amazonaws.com/sounds/basketball/basketball.wav', ignoreForCollisions: false, modelURL: basketballURL, @@ -672,7 +672,7 @@ MasterReset = function() { type: 'Model', modelURL: MODEL_URL, shapeType: 'compound', - collisionsWillMove: true, + dynamic: true, dimensions: TARGET_DIMENSIONS, compoundShapeURL: COLLISION_HULL_URL, position: position, @@ -753,7 +753,7 @@ MasterReset = function() { y: 0.30, z: 0.08 }, - collisionsWillMove: true, + dynamic: true, collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/flashlight_drop.L.wav", gravity: { x: 0, @@ -1043,7 +1043,7 @@ MasterReset = function() { z: 0 }, shapeType: "box", - collisionsWillMove: true, + dynamic: true, userData: JSON.stringify({ resetMe: { resetMe: true @@ -1087,7 +1087,7 @@ MasterReset = function() { z: 0.2 }, rotation: rotation, - collisionsWillMove: true, + dynamic: true, gravity: { x: 0, y: -100, @@ -1138,7 +1138,7 @@ MasterReset = function() { y: 0.21, z: 0.47 }, - collisionsWillMove: true, + dynamic: true, collisionSoundURL: COLLISION_SOUND_URL, userData: JSON.stringify({ resetMe: { @@ -1186,7 +1186,7 @@ MasterReset = function() { z: 0.05 }, //must be enabled to be grabbable in the physics engine - collisionsWillMove: true, + dynamic: true, compoundShapeURL: WAND_COLLISION_SHAPE, script: wandScriptURL, userData: JSON.stringify({ @@ -1217,7 +1217,7 @@ MasterReset = function() { type: "Model", modelURL: modelURL, position: position, - collisionsWillMove: true, + dynamic: true, shapeType: "sphere", name: "basketball", dimensions: { @@ -1277,7 +1277,7 @@ MasterReset = function() { y: -0.1, z: 0 }, - collisionsWillMove: true, + dynamic: true, userData: JSON.stringify({ resetMe: { resetMe: true @@ -1305,7 +1305,7 @@ MasterReset = function() { y: 0.17, z: 0.07 }, - collisionsWillMove: true, + dynamic: true, collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/SpryPntCnDrp1.L.wav", shapeType: 'box', gravity: { @@ -1344,7 +1344,7 @@ MasterReset = function() { y: 2.18, z: 1.07 }, - collisionsWillMove: true, + dynamic: true, shapeType: 'box', gravity: { x: 0, @@ -1388,7 +1388,7 @@ MasterReset = function() { y: 1.56, z: 1.35 }, - collisionsWillMove: true, + dynamic: true, gravity: { x: 0, y: -0.8, @@ -1470,7 +1470,7 @@ MasterReset = function() { shapeType: 'box', name: "block", dimensions: blockTypes[i].dimensions, - collisionsWillMove: true, + dynamic: true, collisionSoundURL: collisionSoundURL, gravity: { x: 0, diff --git a/unpublishedScripts/targetsResetter.js b/unpublishedScripts/targetsResetter.js index 326c0ce1be..ccec8173de 100644 --- a/unpublishedScripts/targetsResetter.js +++ b/unpublishedScripts/targetsResetter.js @@ -93,7 +93,7 @@ type: 'Model', modelURL: MODEL_URL, shapeType: 'compound', - collisionsWillMove: true, + dynamic: true, dimensions: TARGET_DIMENSIONS, compoundShapeURL: COLLISION_HULL_URL, position: position, From e763c055b3fdc77f0d97e39bd4695531216c0ab8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Jan 2016 09:38:18 -0800 Subject: [PATCH 177/215] more namechanges in JS scripts --- examples/example/games/exterminatorGame/pistol.js | 2 +- examples/libraries/entityPropertyDialogBox.js | 2 +- examples/toybox/pistol/pistol.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/example/games/exterminatorGame/pistol.js b/examples/example/games/exterminatorGame/pistol.js index b5b8d37812..2cccf95986 100644 --- a/examples/example/games/exterminatorGame/pistol.js +++ b/examples/example/games/exterminatorGame/pistol.js @@ -170,7 +170,7 @@ function fire(side, value) { Script.setTimeout(function() { createEntityHitEffect(intersection.intersection); if (shootAnything && intersection.properties.dynamic === 1) { - // Any entity with collisions will move can be shot + // Any dynamic entity can be shot Entities.editEntity(intersection.entityID, { velocity: Vec3.multiply(shotDirection, GUN_FORCE) }); diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js index 3f09a40e9c..2b720392b0 100644 --- a/examples/libraries/entityPropertyDialogBox.js +++ b/examples/libraries/entityPropertyDialogBox.js @@ -201,7 +201,7 @@ EntityPropertyDialogBox = (function () { index++; array.push({ label: "Ignore for Collisions:", type: "checkbox", value: properties.ignoreForCollisions }); index++; - array.push({ label: "Collisions Will Move:", type: "checkbox", value: properties.dynamic }); + array.push({ label: "Dynamic:", type: "checkbox", value: properties.dynamic }); index++; array.push({ label: "Collision Sound URL:", value: properties.collisionSoundURL }); index++; diff --git a/examples/toybox/pistol/pistol.js b/examples/toybox/pistol/pistol.js index 989ab4b179..6ed3407ea9 100644 --- a/examples/toybox/pistol/pistol.js +++ b/examples/toybox/pistol/pistol.js @@ -154,7 +154,7 @@ }, randFloat(10, 200)); } if (intersection.properties.dynamic === 1) { - // Any entity with collisions will move can be shot + // Any dynaic entity can be shot Entities.editEntity(intersection.entityID, { velocity: Vec3.multiply(this.firingDirection, this.bulletForce) }); From 84282d01141ffcb15d7d541fbe3484f7e5f28f86 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 15 Jan 2016 15:28:26 -0800 Subject: [PATCH 178/215] final repairs after rebase --- examples/html/entityProperties.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index f2a8e026fb..41581845df 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -262,7 +262,7 @@ var elDensity = document.getElementById("property-density"); var elIgnoreForCollisions = document.getElementById("property-ignore-for-collisions"); - var elCollisionsWillMove = document.getElementById("property-collisions-will-move"); + var elDynamic = document.getElementById("property-dyanmict ); var elCollisionSoundURL = document.getElementById("property-collision-sound-url"); var elLifetime = document.getElementById("property-lifetime"); var elScriptURL = document.getElementById("property-script-url"); @@ -492,7 +492,7 @@ elDensity.value = properties.density.toFixed(2); elIgnoreForCollisions.checked = properties.ignoreForCollisions; - elCollisionsWillMove.checked = properties.collisionsWillMove; + elDynamic.checked = properties.dynamic; elCollisionSoundURL.value = properties.collisionSoundURL; elLifetime.value = properties.lifetime; elScriptURL.value = properties.script; @@ -719,7 +719,7 @@ elDensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('density')); elIgnoreForCollisions.addEventListener('change', createEmitCheckedPropertyUpdateFunction('ignoreForCollisions')); - elCollisionsWillMove.addEventListener('change', createEmitCheckedPropertyUpdateFunction('collisionsWillMove')); + elDynamic.addEventListener('change', createEmitCheckedPropertyUpdateFunction('dynamic')); elCollisionSoundURL.addEventListener('change', createEmitTextPropertyUpdateFunction('collisionSoundURL')); elLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('lifetime')); From fad38c0bfbf8b4f4ce53a3305ed502963774ff88 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 14 Jan 2016 15:16:05 -0800 Subject: [PATCH 179/215] Add uniform buffer to LightStage --- libraries/render-utils/src/LightStage.cpp | 19 ++++++++++++++++--- libraries/render-utils/src/LightStage.h | 20 ++++++++++++++++---- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index f6c2e14f2b..2217de6f28 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -16,6 +16,8 @@ LightStage::Shadow::Shadow(model::LightPointer light) : _light{ light}, _frustum{ std::make_shared() } { framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(MAP_SIZE)); map = framebuffer->getDepthStencilBuffer(); + Schema schema{glm::mat4(), glm::mat4(), 0, MAP_SIZE}; + _schemaBuffer = std::make_shared(sizeof(Schema), (const gpu::Byte*) &schema); } void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float nearDepth, float farDepth) { @@ -36,8 +38,8 @@ void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float near // Position the keylight frustum _frustum->setPosition(viewFrustum->getPosition() - (nearDepth + farDepth)*direction); - _view = _frustum->getView(); - const Transform viewInverse{ _view.getInverseMatrix() }; + const Transform view{ _frustum->getView()}; + const Transform viewInverse{ view.getInverseMatrix() }; viewFrustum->calculate(); auto nearCorners = viewFrustum->getCorners(nearDepth); @@ -67,7 +69,18 @@ void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float near glm::mat4 ortho = glm::ortho(min.x, max.x, min.y, max.y, -max.z, -min.z); _frustum->setProjection(ortho); - _projection = ortho; + + // Update the buffer + _schemaBuffer.edit().projection = ortho; + _schemaBuffer.edit().view = view.getMatrix(); +} + +const glm::mat4& LightStage::Shadow::getView() const { + return _frustum->getView(); +} + +const glm::mat4& LightStage::Shadow::getProjection() const { + return _frustum->getProjection(); } const LightStage::LightPointer LightStage::addLight(model::LightPointer light) { diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index 3d59de6164..10c8227ff3 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -23,6 +23,7 @@ class LightStage { public: class Shadow { public: + using UniformBufferView = gpu::BufferView; const int MAP_SIZE = 2048; Shadow(model::LightPointer light); @@ -30,16 +31,27 @@ public: void setKeylightFrustum(ViewFrustum* viewFrustum, float nearDepth, float farDepth); const std::shared_ptr getFrustum() const { return _frustum; } - const glm::mat4& getProjection() const { return _projection; } - const Transform& getView() const { return _view; } + + const glm::mat4& getView() const; + const glm::mat4& getProjection() const; + + const UniformBufferView& getBuffer() const { return _schemaBuffer; } gpu::FramebufferPointer framebuffer; gpu::TexturePointer map; protected: model::LightPointer _light; std::shared_ptr _frustum; - glm::mat4 _projection; - Transform _view; + + class Schema { + public: + glm::mat4 projection; + glm::mat4 view; + + glm::float32 bias; + glm::float32 scale; + }; + UniformBufferView _schemaBuffer = nullptr; }; using ShadowPointer = std::shared_ptr; From bc379e920b6a1045717a1d257c7fc5e6f5808e58 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 14 Jan 2016 15:28:11 -0800 Subject: [PATCH 180/215] Update shadow programs --- .../src/DeferredLightingEffect.cpp | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index b5f866166e..ac18348528 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -42,6 +42,7 @@ struct LightLocations { int texcoordMat; int coneParam; int deferredTransformBuffer; + int shadowTransformBuffer; }; static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations); @@ -55,12 +56,9 @@ void DeferredLightingEffect::init() { _spotLightLocations = std::make_shared(); loadLightProgram(deferred_light_vert, directional_light_frag, false, _directionalLight, _directionalLightLocations); - loadLightProgram(deferred_light_vert, directional_ambient_light_frag, false, _directionalAmbientSphereLight, _directionalAmbientSphereLightLocations); - loadLightProgram(deferred_light_vert, directional_skybox_light_frag, false, _directionalSkyboxLight, _directionalSkyboxLightLocations); - loadLightProgram(deferred_light_limited_vert, point_light_frag, true, _pointLight, _pointLightLocations); loadLightProgram(deferred_light_spot_vert, spot_light_frag, true, _spotLight, _spotLightLocations); @@ -174,6 +172,12 @@ void DeferredLightingEffect::render(RenderArgs* args) { batch.setResourceTexture(2, framebufferCache->getDeferredSpecularTexture()); batch.setResourceTexture(3, framebufferCache->getPrimaryDepthTexture()); + assert(_lightStage.lights.size() > 0); + const auto& globalShadow = _lightStage.lights[0]->shadow; + + // Bind the shadow buffer + batch.setResourceTexture(4, globalShadow.map); + // THe main viewport is assumed to be the mono viewport (or the 2 stereo faces side by side within that viewport) auto monoViewport = args->_viewport; float sMin = args->_viewport.x / (float)framebufferSize.width(); @@ -293,6 +297,10 @@ void DeferredLightingEffect::render(RenderArgs* args) { program = _directionalAmbientSphereLight; locations = _directionalAmbientSphereLightLocations; } + + if (locations->shadowTransformBuffer >= 0) { + batch.setUniformBuffer(locations->shadowTransformBuffer, globalShadow.getBuffer()); + } batch.setPipeline(program); } @@ -480,17 +488,18 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), 1)); slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2)); 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)); + static const int LIGHT_GPU_SLOT = 3; - slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_GPU_SLOT)); static const int ATMOSPHERE_GPU_SLOT = 4; - slotBindings.insert(gpu::Shader::Binding(std::string("atmosphereBufferUnit"), ATMOSPHERE_GPU_SLOT)); static const int DEFERRED_TRANSFORM_BUFFER_SLOT = 2; + slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_GPU_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("atmosphereBufferUnit"), ATMOSPHERE_GPU_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), DEFERRED_TRANSFORM_BUFFER_SLOT)); gpu::Shader::makeProgram(*program, slotBindings); - locations->radius = program->getUniforms().findLocation("radius"); locations->ambientSphere = program->getUniforms().findLocation("ambientSphere.L00"); @@ -500,6 +509,7 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); locations->atmosphereBufferUnit = program->getBuffers().findLocation("atmosphereBufferUnit"); locations->deferredTransformBuffer = program->getBuffers().findLocation("deferredTransformBuffer"); + locations->shadowTransformBuffer = program->getBuffers().findLocation("shadowTransformBuffer"); auto state = std::make_shared(); state->setColorWriteMask(true, true, true, false); From 2b27e48bf9395a0dd3429bcf4534f4712c52f774 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 14 Jan 2016 15:46:59 -0800 Subject: [PATCH 181/215] Update shadow shaders --- libraries/render-utils/src/Shadow.slh | 101 +++++++----------- .../src/directional_ambient_light.slf | 10 +- .../render-utils/src/directional_light.slf | 10 +- .../src/directional_skybox_light.slf | 10 +- 4 files changed, 59 insertions(+), 72 deletions(-) diff --git a/libraries/render-utils/src/Shadow.slh b/libraries/render-utils/src/Shadow.slh index 525abf60b7..850be95cde 100755 --- a/libraries/render-utils/src/Shadow.slh +++ b/libraries/render-utils/src/Shadow.slh @@ -14,35 +14,46 @@ // the shadow texture uniform sampler2DShadow shadowMap; -struct EyePlanes { - vec4 _S[1]; - vec4 _T[1]; - vec4 _R[1]; - vec4 _Q[1]; +struct ShadowTransform { + mat4 projection; + mat4 view; + + float bias; + float scale; }; -uniform eyePlanes { - EyePlanes _eyePlanes; +uniform shadowTransformBuffer { + ShadowTransform _shadowTransform; }; -EyePlanes getEyePlanes() { - return _eyePlanes; +mat4 getShadowView() { + return _shadowTransform.view; } +mat4 getShadowProjection() { + return _shadowTransform.projection; +} + +float getShadowScale() { + return 1.0; + //_shadowTransform.scale; +} + +// Compute the texture coordinates from world coordinates +vec4 evalShadowTexcoord(vec4 position) { + mat4 bias = mat4( + 0.5, 0.0, 0.0, 0.0, + 0.0, 0.5, 0.0, 0.0, + 0.0, 0.0, 0.5, 0.0, + 0.5, 0.5, 0.5, 1.0); + return bias * getShadowProjection() * inverse(getShadowView()) * position; +} // Fetching it -float fetchShadow(vec3 texcoord) { - return texture(shadowMap, texcoord); +float fetchShadow(vec3 shadowTexcoord) { + return texture(shadowMap, shadowTexcoord); } -// the distances to the cascade sections -uniform vec3 shadowDistances; - -// the inverse of the size of the shadow map -uniform float shadowScale; - -uniform mat4 shadowMatrices[4]; - vec2 samples[8] = vec2[8]( vec2(-2.0, -2.0), vec2(2.0, -2.0), @@ -54,28 +65,10 @@ vec2 samples[8] = vec2[8]( vec2(0.0, -1.0) ); -vec4 evalShadowTexcoord(vec4 position) { - // compute the corresponding texture coordinates - EyePlanes eyePlanes = getEyePlanes(); - vec3 shadowTexcoord = vec3(dot(eyePlanes._S[0], position), dot(eyePlanes._T[0], position), dot(eyePlanes._R[0], position)); - return vec4(shadowTexcoord, 0.0); -} - -vec4 evalCascadedShadowTexcoord(vec4 position) { - EyePlanes eyePlanes = getEyePlanes(); - - // compute the index of the cascade to use and the corresponding texture coordinates - int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0))); - vec3 shadowTexcoord = vec3( - dot(eyePlanes._S[shadowIndex], position), - dot(eyePlanes._T[shadowIndex], position), - dot(eyePlanes._R[shadowIndex], position)); - - return vec4(shadowTexcoord, shadowIndex); -} - float evalShadowAttenuationPCF(vec4 shadowTexcoord) { float radiusScale = (shadowTexcoord.w + 1.0); + float shadowScale = getShadowScale(); + float shadowAttenuation = (0.25 * ( fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[0], 0.0)) + fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[1], 0.0)) + @@ -98,36 +91,24 @@ float evalShadowAttenuationPCF(vec4 shadowTexcoord) { float evalShadowAttenuationBasic(vec4 shadowTexcoord) { float radiusScale = 0.5; + float shadowScale = getShadowScale(); + float shadowAttenuation = (0.25 * ( fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[0], 0.0)) + fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[1], 0.0)) + fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[2], 0.0)) + fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[3], 0.0)) )); + return shadowAttenuation; } -float evalShadowAttenuation(vec4 shadowTexcoord) { - return evalShadowAttenuationBasic(shadowTexcoord); +float evalShadowAttenuation(vec4 position) { + vec4 shadowTexcoord = evalShadowTexcoord(position); + + return fetchShadow(shadowTexcoord.xyz); + // return evalShadowAttenuationBasic(shadowTexcoord); + // return evalShadowAttenuationPCF(shadowTexcoord); } - - <@endif@> diff --git a/libraries/render-utils/src/directional_ambient_light.slf b/libraries/render-utils/src/directional_ambient_light.slf index a905dbdfd5..5b936f566f 100755 --- a/libraries/render-utils/src/directional_ambient_light.slf +++ b/libraries/render-utils/src/directional_ambient_light.slf @@ -12,9 +12,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// Everything about deferred buffer +<@include Shadow.slh@> <@include DeferredBuffer.slh@> - <@include DeferredGlobalLight.slh@> <$declareEvalLightmappedColor()$> @@ -27,10 +26,13 @@ void main(void) { DeferredTransform deferredTransform = getDeferredTransform(); DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); + vec4 worldPos = deferredTransform.viewInverse * vec4(frag.position.xyz, 1.0); + float shadowAttenuation = evalShadowAttenuation(worldPos); + if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { vec3 color = evalLightmappedColor( deferredTransform.viewInverse, - 1.0, + shadowAttenuation, frag.normal, frag.diffuse, frag.specularVal.xyz); @@ -38,7 +40,7 @@ void main(void) { } else { vec3 color = evalAmbientSphereGlobalColor( deferredTransform.viewInverse, - 1.0, + shadowAttenuation, frag.position.xyz, frag.normal, frag.diffuse, diff --git a/libraries/render-utils/src/directional_light.slf b/libraries/render-utils/src/directional_light.slf index eff40df255..f057f9cc35 100644 --- a/libraries/render-utils/src/directional_light.slf +++ b/libraries/render-utils/src/directional_light.slf @@ -12,9 +12,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// Everything about deferred buffer +<@include Shadow.slh@> <@include DeferredBuffer.slh@> - <@include DeferredGlobalLight.slh@> <$declareEvalLightmappedColor()$> @@ -27,11 +26,14 @@ void main(void) { DeferredTransform deferredTransform = getDeferredTransform(); DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); + vec4 worldPos = deferredTransform.viewInverse * vec4(frag.position.xyz, 1.0); + float shadowAttenuation = evalShadowAttenuation(worldPos); + // Light mapped or not ? if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { vec3 color = evalLightmappedColor( deferredTransform.viewInverse, - 1.0, + shadowAttenuation, frag.normal, frag.diffuse, frag.specularVal.xyz); @@ -39,7 +41,7 @@ void main(void) { } else { vec3 color = evalAmbientGlobalColor( deferredTransform.viewInverse, - 1.0, + shadowAttenuation, frag.position.xyz, frag.normal, frag.diffuse, diff --git a/libraries/render-utils/src/directional_skybox_light.slf b/libraries/render-utils/src/directional_skybox_light.slf index ca3efef047..871cb32337 100755 --- a/libraries/render-utils/src/directional_skybox_light.slf +++ b/libraries/render-utils/src/directional_skybox_light.slf @@ -12,9 +12,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html //!> -// Everything about deferred buffer +<@include Shadow.slh@> <@include DeferredBuffer.slh@> - <@include DeferredGlobalLight.slh@> <$declareEvalLightmappedColor()$> @@ -27,11 +26,14 @@ void main(void) { DeferredTransform deferredTransform = getDeferredTransform(); DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); + vec4 worldPos = deferredTransform.viewInverse * vec4(frag.position.xyz, 1.0); + float shadowAttenuation = evalShadowAttenuation(worldPos); + // Light mapped or not ? if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { vec3 color = evalLightmappedColor( deferredTransform.viewInverse, - 1.0, + shadowAttenuation, frag.normal, frag.diffuse, frag.specularVal.xyz); @@ -39,7 +41,7 @@ void main(void) { } else { vec3 color = evalSkyboxGlobalColor( deferredTransform.viewInverse, - 1.0, + shadowAttenuation, frag.position.xyz, frag.normal, frag.diffuse, From b2c9cf7452af3b2fa19f35299e1a8e7e779b95dd Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 15 Jan 2016 13:30:29 -0800 Subject: [PATCH 182/215] Fit shadowmap to viewFrustum better --- libraries/render-utils/src/LightStage.cpp | 2 +- libraries/render-utils/src/RenderShadowTask.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 2217de6f28..72b2ec478f 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -21,7 +21,7 @@ LightStage::Shadow::Shadow(model::LightPointer light) : _light{ light}, _frustum } void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float nearDepth, float farDepth) { - assert(nearDepth >= 0 && farDepth > 0); + assert(nearDepth < farDepth); // Orient the keylight frustum const auto& direction = glm::normalize(_light->getDirection()); diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 5735fe8318..148b08d4ef 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -115,8 +115,7 @@ void RenderShadowTask::run(const SceneContextPointer& sceneContext, const Render auto nearClip = viewFrustum->getNearClip(); const int SHADOW_NEAR_DEPTH = -1; const int SHADOW_FAR_DEPTH = 20; - globalLight->shadow.setKeylightFrustum(viewFrustum, - glm::max(0.0f, nearClip - SHADOW_NEAR_DEPTH), nearClip + SHADOW_FAR_DEPTH); + globalLight->shadow.setKeylightFrustum(viewFrustum, nearClip + SHADOW_NEAR_DEPTH, nearClip + SHADOW_FAR_DEPTH); // Set the keylight frustum args->_viewFrustum = globalLight->shadow.getFrustum().get(); From 562c909ad8eb22fe4c765ed3240b36d61b52465e Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 15 Jan 2016 15:47:01 -0800 Subject: [PATCH 183/215] Update shadow shaders --- libraries/render-utils/src/LightStage.cpp | 4 +- libraries/render-utils/src/LightStage.h | 8 +-- .../render-utils/src/RenderShadowTask.cpp | 2 +- libraries/render-utils/src/Shadow.slh | 63 ++++++++----------- 4 files changed, 33 insertions(+), 44 deletions(-) diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 72b2ec478f..0392f16594 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -16,7 +16,7 @@ LightStage::Shadow::Shadow(model::LightPointer light) : _light{ light}, _frustum{ std::make_shared() } { framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(MAP_SIZE)); map = framebuffer->getDepthStencilBuffer(); - Schema schema{glm::mat4(), glm::mat4(), 0, MAP_SIZE}; + Schema schema; _schemaBuffer = std::make_shared(sizeof(Schema), (const gpu::Byte*) &schema); } @@ -72,7 +72,7 @@ void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float near // Update the buffer _schemaBuffer.edit().projection = ortho; - _schemaBuffer.edit().view = view.getMatrix(); + _schemaBuffer.edit().viewInverse = viewInverse.getMatrix(); } const glm::mat4& LightStage::Shadow::getView() const { diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index 10c8227ff3..82d4784c90 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -24,7 +24,7 @@ public: class Shadow { public: using UniformBufferView = gpu::BufferView; - const int MAP_SIZE = 2048; + static const int MAP_SIZE = 2048; Shadow(model::LightPointer light); @@ -46,10 +46,10 @@ public: class Schema { public: glm::mat4 projection; - glm::mat4 view; + glm::mat4 viewInverse; - glm::float32 bias; - glm::float32 scale; + glm::float32 bias = 0.005f; + glm::float32 scale = 1 / MAP_SIZE; }; UniformBufferView _schemaBuffer = nullptr; }; diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 148b08d4ef..c889fae110 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -113,7 +113,7 @@ void RenderShadowTask::run(const SceneContextPointer& sceneContext, const Render ViewFrustum* viewFrustum = args->_viewFrustum; auto nearClip = viewFrustum->getNearClip(); - const int SHADOW_NEAR_DEPTH = -1; + const int SHADOW_NEAR_DEPTH = -2; const int SHADOW_FAR_DEPTH = 20; globalLight->shadow.setKeylightFrustum(viewFrustum, nearClip + SHADOW_NEAR_DEPTH, nearClip + SHADOW_FAR_DEPTH); diff --git a/libraries/render-utils/src/Shadow.slh b/libraries/render-utils/src/Shadow.slh index 850be95cde..c0ca4be0fe 100755 --- a/libraries/render-utils/src/Shadow.slh +++ b/libraries/render-utils/src/Shadow.slh @@ -16,7 +16,7 @@ uniform sampler2DShadow shadowMap; struct ShadowTransform { mat4 projection; - mat4 view; + mat4 viewInverse; float bias; float scale; @@ -26,8 +26,8 @@ uniform shadowTransformBuffer { ShadowTransform _shadowTransform; }; -mat4 getShadowView() { - return _shadowTransform.view; +mat4 getShadowViewInverse() { + return _shadowTransform.viewInverse; } mat4 getShadowProjection() { @@ -35,21 +35,27 @@ mat4 getShadowProjection() { } float getShadowScale() { - return 1.0; - //_shadowTransform.scale; + return _shadowTransform.scale; +} + +float getShadowBias() { + return _shadowTransform.bias; } // Compute the texture coordinates from world coordinates vec4 evalShadowTexcoord(vec4 position) { - mat4 bias = mat4( + mat4 biasMatrix = mat4( 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, - 0.0, 0.0, 0.5, 0.0, + 0.0, 0.0, 0.5, 0.0, 0.5, 0.5, 0.5, 1.0); - return bias * getShadowProjection() * inverse(getShadowView()) * position; + float bias = -getShadowBias(); + + vec4 shadowCoord = biasMatrix * getShadowProjection() * getShadowViewInverse() * position; + return vec4(shadowCoord.xy, shadowCoord.z + bias, 1.0); } -// Fetching it +// Sample the shadowMap with PCF (built-in) float fetchShadow(vec3 shadowTexcoord) { return texture(shadowMap, shadowTexcoord); } @@ -65,50 +71,33 @@ vec2 samples[8] = vec2[8]( vec2(0.0, -1.0) ); -float evalShadowAttenuationPCF(vec4 shadowTexcoord) { - float radiusScale = (shadowTexcoord.w + 1.0); +float evalShadowAttenuationSampling(vec4 shadowTexcoord) { float shadowScale = getShadowScale(); float shadowAttenuation = (0.25 * ( - fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[0], 0.0)) + - fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[1], 0.0)) + - fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[2], 0.0)) + - fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[3], 0.0)) + fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[0], 0.0)) + + fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[1], 0.0)) + + fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[2], 0.0)) + + fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[3], 0.0)) )); + // Check for early bailing if ((shadowAttenuation > 0) && (shadowAttenuation < 1.0)) { - radiusScale *= 0.5; shadowAttenuation = 0.5 * shadowAttenuation + (0.125 * ( - fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[4], 0.0)) + - fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[5], 0.0)) + - fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[6], 0.0)) + - fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[7], 0.0)) + fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[4], 0.0)) + + fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[5], 0.0)) + + fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[6], 0.0)) + + fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[7], 0.0)) )); } return shadowAttenuation; } -float evalShadowAttenuationBasic(vec4 shadowTexcoord) { - float radiusScale = 0.5; - float shadowScale = getShadowScale(); - - float shadowAttenuation = (0.25 * ( - fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[0], 0.0)) + - fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[1], 0.0)) + - fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[2], 0.0)) + - fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[3], 0.0)) - )); - - return shadowAttenuation; -} - float evalShadowAttenuation(vec4 position) { vec4 shadowTexcoord = evalShadowTexcoord(position); - return fetchShadow(shadowTexcoord.xyz); - // return evalShadowAttenuationBasic(shadowTexcoord); - // return evalShadowAttenuationPCF(shadowTexcoord); + return evalShadowAttenuationSampling(shadowTexcoord); } <@endif@> From f3a5be9ec0e12cb53d096e6173e3d30052c6d404 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 15 Jan 2016 16:12:37 -0800 Subject: [PATCH 184/215] Decrease shadowMap res to 1024 --- libraries/render-utils/src/LightStage.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index 82d4784c90..f776d8d817 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -24,7 +24,7 @@ public: class Shadow { public: using UniformBufferView = gpu::BufferView; - static const int MAP_SIZE = 2048; + static const int MAP_SIZE = 1024; Shadow(model::LightPointer light); From 625eee2b9c2c6b836ca54bdcebc410380e955d87 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 15 Jan 2016 16:15:44 -0800 Subject: [PATCH 185/215] Clean RenderShadowTask ctor --- libraries/render-utils/src/RenderShadowTask.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index c889fae110..f58d47683e 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -81,16 +81,16 @@ RenderShadowTask::RenderShadowTask() : Task() { } // CPU: Fetch shadow-casting opaques - addJob("FetchShadowMap"); + auto fetchedItems = addJob("FetchShadowMap"); // CPU: Cull against KeyLight frustum (nearby viewing camera) - addJob>("CullShadowMap", _jobs.back().getOutput()); + auto culledItems = addJob>("CullShadowMap", fetchedItems); // CPU: Sort front to back - addJob("DepthSortShadowMap", _jobs.back().getOutput()); + auto shadowItems = addJob("DepthSortShadowMap", culledItems); // GPU: Render to shadow map - addJob("RenderShadowMap", _jobs.back().getOutput(), shapePlumber); + addJob("RenderShadowMap", shadowItems, shapePlumber); } void RenderShadowTask::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { From 4bbf206f643cb4de608757d092f157e5cb28cd33 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 15 Jan 2016 16:34:30 -0800 Subject: [PATCH 186/215] Clean up DrawTask --- libraries/render/src/render/DrawTask.cpp | 55 +++++++++++------------- libraries/render/src/render/DrawTask.h | 13 ++---- 2 files changed, 30 insertions(+), 38 deletions(-) diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 88aeb55ffc..93cb42c2fd 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -18,7 +18,6 @@ #include #include - using namespace render; void render::cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { @@ -62,27 +61,6 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont renderDetails->_rendered += outItems.size(); } - -void FetchItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems) { - auto& scene = sceneContext->_scene; - - outItems.clear(); - - const auto& bucket = scene->getMasterBucket(); - const auto& items = bucket.find(_filter); - if (items != bucket.end()) { - outItems.reserve(items->second.size()); - for (auto& id : items->second) { - auto& item = scene->getItem(id); - outItems.emplace_back(ItemIDAndBounds(id, item.getBound())); - } - } - - if (_probeNumItems) { - _probeNumItems(renderContext, (int)outItems.size()); - } -} - struct ItemBound { float _centerDepth = 0.0f; float _nearDepth = 0.0f; @@ -146,13 +124,6 @@ void render::depthSortItems(const SceneContextPointer& sceneContext, const Rende } } - -void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { - outItems.clear(); - outItems.reserve(inItems.size()); - depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems); -} - void render::renderLights(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) { auto& scene = sceneContext->_scene; RenderArgs* args = renderContext->getArgs(); @@ -190,6 +161,32 @@ void render::renderShapes(const SceneContextPointer& sceneContext, const RenderC } } +void FetchItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems) { + auto& scene = sceneContext->_scene; + + outItems.clear(); + + const auto& bucket = scene->getMasterBucket(); + const auto& items = bucket.find(_filter); + if (items != bucket.end()) { + outItems.reserve(items->second.size()); + for (auto& id : items->second) { + auto& item = scene->getItem(id); + outItems.emplace_back(ItemIDAndBounds(id, item.getBound())); + } + } + + if (_probeNumItems) { + _probeNumItems(renderContext, (int)outItems.size()); + } +} + +void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { + outItems.clear(); + outItems.reserve(inItems.size()); + depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems); +} + void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { assert(renderContext->getArgs()); assert(renderContext->getArgs()->_viewFrustum); diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 3c2c0973b2..e043d5f69e 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -19,12 +19,11 @@ namespace render { -void cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); -void depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); +void cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); +void depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); void renderLights(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems); void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); - class FetchItems { public: typedef std::function ProbeNumItems; @@ -36,7 +35,6 @@ public: ProbeNumItems _probeNumItems; void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems); - using JobModel = Task::Job::ModelO; }; @@ -55,19 +53,16 @@ public: class DepthSortItems { public: - bool _frontToBack = true; - + bool _frontToBack; DepthSortItems(bool frontToBack = true) : _frontToBack(frontToBack) {} - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); - + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); using JobModel = Task::Job::ModelIO; }; class DrawLight { public: void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); - using JobModel = Task::Job::Model; }; From 331d32ef78ea3a8a5b7cf04d375b05d22002ea96 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 15 Jan 2016 17:17:00 -0800 Subject: [PATCH 187/215] Add render Jobs for Shape sorting --- libraries/render/src/render/DrawTask.cpp | 34 ++++++++++++++++++++++-- libraries/render/src/render/DrawTask.h | 15 +++++++++++ libraries/render/src/render/Scene.h | 6 ++++- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 93cb42c2fd..a2af639c02 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -182,8 +182,6 @@ void FetchItems::run(const SceneContextPointer& sceneContext, const RenderContex } void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { - outItems.clear(); - outItems.reserve(inItems.size()); depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems); } @@ -215,3 +213,35 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext args->_batch = nullptr; }); } + +void PipelineSortShapes::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ShapesIDsBounds& outShapes) { + auto& scene = sceneContext->_scene; + outShapes.clear(); + + for (const auto& item : inItems) { + auto key = scene->getItem(item.id).getShapeKey(); + auto outItems = outShapes.find(key); + if (outItems == outShapes.end()) { + outItems = outShapes.insert(std::make_pair(key, ItemIDsBounds{})).first; + outItems->second.reserve(inItems.size()); + } + + outItems->second.push_back(item); + } + + for (auto& items : outShapes) { + items.second.shrink_to_fit(); + } +} + +void DepthSortShapes::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapesIDsBounds& inShapes, ShapesIDsBounds& outShapes) { + for (auto& pipeline : inShapes) { + auto& inItems = pipeline.second; + auto outItems = outShapes.find(pipeline.first); + if (outItems == outShapes.end()) { + outItems = outShapes.insert(std::make_pair(pipeline.first, ItemIDsBounds{})).first; + } + + depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems->second); + } +} \ No newline at end of file diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index e043d5f69e..47ce5c8476 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -66,6 +66,21 @@ public: using JobModel = Task::Job::Model; }; +class PipelineSortShapes { +public: + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ShapesIDsBounds& outShapes); + using JobModel = Task::Job::ModelIO; +}; + +class DepthSortShapes { +public: + bool _frontToBack; + DepthSortShapes(bool frontToBack = true) : _frontToBack(frontToBack) {} + + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapesIDsBounds& inShapes, ShapesIDsBounds& outShapes); + using JobModel = Task::Job::ModelIO; +}; + } #endif // hifi_render_DrawTask_h diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index 567e054a8a..e28225a899 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -432,7 +432,11 @@ public: AABox bounds; }; -typedef std::vector< ItemIDAndBounds > ItemIDsBounds; +// A list of items to be passed between rendering jobs +using ItemIDsBounds = std::vector; + +// A map of items by ShapeKey to optimize rendering pipeline assignments +using ShapesIDsBounds = std::unordered_map; // A map of ItemIDSets allowing to create bucket lists of items which are filtering correctly From 7fd20bb036ea05458c9597161399dbf9602a7d7b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 15 Jan 2016 17:43:17 -0800 Subject: [PATCH 188/215] Set shadow pipelines manually to avoid duplication --- .../render-utils/src/RenderShadowTask.cpp | 31 ++++++++++++++++--- libraries/render-utils/src/RenderShadowTask.h | 4 +-- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index f58d47683e..7ccc4bacda 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -27,7 +27,7 @@ using namespace render; void RenderShadowMap::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, - const render::ItemIDsBounds& inItems) { + const render::ShapesIDsBounds& inShapes) { assert(renderContext->getArgs()); assert(renderContext->getArgs()->_viewFrustum); @@ -52,7 +52,27 @@ void RenderShadowMap::run(const render::SceneContextPointer& sceneContext, const batch.setProjectionTransform(shadow.getProjection()); batch.setViewTransform(shadow.getView()); - renderShapes(sceneContext, renderContext, _shapePlumber, inItems); + auto shadowPipeline = _shapePlumber->pickPipeline(args, ShapeKey()); + auto shadowSkinnedPipeline = _shapePlumber->pickPipeline(args, ShapeKey::Builder().withSkinned()); + args->_pipeline = shadowPipeline; + batch.setPipeline(shadowPipeline->pipeline); + + std::vector skinnedShapeKeys{}; + for (auto items : inShapes) { + if (items.first.isSkinned()) { + skinnedShapeKeys.push_back(items.first); + } else { + renderLights(sceneContext, renderContext, items.second); + } + } + + args->_pipeline = shadowSkinnedPipeline; + batch.setPipeline(shadowSkinnedPipeline->pipeline); + for (const auto& key : skinnedShapeKeys) { + renderLights(sceneContext, renderContext, inShapes.at(key)); + } + + args->_pipeline = nullptr; args->_batch = nullptr; }); } @@ -86,11 +106,14 @@ RenderShadowTask::RenderShadowTask() : Task() { // CPU: Cull against KeyLight frustum (nearby viewing camera) auto culledItems = addJob>("CullShadowMap", fetchedItems); + // CPU: Sort by pipeline + auto sortedShapes = addJob("PipelineSortShadowSort", culledItems); + // CPU: Sort front to back - auto shadowItems = addJob("DepthSortShadowMap", culledItems); + auto shadowShapes = addJob("DepthSortShadowMap", sortedShapes); // GPU: Render to shadow map - addJob("RenderShadowMap", shadowItems, shapePlumber); + addJob("RenderShadowMap", shadowShapes, shapePlumber); } void RenderShadowTask::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index 333ed18c84..4853022359 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -24,9 +24,9 @@ class RenderShadowMap { public: RenderShadowMap(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, - const render::ItemIDsBounds& inItems); + const render::ShapesIDsBounds& inShapes); - using JobModel = render::Task::Job::ModelI; + using JobModel = render::Task::Job::ModelI; protected: render::ShapePlumberPointer _shapePlumber; }; From 7f3e102b5ed820206df47f99129cf0adcd4d4489 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 15 Jan 2016 17:47:37 -0800 Subject: [PATCH 189/215] Rename renderLights to renderItems --- libraries/render-utils/src/RenderDeferredTask.cpp | 2 +- libraries/render-utils/src/RenderShadowTask.cpp | 4 ++-- libraries/render/src/render/DrawTask.cpp | 4 ++-- libraries/render/src/render/DrawTask.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index c458a23812..dc3e5c652b 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -391,7 +391,7 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - renderLights(sceneContext, renderContext, inItems); + renderItems(sceneContext, renderContext, inItems); }); args->_batch = nullptr; } diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 7ccc4bacda..b6b9f15f60 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -62,14 +62,14 @@ void RenderShadowMap::run(const render::SceneContextPointer& sceneContext, const if (items.first.isSkinned()) { skinnedShapeKeys.push_back(items.first); } else { - renderLights(sceneContext, renderContext, items.second); + renderItems(sceneContext, renderContext, items.second); } } args->_pipeline = shadowSkinnedPipeline; batch.setPipeline(shadowSkinnedPipeline->pipeline); for (const auto& key : skinnedShapeKeys) { - renderLights(sceneContext, renderContext, inShapes.at(key)); + renderItems(sceneContext, renderContext, inShapes.at(key)); } args->_pipeline = nullptr; diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index a2af639c02..68e1841345 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -124,7 +124,7 @@ void render::depthSortItems(const SceneContextPointer& sceneContext, const Rende } } -void render::renderLights(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) { +void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) { auto& scene = sceneContext->_scene; RenderArgs* args = renderContext->getArgs(); @@ -209,7 +209,7 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; - renderLights(sceneContext, renderContext, culledItems); + renderItems(sceneContext, renderContext, culledItems); args->_batch = nullptr; }); } diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 47ce5c8476..5ad1bbf8d4 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -21,7 +21,7 @@ namespace render { void cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); void depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); -void renderLights(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems); +void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems); void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); class FetchItems { From 51cb9dd05e00a2e9338c72293be9e7a9b72f3f58 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 16 Jan 2016 15:50:33 +1300 Subject: [PATCH 190/215] Fix crash in Running Scripts when edit filter after highlighting script --- libraries/script-engine/src/ScriptsModel.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/script-engine/src/ScriptsModel.cpp b/libraries/script-engine/src/ScriptsModel.cpp index 620184ba10..37b2551f39 100644 --- a/libraries/script-engine/src/ScriptsModel.cpp +++ b/libraries/script-engine/src/ScriptsModel.cpp @@ -99,6 +99,9 @@ QModelIndex ScriptsModel::parent(const QModelIndex& child) const { QVariant ScriptsModel::data(const QModelIndex& index, int role) const { TreeNodeBase* node = getTreeNodeFromIndex(index); + if (!node) { + return QVariant(); + } if (node->getType() == TREE_NODE_TYPE_SCRIPT) { TreeNodeScript* script = static_cast(node); if (role == Qt::DisplayRole) { From 0b71f1e1b839bc40421fa05f1cb6fb66b41a54fb Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 16 Jan 2016 16:29:01 +1300 Subject: [PATCH 191/215] Make filter in Running Scripts window be case-insensitive --- interface/resources/qml/dialogs/RunningScripts.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/dialogs/RunningScripts.qml b/interface/resources/qml/dialogs/RunningScripts.qml index e9b82609d9..6ce99010ed 100644 --- a/interface/resources/qml/dialogs/RunningScripts.qml +++ b/interface/resources/qml/dialogs/RunningScripts.qml @@ -175,7 +175,7 @@ Window { anchors.bottom: treeView.top anchors.bottomMargin: 8 placeholderText: "filter" - onTextChanged: scriptsModel.filterRegExp = new RegExp("^.*" + text + ".*$") + onTextChanged: scriptsModel.filterRegExp = new RegExp("^.*" + text + ".*$", "i") } TreeView { From 746c388f7ad62bb61ae538e4805fc9bf1b632f67 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 14 Jan 2016 11:50:36 -0800 Subject: [PATCH 192/215] Cleanup of QML windowing and message boxes --- interface/resources/qml/AddressBarDialog.qml | 119 +-- interface/resources/qml/Browser.qml | 10 +- interface/resources/qml/ErrorDialog.qml | 112 --- interface/resources/qml/Global.js | 179 ----- interface/resources/qml/InfoView.qml | 17 +- interface/resources/qml/LoginDialog.qml | 78 +- interface/resources/qml/MarketplaceDialog.qml | 45 -- interface/resources/qml/MessageDialog.qml | 337 -------- interface/resources/qml/RecorderDialog.qml | 105 --- interface/resources/qml/Root.qml | 248 +++++- interface/resources/qml/ToolWindow.qml | 30 +- interface/resources/qml/UpdateDialog.qml | 17 +- interface/resources/qml/controls/Button.qml | 20 +- .../resources/qml/controls/DialogBase.qml | 99 --- .../qml/controls/DialogContainer.qml | 65 -- interface/resources/qml/controls/VrDialog.qml | 179 ----- .../resources/qml/dialogs/FileDialog.qml | 382 +++++---- .../resources/qml/dialogs/MessageDialog.qml | 341 ++++++++ .../resources/qml/dialogs/RunningScripts.qml | 2 - interface/resources/qml/hifi/MenuOption.qml | 167 ++++ .../resources/qml/styles/ButtonStyle.qml | 23 - .../resources/qml/styles/HifiPalette.qml | 11 - .../resources/qml/styles/IconButtonStyle.qml | 10 - .../resources/qml/windows/DefaultFrame.qml | 78 +- interface/resources/qml/windows/Fadable.qml | 57 ++ interface/resources/qml/windows/Frame.qml | 95 ++- .../resources/qml/windows/ModalFrame.qml | 29 + interface/resources/qml/windows/Window.qml | 180 ++--- interface/src/Application.cpp | 14 +- .../scripting/WindowScriptingInterface.cpp | 6 +- interface/src/ui/AddressBarDialog.cpp | 4 +- interface/src/ui/DialogsManager.cpp | 4 - interface/src/ui/DialogsManager.h | 1 - interface/src/ui/MarketplaceDialog.cpp | 29 - interface/src/ui/MarketplaceDialog.h | 29 - interface/src/ui/RecorderDialog.cpp | 22 - interface/src/ui/RecorderDialog.h | 28 - libraries/ui/src/MessageDialog.cpp | 119 --- libraries/ui/src/MessageDialog.h | 100 --- libraries/ui/src/OffscreenQmlDialog.cpp | 2 +- libraries/ui/src/OffscreenUi.cpp | 188 +++-- libraries/ui/src/OffscreenUi.h | 67 +- libraries/ui/src/QmlWindowClass.cpp | 14 +- tests/ui/CMakeLists.txt | 34 +- .../resources => tests/ui}/qml/Palettes.qml | 0 tests/ui/qml/StubMenu.qml | 734 ++++++++++++++++++ .../qml/test => tests/ui/qml}/Stubs.qml | 4 +- .../ui}/qml/TestControllers.qml | 1 - .../resources => tests/ui}/qml/TestDialog.qml | 0 .../resources => tests/ui}/qml/TestMenu.qml | 0 .../resources => tests/ui}/qml/TestRoot.qml | 0 tests/ui/qml/{ => controlDemo}/ButtonPage.qml | 0 tests/ui/qml/{ => controlDemo}/InputPage.qml | 0 .../ui/qml/{ => controlDemo}/ProgressPage.qml | 0 tests/ui/{ => qml/controlDemo}/main.qml | 0 tests/ui/qml/main.qml | 336 ++++++++ tests/ui/qmlscratch.pro | 84 ++ tests/ui/src/main.cpp | 674 ++-------------- tests/ui/src/oldmain.cpp | 643 +++++++++++++++ 59 files changed, 3279 insertions(+), 2893 deletions(-) delete mode 100644 interface/resources/qml/ErrorDialog.qml delete mode 100644 interface/resources/qml/Global.js delete mode 100644 interface/resources/qml/MarketplaceDialog.qml delete mode 100644 interface/resources/qml/MessageDialog.qml delete mode 100644 interface/resources/qml/RecorderDialog.qml delete mode 100644 interface/resources/qml/controls/DialogBase.qml delete mode 100644 interface/resources/qml/controls/DialogContainer.qml delete mode 100644 interface/resources/qml/controls/VrDialog.qml create mode 100644 interface/resources/qml/dialogs/MessageDialog.qml create mode 100644 interface/resources/qml/hifi/MenuOption.qml delete mode 100644 interface/resources/qml/styles/ButtonStyle.qml delete mode 100644 interface/resources/qml/styles/HifiPalette.qml delete mode 100644 interface/resources/qml/styles/IconButtonStyle.qml create mode 100644 interface/resources/qml/windows/Fadable.qml create mode 100644 interface/resources/qml/windows/ModalFrame.qml delete mode 100644 interface/src/ui/MarketplaceDialog.cpp delete mode 100644 interface/src/ui/MarketplaceDialog.h delete mode 100644 interface/src/ui/RecorderDialog.cpp delete mode 100644 interface/src/ui/RecorderDialog.h delete mode 100644 libraries/ui/src/MessageDialog.cpp delete mode 100644 libraries/ui/src/MessageDialog.h rename {interface/resources => tests/ui}/qml/Palettes.qml (100%) create mode 100644 tests/ui/qml/StubMenu.qml rename {interface/resources/qml/test => tests/ui/qml}/Stubs.qml (98%) rename {interface/resources => tests/ui}/qml/TestControllers.qml (99%) rename {interface/resources => tests/ui}/qml/TestDialog.qml (100%) rename {interface/resources => tests/ui}/qml/TestMenu.qml (100%) rename {interface/resources => tests/ui}/qml/TestRoot.qml (100%) rename tests/ui/qml/{ => controlDemo}/ButtonPage.qml (100%) rename tests/ui/qml/{ => controlDemo}/InputPage.qml (100%) rename tests/ui/qml/{ => controlDemo}/ProgressPage.qml (100%) rename tests/ui/{ => qml/controlDemo}/main.qml (100%) create mode 100644 tests/ui/qml/main.qml create mode 100644 tests/ui/qmlscratch.pro create mode 100644 tests/ui/src/oldmain.cpp diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index e8ebb5d5fb..4bb8bcb8df 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -12,37 +12,37 @@ import Hifi 1.0 import QtQuick 2.4 import "controls" import "styles" +import "windows" -DialogContainer { +Window { id: root HifiConstants { id: hifi } - z: 1000 - + anchors.centerIn: parent objectName: "AddressBarDialog" - property bool destroyOnInvisible: false - property real scale: 1.25 // Make this dialog a little larger than normal + destroyOnInvisible: false + resizable: false + scale: 1.25 // Make this dialog a little larger than normal - implicitWidth: addressBarDialog.implicitWidth - implicitHeight: addressBarDialog.implicitHeight - - x: parent ? parent.width / 2 - width / 2 : 0 - y: parent ? parent.height / 2 - height / 2 : 0 - property int maximumX: parent ? parent.width - width : 0 - property int maximumY: parent ? parent.height - height : 0 - - - Rectangle { - id: dragRegion - visible: dragMouseArea.containsMouse - } + width: addressBarDialog.implicitWidth + height: addressBarDialog.implicitHeight AddressBarDialog { id: addressBarDialog - z: dragRegion.z + 1 implicitWidth: backgroundImage.width implicitHeight: backgroundImage.height + Timer { + running: root.visible + interval: 500 + repeat: true + onTriggered: { + if (root.enabled && !addressLine.activeFocus) { + addressLine.forceActiveFocus() + } + } + } + Image { id: backgroundImage @@ -52,45 +52,9 @@ DialogContainer { property int inputAreaHeight: 56.0 * root.scale // Height of the background's input area property int inputAreaStep: (height - inputAreaHeight) / 2 - MouseArea { - id: dragMouseArea - // Drag the icon - width: parent.height - height: parent.height - x: 0 - y: 0 - hoverEnabled: true - drag { - target: root - minimumX: -parent.inputAreaStep - minimumY: -parent.inputAreaStep - maximumX: root.parent ? root.maximumX : 0 - maximumY: root.parent ? root.maximumY + parent.inputAreaStep : 0 - } - } - - - - MouseArea { - // Drag the input rectangle - width: parent.width - parent.height - height: parent.inputAreaHeight - x: parent.height - y: parent.inputAreaStep - drag { - target: root - minimumX: -parent.inputAreaStep - minimumY: -parent.inputAreaStep - maximumX: root.parent ? root.maximumX : 0 - maximumY: root.parent ? root.maximumY + parent.inputAreaStep : 0 - } - } - Image { id: backArrow - source: addressBarDialog.backEnabled ? "../images/left-arrow.svg" : "../images/left-arrow-disabled.svg" - anchors { fill: parent leftMargin: parent.height + hifi.layout.spacing + 6 @@ -110,9 +74,7 @@ DialogContainer { Image { id: forwardArrow - source: addressBarDialog.forwardEnabled ? "../images/right-arrow.svg" : "../images/right-arrow-disabled.svg" - anchors { fill: parent leftMargin: parent.height + hifi.layout.spacing * 9 @@ -130,6 +92,7 @@ DialogContainer { } } + // FIXME replace with TextField TextInput { id: addressLine @@ -139,61 +102,35 @@ DialogContainer { rightMargin: hifi.layout.spacing * 2 topMargin: parent.inputAreaStep + hifi.layout.spacing bottomMargin: parent.inputAreaStep + hifi.layout.spacing - } - font.pixelSize: hifi.fonts.pixelSize * root.scale * 0.75 - helperText: "Go to: place, @user, /path, network address" - - onAccepted: { - event.accepted = true // Generates erroneous error in program log, "ReferenceError: event is not defined". - addressBarDialog.loadAddress(addressLine.text) - } } } } - onEnabledChanged: { - if (enabled) { - addressLine.forceActiveFocus() - } - } - - Timer { - running: root.enabled - interval: 500 - repeat: true - onTriggered: { - if (root.enabled && !addressLine.activeFocus) { - addressLine.forceActiveFocus() - } - } - } - onVisibleChanged: { - if (!visible) { + if (visible) { + addressLine.forceActiveFocus() + } else { addressLine.text = "" } } - + function toggleOrGo() { - if (addressLine.text == "") { - enabled = false - } else { + if (addressLine.text != "") { addressBarDialog.loadAddress(addressLine.text) } + root.close(); } Keys.onPressed: { switch (event.key) { case Qt.Key_Escape: case Qt.Key_Back: - if (enabled) { - enabled = false - event.accepted = true - } + root.close() + event.accepted = true break case Qt.Key_Enter: case Qt.Key_Return: diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index dc71eac1e7..39042a4046 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -12,23 +12,23 @@ Window { title: "Browser" resizable: true destroyOnInvisible: true + width: 800 + height: 600 Component.onCompleted: { - enabled = true + visible = true addressBar.text = webview.url } onParentChanged: { - if (visible && enabled) { + if (visible) { addressBar.forceActiveFocus(); addressBar.selectAll() } } Item { - width: 800 - height: 600 - + anchors.fill: parent Rectangle { anchors.left: parent.left anchors.right: parent.right diff --git a/interface/resources/qml/ErrorDialog.qml b/interface/resources/qml/ErrorDialog.qml deleted file mode 100644 index 4ace671c52..0000000000 --- a/interface/resources/qml/ErrorDialog.qml +++ /dev/null @@ -1,112 +0,0 @@ -// -// ErrorDialog.qml -// -// Created by David Rowe on 30 May 2015 -// 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 -// - -import Hifi 1.0 -import QtQuick 2.4 -import "controls" -import "styles" - -DialogContainer { - id: root - HifiConstants { id: hifi } - - Component.onCompleted: { - enabled = true - } - - onParentChanged: { - if (visible && enabled) { - forceActiveFocus() - } - } - - implicitWidth: content.implicitWidth - implicitHeight: content.implicitHeight - - x: parent ? parent.width / 2 - width / 2 : 0 - y: parent ? parent.height / 2 - height / 2 : 0 - - ErrorDialog { - id: content - - implicitWidth: box.width - implicitHeight: icon.height + hifi.layout.spacing * 2 - - Border { - id: box - - width: 512 - color: "#ebebeb" - radius: 2 - border.width: 1 - border.color: "#000000" - - Image { - id: icon - - source: "../images/address-bar-error-icon.svg" - width: 40 - height: 40 - anchors { - left: parent.left - leftMargin: hifi.layout.spacing - verticalCenter: parent.verticalCenter - } - } - - Text { - id: messageText - - font.pixelSize: hifi.fonts.pixelSize * 0.6 - font.weight: Font.Bold - - anchors { - horizontalCenter: parent.horizontalCenter - verticalCenter: parent.verticalCenter - } - - text: content.text - } - - Image { - source: "../images/address-bar-error-close.svg" - width: 20 - height: 20 - anchors { - right: parent.right - rightMargin: hifi.layout.spacing * 2 - verticalCenter: parent.verticalCenter - } - MouseArea { - anchors.fill: parent - cursorShape: "PointingHandCursor" - onClicked: { - content.accept() - } - } - } - } - } - - Keys.onPressed: { - if (!enabled) { - return - } - switch (event.key) { - case Qt.Key_Escape: - case Qt.Key_Back: - case Qt.Key_Enter: - case Qt.Key_Return: - event.accepted = true - content.accept() - break - } - } -} diff --git a/interface/resources/qml/Global.js b/interface/resources/qml/Global.js deleted file mode 100644 index 3ad6352af6..0000000000 --- a/interface/resources/qml/Global.js +++ /dev/null @@ -1,179 +0,0 @@ -var OFFSCREEN_ROOT_OBJECT_NAME = "desktopRoot" -var OFFSCREEN_WINDOW_OBJECT_NAME = "topLevelWindow" - -function findChild(item, name) { - for (var i = 0; i < item.children.length; ++i) { - if (item.children[i].objectName === name) { - return item.children[i]; - } - } - return null; -} - -function findParentMatching(item, predicate) { - while (item) { - if (predicate(item)) { - break; - } - item = item.parent; - } - return item; -} - -function findParentByName(item, name) { - return findParentMatching(item, function(item) { - var testName = name; - var result = (item.name === testName); - return result; - }); -} - -function findRootMenu(item) { - item = getDesktop(item); - return item ? item.rootMenu : null; -} - -function isDesktop(item) { - return item.desktopRoot; -} - -function isTopLevelWindow(item) { - return item.topLevelWindow; -} - -function getTopLevelWindows(item) { - var desktop = getDesktop(item); - var currentWindows = []; - if (!desktop) { - console.log("Could not find desktop for " + item) - return currentWindows; - } - - for (var i = 0; i < desktop.children.length; ++i) { - var child = desktop.children[i]; - if (isTopLevelWindow(child)) { - var windowId = child.toString(); - currentWindows.push(child) - } - } - return currentWindows; -} - - -function getDesktop(item) { - return findParentMatching(item, isDesktop); -} - -function getDesktopWindow(item) { - return findParentMatching(item, isTopLevelWindow) -} - -function closeWindow(item) { - item = findDialog(item); - if (item) { - item.enabled = false - } else { - console.warn("Could not find top level dialog") - } -} - -function findMenuChild(menu, childName) { - if (!menu) { - return null; - } - - if (menu.type !== 2) { - console.warn("Tried to find child of a non-menu"); - return null; - } - - var items = menu.items; - var count = items.length; - for (var i = 0; i < count; ++i) { - var child = items[i]; - var name; - switch (child.type) { - case 2: - name = child.title; - break; - case 1: - name = child.text; - break; - default: - break; - } - - if (name && name === childName) { - return child; - } - } -} - -function findMenu(rootMenu, path) { - if ('string' === typeof(path)) { - path = [ path ] - } - - var currentMenu = rootMenu; - for (var i = 0; currentMenu && i < path.length; ++i) { - currentMenu = findMenuChild(currentMenu, path[i]); - } - - return currentMenu; -} - -function findInRootMenu(item, path) { - return findMenu(findRootMenu(item), path); -} - - -function menuItemsToListModel(parent, items) { - var newListModel = Qt.createQmlObject('import QtQuick 2.5; ListModel {}', parent); - for (var i = 0; i < items.length; ++i) { - var item = items[i]; - switch (item.type) { - case 2: - newListModel.append({"type":item.type, "name": item.title, "item": item}) - break; - case 1: - newListModel.append({"type":item.type, "name": item.text, "item": item}) - break; - case 0: - newListModel.append({"type":item.type, "name": "-----", "item": item}) - break; - } - } - return newListModel; -} - -function raiseWindow(item) { - var targetWindow = getDesktopWindow(item); - if (!targetWindow) { - console.warn("Could not find top level window for " + item); - return; - } - - var desktop = getDesktop(targetWindow); - if (!desktop) { - console.warn("Could not find desktop for window " + targetWindow); - return; - } - - var maxZ = 0; - var minZ = 100000; - var windows = desktop.windows; - windows.sort(function(a, b){ - return a.z - b.z; - }); - var lastZ = -1; - var lastTargetZ = -1; - for (var i = 0; i < windows.length; ++i) { - var window = windows[i]; - if (window.z > lastZ) { - lastZ = window.z; - ++lastTargetZ; - } - window.z = lastTargetZ; - } - targetWindow.z = lastTargetZ + 1; -} diff --git a/interface/resources/qml/InfoView.qml b/interface/resources/qml/InfoView.qml index 75b82342ca..bc268baeb4 100644 --- a/interface/resources/qml/InfoView.qml +++ b/interface/resources/qml/InfoView.qml @@ -1,11 +1,10 @@ +import QtQuick 2.5 import Hifi 1.0 as Hifi -import QtQuick 2.3 -import QtQuick.Controls 1.2 -import QtQuick.Controls.Styles 1.3 -import QtWebEngine 1.1 -import "controls" -VrDialog { +import "controls" +import "windows" as Windows + +Windows.Window { id: root width: 800 height: 800 @@ -13,12 +12,10 @@ VrDialog { Hifi.InfoView { id: infoView - // Fille the client area + // Fill the client area anchors.fill: parent - anchors.margins: parent.margins - anchors.topMargin: parent.topMargin - WebEngineView { + WebView { id: webview objectName: "WebView" anchors.fill: parent diff --git a/interface/resources/qml/LoginDialog.qml b/interface/resources/qml/LoginDialog.qml index 3ce5251771..19f1f736c4 100644 --- a/interface/resources/qml/LoginDialog.qml +++ b/interface/resources/qml/LoginDialog.qml @@ -12,29 +12,23 @@ import Hifi 1.0 import QtQuick 2.4 import "controls" import "styles" +import "windows" -DialogContainer { +Window { id: root HifiConstants { id: hifi } - objectName: "LoginDialog" - - property bool destroyOnInvisible: false - - implicitWidth: loginDialog.implicitWidth - implicitHeight: loginDialog.implicitHeight - - x: parent ? parent.width / 2 - width / 2 : 0 - y: parent ? parent.height / 2 - height / 2 : 0 - property int maximumX: parent ? parent.width - width : 0 - property int maximumY: parent ? parent.height - height : 0 + height: loginDialog.implicitHeight + width: loginDialog.implicitWidth + // FIXME make movable + anchors.centerIn: parent + destroyOnInvisible: false + visible: false LoginDialog { id: loginDialog - implicitWidth: backgroundRectangle.width implicitHeight: backgroundRectangle.height - readonly property int inputWidth: 500 readonly property int inputHeight: 60 readonly property int borderWidth: 30 @@ -47,46 +41,8 @@ DialogContainer { width: loginDialog.inputWidth + loginDialog.borderWidth * 2 height: loginDialog.inputHeight * 6 + loginDialog.closeMargin * 2 radius: loginDialog.closeMargin * 2 - color: "#2c86b1" opacity: 0.85 - - MouseArea { - width: parent.width - height: parent.height - anchors { - horizontalCenter: parent.horizontalCenter - verticalCenter: parent.verticalCenter - } - drag { - target: root - minimumX: 0 - minimumY: 0 - maximumX: root.parent ? root.maximumX : 0 - maximumY: root.parent ? root.maximumY : 0 - } - } - } - - Image { - id: closeIcon - source: "../images/login-close.svg" - width: 20 - height: 20 - anchors { - top: backgroundRectangle.top - right: backgroundRectangle.right - topMargin: loginDialog.closeMargin - rightMargin: loginDialog.closeMargin - } - - MouseArea { - anchors.fill: parent - cursorShape: "PointingHandCursor" - onClicked: { - root.enabled = false - } - } } Column { @@ -324,18 +280,13 @@ DialogContainer { } } - onOpacityChanged: { - // Set focus once animation is completed so that focus is set at start-up when not logged in - if (opacity == 1.0) { - username.forceActiveFocus() - } - } - onVisibleChanged: { if (!visible) { username.text = "" password.text = "" loginDialog.statusText = "" + } else { + username.forceActiveFocus() } } @@ -343,11 +294,10 @@ DialogContainer { switch (event.key) { case Qt.Key_Escape: case Qt.Key_Back: - if (enabled) { - enabled = false - event.accepted = true - } - break + root.close(); + event.accepted = true; + break; + case Qt.Key_Enter: case Qt.Key_Return: if (username.activeFocus) { diff --git a/interface/resources/qml/MarketplaceDialog.qml b/interface/resources/qml/MarketplaceDialog.qml deleted file mode 100644 index 3a66c5340f..0000000000 --- a/interface/resources/qml/MarketplaceDialog.qml +++ /dev/null @@ -1,45 +0,0 @@ -import Hifi 1.0 -import QtQuick 2.3 -import QtQuick.Controls 1.2 -import QtQuick.Controls.Styles 1.3 -import QtWebEngine 1.1 -import "controls" - -VrDialog { - title: "Test Dlg" - id: testDialog - objectName: "Browser" - width: 720 - height: 720 - resizable: true - - MarketplaceDialog { - id: marketplaceDialog - } - - Item { - id: clientArea - // The client area - anchors.fill: parent - anchors.margins: parent.margins - anchors.topMargin: parent.topMargin - - WebEngineView { - objectName: "WebView" - id: webview - url: "https://metaverse.highfidelity.com/marketplace" - anchors.fill: parent - onNavigationRequested: { - console.log(request.url) - if (!marketplaceDialog.navigationRequested(request.url)) { - console.log("Application absorbed the request") - request.action = WebView.IgnoreRequest; - return; - } - console.log("Application passed on the request") - request.action = WebView.AcceptRequest; - return; - } - } - } -} diff --git a/interface/resources/qml/MessageDialog.qml b/interface/resources/qml/MessageDialog.qml deleted file mode 100644 index 73fb135ac4..0000000000 --- a/interface/resources/qml/MessageDialog.qml +++ /dev/null @@ -1,337 +0,0 @@ -import Hifi 1.0 as Hifi -import QtQuick 2.2 -import QtQuick.Controls 1.2 -import QtQuick.Dialogs 1.2 -import "controls" -import "styles" - -VrDialog { - id: root - HifiConstants { id: hifi } - property real spacing: hifi.layout.spacing - property real outerSpacing: hifi.layout.spacing * 2 - - destroyOnCloseButton: true - destroyOnInvisible: true - contentImplicitWidth: content.implicitWidth - contentImplicitHeight: content.implicitHeight - - Component.onCompleted: { - enabled = true - } - - onParentChanged: { - if (visible && enabled) { - forceActiveFocus(); - } - } - - Hifi.MessageDialog { - id: content - clip: true - - x: root.clientX - y: root.clientY - implicitHeight: contentColumn.implicitHeight + outerSpacing * 2 - implicitWidth: mainText.implicitWidth + outerSpacing * 2 - - Component.onCompleted: { - root.title = title - } - - onTitleChanged: { - root.title = title - } - - Column { - anchors.fill: parent - anchors.margins: 8 - id: contentColumn - spacing: root.outerSpacing - - Item { - width: parent.width - height: Math.max(icon.height, mainText.height + informativeText.height + root.spacing) - - FontAwesome { - id: icon - width: content.icon ? 48 : 0 - height: content.icon ? 48 : 0 - visible: content.icon ? true : false - font.pixelSize: 48 - verticalAlignment: Text.AlignTop - horizontalAlignment: Text.AlignLeft - color: iconColor() - text: iconSymbol() - - function iconSymbol() { - switch (content.icon) { - case Hifi.MessageDialog.Information: - return "\uF05A" - case Hifi.MessageDialog.Question: - return "\uF059" - case Hifi.MessageDialog.Warning: - return "\uF071" - case Hifi.MessageDialog.Critical: - return "\uF057" - default: - break; - } - return content.icon; - } - function iconColor() { - switch (content.icon) { - case Hifi.MessageDialog.Information: - case Hifi.MessageDialog.Question: - return "blue" - case Hifi.MessageDialog.Warning: - case Hifi.MessageDialog.Critical: - return "red" - default: - break - } - return "black" - } - } - - Text { - id: mainText - anchors { - left: icon.right - leftMargin: root.spacing - right: parent.right - } - text: content.text - font.pointSize: 14 - font.weight: Font.Bold - wrapMode: Text.WordWrap - } - - Text { - id: informativeText - anchors { - left: icon.right - right: parent.right - top: mainText.bottom - leftMargin: root.spacing - topMargin: root.spacing - } - text: content.informativeText - font.pointSize: 14 - wrapMode: Text.WordWrap - } - } - - - Flow { - id: buttons - spacing: root.spacing - layoutDirection: Qt.RightToLeft - width: parent.width - Button { - id: okButton - text: qsTr("OK") - onClicked: content.click(StandardButton.Ok) - visible: content.standardButtons & StandardButton.Ok - } - Button { - id: openButton - text: qsTr("Open") - onClicked: content.click(StandardButton.Open) - visible: content.standardButtons & StandardButton.Open - } - Button { - id: saveButton - text: qsTr("Save") - onClicked: content.click(StandardButton.Save) - visible: content.standardButtons & StandardButton.Save - } - Button { - id: saveAllButton - text: qsTr("Save All") - onClicked: content.click(StandardButton.SaveAll) - visible: content.standardButtons & StandardButton.SaveAll - } - Button { - id: retryButton - text: qsTr("Retry") - onClicked: content.click(StandardButton.Retry) - visible: content.standardButtons & StandardButton.Retry - } - Button { - id: ignoreButton - text: qsTr("Ignore") - onClicked: content.click(StandardButton.Ignore) - visible: content.standardButtons & StandardButton.Ignore - } - Button { - id: applyButton - text: qsTr("Apply") - onClicked: content.click(StandardButton.Apply) - visible: content.standardButtons & StandardButton.Apply - } - Button { - id: yesButton - text: qsTr("Yes") - onClicked: content.click(StandardButton.Yes) - visible: content.standardButtons & StandardButton.Yes - } - Button { - id: yesAllButton - text: qsTr("Yes to All") - onClicked: content.click(StandardButton.YesToAll) - visible: content.standardButtons & StandardButton.YesToAll - } - Button { - id: noButton - text: qsTr("No") - onClicked: content.click(StandardButton.No) - visible: content.standardButtons & StandardButton.No - } - Button { - id: noAllButton - text: qsTr("No to All") - onClicked: content.click(StandardButton.NoToAll) - visible: content.standardButtons & StandardButton.NoToAll - } - Button { - id: discardButton - text: qsTr("Discard") - onClicked: content.click(StandardButton.Discard) - visible: content.standardButtons & StandardButton.Discard - } - Button { - id: resetButton - text: qsTr("Reset") - onClicked: content.click(StandardButton.Reset) - visible: content.standardButtons & StandardButton.Reset - } - Button { - id: restoreDefaultsButton - text: qsTr("Restore Defaults") - onClicked: content.click(StandardButton.RestoreDefaults) - visible: content.standardButtons & StandardButton.RestoreDefaults - } - Button { - id: cancelButton - text: qsTr("Cancel") - onClicked: content.click(StandardButton.Cancel) - visible: content.standardButtons & StandardButton.Cancel - } - Button { - id: abortButton - text: qsTr("Abort") - onClicked: content.click(StandardButton.Abort) - visible: content.standardButtons & StandardButton.Abort - } - Button { - id: closeButton - text: qsTr("Close") - onClicked: content.click(StandardButton.Close) - visible: content.standardButtons & StandardButton.Close - } - Button { - id: moreButton - text: qsTr("Show Details...") - onClicked: content.state = (content.state === "" ? "expanded" : "") - visible: content.detailedText.length > 0 - } - Button { - id: helpButton - text: qsTr("Help") - onClicked: content.click(StandardButton.Help) - visible: content.standardButtons & StandardButton.Help - } - } - } - - Item { - id: details - width: parent.width - implicitHeight: detailedText.implicitHeight + root.spacing - height: 0 - clip: true - - anchors { - left: parent.left - right: parent.right - top: contentColumn.bottom - topMargin: root.spacing - leftMargin: root.outerSpacing - rightMargin: root.outerSpacing - } - - Flickable { - id: flickable - contentHeight: detailedText.height - anchors.fill: parent - anchors.topMargin: root.spacing - anchors.bottomMargin: root.outerSpacing - TextEdit { - id: detailedText - text: content.detailedText - width: details.width - wrapMode: Text.WordWrap - readOnly: true - selectByMouse: true - } - } - } - - states: [ - State { - name: "expanded" - PropertyChanges { - target: details - height: root.height - contentColumn.height - root.spacing - root.outerSpacing - } - PropertyChanges { - target: content - implicitHeight: contentColumn.implicitHeight + root.spacing * 2 + - detailedText.implicitHeight + root.outerSpacing * 2 - } - PropertyChanges { - target: moreButton - text: qsTr("Hide Details") - } - } - ] - } - - - Keys.onPressed: { - if (!enabled) { - return - } - - if (event.modifiers === Qt.ControlModifier) - switch (event.key) { - case Qt.Key_A: - event.accepted = true - detailedText.selectAll() - break - case Qt.Key_C: - event.accepted = true - detailedText.copy() - break - case Qt.Key_Period: - if (Qt.platform.os === "osx") { - event.accepted = true - content.reject() - } - break - } else switch (event.key) { - case Qt.Key_Escape: - case Qt.Key_Back: - event.accepted = true - content.reject() - break - - case Qt.Key_Enter: - case Qt.Key_Return: - event.accepted = true - content.accept() - break - } - } -} diff --git a/interface/resources/qml/RecorderDialog.qml b/interface/resources/qml/RecorderDialog.qml deleted file mode 100644 index 4f197846aa..0000000000 --- a/interface/resources/qml/RecorderDialog.qml +++ /dev/null @@ -1,105 +0,0 @@ -// -// Created by Bradley Austin Davis on 2015/11/14 -// 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 -// - - -import Hifi 1.0 -import QtQuick 2.4 -import "controls" -import "styles" - -VrDialog { - id: root - HifiConstants { id: hifi } - - property real spacing: hifi.layout.spacing - property real outerSpacing: hifi.layout.spacing * 2 - - objectName: "RecorderDialog" - - destroyOnInvisible: false - destroyOnCloseButton: false - - contentImplicitWidth: recorderDialog.width - contentImplicitHeight: recorderDialog.height - - RecorderDialog { - id: recorderDialog - x: root.clientX; y: root.clientY - width: 800 - height: 128 - signal play() - signal rewind() - - onPlay: { - console.log("Pressed play") - player.isPlaying = !player.isPlaying - } - - onRewind: { - console.log("Pressed rewind") - player.position = 0 - } - - Row { - height: 32 - ButtonAwesome { - id: cmdRecord - visible: root.showRecordButton - width: 32; height: 32 - text: "\uf111" - iconColor: "red" - onClicked: { - console.log("Pressed record") - status.text = "Recording"; - } - } - } - Text { - id: status - anchors.top: parent.top - anchors.right: parent.right - width: 128 - text: "Idle" - } - - Player { - id: player - y: root.clientY + 64 - height: 64 - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - - - -// onClicked: { -// if (recordTimer.running) { -// recordTimer.stop(); -// } -// recordTimer.start(); -// } - Timer { - id: recordTimer; - interval: 1000; running: false; repeat: false - onTriggered: { - console.log("Recording: " + MyAvatar.isRecording()) - MyAvatar.startRecording(); - console.log("Recording: " + MyAvatar.isRecording()) - } - } - - } - - Component.onCompleted: { - player.play.connect(play) - player.rewind.connect(rewind) - - } - } -} - diff --git a/interface/resources/qml/Root.qml b/interface/resources/qml/Root.qml index 08e75b7cce..b503e2e1a6 100644 --- a/interface/resources/qml/Root.qml +++ b/interface/resources/qml/Root.qml @@ -1,14 +1,19 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 +import QtQuick.Dialogs 1.2 as OriginalDialogs; -import "Global.js" as Global +import "dialogs" -// This is our primary 'desktop' object to which all VR dialogs and -// windows will be childed. +// This is our primary 'desktop' object to which all VR dialogs and +// windows will be childed. Item { id: desktop anchors.fill: parent; - onParentChanged: forceActiveFocus(); + + // Debugging help for figuring out focus issues + property var offscreenWindow; + onOffscreenWindowChanged: offscreenWindow.activeFocusItemChanged.connect(onWindowFocusChanged); + function onWindowFocusChanged() { console.log("Focus item is " + offscreenWindow.activeFocusItem); } // Allows QML/JS to find the desktop through the parent chain property bool desktopRoot: true @@ -16,16 +21,241 @@ Item { // The VR version of the primary menu property var rootMenu: Menu { objectName: "rootMenu" } - // List of all top level windows - property var windows: []; - onChildrenChanged: windows = Global.getTopLevelWindows(desktop); - // The tool window, one instance property alias toolWindow: toolWindow ToolWindow { id: toolWindow } + // FIXME support always on top flags function raise(item) { - Global.raiseWindow(item); + d.raiseWindow(item); } + Component { + id: messageDialogBuilder + MessageDialog { } + } + + Component { + id: nativeMessageDialogBuilder + OriginalDialogs.MessageDialog { } + } + + function messageBox(properties) { + // Debugging: native message dialog for comparison + // nativeMessageDialogBuilder.createObject(desktop, properties); + return messageDialogBuilder.createObject(desktop, properties); + } + + QtObject { + id: d + + readonly property int zBasisNormal: 0 + readonly property int zBasisAlwaysOnTop: 4096 + readonly property int zBasisModal: 8192 + + + function findChild(item, name) { + for (var i = 0; i < item.children.length; ++i) { + if (item.children[i].objectName === name) { + return item.children[i]; + } + } + return null; + } + + function findParentMatching(item, predicate) { + while (item) { + if (predicate(item)) { + break; + } + item = item.parent; + } + return item; + } + + function isDesktop(item) { + return item.desktopRoot; + } + + function isTopLevelWindow(item) { + return item.topLevelWindow; + } + + function isAlwaysOnTopWindow(window) { + return window.alwaysOnTop; + } + + function isModalWindow(window) { + return window.modality !== Qt.NonModal; + } + + function getTopLevelWindows(predicate) { + var currentWindows = []; + if (!desktop) { + console.log("Could not find desktop for " + item) + return currentWindows; + } + + for (var i = 0; i < desktop.children.length; ++i) { + var child = desktop.children[i]; + if (isTopLevelWindow(child) && (!predicate || predicate(child))) { + currentWindows.push(child) + } + } + return currentWindows; + } + + + function getDesktopWindow(item) { + return findParentMatching(item, isTopLevelWindow) + } + + function fixupZOrder(windows, basis, topWindow) { + windows.sort(function(a, b){ + return a.z - b.z; + }); + + if ((topWindow.z >= basis) && (windows[windows.length - 1] === topWindow)) { + return; + } + + var lastZ = -1; + var lastTargetZ = basis - 1; + for (var i = 0; i < windows.length; ++i) { + var window = windows[i]; + if (!window.visible) { + continue + } + + if (topWindow && (topWindow === window)) { + continue + } + + if (window.z > lastZ) { + lastZ = window.z; + ++lastTargetZ; + } + if (DebugQML) { + console.log("Assigning z order " + lastTargetZ + " to " + window) + } + + window.z = lastTargetZ; + } + if (topWindow) { + ++lastTargetZ; + if (DebugQML) { + console.log("Assigning z order " + lastTargetZ + " to " + topWindow) + } + topWindow.z = lastTargetZ; + } + + return lastTargetZ; + } + + function raiseWindow(item) { + var targetWindow = getDesktopWindow(item); + if (!targetWindow) { + console.warn("Could not find top level window for " + item); + return; + } + + if (!desktop) { + console.warn("Could not find desktop for window " + targetWindow); + return; + } + + var predicate; + var zBasis; + if (isModalWindow(targetWindow)) { + predicate = isModalWindow; + zBasis = zBasisModal + } else if (isAlwaysOnTopWindow(targetWindow)) { + predicate = function(window) { + return (isAlwaysOnTopWindow(window) && !isModalWindow(window)); + } + zBasis = zBasisAlwaysOnTop + } else { + predicate = function(window) { + return (!isAlwaysOnTopWindow(window) && !isModalWindow(window)); + } + zBasis = zBasisNormal + } + + var windows = getTopLevelWindows(predicate); + fixupZOrder(windows, zBasis, targetWindow); + } + + + + //function findMenuChild(menu, childName) { + // if (!menu) { + // return null; + // } + + // if (menu.type !== 2) { + // console.warn("Tried to find child of a non-menu"); + // return null; + // } + + // var items = menu.items; + // var count = items.length; + // for (var i = 0; i < count; ++i) { + // var child = items[i]; + // var name; + // switch (child.type) { + // case 2: + // name = child.title; + // break; + // case 1: + // name = child.text; + // break; + // default: + // break; + // } + + // if (name && name === childName) { + // return child; + // } + // } + //} + + //function findMenu(rootMenu, path) { + // if ('string' === typeof(path)) { + // path = [ path ] + // } + + // var currentMenu = rootMenu; + // for (var i = 0; currentMenu && i < path.length; ++i) { + // currentMenu = findMenuChild(currentMenu, path[i]); + // } + + // return currentMenu; + //} + + //function findInRootMenu(item, path) { + // return findMenu(findRootMenu(item), path); + //} + + //function menuItemsToListModel(parent, items) { + // var newListModel = Qt.createQmlObject('import QtQuick 2.5; ListModel {}', parent); + // for (var i = 0; i < items.length; ++i) { + // var item = items[i]; + // switch (item.type) { + // case 2: + // newListModel.append({"type":item.type, "name": item.title, "item": item}) + // break; + // case 1: + // newListModel.append({"type":item.type, "name": item.text, "item": item}) + // break; + // case 0: + // newListModel.append({"type":item.type, "name": "-----", "item": item}) + // break; + // } + // } + // return newListModel; + //} + } } + + + diff --git a/interface/resources/qml/ToolWindow.qml b/interface/resources/qml/ToolWindow.qml index b2529ff522..2fa57a6ce4 100644 --- a/interface/resources/qml/ToolWindow.qml +++ b/interface/resources/qml/ToolWindow.qml @@ -15,6 +15,7 @@ Windows.Window { destroyOnInvisible: false closable: false visible: false + width: 384; height: 640; property string newTabSource property alias tabView: tabView onParentChanged: { @@ -43,7 +44,8 @@ Windows.Window { } TabView { - id: tabView; width: 384; height: 640; + anchors.fill: parent + id: tabView; onCountChanged: { if (0 == count) { toolWindow.visible = false @@ -73,13 +75,37 @@ Windows.Window { return i; } } + console.warn("Could not find tab for " + source); return -1; } + function findTabForUrl(source) { + var index = findIndexForUrl(source); + if (index < 0) { + return; + } + return tabView.getTab(index); + } + + function showTabForUrl(source, newVisible) { + var index = findIndexForUrl(source); + if (index < 0) { + return; + } + + var tab = tabView.getTab(index); + if (newVisible) { + toolWindow.visible = true + tab.enabled = true + } else { + tab.enabled = false; + updateVisiblity(); + } + } + function removeTabForUrl(source) { var index = findIndexForUrl(source); if (index < 0) { - console.warn("Could not find tab for " + source); return; } tabView.removeTab(index); diff --git a/interface/resources/qml/UpdateDialog.qml b/interface/resources/qml/UpdateDialog.qml index 8baf41cd75..4cb5b206c6 100644 --- a/interface/resources/qml/UpdateDialog.qml +++ b/interface/resources/qml/UpdateDialog.qml @@ -5,21 +5,16 @@ import QtQuick.Controls.Styles 1.3 import QtGraphicalEffects 1.0 import "controls" import "styles" +import "windows" -DialogContainer { +Window { id: root HifiConstants { id: hifi } - objectName: "UpdateDialog" - - implicitWidth: updateDialog.implicitWidth - implicitHeight: updateDialog.implicitHeight - - x: parent ? parent.width / 2 - width / 2 : 0 - y: parent ? parent.height / 2 - height / 2 : 0 - property int maximumX: parent ? parent.width - width : 0 - property int maximumY: parent ? parent.height - height : 0 - + width: updateDialog.implicitWidth + height: updateDialog.implicitHeight + resizable: false + anchors.centerIn: parent UpdateDialog { id: updateDialog diff --git a/interface/resources/qml/controls/Button.qml b/interface/resources/qml/controls/Button.qml index 989d5b579c..c5a9f99343 100644 --- a/interface/resources/qml/controls/Button.qml +++ b/interface/resources/qml/controls/Button.qml @@ -1,9 +1,27 @@ import QtQuick 2.3 import QtQuick.Controls 1.3 as Original import QtQuick.Controls.Styles 1.3 + import "." import "../styles" Original.Button { - style: ButtonStyle { } + style: ButtonStyle { + HifiConstants { id: hifi } + padding { + top: 8 + left: 12 + right: 12 + bottom: 8 + } + background: Border { + anchors.fill: parent + } + label: Text { + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: control.text + color: control.enabled ? hifi.colors.text : hifi.colors.disabledText + } + } } diff --git a/interface/resources/qml/controls/DialogBase.qml b/interface/resources/qml/controls/DialogBase.qml deleted file mode 100644 index 9fb2a47907..0000000000 --- a/interface/resources/qml/controls/DialogBase.qml +++ /dev/null @@ -1,99 +0,0 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.2 -import "." -import "../styles" - -Item { - id: root - objectName: "topLevelWindow" - HifiConstants { id: hifi } - implicitHeight: contentImplicitHeight + titleBorder.height + hifi.styles.borderWidth - implicitWidth: contentImplicitWidth + hifi.styles.borderWidth * 2 - property string title - property int titleSize: titleBorder.height + 12 - property string frameColor: hifi.colors.hifiBlue - property string backgroundColor: hifi.colors.dialogBackground - property bool active: false - property real contentImplicitWidth: 800 - property real contentImplicitHeight: 800 - - property alias titleBorder: titleBorder - readonly property alias titleX: titleBorder.x - readonly property alias titleY: titleBorder.y - readonly property alias titleWidth: titleBorder.width - readonly property alias titleHeight: titleBorder.height - - // readonly property real borderWidth: hifi.styles.borderWidth - readonly property real borderWidth: 0 - property alias clientBorder: clientBorder - readonly property real clientX: clientBorder.x + borderWidth - readonly property real clientY: clientBorder.y + borderWidth - readonly property real clientWidth: clientBorder.width - borderWidth * 2 - readonly property real clientHeight: clientBorder.height - borderWidth * 2 - - /* - * Window decorations, with a title bar and frames - */ - Border { - id: windowBorder - anchors.fill: parent - border.color: root.frameColor - border.width: 0 - color: "#00000000" - - Border { - id: titleBorder - height: hifi.layout.windowTitleHeight - anchors.right: parent.right - anchors.left: parent.left - border.color: root.frameColor - border.width: 0 - clip: true - color: root.active ? - hifi.colors.activeWindow.headerBackground : - hifi.colors.inactiveWindow.headerBackground - - - Text { - id: titleText - color: root.active ? - hifi.colors.activeWindow.headerText : - hifi.colors.inactiveWindow.headerText - text: root.title - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - anchors.fill: parent - } - } // header border - - // These two rectangles hide the curves between the title area - // and the client area - Rectangle { - y: titleBorder.height - titleBorder.radius - height: titleBorder.radius - width: titleBorder.width - color: titleBorder.color - visible: borderWidth == 0 - } - - Rectangle { - y: titleBorder.height - width: clientBorder.width - height: clientBorder.radius - color: clientBorder.color - } - - Border { - id: clientBorder - border.width: 0 - border.color: root.frameColor - color: root.backgroundColor - anchors.bottom: parent.bottom - anchors.top: titleBorder.bottom - anchors.topMargin: -titleBorder.border.width - anchors.right: parent.right - anchors.left: parent.left - } // client border - } // window border - -} diff --git a/interface/resources/qml/controls/DialogContainer.qml b/interface/resources/qml/controls/DialogContainer.qml deleted file mode 100644 index 4aa4e45d67..0000000000 --- a/interface/resources/qml/controls/DialogContainer.qml +++ /dev/null @@ -1,65 +0,0 @@ -// -// DialogCommon.qml -// -// Created by David Rowe on 3 Jun 2015 -// 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 -// - -import Hifi 1.0 -import QtQuick 2.4 -import "../styles" - -Item { - id: root - - property bool destroyOnInvisible: true - - - // The UI enables an object, rather than manipulating its visibility, so that we can do animations in both directions. - // Because visibility and enabled are booleans, they cannot be animated. So when enabled is changed, we modify a property - // that can be animated, like scale or opacity, and then when the target animation value is reached, we can modify the - // visibility. - enabled: false - opacity: 0.0 - - onEnabledChanged: { - opacity = enabled ? 1.0 : 0.0 - } - - Behavior on opacity { - // Animate opacity. - NumberAnimation { - duration: hifi.effects.fadeInDuration - easing.type: Easing.OutCubic - } - } - - onOpacityChanged: { - // Once we're transparent, disable the dialog's visibility. - visible = (opacity != 0.0) - } - - onVisibleChanged: { - if (!visible) { - // Some dialogs should be destroyed when they become invisible. - if (destroyOnInvisible) { - destroy() - } - } - } - - - Keys.onPressed: { - switch(event.key) { - case Qt.Key_W: - if (event.modifiers == Qt.ControlModifier) { - enabled = false - event.accepted = true - } - break - } - } -} diff --git a/interface/resources/qml/controls/VrDialog.qml b/interface/resources/qml/controls/VrDialog.qml deleted file mode 100644 index d4568cded1..0000000000 --- a/interface/resources/qml/controls/VrDialog.qml +++ /dev/null @@ -1,179 +0,0 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.2 -import "." -import "../styles" - -/* - * FIXME Need to create a client property here so that objects can be - * placed in it without having to think about positioning within the outer - * window. - * - * Examine the QML ApplicationWindow.qml source for how it does this - * - */ -DialogBase { - id: root - HifiConstants { id: hifi } - // FIXME better placement via a window manager - x: parent ? parent.width / 2 - width / 2 : 0 - y: parent ? parent.height / 2 - height / 2 : 0 - - property bool destroyOnInvisible: false - property bool destroyOnCloseButton: true - property bool resizable: false - - property int animationDuration: hifi.effects.fadeInDuration - property int minX: 256 - property int minY: 256 - readonly property int topMargin: root.height - clientBorder.height + hifi.layout.spacing - - /* - * Support for animating the dialog in and out. - */ - enabled: false - opacity: 1.0 - - // The offscreen UI will enable an object, rather than manipulating it's - // visibility, so that we can do animations in both directions. Because - // visibility and enabled are boolean flags, they cannot be animated. So when - // enabled is change, we modify a property that can be animated, like scale or - // opacity, and then when the target animation value is reached, we can - // modify the visibility - onEnabledChanged: { - opacity = enabled ? 1.0 : 0.0 - // If the dialog is initially invisible, setting opacity doesn't - // trigger making it visible. - if (enabled) { - visible = true; - if (root.parent) { - Desktop.raise(root); - } - } - } - - onParentChanged: { - if (enabled && parent) { - Global.raiseWindow(root); - } - } - - // The actual animator - Behavior on opacity { - NumberAnimation { - duration: animationDuration - easing.type: Easing.OutCubic - } - } - - // Once we're transparent, disable the dialog's visibility - onOpacityChanged: { - visible = (opacity != 0.0); - } - - Component.onCompleted: { - if (visible) { - Global.raiseWindow(root); - } - } - - // Some dialogs should be destroyed when they become invisible, - // so handle that - onVisibleChanged: { - if (!visible && destroyOnInvisible) { - destroy(); - } - } - - // our close function performs the same way as the OffscreenUI class: - // don't do anything but manipulate the enabled flag and let the other - // mechanisms decide if the window should be destroyed after the close - // animation completes - function close() { - if (destroyOnCloseButton) { - destroyOnInvisible = true - } - enabled = false; - } - - /* - * Resize support - */ - function deltaSize(dx, dy) { - width = Math.max(width + dx, minX) - height = Math.max(height + dy, minY) - } - - MouseArea { - id: sizeDrag - enabled: root.resizable - property int startX - property int startY - anchors.right: parent.right - anchors.bottom: parent.bottom - width: 16 - height: 16 - z: 1000 - hoverEnabled: true - onPressed: { - startX = mouseX - startY = mouseY - } - onPositionChanged: { - if (pressed) { - root.deltaSize((mouseX - startX), (mouseY - startY)) - startX = mouseX - startY = mouseY - } - } - } - - MouseArea { - id: titleDrag - x: root.titleX - y: root.titleY - width: root.titleWidth - height: root.titleHeight - onClicked: Global.raiseWindow(root) - - drag { - target: root - minimumX: 0 - minimumY: 0 - maximumX: root.parent ? root.parent.width - root.width : 0 - maximumY: root.parent ? root.parent.height - root.height : 0 - } - - Row { - id: windowControls - anchors.bottom: parent.bottom - anchors.top: parent.top - anchors.right: parent.right - anchors.rightMargin: hifi.layout.spacing - FontAwesome { - id: icon - anchors.verticalCenter: parent.verticalCenter - size: root.titleHeight - hifi.layout.spacing * 2 - color: "red" - text: "\uf00d" - MouseArea { - anchors.margins: hifi.layout.spacing / 2 - anchors.fill: parent - onClicked: { - root.close(); - } - } - } - } - } - - Keys.onPressed: { - switch(event.key) { - case Qt.Key_W: - if (event.modifiers == Qt.ControlModifier) { - event.accepted = true - enabled = false - } - break; - } - } -} diff --git a/interface/resources/qml/dialogs/FileDialog.qml b/interface/resources/qml/dialogs/FileDialog.qml index 6711475d23..fcaf994b1b 100644 --- a/interface/resources/qml/dialogs/FileDialog.qml +++ b/interface/resources/qml/dialogs/FileDialog.qml @@ -4,17 +4,200 @@ import Qt.labs.folderlistmodel 2.1 import Qt.labs.settings 1.0 import ".." -import "." +import "../windows" +import "../styles" // Work in progress.... -DialogBase { +Window { id: root - Constants { id: vr } - property string settingsName: "" + HifiConstants { id: hifi } signal selectedFile(var file); signal canceled(); + anchors.centerIn: parent + resizable: true + width: 640 + height: 480 + modality: Qt.ApplicationModal + property string settingsName: "" + property alias folder: folderModel.folder + property alias filterModel: selectionType.model + + + Rectangle { + anchors.fill: parent + color: "white" + + Settings { + // fixme, combine with a property to allow different saved locations + category: "FileOpenLastFolder." + settingsName + property alias folder: folderModel.folder + } + + TextField { + id: currentDirectory + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.margins: 8 + readOnly: true + text: folderModel.folder + } + + Component { + id: fileItemDelegate + Item { + clip: true + Text { + x: 3 + id: columnText + anchors.verticalCenter: parent.verticalCenter +// font.pointSize: 12 + color: tableView.activeFocus && styleData.row === tableView.currentRow ? "yellow" : styleData.textColor + elide: styleData.elideMode + text: getText(); + font.italic: folderModel.get(styleData.row, "fileIsDir") ? true : false + + + Connections { + target: tableView + //onCurrentRowChanged: columnText.color = (tableView.activeFocus && styleData.row === tableView.currentRow ? "yellow" : styleData.textColor) + } + + function getText() { + switch (styleData.column) { + //case 1: return Date.fromLocaleString(locale, styleData.value, "yyyy-MM-dd hh:mm:ss"); + case 2: return folderModel.get(styleData.row, "fileIsDir") ? "" : formatSize(styleData.value); + default: return styleData.value; + } + } + + function formatSize(size) { + var suffixes = [ "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" ]; + var suffixIndex = 0 + while ((size / 1024.0) > 1.1) { + size /= 1024.0; + ++suffixIndex; + } + + size = Math.round(size*1000)/1000; + size = size.toLocaleString() + + return size + " " + suffixes[suffixIndex]; + } + } + } + } + + TableView { + id: tableView + focus: true + model: FolderListModel { + id: folderModel + showDotAndDotDot: true + showDirsFirst: true + onFolderChanged: { + tableView.currentRow = -1; + tableView.positionViewAtRow(0, ListView.Beginning) + } + } + anchors.top: currentDirectory.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: selectionType.top + anchors.margins: 8 + itemDelegate: fileItemDelegate +// rowDelegate: Rectangle { +// id: rowDelegate +// color: styleData.selected ? "#7f0000ff" : "#00000000" +// Connections { target: folderModel; onFolderChanged: rowDelegate.visible = false } +// Connections { target: tableView; onCurrentRowChanged: rowDelegate.visible = true; } +// } + + TableViewColumn { + role: "fileName" + title: "Name" + width: 400 + } + TableViewColumn { + role: "fileModified" + title: "Date Modified" + width: 200 + } + TableViewColumn { + role: "fileSize" + title: "Size" + width: 200 + } + + Keys.onReturnPressed: selectCurrentFile(); + onDoubleClicked: { currentRow = row; selectCurrentFile(); } + onCurrentRowChanged: currentSelection.text = model.get(currentRow, "fileName"); + KeyNavigation.left: cancelButton + KeyNavigation.right: selectionType + } + + + TextField { + id: currentSelection + anchors.right: selectionType.left + anchors.rightMargin: 8 + anchors.left: parent.left + anchors.leftMargin: 8 + anchors.top: selectionType.top + } + + ComboBox { + id: selectionType + anchors.bottom: buttonRow.top + anchors.bottomMargin: 8 + anchors.right: parent.right + anchors.rightMargin: 8 + anchors.left: buttonRow.left + + model: ListModel { + ListElement { text: "All Files (*.*)"; filter: "*.*" } + } + + onCurrentIndexChanged: { + folderModel.nameFilters = [ filterModel.get(currentIndex).filter ] + } + KeyNavigation.left: tableView + KeyNavigation.right: openButton + } + + Row { + id: buttonRow + anchors.right: parent.right + anchors.rightMargin: 8 + anchors.bottom: parent.bottom + anchors.bottomMargin: 8 + layoutDirection: Qt.RightToLeft + spacing: 8 + Button { + id: cancelButton + text: "Cancel" + KeyNavigation.up: selectionType + KeyNavigation.left: openButton + KeyNavigation.right: tableView.contentItem + Keys.onReturnPressed: { canceled(); root.enabled = false } + onClicked: { canceled(); close() } + } + Button { + id: openButton + text: "Open" + enabled: tableView.currentRow != -1 && !folderModel.get(tableView.currentRow, "fileIsDir") + onClicked: selectCurrentFile(); + Keys.onReturnPressed: selectCurrentFile(); + + KeyNavigation.up: selectionType + KeyNavigation.left: selectionType + KeyNavigation.right: cancelButton + } + } + } + function selectCurrentFile() { var row = tableView.currentRow console.log("Selecting row " + row) @@ -25,200 +208,11 @@ DialogBase { folderModel.folder = folderModel.get(row, "fileURL"); } else { selectedFile(folderModel.get(row, "fileURL")); - enabled = false + close(); } } - property var folderModel: FolderListModel { - id: folderModel - showDotAndDotDot: true - showDirsFirst: true - folder: "file:///C:/"; - onFolderChanged: tableView.currentRow = 0 - } - - property var filterModel: ListModel { - ListElement { - text: "All Files (*.*)" - filter: "*" - } - ListElement { - text: "Javascript Files (*.js)" - filter: "*.js" - } - ListElement { - text: "QML Files (*.qml)" - filter: "*.qml" - } - } - - Settings { - // fixme, combine with a property to allow different saved locations - category: "FileOpenLastFolder." + settingsName - property alias folder: folderModel.folder - } - - Rectangle { - id: currentDirectoryWrapper - anchors.left: parent.left - anchors.leftMargin: 8 - anchors.right: parent.right - anchors.rightMargin: 8 - anchors.top: parent.top - anchors.topMargin: 8 - height: currentDirectory.implicitHeight + 8 - radius: vr.styles.radius - color: vr.controls.colors.inputBackground - - TextEdit { - enabled: false - id: currentDirectory - text: folderModel.folder - anchors { - fill: parent - leftMargin: 8 - rightMargin: 8 - topMargin: 4 - bottomMargin: 4 - } - } - } - - - TableView { - id: tableView - focus: true - model: folderModel - anchors.top: currentDirectoryWrapper.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: selectionType.top - anchors.margins: 8 - itemDelegate: Item { - Text { - anchors.verticalCenter: parent.verticalCenter - font.family: vr.fonts.lightFontName - font.pointSize: 12 - color: tableView.activeFocus && styleData.row === tableView.currentRow ? "yellow" : styleData.textColor - elide: styleData.elideMode - text: getText(); - function getText() { - switch (styleData.column) { - //case 1: return Date.fromLocaleString(locale, styleData.value, "yyyy-MM-dd hh:mm:ss"); - case 2: return folderModel.get(styleData.row, "fileIsDir") ? "" : formatSize(styleData.value); - default: return styleData.value; - } - } - - function formatSize(size) { - var suffixes = [ "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" ]; - var suffixIndex = 0 - while ((size / 1024.0) > 1.1) { - size /= 1024.0; - ++suffixIndex; - } - - size = Math.round(size*1000)/1000; - size = size.toLocaleString() - - return size + " " + suffixes[suffixIndex]; - } - } - } - - TableViewColumn { - role: "fileName" - title: "Name" - width: 400 - } - TableViewColumn { - role: "fileModified" - title: "Date Modified" - width: 200 - } - TableViewColumn { - role: "fileSize" - title: "Size" - width: 200 - } - - function selectItem(row) { - selectCurrentFile() - } - - - Keys.onReturnPressed: selectCurrentFile(); - onDoubleClicked: { currentRow = row; selectCurrentFile(); } - onCurrentRowChanged: currentSelection.text = model.get(currentRow, "fileName"); - KeyNavigation.left: cancelButton - KeyNavigation.right: selectionType - } - - Rectangle { - anchors.right: selectionType.left - anchors.rightMargin: 8 - anchors.top: selectionType.top - anchors.bottom: selectionType.bottom - anchors.left: parent.left - anchors.leftMargin: 8 - radius: 8 - color: "#eee" - Text { - id: currentSelection - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: 8 - anchors.verticalCenter: parent.verticalCenter - font.family: vr.fonts.mainFontName - font.pointSize: 18 - } - } - - ComboBox { - id: selectionType - anchors.bottom: buttonRow.top - anchors.bottomMargin: 8 - anchors.right: parent.right - anchors.rightMargin: 8 - anchors.left: buttonRow.left - model: filterModel - onCurrentIndexChanged: folderModel.nameFilters = [ - filterModel.get(currentIndex).filter - ] - - KeyNavigation.left: tableView - KeyNavigation.right: openButton - } - - Row { - id: buttonRow - anchors.right: parent.right - anchors.rightMargin: 8 - anchors.bottom: parent.bottom - anchors.bottomMargin: 8 - layoutDirection: Qt.RightToLeft - spacing: 8 - Button { - id: cancelButton - text: "Cancel" - KeyNavigation.up: selectionType - KeyNavigation.left: openButton - KeyNavigation.right: tableView.contentItem - Keys.onReturnPressed: { canceled(); root.enabled = false } - onClicked: { canceled(); root.enabled = false } - } - Button { - id: openButton - text: "Open" - enabled: tableView.currentRow != -1 && !folderModel.get(tableView.currentRow, "fileIsDir") - KeyNavigation.up: selectionType - KeyNavigation.left: selectionType - KeyNavigation.right: cancelButton - onClicked: selectCurrentFile(); - Keys.onReturnPressed: selectedFile(folderModel.get(tableView.currentRow, "fileURL")) - } - } Keys.onPressed: { if (event.key === Qt.Key_Backspace && folderModel.parentFolder && folderModel.parentFolder != "") { diff --git a/interface/resources/qml/dialogs/MessageDialog.qml b/interface/resources/qml/dialogs/MessageDialog.qml new file mode 100644 index 0000000000..6f96340be6 --- /dev/null +++ b/interface/resources/qml/dialogs/MessageDialog.qml @@ -0,0 +1,341 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.2 +import QtQuick.Dialogs 1.2 as OriginalDialogs + +import "../controls" +import "../styles" +import "../windows" + +// FIXME respect default button functionality +// FIXME force active focus at all times (modal dialog) +Window { + id: root + HifiConstants { id: hifi } + + implicitWidth: 640 + implicitHeight: 320 + destroyOnCloseButton: true + destroyOnInvisible: true + visible: true + modality: Qt.ApplicationModal + anchors.centerIn: parent + frame: ModalFrame {} + + signal selected(int button); + + function click(button) { + console.log("User clicked " + button) + clickedButton = button; + selected(button); + destroy(); + } + + property alias detailedText: detailedText.text + property alias text: mainTextContainer.text + property alias informativeText: informativeTextContainer.text + onIconChanged: iconHolder.updateIcon(); + property int buttons: OriginalDialogs.StandardButton.Ok + property int icon: OriginalDialogs.StandardIcon.NoIcon + property int defaultButton: OriginalDialogs.StandardButton.NoButton; + property int clickedButton: OriginalDialogs.StandardButton.NoButton; + focus: defaultButton === OriginalDialogs.StandardButton.NoButton + + Rectangle { + id: messageBox + clip: true + anchors.fill: parent + radius: 4 + color: "white" + + QtObject { + id: d + readonly property real spacing: hifi.layout.spacing + readonly property real outerSpacing: hifi.layout.spacing * 2 + readonly property int minWidth: 480 + readonly property int maxWdith: 1280 + readonly property int minHeight: 160 + readonly property int maxHeight: 720 + + function resize() { + var targetWidth = iconHolder.width + mainTextContainer.width + d.spacing * 6 + var targetHeight = mainTextContainer.implicitHeight + informativeTextContainer.implicitHeight + d.spacing * 8 + buttons.height + details.height + root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth) + root.height = (targetHeight < d.minHeight) ? d.minHeight: ((targetHeight > d.maxHeight) ? d.maxHeight : targetHeight) + } + } + + FontAwesome { + id: iconHolder + size: 48 + anchors { + left: parent.left + top: parent.top + margins: d.spacing * 2 + } + + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + style: Text.Outline; styleColor: "black" + Component.onCompleted: updateIcon(); + function updateIcon() { + if (!root) { + return; + } + switch (root.icon) { + case OriginalDialogs.StandardIcon.Information: + text = "\uF05A"; + color = "blue"; + break; + + case OriginalDialogs.StandardIcon.Question: + text = "\uF059" + color = "blue"; + break; + + case OriginalDialogs.StandardIcon.Warning: + text = "\uF071" + color = "yellow"; + break; + + case OriginalDialogs.StandardIcon.Critical: + text = "\uF057" + color = "red" + break; + + default: + text = "" + } + visible = (text != ""); + } + } + + Text { + id: mainTextContainer + onHeightChanged: d.resize(); onWidthChanged: d.resize(); + wrapMode: Text.WordWrap + font { pointSize: 14; weight: Font.Bold } + anchors { left: iconHolder.right; top: parent.top; margins: d.spacing * 2 } + } + + Text { + id: informativeTextContainer + onHeightChanged: d.resize(); onWidthChanged: d.resize(); + wrapMode: Text.WordWrap + font.pointSize: 11 + anchors { top: mainTextContainer.bottom; right: parent.right; left: iconHolder.right; margins: d.spacing * 2 } + } + + Flow { + id: buttons + focus: true + spacing: d.spacing + onHeightChanged: d.resize(); onWidthChanged: d.resize(); + layoutDirection: Qt.RightToLeft + anchors { bottom: details.top; right: parent.right; margins: d.spacing * 2; bottomMargin: 0 } + Button { + id: okButton + text: qsTr("OK") + focus: root.defaultButton === OriginalDialogs.StandardButton.Ok + onClicked: root.click(OriginalDialogs.StandardButton.Ok) + visible: root.buttons & OriginalDialogs.StandardButton.Ok + + } + Button { + id: openButton + text: qsTr("Open") + focus: root.defaultButton === OriginalDialogs.StandardButton.Open + onClicked: root.click(OriginalDialogs.StandardButton.Open) + visible: root.buttons & OriginalDialogs.StandardButton.Open + } + Button { + id: saveButton + text: qsTr("Save") + focus: root.defaultButton === OriginalDialogs.StandardButton.Save + onClicked: root.click(OriginalDialogs.StandardButton.Save) + visible: root.buttons & OriginalDialogs.StandardButton.Save + } + Button { + id: saveAllButton + text: qsTr("Save All") + focus: root.defaultButton === OriginalDialogs.StandardButton.SaveAll + onClicked: root.click(OriginalDialogs.StandardButton.SaveAll) + visible: root.buttons & OriginalDialogs.StandardButton.SaveAll + } + Button { + id: retryButton + text: qsTr("Retry") + focus: root.defaultButton === OriginalDialogs.StandardButton.Retry + onClicked: root.click(OriginalDialogs.StandardButton.Retry) + visible: root.buttons & OriginalDialogs.StandardButton.Retry + } + Button { + id: ignoreButton + text: qsTr("Ignore") + focus: root.defaultButton === OriginalDialogs.StandardButton.Ignore + onClicked: root.click(OriginalDialogs.StandardButton.Ignore) + visible: root.buttons & OriginalDialogs.StandardButton.Ignore + } + Button { + id: applyButton + text: qsTr("Apply") + focus: root.defaultButton === OriginalDialogs.StandardButton.Apply + onClicked: root.click(OriginalDialogs.StandardButton.Apply) + visible: root.buttons & OriginalDialogs.StandardButton.Apply + } + Button { + id: yesButton + text: qsTr("Yes") + focus: root.defaultButton === OriginalDialogs.StandardButton.Yes + onClicked: root.click(OriginalDialogs.StandardButton.Yes) + visible: root.buttons & OriginalDialogs.StandardButton.Yes + } + Button { + id: yesAllButton + text: qsTr("Yes to All") + focus: root.defaultButton === OriginalDialogs.StandardButton.YesToAll + onClicked: root.click(OriginalDialogs.StandardButton.YesToAll) + visible: root.buttons & OriginalDialogs.StandardButton.YesToAll + } + Button { + id: noButton + text: qsTr("No") + focus: root.defaultButton === OriginalDialogs.StandardButton.No + onClicked: root.click(OriginalDialogs.StandardButton.No) + visible: root.buttons & OriginalDialogs.StandardButton.No + } + Button { + id: noAllButton + text: qsTr("No to All") + focus: root.defaultButton === OriginalDialogs.StandardButton.NoToAll + onClicked: root.click(OriginalDialogs.StandardButton.NoToAll) + visible: root.buttons & OriginalDialogs.StandardButton.NoToAll + } + Button { + id: discardButton + text: qsTr("Discard") + focus: root.defaultButton === OriginalDialogs.StandardButton.Discard + onClicked: root.click(OriginalDialogs.StandardButton.Discard) + visible: root.buttons & OriginalDialogs.StandardButton.Discard + } + Button { + id: resetButton + text: qsTr("Reset") + focus: root.defaultButton === OriginalDialogs.StandardButton.Reset + onClicked: root.click(OriginalDialogs.StandardButton.Reset) + visible: root.buttons & OriginalDialogs.StandardButton.Reset + } + Button { + id: restoreDefaultsButton + text: qsTr("Restore Defaults") + focus: root.defaultButton === OriginalDialogs.StandardButton.RestoreDefaults + onClicked: root.click(OriginalDialogs.StandardButton.RestoreDefaults) + visible: root.buttons & OriginalDialogs.StandardButton.RestoreDefaults + } + Button { + id: cancelButton + text: qsTr("Cancel") + focus: root.defaultButton === OriginalDialogs.StandardButton.Cancel + onClicked: root.click(OriginalDialogs.StandardButton.Cancel) + visible: root.buttons & OriginalDialogs.StandardButton.Cancel + } + Button { + id: abortButton + text: qsTr("Abort") + focus: root.defaultButton === OriginalDialogs.StandardButton.Abort + onClicked: root.click(OriginalDialogs.StandardButton.Abort) + visible: root.buttons & OriginalDialogs.StandardButton.Abort + } + Button { + id: closeButton + text: qsTr("Close") + focus: root.defaultButton === OriginalDialogs.StandardButton.Close + onClicked: root.click(OriginalDialogs.StandardButton.Close) + visible: root.buttons & OriginalDialogs.StandardButton.Close + } + Button { + id: moreButton + text: qsTr("Show Details...") + onClicked: { content.state = (content.state === "" ? "expanded" : "") + } + visible: detailedText && detailedText.length > 0 + } + Button { + id: helpButton + text: qsTr("Help") + focus: root.defaultButton === OriginalDialogs.StandardButton.Help + onClicked: root.click(OriginalDialogs.StandardButton.Help) + visible: root.buttons & OriginalDialogs.StandardButton.Help + } + } + + Item { + id: details + width: parent.width + implicitHeight: detailedText.implicitHeight + root.spacing + height: 0 + clip: true + anchors { bottom: parent.bottom; left: parent.left; right: parent.right; margins: d.spacing * 2 } + Flickable { + id: flickable + contentHeight: detailedText.height + anchors.fill: parent + anchors.topMargin: root.spacing + anchors.bottomMargin: root.outerSpacing + TextEdit { + id: detailedText + width: details.width + wrapMode: Text.WordWrap + readOnly: true + selectByMouse: true + } + } + } + + states: [ + State { + name: "expanded" + PropertyChanges { target: root; anchors.fill: undefined } + PropertyChanges { target: details; height: 120 } + PropertyChanges { target: moreButton; text: qsTr("Hide Details") } + } + ] + + onStateChanged: d.resize() + } + + Keys.onPressed: { + if (!visible) { + return + } + + if (event.modifiers === Qt.ControlModifier) + switch (event.key) { + case Qt.Key_A: + event.accepted = true + detailedText.selectAll() + break + case Qt.Key_C: + event.accepted = true + detailedText.copy() + break + case Qt.Key_Period: + if (Qt.platform.os === "osx") { + event.accepted = true + content.reject() + } + break + } else switch (event.key) { + case Qt.Key_Escape: + case Qt.Key_Back: + event.accepted = true + root.click(OriginalDialogs.StandardButton.Cancel) + break + + case Qt.Key_Enter: + case Qt.Key_Return: + event.accepted = true + root.click(OriginalDialogs.StandardButton.Ok) + break + } + } +} diff --git a/interface/resources/qml/dialogs/RunningScripts.qml b/interface/resources/qml/dialogs/RunningScripts.qml index e9b82609d9..9f4309844d 100644 --- a/interface/resources/qml/dialogs/RunningScripts.qml +++ b/interface/resources/qml/dialogs/RunningScripts.qml @@ -13,7 +13,6 @@ Window { title: "Running Scripts" resizable: true destroyOnInvisible: true - enabled: false x: 40; y: 40 property var scripts: ScriptDiscoveryService; @@ -202,7 +201,6 @@ Window { TextField { id: selectedScript - enabled: true readOnly: true anchors.left: parent.left anchors.right: loadButton.left diff --git a/interface/resources/qml/hifi/MenuOption.qml b/interface/resources/qml/hifi/MenuOption.qml new file mode 100644 index 0000000000..3add333236 --- /dev/null +++ b/interface/resources/qml/hifi/MenuOption.qml @@ -0,0 +1,167 @@ +import QtQuick 2.5 + +QtObject { + readonly property string aboutApp: "About Interface"; + readonly property string addRemoveFriends: "Add/Remove Friends..."; + readonly property string addressBar: "Show Address Bar"; + readonly property string animations: "Animations..."; + readonly property string animDebugDrawAnimPose: "Debug Draw Animation"; + readonly property string animDebugDrawDefaultPose: "Debug Draw Default Pose"; + readonly property string animDebugDrawPosition: "Debug Draw Position"; + readonly property string antialiasing: "Antialiasing"; + readonly property string assetMigration: "ATP Asset Migration"; + readonly property string atmosphere: "Atmosphere"; + readonly property string attachments: "Attachments..."; + readonly property string audioNetworkStats: "Audio Network Stats"; + readonly property string audioNoiseReduction: "Audio Noise Reduction"; + readonly property string audioScope: "Show Scope"; + readonly property string audioScopeFiftyFrames: "Fifty"; + readonly property string audioScopeFiveFrames: "Five"; + readonly property string audioScopeFrames: "Display Frames"; + readonly property string audioScopePause: "Pause Scope"; + readonly property string audioScopeTwentyFrames: "Twenty"; + readonly property string audioStatsShowInjectedStreams: "Audio Stats Show Injected Streams"; + readonly property string audioTools: "Show Level Meter"; + readonly property string autoMuteAudio: "Auto Mute Microphone"; + readonly property string avatarReceiveStats: "Show Receive Stats"; + readonly property string back: "Back"; + readonly property string bandwidthDetails: "Bandwidth Details"; + readonly property string binaryEyelidControl: "Binary Eyelid Control"; + readonly property string bookmarkLocation: "Bookmark Location"; + readonly property string bookmarks: "Bookmarks"; + readonly property string cachesSize: "RAM Caches Size"; + readonly property string calibrateCamera: "Calibrate Camera"; + readonly property string cameraEntityMode: "Entity Mode"; + readonly property string centerPlayerInView: "Center Player In View"; + readonly property string chat: "Chat..."; + readonly property string collisions: "Collisions"; + readonly property string comfortMode: "Comfort Mode"; + readonly property string connexion: "Activate 3D Connexion Devices"; + readonly property string console_: "Console..."; + readonly property string controlWithSpeech: "Control With Speech"; + readonly property string copyAddress: "Copy Address to Clipboard"; + readonly property string copyPath: "Copy Path to Clipboard"; + readonly property string coupleEyelids: "Couple Eyelids"; + readonly property string crashInterface: "Crash Interface"; + readonly property string debugAmbientOcclusion: "Debug Ambient Occlusion"; + readonly property string decreaseAvatarSize: "Decrease Avatar Size"; + readonly property string deleteBookmark: "Delete Bookmark..."; + readonly property string disableActivityLogger: "Disable Activity Logger"; + readonly property string disableEyelidAdjustment: "Disable Eyelid Adjustment"; + readonly property string disableLightEntities: "Disable Light Entities"; + readonly property string disableNackPackets: "Disable Entity NACK Packets"; + readonly property string diskCacheEditor: "Disk Cache Editor"; + readonly property string displayCrashOptions: "Display Crash Options"; + readonly property string displayHandTargets: "Show Hand Targets"; + readonly property string displayModelBounds: "Display Model Bounds"; + readonly property string displayModelTriangles: "Display Model Triangles"; + readonly property string displayModelElementChildProxies: "Display Model Element Children"; + readonly property string displayModelElementProxy: "Display Model Element Bounds"; + readonly property string displayDebugTimingDetails: "Display Timing Details"; + readonly property string dontDoPrecisionPicking: "Don't Do Precision Picking"; + readonly property string dontRenderEntitiesAsScene: "Don't Render Entities as Scene"; + readonly property string echoLocalAudio: "Echo Local Audio"; + readonly property string echoServerAudio: "Echo Server Audio"; + readonly property string enable3DTVMode: "Enable 3DTV Mode"; + readonly property string enableCharacterController: "Enable avatar collisions"; + readonly property string expandMyAvatarSimulateTiming: "Expand /myAvatar/simulation"; + readonly property string expandMyAvatarTiming: "Expand /myAvatar"; + readonly property string expandOtherAvatarTiming: "Expand /otherAvatar"; + readonly property string expandPaintGLTiming: "Expand /paintGL"; + readonly property string expandUpdateTiming: "Expand /update"; + readonly property string faceshift: "Faceshift"; + readonly property string firstPerson: "First Person"; + readonly property string fivePointCalibration: "5 Point Calibration"; + readonly property string fixGaze: "Fix Gaze (no saccade)"; + readonly property string forward: "Forward"; + readonly property string frameTimer: "Show Timer"; + readonly property string fullscreenMirror: "Mirror"; + readonly property string glowWhenSpeaking: "Glow When Speaking"; + readonly property string help: "Help..."; + readonly property string increaseAvatarSize: "Increase Avatar Size"; + readonly property string independentMode: "Independent Mode"; + readonly property string inputMenu: "Avatar>Input Devices"; + readonly property string keyboardMotorControl: "Enable Keyboard Motor Control"; + readonly property string leapMotionOnHMD: "Leap Motion on HMD"; + readonly property string loadScript: "Open and Run Script File..."; + readonly property string loadScriptURL: "Open and Run Script from URL..."; + readonly property string lodTools: "LOD Tools"; + readonly property string login: "Login"; + readonly property string log: "Log"; + readonly property string logExtraTimings: "Log Extra Timing Details"; + readonly property string lowVelocityFilter: "Low Velocity Filter"; + readonly property string meshVisible: "Draw Mesh"; + readonly property string miniMirror: "Mini Mirror"; + readonly property string muteAudio: "Mute Microphone"; + readonly property string muteEnvironment: "Mute Environment"; + readonly property string muteFaceTracking: "Mute Face Tracking"; + readonly property string namesAboveHeads: "Names Above Heads"; + readonly property string noFaceTracking: "None"; + readonly property string octreeStats: "Entity Statistics"; + readonly property string onePointCalibration: "1 Point Calibration"; + readonly property string onlyDisplayTopTen: "Only Display Top Ten"; + readonly property string outputMenu: "Display"; + readonly property string packageModel: "Package Model..."; + readonly property string pair: "Pair"; + readonly property string physicsShowOwned: "Highlight Simulation Ownership"; + readonly property string physicsShowHulls: "Draw Collision Hulls"; + readonly property string pipelineWarnings: "Log Render Pipeline Warnings"; + readonly property string preferences: "General..."; + readonly property string quit: "Quit"; + readonly property string reloadAllScripts: "Reload All Scripts"; + readonly property string reloadContent: "Reload Content (Clears all caches)"; + readonly property string renderBoundingCollisionShapes: "Show Bounding Collision Shapes"; + readonly property string renderFocusIndicator: "Show Eye Focus"; + readonly property string renderLookAtTargets: "Show Look-at Targets"; + readonly property string renderLookAtVectors: "Show Look-at Vectors"; + readonly property string renderResolution: "Scale Resolution"; + readonly property string renderResolutionOne: "1"; + readonly property string renderResolutionTwoThird: "2/3"; + readonly property string renderResolutionHalf: "1/2"; + readonly property string renderResolutionThird: "1/3"; + readonly property string renderResolutionQuarter: "1/4"; + readonly property string renderAmbientLight: "Ambient Light"; + readonly property string renderAmbientLightGlobal: "Global"; + readonly property string renderAmbientLight0: "OLD_TOWN_SQUARE"; + readonly property string renderAmbientLight1: "GRACE_CATHEDRAL"; + readonly property string renderAmbientLight2: "EUCALYPTUS_GROVE"; + readonly property string renderAmbientLight3: "ST_PETERS_BASILICA"; + readonly property string renderAmbientLight4: "UFFIZI_GALLERY"; + readonly property string renderAmbientLight5: "GALILEOS_TOMB"; + readonly property string renderAmbientLight6: "VINE_STREET_KITCHEN"; + readonly property string renderAmbientLight7: "BREEZEWAY"; + readonly property string renderAmbientLight8: "CAMPUS_SUNSET"; + readonly property string renderAmbientLight9: "FUNSTON_BEACH_SUNSET"; + readonly property string resetAvatarSize: "Reset Avatar Size"; + readonly property string resetSensors: "Reset Sensors"; + readonly property string runningScripts: "Running Scripts..."; + readonly property string runTimingTests: "Run Timing Tests"; + readonly property string scriptEditor: "Script Editor..."; + readonly property string scriptedMotorControl: "Enable Scripted Motor Control"; + readonly property string showDSConnectTable: "Show Domain Connection Timing"; + readonly property string showBordersEntityNodes: "Show Entity Nodes"; + readonly property string showRealtimeEntityStats: "Show Realtime Entity Stats"; + readonly property string showWhosLookingAtMe: "Show Who's Looking at Me"; + readonly property string standingHMDSensorMode: "Standing HMD Sensor Mode"; + readonly property string simulateEyeTracking: "Simulate"; + readonly property string sMIEyeTracking: "SMI Eye Tracking"; + readonly property string stars: "Stars"; + readonly property string stats: "Stats"; + readonly property string stopAllScripts: "Stop All Scripts"; + readonly property string suppressShortTimings: "Suppress Timings Less than 10ms"; + readonly property string thirdPerson: "Third Person"; + readonly property string threePointCalibration: "3 Point Calibration"; + readonly property string throttleFPSIfNotFocus: "Throttle FPS If Not Focus"; // FIXME - this value duplicated in Basic2DWindowOpenGLDisplayPlugin.cpp + readonly property string toolWindow: "Tool Window"; + readonly property string transmitterDrive: "Transmitter Drive"; + readonly property string turnWithHead: "Turn using Head"; + readonly property string uploadAsset: "Upload File to Asset Server"; + readonly property string useAudioForMouth: "Use Audio for Mouth"; + readonly property string useCamera: "Use Camera"; + readonly property string velocityFilter: "Velocity Filter"; + readonly property string visibleToEveryone: "Everyone"; + readonly property string visibleToFriends: "Friends"; + readonly property string visibleToNoOne: "No one"; + readonly property string worldAxes: "World Axes"; +} + diff --git a/interface/resources/qml/styles/ButtonStyle.qml b/interface/resources/qml/styles/ButtonStyle.qml deleted file mode 100644 index bcb167f4dc..0000000000 --- a/interface/resources/qml/styles/ButtonStyle.qml +++ /dev/null @@ -1,23 +0,0 @@ -import QtQuick 2.4 as Original -import QtQuick.Controls.Styles 1.3 as OriginalStyles -import "." -import "../controls" - -OriginalStyles.ButtonStyle { - HifiConstants { id: hifi } - padding { - top: 8 - left: 12 - right: 12 - bottom: 8 - } - background: Border { - anchors.fill: parent - } - label: Text { - verticalAlignment: Original.Text.AlignVCenter - horizontalAlignment: Original.Text.AlignHCenter - text: control.text - color: control.enabled ? hifi.colors.text : hifi.colors.disabledText - } -} diff --git a/interface/resources/qml/styles/HifiPalette.qml b/interface/resources/qml/styles/HifiPalette.qml deleted file mode 100644 index 421fa2c75d..0000000000 --- a/interface/resources/qml/styles/HifiPalette.qml +++ /dev/null @@ -1,11 +0,0 @@ -import QtQuick 2.4 - -Item { - property string hifiBlue: "#0e7077" - property alias colors: colorsObj - - Item { - id: colorsObj - property string hifiRed: "red" - } -} diff --git a/interface/resources/qml/styles/IconButtonStyle.qml b/interface/resources/qml/styles/IconButtonStyle.qml deleted file mode 100644 index 812cd493b0..0000000000 --- a/interface/resources/qml/styles/IconButtonStyle.qml +++ /dev/null @@ -1,10 +0,0 @@ -ButtonStyle { - background: Item { anchors.fill: parent } - label: FontAwesome { - id: icon - font.pointSize: 18 - property alias unicode: text - text: control.text - color: control.enabled ? hifi.colors.text : hifi.colors.disabledText - } -} diff --git a/interface/resources/qml/windows/DefaultFrame.qml b/interface/resources/qml/windows/DefaultFrame.qml index c9d41a6935..d3b7434990 100644 --- a/interface/resources/qml/windows/DefaultFrame.qml +++ b/interface/resources/qml/windows/DefaultFrame.qml @@ -8,27 +8,10 @@ Frame { // The frame fills the parent, which should be the size of the content. // The frame decorations use negative anchor margins to extend beyond anchors.fill: parent - // Size of the controls - readonly property real iconSize: 24; - // Convenience accessor for the window - property alias window: frame.parent // FIXME needed? - property alias decoration: decoration - Rectangle { - anchors { margins: -4 } - visible: !decoration.visible - anchors.fill: parent; - color: "#7f7f7f7f"; - radius: 3; - } - - Rectangle { - id: decoration anchors { margins: -iconSize; topMargin: -iconSize * (window.closable ? 2 : 1); } - // FIXME doesn't work - // visible: window.activator.containsMouse anchors.fill: parent; color: "#7f7f7f7f"; radius: 3; @@ -36,14 +19,9 @@ Frame { // Allow dragging of the window MouseArea { id: dragMouseArea + hoverEnabled: true anchors.fill: parent - drag { - target: window - // minimumX: (decoration.width - window.width) * -1 - // minimumY: 0 - // maximumX: (window.parent.width - window.width) - 2 * (decoration.width - window.width) - // maximumY: (window.parent.height - window.height) - 2 * (decoration.height - window.height) - } + drag.target: window } Row { @@ -53,6 +31,7 @@ Frame { anchors.rightMargin: iconSize anchors.topMargin: iconSize / 2 spacing: iconSize / 4 + FontAwesome { visible: false text: "\uf08d" @@ -66,7 +45,6 @@ Frame { onClicked: { frame.pin(); mouse.accepted = false; } } } - FontAwesome { visible: window.closable text: closeClickArea.containsMouse ? "\uf057" : "\uf05c" @@ -82,56 +60,6 @@ Frame { } } } - - // Allow sizing of the window - // FIXME works in native QML, doesn't work in Interface - MouseArea { - id: sizeDrag - width: iconSize - height: iconSize - - anchors { - right: decoration.right; - bottom: decoration.bottom - bottomMargin: iconSize * 2 - } - property vector2d pressOrigin - property vector2d sizeOrigin - property bool hid: false - onPressed: { - console.log("Pressed on size") - pressOrigin = Qt.vector2d(mouseX, mouseY) - sizeOrigin = Qt.vector2d(window.content.width, window.content.height) - hid = false; - } - onReleased: { - if (hid) { - window.content.visible = true - hid = false; - } - } - - onPositionChanged: { - if (pressed) { - if (window.content.visible) { - window.content.visible = false; - hid = true; - } - var delta = Qt.vector2d(mouseX, mouseY).minus(pressOrigin); - frame.deltaSize(delta.x, delta.y) - } - } - } - - FontAwesome { - visible: window.resizable - rotation: -45 - anchors { centerIn: sizeDrag } - horizontalAlignment: Text.AlignHCenter - text: "\uf07d" - size: iconSize / 3 * 2 - style: Text.Outline; styleColor: "white" - } } } diff --git a/interface/resources/qml/windows/Fadable.qml b/interface/resources/qml/windows/Fadable.qml new file mode 100644 index 0000000000..9b88ea241f --- /dev/null +++ b/interface/resources/qml/windows/Fadable.qml @@ -0,0 +1,57 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtGraphicalEffects 1.0 +import "." +import "../styles" + +// Enable window visibility transitions +FocusScope { + id: root + HifiConstants { id: hifi } + + // Should hiding the window destroy it or just hide it? + property bool destroyOnInvisible: false + + Component.onCompleted: { + fadeTargetProperty = visible ? 1.0 : 0.0 + } + + // The target property to animate, usually scale or opacity + property alias fadeTargetProperty: root.opacity + // always start the property at 0 to enable fade in on creation + fadeTargetProperty: 0 + // DO NOT set visible to false or when derived types override it it + // will short circuit the fade in on initial visibility + // visible: false <--- NO + + // Some dialogs should be destroyed when they become + // invisible, so handle that + onVisibleChanged: { + // If someone directly set the visibility to false + // toggle it back on and use the targetVisible flag to transition + // via fading. + if ((!visible && fadeTargetProperty != 0.0) || (visible && fadeTargetProperty == 0.0)) { + var target = visible; + visible = !visible; + fadeTargetProperty = target ? 1.0 : 0.0; + return; + } + + if (!visible && destroyOnInvisible) { + destroy(); + } + } + + // The actual animator + Behavior on fadeTargetProperty { + NumberAnimation { + duration: hifi.effects.fadeInDuration + easing.type: Easing.InOutCubic + } + } + + // Once we're transparent, disable the dialog's visibility + onFadeTargetPropertyChanged: { + visible = (fadeTargetProperty != 0.0); + } +} diff --git a/interface/resources/qml/windows/Frame.qml b/interface/resources/qml/windows/Frame.qml index cef2c5abc2..dfffde4ad4 100644 --- a/interface/resources/qml/windows/Frame.qml +++ b/interface/resources/qml/windows/Frame.qml @@ -1,8 +1,95 @@ import QtQuick 2.5 +import "../controls" + Item { - signal close() - signal pin() - signal raise() - signal deltaSize(real dx, real dy) + id: frame + + // Convenience accessor for the window + property alias window: frame.parent + readonly property int iconSize: 24 + default property var decoration; + + children: [ + decoration, + sizeOutline, + debugZ, + sizeDrag, + ] + + Text { + id: debugZ + visible: DebugQML + text: "Z: " + window.z + y: -height + } + + function close() { + window.close(); + } + + function raise() { + window.raise(); + } + + function deltaSize(dx, dy) { + var newSize = Qt.vector2d(window.width + dx, window.height + dy); + newSize = clampVector(newSize, window.minSize, window.maxSize); + window.width = newSize.x + window.height = newSize.y + } + + Rectangle { + id: sizeOutline + width: window.width + height: window.height + color: "#00000000" + border.width: 4 + radius: 10 + visible: !window.content.visible + } + + MouseArea { + id: sizeDrag + width: iconSize + height: iconSize + enabled: window.resizable + x: window.width + y: window.height + property vector2d pressOrigin + property vector2d sizeOrigin + property bool hid: false + onPressed: { + console.log("Pressed on size") + pressOrigin = Qt.vector2d(mouseX, mouseY) + sizeOrigin = Qt.vector2d(window.content.width, window.content.height) + hid = false; + } + onReleased: { + if (hid) { + window.content.visible = true + hid = false; + } + } + onPositionChanged: { + if (pressed) { + if (window.content.visible) { + window.content.visible = false; + hid = true; + } + var delta = Qt.vector2d(mouseX, mouseY).minus(pressOrigin); + frame.deltaSize(delta.x, delta.y) + } + } + FontAwesome { + visible: sizeDrag.enabled + rotation: -45 + anchors { centerIn: parent } + horizontalAlignment: Text.AlignHCenter + text: "\uf07d" + size: iconSize / 3 * 2 + style: Text.Outline; styleColor: "white" + } + } + } diff --git a/interface/resources/qml/windows/ModalFrame.qml b/interface/resources/qml/windows/ModalFrame.qml new file mode 100644 index 0000000000..e0e9049828 --- /dev/null +++ b/interface/resources/qml/windows/ModalFrame.qml @@ -0,0 +1,29 @@ +import QtQuick 2.5 + +import "." +import "../controls" + +Frame { + id: frame + // The frame fills the parent, which should be the size of the content. + // The frame decorations use negative anchor margins to extend beyond + anchors.fill: parent + property alias window: frame.parent + + Rectangle { + anchors.fill: parent + anchors.margins: -4096 + visible: window.visible + color: "#7f7f7f7f"; + radius: 3; + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.AllButtons + onClicked: { } + onDoubleClicked: {} + onPressAndHold: {} + onReleased: {} + } + } +} + diff --git a/interface/resources/qml/windows/Window.qml b/interface/resources/qml/windows/Window.qml index 6b008f2872..6bc8a2bab5 100644 --- a/interface/resources/qml/windows/Window.qml +++ b/interface/resources/qml/windows/Window.qml @@ -1,53 +1,48 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtGraphicalEffects 1.0 + import "." import "../styles" -FocusScope { +// FIXME how do I set the initial position of a window without +// overriding places where the a individual client of the window +// might be setting the position with a Settings{} element? + +// FIXME how to I enable dragging without allowing the window to lay outside +// of the desktop? How do I ensure when the desktop resizes all the windows +// are still at least partially visible? +Fadable { id: window HifiConstants { id: hifi } // The Window size is the size of the content, while the frame - // decorations can extend outside it. Windows should generally not be - // given explicit height / width, but rather be allowed to conform to - // their content + // decorations can extend outside it. implicitHeight: content.height implicitWidth: content.width - property bool topLevelWindow: true + property int modality: Qt.NonModal + + readonly property bool topLevelWindow: true property string title - // Should the window include a close control? + // Should the window be closable control? property bool closable: true + // Should the window try to remain on top of other windows? + property bool alwaysOnTop: false // Should hitting the close button hide or destroy the window? property bool destroyOnCloseButton: true - // Should hiding the window destroy it or just hide it? - property bool destroyOnInvisible: false // FIXME support for pinned / unpinned pending full design // property bool pinnable: false // property bool pinned: false property bool resizable: false property vector2d minSize: Qt.vector2d(100, 100) property vector2d maxSize: Qt.vector2d(1280, 720) + enabled: visible // The content to place inside the window, determined by the client default property var content - - onContentChanged: { - if (content) { - content.anchors.fill = window - } - } - - // Default to a standard frame. Can be overriden to provide custom - // frame styles, like a full desktop frame to simulate a modal window - property var frame: DefaultFrame { - z: -1 - anchors.fill: parent - } - - // This mouse area serves to raise the window. To function, it must live - // in the window and have a higher Z-order than the content, but follow + // This mouse area serves to raise the window. To function, it must live + // in the window and have a higher Z-order than the content, but follow // the position and size of frame decoration property var activator: MouseArea { width: frame.decoration.width @@ -56,18 +51,48 @@ FocusScope { y: frame.decoration.anchors.topMargin propagateComposedEvents: true hoverEnabled: true - onPressed: { window.raise(); mouse.accepted = false; } - // Debugging visualization - // Rectangle { anchors.fill:parent; color: "#7f00ff00" } + acceptedButtons: Qt.AllButtons + onPressed: { + //console.log("Pressed on activator area"); + window.raise(); + mouse.accepted = false; + } + // Debugging +// onEntered: console.log("activator entered") +// onExited: console.log("activator exited") +// onContainsMouseChanged: console.log("Activator contains mouse " + containsMouse) +// onPositionChanged: console.log("Activator mouse position " + mouse.x + " x " + mouse.y) +// Rectangle { anchors.fill:parent; color: "#7f00ff00" } + } + + signal windowDestroyed(); + + // Default to a standard frame. Can be overriden to provide custom + // frame styles, like a full desktop frame to simulate a modal window + property var frame; + + Component { + id: defaultFrameBuilder; + DefaultFrame { anchors.fill: parent } + } + + Component { + id: modalFrameBuilder; + ModalFrame { anchors.fill: parent } + } + + Component.onCompleted: { + if (!frame) { + if (modality === Qt.NonModal) { + frame = defaultFrameBuilder.createObject(window); + } else { + frame = modalFrameBuilder.createObject(window); + } + } + raise(); } children: [ frame, content, activator ] - signal windowDestroyed(); - - Component.onCompleted: { - fadeTargetProperty = visible ? 1.0 : 0.0 - raise(); - } Component.onDestruction: { content.destroy(); @@ -76,17 +101,15 @@ FocusScope { } onParentChanged: raise(); - Connections { - target: frame - onRaise: window.raise(); - onClose: window.close(); - onPin: window.pin(); - onDeltaSize: { - var newSize = Qt.vector2d(content.width + dx, content.height + dy); - newSize = clampVector(newSize, minSize, maxSize); - window.width = newSize.x - window.height = newSize.y + onVisibleChanged: { + if (!visible && destroyOnInvisible) { + destroy(); + return; } + if (visible) { + raise(); + } + enabled = visible } function raise() { @@ -114,67 +137,6 @@ FocusScope { visible = false; } - // - // Enable window visibility transitions - // - - // The target property to animate, usually scale or opacity - property alias fadeTargetProperty: window.opacity - // always start the property at 0 to enable fade in on creation - opacity: 0 - - // Some dialogs should be destroyed when they become - // invisible, so handle that - onVisibleChanged: { - // If someone directly set the visibility to false - // toggle it back on and use the targetVisible flag to transition - // via fading. - if ((!visible && fadeTargetProperty != 0.0) || (visible && fadeTargetProperty == 0.0)) { - var target = visible; - visible = !visible; - fadeTargetProperty = target ? 1.0 : 0.0; - return; - } - if (!visible && destroyOnInvisible) { - console.log("Destroying " + window); - destroy(); - return; - } - } - - // The offscreen UI will enable an object, rather than manipulating it's - // visibility, so that we can do animations in both directions. Because - // visibility is a boolean flags, it cannot be animated. So when - // targetVisible is changed, we modify a property that can be animated, - // like scale or opacity, and then when the target animation value is reached, - // we can modify the visibility - - // The actual animator - Behavior on fadeTargetProperty { - NumberAnimation { - duration: hifi.effects.fadeInDuration - easing.type: Easing.OutCubic - } - } - - // Once we're transparent, disable the dialog's visibility - onFadeTargetPropertyChanged: { - visible = (fadeTargetProperty != 0.0); - } - - - Keys.onPressed: { - switch(event.key) { - case Qt.Key_W: - if (event.modifiers === Qt.ControlModifier) { - event.accepted = true - visible = false - } - break; - } - } - - function clamp(value, min, max) { return Math.min(Math.max(value, min), max); } @@ -185,4 +147,14 @@ FocusScope { clamp(value.y, min.y, max.y)) } + Keys.onPressed: { + switch(event.key) { + case Qt.Key_W: + if (window.closable && (event.modifiers === Qt.ControlModifier)) { + visible = false + event.accepted = true + } + break + } + } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ccde915ecc..cc175e3fae 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -80,7 +80,6 @@ #include #include #include -#include #include #include #include @@ -149,7 +148,6 @@ #endif #include "Stars.h" #include "ui/AddressBarDialog.h" -#include "ui/RecorderDialog.h" #include "ui/AvatarInputs.h" #include "ui/AssetUploadDialogFactory.h" #include "ui/DataWebDialog.h" @@ -1176,10 +1174,8 @@ void Application::initializeGL() { void Application::initializeUi() { AddressBarDialog::registerType(); - RecorderDialog::registerType(); ErrorDialog::registerType(); LoginDialog::registerType(); - MessageDialog::registerType(); VrMenu::registerType(); Tooltip::registerType(); UpdateDialog::registerType(); @@ -1843,14 +1839,6 @@ void Application::keyPressEvent(QKeyEvent* event) { } break; - case Qt::Key_X: - if (isMeta && isShifted) { -// auto offscreenUi = DependencyManager::get(); -// offscreenUi->load("TestControllers.qml"); - RecorderDialog::toggle(); - } - break; - case Qt::Key_L: if (isShifted && isMeta) { Menu::getInstance()->triggerOption(MenuOption::Log); @@ -4544,7 +4532,7 @@ bool Application::displayAvatarAttachmentConfirmationDialog(const QString& name) void Application::toggleRunningScriptsWidget() { static const QUrl url("dialogs/RunningScripts.qml"); - DependencyManager::get()->toggle(url, "RunningScripts"); + DependencyManager::get()->show(url, "RunningScripts"); //if (_runningScriptsWidget->isVisible()) { // if (_runningScriptsWidget->hasFocus()) { // _runningScriptsWidget->hide(); diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 03a4993d92..5e5576b154 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -168,9 +168,9 @@ QScriptValue WindowScriptingInterface::showAlert(const QString& message) { /// \return QScriptValue `true` if 'Yes' was clicked, `false` otherwise QScriptValue WindowScriptingInterface::showConfirm(const QString& message) { bool confirm = false; - OffscreenUi::question("", message, [&](QMessageBox::StandardButton response){ - confirm = (response == QMessageBox::Yes); - }); + if (QMessageBox::Yes == OffscreenUi::question("", message)) { + confirm = true; + } return QScriptValue(confirm); } diff --git a/interface/src/ui/AddressBarDialog.cpp b/interface/src/ui/AddressBarDialog.cpp index b208c15264..9718aafd14 100644 --- a/interface/src/ui/AddressBarDialog.cpp +++ b/interface/src/ui/AddressBarDialog.cpp @@ -61,10 +61,10 @@ void AddressBarDialog::loadForward() { } void AddressBarDialog::displayAddressOfflineMessage() { - OffscreenUi::error("That user or place is currently offline"); + OffscreenUi::critical("", "That user or place is currently offline"); } void AddressBarDialog::displayAddressNotFoundMessage() { - OffscreenUi::error("There is no address information for that user or place"); + OffscreenUi::critical("", "There is no address information for that user or place"); } diff --git a/interface/src/ui/DialogsManager.cpp b/interface/src/ui/DialogsManager.cpp index 85b8ce0273..0755ab7d25 100644 --- a/interface/src/ui/DialogsManager.cpp +++ b/interface/src/ui/DialogsManager.cpp @@ -147,10 +147,6 @@ void DialogsManager::lodTools() { _lodToolsDialog->raise(); } -void DialogsManager::toggleToolWindow() { - DependencyManager::get()->toggleToolWindow(); -} - void DialogsManager::hmdTools(bool showTools) { if (showTools) { if (!_hmdToolsDialog) { diff --git a/interface/src/ui/DialogsManager.h b/interface/src/ui/DialogsManager.h index e0b841fa12..46926a694b 100644 --- a/interface/src/ui/DialogsManager.h +++ b/interface/src/ui/DialogsManager.h @@ -66,7 +66,6 @@ signals: void addressBarToggled(); private slots: - void toggleToolWindow(); void hmdToolsClosed(); private: diff --git a/interface/src/ui/MarketplaceDialog.cpp b/interface/src/ui/MarketplaceDialog.cpp deleted file mode 100644 index 11286e0ee1..0000000000 --- a/interface/src/ui/MarketplaceDialog.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// -// MarketplaceDialog.cpp -// -// Created by Bradley Austin Davis on 2015/04/14 -// 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 "Application.h" -#include "MarketplaceDialog.h" -#include "DependencyManager.h" - -HIFI_QML_DEF(MarketplaceDialog) - - -MarketplaceDialog::MarketplaceDialog(QQuickItem* parent) : OffscreenQmlDialog(parent) { -} - -bool MarketplaceDialog::navigationRequested(const QString& url) { - qDebug() << url; - if (qApp->canAcceptURL(url)) { - if (qApp->acceptURL(url)) { - return false; // we handled it, so QWebPage doesn't need to handle it - } - } - return true; -} diff --git a/interface/src/ui/MarketplaceDialog.h b/interface/src/ui/MarketplaceDialog.h deleted file mode 100644 index 2440c3e07c..0000000000 --- a/interface/src/ui/MarketplaceDialog.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// MarketplaceDialog.h -// -// Created by Bradley Austin Davis on 2015/04/14 -// 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 -// - -#pragma once -#ifndef hifi_MarketplaceDialog_h -#define hifi_MarketplaceDialog_h - -#include - -class MarketplaceDialog : public OffscreenQmlDialog -{ - Q_OBJECT - HIFI_QML_DECL - -public: - MarketplaceDialog(QQuickItem* parent = nullptr); - - Q_INVOKABLE bool navigationRequested(const QString& url); - -}; - -#endif diff --git a/interface/src/ui/RecorderDialog.cpp b/interface/src/ui/RecorderDialog.cpp deleted file mode 100644 index ddefa9fbd9..0000000000 --- a/interface/src/ui/RecorderDialog.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// -// Created by Bradley Austin Davis on 2015/11/14 -// 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 "RecorderDialog.h" - -#include - -#include "DependencyManager.h" - -HIFI_QML_DEF(RecorderDialog) - -RecorderDialog::RecorderDialog(QQuickItem* parent) : OffscreenQmlDialog(parent) { -} - -void RecorderDialog::hide() { - ((QQuickItem*)parent())->setEnabled(false); -} diff --git a/interface/src/ui/RecorderDialog.h b/interface/src/ui/RecorderDialog.h deleted file mode 100644 index f4f0a7c2d8..0000000000 --- a/interface/src/ui/RecorderDialog.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// Created by Bradley Austin Davis on 2015/11/14 -// 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 -// - -#pragma once -#ifndef hifi_RecorderDialog_h -#define hifi_RecorderDialog_h - -#include - -class RecorderDialog : public OffscreenQmlDialog { - Q_OBJECT - HIFI_QML_DECL - -public: - RecorderDialog(QQuickItem* parent = nullptr); - -signals: - -protected: - void hide(); -}; - -#endif diff --git a/libraries/ui/src/MessageDialog.cpp b/libraries/ui/src/MessageDialog.cpp deleted file mode 100644 index 695f87552a..0000000000 --- a/libraries/ui/src/MessageDialog.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// -// MessageDialog.cpp -// -// Created by Bradley Austin Davis on 2015/04/14 -// 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 "MessageDialog.h" - -HIFI_QML_DEF(MessageDialog) - -MessageDialog::MessageDialog(QQuickItem* parent) : OffscreenQmlDialog(parent) { - _buttons = StandardButtons(Ok | Cancel); -} - -MessageDialog::~MessageDialog() { -} - -QString MessageDialog::text() const { - return _text; -} - -QString MessageDialog::informativeText() const { - return _informativeText; -} - -QString MessageDialog::detailedText() const { - return _detailedText; -} - -MessageDialog::Icon MessageDialog::icon() const { - return _icon; -} - -void MessageDialog::setVisible(bool v) { - OffscreenQmlDialog::setVisible(v); -} - -void MessageDialog::setText(const QString& arg) { - if (arg != _text) { - _text = arg; - emit textChanged(); - } -} - -void MessageDialog::setInformativeText(const QString& arg) { - if (arg != _informativeText) { - _informativeText = arg; - emit informativeTextChanged(); - } -} - -void MessageDialog::setDetailedText(const QString& arg) { - if (arg != _detailedText) { - _detailedText = arg; - emit detailedTextChanged(); - } -} - -void MessageDialog::setIcon(MessageDialog::Icon icon) { - if (icon != _icon) { - _icon = icon; - emit iconChanged(); - } -} - -void MessageDialog::setStandardButtons(StandardButtons buttons) { - if (buttons != _buttons) { - _buttons = buttons; - emit standardButtonsChanged(); - } -} - -void MessageDialog::click(StandardButton button) { - // FIXME try to do it more like the standard dialog - click(StandardButton(button), ButtonRole::NoRole); -} - -MessageDialog::StandardButtons MessageDialog::standardButtons() const { - return _buttons; -} - -MessageDialog::StandardButton MessageDialog::clickedButton() const { - return _clickedButton; -} - -void MessageDialog::click(StandardButton button, ButtonRole) { - _clickedButton = button; - if (_resultCallback) { - _resultCallback(QMessageBox::StandardButton(_clickedButton)); - } - hide(); -} - -void MessageDialog::accept() { - // enter key is treated like OK - if (_clickedButton == NoButton) - _clickedButton = Ok; - if (_resultCallback) { - _resultCallback(QMessageBox::StandardButton(_clickedButton)); - } - OffscreenQmlDialog::accept(); -} - -void MessageDialog::reject() { - // escape key is treated like cancel - if (_clickedButton == NoButton) - _clickedButton = Cancel; - if (_resultCallback) { - _resultCallback(QMessageBox::StandardButton(_clickedButton)); - } - OffscreenQmlDialog::reject(); -} - -void MessageDialog::setResultCallback(OffscreenUi::ButtonCallback callback) { - _resultCallback = callback; -} diff --git a/libraries/ui/src/MessageDialog.h b/libraries/ui/src/MessageDialog.h deleted file mode 100644 index 461bca8251..0000000000 --- a/libraries/ui/src/MessageDialog.h +++ /dev/null @@ -1,100 +0,0 @@ -// -// MessageDialog.h -// -// Created by Bradley Austin Davis on 2015/04/14 -// 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 -// - -#pragma once -#ifndef hifi_MessageDialog_h -#define hifi_MessageDialog_h - -#include "OffscreenQmlDialog.h" - -class MessageDialog : public OffscreenQmlDialog -{ - Q_OBJECT - HIFI_QML_DECL - -private: - Q_ENUMS(Icon) - Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) - Q_PROPERTY(QString informativeText READ informativeText WRITE setInformativeText NOTIFY informativeTextChanged) - Q_PROPERTY(QString detailedText READ detailedText WRITE setDetailedText NOTIFY detailedTextChanged) - Q_PROPERTY(Icon icon READ icon WRITE setIcon NOTIFY iconChanged) - Q_PROPERTY(StandardButtons standardButtons READ standardButtons WRITE setStandardButtons NOTIFY standardButtonsChanged) - Q_PROPERTY(StandardButton clickedButton READ clickedButton NOTIFY buttonClicked) - -public: - enum Icon { NoIcon, Information, Warning, Critical, Question }; - - enum ButtonRole { - // keep this in sync with QDialogButtonBox::ButtonRole and QPlatformDialogHelper::ButtonRole - InvalidRole = -1, - AcceptRole, - RejectRole, - DestructiveRole, - ActionRole, - HelpRole, - YesRole, - NoRole, - ResetRole, - ApplyRole, - - NRoles - }; - - MessageDialog(QQuickItem* parent = 0); - virtual ~MessageDialog(); - - QString text() const; - QString informativeText() const; - QString detailedText() const; - Icon icon() const; - -public slots: - virtual void setVisible(bool v); - void setText(const QString& arg); - void setInformativeText(const QString& arg); - void setDetailedText(const QString& arg); - void setIcon(Icon icon); - void setStandardButtons(StandardButtons buttons); - void setResultCallback(OffscreenUi::ButtonCallback callback); - void click(StandardButton button); - StandardButtons standardButtons() const; - StandardButton clickedButton() const; - -signals: - void textChanged(); - void informativeTextChanged(); - void detailedTextChanged(); - void iconChanged(); - void standardButtonsChanged(); - void buttonClicked(); - void discard(); - void help(); - void yes(); - void no(); - void apply(); - void reset(); - -protected slots: - virtual void click(StandardButton button, ButtonRole); - virtual void accept(); - virtual void reject(); - -private: - QString _title; - QString _text; - QString _informativeText; - QString _detailedText; - Icon _icon{ Information }; - StandardButtons _buttons; - StandardButton _clickedButton{ NoButton }; - OffscreenUi::ButtonCallback _resultCallback; -}; - -#endif // hifi_MessageDialog_h diff --git a/libraries/ui/src/OffscreenQmlDialog.cpp b/libraries/ui/src/OffscreenQmlDialog.cpp index eba81f708b..43514c4761 100644 --- a/libraries/ui/src/OffscreenQmlDialog.cpp +++ b/libraries/ui/src/OffscreenQmlDialog.cpp @@ -17,7 +17,7 @@ OffscreenQmlDialog::~OffscreenQmlDialog() { } void OffscreenQmlDialog::hide() { - static_cast(parent())->setEnabled(false); + static_cast(parent())->setVisible(false); } QString OffscreenQmlDialog::title() const { diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 7188d49846..479a7721ce 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -16,10 +16,6 @@ #include #include - -#include "ErrorDialog.h" -#include "MessageDialog.h" - // Needs to match the constants in resources/qml/Global.js class OffscreenFlags : public QObject { Q_OBJECT @@ -117,7 +113,7 @@ void OffscreenUi::show(const QUrl& url, const QString& name, std::functionfindChild(name); } if (item) { - item->setEnabled(true); + item->setVisible(true); } } @@ -129,109 +125,103 @@ void OffscreenUi::toggle(const QUrl& url, const QString& name, std::functionfindChild(name); } if (item) { - item->setEnabled(!item->isEnabled()); + item->setVisible(!item->isVisible()); } } -void OffscreenUi::messageBox(const QString& title, const QString& text, - ButtonCallback callback, - QMessageBox::Icon icon, - QMessageBox::StandardButtons buttons) { - MessageDialog* pDialog{ nullptr }; - MessageDialog::show([&](QQmlContext* ctx, QObject* item) { - pDialog = item->findChild(); - pDialog->setIcon((MessageDialog::Icon)icon); - pDialog->setTitle(title); - pDialog->setText(text); - pDialog->setStandardButtons(MessageDialog::StandardButtons(static_cast(buttons))); - pDialog->setResultCallback(callback); - }); - pDialog->setEnabled(true); -} +class MessageBoxListener : public QObject { + Q_OBJECT -void OffscreenUi::information(const QString& title, const QString& text, - ButtonCallback callback, - QMessageBox::StandardButtons buttons) { - messageBox(title, text, callback, - static_cast(MessageDialog::Information), buttons); -} + friend class OffscreenUi; -void OffscreenUi::question(const QString& title, const QString& text, - ButtonCallback callback, - QMessageBox::StandardButtons buttons) { - - bool waiting = true; - ButtonCallback blockingCallback = [&](QMessageBox::StandardButton response){ - callback(response); // call the actual callback - waiting = false; - }; - - messageBox(title, text, blockingCallback, - static_cast(MessageDialog::Question), buttons); - - // block until the call back has been called - while (waiting) { - QCoreApplication::processEvents(); + MessageBoxListener(QQuickItem* messageBox) : _messageBox(messageBox) { + if (!_messageBox) { + _finished = true; + return; + } + connect(_messageBox, SIGNAL(selected(int)), this, SLOT(onSelected(int))); + connect(_messageBox, SIGNAL(destroyed()), this, SLOT(onDestroyed())); } + + ~MessageBoxListener() { + disconnect(_messageBox); + } + + QMessageBox::StandardButton waitForResult() { + while (!_finished) { + QCoreApplication::processEvents(); + } + return _result; + } + +private slots: + void onSelected(int button) { + _result = static_cast(button); + _finished = true; + disconnect(_messageBox); + } + + void onDestroyed() { + _finished = true; + disconnect(_messageBox); + } + +private: + bool _finished { false }; + QMessageBox::StandardButton _result { QMessageBox::StandardButton::NoButton }; + QQuickItem* const _messageBox; +}; + +QMessageBox::StandardButton OffscreenUi::messageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { + if (QThread::currentThread() != thread()) { + QMessageBox::StandardButton result = QMessageBox::StandardButton::NoButton; + QMetaObject::invokeMethod(this, "messageBox", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QMessageBox::StandardButton, result), + Q_ARG(QMessageBox::Icon, icon), + Q_ARG(QString, title), + Q_ARG(QString, text), + Q_ARG(QMessageBox::StandardButtons, buttons), + Q_ARG(QMessageBox::StandardButton, defaultButton)); + return result; + } + + QVariantMap map; + map.insert("title", title); + map.insert("text", text); + map.insert("icon", icon); + map.insert("buttons", buttons.operator int()); + map.insert("defaultButton", defaultButton); + QVariant result; + bool invokeResult = QMetaObject::invokeMethod(getDesktop(), "messageBox", + Q_RETURN_ARG(QVariant, result), + Q_ARG(QVariant, QVariant::fromValue(map))); + + if (!invokeResult) { + qWarning() << "Failed to create message box"; + return QMessageBox::StandardButton::NoButton; + } + + auto resultButton = MessageBoxListener(qvariant_cast(result)).waitForResult(); + qDebug() << "Message box got a result of " << resultButton; + return resultButton; } -QMessageBox::StandardButton OffscreenUi::question(void* ignored, const QString& title, const QString& text, - QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { - - QMessageBox::StandardButton result = defaultButton; - - OffscreenUi::question(title, text, [&](QMessageBox::StandardButton response){ - result = response; - }, buttons); - - return result; -} - - -void OffscreenUi::warning(const QString& title, const QString& text, - ButtonCallback callback, - QMessageBox::StandardButtons buttons) { - messageBox(title, text, callback, - static_cast(MessageDialog::Warning), buttons); -} - -QMessageBox::StandardButton OffscreenUi::warning(void* ignored, const QString& title, const QString& text, +QMessageBox::StandardButton OffscreenUi::critical(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { - - bool waiting = true; - QMessageBox::StandardButton result = defaultButton; - - OffscreenUi::warning(title, text, [&](QMessageBox::StandardButton response){ - result = response; - waiting = false; - }, buttons); - - // block until the call back has been called - while (waiting) { - QCoreApplication::processEvents(); - } - - return result; + return DependencyManager::get()->messageBox(QMessageBox::Icon::Critical, title, text, buttons, defaultButton); } - - -void OffscreenUi::critical(const QString& title, const QString& text, - ButtonCallback callback, - QMessageBox::StandardButtons buttons) { - messageBox(title, text, callback, - static_cast(MessageDialog::Critical), buttons); +QMessageBox::StandardButton OffscreenUi::information(const QString& title, const QString& text, + QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { + return DependencyManager::get()->messageBox(QMessageBox::Icon::Critical, title, text, buttons, defaultButton); } - -void OffscreenUi::error(const QString& text) { - ErrorDialog* pDialog{ nullptr }; - ErrorDialog::show([&](QQmlContext* ctx, QObject* item) { - pDialog = item->findChild(); - pDialog->setText(text); - }); - pDialog->setEnabled(true); +QMessageBox::StandardButton OffscreenUi::question(const QString& title, const QString& text, + QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { + return DependencyManager::get()->messageBox(QMessageBox::Icon::Critical, title, text, buttons, defaultButton); +} +QMessageBox::StandardButton OffscreenUi::warning(const QString& title, const QString& text, + QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { + return DependencyManager::get()->messageBox(QMessageBox::Icon::Critical, title, text, buttons, defaultButton); } - -OffscreenUi::ButtonCallback OffscreenUi::NO_OP_CALLBACK = [](QMessageBox::StandardButton) {}; bool OffscreenUi::navigationFocused() { return offscreenFlags->isNavigationFocused(); @@ -245,16 +235,14 @@ void OffscreenUi::createDesktop() { if (_desktop) { qDebug() << "Desktop already created"; } + getRootContext()->setContextProperty("DebugQML", false); _desktop = dynamic_cast(load("Root.qml")); Q_ASSERT(_desktop); getRootContext()->setContextProperty("Desktop", _desktop); + _desktop->setProperty("offscreenWindow", QVariant::fromValue(getWindow())); _toolWindow = _desktop->findChild("ToolWindow"); } -void OffscreenUi::toggleToolWindow() { - _toolWindow->setEnabled(!_toolWindow->isEnabled()); -} - QQuickItem* OffscreenUi::getDesktop() { return _desktop; } diff --git a/libraries/ui/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h index 4add90be75..b42fe50a92 100644 --- a/libraries/ui/src/OffscreenUi.h +++ b/libraries/ui/src/OffscreenUi.h @@ -40,45 +40,46 @@ public: Q_INVOKABLE void executeOnUiThread(std::function function); Q_INVOKABLE QVariant returnFromUiThread(std::function function); - // Messagebox replacement functions - using ButtonCallback = std::function; - static ButtonCallback NO_OP_CALLBACK; - - static void messageBox(const QString& title, const QString& text, - ButtonCallback f, - QMessageBox::Icon icon, - QMessageBox::StandardButtons buttons); - - static void information(const QString& title, const QString& text, - ButtonCallback callback = NO_OP_CALLBACK, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); - - /// Note: will block until user clicks a response to the question - static void question(const QString& title, const QString& text, - ButtonCallback callback = NO_OP_CALLBACK, - QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No)); - + /// Same design as QMessageBox::critical(), will block, returns result + static QMessageBox::StandardButton critical(void* ignored, const QString& title, const QString& text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton) { + return critical(title, text, buttons, defaultButton); + } + /// Same design as QMessageBox::information(), will block, returns result + static QMessageBox::StandardButton information(void* ignored, const QString& title, const QString& text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton) { + return information(title, text, buttons, defaultButton); + } /// Same design as QMessageBox::question(), will block, returns result - static QMessageBox::StandardButton question(void* ignored, const QString& title, const QString& text, - QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No), - QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); - - static void warning(const QString& title, const QString& text, - ButtonCallback callback = NO_OP_CALLBACK, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); - + static QMessageBox::StandardButton question(void* ignored, const QString& title, const QString& text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton) { + return question(title, text, buttons, defaultButton); + } /// Same design as QMessageBox::warning(), will block, returns result static QMessageBox::StandardButton warning(void* ignored, const QString& title, const QString& text, - QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No), + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton) { + return warning(title, text, buttons, defaultButton); + } + + static QMessageBox::StandardButton critical(const QString& title, const QString& text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); + static QMessageBox::StandardButton information(const QString& title, const QString& text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); + static QMessageBox::StandardButton question(const QString& title, const QString& text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); + static QMessageBox::StandardButton warning(const QString& title, const QString& text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); - static void critical(const QString& title, const QString& text, - ButtonCallback callback = NO_OP_CALLBACK, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); + QMessageBox::StandardButton messageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton); - static void error(const QString& text); // Interim dialog in new style - - void toggleToolWindow(); private: QQuickItem* _desktop { nullptr }; QQuickItem* _toolWindow { nullptr }; diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index 26561a43b6..4a827f57db 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -250,16 +250,13 @@ QQuickItem* QmlWindowClass::asQuickItem() const { } void QmlWindowClass::setVisible(bool visible) { - // For tool window tabs we special case visiblility as enable / disable of the tab, not the window - // The tool window itself has special logic based on whether any tabs are enabled + QQuickItem* targetWindow = asQuickItem(); if (_toolWindow) { - auto targetTab = dynamic_cast(_qmlWindow); - DependencyManager::get()->executeOnUiThread([=] { - targetTab->setEnabled(visible); - //emit visibilityChanged(visible); - }); + // For tool window tabs we special case visibility as a function call on the tab parent + // The tool window itself has special logic based on whether any tabs are visible + auto offscreenUi = DependencyManager::get(); + QMetaObject::invokeMethod(targetWindow, "showTabForUrl", Qt::QueuedConnection, Q_ARG(QVariant, _source), Q_ARG(QVariant, visible)); } else { - QQuickItem* targetWindow = asQuickItem(); DependencyManager::get()->executeOnUiThread([=] { targetWindow->setVisible(visible); //emit visibilityChanged(visible); @@ -282,7 +279,6 @@ bool QmlWindowClass::isVisible() const { } } - glm::vec2 QmlWindowClass::getPosition() const { QQuickItem* targetWindow = asQuickItem(); QVariant result = DependencyManager::get()->returnFromUiThread([&]()->QVariant { diff --git a/tests/ui/CMakeLists.txt b/tests/ui/CMakeLists.txt index f94a0b85c0..0a5d6796e0 100644 --- a/tests/ui/CMakeLists.txt +++ b/tests/ui/CMakeLists.txt @@ -1,33 +1 @@ - -set(TARGET_NAME "ui-test") - -# This is not a testcase -- just set it up as a regular hifi project -setup_hifi_project(Network OpenGL Qml Quick Script WebChannel WebEngine WebSockets) - -set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") - -if (WIN32) - target_link_libraries(${TARGET_NAME} wsock32.lib opengl32.lib Winmm.lib) - # Issue causes build failure unless we add this directory. - # See https://bugreports.qt.io/browse/QTBUG-43351 - add_paths_to_fixup_libs(${Qt5_DIR}/../../../plugins/qtwebengine) -endif() - -# link in the shared libraries -link_hifi_libraries(shared networking gl gpu ui) - -# copy the resources files beside the executable -add_custom_command(TARGET ${TARGET_NAME} POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy_directory - "${PROJECT_SOURCE_DIR}/qml" - $/qml -) - - -target_glew() - -if (WIN32) - set(EXTRA_DEPLOY_OPTIONS "--qmldir ${PROJECT_SOURCE_DIR}/../../interface/resources/qml") -endif() - -package_libraries_for_deployment() +# This folder contains code for testing the QML UI using Qt Creator. It is not intended to be included in the CMake project diff --git a/interface/resources/qml/Palettes.qml b/tests/ui/qml/Palettes.qml similarity index 100% rename from interface/resources/qml/Palettes.qml rename to tests/ui/qml/Palettes.qml diff --git a/tests/ui/qml/StubMenu.qml b/tests/ui/qml/StubMenu.qml new file mode 100644 index 0000000000..63c9b5b3ea --- /dev/null +++ b/tests/ui/qml/StubMenu.qml @@ -0,0 +1,734 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 + +import "../../../interface/resources/qml/hifi" + +Menu { + property var menuOption: MenuOption {} + Item { + Action { + id: login; + text: menuOption.login + } + Action { + id: update; + text: "Update"; + enabled: false + } + Action { + id: crashReporter; + text: "Crash Reporter..."; + enabled: false + } + Action { + id: help; + text: menuOption.help + onTriggered: Application.showHelp() + } + Action { + id: aboutApp; + text: menuOption.aboutApp + } + Action { + id: quit; + text: menuOption.quit + } + + ExclusiveGroup { id: renderResolutionGroup } + Action { + id: renderResolutionOne; + exclusiveGroup: renderResolutionGroup; + text: menuOption.renderResolutionOne; + checkable: true; + checked: true + } + Action { + id: renderResolutionTwoThird; + exclusiveGroup: renderResolutionGroup; + text: menuOption.renderResolutionTwoThird; + checkable: true + } + Action { + id: renderResolutionHalf; + exclusiveGroup: renderResolutionGroup; + text: menuOption.renderResolutionHalf; + checkable: true + } + Action { + id: renderResolutionThird; + exclusiveGroup: renderResolutionGroup; + text: menuOption.renderResolutionThird; + checkable: true + } + Action { + id: renderResolutionQuarter; + exclusiveGroup: renderResolutionGroup; + text: menuOption.renderResolutionQuarter; + checkable: true + } + + ExclusiveGroup { id: ambientLightGroup } + Action { + id: renderAmbientLightGlobal; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLightGlobal; + checkable: true; + checked: true + } + Action { + id: renderAmbientLight0; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLight0; + checkable: true; + checked: true + } + Action { + id: renderAmbientLight1; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLight1; + checkable: true; + checked: true + } + Action { + id: renderAmbientLight2; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLight2; + checkable: true; + checked: true + } + Action { + id: renderAmbientLight3; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLight3; + checkable: true; + checked: true + } + Action { + id: renderAmbientLight4; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLight4; + checkable: true; + checked: true + } + Action { + id: renderAmbientLight5; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLight5; + checkable: true; + checked: true + } + Action { + id: renderAmbientLight6; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLight6; + checkable: true; + checked: true + } + Action { + id: renderAmbientLight7; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLight7; + checkable: true; + checked: true + } + Action { + id: renderAmbientLight8; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLight8; + checkable: true; + checked: true + } + Action { + id: renderAmbientLight9; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLight9; + checkable: true; + checked: true + } + Action { + id: preferences + shortcut: StandardKey.Preferences + text: menuOption.preferences + onTriggered: dialogsManager.editPreferences() + } + + } + + Menu { + title: "File" + MenuItem { + action: login + } + MenuItem { + action: update + } + MenuItem { + action: help + } + MenuItem { + action: crashReporter + } + MenuItem { + action: aboutApp + } + MenuItem { + action: quit + } + } + + Menu { + title: "Edit" + MenuItem { + text: "Undo" } + MenuItem { + text: "Redo" } + MenuItem { + text: menuOption.runningScripts + } + MenuItem { + text: menuOption.loadScript + } + MenuItem { + text: menuOption.loadScriptURL + } + MenuItem { + text: menuOption.stopAllScripts + } + MenuItem { + text: menuOption.reloadAllScripts + } + MenuItem { + text: menuOption.scriptEditor + } + MenuItem { + text: menuOption.console_ + } + MenuItem { + text: menuOption.reloadContent + } + MenuItem { + text: menuOption.packageModel + } + } + + Menu { + title: "Audio" + MenuItem { + text: menuOption.muteAudio; + checkable: true + } + MenuItem { + text: menuOption.audioTools; + checkable: true + } + } + Menu { + title: "Avatar" + // Avatar > Attachments... + MenuItem { + text: menuOption.attachments + } + Menu { + title: "Size" + // Avatar > Size > Increase + MenuItem { + text: menuOption.increaseAvatarSize + } + // Avatar > Size > Decrease + MenuItem { + text: menuOption.decreaseAvatarSize + } + // Avatar > Size > Reset + MenuItem { + text: menuOption.resetAvatarSize + } + } + // Avatar > Reset Sensors + MenuItem { + text: menuOption.resetSensors + } + } + Menu { + title: "Display" + } + Menu { + title: "View" + ExclusiveGroup { + id: cameraModeGroup + } + + MenuItem { + text: menuOption.firstPerson; + checkable: true; + exclusiveGroup: cameraModeGroup + } + MenuItem { + text: menuOption.thirdPerson; + checkable: true; + exclusiveGroup: cameraModeGroup + } + MenuItem { + text: menuOption.fullscreenMirror; + checkable: true; + exclusiveGroup: cameraModeGroup + } + MenuItem { + text: menuOption.independentMode; + checkable: true; + exclusiveGroup: cameraModeGroup + } + MenuItem { + text: menuOption.cameraEntityMode; + checkable: true; + exclusiveGroup: cameraModeGroup + } + MenuSeparator{} + MenuItem { + text: menuOption.miniMirror; + checkable: true + } + } + Menu { + title: "Navigate" + MenuItem { + text: "Home" } + MenuItem { + text: menuOption.addressBar + } + MenuItem { + text: "Directory" } + MenuItem { + text: menuOption.copyAddress + } + MenuItem { + text: menuOption.copyPath + } + } + Menu { + title: "Settings" + MenuItem { + text: "Advanced Menus" } + MenuItem { + text: "Developer Menus" } + MenuItem { + text: menuOption.preferences + } + MenuItem { + text: "Avatar..." } + MenuItem { + text: "Audio..." } + MenuItem { + text: "LOD..." } + MenuItem { + text: menuOption.inputMenu + } + } + Menu { + title: "Developer" + Menu { + title: "Render" + MenuItem { + text: menuOption.atmosphere; + checkable: true + } + MenuItem { + text: menuOption.worldAxes; + checkable: true + } + MenuItem { + text: menuOption.debugAmbientOcclusion; + checkable: true + } + MenuItem { + text: menuOption.antialiasing; + checkable: true + } + MenuItem { + text: menuOption.stars; + checkable: true + } + Menu { + title: menuOption.renderAmbientLight + MenuItem { + action: renderAmbientLightGlobal; } + MenuItem { + action: renderAmbientLight0; } + MenuItem { + action: renderAmbientLight1; } + MenuItem { + action: renderAmbientLight2; } + MenuItem { + action: renderAmbientLight3; } + MenuItem { + action: renderAmbientLight4; } + MenuItem { + action: renderAmbientLight5; } + MenuItem { + action: renderAmbientLight6; } + MenuItem { + action: renderAmbientLight7; } + MenuItem { + action: renderAmbientLight8; } + MenuItem { + action: renderAmbientLight9; } + } + MenuItem { + text: menuOption.throttleFPSIfNotFocus; + checkable: true + } + Menu { + title: menuOption.renderResolution + MenuItem { + action: renderResolutionOne + } + MenuItem { + action: renderResolutionTwoThird + } + MenuItem { + action: renderResolutionHalf + } + MenuItem { + action: renderResolutionThird + } + MenuItem { + action: renderResolutionQuarter + } + } + MenuItem { + text: menuOption.lodTools + } + } + Menu { + title: "Assets" + MenuItem { + text: menuOption.uploadAsset + } + MenuItem { + text: menuOption.assetMigration + } + } + Menu { + title: "Avatar" + Menu { + title: "Face Tracking" + MenuItem { + text: menuOption.noFaceTracking; + checkable: true + } + MenuItem { + text: menuOption.faceshift; + checkable: true + } + MenuItem { + text: menuOption.useCamera; + checkable: true + } + MenuSeparator{} + MenuItem { + text: menuOption.binaryEyelidControl; + checkable: true + } + MenuItem { + text: menuOption.coupleEyelids; + checkable: true + } + MenuItem { + text: menuOption.useAudioForMouth; + checkable: true + } + MenuItem { + text: menuOption.velocityFilter; + checkable: true + } + MenuItem { + text: menuOption.calibrateCamera + } + MenuSeparator{} + MenuItem { + text: menuOption.muteFaceTracking; + checkable: true + } + MenuItem { + text: menuOption.autoMuteAudio; + checkable: true + } + } + Menu { + title: "Eye Tracking" + MenuItem { + text: menuOption.sMIEyeTracking; + checkable: true + } + Menu { + title: "Calibrate" + MenuItem { + text: menuOption.onePointCalibration + } + MenuItem { + text: menuOption.threePointCalibration + } + MenuItem { + text: menuOption.fivePointCalibration + } + } + MenuItem { + text: menuOption.simulateEyeTracking; + checkable: true + } + } + MenuItem { + text: menuOption.avatarReceiveStats; + checkable: true + } + MenuItem { + text: menuOption.renderBoundingCollisionShapes; + checkable: true + } + MenuItem { + text: menuOption.renderLookAtVectors; + checkable: true + } + MenuItem { + text: menuOption.renderLookAtTargets; + checkable: true + } + MenuItem { + text: menuOption.renderFocusIndicator; + checkable: true + } + MenuItem { + text: menuOption.showWhosLookingAtMe; + checkable: true + } + MenuItem { + text: menuOption.fixGaze; + checkable: true + } + MenuItem { + text: menuOption.animDebugDrawDefaultPose; + checkable: true + } + MenuItem { + text: menuOption.animDebugDrawAnimPose; + checkable: true + } + MenuItem { + text: menuOption.animDebugDrawPosition; + checkable: true + } + MenuItem { + text: menuOption.meshVisible; + checkable: true + } + MenuItem { + text: menuOption.disableEyelidAdjustment; + checkable: true + } + MenuItem { + text: menuOption.turnWithHead; + checkable: true + } + MenuItem { + text: menuOption.comfortMode; + checkable: true + } + MenuItem { + text: menuOption.keyboardMotorControl; + checkable: true + } + MenuItem { + text: menuOption.scriptedMotorControl; + checkable: true + } + MenuItem { + text: menuOption.enableCharacterController; + checkable: true + } + } + Menu { + title: "Hands" + MenuItem { + text: menuOption.displayHandTargets; + checkable: true + } + MenuItem { + text: menuOption.lowVelocityFilter; + checkable: true + } + Menu { + title: "Leap Motion" + MenuItem { + text: menuOption.leapMotionOnHMD; + checkable: true + } + } + } + Menu { + title: "Entities" + MenuItem { + text: menuOption.octreeStats + } + MenuItem { + text: menuOption.showRealtimeEntityStats; + checkable: true + } + } + Menu { + title: "Network" + MenuItem { + text: menuOption.reloadContent + } + MenuItem { + text: menuOption.disableNackPackets; + checkable: true + } + MenuItem { + text: menuOption.disableActivityLogger; + checkable: true + } + MenuItem { + text: menuOption.cachesSize + } + MenuItem { + text: menuOption.diskCacheEditor + } + MenuItem { + text: menuOption.showDSConnectTable + } + MenuItem { + text: menuOption.bandwidthDetails + } + } + Menu { + title: "Timing" + Menu { + title: "Performance Timer" + MenuItem { + text: menuOption.displayDebugTimingDetails; + checkable: true + } + MenuItem { + text: menuOption.onlyDisplayTopTen; + checkable: true + } + MenuItem { + text: menuOption.expandUpdateTiming; + checkable: true + } + MenuItem { + text: menuOption.expandMyAvatarTiming; + checkable: true + } + MenuItem { + text: menuOption.expandMyAvatarSimulateTiming; + checkable: true + } + MenuItem { + text: menuOption.expandOtherAvatarTiming; + checkable: true + } + MenuItem { + text: menuOption.expandPaintGLTiming; + checkable: true + } + } + MenuItem { + text: menuOption.frameTimer; + checkable: true + } + MenuItem { + text: menuOption.runTimingTests + } + MenuItem { + text: menuOption.pipelineWarnings; + checkable: true + } + MenuItem { + text: menuOption.logExtraTimings; + checkable: true + } + MenuItem { + text: menuOption.suppressShortTimings; + checkable: true + } + } + Menu { + title: "Audio" + MenuItem { + text: menuOption.audioNoiseReduction; + checkable: true + } + MenuItem { + text: menuOption.echoServerAudio; + checkable: true + } + MenuItem { + text: menuOption.echoLocalAudio; + checkable: true + } + MenuItem { + text: menuOption.muteEnvironment + } + Menu { + title: "Audio" + MenuItem { + text: menuOption.audioScope; + checkable: true + } + MenuItem { + text: menuOption.audioScopePause; + checkable: true + } + Menu { + title: "Display Frames" + ExclusiveGroup { + id: audioScopeFramesGroup + } + MenuItem { + exclusiveGroup: audioScopeFramesGroup; + text: menuOption.audioScopeFiveFrames; + checkable: true + } + MenuItem { + exclusiveGroup: audioScopeFramesGroup; + text: menuOption.audioScopeTwentyFrames; + checkable: true + } + MenuItem { + exclusiveGroup: audioScopeFramesGroup; + text: menuOption.audioScopeFiftyFrames; + checkable: true + } + } + MenuItem { + text: menuOption.audioNetworkStats + } + } + } + Menu { + title: "Physics" + MenuItem { + text: menuOption.physicsShowOwned; + checkable: true + } + MenuItem { + text: menuOption.physicsShowHulls; + checkable: true + } + } + MenuItem { + text: menuOption.displayCrashOptions; + checkable: true + } + MenuItem { + text: menuOption.crashInterface + } + MenuItem { + text: menuOption.log + } + MenuItem { + text: menuOption.stats; + checkable: true + } + } +} diff --git a/interface/resources/qml/test/Stubs.qml b/tests/ui/qml/Stubs.qml similarity index 98% rename from interface/resources/qml/test/Stubs.qml rename to tests/ui/qml/Stubs.qml index f23e5c89ee..f46fad3652 100644 --- a/interface/resources/qml/test/Stubs.qml +++ b/tests/ui/qml/Stubs.qml @@ -20,7 +20,7 @@ Item { Item { objectName: "ScriptDiscoveryService" - property var scriptsModelFilter: scriptsModel + //property var scriptsModelFilter: scriptsModel signal scriptCountChanged() property var _runningScripts:[ { name: "wireFrameTest.js", url: "foo/wireframetest.js", path: "foo/wireframetest.js", local: true }, @@ -106,7 +106,7 @@ Item { function closeDialog(item) { item = findDialog(item); if (item) { - item.enabled = false + item.visible = false } else { console.warn("Could not find top level dialog") } diff --git a/interface/resources/qml/TestControllers.qml b/tests/ui/qml/TestControllers.qml similarity index 99% rename from interface/resources/qml/TestControllers.qml rename to tests/ui/qml/TestControllers.qml index 482616203f..e9a7fb49e5 100644 --- a/interface/resources/qml/TestControllers.qml +++ b/tests/ui/qml/TestControllers.qml @@ -42,7 +42,6 @@ HifiControls.VrDialog { } Component.onCompleted: { - enabled = true var xboxRegex = /^GamePad/; var hydraRegex = /^Hydra/; for (var prop in Controller.Hardware) { diff --git a/interface/resources/qml/TestDialog.qml b/tests/ui/qml/TestDialog.qml similarity index 100% rename from interface/resources/qml/TestDialog.qml rename to tests/ui/qml/TestDialog.qml diff --git a/interface/resources/qml/TestMenu.qml b/tests/ui/qml/TestMenu.qml similarity index 100% rename from interface/resources/qml/TestMenu.qml rename to tests/ui/qml/TestMenu.qml diff --git a/interface/resources/qml/TestRoot.qml b/tests/ui/qml/TestRoot.qml similarity index 100% rename from interface/resources/qml/TestRoot.qml rename to tests/ui/qml/TestRoot.qml diff --git a/tests/ui/qml/ButtonPage.qml b/tests/ui/qml/controlDemo/ButtonPage.qml similarity index 100% rename from tests/ui/qml/ButtonPage.qml rename to tests/ui/qml/controlDemo/ButtonPage.qml diff --git a/tests/ui/qml/InputPage.qml b/tests/ui/qml/controlDemo/InputPage.qml similarity index 100% rename from tests/ui/qml/InputPage.qml rename to tests/ui/qml/controlDemo/InputPage.qml diff --git a/tests/ui/qml/ProgressPage.qml b/tests/ui/qml/controlDemo/ProgressPage.qml similarity index 100% rename from tests/ui/qml/ProgressPage.qml rename to tests/ui/qml/controlDemo/ProgressPage.qml diff --git a/tests/ui/main.qml b/tests/ui/qml/controlDemo/main.qml similarity index 100% rename from tests/ui/main.qml rename to tests/ui/qml/controlDemo/main.qml diff --git a/tests/ui/qml/main.qml b/tests/ui/qml/main.qml new file mode 100644 index 0000000000..c1f1831275 --- /dev/null +++ b/tests/ui/qml/main.qml @@ -0,0 +1,336 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Dialogs 1.2 as OriginalDialogs +import Qt.labs.settings 1.0 + +import "../../../interface/resources/qml" +import "../../../interface/resources/qml/windows" +import "../../../interface/resources/qml/dialogs" + +ApplicationWindow { + id: appWindow + visible: true + width: 1280 + height: 720 + title: qsTr("Scratch App") + + Component { id: listModelBuilder; ListModel{} } + + function menuItemsToModel(menu) { + var items = menu.items + var newListModel = listModelBuilder.createObject(desktop); + for (var i = 0; i < items.length; ++i) { + var item = items[i]; + switch (item.type) { + case 2: + newListModel.append({"type":item.type, "name": item.title, "item": item}) + break; + case 1: + newListModel.append({"type":item.type, "name": item.text, "item": item}) + break; + case 0: + newListModel.append({"type":item.type, "name": "-----", "item": item}) + break; + } + } + return newListModel; + } + + Root { + id: desktop + anchors.fill: parent + + StubMenu { id: stubMenu } + + Row { + id: testButtons + anchors { margins: 8; left: parent.left; top: parent.top } + spacing: 8 + property int count: 0 + + property var tabs: []; + property var urls: []; + Button { + text: "restore all" + onClicked: { + for (var i = 0; i < desktop.windows.length; ++i) { + desktop.windows[i].visible = true + } + } + } + Button { + text: "toggle blue visible" + onClicked: { + blue.visible = !blue.visible + } + } + Button { + text: "toggle blue enabled" + onClicked: { + blue.enabled = !blue.enabled + } + } +// Button { +// text: "add web tab" +// onClicked: { +// testButtons.urls.push("http://slashdot.org?" + testButtons.count++); +// testButtons.tabs.push(desktop.toolWindow.addWebTab({ title: "test", source: testButtons.urls[testButtons.urls.length - 1], width: 500, height: 720 })) +// } +// } +// Button { +// text: "toggle tab visible" +// onClicked: { +// var lastUrl = testButtons.urls[testButtons.urls.length - 1]; +// var tab = desktop.toolWindow.findTabForUrl(lastUrl); +// desktop.toolWindow.showTabForUrl(lastUrl, !tab.enabled) +// } +// } +// Button { +// text: "Remove last tab" +// onClicked: { +// testButtons.tabs.pop(); +// desktop.toolWindow.removeTabForUrl(testButtons.urls.pop()); +// } +// } + Button { + text: "Show Long Error" + onClicked: { + desktop.messageBox({ + informativeText: "Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds ", + text: "Baloney", + icon: OriginalDialogs.StandardIcon.Warning, + detailedText: "sakjd;laskj dksa;dl jka;lsd j;lkjas ;dlkaj s;dlakjd ;alkjda; slkjda; lkjda;lksjd ;alksjd; alksjd ;alksjd; alksjd; alksdjas;ldkjas;lkdja ;kj ;lkasjd; lkj as;dlka jsd;lka jsd;laksjd a" + }); + } + } + Button { + text: "Show Error" + onClicked: { + desktop.messageBox({ + text: "Diagnostic cycle will be complete in 30 seconds", + icon: OriginalDialogs.StandardIcon.Critical, + }); + } + } + Button { + text: "Open File" + property var builder: Component { + FileDialog { } + } + + ListModel { + id: jsFilters + ListElement { text: "Javascript Files (*.js)"; filter: "*.js" } + ListElement { text: "All Files (*.*)"; filter: "*.*" } + } + onClicked: { + var fileDialogProperties = { + filterModel: jsFilters + } + var fileDialog = builder.createObject(desktop, fileDialogProperties); + fileDialog.canceled.connect(function(){ + console.log("Cancelled") + }) + fileDialog.selectedFile.connect(function(file){ + console.log("Selected " + file) + }) + } + } + Button { + text: "Focus Test" + onClicked: { + var item = desktop; + while (item) { + console.log(item); + item = item.parent; + } + item = appWindow + while (item) { + console.log(item); + item = item.parent; + } + console.log(appWindow.activeFocusItem); + } + } + } + + Window { + id: blue + closable: true + visible: true + resizable: true + destroyOnInvisible: false + + width: 100; height: 100 + x: 1280 / 2; y: 720 / 2 + Settings { + category: "TestWindow.Blue" + property alias x: blue.x + property alias y: blue.y + property alias width: blue.width + property alias height: blue.height + } + + Rectangle { + anchors.fill: parent + visible: true + color: "blue" + Component.onDestruction: console.log("Blue destroyed") + } + } + + Window { + id: green + alwaysOnTop: true + closable: true + visible: true + resizable: false + x: 1280 / 2; y: 720 / 2 + Settings { + category: "TestWindow.Green" + property alias x: green.x + property alias y: green.y + property alias width: green.width + property alias height: green.height + } + width: 100; height: 100 + Rectangle { anchors.fill: parent; color: "green" } + } + + Window { + id: yellow + closable: true + visible: true + resizable: true + width: 100; height: 100 + Rectangle { + anchors.fill: parent + visible: true + color: "yellow" + } + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.RightButton + + Component { + id: menuBuilder + VrMenuView { } + } + + onClicked: { + console.log("zzz") + var menuItems = menuItemsToModel(stubMenu); + var newMenu = menuBuilder.createObject(desktop, { source: stubMenu, items: menuItems }); + newMenu.x = mouseX + newMenu.y = mouseY + } + + } + } + + /* + Arcane.Test { + anchors.centerIn: parent + height: 600; width: 600 + } + + + Item { + id: desktop + anchors.fill: parent + objectName: Desktop._OFFSCREEN_ROOT_OBJECT_NAME + property bool uiVisible: true + property variant toolbars: { "_root" : null } + focus: true + + + + Rectangle { + id: root + Vr.Constants { id: vr } + implicitWidth: 384; implicitHeight: 640 + anchors.centerIn: parent + color: vr.windows.colors.background + border.color: vr.controls.colors.background + border.width: vr.styles.borderWidth + radius: vr.styles.borderRadius + RunningScripts { } + } + + FileDialog { + id: fileDialog + width: 800; height: 600 + anchors.centerIn: parent + onSelectedFile: console.log("Chose file " + file) + } + Timer { + id: timer + running: false + interval: 100 + onTriggered: wireFrameContainer.enabled = true + } + + Item { + id: wireFrameContainer + objectName: Desktop._OFFSCREEN_DIALOG_OBJECT_NAME + anchors.fill: parent + onEnabledChanged: if (!enabled) timer.running = true + + NewUi.Main { + id: wireFrame + anchors.fill: parent + + property var offscreenFlags: Item { + property bool navigationFocused: false + } + + property var urlHandler: Item { + function fixupUrl(url) { + var urlString = url.toString(); + if (urlString.indexOf("https://metaverse.highfidelity.com/") !== -1 && + urlString.indexOf("access_token") === -1) { + console.log("metaverse URL, fixing") + return urlString + "?access_token=875885020b1d5f1ea694ce971c8601fa33ffd77f61851be01ed1e3fde8cabbe9" + } + return url + } + + function canHandleUrl(url) { + var urlString = url.toString(); + if (urlString.indexOf("hifi://") === 0) { + console.log("Can handle hifi addresses: " + urlString) + return true; + } + + if (urlString.indexOf(".svo.json?") !== -1) { + console.log("Can handle svo json addresses: " + urlString) + return true; + } + + if (urlString.indexOf(".js?") !== -1) { + console.log("Can handle javascript addresses: " + urlString) + return true; + } + + return false + } + + function handleUrl(url) { + return true + } + } + + property var addressManager: Item { + function navigate(url) { + console.log("Navigate to: " + url); + } + } + } + } + Keys.onMenuPressed: desktop.uiVisible = !desktop.uiVisible + Keys.onEscapePressed: desktop.uiVisible = !desktop.uiVisible + } +*/ +} diff --git a/tests/ui/qmlscratch.pro b/tests/ui/qmlscratch.pro new file mode 100644 index 0000000000..e1fbb00ca6 --- /dev/null +++ b/tests/ui/qmlscratch.pro @@ -0,0 +1,84 @@ +TEMPLATE = app + +QT += gui qml quick xml webengine widgets + +CONFIG += c++11 + +SOURCES += src/main.cpp + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = + +DISTFILES += \ + qml/UI.js \ + qml/main.qml \ + qml/Palettes.qml \ + qml/StubMenu.qml \ + qml/Stubs.qml \ + qml/TestControllers.qml \ + qml/TestDialog.qml \ + qml/TestMenu.qml \ + qml/TestRoot.qml \ + qml/controlDemo/ButtonPage.qml \ + qml/controlDemo/InputPage.qml \ + qml/controlDemo/main.qml \ + qml/controlDemo/ProgressPage.qml \ + ../../interface/resources/qml/controller/hydra/HydraButtons.qml \ + ../../interface/resources/qml/controller/hydra/HydraStick.qml \ + ../../interface/resources/qml/controller/xbox/DPad.qml \ + ../../interface/resources/qml/controller/xbox/LeftAnalogStick.qml \ + ../../interface/resources/qml/controller/xbox/RightAnalogStick.qml \ + ../../interface/resources/qml/controller/xbox/XboxButtons.qml \ + ../../interface/resources/qml/controller/AnalogButton.qml \ + ../../interface/resources/qml/controller/AnalogStick.qml \ + ../../interface/resources/qml/controller/Hydra.qml \ + ../../interface/resources/qml/controller/Standard.qml \ + ../../interface/resources/qml/controller/ToggleButton.qml \ + ../../interface/resources/qml/controller/Xbox.qml \ + ../../interface/resources/qml/controls/Button.qml \ + ../../interface/resources/qml/controls/ButtonAwesome.qml \ + ../../interface/resources/qml/controls/CheckBox.qml \ + ../../interface/resources/qml/controls/FontAwesome.qml \ + ../../interface/resources/qml/controls/Player.qml \ + ../../interface/resources/qml/controls/Slider.qml \ + ../../interface/resources/qml/controls/Spacer.qml \ + ../../interface/resources/qml/controls/SpinBox.qml \ + ../../interface/resources/qml/controls/Text.qml \ + ../../interface/resources/qml/controls/TextAndSlider.qml \ + ../../interface/resources/qml/controls/TextAndSpinBox.qml \ + ../../interface/resources/qml/controls/TextArea.qml \ + ../../interface/resources/qml/controls/TextEdit.qml \ + ../../interface/resources/qml/controls/TextHeader.qml \ + ../../interface/resources/qml/controls/TextInput.qml \ + ../../interface/resources/qml/controls/TextInputAndButton.qml \ + ../../interface/resources/qml/controls/WebView.qml \ + ../../interface/resources/qml/dialogs/FileDialog.qml \ + ../../interface/resources/qml/dialogs/MessageDialog.qml \ + ../../interface/resources/qml/dialogs/RunningScripts.qml \ + ../../interface/resources/qml/hifi/MenuOption.qml \ + ../../interface/resources/qml/styles/Border.qml \ + ../../interface/resources/qml/styles/HifiConstants.qml \ + ../../interface/resources/qml/windows/DefaultFrame.qml \ + ../../interface/resources/qml/windows/Fadable.qml \ + ../../interface/resources/qml/windows/Frame.qml \ + ../../interface/resources/qml/windows/ModalFrame.qml \ + ../../interface/resources/qml/windows/Window.qml \ + ../../interface/resources/qml/AddressBarDialog.qml \ + ../../interface/resources/qml/AvatarInputs.qml \ + ../../interface/resources/qml/Browser.qml \ + ../../interface/resources/qml/InfoView.qml \ + ../../interface/resources/qml/LoginDialog.qml \ + ../../interface/resources/qml/QmlWebWindow.qml \ + ../../interface/resources/qml/QmlWindow.qml \ + ../../interface/resources/qml/Root.qml \ + ../../interface/resources/qml/ScrollingGraph.qml \ + ../../interface/resources/qml/Stats.qml \ + ../../interface/resources/qml/TextOverlayElement.qml \ + ../../interface/resources/qml/Tooltip.qml \ + ../../interface/resources/qml/ToolWindow.qml \ + ../../interface/resources/qml/UpdateDialog.qml \ + ../../interface/resources/qml/VrMenu.qml \ + ../../interface/resources/qml/VrMenuItem.qml \ + ../../interface/resources/qml/VrMenuView.qml \ + ../../interface/resources/qml/WebEntity.qml + diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index 59e7376f1b..1e79fca732 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -1,645 +1,65 @@ -// -// Created by Bradley Austin Davis on 2015-04-22 -// Copyright 2013-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 +#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 - -const QString& getResourcesDir() { - static QString dir; - if (dir.isEmpty()) { - QDir path(__FILE__); - path.cdUp(); - dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/")) + "/"; - qDebug() << "Resources Path: " << dir; - } - return dir; +QString getRelativeDir(const QString& relativePath = ".") { + QDir path(__FILE__); path.cdUp(); + auto result = path.absoluteFilePath(relativePath); + result = path.cleanPath(result) + "/"; + return result; } -const QString& getExamplesDir() { - static QString dir; - if (dir.isEmpty()) { - QDir path(__FILE__); - path.cdUp(); - dir = path.cleanPath(path.absoluteFilePath("../../../examples/")) + "/"; - qDebug() << "Resources Path: " << dir; - } - return dir; +QString getTestQmlDir() { + return getRelativeDir("../qml"); } -const QString& getInterfaceQmlDir() { - static QString dir; - if (dir.isEmpty()) { - dir = getResourcesDir() + "qml/"; - qDebug() << "Qml Path: " << dir; - } - return dir; -} - -const QString& getTestQmlDir() { - static QString dir; - if (dir.isEmpty()) { - QDir path(__FILE__); - path.cdUp(); - dir = path.cleanPath(path.absoluteFilePath("../")) + "/"; - qDebug() << "Qml Test Path: " << dir; - } - return dir; +QString getInterfaceQmlDir() { + return getRelativeDir("/"); } -class RateCounter { - std::vector times; - QElapsedTimer timer; -public: - RateCounter() { - timer.start(); +void setChild(QQmlApplicationEngine& engine, const char* name) { + for (auto obj : engine.rootObjects()) { + auto child = obj->findChild(QString(name)); + if (child) { + engine.rootContext()->setContextProperty(name, child); + return; } - - void reset() { - times.clear(); - } - - size_t count() const { - return times.size() - 1; - } - - float elapsed() const { - if (times.size() < 1) { - return 0.0f; - } - float elapsed = *times.rbegin() - *times.begin(); - return elapsed; - } - - void increment() { - times.push_back(timer.elapsed() / 1000.0f); - } - - float rate() const { - if (elapsed() == 0.0f) { - return 0.0f; - } - return (float) count() / elapsed(); - } -}; - - - - -extern QOpenGLContext* qt_gl_global_share_context(); - - -static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName) { - if (engine.hasUncaughtException()) { - const auto backtrace = engine.uncaughtExceptionBacktrace(); - const auto exception = engine.uncaughtException().toString(); - const auto line = QString::number(engine.uncaughtExceptionLineNumber()); - engine.clearExceptions(); - - auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line); - if (!backtrace.empty()) { - static const auto lineSeparator = "\n "; - message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator)); - } - qWarning() << qPrintable(message); - return true; - } - return false; + } + qWarning() << "Could not find object named " << name; } -const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0f / 60.0f) * 1000 * 1000) + 0.5f); - -static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) { - QString message = ""; - for (int i = 0; i < context->argumentCount(); i++) { - if (i > 0) { - message += " "; - } - message += context->argument(i).toString(); - } - qDebug().noquote() << "script:print()<<" << message; // noquote() so that \n is treated as newline - - message = message.replace("\\", "\\\\") - .replace("\n", "\\n") - .replace("\r", "\\r") - .replace("'", "\\'"); - engine->evaluate("Script.print('" + message + "')"); - - return QScriptValue(); +void addImportPath(QQmlApplicationEngine& engine, const QString& relativePath) { + QString resolvedPath = getRelativeDir("../qml"); + QUrl resolvedUrl = QUrl::fromLocalFile(resolvedPath); + resolvedPath = resolvedUrl.toString(); + engine.addImportPath(resolvedPath); } -class ScriptEngine : public QScriptEngine { - Q_OBJECT +int main(int argc, char *argv[]) { + QApplication app(argc, argv); + app.setOrganizationName("Some Company"); + app.setOrganizationDomain("somecompany.com"); + app.setApplicationName("Amazing Application"); + QDir::setCurrent(getRelativeDir("..")); -public: - void loadFile(const QString& scriptPath) { - if (_isRunning) { - return; - } - qDebug() << "Loading script from " << scriptPath; - _fileNameString = scriptPath; + QtWebEngine::initialize(); - QFile file(scriptPath); - if (file.exists()) { - file.open(QIODevice::ReadOnly); - _scriptContents = file.readAll(); - } else { - qFatal("Missing file "); - } - runInThread(); - } + QQmlApplicationEngine engine; + addImportPath(engine, "../qml"); + addImportPath(engine, "../../../interface/resources/qml"); + engine.load(QUrl(QStringLiteral("qml/Stubs.qml"))); - Q_INVOKABLE void stop() { - if (!_isFinished) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "stop"); - return; - } - _isFinished = true; - if (_wantSignals) { - emit runningStateChanged(); - } - } - } + setChild(engine, "rootMenu"); + setChild(engine, "Account"); + setChild(engine, "Desktop"); + setChild(engine, "ScriptDiscoveryService"); + setChild(engine, "MenuHelper"); + setChild(engine, "urlHandler"); + engine.rootContext()->setContextProperty("DebugQML", true); - Q_INVOKABLE void print(const QString& message) { - if (_wantSignals) { - emit printedMessage(message); - } - } - - Q_INVOKABLE QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot) { - // create the timer, add it to the map, and start it - QTimer* newTimer = new QTimer(this); - newTimer->setSingleShot(isSingleShot); - - connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired); - - // make sure the timer stops when the script does - connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop); - - _timerFunctionMap.insert(newTimer, function); - - newTimer->start(intervalMS); - return newTimer; - } - - Q_INVOKABLE QObject* setInterval(const QScriptValue& function, int intervalMS) { - return setupTimerWithInterval(function, intervalMS, false); - } - - Q_INVOKABLE QObject* setTimeout(const QScriptValue& function, int timeoutMS) { - return setupTimerWithInterval(function, timeoutMS, true); - } -private: - - void runInThread() { - QThread* workerThread = new QThread(); - connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater); - connect(workerThread, &QThread::started, this, &ScriptEngine::run); - connect(workerThread, &QThread::finished, this, &ScriptEngine::deleteLater); - connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit); - moveToThread(workerThread); - workerThread->start(); - } - - void init() { - _isInitialized = true; - registerMetaTypes(this); - registerGlobalObject("Script", this); - qScriptRegisterSequenceMetaType>(this); - qScriptRegisterSequenceMetaType>(this); - globalObject().setProperty("OverlayWebWindow", newFunction(QmlWebWindowClass::constructor)); - QScriptValue printConstructorValue = newFunction(debugPrint); - globalObject().setProperty("print", printConstructorValue); - } - - void timerFired() { - QTimer* callingTimer = reinterpret_cast(sender()); - QScriptValue timerFunction = _timerFunctionMap.value(callingTimer); - - if (!callingTimer->isActive()) { - // this timer is done, we can kill it - _timerFunctionMap.remove(callingTimer); - delete callingTimer; - } - - // call the associated JS function, if it exists - if (timerFunction.isValid()) { - timerFunction.call(); - } - } - - - void run() { - if (!_isInitialized) { - init(); - } - - _isRunning = true; - if (_wantSignals) { - emit runningStateChanged(); - } - - QScriptValue result = evaluate(_scriptContents, _fileNameString); - QElapsedTimer startTime; - startTime.start(); - - int thisFrame = 0; - - qint64 lastUpdate = usecTimestampNow(); - - while (!_isFinished) { - int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec - if (usecToSleep > 0) { - usleep(usecToSleep); - } - - if (_isFinished) { - break; - } - - QCoreApplication::processEvents(); - if (_isFinished) { - break; - } - - qint64 now = usecTimestampNow(); - float deltaTime = (float)(now - lastUpdate) / (float)USECS_PER_SECOND; - if (!_isFinished) { - if (_wantSignals) { - emit update(deltaTime); - } - } - lastUpdate = now; - - // Debug and clear exceptions - hadUncaughtExceptions(*this, _fileNameString); - } - - if (_wantSignals) { - emit scriptEnding(); - } - - if (_wantSignals) { - emit finished(_fileNameString, this); - } - - _isRunning = false; - - if (_wantSignals) { - emit runningStateChanged(); - emit doneRunning(); - } - } - - void registerGlobalObject(const QString& name, QObject* object) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "registerGlobalObject", - Q_ARG(const QString&, name), - Q_ARG(QObject*, object)); - return; - } - if (!globalObject().property(name).isValid()) { - if (object) { - QScriptValue value = newQObject(object); - globalObject().setProperty(name, value); - } else { - globalObject().setProperty(name, QScriptValue()); - } - } - } - - void registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "registerFunction", - Q_ARG(const QString&, name), - Q_ARG(QScriptEngine::FunctionSignature, functionSignature), - Q_ARG(int, numArguments)); - return; - } - QScriptValue scriptFun = newFunction(functionSignature, numArguments); - globalObject().setProperty(name, scriptFun); - } - - void registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "registerFunction", - Q_ARG(const QString&, name), - Q_ARG(QScriptEngine::FunctionSignature, functionSignature), - Q_ARG(int, numArguments)); - return; - } - - QScriptValue object = globalObject().property(parent); - if (object.isValid()) { - QScriptValue scriptFun = newFunction(functionSignature, numArguments); - object.setProperty(name, scriptFun); - } - } - -signals: - void scriptLoaded(const QString& scriptFilename); - void errorLoadingScript(const QString& scriptFilename); - void update(float deltaTime); - void scriptEnding(); - void finished(const QString& fileNameString, ScriptEngine* engine); - void cleanupMenuItem(const QString& menuItemString); - void printedMessage(const QString& message); - void errorMessage(const QString& message); - void runningStateChanged(); - void evaluationFinished(QScriptValue result, bool isException); - void loadScript(const QString& scriptName, bool isUserLoaded); - void reloadScript(const QString& scriptName, bool isUserLoaded); - void doneRunning(); - - -private: - QString _scriptContents; - QString _fileNameString; - QString _parentURL; - bool _isInitialized { false }; - std::atomic _isFinished { false }; - std::atomic _isRunning { false }; - bool _wantSignals { true }; - QHash _timerFunctionMap; -}; - - - -ScriptEngine* loadScript(const QString& scriptFilename) { - ScriptEngine* scriptEngine = new ScriptEngine(); - scriptEngine->loadFile(scriptFilename); - return scriptEngine; + //engine.load(QUrl(QStringLiteral("qrc:/qml/gallery/main.qml"))); + engine.load(QUrl(QStringLiteral("qml/main.qml"))); + return app.exec(); } - -OffscreenGLCanvas* _chromiumShareContext { nullptr }; -Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context); - - -// Create a simple OpenGL window that renders text in various ways -class QTestWindow : public QWindow { - Q_OBJECT - - QOpenGLContextWrapper* _context{ nullptr }; - QSize _size; - bool _altPressed{ false }; - RateCounter fps; - QTimer _timer; - int testQmlTexture{ 0 }; - ProgramPtr _program; - ShapeWrapperPtr _plane; - QScriptEngine* _scriptEngine { nullptr }; - -public: - QObject* rootMenu; - - QTestWindow() { - _scriptEngine = new ScriptEngine(); - _timer.setInterval(1); - QObject::connect(&_timer, &QTimer::timeout, this, &QTestWindow::draw); - - _chromiumShareContext = new OffscreenGLCanvas(); - _chromiumShareContext->create(); - _chromiumShareContext->makeCurrent(); - qt_gl_set_global_share_context(_chromiumShareContext->getContext()); - - { - setSurfaceType(QSurface::OpenGLSurface); - QSurfaceFormat format = getDefaultOpenGLSurfaceFormat(); - setFormat(format); - _context = new QOpenGLContextWrapper(); - _context->setFormat(format); - _context->setShareContext(_chromiumShareContext->getContext()); - } - - - if (!_context->create()) { - qFatal("Could not create OpenGL context"); - } - - show(); - - makeCurrent(); - - glewExperimental = true; - glewInit(); - glGetError(); - - using namespace oglplus; - Context::Enable(Capability::Blend); - Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha); - Context::Disable(Capability::DepthTest); - Context::Disable(Capability::CullFace); - Context::ClearColor(0.2f, 0.2f, 0.2f, 1); - - MessageDialog::registerType(); - InfoView::registerType(); - - auto offscreenUi = DependencyManager::set(); - { - offscreenUi->create(_context->getContext()); - offscreenUi->setProxyWindow(this); - - connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) { - testQmlTexture = textureId; - }); - - makeCurrent(); - } - - - auto primaryScreen = QGuiApplication::primaryScreen(); - auto targetScreen = primaryScreen; - auto screens = QGuiApplication::screens(); - if (screens.size() > 1) { - for (auto screen : screens) { - if (screen != targetScreen) { - targetScreen = screen; - break; - } - } - } - auto rect = targetScreen->availableGeometry(); - rect.setWidth(rect.width() * 0.8f); - rect.setHeight(rect.height() * 0.8f); - rect.moveTo(QPoint(20, 20)); - setGeometry(rect); - -#ifdef QML_CONTROL_GALLERY - offscreenUi->setBaseUrl(QUrl::fromLocalFile(getTestQmlDir())); - offscreenUi->load(QUrl("main.qml")); -#else - offscreenUi->setBaseUrl(QUrl::fromLocalFile(getInterfaceQmlDir())); - offscreenUi->load(QUrl("TestRoot.qml")); -#endif - installEventFilter(offscreenUi.data()); - offscreenUi->resume(); - _timer.start(); - } - - virtual ~QTestWindow() { - DependencyManager::destroy(); - } - -private: - void draw() { - if (!isVisible()) { - return; - } - - makeCurrent(); - auto error = glGetError(); - if (error != GL_NO_ERROR) { - qDebug() << "GL error in entering draw " << error; - } - - using namespace oglplus; - Context::Clear().ColorBuffer().DepthBuffer(); - ivec2 size(_size.width(), _size.height()); - size *= devicePixelRatio(); - size = glm::max(size, ivec2(100, 100)); - Context::Viewport(size.x, size.y); - if (!_program) { - _program = loadDefaultShader(); - _plane = loadPlane(_program); - } - - if (testQmlTexture > 0) { - glBindTexture(GL_TEXTURE_2D, testQmlTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } - - _program->Bind(); - _plane->Use(); - _plane->Draw(); - _context->swapBuffers(this); - - fps.increment(); - if (fps.elapsed() >= 10.0f) { - qDebug() << "FPS: " << fps.rate(); - fps.reset(); - } - } - - void makeCurrent() { - _context->makeCurrent(this); - } - - void resizeWindow(const QSize & size) { - _size = size; - DependencyManager::get()->resize(_size); - } - - -protected: - void resizeEvent(QResizeEvent* ev) override { - resizeWindow(ev->size()); - } - - - void keyPressEvent(QKeyEvent* event) override { - _altPressed = Qt::Key_Alt == event->key(); - switch (event->key()) { - case Qt::Key_B: - if (event->modifiers() & Qt::CTRL) { - auto offscreenUi = DependencyManager::get(); - offscreenUi->load("Browser.qml"); - } - break; - - case Qt::Key_J: - if (event->modifiers() & Qt::CTRL) { - loadScript(getExamplesDir() + "tests/qmlWebTest.js"); - } - break; - - case Qt::Key_K: - if (event->modifiers() & Qt::CTRL) { - OffscreenUi::question("Message title", "Message contents", [](QMessageBox::Button b){ - qDebug() << b; - }); - } - break; - } - QWindow::keyPressEvent(event); - } - - void moveEvent(QMoveEvent* event) override { - static qreal oldPixelRatio = 0.0; - if (devicePixelRatio() != oldPixelRatio) { - oldPixelRatio = devicePixelRatio(); - resizeWindow(size()); - } - QWindow::moveEvent(event); - } -}; - -const char * LOG_FILTER_RULES = R"V0G0N( -hifi.offscreen.focus.debug=false -qt.quick.mouse.debug=false -)V0G0N"; - -void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { - QString logMessage = message; - -#ifdef Q_OS_WIN - if (!logMessage.isEmpty()) { - OutputDebugStringA(logMessage.toLocal8Bit().constData()); - OutputDebugStringA("\n"); - } -#endif -} - - -int main(int argc, char** argv) { - QGuiApplication app(argc, argv); - qInstallMessageHandler(messageHandler); - QLoggingCategory::setFilterRules(LOG_FILTER_RULES); - QTestWindow window; - app.exec(); - return 0; -} - -#include "main.moc" diff --git a/tests/ui/src/oldmain.cpp b/tests/ui/src/oldmain.cpp new file mode 100644 index 0000000000..82ba8376bd --- /dev/null +++ b/tests/ui/src/oldmain.cpp @@ -0,0 +1,643 @@ +// +// Created by Bradley Austin Davis on 2015-04-22 +// Copyright 2013-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 +#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 + +const QString& getResourcesDir() { + static QString dir; + if (dir.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/")) + "/"; + qDebug() << "Resources Path: " << dir; + } + return dir; +} + +const QString& getExamplesDir() { + static QString dir; + if (dir.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + dir = path.cleanPath(path.absoluteFilePath("../../../examples/")) + "/"; + qDebug() << "Resources Path: " << dir; + } + return dir; +} + +const QString& getInterfaceQmlDir() { + static QString dir; + if (dir.isEmpty()) { + dir = getResourcesDir() + "qml/"; + qDebug() << "Qml Path: " << dir; + } + return dir; +} + +const QString& getTestQmlDir() { + static QString dir; + if (dir.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + dir = path.cleanPath(path.absoluteFilePath("../")) + "/"; + qDebug() << "Qml Test Path: " << dir; + } + return dir; +} + + +class RateCounter { + std::vector times; + QElapsedTimer timer; +public: + RateCounter() { + timer.start(); + } + + void reset() { + times.clear(); + } + + size_t count() const { + return times.size() - 1; + } + + float elapsed() const { + if (times.size() < 1) { + return 0.0f; + } + float elapsed = *times.rbegin() - *times.begin(); + return elapsed; + } + + void increment() { + times.push_back(timer.elapsed() / 1000.0f); + } + + float rate() const { + if (elapsed() == 0.0f) { + return 0.0f; + } + return (float) count() / elapsed(); + } +}; + + + + +extern QOpenGLContext* qt_gl_global_share_context(); + + +static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName) { + if (engine.hasUncaughtException()) { + const auto backtrace = engine.uncaughtExceptionBacktrace(); + const auto exception = engine.uncaughtException().toString(); + const auto line = QString::number(engine.uncaughtExceptionLineNumber()); + engine.clearExceptions(); + + auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line); + if (!backtrace.empty()) { + static const auto lineSeparator = "\n "; + message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator)); + } + qWarning() << qPrintable(message); + return true; + } + return false; +} + +const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0f / 60.0f) * 1000 * 1000) + 0.5f); + +static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) { + QString message = ""; + for (int i = 0; i < context->argumentCount(); i++) { + if (i > 0) { + message += " "; + } + message += context->argument(i).toString(); + } + qDebug().noquote() << "script:print()<<" << message; // noquote() so that \n is treated as newline + + message = message.replace("\\", "\\\\") + .replace("\n", "\\n") + .replace("\r", "\\r") + .replace("'", "\\'"); + engine->evaluate("Script.print('" + message + "')"); + + return QScriptValue(); +} + +class ScriptEngine : public QScriptEngine { + Q_OBJECT + +public: + void loadFile(const QString& scriptPath) { + if (_isRunning) { + return; + } + qDebug() << "Loading script from " << scriptPath; + _fileNameString = scriptPath; + + QFile file(scriptPath); + if (file.exists()) { + file.open(QIODevice::ReadOnly); + _scriptContents = file.readAll(); + } else { + qFatal("Missing file "); + } + runInThread(); + } + + Q_INVOKABLE void stop() { + if (!_isFinished) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "stop"); + return; + } + _isFinished = true; + if (_wantSignals) { + emit runningStateChanged(); + } + } + } + + Q_INVOKABLE void print(const QString& message) { + if (_wantSignals) { + emit printedMessage(message); + } + } + + Q_INVOKABLE QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot) { + // create the timer, add it to the map, and start it + QTimer* newTimer = new QTimer(this); + newTimer->setSingleShot(isSingleShot); + + connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired); + + // make sure the timer stops when the script does + connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop); + + _timerFunctionMap.insert(newTimer, function); + + newTimer->start(intervalMS); + return newTimer; + } + + Q_INVOKABLE QObject* setInterval(const QScriptValue& function, int intervalMS) { + return setupTimerWithInterval(function, intervalMS, false); + } + + Q_INVOKABLE QObject* setTimeout(const QScriptValue& function, int timeoutMS) { + return setupTimerWithInterval(function, timeoutMS, true); + } +private: + + void runInThread() { + QThread* workerThread = new QThread(); + connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater); + connect(workerThread, &QThread::started, this, &ScriptEngine::run); + connect(workerThread, &QThread::finished, this, &ScriptEngine::deleteLater); + connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit); + moveToThread(workerThread); + workerThread->start(); + } + + void init() { + _isInitialized = true; + registerMetaTypes(this); + registerGlobalObject("Script", this); + qScriptRegisterSequenceMetaType>(this); + qScriptRegisterSequenceMetaType>(this); + globalObject().setProperty("OverlayWebWindow", newFunction(QmlWebWindowClass::constructor)); + QScriptValue printConstructorValue = newFunction(debugPrint); + globalObject().setProperty("print", printConstructorValue); + } + + void timerFired() { + QTimer* callingTimer = reinterpret_cast(sender()); + QScriptValue timerFunction = _timerFunctionMap.value(callingTimer); + + if (!callingTimer->isActive()) { + // this timer is done, we can kill it + _timerFunctionMap.remove(callingTimer); + delete callingTimer; + } + + // call the associated JS function, if it exists + if (timerFunction.isValid()) { + timerFunction.call(); + } + } + + + void run() { + if (!_isInitialized) { + init(); + } + + _isRunning = true; + if (_wantSignals) { + emit runningStateChanged(); + } + + QScriptValue result = evaluate(_scriptContents, _fileNameString); + QElapsedTimer startTime; + startTime.start(); + + int thisFrame = 0; + + qint64 lastUpdate = usecTimestampNow(); + + while (!_isFinished) { + int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec + if (usecToSleep > 0) { + usleep(usecToSleep); + } + + if (_isFinished) { + break; + } + + QCoreApplication::processEvents(); + if (_isFinished) { + break; + } + + qint64 now = usecTimestampNow(); + float deltaTime = (float)(now - lastUpdate) / (float)USECS_PER_SECOND; + if (!_isFinished) { + if (_wantSignals) { + emit update(deltaTime); + } + } + lastUpdate = now; + + // Debug and clear exceptions + hadUncaughtExceptions(*this, _fileNameString); + } + + if (_wantSignals) { + emit scriptEnding(); + } + + if (_wantSignals) { + emit finished(_fileNameString, this); + } + + _isRunning = false; + + if (_wantSignals) { + emit runningStateChanged(); + emit doneRunning(); + } + } + + void registerGlobalObject(const QString& name, QObject* object) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "registerGlobalObject", + Q_ARG(const QString&, name), + Q_ARG(QObject*, object)); + return; + } + if (!globalObject().property(name).isValid()) { + if (object) { + QScriptValue value = newQObject(object); + globalObject().setProperty(name, value); + } else { + globalObject().setProperty(name, QScriptValue()); + } + } + } + + void registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "registerFunction", + Q_ARG(const QString&, name), + Q_ARG(QScriptEngine::FunctionSignature, functionSignature), + Q_ARG(int, numArguments)); + return; + } + QScriptValue scriptFun = newFunction(functionSignature, numArguments); + globalObject().setProperty(name, scriptFun); + } + + void registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "registerFunction", + Q_ARG(const QString&, name), + Q_ARG(QScriptEngine::FunctionSignature, functionSignature), + Q_ARG(int, numArguments)); + return; + } + + QScriptValue object = globalObject().property(parent); + if (object.isValid()) { + QScriptValue scriptFun = newFunction(functionSignature, numArguments); + object.setProperty(name, scriptFun); + } + } + +signals: + void scriptLoaded(const QString& scriptFilename); + void errorLoadingScript(const QString& scriptFilename); + void update(float deltaTime); + void scriptEnding(); + void finished(const QString& fileNameString, ScriptEngine* engine); + void cleanupMenuItem(const QString& menuItemString); + void printedMessage(const QString& message); + void errorMessage(const QString& message); + void runningStateChanged(); + void evaluationFinished(QScriptValue result, bool isException); + void loadScript(const QString& scriptName, bool isUserLoaded); + void reloadScript(const QString& scriptName, bool isUserLoaded); + void doneRunning(); + + +private: + QString _scriptContents; + QString _fileNameString; + QString _parentURL; + bool _isInitialized { false }; + std::atomic _isFinished { false }; + std::atomic _isRunning { false }; + bool _wantSignals { true }; + QHash _timerFunctionMap; +}; + + + +ScriptEngine* loadScript(const QString& scriptFilename) { + ScriptEngine* scriptEngine = new ScriptEngine(); + scriptEngine->loadFile(scriptFilename); + return scriptEngine; +} + +OffscreenGLCanvas* _chromiumShareContext { nullptr }; +Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context); + + +// Create a simple OpenGL window that renders text in various ways +class QTestWindow : public QWindow { + Q_OBJECT + + QOpenGLContextWrapper* _context{ nullptr }; + QSize _size; + bool _altPressed{ false }; + RateCounter fps; + QTimer _timer; + int testQmlTexture{ 0 }; + ProgramPtr _program; + ShapeWrapperPtr _plane; + QScriptEngine* _scriptEngine { nullptr }; + +public: + QObject* rootMenu; + + QTestWindow() { + _scriptEngine = new ScriptEngine(); + _timer.setInterval(1); + QObject::connect(&_timer, &QTimer::timeout, this, &QTestWindow::draw); + + _chromiumShareContext = new OffscreenGLCanvas(); + _chromiumShareContext->create(); + _chromiumShareContext->makeCurrent(); + qt_gl_set_global_share_context(_chromiumShareContext->getContext()); + + { + setSurfaceType(QSurface::OpenGLSurface); + QSurfaceFormat format = getDefaultOpenGLSurfaceFormat(); + setFormat(format); + _context = new QOpenGLContextWrapper(); + _context->setFormat(format); + _context->setShareContext(_chromiumShareContext->getContext()); + } + + + if (!_context->create()) { + qFatal("Could not create OpenGL context"); + } + + show(); + + makeCurrent(); + + glewExperimental = true; + glewInit(); + glGetError(); + + using namespace oglplus; + Context::Enable(Capability::Blend); + Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha); + Context::Disable(Capability::DepthTest); + Context::Disable(Capability::CullFace); + Context::ClearColor(0.2f, 0.2f, 0.2f, 1); + + InfoView::registerType(); + + auto offscreenUi = DependencyManager::set(); + { + offscreenUi->create(_context->getContext()); + offscreenUi->setProxyWindow(this); + + connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) { + testQmlTexture = textureId; + }); + + makeCurrent(); + } + + + auto primaryScreen = QGuiApplication::primaryScreen(); + auto targetScreen = primaryScreen; + auto screens = QGuiApplication::screens(); + if (screens.size() > 1) { + for (auto screen : screens) { + if (screen != targetScreen) { + targetScreen = screen; + break; + } + } + } + auto rect = targetScreen->availableGeometry(); + rect.setWidth(rect.width() * 0.8f); + rect.setHeight(rect.height() * 0.8f); + rect.moveTo(QPoint(20, 20)); + setGeometry(rect); + +#ifdef QML_CONTROL_GALLERY + offscreenUi->setBaseUrl(QUrl::fromLocalFile(getTestQmlDir())); + offscreenUi->load(QUrl("main.qml")); +#else + offscreenUi->setBaseUrl(QUrl::fromLocalFile(getInterfaceQmlDir())); + offscreenUi->load(QUrl("TestRoot.qml")); +#endif + installEventFilter(offscreenUi.data()); + offscreenUi->resume(); + _timer.start(); + } + + virtual ~QTestWindow() { + DependencyManager::destroy(); + } + +private: + void draw() { + if (!isVisible()) { + return; + } + + makeCurrent(); + auto error = glGetError(); + if (error != GL_NO_ERROR) { + qDebug() << "GL error in entering draw " << error; + } + + using namespace oglplus; + Context::Clear().ColorBuffer().DepthBuffer(); + ivec2 size(_size.width(), _size.height()); + size *= devicePixelRatio(); + size = glm::max(size, ivec2(100, 100)); + Context::Viewport(size.x, size.y); + if (!_program) { + _program = loadDefaultShader(); + _plane = loadPlane(_program); + } + + if (testQmlTexture > 0) { + glBindTexture(GL_TEXTURE_2D, testQmlTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + + _program->Bind(); + _plane->Use(); + _plane->Draw(); + _context->swapBuffers(this); + + fps.increment(); + if (fps.elapsed() >= 10.0f) { + qDebug() << "FPS: " << fps.rate(); + fps.reset(); + } + } + + void makeCurrent() { + _context->makeCurrent(this); + } + + void resizeWindow(const QSize & size) { + _size = size; + DependencyManager::get()->resize(_size); + } + + +protected: + void resizeEvent(QResizeEvent* ev) override { + resizeWindow(ev->size()); + } + + + void keyPressEvent(QKeyEvent* event) override { + _altPressed = Qt::Key_Alt == event->key(); + switch (event->key()) { + case Qt::Key_B: + if (event->modifiers() & Qt::CTRL) { + auto offscreenUi = DependencyManager::get(); + offscreenUi->load("Browser.qml"); + } + break; + + case Qt::Key_J: + if (event->modifiers() & Qt::CTRL) { + loadScript(getExamplesDir() + "tests/qmlWebTest.js"); + } + break; + + case Qt::Key_K: + if (event->modifiers() & Qt::CTRL) { + OffscreenUi::question("Message title", "Message contents", [](QMessageBox::Button b){ + qDebug() << b; + }); + } + break; + } + QWindow::keyPressEvent(event); + } + + void moveEvent(QMoveEvent* event) override { + static qreal oldPixelRatio = 0.0; + if (devicePixelRatio() != oldPixelRatio) { + oldPixelRatio = devicePixelRatio(); + resizeWindow(size()); + } + QWindow::moveEvent(event); + } +}; + +const char * LOG_FILTER_RULES = R"V0G0N( +hifi.offscreen.focus.debug=false +qt.quick.mouse.debug=false +)V0G0N"; + +void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { + QString logMessage = message; + +#ifdef Q_OS_WIN + if (!logMessage.isEmpty()) { + OutputDebugStringA(logMessage.toLocal8Bit().constData()); + OutputDebugStringA("\n"); + } +#endif +} + + +int main(int argc, char** argv) { + QGuiApplication app(argc, argv); + qInstallMessageHandler(messageHandler); + QLoggingCategory::setFilterRules(LOG_FILTER_RULES); + QTestWindow window; + app.exec(); + return 0; +} + +#include "main.moc" From cf8d2c518212e3d2545063b3ae1332f95a580372 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 15 Jan 2016 23:29:49 -0800 Subject: [PATCH 193/215] Integrate file open dialog into running scripts dialog --- .../resources/qml/dialogs/RunningScripts.qml | 25 ++++++++++++++++++- libraries/ui/src/OffscreenUi.cpp | 2 +- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/dialogs/RunningScripts.qml b/interface/resources/qml/dialogs/RunningScripts.qml index 9f4309844d..d259f747ad 100644 --- a/interface/resources/qml/dialogs/RunningScripts.qml +++ b/interface/resources/qml/dialogs/RunningScripts.qml @@ -18,6 +18,12 @@ Window { property var scripts: ScriptDiscoveryService; property var scriptsModel: scripts.scriptsModelFilter property var runningScriptsModel: ListModel { } + property var fileFilters: ListModel { + id: jsFilters + ListElement { text: "Javascript Files (*.js)"; filter: "*.js" } + ListElement { text: "All Files (*.*)"; filter: "*.*" } + } + Settings { category: "Overlay.RunningScripts" @@ -65,6 +71,23 @@ Window { scripts.stopAllScripts(); } + Component { + id: fileDialogBuilder + FileDialog { } + } + + function loadFromFile() { + var fileDialog = fileDialogBuilder.createObject(Desktop, { filterModel: fileFilters }); + fileDialog.canceled.connect(function(){ + console.debug("Cancelled file open") + }) + + fileDialog.selectedFile.connect(function(file){ + console.debug("Selected " + file) + scripts.loadOneScript(file); + }) + } + Rectangle { color: "white" implicitWidth: 384; implicitHeight: 640 @@ -163,7 +186,7 @@ Window { } Button { text: "from Disk" - onClicked: ApplicationInterface.loadDialog(); + onClicked: loadFromFile(); } } diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 479a7721ce..36905797d6 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -235,7 +235,7 @@ void OffscreenUi::createDesktop() { if (_desktop) { qDebug() << "Desktop already created"; } - getRootContext()->setContextProperty("DebugQML", false); + getRootContext()->setContextProperty("DebugQML", QVariant(false)); _desktop = dynamic_cast(load("Root.qml")); Q_ASSERT(_desktop); getRootContext()->setContextProperty("Desktop", _desktop); From 63db6d0f72df8e3a1a0ca72038cbc4efb3cc6bc1 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Sat, 16 Jan 2016 11:17:13 -0800 Subject: [PATCH 194/215] A script to test rendering load by creating a rectangular matrix of the specified objects, with no physical or entity changes after creation, either in front of you or overhead. --- .../tests/performance/renderableMatrix.js | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 examples/tests/performance/renderableMatrix.js diff --git a/examples/tests/performance/renderableMatrix.js b/examples/tests/performance/renderableMatrix.js new file mode 100644 index 0000000000..a1a0153f76 --- /dev/null +++ b/examples/tests/performance/renderableMatrix.js @@ -0,0 +1,124 @@ +"use strict"; +/*jslint nomen: true, plusplus: true, vars: true*/ +var Entities, Script, print, Vec3, MyAvatar, Camera, Quat; +// +// Created by Howard Stearns +// Copyright 2016 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 +// +// Creates a rectangular matrix of objects with no physical or entity changes after creation. +// Useful for testing the rendering, LOD, and octree storage aspects of the system. +// + +var LIFETIME = 60; +// Matrix will be axis-aligned, approximately all in this field of view. +// As special case, if zero, grid is centered above your head. +var MINIMUM_VIEW_ANGLE_IN_RADIANS = 30 * Math.PI / 180; // 30 degrees +var ROWS_X = 10; +var ROWS_Y = 10; +var ROWS_Z = 10; +var SEPARATION = 10; +var SIZE = 1; +var TYPES_TO_USE = [ // Entities will be populated from this list set by the script writer for different tests. + 'Box', + 'Sphere', + //'Light', + //'ParticleEffect', + //'Web', + //"https://hifi-content.s3.amazonaws.com/ozan/dev/sets/lowpoly_island/CypressTreeGroup.fbx", + //"http://s3.amazonaws.com/hifi-public/marketplace/hificontent/Games/blocks/block.fbx", +]; +var MODEL_SCALE = { x: 1, y: 2, z: 3 }; // how to stretch out models proportionally to SIZE +// Note that when creating things quickly, the entity server will ignore data if we send updates too quickly. +// like Internet MTU, these rates are set by th domain operator, so in this script there is a RATE_PER_SECOND +// variable letting you set this speed. If entities are missing from the grid after a relog, this number +// being too high may be the reason. +var RATE_PER_SECOND = 1000; // The entity server will drop data if we create things too fast. +var SCRIPT_INTERVAL = 100; + +var ALLOWED_TYPES = ['Box', 'Sphere', 'Light', 'ParticleEffect', 'Web']; // otherwise assumed to be a model url + +var x = 0; +var y = 0; +var z = 0; +var xDim = ROWS_X * SEPARATION; +var yDim = ROWS_Y * SEPARATION; +var zDim = ROWS_Z * SEPARATION; +var centered = !MINIMUM_VIEW_ANGLE_IN_RADIANS; +var approximateNearDistance = !centered && + Math.max(xDim, 2 * yDim, zDim) / (2 * Math.tan(MINIMUM_VIEW_ANGLE_IN_RADIANS / 2)); // matrix is up, not vertically centered +var o = Vec3.sum(MyAvatar.position, + Vec3.sum({x: xDim / -2, y: 0, z: zDim / -2}, + centered ? {x: 0, y: SEPARATION, z: 0} : Vec3.multiply(approximateNearDistance, Quat.getFront(Camera.orientation)))); +var totalCreated = 0; +var startTime = new Date(); +var totalToCreate = ROWS_X * ROWS_Y * ROWS_Z; +print("Creating " + totalToCreate + " entities starting at " + startTime); + +Script.setInterval(function () { + if (!Entities.serversExist() || !Entities.canRez()) { + return; + } + + var numToCreate = Math.min(RATE_PER_SECOND * (SCRIPT_INTERVAL / 1000.0), totalToCreate - totalCreated); + var chooseTypeRandomly = TYPES_TO_USE.length !== 2; + var i, typeIndex, type, isModel, properties; + for (i = 0; i < numToCreate; i++) { + typeIndex = chooseTypeRandomly ? Math.floor(Math.random() * TYPES_TO_USE.length) : i % TYPES_TO_USE.length; + type = TYPES_TO_USE[typeIndex]; + isModel = ALLOWED_TYPES.indexOf(type) === -1; + properties = { + position: { x: o.x + SIZE + (x * SEPARATION), y: o.y + SIZE + (y * SEPARATION), z: o.z + SIZE + (z * SEPARATION) }, + name: "renderable-" + x + "-" + y + "-" + z, + type: isModel ? 'Model' : type, + dimensions: isModel ? Vec3.multiply(SIZE, MODEL_SCALE) : { x: SIZE, y: SIZE, z: SIZE }, + ignoreCollisions: true, + collisionsWillMove: false, + lifetime: LIFETIME + }; + if (isModel) { + properties.modelURL = type; + } else if (type === 'Web') { + properties.sourceUrl = 'https://highfidelity.com'; + } else { + properties.color = { red: x / ROWS_X * 255, green: y / ROWS_Y * 255, blue: z / ROWS_Z * 255 }; + if (type === 'ParticleEffect') { + properties.emitOrientation = Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0); + properties.particleRadius = 0.04; + properties.radiusSpread = 0.0; + properties.emitRate = 100; + properties.emitSpeed = 1; + properties.speedSpread = 0.0; + properties.emitAcceleration = { x: 0.0, y: -0.3, z: 0.0 }; + properties.accelerationSpread = { x: 0.0, y: 0.0, z: 0.0 }; + properties.textures = "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png"; + properties.lifespan = 5.0; + properties.colorStart = properties.color; + properties.colorFinish = properties.color; + properties.alphaFinish = 0.0; + properties.polarFinish = 2.0 * Math.PI / 180; + } else if (type === 'Light') { + properties.dimensions = Vec3.multiply(SEPARATION, properties.position); + } + } + Entities.addEntity(properties); + totalCreated++; + + x++; + if (x === ROWS_X) { + x = 0; + y++; + if (y === ROWS_Y) { + y = 0; + z++; + print("Created: " + totalCreated); + } + } + if (z === ROWS_Z) { + print("Total: " + totalCreated + " entities in " + ((new Date() - startTime) / 1000.0) + " seconds."); + Script.stop(); + } + } +}, SCRIPT_INTERVAL); From 994d13df5a172e9188f92cecc1b6ef53d8f54ba9 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Sat, 16 Jan 2016 11:32:19 -0800 Subject: [PATCH 195/215] A test script to confirm that the specified edit rate can be achieved for the specified number of objects. --- examples/tests/performance/staticEdits.js | 97 +++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 examples/tests/performance/staticEdits.js diff --git a/examples/tests/performance/staticEdits.js b/examples/tests/performance/staticEdits.js new file mode 100644 index 0000000000..61d75c9a9a --- /dev/null +++ b/examples/tests/performance/staticEdits.js @@ -0,0 +1,97 @@ +"use strict"; +/*jslint nomen: true, plusplus: true, vars: true*/ +var Entities, Script, print, Vec3, MyAvatar; +// +// Created by Howard Stearns +// Copyright 2016 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 +// +// Creates a rectangular matrix of objects overhed, and edits them at EDIT_FREQUENCY_TARGET. +// Reports ms since last edit, ms to edit all the created entities, and average ms to edit one entity, +// so that you can measure how many edits can be made. +// +var LIFETIME = 15; +var EDIT_FREQUENCY_TARGET = 60; // hertz +var ROWS_X = 10; +var ROWS_Y = 1; +var ROWS_Z = 10; +var SEPARATION = 10.0; +var SIZE = 1.0; +// Note that when creating things quickly, the entity server will ignore data if we send updates too quickly. +// like Internet MTU, these rates are set by th domain operator, so in this script there is a RATE_PER_SECOND +// variable letting you set this speed. If entities are missing from the grid after a relog, this number +// being too high may be the reason. +var RATE_PER_SECOND = 600; // The entity server will drop data if we create things too fast. +var SCRIPT_INTERVAL = 100; + +var x = 0; +var y = 0; +var z = 0; +var o = Vec3.sum(MyAvatar.position, {x: ROWS_X * SEPARATION / -2, y: SEPARATION, z: ROWS_Z * SEPARATION / -2}); +var totalCreated = 0; +var startTime = new Date(); +var totalToCreate = ROWS_X * ROWS_Y * ROWS_Z; +print("Creating " + totalToCreate + " entities starting at " + startTime); + +var ids = [], colors = [], flasher, lastService = Date.now(); +function doFlash() { // One could call this in an interval timer, an update, or even a separate entity script. + var i, oldColor, newColor; + var start = Date.now(); + for (i = 0; i < ids.length; i++) { + oldColor = colors[i]; + newColor = {red: oldColor.green, green: oldColor.blue, blue: oldColor.red}; + colors[i] = newColor; + Entities.editEntity(ids[i], {color: newColor}); + } + var elapsed = Date.now() - start, serviceTime = start - lastService; + lastService = start; + print(serviceTime, elapsed, elapsed / totalCreated); // ms since last flash, ms to edit all entities, average ms to edit one entity +} +function stopFlash() { + Script.clearTimeout(flasher); + Script.stop(); +} +var creator = Script.setInterval(function () { + if (!Entities.serversExist() || !Entities.canRez()) { + return; + } + + var numToCreate = Math.min(RATE_PER_SECOND * (SCRIPT_INTERVAL / 1000.0), totalToCreate - totalCreated); + var i, properties; + for (i = 0; i < numToCreate; i++) { + properties = { + position: { x: o.x + SIZE + (x * SEPARATION), y: o.y + SIZE + (y * SEPARATION), z: o.z + SIZE + (z * SEPARATION) }, + name: "gridTest", + type: 'Box', + dimensions: {x: SIZE, y: SIZE, z: SIZE}, + ignoreCollisions: true, + collisionsWillMove: false, + lifetime: LIFETIME, + color: {red: x / ROWS_X * 255, green: y / ROWS_Y * 255, blue: z / ROWS_Z * 255} + }; + colors.push(properties.color); + ids.push(Entities.addEntity(properties)); + totalCreated++; + + x++; + if (x === ROWS_X) { + x = 0; + y++; + if (y === ROWS_Y) { + y = 0; + z++; + print("Created: " + totalCreated); + } + } + if (z === ROWS_Z) { + print("Total: " + totalCreated + " entities in " + ((new Date() - startTime) / 1000.0) + " seconds."); + Script.clearTimeout(creator); + flasher = Script.setInterval(doFlash, Math.ceil((1 / EDIT_FREQUENCY_TARGET) * 1000)); + Script.setTimeout(stopFlash, LIFETIME * 1000); + } + } +}, SCRIPT_INTERVAL); +Script.scriptEnding.connect(function () { Script.clearTimeout(flasher); }); + From 1985aa9d775b97ab698e3d868d056a1ccfb84bda Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Sat, 16 Jan 2016 13:26:39 -0800 Subject: [PATCH 196/215] Drops a bunch of "tribbles" (small spheres) in front of you. They edit change color at 60hz and jump randomly at an average 1hz for 30 seconds, and then dissapear after 60 seconds. Useful for testing the load of physical objects. --- examples/entityScripts/tribble.js | 66 ++++++++++++++++++ examples/tests/performance/tribbles.js | 96 ++++++++++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 examples/entityScripts/tribble.js create mode 100644 examples/tests/performance/tribbles.js diff --git a/examples/entityScripts/tribble.js b/examples/entityScripts/tribble.js new file mode 100644 index 0000000000..3f84901344 --- /dev/null +++ b/examples/entityScripts/tribble.js @@ -0,0 +1,66 @@ +(function () { + // See tests/performance/tribbles.js + var dimensions, oldColor, entityID, + editRate = 60, + moveRate = 1, + scale = 2, + accumulated = 0, + increment = {red: 1, green: 1, blue: 1}, + hasUpdate = false, + shutdown = false; + function nextWavelength(color) { + var old = oldColor[color]; + if (old === 255) { + increment[color] = -1; + } else if (old === 0) { + increment[color] = 1; + } + var next = (old + increment[color]) % 256; + return next; + } + function update(delta) { // High frequency stuff is done in update in case we fall behind. + accumulated += delta; + if (accumulated > (1 / editRate)) { + var newColor = {red: nextWavelength('red'), green: nextWavelength('green'), blue: nextWavelength('blue')}; + oldColor = newColor; + Entities.editEntity(entityID, {color: newColor}); + accumulated = 0; + } + } + function randomCentered() { return Math.random() - 0.5; } + function randomVector() { return {x: randomCentered() * dimensions.x, y: randomCentered() * dimensions.y, z: randomCentered() * dimensions.z}; } + function move() { + var newData = {velocity: Vec3.sum({x: 0, y: 1, z: 0}, randomVector()), angularVelocity: Vec3.multiply(Math.PI, randomVector())}; + var nextChange = Math.ceil(Math.random() * 2000 / moveRate); + Entities.editEntity(entityID, newData); + if (!shutdown) { Script.setTimeout(move, nextChange); } + } + this.preload = function (givenEntityID) { + entityID = givenEntityID; + var properties = Entities.getEntityProperties(entityID); + var userData = properties.userData && JSON.parse(properties.userData); + var moveTimeout = userData ? userData.moveTimeout : 0; + var editTimeout = userData ? userData.editTimeout : 0; + editRate = (userData && userData.editRate) || editRate; + moveRate = (moveRate && userData.moveRate) || moveRate; + oldColor = properties.color; + dimensions = Vec3.multiply(scale, properties.dimensions); + if (editTimeout) { + hasUpdate = true; + Script.update.connect(update); + if (editTimeout > 0) { + Script.setTimeout(function () { Script.update.disconnect(update); hasUpdate = false; }, editTimeout * 1000); + } + } + if (moveTimeout) { + Script.setTimeout(move, 1000); + if (moveTimeout > 0) { + Script.setTimeout(function () { shutdown = true; }, moveTimeout * 1000); + } + } + }; + this.unload = function () { + shutdown = true; + if (hasUpdate) { Script.update.disconnect(update); } + }; +}) diff --git a/examples/tests/performance/tribbles.js b/examples/tests/performance/tribbles.js new file mode 100644 index 0000000000..1e7b6ddf39 --- /dev/null +++ b/examples/tests/performance/tribbles.js @@ -0,0 +1,96 @@ +"use strict"; +/*jslint nomen: true, plusplus: true, vars: true*/ +var Vec3, Quat, MyAvatar, Entities, Camera, Script, print; +// +// Created by Howard Stearns +// Copyright 2016 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 +// +// Drops a bunch of physical spheres in front of you, each running a script that will: +// * Edit color at EDIT_RATE for EDIT_TIMEOUT. +// * Randomly move at an average of MOVE_RATE for MOVE_TIMEOUT. +// The _TIMEOUT parameters can be 0 for no activity, and -1 to be active indefinitely. +// + +var NUMBER_TO_CREATE = 120; +var LIFETIME = 60; // seconds +var EDIT_RATE = 60; // hz +var EDIT_TIMEOUT = -1; +var MOVE_RATE = 1; // hz +var MOVE_TIMEOUT = LIFETIME / 2; + +var SIZE = 0.5; +var TYPE = "Sphere"; +// Note that when creating things quickly, the entity server will ignore data if we send updates too quickly. +// like Internet MTU, these rates are set by th domain operator, so in this script there is a RATE_PER_SECOND +// variable letting you set this speed. If entities are missing from the grid after a relog, this number +// being too high may be the reason. +var RATE_PER_SECOND = 600; // The entity server will drop data if we create things too fast. +var SCRIPT_INTERVAL = 100; + +var GRAVITY = { x: 0, y: -9.8, z: 0 }; +var VELOCITY = { x: 0.0, y: 0, z: 0 }; +var ANGULAR_VELOCITY = { x: 1, y: 1, z: 1 }; + +var DAMPING = 0.5; +var ANGULAR_DAMPING = 0.5; + +var RANGE = 3; +var HOW_FAR_IN_FRONT_OF_ME = RANGE * 3; +var HOW_FAR_UP = RANGE / 1.5; // higher (for uneven ground) above range/2 (for distribution) + +var x = 0; +var z = 0; +var totalCreated = 0; +var offset = Vec3.sum(Vec3.multiply(HOW_FAR_UP, Vec3.UNIT_Y), + Vec3.multiply(HOW_FAR_IN_FRONT_OF_ME, Quat.getFront(Camera.orientation))); +var center = Vec3.sum(MyAvatar.position, offset); + +function randomVector(range) { + return { + x: (Math.random() - 0.5) * range.x, + y: (Math.random() - 0.5) * range.y, + z: (Math.random() - 0.5) * range.z + }; +} + +Script.setInterval(function () { + if (!Entities.serversExist() || !Entities.canRez()) { + return; + } + if (totalCreated >= NUMBER_TO_CREATE) { + print("Created " + totalCreated + " tribbles."); + Script.stop(); + } + + var i, numToCreate = RATE_PER_SECOND * (SCRIPT_INTERVAL / 1000.0); + var parameters = JSON.stringify({ + moveTimeout: MOVE_TIMEOUT, + moveRate: MOVE_RATE, + editTimeout: EDIT_TIMEOUT, + editRate: EDIT_RATE + }); + for (i = 0; (i < numToCreate) && (totalCreated < NUMBER_TO_CREATE); i++) { + Entities.addEntity({ + userData: parameters, + type: TYPE, + name: "tribble-" + totalCreated, + position: Vec3.sum(center, randomVector({ x: RANGE, y: RANGE, z: RANGE })), + dimensions: {x: SIZE, y: SIZE, z: SIZE}, + color: {red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255}, + velocity: VELOCITY, + angularVelocity: Vec3.multiply(Math.random(), ANGULAR_VELOCITY), + damping: DAMPING, + angularDamping: ANGULAR_DAMPING, + gravity: GRAVITY, + collisionsWillMove: true, + lifetime: LIFETIME, + script: "https://s3.amazonaws.com/hifi-public/scripts/entityScripts/tribble.js" + }); + + totalCreated++; + } +}, SCRIPT_INTERVAL); + From c1a1cbf718653d851b3919df376eca969217bb90 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sat, 16 Jan 2016 15:55:10 -0800 Subject: [PATCH 197/215] fix typo --- examples/html/entityProperties.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 41581845df..7ee86ac4b4 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -262,7 +262,7 @@ var elDensity = document.getElementById("property-density"); var elIgnoreForCollisions = document.getElementById("property-ignore-for-collisions"); - var elDynamic = document.getElementById("property-dyanmict ); + var elDynamic = document.getElementById("property-dyanmic" ); var elCollisionSoundURL = document.getElementById("property-collision-sound-url"); var elLifetime = document.getElementById("property-lifetime"); var elScriptURL = document.getElementById("property-script-url"); From 23a8d57ca2c0e95453b1b88756ec0cd6d5799c31 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Sun, 17 Jan 2016 14:14:00 -0800 Subject: [PATCH 198/215] Always show search ray --- examples/controllers/handControllerGrab.js | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index fa38c3f56e..d4fcf6390f 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -304,8 +304,10 @@ function MyController(hand) { this.searchSphere = null; // how far from camera to search intersection? + var DEFAULT_SEARCH_SPHERE_DISTANCE = 1000; this.intersectionDistance = 0.0; - this.searchSphereDistance = 0.0; + this.searchSphereDistance = DEFAULT_SEARCH_SPHERE_DISTANCE; + this.ignoreIK = false; this.offsetPosition = Vec3.ZERO; @@ -458,7 +460,6 @@ function MyController(hand) { visible: true, alpha: 1 }; - this.overlayLine = Overlays.addOverlay("line3d", lineProperties); } else { @@ -701,10 +702,9 @@ function MyController(hand) { this.searchSphereOff = function() { if (this.searchSphere !== null) { - //Overlays.editOverlay(this.searchSphere, { visible: false }); Overlays.deleteOverlay(this.searchSphere); this.searchSphere = null; - this.searchSphereDistance = 0.0; + this.searchSphereDistance = DEFAULT_SEARCH_SPHERE_DISTANCE; this.intersectionDistance = 0.0; } @@ -945,18 +945,18 @@ function MyController(hand) { this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); } - if (this.intersectionDistance > 0) { - var SPHERE_INTERSECTION_SIZE = 0.011; - var SEARCH_SPHERE_FOLLOW_RATE = 0.50; - var SEARCH_SPHERE_CHASE_DROP = 0.2; + var SPHERE_INTERSECTION_SIZE = 0.011; + var SEARCH_SPHERE_FOLLOW_RATE = 0.50; + if (this.intersectionDistance > 0) { + // If we hit something with our pick ray, move the search sphere toward that distance this.searchSphereDistance = this.searchSphereDistance * SEARCH_SPHERE_FOLLOW_RATE + this.intersectionDistance * (1.0 - SEARCH_SPHERE_FOLLOW_RATE); - var searchSphereLocation = Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, this.searchSphereDistance)); - searchSphereLocation.y -= ((this.intersectionDistance - this.searchSphereDistance) / this.intersectionDistance) * SEARCH_SPHERE_CHASE_DROP; - this.searchSphereOn(searchSphereLocation, SPHERE_INTERSECTION_SIZE * this.intersectionDistance, this.triggerSmoothedGrab() ? INTERSECT_COLOR : NO_INTERSECT_COLOR); - if ((USE_OVERLAY_LINES_FOR_SEARCHING === true) && PICK_WITH_HAND_RAY) { - this.overlayLineOn(handPosition, searchSphereLocation, this.triggerSmoothedGrab() ? INTERSECT_COLOR : NO_INTERSECT_COLOR); - } + } + + var searchSphereLocation = Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, this.searchSphereDistance)); + this.searchSphereOn(searchSphereLocation, SPHERE_INTERSECTION_SIZE * this.searchSphereDistance, this.triggerSmoothedGrab() ? INTERSECT_COLOR : NO_INTERSECT_COLOR); + if ((USE_OVERLAY_LINES_FOR_SEARCHING === true) && PICK_WITH_HAND_RAY) { + this.overlayLineOn(handPosition, searchSphereLocation, this.triggerSmoothedGrab() ? INTERSECT_COLOR : NO_INTERSECT_COLOR); } }; From 9b3155188da141ef1e78175e1a56cd03a3868ea8 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Sun, 17 Jan 2016 19:10:40 -0800 Subject: [PATCH 199/215] Squeeze a little to search, a lot to grab --- examples/controllers/handControllerGrab.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index d4fcf6390f..7721366bab 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -853,7 +853,7 @@ function MyController(hand) { intersection = Entities.findRayIntersection(pickRayBacked, true, [], blacklist); } else { intersection = Entities.findRayIntersection(pickRayBacked, true); - } + } if (intersection.intersects) { rayPickedCandidateEntities.push(intersection.entityID); @@ -900,8 +900,8 @@ function MyController(hand) { grabbableData = grabbableDataForCandidate; } } - if (this.grabbedEntity !== null) { - // We've found an entity that we'll do something with. + if ((this.grabbedEntity !== null) && (this.triggerSmoothedGrab() || this.bumperSqueezed())) { + // We are squeezing enough to grab, and we've found an entity that we'll try to do something with. var near = (nearPickedCandidateEntities.indexOf(this.grabbedEntity) >= 0); var isPhysical = this.propsArePhysical(props); @@ -945,7 +945,7 @@ function MyController(hand) { this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); } - var SPHERE_INTERSECTION_SIZE = 0.011; + var SEARCH_SPHERE_SIZE = 0.011; var SEARCH_SPHERE_FOLLOW_RATE = 0.50; if (this.intersectionDistance > 0) { @@ -954,9 +954,9 @@ function MyController(hand) { } var searchSphereLocation = Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, this.searchSphereDistance)); - this.searchSphereOn(searchSphereLocation, SPHERE_INTERSECTION_SIZE * this.searchSphereDistance, this.triggerSmoothedGrab() ? INTERSECT_COLOR : NO_INTERSECT_COLOR); + this.searchSphereOn(searchSphereLocation, SEARCH_SPHERE_SIZE * this.searchSphereDistance, (this.triggerSmoothedGrab() || this.bumperSqueezed()) ? INTERSECT_COLOR : NO_INTERSECT_COLOR); if ((USE_OVERLAY_LINES_FOR_SEARCHING === true) && PICK_WITH_HAND_RAY) { - this.overlayLineOn(handPosition, searchSphereLocation, this.triggerSmoothedGrab() ? INTERSECT_COLOR : NO_INTERSECT_COLOR); + this.overlayLineOn(handPosition, searchSphereLocation, (this.triggerSmoothedGrab() || this.bumperSqueezed()) ? INTERSECT_COLOR : NO_INTERSECT_COLOR); } }; From 5aa8398adbbda8aeb8973313ef5a8ae26eb80533 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sun, 17 Jan 2016 20:56:07 -0800 Subject: [PATCH 200/215] Working on keyboard focus issues --- interface/resources/qml/Root.qml | 97 +++++++++----------------------- interface/src/Application.cpp | 5 ++ libraries/ui/src/OffscreenUi.cpp | 5 ++ libraries/ui/src/OffscreenUi.h | 2 +- tests/ui/qml/main.qml | 2 +- 5 files changed, 38 insertions(+), 73 deletions(-) diff --git a/interface/resources/qml/Root.qml b/interface/resources/qml/Root.qml index b503e2e1a6..e1431de967 100644 --- a/interface/resources/qml/Root.qml +++ b/interface/resources/qml/Root.qml @@ -6,14 +6,31 @@ import "dialogs" // This is our primary 'desktop' object to which all VR dialogs and // windows will be childed. -Item { +FocusScope { id: desktop anchors.fill: parent; // Debugging help for figuring out focus issues property var offscreenWindow; onOffscreenWindowChanged: offscreenWindow.activeFocusItemChanged.connect(onWindowFocusChanged); - function onWindowFocusChanged() { console.log("Focus item is " + offscreenWindow.activeFocusItem); } + function onWindowFocusChanged() { + console.log("Focus item is " + offscreenWindow.activeFocusItem); + var focusedItem = offscreenWindow.activeFocusItem ; + if (DebugQML && focusedItem) { + var rect = desktop.mapToItem(desktop, focusedItem.x, focusedItem.y, focusedItem.width, focusedItem.height); + focusDebugger.visible = true + focusDebugger.x = rect.x; + focusDebugger.y = rect.y; + focusDebugger.width = rect.width + focusDebugger.height = rect.height + } + } + + Rectangle { + id: focusDebugger; + z: 9999; visible: false; color: "red" + ColorAnimation on color { from: "#7fffff00"; to: "#7f0000ff"; duration: 1000; loops: 9999 } + } // Allows QML/JS to find the desktop through the parent chain property bool desktopRoot: true @@ -184,76 +201,14 @@ Item { var windows = getTopLevelWindows(predicate); fixupZOrder(windows, zBasis, targetWindow); } + } - - - //function findMenuChild(menu, childName) { - // if (!menu) { - // return null; - // } - - // if (menu.type !== 2) { - // console.warn("Tried to find child of a non-menu"); - // return null; - // } - - // var items = menu.items; - // var count = items.length; - // for (var i = 0; i < count; ++i) { - // var child = items[i]; - // var name; - // switch (child.type) { - // case 2: - // name = child.title; - // break; - // case 1: - // name = child.text; - // break; - // default: - // break; - // } - - // if (name && name === childName) { - // return child; - // } - // } - //} - - //function findMenu(rootMenu, path) { - // if ('string' === typeof(path)) { - // path = [ path ] - // } - - // var currentMenu = rootMenu; - // for (var i = 0; currentMenu && i < path.length; ++i) { - // currentMenu = findMenuChild(currentMenu, path[i]); - // } - - // return currentMenu; - //} - - //function findInRootMenu(item, path) { - // return findMenu(findRootMenu(item), path); - //} - - //function menuItemsToListModel(parent, items) { - // var newListModel = Qt.createQmlObject('import QtQuick 2.5; ListModel {}', parent); - // for (var i = 0; i < items.length; ++i) { - // var item = items[i]; - // switch (item.type) { - // case 2: - // newListModel.append({"type":item.type, "name": item.title, "item": item}) - // break; - // case 1: - // newListModel.append({"type":item.type, "name": item.text, "item": item}) - // break; - // case 0: - // newListModel.append({"type":item.type, "name": "-----", "item": item}) - // break; - // } - // } - // return newListModel; - //} + function unfocusWindows() { + var windows = d.getTopLevelWindows(); + for (var i = 0; i < windows.length; ++i) { + windows[i].focus = false; + } + desktop.focus = true; } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cc175e3fae..55619ec87a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2191,6 +2191,11 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { _altPressed = false; auto offscreenUi = DependencyManager::get(); + // If we get a mouse press event it means it wasn't consumed by the offscreen UI, + // hence, we should defocus all of the offscreen UI windows, in order to allow + // keyboard shortcuts not to be swallowed by them. In particular, WebEngineViews + // will consume all keyboard events. + offscreenUi->unfocusWindows(); QPointF transformedPos = offscreenUi->mapToVirtualScreen(event->localPos(), _glWidget); QMouseEvent mappedEvent(event->type(), transformedPos, diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 36905797d6..e215fcc067 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -279,5 +279,10 @@ QVariant OffscreenUi::returnFromUiThread(std::function function) { return function(); } +void OffscreenUi::unfocusWindows() { + bool invokeResult = QMetaObject::invokeMethod(_desktop, "unfocusWindows"); + Q_ASSERT(invokeResult); +} + #include "OffscreenUi.moc" diff --git a/libraries/ui/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h index b42fe50a92..fa4d7aaeaf 100644 --- a/libraries/ui/src/OffscreenUi.h +++ b/libraries/ui/src/OffscreenUi.h @@ -33,7 +33,7 @@ public: bool shouldSwallowShortcut(QEvent* event); bool navigationFocused(); void setNavigationFocused(bool focused); - + void unfocusWindows(); QQuickItem* getDesktop(); QQuickItem* getToolWindow(); diff --git a/tests/ui/qml/main.qml b/tests/ui/qml/main.qml index c1f1831275..0acb88c36d 100644 --- a/tests/ui/qml/main.qml +++ b/tests/ui/qml/main.qml @@ -39,8 +39,8 @@ ApplicationWindow { Root { id: desktop anchors.fill: parent - StubMenu { id: stubMenu } + Component.onCompleted: offscreenWindow = appWindow Row { id: testButtons From 737a00a2cb2eef2c2e8544f6d2365fc6e596ea4d Mon Sep 17 00:00:00 2001 From: AlessandroSigna Date: Mon, 18 Jan 2016 16:20:32 +0100 Subject: [PATCH 201/215] Typo fixed --- examples/vrShop/review/shopReviewEntityScript.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/vrShop/review/shopReviewEntityScript.js b/examples/vrShop/review/shopReviewEntityScript.js index 49f0a49dea..6f3aaa8186 100644 --- a/examples/vrShop/review/shopReviewEntityScript.js +++ b/examples/vrShop/review/shopReviewEntityScript.js @@ -241,7 +241,7 @@ var myName = MyAvatar.displayName ? MyAvatar.displayName : "Anonymous"; dbObj.dbKey[dbObj.dbKey.length] = {name: myName, score: scoreAssigned, clip_url: url}; setEntityCustomData('infoKey', dataBaseID, dbObj); - print("Feeded DB: " + url"); + print("Feeded DB: " + url); } }; From 2774df38bc9d20b557dbb7b4649896ce886e1ff3 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 14 Jan 2016 17:31:39 -0800 Subject: [PATCH 202/215] check for entity size before including it for LOD --- interface/src/LODManager.cpp | 2 +- libraries/entities/src/EntityTreeElement.cpp | 20 ++++++++ libraries/octree/src/Octree.cpp | 4 -- libraries/octree/src/Octree.h | 2 - libraries/octree/src/ViewFrustum.cpp | 48 ++++++++++++++++++++ libraries/octree/src/ViewFrustum.h | 2 + 6 files changed, 71 insertions(+), 7 deletions(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 13bedb128a..d8815be640 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -253,7 +253,7 @@ QString LODManager::getLODStatsRenderText() { const QString label = "Rendered objects: "; return label + QString::number(getRenderedCount()) + " w/in " + QString::number((int)getRenderDistance()) + "m"; } -// compare audoAdjustLOD() +// compare autoAdjustLOD() void LODManager::updatePIDRenderDistance(float targetFps, float measuredFps, float deltaTime, bool isThrottled) { float distance; if (!isThrottled) { diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 2320004be8..6d47a286d2 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -307,9 +307,29 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData if (!success || params.viewFrustum->cubeInFrustum(entityCube) == ViewFrustum::OUTSIDE) { includeThisEntity = false; // out of view, don't include it } + + // Now check the size of the entity, it's possible that a "too small to see" entity is included in a larger + // octree cell because of it's position (for example if it crosses the boundary of a cell it pops to the next + // higher cell. So we want to check to see that the entity is large enough to be seen before we consider + // including it. + if (includeThisEntity) { + AABox entityBounds = entity->getAABox(success); + if (success) { + auto renderAccuracy = params.viewFrustum->calculateRenderAccuracy(entityBounds, params.octreeElementSizeScale, params.boundaryLevelAdjust); + qDebug() << "checking entity:" << entity->getID() << " entityBounds:" << entityBounds << "---renderAccuracy:" << renderAccuracy + << " [ sizeScale:" << params.octreeElementSizeScale << "levelAdjust:" << params.boundaryLevelAdjust << " ]"; + if (renderAccuracy <= 0.0f) { + includeThisEntity = false; // too small, don't include it + qDebug() << "returning FALSE... too small..."; + } + } else { + includeThisEntity = false; // couldn't get box, don't include it + } + } } if (includeThisEntity) { + qDebug() << "including entity:" << entity->getID() << " octree cell:" << getAACube(); indexesOfEntitiesToInclude << i; numberOfEntities++; } diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 652089ebb1..bdad5682a9 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -50,10 +50,6 @@ QVector PERSIST_EXTENSIONS = {"svo", "json", "json.gz"}; -float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale) { - return voxelSizeScale / powf(2, renderLevel); -} - Octree::Octree(bool shouldReaverage) : _rootElement(NULL), _isDirty(true), diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index dc0294e1de..789d0f5600 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -385,6 +385,4 @@ protected: bool _isServer; }; -float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale); - #endif // hifi_Octree_h diff --git a/libraries/octree/src/ViewFrustum.cpp b/libraries/octree/src/ViewFrustum.cpp index fd175a8e5b..63cad25b8b 100644 --- a/libraries/octree/src/ViewFrustum.cpp +++ b/libraries/octree/src/ViewFrustum.cpp @@ -750,3 +750,51 @@ void ViewFrustum::evalViewTransform(Transform& view) const { view.setTranslation(getPosition()); view.setRotation(getOrientation()); } + +// renderAccuracy represents a floating point "visibility" of an object based on it's view from the camera. At a simple +// level it returns 0.0f for things that are so small for the current settings that they could not be visible. +float ViewFrustum::calculateRenderAccuracy(const AABox& bounds, float octreeSizeScale, int boundaryLevelAdjust) const { + float distanceToCamera = glm::length(bounds.calcCenter() - getPosition()); + float largestDimension = bounds.getLargestDimension(); + + const float maxScale = (float)TREE_SCALE; + const float octreeToMeshRatio = 4.0f; // must be this many times closer to a mesh than a voxel to see it. + float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / octreeToMeshRatio; + + static bool shouldRenderTableNeedsBuilding = true; + static QMap shouldRenderTable; + if (shouldRenderTableNeedsBuilding) { + float SMALLEST_SCALE_IN_TABLE = 0.001f; // 1mm is plenty small + float scale = maxScale; + float factor = 1.0f; + + while (scale > SMALLEST_SCALE_IN_TABLE) { + scale /= 2.0f; + factor /= 2.0f; + shouldRenderTable[scale] = factor; + } + + shouldRenderTableNeedsBuilding = false; + } + + float closestScale = maxScale; + float visibleDistanceAtClosestScale = visibleDistanceAtMaxScale; + QMap::const_iterator lowerBound = shouldRenderTable.lowerBound(largestDimension); + if (lowerBound != shouldRenderTable.constEnd()) { + closestScale = lowerBound.key(); + visibleDistanceAtClosestScale = visibleDistanceAtMaxScale * lowerBound.value(); + } + + if (closestScale < largestDimension) { + visibleDistanceAtClosestScale *= 2.0f; + } + + // FIXME - for now, it's either visible or not visible. We want to adjust this to eventually return + // a floating point for objects that have small angular size to indicate that they may be rendered + // with lower preciscion + return (distanceToCamera <= visibleDistanceAtClosestScale) ? 1.0f : 0.0f; +} + +float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale) { + return voxelSizeScale / powf(2, renderLevel); +} diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index 795a259a3c..0d6170e3ed 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -107,6 +107,7 @@ public: void evalProjectionMatrix(glm::mat4& proj) const; void evalViewTransform(Transform& view) const; + float calculateRenderAccuracy(const AABox& bounds, float octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE, int boundaryLevelAdjust = 0) const; private: // Used for keyhole calculations @@ -152,5 +153,6 @@ private: glm::mat4 _ourModelViewProjectionMatrix; }; +float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale); #endif // hifi_ViewFrustum_h From 88af387214546ae4b56186e0c109219f940df040 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 18 Jan 2016 10:10:24 -0800 Subject: [PATCH 203/215] cleanup --- interface/src/LODManager.cpp | 85 ++------------------ interface/src/LODManager.h | 1 - libraries/entities/src/EntityTreeElement.cpp | 32 +++++--- libraries/octree/src/OctreeConstants.h | 6 ++ libraries/octree/src/ViewFrustum.cpp | 5 +- libraries/octree/src/ViewFrustum.h | 6 +- 6 files changed, 43 insertions(+), 92 deletions(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index d8815be640..4dec925530 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -25,7 +25,7 @@ Setting::Handle hmdLODDecreaseFPS("hmdLODDecreaseFPS", DEFAULT_HMD_LOD_DO // pid: renderDistance is adjusted by a PID such that frame rate targets are met. // acuity: a pseudo-acuity target is held, or adjusted to match minimum frame rates (and a PID controlls avatar rendering distance) // If unspecified, acuity is used only if user has specified non-default minumum frame rates. -Setting::Handle lodPreference("lodPreference", (int)LODManager::LODPreference::unspecified); +Setting::Handle lodPreference("lodPreference", (int)LODManager::LODPreference::acuity); const float SMALLEST_REASONABLE_HORIZON = 50.0f; // meters Setting::Handle renderDistanceInverseHighLimit("renderDistanceInverseHighLimit", 1.0f / SMALLEST_REASONABLE_HORIZON); void LODManager::setRenderDistanceInverseHighLimit(float newValue) { @@ -274,92 +274,23 @@ void LODManager::updatePIDRenderDistance(float targetFps, float measuredFps, flo } bool LODManager::shouldRender(const RenderArgs* args, const AABox& bounds) { - float distanceToCamera = glm::length(bounds.calcCenter() - args->_viewFrustum->getPosition()); - float largestDimension = bounds.getLargestDimension(); + // NOTE: this branch of code is the alternate form of LOD that uses PID controllers. if (!getUseAcuity()) { + float distanceToCamera = glm::length(bounds.calcCenter() - args->_viewFrustum->getPosition()); + float largestDimension = bounds.getLargestDimension(); const float scenerySize = 300; // meters bool isRendered = (largestDimension > scenerySize) || // render scenery regardless of distance (distanceToCamera < renderDistance + largestDimension); renderedCount += isRendered ? 1 : 0; return isRendered; } - - const float maxScale = (float)TREE_SCALE; - const float octreeToMeshRatio = 4.0f; // must be this many times closer to a mesh than a voxel to see it. - float octreeSizeScale = args->_sizeScale; - int boundaryLevelAdjust = args->_boundaryLevelAdjust; - float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / octreeToMeshRatio; - - static bool shouldRenderTableNeedsBuilding = true; - static QMap shouldRenderTable; - if (shouldRenderTableNeedsBuilding) { - float SMALLEST_SCALE_IN_TABLE = 0.001f; // 1mm is plenty small - float scale = maxScale; - float factor = 1.0f; - - while (scale > SMALLEST_SCALE_IN_TABLE) { - scale /= 2.0f; - factor /= 2.0f; - shouldRenderTable[scale] = factor; - } - - shouldRenderTableNeedsBuilding = false; - } - float closestScale = maxScale; - float visibleDistanceAtClosestScale = visibleDistanceAtMaxScale; - QMap::const_iterator lowerBound = shouldRenderTable.lowerBound(largestDimension); - if (lowerBound != shouldRenderTable.constEnd()) { - closestScale = lowerBound.key(); - visibleDistanceAtClosestScale = visibleDistanceAtMaxScale * lowerBound.value(); - } - - if (closestScale < largestDimension) { - visibleDistanceAtClosestScale *= 2.0f; - } - - return distanceToCamera <= visibleDistanceAtClosestScale; + // FIXME - eventually we want to use the render accuracy as an indicator for the level of detail + // to use in rendering. + float renderAccuracy = args->_viewFrustum->calculateRenderAccuracy(bounds, args->_sizeScale, args->_boundaryLevelAdjust); + return (renderAccuracy > 0.0f); }; -// TODO: This is essentially the same logic used to render octree cells, but since models are more detailed then octree cells -// I've added a voxelToModelRatio that adjusts how much closer to a model you have to be to see it. -bool LODManager::shouldRenderMesh(float largestDimension, float distanceToCamera) { - const float octreeToMeshRatio = 4.0f; // must be this many times closer to a mesh than a voxel to see it. - float octreeSizeScale = getOctreeSizeScale(); - int boundaryLevelAdjust = getBoundaryLevelAdjust(); - float maxScale = (float)TREE_SCALE; - float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / octreeToMeshRatio; - - if (_shouldRenderTableNeedsRebuilding) { - _shouldRenderTable.clear(); - - float SMALLEST_SCALE_IN_TABLE = 0.001f; // 1mm is plenty small - float scale = maxScale; - float visibleDistanceAtScale = visibleDistanceAtMaxScale; - - while (scale > SMALLEST_SCALE_IN_TABLE) { - scale /= 2.0f; - visibleDistanceAtScale /= 2.0f; - _shouldRenderTable[scale] = visibleDistanceAtScale; - } - _shouldRenderTableNeedsRebuilding = false; - } - - float closestScale = maxScale; - float visibleDistanceAtClosestScale = visibleDistanceAtMaxScale; - QMap::const_iterator lowerBound = _shouldRenderTable.lowerBound(largestDimension); - if (lowerBound != _shouldRenderTable.constEnd()) { - closestScale = lowerBound.key(); - visibleDistanceAtClosestScale = lowerBound.value(); - } - - if (closestScale < largestDimension) { - visibleDistanceAtClosestScale *= 2.0f; - } - - return (distanceToCamera <= visibleDistanceAtClosestScale); -} - void LODManager::setOctreeSizeScale(float sizeScale) { _octreeSizeScale = sizeScale; calculateAvatarLODDistanceMultiplier(); diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 6b141004e5..d8fcc50cac 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -104,7 +104,6 @@ public: QString getLODStatsRenderText(); static bool shouldRender(const RenderArgs* args, const AABox& bounds); - bool shouldRenderMesh(float largestDimension, float distanceToCamera); void autoAdjustLOD(float currentFPS); void loadSettings(); diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 6d47a286d2..4842197201 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -308,19 +308,27 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData includeThisEntity = false; // out of view, don't include it } - // Now check the size of the entity, it's possible that a "too small to see" entity is included in a larger - // octree cell because of it's position (for example if it crosses the boundary of a cell it pops to the next - // higher cell. So we want to check to see that the entity is large enough to be seen before we consider - // including it. + // Now check the size of the entity, it's possible that a "too small to see" entity is included in a + // larger octree cell because of it's position (for example if it crosses the boundary of a cell it + // pops to the next higher cell. So we want to check to see that the entity is large enough to be seen + // before we consider including it. if (includeThisEntity) { AABox entityBounds = entity->getAABox(success); if (success) { - auto renderAccuracy = params.viewFrustum->calculateRenderAccuracy(entityBounds, params.octreeElementSizeScale, params.boundaryLevelAdjust); - qDebug() << "checking entity:" << entity->getID() << " entityBounds:" << entityBounds << "---renderAccuracy:" << renderAccuracy - << " [ sizeScale:" << params.octreeElementSizeScale << "levelAdjust:" << params.boundaryLevelAdjust << " ]"; + auto renderAccuracy = params.viewFrustum->calculateRenderAccuracy(entityBounds, + params.octreeElementSizeScale, params.boundaryLevelAdjust); + if (renderAccuracy <= 0.0f) { includeThisEntity = false; // too small, don't include it - qDebug() << "returning FALSE... too small..."; + + #ifdef WANT_LOD_DEBUGGING + qDebug() << "skipping entity - TOO SMALL - \n" + << "......id:" << entity->getID() << "\n" + << "....name:" << entity->getName() << "\n" + << "..bounds:" << entityBounds << "\n" + << "....cell:" << getAACube(); + #endif + } } else { includeThisEntity = false; // couldn't get box, don't include it @@ -329,7 +337,13 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData } if (includeThisEntity) { - qDebug() << "including entity:" << entity->getID() << " octree cell:" << getAACube(); + #ifdef WANT_LOD_DEBUGGING + qDebug() << "including entity - \n" + << "......id:" << entity->getID() << "\n" + << "....name:" << entity->getName() << "\n" + << "..bounds:" << entityBounds << "\n" + << "....cell:" << getAACube(); + #endif indexesOfEntitiesToInclude << i; numberOfEntities++; } diff --git a/libraries/octree/src/OctreeConstants.h b/libraries/octree/src/OctreeConstants.h index 0b05a8606c..ea1ea63353 100644 --- a/libraries/octree/src/OctreeConstants.h +++ b/libraries/octree/src/OctreeConstants.h @@ -23,6 +23,12 @@ const int HALF_TREE_SCALE = TREE_SCALE / 2; // This controls the LOD. Larger number will make smaller voxels visible at greater distance. const float DEFAULT_OCTREE_SIZE_SCALE = TREE_SCALE * 400.0f; +// Since entities like models live inside of octree cells, and they themselves can have very small mesh parts, +// we want to have some constant that controls have big a mesh part must be to render even if the octree cell itself +// would be visible. This constanct controls that. It basically means you must be this many times closer to a mesh +// than an octree cell to see the mesh. +const float OCTREE_TO_MESH_RATIO = 4.0f; + // This is used in the LOD Tools to translate between the size scale slider and the values used to set the OctreeSizeScale const float MAX_LOD_SIZE_MULTIPLIER = 4000.0f; diff --git a/libraries/octree/src/ViewFrustum.cpp b/libraries/octree/src/ViewFrustum.cpp index 63cad25b8b..126eea4f27 100644 --- a/libraries/octree/src/ViewFrustum.cpp +++ b/libraries/octree/src/ViewFrustum.cpp @@ -751,15 +751,12 @@ void ViewFrustum::evalViewTransform(Transform& view) const { view.setRotation(getOrientation()); } -// renderAccuracy represents a floating point "visibility" of an object based on it's view from the camera. At a simple -// level it returns 0.0f for things that are so small for the current settings that they could not be visible. float ViewFrustum::calculateRenderAccuracy(const AABox& bounds, float octreeSizeScale, int boundaryLevelAdjust) const { float distanceToCamera = glm::length(bounds.calcCenter() - getPosition()); float largestDimension = bounds.getLargestDimension(); const float maxScale = (float)TREE_SCALE; - const float octreeToMeshRatio = 4.0f; // must be this many times closer to a mesh than a voxel to see it. - float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / octreeToMeshRatio; + float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / OCTREE_TO_MESH_RATIO; static bool shouldRenderTableNeedsBuilding = true; static QMap shouldRenderTable; diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index 0d6170e3ed..43f594b54c 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -107,7 +107,11 @@ public: void evalProjectionMatrix(glm::mat4& proj) const; void evalViewTransform(Transform& view) const; - float calculateRenderAccuracy(const AABox& bounds, float octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE, int boundaryLevelAdjust = 0) const; + + /// renderAccuracy represents a floating point "visibility" of an object based on it's view from the camera. At a simple + /// level it returns 0.0f for things that are so small for the current settings that they could not be visible. + float calculateRenderAccuracy(const AABox& bounds, float octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE, + int boundaryLevelAdjust = 0) const; private: // Used for keyhole calculations From 6434d983657cf47b7cf09dd7e32dfa9b02f6f15b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 18 Jan 2016 11:11:28 -0800 Subject: [PATCH 204/215] Separate directional shaders with(out) shadowmaps --- .../src/DeferredLightingEffect.cpp | 7 ++- .../src/directional_ambient_light.slf | 6 +-- .../src/directional_ambient_light_shadow.slf | 51 ++++++++++++++++++ .../render-utils/src/directional_light.slf | 6 +-- .../src/directional_light_shadow.slf | 52 ++++++++++++++++++ .../src/directional_skybox_light.slf | 10 ++-- .../src/directional_skybox_light_shadow.slf | 53 +++++++++++++++++++ 7 files changed, 170 insertions(+), 15 deletions(-) create mode 100644 libraries/render-utils/src/directional_ambient_light_shadow.slf create mode 100644 libraries/render-utils/src/directional_light_shadow.slf create mode 100644 libraries/render-utils/src/directional_skybox_light_shadow.slf diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index ac18348528..5af89e7afc 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -31,6 +31,10 @@ #include "directional_ambient_light_frag.h" #include "directional_skybox_light_frag.h" +#include "directional_light_shadow_frag.h" +#include "directional_ambient_light_shadow_frag.h" +#include "directional_skybox_light_shadow_frag.h" + #include "point_light_frag.h" #include "spot_light_frag.h" @@ -47,14 +51,15 @@ struct LightLocations { static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations); - void DeferredLightingEffect::init() { _directionalLightLocations = std::make_shared(); _directionalAmbientSphereLightLocations = std::make_shared(); _directionalSkyboxLightLocations = std::make_shared(); + _pointLightLocations = std::make_shared(); _spotLightLocations = std::make_shared(); + // TODO: To use shadowmaps, replace directional_*_light_frag with directional_*_light_shadow_frag shaders. loadLightProgram(deferred_light_vert, directional_light_frag, false, _directionalLight, _directionalLightLocations); loadLightProgram(deferred_light_vert, directional_ambient_light_frag, false, _directionalAmbientSphereLight, _directionalAmbientSphereLightLocations); loadLightProgram(deferred_light_vert, directional_skybox_light_frag, false, _directionalSkyboxLight, _directionalSkyboxLightLocations); diff --git a/libraries/render-utils/src/directional_ambient_light.slf b/libraries/render-utils/src/directional_ambient_light.slf index 5b936f566f..5c0a5c8331 100755 --- a/libraries/render-utils/src/directional_ambient_light.slf +++ b/libraries/render-utils/src/directional_ambient_light.slf @@ -6,13 +6,12 @@ // fragment shader // // Created by Andrzej Kapolka on 9/3/14. -// Copyright 2014 High Fidelity, Inc. +// Copyright 2016 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 Shadow.slh@> <@include DeferredBuffer.slh@> <@include DeferredGlobalLight.slh@> @@ -26,8 +25,7 @@ void main(void) { DeferredTransform deferredTransform = getDeferredTransform(); DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); - vec4 worldPos = deferredTransform.viewInverse * vec4(frag.position.xyz, 1.0); - float shadowAttenuation = evalShadowAttenuation(worldPos); + float shadowAttenuation = 1.0; if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { vec3 color = evalLightmappedColor( diff --git a/libraries/render-utils/src/directional_ambient_light_shadow.slf b/libraries/render-utils/src/directional_ambient_light_shadow.slf new file mode 100644 index 0000000000..1cb425c881 --- /dev/null +++ b/libraries/render-utils/src/directional_ambient_light_shadow.slf @@ -0,0 +1,51 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// directional_light_shadow.frag +// fragment shader +// +// Created by Zach Pomerantz on 1/18/2016. +// Copyright 2016 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 Shadow.slh@> +<@include DeferredBuffer.slh@> +<@include DeferredGlobalLight.slh@> + +<$declareEvalLightmappedColor()$> +<$declareEvalAmbientSphereGlobalColor()$> + +in vec2 _texCoord0; +out vec4 _fragColor; + +void main(void) { + DeferredTransform deferredTransform = getDeferredTransform(); + DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); + + vec4 worldPos = deferredTransform.viewInverse * vec4(frag.position.xyz, 1.0); + float shadowAttenuation = evalShadowAttenuation(worldPos); + + if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { + vec3 color = evalLightmappedColor( + deferredTransform.viewInverse, + shadowAttenuation, + frag.normal, + frag.diffuse, + frag.specularVal.xyz); + _fragColor = vec4(color, 1.0); + } else { + vec3 color = evalAmbientSphereGlobalColor( + deferredTransform.viewInverse, + shadowAttenuation, + frag.position.xyz, + frag.normal, + frag.diffuse, + frag.specular, + frag.gloss); + _fragColor = vec4(color, frag.normalVal.a); + } +} diff --git a/libraries/render-utils/src/directional_light.slf b/libraries/render-utils/src/directional_light.slf index f057f9cc35..9318f07f5a 100644 --- a/libraries/render-utils/src/directional_light.slf +++ b/libraries/render-utils/src/directional_light.slf @@ -6,13 +6,12 @@ // fragment shader // // Created by Andrzej Kapolka on 9/3/14. -// Copyright 2014 High Fidelity, Inc. +// Copyright 2016 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 Shadow.slh@> <@include DeferredBuffer.slh@> <@include DeferredGlobalLight.slh@> @@ -26,8 +25,7 @@ void main(void) { DeferredTransform deferredTransform = getDeferredTransform(); DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); - vec4 worldPos = deferredTransform.viewInverse * vec4(frag.position.xyz, 1.0); - float shadowAttenuation = evalShadowAttenuation(worldPos); + float shadowAttenuation = 1.0; // Light mapped or not ? if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { diff --git a/libraries/render-utils/src/directional_light_shadow.slf b/libraries/render-utils/src/directional_light_shadow.slf new file mode 100644 index 0000000000..6c7c450bc5 --- /dev/null +++ b/libraries/render-utils/src/directional_light_shadow.slf @@ -0,0 +1,52 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// directional_light_shadow.frag +// fragment shader +// +// Created by Zach Pomerantz on 1/18/2016. +// Copyright 2016 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 Shadow.slh@> +<@include DeferredBuffer.slh@> +<@include DeferredGlobalLight.slh@> + +<$declareEvalLightmappedColor()$> +<$declareEvalAmbientGlobalColor()$> + +in vec2 _texCoord0; +out vec4 _fragColor; + +void main(void) { + DeferredTransform deferredTransform = getDeferredTransform(); + DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); + + vec4 worldPos = deferredTransform.viewInverse * vec4(frag.position.xyz, 1.0); + float shadowAttenuation = evalShadowAttenuation(worldPos); + + // Light mapped or not ? + if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { + vec3 color = evalLightmappedColor( + deferredTransform.viewInverse, + shadowAttenuation, + frag.normal, + frag.diffuse, + frag.specularVal.xyz); + _fragColor = vec4(color, 1.0); + } else { + vec3 color = evalAmbientGlobalColor( + deferredTransform.viewInverse, + shadowAttenuation, + frag.position.xyz, + frag.normal, + frag.diffuse, + frag.specular, + frag.gloss); + _fragColor = vec4(color, frag.normalVal.a); + } +} diff --git a/libraries/render-utils/src/directional_skybox_light.slf b/libraries/render-utils/src/directional_skybox_light.slf index 871cb32337..d149a78a14 100755 --- a/libraries/render-utils/src/directional_skybox_light.slf +++ b/libraries/render-utils/src/directional_skybox_light.slf @@ -3,16 +3,15 @@ // Generated on <$_SCRIBE_DATE$> // // directional_light.frag - +// -<@include Shadow.slh@> <@include DeferredBuffer.slh@> <@include DeferredGlobalLight.slh@> @@ -26,8 +25,7 @@ void main(void) { DeferredTransform deferredTransform = getDeferredTransform(); DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); - vec4 worldPos = deferredTransform.viewInverse * vec4(frag.position.xyz, 1.0); - float shadowAttenuation = evalShadowAttenuation(worldPos); + float shadowAttenuation = 1.0; // Light mapped or not ? if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { diff --git a/libraries/render-utils/src/directional_skybox_light_shadow.slf b/libraries/render-utils/src/directional_skybox_light_shadow.slf new file mode 100644 index 0000000000..1b7ef76035 --- /dev/null +++ b/libraries/render-utils/src/directional_skybox_light_shadow.slf @@ -0,0 +1,53 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// directional_light_shadow.frag +// fragment shader +// +// Created by Zach Pomerantz on 1/18/2016. +// Copyright 2016 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 Shadow.slh@> +<@include DeferredBuffer.slh@> +<@include DeferredGlobalLight.slh@> + +<$declareEvalLightmappedColor()$> +<$declareEvalSkyboxGlobalColor()$> + +in vec2 _texCoord0; +out vec4 _fragColor; + +void main(void) { + DeferredTransform deferredTransform = getDeferredTransform(); + DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); + + vec4 worldPos = deferredTransform.viewInverse * vec4(frag.position.xyz, 1.0); + float shadowAttenuation = evalShadowAttenuation(worldPos); + + // Light mapped or not ? + if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { + vec3 color = evalLightmappedColor( + deferredTransform.viewInverse, + shadowAttenuation, + frag.normal, + frag.diffuse, + frag.specularVal.xyz); + _fragColor = vec4(color, 1.0); + } else { + vec3 color = evalSkyboxGlobalColor( + deferredTransform.viewInverse, + shadowAttenuation, + frag.position.xyz, + frag.normal, + frag.diffuse, + frag.specular, + frag.gloss); + + _fragColor = vec4(color, frag.normalVal.a); + } +} From 8b6e89a5c464aa78d9eb4761e38b6d47ac5ba314 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 18 Jan 2016 11:13:33 -0800 Subject: [PATCH 205/215] fix stopFarTrigger entity method call. re-add code to keep more than one distance grab per object from happening --- examples/controllers/handControllerGrab.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 7721366bab..3b46a51960 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -42,7 +42,7 @@ var PICK_WITH_HAND_RAY = true; var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did -var MOVE_WITH_HEAD = true; // experimental head-controll of distantly held objects +var MOVE_WITH_HEAD = true; // experimental head-control of distantly held objects var FAR_TO_NEAR_GRAB_PADDING_FACTOR = 1.2; var NO_INTERSECT_COLOR = { @@ -917,6 +917,10 @@ function MyController(hand) { } // far grab or equip with action if (isPhysical && !near) { + if (entityIsGrabbedByOther(intersection.entityID)) { + // don't distance grab something that is already grabbed. + return; + } this.temporaryPositionOffset = null; if (typeof grabbableData.spatialKey === 'undefined') { // We want to give a temporary position offset to this object so it is pulled close to hand @@ -1143,7 +1147,6 @@ function MyController(hand) { y: this.currentObjectPosition.y, z: this.currentObjectPosition.z } - } @@ -1489,7 +1492,7 @@ function MyController(hand) { this.continueFarTrigger = function() { if (this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); return; } From 4232e400ccc7b3682d0865e58d49191d46ab784c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 18 Jan 2016 11:15:03 -0800 Subject: [PATCH 206/215] add getJointIndex call --- .../src/RenderableModelEntityItem.cpp | 14 ++++++++++++++ .../src/RenderableModelEntityItem.h | 2 ++ 2 files changed, 16 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 58c06fccfb..57a29de596 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -763,3 +763,17 @@ void RenderableModelEntityItem::locationChanged() { _model->setTranslation(getPosition()); } } + +int RenderableModelEntityItem::getJointIndex(const QString& name) const { + if (_model && _model->isActive()) { + RigPointer rig = _model->getRig(); + return rig->indexOfJoint(name); + } + return -1; +} + + +// TODO -- expose a way to list joint names +// RenderableModelEntityItem::QStringList getJointNames() const { +// rig->nameOfJoint(i); +// } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 99e5ecb097..834513ecf7 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -79,6 +79,8 @@ public: virtual void resizeJointArrays(int newSize = -1) override; + virtual int getJointIndex(const QString& name) const override; + private: QVariantMap parseTexturesToMap(QString textures); void remapTextures(); From d6e3b85237ea96e66634f037bf00691456b7b352 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 18 Jan 2016 11:15:32 -0800 Subject: [PATCH 207/215] fix javascript access via localPosition and localRotation --- libraries/entities/src/EntityItem.cpp | 2 ++ libraries/entities/src/EntityItem.h | 2 ++ .../entities/src/EntityItemProperties.cpp | 13 +++++++++++-- .../entities/src/EntityScriptingInterface.cpp | 18 +++++++++++++++++- .../entities/src/EntityScriptingInterface.h | 2 ++ 5 files changed, 34 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 0a7a30f098..a6835dff41 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1057,6 +1057,8 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentID, getParentID); COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentJointIndex, getParentJointIndex); COPY_ENTITY_PROPERTY_TO_PROPERTIES(queryAACube, getQueryAACube); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(localPosition, getLocalPosition); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(localRotation, getLocalOrientation); properties._defaultSettings = false; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index d0b79723d1..7507893b3d 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -395,6 +395,8 @@ public: virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; } virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override { return false; } + virtual int getJointIndex(const QString& name) const { return -1; } + virtual void loader() {} // called indirectly when urls for geometry are updated protected: diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index f8dcb6ee56..d1a5b8d9ee 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -321,6 +321,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_JOINT_TRANSLATIONS_SET, jointTranslationsSet); CHECK_PROPERTY_CHANGE(PROP_JOINT_TRANSLATIONS, jointTranslations); CHECK_PROPERTY_CHANGE(PROP_QUERY_AA_CUBE, queryAACube); + CHECK_PROPERTY_CHANGE(PROP_LOCAL_POSITION, localPosition); + CHECK_PROPERTY_CHANGE(PROP_LOCAL_ROTATION, localRotation); changedProperties += _animation.getChangedProperties(); changedProperties += _keyLight.getChangedProperties(); @@ -415,8 +417,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_START, alphaStart); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_FINISH, alphaFinish); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMITTER_SHOULD_TRAIL, emitterShouldTrail); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_POSITION, localPosition); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localRotation); } // Models only @@ -432,6 +432,12 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool if (_type == EntityTypes::Model || _type == EntityTypes::Zone || _type == EntityTypes::ParticleEffect) { COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, getShapeTypeAsString()); } + if (_type == EntityTypes::Box) { + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, QString("Box")); + } + if (_type == EntityTypes::Sphere) { + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, QString("Sphere")); + } // FIXME - it seems like ParticleEffect should also support this if (_type == EntityTypes::Model || _type == EntityTypes::Zone) { @@ -822,6 +828,9 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_PARENT_ID, ParentID, parentID, QUuid); ADD_PROPERTY_TO_MAP(PROP_PARENT_JOINT_INDEX, ParentJointIndex, parentJointIndex, uint16_t); + ADD_PROPERTY_TO_MAP(PROP_LOCAL_POSITION, LocalPosition, localPosition, glm::vec3); + ADD_PROPERTY_TO_MAP(PROP_LOCAL_ROTATION, LocalRotation, localRotation, glm::quat); + ADD_PROPERTY_TO_MAP(PROP_JOINT_ROTATIONS_SET, JointRotationsSet, jointRotationsSet, QVector); ADD_PROPERTY_TO_MAP(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector); ADD_PROPERTY_TO_MAP(PROP_JOINT_TRANSLATIONS_SET, JointTranslationsSet, jointTranslationsSet, QVector); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 4e2052c283..f78cd4fd8c 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -178,6 +178,15 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit desiredProperties.setHasProperty(PROP_PARENT_JOINT_INDEX); } + if (desiredProperties.isEmpty()) { + // these are left out of EntityItem::getEntityProperties so that localPosition and localRotation + // don't end up in json saves, etc. We still want them here, though. + EncodeBitstreamParams params; // unknown + desiredProperties = entity->getEntityProperties(params); + desiredProperties.setHasProperty(PROP_LOCAL_POSITION); + desiredProperties.setHasProperty(PROP_LOCAL_ROTATION); + } + results = entity->getProperties(desiredProperties); // TODO: improve sitting points and naturalDimensions in the future, @@ -956,7 +965,6 @@ bool EntityScriptingInterface::setAbsoluteJointTranslationsInObjectFrame(const Q return false; } - bool EntityScriptingInterface::setAbsoluteJointsDataInObjectFrame(const QUuid& entityID, const QVector& rotations, const QVector& translations) { @@ -964,3 +972,11 @@ bool EntityScriptingInterface::setAbsoluteJointsDataInObjectFrame(const QUuid& e return setAbsoluteJointRotationsInObjectFrame(entityID, rotations) || setAbsoluteJointTranslationsInObjectFrame(entityID, translations); } + +int EntityScriptingInterface::getJointIndex(const QUuid& entityID, const QString& name) { + if (!_entityTree) { + return -1; + } + EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); + return entity->getJointIndex(name); +} diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 5c22d7f6b8..e7a4c0e071 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -161,6 +161,8 @@ public slots: const QVector& rotations, const QVector& translations); + Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name); + signals: void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); From 3b3720781f11c168f01e418110a8bd58ab3d7aba Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 18 Jan 2016 11:15:53 -0800 Subject: [PATCH 208/215] fix a place where parent's scale wasn't properly squashed --- libraries/shared/src/SpatiallyNestable.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 02b1c0c0ae..2fea6b7db4 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -371,6 +371,7 @@ const Transform SpatiallyNestable::getTransform(int jointIndex, bool& success) c Transform jointInWorldFrame; Transform worldTransform = getTransform(success); + worldTransform.setScale(1.0f); // TODO -- scale; if (!success) { return jointInWorldFrame; } From d10e1cc39d526ecb195df712bfa642e09d820808 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 18 Jan 2016 12:09:21 -0800 Subject: [PATCH 209/215] CR feedback, dead code cleanup --- interface/src/Application.cpp | 8 -------- interface/src/Application.h | 2 -- interface/src/LODManager.cpp | 3 --- interface/src/LODManager.h | 3 --- .../entities-renderer/src/EntityTreeRenderer.cpp | 9 --------- libraries/entities-renderer/src/EntityTreeRenderer.h | 2 -- libraries/entities/src/EntityTreeElement.cpp | 5 ++--- libraries/octree/src/OctreeHeadlessViewer.cpp | 11 +++-------- libraries/octree/src/OctreeHeadlessViewer.h | 9 +++++---- libraries/octree/src/OctreeRenderer.h | 2 -- libraries/octree/src/ViewFrustum.cpp | 8 +++----- .../render-utils/src/AbstractViewStateInterface.h | 2 -- 12 files changed, 13 insertions(+), 51 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ccde915ecc..e44f310700 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3507,14 +3507,6 @@ glm::vec3 Application::getSunDirection() { // FIXME, preprocessor guard this check to occur only in DEBUG builds static QThread * activeRenderingThread = nullptr; -float Application::getSizeScale() const { - return DependencyManager::get()->getOctreeSizeScale(); -} - -int Application::getBoundaryLevelAdjust() const { - return DependencyManager::get()->getBoundaryLevelAdjust(); -} - PickRay Application::computePickRay(float x, float y) const { vec2 pickPoint { x, y }; PickRay result; diff --git a/interface/src/Application.h b/interface/src/Application.h index 24e853eabb..3840e10c93 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -170,8 +170,6 @@ public: virtual ViewFrustum* getCurrentViewFrustum() { return getDisplayViewFrustum(); } virtual QThread* getMainThread() { return thread(); } - virtual float getSizeScale() const; - virtual int getBoundaryLevelAdjust() const; virtual PickRay computePickRay(float x, float y) const; virtual glm::vec3 getAvatarPosition() const; virtual void overrideEnvironmentData(const EnvironmentData& newData) { _environment.override(newData); } diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 4dec925530..c846757325 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -183,7 +183,6 @@ void LODManager::autoAdjustLOD(float currentFPS) { if (changed) { calculateAvatarLODDistanceMultiplier(); - _shouldRenderTableNeedsRebuilding = true; auto lodToolsDialog = DependencyManager::get()->getLodToolsDialog(); if (lodToolsDialog) { lodToolsDialog->reloadSliders(); @@ -294,7 +293,6 @@ bool LODManager::shouldRender(const RenderArgs* args, const AABox& bounds) { void LODManager::setOctreeSizeScale(float sizeScale) { _octreeSizeScale = sizeScale; calculateAvatarLODDistanceMultiplier(); - _shouldRenderTableNeedsRebuilding = true; } void LODManager::calculateAvatarLODDistanceMultiplier() { @@ -303,7 +301,6 @@ void LODManager::calculateAvatarLODDistanceMultiplier() { void LODManager::setBoundaryLevelAdjust(int boundaryLevelAdjust) { _boundaryLevelAdjust = boundaryLevelAdjust; - _shouldRenderTableNeedsRebuilding = true; } diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index d8fcc50cac..3566113519 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -135,9 +135,6 @@ private: SimpleMovingAverage _fpsAverageDownWindow = DOWN_SHIFT_SAMPLES_OF_FRAMES; SimpleMovingAverage _fpsAverageUpWindow = UP_SHIFT_SAMPLES_OF_FRAMES; - bool _shouldRenderTableNeedsRebuilding = true; - QMap _shouldRenderTable; - PIDController _renderDistanceController{}; SimpleMovingAverage _renderDistanceAverage{ 10 }; }; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index c3e012d412..a2c1cf27c2 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -417,15 +417,6 @@ const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(EntityItemP return result; } -float EntityTreeRenderer::getSizeScale() const { - return _viewState->getSizeScale(); -} - -int EntityTreeRenderer::getBoundaryLevelAdjust() const { - return _viewState->getBoundaryLevelAdjust(); -} - - void EntityTreeRenderer::processEraseMessage(ReceivedMessage& message, const SharedNodePointer& sourceNode) { std::static_pointer_cast(_tree)->processEraseMessage(message, sourceNode); } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 09fe7a527c..2a3d688492 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -41,8 +41,6 @@ public: virtual char getMyNodeType() const { return NodeType::EntityServer; } virtual PacketType getMyQueryMessageType() const { return PacketType::EntityQuery; } virtual PacketType getExpectedPacketType() const { return PacketType::EntityData; } - virtual float getSizeScale() const; - virtual int getBoundaryLevelAdjust() const; virtual void setTree(OctreePointer newTree); void shutdown(); diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 4842197201..db44a5499b 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -321,7 +321,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData if (renderAccuracy <= 0.0f) { includeThisEntity = false; // too small, don't include it - #ifdef WANT_LOD_DEBUGGING + #if 1 //def WANT_LOD_DEBUGGING qDebug() << "skipping entity - TOO SMALL - \n" << "......id:" << entity->getID() << "\n" << "....name:" << entity->getName() << "\n" @@ -337,11 +337,10 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData } if (includeThisEntity) { - #ifdef WANT_LOD_DEBUGGING + #if 1 //def WANT_LOD_DEBUGGING qDebug() << "including entity - \n" << "......id:" << entity->getID() << "\n" << "....name:" << entity->getName() << "\n" - << "..bounds:" << entityBounds << "\n" << "....cell:" << getAACube(); #endif indexesOfEntitiesToInclude << i; diff --git a/libraries/octree/src/OctreeHeadlessViewer.cpp b/libraries/octree/src/OctreeHeadlessViewer.cpp index 3f761a0748..547b3ac32b 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.cpp +++ b/libraries/octree/src/OctreeHeadlessViewer.cpp @@ -14,11 +14,7 @@ #include "OctreeLogging.h" #include "OctreeHeadlessViewer.h" -OctreeHeadlessViewer::OctreeHeadlessViewer() : - OctreeRenderer(), - _voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE), - _boundaryLevelAdjust(0), - _maxPacketsPerSecond(DEFAULT_MAX_OCTREE_PPS) +OctreeHeadlessViewer::OctreeHeadlessViewer() : OctreeRenderer() { _viewFrustum.setProjection(glm::perspective(glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES), DEFAULT_ASPECT_RATIO, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP)); } @@ -57,9 +53,8 @@ void OctreeHeadlessViewer::queryOctree() { _octreeQuery.setCameraFarClip(_viewFrustum.getFarClip()); _octreeQuery.setCameraEyeOffsetPosition(glm::vec3()); _octreeQuery.setKeyholeRadius(_viewFrustum.getKeyholeRadius()); - - _octreeQuery.setOctreeSizeScale(getVoxelSizeScale()); - _octreeQuery.setBoundaryLevelAdjust(getBoundaryLevelAdjust()); + _octreeQuery.setOctreeSizeScale(_voxelSizeScale); + _octreeQuery.setBoundaryLevelAdjust(_boundaryLevelAdjust); // Iterate all of the nodes, and get a count of how many voxel servers we have... int totalServers = 0; diff --git a/libraries/octree/src/OctreeHeadlessViewer.h b/libraries/octree/src/OctreeHeadlessViewer.h index 82282dafaa..bdfebd82f6 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.h +++ b/libraries/octree/src/OctreeHeadlessViewer.h @@ -59,7 +59,7 @@ public slots: // getters for LOD and PPS float getVoxelSizeScale() const { return _voxelSizeScale; } - int getBoundaryLevelAdjust() const override { return _boundaryLevelAdjust; } + int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } int getMaxPacketsPerSecond() const { return _maxPacketsPerSecond; } unsigned getOctreeElementsCount() const { return _tree->getOctreeElementsCount(); } @@ -68,9 +68,10 @@ private: ViewFrustum _viewFrustum; JurisdictionListener* _jurisdictionListener = nullptr; OctreeQuery _octreeQuery; - float _voxelSizeScale; - int _boundaryLevelAdjust; - int _maxPacketsPerSecond; + + float _voxelSizeScale { DEFAULT_OCTREE_SIZE_SCALE }; + int _boundaryLevelAdjust { 0 }; + int _maxPacketsPerSecond { DEFAULT_MAX_OCTREE_PPS }; }; #endif // hifi_OctreeHeadlessViewer_h diff --git a/libraries/octree/src/OctreeRenderer.h b/libraries/octree/src/OctreeRenderer.h index b5126ab6e6..198de7ceed 100644 --- a/libraries/octree/src/OctreeRenderer.h +++ b/libraries/octree/src/OctreeRenderer.h @@ -39,8 +39,6 @@ public: virtual PacketType getMyQueryMessageType() const = 0; virtual PacketType getExpectedPacketType() const = 0; virtual void renderElement(OctreeElementPointer element, RenderArgs* args) { } - virtual float getSizeScale() const { return DEFAULT_OCTREE_SIZE_SCALE; } - virtual int getBoundaryLevelAdjust() const { return 0; } virtual void setTree(OctreePointer newTree); diff --git a/libraries/octree/src/ViewFrustum.cpp b/libraries/octree/src/ViewFrustum.cpp index 126eea4f27..5674a4e882 100644 --- a/libraries/octree/src/ViewFrustum.cpp +++ b/libraries/octree/src/ViewFrustum.cpp @@ -758,9 +758,9 @@ float ViewFrustum::calculateRenderAccuracy(const AABox& bounds, float octreeSize const float maxScale = (float)TREE_SCALE; float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / OCTREE_TO_MESH_RATIO; - static bool shouldRenderTableNeedsBuilding = true; + static std::once_flag once; static QMap shouldRenderTable; - if (shouldRenderTableNeedsBuilding) { + std::call_once(once, [&] { float SMALLEST_SCALE_IN_TABLE = 0.001f; // 1mm is plenty small float scale = maxScale; float factor = 1.0f; @@ -770,9 +770,7 @@ float ViewFrustum::calculateRenderAccuracy(const AABox& bounds, float octreeSize factor /= 2.0f; shouldRenderTable[scale] = factor; } - - shouldRenderTableNeedsBuilding = false; - } + }); float closestScale = maxScale; float visibleDistanceAtClosestScale = visibleDistanceAtMaxScale; diff --git a/libraries/render-utils/src/AbstractViewStateInterface.h b/libraries/render-utils/src/AbstractViewStateInterface.h index 39da33ee8f..1a4cfde16f 100644 --- a/libraries/render-utils/src/AbstractViewStateInterface.h +++ b/libraries/render-utils/src/AbstractViewStateInterface.h @@ -41,8 +41,6 @@ public: virtual QThread* getMainThread() = 0; - virtual float getSizeScale() const = 0; - virtual int getBoundaryLevelAdjust() const = 0; virtual PickRay computePickRay(float x, float y) const = 0; virtual glm::vec3 getAvatarPosition() const = 0; From b8747709efe1dc209d51ce335c2bbe99e2384aa4 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 18 Jan 2016 12:11:23 -0800 Subject: [PATCH 210/215] CR feedback, dead code cleanup --- libraries/entities/src/EntityTreeElement.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index db44a5499b..b7e4d11d7b 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -321,7 +321,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData if (renderAccuracy <= 0.0f) { includeThisEntity = false; // too small, don't include it - #if 1 //def WANT_LOD_DEBUGGING + #ifdef WANT_LOD_DEBUGGING qDebug() << "skipping entity - TOO SMALL - \n" << "......id:" << entity->getID() << "\n" << "....name:" << entity->getName() << "\n" @@ -337,7 +337,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData } if (includeThisEntity) { - #if 1 //def WANT_LOD_DEBUGGING + #ifdef WANT_LOD_DEBUGGING qDebug() << "including entity - \n" << "......id:" << entity->getID() << "\n" << "....name:" << entity->getName() << "\n" From 9428da61cf3ba555879a877439d14b4f8c3d1092 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 18 Jan 2016 14:31:55 -0800 Subject: [PATCH 211/215] fix property name typo --- examples/html/entityProperties.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 7ee86ac4b4..6ee08286ba 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -262,7 +262,7 @@ var elDensity = document.getElementById("property-density"); var elIgnoreForCollisions = document.getElementById("property-ignore-for-collisions"); - var elDynamic = document.getElementById("property-dyanmic" ); + var elDynamic = document.getElementById("property-dynamic" ); var elCollisionSoundURL = document.getElementById("property-collision-sound-url"); var elLifetime = document.getElementById("property-lifetime"); var elScriptURL = document.getElementById("property-script-url"); From ec2f8db83a70ff7b6023b92fc656a504933de0f1 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 18 Jan 2016 17:37:28 -0800 Subject: [PATCH 212/215] Avatar: Fix for one frame lag in hold action AvatarActionHold now uses the most recent un-cached palm positions/orientations instead of the cached version from the previous frame. --- interface/src/avatar/Avatar.cpp | 42 ++++++++++++++++++++--- interface/src/avatar/Avatar.h | 15 +++++--- interface/src/avatar/AvatarActionHold.cpp | 8 ++--- 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 7cde674e52..f423bef9b6 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -1160,25 +1160,59 @@ void Avatar::rebuildCollisionShape() { } // thread-safe -glm::vec3 Avatar::getLeftPalmPosition() { +glm::vec3 Avatar::getLeftPalmPosition() const { return _leftPalmPositionCache.get(); } // thread-safe -glm::quat Avatar::getLeftPalmRotation() { +glm::quat Avatar::getLeftPalmRotation() const { return _leftPalmRotationCache.get(); } // thread-safe -glm::vec3 Avatar::getRightPalmPosition() { +glm::vec3 Avatar::getRightPalmPosition() const { return _rightPalmPositionCache.get(); } // thread-safe -glm::quat Avatar::getRightPalmRotation() { +glm::quat Avatar::getRightPalmRotation() const { return _rightPalmRotationCache.get(); } +glm::vec3 Avatar::getUncachedLeftPalmPosition() const { + assert(QThread::currentThread() == thread()); // main thread access only + glm::quat leftPalmRotation; + getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftPalmRotation); + glm::vec3 leftPalmPosition; + getSkeletonModel().getLeftHandPosition(leftPalmPosition); + leftPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(leftPalmRotation); + return leftPalmPosition; +} + +glm::quat Avatar::getUncachedLeftPalmRotation() const { + assert(QThread::currentThread() == thread()); // main thread access only + glm::quat leftPalmRotation; + getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftPalmRotation); + return leftPalmRotation; +} + +glm::vec3 Avatar::getUncachedRightPalmPosition() const { + assert(QThread::currentThread() == thread()); // main thread access only + glm::quat rightPalmRotation; + getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightPalmRotation); + glm::vec3 rightPalmPosition; + getSkeletonModel().getRightHandPosition(rightPalmPosition); + rightPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(rightPalmRotation); + return rightPalmPosition; +} + +glm::quat Avatar::getUncachedRightPalmRotation() const { + assert(QThread::currentThread() == thread()); // main thread access only + glm::quat rightPalmRotation; + getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightPalmRotation); + return rightPalmRotation; +} + void Avatar::setPosition(const glm::vec3& position) { AvatarData::setPosition(position); updateAttitude(); diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index ddd1c612f1..e40db11800 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -167,13 +167,20 @@ public: using SpatiallyNestable::setOrientation; virtual void setOrientation(const glm::quat& orientation) override; + // NOT thread safe, must be called on main thread. + glm::vec3 getUncachedLeftPalmPosition() const; + glm::quat getUncachedLeftPalmRotation() const; + glm::vec3 getUncachedRightPalmPosition() const; + glm::quat getUncachedRightPalmRotation() const; + public slots: // FIXME - these should be migrated to use Pose data instead - glm::vec3 getLeftPalmPosition(); - glm::quat getLeftPalmRotation(); - glm::vec3 getRightPalmPosition(); - glm::quat getRightPalmRotation(); + // thread safe, will return last valid palm from cache + glm::vec3 getLeftPalmPosition() const; + glm::quat getLeftPalmRotation() const; + glm::vec3 getRightPalmPosition() const; + glm::quat getRightPalmRotation() const; protected: friend class AvatarManager; diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 12c792e631..71bd1b1f82 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -60,11 +60,11 @@ void AvatarActionHold::prepareForPhysicsSimulation() { glm::vec3 palmPosition; glm::quat palmRotation; if (_hand == "right") { - palmPosition = holdingAvatar->getRightPalmPosition(); - palmRotation = holdingAvatar->getRightPalmRotation(); + palmPosition = holdingAvatar->getUncachedRightPalmPosition(); + palmRotation = holdingAvatar->getUncachedRightPalmRotation(); } else { - palmPosition = holdingAvatar->getLeftPalmPosition(); - palmRotation = holdingAvatar->getLeftPalmRotation(); + palmPosition = holdingAvatar->getUncachedLeftPalmPosition(); + palmRotation = holdingAvatar->getUncachedLeftPalmRotation(); } glm::vec3 avatarRigidBodyPosition; From 7fb145e8196ecf3616c2e0c5f4e879ebe6284727 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 18 Jan 2016 13:29:23 -0800 Subject: [PATCH 213/215] namechange ignoreForCollisions --> collisionless --- examples/acScripts/rain.js | 2 +- examples/breakdanceCore.js | 4 ++-- .../data_visualization/earthquakes_live.js | 2 +- examples/debugging/grabInspector.js | 2 +- examples/drylake/createAvatarDetector.js | 2 +- examples/drylake/ratCreator.js | 4 ++-- examples/entityScripts/createRecorder.js | 4 ++-- .../entityScripts/recordingEntityScript.js | 8 +++---- .../games/color_busters/colorBusterWand.js | 2 +- .../color_busters/createColorBusterCubes.js | 2 +- examples/example/games/planky.js | 4 ++-- examples/flowArts/arcBall/arcBall.js | 2 +- examples/grab.js | 8 +++---- examples/harmonicOscillator.js | 2 +- examples/html/entityProperties.html | 10 ++++---- examples/leaves.js | 2 +- examples/libraries/entityPropertyDialogBox.js | 4 ++-- examples/light_modifier/lightModifier.js | 12 +++++----- examples/particle_explorer/main.js | 2 +- examples/pointer.js | 2 +- examples/toybox/basketball/createRack.js | 4 ++-- examples/toybox/bow/bow.js | 10 ++++---- examples/toybox/bubblewand/wand.js | 2 +- .../toybox/ping_pong_gun/createTargets.js | 2 +- .../targetPractice/targetPracticeGame.js | 2 +- libraries/entities/src/EntityItem.cpp | 18 +++++++-------- libraries/entities/src/EntityItem.h | 10 ++++---- .../entities/src/EntityItemProperties.cpp | 23 +++++++++++-------- libraries/entities/src/EntityItemProperties.h | 4 ++-- .../src/EntityItemPropertiesDefaults.h | 4 ++-- libraries/entities/src/EntityPropertyFlags.h | 2 +- libraries/entities/src/EntityTree.cpp | 8 +++---- libraries/physics/src/EntityMotionState.cpp | 2 +- 33 files changed, 87 insertions(+), 84 deletions(-) diff --git a/examples/acScripts/rain.js b/examples/acScripts/rain.js index fc02b7163f..25d8795191 100644 --- a/examples/acScripts/rain.js +++ b/examples/acScripts/rain.js @@ -76,7 +76,7 @@ var RainSquall = function (properties) { velocity: { x: 0, y: -dropFallSpeed, z: 0 }, damping: 0, angularDamping: 0, - ignoreForCollisions: true + collisionless: true }; } diff --git a/examples/breakdanceCore.js b/examples/breakdanceCore.js index 0220962ec8..70dacd67ab 100644 --- a/examples/breakdanceCore.js +++ b/examples/breakdanceCore.js @@ -409,7 +409,7 @@ function createPuppet(model, location) { registrationPoint: { x: 0.5, y: 0, z: 0.5 }, animation: ANIMATION_SETTINGS, position: location, - ignoreForCollisions: true, + collisionless: true, dimensions: DIMENSIONS, lifetime: TEMPORARY_LIFETIME }); @@ -595,4 +595,4 @@ breakdanceEnd= function() { Overlays.deleteOverlay(rightFrontOverlay); Entities.deleteEntity(puppetEntityID); -} \ No newline at end of file +} diff --git a/examples/data_visualization/earthquakes_live.js b/examples/data_visualization/earthquakes_live.js index ad0c9ec6a6..eba2717f3e 100644 --- a/examples/data_visualization/earthquakes_live.js +++ b/examples/data_visualization/earthquakes_live.js @@ -122,7 +122,7 @@ function createQuakeMarker(earthquake) { parentID:earth, dimensions: QUAKE_MARKER_DIMENSIONS, position: getQuakePosition(earthquake), - ignoreForCollisions:true, + collisionless:true, lifetime: 6000, color: getQuakeMarkerColor(earthquake) } diff --git a/examples/debugging/grabInspector.js b/examples/debugging/grabInspector.js index 11367d8832..6b6dfc5d69 100644 --- a/examples/debugging/grabInspector.js +++ b/examples/debugging/grabInspector.js @@ -108,7 +108,7 @@ Script.setInterval(function() { var grabData = userData["grabKey"] // {"grabbableKey":{"invertSolidWhileHeld":true}, - // "grabKey":{"activated":true,"avatarId":"{6ea8b092-10e0-4058-888b-6facc40d0fe9}","refCount":1,"gravity":{"x":0,"y":0,"z":0},"ignoreForCollisions":0,"dynamic":1} + // "grabKey":{"activated":true,"avatarId":"{6ea8b092-10e0-4058-888b-6facc40d0fe9}","refCount":1,"gravity":{"x":0,"y":0,"z":0},"collisionless":0,"dynamic":1} // } if (typeof grabData != 'undefined') { diff --git a/examples/drylake/createAvatarDetector.js b/examples/drylake/createAvatarDetector.js index c858512ba0..6cd8e829c9 100644 --- a/examples/drylake/createAvatarDetector.js +++ b/examples/drylake/createAvatarDetector.js @@ -25,7 +25,7 @@ function createAvatarDetector() { z: 1 }, dynamic: false, - ignoreForCollisions: true, + collisionless: true, visible: false, color: { red: 255, diff --git a/examples/drylake/ratCreator.js b/examples/drylake/ratCreator.js index 60a026084e..60ccf1a1a3 100644 --- a/examples/drylake/ratCreator.js +++ b/examples/drylake/ratCreator.js @@ -91,7 +91,7 @@ var modelRatProperties = { angularDamping: 0.99, friction: 0.75, dynamic: true, - ignoreForCollisions: false, + collisionless: false, gravity: { x: 0, y: -9.8, @@ -195,7 +195,7 @@ function addAvoiderBlock(position) { }, position: position, dynamic: false, - ignoreForCollisions: true, + collisionless: true, visible: false }; diff --git a/examples/entityScripts/createRecorder.js b/examples/entityScripts/createRecorder.js index 946d4e1071..f62b28a132 100644 --- a/examples/entityScripts/createRecorder.js +++ b/examples/entityScripts/createRecorder.js @@ -19,5 +19,5 @@ var recordAreaEntity = Entities.addEntity({ }, visible: true, script: PARAMS_SCRIPT_URL, - ignoreForCollision: true, -}); \ No newline at end of file + collisionless: true, +}); diff --git a/examples/entityScripts/recordingEntityScript.js b/examples/entityScripts/recordingEntityScript.js index dedfbf809e..3d1b6f46df 100644 --- a/examples/entityScripts/recordingEntityScript.js +++ b/examples/entityScripts/recordingEntityScript.js @@ -54,10 +54,10 @@ preload: function (entityID) { print("RECORDING ENTITY PRELOAD"); this.entityID = entityID; - + var entityProperties = Entities.getEntityProperties(_this.entityID); - if (!entityProperties.ignoreForCollisions) { - Entities.editEntity(_this.entityID, { ignoreForCollisions: true }); + if (!entityProperties.collisionless) { + Entities.editEntity(_this.entityID, { collisionless: true }); } Messages.messageReceived.connect(receivingMessage); @@ -117,4 +117,4 @@ } return new recordingEntity(); -}); \ No newline at end of file +}); diff --git a/examples/example/games/color_busters/colorBusterWand.js b/examples/example/games/color_busters/colorBusterWand.js index 825883d3fd..818fe28331 100644 --- a/examples/example/games/color_busters/colorBusterWand.js +++ b/examples/example/games/color_busters/colorBusterWand.js @@ -220,7 +220,7 @@ dimensions: COLOR_INDICATOR_DIMENSIONS, position: this.currentProperties.position, dynamic: false, - ignoreForCollisions: true + collisionless: true } this.colorIndicator = Entities.addEntity(properties); diff --git a/examples/example/games/color_busters/createColorBusterCubes.js b/examples/example/games/color_busters/createColorBusterCubes.js index bcec021676..98c011147d 100644 --- a/examples/example/games/color_busters/createColorBusterCubes.js +++ b/examples/example/games/color_busters/createColorBusterCubes.js @@ -82,7 +82,7 @@ function createColorBusterCube(row, column, vertical) { type: 'Box', dimensions: CUBE_DIMENSIONS, dynamic: false, - ignoreForCollisions: false, + collisionless: false, color: startingColor[1], position: position, userData: JSON.stringify({ diff --git a/examples/example/games/planky.js b/examples/example/games/planky.js index 5f16097bb1..22388eba47 100644 --- a/examples/example/games/planky.js +++ b/examples/example/games/planky.js @@ -254,7 +254,7 @@ PlankyStack = function() { density: _this.options.density, velocity: {x: 0, y: 0, z: 0}, angularVelocity: Quat.fromPitchYawRollDegrees(0, 0, 0), - ignoreForCollisions: true + collisionless: true }; _this.planks.forEach(function(plank, index, object) { if (plank.layer === layer && plank.row === row) { @@ -289,7 +289,7 @@ PlankyStack = function() { } if (!editMode) { _this.planks.forEach(function(plank, index, object) { - Entities.editEntity(plank.entity, {ignoreForCollisions: false, dynamic: true}); + Entities.editEntity(plank.entity, {collisionless: false, dynamic: true}); }); } }; diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index 1c8d7cf3c8..f62a5bf7bc 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -44,7 +44,7 @@ ArcBall = function(spawnPosition) { green: 10, blue: 150 }, - ignoreForCollisions: true, + collisionless: true, damping: 0.8, dynamic: true, userData: JSON.stringify({ diff --git a/examples/grab.js b/examples/grab.js index 64a8ea16e2..8c799ca62f 100644 --- a/examples/grab.js +++ b/examples/grab.js @@ -506,14 +506,14 @@ Grabber.prototype.activateEntity = function(entityID, grabbedProperties) { data["activated"] = true; data["avatarId"] = MyAvatar.sessionUUID; data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1; - // zero gravity and set ignoreForCollisions to true, but in a way that lets us put them back, after all grabs are done + // zero gravity and set collisionless to true, but in a way that lets us put them back, after all grabs are done if (data["refCount"] == 1) { data["gravity"] = grabbedProperties.gravity; - data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions; + data["collisionless"] = grabbedProperties.collisionless; data["dynamic"] = grabbedProperties.dynamic; var whileHeldProperties = {gravity: {x:0, y:0, z:0}}; if (invertSolidWhileHeld) { - whileHeldProperties["ignoreForCollisions"] = ! grabbedProperties.ignoreForCollisions; + whileHeldProperties["collisionless"] = ! grabbedProperties.collisionless; } Entities.editEntity(entityID, whileHeldProperties); } @@ -527,7 +527,7 @@ Grabber.prototype.deactivateEntity = function(entityID) { if (data["refCount"] < 1) { Entities.editEntity(entityID, { gravity: data["gravity"], - ignoreForCollisions: data["ignoreForCollisions"], + collisionless: data["collisionless"], dynamic: data["dynamic"] }); data = null; diff --git a/examples/harmonicOscillator.js b/examples/harmonicOscillator.js index 953820922b..cb5d27c03c 100644 --- a/examples/harmonicOscillator.js +++ b/examples/harmonicOscillator.js @@ -26,7 +26,7 @@ ball = Entities.addEntity( dimensions: { x: 0.1, y: 0.1, z: 0.1 }, color: { red: 255, green: 0, blue: 255 }, dynamic: false, - ignoreForCollisions: true + collisionless: true }); disc = Entities.addEntity( diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 6ee08286ba..9ced830e0c 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -261,7 +261,7 @@ var elAccelerationZ = document.getElementById("property-lacc-z"); var elDensity = document.getElementById("property-density"); - var elIgnoreForCollisions = document.getElementById("property-ignore-for-collisions"); + var elCollisionless = document.getElementById("property-collisionless"); var elDynamic = document.getElementById("property-dynamic" ); var elCollisionSoundURL = document.getElementById("property-collision-sound-url"); var elLifetime = document.getElementById("property-lifetime"); @@ -491,7 +491,7 @@ elAccelerationZ.value = properties.acceleration.z.toFixed(2); elDensity.value = properties.density.toFixed(2); - elIgnoreForCollisions.checked = properties.ignoreForCollisions; + elCollisionless.checked = properties.collisionless; elDynamic.checked = properties.dynamic; elCollisionSoundURL.value = properties.collisionSoundURL; elLifetime.value = properties.lifetime; @@ -718,7 +718,7 @@ elAccelerationZ.addEventListener('change', accelerationChangeFunction); elDensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('density')); - elIgnoreForCollisions.addEventListener('change', createEmitCheckedPropertyUpdateFunction('ignoreForCollisions')); + elCollisionless.addEventListener('change', createEmitCheckedPropertyUpdateFunction('collisionless')); elDynamic.addEventListener('change', createEmitCheckedPropertyUpdateFunction('dynamic')); elCollisionSoundURL.addEventListener('change', createEmitTextPropertyUpdateFunction('collisionSoundURL')); @@ -1235,9 +1235,9 @@
- Ignore For Collisions + Collisionless - +
diff --git a/examples/leaves.js b/examples/leaves.js index 40398822c2..4d8db4c70a 100755 --- a/examples/leaves.js +++ b/examples/leaves.js @@ -117,7 +117,7 @@ var leafSquall = function (properties) { }, damping: 0, angularDamping: 0, - ignoreForCollisions: true + collisionless: true }; } diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js index 2b720392b0..b04d797b77 100644 --- a/examples/libraries/entityPropertyDialogBox.js +++ b/examples/libraries/entityPropertyDialogBox.js @@ -199,7 +199,7 @@ EntityPropertyDialogBox = (function () { index++; array.push({ label: "Density:", value: properties.density.toFixed(decimals) }); index++; - array.push({ label: "Ignore for Collisions:", type: "checkbox", value: properties.ignoreForCollisions }); + array.push({ label: "Collisionless:", type: "checkbox", value: properties.collisionless }); index++; array.push({ label: "Dynamic:", type: "checkbox", value: properties.dynamic }); index++; @@ -412,7 +412,7 @@ EntityPropertyDialogBox = (function () { index++; // skip header properties.density = array[index++].value; - properties.ignoreForCollisions = array[index++].value; + properties.collisionless = array[index++].value; properties.dynamic = array[index++].value; properties.lifetime = array[index++].value; diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 84ef3430fc..0c691e2b2e 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -228,7 +228,7 @@ entitySlider.prototype = { name: 'Hifi-Slider-Axis::' + this.sliderType, color: this.color, dynamic: false, - ignoreForCollisions: true, + collisionless: true, dimensions: { x: 3, y: 3, @@ -251,7 +251,7 @@ entitySlider.prototype = { name: 'Hifi-End-Of-Axis', type: 'Box', dynamic: false, - ignoreForCollisions: true, + collisionless: true, dimensions: { x: 0.01, y: 0.01, @@ -364,7 +364,7 @@ entitySlider.prototype = { color: this.color, position: sliderPosition, script: SLIDER_SCRIPT_URL, - ignoreForCollisions: true, + collisionless: true, userData: JSON.stringify({ lightModifierKey: { lightID: this.lightID, @@ -559,7 +559,7 @@ function createPanelEntity(position) { }, visible: false, dynamic: false, - ignoreForCollisions: true + collisionless: true } var panel = Entities.addEntity(panelProperties); @@ -583,7 +583,7 @@ function createVisiblePanel() { }, visible: true, dynamic: false, - ignoreForCollisions: true, + collisionless: true, position: moveDown, rotation: avatarRot, script: VISIBLE_PANEL_SCRIPT_URL @@ -640,7 +640,7 @@ function createCloseButton(axisStart) { rotation: Quat.multiply(avatarRot, Quat.fromPitchYawRollDegrees(90, 0, 45)), //rotation: Quat.fromPitchYawRollDegrees(0, 0, 90), dynamic: false, - ignoreForCollisions: true, + collisionless: true, script: CLOSE_BUTTON_SCRIPT_URL, userData: JSON.stringify({ grabbableKey: { diff --git a/examples/particle_explorer/main.js b/examples/particle_explorer/main.js index 3f15efb836..4c82312e44 100644 --- a/examples/particle_explorer/main.js +++ b/examples/particle_explorer/main.js @@ -65,7 +65,7 @@ var keysToIgnore = [ 'registrationPoint', 'angularVelocity', 'angularDamping', - 'ignoreForCollisions', + 'collisionless', 'dynamic', 'href', 'actionData', diff --git a/examples/pointer.js b/examples/pointer.js index 99c2bcb23b..7d24bfab6b 100644 --- a/examples/pointer.js +++ b/examples/pointer.js @@ -102,7 +102,7 @@ function createOrUpdateLine(event) { sphereEntityID = Entities.addEntity({ type: "Sphere", position: intersection.intersection, - ignoreForCollisions: 1, + collisionless: 1, dimensions: { x: 0.6, y: 0.6, z: 0.6 }, color: { red: 0, green: 255, blue: 0 }, lifetime: 15 // if someone crashes while pointing, don't leave the line there forever. diff --git a/examples/toybox/basketball/createRack.js b/examples/toybox/basketball/createRack.js index 995f5487f9..4295170045 100644 --- a/examples/toybox/basketball/createRack.js +++ b/examples/toybox/basketball/createRack.js @@ -48,7 +48,7 @@ var rack = Entities.addEntity({ z: 1.73 }, dynamic: true, - ignoreForCollisions: false, + collisionless: false, collisionSoundURL: collisionSoundURL, compoundShapeURL: rackCollisionHullURL, userData: JSON.stringify({ @@ -90,7 +90,7 @@ function createBalls() { z: 0 }, dynamic: true, - ignoreForCollisions: false, + collisionless: false, modelURL: basketballURL, userData: JSON.stringify({ grabbableKey: { diff --git a/examples/toybox/bow/bow.js b/examples/toybox/bow/bow.js index 5c27b61e9e..660666b8b7 100644 --- a/examples/toybox/bow/bow.js +++ b/examples/toybox/bow/bow.js @@ -235,7 +235,7 @@ dimensions: ARROW_DIMENSIONS, position: this.bowProperties.position, dynamic: false, - ignoreForCollisions: true, + collisionless: true, collisionSoundURL: ARROW_HIT_SOUND_URL, damping: 0.01, userData: JSON.stringify({ @@ -287,7 +287,7 @@ position: Vec3.sum(this.bowProperties.position, TOP_NOTCH_OFFSET), dimensions: LINE_DIMENSIONS, dynamic: false, - ignoreForCollisions: true, + collisionless: true, userData: JSON.stringify({ grabbableKey: { grabbable: false @@ -305,7 +305,7 @@ position: Vec3.sum(this.bowProperties.position, BOTTOM_NOTCH_OFFSET), dimensions: LINE_DIMENSIONS, dynamic: false, - ignoreForCollisions: true, + collisionless: true, userData: JSON.stringify({ grabbableKey: { grabbable: false @@ -390,7 +390,7 @@ dimensions: LINE_DIMENSIONS, visible: true, dynamic: false, - ignoreForCollisions: true, + collisionless: true, userData: JSON.stringify({ grabbableKey: { grabbable: false @@ -539,7 +539,7 @@ //make the arrow physical, give it gravity, a lifetime, and set our velocity var arrowProperties = { dynamic: true, - ignoreForCollisions: false, + collisionless: false, collisionMask: "static,dynamic,otherAvatar", // workaround: not with kinematic --> no collision with bow velocity: releaseVelocity, gravity: ARROW_GRAVITY, diff --git a/examples/toybox/bubblewand/wand.js b/examples/toybox/bubblewand/wand.js index 02dcdb2cb9..fe1d917e69 100644 --- a/examples/toybox/bubblewand/wand.js +++ b/examples/toybox/bubblewand/wand.js @@ -162,7 +162,7 @@ position: this.getWandTipPosition(properties), dimensions: BUBBLE_INITIAL_DIMENSIONS, dynamic: false, - ignoreForCollisions: true, + collisionless: true, damping: BUBBLE_LINEAR_DAMPING, shapeType: "sphere" }); diff --git a/examples/toybox/ping_pong_gun/createTargets.js b/examples/toybox/ping_pong_gun/createTargets.js index baeca9c065..fcd187a687 100644 --- a/examples/toybox/ping_pong_gun/createTargets.js +++ b/examples/toybox/ping_pong_gun/createTargets.js @@ -56,7 +56,7 @@ var targetIntervalClearer = Entities.addEntity({ rotation: rotation, visible: false, dynamic: false, - ignoreForCollisions: true, + collisionless: true, }); var targets = []; diff --git a/examples/winterSmashUp/targetPractice/targetPracticeGame.js b/examples/winterSmashUp/targetPractice/targetPracticeGame.js index 72c10ddb01..5e2612ded6 100644 --- a/examples/winterSmashUp/targetPractice/targetPracticeGame.js +++ b/examples/winterSmashUp/targetPractice/targetPracticeGame.js @@ -153,7 +153,7 @@ var onTargetHit = function(targetEntity, projectileEntity, collision) { }); // Attach arrow to target for the nice effect Entities.editEntity(projectileEntity, { - ignoreForCollisions: true, + collisionless: true, parentID: targetEntity }); Entities.editEntity(targetEntity, { diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 93826d0fbf..b6fb3cb2cf 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -63,7 +63,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _angularVelocity(ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY), _angularDamping(ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING), _visible(ENTITY_ITEM_DEFAULT_VISIBLE), - _ignoreForCollisions(ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS), + _collisionless(ENTITY_ITEM_DEFAULT_COLLISIONLESS), _collisionMask(ENTITY_COLLISION_MASK_DEFAULT), _dynamic(ENTITY_ITEM_DEFAULT_DYNAMIC), _locked(ENTITY_ITEM_DEFAULT_LOCKED), @@ -123,7 +123,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_REGISTRATION_POINT; requestedProperties += PROP_ANGULAR_DAMPING; requestedProperties += PROP_VISIBLE; - requestedProperties += PROP_IGNORE_FOR_COLLISIONS; + requestedProperties += PROP_COLLISIONLESS; requestedProperties += PROP_COLLISION_MASK; requestedProperties += PROP_DYNAMIC; requestedProperties += PROP_LOCKED; @@ -260,7 +260,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, getRegistrationPoint()); APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, getAngularDamping()); APPEND_ENTITY_PROPERTY(PROP_VISIBLE, getVisible()); - APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, getIgnoreForCollisions()); + APPEND_ENTITY_PROPERTY(PROP_COLLISIONLESS, getCollisionless()); APPEND_ENTITY_PROPERTY(PROP_COLLISION_MASK, getCollisionMask()); APPEND_ENTITY_PROPERTY(PROP_DYNAMIC, getDynamic()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, getLocked()); @@ -680,7 +680,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible); - READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, updateIgnoreForCollisions); + READ_ENTITY_PROPERTY(PROP_COLLISIONLESS, bool, updateCollisionless); READ_ENTITY_PROPERTY(PROP_COLLISION_MASK, uint8_t, updateCollisionMask); READ_ENTITY_PROPERTY(PROP_DYNAMIC, bool, updateDynamic); READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked); @@ -1044,7 +1044,7 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper COPY_ENTITY_PROPERTY_TO_PROPERTIES(glowLevel, getGlowLevel); COPY_ENTITY_PROPERTY_TO_PROPERTIES(localRenderAlpha, getLocalRenderAlpha); COPY_ENTITY_PROPERTY_TO_PROPERTIES(visible, getVisible); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(ignoreForCollisions, getIgnoreForCollisions); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionless, getCollisionless); COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionMask, getCollisionMask); COPY_ENTITY_PROPERTY_TO_PROPERTIES(dynamic, getDynamic); COPY_ENTITY_PROPERTY_TO_PROPERTIES(locked, getLocked); @@ -1100,7 +1100,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularDamping, updateAngularDamping); SET_ENTITY_PROPERTY_FROM_PROPERTIES(restitution, updateRestitution); SET_ENTITY_PROPERTY_FROM_PROPERTIES(friction, updateFriction); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, updateIgnoreForCollisions); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionless, updateCollisionless); SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionMask, updateCollisionMask); SET_ENTITY_PROPERTY_FROM_PROPERTIES(dynamic, updateDynamic); SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, updateCreated); @@ -1444,9 +1444,9 @@ void EntityItem::updateAngularDamping(float value) { } } -void EntityItem::updateIgnoreForCollisions(bool value) { - if (_ignoreForCollisions != value) { - _ignoreForCollisions = value; +void EntityItem::updateCollisionless(bool value) { + if (_collisionless != value) { + _collisionless = value; _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; } } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index f00ad7691a..2ad4c25a54 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -271,11 +271,11 @@ public: bool isVisible() const { return _visible; } bool isInvisible() const { return !_visible; } - bool getIgnoreForCollisions() const { return _ignoreForCollisions; } - void setIgnoreForCollisions(bool value) { _ignoreForCollisions = value; } + bool getCollisionless() const { return _collisionless; } + void setCollisionless(bool value) { _collisionless = value; } uint8_t getCollisionMask() const { return _collisionMask; } - uint8_t getFinalCollisionMask() const { return _ignoreForCollisions ? 0 : _collisionMask; } + uint8_t getFinalCollisionMask() const { return _collisionless ? 0 : _collisionMask; } void setCollisionMask(uint8_t value) { _collisionMask = value; } bool getDynamic() const { return _dynamic; } @@ -331,7 +331,7 @@ public: void updateGravity(const glm::vec3& value); void updateAngularVelocity(const glm::vec3& value); void updateAngularDamping(float value); - void updateIgnoreForCollisions(bool value); + void updateCollisionless(bool value); void updateCollisionMask(uint8_t value); void updateDynamic(bool value); void updateLifetime(float value); @@ -445,7 +445,7 @@ protected: glm::vec3 _angularVelocity; float _angularDamping; bool _visible; - bool _ignoreForCollisions; + bool _collisionless; uint8_t _collisionMask { ENTITY_COLLISION_MASK_DEFAULT }; bool _dynamic; bool _locked; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index cc53b35c3b..8dc318c5c2 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -255,7 +255,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_REGISTRATION_POINT, registrationPoint); CHECK_PROPERTY_CHANGE(PROP_ANGULAR_VELOCITY, angularVelocity); CHECK_PROPERTY_CHANGE(PROP_ANGULAR_DAMPING, angularDamping); - CHECK_PROPERTY_CHANGE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions); + CHECK_PROPERTY_CHANGE(PROP_COLLISIONLESS, collisionless); CHECK_PROPERTY_CHANGE(PROP_COLLISION_MASK, collisionMask); CHECK_PROPERTY_CHANGE(PROP_DYNAMIC, dynamic); CHECK_PROPERTY_CHANGE(PROP_IS_SPOTLIGHT, isSpotlight); @@ -370,7 +370,8 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_VELOCITY, angularVelocity); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_DAMPING, angularDamping); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE, visible); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISIONLESS, collisionless); + COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_COLLISIONLESS, collisionless, ignoreForCollisions, getCollisionless()); // legacy support COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_COLLISION_MASK, collisionMask, getCollisionMaskAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DYNAMIC, dynamic); COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_DYNAMIC, dynamic, collisionsWillMove, getDynamic()); // legacy support @@ -593,7 +594,8 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(compoundShapeURL, QString, setCompoundShapeURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(glowLevel, float, setGlowLevel); COPY_PROPERTY_FROM_QSCRIPTVALUE(localRenderAlpha, float, setLocalRenderAlpha); - COPY_PROPERTY_FROM_QSCRIPTVALUE(ignoreForCollisions, bool, setIgnoreForCollisions); + COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionless, bool, setCollisionless); + COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(ignoreForCollisions, bool, setCollisionless, getCollisionless); // legacy support COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(collisionMask, CollisionMask); COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(collisionsWillMove, bool, setDynamic, getDynamic); // legacy support COPY_PROPERTY_FROM_QSCRIPTVALUE(dynamic, bool, setDynamic); @@ -757,7 +759,8 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_REGISTRATION_POINT, RegistrationPoint, registrationPoint, glm::vec3); ADD_PROPERTY_TO_MAP(PROP_ANGULAR_VELOCITY, AngularVelocity, angularVelocity, glm::vec3); ADD_PROPERTY_TO_MAP(PROP_ANGULAR_DAMPING, AngularDamping, angularDamping, float); - ADD_PROPERTY_TO_MAP(PROP_IGNORE_FOR_COLLISIONS, IgnoreForCollisions, ignoreForCollisions, bool); + ADD_PROPERTY_TO_MAP(PROP_COLLISIONLESS, Collisionless, collisionless, bool); + ADD_PROPERTY_TO_MAP(PROP_DYNAMIC, unused, ignoreForCollisions, unused); // legacy support ADD_PROPERTY_TO_MAP(PROP_COLLISION_MASK, CollisionMask, collisionMask, uint8_t); ADD_PROPERTY_TO_MAP(PROP_DYNAMIC, unused, collisionsWillMove, unused); // legacy support ADD_PROPERTY_TO_MAP(PROP_DYNAMIC, unused, dynamic, unused); @@ -1005,7 +1008,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, properties.getAngularVelocity()); APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, properties.getAngularDamping()); APPEND_ENTITY_PROPERTY(PROP_VISIBLE, properties.getVisible()); - APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, properties.getIgnoreForCollisions()); + APPEND_ENTITY_PROPERTY(PROP_COLLISIONLESS, properties.getCollisionless()); APPEND_ENTITY_PROPERTY(PROP_COLLISION_MASK, properties.getCollisionMask()); APPEND_ENTITY_PROPERTY(PROP_DYNAMIC, properties.getDynamic()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, properties.getLocked()); @@ -1298,7 +1301,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_VELOCITY, glm::vec3, setAngularVelocity); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_DAMPING, float, setAngularDamping); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE, bool, setVisible); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IGNORE_FOR_COLLISIONS, bool, setIgnoreForCollisions); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISIONLESS, bool, setCollisionless); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_MASK, uint8_t, setCollisionMask); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DYNAMIC, bool, setDynamic); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked); @@ -1480,7 +1483,7 @@ void EntityItemProperties::markAllChanged() { _glowLevelChanged = true; _localRenderAlphaChanged = true; _isSpotlightChanged = true; - _ignoreForCollisionsChanged = true; + _collisionlessChanged = true; _collisionMaskChanged = true; _dynamicChanged = true; @@ -1600,7 +1603,7 @@ bool EntityItemProperties::hasTerseUpdateChanges() const { bool EntityItemProperties::hasMiscPhysicsChanges() const { return _gravityChanged || _dimensionsChanged || _densityChanged || _frictionChanged || _restitutionChanged || _dampingChanged || _angularDampingChanged || _registrationPointChanged || - _compoundShapeURLChanged || _dynamicChanged || _ignoreForCollisionsChanged || _collisionMaskChanged; + _compoundShapeURLChanged || _dynamicChanged || _collisionlessChanged || _collisionMaskChanged; } void EntityItemProperties::clearSimulationOwner() { @@ -1713,8 +1716,8 @@ QList EntityItemProperties::listChangedProperties() { if (angularDampingChanged()) { out += "angularDamping"; } - if (ignoreForCollisionsChanged()) { - out += "ignoreForCollisions"; + if (collisionlessChanged()) { + out += "collisionless"; } if (collisionMaskChanged()) { out += "collisionMask"; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index f9072e2e89..0f0bab5fdd 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -127,7 +127,7 @@ public: DEFINE_PROPERTY_REF(PROP_REGISTRATION_POINT, RegistrationPoint, registrationPoint, glm::vec3, ENTITY_ITEM_DEFAULT_REGISTRATION_POINT); DEFINE_PROPERTY_REF(PROP_ANGULAR_VELOCITY, AngularVelocity, angularVelocity, glm::vec3, ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY); DEFINE_PROPERTY(PROP_ANGULAR_DAMPING, AngularDamping, angularDamping, float, ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING); - DEFINE_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, IgnoreForCollisions, ignoreForCollisions, bool, ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS); + DEFINE_PROPERTY(PROP_COLLISIONLESS, Collisionless, collisionless, bool, ENTITY_ITEM_DEFAULT_COLLISIONLESS); DEFINE_PROPERTY(PROP_COLLISION_MASK, CollisionMask, collisionMask, uint8_t, ENTITY_COLLISION_MASK_DEFAULT); DEFINE_PROPERTY(PROP_DYNAMIC, Dynamic, dynamic, bool, ENTITY_ITEM_DEFAULT_DYNAMIC); DEFINE_PROPERTY(PROP_IS_SPOTLIGHT, IsSpotlight, isSpotlight, bool, false); @@ -355,7 +355,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, RegistrationPoint, registrationPoint, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AngularVelocity, angularVelocity, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AngularDamping, angularDamping, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, IgnoreForCollisions, ignoreForCollisions, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, Collisionless, collisionless, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Dynamic, dynamic, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, IsSpotlight, isSpotlight, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Intensity, intensity, ""); diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index 39b144c014..5375b1bc3a 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -18,7 +18,7 @@ #include -// There is a minor performance gain when comparing/copying an existing glm::vec3 rather than +// There is a minor performance gain when comparing/copying an existing glm::vec3 rather than // creating a new one on the stack so we declare the ZERO_VEC3 constant as an optimization. const glm::vec3 ENTITY_ITEM_ZERO_VEC3 = glm::vec3(0.0f); const glm::vec3 ENTITY_ITEM_ONE_VEC3 = glm::vec3(1.0f); @@ -68,7 +68,7 @@ const float ENTITY_ITEM_MIN_FRICTION = 0.0f; const float ENTITY_ITEM_MAX_FRICTION = 0.99f; const float ENTITY_ITEM_DEFAULT_FRICTION = 0.5f; -const bool ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS = false; +const bool ENTITY_ITEM_DEFAULT_COLLISIONLESS = false; const bool ENTITY_ITEM_DEFAULT_DYNAMIC = false; const bool ENTITY_ITEM_DEFAULT_BILLBOARDED = false; diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index dec2a607da..ac0a65aa27 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -45,7 +45,7 @@ enum EntityPropertyList { PROP_REGISTRATION_POINT, PROP_ANGULAR_VELOCITY, PROP_ANGULAR_DAMPING, - PROP_IGNORE_FOR_COLLISIONS, + PROP_COLLISIONLESS, PROP_DYNAMIC, // property used by Light entity diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 1017f54f67..eb23034506 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -722,15 +722,15 @@ void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList= 0) { - bool value = properties.getIgnoreForCollisions(); + bool value = properties.getCollisionless(); QString changeHint = "0"; if (value) { changeHint = "1"; } - changedProperties[index] = QString("ignoreForCollisions:") + changeHint; + changedProperties[index] = QString("collisionless:") + changeHint; } } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index d0de720fa3..4e5f942265 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -624,7 +624,7 @@ QString EntityMotionState::getName() const { void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const { group = BULLET_COLLISION_GROUP_STATIC; if (_entity) { - if (_entity->getIgnoreForCollisions()) { + if (_entity->getCollisionless()) { group = BULLET_COLLISION_GROUP_COLLISIONLESS; } switch (computePhysicsMotionType()){ From 48374ef5bc1ca9d80b10127c4c235ea9cdfaff5d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 18 Jan 2016 13:40:24 -0800 Subject: [PATCH 214/215] more ignoreForCollisions to collisionless --- .../games/exterminatorGame/pistolScriptSpawnerSpawner.js | 6 +++--- unpublishedScripts/basketballsResetter.js | 2 +- unpublishedScripts/hiddenEntityReset.js | 6 +++--- unpublishedScripts/masterReset.js | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/example/games/exterminatorGame/pistolScriptSpawnerSpawner.js b/examples/example/games/exterminatorGame/pistolScriptSpawnerSpawner.js index 099deea652..1967e5dc23 100644 --- a/examples/example/games/exterminatorGame/pistolScriptSpawnerSpawner.js +++ b/examples/example/games/exterminatorGame/pistolScriptSpawnerSpawner.js @@ -7,7 +7,7 @@ var pistolSpawnerEntity = Entities.addEntity({ dimensions: {x: 0.38, y: 1.9, z: 3.02}, script: scriptURL, visible: false, - ignoreForCollisions: true + collisionless: true }); var pistol = Entities.addEntity({ @@ -17,7 +17,7 @@ var pistol = Entities.addEntity({ dimensions: {x: 0.38, y: 1.9, z: 3.02}, script: scriptURL, color: {red: 200, green: 0, blue: 20}, - ignoreForCollisions: true + collisionless: true }); @@ -28,4 +28,4 @@ function cleanup() { } // Script.update.connect(update); -Script.scriptEnding.connect(cleanup); \ No newline at end of file +Script.scriptEnding.connect(cleanup); diff --git a/unpublishedScripts/basketballsResetter.js b/unpublishedScripts/basketballsResetter.js index e4938a2b79..76cc4e8331 100644 --- a/unpublishedScripts/basketballsResetter.js +++ b/unpublishedScripts/basketballsResetter.js @@ -83,7 +83,7 @@ var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; }, dynamic: true, collisionSoundURL: basketballCollisionSoundURL, - ignoreForCollisions: false, + collisionless: false, modelURL: basketballURL, userData: JSON.stringify({ resetMe: { diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index ec50264811..78aab78d61 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -494,7 +494,7 @@ z: 1.73 }, dynamic: true, - ignoreForCollisions: false, + collisionless: false, compoundShapeURL: rackCollisionHullURL, userData: JSON.stringify({ resetMe: { @@ -543,7 +543,7 @@ }, dynamic: true, collisionSoundURL: 'http://hifi-public.s3.amazonaws.com/sounds/basketball/basketball.wav', - ignoreForCollisions: false, + collisionless: false, modelURL: basketballURL, userData: JSON.stringify({ originalPositionKey: { @@ -1523,4 +1523,4 @@ }; // entity scripts always need to return a newly constructed object of our type return new ResetSwitch(); -}); \ No newline at end of file +}); diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 72074da5f1..b3a9d49ea3 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -478,7 +478,7 @@ MasterReset = function() { z: 1.73 }, dynamic: true, - ignoreForCollisions: false, + collisionless: false, compoundShapeURL: rackCollisionHullURL, userData: JSON.stringify({ resetMe: { @@ -528,7 +528,7 @@ MasterReset = function() { }, dynamic: true, collisionSoundURL: 'http://hifi-public.s3.amazonaws.com/sounds/basketball/basketball.wav', - ignoreForCollisions: false, + collisionless: false, modelURL: basketballURL, userData: JSON.stringify({ originalPositionKey: { @@ -1504,4 +1504,4 @@ MasterReset = function() { Script.scriptEnding.connect(cleanup); } -}; \ No newline at end of file +}; From b750128c945b4646995cfa36f3b8e6227e3b4241 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 19 Jan 2016 11:03:00 -0800 Subject: [PATCH 215/215] Avatar: centeralized palm rotation/position to world space calculation. --- interface/src/avatar/Avatar.cpp | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index f423bef9b6..798ddd951c 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -1224,22 +1224,9 @@ void Avatar::setOrientation(const glm::quat& orientation) { } void Avatar::updatePalms() { - - // get palm rotations - glm::quat leftPalmRotation, rightPalmRotation; - getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftPalmRotation); - getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightPalmRotation); - - // get palm positions - glm::vec3 leftPalmPosition, rightPalmPosition; - getSkeletonModel().getLeftHandPosition(leftPalmPosition); - getSkeletonModel().getRightHandPosition(rightPalmPosition); - leftPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(leftPalmRotation); - rightPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(rightPalmRotation); - // update thread-safe caches - _leftPalmRotationCache.set(leftPalmRotation); - _rightPalmRotationCache.set(rightPalmRotation); - _leftPalmPositionCache.set(leftPalmPosition); - _rightPalmPositionCache.set(rightPalmPosition); + _leftPalmRotationCache.set(getUncachedLeftPalmRotation()); + _rightPalmRotationCache.set(getUncachedRightPalmRotation()); + _leftPalmPositionCache.set(getUncachedLeftPalmPosition()); + _rightPalmPositionCache.set(getUncachedRightPalmPosition()); }