mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 06:18:52 +02:00
Merge branch 'team-teaching' of github.com:highfidelity/hifi into scene-avatar
Conflicts: interface/src/Application.cpp
This commit is contained in:
commit
c13254a9c4
14 changed files with 168 additions and 57 deletions
|
@ -262,7 +262,6 @@ $(document).ready(function(){
|
||||||
$('#' + Settings.FORM_ID).on('click', '#' + Settings.CONNECT_ACCOUNT_BTN_ID, function(e){
|
$('#' + Settings.FORM_ID).on('click', '#' + Settings.CONNECT_ACCOUNT_BTN_ID, function(e){
|
||||||
$(this).blur();
|
$(this).blur();
|
||||||
prepareAccessTokenPrompt();
|
prepareAccessTokenPrompt();
|
||||||
e.preventDefault();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var panelsSource = $('#panels-template').html()
|
var panelsSource = $('#panels-template').html()
|
||||||
|
|
|
@ -3169,25 +3169,36 @@ const ViewFrustum* Application::getDisplayViewFrustum() const {
|
||||||
return &_displayViewFrustum;
|
return &_displayViewFrustum;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyFirstStuff {
|
// WorldBox Render Data & rendering functions
|
||||||
|
|
||||||
|
class WorldBoxRenderData {
|
||||||
public:
|
public:
|
||||||
typedef render::Payload<MyFirstStuff> Payload;
|
typedef render::Payload<WorldBoxRenderData> Payload;
|
||||||
typedef std::shared_ptr<render::Item::PayloadInterface> PayloadPointer;
|
|
||||||
typedef Payload::DataPointer Pointer;
|
typedef Payload::DataPointer Pointer;
|
||||||
|
|
||||||
|
static render::ItemID _item; // unique WorldBoxRenderData
|
||||||
};
|
};
|
||||||
|
|
||||||
// For Ubuntu, the compiler want's the Payload's functions to be specialized in the "render" namespace explicitely...
|
render::ItemID WorldBoxRenderData::_item = 0;
|
||||||
|
|
||||||
namespace render {
|
namespace render {
|
||||||
template <> const ItemKey payloadGetKey(const MyFirstStuff::Pointer& stuff) { return ItemKey::Builder::opaqueShape(); }
|
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape(); }
|
||||||
template <> const Item::Bound payloadGetBound(const MyFirstStuff::Pointer& stuff) { return Item::Bound(); }
|
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
|
||||||
template <> void payloadRender(const MyFirstStuff::Pointer& stuff, RenderArgs* args) {
|
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
|
||||||
if (args) {
|
if (args->_renderMode != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
|
||||||
args->_elementsTouched ++;
|
PerformanceTimer perfTimer("worldBox");
|
||||||
|
renderWorldBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// never the less
|
||||||
|
float originSphereRadius = 0.05f;
|
||||||
|
DependencyManager::get<GeometryCache>()->renderSphere(originSphereRadius, 15, 15, glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool selfAvatarOnly) {
|
void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool selfAvatarOnly) {
|
||||||
activeRenderingThread = QThread::currentThread();
|
activeRenderingThread = QThread::currentThread();
|
||||||
PROFILE_RANGE(__FUNCTION__);
|
PROFILE_RANGE(__FUNCTION__);
|
||||||
|
@ -3350,11 +3361,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
||||||
DependencyManager::get<DeferredLightingEffect>()->prepare();
|
DependencyManager::get<DeferredLightingEffect>()->prepare();
|
||||||
|
|
||||||
if (!selfAvatarOnly) {
|
if (!selfAvatarOnly) {
|
||||||
// draw a red sphere
|
|
||||||
float originSphereRadius = 0.05f;
|
|
||||||
DependencyManager::get<GeometryCache>()->renderSphere(originSphereRadius, 15, 15, glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));
|
|
||||||
|
|
||||||
|
|
||||||
// render JS/scriptable overlays
|
// render JS/scriptable overlays
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("3dOverlays");
|
PerformanceTimer perfTimer("3dOverlays");
|
||||||
|
@ -3398,23 +3405,29 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
||||||
DependencyManager::get<AmbientOcclusionEffect>()->render();
|
DependencyManager::get<AmbientOcclusionEffect>()->render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static render::ItemID myFirstRenderItem = 0;
|
|
||||||
|
|
||||||
if (myFirstRenderItem == 0) {
|
render::Scene::PendingChanges pendingChanges;
|
||||||
auto myVeryFirstStuff = MyFirstStuff::Pointer(new MyFirstStuff());
|
|
||||||
auto myVeryFirstPayload = new MyFirstStuff::Payload(myVeryFirstStuff);
|
|
||||||
auto myFirstPayload = MyFirstStuff::PayloadPointer(myVeryFirstPayload);
|
|
||||||
myFirstRenderItem = _main3DScene->allocateID();
|
|
||||||
|
|
||||||
render::Scene::PendingChanges pendingChanges;
|
// Make sure the WorldBox is in the scene
|
||||||
pendingChanges.resetItem(myFirstRenderItem, myFirstPayload);
|
if (WorldBoxRenderData::_item == 0) {
|
||||||
|
auto worldBoxRenderData = WorldBoxRenderData::Pointer(new WorldBoxRenderData());
|
||||||
|
auto worldBoxRenderPayload = render::PayloadPointer(new WorldBoxRenderData::Payload(worldBoxRenderData));
|
||||||
|
|
||||||
_main3DScene->enqueuePendingChanges(pendingChanges);
|
WorldBoxRenderData::_item = _main3DScene->allocateID();
|
||||||
|
|
||||||
|
pendingChanges.resetItem(WorldBoxRenderData::_item, worldBoxRenderPayload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_main3DScene->enqueuePendingChanges(pendingChanges);
|
||||||
|
|
||||||
_main3DScene->processPendingChangesQueue();
|
_main3DScene->processPendingChangesQueue();
|
||||||
|
|
||||||
|
// FOr now every frame pass the renderCOntext
|
||||||
|
render::RenderContext renderContext;
|
||||||
|
renderContext.args = renderArgs;
|
||||||
|
_renderEngine->setRenderContext(renderContext);
|
||||||
|
|
||||||
// Before the deferred pass, let's try to use the render engine
|
// Before the deferred pass, let's try to use the render engine
|
||||||
_renderEngine->run();
|
_renderEngine->run();
|
||||||
|
|
||||||
|
@ -3437,12 +3450,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
||||||
|
|
||||||
if (!selfAvatarOnly) {
|
if (!selfAvatarOnly) {
|
||||||
_nodeBoundsDisplay.draw();
|
_nodeBoundsDisplay.draw();
|
||||||
|
|
||||||
// Render the world box
|
|
||||||
if (theCamera.getMode() != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
|
|
||||||
PerformanceTimer perfTimer("worldBox");
|
|
||||||
renderWorldBox();
|
|
||||||
}
|
|
||||||
|
|
||||||
// render octree fades if they exist
|
// render octree fades if they exist
|
||||||
if (_octreeFades.size() > 0) {
|
if (_octreeFades.size() > 0) {
|
||||||
|
|
|
@ -114,7 +114,6 @@ void EntityTreeRenderer::init() {
|
||||||
connect(entityTree, &EntityTree::deletingEntity, this, &EntityTreeRenderer::deletingEntity);
|
connect(entityTree, &EntityTree::deletingEntity, this, &EntityTreeRenderer::deletingEntity);
|
||||||
connect(entityTree, &EntityTree::addingEntity, this, &EntityTreeRenderer::addingEntity);
|
connect(entityTree, &EntityTree::addingEntity, this, &EntityTreeRenderer::addingEntity);
|
||||||
connect(entityTree, &EntityTree::entityScriptChanging, this, &EntityTreeRenderer::entitySciptChanging);
|
connect(entityTree, &EntityTree::entityScriptChanging, this, &EntityTreeRenderer::entitySciptChanging);
|
||||||
connect(entityTree, &EntityTree::changingEntityID, this, &EntityTreeRenderer::changingEntityID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityTreeRenderer::shutdown() {
|
void EntityTreeRenderer::shutdown() {
|
||||||
|
@ -855,6 +854,7 @@ void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityS
|
||||||
|
|
||||||
connect(this, &EntityTreeRenderer::enterEntity, entityScriptingInterface, &EntityScriptingInterface::enterEntity);
|
connect(this, &EntityTreeRenderer::enterEntity, entityScriptingInterface, &EntityScriptingInterface::enterEntity);
|
||||||
connect(this, &EntityTreeRenderer::leaveEntity, entityScriptingInterface, &EntityScriptingInterface::leaveEntity);
|
connect(this, &EntityTreeRenderer::leaveEntity, entityScriptingInterface, &EntityScriptingInterface::leaveEntity);
|
||||||
|
connect(this, &EntityTreeRenderer::collisionWithEntity, entityScriptingInterface, &EntityScriptingInterface::collisionWithEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
QScriptValueList EntityTreeRenderer::createMouseEventArgs(const EntityItemID& entityID, QMouseEvent* event, unsigned int deviceID) {
|
QScriptValueList EntityTreeRenderer::createMouseEventArgs(const EntityItemID& entityID, QMouseEvent* event, unsigned int deviceID) {
|
||||||
|
@ -1083,14 +1083,6 @@ void EntityTreeRenderer::checkAndCallUnload(const EntityItemID& entityID) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EntityTreeRenderer::changingEntityID(const EntityItemID& oldEntityID, const EntityItemID& newEntityID) {
|
|
||||||
if (_entityScripts.contains(oldEntityID)) {
|
|
||||||
EntityScriptDetails details = _entityScripts[oldEntityID];
|
|
||||||
_entityScripts.remove(oldEntityID);
|
|
||||||
_entityScripts[newEntityID] = details;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision) {
|
void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision) {
|
||||||
EntityItemPointer entity = entityTree->findEntityByEntityItemID(id);
|
EntityItemPointer entity = entityTree->findEntityByEntityItemID(id);
|
||||||
if (!entity) {
|
if (!entity) {
|
||||||
|
@ -1169,6 +1161,7 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons
|
||||||
playEntityCollisionSound(myNodeID, entityTree, idB, collision);
|
playEntityCollisionSound(myNodeID, entityTree, idB, collision);
|
||||||
|
|
||||||
// And now the entity scripts
|
// And now the entity scripts
|
||||||
|
emit collisionWithEntity(idA, idB, collision);
|
||||||
QScriptValue entityScriptA = loadEntityScript(idA);
|
QScriptValue entityScriptA = loadEntityScript(idA);
|
||||||
if (entityScriptA.property("collisionWithEntity").isValid()) {
|
if (entityScriptA.property("collisionWithEntity").isValid()) {
|
||||||
QScriptValueList args;
|
QScriptValueList args;
|
||||||
|
@ -1178,6 +1171,7 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons
|
||||||
entityScriptA.property("collisionWithEntity").call(entityScriptA, args);
|
entityScriptA.property("collisionWithEntity").call(entityScriptA, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit collisionWithEntity(idB, idA, collision);
|
||||||
QScriptValue entityScriptB = loadEntityScript(idB);
|
QScriptValue entityScriptB = loadEntityScript(idB);
|
||||||
if (entityScriptB.property("collisionWithEntity").isValid()) {
|
if (entityScriptB.property("collisionWithEntity").isValid()) {
|
||||||
QScriptValueList args;
|
QScriptValueList args;
|
||||||
|
|
|
@ -105,11 +105,11 @@ signals:
|
||||||
|
|
||||||
void enterEntity(const EntityItemID& entityItemID);
|
void enterEntity(const EntityItemID& entityItemID);
|
||||||
void leaveEntity(const EntityItemID& entityItemID);
|
void leaveEntity(const EntityItemID& entityItemID);
|
||||||
|
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void addingEntity(const EntityItemID& entityID);
|
void addingEntity(const EntityItemID& entityID);
|
||||||
void deletingEntity(const EntityItemID& entityID);
|
void deletingEntity(const EntityItemID& entityID);
|
||||||
void changingEntityID(const EntityItemID& oldEntityID, const EntityItemID& newEntityID);
|
|
||||||
void entitySciptChanging(const EntityItemID& entityID);
|
void entitySciptChanging(const EntityItemID& entityID);
|
||||||
void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,7 @@ public slots:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
||||||
|
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
||||||
|
|
||||||
void canAdjustLocksChanged(bool canAdjustLocks);
|
void canAdjustLocksChanged(bool canAdjustLocks);
|
||||||
void canRezChanged(bool canRez);
|
void canRezChanged(bool canRez);
|
||||||
|
|
|
@ -171,7 +171,6 @@ signals:
|
||||||
void deletingEntity(const EntityItemID& entityID);
|
void deletingEntity(const EntityItemID& entityID);
|
||||||
void addingEntity(const EntityItemID& entityID);
|
void addingEntity(const EntityItemID& entityID);
|
||||||
void entityScriptChanging(const EntityItemID& entityItemID);
|
void entityScriptChanging(const EntityItemID& entityItemID);
|
||||||
void changingEntityID(const EntityItemID& oldEntityID, const EntityItemID& newEntityID);
|
|
||||||
void clearingEntities();
|
void clearingEntities();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -17,7 +17,7 @@ using namespace render;
|
||||||
DrawSceneTask::~DrawSceneTask() {
|
DrawSceneTask::~DrawSceneTask() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawSceneTask::run(const SceneContextPointer& sceneContext) {
|
void DrawSceneTask::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||||
// sanity checks
|
// sanity checks
|
||||||
assert(sceneContext);
|
assert(sceneContext);
|
||||||
if (!sceneContext->_scene) {
|
if (!sceneContext->_scene) {
|
||||||
|
@ -27,14 +27,14 @@ void DrawSceneTask::run(const SceneContextPointer& sceneContext) {
|
||||||
|
|
||||||
auto& itemBucketMap = scene->getMasterBucket();
|
auto& itemBucketMap = scene->getMasterBucket();
|
||||||
|
|
||||||
RenderArgs args;
|
RenderArgs* args = renderContext->args;
|
||||||
// render opaques
|
// render opaques
|
||||||
auto filter = ItemFilter::Builder::opaqueShape();
|
auto filter = ItemFilter::Builder::opaqueShape();
|
||||||
auto& opaqueShapeItems = itemBucketMap.at(filter);
|
auto& opaqueShapeItems = itemBucketMap.at(filter);
|
||||||
|
|
||||||
for (auto id : opaqueShapeItems) {
|
for (auto id : opaqueShapeItems) {
|
||||||
auto item = scene->getItem(id);
|
auto item = scene->getItem(id);
|
||||||
item.render(&args);
|
item.render(args);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ public:
|
||||||
DrawSceneTask() : Task() {}
|
DrawSceneTask() : Task() {}
|
||||||
~DrawSceneTask();
|
~DrawSceneTask();
|
||||||
|
|
||||||
virtual void run(const SceneContextPointer& sceneContext);
|
virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,8 @@ using namespace render;
|
||||||
|
|
||||||
|
|
||||||
Engine::Engine() :
|
Engine::Engine() :
|
||||||
_sceneContext(new SceneContext())
|
_sceneContext(new SceneContext()),
|
||||||
|
_renderContext(new RenderContext())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +24,10 @@ void Engine::registerScene(const ScenePointer& scene) {
|
||||||
_sceneContext->_scene = scene;
|
_sceneContext->_scene = scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Engine::setRenderContext(const RenderContext& renderContext) {
|
||||||
|
(*_renderContext) = renderContext;
|
||||||
|
}
|
||||||
|
|
||||||
void Engine::addTask(const TaskPointer& task) {
|
void Engine::addTask(const TaskPointer& task) {
|
||||||
if (task) {
|
if (task) {
|
||||||
_tasks.push_back(task);
|
_tasks.push_back(task);
|
||||||
|
@ -31,7 +36,7 @@ void Engine::addTask(const TaskPointer& task) {
|
||||||
|
|
||||||
void Engine::run() {
|
void Engine::run() {
|
||||||
for (auto task : _tasks) {
|
for (auto task : _tasks) {
|
||||||
task->run(_sceneContext);
|
task->run(_sceneContext, _renderContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,18 +25,25 @@ public:
|
||||||
};
|
};
|
||||||
typedef std::shared_ptr<SceneContext> SceneContextPointer;
|
typedef std::shared_ptr<SceneContext> SceneContextPointer;
|
||||||
|
|
||||||
|
|
||||||
|
class RenderContext {
|
||||||
|
public:
|
||||||
|
RenderArgs* args;
|
||||||
|
|
||||||
|
RenderContext() {}
|
||||||
|
};
|
||||||
|
typedef std::shared_ptr<RenderContext> RenderContextPointer;
|
||||||
|
|
||||||
// THe base class for a task that runs on the SceneContext
|
// THe base class for a task that runs on the SceneContext
|
||||||
class Task {
|
class Task {
|
||||||
public:
|
public:
|
||||||
Task() {}
|
Task() {}
|
||||||
~Task() {}
|
~Task() {}
|
||||||
|
|
||||||
virtual void run(const SceneContextPointer& sceneContext) {}
|
virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef std::shared_ptr<Task> TaskPointer;
|
typedef std::shared_ptr<Task> TaskPointer;
|
||||||
typedef std::vector<TaskPointer> Tasks;
|
typedef std::vector<TaskPointer> Tasks;
|
||||||
|
|
||||||
|
@ -51,6 +58,9 @@ public:
|
||||||
// Register the scene should be [art of the init phase before running the engine
|
// Register the scene should be [art of the init phase before running the engine
|
||||||
void registerScene(const ScenePointer& scene);
|
void registerScene(const ScenePointer& scene);
|
||||||
|
|
||||||
|
// Push a RenderContext
|
||||||
|
void setRenderContext(const RenderContext& renderContext);
|
||||||
|
|
||||||
void addTask(const TaskPointer& task);
|
void addTask(const TaskPointer& task);
|
||||||
const Tasks& getTasks() const { return _tasks; }
|
const Tasks& getTasks() const { return _tasks; }
|
||||||
|
|
||||||
|
@ -65,6 +75,7 @@ protected:
|
||||||
Tasks _tasks;
|
Tasks _tasks;
|
||||||
|
|
||||||
SceneContextPointer _sceneContext;
|
SceneContextPointer _sceneContext;
|
||||||
|
RenderContextPointer _renderContext;
|
||||||
};
|
};
|
||||||
typedef std::shared_ptr<Engine> EnginePointer;
|
typedef std::shared_ptr<Engine> EnginePointer;
|
||||||
|
|
||||||
|
|
|
@ -89,9 +89,8 @@ void Scene::PendingChanges::merge(PendingChanges& changes) {
|
||||||
_movedItems.insert(_movedItems.end(), changes._movedItems.begin(), changes._movedItems.end());
|
_movedItems.insert(_movedItems.end(), changes._movedItems.begin(), changes._movedItems.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
Scene::Scene() :
|
Scene::Scene() {
|
||||||
_IDAllocator(0)
|
_items.push_back(Item()); // add the itemID #0 to nothing
|
||||||
{
|
|
||||||
_masterBucketMap.allocateStandardOpaqueTranparentBuckets();
|
_masterBucketMap.allocateStandardOpaqueTranparentBuckets();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -368,7 +368,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Thread safe elements that can be accessed from anywhere
|
// Thread safe elements that can be accessed from anywhere
|
||||||
std::atomic<unsigned int> _IDAllocator;
|
std::atomic<unsigned int> _IDAllocator{ 1 }; // first valid itemID will be One
|
||||||
std::mutex _changeQueueMutex;
|
std::mutex _changeQueueMutex;
|
||||||
PendingChangesQueue _changeQueue;
|
PendingChangesQueue _changeQueue;
|
||||||
|
|
||||||
|
|
|
@ -389,6 +389,94 @@ void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::Func
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args
|
||||||
|
void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& eventName, std::function<QScriptValueList()> argGenerator) {
|
||||||
|
if (!_registeredHandlers.contains(entityID)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const RegisteredEventHandlers& handlersOnEntity = _registeredHandlers[entityID];
|
||||||
|
if (!handlersOnEntity.contains(eventName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QScriptValueList handlersForEvent = handlersOnEntity[eventName];
|
||||||
|
if (!handlersForEvent.isEmpty()) {
|
||||||
|
QScriptValueList args = argGenerator();
|
||||||
|
for (int i = 0; i < handlersForEvent.count(); ++i) {
|
||||||
|
handlersForEvent[i].call(QScriptValue(), args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Unregister the handlers for this eventName and entityID.
|
||||||
|
void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) {
|
||||||
|
if (!_registeredHandlers.contains(entityID)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RegisteredEventHandlers& handlersOnEntity = _registeredHandlers[entityID];
|
||||||
|
QScriptValueList& handlersForEvent = handlersOnEntity[eventName];
|
||||||
|
// QScriptValue does not have operator==(), so we can't use QList::removeOne and friends. So iterate.
|
||||||
|
for (int i = 0; i < handlersForEvent.count(); ++i) {
|
||||||
|
if (handlersForEvent[i].equals(handler)) {
|
||||||
|
handlersForEvent.removeAt(i);
|
||||||
|
return; // Design choice: since comparison is relatively expensive, just remove the first matching handler.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Register the handler.
|
||||||
|
void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) {
|
||||||
|
if (_registeredHandlers.count() == 0) { // First time any per-entity handler has been added in this script...
|
||||||
|
// Connect up ALL the handlers to the global entities object's signals.
|
||||||
|
// (We could go signal by signal, or even handler by handler, but I don't think the efficiency is worth the complexity.)
|
||||||
|
auto entities = DependencyManager::get<EntityScriptingInterface>();
|
||||||
|
connect(entities.data(), &EntityScriptingInterface::deletingEntity, this,
|
||||||
|
[=](const EntityItemID& entityID) {
|
||||||
|
_registeredHandlers.remove(entityID);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Two common cases of event handler, differing only in argument signature.
|
||||||
|
auto makeSingleEntityHandler = [=](const QString& eventName) -> std::function<void(const EntityItemID&)> {
|
||||||
|
return [=](const EntityItemID& entityItemID) -> void {
|
||||||
|
generalHandler(entityItemID, eventName, [=]() -> QScriptValueList {
|
||||||
|
return QScriptValueList() << entityItemID.toScriptValue(this);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
auto makeMouseHandler = [=](const QString& eventName) -> std::function<void(const EntityItemID&, const MouseEvent&)> {
|
||||||
|
return [=](const EntityItemID& entityItemID, const MouseEvent& event) -> void {
|
||||||
|
generalHandler(entityItemID, eventName, [=]() -> QScriptValueList {
|
||||||
|
return QScriptValueList() << entityItemID.toScriptValue(this) << event.toScriptValue(this);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity"));
|
||||||
|
connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, makeSingleEntityHandler("leaveEntity"));
|
||||||
|
|
||||||
|
connect(entities.data(), &EntityScriptingInterface::mousePressOnEntity, this, makeMouseHandler("mousePressOnEntity"));
|
||||||
|
connect(entities.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, makeMouseHandler("mouseMoveOnEntity"));
|
||||||
|
connect(entities.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, makeMouseHandler("mouseReleaseOnEntity"));
|
||||||
|
|
||||||
|
connect(entities.data(), &EntityScriptingInterface::clickDownOnEntity, this, makeMouseHandler("clickDownOnEntity"));
|
||||||
|
connect(entities.data(), &EntityScriptingInterface::holdingClickOnEntity, this, makeMouseHandler("holdingClickOnEntity"));
|
||||||
|
connect(entities.data(), &EntityScriptingInterface::clickReleaseOnEntity, this, makeMouseHandler("clickReleaseOnEntity"));
|
||||||
|
|
||||||
|
connect(entities.data(), &EntityScriptingInterface::hoverEnterEntity, this, makeMouseHandler("hoverEnterEntity"));
|
||||||
|
connect(entities.data(), &EntityScriptingInterface::hoverOverEntity, this, makeMouseHandler("hoverOverEntity"));
|
||||||
|
connect(entities.data(), &EntityScriptingInterface::hoverLeaveEntity, this, makeMouseHandler("hoverLeaveEntity"));
|
||||||
|
|
||||||
|
connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this,
|
||||||
|
[=](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) {
|
||||||
|
generalHandler(idA, "collisionWithEntity", [=]() {
|
||||||
|
return QScriptValueList () << idA.toScriptValue(this) << idB.toScriptValue(this) << collisionToScriptValue(this, collision);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!_registeredHandlers.contains(entityID)) {
|
||||||
|
_registeredHandlers[entityID] = RegisteredEventHandlers();
|
||||||
|
}
|
||||||
|
QScriptValueList& handlersForEvent = _registeredHandlers[entityID][eventName];
|
||||||
|
handlersForEvent << handler; // Note that the same handler can be added many times. See removeEntityEventHandler().
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ScriptEngine::evaluate() {
|
void ScriptEngine::evaluate() {
|
||||||
if (_stoppingAllScripts) {
|
if (_stoppingAllScripts) {
|
||||||
return; // bail early
|
return; // bail early
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <AvatarData.h>
|
#include <AvatarData.h>
|
||||||
#include <AvatarHashMap.h>
|
#include <AvatarHashMap.h>
|
||||||
#include <LimitedNodeList.h>
|
#include <LimitedNodeList.h>
|
||||||
|
#include <EntityItemID.h>
|
||||||
|
|
||||||
#include "AbstractControllerScriptingInterface.h"
|
#include "AbstractControllerScriptingInterface.h"
|
||||||
#include "ArrayBufferClass.h"
|
#include "ArrayBufferClass.h"
|
||||||
|
@ -36,6 +37,8 @@ const QString NO_SCRIPT("");
|
||||||
|
|
||||||
const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0 / 60.0f) * 1000 * 1000) + 0.5);
|
const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0 / 60.0f) * 1000 * 1000) + 0.5);
|
||||||
|
|
||||||
|
typedef QHash<QString, QScriptValueList> RegisteredEventHandlers;
|
||||||
|
|
||||||
class ScriptEngine : public QScriptEngine, public ScriptUser {
|
class ScriptEngine : public QScriptEngine, public ScriptUser {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -98,6 +101,9 @@ public:
|
||||||
virtual void scriptContentsAvailable(const QUrl& url, const QString& scriptContents);
|
virtual void scriptContentsAvailable(const QUrl& url, const QString& scriptContents);
|
||||||
virtual void errorInLoadingScript(const QUrl& url);
|
virtual void errorInLoadingScript(const QUrl& url);
|
||||||
|
|
||||||
|
Q_INVOKABLE void addEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler);
|
||||||
|
Q_INVOKABLE void removeEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void loadURL(const QUrl& scriptURL);
|
void loadURL(const QUrl& scriptURL);
|
||||||
void stop();
|
void stop();
|
||||||
|
@ -164,6 +170,8 @@ private:
|
||||||
ArrayBufferClass* _arrayBufferClass;
|
ArrayBufferClass* _arrayBufferClass;
|
||||||
|
|
||||||
QHash<QUuid, quint16> _outgoingScriptAudioSequenceNumbers;
|
QHash<QUuid, quint16> _outgoingScriptAudioSequenceNumbers;
|
||||||
|
QHash<EntityItemID, RegisteredEventHandlers> _registeredHandlers;
|
||||||
|
void generalHandler(const EntityItemID& entityID, const QString& eventName, std::function<QScriptValueList()> argGenerator);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static QSet<ScriptEngine*> _allKnownScriptEngines;
|
static QSet<ScriptEngine*> _allKnownScriptEngines;
|
||||||
|
|
Loading…
Reference in a new issue