diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 1d92ed917f..7c8d8f0e01 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -17,6 +17,7 @@ #include "OctreeSendThread.h" #include "OctreeServer.h" #include "OctreeServerConsts.h" +#include "OctreeLogging.h" quint64 startSceneSleepTime = 0; quint64 endSceneSleepTime = 0; @@ -572,14 +573,12 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus OctreeServer::trackInsideTime((float)elapsedInsideUsecs); } - if (somethingToSend && _myServer->wantsVerboseDebug()) { - qDebug() << "Hit PPS Limit, packetsSentThisInterval =" << packetsSentThisInterval - << " maxPacketsPerInterval = " << maxPacketsPerInterval - << " clientMaxPacketsPerInterval = " << clientMaxPacketsPerInterval; + qCDebug(octree) << "Hit PPS Limit, packetsSentThisInterval =" << packetsSentThisInterval + << " maxPacketsPerInterval = " << maxPacketsPerInterval + << " clientMaxPacketsPerInterval = " << clientMaxPacketsPerInterval; } - // Here's where we can/should allow the server to send other data... // send the environment packet // TODO: should we turn this into a while loop to better handle sending multiple special packets diff --git a/examples/grab.js b/examples/grab.js index ee6c3c4de5..1637e1bcf2 100644 --- a/examples/grab.js +++ b/examples/grab.js @@ -506,6 +506,7 @@ Grabber.prototype.activateEntity = function(entityID, grabbedProperties) { if (data["refCount"] == 1) { data["gravity"] = grabbedProperties.gravity; data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions; + data["collisionsWillMove"] = grabbedProperties.collisionsWillMove; var whileHeldProperties = {gravity: {x:0, y:0, z:0}}; if (invertSolidWhileHeld) { whileHeldProperties["ignoreForCollisions"] = ! grabbedProperties.ignoreForCollisions; @@ -522,7 +523,8 @@ Grabber.prototype.deactivateEntity = function(entityID) { if (data["refCount"] < 1) { Entities.editEntity(entityID, { gravity: data["gravity"], - ignoreForCollisions: data["ignoreForCollisions"] + ignoreForCollisions: data["ignoreForCollisions"], + collisionsWillMove: data["collisionsWillMove"] }); data = null; } diff --git a/examples/grabInspector.js b/examples/grabInspector.js new file mode 100644 index 0000000000..8a027f819a --- /dev/null +++ b/examples/grabInspector.js @@ -0,0 +1,137 @@ +// +// grabInspector.js +// examples +// +// Created by Seth Alves on 2015-9-30. +// 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 +// + +Script.include("libraries/utils.js"); + +var INSPECT_RADIUS = 10; +var overlays = {}; + +var toType = function(obj) { + return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase() +} + +function grabDataToString(grabData) { + var result = ""; + + for (var argumentName in grabData) { + if (grabData.hasOwnProperty(argumentName)) { + if (argumentName == "type") { + continue; + } + var arg = grabData[argumentName]; + var argType = toType(arg); + var argString = arg; + if (argType == "object") { + if (Object.keys(arg).length == 3) { + argString = vec3toStr(arg, 1); + } + } else if (argType == "number") { + argString = arg.toFixed(2); + } + result += argumentName + ": " + // + toType(arg) + " -- " + + argString + "\n"; + } + } + + return result; +} + + + +function updateOverlay(entityID, grabText) { + var properties = Entities.getEntityProperties(entityID, ["position", "dimensions"]); + var position = Vec3.sum(properties.position, {x:0, y:properties.dimensions.y, z:0}); + if (entityID in overlays) { + var overlay = overlays[entityID]; + Overlays.editOverlay(overlay, { + text: grabText, + position: position + }); + } else { + var lines = grabText.split(/\r\n|\r|\n/); + + var maxLineLength = lines[0].length; + for (var i = 1; i < lines.length; i++) { + if (lines[i].length > maxLineLength) { + maxLineLength = lines[i].length; + } + } + + var textWidth = maxLineLength * 0.034; // XXX how to know this? + var textHeight = .5; + var numberOfLines = lines.length; + var textMargin = 0.05; + var lineHeight = (textHeight - (2 * textMargin)) / numberOfLines; + + overlays[entityID] = Overlays.addOverlay("text3d", { + position: position, + dimensions: { x: textWidth, y: textHeight }, + backgroundColor: { red: 0, green: 0, blue: 0}, + color: { red: 255, green: 255, blue: 255}, + topMargin: textMargin, + leftMargin: textMargin, + bottomMargin: textMargin, + rightMargin: textMargin, + text: grabText, + lineHeight: lineHeight, + alpha: 0.9, + backgroundAlpha: 0.9, + ignoreRayIntersection: true, + visible: true, + isFacingAvatar: true + }); + } +} + + +function cleanup() { + for (var entityID in overlays) { + Overlays.deleteOverlay(overlays[entityID]); + } +} + + +Script.setInterval(function() { + var nearbyEntities = Entities.findEntities(MyAvatar.position, INSPECT_RADIUS); + for (var entityIndex = 0; entityIndex < nearbyEntities.length; entityIndex++) { + var entityID = nearbyEntities[entityIndex]; + var userData = getEntityUserData(entityID); + 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} + // } + + if (typeof grabData != 'undefined') { + var grabText = grabDataToString(grabData); + updateOverlay(entityID, grabText); + } else { + if (entityID in overlays) { + Overlays.deleteOverlay(overlays[entityID]); + delete overlays[entityID]; + } + } + } + + // if an entity is too far away, remove its overlay + for (var entityID in overlays) { + var position = Entities.getEntityProperties(entityID, ["position"]).position; + if (Vec3.distance(position, MyAvatar.position) > INSPECT_RADIUS) { + Overlays.deleteOverlay(overlays[entityID]); + delete overlays[entityID]; + } + } + +}, 100); + + +Script.scriptEnding.connect(cleanup); diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index 3271741985..cca97b7184 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -62,10 +62,24 @@ var overlaysCounter = new CounterWidget(panel, "Overlays", ); -panel.newCheckbox("Display status", - function(value) { Scene.setEngineDisplayItemStatus(value); }, - function() { return Scene.doEngineDisplayItemStatus(); }, - function(value) { return (value); } +// see libraries/render/src/render/Engine.h +var showDisplayStatusFlag = 1; +var showNetworkStatusFlag = 2; + +panel.newCheckbox("Display status", + function(value) { Scene.setEngineDisplayItemStatus(value ? + Scene.doEngineDisplayItemStatus() | showDisplayStatusFlag : + Scene.doEngineDisplayItemStatus() & ~showDisplayStatusFlag); }, + function() { return (Scene.doEngineDisplayItemStatus() & showDisplayStatusFlag) > 0; }, + function(value) { return (value & showDisplayStatusFlag) > 0; } +); + +panel.newCheckbox("Network/Physics status", + function(value) { Scene.setEngineDisplayItemStatus(value ? + Scene.doEngineDisplayItemStatus() | showNetworkStatusFlag : + Scene.doEngineDisplayItemStatus() & ~showNetworkStatusFlag); }, + function() { return (Scene.doEngineDisplayItemStatus() & showNetworkStatusFlag) > 0; }, + function(value) { return (value & showNetworkStatusFlag) > 0; } ); var tickTackPeriod = 500; diff --git a/interface/resources/icons/statusIconAtlas.svg b/interface/resources/icons/statusIconAtlas.svg new file mode 100644 index 0000000000..72f9bc4af7 --- /dev/null +++ b/interface/resources/icons/statusIconAtlas.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7a564bbbf0..dd99599d96 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3499,10 +3499,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls)) { renderDebugFlags = (RenderArgs::DebugFlags) (renderDebugFlags | (int)RenderArgs::RENDER_DEBUG_HULLS); } - if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowOwned)) { - renderDebugFlags = - (RenderArgs::DebugFlags) (renderDebugFlags | (int)RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP); - } renderArgs->_debugFlags = renderDebugFlags; //ViveControllerManager::getInstance().updateRendering(renderArgs, _main3DScene, pendingChanges); } @@ -3562,6 +3558,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se renderContext._maxDrawnOverlay3DItems = sceneInterface->getEngineMaxDrawnOverlay3DItems(); renderContext._drawItemStatus = sceneInterface->doEngineDisplayItemStatus(); + if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowOwned)) { + renderContext._drawItemStatus |= render::showNetworkStatusFlag; + } renderContext._drawHitEffect = sceneInterface->doEngineDisplayHitEffect(); renderContext._occlusionStatus = Menu::getInstance()->isOptionChecked(MenuOption::DebugAmbientOcclusion); diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 866f444b32..839f2d4fbb 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -212,6 +212,7 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { auto ownerEntity = _ownerEntity.lock(); if (ownerEntity) { ownerEntity->setActionDataDirty(true); + ownerEntity->setActionDataNeedsTransmit(true); } }); activateBody(); diff --git a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp index 077f28350b..5d82311bcc 100644 --- a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp @@ -20,7 +20,6 @@ #include #include -#include "RenderableDebugableEntityItem.h" #include "../render-utils/simple_vert.h" #include "../render-utils/simple_frag.h" @@ -63,6 +62,4 @@ void RenderableBoxEntityItem::render(RenderArgs* args) { } else { DependencyManager::get()->renderSolidCubeInstance(batch, getTransformToCenter(), cubeColor); } - - RenderableDebugableEntityItem::render(this, args); }; diff --git a/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp b/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp deleted file mode 100644 index f103aaed4c..0000000000 --- a/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp +++ /dev/null @@ -1,67 +0,0 @@ -// -// RenderableDebugableEntityItem.cpp -// libraries/entities-renderer/src/ -// -// Created by Seth Alves on 5/1/15. -// 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 "RenderableDebugableEntityItem.h" - -#include - -#include -#include -#include - - -void RenderableDebugableEntityItem::renderBoundingBox(EntityItem* entity, RenderArgs* args, - float puffedOut, glm::vec4& color) { - Q_ASSERT(args->_batch); - gpu::Batch& batch = *args->_batch; - - auto shapeTransform = entity->getTransformToCenter(); - if (puffedOut != 0.0f) { - shapeTransform.postScale(1.0f + puffedOut); - } - batch.setModelTransform(Transform()); // we want to include the scale as well - DependencyManager::get()->renderWireCubeInstance(batch, shapeTransform, color); -} - -void RenderableDebugableEntityItem::render(EntityItem* entity, RenderArgs* args) { - if (args->_debugFlags & RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP) { - Q_ASSERT(args->_batch); - gpu::Batch& batch = *args->_batch; - - batch.setModelTransform(entity->getTransformToCenter()); // we want to include the scale as well - - auto nodeList = DependencyManager::get(); - const QUuid& myNodeID = nodeList->getSessionUUID(); - bool highlightSimulationOwnership = (entity->getSimulatorID() == myNodeID); - if (highlightSimulationOwnership) { - glm::vec4 greenColor(0.0f, 1.0f, 0.2f, 1.0f); - renderBoundingBox(entity, args, 0.08f, greenColor); - } - - quint64 now = usecTimestampNow(); - if (now - entity->getLastEditedFromRemote() < 0.1f * USECS_PER_SECOND) { - glm::vec4 redColor(1.0f, 0.0f, 0.0f, 1.0f); - renderBoundingBox(entity, args, 0.16f, redColor); - } - - if (now - entity->getLastBroadcast() < 0.2f * USECS_PER_SECOND) { - glm::vec4 yellowColor(1.0f, 1.0f, 0.2f, 1.0f); - renderBoundingBox(entity, args, 0.24f, yellowColor); - } - - ObjectMotionState* motionState = static_cast(entity->getPhysicsInfo()); - if (motionState && motionState->isActive()) { - glm::vec4 blueColor(0.0f, 0.0f, 1.0f, 1.0f); - renderBoundingBox(entity, args, 0.32f, blueColor); - } - } -} diff --git a/libraries/entities-renderer/src/RenderableDebugableEntityItem.h b/libraries/entities-renderer/src/RenderableDebugableEntityItem.h deleted file mode 100644 index 2680d882f5..0000000000 --- a/libraries/entities-renderer/src/RenderableDebugableEntityItem.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// RenderableDebugableEntityItem.h -// libraries/entities-renderer/src/ -// -// Created by Seth Alves on 5/1/15. -// 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_RenderableDebugableEntityItem_h -#define hifi_RenderableDebugableEntityItem_h - -#include - -class RenderableDebugableEntityItem { -public: - static void renderBoundingBox(EntityItem* entity, RenderArgs* args, float puffedOut, glm::vec4& color); - static void render(EntityItem* entity, RenderArgs* args); -}; - -#endif // hifi_RenderableDebugableEntityItem_h diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index bf9710857a..5504268dce 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -10,6 +10,7 @@ // +#include #include "RenderableEntityItem.h" namespace render { @@ -40,5 +41,60 @@ namespace render { } } +void makeEntityItemStatusGetters(EntityItemPointer entity, render::Item::Status::Getters& statusGetters) { + statusGetters.push_back([entity] () -> render::Item::Status::Value { + quint64 delta = usecTimestampNow() - entity->getLastEditedFromRemote(); + const float WAIT_THRESHOLD_INV = 1.0f / (0.2f * USECS_PER_SECOND); + float normalizedDelta = delta * WAIT_THRESHOLD_INV; + // Status icon will scale from 1.0f down to 0.0f after WAIT_THRESHOLD + // Color is red if last update is after WAIT_THRESHOLD, green otherwise (120 deg is green) + return render::Item::Status::Value(1.0f - normalizedDelta, (normalizedDelta > 1.0f ? + render::Item::Status::Value::GREEN : + render::Item::Status::Value::RED), + (unsigned char) RenderItemStatusIcon::PACKET_RECEIVED); + }); + statusGetters.push_back([entity] () -> render::Item::Status::Value { + quint64 delta = usecTimestampNow() - entity->getLastBroadcast(); + const float WAIT_THRESHOLD_INV = 1.0f / (0.4f * USECS_PER_SECOND); + float normalizedDelta = delta * WAIT_THRESHOLD_INV; + // Status icon will scale from 1.0f down to 0.0f after WAIT_THRESHOLD + // Color is Magenta if last update is after WAIT_THRESHOLD, cyan otherwise (180 deg is green) + return render::Item::Status::Value(1.0f - normalizedDelta, (normalizedDelta > 1.0f ? + render::Item::Status::Value::MAGENTA : + render::Item::Status::Value::CYAN), + (unsigned char)RenderItemStatusIcon::PACKET_SENT); + }); + statusGetters.push_back([entity] () -> render::Item::Status::Value { + ObjectMotionState* motionState = static_cast(entity->getPhysicsInfo()); + if (motionState && motionState->isActive()) { + return render::Item::Status::Value(1.0f, render::Item::Status::Value::BLUE, + (unsigned char)RenderItemStatusIcon::ACTIVE_IN_BULLET); + } + return render::Item::Status::Value(0.0f, render::Item::Status::Value::BLUE, + (unsigned char)RenderItemStatusIcon::ACTIVE_IN_BULLET); + }); + + statusGetters.push_back([entity] () -> render::Item::Status::Value { + auto nodeList = DependencyManager::get(); + const QUuid& myNodeID = nodeList->getSessionUUID(); + bool weOwnSimulation = entity->getSimulationOwner().matchesValidID(myNodeID); + + if (weOwnSimulation) { + return render::Item::Status::Value(1.0f, render::Item::Status::Value::BLUE, + (unsigned char)RenderItemStatusIcon::SIMULATION_OWNER); + } + return render::Item::Status::Value(0.0f, render::Item::Status::Value::BLUE, + (unsigned char)RenderItemStatusIcon::SIMULATION_OWNER); + }); + + statusGetters.push_back([entity] () -> render::Item::Status::Value { + if (entity->hasActions()) { + return render::Item::Status::Value(1.0f, render::Item::Status::Value::GREEN, + (unsigned char)RenderItemStatusIcon::HAS_ACTIONS); + } + return render::Item::Status::Value(0.0f, render::Item::Status::Value::GREEN, + (unsigned char)RenderItemStatusIcon::HAS_ACTIONS); + }); +} diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index 1832ef28c3..212b71759f 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -15,13 +15,26 @@ #include #include +// These or the icon "name" used by the render item status value, they correspond to the atlas texture used by the DrawItemStatus +// job in the current rendering pipeline defined as of now (11/2015) in render-utils/RenderDeferredTask.cpp. +enum class RenderItemStatusIcon { + ACTIVE_IN_BULLET = 0, + PACKET_SENT = 1, + PACKET_RECEIVED = 2, + SIMULATION_OWNER = 3, + HAS_ACTIONS = 4, + NONE = 255 +}; + +void makeEntityItemStatusGetters(EntityItemPointer entity, render::Item::Status::Getters& statusGetters); + class RenderableEntityItemProxy { public: RenderableEntityItemProxy(EntityItemPointer entity) : entity(entity) { } typedef render::Payload Payload; typedef Payload::DataPointer Pointer; - + EntityItemPointer entity; }; @@ -36,19 +49,23 @@ class SimpleRenderableEntityItem { public: bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { _myItem = scene->allocateID(); - + auto renderData = std::make_shared(self); auto renderPayload = std::make_shared(renderData); - + + render::Item::Status::Getters statusGetters; + makeEntityItemStatusGetters(self, statusGetters); + renderPayload->addStatusGetters(statusGetters); + pendingChanges.resetItem(_myItem, renderPayload); - + return true; } void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { pendingChanges.removeItem(_myItem); } - + private: render::ItemID _myItem; }; @@ -62,5 +79,4 @@ private: \ SimpleRenderableEntityItem _renderHelper; - #endif // hifi_RenderableEntityItem_h diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp index 3735690c33..f39c31e22b 100644 --- a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp @@ -54,6 +54,4 @@ void RenderableLineEntityItem::render(RenderArgs* args) { DependencyManager::get()->bindSimpleProgram(batch); DependencyManager::get()->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID); } - - RenderableDebugableEntityItem::render(this, args); }; diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.h b/libraries/entities-renderer/src/RenderableLineEntityItem.h index 09f98ca364..ba990046a0 100644 --- a/libraries/entities-renderer/src/RenderableLineEntityItem.h +++ b/libraries/entities-renderer/src/RenderableLineEntityItem.h @@ -13,7 +13,6 @@ #define hifi_RenderableLineEntityItem_h #include -#include "RenderableDebugableEntityItem.h" #include "RenderableEntityItem.h" #include diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index e604bdb925..f1be8611e1 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -21,7 +21,9 @@ #include "EntityTreeRenderer.h" #include "EntitiesRendererLogging.h" +#include "RenderableEntityItem.h" #include "RenderableModelEntityItem.h" +#include "RenderableEntityItem.h" EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { return std::make_shared(entityID, properties); @@ -179,25 +181,6 @@ namespace render { } } -void makeEntityItemStatusGetters(RenderableModelEntityItem* entity, render::Item::Status::Getters& statusGetters) { - statusGetters.push_back([entity] () -> render::Item::Status::Value { - quint64 delta = usecTimestampNow() - entity->getLastEditedFromRemote(); - const float WAIT_THRESHOLD_INV = 1.0f / (0.2f * USECS_PER_SECOND); - float normalizedDelta = delta * WAIT_THRESHOLD_INV; - // Status icon will scale from 1.0f down to 0.0f after WAIT_THRESHOLD - // Color is red if last update is after WAIT_THRESHOLD, green otherwise (120 deg is green) - return render::Item::Status::Value(1.0f - normalizedDelta, (normalizedDelta > 1.0f ? render::Item::Status::Value::GREEN : render::Item::Status::Value::RED)); - }); - statusGetters.push_back([entity] () -> render::Item::Status::Value { - quint64 delta = usecTimestampNow() - entity->getLastBroadcast(); - const float WAIT_THRESHOLD_INV = 1.0f / (0.4f * USECS_PER_SECOND); - float normalizedDelta = delta * WAIT_THRESHOLD_INV; - // Status icon will scale from 1.0f down to 0.0f after WAIT_THRESHOLD - // Color is Magenta if last update is after WAIT_THRESHOLD, cyan otherwise (180 deg is green) - return render::Item::Status::Value(1.0f - normalizedDelta, (normalizedDelta > 1.0f ? render::Item::Status::Value::MAGENTA : render::Item::Status::Value::CYAN)); - }); -} - bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { _myMetaItem = scene->allocateID(); @@ -209,11 +192,11 @@ bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_p if (_model) { render::Item::Status::Getters statusGetters; - makeEntityItemStatusGetters(this, statusGetters); + makeEntityItemStatusGetters(shared_from_this(), statusGetters); // note: we don't care if the model fails to add items, we always added our meta item and therefore we return // true so that the system knows our meta item is in the scene! - _model->addToScene(scene, pendingChanges, statusGetters); + _model->addToScene(scene, pendingChanges, statusGetters, _showCollisionHull); } return true; @@ -245,14 +228,16 @@ void RenderableModelEntityItem::render(RenderArgs* args) { // check to see if when we added our models to the scene they were ready, if they were not ready, then // fix them up in the scene - if (_model->needsFixupInScene()) { + bool shouldShowCollisionHull = (args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS) > 0; + if (_model->needsFixupInScene() || _showCollisionHull != shouldShowCollisionHull) { + _showCollisionHull = shouldShowCollisionHull; render::PendingChanges pendingChanges; _model->removeFromScene(scene, pendingChanges); render::Item::Status::Getters statusGetters; - makeEntityItemStatusGetters(this, statusGetters); - _model->addToScene(scene, pendingChanges, statusGetters); + makeEntityItemStatusGetters(shared_from_this(), statusGetters); + _model->addToScene(scene, pendingChanges, statusGetters, _showCollisionHull); scene->enqueuePendingChanges(pendingChanges); } @@ -274,7 +259,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) { EntityTreeRenderer* renderer = static_cast(args->_renderer); getModel(renderer); } - + if (_model) { // handle animations.. if (hasAnimation()) { @@ -320,11 +305,12 @@ void RenderableModelEntityItem::render(RenderArgs* args) { } } } else { - glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f); - RenderableDebugableEntityItem::renderBoundingBox(this, args, 0.0f, greenColor); + static glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f); + gpu::Batch& batch = *args->_batch; + auto shapeTransform = getTransformToCenter(); + batch.setModelTransform(Transform()); // we want to include the scale as well + DependencyManager::get()->renderWireCubeInstance(batch, shapeTransform, greenColor); } - - RenderableDebugableEntityItem::render(this, args); } Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 4dc1cced48..c4e36c240a 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -16,7 +16,6 @@ #include #include -#include "RenderableDebugableEntityItem.h" class Model; class EntityTreeRenderer; @@ -82,6 +81,8 @@ private: bool _dimensionsInitialized = true; render::ItemID _myMetaItem; + + bool _showCollisionHull = false; }; #endif // hifi_RenderableModelEntityItem_h diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 41cf3b9bbf..05fca343fd 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -139,6 +139,9 @@ bool RenderableParticleEffectEntityItem::addToScene(EntityItemPointer self, _renderItemId = scene->allocateID(); auto renderData = ParticlePayload::Pointer(particlePayload); auto renderPayload = render::PayloadPointer(new ParticlePayload::Payload(renderData)); + render::Item::Status::Getters statusGetters; + makeEntityItemStatusGetters(shared_from_this(), statusGetters); + renderPayload->addStatusGetters(statusGetters); pendingChanges.resetItem(_renderItemId, renderPayload); _scene = scene; return true; diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index 7bec8f2b03..32418199b8 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -153,6 +153,4 @@ void RenderablePolyLineEntityItem::render(RenderArgs* args) { batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride); batch.draw(gpu::TRIANGLE_STRIP, _numVertices, 0); - - RenderableDebugableEntityItem::render(this, args); }; diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h index 2832053639..c8a47cce0c 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h @@ -14,7 +14,6 @@ #include #include -#include "RenderableDebugableEntityItem.h" #include "RenderableEntityItem.h" #include #include diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index fd5a9a6b4a..2e8b8920ce 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -538,8 +538,6 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { batch._glUniform3f(voxelVolumeSizeLocation, _voxelVolumeSize.x, _voxelVolumeSize.y, _voxelVolumeSize.z); batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0); - - RenderableDebugableEntityItem::render(this, args); } bool RenderablePolyVoxEntityItem::addToScene(EntityItemPointer self, @@ -551,6 +549,10 @@ bool RenderablePolyVoxEntityItem::addToScene(EntityItemPointer self, auto renderData = PolyVoxPayload::Pointer(renderItem); auto renderPayload = std::make_shared(renderData); + render::Item::Status::Getters statusGetters; + makeEntityItemStatusGetters(shared_from_this(), statusGetters); + renderPayload->addStatusGetters(statusGetters); + pendingChanges.resetItem(_myItem, renderPayload); return true; diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index ef44ba5ab0..9d0931a47e 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -21,7 +21,6 @@ #include #include "PolyVoxEntityItem.h" -#include "RenderableDebugableEntityItem.h" #include "RenderableEntityItem.h" #include "gpu/Context.h" diff --git a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp index 246cd2fea7..0400ecb999 100644 --- a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp @@ -20,7 +20,6 @@ #include #include -#include "RenderableDebugableEntityItem.h" #include "../render-utils/simple_vert.h" #include "../render-utils/simple_frag.h" @@ -70,7 +69,4 @@ void RenderableSphereEntityItem::render(RenderArgs* args) { batch.setModelTransform(Transform()); DependencyManager::get()->renderSolidSphereInstance(batch, modelTransform, sphereColor); } - - - RenderableDebugableEntityItem::render(this, args); }; diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index ff56bef46b..b7b91c9b3a 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -19,6 +19,8 @@ #include #include +#include "RenderableEntityItem.h" + // Sphere entities should fit inside a cube entity of the same size, so a sphere that has dimensions 1x1x1 // is a half unit sphere. However, the geometry cache renders a UNIT sphere, so we need to scale down. static const float SPHERE_ENTITY_SCALE = 0.5f; @@ -112,7 +114,9 @@ void RenderableZoneEntityItem::render(RenderArgs* args) { render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); render::PendingChanges pendingChanges; _model->removeFromScene(scene, pendingChanges); - _model->addToScene(scene, pendingChanges); + render::Item::Status::Getters statusGetters; + makeEntityItemStatusGetters(shared_from_this(), statusGetters); + _model->addToScene(scene, pendingChanges, false); scene->enqueuePendingChanges(pendingChanges); @@ -203,7 +207,11 @@ bool RenderableZoneEntityItem::addToScene(EntityItemPointer self, std::shared_pt auto renderData = std::make_shared(self); auto renderPayload = std::make_shared(renderData); - + + render::Item::Status::Getters statusGetters; + makeEntityItemStatusGetters(shared_from_this(), statusGetters); + renderPayload->addStatusGetters(statusGetters); + pendingChanges.resetItem(_myMetaItem, renderPayload); return true; } diff --git a/libraries/entities/src/EntityActionInterface.cpp b/libraries/entities/src/EntityActionInterface.cpp index 549aacbd0a..ce9a93a6ac 100644 --- a/libraries/entities/src/EntityActionInterface.cpp +++ b/libraries/entities/src/EntityActionInterface.cpp @@ -304,3 +304,24 @@ QDataStream& operator>>(QDataStream& stream, EntityActionType& entityActionType) entityActionType = (EntityActionType)actionTypeAsInt; return stream; } + +QString serializedActionsToDebugString(QByteArray data) { + if (data.size() == 0) { + return QString(); + } + QVector serializedActions; + QDataStream serializedActionsStream(data); + serializedActionsStream >> serializedActions; + + QString result; + foreach(QByteArray serializedAction, serializedActions) { + QDataStream serializedActionStream(serializedAction); + EntityActionType actionType; + QUuid actionID; + serializedActionStream >> actionType; + serializedActionStream >> actionID; + result += EntityActionInterface::actionTypeToString(actionType) + "-" + actionID.toString() + " "; + } + + return result; +} diff --git a/libraries/entities/src/EntityActionInterface.h b/libraries/entities/src/EntityActionInterface.h index b257df3325..01292e3840 100644 --- a/libraries/entities/src/EntityActionInterface.h +++ b/libraries/entities/src/EntityActionInterface.h @@ -89,4 +89,6 @@ typedef std::shared_ptr EntityActionPointer; QDataStream& operator<<(QDataStream& stream, const EntityActionType& entityActionType); QDataStream& operator>>(QDataStream& stream, EntityActionType& entityActionType); +QString serializedActionsToDebugString(QByteArray data); + #endif // hifi_EntityActionInterface_h diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index cce3045049..f032dcd347 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -630,6 +630,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef dataAt += bytes; bytesRead += bytes; + if (wantTerseEditLogging() && _simulationOwner != newSimOwner) { + qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << newSimOwner; + } if (_simulationOwner.set(newSimOwner)) { _dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID; } @@ -704,17 +707,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL); READ_ENTITY_PROPERTY(PROP_HREF, QString, setHref); READ_ENTITY_PROPERTY(PROP_DESCRIPTION, QString, setDescription); - - { // When we own the simulation we don't accept updates to the entity's actions - // but since we're using macros below we have to temporarily modify overwriteLocalData. - // NOTE: this prevents userB from adding an action to an object1 when UserA - // has simulation ownership of it. - // TODO: figure out how to allow multiple users to update actions simultaneously - bool oldOverwrite = overwriteLocalData; - overwriteLocalData = overwriteLocalData && !weOwnSimulation; - READ_ENTITY_PROPERTY(PROP_ACTION_DATA, QByteArray, setActionData); - overwriteLocalData = oldOverwrite; - } + READ_ENTITY_PROPERTY(PROP_ACTION_DATA, QByteArray, setActionData); bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData, somethingChanged); @@ -737,7 +730,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // this "new" data is actually slightly out of date. We calculate the time we need to skip forward and // use our simulation helper routine to get a best estimate of where the entity should be. float skipTimeForward = (float)(now - lastSimulatedFromBufferAdjusted) / (float)(USECS_PER_SECOND); - + // we want to extrapolate the motion forward to compensate for packet travel time, but // we don't want the side effect of flag setting. simulateKinematicMotion(skipTimeForward, false); @@ -745,7 +738,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef if (overwriteLocalData) { if (!_simulationOwner.matchesValidID(myNodeID)) { - _lastSimulated = now; } } @@ -996,6 +988,11 @@ EntityTreePointer EntityItem::getTree() const { return tree; } +bool EntityItem::wantTerseEditLogging() { + EntityTreePointer tree = getTree(); + return tree ? tree->wantTerseEditLogging() : false; +} + glm::mat4 EntityItem::getEntityToWorldMatrix() const { glm::mat4 translation = glm::translate(getPosition()); glm::mat4 rotation = glm::mat4_cast(getRotation()); @@ -1492,20 +1489,35 @@ void EntityItem::updateCreated(uint64_t value) { } void EntityItem::setSimulationOwner(const QUuid& id, quint8 priority) { + if (wantTerseEditLogging() && (id != _simulationOwner.getID() || priority != _simulationOwner.getPriority())) { + qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << id << priority; + } _simulationOwner.set(id, priority); } void EntityItem::setSimulationOwner(const SimulationOwner& owner) { + if (wantTerseEditLogging() && _simulationOwner != owner) { + qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << owner; + } + _simulationOwner.set(owner); } void EntityItem::updateSimulatorID(const QUuid& value) { + if (wantTerseEditLogging() && _simulationOwner.getID() != value) { + qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << value; + } + if (_simulationOwner.setID(value)) { _dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID; } } void EntityItem::clearSimulationOwnership() { + if (wantTerseEditLogging() && !_simulationOwner.isNull()) { + qCDebug(entities) << "sim ownership for" << getDebugName() << "is now null"; + } + _simulationOwner.clear(); // don't bother setting the DIRTY_SIMULATOR_ID flag because clearSimulationOwnership() // is only ever called entity-server-side and the flags are only used client-side @@ -1607,6 +1619,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* s bool success = true; serializeActions(success, _allActionsDataCache); _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + setActionDataNeedsTransmit(true); return success; } return false; @@ -1649,7 +1662,7 @@ void EntityItem::deserializeActionsInternal() { return; } - EntityTreePointer entityTree = _element ? _element->getTree() : nullptr; + EntityTreePointer entityTree = getTree(); assert(entityTree); EntitySimulation* simulation = entityTree ? entityTree->getSimulation() : nullptr; assert(simulation); @@ -1770,6 +1783,7 @@ void EntityItem::serializeActions(bool& success, QByteArray& result) const { serializedActionsStream << serializedActions; if (result.size() >= _maxActionsDataSize) { + qDebug() << "EntityItem::serializeActions size is too large -- " << result.size() << ">=" << _maxActionsDataSize; success = false; return; } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 858dc7e326..5b47198e97 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -307,6 +307,7 @@ public: QString getName() const { return _name; } void setName(const QString& value) { _name = value; } + QString getDebugName() { return _name != "" ? _name : getID().toString(); } bool getVisible() const { return _visible; } void setVisible(bool value) { _visible = value; } @@ -381,6 +382,7 @@ public: void setPhysicsInfo(void* data) { _physicsInfo = data; } EntityTreeElementPointer getElement() const { return _element; } EntityTreePointer getTree() const; + bool wantTerseEditLogging(); static void setSendPhysicsUpdates(bool value) { _sendPhysicsUpdates = value; } static bool getSendPhysicsUpdates() { return _sendPhysicsUpdates; } @@ -406,7 +408,13 @@ public: QList getActionIDs() { return _objectActions.keys(); } QVariantMap getActionArguments(const QUuid& actionID) const; void deserializeActions(); + void setActionDataDirty(bool value) const { _actionDataDirty = value; } + bool actionDataDirty() const { return _actionDataDirty; } + + void setActionDataNeedsTransmit(bool value) const { _actionDataNeedsTransmit = value; } + bool actionDataNeedsTransmit() const { return _actionDataNeedsTransmit; } + bool shouldSuppressLocationEdits() const; void setSourceUUID(const QUuid& sourceUUID) { _sourceUUID = sourceUUID; } @@ -439,7 +447,7 @@ protected: mutable bool _recalcAABox = true; mutable bool _recalcMinAACube = true; mutable bool _recalcMaxAACube = true; - + float _glowLevel; float _localRenderAlpha; float _density = ENTITY_ITEM_DEFAULT_DENSITY; // kg/m^3 @@ -510,6 +518,7 @@ protected: void checkWaitingToRemove(EntitySimulation* simulation = nullptr); mutable QSet _actionsToRemove; mutable bool _actionDataDirty = false; + mutable bool _actionDataNeedsTransmit = false; // _previouslyDeletedActions is used to avoid an action being re-added due to server round-trip lag static quint64 _rememberDeletedActionTime; mutable QHash _previouslyDeletedActions; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 8ca0e9b5fa..bc57f2c72c 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -611,7 +611,8 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString, const QVariantMap& arguments) { QUuid actionID = QUuid::createUuid(); auto actionFactory = DependencyManager::get(); - bool success = actionWorker(entityID, [&](EntitySimulation* simulation, EntityItemPointer entity) { + bool success = false; + actionWorker(entityID, [&](EntitySimulation* simulation, EntityItemPointer entity) { // create this action even if the entity doesn't have physics info. it will often be the // case that a script adds an action immediately after an object is created, and the physicsInfo // is computed asynchronously. @@ -623,16 +624,16 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString, return false; } EntityActionPointer action = actionFactory->factory(actionType, actionID, entity, arguments); - if (action) { - entity->addAction(simulation, action); - auto nodeList = DependencyManager::get(); - const QUuid myNodeID = nodeList->getSessionUUID(); - if (entity->getSimulatorID() != myNodeID) { - entity->flagForOwnership(); - } - return true; + if (!action) { + return false; } - return false; + success = entity->addAction(simulation, action); + auto nodeList = DependencyManager::get(); + const QUuid myNodeID = nodeList->getSessionUUID(); + if (entity->getSimulatorID() != myNodeID) { + entity->flagForOwnership(); + } + return false; // Physics will cause a packet to be sent, so don't send from here. }); if (success) { return actionID; @@ -656,9 +657,12 @@ bool EntityScriptingInterface::updateAction(const QUuid& entityID, const QUuid& } bool EntityScriptingInterface::deleteAction(const QUuid& entityID, const QUuid& actionID) { - return actionWorker(entityID, [&](EntitySimulation* simulation, EntityItemPointer entity) { - return entity->removeAction(simulation, actionID); + bool success = false; + actionWorker(entityID, [&](EntitySimulation* simulation, EntityItemPointer entity) { + success = entity->removeAction(simulation, actionID); + return false; // Physics will cause a packet to be sent, so don't send from here. }); + return success; } QVector EntityScriptingInterface::getActionIDs(const QUuid& entityID) { diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index c2f635c95f..027972549a 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -198,6 +198,10 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI properties.setVelocityChanged(false); properties.setAngularVelocityChanged(false); properties.setAccelerationChanged(false); + + if (wantTerseEditLogging()) { + qCDebug(entities) << senderNode->getUUID() << "physical edits suppressed"; + } } } // else client accepts what the server says @@ -612,6 +616,14 @@ EntityItemPointer EntityTree::findEntityByEntityItemID(const EntityItemID& entit } void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList& changedProperties) { + static quint64 lastTerseLog = 0; + quint64 now = usecTimestampNow(); + + if (now - lastTerseLog > USECS_PER_SECOND) { + qCDebug(entities) << "-------------------------"; + } + lastTerseLog = now; + if (properties.simulationOwnerChanged()) { int simIndex = changedProperties.indexOf("simulationOwner"); if (simIndex >= 0) { @@ -619,6 +631,79 @@ void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList= 0) { + glm::vec3 value = properties.getVelocity(); + QString changeHint = "0"; + if (value.x + value.y + value.z > 0) { + changeHint = "+"; + } else if (value.x + value.y + value.z < 0) { + changeHint = "-"; + } + changedProperties[index] = QString("velocity:") + changeHint; + } + } + + if (properties.gravityChanged()) { + int index = changedProperties.indexOf("gravity"); + if (index >= 0) { + glm::vec3 value = properties.getGravity(); + QString changeHint = "0"; + if (value.x + value.y + value.z > 0) { + changeHint = "+"; + } else if (value.x + value.y + value.z < 0) { + changeHint = "-"; + } + changedProperties[index] = QString("gravity:") + changeHint; + } + } + + if (properties.actionDataChanged()) { + int index = changedProperties.indexOf("actionData"); + if (index >= 0) { + QByteArray value = properties.getActionData(); + QString changeHint = serializedActionsToDebugString(value); + changedProperties[index] = QString("actionData:") + changeHint; + } + } + + if (properties.ignoreForCollisionsChanged()) { + int index = changedProperties.indexOf("ignoreForCollisions"); + if (index >= 0) { + bool value = properties.getIgnoreForCollisions(); + QString changeHint = "0"; + if (value) { + changeHint = "1"; + } + changedProperties[index] = QString("ignoreForCollisions:") + changeHint; + } + } + + if (properties.collisionsWillMoveChanged()) { + int index = changedProperties.indexOf("collisionsWillMove"); + if (index >= 0) { + bool value = properties.getCollisionsWillMove(); + QString changeHint = "0"; + if (value) { + changeHint = "1"; + } + changedProperties[index] = QString("collisionsWillMove:") + changeHint; + } + } + + if (properties.lockedChanged()) { + int index = changedProperties.indexOf("locked"); + if (index >= 0) { + bool value = properties.getLocked(); + QString changeHint = "0"; + if (value) { + changeHint = "1"; + } + changedProperties[index] = QString("locked:") + changeHint; + } + } } int EntityTree::processEditPacketData(NLPacket& packet, const unsigned char* editData, int maxLength, @@ -673,7 +758,8 @@ int EntityTree::processEditPacketData(NLPacket& packet, const unsigned char* edi if (wantTerseEditLogging()) { QList changedProperties = properties.listChangedProperties(); fixupTerseEditLogging(properties, changedProperties); - qCDebug(entities) << "edit" << entityItemID.toString() << changedProperties; + qCDebug(entities) << senderNode->getUUID() << "edit" << + existingEntity->getDebugName() << changedProperties; } endLogging = usecTimestampNow(); @@ -703,7 +789,7 @@ int EntityTree::processEditPacketData(NLPacket& packet, const unsigned char* edi if (wantTerseEditLogging()) { QList changedProperties = properties.listChangedProperties(); fixupTerseEditLogging(properties, changedProperties); - qCDebug(entities) << "add" << entityItemID.toString() << changedProperties; + qCDebug(entities) << senderNode->getUUID() << "add" << entityItemID << changedProperties; } endLogging = usecTimestampNow(); diff --git a/libraries/entities/src/SimulationOwner.cpp b/libraries/entities/src/SimulationOwner.cpp index d6957873e2..24f6784954 100644 --- a/libraries/entities/src/SimulationOwner.cpp +++ b/libraries/entities/src/SimulationOwner.cpp @@ -157,7 +157,7 @@ void SimulationOwner::test() { } bool SimulationOwner::operator!=(const SimulationOwner& other) { - return (_id != other._id && _priority != other._priority); + return (_id != other._id || _priority != other._priority); } SimulationOwner& SimulationOwner::operator=(const SimulationOwner& other) { diff --git a/libraries/gpu/src/gpu/Resource.h b/libraries/gpu/src/gpu/Resource.h index f330b0fd07..8d53d6e2e7 100644 --- a/libraries/gpu/src/gpu/Resource.h +++ b/libraries/gpu/src/gpu/Resource.h @@ -331,7 +331,7 @@ public: template Iterator begin() { return Iterator(&edit(0), _stride); } template Iterator end() { return Iterator(&edit(getNum()), _stride); } - template Iterator cbegin() const { return Iterator(&get(0), _stride); } + template Iterator cbegin() const { return Iterator(&get(), _stride); } template Iterator cend() const { return Iterator(&get(getNum()), _stride); } // the number of elements of the specified type fitting in the view size diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index c8a0f87b6d..181ae7060e 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -112,8 +112,8 @@ 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) { - // we own the simulation or our priority looses to remote + if (engine->getSessionID() == _entity->getSimulatorID() || _entity->getSimulationPriority() >= _outgoingPriority) { + // we own the simulation or our priority looses to (or ties with) remote _outgoingPriority = NO_PRORITY; } } @@ -244,7 +244,7 @@ bool EntityMotionState::isCandidateForOwnership(const QUuid& sessionID) const { return false; } assert(entityTreeIsLocked()); - return _outgoingPriority != NO_PRORITY || sessionID == _entity->getSimulatorID(); + return _outgoingPriority != NO_PRORITY || sessionID == _entity->getSimulatorID() || _entity->actionDataNeedsTransmit(); } bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { @@ -292,7 +292,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { _serverPosition += dt * _serverVelocity; } - if (_serverActionData != _entity->getActionData()) { + if (_entity->actionDataNeedsTransmit()) { setOutgoingPriority(SCRIPT_EDIT_SIMULATION_PRIORITY); return true; } @@ -370,11 +370,15 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& s assert(_body); assert(entityTreeIsLocked()); + if (_entity->actionDataNeedsTransmit()) { + return true; + } + if (_entity->getSimulatorID() != sessionID) { // we don't own the simulation, but maybe we should... if (_outgoingPriority != NO_PRORITY) { if (_outgoingPriority < _entity->getSimulationPriority()) { - // our priority looses to remote, so we don't bother to bid + // our priority loses to remote, so we don't bother to bid _outgoingPriority = NO_PRORITY; return false; } @@ -456,7 +460,10 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q properties.setVelocity(_serverVelocity); properties.setAcceleration(_serverAcceleration); properties.setAngularVelocity(_serverAngularVelocity); - properties.setActionData(_serverActionData); + if (_entity->actionDataNeedsTransmit()) { + _entity->setActionDataNeedsTransmit(false); + properties.setActionData(_serverActionData); + } // set the LastEdited of the properties but NOT the entity itself quint64 now = usecTimestampNow(); @@ -526,7 +533,7 @@ void EntityMotionState::clearIncomingDirtyFlags() { } } -// virtual +// virtual quint8 EntityMotionState::getSimulationPriority() const { if (_entity) { return _entity->getSimulationPriority(); diff --git a/libraries/physics/src/ObjectActionOffset.cpp b/libraries/physics/src/ObjectActionOffset.cpp index 2cfd98497b..5c2999a0a1 100644 --- a/libraries/physics/src/ObjectActionOffset.cpp +++ b/libraries/physics/src/ObjectActionOffset.cpp @@ -130,6 +130,7 @@ bool ObjectActionOffset::updateArguments(QVariantMap arguments) { auto ownerEntity = _ownerEntity.lock(); if (ownerEntity) { ownerEntity->setActionDataDirty(true); + ownerEntity->setActionDataNeedsTransmit(true); } }); activateBody(); diff --git a/libraries/physics/src/ObjectActionSpring.cpp b/libraries/physics/src/ObjectActionSpring.cpp index c1cd2db5ca..d9d6a323a7 100644 --- a/libraries/physics/src/ObjectActionSpring.cpp +++ b/libraries/physics/src/ObjectActionSpring.cpp @@ -163,6 +163,7 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) { auto ownerEntity = _ownerEntity.lock(); if (ownerEntity) { ownerEntity->setActionDataDirty(true); + ownerEntity->setActionDataNeedsTransmit(true); } }); activateBody(); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index fa1d556cee..5b81c68e99 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -501,8 +501,10 @@ void Model::setVisibleInScene(bool newValue, std::shared_ptr scen } -bool Model::addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges) { - if (!_meshGroupsKnown && isLoaded()) { +bool Model::addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges, bool showCollisionHull) { + + if ((!_meshGroupsKnown || showCollisionHull != _showCollisionHull) && isLoaded()) { + _showCollisionHull = showCollisionHull; segregateMeshGroups(); } @@ -525,8 +527,12 @@ bool Model::addToScene(std::shared_ptr scene, render::PendingChan return somethingAdded; } -bool Model::addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges, render::Item::Status::Getters& statusGetters) { - if (!_meshGroupsKnown && isLoaded()) { +bool Model::addToScene(std::shared_ptr scene, + render::PendingChanges& pendingChanges, + render::Item::Status::Getters& statusGetters, + bool showCollisionHull) { + if ((!_meshGroupsKnown || showCollisionHull != _showCollisionHull) && isLoaded()) { + _showCollisionHull = showCollisionHull; segregateMeshGroups(); } @@ -1139,8 +1145,14 @@ AABox Model::getPartBounds(int meshIndex, int partIndex) { } void Model::segregateMeshGroups() { - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - const std::vector>& networkMeshes = _geometry->getMeshes(); + QSharedPointer networkGeometry; + if (_showCollisionHull && _collisionGeometry && _collisionGeometry->isLoaded()) { + networkGeometry = _collisionGeometry; + } else { + networkGeometry = _geometry; + } + const FBXGeometry& geometry = networkGeometry->getFBXGeometry(); + const std::vector>& networkMeshes = networkGeometry->getMeshes(); _rig->makeAnimSkeleton(geometry); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index f5d5f40363..b154ae2b52 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -76,10 +76,13 @@ public: return !_needsReload && isRenderable() && isActive() && isLoaded(); } bool initWhenReady(render::ScenePointer scene); - bool addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges); bool addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges, - render::Item::Status::Getters& statusGetters); + bool showCollisionHull = false); + bool addToScene(std::shared_ptr scene, + render::PendingChanges& pendingChanges, + render::Item::Status::Getters& statusGetters, + bool showCollisionHull = false); void removeFromScene(std::shared_ptr scene, render::PendingChanges& pendingChanges); void renderSetup(RenderArgs* args); bool isRenderable() const { return !_meshStates.isEmpty() || (isActive() && _geometry->getMeshes().empty()); } @@ -368,6 +371,7 @@ private: bool _readyWhenAdded = false; bool _needsReload = true; bool _needsUpdateClusterMatrices = true; + bool _showCollisionHull = false; friend class MeshPartPayload; protected: diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 845c96372c..e65018ad3d 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -12,6 +12,7 @@ #include "RenderDeferredTask.h" #include +#include #include #include #include @@ -111,8 +112,11 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false)))); _jobs.push_back(Job(new DrawTransparentDeferred::JobModel("TransparentDeferred", _jobs.back().getOutput()))); - _jobs.push_back(Job(new render::DrawStatus::JobModel("DrawStatus", renderedOpaques))); + // 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)))); _jobs.back().setEnabled(false); _drawStatusJobIndex = _jobs.size() - 1; @@ -387,4 +391,4 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const }); args->_batch = nullptr; -} \ No newline at end of file +} diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 04483fc037..6daa90b1ed 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -97,7 +97,12 @@ public: int _drawStatusJobIndex = -1; int _drawHitEffectJobIndex = -1; - void setDrawItemStatus(bool draw) { if (_drawStatusJobIndex >= 0) { _jobs[_drawStatusJobIndex].setEnabled(draw); } } + 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 setDrawHitEffect(bool draw) { if (_drawHitEffectJobIndex >= 0) { _jobs[_drawHitEffectJobIndex].setEnabled(draw); } } diff --git a/libraries/render/src/render/DrawStatus.cpp b/libraries/render/src/render/DrawStatus.cpp index 57e21a1511..5e8fd74e5f 100644 --- a/libraries/render/src/render/DrawStatus.cpp +++ b/libraries/render/src/render/DrawStatus.cpp @@ -29,7 +29,7 @@ using namespace render; -const gpu::PipelinePointer& DrawStatus::getDrawItemBoundsPipeline() { +const gpu::PipelinePointer DrawStatus::getDrawItemBoundsPipeline() { if (!_drawItemBoundsPipeline) { auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(drawItemBounds_vert))); auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(drawItemBounds_frag))); @@ -56,18 +56,20 @@ const gpu::PipelinePointer& DrawStatus::getDrawItemBoundsPipeline() { return _drawItemBoundsPipeline; } -const gpu::PipelinePointer& DrawStatus::getDrawItemStatusPipeline() { +const gpu::PipelinePointer DrawStatus::getDrawItemStatusPipeline() { if (!_drawItemStatusPipeline) { auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(drawItemStatus_vert))); auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(drawItemStatus_frag))); gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("iconStatusMap"), 0)); gpu::Shader::makeProgram(*program, slotBindings); _drawItemStatusPosLoc = program->getUniforms().findLocation("inBoundPos"); _drawItemStatusDimLoc = program->getUniforms().findLocation("inBoundDim"); - _drawItemStatusValueLoc = program->getUniforms().findLocation("inStatus"); + _drawItemStatusValue0Loc = program->getUniforms().findLocation("inStatus0"); + _drawItemStatusValue1Loc = program->getUniforms().findLocation("inStatus1"); auto state = std::make_shared(); @@ -84,11 +86,23 @@ const gpu::PipelinePointer& DrawStatus::getDrawItemStatusPipeline() { return _drawItemStatusPipeline; } -void DrawStatus::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) { +void DrawStatus::setStatusIconMap(const gpu::TexturePointer& map) { + _statusIconMap = map; +} + +const gpu::TexturePointer DrawStatus::getStatusIconMap() const { + return _statusIconMap; +} + +void DrawStatus::run(const SceneContextPointer& sceneContext, + const RenderContextPointer& renderContext, + const ItemIDsBounds& inItems) { assert(renderContext->args); assert(renderContext->args->_viewFrustum); RenderArgs* args = renderContext->args; auto& scene = sceneContext->_scene; + const int NUM_STATUS_VEC4_PER_ITEM = 2; + const int VEC4_LENGTH = 4; // FIrst thing, we collect the bound and the status for all the items we want to render int nbItems = 0; @@ -101,7 +115,7 @@ void DrawStatus::run(const SceneContextPointer& sceneContext, const RenderContex } _itemBounds->resize((inItems.size() * sizeof(AABox))); - _itemStatus->resize((inItems.size() * sizeof(glm::vec4))); + _itemStatus->resize((inItems.size() * NUM_STATUS_VEC4_PER_ITEM * sizeof(glm::vec4))); AABox* itemAABox = reinterpret_cast (_itemBounds->editData()); glm::ivec4* itemStatus = reinterpret_cast (_itemStatus->editData()); for (auto& item : inItems) { @@ -112,11 +126,31 @@ void DrawStatus::run(const SceneContextPointer& sceneContext, const RenderContex (*itemAABox).setBox(item.bounds.getCorner(), 0.1f); } auto& itemScene = scene->getItem(item.id); - (*itemStatus) = itemScene.getStatusPackedValues(); + + auto itemStatusPointer = itemScene.getStatus(); + if (itemStatusPointer) { + // Query the current status values, this is where the statusGetter lambda get called + auto&& currentStatusValues = itemStatusPointer->getCurrentValues(); + int valueNum = 0; + for (int vec4Num = 0; vec4Num < NUM_STATUS_VEC4_PER_ITEM; vec4Num++) { + (*itemStatus) = glm::ivec4(Item::Status::Value::INVALID.getPackedData()); + for (int component = 0; component < VEC4_LENGTH; component++) { + valueNum = vec4Num * VEC4_LENGTH + component; + if (valueNum < (int)currentStatusValues.size()) { + (*itemStatus)[component] = currentStatusValues[valueNum].getPackedData(); + } + } + itemStatus++; + } + } else { + (*itemStatus) = glm::ivec4(Item::Status::Value::INVALID.getPackedData()); + itemStatus++; + (*itemStatus) = glm::ivec4(Item::Status::Value::INVALID.getPackedData()); + itemStatus++; + } nbItems++; itemAABox++; - itemStatus++; } } } @@ -131,6 +165,7 @@ void DrawStatus::run(const SceneContextPointer& sceneContext, const RenderContex Transform viewMat; args->_viewFrustum->evalProjectionMatrix(projMat); args->_viewFrustum->evalViewTransform(viewMat); + batch.setViewportTransform(args->_viewport); batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); @@ -144,20 +179,28 @@ void DrawStatus::run(const SceneContextPointer& sceneContext, const RenderContex const unsigned int VEC3_ADRESS_OFFSET = 3; - for (int i = 0; i < nbItems; i++) { - batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const float*) (itemAABox + i)); - batch._glUniform3fv(_drawItemBoundDimLoc, 1, ((const float*) (itemAABox + i)) + VEC3_ADRESS_OFFSET); + if ((renderContext->_drawItemStatus & showDisplayStatusFlag) > 0) { + for (int i = 0; i < nbItems; i++) { + batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const float*) (itemAABox + i)); + batch._glUniform3fv(_drawItemBoundDimLoc, 1, ((const float*) (itemAABox + i)) + VEC3_ADRESS_OFFSET); - batch.draw(gpu::LINES, 24, 0); + batch.draw(gpu::LINES, 24, 0); + } } + batch.setResourceTexture(0, gpu::TextureView(getStatusIconMap(), 0)); + batch.setPipeline(getDrawItemStatusPipeline()); - for (int i = 0; i < nbItems; i++) { - batch._glUniform3fv(_drawItemStatusPosLoc, 1, (const float*) (itemAABox + i)); - batch._glUniform3fv(_drawItemStatusDimLoc, 1, ((const float*) (itemAABox + i)) + VEC3_ADRESS_OFFSET); - batch._glUniform4iv(_drawItemStatusValueLoc, 1, (const int*) (itemStatus + i)); - batch.draw(gpu::TRIANGLES, 24, 0); + if ((renderContext->_drawItemStatus & showNetworkStatusFlag) > 0) { + for (int i = 0; i < nbItems; i++) { + batch._glUniform3fv(_drawItemStatusPosLoc, 1, (const float*) (itemAABox + i)); + batch._glUniform3fv(_drawItemStatusDimLoc, 1, ((const float*) (itemAABox + i)) + VEC3_ADRESS_OFFSET); + batch._glUniform4iv(_drawItemStatusValue0Loc, 1, (const int*)(itemStatus + NUM_STATUS_VEC4_PER_ITEM * i)); + batch._glUniform4iv(_drawItemStatusValue1Loc, 1, (const int*)(itemStatus + NUM_STATUS_VEC4_PER_ITEM * i + 1)); + batch.draw(gpu::TRIANGLES, 24 * NUM_STATUS_VEC4_PER_ITEM, 0); + } } + batch.setResourceTexture(0, 0); }); } diff --git a/libraries/render/src/render/DrawStatus.h b/libraries/render/src/render/DrawStatus.h index a96b897f5c..1239819911 100644 --- a/libraries/render/src/render/DrawStatus.h +++ b/libraries/render/src/render/DrawStatus.h @@ -21,22 +21,30 @@ namespace render { int _drawItemBoundDimLoc = -1; int _drawItemStatusPosLoc = -1; int _drawItemStatusDimLoc = -1; - int _drawItemStatusValueLoc = -1; + int _drawItemStatusValue0Loc = -1; + int _drawItemStatusValue1Loc = -1; gpu::Stream::FormatPointer _drawItemFormat; gpu::PipelinePointer _drawItemBoundsPipeline; gpu::PipelinePointer _drawItemStatusPipeline; gpu::BufferPointer _itemBounds; gpu::BufferPointer _itemStatus; + gpu::TexturePointer _statusIconMap; public: + DrawStatus() {} + DrawStatus(const gpu::TexturePointer statusIconMap) { setStatusIconMap(statusIconMap); } + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems); typedef Job::ModelI JobModel; - const gpu::PipelinePointer& getDrawItemBoundsPipeline(); - const gpu::PipelinePointer& getDrawItemStatusPipeline(); + const gpu::PipelinePointer getDrawItemBoundsPipeline(); + const gpu::PipelinePointer getDrawItemStatusPipeline(); + + void setStatusIconMap(const gpu::TexturePointer& map); + const gpu::TexturePointer getStatusIconMap() const; }; } diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index ed51273f88..3f628c3a02 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -143,7 +143,7 @@ public: const Varying getInput() const { return _input; } - ModelI(const std::string& name, const Varying& input): Concept(name), _input(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) { diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 5da7956b22..7c11246cff 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -25,6 +25,10 @@ public: }; typedef std::shared_ptr SceneContextPointer; +// see examples/utilities/tools/renderEngineDebug.js +const int showDisplayStatusFlag = 1; +const int showNetworkStatusFlag = 2; + class RenderContext { public: @@ -49,7 +53,7 @@ public: int _numDrawnOverlay3DItems = 0; int _maxDrawnOverlay3DItems = -1; - bool _drawItemStatus = false; + int _drawItemStatus = 0; bool _drawHitEffect = false; bool _occlusionStatus = false; diff --git a/libraries/render/src/render/Scene.cpp b/libraries/render/src/render/Scene.cpp index fb6782e011..18cf1d8335 100644 --- a/libraries/render/src/render/Scene.cpp +++ b/libraries/render/src/render/Scene.cpp @@ -72,17 +72,20 @@ void Item::Status::Value::setScale(float scale) { void Item::Status::Value::setColor(float hue) { // Convert the HUe from range [0, 360] to signed normalized value const float HUE_MAX = 360.0f; - _color = (std::numeric_limits::max() - 1) * 0.5f * (1.0f + std::max(std::min(hue, HUE_MAX), 0.0f) / HUE_MAX); + _color = (std::numeric_limits::max()) * (std::max(std::min(hue, HUE_MAX), 0.0f) / HUE_MAX); +} +void Item::Status::Value::setIcon(unsigned char icon) { + _icon = icon; } -void Item::Status::getPackedValues(glm::ivec4& values) const { - for (unsigned int i = 0; i < (unsigned int)values.length(); i++) { - if (i < _values.size()) { - values[i] = _values[i]().getPackedData(); - } else { - values[i] = Value::INVALID.getPackedData(); - } +Item::Status::Values Item::Status::getCurrentValues() const { + Values currentValues(_values.size()); + auto currentValue = currentValues.begin(); + for (auto& getter : _values) { + (*currentValue) = getter(); + currentValue++; } + return currentValues; } void Item::PayloadInterface::addStatusGetter(const Status::Getter& getter) { @@ -110,15 +113,6 @@ void Item::resetPayload(const PayloadPointer& payload) { } } -glm::ivec4 Item::getStatusPackedValues() const { - glm::ivec4 values(Status::Value::INVALID.getPackedData()); - auto& status = getStatus(); - if (status) { - status->getPackedValues(values); - }; - return values; -} - void PendingChanges::resetItem(ItemID id, const PayloadPointer& payload) { _resetItems.push_back(id); _resetPayloads.push_back(payload); diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index ab71a583b4..6ddd60cce8 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -206,17 +206,21 @@ public: // It can be scaled in the range [0, 1] and the color hue in the range [0, 360] representing the color wheel hue class Value { unsigned short _scale = 0xFFFF; - unsigned short _color = 0xFFFF; + unsigned char _color = 0xFF; + unsigned char _icon = 0xFF; public: const static Value INVALID; // Invalid value meanss the status won't show Value() {} - Value(float scale, float hue) { setScale(scale); setColor(hue); } + Value(float scale, float hue, unsigned char icon = 0xFF) { setScale(scale); setColor(hue); setIcon(icon); } // It can be scaled in the range [0, 1] void setScale(float scale); // the color hue in the range [0, 360] representing the color wheel hue void setColor(float hue); + // the icon to display in the range [0, 255], where 0 means no icon, just filled quad and anything else would + // hopefully have an icon available to display (see DrawStatusJob) + void setIcon(unsigned char icon); // Standard color Hue static const float RED; // 0.0f; @@ -237,7 +241,10 @@ public: void addGetter(const Getter& getter) { _values.push_back(getter); } - void getPackedValues(glm::ivec4& values) const; + size_t getNumValues() const { return _values.size(); } + + using Values = std::vector ; + Values getCurrentValues() const; }; typedef std::shared_ptr StatusPointer; @@ -301,7 +308,6 @@ public: // Access the status const StatusPointer& getStatus() const { return _payload->getStatus(); } - glm::ivec4 getStatusPackedValues() const; protected: PayloadPointer _payload; diff --git a/libraries/render/src/render/drawItemStatus.slf b/libraries/render/src/render/drawItemStatus.slf index 4cc45db2ec..40cf450363 100644 --- a/libraries/render/src/render/drawItemStatus.slf +++ b/libraries/render/src/render/drawItemStatus.slf @@ -12,9 +12,20 @@ // in vec4 varColor; +in vec3 varTexcoord; out vec4 outFragColor; +uniform sampler2D _icons; +vec2 getIconTexcoord(float icon, vec2 uv) { + const vec2 ICON_COORD_SIZE = vec2(0.0625, 1.0); + return vec2((uv.x + icon) * ICON_COORD_SIZE.x, uv.y * ICON_COORD_SIZE.y); +} void main(void) { - outFragColor = varColor; + if (varTexcoord.z < 254.5) { + outFragColor = texture(_icons, getIconTexcoord(varTexcoord.z, varTexcoord.xy)) * varColor; + } else { + vec2 centerDir = varTexcoord.xy * 2.0f - 1.0f; + outFragColor = vec4(varColor.xyz, 1.0 - step(1.0f, dot(centerDir.xy, centerDir.xy))); + } } diff --git a/libraries/render/src/render/drawItemStatus.slv b/libraries/render/src/render/drawItemStatus.slv index 178293575d..cb4ae7ebd2 100644 --- a/libraries/render/src/render/drawItemStatus.slv +++ b/libraries/render/src/render/drawItemStatus.slv @@ -17,10 +17,12 @@ <$declareStandardTransform()$> out vec4 varColor; +out vec3 varTexcoord; uniform vec3 inBoundPos; uniform vec3 inBoundDim; -uniform ivec4 inStatus; +uniform ivec4 inStatus0; +uniform ivec4 inStatus1; vec3 paintRainbow(float normalizedHue) { float v = normalizedHue * 6.f; @@ -43,16 +45,28 @@ vec3 paintRainbow(float normalizedHue) { } } -vec2 unpackStatus(int v) { - return vec2(clamp(float(int((v >> 0) & 0xFFFF) - 32727) / 32727.0, -1.0, 1.0), - clamp(float(int((v >> 16) & 0xFFFF) - 32727) / 32727.0, -1.0, 1.0)); +const int INVALID_STATUS = int(0xFFFFFFFF); +const int MAX_NUM_ICONS = 8; +const int ICONS_PER_ROW = 4; + +int getIconStatus(int icon) { + if (icon < ICONS_PER_ROW) { + return inStatus0[icon]; + } else if (icon < MAX_NUM_ICONS) { + return inStatus1[icon - ICONS_PER_ROW]; + } + return INVALID_STATUS; +} + +vec3 unpackStatus(int v) { + return vec3(clamp(float(int((v >> 0) & 0xFFFF) - 32727) / 32727.0, -1.0, 1.0), + clamp(float(uint((v >> 16) & 0xFF)) / 255.0, 0.0, 1.0), + clamp(float(int((v >> 24) & 0xFF)), 0.0, 255.0)); } void main(void) { - const vec2 ICON_PIXEL_SIZE = vec2(10, 10); - const vec2 MARGIN_PIXEL_SIZE = vec2(2, 2); - const int NUM_VERTICES = 6; - const vec4 UNIT_QUAD[NUM_VERTICES] = vec4[NUM_VERTICES]( + const int NUM_VERTICES_PER_ICON = 6; + const vec4 UNIT_QUAD[NUM_VERTICES_PER_ICON] = vec4[NUM_VERTICES_PER_ICON]( vec4(-1.0, -1.0, 0.0, 1.0), vec4(1.0, -1.0, 0.0, 1.0), vec4(-1.0, 1.0, 0.0, 1.0), @@ -61,6 +75,17 @@ void main(void) { vec4(1.0, 1.0, 0.0, 1.0) ); + const vec2 ICON_PIXEL_SIZE = vec2(20, 20); + const vec2 MARGIN_PIXEL_SIZE = vec2(2, 2); + const vec2 ICON_GRID_SLOTS[MAX_NUM_ICONS] = vec2[MAX_NUM_ICONS](vec2(-1.5, 0.5), + vec2(-0.5, 0.5), + vec2(0.5, 0.5), + vec2(1.5, 0.5), + vec2(-1.5,-0.5), + vec2(-0.5,-0.5), + vec2(0.5, -0.5), + vec2(1.5, -0.5)); + // anchor point in clip space vec4 anchorPoint = vec4(inBoundPos, 1.0) + vec4(inBoundDim, 0.0) * vec4(0.5, 0.5, 0.5, 0.0); TransformCamera cam = getTransformCamera(); @@ -68,36 +93,43 @@ void main(void) { <$transformModelToClipPos(cam, obj, anchorPoint, anchorPoint)$> // Which icon are we dealing with ? - int iconNum = gl_VertexID / NUM_VERTICES; + int iconNum = gl_VertexID / NUM_VERTICES_PER_ICON; + int packedIconStatus = getIconStatus(iconNum); // if invalid, just kill - if (inStatus[iconNum] == 0xFFFFFFFF) { + if (packedIconStatus == INVALID_STATUS) { gl_Position = anchorPoint; varColor = vec4(1.0); return; } + // Which quad vertex pos? + int twoTriID = gl_VertexID - iconNum * NUM_VERTICES_PER_ICON; + vec4 quadPos = UNIT_QUAD[twoTriID]; + // unpack to get x and y satus - vec2 iconStatus = unpackStatus(inStatus[iconNum]); + vec3 iconStatus = unpackStatus(packedIconStatus); // Use the status for showing a color varColor = vec4(paintRainbow(abs(iconStatus.y)), 1.0); + // Pass the texcoord and the z texcoord is representing the texture icon + varTexcoord = vec3((quadPos.xy + 1.0) * 0.5, iconStatus.z); + // Also changes the size of the notification vec2 iconScale = ICON_PIXEL_SIZE; - iconScale = max(vec2(1, 1), (iconScale * iconStatus.x)); + iconScale = max(vec2(0, 0), (iconScale * iconStatus.x)); //Offset icon to the right based on the iconNum - vec2 offset = vec2(iconNum * (ICON_PIXEL_SIZE.x + MARGIN_PIXEL_SIZE.x), 0); + vec2 gridOffset = ICON_GRID_SLOTS[iconNum]; + vec2 offset = gridOffset * (ICON_PIXEL_SIZE + MARGIN_PIXEL_SIZE); // Final position in pixel space - int twoTriID = gl_VertexID - iconNum * NUM_VERTICES; - vec4 pos = UNIT_QUAD[twoTriID]; - vec2 quadPixelPos = offset.xy + pos.xy * 0.5 * iconScale; + vec2 quadPixelPos = offset.xy + quadPos.xy * 0.5 * iconScale; vec4 viewport; <$transformCameraViewport(cam, viewport)$>; vec2 pixelToClip = vec2(2.0 / viewport.z, 2.0 / viewport.w); gl_Position = anchorPoint + (anchorPoint.w * vec4(quadPixelPos * pixelToClip, 0.0, 0.0)); -} \ No newline at end of file +} diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index 95919d6c0c..6be0ce44a8 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -107,8 +107,8 @@ public: Q_INVOKABLE void setEngineMaxDrawnOverlay3DItems(int count) { _maxDrawnOverlay3DItems = count; } Q_INVOKABLE int getEngineMaxDrawnOverlay3DItems() { return _maxDrawnOverlay3DItems; } - Q_INVOKABLE void setEngineDisplayItemStatus(bool display) { _drawItemStatus = display; } - Q_INVOKABLE bool doEngineDisplayItemStatus() { return _drawItemStatus; } + Q_INVOKABLE void setEngineDisplayItemStatus(int display) { _drawItemStatus = display; } + Q_INVOKABLE int doEngineDisplayItemStatus() { return _drawItemStatus; } Q_INVOKABLE void setEngineDisplayHitEffect(bool display) { _drawHitEffect = display; } Q_INVOKABLE bool doEngineDisplayHitEffect() { return _drawHitEffect; } @@ -143,7 +143,7 @@ protected: int _maxDrawnTransparentItems = -1; int _maxDrawnOverlay3DItems = -1; - bool _drawItemStatus = false; + int _drawItemStatus = 0; bool _drawHitEffect = false; diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index 25eed96490..fcacf7aaed 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -68,17 +68,16 @@ public: class RenderArgs { public: typedef std::function ShoudRenderFunctor; - + enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE }; enum RenderSide { MONO, STEREO_LEFT, STEREO_RIGHT }; enum DebugFlags { RENDER_DEBUG_NONE = 0, - RENDER_DEBUG_HULLS = 1, - RENDER_DEBUG_SIMULATION_OWNERSHIP = 2, + RENDER_DEBUG_HULLS = 1 }; - + RenderArgs(std::shared_ptr context = nullptr, OctreeRenderer* renderer = nullptr, ViewFrustum* viewFrustum = nullptr,