diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 05fc2fec0a..9ffbb86ae0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -142,6 +142,7 @@ #include "ui/Stats.h" #include "ui/AddressBarDialog.h" + // ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU #if defined(Q_OS_WIN) extern "C" { diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp new file mode 100755 index 0000000000..c97b3e43c2 --- /dev/null +++ b/libraries/render/src/render/DrawTask.cpp @@ -0,0 +1,41 @@ +// +// DrawTask.cpp +// render/src/render +// +// Created by Sam Gateau on 5/21/15. +// Copyright 20154 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 "DrawTask.h" + +using namespace render; + + +DrawSceneTask::~DrawSceneTask() { +} + +void DrawSceneTask::run(const SceneContextPointer& sceneContext) { + // sanity checks + assert(sceneContext); + if (!sceneContext->_scene) { + return; + } + auto scene = sceneContext->_scene; + + auto itemBucketMap = scene->getMasterBucketMap(); + + // render opaques + auto& opaqueShapeItems = itemBucketMap.find(ItemKey::Builder().withTypeShape().build()); + if (opaqueShapeItems != itemBucketMap.end()) { + + for (auto id : opaqueShapeItems.second) { + auto item = scene->getItem(id); + item.render() + } + } + +}; + diff --git a/libraries/render/src/render/Task.h b/libraries/render/src/render/DrawTask.h similarity index 74% rename from libraries/render/src/render/Task.h rename to libraries/render/src/render/DrawTask.h index 5223463295..14b05be777 100755 --- a/libraries/render/src/render/Task.h +++ b/libraries/render/src/render/DrawTask.h @@ -1,5 +1,5 @@ // -// Task.h +// DrawTask.h // render/src/render // // Created by Sam Gateau on 5/21/15. @@ -12,30 +12,18 @@ #ifndef hifi_render_Task_h #define hifi_render_Task_h -#include "Scene.h" +#include "Engine.h" namespace render { - -class Task { -public: - Task() {} - ~Task() {} - - void run() {} - -protected: -}; - class DrawSceneTask : public Task { public: DrawSceneTask() : Task() {} ~DrawSceneTask(); - void setup(RenderArgs* args); - void run(); + virtual void run(const SceneContextPointer& sceneContext); }; diff --git a/libraries/render/src/render/Engine.cpp b/libraries/render/src/render/Engine.cpp index ff147f23cf..8648f2c583 100644 --- a/libraries/render/src/render/Engine.cpp +++ b/libraries/render/src/render/Engine.cpp @@ -13,5 +13,26 @@ using namespace render; +Engine::Engine() : + _sceneContext(new SceneContext()) +{ +} + +void Engine::registerScene(const ScenePointer& scene) { + _sceneContext->_scene = scene; +} + +void Engine::addTask(const TaskPointer& task) { + if (task) { + _tasks.push_back(task); + } +} + +void Engine::run() { + for (auto task : _tasks) { + task->run(_sceneContext); + } +} + diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index b3e1d34db4..755d302ecf 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -17,16 +17,54 @@ namespace render { +class SceneContext { +public: + ScenePointer _scene; + + SceneContext() {} +}; +typedef std::shared_ptr SceneContextPointer; +// THe base class for a task that runs on the SceneContext +class Task { +public: + Task() {} + ~Task() {} + + virtual void run(const SceneContextPointer& sceneContext) {} + +protected: +}; + + +typedef std::shared_ptr TaskPointer; +typedef std::vector Tasks; + +// The root of the takss, the Engine, should not be known from the Tasks, +// The SceneContext is what navigates from the engine down to the Tasks class Engine { public: - Engine() {} + Engine(); ~Engine() {} + // Register the scene should be [art of the init phase before running the engine + void registerScene(const ScenePointer& scene); + + void addTask(const TaskPointer& task); + const Tasks& getTasks() const { return _tasks; } + + + void run(); + protected: + Tasks _tasks; + + SceneContextPointer _sceneContext; }; +typedef std::shared_ptr EnginePointer; + } diff --git a/libraries/render/src/render/Scene.cpp b/libraries/render/src/render/Scene.cpp index d1c776e817..21d6dc1bc3 100644 --- a/libraries/render/src/render/Scene.cpp +++ b/libraries/render/src/render/Scene.cpp @@ -15,7 +15,7 @@ using namespace render; void ItemBucketMap::insert(const ItemID& id, const ItemKey& key) { // Insert the itemID in every bucket where it filters true for (auto& bucket : (*this)) { - if (key.filterTest(bucket.first)) { + if (bucket.first.test(key)) { bucket.second.insert(id); } } @@ -23,7 +23,7 @@ void ItemBucketMap::insert(const ItemID& id, const ItemKey& key) { void ItemBucketMap::erase(const ItemID& id, const ItemKey& key) { // Remove the itemID in every bucket where it filters true for (auto& bucket : (*this)) { - if (key.filterTest(bucket.first)) { + if (bucket.first.test(key)) { bucket.second.erase(id); } } @@ -34,16 +34,20 @@ void ItemBucketMap::reset(const ItemID& id, const ItemKey& oldKey, const ItemKey // Remove from the buckets where oldKey filters true AND newKey filters false // Insert into the buckets where newKey filters true for (auto& bucket : (*this)) { - if (oldKey.filterTest(bucket.first)) { - if (!newKey.filterTest(bucket.first)) { + if (bucket.first.test(oldKey)) { + if (!bucket.first.test(newKey)) { bucket.second.erase(id); } - } else if (newKey.filterTest(bucket.first)) { + } else if (bucket.first.test(newKey)) { bucket.second.insert(id); } } } +void ItemBucketMap::allocateStandardOpaqueTranparentBuckets() { + (*this)[ItemFilter::Builder::opaqueShape()]; + (*this)[ItemFilter::Builder::transparentShape()]; +} void Scene::PendingChanges::resetItem(ItemID id, PayloadPointer& payload) { _resetItems.push_back(id); @@ -69,6 +73,7 @@ void Scene::PendingChanges::merge(PendingChanges& changes) { Scene::Scene() : _IDAllocator(0) { + _masterBucketMap.allocateStandardOpaqueTranparentBuckets(); } ItemID Scene::allocateID() { @@ -122,14 +127,14 @@ void Scene::resetItems(const ItemIDs& ids, Payloads& payloads) { auto oldKey = item.getKey(); item.resetPayload(*resetPayload); - _buckets.reset((*resetID), oldKey, item.getKey()); + _masterBucketMap.reset((*resetID), oldKey, item.getKey()); } } void Scene::removeItems(const ItemIDs& ids) { for (auto removedID :ids) { - _buckets.erase(removedID, _items[removedID].getKey()); + _masterBucketMap.erase(removedID, _items[removedID].getKey()); _items[removedID].kill(); } } diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index 929db3f52c..921bad3bbf 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -32,21 +33,20 @@ public: enum FlagBit { TYPE_SHAPE = 0, // Item is a Shape TYPE_LIGHT, // Item is a Light - TRANSLUCENT, // Translucent and not opaque + TRANSPARENT, // Transparent and not opaque VIEW_SPACE, // Transformed in view space, and not in world space DYNAMIC, // Dynamic and bound will change unlike static item DEFORMED, // Deformed within bound, not solid INVISIBLE, // Visible or not? could be just here to cast shadow SHADOW_CASTER, // Item cast shadows PICKABLE, // Item can be picked/selected - - INVERT_FLAG, // If true then the meaning of the other flags is inverted NUM_FLAGS, // Not a valid flag + ALL_FLAGS_MASK = 0xFFFF, }; typedef std::bitset Flags; - // THe key is the Flags + // The key is the Flags Flags _flags; ItemKey() : _flags(0) {} @@ -57,22 +57,25 @@ public: public: Builder() {} - const ItemKey& build() const { return ItemKey(_flags); } + const ItemKey build() const { return ItemKey(_flags); } Builder& withTypeShape() { _flags.set(TYPE_SHAPE); return (*this); } Builder& withTypeLight() { _flags.set(TYPE_LIGHT); return (*this); } - Builder& withTranslucent() { _flags.set(TRANSLUCENT); return (*this); } + Builder& withTransparent() { _flags.set(TRANSPARENT); return (*this); } Builder& withViewSpace() { _flags.set(VIEW_SPACE); return (*this); } Builder& withDynamic() { _flags.set(DYNAMIC); return (*this); } Builder& withDeformed() { _flags.set(DEFORMED); return (*this); } Builder& withInvisible() { _flags.set(INVISIBLE); return (*this); } Builder& withShadowCaster() { _flags.set(SHADOW_CASTER); return (*this); } Builder& withPickable() { _flags.set(PICKABLE); return (*this); } + + // Convenient standard keys that we will keep on using all over the place + static const ItemKey opaqueShape() { return Builder().withTypeShape().build(); } + static const ItemKey transparentShape() { return Builder().withTypeShape().withTransparent().build(); } }; - - bool isOpaque() const { return !_flags[TRANSLUCENT]; } - bool isTranslucent() const { return _flags[TRANSLUCENT]; } + bool isOpaque() const { return !_flags[TRANSPARENT]; } + bool isTransparent() const { return _flags[TRANSPARENT]; } bool isWorldSpace() const { return !_flags[VIEW_SPACE]; } bool isViewSpace() const { return _flags[VIEW_SPACE]; } @@ -89,20 +92,66 @@ public: bool isShadowCaster() const { return _flags[SHADOW_CASTER]; } bool isPickable() const { return _flags[PICKABLE]; } +}; + - - // Item Key operator testing if a key pass a filter test - // the filter can have several flags on and the test is true if - // (key AND filter) == filter - // IF the filter has the INVERT_FLAGS On then we need to use the - // !key value instead of key - bool filterTest(const ItemKey& filter) const { - if (filter._flags[INVERT_FLAG]) { - return (filter._flags & ~_flags) == filter._flags; - } else { - return (filter._flags & _flags) == filter._flags; +class ItemFilter { +public: + ItemKey::Flags _value{ 0 }; + ItemKey::Flags _mask{ 0 }; + + + ItemFilter(const ItemKey::Flags& value = ItemKey::Flags(0), const ItemKey::Flags& mask = ItemKey::Flags(0)) : _value(value), _mask(mask) {} + + class Builder { + ItemKey::Flags _value; + ItemKey::Flags _mask; + public: + Builder() {} + + const ItemFilter build() const { return ItemFilter(_value, _mask); } + + Builder& withTypeShape() { _value.set(ItemKey::TYPE_SHAPE); _mask.set(ItemKey::TYPE_SHAPE); return (*this); } + Builder& withTypeLight() { _value.set(ItemKey::TYPE_LIGHT); _mask.set(ItemKey::TYPE_LIGHT); return (*this); } + + Builder& withOpaque() { _value.reset(ItemKey::TRANSPARENT); _mask.set(ItemKey::TRANSPARENT); return (*this); } + Builder& withTransparent() { _value.set(ItemKey::TRANSPARENT); _mask.set(ItemKey::TRANSPARENT); return (*this); } + + Builder& withWorldSpace() { _value.reset(ItemKey::VIEW_SPACE); _mask.set(ItemKey::VIEW_SPACE); return (*this); } + Builder& withViewSpace() { _value.set(ItemKey::VIEW_SPACE); _mask.set(ItemKey::VIEW_SPACE); return (*this); } + + Builder& withStatic() { _value.reset(ItemKey::DYNAMIC); _mask.set(ItemKey::DYNAMIC); return (*this); } + Builder& withDynamic() { _value.set(ItemKey::DYNAMIC); _mask.set(ItemKey::DYNAMIC); return (*this); } + + Builder& withRigid() { _value.reset(ItemKey::DEFORMED); _mask.set(ItemKey::DEFORMED); return (*this); } + Builder& withDeformed() { _value.set(ItemKey::DEFORMED); _mask.set(ItemKey::DEFORMED); return (*this); } + + Builder& withVisible() { _value.reset(ItemKey::INVISIBLE); _mask.set(ItemKey::INVISIBLE); return (*this); } + Builder& withInvisible() { _value.set(ItemKey::INVISIBLE); _mask.set(ItemKey::INVISIBLE); return (*this); } + + Builder& withNoShadowCaster() { _value.reset(ItemKey::SHADOW_CASTER); _mask.set(ItemKey::SHADOW_CASTER); return (*this); } + Builder& withShadowCaster() { _value.set(ItemKey::SHADOW_CASTER); _mask.set(ItemKey::SHADOW_CASTER); return (*this); } + + Builder& withPickable() { _value.set(ItemKey::PICKABLE); _mask.set(ItemKey::PICKABLE); return (*this); } + + // Convenient standard keys that we will keep on using all over the place + static const ItemFilter opaqueShape() { return Builder().withTypeShape().withOpaque().build(); } + static const ItemFilter transparentShape() { return Builder().withTypeShape().withTransparent().build(); } + }; + + // Item Filter operator testing if a key pass the filter + bool test(const ItemKey& key) const { return (key._flags & _mask) == (_value & _mask); } + + class Less { + public: + bool operator() (const ItemFilter& left, const ItemFilter& right) { + if (left._value.to_ulong() > right._value.to_ulong()) { + return left._mask.to_ulong() < right._mask.to_ulong(); + } else { + return true; + } } - } + }; }; class Item { @@ -221,7 +270,7 @@ typedef std::vector ItemIDs; typedef std::set ItemIDSet; // A map of ItemIDSets allowing to create bucket lists of items which are filtering correctly -class ItemBucketMap : public std::map { +class ItemBucketMap : public std::map { public: ItemBucketMap() {} @@ -230,6 +279,9 @@ public: void erase(const ItemID& id, const ItemKey& key); void reset(const ItemID& id, const ItemKey& oldKey, const ItemKey& newKey); + // standard builders allocating the main buckets + void allocateStandardOpaqueTranparentBuckets(); + }; class Engine; @@ -305,6 +357,16 @@ public: void registerObserver(ObserverPointer& observer); void unregisterObserver(ObserverPointer& observer); + + /// Access the main bucketmap of items + const ItemBucketMap& getMasterBucket() const { return _masterBucketMap; } + + /// Access a particular item form its ID + /// WARNING, There is No check on the validity of the ID, so this could return a bad Item + const Item& getItem(const ItemID& id) const { return _items[id]; } + + unsigned int getNumItems() const { return _items.size(); } + protected: // Thread safe elements that can be accessed from anywhere std::atomic _IDAllocator; @@ -315,7 +377,7 @@ protected: // database of items is protected for editing by a mutex std::mutex _itemsMutex; Item::Vector _items; - ItemBucketMap _buckets; + ItemBucketMap _masterBucketMap; void processPendingChangesQueue(); void resetItems(const ItemIDs& ids, Payloads& payloads); diff --git a/libraries/render/src/render/Task.cpp b/libraries/render/src/render/Task.cpp deleted file mode 100755 index 11163d583a..0000000000 --- a/libraries/render/src/render/Task.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// -// Task.cpp -// render/src/render -// -// Created by Sam Gateau on 5/21/15. -// Copyright 20154 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 "Task.h" - -using namespace render; - - -DrawSceneTask::~DrawSceneTask() { -} - -void DrawSceneTask::setup(RenderArgs* args) { -}; - -void DrawSceneTask::run() { -}; - - - - -} - -#endif // hifi_render_Task_h