mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 17:35:08 +02:00
FIrst version of the design for the Engine, the Tasks and a DrawTask. Introduced the ItemFilter
This commit is contained in:
parent
bec8d1838c
commit
e7e3eb2b7c
8 changed files with 202 additions and 77 deletions
|
@ -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" {
|
||||
|
|
41
libraries/render/src/render/DrawTask.cpp
Executable file
41
libraries/render/src/render/DrawTask.cpp
Executable 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()
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
Loading…
Reference in a new issue