FIrst version of the design for the Engine, the Tasks and a DrawTask. Introduced the ItemFilter

This commit is contained in:
Sam Gateau 2015-05-22 12:58:18 -07:00
parent bec8d1838c
commit e7e3eb2b7c
8 changed files with 202 additions and 77 deletions

View file

@ -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" {

View file

@ -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()
}
}
};

View file

@ -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);
};

View file

@ -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);
}
}

View file

@ -17,16 +17,54 @@
namespace render {
class SceneContext {
public:
ScenePointer _scene;
SceneContext() {}
};
typedef std::shared_ptr<SceneContext> 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<Task> TaskPointer;
typedef std::vector<TaskPointer> 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<Engine> EnginePointer;
}

View file

@ -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();
}
}

View file

@ -17,6 +17,7 @@
#include <vector>
#include <set>
#include <map>
#include <RenderArgs.h>
#include <AABox.h>
#include <atomic>
#include <mutex>
@ -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<NUM_FLAGS> 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<ItemID> ItemIDs;
typedef std::set<ItemID> ItemIDSet;
// A map of ItemIDSets allowing to create bucket lists of items which are filtering correctly
class ItemBucketMap : public std::map<ItemKey, ItemIDSet> {
class ItemBucketMap : public std::map<ItemFilter, ItemIDSet, ItemFilter::Less> {
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<unsigned int> _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);

View file

@ -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