From 81cc15495f7cde1505b2a4bbb5ef2653150c1168 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 30 Oct 2014 14:43:43 -0700 Subject: [PATCH 1/4] rename Models to Entities, and add menu option to disable Light entities --- examples/lobby.js | 2 +- interface/src/Application.cpp | 4 ++-- interface/src/Menu.cpp | 20 ++++++++++--------- interface/src/Menu.h | 4 ++-- .../entities/RenderableLightEntityItem.cpp | 19 ++++++++++-------- .../src/voxels/OctreePacketProcessor.cpp | 4 ++-- 6 files changed, 29 insertions(+), 24 deletions(-) diff --git a/examples/lobby.js b/examples/lobby.js index 4642d13387..b5353131a5 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -174,7 +174,7 @@ function maybeCleanupLobby() { function toggleEnvironmentRendering(shouldRender) { Menu.setIsOptionChecked("Voxels", shouldRender); - Menu.setIsOptionChecked("Models", shouldRender); + Menu.setIsOptionChecked("Entities", shouldRender); Menu.setIsOptionChecked("Metavoxels", shouldRender); Menu.setIsOptionChecked("Avatars", shouldRender); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 92e74a9a2a..c33bc17091 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2338,7 +2338,7 @@ void Application::update(float deltaTime) { if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { queryOctree(NodeType::VoxelServer, PacketTypeVoxelQuery, _voxelServerJurisdictions); } - if (Menu::getInstance()->isOptionChecked(MenuOption::Models)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::Entities)) { queryOctree(NodeType::EntityServer, PacketTypeEntityQuery, _entityServerJurisdictions); } _lastQueriedViewFrustum = _viewFrustum; @@ -2985,7 +2985,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { } // render models... - if (Menu::getInstance()->isOptionChecked(MenuOption::Models)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::Entities)) { PerformanceTimer perfTimer("entities"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... entities..."); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index f2e2d2b3d9..617a119aad 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -367,7 +367,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, Qt::SHIFT | Qt::Key_A, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Avatars, 0, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, true); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Models, 0, true); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Entities, 0, true); QMenu* shadowMenu = renderOptionsMenu->addMenu("Shadows"); QActionGroup* shadowGroup = new QActionGroup(shadowMenu); @@ -434,14 +434,16 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtVectors, 0, false); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderFocusIndicator, 0, false); - QMenu* modelDebugMenu = developerMenu->addMenu("Models"); - addCheckableActionToQMenuAndActionHash(modelDebugMenu, MenuOption::DisplayModelBounds, 0, false); - addCheckableActionToQMenuAndActionHash(modelDebugMenu, MenuOption::DisplayModelElementProxy, 0, false); - addCheckableActionToQMenuAndActionHash(modelDebugMenu, MenuOption::DisplayModelElementChildProxies, 0, false); - QMenu* modelCullingMenu = modelDebugMenu->addMenu("Culling"); - addCheckableActionToQMenuAndActionHash(modelCullingMenu, MenuOption::DontCullOutOfViewMeshParts, 0, false); - addCheckableActionToQMenuAndActionHash(modelCullingMenu, MenuOption::DontCullTooSmallMeshParts, 0, false); - addCheckableActionToQMenuAndActionHash(modelCullingMenu, MenuOption::DontReduceMaterialSwitches, 0, false); + QMenu* entitiesDebugMenu = developerMenu->addMenu("Entities"); + addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DisplayModelBounds, 0, false); + addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DisplayModelElementProxy, 0, false); + addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DisplayModelElementChildProxies, 0, false); + addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DisableLightEntities, 0, false); + + QMenu* entityCullingMenu = entitiesDebugMenu->addMenu("Culling"); + addCheckableActionToQMenuAndActionHash(entityCullingMenu, MenuOption::DontCullOutOfViewMeshParts, 0, false); + addCheckableActionToQMenuAndActionHash(entityCullingMenu, MenuOption::DontCullTooSmallMeshParts, 0, false); + addCheckableActionToQMenuAndActionHash(entityCullingMenu, MenuOption::DontReduceMaterialSwitches, 0, false); QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxels"); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index d5ffbfcfc0..6afd03a0f0 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -387,6 +387,7 @@ namespace MenuOption { const QString DecreaseVoxelSize = "Decrease Voxel Size"; const QString DisableActivityLogger = "Disable Activity Logger"; const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD"; + const QString DisableLightEntities = "Disable Light Entities"; const QString DisableNackPackets = "Disable NACK Packets"; const QString DisplayFrustum = "Display Frustum"; const QString DisplayHands = "Show Hand Info"; @@ -403,6 +404,7 @@ namespace MenuOption { const QString Enable3DTVMode = "Enable 3DTV Mode"; const QString EnableGlowEffect = "Enable Glow Effect (Warning: Poor Oculus Performance)"; const QString EnableVRMode = "Enable VR Mode"; + const QString Entities = "Entities"; const QString ExpandMyAvatarSimulateTiming = "Expand /myAvatar/simulation"; const QString ExpandMyAvatarTiming = "Expand /myAvatar"; const QString ExpandOtherAvatarTiming = "Expand /otherAvatar"; @@ -433,8 +435,6 @@ namespace MenuOption { const QString MetavoxelEditor = "Metavoxel Editor..."; const QString Metavoxels = "Metavoxels"; const QString Mirror = "Mirror"; - const QString ModelOptions = "Model Options"; - const QString Models = "Models"; const QString MoveWithLean = "Move with Lean"; const QString MuteAudio = "Mute Microphone"; const QString MuteEnvironment = "Mute Environment"; diff --git a/interface/src/entities/RenderableLightEntityItem.cpp b/interface/src/entities/RenderableLightEntityItem.cpp index bf9939e164..e3e8f61e58 100644 --- a/interface/src/entities/RenderableLightEntityItem.cpp +++ b/interface/src/entities/RenderableLightEntityItem.cpp @@ -61,15 +61,18 @@ void RenderableLightEntityItem::render(RenderArgs* args) { float exponent = getExponent(); float cutoff = glm::radians(getCutoff()); - if (_isSpotlight) { - Application::getInstance()->getDeferredLightingEffect()->addSpotLight(position, largestDiameter / 2.0f, - ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation, - direction, exponent, cutoff); - } else { - Application::getInstance()->getDeferredLightingEffect()->addPointLight(position, largestDiameter / 2.0f, - ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation); - } + bool disableLights = Menu::getInstance()->isOptionChecked(MenuOption::DisableLightEntities); + if (!disableLights) { + if (_isSpotlight) { + Application::getInstance()->getDeferredLightingEffect()->addSpotLight(position, largestDiameter / 2.0f, + ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation, + direction, exponent, cutoff); + } else { + Application::getInstance()->getDeferredLightingEffect()->addPointLight(position, largestDiameter / 2.0f, + ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation); + } + } bool wantDebug = false; if (wantDebug) { glColor4f(diffuseR, diffuseG, diffuseB, 1.0f); diff --git a/interface/src/voxels/OctreePacketProcessor.cpp b/interface/src/voxels/OctreePacketProcessor.cpp index b3cf012869..9f53492e70 100644 --- a/interface/src/voxels/OctreePacketProcessor.cpp +++ b/interface/src/voxels/OctreePacketProcessor.cpp @@ -86,13 +86,13 @@ void OctreePacketProcessor::processPacket(const SharedNodePointer& sendingNode, switch(voxelPacketType) { case PacketTypeEntityErase: { - if (Menu::getInstance()->isOptionChecked(MenuOption::Models)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::Entities)) { app->_entities.processEraseMessage(mutablePacket, sendingNode); } } break; case PacketTypeEntityData: { - if (Menu::getInstance()->isOptionChecked(MenuOption::Models)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::Entities)) { app->_entities.processDatagram(mutablePacket, sendingNode); } } break; From 915a0d52d42010d7a3537cf60807028bae1a27f1 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 30 Oct 2014 15:01:59 -0700 Subject: [PATCH 2/4] only remap textures on the render thread, fix deadlock, and improve handling of changes to textures --- .../entities/RenderableModelEntityItem.cpp | 61 +++++++++++++------ .../src/entities/RenderableModelEntityItem.h | 2 + 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index 5a3ee61bbe..b64bca4217 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -38,12 +38,9 @@ RenderableModelEntityItem::~RenderableModelEntityItem() { bool RenderableModelEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) { QString oldModelURL = getModelURL(); - QString oldTextures = getTextures(); bool somethingChanged = ModelEntityItem::setProperties(properties, forceCopy); - if (somethingChanged) { - if ((oldModelURL != getModelURL()) || (oldTextures != getTextures())) { - _needsModelReload = true; - } + if (somethingChanged && oldModelURL != getModelURL()) { + _needsModelReload = true; } return somethingChanged; } @@ -60,6 +57,47 @@ int RenderableModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned c return bytesRead; } +void RenderableModelEntityItem::remapTextures() { + if (!_model) { + return; // nothing to do if we don't have a model + } + + if (_currentTextures == _textures) { + return; // nothing to do if our recently mapped textures match our desired textures + } + qDebug() << "void RenderableModelEntityItem::remapTextures()...."; + + // since we're changing here, we need to run through our current texture map + // and any textures in the recently mapped texture, that is not in our desired + // textures, we need to "unset" + QJsonDocument currentTexturesAsJson = QJsonDocument::fromJson(_currentTextures.toUtf8()); + QJsonObject currentTexturesAsJsonObject = currentTexturesAsJson.object(); + QVariantMap currentTextureMap = currentTexturesAsJsonObject.toVariantMap(); + + QJsonDocument texturesAsJson = QJsonDocument::fromJson(_textures.toUtf8()); + QJsonObject texturesAsJsonObject = texturesAsJson.object(); + QVariantMap textureMap = texturesAsJsonObject.toVariantMap(); + + foreach(const QString& key, currentTextureMap.keys()) { + // if the desired texture map (what we're setting the textures to) doesn't + // contain this texture, then remove it by setting the URL to null + if (!textureMap.contains(key)) { + QUrl noURL; + qDebug() << "Removing texture named" << key << "by replacing it with no URL"; + _model->setTextureWithNameToURL(key, noURL); + } + } + + // here's where we remap any textures if needed... + foreach(const QString& key, textureMap.keys()) { + QUrl newTextureURL = textureMap[key].toUrl(); + qDebug() << "Updating texture named" << key << "to texture at URL" << newTextureURL; + _model->setTextureWithNameToURL(key, newTextureURL); + } + + _currentTextures = _textures; +} + void RenderableModelEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RMEIrender"); @@ -72,6 +110,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) { glm::vec3 dimensions = getDimensions() * (float)TREE_SCALE; if (drawAsModel) { + remapTextures(); glPushMatrix(); { float alpha = getLocalRenderAlpha(); @@ -183,18 +222,6 @@ Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) { } } - // here's where we remap any textures if needed... - if (!_textures.isEmpty() && _model) { - QJsonDocument texturesAsJson = QJsonDocument::fromJson(_textures.toUtf8()); - QJsonObject texturesAsJsonObject = texturesAsJson.object(); - QVariantMap textureMap = texturesAsJsonObject.toVariantMap(); - foreach(const QString& key, textureMap.keys()) { - QUrl newTextureURL = textureMap[key].toUrl(); - qDebug() << "Updating texture named" << key << "to texture at URL" << newTextureURL; - _model->setTextureWithNameToURL(key, newTextureURL); - } - } - return result; } diff --git a/interface/src/entities/RenderableModelEntityItem.h b/interface/src/entities/RenderableModelEntityItem.h index f36b66dba4..dbc77b7e48 100644 --- a/interface/src/entities/RenderableModelEntityItem.h +++ b/interface/src/entities/RenderableModelEntityItem.h @@ -51,12 +51,14 @@ public: virtual void render(RenderArgs* args); Model* getModel(EntityTreeRenderer* renderer); private: + void remapTextures(); bool needsSimulation() const; Model* _model; bool _needsInitialSimulation; bool _needsModelReload; EntityTreeRenderer* _myRenderer; + QString _currentTextures; }; #endif // hifi_RenderableModelEntityItem_h From 5e21701a5b0c49658ff7c658f722ded4fc0ee478 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 30 Oct 2014 15:22:50 -0700 Subject: [PATCH 3/4] fix possible deadlocks --- interface/src/entities/RenderableModelEntityItem.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index b64bca4217..ce8d497da3 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -198,6 +198,10 @@ Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) { } assert(_myRenderer == renderer); // you should only ever render on one renderer + if (QThread::currentThread() != _myRenderer->thread()) { + return _model; + } + _needsModelReload = false; // this is the reload // if we have a URL, then we will want to end up returning a model... From fecea5fe3c0ec6dfc84a6bb84a08d1dde44bab76 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 30 Oct 2014 15:27:05 -0700 Subject: [PATCH 4/4] fixes to the Model List feature in editModels.js and added it to new edit --- examples/editModels.js | 18 ++++++++++++------ examples/newEditEntities.js | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index d0e69807aa..7f4c27814c 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -2787,13 +2787,13 @@ function setupModelMenus() { print("delete exists... don't add ours"); } + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Model List...", afterItem: "Models" }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Edit Properties..." }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Large Models", shortcutKey: "CTRL+META+L", afterItem: "Paste Models", isCheckable: true }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Small Models", shortcutKey: "CTRL+META+S", afterItem: "Allow Select Large Models", isCheckable: true }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Model List", afterItem: "Models" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Models", isSeparator: true, beforeItem: "Settings" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Export Models", shortcutKey: "CTRL+META+E", afterItem: "Models" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Import Models", shortcutKey: "CTRL+META+I", afterItem: "Export Models" }); @@ -2809,6 +2809,7 @@ function cleanupModelMenus() { Menu.removeMenuItem("Edit", "Delete"); } + Menu.removeMenuItem("Edit", "Model List..."); Menu.removeMenuItem("Edit", "Paste Models"); Menu.removeMenuItem("Edit", "Allow Select Large Models"); Menu.removeMenuItem("Edit", "Allow Select Small Models"); @@ -2883,16 +2884,21 @@ function handeMenuEvent(menuItem) { } else { print(" Delete Entity.... not holding..."); } - } else if (menuItem == "Model List") { + } else if (menuItem == "Model List...") { var models = new Array(); models = Entities.findEntities(MyAvatar.position, Number.MAX_VALUE); for (var i = 0; i < models.length; i++) { models[i].properties = Entities.getEntityProperties(models[i]); models[i].toString = function() { - var modelname = decodeURIComponent( - this.properties.modelURL.indexOf("/") != -1 ? - this.properties.modelURL.substring(this.properties.modelURL.lastIndexOf("/") + 1) : - this.properties.modelURL); + var modelname; + if (this.properties.type == "Model") { + modelname = decodeURIComponent( + this.properties.modelURL.indexOf("/") != -1 ? + this.properties.modelURL.substring(this.properties.modelURL.lastIndexOf("/") + 1) : + this.properties.modelURL); + } else { + modelname = this.properties.id; + } return "[" + this.properties.type + "] " + modelname; }; } diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index 8d19a350a2..71e29b3a38 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -584,6 +584,7 @@ function setupModelMenus() { print("delete exists... don't add ours"); } + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Model List...", afterItem: "Models" }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Edit Properties..." }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Large Models", shortcutKey: "CTRL+META+L", afterItem: "Paste Models", isCheckable: true }); @@ -606,6 +607,7 @@ function cleanupModelMenus() { Menu.removeMenuItem("Edit", "Delete"); } + Menu.removeMenuItem("Edit", "Model List..."); Menu.removeMenuItem("Edit", "Paste Models"); Menu.removeMenuItem("Edit", "Allow Select Large Models"); Menu.removeMenuItem("Edit", "Allow Select Small Models"); @@ -662,6 +664,38 @@ function handeMenuEvent(menuItem) { } else { print(" Delete Entity.... not holding..."); } + } else if (menuItem == "Model List...") { + var models = new Array(); + models = Entities.findEntities(MyAvatar.position, Number.MAX_VALUE); + for (var i = 0; i < models.length; i++) { + models[i].properties = Entities.getEntityProperties(models[i]); + models[i].toString = function() { + var modelname; + if (this.properties.type == "Model") { + modelname = decodeURIComponent( + this.properties.modelURL.indexOf("/") != -1 ? + this.properties.modelURL.substring(this.properties.modelURL.lastIndexOf("/") + 1) : + this.properties.modelURL); + } else { + modelname = this.properties.id; + } + return "[" + this.properties.type + "] " + modelname; + }; + } + var form = [{label: "Model: ", options: models}]; + form.push({label: "Action: ", options: ["Properties", "Delete", "Teleport"]}); + form.push({ button: "Cancel" }); + if (Window.form("Model List", form)) { + var selectedModel = form[0].value; + if (form[1].value == "Properties") { + editModelID = selectedModel; + showPropertiesForm(editModelID); + } else if (form[1].value == "Delete") { + Entities.deleteEntity(selectedModel); + } else if (form[1].value == "Teleport") { + MyAvatar.position = selectedModel.properties.position; + } + } } else if (menuItem == "Edit Properties...") { // good place to put the properties dialog